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