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*fdb6f38aSEric Joyner char ixl_driver_version[] = "1.4.12-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 157*fdb6f38aSEric Joyner /* Sysctls*/ 158*fdb6f38aSEric Joyner static void ixl_add_device_sysctls(struct ixl_pf *); 15961ae650dSJack F Vogel 16061ae650dSJack F Vogel static int ixl_debug_info(SYSCTL_HANDLER_ARGS); 16161ae650dSJack F Vogel static void ixl_print_debug_info(struct ixl_pf *); 16261ae650dSJack F Vogel 163*fdb6f38aSEric Joyner static int ixl_set_flowcntl(SYSCTL_HANDLER_ARGS); 164*fdb6f38aSEric Joyner static int ixl_set_advertise(SYSCTL_HANDLER_ARGS); 165*fdb6f38aSEric Joyner static int ixl_current_speed(SYSCTL_HANDLER_ARGS); 166*fdb6f38aSEric Joyner static int ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS); 167*fdb6f38aSEric Joyner 168*fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL 169*fdb6f38aSEric Joyner static int ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS); 170*fdb6f38aSEric Joyner static int ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS); 171*fdb6f38aSEric Joyner static int ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS); 172*fdb6f38aSEric Joyner static int ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS); 173*fdb6f38aSEric Joyner static int ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS); 174*fdb6f38aSEric Joyner #endif 175*fdb6f38aSEric 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 36261ae650dSJack F Vogel INIT_DEBUGOUT("ixl_probe: begin"); 36361ae650dSJack F Vogel 36461ae650dSJack F Vogel pci_vendor_id = pci_get_vendor(dev); 36561ae650dSJack F Vogel if (pci_vendor_id != I40E_INTEL_VENDOR_ID) 36661ae650dSJack F Vogel return (ENXIO); 36761ae650dSJack F Vogel 36861ae650dSJack F Vogel pci_device_id = pci_get_device(dev); 36961ae650dSJack F Vogel pci_subvendor_id = pci_get_subvendor(dev); 37061ae650dSJack F Vogel pci_subdevice_id = pci_get_subdevice(dev); 37161ae650dSJack F Vogel 37261ae650dSJack F Vogel ent = ixl_vendor_info_array; 37361ae650dSJack F Vogel while (ent->vendor_id != 0) { 37461ae650dSJack F Vogel if ((pci_vendor_id == ent->vendor_id) && 37561ae650dSJack F Vogel (pci_device_id == ent->device_id) && 37661ae650dSJack F Vogel 37761ae650dSJack F Vogel ((pci_subvendor_id == ent->subvendor_id) || 37861ae650dSJack F Vogel (ent->subvendor_id == 0)) && 37961ae650dSJack F Vogel 38061ae650dSJack F Vogel ((pci_subdevice_id == ent->subdevice_id) || 38161ae650dSJack F Vogel (ent->subdevice_id == 0))) { 38261ae650dSJack F Vogel sprintf(device_name, "%s, Version - %s", 38361ae650dSJack F Vogel ixl_strings[ent->index], 38461ae650dSJack F Vogel ixl_driver_version); 38561ae650dSJack F Vogel device_set_desc_copy(dev, device_name); 38661ae650dSJack F Vogel /* One shot mutex init */ 38761ae650dSJack F Vogel if (lock_init == FALSE) { 38861ae650dSJack F Vogel lock_init = TRUE; 38961ae650dSJack F Vogel mtx_init(&ixl_reset_mtx, 39061ae650dSJack F Vogel "ixl_reset", 39161ae650dSJack F Vogel "IXL RESET Lock", MTX_DEF); 39261ae650dSJack F Vogel } 39361ae650dSJack F Vogel return (BUS_PROBE_DEFAULT); 39461ae650dSJack F Vogel } 39561ae650dSJack F Vogel ent++; 39661ae650dSJack F Vogel } 39761ae650dSJack F Vogel return (ENXIO); 39861ae650dSJack F Vogel } 39961ae650dSJack F Vogel 40061ae650dSJack F Vogel /********************************************************************* 40161ae650dSJack F Vogel * Device initialization routine 40261ae650dSJack F Vogel * 40361ae650dSJack F Vogel * The attach entry point is called when the driver is being loaded. 40461ae650dSJack F Vogel * This routine identifies the type of hardware, allocates all resources 40561ae650dSJack F Vogel * and initializes the hardware. 40661ae650dSJack F Vogel * 40761ae650dSJack F Vogel * return 0 on success, positive on failure 40861ae650dSJack F Vogel *********************************************************************/ 40961ae650dSJack F Vogel 41061ae650dSJack F Vogel static int 41161ae650dSJack F Vogel ixl_attach(device_t dev) 41261ae650dSJack F Vogel { 41361ae650dSJack F Vogel struct ixl_pf *pf; 41461ae650dSJack F Vogel struct i40e_hw *hw; 41561ae650dSJack F Vogel struct ixl_vsi *vsi; 41661ae650dSJack F Vogel u16 bus; 41761ae650dSJack F Vogel int error = 0; 41856c2c47bSJack F Vogel #ifdef PCI_IOV 41956c2c47bSJack F Vogel nvlist_t *pf_schema, *vf_schema; 42056c2c47bSJack F Vogel int iov_error; 42156c2c47bSJack F Vogel #endif 42261ae650dSJack F Vogel 42361ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: begin"); 42461ae650dSJack F Vogel 42561ae650dSJack F Vogel /* Allocate, clear, and link in our primary soft structure */ 42661ae650dSJack F Vogel pf = device_get_softc(dev); 42761ae650dSJack F Vogel pf->dev = pf->osdep.dev = dev; 42861ae650dSJack F Vogel hw = &pf->hw; 42961ae650dSJack F Vogel 43061ae650dSJack F Vogel /* 43161ae650dSJack F Vogel ** Note this assumes we have a single embedded VSI, 43261ae650dSJack F Vogel ** this could be enhanced later to allocate multiple 43361ae650dSJack F Vogel */ 43461ae650dSJack F Vogel vsi = &pf->vsi; 43561ae650dSJack F Vogel vsi->dev = pf->dev; 43661ae650dSJack F Vogel 43761ae650dSJack F Vogel /* Core Lock Init*/ 43861ae650dSJack F Vogel IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev)); 43961ae650dSJack F Vogel 44061ae650dSJack F Vogel /* Set up the timer callout */ 44161ae650dSJack F Vogel callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); 44261ae650dSJack F Vogel 443e5100ee2SJack F Vogel /* Save off the PCI information */ 44461ae650dSJack F Vogel hw->vendor_id = pci_get_vendor(dev); 44561ae650dSJack F Vogel hw->device_id = pci_get_device(dev); 44661ae650dSJack F Vogel hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 44761ae650dSJack F Vogel hw->subsystem_vendor_id = 44861ae650dSJack F Vogel pci_read_config(dev, PCIR_SUBVEND_0, 2); 44961ae650dSJack F Vogel hw->subsystem_device_id = 45061ae650dSJack F Vogel pci_read_config(dev, PCIR_SUBDEV_0, 2); 45161ae650dSJack F Vogel 45261ae650dSJack F Vogel hw->bus.device = pci_get_slot(dev); 45361ae650dSJack F Vogel hw->bus.func = pci_get_function(dev); 45461ae650dSJack F Vogel 45556c2c47bSJack F Vogel pf->vc_debug_lvl = 1; 45656c2c47bSJack F Vogel 45761ae650dSJack F Vogel /* Do PCI setup - map BAR0, etc */ 45861ae650dSJack F Vogel if (ixl_allocate_pci_resources(pf)) { 45961ae650dSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 46061ae650dSJack F Vogel error = ENXIO; 46161ae650dSJack F Vogel goto err_out; 46261ae650dSJack F Vogel } 46361ae650dSJack F Vogel 46461ae650dSJack F Vogel /* Establish a clean starting point */ 46561ae650dSJack F Vogel i40e_clear_hw(hw); 46661ae650dSJack F Vogel error = i40e_pf_reset(hw); 46761ae650dSJack F Vogel if (error) { 468*fdb6f38aSEric Joyner device_printf(dev, "PF reset failure %d\n", error); 46961ae650dSJack F Vogel error = EIO; 47061ae650dSJack F Vogel goto err_out; 47161ae650dSJack F Vogel } 47261ae650dSJack F Vogel 47361ae650dSJack F Vogel /* Set admin queue parameters */ 47461ae650dSJack F Vogel hw->aq.num_arq_entries = IXL_AQ_LEN; 47561ae650dSJack F Vogel hw->aq.num_asq_entries = IXL_AQ_LEN; 47661ae650dSJack F Vogel hw->aq.arq_buf_size = IXL_AQ_BUFSZ; 47761ae650dSJack F Vogel hw->aq.asq_buf_size = IXL_AQ_BUFSZ; 47861ae650dSJack F Vogel 479*fdb6f38aSEric Joyner /* Initialize mac filter list for VSI */ 480*fdb6f38aSEric Joyner SLIST_INIT(&vsi->ftl); 481*fdb6f38aSEric Joyner 48261ae650dSJack F Vogel /* Initialize the shared code */ 48361ae650dSJack F Vogel error = i40e_init_shared_code(hw); 48461ae650dSJack F Vogel if (error) { 485*fdb6f38aSEric Joyner device_printf(dev, "Unable to initialize shared code, error %d\n", 486*fdb6f38aSEric Joyner error); 48761ae650dSJack F Vogel error = EIO; 48861ae650dSJack F Vogel goto err_out; 48961ae650dSJack F Vogel } 49061ae650dSJack F Vogel 49161ae650dSJack F Vogel /* Set up the admin queue */ 49261ae650dSJack F Vogel error = i40e_init_adminq(hw); 493*fdb6f38aSEric Joyner if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) { 494*fdb6f38aSEric Joyner device_printf(dev, "Unable to initialize Admin Queue, error %d\n", 495*fdb6f38aSEric Joyner error); 496*fdb6f38aSEric Joyner error = EIO; 497*fdb6f38aSEric Joyner goto err_out; 498*fdb6f38aSEric Joyner } 499*fdb6f38aSEric Joyner device_printf(dev, "%s\n", ixl_fw_version_str(hw)); 500*fdb6f38aSEric Joyner if (error == I40E_ERR_FIRMWARE_API_VERSION) { 50161ae650dSJack F Vogel device_printf(dev, "The driver for the device stopped " 50261ae650dSJack F Vogel "because the NVM image is newer than expected.\n" 50361ae650dSJack F Vogel "You must install the most recent version of " 50461ae650dSJack F Vogel "the network driver.\n"); 505*fdb6f38aSEric Joyner error = EIO; 50661ae650dSJack F Vogel goto err_out; 50761ae650dSJack F Vogel } 50861ae650dSJack F Vogel 50961ae650dSJack F Vogel if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 51061ae650dSJack F Vogel hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) 51161ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 51261ae650dSJack F Vogel "a newer version of the NVM image than expected.\n" 51361ae650dSJack F Vogel "Please install the most recent version of the network driver.\n"); 51461ae650dSJack F Vogel else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || 51561ae650dSJack F Vogel hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) 51661ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 51761ae650dSJack F Vogel "an older version of the NVM image than expected.\n" 51861ae650dSJack F Vogel "Please update the NVM image.\n"); 51961ae650dSJack F Vogel 52061ae650dSJack F Vogel /* Clear PXE mode */ 52161ae650dSJack F Vogel i40e_clear_pxe_mode(hw); 52261ae650dSJack F Vogel 52361ae650dSJack F Vogel /* Get capabilities from the device */ 52461ae650dSJack F Vogel error = ixl_get_hw_capabilities(pf); 52561ae650dSJack F Vogel if (error) { 52661ae650dSJack F Vogel device_printf(dev, "HW capabilities failure!\n"); 52761ae650dSJack F Vogel goto err_get_cap; 52861ae650dSJack F Vogel } 52961ae650dSJack F Vogel 53061ae650dSJack F Vogel /* Set up host memory cache */ 53156c2c47bSJack F Vogel error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 53256c2c47bSJack F Vogel hw->func_caps.num_rx_qp, 0, 0); 53361ae650dSJack F Vogel if (error) { 53461ae650dSJack F Vogel device_printf(dev, "init_lan_hmc failed: %d\n", error); 53561ae650dSJack F Vogel goto err_get_cap; 53661ae650dSJack F Vogel } 53761ae650dSJack F Vogel 53861ae650dSJack F Vogel error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 53961ae650dSJack F Vogel if (error) { 54061ae650dSJack F Vogel device_printf(dev, "configure_lan_hmc failed: %d\n", error); 54161ae650dSJack F Vogel goto err_mac_hmc; 54261ae650dSJack F Vogel } 54361ae650dSJack F Vogel 54461ae650dSJack F Vogel /* Disable LLDP from the firmware */ 54561ae650dSJack F Vogel i40e_aq_stop_lldp(hw, TRUE, NULL); 54661ae650dSJack F Vogel 54761ae650dSJack F Vogel i40e_get_mac_addr(hw, hw->mac.addr); 54861ae650dSJack F Vogel error = i40e_validate_mac_addr(hw->mac.addr); 54961ae650dSJack F Vogel if (error) { 55061ae650dSJack F Vogel device_printf(dev, "validate_mac_addr failed: %d\n", error); 55161ae650dSJack F Vogel goto err_mac_hmc; 55261ae650dSJack F Vogel } 55361ae650dSJack F Vogel bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 55461ae650dSJack F Vogel i40e_get_port_mac_addr(hw, hw->mac.port_addr); 55561ae650dSJack F Vogel 556e5100ee2SJack F Vogel /* Set up VSI and queues */ 55761ae650dSJack F Vogel if (ixl_setup_stations(pf) != 0) { 55861ae650dSJack F Vogel device_printf(dev, "setup stations failed!\n"); 55961ae650dSJack F Vogel error = ENOMEM; 56061ae650dSJack F Vogel goto err_mac_hmc; 56161ae650dSJack F Vogel } 56261ae650dSJack F Vogel 563b6c8f260SJack F Vogel if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 564b6c8f260SJack F Vogel (hw->aq.fw_maj_ver < 4)) { 56561ae650dSJack F Vogel i40e_msec_delay(75); 56661ae650dSJack F Vogel error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 567223d846dSEric Joyner if (error) { 56861ae650dSJack F Vogel device_printf(dev, "link restart failed, aq_err=%d\n", 56961ae650dSJack F Vogel pf->hw.aq.asq_last_status); 570223d846dSEric Joyner goto err_late; 571223d846dSEric Joyner } 57261ae650dSJack F Vogel } 57361ae650dSJack F Vogel 57461ae650dSJack F Vogel /* Determine link state */ 575223d846dSEric Joyner hw->phy.get_link_info = TRUE; 576be771cdaSJack F Vogel i40e_get_link_status(hw, &pf->link_up); 57761ae650dSJack F Vogel 578223d846dSEric Joyner /* Setup OS network interface / ifnet */ 579e5100ee2SJack F Vogel if (ixl_setup_interface(dev, vsi) != 0) { 580e5100ee2SJack F Vogel device_printf(dev, "interface setup failed!\n"); 581e5100ee2SJack F Vogel error = EIO; 58261ae650dSJack F Vogel goto err_late; 583e5100ee2SJack F Vogel } 58461ae650dSJack F Vogel 585b6c8f260SJack F Vogel error = ixl_switch_config(pf); 586b6c8f260SJack F Vogel if (error) { 587223d846dSEric Joyner device_printf(dev, "Initial ixl_switch_config() failed: %d\n", error); 588a48d00d2SEric Joyner goto err_late; 589b6c8f260SJack F Vogel } 590b6c8f260SJack F Vogel 591223d846dSEric Joyner /* Limit PHY interrupts to link, autoneg, and modules failure */ 5927f70bec6SEric Joyner error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, 593223d846dSEric Joyner NULL); 594223d846dSEric Joyner if (error) { 595223d846dSEric Joyner device_printf(dev, "i40e_aq_set_phy_mask() failed: err %d," 596223d846dSEric Joyner " aq_err %d\n", error, hw->aq.asq_last_status); 597223d846dSEric Joyner goto err_late; 598223d846dSEric Joyner } 599b6c8f260SJack F Vogel 60061ae650dSJack F Vogel /* Get the bus configuration and set the shared code */ 60161ae650dSJack F Vogel bus = ixl_get_bus_info(hw, dev); 60261ae650dSJack F Vogel i40e_set_pci_config_data(hw, bus); 60361ae650dSJack F Vogel 604a48d00d2SEric Joyner /* Initialize taskqueues */ 605a48d00d2SEric Joyner ixl_init_taskqueues(pf); 606a48d00d2SEric Joyner 607*fdb6f38aSEric Joyner /* Initialize statistics & add sysctls */ 608*fdb6f38aSEric Joyner ixl_add_device_sysctls(pf); 609*fdb6f38aSEric Joyner 61061ae650dSJack F Vogel ixl_pf_reset_stats(pf); 61161ae650dSJack F Vogel ixl_update_stats_counters(pf); 61261ae650dSJack F Vogel ixl_add_hw_stats(pf); 61361ae650dSJack F Vogel 61461ae650dSJack F Vogel /* Register for VLAN events */ 61561ae650dSJack F Vogel vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 61661ae650dSJack F Vogel ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); 61761ae650dSJack F Vogel vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 61861ae650dSJack F Vogel ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); 61961ae650dSJack F Vogel 62056c2c47bSJack F Vogel #ifdef PCI_IOV 62156c2c47bSJack F Vogel /* SR-IOV is only supported when MSI-X is in use. */ 62256c2c47bSJack F Vogel if (pf->msix > 1) { 62356c2c47bSJack F Vogel pf_schema = pci_iov_schema_alloc_node(); 62456c2c47bSJack F Vogel vf_schema = pci_iov_schema_alloc_node(); 62556c2c47bSJack F Vogel pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); 62656c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", 62756c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, TRUE); 62856c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-set-mac", 62956c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 63056c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-promisc", 63156c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 632e5100ee2SJack F Vogel 63356c2c47bSJack F Vogel iov_error = pci_iov_attach(dev, pf_schema, vf_schema); 63456c2c47bSJack F Vogel if (iov_error != 0) 63556c2c47bSJack F Vogel device_printf(dev, 63656c2c47bSJack F Vogel "Failed to initialize SR-IOV (error=%d)\n", 63756c2c47bSJack F Vogel iov_error); 63856c2c47bSJack F Vogel } 63956c2c47bSJack F Vogel #endif 64056c2c47bSJack F Vogel 64131830672SJack F Vogel #ifdef DEV_NETMAP 64231830672SJack F Vogel ixl_netmap_attach(vsi); 64331830672SJack F Vogel #endif /* DEV_NETMAP */ 64461ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: end"); 64561ae650dSJack F Vogel return (0); 64661ae650dSJack F Vogel 64761ae650dSJack F Vogel err_late: 648e5100ee2SJack F Vogel if (vsi->ifp != NULL) 649e5100ee2SJack F Vogel if_free(vsi->ifp); 65061ae650dSJack F Vogel err_mac_hmc: 65161ae650dSJack F Vogel i40e_shutdown_lan_hmc(hw); 65261ae650dSJack F Vogel err_get_cap: 65361ae650dSJack F Vogel i40e_shutdown_adminq(hw); 65461ae650dSJack F Vogel err_out: 65561ae650dSJack F Vogel ixl_free_pci_resources(pf); 656e5100ee2SJack F Vogel ixl_free_vsi(vsi); 65761ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 65861ae650dSJack F Vogel return (error); 65961ae650dSJack F Vogel } 66061ae650dSJack F Vogel 66161ae650dSJack F Vogel /********************************************************************* 66261ae650dSJack F Vogel * Device removal routine 66361ae650dSJack F Vogel * 66461ae650dSJack F Vogel * The detach entry point is called when the driver is being removed. 66561ae650dSJack F Vogel * This routine stops the adapter and deallocates all the resources 66661ae650dSJack F Vogel * that were allocated for driver operation. 66761ae650dSJack F Vogel * 66861ae650dSJack F Vogel * return 0 on success, positive on failure 66961ae650dSJack F Vogel *********************************************************************/ 67061ae650dSJack F Vogel 67161ae650dSJack F Vogel static int 67261ae650dSJack F Vogel ixl_detach(device_t dev) 67361ae650dSJack F Vogel { 67461ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 67561ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 67661ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 67761ae650dSJack F Vogel i40e_status status; 67856c2c47bSJack F Vogel #ifdef PCI_IOV 67956c2c47bSJack F Vogel int error; 68056c2c47bSJack F Vogel #endif 68161ae650dSJack F Vogel 68261ae650dSJack F Vogel INIT_DEBUGOUT("ixl_detach: begin"); 68361ae650dSJack F Vogel 68461ae650dSJack F Vogel /* Make sure VLANS are not using driver */ 68561ae650dSJack F Vogel if (vsi->ifp->if_vlantrunk != NULL) { 68661ae650dSJack F Vogel device_printf(dev,"Vlan in use, detach first\n"); 68761ae650dSJack F Vogel return (EBUSY); 68861ae650dSJack F Vogel } 68961ae650dSJack F Vogel 69056c2c47bSJack F Vogel #ifdef PCI_IOV 69156c2c47bSJack F Vogel error = pci_iov_detach(dev); 69256c2c47bSJack F Vogel if (error != 0) { 69356c2c47bSJack F Vogel device_printf(dev, "SR-IOV in use; detach first.\n"); 69456c2c47bSJack F Vogel return (error); 69556c2c47bSJack F Vogel } 69656c2c47bSJack F Vogel #endif 69756c2c47bSJack F Vogel 698b6c8f260SJack F Vogel ether_ifdetach(vsi->ifp); 699223d846dSEric Joyner if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) 70061ae650dSJack F Vogel ixl_stop(pf); 70161ae650dSJack F Vogel 702a48d00d2SEric Joyner ixl_free_taskqueues(pf); 70361ae650dSJack F Vogel 70461ae650dSJack F Vogel /* Shutdown LAN HMC */ 70561ae650dSJack F Vogel status = i40e_shutdown_lan_hmc(hw); 70661ae650dSJack F Vogel if (status) 70761ae650dSJack F Vogel device_printf(dev, 70861ae650dSJack F Vogel "Shutdown LAN HMC failed with code %d\n", status); 70961ae650dSJack F Vogel 71061ae650dSJack F Vogel /* Shutdown admin queue */ 71161ae650dSJack F Vogel status = i40e_shutdown_adminq(hw); 71261ae650dSJack F Vogel if (status) 71361ae650dSJack F Vogel device_printf(dev, 71461ae650dSJack F Vogel "Shutdown Admin queue failed with code %d\n", status); 71561ae650dSJack F Vogel 71661ae650dSJack F Vogel /* Unregister VLAN events */ 71761ae650dSJack F Vogel if (vsi->vlan_attach != NULL) 71861ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); 71961ae650dSJack F Vogel if (vsi->vlan_detach != NULL) 72061ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); 72161ae650dSJack F Vogel 72261ae650dSJack F Vogel callout_drain(&pf->timer); 72331830672SJack F Vogel #ifdef DEV_NETMAP 72431830672SJack F Vogel netmap_detach(vsi->ifp); 72531830672SJack F Vogel #endif /* DEV_NETMAP */ 72661ae650dSJack F Vogel ixl_free_pci_resources(pf); 72761ae650dSJack F Vogel bus_generic_detach(dev); 72861ae650dSJack F Vogel if_free(vsi->ifp); 72961ae650dSJack F Vogel ixl_free_vsi(vsi); 73061ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 73161ae650dSJack F Vogel return (0); 73261ae650dSJack F Vogel } 73361ae650dSJack F Vogel 73461ae650dSJack F Vogel /********************************************************************* 73561ae650dSJack F Vogel * 73661ae650dSJack F Vogel * Shutdown entry point 73761ae650dSJack F Vogel * 73861ae650dSJack F Vogel **********************************************************************/ 73961ae650dSJack F Vogel 74061ae650dSJack F Vogel static int 74161ae650dSJack F Vogel ixl_shutdown(device_t dev) 74261ae650dSJack F Vogel { 74361ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 74461ae650dSJack F Vogel ixl_stop(pf); 74561ae650dSJack F Vogel return (0); 74661ae650dSJack F Vogel } 74761ae650dSJack F Vogel 74861ae650dSJack F Vogel 74961ae650dSJack F Vogel /********************************************************************* 75061ae650dSJack F Vogel * 75161ae650dSJack F Vogel * Get the hardware capabilities 75261ae650dSJack F Vogel * 75361ae650dSJack F Vogel **********************************************************************/ 75461ae650dSJack F Vogel 75561ae650dSJack F Vogel static int 75661ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf) 75761ae650dSJack F Vogel { 75861ae650dSJack F Vogel struct i40e_aqc_list_capabilities_element_resp *buf; 75961ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 76061ae650dSJack F Vogel device_t dev = pf->dev; 76161ae650dSJack F Vogel int error, len; 76261ae650dSJack F Vogel u16 needed; 76361ae650dSJack F Vogel bool again = TRUE; 76461ae650dSJack F Vogel 76561ae650dSJack F Vogel len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); 76661ae650dSJack F Vogel retry: 76761ae650dSJack F Vogel if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *) 76861ae650dSJack F Vogel malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) { 76961ae650dSJack F Vogel device_printf(dev, "Unable to allocate cap memory\n"); 77061ae650dSJack F Vogel return (ENOMEM); 77161ae650dSJack F Vogel } 77261ae650dSJack F Vogel 77361ae650dSJack F Vogel /* This populates the hw struct */ 77461ae650dSJack F Vogel error = i40e_aq_discover_capabilities(hw, buf, len, 77561ae650dSJack F Vogel &needed, i40e_aqc_opc_list_func_capabilities, NULL); 77661ae650dSJack F Vogel free(buf, M_DEVBUF); 77761ae650dSJack F Vogel if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && 77861ae650dSJack F Vogel (again == TRUE)) { 77961ae650dSJack F Vogel /* retry once with a larger buffer */ 78061ae650dSJack F Vogel again = FALSE; 78161ae650dSJack F Vogel len = needed; 78261ae650dSJack F Vogel goto retry; 78361ae650dSJack F Vogel } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { 78461ae650dSJack F Vogel device_printf(dev, "capability discovery failed: %d\n", 78561ae650dSJack F Vogel pf->hw.aq.asq_last_status); 78661ae650dSJack F Vogel return (ENODEV); 78761ae650dSJack F Vogel } 78861ae650dSJack F Vogel 78961ae650dSJack F Vogel /* Capture this PF's starting queue pair */ 79061ae650dSJack F Vogel pf->qbase = hw->func_caps.base_queue; 79161ae650dSJack F Vogel 79261ae650dSJack F Vogel #ifdef IXL_DEBUG 79361ae650dSJack F Vogel device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, " 79461ae650dSJack F Vogel "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", 79561ae650dSJack F Vogel hw->pf_id, hw->func_caps.num_vfs, 79661ae650dSJack F Vogel hw->func_caps.num_msix_vectors, 79761ae650dSJack F Vogel hw->func_caps.num_msix_vectors_vf, 79861ae650dSJack F Vogel hw->func_caps.fd_filters_guaranteed, 79961ae650dSJack F Vogel hw->func_caps.fd_filters_best_effort, 80061ae650dSJack F Vogel hw->func_caps.num_tx_qp, 80161ae650dSJack F Vogel hw->func_caps.num_rx_qp, 80261ae650dSJack F Vogel hw->func_caps.base_queue); 80361ae650dSJack F Vogel #endif 80461ae650dSJack F Vogel return (error); 80561ae650dSJack F Vogel } 80661ae650dSJack F Vogel 80761ae650dSJack F Vogel static void 80861ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) 80961ae650dSJack F Vogel { 81061ae650dSJack F Vogel device_t dev = vsi->dev; 81161ae650dSJack F Vogel 81261ae650dSJack F Vogel /* Enable/disable TXCSUM/TSO4 */ 81361ae650dSJack F Vogel if (!(ifp->if_capenable & IFCAP_TXCSUM) 81461ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO4)) { 81561ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) { 81661ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TXCSUM; 81761ae650dSJack F Vogel /* enable TXCSUM, restore TSO if previously enabled */ 81861ae650dSJack F Vogel if (vsi->flags & IXL_FLAGS_KEEP_TSO4) { 81961ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 82061ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO4; 82161ae650dSJack F Vogel } 82261ae650dSJack F Vogel } 82361ae650dSJack F Vogel else if (mask & IFCAP_TSO4) { 82461ae650dSJack F Vogel ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); 82561ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 82661ae650dSJack F Vogel device_printf(dev, 82761ae650dSJack F Vogel "TSO4 requires txcsum, enabling both...\n"); 82861ae650dSJack F Vogel } 82961ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM) 83061ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO4)) { 83161ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) 83261ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TXCSUM; 83361ae650dSJack F Vogel else if (mask & IFCAP_TSO4) 83461ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO4; 83561ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM) 83661ae650dSJack F Vogel && (ifp->if_capenable & IFCAP_TSO4)) { 83761ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) { 83861ae650dSJack F Vogel vsi->flags |= IXL_FLAGS_KEEP_TSO4; 83961ae650dSJack F Vogel ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); 84061ae650dSJack F Vogel device_printf(dev, 84161ae650dSJack F Vogel "TSO4 requires txcsum, disabling both...\n"); 84261ae650dSJack F Vogel } else if (mask & IFCAP_TSO4) 84361ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TSO4; 84461ae650dSJack F Vogel } 84561ae650dSJack F Vogel 84661ae650dSJack F Vogel /* Enable/disable TXCSUM_IPV6/TSO6 */ 84761ae650dSJack F Vogel if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) 84861ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO6)) { 84961ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) { 85061ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TXCSUM_IPV6; 85161ae650dSJack F Vogel if (vsi->flags & IXL_FLAGS_KEEP_TSO6) { 85261ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 85361ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO6; 85461ae650dSJack F Vogel } 85561ae650dSJack F Vogel } else if (mask & IFCAP_TSO6) { 85661ae650dSJack F Vogel ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 85761ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 85861ae650dSJack F Vogel device_printf(dev, 85961ae650dSJack F Vogel "TSO6 requires txcsum6, enabling both...\n"); 86061ae650dSJack F Vogel } 86161ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 86261ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO6)) { 86361ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) 86461ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; 86561ae650dSJack F Vogel else if (mask & IFCAP_TSO6) 86661ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO6; 86761ae650dSJack F Vogel } else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 86861ae650dSJack F Vogel && (ifp->if_capenable & IFCAP_TSO6)) { 86961ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) { 87061ae650dSJack F Vogel vsi->flags |= IXL_FLAGS_KEEP_TSO6; 87161ae650dSJack F Vogel ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 87261ae650dSJack F Vogel device_printf(dev, 87361ae650dSJack F Vogel "TSO6 requires txcsum6, disabling both...\n"); 87461ae650dSJack F Vogel } else if (mask & IFCAP_TSO6) 87561ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TSO6; 87661ae650dSJack F Vogel } 87761ae650dSJack F Vogel } 87861ae650dSJack F Vogel 87961ae650dSJack F Vogel /********************************************************************* 88061ae650dSJack F Vogel * Ioctl entry point 88161ae650dSJack F Vogel * 88261ae650dSJack F Vogel * ixl_ioctl is called when the user wants to configure the 88361ae650dSJack F Vogel * interface. 88461ae650dSJack F Vogel * 88561ae650dSJack F Vogel * return 0 on success, positive on failure 88661ae650dSJack F Vogel **********************************************************************/ 88761ae650dSJack F Vogel 88861ae650dSJack F Vogel static int 88961ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 89061ae650dSJack F Vogel { 89161ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 89256c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 89361ae650dSJack F Vogel struct ifreq *ifr = (struct ifreq *)data; 894223d846dSEric Joyner struct ifdrv *ifd = (struct ifdrv *)data; 89561ae650dSJack F Vogel #if defined(INET) || defined(INET6) 89661ae650dSJack F Vogel struct ifaddr *ifa = (struct ifaddr *)data; 89761ae650dSJack F Vogel bool avoid_reset = FALSE; 89861ae650dSJack F Vogel #endif 89961ae650dSJack F Vogel int error = 0; 90061ae650dSJack F Vogel 90161ae650dSJack F Vogel switch (command) { 90261ae650dSJack F Vogel 90361ae650dSJack F Vogel case SIOCSIFADDR: 90461ae650dSJack F Vogel #ifdef INET 90561ae650dSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET) 90661ae650dSJack F Vogel avoid_reset = TRUE; 90761ae650dSJack F Vogel #endif 90861ae650dSJack F Vogel #ifdef INET6 90961ae650dSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET6) 91061ae650dSJack F Vogel avoid_reset = TRUE; 91161ae650dSJack F Vogel #endif 91261ae650dSJack F Vogel #if defined(INET) || defined(INET6) 91361ae650dSJack F Vogel /* 91461ae650dSJack F Vogel ** Calling init results in link renegotiation, 91561ae650dSJack F Vogel ** so we avoid doing it when possible. 91661ae650dSJack F Vogel */ 91761ae650dSJack F Vogel if (avoid_reset) { 91861ae650dSJack F Vogel ifp->if_flags |= IFF_UP; 91961ae650dSJack F Vogel if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 92061ae650dSJack F Vogel ixl_init(pf); 9217e0dde7dSBjoern A. Zeeb #ifdef INET 92261ae650dSJack F Vogel if (!(ifp->if_flags & IFF_NOARP)) 92361ae650dSJack F Vogel arp_ifinit(ifp, ifa); 9247e0dde7dSBjoern A. Zeeb #endif 92561ae650dSJack F Vogel } else 92661ae650dSJack F Vogel error = ether_ioctl(ifp, command, data); 92761ae650dSJack F Vogel break; 92861ae650dSJack F Vogel #endif 92961ae650dSJack F Vogel case SIOCSIFMTU: 93061ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 93161ae650dSJack F Vogel if (ifr->ifr_mtu > IXL_MAX_FRAME - 93261ae650dSJack F Vogel ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) { 93361ae650dSJack F Vogel error = EINVAL; 93461ae650dSJack F Vogel } else { 93561ae650dSJack F Vogel IXL_PF_LOCK(pf); 93661ae650dSJack F Vogel ifp->if_mtu = ifr->ifr_mtu; 93761ae650dSJack F Vogel vsi->max_frame_size = 93861ae650dSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 93961ae650dSJack F Vogel + ETHER_VLAN_ENCAP_LEN; 94061ae650dSJack F Vogel ixl_init_locked(pf); 94161ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 94261ae650dSJack F Vogel } 94361ae650dSJack F Vogel break; 94461ae650dSJack F Vogel case SIOCSIFFLAGS: 94561ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 94661ae650dSJack F Vogel IXL_PF_LOCK(pf); 94761ae650dSJack F Vogel if (ifp->if_flags & IFF_UP) { 94861ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 94961ae650dSJack F Vogel if ((ifp->if_flags ^ pf->if_flags) & 95061ae650dSJack F Vogel (IFF_PROMISC | IFF_ALLMULTI)) { 95161ae650dSJack F Vogel ixl_set_promisc(vsi); 95261ae650dSJack F Vogel } 953223d846dSEric Joyner } else { 954223d846dSEric Joyner IXL_PF_UNLOCK(pf); 955223d846dSEric Joyner ixl_init(pf); 956223d846dSEric Joyner IXL_PF_LOCK(pf); 957223d846dSEric Joyner } 958223d846dSEric Joyner } else { 959223d846dSEric Joyner if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 960223d846dSEric Joyner IXL_PF_UNLOCK(pf); 96161ae650dSJack F Vogel ixl_stop(pf); 962223d846dSEric Joyner IXL_PF_LOCK(pf); 963223d846dSEric Joyner } 964223d846dSEric Joyner } 96561ae650dSJack F Vogel pf->if_flags = ifp->if_flags; 96661ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 96761ae650dSJack F Vogel break; 968223d846dSEric Joyner case SIOCSDRVSPEC: 969223d846dSEric Joyner case SIOCGDRVSPEC: 970223d846dSEric Joyner IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific " 971223d846dSEric Joyner "Info)\n"); 972223d846dSEric Joyner 973223d846dSEric Joyner /* NVM update command */ 974223d846dSEric Joyner if (ifd->ifd_cmd == I40E_NVM_ACCESS) 975223d846dSEric Joyner error = ixl_handle_nvmupd_cmd(pf, ifd); 976223d846dSEric Joyner else 977223d846dSEric Joyner error = EINVAL; 978223d846dSEric Joyner break; 97961ae650dSJack F Vogel case SIOCADDMULTI: 98061ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); 98161ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 98261ae650dSJack F Vogel IXL_PF_LOCK(pf); 98361ae650dSJack F Vogel ixl_disable_intr(vsi); 98461ae650dSJack F Vogel ixl_add_multi(vsi); 98561ae650dSJack F Vogel ixl_enable_intr(vsi); 98661ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 98761ae650dSJack F Vogel } 98861ae650dSJack F Vogel break; 98961ae650dSJack F Vogel case SIOCDELMULTI: 99061ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); 99161ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 99261ae650dSJack F Vogel IXL_PF_LOCK(pf); 99361ae650dSJack F Vogel ixl_disable_intr(vsi); 99461ae650dSJack F Vogel ixl_del_multi(vsi); 99561ae650dSJack F Vogel ixl_enable_intr(vsi); 99661ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 99761ae650dSJack F Vogel } 99861ae650dSJack F Vogel break; 99961ae650dSJack F Vogel case SIOCSIFMEDIA: 100061ae650dSJack F Vogel case SIOCGIFMEDIA: 1001be771cdaSJack F Vogel #ifdef IFM_ETH_XTYPE 1002be771cdaSJack F Vogel case SIOCGIFXMEDIA: 1003be771cdaSJack F Vogel #endif 100461ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 100561ae650dSJack F Vogel error = ifmedia_ioctl(ifp, ifr, &vsi->media, command); 100661ae650dSJack F Vogel break; 100761ae650dSJack F Vogel case SIOCSIFCAP: 100861ae650dSJack F Vogel { 100961ae650dSJack F Vogel int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 101061ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 101161ae650dSJack F Vogel 101261ae650dSJack F Vogel ixl_cap_txcsum_tso(vsi, ifp, mask); 101361ae650dSJack F Vogel 101461ae650dSJack F Vogel if (mask & IFCAP_RXCSUM) 101561ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_RXCSUM; 101661ae650dSJack F Vogel if (mask & IFCAP_RXCSUM_IPV6) 101761ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 101861ae650dSJack F Vogel if (mask & IFCAP_LRO) 101961ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_LRO; 102061ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWTAGGING) 102161ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 102261ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWFILTER) 102361ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 102461ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWTSO) 102561ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 102661ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 102761ae650dSJack F Vogel IXL_PF_LOCK(pf); 102861ae650dSJack F Vogel ixl_init_locked(pf); 102961ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 103061ae650dSJack F Vogel } 103161ae650dSJack F Vogel VLAN_CAPABILITIES(ifp); 103261ae650dSJack F Vogel 103361ae650dSJack F Vogel break; 103461ae650dSJack F Vogel } 103561ae650dSJack F Vogel 103661ae650dSJack F Vogel default: 103761ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command); 103861ae650dSJack F Vogel error = ether_ioctl(ifp, command, data); 103961ae650dSJack F Vogel break; 104061ae650dSJack F Vogel } 104161ae650dSJack F Vogel 104261ae650dSJack F Vogel return (error); 104361ae650dSJack F Vogel } 104461ae650dSJack F Vogel 104561ae650dSJack F Vogel 104661ae650dSJack F Vogel /********************************************************************* 104761ae650dSJack F Vogel * Init entry point 104861ae650dSJack F Vogel * 104961ae650dSJack F Vogel * This routine is used in two ways. It is used by the stack as 105061ae650dSJack F Vogel * init entry point in network interface structure. It is also used 105161ae650dSJack F Vogel * by the driver as a hw/sw initialization routine to get to a 105261ae650dSJack F Vogel * consistent state. 105361ae650dSJack F Vogel * 105461ae650dSJack F Vogel * return 0 on success, positive on failure 105561ae650dSJack F Vogel **********************************************************************/ 105661ae650dSJack F Vogel 105761ae650dSJack F Vogel static void 105861ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf) 105961ae650dSJack F Vogel { 106061ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 106161ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 106261ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 106361ae650dSJack F Vogel device_t dev = pf->dev; 106461ae650dSJack F Vogel struct i40e_filter_control_settings filter; 106561ae650dSJack F Vogel u8 tmpaddr[ETHER_ADDR_LEN]; 106661ae650dSJack F Vogel int ret; 106761ae650dSJack F Vogel 106861ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 106961ae650dSJack F Vogel INIT_DEBUGOUT("ixl_init: begin"); 1070223d846dSEric Joyner 1071223d846dSEric Joyner ixl_stop_locked(pf); 107261ae650dSJack F Vogel 107361ae650dSJack F Vogel /* Get the latest mac address... User might use a LAA */ 107461ae650dSJack F Vogel bcopy(IF_LLADDR(vsi->ifp), tmpaddr, 107561ae650dSJack F Vogel I40E_ETH_LENGTH_OF_ADDRESS); 107661ae650dSJack F Vogel if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && 1077a48d00d2SEric Joyner (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { 1078a48d00d2SEric Joyner ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); 107961ae650dSJack F Vogel bcopy(tmpaddr, hw->mac.addr, 108061ae650dSJack F Vogel I40E_ETH_LENGTH_OF_ADDRESS); 108161ae650dSJack F Vogel ret = i40e_aq_mac_address_write(hw, 108261ae650dSJack F Vogel I40E_AQC_WRITE_TYPE_LAA_ONLY, 108361ae650dSJack F Vogel hw->mac.addr, NULL); 108461ae650dSJack F Vogel if (ret) { 108561ae650dSJack F Vogel device_printf(dev, "LLA address" 108661ae650dSJack F Vogel "change failed!!\n"); 108761ae650dSJack F Vogel return; 1088a48d00d2SEric Joyner } else { 1089a48d00d2SEric Joyner ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); 109061ae650dSJack F Vogel } 109161ae650dSJack F Vogel } 109261ae650dSJack F Vogel 109361ae650dSJack F Vogel /* Set the various hardware offload abilities */ 109461ae650dSJack F Vogel ifp->if_hwassist = 0; 109561ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TSO) 109661ae650dSJack F Vogel ifp->if_hwassist |= CSUM_TSO; 109761ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM) 109861ae650dSJack F Vogel ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 109961ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 110061ae650dSJack F Vogel ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); 110161ae650dSJack F Vogel 110261ae650dSJack F Vogel /* Set up the device filtering */ 110361ae650dSJack F Vogel bzero(&filter, sizeof(filter)); 110461ae650dSJack F Vogel filter.enable_ethtype = TRUE; 110561ae650dSJack F Vogel filter.enable_macvlan = TRUE; 110661ae650dSJack F Vogel #ifdef IXL_FDIR 110761ae650dSJack F Vogel filter.enable_fdir = TRUE; 110861ae650dSJack F Vogel #endif 11097f70bec6SEric Joyner filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; 111061ae650dSJack F Vogel if (i40e_set_filter_control(hw, &filter)) 11117f70bec6SEric Joyner device_printf(dev, "i40e_set_filter_control() failed\n"); 111261ae650dSJack F Vogel 111361ae650dSJack F Vogel /* Set up RSS */ 111461ae650dSJack F Vogel ixl_config_rss(vsi); 111561ae650dSJack F Vogel 11167f70bec6SEric Joyner /* Prepare the VSI: rings, hmc contexts, etc... */ 111761ae650dSJack F Vogel if (ixl_initialize_vsi(vsi)) { 111861ae650dSJack F Vogel device_printf(dev, "initialize vsi failed!!\n"); 111961ae650dSJack F Vogel return; 112061ae650dSJack F Vogel } 112161ae650dSJack F Vogel 112261ae650dSJack F Vogel /* Add protocol filters to list */ 112361ae650dSJack F Vogel ixl_init_filters(vsi); 112461ae650dSJack F Vogel 112561ae650dSJack F Vogel /* Setup vlan's if needed */ 112661ae650dSJack F Vogel ixl_setup_vlan_filters(vsi); 112761ae650dSJack F Vogel 112861ae650dSJack F Vogel /* Set up MSI/X routing and the ITR settings */ 112961ae650dSJack F Vogel if (ixl_enable_msix) { 113061ae650dSJack F Vogel ixl_configure_msix(pf); 113161ae650dSJack F Vogel ixl_configure_itr(pf); 113261ae650dSJack F Vogel } else 113361ae650dSJack F Vogel ixl_configure_legacy(pf); 113461ae650dSJack F Vogel 113561ae650dSJack F Vogel ixl_enable_rings(vsi); 113661ae650dSJack F Vogel 113761ae650dSJack F Vogel i40e_aq_set_default_vsi(hw, vsi->seid, NULL); 113861ae650dSJack F Vogel 113956c2c47bSJack F Vogel ixl_reconfigure_filters(vsi); 114056c2c47bSJack F Vogel 114161ae650dSJack F Vogel /* Set MTU in hardware*/ 114261ae650dSJack F Vogel int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size, 114361ae650dSJack F Vogel TRUE, 0, NULL); 114461ae650dSJack F Vogel if (aq_error) 114561ae650dSJack F Vogel device_printf(vsi->dev, 114661ae650dSJack F Vogel "aq_set_mac_config in init error, code %d\n", 114761ae650dSJack F Vogel aq_error); 114861ae650dSJack F Vogel 114961ae650dSJack F Vogel /* And now turn on interrupts */ 115061ae650dSJack F Vogel ixl_enable_intr(vsi); 115161ae650dSJack F Vogel 1152223d846dSEric Joyner /* Get link info */ 1153223d846dSEric Joyner hw->phy.get_link_info = TRUE; 1154223d846dSEric Joyner i40e_get_link_status(hw, &pf->link_up); 1155223d846dSEric Joyner ixl_update_link_status(pf); 1156223d846dSEric Joyner 11577f70bec6SEric Joyner /* Start the local timer */ 11587f70bec6SEric Joyner callout_reset(&pf->timer, hz, ixl_local_timer, pf); 11597f70bec6SEric Joyner 116061ae650dSJack F Vogel /* Now inform the stack we're ready */ 116161ae650dSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 116261ae650dSJack F Vogel 116361ae650dSJack F Vogel return; 116461ae650dSJack F Vogel } 116561ae650dSJack F Vogel 11667f70bec6SEric Joyner // XXX: super experimental stuff 11677f70bec6SEric Joyner static int 11687f70bec6SEric Joyner ixl_teardown_hw_structs(struct ixl_pf *pf) 11697f70bec6SEric Joyner { 11707f70bec6SEric Joyner enum i40e_status_code status = 0; 11717f70bec6SEric Joyner struct i40e_hw *hw = &pf->hw; 11727f70bec6SEric Joyner device_t dev = pf->dev; 11737f70bec6SEric Joyner 11747f70bec6SEric Joyner /* Shutdown LAN HMC */ 11757f70bec6SEric Joyner if (hw->hmc.hmc_obj) { 11767f70bec6SEric Joyner status = i40e_shutdown_lan_hmc(hw); 11777f70bec6SEric Joyner if (status) { 11787f70bec6SEric Joyner device_printf(dev, 11797f70bec6SEric Joyner "init: LAN HMC shutdown failure; status %d\n", status); 11807f70bec6SEric Joyner goto err_out; 11817f70bec6SEric Joyner } 11827f70bec6SEric Joyner } 11837f70bec6SEric Joyner 11847f70bec6SEric Joyner // XXX: This gets called when we know the adminq is inactive; 11857f70bec6SEric Joyner // so we already know it's setup when we get here. 11867f70bec6SEric Joyner 11877f70bec6SEric Joyner /* Shutdown admin queue */ 11887f70bec6SEric Joyner status = i40e_shutdown_adminq(hw); 11897f70bec6SEric Joyner if (status) 11907f70bec6SEric Joyner device_printf(dev, 11917f70bec6SEric Joyner "init: Admin Queue shutdown failure; status %d\n", status); 11927f70bec6SEric Joyner 11937f70bec6SEric Joyner err_out: 11947f70bec6SEric Joyner return (status); 11957f70bec6SEric Joyner } 11967f70bec6SEric Joyner 11977f70bec6SEric Joyner static int 11987f70bec6SEric Joyner ixl_reset(struct ixl_pf *pf) 11997f70bec6SEric Joyner { 12007f70bec6SEric Joyner struct i40e_hw *hw = &pf->hw; 12017f70bec6SEric Joyner device_t dev = pf->dev; 12027f70bec6SEric Joyner int error = 0; 12037f70bec6SEric Joyner 12047f70bec6SEric Joyner // XXX: clear_hw() actually writes to hw registers -- maybe this isn't necessary 12057f70bec6SEric Joyner i40e_clear_hw(hw); 12067f70bec6SEric Joyner error = i40e_pf_reset(hw); 12077f70bec6SEric Joyner if (error) { 12087f70bec6SEric Joyner device_printf(dev, "init: PF reset failure"); 12097f70bec6SEric Joyner error = EIO; 12107f70bec6SEric Joyner goto err_out; 12117f70bec6SEric Joyner } 12127f70bec6SEric Joyner 12137f70bec6SEric Joyner error = i40e_init_adminq(hw); 12147f70bec6SEric Joyner if (error) { 12157f70bec6SEric Joyner device_printf(dev, "init: Admin queue init failure; status code %d", error); 12167f70bec6SEric Joyner error = EIO; 12177f70bec6SEric Joyner goto err_out; 12187f70bec6SEric Joyner } 12197f70bec6SEric Joyner 12207f70bec6SEric Joyner i40e_clear_pxe_mode(hw); 12217f70bec6SEric Joyner 12227f70bec6SEric Joyner error = ixl_get_hw_capabilities(pf); 12237f70bec6SEric Joyner if (error) { 12247f70bec6SEric Joyner device_printf(dev, "init: Error retrieving HW capabilities; status code %d\n", error); 12257f70bec6SEric Joyner goto err_out; 12267f70bec6SEric Joyner } 12277f70bec6SEric Joyner 12287f70bec6SEric Joyner error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 12297f70bec6SEric Joyner hw->func_caps.num_rx_qp, 0, 0); 12307f70bec6SEric Joyner if (error) { 12317f70bec6SEric Joyner device_printf(dev, "init: LAN HMC init failed; status code %d\n", error); 12327f70bec6SEric Joyner error = EIO; 12337f70bec6SEric Joyner goto err_out; 12347f70bec6SEric Joyner } 12357f70bec6SEric Joyner 12367f70bec6SEric Joyner error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 12377f70bec6SEric Joyner if (error) { 12387f70bec6SEric Joyner device_printf(dev, "init: LAN HMC config failed; status code %d\n", error); 12397f70bec6SEric Joyner error = EIO; 12407f70bec6SEric Joyner goto err_out; 12417f70bec6SEric Joyner } 12427f70bec6SEric Joyner 12437f70bec6SEric Joyner // XXX: need to do switch config here? 12447f70bec6SEric Joyner 12457f70bec6SEric Joyner error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, 12467f70bec6SEric Joyner NULL); 12477f70bec6SEric Joyner if (error) { 12487f70bec6SEric Joyner device_printf(dev, "init: i40e_aq_set_phy_mask() failed: err %d," 12497f70bec6SEric Joyner " aq_err %d\n", error, hw->aq.asq_last_status); 12507f70bec6SEric Joyner error = EIO; 12517f70bec6SEric Joyner goto err_out; 12527f70bec6SEric Joyner } 12537f70bec6SEric Joyner 12547f70bec6SEric Joyner u8 set_fc_err_mask; 12557f70bec6SEric Joyner error = i40e_set_fc(hw, &set_fc_err_mask, true); 12567f70bec6SEric Joyner if (error) { 12577f70bec6SEric Joyner device_printf(dev, "init: setting link flow control failed; retcode %d," 12587f70bec6SEric Joyner " fc_err_mask 0x%02x\n", error, set_fc_err_mask); 12597f70bec6SEric Joyner goto err_out; 12607f70bec6SEric Joyner } 12617f70bec6SEric Joyner 12627f70bec6SEric Joyner // XXX: (Rebuild VSIs?) 12637f70bec6SEric Joyner 12647f70bec6SEric Joyner // Firmware delay workaround 12657f70bec6SEric Joyner if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 12667f70bec6SEric Joyner (hw->aq.fw_maj_ver < 4)) { 12677f70bec6SEric Joyner i40e_msec_delay(75); 12687f70bec6SEric Joyner error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 12697f70bec6SEric Joyner if (error) { 12707f70bec6SEric Joyner device_printf(dev, "init: link restart failed, aq_err %d\n", 12717f70bec6SEric Joyner hw->aq.asq_last_status); 12727f70bec6SEric Joyner goto err_out; 12737f70bec6SEric Joyner } 12747f70bec6SEric Joyner } 12757f70bec6SEric Joyner 12767f70bec6SEric Joyner // [add_filter_to_drop_tx_flow_control_frames] 12777f70bec6SEric Joyner // - TODO: Implement 12787f70bec6SEric Joyner 12797f70bec6SEric Joyner // i40e_send_version 12807f70bec6SEric Joyner // - TODO: Properly implement 12817f70bec6SEric Joyner struct i40e_driver_version dv; 12827f70bec6SEric Joyner 12837f70bec6SEric Joyner dv.major_version = 1; 12847f70bec6SEric Joyner dv.minor_version = 1; 12857f70bec6SEric Joyner dv.build_version = 1; 12867f70bec6SEric Joyner dv.subbuild_version = 0; 12877f70bec6SEric Joyner // put in a driver version string that is less than 0x80 bytes long 12887f70bec6SEric Joyner bzero(&dv.driver_string, sizeof(dv.driver_string)); 12897f70bec6SEric Joyner i40e_aq_send_driver_version(hw, &dv, NULL); 12907f70bec6SEric Joyner 12917f70bec6SEric Joyner err_out: 12927f70bec6SEric Joyner return (error); 12937f70bec6SEric Joyner } 12947f70bec6SEric Joyner 129561ae650dSJack F Vogel static void 129661ae650dSJack F Vogel ixl_init(void *arg) 129761ae650dSJack F Vogel { 129861ae650dSJack F Vogel struct ixl_pf *pf = arg; 1299223d846dSEric Joyner int ret = 0; 1300223d846dSEric Joyner 13017f70bec6SEric Joyner /* 13027f70bec6SEric Joyner * If the aq is dead here, it probably means something outside of the driver 13037f70bec6SEric Joyner * did something to the adapter, like a PF reset. 13047f70bec6SEric Joyner * So rebuild the driver's state here if that occurs. 13057f70bec6SEric Joyner */ 13067f70bec6SEric Joyner if (!i40e_check_asq_alive(&pf->hw)) { 13077f70bec6SEric Joyner device_printf(pf->dev, "asq is not alive; rebuilding...\n"); 13087f70bec6SEric Joyner IXL_PF_LOCK(pf); 13097f70bec6SEric Joyner ixl_teardown_hw_structs(pf); 13107f70bec6SEric Joyner ixl_reset(pf); 13117f70bec6SEric Joyner IXL_PF_UNLOCK(pf); 13127f70bec6SEric Joyner } 13137f70bec6SEric Joyner 1314223d846dSEric Joyner /* Set up interrupt routing here */ 1315223d846dSEric Joyner if (pf->msix > 1) 1316223d846dSEric Joyner ret = ixl_assign_vsi_msix(pf); 1317223d846dSEric Joyner else 1318223d846dSEric Joyner ret = ixl_assign_vsi_legacy(pf); 1319223d846dSEric Joyner if (ret) { 1320223d846dSEric Joyner device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", ret); 1321223d846dSEric Joyner return; 1322223d846dSEric Joyner } 132361ae650dSJack F Vogel 132461ae650dSJack F Vogel IXL_PF_LOCK(pf); 132561ae650dSJack F Vogel ixl_init_locked(pf); 132661ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 132761ae650dSJack F Vogel return; 132861ae650dSJack F Vogel } 132961ae650dSJack F Vogel 133061ae650dSJack F Vogel /* 133161ae650dSJack F Vogel ** 133261ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets 133361ae650dSJack F Vogel ** 133461ae650dSJack F Vogel */ 133561ae650dSJack F Vogel static void 133661ae650dSJack F Vogel ixl_handle_que(void *context, int pending) 133761ae650dSJack F Vogel { 133861ae650dSJack F Vogel struct ixl_queue *que = context; 133961ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 134061ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 134161ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 134261ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 134361ae650dSJack F Vogel bool more; 134461ae650dSJack F Vogel 134561ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 134661ae650dSJack F Vogel more = ixl_rxeof(que, IXL_RX_LIMIT); 134761ae650dSJack F Vogel IXL_TX_LOCK(txr); 134861ae650dSJack F Vogel ixl_txeof(que); 134961ae650dSJack F Vogel if (!drbr_empty(ifp, txr->br)) 135061ae650dSJack F Vogel ixl_mq_start_locked(ifp, txr); 135161ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 135261ae650dSJack F Vogel if (more) { 135361ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->task); 135461ae650dSJack F Vogel return; 135561ae650dSJack F Vogel } 135661ae650dSJack F Vogel } 135761ae650dSJack F Vogel 135861ae650dSJack F Vogel /* Reenable this interrupt - hmmm */ 135961ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 136061ae650dSJack F Vogel return; 136161ae650dSJack F Vogel } 136261ae650dSJack F Vogel 136361ae650dSJack F Vogel 136461ae650dSJack F Vogel /********************************************************************* 136561ae650dSJack F Vogel * 136661ae650dSJack F Vogel * Legacy Interrupt Service routine 136761ae650dSJack F Vogel * 136861ae650dSJack F Vogel **********************************************************************/ 136961ae650dSJack F Vogel void 137061ae650dSJack F Vogel ixl_intr(void *arg) 137161ae650dSJack F Vogel { 137261ae650dSJack F Vogel struct ixl_pf *pf = arg; 137361ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 137461ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 137561ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 137661ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 137761ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 137861ae650dSJack F Vogel u32 reg, icr0, mask; 137961ae650dSJack F Vogel bool more_tx, more_rx; 138061ae650dSJack F Vogel 138161ae650dSJack F Vogel ++que->irqs; 138261ae650dSJack F Vogel 138361ae650dSJack F Vogel /* Protect against spurious interrupts */ 138461ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 138561ae650dSJack F Vogel return; 138661ae650dSJack F Vogel 138761ae650dSJack F Vogel icr0 = rd32(hw, I40E_PFINT_ICR0); 138861ae650dSJack F Vogel 138961ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_DYN_CTL0); 139061ae650dSJack F Vogel reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 139161ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 139261ae650dSJack F Vogel 139361ae650dSJack F Vogel mask = rd32(hw, I40E_PFINT_ICR0_ENA); 139461ae650dSJack F Vogel 139556c2c47bSJack F Vogel #ifdef PCI_IOV 139656c2c47bSJack F Vogel if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) 139756c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->vflr_task); 139856c2c47bSJack F Vogel #endif 139956c2c47bSJack F Vogel 140061ae650dSJack F Vogel if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) { 140161ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 140261ae650dSJack F Vogel return; 140361ae650dSJack F Vogel } 140461ae650dSJack F Vogel 140561ae650dSJack F Vogel more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 140661ae650dSJack F Vogel 140761ae650dSJack F Vogel IXL_TX_LOCK(txr); 140861ae650dSJack F Vogel more_tx = ixl_txeof(que); 140961ae650dSJack F Vogel if (!drbr_empty(vsi->ifp, txr->br)) 141061ae650dSJack F Vogel more_tx = 1; 141161ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 141261ae650dSJack F Vogel 141361ae650dSJack F Vogel /* re-enable other interrupt causes */ 141461ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, mask); 141561ae650dSJack F Vogel 141661ae650dSJack F Vogel /* And now the queues */ 141761ae650dSJack F Vogel reg = rd32(hw, I40E_QINT_RQCTL(0)); 141861ae650dSJack F Vogel reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; 141961ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(0), reg); 142061ae650dSJack F Vogel 142161ae650dSJack F Vogel reg = rd32(hw, I40E_QINT_TQCTL(0)); 142261ae650dSJack F Vogel reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; 142361ae650dSJack F Vogel reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK; 142461ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(0), reg); 142561ae650dSJack F Vogel 142661ae650dSJack F Vogel ixl_enable_legacy(hw); 142761ae650dSJack F Vogel 142861ae650dSJack F Vogel return; 142961ae650dSJack F Vogel } 143061ae650dSJack F Vogel 143161ae650dSJack F Vogel 143261ae650dSJack F Vogel /********************************************************************* 143361ae650dSJack F Vogel * 143461ae650dSJack F Vogel * MSIX VSI Interrupt Service routine 143561ae650dSJack F Vogel * 143661ae650dSJack F Vogel **********************************************************************/ 143761ae650dSJack F Vogel void 143861ae650dSJack F Vogel ixl_msix_que(void *arg) 143961ae650dSJack F Vogel { 144061ae650dSJack F Vogel struct ixl_queue *que = arg; 144161ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 144261ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 144361ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 144461ae650dSJack F Vogel bool more_tx, more_rx; 144561ae650dSJack F Vogel 144661ae650dSJack F Vogel /* Protect against spurious interrupts */ 144761ae650dSJack F Vogel if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) 144861ae650dSJack F Vogel return; 144961ae650dSJack F Vogel 145061ae650dSJack F Vogel ++que->irqs; 145161ae650dSJack F Vogel 145261ae650dSJack F Vogel more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 145361ae650dSJack F Vogel 145461ae650dSJack F Vogel IXL_TX_LOCK(txr); 145561ae650dSJack F Vogel more_tx = ixl_txeof(que); 145661ae650dSJack F Vogel /* 145761ae650dSJack F Vogel ** Make certain that if the stack 145861ae650dSJack F Vogel ** has anything queued the task gets 145961ae650dSJack F Vogel ** scheduled to handle it. 146061ae650dSJack F Vogel */ 146161ae650dSJack F Vogel if (!drbr_empty(vsi->ifp, txr->br)) 146261ae650dSJack F Vogel more_tx = 1; 146361ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 146461ae650dSJack F Vogel 146561ae650dSJack F Vogel ixl_set_queue_rx_itr(que); 146661ae650dSJack F Vogel ixl_set_queue_tx_itr(que); 146761ae650dSJack F Vogel 146861ae650dSJack F Vogel if (more_tx || more_rx) 146961ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->task); 147061ae650dSJack F Vogel else 147161ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 147261ae650dSJack F Vogel 147361ae650dSJack F Vogel return; 147461ae650dSJack F Vogel } 147561ae650dSJack F Vogel 147661ae650dSJack F Vogel 147761ae650dSJack F Vogel /********************************************************************* 147861ae650dSJack F Vogel * 147961ae650dSJack F Vogel * MSIX Admin Queue Interrupt Service routine 148061ae650dSJack F Vogel * 148161ae650dSJack F Vogel **********************************************************************/ 148261ae650dSJack F Vogel static void 148361ae650dSJack F Vogel ixl_msix_adminq(void *arg) 148461ae650dSJack F Vogel { 148561ae650dSJack F Vogel struct ixl_pf *pf = arg; 148661ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 1487*fdb6f38aSEric Joyner u32 reg, mask, rstat_reg; 1488*fdb6f38aSEric Joyner bool do_task = FALSE; 148961ae650dSJack F Vogel 149061ae650dSJack F Vogel ++pf->admin_irq; 149161ae650dSJack F Vogel 149261ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0); 149361ae650dSJack F Vogel mask = rd32(hw, I40E_PFINT_ICR0_ENA); 149461ae650dSJack F Vogel 149561ae650dSJack F Vogel /* Check on the cause */ 1496*fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) { 1497*fdb6f38aSEric Joyner mask &= ~I40E_PFINT_ICR0_ADMINQ_MASK; 1498*fdb6f38aSEric Joyner do_task = TRUE; 1499*fdb6f38aSEric Joyner } 150061ae650dSJack F Vogel 150161ae650dSJack F Vogel if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) { 150261ae650dSJack F Vogel ixl_handle_mdd_event(pf); 1503*fdb6f38aSEric Joyner mask &= ~I40E_PFINT_ICR0_MAL_DETECT_MASK; 1504*fdb6f38aSEric Joyner } 1505*fdb6f38aSEric Joyner 1506*fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_GRST_MASK) { 1507*fdb6f38aSEric Joyner device_printf(pf->dev, "Reset Requested!\n"); 1508*fdb6f38aSEric Joyner rstat_reg = rd32(hw, I40E_GLGEN_RSTAT); 1509*fdb6f38aSEric Joyner rstat_reg = (rstat_reg & I40E_GLGEN_RSTAT_RESET_TYPE_MASK) 1510*fdb6f38aSEric Joyner >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT; 1511*fdb6f38aSEric Joyner device_printf(pf->dev, "Reset type: "); 1512*fdb6f38aSEric Joyner switch (rstat_reg) { 1513*fdb6f38aSEric Joyner /* These others might be handled similarly to an EMPR reset */ 1514*fdb6f38aSEric Joyner case I40E_RESET_CORER: 1515*fdb6f38aSEric Joyner printf("CORER\n"); 1516*fdb6f38aSEric Joyner break; 1517*fdb6f38aSEric Joyner case I40E_RESET_GLOBR: 1518*fdb6f38aSEric Joyner printf("GLOBR\n"); 1519*fdb6f38aSEric Joyner break; 1520*fdb6f38aSEric Joyner case I40E_RESET_EMPR: 1521*fdb6f38aSEric Joyner printf("EMPR\n"); 1522*fdb6f38aSEric Joyner atomic_set_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); 1523*fdb6f38aSEric Joyner break; 1524*fdb6f38aSEric Joyner default: 1525*fdb6f38aSEric Joyner printf("?\n"); 1526*fdb6f38aSEric Joyner break; 1527*fdb6f38aSEric Joyner } 1528*fdb6f38aSEric Joyner // overload admin queue task to check reset progress? 1529*fdb6f38aSEric Joyner do_task = TRUE; 1530*fdb6f38aSEric Joyner } 1531*fdb6f38aSEric Joyner 1532*fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_ECC_ERR_MASK) { 1533*fdb6f38aSEric Joyner device_printf(pf->dev, "ECC Error detected!\n"); 1534*fdb6f38aSEric Joyner } 1535*fdb6f38aSEric Joyner 1536*fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_HMC_ERR_MASK) { 1537*fdb6f38aSEric Joyner device_printf(pf->dev, "HMC Error detected!\n"); 1538*fdb6f38aSEric Joyner } 1539*fdb6f38aSEric Joyner 1540*fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) { 1541*fdb6f38aSEric Joyner device_printf(pf->dev, "PCI Exception detected!\n"); 154261ae650dSJack F Vogel } 154361ae650dSJack F Vogel 154456c2c47bSJack F Vogel #ifdef PCI_IOV 154556c2c47bSJack F Vogel if (reg & I40E_PFINT_ICR0_VFLR_MASK) { 154661ae650dSJack F Vogel mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; 154756c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->vflr_task); 154856c2c47bSJack F Vogel } 154956c2c47bSJack F Vogel #endif 155061ae650dSJack F Vogel 155161ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_DYN_CTL0); 155261ae650dSJack F Vogel reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 155361ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 155461ae650dSJack F Vogel 1555*fdb6f38aSEric Joyner if (do_task) 155661ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 155761ae650dSJack F Vogel } 155861ae650dSJack F Vogel 155961ae650dSJack F Vogel /********************************************************************* 156061ae650dSJack F Vogel * 156161ae650dSJack F Vogel * Media Ioctl callback 156261ae650dSJack F Vogel * 156361ae650dSJack F Vogel * This routine is called whenever the user queries the status of 156461ae650dSJack F Vogel * the interface using ifconfig. 156561ae650dSJack F Vogel * 156661ae650dSJack F Vogel **********************************************************************/ 156761ae650dSJack F Vogel static void 156861ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 156961ae650dSJack F Vogel { 157061ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 157156c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 157261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 157361ae650dSJack F Vogel 157461ae650dSJack F Vogel INIT_DEBUGOUT("ixl_media_status: begin"); 157561ae650dSJack F Vogel IXL_PF_LOCK(pf); 157661ae650dSJack F Vogel 157756c2c47bSJack F Vogel hw->phy.get_link_info = TRUE; 1578be771cdaSJack F Vogel i40e_get_link_status(hw, &pf->link_up); 157961ae650dSJack F Vogel ixl_update_link_status(pf); 158061ae650dSJack F Vogel 158161ae650dSJack F Vogel ifmr->ifm_status = IFM_AVALID; 158261ae650dSJack F Vogel ifmr->ifm_active = IFM_ETHER; 158361ae650dSJack F Vogel 158456c2c47bSJack F Vogel if (!pf->link_up) { 158561ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 158661ae650dSJack F Vogel return; 158761ae650dSJack F Vogel } 158861ae650dSJack F Vogel 158961ae650dSJack F Vogel ifmr->ifm_status |= IFM_ACTIVE; 1590ac83ea83SEric Joyner 1591ac83ea83SEric Joyner /* Hardware always does full-duplex */ 159261ae650dSJack F Vogel ifmr->ifm_active |= IFM_FDX; 159361ae650dSJack F Vogel 159461ae650dSJack F Vogel switch (hw->phy.link_info.phy_type) { 159561ae650dSJack F Vogel /* 100 M */ 159661ae650dSJack F Vogel case I40E_PHY_TYPE_100BASE_TX: 159761ae650dSJack F Vogel ifmr->ifm_active |= IFM_100_TX; 159861ae650dSJack F Vogel break; 159961ae650dSJack F Vogel /* 1 G */ 160061ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_T: 160161ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_T; 160261ae650dSJack F Vogel break; 160361ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_SX: 160461ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_SX; 160561ae650dSJack F Vogel break; 160661ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_LX: 160761ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_LX; 160861ae650dSJack F Vogel break; 160961ae650dSJack F Vogel /* 10 G */ 161061ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_SFPP_CU: 161161ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX; 161261ae650dSJack F Vogel break; 161361ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_SR: 161461ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_SR; 161561ae650dSJack F Vogel break; 161661ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_LR: 161761ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_LR; 161861ae650dSJack F Vogel break; 161961ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_T: 162061ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_T; 162161ae650dSJack F Vogel break; 162261ae650dSJack F Vogel /* 40 G */ 162361ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_CR4: 162461ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_CR4_CU: 162561ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_CR4; 162661ae650dSJack F Vogel break; 162761ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_SR4: 162861ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_SR4; 162961ae650dSJack F Vogel break; 163061ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_LR4: 163161ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_LR4; 163261ae650dSJack F Vogel break; 1633be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE 1634be771cdaSJack F Vogel case I40E_PHY_TYPE_1000BASE_KX: 1635be771cdaSJack F Vogel ifmr->ifm_active |= IFM_1000_CX; 1636b6c8f260SJack F Vogel break; 1637be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1_CU: 1638be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1: 1639be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX; 1640be771cdaSJack F Vogel break; 1641be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KX4: 1642be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_CX4; 1643be771cdaSJack F Vogel break; 1644be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KR: 1645be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_SR; 1646be771cdaSJack F Vogel break; 1647be771cdaSJack F Vogel case I40E_PHY_TYPE_40GBASE_KR4: 1648be771cdaSJack F Vogel case I40E_PHY_TYPE_XLPPI: 1649be771cdaSJack F Vogel ifmr->ifm_active |= IFM_40G_SR4; 1650be771cdaSJack F Vogel break; 1651be771cdaSJack F Vogel #else 1652be771cdaSJack F Vogel case I40E_PHY_TYPE_1000BASE_KX: 1653be771cdaSJack F Vogel ifmr->ifm_active |= IFM_1000_KX; 1654be771cdaSJack F Vogel break; 1655be771cdaSJack F Vogel /* ERJ: What's the difference between these? */ 1656be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1_CU: 1657be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1: 1658be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_CR1; 1659be771cdaSJack F Vogel break; 1660be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KX4: 1661be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_KX4; 1662be771cdaSJack F Vogel break; 1663be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KR: 1664be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_KR; 1665be771cdaSJack F Vogel break; 1666ac83ea83SEric Joyner /* Our single 20G media type */ 1667be771cdaSJack F Vogel case I40E_PHY_TYPE_20GBASE_KR2: 1668be771cdaSJack F Vogel ifmr->ifm_active |= IFM_20G_KR2; 1669be771cdaSJack F Vogel break; 1670be771cdaSJack F Vogel case I40E_PHY_TYPE_40GBASE_KR4: 1671be771cdaSJack F Vogel ifmr->ifm_active |= IFM_40G_KR4; 1672be771cdaSJack F Vogel break; 1673be771cdaSJack F Vogel case I40E_PHY_TYPE_XLPPI: 1674be771cdaSJack F Vogel ifmr->ifm_active |= IFM_40G_XLPPI; 1675be771cdaSJack F Vogel break; 1676be771cdaSJack F Vogel #endif 167761ae650dSJack F Vogel default: 167861ae650dSJack F Vogel ifmr->ifm_active |= IFM_UNKNOWN; 167961ae650dSJack F Vogel break; 168061ae650dSJack F Vogel } 168161ae650dSJack F Vogel /* Report flow control status as well */ 168261ae650dSJack F Vogel if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) 168361ae650dSJack F Vogel ifmr->ifm_active |= IFM_ETH_TXPAUSE; 168461ae650dSJack F Vogel if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) 168561ae650dSJack F Vogel ifmr->ifm_active |= IFM_ETH_RXPAUSE; 168661ae650dSJack F Vogel 168761ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 168861ae650dSJack F Vogel 168961ae650dSJack F Vogel return; 169061ae650dSJack F Vogel } 169161ae650dSJack F Vogel 1692ac83ea83SEric Joyner /* 1693ac83ea83SEric Joyner * NOTE: Fortville does not support forcing media speeds. Instead, 1694ac83ea83SEric Joyner * use the set_advertise sysctl to set the speeds Fortville 1695ac83ea83SEric Joyner * will advertise or be allowed to operate at. 1696ac83ea83SEric Joyner */ 169761ae650dSJack F Vogel static int 169861ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp) 169961ae650dSJack F Vogel { 170061ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 170161ae650dSJack F Vogel struct ifmedia *ifm = &vsi->media; 170261ae650dSJack F Vogel 170361ae650dSJack F Vogel INIT_DEBUGOUT("ixl_media_change: begin"); 170461ae650dSJack F Vogel 170561ae650dSJack F Vogel if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 170661ae650dSJack F Vogel return (EINVAL); 170761ae650dSJack F Vogel 1708ac83ea83SEric Joyner if_printf(ifp, "Media change is not supported.\n"); 170961ae650dSJack F Vogel 171061ae650dSJack F Vogel return (ENODEV); 171161ae650dSJack F Vogel } 171261ae650dSJack F Vogel 171361ae650dSJack F Vogel 171461ae650dSJack F Vogel #ifdef IXL_FDIR 171561ae650dSJack F Vogel /* 171661ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter 171761ae650dSJack F Vogel ** based on TX flow info that will keep the receive 171861ae650dSJack F Vogel ** portion of the flow on the same queue. Based on the 171961ae650dSJack F Vogel ** implementation this is only available for TCP connections 172061ae650dSJack F Vogel */ 172161ae650dSJack F Vogel void 172261ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype) 172361ae650dSJack F Vogel { 172461ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 172561ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 172661ae650dSJack F Vogel struct i40e_filter_program_desc *FDIR; 172761ae650dSJack F Vogel u32 ptype, dtype; 172861ae650dSJack F Vogel int idx; 172961ae650dSJack F Vogel 173061ae650dSJack F Vogel /* check if ATR is enabled and sample rate */ 173161ae650dSJack F Vogel if ((!ixl_enable_fdir) || (!txr->atr_rate)) 173261ae650dSJack F Vogel return; 173361ae650dSJack F Vogel /* 173461ae650dSJack F Vogel ** We sample all TCP SYN/FIN packets, 173561ae650dSJack F Vogel ** or at the selected sample rate 173661ae650dSJack F Vogel */ 173761ae650dSJack F Vogel txr->atr_count++; 173861ae650dSJack F Vogel if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) && 173961ae650dSJack F Vogel (txr->atr_count < txr->atr_rate)) 174061ae650dSJack F Vogel return; 174161ae650dSJack F Vogel txr->atr_count = 0; 174261ae650dSJack F Vogel 174361ae650dSJack F Vogel /* Get a descriptor to use */ 174461ae650dSJack F Vogel idx = txr->next_avail; 174561ae650dSJack F Vogel FDIR = (struct i40e_filter_program_desc *) &txr->base[idx]; 174661ae650dSJack F Vogel if (++idx == que->num_desc) 174761ae650dSJack F Vogel idx = 0; 174861ae650dSJack F Vogel txr->avail--; 174961ae650dSJack F Vogel txr->next_avail = idx; 175061ae650dSJack F Vogel 175161ae650dSJack F Vogel ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & 175261ae650dSJack F Vogel I40E_TXD_FLTR_QW0_QINDEX_MASK; 175361ae650dSJack F Vogel 175461ae650dSJack F Vogel ptype |= (etype == ETHERTYPE_IP) ? 175561ae650dSJack F Vogel (I40E_FILTER_PCTYPE_NONF_IPV4_TCP << 175661ae650dSJack F Vogel I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) : 175761ae650dSJack F Vogel (I40E_FILTER_PCTYPE_NONF_IPV6_TCP << 175861ae650dSJack F Vogel I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); 175961ae650dSJack F Vogel 176061ae650dSJack F Vogel ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT; 176161ae650dSJack F Vogel 176261ae650dSJack F Vogel dtype = I40E_TX_DESC_DTYPE_FILTER_PROG; 176361ae650dSJack F Vogel 176461ae650dSJack F Vogel /* 176561ae650dSJack F Vogel ** We use the TCP TH_FIN as a trigger to remove 176661ae650dSJack F Vogel ** the filter, otherwise its an update. 176761ae650dSJack F Vogel */ 176861ae650dSJack F Vogel dtype |= (th->th_flags & TH_FIN) ? 176961ae650dSJack F Vogel (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << 177061ae650dSJack F Vogel I40E_TXD_FLTR_QW1_PCMD_SHIFT) : 177161ae650dSJack F Vogel (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << 177261ae650dSJack F Vogel I40E_TXD_FLTR_QW1_PCMD_SHIFT); 177361ae650dSJack F Vogel 177461ae650dSJack F Vogel dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX << 177561ae650dSJack F Vogel I40E_TXD_FLTR_QW1_DEST_SHIFT; 177661ae650dSJack F Vogel 177761ae650dSJack F Vogel dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID << 177861ae650dSJack F Vogel I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT; 177961ae650dSJack F Vogel 178061ae650dSJack F Vogel FDIR->qindex_flex_ptype_vsi = htole32(ptype); 178161ae650dSJack F Vogel FDIR->dtype_cmd_cntindex = htole32(dtype); 178261ae650dSJack F Vogel return; 178361ae650dSJack F Vogel } 178461ae650dSJack F Vogel #endif 178561ae650dSJack F Vogel 178661ae650dSJack F Vogel 178761ae650dSJack F Vogel static void 178861ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi) 178961ae650dSJack F Vogel { 179061ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 179161ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 179261ae650dSJack F Vogel int err, mcnt = 0; 179361ae650dSJack F Vogel bool uni = FALSE, multi = FALSE; 179461ae650dSJack F Vogel 179561ae650dSJack F Vogel if (ifp->if_flags & IFF_ALLMULTI) 179661ae650dSJack F Vogel multi = TRUE; 179761ae650dSJack F Vogel else { /* Need to count the multicast addresses */ 179861ae650dSJack F Vogel struct ifmultiaddr *ifma; 179961ae650dSJack F Vogel if_maddr_rlock(ifp); 180061ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 180161ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 180261ae650dSJack F Vogel continue; 180361ae650dSJack F Vogel if (mcnt == MAX_MULTICAST_ADDR) 180461ae650dSJack F Vogel break; 180561ae650dSJack F Vogel mcnt++; 180661ae650dSJack F Vogel } 180761ae650dSJack F Vogel if_maddr_runlock(ifp); 180861ae650dSJack F Vogel } 180961ae650dSJack F Vogel 181061ae650dSJack F Vogel if (mcnt >= MAX_MULTICAST_ADDR) 181161ae650dSJack F Vogel multi = TRUE; 181261ae650dSJack F Vogel if (ifp->if_flags & IFF_PROMISC) 181361ae650dSJack F Vogel uni = TRUE; 181461ae650dSJack F Vogel 181561ae650dSJack F Vogel err = i40e_aq_set_vsi_unicast_promiscuous(hw, 181661ae650dSJack F Vogel vsi->seid, uni, NULL); 181761ae650dSJack F Vogel err = i40e_aq_set_vsi_multicast_promiscuous(hw, 181861ae650dSJack F Vogel vsi->seid, multi, NULL); 181961ae650dSJack F Vogel return; 182061ae650dSJack F Vogel } 182161ae650dSJack F Vogel 182261ae650dSJack F Vogel /********************************************************************* 182361ae650dSJack F Vogel * Filter Routines 182461ae650dSJack F Vogel * 182561ae650dSJack F Vogel * Routines for multicast and vlan filter management. 182661ae650dSJack F Vogel * 182761ae650dSJack F Vogel *********************************************************************/ 182861ae650dSJack F Vogel static void 182961ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi) 183061ae650dSJack F Vogel { 183161ae650dSJack F Vogel struct ifmultiaddr *ifma; 183261ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 183361ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 183461ae650dSJack F Vogel int mcnt = 0, flags; 183561ae650dSJack F Vogel 183661ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_add_multi: begin"); 183761ae650dSJack F Vogel 183861ae650dSJack F Vogel if_maddr_rlock(ifp); 183961ae650dSJack F Vogel /* 184061ae650dSJack F Vogel ** First just get a count, to decide if we 184161ae650dSJack F Vogel ** we simply use multicast promiscuous. 184261ae650dSJack F Vogel */ 184361ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 184461ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 184561ae650dSJack F Vogel continue; 184661ae650dSJack F Vogel mcnt++; 184761ae650dSJack F Vogel } 184861ae650dSJack F Vogel if_maddr_runlock(ifp); 184961ae650dSJack F Vogel 185061ae650dSJack F Vogel if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { 185161ae650dSJack F Vogel /* delete existing MC filters */ 185261ae650dSJack F Vogel ixl_del_hw_filters(vsi, mcnt); 185361ae650dSJack F Vogel i40e_aq_set_vsi_multicast_promiscuous(hw, 185461ae650dSJack F Vogel vsi->seid, TRUE, NULL); 185561ae650dSJack F Vogel return; 185661ae650dSJack F Vogel } 185761ae650dSJack F Vogel 185861ae650dSJack F Vogel mcnt = 0; 185961ae650dSJack F Vogel if_maddr_rlock(ifp); 186061ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 186161ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 186261ae650dSJack F Vogel continue; 186361ae650dSJack F Vogel ixl_add_mc_filter(vsi, 186461ae650dSJack F Vogel (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); 186561ae650dSJack F Vogel mcnt++; 186661ae650dSJack F Vogel } 186761ae650dSJack F Vogel if_maddr_runlock(ifp); 186861ae650dSJack F Vogel if (mcnt > 0) { 186961ae650dSJack F Vogel flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); 187061ae650dSJack F Vogel ixl_add_hw_filters(vsi, flags, mcnt); 187161ae650dSJack F Vogel } 187261ae650dSJack F Vogel 187361ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_add_multi: end"); 187461ae650dSJack F Vogel return; 187561ae650dSJack F Vogel } 187661ae650dSJack F Vogel 187761ae650dSJack F Vogel static void 187861ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi) 187961ae650dSJack F Vogel { 188061ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 188161ae650dSJack F Vogel struct ifmultiaddr *ifma; 188261ae650dSJack F Vogel struct ixl_mac_filter *f; 188361ae650dSJack F Vogel int mcnt = 0; 188461ae650dSJack F Vogel bool match = FALSE; 188561ae650dSJack F Vogel 188661ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_del_multi: begin"); 188761ae650dSJack F Vogel 188861ae650dSJack F Vogel /* Search for removed multicast addresses */ 188961ae650dSJack F Vogel if_maddr_rlock(ifp); 189061ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 189161ae650dSJack F Vogel if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) { 189261ae650dSJack F Vogel match = FALSE; 189361ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 189461ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 189561ae650dSJack F Vogel continue; 189661ae650dSJack F Vogel u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 189761ae650dSJack F Vogel if (cmp_etheraddr(f->macaddr, mc_addr)) { 189861ae650dSJack F Vogel match = TRUE; 189961ae650dSJack F Vogel break; 190061ae650dSJack F Vogel } 190161ae650dSJack F Vogel } 190261ae650dSJack F Vogel if (match == FALSE) { 190361ae650dSJack F Vogel f->flags |= IXL_FILTER_DEL; 190461ae650dSJack F Vogel mcnt++; 190561ae650dSJack F Vogel } 190661ae650dSJack F Vogel } 190761ae650dSJack F Vogel } 190861ae650dSJack F Vogel if_maddr_runlock(ifp); 190961ae650dSJack F Vogel 191061ae650dSJack F Vogel if (mcnt > 0) 191161ae650dSJack F Vogel ixl_del_hw_filters(vsi, mcnt); 191261ae650dSJack F Vogel } 191361ae650dSJack F Vogel 191461ae650dSJack F Vogel 191561ae650dSJack F Vogel /********************************************************************* 191661ae650dSJack F Vogel * Timer routine 191761ae650dSJack F Vogel * 191861ae650dSJack F Vogel * This routine checks for link status,updates statistics, 191961ae650dSJack F Vogel * and runs the watchdog check. 192061ae650dSJack F Vogel * 192161ae650dSJack F Vogel **********************************************************************/ 192261ae650dSJack F Vogel 192361ae650dSJack F Vogel static void 192461ae650dSJack F Vogel ixl_local_timer(void *arg) 192561ae650dSJack F Vogel { 192661ae650dSJack F Vogel struct ixl_pf *pf = arg; 192761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 192861ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 192961ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 193061ae650dSJack F Vogel device_t dev = pf->dev; 193161ae650dSJack F Vogel int hung = 0; 193261ae650dSJack F Vogel u32 mask; 193361ae650dSJack F Vogel 193461ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 193561ae650dSJack F Vogel 193661ae650dSJack F Vogel /* Fire off the adminq task */ 193761ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 193861ae650dSJack F Vogel 193961ae650dSJack F Vogel /* Update stats */ 194061ae650dSJack F Vogel ixl_update_stats_counters(pf); 194161ae650dSJack F Vogel 194261ae650dSJack F Vogel /* 194361ae650dSJack F Vogel ** Check status of the queues 194461ae650dSJack F Vogel */ 194561ae650dSJack F Vogel mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | 194661ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); 194761ae650dSJack F Vogel 194861ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++,que++) { 194961ae650dSJack F Vogel /* Any queues with outstanding work get a sw irq */ 195061ae650dSJack F Vogel if (que->busy) 195161ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask); 195261ae650dSJack F Vogel /* 195361ae650dSJack F Vogel ** Each time txeof runs without cleaning, but there 195461ae650dSJack F Vogel ** are uncleaned descriptors it increments busy. If 195561ae650dSJack F Vogel ** we get to 5 we declare it hung. 195661ae650dSJack F Vogel */ 195761ae650dSJack F Vogel if (que->busy == IXL_QUEUE_HUNG) { 195861ae650dSJack F Vogel ++hung; 195961ae650dSJack F Vogel /* Mark the queue as inactive */ 196061ae650dSJack F Vogel vsi->active_queues &= ~((u64)1 << que->me); 196161ae650dSJack F Vogel continue; 196261ae650dSJack F Vogel } else { 196361ae650dSJack F Vogel /* Check if we've come back from hung */ 196461ae650dSJack F Vogel if ((vsi->active_queues & ((u64)1 << que->me)) == 0) 196561ae650dSJack F Vogel vsi->active_queues |= ((u64)1 << que->me); 196661ae650dSJack F Vogel } 196761ae650dSJack F Vogel if (que->busy >= IXL_MAX_TX_BUSY) { 1968393c4bb1SJack F Vogel #ifdef IXL_DEBUG 196961ae650dSJack F Vogel device_printf(dev,"Warning queue %d " 197061ae650dSJack F Vogel "appears to be hung!\n", i); 1971393c4bb1SJack F Vogel #endif 197261ae650dSJack F Vogel que->busy = IXL_QUEUE_HUNG; 197361ae650dSJack F Vogel ++hung; 197461ae650dSJack F Vogel } 197561ae650dSJack F Vogel } 197661ae650dSJack F Vogel /* Only reinit if all queues show hung */ 197761ae650dSJack F Vogel if (hung == vsi->num_queues) 197861ae650dSJack F Vogel goto hung; 197961ae650dSJack F Vogel 198061ae650dSJack F Vogel callout_reset(&pf->timer, hz, ixl_local_timer, pf); 198161ae650dSJack F Vogel return; 198261ae650dSJack F Vogel 198361ae650dSJack F Vogel hung: 198461ae650dSJack F Vogel device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n"); 198561ae650dSJack F Vogel ixl_init_locked(pf); 198661ae650dSJack F Vogel } 198761ae650dSJack F Vogel 198861ae650dSJack F Vogel /* 198961ae650dSJack F Vogel ** Note: this routine updates the OS on the link state 199061ae650dSJack F Vogel ** the real check of the hardware only happens with 199161ae650dSJack F Vogel ** a link interrupt. 199261ae650dSJack F Vogel */ 199361ae650dSJack F Vogel static void 199461ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf) 199561ae650dSJack F Vogel { 199661ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 199761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 199861ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 199961ae650dSJack F Vogel device_t dev = pf->dev; 200061ae650dSJack F Vogel 200156c2c47bSJack F Vogel if (pf->link_up) { 200261ae650dSJack F Vogel if (vsi->link_active == FALSE) { 2003b6c8f260SJack F Vogel pf->fc = hw->fc.current_mode; 200461ae650dSJack F Vogel if (bootverbose) { 200561ae650dSJack F Vogel device_printf(dev,"Link is up %d Gbps %s," 200661ae650dSJack F Vogel " Flow Control: %s\n", 200756c2c47bSJack F Vogel ((pf->link_speed == 200856c2c47bSJack F Vogel I40E_LINK_SPEED_40GB)? 40:10), 2009b6c8f260SJack F Vogel "Full Duplex", ixl_fc_string[pf->fc]); 201061ae650dSJack F Vogel } 201161ae650dSJack F Vogel vsi->link_active = TRUE; 2012393c4bb1SJack F Vogel /* 2013393c4bb1SJack F Vogel ** Warn user if link speed on NPAR enabled 2014393c4bb1SJack F Vogel ** partition is not at least 10GB 2015393c4bb1SJack F Vogel */ 2016393c4bb1SJack F Vogel if (hw->func_caps.npar_enable && 201756c2c47bSJack F Vogel (hw->phy.link_info.link_speed == 201856c2c47bSJack F Vogel I40E_LINK_SPEED_1GB || 201956c2c47bSJack F Vogel hw->phy.link_info.link_speed == 202056c2c47bSJack F Vogel I40E_LINK_SPEED_100MB)) 202156c2c47bSJack F Vogel device_printf(dev, "The partition detected" 202256c2c47bSJack F Vogel "link speed that is less than 10Gbps\n"); 202361ae650dSJack F Vogel if_link_state_change(ifp, LINK_STATE_UP); 202461ae650dSJack F Vogel } 202561ae650dSJack F Vogel } else { /* Link down */ 202661ae650dSJack F Vogel if (vsi->link_active == TRUE) { 202761ae650dSJack F Vogel if (bootverbose) 202861ae650dSJack F Vogel device_printf(dev, "Link is Down\n"); 202961ae650dSJack F Vogel if_link_state_change(ifp, LINK_STATE_DOWN); 203061ae650dSJack F Vogel vsi->link_active = FALSE; 203161ae650dSJack F Vogel } 203261ae650dSJack F Vogel } 203361ae650dSJack F Vogel 203461ae650dSJack F Vogel return; 203561ae650dSJack F Vogel } 203661ae650dSJack F Vogel 2037223d846dSEric Joyner static void 2038223d846dSEric Joyner ixl_stop(struct ixl_pf *pf) 2039223d846dSEric Joyner { 2040223d846dSEric Joyner IXL_PF_LOCK(pf); 2041223d846dSEric Joyner ixl_stop_locked(pf); 2042223d846dSEric Joyner IXL_PF_UNLOCK(pf); 2043223d846dSEric Joyner 2044223d846dSEric Joyner ixl_free_interrupt_resources(pf); 2045223d846dSEric Joyner } 2046223d846dSEric Joyner 204761ae650dSJack F Vogel /********************************************************************* 204861ae650dSJack F Vogel * 204961ae650dSJack F Vogel * This routine disables all traffic on the adapter by issuing a 205061ae650dSJack F Vogel * global reset on the MAC and deallocates TX/RX buffers. 205161ae650dSJack F Vogel * 205261ae650dSJack F Vogel **********************************************************************/ 205361ae650dSJack F Vogel 205461ae650dSJack F Vogel static void 2055223d846dSEric Joyner ixl_stop_locked(struct ixl_pf *pf) 205661ae650dSJack F Vogel { 205761ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 205861ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 205961ae650dSJack F Vogel 206061ae650dSJack F Vogel INIT_DEBUGOUT("ixl_stop: begin\n"); 2061223d846dSEric Joyner 2062223d846dSEric Joyner IXL_PF_LOCK_ASSERT(pf); 2063223d846dSEric Joyner 2064223d846dSEric Joyner /* Stop the local timer */ 2065223d846dSEric Joyner callout_stop(&pf->timer); 2066223d846dSEric Joyner 206756c2c47bSJack F Vogel if (pf->num_vfs == 0) 206861ae650dSJack F Vogel ixl_disable_intr(vsi); 206956c2c47bSJack F Vogel else 207056c2c47bSJack F Vogel ixl_disable_rings_intr(vsi); 207161ae650dSJack F Vogel ixl_disable_rings(vsi); 207261ae650dSJack F Vogel 207361ae650dSJack F Vogel /* Tell the stack that the interface is no longer active */ 207461ae650dSJack F Vogel ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 207561ae650dSJack F Vogel 207661ae650dSJack F Vogel return; 207761ae650dSJack F Vogel } 207861ae650dSJack F Vogel 207961ae650dSJack F Vogel 208061ae650dSJack F Vogel /********************************************************************* 208161ae650dSJack F Vogel * 208261ae650dSJack F Vogel * Setup MSIX Interrupt resources and handlers for the VSI 208361ae650dSJack F Vogel * 208461ae650dSJack F Vogel **********************************************************************/ 208561ae650dSJack F Vogel static int 208661ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf) 208761ae650dSJack F Vogel { 208861ae650dSJack F Vogel device_t dev = pf->dev; 208961ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 209061ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 209161ae650dSJack F Vogel int error, rid = 0; 209261ae650dSJack F Vogel 209361ae650dSJack F Vogel if (pf->msix == 1) 209461ae650dSJack F Vogel rid = 1; 209561ae650dSJack F Vogel pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 209661ae650dSJack F Vogel &rid, RF_SHAREABLE | RF_ACTIVE); 209761ae650dSJack F Vogel if (pf->res == NULL) { 209861ae650dSJack F Vogel device_printf(dev, "Unable to allocate" 209961ae650dSJack F Vogel " bus resource: vsi legacy/msi interrupt\n"); 210061ae650dSJack F Vogel return (ENXIO); 210161ae650dSJack F Vogel } 210261ae650dSJack F Vogel 210361ae650dSJack F Vogel /* Set the handler function */ 210461ae650dSJack F Vogel error = bus_setup_intr(dev, pf->res, 210561ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 210661ae650dSJack F Vogel ixl_intr, pf, &pf->tag); 210761ae650dSJack F Vogel if (error) { 210861ae650dSJack F Vogel pf->res = NULL; 210961ae650dSJack F Vogel device_printf(dev, "Failed to register legacy/msi handler"); 211061ae650dSJack F Vogel return (error); 211161ae650dSJack F Vogel } 211261ae650dSJack F Vogel bus_describe_intr(dev, pf->res, pf->tag, "irq0"); 211361ae650dSJack F Vogel TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 211461ae650dSJack F Vogel TASK_INIT(&que->task, 0, ixl_handle_que, que); 211561ae650dSJack F Vogel que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 211661ae650dSJack F Vogel taskqueue_thread_enqueue, &que->tq); 211761ae650dSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 211861ae650dSJack F Vogel device_get_nameunit(dev)); 211961ae650dSJack F Vogel TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 212056c2c47bSJack F Vogel 212156c2c47bSJack F Vogel #ifdef PCI_IOV 212256c2c47bSJack F Vogel TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf); 212356c2c47bSJack F Vogel #endif 212456c2c47bSJack F Vogel 212561ae650dSJack F Vogel pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 212661ae650dSJack F Vogel taskqueue_thread_enqueue, &pf->tq); 212761ae650dSJack F Vogel taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 212861ae650dSJack F Vogel device_get_nameunit(dev)); 212961ae650dSJack F Vogel 213061ae650dSJack F Vogel return (0); 213161ae650dSJack F Vogel } 213261ae650dSJack F Vogel 2133a48d00d2SEric Joyner static void 2134a48d00d2SEric Joyner ixl_init_taskqueues(struct ixl_pf *pf) 2135a48d00d2SEric Joyner { 2136a48d00d2SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 2137a48d00d2SEric Joyner struct ixl_queue *que = vsi->queues; 2138a48d00d2SEric Joyner device_t dev = pf->dev; 2139a48d00d2SEric Joyner 2140a48d00d2SEric Joyner /* Tasklet for Admin Queue */ 2141a48d00d2SEric Joyner TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 2142a48d00d2SEric Joyner #ifdef PCI_IOV 2143a48d00d2SEric Joyner /* VFLR Tasklet */ 2144a48d00d2SEric Joyner TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf); 2145a48d00d2SEric Joyner #endif 2146a48d00d2SEric Joyner 2147a48d00d2SEric Joyner /* Create and start PF taskqueue */ 2148a48d00d2SEric Joyner pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 2149a48d00d2SEric Joyner taskqueue_thread_enqueue, &pf->tq); 2150a48d00d2SEric Joyner taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 2151a48d00d2SEric Joyner device_get_nameunit(dev)); 2152a48d00d2SEric Joyner 2153a48d00d2SEric Joyner /* Create queue tasks and start queue taskqueues */ 2154a48d00d2SEric Joyner for (int i = 0; i < vsi->num_queues; i++, que++) { 2155a48d00d2SEric Joyner TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 2156a48d00d2SEric Joyner TASK_INIT(&que->task, 0, ixl_handle_que, que); 2157a48d00d2SEric Joyner que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 2158a48d00d2SEric Joyner taskqueue_thread_enqueue, &que->tq); 2159a48d00d2SEric Joyner #ifdef RSS 2160a48d00d2SEric Joyner CPU_SETOF(cpu_id, &cpu_mask); 2161a48d00d2SEric Joyner taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, 2162a48d00d2SEric Joyner &cpu_mask, "%s (bucket %d)", 2163a48d00d2SEric Joyner device_get_nameunit(dev), cpu_id); 2164a48d00d2SEric Joyner #else 2165a48d00d2SEric Joyner taskqueue_start_threads(&que->tq, 1, PI_NET, 2166a48d00d2SEric Joyner "%s (que %d)", device_get_nameunit(dev), que->me); 2167a48d00d2SEric Joyner #endif 2168a48d00d2SEric Joyner } 2169a48d00d2SEric Joyner 2170a48d00d2SEric Joyner } 2171a48d00d2SEric Joyner 2172a48d00d2SEric Joyner static void 2173a48d00d2SEric Joyner ixl_free_taskqueues(struct ixl_pf *pf) 2174a48d00d2SEric Joyner { 2175a48d00d2SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 2176a48d00d2SEric Joyner struct ixl_queue *que = vsi->queues; 2177a48d00d2SEric Joyner 2178a48d00d2SEric Joyner if (pf->tq) 2179a48d00d2SEric Joyner taskqueue_free(pf->tq); 2180a48d00d2SEric Joyner for (int i = 0; i < vsi->num_queues; i++, que++) { 2181a48d00d2SEric Joyner if (que->tq) 2182a48d00d2SEric Joyner taskqueue_free(que->tq); 2183a48d00d2SEric Joyner } 2184a48d00d2SEric Joyner } 218561ae650dSJack F Vogel 218661ae650dSJack F Vogel /********************************************************************* 218761ae650dSJack F Vogel * 218861ae650dSJack F Vogel * Setup MSIX Interrupt resources and handlers for the VSI 218961ae650dSJack F Vogel * 219061ae650dSJack F Vogel **********************************************************************/ 219161ae650dSJack F Vogel static int 219261ae650dSJack F Vogel ixl_assign_vsi_msix(struct ixl_pf *pf) 219361ae650dSJack F Vogel { 219461ae650dSJack F Vogel device_t dev = pf->dev; 219561ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 219661ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 219761ae650dSJack F Vogel struct tx_ring *txr; 219861ae650dSJack F Vogel int error, rid, vector = 0; 2199ac83ea83SEric Joyner #ifdef RSS 2200ac83ea83SEric Joyner cpuset_t cpu_mask; 2201ac83ea83SEric Joyner #endif 220261ae650dSJack F Vogel 2203a48d00d2SEric Joyner /* Admin Queue interrupt vector is 0 */ 220461ae650dSJack F Vogel rid = vector + 1; 220561ae650dSJack F Vogel pf->res = bus_alloc_resource_any(dev, 220661ae650dSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 220761ae650dSJack F Vogel if (!pf->res) { 220861ae650dSJack F Vogel device_printf(dev, "Unable to allocate" 2209a48d00d2SEric Joyner " bus resource: Adminq interrupt [rid=%d]\n", rid); 221061ae650dSJack F Vogel return (ENXIO); 221161ae650dSJack F Vogel } 221261ae650dSJack F Vogel /* Set the adminq vector and handler */ 221361ae650dSJack F Vogel error = bus_setup_intr(dev, pf->res, 221461ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 221561ae650dSJack F Vogel ixl_msix_adminq, pf, &pf->tag); 221661ae650dSJack F Vogel if (error) { 221761ae650dSJack F Vogel pf->res = NULL; 221861ae650dSJack F Vogel device_printf(dev, "Failed to register Admin que handler"); 221961ae650dSJack F Vogel return (error); 222061ae650dSJack F Vogel } 222161ae650dSJack F Vogel bus_describe_intr(dev, pf->res, pf->tag, "aq"); 222261ae650dSJack F Vogel pf->admvec = vector; 222361ae650dSJack F Vogel ++vector; 222461ae650dSJack F Vogel 222561ae650dSJack F Vogel /* Now set up the stations */ 222661ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { 2227393c4bb1SJack F Vogel int cpu_id = i; 222861ae650dSJack F Vogel rid = vector + 1; 222961ae650dSJack F Vogel txr = &que->txr; 223061ae650dSJack F Vogel que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 223161ae650dSJack F Vogel RF_SHAREABLE | RF_ACTIVE); 223261ae650dSJack F Vogel if (que->res == NULL) { 223361ae650dSJack F Vogel device_printf(dev, "Unable to allocate" 2234a48d00d2SEric Joyner " bus resource: que interrupt [rid=%d]\n", rid); 223561ae650dSJack F Vogel return (ENXIO); 223661ae650dSJack F Vogel } 223761ae650dSJack F Vogel /* Set the handler function */ 223861ae650dSJack F Vogel error = bus_setup_intr(dev, que->res, 223961ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 224061ae650dSJack F Vogel ixl_msix_que, que, &que->tag); 224161ae650dSJack F Vogel if (error) { 224261ae650dSJack F Vogel que->res = NULL; 224361ae650dSJack F Vogel device_printf(dev, "Failed to register que handler"); 224461ae650dSJack F Vogel return (error); 224561ae650dSJack F Vogel } 2246a48d00d2SEric Joyner bus_describe_intr(dev, que->res, que->tag, "que%d", i); 224761ae650dSJack F Vogel /* Bind the vector to a CPU */ 2248393c4bb1SJack F Vogel #ifdef RSS 2249393c4bb1SJack F Vogel cpu_id = rss_getcpu(i % rss_getnumbuckets()); 2250393c4bb1SJack F Vogel #endif 2251393c4bb1SJack F Vogel bus_bind_intr(dev, que->res, cpu_id); 225261ae650dSJack F Vogel que->msix = vector; 225361ae650dSJack F Vogel } 225461ae650dSJack F Vogel 225561ae650dSJack F Vogel return (0); 225661ae650dSJack F Vogel } 225761ae650dSJack F Vogel 225861ae650dSJack F Vogel 225961ae650dSJack F Vogel /* 226061ae650dSJack F Vogel * Allocate MSI/X vectors 226161ae650dSJack F Vogel */ 226261ae650dSJack F Vogel static int 226361ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf) 226461ae650dSJack F Vogel { 226561ae650dSJack F Vogel device_t dev = pf->dev; 226661ae650dSJack F Vogel int rid, want, vectors, queues, available; 226761ae650dSJack F Vogel 226861ae650dSJack F Vogel /* Override by tuneable */ 226961ae650dSJack F Vogel if (ixl_enable_msix == 0) 227061ae650dSJack F Vogel goto msi; 227161ae650dSJack F Vogel 227261ae650dSJack F Vogel /* 227361ae650dSJack F Vogel ** When used in a virtualized environment 227461ae650dSJack F Vogel ** PCI BUSMASTER capability may not be set 227561ae650dSJack F Vogel ** so explicity set it here and rewrite 227661ae650dSJack F Vogel ** the ENABLE in the MSIX control register 227761ae650dSJack F Vogel ** at this point to cause the host to 227861ae650dSJack F Vogel ** successfully initialize us. 227961ae650dSJack F Vogel */ 228061ae650dSJack F Vogel { 228161ae650dSJack F Vogel u16 pci_cmd_word; 228261ae650dSJack F Vogel int msix_ctrl; 228361ae650dSJack F Vogel pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); 228461ae650dSJack F Vogel pci_cmd_word |= PCIM_CMD_BUSMASTEREN; 228561ae650dSJack F Vogel pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); 228661ae650dSJack F Vogel pci_find_cap(dev, PCIY_MSIX, &rid); 228761ae650dSJack F Vogel rid += PCIR_MSIX_CTRL; 228861ae650dSJack F Vogel msix_ctrl = pci_read_config(dev, rid, 2); 228961ae650dSJack F Vogel msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; 229061ae650dSJack F Vogel pci_write_config(dev, rid, msix_ctrl, 2); 229161ae650dSJack F Vogel } 229261ae650dSJack F Vogel 229361ae650dSJack F Vogel /* First try MSI/X */ 229461ae650dSJack F Vogel rid = PCIR_BAR(IXL_BAR); 229561ae650dSJack F Vogel pf->msix_mem = bus_alloc_resource_any(dev, 229661ae650dSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 229761ae650dSJack F Vogel if (!pf->msix_mem) { 229861ae650dSJack F Vogel /* May not be enabled */ 229961ae650dSJack F Vogel device_printf(pf->dev, 230061ae650dSJack F Vogel "Unable to map MSIX table\n"); 230161ae650dSJack F Vogel goto msi; 230261ae650dSJack F Vogel } 230361ae650dSJack F Vogel 230461ae650dSJack F Vogel available = pci_msix_count(dev); 230561ae650dSJack F Vogel if (available == 0) { /* system has msix disabled */ 230661ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 230761ae650dSJack F Vogel rid, pf->msix_mem); 230861ae650dSJack F Vogel pf->msix_mem = NULL; 230961ae650dSJack F Vogel goto msi; 231061ae650dSJack F Vogel } 231161ae650dSJack F Vogel 231261ae650dSJack F Vogel /* Figure out a reasonable auto config value */ 231361ae650dSJack F Vogel queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus; 231461ae650dSJack F Vogel 2315a48d00d2SEric Joyner /* Override with hardcoded value if it's less than autoconfig count */ 231661ae650dSJack F Vogel if ((ixl_max_queues != 0) && (ixl_max_queues <= queues)) 231761ae650dSJack F Vogel queues = ixl_max_queues; 2318a48d00d2SEric Joyner else if ((ixl_max_queues != 0) && (ixl_max_queues > queues)) 2319a48d00d2SEric Joyner device_printf(dev, "ixl_max_queues > # of cpus, using " 2320a48d00d2SEric Joyner "autoconfig amount...\n"); 2321a48d00d2SEric Joyner /* Or limit maximum auto-configured queues to 8 */ 2322a48d00d2SEric Joyner else if ((ixl_max_queues == 0) && (queues > 8)) 2323a48d00d2SEric Joyner queues = 8; 232461ae650dSJack F Vogel 2325393c4bb1SJack F Vogel #ifdef RSS 2326393c4bb1SJack F Vogel /* If we're doing RSS, clamp at the number of RSS buckets */ 2327393c4bb1SJack F Vogel if (queues > rss_getnumbuckets()) 2328393c4bb1SJack F Vogel queues = rss_getnumbuckets(); 2329393c4bb1SJack F Vogel #endif 2330393c4bb1SJack F Vogel 233161ae650dSJack F Vogel /* 233261ae650dSJack F Vogel ** Want one vector (RX/TX pair) per queue 233361ae650dSJack F Vogel ** plus an additional for the admin queue. 233461ae650dSJack F Vogel */ 233561ae650dSJack F Vogel want = queues + 1; 233661ae650dSJack F Vogel if (want <= available) /* Have enough */ 233761ae650dSJack F Vogel vectors = want; 233861ae650dSJack F Vogel else { 233961ae650dSJack F Vogel device_printf(pf->dev, 234061ae650dSJack F Vogel "MSIX Configuration Problem, " 234161ae650dSJack F Vogel "%d vectors available but %d wanted!\n", 234261ae650dSJack F Vogel available, want); 234361ae650dSJack F Vogel return (0); /* Will go to Legacy setup */ 234461ae650dSJack F Vogel } 234561ae650dSJack F Vogel 234661ae650dSJack F Vogel if (pci_alloc_msix(dev, &vectors) == 0) { 234761ae650dSJack F Vogel device_printf(pf->dev, 234861ae650dSJack F Vogel "Using MSIX interrupts with %d vectors\n", vectors); 234961ae650dSJack F Vogel pf->msix = vectors; 235061ae650dSJack F Vogel pf->vsi.num_queues = queues; 2351393c4bb1SJack F Vogel #ifdef RSS 2352393c4bb1SJack F Vogel /* 2353393c4bb1SJack F Vogel * If we're doing RSS, the number of queues needs to 2354393c4bb1SJack F Vogel * match the number of RSS buckets that are configured. 2355393c4bb1SJack F Vogel * 2356393c4bb1SJack F Vogel * + If there's more queues than RSS buckets, we'll end 2357393c4bb1SJack F Vogel * up with queues that get no traffic. 2358393c4bb1SJack F Vogel * 2359393c4bb1SJack F Vogel * + If there's more RSS buckets than queues, we'll end 2360393c4bb1SJack F Vogel * up having multiple RSS buckets map to the same queue, 2361393c4bb1SJack F Vogel * so there'll be some contention. 2362393c4bb1SJack F Vogel */ 2363393c4bb1SJack F Vogel if (queues != rss_getnumbuckets()) { 2364393c4bb1SJack F Vogel device_printf(dev, 2365393c4bb1SJack F Vogel "%s: queues (%d) != RSS buckets (%d)" 2366393c4bb1SJack F Vogel "; performance will be impacted.\n", 2367393c4bb1SJack F Vogel __func__, queues, rss_getnumbuckets()); 2368393c4bb1SJack F Vogel } 2369393c4bb1SJack F Vogel #endif 237061ae650dSJack F Vogel return (vectors); 237161ae650dSJack F Vogel } 237261ae650dSJack F Vogel msi: 237361ae650dSJack F Vogel vectors = pci_msi_count(dev); 237461ae650dSJack F Vogel pf->vsi.num_queues = 1; 237561ae650dSJack F Vogel pf->msix = 1; 237661ae650dSJack F Vogel ixl_max_queues = 1; 237761ae650dSJack F Vogel ixl_enable_msix = 0; 237861ae650dSJack F Vogel if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) 237961ae650dSJack F Vogel device_printf(pf->dev, "Using an MSI interrupt\n"); 238061ae650dSJack F Vogel else { 238161ae650dSJack F Vogel pf->msix = 0; 238261ae650dSJack F Vogel device_printf(pf->dev, "Using a Legacy interrupt\n"); 238361ae650dSJack F Vogel } 238461ae650dSJack F Vogel return (vectors); 238561ae650dSJack F Vogel } 238661ae650dSJack F Vogel 238761ae650dSJack F Vogel 238861ae650dSJack F Vogel /* 2389223d846dSEric Joyner * Plumb MSIX vectors 239061ae650dSJack F Vogel */ 239161ae650dSJack F Vogel static void 239261ae650dSJack F Vogel ixl_configure_msix(struct ixl_pf *pf) 239361ae650dSJack F Vogel { 239461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 239561ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 239661ae650dSJack F Vogel u32 reg; 239761ae650dSJack F Vogel u16 vector = 1; 239861ae650dSJack F Vogel 239961ae650dSJack F Vogel /* First set up the adminq - vector 0 */ 240061ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, 0); /* disable all */ 240161ae650dSJack F Vogel rd32(hw, I40E_PFINT_ICR0); /* read to clear */ 240261ae650dSJack F Vogel 240361ae650dSJack F Vogel reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | 240461ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_GRST_MASK | 2405*fdb6f38aSEric Joyner I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | 240661ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_ADMINQ_MASK | 240761ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK | 240861ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_VFLR_MASK | 240961ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK; 241061ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 241161ae650dSJack F Vogel 2412223d846dSEric Joyner /* 2413223d846dSEric Joyner * 0x7FF is the end of the queue list. 2414223d846dSEric Joyner * This means we won't use MSI-X vector 0 for a queue interrupt 2415223d846dSEric Joyner * in MSIX mode. 2416223d846dSEric Joyner */ 241761ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLST0, 0x7FF); 2418223d846dSEric Joyner /* Value is in 2 usec units, so 0x3E is 62*2 = 124 usecs. */ 2419223d846dSEric Joyner wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x3E); 242061ae650dSJack F Vogel 242161ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, 242261ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK | 242361ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK); 242461ae650dSJack F Vogel 242561ae650dSJack F Vogel wr32(hw, I40E_PFINT_STAT_CTL0, 0); 242661ae650dSJack F Vogel 242761ae650dSJack F Vogel /* Next configure the queues */ 242861ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, vector++) { 2429ac83ea83SEric Joyner wr32(hw, I40E_PFINT_DYN_CTLN(i), i); 243061ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLSTN(i), i); 243161ae650dSJack F Vogel 243261ae650dSJack F Vogel reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | 243361ae650dSJack F Vogel (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | 243461ae650dSJack F Vogel (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 243561ae650dSJack F Vogel (i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 243661ae650dSJack F Vogel (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); 243761ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(i), reg); 243861ae650dSJack F Vogel 243961ae650dSJack F Vogel reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK | 244061ae650dSJack F Vogel (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | 244161ae650dSJack F Vogel (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | 2442ac83ea83SEric Joyner ((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | 244361ae650dSJack F Vogel (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 2444ac83ea83SEric Joyner if (i == (vsi->num_queues - 1)) 2445ac83ea83SEric Joyner reg |= (IXL_QUEUE_EOL 2446ac83ea83SEric Joyner << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 244761ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(i), reg); 244861ae650dSJack F Vogel } 244961ae650dSJack F Vogel } 245061ae650dSJack F Vogel 245161ae650dSJack F Vogel /* 245261ae650dSJack F Vogel * Configure for MSI single vector operation 245361ae650dSJack F Vogel */ 245461ae650dSJack F Vogel static void 245561ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf) 245661ae650dSJack F Vogel { 245761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 245861ae650dSJack F Vogel u32 reg; 245961ae650dSJack F Vogel 246061ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(0), 0); 246161ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(1), 0); 246261ae650dSJack F Vogel 246361ae650dSJack F Vogel /* Setup "other" causes */ 246461ae650dSJack F Vogel reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK 246561ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK 246661ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_GRST_MASK 246761ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK 246861ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_GPIO_MASK 246961ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK 247061ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK 247161ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK 247261ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_VFLR_MASK 247361ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_ADMINQ_MASK 247461ae650dSJack F Vogel ; 247561ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 247661ae650dSJack F Vogel 247761ae650dSJack F Vogel /* SW_ITR_IDX = 0, but don't change INTENA */ 247861ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, 247961ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK | 248061ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK); 248161ae650dSJack F Vogel /* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */ 248261ae650dSJack F Vogel wr32(hw, I40E_PFINT_STAT_CTL0, 0); 248361ae650dSJack F Vogel 248461ae650dSJack F Vogel /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ 248561ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLST0, 0); 248661ae650dSJack F Vogel 248761ae650dSJack F Vogel /* Associate the queue pair to the vector and enable the q int */ 248861ae650dSJack F Vogel reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK 248961ae650dSJack F Vogel | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) 249061ae650dSJack F Vogel | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 249161ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(0), reg); 249261ae650dSJack F Vogel 249361ae650dSJack F Vogel reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK 249461ae650dSJack F Vogel | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) 249561ae650dSJack F Vogel | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 249661ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(0), reg); 249761ae650dSJack F Vogel 249861ae650dSJack F Vogel /* Next enable the queue pair */ 249961ae650dSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(0)); 250061ae650dSJack F Vogel reg |= I40E_QTX_ENA_QENA_REQ_MASK; 250161ae650dSJack F Vogel wr32(hw, I40E_QTX_ENA(0), reg); 250261ae650dSJack F Vogel 250361ae650dSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(0)); 250461ae650dSJack F Vogel reg |= I40E_QRX_ENA_QENA_REQ_MASK; 250561ae650dSJack F Vogel wr32(hw, I40E_QRX_ENA(0), reg); 250661ae650dSJack F Vogel } 250761ae650dSJack F Vogel 250861ae650dSJack F Vogel 250961ae650dSJack F Vogel /* 251061ae650dSJack F Vogel * Set the Initial ITR state 251161ae650dSJack F Vogel */ 251261ae650dSJack F Vogel static void 251361ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf) 251461ae650dSJack F Vogel { 251561ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 251661ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 251761ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 251861ae650dSJack F Vogel 251961ae650dSJack F Vogel vsi->rx_itr_setting = ixl_rx_itr; 252061ae650dSJack F Vogel if (ixl_dynamic_rx_itr) 252161ae650dSJack F Vogel vsi->rx_itr_setting |= IXL_ITR_DYNAMIC; 252261ae650dSJack F Vogel vsi->tx_itr_setting = ixl_tx_itr; 252361ae650dSJack F Vogel if (ixl_dynamic_tx_itr) 252461ae650dSJack F Vogel vsi->tx_itr_setting |= IXL_ITR_DYNAMIC; 252561ae650dSJack F Vogel 252661ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 252761ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 252861ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 252961ae650dSJack F Vogel 253061ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i), 253161ae650dSJack F Vogel vsi->rx_itr_setting); 253261ae650dSJack F Vogel rxr->itr = vsi->rx_itr_setting; 253361ae650dSJack F Vogel rxr->latency = IXL_AVE_LATENCY; 253461ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i), 253561ae650dSJack F Vogel vsi->tx_itr_setting); 253661ae650dSJack F Vogel txr->itr = vsi->tx_itr_setting; 253761ae650dSJack F Vogel txr->latency = IXL_AVE_LATENCY; 253861ae650dSJack F Vogel } 253961ae650dSJack F Vogel } 254061ae650dSJack F Vogel 254161ae650dSJack F Vogel 254261ae650dSJack F Vogel static int 254361ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf) 254461ae650dSJack F Vogel { 254561ae650dSJack F Vogel int rid; 254661ae650dSJack F Vogel device_t dev = pf->dev; 254761ae650dSJack F Vogel 254861ae650dSJack F Vogel rid = PCIR_BAR(0); 254961ae650dSJack F Vogel pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 255061ae650dSJack F Vogel &rid, RF_ACTIVE); 255161ae650dSJack F Vogel 255261ae650dSJack F Vogel if (!(pf->pci_mem)) { 255361ae650dSJack F Vogel device_printf(dev, "Unable to allocate bus resource: memory\n"); 255461ae650dSJack F Vogel return (ENXIO); 255561ae650dSJack F Vogel } 255661ae650dSJack F Vogel 255761ae650dSJack F Vogel pf->osdep.mem_bus_space_tag = 255861ae650dSJack F Vogel rman_get_bustag(pf->pci_mem); 255961ae650dSJack F Vogel pf->osdep.mem_bus_space_handle = 256061ae650dSJack F Vogel rman_get_bushandle(pf->pci_mem); 256161ae650dSJack F Vogel pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); 2562cf3c0c32SRyan Stone pf->osdep.flush_reg = I40E_GLGEN_STAT; 256361ae650dSJack F Vogel pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; 256461ae650dSJack F Vogel 256561ae650dSJack F Vogel pf->hw.back = &pf->osdep; 256661ae650dSJack F Vogel 256761ae650dSJack F Vogel /* 256861ae650dSJack F Vogel ** Now setup MSI or MSI/X, should 256961ae650dSJack F Vogel ** return us the number of supported 257061ae650dSJack F Vogel ** vectors. (Will be 1 for MSI) 257161ae650dSJack F Vogel */ 257261ae650dSJack F Vogel pf->msix = ixl_init_msix(pf); 257361ae650dSJack F Vogel return (0); 257461ae650dSJack F Vogel } 257561ae650dSJack F Vogel 257661ae650dSJack F Vogel static void 2577223d846dSEric Joyner ixl_free_interrupt_resources(struct ixl_pf *pf) 257861ae650dSJack F Vogel { 257961ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 258061ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 258161ae650dSJack F Vogel device_t dev = pf->dev; 2582223d846dSEric Joyner int rid; 258361ae650dSJack F Vogel 258461ae650dSJack F Vogel /* We may get here before stations are setup */ 258561ae650dSJack F Vogel if ((!ixl_enable_msix) || (que == NULL)) 258661ae650dSJack F Vogel goto early; 258761ae650dSJack F Vogel 258861ae650dSJack F Vogel /* 258961ae650dSJack F Vogel ** Release all msix VSI resources: 259061ae650dSJack F Vogel */ 259161ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 259261ae650dSJack F Vogel rid = que->msix + 1; 259361ae650dSJack F Vogel if (que->tag != NULL) { 259461ae650dSJack F Vogel bus_teardown_intr(dev, que->res, que->tag); 259561ae650dSJack F Vogel que->tag = NULL; 259661ae650dSJack F Vogel } 2597223d846dSEric Joyner if (que->res != NULL) { 259861ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2599223d846dSEric Joyner que->res = NULL; 2600223d846dSEric Joyner } 260161ae650dSJack F Vogel } 260261ae650dSJack F Vogel 260361ae650dSJack F Vogel early: 260461ae650dSJack F Vogel /* Clean the AdminQ interrupt last */ 260561ae650dSJack F Vogel if (pf->admvec) /* we are doing MSIX */ 260661ae650dSJack F Vogel rid = pf->admvec + 1; 260761ae650dSJack F Vogel else 260861ae650dSJack F Vogel (pf->msix != 0) ? (rid = 1):(rid = 0); 260961ae650dSJack F Vogel 261061ae650dSJack F Vogel if (pf->tag != NULL) { 261161ae650dSJack F Vogel bus_teardown_intr(dev, pf->res, pf->tag); 261261ae650dSJack F Vogel pf->tag = NULL; 261361ae650dSJack F Vogel } 2614223d846dSEric Joyner if (pf->res != NULL) { 261561ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); 2616223d846dSEric Joyner pf->res = NULL; 2617223d846dSEric Joyner } 2618223d846dSEric Joyner } 2619223d846dSEric Joyner 2620223d846dSEric Joyner static void 2621223d846dSEric Joyner ixl_free_pci_resources(struct ixl_pf *pf) 2622223d846dSEric Joyner { 2623223d846dSEric Joyner device_t dev = pf->dev; 2624223d846dSEric Joyner int memrid; 2625223d846dSEric Joyner 2626223d846dSEric Joyner ixl_free_interrupt_resources(pf); 262761ae650dSJack F Vogel 262861ae650dSJack F Vogel if (pf->msix) 262961ae650dSJack F Vogel pci_release_msi(dev); 263061ae650dSJack F Vogel 2631223d846dSEric Joyner memrid = PCIR_BAR(IXL_BAR); 2632223d846dSEric Joyner 263361ae650dSJack F Vogel if (pf->msix_mem != NULL) 263461ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 263561ae650dSJack F Vogel memrid, pf->msix_mem); 263661ae650dSJack F Vogel 263761ae650dSJack F Vogel if (pf->pci_mem != NULL) 263861ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 263961ae650dSJack F Vogel PCIR_BAR(0), pf->pci_mem); 264061ae650dSJack F Vogel 264161ae650dSJack F Vogel return; 264261ae650dSJack F Vogel } 264361ae650dSJack F Vogel 2644e5100ee2SJack F Vogel static void 2645e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type) 2646e5100ee2SJack F Vogel { 2647e5100ee2SJack F Vogel /* Display supported media types */ 2648e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX)) 2649e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2650e5100ee2SJack F Vogel 2651e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T)) 2652e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); 265356c2c47bSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_SX)) 265456c2c47bSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 265556c2c47bSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_LX)) 265656c2c47bSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL); 2657e5100ee2SJack F Vogel 2658be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_XAUI) || 2659b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XFI) || 2660e5100ee2SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU)) 2661e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2662b6c8f260SJack F Vogel 2663e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR)) 2664e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2665e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR)) 2666e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2667e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T)) 2668e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2669e5100ee2SJack F Vogel 2670b6c8f260SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) || 2671b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) || 2672b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) || 2673b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XLAUI) || 2674b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2675e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2676e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4)) 2677e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2678e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4)) 2679e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); 2680be771cdaSJack F Vogel 2681be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE 2682be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX)) 2683be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_CX, 0, NULL); 2684be771cdaSJack F Vogel 2685be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) || 2686be771cdaSJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1) || 2687be771cdaSJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) || 2688be771cdaSJack F Vogel phy_type & (1 << I40E_PHY_TYPE_SFI)) 2689be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2690be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4)) 2691be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2692be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR)) 2693be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2694be771cdaSJack F Vogel 2695be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2696be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2697be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_XLPPI)) 2698be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2699be771cdaSJack F Vogel #else 2700be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX)) 2701be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL); 2702be771cdaSJack F Vogel 2703be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) 2704be771cdaSJack F Vogel || phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1)) 2705be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL); 2706be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC)) 2707be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL); 2708be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_SFI)) 2709be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL); 2710be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4)) 2711be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); 2712be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR)) 2713be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL); 2714be771cdaSJack F Vogel 2715be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_20GBASE_KR2)) 2716be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL); 2717be771cdaSJack F Vogel 2718be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2719be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL); 2720be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_XLPPI)) 2721be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL); 2722be771cdaSJack F Vogel #endif 2723e5100ee2SJack F Vogel } 272461ae650dSJack F Vogel 272561ae650dSJack F Vogel /********************************************************************* 272661ae650dSJack F Vogel * 272761ae650dSJack F Vogel * Setup networking device structure and register an interface. 272861ae650dSJack F Vogel * 272961ae650dSJack F Vogel **********************************************************************/ 273061ae650dSJack F Vogel static int 273161ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi) 273261ae650dSJack F Vogel { 273361ae650dSJack F Vogel struct ifnet *ifp; 273461ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 273561ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 2736b6c8f260SJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 273761ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 273861ae650dSJack F Vogel 273961ae650dSJack F Vogel INIT_DEBUGOUT("ixl_setup_interface: begin"); 274061ae650dSJack F Vogel 274161ae650dSJack F Vogel ifp = vsi->ifp = if_alloc(IFT_ETHER); 274261ae650dSJack F Vogel if (ifp == NULL) { 274361ae650dSJack F Vogel device_printf(dev, "can not allocate ifnet structure\n"); 274461ae650dSJack F Vogel return (-1); 274561ae650dSJack F Vogel } 274661ae650dSJack F Vogel if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 274761ae650dSJack F Vogel ifp->if_mtu = ETHERMTU; 2748a48d00d2SEric Joyner ifp->if_baudrate = IF_Gbps(40); 274961ae650dSJack F Vogel ifp->if_init = ixl_init; 275061ae650dSJack F Vogel ifp->if_softc = vsi; 275161ae650dSJack F Vogel ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 275261ae650dSJack F Vogel ifp->if_ioctl = ixl_ioctl; 275361ae650dSJack F Vogel 2754e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036 27554b443922SGleb Smirnoff if_setgetcounterfn(ifp, ixl_get_counter); 27564b443922SGleb Smirnoff #endif 27574b443922SGleb Smirnoff 275861ae650dSJack F Vogel ifp->if_transmit = ixl_mq_start; 275961ae650dSJack F Vogel 276061ae650dSJack F Vogel ifp->if_qflush = ixl_qflush; 276161ae650dSJack F Vogel 276261ae650dSJack F Vogel ifp->if_snd.ifq_maxlen = que->num_desc - 2; 276361ae650dSJack F Vogel 276461ae650dSJack F Vogel vsi->max_frame_size = 276561ae650dSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 276661ae650dSJack F Vogel + ETHER_VLAN_ENCAP_LEN; 276761ae650dSJack F Vogel 276861ae650dSJack F Vogel /* 276961ae650dSJack F Vogel * Tell the upper layer(s) we support long frames. 277061ae650dSJack F Vogel */ 27711bffa951SGleb Smirnoff ifp->if_hdrlen = sizeof(struct ether_vlan_header); 277261ae650dSJack F Vogel 277361ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM; 277461ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; 277561ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_TSO; 277661ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_JUMBO_MTU; 277761ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_LRO; 277861ae650dSJack F Vogel 277961ae650dSJack F Vogel /* VLAN capabilties */ 278061ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 278161ae650dSJack F Vogel | IFCAP_VLAN_HWTSO 278261ae650dSJack F Vogel | IFCAP_VLAN_MTU 278361ae650dSJack F Vogel | IFCAP_VLAN_HWCSUM; 278461ae650dSJack F Vogel ifp->if_capenable = ifp->if_capabilities; 278561ae650dSJack F Vogel 278661ae650dSJack F Vogel /* 278761ae650dSJack F Vogel ** Don't turn this on by default, if vlans are 278861ae650dSJack F Vogel ** created on another pseudo device (eg. lagg) 278961ae650dSJack F Vogel ** then vlan events are not passed thru, breaking 279061ae650dSJack F Vogel ** operation, but with HW FILTER off it works. If 279161ae650dSJack F Vogel ** using vlans directly on the ixl driver you can 279261ae650dSJack F Vogel ** enable this and get full hardware tag filtering. 279361ae650dSJack F Vogel */ 279461ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 279561ae650dSJack F Vogel 279661ae650dSJack F Vogel /* 279761ae650dSJack F Vogel * Specify the media types supported by this adapter and register 279861ae650dSJack F Vogel * callbacks to update media and link information 279961ae650dSJack F Vogel */ 280061ae650dSJack F Vogel ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change, 280161ae650dSJack F Vogel ixl_media_status); 280261ae650dSJack F Vogel 2803b6c8f260SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 2804b6c8f260SJack F Vogel FALSE, TRUE, &abilities, NULL); 2805b6c8f260SJack F Vogel /* May need delay to detect fiber correctly */ 2806e5100ee2SJack F Vogel if (aq_error == I40E_ERR_UNKNOWN_PHY) { 2807e5100ee2SJack F Vogel i40e_msec_delay(200); 2808393c4bb1SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, 2809b6c8f260SJack F Vogel TRUE, &abilities, NULL); 2810b6c8f260SJack F Vogel } 2811b6c8f260SJack F Vogel if (aq_error) { 2812e5100ee2SJack F Vogel if (aq_error == I40E_ERR_UNKNOWN_PHY) 2813e5100ee2SJack F Vogel device_printf(dev, "Unknown PHY type detected!\n"); 2814e5100ee2SJack F Vogel else 2815b6c8f260SJack F Vogel device_printf(dev, 2816b6c8f260SJack F Vogel "Error getting supported media types, err %d," 2817e5100ee2SJack F Vogel " AQ error %d\n", aq_error, hw->aq.asq_last_status); 2818b6c8f260SJack F Vogel return (0); 2819b6c8f260SJack F Vogel } 2820b6c8f260SJack F Vogel 2821b6c8f260SJack F Vogel ixl_add_ifmedia(vsi, abilities.phy_type); 282261ae650dSJack F Vogel 282361ae650dSJack F Vogel /* Use autoselect media by default */ 282461ae650dSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); 282561ae650dSJack F Vogel ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); 282661ae650dSJack F Vogel 2827e5100ee2SJack F Vogel ether_ifattach(ifp, hw->mac.addr); 2828e5100ee2SJack F Vogel 282961ae650dSJack F Vogel return (0); 283061ae650dSJack F Vogel } 283161ae650dSJack F Vogel 283256c2c47bSJack F Vogel /* 2833223d846dSEric Joyner ** Run when the Admin Queue gets a link state change interrupt. 283456c2c47bSJack F Vogel */ 283556c2c47bSJack F Vogel static void 283656c2c47bSJack F Vogel ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e) 283761ae650dSJack F Vogel { 283856c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 2839223d846dSEric Joyner device_t dev = pf->dev; 284056c2c47bSJack F Vogel struct i40e_aqc_get_link_status *status = 284156c2c47bSJack F Vogel (struct i40e_aqc_get_link_status *)&e->desc.params.raw; 284261ae650dSJack F Vogel 2843223d846dSEric Joyner /* Firmware workaround: may need to wait for link to actually come up... */ 2844223d846dSEric Joyner if (!pf->link_up && (status->link_info & I40E_AQ_SIGNAL_DETECT)) { 2845223d846dSEric Joyner device_printf(dev, "%s: Waiting...\n", __func__); 2846223d846dSEric Joyner i40e_msec_delay(4000); 2847223d846dSEric Joyner } 2848223d846dSEric Joyner 2849223d846dSEric Joyner /* Request link status from adapter */ 285056c2c47bSJack F Vogel hw->phy.get_link_info = TRUE; 2851223d846dSEric Joyner i40e_get_link_status(hw, &pf->link_up); 2852223d846dSEric Joyner 2853223d846dSEric Joyner /* Print out message if an unqualified module is found */ 285456c2c47bSJack F Vogel if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) && 285556c2c47bSJack F Vogel (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) && 285656c2c47bSJack F Vogel (!(status->link_info & I40E_AQ_LINK_UP))) 2857223d846dSEric Joyner device_printf(dev, "Link failed because " 2858223d846dSEric Joyner "an unqualified module was detected!\n"); 285956c2c47bSJack F Vogel 2860223d846dSEric Joyner /* Update OS link info */ 2861223d846dSEric Joyner ixl_update_link_status(pf); 286261ae650dSJack F Vogel } 286361ae650dSJack F Vogel 286461ae650dSJack F Vogel /********************************************************************* 286561ae650dSJack F Vogel * 2866b6c8f260SJack F Vogel * Get Firmware Switch configuration 2867b6c8f260SJack F Vogel * - this will need to be more robust when more complex 2868b6c8f260SJack F Vogel * switch configurations are enabled. 286961ae650dSJack F Vogel * 287061ae650dSJack F Vogel **********************************************************************/ 287161ae650dSJack F Vogel static int 2872b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf) 287361ae650dSJack F Vogel { 2874b6c8f260SJack F Vogel struct i40e_hw *hw = &pf->hw; 2875b6c8f260SJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 287661ae650dSJack F Vogel device_t dev = vsi->dev; 287761ae650dSJack F Vogel struct i40e_aqc_get_switch_config_resp *sw_config; 287861ae650dSJack F Vogel u8 aq_buf[I40E_AQ_LARGE_BUF]; 287956c2c47bSJack F Vogel int ret; 288061ae650dSJack F Vogel u16 next = 0; 288161ae650dSJack F Vogel 2882b6c8f260SJack F Vogel memset(&aq_buf, 0, sizeof(aq_buf)); 288361ae650dSJack F Vogel sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 288461ae650dSJack F Vogel ret = i40e_aq_get_switch_config(hw, sw_config, 288561ae650dSJack F Vogel sizeof(aq_buf), &next, NULL); 288661ae650dSJack F Vogel if (ret) { 288756c2c47bSJack F Vogel device_printf(dev,"aq_get_switch_config failed (ret=%d)!!\n", 288856c2c47bSJack F Vogel ret); 288961ae650dSJack F Vogel return (ret); 289061ae650dSJack F Vogel } 289161ae650dSJack F Vogel #ifdef IXL_DEBUG 289256c2c47bSJack F Vogel device_printf(dev, 289356c2c47bSJack F Vogel "Switch config: header reported: %d in structure, %d total\n", 289461ae650dSJack F Vogel sw_config->header.num_reported, sw_config->header.num_total); 289556c2c47bSJack F Vogel for (int i = 0; i < sw_config->header.num_reported; i++) { 289656c2c47bSJack F Vogel device_printf(dev, 289756c2c47bSJack F Vogel "%d: type=%d seid=%d uplink=%d downlink=%d\n", i, 289856c2c47bSJack F Vogel sw_config->element[i].element_type, 289956c2c47bSJack F Vogel sw_config->element[i].seid, 290056c2c47bSJack F Vogel sw_config->element[i].uplink_seid, 290156c2c47bSJack F Vogel sw_config->element[i].downlink_seid); 290256c2c47bSJack F Vogel } 290361ae650dSJack F Vogel #endif 2904b6c8f260SJack F Vogel /* Simplified due to a single VSI at the moment */ 290556c2c47bSJack F Vogel vsi->uplink_seid = sw_config->element[0].uplink_seid; 290656c2c47bSJack F Vogel vsi->downlink_seid = sw_config->element[0].downlink_seid; 290761ae650dSJack F Vogel vsi->seid = sw_config->element[0].seid; 2908b6c8f260SJack F Vogel return (ret); 2909b6c8f260SJack F Vogel } 2910b6c8f260SJack F Vogel 2911b6c8f260SJack F Vogel /********************************************************************* 2912b6c8f260SJack F Vogel * 2913b6c8f260SJack F Vogel * Initialize the VSI: this handles contexts, which means things 2914b6c8f260SJack F Vogel * like the number of descriptors, buffer size, 2915b6c8f260SJack F Vogel * plus we init the rings thru this function. 2916b6c8f260SJack F Vogel * 2917b6c8f260SJack F Vogel **********************************************************************/ 2918b6c8f260SJack F Vogel static int 2919b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi) 2920b6c8f260SJack F Vogel { 292156c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 2922b6c8f260SJack F Vogel struct ixl_queue *que = vsi->queues; 2923b6c8f260SJack F Vogel device_t dev = vsi->dev; 2924b6c8f260SJack F Vogel struct i40e_hw *hw = vsi->hw; 2925b6c8f260SJack F Vogel struct i40e_vsi_context ctxt; 2926b6c8f260SJack F Vogel int err = 0; 292761ae650dSJack F Vogel 292861ae650dSJack F Vogel memset(&ctxt, 0, sizeof(ctxt)); 292961ae650dSJack F Vogel ctxt.seid = vsi->seid; 293056c2c47bSJack F Vogel if (pf->veb_seid != 0) 293156c2c47bSJack F Vogel ctxt.uplink_seid = pf->veb_seid; 293261ae650dSJack F Vogel ctxt.pf_num = hw->pf_id; 2933b6c8f260SJack F Vogel err = i40e_aq_get_vsi_params(hw, &ctxt, NULL); 2934b6c8f260SJack F Vogel if (err) { 29357f70bec6SEric Joyner device_printf(dev, "i40e_aq_get_vsi_params() failed, error %d\n", err); 2936b6c8f260SJack F Vogel return (err); 293761ae650dSJack F Vogel } 293861ae650dSJack F Vogel #ifdef IXL_DEBUG 29397f70bec6SEric Joyner device_printf(dev, "get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, " 294061ae650dSJack F Vogel "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, " 294161ae650dSJack F Vogel "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid, 294261ae650dSJack F Vogel ctxt.uplink_seid, ctxt.vsi_number, 294361ae650dSJack F Vogel ctxt.vsis_allocated, ctxt.vsis_unallocated, 294461ae650dSJack F Vogel ctxt.flags, ctxt.pf_num, ctxt.vf_num, 294561ae650dSJack F Vogel ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits); 294661ae650dSJack F Vogel #endif 294761ae650dSJack F Vogel /* 294861ae650dSJack F Vogel ** Set the queue and traffic class bits 294961ae650dSJack F Vogel ** - when multiple traffic classes are supported 295061ae650dSJack F Vogel ** this will need to be more robust. 295161ae650dSJack F Vogel */ 295261ae650dSJack F Vogel ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID; 295361ae650dSJack F Vogel ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG; 295461ae650dSJack F Vogel ctxt.info.queue_mapping[0] = 0; 29557f70bec6SEric Joyner ctxt.info.tc_mapping[0] = 0x0c00; 295661ae650dSJack F Vogel 295761ae650dSJack F Vogel /* Set VLAN receive stripping mode */ 295861ae650dSJack F Vogel ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; 295961ae650dSJack F Vogel ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; 296061ae650dSJack F Vogel if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 296161ae650dSJack F Vogel ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 296261ae650dSJack F Vogel else 296361ae650dSJack F Vogel ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 296461ae650dSJack F Vogel 296561ae650dSJack F Vogel /* Keep copy of VSI info in VSI for statistic counters */ 296661ae650dSJack F Vogel memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); 296761ae650dSJack F Vogel 296861ae650dSJack F Vogel /* Reset VSI statistics */ 296961ae650dSJack F Vogel ixl_vsi_reset_stats(vsi); 297061ae650dSJack F Vogel vsi->hw_filters_add = 0; 297161ae650dSJack F Vogel vsi->hw_filters_del = 0; 297261ae650dSJack F Vogel 297356c2c47bSJack F Vogel ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF); 297456c2c47bSJack F Vogel 2975b6c8f260SJack F Vogel err = i40e_aq_update_vsi_params(hw, &ctxt, NULL); 2976b6c8f260SJack F Vogel if (err) { 29777f70bec6SEric Joyner device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d, aq_error %d\n", 29787f70bec6SEric Joyner err, hw->aq.asq_last_status); 2979b6c8f260SJack F Vogel return (err); 298061ae650dSJack F Vogel } 298161ae650dSJack F Vogel 298261ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 298361ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 298461ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 298561ae650dSJack F Vogel struct i40e_hmc_obj_txq tctx; 298661ae650dSJack F Vogel struct i40e_hmc_obj_rxq rctx; 298761ae650dSJack F Vogel u32 txctl; 298861ae650dSJack F Vogel u16 size; 298961ae650dSJack F Vogel 299061ae650dSJack F Vogel /* Setup the HMC TX Context */ 299161ae650dSJack F Vogel size = que->num_desc * sizeof(struct i40e_tx_desc); 299261ae650dSJack F Vogel memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq)); 299361ae650dSJack F Vogel tctx.new_context = 1; 299456c2c47bSJack F Vogel tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS); 299561ae650dSJack F Vogel tctx.qlen = que->num_desc; 299661ae650dSJack F Vogel tctx.fc_ena = 0; 299761ae650dSJack F Vogel tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */ 299861ae650dSJack F Vogel /* Enable HEAD writeback */ 299961ae650dSJack F Vogel tctx.head_wb_ena = 1; 300061ae650dSJack F Vogel tctx.head_wb_addr = txr->dma.pa + 300161ae650dSJack F Vogel (que->num_desc * sizeof(struct i40e_tx_desc)); 300261ae650dSJack F Vogel tctx.rdylist_act = 0; 300361ae650dSJack F Vogel err = i40e_clear_lan_tx_queue_context(hw, i); 300461ae650dSJack F Vogel if (err) { 300561ae650dSJack F Vogel device_printf(dev, "Unable to clear TX context\n"); 300661ae650dSJack F Vogel break; 300761ae650dSJack F Vogel } 300861ae650dSJack F Vogel err = i40e_set_lan_tx_queue_context(hw, i, &tctx); 300961ae650dSJack F Vogel if (err) { 301061ae650dSJack F Vogel device_printf(dev, "Unable to set TX context\n"); 301161ae650dSJack F Vogel break; 301261ae650dSJack F Vogel } 301361ae650dSJack F Vogel /* Associate the ring with this PF */ 301461ae650dSJack F Vogel txctl = I40E_QTX_CTL_PF_QUEUE; 301561ae650dSJack F Vogel txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & 301661ae650dSJack F Vogel I40E_QTX_CTL_PF_INDX_MASK); 301761ae650dSJack F Vogel wr32(hw, I40E_QTX_CTL(i), txctl); 301861ae650dSJack F Vogel ixl_flush(hw); 301961ae650dSJack F Vogel 302061ae650dSJack F Vogel /* Do ring (re)init */ 302161ae650dSJack F Vogel ixl_init_tx_ring(que); 302261ae650dSJack F Vogel 302361ae650dSJack F Vogel /* Next setup the HMC RX Context */ 302456c2c47bSJack F Vogel if (vsi->max_frame_size <= MCLBYTES) 302561ae650dSJack F Vogel rxr->mbuf_sz = MCLBYTES; 302661ae650dSJack F Vogel else 302761ae650dSJack F Vogel rxr->mbuf_sz = MJUMPAGESIZE; 302861ae650dSJack F Vogel 302961ae650dSJack F Vogel u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len; 303061ae650dSJack F Vogel 303161ae650dSJack F Vogel /* Set up an RX context for the HMC */ 303261ae650dSJack F Vogel memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq)); 303361ae650dSJack F Vogel rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT; 303461ae650dSJack F Vogel /* ignore header split for now */ 303561ae650dSJack F Vogel rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; 303661ae650dSJack F Vogel rctx.rxmax = (vsi->max_frame_size < max_rxmax) ? 303761ae650dSJack F Vogel vsi->max_frame_size : max_rxmax; 303861ae650dSJack F Vogel rctx.dtype = 0; 303961ae650dSJack F Vogel rctx.dsize = 1; /* do 32byte descriptors */ 304061ae650dSJack F Vogel rctx.hsplit_0 = 0; /* no HDR split initially */ 304156c2c47bSJack F Vogel rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS); 304261ae650dSJack F Vogel rctx.qlen = que->num_desc; 304361ae650dSJack F Vogel rctx.tphrdesc_ena = 1; 304461ae650dSJack F Vogel rctx.tphwdesc_ena = 1; 304561ae650dSJack F Vogel rctx.tphdata_ena = 0; 304661ae650dSJack F Vogel rctx.tphhead_ena = 0; 304761ae650dSJack F Vogel rctx.lrxqthresh = 2; 304861ae650dSJack F Vogel rctx.crcstrip = 1; 304961ae650dSJack F Vogel rctx.l2tsel = 1; 305061ae650dSJack F Vogel rctx.showiv = 1; 305161ae650dSJack F Vogel rctx.fc_ena = 0; 305261ae650dSJack F Vogel rctx.prefena = 1; 305361ae650dSJack F Vogel 305461ae650dSJack F Vogel err = i40e_clear_lan_rx_queue_context(hw, i); 305561ae650dSJack F Vogel if (err) { 305661ae650dSJack F Vogel device_printf(dev, 305761ae650dSJack F Vogel "Unable to clear RX context %d\n", i); 305861ae650dSJack F Vogel break; 305961ae650dSJack F Vogel } 306061ae650dSJack F Vogel err = i40e_set_lan_rx_queue_context(hw, i, &rctx); 306161ae650dSJack F Vogel if (err) { 306261ae650dSJack F Vogel device_printf(dev, "Unable to set RX context %d\n", i); 306361ae650dSJack F Vogel break; 306461ae650dSJack F Vogel } 306561ae650dSJack F Vogel err = ixl_init_rx_ring(que); 306661ae650dSJack F Vogel if (err) { 306761ae650dSJack F Vogel device_printf(dev, "Fail in init_rx_ring %d\n", i); 306861ae650dSJack F Vogel break; 306961ae650dSJack F Vogel } 3070ac83ea83SEric Joyner wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0); 307131830672SJack F Vogel #ifdef DEV_NETMAP 307231830672SJack F Vogel /* preserve queue */ 307331830672SJack F Vogel if (vsi->ifp->if_capenable & IFCAP_NETMAP) { 307431830672SJack F Vogel struct netmap_adapter *na = NA(vsi->ifp); 307531830672SJack F Vogel struct netmap_kring *kring = &na->rx_rings[i]; 307631830672SJack F Vogel int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); 307731830672SJack F Vogel wr32(vsi->hw, I40E_QRX_TAIL(que->me), t); 307831830672SJack F Vogel } else 307931830672SJack F Vogel #endif /* DEV_NETMAP */ 308061ae650dSJack F Vogel wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1); 308161ae650dSJack F Vogel } 308261ae650dSJack F Vogel return (err); 308361ae650dSJack F Vogel } 308461ae650dSJack F Vogel 308561ae650dSJack F Vogel 308661ae650dSJack F Vogel /********************************************************************* 308761ae650dSJack F Vogel * 308861ae650dSJack F Vogel * Free all VSI structs. 308961ae650dSJack F Vogel * 309061ae650dSJack F Vogel **********************************************************************/ 309161ae650dSJack F Vogel void 309261ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi) 309361ae650dSJack F Vogel { 309461ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 309561ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 309661ae650dSJack F Vogel 309761ae650dSJack F Vogel /* Free station queues */ 3098*fdb6f38aSEric Joyner if (!vsi->queues) 3099*fdb6f38aSEric Joyner goto free_filters; 3100*fdb6f38aSEric Joyner 310161ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 310261ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 310361ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 310461ae650dSJack F Vogel 310561ae650dSJack F Vogel if (!mtx_initialized(&txr->mtx)) /* uninitialized */ 310661ae650dSJack F Vogel continue; 310761ae650dSJack F Vogel IXL_TX_LOCK(txr); 310861ae650dSJack F Vogel ixl_free_que_tx(que); 310961ae650dSJack F Vogel if (txr->base) 3110d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &txr->dma); 311161ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 311261ae650dSJack F Vogel IXL_TX_LOCK_DESTROY(txr); 311361ae650dSJack F Vogel 311461ae650dSJack F Vogel if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ 311561ae650dSJack F Vogel continue; 311661ae650dSJack F Vogel IXL_RX_LOCK(rxr); 311761ae650dSJack F Vogel ixl_free_que_rx(que); 311861ae650dSJack F Vogel if (rxr->base) 3119d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &rxr->dma); 312061ae650dSJack F Vogel IXL_RX_UNLOCK(rxr); 312161ae650dSJack F Vogel IXL_RX_LOCK_DESTROY(rxr); 312261ae650dSJack F Vogel 312361ae650dSJack F Vogel } 312461ae650dSJack F Vogel free(vsi->queues, M_DEVBUF); 312561ae650dSJack F Vogel 3126*fdb6f38aSEric Joyner free_filters: 312761ae650dSJack F Vogel /* Free VSI filter list */ 312856c2c47bSJack F Vogel ixl_free_mac_filters(vsi); 312956c2c47bSJack F Vogel } 313056c2c47bSJack F Vogel 313156c2c47bSJack F Vogel static void 313256c2c47bSJack F Vogel ixl_free_mac_filters(struct ixl_vsi *vsi) 313356c2c47bSJack F Vogel { 313456c2c47bSJack F Vogel struct ixl_mac_filter *f; 313556c2c47bSJack F Vogel 313661ae650dSJack F Vogel while (!SLIST_EMPTY(&vsi->ftl)) { 313761ae650dSJack F Vogel f = SLIST_FIRST(&vsi->ftl); 313861ae650dSJack F Vogel SLIST_REMOVE_HEAD(&vsi->ftl, next); 313961ae650dSJack F Vogel free(f, M_DEVBUF); 314061ae650dSJack F Vogel } 314161ae650dSJack F Vogel } 314261ae650dSJack F Vogel 314361ae650dSJack F Vogel 314461ae650dSJack F Vogel /********************************************************************* 314561ae650dSJack F Vogel * 314661ae650dSJack F Vogel * Allocate memory for the VSI (virtual station interface) and their 314761ae650dSJack F Vogel * associated queues, rings and the descriptors associated with each, 314861ae650dSJack F Vogel * called only once at attach. 314961ae650dSJack F Vogel * 315061ae650dSJack F Vogel **********************************************************************/ 315161ae650dSJack F Vogel static int 315261ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf) 315361ae650dSJack F Vogel { 315461ae650dSJack F Vogel device_t dev = pf->dev; 315561ae650dSJack F Vogel struct ixl_vsi *vsi; 315661ae650dSJack F Vogel struct ixl_queue *que; 315761ae650dSJack F Vogel struct tx_ring *txr; 315861ae650dSJack F Vogel struct rx_ring *rxr; 315961ae650dSJack F Vogel int rsize, tsize; 316061ae650dSJack F Vogel int error = I40E_SUCCESS; 316161ae650dSJack F Vogel 316261ae650dSJack F Vogel vsi = &pf->vsi; 316361ae650dSJack F Vogel vsi->back = (void *)pf; 316461ae650dSJack F Vogel vsi->hw = &pf->hw; 316561ae650dSJack F Vogel vsi->id = 0; 316661ae650dSJack F Vogel vsi->num_vlans = 0; 316756c2c47bSJack F Vogel vsi->back = pf; 316861ae650dSJack F Vogel 316961ae650dSJack F Vogel /* Get memory for the station queues */ 317061ae650dSJack F Vogel if (!(vsi->queues = 317161ae650dSJack F Vogel (struct ixl_queue *) malloc(sizeof(struct ixl_queue) * 317261ae650dSJack F Vogel vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { 317361ae650dSJack F Vogel device_printf(dev, "Unable to allocate queue memory\n"); 317461ae650dSJack F Vogel error = ENOMEM; 317561ae650dSJack F Vogel goto early; 317661ae650dSJack F Vogel } 317761ae650dSJack F Vogel 317861ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 317961ae650dSJack F Vogel que = &vsi->queues[i]; 318061ae650dSJack F Vogel que->num_desc = ixl_ringsz; 318161ae650dSJack F Vogel que->me = i; 318261ae650dSJack F Vogel que->vsi = vsi; 318361ae650dSJack F Vogel /* mark the queue as active */ 318461ae650dSJack F Vogel vsi->active_queues |= (u64)1 << que->me; 318561ae650dSJack F Vogel txr = &que->txr; 318661ae650dSJack F Vogel txr->que = que; 318761ae650dSJack F Vogel txr->tail = I40E_QTX_TAIL(que->me); 318861ae650dSJack F Vogel 318961ae650dSJack F Vogel /* Initialize the TX lock */ 319061ae650dSJack F Vogel snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", 319161ae650dSJack F Vogel device_get_nameunit(dev), que->me); 319261ae650dSJack F Vogel mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF); 319361ae650dSJack F Vogel /* Create the TX descriptor ring */ 319461ae650dSJack F Vogel tsize = roundup2((que->num_desc * 319561ae650dSJack F Vogel sizeof(struct i40e_tx_desc)) + 319661ae650dSJack F Vogel sizeof(u32), DBA_ALIGN); 3197d94ca7cfSBjoern A. Zeeb if (i40e_allocate_dma_mem(&pf->hw, 3198d94ca7cfSBjoern A. Zeeb &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) { 319961ae650dSJack F Vogel device_printf(dev, 320061ae650dSJack F Vogel "Unable to allocate TX Descriptor memory\n"); 320161ae650dSJack F Vogel error = ENOMEM; 320261ae650dSJack F Vogel goto fail; 320361ae650dSJack F Vogel } 320461ae650dSJack F Vogel txr->base = (struct i40e_tx_desc *)txr->dma.va; 320561ae650dSJack F Vogel bzero((void *)txr->base, tsize); 320661ae650dSJack F Vogel /* Now allocate transmit soft structs for the ring */ 320761ae650dSJack F Vogel if (ixl_allocate_tx_data(que)) { 320861ae650dSJack F Vogel device_printf(dev, 320961ae650dSJack F Vogel "Critical Failure setting up TX structures\n"); 321061ae650dSJack F Vogel error = ENOMEM; 321161ae650dSJack F Vogel goto fail; 321261ae650dSJack F Vogel } 321361ae650dSJack F Vogel /* Allocate a buf ring */ 321461ae650dSJack F Vogel txr->br = buf_ring_alloc(4096, M_DEVBUF, 3215223d846dSEric Joyner M_NOWAIT, &txr->mtx); 321661ae650dSJack F Vogel if (txr->br == NULL) { 321761ae650dSJack F Vogel device_printf(dev, 321861ae650dSJack F Vogel "Critical Failure setting up TX buf ring\n"); 321961ae650dSJack F Vogel error = ENOMEM; 322061ae650dSJack F Vogel goto fail; 322161ae650dSJack F Vogel } 322261ae650dSJack F Vogel 322361ae650dSJack F Vogel /* 322461ae650dSJack F Vogel * Next the RX queues... 322561ae650dSJack F Vogel */ 322661ae650dSJack F Vogel rsize = roundup2(que->num_desc * 322761ae650dSJack F Vogel sizeof(union i40e_rx_desc), DBA_ALIGN); 322861ae650dSJack F Vogel rxr = &que->rxr; 322961ae650dSJack F Vogel rxr->que = que; 323061ae650dSJack F Vogel rxr->tail = I40E_QRX_TAIL(que->me); 323161ae650dSJack F Vogel 323261ae650dSJack F Vogel /* Initialize the RX side lock */ 323361ae650dSJack F Vogel snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", 323461ae650dSJack F Vogel device_get_nameunit(dev), que->me); 323561ae650dSJack F Vogel mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF); 323661ae650dSJack F Vogel 3237d94ca7cfSBjoern A. Zeeb if (i40e_allocate_dma_mem(&pf->hw, 3238d94ca7cfSBjoern A. Zeeb &rxr->dma, i40e_mem_reserved, rsize, 4096)) { 323961ae650dSJack F Vogel device_printf(dev, 324061ae650dSJack F Vogel "Unable to allocate RX Descriptor memory\n"); 324161ae650dSJack F Vogel error = ENOMEM; 324261ae650dSJack F Vogel goto fail; 324361ae650dSJack F Vogel } 324461ae650dSJack F Vogel rxr->base = (union i40e_rx_desc *)rxr->dma.va; 324561ae650dSJack F Vogel bzero((void *)rxr->base, rsize); 324661ae650dSJack F Vogel 324761ae650dSJack F Vogel /* Allocate receive soft structs for the ring*/ 324861ae650dSJack F Vogel if (ixl_allocate_rx_data(que)) { 324961ae650dSJack F Vogel device_printf(dev, 325061ae650dSJack F Vogel "Critical Failure setting up receive structs\n"); 325161ae650dSJack F Vogel error = ENOMEM; 325261ae650dSJack F Vogel goto fail; 325361ae650dSJack F Vogel } 325461ae650dSJack F Vogel } 325561ae650dSJack F Vogel 325661ae650dSJack F Vogel return (0); 325761ae650dSJack F Vogel 325861ae650dSJack F Vogel fail: 325961ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 326061ae650dSJack F Vogel que = &vsi->queues[i]; 326161ae650dSJack F Vogel rxr = &que->rxr; 326261ae650dSJack F Vogel txr = &que->txr; 326361ae650dSJack F Vogel if (rxr->base) 3264d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &rxr->dma); 326561ae650dSJack F Vogel if (txr->base) 3266d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &txr->dma); 326761ae650dSJack F Vogel } 326861ae650dSJack F Vogel 326961ae650dSJack F Vogel early: 327061ae650dSJack F Vogel return (error); 327161ae650dSJack F Vogel } 327261ae650dSJack F Vogel 327361ae650dSJack F Vogel /* 327461ae650dSJack F Vogel ** Provide a update to the queue RX 327561ae650dSJack F Vogel ** interrupt moderation value. 327661ae650dSJack F Vogel */ 327761ae650dSJack F Vogel static void 327861ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que) 327961ae650dSJack F Vogel { 328061ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 328161ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 328261ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 328361ae650dSJack F Vogel u16 rx_itr; 328461ae650dSJack F Vogel u16 rx_latency = 0; 328561ae650dSJack F Vogel int rx_bytes; 328661ae650dSJack F Vogel 328761ae650dSJack F Vogel 328861ae650dSJack F Vogel /* Idle, do nothing */ 328961ae650dSJack F Vogel if (rxr->bytes == 0) 329061ae650dSJack F Vogel return; 329161ae650dSJack F Vogel 329261ae650dSJack F Vogel if (ixl_dynamic_rx_itr) { 329361ae650dSJack F Vogel rx_bytes = rxr->bytes/rxr->itr; 329461ae650dSJack F Vogel rx_itr = rxr->itr; 329561ae650dSJack F Vogel 329661ae650dSJack F Vogel /* Adjust latency range */ 329761ae650dSJack F Vogel switch (rxr->latency) { 329861ae650dSJack F Vogel case IXL_LOW_LATENCY: 329961ae650dSJack F Vogel if (rx_bytes > 10) { 330061ae650dSJack F Vogel rx_latency = IXL_AVE_LATENCY; 330161ae650dSJack F Vogel rx_itr = IXL_ITR_20K; 330261ae650dSJack F Vogel } 330361ae650dSJack F Vogel break; 330461ae650dSJack F Vogel case IXL_AVE_LATENCY: 330561ae650dSJack F Vogel if (rx_bytes > 20) { 330661ae650dSJack F Vogel rx_latency = IXL_BULK_LATENCY; 330761ae650dSJack F Vogel rx_itr = IXL_ITR_8K; 330861ae650dSJack F Vogel } else if (rx_bytes <= 10) { 330961ae650dSJack F Vogel rx_latency = IXL_LOW_LATENCY; 331061ae650dSJack F Vogel rx_itr = IXL_ITR_100K; 331161ae650dSJack F Vogel } 331261ae650dSJack F Vogel break; 331361ae650dSJack F Vogel case IXL_BULK_LATENCY: 331461ae650dSJack F Vogel if (rx_bytes <= 20) { 331561ae650dSJack F Vogel rx_latency = IXL_AVE_LATENCY; 331661ae650dSJack F Vogel rx_itr = IXL_ITR_20K; 331761ae650dSJack F Vogel } 331861ae650dSJack F Vogel break; 331961ae650dSJack F Vogel } 332061ae650dSJack F Vogel 332161ae650dSJack F Vogel rxr->latency = rx_latency; 332261ae650dSJack F Vogel 332361ae650dSJack F Vogel if (rx_itr != rxr->itr) { 332461ae650dSJack F Vogel /* do an exponential smoothing */ 332561ae650dSJack F Vogel rx_itr = (10 * rx_itr * rxr->itr) / 332661ae650dSJack F Vogel ((9 * rx_itr) + rxr->itr); 332761ae650dSJack F Vogel rxr->itr = rx_itr & IXL_MAX_ITR; 332861ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 332961ae650dSJack F Vogel que->me), rxr->itr); 333061ae650dSJack F Vogel } 333161ae650dSJack F Vogel } else { /* We may have have toggled to non-dynamic */ 333261ae650dSJack F Vogel if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) 333361ae650dSJack F Vogel vsi->rx_itr_setting = ixl_rx_itr; 333461ae650dSJack F Vogel /* Update the hardware if needed */ 333561ae650dSJack F Vogel if (rxr->itr != vsi->rx_itr_setting) { 333661ae650dSJack F Vogel rxr->itr = vsi->rx_itr_setting; 333761ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 333861ae650dSJack F Vogel que->me), rxr->itr); 333961ae650dSJack F Vogel } 334061ae650dSJack F Vogel } 334161ae650dSJack F Vogel rxr->bytes = 0; 334261ae650dSJack F Vogel rxr->packets = 0; 334361ae650dSJack F Vogel return; 334461ae650dSJack F Vogel } 334561ae650dSJack F Vogel 334661ae650dSJack F Vogel 334761ae650dSJack F Vogel /* 334861ae650dSJack F Vogel ** Provide a update to the queue TX 334961ae650dSJack F Vogel ** interrupt moderation value. 335061ae650dSJack F Vogel */ 335161ae650dSJack F Vogel static void 335261ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que) 335361ae650dSJack F Vogel { 335461ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 335561ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 335661ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 335761ae650dSJack F Vogel u16 tx_itr; 335861ae650dSJack F Vogel u16 tx_latency = 0; 335961ae650dSJack F Vogel int tx_bytes; 336061ae650dSJack F Vogel 336161ae650dSJack F Vogel 336261ae650dSJack F Vogel /* Idle, do nothing */ 336361ae650dSJack F Vogel if (txr->bytes == 0) 336461ae650dSJack F Vogel return; 336561ae650dSJack F Vogel 336661ae650dSJack F Vogel if (ixl_dynamic_tx_itr) { 336761ae650dSJack F Vogel tx_bytes = txr->bytes/txr->itr; 336861ae650dSJack F Vogel tx_itr = txr->itr; 336961ae650dSJack F Vogel 337061ae650dSJack F Vogel switch (txr->latency) { 337161ae650dSJack F Vogel case IXL_LOW_LATENCY: 337261ae650dSJack F Vogel if (tx_bytes > 10) { 337361ae650dSJack F Vogel tx_latency = IXL_AVE_LATENCY; 337461ae650dSJack F Vogel tx_itr = IXL_ITR_20K; 337561ae650dSJack F Vogel } 337661ae650dSJack F Vogel break; 337761ae650dSJack F Vogel case IXL_AVE_LATENCY: 337861ae650dSJack F Vogel if (tx_bytes > 20) { 337961ae650dSJack F Vogel tx_latency = IXL_BULK_LATENCY; 338061ae650dSJack F Vogel tx_itr = IXL_ITR_8K; 338161ae650dSJack F Vogel } else if (tx_bytes <= 10) { 338261ae650dSJack F Vogel tx_latency = IXL_LOW_LATENCY; 338361ae650dSJack F Vogel tx_itr = IXL_ITR_100K; 338461ae650dSJack F Vogel } 338561ae650dSJack F Vogel break; 338661ae650dSJack F Vogel case IXL_BULK_LATENCY: 338761ae650dSJack F Vogel if (tx_bytes <= 20) { 338861ae650dSJack F Vogel tx_latency = IXL_AVE_LATENCY; 338961ae650dSJack F Vogel tx_itr = IXL_ITR_20K; 339061ae650dSJack F Vogel } 339161ae650dSJack F Vogel break; 339261ae650dSJack F Vogel } 339361ae650dSJack F Vogel 339461ae650dSJack F Vogel txr->latency = tx_latency; 339561ae650dSJack F Vogel 339661ae650dSJack F Vogel if (tx_itr != txr->itr) { 339761ae650dSJack F Vogel /* do an exponential smoothing */ 339861ae650dSJack F Vogel tx_itr = (10 * tx_itr * txr->itr) / 339961ae650dSJack F Vogel ((9 * tx_itr) + txr->itr); 340061ae650dSJack F Vogel txr->itr = tx_itr & IXL_MAX_ITR; 340161ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 340261ae650dSJack F Vogel que->me), txr->itr); 340361ae650dSJack F Vogel } 340461ae650dSJack F Vogel 340561ae650dSJack F Vogel } else { /* We may have have toggled to non-dynamic */ 340661ae650dSJack F Vogel if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC) 340761ae650dSJack F Vogel vsi->tx_itr_setting = ixl_tx_itr; 340861ae650dSJack F Vogel /* Update the hardware if needed */ 340961ae650dSJack F Vogel if (txr->itr != vsi->tx_itr_setting) { 341061ae650dSJack F Vogel txr->itr = vsi->tx_itr_setting; 341161ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 341261ae650dSJack F Vogel que->me), txr->itr); 341361ae650dSJack F Vogel } 341461ae650dSJack F Vogel } 341561ae650dSJack F Vogel txr->bytes = 0; 341661ae650dSJack F Vogel txr->packets = 0; 341761ae650dSJack F Vogel return; 341861ae650dSJack F Vogel } 341961ae650dSJack F Vogel 342056c2c47bSJack F Vogel #define QUEUE_NAME_LEN 32 342156c2c47bSJack F Vogel 342256c2c47bSJack F Vogel static void 342356c2c47bSJack F Vogel ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi, 342456c2c47bSJack F Vogel struct sysctl_ctx_list *ctx, const char *sysctl_name) 342556c2c47bSJack F Vogel { 342656c2c47bSJack F Vogel struct sysctl_oid *tree; 342756c2c47bSJack F Vogel struct sysctl_oid_list *child; 342856c2c47bSJack F Vogel struct sysctl_oid_list *vsi_list; 342956c2c47bSJack F Vogel 343056c2c47bSJack F Vogel tree = device_get_sysctl_tree(pf->dev); 343156c2c47bSJack F Vogel child = SYSCTL_CHILDREN(tree); 343256c2c47bSJack F Vogel vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name, 343356c2c47bSJack F Vogel CTLFLAG_RD, NULL, "VSI Number"); 343456c2c47bSJack F Vogel vsi_list = SYSCTL_CHILDREN(vsi->vsi_node); 343556c2c47bSJack F Vogel 343656c2c47bSJack F Vogel ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats); 343756c2c47bSJack F Vogel } 343861ae650dSJack F Vogel 343961ae650dSJack F Vogel static void 344061ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf) 344161ae650dSJack F Vogel { 344261ae650dSJack F Vogel device_t dev = pf->dev; 344361ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 344461ae650dSJack F Vogel struct ixl_queue *queues = vsi->queues; 344561ae650dSJack F Vogel struct i40e_hw_port_stats *pf_stats = &pf->stats; 344661ae650dSJack F Vogel 344761ae650dSJack F Vogel struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 344861ae650dSJack F Vogel struct sysctl_oid *tree = device_get_sysctl_tree(dev); 344961ae650dSJack F Vogel struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 345056c2c47bSJack F Vogel struct sysctl_oid_list *vsi_list; 345161ae650dSJack F Vogel 345256c2c47bSJack F Vogel struct sysctl_oid *queue_node; 345356c2c47bSJack F Vogel struct sysctl_oid_list *queue_list; 345461ae650dSJack F Vogel 345561ae650dSJack F Vogel struct tx_ring *txr; 345661ae650dSJack F Vogel struct rx_ring *rxr; 345756c2c47bSJack F Vogel char queue_namebuf[QUEUE_NAME_LEN]; 345861ae650dSJack F Vogel 345961ae650dSJack F Vogel /* Driver statistics */ 346061ae650dSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 346161ae650dSJack F Vogel CTLFLAG_RD, &pf->watchdog_events, 346261ae650dSJack F Vogel "Watchdog timeouts"); 346361ae650dSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq", 346461ae650dSJack F Vogel CTLFLAG_RD, &pf->admin_irq, 346561ae650dSJack F Vogel "Admin Queue IRQ Handled"); 346661ae650dSJack F Vogel 346756c2c47bSJack F Vogel ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf"); 346856c2c47bSJack F Vogel vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node); 346961ae650dSJack F Vogel 347061ae650dSJack F Vogel /* Queue statistics */ 347161ae650dSJack F Vogel for (int q = 0; q < vsi->num_queues; q++) { 347261ae650dSJack F Vogel snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); 347356c2c47bSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, 347456c2c47bSJack F Vogel OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #"); 347561ae650dSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 347661ae650dSJack F Vogel 347761ae650dSJack F Vogel txr = &(queues[q].txr); 347861ae650dSJack F Vogel rxr = &(queues[q].rxr); 347961ae650dSJack F Vogel 348061ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", 348161ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), 348261ae650dSJack F Vogel "m_defrag() failed"); 348361ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped", 348461ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].dropped_pkts), 348561ae650dSJack F Vogel "Driver dropped packets"); 348661ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 348761ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].irqs), 348861ae650dSJack F Vogel "irqs on this queue"); 348961ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", 349061ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].tso), 349161ae650dSJack F Vogel "TSO"); 349261ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup", 349361ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].tx_dma_setup), 349461ae650dSJack F Vogel "Driver tx dma failure in xmit"); 349561ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 349661ae650dSJack F Vogel CTLFLAG_RD, &(txr->no_desc), 349761ae650dSJack F Vogel "Queue No Descriptor Available"); 349861ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 349961ae650dSJack F Vogel CTLFLAG_RD, &(txr->total_packets), 350061ae650dSJack F Vogel "Queue Packets Transmitted"); 350161ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", 350261ae650dSJack F Vogel CTLFLAG_RD, &(txr->tx_bytes), 350361ae650dSJack F Vogel "Queue Bytes Transmitted"); 350461ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 350561ae650dSJack F Vogel CTLFLAG_RD, &(rxr->rx_packets), 350661ae650dSJack F Vogel "Queue Packets Received"); 350761ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 350861ae650dSJack F Vogel CTLFLAG_RD, &(rxr->rx_bytes), 350961ae650dSJack F Vogel "Queue Bytes Received"); 351061ae650dSJack F Vogel } 351161ae650dSJack F Vogel 351261ae650dSJack F Vogel /* MAC stats */ 351361ae650dSJack F Vogel ixl_add_sysctls_mac_stats(ctx, child, pf_stats); 351461ae650dSJack F Vogel } 351561ae650dSJack F Vogel 351661ae650dSJack F Vogel static void 351761ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx, 351861ae650dSJack F Vogel struct sysctl_oid_list *child, 351961ae650dSJack F Vogel struct i40e_eth_stats *eth_stats) 352061ae650dSJack F Vogel { 352161ae650dSJack F Vogel struct ixl_sysctl_info ctls[] = 352261ae650dSJack F Vogel { 352361ae650dSJack F Vogel {ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, 352461ae650dSJack F Vogel {ð_stats->rx_unicast, "ucast_pkts_rcvd", 352561ae650dSJack F Vogel "Unicast Packets Received"}, 352661ae650dSJack F Vogel {ð_stats->rx_multicast, "mcast_pkts_rcvd", 352761ae650dSJack F Vogel "Multicast Packets Received"}, 352861ae650dSJack F Vogel {ð_stats->rx_broadcast, "bcast_pkts_rcvd", 352961ae650dSJack F Vogel "Broadcast Packets Received"}, 353061ae650dSJack F Vogel {ð_stats->rx_discards, "rx_discards", "Discarded RX packets"}, 353161ae650dSJack F Vogel {ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, 353261ae650dSJack F Vogel {ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, 353361ae650dSJack F Vogel {ð_stats->tx_multicast, "mcast_pkts_txd", 353461ae650dSJack F Vogel "Multicast Packets Transmitted"}, 353561ae650dSJack F Vogel {ð_stats->tx_broadcast, "bcast_pkts_txd", 353661ae650dSJack F Vogel "Broadcast Packets Transmitted"}, 353761ae650dSJack F Vogel // end 353861ae650dSJack F Vogel {0,0,0} 353961ae650dSJack F Vogel }; 354061ae650dSJack F Vogel 354161ae650dSJack F Vogel struct ixl_sysctl_info *entry = ctls; 3542648970d8SPedro F. Giffuni while (entry->stat != NULL) 354361ae650dSJack F Vogel { 354461ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name, 354561ae650dSJack F Vogel CTLFLAG_RD, entry->stat, 354661ae650dSJack F Vogel entry->description); 354761ae650dSJack F Vogel entry++; 354861ae650dSJack F Vogel } 354961ae650dSJack F Vogel } 355061ae650dSJack F Vogel 355161ae650dSJack F Vogel static void 355261ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx, 355361ae650dSJack F Vogel struct sysctl_oid_list *child, 355461ae650dSJack F Vogel struct i40e_hw_port_stats *stats) 355561ae650dSJack F Vogel { 355661ae650dSJack F Vogel struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", 355761ae650dSJack F Vogel CTLFLAG_RD, NULL, "Mac Statistics"); 355861ae650dSJack F Vogel struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node); 355961ae650dSJack F Vogel 356061ae650dSJack F Vogel struct i40e_eth_stats *eth_stats = &stats->eth; 356161ae650dSJack F Vogel ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats); 356261ae650dSJack F Vogel 356361ae650dSJack F Vogel struct ixl_sysctl_info ctls[] = 356461ae650dSJack F Vogel { 356561ae650dSJack F Vogel {&stats->crc_errors, "crc_errors", "CRC Errors"}, 356661ae650dSJack F Vogel {&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"}, 356761ae650dSJack F Vogel {&stats->mac_local_faults, "local_faults", "MAC Local Faults"}, 356861ae650dSJack F Vogel {&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"}, 356961ae650dSJack F Vogel {&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"}, 357061ae650dSJack F Vogel /* Packet Reception Stats */ 357161ae650dSJack F Vogel {&stats->rx_size_64, "rx_frames_64", "64 byte frames received"}, 357261ae650dSJack F Vogel {&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"}, 357361ae650dSJack F Vogel {&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"}, 357461ae650dSJack F Vogel {&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"}, 357561ae650dSJack F Vogel {&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"}, 357661ae650dSJack F Vogel {&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"}, 357761ae650dSJack F Vogel {&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"}, 357861ae650dSJack F Vogel {&stats->rx_undersize, "rx_undersize", "Undersized packets received"}, 357961ae650dSJack F Vogel {&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"}, 358061ae650dSJack F Vogel {&stats->rx_oversize, "rx_oversized", "Oversized packets received"}, 358161ae650dSJack F Vogel {&stats->rx_jabber, "rx_jabber", "Received Jabber"}, 358261ae650dSJack F Vogel {&stats->checksum_error, "checksum_errors", "Checksum Errors"}, 358361ae650dSJack F Vogel /* Packet Transmission Stats */ 358461ae650dSJack F Vogel {&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"}, 358561ae650dSJack F Vogel {&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"}, 358661ae650dSJack F Vogel {&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"}, 358761ae650dSJack F Vogel {&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"}, 358861ae650dSJack F Vogel {&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"}, 358961ae650dSJack F Vogel {&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"}, 359061ae650dSJack F Vogel {&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"}, 359161ae650dSJack F Vogel /* Flow control */ 359261ae650dSJack F Vogel {&stats->link_xon_tx, "xon_txd", "Link XON transmitted"}, 359361ae650dSJack F Vogel {&stats->link_xon_rx, "xon_recvd", "Link XON received"}, 359461ae650dSJack F Vogel {&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"}, 359561ae650dSJack F Vogel {&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"}, 359661ae650dSJack F Vogel /* End */ 359761ae650dSJack F Vogel {0,0,0} 359861ae650dSJack F Vogel }; 359961ae650dSJack F Vogel 360061ae650dSJack F Vogel struct ixl_sysctl_info *entry = ctls; 3601648970d8SPedro F. Giffuni while (entry->stat != NULL) 360261ae650dSJack F Vogel { 360361ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name, 360461ae650dSJack F Vogel CTLFLAG_RD, entry->stat, 360561ae650dSJack F Vogel entry->description); 360661ae650dSJack F Vogel entry++; 360761ae650dSJack F Vogel } 360861ae650dSJack F Vogel } 360961ae650dSJack F Vogel 3610be771cdaSJack F Vogel 361161ae650dSJack F Vogel /* 361261ae650dSJack F Vogel ** ixl_config_rss - setup RSS 361361ae650dSJack F Vogel ** - note this is done for the single vsi 361461ae650dSJack F Vogel */ 361561ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *vsi) 361661ae650dSJack F Vogel { 361761ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 361861ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 361961ae650dSJack F Vogel u32 lut = 0; 3620393c4bb1SJack F Vogel u64 set_hena = 0, hena; 3621393c4bb1SJack F Vogel int i, j, que_id; 3622393c4bb1SJack F Vogel #ifdef RSS 3623393c4bb1SJack F Vogel u32 rss_hash_config; 3624393c4bb1SJack F Vogel u32 rss_seed[IXL_KEYSZ]; 3625393c4bb1SJack F Vogel #else 3626393c4bb1SJack F Vogel u32 rss_seed[IXL_KEYSZ] = {0x41b01687, 3627393c4bb1SJack F Vogel 0x183cfd8c, 0xce880440, 0x580cbc3c, 3628393c4bb1SJack F Vogel 0x35897377, 0x328b25e1, 0x4fa98922, 3629393c4bb1SJack F Vogel 0xb7d90c14, 0xd5bad70d, 0xcd15a2c1}; 3630393c4bb1SJack F Vogel #endif 363161ae650dSJack F Vogel 3632393c4bb1SJack F Vogel #ifdef RSS 3633393c4bb1SJack F Vogel /* Fetch the configured RSS key */ 3634393c4bb1SJack F Vogel rss_getkey((uint8_t *) &rss_seed); 3635393c4bb1SJack F Vogel #endif 363661ae650dSJack F Vogel 363761ae650dSJack F Vogel /* Fill out hash function seed */ 3638393c4bb1SJack F Vogel for (i = 0; i < IXL_KEYSZ; i++) 3639393c4bb1SJack F Vogel wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]); 364061ae650dSJack F Vogel 364161ae650dSJack F Vogel /* Enable PCTYPES for RSS: */ 3642393c4bb1SJack F Vogel #ifdef RSS 3643393c4bb1SJack F Vogel rss_hash_config = rss_gethashconfig(); 3644393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 3645393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); 3646393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 3647393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); 3648393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 3649393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP); 3650393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 3651393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); 3652df1d7a71SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 3653df1d7a71SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); 3654393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 3655393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); 3656393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 3657393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP); 3658393c4bb1SJack F Vogel #else 365961ae650dSJack F Vogel set_hena = 366061ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | 366161ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | 366261ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | 366361ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | 366461ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | 366561ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | 366661ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | 366761ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | 366861ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | 366961ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | 367061ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD); 3671393c4bb1SJack F Vogel #endif 367261ae650dSJack F Vogel hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) | 367361ae650dSJack F Vogel ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32); 367461ae650dSJack F Vogel hena |= set_hena; 367561ae650dSJack F Vogel wr32(hw, I40E_PFQF_HENA(0), (u32)hena); 367661ae650dSJack F Vogel wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); 367761ae650dSJack F Vogel 367861ae650dSJack F Vogel /* Populate the LUT with max no. of queues in round robin fashion */ 367961ae650dSJack F Vogel for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) { 368061ae650dSJack F Vogel if (j == vsi->num_queues) 368161ae650dSJack F Vogel j = 0; 3682393c4bb1SJack F Vogel #ifdef RSS 3683393c4bb1SJack F Vogel /* 3684393c4bb1SJack F Vogel * Fetch the RSS bucket id for the given indirection entry. 3685393c4bb1SJack F Vogel * Cap it at the number of configured buckets (which is 3686393c4bb1SJack F Vogel * num_queues.) 3687393c4bb1SJack F Vogel */ 3688393c4bb1SJack F Vogel que_id = rss_get_indirection_to_bucket(i); 3689dcd7b3b2SJack F Vogel que_id = que_id % vsi->num_queues; 3690393c4bb1SJack F Vogel #else 3691393c4bb1SJack F Vogel que_id = j; 3692393c4bb1SJack F Vogel #endif 369361ae650dSJack F Vogel /* lut = 4-byte sliding window of 4 lut entries */ 3694393c4bb1SJack F Vogel lut = (lut << 8) | (que_id & 369561ae650dSJack F Vogel ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1)); 369661ae650dSJack F Vogel /* On i = 3, we have 4 entries in lut; write to the register */ 369761ae650dSJack F Vogel if ((i & 3) == 3) 369861ae650dSJack F Vogel wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); 369961ae650dSJack F Vogel } 370061ae650dSJack F Vogel ixl_flush(hw); 370161ae650dSJack F Vogel } 370261ae650dSJack F Vogel 370361ae650dSJack F Vogel 370461ae650dSJack F Vogel /* 370561ae650dSJack F Vogel ** This routine is run via an vlan config EVENT, 370661ae650dSJack F Vogel ** it enables us to use the HW Filter table since 370761ae650dSJack F Vogel ** we can get the vlan id. This just creates the 370861ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will 370961ae650dSJack F Vogel ** repopulate the real table. 371061ae650dSJack F Vogel */ 371161ae650dSJack F Vogel static void 371261ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 371361ae650dSJack F Vogel { 371461ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 371561ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 371661ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 371761ae650dSJack F Vogel 371861ae650dSJack F Vogel if (ifp->if_softc != arg) /* Not our event */ 371961ae650dSJack F Vogel return; 372061ae650dSJack F Vogel 372161ae650dSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 372261ae650dSJack F Vogel return; 372361ae650dSJack F Vogel 372461ae650dSJack F Vogel IXL_PF_LOCK(pf); 372561ae650dSJack F Vogel ++vsi->num_vlans; 372661ae650dSJack F Vogel ixl_add_filter(vsi, hw->mac.addr, vtag); 372761ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 372861ae650dSJack F Vogel } 372961ae650dSJack F Vogel 373061ae650dSJack F Vogel /* 373161ae650dSJack F Vogel ** This routine is run via an vlan 373261ae650dSJack F Vogel ** unconfig EVENT, remove our entry 373361ae650dSJack F Vogel ** in the soft vfta. 373461ae650dSJack F Vogel */ 373561ae650dSJack F Vogel static void 373661ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 373761ae650dSJack F Vogel { 373861ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 373961ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 374061ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 374161ae650dSJack F Vogel 374261ae650dSJack F Vogel if (ifp->if_softc != arg) 374361ae650dSJack F Vogel return; 374461ae650dSJack F Vogel 374561ae650dSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 374661ae650dSJack F Vogel return; 374761ae650dSJack F Vogel 374861ae650dSJack F Vogel IXL_PF_LOCK(pf); 374961ae650dSJack F Vogel --vsi->num_vlans; 375061ae650dSJack F Vogel ixl_del_filter(vsi, hw->mac.addr, vtag); 375161ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 375261ae650dSJack F Vogel } 375361ae650dSJack F Vogel 375461ae650dSJack F Vogel /* 375561ae650dSJack F Vogel ** This routine updates vlan filters, called by init 375661ae650dSJack F Vogel ** it scans the filter table and then updates the hw 375761ae650dSJack F Vogel ** after a soft reset. 375861ae650dSJack F Vogel */ 375961ae650dSJack F Vogel static void 376061ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi) 376161ae650dSJack F Vogel { 376261ae650dSJack F Vogel struct ixl_mac_filter *f; 376361ae650dSJack F Vogel int cnt = 0, flags; 376461ae650dSJack F Vogel 376561ae650dSJack F Vogel if (vsi->num_vlans == 0) 376661ae650dSJack F Vogel return; 376761ae650dSJack F Vogel /* 376861ae650dSJack F Vogel ** Scan the filter list for vlan entries, 376961ae650dSJack F Vogel ** mark them for addition and then call 377061ae650dSJack F Vogel ** for the AQ update. 377161ae650dSJack F Vogel */ 377261ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 377361ae650dSJack F Vogel if (f->flags & IXL_FILTER_VLAN) { 377461ae650dSJack F Vogel f->flags |= 377561ae650dSJack F Vogel (IXL_FILTER_ADD | 377661ae650dSJack F Vogel IXL_FILTER_USED); 377761ae650dSJack F Vogel cnt++; 377861ae650dSJack F Vogel } 377961ae650dSJack F Vogel } 378061ae650dSJack F Vogel if (cnt == 0) { 378161ae650dSJack F Vogel printf("setup vlan: no filters found!\n"); 378261ae650dSJack F Vogel return; 378361ae650dSJack F Vogel } 378461ae650dSJack F Vogel flags = IXL_FILTER_VLAN; 378561ae650dSJack F Vogel flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 378661ae650dSJack F Vogel ixl_add_hw_filters(vsi, flags, cnt); 378761ae650dSJack F Vogel return; 378861ae650dSJack F Vogel } 378961ae650dSJack F Vogel 379061ae650dSJack F Vogel /* 379161ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware 379261ae650dSJack F Vogel ** needs to know about. 379361ae650dSJack F Vogel */ 379461ae650dSJack F Vogel static void 379561ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi) 379661ae650dSJack F Vogel { 379761ae650dSJack F Vogel /* Add broadcast address */ 379856c2c47bSJack F Vogel ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY); 379961ae650dSJack F Vogel } 380061ae650dSJack F Vogel 380161ae650dSJack F Vogel /* 380261ae650dSJack F Vogel ** This routine adds mulicast filters 380361ae650dSJack F Vogel */ 380461ae650dSJack F Vogel static void 380561ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr) 380661ae650dSJack F Vogel { 380761ae650dSJack F Vogel struct ixl_mac_filter *f; 380861ae650dSJack F Vogel 380961ae650dSJack F Vogel /* Does one already exist */ 381061ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 381161ae650dSJack F Vogel if (f != NULL) 381261ae650dSJack F Vogel return; 381361ae650dSJack F Vogel 381461ae650dSJack F Vogel f = ixl_get_filter(vsi); 381561ae650dSJack F Vogel if (f == NULL) { 381661ae650dSJack F Vogel printf("WARNING: no filter available!!\n"); 381761ae650dSJack F Vogel return; 381861ae650dSJack F Vogel } 381961ae650dSJack F Vogel bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 382061ae650dSJack F Vogel f->vlan = IXL_VLAN_ANY; 382161ae650dSJack F Vogel f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED 382261ae650dSJack F Vogel | IXL_FILTER_MC); 382361ae650dSJack F Vogel 382461ae650dSJack F Vogel return; 382561ae650dSJack F Vogel } 382661ae650dSJack F Vogel 382756c2c47bSJack F Vogel static void 382856c2c47bSJack F Vogel ixl_reconfigure_filters(struct ixl_vsi *vsi) 382956c2c47bSJack F Vogel { 383056c2c47bSJack F Vogel 383156c2c47bSJack F Vogel ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs); 383256c2c47bSJack F Vogel } 383356c2c47bSJack F Vogel 383461ae650dSJack F Vogel /* 383561ae650dSJack F Vogel ** This routine adds macvlan filters 383661ae650dSJack F Vogel */ 383761ae650dSJack F Vogel static void 383861ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 383961ae650dSJack F Vogel { 384061ae650dSJack F Vogel struct ixl_mac_filter *f, *tmp; 384156c2c47bSJack F Vogel struct ixl_pf *pf; 384256c2c47bSJack F Vogel device_t dev; 384361ae650dSJack F Vogel 384461ae650dSJack F Vogel DEBUGOUT("ixl_add_filter: begin"); 384561ae650dSJack F Vogel 384656c2c47bSJack F Vogel pf = vsi->back; 384756c2c47bSJack F Vogel dev = pf->dev; 384856c2c47bSJack F Vogel 384961ae650dSJack F Vogel /* Does one already exist */ 385061ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, vlan); 385161ae650dSJack F Vogel if (f != NULL) 385261ae650dSJack F Vogel return; 385361ae650dSJack F Vogel /* 385461ae650dSJack F Vogel ** Is this the first vlan being registered, if so we 385561ae650dSJack F Vogel ** need to remove the ANY filter that indicates we are 385661ae650dSJack F Vogel ** not in a vlan, and replace that with a 0 filter. 385761ae650dSJack F Vogel */ 385861ae650dSJack F Vogel if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) { 385961ae650dSJack F Vogel tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 386061ae650dSJack F Vogel if (tmp != NULL) { 386161ae650dSJack F Vogel ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY); 386261ae650dSJack F Vogel ixl_add_filter(vsi, macaddr, 0); 386361ae650dSJack F Vogel } 386461ae650dSJack F Vogel } 386561ae650dSJack F Vogel 386661ae650dSJack F Vogel f = ixl_get_filter(vsi); 386761ae650dSJack F Vogel if (f == NULL) { 386861ae650dSJack F Vogel device_printf(dev, "WARNING: no filter available!!\n"); 386961ae650dSJack F Vogel return; 387061ae650dSJack F Vogel } 387161ae650dSJack F Vogel bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 387261ae650dSJack F Vogel f->vlan = vlan; 387361ae650dSJack F Vogel f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 387461ae650dSJack F Vogel if (f->vlan != IXL_VLAN_ANY) 387561ae650dSJack F Vogel f->flags |= IXL_FILTER_VLAN; 387656c2c47bSJack F Vogel else 387756c2c47bSJack F Vogel vsi->num_macs++; 387861ae650dSJack F Vogel 387961ae650dSJack F Vogel ixl_add_hw_filters(vsi, f->flags, 1); 388061ae650dSJack F Vogel return; 388161ae650dSJack F Vogel } 388261ae650dSJack F Vogel 388361ae650dSJack F Vogel static void 388461ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 388561ae650dSJack F Vogel { 388661ae650dSJack F Vogel struct ixl_mac_filter *f; 388761ae650dSJack F Vogel 388861ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, vlan); 388961ae650dSJack F Vogel if (f == NULL) 389061ae650dSJack F Vogel return; 389161ae650dSJack F Vogel 389261ae650dSJack F Vogel f->flags |= IXL_FILTER_DEL; 389361ae650dSJack F Vogel ixl_del_hw_filters(vsi, 1); 389456c2c47bSJack F Vogel vsi->num_macs--; 389561ae650dSJack F Vogel 389661ae650dSJack F Vogel /* Check if this is the last vlan removal */ 389761ae650dSJack F Vogel if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) { 389861ae650dSJack F Vogel /* Switch back to a non-vlan filter */ 389961ae650dSJack F Vogel ixl_del_filter(vsi, macaddr, 0); 390061ae650dSJack F Vogel ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY); 390161ae650dSJack F Vogel } 390261ae650dSJack F Vogel return; 390361ae650dSJack F Vogel } 390461ae650dSJack F Vogel 390561ae650dSJack F Vogel /* 390661ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id 390761ae650dSJack F Vogel */ 390861ae650dSJack F Vogel static struct ixl_mac_filter * 390961ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 391061ae650dSJack F Vogel { 391161ae650dSJack F Vogel struct ixl_mac_filter *f; 391261ae650dSJack F Vogel bool match = FALSE; 391361ae650dSJack F Vogel 391461ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 391561ae650dSJack F Vogel if (!cmp_etheraddr(f->macaddr, macaddr)) 391661ae650dSJack F Vogel continue; 391761ae650dSJack F Vogel if (f->vlan == vlan) { 391861ae650dSJack F Vogel match = TRUE; 391961ae650dSJack F Vogel break; 392061ae650dSJack F Vogel } 392161ae650dSJack F Vogel } 392261ae650dSJack F Vogel 392361ae650dSJack F Vogel if (!match) 392461ae650dSJack F Vogel f = NULL; 392561ae650dSJack F Vogel return (f); 392661ae650dSJack F Vogel } 392761ae650dSJack F Vogel 392861ae650dSJack F Vogel /* 392961ae650dSJack F Vogel ** This routine takes additions to the vsi filter 393061ae650dSJack F Vogel ** table and creates an Admin Queue call to create 393161ae650dSJack F Vogel ** the filters in the hardware. 393261ae650dSJack F Vogel */ 393361ae650dSJack F Vogel static void 393461ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt) 393561ae650dSJack F Vogel { 393661ae650dSJack F Vogel struct i40e_aqc_add_macvlan_element_data *a, *b; 393761ae650dSJack F Vogel struct ixl_mac_filter *f; 393856c2c47bSJack F Vogel struct ixl_pf *pf; 393956c2c47bSJack F Vogel struct i40e_hw *hw; 394056c2c47bSJack F Vogel device_t dev; 394161ae650dSJack F Vogel int err, j = 0; 394261ae650dSJack F Vogel 394356c2c47bSJack F Vogel pf = vsi->back; 394456c2c47bSJack F Vogel dev = pf->dev; 394556c2c47bSJack F Vogel hw = &pf->hw; 394656c2c47bSJack F Vogel IXL_PF_LOCK_ASSERT(pf); 394756c2c47bSJack F Vogel 394861ae650dSJack F Vogel a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt, 394961ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 395061ae650dSJack F Vogel if (a == NULL) { 3951393c4bb1SJack F Vogel device_printf(dev, "add_hw_filters failed to get memory\n"); 395261ae650dSJack F Vogel return; 395361ae650dSJack F Vogel } 395461ae650dSJack F Vogel 395561ae650dSJack F Vogel /* 395661ae650dSJack F Vogel ** Scan the filter list, each time we find one 395761ae650dSJack F Vogel ** we add it to the admin queue array and turn off 395861ae650dSJack F Vogel ** the add bit. 395961ae650dSJack F Vogel */ 396061ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 396161ae650dSJack F Vogel if (f->flags == flags) { 396261ae650dSJack F Vogel b = &a[j]; // a pox on fvl long names :) 396361ae650dSJack F Vogel bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN); 396456c2c47bSJack F Vogel if (f->vlan == IXL_VLAN_ANY) { 396556c2c47bSJack F Vogel b->vlan_tag = 0; 396656c2c47bSJack F Vogel b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN; 396756c2c47bSJack F Vogel } else { 396856c2c47bSJack F Vogel b->vlan_tag = f->vlan; 396956c2c47bSJack F Vogel b->flags = 0; 397056c2c47bSJack F Vogel } 397156c2c47bSJack F Vogel b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH; 397261ae650dSJack F Vogel f->flags &= ~IXL_FILTER_ADD; 397361ae650dSJack F Vogel j++; 397461ae650dSJack F Vogel } 397561ae650dSJack F Vogel if (j == cnt) 397661ae650dSJack F Vogel break; 397761ae650dSJack F Vogel } 397861ae650dSJack F Vogel if (j > 0) { 397961ae650dSJack F Vogel err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); 398061ae650dSJack F Vogel if (err) 3981b6c8f260SJack F Vogel device_printf(dev, "aq_add_macvlan err %d, " 3982b6c8f260SJack F Vogel "aq_error %d\n", err, hw->aq.asq_last_status); 398361ae650dSJack F Vogel else 398461ae650dSJack F Vogel vsi->hw_filters_add += j; 398561ae650dSJack F Vogel } 398661ae650dSJack F Vogel free(a, M_DEVBUF); 398761ae650dSJack F Vogel return; 398861ae650dSJack F Vogel } 398961ae650dSJack F Vogel 399061ae650dSJack F Vogel /* 399161ae650dSJack F Vogel ** This routine takes removals in the vsi filter 399261ae650dSJack F Vogel ** table and creates an Admin Queue call to delete 399361ae650dSJack F Vogel ** the filters in the hardware. 399461ae650dSJack F Vogel */ 399561ae650dSJack F Vogel static void 399661ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt) 399761ae650dSJack F Vogel { 399861ae650dSJack F Vogel struct i40e_aqc_remove_macvlan_element_data *d, *e; 399956c2c47bSJack F Vogel struct ixl_pf *pf; 400056c2c47bSJack F Vogel struct i40e_hw *hw; 400156c2c47bSJack F Vogel device_t dev; 400261ae650dSJack F Vogel struct ixl_mac_filter *f, *f_temp; 400361ae650dSJack F Vogel int err, j = 0; 400461ae650dSJack F Vogel 400561ae650dSJack F Vogel DEBUGOUT("ixl_del_hw_filters: begin\n"); 400661ae650dSJack F Vogel 400756c2c47bSJack F Vogel pf = vsi->back; 400856c2c47bSJack F Vogel hw = &pf->hw; 400956c2c47bSJack F Vogel dev = pf->dev; 401056c2c47bSJack F Vogel 401161ae650dSJack F Vogel d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt, 401261ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 401361ae650dSJack F Vogel if (d == NULL) { 401461ae650dSJack F Vogel printf("del hw filter failed to get memory\n"); 401561ae650dSJack F Vogel return; 401661ae650dSJack F Vogel } 401761ae650dSJack F Vogel 401861ae650dSJack F Vogel SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) { 401961ae650dSJack F Vogel if (f->flags & IXL_FILTER_DEL) { 402061ae650dSJack F Vogel e = &d[j]; // a pox on fvl long names :) 402161ae650dSJack F Vogel bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN); 402261ae650dSJack F Vogel e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan); 402361ae650dSJack F Vogel e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; 402461ae650dSJack F Vogel /* delete entry from vsi list */ 402561ae650dSJack F Vogel SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next); 402661ae650dSJack F Vogel free(f, M_DEVBUF); 402761ae650dSJack F Vogel j++; 402861ae650dSJack F Vogel } 402961ae650dSJack F Vogel if (j == cnt) 403061ae650dSJack F Vogel break; 403161ae650dSJack F Vogel } 403261ae650dSJack F Vogel if (j > 0) { 403361ae650dSJack F Vogel err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); 403461ae650dSJack F Vogel /* NOTE: returns ENOENT every time but seems to work fine, 403561ae650dSJack F Vogel so we'll ignore that specific error. */ 4036393c4bb1SJack F Vogel // TODO: Does this still occur on current firmwares? 403761ae650dSJack F Vogel if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { 403861ae650dSJack F Vogel int sc = 0; 403961ae650dSJack F Vogel for (int i = 0; i < j; i++) 404061ae650dSJack F Vogel sc += (!d[i].error_code); 404161ae650dSJack F Vogel vsi->hw_filters_del += sc; 404261ae650dSJack F Vogel device_printf(dev, 404361ae650dSJack F Vogel "Failed to remove %d/%d filters, aq error %d\n", 404461ae650dSJack F Vogel j - sc, j, hw->aq.asq_last_status); 404561ae650dSJack F Vogel } else 404661ae650dSJack F Vogel vsi->hw_filters_del += j; 404761ae650dSJack F Vogel } 404861ae650dSJack F Vogel free(d, M_DEVBUF); 404961ae650dSJack F Vogel 405061ae650dSJack F Vogel DEBUGOUT("ixl_del_hw_filters: end\n"); 405161ae650dSJack F Vogel return; 405261ae650dSJack F Vogel } 405361ae650dSJack F Vogel 405456c2c47bSJack F Vogel static int 405561ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi) 405661ae650dSJack F Vogel { 405756c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 405856c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 405956c2c47bSJack F Vogel int index, error; 406061ae650dSJack F Vogel u32 reg; 406161ae650dSJack F Vogel 406256c2c47bSJack F Vogel error = 0; 406361ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 406456c2c47bSJack F Vogel index = vsi->first_queue + i; 406556c2c47bSJack F Vogel i40e_pre_tx_queue_cfg(hw, index, TRUE); 406661ae650dSJack F Vogel 406756c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 406861ae650dSJack F Vogel reg |= I40E_QTX_ENA_QENA_REQ_MASK | 406961ae650dSJack F Vogel I40E_QTX_ENA_QENA_STAT_MASK; 407056c2c47bSJack F Vogel wr32(hw, I40E_QTX_ENA(index), reg); 407161ae650dSJack F Vogel /* Verify the enable took */ 407261ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 407356c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 407461ae650dSJack F Vogel if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 407561ae650dSJack F Vogel break; 407661ae650dSJack F Vogel i40e_msec_delay(10); 407761ae650dSJack F Vogel } 407856c2c47bSJack F Vogel if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) { 407956c2c47bSJack F Vogel device_printf(pf->dev, "TX queue %d disabled!\n", 408056c2c47bSJack F Vogel index); 408156c2c47bSJack F Vogel error = ETIMEDOUT; 408256c2c47bSJack F Vogel } 408361ae650dSJack F Vogel 408456c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 408561ae650dSJack F Vogel reg |= I40E_QRX_ENA_QENA_REQ_MASK | 408661ae650dSJack F Vogel I40E_QRX_ENA_QENA_STAT_MASK; 408756c2c47bSJack F Vogel wr32(hw, I40E_QRX_ENA(index), reg); 408861ae650dSJack F Vogel /* Verify the enable took */ 408961ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 409056c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 409161ae650dSJack F Vogel if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 409261ae650dSJack F Vogel break; 409361ae650dSJack F Vogel i40e_msec_delay(10); 409461ae650dSJack F Vogel } 409556c2c47bSJack F Vogel if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) { 409656c2c47bSJack F Vogel device_printf(pf->dev, "RX queue %d disabled!\n", 409756c2c47bSJack F Vogel index); 409856c2c47bSJack F Vogel error = ETIMEDOUT; 409961ae650dSJack F Vogel } 410061ae650dSJack F Vogel } 410161ae650dSJack F Vogel 410256c2c47bSJack F Vogel return (error); 410356c2c47bSJack F Vogel } 410456c2c47bSJack F Vogel 410556c2c47bSJack F Vogel static int 410661ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi) 410761ae650dSJack F Vogel { 410856c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 410956c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 411056c2c47bSJack F Vogel int index, error; 411161ae650dSJack F Vogel u32 reg; 411261ae650dSJack F Vogel 411356c2c47bSJack F Vogel error = 0; 411461ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 411556c2c47bSJack F Vogel index = vsi->first_queue + i; 411656c2c47bSJack F Vogel 411756c2c47bSJack F Vogel i40e_pre_tx_queue_cfg(hw, index, FALSE); 411861ae650dSJack F Vogel i40e_usec_delay(500); 411961ae650dSJack F Vogel 412056c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 412161ae650dSJack F Vogel reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; 412256c2c47bSJack F Vogel wr32(hw, I40E_QTX_ENA(index), reg); 412361ae650dSJack F Vogel /* Verify the disable took */ 412461ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 412556c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 412661ae650dSJack F Vogel if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK)) 412761ae650dSJack F Vogel break; 412861ae650dSJack F Vogel i40e_msec_delay(10); 412961ae650dSJack F Vogel } 413056c2c47bSJack F Vogel if (reg & I40E_QTX_ENA_QENA_STAT_MASK) { 413156c2c47bSJack F Vogel device_printf(pf->dev, "TX queue %d still enabled!\n", 413256c2c47bSJack F Vogel index); 413356c2c47bSJack F Vogel error = ETIMEDOUT; 413456c2c47bSJack F Vogel } 413561ae650dSJack F Vogel 413656c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 413761ae650dSJack F Vogel reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; 413856c2c47bSJack F Vogel wr32(hw, I40E_QRX_ENA(index), reg); 413961ae650dSJack F Vogel /* Verify the disable took */ 414061ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 414156c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 414261ae650dSJack F Vogel if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK)) 414361ae650dSJack F Vogel break; 414461ae650dSJack F Vogel i40e_msec_delay(10); 414561ae650dSJack F Vogel } 414656c2c47bSJack F Vogel if (reg & I40E_QRX_ENA_QENA_STAT_MASK) { 414756c2c47bSJack F Vogel device_printf(pf->dev, "RX queue %d still enabled!\n", 414856c2c47bSJack F Vogel index); 414956c2c47bSJack F Vogel error = ETIMEDOUT; 415061ae650dSJack F Vogel } 415161ae650dSJack F Vogel } 415261ae650dSJack F Vogel 415356c2c47bSJack F Vogel return (error); 415456c2c47bSJack F Vogel } 415556c2c47bSJack F Vogel 415661ae650dSJack F Vogel /** 415761ae650dSJack F Vogel * ixl_handle_mdd_event 415861ae650dSJack F Vogel * 415961ae650dSJack F Vogel * Called from interrupt handler to identify possibly malicious vfs 416061ae650dSJack F Vogel * (But also detects events from the PF, as well) 416161ae650dSJack F Vogel **/ 416261ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *pf) 416361ae650dSJack F Vogel { 416461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 416561ae650dSJack F Vogel device_t dev = pf->dev; 416661ae650dSJack F Vogel bool mdd_detected = false; 416761ae650dSJack F Vogel bool pf_mdd_detected = false; 416861ae650dSJack F Vogel u32 reg; 416961ae650dSJack F Vogel 417061ae650dSJack F Vogel /* find what triggered the MDD event */ 417161ae650dSJack F Vogel reg = rd32(hw, I40E_GL_MDET_TX); 417261ae650dSJack F Vogel if (reg & I40E_GL_MDET_TX_VALID_MASK) { 417361ae650dSJack F Vogel u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >> 417461ae650dSJack F Vogel I40E_GL_MDET_TX_PF_NUM_SHIFT; 417561ae650dSJack F Vogel u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >> 417661ae650dSJack F Vogel I40E_GL_MDET_TX_EVENT_SHIFT; 417761ae650dSJack F Vogel u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >> 417861ae650dSJack F Vogel I40E_GL_MDET_TX_QUEUE_SHIFT; 417961ae650dSJack F Vogel device_printf(dev, 418061ae650dSJack F Vogel "Malicious Driver Detection event 0x%02x" 418161ae650dSJack F Vogel " on TX queue %d pf number 0x%02x\n", 418261ae650dSJack F Vogel event, queue, pf_num); 418361ae650dSJack F Vogel wr32(hw, I40E_GL_MDET_TX, 0xffffffff); 418461ae650dSJack F Vogel mdd_detected = true; 418561ae650dSJack F Vogel } 418661ae650dSJack F Vogel reg = rd32(hw, I40E_GL_MDET_RX); 418761ae650dSJack F Vogel if (reg & I40E_GL_MDET_RX_VALID_MASK) { 418861ae650dSJack F Vogel u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >> 418961ae650dSJack F Vogel I40E_GL_MDET_RX_FUNCTION_SHIFT; 419061ae650dSJack F Vogel u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >> 419161ae650dSJack F Vogel I40E_GL_MDET_RX_EVENT_SHIFT; 419261ae650dSJack F Vogel u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >> 419361ae650dSJack F Vogel I40E_GL_MDET_RX_QUEUE_SHIFT; 419461ae650dSJack F Vogel device_printf(dev, 419561ae650dSJack F Vogel "Malicious Driver Detection event 0x%02x" 419661ae650dSJack F Vogel " on RX queue %d of function 0x%02x\n", 419761ae650dSJack F Vogel event, queue, func); 419861ae650dSJack F Vogel wr32(hw, I40E_GL_MDET_RX, 0xffffffff); 419961ae650dSJack F Vogel mdd_detected = true; 420061ae650dSJack F Vogel } 420161ae650dSJack F Vogel 420261ae650dSJack F Vogel if (mdd_detected) { 420361ae650dSJack F Vogel reg = rd32(hw, I40E_PF_MDET_TX); 420461ae650dSJack F Vogel if (reg & I40E_PF_MDET_TX_VALID_MASK) { 420561ae650dSJack F Vogel wr32(hw, I40E_PF_MDET_TX, 0xFFFF); 420661ae650dSJack F Vogel device_printf(dev, 420761ae650dSJack F Vogel "MDD TX event is for this function 0x%08x", 420861ae650dSJack F Vogel reg); 420961ae650dSJack F Vogel pf_mdd_detected = true; 421061ae650dSJack F Vogel } 421161ae650dSJack F Vogel reg = rd32(hw, I40E_PF_MDET_RX); 421261ae650dSJack F Vogel if (reg & I40E_PF_MDET_RX_VALID_MASK) { 421361ae650dSJack F Vogel wr32(hw, I40E_PF_MDET_RX, 0xFFFF); 421461ae650dSJack F Vogel device_printf(dev, 421561ae650dSJack F Vogel "MDD RX event is for this function 0x%08x", 421661ae650dSJack F Vogel reg); 421761ae650dSJack F Vogel pf_mdd_detected = true; 421861ae650dSJack F Vogel } 421961ae650dSJack F Vogel } 422061ae650dSJack F Vogel 422161ae650dSJack F Vogel /* re-enable mdd interrupt cause */ 422261ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0_ENA); 422361ae650dSJack F Vogel reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 422461ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 422561ae650dSJack F Vogel ixl_flush(hw); 422661ae650dSJack F Vogel } 422761ae650dSJack F Vogel 422861ae650dSJack F Vogel static void 422961ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi) 423061ae650dSJack F Vogel { 423161ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 423261ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 423361ae650dSJack F Vogel 423461ae650dSJack F Vogel if (ixl_enable_msix) { 423561ae650dSJack F Vogel ixl_enable_adminq(hw); 423661ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) 423761ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 423861ae650dSJack F Vogel } else 423961ae650dSJack F Vogel ixl_enable_legacy(hw); 424061ae650dSJack F Vogel } 424161ae650dSJack F Vogel 424261ae650dSJack F Vogel static void 424356c2c47bSJack F Vogel ixl_disable_rings_intr(struct ixl_vsi *vsi) 424461ae650dSJack F Vogel { 424561ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 424661ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 424761ae650dSJack F Vogel 424861ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) 424961ae650dSJack F Vogel ixl_disable_queue(hw, que->me); 425056c2c47bSJack F Vogel } 425156c2c47bSJack F Vogel 425256c2c47bSJack F Vogel static void 425356c2c47bSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi) 425456c2c47bSJack F Vogel { 425556c2c47bSJack F Vogel struct i40e_hw *hw = vsi->hw; 425656c2c47bSJack F Vogel 425756c2c47bSJack F Vogel if (ixl_enable_msix) 425856c2c47bSJack F Vogel ixl_disable_adminq(hw); 425956c2c47bSJack F Vogel else 426061ae650dSJack F Vogel ixl_disable_legacy(hw); 426161ae650dSJack F Vogel } 426261ae650dSJack F Vogel 426361ae650dSJack F Vogel static void 426461ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw) 426561ae650dSJack F Vogel { 426661ae650dSJack F Vogel u32 reg; 426761ae650dSJack F Vogel 426861ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 426961ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 427061ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 427161ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 427261ae650dSJack F Vogel ixl_flush(hw); 427361ae650dSJack F Vogel } 427461ae650dSJack F Vogel 427561ae650dSJack F Vogel static void 427661ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw) 427761ae650dSJack F Vogel { 427861ae650dSJack F Vogel u32 reg; 427961ae650dSJack F Vogel 428061ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 428161ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 4282223d846dSEric Joyner ixl_flush(hw); 428361ae650dSJack F Vogel } 428461ae650dSJack F Vogel 428561ae650dSJack F Vogel static void 428661ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id) 428761ae650dSJack F Vogel { 428861ae650dSJack F Vogel u32 reg; 428961ae650dSJack F Vogel 429061ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTLN_INTENA_MASK | 429161ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | 429261ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); 429361ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 429461ae650dSJack F Vogel } 429561ae650dSJack F Vogel 429661ae650dSJack F Vogel static void 429761ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id) 429861ae650dSJack F Vogel { 429961ae650dSJack F Vogel u32 reg; 430061ae650dSJack F Vogel 430161ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; 430261ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 430361ae650dSJack F Vogel } 430461ae650dSJack F Vogel 430561ae650dSJack F Vogel static void 430661ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw) 430761ae650dSJack F Vogel { 430861ae650dSJack F Vogel u32 reg; 430961ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 431061ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 431161ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 431261ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 431361ae650dSJack F Vogel } 431461ae650dSJack F Vogel 431561ae650dSJack F Vogel static void 431661ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw) 431761ae650dSJack F Vogel { 431861ae650dSJack F Vogel u32 reg; 431961ae650dSJack F Vogel 432061ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 432161ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 432261ae650dSJack F Vogel } 432361ae650dSJack F Vogel 432461ae650dSJack F Vogel static void 432561ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf) 432661ae650dSJack F Vogel { 432761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 432861ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 432956c2c47bSJack F Vogel struct ixl_vf *vf; 433061ae650dSJack F Vogel 433161ae650dSJack F Vogel struct i40e_hw_port_stats *nsd = &pf->stats; 433261ae650dSJack F Vogel struct i40e_hw_port_stats *osd = &pf->stats_offsets; 433361ae650dSJack F Vogel 433461ae650dSJack F Vogel /* Update hw stats */ 433561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port), 433661ae650dSJack F Vogel pf->stat_offsets_loaded, 433761ae650dSJack F Vogel &osd->crc_errors, &nsd->crc_errors); 433861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port), 433961ae650dSJack F Vogel pf->stat_offsets_loaded, 434061ae650dSJack F Vogel &osd->illegal_bytes, &nsd->illegal_bytes); 434161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port), 434261ae650dSJack F Vogel I40E_GLPRT_GORCL(hw->port), 434361ae650dSJack F Vogel pf->stat_offsets_loaded, 434461ae650dSJack F Vogel &osd->eth.rx_bytes, &nsd->eth.rx_bytes); 434561ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port), 434661ae650dSJack F Vogel I40E_GLPRT_GOTCL(hw->port), 434761ae650dSJack F Vogel pf->stat_offsets_loaded, 434861ae650dSJack F Vogel &osd->eth.tx_bytes, &nsd->eth.tx_bytes); 434961ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port), 435061ae650dSJack F Vogel pf->stat_offsets_loaded, 435161ae650dSJack F Vogel &osd->eth.rx_discards, 435261ae650dSJack F Vogel &nsd->eth.rx_discards); 435361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port), 435461ae650dSJack F Vogel I40E_GLPRT_UPRCL(hw->port), 435561ae650dSJack F Vogel pf->stat_offsets_loaded, 435661ae650dSJack F Vogel &osd->eth.rx_unicast, 435761ae650dSJack F Vogel &nsd->eth.rx_unicast); 435861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port), 435961ae650dSJack F Vogel I40E_GLPRT_UPTCL(hw->port), 436061ae650dSJack F Vogel pf->stat_offsets_loaded, 436161ae650dSJack F Vogel &osd->eth.tx_unicast, 436261ae650dSJack F Vogel &nsd->eth.tx_unicast); 436361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port), 436461ae650dSJack F Vogel I40E_GLPRT_MPRCL(hw->port), 436561ae650dSJack F Vogel pf->stat_offsets_loaded, 436661ae650dSJack F Vogel &osd->eth.rx_multicast, 436761ae650dSJack F Vogel &nsd->eth.rx_multicast); 436861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port), 436961ae650dSJack F Vogel I40E_GLPRT_MPTCL(hw->port), 437061ae650dSJack F Vogel pf->stat_offsets_loaded, 437161ae650dSJack F Vogel &osd->eth.tx_multicast, 437261ae650dSJack F Vogel &nsd->eth.tx_multicast); 437361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port), 437461ae650dSJack F Vogel I40E_GLPRT_BPRCL(hw->port), 437561ae650dSJack F Vogel pf->stat_offsets_loaded, 437661ae650dSJack F Vogel &osd->eth.rx_broadcast, 437761ae650dSJack F Vogel &nsd->eth.rx_broadcast); 437861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port), 437961ae650dSJack F Vogel I40E_GLPRT_BPTCL(hw->port), 438061ae650dSJack F Vogel pf->stat_offsets_loaded, 438161ae650dSJack F Vogel &osd->eth.tx_broadcast, 438261ae650dSJack F Vogel &nsd->eth.tx_broadcast); 438361ae650dSJack F Vogel 438461ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port), 438561ae650dSJack F Vogel pf->stat_offsets_loaded, 438661ae650dSJack F Vogel &osd->tx_dropped_link_down, 438761ae650dSJack F Vogel &nsd->tx_dropped_link_down); 438861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port), 438961ae650dSJack F Vogel pf->stat_offsets_loaded, 439061ae650dSJack F Vogel &osd->mac_local_faults, 439161ae650dSJack F Vogel &nsd->mac_local_faults); 439261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port), 439361ae650dSJack F Vogel pf->stat_offsets_loaded, 439461ae650dSJack F Vogel &osd->mac_remote_faults, 439561ae650dSJack F Vogel &nsd->mac_remote_faults); 439661ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port), 439761ae650dSJack F Vogel pf->stat_offsets_loaded, 439861ae650dSJack F Vogel &osd->rx_length_errors, 439961ae650dSJack F Vogel &nsd->rx_length_errors); 440061ae650dSJack F Vogel 440161ae650dSJack F Vogel /* Flow control (LFC) stats */ 440261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port), 440361ae650dSJack F Vogel pf->stat_offsets_loaded, 440461ae650dSJack F Vogel &osd->link_xon_rx, &nsd->link_xon_rx); 440561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port), 440661ae650dSJack F Vogel pf->stat_offsets_loaded, 440761ae650dSJack F Vogel &osd->link_xon_tx, &nsd->link_xon_tx); 440861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port), 440961ae650dSJack F Vogel pf->stat_offsets_loaded, 441061ae650dSJack F Vogel &osd->link_xoff_rx, &nsd->link_xoff_rx); 441161ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port), 441261ae650dSJack F Vogel pf->stat_offsets_loaded, 441361ae650dSJack F Vogel &osd->link_xoff_tx, &nsd->link_xoff_tx); 441461ae650dSJack F Vogel 441561ae650dSJack F Vogel /* Packet size stats rx */ 441661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port), 441761ae650dSJack F Vogel I40E_GLPRT_PRC64L(hw->port), 441861ae650dSJack F Vogel pf->stat_offsets_loaded, 441961ae650dSJack F Vogel &osd->rx_size_64, &nsd->rx_size_64); 442061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port), 442161ae650dSJack F Vogel I40E_GLPRT_PRC127L(hw->port), 442261ae650dSJack F Vogel pf->stat_offsets_loaded, 442361ae650dSJack F Vogel &osd->rx_size_127, &nsd->rx_size_127); 442461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port), 442561ae650dSJack F Vogel I40E_GLPRT_PRC255L(hw->port), 442661ae650dSJack F Vogel pf->stat_offsets_loaded, 442761ae650dSJack F Vogel &osd->rx_size_255, &nsd->rx_size_255); 442861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port), 442961ae650dSJack F Vogel I40E_GLPRT_PRC511L(hw->port), 443061ae650dSJack F Vogel pf->stat_offsets_loaded, 443161ae650dSJack F Vogel &osd->rx_size_511, &nsd->rx_size_511); 443261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port), 443361ae650dSJack F Vogel I40E_GLPRT_PRC1023L(hw->port), 443461ae650dSJack F Vogel pf->stat_offsets_loaded, 443561ae650dSJack F Vogel &osd->rx_size_1023, &nsd->rx_size_1023); 443661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port), 443761ae650dSJack F Vogel I40E_GLPRT_PRC1522L(hw->port), 443861ae650dSJack F Vogel pf->stat_offsets_loaded, 443961ae650dSJack F Vogel &osd->rx_size_1522, &nsd->rx_size_1522); 444061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port), 444161ae650dSJack F Vogel I40E_GLPRT_PRC9522L(hw->port), 444261ae650dSJack F Vogel pf->stat_offsets_loaded, 444361ae650dSJack F Vogel &osd->rx_size_big, &nsd->rx_size_big); 444461ae650dSJack F Vogel 444561ae650dSJack F Vogel /* Packet size stats tx */ 444661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port), 444761ae650dSJack F Vogel I40E_GLPRT_PTC64L(hw->port), 444861ae650dSJack F Vogel pf->stat_offsets_loaded, 444961ae650dSJack F Vogel &osd->tx_size_64, &nsd->tx_size_64); 445061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port), 445161ae650dSJack F Vogel I40E_GLPRT_PTC127L(hw->port), 445261ae650dSJack F Vogel pf->stat_offsets_loaded, 445361ae650dSJack F Vogel &osd->tx_size_127, &nsd->tx_size_127); 445461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port), 445561ae650dSJack F Vogel I40E_GLPRT_PTC255L(hw->port), 445661ae650dSJack F Vogel pf->stat_offsets_loaded, 445761ae650dSJack F Vogel &osd->tx_size_255, &nsd->tx_size_255); 445861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port), 445961ae650dSJack F Vogel I40E_GLPRT_PTC511L(hw->port), 446061ae650dSJack F Vogel pf->stat_offsets_loaded, 446161ae650dSJack F Vogel &osd->tx_size_511, &nsd->tx_size_511); 446261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port), 446361ae650dSJack F Vogel I40E_GLPRT_PTC1023L(hw->port), 446461ae650dSJack F Vogel pf->stat_offsets_loaded, 446561ae650dSJack F Vogel &osd->tx_size_1023, &nsd->tx_size_1023); 446661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port), 446761ae650dSJack F Vogel I40E_GLPRT_PTC1522L(hw->port), 446861ae650dSJack F Vogel pf->stat_offsets_loaded, 446961ae650dSJack F Vogel &osd->tx_size_1522, &nsd->tx_size_1522); 447061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port), 447161ae650dSJack F Vogel I40E_GLPRT_PTC9522L(hw->port), 447261ae650dSJack F Vogel pf->stat_offsets_loaded, 447361ae650dSJack F Vogel &osd->tx_size_big, &nsd->tx_size_big); 447461ae650dSJack F Vogel 447561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port), 447661ae650dSJack F Vogel pf->stat_offsets_loaded, 447761ae650dSJack F Vogel &osd->rx_undersize, &nsd->rx_undersize); 447861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port), 447961ae650dSJack F Vogel pf->stat_offsets_loaded, 448061ae650dSJack F Vogel &osd->rx_fragments, &nsd->rx_fragments); 448161ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port), 448261ae650dSJack F Vogel pf->stat_offsets_loaded, 448361ae650dSJack F Vogel &osd->rx_oversize, &nsd->rx_oversize); 448461ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port), 448561ae650dSJack F Vogel pf->stat_offsets_loaded, 448661ae650dSJack F Vogel &osd->rx_jabber, &nsd->rx_jabber); 448761ae650dSJack F Vogel pf->stat_offsets_loaded = true; 448861ae650dSJack F Vogel /* End hw stats */ 448961ae650dSJack F Vogel 449061ae650dSJack F Vogel /* Update vsi stats */ 449156c2c47bSJack F Vogel ixl_update_vsi_stats(vsi); 449261ae650dSJack F Vogel 449356c2c47bSJack F Vogel for (int i = 0; i < pf->num_vfs; i++) { 449456c2c47bSJack F Vogel vf = &pf->vfs[i]; 449556c2c47bSJack F Vogel if (vf->vf_flags & VF_FLAG_ENABLED) 449656c2c47bSJack F Vogel ixl_update_eth_stats(&pf->vfs[i].vsi); 449756c2c47bSJack F Vogel } 449861ae650dSJack F Vogel } 449961ae650dSJack F Vogel 450061ae650dSJack F Vogel /* 450161ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts 450261ae650dSJack F Vogel ** - do outside interrupt since it might sleep 450361ae650dSJack F Vogel */ 450461ae650dSJack F Vogel static void 450561ae650dSJack F Vogel ixl_do_adminq(void *context, int pending) 450661ae650dSJack F Vogel { 450761ae650dSJack F Vogel struct ixl_pf *pf = context; 450861ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 450961ae650dSJack F Vogel struct i40e_arq_event_info event; 451061ae650dSJack F Vogel i40e_status ret; 4511223d846dSEric Joyner device_t dev = pf->dev; 4512*fdb6f38aSEric Joyner u32 reg, loop = 0; 451361ae650dSJack F Vogel u16 opcode, result; 451461ae650dSJack F Vogel 4515*fdb6f38aSEric Joyner // XXX: Possibly inappropriate overload 4516*fdb6f38aSEric Joyner if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { 4517*fdb6f38aSEric Joyner int count = 0; 4518*fdb6f38aSEric Joyner // ERJ: Typically finishes within 3-4 seconds 4519*fdb6f38aSEric Joyner while (count++ < 100) { 4520*fdb6f38aSEric Joyner reg = rd32(hw, I40E_GLGEN_RSTAT); 4521*fdb6f38aSEric Joyner reg = reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK; 4522*fdb6f38aSEric Joyner if (reg) { 4523*fdb6f38aSEric Joyner i40e_msec_delay(100); 4524*fdb6f38aSEric Joyner } else { 4525*fdb6f38aSEric Joyner break; 4526*fdb6f38aSEric Joyner } 4527*fdb6f38aSEric Joyner } 4528*fdb6f38aSEric Joyner device_printf(dev, "EMPR reset wait count: %d\n", count); 4529*fdb6f38aSEric Joyner 4530*fdb6f38aSEric Joyner device_printf(dev, "Rebuilding HW structs...\n"); 4531*fdb6f38aSEric Joyner // XXX: I feel like this could cause a kernel panic some time in the future 4532*fdb6f38aSEric Joyner ixl_stop(pf); 4533*fdb6f38aSEric Joyner ixl_init(pf); 4534*fdb6f38aSEric Joyner 4535*fdb6f38aSEric Joyner atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); 4536*fdb6f38aSEric Joyner return; 4537*fdb6f38aSEric Joyner } 4538*fdb6f38aSEric Joyner 4539*fdb6f38aSEric Joyner // Actually do Admin Queue handling 4540e5100ee2SJack F Vogel event.buf_len = IXL_AQ_BUF_SZ; 4541e5100ee2SJack F Vogel event.msg_buf = malloc(event.buf_len, 454261ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 454361ae650dSJack F Vogel if (!event.msg_buf) { 4544223d846dSEric Joyner device_printf(dev, "%s: Unable to allocate memory for Admin" 4545223d846dSEric Joyner " Queue event!\n", __func__); 454661ae650dSJack F Vogel return; 454761ae650dSJack F Vogel } 454861ae650dSJack F Vogel 454956c2c47bSJack F Vogel IXL_PF_LOCK(pf); 455061ae650dSJack F Vogel /* clean and process any events */ 455161ae650dSJack F Vogel do { 455261ae650dSJack F Vogel ret = i40e_clean_arq_element(hw, &event, &result); 455361ae650dSJack F Vogel if (ret) 455461ae650dSJack F Vogel break; 455561ae650dSJack F Vogel opcode = LE16_TO_CPU(event.desc.opcode); 4556223d846dSEric Joyner #ifdef IXL_DEBUG 4557223d846dSEric Joyner device_printf(dev, "%s: Admin Queue event: %#06x\n", __func__, opcode); 4558223d846dSEric Joyner #endif 455961ae650dSJack F Vogel switch (opcode) { 456061ae650dSJack F Vogel case i40e_aqc_opc_get_link_status: 456156c2c47bSJack F Vogel ixl_link_event(pf, &event); 456261ae650dSJack F Vogel break; 456361ae650dSJack F Vogel case i40e_aqc_opc_send_msg_to_pf: 456456c2c47bSJack F Vogel #ifdef PCI_IOV 456556c2c47bSJack F Vogel ixl_handle_vf_msg(pf, &event); 456656c2c47bSJack F Vogel #endif 456761ae650dSJack F Vogel break; 456861ae650dSJack F Vogel case i40e_aqc_opc_event_lan_overflow: 456961ae650dSJack F Vogel default: 457061ae650dSJack F Vogel break; 457161ae650dSJack F Vogel } 457261ae650dSJack F Vogel 457361ae650dSJack F Vogel } while (result && (loop++ < IXL_ADM_LIMIT)); 457461ae650dSJack F Vogel 457561ae650dSJack F Vogel free(event.msg_buf, M_DEVBUF); 457661ae650dSJack F Vogel 457756c2c47bSJack F Vogel /* 457856c2c47bSJack F Vogel * If there are still messages to process, reschedule ourselves. 457956c2c47bSJack F Vogel * Otherwise, re-enable our interrupt and go to sleep. 458056c2c47bSJack F Vogel */ 458156c2c47bSJack F Vogel if (result > 0) 458256c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 458361ae650dSJack F Vogel else 4584223d846dSEric Joyner ixl_enable_adminq(hw); 458556c2c47bSJack F Vogel 458656c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 458761ae650dSJack F Vogel } 458861ae650dSJack F Vogel 458961ae650dSJack F Vogel static int 459061ae650dSJack F Vogel ixl_debug_info(SYSCTL_HANDLER_ARGS) 459161ae650dSJack F Vogel { 459261ae650dSJack F Vogel struct ixl_pf *pf; 459361ae650dSJack F Vogel int error, input = 0; 459461ae650dSJack F Vogel 459561ae650dSJack F Vogel error = sysctl_handle_int(oidp, &input, 0, req); 459661ae650dSJack F Vogel 459761ae650dSJack F Vogel if (error || !req->newptr) 459861ae650dSJack F Vogel return (error); 459961ae650dSJack F Vogel 460061ae650dSJack F Vogel if (input == 1) { 460161ae650dSJack F Vogel pf = (struct ixl_pf *)arg1; 460261ae650dSJack F Vogel ixl_print_debug_info(pf); 460361ae650dSJack F Vogel } 460461ae650dSJack F Vogel 460561ae650dSJack F Vogel return (error); 460661ae650dSJack F Vogel } 460761ae650dSJack F Vogel 460861ae650dSJack F Vogel static void 460961ae650dSJack F Vogel ixl_print_debug_info(struct ixl_pf *pf) 461061ae650dSJack F Vogel { 461161ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 461261ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 461361ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 461461ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 461561ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 461661ae650dSJack F Vogel u32 reg; 461761ae650dSJack F Vogel 461861ae650dSJack F Vogel 4619ff21e856SBjoern A. Zeeb printf("Queue irqs = %jx\n", (uintmax_t)que->irqs); 4620ff21e856SBjoern A. Zeeb printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq); 462161ae650dSJack F Vogel printf("RX next check = %x\n", rxr->next_check); 4622ff21e856SBjoern A. Zeeb printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done); 4623ff21e856SBjoern A. Zeeb printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets); 462461ae650dSJack F Vogel printf("TX desc avail = %x\n", txr->avail); 462561ae650dSJack F Vogel 462661ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_GORCL(0xc)); 462761ae650dSJack F Vogel printf("RX Bytes = %x\n", reg); 462861ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_GORCL(hw->port)); 462961ae650dSJack F Vogel printf("Port RX Bytes = %x\n", reg); 463061ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_RDPC(0xc)); 463161ae650dSJack F Vogel printf("RX discard = %x\n", reg); 463261ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RDPC(hw->port)); 463361ae650dSJack F Vogel printf("Port RX discard = %x\n", reg); 463461ae650dSJack F Vogel 463561ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_TEPC(0xc)); 463661ae650dSJack F Vogel printf("TX errors = %x\n", reg); 463761ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_GOTCL(0xc)); 463861ae650dSJack F Vogel printf("TX Bytes = %x\n", reg); 463961ae650dSJack F Vogel 464061ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RUC(hw->port)); 464161ae650dSJack F Vogel printf("RX undersize = %x\n", reg); 464261ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RFC(hw->port)); 464361ae650dSJack F Vogel printf("RX fragments = %x\n", reg); 464461ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_ROC(hw->port)); 464561ae650dSJack F Vogel printf("RX oversize = %x\n", reg); 464661ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RLEC(hw->port)); 464761ae650dSJack F Vogel printf("RX length error = %x\n", reg); 464861ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_MRFC(hw->port)); 464961ae650dSJack F Vogel printf("mac remote fault = %x\n", reg); 465061ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_MLFC(hw->port)); 465161ae650dSJack F Vogel printf("mac local fault = %x\n", reg); 465261ae650dSJack F Vogel } 465361ae650dSJack F Vogel 465461ae650dSJack F Vogel /** 465561ae650dSJack F Vogel * Update VSI-specific ethernet statistics counters. 465661ae650dSJack F Vogel **/ 465761ae650dSJack F Vogel void ixl_update_eth_stats(struct ixl_vsi *vsi) 465861ae650dSJack F Vogel { 465961ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 466061ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 466161ae650dSJack F Vogel struct i40e_eth_stats *es; 466261ae650dSJack F Vogel struct i40e_eth_stats *oes; 46634b443922SGleb Smirnoff struct i40e_hw_port_stats *nsd; 466461ae650dSJack F Vogel u16 stat_idx = vsi->info.stat_counter_idx; 466561ae650dSJack F Vogel 466661ae650dSJack F Vogel es = &vsi->eth_stats; 466761ae650dSJack F Vogel oes = &vsi->eth_stats_offsets; 46684b443922SGleb Smirnoff nsd = &pf->stats; 466961ae650dSJack F Vogel 467061ae650dSJack F Vogel /* Gather up the stats that the hw collects */ 467161ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx), 467261ae650dSJack F Vogel vsi->stat_offsets_loaded, 467361ae650dSJack F Vogel &oes->tx_errors, &es->tx_errors); 467461ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx), 467561ae650dSJack F Vogel vsi->stat_offsets_loaded, 467661ae650dSJack F Vogel &oes->rx_discards, &es->rx_discards); 467761ae650dSJack F Vogel 467861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx), 467961ae650dSJack F Vogel I40E_GLV_GORCL(stat_idx), 468061ae650dSJack F Vogel vsi->stat_offsets_loaded, 468161ae650dSJack F Vogel &oes->rx_bytes, &es->rx_bytes); 468261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx), 468361ae650dSJack F Vogel I40E_GLV_UPRCL(stat_idx), 468461ae650dSJack F Vogel vsi->stat_offsets_loaded, 468561ae650dSJack F Vogel &oes->rx_unicast, &es->rx_unicast); 468661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx), 468761ae650dSJack F Vogel I40E_GLV_MPRCL(stat_idx), 468861ae650dSJack F Vogel vsi->stat_offsets_loaded, 468961ae650dSJack F Vogel &oes->rx_multicast, &es->rx_multicast); 469061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx), 469161ae650dSJack F Vogel I40E_GLV_BPRCL(stat_idx), 469261ae650dSJack F Vogel vsi->stat_offsets_loaded, 469361ae650dSJack F Vogel &oes->rx_broadcast, &es->rx_broadcast); 469461ae650dSJack F Vogel 469561ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx), 469661ae650dSJack F Vogel I40E_GLV_GOTCL(stat_idx), 469761ae650dSJack F Vogel vsi->stat_offsets_loaded, 469861ae650dSJack F Vogel &oes->tx_bytes, &es->tx_bytes); 469961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx), 470061ae650dSJack F Vogel I40E_GLV_UPTCL(stat_idx), 470161ae650dSJack F Vogel vsi->stat_offsets_loaded, 470261ae650dSJack F Vogel &oes->tx_unicast, &es->tx_unicast); 470361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx), 470461ae650dSJack F Vogel I40E_GLV_MPTCL(stat_idx), 470561ae650dSJack F Vogel vsi->stat_offsets_loaded, 470661ae650dSJack F Vogel &oes->tx_multicast, &es->tx_multicast); 470761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx), 470861ae650dSJack F Vogel I40E_GLV_BPTCL(stat_idx), 470961ae650dSJack F Vogel vsi->stat_offsets_loaded, 471061ae650dSJack F Vogel &oes->tx_broadcast, &es->tx_broadcast); 471161ae650dSJack F Vogel vsi->stat_offsets_loaded = true; 471256c2c47bSJack F Vogel } 471356c2c47bSJack F Vogel 471456c2c47bSJack F Vogel static void 471556c2c47bSJack F Vogel ixl_update_vsi_stats(struct ixl_vsi *vsi) 471656c2c47bSJack F Vogel { 471756c2c47bSJack F Vogel struct ixl_pf *pf; 471856c2c47bSJack F Vogel struct ifnet *ifp; 471956c2c47bSJack F Vogel struct i40e_eth_stats *es; 472056c2c47bSJack F Vogel u64 tx_discards; 472156c2c47bSJack F Vogel 472256c2c47bSJack F Vogel struct i40e_hw_port_stats *nsd; 472356c2c47bSJack F Vogel 472456c2c47bSJack F Vogel pf = vsi->back; 472556c2c47bSJack F Vogel ifp = vsi->ifp; 472656c2c47bSJack F Vogel es = &vsi->eth_stats; 472756c2c47bSJack F Vogel nsd = &pf->stats; 472856c2c47bSJack F Vogel 472956c2c47bSJack F Vogel ixl_update_eth_stats(vsi); 473061ae650dSJack F Vogel 47314b443922SGleb Smirnoff tx_discards = es->tx_discards + nsd->tx_dropped_link_down; 473256c2c47bSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) 47334b443922SGleb Smirnoff tx_discards += vsi->queues[i].txr.br->br_drops; 473461ae650dSJack F Vogel 47354b443922SGleb Smirnoff /* Update ifnet stats */ 47364b443922SGleb Smirnoff IXL_SET_IPACKETS(vsi, es->rx_unicast + 47374b443922SGleb Smirnoff es->rx_multicast + 47384b443922SGleb Smirnoff es->rx_broadcast); 47394b443922SGleb Smirnoff IXL_SET_OPACKETS(vsi, es->tx_unicast + 47404b443922SGleb Smirnoff es->tx_multicast + 47414b443922SGleb Smirnoff es->tx_broadcast); 47424b443922SGleb Smirnoff IXL_SET_IBYTES(vsi, es->rx_bytes); 47434b443922SGleb Smirnoff IXL_SET_OBYTES(vsi, es->tx_bytes); 47444b443922SGleb Smirnoff IXL_SET_IMCASTS(vsi, es->rx_multicast); 47454b443922SGleb Smirnoff IXL_SET_OMCASTS(vsi, es->tx_multicast); 47464b443922SGleb Smirnoff 474756c2c47bSJack F Vogel IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes + 474856c2c47bSJack F Vogel nsd->rx_undersize + nsd->rx_oversize + nsd->rx_fragments + 474956c2c47bSJack F Vogel nsd->rx_jabber); 47504b443922SGleb Smirnoff IXL_SET_OERRORS(vsi, es->tx_errors); 47514b443922SGleb Smirnoff IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards); 47524b443922SGleb Smirnoff IXL_SET_OQDROPS(vsi, tx_discards); 47534b443922SGleb Smirnoff IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol); 47544b443922SGleb Smirnoff IXL_SET_COLLISIONS(vsi, 0); 475561ae650dSJack F Vogel } 475661ae650dSJack F Vogel 475761ae650dSJack F Vogel /** 475861ae650dSJack F Vogel * Reset all of the stats for the given pf 475961ae650dSJack F Vogel **/ 476061ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf) 476161ae650dSJack F Vogel { 476261ae650dSJack F Vogel bzero(&pf->stats, sizeof(struct i40e_hw_port_stats)); 476361ae650dSJack F Vogel bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats)); 476461ae650dSJack F Vogel pf->stat_offsets_loaded = false; 476561ae650dSJack F Vogel } 476661ae650dSJack F Vogel 476761ae650dSJack F Vogel /** 476861ae650dSJack F Vogel * Resets all stats of the given vsi 476961ae650dSJack F Vogel **/ 477061ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi) 477161ae650dSJack F Vogel { 477261ae650dSJack F Vogel bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats)); 477361ae650dSJack F Vogel bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats)); 477461ae650dSJack F Vogel vsi->stat_offsets_loaded = false; 477561ae650dSJack F Vogel } 477661ae650dSJack F Vogel 477761ae650dSJack F Vogel /** 477861ae650dSJack F Vogel * Read and update a 48 bit stat from the hw 477961ae650dSJack F Vogel * 478061ae650dSJack F Vogel * Since the device stats are not reset at PFReset, they likely will not 478161ae650dSJack F Vogel * be zeroed when the driver starts. We'll save the first values read 478261ae650dSJack F Vogel * and use them as offsets to be subtracted from the raw values in order 478361ae650dSJack F Vogel * to report stats that count from zero. 478461ae650dSJack F Vogel **/ 478561ae650dSJack F Vogel static void 478661ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg, 478761ae650dSJack F Vogel bool offset_loaded, u64 *offset, u64 *stat) 478861ae650dSJack F Vogel { 478961ae650dSJack F Vogel u64 new_data; 479061ae650dSJack F Vogel 4791ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__) 479261ae650dSJack F Vogel new_data = rd64(hw, loreg); 479361ae650dSJack F Vogel #else 479461ae650dSJack F Vogel /* 479561ae650dSJack F Vogel * Use two rd32's instead of one rd64; FreeBSD versions before 479661ae650dSJack F Vogel * 10 don't support 8 byte bus reads/writes. 479761ae650dSJack F Vogel */ 479861ae650dSJack F Vogel new_data = rd32(hw, loreg); 479961ae650dSJack F Vogel new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32; 480061ae650dSJack F Vogel #endif 480161ae650dSJack F Vogel 480261ae650dSJack F Vogel if (!offset_loaded) 480361ae650dSJack F Vogel *offset = new_data; 480461ae650dSJack F Vogel if (new_data >= *offset) 480561ae650dSJack F Vogel *stat = new_data - *offset; 480661ae650dSJack F Vogel else 480761ae650dSJack F Vogel *stat = (new_data + ((u64)1 << 48)) - *offset; 480861ae650dSJack F Vogel *stat &= 0xFFFFFFFFFFFFULL; 480961ae650dSJack F Vogel } 481061ae650dSJack F Vogel 481161ae650dSJack F Vogel /** 481261ae650dSJack F Vogel * Read and update a 32 bit stat from the hw 481361ae650dSJack F Vogel **/ 481461ae650dSJack F Vogel static void 481561ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg, 481661ae650dSJack F Vogel bool offset_loaded, u64 *offset, u64 *stat) 481761ae650dSJack F Vogel { 481861ae650dSJack F Vogel u32 new_data; 481961ae650dSJack F Vogel 482061ae650dSJack F Vogel new_data = rd32(hw, reg); 482161ae650dSJack F Vogel if (!offset_loaded) 482261ae650dSJack F Vogel *offset = new_data; 482361ae650dSJack F Vogel if (new_data >= *offset) 482461ae650dSJack F Vogel *stat = (u32)(new_data - *offset); 482561ae650dSJack F Vogel else 482661ae650dSJack F Vogel *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); 482761ae650dSJack F Vogel } 482861ae650dSJack F Vogel 4829*fdb6f38aSEric Joyner static void 4830*fdb6f38aSEric Joyner ixl_add_device_sysctls(struct ixl_pf *pf) 4831*fdb6f38aSEric Joyner { 4832*fdb6f38aSEric Joyner device_t dev = pf->dev; 4833*fdb6f38aSEric Joyner 4834*fdb6f38aSEric Joyner /* Set up sysctls */ 4835*fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4836*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4837*fdb6f38aSEric Joyner OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, 4838*fdb6f38aSEric Joyner pf, 0, ixl_set_flowcntl, "I", "Flow Control"); 4839*fdb6f38aSEric Joyner 4840*fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4841*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4842*fdb6f38aSEric Joyner OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, 4843*fdb6f38aSEric Joyner pf, 0, ixl_set_advertise, "I", "Advertised Speed"); 4844*fdb6f38aSEric Joyner 4845*fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4846*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4847*fdb6f38aSEric Joyner OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD, 4848*fdb6f38aSEric Joyner pf, 0, ixl_current_speed, "A", "Current Port Speed"); 4849*fdb6f38aSEric Joyner 4850*fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4851*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4852*fdb6f38aSEric Joyner OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD, 4853*fdb6f38aSEric Joyner pf, 0, ixl_sysctl_show_fw, "A", "Firmware version"); 4854*fdb6f38aSEric Joyner 4855*fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 4856*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4857*fdb6f38aSEric Joyner OID_AUTO, "rx_itr", CTLFLAG_RW, 4858*fdb6f38aSEric Joyner &ixl_rx_itr, IXL_ITR_8K, "RX ITR"); 4859*fdb6f38aSEric Joyner 4860*fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 4861*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4862*fdb6f38aSEric Joyner OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW, 4863*fdb6f38aSEric Joyner &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR"); 4864*fdb6f38aSEric Joyner 4865*fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 4866*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4867*fdb6f38aSEric Joyner OID_AUTO, "tx_itr", CTLFLAG_RW, 4868*fdb6f38aSEric Joyner &ixl_tx_itr, IXL_ITR_4K, "TX ITR"); 4869*fdb6f38aSEric Joyner 4870*fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 4871*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4872*fdb6f38aSEric Joyner OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW, 4873*fdb6f38aSEric Joyner &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR"); 4874*fdb6f38aSEric Joyner 4875*fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL 4876*fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4877*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4878*fdb6f38aSEric Joyner OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0, 4879*fdb6f38aSEric Joyner ixl_debug_info, "I", "Debug Information"); 4880*fdb6f38aSEric Joyner 4881*fdb6f38aSEric Joyner /* Debug shared-code message level */ 4882*fdb6f38aSEric Joyner SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 4883*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4884*fdb6f38aSEric Joyner OID_AUTO, "debug_mask", CTLFLAG_RW, 4885*fdb6f38aSEric Joyner &pf->hw.debug_mask, 0, "Debug Message Level"); 4886*fdb6f38aSEric Joyner 4887*fdb6f38aSEric Joyner SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 4888*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4889*fdb6f38aSEric Joyner OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl, 4890*fdb6f38aSEric Joyner 0, "PF/VF Virtual Channel debug level"); 4891*fdb6f38aSEric Joyner 4892*fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4893*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4894*fdb6f38aSEric Joyner OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD, 4895*fdb6f38aSEric Joyner pf, 0, ixl_sysctl_link_status, "A", "Current Link Status"); 4896*fdb6f38aSEric Joyner 4897*fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4898*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4899*fdb6f38aSEric Joyner OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD, 4900*fdb6f38aSEric Joyner pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities"); 4901*fdb6f38aSEric Joyner 4902*fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4903*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4904*fdb6f38aSEric Joyner OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD, 4905*fdb6f38aSEric Joyner pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List"); 4906*fdb6f38aSEric Joyner 4907*fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4908*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4909*fdb6f38aSEric Joyner OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD, 4910*fdb6f38aSEric Joyner pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation"); 4911*fdb6f38aSEric Joyner 4912*fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4913*fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4914*fdb6f38aSEric Joyner OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD, 4915*fdb6f38aSEric Joyner pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration"); 4916*fdb6f38aSEric Joyner #endif 4917*fdb6f38aSEric Joyner } 4918*fdb6f38aSEric Joyner 491961ae650dSJack F Vogel /* 492061ae650dSJack F Vogel ** Set flow control using sysctl: 492161ae650dSJack F Vogel ** 0 - off 492261ae650dSJack F Vogel ** 1 - rx pause 492361ae650dSJack F Vogel ** 2 - tx pause 492461ae650dSJack F Vogel ** 3 - full 492561ae650dSJack F Vogel */ 492661ae650dSJack F Vogel static int 492761ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS) 492861ae650dSJack F Vogel { 492961ae650dSJack F Vogel /* 493061ae650dSJack F Vogel * TODO: ensure tx CRC by hardware should be enabled 493161ae650dSJack F Vogel * if tx flow control is enabled. 4932223d846dSEric Joyner * ^ N/A for 40G ports 493361ae650dSJack F Vogel */ 493461ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 493561ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 493661ae650dSJack F Vogel device_t dev = pf->dev; 4937b6c8f260SJack F Vogel int error = 0; 493861ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 493961ae650dSJack F Vogel u8 fc_aq_err = 0; 494061ae650dSJack F Vogel 4941b6c8f260SJack F Vogel /* Get request */ 4942b6c8f260SJack F Vogel error = sysctl_handle_int(oidp, &pf->fc, 0, req); 494361ae650dSJack F Vogel if ((error) || (req->newptr == NULL)) 494461ae650dSJack F Vogel return (error); 4945b6c8f260SJack F Vogel if (pf->fc < 0 || pf->fc > 3) { 494661ae650dSJack F Vogel device_printf(dev, 494761ae650dSJack F Vogel "Invalid fc mode; valid modes are 0 through 3\n"); 494861ae650dSJack F Vogel return (EINVAL); 494961ae650dSJack F Vogel } 495061ae650dSJack F Vogel 495161ae650dSJack F Vogel /* 495261ae650dSJack F Vogel ** Changing flow control mode currently does not work on 495361ae650dSJack F Vogel ** 40GBASE-CR4 PHYs 495461ae650dSJack F Vogel */ 495561ae650dSJack F Vogel if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4 495661ae650dSJack F Vogel || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) { 495761ae650dSJack F Vogel device_printf(dev, "Changing flow control mode unsupported" 495861ae650dSJack F Vogel " on 40GBase-CR4 media.\n"); 495961ae650dSJack F Vogel return (ENODEV); 496061ae650dSJack F Vogel } 496161ae650dSJack F Vogel 496261ae650dSJack F Vogel /* Set fc ability for port */ 4963b6c8f260SJack F Vogel hw->fc.requested_mode = pf->fc; 496461ae650dSJack F Vogel aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE); 496561ae650dSJack F Vogel if (aq_error) { 496661ae650dSJack F Vogel device_printf(dev, 496761ae650dSJack F Vogel "%s: Error setting new fc mode %d; fc_err %#x\n", 496861ae650dSJack F Vogel __func__, aq_error, fc_aq_err); 4969223d846dSEric Joyner return (EIO); 497061ae650dSJack F Vogel } 497161ae650dSJack F Vogel 4972223d846dSEric Joyner /* Get new link state */ 4973223d846dSEric Joyner i40e_msec_delay(250); 4974223d846dSEric Joyner hw->phy.get_link_info = TRUE; 4975223d846dSEric Joyner i40e_get_link_status(hw, &pf->link_up); 4976223d846dSEric Joyner 497761ae650dSJack F Vogel return (0); 497861ae650dSJack F Vogel } 497961ae650dSJack F Vogel 498061ae650dSJack F Vogel static int 498161ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS) 498261ae650dSJack F Vogel { 498361ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 498461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 498561ae650dSJack F Vogel int error = 0, index = 0; 498661ae650dSJack F Vogel 498761ae650dSJack F Vogel char *speeds[] = { 498861ae650dSJack F Vogel "Unknown", 498961ae650dSJack F Vogel "100M", 499061ae650dSJack F Vogel "1G", 499161ae650dSJack F Vogel "10G", 499261ae650dSJack F Vogel "40G", 499361ae650dSJack F Vogel "20G" 499461ae650dSJack F Vogel }; 499561ae650dSJack F Vogel 499661ae650dSJack F Vogel ixl_update_link_status(pf); 499761ae650dSJack F Vogel 499861ae650dSJack F Vogel switch (hw->phy.link_info.link_speed) { 499961ae650dSJack F Vogel case I40E_LINK_SPEED_100MB: 500061ae650dSJack F Vogel index = 1; 500161ae650dSJack F Vogel break; 500261ae650dSJack F Vogel case I40E_LINK_SPEED_1GB: 500361ae650dSJack F Vogel index = 2; 500461ae650dSJack F Vogel break; 500561ae650dSJack F Vogel case I40E_LINK_SPEED_10GB: 500661ae650dSJack F Vogel index = 3; 500761ae650dSJack F Vogel break; 500861ae650dSJack F Vogel case I40E_LINK_SPEED_40GB: 500961ae650dSJack F Vogel index = 4; 501061ae650dSJack F Vogel break; 501161ae650dSJack F Vogel case I40E_LINK_SPEED_20GB: 501261ae650dSJack F Vogel index = 5; 501361ae650dSJack F Vogel break; 501461ae650dSJack F Vogel case I40E_LINK_SPEED_UNKNOWN: 501561ae650dSJack F Vogel default: 501661ae650dSJack F Vogel index = 0; 501761ae650dSJack F Vogel break; 501861ae650dSJack F Vogel } 501961ae650dSJack F Vogel 502061ae650dSJack F Vogel error = sysctl_handle_string(oidp, speeds[index], 502161ae650dSJack F Vogel strlen(speeds[index]), req); 502261ae650dSJack F Vogel return (error); 502361ae650dSJack F Vogel } 502461ae650dSJack F Vogel 5025e5100ee2SJack F Vogel static int 5026e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds) 5027e5100ee2SJack F Vogel { 5028e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 5029e5100ee2SJack F Vogel device_t dev = pf->dev; 5030e5100ee2SJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 5031e5100ee2SJack F Vogel struct i40e_aq_set_phy_config config; 5032e5100ee2SJack F Vogel enum i40e_status_code aq_error = 0; 5033e5100ee2SJack F Vogel 5034e5100ee2SJack F Vogel /* Get current capability information */ 5035b6c8f260SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 5036b6c8f260SJack F Vogel FALSE, FALSE, &abilities, NULL); 5037e5100ee2SJack F Vogel if (aq_error) { 5038b6c8f260SJack F Vogel device_printf(dev, 5039b6c8f260SJack F Vogel "%s: Error getting phy capabilities %d," 5040e5100ee2SJack F Vogel " aq error: %d\n", __func__, aq_error, 5041e5100ee2SJack F Vogel hw->aq.asq_last_status); 5042e5100ee2SJack F Vogel return (EAGAIN); 5043e5100ee2SJack F Vogel } 5044e5100ee2SJack F Vogel 5045e5100ee2SJack F Vogel /* Prepare new config */ 5046e5100ee2SJack F Vogel bzero(&config, sizeof(config)); 5047e5100ee2SJack F Vogel config.phy_type = abilities.phy_type; 5048e5100ee2SJack F Vogel config.abilities = abilities.abilities 5049e5100ee2SJack F Vogel | I40E_AQ_PHY_ENABLE_ATOMIC_LINK; 5050e5100ee2SJack F Vogel config.eee_capability = abilities.eee_capability; 5051e5100ee2SJack F Vogel config.eeer = abilities.eeer_val; 5052e5100ee2SJack F Vogel config.low_power_ctrl = abilities.d3_lpan; 5053e5100ee2SJack F Vogel /* Translate into aq cmd link_speed */ 505456c2c47bSJack F Vogel if (speeds & 0x8) 505556c2c47bSJack F Vogel config.link_speed |= I40E_LINK_SPEED_20GB; 5056e5100ee2SJack F Vogel if (speeds & 0x4) 5057e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_10GB; 5058e5100ee2SJack F Vogel if (speeds & 0x2) 5059e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_1GB; 5060e5100ee2SJack F Vogel if (speeds & 0x1) 5061e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_100MB; 5062e5100ee2SJack F Vogel 5063e5100ee2SJack F Vogel /* Do aq command & restart link */ 5064e5100ee2SJack F Vogel aq_error = i40e_aq_set_phy_config(hw, &config, NULL); 5065e5100ee2SJack F Vogel if (aq_error) { 5066b6c8f260SJack F Vogel device_printf(dev, 5067b6c8f260SJack F Vogel "%s: Error setting new phy config %d," 5068e5100ee2SJack F Vogel " aq error: %d\n", __func__, aq_error, 5069e5100ee2SJack F Vogel hw->aq.asq_last_status); 5070e5100ee2SJack F Vogel return (EAGAIN); 5071e5100ee2SJack F Vogel } 5072e5100ee2SJack F Vogel 5073393c4bb1SJack F Vogel /* 5074393c4bb1SJack F Vogel ** This seems a bit heavy handed, but we 5075393c4bb1SJack F Vogel ** need to get a reinit on some devices 5076393c4bb1SJack F Vogel */ 5077393c4bb1SJack F Vogel IXL_PF_LOCK(pf); 5078223d846dSEric Joyner ixl_stop_locked(pf); 5079393c4bb1SJack F Vogel ixl_init_locked(pf); 5080393c4bb1SJack F Vogel IXL_PF_UNLOCK(pf); 5081393c4bb1SJack F Vogel 5082e5100ee2SJack F Vogel return (0); 5083e5100ee2SJack F Vogel } 5084e5100ee2SJack F Vogel 508561ae650dSJack F Vogel /* 508661ae650dSJack F Vogel ** Control link advertise speed: 508761ae650dSJack F Vogel ** Flags: 508861ae650dSJack F Vogel ** 0x1 - advertise 100 Mb 508961ae650dSJack F Vogel ** 0x2 - advertise 1G 509061ae650dSJack F Vogel ** 0x4 - advertise 10G 509156c2c47bSJack F Vogel ** 0x8 - advertise 20G 509261ae650dSJack F Vogel ** 509361ae650dSJack F Vogel ** Does not work on 40G devices. 509461ae650dSJack F Vogel */ 509561ae650dSJack F Vogel static int 509661ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS) 509761ae650dSJack F Vogel { 509861ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 509961ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 510061ae650dSJack F Vogel device_t dev = pf->dev; 510161ae650dSJack F Vogel int requested_ls = 0; 510261ae650dSJack F Vogel int error = 0; 510361ae650dSJack F Vogel 510461ae650dSJack F Vogel /* 510561ae650dSJack F Vogel ** FW doesn't support changing advertised speed 510661ae650dSJack F Vogel ** for 40G devices; speed is always 40G. 510761ae650dSJack F Vogel */ 510861ae650dSJack F Vogel if (i40e_is_40G_device(hw->device_id)) 510961ae650dSJack F Vogel return (ENODEV); 511061ae650dSJack F Vogel 511161ae650dSJack F Vogel /* Read in new mode */ 511261ae650dSJack F Vogel requested_ls = pf->advertised_speed; 511361ae650dSJack F Vogel error = sysctl_handle_int(oidp, &requested_ls, 0, req); 511461ae650dSJack F Vogel if ((error) || (req->newptr == NULL)) 511561ae650dSJack F Vogel return (error); 511656c2c47bSJack F Vogel /* Check for sane value */ 511756c2c47bSJack F Vogel if (requested_ls < 0x1 || requested_ls > 0xE) { 511856c2c47bSJack F Vogel device_printf(dev, "Invalid advertised speed; " 511956c2c47bSJack F Vogel "valid modes are 0x1 through 0xE\n"); 512061ae650dSJack F Vogel return (EINVAL); 512161ae650dSJack F Vogel } 512256c2c47bSJack F Vogel /* Then check for validity based on adapter type */ 512356c2c47bSJack F Vogel switch (hw->device_id) { 512456c2c47bSJack F Vogel case I40E_DEV_ID_10G_BASE_T: 5125ac83ea83SEric Joyner case I40E_DEV_ID_10G_BASE_T4: 512656c2c47bSJack F Vogel if (requested_ls & 0x8) { 512756c2c47bSJack F Vogel device_printf(dev, 512856c2c47bSJack F Vogel "20Gbs speed not supported on this device.\n"); 512956c2c47bSJack F Vogel return (EINVAL); 513056c2c47bSJack F Vogel } 513156c2c47bSJack F Vogel break; 513256c2c47bSJack F Vogel case I40E_DEV_ID_20G_KR2: 5133ac83ea83SEric Joyner case I40E_DEV_ID_20G_KR2_A: 513456c2c47bSJack F Vogel if (requested_ls & 0x1) { 513556c2c47bSJack F Vogel device_printf(dev, 513656c2c47bSJack F Vogel "100Mbs speed not supported on this device.\n"); 513756c2c47bSJack F Vogel return (EINVAL); 513856c2c47bSJack F Vogel } 513956c2c47bSJack F Vogel break; 514056c2c47bSJack F Vogel default: 514156c2c47bSJack F Vogel if (requested_ls & ~0x6) { 514256c2c47bSJack F Vogel device_printf(dev, 514356c2c47bSJack F Vogel "Only 1/10Gbs speeds are supported on this device.\n"); 514456c2c47bSJack F Vogel return (EINVAL); 514556c2c47bSJack F Vogel } 514656c2c47bSJack F Vogel break; 514756c2c47bSJack F Vogel } 514861ae650dSJack F Vogel 514961ae650dSJack F Vogel /* Exit if no change */ 515061ae650dSJack F Vogel if (pf->advertised_speed == requested_ls) 515161ae650dSJack F Vogel return (0); 515261ae650dSJack F Vogel 5153e5100ee2SJack F Vogel error = ixl_set_advertised_speeds(pf, requested_ls); 5154e5100ee2SJack F Vogel if (error) 5155e5100ee2SJack F Vogel return (error); 515661ae650dSJack F Vogel 515761ae650dSJack F Vogel pf->advertised_speed = requested_ls; 515861ae650dSJack F Vogel ixl_update_link_status(pf); 515961ae650dSJack F Vogel return (0); 516061ae650dSJack F Vogel } 516161ae650dSJack F Vogel 516261ae650dSJack F Vogel /* 516361ae650dSJack F Vogel ** Get the width and transaction speed of 516461ae650dSJack F Vogel ** the bus this adapter is plugged into. 516561ae650dSJack F Vogel */ 516661ae650dSJack F Vogel static u16 516761ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev) 516861ae650dSJack F Vogel { 516961ae650dSJack F Vogel u16 link; 517061ae650dSJack F Vogel u32 offset; 517161ae650dSJack F Vogel 517261ae650dSJack F Vogel /* Get the PCI Express Capabilities offset */ 517361ae650dSJack F Vogel pci_find_cap(dev, PCIY_EXPRESS, &offset); 517461ae650dSJack F Vogel 517561ae650dSJack F Vogel /* ...and read the Link Status Register */ 517661ae650dSJack F Vogel link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 517761ae650dSJack F Vogel 517861ae650dSJack F Vogel switch (link & I40E_PCI_LINK_WIDTH) { 517961ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_1: 518061ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x1; 518161ae650dSJack F Vogel break; 518261ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_2: 518361ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x2; 518461ae650dSJack F Vogel break; 518561ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_4: 518661ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x4; 518761ae650dSJack F Vogel break; 518861ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_8: 518961ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x8; 519061ae650dSJack F Vogel break; 519161ae650dSJack F Vogel default: 519261ae650dSJack F Vogel hw->bus.width = i40e_bus_width_unknown; 519361ae650dSJack F Vogel break; 519461ae650dSJack F Vogel } 519561ae650dSJack F Vogel 519661ae650dSJack F Vogel switch (link & I40E_PCI_LINK_SPEED) { 519761ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_2500: 519861ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_2500; 519961ae650dSJack F Vogel break; 520061ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_5000: 520161ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_5000; 520261ae650dSJack F Vogel break; 520361ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_8000: 520461ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_8000; 520561ae650dSJack F Vogel break; 520661ae650dSJack F Vogel default: 520761ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_unknown; 520861ae650dSJack F Vogel break; 520961ae650dSJack F Vogel } 521061ae650dSJack F Vogel 521161ae650dSJack F Vogel 521261ae650dSJack F Vogel device_printf(dev,"PCI Express Bus: Speed %s %s\n", 521361ae650dSJack F Vogel ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s": 521461ae650dSJack F Vogel (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s": 521561ae650dSJack F Vogel (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"), 521661ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" : 521761ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" : 521861ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" : 521961ae650dSJack F Vogel ("Unknown")); 522061ae650dSJack F Vogel 522161ae650dSJack F Vogel if ((hw->bus.width <= i40e_bus_width_pcie_x8) && 522261ae650dSJack F Vogel (hw->bus.speed < i40e_bus_speed_8000)) { 522361ae650dSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 522456c2c47bSJack F Vogel " for this device\n may be insufficient for" 522556c2c47bSJack F Vogel " optimal performance.\n"); 522661ae650dSJack F Vogel device_printf(dev, "For expected performance a x8 " 522761ae650dSJack F Vogel "PCIE Gen3 slot is required.\n"); 522861ae650dSJack F Vogel } 522961ae650dSJack F Vogel 523061ae650dSJack F Vogel return (link); 523161ae650dSJack F Vogel } 523261ae650dSJack F Vogel 5233e5100ee2SJack F Vogel static int 5234e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS) 5235e5100ee2SJack F Vogel { 5236e5100ee2SJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 5237e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 5238e5100ee2SJack F Vogel char buf[32]; 5239e5100ee2SJack F Vogel 5240e5100ee2SJack F Vogel snprintf(buf, sizeof(buf), 5241e5100ee2SJack F Vogel "f%d.%d a%d.%d n%02x.%02x e%08x", 5242e5100ee2SJack F Vogel hw->aq.fw_maj_ver, hw->aq.fw_min_ver, 5243e5100ee2SJack F Vogel hw->aq.api_maj_ver, hw->aq.api_min_ver, 5244e5100ee2SJack F Vogel (hw->nvm.version & IXL_NVM_VERSION_HI_MASK) >> 5245e5100ee2SJack F Vogel IXL_NVM_VERSION_HI_SHIFT, 5246e5100ee2SJack F Vogel (hw->nvm.version & IXL_NVM_VERSION_LO_MASK) >> 5247e5100ee2SJack F Vogel IXL_NVM_VERSION_LO_SHIFT, 5248e5100ee2SJack F Vogel hw->nvm.eetrack); 5249e5100ee2SJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 5250e5100ee2SJack F Vogel } 5251e5100ee2SJack F Vogel 5252223d846dSEric Joyner static int 5253223d846dSEric Joyner ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd) 5254223d846dSEric Joyner { 5255223d846dSEric Joyner struct i40e_hw *hw = &pf->hw; 5256223d846dSEric Joyner struct i40e_nvm_access *nvma; 5257223d846dSEric Joyner device_t dev = pf->dev; 5258223d846dSEric Joyner enum i40e_status_code status = 0; 5259223d846dSEric Joyner int perrno; 5260223d846dSEric Joyner 5261223d846dSEric Joyner DEBUGFUNC("ixl_handle_nvmupd_cmd"); 5262223d846dSEric Joyner 5263223d846dSEric Joyner if (ifd->ifd_len < sizeof(struct i40e_nvm_access) || 5264223d846dSEric Joyner ifd->ifd_data == NULL) { 5265223d846dSEric Joyner device_printf(dev, "%s: incorrect ifdrv length or data pointer\n", __func__); 5266223d846dSEric Joyner device_printf(dev, "%s: ifdrv length: %lu, sizeof(struct i40e_nvm_access): %lu\n", __func__, 5267223d846dSEric Joyner ifd->ifd_len, sizeof(struct i40e_nvm_access)); 5268223d846dSEric Joyner device_printf(dev, "%s: data pointer: %p\n", __func__, ifd->ifd_data); 5269223d846dSEric Joyner return (EINVAL); 5270223d846dSEric Joyner } 5271223d846dSEric Joyner 5272223d846dSEric Joyner nvma = (struct i40e_nvm_access *)ifd->ifd_data; 5273223d846dSEric Joyner 5274*fdb6f38aSEric Joyner if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { 5275*fdb6f38aSEric Joyner int count = 0; 5276*fdb6f38aSEric Joyner while (count++ < 100) { 5277*fdb6f38aSEric Joyner i40e_msec_delay(100); 5278*fdb6f38aSEric Joyner if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) 5279*fdb6f38aSEric Joyner break; 5280*fdb6f38aSEric Joyner } 5281*fdb6f38aSEric Joyner // device_printf(dev, "ioctl EMPR reset wait count %d\n", count); 5282*fdb6f38aSEric Joyner } 5283*fdb6f38aSEric Joyner 5284*fdb6f38aSEric Joyner if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) { 5285*fdb6f38aSEric Joyner IXL_PF_LOCK(pf); 5286223d846dSEric Joyner status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno); 5287*fdb6f38aSEric Joyner IXL_PF_UNLOCK(pf); 5288*fdb6f38aSEric Joyner } else { 5289*fdb6f38aSEric Joyner perrno = -EBUSY; 5290*fdb6f38aSEric Joyner } 5291*fdb6f38aSEric Joyner 52927f70bec6SEric Joyner if (status) 52937f70bec6SEric Joyner device_printf(dev, "i40e_nvmupd_command status %d, perrno %d\n", 52947f70bec6SEric Joyner status, perrno); 5295223d846dSEric Joyner 5296*fdb6f38aSEric Joyner /* 5297*fdb6f38aSEric Joyner * -EPERM is actually ERESTART, which the kernel interprets as it needing 5298*fdb6f38aSEric Joyner * to run this ioctl again. So use -EACCES for -EPERM instead. 5299*fdb6f38aSEric Joyner */ 53007f70bec6SEric Joyner if (perrno == -EPERM) 53017f70bec6SEric Joyner return (-EACCES); 53027f70bec6SEric Joyner else 53037f70bec6SEric Joyner return (perrno); 5304223d846dSEric Joyner } 5305e5100ee2SJack F Vogel 5306393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL 530761ae650dSJack F Vogel static int 530861ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS) 530961ae650dSJack F Vogel { 531061ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 531161ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 531261ae650dSJack F Vogel struct i40e_link_status link_status; 531361ae650dSJack F Vogel char buf[512]; 531461ae650dSJack F Vogel 531561ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 531661ae650dSJack F Vogel 531761ae650dSJack F Vogel aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL); 531861ae650dSJack F Vogel if (aq_error) { 531961ae650dSJack F Vogel printf("i40e_aq_get_link_info() error %d\n", aq_error); 532061ae650dSJack F Vogel return (EPERM); 532161ae650dSJack F Vogel } 532261ae650dSJack F Vogel 532361ae650dSJack F Vogel sprintf(buf, "\n" 532461ae650dSJack F Vogel "PHY Type : %#04x\n" 532561ae650dSJack F Vogel "Speed : %#04x\n" 532661ae650dSJack F Vogel "Link info: %#04x\n" 532761ae650dSJack F Vogel "AN info : %#04x\n" 532861ae650dSJack F Vogel "Ext info : %#04x", 532961ae650dSJack F Vogel link_status.phy_type, link_status.link_speed, 533061ae650dSJack F Vogel link_status.link_info, link_status.an_info, 533161ae650dSJack F Vogel link_status.ext_info); 533261ae650dSJack F Vogel 533361ae650dSJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 533461ae650dSJack F Vogel } 533561ae650dSJack F Vogel 533661ae650dSJack F Vogel static int 533761ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS) 533861ae650dSJack F Vogel { 533961ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 534061ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 534161ae650dSJack F Vogel char buf[512]; 534261ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 534361ae650dSJack F Vogel 534456c2c47bSJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 534556c2c47bSJack F Vogel 534656c2c47bSJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 534756c2c47bSJack F Vogel TRUE, FALSE, &abilities, NULL); 534861ae650dSJack F Vogel if (aq_error) { 534961ae650dSJack F Vogel printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error); 535061ae650dSJack F Vogel return (EPERM); 535161ae650dSJack F Vogel } 535261ae650dSJack F Vogel 535361ae650dSJack F Vogel sprintf(buf, "\n" 535461ae650dSJack F Vogel "PHY Type : %#010x\n" 535561ae650dSJack F Vogel "Speed : %#04x\n" 535661ae650dSJack F Vogel "Abilities: %#04x\n" 535761ae650dSJack F Vogel "EEE cap : %#06x\n" 535861ae650dSJack F Vogel "EEER reg : %#010x\n" 535961ae650dSJack F Vogel "D3 Lpan : %#04x", 536056c2c47bSJack F Vogel abilities.phy_type, abilities.link_speed, 536156c2c47bSJack F Vogel abilities.abilities, abilities.eee_capability, 536256c2c47bSJack F Vogel abilities.eeer_val, abilities.d3_lpan); 536361ae650dSJack F Vogel 536461ae650dSJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 536561ae650dSJack F Vogel } 536661ae650dSJack F Vogel 536761ae650dSJack F Vogel static int 536861ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS) 536961ae650dSJack F Vogel { 537061ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 537161ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 537261ae650dSJack F Vogel struct ixl_mac_filter *f; 537361ae650dSJack F Vogel char *buf, *buf_i; 537461ae650dSJack F Vogel 537561ae650dSJack F Vogel int error = 0; 537661ae650dSJack F Vogel int ftl_len = 0; 537761ae650dSJack F Vogel int ftl_counter = 0; 537861ae650dSJack F Vogel int buf_len = 0; 537961ae650dSJack F Vogel int entry_len = 42; 538061ae650dSJack F Vogel 538161ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 538261ae650dSJack F Vogel ftl_len++; 538361ae650dSJack F Vogel } 538461ae650dSJack F Vogel 538561ae650dSJack F Vogel if (ftl_len < 1) { 538661ae650dSJack F Vogel sysctl_handle_string(oidp, "(none)", 6, req); 538761ae650dSJack F Vogel return (0); 538861ae650dSJack F Vogel } 538961ae650dSJack F Vogel 539061ae650dSJack F Vogel buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2; 539161ae650dSJack F Vogel buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT); 539261ae650dSJack F Vogel 539361ae650dSJack F Vogel sprintf(buf_i++, "\n"); 539461ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 539561ae650dSJack F Vogel sprintf(buf_i, 539661ae650dSJack F Vogel MAC_FORMAT ", vlan %4d, flags %#06x", 539761ae650dSJack F Vogel MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags); 539861ae650dSJack F Vogel buf_i += entry_len; 539961ae650dSJack F Vogel /* don't print '\n' for last entry */ 540061ae650dSJack F Vogel if (++ftl_counter != ftl_len) { 540161ae650dSJack F Vogel sprintf(buf_i, "\n"); 540261ae650dSJack F Vogel buf_i++; 540361ae650dSJack F Vogel } 540461ae650dSJack F Vogel } 540561ae650dSJack F Vogel 540661ae650dSJack F Vogel error = sysctl_handle_string(oidp, buf, strlen(buf), req); 540761ae650dSJack F Vogel if (error) 540861ae650dSJack F Vogel printf("sysctl error: %d\n", error); 540961ae650dSJack F Vogel free(buf, M_DEVBUF); 541061ae650dSJack F Vogel return error; 541161ae650dSJack F Vogel } 541261ae650dSJack F Vogel 541361ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14 541461ae650dSJack F Vogel static int 5415393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b) 5416393c4bb1SJack F Vogel { 5417393c4bb1SJack F Vogel const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two; 5418be771cdaSJack F Vogel one = (const struct i40e_aqc_switch_resource_alloc_element_resp *)a; 5419be771cdaSJack F Vogel two = (const struct i40e_aqc_switch_resource_alloc_element_resp *)b; 5420393c4bb1SJack F Vogel 5421393c4bb1SJack F Vogel return ((int)one->resource_type - (int)two->resource_type); 5422393c4bb1SJack F Vogel } 5423393c4bb1SJack F Vogel 5424*fdb6f38aSEric Joyner /* 5425*fdb6f38aSEric Joyner * Longest string length: 25 5426*fdb6f38aSEric Joyner */ 5427*fdb6f38aSEric Joyner static char * 5428*fdb6f38aSEric Joyner ixl_switch_res_type_string(u8 type) 5429*fdb6f38aSEric Joyner { 5430*fdb6f38aSEric Joyner static char * ixl_switch_res_type_strings[0x14] = { 5431*fdb6f38aSEric Joyner "VEB", 5432*fdb6f38aSEric Joyner "VSI", 5433*fdb6f38aSEric Joyner "Perfect Match MAC address", 5434*fdb6f38aSEric Joyner "S-tag", 5435*fdb6f38aSEric Joyner "(Reserved)", 5436*fdb6f38aSEric Joyner "Multicast hash entry", 5437*fdb6f38aSEric Joyner "Unicast hash entry", 5438*fdb6f38aSEric Joyner "VLAN", 5439*fdb6f38aSEric Joyner "VSI List entry", 5440*fdb6f38aSEric Joyner "(Reserved)", 5441*fdb6f38aSEric Joyner "VLAN Statistic Pool", 5442*fdb6f38aSEric Joyner "Mirror Rule", 5443*fdb6f38aSEric Joyner "Queue Set", 5444*fdb6f38aSEric Joyner "Inner VLAN Forward filter", 5445*fdb6f38aSEric Joyner "(Reserved)", 5446*fdb6f38aSEric Joyner "Inner MAC", 5447*fdb6f38aSEric Joyner "IP", 5448*fdb6f38aSEric Joyner "GRE/VN1 Key", 5449*fdb6f38aSEric Joyner "VN2 Key", 5450*fdb6f38aSEric Joyner "Tunneling Port" 5451*fdb6f38aSEric Joyner }; 5452*fdb6f38aSEric Joyner 5453*fdb6f38aSEric Joyner if (type < 0x14) 5454*fdb6f38aSEric Joyner return ixl_switch_res_type_strings[type]; 5455*fdb6f38aSEric Joyner else 5456*fdb6f38aSEric Joyner return "(Reserved)"; 5457*fdb6f38aSEric Joyner } 5458*fdb6f38aSEric Joyner 5459393c4bb1SJack F Vogel static int 5460e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS) 546161ae650dSJack F Vogel { 546261ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 546361ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 546461ae650dSJack F Vogel device_t dev = pf->dev; 546561ae650dSJack F Vogel struct sbuf *buf; 546661ae650dSJack F Vogel int error = 0; 546761ae650dSJack F Vogel 546861ae650dSJack F Vogel u8 num_entries; 546961ae650dSJack F Vogel struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE]; 547061ae650dSJack F Vogel 5471a48d00d2SEric Joyner buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 547261ae650dSJack F Vogel if (!buf) { 547361ae650dSJack F Vogel device_printf(dev, "Could not allocate sbuf for output.\n"); 547461ae650dSJack F Vogel return (ENOMEM); 547561ae650dSJack F Vogel } 547661ae650dSJack F Vogel 5477393c4bb1SJack F Vogel bzero(resp, sizeof(resp)); 547861ae650dSJack F Vogel error = i40e_aq_get_switch_resource_alloc(hw, &num_entries, 547961ae650dSJack F Vogel resp, 548061ae650dSJack F Vogel IXL_SW_RES_SIZE, 548161ae650dSJack F Vogel NULL); 548261ae650dSJack F Vogel if (error) { 548356c2c47bSJack F Vogel device_printf(dev, 548456c2c47bSJack F Vogel "%s: get_switch_resource_alloc() error %d, aq error %d\n", 548561ae650dSJack F Vogel __func__, error, hw->aq.asq_last_status); 548661ae650dSJack F Vogel sbuf_delete(buf); 548761ae650dSJack F Vogel return error; 548861ae650dSJack F Vogel } 5489393c4bb1SJack F Vogel 5490393c4bb1SJack F Vogel /* Sort entries by type for display */ 5491393c4bb1SJack F Vogel qsort(resp, num_entries, 5492393c4bb1SJack F Vogel sizeof(struct i40e_aqc_switch_resource_alloc_element_resp), 5493393c4bb1SJack F Vogel &ixl_res_alloc_cmp); 549461ae650dSJack F Vogel 549561ae650dSJack F Vogel sbuf_cat(buf, "\n"); 5496393c4bb1SJack F Vogel sbuf_printf(buf, "# of entries: %d\n", num_entries); 549761ae650dSJack F Vogel sbuf_printf(buf, 5498*fdb6f38aSEric Joyner #if 0 5499*fdb6f38aSEric Joyner "Type | Guaranteed | Total | Used | Un-allocated\n" 5500*fdb6f38aSEric Joyner " | (this) | (all) | (this) | (all) \n"); 5501*fdb6f38aSEric Joyner #endif 550261ae650dSJack F Vogel " Type | Guaranteed | Total | Used | Un-allocated\n" 550361ae650dSJack F Vogel " | (this) | (all) | (this) | (all) \n"); 550461ae650dSJack F Vogel for (int i = 0; i < num_entries; i++) { 550561ae650dSJack F Vogel sbuf_printf(buf, 5506*fdb6f38aSEric Joyner #if 0 550761ae650dSJack F Vogel "%#4x | %10d %5d %6d %12d", 550861ae650dSJack F Vogel resp[i].resource_type, 5509*fdb6f38aSEric Joyner #endif 5510*fdb6f38aSEric Joyner "%25s | %10d %5d %6d %12d", 5511*fdb6f38aSEric Joyner ixl_switch_res_type_string(resp[i].resource_type), 551261ae650dSJack F Vogel resp[i].guaranteed, 551361ae650dSJack F Vogel resp[i].total, 551461ae650dSJack F Vogel resp[i].used, 551561ae650dSJack F Vogel resp[i].total_unalloced); 551661ae650dSJack F Vogel if (i < num_entries - 1) 551761ae650dSJack F Vogel sbuf_cat(buf, "\n"); 551861ae650dSJack F Vogel } 551961ae650dSJack F Vogel 552061ae650dSJack F Vogel error = sbuf_finish(buf); 5521ac83ea83SEric Joyner if (error) 5522a48d00d2SEric Joyner device_printf(dev, "Error finishing sbuf: %d\n", error); 5523a48d00d2SEric Joyner 5524ac83ea83SEric Joyner sbuf_delete(buf); 5525ac83ea83SEric Joyner return error; 5526e5100ee2SJack F Vogel } 552761ae650dSJack F Vogel 5528e5100ee2SJack F Vogel /* 5529e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and 5530e5100ee2SJack F Vogel ** finish it for caller. 5531*fdb6f38aSEric Joyner ** 5532*fdb6f38aSEric Joyner ** XXX: Cannot use the SEID for this, since there is no longer a 5533*fdb6f38aSEric Joyner ** fixed mapping between SEID and element type. 5534e5100ee2SJack F Vogel */ 5535e5100ee2SJack F Vogel static char * 5536*fdb6f38aSEric Joyner ixl_switch_element_string(struct sbuf *s, 5537*fdb6f38aSEric Joyner struct i40e_aqc_switch_config_element_resp *element) 5538e5100ee2SJack F Vogel { 5539e5100ee2SJack F Vogel sbuf_clear(s); 5540e5100ee2SJack F Vogel 5541*fdb6f38aSEric Joyner switch (element->element_type) { 5542*fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_MAC: 5543*fdb6f38aSEric Joyner sbuf_printf(s, "MAC %3d", element->element_info); 5544*fdb6f38aSEric Joyner break; 5545*fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_PF: 5546*fdb6f38aSEric Joyner sbuf_printf(s, "PF %3d", element->element_info); 5547*fdb6f38aSEric Joyner break; 5548*fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_VF: 5549*fdb6f38aSEric Joyner sbuf_printf(s, "VF %3d", element->element_info); 5550*fdb6f38aSEric Joyner break; 5551*fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_EMP: 5552e5100ee2SJack F Vogel sbuf_cat(s, "EMP"); 5553*fdb6f38aSEric Joyner break; 5554*fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_BMC: 5555*fdb6f38aSEric Joyner sbuf_cat(s, "BMC"); 5556*fdb6f38aSEric Joyner break; 5557*fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_PV: 5558*fdb6f38aSEric Joyner sbuf_cat(s, "PV"); 5559*fdb6f38aSEric Joyner break; 5560*fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_VEB: 5561*fdb6f38aSEric Joyner sbuf_cat(s, "VEB"); 5562*fdb6f38aSEric Joyner break; 5563*fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_PA: 5564*fdb6f38aSEric Joyner sbuf_cat(s, "PA"); 5565*fdb6f38aSEric Joyner break; 5566*fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_VSI: 5567*fdb6f38aSEric Joyner sbuf_printf(s, "VSI %3d", element->element_info); 5568*fdb6f38aSEric Joyner break; 5569*fdb6f38aSEric Joyner default: 5570*fdb6f38aSEric Joyner sbuf_cat(s, "?"); 5571*fdb6f38aSEric Joyner break; 5572*fdb6f38aSEric Joyner } 5573e5100ee2SJack F Vogel 5574e5100ee2SJack F Vogel sbuf_finish(s); 5575e5100ee2SJack F Vogel return sbuf_data(s); 5576e5100ee2SJack F Vogel } 5577e5100ee2SJack F Vogel 5578e5100ee2SJack F Vogel static int 5579e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS) 5580e5100ee2SJack F Vogel { 5581e5100ee2SJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 5582e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 5583e5100ee2SJack F Vogel device_t dev = pf->dev; 5584e5100ee2SJack F Vogel struct sbuf *buf; 5585e5100ee2SJack F Vogel struct sbuf *nmbuf; 5586e5100ee2SJack F Vogel int error = 0; 5587*fdb6f38aSEric Joyner u16 next = 0; 5588e5100ee2SJack F Vogel u8 aq_buf[I40E_AQ_LARGE_BUF]; 5589e5100ee2SJack F Vogel 5590e5100ee2SJack F Vogel struct i40e_aqc_get_switch_config_resp *sw_config; 5591e5100ee2SJack F Vogel sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 5592e5100ee2SJack F Vogel 5593a48d00d2SEric Joyner buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5594e5100ee2SJack F Vogel if (!buf) { 5595e5100ee2SJack F Vogel device_printf(dev, "Could not allocate sbuf for sysctl output.\n"); 5596e5100ee2SJack F Vogel return (ENOMEM); 5597e5100ee2SJack F Vogel } 5598e5100ee2SJack F Vogel 5599e5100ee2SJack F Vogel error = i40e_aq_get_switch_config(hw, sw_config, 5600e5100ee2SJack F Vogel sizeof(aq_buf), &next, NULL); 5601e5100ee2SJack F Vogel if (error) { 560256c2c47bSJack F Vogel device_printf(dev, 560356c2c47bSJack F Vogel "%s: aq_get_switch_config() error %d, aq error %d\n", 5604e5100ee2SJack F Vogel __func__, error, hw->aq.asq_last_status); 5605e5100ee2SJack F Vogel sbuf_delete(buf); 5606e5100ee2SJack F Vogel return error; 5607e5100ee2SJack F Vogel } 5608*fdb6f38aSEric Joyner if (next) 5609*fdb6f38aSEric Joyner device_printf(dev, "%s: TODO: get more config with SEID %d\n", 5610*fdb6f38aSEric Joyner __func__, next); 5611e5100ee2SJack F Vogel 5612e5100ee2SJack F Vogel nmbuf = sbuf_new_auto(); 5613e5100ee2SJack F Vogel if (!nmbuf) { 5614e5100ee2SJack F Vogel device_printf(dev, "Could not allocate sbuf for name output.\n"); 5615a48d00d2SEric Joyner sbuf_delete(buf); 5616e5100ee2SJack F Vogel return (ENOMEM); 5617e5100ee2SJack F Vogel } 5618e5100ee2SJack F Vogel 5619e5100ee2SJack F Vogel sbuf_cat(buf, "\n"); 5620e5100ee2SJack F Vogel // Assuming <= 255 elements in switch 5621*fdb6f38aSEric Joyner sbuf_printf(buf, "# of reported elements: %d\n", sw_config->header.num_reported); 5622*fdb6f38aSEric Joyner sbuf_printf(buf, "total # of elements: %d\n", sw_config->header.num_total); 5623e5100ee2SJack F Vogel /* Exclude: 5624e5100ee2SJack F Vogel ** Revision -- all elements are revision 1 for now 5625e5100ee2SJack F Vogel */ 5626e5100ee2SJack F Vogel sbuf_printf(buf, 5627e5100ee2SJack F Vogel "SEID ( Name ) | Uplink | Downlink | Conn Type\n" 5628e5100ee2SJack F Vogel " | | | (uplink)\n"); 5629e5100ee2SJack F Vogel for (int i = 0; i < sw_config->header.num_reported; i++) { 5630e5100ee2SJack F Vogel // "%4d (%8s) | %8s %8s %#8x", 5631e5100ee2SJack F Vogel sbuf_printf(buf, "%4d", sw_config->element[i].seid); 5632e5100ee2SJack F Vogel sbuf_cat(buf, " "); 563356c2c47bSJack F Vogel sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf, 5634*fdb6f38aSEric Joyner &sw_config->element[i])); 5635e5100ee2SJack F Vogel sbuf_cat(buf, " | "); 5636*fdb6f38aSEric Joyner sbuf_printf(buf, "%8d", sw_config->element[i].uplink_seid); 5637e5100ee2SJack F Vogel sbuf_cat(buf, " "); 5638*fdb6f38aSEric Joyner sbuf_printf(buf, "%8d", sw_config->element[i].downlink_seid); 5639e5100ee2SJack F Vogel sbuf_cat(buf, " "); 5640e5100ee2SJack F Vogel sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type); 5641e5100ee2SJack F Vogel if (i < sw_config->header.num_reported - 1) 5642e5100ee2SJack F Vogel sbuf_cat(buf, "\n"); 5643e5100ee2SJack F Vogel } 5644e5100ee2SJack F Vogel sbuf_delete(nmbuf); 5645e5100ee2SJack F Vogel 5646e5100ee2SJack F Vogel error = sbuf_finish(buf); 5647ac83ea83SEric Joyner if (error) 5648a48d00d2SEric Joyner device_printf(dev, "Error finishing sbuf: %d\n", error); 5649a48d00d2SEric Joyner 5650e5100ee2SJack F Vogel sbuf_delete(buf); 5651e5100ee2SJack F Vogel 5652e5100ee2SJack F Vogel return (error); 565361ae650dSJack F Vogel } 5654393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */ 565561ae650dSJack F Vogel 565656c2c47bSJack F Vogel #ifdef PCI_IOV 565756c2c47bSJack F Vogel static int 565856c2c47bSJack F Vogel ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf) 565956c2c47bSJack F Vogel { 566056c2c47bSJack F Vogel struct i40e_hw *hw; 566156c2c47bSJack F Vogel struct ixl_vsi *vsi; 566256c2c47bSJack F Vogel struct i40e_vsi_context vsi_ctx; 566356c2c47bSJack F Vogel int i; 566456c2c47bSJack F Vogel uint16_t first_queue; 566556c2c47bSJack F Vogel enum i40e_status_code code; 566656c2c47bSJack F Vogel 566756c2c47bSJack F Vogel hw = &pf->hw; 566856c2c47bSJack F Vogel vsi = &pf->vsi; 566956c2c47bSJack F Vogel 567056c2c47bSJack F Vogel vsi_ctx.pf_num = hw->pf_id; 567156c2c47bSJack F Vogel vsi_ctx.uplink_seid = pf->veb_seid; 567256c2c47bSJack F Vogel vsi_ctx.connection_type = IXL_VSI_DATA_PORT; 567356c2c47bSJack F Vogel vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num; 567456c2c47bSJack F Vogel vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF; 567556c2c47bSJack F Vogel 567656c2c47bSJack F Vogel bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); 567756c2c47bSJack F Vogel 567856c2c47bSJack F Vogel vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID); 567956c2c47bSJack F Vogel vsi_ctx.info.switch_id = htole16(0); 568056c2c47bSJack F Vogel 568156c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID); 568256c2c47bSJack F Vogel vsi_ctx.info.sec_flags = 0; 568356c2c47bSJack F Vogel if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF) 568456c2c47bSJack F Vogel vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK; 568556c2c47bSJack F Vogel 568656c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID); 568756c2c47bSJack F Vogel vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 568856c2c47bSJack F Vogel I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 568956c2c47bSJack F Vogel 569056c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= 569156c2c47bSJack F Vogel htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID); 569256c2c47bSJack F Vogel vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG); 569356c2c47bSJack F Vogel first_queue = vsi->num_queues + vf->vf_num * IXLV_MAX_QUEUES; 569456c2c47bSJack F Vogel for (i = 0; i < IXLV_MAX_QUEUES; i++) 569556c2c47bSJack F Vogel vsi_ctx.info.queue_mapping[i] = htole16(first_queue + i); 569656c2c47bSJack F Vogel for (; i < nitems(vsi_ctx.info.queue_mapping); i++) 569756c2c47bSJack F Vogel vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK); 569856c2c47bSJack F Vogel 569956c2c47bSJack F Vogel vsi_ctx.info.tc_mapping[0] = htole16( 570056c2c47bSJack F Vogel (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) | 570156c2c47bSJack F Vogel (1 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)); 570256c2c47bSJack F Vogel 570356c2c47bSJack F Vogel code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL); 570456c2c47bSJack F Vogel if (code != I40E_SUCCESS) 570556c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 570656c2c47bSJack F Vogel vf->vsi.seid = vsi_ctx.seid; 570756c2c47bSJack F Vogel vf->vsi.vsi_num = vsi_ctx.vsi_number; 570856c2c47bSJack F Vogel vf->vsi.first_queue = first_queue; 570956c2c47bSJack F Vogel vf->vsi.num_queues = IXLV_MAX_QUEUES; 571056c2c47bSJack F Vogel 571156c2c47bSJack F Vogel code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL); 571256c2c47bSJack F Vogel if (code != I40E_SUCCESS) 571356c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 571456c2c47bSJack F Vogel 571556c2c47bSJack F Vogel code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL); 571656c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 571756c2c47bSJack F Vogel device_printf(pf->dev, "Failed to disable BW limit: %d\n", 571856c2c47bSJack F Vogel ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 571956c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 572056c2c47bSJack F Vogel } 572156c2c47bSJack F Vogel 572256c2c47bSJack F Vogel memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info)); 572356c2c47bSJack F Vogel return (0); 572456c2c47bSJack F Vogel } 572556c2c47bSJack F Vogel 572656c2c47bSJack F Vogel static int 572756c2c47bSJack F Vogel ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf) 572856c2c47bSJack F Vogel { 572956c2c47bSJack F Vogel struct i40e_hw *hw; 573056c2c47bSJack F Vogel int error; 573156c2c47bSJack F Vogel 573256c2c47bSJack F Vogel hw = &pf->hw; 573356c2c47bSJack F Vogel 573456c2c47bSJack F Vogel error = ixl_vf_alloc_vsi(pf, vf); 573556c2c47bSJack F Vogel if (error != 0) 573656c2c47bSJack F Vogel return (error); 573756c2c47bSJack F Vogel 573856c2c47bSJack F Vogel vf->vsi.hw_filters_add = 0; 573956c2c47bSJack F Vogel vf->vsi.hw_filters_del = 0; 574056c2c47bSJack F Vogel ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY); 574156c2c47bSJack F Vogel ixl_reconfigure_filters(&vf->vsi); 574256c2c47bSJack F Vogel 574356c2c47bSJack F Vogel return (0); 574456c2c47bSJack F Vogel } 574556c2c47bSJack F Vogel 574656c2c47bSJack F Vogel static void 574756c2c47bSJack F Vogel ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum, 574856c2c47bSJack F Vogel uint32_t val) 574956c2c47bSJack F Vogel { 575056c2c47bSJack F Vogel uint32_t qtable; 575156c2c47bSJack F Vogel int index, shift; 575256c2c47bSJack F Vogel 575356c2c47bSJack F Vogel /* 575456c2c47bSJack F Vogel * Two queues are mapped in a single register, so we have to do some 575556c2c47bSJack F Vogel * gymnastics to convert the queue number into a register index and 575656c2c47bSJack F Vogel * shift. 575756c2c47bSJack F Vogel */ 575856c2c47bSJack F Vogel index = qnum / 2; 575956c2c47bSJack F Vogel shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT; 576056c2c47bSJack F Vogel 576156c2c47bSJack F Vogel qtable = rd32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num)); 576256c2c47bSJack F Vogel qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift); 576356c2c47bSJack F Vogel qtable |= val << shift; 576456c2c47bSJack F Vogel wr32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable); 576556c2c47bSJack F Vogel } 576656c2c47bSJack F Vogel 576756c2c47bSJack F Vogel static void 576856c2c47bSJack F Vogel ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf) 576956c2c47bSJack F Vogel { 577056c2c47bSJack F Vogel struct i40e_hw *hw; 577156c2c47bSJack F Vogel uint32_t qtable; 577256c2c47bSJack F Vogel int i; 577356c2c47bSJack F Vogel 577456c2c47bSJack F Vogel hw = &pf->hw; 577556c2c47bSJack F Vogel 577656c2c47bSJack F Vogel /* 577756c2c47bSJack F Vogel * Contiguous mappings aren't actually supported by the hardware, 577856c2c47bSJack F Vogel * so we have to use non-contiguous mappings. 577956c2c47bSJack F Vogel */ 578056c2c47bSJack F Vogel wr32(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num), 578156c2c47bSJack F Vogel I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK); 578256c2c47bSJack F Vogel 578356c2c47bSJack F Vogel wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num), 578456c2c47bSJack F Vogel I40E_VPLAN_MAPENA_TXRX_ENA_MASK); 578556c2c47bSJack F Vogel 578656c2c47bSJack F Vogel for (i = 0; i < vf->vsi.num_queues; i++) { 578756c2c47bSJack F Vogel qtable = (vf->vsi.first_queue + i) << 578856c2c47bSJack F Vogel I40E_VPLAN_QTABLE_QINDEX_SHIFT; 578956c2c47bSJack F Vogel 579056c2c47bSJack F Vogel wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable); 579156c2c47bSJack F Vogel } 579256c2c47bSJack F Vogel 579356c2c47bSJack F Vogel /* Map queues allocated to VF to its VSI. */ 579456c2c47bSJack F Vogel for (i = 0; i < vf->vsi.num_queues; i++) 579556c2c47bSJack F Vogel ixl_vf_map_vsi_queue(hw, vf, i, vf->vsi.first_queue + i); 579656c2c47bSJack F Vogel 579756c2c47bSJack F Vogel /* Set rest of VSI queues as unused. */ 579856c2c47bSJack F Vogel for (; i < IXL_MAX_VSI_QUEUES; i++) 579956c2c47bSJack F Vogel ixl_vf_map_vsi_queue(hw, vf, i, 580056c2c47bSJack F Vogel I40E_VSILAN_QTABLE_QINDEX_0_MASK); 580156c2c47bSJack F Vogel 580256c2c47bSJack F Vogel ixl_flush(hw); 580356c2c47bSJack F Vogel } 580456c2c47bSJack F Vogel 580556c2c47bSJack F Vogel static void 580656c2c47bSJack F Vogel ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi) 580756c2c47bSJack F Vogel { 580856c2c47bSJack F Vogel struct i40e_hw *hw; 580956c2c47bSJack F Vogel 581056c2c47bSJack F Vogel hw = &pf->hw; 581156c2c47bSJack F Vogel 581256c2c47bSJack F Vogel if (vsi->seid == 0) 581356c2c47bSJack F Vogel return; 581456c2c47bSJack F Vogel 581556c2c47bSJack F Vogel i40e_aq_delete_element(hw, vsi->seid, NULL); 581656c2c47bSJack F Vogel } 581756c2c47bSJack F Vogel 581856c2c47bSJack F Vogel static void 581956c2c47bSJack F Vogel ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg) 582056c2c47bSJack F Vogel { 582156c2c47bSJack F Vogel 582256c2c47bSJack F Vogel wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK); 582356c2c47bSJack F Vogel ixl_flush(hw); 582456c2c47bSJack F Vogel } 582556c2c47bSJack F Vogel 582656c2c47bSJack F Vogel static void 582756c2c47bSJack F Vogel ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg) 582856c2c47bSJack F Vogel { 582956c2c47bSJack F Vogel 583056c2c47bSJack F Vogel wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK | 583156c2c47bSJack F Vogel I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK); 583256c2c47bSJack F Vogel ixl_flush(hw); 583356c2c47bSJack F Vogel } 583456c2c47bSJack F Vogel 583556c2c47bSJack F Vogel static void 583656c2c47bSJack F Vogel ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf) 583756c2c47bSJack F Vogel { 583856c2c47bSJack F Vogel struct i40e_hw *hw; 583956c2c47bSJack F Vogel uint32_t vfint_reg, vpint_reg; 584056c2c47bSJack F Vogel int i; 584156c2c47bSJack F Vogel 584256c2c47bSJack F Vogel hw = &pf->hw; 584356c2c47bSJack F Vogel 584456c2c47bSJack F Vogel ixl_vf_vsi_release(pf, &vf->vsi); 584556c2c47bSJack F Vogel 584656c2c47bSJack F Vogel /* Index 0 has a special register. */ 584756c2c47bSJack F Vogel ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num)); 584856c2c47bSJack F Vogel 584956c2c47bSJack F Vogel for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) { 585056c2c47bSJack F Vogel vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num); 585156c2c47bSJack F Vogel ixl_vf_disable_queue_intr(hw, vfint_reg); 585256c2c47bSJack F Vogel } 585356c2c47bSJack F Vogel 585456c2c47bSJack F Vogel /* Index 0 has a special register. */ 585556c2c47bSJack F Vogel ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num)); 585656c2c47bSJack F Vogel 585756c2c47bSJack F Vogel for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) { 585856c2c47bSJack F Vogel vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num); 585956c2c47bSJack F Vogel ixl_vf_unregister_intr(hw, vpint_reg); 586056c2c47bSJack F Vogel } 586156c2c47bSJack F Vogel 586256c2c47bSJack F Vogel vf->vsi.num_queues = 0; 586356c2c47bSJack F Vogel } 586456c2c47bSJack F Vogel 586556c2c47bSJack F Vogel static int 586656c2c47bSJack F Vogel ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf) 586756c2c47bSJack F Vogel { 586856c2c47bSJack F Vogel struct i40e_hw *hw; 586956c2c47bSJack F Vogel int i; 587056c2c47bSJack F Vogel uint16_t global_vf_num; 587156c2c47bSJack F Vogel uint32_t ciad; 587256c2c47bSJack F Vogel 587356c2c47bSJack F Vogel hw = &pf->hw; 587456c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + vf->vf_num; 587556c2c47bSJack F Vogel 587656c2c47bSJack F Vogel wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS | 587756c2c47bSJack F Vogel (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT)); 587856c2c47bSJack F Vogel for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) { 587956c2c47bSJack F Vogel ciad = rd32(hw, I40E_PF_PCI_CIAD); 588056c2c47bSJack F Vogel if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0) 588156c2c47bSJack F Vogel return (0); 588256c2c47bSJack F Vogel DELAY(1); 588356c2c47bSJack F Vogel } 588456c2c47bSJack F Vogel 588556c2c47bSJack F Vogel return (ETIMEDOUT); 588656c2c47bSJack F Vogel } 588756c2c47bSJack F Vogel 588856c2c47bSJack F Vogel static void 588956c2c47bSJack F Vogel ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf) 589056c2c47bSJack F Vogel { 589156c2c47bSJack F Vogel struct i40e_hw *hw; 589256c2c47bSJack F Vogel uint32_t vfrtrig; 589356c2c47bSJack F Vogel 589456c2c47bSJack F Vogel hw = &pf->hw; 589556c2c47bSJack F Vogel 589656c2c47bSJack F Vogel vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); 589756c2c47bSJack F Vogel vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK; 589856c2c47bSJack F Vogel wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); 589956c2c47bSJack F Vogel ixl_flush(hw); 590056c2c47bSJack F Vogel 590156c2c47bSJack F Vogel ixl_reinit_vf(pf, vf); 590256c2c47bSJack F Vogel } 590356c2c47bSJack F Vogel 590456c2c47bSJack F Vogel static void 590556c2c47bSJack F Vogel ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf) 590656c2c47bSJack F Vogel { 590756c2c47bSJack F Vogel struct i40e_hw *hw; 590856c2c47bSJack F Vogel uint32_t vfrstat, vfrtrig; 590956c2c47bSJack F Vogel int i, error; 591056c2c47bSJack F Vogel 591156c2c47bSJack F Vogel hw = &pf->hw; 591256c2c47bSJack F Vogel 591356c2c47bSJack F Vogel error = ixl_flush_pcie(pf, vf); 591456c2c47bSJack F Vogel if (error != 0) 591556c2c47bSJack F Vogel device_printf(pf->dev, 591656c2c47bSJack F Vogel "Timed out waiting for PCIe activity to stop on VF-%d\n", 591756c2c47bSJack F Vogel vf->vf_num); 591856c2c47bSJack F Vogel 591956c2c47bSJack F Vogel for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) { 592056c2c47bSJack F Vogel DELAY(10); 592156c2c47bSJack F Vogel 592256c2c47bSJack F Vogel vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num)); 592356c2c47bSJack F Vogel if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK) 592456c2c47bSJack F Vogel break; 592556c2c47bSJack F Vogel } 592656c2c47bSJack F Vogel 592756c2c47bSJack F Vogel if (i == IXL_VF_RESET_TIMEOUT) 592856c2c47bSJack F Vogel device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num); 592956c2c47bSJack F Vogel 593056c2c47bSJack F Vogel wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_COMPLETED); 593156c2c47bSJack F Vogel 593256c2c47bSJack F Vogel vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); 593356c2c47bSJack F Vogel vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK; 593456c2c47bSJack F Vogel wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); 593556c2c47bSJack F Vogel 593656c2c47bSJack F Vogel if (vf->vsi.seid != 0) 593756c2c47bSJack F Vogel ixl_disable_rings(&vf->vsi); 593856c2c47bSJack F Vogel 593956c2c47bSJack F Vogel ixl_vf_release_resources(pf, vf); 594056c2c47bSJack F Vogel ixl_vf_setup_vsi(pf, vf); 594156c2c47bSJack F Vogel ixl_vf_map_queues(pf, vf); 594256c2c47bSJack F Vogel 594356c2c47bSJack F Vogel wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_VFACTIVE); 594456c2c47bSJack F Vogel ixl_flush(hw); 594556c2c47bSJack F Vogel } 594656c2c47bSJack F Vogel 594756c2c47bSJack F Vogel static const char * 594856c2c47bSJack F Vogel ixl_vc_opcode_str(uint16_t op) 594956c2c47bSJack F Vogel { 595056c2c47bSJack F Vogel 595156c2c47bSJack F Vogel switch (op) { 595256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_VERSION: 595356c2c47bSJack F Vogel return ("VERSION"); 595456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_RESET_VF: 595556c2c47bSJack F Vogel return ("RESET_VF"); 595656c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: 595756c2c47bSJack F Vogel return ("GET_VF_RESOURCES"); 595856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: 595956c2c47bSJack F Vogel return ("CONFIG_TX_QUEUE"); 596056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: 596156c2c47bSJack F Vogel return ("CONFIG_RX_QUEUE"); 596256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: 596356c2c47bSJack F Vogel return ("CONFIG_VSI_QUEUES"); 596456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: 596556c2c47bSJack F Vogel return ("CONFIG_IRQ_MAP"); 596656c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ENABLE_QUEUES: 596756c2c47bSJack F Vogel return ("ENABLE_QUEUES"); 596856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DISABLE_QUEUES: 596956c2c47bSJack F Vogel return ("DISABLE_QUEUES"); 597056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: 597156c2c47bSJack F Vogel return ("ADD_ETHER_ADDRESS"); 597256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: 597356c2c47bSJack F Vogel return ("DEL_ETHER_ADDRESS"); 597456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_VLAN: 597556c2c47bSJack F Vogel return ("ADD_VLAN"); 597656c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_VLAN: 597756c2c47bSJack F Vogel return ("DEL_VLAN"); 597856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: 597956c2c47bSJack F Vogel return ("CONFIG_PROMISCUOUS_MODE"); 598056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 598156c2c47bSJack F Vogel return ("GET_STATS"); 598256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_FCOE: 598356c2c47bSJack F Vogel return ("FCOE"); 598456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_EVENT: 598556c2c47bSJack F Vogel return ("EVENT"); 598656c2c47bSJack F Vogel default: 598756c2c47bSJack F Vogel return ("UNKNOWN"); 598856c2c47bSJack F Vogel } 598956c2c47bSJack F Vogel } 599056c2c47bSJack F Vogel 599156c2c47bSJack F Vogel static int 599256c2c47bSJack F Vogel ixl_vc_opcode_level(uint16_t opcode) 599356c2c47bSJack F Vogel { 599456c2c47bSJack F Vogel 599556c2c47bSJack F Vogel switch (opcode) { 599656c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 599756c2c47bSJack F Vogel return (10); 599856c2c47bSJack F Vogel default: 599956c2c47bSJack F Vogel return (5); 600056c2c47bSJack F Vogel } 600156c2c47bSJack F Vogel } 600256c2c47bSJack F Vogel 600356c2c47bSJack F Vogel static void 600456c2c47bSJack F Vogel ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, 600556c2c47bSJack F Vogel enum i40e_status_code status, void *msg, uint16_t len) 600656c2c47bSJack F Vogel { 600756c2c47bSJack F Vogel struct i40e_hw *hw; 600856c2c47bSJack F Vogel int global_vf_id; 600956c2c47bSJack F Vogel 601056c2c47bSJack F Vogel hw = &pf->hw; 601156c2c47bSJack F Vogel global_vf_id = hw->func_caps.vf_base_id + vf->vf_num; 601256c2c47bSJack F Vogel 601356c2c47bSJack F Vogel I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op), 601456c2c47bSJack F Vogel "Sending msg (op=%s[%d], status=%d) to VF-%d\n", 601556c2c47bSJack F Vogel ixl_vc_opcode_str(op), op, status, vf->vf_num); 601656c2c47bSJack F Vogel 601756c2c47bSJack F Vogel i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL); 601856c2c47bSJack F Vogel } 601956c2c47bSJack F Vogel 602056c2c47bSJack F Vogel static void 602156c2c47bSJack F Vogel ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op) 602256c2c47bSJack F Vogel { 602356c2c47bSJack F Vogel 602456c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0); 602556c2c47bSJack F Vogel } 602656c2c47bSJack F Vogel 602756c2c47bSJack F Vogel static void 602856c2c47bSJack F Vogel ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, 602956c2c47bSJack F Vogel enum i40e_status_code status, const char *file, int line) 603056c2c47bSJack F Vogel { 603156c2c47bSJack F Vogel 603256c2c47bSJack F Vogel I40E_VC_DEBUG(pf, 1, 603356c2c47bSJack F Vogel "Sending NACK (op=%s[%d], err=%d) to VF-%d from %s:%d\n", 603456c2c47bSJack F Vogel ixl_vc_opcode_str(op), op, status, vf->vf_num, file, line); 603556c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, op, status, NULL, 0); 603656c2c47bSJack F Vogel } 603756c2c47bSJack F Vogel 603856c2c47bSJack F Vogel static void 603956c2c47bSJack F Vogel ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 604056c2c47bSJack F Vogel uint16_t msg_size) 604156c2c47bSJack F Vogel { 604256c2c47bSJack F Vogel struct i40e_virtchnl_version_info reply; 604356c2c47bSJack F Vogel 604456c2c47bSJack F Vogel if (msg_size != sizeof(struct i40e_virtchnl_version_info)) { 604556c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_VERSION, 604656c2c47bSJack F Vogel I40E_ERR_PARAM); 604756c2c47bSJack F Vogel return; 604856c2c47bSJack F Vogel } 604956c2c47bSJack F Vogel 605056c2c47bSJack F Vogel reply.major = I40E_VIRTCHNL_VERSION_MAJOR; 605156c2c47bSJack F Vogel reply.minor = I40E_VIRTCHNL_VERSION_MINOR; 605256c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, &reply, 605356c2c47bSJack F Vogel sizeof(reply)); 605456c2c47bSJack F Vogel } 605556c2c47bSJack F Vogel 605656c2c47bSJack F Vogel static void 605756c2c47bSJack F Vogel ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 605856c2c47bSJack F Vogel uint16_t msg_size) 605956c2c47bSJack F Vogel { 606056c2c47bSJack F Vogel 606156c2c47bSJack F Vogel if (msg_size != 0) { 606256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_RESET_VF, 606356c2c47bSJack F Vogel I40E_ERR_PARAM); 606456c2c47bSJack F Vogel return; 606556c2c47bSJack F Vogel } 606656c2c47bSJack F Vogel 606756c2c47bSJack F Vogel ixl_reset_vf(pf, vf); 606856c2c47bSJack F Vogel 606956c2c47bSJack F Vogel /* No response to a reset message. */ 607056c2c47bSJack F Vogel } 607156c2c47bSJack F Vogel 607256c2c47bSJack F Vogel static void 607356c2c47bSJack F Vogel ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 607456c2c47bSJack F Vogel uint16_t msg_size) 607556c2c47bSJack F Vogel { 607656c2c47bSJack F Vogel struct i40e_virtchnl_vf_resource reply; 607756c2c47bSJack F Vogel 607856c2c47bSJack F Vogel if (msg_size != 0) { 607956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, 608056c2c47bSJack F Vogel I40E_ERR_PARAM); 608156c2c47bSJack F Vogel return; 608256c2c47bSJack F Vogel } 608356c2c47bSJack F Vogel 608456c2c47bSJack F Vogel bzero(&reply, sizeof(reply)); 608556c2c47bSJack F Vogel 608656c2c47bSJack F Vogel reply.vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2; 608756c2c47bSJack F Vogel 608856c2c47bSJack F Vogel reply.num_vsis = 1; 608956c2c47bSJack F Vogel reply.num_queue_pairs = vf->vsi.num_queues; 609056c2c47bSJack F Vogel reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf; 609156c2c47bSJack F Vogel reply.vsi_res[0].vsi_id = vf->vsi.vsi_num; 609256c2c47bSJack F Vogel reply.vsi_res[0].vsi_type = I40E_VSI_SRIOV; 609356c2c47bSJack F Vogel reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues; 609456c2c47bSJack F Vogel memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN); 609556c2c47bSJack F Vogel 609656c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, 609756c2c47bSJack F Vogel I40E_SUCCESS, &reply, sizeof(reply)); 609856c2c47bSJack F Vogel } 609956c2c47bSJack F Vogel 610056c2c47bSJack F Vogel static int 610156c2c47bSJack F Vogel ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf, 610256c2c47bSJack F Vogel struct i40e_virtchnl_txq_info *info) 610356c2c47bSJack F Vogel { 610456c2c47bSJack F Vogel struct i40e_hw *hw; 610556c2c47bSJack F Vogel struct i40e_hmc_obj_txq txq; 610656c2c47bSJack F Vogel uint16_t global_queue_num, global_vf_num; 610756c2c47bSJack F Vogel enum i40e_status_code status; 610856c2c47bSJack F Vogel uint32_t qtx_ctl; 610956c2c47bSJack F Vogel 611056c2c47bSJack F Vogel hw = &pf->hw; 611156c2c47bSJack F Vogel global_queue_num = vf->vsi.first_queue + info->queue_id; 611256c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + vf->vf_num; 611356c2c47bSJack F Vogel bzero(&txq, sizeof(txq)); 611456c2c47bSJack F Vogel 611556c2c47bSJack F Vogel status = i40e_clear_lan_tx_queue_context(hw, global_queue_num); 611656c2c47bSJack F Vogel if (status != I40E_SUCCESS) 611756c2c47bSJack F Vogel return (EINVAL); 611856c2c47bSJack F Vogel 611956c2c47bSJack F Vogel txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS; 612056c2c47bSJack F Vogel 612156c2c47bSJack F Vogel txq.head_wb_ena = info->headwb_enabled; 612256c2c47bSJack F Vogel txq.head_wb_addr = info->dma_headwb_addr; 612356c2c47bSJack F Vogel txq.qlen = info->ring_len; 612456c2c47bSJack F Vogel txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]); 612556c2c47bSJack F Vogel txq.rdylist_act = 0; 612656c2c47bSJack F Vogel 612756c2c47bSJack F Vogel status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq); 612856c2c47bSJack F Vogel if (status != I40E_SUCCESS) 612956c2c47bSJack F Vogel return (EINVAL); 613056c2c47bSJack F Vogel 613156c2c47bSJack F Vogel qtx_ctl = I40E_QTX_CTL_VF_QUEUE | 613256c2c47bSJack F Vogel (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) | 613356c2c47bSJack F Vogel (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT); 613456c2c47bSJack F Vogel wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl); 613556c2c47bSJack F Vogel ixl_flush(hw); 613656c2c47bSJack F Vogel 613756c2c47bSJack F Vogel return (0); 613856c2c47bSJack F Vogel } 613956c2c47bSJack F Vogel 614056c2c47bSJack F Vogel static int 614156c2c47bSJack F Vogel ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf, 614256c2c47bSJack F Vogel struct i40e_virtchnl_rxq_info *info) 614356c2c47bSJack F Vogel { 614456c2c47bSJack F Vogel struct i40e_hw *hw; 614556c2c47bSJack F Vogel struct i40e_hmc_obj_rxq rxq; 614656c2c47bSJack F Vogel uint16_t global_queue_num; 614756c2c47bSJack F Vogel enum i40e_status_code status; 614856c2c47bSJack F Vogel 614956c2c47bSJack F Vogel hw = &pf->hw; 615056c2c47bSJack F Vogel global_queue_num = vf->vsi.first_queue + info->queue_id; 615156c2c47bSJack F Vogel bzero(&rxq, sizeof(rxq)); 615256c2c47bSJack F Vogel 615356c2c47bSJack F Vogel if (info->databuffer_size > IXL_VF_MAX_BUFFER) 615456c2c47bSJack F Vogel return (EINVAL); 615556c2c47bSJack F Vogel 615656c2c47bSJack F Vogel if (info->max_pkt_size > IXL_VF_MAX_FRAME || 615756c2c47bSJack F Vogel info->max_pkt_size < ETHER_MIN_LEN) 615856c2c47bSJack F Vogel return (EINVAL); 615956c2c47bSJack F Vogel 616056c2c47bSJack F Vogel if (info->splithdr_enabled) { 616156c2c47bSJack F Vogel if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER) 616256c2c47bSJack F Vogel return (EINVAL); 616356c2c47bSJack F Vogel 616456c2c47bSJack F Vogel rxq.hsplit_0 = info->rx_split_pos & 616556c2c47bSJack F Vogel (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 | 616656c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP | 616756c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP | 616856c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP); 616956c2c47bSJack F Vogel rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT; 617056c2c47bSJack F Vogel 617156c2c47bSJack F Vogel rxq.dtype = 2; 617256c2c47bSJack F Vogel } 617356c2c47bSJack F Vogel 617456c2c47bSJack F Vogel status = i40e_clear_lan_rx_queue_context(hw, global_queue_num); 617556c2c47bSJack F Vogel if (status != I40E_SUCCESS) 617656c2c47bSJack F Vogel return (EINVAL); 617756c2c47bSJack F Vogel 617856c2c47bSJack F Vogel rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS; 617956c2c47bSJack F Vogel rxq.qlen = info->ring_len; 618056c2c47bSJack F Vogel 618156c2c47bSJack F Vogel rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT; 618256c2c47bSJack F Vogel 618356c2c47bSJack F Vogel rxq.dsize = 1; 618456c2c47bSJack F Vogel rxq.crcstrip = 1; 618556c2c47bSJack F Vogel rxq.l2tsel = 1; 618656c2c47bSJack F Vogel 618756c2c47bSJack F Vogel rxq.rxmax = info->max_pkt_size; 618856c2c47bSJack F Vogel rxq.tphrdesc_ena = 1; 618956c2c47bSJack F Vogel rxq.tphwdesc_ena = 1; 619056c2c47bSJack F Vogel rxq.tphdata_ena = 1; 619156c2c47bSJack F Vogel rxq.tphhead_ena = 1; 619256c2c47bSJack F Vogel rxq.lrxqthresh = 2; 619356c2c47bSJack F Vogel rxq.prefena = 1; 619456c2c47bSJack F Vogel 619556c2c47bSJack F Vogel status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq); 619656c2c47bSJack F Vogel if (status != I40E_SUCCESS) 619756c2c47bSJack F Vogel return (EINVAL); 619856c2c47bSJack F Vogel 619956c2c47bSJack F Vogel return (0); 620056c2c47bSJack F Vogel } 620156c2c47bSJack F Vogel 620256c2c47bSJack F Vogel static void 620356c2c47bSJack F Vogel ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 620456c2c47bSJack F Vogel uint16_t msg_size) 620556c2c47bSJack F Vogel { 620656c2c47bSJack F Vogel struct i40e_virtchnl_vsi_queue_config_info *info; 620756c2c47bSJack F Vogel struct i40e_virtchnl_queue_pair_info *pair; 620856c2c47bSJack F Vogel int i; 620956c2c47bSJack F Vogel 621056c2c47bSJack F Vogel if (msg_size < sizeof(*info)) { 621156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 621256c2c47bSJack F Vogel I40E_ERR_PARAM); 621356c2c47bSJack F Vogel return; 621456c2c47bSJack F Vogel } 621556c2c47bSJack F Vogel 621656c2c47bSJack F Vogel info = msg; 621756c2c47bSJack F Vogel if (info->num_queue_pairs == 0) { 621856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 621956c2c47bSJack F Vogel I40E_ERR_PARAM); 622056c2c47bSJack F Vogel return; 622156c2c47bSJack F Vogel } 622256c2c47bSJack F Vogel 622356c2c47bSJack F Vogel if (msg_size != sizeof(*info) + info->num_queue_pairs * sizeof(*pair)) { 622456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 622556c2c47bSJack F Vogel I40E_ERR_PARAM); 622656c2c47bSJack F Vogel return; 622756c2c47bSJack F Vogel } 622856c2c47bSJack F Vogel 622956c2c47bSJack F Vogel if (info->vsi_id != vf->vsi.vsi_num) { 623056c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 623156c2c47bSJack F Vogel I40E_ERR_PARAM); 623256c2c47bSJack F Vogel return; 623356c2c47bSJack F Vogel } 623456c2c47bSJack F Vogel 623556c2c47bSJack F Vogel for (i = 0; i < info->num_queue_pairs; i++) { 623656c2c47bSJack F Vogel pair = &info->qpair[i]; 623756c2c47bSJack F Vogel 623856c2c47bSJack F Vogel if (pair->txq.vsi_id != vf->vsi.vsi_num || 623956c2c47bSJack F Vogel pair->rxq.vsi_id != vf->vsi.vsi_num || 624056c2c47bSJack F Vogel pair->txq.queue_id != pair->rxq.queue_id || 624156c2c47bSJack F Vogel pair->txq.queue_id >= vf->vsi.num_queues) { 624256c2c47bSJack F Vogel 624356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 624456c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 624556c2c47bSJack F Vogel return; 624656c2c47bSJack F Vogel } 624756c2c47bSJack F Vogel 624856c2c47bSJack F Vogel if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) { 624956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 625056c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 625156c2c47bSJack F Vogel return; 625256c2c47bSJack F Vogel } 625356c2c47bSJack F Vogel 625456c2c47bSJack F Vogel if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) { 625556c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 625656c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 625756c2c47bSJack F Vogel return; 625856c2c47bSJack F Vogel } 625956c2c47bSJack F Vogel } 626056c2c47bSJack F Vogel 626156c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES); 626256c2c47bSJack F Vogel } 626356c2c47bSJack F Vogel 626456c2c47bSJack F Vogel static void 626556c2c47bSJack F Vogel ixl_vf_set_qctl(struct ixl_pf *pf, 626656c2c47bSJack F Vogel const struct i40e_virtchnl_vector_map *vector, 626756c2c47bSJack F Vogel enum i40e_queue_type cur_type, uint16_t cur_queue, 626856c2c47bSJack F Vogel enum i40e_queue_type *last_type, uint16_t *last_queue) 626956c2c47bSJack F Vogel { 627056c2c47bSJack F Vogel uint32_t offset, qctl; 627156c2c47bSJack F Vogel uint16_t itr_indx; 627256c2c47bSJack F Vogel 627356c2c47bSJack F Vogel if (cur_type == I40E_QUEUE_TYPE_RX) { 627456c2c47bSJack F Vogel offset = I40E_QINT_RQCTL(cur_queue); 627556c2c47bSJack F Vogel itr_indx = vector->rxitr_idx; 627656c2c47bSJack F Vogel } else { 627756c2c47bSJack F Vogel offset = I40E_QINT_TQCTL(cur_queue); 627856c2c47bSJack F Vogel itr_indx = vector->txitr_idx; 627956c2c47bSJack F Vogel } 628056c2c47bSJack F Vogel 628156c2c47bSJack F Vogel qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 628256c2c47bSJack F Vogel (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) | 628356c2c47bSJack F Vogel (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 628456c2c47bSJack F Vogel I40E_QINT_RQCTL_CAUSE_ENA_MASK | 628556c2c47bSJack F Vogel (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT)); 628656c2c47bSJack F Vogel 628756c2c47bSJack F Vogel wr32(&pf->hw, offset, qctl); 628856c2c47bSJack F Vogel 628956c2c47bSJack F Vogel *last_type = cur_type; 629056c2c47bSJack F Vogel *last_queue = cur_queue; 629156c2c47bSJack F Vogel } 629256c2c47bSJack F Vogel 629356c2c47bSJack F Vogel static void 629456c2c47bSJack F Vogel ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf, 629556c2c47bSJack F Vogel const struct i40e_virtchnl_vector_map *vector) 629656c2c47bSJack F Vogel { 629756c2c47bSJack F Vogel struct i40e_hw *hw; 629856c2c47bSJack F Vogel u_int qindex; 629956c2c47bSJack F Vogel enum i40e_queue_type type, last_type; 630056c2c47bSJack F Vogel uint32_t lnklst_reg; 630156c2c47bSJack F Vogel uint16_t rxq_map, txq_map, cur_queue, last_queue; 630256c2c47bSJack F Vogel 630356c2c47bSJack F Vogel hw = &pf->hw; 630456c2c47bSJack F Vogel 630556c2c47bSJack F Vogel rxq_map = vector->rxq_map; 630656c2c47bSJack F Vogel txq_map = vector->txq_map; 630756c2c47bSJack F Vogel 630856c2c47bSJack F Vogel last_queue = IXL_END_OF_INTR_LNKLST; 630956c2c47bSJack F Vogel last_type = I40E_QUEUE_TYPE_RX; 631056c2c47bSJack F Vogel 631156c2c47bSJack F Vogel /* 631256c2c47bSJack F Vogel * The datasheet says to optimize performance, RX queues and TX queues 631356c2c47bSJack F Vogel * should be interleaved in the interrupt linked list, so we process 631456c2c47bSJack F Vogel * both at once here. 631556c2c47bSJack F Vogel */ 631656c2c47bSJack F Vogel while ((rxq_map != 0) || (txq_map != 0)) { 631756c2c47bSJack F Vogel if (txq_map != 0) { 631856c2c47bSJack F Vogel qindex = ffs(txq_map) - 1; 631956c2c47bSJack F Vogel type = I40E_QUEUE_TYPE_TX; 632056c2c47bSJack F Vogel cur_queue = vf->vsi.first_queue + qindex; 632156c2c47bSJack F Vogel ixl_vf_set_qctl(pf, vector, type, cur_queue, 632256c2c47bSJack F Vogel &last_type, &last_queue); 632356c2c47bSJack F Vogel txq_map &= ~(1 << qindex); 632456c2c47bSJack F Vogel } 632556c2c47bSJack F Vogel 632656c2c47bSJack F Vogel if (rxq_map != 0) { 632756c2c47bSJack F Vogel qindex = ffs(rxq_map) - 1; 632856c2c47bSJack F Vogel type = I40E_QUEUE_TYPE_RX; 632956c2c47bSJack F Vogel cur_queue = vf->vsi.first_queue + qindex; 633056c2c47bSJack F Vogel ixl_vf_set_qctl(pf, vector, type, cur_queue, 633156c2c47bSJack F Vogel &last_type, &last_queue); 633256c2c47bSJack F Vogel rxq_map &= ~(1 << qindex); 633356c2c47bSJack F Vogel } 633456c2c47bSJack F Vogel } 633556c2c47bSJack F Vogel 633656c2c47bSJack F Vogel if (vector->vector_id == 0) 633756c2c47bSJack F Vogel lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num); 633856c2c47bSJack F Vogel else 633956c2c47bSJack F Vogel lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id, 634056c2c47bSJack F Vogel vf->vf_num); 634156c2c47bSJack F Vogel wr32(hw, lnklst_reg, 634256c2c47bSJack F Vogel (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) | 634356c2c47bSJack F Vogel (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT)); 634456c2c47bSJack F Vogel 634556c2c47bSJack F Vogel ixl_flush(hw); 634656c2c47bSJack F Vogel } 634756c2c47bSJack F Vogel 634856c2c47bSJack F Vogel static void 634956c2c47bSJack F Vogel ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 635056c2c47bSJack F Vogel uint16_t msg_size) 635156c2c47bSJack F Vogel { 635256c2c47bSJack F Vogel struct i40e_virtchnl_irq_map_info *map; 635356c2c47bSJack F Vogel struct i40e_virtchnl_vector_map *vector; 635456c2c47bSJack F Vogel struct i40e_hw *hw; 635556c2c47bSJack F Vogel int i, largest_txq, largest_rxq; 635656c2c47bSJack F Vogel 635756c2c47bSJack F Vogel hw = &pf->hw; 635856c2c47bSJack F Vogel 635956c2c47bSJack F Vogel if (msg_size < sizeof(*map)) { 636056c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 636156c2c47bSJack F Vogel I40E_ERR_PARAM); 636256c2c47bSJack F Vogel return; 636356c2c47bSJack F Vogel } 636456c2c47bSJack F Vogel 636556c2c47bSJack F Vogel map = msg; 636656c2c47bSJack F Vogel if (map->num_vectors == 0) { 636756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 636856c2c47bSJack F Vogel I40E_ERR_PARAM); 636956c2c47bSJack F Vogel return; 637056c2c47bSJack F Vogel } 637156c2c47bSJack F Vogel 637256c2c47bSJack F Vogel if (msg_size != sizeof(*map) + map->num_vectors * sizeof(*vector)) { 637356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 637456c2c47bSJack F Vogel I40E_ERR_PARAM); 637556c2c47bSJack F Vogel return; 637656c2c47bSJack F Vogel } 637756c2c47bSJack F Vogel 637856c2c47bSJack F Vogel for (i = 0; i < map->num_vectors; i++) { 637956c2c47bSJack F Vogel vector = &map->vecmap[i]; 638056c2c47bSJack F Vogel 638156c2c47bSJack F Vogel if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) || 638256c2c47bSJack F Vogel vector->vsi_id != vf->vsi.vsi_num) { 638356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 638456c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM); 638556c2c47bSJack F Vogel return; 638656c2c47bSJack F Vogel } 638756c2c47bSJack F Vogel 638856c2c47bSJack F Vogel if (vector->rxq_map != 0) { 638956c2c47bSJack F Vogel largest_rxq = fls(vector->rxq_map) - 1; 639056c2c47bSJack F Vogel if (largest_rxq >= vf->vsi.num_queues) { 639156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 639256c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 639356c2c47bSJack F Vogel I40E_ERR_PARAM); 639456c2c47bSJack F Vogel return; 639556c2c47bSJack F Vogel } 639656c2c47bSJack F Vogel } 639756c2c47bSJack F Vogel 639856c2c47bSJack F Vogel if (vector->txq_map != 0) { 639956c2c47bSJack F Vogel largest_txq = fls(vector->txq_map) - 1; 640056c2c47bSJack F Vogel if (largest_txq >= vf->vsi.num_queues) { 640156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 640256c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 640356c2c47bSJack F Vogel I40E_ERR_PARAM); 640456c2c47bSJack F Vogel return; 640556c2c47bSJack F Vogel } 640656c2c47bSJack F Vogel } 640756c2c47bSJack F Vogel 640856c2c47bSJack F Vogel if (vector->rxitr_idx > IXL_MAX_ITR_IDX || 640956c2c47bSJack F Vogel vector->txitr_idx > IXL_MAX_ITR_IDX) { 641056c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 641156c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 641256c2c47bSJack F Vogel I40E_ERR_PARAM); 641356c2c47bSJack F Vogel return; 641456c2c47bSJack F Vogel } 641556c2c47bSJack F Vogel 641656c2c47bSJack F Vogel ixl_vf_config_vector(pf, vf, vector); 641756c2c47bSJack F Vogel } 641856c2c47bSJack F Vogel 641956c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP); 642056c2c47bSJack F Vogel } 642156c2c47bSJack F Vogel 642256c2c47bSJack F Vogel static void 642356c2c47bSJack F Vogel ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 642456c2c47bSJack F Vogel uint16_t msg_size) 642556c2c47bSJack F Vogel { 642656c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *select; 642756c2c47bSJack F Vogel int error; 642856c2c47bSJack F Vogel 642956c2c47bSJack F Vogel if (msg_size != sizeof(*select)) { 643056c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 643156c2c47bSJack F Vogel I40E_ERR_PARAM); 643256c2c47bSJack F Vogel return; 643356c2c47bSJack F Vogel } 643456c2c47bSJack F Vogel 643556c2c47bSJack F Vogel select = msg; 643656c2c47bSJack F Vogel if (select->vsi_id != vf->vsi.vsi_num || 643756c2c47bSJack F Vogel select->rx_queues == 0 || select->tx_queues == 0) { 643856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 643956c2c47bSJack F Vogel I40E_ERR_PARAM); 644056c2c47bSJack F Vogel return; 644156c2c47bSJack F Vogel } 644256c2c47bSJack F Vogel 644356c2c47bSJack F Vogel error = ixl_enable_rings(&vf->vsi); 644456c2c47bSJack F Vogel if (error) { 644556c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 644656c2c47bSJack F Vogel I40E_ERR_TIMEOUT); 644756c2c47bSJack F Vogel return; 644856c2c47bSJack F Vogel } 644956c2c47bSJack F Vogel 645056c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES); 645156c2c47bSJack F Vogel } 645256c2c47bSJack F Vogel 645356c2c47bSJack F Vogel static void 645456c2c47bSJack F Vogel ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, 645556c2c47bSJack F Vogel void *msg, uint16_t msg_size) 645656c2c47bSJack F Vogel { 645756c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *select; 645856c2c47bSJack F Vogel int error; 645956c2c47bSJack F Vogel 646056c2c47bSJack F Vogel if (msg_size != sizeof(*select)) { 646156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 646256c2c47bSJack F Vogel I40E_ERR_PARAM); 646356c2c47bSJack F Vogel return; 646456c2c47bSJack F Vogel } 646556c2c47bSJack F Vogel 646656c2c47bSJack F Vogel select = msg; 646756c2c47bSJack F Vogel if (select->vsi_id != vf->vsi.vsi_num || 646856c2c47bSJack F Vogel select->rx_queues == 0 || select->tx_queues == 0) { 646956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 647056c2c47bSJack F Vogel I40E_ERR_PARAM); 647156c2c47bSJack F Vogel return; 647256c2c47bSJack F Vogel } 647356c2c47bSJack F Vogel 647456c2c47bSJack F Vogel error = ixl_disable_rings(&vf->vsi); 647556c2c47bSJack F Vogel if (error) { 647656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 647756c2c47bSJack F Vogel I40E_ERR_TIMEOUT); 647856c2c47bSJack F Vogel return; 647956c2c47bSJack F Vogel } 648056c2c47bSJack F Vogel 648156c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES); 648256c2c47bSJack F Vogel } 648356c2c47bSJack F Vogel 648456c2c47bSJack F Vogel static boolean_t 648556c2c47bSJack F Vogel ixl_zero_mac(const uint8_t *addr) 648656c2c47bSJack F Vogel { 648756c2c47bSJack F Vogel uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0}; 648856c2c47bSJack F Vogel 648956c2c47bSJack F Vogel return (cmp_etheraddr(addr, zero)); 649056c2c47bSJack F Vogel } 649156c2c47bSJack F Vogel 649256c2c47bSJack F Vogel static boolean_t 649356c2c47bSJack F Vogel ixl_bcast_mac(const uint8_t *addr) 649456c2c47bSJack F Vogel { 649556c2c47bSJack F Vogel 649656c2c47bSJack F Vogel return (cmp_etheraddr(addr, ixl_bcast_addr)); 649756c2c47bSJack F Vogel } 649856c2c47bSJack F Vogel 649956c2c47bSJack F Vogel static int 650056c2c47bSJack F Vogel ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr) 650156c2c47bSJack F Vogel { 650256c2c47bSJack F Vogel 650356c2c47bSJack F Vogel if (ixl_zero_mac(addr) || ixl_bcast_mac(addr)) 650456c2c47bSJack F Vogel return (EINVAL); 650556c2c47bSJack F Vogel 650656c2c47bSJack F Vogel /* 650756c2c47bSJack F Vogel * If the VF is not allowed to change its MAC address, don't let it 650856c2c47bSJack F Vogel * set a MAC filter for an address that is not a multicast address and 650956c2c47bSJack F Vogel * is not its assigned MAC. 651056c2c47bSJack F Vogel */ 651156c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) && 651256c2c47bSJack F Vogel !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac))) 651356c2c47bSJack F Vogel return (EPERM); 651456c2c47bSJack F Vogel 651556c2c47bSJack F Vogel return (0); 651656c2c47bSJack F Vogel } 651756c2c47bSJack F Vogel 651856c2c47bSJack F Vogel static void 651956c2c47bSJack F Vogel ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 652056c2c47bSJack F Vogel uint16_t msg_size) 652156c2c47bSJack F Vogel { 652256c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr_list *addr_list; 652356c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr *addr; 652456c2c47bSJack F Vogel struct ixl_vsi *vsi; 652556c2c47bSJack F Vogel int i; 652656c2c47bSJack F Vogel size_t expected_size; 652756c2c47bSJack F Vogel 652856c2c47bSJack F Vogel vsi = &vf->vsi; 652956c2c47bSJack F Vogel 653056c2c47bSJack F Vogel if (msg_size < sizeof(*addr_list)) { 653156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 653256c2c47bSJack F Vogel I40E_ERR_PARAM); 653356c2c47bSJack F Vogel return; 653456c2c47bSJack F Vogel } 653556c2c47bSJack F Vogel 653656c2c47bSJack F Vogel addr_list = msg; 653756c2c47bSJack F Vogel expected_size = sizeof(*addr_list) + 653856c2c47bSJack F Vogel addr_list->num_elements * sizeof(*addr); 653956c2c47bSJack F Vogel 654056c2c47bSJack F Vogel if (addr_list->num_elements == 0 || 654156c2c47bSJack F Vogel addr_list->vsi_id != vsi->vsi_num || 654256c2c47bSJack F Vogel msg_size != expected_size) { 654356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 654456c2c47bSJack F Vogel I40E_ERR_PARAM); 654556c2c47bSJack F Vogel return; 654656c2c47bSJack F Vogel } 654756c2c47bSJack F Vogel 654856c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 654956c2c47bSJack F Vogel if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) { 655056c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 655156c2c47bSJack F Vogel I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM); 655256c2c47bSJack F Vogel return; 655356c2c47bSJack F Vogel } 655456c2c47bSJack F Vogel } 655556c2c47bSJack F Vogel 655656c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 655756c2c47bSJack F Vogel addr = &addr_list->list[i]; 655856c2c47bSJack F Vogel ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY); 655956c2c47bSJack F Vogel } 656056c2c47bSJack F Vogel 656156c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS); 656256c2c47bSJack F Vogel } 656356c2c47bSJack F Vogel 656456c2c47bSJack F Vogel static void 656556c2c47bSJack F Vogel ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 656656c2c47bSJack F Vogel uint16_t msg_size) 656756c2c47bSJack F Vogel { 656856c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr_list *addr_list; 656956c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr *addr; 657056c2c47bSJack F Vogel size_t expected_size; 657156c2c47bSJack F Vogel int i; 657256c2c47bSJack F Vogel 657356c2c47bSJack F Vogel if (msg_size < sizeof(*addr_list)) { 657456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 657556c2c47bSJack F Vogel I40E_ERR_PARAM); 657656c2c47bSJack F Vogel return; 657756c2c47bSJack F Vogel } 657856c2c47bSJack F Vogel 657956c2c47bSJack F Vogel addr_list = msg; 658056c2c47bSJack F Vogel expected_size = sizeof(*addr_list) + 658156c2c47bSJack F Vogel addr_list->num_elements * sizeof(*addr); 658256c2c47bSJack F Vogel 658356c2c47bSJack F Vogel if (addr_list->num_elements == 0 || 658456c2c47bSJack F Vogel addr_list->vsi_id != vf->vsi.vsi_num || 658556c2c47bSJack F Vogel msg_size != expected_size) { 658656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 658756c2c47bSJack F Vogel I40E_ERR_PARAM); 658856c2c47bSJack F Vogel return; 658956c2c47bSJack F Vogel } 659056c2c47bSJack F Vogel 659156c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 659256c2c47bSJack F Vogel addr = &addr_list->list[i]; 659356c2c47bSJack F Vogel if (ixl_zero_mac(addr->addr) || ixl_bcast_mac(addr->addr)) { 659456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 659556c2c47bSJack F Vogel I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM); 659656c2c47bSJack F Vogel return; 659756c2c47bSJack F Vogel } 659856c2c47bSJack F Vogel } 659956c2c47bSJack F Vogel 660056c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 660156c2c47bSJack F Vogel addr = &addr_list->list[i]; 660256c2c47bSJack F Vogel ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY); 660356c2c47bSJack F Vogel } 660456c2c47bSJack F Vogel 660556c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS); 660656c2c47bSJack F Vogel } 660756c2c47bSJack F Vogel 660856c2c47bSJack F Vogel static enum i40e_status_code 660956c2c47bSJack F Vogel ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf) 661056c2c47bSJack F Vogel { 661156c2c47bSJack F Vogel struct i40e_vsi_context vsi_ctx; 661256c2c47bSJack F Vogel 661356c2c47bSJack F Vogel vsi_ctx.seid = vf->vsi.seid; 661456c2c47bSJack F Vogel 661556c2c47bSJack F Vogel bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); 661656c2c47bSJack F Vogel vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID); 661756c2c47bSJack F Vogel vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 661856c2c47bSJack F Vogel I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 661956c2c47bSJack F Vogel return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL)); 662056c2c47bSJack F Vogel } 662156c2c47bSJack F Vogel 662256c2c47bSJack F Vogel static void 662356c2c47bSJack F Vogel ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 662456c2c47bSJack F Vogel uint16_t msg_size) 662556c2c47bSJack F Vogel { 662656c2c47bSJack F Vogel struct i40e_virtchnl_vlan_filter_list *filter_list; 662756c2c47bSJack F Vogel enum i40e_status_code code; 662856c2c47bSJack F Vogel size_t expected_size; 662956c2c47bSJack F Vogel int i; 663056c2c47bSJack F Vogel 663156c2c47bSJack F Vogel if (msg_size < sizeof(*filter_list)) { 663256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 663356c2c47bSJack F Vogel I40E_ERR_PARAM); 663456c2c47bSJack F Vogel return; 663556c2c47bSJack F Vogel } 663656c2c47bSJack F Vogel 663756c2c47bSJack F Vogel filter_list = msg; 663856c2c47bSJack F Vogel expected_size = sizeof(*filter_list) + 663956c2c47bSJack F Vogel filter_list->num_elements * sizeof(uint16_t); 664056c2c47bSJack F Vogel if (filter_list->num_elements == 0 || 664156c2c47bSJack F Vogel filter_list->vsi_id != vf->vsi.vsi_num || 664256c2c47bSJack F Vogel msg_size != expected_size) { 664356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 664456c2c47bSJack F Vogel I40E_ERR_PARAM); 664556c2c47bSJack F Vogel return; 664656c2c47bSJack F Vogel } 664756c2c47bSJack F Vogel 664856c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) { 664956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 665056c2c47bSJack F Vogel I40E_ERR_PARAM); 665156c2c47bSJack F Vogel return; 665256c2c47bSJack F Vogel } 665356c2c47bSJack F Vogel 665456c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) { 665556c2c47bSJack F Vogel if (filter_list->vlan_id[i] > EVL_VLID_MASK) { 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 666256c2c47bSJack F Vogel code = ixl_vf_enable_vlan_strip(pf, vf); 666356c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 666456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 666556c2c47bSJack F Vogel I40E_ERR_PARAM); 666656c2c47bSJack F Vogel } 666756c2c47bSJack F Vogel 666856c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) 666956c2c47bSJack F Vogel ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]); 667056c2c47bSJack F Vogel 667156c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN); 667256c2c47bSJack F Vogel } 667356c2c47bSJack F Vogel 667456c2c47bSJack F Vogel static void 667556c2c47bSJack F Vogel ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 667656c2c47bSJack F Vogel uint16_t msg_size) 667756c2c47bSJack F Vogel { 667856c2c47bSJack F Vogel struct i40e_virtchnl_vlan_filter_list *filter_list; 667956c2c47bSJack F Vogel int i; 668056c2c47bSJack F Vogel size_t expected_size; 668156c2c47bSJack F Vogel 668256c2c47bSJack F Vogel if (msg_size < sizeof(*filter_list)) { 668356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN, 668456c2c47bSJack F Vogel I40E_ERR_PARAM); 668556c2c47bSJack F Vogel return; 668656c2c47bSJack F Vogel } 668756c2c47bSJack F Vogel 668856c2c47bSJack F Vogel filter_list = msg; 668956c2c47bSJack F Vogel expected_size = sizeof(*filter_list) + 669056c2c47bSJack F Vogel filter_list->num_elements * sizeof(uint16_t); 669156c2c47bSJack F Vogel if (filter_list->num_elements == 0 || 669256c2c47bSJack F Vogel filter_list->vsi_id != vf->vsi.vsi_num || 669356c2c47bSJack F Vogel msg_size != expected_size) { 669456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN, 669556c2c47bSJack F Vogel I40E_ERR_PARAM); 669656c2c47bSJack F Vogel return; 669756c2c47bSJack F Vogel } 669856c2c47bSJack F Vogel 669956c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) { 670056c2c47bSJack F Vogel if (filter_list->vlan_id[i] > EVL_VLID_MASK) { 670156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 670256c2c47bSJack F Vogel I40E_ERR_PARAM); 670356c2c47bSJack F Vogel return; 670456c2c47bSJack F Vogel } 670556c2c47bSJack F Vogel } 670656c2c47bSJack F Vogel 670756c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) { 670856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 670956c2c47bSJack F Vogel I40E_ERR_PARAM); 671056c2c47bSJack F Vogel return; 671156c2c47bSJack F Vogel } 671256c2c47bSJack F Vogel 671356c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) 671456c2c47bSJack F Vogel ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]); 671556c2c47bSJack F Vogel 671656c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN); 671756c2c47bSJack F Vogel } 671856c2c47bSJack F Vogel 671956c2c47bSJack F Vogel static void 672056c2c47bSJack F Vogel ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, 672156c2c47bSJack F Vogel void *msg, uint16_t msg_size) 672256c2c47bSJack F Vogel { 672356c2c47bSJack F Vogel struct i40e_virtchnl_promisc_info *info; 672456c2c47bSJack F Vogel enum i40e_status_code code; 672556c2c47bSJack F Vogel 672656c2c47bSJack F Vogel if (msg_size != sizeof(*info)) { 672756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 672856c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 672956c2c47bSJack F Vogel return; 673056c2c47bSJack F Vogel } 673156c2c47bSJack F Vogel 673229899c0aSKevin Lo if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) { 673356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 673456c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 673556c2c47bSJack F Vogel return; 673656c2c47bSJack F Vogel } 673756c2c47bSJack F Vogel 673856c2c47bSJack F Vogel info = msg; 673956c2c47bSJack F Vogel if (info->vsi_id != vf->vsi.vsi_num) { 674056c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 674156c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 674256c2c47bSJack F Vogel return; 674356c2c47bSJack F Vogel } 674456c2c47bSJack F Vogel 674556c2c47bSJack F Vogel code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id, 674656c2c47bSJack F Vogel info->flags & I40E_FLAG_VF_UNICAST_PROMISC, NULL); 674756c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 674856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 674956c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); 675056c2c47bSJack F Vogel return; 675156c2c47bSJack F Vogel } 675256c2c47bSJack F Vogel 675356c2c47bSJack F Vogel code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id, 675456c2c47bSJack F Vogel info->flags & I40E_FLAG_VF_MULTICAST_PROMISC, NULL); 675556c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 675656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 675756c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); 675856c2c47bSJack F Vogel return; 675956c2c47bSJack F Vogel } 676056c2c47bSJack F Vogel 676156c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE); 676256c2c47bSJack F Vogel } 676356c2c47bSJack F Vogel 676456c2c47bSJack F Vogel static void 676556c2c47bSJack F Vogel ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 676656c2c47bSJack F Vogel uint16_t msg_size) 676756c2c47bSJack F Vogel { 676856c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *queue; 676956c2c47bSJack F Vogel 677056c2c47bSJack F Vogel if (msg_size != sizeof(*queue)) { 677156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 677256c2c47bSJack F Vogel I40E_ERR_PARAM); 677356c2c47bSJack F Vogel return; 677456c2c47bSJack F Vogel } 677556c2c47bSJack F Vogel 677656c2c47bSJack F Vogel queue = msg; 677756c2c47bSJack F Vogel if (queue->vsi_id != vf->vsi.vsi_num) { 677856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 677956c2c47bSJack F Vogel I40E_ERR_PARAM); 678056c2c47bSJack F Vogel return; 678156c2c47bSJack F Vogel } 678256c2c47bSJack F Vogel 678356c2c47bSJack F Vogel ixl_update_eth_stats(&vf->vsi); 678456c2c47bSJack F Vogel 678556c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 678656c2c47bSJack F Vogel I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats)); 678756c2c47bSJack F Vogel } 678856c2c47bSJack F Vogel 678956c2c47bSJack F Vogel static void 679056c2c47bSJack F Vogel ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event) 679156c2c47bSJack F Vogel { 679256c2c47bSJack F Vogel struct ixl_vf *vf; 679356c2c47bSJack F Vogel void *msg; 679456c2c47bSJack F Vogel uint16_t vf_num, msg_size; 679556c2c47bSJack F Vogel uint32_t opcode; 679656c2c47bSJack F Vogel 679756c2c47bSJack F Vogel vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id; 679856c2c47bSJack F Vogel opcode = le32toh(event->desc.cookie_high); 679956c2c47bSJack F Vogel 680056c2c47bSJack F Vogel if (vf_num >= pf->num_vfs) { 680156c2c47bSJack F Vogel device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num); 680256c2c47bSJack F Vogel return; 680356c2c47bSJack F Vogel } 680456c2c47bSJack F Vogel 680556c2c47bSJack F Vogel vf = &pf->vfs[vf_num]; 680656c2c47bSJack F Vogel msg = event->msg_buf; 680756c2c47bSJack F Vogel msg_size = event->msg_len; 680856c2c47bSJack F Vogel 680956c2c47bSJack F Vogel I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode), 681056c2c47bSJack F Vogel "Got msg %s(%d) from VF-%d of size %d\n", 681156c2c47bSJack F Vogel ixl_vc_opcode_str(opcode), opcode, vf_num, msg_size); 681256c2c47bSJack F Vogel 681356c2c47bSJack F Vogel switch (opcode) { 681456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_VERSION: 681556c2c47bSJack F Vogel ixl_vf_version_msg(pf, vf, msg, msg_size); 681656c2c47bSJack F Vogel break; 681756c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_RESET_VF: 681856c2c47bSJack F Vogel ixl_vf_reset_msg(pf, vf, msg, msg_size); 681956c2c47bSJack F Vogel break; 682056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: 682156c2c47bSJack F Vogel ixl_vf_get_resources_msg(pf, vf, msg, msg_size); 682256c2c47bSJack F Vogel break; 682356c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: 682456c2c47bSJack F Vogel ixl_vf_config_vsi_msg(pf, vf, msg, msg_size); 682556c2c47bSJack F Vogel break; 682656c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: 682756c2c47bSJack F Vogel ixl_vf_config_irq_msg(pf, vf, msg, msg_size); 682856c2c47bSJack F Vogel break; 682956c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ENABLE_QUEUES: 683056c2c47bSJack F Vogel ixl_vf_enable_queues_msg(pf, vf, msg, msg_size); 683156c2c47bSJack F Vogel break; 683256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DISABLE_QUEUES: 683356c2c47bSJack F Vogel ixl_vf_disable_queues_msg(pf, vf, msg, msg_size); 683456c2c47bSJack F Vogel break; 683556c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: 683656c2c47bSJack F Vogel ixl_vf_add_mac_msg(pf, vf, msg, msg_size); 683756c2c47bSJack F Vogel break; 683856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: 683956c2c47bSJack F Vogel ixl_vf_del_mac_msg(pf, vf, msg, msg_size); 684056c2c47bSJack F Vogel break; 684156c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_VLAN: 684256c2c47bSJack F Vogel ixl_vf_add_vlan_msg(pf, vf, msg, msg_size); 684356c2c47bSJack F Vogel break; 684456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_VLAN: 684556c2c47bSJack F Vogel ixl_vf_del_vlan_msg(pf, vf, msg, msg_size); 684656c2c47bSJack F Vogel break; 684756c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: 684856c2c47bSJack F Vogel ixl_vf_config_promisc_msg(pf, vf, msg, msg_size); 684956c2c47bSJack F Vogel break; 685056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 685156c2c47bSJack F Vogel ixl_vf_get_stats_msg(pf, vf, msg, msg_size); 685256c2c47bSJack F Vogel break; 685356c2c47bSJack F Vogel 685456c2c47bSJack F Vogel /* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */ 685556c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: 685656c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: 685756c2c47bSJack F Vogel default: 685856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED); 685956c2c47bSJack F Vogel break; 686056c2c47bSJack F Vogel } 686156c2c47bSJack F Vogel } 686256c2c47bSJack F Vogel 686356c2c47bSJack F Vogel /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */ 686456c2c47bSJack F Vogel static void 686556c2c47bSJack F Vogel ixl_handle_vflr(void *arg, int pending) 686656c2c47bSJack F Vogel { 686756c2c47bSJack F Vogel struct ixl_pf *pf; 686856c2c47bSJack F Vogel struct i40e_hw *hw; 686956c2c47bSJack F Vogel uint16_t global_vf_num; 687056c2c47bSJack F Vogel uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0; 687156c2c47bSJack F Vogel int i; 687256c2c47bSJack F Vogel 687356c2c47bSJack F Vogel pf = arg; 687456c2c47bSJack F Vogel hw = &pf->hw; 687556c2c47bSJack F Vogel 687656c2c47bSJack F Vogel IXL_PF_LOCK(pf); 687756c2c47bSJack F Vogel for (i = 0; i < pf->num_vfs; i++) { 687856c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + i; 687956c2c47bSJack F Vogel 688056c2c47bSJack F Vogel vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num); 688156c2c47bSJack F Vogel vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num); 688256c2c47bSJack F Vogel vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index)); 688356c2c47bSJack F Vogel if (vflrstat & vflrstat_mask) { 688456c2c47bSJack F Vogel wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index), 688556c2c47bSJack F Vogel vflrstat_mask); 688656c2c47bSJack F Vogel 688756c2c47bSJack F Vogel ixl_reinit_vf(pf, &pf->vfs[i]); 688856c2c47bSJack F Vogel } 688956c2c47bSJack F Vogel } 689056c2c47bSJack F Vogel 689156c2c47bSJack F Vogel icr0 = rd32(hw, I40E_PFINT_ICR0_ENA); 689256c2c47bSJack F Vogel icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK; 689356c2c47bSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, icr0); 689456c2c47bSJack F Vogel ixl_flush(hw); 689556c2c47bSJack F Vogel 689656c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 689756c2c47bSJack F Vogel } 689856c2c47bSJack F Vogel 689956c2c47bSJack F Vogel static int 690056c2c47bSJack F Vogel ixl_adminq_err_to_errno(enum i40e_admin_queue_err err) 690156c2c47bSJack F Vogel { 690256c2c47bSJack F Vogel 690356c2c47bSJack F Vogel switch (err) { 690456c2c47bSJack F Vogel case I40E_AQ_RC_EPERM: 690556c2c47bSJack F Vogel return (EPERM); 690656c2c47bSJack F Vogel case I40E_AQ_RC_ENOENT: 690756c2c47bSJack F Vogel return (ENOENT); 690856c2c47bSJack F Vogel case I40E_AQ_RC_ESRCH: 690956c2c47bSJack F Vogel return (ESRCH); 691056c2c47bSJack F Vogel case I40E_AQ_RC_EINTR: 691156c2c47bSJack F Vogel return (EINTR); 691256c2c47bSJack F Vogel case I40E_AQ_RC_EIO: 691356c2c47bSJack F Vogel return (EIO); 691456c2c47bSJack F Vogel case I40E_AQ_RC_ENXIO: 691556c2c47bSJack F Vogel return (ENXIO); 691656c2c47bSJack F Vogel case I40E_AQ_RC_E2BIG: 691756c2c47bSJack F Vogel return (E2BIG); 691856c2c47bSJack F Vogel case I40E_AQ_RC_EAGAIN: 691956c2c47bSJack F Vogel return (EAGAIN); 692056c2c47bSJack F Vogel case I40E_AQ_RC_ENOMEM: 692156c2c47bSJack F Vogel return (ENOMEM); 692256c2c47bSJack F Vogel case I40E_AQ_RC_EACCES: 692356c2c47bSJack F Vogel return (EACCES); 692456c2c47bSJack F Vogel case I40E_AQ_RC_EFAULT: 692556c2c47bSJack F Vogel return (EFAULT); 692656c2c47bSJack F Vogel case I40E_AQ_RC_EBUSY: 692756c2c47bSJack F Vogel return (EBUSY); 692856c2c47bSJack F Vogel case I40E_AQ_RC_EEXIST: 692956c2c47bSJack F Vogel return (EEXIST); 693056c2c47bSJack F Vogel case I40E_AQ_RC_EINVAL: 693156c2c47bSJack F Vogel return (EINVAL); 693256c2c47bSJack F Vogel case I40E_AQ_RC_ENOTTY: 693356c2c47bSJack F Vogel return (ENOTTY); 693456c2c47bSJack F Vogel case I40E_AQ_RC_ENOSPC: 693556c2c47bSJack F Vogel return (ENOSPC); 693656c2c47bSJack F Vogel case I40E_AQ_RC_ENOSYS: 693756c2c47bSJack F Vogel return (ENOSYS); 693856c2c47bSJack F Vogel case I40E_AQ_RC_ERANGE: 693956c2c47bSJack F Vogel return (ERANGE); 694056c2c47bSJack F Vogel case I40E_AQ_RC_EFLUSHED: 694156c2c47bSJack F Vogel return (EINVAL); /* No exact equivalent in errno.h */ 694256c2c47bSJack F Vogel case I40E_AQ_RC_BAD_ADDR: 694356c2c47bSJack F Vogel return (EFAULT); 694456c2c47bSJack F Vogel case I40E_AQ_RC_EMODE: 694556c2c47bSJack F Vogel return (EPERM); 694656c2c47bSJack F Vogel case I40E_AQ_RC_EFBIG: 694756c2c47bSJack F Vogel return (EFBIG); 694856c2c47bSJack F Vogel default: 694956c2c47bSJack F Vogel return (EINVAL); 695056c2c47bSJack F Vogel } 695156c2c47bSJack F Vogel } 695256c2c47bSJack F Vogel 695356c2c47bSJack F Vogel static int 6954a48d00d2SEric Joyner ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params) 695556c2c47bSJack F Vogel { 695656c2c47bSJack F Vogel struct ixl_pf *pf; 695756c2c47bSJack F Vogel struct i40e_hw *hw; 695856c2c47bSJack F Vogel struct ixl_vsi *pf_vsi; 695956c2c47bSJack F Vogel enum i40e_status_code ret; 696056c2c47bSJack F Vogel int i, error; 696156c2c47bSJack F Vogel 696256c2c47bSJack F Vogel pf = device_get_softc(dev); 696356c2c47bSJack F Vogel hw = &pf->hw; 696456c2c47bSJack F Vogel pf_vsi = &pf->vsi; 696556c2c47bSJack F Vogel 696656c2c47bSJack F Vogel IXL_PF_LOCK(pf); 696756c2c47bSJack F Vogel pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT | 696856c2c47bSJack F Vogel M_ZERO); 696956c2c47bSJack F Vogel 697056c2c47bSJack F Vogel if (pf->vfs == NULL) { 697156c2c47bSJack F Vogel error = ENOMEM; 697256c2c47bSJack F Vogel goto fail; 697356c2c47bSJack F Vogel } 697456c2c47bSJack F Vogel 697556c2c47bSJack F Vogel for (i = 0; i < num_vfs; i++) 697656c2c47bSJack F Vogel sysctl_ctx_init(&pf->vfs[i].ctx); 697756c2c47bSJack F Vogel 697856c2c47bSJack F Vogel ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid, 697956c2c47bSJack F Vogel 1, FALSE, FALSE, &pf->veb_seid, NULL); 698056c2c47bSJack F Vogel if (ret != I40E_SUCCESS) { 698156c2c47bSJack F Vogel error = ixl_adminq_err_to_errno(hw->aq.asq_last_status); 698256c2c47bSJack F Vogel device_printf(dev, "add_veb failed; code=%d error=%d", ret, 698356c2c47bSJack F Vogel error); 698456c2c47bSJack F Vogel goto fail; 698556c2c47bSJack F Vogel } 698656c2c47bSJack F Vogel 698756c2c47bSJack F Vogel ixl_configure_msix(pf); 698856c2c47bSJack F Vogel ixl_enable_adminq(hw); 698956c2c47bSJack F Vogel 699056c2c47bSJack F Vogel pf->num_vfs = num_vfs; 699156c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 699256c2c47bSJack F Vogel return (0); 699356c2c47bSJack F Vogel 699456c2c47bSJack F Vogel fail: 699556c2c47bSJack F Vogel free(pf->vfs, M_IXL); 699656c2c47bSJack F Vogel pf->vfs = NULL; 699756c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 699856c2c47bSJack F Vogel return (error); 699956c2c47bSJack F Vogel } 700056c2c47bSJack F Vogel 700156c2c47bSJack F Vogel static void 7002a48d00d2SEric Joyner ixl_iov_uninit(device_t dev) 700356c2c47bSJack F Vogel { 700456c2c47bSJack F Vogel struct ixl_pf *pf; 700556c2c47bSJack F Vogel struct i40e_hw *hw; 700656c2c47bSJack F Vogel struct ixl_vsi *vsi; 700756c2c47bSJack F Vogel struct ifnet *ifp; 700856c2c47bSJack F Vogel struct ixl_vf *vfs; 700956c2c47bSJack F Vogel int i, num_vfs; 701056c2c47bSJack F Vogel 701156c2c47bSJack F Vogel pf = device_get_softc(dev); 701256c2c47bSJack F Vogel hw = &pf->hw; 701356c2c47bSJack F Vogel vsi = &pf->vsi; 701456c2c47bSJack F Vogel ifp = vsi->ifp; 701556c2c47bSJack F Vogel 701656c2c47bSJack F Vogel IXL_PF_LOCK(pf); 701756c2c47bSJack F Vogel for (i = 0; i < pf->num_vfs; i++) { 701856c2c47bSJack F Vogel if (pf->vfs[i].vsi.seid != 0) 701956c2c47bSJack F Vogel i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL); 702056c2c47bSJack F Vogel } 702156c2c47bSJack F Vogel 702256c2c47bSJack F Vogel if (pf->veb_seid != 0) { 702356c2c47bSJack F Vogel i40e_aq_delete_element(hw, pf->veb_seid, NULL); 702456c2c47bSJack F Vogel pf->veb_seid = 0; 702556c2c47bSJack F Vogel } 702656c2c47bSJack F Vogel 702756c2c47bSJack F Vogel if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 702856c2c47bSJack F Vogel ixl_disable_intr(vsi); 702956c2c47bSJack F Vogel 703056c2c47bSJack F Vogel vfs = pf->vfs; 703156c2c47bSJack F Vogel num_vfs = pf->num_vfs; 703256c2c47bSJack F Vogel 703356c2c47bSJack F Vogel pf->vfs = NULL; 703456c2c47bSJack F Vogel pf->num_vfs = 0; 703556c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 703656c2c47bSJack F Vogel 703756c2c47bSJack F Vogel /* Do this after the unlock as sysctl_ctx_free might sleep. */ 703856c2c47bSJack F Vogel for (i = 0; i < num_vfs; i++) 703956c2c47bSJack F Vogel sysctl_ctx_free(&vfs[i].ctx); 704056c2c47bSJack F Vogel free(vfs, M_IXL); 704156c2c47bSJack F Vogel } 704256c2c47bSJack F Vogel 704356c2c47bSJack F Vogel static int 704456c2c47bSJack F Vogel ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params) 704556c2c47bSJack F Vogel { 704656c2c47bSJack F Vogel char sysctl_name[QUEUE_NAME_LEN]; 704756c2c47bSJack F Vogel struct ixl_pf *pf; 704856c2c47bSJack F Vogel struct ixl_vf *vf; 704956c2c47bSJack F Vogel const void *mac; 705056c2c47bSJack F Vogel size_t size; 705156c2c47bSJack F Vogel int error; 705256c2c47bSJack F Vogel 705356c2c47bSJack F Vogel pf = device_get_softc(dev); 705456c2c47bSJack F Vogel vf = &pf->vfs[vfnum]; 705556c2c47bSJack F Vogel 705656c2c47bSJack F Vogel IXL_PF_LOCK(pf); 705756c2c47bSJack F Vogel vf->vf_num = vfnum; 705856c2c47bSJack F Vogel 705956c2c47bSJack F Vogel vf->vsi.back = pf; 706056c2c47bSJack F Vogel vf->vf_flags = VF_FLAG_ENABLED; 706156c2c47bSJack F Vogel SLIST_INIT(&vf->vsi.ftl); 706256c2c47bSJack F Vogel 706356c2c47bSJack F Vogel error = ixl_vf_setup_vsi(pf, vf); 706456c2c47bSJack F Vogel if (error != 0) 706556c2c47bSJack F Vogel goto out; 706656c2c47bSJack F Vogel 706756c2c47bSJack F Vogel if (nvlist_exists_binary(params, "mac-addr")) { 706856c2c47bSJack F Vogel mac = nvlist_get_binary(params, "mac-addr", &size); 706956c2c47bSJack F Vogel bcopy(mac, vf->mac, ETHER_ADDR_LEN); 707056c2c47bSJack F Vogel 707156c2c47bSJack F Vogel if (nvlist_get_bool(params, "allow-set-mac")) 707256c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_SET_MAC_CAP; 707356c2c47bSJack F Vogel } else 707456c2c47bSJack F Vogel /* 707556c2c47bSJack F Vogel * If the administrator has not specified a MAC address then 707656c2c47bSJack F Vogel * we must allow the VF to choose one. 707756c2c47bSJack F Vogel */ 707856c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_SET_MAC_CAP; 707956c2c47bSJack F Vogel 708056c2c47bSJack F Vogel if (nvlist_get_bool(params, "mac-anti-spoof")) 708156c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF; 708256c2c47bSJack F Vogel 708356c2c47bSJack F Vogel if (nvlist_get_bool(params, "allow-promisc")) 708456c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_PROMISC_CAP; 708556c2c47bSJack F Vogel 708656c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_VLAN_CAP; 708756c2c47bSJack F Vogel 708856c2c47bSJack F Vogel ixl_reset_vf(pf, vf); 708956c2c47bSJack F Vogel out: 709056c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 709156c2c47bSJack F Vogel if (error == 0) { 709256c2c47bSJack F Vogel snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum); 709356c2c47bSJack F Vogel ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name); 709456c2c47bSJack F Vogel } 709556c2c47bSJack F Vogel 709656c2c47bSJack F Vogel return (error); 709756c2c47bSJack F Vogel } 709856c2c47bSJack F Vogel #endif /* PCI_IOV */ 7099