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*d4683565SEric Joyner char ixl_driver_version[] = "1.4.27-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 *); 1086c426059SEric Joyner 1096c426059SEric Joyner static int ixl_setup_adminq_msix(struct ixl_pf *); 1106c426059SEric Joyner static int ixl_setup_adminq_tq(struct ixl_pf *); 1116c426059SEric Joyner static int ixl_setup_queue_msix(struct ixl_vsi *); 1126c426059SEric Joyner static int ixl_setup_queue_tqs(struct ixl_vsi *); 1136c426059SEric Joyner static int ixl_teardown_adminq_msix(struct ixl_pf *); 1146c426059SEric Joyner static int ixl_teardown_queue_msix(struct ixl_vsi *); 1156c426059SEric Joyner static void ixl_configure_intr0_msix(struct ixl_pf *); 1166c426059SEric Joyner static void ixl_configure_queue_intr_msix(struct ixl_pf *); 1176c426059SEric Joyner static void ixl_free_queue_tqs(struct ixl_vsi *); 1186c426059SEric Joyner static void ixl_free_adminq_tq(struct ixl_pf *); 1196c426059SEric Joyner 12061ae650dSJack F Vogel static int ixl_assign_vsi_legacy(struct ixl_pf *); 12161ae650dSJack F Vogel static int ixl_init_msix(struct ixl_pf *); 12261ae650dSJack F Vogel static void ixl_configure_itr(struct ixl_pf *); 12361ae650dSJack F Vogel static void ixl_configure_legacy(struct ixl_pf *); 12461ae650dSJack F Vogel static void ixl_free_pci_resources(struct ixl_pf *); 12561ae650dSJack F Vogel static void ixl_local_timer(void *); 12661ae650dSJack F Vogel static int ixl_setup_interface(device_t, struct ixl_vsi *); 12756c2c47bSJack F Vogel static void ixl_link_event(struct ixl_pf *, struct i40e_arq_event_info *); 12861ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *); 12961ae650dSJack F Vogel static void ixl_set_queue_rx_itr(struct ixl_queue *); 13061ae650dSJack F Vogel static void ixl_set_queue_tx_itr(struct ixl_queue *); 131e5100ee2SJack F Vogel static int ixl_set_advertised_speeds(struct ixl_pf *, int); 1326c426059SEric Joyner static void ixl_get_initial_advertised_speeds(struct ixl_pf *); 13361ae650dSJack F Vogel 13456c2c47bSJack F Vogel static int ixl_enable_rings(struct ixl_vsi *); 13556c2c47bSJack F Vogel static int ixl_disable_rings(struct ixl_vsi *); 13661ae650dSJack F Vogel static void ixl_enable_intr(struct ixl_vsi *); 13761ae650dSJack F Vogel static void ixl_disable_intr(struct ixl_vsi *); 13856c2c47bSJack F Vogel static void ixl_disable_rings_intr(struct ixl_vsi *); 13961ae650dSJack F Vogel 14061ae650dSJack F Vogel static void ixl_enable_adminq(struct i40e_hw *); 14161ae650dSJack F Vogel static void ixl_disable_adminq(struct i40e_hw *); 14261ae650dSJack F Vogel static void ixl_enable_queue(struct i40e_hw *, int); 14361ae650dSJack F Vogel static void ixl_disable_queue(struct i40e_hw *, int); 14461ae650dSJack F Vogel static void ixl_enable_legacy(struct i40e_hw *); 14561ae650dSJack F Vogel static void ixl_disable_legacy(struct i40e_hw *); 14661ae650dSJack F Vogel 14761ae650dSJack F Vogel static void ixl_set_promisc(struct ixl_vsi *); 14861ae650dSJack F Vogel static void ixl_add_multi(struct ixl_vsi *); 14961ae650dSJack F Vogel static void ixl_del_multi(struct ixl_vsi *); 15061ae650dSJack F Vogel static void ixl_register_vlan(void *, struct ifnet *, u16); 15161ae650dSJack F Vogel static void ixl_unregister_vlan(void *, struct ifnet *, u16); 15261ae650dSJack F Vogel static void ixl_setup_vlan_filters(struct ixl_vsi *); 15361ae650dSJack F Vogel 15461ae650dSJack F Vogel static void ixl_init_filters(struct ixl_vsi *); 15556c2c47bSJack F Vogel static void ixl_reconfigure_filters(struct ixl_vsi *vsi); 15661ae650dSJack F Vogel static void ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan); 15761ae650dSJack F Vogel static void ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan); 15861ae650dSJack F Vogel static void ixl_add_hw_filters(struct ixl_vsi *, int, int); 15961ae650dSJack F Vogel static void ixl_del_hw_filters(struct ixl_vsi *, int); 16061ae650dSJack F Vogel static struct ixl_mac_filter * 16161ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *, u8 *, s16); 16261ae650dSJack F Vogel static void ixl_add_mc_filter(struct ixl_vsi *, u8 *); 16356c2c47bSJack F Vogel static void ixl_free_mac_filters(struct ixl_vsi *vsi); 16456c2c47bSJack F Vogel 165fdb6f38aSEric Joyner /* Sysctls*/ 166fdb6f38aSEric Joyner static void ixl_add_device_sysctls(struct ixl_pf *); 16761ae650dSJack F Vogel 168fdb6f38aSEric Joyner static int ixl_set_flowcntl(SYSCTL_HANDLER_ARGS); 169fdb6f38aSEric Joyner static int ixl_set_advertise(SYSCTL_HANDLER_ARGS); 170fdb6f38aSEric Joyner static int ixl_current_speed(SYSCTL_HANDLER_ARGS); 171fdb6f38aSEric Joyner static int ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS); 172fdb6f38aSEric Joyner 173fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL 1741d767a8eSEric Joyner static int ixl_debug_info(SYSCTL_HANDLER_ARGS); 1751d767a8eSEric Joyner static void ixl_print_debug_info(struct ixl_pf *); 1761d767a8eSEric Joyner 177fdb6f38aSEric Joyner static int ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS); 178fdb6f38aSEric Joyner static int ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS); 179fdb6f38aSEric Joyner static int ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS); 180fdb6f38aSEric Joyner static int ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS); 181fdb6f38aSEric Joyner static int ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS); 182fdb6f38aSEric Joyner #endif 183fdb6f38aSEric Joyner 18461ae650dSJack F Vogel /* The MSI/X Interrupt handlers */ 18561ae650dSJack F Vogel static void ixl_intr(void *); 18661ae650dSJack F Vogel static void ixl_msix_que(void *); 18761ae650dSJack F Vogel static void ixl_msix_adminq(void *); 18861ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *); 18961ae650dSJack F Vogel 19061ae650dSJack F Vogel /* Deferred interrupt tasklets */ 19161ae650dSJack F Vogel static void ixl_do_adminq(void *, int); 19261ae650dSJack F Vogel 19361ae650dSJack F Vogel /* Statistics */ 19461ae650dSJack F Vogel static void ixl_add_hw_stats(struct ixl_pf *); 19561ae650dSJack F Vogel static void ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *, 19661ae650dSJack F Vogel struct sysctl_oid_list *, struct i40e_hw_port_stats *); 19761ae650dSJack F Vogel static void ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *, 19861ae650dSJack F Vogel struct sysctl_oid_list *, 19961ae650dSJack F Vogel struct i40e_eth_stats *); 20061ae650dSJack F Vogel static void ixl_update_stats_counters(struct ixl_pf *); 20161ae650dSJack F Vogel static void ixl_update_eth_stats(struct ixl_vsi *); 20256c2c47bSJack F Vogel static void ixl_update_vsi_stats(struct ixl_vsi *); 20361ae650dSJack F Vogel static void ixl_pf_reset_stats(struct ixl_pf *); 20461ae650dSJack F Vogel static void ixl_vsi_reset_stats(struct ixl_vsi *); 20561ae650dSJack F Vogel static void ixl_stat_update48(struct i40e_hw *, u32, u32, bool, 20661ae650dSJack F Vogel u64 *, u64 *); 20761ae650dSJack F Vogel static void ixl_stat_update32(struct i40e_hw *, u32, bool, 20861ae650dSJack F Vogel u64 *, u64 *); 209223d846dSEric Joyner /* NVM update */ 210223d846dSEric Joyner static int ixl_handle_nvmupd_cmd(struct ixl_pf *, struct ifdrv *); 2116c426059SEric Joyner static void ixl_handle_empr_reset(struct ixl_pf *); 2126c426059SEric Joyner static int ixl_rebuild_hw_structs_after_reset(struct ixl_pf *); 21361ae650dSJack F Vogel 2146d011ad5SEric Joyner /* Debug helper functions */ 2156d011ad5SEric Joyner #ifdef IXL_DEBUG 2166d011ad5SEric Joyner static void ixl_print_nvm_cmd(device_t, struct i40e_nvm_access *); 2176d011ad5SEric Joyner #endif 218223d846dSEric Joyner 21956c2c47bSJack F Vogel #ifdef PCI_IOV 22056c2c47bSJack F Vogel static int ixl_adminq_err_to_errno(enum i40e_admin_queue_err err); 22156c2c47bSJack F Vogel 222a48d00d2SEric Joyner static int ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t*); 223a48d00d2SEric Joyner static void ixl_iov_uninit(device_t dev); 22456c2c47bSJack F Vogel static int ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t*); 22556c2c47bSJack F Vogel 22656c2c47bSJack F Vogel static void ixl_handle_vf_msg(struct ixl_pf *, 22756c2c47bSJack F Vogel struct i40e_arq_event_info *); 22856c2c47bSJack F Vogel static void ixl_handle_vflr(void *arg, int pending); 22956c2c47bSJack F Vogel 23056c2c47bSJack F Vogel static void ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf); 23156c2c47bSJack F Vogel static void ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf); 23261ae650dSJack F Vogel #endif 23361ae650dSJack F Vogel 23461ae650dSJack F Vogel /********************************************************************* 23561ae650dSJack F Vogel * FreeBSD Device Interface Entry Points 23661ae650dSJack F Vogel *********************************************************************/ 23761ae650dSJack F Vogel 23861ae650dSJack F Vogel static device_method_t ixl_methods[] = { 23961ae650dSJack F Vogel /* Device interface */ 24061ae650dSJack F Vogel DEVMETHOD(device_probe, ixl_probe), 24161ae650dSJack F Vogel DEVMETHOD(device_attach, ixl_attach), 24261ae650dSJack F Vogel DEVMETHOD(device_detach, ixl_detach), 24361ae650dSJack F Vogel DEVMETHOD(device_shutdown, ixl_shutdown), 24456c2c47bSJack F Vogel #ifdef PCI_IOV 245a48d00d2SEric Joyner DEVMETHOD(pci_iov_init, ixl_iov_init), 246a48d00d2SEric Joyner DEVMETHOD(pci_iov_uninit, ixl_iov_uninit), 247a48d00d2SEric Joyner DEVMETHOD(pci_iov_add_vf, ixl_add_vf), 24856c2c47bSJack F Vogel #endif 24961ae650dSJack F Vogel {0, 0} 25061ae650dSJack F Vogel }; 25161ae650dSJack F Vogel 25261ae650dSJack F Vogel static driver_t ixl_driver = { 25361ae650dSJack F Vogel "ixl", ixl_methods, sizeof(struct ixl_pf), 25461ae650dSJack F Vogel }; 25561ae650dSJack F Vogel 25661ae650dSJack F Vogel devclass_t ixl_devclass; 25761ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); 25861ae650dSJack F Vogel 25961ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1); 26061ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1); 26131830672SJack F Vogel #ifdef DEV_NETMAP 26231830672SJack F Vogel MODULE_DEPEND(ixl, netmap, 1, 1, 1); 26331830672SJack F Vogel #endif /* DEV_NETMAP */ 26431830672SJack F Vogel 26561ae650dSJack F Vogel /* 26661ae650dSJack F Vogel ** Global reset mutex 26761ae650dSJack F Vogel */ 26861ae650dSJack F Vogel static struct mtx ixl_reset_mtx; 26961ae650dSJack F Vogel 27061ae650dSJack F Vogel /* 27161ae650dSJack F Vogel ** TUNEABLE PARAMETERS: 27261ae650dSJack F Vogel */ 27361ae650dSJack F Vogel 27461ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, 27561ae650dSJack F Vogel "IXL driver parameters"); 27661ae650dSJack F Vogel 27761ae650dSJack F Vogel /* 27861ae650dSJack F Vogel * MSIX should be the default for best performance, 27961ae650dSJack F Vogel * but this allows it to be forced off for testing. 28061ae650dSJack F Vogel */ 28161ae650dSJack F Vogel static int ixl_enable_msix = 1; 28261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); 28361ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, 28461ae650dSJack F Vogel "Enable MSI-X interrupts"); 28561ae650dSJack F Vogel 28661ae650dSJack F Vogel /* 28761ae650dSJack F Vogel ** Number of descriptors per ring: 28861ae650dSJack F Vogel ** - TX and RX are the same size 28961ae650dSJack F Vogel */ 29061ae650dSJack F Vogel static int ixl_ringsz = DEFAULT_RING; 29161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz); 29261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN, 29361ae650dSJack F Vogel &ixl_ringsz, 0, "Descriptor Ring Size"); 29461ae650dSJack F Vogel 29561ae650dSJack F Vogel /* 29661ae650dSJack F Vogel ** This can be set manually, if left as 0 the 29761ae650dSJack F Vogel ** number of queues will be calculated based 29861ae650dSJack F Vogel ** on cpus and msix vectors available. 29961ae650dSJack F Vogel */ 30061ae650dSJack F Vogel int ixl_max_queues = 0; 30161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues); 30261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN, 30361ae650dSJack F Vogel &ixl_max_queues, 0, "Number of Queues"); 30461ae650dSJack F Vogel 30561ae650dSJack F Vogel /* 30661ae650dSJack F Vogel ** Controls for Interrupt Throttling 30761ae650dSJack F Vogel ** - true/false for dynamic adjustment 30861ae650dSJack F Vogel ** - default values for static ITR 30961ae650dSJack F Vogel */ 3106d011ad5SEric Joyner int ixl_dynamic_rx_itr = 1; 31161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr); 31261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, 31361ae650dSJack F Vogel &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); 31461ae650dSJack F Vogel 3156d011ad5SEric Joyner int ixl_dynamic_tx_itr = 1; 31661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr); 31761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, 31861ae650dSJack F Vogel &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); 31961ae650dSJack F Vogel 32061ae650dSJack F Vogel int ixl_rx_itr = IXL_ITR_8K; 32161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr); 32261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, 32361ae650dSJack F Vogel &ixl_rx_itr, 0, "RX Interrupt Rate"); 32461ae650dSJack F Vogel 32561ae650dSJack F Vogel int ixl_tx_itr = IXL_ITR_4K; 32661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); 32761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, 32861ae650dSJack F Vogel &ixl_tx_itr, 0, "TX Interrupt Rate"); 32961ae650dSJack F Vogel 33061ae650dSJack F Vogel #ifdef IXL_FDIR 33161ae650dSJack F Vogel static int ixl_enable_fdir = 1; 33261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir); 33361ae650dSJack F Vogel /* Rate at which we sample */ 33461ae650dSJack F Vogel int ixl_atr_rate = 20; 33561ae650dSJack F Vogel TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate); 33661ae650dSJack F Vogel #endif 33761ae650dSJack F Vogel 33831830672SJack F Vogel #ifdef DEV_NETMAP 33931830672SJack F Vogel #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */ 34031830672SJack F Vogel #include <dev/netmap/if_ixl_netmap.h> 34131830672SJack F Vogel #endif /* DEV_NETMAP */ 342e5100ee2SJack F Vogel 34361ae650dSJack F Vogel static char *ixl_fc_string[6] = { 34461ae650dSJack F Vogel "None", 34561ae650dSJack F Vogel "Rx", 34661ae650dSJack F Vogel "Tx", 34761ae650dSJack F Vogel "Full", 34861ae650dSJack F Vogel "Priority", 34961ae650dSJack F Vogel "Default" 35061ae650dSJack F Vogel }; 35161ae650dSJack F Vogel 35256c2c47bSJack F Vogel static MALLOC_DEFINE(M_IXL, "ixl", "ixl driver allocations"); 35356c2c47bSJack F Vogel 35456c2c47bSJack F Vogel static uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] = 35556c2c47bSJack F Vogel {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 35661ae650dSJack F Vogel 35761ae650dSJack F Vogel /********************************************************************* 35861ae650dSJack F Vogel * Device identification routine 35961ae650dSJack F Vogel * 36061ae650dSJack F Vogel * ixl_probe determines if the driver should be loaded on 36161ae650dSJack F Vogel * the hardware based on PCI vendor/device id of the device. 36261ae650dSJack F Vogel * 36361ae650dSJack F Vogel * return BUS_PROBE_DEFAULT on success, positive on failure 36461ae650dSJack F Vogel *********************************************************************/ 36561ae650dSJack F Vogel 36661ae650dSJack F Vogel static int 36761ae650dSJack F Vogel ixl_probe(device_t dev) 36861ae650dSJack F Vogel { 36961ae650dSJack F Vogel ixl_vendor_info_t *ent; 37061ae650dSJack F Vogel 37161ae650dSJack F Vogel u16 pci_vendor_id, pci_device_id; 37261ae650dSJack F Vogel u16 pci_subvendor_id, pci_subdevice_id; 37361ae650dSJack F Vogel char device_name[256]; 37461ae650dSJack F Vogel static bool lock_init = FALSE; 37561ae650dSJack F Vogel 3761d767a8eSEric Joyner #if 0 37761ae650dSJack F Vogel INIT_DEBUGOUT("ixl_probe: begin"); 3781d767a8eSEric Joyner #endif 37961ae650dSJack F Vogel pci_vendor_id = pci_get_vendor(dev); 38061ae650dSJack F Vogel if (pci_vendor_id != I40E_INTEL_VENDOR_ID) 38161ae650dSJack F Vogel return (ENXIO); 38261ae650dSJack F Vogel 38361ae650dSJack F Vogel pci_device_id = pci_get_device(dev); 38461ae650dSJack F Vogel pci_subvendor_id = pci_get_subvendor(dev); 38561ae650dSJack F Vogel pci_subdevice_id = pci_get_subdevice(dev); 38661ae650dSJack F Vogel 38761ae650dSJack F Vogel ent = ixl_vendor_info_array; 38861ae650dSJack F Vogel while (ent->vendor_id != 0) { 38961ae650dSJack F Vogel if ((pci_vendor_id == ent->vendor_id) && 39061ae650dSJack F Vogel (pci_device_id == ent->device_id) && 39161ae650dSJack F Vogel 39261ae650dSJack F Vogel ((pci_subvendor_id == ent->subvendor_id) || 39361ae650dSJack F Vogel (ent->subvendor_id == 0)) && 39461ae650dSJack F Vogel 39561ae650dSJack F Vogel ((pci_subdevice_id == ent->subdevice_id) || 39661ae650dSJack F Vogel (ent->subdevice_id == 0))) { 39761ae650dSJack F Vogel sprintf(device_name, "%s, Version - %s", 39861ae650dSJack F Vogel ixl_strings[ent->index], 39961ae650dSJack F Vogel ixl_driver_version); 40061ae650dSJack F Vogel device_set_desc_copy(dev, device_name); 40161ae650dSJack F Vogel /* One shot mutex init */ 40261ae650dSJack F Vogel if (lock_init == FALSE) { 40361ae650dSJack F Vogel lock_init = TRUE; 40461ae650dSJack F Vogel mtx_init(&ixl_reset_mtx, 40561ae650dSJack F Vogel "ixl_reset", 40661ae650dSJack F Vogel "IXL RESET Lock", MTX_DEF); 40761ae650dSJack F Vogel } 40861ae650dSJack F Vogel return (BUS_PROBE_DEFAULT); 40961ae650dSJack F Vogel } 41061ae650dSJack F Vogel ent++; 41161ae650dSJack F Vogel } 41261ae650dSJack F Vogel return (ENXIO); 41361ae650dSJack F Vogel } 41461ae650dSJack F Vogel 41561ae650dSJack F Vogel /********************************************************************* 41661ae650dSJack F Vogel * Device initialization routine 41761ae650dSJack F Vogel * 41861ae650dSJack F Vogel * The attach entry point is called when the driver is being loaded. 41961ae650dSJack F Vogel * This routine identifies the type of hardware, allocates all resources 42061ae650dSJack F Vogel * and initializes the hardware. 42161ae650dSJack F Vogel * 42261ae650dSJack F Vogel * return 0 on success, positive on failure 42361ae650dSJack F Vogel *********************************************************************/ 42461ae650dSJack F Vogel 42561ae650dSJack F Vogel static int 42661ae650dSJack F Vogel ixl_attach(device_t dev) 42761ae650dSJack F Vogel { 42861ae650dSJack F Vogel struct ixl_pf *pf; 42961ae650dSJack F Vogel struct i40e_hw *hw; 43061ae650dSJack F Vogel struct ixl_vsi *vsi; 43161ae650dSJack F Vogel u16 bus; 43261ae650dSJack F Vogel int error = 0; 43356c2c47bSJack F Vogel #ifdef PCI_IOV 43456c2c47bSJack F Vogel nvlist_t *pf_schema, *vf_schema; 43556c2c47bSJack F Vogel int iov_error; 43656c2c47bSJack F Vogel #endif 43761ae650dSJack F Vogel 43861ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: begin"); 43961ae650dSJack F Vogel 44061ae650dSJack F Vogel /* Allocate, clear, and link in our primary soft structure */ 44161ae650dSJack F Vogel pf = device_get_softc(dev); 44261ae650dSJack F Vogel pf->dev = pf->osdep.dev = dev; 44361ae650dSJack F Vogel hw = &pf->hw; 44461ae650dSJack F Vogel 44561ae650dSJack F Vogel /* 44661ae650dSJack F Vogel ** Note this assumes we have a single embedded VSI, 44761ae650dSJack F Vogel ** this could be enhanced later to allocate multiple 44861ae650dSJack F Vogel */ 44961ae650dSJack F Vogel vsi = &pf->vsi; 45061ae650dSJack F Vogel vsi->dev = pf->dev; 45161ae650dSJack F Vogel 45261ae650dSJack F Vogel /* Core Lock Init*/ 45361ae650dSJack F Vogel IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev)); 45461ae650dSJack F Vogel 45561ae650dSJack F Vogel /* Set up the timer callout */ 45661ae650dSJack F Vogel callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); 45761ae650dSJack F Vogel 458e5100ee2SJack F Vogel /* Save off the PCI information */ 45961ae650dSJack F Vogel hw->vendor_id = pci_get_vendor(dev); 46061ae650dSJack F Vogel hw->device_id = pci_get_device(dev); 46161ae650dSJack F Vogel hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 46261ae650dSJack F Vogel hw->subsystem_vendor_id = 46361ae650dSJack F Vogel pci_read_config(dev, PCIR_SUBVEND_0, 2); 46461ae650dSJack F Vogel hw->subsystem_device_id = 46561ae650dSJack F Vogel pci_read_config(dev, PCIR_SUBDEV_0, 2); 46661ae650dSJack F Vogel 46761ae650dSJack F Vogel hw->bus.device = pci_get_slot(dev); 46861ae650dSJack F Vogel hw->bus.func = pci_get_function(dev); 46961ae650dSJack F Vogel 47056c2c47bSJack F Vogel pf->vc_debug_lvl = 1; 47156c2c47bSJack F Vogel 47261ae650dSJack F Vogel /* Do PCI setup - map BAR0, etc */ 47361ae650dSJack F Vogel if (ixl_allocate_pci_resources(pf)) { 47461ae650dSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 47561ae650dSJack F Vogel error = ENXIO; 47661ae650dSJack F Vogel goto err_out; 47761ae650dSJack F Vogel } 47861ae650dSJack F Vogel 47961ae650dSJack F Vogel /* Establish a clean starting point */ 48061ae650dSJack F Vogel i40e_clear_hw(hw); 48161ae650dSJack F Vogel error = i40e_pf_reset(hw); 48261ae650dSJack F Vogel if (error) { 483fdb6f38aSEric Joyner device_printf(dev, "PF reset failure %d\n", error); 48461ae650dSJack F Vogel error = EIO; 48561ae650dSJack F Vogel goto err_out; 48661ae650dSJack F Vogel } 48761ae650dSJack F Vogel 48861ae650dSJack F Vogel /* Set admin queue parameters */ 48961ae650dSJack F Vogel hw->aq.num_arq_entries = IXL_AQ_LEN; 49061ae650dSJack F Vogel hw->aq.num_asq_entries = IXL_AQ_LEN; 49161ae650dSJack F Vogel hw->aq.arq_buf_size = IXL_AQ_BUFSZ; 49261ae650dSJack F Vogel hw->aq.asq_buf_size = IXL_AQ_BUFSZ; 49361ae650dSJack F Vogel 494fdb6f38aSEric Joyner /* Initialize mac filter list for VSI */ 495fdb6f38aSEric Joyner SLIST_INIT(&vsi->ftl); 496fdb6f38aSEric Joyner 49761ae650dSJack F Vogel /* Initialize the shared code */ 49861ae650dSJack F Vogel error = i40e_init_shared_code(hw); 49961ae650dSJack F Vogel if (error) { 500fdb6f38aSEric Joyner device_printf(dev, "Unable to initialize shared code, error %d\n", 501fdb6f38aSEric Joyner error); 50261ae650dSJack F Vogel error = EIO; 50361ae650dSJack F Vogel goto err_out; 50461ae650dSJack F Vogel } 50561ae650dSJack F Vogel 50661ae650dSJack F Vogel /* Set up the admin queue */ 50761ae650dSJack F Vogel error = i40e_init_adminq(hw); 508fdb6f38aSEric Joyner if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) { 509fdb6f38aSEric Joyner device_printf(dev, "Unable to initialize Admin Queue, error %d\n", 510fdb6f38aSEric Joyner error); 511fdb6f38aSEric Joyner error = EIO; 512fdb6f38aSEric Joyner goto err_out; 513fdb6f38aSEric Joyner } 5141d767a8eSEric Joyner ixl_print_nvm_version(pf); 5151d767a8eSEric Joyner 516fdb6f38aSEric Joyner if (error == I40E_ERR_FIRMWARE_API_VERSION) { 51761ae650dSJack F Vogel device_printf(dev, "The driver for the device stopped " 51861ae650dSJack F Vogel "because the NVM image is newer than expected.\n" 51961ae650dSJack F Vogel "You must install the most recent version of " 52061ae650dSJack F Vogel "the network driver.\n"); 521fdb6f38aSEric Joyner error = EIO; 52261ae650dSJack F Vogel goto err_out; 52361ae650dSJack F Vogel } 52461ae650dSJack F Vogel 52561ae650dSJack F Vogel if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 52661ae650dSJack F Vogel hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) 52761ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 52861ae650dSJack F Vogel "a newer version of the NVM image than expected.\n" 52961ae650dSJack F Vogel "Please install the most recent version of the network driver.\n"); 53061ae650dSJack F Vogel else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || 53161ae650dSJack F Vogel hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) 53261ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 53361ae650dSJack F Vogel "an older version of the NVM image than expected.\n" 53461ae650dSJack F Vogel "Please update the NVM image.\n"); 53561ae650dSJack F Vogel 53661ae650dSJack F Vogel /* Clear PXE mode */ 53761ae650dSJack F Vogel i40e_clear_pxe_mode(hw); 53861ae650dSJack F Vogel 53961ae650dSJack F Vogel /* Get capabilities from the device */ 54061ae650dSJack F Vogel error = ixl_get_hw_capabilities(pf); 54161ae650dSJack F Vogel if (error) { 54261ae650dSJack F Vogel device_printf(dev, "HW capabilities failure!\n"); 54361ae650dSJack F Vogel goto err_get_cap; 54461ae650dSJack F Vogel } 54561ae650dSJack F Vogel 54661ae650dSJack F Vogel /* Set up host memory cache */ 54756c2c47bSJack F Vogel error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 54856c2c47bSJack F Vogel hw->func_caps.num_rx_qp, 0, 0); 54961ae650dSJack F Vogel if (error) { 55061ae650dSJack F Vogel device_printf(dev, "init_lan_hmc failed: %d\n", error); 55161ae650dSJack F Vogel goto err_get_cap; 55261ae650dSJack F Vogel } 55361ae650dSJack F Vogel 55461ae650dSJack F Vogel error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 55561ae650dSJack F Vogel if (error) { 55661ae650dSJack F Vogel device_printf(dev, "configure_lan_hmc failed: %d\n", error); 55761ae650dSJack F Vogel goto err_mac_hmc; 55861ae650dSJack F Vogel } 55961ae650dSJack F Vogel 560*d4683565SEric Joyner /* Disable LLDP from the firmware for certain NVM versions */ 561*d4683565SEric Joyner if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || 562*d4683565SEric Joyner (pf->hw.aq.fw_maj_ver < 4)) 56361ae650dSJack F Vogel i40e_aq_stop_lldp(hw, TRUE, NULL); 56461ae650dSJack F Vogel 56561ae650dSJack F Vogel i40e_get_mac_addr(hw, hw->mac.addr); 56661ae650dSJack F Vogel error = i40e_validate_mac_addr(hw->mac.addr); 56761ae650dSJack F Vogel if (error) { 56861ae650dSJack F Vogel device_printf(dev, "validate_mac_addr failed: %d\n", error); 56961ae650dSJack F Vogel goto err_mac_hmc; 57061ae650dSJack F Vogel } 57161ae650dSJack F Vogel bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 57261ae650dSJack F Vogel i40e_get_port_mac_addr(hw, hw->mac.port_addr); 57361ae650dSJack F Vogel 574e5100ee2SJack F Vogel /* Set up VSI and queues */ 57561ae650dSJack F Vogel if (ixl_setup_stations(pf) != 0) { 57661ae650dSJack F Vogel device_printf(dev, "setup stations failed!\n"); 57761ae650dSJack F Vogel error = ENOMEM; 57861ae650dSJack F Vogel goto err_mac_hmc; 57961ae650dSJack F Vogel } 58061ae650dSJack F Vogel 581b6c8f260SJack F Vogel if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 582b6c8f260SJack F Vogel (hw->aq.fw_maj_ver < 4)) { 58361ae650dSJack F Vogel i40e_msec_delay(75); 58461ae650dSJack F Vogel error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 585223d846dSEric Joyner if (error) { 58661ae650dSJack F Vogel device_printf(dev, "link restart failed, aq_err=%d\n", 58761ae650dSJack F Vogel pf->hw.aq.asq_last_status); 588223d846dSEric Joyner goto err_late; 589223d846dSEric Joyner } 59061ae650dSJack F Vogel } 59161ae650dSJack F Vogel 59261ae650dSJack F Vogel /* Determine link state */ 593223d846dSEric Joyner hw->phy.get_link_info = TRUE; 594be771cdaSJack F Vogel i40e_get_link_status(hw, &pf->link_up); 59561ae650dSJack F Vogel 596223d846dSEric Joyner /* Setup OS network interface / ifnet */ 597e5100ee2SJack F Vogel if (ixl_setup_interface(dev, vsi) != 0) { 598e5100ee2SJack F Vogel device_printf(dev, "interface setup failed!\n"); 599e5100ee2SJack F Vogel error = EIO; 60061ae650dSJack F Vogel goto err_late; 601e5100ee2SJack F Vogel } 60261ae650dSJack F Vogel 603b6c8f260SJack F Vogel error = ixl_switch_config(pf); 604b6c8f260SJack F Vogel if (error) { 6056c426059SEric Joyner device_printf(dev, "Initial ixl_switch_config() failed: %d\n", 6066c426059SEric Joyner error); 607a48d00d2SEric Joyner goto err_late; 608b6c8f260SJack F Vogel } 609b6c8f260SJack F Vogel 610223d846dSEric Joyner /* Limit PHY interrupts to link, autoneg, and modules failure */ 6117f70bec6SEric Joyner error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, 612223d846dSEric Joyner NULL); 613223d846dSEric Joyner if (error) { 614223d846dSEric Joyner device_printf(dev, "i40e_aq_set_phy_mask() failed: err %d," 615223d846dSEric Joyner " aq_err %d\n", error, hw->aq.asq_last_status); 616223d846dSEric Joyner goto err_late; 617223d846dSEric Joyner } 618b6c8f260SJack F Vogel 6196c426059SEric Joyner /* Get the bus configuration and set the shared code's config */ 62061ae650dSJack F Vogel bus = ixl_get_bus_info(hw, dev); 62161ae650dSJack F Vogel i40e_set_pci_config_data(hw, bus); 62261ae650dSJack F Vogel 6236c426059SEric Joyner /* 6246c426059SEric Joyner * In MSI-X mode, initialize the Admin Queue interrupt, 6256c426059SEric Joyner * so userland tools can communicate with the adapter regardless of 6266c426059SEric Joyner * the ifnet interface's status. 6276c426059SEric Joyner */ 6286c426059SEric Joyner if (pf->msix > 1) { 6296c426059SEric Joyner error = ixl_setup_adminq_msix(pf); 6306c426059SEric Joyner if (error) { 6316c426059SEric Joyner device_printf(dev, "ixl_setup_adminq_msix error: %d\n", 6326c426059SEric Joyner error); 6336c426059SEric Joyner goto err_late; 6346c426059SEric Joyner } 6356c426059SEric Joyner error = ixl_setup_adminq_tq(pf); 6366c426059SEric Joyner if (error) { 6376c426059SEric Joyner device_printf(dev, "ixl_setup_adminq_tq error: %d\n", 6386c426059SEric Joyner error); 6396c426059SEric Joyner goto err_late; 6406c426059SEric Joyner } 6416c426059SEric Joyner ixl_configure_intr0_msix(pf); 6426c426059SEric Joyner ixl_enable_adminq(hw); 6436c426059SEric Joyner } 644a48d00d2SEric Joyner 645fdb6f38aSEric Joyner /* Initialize statistics & add sysctls */ 646fdb6f38aSEric Joyner ixl_add_device_sysctls(pf); 647fdb6f38aSEric Joyner 64861ae650dSJack F Vogel ixl_pf_reset_stats(pf); 64961ae650dSJack F Vogel ixl_update_stats_counters(pf); 65061ae650dSJack F Vogel ixl_add_hw_stats(pf); 65161ae650dSJack F Vogel 65261ae650dSJack F Vogel /* Register for VLAN events */ 65361ae650dSJack F Vogel vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 65461ae650dSJack F Vogel ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); 65561ae650dSJack F Vogel vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 65661ae650dSJack F Vogel ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); 65761ae650dSJack F Vogel 65856c2c47bSJack F Vogel #ifdef PCI_IOV 65956c2c47bSJack F Vogel /* SR-IOV is only supported when MSI-X is in use. */ 66056c2c47bSJack F Vogel if (pf->msix > 1) { 66156c2c47bSJack F Vogel pf_schema = pci_iov_schema_alloc_node(); 66256c2c47bSJack F Vogel vf_schema = pci_iov_schema_alloc_node(); 66356c2c47bSJack F Vogel pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); 66456c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", 66556c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, TRUE); 66656c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-set-mac", 66756c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 66856c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-promisc", 66956c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 670e5100ee2SJack F Vogel 67156c2c47bSJack F Vogel iov_error = pci_iov_attach(dev, pf_schema, vf_schema); 6721d767a8eSEric Joyner if (iov_error != 0) { 67356c2c47bSJack F Vogel device_printf(dev, 67456c2c47bSJack F Vogel "Failed to initialize SR-IOV (error=%d)\n", 67556c2c47bSJack F Vogel iov_error); 6761d767a8eSEric Joyner } else 6771d767a8eSEric Joyner device_printf(dev, "SR-IOV ready\n"); 67856c2c47bSJack F Vogel } 67956c2c47bSJack F Vogel #endif 68056c2c47bSJack F Vogel 68131830672SJack F Vogel #ifdef DEV_NETMAP 68231830672SJack F Vogel ixl_netmap_attach(vsi); 68331830672SJack F Vogel #endif /* DEV_NETMAP */ 68461ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: end"); 68561ae650dSJack F Vogel return (0); 68661ae650dSJack F Vogel 68761ae650dSJack F Vogel err_late: 688e5100ee2SJack F Vogel if (vsi->ifp != NULL) 689e5100ee2SJack F Vogel if_free(vsi->ifp); 69061ae650dSJack F Vogel err_mac_hmc: 69161ae650dSJack F Vogel i40e_shutdown_lan_hmc(hw); 69261ae650dSJack F Vogel err_get_cap: 69361ae650dSJack F Vogel i40e_shutdown_adminq(hw); 69461ae650dSJack F Vogel err_out: 69561ae650dSJack F Vogel ixl_free_pci_resources(pf); 696e5100ee2SJack F Vogel ixl_free_vsi(vsi); 69761ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 69861ae650dSJack F Vogel return (error); 69961ae650dSJack F Vogel } 70061ae650dSJack F Vogel 70161ae650dSJack F Vogel /********************************************************************* 70261ae650dSJack F Vogel * Device removal routine 70361ae650dSJack F Vogel * 70461ae650dSJack F Vogel * The detach entry point is called when the driver is being removed. 70561ae650dSJack F Vogel * This routine stops the adapter and deallocates all the resources 70661ae650dSJack F Vogel * that were allocated for driver operation. 70761ae650dSJack F Vogel * 70861ae650dSJack F Vogel * return 0 on success, positive on failure 70961ae650dSJack F Vogel *********************************************************************/ 71061ae650dSJack F Vogel 71161ae650dSJack F Vogel static int 71261ae650dSJack F Vogel ixl_detach(device_t dev) 71361ae650dSJack F Vogel { 71461ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 71561ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 71661ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 7176c426059SEric Joyner enum i40e_status_code status; 71856c2c47bSJack F Vogel #ifdef PCI_IOV 71956c2c47bSJack F Vogel int error; 72056c2c47bSJack F Vogel #endif 72161ae650dSJack F Vogel 72261ae650dSJack F Vogel INIT_DEBUGOUT("ixl_detach: begin"); 72361ae650dSJack F Vogel 72461ae650dSJack F Vogel /* Make sure VLANS are not using driver */ 72561ae650dSJack F Vogel if (vsi->ifp->if_vlantrunk != NULL) { 72661ae650dSJack F Vogel device_printf(dev, "Vlan in use, detach first\n"); 72761ae650dSJack F Vogel return (EBUSY); 72861ae650dSJack F Vogel } 72961ae650dSJack F Vogel 73056c2c47bSJack F Vogel #ifdef PCI_IOV 73156c2c47bSJack F Vogel error = pci_iov_detach(dev); 73256c2c47bSJack F Vogel if (error != 0) { 73356c2c47bSJack F Vogel device_printf(dev, "SR-IOV in use; detach first.\n"); 73456c2c47bSJack F Vogel return (error); 73556c2c47bSJack F Vogel } 73656c2c47bSJack F Vogel #endif 73756c2c47bSJack F Vogel 738b6c8f260SJack F Vogel ether_ifdetach(vsi->ifp); 739223d846dSEric Joyner if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) 74061ae650dSJack F Vogel ixl_stop(pf); 74161ae650dSJack F Vogel 7426c426059SEric Joyner ixl_free_queue_tqs(vsi); 74361ae650dSJack F Vogel 74461ae650dSJack F Vogel /* Shutdown LAN HMC */ 74561ae650dSJack F Vogel status = i40e_shutdown_lan_hmc(hw); 74661ae650dSJack F Vogel if (status) 74761ae650dSJack F Vogel device_printf(dev, 74861ae650dSJack F Vogel "Shutdown LAN HMC failed with code %d\n", status); 74961ae650dSJack F Vogel 75061ae650dSJack F Vogel /* Shutdown admin queue */ 7516c426059SEric Joyner ixl_disable_adminq(hw); 7526c426059SEric Joyner ixl_free_adminq_tq(pf); 7536c426059SEric Joyner ixl_teardown_adminq_msix(pf); 75461ae650dSJack F Vogel status = i40e_shutdown_adminq(hw); 75561ae650dSJack F Vogel if (status) 75661ae650dSJack F Vogel device_printf(dev, 75761ae650dSJack F Vogel "Shutdown Admin queue failed with code %d\n", status); 75861ae650dSJack F Vogel 75961ae650dSJack F Vogel /* Unregister VLAN events */ 76061ae650dSJack F Vogel if (vsi->vlan_attach != NULL) 76161ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); 76261ae650dSJack F Vogel if (vsi->vlan_detach != NULL) 76361ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); 76461ae650dSJack F Vogel 76561ae650dSJack F Vogel callout_drain(&pf->timer); 76631830672SJack F Vogel #ifdef DEV_NETMAP 76731830672SJack F Vogel netmap_detach(vsi->ifp); 76831830672SJack F Vogel #endif /* DEV_NETMAP */ 76961ae650dSJack F Vogel ixl_free_pci_resources(pf); 77061ae650dSJack F Vogel bus_generic_detach(dev); 77161ae650dSJack F Vogel if_free(vsi->ifp); 77261ae650dSJack F Vogel ixl_free_vsi(vsi); 77361ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 77461ae650dSJack F Vogel return (0); 77561ae650dSJack F Vogel } 77661ae650dSJack F Vogel 77761ae650dSJack F Vogel /********************************************************************* 77861ae650dSJack F Vogel * 77961ae650dSJack F Vogel * Shutdown entry point 78061ae650dSJack F Vogel * 78161ae650dSJack F Vogel **********************************************************************/ 78261ae650dSJack F Vogel 78361ae650dSJack F Vogel static int 78461ae650dSJack F Vogel ixl_shutdown(device_t dev) 78561ae650dSJack F Vogel { 78661ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 78761ae650dSJack F Vogel ixl_stop(pf); 78861ae650dSJack F Vogel return (0); 78961ae650dSJack F Vogel } 79061ae650dSJack F Vogel 79161ae650dSJack F Vogel 79261ae650dSJack F Vogel /********************************************************************* 79361ae650dSJack F Vogel * 79461ae650dSJack F Vogel * Get the hardware capabilities 79561ae650dSJack F Vogel * 79661ae650dSJack F Vogel **********************************************************************/ 79761ae650dSJack F Vogel 79861ae650dSJack F Vogel static int 79961ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf) 80061ae650dSJack F Vogel { 80161ae650dSJack F Vogel struct i40e_aqc_list_capabilities_element_resp *buf; 80261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 80361ae650dSJack F Vogel device_t dev = pf->dev; 80461ae650dSJack F Vogel int error, len; 80561ae650dSJack F Vogel u16 needed; 80661ae650dSJack F Vogel bool again = TRUE; 80761ae650dSJack F Vogel 80861ae650dSJack F Vogel len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); 80961ae650dSJack F Vogel retry: 81061ae650dSJack F Vogel if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *) 81161ae650dSJack F Vogel malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) { 81261ae650dSJack F Vogel device_printf(dev, "Unable to allocate cap memory\n"); 81361ae650dSJack F Vogel return (ENOMEM); 81461ae650dSJack F Vogel } 81561ae650dSJack F Vogel 81661ae650dSJack F Vogel /* This populates the hw struct */ 81761ae650dSJack F Vogel error = i40e_aq_discover_capabilities(hw, buf, len, 81861ae650dSJack F Vogel &needed, i40e_aqc_opc_list_func_capabilities, NULL); 81961ae650dSJack F Vogel free(buf, M_DEVBUF); 82061ae650dSJack F Vogel if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && 82161ae650dSJack F Vogel (again == TRUE)) { 82261ae650dSJack F Vogel /* retry once with a larger buffer */ 82361ae650dSJack F Vogel again = FALSE; 82461ae650dSJack F Vogel len = needed; 82561ae650dSJack F Vogel goto retry; 82661ae650dSJack F Vogel } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { 82761ae650dSJack F Vogel device_printf(dev, "capability discovery failed: %d\n", 82861ae650dSJack F Vogel pf->hw.aq.asq_last_status); 82961ae650dSJack F Vogel return (ENODEV); 83061ae650dSJack F Vogel } 83161ae650dSJack F Vogel 83261ae650dSJack F Vogel /* Capture this PF's starting queue pair */ 83361ae650dSJack F Vogel pf->qbase = hw->func_caps.base_queue; 83461ae650dSJack F Vogel 83561ae650dSJack F Vogel #ifdef IXL_DEBUG 83661ae650dSJack F Vogel device_printf(dev, "pf_id=%d, num_vfs=%d, msix_pf=%d, " 83761ae650dSJack F Vogel "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", 83861ae650dSJack F Vogel hw->pf_id, hw->func_caps.num_vfs, 83961ae650dSJack F Vogel hw->func_caps.num_msix_vectors, 84061ae650dSJack F Vogel hw->func_caps.num_msix_vectors_vf, 84161ae650dSJack F Vogel hw->func_caps.fd_filters_guaranteed, 84261ae650dSJack F Vogel hw->func_caps.fd_filters_best_effort, 84361ae650dSJack F Vogel hw->func_caps.num_tx_qp, 84461ae650dSJack F Vogel hw->func_caps.num_rx_qp, 84561ae650dSJack F Vogel hw->func_caps.base_queue); 84661ae650dSJack F Vogel #endif 84761ae650dSJack F Vogel return (error); 84861ae650dSJack F Vogel } 84961ae650dSJack F Vogel 85061ae650dSJack F Vogel static void 85161ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) 85261ae650dSJack F Vogel { 85361ae650dSJack F Vogel device_t dev = vsi->dev; 85461ae650dSJack F Vogel 85561ae650dSJack F Vogel /* Enable/disable TXCSUM/TSO4 */ 85661ae650dSJack F Vogel if (!(ifp->if_capenable & IFCAP_TXCSUM) 85761ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO4)) { 85861ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) { 85961ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TXCSUM; 86061ae650dSJack F Vogel /* enable TXCSUM, restore TSO if previously enabled */ 86161ae650dSJack F Vogel if (vsi->flags & IXL_FLAGS_KEEP_TSO4) { 86261ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 86361ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO4; 86461ae650dSJack F Vogel } 86561ae650dSJack F Vogel } 86661ae650dSJack F Vogel else if (mask & IFCAP_TSO4) { 86761ae650dSJack F Vogel ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); 86861ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 86961ae650dSJack F Vogel device_printf(dev, 87061ae650dSJack F Vogel "TSO4 requires txcsum, enabling both...\n"); 87161ae650dSJack F Vogel } 87261ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM) 87361ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO4)) { 87461ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) 87561ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TXCSUM; 87661ae650dSJack F Vogel else if (mask & IFCAP_TSO4) 87761ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO4; 87861ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM) 87961ae650dSJack F Vogel && (ifp->if_capenable & IFCAP_TSO4)) { 88061ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) { 88161ae650dSJack F Vogel vsi->flags |= IXL_FLAGS_KEEP_TSO4; 88261ae650dSJack F Vogel ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); 88361ae650dSJack F Vogel device_printf(dev, 88461ae650dSJack F Vogel "TSO4 requires txcsum, disabling both...\n"); 88561ae650dSJack F Vogel } else if (mask & IFCAP_TSO4) 88661ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TSO4; 88761ae650dSJack F Vogel } 88861ae650dSJack F Vogel 88961ae650dSJack F Vogel /* Enable/disable TXCSUM_IPV6/TSO6 */ 89061ae650dSJack F Vogel if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) 89161ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO6)) { 89261ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) { 89361ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TXCSUM_IPV6; 89461ae650dSJack F Vogel if (vsi->flags & IXL_FLAGS_KEEP_TSO6) { 89561ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 89661ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO6; 89761ae650dSJack F Vogel } 89861ae650dSJack F Vogel } else if (mask & IFCAP_TSO6) { 89961ae650dSJack F Vogel ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 90061ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 90161ae650dSJack F Vogel device_printf(dev, 90261ae650dSJack F Vogel "TSO6 requires txcsum6, enabling both...\n"); 90361ae650dSJack F Vogel } 90461ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 90561ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO6)) { 90661ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) 90761ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; 90861ae650dSJack F Vogel else if (mask & IFCAP_TSO6) 90961ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO6; 91061ae650dSJack F Vogel } else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 91161ae650dSJack F Vogel && (ifp->if_capenable & IFCAP_TSO6)) { 91261ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) { 91361ae650dSJack F Vogel vsi->flags |= IXL_FLAGS_KEEP_TSO6; 91461ae650dSJack F Vogel ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 91561ae650dSJack F Vogel device_printf(dev, 91661ae650dSJack F Vogel "TSO6 requires txcsum6, disabling both...\n"); 91761ae650dSJack F Vogel } else if (mask & IFCAP_TSO6) 91861ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TSO6; 91961ae650dSJack F Vogel } 92061ae650dSJack F Vogel } 92161ae650dSJack F Vogel 92261ae650dSJack F Vogel /********************************************************************* 92361ae650dSJack F Vogel * Ioctl entry point 92461ae650dSJack F Vogel * 92561ae650dSJack F Vogel * ixl_ioctl is called when the user wants to configure the 92661ae650dSJack F Vogel * interface. 92761ae650dSJack F Vogel * 92861ae650dSJack F Vogel * return 0 on success, positive on failure 92961ae650dSJack F Vogel **********************************************************************/ 93061ae650dSJack F Vogel 93161ae650dSJack F Vogel static int 93261ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 93361ae650dSJack F Vogel { 93461ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 93556c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 93661ae650dSJack F Vogel struct ifreq *ifr = (struct ifreq *)data; 937223d846dSEric Joyner struct ifdrv *ifd = (struct ifdrv *)data; 93861ae650dSJack F Vogel #if defined(INET) || defined(INET6) 93961ae650dSJack F Vogel struct ifaddr *ifa = (struct ifaddr *)data; 94061ae650dSJack F Vogel bool avoid_reset = FALSE; 94161ae650dSJack F Vogel #endif 94261ae650dSJack F Vogel int error = 0; 94361ae650dSJack F Vogel 94461ae650dSJack F Vogel switch (command) { 94561ae650dSJack F Vogel 94661ae650dSJack F Vogel case SIOCSIFADDR: 94761ae650dSJack F Vogel #ifdef INET 94861ae650dSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET) 94961ae650dSJack F Vogel avoid_reset = TRUE; 95061ae650dSJack F Vogel #endif 95161ae650dSJack F Vogel #ifdef INET6 95261ae650dSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET6) 95361ae650dSJack F Vogel avoid_reset = TRUE; 95461ae650dSJack F Vogel #endif 95561ae650dSJack F Vogel #if defined(INET) || defined(INET6) 95661ae650dSJack F Vogel /* 95761ae650dSJack F Vogel ** Calling init results in link renegotiation, 95861ae650dSJack F Vogel ** so we avoid doing it when possible. 95961ae650dSJack F Vogel */ 96061ae650dSJack F Vogel if (avoid_reset) { 96161ae650dSJack F Vogel ifp->if_flags |= IFF_UP; 96261ae650dSJack F Vogel if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 96361ae650dSJack F Vogel ixl_init(pf); 9647e0dde7dSBjoern A. Zeeb #ifdef INET 96561ae650dSJack F Vogel if (!(ifp->if_flags & IFF_NOARP)) 96661ae650dSJack F Vogel arp_ifinit(ifp, ifa); 9677e0dde7dSBjoern A. Zeeb #endif 96861ae650dSJack F Vogel } else 96961ae650dSJack F Vogel error = ether_ioctl(ifp, command, data); 97061ae650dSJack F Vogel break; 97161ae650dSJack F Vogel #endif 97261ae650dSJack F Vogel case SIOCSIFMTU: 97361ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 97461ae650dSJack F Vogel if (ifr->ifr_mtu > IXL_MAX_FRAME - 97561ae650dSJack F Vogel ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) { 97661ae650dSJack F Vogel error = EINVAL; 97761ae650dSJack F Vogel } else { 97861ae650dSJack F Vogel IXL_PF_LOCK(pf); 97961ae650dSJack F Vogel ifp->if_mtu = ifr->ifr_mtu; 98061ae650dSJack F Vogel vsi->max_frame_size = 98161ae650dSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 98261ae650dSJack F Vogel + ETHER_VLAN_ENCAP_LEN; 98361ae650dSJack F Vogel ixl_init_locked(pf); 98461ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 98561ae650dSJack F Vogel } 98661ae650dSJack F Vogel break; 98761ae650dSJack F Vogel case SIOCSIFFLAGS: 98861ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 98961ae650dSJack F Vogel IXL_PF_LOCK(pf); 99061ae650dSJack F Vogel if (ifp->if_flags & IFF_UP) { 99161ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 99261ae650dSJack F Vogel if ((ifp->if_flags ^ pf->if_flags) & 99361ae650dSJack F Vogel (IFF_PROMISC | IFF_ALLMULTI)) { 99461ae650dSJack F Vogel ixl_set_promisc(vsi); 99561ae650dSJack F Vogel } 996223d846dSEric Joyner } else { 997223d846dSEric Joyner IXL_PF_UNLOCK(pf); 998223d846dSEric Joyner ixl_init(pf); 999223d846dSEric Joyner IXL_PF_LOCK(pf); 1000223d846dSEric Joyner } 1001223d846dSEric Joyner } else { 1002223d846dSEric Joyner if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1003223d846dSEric Joyner IXL_PF_UNLOCK(pf); 100461ae650dSJack F Vogel ixl_stop(pf); 1005223d846dSEric Joyner IXL_PF_LOCK(pf); 1006223d846dSEric Joyner } 1007223d846dSEric Joyner } 100861ae650dSJack F Vogel pf->if_flags = ifp->if_flags; 100961ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 101061ae650dSJack F Vogel break; 1011223d846dSEric Joyner case SIOCSDRVSPEC: 1012223d846dSEric Joyner case SIOCGDRVSPEC: 1013223d846dSEric Joyner IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific " 1014223d846dSEric Joyner "Info)\n"); 1015223d846dSEric Joyner 1016223d846dSEric Joyner /* NVM update command */ 1017223d846dSEric Joyner if (ifd->ifd_cmd == I40E_NVM_ACCESS) 1018223d846dSEric Joyner error = ixl_handle_nvmupd_cmd(pf, ifd); 1019223d846dSEric Joyner else 1020223d846dSEric Joyner error = EINVAL; 1021223d846dSEric Joyner break; 102261ae650dSJack F Vogel case SIOCADDMULTI: 102361ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); 102461ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 102561ae650dSJack F Vogel IXL_PF_LOCK(pf); 102661ae650dSJack F Vogel ixl_disable_intr(vsi); 102761ae650dSJack F Vogel ixl_add_multi(vsi); 102861ae650dSJack F Vogel ixl_enable_intr(vsi); 102961ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 103061ae650dSJack F Vogel } 103161ae650dSJack F Vogel break; 103261ae650dSJack F Vogel case SIOCDELMULTI: 103361ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); 103461ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 103561ae650dSJack F Vogel IXL_PF_LOCK(pf); 103661ae650dSJack F Vogel ixl_disable_intr(vsi); 103761ae650dSJack F Vogel ixl_del_multi(vsi); 103861ae650dSJack F Vogel ixl_enable_intr(vsi); 103961ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 104061ae650dSJack F Vogel } 104161ae650dSJack F Vogel break; 104261ae650dSJack F Vogel case SIOCSIFMEDIA: 104361ae650dSJack F Vogel case SIOCGIFMEDIA: 1044be771cdaSJack F Vogel #ifdef IFM_ETH_XTYPE 1045be771cdaSJack F Vogel case SIOCGIFXMEDIA: 1046be771cdaSJack F Vogel #endif 104761ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 104861ae650dSJack F Vogel error = ifmedia_ioctl(ifp, ifr, &vsi->media, command); 104961ae650dSJack F Vogel break; 105061ae650dSJack F Vogel case SIOCSIFCAP: 105161ae650dSJack F Vogel { 105261ae650dSJack F Vogel int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 105361ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 105461ae650dSJack F Vogel 105561ae650dSJack F Vogel ixl_cap_txcsum_tso(vsi, ifp, mask); 105661ae650dSJack F Vogel 105761ae650dSJack F Vogel if (mask & IFCAP_RXCSUM) 105861ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_RXCSUM; 105961ae650dSJack F Vogel if (mask & IFCAP_RXCSUM_IPV6) 106061ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 106161ae650dSJack F Vogel if (mask & IFCAP_LRO) 106261ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_LRO; 106361ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWTAGGING) 106461ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 106561ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWFILTER) 106661ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 106761ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWTSO) 106861ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 106961ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 107061ae650dSJack F Vogel IXL_PF_LOCK(pf); 107161ae650dSJack F Vogel ixl_init_locked(pf); 107261ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 107361ae650dSJack F Vogel } 107461ae650dSJack F Vogel VLAN_CAPABILITIES(ifp); 107561ae650dSJack F Vogel 107661ae650dSJack F Vogel break; 107761ae650dSJack F Vogel } 107861ae650dSJack F Vogel 107961ae650dSJack F Vogel default: 108061ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command); 108161ae650dSJack F Vogel error = ether_ioctl(ifp, command, data); 108261ae650dSJack F Vogel break; 108361ae650dSJack F Vogel } 108461ae650dSJack F Vogel 108561ae650dSJack F Vogel return (error); 108661ae650dSJack F Vogel } 108761ae650dSJack F Vogel 108861ae650dSJack F Vogel 108961ae650dSJack F Vogel /********************************************************************* 109061ae650dSJack F Vogel * Init entry point 109161ae650dSJack F Vogel * 109261ae650dSJack F Vogel * This routine is used in two ways. It is used by the stack as 109361ae650dSJack F Vogel * init entry point in network interface structure. It is also used 109461ae650dSJack F Vogel * by the driver as a hw/sw initialization routine to get to a 109561ae650dSJack F Vogel * consistent state. 109661ae650dSJack F Vogel * 109761ae650dSJack F Vogel * return 0 on success, positive on failure 109861ae650dSJack F Vogel **********************************************************************/ 109961ae650dSJack F Vogel 110061ae650dSJack F Vogel static void 110161ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf) 110261ae650dSJack F Vogel { 110361ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 110461ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 110561ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 110661ae650dSJack F Vogel device_t dev = pf->dev; 110761ae650dSJack F Vogel struct i40e_filter_control_settings filter; 110861ae650dSJack F Vogel u8 tmpaddr[ETHER_ADDR_LEN]; 110961ae650dSJack F Vogel int ret; 111061ae650dSJack F Vogel 111161ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 11126d011ad5SEric Joyner INIT_DEBUGOUT("ixl_init_locked: begin"); 1113223d846dSEric Joyner 1114223d846dSEric Joyner ixl_stop_locked(pf); 111561ae650dSJack F Vogel 111661ae650dSJack F Vogel /* Get the latest mac address... User might use a LAA */ 111761ae650dSJack F Vogel bcopy(IF_LLADDR(vsi->ifp), tmpaddr, 111861ae650dSJack F Vogel I40E_ETH_LENGTH_OF_ADDRESS); 111961ae650dSJack F Vogel if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && 1120a48d00d2SEric Joyner (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { 1121a48d00d2SEric Joyner ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); 112261ae650dSJack F Vogel bcopy(tmpaddr, hw->mac.addr, 112361ae650dSJack F Vogel I40E_ETH_LENGTH_OF_ADDRESS); 112461ae650dSJack F Vogel ret = i40e_aq_mac_address_write(hw, 112561ae650dSJack F Vogel I40E_AQC_WRITE_TYPE_LAA_ONLY, 112661ae650dSJack F Vogel hw->mac.addr, NULL); 112761ae650dSJack F Vogel if (ret) { 112861ae650dSJack F Vogel device_printf(dev, "LLA address" 112961ae650dSJack F Vogel "change failed!!\n"); 113061ae650dSJack F Vogel return; 113195bb0504SEric Joyner } 113295bb0504SEric Joyner } 113395bb0504SEric Joyner 1134a48d00d2SEric Joyner ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); 113561ae650dSJack F Vogel 113661ae650dSJack F Vogel /* Set the various hardware offload abilities */ 113761ae650dSJack F Vogel ifp->if_hwassist = 0; 113861ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TSO) 113961ae650dSJack F Vogel ifp->if_hwassist |= CSUM_TSO; 114061ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM) 114161ae650dSJack F Vogel ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 114261ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 114361ae650dSJack F Vogel ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); 114461ae650dSJack F Vogel 114561ae650dSJack F Vogel /* Set up the device filtering */ 114661ae650dSJack F Vogel bzero(&filter, sizeof(filter)); 114761ae650dSJack F Vogel filter.enable_ethtype = TRUE; 114861ae650dSJack F Vogel filter.enable_macvlan = TRUE; 114961ae650dSJack F Vogel #ifdef IXL_FDIR 115061ae650dSJack F Vogel filter.enable_fdir = TRUE; 115161ae650dSJack F Vogel #endif 11527f70bec6SEric Joyner filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; 115361ae650dSJack F Vogel if (i40e_set_filter_control(hw, &filter)) 11547f70bec6SEric Joyner device_printf(dev, "i40e_set_filter_control() failed\n"); 115561ae650dSJack F Vogel 115661ae650dSJack F Vogel /* Set up RSS */ 115761ae650dSJack F Vogel ixl_config_rss(vsi); 115861ae650dSJack F Vogel 11597f70bec6SEric Joyner /* Prepare the VSI: rings, hmc contexts, etc... */ 116061ae650dSJack F Vogel if (ixl_initialize_vsi(vsi)) { 116161ae650dSJack F Vogel device_printf(dev, "initialize vsi failed!!\n"); 116261ae650dSJack F Vogel return; 116361ae650dSJack F Vogel } 116461ae650dSJack F Vogel 116561ae650dSJack F Vogel /* Add protocol filters to list */ 116661ae650dSJack F Vogel ixl_init_filters(vsi); 116761ae650dSJack F Vogel 116861ae650dSJack F Vogel /* Setup vlan's if needed */ 116961ae650dSJack F Vogel ixl_setup_vlan_filters(vsi); 117061ae650dSJack F Vogel 117161ae650dSJack F Vogel /* Set up MSI/X routing and the ITR settings */ 117261ae650dSJack F Vogel if (ixl_enable_msix) { 11736c426059SEric Joyner ixl_configure_queue_intr_msix(pf); 117461ae650dSJack F Vogel ixl_configure_itr(pf); 117561ae650dSJack F Vogel } else 117661ae650dSJack F Vogel ixl_configure_legacy(pf); 117761ae650dSJack F Vogel 117861ae650dSJack F Vogel ixl_enable_rings(vsi); 117961ae650dSJack F Vogel 118061ae650dSJack F Vogel i40e_aq_set_default_vsi(hw, vsi->seid, NULL); 118161ae650dSJack F Vogel 118256c2c47bSJack F Vogel ixl_reconfigure_filters(vsi); 118356c2c47bSJack F Vogel 118461ae650dSJack F Vogel /* And now turn on interrupts */ 118561ae650dSJack F Vogel ixl_enable_intr(vsi); 118661ae650dSJack F Vogel 1187223d846dSEric Joyner /* Get link info */ 1188223d846dSEric Joyner hw->phy.get_link_info = TRUE; 1189223d846dSEric Joyner i40e_get_link_status(hw, &pf->link_up); 1190223d846dSEric Joyner ixl_update_link_status(pf); 1191223d846dSEric Joyner 11926c426059SEric Joyner /* Set initial advertised speed sysctl value */ 11936c426059SEric Joyner ixl_get_initial_advertised_speeds(pf); 11946c426059SEric Joyner 11957f70bec6SEric Joyner /* Start the local timer */ 11967f70bec6SEric Joyner callout_reset(&pf->timer, hz, ixl_local_timer, pf); 11977f70bec6SEric Joyner 119861ae650dSJack F Vogel /* Now inform the stack we're ready */ 119961ae650dSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 120061ae650dSJack F Vogel 120161ae650dSJack F Vogel return; 120261ae650dSJack F Vogel } 120361ae650dSJack F Vogel 12046c426059SEric Joyner /* For the set_advertise sysctl */ 12056c426059SEric Joyner static void 12066c426059SEric Joyner ixl_get_initial_advertised_speeds(struct ixl_pf *pf) 12076c426059SEric Joyner { 12086c426059SEric Joyner struct i40e_hw *hw = &pf->hw; 12096c426059SEric Joyner device_t dev = pf->dev; 12106c426059SEric Joyner enum i40e_status_code status; 12116c426059SEric Joyner struct i40e_aq_get_phy_abilities_resp abilities; 12126c426059SEric Joyner 12136c426059SEric Joyner /* Set initial sysctl values */ 12146c426059SEric Joyner status = i40e_aq_get_phy_capabilities(hw, FALSE, false, &abilities, 12156c426059SEric Joyner NULL); 12166c426059SEric Joyner if (status) { 12176c426059SEric Joyner /* Non-fatal error */ 12186c426059SEric Joyner device_printf(dev, "%s: i40e_aq_get_phy_capabilities() error %d\n", 12196c426059SEric Joyner __func__, status); 12206c426059SEric Joyner return; 12216c426059SEric Joyner } 12226c426059SEric Joyner 12236c426059SEric Joyner if (abilities.link_speed & I40E_LINK_SPEED_40GB) 12246c426059SEric Joyner pf->advertised_speed |= 0x10; 12256c426059SEric Joyner if (abilities.link_speed & I40E_LINK_SPEED_20GB) 12266c426059SEric Joyner pf->advertised_speed |= 0x8; 12276c426059SEric Joyner if (abilities.link_speed & I40E_LINK_SPEED_10GB) 12286c426059SEric Joyner pf->advertised_speed |= 0x4; 12296c426059SEric Joyner if (abilities.link_speed & I40E_LINK_SPEED_1GB) 12306c426059SEric Joyner pf->advertised_speed |= 0x2; 12316c426059SEric Joyner if (abilities.link_speed & I40E_LINK_SPEED_100MB) 12326c426059SEric Joyner pf->advertised_speed |= 0x1; 12336c426059SEric Joyner } 12346c426059SEric Joyner 12357f70bec6SEric Joyner static int 12367f70bec6SEric Joyner ixl_teardown_hw_structs(struct ixl_pf *pf) 12377f70bec6SEric Joyner { 12387f70bec6SEric Joyner enum i40e_status_code status = 0; 12397f70bec6SEric Joyner struct i40e_hw *hw = &pf->hw; 12407f70bec6SEric Joyner device_t dev = pf->dev; 12417f70bec6SEric Joyner 12427f70bec6SEric Joyner /* Shutdown LAN HMC */ 12437f70bec6SEric Joyner if (hw->hmc.hmc_obj) { 12447f70bec6SEric Joyner status = i40e_shutdown_lan_hmc(hw); 12457f70bec6SEric Joyner if (status) { 12467f70bec6SEric Joyner device_printf(dev, 12477f70bec6SEric Joyner "init: LAN HMC shutdown failure; status %d\n", status); 12487f70bec6SEric Joyner goto err_out; 12497f70bec6SEric Joyner } 12507f70bec6SEric Joyner } 12517f70bec6SEric Joyner 12527f70bec6SEric Joyner // XXX: This gets called when we know the adminq is inactive; 12537f70bec6SEric Joyner // so we already know it's setup when we get here. 12547f70bec6SEric Joyner 12557f70bec6SEric Joyner /* Shutdown admin queue */ 12567f70bec6SEric Joyner status = i40e_shutdown_adminq(hw); 12577f70bec6SEric Joyner if (status) 12587f70bec6SEric Joyner device_printf(dev, 12597f70bec6SEric Joyner "init: Admin Queue shutdown failure; status %d\n", status); 12607f70bec6SEric Joyner 12617f70bec6SEric Joyner err_out: 12627f70bec6SEric Joyner return (status); 12637f70bec6SEric Joyner } 12647f70bec6SEric Joyner 12657f70bec6SEric Joyner static int 12667f70bec6SEric Joyner ixl_reset(struct ixl_pf *pf) 12677f70bec6SEric Joyner { 12687f70bec6SEric Joyner struct i40e_hw *hw = &pf->hw; 12697f70bec6SEric Joyner device_t dev = pf->dev; 12706d011ad5SEric Joyner u8 set_fc_err_mask; 12717f70bec6SEric Joyner int error = 0; 12727f70bec6SEric Joyner 12737f70bec6SEric Joyner // XXX: clear_hw() actually writes to hw registers -- maybe this isn't necessary 12747f70bec6SEric Joyner i40e_clear_hw(hw); 12757f70bec6SEric Joyner error = i40e_pf_reset(hw); 12767f70bec6SEric Joyner if (error) { 12777f70bec6SEric Joyner device_printf(dev, "init: PF reset failure"); 12787f70bec6SEric Joyner error = EIO; 12797f70bec6SEric Joyner goto err_out; 12807f70bec6SEric Joyner } 12817f70bec6SEric Joyner 12827f70bec6SEric Joyner error = i40e_init_adminq(hw); 12837f70bec6SEric Joyner if (error) { 12846d011ad5SEric Joyner device_printf(dev, "init: Admin queue init failure;" 12856d011ad5SEric Joyner " status code %d", error); 12867f70bec6SEric Joyner error = EIO; 12877f70bec6SEric Joyner goto err_out; 12887f70bec6SEric Joyner } 12897f70bec6SEric Joyner 12907f70bec6SEric Joyner i40e_clear_pxe_mode(hw); 12917f70bec6SEric Joyner 12927f70bec6SEric Joyner error = ixl_get_hw_capabilities(pf); 12937f70bec6SEric Joyner if (error) { 12946d011ad5SEric Joyner device_printf(dev, "init: Error retrieving HW capabilities;" 12956d011ad5SEric Joyner " status code %d\n", error); 12967f70bec6SEric Joyner goto err_out; 12977f70bec6SEric Joyner } 12987f70bec6SEric Joyner 12997f70bec6SEric Joyner error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 13007f70bec6SEric Joyner hw->func_caps.num_rx_qp, 0, 0); 13017f70bec6SEric Joyner if (error) { 13026d011ad5SEric Joyner device_printf(dev, "init: LAN HMC init failed; status code %d\n", 13036d011ad5SEric Joyner error); 13047f70bec6SEric Joyner error = EIO; 13057f70bec6SEric Joyner goto err_out; 13067f70bec6SEric Joyner } 13077f70bec6SEric Joyner 13087f70bec6SEric Joyner error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 13097f70bec6SEric Joyner if (error) { 13106d011ad5SEric Joyner device_printf(dev, "init: LAN HMC config failed; status code %d\n", 13116d011ad5SEric Joyner error); 13127f70bec6SEric Joyner error = EIO; 13137f70bec6SEric Joyner goto err_out; 13147f70bec6SEric Joyner } 13157f70bec6SEric Joyner 13166d011ad5SEric Joyner // XXX: possible fix for panic, but our failure recovery is still broken 13176d011ad5SEric Joyner error = ixl_switch_config(pf); 13186d011ad5SEric Joyner if (error) { 13196d011ad5SEric Joyner device_printf(dev, "init: ixl_switch_config() failed: %d\n", 13206d011ad5SEric Joyner error); 13216d011ad5SEric Joyner goto err_out; 13226d011ad5SEric Joyner } 13237f70bec6SEric Joyner 13247f70bec6SEric Joyner error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, 13257f70bec6SEric Joyner NULL); 13267f70bec6SEric Joyner if (error) { 13277f70bec6SEric Joyner device_printf(dev, "init: i40e_aq_set_phy_mask() failed: err %d," 13287f70bec6SEric Joyner " aq_err %d\n", error, hw->aq.asq_last_status); 13297f70bec6SEric Joyner error = EIO; 13307f70bec6SEric Joyner goto err_out; 13317f70bec6SEric Joyner } 13327f70bec6SEric Joyner 13337f70bec6SEric Joyner error = i40e_set_fc(hw, &set_fc_err_mask, true); 13347f70bec6SEric Joyner if (error) { 13357f70bec6SEric Joyner device_printf(dev, "init: setting link flow control failed; retcode %d," 13367f70bec6SEric Joyner " fc_err_mask 0x%02x\n", error, set_fc_err_mask); 13377f70bec6SEric Joyner goto err_out; 13387f70bec6SEric Joyner } 13397f70bec6SEric Joyner 13407f70bec6SEric Joyner // XXX: (Rebuild VSIs?) 13417f70bec6SEric Joyner 13421d767a8eSEric Joyner /* Firmware delay workaround */ 13437f70bec6SEric Joyner if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 13447f70bec6SEric Joyner (hw->aq.fw_maj_ver < 4)) { 13457f70bec6SEric Joyner i40e_msec_delay(75); 13467f70bec6SEric Joyner error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 13477f70bec6SEric Joyner if (error) { 13487f70bec6SEric Joyner device_printf(dev, "init: link restart failed, aq_err %d\n", 13497f70bec6SEric Joyner hw->aq.asq_last_status); 13507f70bec6SEric Joyner goto err_out; 13517f70bec6SEric Joyner } 13527f70bec6SEric Joyner } 13537f70bec6SEric Joyner 13547f70bec6SEric Joyner 13557f70bec6SEric Joyner err_out: 13567f70bec6SEric Joyner return (error); 13577f70bec6SEric Joyner } 13587f70bec6SEric Joyner 135961ae650dSJack F Vogel static void 136061ae650dSJack F Vogel ixl_init(void *arg) 136161ae650dSJack F Vogel { 136261ae650dSJack F Vogel struct ixl_pf *pf = arg; 13636d011ad5SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 13646c426059SEric Joyner device_t dev = pf->dev; 13656c426059SEric Joyner int error = 0; 1366223d846dSEric Joyner 13677f70bec6SEric Joyner /* 13687f70bec6SEric Joyner * If the aq is dead here, it probably means something outside of the driver 13697f70bec6SEric Joyner * did something to the adapter, like a PF reset. 13707f70bec6SEric Joyner * So rebuild the driver's state here if that occurs. 13717f70bec6SEric Joyner */ 13727f70bec6SEric Joyner if (!i40e_check_asq_alive(&pf->hw)) { 13736c426059SEric Joyner device_printf(dev, "Admin Queue is down; resetting...\n"); 13747f70bec6SEric Joyner IXL_PF_LOCK(pf); 13757f70bec6SEric Joyner ixl_teardown_hw_structs(pf); 13767f70bec6SEric Joyner ixl_reset(pf); 13777f70bec6SEric Joyner IXL_PF_UNLOCK(pf); 13787f70bec6SEric Joyner } 13797f70bec6SEric Joyner 13806c426059SEric Joyner /* 13816c426059SEric Joyner * Set up LAN queue interrupts here. 13826c426059SEric Joyner * Kernel interrupt setup functions cannot be called while holding a lock, 13836c426059SEric Joyner * so this is done outside of init_locked(). 13846c426059SEric Joyner */ 13856c426059SEric Joyner if (pf->msix > 1) { 13866d011ad5SEric Joyner /* Teardown existing interrupts, if they exist */ 13876d011ad5SEric Joyner ixl_teardown_queue_msix(vsi); 13886d011ad5SEric Joyner ixl_free_queue_tqs(vsi); 13896d011ad5SEric Joyner /* Then set them up again */ 13906d011ad5SEric Joyner error = ixl_setup_queue_msix(vsi); 13916c426059SEric Joyner if (error) 13926c426059SEric Joyner device_printf(dev, "ixl_setup_queue_msix() error: %d\n", 13936c426059SEric Joyner error); 13946d011ad5SEric Joyner error = ixl_setup_queue_tqs(vsi); 13956c426059SEric Joyner if (error) 13966c426059SEric Joyner device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", 13976c426059SEric Joyner error); 13986c426059SEric Joyner } else 13996c426059SEric Joyner // possibly broken 14006c426059SEric Joyner error = ixl_assign_vsi_legacy(pf); 14016c426059SEric Joyner if (error) { 14026c426059SEric Joyner device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", error); 1403223d846dSEric Joyner return; 1404223d846dSEric Joyner } 140561ae650dSJack F Vogel 140661ae650dSJack F Vogel IXL_PF_LOCK(pf); 140761ae650dSJack F Vogel ixl_init_locked(pf); 140861ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 140961ae650dSJack F Vogel } 141061ae650dSJack F Vogel 141161ae650dSJack F Vogel /* 141261ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets 141361ae650dSJack F Vogel */ 141461ae650dSJack F Vogel static void 141561ae650dSJack F Vogel ixl_handle_que(void *context, int pending) 141661ae650dSJack F Vogel { 141761ae650dSJack F Vogel struct ixl_queue *que = context; 141861ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 141961ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 142061ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 142161ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 142261ae650dSJack F Vogel bool more; 142361ae650dSJack F Vogel 142461ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 142561ae650dSJack F Vogel more = ixl_rxeof(que, IXL_RX_LIMIT); 142661ae650dSJack F Vogel IXL_TX_LOCK(txr); 142761ae650dSJack F Vogel ixl_txeof(que); 142861ae650dSJack F Vogel if (!drbr_empty(ifp, txr->br)) 142961ae650dSJack F Vogel ixl_mq_start_locked(ifp, txr); 143061ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 143161ae650dSJack F Vogel if (more) { 143261ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->task); 143361ae650dSJack F Vogel return; 143461ae650dSJack F Vogel } 143561ae650dSJack F Vogel } 143661ae650dSJack F Vogel 143761ae650dSJack F Vogel /* Reenable this interrupt - hmmm */ 143861ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 143961ae650dSJack F Vogel return; 144061ae650dSJack F Vogel } 144161ae650dSJack F Vogel 144261ae650dSJack F Vogel 144361ae650dSJack F Vogel /********************************************************************* 144461ae650dSJack F Vogel * 144561ae650dSJack F Vogel * Legacy Interrupt Service routine 144661ae650dSJack F Vogel * 144761ae650dSJack F Vogel **********************************************************************/ 144861ae650dSJack F Vogel void 144961ae650dSJack F Vogel ixl_intr(void *arg) 145061ae650dSJack F Vogel { 145161ae650dSJack F Vogel struct ixl_pf *pf = arg; 145261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 145361ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 145461ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 145561ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 145661ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 145761ae650dSJack F Vogel u32 reg, icr0, mask; 145861ae650dSJack F Vogel bool more_tx, more_rx; 145961ae650dSJack F Vogel 146061ae650dSJack F Vogel ++que->irqs; 146161ae650dSJack F Vogel 146261ae650dSJack F Vogel /* Protect against spurious interrupts */ 146361ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 146461ae650dSJack F Vogel return; 146561ae650dSJack F Vogel 146661ae650dSJack F Vogel icr0 = rd32(hw, I40E_PFINT_ICR0); 146761ae650dSJack F Vogel 146861ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_DYN_CTL0); 146961ae650dSJack F Vogel reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 147061ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 147161ae650dSJack F Vogel 147261ae650dSJack F Vogel mask = rd32(hw, I40E_PFINT_ICR0_ENA); 147361ae650dSJack F Vogel 147456c2c47bSJack F Vogel #ifdef PCI_IOV 147556c2c47bSJack F Vogel if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) 147656c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->vflr_task); 147756c2c47bSJack F Vogel #endif 147856c2c47bSJack F Vogel 147961ae650dSJack F Vogel if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) { 148061ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 148161ae650dSJack F Vogel return; 148261ae650dSJack F Vogel } 148361ae650dSJack F Vogel 148461ae650dSJack F Vogel more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 148561ae650dSJack F Vogel 148661ae650dSJack F Vogel IXL_TX_LOCK(txr); 148761ae650dSJack F Vogel more_tx = ixl_txeof(que); 148861ae650dSJack F Vogel if (!drbr_empty(vsi->ifp, txr->br)) 148961ae650dSJack F Vogel more_tx = 1; 149061ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 149161ae650dSJack F Vogel 149261ae650dSJack F Vogel /* re-enable other interrupt causes */ 149361ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, mask); 149461ae650dSJack F Vogel 149561ae650dSJack F Vogel /* And now the queues */ 149661ae650dSJack F Vogel reg = rd32(hw, I40E_QINT_RQCTL(0)); 149761ae650dSJack F Vogel reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; 149861ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(0), reg); 149961ae650dSJack F Vogel 150061ae650dSJack F Vogel reg = rd32(hw, I40E_QINT_TQCTL(0)); 150161ae650dSJack F Vogel reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; 150261ae650dSJack F Vogel reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK; 150361ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(0), reg); 150461ae650dSJack F Vogel 150561ae650dSJack F Vogel ixl_enable_legacy(hw); 150661ae650dSJack F Vogel 150761ae650dSJack F Vogel return; 150861ae650dSJack F Vogel } 150961ae650dSJack F Vogel 151061ae650dSJack F Vogel 151161ae650dSJack F Vogel /********************************************************************* 151261ae650dSJack F Vogel * 151361ae650dSJack F Vogel * MSIX VSI Interrupt Service routine 151461ae650dSJack F Vogel * 151561ae650dSJack F Vogel **********************************************************************/ 151661ae650dSJack F Vogel void 151761ae650dSJack F Vogel ixl_msix_que(void *arg) 151861ae650dSJack F Vogel { 151961ae650dSJack F Vogel struct ixl_queue *que = arg; 152061ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 152161ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 152261ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 152361ae650dSJack F Vogel bool more_tx, more_rx; 152461ae650dSJack F Vogel 152561ae650dSJack F Vogel /* Protect against spurious interrupts */ 152661ae650dSJack F Vogel if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) 152761ae650dSJack F Vogel return; 152861ae650dSJack F Vogel 152961ae650dSJack F Vogel ++que->irqs; 153061ae650dSJack F Vogel 153161ae650dSJack F Vogel more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 153261ae650dSJack F Vogel 153361ae650dSJack F Vogel IXL_TX_LOCK(txr); 153461ae650dSJack F Vogel more_tx = ixl_txeof(que); 153561ae650dSJack F Vogel /* 153661ae650dSJack F Vogel ** Make certain that if the stack 153761ae650dSJack F Vogel ** has anything queued the task gets 153861ae650dSJack F Vogel ** scheduled to handle it. 153961ae650dSJack F Vogel */ 154061ae650dSJack F Vogel if (!drbr_empty(vsi->ifp, txr->br)) 154161ae650dSJack F Vogel more_tx = 1; 154261ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 154361ae650dSJack F Vogel 154461ae650dSJack F Vogel ixl_set_queue_rx_itr(que); 154561ae650dSJack F Vogel ixl_set_queue_tx_itr(que); 154661ae650dSJack F Vogel 154761ae650dSJack F Vogel if (more_tx || more_rx) 154861ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->task); 154961ae650dSJack F Vogel else 155061ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 155161ae650dSJack F Vogel 155261ae650dSJack F Vogel return; 155361ae650dSJack F Vogel } 155461ae650dSJack F Vogel 155561ae650dSJack F Vogel 155661ae650dSJack F Vogel /********************************************************************* 155761ae650dSJack F Vogel * 155861ae650dSJack F Vogel * MSIX Admin Queue Interrupt Service routine 155961ae650dSJack F Vogel * 156061ae650dSJack F Vogel **********************************************************************/ 156161ae650dSJack F Vogel static void 156261ae650dSJack F Vogel ixl_msix_adminq(void *arg) 156361ae650dSJack F Vogel { 156461ae650dSJack F Vogel struct ixl_pf *pf = arg; 156561ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 1566fdb6f38aSEric Joyner u32 reg, mask, rstat_reg; 1567fdb6f38aSEric Joyner bool do_task = FALSE; 156861ae650dSJack F Vogel 156961ae650dSJack F Vogel ++pf->admin_irq; 157061ae650dSJack F Vogel 157161ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0); 157261ae650dSJack F Vogel mask = rd32(hw, I40E_PFINT_ICR0_ENA); 157361ae650dSJack F Vogel 157461ae650dSJack F Vogel /* Check on the cause */ 1575fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) { 1576fdb6f38aSEric Joyner mask &= ~I40E_PFINT_ICR0_ADMINQ_MASK; 1577fdb6f38aSEric Joyner do_task = TRUE; 1578fdb6f38aSEric Joyner } 157961ae650dSJack F Vogel 158061ae650dSJack F Vogel if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) { 158161ae650dSJack F Vogel ixl_handle_mdd_event(pf); 1582fdb6f38aSEric Joyner mask &= ~I40E_PFINT_ICR0_MAL_DETECT_MASK; 1583fdb6f38aSEric Joyner } 1584fdb6f38aSEric Joyner 1585fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_GRST_MASK) { 1586fdb6f38aSEric Joyner device_printf(pf->dev, "Reset Requested!\n"); 1587fdb6f38aSEric Joyner rstat_reg = rd32(hw, I40E_GLGEN_RSTAT); 1588fdb6f38aSEric Joyner rstat_reg = (rstat_reg & I40E_GLGEN_RSTAT_RESET_TYPE_MASK) 1589fdb6f38aSEric Joyner >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT; 1590fdb6f38aSEric Joyner device_printf(pf->dev, "Reset type: "); 1591fdb6f38aSEric Joyner switch (rstat_reg) { 1592fdb6f38aSEric Joyner /* These others might be handled similarly to an EMPR reset */ 1593fdb6f38aSEric Joyner case I40E_RESET_CORER: 1594fdb6f38aSEric Joyner printf("CORER\n"); 1595fdb6f38aSEric Joyner break; 1596fdb6f38aSEric Joyner case I40E_RESET_GLOBR: 1597fdb6f38aSEric Joyner printf("GLOBR\n"); 1598fdb6f38aSEric Joyner break; 1599fdb6f38aSEric Joyner case I40E_RESET_EMPR: 1600fdb6f38aSEric Joyner printf("EMPR\n"); 1601fdb6f38aSEric Joyner atomic_set_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); 1602fdb6f38aSEric Joyner break; 1603fdb6f38aSEric Joyner default: 1604fdb6f38aSEric Joyner printf("?\n"); 1605fdb6f38aSEric Joyner break; 1606fdb6f38aSEric Joyner } 1607fdb6f38aSEric Joyner // overload admin queue task to check reset progress? 1608fdb6f38aSEric Joyner do_task = TRUE; 1609fdb6f38aSEric Joyner } 1610fdb6f38aSEric Joyner 1611fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_ECC_ERR_MASK) { 1612fdb6f38aSEric Joyner device_printf(pf->dev, "ECC Error detected!\n"); 1613fdb6f38aSEric Joyner } 1614fdb6f38aSEric Joyner 1615fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_HMC_ERR_MASK) { 1616fdb6f38aSEric Joyner device_printf(pf->dev, "HMC Error detected!\n"); 1617fdb6f38aSEric Joyner } 1618fdb6f38aSEric Joyner 1619fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) { 1620fdb6f38aSEric Joyner device_printf(pf->dev, "PCI Exception detected!\n"); 162161ae650dSJack F Vogel } 162261ae650dSJack F Vogel 162356c2c47bSJack F Vogel #ifdef PCI_IOV 162456c2c47bSJack F Vogel if (reg & I40E_PFINT_ICR0_VFLR_MASK) { 162561ae650dSJack F Vogel mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; 162656c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->vflr_task); 162756c2c47bSJack F Vogel } 162856c2c47bSJack F Vogel #endif 162961ae650dSJack F Vogel 163061ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_DYN_CTL0); 163161ae650dSJack F Vogel reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 163261ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 163361ae650dSJack F Vogel 1634fdb6f38aSEric Joyner if (do_task) 163561ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 163661ae650dSJack F Vogel } 163761ae650dSJack F Vogel 163861ae650dSJack F Vogel /********************************************************************* 163961ae650dSJack F Vogel * 164061ae650dSJack F Vogel * Media Ioctl callback 164161ae650dSJack F Vogel * 164261ae650dSJack F Vogel * This routine is called whenever the user queries the status of 164361ae650dSJack F Vogel * the interface using ifconfig. 164461ae650dSJack F Vogel * 164561ae650dSJack F Vogel **********************************************************************/ 164661ae650dSJack F Vogel static void 164761ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 164861ae650dSJack F Vogel { 164961ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 165056c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 165161ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 165261ae650dSJack F Vogel 165361ae650dSJack F Vogel INIT_DEBUGOUT("ixl_media_status: begin"); 165461ae650dSJack F Vogel IXL_PF_LOCK(pf); 165561ae650dSJack F Vogel 165656c2c47bSJack F Vogel hw->phy.get_link_info = TRUE; 1657be771cdaSJack F Vogel i40e_get_link_status(hw, &pf->link_up); 165861ae650dSJack F Vogel ixl_update_link_status(pf); 165961ae650dSJack F Vogel 166061ae650dSJack F Vogel ifmr->ifm_status = IFM_AVALID; 166161ae650dSJack F Vogel ifmr->ifm_active = IFM_ETHER; 166261ae650dSJack F Vogel 166356c2c47bSJack F Vogel if (!pf->link_up) { 166461ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 166561ae650dSJack F Vogel return; 166661ae650dSJack F Vogel } 166761ae650dSJack F Vogel 166861ae650dSJack F Vogel ifmr->ifm_status |= IFM_ACTIVE; 1669ac83ea83SEric Joyner 1670ac83ea83SEric Joyner /* Hardware always does full-duplex */ 167161ae650dSJack F Vogel ifmr->ifm_active |= IFM_FDX; 167261ae650dSJack F Vogel 167361ae650dSJack F Vogel switch (hw->phy.link_info.phy_type) { 167461ae650dSJack F Vogel /* 100 M */ 167561ae650dSJack F Vogel case I40E_PHY_TYPE_100BASE_TX: 167661ae650dSJack F Vogel ifmr->ifm_active |= IFM_100_TX; 167761ae650dSJack F Vogel break; 167861ae650dSJack F Vogel /* 1 G */ 167961ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_T: 168061ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_T; 168161ae650dSJack F Vogel break; 168261ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_SX: 168361ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_SX; 168461ae650dSJack F Vogel break; 168561ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_LX: 168661ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_LX; 168761ae650dSJack F Vogel break; 16881d767a8eSEric Joyner case I40E_PHY_TYPE_1000BASE_T_OPTICAL: 16891d767a8eSEric Joyner ifmr->ifm_active |= IFM_OTHER; 16901d767a8eSEric Joyner break; 169161ae650dSJack F Vogel /* 10 G */ 169261ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_SFPP_CU: 169361ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX; 169461ae650dSJack F Vogel break; 169561ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_SR: 169661ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_SR; 169761ae650dSJack F Vogel break; 169861ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_LR: 169961ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_LR; 170061ae650dSJack F Vogel break; 170161ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_T: 170261ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_T; 170361ae650dSJack F Vogel break; 17041d767a8eSEric Joyner case I40E_PHY_TYPE_XAUI: 17051d767a8eSEric Joyner case I40E_PHY_TYPE_XFI: 17061d767a8eSEric Joyner case I40E_PHY_TYPE_10GBASE_AOC: 17071d767a8eSEric Joyner ifmr->ifm_active |= IFM_OTHER; 17081d767a8eSEric Joyner break; 170961ae650dSJack F Vogel /* 40 G */ 171061ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_CR4: 171161ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_CR4_CU: 171261ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_CR4; 171361ae650dSJack F Vogel break; 171461ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_SR4: 171561ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_SR4; 171661ae650dSJack F Vogel break; 171761ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_LR4: 171861ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_LR4; 171961ae650dSJack F Vogel break; 17201d767a8eSEric Joyner case I40E_PHY_TYPE_XLAUI: 17211d767a8eSEric Joyner ifmr->ifm_active |= IFM_OTHER; 17221d767a8eSEric Joyner break; 1723be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE 1724be771cdaSJack F Vogel case I40E_PHY_TYPE_1000BASE_KX: 1725be771cdaSJack F Vogel ifmr->ifm_active |= IFM_1000_CX; 1726b6c8f260SJack F Vogel break; 17271d767a8eSEric Joyner case I40E_PHY_TYPE_SGMII: 17281d767a8eSEric Joyner ifmr->ifm_active |= IFM_OTHER; 17291d767a8eSEric Joyner break; 1730be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1_CU: 1731be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1: 1732be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX; 1733be771cdaSJack F Vogel break; 1734be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KX4: 1735be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_CX4; 1736be771cdaSJack F Vogel break; 1737be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KR: 1738be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_SR; 1739be771cdaSJack F Vogel break; 17401d767a8eSEric Joyner case I40E_PHY_TYPE_SFI: 17411d767a8eSEric Joyner ifmr->ifm_active |= IFM_OTHER; 17421d767a8eSEric Joyner break; 1743be771cdaSJack F Vogel case I40E_PHY_TYPE_40GBASE_KR4: 1744be771cdaSJack F Vogel case I40E_PHY_TYPE_XLPPI: 17451d767a8eSEric Joyner case I40E_PHY_TYPE_40GBASE_AOC: 1746be771cdaSJack F Vogel ifmr->ifm_active |= IFM_40G_SR4; 1747be771cdaSJack F Vogel break; 1748be771cdaSJack F Vogel #else 1749be771cdaSJack F Vogel case I40E_PHY_TYPE_1000BASE_KX: 1750be771cdaSJack F Vogel ifmr->ifm_active |= IFM_1000_KX; 1751be771cdaSJack F Vogel break; 17521d767a8eSEric Joyner case I40E_PHY_TYPE_SGMII: 17531d767a8eSEric Joyner ifmr->ifm_active |= IFM_1000_SGMII; 17541d767a8eSEric Joyner break; 1755be771cdaSJack F Vogel /* ERJ: What's the difference between these? */ 1756be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1_CU: 1757be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1: 1758be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_CR1; 1759be771cdaSJack F Vogel break; 1760be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KX4: 1761be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_KX4; 1762be771cdaSJack F Vogel break; 1763be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KR: 1764be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_KR; 1765be771cdaSJack F Vogel break; 17661d767a8eSEric Joyner case I40E_PHY_TYPE_SFI: 17671d767a8eSEric Joyner ifmr->ifm_active |= IFM_10G_SFI; 17681d767a8eSEric Joyner break; 1769ac83ea83SEric Joyner /* Our single 20G media type */ 1770be771cdaSJack F Vogel case I40E_PHY_TYPE_20GBASE_KR2: 1771be771cdaSJack F Vogel ifmr->ifm_active |= IFM_20G_KR2; 1772be771cdaSJack F Vogel break; 1773be771cdaSJack F Vogel case I40E_PHY_TYPE_40GBASE_KR4: 1774be771cdaSJack F Vogel ifmr->ifm_active |= IFM_40G_KR4; 1775be771cdaSJack F Vogel break; 1776be771cdaSJack F Vogel case I40E_PHY_TYPE_XLPPI: 17771d767a8eSEric Joyner case I40E_PHY_TYPE_40GBASE_AOC: 1778be771cdaSJack F Vogel ifmr->ifm_active |= IFM_40G_XLPPI; 1779be771cdaSJack F Vogel break; 1780be771cdaSJack F Vogel #endif 17811d767a8eSEric Joyner /* Unknown to driver */ 178261ae650dSJack F Vogel default: 178361ae650dSJack F Vogel ifmr->ifm_active |= IFM_UNKNOWN; 178461ae650dSJack F Vogel break; 178561ae650dSJack F Vogel } 178661ae650dSJack F Vogel /* Report flow control status as well */ 178761ae650dSJack F Vogel if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) 178861ae650dSJack F Vogel ifmr->ifm_active |= IFM_ETH_TXPAUSE; 178961ae650dSJack F Vogel if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) 179061ae650dSJack F Vogel ifmr->ifm_active |= IFM_ETH_RXPAUSE; 179161ae650dSJack F Vogel 179261ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 179361ae650dSJack F Vogel 179461ae650dSJack F Vogel return; 179561ae650dSJack F Vogel } 179661ae650dSJack F Vogel 1797ac83ea83SEric Joyner /* 1798ac83ea83SEric Joyner * NOTE: Fortville does not support forcing media speeds. Instead, 1799ac83ea83SEric Joyner * use the set_advertise sysctl to set the speeds Fortville 1800ac83ea83SEric Joyner * will advertise or be allowed to operate at. 1801ac83ea83SEric Joyner */ 180261ae650dSJack F Vogel static int 180361ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp) 180461ae650dSJack F Vogel { 180561ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 180661ae650dSJack F Vogel struct ifmedia *ifm = &vsi->media; 180761ae650dSJack F Vogel 180861ae650dSJack F Vogel INIT_DEBUGOUT("ixl_media_change: begin"); 180961ae650dSJack F Vogel 181061ae650dSJack F Vogel if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 181161ae650dSJack F Vogel return (EINVAL); 181261ae650dSJack F Vogel 1813ac83ea83SEric Joyner if_printf(ifp, "Media change is not supported.\n"); 181461ae650dSJack F Vogel 181561ae650dSJack F Vogel return (ENODEV); 181661ae650dSJack F Vogel } 181761ae650dSJack F Vogel 181861ae650dSJack F Vogel 181961ae650dSJack F Vogel #ifdef IXL_FDIR 182061ae650dSJack F Vogel /* 182161ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter 182261ae650dSJack F Vogel ** based on TX flow info that will keep the receive 182361ae650dSJack F Vogel ** portion of the flow on the same queue. Based on the 182461ae650dSJack F Vogel ** implementation this is only available for TCP connections 182561ae650dSJack F Vogel */ 182661ae650dSJack F Vogel void 182761ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype) 182861ae650dSJack F Vogel { 182961ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 183061ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 183161ae650dSJack F Vogel struct i40e_filter_program_desc *FDIR; 183261ae650dSJack F Vogel u32 ptype, dtype; 183361ae650dSJack F Vogel int idx; 183461ae650dSJack F Vogel 183561ae650dSJack F Vogel /* check if ATR is enabled and sample rate */ 183661ae650dSJack F Vogel if ((!ixl_enable_fdir) || (!txr->atr_rate)) 183761ae650dSJack F Vogel return; 183861ae650dSJack F Vogel /* 183961ae650dSJack F Vogel ** We sample all TCP SYN/FIN packets, 184061ae650dSJack F Vogel ** or at the selected sample rate 184161ae650dSJack F Vogel */ 184261ae650dSJack F Vogel txr->atr_count++; 184361ae650dSJack F Vogel if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) && 184461ae650dSJack F Vogel (txr->atr_count < txr->atr_rate)) 184561ae650dSJack F Vogel return; 184661ae650dSJack F Vogel txr->atr_count = 0; 184761ae650dSJack F Vogel 184861ae650dSJack F Vogel /* Get a descriptor to use */ 184961ae650dSJack F Vogel idx = txr->next_avail; 185061ae650dSJack F Vogel FDIR = (struct i40e_filter_program_desc *) &txr->base[idx]; 185161ae650dSJack F Vogel if (++idx == que->num_desc) 185261ae650dSJack F Vogel idx = 0; 185361ae650dSJack F Vogel txr->avail--; 185461ae650dSJack F Vogel txr->next_avail = idx; 185561ae650dSJack F Vogel 185661ae650dSJack F Vogel ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & 185761ae650dSJack F Vogel I40E_TXD_FLTR_QW0_QINDEX_MASK; 185861ae650dSJack F Vogel 185961ae650dSJack F Vogel ptype |= (etype == ETHERTYPE_IP) ? 186061ae650dSJack F Vogel (I40E_FILTER_PCTYPE_NONF_IPV4_TCP << 186161ae650dSJack F Vogel I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) : 186261ae650dSJack F Vogel (I40E_FILTER_PCTYPE_NONF_IPV6_TCP << 186361ae650dSJack F Vogel I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); 186461ae650dSJack F Vogel 186561ae650dSJack F Vogel ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT; 186661ae650dSJack F Vogel 186761ae650dSJack F Vogel dtype = I40E_TX_DESC_DTYPE_FILTER_PROG; 186861ae650dSJack F Vogel 186961ae650dSJack F Vogel /* 187061ae650dSJack F Vogel ** We use the TCP TH_FIN as a trigger to remove 187161ae650dSJack F Vogel ** the filter, otherwise its an update. 187261ae650dSJack F Vogel */ 187361ae650dSJack F Vogel dtype |= (th->th_flags & TH_FIN) ? 187461ae650dSJack F Vogel (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << 187561ae650dSJack F Vogel I40E_TXD_FLTR_QW1_PCMD_SHIFT) : 187661ae650dSJack F Vogel (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << 187761ae650dSJack F Vogel I40E_TXD_FLTR_QW1_PCMD_SHIFT); 187861ae650dSJack F Vogel 187961ae650dSJack F Vogel dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX << 188061ae650dSJack F Vogel I40E_TXD_FLTR_QW1_DEST_SHIFT; 188161ae650dSJack F Vogel 188261ae650dSJack F Vogel dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID << 188361ae650dSJack F Vogel I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT; 188461ae650dSJack F Vogel 188561ae650dSJack F Vogel FDIR->qindex_flex_ptype_vsi = htole32(ptype); 188661ae650dSJack F Vogel FDIR->dtype_cmd_cntindex = htole32(dtype); 188761ae650dSJack F Vogel return; 188861ae650dSJack F Vogel } 188961ae650dSJack F Vogel #endif 189061ae650dSJack F Vogel 189161ae650dSJack F Vogel 189261ae650dSJack F Vogel static void 189361ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi) 189461ae650dSJack F Vogel { 189561ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 189661ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 189761ae650dSJack F Vogel int err, mcnt = 0; 189861ae650dSJack F Vogel bool uni = FALSE, multi = FALSE; 189961ae650dSJack F Vogel 190061ae650dSJack F Vogel if (ifp->if_flags & IFF_ALLMULTI) 190161ae650dSJack F Vogel multi = TRUE; 190261ae650dSJack F Vogel else { /* Need to count the multicast addresses */ 190361ae650dSJack F Vogel struct ifmultiaddr *ifma; 190461ae650dSJack F Vogel if_maddr_rlock(ifp); 190561ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 190661ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 190761ae650dSJack F Vogel continue; 190861ae650dSJack F Vogel if (mcnt == MAX_MULTICAST_ADDR) 190961ae650dSJack F Vogel break; 191061ae650dSJack F Vogel mcnt++; 191161ae650dSJack F Vogel } 191261ae650dSJack F Vogel if_maddr_runlock(ifp); 191361ae650dSJack F Vogel } 191461ae650dSJack F Vogel 191561ae650dSJack F Vogel if (mcnt >= MAX_MULTICAST_ADDR) 191661ae650dSJack F Vogel multi = TRUE; 191761ae650dSJack F Vogel if (ifp->if_flags & IFF_PROMISC) 191861ae650dSJack F Vogel uni = TRUE; 191961ae650dSJack F Vogel 192061ae650dSJack F Vogel err = i40e_aq_set_vsi_unicast_promiscuous(hw, 192161ae650dSJack F Vogel vsi->seid, uni, NULL); 192261ae650dSJack F Vogel err = i40e_aq_set_vsi_multicast_promiscuous(hw, 192361ae650dSJack F Vogel vsi->seid, multi, NULL); 192461ae650dSJack F Vogel return; 192561ae650dSJack F Vogel } 192661ae650dSJack F Vogel 192761ae650dSJack F Vogel /********************************************************************* 192861ae650dSJack F Vogel * Filter Routines 192961ae650dSJack F Vogel * 193061ae650dSJack F Vogel * Routines for multicast and vlan filter management. 193161ae650dSJack F Vogel * 193261ae650dSJack F Vogel *********************************************************************/ 193361ae650dSJack F Vogel static void 193461ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi) 193561ae650dSJack F Vogel { 193661ae650dSJack F Vogel struct ifmultiaddr *ifma; 193761ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 193861ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 193961ae650dSJack F Vogel int mcnt = 0, flags; 194061ae650dSJack F Vogel 194161ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_add_multi: begin"); 194261ae650dSJack F Vogel 194361ae650dSJack F Vogel if_maddr_rlock(ifp); 194461ae650dSJack F Vogel /* 194561ae650dSJack F Vogel ** First just get a count, to decide if we 194661ae650dSJack F Vogel ** we simply use multicast promiscuous. 194761ae650dSJack F Vogel */ 194861ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 194961ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 195061ae650dSJack F Vogel continue; 195161ae650dSJack F Vogel mcnt++; 195261ae650dSJack F Vogel } 195361ae650dSJack F Vogel if_maddr_runlock(ifp); 195461ae650dSJack F Vogel 195561ae650dSJack F Vogel if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { 195661ae650dSJack F Vogel /* delete existing MC filters */ 195761ae650dSJack F Vogel ixl_del_hw_filters(vsi, mcnt); 195861ae650dSJack F Vogel i40e_aq_set_vsi_multicast_promiscuous(hw, 195961ae650dSJack F Vogel vsi->seid, TRUE, NULL); 196061ae650dSJack F Vogel return; 196161ae650dSJack F Vogel } 196261ae650dSJack F Vogel 196361ae650dSJack F Vogel mcnt = 0; 196461ae650dSJack F Vogel if_maddr_rlock(ifp); 196561ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 196661ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 196761ae650dSJack F Vogel continue; 196861ae650dSJack F Vogel ixl_add_mc_filter(vsi, 196961ae650dSJack F Vogel (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); 197061ae650dSJack F Vogel mcnt++; 197161ae650dSJack F Vogel } 197261ae650dSJack F Vogel if_maddr_runlock(ifp); 197361ae650dSJack F Vogel if (mcnt > 0) { 197461ae650dSJack F Vogel flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); 197561ae650dSJack F Vogel ixl_add_hw_filters(vsi, flags, mcnt); 197661ae650dSJack F Vogel } 197761ae650dSJack F Vogel 197861ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_add_multi: end"); 197961ae650dSJack F Vogel return; 198061ae650dSJack F Vogel } 198161ae650dSJack F Vogel 198261ae650dSJack F Vogel static void 198361ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi) 198461ae650dSJack F Vogel { 198561ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 198661ae650dSJack F Vogel struct ifmultiaddr *ifma; 198761ae650dSJack F Vogel struct ixl_mac_filter *f; 198861ae650dSJack F Vogel int mcnt = 0; 198961ae650dSJack F Vogel bool match = FALSE; 199061ae650dSJack F Vogel 199161ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_del_multi: begin"); 199261ae650dSJack F Vogel 199361ae650dSJack F Vogel /* Search for removed multicast addresses */ 199461ae650dSJack F Vogel if_maddr_rlock(ifp); 199561ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 199661ae650dSJack F Vogel if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) { 199761ae650dSJack F Vogel match = FALSE; 199861ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 199961ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 200061ae650dSJack F Vogel continue; 200161ae650dSJack F Vogel u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 200261ae650dSJack F Vogel if (cmp_etheraddr(f->macaddr, mc_addr)) { 200361ae650dSJack F Vogel match = TRUE; 200461ae650dSJack F Vogel break; 200561ae650dSJack F Vogel } 200661ae650dSJack F Vogel } 200761ae650dSJack F Vogel if (match == FALSE) { 200861ae650dSJack F Vogel f->flags |= IXL_FILTER_DEL; 200961ae650dSJack F Vogel mcnt++; 201061ae650dSJack F Vogel } 201161ae650dSJack F Vogel } 201261ae650dSJack F Vogel } 201361ae650dSJack F Vogel if_maddr_runlock(ifp); 201461ae650dSJack F Vogel 201561ae650dSJack F Vogel if (mcnt > 0) 201661ae650dSJack F Vogel ixl_del_hw_filters(vsi, mcnt); 201761ae650dSJack F Vogel } 201861ae650dSJack F Vogel 201961ae650dSJack F Vogel 202061ae650dSJack F Vogel /********************************************************************* 202161ae650dSJack F Vogel * Timer routine 202261ae650dSJack F Vogel * 202361ae650dSJack F Vogel * This routine checks for link status,updates statistics, 202461ae650dSJack F Vogel * and runs the watchdog check. 202561ae650dSJack F Vogel * 202695bb0504SEric Joyner * Only runs when the driver is configured UP and RUNNING. 202795bb0504SEric Joyner * 202861ae650dSJack F Vogel **********************************************************************/ 202961ae650dSJack F Vogel 203061ae650dSJack F Vogel static void 203161ae650dSJack F Vogel ixl_local_timer(void *arg) 203261ae650dSJack F Vogel { 203361ae650dSJack F Vogel struct ixl_pf *pf = arg; 203461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 203561ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 203661ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 203761ae650dSJack F Vogel device_t dev = pf->dev; 203861ae650dSJack F Vogel int hung = 0; 203961ae650dSJack F Vogel u32 mask; 204061ae650dSJack F Vogel 204161ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 204261ae650dSJack F Vogel 204361ae650dSJack F Vogel /* Fire off the adminq task */ 204461ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 204561ae650dSJack F Vogel 204661ae650dSJack F Vogel /* Update stats */ 204761ae650dSJack F Vogel ixl_update_stats_counters(pf); 204861ae650dSJack F Vogel 204961ae650dSJack F Vogel /* 205061ae650dSJack F Vogel ** Check status of the queues 205161ae650dSJack F Vogel */ 205261ae650dSJack F Vogel mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | 205361ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); 205461ae650dSJack F Vogel 205561ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 205661ae650dSJack F Vogel /* Any queues with outstanding work get a sw irq */ 205761ae650dSJack F Vogel if (que->busy) 205861ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask); 205961ae650dSJack F Vogel /* 206061ae650dSJack F Vogel ** Each time txeof runs without cleaning, but there 206161ae650dSJack F Vogel ** are uncleaned descriptors it increments busy. If 206261ae650dSJack F Vogel ** we get to 5 we declare it hung. 206361ae650dSJack F Vogel */ 206461ae650dSJack F Vogel if (que->busy == IXL_QUEUE_HUNG) { 206561ae650dSJack F Vogel ++hung; 206661ae650dSJack F Vogel /* Mark the queue as inactive */ 206761ae650dSJack F Vogel vsi->active_queues &= ~((u64)1 << que->me); 206861ae650dSJack F Vogel continue; 206961ae650dSJack F Vogel } else { 207061ae650dSJack F Vogel /* Check if we've come back from hung */ 207161ae650dSJack F Vogel if ((vsi->active_queues & ((u64)1 << que->me)) == 0) 207261ae650dSJack F Vogel vsi->active_queues |= ((u64)1 << que->me); 207361ae650dSJack F Vogel } 207461ae650dSJack F Vogel if (que->busy >= IXL_MAX_TX_BUSY) { 2075393c4bb1SJack F Vogel #ifdef IXL_DEBUG 207661ae650dSJack F Vogel device_printf(dev,"Warning queue %d " 207761ae650dSJack F Vogel "appears to be hung!\n", i); 2078393c4bb1SJack F Vogel #endif 207961ae650dSJack F Vogel que->busy = IXL_QUEUE_HUNG; 208061ae650dSJack F Vogel ++hung; 208161ae650dSJack F Vogel } 208261ae650dSJack F Vogel } 208361ae650dSJack F Vogel /* Only reinit if all queues show hung */ 208461ae650dSJack F Vogel if (hung == vsi->num_queues) 208561ae650dSJack F Vogel goto hung; 208661ae650dSJack F Vogel 208761ae650dSJack F Vogel callout_reset(&pf->timer, hz, ixl_local_timer, pf); 208861ae650dSJack F Vogel return; 208961ae650dSJack F Vogel 209061ae650dSJack F Vogel hung: 209161ae650dSJack F Vogel device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n"); 209261ae650dSJack F Vogel ixl_init_locked(pf); 209361ae650dSJack F Vogel } 209461ae650dSJack F Vogel 209561ae650dSJack F Vogel /* 209661ae650dSJack F Vogel ** Note: this routine updates the OS on the link state 209761ae650dSJack F Vogel ** the real check of the hardware only happens with 209861ae650dSJack F Vogel ** a link interrupt. 209961ae650dSJack F Vogel */ 210061ae650dSJack F Vogel static void 210161ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf) 210261ae650dSJack F Vogel { 210361ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 210461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 210561ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 210661ae650dSJack F Vogel device_t dev = pf->dev; 210761ae650dSJack F Vogel 210856c2c47bSJack F Vogel if (pf->link_up) { 210961ae650dSJack F Vogel if (vsi->link_active == FALSE) { 2110b6c8f260SJack F Vogel pf->fc = hw->fc.current_mode; 211161ae650dSJack F Vogel if (bootverbose) { 211261ae650dSJack F Vogel device_printf(dev,"Link is up %d Gbps %s," 211361ae650dSJack F Vogel " Flow Control: %s\n", 211456c2c47bSJack F Vogel ((pf->link_speed == 211556c2c47bSJack F Vogel I40E_LINK_SPEED_40GB)? 40:10), 2116b6c8f260SJack F Vogel "Full Duplex", ixl_fc_string[pf->fc]); 211761ae650dSJack F Vogel } 211861ae650dSJack F Vogel vsi->link_active = TRUE; 2119393c4bb1SJack F Vogel /* 2120393c4bb1SJack F Vogel ** Warn user if link speed on NPAR enabled 2121393c4bb1SJack F Vogel ** partition is not at least 10GB 2122393c4bb1SJack F Vogel */ 2123393c4bb1SJack F Vogel if (hw->func_caps.npar_enable && 212456c2c47bSJack F Vogel (hw->phy.link_info.link_speed == 212556c2c47bSJack F Vogel I40E_LINK_SPEED_1GB || 212656c2c47bSJack F Vogel hw->phy.link_info.link_speed == 212756c2c47bSJack F Vogel I40E_LINK_SPEED_100MB)) 212856c2c47bSJack F Vogel device_printf(dev, "The partition detected" 212956c2c47bSJack F Vogel "link speed that is less than 10Gbps\n"); 213061ae650dSJack F Vogel if_link_state_change(ifp, LINK_STATE_UP); 213161ae650dSJack F Vogel } 213261ae650dSJack F Vogel } else { /* Link down */ 213361ae650dSJack F Vogel if (vsi->link_active == TRUE) { 213461ae650dSJack F Vogel if (bootverbose) 213561ae650dSJack F Vogel device_printf(dev, "Link is Down\n"); 213661ae650dSJack F Vogel if_link_state_change(ifp, LINK_STATE_DOWN); 213761ae650dSJack F Vogel vsi->link_active = FALSE; 213861ae650dSJack F Vogel } 213961ae650dSJack F Vogel } 214061ae650dSJack F Vogel 214161ae650dSJack F Vogel return; 214261ae650dSJack F Vogel } 214361ae650dSJack F Vogel 2144223d846dSEric Joyner static void 2145223d846dSEric Joyner ixl_stop(struct ixl_pf *pf) 2146223d846dSEric Joyner { 2147223d846dSEric Joyner IXL_PF_LOCK(pf); 2148223d846dSEric Joyner ixl_stop_locked(pf); 2149223d846dSEric Joyner IXL_PF_UNLOCK(pf); 2150223d846dSEric Joyner 21516c426059SEric Joyner ixl_teardown_queue_msix(&pf->vsi); 21526d011ad5SEric Joyner ixl_free_queue_tqs(&pf->vsi); 2153223d846dSEric Joyner } 2154223d846dSEric Joyner 215561ae650dSJack F Vogel /********************************************************************* 215661ae650dSJack F Vogel * 215761ae650dSJack F Vogel * This routine disables all traffic on the adapter by issuing a 215861ae650dSJack F Vogel * global reset on the MAC and deallocates TX/RX buffers. 215961ae650dSJack F Vogel * 216061ae650dSJack F Vogel **********************************************************************/ 216161ae650dSJack F Vogel 216261ae650dSJack F Vogel static void 2163223d846dSEric Joyner ixl_stop_locked(struct ixl_pf *pf) 216461ae650dSJack F Vogel { 216561ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 216661ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 216761ae650dSJack F Vogel 216861ae650dSJack F Vogel INIT_DEBUGOUT("ixl_stop: begin\n"); 2169223d846dSEric Joyner 2170223d846dSEric Joyner IXL_PF_LOCK_ASSERT(pf); 2171223d846dSEric Joyner 2172223d846dSEric Joyner /* Stop the local timer */ 2173223d846dSEric Joyner callout_stop(&pf->timer); 2174223d846dSEric Joyner 217556c2c47bSJack F Vogel ixl_disable_rings_intr(vsi); 217661ae650dSJack F Vogel ixl_disable_rings(vsi); 217761ae650dSJack F Vogel 217861ae650dSJack F Vogel /* Tell the stack that the interface is no longer active */ 21796c426059SEric Joyner ifp->if_drv_flags &= ~(IFF_DRV_RUNNING); 218061ae650dSJack F Vogel } 218161ae650dSJack F Vogel 218261ae650dSJack F Vogel 218361ae650dSJack F Vogel /********************************************************************* 218461ae650dSJack F Vogel * 218561ae650dSJack F Vogel * Setup MSIX Interrupt resources and handlers for the VSI 218661ae650dSJack F Vogel * 218761ae650dSJack F Vogel **********************************************************************/ 218861ae650dSJack F Vogel static int 218961ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf) 219061ae650dSJack F Vogel { 219161ae650dSJack F Vogel device_t dev = pf->dev; 219261ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 219361ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 219461ae650dSJack F Vogel int error, rid = 0; 219561ae650dSJack F Vogel 219661ae650dSJack F Vogel if (pf->msix == 1) 219761ae650dSJack F Vogel rid = 1; 219861ae650dSJack F Vogel pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 219961ae650dSJack F Vogel &rid, RF_SHAREABLE | RF_ACTIVE); 220061ae650dSJack F Vogel if (pf->res == NULL) { 220161ae650dSJack F Vogel device_printf(dev, "Unable to allocate" 220261ae650dSJack F Vogel " bus resource: vsi legacy/msi interrupt\n"); 220361ae650dSJack F Vogel return (ENXIO); 220461ae650dSJack F Vogel } 220561ae650dSJack F Vogel 220661ae650dSJack F Vogel /* Set the handler function */ 220761ae650dSJack F Vogel error = bus_setup_intr(dev, pf->res, 220861ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 220961ae650dSJack F Vogel ixl_intr, pf, &pf->tag); 221061ae650dSJack F Vogel if (error) { 221161ae650dSJack F Vogel pf->res = NULL; 22121d767a8eSEric Joyner device_printf(dev, "Failed to register legacy/msi handler\n"); 221361ae650dSJack F Vogel return (error); 221461ae650dSJack F Vogel } 221561ae650dSJack F Vogel bus_describe_intr(dev, pf->res, pf->tag, "irq0"); 221661ae650dSJack F Vogel TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 221761ae650dSJack F Vogel TASK_INIT(&que->task, 0, ixl_handle_que, que); 221861ae650dSJack F Vogel que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 221961ae650dSJack F Vogel taskqueue_thread_enqueue, &que->tq); 222061ae650dSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 222161ae650dSJack F Vogel device_get_nameunit(dev)); 222261ae650dSJack F Vogel TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 222356c2c47bSJack F Vogel 222461ae650dSJack F Vogel pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 222561ae650dSJack F Vogel taskqueue_thread_enqueue, &pf->tq); 222661ae650dSJack F Vogel taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 222761ae650dSJack F Vogel device_get_nameunit(dev)); 222861ae650dSJack F Vogel 222961ae650dSJack F Vogel return (0); 223061ae650dSJack F Vogel } 223161ae650dSJack F Vogel 22326c426059SEric Joyner static int 22336c426059SEric Joyner ixl_setup_adminq_tq(struct ixl_pf *pf) 2234a48d00d2SEric Joyner { 2235a48d00d2SEric Joyner device_t dev = pf->dev; 22366c426059SEric Joyner int error = 0; 2237a48d00d2SEric Joyner 22386c426059SEric Joyner /* Tasklet for Admin Queue interrupts */ 2239a48d00d2SEric Joyner TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 2240a48d00d2SEric Joyner #ifdef PCI_IOV 2241a48d00d2SEric Joyner /* VFLR Tasklet */ 2242a48d00d2SEric Joyner TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf); 2243a48d00d2SEric Joyner #endif 22446c426059SEric Joyner /* Create and start Admin Queue taskqueue */ 22456c426059SEric Joyner pf->tq = taskqueue_create_fast("ixl_aq", M_NOWAIT, 2246a48d00d2SEric Joyner taskqueue_thread_enqueue, &pf->tq); 22476c426059SEric Joyner if (!pf->tq) { 22486c426059SEric Joyner device_printf(dev, "taskqueue_create_fast (for AQ) returned NULL!\n"); 22496c426059SEric Joyner return (ENOMEM); 22506c426059SEric Joyner } 22516c426059SEric Joyner error = taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s aq", 2252a48d00d2SEric Joyner device_get_nameunit(dev)); 22536c426059SEric Joyner if (error) { 22546c426059SEric Joyner device_printf(dev, "taskqueue_start_threads (for AQ) error: %d\n", 22556c426059SEric Joyner error); 22566c426059SEric Joyner taskqueue_free(pf->tq); 22576c426059SEric Joyner return (error); 22586c426059SEric Joyner } 22596c426059SEric Joyner return (0); 22606c426059SEric Joyner } 22616c426059SEric Joyner 22626c426059SEric Joyner static int 22636c426059SEric Joyner ixl_setup_queue_tqs(struct ixl_vsi *vsi) 22646c426059SEric Joyner { 22656c426059SEric Joyner struct ixl_queue *que = vsi->queues; 22666c426059SEric Joyner device_t dev = vsi->dev; 2267a48d00d2SEric Joyner 2268a48d00d2SEric Joyner /* Create queue tasks and start queue taskqueues */ 2269a48d00d2SEric Joyner for (int i = 0; i < vsi->num_queues; i++, que++) { 2270a48d00d2SEric Joyner TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 2271a48d00d2SEric Joyner TASK_INIT(&que->task, 0, ixl_handle_que, que); 2272a48d00d2SEric Joyner que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 2273a48d00d2SEric Joyner taskqueue_thread_enqueue, &que->tq); 2274a48d00d2SEric Joyner #ifdef RSS 2275a48d00d2SEric Joyner CPU_SETOF(cpu_id, &cpu_mask); 2276a48d00d2SEric Joyner taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, 2277a48d00d2SEric Joyner &cpu_mask, "%s (bucket %d)", 2278a48d00d2SEric Joyner device_get_nameunit(dev), cpu_id); 2279a48d00d2SEric Joyner #else 2280a48d00d2SEric Joyner taskqueue_start_threads(&que->tq, 1, PI_NET, 2281a48d00d2SEric Joyner "%s (que %d)", device_get_nameunit(dev), que->me); 2282a48d00d2SEric Joyner #endif 2283a48d00d2SEric Joyner } 2284a48d00d2SEric Joyner 22856c426059SEric Joyner return (0); 2286a48d00d2SEric Joyner } 2287a48d00d2SEric Joyner 2288a48d00d2SEric Joyner static void 22896c426059SEric Joyner ixl_free_adminq_tq(struct ixl_pf *pf) 2290a48d00d2SEric Joyner { 22916d011ad5SEric Joyner if (pf->tq) { 2292a48d00d2SEric Joyner taskqueue_free(pf->tq); 22936d011ad5SEric Joyner pf->tq = NULL; 22946d011ad5SEric Joyner } 22956c426059SEric Joyner } 22966c426059SEric Joyner 22976c426059SEric Joyner static void 22986c426059SEric Joyner ixl_free_queue_tqs(struct ixl_vsi *vsi) 22996c426059SEric Joyner { 23006c426059SEric Joyner struct ixl_queue *que = vsi->queues; 23016c426059SEric Joyner 2302a48d00d2SEric Joyner for (int i = 0; i < vsi->num_queues; i++, que++) { 23036d011ad5SEric Joyner if (que->tq) { 2304a48d00d2SEric Joyner taskqueue_free(que->tq); 23056d011ad5SEric Joyner que->tq = NULL; 23066d011ad5SEric Joyner } 2307a48d00d2SEric Joyner } 2308a48d00d2SEric Joyner } 230961ae650dSJack F Vogel 231061ae650dSJack F Vogel static int 23116c426059SEric Joyner ixl_setup_adminq_msix(struct ixl_pf *pf) 231261ae650dSJack F Vogel { 231361ae650dSJack F Vogel device_t dev = pf->dev; 23146c426059SEric Joyner int rid, error = 0; 231561ae650dSJack F Vogel 23166c426059SEric Joyner /* Admin IRQ rid is 1, vector is 0 */ 23176c426059SEric Joyner rid = 1; 23186c426059SEric Joyner /* Get interrupt resource from bus */ 231961ae650dSJack F Vogel pf->res = bus_alloc_resource_any(dev, 232061ae650dSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 232161ae650dSJack F Vogel if (!pf->res) { 23226c426059SEric Joyner device_printf(dev, "bus_alloc_resource_any() for Admin Queue" 23236c426059SEric Joyner " interrupt failed [rid=%d]\n", rid); 232461ae650dSJack F Vogel return (ENXIO); 232561ae650dSJack F Vogel } 23266c426059SEric Joyner /* Then associate interrupt with handler */ 232761ae650dSJack F Vogel error = bus_setup_intr(dev, pf->res, 232861ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 232961ae650dSJack F Vogel ixl_msix_adminq, pf, &pf->tag); 233061ae650dSJack F Vogel if (error) { 233161ae650dSJack F Vogel pf->res = NULL; 23326c426059SEric Joyner device_printf(dev, "bus_setup_intr() for Admin Queue" 23336c426059SEric Joyner " interrupt handler failed, error %d\n", error); 23346c426059SEric Joyner return (ENXIO); 233561ae650dSJack F Vogel } 23366c426059SEric Joyner error = bus_describe_intr(dev, pf->res, pf->tag, "aq"); 23376c426059SEric Joyner if (error) { 23386c426059SEric Joyner /* Probably non-fatal? */ 23396c426059SEric Joyner device_printf(dev, "bus_describe_intr() for Admin Queue" 23406c426059SEric Joyner " interrupt name failed, error %d\n", error); 23416c426059SEric Joyner } 23426c426059SEric Joyner pf->admvec = 0; 234361ae650dSJack F Vogel 23446c426059SEric Joyner return (0); 23456c426059SEric Joyner } 23466c426059SEric Joyner 23476c426059SEric Joyner /* 23486c426059SEric Joyner * Allocate interrupt resources from bus and associate an interrupt handler 23496c426059SEric Joyner * to those for the VSI's queues. 23506c426059SEric Joyner */ 23516c426059SEric Joyner static int 23526c426059SEric Joyner ixl_setup_queue_msix(struct ixl_vsi *vsi) 23536c426059SEric Joyner { 23546c426059SEric Joyner device_t dev = vsi->dev; 23556c426059SEric Joyner struct ixl_queue *que = vsi->queues; 23566c426059SEric Joyner struct tx_ring *txr; 23576c426059SEric Joyner int error, rid, vector = 1; 23586c426059SEric Joyner #ifdef RSS 23596c426059SEric Joyner cpuset_t cpu_mask; 23606c426059SEric Joyner #endif 23616c426059SEric Joyner 23626c426059SEric Joyner /* Queue interrupt vector numbers start at 1 (adminq intr is 0) */ 236361ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { 2364393c4bb1SJack F Vogel int cpu_id = i; 236561ae650dSJack F Vogel rid = vector + 1; 236661ae650dSJack F Vogel txr = &que->txr; 236761ae650dSJack F Vogel que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 236861ae650dSJack F Vogel RF_SHAREABLE | RF_ACTIVE); 23696c426059SEric Joyner if (!que->res) { 23706c426059SEric Joyner device_printf(dev, "bus_alloc_resource_any() for" 23716c426059SEric Joyner " Queue %d interrupt failed [rid=%d]\n", 23726c426059SEric Joyner que->me, rid); 237361ae650dSJack F Vogel return (ENXIO); 237461ae650dSJack F Vogel } 237561ae650dSJack F Vogel /* Set the handler function */ 237661ae650dSJack F Vogel error = bus_setup_intr(dev, que->res, 237761ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 237861ae650dSJack F Vogel ixl_msix_que, que, &que->tag); 237961ae650dSJack F Vogel if (error) { 23806c426059SEric Joyner device_printf(dev, "bus_setup_intr() for Queue %d" 23816c426059SEric Joyner " interrupt handler failed, error %d\n", 23826c426059SEric Joyner que->me, error); 23836c426059SEric Joyner // TODO: Check for error from this? 23846c426059SEric Joyner bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 238561ae650dSJack F Vogel return (error); 238661ae650dSJack F Vogel } 23876d011ad5SEric Joyner error = bus_describe_intr(dev, que->res, que->tag, "q%d", i); 23886c426059SEric Joyner if (error) { 23896c426059SEric Joyner device_printf(dev, "bus_describe_intr() for Queue %d" 23906c426059SEric Joyner " interrupt name failed, error %d\n", 23916c426059SEric Joyner que->me, error); 23926c426059SEric Joyner } 239361ae650dSJack F Vogel /* Bind the vector to a CPU */ 2394393c4bb1SJack F Vogel #ifdef RSS 2395393c4bb1SJack F Vogel cpu_id = rss_getcpu(i % rss_getnumbuckets()); 2396393c4bb1SJack F Vogel #endif 23976c426059SEric Joyner error = bus_bind_intr(dev, que->res, cpu_id); 23986c426059SEric Joyner if (error) { 23996c426059SEric Joyner device_printf(dev, "bus_bind_intr() for Queue %d" 24006c426059SEric Joyner " to CPU %d failed, error %d\n", 24016c426059SEric Joyner que->me, cpu_id, error); 24026c426059SEric Joyner } 240361ae650dSJack F Vogel que->msix = vector; 240461ae650dSJack F Vogel } 240561ae650dSJack F Vogel 240661ae650dSJack F Vogel return (0); 240761ae650dSJack F Vogel } 240861ae650dSJack F Vogel 240961ae650dSJack F Vogel 241061ae650dSJack F Vogel /* 241161ae650dSJack F Vogel * Allocate MSI/X vectors 241261ae650dSJack F Vogel */ 241361ae650dSJack F Vogel static int 241461ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf) 241561ae650dSJack F Vogel { 241661ae650dSJack F Vogel device_t dev = pf->dev; 241761ae650dSJack F Vogel int rid, want, vectors, queues, available; 241861ae650dSJack F Vogel 241961ae650dSJack F Vogel /* Override by tuneable */ 242061ae650dSJack F Vogel if (ixl_enable_msix == 0) 24211d767a8eSEric Joyner goto no_msix; 242261ae650dSJack F Vogel 242361ae650dSJack F Vogel /* 242461ae650dSJack F Vogel ** When used in a virtualized environment 242561ae650dSJack F Vogel ** PCI BUSMASTER capability may not be set 242661ae650dSJack F Vogel ** so explicity set it here and rewrite 242761ae650dSJack F Vogel ** the ENABLE in the MSIX control register 242861ae650dSJack F Vogel ** at this point to cause the host to 242961ae650dSJack F Vogel ** successfully initialize us. 243061ae650dSJack F Vogel */ 243161ae650dSJack F Vogel { 243261ae650dSJack F Vogel u16 pci_cmd_word; 243361ae650dSJack F Vogel int msix_ctrl; 243461ae650dSJack F Vogel pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); 243561ae650dSJack F Vogel pci_cmd_word |= PCIM_CMD_BUSMASTEREN; 243661ae650dSJack F Vogel pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); 243761ae650dSJack F Vogel pci_find_cap(dev, PCIY_MSIX, &rid); 243861ae650dSJack F Vogel rid += PCIR_MSIX_CTRL; 243961ae650dSJack F Vogel msix_ctrl = pci_read_config(dev, rid, 2); 244061ae650dSJack F Vogel msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; 244161ae650dSJack F Vogel pci_write_config(dev, rid, msix_ctrl, 2); 244261ae650dSJack F Vogel } 244361ae650dSJack F Vogel 244461ae650dSJack F Vogel /* First try MSI/X */ 244561ae650dSJack F Vogel rid = PCIR_BAR(IXL_BAR); 244661ae650dSJack F Vogel pf->msix_mem = bus_alloc_resource_any(dev, 244761ae650dSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 244861ae650dSJack F Vogel if (!pf->msix_mem) { 244961ae650dSJack F Vogel /* May not be enabled */ 245061ae650dSJack F Vogel device_printf(pf->dev, 245161ae650dSJack F Vogel "Unable to map MSIX table\n"); 24521d767a8eSEric Joyner goto no_msix; 245361ae650dSJack F Vogel } 245461ae650dSJack F Vogel 245561ae650dSJack F Vogel available = pci_msix_count(dev); 245661ae650dSJack F Vogel if (available == 0) { /* system has msix disabled */ 245761ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 245861ae650dSJack F Vogel rid, pf->msix_mem); 245961ae650dSJack F Vogel pf->msix_mem = NULL; 24601d767a8eSEric Joyner goto no_msix; 246161ae650dSJack F Vogel } 246261ae650dSJack F Vogel 246361ae650dSJack F Vogel /* Figure out a reasonable auto config value */ 246461ae650dSJack F Vogel queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus; 246561ae650dSJack F Vogel 24661d767a8eSEric Joyner /* Override with tunable value if tunable is less than autoconfig count */ 246761ae650dSJack F Vogel if ((ixl_max_queues != 0) && (ixl_max_queues <= queues)) 246861ae650dSJack F Vogel queues = ixl_max_queues; 2469a48d00d2SEric Joyner else if ((ixl_max_queues != 0) && (ixl_max_queues > queues)) 2470a48d00d2SEric Joyner device_printf(dev, "ixl_max_queues > # of cpus, using " 2471a48d00d2SEric Joyner "autoconfig amount...\n"); 2472a48d00d2SEric Joyner /* Or limit maximum auto-configured queues to 8 */ 2473a48d00d2SEric Joyner else if ((ixl_max_queues == 0) && (queues > 8)) 2474a48d00d2SEric Joyner queues = 8; 247561ae650dSJack F Vogel 2476393c4bb1SJack F Vogel #ifdef RSS 2477393c4bb1SJack F Vogel /* If we're doing RSS, clamp at the number of RSS buckets */ 2478393c4bb1SJack F Vogel if (queues > rss_getnumbuckets()) 2479393c4bb1SJack F Vogel queues = rss_getnumbuckets(); 2480393c4bb1SJack F Vogel #endif 2481393c4bb1SJack F Vogel 248261ae650dSJack F Vogel /* 248361ae650dSJack F Vogel ** Want one vector (RX/TX pair) per queue 248461ae650dSJack F Vogel ** plus an additional for the admin queue. 248561ae650dSJack F Vogel */ 248661ae650dSJack F Vogel want = queues + 1; 248761ae650dSJack F Vogel if (want <= available) /* Have enough */ 248861ae650dSJack F Vogel vectors = want; 248961ae650dSJack F Vogel else { 249061ae650dSJack F Vogel device_printf(pf->dev, 249161ae650dSJack F Vogel "MSIX Configuration Problem, " 249261ae650dSJack F Vogel "%d vectors available but %d wanted!\n", 249361ae650dSJack F Vogel available, want); 249461ae650dSJack F Vogel return (0); /* Will go to Legacy setup */ 249561ae650dSJack F Vogel } 249661ae650dSJack F Vogel 249761ae650dSJack F Vogel if (pci_alloc_msix(dev, &vectors) == 0) { 249861ae650dSJack F Vogel device_printf(pf->dev, 249961ae650dSJack F Vogel "Using MSIX interrupts with %d vectors\n", vectors); 250061ae650dSJack F Vogel pf->msix = vectors; 250161ae650dSJack F Vogel pf->vsi.num_queues = queues; 2502393c4bb1SJack F Vogel #ifdef RSS 2503393c4bb1SJack F Vogel /* 2504393c4bb1SJack F Vogel * If we're doing RSS, the number of queues needs to 2505393c4bb1SJack F Vogel * match the number of RSS buckets that are configured. 2506393c4bb1SJack F Vogel * 2507393c4bb1SJack F Vogel * + If there's more queues than RSS buckets, we'll end 2508393c4bb1SJack F Vogel * up with queues that get no traffic. 2509393c4bb1SJack F Vogel * 2510393c4bb1SJack F Vogel * + If there's more RSS buckets than queues, we'll end 2511393c4bb1SJack F Vogel * up having multiple RSS buckets map to the same queue, 2512393c4bb1SJack F Vogel * so there'll be some contention. 2513393c4bb1SJack F Vogel */ 2514393c4bb1SJack F Vogel if (queues != rss_getnumbuckets()) { 2515393c4bb1SJack F Vogel device_printf(dev, 2516393c4bb1SJack F Vogel "%s: queues (%d) != RSS buckets (%d)" 2517393c4bb1SJack F Vogel "; performance will be impacted.\n", 2518393c4bb1SJack F Vogel __func__, queues, rss_getnumbuckets()); 2519393c4bb1SJack F Vogel } 2520393c4bb1SJack F Vogel #endif 252161ae650dSJack F Vogel return (vectors); 252261ae650dSJack F Vogel } 25231d767a8eSEric Joyner no_msix: 252461ae650dSJack F Vogel vectors = pci_msi_count(dev); 252561ae650dSJack F Vogel pf->vsi.num_queues = 1; 252661ae650dSJack F Vogel ixl_max_queues = 1; 252761ae650dSJack F Vogel ixl_enable_msix = 0; 252861ae650dSJack F Vogel if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) 252961ae650dSJack F Vogel device_printf(pf->dev, "Using an MSI interrupt\n"); 253061ae650dSJack F Vogel else { 25311d767a8eSEric Joyner vectors = 0; 253261ae650dSJack F Vogel device_printf(pf->dev, "Using a Legacy interrupt\n"); 253361ae650dSJack F Vogel } 253461ae650dSJack F Vogel return (vectors); 253561ae650dSJack F Vogel } 253661ae650dSJack F Vogel 253761ae650dSJack F Vogel /* 25386c426059SEric Joyner * Configure admin queue/misc interrupt cause registers in hardware. 253961ae650dSJack F Vogel */ 254061ae650dSJack F Vogel static void 25416c426059SEric Joyner ixl_configure_intr0_msix(struct ixl_pf *pf) 254261ae650dSJack F Vogel { 254361ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 254461ae650dSJack F Vogel u32 reg; 254561ae650dSJack F Vogel 254661ae650dSJack F Vogel /* First set up the adminq - vector 0 */ 254761ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, 0); /* disable all */ 254861ae650dSJack F Vogel rd32(hw, I40E_PFINT_ICR0); /* read to clear */ 254961ae650dSJack F Vogel 255061ae650dSJack F Vogel reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | 255161ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_GRST_MASK | 2552fdb6f38aSEric Joyner I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | 255361ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_ADMINQ_MASK | 255461ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK | 255561ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_VFLR_MASK | 255661ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK; 255761ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 255861ae650dSJack F Vogel 2559223d846dSEric Joyner /* 2560223d846dSEric Joyner * 0x7FF is the end of the queue list. 2561223d846dSEric Joyner * This means we won't use MSI-X vector 0 for a queue interrupt 2562223d846dSEric Joyner * in MSIX mode. 2563223d846dSEric Joyner */ 256461ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLST0, 0x7FF); 2565223d846dSEric Joyner /* Value is in 2 usec units, so 0x3E is 62*2 = 124 usecs. */ 2566223d846dSEric Joyner wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x3E); 256761ae650dSJack F Vogel 256861ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, 256961ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK | 257061ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK); 257161ae650dSJack F Vogel 257261ae650dSJack F Vogel wr32(hw, I40E_PFINT_STAT_CTL0, 0); 25736c426059SEric Joyner } 257461ae650dSJack F Vogel 25756c426059SEric Joyner /* 25766c426059SEric Joyner * Configure queue interrupt cause registers in hardware. 25776c426059SEric Joyner */ 25786c426059SEric Joyner static void 25796c426059SEric Joyner ixl_configure_queue_intr_msix(struct ixl_pf *pf) 25806c426059SEric Joyner { 25816c426059SEric Joyner struct i40e_hw *hw = &pf->hw; 25826c426059SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 25836c426059SEric Joyner u32 reg; 25846c426059SEric Joyner u16 vector = 1; 25856c426059SEric Joyner 258661ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, vector++) { 2587*d4683565SEric Joyner wr32(hw, I40E_PFINT_DYN_CTLN(i), 0); 2588*d4683565SEric Joyner /* First queue type is RX / 0 */ 258961ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLSTN(i), i); 259061ae650dSJack F Vogel 259161ae650dSJack F Vogel reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | 259261ae650dSJack F Vogel (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | 259361ae650dSJack F Vogel (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 259461ae650dSJack F Vogel (i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 259561ae650dSJack F Vogel (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); 259661ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(i), reg); 259761ae650dSJack F Vogel 259861ae650dSJack F Vogel reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK | 259961ae650dSJack F Vogel (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | 260061ae650dSJack F Vogel (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | 2601*d4683565SEric Joyner (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | 260261ae650dSJack F Vogel (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 260361ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(i), reg); 260461ae650dSJack F Vogel } 260561ae650dSJack F Vogel } 260661ae650dSJack F Vogel 260761ae650dSJack F Vogel /* 260861ae650dSJack F Vogel * Configure for MSI single vector operation 260961ae650dSJack F Vogel */ 261061ae650dSJack F Vogel static void 261161ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf) 261261ae650dSJack F Vogel { 261361ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 261461ae650dSJack F Vogel u32 reg; 261561ae650dSJack F Vogel 261661ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(0), 0); 261761ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(1), 0); 261861ae650dSJack F Vogel 261961ae650dSJack F Vogel /* Setup "other" causes */ 262061ae650dSJack F Vogel reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK 262161ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK 262261ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_GRST_MASK 262361ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK 262461ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_GPIO_MASK 262561ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK 262661ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK 262761ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK 262861ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_VFLR_MASK 262961ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_ADMINQ_MASK 263061ae650dSJack F Vogel ; 263161ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 263261ae650dSJack F Vogel 263361ae650dSJack F Vogel /* SW_ITR_IDX = 0, but don't change INTENA */ 263461ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, 263561ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK | 263661ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK); 263761ae650dSJack F Vogel /* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */ 263861ae650dSJack F Vogel wr32(hw, I40E_PFINT_STAT_CTL0, 0); 263961ae650dSJack F Vogel 264061ae650dSJack F Vogel /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ 264161ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLST0, 0); 264261ae650dSJack F Vogel 264361ae650dSJack F Vogel /* Associate the queue pair to the vector and enable the q int */ 264461ae650dSJack F Vogel reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK 264561ae650dSJack F Vogel | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) 264661ae650dSJack F Vogel | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 264761ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(0), reg); 264861ae650dSJack F Vogel 264961ae650dSJack F Vogel reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK 265061ae650dSJack F Vogel | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) 265161ae650dSJack F Vogel | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 265261ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(0), reg); 265361ae650dSJack F Vogel } 265461ae650dSJack F Vogel 265561ae650dSJack F Vogel 265661ae650dSJack F Vogel /* 26576d011ad5SEric Joyner * Get initial ITR values from tunable values. 265861ae650dSJack F Vogel */ 265961ae650dSJack F Vogel static void 266061ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf) 266161ae650dSJack F Vogel { 266261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 266361ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 266461ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 266561ae650dSJack F Vogel 266661ae650dSJack F Vogel vsi->rx_itr_setting = ixl_rx_itr; 266761ae650dSJack F Vogel vsi->tx_itr_setting = ixl_tx_itr; 266861ae650dSJack F Vogel 266961ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 267061ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 267161ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 267261ae650dSJack F Vogel 267361ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i), 267461ae650dSJack F Vogel vsi->rx_itr_setting); 267561ae650dSJack F Vogel rxr->itr = vsi->rx_itr_setting; 267661ae650dSJack F Vogel rxr->latency = IXL_AVE_LATENCY; 26776d011ad5SEric Joyner 267861ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i), 267961ae650dSJack F Vogel vsi->tx_itr_setting); 268061ae650dSJack F Vogel txr->itr = vsi->tx_itr_setting; 268161ae650dSJack F Vogel txr->latency = IXL_AVE_LATENCY; 268261ae650dSJack F Vogel } 268361ae650dSJack F Vogel } 268461ae650dSJack F Vogel 268561ae650dSJack F Vogel 268661ae650dSJack F Vogel static int 268761ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf) 268861ae650dSJack F Vogel { 268961ae650dSJack F Vogel int rid; 269061ae650dSJack F Vogel device_t dev = pf->dev; 269161ae650dSJack F Vogel 269261ae650dSJack F Vogel rid = PCIR_BAR(0); 269361ae650dSJack F Vogel pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 269461ae650dSJack F Vogel &rid, RF_ACTIVE); 269561ae650dSJack F Vogel 269661ae650dSJack F Vogel if (!(pf->pci_mem)) { 26971d767a8eSEric Joyner device_printf(dev, "Unable to allocate bus resource: PCI memory\n"); 269861ae650dSJack F Vogel return (ENXIO); 269961ae650dSJack F Vogel } 270061ae650dSJack F Vogel 270161ae650dSJack F Vogel pf->osdep.mem_bus_space_tag = 270261ae650dSJack F Vogel rman_get_bustag(pf->pci_mem); 270361ae650dSJack F Vogel pf->osdep.mem_bus_space_handle = 270461ae650dSJack F Vogel rman_get_bushandle(pf->pci_mem); 270561ae650dSJack F Vogel pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); 2706cf3c0c32SRyan Stone pf->osdep.flush_reg = I40E_GLGEN_STAT; 270761ae650dSJack F Vogel pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; 270861ae650dSJack F Vogel 270961ae650dSJack F Vogel pf->hw.back = &pf->osdep; 271061ae650dSJack F Vogel 271161ae650dSJack F Vogel /* 271261ae650dSJack F Vogel ** Now setup MSI or MSI/X, should 271361ae650dSJack F Vogel ** return us the number of supported 271461ae650dSJack F Vogel ** vectors. (Will be 1 for MSI) 271561ae650dSJack F Vogel */ 271661ae650dSJack F Vogel pf->msix = ixl_init_msix(pf); 271761ae650dSJack F Vogel return (0); 271861ae650dSJack F Vogel } 271961ae650dSJack F Vogel 27206c426059SEric Joyner /* 27216c426059SEric Joyner * Teardown and release the admin queue/misc vector 27226c426059SEric Joyner * interrupt. 27236c426059SEric Joyner */ 27246c426059SEric Joyner static int 27256c426059SEric Joyner ixl_teardown_adminq_msix(struct ixl_pf *pf) 272661ae650dSJack F Vogel { 272761ae650dSJack F Vogel device_t dev = pf->dev; 2728223d846dSEric Joyner int rid; 272961ae650dSJack F Vogel 27306c426059SEric Joyner if (pf->admvec) /* we are doing MSIX */ 27316c426059SEric Joyner rid = pf->admvec + 1; 27326c426059SEric Joyner else 27336c426059SEric Joyner (pf->msix != 0) ? (rid = 1):(rid = 0); 27346c426059SEric Joyner 27356c426059SEric Joyner // TODO: Check for errors from bus_teardown_intr 27366c426059SEric Joyner // TODO: Check for errors from bus_release_resource 27376c426059SEric Joyner if (pf->tag != NULL) { 27386c426059SEric Joyner bus_teardown_intr(dev, pf->res, pf->tag); 27396c426059SEric Joyner pf->tag = NULL; 27406c426059SEric Joyner } 27416c426059SEric Joyner if (pf->res != NULL) { 27426c426059SEric Joyner bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); 27436c426059SEric Joyner pf->res = NULL; 27446c426059SEric Joyner } 27456c426059SEric Joyner 27466c426059SEric Joyner return (0); 27476c426059SEric Joyner } 27486c426059SEric Joyner 27496c426059SEric Joyner static int 27506c426059SEric Joyner ixl_teardown_queue_msix(struct ixl_vsi *vsi) 27516c426059SEric Joyner { 27526c426059SEric Joyner struct ixl_queue *que = vsi->queues; 27536c426059SEric Joyner device_t dev = vsi->dev; 27546d011ad5SEric Joyner int rid, error = 0; 27556c426059SEric Joyner 275661ae650dSJack F Vogel /* We may get here before stations are setup */ 275761ae650dSJack F Vogel if ((!ixl_enable_msix) || (que == NULL)) 27586c426059SEric Joyner return (0); 275961ae650dSJack F Vogel 27606c426059SEric Joyner /* Release all MSIX queue resources */ 276161ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 276261ae650dSJack F Vogel rid = que->msix + 1; 276361ae650dSJack F Vogel if (que->tag != NULL) { 27646d011ad5SEric Joyner error = bus_teardown_intr(dev, que->res, que->tag); 27656d011ad5SEric Joyner if (error) { 27666d011ad5SEric Joyner device_printf(dev, "bus_teardown_intr() for" 27676d011ad5SEric Joyner " Queue %d interrupt failed\n", 27686d011ad5SEric Joyner que->me); 27696d011ad5SEric Joyner // return (ENXIO); 27706d011ad5SEric Joyner } 277161ae650dSJack F Vogel que->tag = NULL; 277261ae650dSJack F Vogel } 2773223d846dSEric Joyner if (que->res != NULL) { 27746d011ad5SEric Joyner error = bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 27756d011ad5SEric Joyner if (error) { 27766d011ad5SEric Joyner device_printf(dev, "bus_release_resource() for" 27776d011ad5SEric Joyner " Queue %d interrupt failed [rid=%d]\n", 27786d011ad5SEric Joyner que->me, rid); 27796d011ad5SEric Joyner // return (ENXIO); 27806d011ad5SEric Joyner } 2781223d846dSEric Joyner que->res = NULL; 2782223d846dSEric Joyner } 278361ae650dSJack F Vogel } 278461ae650dSJack F Vogel 27856c426059SEric Joyner return (0); 2786223d846dSEric Joyner } 2787223d846dSEric Joyner 2788223d846dSEric Joyner static void 2789223d846dSEric Joyner ixl_free_pci_resources(struct ixl_pf *pf) 2790223d846dSEric Joyner { 2791223d846dSEric Joyner device_t dev = pf->dev; 2792223d846dSEric Joyner int memrid; 2793223d846dSEric Joyner 27946c426059SEric Joyner ixl_teardown_queue_msix(&pf->vsi); 27956c426059SEric Joyner ixl_teardown_adminq_msix(pf); 279661ae650dSJack F Vogel 279761ae650dSJack F Vogel if (pf->msix) 279861ae650dSJack F Vogel pci_release_msi(dev); 279961ae650dSJack F Vogel 2800223d846dSEric Joyner memrid = PCIR_BAR(IXL_BAR); 2801223d846dSEric Joyner 280261ae650dSJack F Vogel if (pf->msix_mem != NULL) 280361ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 280461ae650dSJack F Vogel memrid, pf->msix_mem); 280561ae650dSJack F Vogel 280661ae650dSJack F Vogel if (pf->pci_mem != NULL) 280761ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 280861ae650dSJack F Vogel PCIR_BAR(0), pf->pci_mem); 280961ae650dSJack F Vogel 281061ae650dSJack F Vogel return; 281161ae650dSJack F Vogel } 281261ae650dSJack F Vogel 2813e5100ee2SJack F Vogel static void 2814e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type) 2815e5100ee2SJack F Vogel { 2816e5100ee2SJack F Vogel /* Display supported media types */ 2817e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX)) 2818e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2819e5100ee2SJack F Vogel 2820e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T)) 2821e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); 282256c2c47bSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_SX)) 282356c2c47bSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 282456c2c47bSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_LX)) 282556c2c47bSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL); 2826e5100ee2SJack F Vogel 2827be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_XAUI) || 2828b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XFI) || 2829e5100ee2SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU)) 2830e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2831b6c8f260SJack F Vogel 2832e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR)) 2833e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2834e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR)) 2835e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2836e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T)) 2837e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2838e5100ee2SJack F Vogel 2839b6c8f260SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) || 2840b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) || 2841b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) || 2842b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XLAUI) || 2843b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2844e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2845e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4)) 2846e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2847e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4)) 2848e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); 2849be771cdaSJack F Vogel 2850be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE 2851be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX)) 2852be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_CX, 0, NULL); 2853be771cdaSJack F Vogel 2854be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) || 2855be771cdaSJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1) || 2856be771cdaSJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) || 2857be771cdaSJack F Vogel phy_type & (1 << I40E_PHY_TYPE_SFI)) 2858be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2859be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4)) 2860be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2861be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR)) 2862be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2863be771cdaSJack F Vogel 2864be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2865be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2866be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_XLPPI)) 2867be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2868be771cdaSJack F Vogel #else 2869be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX)) 2870be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL); 2871be771cdaSJack F Vogel 2872be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) 2873be771cdaSJack F Vogel || phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1)) 2874be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL); 2875be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC)) 2876be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL); 2877be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_SFI)) 2878be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL); 2879be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4)) 2880be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); 2881be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR)) 2882be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL); 2883be771cdaSJack F Vogel 2884be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_20GBASE_KR2)) 2885be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL); 2886be771cdaSJack F Vogel 2887be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2888be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL); 2889be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_XLPPI)) 2890be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL); 2891be771cdaSJack F Vogel #endif 2892e5100ee2SJack F Vogel } 289361ae650dSJack F Vogel 289461ae650dSJack F Vogel /********************************************************************* 289561ae650dSJack F Vogel * 289661ae650dSJack F Vogel * Setup networking device structure and register an interface. 289761ae650dSJack F Vogel * 289861ae650dSJack F Vogel **********************************************************************/ 289961ae650dSJack F Vogel static int 290061ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi) 290161ae650dSJack F Vogel { 290261ae650dSJack F Vogel struct ifnet *ifp; 290361ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 290461ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 2905b6c8f260SJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 290661ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 290761ae650dSJack F Vogel 290861ae650dSJack F Vogel INIT_DEBUGOUT("ixl_setup_interface: begin"); 290961ae650dSJack F Vogel 291061ae650dSJack F Vogel ifp = vsi->ifp = if_alloc(IFT_ETHER); 291161ae650dSJack F Vogel if (ifp == NULL) { 291261ae650dSJack F Vogel device_printf(dev, "can not allocate ifnet structure\n"); 291361ae650dSJack F Vogel return (-1); 291461ae650dSJack F Vogel } 291561ae650dSJack F Vogel if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 291661ae650dSJack F Vogel ifp->if_mtu = ETHERMTU; 2917a48d00d2SEric Joyner ifp->if_baudrate = IF_Gbps(40); 291861ae650dSJack F Vogel ifp->if_init = ixl_init; 291961ae650dSJack F Vogel ifp->if_softc = vsi; 292061ae650dSJack F Vogel ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 292161ae650dSJack F Vogel ifp->if_ioctl = ixl_ioctl; 292261ae650dSJack F Vogel 2923e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036 29244b443922SGleb Smirnoff if_setgetcounterfn(ifp, ixl_get_counter); 29254b443922SGleb Smirnoff #endif 29264b443922SGleb Smirnoff 292761ae650dSJack F Vogel ifp->if_transmit = ixl_mq_start; 292861ae650dSJack F Vogel 292961ae650dSJack F Vogel ifp->if_qflush = ixl_qflush; 293061ae650dSJack F Vogel 293161ae650dSJack F Vogel ifp->if_snd.ifq_maxlen = que->num_desc - 2; 293261ae650dSJack F Vogel 293361ae650dSJack F Vogel vsi->max_frame_size = 293461ae650dSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 293561ae650dSJack F Vogel + ETHER_VLAN_ENCAP_LEN; 293661ae650dSJack F Vogel 293761ae650dSJack F Vogel /* 293861ae650dSJack F Vogel * Tell the upper layer(s) we support long frames. 293961ae650dSJack F Vogel */ 29401bffa951SGleb Smirnoff ifp->if_hdrlen = sizeof(struct ether_vlan_header); 294161ae650dSJack F Vogel 294261ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM; 294361ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; 294461ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_TSO; 294561ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_JUMBO_MTU; 294661ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_LRO; 294761ae650dSJack F Vogel 294861ae650dSJack F Vogel /* VLAN capabilties */ 294961ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 295061ae650dSJack F Vogel | IFCAP_VLAN_HWTSO 295161ae650dSJack F Vogel | IFCAP_VLAN_MTU 295261ae650dSJack F Vogel | IFCAP_VLAN_HWCSUM; 295361ae650dSJack F Vogel ifp->if_capenable = ifp->if_capabilities; 295461ae650dSJack F Vogel 295561ae650dSJack F Vogel /* 295661ae650dSJack F Vogel ** Don't turn this on by default, if vlans are 295761ae650dSJack F Vogel ** created on another pseudo device (eg. lagg) 295861ae650dSJack F Vogel ** then vlan events are not passed thru, breaking 295961ae650dSJack F Vogel ** operation, but with HW FILTER off it works. If 296061ae650dSJack F Vogel ** using vlans directly on the ixl driver you can 296161ae650dSJack F Vogel ** enable this and get full hardware tag filtering. 296261ae650dSJack F Vogel */ 296361ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 296461ae650dSJack F Vogel 296561ae650dSJack F Vogel /* 296661ae650dSJack F Vogel * Specify the media types supported by this adapter and register 296761ae650dSJack F Vogel * callbacks to update media and link information 296861ae650dSJack F Vogel */ 296961ae650dSJack F Vogel ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change, 297061ae650dSJack F Vogel ixl_media_status); 297161ae650dSJack F Vogel 2972b6c8f260SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 2973b6c8f260SJack F Vogel FALSE, TRUE, &abilities, NULL); 2974b6c8f260SJack F Vogel /* May need delay to detect fiber correctly */ 2975e5100ee2SJack F Vogel if (aq_error == I40E_ERR_UNKNOWN_PHY) { 2976e5100ee2SJack F Vogel i40e_msec_delay(200); 2977393c4bb1SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, 2978b6c8f260SJack F Vogel TRUE, &abilities, NULL); 2979b6c8f260SJack F Vogel } 2980b6c8f260SJack F Vogel if (aq_error) { 2981e5100ee2SJack F Vogel if (aq_error == I40E_ERR_UNKNOWN_PHY) 2982e5100ee2SJack F Vogel device_printf(dev, "Unknown PHY type detected!\n"); 2983e5100ee2SJack F Vogel else 2984b6c8f260SJack F Vogel device_printf(dev, 2985b6c8f260SJack F Vogel "Error getting supported media types, err %d," 2986e5100ee2SJack F Vogel " AQ error %d\n", aq_error, hw->aq.asq_last_status); 2987b6c8f260SJack F Vogel return (0); 2988b6c8f260SJack F Vogel } 2989b6c8f260SJack F Vogel 2990b6c8f260SJack F Vogel ixl_add_ifmedia(vsi, abilities.phy_type); 299161ae650dSJack F Vogel 299261ae650dSJack F Vogel /* Use autoselect media by default */ 299361ae650dSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); 299461ae650dSJack F Vogel ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); 299561ae650dSJack F Vogel 2996e5100ee2SJack F Vogel ether_ifattach(ifp, hw->mac.addr); 2997e5100ee2SJack F Vogel 299861ae650dSJack F Vogel return (0); 299961ae650dSJack F Vogel } 300061ae650dSJack F Vogel 300156c2c47bSJack F Vogel /* 3002223d846dSEric Joyner ** Run when the Admin Queue gets a link state change interrupt. 300356c2c47bSJack F Vogel */ 300456c2c47bSJack F Vogel static void 300556c2c47bSJack F Vogel ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e) 300661ae650dSJack F Vogel { 300756c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 3008223d846dSEric Joyner device_t dev = pf->dev; 300956c2c47bSJack F Vogel struct i40e_aqc_get_link_status *status = 301056c2c47bSJack F Vogel (struct i40e_aqc_get_link_status *)&e->desc.params.raw; 301161ae650dSJack F Vogel 3012223d846dSEric Joyner /* Request link status from adapter */ 301356c2c47bSJack F Vogel hw->phy.get_link_info = TRUE; 3014223d846dSEric Joyner i40e_get_link_status(hw, &pf->link_up); 3015223d846dSEric Joyner 3016223d846dSEric Joyner /* Print out message if an unqualified module is found */ 301756c2c47bSJack F Vogel if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) && 301856c2c47bSJack F Vogel (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) && 301956c2c47bSJack F Vogel (!(status->link_info & I40E_AQ_LINK_UP))) 3020223d846dSEric Joyner device_printf(dev, "Link failed because " 3021223d846dSEric Joyner "an unqualified module was detected!\n"); 302256c2c47bSJack F Vogel 3023223d846dSEric Joyner /* Update OS link info */ 3024223d846dSEric Joyner ixl_update_link_status(pf); 302561ae650dSJack F Vogel } 302661ae650dSJack F Vogel 302761ae650dSJack F Vogel /********************************************************************* 302861ae650dSJack F Vogel * 3029b6c8f260SJack F Vogel * Get Firmware Switch configuration 3030b6c8f260SJack F Vogel * - this will need to be more robust when more complex 3031b6c8f260SJack F Vogel * switch configurations are enabled. 303261ae650dSJack F Vogel * 303361ae650dSJack F Vogel **********************************************************************/ 303461ae650dSJack F Vogel static int 3035b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf) 303661ae650dSJack F Vogel { 3037b6c8f260SJack F Vogel struct i40e_hw *hw = &pf->hw; 3038b6c8f260SJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 303961ae650dSJack F Vogel device_t dev = vsi->dev; 304061ae650dSJack F Vogel struct i40e_aqc_get_switch_config_resp *sw_config; 304161ae650dSJack F Vogel u8 aq_buf[I40E_AQ_LARGE_BUF]; 304256c2c47bSJack F Vogel int ret; 304361ae650dSJack F Vogel u16 next = 0; 304461ae650dSJack F Vogel 3045b6c8f260SJack F Vogel memset(&aq_buf, 0, sizeof(aq_buf)); 304661ae650dSJack F Vogel sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 304761ae650dSJack F Vogel ret = i40e_aq_get_switch_config(hw, sw_config, 304861ae650dSJack F Vogel sizeof(aq_buf), &next, NULL); 304961ae650dSJack F Vogel if (ret) { 30506d011ad5SEric Joyner device_printf(dev, "aq_get_switch_config() failed, error %d," 30516d011ad5SEric Joyner " aq_error %d\n", ret, pf->hw.aq.asq_last_status); 305261ae650dSJack F Vogel return (ret); 305361ae650dSJack F Vogel } 305461ae650dSJack F Vogel #ifdef IXL_DEBUG 305556c2c47bSJack F Vogel device_printf(dev, 305656c2c47bSJack F Vogel "Switch config: header reported: %d in structure, %d total\n", 305761ae650dSJack F Vogel sw_config->header.num_reported, sw_config->header.num_total); 305856c2c47bSJack F Vogel for (int i = 0; i < sw_config->header.num_reported; i++) { 305956c2c47bSJack F Vogel device_printf(dev, 306056c2c47bSJack F Vogel "%d: type=%d seid=%d uplink=%d downlink=%d\n", i, 306156c2c47bSJack F Vogel sw_config->element[i].element_type, 306256c2c47bSJack F Vogel sw_config->element[i].seid, 306356c2c47bSJack F Vogel sw_config->element[i].uplink_seid, 306456c2c47bSJack F Vogel sw_config->element[i].downlink_seid); 306556c2c47bSJack F Vogel } 306661ae650dSJack F Vogel #endif 3067b6c8f260SJack F Vogel /* Simplified due to a single VSI at the moment */ 306856c2c47bSJack F Vogel vsi->uplink_seid = sw_config->element[0].uplink_seid; 306956c2c47bSJack F Vogel vsi->downlink_seid = sw_config->element[0].downlink_seid; 307061ae650dSJack F Vogel vsi->seid = sw_config->element[0].seid; 3071b6c8f260SJack F Vogel return (ret); 3072b6c8f260SJack F Vogel } 3073b6c8f260SJack F Vogel 3074b6c8f260SJack F Vogel /********************************************************************* 3075b6c8f260SJack F Vogel * 3076b6c8f260SJack F Vogel * Initialize the VSI: this handles contexts, which means things 3077b6c8f260SJack F Vogel * like the number of descriptors, buffer size, 3078b6c8f260SJack F Vogel * plus we init the rings thru this function. 3079b6c8f260SJack F Vogel * 3080b6c8f260SJack F Vogel **********************************************************************/ 3081b6c8f260SJack F Vogel static int 3082b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi) 3083b6c8f260SJack F Vogel { 308456c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 3085b6c8f260SJack F Vogel struct ixl_queue *que = vsi->queues; 3086b6c8f260SJack F Vogel device_t dev = vsi->dev; 3087b6c8f260SJack F Vogel struct i40e_hw *hw = vsi->hw; 3088b6c8f260SJack F Vogel struct i40e_vsi_context ctxt; 3089b6c8f260SJack F Vogel int err = 0; 309061ae650dSJack F Vogel 309161ae650dSJack F Vogel memset(&ctxt, 0, sizeof(ctxt)); 309261ae650dSJack F Vogel ctxt.seid = vsi->seid; 309356c2c47bSJack F Vogel if (pf->veb_seid != 0) 309456c2c47bSJack F Vogel ctxt.uplink_seid = pf->veb_seid; 309561ae650dSJack F Vogel ctxt.pf_num = hw->pf_id; 3096b6c8f260SJack F Vogel err = i40e_aq_get_vsi_params(hw, &ctxt, NULL); 3097b6c8f260SJack F Vogel if (err) { 30986d011ad5SEric Joyner device_printf(dev, "i40e_aq_get_vsi_params() failed, error %d" 30996d011ad5SEric Joyner " aq_error %d\n", err, hw->aq.asq_last_status); 3100b6c8f260SJack F Vogel return (err); 310161ae650dSJack F Vogel } 310261ae650dSJack F Vogel #ifdef IXL_DEBUG 31037f70bec6SEric Joyner device_printf(dev, "get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, " 310461ae650dSJack F Vogel "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, " 310561ae650dSJack F Vogel "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid, 310661ae650dSJack F Vogel ctxt.uplink_seid, ctxt.vsi_number, 310761ae650dSJack F Vogel ctxt.vsis_allocated, ctxt.vsis_unallocated, 310861ae650dSJack F Vogel ctxt.flags, ctxt.pf_num, ctxt.vf_num, 310961ae650dSJack F Vogel ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits); 311061ae650dSJack F Vogel #endif 311161ae650dSJack F Vogel /* 311261ae650dSJack F Vogel ** Set the queue and traffic class bits 311361ae650dSJack F Vogel ** - when multiple traffic classes are supported 311461ae650dSJack F Vogel ** this will need to be more robust. 311561ae650dSJack F Vogel */ 311661ae650dSJack F Vogel ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID; 311761ae650dSJack F Vogel ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG; 311861ae650dSJack F Vogel ctxt.info.queue_mapping[0] = 0; 31191d767a8eSEric Joyner /* This VSI is assigned 64 queues (we may not use all of them) */ 31207f70bec6SEric Joyner ctxt.info.tc_mapping[0] = 0x0c00; 312161ae650dSJack F Vogel 312261ae650dSJack F Vogel /* Set VLAN receive stripping mode */ 312361ae650dSJack F Vogel ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; 312461ae650dSJack F Vogel ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; 312561ae650dSJack F Vogel if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 312661ae650dSJack F Vogel ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 312761ae650dSJack F Vogel else 312861ae650dSJack F Vogel ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 312961ae650dSJack F Vogel 313061ae650dSJack F Vogel /* Keep copy of VSI info in VSI for statistic counters */ 313161ae650dSJack F Vogel memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); 313261ae650dSJack F Vogel 313361ae650dSJack F Vogel /* Reset VSI statistics */ 313461ae650dSJack F Vogel ixl_vsi_reset_stats(vsi); 313561ae650dSJack F Vogel vsi->hw_filters_add = 0; 313661ae650dSJack F Vogel vsi->hw_filters_del = 0; 313761ae650dSJack F Vogel 313856c2c47bSJack F Vogel ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF); 313956c2c47bSJack F Vogel 3140b6c8f260SJack F Vogel err = i40e_aq_update_vsi_params(hw, &ctxt, NULL); 3141b6c8f260SJack F Vogel if (err) { 31427f70bec6SEric Joyner device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d, aq_error %d\n", 31437f70bec6SEric Joyner err, hw->aq.asq_last_status); 3144b6c8f260SJack F Vogel return (err); 314561ae650dSJack F Vogel } 314661ae650dSJack F Vogel 314761ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 314861ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 314961ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 315061ae650dSJack F Vogel struct i40e_hmc_obj_txq tctx; 315161ae650dSJack F Vogel struct i40e_hmc_obj_rxq rctx; 315261ae650dSJack F Vogel u32 txctl; 315361ae650dSJack F Vogel u16 size; 315461ae650dSJack F Vogel 315561ae650dSJack F Vogel /* Setup the HMC TX Context */ 315661ae650dSJack F Vogel size = que->num_desc * sizeof(struct i40e_tx_desc); 315761ae650dSJack F Vogel memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq)); 315861ae650dSJack F Vogel tctx.new_context = 1; 315956c2c47bSJack F Vogel tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS); 316061ae650dSJack F Vogel tctx.qlen = que->num_desc; 316161ae650dSJack F Vogel tctx.fc_ena = 0; 316261ae650dSJack F Vogel tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */ 316361ae650dSJack F Vogel /* Enable HEAD writeback */ 316461ae650dSJack F Vogel tctx.head_wb_ena = 1; 316561ae650dSJack F Vogel tctx.head_wb_addr = txr->dma.pa + 316661ae650dSJack F Vogel (que->num_desc * sizeof(struct i40e_tx_desc)); 316761ae650dSJack F Vogel tctx.rdylist_act = 0; 316861ae650dSJack F Vogel err = i40e_clear_lan_tx_queue_context(hw, i); 316961ae650dSJack F Vogel if (err) { 317061ae650dSJack F Vogel device_printf(dev, "Unable to clear TX context\n"); 317161ae650dSJack F Vogel break; 317261ae650dSJack F Vogel } 317361ae650dSJack F Vogel err = i40e_set_lan_tx_queue_context(hw, i, &tctx); 317461ae650dSJack F Vogel if (err) { 317561ae650dSJack F Vogel device_printf(dev, "Unable to set TX context\n"); 317661ae650dSJack F Vogel break; 317761ae650dSJack F Vogel } 317861ae650dSJack F Vogel /* Associate the ring with this PF */ 317961ae650dSJack F Vogel txctl = I40E_QTX_CTL_PF_QUEUE; 318061ae650dSJack F Vogel txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & 318161ae650dSJack F Vogel I40E_QTX_CTL_PF_INDX_MASK); 318261ae650dSJack F Vogel wr32(hw, I40E_QTX_CTL(i), txctl); 318361ae650dSJack F Vogel ixl_flush(hw); 318461ae650dSJack F Vogel 318561ae650dSJack F Vogel /* Do ring (re)init */ 318661ae650dSJack F Vogel ixl_init_tx_ring(que); 318761ae650dSJack F Vogel 318861ae650dSJack F Vogel /* Next setup the HMC RX Context */ 318956c2c47bSJack F Vogel if (vsi->max_frame_size <= MCLBYTES) 319061ae650dSJack F Vogel rxr->mbuf_sz = MCLBYTES; 319161ae650dSJack F Vogel else 319261ae650dSJack F Vogel rxr->mbuf_sz = MJUMPAGESIZE; 319361ae650dSJack F Vogel 319461ae650dSJack F Vogel u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len; 319561ae650dSJack F Vogel 319661ae650dSJack F Vogel /* Set up an RX context for the HMC */ 319761ae650dSJack F Vogel memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq)); 319861ae650dSJack F Vogel rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT; 319961ae650dSJack F Vogel /* ignore header split for now */ 320061ae650dSJack F Vogel rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; 320161ae650dSJack F Vogel rctx.rxmax = (vsi->max_frame_size < max_rxmax) ? 320261ae650dSJack F Vogel vsi->max_frame_size : max_rxmax; 320361ae650dSJack F Vogel rctx.dtype = 0; 320461ae650dSJack F Vogel rctx.dsize = 1; /* do 32byte descriptors */ 320561ae650dSJack F Vogel rctx.hsplit_0 = 0; /* no HDR split initially */ 320656c2c47bSJack F Vogel rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS); 320761ae650dSJack F Vogel rctx.qlen = que->num_desc; 320861ae650dSJack F Vogel rctx.tphrdesc_ena = 1; 320961ae650dSJack F Vogel rctx.tphwdesc_ena = 1; 321061ae650dSJack F Vogel rctx.tphdata_ena = 0; 321161ae650dSJack F Vogel rctx.tphhead_ena = 0; 321261ae650dSJack F Vogel rctx.lrxqthresh = 2; 321361ae650dSJack F Vogel rctx.crcstrip = 1; 321461ae650dSJack F Vogel rctx.l2tsel = 1; 321561ae650dSJack F Vogel rctx.showiv = 1; 321661ae650dSJack F Vogel rctx.fc_ena = 0; 321761ae650dSJack F Vogel rctx.prefena = 1; 321861ae650dSJack F Vogel 321961ae650dSJack F Vogel err = i40e_clear_lan_rx_queue_context(hw, i); 322061ae650dSJack F Vogel if (err) { 322161ae650dSJack F Vogel device_printf(dev, 322261ae650dSJack F Vogel "Unable to clear RX context %d\n", i); 322361ae650dSJack F Vogel break; 322461ae650dSJack F Vogel } 322561ae650dSJack F Vogel err = i40e_set_lan_rx_queue_context(hw, i, &rctx); 322661ae650dSJack F Vogel if (err) { 322761ae650dSJack F Vogel device_printf(dev, "Unable to set RX context %d\n", i); 322861ae650dSJack F Vogel break; 322961ae650dSJack F Vogel } 323061ae650dSJack F Vogel err = ixl_init_rx_ring(que); 323161ae650dSJack F Vogel if (err) { 323261ae650dSJack F Vogel device_printf(dev, "Fail in init_rx_ring %d\n", i); 323361ae650dSJack F Vogel break; 323461ae650dSJack F Vogel } 323531830672SJack F Vogel #ifdef DEV_NETMAP 323631830672SJack F Vogel /* preserve queue */ 323731830672SJack F Vogel if (vsi->ifp->if_capenable & IFCAP_NETMAP) { 323831830672SJack F Vogel struct netmap_adapter *na = NA(vsi->ifp); 323931830672SJack F Vogel struct netmap_kring *kring = &na->rx_rings[i]; 324031830672SJack F Vogel int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); 324131830672SJack F Vogel wr32(vsi->hw, I40E_QRX_TAIL(que->me), t); 324231830672SJack F Vogel } else 324331830672SJack F Vogel #endif /* DEV_NETMAP */ 324461ae650dSJack F Vogel wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1); 324561ae650dSJack F Vogel } 324661ae650dSJack F Vogel return (err); 324761ae650dSJack F Vogel } 324861ae650dSJack F Vogel 324961ae650dSJack F Vogel 325061ae650dSJack F Vogel /********************************************************************* 325161ae650dSJack F Vogel * 325261ae650dSJack F Vogel * Free all VSI structs. 325361ae650dSJack F Vogel * 325461ae650dSJack F Vogel **********************************************************************/ 325561ae650dSJack F Vogel void 325661ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi) 325761ae650dSJack F Vogel { 325861ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 325961ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 326061ae650dSJack F Vogel 326161ae650dSJack F Vogel /* Free station queues */ 3262fdb6f38aSEric Joyner if (!vsi->queues) 3263fdb6f38aSEric Joyner goto free_filters; 3264fdb6f38aSEric Joyner 326561ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 326661ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 326761ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 326861ae650dSJack F Vogel 326961ae650dSJack F Vogel if (!mtx_initialized(&txr->mtx)) /* uninitialized */ 327061ae650dSJack F Vogel continue; 327161ae650dSJack F Vogel IXL_TX_LOCK(txr); 327261ae650dSJack F Vogel ixl_free_que_tx(que); 327361ae650dSJack F Vogel if (txr->base) 3274d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &txr->dma); 327561ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 327661ae650dSJack F Vogel IXL_TX_LOCK_DESTROY(txr); 327761ae650dSJack F Vogel 327861ae650dSJack F Vogel if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ 327961ae650dSJack F Vogel continue; 328061ae650dSJack F Vogel IXL_RX_LOCK(rxr); 328161ae650dSJack F Vogel ixl_free_que_rx(que); 328261ae650dSJack F Vogel if (rxr->base) 3283d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &rxr->dma); 328461ae650dSJack F Vogel IXL_RX_UNLOCK(rxr); 328561ae650dSJack F Vogel IXL_RX_LOCK_DESTROY(rxr); 328661ae650dSJack F Vogel 328761ae650dSJack F Vogel } 328861ae650dSJack F Vogel free(vsi->queues, M_DEVBUF); 328961ae650dSJack F Vogel 3290fdb6f38aSEric Joyner free_filters: 329161ae650dSJack F Vogel /* Free VSI filter list */ 329256c2c47bSJack F Vogel ixl_free_mac_filters(vsi); 329356c2c47bSJack F Vogel } 329456c2c47bSJack F Vogel 329556c2c47bSJack F Vogel static void 329656c2c47bSJack F Vogel ixl_free_mac_filters(struct ixl_vsi *vsi) 329756c2c47bSJack F Vogel { 329856c2c47bSJack F Vogel struct ixl_mac_filter *f; 329956c2c47bSJack F Vogel 330061ae650dSJack F Vogel while (!SLIST_EMPTY(&vsi->ftl)) { 330161ae650dSJack F Vogel f = SLIST_FIRST(&vsi->ftl); 330261ae650dSJack F Vogel SLIST_REMOVE_HEAD(&vsi->ftl, next); 330361ae650dSJack F Vogel free(f, M_DEVBUF); 330461ae650dSJack F Vogel } 330561ae650dSJack F Vogel } 330661ae650dSJack F Vogel 330761ae650dSJack F Vogel 330861ae650dSJack F Vogel /********************************************************************* 330961ae650dSJack F Vogel * 331061ae650dSJack F Vogel * Allocate memory for the VSI (virtual station interface) and their 331161ae650dSJack F Vogel * associated queues, rings and the descriptors associated with each, 331261ae650dSJack F Vogel * called only once at attach. 331361ae650dSJack F Vogel * 331461ae650dSJack F Vogel **********************************************************************/ 331561ae650dSJack F Vogel static int 331661ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf) 331761ae650dSJack F Vogel { 331861ae650dSJack F Vogel device_t dev = pf->dev; 331961ae650dSJack F Vogel struct ixl_vsi *vsi; 332061ae650dSJack F Vogel struct ixl_queue *que; 332161ae650dSJack F Vogel struct tx_ring *txr; 332261ae650dSJack F Vogel struct rx_ring *rxr; 332361ae650dSJack F Vogel int rsize, tsize; 332461ae650dSJack F Vogel int error = I40E_SUCCESS; 332561ae650dSJack F Vogel 332661ae650dSJack F Vogel vsi = &pf->vsi; 332761ae650dSJack F Vogel vsi->back = (void *)pf; 332861ae650dSJack F Vogel vsi->hw = &pf->hw; 332961ae650dSJack F Vogel vsi->id = 0; 333061ae650dSJack F Vogel vsi->num_vlans = 0; 333156c2c47bSJack F Vogel vsi->back = pf; 333261ae650dSJack F Vogel 333361ae650dSJack F Vogel /* Get memory for the station queues */ 333461ae650dSJack F Vogel if (!(vsi->queues = 333561ae650dSJack F Vogel (struct ixl_queue *) malloc(sizeof(struct ixl_queue) * 333661ae650dSJack F Vogel vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { 333761ae650dSJack F Vogel device_printf(dev, "Unable to allocate queue memory\n"); 333861ae650dSJack F Vogel error = ENOMEM; 333961ae650dSJack F Vogel goto early; 334061ae650dSJack F Vogel } 334161ae650dSJack F Vogel 334261ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 334361ae650dSJack F Vogel que = &vsi->queues[i]; 334461ae650dSJack F Vogel que->num_desc = ixl_ringsz; 334561ae650dSJack F Vogel que->me = i; 334661ae650dSJack F Vogel que->vsi = vsi; 334761ae650dSJack F Vogel /* mark the queue as active */ 334861ae650dSJack F Vogel vsi->active_queues |= (u64)1 << que->me; 334961ae650dSJack F Vogel txr = &que->txr; 335061ae650dSJack F Vogel txr->que = que; 335161ae650dSJack F Vogel txr->tail = I40E_QTX_TAIL(que->me); 335261ae650dSJack F Vogel 335361ae650dSJack F Vogel /* Initialize the TX lock */ 335461ae650dSJack F Vogel snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", 335561ae650dSJack F Vogel device_get_nameunit(dev), que->me); 335661ae650dSJack F Vogel mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF); 335761ae650dSJack F Vogel /* Create the TX descriptor ring */ 335861ae650dSJack F Vogel tsize = roundup2((que->num_desc * 335961ae650dSJack F Vogel sizeof(struct i40e_tx_desc)) + 336061ae650dSJack F Vogel sizeof(u32), DBA_ALIGN); 3361d94ca7cfSBjoern A. Zeeb if (i40e_allocate_dma_mem(&pf->hw, 3362d94ca7cfSBjoern A. Zeeb &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) { 336361ae650dSJack F Vogel device_printf(dev, 336461ae650dSJack F Vogel "Unable to allocate TX Descriptor memory\n"); 336561ae650dSJack F Vogel error = ENOMEM; 336661ae650dSJack F Vogel goto fail; 336761ae650dSJack F Vogel } 336861ae650dSJack F Vogel txr->base = (struct i40e_tx_desc *)txr->dma.va; 336961ae650dSJack F Vogel bzero((void *)txr->base, tsize); 337061ae650dSJack F Vogel /* Now allocate transmit soft structs for the ring */ 337161ae650dSJack F Vogel if (ixl_allocate_tx_data(que)) { 337261ae650dSJack F Vogel device_printf(dev, 337361ae650dSJack F Vogel "Critical Failure setting up TX structures\n"); 337461ae650dSJack F Vogel error = ENOMEM; 337561ae650dSJack F Vogel goto fail; 337661ae650dSJack F Vogel } 337761ae650dSJack F Vogel /* Allocate a buf ring */ 337861ae650dSJack F Vogel txr->br = buf_ring_alloc(4096, M_DEVBUF, 3379223d846dSEric Joyner M_NOWAIT, &txr->mtx); 338061ae650dSJack F Vogel if (txr->br == NULL) { 338161ae650dSJack F Vogel device_printf(dev, 338261ae650dSJack F Vogel "Critical Failure setting up TX buf ring\n"); 338361ae650dSJack F Vogel error = ENOMEM; 338461ae650dSJack F Vogel goto fail; 338561ae650dSJack F Vogel } 338661ae650dSJack F Vogel 338761ae650dSJack F Vogel /* 338861ae650dSJack F Vogel * Next the RX queues... 338961ae650dSJack F Vogel */ 339061ae650dSJack F Vogel rsize = roundup2(que->num_desc * 339161ae650dSJack F Vogel sizeof(union i40e_rx_desc), DBA_ALIGN); 339261ae650dSJack F Vogel rxr = &que->rxr; 339361ae650dSJack F Vogel rxr->que = que; 339461ae650dSJack F Vogel rxr->tail = I40E_QRX_TAIL(que->me); 339561ae650dSJack F Vogel 339661ae650dSJack F Vogel /* Initialize the RX side lock */ 339761ae650dSJack F Vogel snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", 339861ae650dSJack F Vogel device_get_nameunit(dev), que->me); 339961ae650dSJack F Vogel mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF); 340061ae650dSJack F Vogel 3401d94ca7cfSBjoern A. Zeeb if (i40e_allocate_dma_mem(&pf->hw, 3402d94ca7cfSBjoern A. Zeeb &rxr->dma, i40e_mem_reserved, rsize, 4096)) { 340361ae650dSJack F Vogel device_printf(dev, 340461ae650dSJack F Vogel "Unable to allocate RX Descriptor memory\n"); 340561ae650dSJack F Vogel error = ENOMEM; 340661ae650dSJack F Vogel goto fail; 340761ae650dSJack F Vogel } 340861ae650dSJack F Vogel rxr->base = (union i40e_rx_desc *)rxr->dma.va; 340961ae650dSJack F Vogel bzero((void *)rxr->base, rsize); 341061ae650dSJack F Vogel 341161ae650dSJack F Vogel /* Allocate receive soft structs for the ring*/ 341261ae650dSJack F Vogel if (ixl_allocate_rx_data(que)) { 341361ae650dSJack F Vogel device_printf(dev, 341461ae650dSJack F Vogel "Critical Failure setting up receive structs\n"); 341561ae650dSJack F Vogel error = ENOMEM; 341661ae650dSJack F Vogel goto fail; 341761ae650dSJack F Vogel } 341861ae650dSJack F Vogel } 341961ae650dSJack F Vogel 342061ae650dSJack F Vogel return (0); 342161ae650dSJack F Vogel 342261ae650dSJack F Vogel fail: 342361ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 342461ae650dSJack F Vogel que = &vsi->queues[i]; 342561ae650dSJack F Vogel rxr = &que->rxr; 342661ae650dSJack F Vogel txr = &que->txr; 342761ae650dSJack F Vogel if (rxr->base) 3428d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &rxr->dma); 342961ae650dSJack F Vogel if (txr->base) 3430d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &txr->dma); 343161ae650dSJack F Vogel } 343261ae650dSJack F Vogel 343361ae650dSJack F Vogel early: 343461ae650dSJack F Vogel return (error); 343561ae650dSJack F Vogel } 343661ae650dSJack F Vogel 343761ae650dSJack F Vogel /* 343861ae650dSJack F Vogel ** Provide a update to the queue RX 343961ae650dSJack F Vogel ** interrupt moderation value. 344061ae650dSJack F Vogel */ 344161ae650dSJack F Vogel static void 344261ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que) 344361ae650dSJack F Vogel { 344461ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 344561ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 344661ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 344761ae650dSJack F Vogel u16 rx_itr; 344861ae650dSJack F Vogel u16 rx_latency = 0; 344961ae650dSJack F Vogel int rx_bytes; 345061ae650dSJack F Vogel 345161ae650dSJack F Vogel /* Idle, do nothing */ 345261ae650dSJack F Vogel if (rxr->bytes == 0) 345361ae650dSJack F Vogel return; 345461ae650dSJack F Vogel 345561ae650dSJack F Vogel if (ixl_dynamic_rx_itr) { 345661ae650dSJack F Vogel rx_bytes = rxr->bytes/rxr->itr; 345761ae650dSJack F Vogel rx_itr = rxr->itr; 345861ae650dSJack F Vogel 345961ae650dSJack F Vogel /* Adjust latency range */ 346061ae650dSJack F Vogel switch (rxr->latency) { 346161ae650dSJack F Vogel case IXL_LOW_LATENCY: 346261ae650dSJack F Vogel if (rx_bytes > 10) { 346361ae650dSJack F Vogel rx_latency = IXL_AVE_LATENCY; 346461ae650dSJack F Vogel rx_itr = IXL_ITR_20K; 346561ae650dSJack F Vogel } 346661ae650dSJack F Vogel break; 346761ae650dSJack F Vogel case IXL_AVE_LATENCY: 346861ae650dSJack F Vogel if (rx_bytes > 20) { 346961ae650dSJack F Vogel rx_latency = IXL_BULK_LATENCY; 347061ae650dSJack F Vogel rx_itr = IXL_ITR_8K; 347161ae650dSJack F Vogel } else if (rx_bytes <= 10) { 347261ae650dSJack F Vogel rx_latency = IXL_LOW_LATENCY; 347361ae650dSJack F Vogel rx_itr = IXL_ITR_100K; 347461ae650dSJack F Vogel } 347561ae650dSJack F Vogel break; 347661ae650dSJack F Vogel case IXL_BULK_LATENCY: 347761ae650dSJack F Vogel if (rx_bytes <= 20) { 347861ae650dSJack F Vogel rx_latency = IXL_AVE_LATENCY; 347961ae650dSJack F Vogel rx_itr = IXL_ITR_20K; 348061ae650dSJack F Vogel } 348161ae650dSJack F Vogel break; 348261ae650dSJack F Vogel } 348361ae650dSJack F Vogel 348461ae650dSJack F Vogel rxr->latency = rx_latency; 348561ae650dSJack F Vogel 348661ae650dSJack F Vogel if (rx_itr != rxr->itr) { 348761ae650dSJack F Vogel /* do an exponential smoothing */ 348861ae650dSJack F Vogel rx_itr = (10 * rx_itr * rxr->itr) / 348961ae650dSJack F Vogel ((9 * rx_itr) + rxr->itr); 349061ae650dSJack F Vogel rxr->itr = rx_itr & IXL_MAX_ITR; 349161ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 349261ae650dSJack F Vogel que->me), rxr->itr); 349361ae650dSJack F Vogel } 349461ae650dSJack F Vogel } else { /* We may have have toggled to non-dynamic */ 349561ae650dSJack F Vogel if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) 349661ae650dSJack F Vogel vsi->rx_itr_setting = ixl_rx_itr; 349761ae650dSJack F Vogel /* Update the hardware if needed */ 349861ae650dSJack F Vogel if (rxr->itr != vsi->rx_itr_setting) { 349961ae650dSJack F Vogel rxr->itr = vsi->rx_itr_setting; 350061ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 350161ae650dSJack F Vogel que->me), rxr->itr); 350261ae650dSJack F Vogel } 350361ae650dSJack F Vogel } 350461ae650dSJack F Vogel rxr->bytes = 0; 350561ae650dSJack F Vogel rxr->packets = 0; 350661ae650dSJack F Vogel return; 350761ae650dSJack F Vogel } 350861ae650dSJack F Vogel 350961ae650dSJack F Vogel 351061ae650dSJack F Vogel /* 351161ae650dSJack F Vogel ** Provide a update to the queue TX 351261ae650dSJack F Vogel ** interrupt moderation value. 351361ae650dSJack F Vogel */ 351461ae650dSJack F Vogel static void 351561ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que) 351661ae650dSJack F Vogel { 351761ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 351861ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 351961ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 352061ae650dSJack F Vogel u16 tx_itr; 352161ae650dSJack F Vogel u16 tx_latency = 0; 352261ae650dSJack F Vogel int tx_bytes; 352361ae650dSJack F Vogel 352461ae650dSJack F Vogel 352561ae650dSJack F Vogel /* Idle, do nothing */ 352661ae650dSJack F Vogel if (txr->bytes == 0) 352761ae650dSJack F Vogel return; 352861ae650dSJack F Vogel 352961ae650dSJack F Vogel if (ixl_dynamic_tx_itr) { 353061ae650dSJack F Vogel tx_bytes = txr->bytes/txr->itr; 353161ae650dSJack F Vogel tx_itr = txr->itr; 353261ae650dSJack F Vogel 353361ae650dSJack F Vogel switch (txr->latency) { 353461ae650dSJack F Vogel case IXL_LOW_LATENCY: 353561ae650dSJack F Vogel if (tx_bytes > 10) { 353661ae650dSJack F Vogel tx_latency = IXL_AVE_LATENCY; 353761ae650dSJack F Vogel tx_itr = IXL_ITR_20K; 353861ae650dSJack F Vogel } 353961ae650dSJack F Vogel break; 354061ae650dSJack F Vogel case IXL_AVE_LATENCY: 354161ae650dSJack F Vogel if (tx_bytes > 20) { 354261ae650dSJack F Vogel tx_latency = IXL_BULK_LATENCY; 354361ae650dSJack F Vogel tx_itr = IXL_ITR_8K; 354461ae650dSJack F Vogel } else if (tx_bytes <= 10) { 354561ae650dSJack F Vogel tx_latency = IXL_LOW_LATENCY; 354661ae650dSJack F Vogel tx_itr = IXL_ITR_100K; 354761ae650dSJack F Vogel } 354861ae650dSJack F Vogel break; 354961ae650dSJack F Vogel case IXL_BULK_LATENCY: 355061ae650dSJack F Vogel if (tx_bytes <= 20) { 355161ae650dSJack F Vogel tx_latency = IXL_AVE_LATENCY; 355261ae650dSJack F Vogel tx_itr = IXL_ITR_20K; 355361ae650dSJack F Vogel } 355461ae650dSJack F Vogel break; 355561ae650dSJack F Vogel } 355661ae650dSJack F Vogel 355761ae650dSJack F Vogel txr->latency = tx_latency; 355861ae650dSJack F Vogel 355961ae650dSJack F Vogel if (tx_itr != txr->itr) { 356061ae650dSJack F Vogel /* do an exponential smoothing */ 356161ae650dSJack F Vogel tx_itr = (10 * tx_itr * txr->itr) / 356261ae650dSJack F Vogel ((9 * tx_itr) + txr->itr); 356361ae650dSJack F Vogel txr->itr = tx_itr & IXL_MAX_ITR; 356461ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 356561ae650dSJack F Vogel que->me), txr->itr); 356661ae650dSJack F Vogel } 356761ae650dSJack F Vogel 356861ae650dSJack F Vogel } else { /* We may have have toggled to non-dynamic */ 356961ae650dSJack F Vogel if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC) 357061ae650dSJack F Vogel vsi->tx_itr_setting = ixl_tx_itr; 357161ae650dSJack F Vogel /* Update the hardware if needed */ 357261ae650dSJack F Vogel if (txr->itr != vsi->tx_itr_setting) { 357361ae650dSJack F Vogel txr->itr = vsi->tx_itr_setting; 357461ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 357561ae650dSJack F Vogel que->me), txr->itr); 357661ae650dSJack F Vogel } 357761ae650dSJack F Vogel } 357861ae650dSJack F Vogel txr->bytes = 0; 357961ae650dSJack F Vogel txr->packets = 0; 358061ae650dSJack F Vogel return; 358161ae650dSJack F Vogel } 358261ae650dSJack F Vogel 358356c2c47bSJack F Vogel #define QUEUE_NAME_LEN 32 358456c2c47bSJack F Vogel 358556c2c47bSJack F Vogel static void 358656c2c47bSJack F Vogel ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi, 358756c2c47bSJack F Vogel struct sysctl_ctx_list *ctx, const char *sysctl_name) 358856c2c47bSJack F Vogel { 358956c2c47bSJack F Vogel struct sysctl_oid *tree; 359056c2c47bSJack F Vogel struct sysctl_oid_list *child; 359156c2c47bSJack F Vogel struct sysctl_oid_list *vsi_list; 359256c2c47bSJack F Vogel 359356c2c47bSJack F Vogel tree = device_get_sysctl_tree(pf->dev); 359456c2c47bSJack F Vogel child = SYSCTL_CHILDREN(tree); 359556c2c47bSJack F Vogel vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name, 359656c2c47bSJack F Vogel CTLFLAG_RD, NULL, "VSI Number"); 359756c2c47bSJack F Vogel vsi_list = SYSCTL_CHILDREN(vsi->vsi_node); 359856c2c47bSJack F Vogel 359956c2c47bSJack F Vogel ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats); 360056c2c47bSJack F Vogel } 360161ae650dSJack F Vogel 36026d011ad5SEric Joyner #ifdef IXL_DEBUG 36036d011ad5SEric Joyner /** 36046d011ad5SEric Joyner * ixl_sysctl_qtx_tail_handler 36056d011ad5SEric Joyner * Retrieves I40E_QTX_TAIL value from hardware 36066d011ad5SEric Joyner * for a sysctl. 36076d011ad5SEric Joyner */ 36086d011ad5SEric Joyner static int 36096d011ad5SEric Joyner ixl_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS) 36106d011ad5SEric Joyner { 36116d011ad5SEric Joyner struct ixl_queue *que; 36126d011ad5SEric Joyner int error; 36136d011ad5SEric Joyner u32 val; 36146d011ad5SEric Joyner 36156d011ad5SEric Joyner que = ((struct ixl_queue *)oidp->oid_arg1); 36166d011ad5SEric Joyner if (!que) return 0; 36176d011ad5SEric Joyner 36186d011ad5SEric Joyner val = rd32(que->vsi->hw, que->txr.tail); 36196d011ad5SEric Joyner error = sysctl_handle_int(oidp, &val, 0, req); 36206d011ad5SEric Joyner if (error || !req->newptr) 36216d011ad5SEric Joyner return error; 36226d011ad5SEric Joyner return (0); 36236d011ad5SEric Joyner } 36246d011ad5SEric Joyner 36256d011ad5SEric Joyner /** 36266d011ad5SEric Joyner * ixl_sysctl_qrx_tail_handler 36276d011ad5SEric Joyner * Retrieves I40E_QRX_TAIL value from hardware 36286d011ad5SEric Joyner * for a sysctl. 36296d011ad5SEric Joyner */ 36306d011ad5SEric Joyner static int 36316d011ad5SEric Joyner ixl_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS) 36326d011ad5SEric Joyner { 36336d011ad5SEric Joyner struct ixl_queue *que; 36346d011ad5SEric Joyner int error; 36356d011ad5SEric Joyner u32 val; 36366d011ad5SEric Joyner 36376d011ad5SEric Joyner que = ((struct ixl_queue *)oidp->oid_arg1); 36386d011ad5SEric Joyner if (!que) return 0; 36396d011ad5SEric Joyner 36406d011ad5SEric Joyner val = rd32(que->vsi->hw, que->rxr.tail); 36416d011ad5SEric Joyner error = sysctl_handle_int(oidp, &val, 0, req); 36426d011ad5SEric Joyner if (error || !req->newptr) 36436d011ad5SEric Joyner return error; 36446d011ad5SEric Joyner return (0); 36456d011ad5SEric Joyner } 36466d011ad5SEric Joyner #endif 36476d011ad5SEric Joyner 364861ae650dSJack F Vogel static void 364961ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf) 365061ae650dSJack F Vogel { 365161ae650dSJack F Vogel device_t dev = pf->dev; 365261ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 365361ae650dSJack F Vogel struct ixl_queue *queues = vsi->queues; 365461ae650dSJack F Vogel struct i40e_hw_port_stats *pf_stats = &pf->stats; 365561ae650dSJack F Vogel 365661ae650dSJack F Vogel struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 365761ae650dSJack F Vogel struct sysctl_oid *tree = device_get_sysctl_tree(dev); 365861ae650dSJack F Vogel struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 365956c2c47bSJack F Vogel struct sysctl_oid_list *vsi_list; 366061ae650dSJack F Vogel 366156c2c47bSJack F Vogel struct sysctl_oid *queue_node; 366256c2c47bSJack F Vogel struct sysctl_oid_list *queue_list; 366361ae650dSJack F Vogel 366461ae650dSJack F Vogel struct tx_ring *txr; 366561ae650dSJack F Vogel struct rx_ring *rxr; 366656c2c47bSJack F Vogel char queue_namebuf[QUEUE_NAME_LEN]; 366761ae650dSJack F Vogel 366861ae650dSJack F Vogel /* Driver statistics */ 366961ae650dSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 367061ae650dSJack F Vogel CTLFLAG_RD, &pf->watchdog_events, 367161ae650dSJack F Vogel "Watchdog timeouts"); 367261ae650dSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq", 367361ae650dSJack F Vogel CTLFLAG_RD, &pf->admin_irq, 367461ae650dSJack F Vogel "Admin Queue IRQ Handled"); 367561ae650dSJack F Vogel 367656c2c47bSJack F Vogel ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf"); 367756c2c47bSJack F Vogel vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node); 367861ae650dSJack F Vogel 367961ae650dSJack F Vogel /* Queue statistics */ 368061ae650dSJack F Vogel for (int q = 0; q < vsi->num_queues; q++) { 368161ae650dSJack F Vogel snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); 368256c2c47bSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, 368356c2c47bSJack F Vogel OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #"); 368461ae650dSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 368561ae650dSJack F Vogel 368661ae650dSJack F Vogel txr = &(queues[q].txr); 368761ae650dSJack F Vogel rxr = &(queues[q].rxr); 368861ae650dSJack F Vogel 368961ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", 369061ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), 369161ae650dSJack F Vogel "m_defrag() failed"); 369261ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 369361ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].irqs), 369461ae650dSJack F Vogel "irqs on this queue"); 369561ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", 369661ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].tso), 369761ae650dSJack F Vogel "TSO"); 369861ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup", 369961ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].tx_dma_setup), 370061ae650dSJack F Vogel "Driver tx dma failure in xmit"); 370161ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 370261ae650dSJack F Vogel CTLFLAG_RD, &(txr->no_desc), 370361ae650dSJack F Vogel "Queue No Descriptor Available"); 370461ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 370561ae650dSJack F Vogel CTLFLAG_RD, &(txr->total_packets), 370661ae650dSJack F Vogel "Queue Packets Transmitted"); 370761ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", 370861ae650dSJack F Vogel CTLFLAG_RD, &(txr->tx_bytes), 370961ae650dSJack F Vogel "Queue Bytes Transmitted"); 371061ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 371161ae650dSJack F Vogel CTLFLAG_RD, &(rxr->rx_packets), 371261ae650dSJack F Vogel "Queue Packets Received"); 371361ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 371461ae650dSJack F Vogel CTLFLAG_RD, &(rxr->rx_bytes), 371561ae650dSJack F Vogel "Queue Bytes Received"); 37166d011ad5SEric Joyner SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_desc_err", 37176d011ad5SEric Joyner CTLFLAG_RD, &(rxr->desc_errs), 37186d011ad5SEric Joyner "Queue Rx Descriptor Errors"); 37196d011ad5SEric Joyner SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_itr", 37206d011ad5SEric Joyner CTLFLAG_RD, &(rxr->itr), 0, 37216d011ad5SEric Joyner "Queue Rx ITR Interval"); 37226d011ad5SEric Joyner SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "tx_itr", 37236d011ad5SEric Joyner CTLFLAG_RD, &(txr->itr), 0, 37246d011ad5SEric Joyner "Queue Tx ITR Interval"); 37256d011ad5SEric Joyner // Not actual latency; just a calculated value to put in a register 37266d011ad5SEric Joyner // TODO: Put in better descriptions here 37276d011ad5SEric Joyner SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_latency", 37286d011ad5SEric Joyner CTLFLAG_RD, &(rxr->latency), 0, 37296d011ad5SEric Joyner "Queue Rx ITRL Average Interval"); 37306d011ad5SEric Joyner SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "tx_latency", 37316d011ad5SEric Joyner CTLFLAG_RD, &(txr->latency), 0, 37326d011ad5SEric Joyner "Queue Tx ITRL Average Interval"); 37336d011ad5SEric Joyner 37346d011ad5SEric Joyner #ifdef IXL_DEBUG 37356d011ad5SEric Joyner SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_not_done", 37366d011ad5SEric Joyner CTLFLAG_RD, &(rxr->not_done), 37376d011ad5SEric Joyner "Queue Rx Descriptors not Done"); 37386d011ad5SEric Joyner SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_next_refresh", 37396d011ad5SEric Joyner CTLFLAG_RD, &(rxr->next_refresh), 0, 37406d011ad5SEric Joyner "Queue Rx Descriptors not Done"); 37416d011ad5SEric Joyner SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_next_check", 37426d011ad5SEric Joyner CTLFLAG_RD, &(rxr->next_check), 0, 37436d011ad5SEric Joyner "Queue Rx Descriptors not Done"); 37446d011ad5SEric Joyner SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qtx_tail", 37456d011ad5SEric Joyner CTLTYPE_UINT | CTLFLAG_RD, &queues[q], 37466d011ad5SEric Joyner sizeof(struct ixl_queue), 37476d011ad5SEric Joyner ixl_sysctl_qtx_tail_handler, "IU", 37486d011ad5SEric Joyner "Queue Transmit Descriptor Tail"); 37496d011ad5SEric Joyner SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qrx_tail", 37506d011ad5SEric Joyner CTLTYPE_UINT | CTLFLAG_RD, &queues[q], 37516d011ad5SEric Joyner sizeof(struct ixl_queue), 37526d011ad5SEric Joyner ixl_sysctl_qrx_tail_handler, "IU", 37536d011ad5SEric Joyner "Queue Receive Descriptor Tail"); 37546d011ad5SEric Joyner #endif 375561ae650dSJack F Vogel } 375661ae650dSJack F Vogel 375761ae650dSJack F Vogel /* MAC stats */ 375861ae650dSJack F Vogel ixl_add_sysctls_mac_stats(ctx, child, pf_stats); 375961ae650dSJack F Vogel } 376061ae650dSJack F Vogel 376161ae650dSJack F Vogel static void 376261ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx, 376361ae650dSJack F Vogel struct sysctl_oid_list *child, 376461ae650dSJack F Vogel struct i40e_eth_stats *eth_stats) 376561ae650dSJack F Vogel { 376661ae650dSJack F Vogel struct ixl_sysctl_info ctls[] = 376761ae650dSJack F Vogel { 376861ae650dSJack F Vogel {ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, 376961ae650dSJack F Vogel {ð_stats->rx_unicast, "ucast_pkts_rcvd", 377061ae650dSJack F Vogel "Unicast Packets Received"}, 377161ae650dSJack F Vogel {ð_stats->rx_multicast, "mcast_pkts_rcvd", 377261ae650dSJack F Vogel "Multicast Packets Received"}, 377361ae650dSJack F Vogel {ð_stats->rx_broadcast, "bcast_pkts_rcvd", 377461ae650dSJack F Vogel "Broadcast Packets Received"}, 377561ae650dSJack F Vogel {ð_stats->rx_discards, "rx_discards", "Discarded RX packets"}, 377661ae650dSJack F Vogel {ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, 377761ae650dSJack F Vogel {ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, 377861ae650dSJack F Vogel {ð_stats->tx_multicast, "mcast_pkts_txd", 377961ae650dSJack F Vogel "Multicast Packets Transmitted"}, 378061ae650dSJack F Vogel {ð_stats->tx_broadcast, "bcast_pkts_txd", 378161ae650dSJack F Vogel "Broadcast Packets Transmitted"}, 378261ae650dSJack F Vogel // end 378361ae650dSJack F Vogel {0,0,0} 378461ae650dSJack F Vogel }; 378561ae650dSJack F Vogel 378661ae650dSJack F Vogel struct ixl_sysctl_info *entry = ctls; 3787648970d8SPedro F. Giffuni while (entry->stat != NULL) 378861ae650dSJack F Vogel { 378961ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name, 379061ae650dSJack F Vogel CTLFLAG_RD, entry->stat, 379161ae650dSJack F Vogel entry->description); 379261ae650dSJack F Vogel entry++; 379361ae650dSJack F Vogel } 379461ae650dSJack F Vogel } 379561ae650dSJack F Vogel 379661ae650dSJack F Vogel static void 379761ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx, 379861ae650dSJack F Vogel struct sysctl_oid_list *child, 379961ae650dSJack F Vogel struct i40e_hw_port_stats *stats) 380061ae650dSJack F Vogel { 380161ae650dSJack F Vogel struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", 380261ae650dSJack F Vogel CTLFLAG_RD, NULL, "Mac Statistics"); 380361ae650dSJack F Vogel struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node); 380461ae650dSJack F Vogel 380561ae650dSJack F Vogel struct i40e_eth_stats *eth_stats = &stats->eth; 380661ae650dSJack F Vogel ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats); 380761ae650dSJack F Vogel 380861ae650dSJack F Vogel struct ixl_sysctl_info ctls[] = 380961ae650dSJack F Vogel { 381061ae650dSJack F Vogel {&stats->crc_errors, "crc_errors", "CRC Errors"}, 381161ae650dSJack F Vogel {&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"}, 381261ae650dSJack F Vogel {&stats->mac_local_faults, "local_faults", "MAC Local Faults"}, 381361ae650dSJack F Vogel {&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"}, 381461ae650dSJack F Vogel {&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"}, 381561ae650dSJack F Vogel /* Packet Reception Stats */ 381661ae650dSJack F Vogel {&stats->rx_size_64, "rx_frames_64", "64 byte frames received"}, 381761ae650dSJack F Vogel {&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"}, 381861ae650dSJack F Vogel {&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"}, 381961ae650dSJack F Vogel {&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"}, 382061ae650dSJack F Vogel {&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"}, 382161ae650dSJack F Vogel {&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"}, 382261ae650dSJack F Vogel {&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"}, 382361ae650dSJack F Vogel {&stats->rx_undersize, "rx_undersize", "Undersized packets received"}, 382461ae650dSJack F Vogel {&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"}, 382561ae650dSJack F Vogel {&stats->rx_oversize, "rx_oversized", "Oversized packets received"}, 382661ae650dSJack F Vogel {&stats->rx_jabber, "rx_jabber", "Received Jabber"}, 382761ae650dSJack F Vogel {&stats->checksum_error, "checksum_errors", "Checksum Errors"}, 382861ae650dSJack F Vogel /* Packet Transmission Stats */ 382961ae650dSJack F Vogel {&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"}, 383061ae650dSJack F Vogel {&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"}, 383161ae650dSJack F Vogel {&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"}, 383261ae650dSJack F Vogel {&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"}, 383361ae650dSJack F Vogel {&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"}, 383461ae650dSJack F Vogel {&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"}, 383561ae650dSJack F Vogel {&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"}, 383661ae650dSJack F Vogel /* Flow control */ 383761ae650dSJack F Vogel {&stats->link_xon_tx, "xon_txd", "Link XON transmitted"}, 383861ae650dSJack F Vogel {&stats->link_xon_rx, "xon_recvd", "Link XON received"}, 383961ae650dSJack F Vogel {&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"}, 384061ae650dSJack F Vogel {&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"}, 384161ae650dSJack F Vogel /* End */ 384261ae650dSJack F Vogel {0,0,0} 384361ae650dSJack F Vogel }; 384461ae650dSJack F Vogel 384561ae650dSJack F Vogel struct ixl_sysctl_info *entry = ctls; 3846648970d8SPedro F. Giffuni while (entry->stat != NULL) 384761ae650dSJack F Vogel { 384861ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name, 384961ae650dSJack F Vogel CTLFLAG_RD, entry->stat, 385061ae650dSJack F Vogel entry->description); 385161ae650dSJack F Vogel entry++; 385261ae650dSJack F Vogel } 385361ae650dSJack F Vogel } 385461ae650dSJack F Vogel 3855be771cdaSJack F Vogel 385661ae650dSJack F Vogel /* 385761ae650dSJack F Vogel ** ixl_config_rss - setup RSS 385861ae650dSJack F Vogel ** - note this is done for the single vsi 385961ae650dSJack F Vogel */ 38606d011ad5SEric Joyner static void 38616d011ad5SEric Joyner ixl_config_rss(struct ixl_vsi *vsi) 386261ae650dSJack F Vogel { 386361ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 386461ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 386561ae650dSJack F Vogel u32 lut = 0; 3866393c4bb1SJack F Vogel u64 set_hena = 0, hena; 3867393c4bb1SJack F Vogel int i, j, que_id; 3868393c4bb1SJack F Vogel #ifdef RSS 3869393c4bb1SJack F Vogel u32 rss_hash_config; 3870393c4bb1SJack F Vogel u32 rss_seed[IXL_KEYSZ]; 3871393c4bb1SJack F Vogel #else 3872393c4bb1SJack F Vogel u32 rss_seed[IXL_KEYSZ] = {0x41b01687, 3873393c4bb1SJack F Vogel 0x183cfd8c, 0xce880440, 0x580cbc3c, 3874393c4bb1SJack F Vogel 0x35897377, 0x328b25e1, 0x4fa98922, 3875393c4bb1SJack F Vogel 0xb7d90c14, 0xd5bad70d, 0xcd15a2c1}; 3876393c4bb1SJack F Vogel #endif 387761ae650dSJack F Vogel 3878393c4bb1SJack F Vogel #ifdef RSS 3879393c4bb1SJack F Vogel /* Fetch the configured RSS key */ 3880393c4bb1SJack F Vogel rss_getkey((uint8_t *) &rss_seed); 3881393c4bb1SJack F Vogel #endif 388261ae650dSJack F Vogel 388361ae650dSJack F Vogel /* Fill out hash function seed */ 3884393c4bb1SJack F Vogel for (i = 0; i < IXL_KEYSZ; i++) 3885*d4683565SEric Joyner i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), rss_seed[i]); 388661ae650dSJack F Vogel 388761ae650dSJack F Vogel /* Enable PCTYPES for RSS: */ 3888393c4bb1SJack F Vogel #ifdef RSS 3889393c4bb1SJack F Vogel rss_hash_config = rss_gethashconfig(); 3890393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 3891393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); 3892393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 3893393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); 3894393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 3895393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP); 3896393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 3897393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); 3898df1d7a71SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 3899df1d7a71SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); 3900393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 3901393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); 3902393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 3903393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP); 3904393c4bb1SJack F Vogel #else 390561ae650dSJack F Vogel set_hena = 390661ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | 390761ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | 390861ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | 390961ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | 391061ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | 391161ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | 391261ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | 391361ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | 391461ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | 391561ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | 391661ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD); 3917393c4bb1SJack F Vogel #endif 3918*d4683565SEric Joyner hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) | 3919*d4683565SEric Joyner ((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32); 392061ae650dSJack F Vogel hena |= set_hena; 3921*d4683565SEric Joyner i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena); 3922*d4683565SEric Joyner i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); 392361ae650dSJack F Vogel 392461ae650dSJack F Vogel /* Populate the LUT with max no. of queues in round robin fashion */ 392561ae650dSJack F Vogel for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) { 392661ae650dSJack F Vogel if (j == vsi->num_queues) 392761ae650dSJack F Vogel j = 0; 3928393c4bb1SJack F Vogel #ifdef RSS 3929393c4bb1SJack F Vogel /* 3930393c4bb1SJack F Vogel * Fetch the RSS bucket id for the given indirection entry. 3931393c4bb1SJack F Vogel * Cap it at the number of configured buckets (which is 3932393c4bb1SJack F Vogel * num_queues.) 3933393c4bb1SJack F Vogel */ 3934393c4bb1SJack F Vogel que_id = rss_get_indirection_to_bucket(i); 3935dcd7b3b2SJack F Vogel que_id = que_id % vsi->num_queues; 3936393c4bb1SJack F Vogel #else 3937393c4bb1SJack F Vogel que_id = j; 3938393c4bb1SJack F Vogel #endif 393961ae650dSJack F Vogel /* lut = 4-byte sliding window of 4 lut entries */ 3940393c4bb1SJack F Vogel lut = (lut << 8) | (que_id & 394161ae650dSJack F Vogel ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1)); 394261ae650dSJack F Vogel /* On i = 3, we have 4 entries in lut; write to the register */ 394361ae650dSJack F Vogel if ((i & 3) == 3) 394461ae650dSJack F Vogel wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); 394561ae650dSJack F Vogel } 394661ae650dSJack F Vogel ixl_flush(hw); 394761ae650dSJack F Vogel } 394861ae650dSJack F Vogel 394961ae650dSJack F Vogel 395061ae650dSJack F Vogel /* 395161ae650dSJack F Vogel ** This routine is run via an vlan config EVENT, 395261ae650dSJack F Vogel ** it enables us to use the HW Filter table since 395361ae650dSJack F Vogel ** we can get the vlan id. This just creates the 395461ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will 395561ae650dSJack F Vogel ** repopulate the real table. 395661ae650dSJack F Vogel */ 395761ae650dSJack F Vogel static void 395861ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 395961ae650dSJack F Vogel { 396061ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 396161ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 396261ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 396361ae650dSJack F Vogel 396461ae650dSJack F Vogel if (ifp->if_softc != arg) /* Not our event */ 396561ae650dSJack F Vogel return; 396661ae650dSJack F Vogel 396761ae650dSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 396861ae650dSJack F Vogel return; 396961ae650dSJack F Vogel 397061ae650dSJack F Vogel IXL_PF_LOCK(pf); 397161ae650dSJack F Vogel ++vsi->num_vlans; 397261ae650dSJack F Vogel ixl_add_filter(vsi, hw->mac.addr, vtag); 397361ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 397461ae650dSJack F Vogel } 397561ae650dSJack F Vogel 397661ae650dSJack F Vogel /* 397761ae650dSJack F Vogel ** This routine is run via an vlan 397861ae650dSJack F Vogel ** unconfig EVENT, remove our entry 397961ae650dSJack F Vogel ** in the soft vfta. 398061ae650dSJack F Vogel */ 398161ae650dSJack F Vogel static void 398261ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 398361ae650dSJack F Vogel { 398461ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 398561ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 398661ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 398761ae650dSJack F Vogel 398861ae650dSJack F Vogel if (ifp->if_softc != arg) 398961ae650dSJack F Vogel return; 399061ae650dSJack F Vogel 399161ae650dSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 399261ae650dSJack F Vogel return; 399361ae650dSJack F Vogel 399461ae650dSJack F Vogel IXL_PF_LOCK(pf); 399561ae650dSJack F Vogel --vsi->num_vlans; 399661ae650dSJack F Vogel ixl_del_filter(vsi, hw->mac.addr, vtag); 399761ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 399861ae650dSJack F Vogel } 399961ae650dSJack F Vogel 400061ae650dSJack F Vogel /* 400161ae650dSJack F Vogel ** This routine updates vlan filters, called by init 400261ae650dSJack F Vogel ** it scans the filter table and then updates the hw 400361ae650dSJack F Vogel ** after a soft reset. 400461ae650dSJack F Vogel */ 400561ae650dSJack F Vogel static void 400661ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi) 400761ae650dSJack F Vogel { 400861ae650dSJack F Vogel struct ixl_mac_filter *f; 400961ae650dSJack F Vogel int cnt = 0, flags; 401061ae650dSJack F Vogel 401161ae650dSJack F Vogel if (vsi->num_vlans == 0) 401261ae650dSJack F Vogel return; 401361ae650dSJack F Vogel /* 401461ae650dSJack F Vogel ** Scan the filter list for vlan entries, 401561ae650dSJack F Vogel ** mark them for addition and then call 401661ae650dSJack F Vogel ** for the AQ update. 401761ae650dSJack F Vogel */ 401861ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 401961ae650dSJack F Vogel if (f->flags & IXL_FILTER_VLAN) { 402061ae650dSJack F Vogel f->flags |= 402161ae650dSJack F Vogel (IXL_FILTER_ADD | 402261ae650dSJack F Vogel IXL_FILTER_USED); 402361ae650dSJack F Vogel cnt++; 402461ae650dSJack F Vogel } 402561ae650dSJack F Vogel } 402661ae650dSJack F Vogel if (cnt == 0) { 402761ae650dSJack F Vogel printf("setup vlan: no filters found!\n"); 402861ae650dSJack F Vogel return; 402961ae650dSJack F Vogel } 403061ae650dSJack F Vogel flags = IXL_FILTER_VLAN; 403161ae650dSJack F Vogel flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 403261ae650dSJack F Vogel ixl_add_hw_filters(vsi, flags, cnt); 403361ae650dSJack F Vogel return; 403461ae650dSJack F Vogel } 403561ae650dSJack F Vogel 403661ae650dSJack F Vogel /* 403761ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware 403861ae650dSJack F Vogel ** needs to know about. 40391d767a8eSEric Joyner ** 40401d767a8eSEric Joyner ** Requires VSI's filter list & seid to be set before calling. 404161ae650dSJack F Vogel */ 404261ae650dSJack F Vogel static void 404361ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi) 404461ae650dSJack F Vogel { 404561ae650dSJack F Vogel /* Add broadcast address */ 404656c2c47bSJack F Vogel ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY); 40471d767a8eSEric Joyner 40481d767a8eSEric Joyner /* 40491d767a8eSEric Joyner * Prevent Tx flow control frames from being sent out by 40501d767a8eSEric Joyner * non-firmware transmitters. 40511d767a8eSEric Joyner */ 40521d767a8eSEric Joyner i40e_add_filter_to_drop_tx_flow_control_frames(vsi->hw, vsi->seid); 405361ae650dSJack F Vogel } 405461ae650dSJack F Vogel 405561ae650dSJack F Vogel /* 405661ae650dSJack F Vogel ** This routine adds mulicast filters 405761ae650dSJack F Vogel */ 405861ae650dSJack F Vogel static void 405961ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr) 406061ae650dSJack F Vogel { 406161ae650dSJack F Vogel struct ixl_mac_filter *f; 406261ae650dSJack F Vogel 406361ae650dSJack F Vogel /* Does one already exist */ 406461ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 406561ae650dSJack F Vogel if (f != NULL) 406661ae650dSJack F Vogel return; 406761ae650dSJack F Vogel 406861ae650dSJack F Vogel f = ixl_get_filter(vsi); 406961ae650dSJack F Vogel if (f == NULL) { 407061ae650dSJack F Vogel printf("WARNING: no filter available!!\n"); 407161ae650dSJack F Vogel return; 407261ae650dSJack F Vogel } 407361ae650dSJack F Vogel bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 407461ae650dSJack F Vogel f->vlan = IXL_VLAN_ANY; 407561ae650dSJack F Vogel f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED 407661ae650dSJack F Vogel | IXL_FILTER_MC); 407761ae650dSJack F Vogel 407861ae650dSJack F Vogel return; 407961ae650dSJack F Vogel } 408061ae650dSJack F Vogel 408156c2c47bSJack F Vogel static void 408256c2c47bSJack F Vogel ixl_reconfigure_filters(struct ixl_vsi *vsi) 408356c2c47bSJack F Vogel { 408456c2c47bSJack F Vogel 408556c2c47bSJack F Vogel ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs); 408656c2c47bSJack F Vogel } 408756c2c47bSJack F Vogel 408861ae650dSJack F Vogel /* 408961ae650dSJack F Vogel ** This routine adds macvlan filters 409061ae650dSJack F Vogel */ 409161ae650dSJack F Vogel static void 409261ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 409361ae650dSJack F Vogel { 409461ae650dSJack F Vogel struct ixl_mac_filter *f, *tmp; 409556c2c47bSJack F Vogel struct ixl_pf *pf; 409656c2c47bSJack F Vogel device_t dev; 409761ae650dSJack F Vogel 409861ae650dSJack F Vogel DEBUGOUT("ixl_add_filter: begin"); 409961ae650dSJack F Vogel 410056c2c47bSJack F Vogel pf = vsi->back; 410156c2c47bSJack F Vogel dev = pf->dev; 410256c2c47bSJack F Vogel 410361ae650dSJack F Vogel /* Does one already exist */ 410461ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, vlan); 410561ae650dSJack F Vogel if (f != NULL) 410661ae650dSJack F Vogel return; 410761ae650dSJack F Vogel /* 410861ae650dSJack F Vogel ** Is this the first vlan being registered, if so we 410961ae650dSJack F Vogel ** need to remove the ANY filter that indicates we are 411061ae650dSJack F Vogel ** not in a vlan, and replace that with a 0 filter. 411161ae650dSJack F Vogel */ 411261ae650dSJack F Vogel if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) { 411361ae650dSJack F Vogel tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 411461ae650dSJack F Vogel if (tmp != NULL) { 411561ae650dSJack F Vogel ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY); 411661ae650dSJack F Vogel ixl_add_filter(vsi, macaddr, 0); 411761ae650dSJack F Vogel } 411861ae650dSJack F Vogel } 411961ae650dSJack F Vogel 412061ae650dSJack F Vogel f = ixl_get_filter(vsi); 412161ae650dSJack F Vogel if (f == NULL) { 412261ae650dSJack F Vogel device_printf(dev, "WARNING: no filter available!!\n"); 412361ae650dSJack F Vogel return; 412461ae650dSJack F Vogel } 412561ae650dSJack F Vogel bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 412661ae650dSJack F Vogel f->vlan = vlan; 412761ae650dSJack F Vogel f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 412861ae650dSJack F Vogel if (f->vlan != IXL_VLAN_ANY) 412961ae650dSJack F Vogel f->flags |= IXL_FILTER_VLAN; 413056c2c47bSJack F Vogel else 413156c2c47bSJack F Vogel vsi->num_macs++; 413261ae650dSJack F Vogel 413361ae650dSJack F Vogel ixl_add_hw_filters(vsi, f->flags, 1); 413461ae650dSJack F Vogel return; 413561ae650dSJack F Vogel } 413661ae650dSJack F Vogel 413761ae650dSJack F Vogel static void 413861ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 413961ae650dSJack F Vogel { 414061ae650dSJack F Vogel struct ixl_mac_filter *f; 414161ae650dSJack F Vogel 414261ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, vlan); 414361ae650dSJack F Vogel if (f == NULL) 414461ae650dSJack F Vogel return; 414561ae650dSJack F Vogel 414661ae650dSJack F Vogel f->flags |= IXL_FILTER_DEL; 414761ae650dSJack F Vogel ixl_del_hw_filters(vsi, 1); 414856c2c47bSJack F Vogel vsi->num_macs--; 414961ae650dSJack F Vogel 415061ae650dSJack F Vogel /* Check if this is the last vlan removal */ 415161ae650dSJack F Vogel if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) { 415261ae650dSJack F Vogel /* Switch back to a non-vlan filter */ 415361ae650dSJack F Vogel ixl_del_filter(vsi, macaddr, 0); 415461ae650dSJack F Vogel ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY); 415561ae650dSJack F Vogel } 415661ae650dSJack F Vogel return; 415761ae650dSJack F Vogel } 415861ae650dSJack F Vogel 415961ae650dSJack F Vogel /* 416061ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id 416161ae650dSJack F Vogel */ 416261ae650dSJack F Vogel static struct ixl_mac_filter * 416361ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 416461ae650dSJack F Vogel { 416561ae650dSJack F Vogel struct ixl_mac_filter *f; 416661ae650dSJack F Vogel bool match = FALSE; 416761ae650dSJack F Vogel 416861ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 416961ae650dSJack F Vogel if (!cmp_etheraddr(f->macaddr, macaddr)) 417061ae650dSJack F Vogel continue; 417161ae650dSJack F Vogel if (f->vlan == vlan) { 417261ae650dSJack F Vogel match = TRUE; 417361ae650dSJack F Vogel break; 417461ae650dSJack F Vogel } 417561ae650dSJack F Vogel } 417661ae650dSJack F Vogel 417761ae650dSJack F Vogel if (!match) 417861ae650dSJack F Vogel f = NULL; 417961ae650dSJack F Vogel return (f); 418061ae650dSJack F Vogel } 418161ae650dSJack F Vogel 418261ae650dSJack F Vogel /* 418361ae650dSJack F Vogel ** This routine takes additions to the vsi filter 418461ae650dSJack F Vogel ** table and creates an Admin Queue call to create 418561ae650dSJack F Vogel ** the filters in the hardware. 418661ae650dSJack F Vogel */ 418761ae650dSJack F Vogel static void 418861ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt) 418961ae650dSJack F Vogel { 419061ae650dSJack F Vogel struct i40e_aqc_add_macvlan_element_data *a, *b; 419161ae650dSJack F Vogel struct ixl_mac_filter *f; 419256c2c47bSJack F Vogel struct ixl_pf *pf; 419356c2c47bSJack F Vogel struct i40e_hw *hw; 419456c2c47bSJack F Vogel device_t dev; 419561ae650dSJack F Vogel int err, j = 0; 419661ae650dSJack F Vogel 419756c2c47bSJack F Vogel pf = vsi->back; 419856c2c47bSJack F Vogel dev = pf->dev; 419956c2c47bSJack F Vogel hw = &pf->hw; 420056c2c47bSJack F Vogel IXL_PF_LOCK_ASSERT(pf); 420156c2c47bSJack F Vogel 420261ae650dSJack F Vogel a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt, 420361ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 420461ae650dSJack F Vogel if (a == NULL) { 4205393c4bb1SJack F Vogel device_printf(dev, "add_hw_filters failed to get memory\n"); 420661ae650dSJack F Vogel return; 420761ae650dSJack F Vogel } 420861ae650dSJack F Vogel 420961ae650dSJack F Vogel /* 421061ae650dSJack F Vogel ** Scan the filter list, each time we find one 421161ae650dSJack F Vogel ** we add it to the admin queue array and turn off 421261ae650dSJack F Vogel ** the add bit. 421361ae650dSJack F Vogel */ 421461ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 421561ae650dSJack F Vogel if (f->flags == flags) { 421661ae650dSJack F Vogel b = &a[j]; // a pox on fvl long names :) 421761ae650dSJack F Vogel bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN); 421856c2c47bSJack F Vogel if (f->vlan == IXL_VLAN_ANY) { 421956c2c47bSJack F Vogel b->vlan_tag = 0; 422056c2c47bSJack F Vogel b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN; 422156c2c47bSJack F Vogel } else { 422256c2c47bSJack F Vogel b->vlan_tag = f->vlan; 422356c2c47bSJack F Vogel b->flags = 0; 422456c2c47bSJack F Vogel } 422556c2c47bSJack F Vogel b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH; 422661ae650dSJack F Vogel f->flags &= ~IXL_FILTER_ADD; 422761ae650dSJack F Vogel j++; 422861ae650dSJack F Vogel } 422961ae650dSJack F Vogel if (j == cnt) 423061ae650dSJack F Vogel break; 423161ae650dSJack F Vogel } 423261ae650dSJack F Vogel if (j > 0) { 423361ae650dSJack F Vogel err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); 423461ae650dSJack F Vogel if (err) 4235b6c8f260SJack F Vogel device_printf(dev, "aq_add_macvlan err %d, " 4236b6c8f260SJack F Vogel "aq_error %d\n", err, hw->aq.asq_last_status); 423761ae650dSJack F Vogel else 423861ae650dSJack F Vogel vsi->hw_filters_add += j; 423961ae650dSJack F Vogel } 424061ae650dSJack F Vogel free(a, M_DEVBUF); 424161ae650dSJack F Vogel return; 424261ae650dSJack F Vogel } 424361ae650dSJack F Vogel 424461ae650dSJack F Vogel /* 424561ae650dSJack F Vogel ** This routine takes removals in the vsi filter 424661ae650dSJack F Vogel ** table and creates an Admin Queue call to delete 424761ae650dSJack F Vogel ** the filters in the hardware. 424861ae650dSJack F Vogel */ 424961ae650dSJack F Vogel static void 425061ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt) 425161ae650dSJack F Vogel { 425261ae650dSJack F Vogel struct i40e_aqc_remove_macvlan_element_data *d, *e; 425356c2c47bSJack F Vogel struct ixl_pf *pf; 425456c2c47bSJack F Vogel struct i40e_hw *hw; 425556c2c47bSJack F Vogel device_t dev; 425661ae650dSJack F Vogel struct ixl_mac_filter *f, *f_temp; 425761ae650dSJack F Vogel int err, j = 0; 425861ae650dSJack F Vogel 425961ae650dSJack F Vogel DEBUGOUT("ixl_del_hw_filters: begin\n"); 426061ae650dSJack F Vogel 426156c2c47bSJack F Vogel pf = vsi->back; 426256c2c47bSJack F Vogel hw = &pf->hw; 426356c2c47bSJack F Vogel dev = pf->dev; 426456c2c47bSJack F Vogel 426561ae650dSJack F Vogel d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt, 426661ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 426761ae650dSJack F Vogel if (d == NULL) { 426861ae650dSJack F Vogel printf("del hw filter failed to get memory\n"); 426961ae650dSJack F Vogel return; 427061ae650dSJack F Vogel } 427161ae650dSJack F Vogel 427261ae650dSJack F Vogel SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) { 427361ae650dSJack F Vogel if (f->flags & IXL_FILTER_DEL) { 427461ae650dSJack F Vogel e = &d[j]; // a pox on fvl long names :) 427561ae650dSJack F Vogel bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN); 427661ae650dSJack F Vogel e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan); 427761ae650dSJack F Vogel e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; 427861ae650dSJack F Vogel /* delete entry from vsi list */ 427961ae650dSJack F Vogel SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next); 428061ae650dSJack F Vogel free(f, M_DEVBUF); 428161ae650dSJack F Vogel j++; 428261ae650dSJack F Vogel } 428361ae650dSJack F Vogel if (j == cnt) 428461ae650dSJack F Vogel break; 428561ae650dSJack F Vogel } 428661ae650dSJack F Vogel if (j > 0) { 428761ae650dSJack F Vogel err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); 428861ae650dSJack F Vogel /* NOTE: returns ENOENT every time but seems to work fine, 428961ae650dSJack F Vogel so we'll ignore that specific error. */ 4290393c4bb1SJack F Vogel // TODO: Does this still occur on current firmwares? 429161ae650dSJack F Vogel if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { 429261ae650dSJack F Vogel int sc = 0; 429361ae650dSJack F Vogel for (int i = 0; i < j; i++) 429461ae650dSJack F Vogel sc += (!d[i].error_code); 429561ae650dSJack F Vogel vsi->hw_filters_del += sc; 429661ae650dSJack F Vogel device_printf(dev, 429761ae650dSJack F Vogel "Failed to remove %d/%d filters, aq error %d\n", 429861ae650dSJack F Vogel j - sc, j, hw->aq.asq_last_status); 429961ae650dSJack F Vogel } else 430061ae650dSJack F Vogel vsi->hw_filters_del += j; 430161ae650dSJack F Vogel } 430261ae650dSJack F Vogel free(d, M_DEVBUF); 430361ae650dSJack F Vogel 430461ae650dSJack F Vogel DEBUGOUT("ixl_del_hw_filters: end\n"); 430561ae650dSJack F Vogel return; 430661ae650dSJack F Vogel } 430761ae650dSJack F Vogel 430856c2c47bSJack F Vogel static int 430961ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi) 431061ae650dSJack F Vogel { 431156c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 431256c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 431356c2c47bSJack F Vogel int index, error; 431461ae650dSJack F Vogel u32 reg; 431561ae650dSJack F Vogel 431656c2c47bSJack F Vogel error = 0; 431761ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 431856c2c47bSJack F Vogel index = vsi->first_queue + i; 431956c2c47bSJack F Vogel i40e_pre_tx_queue_cfg(hw, index, TRUE); 432061ae650dSJack F Vogel 432156c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 432261ae650dSJack F Vogel reg |= I40E_QTX_ENA_QENA_REQ_MASK | 432361ae650dSJack F Vogel I40E_QTX_ENA_QENA_STAT_MASK; 432456c2c47bSJack F Vogel wr32(hw, I40E_QTX_ENA(index), reg); 432561ae650dSJack F Vogel /* Verify the enable took */ 432661ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 432756c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 432861ae650dSJack F Vogel if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 432961ae650dSJack F Vogel break; 433061ae650dSJack F Vogel i40e_msec_delay(10); 433161ae650dSJack F Vogel } 433256c2c47bSJack F Vogel if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) { 433356c2c47bSJack F Vogel device_printf(pf->dev, "TX queue %d disabled!\n", 433456c2c47bSJack F Vogel index); 433556c2c47bSJack F Vogel error = ETIMEDOUT; 433656c2c47bSJack F Vogel } 433761ae650dSJack F Vogel 433856c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 433961ae650dSJack F Vogel reg |= I40E_QRX_ENA_QENA_REQ_MASK | 434061ae650dSJack F Vogel I40E_QRX_ENA_QENA_STAT_MASK; 434156c2c47bSJack F Vogel wr32(hw, I40E_QRX_ENA(index), reg); 434261ae650dSJack F Vogel /* Verify the enable took */ 434361ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 434456c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 434561ae650dSJack F Vogel if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 434661ae650dSJack F Vogel break; 434761ae650dSJack F Vogel i40e_msec_delay(10); 434861ae650dSJack F Vogel } 434956c2c47bSJack F Vogel if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) { 435056c2c47bSJack F Vogel device_printf(pf->dev, "RX queue %d disabled!\n", 435156c2c47bSJack F Vogel index); 435256c2c47bSJack F Vogel error = ETIMEDOUT; 435361ae650dSJack F Vogel } 435461ae650dSJack F Vogel } 435561ae650dSJack F Vogel 435656c2c47bSJack F Vogel return (error); 435756c2c47bSJack F Vogel } 435856c2c47bSJack F Vogel 435956c2c47bSJack F Vogel static int 436061ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi) 436161ae650dSJack F Vogel { 436256c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 436356c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 436456c2c47bSJack F Vogel int index, error; 436561ae650dSJack F Vogel u32 reg; 436661ae650dSJack F Vogel 436756c2c47bSJack F Vogel error = 0; 436861ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 436956c2c47bSJack F Vogel index = vsi->first_queue + i; 437056c2c47bSJack F Vogel 437156c2c47bSJack F Vogel i40e_pre_tx_queue_cfg(hw, index, FALSE); 437261ae650dSJack F Vogel i40e_usec_delay(500); 437361ae650dSJack F Vogel 437456c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 437561ae650dSJack F Vogel reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; 437656c2c47bSJack F Vogel wr32(hw, I40E_QTX_ENA(index), reg); 437761ae650dSJack F Vogel /* Verify the disable took */ 437861ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 437956c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 438061ae650dSJack F Vogel if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK)) 438161ae650dSJack F Vogel break; 438261ae650dSJack F Vogel i40e_msec_delay(10); 438361ae650dSJack F Vogel } 438456c2c47bSJack F Vogel if (reg & I40E_QTX_ENA_QENA_STAT_MASK) { 438556c2c47bSJack F Vogel device_printf(pf->dev, "TX queue %d still enabled!\n", 438656c2c47bSJack F Vogel index); 438756c2c47bSJack F Vogel error = ETIMEDOUT; 438856c2c47bSJack F Vogel } 438961ae650dSJack F Vogel 439056c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 439161ae650dSJack F Vogel reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; 439256c2c47bSJack F Vogel wr32(hw, I40E_QRX_ENA(index), reg); 439361ae650dSJack F Vogel /* Verify the disable took */ 439461ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 439556c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 439661ae650dSJack F Vogel if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK)) 439761ae650dSJack F Vogel break; 439861ae650dSJack F Vogel i40e_msec_delay(10); 439961ae650dSJack F Vogel } 440056c2c47bSJack F Vogel if (reg & I40E_QRX_ENA_QENA_STAT_MASK) { 440156c2c47bSJack F Vogel device_printf(pf->dev, "RX queue %d still enabled!\n", 440256c2c47bSJack F Vogel index); 440356c2c47bSJack F Vogel error = ETIMEDOUT; 440461ae650dSJack F Vogel } 440561ae650dSJack F Vogel } 440661ae650dSJack F Vogel 440756c2c47bSJack F Vogel return (error); 440856c2c47bSJack F Vogel } 440956c2c47bSJack F Vogel 441061ae650dSJack F Vogel /** 441161ae650dSJack F Vogel * ixl_handle_mdd_event 441261ae650dSJack F Vogel * 441361ae650dSJack F Vogel * Called from interrupt handler to identify possibly malicious vfs 441461ae650dSJack F Vogel * (But also detects events from the PF, as well) 441561ae650dSJack F Vogel **/ 44166d011ad5SEric Joyner static void 44176d011ad5SEric Joyner ixl_handle_mdd_event(struct ixl_pf *pf) 441861ae650dSJack F Vogel { 441961ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 442061ae650dSJack F Vogel device_t dev = pf->dev; 442161ae650dSJack F Vogel bool mdd_detected = false; 442261ae650dSJack F Vogel bool pf_mdd_detected = false; 442361ae650dSJack F Vogel u32 reg; 442461ae650dSJack F Vogel 442561ae650dSJack F Vogel /* find what triggered the MDD event */ 442661ae650dSJack F Vogel reg = rd32(hw, I40E_GL_MDET_TX); 442761ae650dSJack F Vogel if (reg & I40E_GL_MDET_TX_VALID_MASK) { 442861ae650dSJack F Vogel u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >> 442961ae650dSJack F Vogel I40E_GL_MDET_TX_PF_NUM_SHIFT; 443061ae650dSJack F Vogel u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >> 443161ae650dSJack F Vogel I40E_GL_MDET_TX_EVENT_SHIFT; 443261ae650dSJack F Vogel u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >> 443361ae650dSJack F Vogel I40E_GL_MDET_TX_QUEUE_SHIFT; 443461ae650dSJack F Vogel device_printf(dev, 443561ae650dSJack F Vogel "Malicious Driver Detection event 0x%02x" 443661ae650dSJack F Vogel " on TX queue %d pf number 0x%02x\n", 443761ae650dSJack F Vogel event, queue, pf_num); 443861ae650dSJack F Vogel wr32(hw, I40E_GL_MDET_TX, 0xffffffff); 443961ae650dSJack F Vogel mdd_detected = true; 444061ae650dSJack F Vogel } 444161ae650dSJack F Vogel reg = rd32(hw, I40E_GL_MDET_RX); 444261ae650dSJack F Vogel if (reg & I40E_GL_MDET_RX_VALID_MASK) { 444361ae650dSJack F Vogel u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >> 444461ae650dSJack F Vogel I40E_GL_MDET_RX_FUNCTION_SHIFT; 444561ae650dSJack F Vogel u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >> 444661ae650dSJack F Vogel I40E_GL_MDET_RX_EVENT_SHIFT; 444761ae650dSJack F Vogel u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >> 444861ae650dSJack F Vogel I40E_GL_MDET_RX_QUEUE_SHIFT; 444961ae650dSJack F Vogel device_printf(dev, 445061ae650dSJack F Vogel "Malicious Driver Detection event 0x%02x" 445161ae650dSJack F Vogel " on RX queue %d of function 0x%02x\n", 445261ae650dSJack F Vogel event, queue, func); 445361ae650dSJack F Vogel wr32(hw, I40E_GL_MDET_RX, 0xffffffff); 445461ae650dSJack F Vogel mdd_detected = true; 445561ae650dSJack F Vogel } 445661ae650dSJack F Vogel 445761ae650dSJack F Vogel if (mdd_detected) { 445861ae650dSJack F Vogel reg = rd32(hw, I40E_PF_MDET_TX); 445961ae650dSJack F Vogel if (reg & I40E_PF_MDET_TX_VALID_MASK) { 446061ae650dSJack F Vogel wr32(hw, I40E_PF_MDET_TX, 0xFFFF); 446161ae650dSJack F Vogel device_printf(dev, 446261ae650dSJack F Vogel "MDD TX event is for this function 0x%08x", 446361ae650dSJack F Vogel reg); 446461ae650dSJack F Vogel pf_mdd_detected = true; 446561ae650dSJack F Vogel } 446661ae650dSJack F Vogel reg = rd32(hw, I40E_PF_MDET_RX); 446761ae650dSJack F Vogel if (reg & I40E_PF_MDET_RX_VALID_MASK) { 446861ae650dSJack F Vogel wr32(hw, I40E_PF_MDET_RX, 0xFFFF); 446961ae650dSJack F Vogel device_printf(dev, 447061ae650dSJack F Vogel "MDD RX event is for this function 0x%08x", 447161ae650dSJack F Vogel reg); 447261ae650dSJack F Vogel pf_mdd_detected = true; 447361ae650dSJack F Vogel } 447461ae650dSJack F Vogel } 447561ae650dSJack F Vogel 447661ae650dSJack F Vogel /* re-enable mdd interrupt cause */ 447761ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0_ENA); 447861ae650dSJack F Vogel reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 447961ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 448061ae650dSJack F Vogel ixl_flush(hw); 448161ae650dSJack F Vogel } 448261ae650dSJack F Vogel 448361ae650dSJack F Vogel static void 448461ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi) 448561ae650dSJack F Vogel { 448661ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 448761ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 448861ae650dSJack F Vogel 448961ae650dSJack F Vogel if (ixl_enable_msix) { 449061ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) 449161ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 449261ae650dSJack F Vogel } else 449361ae650dSJack F Vogel ixl_enable_legacy(hw); 449461ae650dSJack F Vogel } 449561ae650dSJack F Vogel 449661ae650dSJack F Vogel static void 449756c2c47bSJack F Vogel ixl_disable_rings_intr(struct ixl_vsi *vsi) 449861ae650dSJack F Vogel { 449961ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 450061ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 450161ae650dSJack F Vogel 450261ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) 450361ae650dSJack F Vogel ixl_disable_queue(hw, que->me); 450456c2c47bSJack F Vogel } 450556c2c47bSJack F Vogel 450656c2c47bSJack F Vogel static void 450756c2c47bSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi) 450856c2c47bSJack F Vogel { 450956c2c47bSJack F Vogel struct i40e_hw *hw = vsi->hw; 451056c2c47bSJack F Vogel 451156c2c47bSJack F Vogel if (ixl_enable_msix) 451256c2c47bSJack F Vogel ixl_disable_adminq(hw); 451356c2c47bSJack F Vogel else 451461ae650dSJack F Vogel ixl_disable_legacy(hw); 451561ae650dSJack F Vogel } 451661ae650dSJack F Vogel 451761ae650dSJack F Vogel static void 451861ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw) 451961ae650dSJack F Vogel { 452061ae650dSJack F Vogel u32 reg; 452161ae650dSJack F Vogel 452261ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 452361ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 452461ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 452561ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 452661ae650dSJack F Vogel ixl_flush(hw); 452761ae650dSJack F Vogel } 452861ae650dSJack F Vogel 452961ae650dSJack F Vogel static void 453061ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw) 453161ae650dSJack F Vogel { 453261ae650dSJack F Vogel u32 reg; 453361ae650dSJack F Vogel 453461ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 453561ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 4536223d846dSEric Joyner ixl_flush(hw); 453761ae650dSJack F Vogel } 453861ae650dSJack F Vogel 453961ae650dSJack F Vogel static void 454061ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id) 454161ae650dSJack F Vogel { 454261ae650dSJack F Vogel u32 reg; 454361ae650dSJack F Vogel 454461ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTLN_INTENA_MASK | 454561ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | 454661ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); 454761ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 454861ae650dSJack F Vogel } 454961ae650dSJack F Vogel 455061ae650dSJack F Vogel static void 455161ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id) 455261ae650dSJack F Vogel { 455361ae650dSJack F Vogel u32 reg; 455461ae650dSJack F Vogel 455561ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; 455661ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 455761ae650dSJack F Vogel } 455861ae650dSJack F Vogel 455961ae650dSJack F Vogel static void 456061ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw) 456161ae650dSJack F Vogel { 456261ae650dSJack F Vogel u32 reg; 456361ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 456461ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 456561ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 456661ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 456761ae650dSJack F Vogel } 456861ae650dSJack F Vogel 456961ae650dSJack F Vogel static void 457061ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw) 457161ae650dSJack F Vogel { 457261ae650dSJack F Vogel u32 reg; 457361ae650dSJack F Vogel 457461ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 457561ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 457661ae650dSJack F Vogel } 457761ae650dSJack F Vogel 457861ae650dSJack F Vogel static void 457961ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf) 458061ae650dSJack F Vogel { 458161ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 458261ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 458356c2c47bSJack F Vogel struct ixl_vf *vf; 458461ae650dSJack F Vogel 458561ae650dSJack F Vogel struct i40e_hw_port_stats *nsd = &pf->stats; 458661ae650dSJack F Vogel struct i40e_hw_port_stats *osd = &pf->stats_offsets; 458761ae650dSJack F Vogel 458861ae650dSJack F Vogel /* Update hw stats */ 458961ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port), 459061ae650dSJack F Vogel pf->stat_offsets_loaded, 459161ae650dSJack F Vogel &osd->crc_errors, &nsd->crc_errors); 459261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port), 459361ae650dSJack F Vogel pf->stat_offsets_loaded, 459461ae650dSJack F Vogel &osd->illegal_bytes, &nsd->illegal_bytes); 459561ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port), 459661ae650dSJack F Vogel I40E_GLPRT_GORCL(hw->port), 459761ae650dSJack F Vogel pf->stat_offsets_loaded, 459861ae650dSJack F Vogel &osd->eth.rx_bytes, &nsd->eth.rx_bytes); 459961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port), 460061ae650dSJack F Vogel I40E_GLPRT_GOTCL(hw->port), 460161ae650dSJack F Vogel pf->stat_offsets_loaded, 460261ae650dSJack F Vogel &osd->eth.tx_bytes, &nsd->eth.tx_bytes); 460361ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port), 460461ae650dSJack F Vogel pf->stat_offsets_loaded, 460561ae650dSJack F Vogel &osd->eth.rx_discards, 460661ae650dSJack F Vogel &nsd->eth.rx_discards); 460761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port), 460861ae650dSJack F Vogel I40E_GLPRT_UPRCL(hw->port), 460961ae650dSJack F Vogel pf->stat_offsets_loaded, 461061ae650dSJack F Vogel &osd->eth.rx_unicast, 461161ae650dSJack F Vogel &nsd->eth.rx_unicast); 461261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port), 461361ae650dSJack F Vogel I40E_GLPRT_UPTCL(hw->port), 461461ae650dSJack F Vogel pf->stat_offsets_loaded, 461561ae650dSJack F Vogel &osd->eth.tx_unicast, 461661ae650dSJack F Vogel &nsd->eth.tx_unicast); 461761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port), 461861ae650dSJack F Vogel I40E_GLPRT_MPRCL(hw->port), 461961ae650dSJack F Vogel pf->stat_offsets_loaded, 462061ae650dSJack F Vogel &osd->eth.rx_multicast, 462161ae650dSJack F Vogel &nsd->eth.rx_multicast); 462261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port), 462361ae650dSJack F Vogel I40E_GLPRT_MPTCL(hw->port), 462461ae650dSJack F Vogel pf->stat_offsets_loaded, 462561ae650dSJack F Vogel &osd->eth.tx_multicast, 462661ae650dSJack F Vogel &nsd->eth.tx_multicast); 462761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port), 462861ae650dSJack F Vogel I40E_GLPRT_BPRCL(hw->port), 462961ae650dSJack F Vogel pf->stat_offsets_loaded, 463061ae650dSJack F Vogel &osd->eth.rx_broadcast, 463161ae650dSJack F Vogel &nsd->eth.rx_broadcast); 463261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port), 463361ae650dSJack F Vogel I40E_GLPRT_BPTCL(hw->port), 463461ae650dSJack F Vogel pf->stat_offsets_loaded, 463561ae650dSJack F Vogel &osd->eth.tx_broadcast, 463661ae650dSJack F Vogel &nsd->eth.tx_broadcast); 463761ae650dSJack F Vogel 463861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port), 463961ae650dSJack F Vogel pf->stat_offsets_loaded, 464061ae650dSJack F Vogel &osd->tx_dropped_link_down, 464161ae650dSJack F Vogel &nsd->tx_dropped_link_down); 464261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port), 464361ae650dSJack F Vogel pf->stat_offsets_loaded, 464461ae650dSJack F Vogel &osd->mac_local_faults, 464561ae650dSJack F Vogel &nsd->mac_local_faults); 464661ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port), 464761ae650dSJack F Vogel pf->stat_offsets_loaded, 464861ae650dSJack F Vogel &osd->mac_remote_faults, 464961ae650dSJack F Vogel &nsd->mac_remote_faults); 465061ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port), 465161ae650dSJack F Vogel pf->stat_offsets_loaded, 465261ae650dSJack F Vogel &osd->rx_length_errors, 465361ae650dSJack F Vogel &nsd->rx_length_errors); 465461ae650dSJack F Vogel 465561ae650dSJack F Vogel /* Flow control (LFC) stats */ 465661ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port), 465761ae650dSJack F Vogel pf->stat_offsets_loaded, 465861ae650dSJack F Vogel &osd->link_xon_rx, &nsd->link_xon_rx); 465961ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port), 466061ae650dSJack F Vogel pf->stat_offsets_loaded, 466161ae650dSJack F Vogel &osd->link_xon_tx, &nsd->link_xon_tx); 466261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port), 466361ae650dSJack F Vogel pf->stat_offsets_loaded, 466461ae650dSJack F Vogel &osd->link_xoff_rx, &nsd->link_xoff_rx); 466561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port), 466661ae650dSJack F Vogel pf->stat_offsets_loaded, 466761ae650dSJack F Vogel &osd->link_xoff_tx, &nsd->link_xoff_tx); 466861ae650dSJack F Vogel 466961ae650dSJack F Vogel /* Packet size stats rx */ 467061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port), 467161ae650dSJack F Vogel I40E_GLPRT_PRC64L(hw->port), 467261ae650dSJack F Vogel pf->stat_offsets_loaded, 467361ae650dSJack F Vogel &osd->rx_size_64, &nsd->rx_size_64); 467461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port), 467561ae650dSJack F Vogel I40E_GLPRT_PRC127L(hw->port), 467661ae650dSJack F Vogel pf->stat_offsets_loaded, 467761ae650dSJack F Vogel &osd->rx_size_127, &nsd->rx_size_127); 467861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port), 467961ae650dSJack F Vogel I40E_GLPRT_PRC255L(hw->port), 468061ae650dSJack F Vogel pf->stat_offsets_loaded, 468161ae650dSJack F Vogel &osd->rx_size_255, &nsd->rx_size_255); 468261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port), 468361ae650dSJack F Vogel I40E_GLPRT_PRC511L(hw->port), 468461ae650dSJack F Vogel pf->stat_offsets_loaded, 468561ae650dSJack F Vogel &osd->rx_size_511, &nsd->rx_size_511); 468661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port), 468761ae650dSJack F Vogel I40E_GLPRT_PRC1023L(hw->port), 468861ae650dSJack F Vogel pf->stat_offsets_loaded, 468961ae650dSJack F Vogel &osd->rx_size_1023, &nsd->rx_size_1023); 469061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port), 469161ae650dSJack F Vogel I40E_GLPRT_PRC1522L(hw->port), 469261ae650dSJack F Vogel pf->stat_offsets_loaded, 469361ae650dSJack F Vogel &osd->rx_size_1522, &nsd->rx_size_1522); 469461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port), 469561ae650dSJack F Vogel I40E_GLPRT_PRC9522L(hw->port), 469661ae650dSJack F Vogel pf->stat_offsets_loaded, 469761ae650dSJack F Vogel &osd->rx_size_big, &nsd->rx_size_big); 469861ae650dSJack F Vogel 469961ae650dSJack F Vogel /* Packet size stats tx */ 470061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port), 470161ae650dSJack F Vogel I40E_GLPRT_PTC64L(hw->port), 470261ae650dSJack F Vogel pf->stat_offsets_loaded, 470361ae650dSJack F Vogel &osd->tx_size_64, &nsd->tx_size_64); 470461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port), 470561ae650dSJack F Vogel I40E_GLPRT_PTC127L(hw->port), 470661ae650dSJack F Vogel pf->stat_offsets_loaded, 470761ae650dSJack F Vogel &osd->tx_size_127, &nsd->tx_size_127); 470861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port), 470961ae650dSJack F Vogel I40E_GLPRT_PTC255L(hw->port), 471061ae650dSJack F Vogel pf->stat_offsets_loaded, 471161ae650dSJack F Vogel &osd->tx_size_255, &nsd->tx_size_255); 471261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port), 471361ae650dSJack F Vogel I40E_GLPRT_PTC511L(hw->port), 471461ae650dSJack F Vogel pf->stat_offsets_loaded, 471561ae650dSJack F Vogel &osd->tx_size_511, &nsd->tx_size_511); 471661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port), 471761ae650dSJack F Vogel I40E_GLPRT_PTC1023L(hw->port), 471861ae650dSJack F Vogel pf->stat_offsets_loaded, 471961ae650dSJack F Vogel &osd->tx_size_1023, &nsd->tx_size_1023); 472061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port), 472161ae650dSJack F Vogel I40E_GLPRT_PTC1522L(hw->port), 472261ae650dSJack F Vogel pf->stat_offsets_loaded, 472361ae650dSJack F Vogel &osd->tx_size_1522, &nsd->tx_size_1522); 472461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port), 472561ae650dSJack F Vogel I40E_GLPRT_PTC9522L(hw->port), 472661ae650dSJack F Vogel pf->stat_offsets_loaded, 472761ae650dSJack F Vogel &osd->tx_size_big, &nsd->tx_size_big); 472861ae650dSJack F Vogel 472961ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port), 473061ae650dSJack F Vogel pf->stat_offsets_loaded, 473161ae650dSJack F Vogel &osd->rx_undersize, &nsd->rx_undersize); 473261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port), 473361ae650dSJack F Vogel pf->stat_offsets_loaded, 473461ae650dSJack F Vogel &osd->rx_fragments, &nsd->rx_fragments); 473561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port), 473661ae650dSJack F Vogel pf->stat_offsets_loaded, 473761ae650dSJack F Vogel &osd->rx_oversize, &nsd->rx_oversize); 473861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port), 473961ae650dSJack F Vogel pf->stat_offsets_loaded, 474061ae650dSJack F Vogel &osd->rx_jabber, &nsd->rx_jabber); 474161ae650dSJack F Vogel pf->stat_offsets_loaded = true; 474261ae650dSJack F Vogel /* End hw stats */ 474361ae650dSJack F Vogel 474461ae650dSJack F Vogel /* Update vsi stats */ 474556c2c47bSJack F Vogel ixl_update_vsi_stats(vsi); 474661ae650dSJack F Vogel 474756c2c47bSJack F Vogel for (int i = 0; i < pf->num_vfs; i++) { 474856c2c47bSJack F Vogel vf = &pf->vfs[i]; 474956c2c47bSJack F Vogel if (vf->vf_flags & VF_FLAG_ENABLED) 475056c2c47bSJack F Vogel ixl_update_eth_stats(&pf->vfs[i].vsi); 475156c2c47bSJack F Vogel } 475261ae650dSJack F Vogel } 475361ae650dSJack F Vogel 47546c426059SEric Joyner static int 47556c426059SEric Joyner ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf) 47566c426059SEric Joyner { 47576c426059SEric Joyner struct i40e_hw *hw = &pf->hw; 47586c426059SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 47596c426059SEric Joyner device_t dev = pf->dev; 47606c426059SEric Joyner bool is_up = false; 47616c426059SEric Joyner int error = 0; 47626c426059SEric Joyner 47636c426059SEric Joyner is_up = !!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING); 47646c426059SEric Joyner 47656c426059SEric Joyner /* Teardown */ 47666c426059SEric Joyner if (is_up) 47676c426059SEric Joyner ixl_stop(pf); 47686c426059SEric Joyner error = i40e_shutdown_lan_hmc(hw); 47696c426059SEric Joyner if (error) 47706c426059SEric Joyner device_printf(dev, 47716c426059SEric Joyner "Shutdown LAN HMC failed with code %d\n", error); 47726c426059SEric Joyner ixl_disable_adminq(hw); 47736c426059SEric Joyner ixl_teardown_adminq_msix(pf); 47746c426059SEric Joyner error = i40e_shutdown_adminq(hw); 47756c426059SEric Joyner if (error) 47766c426059SEric Joyner device_printf(dev, 47776c426059SEric Joyner "Shutdown Admin queue failed with code %d\n", error); 47786c426059SEric Joyner 47796c426059SEric Joyner /* Setup */ 47806c426059SEric Joyner error = i40e_init_adminq(hw); 47816c426059SEric Joyner if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) { 47826c426059SEric Joyner device_printf(dev, "Unable to initialize Admin Queue, error %d\n", 47836c426059SEric Joyner error); 47846c426059SEric Joyner } 47856c426059SEric Joyner error = ixl_setup_adminq_msix(pf); 47866c426059SEric Joyner if (error) { 47876c426059SEric Joyner device_printf(dev, "ixl_setup_adminq_msix error: %d\n", 47886c426059SEric Joyner error); 47896c426059SEric Joyner } 47906c426059SEric Joyner ixl_configure_intr0_msix(pf); 47916c426059SEric Joyner ixl_enable_adminq(hw); 47926c426059SEric Joyner error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 47936c426059SEric Joyner hw->func_caps.num_rx_qp, 0, 0); 47946c426059SEric Joyner if (error) { 47956c426059SEric Joyner device_printf(dev, "init_lan_hmc failed: %d\n", error); 47966c426059SEric Joyner } 47976c426059SEric Joyner error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 47986c426059SEric Joyner if (error) { 47996c426059SEric Joyner device_printf(dev, "configure_lan_hmc failed: %d\n", error); 48006c426059SEric Joyner } 48016c426059SEric Joyner if (is_up) 48026c426059SEric Joyner ixl_init(pf); 48036c426059SEric Joyner 48046c426059SEric Joyner return (0); 48056c426059SEric Joyner } 48066c426059SEric Joyner 48076c426059SEric Joyner static void 48086c426059SEric Joyner ixl_handle_empr_reset(struct ixl_pf *pf) 48096c426059SEric Joyner { 48106c426059SEric Joyner struct i40e_hw *hw = &pf->hw; 48116c426059SEric Joyner device_t dev = pf->dev; 48126c426059SEric Joyner int count = 0; 48136c426059SEric Joyner u32 reg; 48146c426059SEric Joyner 48156c426059SEric Joyner /* Typically finishes within 3-4 seconds */ 48166c426059SEric Joyner while (count++ < 100) { 48176c426059SEric Joyner reg = rd32(hw, I40E_GLGEN_RSTAT) 48186c426059SEric Joyner & I40E_GLGEN_RSTAT_DEVSTATE_MASK; 48196c426059SEric Joyner if (reg) 48206c426059SEric Joyner i40e_msec_delay(100); 48216c426059SEric Joyner else 48226c426059SEric Joyner break; 48236c426059SEric Joyner } 48246c426059SEric Joyner #ifdef IXL_DEBUG 48256c426059SEric Joyner // Reset-related 48266c426059SEric Joyner device_printf(dev, "EMPR reset wait count: %d\n", count); 48276c426059SEric Joyner #endif 48286c426059SEric Joyner 48296c426059SEric Joyner device_printf(dev, "Rebuilding driver state...\n"); 48306c426059SEric Joyner ixl_rebuild_hw_structs_after_reset(pf); 48316c426059SEric Joyner device_printf(dev, "Rebuilding driver state done.\n"); 48326c426059SEric Joyner 48336c426059SEric Joyner atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); 48346c426059SEric Joyner } 48356c426059SEric Joyner 483661ae650dSJack F Vogel /* 483761ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts 483861ae650dSJack F Vogel ** - do outside interrupt since it might sleep 483961ae650dSJack F Vogel */ 484061ae650dSJack F Vogel static void 484161ae650dSJack F Vogel ixl_do_adminq(void *context, int pending) 484261ae650dSJack F Vogel { 484361ae650dSJack F Vogel struct ixl_pf *pf = context; 484461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 484561ae650dSJack F Vogel struct i40e_arq_event_info event; 484661ae650dSJack F Vogel i40e_status ret; 4847223d846dSEric Joyner device_t dev = pf->dev; 48486c426059SEric Joyner u32 loop = 0; 484961ae650dSJack F Vogel u16 opcode, result; 485061ae650dSJack F Vogel 4851fdb6f38aSEric Joyner if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { 48526c426059SEric Joyner /* Flag cleared at end of this function */ 48536c426059SEric Joyner ixl_handle_empr_reset(pf); 4854fdb6f38aSEric Joyner return; 4855fdb6f38aSEric Joyner } 4856fdb6f38aSEric Joyner 48576c426059SEric Joyner /* Admin Queue handling */ 4858e5100ee2SJack F Vogel event.buf_len = IXL_AQ_BUF_SZ; 4859e5100ee2SJack F Vogel event.msg_buf = malloc(event.buf_len, 486061ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 486161ae650dSJack F Vogel if (!event.msg_buf) { 4862223d846dSEric Joyner device_printf(dev, "%s: Unable to allocate memory for Admin" 4863223d846dSEric Joyner " Queue event!\n", __func__); 486461ae650dSJack F Vogel return; 486561ae650dSJack F Vogel } 486661ae650dSJack F Vogel 486756c2c47bSJack F Vogel IXL_PF_LOCK(pf); 486861ae650dSJack F Vogel /* clean and process any events */ 486961ae650dSJack F Vogel do { 487061ae650dSJack F Vogel ret = i40e_clean_arq_element(hw, &event, &result); 487161ae650dSJack F Vogel if (ret) 487261ae650dSJack F Vogel break; 487361ae650dSJack F Vogel opcode = LE16_TO_CPU(event.desc.opcode); 4874223d846dSEric Joyner #ifdef IXL_DEBUG 48756c426059SEric Joyner device_printf(dev, "%s: Admin Queue event: %#06x\n", __func__, 48766c426059SEric Joyner opcode); 4877223d846dSEric Joyner #endif 487861ae650dSJack F Vogel switch (opcode) { 487961ae650dSJack F Vogel case i40e_aqc_opc_get_link_status: 488056c2c47bSJack F Vogel ixl_link_event(pf, &event); 488161ae650dSJack F Vogel break; 488261ae650dSJack F Vogel case i40e_aqc_opc_send_msg_to_pf: 488356c2c47bSJack F Vogel #ifdef PCI_IOV 488456c2c47bSJack F Vogel ixl_handle_vf_msg(pf, &event); 488556c2c47bSJack F Vogel #endif 488661ae650dSJack F Vogel break; 488761ae650dSJack F Vogel case i40e_aqc_opc_event_lan_overflow: 488861ae650dSJack F Vogel default: 488961ae650dSJack F Vogel break; 489061ae650dSJack F Vogel } 489161ae650dSJack F Vogel 489261ae650dSJack F Vogel } while (result && (loop++ < IXL_ADM_LIMIT)); 489361ae650dSJack F Vogel 489461ae650dSJack F Vogel free(event.msg_buf, M_DEVBUF); 489561ae650dSJack F Vogel 489656c2c47bSJack F Vogel /* 489756c2c47bSJack F Vogel * If there are still messages to process, reschedule ourselves. 489856c2c47bSJack F Vogel * Otherwise, re-enable our interrupt and go to sleep. 489956c2c47bSJack F Vogel */ 490056c2c47bSJack F Vogel if (result > 0) 490156c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 490261ae650dSJack F Vogel else 4903223d846dSEric Joyner ixl_enable_adminq(hw); 490456c2c47bSJack F Vogel 490556c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 490661ae650dSJack F Vogel } 490761ae650dSJack F Vogel 490861ae650dSJack F Vogel /** 490961ae650dSJack F Vogel * Update VSI-specific ethernet statistics counters. 491061ae650dSJack F Vogel **/ 49116d011ad5SEric Joyner void 49126d011ad5SEric Joyner ixl_update_eth_stats(struct ixl_vsi *vsi) 491361ae650dSJack F Vogel { 491461ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 491561ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 491661ae650dSJack F Vogel struct i40e_eth_stats *es; 491761ae650dSJack F Vogel struct i40e_eth_stats *oes; 49184b443922SGleb Smirnoff struct i40e_hw_port_stats *nsd; 491961ae650dSJack F Vogel u16 stat_idx = vsi->info.stat_counter_idx; 492061ae650dSJack F Vogel 492161ae650dSJack F Vogel es = &vsi->eth_stats; 492261ae650dSJack F Vogel oes = &vsi->eth_stats_offsets; 49234b443922SGleb Smirnoff nsd = &pf->stats; 492461ae650dSJack F Vogel 492561ae650dSJack F Vogel /* Gather up the stats that the hw collects */ 492661ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx), 492761ae650dSJack F Vogel vsi->stat_offsets_loaded, 492861ae650dSJack F Vogel &oes->tx_errors, &es->tx_errors); 492961ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx), 493061ae650dSJack F Vogel vsi->stat_offsets_loaded, 493161ae650dSJack F Vogel &oes->rx_discards, &es->rx_discards); 493261ae650dSJack F Vogel 493361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx), 493461ae650dSJack F Vogel I40E_GLV_GORCL(stat_idx), 493561ae650dSJack F Vogel vsi->stat_offsets_loaded, 493661ae650dSJack F Vogel &oes->rx_bytes, &es->rx_bytes); 493761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx), 493861ae650dSJack F Vogel I40E_GLV_UPRCL(stat_idx), 493961ae650dSJack F Vogel vsi->stat_offsets_loaded, 494061ae650dSJack F Vogel &oes->rx_unicast, &es->rx_unicast); 494161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx), 494261ae650dSJack F Vogel I40E_GLV_MPRCL(stat_idx), 494361ae650dSJack F Vogel vsi->stat_offsets_loaded, 494461ae650dSJack F Vogel &oes->rx_multicast, &es->rx_multicast); 494561ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx), 494661ae650dSJack F Vogel I40E_GLV_BPRCL(stat_idx), 494761ae650dSJack F Vogel vsi->stat_offsets_loaded, 494861ae650dSJack F Vogel &oes->rx_broadcast, &es->rx_broadcast); 494961ae650dSJack F Vogel 495061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx), 495161ae650dSJack F Vogel I40E_GLV_GOTCL(stat_idx), 495261ae650dSJack F Vogel vsi->stat_offsets_loaded, 495361ae650dSJack F Vogel &oes->tx_bytes, &es->tx_bytes); 495461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx), 495561ae650dSJack F Vogel I40E_GLV_UPTCL(stat_idx), 495661ae650dSJack F Vogel vsi->stat_offsets_loaded, 495761ae650dSJack F Vogel &oes->tx_unicast, &es->tx_unicast); 495861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx), 495961ae650dSJack F Vogel I40E_GLV_MPTCL(stat_idx), 496061ae650dSJack F Vogel vsi->stat_offsets_loaded, 496161ae650dSJack F Vogel &oes->tx_multicast, &es->tx_multicast); 496261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx), 496361ae650dSJack F Vogel I40E_GLV_BPTCL(stat_idx), 496461ae650dSJack F Vogel vsi->stat_offsets_loaded, 496561ae650dSJack F Vogel &oes->tx_broadcast, &es->tx_broadcast); 496661ae650dSJack F Vogel vsi->stat_offsets_loaded = true; 496756c2c47bSJack F Vogel } 496856c2c47bSJack F Vogel 496956c2c47bSJack F Vogel static void 497056c2c47bSJack F Vogel ixl_update_vsi_stats(struct ixl_vsi *vsi) 497156c2c47bSJack F Vogel { 497256c2c47bSJack F Vogel struct ixl_pf *pf; 497356c2c47bSJack F Vogel struct ifnet *ifp; 497456c2c47bSJack F Vogel struct i40e_eth_stats *es; 497556c2c47bSJack F Vogel u64 tx_discards; 497656c2c47bSJack F Vogel 497756c2c47bSJack F Vogel struct i40e_hw_port_stats *nsd; 497856c2c47bSJack F Vogel 497956c2c47bSJack F Vogel pf = vsi->back; 498056c2c47bSJack F Vogel ifp = vsi->ifp; 498156c2c47bSJack F Vogel es = &vsi->eth_stats; 498256c2c47bSJack F Vogel nsd = &pf->stats; 498356c2c47bSJack F Vogel 498456c2c47bSJack F Vogel ixl_update_eth_stats(vsi); 498561ae650dSJack F Vogel 49864b443922SGleb Smirnoff tx_discards = es->tx_discards + nsd->tx_dropped_link_down; 498756c2c47bSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) 49884b443922SGleb Smirnoff tx_discards += vsi->queues[i].txr.br->br_drops; 498961ae650dSJack F Vogel 49904b443922SGleb Smirnoff /* Update ifnet stats */ 49914b443922SGleb Smirnoff IXL_SET_IPACKETS(vsi, es->rx_unicast + 49924b443922SGleb Smirnoff es->rx_multicast + 49934b443922SGleb Smirnoff es->rx_broadcast); 49944b443922SGleb Smirnoff IXL_SET_OPACKETS(vsi, es->tx_unicast + 49954b443922SGleb Smirnoff es->tx_multicast + 49964b443922SGleb Smirnoff es->tx_broadcast); 49974b443922SGleb Smirnoff IXL_SET_IBYTES(vsi, es->rx_bytes); 49984b443922SGleb Smirnoff IXL_SET_OBYTES(vsi, es->tx_bytes); 49994b443922SGleb Smirnoff IXL_SET_IMCASTS(vsi, es->rx_multicast); 50004b443922SGleb Smirnoff IXL_SET_OMCASTS(vsi, es->tx_multicast); 50014b443922SGleb Smirnoff 500256c2c47bSJack F Vogel IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes + 500356c2c47bSJack F Vogel nsd->rx_undersize + nsd->rx_oversize + nsd->rx_fragments + 500456c2c47bSJack F Vogel nsd->rx_jabber); 50054b443922SGleb Smirnoff IXL_SET_OERRORS(vsi, es->tx_errors); 50064b443922SGleb Smirnoff IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards); 50074b443922SGleb Smirnoff IXL_SET_OQDROPS(vsi, tx_discards); 50084b443922SGleb Smirnoff IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol); 50094b443922SGleb Smirnoff IXL_SET_COLLISIONS(vsi, 0); 501061ae650dSJack F Vogel } 501161ae650dSJack F Vogel 501261ae650dSJack F Vogel /** 501361ae650dSJack F Vogel * Reset all of the stats for the given pf 501461ae650dSJack F Vogel **/ 501561ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf) 501661ae650dSJack F Vogel { 501761ae650dSJack F Vogel bzero(&pf->stats, sizeof(struct i40e_hw_port_stats)); 501861ae650dSJack F Vogel bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats)); 501961ae650dSJack F Vogel pf->stat_offsets_loaded = false; 502061ae650dSJack F Vogel } 502161ae650dSJack F Vogel 502261ae650dSJack F Vogel /** 502361ae650dSJack F Vogel * Resets all stats of the given vsi 502461ae650dSJack F Vogel **/ 502561ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi) 502661ae650dSJack F Vogel { 502761ae650dSJack F Vogel bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats)); 502861ae650dSJack F Vogel bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats)); 502961ae650dSJack F Vogel vsi->stat_offsets_loaded = false; 503061ae650dSJack F Vogel } 503161ae650dSJack F Vogel 503261ae650dSJack F Vogel /** 503361ae650dSJack F Vogel * Read and update a 48 bit stat from the hw 503461ae650dSJack F Vogel * 503561ae650dSJack F Vogel * Since the device stats are not reset at PFReset, they likely will not 503661ae650dSJack F Vogel * be zeroed when the driver starts. We'll save the first values read 503761ae650dSJack F Vogel * and use them as offsets to be subtracted from the raw values in order 503861ae650dSJack F Vogel * to report stats that count from zero. 503961ae650dSJack F Vogel **/ 504061ae650dSJack F Vogel static void 504161ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg, 504261ae650dSJack F Vogel bool offset_loaded, u64 *offset, u64 *stat) 504361ae650dSJack F Vogel { 504461ae650dSJack F Vogel u64 new_data; 504561ae650dSJack F Vogel 5046ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__) 504761ae650dSJack F Vogel new_data = rd64(hw, loreg); 504861ae650dSJack F Vogel #else 504961ae650dSJack F Vogel /* 505061ae650dSJack F Vogel * Use two rd32's instead of one rd64; FreeBSD versions before 505161ae650dSJack F Vogel * 10 don't support 8 byte bus reads/writes. 505261ae650dSJack F Vogel */ 505361ae650dSJack F Vogel new_data = rd32(hw, loreg); 505461ae650dSJack F Vogel new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32; 505561ae650dSJack F Vogel #endif 505661ae650dSJack F Vogel 505761ae650dSJack F Vogel if (!offset_loaded) 505861ae650dSJack F Vogel *offset = new_data; 505961ae650dSJack F Vogel if (new_data >= *offset) 506061ae650dSJack F Vogel *stat = new_data - *offset; 506161ae650dSJack F Vogel else 506261ae650dSJack F Vogel *stat = (new_data + ((u64)1 << 48)) - *offset; 506361ae650dSJack F Vogel *stat &= 0xFFFFFFFFFFFFULL; 506461ae650dSJack F Vogel } 506561ae650dSJack F Vogel 506661ae650dSJack F Vogel /** 506761ae650dSJack F Vogel * Read and update a 32 bit stat from the hw 506861ae650dSJack F Vogel **/ 506961ae650dSJack F Vogel static void 507061ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg, 507161ae650dSJack F Vogel bool offset_loaded, u64 *offset, u64 *stat) 507261ae650dSJack F Vogel { 507361ae650dSJack F Vogel u32 new_data; 507461ae650dSJack F Vogel 507561ae650dSJack F Vogel new_data = rd32(hw, reg); 507661ae650dSJack F Vogel if (!offset_loaded) 507761ae650dSJack F Vogel *offset = new_data; 507861ae650dSJack F Vogel if (new_data >= *offset) 507961ae650dSJack F Vogel *stat = (u32)(new_data - *offset); 508061ae650dSJack F Vogel else 508161ae650dSJack F Vogel *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); 508261ae650dSJack F Vogel } 508361ae650dSJack F Vogel 5084fdb6f38aSEric Joyner static void 5085fdb6f38aSEric Joyner ixl_add_device_sysctls(struct ixl_pf *pf) 5086fdb6f38aSEric Joyner { 5087fdb6f38aSEric Joyner device_t dev = pf->dev; 5088fdb6f38aSEric Joyner 5089fdb6f38aSEric Joyner /* Set up sysctls */ 5090fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5091fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5092fdb6f38aSEric Joyner OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, 509395bb0504SEric Joyner pf, 0, ixl_set_flowcntl, "I", IXL_SYSCTL_HELP_FC); 5094fdb6f38aSEric Joyner 5095fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5096fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5097fdb6f38aSEric Joyner OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, 509895bb0504SEric Joyner pf, 0, ixl_set_advertise, "I", IXL_SYSCTL_HELP_SET_ADVERTISE); 5099fdb6f38aSEric Joyner 5100fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5101fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5102fdb6f38aSEric Joyner OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD, 5103fdb6f38aSEric Joyner pf, 0, ixl_current_speed, "A", "Current Port Speed"); 5104fdb6f38aSEric Joyner 5105fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5106fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5107fdb6f38aSEric Joyner OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD, 5108fdb6f38aSEric Joyner pf, 0, ixl_sysctl_show_fw, "A", "Firmware version"); 5109fdb6f38aSEric Joyner 51106d011ad5SEric Joyner #if 0 5111fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5112fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5113fdb6f38aSEric Joyner OID_AUTO, "rx_itr", CTLFLAG_RW, 51146d011ad5SEric Joyner &ixl_rx_itr, 0, "RX ITR"); 5115fdb6f38aSEric Joyner 5116fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5117fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5118fdb6f38aSEric Joyner OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW, 5119fdb6f38aSEric Joyner &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR"); 5120fdb6f38aSEric Joyner 5121fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5122fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5123fdb6f38aSEric Joyner OID_AUTO, "tx_itr", CTLFLAG_RW, 51246d011ad5SEric Joyner &ixl_tx_itr, 0, "TX ITR"); 5125fdb6f38aSEric Joyner 5126fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5127fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5128fdb6f38aSEric Joyner OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW, 5129fdb6f38aSEric Joyner &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR"); 51306d011ad5SEric Joyner #endif 5131fdb6f38aSEric Joyner 5132fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL 5133fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5134fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5135fdb6f38aSEric Joyner OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0, 5136fdb6f38aSEric Joyner ixl_debug_info, "I", "Debug Information"); 5137fdb6f38aSEric Joyner 513895bb0504SEric Joyner /* Shared-code debug message level */ 5139fdb6f38aSEric Joyner SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 5140fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5141fdb6f38aSEric Joyner OID_AUTO, "debug_mask", CTLFLAG_RW, 5142fdb6f38aSEric Joyner &pf->hw.debug_mask, 0, "Debug Message Level"); 5143fdb6f38aSEric Joyner 5144fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5145fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5146fdb6f38aSEric Joyner OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD, 514795bb0504SEric Joyner pf, 0, ixl_sysctl_link_status, "A", IXL_SYSCTL_HELP_LINK_STATUS); 5148fdb6f38aSEric Joyner 5149fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5150fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5151fdb6f38aSEric Joyner OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD, 5152fdb6f38aSEric Joyner pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities"); 5153fdb6f38aSEric Joyner 5154fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5155fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5156fdb6f38aSEric Joyner OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD, 5157fdb6f38aSEric Joyner pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List"); 5158fdb6f38aSEric Joyner 5159fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5160fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5161fdb6f38aSEric Joyner OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD, 5162fdb6f38aSEric Joyner pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation"); 5163fdb6f38aSEric Joyner 5164fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5165fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5166fdb6f38aSEric Joyner OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD, 5167fdb6f38aSEric Joyner pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration"); 516895bb0504SEric Joyner 516995bb0504SEric Joyner #ifdef PCI_IOV 517095bb0504SEric Joyner SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 517195bb0504SEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 517295bb0504SEric Joyner OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl, 517395bb0504SEric Joyner 0, "PF/VF Virtual Channel debug level"); 517495bb0504SEric Joyner #endif 5175fdb6f38aSEric Joyner #endif 5176fdb6f38aSEric Joyner } 5177fdb6f38aSEric Joyner 517861ae650dSJack F Vogel /* 517961ae650dSJack F Vogel ** Set flow control using sysctl: 518061ae650dSJack F Vogel ** 0 - off 518161ae650dSJack F Vogel ** 1 - rx pause 518261ae650dSJack F Vogel ** 2 - tx pause 518361ae650dSJack F Vogel ** 3 - full 518461ae650dSJack F Vogel */ 518561ae650dSJack F Vogel static int 518661ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS) 518761ae650dSJack F Vogel { 518861ae650dSJack F Vogel /* 518961ae650dSJack F Vogel * TODO: ensure tx CRC by hardware should be enabled 519061ae650dSJack F Vogel * if tx flow control is enabled. 5191223d846dSEric Joyner * ^ N/A for 40G ports 519261ae650dSJack F Vogel */ 519361ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 519461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 519561ae650dSJack F Vogel device_t dev = pf->dev; 51966c426059SEric Joyner int requested_fc, error = 0; 519761ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 519861ae650dSJack F Vogel u8 fc_aq_err = 0; 519961ae650dSJack F Vogel 5200b6c8f260SJack F Vogel /* Get request */ 52016c426059SEric Joyner requested_fc = pf->fc; 52026c426059SEric Joyner error = sysctl_handle_int(oidp, &requested_fc, 0, req); 520361ae650dSJack F Vogel if ((error) || (req->newptr == NULL)) 520461ae650dSJack F Vogel return (error); 52056c426059SEric Joyner if (requested_fc < 0 || requested_fc > 3) { 520661ae650dSJack F Vogel device_printf(dev, 520761ae650dSJack F Vogel "Invalid fc mode; valid modes are 0 through 3\n"); 520861ae650dSJack F Vogel return (EINVAL); 520961ae650dSJack F Vogel } 521061ae650dSJack F Vogel 521161ae650dSJack F Vogel /* Set fc ability for port */ 52126c426059SEric Joyner hw->fc.requested_mode = requested_fc; 521361ae650dSJack F Vogel aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE); 521461ae650dSJack F Vogel if (aq_error) { 521561ae650dSJack F Vogel device_printf(dev, 521661ae650dSJack F Vogel "%s: Error setting new fc mode %d; fc_err %#x\n", 521761ae650dSJack F Vogel __func__, aq_error, fc_aq_err); 5218223d846dSEric Joyner return (EIO); 521961ae650dSJack F Vogel } 52206c426059SEric Joyner pf->fc = requested_fc; 522161ae650dSJack F Vogel 5222223d846dSEric Joyner /* Get new link state */ 5223223d846dSEric Joyner i40e_msec_delay(250); 5224223d846dSEric Joyner hw->phy.get_link_info = TRUE; 5225223d846dSEric Joyner i40e_get_link_status(hw, &pf->link_up); 5226223d846dSEric Joyner 522761ae650dSJack F Vogel return (0); 522861ae650dSJack F Vogel } 522961ae650dSJack F Vogel 523061ae650dSJack F Vogel static int 523161ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS) 523261ae650dSJack F Vogel { 523361ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 523461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 523561ae650dSJack F Vogel int error = 0, index = 0; 523661ae650dSJack F Vogel 523761ae650dSJack F Vogel char *speeds[] = { 523861ae650dSJack F Vogel "Unknown", 523961ae650dSJack F Vogel "100M", 524061ae650dSJack F Vogel "1G", 524161ae650dSJack F Vogel "10G", 524261ae650dSJack F Vogel "40G", 524361ae650dSJack F Vogel "20G" 524461ae650dSJack F Vogel }; 524561ae650dSJack F Vogel 524661ae650dSJack F Vogel ixl_update_link_status(pf); 524761ae650dSJack F Vogel 524861ae650dSJack F Vogel switch (hw->phy.link_info.link_speed) { 524961ae650dSJack F Vogel case I40E_LINK_SPEED_100MB: 525061ae650dSJack F Vogel index = 1; 525161ae650dSJack F Vogel break; 525261ae650dSJack F Vogel case I40E_LINK_SPEED_1GB: 525361ae650dSJack F Vogel index = 2; 525461ae650dSJack F Vogel break; 525561ae650dSJack F Vogel case I40E_LINK_SPEED_10GB: 525661ae650dSJack F Vogel index = 3; 525761ae650dSJack F Vogel break; 525861ae650dSJack F Vogel case I40E_LINK_SPEED_40GB: 525961ae650dSJack F Vogel index = 4; 526061ae650dSJack F Vogel break; 526161ae650dSJack F Vogel case I40E_LINK_SPEED_20GB: 526261ae650dSJack F Vogel index = 5; 526361ae650dSJack F Vogel break; 526461ae650dSJack F Vogel case I40E_LINK_SPEED_UNKNOWN: 526561ae650dSJack F Vogel default: 526661ae650dSJack F Vogel index = 0; 526761ae650dSJack F Vogel break; 526861ae650dSJack F Vogel } 526961ae650dSJack F Vogel 527061ae650dSJack F Vogel error = sysctl_handle_string(oidp, speeds[index], 527161ae650dSJack F Vogel strlen(speeds[index]), req); 527261ae650dSJack F Vogel return (error); 527361ae650dSJack F Vogel } 527461ae650dSJack F Vogel 5275e5100ee2SJack F Vogel static int 5276e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds) 5277e5100ee2SJack F Vogel { 5278e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 5279e5100ee2SJack F Vogel device_t dev = pf->dev; 5280e5100ee2SJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 5281e5100ee2SJack F Vogel struct i40e_aq_set_phy_config config; 5282e5100ee2SJack F Vogel enum i40e_status_code aq_error = 0; 5283e5100ee2SJack F Vogel 5284e5100ee2SJack F Vogel /* Get current capability information */ 5285b6c8f260SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 5286b6c8f260SJack F Vogel FALSE, FALSE, &abilities, NULL); 5287e5100ee2SJack F Vogel if (aq_error) { 5288b6c8f260SJack F Vogel device_printf(dev, 5289b6c8f260SJack F Vogel "%s: Error getting phy capabilities %d," 5290e5100ee2SJack F Vogel " aq error: %d\n", __func__, aq_error, 5291e5100ee2SJack F Vogel hw->aq.asq_last_status); 5292e5100ee2SJack F Vogel return (EAGAIN); 5293e5100ee2SJack F Vogel } 5294e5100ee2SJack F Vogel 5295e5100ee2SJack F Vogel /* Prepare new config */ 5296e5100ee2SJack F Vogel bzero(&config, sizeof(config)); 5297e5100ee2SJack F Vogel config.phy_type = abilities.phy_type; 5298e5100ee2SJack F Vogel config.abilities = abilities.abilities 5299e5100ee2SJack F Vogel | I40E_AQ_PHY_ENABLE_ATOMIC_LINK; 5300e5100ee2SJack F Vogel config.eee_capability = abilities.eee_capability; 5301e5100ee2SJack F Vogel config.eeer = abilities.eeer_val; 5302e5100ee2SJack F Vogel config.low_power_ctrl = abilities.d3_lpan; 5303e5100ee2SJack F Vogel /* Translate into aq cmd link_speed */ 53041d767a8eSEric Joyner if (speeds & 0x10) 53051d767a8eSEric Joyner config.link_speed |= I40E_LINK_SPEED_40GB; 530656c2c47bSJack F Vogel if (speeds & 0x8) 530756c2c47bSJack F Vogel config.link_speed |= I40E_LINK_SPEED_20GB; 5308e5100ee2SJack F Vogel if (speeds & 0x4) 5309e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_10GB; 5310e5100ee2SJack F Vogel if (speeds & 0x2) 5311e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_1GB; 5312e5100ee2SJack F Vogel if (speeds & 0x1) 5313e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_100MB; 5314e5100ee2SJack F Vogel 5315e5100ee2SJack F Vogel /* Do aq command & restart link */ 5316e5100ee2SJack F Vogel aq_error = i40e_aq_set_phy_config(hw, &config, NULL); 5317e5100ee2SJack F Vogel if (aq_error) { 5318b6c8f260SJack F Vogel device_printf(dev, 5319b6c8f260SJack F Vogel "%s: Error setting new phy config %d," 5320e5100ee2SJack F Vogel " aq error: %d\n", __func__, aq_error, 5321e5100ee2SJack F Vogel hw->aq.asq_last_status); 5322e5100ee2SJack F Vogel return (EAGAIN); 5323e5100ee2SJack F Vogel } 5324e5100ee2SJack F Vogel 5325393c4bb1SJack F Vogel /* 5326393c4bb1SJack F Vogel ** This seems a bit heavy handed, but we 5327393c4bb1SJack F Vogel ** need to get a reinit on some devices 5328393c4bb1SJack F Vogel */ 5329393c4bb1SJack F Vogel IXL_PF_LOCK(pf); 5330223d846dSEric Joyner ixl_stop_locked(pf); 5331393c4bb1SJack F Vogel ixl_init_locked(pf); 5332393c4bb1SJack F Vogel IXL_PF_UNLOCK(pf); 5333393c4bb1SJack F Vogel 5334e5100ee2SJack F Vogel return (0); 5335e5100ee2SJack F Vogel } 5336e5100ee2SJack F Vogel 533761ae650dSJack F Vogel /* 533861ae650dSJack F Vogel ** Control link advertise speed: 533961ae650dSJack F Vogel ** Flags: 534061ae650dSJack F Vogel ** 0x1 - advertise 100 Mb 534161ae650dSJack F Vogel ** 0x2 - advertise 1G 534261ae650dSJack F Vogel ** 0x4 - advertise 10G 534356c2c47bSJack F Vogel ** 0x8 - advertise 20G 53441d767a8eSEric Joyner ** 0x10 - advertise 40G 534561ae650dSJack F Vogel ** 53461d767a8eSEric Joyner ** Set to 0 to disable link 534761ae650dSJack F Vogel */ 534861ae650dSJack F Vogel static int 534961ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS) 535061ae650dSJack F Vogel { 535161ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 535261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 535361ae650dSJack F Vogel device_t dev = pf->dev; 535461ae650dSJack F Vogel int requested_ls = 0; 535561ae650dSJack F Vogel int error = 0; 535661ae650dSJack F Vogel 535761ae650dSJack F Vogel /* Read in new mode */ 535861ae650dSJack F Vogel requested_ls = pf->advertised_speed; 535961ae650dSJack F Vogel error = sysctl_handle_int(oidp, &requested_ls, 0, req); 536061ae650dSJack F Vogel if ((error) || (req->newptr == NULL)) 536161ae650dSJack F Vogel return (error); 536256c2c47bSJack F Vogel /* Check for sane value */ 53631d767a8eSEric Joyner if (requested_ls > 0x10) { 536456c2c47bSJack F Vogel device_printf(dev, "Invalid advertised speed; " 53651d767a8eSEric Joyner "valid modes are 0x1 through 0x10\n"); 536661ae650dSJack F Vogel return (EINVAL); 536761ae650dSJack F Vogel } 536856c2c47bSJack F Vogel /* Then check for validity based on adapter type */ 536956c2c47bSJack F Vogel switch (hw->device_id) { 537056c2c47bSJack F Vogel case I40E_DEV_ID_10G_BASE_T: 5371ac83ea83SEric Joyner case I40E_DEV_ID_10G_BASE_T4: 53721d767a8eSEric Joyner /* BaseT */ 53731d767a8eSEric Joyner if (requested_ls & ~(0x7)) { 537456c2c47bSJack F Vogel device_printf(dev, 53751d767a8eSEric Joyner "Only 100M/1G/10G speeds supported on this device.\n"); 537656c2c47bSJack F Vogel return (EINVAL); 537756c2c47bSJack F Vogel } 537856c2c47bSJack F Vogel break; 537956c2c47bSJack F Vogel case I40E_DEV_ID_20G_KR2: 5380ac83ea83SEric Joyner case I40E_DEV_ID_20G_KR2_A: 53811d767a8eSEric Joyner /* 20G */ 53821d767a8eSEric Joyner if (requested_ls & ~(0xE)) { 538356c2c47bSJack F Vogel device_printf(dev, 53841d767a8eSEric Joyner "Only 1G/10G/20G speeds supported on this device.\n"); 53851d767a8eSEric Joyner return (EINVAL); 53861d767a8eSEric Joyner } 53871d767a8eSEric Joyner break; 53881d767a8eSEric Joyner case I40E_DEV_ID_KX_B: 53891d767a8eSEric Joyner case I40E_DEV_ID_QSFP_A: 53901d767a8eSEric Joyner case I40E_DEV_ID_QSFP_B: 53911d767a8eSEric Joyner /* 40G */ 53921d767a8eSEric Joyner if (requested_ls & ~(0x10)) { 53931d767a8eSEric Joyner device_printf(dev, 53941d767a8eSEric Joyner "Only 40G speeds supported on this device.\n"); 539556c2c47bSJack F Vogel return (EINVAL); 539656c2c47bSJack F Vogel } 539756c2c47bSJack F Vogel break; 539856c2c47bSJack F Vogel default: 53991d767a8eSEric Joyner /* 10G (1G) */ 54001d767a8eSEric Joyner if (requested_ls & ~(0x6)) { 540156c2c47bSJack F Vogel device_printf(dev, 540256c2c47bSJack F Vogel "Only 1/10Gbs speeds are supported on this device.\n"); 540356c2c47bSJack F Vogel return (EINVAL); 540456c2c47bSJack F Vogel } 540556c2c47bSJack F Vogel break; 540656c2c47bSJack F Vogel } 540761ae650dSJack F Vogel 540861ae650dSJack F Vogel /* Exit if no change */ 540961ae650dSJack F Vogel if (pf->advertised_speed == requested_ls) 541061ae650dSJack F Vogel return (0); 541161ae650dSJack F Vogel 5412e5100ee2SJack F Vogel error = ixl_set_advertised_speeds(pf, requested_ls); 5413e5100ee2SJack F Vogel if (error) 5414e5100ee2SJack F Vogel return (error); 541561ae650dSJack F Vogel 541661ae650dSJack F Vogel pf->advertised_speed = requested_ls; 541761ae650dSJack F Vogel ixl_update_link_status(pf); 541861ae650dSJack F Vogel return (0); 541961ae650dSJack F Vogel } 542061ae650dSJack F Vogel 542161ae650dSJack F Vogel /* 542261ae650dSJack F Vogel ** Get the width and transaction speed of 542361ae650dSJack F Vogel ** the bus this adapter is plugged into. 542461ae650dSJack F Vogel */ 542561ae650dSJack F Vogel static u16 542661ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev) 542761ae650dSJack F Vogel { 542861ae650dSJack F Vogel u16 link; 542961ae650dSJack F Vogel u32 offset; 543061ae650dSJack F Vogel 543161ae650dSJack F Vogel /* Get the PCI Express Capabilities offset */ 543261ae650dSJack F Vogel pci_find_cap(dev, PCIY_EXPRESS, &offset); 543361ae650dSJack F Vogel 543461ae650dSJack F Vogel /* ...and read the Link Status Register */ 543561ae650dSJack F Vogel link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 543661ae650dSJack F Vogel 543761ae650dSJack F Vogel switch (link & I40E_PCI_LINK_WIDTH) { 543861ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_1: 543961ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x1; 544061ae650dSJack F Vogel break; 544161ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_2: 544261ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x2; 544361ae650dSJack F Vogel break; 544461ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_4: 544561ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x4; 544661ae650dSJack F Vogel break; 544761ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_8: 544861ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x8; 544961ae650dSJack F Vogel break; 545061ae650dSJack F Vogel default: 545161ae650dSJack F Vogel hw->bus.width = i40e_bus_width_unknown; 545261ae650dSJack F Vogel break; 545361ae650dSJack F Vogel } 545461ae650dSJack F Vogel 545561ae650dSJack F Vogel switch (link & I40E_PCI_LINK_SPEED) { 545661ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_2500: 545761ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_2500; 545861ae650dSJack F Vogel break; 545961ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_5000: 546061ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_5000; 546161ae650dSJack F Vogel break; 546261ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_8000: 546361ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_8000; 546461ae650dSJack F Vogel break; 546561ae650dSJack F Vogel default: 546661ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_unknown; 546761ae650dSJack F Vogel break; 546861ae650dSJack F Vogel } 546961ae650dSJack F Vogel 547061ae650dSJack F Vogel device_printf(dev,"PCI Express Bus: Speed %s %s\n", 547161ae650dSJack F Vogel ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s": 547261ae650dSJack F Vogel (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s": 547361ae650dSJack F Vogel (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"), 547461ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" : 547561ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" : 547661ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" : 547761ae650dSJack F Vogel ("Unknown")); 547861ae650dSJack F Vogel 547961ae650dSJack F Vogel if ((hw->bus.width <= i40e_bus_width_pcie_x8) && 548061ae650dSJack F Vogel (hw->bus.speed < i40e_bus_speed_8000)) { 548161ae650dSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 548256c2c47bSJack F Vogel " for this device\n may be insufficient for" 548356c2c47bSJack F Vogel " optimal performance.\n"); 548461ae650dSJack F Vogel device_printf(dev, "For expected performance a x8 " 548561ae650dSJack F Vogel "PCIE Gen3 slot is required.\n"); 548661ae650dSJack F Vogel } 548761ae650dSJack F Vogel 548861ae650dSJack F Vogel return (link); 548961ae650dSJack F Vogel } 549061ae650dSJack F Vogel 5491e5100ee2SJack F Vogel static int 5492e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS) 5493e5100ee2SJack F Vogel { 5494e5100ee2SJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 5495e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 54961d767a8eSEric Joyner struct sbuf *sbuf; 5497e5100ee2SJack F Vogel 54981d767a8eSEric Joyner sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 54991d767a8eSEric Joyner ixl_nvm_version_str(hw, sbuf); 55001d767a8eSEric Joyner sbuf_finish(sbuf); 55011d767a8eSEric Joyner sbuf_delete(sbuf); 55021d767a8eSEric Joyner 55031d767a8eSEric Joyner return 0; 5504e5100ee2SJack F Vogel } 5505e5100ee2SJack F Vogel 55066d011ad5SEric Joyner #ifdef IXL_DEBUG 55076d011ad5SEric Joyner static void 55086c426059SEric Joyner ixl_print_nvm_cmd(device_t dev, struct i40e_nvm_access *nvma) 55096c426059SEric Joyner { 55106c426059SEric Joyner if ((nvma->command == I40E_NVM_READ) && 55116c426059SEric Joyner ((nvma->config & 0xFF) == 0xF) && 55126c426059SEric Joyner (((nvma->config & 0xF00) >> 8) == 0xF) && 55136c426059SEric Joyner (nvma->offset == 0) && 55146c426059SEric Joyner (nvma->data_size == 1)) { 55156c426059SEric Joyner // device_printf(dev, "- Get Driver Status Command\n"); 55166c426059SEric Joyner } 55176c426059SEric Joyner else if (nvma->command == I40E_NVM_READ) { 55186c426059SEric Joyner 55196c426059SEric Joyner } 55206c426059SEric Joyner else { 55216c426059SEric Joyner switch (nvma->command) { 55226c426059SEric Joyner case 0xB: 55236c426059SEric Joyner device_printf(dev, "- command: I40E_NVM_READ\n"); 55246c426059SEric Joyner break; 55256c426059SEric Joyner case 0xC: 55266c426059SEric Joyner device_printf(dev, "- command: I40E_NVM_WRITE\n"); 55276c426059SEric Joyner break; 55286c426059SEric Joyner default: 55296c426059SEric Joyner device_printf(dev, "- command: unknown 0x%08x\n", nvma->command); 55306c426059SEric Joyner break; 55316c426059SEric Joyner } 55326c426059SEric Joyner 55336c426059SEric Joyner device_printf(dev, "- config (ptr) : 0x%02x\n", nvma->config & 0xFF); 55346c426059SEric Joyner device_printf(dev, "- config (flags): 0x%01x\n", (nvma->config & 0xF00) >> 8); 55356c426059SEric Joyner device_printf(dev, "- offset : 0x%08x\n", nvma->offset); 55366c426059SEric Joyner device_printf(dev, "- data_s : 0x%08x\n", nvma->data_size); 55376c426059SEric Joyner } 55386c426059SEric Joyner } 55396d011ad5SEric Joyner #endif 55406c426059SEric Joyner 5541223d846dSEric Joyner static int 5542223d846dSEric Joyner ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd) 5543223d846dSEric Joyner { 5544223d846dSEric Joyner struct i40e_hw *hw = &pf->hw; 5545223d846dSEric Joyner struct i40e_nvm_access *nvma; 5546223d846dSEric Joyner device_t dev = pf->dev; 5547223d846dSEric Joyner enum i40e_status_code status = 0; 5548223d846dSEric Joyner int perrno; 5549223d846dSEric Joyner 5550223d846dSEric Joyner DEBUGFUNC("ixl_handle_nvmupd_cmd"); 5551223d846dSEric Joyner 55526c426059SEric Joyner /* Sanity checks */ 5553223d846dSEric Joyner if (ifd->ifd_len < sizeof(struct i40e_nvm_access) || 5554223d846dSEric Joyner ifd->ifd_data == NULL) { 55556c426059SEric Joyner device_printf(dev, "%s: incorrect ifdrv length or data pointer\n", 55566c426059SEric Joyner __func__); 55576c426059SEric Joyner device_printf(dev, "%s: ifdrv length: %lu, sizeof(struct i40e_nvm_access): %lu\n", 55586c426059SEric Joyner __func__, ifd->ifd_len, sizeof(struct i40e_nvm_access)); 55596c426059SEric Joyner device_printf(dev, "%s: data pointer: %p\n", __func__, 55606c426059SEric Joyner ifd->ifd_data); 5561223d846dSEric Joyner return (EINVAL); 5562223d846dSEric Joyner } 5563223d846dSEric Joyner 5564223d846dSEric Joyner nvma = (struct i40e_nvm_access *)ifd->ifd_data; 5565223d846dSEric Joyner 55666c426059SEric Joyner #ifdef IXL_DEBUG 55676c426059SEric Joyner ixl_print_nvm_cmd(dev, nvma); 55686c426059SEric Joyner #endif 55696c426059SEric Joyner 5570fdb6f38aSEric Joyner if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { 5571fdb6f38aSEric Joyner int count = 0; 5572fdb6f38aSEric Joyner while (count++ < 100) { 5573fdb6f38aSEric Joyner i40e_msec_delay(100); 5574fdb6f38aSEric Joyner if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) 5575fdb6f38aSEric Joyner break; 5576fdb6f38aSEric Joyner } 5577fdb6f38aSEric Joyner } 5578fdb6f38aSEric Joyner 5579fdb6f38aSEric Joyner if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) { 5580fdb6f38aSEric Joyner IXL_PF_LOCK(pf); 5581223d846dSEric Joyner status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno); 5582fdb6f38aSEric Joyner IXL_PF_UNLOCK(pf); 5583fdb6f38aSEric Joyner } else { 5584fdb6f38aSEric Joyner perrno = -EBUSY; 5585fdb6f38aSEric Joyner } 5586fdb6f38aSEric Joyner 55877f70bec6SEric Joyner if (status) 55887f70bec6SEric Joyner device_printf(dev, "i40e_nvmupd_command status %d, perrno %d\n", 55897f70bec6SEric Joyner status, perrno); 5590223d846dSEric Joyner 5591fdb6f38aSEric Joyner /* 5592fdb6f38aSEric Joyner * -EPERM is actually ERESTART, which the kernel interprets as it needing 5593fdb6f38aSEric Joyner * to run this ioctl again. So use -EACCES for -EPERM instead. 5594fdb6f38aSEric Joyner */ 55957f70bec6SEric Joyner if (perrno == -EPERM) 55967f70bec6SEric Joyner return (-EACCES); 55977f70bec6SEric Joyner else 55987f70bec6SEric Joyner return (perrno); 5599223d846dSEric Joyner } 5600e5100ee2SJack F Vogel 5601393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL 560261ae650dSJack F Vogel static int 560361ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS) 560461ae650dSJack F Vogel { 560561ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 560661ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 560761ae650dSJack F Vogel struct i40e_link_status link_status; 560861ae650dSJack F Vogel char buf[512]; 560961ae650dSJack F Vogel 561061ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 561161ae650dSJack F Vogel 561261ae650dSJack F Vogel aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL); 561361ae650dSJack F Vogel if (aq_error) { 561461ae650dSJack F Vogel printf("i40e_aq_get_link_info() error %d\n", aq_error); 561561ae650dSJack F Vogel return (EPERM); 561661ae650dSJack F Vogel } 561761ae650dSJack F Vogel 561861ae650dSJack F Vogel sprintf(buf, "\n" 561961ae650dSJack F Vogel "PHY Type : %#04x\n" 562061ae650dSJack F Vogel "Speed : %#04x\n" 562161ae650dSJack F Vogel "Link info: %#04x\n" 562261ae650dSJack F Vogel "AN info : %#04x\n" 562395bb0504SEric Joyner "Ext info : %#04x\n" 562495bb0504SEric Joyner "Max Frame: %d\n" 56251d767a8eSEric Joyner "Pacing : %#04x\n" 56261d767a8eSEric Joyner "CRC En? : %d", 562761ae650dSJack F Vogel link_status.phy_type, link_status.link_speed, 562861ae650dSJack F Vogel link_status.link_info, link_status.an_info, 562995bb0504SEric Joyner link_status.ext_info, link_status.max_frame_size, 56301d767a8eSEric Joyner link_status.pacing, link_status.crc_enable); 563161ae650dSJack F Vogel 563261ae650dSJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 563361ae650dSJack F Vogel } 563461ae650dSJack F Vogel 563561ae650dSJack F Vogel static int 563661ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS) 563761ae650dSJack F Vogel { 563861ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 563961ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 564061ae650dSJack F Vogel char buf[512]; 564161ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 564261ae650dSJack F Vogel 564356c2c47bSJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 564456c2c47bSJack F Vogel 564556c2c47bSJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 564656c2c47bSJack F Vogel TRUE, FALSE, &abilities, NULL); 564761ae650dSJack F Vogel if (aq_error) { 564861ae650dSJack F Vogel printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error); 564961ae650dSJack F Vogel return (EPERM); 565061ae650dSJack F Vogel } 565161ae650dSJack F Vogel 565261ae650dSJack F Vogel sprintf(buf, "\n" 565361ae650dSJack F Vogel "PHY Type : %#010x\n" 565461ae650dSJack F Vogel "Speed : %#04x\n" 565561ae650dSJack F Vogel "Abilities: %#04x\n" 565661ae650dSJack F Vogel "EEE cap : %#06x\n" 565761ae650dSJack F Vogel "EEER reg : %#010x\n" 565861ae650dSJack F Vogel "D3 Lpan : %#04x", 565956c2c47bSJack F Vogel abilities.phy_type, abilities.link_speed, 566056c2c47bSJack F Vogel abilities.abilities, abilities.eee_capability, 566156c2c47bSJack F Vogel abilities.eeer_val, abilities.d3_lpan); 566261ae650dSJack F Vogel 566361ae650dSJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 566461ae650dSJack F Vogel } 566561ae650dSJack F Vogel 566661ae650dSJack F Vogel static int 566761ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS) 566861ae650dSJack F Vogel { 566961ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 567061ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 567161ae650dSJack F Vogel struct ixl_mac_filter *f; 567261ae650dSJack F Vogel char *buf, *buf_i; 567361ae650dSJack F Vogel 567461ae650dSJack F Vogel int error = 0; 567561ae650dSJack F Vogel int ftl_len = 0; 567661ae650dSJack F Vogel int ftl_counter = 0; 567761ae650dSJack F Vogel int buf_len = 0; 567861ae650dSJack F Vogel int entry_len = 42; 567961ae650dSJack F Vogel 568061ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 568161ae650dSJack F Vogel ftl_len++; 568261ae650dSJack F Vogel } 568361ae650dSJack F Vogel 568461ae650dSJack F Vogel if (ftl_len < 1) { 568561ae650dSJack F Vogel sysctl_handle_string(oidp, "(none)", 6, req); 568661ae650dSJack F Vogel return (0); 568761ae650dSJack F Vogel } 568861ae650dSJack F Vogel 568961ae650dSJack F Vogel buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2; 569061ae650dSJack F Vogel buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT); 569161ae650dSJack F Vogel 569261ae650dSJack F Vogel sprintf(buf_i++, "\n"); 569361ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 569461ae650dSJack F Vogel sprintf(buf_i, 569561ae650dSJack F Vogel MAC_FORMAT ", vlan %4d, flags %#06x", 569661ae650dSJack F Vogel MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags); 569761ae650dSJack F Vogel buf_i += entry_len; 569861ae650dSJack F Vogel /* don't print '\n' for last entry */ 569961ae650dSJack F Vogel if (++ftl_counter != ftl_len) { 570061ae650dSJack F Vogel sprintf(buf_i, "\n"); 570161ae650dSJack F Vogel buf_i++; 570261ae650dSJack F Vogel } 570361ae650dSJack F Vogel } 570461ae650dSJack F Vogel 570561ae650dSJack F Vogel error = sysctl_handle_string(oidp, buf, strlen(buf), req); 570661ae650dSJack F Vogel if (error) 570761ae650dSJack F Vogel printf("sysctl error: %d\n", error); 570861ae650dSJack F Vogel free(buf, M_DEVBUF); 570961ae650dSJack F Vogel return error; 571061ae650dSJack F Vogel } 571161ae650dSJack F Vogel 571261ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14 571361ae650dSJack F Vogel static int 5714393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b) 5715393c4bb1SJack F Vogel { 5716393c4bb1SJack F Vogel const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two; 5717be771cdaSJack F Vogel one = (const struct i40e_aqc_switch_resource_alloc_element_resp *)a; 5718be771cdaSJack F Vogel two = (const struct i40e_aqc_switch_resource_alloc_element_resp *)b; 5719393c4bb1SJack F Vogel 5720393c4bb1SJack F Vogel return ((int)one->resource_type - (int)two->resource_type); 5721393c4bb1SJack F Vogel } 5722393c4bb1SJack F Vogel 5723fdb6f38aSEric Joyner /* 5724fdb6f38aSEric Joyner * Longest string length: 25 5725fdb6f38aSEric Joyner */ 5726fdb6f38aSEric Joyner static char * 5727fdb6f38aSEric Joyner ixl_switch_res_type_string(u8 type) 5728fdb6f38aSEric Joyner { 5729fdb6f38aSEric Joyner static char * ixl_switch_res_type_strings[0x14] = { 5730fdb6f38aSEric Joyner "VEB", 5731fdb6f38aSEric Joyner "VSI", 5732fdb6f38aSEric Joyner "Perfect Match MAC address", 5733fdb6f38aSEric Joyner "S-tag", 5734fdb6f38aSEric Joyner "(Reserved)", 5735fdb6f38aSEric Joyner "Multicast hash entry", 5736fdb6f38aSEric Joyner "Unicast hash entry", 5737fdb6f38aSEric Joyner "VLAN", 5738fdb6f38aSEric Joyner "VSI List entry", 5739fdb6f38aSEric Joyner "(Reserved)", 5740fdb6f38aSEric Joyner "VLAN Statistic Pool", 5741fdb6f38aSEric Joyner "Mirror Rule", 5742fdb6f38aSEric Joyner "Queue Set", 5743fdb6f38aSEric Joyner "Inner VLAN Forward filter", 5744fdb6f38aSEric Joyner "(Reserved)", 5745fdb6f38aSEric Joyner "Inner MAC", 5746fdb6f38aSEric Joyner "IP", 5747fdb6f38aSEric Joyner "GRE/VN1 Key", 5748fdb6f38aSEric Joyner "VN2 Key", 5749fdb6f38aSEric Joyner "Tunneling Port" 5750fdb6f38aSEric Joyner }; 5751fdb6f38aSEric Joyner 5752fdb6f38aSEric Joyner if (type < 0x14) 5753fdb6f38aSEric Joyner return ixl_switch_res_type_strings[type]; 5754fdb6f38aSEric Joyner else 5755fdb6f38aSEric Joyner return "(Reserved)"; 5756fdb6f38aSEric Joyner } 5757fdb6f38aSEric Joyner 5758393c4bb1SJack F Vogel static int 5759e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS) 576061ae650dSJack F Vogel { 576161ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 576261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 576361ae650dSJack F Vogel device_t dev = pf->dev; 576461ae650dSJack F Vogel struct sbuf *buf; 576561ae650dSJack F Vogel int error = 0; 576661ae650dSJack F Vogel 576761ae650dSJack F Vogel u8 num_entries; 576861ae650dSJack F Vogel struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE]; 576961ae650dSJack F Vogel 5770a48d00d2SEric Joyner buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 577161ae650dSJack F Vogel if (!buf) { 577261ae650dSJack F Vogel device_printf(dev, "Could not allocate sbuf for output.\n"); 577361ae650dSJack F Vogel return (ENOMEM); 577461ae650dSJack F Vogel } 577561ae650dSJack F Vogel 5776393c4bb1SJack F Vogel bzero(resp, sizeof(resp)); 577761ae650dSJack F Vogel error = i40e_aq_get_switch_resource_alloc(hw, &num_entries, 577861ae650dSJack F Vogel resp, 577961ae650dSJack F Vogel IXL_SW_RES_SIZE, 578061ae650dSJack F Vogel NULL); 578161ae650dSJack F Vogel if (error) { 578256c2c47bSJack F Vogel device_printf(dev, 578356c2c47bSJack F Vogel "%s: get_switch_resource_alloc() error %d, aq error %d\n", 578461ae650dSJack F Vogel __func__, error, hw->aq.asq_last_status); 578561ae650dSJack F Vogel sbuf_delete(buf); 578661ae650dSJack F Vogel return error; 578761ae650dSJack F Vogel } 5788393c4bb1SJack F Vogel 5789393c4bb1SJack F Vogel /* Sort entries by type for display */ 5790393c4bb1SJack F Vogel qsort(resp, num_entries, 5791393c4bb1SJack F Vogel sizeof(struct i40e_aqc_switch_resource_alloc_element_resp), 5792393c4bb1SJack F Vogel &ixl_res_alloc_cmp); 579361ae650dSJack F Vogel 579461ae650dSJack F Vogel sbuf_cat(buf, "\n"); 5795393c4bb1SJack F Vogel sbuf_printf(buf, "# of entries: %d\n", num_entries); 579661ae650dSJack F Vogel sbuf_printf(buf, 579761ae650dSJack F Vogel " Type | Guaranteed | Total | Used | Un-allocated\n" 579861ae650dSJack F Vogel " | (this) | (all) | (this) | (all) \n"); 579961ae650dSJack F Vogel for (int i = 0; i < num_entries; i++) { 580061ae650dSJack F Vogel sbuf_printf(buf, 5801fdb6f38aSEric Joyner "%25s | %10d %5d %6d %12d", 5802fdb6f38aSEric Joyner ixl_switch_res_type_string(resp[i].resource_type), 580361ae650dSJack F Vogel resp[i].guaranteed, 580461ae650dSJack F Vogel resp[i].total, 580561ae650dSJack F Vogel resp[i].used, 580661ae650dSJack F Vogel resp[i].total_unalloced); 580761ae650dSJack F Vogel if (i < num_entries - 1) 580861ae650dSJack F Vogel sbuf_cat(buf, "\n"); 580961ae650dSJack F Vogel } 581061ae650dSJack F Vogel 581161ae650dSJack F Vogel error = sbuf_finish(buf); 5812ac83ea83SEric Joyner if (error) 5813a48d00d2SEric Joyner device_printf(dev, "Error finishing sbuf: %d\n", error); 5814a48d00d2SEric Joyner 5815ac83ea83SEric Joyner sbuf_delete(buf); 5816ac83ea83SEric Joyner return error; 5817e5100ee2SJack F Vogel } 581861ae650dSJack F Vogel 5819e5100ee2SJack F Vogel /* 5820e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and 5821e5100ee2SJack F Vogel ** finish it for caller. 5822fdb6f38aSEric Joyner ** 5823fdb6f38aSEric Joyner ** XXX: Cannot use the SEID for this, since there is no longer a 5824fdb6f38aSEric Joyner ** fixed mapping between SEID and element type. 5825e5100ee2SJack F Vogel */ 5826e5100ee2SJack F Vogel static char * 5827fdb6f38aSEric Joyner ixl_switch_element_string(struct sbuf *s, 5828fdb6f38aSEric Joyner struct i40e_aqc_switch_config_element_resp *element) 5829e5100ee2SJack F Vogel { 5830e5100ee2SJack F Vogel sbuf_clear(s); 5831e5100ee2SJack F Vogel 5832fdb6f38aSEric Joyner switch (element->element_type) { 5833fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_MAC: 5834fdb6f38aSEric Joyner sbuf_printf(s, "MAC %3d", element->element_info); 5835fdb6f38aSEric Joyner break; 5836fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_PF: 5837fdb6f38aSEric Joyner sbuf_printf(s, "PF %3d", element->element_info); 5838fdb6f38aSEric Joyner break; 5839fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_VF: 5840fdb6f38aSEric Joyner sbuf_printf(s, "VF %3d", element->element_info); 5841fdb6f38aSEric Joyner break; 5842fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_EMP: 5843e5100ee2SJack F Vogel sbuf_cat(s, "EMP"); 5844fdb6f38aSEric Joyner break; 5845fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_BMC: 5846fdb6f38aSEric Joyner sbuf_cat(s, "BMC"); 5847fdb6f38aSEric Joyner break; 5848fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_PV: 5849fdb6f38aSEric Joyner sbuf_cat(s, "PV"); 5850fdb6f38aSEric Joyner break; 5851fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_VEB: 5852fdb6f38aSEric Joyner sbuf_cat(s, "VEB"); 5853fdb6f38aSEric Joyner break; 5854fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_PA: 5855fdb6f38aSEric Joyner sbuf_cat(s, "PA"); 5856fdb6f38aSEric Joyner break; 5857fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_VSI: 5858fdb6f38aSEric Joyner sbuf_printf(s, "VSI %3d", element->element_info); 5859fdb6f38aSEric Joyner break; 5860fdb6f38aSEric Joyner default: 5861fdb6f38aSEric Joyner sbuf_cat(s, "?"); 5862fdb6f38aSEric Joyner break; 5863fdb6f38aSEric Joyner } 5864e5100ee2SJack F Vogel 5865e5100ee2SJack F Vogel sbuf_finish(s); 5866e5100ee2SJack F Vogel return sbuf_data(s); 5867e5100ee2SJack F Vogel } 5868e5100ee2SJack F Vogel 5869e5100ee2SJack F Vogel static int 5870e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS) 5871e5100ee2SJack F Vogel { 5872e5100ee2SJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 5873e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 5874e5100ee2SJack F Vogel device_t dev = pf->dev; 5875e5100ee2SJack F Vogel struct sbuf *buf; 5876e5100ee2SJack F Vogel struct sbuf *nmbuf; 5877e5100ee2SJack F Vogel int error = 0; 5878fdb6f38aSEric Joyner u16 next = 0; 5879e5100ee2SJack F Vogel u8 aq_buf[I40E_AQ_LARGE_BUF]; 5880e5100ee2SJack F Vogel 5881e5100ee2SJack F Vogel struct i40e_aqc_get_switch_config_resp *sw_config; 5882e5100ee2SJack F Vogel sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 5883e5100ee2SJack F Vogel 5884a48d00d2SEric Joyner buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5885e5100ee2SJack F Vogel if (!buf) { 5886e5100ee2SJack F Vogel device_printf(dev, "Could not allocate sbuf for sysctl output.\n"); 5887e5100ee2SJack F Vogel return (ENOMEM); 5888e5100ee2SJack F Vogel } 5889e5100ee2SJack F Vogel 5890e5100ee2SJack F Vogel error = i40e_aq_get_switch_config(hw, sw_config, 5891e5100ee2SJack F Vogel sizeof(aq_buf), &next, NULL); 5892e5100ee2SJack F Vogel if (error) { 589356c2c47bSJack F Vogel device_printf(dev, 589456c2c47bSJack F Vogel "%s: aq_get_switch_config() error %d, aq error %d\n", 5895e5100ee2SJack F Vogel __func__, error, hw->aq.asq_last_status); 5896e5100ee2SJack F Vogel sbuf_delete(buf); 5897e5100ee2SJack F Vogel return error; 5898e5100ee2SJack F Vogel } 5899fdb6f38aSEric Joyner if (next) 5900fdb6f38aSEric Joyner device_printf(dev, "%s: TODO: get more config with SEID %d\n", 5901fdb6f38aSEric Joyner __func__, next); 5902e5100ee2SJack F Vogel 5903e5100ee2SJack F Vogel nmbuf = sbuf_new_auto(); 5904e5100ee2SJack F Vogel if (!nmbuf) { 5905e5100ee2SJack F Vogel device_printf(dev, "Could not allocate sbuf for name output.\n"); 5906a48d00d2SEric Joyner sbuf_delete(buf); 5907e5100ee2SJack F Vogel return (ENOMEM); 5908e5100ee2SJack F Vogel } 5909e5100ee2SJack F Vogel 5910e5100ee2SJack F Vogel sbuf_cat(buf, "\n"); 5911e5100ee2SJack F Vogel // Assuming <= 255 elements in switch 5912fdb6f38aSEric Joyner sbuf_printf(buf, "# of reported elements: %d\n", sw_config->header.num_reported); 5913fdb6f38aSEric Joyner sbuf_printf(buf, "total # of elements: %d\n", sw_config->header.num_total); 5914e5100ee2SJack F Vogel /* Exclude: 5915e5100ee2SJack F Vogel ** Revision -- all elements are revision 1 for now 5916e5100ee2SJack F Vogel */ 5917e5100ee2SJack F Vogel sbuf_printf(buf, 5918e5100ee2SJack F Vogel "SEID ( Name ) | Uplink | Downlink | Conn Type\n" 5919e5100ee2SJack F Vogel " | | | (uplink)\n"); 5920e5100ee2SJack F Vogel for (int i = 0; i < sw_config->header.num_reported; i++) { 5921e5100ee2SJack F Vogel // "%4d (%8s) | %8s %8s %#8x", 5922e5100ee2SJack F Vogel sbuf_printf(buf, "%4d", sw_config->element[i].seid); 5923e5100ee2SJack F Vogel sbuf_cat(buf, " "); 592456c2c47bSJack F Vogel sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf, 5925fdb6f38aSEric Joyner &sw_config->element[i])); 5926e5100ee2SJack F Vogel sbuf_cat(buf, " | "); 5927fdb6f38aSEric Joyner sbuf_printf(buf, "%8d", sw_config->element[i].uplink_seid); 5928e5100ee2SJack F Vogel sbuf_cat(buf, " "); 5929fdb6f38aSEric Joyner sbuf_printf(buf, "%8d", sw_config->element[i].downlink_seid); 5930e5100ee2SJack F Vogel sbuf_cat(buf, " "); 5931e5100ee2SJack F Vogel sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type); 5932e5100ee2SJack F Vogel if (i < sw_config->header.num_reported - 1) 5933e5100ee2SJack F Vogel sbuf_cat(buf, "\n"); 5934e5100ee2SJack F Vogel } 5935e5100ee2SJack F Vogel sbuf_delete(nmbuf); 5936e5100ee2SJack F Vogel 5937e5100ee2SJack F Vogel error = sbuf_finish(buf); 5938ac83ea83SEric Joyner if (error) 5939a48d00d2SEric Joyner device_printf(dev, "Error finishing sbuf: %d\n", error); 5940a48d00d2SEric Joyner 5941e5100ee2SJack F Vogel sbuf_delete(buf); 5942e5100ee2SJack F Vogel 5943e5100ee2SJack F Vogel return (error); 594461ae650dSJack F Vogel } 59451d767a8eSEric Joyner 59461d767a8eSEric Joyner static int 59471d767a8eSEric Joyner ixl_debug_info(SYSCTL_HANDLER_ARGS) 59481d767a8eSEric Joyner { 59491d767a8eSEric Joyner struct ixl_pf *pf; 59501d767a8eSEric Joyner int error, input = 0; 59511d767a8eSEric Joyner 59521d767a8eSEric Joyner error = sysctl_handle_int(oidp, &input, 0, req); 59531d767a8eSEric Joyner 59541d767a8eSEric Joyner if (error || !req->newptr) 59551d767a8eSEric Joyner return (error); 59561d767a8eSEric Joyner 59571d767a8eSEric Joyner if (input == 1) { 59581d767a8eSEric Joyner pf = (struct ixl_pf *)arg1; 59591d767a8eSEric Joyner ixl_print_debug_info(pf); 59601d767a8eSEric Joyner } 59611d767a8eSEric Joyner 59621d767a8eSEric Joyner return (error); 59631d767a8eSEric Joyner } 59641d767a8eSEric Joyner 59651d767a8eSEric Joyner static void 59661d767a8eSEric Joyner ixl_print_debug_info(struct ixl_pf *pf) 59671d767a8eSEric Joyner { 59681d767a8eSEric Joyner struct i40e_hw *hw = &pf->hw; 59691d767a8eSEric Joyner struct ixl_vsi *vsi = &pf->vsi; 59701d767a8eSEric Joyner struct ixl_queue *que = vsi->queues; 59711d767a8eSEric Joyner struct rx_ring *rxr = &que->rxr; 59721d767a8eSEric Joyner struct tx_ring *txr = &que->txr; 59731d767a8eSEric Joyner u32 reg; 59741d767a8eSEric Joyner 59751d767a8eSEric Joyner 59761d767a8eSEric Joyner printf("Queue irqs = %jx\n", (uintmax_t)que->irqs); 59771d767a8eSEric Joyner printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq); 59781d767a8eSEric Joyner printf("RX next check = %x\n", rxr->next_check); 59791d767a8eSEric Joyner printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done); 59801d767a8eSEric Joyner printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets); 59811d767a8eSEric Joyner printf("TX desc avail = %x\n", txr->avail); 59821d767a8eSEric Joyner 59831d767a8eSEric Joyner reg = rd32(hw, I40E_GLV_GORCL(0xc)); 59841d767a8eSEric Joyner printf("RX Bytes = %x\n", reg); 59851d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_GORCL(hw->port)); 59861d767a8eSEric Joyner printf("Port RX Bytes = %x\n", reg); 59871d767a8eSEric Joyner reg = rd32(hw, I40E_GLV_RDPC(0xc)); 59881d767a8eSEric Joyner printf("RX discard = %x\n", reg); 59891d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_RDPC(hw->port)); 59901d767a8eSEric Joyner printf("Port RX discard = %x\n", reg); 59911d767a8eSEric Joyner 59921d767a8eSEric Joyner reg = rd32(hw, I40E_GLV_TEPC(0xc)); 59931d767a8eSEric Joyner printf("TX errors = %x\n", reg); 59941d767a8eSEric Joyner reg = rd32(hw, I40E_GLV_GOTCL(0xc)); 59951d767a8eSEric Joyner printf("TX Bytes = %x\n", reg); 59961d767a8eSEric Joyner 59971d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_RUC(hw->port)); 59981d767a8eSEric Joyner printf("RX undersize = %x\n", reg); 59991d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_RFC(hw->port)); 60001d767a8eSEric Joyner printf("RX fragments = %x\n", reg); 60011d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_ROC(hw->port)); 60021d767a8eSEric Joyner printf("RX oversize = %x\n", reg); 60031d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_RLEC(hw->port)); 60041d767a8eSEric Joyner printf("RX length error = %x\n", reg); 60051d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_MRFC(hw->port)); 60061d767a8eSEric Joyner printf("mac remote fault = %x\n", reg); 60071d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_MLFC(hw->port)); 60081d767a8eSEric Joyner printf("mac local fault = %x\n", reg); 60091d767a8eSEric Joyner } 60101d767a8eSEric Joyner 6011393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */ 601261ae650dSJack F Vogel 601356c2c47bSJack F Vogel #ifdef PCI_IOV 601456c2c47bSJack F Vogel static int 601556c2c47bSJack F Vogel ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf) 601656c2c47bSJack F Vogel { 601756c2c47bSJack F Vogel struct i40e_hw *hw; 601856c2c47bSJack F Vogel struct ixl_vsi *vsi; 601956c2c47bSJack F Vogel struct i40e_vsi_context vsi_ctx; 602056c2c47bSJack F Vogel int i; 602156c2c47bSJack F Vogel uint16_t first_queue; 602256c2c47bSJack F Vogel enum i40e_status_code code; 602356c2c47bSJack F Vogel 602456c2c47bSJack F Vogel hw = &pf->hw; 602556c2c47bSJack F Vogel vsi = &pf->vsi; 602656c2c47bSJack F Vogel 602756c2c47bSJack F Vogel vsi_ctx.pf_num = hw->pf_id; 602856c2c47bSJack F Vogel vsi_ctx.uplink_seid = pf->veb_seid; 602956c2c47bSJack F Vogel vsi_ctx.connection_type = IXL_VSI_DATA_PORT; 603056c2c47bSJack F Vogel vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num; 603156c2c47bSJack F Vogel vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF; 603256c2c47bSJack F Vogel 603356c2c47bSJack F Vogel bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); 603456c2c47bSJack F Vogel 603556c2c47bSJack F Vogel vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID); 603656c2c47bSJack F Vogel vsi_ctx.info.switch_id = htole16(0); 603756c2c47bSJack F Vogel 603856c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID); 603956c2c47bSJack F Vogel vsi_ctx.info.sec_flags = 0; 604056c2c47bSJack F Vogel if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF) 604156c2c47bSJack F Vogel vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK; 604256c2c47bSJack F Vogel 604395bb0504SEric Joyner /* TODO: If a port VLAN is set, then this needs to be changed */ 604456c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID); 604556c2c47bSJack F Vogel vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 604656c2c47bSJack F Vogel I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 604756c2c47bSJack F Vogel 604856c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= 604956c2c47bSJack F Vogel htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID); 605056c2c47bSJack F Vogel vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG); 605156c2c47bSJack F Vogel first_queue = vsi->num_queues + vf->vf_num * IXLV_MAX_QUEUES; 605256c2c47bSJack F Vogel for (i = 0; i < IXLV_MAX_QUEUES; i++) 605356c2c47bSJack F Vogel vsi_ctx.info.queue_mapping[i] = htole16(first_queue + i); 605456c2c47bSJack F Vogel for (; i < nitems(vsi_ctx.info.queue_mapping); i++) 605556c2c47bSJack F Vogel vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK); 605656c2c47bSJack F Vogel 605756c2c47bSJack F Vogel vsi_ctx.info.tc_mapping[0] = htole16( 605856c2c47bSJack F Vogel (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) | 605956c2c47bSJack F Vogel (1 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)); 606056c2c47bSJack F Vogel 606156c2c47bSJack F Vogel code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL); 606256c2c47bSJack F Vogel if (code != I40E_SUCCESS) 606356c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 606456c2c47bSJack F Vogel vf->vsi.seid = vsi_ctx.seid; 606556c2c47bSJack F Vogel vf->vsi.vsi_num = vsi_ctx.vsi_number; 606656c2c47bSJack F Vogel vf->vsi.first_queue = first_queue; 606756c2c47bSJack F Vogel vf->vsi.num_queues = IXLV_MAX_QUEUES; 606856c2c47bSJack F Vogel 606956c2c47bSJack F Vogel code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL); 607056c2c47bSJack F Vogel if (code != I40E_SUCCESS) 607156c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 607256c2c47bSJack F Vogel 607356c2c47bSJack F Vogel code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL); 607456c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 607556c2c47bSJack F Vogel device_printf(pf->dev, "Failed to disable BW limit: %d\n", 607656c2c47bSJack F Vogel ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 607756c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 607856c2c47bSJack F Vogel } 607956c2c47bSJack F Vogel 608056c2c47bSJack F Vogel memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info)); 608156c2c47bSJack F Vogel return (0); 608256c2c47bSJack F Vogel } 608356c2c47bSJack F Vogel 608456c2c47bSJack F Vogel static int 608556c2c47bSJack F Vogel ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf) 608656c2c47bSJack F Vogel { 608756c2c47bSJack F Vogel struct i40e_hw *hw; 608856c2c47bSJack F Vogel int error; 608956c2c47bSJack F Vogel 609056c2c47bSJack F Vogel hw = &pf->hw; 609156c2c47bSJack F Vogel 609256c2c47bSJack F Vogel error = ixl_vf_alloc_vsi(pf, vf); 609356c2c47bSJack F Vogel if (error != 0) 609456c2c47bSJack F Vogel return (error); 609556c2c47bSJack F Vogel 609656c2c47bSJack F Vogel vf->vsi.hw_filters_add = 0; 609756c2c47bSJack F Vogel vf->vsi.hw_filters_del = 0; 609856c2c47bSJack F Vogel ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY); 609956c2c47bSJack F Vogel ixl_reconfigure_filters(&vf->vsi); 610056c2c47bSJack F Vogel 610156c2c47bSJack F Vogel return (0); 610256c2c47bSJack F Vogel } 610356c2c47bSJack F Vogel 610456c2c47bSJack F Vogel static void 610556c2c47bSJack F Vogel ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum, 610656c2c47bSJack F Vogel uint32_t val) 610756c2c47bSJack F Vogel { 610856c2c47bSJack F Vogel uint32_t qtable; 610956c2c47bSJack F Vogel int index, shift; 611056c2c47bSJack F Vogel 611156c2c47bSJack F Vogel /* 611256c2c47bSJack F Vogel * Two queues are mapped in a single register, so we have to do some 611356c2c47bSJack F Vogel * gymnastics to convert the queue number into a register index and 611456c2c47bSJack F Vogel * shift. 611556c2c47bSJack F Vogel */ 611656c2c47bSJack F Vogel index = qnum / 2; 611756c2c47bSJack F Vogel shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT; 611856c2c47bSJack F Vogel 6119*d4683565SEric Joyner qtable = i40e_read_rx_ctl(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num)); 612056c2c47bSJack F Vogel qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift); 612156c2c47bSJack F Vogel qtable |= val << shift; 6122*d4683565SEric Joyner i40e_write_rx_ctl(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable); 612356c2c47bSJack F Vogel } 612456c2c47bSJack F Vogel 612556c2c47bSJack F Vogel static void 612656c2c47bSJack F Vogel ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf) 612756c2c47bSJack F Vogel { 612856c2c47bSJack F Vogel struct i40e_hw *hw; 612956c2c47bSJack F Vogel uint32_t qtable; 613056c2c47bSJack F Vogel int i; 613156c2c47bSJack F Vogel 613256c2c47bSJack F Vogel hw = &pf->hw; 613356c2c47bSJack F Vogel 613456c2c47bSJack F Vogel /* 613556c2c47bSJack F Vogel * Contiguous mappings aren't actually supported by the hardware, 613656c2c47bSJack F Vogel * so we have to use non-contiguous mappings. 613756c2c47bSJack F Vogel */ 6138*d4683565SEric Joyner i40e_write_rx_ctl(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num), 613956c2c47bSJack F Vogel I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK); 614056c2c47bSJack F Vogel 614156c2c47bSJack F Vogel wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num), 614256c2c47bSJack F Vogel I40E_VPLAN_MAPENA_TXRX_ENA_MASK); 614356c2c47bSJack F Vogel 614456c2c47bSJack F Vogel for (i = 0; i < vf->vsi.num_queues; i++) { 614556c2c47bSJack F Vogel qtable = (vf->vsi.first_queue + i) << 614656c2c47bSJack F Vogel I40E_VPLAN_QTABLE_QINDEX_SHIFT; 614756c2c47bSJack F Vogel 614856c2c47bSJack F Vogel wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable); 614956c2c47bSJack F Vogel } 615056c2c47bSJack F Vogel 615156c2c47bSJack F Vogel /* Map queues allocated to VF to its VSI. */ 615256c2c47bSJack F Vogel for (i = 0; i < vf->vsi.num_queues; i++) 615356c2c47bSJack F Vogel ixl_vf_map_vsi_queue(hw, vf, i, vf->vsi.first_queue + i); 615456c2c47bSJack F Vogel 615556c2c47bSJack F Vogel /* Set rest of VSI queues as unused. */ 615656c2c47bSJack F Vogel for (; i < IXL_MAX_VSI_QUEUES; i++) 615756c2c47bSJack F Vogel ixl_vf_map_vsi_queue(hw, vf, i, 615856c2c47bSJack F Vogel I40E_VSILAN_QTABLE_QINDEX_0_MASK); 615956c2c47bSJack F Vogel 616056c2c47bSJack F Vogel ixl_flush(hw); 616156c2c47bSJack F Vogel } 616256c2c47bSJack F Vogel 616356c2c47bSJack F Vogel static void 616456c2c47bSJack F Vogel ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi) 616556c2c47bSJack F Vogel { 616656c2c47bSJack F Vogel struct i40e_hw *hw; 616756c2c47bSJack F Vogel 616856c2c47bSJack F Vogel hw = &pf->hw; 616956c2c47bSJack F Vogel 617056c2c47bSJack F Vogel if (vsi->seid == 0) 617156c2c47bSJack F Vogel return; 617256c2c47bSJack F Vogel 617356c2c47bSJack F Vogel i40e_aq_delete_element(hw, vsi->seid, NULL); 617456c2c47bSJack F Vogel } 617556c2c47bSJack F Vogel 617656c2c47bSJack F Vogel static void 617756c2c47bSJack F Vogel ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg) 617856c2c47bSJack F Vogel { 617956c2c47bSJack F Vogel 618056c2c47bSJack F Vogel wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK); 618156c2c47bSJack F Vogel ixl_flush(hw); 618256c2c47bSJack F Vogel } 618356c2c47bSJack F Vogel 618456c2c47bSJack F Vogel static void 618556c2c47bSJack F Vogel ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg) 618656c2c47bSJack F Vogel { 618756c2c47bSJack F Vogel 618856c2c47bSJack F Vogel wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK | 618956c2c47bSJack F Vogel I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK); 619056c2c47bSJack F Vogel ixl_flush(hw); 619156c2c47bSJack F Vogel } 619256c2c47bSJack F Vogel 619356c2c47bSJack F Vogel static void 619456c2c47bSJack F Vogel ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf) 619556c2c47bSJack F Vogel { 619656c2c47bSJack F Vogel struct i40e_hw *hw; 619756c2c47bSJack F Vogel uint32_t vfint_reg, vpint_reg; 619856c2c47bSJack F Vogel int i; 619956c2c47bSJack F Vogel 620056c2c47bSJack F Vogel hw = &pf->hw; 620156c2c47bSJack F Vogel 620256c2c47bSJack F Vogel ixl_vf_vsi_release(pf, &vf->vsi); 620356c2c47bSJack F Vogel 620456c2c47bSJack F Vogel /* Index 0 has a special register. */ 620556c2c47bSJack F Vogel ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num)); 620656c2c47bSJack F Vogel 620756c2c47bSJack F Vogel for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) { 620856c2c47bSJack F Vogel vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num); 620956c2c47bSJack F Vogel ixl_vf_disable_queue_intr(hw, vfint_reg); 621056c2c47bSJack F Vogel } 621156c2c47bSJack F Vogel 621256c2c47bSJack F Vogel /* Index 0 has a special register. */ 621356c2c47bSJack F Vogel ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num)); 621456c2c47bSJack F Vogel 621556c2c47bSJack F Vogel for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) { 621656c2c47bSJack F Vogel vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num); 621756c2c47bSJack F Vogel ixl_vf_unregister_intr(hw, vpint_reg); 621856c2c47bSJack F Vogel } 621956c2c47bSJack F Vogel 622056c2c47bSJack F Vogel vf->vsi.num_queues = 0; 622156c2c47bSJack F Vogel } 622256c2c47bSJack F Vogel 622356c2c47bSJack F Vogel static int 622456c2c47bSJack F Vogel ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf) 622556c2c47bSJack F Vogel { 622656c2c47bSJack F Vogel struct i40e_hw *hw; 622756c2c47bSJack F Vogel int i; 622856c2c47bSJack F Vogel uint16_t global_vf_num; 622956c2c47bSJack F Vogel uint32_t ciad; 623056c2c47bSJack F Vogel 623156c2c47bSJack F Vogel hw = &pf->hw; 623256c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + vf->vf_num; 623356c2c47bSJack F Vogel 623456c2c47bSJack F Vogel wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS | 623556c2c47bSJack F Vogel (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT)); 623656c2c47bSJack F Vogel for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) { 623756c2c47bSJack F Vogel ciad = rd32(hw, I40E_PF_PCI_CIAD); 623856c2c47bSJack F Vogel if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0) 623956c2c47bSJack F Vogel return (0); 624056c2c47bSJack F Vogel DELAY(1); 624156c2c47bSJack F Vogel } 624256c2c47bSJack F Vogel 624356c2c47bSJack F Vogel return (ETIMEDOUT); 624456c2c47bSJack F Vogel } 624556c2c47bSJack F Vogel 624656c2c47bSJack F Vogel static void 624756c2c47bSJack F Vogel ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf) 624856c2c47bSJack F Vogel { 624956c2c47bSJack F Vogel struct i40e_hw *hw; 625056c2c47bSJack F Vogel uint32_t vfrtrig; 625156c2c47bSJack F Vogel 625256c2c47bSJack F Vogel hw = &pf->hw; 625356c2c47bSJack F Vogel 625456c2c47bSJack F Vogel vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); 625556c2c47bSJack F Vogel vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK; 625656c2c47bSJack F Vogel wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); 625756c2c47bSJack F Vogel ixl_flush(hw); 625856c2c47bSJack F Vogel 625956c2c47bSJack F Vogel ixl_reinit_vf(pf, vf); 626056c2c47bSJack F Vogel } 626156c2c47bSJack F Vogel 626256c2c47bSJack F Vogel static void 626356c2c47bSJack F Vogel ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf) 626456c2c47bSJack F Vogel { 626556c2c47bSJack F Vogel struct i40e_hw *hw; 626656c2c47bSJack F Vogel uint32_t vfrstat, vfrtrig; 626756c2c47bSJack F Vogel int i, error; 626856c2c47bSJack F Vogel 626956c2c47bSJack F Vogel hw = &pf->hw; 627056c2c47bSJack F Vogel 627156c2c47bSJack F Vogel error = ixl_flush_pcie(pf, vf); 627256c2c47bSJack F Vogel if (error != 0) 627356c2c47bSJack F Vogel device_printf(pf->dev, 627456c2c47bSJack F Vogel "Timed out waiting for PCIe activity to stop on VF-%d\n", 627556c2c47bSJack F Vogel vf->vf_num); 627656c2c47bSJack F Vogel 627756c2c47bSJack F Vogel for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) { 627856c2c47bSJack F Vogel DELAY(10); 627956c2c47bSJack F Vogel 628056c2c47bSJack F Vogel vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num)); 628156c2c47bSJack F Vogel if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK) 628256c2c47bSJack F Vogel break; 628356c2c47bSJack F Vogel } 628456c2c47bSJack F Vogel 628556c2c47bSJack F Vogel if (i == IXL_VF_RESET_TIMEOUT) 628656c2c47bSJack F Vogel device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num); 628756c2c47bSJack F Vogel 628856c2c47bSJack F Vogel wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_COMPLETED); 628956c2c47bSJack F Vogel 629056c2c47bSJack F Vogel vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); 629156c2c47bSJack F Vogel vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK; 629256c2c47bSJack F Vogel wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); 629356c2c47bSJack F Vogel 629456c2c47bSJack F Vogel if (vf->vsi.seid != 0) 629556c2c47bSJack F Vogel ixl_disable_rings(&vf->vsi); 629656c2c47bSJack F Vogel 629756c2c47bSJack F Vogel ixl_vf_release_resources(pf, vf); 629856c2c47bSJack F Vogel ixl_vf_setup_vsi(pf, vf); 629956c2c47bSJack F Vogel ixl_vf_map_queues(pf, vf); 630056c2c47bSJack F Vogel 630156c2c47bSJack F Vogel wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_VFACTIVE); 630256c2c47bSJack F Vogel ixl_flush(hw); 630356c2c47bSJack F Vogel } 630456c2c47bSJack F Vogel 630556c2c47bSJack F Vogel static const char * 630656c2c47bSJack F Vogel ixl_vc_opcode_str(uint16_t op) 630756c2c47bSJack F Vogel { 630856c2c47bSJack F Vogel 630956c2c47bSJack F Vogel switch (op) { 631056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_VERSION: 631156c2c47bSJack F Vogel return ("VERSION"); 631256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_RESET_VF: 631356c2c47bSJack F Vogel return ("RESET_VF"); 631456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: 631556c2c47bSJack F Vogel return ("GET_VF_RESOURCES"); 631656c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: 631756c2c47bSJack F Vogel return ("CONFIG_TX_QUEUE"); 631856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: 631956c2c47bSJack F Vogel return ("CONFIG_RX_QUEUE"); 632056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: 632156c2c47bSJack F Vogel return ("CONFIG_VSI_QUEUES"); 632256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: 632356c2c47bSJack F Vogel return ("CONFIG_IRQ_MAP"); 632456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ENABLE_QUEUES: 632556c2c47bSJack F Vogel return ("ENABLE_QUEUES"); 632656c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DISABLE_QUEUES: 632756c2c47bSJack F Vogel return ("DISABLE_QUEUES"); 632856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: 632956c2c47bSJack F Vogel return ("ADD_ETHER_ADDRESS"); 633056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: 633156c2c47bSJack F Vogel return ("DEL_ETHER_ADDRESS"); 633256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_VLAN: 633356c2c47bSJack F Vogel return ("ADD_VLAN"); 633456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_VLAN: 633556c2c47bSJack F Vogel return ("DEL_VLAN"); 633656c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: 633756c2c47bSJack F Vogel return ("CONFIG_PROMISCUOUS_MODE"); 633856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 633956c2c47bSJack F Vogel return ("GET_STATS"); 634056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_FCOE: 634156c2c47bSJack F Vogel return ("FCOE"); 634256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_EVENT: 634356c2c47bSJack F Vogel return ("EVENT"); 634456c2c47bSJack F Vogel default: 634556c2c47bSJack F Vogel return ("UNKNOWN"); 634656c2c47bSJack F Vogel } 634756c2c47bSJack F Vogel } 634856c2c47bSJack F Vogel 634956c2c47bSJack F Vogel static int 635056c2c47bSJack F Vogel ixl_vc_opcode_level(uint16_t opcode) 635156c2c47bSJack F Vogel { 635256c2c47bSJack F Vogel switch (opcode) { 635356c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 635456c2c47bSJack F Vogel return (10); 635556c2c47bSJack F Vogel default: 635656c2c47bSJack F Vogel return (5); 635756c2c47bSJack F Vogel } 635856c2c47bSJack F Vogel } 635956c2c47bSJack F Vogel 636056c2c47bSJack F Vogel static void 636156c2c47bSJack F Vogel ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, 636256c2c47bSJack F Vogel enum i40e_status_code status, void *msg, uint16_t len) 636356c2c47bSJack F Vogel { 636456c2c47bSJack F Vogel struct i40e_hw *hw; 636556c2c47bSJack F Vogel int global_vf_id; 636656c2c47bSJack F Vogel 636756c2c47bSJack F Vogel hw = &pf->hw; 636856c2c47bSJack F Vogel global_vf_id = hw->func_caps.vf_base_id + vf->vf_num; 636956c2c47bSJack F Vogel 637056c2c47bSJack F Vogel I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op), 637156c2c47bSJack F Vogel "Sending msg (op=%s[%d], status=%d) to VF-%d\n", 637256c2c47bSJack F Vogel ixl_vc_opcode_str(op), op, status, vf->vf_num); 637356c2c47bSJack F Vogel 637456c2c47bSJack F Vogel i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL); 637556c2c47bSJack F Vogel } 637656c2c47bSJack F Vogel 637756c2c47bSJack F Vogel static void 637856c2c47bSJack F Vogel ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op) 637956c2c47bSJack F Vogel { 638056c2c47bSJack F Vogel 638156c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0); 638256c2c47bSJack F Vogel } 638356c2c47bSJack F Vogel 638456c2c47bSJack F Vogel static void 638556c2c47bSJack F Vogel ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, 638656c2c47bSJack F Vogel enum i40e_status_code status, const char *file, int line) 638756c2c47bSJack F Vogel { 638856c2c47bSJack F Vogel 638956c2c47bSJack F Vogel I40E_VC_DEBUG(pf, 1, 639056c2c47bSJack F Vogel "Sending NACK (op=%s[%d], err=%d) to VF-%d from %s:%d\n", 639156c2c47bSJack F Vogel ixl_vc_opcode_str(op), op, status, vf->vf_num, file, line); 639256c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, op, status, NULL, 0); 639356c2c47bSJack F Vogel } 639456c2c47bSJack F Vogel 639556c2c47bSJack F Vogel static void 639656c2c47bSJack F Vogel ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 639756c2c47bSJack F Vogel uint16_t msg_size) 639856c2c47bSJack F Vogel { 639956c2c47bSJack F Vogel struct i40e_virtchnl_version_info reply; 640056c2c47bSJack F Vogel 640156c2c47bSJack F Vogel if (msg_size != sizeof(struct i40e_virtchnl_version_info)) { 640256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_VERSION, 640356c2c47bSJack F Vogel I40E_ERR_PARAM); 640456c2c47bSJack F Vogel return; 640556c2c47bSJack F Vogel } 640656c2c47bSJack F Vogel 64071d767a8eSEric Joyner vf->version = ((struct i40e_virtchnl_version_info *)msg)->minor; 64081d767a8eSEric Joyner 640956c2c47bSJack F Vogel reply.major = I40E_VIRTCHNL_VERSION_MAJOR; 641056c2c47bSJack F Vogel reply.minor = I40E_VIRTCHNL_VERSION_MINOR; 641156c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, &reply, 641256c2c47bSJack F Vogel sizeof(reply)); 641356c2c47bSJack F Vogel } 641456c2c47bSJack F Vogel 641556c2c47bSJack F Vogel static void 641656c2c47bSJack F Vogel ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 641756c2c47bSJack F Vogel uint16_t msg_size) 641856c2c47bSJack F Vogel { 641956c2c47bSJack F Vogel 642056c2c47bSJack F Vogel if (msg_size != 0) { 642156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_RESET_VF, 642256c2c47bSJack F Vogel I40E_ERR_PARAM); 642356c2c47bSJack F Vogel return; 642456c2c47bSJack F Vogel } 642556c2c47bSJack F Vogel 642656c2c47bSJack F Vogel ixl_reset_vf(pf, vf); 642756c2c47bSJack F Vogel 642856c2c47bSJack F Vogel /* No response to a reset message. */ 642956c2c47bSJack F Vogel } 643056c2c47bSJack F Vogel 643156c2c47bSJack F Vogel static void 643256c2c47bSJack F Vogel ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 643356c2c47bSJack F Vogel uint16_t msg_size) 643456c2c47bSJack F Vogel { 643556c2c47bSJack F Vogel struct i40e_virtchnl_vf_resource reply; 643656c2c47bSJack F Vogel 64371d767a8eSEric Joyner if ((vf->version == 0 && msg_size != 0) || 64381d767a8eSEric Joyner (vf->version == 1 && msg_size != 4)) { 64391d767a8eSEric Joyner device_printf(pf->dev, "Invalid GET_VF_RESOURCES message size," 64401d767a8eSEric Joyner " for VF version %d.%d\n", I40E_VIRTCHNL_VERSION_MAJOR, 64411d767a8eSEric Joyner vf->version); 644256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, 644356c2c47bSJack F Vogel I40E_ERR_PARAM); 644456c2c47bSJack F Vogel return; 644556c2c47bSJack F Vogel } 644656c2c47bSJack F Vogel 644756c2c47bSJack F Vogel bzero(&reply, sizeof(reply)); 644856c2c47bSJack F Vogel 64491d767a8eSEric Joyner if (vf->version == I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS) 64501d767a8eSEric Joyner reply.vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2 | 64511d767a8eSEric Joyner I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | 64521d767a8eSEric Joyner I40E_VIRTCHNL_VF_OFFLOAD_VLAN; 64531d767a8eSEric Joyner else 64541d767a8eSEric Joyner reply.vf_offload_flags = *(u32 *)msg; 645556c2c47bSJack F Vogel 645656c2c47bSJack F Vogel reply.num_vsis = 1; 645756c2c47bSJack F Vogel reply.num_queue_pairs = vf->vsi.num_queues; 645856c2c47bSJack F Vogel reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf; 645956c2c47bSJack F Vogel reply.vsi_res[0].vsi_id = vf->vsi.vsi_num; 646056c2c47bSJack F Vogel reply.vsi_res[0].vsi_type = I40E_VSI_SRIOV; 646156c2c47bSJack F Vogel reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues; 646256c2c47bSJack F Vogel memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN); 646356c2c47bSJack F Vogel 646456c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, 646556c2c47bSJack F Vogel I40E_SUCCESS, &reply, sizeof(reply)); 646656c2c47bSJack F Vogel } 646756c2c47bSJack F Vogel 646856c2c47bSJack F Vogel static int 646956c2c47bSJack F Vogel ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf, 647056c2c47bSJack F Vogel struct i40e_virtchnl_txq_info *info) 647156c2c47bSJack F Vogel { 647256c2c47bSJack F Vogel struct i40e_hw *hw; 647356c2c47bSJack F Vogel struct i40e_hmc_obj_txq txq; 647456c2c47bSJack F Vogel uint16_t global_queue_num, global_vf_num; 647556c2c47bSJack F Vogel enum i40e_status_code status; 647656c2c47bSJack F Vogel uint32_t qtx_ctl; 647756c2c47bSJack F Vogel 647856c2c47bSJack F Vogel hw = &pf->hw; 647956c2c47bSJack F Vogel global_queue_num = vf->vsi.first_queue + info->queue_id; 648056c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + vf->vf_num; 648156c2c47bSJack F Vogel bzero(&txq, sizeof(txq)); 648256c2c47bSJack F Vogel 648356c2c47bSJack F Vogel status = i40e_clear_lan_tx_queue_context(hw, global_queue_num); 648456c2c47bSJack F Vogel if (status != I40E_SUCCESS) 648556c2c47bSJack F Vogel return (EINVAL); 648656c2c47bSJack F Vogel 648756c2c47bSJack F Vogel txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS; 648856c2c47bSJack F Vogel 648956c2c47bSJack F Vogel txq.head_wb_ena = info->headwb_enabled; 649056c2c47bSJack F Vogel txq.head_wb_addr = info->dma_headwb_addr; 649156c2c47bSJack F Vogel txq.qlen = info->ring_len; 649256c2c47bSJack F Vogel txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]); 649356c2c47bSJack F Vogel txq.rdylist_act = 0; 649456c2c47bSJack F Vogel 649556c2c47bSJack F Vogel status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq); 649656c2c47bSJack F Vogel if (status != I40E_SUCCESS) 649756c2c47bSJack F Vogel return (EINVAL); 649856c2c47bSJack F Vogel 649956c2c47bSJack F Vogel qtx_ctl = I40E_QTX_CTL_VF_QUEUE | 650056c2c47bSJack F Vogel (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) | 650156c2c47bSJack F Vogel (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT); 650256c2c47bSJack F Vogel wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl); 650356c2c47bSJack F Vogel ixl_flush(hw); 650456c2c47bSJack F Vogel 650556c2c47bSJack F Vogel return (0); 650656c2c47bSJack F Vogel } 650756c2c47bSJack F Vogel 650856c2c47bSJack F Vogel static int 650956c2c47bSJack F Vogel ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf, 651056c2c47bSJack F Vogel struct i40e_virtchnl_rxq_info *info) 651156c2c47bSJack F Vogel { 651256c2c47bSJack F Vogel struct i40e_hw *hw; 651356c2c47bSJack F Vogel struct i40e_hmc_obj_rxq rxq; 651456c2c47bSJack F Vogel uint16_t global_queue_num; 651556c2c47bSJack F Vogel enum i40e_status_code status; 651656c2c47bSJack F Vogel 651756c2c47bSJack F Vogel hw = &pf->hw; 651856c2c47bSJack F Vogel global_queue_num = vf->vsi.first_queue + info->queue_id; 651956c2c47bSJack F Vogel bzero(&rxq, sizeof(rxq)); 652056c2c47bSJack F Vogel 652156c2c47bSJack F Vogel if (info->databuffer_size > IXL_VF_MAX_BUFFER) 652256c2c47bSJack F Vogel return (EINVAL); 652356c2c47bSJack F Vogel 652456c2c47bSJack F Vogel if (info->max_pkt_size > IXL_VF_MAX_FRAME || 652556c2c47bSJack F Vogel info->max_pkt_size < ETHER_MIN_LEN) 652656c2c47bSJack F Vogel return (EINVAL); 652756c2c47bSJack F Vogel 652856c2c47bSJack F Vogel if (info->splithdr_enabled) { 652956c2c47bSJack F Vogel if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER) 653056c2c47bSJack F Vogel return (EINVAL); 653156c2c47bSJack F Vogel 653256c2c47bSJack F Vogel rxq.hsplit_0 = info->rx_split_pos & 653356c2c47bSJack F Vogel (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 | 653456c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP | 653556c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP | 653656c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP); 653756c2c47bSJack F Vogel rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT; 653856c2c47bSJack F Vogel 653956c2c47bSJack F Vogel rxq.dtype = 2; 654056c2c47bSJack F Vogel } 654156c2c47bSJack F Vogel 654256c2c47bSJack F Vogel status = i40e_clear_lan_rx_queue_context(hw, global_queue_num); 654356c2c47bSJack F Vogel if (status != I40E_SUCCESS) 654456c2c47bSJack F Vogel return (EINVAL); 654556c2c47bSJack F Vogel 654656c2c47bSJack F Vogel rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS; 654756c2c47bSJack F Vogel rxq.qlen = info->ring_len; 654856c2c47bSJack F Vogel 654956c2c47bSJack F Vogel rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT; 655056c2c47bSJack F Vogel 655156c2c47bSJack F Vogel rxq.dsize = 1; 655256c2c47bSJack F Vogel rxq.crcstrip = 1; 655356c2c47bSJack F Vogel rxq.l2tsel = 1; 655456c2c47bSJack F Vogel 655556c2c47bSJack F Vogel rxq.rxmax = info->max_pkt_size; 655656c2c47bSJack F Vogel rxq.tphrdesc_ena = 1; 655756c2c47bSJack F Vogel rxq.tphwdesc_ena = 1; 655856c2c47bSJack F Vogel rxq.tphdata_ena = 1; 655956c2c47bSJack F Vogel rxq.tphhead_ena = 1; 656056c2c47bSJack F Vogel rxq.lrxqthresh = 2; 656156c2c47bSJack F Vogel rxq.prefena = 1; 656256c2c47bSJack F Vogel 656356c2c47bSJack F Vogel status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq); 656456c2c47bSJack F Vogel if (status != I40E_SUCCESS) 656556c2c47bSJack F Vogel return (EINVAL); 656656c2c47bSJack F Vogel 656756c2c47bSJack F Vogel return (0); 656856c2c47bSJack F Vogel } 656956c2c47bSJack F Vogel 657056c2c47bSJack F Vogel static void 657156c2c47bSJack F Vogel ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 657256c2c47bSJack F Vogel uint16_t msg_size) 657356c2c47bSJack F Vogel { 657456c2c47bSJack F Vogel struct i40e_virtchnl_vsi_queue_config_info *info; 657556c2c47bSJack F Vogel struct i40e_virtchnl_queue_pair_info *pair; 657656c2c47bSJack F Vogel int i; 657756c2c47bSJack F Vogel 657856c2c47bSJack F Vogel if (msg_size < sizeof(*info)) { 657956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 658056c2c47bSJack F Vogel I40E_ERR_PARAM); 658156c2c47bSJack F Vogel return; 658256c2c47bSJack F Vogel } 658356c2c47bSJack F Vogel 658456c2c47bSJack F Vogel info = msg; 658556c2c47bSJack F Vogel if (info->num_queue_pairs == 0) { 658656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 658756c2c47bSJack F Vogel I40E_ERR_PARAM); 658856c2c47bSJack F Vogel return; 658956c2c47bSJack F Vogel } 659056c2c47bSJack F Vogel 659156c2c47bSJack F Vogel if (msg_size != sizeof(*info) + info->num_queue_pairs * sizeof(*pair)) { 659256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 659356c2c47bSJack F Vogel I40E_ERR_PARAM); 659456c2c47bSJack F Vogel return; 659556c2c47bSJack F Vogel } 659656c2c47bSJack F Vogel 659756c2c47bSJack F Vogel if (info->vsi_id != vf->vsi.vsi_num) { 659856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 659956c2c47bSJack F Vogel I40E_ERR_PARAM); 660056c2c47bSJack F Vogel return; 660156c2c47bSJack F Vogel } 660256c2c47bSJack F Vogel 660356c2c47bSJack F Vogel for (i = 0; i < info->num_queue_pairs; i++) { 660456c2c47bSJack F Vogel pair = &info->qpair[i]; 660556c2c47bSJack F Vogel 660656c2c47bSJack F Vogel if (pair->txq.vsi_id != vf->vsi.vsi_num || 660756c2c47bSJack F Vogel pair->rxq.vsi_id != vf->vsi.vsi_num || 660856c2c47bSJack F Vogel pair->txq.queue_id != pair->rxq.queue_id || 660956c2c47bSJack F Vogel pair->txq.queue_id >= vf->vsi.num_queues) { 661056c2c47bSJack F Vogel 661156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 661256c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 661356c2c47bSJack F Vogel return; 661456c2c47bSJack F Vogel } 661556c2c47bSJack F Vogel 661656c2c47bSJack F Vogel if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) { 661756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 661856c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 661956c2c47bSJack F Vogel return; 662056c2c47bSJack F Vogel } 662156c2c47bSJack F Vogel 662256c2c47bSJack F Vogel if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) { 662356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 662456c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 662556c2c47bSJack F Vogel return; 662656c2c47bSJack F Vogel } 662756c2c47bSJack F Vogel } 662856c2c47bSJack F Vogel 662956c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES); 663056c2c47bSJack F Vogel } 663156c2c47bSJack F Vogel 663256c2c47bSJack F Vogel static void 663356c2c47bSJack F Vogel ixl_vf_set_qctl(struct ixl_pf *pf, 663456c2c47bSJack F Vogel const struct i40e_virtchnl_vector_map *vector, 663556c2c47bSJack F Vogel enum i40e_queue_type cur_type, uint16_t cur_queue, 663656c2c47bSJack F Vogel enum i40e_queue_type *last_type, uint16_t *last_queue) 663756c2c47bSJack F Vogel { 663856c2c47bSJack F Vogel uint32_t offset, qctl; 663956c2c47bSJack F Vogel uint16_t itr_indx; 664056c2c47bSJack F Vogel 664156c2c47bSJack F Vogel if (cur_type == I40E_QUEUE_TYPE_RX) { 664256c2c47bSJack F Vogel offset = I40E_QINT_RQCTL(cur_queue); 664356c2c47bSJack F Vogel itr_indx = vector->rxitr_idx; 664456c2c47bSJack F Vogel } else { 664556c2c47bSJack F Vogel offset = I40E_QINT_TQCTL(cur_queue); 664656c2c47bSJack F Vogel itr_indx = vector->txitr_idx; 664756c2c47bSJack F Vogel } 664856c2c47bSJack F Vogel 664956c2c47bSJack F Vogel qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 665056c2c47bSJack F Vogel (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) | 665156c2c47bSJack F Vogel (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 665256c2c47bSJack F Vogel I40E_QINT_RQCTL_CAUSE_ENA_MASK | 665356c2c47bSJack F Vogel (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT)); 665456c2c47bSJack F Vogel 665556c2c47bSJack F Vogel wr32(&pf->hw, offset, qctl); 665656c2c47bSJack F Vogel 665756c2c47bSJack F Vogel *last_type = cur_type; 665856c2c47bSJack F Vogel *last_queue = cur_queue; 665956c2c47bSJack F Vogel } 666056c2c47bSJack F Vogel 666156c2c47bSJack F Vogel static void 666256c2c47bSJack F Vogel ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf, 666356c2c47bSJack F Vogel const struct i40e_virtchnl_vector_map *vector) 666456c2c47bSJack F Vogel { 666556c2c47bSJack F Vogel struct i40e_hw *hw; 666656c2c47bSJack F Vogel u_int qindex; 666756c2c47bSJack F Vogel enum i40e_queue_type type, last_type; 666856c2c47bSJack F Vogel uint32_t lnklst_reg; 666956c2c47bSJack F Vogel uint16_t rxq_map, txq_map, cur_queue, last_queue; 667056c2c47bSJack F Vogel 667156c2c47bSJack F Vogel hw = &pf->hw; 667256c2c47bSJack F Vogel 667356c2c47bSJack F Vogel rxq_map = vector->rxq_map; 667456c2c47bSJack F Vogel txq_map = vector->txq_map; 667556c2c47bSJack F Vogel 667656c2c47bSJack F Vogel last_queue = IXL_END_OF_INTR_LNKLST; 667756c2c47bSJack F Vogel last_type = I40E_QUEUE_TYPE_RX; 667856c2c47bSJack F Vogel 667956c2c47bSJack F Vogel /* 668056c2c47bSJack F Vogel * The datasheet says to optimize performance, RX queues and TX queues 668156c2c47bSJack F Vogel * should be interleaved in the interrupt linked list, so we process 668256c2c47bSJack F Vogel * both at once here. 668356c2c47bSJack F Vogel */ 668456c2c47bSJack F Vogel while ((rxq_map != 0) || (txq_map != 0)) { 668556c2c47bSJack F Vogel if (txq_map != 0) { 668656c2c47bSJack F Vogel qindex = ffs(txq_map) - 1; 668756c2c47bSJack F Vogel type = I40E_QUEUE_TYPE_TX; 668856c2c47bSJack F Vogel cur_queue = vf->vsi.first_queue + qindex; 668956c2c47bSJack F Vogel ixl_vf_set_qctl(pf, vector, type, cur_queue, 669056c2c47bSJack F Vogel &last_type, &last_queue); 669156c2c47bSJack F Vogel txq_map &= ~(1 << qindex); 669256c2c47bSJack F Vogel } 669356c2c47bSJack F Vogel 669456c2c47bSJack F Vogel if (rxq_map != 0) { 669556c2c47bSJack F Vogel qindex = ffs(rxq_map) - 1; 669656c2c47bSJack F Vogel type = I40E_QUEUE_TYPE_RX; 669756c2c47bSJack F Vogel cur_queue = vf->vsi.first_queue + qindex; 669856c2c47bSJack F Vogel ixl_vf_set_qctl(pf, vector, type, cur_queue, 669956c2c47bSJack F Vogel &last_type, &last_queue); 670056c2c47bSJack F Vogel rxq_map &= ~(1 << qindex); 670156c2c47bSJack F Vogel } 670256c2c47bSJack F Vogel } 670356c2c47bSJack F Vogel 670456c2c47bSJack F Vogel if (vector->vector_id == 0) 670556c2c47bSJack F Vogel lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num); 670656c2c47bSJack F Vogel else 670756c2c47bSJack F Vogel lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id, 670856c2c47bSJack F Vogel vf->vf_num); 670956c2c47bSJack F Vogel wr32(hw, lnklst_reg, 671056c2c47bSJack F Vogel (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) | 671156c2c47bSJack F Vogel (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT)); 671256c2c47bSJack F Vogel 671356c2c47bSJack F Vogel ixl_flush(hw); 671456c2c47bSJack F Vogel } 671556c2c47bSJack F Vogel 671656c2c47bSJack F Vogel static void 671756c2c47bSJack F Vogel ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 671856c2c47bSJack F Vogel uint16_t msg_size) 671956c2c47bSJack F Vogel { 672056c2c47bSJack F Vogel struct i40e_virtchnl_irq_map_info *map; 672156c2c47bSJack F Vogel struct i40e_virtchnl_vector_map *vector; 672256c2c47bSJack F Vogel struct i40e_hw *hw; 672356c2c47bSJack F Vogel int i, largest_txq, largest_rxq; 672456c2c47bSJack F Vogel 672556c2c47bSJack F Vogel hw = &pf->hw; 672656c2c47bSJack F Vogel 672756c2c47bSJack F Vogel if (msg_size < sizeof(*map)) { 672856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 672956c2c47bSJack F Vogel I40E_ERR_PARAM); 673056c2c47bSJack F Vogel return; 673156c2c47bSJack F Vogel } 673256c2c47bSJack F Vogel 673356c2c47bSJack F Vogel map = msg; 673456c2c47bSJack F Vogel if (map->num_vectors == 0) { 673556c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 673656c2c47bSJack F Vogel I40E_ERR_PARAM); 673756c2c47bSJack F Vogel return; 673856c2c47bSJack F Vogel } 673956c2c47bSJack F Vogel 674056c2c47bSJack F Vogel if (msg_size != sizeof(*map) + map->num_vectors * sizeof(*vector)) { 674156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 674256c2c47bSJack F Vogel I40E_ERR_PARAM); 674356c2c47bSJack F Vogel return; 674456c2c47bSJack F Vogel } 674556c2c47bSJack F Vogel 674656c2c47bSJack F Vogel for (i = 0; i < map->num_vectors; i++) { 674756c2c47bSJack F Vogel vector = &map->vecmap[i]; 674856c2c47bSJack F Vogel 674956c2c47bSJack F Vogel if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) || 675056c2c47bSJack F Vogel vector->vsi_id != vf->vsi.vsi_num) { 675156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 675256c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM); 675356c2c47bSJack F Vogel return; 675456c2c47bSJack F Vogel } 675556c2c47bSJack F Vogel 675656c2c47bSJack F Vogel if (vector->rxq_map != 0) { 675756c2c47bSJack F Vogel largest_rxq = fls(vector->rxq_map) - 1; 675856c2c47bSJack F Vogel if (largest_rxq >= vf->vsi.num_queues) { 675956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 676056c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 676156c2c47bSJack F Vogel I40E_ERR_PARAM); 676256c2c47bSJack F Vogel return; 676356c2c47bSJack F Vogel } 676456c2c47bSJack F Vogel } 676556c2c47bSJack F Vogel 676656c2c47bSJack F Vogel if (vector->txq_map != 0) { 676756c2c47bSJack F Vogel largest_txq = fls(vector->txq_map) - 1; 676856c2c47bSJack F Vogel if (largest_txq >= vf->vsi.num_queues) { 676956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 677056c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 677156c2c47bSJack F Vogel I40E_ERR_PARAM); 677256c2c47bSJack F Vogel return; 677356c2c47bSJack F Vogel } 677456c2c47bSJack F Vogel } 677556c2c47bSJack F Vogel 677656c2c47bSJack F Vogel if (vector->rxitr_idx > IXL_MAX_ITR_IDX || 677756c2c47bSJack F Vogel vector->txitr_idx > IXL_MAX_ITR_IDX) { 677856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 677956c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 678056c2c47bSJack F Vogel I40E_ERR_PARAM); 678156c2c47bSJack F Vogel return; 678256c2c47bSJack F Vogel } 678356c2c47bSJack F Vogel 678456c2c47bSJack F Vogel ixl_vf_config_vector(pf, vf, vector); 678556c2c47bSJack F Vogel } 678656c2c47bSJack F Vogel 678756c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP); 678856c2c47bSJack F Vogel } 678956c2c47bSJack F Vogel 679056c2c47bSJack F Vogel static void 679156c2c47bSJack F Vogel ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 679256c2c47bSJack F Vogel uint16_t msg_size) 679356c2c47bSJack F Vogel { 679456c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *select; 679556c2c47bSJack F Vogel int error; 679656c2c47bSJack F Vogel 679756c2c47bSJack F Vogel if (msg_size != sizeof(*select)) { 679856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 679956c2c47bSJack F Vogel I40E_ERR_PARAM); 680056c2c47bSJack F Vogel return; 680156c2c47bSJack F Vogel } 680256c2c47bSJack F Vogel 680356c2c47bSJack F Vogel select = msg; 680456c2c47bSJack F Vogel if (select->vsi_id != vf->vsi.vsi_num || 680556c2c47bSJack F Vogel select->rx_queues == 0 || select->tx_queues == 0) { 680656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 680756c2c47bSJack F Vogel I40E_ERR_PARAM); 680856c2c47bSJack F Vogel return; 680956c2c47bSJack F Vogel } 681056c2c47bSJack F Vogel 681156c2c47bSJack F Vogel error = ixl_enable_rings(&vf->vsi); 681256c2c47bSJack F Vogel if (error) { 681356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 681456c2c47bSJack F Vogel I40E_ERR_TIMEOUT); 681556c2c47bSJack F Vogel return; 681656c2c47bSJack F Vogel } 681756c2c47bSJack F Vogel 681856c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES); 681956c2c47bSJack F Vogel } 682056c2c47bSJack F Vogel 682156c2c47bSJack F Vogel static void 682256c2c47bSJack F Vogel ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, 682356c2c47bSJack F Vogel void *msg, uint16_t msg_size) 682456c2c47bSJack F Vogel { 682556c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *select; 682656c2c47bSJack F Vogel int error; 682756c2c47bSJack F Vogel 682856c2c47bSJack F Vogel if (msg_size != sizeof(*select)) { 682956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 683056c2c47bSJack F Vogel I40E_ERR_PARAM); 683156c2c47bSJack F Vogel return; 683256c2c47bSJack F Vogel } 683356c2c47bSJack F Vogel 683456c2c47bSJack F Vogel select = msg; 683556c2c47bSJack F Vogel if (select->vsi_id != vf->vsi.vsi_num || 683656c2c47bSJack F Vogel select->rx_queues == 0 || select->tx_queues == 0) { 683756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 683856c2c47bSJack F Vogel I40E_ERR_PARAM); 683956c2c47bSJack F Vogel return; 684056c2c47bSJack F Vogel } 684156c2c47bSJack F Vogel 684256c2c47bSJack F Vogel error = ixl_disable_rings(&vf->vsi); 684356c2c47bSJack F Vogel if (error) { 684456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 684556c2c47bSJack F Vogel I40E_ERR_TIMEOUT); 684656c2c47bSJack F Vogel return; 684756c2c47bSJack F Vogel } 684856c2c47bSJack F Vogel 684956c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES); 685056c2c47bSJack F Vogel } 685156c2c47bSJack F Vogel 685256c2c47bSJack F Vogel static boolean_t 685356c2c47bSJack F Vogel ixl_zero_mac(const uint8_t *addr) 685456c2c47bSJack F Vogel { 685556c2c47bSJack F Vogel uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0}; 685656c2c47bSJack F Vogel 685756c2c47bSJack F Vogel return (cmp_etheraddr(addr, zero)); 685856c2c47bSJack F Vogel } 685956c2c47bSJack F Vogel 686056c2c47bSJack F Vogel static boolean_t 686156c2c47bSJack F Vogel ixl_bcast_mac(const uint8_t *addr) 686256c2c47bSJack F Vogel { 686356c2c47bSJack F Vogel 686456c2c47bSJack F Vogel return (cmp_etheraddr(addr, ixl_bcast_addr)); 686556c2c47bSJack F Vogel } 686656c2c47bSJack F Vogel 686756c2c47bSJack F Vogel static int 686856c2c47bSJack F Vogel ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr) 686956c2c47bSJack F Vogel { 687056c2c47bSJack F Vogel 687156c2c47bSJack F Vogel if (ixl_zero_mac(addr) || ixl_bcast_mac(addr)) 687256c2c47bSJack F Vogel return (EINVAL); 687356c2c47bSJack F Vogel 687456c2c47bSJack F Vogel /* 687556c2c47bSJack F Vogel * If the VF is not allowed to change its MAC address, don't let it 687656c2c47bSJack F Vogel * set a MAC filter for an address that is not a multicast address and 687756c2c47bSJack F Vogel * is not its assigned MAC. 687856c2c47bSJack F Vogel */ 687956c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) && 688056c2c47bSJack F Vogel !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac))) 688156c2c47bSJack F Vogel return (EPERM); 688256c2c47bSJack F Vogel 688356c2c47bSJack F Vogel return (0); 688456c2c47bSJack F Vogel } 688556c2c47bSJack F Vogel 688656c2c47bSJack F Vogel static void 688756c2c47bSJack F Vogel ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 688856c2c47bSJack F Vogel uint16_t msg_size) 688956c2c47bSJack F Vogel { 689056c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr_list *addr_list; 689156c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr *addr; 689256c2c47bSJack F Vogel struct ixl_vsi *vsi; 689356c2c47bSJack F Vogel int i; 689456c2c47bSJack F Vogel size_t expected_size; 689556c2c47bSJack F Vogel 689656c2c47bSJack F Vogel vsi = &vf->vsi; 689756c2c47bSJack F Vogel 689856c2c47bSJack F Vogel if (msg_size < sizeof(*addr_list)) { 689956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 690056c2c47bSJack F Vogel I40E_ERR_PARAM); 690156c2c47bSJack F Vogel return; 690256c2c47bSJack F Vogel } 690356c2c47bSJack F Vogel 690456c2c47bSJack F Vogel addr_list = msg; 690556c2c47bSJack F Vogel expected_size = sizeof(*addr_list) + 690656c2c47bSJack F Vogel addr_list->num_elements * sizeof(*addr); 690756c2c47bSJack F Vogel 690856c2c47bSJack F Vogel if (addr_list->num_elements == 0 || 690956c2c47bSJack F Vogel addr_list->vsi_id != vsi->vsi_num || 691056c2c47bSJack F Vogel msg_size != expected_size) { 691156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 691256c2c47bSJack F Vogel I40E_ERR_PARAM); 691356c2c47bSJack F Vogel return; 691456c2c47bSJack F Vogel } 691556c2c47bSJack F Vogel 691656c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 691756c2c47bSJack F Vogel if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) { 691856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 691956c2c47bSJack F Vogel I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM); 692056c2c47bSJack F Vogel return; 692156c2c47bSJack F Vogel } 692256c2c47bSJack F Vogel } 692356c2c47bSJack F Vogel 692456c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 692556c2c47bSJack F Vogel addr = &addr_list->list[i]; 692656c2c47bSJack F Vogel ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY); 692756c2c47bSJack F Vogel } 692856c2c47bSJack F Vogel 692956c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS); 693056c2c47bSJack F Vogel } 693156c2c47bSJack F Vogel 693256c2c47bSJack F Vogel static void 693356c2c47bSJack F Vogel ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 693456c2c47bSJack F Vogel uint16_t msg_size) 693556c2c47bSJack F Vogel { 693656c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr_list *addr_list; 693756c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr *addr; 693856c2c47bSJack F Vogel size_t expected_size; 693956c2c47bSJack F Vogel int i; 694056c2c47bSJack F Vogel 694156c2c47bSJack F Vogel if (msg_size < sizeof(*addr_list)) { 694256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 694356c2c47bSJack F Vogel I40E_ERR_PARAM); 694456c2c47bSJack F Vogel return; 694556c2c47bSJack F Vogel } 694656c2c47bSJack F Vogel 694756c2c47bSJack F Vogel addr_list = msg; 694856c2c47bSJack F Vogel expected_size = sizeof(*addr_list) + 694956c2c47bSJack F Vogel addr_list->num_elements * sizeof(*addr); 695056c2c47bSJack F Vogel 695156c2c47bSJack F Vogel if (addr_list->num_elements == 0 || 695256c2c47bSJack F Vogel addr_list->vsi_id != vf->vsi.vsi_num || 695356c2c47bSJack F Vogel msg_size != expected_size) { 695456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 695556c2c47bSJack F Vogel I40E_ERR_PARAM); 695656c2c47bSJack F Vogel return; 695756c2c47bSJack F Vogel } 695856c2c47bSJack F Vogel 695956c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 696056c2c47bSJack F Vogel addr = &addr_list->list[i]; 696156c2c47bSJack F Vogel if (ixl_zero_mac(addr->addr) || ixl_bcast_mac(addr->addr)) { 696256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 696356c2c47bSJack F Vogel I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM); 696456c2c47bSJack F Vogel return; 696556c2c47bSJack F Vogel } 696656c2c47bSJack F Vogel } 696756c2c47bSJack F Vogel 696856c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 696956c2c47bSJack F Vogel addr = &addr_list->list[i]; 697056c2c47bSJack F Vogel ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY); 697156c2c47bSJack F Vogel } 697256c2c47bSJack F Vogel 697356c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS); 697456c2c47bSJack F Vogel } 697556c2c47bSJack F Vogel 697656c2c47bSJack F Vogel static enum i40e_status_code 697756c2c47bSJack F Vogel ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf) 697856c2c47bSJack F Vogel { 697956c2c47bSJack F Vogel struct i40e_vsi_context vsi_ctx; 698056c2c47bSJack F Vogel 698156c2c47bSJack F Vogel vsi_ctx.seid = vf->vsi.seid; 698256c2c47bSJack F Vogel 698356c2c47bSJack F Vogel bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); 698456c2c47bSJack F Vogel vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID); 698556c2c47bSJack F Vogel vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 698656c2c47bSJack F Vogel I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 698756c2c47bSJack F Vogel return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL)); 698856c2c47bSJack F Vogel } 698956c2c47bSJack F Vogel 699056c2c47bSJack F Vogel static void 699156c2c47bSJack F Vogel ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 699256c2c47bSJack F Vogel uint16_t msg_size) 699356c2c47bSJack F Vogel { 699456c2c47bSJack F Vogel struct i40e_virtchnl_vlan_filter_list *filter_list; 699556c2c47bSJack F Vogel enum i40e_status_code code; 699656c2c47bSJack F Vogel size_t expected_size; 699756c2c47bSJack F Vogel int i; 699856c2c47bSJack F Vogel 699956c2c47bSJack F Vogel if (msg_size < sizeof(*filter_list)) { 700056c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 700156c2c47bSJack F Vogel I40E_ERR_PARAM); 700256c2c47bSJack F Vogel return; 700356c2c47bSJack F Vogel } 700456c2c47bSJack F Vogel 700556c2c47bSJack F Vogel filter_list = msg; 700656c2c47bSJack F Vogel expected_size = sizeof(*filter_list) + 700756c2c47bSJack F Vogel filter_list->num_elements * sizeof(uint16_t); 700856c2c47bSJack F Vogel if (filter_list->num_elements == 0 || 700956c2c47bSJack F Vogel filter_list->vsi_id != vf->vsi.vsi_num || 701056c2c47bSJack F Vogel msg_size != expected_size) { 701156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 701256c2c47bSJack F Vogel I40E_ERR_PARAM); 701356c2c47bSJack F Vogel return; 701456c2c47bSJack F Vogel } 701556c2c47bSJack F Vogel 701656c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) { 701756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 701856c2c47bSJack F Vogel I40E_ERR_PARAM); 701956c2c47bSJack F Vogel return; 702056c2c47bSJack F Vogel } 702156c2c47bSJack F Vogel 702256c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) { 702356c2c47bSJack F Vogel if (filter_list->vlan_id[i] > EVL_VLID_MASK) { 702456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 702556c2c47bSJack F Vogel I40E_ERR_PARAM); 702656c2c47bSJack F Vogel return; 702756c2c47bSJack F Vogel } 702856c2c47bSJack F Vogel } 702956c2c47bSJack F Vogel 703056c2c47bSJack F Vogel code = ixl_vf_enable_vlan_strip(pf, vf); 703156c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 703256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 703356c2c47bSJack F Vogel I40E_ERR_PARAM); 703456c2c47bSJack F Vogel } 703556c2c47bSJack F Vogel 703656c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) 703756c2c47bSJack F Vogel ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]); 703856c2c47bSJack F Vogel 703956c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN); 704056c2c47bSJack F Vogel } 704156c2c47bSJack F Vogel 704256c2c47bSJack F Vogel static void 704356c2c47bSJack F Vogel ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 704456c2c47bSJack F Vogel uint16_t msg_size) 704556c2c47bSJack F Vogel { 704656c2c47bSJack F Vogel struct i40e_virtchnl_vlan_filter_list *filter_list; 704756c2c47bSJack F Vogel int i; 704856c2c47bSJack F Vogel size_t expected_size; 704956c2c47bSJack F Vogel 705056c2c47bSJack F Vogel if (msg_size < sizeof(*filter_list)) { 705156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN, 705256c2c47bSJack F Vogel I40E_ERR_PARAM); 705356c2c47bSJack F Vogel return; 705456c2c47bSJack F Vogel } 705556c2c47bSJack F Vogel 705656c2c47bSJack F Vogel filter_list = msg; 705756c2c47bSJack F Vogel expected_size = sizeof(*filter_list) + 705856c2c47bSJack F Vogel filter_list->num_elements * sizeof(uint16_t); 705956c2c47bSJack F Vogel if (filter_list->num_elements == 0 || 706056c2c47bSJack F Vogel filter_list->vsi_id != vf->vsi.vsi_num || 706156c2c47bSJack F Vogel msg_size != expected_size) { 706256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN, 706356c2c47bSJack F Vogel I40E_ERR_PARAM); 706456c2c47bSJack F Vogel return; 706556c2c47bSJack F Vogel } 706656c2c47bSJack F Vogel 706756c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) { 706856c2c47bSJack F Vogel if (filter_list->vlan_id[i] > EVL_VLID_MASK) { 706956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 707056c2c47bSJack F Vogel I40E_ERR_PARAM); 707156c2c47bSJack F Vogel return; 707256c2c47bSJack F Vogel } 707356c2c47bSJack F Vogel } 707456c2c47bSJack F Vogel 707556c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) { 707656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 707756c2c47bSJack F Vogel I40E_ERR_PARAM); 707856c2c47bSJack F Vogel return; 707956c2c47bSJack F Vogel } 708056c2c47bSJack F Vogel 708156c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) 708256c2c47bSJack F Vogel ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]); 708356c2c47bSJack F Vogel 708456c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN); 708556c2c47bSJack F Vogel } 708656c2c47bSJack F Vogel 708756c2c47bSJack F Vogel static void 708856c2c47bSJack F Vogel ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, 708956c2c47bSJack F Vogel void *msg, uint16_t msg_size) 709056c2c47bSJack F Vogel { 709156c2c47bSJack F Vogel struct i40e_virtchnl_promisc_info *info; 709256c2c47bSJack F Vogel enum i40e_status_code code; 709356c2c47bSJack F Vogel 709456c2c47bSJack F Vogel if (msg_size != sizeof(*info)) { 709556c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 709656c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 709756c2c47bSJack F Vogel return; 709856c2c47bSJack F Vogel } 709956c2c47bSJack F Vogel 710029899c0aSKevin Lo if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) { 710156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 710256c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 710356c2c47bSJack F Vogel return; 710456c2c47bSJack F Vogel } 710556c2c47bSJack F Vogel 710656c2c47bSJack F Vogel info = msg; 710756c2c47bSJack F Vogel if (info->vsi_id != vf->vsi.vsi_num) { 710856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 710956c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 711056c2c47bSJack F Vogel return; 711156c2c47bSJack F Vogel } 711256c2c47bSJack F Vogel 711356c2c47bSJack F Vogel code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id, 711456c2c47bSJack F Vogel info->flags & I40E_FLAG_VF_UNICAST_PROMISC, NULL); 711556c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 711656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 711756c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); 711856c2c47bSJack F Vogel return; 711956c2c47bSJack F Vogel } 712056c2c47bSJack F Vogel 712156c2c47bSJack F Vogel code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id, 712256c2c47bSJack F Vogel info->flags & I40E_FLAG_VF_MULTICAST_PROMISC, NULL); 712356c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 712456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 712556c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); 712656c2c47bSJack F Vogel return; 712756c2c47bSJack F Vogel } 712856c2c47bSJack F Vogel 712956c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE); 713056c2c47bSJack F Vogel } 713156c2c47bSJack F Vogel 713256c2c47bSJack F Vogel static void 713356c2c47bSJack F Vogel ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 713456c2c47bSJack F Vogel uint16_t msg_size) 713556c2c47bSJack F Vogel { 713656c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *queue; 713756c2c47bSJack F Vogel 713856c2c47bSJack F Vogel if (msg_size != sizeof(*queue)) { 713956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 714056c2c47bSJack F Vogel I40E_ERR_PARAM); 714156c2c47bSJack F Vogel return; 714256c2c47bSJack F Vogel } 714356c2c47bSJack F Vogel 714456c2c47bSJack F Vogel queue = msg; 714556c2c47bSJack F Vogel if (queue->vsi_id != vf->vsi.vsi_num) { 714656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 714756c2c47bSJack F Vogel I40E_ERR_PARAM); 714856c2c47bSJack F Vogel return; 714956c2c47bSJack F Vogel } 715056c2c47bSJack F Vogel 715156c2c47bSJack F Vogel ixl_update_eth_stats(&vf->vsi); 715256c2c47bSJack F Vogel 715356c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 715456c2c47bSJack F Vogel I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats)); 715556c2c47bSJack F Vogel } 715656c2c47bSJack F Vogel 715756c2c47bSJack F Vogel static void 715856c2c47bSJack F Vogel ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event) 715956c2c47bSJack F Vogel { 716056c2c47bSJack F Vogel struct ixl_vf *vf; 716156c2c47bSJack F Vogel void *msg; 716256c2c47bSJack F Vogel uint16_t vf_num, msg_size; 716356c2c47bSJack F Vogel uint32_t opcode; 716456c2c47bSJack F Vogel 716556c2c47bSJack F Vogel vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id; 716656c2c47bSJack F Vogel opcode = le32toh(event->desc.cookie_high); 716756c2c47bSJack F Vogel 716856c2c47bSJack F Vogel if (vf_num >= pf->num_vfs) { 716956c2c47bSJack F Vogel device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num); 717056c2c47bSJack F Vogel return; 717156c2c47bSJack F Vogel } 717256c2c47bSJack F Vogel 717356c2c47bSJack F Vogel vf = &pf->vfs[vf_num]; 717456c2c47bSJack F Vogel msg = event->msg_buf; 717556c2c47bSJack F Vogel msg_size = event->msg_len; 717656c2c47bSJack F Vogel 717756c2c47bSJack F Vogel I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode), 717856c2c47bSJack F Vogel "Got msg %s(%d) from VF-%d of size %d\n", 717956c2c47bSJack F Vogel ixl_vc_opcode_str(opcode), opcode, vf_num, msg_size); 718056c2c47bSJack F Vogel 718156c2c47bSJack F Vogel switch (opcode) { 718256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_VERSION: 718356c2c47bSJack F Vogel ixl_vf_version_msg(pf, vf, msg, msg_size); 718456c2c47bSJack F Vogel break; 718556c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_RESET_VF: 718656c2c47bSJack F Vogel ixl_vf_reset_msg(pf, vf, msg, msg_size); 718756c2c47bSJack F Vogel break; 718856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: 718956c2c47bSJack F Vogel ixl_vf_get_resources_msg(pf, vf, msg, msg_size); 719056c2c47bSJack F Vogel break; 719156c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: 719256c2c47bSJack F Vogel ixl_vf_config_vsi_msg(pf, vf, msg, msg_size); 719356c2c47bSJack F Vogel break; 719456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: 719556c2c47bSJack F Vogel ixl_vf_config_irq_msg(pf, vf, msg, msg_size); 719656c2c47bSJack F Vogel break; 719756c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ENABLE_QUEUES: 719856c2c47bSJack F Vogel ixl_vf_enable_queues_msg(pf, vf, msg, msg_size); 719956c2c47bSJack F Vogel break; 720056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DISABLE_QUEUES: 720156c2c47bSJack F Vogel ixl_vf_disable_queues_msg(pf, vf, msg, msg_size); 720256c2c47bSJack F Vogel break; 720356c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: 720456c2c47bSJack F Vogel ixl_vf_add_mac_msg(pf, vf, msg, msg_size); 720556c2c47bSJack F Vogel break; 720656c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: 720756c2c47bSJack F Vogel ixl_vf_del_mac_msg(pf, vf, msg, msg_size); 720856c2c47bSJack F Vogel break; 720956c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_VLAN: 721056c2c47bSJack F Vogel ixl_vf_add_vlan_msg(pf, vf, msg, msg_size); 721156c2c47bSJack F Vogel break; 721256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_VLAN: 721356c2c47bSJack F Vogel ixl_vf_del_vlan_msg(pf, vf, msg, msg_size); 721456c2c47bSJack F Vogel break; 721556c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: 721656c2c47bSJack F Vogel ixl_vf_config_promisc_msg(pf, vf, msg, msg_size); 721756c2c47bSJack F Vogel break; 721856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 721956c2c47bSJack F Vogel ixl_vf_get_stats_msg(pf, vf, msg, msg_size); 722056c2c47bSJack F Vogel break; 722156c2c47bSJack F Vogel 722256c2c47bSJack F Vogel /* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */ 722356c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: 722456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: 722556c2c47bSJack F Vogel default: 722656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED); 722756c2c47bSJack F Vogel break; 722856c2c47bSJack F Vogel } 722956c2c47bSJack F Vogel } 723056c2c47bSJack F Vogel 723156c2c47bSJack F Vogel /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */ 723256c2c47bSJack F Vogel static void 723356c2c47bSJack F Vogel ixl_handle_vflr(void *arg, int pending) 723456c2c47bSJack F Vogel { 723556c2c47bSJack F Vogel struct ixl_pf *pf; 723656c2c47bSJack F Vogel struct i40e_hw *hw; 723756c2c47bSJack F Vogel uint16_t global_vf_num; 723856c2c47bSJack F Vogel uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0; 723956c2c47bSJack F Vogel int i; 724056c2c47bSJack F Vogel 724156c2c47bSJack F Vogel pf = arg; 724256c2c47bSJack F Vogel hw = &pf->hw; 724356c2c47bSJack F Vogel 724456c2c47bSJack F Vogel IXL_PF_LOCK(pf); 724556c2c47bSJack F Vogel for (i = 0; i < pf->num_vfs; i++) { 724656c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + i; 724756c2c47bSJack F Vogel 724856c2c47bSJack F Vogel vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num); 724956c2c47bSJack F Vogel vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num); 725056c2c47bSJack F Vogel vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index)); 725156c2c47bSJack F Vogel if (vflrstat & vflrstat_mask) { 725256c2c47bSJack F Vogel wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index), 725356c2c47bSJack F Vogel vflrstat_mask); 725456c2c47bSJack F Vogel 725556c2c47bSJack F Vogel ixl_reinit_vf(pf, &pf->vfs[i]); 725656c2c47bSJack F Vogel } 725756c2c47bSJack F Vogel } 725856c2c47bSJack F Vogel 725956c2c47bSJack F Vogel icr0 = rd32(hw, I40E_PFINT_ICR0_ENA); 726056c2c47bSJack F Vogel icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK; 726156c2c47bSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, icr0); 726256c2c47bSJack F Vogel ixl_flush(hw); 726356c2c47bSJack F Vogel 726456c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 726556c2c47bSJack F Vogel } 726656c2c47bSJack F Vogel 726756c2c47bSJack F Vogel static int 726856c2c47bSJack F Vogel ixl_adminq_err_to_errno(enum i40e_admin_queue_err err) 726956c2c47bSJack F Vogel { 727056c2c47bSJack F Vogel 727156c2c47bSJack F Vogel switch (err) { 727256c2c47bSJack F Vogel case I40E_AQ_RC_EPERM: 727356c2c47bSJack F Vogel return (EPERM); 727456c2c47bSJack F Vogel case I40E_AQ_RC_ENOENT: 727556c2c47bSJack F Vogel return (ENOENT); 727656c2c47bSJack F Vogel case I40E_AQ_RC_ESRCH: 727756c2c47bSJack F Vogel return (ESRCH); 727856c2c47bSJack F Vogel case I40E_AQ_RC_EINTR: 727956c2c47bSJack F Vogel return (EINTR); 728056c2c47bSJack F Vogel case I40E_AQ_RC_EIO: 728156c2c47bSJack F Vogel return (EIO); 728256c2c47bSJack F Vogel case I40E_AQ_RC_ENXIO: 728356c2c47bSJack F Vogel return (ENXIO); 728456c2c47bSJack F Vogel case I40E_AQ_RC_E2BIG: 728556c2c47bSJack F Vogel return (E2BIG); 728656c2c47bSJack F Vogel case I40E_AQ_RC_EAGAIN: 728756c2c47bSJack F Vogel return (EAGAIN); 728856c2c47bSJack F Vogel case I40E_AQ_RC_ENOMEM: 728956c2c47bSJack F Vogel return (ENOMEM); 729056c2c47bSJack F Vogel case I40E_AQ_RC_EACCES: 729156c2c47bSJack F Vogel return (EACCES); 729256c2c47bSJack F Vogel case I40E_AQ_RC_EFAULT: 729356c2c47bSJack F Vogel return (EFAULT); 729456c2c47bSJack F Vogel case I40E_AQ_RC_EBUSY: 729556c2c47bSJack F Vogel return (EBUSY); 729656c2c47bSJack F Vogel case I40E_AQ_RC_EEXIST: 729756c2c47bSJack F Vogel return (EEXIST); 729856c2c47bSJack F Vogel case I40E_AQ_RC_EINVAL: 729956c2c47bSJack F Vogel return (EINVAL); 730056c2c47bSJack F Vogel case I40E_AQ_RC_ENOTTY: 730156c2c47bSJack F Vogel return (ENOTTY); 730256c2c47bSJack F Vogel case I40E_AQ_RC_ENOSPC: 730356c2c47bSJack F Vogel return (ENOSPC); 730456c2c47bSJack F Vogel case I40E_AQ_RC_ENOSYS: 730556c2c47bSJack F Vogel return (ENOSYS); 730656c2c47bSJack F Vogel case I40E_AQ_RC_ERANGE: 730756c2c47bSJack F Vogel return (ERANGE); 730856c2c47bSJack F Vogel case I40E_AQ_RC_EFLUSHED: 730956c2c47bSJack F Vogel return (EINVAL); /* No exact equivalent in errno.h */ 731056c2c47bSJack F Vogel case I40E_AQ_RC_BAD_ADDR: 731156c2c47bSJack F Vogel return (EFAULT); 731256c2c47bSJack F Vogel case I40E_AQ_RC_EMODE: 731356c2c47bSJack F Vogel return (EPERM); 731456c2c47bSJack F Vogel case I40E_AQ_RC_EFBIG: 731556c2c47bSJack F Vogel return (EFBIG); 731656c2c47bSJack F Vogel default: 731756c2c47bSJack F Vogel return (EINVAL); 731856c2c47bSJack F Vogel } 731956c2c47bSJack F Vogel } 732056c2c47bSJack F Vogel 732156c2c47bSJack F Vogel static int 7322a48d00d2SEric Joyner ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params) 732356c2c47bSJack F Vogel { 732456c2c47bSJack F Vogel struct ixl_pf *pf; 732556c2c47bSJack F Vogel struct i40e_hw *hw; 732656c2c47bSJack F Vogel struct ixl_vsi *pf_vsi; 732756c2c47bSJack F Vogel enum i40e_status_code ret; 732856c2c47bSJack F Vogel int i, error; 732956c2c47bSJack F Vogel 733056c2c47bSJack F Vogel pf = device_get_softc(dev); 733156c2c47bSJack F Vogel hw = &pf->hw; 733256c2c47bSJack F Vogel pf_vsi = &pf->vsi; 733356c2c47bSJack F Vogel 733456c2c47bSJack F Vogel IXL_PF_LOCK(pf); 733556c2c47bSJack F Vogel pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT | 733656c2c47bSJack F Vogel M_ZERO); 733756c2c47bSJack F Vogel 733856c2c47bSJack F Vogel if (pf->vfs == NULL) { 733956c2c47bSJack F Vogel error = ENOMEM; 734056c2c47bSJack F Vogel goto fail; 734156c2c47bSJack F Vogel } 734256c2c47bSJack F Vogel 734356c2c47bSJack F Vogel for (i = 0; i < num_vfs; i++) 734456c2c47bSJack F Vogel sysctl_ctx_init(&pf->vfs[i].ctx); 734556c2c47bSJack F Vogel 734656c2c47bSJack F Vogel ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid, 73471d767a8eSEric Joyner 1, FALSE, &pf->veb_seid, FALSE, NULL); 734856c2c47bSJack F Vogel if (ret != I40E_SUCCESS) { 734956c2c47bSJack F Vogel error = ixl_adminq_err_to_errno(hw->aq.asq_last_status); 735056c2c47bSJack F Vogel device_printf(dev, "add_veb failed; code=%d error=%d", ret, 735156c2c47bSJack F Vogel error); 735256c2c47bSJack F Vogel goto fail; 735356c2c47bSJack F Vogel } 735456c2c47bSJack F Vogel 73556c426059SEric Joyner // TODO: [Configure MSI-X here] 735656c2c47bSJack F Vogel ixl_enable_adminq(hw); 735756c2c47bSJack F Vogel 735856c2c47bSJack F Vogel pf->num_vfs = num_vfs; 735956c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 736056c2c47bSJack F Vogel return (0); 736156c2c47bSJack F Vogel 736256c2c47bSJack F Vogel fail: 736356c2c47bSJack F Vogel free(pf->vfs, M_IXL); 736456c2c47bSJack F Vogel pf->vfs = NULL; 736556c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 736656c2c47bSJack F Vogel return (error); 736756c2c47bSJack F Vogel } 736856c2c47bSJack F Vogel 736956c2c47bSJack F Vogel static void 7370a48d00d2SEric Joyner ixl_iov_uninit(device_t dev) 737156c2c47bSJack F Vogel { 737256c2c47bSJack F Vogel struct ixl_pf *pf; 737356c2c47bSJack F Vogel struct i40e_hw *hw; 737456c2c47bSJack F Vogel struct ixl_vsi *vsi; 737556c2c47bSJack F Vogel struct ifnet *ifp; 737656c2c47bSJack F Vogel struct ixl_vf *vfs; 737756c2c47bSJack F Vogel int i, num_vfs; 737856c2c47bSJack F Vogel 737956c2c47bSJack F Vogel pf = device_get_softc(dev); 738056c2c47bSJack F Vogel hw = &pf->hw; 738156c2c47bSJack F Vogel vsi = &pf->vsi; 738256c2c47bSJack F Vogel ifp = vsi->ifp; 738356c2c47bSJack F Vogel 738456c2c47bSJack F Vogel IXL_PF_LOCK(pf); 738556c2c47bSJack F Vogel for (i = 0; i < pf->num_vfs; i++) { 738656c2c47bSJack F Vogel if (pf->vfs[i].vsi.seid != 0) 738756c2c47bSJack F Vogel i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL); 738856c2c47bSJack F Vogel } 738956c2c47bSJack F Vogel 739056c2c47bSJack F Vogel if (pf->veb_seid != 0) { 739156c2c47bSJack F Vogel i40e_aq_delete_element(hw, pf->veb_seid, NULL); 739256c2c47bSJack F Vogel pf->veb_seid = 0; 739356c2c47bSJack F Vogel } 739456c2c47bSJack F Vogel 739556c2c47bSJack F Vogel if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 739656c2c47bSJack F Vogel ixl_disable_intr(vsi); 739756c2c47bSJack F Vogel 739856c2c47bSJack F Vogel vfs = pf->vfs; 739956c2c47bSJack F Vogel num_vfs = pf->num_vfs; 740056c2c47bSJack F Vogel 740156c2c47bSJack F Vogel pf->vfs = NULL; 740256c2c47bSJack F Vogel pf->num_vfs = 0; 740356c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 740456c2c47bSJack F Vogel 740556c2c47bSJack F Vogel /* Do this after the unlock as sysctl_ctx_free might sleep. */ 740656c2c47bSJack F Vogel for (i = 0; i < num_vfs; i++) 740756c2c47bSJack F Vogel sysctl_ctx_free(&vfs[i].ctx); 740856c2c47bSJack F Vogel free(vfs, M_IXL); 740956c2c47bSJack F Vogel } 741056c2c47bSJack F Vogel 741156c2c47bSJack F Vogel static int 741256c2c47bSJack F Vogel ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params) 741356c2c47bSJack F Vogel { 741456c2c47bSJack F Vogel char sysctl_name[QUEUE_NAME_LEN]; 741556c2c47bSJack F Vogel struct ixl_pf *pf; 741656c2c47bSJack F Vogel struct ixl_vf *vf; 741756c2c47bSJack F Vogel const void *mac; 741856c2c47bSJack F Vogel size_t size; 741956c2c47bSJack F Vogel int error; 742056c2c47bSJack F Vogel 742156c2c47bSJack F Vogel pf = device_get_softc(dev); 742256c2c47bSJack F Vogel vf = &pf->vfs[vfnum]; 742356c2c47bSJack F Vogel 742456c2c47bSJack F Vogel IXL_PF_LOCK(pf); 742556c2c47bSJack F Vogel vf->vf_num = vfnum; 742656c2c47bSJack F Vogel 742756c2c47bSJack F Vogel vf->vsi.back = pf; 742856c2c47bSJack F Vogel vf->vf_flags = VF_FLAG_ENABLED; 742956c2c47bSJack F Vogel SLIST_INIT(&vf->vsi.ftl); 743056c2c47bSJack F Vogel 743156c2c47bSJack F Vogel error = ixl_vf_setup_vsi(pf, vf); 743256c2c47bSJack F Vogel if (error != 0) 743356c2c47bSJack F Vogel goto out; 743456c2c47bSJack F Vogel 743556c2c47bSJack F Vogel if (nvlist_exists_binary(params, "mac-addr")) { 743656c2c47bSJack F Vogel mac = nvlist_get_binary(params, "mac-addr", &size); 743756c2c47bSJack F Vogel bcopy(mac, vf->mac, ETHER_ADDR_LEN); 743856c2c47bSJack F Vogel 743956c2c47bSJack F Vogel if (nvlist_get_bool(params, "allow-set-mac")) 744056c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_SET_MAC_CAP; 744156c2c47bSJack F Vogel } else 744256c2c47bSJack F Vogel /* 744356c2c47bSJack F Vogel * If the administrator has not specified a MAC address then 744456c2c47bSJack F Vogel * we must allow the VF to choose one. 744556c2c47bSJack F Vogel */ 744656c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_SET_MAC_CAP; 744756c2c47bSJack F Vogel 744856c2c47bSJack F Vogel if (nvlist_get_bool(params, "mac-anti-spoof")) 744956c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF; 745056c2c47bSJack F Vogel 745156c2c47bSJack F Vogel if (nvlist_get_bool(params, "allow-promisc")) 745256c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_PROMISC_CAP; 745356c2c47bSJack F Vogel 74541d767a8eSEric Joyner /* TODO: Get VLAN that PF has set for the VF */ 74551d767a8eSEric Joyner 745656c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_VLAN_CAP; 745756c2c47bSJack F Vogel 745856c2c47bSJack F Vogel ixl_reset_vf(pf, vf); 745956c2c47bSJack F Vogel out: 746056c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 746156c2c47bSJack F Vogel if (error == 0) { 746256c2c47bSJack F Vogel snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum); 746356c2c47bSJack F Vogel ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name); 746456c2c47bSJack F Vogel } 746556c2c47bSJack F Vogel 746656c2c47bSJack F Vogel return (error); 746756c2c47bSJack F Vogel } 746856c2c47bSJack F Vogel #endif /* PCI_IOV */ 7469