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*56c2c47bSJack F Vogel char ixl_driver_version[] = "1.4.1"; 5261ae650dSJack F Vogel 5361ae650dSJack F Vogel /********************************************************************* 5461ae650dSJack F Vogel * PCI Device ID Table 5561ae650dSJack F Vogel * 5661ae650dSJack F Vogel * Used by probe to select devices to load on 5761ae650dSJack F Vogel * Last field stores an index into ixl_strings 5861ae650dSJack F Vogel * Last entry must be all 0s 5961ae650dSJack F Vogel * 6061ae650dSJack F Vogel * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 6161ae650dSJack F Vogel *********************************************************************/ 6261ae650dSJack F Vogel 6361ae650dSJack F Vogel static ixl_vendor_info_t ixl_vendor_info_array[] = 6461ae650dSJack F Vogel { 6561ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0}, 6661ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_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}, 73*56c2c47bSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_20G_KR2, 0, 0, 0}, 7461ae650dSJack F Vogel /* required last entry */ 7561ae650dSJack F Vogel {0, 0, 0, 0, 0} 7661ae650dSJack F Vogel }; 7761ae650dSJack F Vogel 7861ae650dSJack F Vogel /********************************************************************* 7961ae650dSJack F Vogel * Table of branding strings 8061ae650dSJack F Vogel *********************************************************************/ 8161ae650dSJack F Vogel 8261ae650dSJack F Vogel static char *ixl_strings[] = { 8361ae650dSJack F Vogel "Intel(R) Ethernet Connection XL710 Driver" 8461ae650dSJack F Vogel }; 8561ae650dSJack F Vogel 8661ae650dSJack F Vogel 8761ae650dSJack F Vogel /********************************************************************* 8861ae650dSJack F Vogel * Function prototypes 8961ae650dSJack F Vogel *********************************************************************/ 9061ae650dSJack F Vogel static int ixl_probe(device_t); 9161ae650dSJack F Vogel static int ixl_attach(device_t); 9261ae650dSJack F Vogel static int ixl_detach(device_t); 9361ae650dSJack F Vogel static int ixl_shutdown(device_t); 9461ae650dSJack F Vogel static int ixl_get_hw_capabilities(struct ixl_pf *); 9561ae650dSJack F Vogel static void ixl_cap_txcsum_tso(struct ixl_vsi *, struct ifnet *, int); 9661ae650dSJack F Vogel static int ixl_ioctl(struct ifnet *, u_long, caddr_t); 9761ae650dSJack F Vogel static void ixl_init(void *); 9861ae650dSJack F Vogel static void ixl_init_locked(struct ixl_pf *); 9961ae650dSJack F Vogel static void ixl_stop(struct ixl_pf *); 10061ae650dSJack F Vogel static void ixl_media_status(struct ifnet *, struct ifmediareq *); 10161ae650dSJack F Vogel static int ixl_media_change(struct ifnet *); 10261ae650dSJack F Vogel static void ixl_update_link_status(struct ixl_pf *); 10361ae650dSJack F Vogel static int ixl_allocate_pci_resources(struct ixl_pf *); 10461ae650dSJack F Vogel static u16 ixl_get_bus_info(struct i40e_hw *, device_t); 10561ae650dSJack F Vogel static int ixl_setup_stations(struct ixl_pf *); 106b6c8f260SJack F Vogel static int ixl_switch_config(struct ixl_pf *); 10761ae650dSJack F Vogel static int ixl_initialize_vsi(struct ixl_vsi *); 10861ae650dSJack F Vogel static int ixl_assign_vsi_msix(struct ixl_pf *); 10961ae650dSJack F Vogel static int ixl_assign_vsi_legacy(struct ixl_pf *); 11061ae650dSJack F Vogel static int ixl_init_msix(struct ixl_pf *); 11161ae650dSJack F Vogel static void ixl_configure_msix(struct ixl_pf *); 11261ae650dSJack F Vogel static void ixl_configure_itr(struct ixl_pf *); 11361ae650dSJack F Vogel static void ixl_configure_legacy(struct ixl_pf *); 11461ae650dSJack F Vogel static void ixl_free_pci_resources(struct ixl_pf *); 11561ae650dSJack F Vogel static void ixl_local_timer(void *); 11661ae650dSJack F Vogel static int ixl_setup_interface(device_t, struct ixl_vsi *); 117*56c2c47bSJack F Vogel static void ixl_link_event(struct ixl_pf *, struct i40e_arq_event_info *); 11861ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *); 11961ae650dSJack F Vogel static void ixl_set_queue_rx_itr(struct ixl_queue *); 12061ae650dSJack F Vogel static void ixl_set_queue_tx_itr(struct ixl_queue *); 121e5100ee2SJack F Vogel static int ixl_set_advertised_speeds(struct ixl_pf *, int); 12261ae650dSJack F Vogel 123*56c2c47bSJack F Vogel static int ixl_enable_rings(struct ixl_vsi *); 124*56c2c47bSJack F Vogel static int ixl_disable_rings(struct ixl_vsi *); 12561ae650dSJack F Vogel static void ixl_enable_intr(struct ixl_vsi *); 12661ae650dSJack F Vogel static void ixl_disable_intr(struct ixl_vsi *); 127*56c2c47bSJack F Vogel static void ixl_disable_rings_intr(struct ixl_vsi *); 12861ae650dSJack F Vogel 12961ae650dSJack F Vogel static void ixl_enable_adminq(struct i40e_hw *); 13061ae650dSJack F Vogel static void ixl_disable_adminq(struct i40e_hw *); 13161ae650dSJack F Vogel static void ixl_enable_queue(struct i40e_hw *, int); 13261ae650dSJack F Vogel static void ixl_disable_queue(struct i40e_hw *, int); 13361ae650dSJack F Vogel static void ixl_enable_legacy(struct i40e_hw *); 13461ae650dSJack F Vogel static void ixl_disable_legacy(struct i40e_hw *); 13561ae650dSJack F Vogel 13661ae650dSJack F Vogel static void ixl_set_promisc(struct ixl_vsi *); 13761ae650dSJack F Vogel static void ixl_add_multi(struct ixl_vsi *); 13861ae650dSJack F Vogel static void ixl_del_multi(struct ixl_vsi *); 13961ae650dSJack F Vogel static void ixl_register_vlan(void *, struct ifnet *, u16); 14061ae650dSJack F Vogel static void ixl_unregister_vlan(void *, struct ifnet *, u16); 14161ae650dSJack F Vogel static void ixl_setup_vlan_filters(struct ixl_vsi *); 14261ae650dSJack F Vogel 14361ae650dSJack F Vogel static void ixl_init_filters(struct ixl_vsi *); 144*56c2c47bSJack F Vogel static void ixl_reconfigure_filters(struct ixl_vsi *vsi); 14561ae650dSJack F Vogel static void ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan); 14661ae650dSJack F Vogel static void ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan); 14761ae650dSJack F Vogel static void ixl_add_hw_filters(struct ixl_vsi *, int, int); 14861ae650dSJack F Vogel static void ixl_del_hw_filters(struct ixl_vsi *, int); 14961ae650dSJack F Vogel static struct ixl_mac_filter * 15061ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *, u8 *, s16); 15161ae650dSJack F Vogel static void ixl_add_mc_filter(struct ixl_vsi *, u8 *); 152*56c2c47bSJack F Vogel static void ixl_free_mac_filters(struct ixl_vsi *vsi); 153*56c2c47bSJack F Vogel 15461ae650dSJack F Vogel 15561ae650dSJack F Vogel /* Sysctl debug interface */ 15661ae650dSJack F Vogel static int ixl_debug_info(SYSCTL_HANDLER_ARGS); 15761ae650dSJack F Vogel static void ixl_print_debug_info(struct ixl_pf *); 15861ae650dSJack F Vogel 15961ae650dSJack F Vogel /* The MSI/X Interrupt handlers */ 16061ae650dSJack F Vogel static void ixl_intr(void *); 16161ae650dSJack F Vogel static void ixl_msix_que(void *); 16261ae650dSJack F Vogel static void ixl_msix_adminq(void *); 16361ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *); 16461ae650dSJack F Vogel 16561ae650dSJack F Vogel /* Deferred interrupt tasklets */ 16661ae650dSJack F Vogel static void ixl_do_adminq(void *, int); 16761ae650dSJack F Vogel 16861ae650dSJack F Vogel /* Sysctl handlers */ 16961ae650dSJack F Vogel static int ixl_set_flowcntl(SYSCTL_HANDLER_ARGS); 17061ae650dSJack F Vogel static int ixl_set_advertise(SYSCTL_HANDLER_ARGS); 17161ae650dSJack F Vogel static int ixl_current_speed(SYSCTL_HANDLER_ARGS); 172e5100ee2SJack F Vogel static int ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS); 17361ae650dSJack F Vogel 17461ae650dSJack F Vogel /* Statistics */ 17561ae650dSJack F Vogel static void ixl_add_hw_stats(struct ixl_pf *); 17661ae650dSJack F Vogel static void ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *, 17761ae650dSJack F Vogel struct sysctl_oid_list *, struct i40e_hw_port_stats *); 17861ae650dSJack F Vogel static void ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *, 17961ae650dSJack F Vogel struct sysctl_oid_list *, 18061ae650dSJack F Vogel struct i40e_eth_stats *); 18161ae650dSJack F Vogel static void ixl_update_stats_counters(struct ixl_pf *); 18261ae650dSJack F Vogel static void ixl_update_eth_stats(struct ixl_vsi *); 183*56c2c47bSJack F Vogel static void ixl_update_vsi_stats(struct ixl_vsi *); 18461ae650dSJack F Vogel static void ixl_pf_reset_stats(struct ixl_pf *); 18561ae650dSJack F Vogel static void ixl_vsi_reset_stats(struct ixl_vsi *); 18661ae650dSJack F Vogel static void ixl_stat_update48(struct i40e_hw *, u32, u32, bool, 18761ae650dSJack F Vogel u64 *, u64 *); 18861ae650dSJack F Vogel static void ixl_stat_update32(struct i40e_hw *, u32, bool, 18961ae650dSJack F Vogel u64 *, u64 *); 19061ae650dSJack F Vogel 191393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL 19261ae650dSJack F Vogel static int ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS); 19361ae650dSJack F Vogel static int ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS); 19461ae650dSJack F Vogel static int ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS); 195e5100ee2SJack F Vogel static int ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS); 196e5100ee2SJack F Vogel static int ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS); 197*56c2c47bSJack F Vogel #endif 198*56c2c47bSJack F Vogel 199*56c2c47bSJack F Vogel #ifdef PCI_IOV 200*56c2c47bSJack F Vogel static int ixl_adminq_err_to_errno(enum i40e_admin_queue_err err); 201*56c2c47bSJack F Vogel 202*56c2c47bSJack F Vogel static int ixl_init_iov(device_t dev, uint16_t num_vfs, const nvlist_t*); 203*56c2c47bSJack F Vogel static void ixl_uninit_iov(device_t dev); 204*56c2c47bSJack F Vogel static int ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t*); 205*56c2c47bSJack F Vogel 206*56c2c47bSJack F Vogel static void ixl_handle_vf_msg(struct ixl_pf *, 207*56c2c47bSJack F Vogel struct i40e_arq_event_info *); 208*56c2c47bSJack F Vogel static void ixl_handle_vflr(void *arg, int pending); 209*56c2c47bSJack F Vogel 210*56c2c47bSJack F Vogel static void ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf); 211*56c2c47bSJack F Vogel static void ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf); 21261ae650dSJack F Vogel #endif 21361ae650dSJack F Vogel 21461ae650dSJack F Vogel /********************************************************************* 21561ae650dSJack F Vogel * FreeBSD Device Interface Entry Points 21661ae650dSJack F Vogel *********************************************************************/ 21761ae650dSJack F Vogel 21861ae650dSJack F Vogel static device_method_t ixl_methods[] = { 21961ae650dSJack F Vogel /* Device interface */ 22061ae650dSJack F Vogel DEVMETHOD(device_probe, ixl_probe), 22161ae650dSJack F Vogel DEVMETHOD(device_attach, ixl_attach), 22261ae650dSJack F Vogel DEVMETHOD(device_detach, ixl_detach), 22361ae650dSJack F Vogel DEVMETHOD(device_shutdown, ixl_shutdown), 224*56c2c47bSJack F Vogel #ifdef PCI_IOV 225*56c2c47bSJack F Vogel DEVMETHOD(pci_init_iov, ixl_init_iov), 226*56c2c47bSJack F Vogel DEVMETHOD(pci_uninit_iov, ixl_uninit_iov), 227*56c2c47bSJack F Vogel DEVMETHOD(pci_add_vf, ixl_add_vf), 228*56c2c47bSJack F Vogel #endif 22961ae650dSJack F Vogel {0, 0} 23061ae650dSJack F Vogel }; 23161ae650dSJack F Vogel 23261ae650dSJack F Vogel static driver_t ixl_driver = { 23361ae650dSJack F Vogel "ixl", ixl_methods, sizeof(struct ixl_pf), 23461ae650dSJack F Vogel }; 23561ae650dSJack F Vogel 23661ae650dSJack F Vogel devclass_t ixl_devclass; 23761ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); 23861ae650dSJack F Vogel 23961ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1); 24061ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1); 24161ae650dSJack F Vogel 24261ae650dSJack F Vogel /* 24361ae650dSJack F Vogel ** Global reset mutex 24461ae650dSJack F Vogel */ 24561ae650dSJack F Vogel static struct mtx ixl_reset_mtx; 24661ae650dSJack F Vogel 24761ae650dSJack F Vogel /* 24861ae650dSJack F Vogel ** TUNEABLE PARAMETERS: 24961ae650dSJack F Vogel */ 25061ae650dSJack F Vogel 25161ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, 25261ae650dSJack F Vogel "IXL driver parameters"); 25361ae650dSJack F Vogel 25461ae650dSJack F Vogel /* 25561ae650dSJack F Vogel * MSIX should be the default for best performance, 25661ae650dSJack F Vogel * but this allows it to be forced off for testing. 25761ae650dSJack F Vogel */ 25861ae650dSJack F Vogel static int ixl_enable_msix = 1; 25961ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); 26061ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, 26161ae650dSJack F Vogel "Enable MSI-X interrupts"); 26261ae650dSJack F Vogel 26361ae650dSJack F Vogel /* 26461ae650dSJack F Vogel ** Number of descriptors per ring: 26561ae650dSJack F Vogel ** - TX and RX are the same size 26661ae650dSJack F Vogel */ 26761ae650dSJack F Vogel static int ixl_ringsz = DEFAULT_RING; 26861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz); 26961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN, 27061ae650dSJack F Vogel &ixl_ringsz, 0, "Descriptor Ring Size"); 27161ae650dSJack F Vogel 27261ae650dSJack F Vogel /* 27361ae650dSJack F Vogel ** This can be set manually, if left as 0 the 27461ae650dSJack F Vogel ** number of queues will be calculated based 27561ae650dSJack F Vogel ** on cpus and msix vectors available. 27661ae650dSJack F Vogel */ 27761ae650dSJack F Vogel int ixl_max_queues = 0; 27861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues); 27961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN, 28061ae650dSJack F Vogel &ixl_max_queues, 0, "Number of Queues"); 28161ae650dSJack F Vogel 28261ae650dSJack F Vogel /* 28361ae650dSJack F Vogel ** Controls for Interrupt Throttling 28461ae650dSJack F Vogel ** - true/false for dynamic adjustment 28561ae650dSJack F Vogel ** - default values for static ITR 28661ae650dSJack F Vogel */ 28761ae650dSJack F Vogel int ixl_dynamic_rx_itr = 0; 28861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr); 28961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, 29061ae650dSJack F Vogel &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); 29161ae650dSJack F Vogel 29261ae650dSJack F Vogel int ixl_dynamic_tx_itr = 0; 29361ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr); 29461ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, 29561ae650dSJack F Vogel &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); 29661ae650dSJack F Vogel 29761ae650dSJack F Vogel int ixl_rx_itr = IXL_ITR_8K; 29861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr); 29961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, 30061ae650dSJack F Vogel &ixl_rx_itr, 0, "RX Interrupt Rate"); 30161ae650dSJack F Vogel 30261ae650dSJack F Vogel int ixl_tx_itr = IXL_ITR_4K; 30361ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); 30461ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, 30561ae650dSJack F Vogel &ixl_tx_itr, 0, "TX Interrupt Rate"); 30661ae650dSJack F Vogel 30761ae650dSJack F Vogel #ifdef IXL_FDIR 30861ae650dSJack F Vogel static int ixl_enable_fdir = 1; 30961ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir); 31061ae650dSJack F Vogel /* Rate at which we sample */ 31161ae650dSJack F Vogel int ixl_atr_rate = 20; 31261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate); 31361ae650dSJack F Vogel #endif 31461ae650dSJack F Vogel 315e5100ee2SJack F Vogel 31661ae650dSJack F Vogel static char *ixl_fc_string[6] = { 31761ae650dSJack F Vogel "None", 31861ae650dSJack F Vogel "Rx", 31961ae650dSJack F Vogel "Tx", 32061ae650dSJack F Vogel "Full", 32161ae650dSJack F Vogel "Priority", 32261ae650dSJack F Vogel "Default" 32361ae650dSJack F Vogel }; 32461ae650dSJack F Vogel 325*56c2c47bSJack F Vogel static MALLOC_DEFINE(M_IXL, "ixl", "ixl driver allocations"); 326*56c2c47bSJack F Vogel 327*56c2c47bSJack F Vogel static uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] = 328*56c2c47bSJack F Vogel {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 32961ae650dSJack F Vogel 33061ae650dSJack F Vogel /********************************************************************* 33161ae650dSJack F Vogel * Device identification routine 33261ae650dSJack F Vogel * 33361ae650dSJack F Vogel * ixl_probe determines if the driver should be loaded on 33461ae650dSJack F Vogel * the hardware based on PCI vendor/device id of the device. 33561ae650dSJack F Vogel * 33661ae650dSJack F Vogel * return BUS_PROBE_DEFAULT on success, positive on failure 33761ae650dSJack F Vogel *********************************************************************/ 33861ae650dSJack F Vogel 33961ae650dSJack F Vogel static int 34061ae650dSJack F Vogel ixl_probe(device_t dev) 34161ae650dSJack F Vogel { 34261ae650dSJack F Vogel ixl_vendor_info_t *ent; 34361ae650dSJack F Vogel 34461ae650dSJack F Vogel u16 pci_vendor_id, pci_device_id; 34561ae650dSJack F Vogel u16 pci_subvendor_id, pci_subdevice_id; 34661ae650dSJack F Vogel char device_name[256]; 34761ae650dSJack F Vogel static bool lock_init = FALSE; 34861ae650dSJack F Vogel 34961ae650dSJack F Vogel INIT_DEBUGOUT("ixl_probe: begin"); 35061ae650dSJack F Vogel 35161ae650dSJack F Vogel pci_vendor_id = pci_get_vendor(dev); 35261ae650dSJack F Vogel if (pci_vendor_id != I40E_INTEL_VENDOR_ID) 35361ae650dSJack F Vogel return (ENXIO); 35461ae650dSJack F Vogel 35561ae650dSJack F Vogel pci_device_id = pci_get_device(dev); 35661ae650dSJack F Vogel pci_subvendor_id = pci_get_subvendor(dev); 35761ae650dSJack F Vogel pci_subdevice_id = pci_get_subdevice(dev); 35861ae650dSJack F Vogel 35961ae650dSJack F Vogel ent = ixl_vendor_info_array; 36061ae650dSJack F Vogel while (ent->vendor_id != 0) { 36161ae650dSJack F Vogel if ((pci_vendor_id == ent->vendor_id) && 36261ae650dSJack F Vogel (pci_device_id == ent->device_id) && 36361ae650dSJack F Vogel 36461ae650dSJack F Vogel ((pci_subvendor_id == ent->subvendor_id) || 36561ae650dSJack F Vogel (ent->subvendor_id == 0)) && 36661ae650dSJack F Vogel 36761ae650dSJack F Vogel ((pci_subdevice_id == ent->subdevice_id) || 36861ae650dSJack F Vogel (ent->subdevice_id == 0))) { 36961ae650dSJack F Vogel sprintf(device_name, "%s, Version - %s", 37061ae650dSJack F Vogel ixl_strings[ent->index], 37161ae650dSJack F Vogel ixl_driver_version); 37261ae650dSJack F Vogel device_set_desc_copy(dev, device_name); 37361ae650dSJack F Vogel /* One shot mutex init */ 37461ae650dSJack F Vogel if (lock_init == FALSE) { 37561ae650dSJack F Vogel lock_init = TRUE; 37661ae650dSJack F Vogel mtx_init(&ixl_reset_mtx, 37761ae650dSJack F Vogel "ixl_reset", 37861ae650dSJack F Vogel "IXL RESET Lock", MTX_DEF); 37961ae650dSJack F Vogel } 38061ae650dSJack F Vogel return (BUS_PROBE_DEFAULT); 38161ae650dSJack F Vogel } 38261ae650dSJack F Vogel ent++; 38361ae650dSJack F Vogel } 38461ae650dSJack F Vogel return (ENXIO); 38561ae650dSJack F Vogel } 38661ae650dSJack F Vogel 38761ae650dSJack F Vogel /********************************************************************* 38861ae650dSJack F Vogel * Device initialization routine 38961ae650dSJack F Vogel * 39061ae650dSJack F Vogel * The attach entry point is called when the driver is being loaded. 39161ae650dSJack F Vogel * This routine identifies the type of hardware, allocates all resources 39261ae650dSJack F Vogel * and initializes the hardware. 39361ae650dSJack F Vogel * 39461ae650dSJack F Vogel * return 0 on success, positive on failure 39561ae650dSJack F Vogel *********************************************************************/ 39661ae650dSJack F Vogel 39761ae650dSJack F Vogel static int 39861ae650dSJack F Vogel ixl_attach(device_t dev) 39961ae650dSJack F Vogel { 40061ae650dSJack F Vogel struct ixl_pf *pf; 40161ae650dSJack F Vogel struct i40e_hw *hw; 40261ae650dSJack F Vogel struct ixl_vsi *vsi; 40361ae650dSJack F Vogel u16 bus; 40461ae650dSJack F Vogel int error = 0; 405*56c2c47bSJack F Vogel #ifdef PCI_IOV 406*56c2c47bSJack F Vogel nvlist_t *pf_schema, *vf_schema; 407*56c2c47bSJack F Vogel int iov_error; 408*56c2c47bSJack F Vogel #endif 40961ae650dSJack F Vogel 41061ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: begin"); 41161ae650dSJack F Vogel 41261ae650dSJack F Vogel /* Allocate, clear, and link in our primary soft structure */ 41361ae650dSJack F Vogel pf = device_get_softc(dev); 41461ae650dSJack F Vogel pf->dev = pf->osdep.dev = dev; 41561ae650dSJack F Vogel hw = &pf->hw; 41661ae650dSJack F Vogel 41761ae650dSJack F Vogel /* 41861ae650dSJack F Vogel ** Note this assumes we have a single embedded VSI, 41961ae650dSJack F Vogel ** this could be enhanced later to allocate multiple 42061ae650dSJack F Vogel */ 42161ae650dSJack F Vogel vsi = &pf->vsi; 42261ae650dSJack F Vogel vsi->dev = pf->dev; 42361ae650dSJack F Vogel 42461ae650dSJack F Vogel /* Core Lock Init*/ 42561ae650dSJack F Vogel IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev)); 42661ae650dSJack F Vogel 42761ae650dSJack F Vogel /* Set up the timer callout */ 42861ae650dSJack F Vogel callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); 42961ae650dSJack F Vogel 43061ae650dSJack F Vogel /* Set up sysctls */ 43161ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 43261ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 43361ae650dSJack F Vogel OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, 43461ae650dSJack F Vogel pf, 0, ixl_set_flowcntl, "I", "Flow Control"); 43561ae650dSJack F Vogel 43661ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 43761ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 43861ae650dSJack F Vogel OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, 43961ae650dSJack F Vogel pf, 0, ixl_set_advertise, "I", "Advertised Speed"); 44061ae650dSJack F Vogel 44161ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 44261ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 44361ae650dSJack F Vogel OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD, 44461ae650dSJack F Vogel pf, 0, ixl_current_speed, "A", "Current Port Speed"); 44561ae650dSJack F Vogel 446e5100ee2SJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 447e5100ee2SJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 448e5100ee2SJack F Vogel OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD, 449e5100ee2SJack F Vogel pf, 0, ixl_sysctl_show_fw, "A", "Firmware version"); 450e5100ee2SJack F Vogel 45161ae650dSJack F Vogel SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 45261ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 453f0188618SHans Petter Selasky OID_AUTO, "rx_itr", CTLFLAG_RW, 45461ae650dSJack F Vogel &ixl_rx_itr, IXL_ITR_8K, "RX ITR"); 45561ae650dSJack F Vogel 45661ae650dSJack F Vogel SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 45761ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 458f0188618SHans Petter Selasky OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW, 45961ae650dSJack F Vogel &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR"); 46061ae650dSJack F Vogel 46161ae650dSJack F Vogel SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 46261ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 463f0188618SHans Petter Selasky OID_AUTO, "tx_itr", CTLFLAG_RW, 46461ae650dSJack F Vogel &ixl_tx_itr, IXL_ITR_4K, "TX ITR"); 46561ae650dSJack F Vogel 46661ae650dSJack F Vogel SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 46761ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 468f0188618SHans Petter Selasky OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW, 46961ae650dSJack F Vogel &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR"); 47061ae650dSJack F Vogel 471393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL 47261ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 47361ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 47461ae650dSJack F Vogel OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD, 47561ae650dSJack F Vogel pf, 0, ixl_sysctl_link_status, "A", "Current Link Status"); 47661ae650dSJack F Vogel 47761ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 47861ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 47961ae650dSJack F Vogel OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD, 48061ae650dSJack F Vogel pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities"); 48161ae650dSJack F Vogel 48261ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 48361ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 48461ae650dSJack F Vogel OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD, 48561ae650dSJack F Vogel pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List"); 48661ae650dSJack F Vogel 48761ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 48861ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 489e5100ee2SJack F Vogel OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD, 490e5100ee2SJack F Vogel pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation"); 491e5100ee2SJack F Vogel 492e5100ee2SJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 493e5100ee2SJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 494e5100ee2SJack F Vogel OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD, 495e5100ee2SJack F Vogel pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration"); 49661ae650dSJack F Vogel #endif 49761ae650dSJack F Vogel 498e5100ee2SJack F Vogel /* Save off the PCI information */ 49961ae650dSJack F Vogel hw->vendor_id = pci_get_vendor(dev); 50061ae650dSJack F Vogel hw->device_id = pci_get_device(dev); 50161ae650dSJack F Vogel hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 50261ae650dSJack F Vogel hw->subsystem_vendor_id = 50361ae650dSJack F Vogel pci_read_config(dev, PCIR_SUBVEND_0, 2); 50461ae650dSJack F Vogel hw->subsystem_device_id = 50561ae650dSJack F Vogel pci_read_config(dev, PCIR_SUBDEV_0, 2); 50661ae650dSJack F Vogel 50761ae650dSJack F Vogel hw->bus.device = pci_get_slot(dev); 50861ae650dSJack F Vogel hw->bus.func = pci_get_function(dev); 50961ae650dSJack F Vogel 510*56c2c47bSJack F Vogel pf->vc_debug_lvl = 1; 511*56c2c47bSJack F Vogel 51261ae650dSJack F Vogel /* Do PCI setup - map BAR0, etc */ 51361ae650dSJack F Vogel if (ixl_allocate_pci_resources(pf)) { 51461ae650dSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 51561ae650dSJack F Vogel error = ENXIO; 51661ae650dSJack F Vogel goto err_out; 51761ae650dSJack F Vogel } 51861ae650dSJack F Vogel 51961ae650dSJack F Vogel /* Create for initial debugging use */ 52061ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 52161ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 52261ae650dSJack F Vogel OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0, 52361ae650dSJack F Vogel ixl_debug_info, "I", "Debug Information"); 52461ae650dSJack F Vogel 52561ae650dSJack F Vogel 52661ae650dSJack F Vogel /* Establish a clean starting point */ 52761ae650dSJack F Vogel i40e_clear_hw(hw); 52861ae650dSJack F Vogel error = i40e_pf_reset(hw); 52961ae650dSJack F Vogel if (error) { 53061ae650dSJack F Vogel device_printf(dev,"PF reset failure %x\n", error); 53161ae650dSJack F Vogel error = EIO; 53261ae650dSJack F Vogel goto err_out; 53361ae650dSJack F Vogel } 53461ae650dSJack F Vogel 53561ae650dSJack F Vogel /* Set admin queue parameters */ 53661ae650dSJack F Vogel hw->aq.num_arq_entries = IXL_AQ_LEN; 53761ae650dSJack F Vogel hw->aq.num_asq_entries = IXL_AQ_LEN; 53861ae650dSJack F Vogel hw->aq.arq_buf_size = IXL_AQ_BUFSZ; 53961ae650dSJack F Vogel hw->aq.asq_buf_size = IXL_AQ_BUFSZ; 54061ae650dSJack F Vogel 54161ae650dSJack F Vogel /* Initialize the shared code */ 54261ae650dSJack F Vogel error = i40e_init_shared_code(hw); 54361ae650dSJack F Vogel if (error) { 54461ae650dSJack F Vogel device_printf(dev,"Unable to initialize the shared code\n"); 54561ae650dSJack F Vogel error = EIO; 54661ae650dSJack F Vogel goto err_out; 54761ae650dSJack F Vogel } 54861ae650dSJack F Vogel 54961ae650dSJack F Vogel /* Set up the admin queue */ 55061ae650dSJack F Vogel error = i40e_init_adminq(hw); 55161ae650dSJack F Vogel if (error) { 55261ae650dSJack F Vogel device_printf(dev, "The driver for the device stopped " 55361ae650dSJack F Vogel "because the NVM image is newer than expected.\n" 55461ae650dSJack F Vogel "You must install the most recent version of " 55561ae650dSJack F Vogel " the network driver.\n"); 55661ae650dSJack F Vogel goto err_out; 55761ae650dSJack F Vogel } 55861ae650dSJack F Vogel device_printf(dev, "%s\n", ixl_fw_version_str(hw)); 55961ae650dSJack F Vogel 56061ae650dSJack F Vogel if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 56161ae650dSJack F Vogel hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) 56261ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 56361ae650dSJack F Vogel "a newer version of the NVM image than expected.\n" 56461ae650dSJack F Vogel "Please install the most recent version of the network driver.\n"); 56561ae650dSJack F Vogel else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || 56661ae650dSJack F Vogel hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) 56761ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 56861ae650dSJack F Vogel "an older version of the NVM image than expected.\n" 56961ae650dSJack F Vogel "Please update the NVM image.\n"); 57061ae650dSJack F Vogel 57161ae650dSJack F Vogel /* Clear PXE mode */ 57261ae650dSJack F Vogel i40e_clear_pxe_mode(hw); 57361ae650dSJack F Vogel 57461ae650dSJack F Vogel /* Get capabilities from the device */ 57561ae650dSJack F Vogel error = ixl_get_hw_capabilities(pf); 57661ae650dSJack F Vogel if (error) { 57761ae650dSJack F Vogel device_printf(dev, "HW capabilities failure!\n"); 57861ae650dSJack F Vogel goto err_get_cap; 57961ae650dSJack F Vogel } 58061ae650dSJack F Vogel 58161ae650dSJack F Vogel /* Set up host memory cache */ 582*56c2c47bSJack F Vogel error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 583*56c2c47bSJack F Vogel hw->func_caps.num_rx_qp, 0, 0); 58461ae650dSJack F Vogel if (error) { 58561ae650dSJack F Vogel device_printf(dev, "init_lan_hmc failed: %d\n", error); 58661ae650dSJack F Vogel goto err_get_cap; 58761ae650dSJack F Vogel } 58861ae650dSJack F Vogel 58961ae650dSJack F Vogel error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 59061ae650dSJack F Vogel if (error) { 59161ae650dSJack F Vogel device_printf(dev, "configure_lan_hmc failed: %d\n", error); 59261ae650dSJack F Vogel goto err_mac_hmc; 59361ae650dSJack F Vogel } 59461ae650dSJack F Vogel 59561ae650dSJack F Vogel /* Disable LLDP from the firmware */ 59661ae650dSJack F Vogel i40e_aq_stop_lldp(hw, TRUE, NULL); 59761ae650dSJack F Vogel 59861ae650dSJack F Vogel i40e_get_mac_addr(hw, hw->mac.addr); 59961ae650dSJack F Vogel error = i40e_validate_mac_addr(hw->mac.addr); 60061ae650dSJack F Vogel if (error) { 60161ae650dSJack F Vogel device_printf(dev, "validate_mac_addr failed: %d\n", error); 60261ae650dSJack F Vogel goto err_mac_hmc; 60361ae650dSJack F Vogel } 60461ae650dSJack F Vogel bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 60561ae650dSJack F Vogel i40e_get_port_mac_addr(hw, hw->mac.port_addr); 60661ae650dSJack F Vogel 607e5100ee2SJack F Vogel /* Set up VSI and queues */ 60861ae650dSJack F Vogel if (ixl_setup_stations(pf) != 0) { 60961ae650dSJack F Vogel device_printf(dev, "setup stations failed!\n"); 61061ae650dSJack F Vogel error = ENOMEM; 61161ae650dSJack F Vogel goto err_mac_hmc; 61261ae650dSJack F Vogel } 61361ae650dSJack F Vogel 61461ae650dSJack F Vogel /* Initialize mac filter list for VSI */ 61561ae650dSJack F Vogel SLIST_INIT(&vsi->ftl); 61661ae650dSJack F Vogel 61761ae650dSJack F Vogel /* Set up interrupt routing here */ 61861ae650dSJack F Vogel if (pf->msix > 1) 61961ae650dSJack F Vogel error = ixl_assign_vsi_msix(pf); 62061ae650dSJack F Vogel else 62161ae650dSJack F Vogel error = ixl_assign_vsi_legacy(pf); 62261ae650dSJack F Vogel if (error) 62361ae650dSJack F Vogel goto err_late; 62461ae650dSJack F Vogel 625b6c8f260SJack F Vogel if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 626b6c8f260SJack F Vogel (hw->aq.fw_maj_ver < 4)) { 62761ae650dSJack F Vogel i40e_msec_delay(75); 62861ae650dSJack F Vogel error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 629b6c8f260SJack F Vogel if (error) 63061ae650dSJack F Vogel device_printf(dev, "link restart failed, aq_err=%d\n", 63161ae650dSJack F Vogel pf->hw.aq.asq_last_status); 63261ae650dSJack F Vogel } 63361ae650dSJack F Vogel 63461ae650dSJack F Vogel /* Determine link state */ 635*56c2c47bSJack F Vogel i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 636*56c2c47bSJack F Vogel pf->link_up = i40e_get_link_status(hw); 63761ae650dSJack F Vogel 63861ae650dSJack F Vogel /* Setup OS specific network interface */ 639e5100ee2SJack F Vogel if (ixl_setup_interface(dev, vsi) != 0) { 640e5100ee2SJack F Vogel device_printf(dev, "interface setup failed!\n"); 641e5100ee2SJack F Vogel error = EIO; 64261ae650dSJack F Vogel goto err_late; 643e5100ee2SJack F Vogel } 64461ae650dSJack F Vogel 645b6c8f260SJack F Vogel error = ixl_switch_config(pf); 646b6c8f260SJack F Vogel if (error) { 647b6c8f260SJack F Vogel device_printf(dev, "Initial switch config failed: %d\n", error); 648b6c8f260SJack F Vogel goto err_mac_hmc; 649b6c8f260SJack F Vogel } 650b6c8f260SJack F Vogel 651b6c8f260SJack F Vogel /* Limit phy interrupts to link and modules failure */ 652b6c8f260SJack F Vogel error = i40e_aq_set_phy_int_mask(hw, 653b6c8f260SJack F Vogel I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL); 654b6c8f260SJack F Vogel if (error) 655b6c8f260SJack F Vogel device_printf(dev, "set phy mask failed: %d\n", error); 656b6c8f260SJack F Vogel 65761ae650dSJack F Vogel /* Get the bus configuration and set the shared code */ 65861ae650dSJack F Vogel bus = ixl_get_bus_info(hw, dev); 65961ae650dSJack F Vogel i40e_set_pci_config_data(hw, bus); 66061ae650dSJack F Vogel 66161ae650dSJack F Vogel /* Initialize statistics */ 66261ae650dSJack F Vogel ixl_pf_reset_stats(pf); 66361ae650dSJack F Vogel ixl_update_stats_counters(pf); 66461ae650dSJack F Vogel ixl_add_hw_stats(pf); 66561ae650dSJack F Vogel 66661ae650dSJack F Vogel /* Register for VLAN events */ 66761ae650dSJack F Vogel vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 66861ae650dSJack F Vogel ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); 66961ae650dSJack F Vogel vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 67061ae650dSJack F Vogel ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); 67161ae650dSJack F Vogel 672*56c2c47bSJack F Vogel #ifdef PCI_IOV 673*56c2c47bSJack F Vogel /* SR-IOV is only supported when MSI-X is in use. */ 674*56c2c47bSJack F Vogel if (pf->msix > 1) { 675*56c2c47bSJack F Vogel pf_schema = pci_iov_schema_alloc_node(); 676*56c2c47bSJack F Vogel vf_schema = pci_iov_schema_alloc_node(); 677*56c2c47bSJack F Vogel pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); 678*56c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", 679*56c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, TRUE); 680*56c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-set-mac", 681*56c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 682*56c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-promisc", 683*56c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 684e5100ee2SJack F Vogel 685*56c2c47bSJack F Vogel iov_error = pci_iov_attach(dev, pf_schema, vf_schema); 686*56c2c47bSJack F Vogel if (iov_error != 0) 687*56c2c47bSJack F Vogel device_printf(dev, 688*56c2c47bSJack F Vogel "Failed to initialize SR-IOV (error=%d)\n", 689*56c2c47bSJack F Vogel iov_error); 690*56c2c47bSJack F Vogel } 691*56c2c47bSJack F Vogel #endif 692*56c2c47bSJack F Vogel 69361ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: end"); 69461ae650dSJack F Vogel return (0); 69561ae650dSJack F Vogel 69661ae650dSJack F Vogel err_late: 697e5100ee2SJack F Vogel if (vsi->ifp != NULL) 698e5100ee2SJack F Vogel if_free(vsi->ifp); 69961ae650dSJack F Vogel err_mac_hmc: 70061ae650dSJack F Vogel i40e_shutdown_lan_hmc(hw); 70161ae650dSJack F Vogel err_get_cap: 70261ae650dSJack F Vogel i40e_shutdown_adminq(hw); 70361ae650dSJack F Vogel err_out: 70461ae650dSJack F Vogel ixl_free_pci_resources(pf); 705e5100ee2SJack F Vogel ixl_free_vsi(vsi); 70661ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 70761ae650dSJack F Vogel return (error); 70861ae650dSJack F Vogel } 70961ae650dSJack F Vogel 71061ae650dSJack F Vogel /********************************************************************* 71161ae650dSJack F Vogel * Device removal routine 71261ae650dSJack F Vogel * 71361ae650dSJack F Vogel * The detach entry point is called when the driver is being removed. 71461ae650dSJack F Vogel * This routine stops the adapter and deallocates all the resources 71561ae650dSJack F Vogel * that were allocated for driver operation. 71661ae650dSJack F Vogel * 71761ae650dSJack F Vogel * return 0 on success, positive on failure 71861ae650dSJack F Vogel *********************************************************************/ 71961ae650dSJack F Vogel 72061ae650dSJack F Vogel static int 72161ae650dSJack F Vogel ixl_detach(device_t dev) 72261ae650dSJack F Vogel { 72361ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 72461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 72561ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 72661ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 72761ae650dSJack F Vogel i40e_status status; 728*56c2c47bSJack F Vogel #ifdef PCI_IOV 729*56c2c47bSJack F Vogel int error; 730*56c2c47bSJack F Vogel #endif 73161ae650dSJack F Vogel 73261ae650dSJack F Vogel INIT_DEBUGOUT("ixl_detach: begin"); 73361ae650dSJack F Vogel 73461ae650dSJack F Vogel /* Make sure VLANS are not using driver */ 73561ae650dSJack F Vogel if (vsi->ifp->if_vlantrunk != NULL) { 73661ae650dSJack F Vogel device_printf(dev,"Vlan in use, detach first\n"); 73761ae650dSJack F Vogel return (EBUSY); 73861ae650dSJack F Vogel } 73961ae650dSJack F Vogel 740*56c2c47bSJack F Vogel #ifdef PCI_IOV 741*56c2c47bSJack F Vogel error = pci_iov_detach(dev); 742*56c2c47bSJack F Vogel if (error != 0) { 743*56c2c47bSJack F Vogel device_printf(dev, "SR-IOV in use; detach first.\n"); 744*56c2c47bSJack F Vogel return (error); 745*56c2c47bSJack F Vogel } 746*56c2c47bSJack F Vogel #endif 747*56c2c47bSJack F Vogel 748b6c8f260SJack F Vogel ether_ifdetach(vsi->ifp); 749b6c8f260SJack F Vogel if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) { 75061ae650dSJack F Vogel IXL_PF_LOCK(pf); 75161ae650dSJack F Vogel ixl_stop(pf); 75261ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 753b6c8f260SJack F Vogel } 75461ae650dSJack F Vogel 75561ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 75661ae650dSJack F Vogel if (que->tq) { 75761ae650dSJack F Vogel taskqueue_drain(que->tq, &que->task); 75861ae650dSJack F Vogel taskqueue_drain(que->tq, &que->tx_task); 75961ae650dSJack F Vogel taskqueue_free(que->tq); 76061ae650dSJack F Vogel } 76161ae650dSJack F Vogel } 76261ae650dSJack F Vogel 76361ae650dSJack F Vogel /* Shutdown LAN HMC */ 76461ae650dSJack F Vogel status = i40e_shutdown_lan_hmc(hw); 76561ae650dSJack F Vogel if (status) 76661ae650dSJack F Vogel device_printf(dev, 76761ae650dSJack F Vogel "Shutdown LAN HMC failed with code %d\n", status); 76861ae650dSJack F Vogel 76961ae650dSJack F Vogel /* Shutdown admin queue */ 77061ae650dSJack F Vogel status = i40e_shutdown_adminq(hw); 77161ae650dSJack F Vogel if (status) 77261ae650dSJack F Vogel device_printf(dev, 77361ae650dSJack F Vogel "Shutdown Admin queue failed with code %d\n", status); 77461ae650dSJack F Vogel 77561ae650dSJack F Vogel /* Unregister VLAN events */ 77661ae650dSJack F Vogel if (vsi->vlan_attach != NULL) 77761ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); 77861ae650dSJack F Vogel if (vsi->vlan_detach != NULL) 77961ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); 78061ae650dSJack F Vogel 78161ae650dSJack F Vogel callout_drain(&pf->timer); 78261ae650dSJack F Vogel ixl_free_pci_resources(pf); 78361ae650dSJack F Vogel bus_generic_detach(dev); 78461ae650dSJack F Vogel if_free(vsi->ifp); 78561ae650dSJack F Vogel ixl_free_vsi(vsi); 78661ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 78761ae650dSJack F Vogel return (0); 78861ae650dSJack F Vogel } 78961ae650dSJack F Vogel 79061ae650dSJack F Vogel /********************************************************************* 79161ae650dSJack F Vogel * 79261ae650dSJack F Vogel * Shutdown entry point 79361ae650dSJack F Vogel * 79461ae650dSJack F Vogel **********************************************************************/ 79561ae650dSJack F Vogel 79661ae650dSJack F Vogel static int 79761ae650dSJack F Vogel ixl_shutdown(device_t dev) 79861ae650dSJack F Vogel { 79961ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 80061ae650dSJack F Vogel IXL_PF_LOCK(pf); 80161ae650dSJack F Vogel ixl_stop(pf); 80261ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 80361ae650dSJack F Vogel return (0); 80461ae650dSJack F Vogel } 80561ae650dSJack F Vogel 80661ae650dSJack F Vogel 80761ae650dSJack F Vogel /********************************************************************* 80861ae650dSJack F Vogel * 80961ae650dSJack F Vogel * Get the hardware capabilities 81061ae650dSJack F Vogel * 81161ae650dSJack F Vogel **********************************************************************/ 81261ae650dSJack F Vogel 81361ae650dSJack F Vogel static int 81461ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf) 81561ae650dSJack F Vogel { 81661ae650dSJack F Vogel struct i40e_aqc_list_capabilities_element_resp *buf; 81761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 81861ae650dSJack F Vogel device_t dev = pf->dev; 81961ae650dSJack F Vogel int error, len; 82061ae650dSJack F Vogel u16 needed; 82161ae650dSJack F Vogel bool again = TRUE; 82261ae650dSJack F Vogel 82361ae650dSJack F Vogel len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); 82461ae650dSJack F Vogel retry: 82561ae650dSJack F Vogel if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *) 82661ae650dSJack F Vogel malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) { 82761ae650dSJack F Vogel device_printf(dev, "Unable to allocate cap memory\n"); 82861ae650dSJack F Vogel return (ENOMEM); 82961ae650dSJack F Vogel } 83061ae650dSJack F Vogel 83161ae650dSJack F Vogel /* This populates the hw struct */ 83261ae650dSJack F Vogel error = i40e_aq_discover_capabilities(hw, buf, len, 83361ae650dSJack F Vogel &needed, i40e_aqc_opc_list_func_capabilities, NULL); 83461ae650dSJack F Vogel free(buf, M_DEVBUF); 83561ae650dSJack F Vogel if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && 83661ae650dSJack F Vogel (again == TRUE)) { 83761ae650dSJack F Vogel /* retry once with a larger buffer */ 83861ae650dSJack F Vogel again = FALSE; 83961ae650dSJack F Vogel len = needed; 84061ae650dSJack F Vogel goto retry; 84161ae650dSJack F Vogel } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { 84261ae650dSJack F Vogel device_printf(dev, "capability discovery failed: %d\n", 84361ae650dSJack F Vogel pf->hw.aq.asq_last_status); 84461ae650dSJack F Vogel return (ENODEV); 84561ae650dSJack F Vogel } 84661ae650dSJack F Vogel 84761ae650dSJack F Vogel /* Capture this PF's starting queue pair */ 84861ae650dSJack F Vogel pf->qbase = hw->func_caps.base_queue; 84961ae650dSJack F Vogel 85061ae650dSJack F Vogel #ifdef IXL_DEBUG 85161ae650dSJack F Vogel device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, " 85261ae650dSJack F Vogel "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", 85361ae650dSJack F Vogel hw->pf_id, hw->func_caps.num_vfs, 85461ae650dSJack F Vogel hw->func_caps.num_msix_vectors, 85561ae650dSJack F Vogel hw->func_caps.num_msix_vectors_vf, 85661ae650dSJack F Vogel hw->func_caps.fd_filters_guaranteed, 85761ae650dSJack F Vogel hw->func_caps.fd_filters_best_effort, 85861ae650dSJack F Vogel hw->func_caps.num_tx_qp, 85961ae650dSJack F Vogel hw->func_caps.num_rx_qp, 86061ae650dSJack F Vogel hw->func_caps.base_queue); 86161ae650dSJack F Vogel #endif 86261ae650dSJack F Vogel return (error); 86361ae650dSJack F Vogel } 86461ae650dSJack F Vogel 86561ae650dSJack F Vogel static void 86661ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) 86761ae650dSJack F Vogel { 86861ae650dSJack F Vogel device_t dev = vsi->dev; 86961ae650dSJack F Vogel 87061ae650dSJack F Vogel /* Enable/disable TXCSUM/TSO4 */ 87161ae650dSJack F Vogel if (!(ifp->if_capenable & IFCAP_TXCSUM) 87261ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO4)) { 87361ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) { 87461ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TXCSUM; 87561ae650dSJack F Vogel /* enable TXCSUM, restore TSO if previously enabled */ 87661ae650dSJack F Vogel if (vsi->flags & IXL_FLAGS_KEEP_TSO4) { 87761ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 87861ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO4; 87961ae650dSJack F Vogel } 88061ae650dSJack F Vogel } 88161ae650dSJack F Vogel else if (mask & IFCAP_TSO4) { 88261ae650dSJack F Vogel ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); 88361ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 88461ae650dSJack F Vogel device_printf(dev, 88561ae650dSJack F Vogel "TSO4 requires txcsum, enabling both...\n"); 88661ae650dSJack F Vogel } 88761ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM) 88861ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO4)) { 88961ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) 89061ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TXCSUM; 89161ae650dSJack F Vogel else if (mask & IFCAP_TSO4) 89261ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO4; 89361ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM) 89461ae650dSJack F Vogel && (ifp->if_capenable & IFCAP_TSO4)) { 89561ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) { 89661ae650dSJack F Vogel vsi->flags |= IXL_FLAGS_KEEP_TSO4; 89761ae650dSJack F Vogel ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); 89861ae650dSJack F Vogel device_printf(dev, 89961ae650dSJack F Vogel "TSO4 requires txcsum, disabling both...\n"); 90061ae650dSJack F Vogel } else if (mask & IFCAP_TSO4) 90161ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TSO4; 90261ae650dSJack F Vogel } 90361ae650dSJack F Vogel 90461ae650dSJack F Vogel /* Enable/disable TXCSUM_IPV6/TSO6 */ 90561ae650dSJack F Vogel if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) 90661ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO6)) { 90761ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) { 90861ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TXCSUM_IPV6; 90961ae650dSJack F Vogel if (vsi->flags & IXL_FLAGS_KEEP_TSO6) { 91061ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 91161ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO6; 91261ae650dSJack F Vogel } 91361ae650dSJack F Vogel } else if (mask & IFCAP_TSO6) { 91461ae650dSJack F Vogel ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 91561ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 91661ae650dSJack F Vogel device_printf(dev, 91761ae650dSJack F Vogel "TSO6 requires txcsum6, enabling both...\n"); 91861ae650dSJack F Vogel } 91961ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 92061ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO6)) { 92161ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) 92261ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; 92361ae650dSJack F Vogel else if (mask & IFCAP_TSO6) 92461ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO6; 92561ae650dSJack F Vogel } else 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 vsi->flags |= IXL_FLAGS_KEEP_TSO6; 92961ae650dSJack F Vogel ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 93061ae650dSJack F Vogel device_printf(dev, 93161ae650dSJack F Vogel "TSO6 requires txcsum6, disabling both...\n"); 93261ae650dSJack F Vogel } else if (mask & IFCAP_TSO6) 93361ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TSO6; 93461ae650dSJack F Vogel } 93561ae650dSJack F Vogel } 93661ae650dSJack F Vogel 93761ae650dSJack F Vogel /********************************************************************* 93861ae650dSJack F Vogel * Ioctl entry point 93961ae650dSJack F Vogel * 94061ae650dSJack F Vogel * ixl_ioctl is called when the user wants to configure the 94161ae650dSJack F Vogel * interface. 94261ae650dSJack F Vogel * 94361ae650dSJack F Vogel * return 0 on success, positive on failure 94461ae650dSJack F Vogel **********************************************************************/ 94561ae650dSJack F Vogel 94661ae650dSJack F Vogel static int 94761ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 94861ae650dSJack F Vogel { 94961ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 950*56c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 95161ae650dSJack F Vogel struct ifreq *ifr = (struct ifreq *) data; 95261ae650dSJack F Vogel #if defined(INET) || defined(INET6) 95361ae650dSJack F Vogel struct ifaddr *ifa = (struct ifaddr *)data; 95461ae650dSJack F Vogel bool avoid_reset = FALSE; 95561ae650dSJack F Vogel #endif 95661ae650dSJack F Vogel int error = 0; 95761ae650dSJack F Vogel 95861ae650dSJack F Vogel switch (command) { 95961ae650dSJack F Vogel 96061ae650dSJack F Vogel case SIOCSIFADDR: 96161ae650dSJack F Vogel #ifdef INET 96261ae650dSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET) 96361ae650dSJack F Vogel avoid_reset = TRUE; 96461ae650dSJack F Vogel #endif 96561ae650dSJack F Vogel #ifdef INET6 96661ae650dSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET6) 96761ae650dSJack F Vogel avoid_reset = TRUE; 96861ae650dSJack F Vogel #endif 96961ae650dSJack F Vogel #if defined(INET) || defined(INET6) 97061ae650dSJack F Vogel /* 97161ae650dSJack F Vogel ** Calling init results in link renegotiation, 97261ae650dSJack F Vogel ** so we avoid doing it when possible. 97361ae650dSJack F Vogel */ 97461ae650dSJack F Vogel if (avoid_reset) { 97561ae650dSJack F Vogel ifp->if_flags |= IFF_UP; 97661ae650dSJack F Vogel if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 97761ae650dSJack F Vogel ixl_init(pf); 9787e0dde7dSBjoern A. Zeeb #ifdef INET 97961ae650dSJack F Vogel if (!(ifp->if_flags & IFF_NOARP)) 98061ae650dSJack F Vogel arp_ifinit(ifp, ifa); 9817e0dde7dSBjoern A. Zeeb #endif 98261ae650dSJack F Vogel } else 98361ae650dSJack F Vogel error = ether_ioctl(ifp, command, data); 98461ae650dSJack F Vogel break; 98561ae650dSJack F Vogel #endif 98661ae650dSJack F Vogel case SIOCSIFMTU: 98761ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 98861ae650dSJack F Vogel if (ifr->ifr_mtu > IXL_MAX_FRAME - 98961ae650dSJack F Vogel ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) { 99061ae650dSJack F Vogel error = EINVAL; 99161ae650dSJack F Vogel } else { 99261ae650dSJack F Vogel IXL_PF_LOCK(pf); 99361ae650dSJack F Vogel ifp->if_mtu = ifr->ifr_mtu; 99461ae650dSJack F Vogel vsi->max_frame_size = 99561ae650dSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 99661ae650dSJack F Vogel + ETHER_VLAN_ENCAP_LEN; 99761ae650dSJack F Vogel ixl_init_locked(pf); 99861ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 99961ae650dSJack F Vogel } 100061ae650dSJack F Vogel break; 100161ae650dSJack F Vogel case SIOCSIFFLAGS: 100261ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 100361ae650dSJack F Vogel IXL_PF_LOCK(pf); 100461ae650dSJack F Vogel if (ifp->if_flags & IFF_UP) { 100561ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 100661ae650dSJack F Vogel if ((ifp->if_flags ^ pf->if_flags) & 100761ae650dSJack F Vogel (IFF_PROMISC | IFF_ALLMULTI)) { 100861ae650dSJack F Vogel ixl_set_promisc(vsi); 100961ae650dSJack F Vogel } 101061ae650dSJack F Vogel } else 101161ae650dSJack F Vogel ixl_init_locked(pf); 101261ae650dSJack F Vogel } else 101361ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) 101461ae650dSJack F Vogel ixl_stop(pf); 101561ae650dSJack F Vogel pf->if_flags = ifp->if_flags; 101661ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 101761ae650dSJack F Vogel break; 101861ae650dSJack F Vogel case SIOCADDMULTI: 101961ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); 102061ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 102161ae650dSJack F Vogel IXL_PF_LOCK(pf); 102261ae650dSJack F Vogel ixl_disable_intr(vsi); 102361ae650dSJack F Vogel ixl_add_multi(vsi); 102461ae650dSJack F Vogel ixl_enable_intr(vsi); 102561ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 102661ae650dSJack F Vogel } 102761ae650dSJack F Vogel break; 102861ae650dSJack F Vogel case SIOCDELMULTI: 102961ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); 103061ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 103161ae650dSJack F Vogel IXL_PF_LOCK(pf); 103261ae650dSJack F Vogel ixl_disable_intr(vsi); 103361ae650dSJack F Vogel ixl_del_multi(vsi); 103461ae650dSJack F Vogel ixl_enable_intr(vsi); 103561ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 103661ae650dSJack F Vogel } 103761ae650dSJack F Vogel break; 103861ae650dSJack F Vogel case SIOCSIFMEDIA: 103961ae650dSJack F Vogel case SIOCGIFMEDIA: 104061ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 104161ae650dSJack F Vogel error = ifmedia_ioctl(ifp, ifr, &vsi->media, command); 104261ae650dSJack F Vogel break; 104361ae650dSJack F Vogel case SIOCSIFCAP: 104461ae650dSJack F Vogel { 104561ae650dSJack F Vogel int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 104661ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 104761ae650dSJack F Vogel 104861ae650dSJack F Vogel ixl_cap_txcsum_tso(vsi, ifp, mask); 104961ae650dSJack F Vogel 105061ae650dSJack F Vogel if (mask & IFCAP_RXCSUM) 105161ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_RXCSUM; 105261ae650dSJack F Vogel if (mask & IFCAP_RXCSUM_IPV6) 105361ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 105461ae650dSJack F Vogel if (mask & IFCAP_LRO) 105561ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_LRO; 105661ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWTAGGING) 105761ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 105861ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWFILTER) 105961ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 106061ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWTSO) 106161ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 106261ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 106361ae650dSJack F Vogel IXL_PF_LOCK(pf); 106461ae650dSJack F Vogel ixl_init_locked(pf); 106561ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 106661ae650dSJack F Vogel } 106761ae650dSJack F Vogel VLAN_CAPABILITIES(ifp); 106861ae650dSJack F Vogel 106961ae650dSJack F Vogel break; 107061ae650dSJack F Vogel } 107161ae650dSJack F Vogel 107261ae650dSJack F Vogel default: 107361ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command); 107461ae650dSJack F Vogel error = ether_ioctl(ifp, command, data); 107561ae650dSJack F Vogel break; 107661ae650dSJack F Vogel } 107761ae650dSJack F Vogel 107861ae650dSJack F Vogel return (error); 107961ae650dSJack F Vogel } 108061ae650dSJack F Vogel 108161ae650dSJack F Vogel 108261ae650dSJack F Vogel /********************************************************************* 108361ae650dSJack F Vogel * Init entry point 108461ae650dSJack F Vogel * 108561ae650dSJack F Vogel * This routine is used in two ways. It is used by the stack as 108661ae650dSJack F Vogel * init entry point in network interface structure. It is also used 108761ae650dSJack F Vogel * by the driver as a hw/sw initialization routine to get to a 108861ae650dSJack F Vogel * consistent state. 108961ae650dSJack F Vogel * 109061ae650dSJack F Vogel * return 0 on success, positive on failure 109161ae650dSJack F Vogel **********************************************************************/ 109261ae650dSJack F Vogel 109361ae650dSJack F Vogel static void 109461ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf) 109561ae650dSJack F Vogel { 109661ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 109761ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 109861ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 109961ae650dSJack F Vogel device_t dev = pf->dev; 110061ae650dSJack F Vogel struct i40e_filter_control_settings filter; 110161ae650dSJack F Vogel u8 tmpaddr[ETHER_ADDR_LEN]; 110261ae650dSJack F Vogel int ret; 110361ae650dSJack F Vogel 110461ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 110561ae650dSJack F Vogel INIT_DEBUGOUT("ixl_init: begin"); 110661ae650dSJack F Vogel ixl_stop(pf); 110761ae650dSJack F Vogel 110861ae650dSJack F Vogel /* Get the latest mac address... User might use a LAA */ 110961ae650dSJack F Vogel bcopy(IF_LLADDR(vsi->ifp), tmpaddr, 111061ae650dSJack F Vogel I40E_ETH_LENGTH_OF_ADDRESS); 111161ae650dSJack F Vogel if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && 111261ae650dSJack F Vogel i40e_validate_mac_addr(tmpaddr)) { 111361ae650dSJack F Vogel bcopy(tmpaddr, hw->mac.addr, 111461ae650dSJack F Vogel I40E_ETH_LENGTH_OF_ADDRESS); 111561ae650dSJack F Vogel ret = i40e_aq_mac_address_write(hw, 111661ae650dSJack F Vogel I40E_AQC_WRITE_TYPE_LAA_ONLY, 111761ae650dSJack F Vogel hw->mac.addr, NULL); 111861ae650dSJack F Vogel if (ret) { 111961ae650dSJack F Vogel device_printf(dev, "LLA address" 112061ae650dSJack F Vogel "change failed!!\n"); 112161ae650dSJack F Vogel return; 112261ae650dSJack F Vogel } 112361ae650dSJack F Vogel } 112461ae650dSJack F Vogel 112561ae650dSJack F Vogel /* Set the various hardware offload abilities */ 112661ae650dSJack F Vogel ifp->if_hwassist = 0; 112761ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TSO) 112861ae650dSJack F Vogel ifp->if_hwassist |= CSUM_TSO; 112961ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM) 113061ae650dSJack F Vogel ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 113161ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 113261ae650dSJack F Vogel ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); 113361ae650dSJack F Vogel 113461ae650dSJack F Vogel /* Set up the device filtering */ 113561ae650dSJack F Vogel bzero(&filter, sizeof(filter)); 113661ae650dSJack F Vogel filter.enable_ethtype = TRUE; 113761ae650dSJack F Vogel filter.enable_macvlan = TRUE; 113861ae650dSJack F Vogel #ifdef IXL_FDIR 113961ae650dSJack F Vogel filter.enable_fdir = TRUE; 114061ae650dSJack F Vogel #endif 114161ae650dSJack F Vogel if (i40e_set_filter_control(hw, &filter)) 114261ae650dSJack F Vogel device_printf(dev, "set_filter_control() failed\n"); 114361ae650dSJack F Vogel 114461ae650dSJack F Vogel /* Set up RSS */ 114561ae650dSJack F Vogel ixl_config_rss(vsi); 114661ae650dSJack F Vogel 114761ae650dSJack F Vogel /* 1148b6c8f260SJack F Vogel ** Prepare the VSI: rings, hmc contexts, etc... 114961ae650dSJack F Vogel */ 115061ae650dSJack F Vogel if (ixl_initialize_vsi(vsi)) { 115161ae650dSJack F Vogel device_printf(dev, "initialize vsi failed!!\n"); 115261ae650dSJack F Vogel return; 115361ae650dSJack F Vogel } 115461ae650dSJack F Vogel 115561ae650dSJack F Vogel /* Add protocol filters to list */ 115661ae650dSJack F Vogel ixl_init_filters(vsi); 115761ae650dSJack F Vogel 115861ae650dSJack F Vogel /* Setup vlan's if needed */ 115961ae650dSJack F Vogel ixl_setup_vlan_filters(vsi); 116061ae650dSJack F Vogel 116161ae650dSJack F Vogel /* Start the local timer */ 116261ae650dSJack F Vogel callout_reset(&pf->timer, hz, ixl_local_timer, pf); 116361ae650dSJack F Vogel 116461ae650dSJack F Vogel /* Set up MSI/X routing and the ITR settings */ 116561ae650dSJack F Vogel if (ixl_enable_msix) { 116661ae650dSJack F Vogel ixl_configure_msix(pf); 116761ae650dSJack F Vogel ixl_configure_itr(pf); 116861ae650dSJack F Vogel } else 116961ae650dSJack F Vogel ixl_configure_legacy(pf); 117061ae650dSJack F Vogel 117161ae650dSJack F Vogel ixl_enable_rings(vsi); 117261ae650dSJack F Vogel 117361ae650dSJack F Vogel i40e_aq_set_default_vsi(hw, vsi->seid, NULL); 117461ae650dSJack F Vogel 1175*56c2c47bSJack F Vogel ixl_reconfigure_filters(vsi); 1176*56c2c47bSJack F Vogel 117761ae650dSJack F Vogel /* Set MTU in hardware*/ 117861ae650dSJack F Vogel int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size, 117961ae650dSJack F Vogel TRUE, 0, NULL); 118061ae650dSJack F Vogel if (aq_error) 118161ae650dSJack F Vogel device_printf(vsi->dev, 118261ae650dSJack F Vogel "aq_set_mac_config in init error, code %d\n", 118361ae650dSJack F Vogel aq_error); 118461ae650dSJack F Vogel 118561ae650dSJack F Vogel /* And now turn on interrupts */ 118661ae650dSJack F Vogel ixl_enable_intr(vsi); 118761ae650dSJack F Vogel 118861ae650dSJack F Vogel /* Now inform the stack we're ready */ 118961ae650dSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 119061ae650dSJack F Vogel ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 119161ae650dSJack F Vogel 119261ae650dSJack F Vogel return; 119361ae650dSJack F Vogel } 119461ae650dSJack F Vogel 119561ae650dSJack F Vogel static void 119661ae650dSJack F Vogel ixl_init(void *arg) 119761ae650dSJack F Vogel { 119861ae650dSJack F Vogel struct ixl_pf *pf = arg; 119961ae650dSJack F Vogel 120061ae650dSJack F Vogel IXL_PF_LOCK(pf); 120161ae650dSJack F Vogel ixl_init_locked(pf); 120261ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 120361ae650dSJack F Vogel return; 120461ae650dSJack F Vogel } 120561ae650dSJack F Vogel 120661ae650dSJack F Vogel /* 120761ae650dSJack F Vogel ** 120861ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets 120961ae650dSJack F Vogel ** 121061ae650dSJack F Vogel */ 121161ae650dSJack F Vogel static void 121261ae650dSJack F Vogel ixl_handle_que(void *context, int pending) 121361ae650dSJack F Vogel { 121461ae650dSJack F Vogel struct ixl_queue *que = context; 121561ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 121661ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 121761ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 121861ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 121961ae650dSJack F Vogel bool more; 122061ae650dSJack F Vogel 122161ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 122261ae650dSJack F Vogel more = ixl_rxeof(que, IXL_RX_LIMIT); 122361ae650dSJack F Vogel IXL_TX_LOCK(txr); 122461ae650dSJack F Vogel ixl_txeof(que); 122561ae650dSJack F Vogel if (!drbr_empty(ifp, txr->br)) 122661ae650dSJack F Vogel ixl_mq_start_locked(ifp, txr); 122761ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 122861ae650dSJack F Vogel if (more) { 122961ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->task); 123061ae650dSJack F Vogel return; 123161ae650dSJack F Vogel } 123261ae650dSJack F Vogel } 123361ae650dSJack F Vogel 123461ae650dSJack F Vogel /* Reenable this interrupt - hmmm */ 123561ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 123661ae650dSJack F Vogel return; 123761ae650dSJack F Vogel } 123861ae650dSJack F Vogel 123961ae650dSJack F Vogel 124061ae650dSJack F Vogel /********************************************************************* 124161ae650dSJack F Vogel * 124261ae650dSJack F Vogel * Legacy Interrupt Service routine 124361ae650dSJack F Vogel * 124461ae650dSJack F Vogel **********************************************************************/ 124561ae650dSJack F Vogel void 124661ae650dSJack F Vogel ixl_intr(void *arg) 124761ae650dSJack F Vogel { 124861ae650dSJack F Vogel struct ixl_pf *pf = arg; 124961ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 125061ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 125161ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 125261ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 125361ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 125461ae650dSJack F Vogel u32 reg, icr0, mask; 125561ae650dSJack F Vogel bool more_tx, more_rx; 125661ae650dSJack F Vogel 125761ae650dSJack F Vogel ++que->irqs; 125861ae650dSJack F Vogel 125961ae650dSJack F Vogel /* Protect against spurious interrupts */ 126061ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 126161ae650dSJack F Vogel return; 126261ae650dSJack F Vogel 126361ae650dSJack F Vogel icr0 = rd32(hw, I40E_PFINT_ICR0); 126461ae650dSJack F Vogel 126561ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_DYN_CTL0); 126661ae650dSJack F Vogel reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 126761ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 126861ae650dSJack F Vogel 126961ae650dSJack F Vogel mask = rd32(hw, I40E_PFINT_ICR0_ENA); 127061ae650dSJack F Vogel 1271*56c2c47bSJack F Vogel #ifdef PCI_IOV 1272*56c2c47bSJack F Vogel if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) 1273*56c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->vflr_task); 1274*56c2c47bSJack F Vogel #endif 1275*56c2c47bSJack F Vogel 127661ae650dSJack F Vogel if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) { 127761ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 127861ae650dSJack F Vogel return; 127961ae650dSJack F Vogel } 128061ae650dSJack F Vogel 128161ae650dSJack F Vogel more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 128261ae650dSJack F Vogel 128361ae650dSJack F Vogel IXL_TX_LOCK(txr); 128461ae650dSJack F Vogel more_tx = ixl_txeof(que); 128561ae650dSJack F Vogel if (!drbr_empty(vsi->ifp, txr->br)) 128661ae650dSJack F Vogel more_tx = 1; 128761ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 128861ae650dSJack F Vogel 128961ae650dSJack F Vogel /* re-enable other interrupt causes */ 129061ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, mask); 129161ae650dSJack F Vogel 129261ae650dSJack F Vogel /* And now the queues */ 129361ae650dSJack F Vogel reg = rd32(hw, I40E_QINT_RQCTL(0)); 129461ae650dSJack F Vogel reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; 129561ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(0), reg); 129661ae650dSJack F Vogel 129761ae650dSJack F Vogel reg = rd32(hw, I40E_QINT_TQCTL(0)); 129861ae650dSJack F Vogel reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; 129961ae650dSJack F Vogel reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK; 130061ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(0), reg); 130161ae650dSJack F Vogel 130261ae650dSJack F Vogel ixl_enable_legacy(hw); 130361ae650dSJack F Vogel 130461ae650dSJack F Vogel return; 130561ae650dSJack F Vogel } 130661ae650dSJack F Vogel 130761ae650dSJack F Vogel 130861ae650dSJack F Vogel /********************************************************************* 130961ae650dSJack F Vogel * 131061ae650dSJack F Vogel * MSIX VSI Interrupt Service routine 131161ae650dSJack F Vogel * 131261ae650dSJack F Vogel **********************************************************************/ 131361ae650dSJack F Vogel void 131461ae650dSJack F Vogel ixl_msix_que(void *arg) 131561ae650dSJack F Vogel { 131661ae650dSJack F Vogel struct ixl_queue *que = arg; 131761ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 131861ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 131961ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 132061ae650dSJack F Vogel bool more_tx, more_rx; 132161ae650dSJack F Vogel 132261ae650dSJack F Vogel /* Protect against spurious interrupts */ 132361ae650dSJack F Vogel if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) 132461ae650dSJack F Vogel return; 132561ae650dSJack F Vogel 132661ae650dSJack F Vogel ++que->irqs; 132761ae650dSJack F Vogel 132861ae650dSJack F Vogel more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 132961ae650dSJack F Vogel 133061ae650dSJack F Vogel IXL_TX_LOCK(txr); 133161ae650dSJack F Vogel more_tx = ixl_txeof(que); 133261ae650dSJack F Vogel /* 133361ae650dSJack F Vogel ** Make certain that if the stack 133461ae650dSJack F Vogel ** has anything queued the task gets 133561ae650dSJack F Vogel ** scheduled to handle it. 133661ae650dSJack F Vogel */ 133761ae650dSJack F Vogel if (!drbr_empty(vsi->ifp, txr->br)) 133861ae650dSJack F Vogel more_tx = 1; 133961ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 134061ae650dSJack F Vogel 134161ae650dSJack F Vogel ixl_set_queue_rx_itr(que); 134261ae650dSJack F Vogel ixl_set_queue_tx_itr(que); 134361ae650dSJack F Vogel 134461ae650dSJack F Vogel if (more_tx || more_rx) 134561ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->task); 134661ae650dSJack F Vogel else 134761ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 134861ae650dSJack F Vogel 134961ae650dSJack F Vogel return; 135061ae650dSJack F Vogel } 135161ae650dSJack F Vogel 135261ae650dSJack F Vogel 135361ae650dSJack F Vogel /********************************************************************* 135461ae650dSJack F Vogel * 135561ae650dSJack F Vogel * MSIX Admin Queue Interrupt Service routine 135661ae650dSJack F Vogel * 135761ae650dSJack F Vogel **********************************************************************/ 135861ae650dSJack F Vogel static void 135961ae650dSJack F Vogel ixl_msix_adminq(void *arg) 136061ae650dSJack F Vogel { 136161ae650dSJack F Vogel struct ixl_pf *pf = arg; 136261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 136361ae650dSJack F Vogel u32 reg, mask; 136461ae650dSJack F Vogel 136561ae650dSJack F Vogel ++pf->admin_irq; 136661ae650dSJack F Vogel 136761ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0); 136861ae650dSJack F Vogel mask = rd32(hw, I40E_PFINT_ICR0_ENA); 136961ae650dSJack F Vogel 137061ae650dSJack F Vogel /* Check on the cause */ 137161ae650dSJack F Vogel if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) 137261ae650dSJack F Vogel mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 137361ae650dSJack F Vogel 137461ae650dSJack F Vogel if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) { 137561ae650dSJack F Vogel ixl_handle_mdd_event(pf); 137661ae650dSJack F Vogel mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 137761ae650dSJack F Vogel } 137861ae650dSJack F Vogel 1379*56c2c47bSJack F Vogel #ifdef PCI_IOV 1380*56c2c47bSJack F Vogel if (reg & I40E_PFINT_ICR0_VFLR_MASK) { 138161ae650dSJack F Vogel mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; 1382*56c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->vflr_task); 1383*56c2c47bSJack F Vogel } 1384*56c2c47bSJack F Vogel #endif 138561ae650dSJack F Vogel 138661ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_DYN_CTL0); 138761ae650dSJack F Vogel reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 138861ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 138961ae650dSJack F Vogel 139061ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 139161ae650dSJack F Vogel return; 139261ae650dSJack F Vogel } 139361ae650dSJack F Vogel 139461ae650dSJack F Vogel /********************************************************************* 139561ae650dSJack F Vogel * 139661ae650dSJack F Vogel * Media Ioctl callback 139761ae650dSJack F Vogel * 139861ae650dSJack F Vogel * This routine is called whenever the user queries the status of 139961ae650dSJack F Vogel * the interface using ifconfig. 140061ae650dSJack F Vogel * 140161ae650dSJack F Vogel **********************************************************************/ 140261ae650dSJack F Vogel static void 140361ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 140461ae650dSJack F Vogel { 140561ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 1406*56c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 140761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 140861ae650dSJack F Vogel 140961ae650dSJack F Vogel INIT_DEBUGOUT("ixl_media_status: begin"); 141061ae650dSJack F Vogel IXL_PF_LOCK(pf); 141161ae650dSJack F Vogel 1412*56c2c47bSJack F Vogel hw->phy.get_link_info = TRUE; 1413*56c2c47bSJack F Vogel pf->link_up = i40e_get_link_status(hw); 141461ae650dSJack F Vogel ixl_update_link_status(pf); 141561ae650dSJack F Vogel 141661ae650dSJack F Vogel ifmr->ifm_status = IFM_AVALID; 141761ae650dSJack F Vogel ifmr->ifm_active = IFM_ETHER; 141861ae650dSJack F Vogel 1419*56c2c47bSJack F Vogel if (!pf->link_up) { 142061ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 142161ae650dSJack F Vogel return; 142261ae650dSJack F Vogel } 142361ae650dSJack F Vogel 142461ae650dSJack F Vogel ifmr->ifm_status |= IFM_ACTIVE; 142561ae650dSJack F Vogel /* Hardware is always full-duplex */ 142661ae650dSJack F Vogel ifmr->ifm_active |= IFM_FDX; 142761ae650dSJack F Vogel 142861ae650dSJack F Vogel switch (hw->phy.link_info.phy_type) { 142961ae650dSJack F Vogel /* 100 M */ 143061ae650dSJack F Vogel case I40E_PHY_TYPE_100BASE_TX: 143161ae650dSJack F Vogel ifmr->ifm_active |= IFM_100_TX; 143261ae650dSJack F Vogel break; 143361ae650dSJack F Vogel /* 1 G */ 143461ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_T: 143561ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_T; 143661ae650dSJack F Vogel break; 143761ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_SX: 143861ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_SX; 143961ae650dSJack F Vogel break; 144061ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_LX: 144161ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_LX; 144261ae650dSJack F Vogel break; 144361ae650dSJack F Vogel /* 10 G */ 1444b6c8f260SJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1: 144561ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1_CU: 144661ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_SFPP_CU: 1447b6c8f260SJack F Vogel /* Using this until a real KR media type */ 1448b6c8f260SJack F Vogel case I40E_PHY_TYPE_10GBASE_KR: 1449b6c8f260SJack F Vogel case I40E_PHY_TYPE_10GBASE_KX4: 145061ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX; 145161ae650dSJack F Vogel break; 145261ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_SR: 145361ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_SR; 145461ae650dSJack F Vogel break; 145561ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_LR: 145661ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_LR; 145761ae650dSJack F Vogel break; 145861ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_T: 145961ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_T; 146061ae650dSJack F Vogel break; 146161ae650dSJack F Vogel /* 40 G */ 146261ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_CR4: 146361ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_CR4_CU: 146461ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_CR4; 146561ae650dSJack F Vogel break; 146661ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_SR4: 146761ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_SR4; 146861ae650dSJack F Vogel break; 146961ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_LR4: 147061ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_LR4; 147161ae650dSJack F Vogel break; 1472b6c8f260SJack F Vogel /* 1473b6c8f260SJack F Vogel ** Set these to CR4 because OS does not 1474b6c8f260SJack F Vogel ** have types available yet. 1475b6c8f260SJack F Vogel */ 1476b6c8f260SJack F Vogel case I40E_PHY_TYPE_40GBASE_KR4: 1477b6c8f260SJack F Vogel case I40E_PHY_TYPE_XLAUI: 1478b6c8f260SJack F Vogel case I40E_PHY_TYPE_XLPPI: 1479b6c8f260SJack F Vogel case I40E_PHY_TYPE_40GBASE_AOC: 1480b6c8f260SJack F Vogel ifmr->ifm_active |= IFM_40G_CR4; 1481b6c8f260SJack F Vogel break; 148261ae650dSJack F Vogel default: 148361ae650dSJack F Vogel ifmr->ifm_active |= IFM_UNKNOWN; 148461ae650dSJack F Vogel break; 148561ae650dSJack F Vogel } 148661ae650dSJack F Vogel /* Report flow control status as well */ 148761ae650dSJack F Vogel if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) 148861ae650dSJack F Vogel ifmr->ifm_active |= IFM_ETH_TXPAUSE; 148961ae650dSJack F Vogel if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) 149061ae650dSJack F Vogel ifmr->ifm_active |= IFM_ETH_RXPAUSE; 149161ae650dSJack F Vogel 149261ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 149361ae650dSJack F Vogel 149461ae650dSJack F Vogel return; 149561ae650dSJack F Vogel } 149661ae650dSJack F Vogel 149761ae650dSJack F Vogel /********************************************************************* 149861ae650dSJack F Vogel * 149961ae650dSJack F Vogel * Media Ioctl callback 150061ae650dSJack F Vogel * 150161ae650dSJack F Vogel * This routine is called when the user changes speed/duplex using 150261ae650dSJack F Vogel * media/mediopt option with ifconfig. 150361ae650dSJack F Vogel * 150461ae650dSJack F Vogel **********************************************************************/ 150561ae650dSJack F Vogel static int 150661ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp) 150761ae650dSJack F Vogel { 150861ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 150961ae650dSJack F Vogel struct ifmedia *ifm = &vsi->media; 151061ae650dSJack F Vogel 151161ae650dSJack F Vogel INIT_DEBUGOUT("ixl_media_change: begin"); 151261ae650dSJack F Vogel 151361ae650dSJack F Vogel if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 151461ae650dSJack F Vogel return (EINVAL); 151561ae650dSJack F Vogel 151661ae650dSJack F Vogel if_printf(ifp, "Media change is currently not supported.\n"); 151761ae650dSJack F Vogel 151861ae650dSJack F Vogel return (ENODEV); 151961ae650dSJack F Vogel } 152061ae650dSJack F Vogel 152161ae650dSJack F Vogel 152261ae650dSJack F Vogel #ifdef IXL_FDIR 152361ae650dSJack F Vogel /* 152461ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter 152561ae650dSJack F Vogel ** based on TX flow info that will keep the receive 152661ae650dSJack F Vogel ** portion of the flow on the same queue. Based on the 152761ae650dSJack F Vogel ** implementation this is only available for TCP connections 152861ae650dSJack F Vogel */ 152961ae650dSJack F Vogel void 153061ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype) 153161ae650dSJack F Vogel { 153261ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 153361ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 153461ae650dSJack F Vogel struct i40e_filter_program_desc *FDIR; 153561ae650dSJack F Vogel u32 ptype, dtype; 153661ae650dSJack F Vogel int idx; 153761ae650dSJack F Vogel 153861ae650dSJack F Vogel /* check if ATR is enabled and sample rate */ 153961ae650dSJack F Vogel if ((!ixl_enable_fdir) || (!txr->atr_rate)) 154061ae650dSJack F Vogel return; 154161ae650dSJack F Vogel /* 154261ae650dSJack F Vogel ** We sample all TCP SYN/FIN packets, 154361ae650dSJack F Vogel ** or at the selected sample rate 154461ae650dSJack F Vogel */ 154561ae650dSJack F Vogel txr->atr_count++; 154661ae650dSJack F Vogel if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) && 154761ae650dSJack F Vogel (txr->atr_count < txr->atr_rate)) 154861ae650dSJack F Vogel return; 154961ae650dSJack F Vogel txr->atr_count = 0; 155061ae650dSJack F Vogel 155161ae650dSJack F Vogel /* Get a descriptor to use */ 155261ae650dSJack F Vogel idx = txr->next_avail; 155361ae650dSJack F Vogel FDIR = (struct i40e_filter_program_desc *) &txr->base[idx]; 155461ae650dSJack F Vogel if (++idx == que->num_desc) 155561ae650dSJack F Vogel idx = 0; 155661ae650dSJack F Vogel txr->avail--; 155761ae650dSJack F Vogel txr->next_avail = idx; 155861ae650dSJack F Vogel 155961ae650dSJack F Vogel ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & 156061ae650dSJack F Vogel I40E_TXD_FLTR_QW0_QINDEX_MASK; 156161ae650dSJack F Vogel 156261ae650dSJack F Vogel ptype |= (etype == ETHERTYPE_IP) ? 156361ae650dSJack F Vogel (I40E_FILTER_PCTYPE_NONF_IPV4_TCP << 156461ae650dSJack F Vogel I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) : 156561ae650dSJack F Vogel (I40E_FILTER_PCTYPE_NONF_IPV6_TCP << 156661ae650dSJack F Vogel I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); 156761ae650dSJack F Vogel 156861ae650dSJack F Vogel ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT; 156961ae650dSJack F Vogel 157061ae650dSJack F Vogel dtype = I40E_TX_DESC_DTYPE_FILTER_PROG; 157161ae650dSJack F Vogel 157261ae650dSJack F Vogel /* 157361ae650dSJack F Vogel ** We use the TCP TH_FIN as a trigger to remove 157461ae650dSJack F Vogel ** the filter, otherwise its an update. 157561ae650dSJack F Vogel */ 157661ae650dSJack F Vogel dtype |= (th->th_flags & TH_FIN) ? 157761ae650dSJack F Vogel (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << 157861ae650dSJack F Vogel I40E_TXD_FLTR_QW1_PCMD_SHIFT) : 157961ae650dSJack F Vogel (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << 158061ae650dSJack F Vogel I40E_TXD_FLTR_QW1_PCMD_SHIFT); 158161ae650dSJack F Vogel 158261ae650dSJack F Vogel dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX << 158361ae650dSJack F Vogel I40E_TXD_FLTR_QW1_DEST_SHIFT; 158461ae650dSJack F Vogel 158561ae650dSJack F Vogel dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID << 158661ae650dSJack F Vogel I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT; 158761ae650dSJack F Vogel 158861ae650dSJack F Vogel FDIR->qindex_flex_ptype_vsi = htole32(ptype); 158961ae650dSJack F Vogel FDIR->dtype_cmd_cntindex = htole32(dtype); 159061ae650dSJack F Vogel return; 159161ae650dSJack F Vogel } 159261ae650dSJack F Vogel #endif 159361ae650dSJack F Vogel 159461ae650dSJack F Vogel 159561ae650dSJack F Vogel static void 159661ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi) 159761ae650dSJack F Vogel { 159861ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 159961ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 160061ae650dSJack F Vogel int err, mcnt = 0; 160161ae650dSJack F Vogel bool uni = FALSE, multi = FALSE; 160261ae650dSJack F Vogel 160361ae650dSJack F Vogel if (ifp->if_flags & IFF_ALLMULTI) 160461ae650dSJack F Vogel multi = TRUE; 160561ae650dSJack F Vogel else { /* Need to count the multicast addresses */ 160661ae650dSJack F Vogel struct ifmultiaddr *ifma; 160761ae650dSJack F Vogel if_maddr_rlock(ifp); 160861ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 160961ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 161061ae650dSJack F Vogel continue; 161161ae650dSJack F Vogel if (mcnt == MAX_MULTICAST_ADDR) 161261ae650dSJack F Vogel break; 161361ae650dSJack F Vogel mcnt++; 161461ae650dSJack F Vogel } 161561ae650dSJack F Vogel if_maddr_runlock(ifp); 161661ae650dSJack F Vogel } 161761ae650dSJack F Vogel 161861ae650dSJack F Vogel if (mcnt >= MAX_MULTICAST_ADDR) 161961ae650dSJack F Vogel multi = TRUE; 162061ae650dSJack F Vogel if (ifp->if_flags & IFF_PROMISC) 162161ae650dSJack F Vogel uni = TRUE; 162261ae650dSJack F Vogel 162361ae650dSJack F Vogel err = i40e_aq_set_vsi_unicast_promiscuous(hw, 162461ae650dSJack F Vogel vsi->seid, uni, NULL); 162561ae650dSJack F Vogel err = i40e_aq_set_vsi_multicast_promiscuous(hw, 162661ae650dSJack F Vogel vsi->seid, multi, NULL); 162761ae650dSJack F Vogel return; 162861ae650dSJack F Vogel } 162961ae650dSJack F Vogel 163061ae650dSJack F Vogel /********************************************************************* 163161ae650dSJack F Vogel * Filter Routines 163261ae650dSJack F Vogel * 163361ae650dSJack F Vogel * Routines for multicast and vlan filter management. 163461ae650dSJack F Vogel * 163561ae650dSJack F Vogel *********************************************************************/ 163661ae650dSJack F Vogel static void 163761ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi) 163861ae650dSJack F Vogel { 163961ae650dSJack F Vogel struct ifmultiaddr *ifma; 164061ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 164161ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 164261ae650dSJack F Vogel int mcnt = 0, flags; 164361ae650dSJack F Vogel 164461ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_add_multi: begin"); 164561ae650dSJack F Vogel 164661ae650dSJack F Vogel if_maddr_rlock(ifp); 164761ae650dSJack F Vogel /* 164861ae650dSJack F Vogel ** First just get a count, to decide if we 164961ae650dSJack F Vogel ** we simply use multicast promiscuous. 165061ae650dSJack F Vogel */ 165161ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 165261ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 165361ae650dSJack F Vogel continue; 165461ae650dSJack F Vogel mcnt++; 165561ae650dSJack F Vogel } 165661ae650dSJack F Vogel if_maddr_runlock(ifp); 165761ae650dSJack F Vogel 165861ae650dSJack F Vogel if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { 165961ae650dSJack F Vogel /* delete existing MC filters */ 166061ae650dSJack F Vogel ixl_del_hw_filters(vsi, mcnt); 166161ae650dSJack F Vogel i40e_aq_set_vsi_multicast_promiscuous(hw, 166261ae650dSJack F Vogel vsi->seid, TRUE, NULL); 166361ae650dSJack F Vogel return; 166461ae650dSJack F Vogel } 166561ae650dSJack F Vogel 166661ae650dSJack F Vogel mcnt = 0; 166761ae650dSJack F Vogel if_maddr_rlock(ifp); 166861ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 166961ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 167061ae650dSJack F Vogel continue; 167161ae650dSJack F Vogel ixl_add_mc_filter(vsi, 167261ae650dSJack F Vogel (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); 167361ae650dSJack F Vogel mcnt++; 167461ae650dSJack F Vogel } 167561ae650dSJack F Vogel if_maddr_runlock(ifp); 167661ae650dSJack F Vogel if (mcnt > 0) { 167761ae650dSJack F Vogel flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); 167861ae650dSJack F Vogel ixl_add_hw_filters(vsi, flags, mcnt); 167961ae650dSJack F Vogel } 168061ae650dSJack F Vogel 168161ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_add_multi: end"); 168261ae650dSJack F Vogel return; 168361ae650dSJack F Vogel } 168461ae650dSJack F Vogel 168561ae650dSJack F Vogel static void 168661ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi) 168761ae650dSJack F Vogel { 168861ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 168961ae650dSJack F Vogel struct ifmultiaddr *ifma; 169061ae650dSJack F Vogel struct ixl_mac_filter *f; 169161ae650dSJack F Vogel int mcnt = 0; 169261ae650dSJack F Vogel bool match = FALSE; 169361ae650dSJack F Vogel 169461ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_del_multi: begin"); 169561ae650dSJack F Vogel 169661ae650dSJack F Vogel /* Search for removed multicast addresses */ 169761ae650dSJack F Vogel if_maddr_rlock(ifp); 169861ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 169961ae650dSJack F Vogel if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) { 170061ae650dSJack F Vogel match = FALSE; 170161ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 170261ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 170361ae650dSJack F Vogel continue; 170461ae650dSJack F Vogel u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 170561ae650dSJack F Vogel if (cmp_etheraddr(f->macaddr, mc_addr)) { 170661ae650dSJack F Vogel match = TRUE; 170761ae650dSJack F Vogel break; 170861ae650dSJack F Vogel } 170961ae650dSJack F Vogel } 171061ae650dSJack F Vogel if (match == FALSE) { 171161ae650dSJack F Vogel f->flags |= IXL_FILTER_DEL; 171261ae650dSJack F Vogel mcnt++; 171361ae650dSJack F Vogel } 171461ae650dSJack F Vogel } 171561ae650dSJack F Vogel } 171661ae650dSJack F Vogel if_maddr_runlock(ifp); 171761ae650dSJack F Vogel 171861ae650dSJack F Vogel if (mcnt > 0) 171961ae650dSJack F Vogel ixl_del_hw_filters(vsi, mcnt); 172061ae650dSJack F Vogel } 172161ae650dSJack F Vogel 172261ae650dSJack F Vogel 172361ae650dSJack F Vogel /********************************************************************* 172461ae650dSJack F Vogel * Timer routine 172561ae650dSJack F Vogel * 172661ae650dSJack F Vogel * This routine checks for link status,updates statistics, 172761ae650dSJack F Vogel * and runs the watchdog check. 172861ae650dSJack F Vogel * 172961ae650dSJack F Vogel **********************************************************************/ 173061ae650dSJack F Vogel 173161ae650dSJack F Vogel static void 173261ae650dSJack F Vogel ixl_local_timer(void *arg) 173361ae650dSJack F Vogel { 173461ae650dSJack F Vogel struct ixl_pf *pf = arg; 173561ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 173661ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 173761ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 173861ae650dSJack F Vogel device_t dev = pf->dev; 173961ae650dSJack F Vogel int hung = 0; 174061ae650dSJack F Vogel u32 mask; 174161ae650dSJack F Vogel 174261ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 174361ae650dSJack F Vogel 174461ae650dSJack F Vogel /* Fire off the adminq task */ 174561ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 174661ae650dSJack F Vogel 174761ae650dSJack F Vogel /* Update stats */ 174861ae650dSJack F Vogel ixl_update_stats_counters(pf); 174961ae650dSJack F Vogel 175061ae650dSJack F Vogel /* 175161ae650dSJack F Vogel ** Check status of the queues 175261ae650dSJack F Vogel */ 175361ae650dSJack F Vogel mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | 175461ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); 175561ae650dSJack F Vogel 175661ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++,que++) { 175761ae650dSJack F Vogel /* Any queues with outstanding work get a sw irq */ 175861ae650dSJack F Vogel if (que->busy) 175961ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask); 176061ae650dSJack F Vogel /* 176161ae650dSJack F Vogel ** Each time txeof runs without cleaning, but there 176261ae650dSJack F Vogel ** are uncleaned descriptors it increments busy. If 176361ae650dSJack F Vogel ** we get to 5 we declare it hung. 176461ae650dSJack F Vogel */ 176561ae650dSJack F Vogel if (que->busy == IXL_QUEUE_HUNG) { 176661ae650dSJack F Vogel ++hung; 176761ae650dSJack F Vogel /* Mark the queue as inactive */ 176861ae650dSJack F Vogel vsi->active_queues &= ~((u64)1 << que->me); 176961ae650dSJack F Vogel continue; 177061ae650dSJack F Vogel } else { 177161ae650dSJack F Vogel /* Check if we've come back from hung */ 177261ae650dSJack F Vogel if ((vsi->active_queues & ((u64)1 << que->me)) == 0) 177361ae650dSJack F Vogel vsi->active_queues |= ((u64)1 << que->me); 177461ae650dSJack F Vogel } 177561ae650dSJack F Vogel if (que->busy >= IXL_MAX_TX_BUSY) { 1776393c4bb1SJack F Vogel #ifdef IXL_DEBUG 177761ae650dSJack F Vogel device_printf(dev,"Warning queue %d " 177861ae650dSJack F Vogel "appears to be hung!\n", i); 1779393c4bb1SJack F Vogel #endif 178061ae650dSJack F Vogel que->busy = IXL_QUEUE_HUNG; 178161ae650dSJack F Vogel ++hung; 178261ae650dSJack F Vogel } 178361ae650dSJack F Vogel } 178461ae650dSJack F Vogel /* Only reinit if all queues show hung */ 178561ae650dSJack F Vogel if (hung == vsi->num_queues) 178661ae650dSJack F Vogel goto hung; 178761ae650dSJack F Vogel 178861ae650dSJack F Vogel callout_reset(&pf->timer, hz, ixl_local_timer, pf); 178961ae650dSJack F Vogel return; 179061ae650dSJack F Vogel 179161ae650dSJack F Vogel hung: 179261ae650dSJack F Vogel device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n"); 179361ae650dSJack F Vogel ixl_init_locked(pf); 179461ae650dSJack F Vogel } 179561ae650dSJack F Vogel 179661ae650dSJack F Vogel /* 179761ae650dSJack F Vogel ** Note: this routine updates the OS on the link state 179861ae650dSJack F Vogel ** the real check of the hardware only happens with 179961ae650dSJack F Vogel ** a link interrupt. 180061ae650dSJack F Vogel */ 180161ae650dSJack F Vogel static void 180261ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf) 180361ae650dSJack F Vogel { 180461ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 180561ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 180661ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 180761ae650dSJack F Vogel device_t dev = pf->dev; 180861ae650dSJack F Vogel 1809*56c2c47bSJack F Vogel if (pf->link_up){ 181061ae650dSJack F Vogel if (vsi->link_active == FALSE) { 1811b6c8f260SJack F Vogel pf->fc = hw->fc.current_mode; 181261ae650dSJack F Vogel if (bootverbose) { 181361ae650dSJack F Vogel device_printf(dev,"Link is up %d Gbps %s," 181461ae650dSJack F Vogel " Flow Control: %s\n", 1815*56c2c47bSJack F Vogel ((pf->link_speed == 1816*56c2c47bSJack F Vogel I40E_LINK_SPEED_40GB)? 40:10), 1817b6c8f260SJack F Vogel "Full Duplex", ixl_fc_string[pf->fc]); 181861ae650dSJack F Vogel } 181961ae650dSJack F Vogel vsi->link_active = TRUE; 1820393c4bb1SJack F Vogel /* 1821393c4bb1SJack F Vogel ** Warn user if link speed on NPAR enabled 1822393c4bb1SJack F Vogel ** partition is not at least 10GB 1823393c4bb1SJack F Vogel */ 1824393c4bb1SJack F Vogel if (hw->func_caps.npar_enable && 1825*56c2c47bSJack F Vogel (hw->phy.link_info.link_speed == 1826*56c2c47bSJack F Vogel I40E_LINK_SPEED_1GB || 1827*56c2c47bSJack F Vogel hw->phy.link_info.link_speed == 1828*56c2c47bSJack F Vogel I40E_LINK_SPEED_100MB)) 1829*56c2c47bSJack F Vogel device_printf(dev, "The partition detected" 1830*56c2c47bSJack F Vogel "link speed that is less than 10Gbps\n"); 183161ae650dSJack F Vogel if_link_state_change(ifp, LINK_STATE_UP); 183261ae650dSJack F Vogel } 183361ae650dSJack F Vogel } else { /* Link down */ 183461ae650dSJack F Vogel if (vsi->link_active == TRUE) { 183561ae650dSJack F Vogel if (bootverbose) 183661ae650dSJack F Vogel device_printf(dev,"Link is Down\n"); 183761ae650dSJack F Vogel if_link_state_change(ifp, LINK_STATE_DOWN); 183861ae650dSJack F Vogel vsi->link_active = FALSE; 183961ae650dSJack F Vogel } 184061ae650dSJack F Vogel } 184161ae650dSJack F Vogel 184261ae650dSJack F Vogel return; 184361ae650dSJack F Vogel } 184461ae650dSJack F Vogel 184561ae650dSJack F Vogel /********************************************************************* 184661ae650dSJack F Vogel * 184761ae650dSJack F Vogel * This routine disables all traffic on the adapter by issuing a 184861ae650dSJack F Vogel * global reset on the MAC and deallocates TX/RX buffers. 184961ae650dSJack F Vogel * 185061ae650dSJack F Vogel **********************************************************************/ 185161ae650dSJack F Vogel 185261ae650dSJack F Vogel static void 185361ae650dSJack F Vogel ixl_stop(struct ixl_pf *pf) 185461ae650dSJack F Vogel { 185561ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 185661ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 185761ae650dSJack F Vogel 185861ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 185961ae650dSJack F Vogel 186061ae650dSJack F Vogel INIT_DEBUGOUT("ixl_stop: begin\n"); 1861*56c2c47bSJack F Vogel if (pf->num_vfs == 0) 186261ae650dSJack F Vogel ixl_disable_intr(vsi); 1863*56c2c47bSJack F Vogel else 1864*56c2c47bSJack F Vogel ixl_disable_rings_intr(vsi); 186561ae650dSJack F Vogel ixl_disable_rings(vsi); 186661ae650dSJack F Vogel 186761ae650dSJack F Vogel /* Tell the stack that the interface is no longer active */ 186861ae650dSJack F Vogel ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 186961ae650dSJack F Vogel 187061ae650dSJack F Vogel /* Stop the local timer */ 187161ae650dSJack F Vogel callout_stop(&pf->timer); 187261ae650dSJack F Vogel 187361ae650dSJack F Vogel return; 187461ae650dSJack F Vogel } 187561ae650dSJack F Vogel 187661ae650dSJack F Vogel 187761ae650dSJack F Vogel /********************************************************************* 187861ae650dSJack F Vogel * 187961ae650dSJack F Vogel * Setup MSIX Interrupt resources and handlers for the VSI 188061ae650dSJack F Vogel * 188161ae650dSJack F Vogel **********************************************************************/ 188261ae650dSJack F Vogel static int 188361ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf) 188461ae650dSJack F Vogel { 188561ae650dSJack F Vogel device_t dev = pf->dev; 188661ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 188761ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 188861ae650dSJack F Vogel int error, rid = 0; 188961ae650dSJack F Vogel 189061ae650dSJack F Vogel if (pf->msix == 1) 189161ae650dSJack F Vogel rid = 1; 189261ae650dSJack F Vogel pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 189361ae650dSJack F Vogel &rid, RF_SHAREABLE | RF_ACTIVE); 189461ae650dSJack F Vogel if (pf->res == NULL) { 189561ae650dSJack F Vogel device_printf(dev,"Unable to allocate" 189661ae650dSJack F Vogel " bus resource: vsi legacy/msi interrupt\n"); 189761ae650dSJack F Vogel return (ENXIO); 189861ae650dSJack F Vogel } 189961ae650dSJack F Vogel 190061ae650dSJack F Vogel /* Set the handler function */ 190161ae650dSJack F Vogel error = bus_setup_intr(dev, pf->res, 190261ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 190361ae650dSJack F Vogel ixl_intr, pf, &pf->tag); 190461ae650dSJack F Vogel if (error) { 190561ae650dSJack F Vogel pf->res = NULL; 190661ae650dSJack F Vogel device_printf(dev, "Failed to register legacy/msi handler"); 190761ae650dSJack F Vogel return (error); 190861ae650dSJack F Vogel } 190961ae650dSJack F Vogel bus_describe_intr(dev, pf->res, pf->tag, "irq0"); 191061ae650dSJack F Vogel TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 191161ae650dSJack F Vogel TASK_INIT(&que->task, 0, ixl_handle_que, que); 191261ae650dSJack F Vogel que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 191361ae650dSJack F Vogel taskqueue_thread_enqueue, &que->tq); 191461ae650dSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 191561ae650dSJack F Vogel device_get_nameunit(dev)); 191661ae650dSJack F Vogel TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 1917*56c2c47bSJack F Vogel 1918*56c2c47bSJack F Vogel #ifdef PCI_IOV 1919*56c2c47bSJack F Vogel TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf); 1920*56c2c47bSJack F Vogel #endif 1921*56c2c47bSJack F Vogel 192261ae650dSJack F Vogel pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 192361ae650dSJack F Vogel taskqueue_thread_enqueue, &pf->tq); 192461ae650dSJack F Vogel taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 192561ae650dSJack F Vogel device_get_nameunit(dev)); 192661ae650dSJack F Vogel 192761ae650dSJack F Vogel return (0); 192861ae650dSJack F Vogel } 192961ae650dSJack F Vogel 193061ae650dSJack F Vogel 193161ae650dSJack F Vogel /********************************************************************* 193261ae650dSJack F Vogel * 193361ae650dSJack F Vogel * Setup MSIX Interrupt resources and handlers for the VSI 193461ae650dSJack F Vogel * 193561ae650dSJack F Vogel **********************************************************************/ 193661ae650dSJack F Vogel static int 193761ae650dSJack F Vogel ixl_assign_vsi_msix(struct ixl_pf *pf) 193861ae650dSJack F Vogel { 193961ae650dSJack F Vogel device_t dev = pf->dev; 194061ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 194161ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 194261ae650dSJack F Vogel struct tx_ring *txr; 194361ae650dSJack F Vogel int error, rid, vector = 0; 19449756bd59SAdrian Chadd #ifdef RSS 19459756bd59SAdrian Chadd cpuset_t cpu_mask; 19469756bd59SAdrian Chadd #endif 194761ae650dSJack F Vogel 194861ae650dSJack F Vogel /* Admin Que is vector 0*/ 194961ae650dSJack F Vogel rid = vector + 1; 195061ae650dSJack F Vogel pf->res = bus_alloc_resource_any(dev, 195161ae650dSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 195261ae650dSJack F Vogel if (!pf->res) { 195361ae650dSJack F Vogel device_printf(dev,"Unable to allocate" 195461ae650dSJack F Vogel " bus resource: Adminq interrupt [%d]\n", rid); 195561ae650dSJack F Vogel return (ENXIO); 195661ae650dSJack F Vogel } 195761ae650dSJack F Vogel /* Set the adminq vector and handler */ 195861ae650dSJack F Vogel error = bus_setup_intr(dev, pf->res, 195961ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 196061ae650dSJack F Vogel ixl_msix_adminq, pf, &pf->tag); 196161ae650dSJack F Vogel if (error) { 196261ae650dSJack F Vogel pf->res = NULL; 196361ae650dSJack F Vogel device_printf(dev, "Failed to register Admin que handler"); 196461ae650dSJack F Vogel return (error); 196561ae650dSJack F Vogel } 196661ae650dSJack F Vogel bus_describe_intr(dev, pf->res, pf->tag, "aq"); 196761ae650dSJack F Vogel pf->admvec = vector; 196861ae650dSJack F Vogel /* Tasklet for Admin Queue */ 196961ae650dSJack F Vogel TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 1970*56c2c47bSJack F Vogel 1971*56c2c47bSJack F Vogel #ifdef PCI_IOV 1972*56c2c47bSJack F Vogel TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf); 1973*56c2c47bSJack F Vogel #endif 1974*56c2c47bSJack F Vogel 197561ae650dSJack F Vogel pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 197661ae650dSJack F Vogel taskqueue_thread_enqueue, &pf->tq); 197761ae650dSJack F Vogel taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 197861ae650dSJack F Vogel device_get_nameunit(pf->dev)); 197961ae650dSJack F Vogel ++vector; 198061ae650dSJack F Vogel 198161ae650dSJack F Vogel /* Now set up the stations */ 198261ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { 1983393c4bb1SJack F Vogel int cpu_id = i; 198461ae650dSJack F Vogel rid = vector + 1; 198561ae650dSJack F Vogel txr = &que->txr; 198661ae650dSJack F Vogel que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 198761ae650dSJack F Vogel RF_SHAREABLE | RF_ACTIVE); 198861ae650dSJack F Vogel if (que->res == NULL) { 198961ae650dSJack F Vogel device_printf(dev,"Unable to allocate" 199061ae650dSJack F Vogel " bus resource: que interrupt [%d]\n", vector); 199161ae650dSJack F Vogel return (ENXIO); 199261ae650dSJack F Vogel } 199361ae650dSJack F Vogel /* Set the handler function */ 199461ae650dSJack F Vogel error = bus_setup_intr(dev, que->res, 199561ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 199661ae650dSJack F Vogel ixl_msix_que, que, &que->tag); 199761ae650dSJack F Vogel if (error) { 199861ae650dSJack F Vogel que->res = NULL; 199961ae650dSJack F Vogel device_printf(dev, "Failed to register que handler"); 200061ae650dSJack F Vogel return (error); 200161ae650dSJack F Vogel } 200261ae650dSJack F Vogel bus_describe_intr(dev, que->res, que->tag, "q%d", i); 200361ae650dSJack F Vogel /* Bind the vector to a CPU */ 2004393c4bb1SJack F Vogel #ifdef RSS 2005393c4bb1SJack F Vogel cpu_id = rss_getcpu(i % rss_getnumbuckets()); 2006393c4bb1SJack F Vogel #endif 2007393c4bb1SJack F Vogel bus_bind_intr(dev, que->res, cpu_id); 200861ae650dSJack F Vogel que->msix = vector; 200961ae650dSJack F Vogel TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 201061ae650dSJack F Vogel TASK_INIT(&que->task, 0, ixl_handle_que, que); 201161ae650dSJack F Vogel que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 201261ae650dSJack F Vogel taskqueue_thread_enqueue, &que->tq); 2013393c4bb1SJack F Vogel #ifdef RSS 2014977dc4e2SAdrian Chadd CPU_SETOF(cpu_id, &cpu_mask); 20159756bd59SAdrian Chadd taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, 20169756bd59SAdrian Chadd &cpu_mask, "%s (bucket %d)", 2017393c4bb1SJack F Vogel device_get_nameunit(dev), cpu_id); 2018393c4bb1SJack F Vogel #else 2019393c4bb1SJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, 2020393c4bb1SJack F Vogel "%s que", device_get_nameunit(dev)); 2021393c4bb1SJack F Vogel #endif 202261ae650dSJack F Vogel } 202361ae650dSJack F Vogel 202461ae650dSJack F Vogel return (0); 202561ae650dSJack F Vogel } 202661ae650dSJack F Vogel 202761ae650dSJack F Vogel 202861ae650dSJack F Vogel /* 202961ae650dSJack F Vogel * Allocate MSI/X vectors 203061ae650dSJack F Vogel */ 203161ae650dSJack F Vogel static int 203261ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf) 203361ae650dSJack F Vogel { 203461ae650dSJack F Vogel device_t dev = pf->dev; 203561ae650dSJack F Vogel int rid, want, vectors, queues, available; 203661ae650dSJack F Vogel 203761ae650dSJack F Vogel /* Override by tuneable */ 203861ae650dSJack F Vogel if (ixl_enable_msix == 0) 203961ae650dSJack F Vogel goto msi; 204061ae650dSJack F Vogel 204161ae650dSJack F Vogel /* 204261ae650dSJack F Vogel ** When used in a virtualized environment 204361ae650dSJack F Vogel ** PCI BUSMASTER capability may not be set 204461ae650dSJack F Vogel ** so explicity set it here and rewrite 204561ae650dSJack F Vogel ** the ENABLE in the MSIX control register 204661ae650dSJack F Vogel ** at this point to cause the host to 204761ae650dSJack F Vogel ** successfully initialize us. 204861ae650dSJack F Vogel */ 204961ae650dSJack F Vogel { 205061ae650dSJack F Vogel u16 pci_cmd_word; 205161ae650dSJack F Vogel int msix_ctrl; 205261ae650dSJack F Vogel pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); 205361ae650dSJack F Vogel pci_cmd_word |= PCIM_CMD_BUSMASTEREN; 205461ae650dSJack F Vogel pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); 205561ae650dSJack F Vogel pci_find_cap(dev, PCIY_MSIX, &rid); 205661ae650dSJack F Vogel rid += PCIR_MSIX_CTRL; 205761ae650dSJack F Vogel msix_ctrl = pci_read_config(dev, rid, 2); 205861ae650dSJack F Vogel msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; 205961ae650dSJack F Vogel pci_write_config(dev, rid, msix_ctrl, 2); 206061ae650dSJack F Vogel } 206161ae650dSJack F Vogel 206261ae650dSJack F Vogel /* First try MSI/X */ 206361ae650dSJack F Vogel rid = PCIR_BAR(IXL_BAR); 206461ae650dSJack F Vogel pf->msix_mem = bus_alloc_resource_any(dev, 206561ae650dSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 206661ae650dSJack F Vogel if (!pf->msix_mem) { 206761ae650dSJack F Vogel /* May not be enabled */ 206861ae650dSJack F Vogel device_printf(pf->dev, 206961ae650dSJack F Vogel "Unable to map MSIX table \n"); 207061ae650dSJack F Vogel goto msi; 207161ae650dSJack F Vogel } 207261ae650dSJack F Vogel 207361ae650dSJack F Vogel available = pci_msix_count(dev); 207461ae650dSJack F Vogel if (available == 0) { /* system has msix disabled */ 207561ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 207661ae650dSJack F Vogel rid, pf->msix_mem); 207761ae650dSJack F Vogel pf->msix_mem = NULL; 207861ae650dSJack F Vogel goto msi; 207961ae650dSJack F Vogel } 208061ae650dSJack F Vogel 208161ae650dSJack F Vogel /* Figure out a reasonable auto config value */ 208261ae650dSJack F Vogel queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus; 208361ae650dSJack F Vogel 208461ae650dSJack F Vogel /* Override with hardcoded value if sane */ 208561ae650dSJack F Vogel if ((ixl_max_queues != 0) && (ixl_max_queues <= queues)) 208661ae650dSJack F Vogel queues = ixl_max_queues; 208761ae650dSJack F Vogel 2088393c4bb1SJack F Vogel #ifdef RSS 2089393c4bb1SJack F Vogel /* If we're doing RSS, clamp at the number of RSS buckets */ 2090393c4bb1SJack F Vogel if (queues > rss_getnumbuckets()) 2091393c4bb1SJack F Vogel queues = rss_getnumbuckets(); 2092393c4bb1SJack F Vogel #endif 2093393c4bb1SJack F Vogel 209461ae650dSJack F Vogel /* 209561ae650dSJack F Vogel ** Want one vector (RX/TX pair) per queue 209661ae650dSJack F Vogel ** plus an additional for the admin queue. 209761ae650dSJack F Vogel */ 209861ae650dSJack F Vogel want = queues + 1; 209961ae650dSJack F Vogel if (want <= available) /* Have enough */ 210061ae650dSJack F Vogel vectors = want; 210161ae650dSJack F Vogel else { 210261ae650dSJack F Vogel device_printf(pf->dev, 210361ae650dSJack F Vogel "MSIX Configuration Problem, " 210461ae650dSJack F Vogel "%d vectors available but %d wanted!\n", 210561ae650dSJack F Vogel available, want); 210661ae650dSJack F Vogel return (0); /* Will go to Legacy setup */ 210761ae650dSJack F Vogel } 210861ae650dSJack F Vogel 210961ae650dSJack F Vogel if (pci_alloc_msix(dev, &vectors) == 0) { 211061ae650dSJack F Vogel device_printf(pf->dev, 211161ae650dSJack F Vogel "Using MSIX interrupts with %d vectors\n", vectors); 211261ae650dSJack F Vogel pf->msix = vectors; 211361ae650dSJack F Vogel pf->vsi.num_queues = queues; 2114393c4bb1SJack F Vogel #ifdef RSS 2115393c4bb1SJack F Vogel /* 2116393c4bb1SJack F Vogel * If we're doing RSS, the number of queues needs to 2117393c4bb1SJack F Vogel * match the number of RSS buckets that are configured. 2118393c4bb1SJack F Vogel * 2119393c4bb1SJack F Vogel * + If there's more queues than RSS buckets, we'll end 2120393c4bb1SJack F Vogel * up with queues that get no traffic. 2121393c4bb1SJack F Vogel * 2122393c4bb1SJack F Vogel * + If there's more RSS buckets than queues, we'll end 2123393c4bb1SJack F Vogel * up having multiple RSS buckets map to the same queue, 2124393c4bb1SJack F Vogel * so there'll be some contention. 2125393c4bb1SJack F Vogel */ 2126393c4bb1SJack F Vogel if (queues != rss_getnumbuckets()) { 2127393c4bb1SJack F Vogel device_printf(dev, 2128393c4bb1SJack F Vogel "%s: queues (%d) != RSS buckets (%d)" 2129393c4bb1SJack F Vogel "; performance will be impacted.\n", 2130393c4bb1SJack F Vogel __func__, queues, rss_getnumbuckets()); 2131393c4bb1SJack F Vogel } 2132393c4bb1SJack F Vogel #endif 213361ae650dSJack F Vogel return (vectors); 213461ae650dSJack F Vogel } 213561ae650dSJack F Vogel msi: 213661ae650dSJack F Vogel vectors = pci_msi_count(dev); 213761ae650dSJack F Vogel pf->vsi.num_queues = 1; 213861ae650dSJack F Vogel pf->msix = 1; 213961ae650dSJack F Vogel ixl_max_queues = 1; 214061ae650dSJack F Vogel ixl_enable_msix = 0; 214161ae650dSJack F Vogel if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) 214261ae650dSJack F Vogel device_printf(pf->dev,"Using an MSI interrupt\n"); 214361ae650dSJack F Vogel else { 214461ae650dSJack F Vogel pf->msix = 0; 214561ae650dSJack F Vogel device_printf(pf->dev,"Using a Legacy interrupt\n"); 214661ae650dSJack F Vogel } 214761ae650dSJack F Vogel return (vectors); 214861ae650dSJack F Vogel } 214961ae650dSJack F Vogel 215061ae650dSJack F Vogel 215161ae650dSJack F Vogel /* 215261ae650dSJack F Vogel * Plumb MSI/X vectors 215361ae650dSJack F Vogel */ 215461ae650dSJack F Vogel static void 215561ae650dSJack F Vogel ixl_configure_msix(struct ixl_pf *pf) 215661ae650dSJack F Vogel { 215761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 215861ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 215961ae650dSJack F Vogel u32 reg; 216061ae650dSJack F Vogel u16 vector = 1; 216161ae650dSJack F Vogel 216261ae650dSJack F Vogel /* First set up the adminq - vector 0 */ 216361ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, 0); /* disable all */ 216461ae650dSJack F Vogel rd32(hw, I40E_PFINT_ICR0); /* read to clear */ 216561ae650dSJack F Vogel 216661ae650dSJack F Vogel reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | 216761ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_GRST_MASK | 216861ae650dSJack F Vogel I40E_PFINT_ICR0_HMC_ERR_MASK | 216961ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_ADMINQ_MASK | 217061ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK | 217161ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_VFLR_MASK | 217261ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK; 217361ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 217461ae650dSJack F Vogel 217561ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLST0, 0x7FF); 217661ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x003E); 217761ae650dSJack F Vogel 217861ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, 217961ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK | 218061ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK); 218161ae650dSJack F Vogel 218261ae650dSJack F Vogel wr32(hw, I40E_PFINT_STAT_CTL0, 0); 218361ae650dSJack F Vogel 218461ae650dSJack F Vogel /* Next configure the queues */ 218561ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, vector++) { 218661ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(i), i); 218761ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLSTN(i), i); 218861ae650dSJack F Vogel 218961ae650dSJack F Vogel reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | 219061ae650dSJack F Vogel (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | 219161ae650dSJack F Vogel (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 219261ae650dSJack F Vogel (i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 219361ae650dSJack F Vogel (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); 219461ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(i), reg); 219561ae650dSJack F Vogel 219661ae650dSJack F Vogel reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK | 219761ae650dSJack F Vogel (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | 219861ae650dSJack F Vogel (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | 219961ae650dSJack F Vogel ((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | 220061ae650dSJack F Vogel (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 220161ae650dSJack F Vogel if (i == (vsi->num_queues - 1)) 220261ae650dSJack F Vogel reg |= (IXL_QUEUE_EOL 220361ae650dSJack F Vogel << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 220461ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(i), reg); 220561ae650dSJack F Vogel } 220661ae650dSJack F Vogel } 220761ae650dSJack F Vogel 220861ae650dSJack F Vogel /* 220961ae650dSJack F Vogel * Configure for MSI single vector operation 221061ae650dSJack F Vogel */ 221161ae650dSJack F Vogel static void 221261ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf) 221361ae650dSJack F Vogel { 221461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 221561ae650dSJack F Vogel u32 reg; 221661ae650dSJack F Vogel 221761ae650dSJack F Vogel 221861ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(0), 0); 221961ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(1), 0); 222061ae650dSJack F Vogel 222161ae650dSJack F Vogel 222261ae650dSJack F Vogel /* Setup "other" causes */ 222361ae650dSJack F Vogel reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK 222461ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK 222561ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_GRST_MASK 222661ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK 222761ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_GPIO_MASK 222861ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK 222961ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK 223061ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK 223161ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_VFLR_MASK 223261ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_ADMINQ_MASK 223361ae650dSJack F Vogel ; 223461ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 223561ae650dSJack F Vogel 223661ae650dSJack F Vogel /* SW_ITR_IDX = 0, but don't change INTENA */ 223761ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, 223861ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK | 223961ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK); 224061ae650dSJack F Vogel /* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */ 224161ae650dSJack F Vogel wr32(hw, I40E_PFINT_STAT_CTL0, 0); 224261ae650dSJack F Vogel 224361ae650dSJack F Vogel /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ 224461ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLST0, 0); 224561ae650dSJack F Vogel 224661ae650dSJack F Vogel /* Associate the queue pair to the vector and enable the q int */ 224761ae650dSJack F Vogel reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK 224861ae650dSJack F Vogel | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) 224961ae650dSJack F Vogel | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 225061ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(0), reg); 225161ae650dSJack F Vogel 225261ae650dSJack F Vogel reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK 225361ae650dSJack F Vogel | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) 225461ae650dSJack F Vogel | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 225561ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(0), reg); 225661ae650dSJack F Vogel 225761ae650dSJack F Vogel /* Next enable the queue pair */ 225861ae650dSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(0)); 225961ae650dSJack F Vogel reg |= I40E_QTX_ENA_QENA_REQ_MASK; 226061ae650dSJack F Vogel wr32(hw, I40E_QTX_ENA(0), reg); 226161ae650dSJack F Vogel 226261ae650dSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(0)); 226361ae650dSJack F Vogel reg |= I40E_QRX_ENA_QENA_REQ_MASK; 226461ae650dSJack F Vogel wr32(hw, I40E_QRX_ENA(0), reg); 226561ae650dSJack F Vogel } 226661ae650dSJack F Vogel 226761ae650dSJack F Vogel 226861ae650dSJack F Vogel /* 226961ae650dSJack F Vogel * Set the Initial ITR state 227061ae650dSJack F Vogel */ 227161ae650dSJack F Vogel static void 227261ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf) 227361ae650dSJack F Vogel { 227461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 227561ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 227661ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 227761ae650dSJack F Vogel 227861ae650dSJack F Vogel vsi->rx_itr_setting = ixl_rx_itr; 227961ae650dSJack F Vogel if (ixl_dynamic_rx_itr) 228061ae650dSJack F Vogel vsi->rx_itr_setting |= IXL_ITR_DYNAMIC; 228161ae650dSJack F Vogel vsi->tx_itr_setting = ixl_tx_itr; 228261ae650dSJack F Vogel if (ixl_dynamic_tx_itr) 228361ae650dSJack F Vogel vsi->tx_itr_setting |= IXL_ITR_DYNAMIC; 228461ae650dSJack F Vogel 228561ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 228661ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 228761ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 228861ae650dSJack F Vogel 228961ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i), 229061ae650dSJack F Vogel vsi->rx_itr_setting); 229161ae650dSJack F Vogel rxr->itr = vsi->rx_itr_setting; 229261ae650dSJack F Vogel rxr->latency = IXL_AVE_LATENCY; 229361ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i), 229461ae650dSJack F Vogel vsi->tx_itr_setting); 229561ae650dSJack F Vogel txr->itr = vsi->tx_itr_setting; 229661ae650dSJack F Vogel txr->latency = IXL_AVE_LATENCY; 229761ae650dSJack F Vogel } 229861ae650dSJack F Vogel } 229961ae650dSJack F Vogel 230061ae650dSJack F Vogel 230161ae650dSJack F Vogel static int 230261ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf) 230361ae650dSJack F Vogel { 230461ae650dSJack F Vogel int rid; 230561ae650dSJack F Vogel device_t dev = pf->dev; 230661ae650dSJack F Vogel 230761ae650dSJack F Vogel rid = PCIR_BAR(0); 230861ae650dSJack F Vogel pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 230961ae650dSJack F Vogel &rid, RF_ACTIVE); 231061ae650dSJack F Vogel 231161ae650dSJack F Vogel if (!(pf->pci_mem)) { 231261ae650dSJack F Vogel device_printf(dev,"Unable to allocate bus resource: memory\n"); 231361ae650dSJack F Vogel return (ENXIO); 231461ae650dSJack F Vogel } 231561ae650dSJack F Vogel 231661ae650dSJack F Vogel pf->osdep.mem_bus_space_tag = 231761ae650dSJack F Vogel rman_get_bustag(pf->pci_mem); 231861ae650dSJack F Vogel pf->osdep.mem_bus_space_handle = 231961ae650dSJack F Vogel rman_get_bushandle(pf->pci_mem); 232061ae650dSJack F Vogel pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); 2321cf3c0c32SRyan Stone pf->osdep.flush_reg = I40E_GLGEN_STAT; 232261ae650dSJack F Vogel pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; 232361ae650dSJack F Vogel 232461ae650dSJack F Vogel pf->hw.back = &pf->osdep; 232561ae650dSJack F Vogel 232661ae650dSJack F Vogel /* 232761ae650dSJack F Vogel ** Now setup MSI or MSI/X, should 232861ae650dSJack F Vogel ** return us the number of supported 232961ae650dSJack F Vogel ** vectors. (Will be 1 for MSI) 233061ae650dSJack F Vogel */ 233161ae650dSJack F Vogel pf->msix = ixl_init_msix(pf); 233261ae650dSJack F Vogel return (0); 233361ae650dSJack F Vogel } 233461ae650dSJack F Vogel 233561ae650dSJack F Vogel static void 233661ae650dSJack F Vogel ixl_free_pci_resources(struct ixl_pf * pf) 233761ae650dSJack F Vogel { 233861ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 233961ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 234061ae650dSJack F Vogel device_t dev = pf->dev; 234161ae650dSJack F Vogel int rid, memrid; 234261ae650dSJack F Vogel 234361ae650dSJack F Vogel memrid = PCIR_BAR(IXL_BAR); 234461ae650dSJack F Vogel 234561ae650dSJack F Vogel /* We may get here before stations are setup */ 234661ae650dSJack F Vogel if ((!ixl_enable_msix) || (que == NULL)) 234761ae650dSJack F Vogel goto early; 234861ae650dSJack F Vogel 234961ae650dSJack F Vogel /* 235061ae650dSJack F Vogel ** Release all msix VSI resources: 235161ae650dSJack F Vogel */ 235261ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 235361ae650dSJack F Vogel rid = que->msix + 1; 235461ae650dSJack F Vogel if (que->tag != NULL) { 235561ae650dSJack F Vogel bus_teardown_intr(dev, que->res, que->tag); 235661ae650dSJack F Vogel que->tag = NULL; 235761ae650dSJack F Vogel } 235861ae650dSJack F Vogel if (que->res != NULL) 235961ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 236061ae650dSJack F Vogel } 236161ae650dSJack F Vogel 236261ae650dSJack F Vogel early: 236361ae650dSJack F Vogel /* Clean the AdminQ interrupt last */ 236461ae650dSJack F Vogel if (pf->admvec) /* we are doing MSIX */ 236561ae650dSJack F Vogel rid = pf->admvec + 1; 236661ae650dSJack F Vogel else 236761ae650dSJack F Vogel (pf->msix != 0) ? (rid = 1):(rid = 0); 236861ae650dSJack F Vogel 236961ae650dSJack F Vogel if (pf->tag != NULL) { 237061ae650dSJack F Vogel bus_teardown_intr(dev, pf->res, pf->tag); 237161ae650dSJack F Vogel pf->tag = NULL; 237261ae650dSJack F Vogel } 237361ae650dSJack F Vogel if (pf->res != NULL) 237461ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); 237561ae650dSJack F Vogel 237661ae650dSJack F Vogel if (pf->msix) 237761ae650dSJack F Vogel pci_release_msi(dev); 237861ae650dSJack F Vogel 237961ae650dSJack F Vogel if (pf->msix_mem != NULL) 238061ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 238161ae650dSJack F Vogel memrid, pf->msix_mem); 238261ae650dSJack F Vogel 238361ae650dSJack F Vogel if (pf->pci_mem != NULL) 238461ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 238561ae650dSJack F Vogel PCIR_BAR(0), pf->pci_mem); 238661ae650dSJack F Vogel 238761ae650dSJack F Vogel return; 238861ae650dSJack F Vogel } 238961ae650dSJack F Vogel 2390e5100ee2SJack F Vogel static void 2391e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type) 2392e5100ee2SJack F Vogel { 2393e5100ee2SJack F Vogel /* Display supported media types */ 2394e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX)) 2395e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2396e5100ee2SJack F Vogel 2397e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T)) 2398e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); 2399*56c2c47bSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_SX)) 2400*56c2c47bSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 2401*56c2c47bSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_LX)) 2402*56c2c47bSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL); 2403e5100ee2SJack F Vogel 2404e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) || 2405b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4) || 2406b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR) || 2407b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) || 2408b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XAUI) || 2409b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XFI) || 2410b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_SFI) || 2411e5100ee2SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU)) 2412e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2413b6c8f260SJack F Vogel 2414e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR)) 2415e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2416e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR)) 2417e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2418e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T)) 2419e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2420e5100ee2SJack F Vogel 2421b6c8f260SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) || 2422b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) || 2423b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) || 2424b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XLAUI) || 2425b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XLPPI) || 2426b6c8f260SJack F Vogel /* KR4 uses CR4 until the OS has the real media type */ 2427b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2428e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2429b6c8f260SJack F Vogel 2430e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4)) 2431e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2432e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4)) 2433e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); 2434e5100ee2SJack F Vogel } 243561ae650dSJack F Vogel 243661ae650dSJack F Vogel /********************************************************************* 243761ae650dSJack F Vogel * 243861ae650dSJack F Vogel * Setup networking device structure and register an interface. 243961ae650dSJack F Vogel * 244061ae650dSJack F Vogel **********************************************************************/ 244161ae650dSJack F Vogel static int 244261ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi) 244361ae650dSJack F Vogel { 244461ae650dSJack F Vogel struct ifnet *ifp; 244561ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 244661ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 2447b6c8f260SJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 244861ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 244961ae650dSJack F Vogel 245061ae650dSJack F Vogel INIT_DEBUGOUT("ixl_setup_interface: begin"); 245161ae650dSJack F Vogel 245261ae650dSJack F Vogel ifp = vsi->ifp = if_alloc(IFT_ETHER); 245361ae650dSJack F Vogel if (ifp == NULL) { 245461ae650dSJack F Vogel device_printf(dev, "can not allocate ifnet structure\n"); 245561ae650dSJack F Vogel return (-1); 245661ae650dSJack F Vogel } 245761ae650dSJack F Vogel if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 245861ae650dSJack F Vogel ifp->if_mtu = ETHERMTU; 245961ae650dSJack F Vogel ifp->if_baudrate = 4000000000; // ?? 246061ae650dSJack F Vogel ifp->if_init = ixl_init; 246161ae650dSJack F Vogel ifp->if_softc = vsi; 246261ae650dSJack F Vogel ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 246361ae650dSJack F Vogel ifp->if_ioctl = ixl_ioctl; 246461ae650dSJack F Vogel 2465e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036 24664b443922SGleb Smirnoff if_setgetcounterfn(ifp, ixl_get_counter); 24674b443922SGleb Smirnoff #endif 24684b443922SGleb Smirnoff 246961ae650dSJack F Vogel ifp->if_transmit = ixl_mq_start; 247061ae650dSJack F Vogel 247161ae650dSJack F Vogel ifp->if_qflush = ixl_qflush; 247261ae650dSJack F Vogel 247361ae650dSJack F Vogel ifp->if_snd.ifq_maxlen = que->num_desc - 2; 247461ae650dSJack F Vogel 247561ae650dSJack F Vogel vsi->max_frame_size = 247661ae650dSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 247761ae650dSJack F Vogel + ETHER_VLAN_ENCAP_LEN; 247861ae650dSJack F Vogel 247961ae650dSJack F Vogel /* 248061ae650dSJack F Vogel * Tell the upper layer(s) we support long frames. 248161ae650dSJack F Vogel */ 24821bffa951SGleb Smirnoff ifp->if_hdrlen = sizeof(struct ether_vlan_header); 248361ae650dSJack F Vogel 248461ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM; 248561ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; 248661ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_TSO; 248761ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_JUMBO_MTU; 248861ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_LRO; 248961ae650dSJack F Vogel 249061ae650dSJack F Vogel /* VLAN capabilties */ 249161ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 249261ae650dSJack F Vogel | IFCAP_VLAN_HWTSO 249361ae650dSJack F Vogel | IFCAP_VLAN_MTU 249461ae650dSJack F Vogel | IFCAP_VLAN_HWCSUM; 249561ae650dSJack F Vogel ifp->if_capenable = ifp->if_capabilities; 249661ae650dSJack F Vogel 249761ae650dSJack F Vogel /* 249861ae650dSJack F Vogel ** Don't turn this on by default, if vlans are 249961ae650dSJack F Vogel ** created on another pseudo device (eg. lagg) 250061ae650dSJack F Vogel ** then vlan events are not passed thru, breaking 250161ae650dSJack F Vogel ** operation, but with HW FILTER off it works. If 250261ae650dSJack F Vogel ** using vlans directly on the ixl driver you can 250361ae650dSJack F Vogel ** enable this and get full hardware tag filtering. 250461ae650dSJack F Vogel */ 250561ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 250661ae650dSJack F Vogel 250761ae650dSJack F Vogel /* 250861ae650dSJack F Vogel * Specify the media types supported by this adapter and register 250961ae650dSJack F Vogel * callbacks to update media and link information 251061ae650dSJack F Vogel */ 251161ae650dSJack F Vogel ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change, 251261ae650dSJack F Vogel ixl_media_status); 251361ae650dSJack F Vogel 2514b6c8f260SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 2515b6c8f260SJack F Vogel FALSE, TRUE, &abilities, NULL); 2516b6c8f260SJack F Vogel /* May need delay to detect fiber correctly */ 2517e5100ee2SJack F Vogel if (aq_error == I40E_ERR_UNKNOWN_PHY) { 2518e5100ee2SJack F Vogel i40e_msec_delay(200); 2519393c4bb1SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, 2520b6c8f260SJack F Vogel TRUE, &abilities, NULL); 2521b6c8f260SJack F Vogel } 2522b6c8f260SJack F Vogel if (aq_error) { 2523e5100ee2SJack F Vogel if (aq_error == I40E_ERR_UNKNOWN_PHY) 2524e5100ee2SJack F Vogel device_printf(dev, "Unknown PHY type detected!\n"); 2525e5100ee2SJack F Vogel else 2526b6c8f260SJack F Vogel device_printf(dev, 2527b6c8f260SJack F Vogel "Error getting supported media types, err %d," 2528e5100ee2SJack F Vogel " AQ error %d\n", aq_error, hw->aq.asq_last_status); 2529b6c8f260SJack F Vogel return (0); 2530b6c8f260SJack F Vogel } 2531b6c8f260SJack F Vogel 2532b6c8f260SJack F Vogel ixl_add_ifmedia(vsi, abilities.phy_type); 253361ae650dSJack F Vogel 253461ae650dSJack F Vogel /* Use autoselect media by default */ 253561ae650dSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); 253661ae650dSJack F Vogel ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); 253761ae650dSJack F Vogel 2538e5100ee2SJack F Vogel ether_ifattach(ifp, hw->mac.addr); 2539e5100ee2SJack F Vogel 254061ae650dSJack F Vogel return (0); 254161ae650dSJack F Vogel } 254261ae650dSJack F Vogel 2543*56c2c47bSJack F Vogel /* 2544*56c2c47bSJack F Vogel ** Run when the Admin Queue gets a 2545*56c2c47bSJack F Vogel ** link transition interrupt. 2546*56c2c47bSJack F Vogel */ 2547*56c2c47bSJack F Vogel static void 2548*56c2c47bSJack F Vogel ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e) 254961ae650dSJack F Vogel { 2550*56c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 2551*56c2c47bSJack F Vogel struct i40e_aqc_get_link_status *status = 2552*56c2c47bSJack F Vogel (struct i40e_aqc_get_link_status *)&e->desc.params.raw; 255361ae650dSJack F Vogel bool check; 255461ae650dSJack F Vogel 2555*56c2c47bSJack F Vogel hw->phy.get_link_info = TRUE; 255661ae650dSJack F Vogel check = i40e_get_link_status(hw); 2557*56c2c47bSJack F Vogel pf->link_up = check; 255861ae650dSJack F Vogel #ifdef IXL_DEBUG 255961ae650dSJack F Vogel printf("Link is %s\n", check ? "up":"down"); 256061ae650dSJack F Vogel #endif 2561*56c2c47bSJack F Vogel /* Report if Unqualified modules are found */ 2562*56c2c47bSJack F Vogel if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) && 2563*56c2c47bSJack F Vogel (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) && 2564*56c2c47bSJack F Vogel (!(status->link_info & I40E_AQ_LINK_UP))) 2565*56c2c47bSJack F Vogel device_printf(pf->dev, "Link failed because " 2566*56c2c47bSJack F Vogel "an unqualified module was detected\n"); 2567*56c2c47bSJack F Vogel 2568*56c2c47bSJack F Vogel return; 256961ae650dSJack F Vogel } 257061ae650dSJack F Vogel 257161ae650dSJack F Vogel /********************************************************************* 257261ae650dSJack F Vogel * 2573b6c8f260SJack F Vogel * Get Firmware Switch configuration 2574b6c8f260SJack F Vogel * - this will need to be more robust when more complex 2575b6c8f260SJack F Vogel * switch configurations are enabled. 257661ae650dSJack F Vogel * 257761ae650dSJack F Vogel **********************************************************************/ 257861ae650dSJack F Vogel static int 2579b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf) 258061ae650dSJack F Vogel { 2581b6c8f260SJack F Vogel struct i40e_hw *hw = &pf->hw; 2582b6c8f260SJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 258361ae650dSJack F Vogel device_t dev = vsi->dev; 258461ae650dSJack F Vogel struct i40e_aqc_get_switch_config_resp *sw_config; 258561ae650dSJack F Vogel u8 aq_buf[I40E_AQ_LARGE_BUF]; 2586*56c2c47bSJack F Vogel int ret; 258761ae650dSJack F Vogel u16 next = 0; 258861ae650dSJack F Vogel 2589b6c8f260SJack F Vogel memset(&aq_buf, 0, sizeof(aq_buf)); 259061ae650dSJack F Vogel sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 259161ae650dSJack F Vogel ret = i40e_aq_get_switch_config(hw, sw_config, 259261ae650dSJack F Vogel sizeof(aq_buf), &next, NULL); 259361ae650dSJack F Vogel if (ret) { 2594*56c2c47bSJack F Vogel device_printf(dev,"aq_get_switch_config failed (ret=%d)!!\n", 2595*56c2c47bSJack F Vogel ret); 259661ae650dSJack F Vogel return (ret); 259761ae650dSJack F Vogel } 259861ae650dSJack F Vogel #ifdef IXL_DEBUG 2599*56c2c47bSJack F Vogel device_printf(dev, 2600*56c2c47bSJack F Vogel "Switch config: header reported: %d in structure, %d total\n", 260161ae650dSJack F Vogel sw_config->header.num_reported, sw_config->header.num_total); 2602*56c2c47bSJack F Vogel for (int i = 0; i < sw_config->header.num_reported; i++) { 2603*56c2c47bSJack F Vogel device_printf(dev, 2604*56c2c47bSJack F Vogel "%d: type=%d seid=%d uplink=%d downlink=%d\n", i, 2605*56c2c47bSJack F Vogel sw_config->element[i].element_type, 2606*56c2c47bSJack F Vogel sw_config->element[i].seid, 2607*56c2c47bSJack F Vogel sw_config->element[i].uplink_seid, 2608*56c2c47bSJack F Vogel sw_config->element[i].downlink_seid); 2609*56c2c47bSJack F Vogel } 261061ae650dSJack F Vogel #endif 2611b6c8f260SJack F Vogel /* Simplified due to a single VSI at the moment */ 2612*56c2c47bSJack F Vogel vsi->uplink_seid = sw_config->element[0].uplink_seid; 2613*56c2c47bSJack F Vogel vsi->downlink_seid = sw_config->element[0].downlink_seid; 261461ae650dSJack F Vogel vsi->seid = sw_config->element[0].seid; 2615b6c8f260SJack F Vogel return (ret); 2616b6c8f260SJack F Vogel } 2617b6c8f260SJack F Vogel 2618b6c8f260SJack F Vogel /********************************************************************* 2619b6c8f260SJack F Vogel * 2620b6c8f260SJack F Vogel * Initialize the VSI: this handles contexts, which means things 2621b6c8f260SJack F Vogel * like the number of descriptors, buffer size, 2622b6c8f260SJack F Vogel * plus we init the rings thru this function. 2623b6c8f260SJack F Vogel * 2624b6c8f260SJack F Vogel **********************************************************************/ 2625b6c8f260SJack F Vogel static int 2626b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi) 2627b6c8f260SJack F Vogel { 2628*56c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 2629b6c8f260SJack F Vogel struct ixl_queue *que = vsi->queues; 2630b6c8f260SJack F Vogel device_t dev = vsi->dev; 2631b6c8f260SJack F Vogel struct i40e_hw *hw = vsi->hw; 2632b6c8f260SJack F Vogel struct i40e_vsi_context ctxt; 2633b6c8f260SJack F Vogel int err = 0; 263461ae650dSJack F Vogel 263561ae650dSJack F Vogel memset(&ctxt, 0, sizeof(ctxt)); 263661ae650dSJack F Vogel ctxt.seid = vsi->seid; 2637*56c2c47bSJack F Vogel if (pf->veb_seid != 0) 2638*56c2c47bSJack F Vogel ctxt.uplink_seid = pf->veb_seid; 263961ae650dSJack F Vogel ctxt.pf_num = hw->pf_id; 2640b6c8f260SJack F Vogel err = i40e_aq_get_vsi_params(hw, &ctxt, NULL); 2641b6c8f260SJack F Vogel if (err) { 2642b6c8f260SJack F Vogel device_printf(dev,"get vsi params failed %x!!\n", err); 2643b6c8f260SJack F Vogel return (err); 264461ae650dSJack F Vogel } 264561ae650dSJack F Vogel #ifdef IXL_DEBUG 264661ae650dSJack F Vogel printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, " 264761ae650dSJack F Vogel "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, " 264861ae650dSJack F Vogel "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid, 264961ae650dSJack F Vogel ctxt.uplink_seid, ctxt.vsi_number, 265061ae650dSJack F Vogel ctxt.vsis_allocated, ctxt.vsis_unallocated, 265161ae650dSJack F Vogel ctxt.flags, ctxt.pf_num, ctxt.vf_num, 265261ae650dSJack F Vogel ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits); 265361ae650dSJack F Vogel #endif 265461ae650dSJack F Vogel /* 265561ae650dSJack F Vogel ** Set the queue and traffic class bits 265661ae650dSJack F Vogel ** - when multiple traffic classes are supported 265761ae650dSJack F Vogel ** this will need to be more robust. 265861ae650dSJack F Vogel */ 265961ae650dSJack F Vogel ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID; 266061ae650dSJack F Vogel ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG; 266161ae650dSJack F Vogel ctxt.info.queue_mapping[0] = 0; 266261ae650dSJack F Vogel ctxt.info.tc_mapping[0] = 0x0800; 266361ae650dSJack F Vogel 266461ae650dSJack F Vogel /* Set VLAN receive stripping mode */ 266561ae650dSJack F Vogel ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; 266661ae650dSJack F Vogel ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; 266761ae650dSJack F Vogel if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 266861ae650dSJack F Vogel ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 266961ae650dSJack F Vogel else 267061ae650dSJack F Vogel ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 267161ae650dSJack F Vogel 267261ae650dSJack F Vogel /* Keep copy of VSI info in VSI for statistic counters */ 267361ae650dSJack F Vogel memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); 267461ae650dSJack F Vogel 267561ae650dSJack F Vogel /* Reset VSI statistics */ 267661ae650dSJack F Vogel ixl_vsi_reset_stats(vsi); 267761ae650dSJack F Vogel vsi->hw_filters_add = 0; 267861ae650dSJack F Vogel vsi->hw_filters_del = 0; 267961ae650dSJack F Vogel 2680*56c2c47bSJack F Vogel ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF); 2681*56c2c47bSJack F Vogel 2682b6c8f260SJack F Vogel err = i40e_aq_update_vsi_params(hw, &ctxt, NULL); 2683b6c8f260SJack F Vogel if (err) { 268461ae650dSJack F Vogel device_printf(dev,"update vsi params failed %x!!\n", 268561ae650dSJack F Vogel hw->aq.asq_last_status); 2686b6c8f260SJack F Vogel return (err); 268761ae650dSJack F Vogel } 268861ae650dSJack F Vogel 268961ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 269061ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 269161ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 269261ae650dSJack F Vogel struct i40e_hmc_obj_txq tctx; 269361ae650dSJack F Vogel struct i40e_hmc_obj_rxq rctx; 269461ae650dSJack F Vogel u32 txctl; 269561ae650dSJack F Vogel u16 size; 269661ae650dSJack F Vogel 269761ae650dSJack F Vogel 269861ae650dSJack F Vogel /* Setup the HMC TX Context */ 269961ae650dSJack F Vogel size = que->num_desc * sizeof(struct i40e_tx_desc); 270061ae650dSJack F Vogel memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq)); 270161ae650dSJack F Vogel tctx.new_context = 1; 2702*56c2c47bSJack F Vogel tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS); 270361ae650dSJack F Vogel tctx.qlen = que->num_desc; 270461ae650dSJack F Vogel tctx.fc_ena = 0; 270561ae650dSJack F Vogel tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */ 270661ae650dSJack F Vogel /* Enable HEAD writeback */ 270761ae650dSJack F Vogel tctx.head_wb_ena = 1; 270861ae650dSJack F Vogel tctx.head_wb_addr = txr->dma.pa + 270961ae650dSJack F Vogel (que->num_desc * sizeof(struct i40e_tx_desc)); 271061ae650dSJack F Vogel tctx.rdylist_act = 0; 271161ae650dSJack F Vogel err = i40e_clear_lan_tx_queue_context(hw, i); 271261ae650dSJack F Vogel if (err) { 271361ae650dSJack F Vogel device_printf(dev, "Unable to clear TX context\n"); 271461ae650dSJack F Vogel break; 271561ae650dSJack F Vogel } 271661ae650dSJack F Vogel err = i40e_set_lan_tx_queue_context(hw, i, &tctx); 271761ae650dSJack F Vogel if (err) { 271861ae650dSJack F Vogel device_printf(dev, "Unable to set TX context\n"); 271961ae650dSJack F Vogel break; 272061ae650dSJack F Vogel } 272161ae650dSJack F Vogel /* Associate the ring with this PF */ 272261ae650dSJack F Vogel txctl = I40E_QTX_CTL_PF_QUEUE; 272361ae650dSJack F Vogel txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & 272461ae650dSJack F Vogel I40E_QTX_CTL_PF_INDX_MASK); 272561ae650dSJack F Vogel wr32(hw, I40E_QTX_CTL(i), txctl); 272661ae650dSJack F Vogel ixl_flush(hw); 272761ae650dSJack F Vogel 272861ae650dSJack F Vogel /* Do ring (re)init */ 272961ae650dSJack F Vogel ixl_init_tx_ring(que); 273061ae650dSJack F Vogel 273161ae650dSJack F Vogel /* Next setup the HMC RX Context */ 2732*56c2c47bSJack F Vogel if (vsi->max_frame_size <= MCLBYTES) 273361ae650dSJack F Vogel rxr->mbuf_sz = MCLBYTES; 273461ae650dSJack F Vogel else 273561ae650dSJack F Vogel rxr->mbuf_sz = MJUMPAGESIZE; 273661ae650dSJack F Vogel 273761ae650dSJack F Vogel u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len; 273861ae650dSJack F Vogel 273961ae650dSJack F Vogel /* Set up an RX context for the HMC */ 274061ae650dSJack F Vogel memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq)); 274161ae650dSJack F Vogel rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT; 274261ae650dSJack F Vogel /* ignore header split for now */ 274361ae650dSJack F Vogel rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; 274461ae650dSJack F Vogel rctx.rxmax = (vsi->max_frame_size < max_rxmax) ? 274561ae650dSJack F Vogel vsi->max_frame_size : max_rxmax; 274661ae650dSJack F Vogel rctx.dtype = 0; 274761ae650dSJack F Vogel rctx.dsize = 1; /* do 32byte descriptors */ 274861ae650dSJack F Vogel rctx.hsplit_0 = 0; /* no HDR split initially */ 2749*56c2c47bSJack F Vogel rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS); 275061ae650dSJack F Vogel rctx.qlen = que->num_desc; 275161ae650dSJack F Vogel rctx.tphrdesc_ena = 1; 275261ae650dSJack F Vogel rctx.tphwdesc_ena = 1; 275361ae650dSJack F Vogel rctx.tphdata_ena = 0; 275461ae650dSJack F Vogel rctx.tphhead_ena = 0; 275561ae650dSJack F Vogel rctx.lrxqthresh = 2; 275661ae650dSJack F Vogel rctx.crcstrip = 1; 275761ae650dSJack F Vogel rctx.l2tsel = 1; 275861ae650dSJack F Vogel rctx.showiv = 1; 275961ae650dSJack F Vogel rctx.fc_ena = 0; 276061ae650dSJack F Vogel rctx.prefena = 1; 276161ae650dSJack F Vogel 276261ae650dSJack F Vogel err = i40e_clear_lan_rx_queue_context(hw, i); 276361ae650dSJack F Vogel if (err) { 276461ae650dSJack F Vogel device_printf(dev, 276561ae650dSJack F Vogel "Unable to clear RX context %d\n", i); 276661ae650dSJack F Vogel break; 276761ae650dSJack F Vogel } 276861ae650dSJack F Vogel err = i40e_set_lan_rx_queue_context(hw, i, &rctx); 276961ae650dSJack F Vogel if (err) { 277061ae650dSJack F Vogel device_printf(dev, "Unable to set RX context %d\n", i); 277161ae650dSJack F Vogel break; 277261ae650dSJack F Vogel } 277361ae650dSJack F Vogel err = ixl_init_rx_ring(que); 277461ae650dSJack F Vogel if (err) { 277561ae650dSJack F Vogel device_printf(dev, "Fail in init_rx_ring %d\n", i); 277661ae650dSJack F Vogel break; 277761ae650dSJack F Vogel } 277861ae650dSJack F Vogel wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0); 277961ae650dSJack F Vogel wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1); 278061ae650dSJack F Vogel } 278161ae650dSJack F Vogel return (err); 278261ae650dSJack F Vogel } 278361ae650dSJack F Vogel 278461ae650dSJack F Vogel 278561ae650dSJack F Vogel /********************************************************************* 278661ae650dSJack F Vogel * 278761ae650dSJack F Vogel * Free all VSI structs. 278861ae650dSJack F Vogel * 278961ae650dSJack F Vogel **********************************************************************/ 279061ae650dSJack F Vogel void 279161ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi) 279261ae650dSJack F Vogel { 279361ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 279461ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 279561ae650dSJack F Vogel 279661ae650dSJack F Vogel /* Free station queues */ 279761ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 279861ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 279961ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 280061ae650dSJack F Vogel 280161ae650dSJack F Vogel if (!mtx_initialized(&txr->mtx)) /* uninitialized */ 280261ae650dSJack F Vogel continue; 280361ae650dSJack F Vogel IXL_TX_LOCK(txr); 280461ae650dSJack F Vogel ixl_free_que_tx(que); 280561ae650dSJack F Vogel if (txr->base) 2806d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &txr->dma); 280761ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 280861ae650dSJack F Vogel IXL_TX_LOCK_DESTROY(txr); 280961ae650dSJack F Vogel 281061ae650dSJack F Vogel if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ 281161ae650dSJack F Vogel continue; 281261ae650dSJack F Vogel IXL_RX_LOCK(rxr); 281361ae650dSJack F Vogel ixl_free_que_rx(que); 281461ae650dSJack F Vogel if (rxr->base) 2815d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &rxr->dma); 281661ae650dSJack F Vogel IXL_RX_UNLOCK(rxr); 281761ae650dSJack F Vogel IXL_RX_LOCK_DESTROY(rxr); 281861ae650dSJack F Vogel 281961ae650dSJack F Vogel } 282061ae650dSJack F Vogel free(vsi->queues, M_DEVBUF); 282161ae650dSJack F Vogel 282261ae650dSJack F Vogel /* Free VSI filter list */ 2823*56c2c47bSJack F Vogel ixl_free_mac_filters(vsi); 2824*56c2c47bSJack F Vogel } 2825*56c2c47bSJack F Vogel 2826*56c2c47bSJack F Vogel static void 2827*56c2c47bSJack F Vogel ixl_free_mac_filters(struct ixl_vsi *vsi) 2828*56c2c47bSJack F Vogel { 2829*56c2c47bSJack F Vogel struct ixl_mac_filter *f; 2830*56c2c47bSJack F Vogel 283161ae650dSJack F Vogel while (!SLIST_EMPTY(&vsi->ftl)) { 283261ae650dSJack F Vogel f = SLIST_FIRST(&vsi->ftl); 283361ae650dSJack F Vogel SLIST_REMOVE_HEAD(&vsi->ftl, next); 283461ae650dSJack F Vogel free(f, M_DEVBUF); 283561ae650dSJack F Vogel } 283661ae650dSJack F Vogel } 283761ae650dSJack F Vogel 283861ae650dSJack F Vogel 283961ae650dSJack F Vogel /********************************************************************* 284061ae650dSJack F Vogel * 284161ae650dSJack F Vogel * Allocate memory for the VSI (virtual station interface) and their 284261ae650dSJack F Vogel * associated queues, rings and the descriptors associated with each, 284361ae650dSJack F Vogel * called only once at attach. 284461ae650dSJack F Vogel * 284561ae650dSJack F Vogel **********************************************************************/ 284661ae650dSJack F Vogel static int 284761ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf) 284861ae650dSJack F Vogel { 284961ae650dSJack F Vogel device_t dev = pf->dev; 285061ae650dSJack F Vogel struct ixl_vsi *vsi; 285161ae650dSJack F Vogel struct ixl_queue *que; 285261ae650dSJack F Vogel struct tx_ring *txr; 285361ae650dSJack F Vogel struct rx_ring *rxr; 285461ae650dSJack F Vogel int rsize, tsize; 285561ae650dSJack F Vogel int error = I40E_SUCCESS; 285661ae650dSJack F Vogel 285761ae650dSJack F Vogel vsi = &pf->vsi; 285861ae650dSJack F Vogel vsi->back = (void *)pf; 285961ae650dSJack F Vogel vsi->hw = &pf->hw; 286061ae650dSJack F Vogel vsi->id = 0; 286161ae650dSJack F Vogel vsi->num_vlans = 0; 2862*56c2c47bSJack F Vogel vsi->back = pf; 286361ae650dSJack F Vogel 286461ae650dSJack F Vogel /* Get memory for the station queues */ 286561ae650dSJack F Vogel if (!(vsi->queues = 286661ae650dSJack F Vogel (struct ixl_queue *) malloc(sizeof(struct ixl_queue) * 286761ae650dSJack F Vogel vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { 286861ae650dSJack F Vogel device_printf(dev, "Unable to allocate queue memory\n"); 286961ae650dSJack F Vogel error = ENOMEM; 287061ae650dSJack F Vogel goto early; 287161ae650dSJack F Vogel } 287261ae650dSJack F Vogel 287361ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 287461ae650dSJack F Vogel que = &vsi->queues[i]; 287561ae650dSJack F Vogel que->num_desc = ixl_ringsz; 287661ae650dSJack F Vogel que->me = i; 287761ae650dSJack F Vogel que->vsi = vsi; 287861ae650dSJack F Vogel /* mark the queue as active */ 287961ae650dSJack F Vogel vsi->active_queues |= (u64)1 << que->me; 288061ae650dSJack F Vogel txr = &que->txr; 288161ae650dSJack F Vogel txr->que = que; 288261ae650dSJack F Vogel txr->tail = I40E_QTX_TAIL(que->me); 288361ae650dSJack F Vogel 288461ae650dSJack F Vogel /* Initialize the TX lock */ 288561ae650dSJack F Vogel snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", 288661ae650dSJack F Vogel device_get_nameunit(dev), que->me); 288761ae650dSJack F Vogel mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF); 288861ae650dSJack F Vogel /* Create the TX descriptor ring */ 288961ae650dSJack F Vogel tsize = roundup2((que->num_desc * 289061ae650dSJack F Vogel sizeof(struct i40e_tx_desc)) + 289161ae650dSJack F Vogel sizeof(u32), DBA_ALIGN); 2892d94ca7cfSBjoern A. Zeeb if (i40e_allocate_dma_mem(&pf->hw, 2893d94ca7cfSBjoern A. Zeeb &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) { 289461ae650dSJack F Vogel device_printf(dev, 289561ae650dSJack F Vogel "Unable to allocate TX Descriptor memory\n"); 289661ae650dSJack F Vogel error = ENOMEM; 289761ae650dSJack F Vogel goto fail; 289861ae650dSJack F Vogel } 289961ae650dSJack F Vogel txr->base = (struct i40e_tx_desc *)txr->dma.va; 290061ae650dSJack F Vogel bzero((void *)txr->base, tsize); 290161ae650dSJack F Vogel /* Now allocate transmit soft structs for the ring */ 290261ae650dSJack F Vogel if (ixl_allocate_tx_data(que)) { 290361ae650dSJack F Vogel device_printf(dev, 290461ae650dSJack F Vogel "Critical Failure setting up TX structures\n"); 290561ae650dSJack F Vogel error = ENOMEM; 290661ae650dSJack F Vogel goto fail; 290761ae650dSJack F Vogel } 290861ae650dSJack F Vogel /* Allocate a buf ring */ 290961ae650dSJack F Vogel txr->br = buf_ring_alloc(4096, M_DEVBUF, 291061ae650dSJack F Vogel M_WAITOK, &txr->mtx); 291161ae650dSJack F Vogel if (txr->br == NULL) { 291261ae650dSJack F Vogel device_printf(dev, 291361ae650dSJack F Vogel "Critical Failure setting up TX buf ring\n"); 291461ae650dSJack F Vogel error = ENOMEM; 291561ae650dSJack F Vogel goto fail; 291661ae650dSJack F Vogel } 291761ae650dSJack F Vogel 291861ae650dSJack F Vogel /* 291961ae650dSJack F Vogel * Next the RX queues... 292061ae650dSJack F Vogel */ 292161ae650dSJack F Vogel rsize = roundup2(que->num_desc * 292261ae650dSJack F Vogel sizeof(union i40e_rx_desc), DBA_ALIGN); 292361ae650dSJack F Vogel rxr = &que->rxr; 292461ae650dSJack F Vogel rxr->que = que; 292561ae650dSJack F Vogel rxr->tail = I40E_QRX_TAIL(que->me); 292661ae650dSJack F Vogel 292761ae650dSJack F Vogel /* Initialize the RX side lock */ 292861ae650dSJack F Vogel snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", 292961ae650dSJack F Vogel device_get_nameunit(dev), que->me); 293061ae650dSJack F Vogel mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF); 293161ae650dSJack F Vogel 2932d94ca7cfSBjoern A. Zeeb if (i40e_allocate_dma_mem(&pf->hw, 2933d94ca7cfSBjoern A. Zeeb &rxr->dma, i40e_mem_reserved, rsize, 4096)) { 293461ae650dSJack F Vogel device_printf(dev, 293561ae650dSJack F Vogel "Unable to allocate RX Descriptor memory\n"); 293661ae650dSJack F Vogel error = ENOMEM; 293761ae650dSJack F Vogel goto fail; 293861ae650dSJack F Vogel } 293961ae650dSJack F Vogel rxr->base = (union i40e_rx_desc *)rxr->dma.va; 294061ae650dSJack F Vogel bzero((void *)rxr->base, rsize); 294161ae650dSJack F Vogel 294261ae650dSJack F Vogel /* Allocate receive soft structs for the ring*/ 294361ae650dSJack F Vogel if (ixl_allocate_rx_data(que)) { 294461ae650dSJack F Vogel device_printf(dev, 294561ae650dSJack F Vogel "Critical Failure setting up receive structs\n"); 294661ae650dSJack F Vogel error = ENOMEM; 294761ae650dSJack F Vogel goto fail; 294861ae650dSJack F Vogel } 294961ae650dSJack F Vogel } 295061ae650dSJack F Vogel 295161ae650dSJack F Vogel return (0); 295261ae650dSJack F Vogel 295361ae650dSJack F Vogel fail: 295461ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 295561ae650dSJack F Vogel que = &vsi->queues[i]; 295661ae650dSJack F Vogel rxr = &que->rxr; 295761ae650dSJack F Vogel txr = &que->txr; 295861ae650dSJack F Vogel if (rxr->base) 2959d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &rxr->dma); 296061ae650dSJack F Vogel if (txr->base) 2961d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &txr->dma); 296261ae650dSJack F Vogel } 296361ae650dSJack F Vogel 296461ae650dSJack F Vogel early: 296561ae650dSJack F Vogel return (error); 296661ae650dSJack F Vogel } 296761ae650dSJack F Vogel 296861ae650dSJack F Vogel /* 296961ae650dSJack F Vogel ** Provide a update to the queue RX 297061ae650dSJack F Vogel ** interrupt moderation value. 297161ae650dSJack F Vogel */ 297261ae650dSJack F Vogel static void 297361ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que) 297461ae650dSJack F Vogel { 297561ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 297661ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 297761ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 297861ae650dSJack F Vogel u16 rx_itr; 297961ae650dSJack F Vogel u16 rx_latency = 0; 298061ae650dSJack F Vogel int rx_bytes; 298161ae650dSJack F Vogel 298261ae650dSJack F Vogel 298361ae650dSJack F Vogel /* Idle, do nothing */ 298461ae650dSJack F Vogel if (rxr->bytes == 0) 298561ae650dSJack F Vogel return; 298661ae650dSJack F Vogel 298761ae650dSJack F Vogel if (ixl_dynamic_rx_itr) { 298861ae650dSJack F Vogel rx_bytes = rxr->bytes/rxr->itr; 298961ae650dSJack F Vogel rx_itr = rxr->itr; 299061ae650dSJack F Vogel 299161ae650dSJack F Vogel /* Adjust latency range */ 299261ae650dSJack F Vogel switch (rxr->latency) { 299361ae650dSJack F Vogel case IXL_LOW_LATENCY: 299461ae650dSJack F Vogel if (rx_bytes > 10) { 299561ae650dSJack F Vogel rx_latency = IXL_AVE_LATENCY; 299661ae650dSJack F Vogel rx_itr = IXL_ITR_20K; 299761ae650dSJack F Vogel } 299861ae650dSJack F Vogel break; 299961ae650dSJack F Vogel case IXL_AVE_LATENCY: 300061ae650dSJack F Vogel if (rx_bytes > 20) { 300161ae650dSJack F Vogel rx_latency = IXL_BULK_LATENCY; 300261ae650dSJack F Vogel rx_itr = IXL_ITR_8K; 300361ae650dSJack F Vogel } else if (rx_bytes <= 10) { 300461ae650dSJack F Vogel rx_latency = IXL_LOW_LATENCY; 300561ae650dSJack F Vogel rx_itr = IXL_ITR_100K; 300661ae650dSJack F Vogel } 300761ae650dSJack F Vogel break; 300861ae650dSJack F Vogel case IXL_BULK_LATENCY: 300961ae650dSJack F Vogel if (rx_bytes <= 20) { 301061ae650dSJack F Vogel rx_latency = IXL_AVE_LATENCY; 301161ae650dSJack F Vogel rx_itr = IXL_ITR_20K; 301261ae650dSJack F Vogel } 301361ae650dSJack F Vogel break; 301461ae650dSJack F Vogel } 301561ae650dSJack F Vogel 301661ae650dSJack F Vogel rxr->latency = rx_latency; 301761ae650dSJack F Vogel 301861ae650dSJack F Vogel if (rx_itr != rxr->itr) { 301961ae650dSJack F Vogel /* do an exponential smoothing */ 302061ae650dSJack F Vogel rx_itr = (10 * rx_itr * rxr->itr) / 302161ae650dSJack F Vogel ((9 * rx_itr) + rxr->itr); 302261ae650dSJack F Vogel rxr->itr = rx_itr & IXL_MAX_ITR; 302361ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 302461ae650dSJack F Vogel que->me), rxr->itr); 302561ae650dSJack F Vogel } 302661ae650dSJack F Vogel } else { /* We may have have toggled to non-dynamic */ 302761ae650dSJack F Vogel if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) 302861ae650dSJack F Vogel vsi->rx_itr_setting = ixl_rx_itr; 302961ae650dSJack F Vogel /* Update the hardware if needed */ 303061ae650dSJack F Vogel if (rxr->itr != vsi->rx_itr_setting) { 303161ae650dSJack F Vogel rxr->itr = vsi->rx_itr_setting; 303261ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 303361ae650dSJack F Vogel que->me), rxr->itr); 303461ae650dSJack F Vogel } 303561ae650dSJack F Vogel } 303661ae650dSJack F Vogel rxr->bytes = 0; 303761ae650dSJack F Vogel rxr->packets = 0; 303861ae650dSJack F Vogel return; 303961ae650dSJack F Vogel } 304061ae650dSJack F Vogel 304161ae650dSJack F Vogel 304261ae650dSJack F Vogel /* 304361ae650dSJack F Vogel ** Provide a update to the queue TX 304461ae650dSJack F Vogel ** interrupt moderation value. 304561ae650dSJack F Vogel */ 304661ae650dSJack F Vogel static void 304761ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que) 304861ae650dSJack F Vogel { 304961ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 305061ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 305161ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 305261ae650dSJack F Vogel u16 tx_itr; 305361ae650dSJack F Vogel u16 tx_latency = 0; 305461ae650dSJack F Vogel int tx_bytes; 305561ae650dSJack F Vogel 305661ae650dSJack F Vogel 305761ae650dSJack F Vogel /* Idle, do nothing */ 305861ae650dSJack F Vogel if (txr->bytes == 0) 305961ae650dSJack F Vogel return; 306061ae650dSJack F Vogel 306161ae650dSJack F Vogel if (ixl_dynamic_tx_itr) { 306261ae650dSJack F Vogel tx_bytes = txr->bytes/txr->itr; 306361ae650dSJack F Vogel tx_itr = txr->itr; 306461ae650dSJack F Vogel 306561ae650dSJack F Vogel switch (txr->latency) { 306661ae650dSJack F Vogel case IXL_LOW_LATENCY: 306761ae650dSJack F Vogel if (tx_bytes > 10) { 306861ae650dSJack F Vogel tx_latency = IXL_AVE_LATENCY; 306961ae650dSJack F Vogel tx_itr = IXL_ITR_20K; 307061ae650dSJack F Vogel } 307161ae650dSJack F Vogel break; 307261ae650dSJack F Vogel case IXL_AVE_LATENCY: 307361ae650dSJack F Vogel if (tx_bytes > 20) { 307461ae650dSJack F Vogel tx_latency = IXL_BULK_LATENCY; 307561ae650dSJack F Vogel tx_itr = IXL_ITR_8K; 307661ae650dSJack F Vogel } else if (tx_bytes <= 10) { 307761ae650dSJack F Vogel tx_latency = IXL_LOW_LATENCY; 307861ae650dSJack F Vogel tx_itr = IXL_ITR_100K; 307961ae650dSJack F Vogel } 308061ae650dSJack F Vogel break; 308161ae650dSJack F Vogel case IXL_BULK_LATENCY: 308261ae650dSJack F Vogel if (tx_bytes <= 20) { 308361ae650dSJack F Vogel tx_latency = IXL_AVE_LATENCY; 308461ae650dSJack F Vogel tx_itr = IXL_ITR_20K; 308561ae650dSJack F Vogel } 308661ae650dSJack F Vogel break; 308761ae650dSJack F Vogel } 308861ae650dSJack F Vogel 308961ae650dSJack F Vogel txr->latency = tx_latency; 309061ae650dSJack F Vogel 309161ae650dSJack F Vogel if (tx_itr != txr->itr) { 309261ae650dSJack F Vogel /* do an exponential smoothing */ 309361ae650dSJack F Vogel tx_itr = (10 * tx_itr * txr->itr) / 309461ae650dSJack F Vogel ((9 * tx_itr) + txr->itr); 309561ae650dSJack F Vogel txr->itr = tx_itr & IXL_MAX_ITR; 309661ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 309761ae650dSJack F Vogel que->me), txr->itr); 309861ae650dSJack F Vogel } 309961ae650dSJack F Vogel 310061ae650dSJack F Vogel } else { /* We may have have toggled to non-dynamic */ 310161ae650dSJack F Vogel if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC) 310261ae650dSJack F Vogel vsi->tx_itr_setting = ixl_tx_itr; 310361ae650dSJack F Vogel /* Update the hardware if needed */ 310461ae650dSJack F Vogel if (txr->itr != vsi->tx_itr_setting) { 310561ae650dSJack F Vogel txr->itr = vsi->tx_itr_setting; 310661ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 310761ae650dSJack F Vogel que->me), txr->itr); 310861ae650dSJack F Vogel } 310961ae650dSJack F Vogel } 311061ae650dSJack F Vogel txr->bytes = 0; 311161ae650dSJack F Vogel txr->packets = 0; 311261ae650dSJack F Vogel return; 311361ae650dSJack F Vogel } 311461ae650dSJack F Vogel 3115*56c2c47bSJack F Vogel #define QUEUE_NAME_LEN 32 3116*56c2c47bSJack F Vogel 3117*56c2c47bSJack F Vogel static void 3118*56c2c47bSJack F Vogel ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi, 3119*56c2c47bSJack F Vogel struct sysctl_ctx_list *ctx, const char *sysctl_name) 3120*56c2c47bSJack F Vogel { 3121*56c2c47bSJack F Vogel struct sysctl_oid *tree; 3122*56c2c47bSJack F Vogel struct sysctl_oid_list *child; 3123*56c2c47bSJack F Vogel struct sysctl_oid_list *vsi_list; 3124*56c2c47bSJack F Vogel 3125*56c2c47bSJack F Vogel tree = device_get_sysctl_tree(pf->dev); 3126*56c2c47bSJack F Vogel child = SYSCTL_CHILDREN(tree); 3127*56c2c47bSJack F Vogel vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name, 3128*56c2c47bSJack F Vogel CTLFLAG_RD, NULL, "VSI Number"); 3129*56c2c47bSJack F Vogel vsi_list = SYSCTL_CHILDREN(vsi->vsi_node); 3130*56c2c47bSJack F Vogel 3131*56c2c47bSJack F Vogel ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats); 3132*56c2c47bSJack F Vogel } 313361ae650dSJack F Vogel 313461ae650dSJack F Vogel static void 313561ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf) 313661ae650dSJack F Vogel { 313761ae650dSJack F Vogel device_t dev = pf->dev; 313861ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 313961ae650dSJack F Vogel struct ixl_queue *queues = vsi->queues; 314061ae650dSJack F Vogel struct i40e_hw_port_stats *pf_stats = &pf->stats; 314161ae650dSJack F Vogel 314261ae650dSJack F Vogel struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 314361ae650dSJack F Vogel struct sysctl_oid *tree = device_get_sysctl_tree(dev); 314461ae650dSJack F Vogel struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 3145*56c2c47bSJack F Vogel struct sysctl_oid_list *vsi_list; 314661ae650dSJack F Vogel 3147*56c2c47bSJack F Vogel struct sysctl_oid *queue_node; 3148*56c2c47bSJack F Vogel struct sysctl_oid_list *queue_list; 314961ae650dSJack F Vogel 315061ae650dSJack F Vogel struct tx_ring *txr; 315161ae650dSJack F Vogel struct rx_ring *rxr; 3152*56c2c47bSJack F Vogel char queue_namebuf[QUEUE_NAME_LEN]; 315361ae650dSJack F Vogel 315461ae650dSJack F Vogel /* Driver statistics */ 315561ae650dSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 315661ae650dSJack F Vogel CTLFLAG_RD, &pf->watchdog_events, 315761ae650dSJack F Vogel "Watchdog timeouts"); 315861ae650dSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq", 315961ae650dSJack F Vogel CTLFLAG_RD, &pf->admin_irq, 316061ae650dSJack F Vogel "Admin Queue IRQ Handled"); 316161ae650dSJack F Vogel 3162*56c2c47bSJack F Vogel SYSCTL_ADD_INT(ctx, child, OID_AUTO, "vc_debug_level", 3163*56c2c47bSJack F Vogel CTLFLAG_RW, &pf->vc_debug_lvl, 0, 3164*56c2c47bSJack F Vogel "PF/VF Virtual Channel debug logging level"); 316561ae650dSJack F Vogel 3166*56c2c47bSJack F Vogel ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf"); 3167*56c2c47bSJack F Vogel vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node); 316861ae650dSJack F Vogel 316961ae650dSJack F Vogel /* Queue statistics */ 317061ae650dSJack F Vogel for (int q = 0; q < vsi->num_queues; q++) { 317161ae650dSJack F Vogel snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); 3172*56c2c47bSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, 3173*56c2c47bSJack F Vogel OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #"); 317461ae650dSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 317561ae650dSJack F Vogel 317661ae650dSJack F Vogel txr = &(queues[q].txr); 317761ae650dSJack F Vogel rxr = &(queues[q].rxr); 317861ae650dSJack F Vogel 317961ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", 318061ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), 318161ae650dSJack F Vogel "m_defrag() failed"); 318261ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped", 318361ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].dropped_pkts), 318461ae650dSJack F Vogel "Driver dropped packets"); 318561ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 318661ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].irqs), 318761ae650dSJack F Vogel "irqs on this queue"); 318861ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", 318961ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].tso), 319061ae650dSJack F Vogel "TSO"); 319161ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup", 319261ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].tx_dma_setup), 319361ae650dSJack F Vogel "Driver tx dma failure in xmit"); 319461ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 319561ae650dSJack F Vogel CTLFLAG_RD, &(txr->no_desc), 319661ae650dSJack F Vogel "Queue No Descriptor Available"); 319761ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 319861ae650dSJack F Vogel CTLFLAG_RD, &(txr->total_packets), 319961ae650dSJack F Vogel "Queue Packets Transmitted"); 320061ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", 320161ae650dSJack F Vogel CTLFLAG_RD, &(txr->tx_bytes), 320261ae650dSJack F Vogel "Queue Bytes Transmitted"); 320361ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 320461ae650dSJack F Vogel CTLFLAG_RD, &(rxr->rx_packets), 320561ae650dSJack F Vogel "Queue Packets Received"); 320661ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 320761ae650dSJack F Vogel CTLFLAG_RD, &(rxr->rx_bytes), 320861ae650dSJack F Vogel "Queue Bytes Received"); 320961ae650dSJack F Vogel } 321061ae650dSJack F Vogel 321161ae650dSJack F Vogel /* MAC stats */ 321261ae650dSJack F Vogel ixl_add_sysctls_mac_stats(ctx, child, pf_stats); 321361ae650dSJack F Vogel } 321461ae650dSJack F Vogel 321561ae650dSJack F Vogel static void 321661ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx, 321761ae650dSJack F Vogel struct sysctl_oid_list *child, 321861ae650dSJack F Vogel struct i40e_eth_stats *eth_stats) 321961ae650dSJack F Vogel { 322061ae650dSJack F Vogel struct ixl_sysctl_info ctls[] = 322161ae650dSJack F Vogel { 322261ae650dSJack F Vogel {ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, 322361ae650dSJack F Vogel {ð_stats->rx_unicast, "ucast_pkts_rcvd", 322461ae650dSJack F Vogel "Unicast Packets Received"}, 322561ae650dSJack F Vogel {ð_stats->rx_multicast, "mcast_pkts_rcvd", 322661ae650dSJack F Vogel "Multicast Packets Received"}, 322761ae650dSJack F Vogel {ð_stats->rx_broadcast, "bcast_pkts_rcvd", 322861ae650dSJack F Vogel "Broadcast Packets Received"}, 322961ae650dSJack F Vogel {ð_stats->rx_discards, "rx_discards", "Discarded RX packets"}, 323061ae650dSJack F Vogel {ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, 323161ae650dSJack F Vogel {ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, 323261ae650dSJack F Vogel {ð_stats->tx_multicast, "mcast_pkts_txd", 323361ae650dSJack F Vogel "Multicast Packets Transmitted"}, 323461ae650dSJack F Vogel {ð_stats->tx_broadcast, "bcast_pkts_txd", 323561ae650dSJack F Vogel "Broadcast Packets Transmitted"}, 323661ae650dSJack F Vogel // end 323761ae650dSJack F Vogel {0,0,0} 323861ae650dSJack F Vogel }; 323961ae650dSJack F Vogel 324061ae650dSJack F Vogel struct ixl_sysctl_info *entry = ctls; 324161ae650dSJack F Vogel while (entry->stat != 0) 324261ae650dSJack F Vogel { 324361ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name, 324461ae650dSJack F Vogel CTLFLAG_RD, entry->stat, 324561ae650dSJack F Vogel entry->description); 324661ae650dSJack F Vogel entry++; 324761ae650dSJack F Vogel } 324861ae650dSJack F Vogel } 324961ae650dSJack F Vogel 325061ae650dSJack F Vogel static void 325161ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx, 325261ae650dSJack F Vogel struct sysctl_oid_list *child, 325361ae650dSJack F Vogel struct i40e_hw_port_stats *stats) 325461ae650dSJack F Vogel { 325561ae650dSJack F Vogel struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", 325661ae650dSJack F Vogel CTLFLAG_RD, NULL, "Mac Statistics"); 325761ae650dSJack F Vogel struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node); 325861ae650dSJack F Vogel 325961ae650dSJack F Vogel struct i40e_eth_stats *eth_stats = &stats->eth; 326061ae650dSJack F Vogel ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats); 326161ae650dSJack F Vogel 326261ae650dSJack F Vogel struct ixl_sysctl_info ctls[] = 326361ae650dSJack F Vogel { 326461ae650dSJack F Vogel {&stats->crc_errors, "crc_errors", "CRC Errors"}, 326561ae650dSJack F Vogel {&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"}, 326661ae650dSJack F Vogel {&stats->mac_local_faults, "local_faults", "MAC Local Faults"}, 326761ae650dSJack F Vogel {&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"}, 326861ae650dSJack F Vogel {&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"}, 326961ae650dSJack F Vogel /* Packet Reception Stats */ 327061ae650dSJack F Vogel {&stats->rx_size_64, "rx_frames_64", "64 byte frames received"}, 327161ae650dSJack F Vogel {&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"}, 327261ae650dSJack F Vogel {&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"}, 327361ae650dSJack F Vogel {&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"}, 327461ae650dSJack F Vogel {&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"}, 327561ae650dSJack F Vogel {&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"}, 327661ae650dSJack F Vogel {&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"}, 327761ae650dSJack F Vogel {&stats->rx_undersize, "rx_undersize", "Undersized packets received"}, 327861ae650dSJack F Vogel {&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"}, 327961ae650dSJack F Vogel {&stats->rx_oversize, "rx_oversized", "Oversized packets received"}, 328061ae650dSJack F Vogel {&stats->rx_jabber, "rx_jabber", "Received Jabber"}, 328161ae650dSJack F Vogel {&stats->checksum_error, "checksum_errors", "Checksum Errors"}, 328261ae650dSJack F Vogel /* Packet Transmission Stats */ 328361ae650dSJack F Vogel {&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"}, 328461ae650dSJack F Vogel {&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"}, 328561ae650dSJack F Vogel {&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"}, 328661ae650dSJack F Vogel {&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"}, 328761ae650dSJack F Vogel {&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"}, 328861ae650dSJack F Vogel {&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"}, 328961ae650dSJack F Vogel {&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"}, 329061ae650dSJack F Vogel /* Flow control */ 329161ae650dSJack F Vogel {&stats->link_xon_tx, "xon_txd", "Link XON transmitted"}, 329261ae650dSJack F Vogel {&stats->link_xon_rx, "xon_recvd", "Link XON received"}, 329361ae650dSJack F Vogel {&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"}, 329461ae650dSJack F Vogel {&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"}, 329561ae650dSJack F Vogel /* End */ 329661ae650dSJack F Vogel {0,0,0} 329761ae650dSJack F Vogel }; 329861ae650dSJack F Vogel 329961ae650dSJack F Vogel struct ixl_sysctl_info *entry = ctls; 330061ae650dSJack F Vogel while (entry->stat != 0) 330161ae650dSJack F Vogel { 330261ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name, 330361ae650dSJack F Vogel CTLFLAG_RD, entry->stat, 330461ae650dSJack F Vogel entry->description); 330561ae650dSJack F Vogel entry++; 330661ae650dSJack F Vogel } 330761ae650dSJack F Vogel } 330861ae650dSJack F Vogel 330961ae650dSJack F Vogel /* 331061ae650dSJack F Vogel ** ixl_config_rss - setup RSS 331161ae650dSJack F Vogel ** - note this is done for the single vsi 331261ae650dSJack F Vogel */ 331361ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *vsi) 331461ae650dSJack F Vogel { 331561ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 331661ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 331761ae650dSJack F Vogel u32 lut = 0; 3318393c4bb1SJack F Vogel u64 set_hena = 0, hena; 3319393c4bb1SJack F Vogel int i, j, que_id; 3320393c4bb1SJack F Vogel #ifdef RSS 3321393c4bb1SJack F Vogel u32 rss_hash_config; 3322393c4bb1SJack F Vogel u32 rss_seed[IXL_KEYSZ]; 3323393c4bb1SJack F Vogel #else 3324393c4bb1SJack F Vogel u32 rss_seed[IXL_KEYSZ] = {0x41b01687, 3325393c4bb1SJack F Vogel 0x183cfd8c, 0xce880440, 0x580cbc3c, 3326393c4bb1SJack F Vogel 0x35897377, 0x328b25e1, 0x4fa98922, 3327393c4bb1SJack F Vogel 0xb7d90c14, 0xd5bad70d, 0xcd15a2c1}; 3328393c4bb1SJack F Vogel #endif 332961ae650dSJack F Vogel 3330393c4bb1SJack F Vogel #ifdef RSS 3331393c4bb1SJack F Vogel /* Fetch the configured RSS key */ 3332393c4bb1SJack F Vogel rss_getkey((uint8_t *) &rss_seed); 3333393c4bb1SJack F Vogel #endif 333461ae650dSJack F Vogel 333561ae650dSJack F Vogel /* Fill out hash function seed */ 3336393c4bb1SJack F Vogel for (i = 0; i < IXL_KEYSZ; i++) 3337393c4bb1SJack F Vogel wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]); 333861ae650dSJack F Vogel 333961ae650dSJack F Vogel /* Enable PCTYPES for RSS: */ 3340393c4bb1SJack F Vogel #ifdef RSS 3341393c4bb1SJack F Vogel rss_hash_config = rss_gethashconfig(); 3342393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 3343393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); 3344393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 3345393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); 3346393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 3347393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP); 3348393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 3349393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); 3350df1d7a71SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 3351df1d7a71SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); 3352393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 3353393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); 3354393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 3355393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP); 3356393c4bb1SJack F Vogel #else 335761ae650dSJack F Vogel set_hena = 335861ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | 335961ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | 336061ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | 336161ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | 336261ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | 336361ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | 336461ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | 336561ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | 336661ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | 336761ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | 336861ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD); 3369393c4bb1SJack F Vogel #endif 337061ae650dSJack F Vogel hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) | 337161ae650dSJack F Vogel ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32); 337261ae650dSJack F Vogel hena |= set_hena; 337361ae650dSJack F Vogel wr32(hw, I40E_PFQF_HENA(0), (u32)hena); 337461ae650dSJack F Vogel wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); 337561ae650dSJack F Vogel 337661ae650dSJack F Vogel /* Populate the LUT with max no. of queues in round robin fashion */ 337761ae650dSJack F Vogel for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) { 337861ae650dSJack F Vogel if (j == vsi->num_queues) 337961ae650dSJack F Vogel j = 0; 3380393c4bb1SJack F Vogel #ifdef RSS 3381393c4bb1SJack F Vogel /* 3382393c4bb1SJack F Vogel * Fetch the RSS bucket id for the given indirection entry. 3383393c4bb1SJack F Vogel * Cap it at the number of configured buckets (which is 3384393c4bb1SJack F Vogel * num_queues.) 3385393c4bb1SJack F Vogel */ 3386393c4bb1SJack F Vogel que_id = rss_get_indirection_to_bucket(i); 3387dcd7b3b2SJack F Vogel que_id = que_id % vsi->num_queues; 3388393c4bb1SJack F Vogel #else 3389393c4bb1SJack F Vogel que_id = j; 3390393c4bb1SJack F Vogel #endif 339161ae650dSJack F Vogel /* lut = 4-byte sliding window of 4 lut entries */ 3392393c4bb1SJack F Vogel lut = (lut << 8) | (que_id & 339361ae650dSJack F Vogel ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1)); 339461ae650dSJack F Vogel /* On i = 3, we have 4 entries in lut; write to the register */ 339561ae650dSJack F Vogel if ((i & 3) == 3) 339661ae650dSJack F Vogel wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); 339761ae650dSJack F Vogel } 339861ae650dSJack F Vogel ixl_flush(hw); 339961ae650dSJack F Vogel } 340061ae650dSJack F Vogel 340161ae650dSJack F Vogel 340261ae650dSJack F Vogel /* 340361ae650dSJack F Vogel ** This routine is run via an vlan config EVENT, 340461ae650dSJack F Vogel ** it enables us to use the HW Filter table since 340561ae650dSJack F Vogel ** we can get the vlan id. This just creates the 340661ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will 340761ae650dSJack F Vogel ** repopulate the real table. 340861ae650dSJack F Vogel */ 340961ae650dSJack F Vogel static void 341061ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 341161ae650dSJack F Vogel { 341261ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 341361ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 341461ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 341561ae650dSJack F Vogel 341661ae650dSJack F Vogel if (ifp->if_softc != arg) /* Not our event */ 341761ae650dSJack F Vogel return; 341861ae650dSJack F Vogel 341961ae650dSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 342061ae650dSJack F Vogel return; 342161ae650dSJack F Vogel 342261ae650dSJack F Vogel IXL_PF_LOCK(pf); 342361ae650dSJack F Vogel ++vsi->num_vlans; 342461ae650dSJack F Vogel ixl_add_filter(vsi, hw->mac.addr, vtag); 342561ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 342661ae650dSJack F Vogel } 342761ae650dSJack F Vogel 342861ae650dSJack F Vogel /* 342961ae650dSJack F Vogel ** This routine is run via an vlan 343061ae650dSJack F Vogel ** unconfig EVENT, remove our entry 343161ae650dSJack F Vogel ** in the soft vfta. 343261ae650dSJack F Vogel */ 343361ae650dSJack F Vogel static void 343461ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 343561ae650dSJack F Vogel { 343661ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 343761ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 343861ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 343961ae650dSJack F Vogel 344061ae650dSJack F Vogel if (ifp->if_softc != arg) 344161ae650dSJack F Vogel return; 344261ae650dSJack F Vogel 344361ae650dSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 344461ae650dSJack F Vogel return; 344561ae650dSJack F Vogel 344661ae650dSJack F Vogel IXL_PF_LOCK(pf); 344761ae650dSJack F Vogel --vsi->num_vlans; 344861ae650dSJack F Vogel ixl_del_filter(vsi, hw->mac.addr, vtag); 344961ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 345061ae650dSJack F Vogel } 345161ae650dSJack F Vogel 345261ae650dSJack F Vogel /* 345361ae650dSJack F Vogel ** This routine updates vlan filters, called by init 345461ae650dSJack F Vogel ** it scans the filter table and then updates the hw 345561ae650dSJack F Vogel ** after a soft reset. 345661ae650dSJack F Vogel */ 345761ae650dSJack F Vogel static void 345861ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi) 345961ae650dSJack F Vogel { 346061ae650dSJack F Vogel struct ixl_mac_filter *f; 346161ae650dSJack F Vogel int cnt = 0, flags; 346261ae650dSJack F Vogel 346361ae650dSJack F Vogel if (vsi->num_vlans == 0) 346461ae650dSJack F Vogel return; 346561ae650dSJack F Vogel /* 346661ae650dSJack F Vogel ** Scan the filter list for vlan entries, 346761ae650dSJack F Vogel ** mark them for addition and then call 346861ae650dSJack F Vogel ** for the AQ update. 346961ae650dSJack F Vogel */ 347061ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 347161ae650dSJack F Vogel if (f->flags & IXL_FILTER_VLAN) { 347261ae650dSJack F Vogel f->flags |= 347361ae650dSJack F Vogel (IXL_FILTER_ADD | 347461ae650dSJack F Vogel IXL_FILTER_USED); 347561ae650dSJack F Vogel cnt++; 347661ae650dSJack F Vogel } 347761ae650dSJack F Vogel } 347861ae650dSJack F Vogel if (cnt == 0) { 347961ae650dSJack F Vogel printf("setup vlan: no filters found!\n"); 348061ae650dSJack F Vogel return; 348161ae650dSJack F Vogel } 348261ae650dSJack F Vogel flags = IXL_FILTER_VLAN; 348361ae650dSJack F Vogel flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 348461ae650dSJack F Vogel ixl_add_hw_filters(vsi, flags, cnt); 348561ae650dSJack F Vogel return; 348661ae650dSJack F Vogel } 348761ae650dSJack F Vogel 348861ae650dSJack F Vogel /* 348961ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware 349061ae650dSJack F Vogel ** needs to know about. 349161ae650dSJack F Vogel */ 349261ae650dSJack F Vogel static void 349361ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi) 349461ae650dSJack F Vogel { 349561ae650dSJack F Vogel /* Add broadcast address */ 3496*56c2c47bSJack F Vogel ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY); 349761ae650dSJack F Vogel } 349861ae650dSJack F Vogel 349961ae650dSJack F Vogel /* 350061ae650dSJack F Vogel ** This routine adds mulicast filters 350161ae650dSJack F Vogel */ 350261ae650dSJack F Vogel static void 350361ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr) 350461ae650dSJack F Vogel { 350561ae650dSJack F Vogel struct ixl_mac_filter *f; 350661ae650dSJack F Vogel 350761ae650dSJack F Vogel /* Does one already exist */ 350861ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 350961ae650dSJack F Vogel if (f != NULL) 351061ae650dSJack F Vogel return; 351161ae650dSJack F Vogel 351261ae650dSJack F Vogel f = ixl_get_filter(vsi); 351361ae650dSJack F Vogel if (f == NULL) { 351461ae650dSJack F Vogel printf("WARNING: no filter available!!\n"); 351561ae650dSJack F Vogel return; 351661ae650dSJack F Vogel } 351761ae650dSJack F Vogel bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 351861ae650dSJack F Vogel f->vlan = IXL_VLAN_ANY; 351961ae650dSJack F Vogel f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED 352061ae650dSJack F Vogel | IXL_FILTER_MC); 352161ae650dSJack F Vogel 352261ae650dSJack F Vogel return; 352361ae650dSJack F Vogel } 352461ae650dSJack F Vogel 3525*56c2c47bSJack F Vogel static void 3526*56c2c47bSJack F Vogel ixl_reconfigure_filters(struct ixl_vsi *vsi) 3527*56c2c47bSJack F Vogel { 3528*56c2c47bSJack F Vogel 3529*56c2c47bSJack F Vogel ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs); 3530*56c2c47bSJack F Vogel } 3531*56c2c47bSJack F Vogel 353261ae650dSJack F Vogel /* 353361ae650dSJack F Vogel ** This routine adds macvlan filters 353461ae650dSJack F Vogel */ 353561ae650dSJack F Vogel static void 353661ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 353761ae650dSJack F Vogel { 353861ae650dSJack F Vogel struct ixl_mac_filter *f, *tmp; 3539*56c2c47bSJack F Vogel struct ixl_pf *pf; 3540*56c2c47bSJack F Vogel device_t dev; 354161ae650dSJack F Vogel 354261ae650dSJack F Vogel DEBUGOUT("ixl_add_filter: begin"); 354361ae650dSJack F Vogel 3544*56c2c47bSJack F Vogel pf = vsi->back; 3545*56c2c47bSJack F Vogel dev = pf->dev; 3546*56c2c47bSJack F Vogel 354761ae650dSJack F Vogel /* Does one already exist */ 354861ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, vlan); 354961ae650dSJack F Vogel if (f != NULL) 355061ae650dSJack F Vogel return; 355161ae650dSJack F Vogel /* 355261ae650dSJack F Vogel ** Is this the first vlan being registered, if so we 355361ae650dSJack F Vogel ** need to remove the ANY filter that indicates we are 355461ae650dSJack F Vogel ** not in a vlan, and replace that with a 0 filter. 355561ae650dSJack F Vogel */ 355661ae650dSJack F Vogel if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) { 355761ae650dSJack F Vogel tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 355861ae650dSJack F Vogel if (tmp != NULL) { 355961ae650dSJack F Vogel ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY); 356061ae650dSJack F Vogel ixl_add_filter(vsi, macaddr, 0); 356161ae650dSJack F Vogel } 356261ae650dSJack F Vogel } 356361ae650dSJack F Vogel 356461ae650dSJack F Vogel f = ixl_get_filter(vsi); 356561ae650dSJack F Vogel if (f == NULL) { 356661ae650dSJack F Vogel device_printf(dev, "WARNING: no filter available!!\n"); 356761ae650dSJack F Vogel return; 356861ae650dSJack F Vogel } 356961ae650dSJack F Vogel bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 357061ae650dSJack F Vogel f->vlan = vlan; 357161ae650dSJack F Vogel f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 357261ae650dSJack F Vogel if (f->vlan != IXL_VLAN_ANY) 357361ae650dSJack F Vogel f->flags |= IXL_FILTER_VLAN; 3574*56c2c47bSJack F Vogel else 3575*56c2c47bSJack F Vogel vsi->num_macs++; 357661ae650dSJack F Vogel 357761ae650dSJack F Vogel ixl_add_hw_filters(vsi, f->flags, 1); 357861ae650dSJack F Vogel return; 357961ae650dSJack F Vogel } 358061ae650dSJack F Vogel 358161ae650dSJack F Vogel static void 358261ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 358361ae650dSJack F Vogel { 358461ae650dSJack F Vogel struct ixl_mac_filter *f; 358561ae650dSJack F Vogel 358661ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, vlan); 358761ae650dSJack F Vogel if (f == NULL) 358861ae650dSJack F Vogel return; 358961ae650dSJack F Vogel 359061ae650dSJack F Vogel f->flags |= IXL_FILTER_DEL; 359161ae650dSJack F Vogel ixl_del_hw_filters(vsi, 1); 3592*56c2c47bSJack F Vogel vsi->num_macs--; 359361ae650dSJack F Vogel 359461ae650dSJack F Vogel /* Check if this is the last vlan removal */ 359561ae650dSJack F Vogel if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) { 359661ae650dSJack F Vogel /* Switch back to a non-vlan filter */ 359761ae650dSJack F Vogel ixl_del_filter(vsi, macaddr, 0); 359861ae650dSJack F Vogel ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY); 359961ae650dSJack F Vogel } 360061ae650dSJack F Vogel return; 360161ae650dSJack F Vogel } 360261ae650dSJack F Vogel 360361ae650dSJack F Vogel /* 360461ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id 360561ae650dSJack F Vogel */ 360661ae650dSJack F Vogel static struct ixl_mac_filter * 360761ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 360861ae650dSJack F Vogel { 360961ae650dSJack F Vogel struct ixl_mac_filter *f; 361061ae650dSJack F Vogel bool match = FALSE; 361161ae650dSJack F Vogel 361261ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 361361ae650dSJack F Vogel if (!cmp_etheraddr(f->macaddr, macaddr)) 361461ae650dSJack F Vogel continue; 361561ae650dSJack F Vogel if (f->vlan == vlan) { 361661ae650dSJack F Vogel match = TRUE; 361761ae650dSJack F Vogel break; 361861ae650dSJack F Vogel } 361961ae650dSJack F Vogel } 362061ae650dSJack F Vogel 362161ae650dSJack F Vogel if (!match) 362261ae650dSJack F Vogel f = NULL; 362361ae650dSJack F Vogel return (f); 362461ae650dSJack F Vogel } 362561ae650dSJack F Vogel 362661ae650dSJack F Vogel /* 362761ae650dSJack F Vogel ** This routine takes additions to the vsi filter 362861ae650dSJack F Vogel ** table and creates an Admin Queue call to create 362961ae650dSJack F Vogel ** the filters in the hardware. 363061ae650dSJack F Vogel */ 363161ae650dSJack F Vogel static void 363261ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt) 363361ae650dSJack F Vogel { 363461ae650dSJack F Vogel struct i40e_aqc_add_macvlan_element_data *a, *b; 363561ae650dSJack F Vogel struct ixl_mac_filter *f; 3636*56c2c47bSJack F Vogel struct ixl_pf *pf; 3637*56c2c47bSJack F Vogel struct i40e_hw *hw; 3638*56c2c47bSJack F Vogel device_t dev; 363961ae650dSJack F Vogel int err, j = 0; 364061ae650dSJack F Vogel 3641*56c2c47bSJack F Vogel pf = vsi->back; 3642*56c2c47bSJack F Vogel dev = pf->dev; 3643*56c2c47bSJack F Vogel hw = &pf->hw; 3644*56c2c47bSJack F Vogel IXL_PF_LOCK_ASSERT(pf); 3645*56c2c47bSJack F Vogel 364661ae650dSJack F Vogel a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt, 364761ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 364861ae650dSJack F Vogel if (a == NULL) { 3649393c4bb1SJack F Vogel device_printf(dev, "add_hw_filters failed to get memory\n"); 365061ae650dSJack F Vogel return; 365161ae650dSJack F Vogel } 365261ae650dSJack F Vogel 365361ae650dSJack F Vogel /* 365461ae650dSJack F Vogel ** Scan the filter list, each time we find one 365561ae650dSJack F Vogel ** we add it to the admin queue array and turn off 365661ae650dSJack F Vogel ** the add bit. 365761ae650dSJack F Vogel */ 365861ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 365961ae650dSJack F Vogel if (f->flags == flags) { 366061ae650dSJack F Vogel b = &a[j]; // a pox on fvl long names :) 366161ae650dSJack F Vogel bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN); 3662*56c2c47bSJack F Vogel if (f->vlan == IXL_VLAN_ANY) { 3663*56c2c47bSJack F Vogel b->vlan_tag = 0; 3664*56c2c47bSJack F Vogel b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN; 3665*56c2c47bSJack F Vogel } else { 3666*56c2c47bSJack F Vogel b->vlan_tag = f->vlan; 3667*56c2c47bSJack F Vogel b->flags = 0; 3668*56c2c47bSJack F Vogel } 3669*56c2c47bSJack F Vogel b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH; 367061ae650dSJack F Vogel f->flags &= ~IXL_FILTER_ADD; 367161ae650dSJack F Vogel j++; 367261ae650dSJack F Vogel } 367361ae650dSJack F Vogel if (j == cnt) 367461ae650dSJack F Vogel break; 367561ae650dSJack F Vogel } 367661ae650dSJack F Vogel if (j > 0) { 367761ae650dSJack F Vogel err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); 367861ae650dSJack F Vogel if (err) 3679b6c8f260SJack F Vogel device_printf(dev, "aq_add_macvlan err %d, " 3680b6c8f260SJack F Vogel "aq_error %d\n", err, hw->aq.asq_last_status); 368161ae650dSJack F Vogel else 368261ae650dSJack F Vogel vsi->hw_filters_add += j; 368361ae650dSJack F Vogel } 368461ae650dSJack F Vogel free(a, M_DEVBUF); 368561ae650dSJack F Vogel return; 368661ae650dSJack F Vogel } 368761ae650dSJack F Vogel 368861ae650dSJack F Vogel /* 368961ae650dSJack F Vogel ** This routine takes removals in the vsi filter 369061ae650dSJack F Vogel ** table and creates an Admin Queue call to delete 369161ae650dSJack F Vogel ** the filters in the hardware. 369261ae650dSJack F Vogel */ 369361ae650dSJack F Vogel static void 369461ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt) 369561ae650dSJack F Vogel { 369661ae650dSJack F Vogel struct i40e_aqc_remove_macvlan_element_data *d, *e; 3697*56c2c47bSJack F Vogel struct ixl_pf *pf; 3698*56c2c47bSJack F Vogel struct i40e_hw *hw; 3699*56c2c47bSJack F Vogel device_t dev; 370061ae650dSJack F Vogel struct ixl_mac_filter *f, *f_temp; 370161ae650dSJack F Vogel int err, j = 0; 370261ae650dSJack F Vogel 370361ae650dSJack F Vogel DEBUGOUT("ixl_del_hw_filters: begin\n"); 370461ae650dSJack F Vogel 3705*56c2c47bSJack F Vogel pf = vsi->back; 3706*56c2c47bSJack F Vogel hw = &pf->hw; 3707*56c2c47bSJack F Vogel dev = pf->dev; 3708*56c2c47bSJack F Vogel 370961ae650dSJack F Vogel d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt, 371061ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 371161ae650dSJack F Vogel if (d == NULL) { 371261ae650dSJack F Vogel printf("del hw filter failed to get memory\n"); 371361ae650dSJack F Vogel return; 371461ae650dSJack F Vogel } 371561ae650dSJack F Vogel 371661ae650dSJack F Vogel SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) { 371761ae650dSJack F Vogel if (f->flags & IXL_FILTER_DEL) { 371861ae650dSJack F Vogel e = &d[j]; // a pox on fvl long names :) 371961ae650dSJack F Vogel bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN); 372061ae650dSJack F Vogel e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan); 372161ae650dSJack F Vogel e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; 372261ae650dSJack F Vogel /* delete entry from vsi list */ 372361ae650dSJack F Vogel SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next); 372461ae650dSJack F Vogel free(f, M_DEVBUF); 372561ae650dSJack F Vogel j++; 372661ae650dSJack F Vogel } 372761ae650dSJack F Vogel if (j == cnt) 372861ae650dSJack F Vogel break; 372961ae650dSJack F Vogel } 373061ae650dSJack F Vogel if (j > 0) { 373161ae650dSJack F Vogel err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); 373261ae650dSJack F Vogel /* NOTE: returns ENOENT every time but seems to work fine, 373361ae650dSJack F Vogel so we'll ignore that specific error. */ 3734393c4bb1SJack F Vogel // TODO: Does this still occur on current firmwares? 373561ae650dSJack F Vogel if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { 373661ae650dSJack F Vogel int sc = 0; 373761ae650dSJack F Vogel for (int i = 0; i < j; i++) 373861ae650dSJack F Vogel sc += (!d[i].error_code); 373961ae650dSJack F Vogel vsi->hw_filters_del += sc; 374061ae650dSJack F Vogel device_printf(dev, 374161ae650dSJack F Vogel "Failed to remove %d/%d filters, aq error %d\n", 374261ae650dSJack F Vogel j - sc, j, hw->aq.asq_last_status); 374361ae650dSJack F Vogel } else 374461ae650dSJack F Vogel vsi->hw_filters_del += j; 374561ae650dSJack F Vogel } 374661ae650dSJack F Vogel free(d, M_DEVBUF); 374761ae650dSJack F Vogel 374861ae650dSJack F Vogel DEBUGOUT("ixl_del_hw_filters: end\n"); 374961ae650dSJack F Vogel return; 375061ae650dSJack F Vogel } 375161ae650dSJack F Vogel 3752*56c2c47bSJack F Vogel static int 375361ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi) 375461ae650dSJack F Vogel { 3755*56c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 3756*56c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 3757*56c2c47bSJack F Vogel int index, error; 375861ae650dSJack F Vogel u32 reg; 375961ae650dSJack F Vogel 3760*56c2c47bSJack F Vogel error = 0; 376161ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 3762*56c2c47bSJack F Vogel index = vsi->first_queue + i; 3763*56c2c47bSJack F Vogel i40e_pre_tx_queue_cfg(hw, index, TRUE); 376461ae650dSJack F Vogel 3765*56c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 376661ae650dSJack F Vogel reg |= I40E_QTX_ENA_QENA_REQ_MASK | 376761ae650dSJack F Vogel I40E_QTX_ENA_QENA_STAT_MASK; 3768*56c2c47bSJack F Vogel wr32(hw, I40E_QTX_ENA(index), reg); 376961ae650dSJack F Vogel /* Verify the enable took */ 377061ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 3771*56c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 377261ae650dSJack F Vogel if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 377361ae650dSJack F Vogel break; 377461ae650dSJack F Vogel i40e_msec_delay(10); 377561ae650dSJack F Vogel } 3776*56c2c47bSJack F Vogel if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) { 3777*56c2c47bSJack F Vogel device_printf(pf->dev, "TX queue %d disabled!\n", 3778*56c2c47bSJack F Vogel index); 3779*56c2c47bSJack F Vogel error = ETIMEDOUT; 3780*56c2c47bSJack F Vogel } 378161ae650dSJack F Vogel 3782*56c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 378361ae650dSJack F Vogel reg |= I40E_QRX_ENA_QENA_REQ_MASK | 378461ae650dSJack F Vogel I40E_QRX_ENA_QENA_STAT_MASK; 3785*56c2c47bSJack F Vogel wr32(hw, I40E_QRX_ENA(index), reg); 378661ae650dSJack F Vogel /* Verify the enable took */ 378761ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 3788*56c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 378961ae650dSJack F Vogel if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 379061ae650dSJack F Vogel break; 379161ae650dSJack F Vogel i40e_msec_delay(10); 379261ae650dSJack F Vogel } 3793*56c2c47bSJack F Vogel if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) { 3794*56c2c47bSJack F Vogel device_printf(pf->dev, "RX queue %d disabled!\n", 3795*56c2c47bSJack F Vogel index); 3796*56c2c47bSJack F Vogel error = ETIMEDOUT; 379761ae650dSJack F Vogel } 379861ae650dSJack F Vogel } 379961ae650dSJack F Vogel 3800*56c2c47bSJack F Vogel return (error); 3801*56c2c47bSJack F Vogel } 3802*56c2c47bSJack F Vogel 3803*56c2c47bSJack F Vogel static int 380461ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi) 380561ae650dSJack F Vogel { 3806*56c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 3807*56c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 3808*56c2c47bSJack F Vogel int index, error; 380961ae650dSJack F Vogel u32 reg; 381061ae650dSJack F Vogel 3811*56c2c47bSJack F Vogel error = 0; 381261ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 3813*56c2c47bSJack F Vogel index = vsi->first_queue + i; 3814*56c2c47bSJack F Vogel 3815*56c2c47bSJack F Vogel i40e_pre_tx_queue_cfg(hw, index, FALSE); 381661ae650dSJack F Vogel i40e_usec_delay(500); 381761ae650dSJack F Vogel 3818*56c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 381961ae650dSJack F Vogel reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; 3820*56c2c47bSJack F Vogel wr32(hw, I40E_QTX_ENA(index), reg); 382161ae650dSJack F Vogel /* Verify the disable took */ 382261ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 3823*56c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 382461ae650dSJack F Vogel if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK)) 382561ae650dSJack F Vogel break; 382661ae650dSJack F Vogel i40e_msec_delay(10); 382761ae650dSJack F Vogel } 3828*56c2c47bSJack F Vogel if (reg & I40E_QTX_ENA_QENA_STAT_MASK) { 3829*56c2c47bSJack F Vogel device_printf(pf->dev, "TX queue %d still enabled!\n", 3830*56c2c47bSJack F Vogel index); 3831*56c2c47bSJack F Vogel error = ETIMEDOUT; 3832*56c2c47bSJack F Vogel } 383361ae650dSJack F Vogel 3834*56c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 383561ae650dSJack F Vogel reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; 3836*56c2c47bSJack F Vogel wr32(hw, I40E_QRX_ENA(index), reg); 383761ae650dSJack F Vogel /* Verify the disable took */ 383861ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 3839*56c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 384061ae650dSJack F Vogel if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK)) 384161ae650dSJack F Vogel break; 384261ae650dSJack F Vogel i40e_msec_delay(10); 384361ae650dSJack F Vogel } 3844*56c2c47bSJack F Vogel if (reg & I40E_QRX_ENA_QENA_STAT_MASK) { 3845*56c2c47bSJack F Vogel device_printf(pf->dev, "RX queue %d still enabled!\n", 3846*56c2c47bSJack F Vogel index); 3847*56c2c47bSJack F Vogel error = ETIMEDOUT; 384861ae650dSJack F Vogel } 384961ae650dSJack F Vogel } 385061ae650dSJack F Vogel 3851*56c2c47bSJack F Vogel return (error); 3852*56c2c47bSJack F Vogel } 3853*56c2c47bSJack F Vogel 385461ae650dSJack F Vogel /** 385561ae650dSJack F Vogel * ixl_handle_mdd_event 385661ae650dSJack F Vogel * 385761ae650dSJack F Vogel * Called from interrupt handler to identify possibly malicious vfs 385861ae650dSJack F Vogel * (But also detects events from the PF, as well) 385961ae650dSJack F Vogel **/ 386061ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *pf) 386161ae650dSJack F Vogel { 386261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 386361ae650dSJack F Vogel device_t dev = pf->dev; 386461ae650dSJack F Vogel bool mdd_detected = false; 386561ae650dSJack F Vogel bool pf_mdd_detected = false; 386661ae650dSJack F Vogel u32 reg; 386761ae650dSJack F Vogel 386861ae650dSJack F Vogel /* find what triggered the MDD event */ 386961ae650dSJack F Vogel reg = rd32(hw, I40E_GL_MDET_TX); 387061ae650dSJack F Vogel if (reg & I40E_GL_MDET_TX_VALID_MASK) { 387161ae650dSJack F Vogel u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >> 387261ae650dSJack F Vogel I40E_GL_MDET_TX_PF_NUM_SHIFT; 387361ae650dSJack F Vogel u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >> 387461ae650dSJack F Vogel I40E_GL_MDET_TX_EVENT_SHIFT; 387561ae650dSJack F Vogel u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >> 387661ae650dSJack F Vogel I40E_GL_MDET_TX_QUEUE_SHIFT; 387761ae650dSJack F Vogel device_printf(dev, 387861ae650dSJack F Vogel "Malicious Driver Detection event 0x%02x" 387961ae650dSJack F Vogel " on TX queue %d pf number 0x%02x\n", 388061ae650dSJack F Vogel event, queue, pf_num); 388161ae650dSJack F Vogel wr32(hw, I40E_GL_MDET_TX, 0xffffffff); 388261ae650dSJack F Vogel mdd_detected = true; 388361ae650dSJack F Vogel } 388461ae650dSJack F Vogel reg = rd32(hw, I40E_GL_MDET_RX); 388561ae650dSJack F Vogel if (reg & I40E_GL_MDET_RX_VALID_MASK) { 388661ae650dSJack F Vogel u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >> 388761ae650dSJack F Vogel I40E_GL_MDET_RX_FUNCTION_SHIFT; 388861ae650dSJack F Vogel u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >> 388961ae650dSJack F Vogel I40E_GL_MDET_RX_EVENT_SHIFT; 389061ae650dSJack F Vogel u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >> 389161ae650dSJack F Vogel I40E_GL_MDET_RX_QUEUE_SHIFT; 389261ae650dSJack F Vogel device_printf(dev, 389361ae650dSJack F Vogel "Malicious Driver Detection event 0x%02x" 389461ae650dSJack F Vogel " on RX queue %d of function 0x%02x\n", 389561ae650dSJack F Vogel event, queue, func); 389661ae650dSJack F Vogel wr32(hw, I40E_GL_MDET_RX, 0xffffffff); 389761ae650dSJack F Vogel mdd_detected = true; 389861ae650dSJack F Vogel } 389961ae650dSJack F Vogel 390061ae650dSJack F Vogel if (mdd_detected) { 390161ae650dSJack F Vogel reg = rd32(hw, I40E_PF_MDET_TX); 390261ae650dSJack F Vogel if (reg & I40E_PF_MDET_TX_VALID_MASK) { 390361ae650dSJack F Vogel wr32(hw, I40E_PF_MDET_TX, 0xFFFF); 390461ae650dSJack F Vogel device_printf(dev, 390561ae650dSJack F Vogel "MDD TX event is for this function 0x%08x", 390661ae650dSJack F Vogel reg); 390761ae650dSJack F Vogel pf_mdd_detected = true; 390861ae650dSJack F Vogel } 390961ae650dSJack F Vogel reg = rd32(hw, I40E_PF_MDET_RX); 391061ae650dSJack F Vogel if (reg & I40E_PF_MDET_RX_VALID_MASK) { 391161ae650dSJack F Vogel wr32(hw, I40E_PF_MDET_RX, 0xFFFF); 391261ae650dSJack F Vogel device_printf(dev, 391361ae650dSJack F Vogel "MDD RX event is for this function 0x%08x", 391461ae650dSJack F Vogel reg); 391561ae650dSJack F Vogel pf_mdd_detected = true; 391661ae650dSJack F Vogel } 391761ae650dSJack F Vogel } 391861ae650dSJack F Vogel 391961ae650dSJack F Vogel /* re-enable mdd interrupt cause */ 392061ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0_ENA); 392161ae650dSJack F Vogel reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 392261ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 392361ae650dSJack F Vogel ixl_flush(hw); 392461ae650dSJack F Vogel } 392561ae650dSJack F Vogel 392661ae650dSJack F Vogel static void 392761ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi) 392861ae650dSJack F Vogel { 392961ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 393061ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 393161ae650dSJack F Vogel 393261ae650dSJack F Vogel if (ixl_enable_msix) { 393361ae650dSJack F Vogel ixl_enable_adminq(hw); 393461ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) 393561ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 393661ae650dSJack F Vogel } else 393761ae650dSJack F Vogel ixl_enable_legacy(hw); 393861ae650dSJack F Vogel } 393961ae650dSJack F Vogel 394061ae650dSJack F Vogel static void 3941*56c2c47bSJack F Vogel ixl_disable_rings_intr(struct ixl_vsi *vsi) 394261ae650dSJack F Vogel { 394361ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 394461ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 394561ae650dSJack F Vogel 394661ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) 394761ae650dSJack F Vogel ixl_disable_queue(hw, que->me); 3948*56c2c47bSJack F Vogel } 3949*56c2c47bSJack F Vogel 3950*56c2c47bSJack F Vogel static void 3951*56c2c47bSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi) 3952*56c2c47bSJack F Vogel { 3953*56c2c47bSJack F Vogel struct i40e_hw *hw = vsi->hw; 3954*56c2c47bSJack F Vogel 3955*56c2c47bSJack F Vogel if (ixl_enable_msix) 3956*56c2c47bSJack F Vogel ixl_disable_adminq(hw); 3957*56c2c47bSJack F Vogel else 395861ae650dSJack F Vogel ixl_disable_legacy(hw); 395961ae650dSJack F Vogel } 396061ae650dSJack F Vogel 396161ae650dSJack F Vogel static void 396261ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw) 396361ae650dSJack F Vogel { 396461ae650dSJack F Vogel u32 reg; 396561ae650dSJack F Vogel 396661ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 396761ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 396861ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 396961ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 397061ae650dSJack F Vogel ixl_flush(hw); 397161ae650dSJack F Vogel return; 397261ae650dSJack F Vogel } 397361ae650dSJack F Vogel 397461ae650dSJack F Vogel static void 397561ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw) 397661ae650dSJack F Vogel { 397761ae650dSJack F Vogel u32 reg; 397861ae650dSJack F Vogel 397961ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 398061ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 398161ae650dSJack F Vogel 398261ae650dSJack F Vogel return; 398361ae650dSJack F Vogel } 398461ae650dSJack F Vogel 398561ae650dSJack F Vogel static void 398661ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id) 398761ae650dSJack F Vogel { 398861ae650dSJack F Vogel u32 reg; 398961ae650dSJack F Vogel 399061ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTLN_INTENA_MASK | 399161ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | 399261ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); 399361ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 399461ae650dSJack F Vogel } 399561ae650dSJack F Vogel 399661ae650dSJack F Vogel static void 399761ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id) 399861ae650dSJack F Vogel { 399961ae650dSJack F Vogel u32 reg; 400061ae650dSJack F Vogel 400161ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; 400261ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 400361ae650dSJack F Vogel 400461ae650dSJack F Vogel return; 400561ae650dSJack F Vogel } 400661ae650dSJack F Vogel 400761ae650dSJack F Vogel static void 400861ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw) 400961ae650dSJack F Vogel { 401061ae650dSJack F Vogel u32 reg; 401161ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 401261ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 401361ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 401461ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 401561ae650dSJack F Vogel } 401661ae650dSJack F Vogel 401761ae650dSJack F Vogel static void 401861ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw) 401961ae650dSJack F Vogel { 402061ae650dSJack F Vogel u32 reg; 402161ae650dSJack F Vogel 402261ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 402361ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 402461ae650dSJack F Vogel 402561ae650dSJack F Vogel return; 402661ae650dSJack F Vogel } 402761ae650dSJack F Vogel 402861ae650dSJack F Vogel static void 402961ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf) 403061ae650dSJack F Vogel { 403161ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 403261ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 4033*56c2c47bSJack F Vogel struct ixl_vf *vf; 403461ae650dSJack F Vogel 403561ae650dSJack F Vogel struct i40e_hw_port_stats *nsd = &pf->stats; 403661ae650dSJack F Vogel struct i40e_hw_port_stats *osd = &pf->stats_offsets; 403761ae650dSJack F Vogel 403861ae650dSJack F Vogel /* Update hw stats */ 403961ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port), 404061ae650dSJack F Vogel pf->stat_offsets_loaded, 404161ae650dSJack F Vogel &osd->crc_errors, &nsd->crc_errors); 404261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port), 404361ae650dSJack F Vogel pf->stat_offsets_loaded, 404461ae650dSJack F Vogel &osd->illegal_bytes, &nsd->illegal_bytes); 404561ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port), 404661ae650dSJack F Vogel I40E_GLPRT_GORCL(hw->port), 404761ae650dSJack F Vogel pf->stat_offsets_loaded, 404861ae650dSJack F Vogel &osd->eth.rx_bytes, &nsd->eth.rx_bytes); 404961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port), 405061ae650dSJack F Vogel I40E_GLPRT_GOTCL(hw->port), 405161ae650dSJack F Vogel pf->stat_offsets_loaded, 405261ae650dSJack F Vogel &osd->eth.tx_bytes, &nsd->eth.tx_bytes); 405361ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port), 405461ae650dSJack F Vogel pf->stat_offsets_loaded, 405561ae650dSJack F Vogel &osd->eth.rx_discards, 405661ae650dSJack F Vogel &nsd->eth.rx_discards); 405761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port), 405861ae650dSJack F Vogel I40E_GLPRT_UPRCL(hw->port), 405961ae650dSJack F Vogel pf->stat_offsets_loaded, 406061ae650dSJack F Vogel &osd->eth.rx_unicast, 406161ae650dSJack F Vogel &nsd->eth.rx_unicast); 406261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port), 406361ae650dSJack F Vogel I40E_GLPRT_UPTCL(hw->port), 406461ae650dSJack F Vogel pf->stat_offsets_loaded, 406561ae650dSJack F Vogel &osd->eth.tx_unicast, 406661ae650dSJack F Vogel &nsd->eth.tx_unicast); 406761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port), 406861ae650dSJack F Vogel I40E_GLPRT_MPRCL(hw->port), 406961ae650dSJack F Vogel pf->stat_offsets_loaded, 407061ae650dSJack F Vogel &osd->eth.rx_multicast, 407161ae650dSJack F Vogel &nsd->eth.rx_multicast); 407261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port), 407361ae650dSJack F Vogel I40E_GLPRT_MPTCL(hw->port), 407461ae650dSJack F Vogel pf->stat_offsets_loaded, 407561ae650dSJack F Vogel &osd->eth.tx_multicast, 407661ae650dSJack F Vogel &nsd->eth.tx_multicast); 407761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port), 407861ae650dSJack F Vogel I40E_GLPRT_BPRCL(hw->port), 407961ae650dSJack F Vogel pf->stat_offsets_loaded, 408061ae650dSJack F Vogel &osd->eth.rx_broadcast, 408161ae650dSJack F Vogel &nsd->eth.rx_broadcast); 408261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port), 408361ae650dSJack F Vogel I40E_GLPRT_BPTCL(hw->port), 408461ae650dSJack F Vogel pf->stat_offsets_loaded, 408561ae650dSJack F Vogel &osd->eth.tx_broadcast, 408661ae650dSJack F Vogel &nsd->eth.tx_broadcast); 408761ae650dSJack F Vogel 408861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port), 408961ae650dSJack F Vogel pf->stat_offsets_loaded, 409061ae650dSJack F Vogel &osd->tx_dropped_link_down, 409161ae650dSJack F Vogel &nsd->tx_dropped_link_down); 409261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port), 409361ae650dSJack F Vogel pf->stat_offsets_loaded, 409461ae650dSJack F Vogel &osd->mac_local_faults, 409561ae650dSJack F Vogel &nsd->mac_local_faults); 409661ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port), 409761ae650dSJack F Vogel pf->stat_offsets_loaded, 409861ae650dSJack F Vogel &osd->mac_remote_faults, 409961ae650dSJack F Vogel &nsd->mac_remote_faults); 410061ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port), 410161ae650dSJack F Vogel pf->stat_offsets_loaded, 410261ae650dSJack F Vogel &osd->rx_length_errors, 410361ae650dSJack F Vogel &nsd->rx_length_errors); 410461ae650dSJack F Vogel 410561ae650dSJack F Vogel /* Flow control (LFC) stats */ 410661ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port), 410761ae650dSJack F Vogel pf->stat_offsets_loaded, 410861ae650dSJack F Vogel &osd->link_xon_rx, &nsd->link_xon_rx); 410961ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port), 411061ae650dSJack F Vogel pf->stat_offsets_loaded, 411161ae650dSJack F Vogel &osd->link_xon_tx, &nsd->link_xon_tx); 411261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port), 411361ae650dSJack F Vogel pf->stat_offsets_loaded, 411461ae650dSJack F Vogel &osd->link_xoff_rx, &nsd->link_xoff_rx); 411561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port), 411661ae650dSJack F Vogel pf->stat_offsets_loaded, 411761ae650dSJack F Vogel &osd->link_xoff_tx, &nsd->link_xoff_tx); 411861ae650dSJack F Vogel 411961ae650dSJack F Vogel /* Packet size stats rx */ 412061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port), 412161ae650dSJack F Vogel I40E_GLPRT_PRC64L(hw->port), 412261ae650dSJack F Vogel pf->stat_offsets_loaded, 412361ae650dSJack F Vogel &osd->rx_size_64, &nsd->rx_size_64); 412461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port), 412561ae650dSJack F Vogel I40E_GLPRT_PRC127L(hw->port), 412661ae650dSJack F Vogel pf->stat_offsets_loaded, 412761ae650dSJack F Vogel &osd->rx_size_127, &nsd->rx_size_127); 412861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port), 412961ae650dSJack F Vogel I40E_GLPRT_PRC255L(hw->port), 413061ae650dSJack F Vogel pf->stat_offsets_loaded, 413161ae650dSJack F Vogel &osd->rx_size_255, &nsd->rx_size_255); 413261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port), 413361ae650dSJack F Vogel I40E_GLPRT_PRC511L(hw->port), 413461ae650dSJack F Vogel pf->stat_offsets_loaded, 413561ae650dSJack F Vogel &osd->rx_size_511, &nsd->rx_size_511); 413661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port), 413761ae650dSJack F Vogel I40E_GLPRT_PRC1023L(hw->port), 413861ae650dSJack F Vogel pf->stat_offsets_loaded, 413961ae650dSJack F Vogel &osd->rx_size_1023, &nsd->rx_size_1023); 414061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port), 414161ae650dSJack F Vogel I40E_GLPRT_PRC1522L(hw->port), 414261ae650dSJack F Vogel pf->stat_offsets_loaded, 414361ae650dSJack F Vogel &osd->rx_size_1522, &nsd->rx_size_1522); 414461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port), 414561ae650dSJack F Vogel I40E_GLPRT_PRC9522L(hw->port), 414661ae650dSJack F Vogel pf->stat_offsets_loaded, 414761ae650dSJack F Vogel &osd->rx_size_big, &nsd->rx_size_big); 414861ae650dSJack F Vogel 414961ae650dSJack F Vogel /* Packet size stats tx */ 415061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port), 415161ae650dSJack F Vogel I40E_GLPRT_PTC64L(hw->port), 415261ae650dSJack F Vogel pf->stat_offsets_loaded, 415361ae650dSJack F Vogel &osd->tx_size_64, &nsd->tx_size_64); 415461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port), 415561ae650dSJack F Vogel I40E_GLPRT_PTC127L(hw->port), 415661ae650dSJack F Vogel pf->stat_offsets_loaded, 415761ae650dSJack F Vogel &osd->tx_size_127, &nsd->tx_size_127); 415861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port), 415961ae650dSJack F Vogel I40E_GLPRT_PTC255L(hw->port), 416061ae650dSJack F Vogel pf->stat_offsets_loaded, 416161ae650dSJack F Vogel &osd->tx_size_255, &nsd->tx_size_255); 416261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port), 416361ae650dSJack F Vogel I40E_GLPRT_PTC511L(hw->port), 416461ae650dSJack F Vogel pf->stat_offsets_loaded, 416561ae650dSJack F Vogel &osd->tx_size_511, &nsd->tx_size_511); 416661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port), 416761ae650dSJack F Vogel I40E_GLPRT_PTC1023L(hw->port), 416861ae650dSJack F Vogel pf->stat_offsets_loaded, 416961ae650dSJack F Vogel &osd->tx_size_1023, &nsd->tx_size_1023); 417061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port), 417161ae650dSJack F Vogel I40E_GLPRT_PTC1522L(hw->port), 417261ae650dSJack F Vogel pf->stat_offsets_loaded, 417361ae650dSJack F Vogel &osd->tx_size_1522, &nsd->tx_size_1522); 417461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port), 417561ae650dSJack F Vogel I40E_GLPRT_PTC9522L(hw->port), 417661ae650dSJack F Vogel pf->stat_offsets_loaded, 417761ae650dSJack F Vogel &osd->tx_size_big, &nsd->tx_size_big); 417861ae650dSJack F Vogel 417961ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port), 418061ae650dSJack F Vogel pf->stat_offsets_loaded, 418161ae650dSJack F Vogel &osd->rx_undersize, &nsd->rx_undersize); 418261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port), 418361ae650dSJack F Vogel pf->stat_offsets_loaded, 418461ae650dSJack F Vogel &osd->rx_fragments, &nsd->rx_fragments); 418561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port), 418661ae650dSJack F Vogel pf->stat_offsets_loaded, 418761ae650dSJack F Vogel &osd->rx_oversize, &nsd->rx_oversize); 418861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port), 418961ae650dSJack F Vogel pf->stat_offsets_loaded, 419061ae650dSJack F Vogel &osd->rx_jabber, &nsd->rx_jabber); 419161ae650dSJack F Vogel pf->stat_offsets_loaded = true; 419261ae650dSJack F Vogel /* End hw stats */ 419361ae650dSJack F Vogel 419461ae650dSJack F Vogel /* Update vsi stats */ 4195*56c2c47bSJack F Vogel ixl_update_vsi_stats(vsi); 419661ae650dSJack F Vogel 4197*56c2c47bSJack F Vogel for (int i = 0; i < pf->num_vfs; i++) { 4198*56c2c47bSJack F Vogel vf = &pf->vfs[i]; 4199*56c2c47bSJack F Vogel if (vf->vf_flags & VF_FLAG_ENABLED) 4200*56c2c47bSJack F Vogel ixl_update_eth_stats(&pf->vfs[i].vsi); 4201*56c2c47bSJack F Vogel } 420261ae650dSJack F Vogel } 420361ae650dSJack F Vogel 420461ae650dSJack F Vogel /* 420561ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts 420661ae650dSJack F Vogel ** - do outside interrupt since it might sleep 420761ae650dSJack F Vogel */ 420861ae650dSJack F Vogel static void 420961ae650dSJack F Vogel ixl_do_adminq(void *context, int pending) 421061ae650dSJack F Vogel { 421161ae650dSJack F Vogel struct ixl_pf *pf = context; 421261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 421361ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 421461ae650dSJack F Vogel struct i40e_arq_event_info event; 421561ae650dSJack F Vogel i40e_status ret; 421661ae650dSJack F Vogel u32 reg, loop = 0; 421761ae650dSJack F Vogel u16 opcode, result; 421861ae650dSJack F Vogel 4219e5100ee2SJack F Vogel event.buf_len = IXL_AQ_BUF_SZ; 4220e5100ee2SJack F Vogel event.msg_buf = malloc(event.buf_len, 422161ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 422261ae650dSJack F Vogel if (!event.msg_buf) { 422361ae650dSJack F Vogel printf("Unable to allocate adminq memory\n"); 422461ae650dSJack F Vogel return; 422561ae650dSJack F Vogel } 422661ae650dSJack F Vogel 4227*56c2c47bSJack F Vogel IXL_PF_LOCK(pf); 422861ae650dSJack F Vogel /* clean and process any events */ 422961ae650dSJack F Vogel do { 423061ae650dSJack F Vogel ret = i40e_clean_arq_element(hw, &event, &result); 423161ae650dSJack F Vogel if (ret) 423261ae650dSJack F Vogel break; 423361ae650dSJack F Vogel opcode = LE16_TO_CPU(event.desc.opcode); 423461ae650dSJack F Vogel switch (opcode) { 423561ae650dSJack F Vogel case i40e_aqc_opc_get_link_status: 4236*56c2c47bSJack F Vogel ixl_link_event(pf, &event); 423761ae650dSJack F Vogel ixl_update_link_status(pf); 423861ae650dSJack F Vogel break; 423961ae650dSJack F Vogel case i40e_aqc_opc_send_msg_to_pf: 4240*56c2c47bSJack F Vogel #ifdef PCI_IOV 4241*56c2c47bSJack F Vogel ixl_handle_vf_msg(pf, &event); 4242*56c2c47bSJack F Vogel #endif 424361ae650dSJack F Vogel break; 424461ae650dSJack F Vogel case i40e_aqc_opc_event_lan_overflow: 424561ae650dSJack F Vogel break; 424661ae650dSJack F Vogel default: 424761ae650dSJack F Vogel #ifdef IXL_DEBUG 424861ae650dSJack F Vogel printf("AdminQ unknown event %x\n", opcode); 424961ae650dSJack F Vogel #endif 425061ae650dSJack F Vogel break; 425161ae650dSJack F Vogel } 425261ae650dSJack F Vogel 425361ae650dSJack F Vogel } while (result && (loop++ < IXL_ADM_LIMIT)); 425461ae650dSJack F Vogel 425561ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0_ENA); 425661ae650dSJack F Vogel reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 425761ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 425861ae650dSJack F Vogel free(event.msg_buf, M_DEVBUF); 425961ae650dSJack F Vogel 4260*56c2c47bSJack F Vogel /* 4261*56c2c47bSJack F Vogel * If there are still messages to process, reschedule ourselves. 4262*56c2c47bSJack F Vogel * Otherwise, re-enable our interrupt and go to sleep. 4263*56c2c47bSJack F Vogel */ 4264*56c2c47bSJack F Vogel if (result > 0) 4265*56c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 426661ae650dSJack F Vogel else 426761ae650dSJack F Vogel ixl_enable_intr(vsi); 4268*56c2c47bSJack F Vogel 4269*56c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 427061ae650dSJack F Vogel } 427161ae650dSJack F Vogel 427261ae650dSJack F Vogel static int 427361ae650dSJack F Vogel ixl_debug_info(SYSCTL_HANDLER_ARGS) 427461ae650dSJack F Vogel { 427561ae650dSJack F Vogel struct ixl_pf *pf; 427661ae650dSJack F Vogel int error, input = 0; 427761ae650dSJack F Vogel 427861ae650dSJack F Vogel error = sysctl_handle_int(oidp, &input, 0, req); 427961ae650dSJack F Vogel 428061ae650dSJack F Vogel if (error || !req->newptr) 428161ae650dSJack F Vogel return (error); 428261ae650dSJack F Vogel 428361ae650dSJack F Vogel if (input == 1) { 428461ae650dSJack F Vogel pf = (struct ixl_pf *)arg1; 428561ae650dSJack F Vogel ixl_print_debug_info(pf); 428661ae650dSJack F Vogel } 428761ae650dSJack F Vogel 428861ae650dSJack F Vogel return (error); 428961ae650dSJack F Vogel } 429061ae650dSJack F Vogel 429161ae650dSJack F Vogel static void 429261ae650dSJack F Vogel ixl_print_debug_info(struct ixl_pf *pf) 429361ae650dSJack F Vogel { 429461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 429561ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 429661ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 429761ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 429861ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 429961ae650dSJack F Vogel u32 reg; 430061ae650dSJack F Vogel 430161ae650dSJack F Vogel 4302ff21e856SBjoern A. Zeeb printf("Queue irqs = %jx\n", (uintmax_t)que->irqs); 4303ff21e856SBjoern A. Zeeb printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq); 430461ae650dSJack F Vogel printf("RX next check = %x\n", rxr->next_check); 4305ff21e856SBjoern A. Zeeb printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done); 4306ff21e856SBjoern A. Zeeb printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets); 430761ae650dSJack F Vogel printf("TX desc avail = %x\n", txr->avail); 430861ae650dSJack F Vogel 430961ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_GORCL(0xc)); 431061ae650dSJack F Vogel printf("RX Bytes = %x\n", reg); 431161ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_GORCL(hw->port)); 431261ae650dSJack F Vogel printf("Port RX Bytes = %x\n", reg); 431361ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_RDPC(0xc)); 431461ae650dSJack F Vogel printf("RX discard = %x\n", reg); 431561ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RDPC(hw->port)); 431661ae650dSJack F Vogel printf("Port RX discard = %x\n", reg); 431761ae650dSJack F Vogel 431861ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_TEPC(0xc)); 431961ae650dSJack F Vogel printf("TX errors = %x\n", reg); 432061ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_GOTCL(0xc)); 432161ae650dSJack F Vogel printf("TX Bytes = %x\n", reg); 432261ae650dSJack F Vogel 432361ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RUC(hw->port)); 432461ae650dSJack F Vogel printf("RX undersize = %x\n", reg); 432561ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RFC(hw->port)); 432661ae650dSJack F Vogel printf("RX fragments = %x\n", reg); 432761ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_ROC(hw->port)); 432861ae650dSJack F Vogel printf("RX oversize = %x\n", reg); 432961ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RLEC(hw->port)); 433061ae650dSJack F Vogel printf("RX length error = %x\n", reg); 433161ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_MRFC(hw->port)); 433261ae650dSJack F Vogel printf("mac remote fault = %x\n", reg); 433361ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_MLFC(hw->port)); 433461ae650dSJack F Vogel printf("mac local fault = %x\n", reg); 433561ae650dSJack F Vogel } 433661ae650dSJack F Vogel 433761ae650dSJack F Vogel /** 433861ae650dSJack F Vogel * Update VSI-specific ethernet statistics counters. 433961ae650dSJack F Vogel **/ 434061ae650dSJack F Vogel void ixl_update_eth_stats(struct ixl_vsi *vsi) 434161ae650dSJack F Vogel { 434261ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 434361ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 434461ae650dSJack F Vogel struct i40e_eth_stats *es; 434561ae650dSJack F Vogel struct i40e_eth_stats *oes; 43464b443922SGleb Smirnoff struct i40e_hw_port_stats *nsd; 434761ae650dSJack F Vogel u16 stat_idx = vsi->info.stat_counter_idx; 434861ae650dSJack F Vogel 434961ae650dSJack F Vogel es = &vsi->eth_stats; 435061ae650dSJack F Vogel oes = &vsi->eth_stats_offsets; 43514b443922SGleb Smirnoff nsd = &pf->stats; 435261ae650dSJack F Vogel 435361ae650dSJack F Vogel /* Gather up the stats that the hw collects */ 435461ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx), 435561ae650dSJack F Vogel vsi->stat_offsets_loaded, 435661ae650dSJack F Vogel &oes->tx_errors, &es->tx_errors); 435761ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx), 435861ae650dSJack F Vogel vsi->stat_offsets_loaded, 435961ae650dSJack F Vogel &oes->rx_discards, &es->rx_discards); 436061ae650dSJack F Vogel 436161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx), 436261ae650dSJack F Vogel I40E_GLV_GORCL(stat_idx), 436361ae650dSJack F Vogel vsi->stat_offsets_loaded, 436461ae650dSJack F Vogel &oes->rx_bytes, &es->rx_bytes); 436561ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx), 436661ae650dSJack F Vogel I40E_GLV_UPRCL(stat_idx), 436761ae650dSJack F Vogel vsi->stat_offsets_loaded, 436861ae650dSJack F Vogel &oes->rx_unicast, &es->rx_unicast); 436961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx), 437061ae650dSJack F Vogel I40E_GLV_MPRCL(stat_idx), 437161ae650dSJack F Vogel vsi->stat_offsets_loaded, 437261ae650dSJack F Vogel &oes->rx_multicast, &es->rx_multicast); 437361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx), 437461ae650dSJack F Vogel I40E_GLV_BPRCL(stat_idx), 437561ae650dSJack F Vogel vsi->stat_offsets_loaded, 437661ae650dSJack F Vogel &oes->rx_broadcast, &es->rx_broadcast); 437761ae650dSJack F Vogel 437861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx), 437961ae650dSJack F Vogel I40E_GLV_GOTCL(stat_idx), 438061ae650dSJack F Vogel vsi->stat_offsets_loaded, 438161ae650dSJack F Vogel &oes->tx_bytes, &es->tx_bytes); 438261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx), 438361ae650dSJack F Vogel I40E_GLV_UPTCL(stat_idx), 438461ae650dSJack F Vogel vsi->stat_offsets_loaded, 438561ae650dSJack F Vogel &oes->tx_unicast, &es->tx_unicast); 438661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx), 438761ae650dSJack F Vogel I40E_GLV_MPTCL(stat_idx), 438861ae650dSJack F Vogel vsi->stat_offsets_loaded, 438961ae650dSJack F Vogel &oes->tx_multicast, &es->tx_multicast); 439061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx), 439161ae650dSJack F Vogel I40E_GLV_BPTCL(stat_idx), 439261ae650dSJack F Vogel vsi->stat_offsets_loaded, 439361ae650dSJack F Vogel &oes->tx_broadcast, &es->tx_broadcast); 439461ae650dSJack F Vogel vsi->stat_offsets_loaded = true; 4395*56c2c47bSJack F Vogel } 4396*56c2c47bSJack F Vogel 4397*56c2c47bSJack F Vogel static void 4398*56c2c47bSJack F Vogel ixl_update_vsi_stats(struct ixl_vsi *vsi) 4399*56c2c47bSJack F Vogel { 4400*56c2c47bSJack F Vogel struct ixl_pf *pf; 4401*56c2c47bSJack F Vogel struct ifnet *ifp; 4402*56c2c47bSJack F Vogel struct i40e_eth_stats *es; 4403*56c2c47bSJack F Vogel u64 tx_discards; 4404*56c2c47bSJack F Vogel 4405*56c2c47bSJack F Vogel struct i40e_hw_port_stats *nsd; 4406*56c2c47bSJack F Vogel 4407*56c2c47bSJack F Vogel pf = vsi->back; 4408*56c2c47bSJack F Vogel ifp = vsi->ifp; 4409*56c2c47bSJack F Vogel es = &vsi->eth_stats; 4410*56c2c47bSJack F Vogel nsd = &pf->stats; 4411*56c2c47bSJack F Vogel 4412*56c2c47bSJack F Vogel ixl_update_eth_stats(vsi); 441361ae650dSJack F Vogel 44144b443922SGleb Smirnoff tx_discards = es->tx_discards + nsd->tx_dropped_link_down; 4415*56c2c47bSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) 44164b443922SGleb Smirnoff tx_discards += vsi->queues[i].txr.br->br_drops; 441761ae650dSJack F Vogel 44184b443922SGleb Smirnoff /* Update ifnet stats */ 44194b443922SGleb Smirnoff IXL_SET_IPACKETS(vsi, es->rx_unicast + 44204b443922SGleb Smirnoff es->rx_multicast + 44214b443922SGleb Smirnoff es->rx_broadcast); 44224b443922SGleb Smirnoff IXL_SET_OPACKETS(vsi, es->tx_unicast + 44234b443922SGleb Smirnoff es->tx_multicast + 44244b443922SGleb Smirnoff es->tx_broadcast); 44254b443922SGleb Smirnoff IXL_SET_IBYTES(vsi, es->rx_bytes); 44264b443922SGleb Smirnoff IXL_SET_OBYTES(vsi, es->tx_bytes); 44274b443922SGleb Smirnoff IXL_SET_IMCASTS(vsi, es->rx_multicast); 44284b443922SGleb Smirnoff IXL_SET_OMCASTS(vsi, es->tx_multicast); 44294b443922SGleb Smirnoff 4430*56c2c47bSJack F Vogel IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes + 4431*56c2c47bSJack F Vogel nsd->rx_undersize + nsd->rx_oversize + nsd->rx_fragments + 4432*56c2c47bSJack F Vogel nsd->rx_jabber); 44334b443922SGleb Smirnoff IXL_SET_OERRORS(vsi, es->tx_errors); 44344b443922SGleb Smirnoff IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards); 44354b443922SGleb Smirnoff IXL_SET_OQDROPS(vsi, tx_discards); 44364b443922SGleb Smirnoff IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol); 44374b443922SGleb Smirnoff IXL_SET_COLLISIONS(vsi, 0); 443861ae650dSJack F Vogel } 443961ae650dSJack F Vogel 444061ae650dSJack F Vogel /** 444161ae650dSJack F Vogel * Reset all of the stats for the given pf 444261ae650dSJack F Vogel **/ 444361ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf) 444461ae650dSJack F Vogel { 444561ae650dSJack F Vogel bzero(&pf->stats, sizeof(struct i40e_hw_port_stats)); 444661ae650dSJack F Vogel bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats)); 444761ae650dSJack F Vogel pf->stat_offsets_loaded = false; 444861ae650dSJack F Vogel } 444961ae650dSJack F Vogel 445061ae650dSJack F Vogel /** 445161ae650dSJack F Vogel * Resets all stats of the given vsi 445261ae650dSJack F Vogel **/ 445361ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi) 445461ae650dSJack F Vogel { 445561ae650dSJack F Vogel bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats)); 445661ae650dSJack F Vogel bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats)); 445761ae650dSJack F Vogel vsi->stat_offsets_loaded = false; 445861ae650dSJack F Vogel } 445961ae650dSJack F Vogel 446061ae650dSJack F Vogel /** 446161ae650dSJack F Vogel * Read and update a 48 bit stat from the hw 446261ae650dSJack F Vogel * 446361ae650dSJack F Vogel * Since the device stats are not reset at PFReset, they likely will not 446461ae650dSJack F Vogel * be zeroed when the driver starts. We'll save the first values read 446561ae650dSJack F Vogel * and use them as offsets to be subtracted from the raw values in order 446661ae650dSJack F Vogel * to report stats that count from zero. 446761ae650dSJack F Vogel **/ 446861ae650dSJack F Vogel static void 446961ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg, 447061ae650dSJack F Vogel bool offset_loaded, u64 *offset, u64 *stat) 447161ae650dSJack F Vogel { 447261ae650dSJack F Vogel u64 new_data; 447361ae650dSJack F Vogel 4474ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__) 447561ae650dSJack F Vogel new_data = rd64(hw, loreg); 447661ae650dSJack F Vogel #else 447761ae650dSJack F Vogel /* 447861ae650dSJack F Vogel * Use two rd32's instead of one rd64; FreeBSD versions before 447961ae650dSJack F Vogel * 10 don't support 8 byte bus reads/writes. 448061ae650dSJack F Vogel */ 448161ae650dSJack F Vogel new_data = rd32(hw, loreg); 448261ae650dSJack F Vogel new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32; 448361ae650dSJack F Vogel #endif 448461ae650dSJack F Vogel 448561ae650dSJack F Vogel if (!offset_loaded) 448661ae650dSJack F Vogel *offset = new_data; 448761ae650dSJack F Vogel if (new_data >= *offset) 448861ae650dSJack F Vogel *stat = new_data - *offset; 448961ae650dSJack F Vogel else 449061ae650dSJack F Vogel *stat = (new_data + ((u64)1 << 48)) - *offset; 449161ae650dSJack F Vogel *stat &= 0xFFFFFFFFFFFFULL; 449261ae650dSJack F Vogel } 449361ae650dSJack F Vogel 449461ae650dSJack F Vogel /** 449561ae650dSJack F Vogel * Read and update a 32 bit stat from the hw 449661ae650dSJack F Vogel **/ 449761ae650dSJack F Vogel static void 449861ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg, 449961ae650dSJack F Vogel bool offset_loaded, u64 *offset, u64 *stat) 450061ae650dSJack F Vogel { 450161ae650dSJack F Vogel u32 new_data; 450261ae650dSJack F Vogel 450361ae650dSJack F Vogel new_data = rd32(hw, reg); 450461ae650dSJack F Vogel if (!offset_loaded) 450561ae650dSJack F Vogel *offset = new_data; 450661ae650dSJack F Vogel if (new_data >= *offset) 450761ae650dSJack F Vogel *stat = (u32)(new_data - *offset); 450861ae650dSJack F Vogel else 450961ae650dSJack F Vogel *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); 451061ae650dSJack F Vogel } 451161ae650dSJack F Vogel 451261ae650dSJack F Vogel /* 451361ae650dSJack F Vogel ** Set flow control using sysctl: 451461ae650dSJack F Vogel ** 0 - off 451561ae650dSJack F Vogel ** 1 - rx pause 451661ae650dSJack F Vogel ** 2 - tx pause 451761ae650dSJack F Vogel ** 3 - full 451861ae650dSJack F Vogel */ 451961ae650dSJack F Vogel static int 452061ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS) 452161ae650dSJack F Vogel { 452261ae650dSJack F Vogel /* 452361ae650dSJack F Vogel * TODO: ensure flow control is disabled if 452461ae650dSJack F Vogel * priority flow control is enabled 452561ae650dSJack F Vogel * 452661ae650dSJack F Vogel * TODO: ensure tx CRC by hardware should be enabled 452761ae650dSJack F Vogel * if tx flow control is enabled. 452861ae650dSJack F Vogel */ 452961ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 453061ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 453161ae650dSJack F Vogel device_t dev = pf->dev; 4532b6c8f260SJack F Vogel int error = 0; 453361ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 453461ae650dSJack F Vogel u8 fc_aq_err = 0; 453561ae650dSJack F Vogel 4536b6c8f260SJack F Vogel /* Get request */ 4537b6c8f260SJack F Vogel error = sysctl_handle_int(oidp, &pf->fc, 0, req); 453861ae650dSJack F Vogel if ((error) || (req->newptr == NULL)) 453961ae650dSJack F Vogel return (error); 4540b6c8f260SJack F Vogel if (pf->fc < 0 || pf->fc > 3) { 454161ae650dSJack F Vogel device_printf(dev, 454261ae650dSJack F Vogel "Invalid fc mode; valid modes are 0 through 3\n"); 454361ae650dSJack F Vogel return (EINVAL); 454461ae650dSJack F Vogel } 454561ae650dSJack F Vogel 454661ae650dSJack F Vogel /* 454761ae650dSJack F Vogel ** Changing flow control mode currently does not work on 454861ae650dSJack F Vogel ** 40GBASE-CR4 PHYs 454961ae650dSJack F Vogel */ 455061ae650dSJack F Vogel if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4 455161ae650dSJack F Vogel || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) { 455261ae650dSJack F Vogel device_printf(dev, "Changing flow control mode unsupported" 455361ae650dSJack F Vogel " on 40GBase-CR4 media.\n"); 455461ae650dSJack F Vogel return (ENODEV); 455561ae650dSJack F Vogel } 455661ae650dSJack F Vogel 455761ae650dSJack F Vogel /* Set fc ability for port */ 4558b6c8f260SJack F Vogel hw->fc.requested_mode = pf->fc; 455961ae650dSJack F Vogel aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE); 456061ae650dSJack F Vogel if (aq_error) { 456161ae650dSJack F Vogel device_printf(dev, 456261ae650dSJack F Vogel "%s: Error setting new fc mode %d; fc_err %#x\n", 456361ae650dSJack F Vogel __func__, aq_error, fc_aq_err); 456461ae650dSJack F Vogel return (EAGAIN); 456561ae650dSJack F Vogel } 456661ae650dSJack F Vogel 456761ae650dSJack F Vogel return (0); 456861ae650dSJack F Vogel } 456961ae650dSJack F Vogel 457061ae650dSJack F Vogel static int 457161ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS) 457261ae650dSJack F Vogel { 457361ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 457461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 457561ae650dSJack F Vogel int error = 0, index = 0; 457661ae650dSJack F Vogel 457761ae650dSJack F Vogel char *speeds[] = { 457861ae650dSJack F Vogel "Unknown", 457961ae650dSJack F Vogel "100M", 458061ae650dSJack F Vogel "1G", 458161ae650dSJack F Vogel "10G", 458261ae650dSJack F Vogel "40G", 458361ae650dSJack F Vogel "20G" 458461ae650dSJack F Vogel }; 458561ae650dSJack F Vogel 458661ae650dSJack F Vogel ixl_update_link_status(pf); 458761ae650dSJack F Vogel 458861ae650dSJack F Vogel switch (hw->phy.link_info.link_speed) { 458961ae650dSJack F Vogel case I40E_LINK_SPEED_100MB: 459061ae650dSJack F Vogel index = 1; 459161ae650dSJack F Vogel break; 459261ae650dSJack F Vogel case I40E_LINK_SPEED_1GB: 459361ae650dSJack F Vogel index = 2; 459461ae650dSJack F Vogel break; 459561ae650dSJack F Vogel case I40E_LINK_SPEED_10GB: 459661ae650dSJack F Vogel index = 3; 459761ae650dSJack F Vogel break; 459861ae650dSJack F Vogel case I40E_LINK_SPEED_40GB: 459961ae650dSJack F Vogel index = 4; 460061ae650dSJack F Vogel break; 460161ae650dSJack F Vogel case I40E_LINK_SPEED_20GB: 460261ae650dSJack F Vogel index = 5; 460361ae650dSJack F Vogel break; 460461ae650dSJack F Vogel case I40E_LINK_SPEED_UNKNOWN: 460561ae650dSJack F Vogel default: 460661ae650dSJack F Vogel index = 0; 460761ae650dSJack F Vogel break; 460861ae650dSJack F Vogel } 460961ae650dSJack F Vogel 461061ae650dSJack F Vogel error = sysctl_handle_string(oidp, speeds[index], 461161ae650dSJack F Vogel strlen(speeds[index]), req); 461261ae650dSJack F Vogel return (error); 461361ae650dSJack F Vogel } 461461ae650dSJack F Vogel 4615e5100ee2SJack F Vogel static int 4616e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds) 4617e5100ee2SJack F Vogel { 4618e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 4619e5100ee2SJack F Vogel device_t dev = pf->dev; 4620e5100ee2SJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 4621e5100ee2SJack F Vogel struct i40e_aq_set_phy_config config; 4622e5100ee2SJack F Vogel enum i40e_status_code aq_error = 0; 4623e5100ee2SJack F Vogel 4624e5100ee2SJack F Vogel /* Get current capability information */ 4625b6c8f260SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 4626b6c8f260SJack F Vogel FALSE, FALSE, &abilities, NULL); 4627e5100ee2SJack F Vogel if (aq_error) { 4628b6c8f260SJack F Vogel device_printf(dev, 4629b6c8f260SJack F Vogel "%s: Error getting phy capabilities %d," 4630e5100ee2SJack F Vogel " aq error: %d\n", __func__, aq_error, 4631e5100ee2SJack F Vogel hw->aq.asq_last_status); 4632e5100ee2SJack F Vogel return (EAGAIN); 4633e5100ee2SJack F Vogel } 4634e5100ee2SJack F Vogel 4635e5100ee2SJack F Vogel /* Prepare new config */ 4636e5100ee2SJack F Vogel bzero(&config, sizeof(config)); 4637e5100ee2SJack F Vogel config.phy_type = abilities.phy_type; 4638e5100ee2SJack F Vogel config.abilities = abilities.abilities 4639e5100ee2SJack F Vogel | I40E_AQ_PHY_ENABLE_ATOMIC_LINK; 4640e5100ee2SJack F Vogel config.eee_capability = abilities.eee_capability; 4641e5100ee2SJack F Vogel config.eeer = abilities.eeer_val; 4642e5100ee2SJack F Vogel config.low_power_ctrl = abilities.d3_lpan; 4643e5100ee2SJack F Vogel /* Translate into aq cmd link_speed */ 4644*56c2c47bSJack F Vogel if (speeds & 0x8) 4645*56c2c47bSJack F Vogel config.link_speed |= I40E_LINK_SPEED_20GB; 4646e5100ee2SJack F Vogel if (speeds & 0x4) 4647e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_10GB; 4648e5100ee2SJack F Vogel if (speeds & 0x2) 4649e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_1GB; 4650e5100ee2SJack F Vogel if (speeds & 0x1) 4651e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_100MB; 4652e5100ee2SJack F Vogel 4653e5100ee2SJack F Vogel /* Do aq command & restart link */ 4654e5100ee2SJack F Vogel aq_error = i40e_aq_set_phy_config(hw, &config, NULL); 4655e5100ee2SJack F Vogel if (aq_error) { 4656b6c8f260SJack F Vogel device_printf(dev, 4657b6c8f260SJack F Vogel "%s: Error setting new phy config %d," 4658e5100ee2SJack F Vogel " aq error: %d\n", __func__, aq_error, 4659e5100ee2SJack F Vogel hw->aq.asq_last_status); 4660e5100ee2SJack F Vogel return (EAGAIN); 4661e5100ee2SJack F Vogel } 4662e5100ee2SJack F Vogel 4663393c4bb1SJack F Vogel /* 4664393c4bb1SJack F Vogel ** This seems a bit heavy handed, but we 4665393c4bb1SJack F Vogel ** need to get a reinit on some devices 4666393c4bb1SJack F Vogel */ 4667393c4bb1SJack F Vogel IXL_PF_LOCK(pf); 4668393c4bb1SJack F Vogel ixl_stop(pf); 4669393c4bb1SJack F Vogel ixl_init_locked(pf); 4670393c4bb1SJack F Vogel IXL_PF_UNLOCK(pf); 4671393c4bb1SJack F Vogel 4672e5100ee2SJack F Vogel return (0); 4673e5100ee2SJack F Vogel } 4674e5100ee2SJack F Vogel 467561ae650dSJack F Vogel /* 467661ae650dSJack F Vogel ** Control link advertise speed: 467761ae650dSJack F Vogel ** Flags: 467861ae650dSJack F Vogel ** 0x1 - advertise 100 Mb 467961ae650dSJack F Vogel ** 0x2 - advertise 1G 468061ae650dSJack F Vogel ** 0x4 - advertise 10G 4681*56c2c47bSJack F Vogel ** 0x8 - advertise 20G 468261ae650dSJack F Vogel ** 468361ae650dSJack F Vogel ** Does not work on 40G devices. 468461ae650dSJack F Vogel */ 468561ae650dSJack F Vogel static int 468661ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS) 468761ae650dSJack F Vogel { 468861ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 468961ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 469061ae650dSJack F Vogel device_t dev = pf->dev; 469161ae650dSJack F Vogel int requested_ls = 0; 469261ae650dSJack F Vogel int error = 0; 469361ae650dSJack F Vogel 469461ae650dSJack F Vogel /* 469561ae650dSJack F Vogel ** FW doesn't support changing advertised speed 469661ae650dSJack F Vogel ** for 40G devices; speed is always 40G. 469761ae650dSJack F Vogel */ 469861ae650dSJack F Vogel if (i40e_is_40G_device(hw->device_id)) 469961ae650dSJack F Vogel return (ENODEV); 470061ae650dSJack F Vogel 470161ae650dSJack F Vogel /* Read in new mode */ 470261ae650dSJack F Vogel requested_ls = pf->advertised_speed; 470361ae650dSJack F Vogel error = sysctl_handle_int(oidp, &requested_ls, 0, req); 470461ae650dSJack F Vogel if ((error) || (req->newptr == NULL)) 470561ae650dSJack F Vogel return (error); 4706*56c2c47bSJack F Vogel /* Check for sane value */ 4707*56c2c47bSJack F Vogel if (requested_ls < 0x1 || requested_ls > 0xE) { 4708*56c2c47bSJack F Vogel device_printf(dev, "Invalid advertised speed; " 4709*56c2c47bSJack F Vogel "valid modes are 0x1 through 0xE\n"); 471061ae650dSJack F Vogel return (EINVAL); 471161ae650dSJack F Vogel } 4712*56c2c47bSJack F Vogel /* Then check for validity based on adapter type */ 4713*56c2c47bSJack F Vogel switch (hw->device_id) { 4714*56c2c47bSJack F Vogel case I40E_DEV_ID_10G_BASE_T: 4715*56c2c47bSJack F Vogel if (requested_ls & 0x8) { 4716*56c2c47bSJack F Vogel device_printf(dev, 4717*56c2c47bSJack F Vogel "20Gbs speed not supported on this device.\n"); 4718*56c2c47bSJack F Vogel return (EINVAL); 4719*56c2c47bSJack F Vogel } 4720*56c2c47bSJack F Vogel break; 4721*56c2c47bSJack F Vogel case I40E_DEV_ID_20G_KR2: 4722*56c2c47bSJack F Vogel if (requested_ls & 0x1) { 4723*56c2c47bSJack F Vogel device_printf(dev, 4724*56c2c47bSJack F Vogel "100Mbs speed not supported on this device.\n"); 4725*56c2c47bSJack F Vogel return (EINVAL); 4726*56c2c47bSJack F Vogel } 4727*56c2c47bSJack F Vogel break; 4728*56c2c47bSJack F Vogel default: 4729*56c2c47bSJack F Vogel if (requested_ls & ~0x6) { 4730*56c2c47bSJack F Vogel device_printf(dev, 4731*56c2c47bSJack F Vogel "Only 1/10Gbs speeds are supported on this device.\n"); 4732*56c2c47bSJack F Vogel return (EINVAL); 4733*56c2c47bSJack F Vogel } 4734*56c2c47bSJack F Vogel break; 4735*56c2c47bSJack F Vogel } 473661ae650dSJack F Vogel 473761ae650dSJack F Vogel /* Exit if no change */ 473861ae650dSJack F Vogel if (pf->advertised_speed == requested_ls) 473961ae650dSJack F Vogel return (0); 474061ae650dSJack F Vogel 4741e5100ee2SJack F Vogel error = ixl_set_advertised_speeds(pf, requested_ls); 4742e5100ee2SJack F Vogel if (error) 4743e5100ee2SJack F Vogel return (error); 474461ae650dSJack F Vogel 474561ae650dSJack F Vogel pf->advertised_speed = requested_ls; 474661ae650dSJack F Vogel ixl_update_link_status(pf); 474761ae650dSJack F Vogel return (0); 474861ae650dSJack F Vogel } 474961ae650dSJack F Vogel 475061ae650dSJack F Vogel /* 475161ae650dSJack F Vogel ** Get the width and transaction speed of 475261ae650dSJack F Vogel ** the bus this adapter is plugged into. 475361ae650dSJack F Vogel */ 475461ae650dSJack F Vogel static u16 475561ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev) 475661ae650dSJack F Vogel { 475761ae650dSJack F Vogel u16 link; 475861ae650dSJack F Vogel u32 offset; 475961ae650dSJack F Vogel 476061ae650dSJack F Vogel 476161ae650dSJack F Vogel /* Get the PCI Express Capabilities offset */ 476261ae650dSJack F Vogel pci_find_cap(dev, PCIY_EXPRESS, &offset); 476361ae650dSJack F Vogel 476461ae650dSJack F Vogel /* ...and read the Link Status Register */ 476561ae650dSJack F Vogel link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 476661ae650dSJack F Vogel 476761ae650dSJack F Vogel switch (link & I40E_PCI_LINK_WIDTH) { 476861ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_1: 476961ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x1; 477061ae650dSJack F Vogel break; 477161ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_2: 477261ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x2; 477361ae650dSJack F Vogel break; 477461ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_4: 477561ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x4; 477661ae650dSJack F Vogel break; 477761ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_8: 477861ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x8; 477961ae650dSJack F Vogel break; 478061ae650dSJack F Vogel default: 478161ae650dSJack F Vogel hw->bus.width = i40e_bus_width_unknown; 478261ae650dSJack F Vogel break; 478361ae650dSJack F Vogel } 478461ae650dSJack F Vogel 478561ae650dSJack F Vogel switch (link & I40E_PCI_LINK_SPEED) { 478661ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_2500: 478761ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_2500; 478861ae650dSJack F Vogel break; 478961ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_5000: 479061ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_5000; 479161ae650dSJack F Vogel break; 479261ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_8000: 479361ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_8000; 479461ae650dSJack F Vogel break; 479561ae650dSJack F Vogel default: 479661ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_unknown; 479761ae650dSJack F Vogel break; 479861ae650dSJack F Vogel } 479961ae650dSJack F Vogel 480061ae650dSJack F Vogel 480161ae650dSJack F Vogel device_printf(dev,"PCI Express Bus: Speed %s %s\n", 480261ae650dSJack F Vogel ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s": 480361ae650dSJack F Vogel (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s": 480461ae650dSJack F Vogel (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"), 480561ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" : 480661ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" : 480761ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" : 480861ae650dSJack F Vogel ("Unknown")); 480961ae650dSJack F Vogel 481061ae650dSJack F Vogel if ((hw->bus.width <= i40e_bus_width_pcie_x8) && 481161ae650dSJack F Vogel (hw->bus.speed < i40e_bus_speed_8000)) { 481261ae650dSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 4813*56c2c47bSJack F Vogel " for this device\n may be insufficient for" 4814*56c2c47bSJack F Vogel " optimal performance.\n"); 481561ae650dSJack F Vogel device_printf(dev, "For expected performance a x8 " 481661ae650dSJack F Vogel "PCIE Gen3 slot is required.\n"); 481761ae650dSJack F Vogel } 481861ae650dSJack F Vogel 481961ae650dSJack F Vogel return (link); 482061ae650dSJack F Vogel } 482161ae650dSJack F Vogel 4822e5100ee2SJack F Vogel static int 4823e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS) 4824e5100ee2SJack F Vogel { 4825e5100ee2SJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 4826e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 4827e5100ee2SJack F Vogel char buf[32]; 4828e5100ee2SJack F Vogel 4829e5100ee2SJack F Vogel snprintf(buf, sizeof(buf), 4830e5100ee2SJack F Vogel "f%d.%d a%d.%d n%02x.%02x e%08x", 4831e5100ee2SJack F Vogel hw->aq.fw_maj_ver, hw->aq.fw_min_ver, 4832e5100ee2SJack F Vogel hw->aq.api_maj_ver, hw->aq.api_min_ver, 4833e5100ee2SJack F Vogel (hw->nvm.version & IXL_NVM_VERSION_HI_MASK) >> 4834e5100ee2SJack F Vogel IXL_NVM_VERSION_HI_SHIFT, 4835e5100ee2SJack F Vogel (hw->nvm.version & IXL_NVM_VERSION_LO_MASK) >> 4836e5100ee2SJack F Vogel IXL_NVM_VERSION_LO_SHIFT, 4837e5100ee2SJack F Vogel hw->nvm.eetrack); 4838e5100ee2SJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 4839e5100ee2SJack F Vogel } 4840e5100ee2SJack F Vogel 4841e5100ee2SJack F Vogel 4842393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL 484361ae650dSJack F Vogel static int 484461ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS) 484561ae650dSJack F Vogel { 484661ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 484761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 484861ae650dSJack F Vogel struct i40e_link_status link_status; 484961ae650dSJack F Vogel char buf[512]; 485061ae650dSJack F Vogel 485161ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 485261ae650dSJack F Vogel 485361ae650dSJack F Vogel aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL); 485461ae650dSJack F Vogel if (aq_error) { 485561ae650dSJack F Vogel printf("i40e_aq_get_link_info() error %d\n", aq_error); 485661ae650dSJack F Vogel return (EPERM); 485761ae650dSJack F Vogel } 485861ae650dSJack F Vogel 485961ae650dSJack F Vogel sprintf(buf, "\n" 486061ae650dSJack F Vogel "PHY Type : %#04x\n" 486161ae650dSJack F Vogel "Speed : %#04x\n" 486261ae650dSJack F Vogel "Link info: %#04x\n" 486361ae650dSJack F Vogel "AN info : %#04x\n" 486461ae650dSJack F Vogel "Ext info : %#04x", 486561ae650dSJack F Vogel link_status.phy_type, link_status.link_speed, 486661ae650dSJack F Vogel link_status.link_info, link_status.an_info, 486761ae650dSJack F Vogel link_status.ext_info); 486861ae650dSJack F Vogel 486961ae650dSJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 487061ae650dSJack F Vogel } 487161ae650dSJack F Vogel 487261ae650dSJack F Vogel static int 487361ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS) 487461ae650dSJack F Vogel { 487561ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 487661ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 487761ae650dSJack F Vogel char buf[512]; 487861ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 487961ae650dSJack F Vogel 4880*56c2c47bSJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 4881*56c2c47bSJack F Vogel 4882*56c2c47bSJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 4883*56c2c47bSJack F Vogel TRUE, FALSE, &abilities, NULL); 488461ae650dSJack F Vogel if (aq_error) { 488561ae650dSJack F Vogel printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error); 488661ae650dSJack F Vogel return (EPERM); 488761ae650dSJack F Vogel } 488861ae650dSJack F Vogel 488961ae650dSJack F Vogel sprintf(buf, "\n" 489061ae650dSJack F Vogel "PHY Type : %#010x\n" 489161ae650dSJack F Vogel "Speed : %#04x\n" 489261ae650dSJack F Vogel "Abilities: %#04x\n" 489361ae650dSJack F Vogel "EEE cap : %#06x\n" 489461ae650dSJack F Vogel "EEER reg : %#010x\n" 489561ae650dSJack F Vogel "D3 Lpan : %#04x", 4896*56c2c47bSJack F Vogel abilities.phy_type, abilities.link_speed, 4897*56c2c47bSJack F Vogel abilities.abilities, abilities.eee_capability, 4898*56c2c47bSJack F Vogel abilities.eeer_val, abilities.d3_lpan); 489961ae650dSJack F Vogel 490061ae650dSJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 490161ae650dSJack F Vogel } 490261ae650dSJack F Vogel 490361ae650dSJack F Vogel static int 490461ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS) 490561ae650dSJack F Vogel { 490661ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 490761ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 490861ae650dSJack F Vogel struct ixl_mac_filter *f; 490961ae650dSJack F Vogel char *buf, *buf_i; 491061ae650dSJack F Vogel 491161ae650dSJack F Vogel int error = 0; 491261ae650dSJack F Vogel int ftl_len = 0; 491361ae650dSJack F Vogel int ftl_counter = 0; 491461ae650dSJack F Vogel int buf_len = 0; 491561ae650dSJack F Vogel int entry_len = 42; 491661ae650dSJack F Vogel 491761ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 491861ae650dSJack F Vogel ftl_len++; 491961ae650dSJack F Vogel } 492061ae650dSJack F Vogel 492161ae650dSJack F Vogel if (ftl_len < 1) { 492261ae650dSJack F Vogel sysctl_handle_string(oidp, "(none)", 6, req); 492361ae650dSJack F Vogel return (0); 492461ae650dSJack F Vogel } 492561ae650dSJack F Vogel 492661ae650dSJack F Vogel buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2; 492761ae650dSJack F Vogel buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT); 492861ae650dSJack F Vogel 492961ae650dSJack F Vogel sprintf(buf_i++, "\n"); 493061ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 493161ae650dSJack F Vogel sprintf(buf_i, 493261ae650dSJack F Vogel MAC_FORMAT ", vlan %4d, flags %#06x", 493361ae650dSJack F Vogel MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags); 493461ae650dSJack F Vogel buf_i += entry_len; 493561ae650dSJack F Vogel /* don't print '\n' for last entry */ 493661ae650dSJack F Vogel if (++ftl_counter != ftl_len) { 493761ae650dSJack F Vogel sprintf(buf_i, "\n"); 493861ae650dSJack F Vogel buf_i++; 493961ae650dSJack F Vogel } 494061ae650dSJack F Vogel } 494161ae650dSJack F Vogel 494261ae650dSJack F Vogel error = sysctl_handle_string(oidp, buf, strlen(buf), req); 494361ae650dSJack F Vogel if (error) 494461ae650dSJack F Vogel printf("sysctl error: %d\n", error); 494561ae650dSJack F Vogel free(buf, M_DEVBUF); 494661ae650dSJack F Vogel return error; 494761ae650dSJack F Vogel } 494861ae650dSJack F Vogel 494961ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14 495061ae650dSJack F Vogel static int 4951393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b) 4952393c4bb1SJack F Vogel { 4953393c4bb1SJack F Vogel const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two; 4954393c4bb1SJack F Vogel one = (struct i40e_aqc_switch_resource_alloc_element_resp *)a; 4955393c4bb1SJack F Vogel two = (struct i40e_aqc_switch_resource_alloc_element_resp *)b; 4956393c4bb1SJack F Vogel 4957393c4bb1SJack F Vogel return ((int)one->resource_type - (int)two->resource_type); 4958393c4bb1SJack F Vogel } 4959393c4bb1SJack F Vogel 4960393c4bb1SJack F Vogel static int 4961e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS) 496261ae650dSJack F Vogel { 496361ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 496461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 496561ae650dSJack F Vogel device_t dev = pf->dev; 496661ae650dSJack F Vogel struct sbuf *buf; 496761ae650dSJack F Vogel int error = 0; 496861ae650dSJack F Vogel 496961ae650dSJack F Vogel u8 num_entries; 497061ae650dSJack F Vogel struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE]; 497161ae650dSJack F Vogel 497261ae650dSJack F Vogel buf = sbuf_new_for_sysctl(NULL, NULL, 0, req); 497361ae650dSJack F Vogel if (!buf) { 497461ae650dSJack F Vogel device_printf(dev, "Could not allocate sbuf for output.\n"); 497561ae650dSJack F Vogel return (ENOMEM); 497661ae650dSJack F Vogel } 497761ae650dSJack F Vogel 4978393c4bb1SJack F Vogel bzero(resp, sizeof(resp)); 497961ae650dSJack F Vogel error = i40e_aq_get_switch_resource_alloc(hw, &num_entries, 498061ae650dSJack F Vogel resp, 498161ae650dSJack F Vogel IXL_SW_RES_SIZE, 498261ae650dSJack F Vogel NULL); 498361ae650dSJack F Vogel if (error) { 4984*56c2c47bSJack F Vogel device_printf(dev, 4985*56c2c47bSJack F Vogel "%s: get_switch_resource_alloc() error %d, aq error %d\n", 498661ae650dSJack F Vogel __func__, error, hw->aq.asq_last_status); 498761ae650dSJack F Vogel sbuf_delete(buf); 498861ae650dSJack F Vogel return error; 498961ae650dSJack F Vogel } 4990393c4bb1SJack F Vogel 4991393c4bb1SJack F Vogel /* Sort entries by type for display */ 4992393c4bb1SJack F Vogel qsort(resp, num_entries, 4993393c4bb1SJack F Vogel sizeof(struct i40e_aqc_switch_resource_alloc_element_resp), 4994393c4bb1SJack F Vogel &ixl_res_alloc_cmp); 499561ae650dSJack F Vogel 499661ae650dSJack F Vogel sbuf_cat(buf, "\n"); 4997393c4bb1SJack F Vogel sbuf_printf(buf, "# of entries: %d\n", num_entries); 499861ae650dSJack F Vogel sbuf_printf(buf, 499961ae650dSJack F Vogel "Type | Guaranteed | Total | Used | Un-allocated\n" 500061ae650dSJack F Vogel " | (this) | (all) | (this) | (all) \n"); 500161ae650dSJack F Vogel for (int i = 0; i < num_entries; i++) { 500261ae650dSJack F Vogel sbuf_printf(buf, 500361ae650dSJack F Vogel "%#4x | %10d %5d %6d %12d", 500461ae650dSJack F Vogel resp[i].resource_type, 500561ae650dSJack F Vogel resp[i].guaranteed, 500661ae650dSJack F Vogel resp[i].total, 500761ae650dSJack F Vogel resp[i].used, 500861ae650dSJack F Vogel resp[i].total_unalloced); 500961ae650dSJack F Vogel if (i < num_entries - 1) 501061ae650dSJack F Vogel sbuf_cat(buf, "\n"); 501161ae650dSJack F Vogel } 501261ae650dSJack F Vogel 501361ae650dSJack F Vogel error = sbuf_finish(buf); 501461ae650dSJack F Vogel if (error) { 501561ae650dSJack F Vogel device_printf(dev, "Error finishing sbuf: %d\n", error); 501661ae650dSJack F Vogel sbuf_delete(buf); 501761ae650dSJack F Vogel return error; 501861ae650dSJack F Vogel } 501961ae650dSJack F Vogel 502061ae650dSJack F Vogel error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req); 502161ae650dSJack F Vogel if (error) 502261ae650dSJack F Vogel device_printf(dev, "sysctl error: %d\n", error); 502361ae650dSJack F Vogel sbuf_delete(buf); 502461ae650dSJack F Vogel return error; 5025e5100ee2SJack F Vogel } 502661ae650dSJack F Vogel 5027e5100ee2SJack F Vogel /* 5028e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and 5029e5100ee2SJack F Vogel ** finish it for caller. 5030e5100ee2SJack F Vogel */ 5031e5100ee2SJack F Vogel static char * 5032e5100ee2SJack F Vogel ixl_switch_element_string(struct sbuf *s, u16 seid, bool uplink) 5033e5100ee2SJack F Vogel { 5034e5100ee2SJack F Vogel sbuf_clear(s); 5035e5100ee2SJack F Vogel 5036e5100ee2SJack F Vogel if (seid == 0 && uplink) 5037e5100ee2SJack F Vogel sbuf_cat(s, "Network"); 5038e5100ee2SJack F Vogel else if (seid == 0) 5039e5100ee2SJack F Vogel sbuf_cat(s, "Host"); 5040e5100ee2SJack F Vogel else if (seid == 1) 5041e5100ee2SJack F Vogel sbuf_cat(s, "EMP"); 5042e5100ee2SJack F Vogel else if (seid <= 5) 5043e5100ee2SJack F Vogel sbuf_printf(s, "MAC %d", seid - 2); 5044e5100ee2SJack F Vogel else if (seid <= 15) 5045e5100ee2SJack F Vogel sbuf_cat(s, "Reserved"); 5046e5100ee2SJack F Vogel else if (seid <= 31) 5047e5100ee2SJack F Vogel sbuf_printf(s, "PF %d", seid - 16); 5048e5100ee2SJack F Vogel else if (seid <= 159) 5049e5100ee2SJack F Vogel sbuf_printf(s, "VF %d", seid - 32); 5050e5100ee2SJack F Vogel else if (seid <= 287) 5051e5100ee2SJack F Vogel sbuf_cat(s, "Reserved"); 5052e5100ee2SJack F Vogel else if (seid <= 511) 5053e5100ee2SJack F Vogel sbuf_cat(s, "Other"); // for other structures 5054e5100ee2SJack F Vogel else if (seid <= 895) 5055e5100ee2SJack F Vogel sbuf_printf(s, "VSI %d", seid - 512); 5056e5100ee2SJack F Vogel else if (seid <= 1023) 5057e5100ee2SJack F Vogel sbuf_printf(s, "Reserved"); 5058e5100ee2SJack F Vogel else 5059e5100ee2SJack F Vogel sbuf_cat(s, "Invalid"); 5060e5100ee2SJack F Vogel 5061e5100ee2SJack F Vogel sbuf_finish(s); 5062e5100ee2SJack F Vogel return sbuf_data(s); 5063e5100ee2SJack F Vogel } 5064e5100ee2SJack F Vogel 5065e5100ee2SJack F Vogel static int 5066e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS) 5067e5100ee2SJack F Vogel { 5068e5100ee2SJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 5069e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 5070e5100ee2SJack F Vogel device_t dev = pf->dev; 5071e5100ee2SJack F Vogel struct sbuf *buf; 5072e5100ee2SJack F Vogel struct sbuf *nmbuf; 5073e5100ee2SJack F Vogel int error = 0; 5074e5100ee2SJack F Vogel u8 aq_buf[I40E_AQ_LARGE_BUF]; 5075e5100ee2SJack F Vogel 5076e5100ee2SJack F Vogel u16 next = 0; 5077e5100ee2SJack F Vogel struct i40e_aqc_get_switch_config_resp *sw_config; 5078e5100ee2SJack F Vogel sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 5079e5100ee2SJack F Vogel 5080e5100ee2SJack F Vogel buf = sbuf_new_for_sysctl(NULL, NULL, 0, req); 5081e5100ee2SJack F Vogel if (!buf) { 5082e5100ee2SJack F Vogel device_printf(dev, "Could not allocate sbuf for sysctl output.\n"); 5083e5100ee2SJack F Vogel return (ENOMEM); 5084e5100ee2SJack F Vogel } 5085e5100ee2SJack F Vogel 5086e5100ee2SJack F Vogel error = i40e_aq_get_switch_config(hw, sw_config, 5087e5100ee2SJack F Vogel sizeof(aq_buf), &next, NULL); 5088e5100ee2SJack F Vogel if (error) { 5089*56c2c47bSJack F Vogel device_printf(dev, 5090*56c2c47bSJack F Vogel "%s: aq_get_switch_config() error %d, aq error %d\n", 5091e5100ee2SJack F Vogel __func__, error, hw->aq.asq_last_status); 5092e5100ee2SJack F Vogel sbuf_delete(buf); 5093e5100ee2SJack F Vogel return error; 5094e5100ee2SJack F Vogel } 5095e5100ee2SJack F Vogel 5096e5100ee2SJack F Vogel nmbuf = sbuf_new_auto(); 5097e5100ee2SJack F Vogel if (!nmbuf) { 5098e5100ee2SJack F Vogel device_printf(dev, "Could not allocate sbuf for name output.\n"); 5099e5100ee2SJack F Vogel return (ENOMEM); 5100e5100ee2SJack F Vogel } 5101e5100ee2SJack F Vogel 5102e5100ee2SJack F Vogel sbuf_cat(buf, "\n"); 5103e5100ee2SJack F Vogel // Assuming <= 255 elements in switch 5104e5100ee2SJack F Vogel sbuf_printf(buf, "# of elements: %d\n", sw_config->header.num_reported); 5105e5100ee2SJack F Vogel /* Exclude: 5106e5100ee2SJack F Vogel ** Revision -- all elements are revision 1 for now 5107e5100ee2SJack F Vogel */ 5108e5100ee2SJack F Vogel sbuf_printf(buf, 5109e5100ee2SJack F Vogel "SEID ( Name ) | Uplink | Downlink | Conn Type\n" 5110e5100ee2SJack F Vogel " | | | (uplink)\n"); 5111e5100ee2SJack F Vogel for (int i = 0; i < sw_config->header.num_reported; i++) { 5112e5100ee2SJack F Vogel // "%4d (%8s) | %8s %8s %#8x", 5113e5100ee2SJack F Vogel sbuf_printf(buf, "%4d", sw_config->element[i].seid); 5114e5100ee2SJack F Vogel sbuf_cat(buf, " "); 5115*56c2c47bSJack F Vogel sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf, 5116*56c2c47bSJack F Vogel sw_config->element[i].seid, false)); 5117e5100ee2SJack F Vogel sbuf_cat(buf, " | "); 5118*56c2c47bSJack F Vogel sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, 5119*56c2c47bSJack F Vogel sw_config->element[i].uplink_seid, true)); 5120e5100ee2SJack F Vogel sbuf_cat(buf, " "); 5121*56c2c47bSJack F Vogel sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, 5122*56c2c47bSJack F Vogel sw_config->element[i].downlink_seid, false)); 5123e5100ee2SJack F Vogel sbuf_cat(buf, " "); 5124e5100ee2SJack F Vogel sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type); 5125e5100ee2SJack F Vogel if (i < sw_config->header.num_reported - 1) 5126e5100ee2SJack F Vogel sbuf_cat(buf, "\n"); 5127e5100ee2SJack F Vogel } 5128e5100ee2SJack F Vogel sbuf_delete(nmbuf); 5129e5100ee2SJack F Vogel 5130e5100ee2SJack F Vogel error = sbuf_finish(buf); 5131e5100ee2SJack F Vogel if (error) { 5132e5100ee2SJack F Vogel device_printf(dev, "Error finishing sbuf: %d\n", error); 5133e5100ee2SJack F Vogel sbuf_delete(buf); 5134e5100ee2SJack F Vogel return error; 5135e5100ee2SJack F Vogel } 5136e5100ee2SJack F Vogel 5137e5100ee2SJack F Vogel error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req); 5138e5100ee2SJack F Vogel if (error) 5139e5100ee2SJack F Vogel device_printf(dev, "sysctl error: %d\n", error); 5140e5100ee2SJack F Vogel sbuf_delete(buf); 5141e5100ee2SJack F Vogel 5142e5100ee2SJack F Vogel return (error); 514361ae650dSJack F Vogel } 5144393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */ 514561ae650dSJack F Vogel 5146*56c2c47bSJack F Vogel 5147*56c2c47bSJack F Vogel #ifdef PCI_IOV 5148*56c2c47bSJack F Vogel static int 5149*56c2c47bSJack F Vogel ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf) 5150*56c2c47bSJack F Vogel { 5151*56c2c47bSJack F Vogel struct i40e_hw *hw; 5152*56c2c47bSJack F Vogel struct ixl_vsi *vsi; 5153*56c2c47bSJack F Vogel struct i40e_vsi_context vsi_ctx; 5154*56c2c47bSJack F Vogel int i; 5155*56c2c47bSJack F Vogel uint16_t first_queue; 5156*56c2c47bSJack F Vogel enum i40e_status_code code; 5157*56c2c47bSJack F Vogel 5158*56c2c47bSJack F Vogel hw = &pf->hw; 5159*56c2c47bSJack F Vogel vsi = &pf->vsi; 5160*56c2c47bSJack F Vogel 5161*56c2c47bSJack F Vogel vsi_ctx.pf_num = hw->pf_id; 5162*56c2c47bSJack F Vogel vsi_ctx.uplink_seid = pf->veb_seid; 5163*56c2c47bSJack F Vogel vsi_ctx.connection_type = IXL_VSI_DATA_PORT; 5164*56c2c47bSJack F Vogel vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num; 5165*56c2c47bSJack F Vogel vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF; 5166*56c2c47bSJack F Vogel 5167*56c2c47bSJack F Vogel bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); 5168*56c2c47bSJack F Vogel 5169*56c2c47bSJack F Vogel vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID); 5170*56c2c47bSJack F Vogel vsi_ctx.info.switch_id = htole16(0); 5171*56c2c47bSJack F Vogel 5172*56c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID); 5173*56c2c47bSJack F Vogel vsi_ctx.info.sec_flags = 0; 5174*56c2c47bSJack F Vogel if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF) 5175*56c2c47bSJack F Vogel vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK; 5176*56c2c47bSJack F Vogel 5177*56c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID); 5178*56c2c47bSJack F Vogel vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 5179*56c2c47bSJack F Vogel I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 5180*56c2c47bSJack F Vogel 5181*56c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= 5182*56c2c47bSJack F Vogel htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID); 5183*56c2c47bSJack F Vogel vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG); 5184*56c2c47bSJack F Vogel first_queue = vsi->num_queues + vf->vf_num * IXLV_MAX_QUEUES; 5185*56c2c47bSJack F Vogel for (i = 0; i < IXLV_MAX_QUEUES; i++) 5186*56c2c47bSJack F Vogel vsi_ctx.info.queue_mapping[i] = htole16(first_queue + i); 5187*56c2c47bSJack F Vogel for (; i < nitems(vsi_ctx.info.queue_mapping); i++) 5188*56c2c47bSJack F Vogel vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK); 5189*56c2c47bSJack F Vogel 5190*56c2c47bSJack F Vogel vsi_ctx.info.tc_mapping[0] = htole16( 5191*56c2c47bSJack F Vogel (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) | 5192*56c2c47bSJack F Vogel (1 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)); 5193*56c2c47bSJack F Vogel 5194*56c2c47bSJack F Vogel code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL); 5195*56c2c47bSJack F Vogel if (code != I40E_SUCCESS) 5196*56c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 5197*56c2c47bSJack F Vogel vf->vsi.seid = vsi_ctx.seid; 5198*56c2c47bSJack F Vogel vf->vsi.vsi_num = vsi_ctx.vsi_number; 5199*56c2c47bSJack F Vogel vf->vsi.first_queue = first_queue; 5200*56c2c47bSJack F Vogel vf->vsi.num_queues = IXLV_MAX_QUEUES; 5201*56c2c47bSJack F Vogel 5202*56c2c47bSJack F Vogel code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL); 5203*56c2c47bSJack F Vogel if (code != I40E_SUCCESS) 5204*56c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 5205*56c2c47bSJack F Vogel 5206*56c2c47bSJack F Vogel code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL); 5207*56c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 5208*56c2c47bSJack F Vogel device_printf(pf->dev, "Failed to disable BW limit: %d\n", 5209*56c2c47bSJack F Vogel ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 5210*56c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 5211*56c2c47bSJack F Vogel } 5212*56c2c47bSJack F Vogel 5213*56c2c47bSJack F Vogel memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info)); 5214*56c2c47bSJack F Vogel return (0); 5215*56c2c47bSJack F Vogel } 5216*56c2c47bSJack F Vogel 5217*56c2c47bSJack F Vogel static int 5218*56c2c47bSJack F Vogel ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf) 5219*56c2c47bSJack F Vogel { 5220*56c2c47bSJack F Vogel struct i40e_hw *hw; 5221*56c2c47bSJack F Vogel int error; 5222*56c2c47bSJack F Vogel 5223*56c2c47bSJack F Vogel hw = &pf->hw; 5224*56c2c47bSJack F Vogel 5225*56c2c47bSJack F Vogel error = ixl_vf_alloc_vsi(pf, vf); 5226*56c2c47bSJack F Vogel if (error != 0) 5227*56c2c47bSJack F Vogel return (error); 5228*56c2c47bSJack F Vogel 5229*56c2c47bSJack F Vogel vf->vsi.hw_filters_add = 0; 5230*56c2c47bSJack F Vogel vf->vsi.hw_filters_del = 0; 5231*56c2c47bSJack F Vogel ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY); 5232*56c2c47bSJack F Vogel ixl_reconfigure_filters(&vf->vsi); 5233*56c2c47bSJack F Vogel 5234*56c2c47bSJack F Vogel return (0); 5235*56c2c47bSJack F Vogel } 5236*56c2c47bSJack F Vogel 5237*56c2c47bSJack F Vogel static void 5238*56c2c47bSJack F Vogel ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum, 5239*56c2c47bSJack F Vogel uint32_t val) 5240*56c2c47bSJack F Vogel { 5241*56c2c47bSJack F Vogel uint32_t qtable; 5242*56c2c47bSJack F Vogel int index, shift; 5243*56c2c47bSJack F Vogel 5244*56c2c47bSJack F Vogel /* 5245*56c2c47bSJack F Vogel * Two queues are mapped in a single register, so we have to do some 5246*56c2c47bSJack F Vogel * gymnastics to convert the queue number into a register index and 5247*56c2c47bSJack F Vogel * shift. 5248*56c2c47bSJack F Vogel */ 5249*56c2c47bSJack F Vogel index = qnum / 2; 5250*56c2c47bSJack F Vogel shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT; 5251*56c2c47bSJack F Vogel 5252*56c2c47bSJack F Vogel qtable = rd32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num)); 5253*56c2c47bSJack F Vogel qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift); 5254*56c2c47bSJack F Vogel qtable |= val << shift; 5255*56c2c47bSJack F Vogel wr32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable); 5256*56c2c47bSJack F Vogel } 5257*56c2c47bSJack F Vogel 5258*56c2c47bSJack F Vogel static void 5259*56c2c47bSJack F Vogel ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf) 5260*56c2c47bSJack F Vogel { 5261*56c2c47bSJack F Vogel struct i40e_hw *hw; 5262*56c2c47bSJack F Vogel uint32_t qtable; 5263*56c2c47bSJack F Vogel int i; 5264*56c2c47bSJack F Vogel 5265*56c2c47bSJack F Vogel hw = &pf->hw; 5266*56c2c47bSJack F Vogel 5267*56c2c47bSJack F Vogel /* 5268*56c2c47bSJack F Vogel * Contiguous mappings aren't actually supported by the hardware, 5269*56c2c47bSJack F Vogel * so we have to use non-contiguous mappings. 5270*56c2c47bSJack F Vogel */ 5271*56c2c47bSJack F Vogel wr32(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num), 5272*56c2c47bSJack F Vogel I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK); 5273*56c2c47bSJack F Vogel 5274*56c2c47bSJack F Vogel wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num), 5275*56c2c47bSJack F Vogel I40E_VPLAN_MAPENA_TXRX_ENA_MASK); 5276*56c2c47bSJack F Vogel 5277*56c2c47bSJack F Vogel for (i = 0; i < vf->vsi.num_queues; i++) { 5278*56c2c47bSJack F Vogel qtable = (vf->vsi.first_queue + i) << 5279*56c2c47bSJack F Vogel I40E_VPLAN_QTABLE_QINDEX_SHIFT; 5280*56c2c47bSJack F Vogel 5281*56c2c47bSJack F Vogel wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable); 5282*56c2c47bSJack F Vogel } 5283*56c2c47bSJack F Vogel 5284*56c2c47bSJack F Vogel /* Map queues allocated to VF to its VSI. */ 5285*56c2c47bSJack F Vogel for (i = 0; i < vf->vsi.num_queues; i++) 5286*56c2c47bSJack F Vogel ixl_vf_map_vsi_queue(hw, vf, i, vf->vsi.first_queue + i); 5287*56c2c47bSJack F Vogel 5288*56c2c47bSJack F Vogel /* Set rest of VSI queues as unused. */ 5289*56c2c47bSJack F Vogel for (; i < IXL_MAX_VSI_QUEUES; i++) 5290*56c2c47bSJack F Vogel ixl_vf_map_vsi_queue(hw, vf, i, 5291*56c2c47bSJack F Vogel I40E_VSILAN_QTABLE_QINDEX_0_MASK); 5292*56c2c47bSJack F Vogel 5293*56c2c47bSJack F Vogel ixl_flush(hw); 5294*56c2c47bSJack F Vogel } 5295*56c2c47bSJack F Vogel 5296*56c2c47bSJack F Vogel static void 5297*56c2c47bSJack F Vogel ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi) 5298*56c2c47bSJack F Vogel { 5299*56c2c47bSJack F Vogel struct i40e_hw *hw; 5300*56c2c47bSJack F Vogel 5301*56c2c47bSJack F Vogel hw = &pf->hw; 5302*56c2c47bSJack F Vogel 5303*56c2c47bSJack F Vogel if (vsi->seid == 0) 5304*56c2c47bSJack F Vogel return; 5305*56c2c47bSJack F Vogel 5306*56c2c47bSJack F Vogel i40e_aq_delete_element(hw, vsi->seid, NULL); 5307*56c2c47bSJack F Vogel } 5308*56c2c47bSJack F Vogel 5309*56c2c47bSJack F Vogel static void 5310*56c2c47bSJack F Vogel ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg) 5311*56c2c47bSJack F Vogel { 5312*56c2c47bSJack F Vogel 5313*56c2c47bSJack F Vogel wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK); 5314*56c2c47bSJack F Vogel ixl_flush(hw); 5315*56c2c47bSJack F Vogel } 5316*56c2c47bSJack F Vogel 5317*56c2c47bSJack F Vogel static void 5318*56c2c47bSJack F Vogel ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg) 5319*56c2c47bSJack F Vogel { 5320*56c2c47bSJack F Vogel 5321*56c2c47bSJack F Vogel wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK | 5322*56c2c47bSJack F Vogel I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK); 5323*56c2c47bSJack F Vogel ixl_flush(hw); 5324*56c2c47bSJack F Vogel } 5325*56c2c47bSJack F Vogel 5326*56c2c47bSJack F Vogel static void 5327*56c2c47bSJack F Vogel ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf) 5328*56c2c47bSJack F Vogel { 5329*56c2c47bSJack F Vogel struct i40e_hw *hw; 5330*56c2c47bSJack F Vogel uint32_t vfint_reg, vpint_reg; 5331*56c2c47bSJack F Vogel int i; 5332*56c2c47bSJack F Vogel 5333*56c2c47bSJack F Vogel hw = &pf->hw; 5334*56c2c47bSJack F Vogel 5335*56c2c47bSJack F Vogel ixl_vf_vsi_release(pf, &vf->vsi); 5336*56c2c47bSJack F Vogel 5337*56c2c47bSJack F Vogel /* Index 0 has a special register. */ 5338*56c2c47bSJack F Vogel ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num)); 5339*56c2c47bSJack F Vogel 5340*56c2c47bSJack F Vogel for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) { 5341*56c2c47bSJack F Vogel vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num); 5342*56c2c47bSJack F Vogel ixl_vf_disable_queue_intr(hw, vfint_reg); 5343*56c2c47bSJack F Vogel } 5344*56c2c47bSJack F Vogel 5345*56c2c47bSJack F Vogel /* Index 0 has a special register. */ 5346*56c2c47bSJack F Vogel ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num)); 5347*56c2c47bSJack F Vogel 5348*56c2c47bSJack F Vogel for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) { 5349*56c2c47bSJack F Vogel vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num); 5350*56c2c47bSJack F Vogel ixl_vf_unregister_intr(hw, vpint_reg); 5351*56c2c47bSJack F Vogel } 5352*56c2c47bSJack F Vogel 5353*56c2c47bSJack F Vogel vf->vsi.num_queues = 0; 5354*56c2c47bSJack F Vogel } 5355*56c2c47bSJack F Vogel 5356*56c2c47bSJack F Vogel static int 5357*56c2c47bSJack F Vogel ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf) 5358*56c2c47bSJack F Vogel { 5359*56c2c47bSJack F Vogel struct i40e_hw *hw; 5360*56c2c47bSJack F Vogel int i; 5361*56c2c47bSJack F Vogel uint16_t global_vf_num; 5362*56c2c47bSJack F Vogel uint32_t ciad; 5363*56c2c47bSJack F Vogel 5364*56c2c47bSJack F Vogel hw = &pf->hw; 5365*56c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + vf->vf_num; 5366*56c2c47bSJack F Vogel 5367*56c2c47bSJack F Vogel wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS | 5368*56c2c47bSJack F Vogel (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT)); 5369*56c2c47bSJack F Vogel for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) { 5370*56c2c47bSJack F Vogel ciad = rd32(hw, I40E_PF_PCI_CIAD); 5371*56c2c47bSJack F Vogel if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0) 5372*56c2c47bSJack F Vogel return (0); 5373*56c2c47bSJack F Vogel DELAY(1); 5374*56c2c47bSJack F Vogel } 5375*56c2c47bSJack F Vogel 5376*56c2c47bSJack F Vogel return (ETIMEDOUT); 5377*56c2c47bSJack F Vogel } 5378*56c2c47bSJack F Vogel 5379*56c2c47bSJack F Vogel static void 5380*56c2c47bSJack F Vogel ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf) 5381*56c2c47bSJack F Vogel { 5382*56c2c47bSJack F Vogel struct i40e_hw *hw; 5383*56c2c47bSJack F Vogel uint32_t vfrtrig; 5384*56c2c47bSJack F Vogel 5385*56c2c47bSJack F Vogel hw = &pf->hw; 5386*56c2c47bSJack F Vogel 5387*56c2c47bSJack F Vogel vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); 5388*56c2c47bSJack F Vogel vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK; 5389*56c2c47bSJack F Vogel wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); 5390*56c2c47bSJack F Vogel ixl_flush(hw); 5391*56c2c47bSJack F Vogel 5392*56c2c47bSJack F Vogel ixl_reinit_vf(pf, vf); 5393*56c2c47bSJack F Vogel } 5394*56c2c47bSJack F Vogel 5395*56c2c47bSJack F Vogel static void 5396*56c2c47bSJack F Vogel ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf) 5397*56c2c47bSJack F Vogel { 5398*56c2c47bSJack F Vogel struct i40e_hw *hw; 5399*56c2c47bSJack F Vogel uint32_t vfrstat, vfrtrig; 5400*56c2c47bSJack F Vogel int i, error; 5401*56c2c47bSJack F Vogel 5402*56c2c47bSJack F Vogel hw = &pf->hw; 5403*56c2c47bSJack F Vogel 5404*56c2c47bSJack F Vogel error = ixl_flush_pcie(pf, vf); 5405*56c2c47bSJack F Vogel if (error != 0) 5406*56c2c47bSJack F Vogel device_printf(pf->dev, 5407*56c2c47bSJack F Vogel "Timed out waiting for PCIe activity to stop on VF-%d\n", 5408*56c2c47bSJack F Vogel vf->vf_num); 5409*56c2c47bSJack F Vogel 5410*56c2c47bSJack F Vogel for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) { 5411*56c2c47bSJack F Vogel DELAY(10); 5412*56c2c47bSJack F Vogel 5413*56c2c47bSJack F Vogel vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num)); 5414*56c2c47bSJack F Vogel if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK) 5415*56c2c47bSJack F Vogel break; 5416*56c2c47bSJack F Vogel } 5417*56c2c47bSJack F Vogel 5418*56c2c47bSJack F Vogel if (i == IXL_VF_RESET_TIMEOUT) 5419*56c2c47bSJack F Vogel device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num); 5420*56c2c47bSJack F Vogel 5421*56c2c47bSJack F Vogel wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_COMPLETED); 5422*56c2c47bSJack F Vogel 5423*56c2c47bSJack F Vogel vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); 5424*56c2c47bSJack F Vogel vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK; 5425*56c2c47bSJack F Vogel wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); 5426*56c2c47bSJack F Vogel 5427*56c2c47bSJack F Vogel if (vf->vsi.seid != 0) 5428*56c2c47bSJack F Vogel ixl_disable_rings(&vf->vsi); 5429*56c2c47bSJack F Vogel 5430*56c2c47bSJack F Vogel ixl_vf_release_resources(pf, vf); 5431*56c2c47bSJack F Vogel ixl_vf_setup_vsi(pf, vf); 5432*56c2c47bSJack F Vogel ixl_vf_map_queues(pf, vf); 5433*56c2c47bSJack F Vogel 5434*56c2c47bSJack F Vogel wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_VFACTIVE); 5435*56c2c47bSJack F Vogel ixl_flush(hw); 5436*56c2c47bSJack F Vogel } 5437*56c2c47bSJack F Vogel 5438*56c2c47bSJack F Vogel static const char * 5439*56c2c47bSJack F Vogel ixl_vc_opcode_str(uint16_t op) 5440*56c2c47bSJack F Vogel { 5441*56c2c47bSJack F Vogel 5442*56c2c47bSJack F Vogel switch (op) { 5443*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_VERSION: 5444*56c2c47bSJack F Vogel return ("VERSION"); 5445*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_RESET_VF: 5446*56c2c47bSJack F Vogel return ("RESET_VF"); 5447*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: 5448*56c2c47bSJack F Vogel return ("GET_VF_RESOURCES"); 5449*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: 5450*56c2c47bSJack F Vogel return ("CONFIG_TX_QUEUE"); 5451*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: 5452*56c2c47bSJack F Vogel return ("CONFIG_RX_QUEUE"); 5453*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: 5454*56c2c47bSJack F Vogel return ("CONFIG_VSI_QUEUES"); 5455*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: 5456*56c2c47bSJack F Vogel return ("CONFIG_IRQ_MAP"); 5457*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ENABLE_QUEUES: 5458*56c2c47bSJack F Vogel return ("ENABLE_QUEUES"); 5459*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DISABLE_QUEUES: 5460*56c2c47bSJack F Vogel return ("DISABLE_QUEUES"); 5461*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: 5462*56c2c47bSJack F Vogel return ("ADD_ETHER_ADDRESS"); 5463*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: 5464*56c2c47bSJack F Vogel return ("DEL_ETHER_ADDRESS"); 5465*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_VLAN: 5466*56c2c47bSJack F Vogel return ("ADD_VLAN"); 5467*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_VLAN: 5468*56c2c47bSJack F Vogel return ("DEL_VLAN"); 5469*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: 5470*56c2c47bSJack F Vogel return ("CONFIG_PROMISCUOUS_MODE"); 5471*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 5472*56c2c47bSJack F Vogel return ("GET_STATS"); 5473*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_FCOE: 5474*56c2c47bSJack F Vogel return ("FCOE"); 5475*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_EVENT: 5476*56c2c47bSJack F Vogel return ("EVENT"); 5477*56c2c47bSJack F Vogel default: 5478*56c2c47bSJack F Vogel return ("UNKNOWN"); 5479*56c2c47bSJack F Vogel } 5480*56c2c47bSJack F Vogel } 5481*56c2c47bSJack F Vogel 5482*56c2c47bSJack F Vogel static int 5483*56c2c47bSJack F Vogel ixl_vc_opcode_level(uint16_t opcode) 5484*56c2c47bSJack F Vogel { 5485*56c2c47bSJack F Vogel 5486*56c2c47bSJack F Vogel switch (opcode) { 5487*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 5488*56c2c47bSJack F Vogel return (10); 5489*56c2c47bSJack F Vogel default: 5490*56c2c47bSJack F Vogel return (5); 5491*56c2c47bSJack F Vogel } 5492*56c2c47bSJack F Vogel } 5493*56c2c47bSJack F Vogel 5494*56c2c47bSJack F Vogel static void 5495*56c2c47bSJack F Vogel ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, 5496*56c2c47bSJack F Vogel enum i40e_status_code status, void *msg, uint16_t len) 5497*56c2c47bSJack F Vogel { 5498*56c2c47bSJack F Vogel struct i40e_hw *hw; 5499*56c2c47bSJack F Vogel int global_vf_id; 5500*56c2c47bSJack F Vogel 5501*56c2c47bSJack F Vogel hw = &pf->hw; 5502*56c2c47bSJack F Vogel global_vf_id = hw->func_caps.vf_base_id + vf->vf_num; 5503*56c2c47bSJack F Vogel 5504*56c2c47bSJack F Vogel I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op), 5505*56c2c47bSJack F Vogel "Sending msg (op=%s[%d], status=%d) to VF-%d\n", 5506*56c2c47bSJack F Vogel ixl_vc_opcode_str(op), op, status, vf->vf_num); 5507*56c2c47bSJack F Vogel 5508*56c2c47bSJack F Vogel i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL); 5509*56c2c47bSJack F Vogel } 5510*56c2c47bSJack F Vogel 5511*56c2c47bSJack F Vogel static void 5512*56c2c47bSJack F Vogel ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op) 5513*56c2c47bSJack F Vogel { 5514*56c2c47bSJack F Vogel 5515*56c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0); 5516*56c2c47bSJack F Vogel } 5517*56c2c47bSJack F Vogel 5518*56c2c47bSJack F Vogel static void 5519*56c2c47bSJack F Vogel ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, 5520*56c2c47bSJack F Vogel enum i40e_status_code status, const char *file, int line) 5521*56c2c47bSJack F Vogel { 5522*56c2c47bSJack F Vogel 5523*56c2c47bSJack F Vogel I40E_VC_DEBUG(pf, 1, 5524*56c2c47bSJack F Vogel "Sending NACK (op=%s[%d], err=%d) to VF-%d from %s:%d\n", 5525*56c2c47bSJack F Vogel ixl_vc_opcode_str(op), op, status, vf->vf_num, file, line); 5526*56c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, op, status, NULL, 0); 5527*56c2c47bSJack F Vogel } 5528*56c2c47bSJack F Vogel 5529*56c2c47bSJack F Vogel static void 5530*56c2c47bSJack F Vogel ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 5531*56c2c47bSJack F Vogel uint16_t msg_size) 5532*56c2c47bSJack F Vogel { 5533*56c2c47bSJack F Vogel struct i40e_virtchnl_version_info reply; 5534*56c2c47bSJack F Vogel 5535*56c2c47bSJack F Vogel if (msg_size != sizeof(struct i40e_virtchnl_version_info)) { 5536*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_VERSION, 5537*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5538*56c2c47bSJack F Vogel return; 5539*56c2c47bSJack F Vogel } 5540*56c2c47bSJack F Vogel 5541*56c2c47bSJack F Vogel reply.major = I40E_VIRTCHNL_VERSION_MAJOR; 5542*56c2c47bSJack F Vogel reply.minor = I40E_VIRTCHNL_VERSION_MINOR; 5543*56c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, &reply, 5544*56c2c47bSJack F Vogel sizeof(reply)); 5545*56c2c47bSJack F Vogel } 5546*56c2c47bSJack F Vogel 5547*56c2c47bSJack F Vogel static void 5548*56c2c47bSJack F Vogel ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 5549*56c2c47bSJack F Vogel uint16_t msg_size) 5550*56c2c47bSJack F Vogel { 5551*56c2c47bSJack F Vogel 5552*56c2c47bSJack F Vogel if (msg_size != 0) { 5553*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_RESET_VF, 5554*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5555*56c2c47bSJack F Vogel return; 5556*56c2c47bSJack F Vogel } 5557*56c2c47bSJack F Vogel 5558*56c2c47bSJack F Vogel ixl_reset_vf(pf, vf); 5559*56c2c47bSJack F Vogel 5560*56c2c47bSJack F Vogel /* No response to a reset message. */ 5561*56c2c47bSJack F Vogel } 5562*56c2c47bSJack F Vogel 5563*56c2c47bSJack F Vogel static void 5564*56c2c47bSJack F Vogel ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 5565*56c2c47bSJack F Vogel uint16_t msg_size) 5566*56c2c47bSJack F Vogel { 5567*56c2c47bSJack F Vogel struct i40e_virtchnl_vf_resource reply; 5568*56c2c47bSJack F Vogel 5569*56c2c47bSJack F Vogel if (msg_size != 0) { 5570*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, 5571*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5572*56c2c47bSJack F Vogel return; 5573*56c2c47bSJack F Vogel } 5574*56c2c47bSJack F Vogel 5575*56c2c47bSJack F Vogel bzero(&reply, sizeof(reply)); 5576*56c2c47bSJack F Vogel 5577*56c2c47bSJack F Vogel reply.vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2; 5578*56c2c47bSJack F Vogel 5579*56c2c47bSJack F Vogel reply.num_vsis = 1; 5580*56c2c47bSJack F Vogel reply.num_queue_pairs = vf->vsi.num_queues; 5581*56c2c47bSJack F Vogel reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf; 5582*56c2c47bSJack F Vogel reply.vsi_res[0].vsi_id = vf->vsi.vsi_num; 5583*56c2c47bSJack F Vogel reply.vsi_res[0].vsi_type = I40E_VSI_SRIOV; 5584*56c2c47bSJack F Vogel reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues; 5585*56c2c47bSJack F Vogel memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN); 5586*56c2c47bSJack F Vogel 5587*56c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, 5588*56c2c47bSJack F Vogel I40E_SUCCESS, &reply, sizeof(reply)); 5589*56c2c47bSJack F Vogel } 5590*56c2c47bSJack F Vogel 5591*56c2c47bSJack F Vogel static int 5592*56c2c47bSJack F Vogel ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf, 5593*56c2c47bSJack F Vogel struct i40e_virtchnl_txq_info *info) 5594*56c2c47bSJack F Vogel { 5595*56c2c47bSJack F Vogel struct i40e_hw *hw; 5596*56c2c47bSJack F Vogel struct i40e_hmc_obj_txq txq; 5597*56c2c47bSJack F Vogel uint16_t global_queue_num, global_vf_num; 5598*56c2c47bSJack F Vogel enum i40e_status_code status; 5599*56c2c47bSJack F Vogel uint32_t qtx_ctl; 5600*56c2c47bSJack F Vogel 5601*56c2c47bSJack F Vogel hw = &pf->hw; 5602*56c2c47bSJack F Vogel global_queue_num = vf->vsi.first_queue + info->queue_id; 5603*56c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + vf->vf_num; 5604*56c2c47bSJack F Vogel bzero(&txq, sizeof(txq)); 5605*56c2c47bSJack F Vogel 5606*56c2c47bSJack F Vogel status = i40e_clear_lan_tx_queue_context(hw, global_queue_num); 5607*56c2c47bSJack F Vogel if (status != I40E_SUCCESS) 5608*56c2c47bSJack F Vogel return (EINVAL); 5609*56c2c47bSJack F Vogel 5610*56c2c47bSJack F Vogel txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS; 5611*56c2c47bSJack F Vogel 5612*56c2c47bSJack F Vogel txq.head_wb_ena = info->headwb_enabled; 5613*56c2c47bSJack F Vogel txq.head_wb_addr = info->dma_headwb_addr; 5614*56c2c47bSJack F Vogel txq.qlen = info->ring_len; 5615*56c2c47bSJack F Vogel txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]); 5616*56c2c47bSJack F Vogel txq.rdylist_act = 0; 5617*56c2c47bSJack F Vogel 5618*56c2c47bSJack F Vogel status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq); 5619*56c2c47bSJack F Vogel if (status != I40E_SUCCESS) 5620*56c2c47bSJack F Vogel return (EINVAL); 5621*56c2c47bSJack F Vogel 5622*56c2c47bSJack F Vogel qtx_ctl = I40E_QTX_CTL_VF_QUEUE | 5623*56c2c47bSJack F Vogel (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) | 5624*56c2c47bSJack F Vogel (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT); 5625*56c2c47bSJack F Vogel wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl); 5626*56c2c47bSJack F Vogel ixl_flush(hw); 5627*56c2c47bSJack F Vogel 5628*56c2c47bSJack F Vogel return (0); 5629*56c2c47bSJack F Vogel } 5630*56c2c47bSJack F Vogel 5631*56c2c47bSJack F Vogel static int 5632*56c2c47bSJack F Vogel ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf, 5633*56c2c47bSJack F Vogel struct i40e_virtchnl_rxq_info *info) 5634*56c2c47bSJack F Vogel { 5635*56c2c47bSJack F Vogel struct i40e_hw *hw; 5636*56c2c47bSJack F Vogel struct i40e_hmc_obj_rxq rxq; 5637*56c2c47bSJack F Vogel uint16_t global_queue_num; 5638*56c2c47bSJack F Vogel enum i40e_status_code status; 5639*56c2c47bSJack F Vogel 5640*56c2c47bSJack F Vogel hw = &pf->hw; 5641*56c2c47bSJack F Vogel global_queue_num = vf->vsi.first_queue + info->queue_id; 5642*56c2c47bSJack F Vogel bzero(&rxq, sizeof(rxq)); 5643*56c2c47bSJack F Vogel 5644*56c2c47bSJack F Vogel if (info->databuffer_size > IXL_VF_MAX_BUFFER) 5645*56c2c47bSJack F Vogel return (EINVAL); 5646*56c2c47bSJack F Vogel 5647*56c2c47bSJack F Vogel if (info->max_pkt_size > IXL_VF_MAX_FRAME || 5648*56c2c47bSJack F Vogel info->max_pkt_size < ETHER_MIN_LEN) 5649*56c2c47bSJack F Vogel return (EINVAL); 5650*56c2c47bSJack F Vogel 5651*56c2c47bSJack F Vogel if (info->splithdr_enabled) { 5652*56c2c47bSJack F Vogel if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER) 5653*56c2c47bSJack F Vogel return (EINVAL); 5654*56c2c47bSJack F Vogel 5655*56c2c47bSJack F Vogel rxq.hsplit_0 = info->rx_split_pos & 5656*56c2c47bSJack F Vogel (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 | 5657*56c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP | 5658*56c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP | 5659*56c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP); 5660*56c2c47bSJack F Vogel rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT; 5661*56c2c47bSJack F Vogel 5662*56c2c47bSJack F Vogel rxq.dtype = 2; 5663*56c2c47bSJack F Vogel } 5664*56c2c47bSJack F Vogel 5665*56c2c47bSJack F Vogel status = i40e_clear_lan_rx_queue_context(hw, global_queue_num); 5666*56c2c47bSJack F Vogel if (status != I40E_SUCCESS) 5667*56c2c47bSJack F Vogel return (EINVAL); 5668*56c2c47bSJack F Vogel 5669*56c2c47bSJack F Vogel rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS; 5670*56c2c47bSJack F Vogel rxq.qlen = info->ring_len; 5671*56c2c47bSJack F Vogel 5672*56c2c47bSJack F Vogel rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT; 5673*56c2c47bSJack F Vogel 5674*56c2c47bSJack F Vogel rxq.dsize = 1; 5675*56c2c47bSJack F Vogel rxq.crcstrip = 1; 5676*56c2c47bSJack F Vogel rxq.l2tsel = 1; 5677*56c2c47bSJack F Vogel 5678*56c2c47bSJack F Vogel rxq.rxmax = info->max_pkt_size; 5679*56c2c47bSJack F Vogel rxq.tphrdesc_ena = 1; 5680*56c2c47bSJack F Vogel rxq.tphwdesc_ena = 1; 5681*56c2c47bSJack F Vogel rxq.tphdata_ena = 1; 5682*56c2c47bSJack F Vogel rxq.tphhead_ena = 1; 5683*56c2c47bSJack F Vogel rxq.lrxqthresh = 2; 5684*56c2c47bSJack F Vogel rxq.prefena = 1; 5685*56c2c47bSJack F Vogel 5686*56c2c47bSJack F Vogel status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq); 5687*56c2c47bSJack F Vogel if (status != I40E_SUCCESS) 5688*56c2c47bSJack F Vogel return (EINVAL); 5689*56c2c47bSJack F Vogel 5690*56c2c47bSJack F Vogel return (0); 5691*56c2c47bSJack F Vogel } 5692*56c2c47bSJack F Vogel 5693*56c2c47bSJack F Vogel static void 5694*56c2c47bSJack F Vogel ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 5695*56c2c47bSJack F Vogel uint16_t msg_size) 5696*56c2c47bSJack F Vogel { 5697*56c2c47bSJack F Vogel struct i40e_virtchnl_vsi_queue_config_info *info; 5698*56c2c47bSJack F Vogel struct i40e_virtchnl_queue_pair_info *pair; 5699*56c2c47bSJack F Vogel int i; 5700*56c2c47bSJack F Vogel 5701*56c2c47bSJack F Vogel if (msg_size < sizeof(*info)) { 5702*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 5703*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5704*56c2c47bSJack F Vogel return; 5705*56c2c47bSJack F Vogel } 5706*56c2c47bSJack F Vogel 5707*56c2c47bSJack F Vogel info = msg; 5708*56c2c47bSJack F Vogel if (info->num_queue_pairs == 0) { 5709*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 5710*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5711*56c2c47bSJack F Vogel return; 5712*56c2c47bSJack F Vogel } 5713*56c2c47bSJack F Vogel 5714*56c2c47bSJack F Vogel if (msg_size != sizeof(*info) + info->num_queue_pairs * sizeof(*pair)) { 5715*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 5716*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5717*56c2c47bSJack F Vogel return; 5718*56c2c47bSJack F Vogel } 5719*56c2c47bSJack F Vogel 5720*56c2c47bSJack F Vogel if (info->vsi_id != vf->vsi.vsi_num) { 5721*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 5722*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5723*56c2c47bSJack F Vogel return; 5724*56c2c47bSJack F Vogel } 5725*56c2c47bSJack F Vogel 5726*56c2c47bSJack F Vogel for (i = 0; i < info->num_queue_pairs; i++) { 5727*56c2c47bSJack F Vogel pair = &info->qpair[i]; 5728*56c2c47bSJack F Vogel 5729*56c2c47bSJack F Vogel if (pair->txq.vsi_id != vf->vsi.vsi_num || 5730*56c2c47bSJack F Vogel pair->rxq.vsi_id != vf->vsi.vsi_num || 5731*56c2c47bSJack F Vogel pair->txq.queue_id != pair->rxq.queue_id || 5732*56c2c47bSJack F Vogel pair->txq.queue_id >= vf->vsi.num_queues) { 5733*56c2c47bSJack F Vogel 5734*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 5735*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 5736*56c2c47bSJack F Vogel return; 5737*56c2c47bSJack F Vogel } 5738*56c2c47bSJack F Vogel 5739*56c2c47bSJack F Vogel if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) { 5740*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 5741*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 5742*56c2c47bSJack F Vogel return; 5743*56c2c47bSJack F Vogel } 5744*56c2c47bSJack F Vogel 5745*56c2c47bSJack F Vogel if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) { 5746*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 5747*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 5748*56c2c47bSJack F Vogel return; 5749*56c2c47bSJack F Vogel } 5750*56c2c47bSJack F Vogel } 5751*56c2c47bSJack F Vogel 5752*56c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES); 5753*56c2c47bSJack F Vogel } 5754*56c2c47bSJack F Vogel 5755*56c2c47bSJack F Vogel static void 5756*56c2c47bSJack F Vogel ixl_vf_set_qctl(struct ixl_pf *pf, 5757*56c2c47bSJack F Vogel const struct i40e_virtchnl_vector_map *vector, 5758*56c2c47bSJack F Vogel enum i40e_queue_type cur_type, uint16_t cur_queue, 5759*56c2c47bSJack F Vogel enum i40e_queue_type *last_type, uint16_t *last_queue) 5760*56c2c47bSJack F Vogel { 5761*56c2c47bSJack F Vogel uint32_t offset, qctl; 5762*56c2c47bSJack F Vogel uint16_t itr_indx; 5763*56c2c47bSJack F Vogel 5764*56c2c47bSJack F Vogel if (cur_type == I40E_QUEUE_TYPE_RX) { 5765*56c2c47bSJack F Vogel offset = I40E_QINT_RQCTL(cur_queue); 5766*56c2c47bSJack F Vogel itr_indx = vector->rxitr_idx; 5767*56c2c47bSJack F Vogel } else { 5768*56c2c47bSJack F Vogel offset = I40E_QINT_TQCTL(cur_queue); 5769*56c2c47bSJack F Vogel itr_indx = vector->txitr_idx; 5770*56c2c47bSJack F Vogel } 5771*56c2c47bSJack F Vogel 5772*56c2c47bSJack F Vogel qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 5773*56c2c47bSJack F Vogel (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) | 5774*56c2c47bSJack F Vogel (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 5775*56c2c47bSJack F Vogel I40E_QINT_RQCTL_CAUSE_ENA_MASK | 5776*56c2c47bSJack F Vogel (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT)); 5777*56c2c47bSJack F Vogel 5778*56c2c47bSJack F Vogel wr32(&pf->hw, offset, qctl); 5779*56c2c47bSJack F Vogel 5780*56c2c47bSJack F Vogel *last_type = cur_type; 5781*56c2c47bSJack F Vogel *last_queue = cur_queue; 5782*56c2c47bSJack F Vogel } 5783*56c2c47bSJack F Vogel 5784*56c2c47bSJack F Vogel static void 5785*56c2c47bSJack F Vogel ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf, 5786*56c2c47bSJack F Vogel const struct i40e_virtchnl_vector_map *vector) 5787*56c2c47bSJack F Vogel { 5788*56c2c47bSJack F Vogel struct i40e_hw *hw; 5789*56c2c47bSJack F Vogel u_int qindex; 5790*56c2c47bSJack F Vogel enum i40e_queue_type type, last_type; 5791*56c2c47bSJack F Vogel uint32_t lnklst_reg; 5792*56c2c47bSJack F Vogel uint16_t rxq_map, txq_map, cur_queue, last_queue; 5793*56c2c47bSJack F Vogel 5794*56c2c47bSJack F Vogel hw = &pf->hw; 5795*56c2c47bSJack F Vogel 5796*56c2c47bSJack F Vogel rxq_map = vector->rxq_map; 5797*56c2c47bSJack F Vogel txq_map = vector->txq_map; 5798*56c2c47bSJack F Vogel 5799*56c2c47bSJack F Vogel last_queue = IXL_END_OF_INTR_LNKLST; 5800*56c2c47bSJack F Vogel last_type = I40E_QUEUE_TYPE_RX; 5801*56c2c47bSJack F Vogel 5802*56c2c47bSJack F Vogel /* 5803*56c2c47bSJack F Vogel * The datasheet says to optimize performance, RX queues and TX queues 5804*56c2c47bSJack F Vogel * should be interleaved in the interrupt linked list, so we process 5805*56c2c47bSJack F Vogel * both at once here. 5806*56c2c47bSJack F Vogel */ 5807*56c2c47bSJack F Vogel while ((rxq_map != 0) || (txq_map != 0)) { 5808*56c2c47bSJack F Vogel if (txq_map != 0) { 5809*56c2c47bSJack F Vogel qindex = ffs(txq_map) - 1; 5810*56c2c47bSJack F Vogel type = I40E_QUEUE_TYPE_TX; 5811*56c2c47bSJack F Vogel cur_queue = vf->vsi.first_queue + qindex; 5812*56c2c47bSJack F Vogel ixl_vf_set_qctl(pf, vector, type, cur_queue, 5813*56c2c47bSJack F Vogel &last_type, &last_queue); 5814*56c2c47bSJack F Vogel txq_map &= ~(1 << qindex); 5815*56c2c47bSJack F Vogel } 5816*56c2c47bSJack F Vogel 5817*56c2c47bSJack F Vogel if (rxq_map != 0) { 5818*56c2c47bSJack F Vogel qindex = ffs(rxq_map) - 1; 5819*56c2c47bSJack F Vogel type = I40E_QUEUE_TYPE_RX; 5820*56c2c47bSJack F Vogel cur_queue = vf->vsi.first_queue + qindex; 5821*56c2c47bSJack F Vogel ixl_vf_set_qctl(pf, vector, type, cur_queue, 5822*56c2c47bSJack F Vogel &last_type, &last_queue); 5823*56c2c47bSJack F Vogel rxq_map &= ~(1 << qindex); 5824*56c2c47bSJack F Vogel } 5825*56c2c47bSJack F Vogel } 5826*56c2c47bSJack F Vogel 5827*56c2c47bSJack F Vogel if (vector->vector_id == 0) 5828*56c2c47bSJack F Vogel lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num); 5829*56c2c47bSJack F Vogel else 5830*56c2c47bSJack F Vogel lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id, 5831*56c2c47bSJack F Vogel vf->vf_num); 5832*56c2c47bSJack F Vogel wr32(hw, lnklst_reg, 5833*56c2c47bSJack F Vogel (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) | 5834*56c2c47bSJack F Vogel (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT)); 5835*56c2c47bSJack F Vogel 5836*56c2c47bSJack F Vogel ixl_flush(hw); 5837*56c2c47bSJack F Vogel } 5838*56c2c47bSJack F Vogel 5839*56c2c47bSJack F Vogel static void 5840*56c2c47bSJack F Vogel ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 5841*56c2c47bSJack F Vogel uint16_t msg_size) 5842*56c2c47bSJack F Vogel { 5843*56c2c47bSJack F Vogel struct i40e_virtchnl_irq_map_info *map; 5844*56c2c47bSJack F Vogel struct i40e_virtchnl_vector_map *vector; 5845*56c2c47bSJack F Vogel struct i40e_hw *hw; 5846*56c2c47bSJack F Vogel int i, largest_txq, largest_rxq; 5847*56c2c47bSJack F Vogel 5848*56c2c47bSJack F Vogel hw = &pf->hw; 5849*56c2c47bSJack F Vogel 5850*56c2c47bSJack F Vogel if (msg_size < sizeof(*map)) { 5851*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 5852*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5853*56c2c47bSJack F Vogel return; 5854*56c2c47bSJack F Vogel } 5855*56c2c47bSJack F Vogel 5856*56c2c47bSJack F Vogel map = msg; 5857*56c2c47bSJack F Vogel if (map->num_vectors == 0) { 5858*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 5859*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5860*56c2c47bSJack F Vogel return; 5861*56c2c47bSJack F Vogel } 5862*56c2c47bSJack F Vogel 5863*56c2c47bSJack F Vogel if (msg_size != sizeof(*map) + map->num_vectors * sizeof(*vector)) { 5864*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 5865*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5866*56c2c47bSJack F Vogel return; 5867*56c2c47bSJack F Vogel } 5868*56c2c47bSJack F Vogel 5869*56c2c47bSJack F Vogel for (i = 0; i < map->num_vectors; i++) { 5870*56c2c47bSJack F Vogel vector = &map->vecmap[i]; 5871*56c2c47bSJack F Vogel 5872*56c2c47bSJack F Vogel if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) || 5873*56c2c47bSJack F Vogel vector->vsi_id != vf->vsi.vsi_num) { 5874*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 5875*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM); 5876*56c2c47bSJack F Vogel return; 5877*56c2c47bSJack F Vogel } 5878*56c2c47bSJack F Vogel 5879*56c2c47bSJack F Vogel if (vector->rxq_map != 0) { 5880*56c2c47bSJack F Vogel largest_rxq = fls(vector->rxq_map) - 1; 5881*56c2c47bSJack F Vogel if (largest_rxq >= vf->vsi.num_queues) { 5882*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 5883*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 5884*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5885*56c2c47bSJack F Vogel return; 5886*56c2c47bSJack F Vogel } 5887*56c2c47bSJack F Vogel } 5888*56c2c47bSJack F Vogel 5889*56c2c47bSJack F Vogel if (vector->txq_map != 0) { 5890*56c2c47bSJack F Vogel largest_txq = fls(vector->txq_map) - 1; 5891*56c2c47bSJack F Vogel if (largest_txq >= vf->vsi.num_queues) { 5892*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 5893*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 5894*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5895*56c2c47bSJack F Vogel return; 5896*56c2c47bSJack F Vogel } 5897*56c2c47bSJack F Vogel } 5898*56c2c47bSJack F Vogel 5899*56c2c47bSJack F Vogel if (vector->rxitr_idx > IXL_MAX_ITR_IDX || 5900*56c2c47bSJack F Vogel vector->txitr_idx > IXL_MAX_ITR_IDX) { 5901*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 5902*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 5903*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5904*56c2c47bSJack F Vogel return; 5905*56c2c47bSJack F Vogel } 5906*56c2c47bSJack F Vogel 5907*56c2c47bSJack F Vogel ixl_vf_config_vector(pf, vf, vector); 5908*56c2c47bSJack F Vogel } 5909*56c2c47bSJack F Vogel 5910*56c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP); 5911*56c2c47bSJack F Vogel } 5912*56c2c47bSJack F Vogel 5913*56c2c47bSJack F Vogel static void 5914*56c2c47bSJack F Vogel ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 5915*56c2c47bSJack F Vogel uint16_t msg_size) 5916*56c2c47bSJack F Vogel { 5917*56c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *select; 5918*56c2c47bSJack F Vogel int error; 5919*56c2c47bSJack F Vogel 5920*56c2c47bSJack F Vogel if (msg_size != sizeof(*select)) { 5921*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 5922*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5923*56c2c47bSJack F Vogel return; 5924*56c2c47bSJack F Vogel } 5925*56c2c47bSJack F Vogel 5926*56c2c47bSJack F Vogel select = msg; 5927*56c2c47bSJack F Vogel if (select->vsi_id != vf->vsi.vsi_num || 5928*56c2c47bSJack F Vogel select->rx_queues == 0 || select->tx_queues == 0) { 5929*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 5930*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5931*56c2c47bSJack F Vogel return; 5932*56c2c47bSJack F Vogel } 5933*56c2c47bSJack F Vogel 5934*56c2c47bSJack F Vogel error = ixl_enable_rings(&vf->vsi); 5935*56c2c47bSJack F Vogel if (error) { 5936*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 5937*56c2c47bSJack F Vogel I40E_ERR_TIMEOUT); 5938*56c2c47bSJack F Vogel return; 5939*56c2c47bSJack F Vogel } 5940*56c2c47bSJack F Vogel 5941*56c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES); 5942*56c2c47bSJack F Vogel } 5943*56c2c47bSJack F Vogel 5944*56c2c47bSJack F Vogel static void 5945*56c2c47bSJack F Vogel ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, 5946*56c2c47bSJack F Vogel void *msg, uint16_t msg_size) 5947*56c2c47bSJack F Vogel { 5948*56c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *select; 5949*56c2c47bSJack F Vogel int error; 5950*56c2c47bSJack F Vogel 5951*56c2c47bSJack F Vogel if (msg_size != sizeof(*select)) { 5952*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 5953*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5954*56c2c47bSJack F Vogel return; 5955*56c2c47bSJack F Vogel } 5956*56c2c47bSJack F Vogel 5957*56c2c47bSJack F Vogel select = msg; 5958*56c2c47bSJack F Vogel if (select->vsi_id != vf->vsi.vsi_num || 5959*56c2c47bSJack F Vogel select->rx_queues == 0 || select->tx_queues == 0) { 5960*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 5961*56c2c47bSJack F Vogel I40E_ERR_PARAM); 5962*56c2c47bSJack F Vogel return; 5963*56c2c47bSJack F Vogel } 5964*56c2c47bSJack F Vogel 5965*56c2c47bSJack F Vogel error = ixl_disable_rings(&vf->vsi); 5966*56c2c47bSJack F Vogel if (error) { 5967*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 5968*56c2c47bSJack F Vogel I40E_ERR_TIMEOUT); 5969*56c2c47bSJack F Vogel return; 5970*56c2c47bSJack F Vogel } 5971*56c2c47bSJack F Vogel 5972*56c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES); 5973*56c2c47bSJack F Vogel } 5974*56c2c47bSJack F Vogel 5975*56c2c47bSJack F Vogel static boolean_t 5976*56c2c47bSJack F Vogel ixl_zero_mac(const uint8_t *addr) 5977*56c2c47bSJack F Vogel { 5978*56c2c47bSJack F Vogel uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0}; 5979*56c2c47bSJack F Vogel 5980*56c2c47bSJack F Vogel return (cmp_etheraddr(addr, zero)); 5981*56c2c47bSJack F Vogel } 5982*56c2c47bSJack F Vogel 5983*56c2c47bSJack F Vogel static boolean_t 5984*56c2c47bSJack F Vogel ixl_bcast_mac(const uint8_t *addr) 5985*56c2c47bSJack F Vogel { 5986*56c2c47bSJack F Vogel 5987*56c2c47bSJack F Vogel return (cmp_etheraddr(addr, ixl_bcast_addr)); 5988*56c2c47bSJack F Vogel } 5989*56c2c47bSJack F Vogel 5990*56c2c47bSJack F Vogel static int 5991*56c2c47bSJack F Vogel ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr) 5992*56c2c47bSJack F Vogel { 5993*56c2c47bSJack F Vogel 5994*56c2c47bSJack F Vogel if (ixl_zero_mac(addr) || ixl_bcast_mac(addr)) 5995*56c2c47bSJack F Vogel return (EINVAL); 5996*56c2c47bSJack F Vogel 5997*56c2c47bSJack F Vogel /* 5998*56c2c47bSJack F Vogel * If the VF is not allowed to change its MAC address, don't let it 5999*56c2c47bSJack F Vogel * set a MAC filter for an address that is not a multicast address and 6000*56c2c47bSJack F Vogel * is not its assigned MAC. 6001*56c2c47bSJack F Vogel */ 6002*56c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) && 6003*56c2c47bSJack F Vogel !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac))) 6004*56c2c47bSJack F Vogel return (EPERM); 6005*56c2c47bSJack F Vogel 6006*56c2c47bSJack F Vogel return (0); 6007*56c2c47bSJack F Vogel } 6008*56c2c47bSJack F Vogel 6009*56c2c47bSJack F Vogel static void 6010*56c2c47bSJack F Vogel ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6011*56c2c47bSJack F Vogel uint16_t msg_size) 6012*56c2c47bSJack F Vogel { 6013*56c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr_list *addr_list; 6014*56c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr *addr; 6015*56c2c47bSJack F Vogel struct ixl_vsi *vsi; 6016*56c2c47bSJack F Vogel int i; 6017*56c2c47bSJack F Vogel size_t expected_size; 6018*56c2c47bSJack F Vogel 6019*56c2c47bSJack F Vogel vsi = &vf->vsi; 6020*56c2c47bSJack F Vogel 6021*56c2c47bSJack F Vogel if (msg_size < sizeof(*addr_list)) { 6022*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 6023*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6024*56c2c47bSJack F Vogel return; 6025*56c2c47bSJack F Vogel } 6026*56c2c47bSJack F Vogel 6027*56c2c47bSJack F Vogel addr_list = msg; 6028*56c2c47bSJack F Vogel expected_size = sizeof(*addr_list) + 6029*56c2c47bSJack F Vogel addr_list->num_elements * sizeof(*addr); 6030*56c2c47bSJack F Vogel 6031*56c2c47bSJack F Vogel if (addr_list->num_elements == 0 || 6032*56c2c47bSJack F Vogel addr_list->vsi_id != vsi->vsi_num || 6033*56c2c47bSJack F Vogel msg_size != expected_size) { 6034*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 6035*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6036*56c2c47bSJack F Vogel return; 6037*56c2c47bSJack F Vogel } 6038*56c2c47bSJack F Vogel 6039*56c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 6040*56c2c47bSJack F Vogel if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) { 6041*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 6042*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM); 6043*56c2c47bSJack F Vogel return; 6044*56c2c47bSJack F Vogel } 6045*56c2c47bSJack F Vogel } 6046*56c2c47bSJack F Vogel 6047*56c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 6048*56c2c47bSJack F Vogel addr = &addr_list->list[i]; 6049*56c2c47bSJack F Vogel ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY); 6050*56c2c47bSJack F Vogel } 6051*56c2c47bSJack F Vogel 6052*56c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS); 6053*56c2c47bSJack F Vogel } 6054*56c2c47bSJack F Vogel 6055*56c2c47bSJack F Vogel static void 6056*56c2c47bSJack F Vogel ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6057*56c2c47bSJack F Vogel uint16_t msg_size) 6058*56c2c47bSJack F Vogel { 6059*56c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr_list *addr_list; 6060*56c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr *addr; 6061*56c2c47bSJack F Vogel size_t expected_size; 6062*56c2c47bSJack F Vogel int i; 6063*56c2c47bSJack F Vogel 6064*56c2c47bSJack F Vogel if (msg_size < sizeof(*addr_list)) { 6065*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 6066*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6067*56c2c47bSJack F Vogel return; 6068*56c2c47bSJack F Vogel } 6069*56c2c47bSJack F Vogel 6070*56c2c47bSJack F Vogel addr_list = msg; 6071*56c2c47bSJack F Vogel expected_size = sizeof(*addr_list) + 6072*56c2c47bSJack F Vogel addr_list->num_elements * sizeof(*addr); 6073*56c2c47bSJack F Vogel 6074*56c2c47bSJack F Vogel if (addr_list->num_elements == 0 || 6075*56c2c47bSJack F Vogel addr_list->vsi_id != vf->vsi.vsi_num || 6076*56c2c47bSJack F Vogel msg_size != expected_size) { 6077*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 6078*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6079*56c2c47bSJack F Vogel return; 6080*56c2c47bSJack F Vogel } 6081*56c2c47bSJack F Vogel 6082*56c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 6083*56c2c47bSJack F Vogel addr = &addr_list->list[i]; 6084*56c2c47bSJack F Vogel if (ixl_zero_mac(addr->addr) || ixl_bcast_mac(addr->addr)) { 6085*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 6086*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM); 6087*56c2c47bSJack F Vogel return; 6088*56c2c47bSJack F Vogel } 6089*56c2c47bSJack F Vogel } 6090*56c2c47bSJack F Vogel 6091*56c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 6092*56c2c47bSJack F Vogel addr = &addr_list->list[i]; 6093*56c2c47bSJack F Vogel ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY); 6094*56c2c47bSJack F Vogel } 6095*56c2c47bSJack F Vogel 6096*56c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS); 6097*56c2c47bSJack F Vogel } 6098*56c2c47bSJack F Vogel 6099*56c2c47bSJack F Vogel static enum i40e_status_code 6100*56c2c47bSJack F Vogel ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf) 6101*56c2c47bSJack F Vogel { 6102*56c2c47bSJack F Vogel struct i40e_vsi_context vsi_ctx; 6103*56c2c47bSJack F Vogel 6104*56c2c47bSJack F Vogel vsi_ctx.seid = vf->vsi.seid; 6105*56c2c47bSJack F Vogel 6106*56c2c47bSJack F Vogel bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); 6107*56c2c47bSJack F Vogel vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID); 6108*56c2c47bSJack F Vogel vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 6109*56c2c47bSJack F Vogel I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 6110*56c2c47bSJack F Vogel return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL)); 6111*56c2c47bSJack F Vogel } 6112*56c2c47bSJack F Vogel 6113*56c2c47bSJack F Vogel static void 6114*56c2c47bSJack F Vogel ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6115*56c2c47bSJack F Vogel uint16_t msg_size) 6116*56c2c47bSJack F Vogel { 6117*56c2c47bSJack F Vogel struct i40e_virtchnl_vlan_filter_list *filter_list; 6118*56c2c47bSJack F Vogel enum i40e_status_code code; 6119*56c2c47bSJack F Vogel size_t expected_size; 6120*56c2c47bSJack F Vogel int i; 6121*56c2c47bSJack F Vogel 6122*56c2c47bSJack F Vogel if (msg_size < sizeof(*filter_list)) { 6123*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 6124*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6125*56c2c47bSJack F Vogel return; 6126*56c2c47bSJack F Vogel } 6127*56c2c47bSJack F Vogel 6128*56c2c47bSJack F Vogel filter_list = msg; 6129*56c2c47bSJack F Vogel expected_size = sizeof(*filter_list) + 6130*56c2c47bSJack F Vogel filter_list->num_elements * sizeof(uint16_t); 6131*56c2c47bSJack F Vogel if (filter_list->num_elements == 0 || 6132*56c2c47bSJack F Vogel filter_list->vsi_id != vf->vsi.vsi_num || 6133*56c2c47bSJack F Vogel msg_size != expected_size) { 6134*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 6135*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6136*56c2c47bSJack F Vogel return; 6137*56c2c47bSJack F Vogel } 6138*56c2c47bSJack F Vogel 6139*56c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) { 6140*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 6141*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6142*56c2c47bSJack F Vogel return; 6143*56c2c47bSJack F Vogel } 6144*56c2c47bSJack F Vogel 6145*56c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) { 6146*56c2c47bSJack F Vogel if (filter_list->vlan_id[i] > EVL_VLID_MASK) { 6147*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 6148*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6149*56c2c47bSJack F Vogel return; 6150*56c2c47bSJack F Vogel } 6151*56c2c47bSJack F Vogel } 6152*56c2c47bSJack F Vogel 6153*56c2c47bSJack F Vogel code = ixl_vf_enable_vlan_strip(pf, vf); 6154*56c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 6155*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 6156*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6157*56c2c47bSJack F Vogel } 6158*56c2c47bSJack F Vogel 6159*56c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) 6160*56c2c47bSJack F Vogel ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]); 6161*56c2c47bSJack F Vogel 6162*56c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN); 6163*56c2c47bSJack F Vogel } 6164*56c2c47bSJack F Vogel 6165*56c2c47bSJack F Vogel static void 6166*56c2c47bSJack F Vogel ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6167*56c2c47bSJack F Vogel uint16_t msg_size) 6168*56c2c47bSJack F Vogel { 6169*56c2c47bSJack F Vogel struct i40e_virtchnl_vlan_filter_list *filter_list; 6170*56c2c47bSJack F Vogel int i; 6171*56c2c47bSJack F Vogel size_t expected_size; 6172*56c2c47bSJack F Vogel 6173*56c2c47bSJack F Vogel if (msg_size < sizeof(*filter_list)) { 6174*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN, 6175*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6176*56c2c47bSJack F Vogel return; 6177*56c2c47bSJack F Vogel } 6178*56c2c47bSJack F Vogel 6179*56c2c47bSJack F Vogel filter_list = msg; 6180*56c2c47bSJack F Vogel expected_size = sizeof(*filter_list) + 6181*56c2c47bSJack F Vogel filter_list->num_elements * sizeof(uint16_t); 6182*56c2c47bSJack F Vogel if (filter_list->num_elements == 0 || 6183*56c2c47bSJack F Vogel filter_list->vsi_id != vf->vsi.vsi_num || 6184*56c2c47bSJack F Vogel msg_size != expected_size) { 6185*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN, 6186*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6187*56c2c47bSJack F Vogel return; 6188*56c2c47bSJack F Vogel } 6189*56c2c47bSJack F Vogel 6190*56c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) { 6191*56c2c47bSJack F Vogel if (filter_list->vlan_id[i] > EVL_VLID_MASK) { 6192*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 6193*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6194*56c2c47bSJack F Vogel return; 6195*56c2c47bSJack F Vogel } 6196*56c2c47bSJack F Vogel } 6197*56c2c47bSJack F Vogel 6198*56c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) { 6199*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 6200*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6201*56c2c47bSJack F Vogel return; 6202*56c2c47bSJack F Vogel } 6203*56c2c47bSJack F Vogel 6204*56c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) 6205*56c2c47bSJack F Vogel ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]); 6206*56c2c47bSJack F Vogel 6207*56c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN); 6208*56c2c47bSJack F Vogel } 6209*56c2c47bSJack F Vogel 6210*56c2c47bSJack F Vogel static void 6211*56c2c47bSJack F Vogel ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, 6212*56c2c47bSJack F Vogel void *msg, uint16_t msg_size) 6213*56c2c47bSJack F Vogel { 6214*56c2c47bSJack F Vogel struct i40e_virtchnl_promisc_info *info; 6215*56c2c47bSJack F Vogel enum i40e_status_code code; 6216*56c2c47bSJack F Vogel 6217*56c2c47bSJack F Vogel if (msg_size != sizeof(*info)) { 6218*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 6219*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 6220*56c2c47bSJack F Vogel return; 6221*56c2c47bSJack F Vogel } 6222*56c2c47bSJack F Vogel 6223*56c2c47bSJack F Vogel if (!vf->vf_flags & VF_FLAG_PROMISC_CAP) { 6224*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 6225*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 6226*56c2c47bSJack F Vogel return; 6227*56c2c47bSJack F Vogel } 6228*56c2c47bSJack F Vogel 6229*56c2c47bSJack F Vogel info = msg; 6230*56c2c47bSJack F Vogel if (info->vsi_id != vf->vsi.vsi_num) { 6231*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 6232*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 6233*56c2c47bSJack F Vogel return; 6234*56c2c47bSJack F Vogel } 6235*56c2c47bSJack F Vogel 6236*56c2c47bSJack F Vogel code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id, 6237*56c2c47bSJack F Vogel info->flags & I40E_FLAG_VF_UNICAST_PROMISC, NULL); 6238*56c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 6239*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 6240*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); 6241*56c2c47bSJack F Vogel return; 6242*56c2c47bSJack F Vogel } 6243*56c2c47bSJack F Vogel 6244*56c2c47bSJack F Vogel code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id, 6245*56c2c47bSJack F Vogel info->flags & I40E_FLAG_VF_MULTICAST_PROMISC, NULL); 6246*56c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 6247*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 6248*56c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); 6249*56c2c47bSJack F Vogel return; 6250*56c2c47bSJack F Vogel } 6251*56c2c47bSJack F Vogel 6252*56c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE); 6253*56c2c47bSJack F Vogel } 6254*56c2c47bSJack F Vogel 6255*56c2c47bSJack F Vogel static void 6256*56c2c47bSJack F Vogel ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6257*56c2c47bSJack F Vogel uint16_t msg_size) 6258*56c2c47bSJack F Vogel { 6259*56c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *queue; 6260*56c2c47bSJack F Vogel 6261*56c2c47bSJack F Vogel if (msg_size != sizeof(*queue)) { 6262*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 6263*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6264*56c2c47bSJack F Vogel return; 6265*56c2c47bSJack F Vogel } 6266*56c2c47bSJack F Vogel 6267*56c2c47bSJack F Vogel queue = msg; 6268*56c2c47bSJack F Vogel if (queue->vsi_id != vf->vsi.vsi_num) { 6269*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 6270*56c2c47bSJack F Vogel I40E_ERR_PARAM); 6271*56c2c47bSJack F Vogel return; 6272*56c2c47bSJack F Vogel } 6273*56c2c47bSJack F Vogel 6274*56c2c47bSJack F Vogel ixl_update_eth_stats(&vf->vsi); 6275*56c2c47bSJack F Vogel 6276*56c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 6277*56c2c47bSJack F Vogel I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats)); 6278*56c2c47bSJack F Vogel } 6279*56c2c47bSJack F Vogel 6280*56c2c47bSJack F Vogel static void 6281*56c2c47bSJack F Vogel ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event) 6282*56c2c47bSJack F Vogel { 6283*56c2c47bSJack F Vogel struct ixl_vf *vf; 6284*56c2c47bSJack F Vogel void *msg; 6285*56c2c47bSJack F Vogel uint16_t vf_num, msg_size; 6286*56c2c47bSJack F Vogel uint32_t opcode; 6287*56c2c47bSJack F Vogel 6288*56c2c47bSJack F Vogel vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id; 6289*56c2c47bSJack F Vogel opcode = le32toh(event->desc.cookie_high); 6290*56c2c47bSJack F Vogel 6291*56c2c47bSJack F Vogel if (vf_num >= pf->num_vfs) { 6292*56c2c47bSJack F Vogel device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num); 6293*56c2c47bSJack F Vogel return; 6294*56c2c47bSJack F Vogel } 6295*56c2c47bSJack F Vogel 6296*56c2c47bSJack F Vogel vf = &pf->vfs[vf_num]; 6297*56c2c47bSJack F Vogel msg = event->msg_buf; 6298*56c2c47bSJack F Vogel msg_size = event->msg_len; 6299*56c2c47bSJack F Vogel 6300*56c2c47bSJack F Vogel I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode), 6301*56c2c47bSJack F Vogel "Got msg %s(%d) from VF-%d of size %d\n", 6302*56c2c47bSJack F Vogel ixl_vc_opcode_str(opcode), opcode, vf_num, msg_size); 6303*56c2c47bSJack F Vogel 6304*56c2c47bSJack F Vogel switch (opcode) { 6305*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_VERSION: 6306*56c2c47bSJack F Vogel ixl_vf_version_msg(pf, vf, msg, msg_size); 6307*56c2c47bSJack F Vogel break; 6308*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_RESET_VF: 6309*56c2c47bSJack F Vogel ixl_vf_reset_msg(pf, vf, msg, msg_size); 6310*56c2c47bSJack F Vogel break; 6311*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: 6312*56c2c47bSJack F Vogel ixl_vf_get_resources_msg(pf, vf, msg, msg_size); 6313*56c2c47bSJack F Vogel break; 6314*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: 6315*56c2c47bSJack F Vogel ixl_vf_config_vsi_msg(pf, vf, msg, msg_size); 6316*56c2c47bSJack F Vogel break; 6317*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: 6318*56c2c47bSJack F Vogel ixl_vf_config_irq_msg(pf, vf, msg, msg_size); 6319*56c2c47bSJack F Vogel break; 6320*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ENABLE_QUEUES: 6321*56c2c47bSJack F Vogel ixl_vf_enable_queues_msg(pf, vf, msg, msg_size); 6322*56c2c47bSJack F Vogel break; 6323*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DISABLE_QUEUES: 6324*56c2c47bSJack F Vogel ixl_vf_disable_queues_msg(pf, vf, msg, msg_size); 6325*56c2c47bSJack F Vogel break; 6326*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: 6327*56c2c47bSJack F Vogel ixl_vf_add_mac_msg(pf, vf, msg, msg_size); 6328*56c2c47bSJack F Vogel break; 6329*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: 6330*56c2c47bSJack F Vogel ixl_vf_del_mac_msg(pf, vf, msg, msg_size); 6331*56c2c47bSJack F Vogel break; 6332*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_VLAN: 6333*56c2c47bSJack F Vogel ixl_vf_add_vlan_msg(pf, vf, msg, msg_size); 6334*56c2c47bSJack F Vogel break; 6335*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_VLAN: 6336*56c2c47bSJack F Vogel ixl_vf_del_vlan_msg(pf, vf, msg, msg_size); 6337*56c2c47bSJack F Vogel break; 6338*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: 6339*56c2c47bSJack F Vogel ixl_vf_config_promisc_msg(pf, vf, msg, msg_size); 6340*56c2c47bSJack F Vogel break; 6341*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 6342*56c2c47bSJack F Vogel ixl_vf_get_stats_msg(pf, vf, msg, msg_size); 6343*56c2c47bSJack F Vogel break; 6344*56c2c47bSJack F Vogel 6345*56c2c47bSJack F Vogel /* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */ 6346*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: 6347*56c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: 6348*56c2c47bSJack F Vogel default: 6349*56c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED); 6350*56c2c47bSJack F Vogel break; 6351*56c2c47bSJack F Vogel } 6352*56c2c47bSJack F Vogel } 6353*56c2c47bSJack F Vogel 6354*56c2c47bSJack F Vogel /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */ 6355*56c2c47bSJack F Vogel static void 6356*56c2c47bSJack F Vogel ixl_handle_vflr(void *arg, int pending) 6357*56c2c47bSJack F Vogel { 6358*56c2c47bSJack F Vogel struct ixl_pf *pf; 6359*56c2c47bSJack F Vogel struct i40e_hw *hw; 6360*56c2c47bSJack F Vogel uint16_t global_vf_num; 6361*56c2c47bSJack F Vogel uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0; 6362*56c2c47bSJack F Vogel int i; 6363*56c2c47bSJack F Vogel 6364*56c2c47bSJack F Vogel pf = arg; 6365*56c2c47bSJack F Vogel hw = &pf->hw; 6366*56c2c47bSJack F Vogel 6367*56c2c47bSJack F Vogel IXL_PF_LOCK(pf); 6368*56c2c47bSJack F Vogel for (i = 0; i < pf->num_vfs; i++) { 6369*56c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + i; 6370*56c2c47bSJack F Vogel 6371*56c2c47bSJack F Vogel vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num); 6372*56c2c47bSJack F Vogel vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num); 6373*56c2c47bSJack F Vogel vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index)); 6374*56c2c47bSJack F Vogel if (vflrstat & vflrstat_mask) { 6375*56c2c47bSJack F Vogel wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index), 6376*56c2c47bSJack F Vogel vflrstat_mask); 6377*56c2c47bSJack F Vogel 6378*56c2c47bSJack F Vogel ixl_reinit_vf(pf, &pf->vfs[i]); 6379*56c2c47bSJack F Vogel } 6380*56c2c47bSJack F Vogel } 6381*56c2c47bSJack F Vogel 6382*56c2c47bSJack F Vogel icr0 = rd32(hw, I40E_PFINT_ICR0_ENA); 6383*56c2c47bSJack F Vogel icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK; 6384*56c2c47bSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, icr0); 6385*56c2c47bSJack F Vogel ixl_flush(hw); 6386*56c2c47bSJack F Vogel 6387*56c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 6388*56c2c47bSJack F Vogel } 6389*56c2c47bSJack F Vogel 6390*56c2c47bSJack F Vogel static int 6391*56c2c47bSJack F Vogel ixl_adminq_err_to_errno(enum i40e_admin_queue_err err) 6392*56c2c47bSJack F Vogel { 6393*56c2c47bSJack F Vogel 6394*56c2c47bSJack F Vogel switch (err) { 6395*56c2c47bSJack F Vogel case I40E_AQ_RC_EPERM: 6396*56c2c47bSJack F Vogel return (EPERM); 6397*56c2c47bSJack F Vogel case I40E_AQ_RC_ENOENT: 6398*56c2c47bSJack F Vogel return (ENOENT); 6399*56c2c47bSJack F Vogel case I40E_AQ_RC_ESRCH: 6400*56c2c47bSJack F Vogel return (ESRCH); 6401*56c2c47bSJack F Vogel case I40E_AQ_RC_EINTR: 6402*56c2c47bSJack F Vogel return (EINTR); 6403*56c2c47bSJack F Vogel case I40E_AQ_RC_EIO: 6404*56c2c47bSJack F Vogel return (EIO); 6405*56c2c47bSJack F Vogel case I40E_AQ_RC_ENXIO: 6406*56c2c47bSJack F Vogel return (ENXIO); 6407*56c2c47bSJack F Vogel case I40E_AQ_RC_E2BIG: 6408*56c2c47bSJack F Vogel return (E2BIG); 6409*56c2c47bSJack F Vogel case I40E_AQ_RC_EAGAIN: 6410*56c2c47bSJack F Vogel return (EAGAIN); 6411*56c2c47bSJack F Vogel case I40E_AQ_RC_ENOMEM: 6412*56c2c47bSJack F Vogel return (ENOMEM); 6413*56c2c47bSJack F Vogel case I40E_AQ_RC_EACCES: 6414*56c2c47bSJack F Vogel return (EACCES); 6415*56c2c47bSJack F Vogel case I40E_AQ_RC_EFAULT: 6416*56c2c47bSJack F Vogel return (EFAULT); 6417*56c2c47bSJack F Vogel case I40E_AQ_RC_EBUSY: 6418*56c2c47bSJack F Vogel return (EBUSY); 6419*56c2c47bSJack F Vogel case I40E_AQ_RC_EEXIST: 6420*56c2c47bSJack F Vogel return (EEXIST); 6421*56c2c47bSJack F Vogel case I40E_AQ_RC_EINVAL: 6422*56c2c47bSJack F Vogel return (EINVAL); 6423*56c2c47bSJack F Vogel case I40E_AQ_RC_ENOTTY: 6424*56c2c47bSJack F Vogel return (ENOTTY); 6425*56c2c47bSJack F Vogel case I40E_AQ_RC_ENOSPC: 6426*56c2c47bSJack F Vogel return (ENOSPC); 6427*56c2c47bSJack F Vogel case I40E_AQ_RC_ENOSYS: 6428*56c2c47bSJack F Vogel return (ENOSYS); 6429*56c2c47bSJack F Vogel case I40E_AQ_RC_ERANGE: 6430*56c2c47bSJack F Vogel return (ERANGE); 6431*56c2c47bSJack F Vogel case I40E_AQ_RC_EFLUSHED: 6432*56c2c47bSJack F Vogel return (EINVAL); /* No exact equivalent in errno.h */ 6433*56c2c47bSJack F Vogel case I40E_AQ_RC_BAD_ADDR: 6434*56c2c47bSJack F Vogel return (EFAULT); 6435*56c2c47bSJack F Vogel case I40E_AQ_RC_EMODE: 6436*56c2c47bSJack F Vogel return (EPERM); 6437*56c2c47bSJack F Vogel case I40E_AQ_RC_EFBIG: 6438*56c2c47bSJack F Vogel return (EFBIG); 6439*56c2c47bSJack F Vogel default: 6440*56c2c47bSJack F Vogel return (EINVAL); 6441*56c2c47bSJack F Vogel } 6442*56c2c47bSJack F Vogel } 6443*56c2c47bSJack F Vogel 6444*56c2c47bSJack F Vogel static int 6445*56c2c47bSJack F Vogel ixl_init_iov(device_t dev, uint16_t num_vfs, const nvlist_t *params) 6446*56c2c47bSJack F Vogel { 6447*56c2c47bSJack F Vogel struct ixl_pf *pf; 6448*56c2c47bSJack F Vogel struct i40e_hw *hw; 6449*56c2c47bSJack F Vogel struct ixl_vsi *pf_vsi; 6450*56c2c47bSJack F Vogel enum i40e_status_code ret; 6451*56c2c47bSJack F Vogel int i, error; 6452*56c2c47bSJack F Vogel 6453*56c2c47bSJack F Vogel pf = device_get_softc(dev); 6454*56c2c47bSJack F Vogel hw = &pf->hw; 6455*56c2c47bSJack F Vogel pf_vsi = &pf->vsi; 6456*56c2c47bSJack F Vogel 6457*56c2c47bSJack F Vogel IXL_PF_LOCK(pf); 6458*56c2c47bSJack F Vogel pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT | 6459*56c2c47bSJack F Vogel M_ZERO); 6460*56c2c47bSJack F Vogel 6461*56c2c47bSJack F Vogel if (pf->vfs == NULL) { 6462*56c2c47bSJack F Vogel error = ENOMEM; 6463*56c2c47bSJack F Vogel goto fail; 6464*56c2c47bSJack F Vogel } 6465*56c2c47bSJack F Vogel 6466*56c2c47bSJack F Vogel for (i = 0; i < num_vfs; i++) 6467*56c2c47bSJack F Vogel sysctl_ctx_init(&pf->vfs[i].ctx); 6468*56c2c47bSJack F Vogel 6469*56c2c47bSJack F Vogel ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid, 6470*56c2c47bSJack F Vogel 1, FALSE, FALSE, &pf->veb_seid, NULL); 6471*56c2c47bSJack F Vogel if (ret != I40E_SUCCESS) { 6472*56c2c47bSJack F Vogel error = ixl_adminq_err_to_errno(hw->aq.asq_last_status); 6473*56c2c47bSJack F Vogel device_printf(dev, "add_veb failed; code=%d error=%d", ret, 6474*56c2c47bSJack F Vogel error); 6475*56c2c47bSJack F Vogel goto fail; 6476*56c2c47bSJack F Vogel } 6477*56c2c47bSJack F Vogel 6478*56c2c47bSJack F Vogel ixl_configure_msix(pf); 6479*56c2c47bSJack F Vogel ixl_enable_adminq(hw); 6480*56c2c47bSJack F Vogel 6481*56c2c47bSJack F Vogel pf->num_vfs = num_vfs; 6482*56c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 6483*56c2c47bSJack F Vogel return (0); 6484*56c2c47bSJack F Vogel 6485*56c2c47bSJack F Vogel fail: 6486*56c2c47bSJack F Vogel free(pf->vfs, M_IXL); 6487*56c2c47bSJack F Vogel pf->vfs = NULL; 6488*56c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 6489*56c2c47bSJack F Vogel return (error); 6490*56c2c47bSJack F Vogel } 6491*56c2c47bSJack F Vogel 6492*56c2c47bSJack F Vogel static void 6493*56c2c47bSJack F Vogel ixl_uninit_iov(device_t dev) 6494*56c2c47bSJack F Vogel { 6495*56c2c47bSJack F Vogel struct ixl_pf *pf; 6496*56c2c47bSJack F Vogel struct i40e_hw *hw; 6497*56c2c47bSJack F Vogel struct ixl_vsi *vsi; 6498*56c2c47bSJack F Vogel struct ifnet *ifp; 6499*56c2c47bSJack F Vogel struct ixl_vf *vfs; 6500*56c2c47bSJack F Vogel int i, num_vfs; 6501*56c2c47bSJack F Vogel 6502*56c2c47bSJack F Vogel pf = device_get_softc(dev); 6503*56c2c47bSJack F Vogel hw = &pf->hw; 6504*56c2c47bSJack F Vogel vsi = &pf->vsi; 6505*56c2c47bSJack F Vogel ifp = vsi->ifp; 6506*56c2c47bSJack F Vogel 6507*56c2c47bSJack F Vogel IXL_PF_LOCK(pf); 6508*56c2c47bSJack F Vogel for (i = 0; i < pf->num_vfs; i++) { 6509*56c2c47bSJack F Vogel if (pf->vfs[i].vsi.seid != 0) 6510*56c2c47bSJack F Vogel i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL); 6511*56c2c47bSJack F Vogel } 6512*56c2c47bSJack F Vogel 6513*56c2c47bSJack F Vogel if (pf->veb_seid != 0) { 6514*56c2c47bSJack F Vogel i40e_aq_delete_element(hw, pf->veb_seid, NULL); 6515*56c2c47bSJack F Vogel pf->veb_seid = 0; 6516*56c2c47bSJack F Vogel } 6517*56c2c47bSJack F Vogel 6518*56c2c47bSJack F Vogel if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 6519*56c2c47bSJack F Vogel ixl_disable_intr(vsi); 6520*56c2c47bSJack F Vogel 6521*56c2c47bSJack F Vogel vfs = pf->vfs; 6522*56c2c47bSJack F Vogel num_vfs = pf->num_vfs; 6523*56c2c47bSJack F Vogel 6524*56c2c47bSJack F Vogel pf->vfs = NULL; 6525*56c2c47bSJack F Vogel pf->num_vfs = 0; 6526*56c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 6527*56c2c47bSJack F Vogel 6528*56c2c47bSJack F Vogel /* Do this after the unlock as sysctl_ctx_free might sleep. */ 6529*56c2c47bSJack F Vogel for (i = 0; i < num_vfs; i++) 6530*56c2c47bSJack F Vogel sysctl_ctx_free(&vfs[i].ctx); 6531*56c2c47bSJack F Vogel free(vfs, M_IXL); 6532*56c2c47bSJack F Vogel } 6533*56c2c47bSJack F Vogel 6534*56c2c47bSJack F Vogel static int 6535*56c2c47bSJack F Vogel ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params) 6536*56c2c47bSJack F Vogel { 6537*56c2c47bSJack F Vogel char sysctl_name[QUEUE_NAME_LEN]; 6538*56c2c47bSJack F Vogel struct ixl_pf *pf; 6539*56c2c47bSJack F Vogel struct ixl_vf *vf; 6540*56c2c47bSJack F Vogel const void *mac; 6541*56c2c47bSJack F Vogel size_t size; 6542*56c2c47bSJack F Vogel int error; 6543*56c2c47bSJack F Vogel 6544*56c2c47bSJack F Vogel pf = device_get_softc(dev); 6545*56c2c47bSJack F Vogel vf = &pf->vfs[vfnum]; 6546*56c2c47bSJack F Vogel 6547*56c2c47bSJack F Vogel IXL_PF_LOCK(pf); 6548*56c2c47bSJack F Vogel vf->vf_num = vfnum; 6549*56c2c47bSJack F Vogel 6550*56c2c47bSJack F Vogel vf->vsi.back = pf; 6551*56c2c47bSJack F Vogel vf->vf_flags = VF_FLAG_ENABLED; 6552*56c2c47bSJack F Vogel SLIST_INIT(&vf->vsi.ftl); 6553*56c2c47bSJack F Vogel 6554*56c2c47bSJack F Vogel error = ixl_vf_setup_vsi(pf, vf); 6555*56c2c47bSJack F Vogel if (error != 0) 6556*56c2c47bSJack F Vogel goto out; 6557*56c2c47bSJack F Vogel 6558*56c2c47bSJack F Vogel if (nvlist_exists_binary(params, "mac-addr")) { 6559*56c2c47bSJack F Vogel mac = nvlist_get_binary(params, "mac-addr", &size); 6560*56c2c47bSJack F Vogel bcopy(mac, vf->mac, ETHER_ADDR_LEN); 6561*56c2c47bSJack F Vogel 6562*56c2c47bSJack F Vogel if (nvlist_get_bool(params, "allow-set-mac")) 6563*56c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_SET_MAC_CAP; 6564*56c2c47bSJack F Vogel } else 6565*56c2c47bSJack F Vogel /* 6566*56c2c47bSJack F Vogel * If the administrator has not specified a MAC address then 6567*56c2c47bSJack F Vogel * we must allow the VF to choose one. 6568*56c2c47bSJack F Vogel */ 6569*56c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_SET_MAC_CAP; 6570*56c2c47bSJack F Vogel 6571*56c2c47bSJack F Vogel if (nvlist_get_bool(params, "mac-anti-spoof")) 6572*56c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF; 6573*56c2c47bSJack F Vogel 6574*56c2c47bSJack F Vogel if (nvlist_get_bool(params, "allow-promisc")) 6575*56c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_PROMISC_CAP; 6576*56c2c47bSJack F Vogel 6577*56c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_VLAN_CAP; 6578*56c2c47bSJack F Vogel 6579*56c2c47bSJack F Vogel ixl_reset_vf(pf, vf); 6580*56c2c47bSJack F Vogel out: 6581*56c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 6582*56c2c47bSJack F Vogel if (error == 0) { 6583*56c2c47bSJack F Vogel snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum); 6584*56c2c47bSJack F Vogel ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name); 6585*56c2c47bSJack F Vogel } 6586*56c2c47bSJack F Vogel 6587*56c2c47bSJack F Vogel return (error); 6588*56c2c47bSJack F Vogel } 6589*56c2c47bSJack F Vogel #endif /* PCI_IOV */ 6590