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*6c426059SEric Joyner char ixl_driver_version[] = "1.4.20-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 *); 108*6c426059SEric Joyner 109*6c426059SEric Joyner static int ixl_setup_adminq_msix(struct ixl_pf *); 110*6c426059SEric Joyner static int ixl_setup_adminq_tq(struct ixl_pf *); 111*6c426059SEric Joyner static int ixl_setup_queue_msix(struct ixl_vsi *); 112*6c426059SEric Joyner static int ixl_setup_queue_tqs(struct ixl_vsi *); 113*6c426059SEric Joyner static int ixl_teardown_adminq_msix(struct ixl_pf *); 114*6c426059SEric Joyner static int ixl_teardown_queue_msix(struct ixl_vsi *); 115*6c426059SEric Joyner static void ixl_configure_intr0_msix(struct ixl_pf *); 116*6c426059SEric Joyner static void ixl_configure_queue_intr_msix(struct ixl_pf *); 117*6c426059SEric Joyner static void ixl_free_queue_tqs(struct ixl_vsi *); 118*6c426059SEric Joyner static void ixl_free_adminq_tq(struct ixl_pf *); 119*6c426059SEric 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); 132*6c426059SEric 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 *); 211*6c426059SEric Joyner static void ixl_handle_empr_reset(struct ixl_pf *); 212*6c426059SEric Joyner static int ixl_rebuild_hw_structs_after_reset(struct ixl_pf *); 21361ae650dSJack F Vogel 214223d846dSEric Joyner 21556c2c47bSJack F Vogel #ifdef PCI_IOV 21656c2c47bSJack F Vogel static int ixl_adminq_err_to_errno(enum i40e_admin_queue_err err); 21756c2c47bSJack F Vogel 218a48d00d2SEric Joyner static int ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t*); 219a48d00d2SEric Joyner static void ixl_iov_uninit(device_t dev); 22056c2c47bSJack F Vogel static int ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t*); 22156c2c47bSJack F Vogel 22256c2c47bSJack F Vogel static void ixl_handle_vf_msg(struct ixl_pf *, 22356c2c47bSJack F Vogel struct i40e_arq_event_info *); 22456c2c47bSJack F Vogel static void ixl_handle_vflr(void *arg, int pending); 22556c2c47bSJack F Vogel 22656c2c47bSJack F Vogel static void ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf); 22756c2c47bSJack F Vogel static void ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf); 22861ae650dSJack F Vogel #endif 22961ae650dSJack F Vogel 23061ae650dSJack F Vogel /********************************************************************* 23161ae650dSJack F Vogel * FreeBSD Device Interface Entry Points 23261ae650dSJack F Vogel *********************************************************************/ 23361ae650dSJack F Vogel 23461ae650dSJack F Vogel static device_method_t ixl_methods[] = { 23561ae650dSJack F Vogel /* Device interface */ 23661ae650dSJack F Vogel DEVMETHOD(device_probe, ixl_probe), 23761ae650dSJack F Vogel DEVMETHOD(device_attach, ixl_attach), 23861ae650dSJack F Vogel DEVMETHOD(device_detach, ixl_detach), 23961ae650dSJack F Vogel DEVMETHOD(device_shutdown, ixl_shutdown), 24056c2c47bSJack F Vogel #ifdef PCI_IOV 241a48d00d2SEric Joyner DEVMETHOD(pci_iov_init, ixl_iov_init), 242a48d00d2SEric Joyner DEVMETHOD(pci_iov_uninit, ixl_iov_uninit), 243a48d00d2SEric Joyner DEVMETHOD(pci_iov_add_vf, ixl_add_vf), 24456c2c47bSJack F Vogel #endif 24561ae650dSJack F Vogel {0, 0} 24661ae650dSJack F Vogel }; 24761ae650dSJack F Vogel 24861ae650dSJack F Vogel static driver_t ixl_driver = { 24961ae650dSJack F Vogel "ixl", ixl_methods, sizeof(struct ixl_pf), 25061ae650dSJack F Vogel }; 25161ae650dSJack F Vogel 25261ae650dSJack F Vogel devclass_t ixl_devclass; 25361ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); 25461ae650dSJack F Vogel 25561ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1); 25661ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1); 25731830672SJack F Vogel #ifdef DEV_NETMAP 25831830672SJack F Vogel MODULE_DEPEND(ixl, netmap, 1, 1, 1); 25931830672SJack F Vogel #endif /* DEV_NETMAP */ 26031830672SJack F Vogel 26161ae650dSJack F Vogel /* 26261ae650dSJack F Vogel ** Global reset mutex 26361ae650dSJack F Vogel */ 26461ae650dSJack F Vogel static struct mtx ixl_reset_mtx; 26561ae650dSJack F Vogel 26661ae650dSJack F Vogel /* 26761ae650dSJack F Vogel ** TUNEABLE PARAMETERS: 26861ae650dSJack F Vogel */ 26961ae650dSJack F Vogel 27061ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, 27161ae650dSJack F Vogel "IXL driver parameters"); 27261ae650dSJack F Vogel 27361ae650dSJack F Vogel /* 27461ae650dSJack F Vogel * MSIX should be the default for best performance, 27561ae650dSJack F Vogel * but this allows it to be forced off for testing. 27661ae650dSJack F Vogel */ 27761ae650dSJack F Vogel static int ixl_enable_msix = 1; 27861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); 27961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, 28061ae650dSJack F Vogel "Enable MSI-X interrupts"); 28161ae650dSJack F Vogel 28261ae650dSJack F Vogel /* 28361ae650dSJack F Vogel ** Number of descriptors per ring: 28461ae650dSJack F Vogel ** - TX and RX are the same size 28561ae650dSJack F Vogel */ 28661ae650dSJack F Vogel static int ixl_ringsz = DEFAULT_RING; 28761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz); 28861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN, 28961ae650dSJack F Vogel &ixl_ringsz, 0, "Descriptor Ring Size"); 29061ae650dSJack F Vogel 29161ae650dSJack F Vogel /* 29261ae650dSJack F Vogel ** This can be set manually, if left as 0 the 29361ae650dSJack F Vogel ** number of queues will be calculated based 29461ae650dSJack F Vogel ** on cpus and msix vectors available. 29561ae650dSJack F Vogel */ 29661ae650dSJack F Vogel int ixl_max_queues = 0; 29761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues); 29861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN, 29961ae650dSJack F Vogel &ixl_max_queues, 0, "Number of Queues"); 30061ae650dSJack F Vogel 30161ae650dSJack F Vogel /* 30261ae650dSJack F Vogel ** Controls for Interrupt Throttling 30361ae650dSJack F Vogel ** - true/false for dynamic adjustment 30461ae650dSJack F Vogel ** - default values for static ITR 30561ae650dSJack F Vogel */ 30661ae650dSJack F Vogel int ixl_dynamic_rx_itr = 0; 30761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr); 30861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, 30961ae650dSJack F Vogel &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); 31061ae650dSJack F Vogel 31161ae650dSJack F Vogel int ixl_dynamic_tx_itr = 0; 31261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr); 31361ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, 31461ae650dSJack F Vogel &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); 31561ae650dSJack F Vogel 31661ae650dSJack F Vogel int ixl_rx_itr = IXL_ITR_8K; 31761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr); 31861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, 31961ae650dSJack F Vogel &ixl_rx_itr, 0, "RX Interrupt Rate"); 32061ae650dSJack F Vogel 32161ae650dSJack F Vogel int ixl_tx_itr = IXL_ITR_4K; 32261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); 32361ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, 32461ae650dSJack F Vogel &ixl_tx_itr, 0, "TX Interrupt Rate"); 32561ae650dSJack F Vogel 32661ae650dSJack F Vogel #ifdef IXL_FDIR 32761ae650dSJack F Vogel static int ixl_enable_fdir = 1; 32861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir); 32961ae650dSJack F Vogel /* Rate at which we sample */ 33061ae650dSJack F Vogel int ixl_atr_rate = 20; 33161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate); 33261ae650dSJack F Vogel #endif 33361ae650dSJack F Vogel 33431830672SJack F Vogel #ifdef DEV_NETMAP 33531830672SJack F Vogel #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */ 33631830672SJack F Vogel #include <dev/netmap/if_ixl_netmap.h> 33731830672SJack F Vogel #endif /* DEV_NETMAP */ 338e5100ee2SJack F Vogel 33961ae650dSJack F Vogel static char *ixl_fc_string[6] = { 34061ae650dSJack F Vogel "None", 34161ae650dSJack F Vogel "Rx", 34261ae650dSJack F Vogel "Tx", 34361ae650dSJack F Vogel "Full", 34461ae650dSJack F Vogel "Priority", 34561ae650dSJack F Vogel "Default" 34661ae650dSJack F Vogel }; 34761ae650dSJack F Vogel 34856c2c47bSJack F Vogel static MALLOC_DEFINE(M_IXL, "ixl", "ixl driver allocations"); 34956c2c47bSJack F Vogel 35056c2c47bSJack F Vogel static uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] = 35156c2c47bSJack F Vogel {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 35261ae650dSJack F Vogel 35361ae650dSJack F Vogel /********************************************************************* 35461ae650dSJack F Vogel * Device identification routine 35561ae650dSJack F Vogel * 35661ae650dSJack F Vogel * ixl_probe determines if the driver should be loaded on 35761ae650dSJack F Vogel * the hardware based on PCI vendor/device id of the device. 35861ae650dSJack F Vogel * 35961ae650dSJack F Vogel * return BUS_PROBE_DEFAULT on success, positive on failure 36061ae650dSJack F Vogel *********************************************************************/ 36161ae650dSJack F Vogel 36261ae650dSJack F Vogel static int 36361ae650dSJack F Vogel ixl_probe(device_t dev) 36461ae650dSJack F Vogel { 36561ae650dSJack F Vogel ixl_vendor_info_t *ent; 36661ae650dSJack F Vogel 36761ae650dSJack F Vogel u16 pci_vendor_id, pci_device_id; 36861ae650dSJack F Vogel u16 pci_subvendor_id, pci_subdevice_id; 36961ae650dSJack F Vogel char device_name[256]; 37061ae650dSJack F Vogel static bool lock_init = FALSE; 37161ae650dSJack F Vogel 3721d767a8eSEric Joyner #if 0 37361ae650dSJack F Vogel INIT_DEBUGOUT("ixl_probe: begin"); 3741d767a8eSEric Joyner #endif 37561ae650dSJack F Vogel pci_vendor_id = pci_get_vendor(dev); 37661ae650dSJack F Vogel if (pci_vendor_id != I40E_INTEL_VENDOR_ID) 37761ae650dSJack F Vogel return (ENXIO); 37861ae650dSJack F Vogel 37961ae650dSJack F Vogel pci_device_id = pci_get_device(dev); 38061ae650dSJack F Vogel pci_subvendor_id = pci_get_subvendor(dev); 38161ae650dSJack F Vogel pci_subdevice_id = pci_get_subdevice(dev); 38261ae650dSJack F Vogel 38361ae650dSJack F Vogel ent = ixl_vendor_info_array; 38461ae650dSJack F Vogel while (ent->vendor_id != 0) { 38561ae650dSJack F Vogel if ((pci_vendor_id == ent->vendor_id) && 38661ae650dSJack F Vogel (pci_device_id == ent->device_id) && 38761ae650dSJack F Vogel 38861ae650dSJack F Vogel ((pci_subvendor_id == ent->subvendor_id) || 38961ae650dSJack F Vogel (ent->subvendor_id == 0)) && 39061ae650dSJack F Vogel 39161ae650dSJack F Vogel ((pci_subdevice_id == ent->subdevice_id) || 39261ae650dSJack F Vogel (ent->subdevice_id == 0))) { 39361ae650dSJack F Vogel sprintf(device_name, "%s, Version - %s", 39461ae650dSJack F Vogel ixl_strings[ent->index], 39561ae650dSJack F Vogel ixl_driver_version); 39661ae650dSJack F Vogel device_set_desc_copy(dev, device_name); 39761ae650dSJack F Vogel /* One shot mutex init */ 39861ae650dSJack F Vogel if (lock_init == FALSE) { 39961ae650dSJack F Vogel lock_init = TRUE; 40061ae650dSJack F Vogel mtx_init(&ixl_reset_mtx, 40161ae650dSJack F Vogel "ixl_reset", 40261ae650dSJack F Vogel "IXL RESET Lock", MTX_DEF); 40361ae650dSJack F Vogel } 40461ae650dSJack F Vogel return (BUS_PROBE_DEFAULT); 40561ae650dSJack F Vogel } 40661ae650dSJack F Vogel ent++; 40761ae650dSJack F Vogel } 40861ae650dSJack F Vogel return (ENXIO); 40961ae650dSJack F Vogel } 41061ae650dSJack F Vogel 41161ae650dSJack F Vogel /********************************************************************* 41261ae650dSJack F Vogel * Device initialization routine 41361ae650dSJack F Vogel * 41461ae650dSJack F Vogel * The attach entry point is called when the driver is being loaded. 41561ae650dSJack F Vogel * This routine identifies the type of hardware, allocates all resources 41661ae650dSJack F Vogel * and initializes the hardware. 41761ae650dSJack F Vogel * 41861ae650dSJack F Vogel * return 0 on success, positive on failure 41961ae650dSJack F Vogel *********************************************************************/ 42061ae650dSJack F Vogel 42161ae650dSJack F Vogel static int 42261ae650dSJack F Vogel ixl_attach(device_t dev) 42361ae650dSJack F Vogel { 42461ae650dSJack F Vogel struct ixl_pf *pf; 42561ae650dSJack F Vogel struct i40e_hw *hw; 42661ae650dSJack F Vogel struct ixl_vsi *vsi; 42761ae650dSJack F Vogel u16 bus; 42861ae650dSJack F Vogel int error = 0; 42956c2c47bSJack F Vogel #ifdef PCI_IOV 43056c2c47bSJack F Vogel nvlist_t *pf_schema, *vf_schema; 43156c2c47bSJack F Vogel int iov_error; 43256c2c47bSJack F Vogel #endif 43361ae650dSJack F Vogel 43461ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: begin"); 43561ae650dSJack F Vogel 43661ae650dSJack F Vogel /* Allocate, clear, and link in our primary soft structure */ 43761ae650dSJack F Vogel pf = device_get_softc(dev); 43861ae650dSJack F Vogel pf->dev = pf->osdep.dev = dev; 43961ae650dSJack F Vogel hw = &pf->hw; 44061ae650dSJack F Vogel 44161ae650dSJack F Vogel /* 44261ae650dSJack F Vogel ** Note this assumes we have a single embedded VSI, 44361ae650dSJack F Vogel ** this could be enhanced later to allocate multiple 44461ae650dSJack F Vogel */ 44561ae650dSJack F Vogel vsi = &pf->vsi; 44661ae650dSJack F Vogel vsi->dev = pf->dev; 44761ae650dSJack F Vogel 44861ae650dSJack F Vogel /* Core Lock Init*/ 44961ae650dSJack F Vogel IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev)); 45061ae650dSJack F Vogel 45161ae650dSJack F Vogel /* Set up the timer callout */ 45261ae650dSJack F Vogel callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); 45361ae650dSJack F Vogel 454e5100ee2SJack F Vogel /* Save off the PCI information */ 45561ae650dSJack F Vogel hw->vendor_id = pci_get_vendor(dev); 45661ae650dSJack F Vogel hw->device_id = pci_get_device(dev); 45761ae650dSJack F Vogel hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 45861ae650dSJack F Vogel hw->subsystem_vendor_id = 45961ae650dSJack F Vogel pci_read_config(dev, PCIR_SUBVEND_0, 2); 46061ae650dSJack F Vogel hw->subsystem_device_id = 46161ae650dSJack F Vogel pci_read_config(dev, PCIR_SUBDEV_0, 2); 46261ae650dSJack F Vogel 46361ae650dSJack F Vogel hw->bus.device = pci_get_slot(dev); 46461ae650dSJack F Vogel hw->bus.func = pci_get_function(dev); 46561ae650dSJack F Vogel 46656c2c47bSJack F Vogel pf->vc_debug_lvl = 1; 46756c2c47bSJack F Vogel 46861ae650dSJack F Vogel /* Do PCI setup - map BAR0, etc */ 46961ae650dSJack F Vogel if (ixl_allocate_pci_resources(pf)) { 47061ae650dSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 47161ae650dSJack F Vogel error = ENXIO; 47261ae650dSJack F Vogel goto err_out; 47361ae650dSJack F Vogel } 47461ae650dSJack F Vogel 47561ae650dSJack F Vogel /* Establish a clean starting point */ 47661ae650dSJack F Vogel i40e_clear_hw(hw); 47761ae650dSJack F Vogel error = i40e_pf_reset(hw); 47861ae650dSJack F Vogel if (error) { 479fdb6f38aSEric Joyner device_printf(dev, "PF reset failure %d\n", error); 48061ae650dSJack F Vogel error = EIO; 48161ae650dSJack F Vogel goto err_out; 48261ae650dSJack F Vogel } 48361ae650dSJack F Vogel 48461ae650dSJack F Vogel /* Set admin queue parameters */ 48561ae650dSJack F Vogel hw->aq.num_arq_entries = IXL_AQ_LEN; 48661ae650dSJack F Vogel hw->aq.num_asq_entries = IXL_AQ_LEN; 48761ae650dSJack F Vogel hw->aq.arq_buf_size = IXL_AQ_BUFSZ; 48861ae650dSJack F Vogel hw->aq.asq_buf_size = IXL_AQ_BUFSZ; 48961ae650dSJack F Vogel 490fdb6f38aSEric Joyner /* Initialize mac filter list for VSI */ 491fdb6f38aSEric Joyner SLIST_INIT(&vsi->ftl); 492fdb6f38aSEric Joyner 49361ae650dSJack F Vogel /* Initialize the shared code */ 49461ae650dSJack F Vogel error = i40e_init_shared_code(hw); 49561ae650dSJack F Vogel if (error) { 496fdb6f38aSEric Joyner device_printf(dev, "Unable to initialize shared code, error %d\n", 497fdb6f38aSEric Joyner error); 49861ae650dSJack F Vogel error = EIO; 49961ae650dSJack F Vogel goto err_out; 50061ae650dSJack F Vogel } 50161ae650dSJack F Vogel 50261ae650dSJack F Vogel /* Set up the admin queue */ 50361ae650dSJack F Vogel error = i40e_init_adminq(hw); 504fdb6f38aSEric Joyner if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) { 505fdb6f38aSEric Joyner device_printf(dev, "Unable to initialize Admin Queue, error %d\n", 506fdb6f38aSEric Joyner error); 507fdb6f38aSEric Joyner error = EIO; 508fdb6f38aSEric Joyner goto err_out; 509fdb6f38aSEric Joyner } 5101d767a8eSEric Joyner ixl_print_nvm_version(pf); 5111d767a8eSEric Joyner 512fdb6f38aSEric Joyner if (error == I40E_ERR_FIRMWARE_API_VERSION) { 51361ae650dSJack F Vogel device_printf(dev, "The driver for the device stopped " 51461ae650dSJack F Vogel "because the NVM image is newer than expected.\n" 51561ae650dSJack F Vogel "You must install the most recent version of " 51661ae650dSJack F Vogel "the network driver.\n"); 517fdb6f38aSEric Joyner error = EIO; 51861ae650dSJack F Vogel goto err_out; 51961ae650dSJack F Vogel } 52061ae650dSJack F Vogel 52161ae650dSJack F Vogel if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 52261ae650dSJack F Vogel hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) 52361ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 52461ae650dSJack F Vogel "a newer version of the NVM image than expected.\n" 52561ae650dSJack F Vogel "Please install the most recent version of the network driver.\n"); 52661ae650dSJack F Vogel else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || 52761ae650dSJack F Vogel hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) 52861ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 52961ae650dSJack F Vogel "an older version of the NVM image than expected.\n" 53061ae650dSJack F Vogel "Please update the NVM image.\n"); 53161ae650dSJack F Vogel 53261ae650dSJack F Vogel /* Clear PXE mode */ 53361ae650dSJack F Vogel i40e_clear_pxe_mode(hw); 53461ae650dSJack F Vogel 53561ae650dSJack F Vogel /* Get capabilities from the device */ 53661ae650dSJack F Vogel error = ixl_get_hw_capabilities(pf); 53761ae650dSJack F Vogel if (error) { 53861ae650dSJack F Vogel device_printf(dev, "HW capabilities failure!\n"); 53961ae650dSJack F Vogel goto err_get_cap; 54061ae650dSJack F Vogel } 54161ae650dSJack F Vogel 54261ae650dSJack F Vogel /* Set up host memory cache */ 54356c2c47bSJack F Vogel error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 54456c2c47bSJack F Vogel hw->func_caps.num_rx_qp, 0, 0); 54561ae650dSJack F Vogel if (error) { 54661ae650dSJack F Vogel device_printf(dev, "init_lan_hmc failed: %d\n", error); 54761ae650dSJack F Vogel goto err_get_cap; 54861ae650dSJack F Vogel } 54961ae650dSJack F Vogel 55061ae650dSJack F Vogel error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 55161ae650dSJack F Vogel if (error) { 55261ae650dSJack F Vogel device_printf(dev, "configure_lan_hmc failed: %d\n", error); 55361ae650dSJack F Vogel goto err_mac_hmc; 55461ae650dSJack F Vogel } 55561ae650dSJack F Vogel 55661ae650dSJack F Vogel /* Disable LLDP from the firmware */ 55761ae650dSJack F Vogel i40e_aq_stop_lldp(hw, TRUE, NULL); 55861ae650dSJack F Vogel 55961ae650dSJack F Vogel i40e_get_mac_addr(hw, hw->mac.addr); 56061ae650dSJack F Vogel error = i40e_validate_mac_addr(hw->mac.addr); 56161ae650dSJack F Vogel if (error) { 56261ae650dSJack F Vogel device_printf(dev, "validate_mac_addr failed: %d\n", error); 56361ae650dSJack F Vogel goto err_mac_hmc; 56461ae650dSJack F Vogel } 56561ae650dSJack F Vogel bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 56661ae650dSJack F Vogel i40e_get_port_mac_addr(hw, hw->mac.port_addr); 56761ae650dSJack F Vogel 568e5100ee2SJack F Vogel /* Set up VSI and queues */ 56961ae650dSJack F Vogel if (ixl_setup_stations(pf) != 0) { 57061ae650dSJack F Vogel device_printf(dev, "setup stations failed!\n"); 57161ae650dSJack F Vogel error = ENOMEM; 57261ae650dSJack F Vogel goto err_mac_hmc; 57361ae650dSJack F Vogel } 57461ae650dSJack F Vogel 575b6c8f260SJack F Vogel if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 576b6c8f260SJack F Vogel (hw->aq.fw_maj_ver < 4)) { 57761ae650dSJack F Vogel i40e_msec_delay(75); 57861ae650dSJack F Vogel error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 579223d846dSEric Joyner if (error) { 58061ae650dSJack F Vogel device_printf(dev, "link restart failed, aq_err=%d\n", 58161ae650dSJack F Vogel pf->hw.aq.asq_last_status); 582223d846dSEric Joyner goto err_late; 583223d846dSEric Joyner } 58461ae650dSJack F Vogel } 58561ae650dSJack F Vogel 58661ae650dSJack F Vogel /* Determine link state */ 587223d846dSEric Joyner hw->phy.get_link_info = TRUE; 588be771cdaSJack F Vogel i40e_get_link_status(hw, &pf->link_up); 58961ae650dSJack F Vogel 590223d846dSEric Joyner /* Setup OS network interface / ifnet */ 591e5100ee2SJack F Vogel if (ixl_setup_interface(dev, vsi) != 0) { 592e5100ee2SJack F Vogel device_printf(dev, "interface setup failed!\n"); 593e5100ee2SJack F Vogel error = EIO; 59461ae650dSJack F Vogel goto err_late; 595e5100ee2SJack F Vogel } 59661ae650dSJack F Vogel 597b6c8f260SJack F Vogel error = ixl_switch_config(pf); 598b6c8f260SJack F Vogel if (error) { 599*6c426059SEric Joyner device_printf(dev, "Initial ixl_switch_config() failed: %d\n", 600*6c426059SEric Joyner error); 601a48d00d2SEric Joyner goto err_late; 602b6c8f260SJack F Vogel } 603b6c8f260SJack F Vogel 604223d846dSEric Joyner /* Limit PHY interrupts to link, autoneg, and modules failure */ 6057f70bec6SEric Joyner error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, 606223d846dSEric Joyner NULL); 607223d846dSEric Joyner if (error) { 608223d846dSEric Joyner device_printf(dev, "i40e_aq_set_phy_mask() failed: err %d," 609223d846dSEric Joyner " aq_err %d\n", error, hw->aq.asq_last_status); 610223d846dSEric Joyner goto err_late; 611223d846dSEric Joyner } 612b6c8f260SJack F Vogel 613*6c426059SEric Joyner /* Get the bus configuration and set the shared code's config */ 61461ae650dSJack F Vogel bus = ixl_get_bus_info(hw, dev); 61561ae650dSJack F Vogel i40e_set_pci_config_data(hw, bus); 61661ae650dSJack F Vogel 617*6c426059SEric Joyner /* 618*6c426059SEric Joyner * In MSI-X mode, initialize the Admin Queue interrupt, 619*6c426059SEric Joyner * so userland tools can communicate with the adapter regardless of 620*6c426059SEric Joyner * the ifnet interface's status. 621*6c426059SEric Joyner */ 622*6c426059SEric Joyner if (pf->msix > 1) { 623*6c426059SEric Joyner error = ixl_setup_adminq_msix(pf); 624*6c426059SEric Joyner if (error) { 625*6c426059SEric Joyner device_printf(dev, "ixl_setup_adminq_msix error: %d\n", 626*6c426059SEric Joyner error); 627*6c426059SEric Joyner goto err_late; 628*6c426059SEric Joyner } 629*6c426059SEric Joyner error = ixl_setup_adminq_tq(pf); 630*6c426059SEric Joyner if (error) { 631*6c426059SEric Joyner device_printf(dev, "ixl_setup_adminq_tq error: %d\n", 632*6c426059SEric Joyner error); 633*6c426059SEric Joyner goto err_late; 634*6c426059SEric Joyner } 635*6c426059SEric Joyner ixl_configure_intr0_msix(pf); 636*6c426059SEric Joyner ixl_enable_adminq(hw); 637*6c426059SEric Joyner } 638a48d00d2SEric Joyner 639fdb6f38aSEric Joyner /* Initialize statistics & add sysctls */ 640fdb6f38aSEric Joyner ixl_add_device_sysctls(pf); 641fdb6f38aSEric Joyner 64261ae650dSJack F Vogel ixl_pf_reset_stats(pf); 64361ae650dSJack F Vogel ixl_update_stats_counters(pf); 64461ae650dSJack F Vogel ixl_add_hw_stats(pf); 64561ae650dSJack F Vogel 64661ae650dSJack F Vogel /* Register for VLAN events */ 64761ae650dSJack F Vogel vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 64861ae650dSJack F Vogel ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); 64961ae650dSJack F Vogel vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 65061ae650dSJack F Vogel ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); 65161ae650dSJack F Vogel 65256c2c47bSJack F Vogel #ifdef PCI_IOV 65356c2c47bSJack F Vogel /* SR-IOV is only supported when MSI-X is in use. */ 65456c2c47bSJack F Vogel if (pf->msix > 1) { 65556c2c47bSJack F Vogel pf_schema = pci_iov_schema_alloc_node(); 65656c2c47bSJack F Vogel vf_schema = pci_iov_schema_alloc_node(); 65756c2c47bSJack F Vogel pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); 65856c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", 65956c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, TRUE); 66056c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-set-mac", 66156c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 66256c2c47bSJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-promisc", 66356c2c47bSJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 664e5100ee2SJack F Vogel 66556c2c47bSJack F Vogel iov_error = pci_iov_attach(dev, pf_schema, vf_schema); 6661d767a8eSEric Joyner if (iov_error != 0) { 66756c2c47bSJack F Vogel device_printf(dev, 66856c2c47bSJack F Vogel "Failed to initialize SR-IOV (error=%d)\n", 66956c2c47bSJack F Vogel iov_error); 6701d767a8eSEric Joyner } else 6711d767a8eSEric Joyner device_printf(dev, "SR-IOV ready\n"); 67256c2c47bSJack F Vogel } 67356c2c47bSJack F Vogel #endif 67456c2c47bSJack F Vogel 67531830672SJack F Vogel #ifdef DEV_NETMAP 67631830672SJack F Vogel ixl_netmap_attach(vsi); 67731830672SJack F Vogel #endif /* DEV_NETMAP */ 67861ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: end"); 67961ae650dSJack F Vogel return (0); 68061ae650dSJack F Vogel 68161ae650dSJack F Vogel err_late: 682e5100ee2SJack F Vogel if (vsi->ifp != NULL) 683e5100ee2SJack F Vogel if_free(vsi->ifp); 68461ae650dSJack F Vogel err_mac_hmc: 68561ae650dSJack F Vogel i40e_shutdown_lan_hmc(hw); 68661ae650dSJack F Vogel err_get_cap: 68761ae650dSJack F Vogel i40e_shutdown_adminq(hw); 68861ae650dSJack F Vogel err_out: 68961ae650dSJack F Vogel ixl_free_pci_resources(pf); 690e5100ee2SJack F Vogel ixl_free_vsi(vsi); 69161ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 69261ae650dSJack F Vogel return (error); 69361ae650dSJack F Vogel } 69461ae650dSJack F Vogel 69561ae650dSJack F Vogel /********************************************************************* 69661ae650dSJack F Vogel * Device removal routine 69761ae650dSJack F Vogel * 69861ae650dSJack F Vogel * The detach entry point is called when the driver is being removed. 69961ae650dSJack F Vogel * This routine stops the adapter and deallocates all the resources 70061ae650dSJack F Vogel * that were allocated for driver operation. 70161ae650dSJack F Vogel * 70261ae650dSJack F Vogel * return 0 on success, positive on failure 70361ae650dSJack F Vogel *********************************************************************/ 70461ae650dSJack F Vogel 70561ae650dSJack F Vogel static int 70661ae650dSJack F Vogel ixl_detach(device_t dev) 70761ae650dSJack F Vogel { 70861ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 70961ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 71061ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 711*6c426059SEric Joyner enum i40e_status_code status; 71256c2c47bSJack F Vogel #ifdef PCI_IOV 71356c2c47bSJack F Vogel int error; 71456c2c47bSJack F Vogel #endif 71561ae650dSJack F Vogel 71661ae650dSJack F Vogel INIT_DEBUGOUT("ixl_detach: begin"); 71761ae650dSJack F Vogel 71861ae650dSJack F Vogel /* Make sure VLANS are not using driver */ 71961ae650dSJack F Vogel if (vsi->ifp->if_vlantrunk != NULL) { 72061ae650dSJack F Vogel device_printf(dev, "Vlan in use, detach first\n"); 72161ae650dSJack F Vogel return (EBUSY); 72261ae650dSJack F Vogel } 72361ae650dSJack F Vogel 72456c2c47bSJack F Vogel #ifdef PCI_IOV 72556c2c47bSJack F Vogel error = pci_iov_detach(dev); 72656c2c47bSJack F Vogel if (error != 0) { 72756c2c47bSJack F Vogel device_printf(dev, "SR-IOV in use; detach first.\n"); 72856c2c47bSJack F Vogel return (error); 72956c2c47bSJack F Vogel } 73056c2c47bSJack F Vogel #endif 73156c2c47bSJack F Vogel 732b6c8f260SJack F Vogel ether_ifdetach(vsi->ifp); 733223d846dSEric Joyner if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) 73461ae650dSJack F Vogel ixl_stop(pf); 73561ae650dSJack F Vogel 736*6c426059SEric Joyner ixl_free_queue_tqs(vsi); 73761ae650dSJack F Vogel 73861ae650dSJack F Vogel /* Shutdown LAN HMC */ 73961ae650dSJack F Vogel status = i40e_shutdown_lan_hmc(hw); 74061ae650dSJack F Vogel if (status) 74161ae650dSJack F Vogel device_printf(dev, 74261ae650dSJack F Vogel "Shutdown LAN HMC failed with code %d\n", status); 74361ae650dSJack F Vogel 74461ae650dSJack F Vogel /* Shutdown admin queue */ 745*6c426059SEric Joyner ixl_disable_adminq(hw); 746*6c426059SEric Joyner ixl_free_adminq_tq(pf); 747*6c426059SEric Joyner ixl_teardown_adminq_msix(pf); 74861ae650dSJack F Vogel status = i40e_shutdown_adminq(hw); 74961ae650dSJack F Vogel if (status) 75061ae650dSJack F Vogel device_printf(dev, 75161ae650dSJack F Vogel "Shutdown Admin queue failed with code %d\n", status); 75261ae650dSJack F Vogel 75361ae650dSJack F Vogel /* Unregister VLAN events */ 75461ae650dSJack F Vogel if (vsi->vlan_attach != NULL) 75561ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); 75661ae650dSJack F Vogel if (vsi->vlan_detach != NULL) 75761ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); 75861ae650dSJack F Vogel 75961ae650dSJack F Vogel callout_drain(&pf->timer); 76031830672SJack F Vogel #ifdef DEV_NETMAP 76131830672SJack F Vogel netmap_detach(vsi->ifp); 76231830672SJack F Vogel #endif /* DEV_NETMAP */ 76361ae650dSJack F Vogel ixl_free_pci_resources(pf); 76461ae650dSJack F Vogel bus_generic_detach(dev); 76561ae650dSJack F Vogel if_free(vsi->ifp); 76661ae650dSJack F Vogel ixl_free_vsi(vsi); 76761ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 76861ae650dSJack F Vogel return (0); 76961ae650dSJack F Vogel } 77061ae650dSJack F Vogel 77161ae650dSJack F Vogel /********************************************************************* 77261ae650dSJack F Vogel * 77361ae650dSJack F Vogel * Shutdown entry point 77461ae650dSJack F Vogel * 77561ae650dSJack F Vogel **********************************************************************/ 77661ae650dSJack F Vogel 77761ae650dSJack F Vogel static int 77861ae650dSJack F Vogel ixl_shutdown(device_t dev) 77961ae650dSJack F Vogel { 78061ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 78161ae650dSJack F Vogel ixl_stop(pf); 78261ae650dSJack F Vogel return (0); 78361ae650dSJack F Vogel } 78461ae650dSJack F Vogel 78561ae650dSJack F Vogel 78661ae650dSJack F Vogel /********************************************************************* 78761ae650dSJack F Vogel * 78861ae650dSJack F Vogel * Get the hardware capabilities 78961ae650dSJack F Vogel * 79061ae650dSJack F Vogel **********************************************************************/ 79161ae650dSJack F Vogel 79261ae650dSJack F Vogel static int 79361ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf) 79461ae650dSJack F Vogel { 79561ae650dSJack F Vogel struct i40e_aqc_list_capabilities_element_resp *buf; 79661ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 79761ae650dSJack F Vogel device_t dev = pf->dev; 79861ae650dSJack F Vogel int error, len; 79961ae650dSJack F Vogel u16 needed; 80061ae650dSJack F Vogel bool again = TRUE; 80161ae650dSJack F Vogel 80261ae650dSJack F Vogel len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); 80361ae650dSJack F Vogel retry: 80461ae650dSJack F Vogel if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *) 80561ae650dSJack F Vogel malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) { 80661ae650dSJack F Vogel device_printf(dev, "Unable to allocate cap memory\n"); 80761ae650dSJack F Vogel return (ENOMEM); 80861ae650dSJack F Vogel } 80961ae650dSJack F Vogel 81061ae650dSJack F Vogel /* This populates the hw struct */ 81161ae650dSJack F Vogel error = i40e_aq_discover_capabilities(hw, buf, len, 81261ae650dSJack F Vogel &needed, i40e_aqc_opc_list_func_capabilities, NULL); 81361ae650dSJack F Vogel free(buf, M_DEVBUF); 81461ae650dSJack F Vogel if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && 81561ae650dSJack F Vogel (again == TRUE)) { 81661ae650dSJack F Vogel /* retry once with a larger buffer */ 81761ae650dSJack F Vogel again = FALSE; 81861ae650dSJack F Vogel len = needed; 81961ae650dSJack F Vogel goto retry; 82061ae650dSJack F Vogel } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { 82161ae650dSJack F Vogel device_printf(dev, "capability discovery failed: %d\n", 82261ae650dSJack F Vogel pf->hw.aq.asq_last_status); 82361ae650dSJack F Vogel return (ENODEV); 82461ae650dSJack F Vogel } 82561ae650dSJack F Vogel 82661ae650dSJack F Vogel /* Capture this PF's starting queue pair */ 82761ae650dSJack F Vogel pf->qbase = hw->func_caps.base_queue; 82861ae650dSJack F Vogel 82961ae650dSJack F Vogel #ifdef IXL_DEBUG 83061ae650dSJack F Vogel device_printf(dev, "pf_id=%d, num_vfs=%d, msix_pf=%d, " 83161ae650dSJack F Vogel "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", 83261ae650dSJack F Vogel hw->pf_id, hw->func_caps.num_vfs, 83361ae650dSJack F Vogel hw->func_caps.num_msix_vectors, 83461ae650dSJack F Vogel hw->func_caps.num_msix_vectors_vf, 83561ae650dSJack F Vogel hw->func_caps.fd_filters_guaranteed, 83661ae650dSJack F Vogel hw->func_caps.fd_filters_best_effort, 83761ae650dSJack F Vogel hw->func_caps.num_tx_qp, 83861ae650dSJack F Vogel hw->func_caps.num_rx_qp, 83961ae650dSJack F Vogel hw->func_caps.base_queue); 84061ae650dSJack F Vogel #endif 84161ae650dSJack F Vogel return (error); 84261ae650dSJack F Vogel } 84361ae650dSJack F Vogel 84461ae650dSJack F Vogel static void 84561ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) 84661ae650dSJack F Vogel { 84761ae650dSJack F Vogel device_t dev = vsi->dev; 84861ae650dSJack F Vogel 84961ae650dSJack F Vogel /* Enable/disable TXCSUM/TSO4 */ 85061ae650dSJack F Vogel if (!(ifp->if_capenable & IFCAP_TXCSUM) 85161ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO4)) { 85261ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) { 85361ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TXCSUM; 85461ae650dSJack F Vogel /* enable TXCSUM, restore TSO if previously enabled */ 85561ae650dSJack F Vogel if (vsi->flags & IXL_FLAGS_KEEP_TSO4) { 85661ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 85761ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO4; 85861ae650dSJack F Vogel } 85961ae650dSJack F Vogel } 86061ae650dSJack F Vogel else if (mask & IFCAP_TSO4) { 86161ae650dSJack F Vogel ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); 86261ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 86361ae650dSJack F Vogel device_printf(dev, 86461ae650dSJack F Vogel "TSO4 requires txcsum, enabling both...\n"); 86561ae650dSJack F Vogel } 86661ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM) 86761ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO4)) { 86861ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) 86961ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TXCSUM; 87061ae650dSJack F Vogel else if (mask & IFCAP_TSO4) 87161ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO4; 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 vsi->flags |= IXL_FLAGS_KEEP_TSO4; 87661ae650dSJack F Vogel ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); 87761ae650dSJack F Vogel device_printf(dev, 87861ae650dSJack F Vogel "TSO4 requires txcsum, disabling both...\n"); 87961ae650dSJack F Vogel } else if (mask & IFCAP_TSO4) 88061ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TSO4; 88161ae650dSJack F Vogel } 88261ae650dSJack F Vogel 88361ae650dSJack F Vogel /* Enable/disable TXCSUM_IPV6/TSO6 */ 88461ae650dSJack F Vogel if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) 88561ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO6)) { 88661ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) { 88761ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TXCSUM_IPV6; 88861ae650dSJack F Vogel if (vsi->flags & IXL_FLAGS_KEEP_TSO6) { 88961ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 89061ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO6; 89161ae650dSJack F Vogel } 89261ae650dSJack F Vogel } else if (mask & IFCAP_TSO6) { 89361ae650dSJack F Vogel ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 89461ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 89561ae650dSJack F Vogel device_printf(dev, 89661ae650dSJack F Vogel "TSO6 requires txcsum6, enabling both...\n"); 89761ae650dSJack F Vogel } 89861ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 89961ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO6)) { 90061ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) 90161ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; 90261ae650dSJack F Vogel else if (mask & IFCAP_TSO6) 90361ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO6; 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 vsi->flags |= IXL_FLAGS_KEEP_TSO6; 90861ae650dSJack F Vogel ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 90961ae650dSJack F Vogel device_printf(dev, 91061ae650dSJack F Vogel "TSO6 requires txcsum6, disabling both...\n"); 91161ae650dSJack F Vogel } else if (mask & IFCAP_TSO6) 91261ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TSO6; 91361ae650dSJack F Vogel } 91461ae650dSJack F Vogel } 91561ae650dSJack F Vogel 91661ae650dSJack F Vogel /********************************************************************* 91761ae650dSJack F Vogel * Ioctl entry point 91861ae650dSJack F Vogel * 91961ae650dSJack F Vogel * ixl_ioctl is called when the user wants to configure the 92061ae650dSJack F Vogel * interface. 92161ae650dSJack F Vogel * 92261ae650dSJack F Vogel * return 0 on success, positive on failure 92361ae650dSJack F Vogel **********************************************************************/ 92461ae650dSJack F Vogel 92561ae650dSJack F Vogel static int 92661ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 92761ae650dSJack F Vogel { 92861ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 92956c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 93061ae650dSJack F Vogel struct ifreq *ifr = (struct ifreq *)data; 931223d846dSEric Joyner struct ifdrv *ifd = (struct ifdrv *)data; 93261ae650dSJack F Vogel #if defined(INET) || defined(INET6) 93361ae650dSJack F Vogel struct ifaddr *ifa = (struct ifaddr *)data; 93461ae650dSJack F Vogel bool avoid_reset = FALSE; 93561ae650dSJack F Vogel #endif 93661ae650dSJack F Vogel int error = 0; 93761ae650dSJack F Vogel 93861ae650dSJack F Vogel switch (command) { 93961ae650dSJack F Vogel 94061ae650dSJack F Vogel case SIOCSIFADDR: 94161ae650dSJack F Vogel #ifdef INET 94261ae650dSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET) 94361ae650dSJack F Vogel avoid_reset = TRUE; 94461ae650dSJack F Vogel #endif 94561ae650dSJack F Vogel #ifdef INET6 94661ae650dSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET6) 94761ae650dSJack F Vogel avoid_reset = TRUE; 94861ae650dSJack F Vogel #endif 94961ae650dSJack F Vogel #if defined(INET) || defined(INET6) 95061ae650dSJack F Vogel /* 95161ae650dSJack F Vogel ** Calling init results in link renegotiation, 95261ae650dSJack F Vogel ** so we avoid doing it when possible. 95361ae650dSJack F Vogel */ 95461ae650dSJack F Vogel if (avoid_reset) { 95561ae650dSJack F Vogel ifp->if_flags |= IFF_UP; 95661ae650dSJack F Vogel if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 95761ae650dSJack F Vogel ixl_init(pf); 9587e0dde7dSBjoern A. Zeeb #ifdef INET 95961ae650dSJack F Vogel if (!(ifp->if_flags & IFF_NOARP)) 96061ae650dSJack F Vogel arp_ifinit(ifp, ifa); 9617e0dde7dSBjoern A. Zeeb #endif 96261ae650dSJack F Vogel } else 96361ae650dSJack F Vogel error = ether_ioctl(ifp, command, data); 96461ae650dSJack F Vogel break; 96561ae650dSJack F Vogel #endif 96661ae650dSJack F Vogel case SIOCSIFMTU: 96761ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 96861ae650dSJack F Vogel if (ifr->ifr_mtu > IXL_MAX_FRAME - 96961ae650dSJack F Vogel ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) { 97061ae650dSJack F Vogel error = EINVAL; 97161ae650dSJack F Vogel } else { 97261ae650dSJack F Vogel IXL_PF_LOCK(pf); 97361ae650dSJack F Vogel ifp->if_mtu = ifr->ifr_mtu; 97461ae650dSJack F Vogel vsi->max_frame_size = 97561ae650dSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 97661ae650dSJack F Vogel + ETHER_VLAN_ENCAP_LEN; 97761ae650dSJack F Vogel ixl_init_locked(pf); 97861ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 97961ae650dSJack F Vogel } 98061ae650dSJack F Vogel break; 98161ae650dSJack F Vogel case SIOCSIFFLAGS: 98261ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 98361ae650dSJack F Vogel IXL_PF_LOCK(pf); 98461ae650dSJack F Vogel if (ifp->if_flags & IFF_UP) { 98561ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 98661ae650dSJack F Vogel if ((ifp->if_flags ^ pf->if_flags) & 98761ae650dSJack F Vogel (IFF_PROMISC | IFF_ALLMULTI)) { 98861ae650dSJack F Vogel ixl_set_promisc(vsi); 98961ae650dSJack F Vogel } 990223d846dSEric Joyner } else { 991223d846dSEric Joyner IXL_PF_UNLOCK(pf); 992223d846dSEric Joyner ixl_init(pf); 993223d846dSEric Joyner IXL_PF_LOCK(pf); 994223d846dSEric Joyner } 995223d846dSEric Joyner } else { 996223d846dSEric Joyner if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 997223d846dSEric Joyner IXL_PF_UNLOCK(pf); 99861ae650dSJack F Vogel ixl_stop(pf); 999223d846dSEric Joyner IXL_PF_LOCK(pf); 1000223d846dSEric Joyner } 1001223d846dSEric Joyner } 100261ae650dSJack F Vogel pf->if_flags = ifp->if_flags; 100361ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 100461ae650dSJack F Vogel break; 1005223d846dSEric Joyner case SIOCSDRVSPEC: 1006223d846dSEric Joyner case SIOCGDRVSPEC: 1007223d846dSEric Joyner IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific " 1008223d846dSEric Joyner "Info)\n"); 1009223d846dSEric Joyner 1010223d846dSEric Joyner /* NVM update command */ 1011223d846dSEric Joyner if (ifd->ifd_cmd == I40E_NVM_ACCESS) 1012223d846dSEric Joyner error = ixl_handle_nvmupd_cmd(pf, ifd); 1013223d846dSEric Joyner else 1014223d846dSEric Joyner error = EINVAL; 1015223d846dSEric Joyner break; 101661ae650dSJack F Vogel case SIOCADDMULTI: 101761ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); 101861ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 101961ae650dSJack F Vogel IXL_PF_LOCK(pf); 102061ae650dSJack F Vogel ixl_disable_intr(vsi); 102161ae650dSJack F Vogel ixl_add_multi(vsi); 102261ae650dSJack F Vogel ixl_enable_intr(vsi); 102361ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 102461ae650dSJack F Vogel } 102561ae650dSJack F Vogel break; 102661ae650dSJack F Vogel case SIOCDELMULTI: 102761ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); 102861ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 102961ae650dSJack F Vogel IXL_PF_LOCK(pf); 103061ae650dSJack F Vogel ixl_disable_intr(vsi); 103161ae650dSJack F Vogel ixl_del_multi(vsi); 103261ae650dSJack F Vogel ixl_enable_intr(vsi); 103361ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 103461ae650dSJack F Vogel } 103561ae650dSJack F Vogel break; 103661ae650dSJack F Vogel case SIOCSIFMEDIA: 103761ae650dSJack F Vogel case SIOCGIFMEDIA: 1038be771cdaSJack F Vogel #ifdef IFM_ETH_XTYPE 1039be771cdaSJack F Vogel case SIOCGIFXMEDIA: 1040be771cdaSJack F Vogel #endif 104161ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 104261ae650dSJack F Vogel error = ifmedia_ioctl(ifp, ifr, &vsi->media, command); 104361ae650dSJack F Vogel break; 104461ae650dSJack F Vogel case SIOCSIFCAP: 104561ae650dSJack F Vogel { 104661ae650dSJack F Vogel int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 104761ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 104861ae650dSJack F Vogel 104961ae650dSJack F Vogel ixl_cap_txcsum_tso(vsi, ifp, mask); 105061ae650dSJack F Vogel 105161ae650dSJack F Vogel if (mask & IFCAP_RXCSUM) 105261ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_RXCSUM; 105361ae650dSJack F Vogel if (mask & IFCAP_RXCSUM_IPV6) 105461ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 105561ae650dSJack F Vogel if (mask & IFCAP_LRO) 105661ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_LRO; 105761ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWTAGGING) 105861ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 105961ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWFILTER) 106061ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 106161ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWTSO) 106261ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 106361ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 106461ae650dSJack F Vogel IXL_PF_LOCK(pf); 106561ae650dSJack F Vogel ixl_init_locked(pf); 106661ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 106761ae650dSJack F Vogel } 106861ae650dSJack F Vogel VLAN_CAPABILITIES(ifp); 106961ae650dSJack F Vogel 107061ae650dSJack F Vogel break; 107161ae650dSJack F Vogel } 107261ae650dSJack F Vogel 107361ae650dSJack F Vogel default: 107461ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command); 107561ae650dSJack F Vogel error = ether_ioctl(ifp, command, data); 107661ae650dSJack F Vogel break; 107761ae650dSJack F Vogel } 107861ae650dSJack F Vogel 107961ae650dSJack F Vogel return (error); 108061ae650dSJack F Vogel } 108161ae650dSJack F Vogel 108261ae650dSJack F Vogel 108361ae650dSJack F Vogel /********************************************************************* 108461ae650dSJack F Vogel * Init entry point 108561ae650dSJack F Vogel * 108661ae650dSJack F Vogel * This routine is used in two ways. It is used by the stack as 108761ae650dSJack F Vogel * init entry point in network interface structure. It is also used 108861ae650dSJack F Vogel * by the driver as a hw/sw initialization routine to get to a 108961ae650dSJack F Vogel * consistent state. 109061ae650dSJack F Vogel * 109161ae650dSJack F Vogel * return 0 on success, positive on failure 109261ae650dSJack F Vogel **********************************************************************/ 109361ae650dSJack F Vogel 109461ae650dSJack F Vogel static void 109561ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf) 109661ae650dSJack F Vogel { 109761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 109861ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 109961ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 110061ae650dSJack F Vogel device_t dev = pf->dev; 110161ae650dSJack F Vogel struct i40e_filter_control_settings filter; 110261ae650dSJack F Vogel u8 tmpaddr[ETHER_ADDR_LEN]; 110361ae650dSJack F Vogel int ret; 110461ae650dSJack F Vogel 110561ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 110661ae650dSJack F Vogel INIT_DEBUGOUT("ixl_init: begin"); 1107223d846dSEric Joyner 1108223d846dSEric Joyner ixl_stop_locked(pf); 110961ae650dSJack F Vogel 111061ae650dSJack F Vogel /* Get the latest mac address... User might use a LAA */ 111161ae650dSJack F Vogel bcopy(IF_LLADDR(vsi->ifp), tmpaddr, 111261ae650dSJack F Vogel I40E_ETH_LENGTH_OF_ADDRESS); 111361ae650dSJack F Vogel if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && 1114a48d00d2SEric Joyner (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { 1115a48d00d2SEric Joyner ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); 111661ae650dSJack F Vogel bcopy(tmpaddr, hw->mac.addr, 111761ae650dSJack F Vogel I40E_ETH_LENGTH_OF_ADDRESS); 111861ae650dSJack F Vogel ret = i40e_aq_mac_address_write(hw, 111961ae650dSJack F Vogel I40E_AQC_WRITE_TYPE_LAA_ONLY, 112061ae650dSJack F Vogel hw->mac.addr, NULL); 112161ae650dSJack F Vogel if (ret) { 112261ae650dSJack F Vogel device_printf(dev, "LLA address" 112361ae650dSJack F Vogel "change failed!!\n"); 112461ae650dSJack F Vogel return; 112595bb0504SEric Joyner } 112695bb0504SEric Joyner } 112795bb0504SEric Joyner 1128a48d00d2SEric Joyner ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); 112961ae650dSJack F Vogel 113061ae650dSJack F Vogel /* Set the various hardware offload abilities */ 113161ae650dSJack F Vogel ifp->if_hwassist = 0; 113261ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TSO) 113361ae650dSJack F Vogel ifp->if_hwassist |= CSUM_TSO; 113461ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM) 113561ae650dSJack F Vogel ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 113661ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 113761ae650dSJack F Vogel ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); 113861ae650dSJack F Vogel 113961ae650dSJack F Vogel /* Set up the device filtering */ 114061ae650dSJack F Vogel bzero(&filter, sizeof(filter)); 114161ae650dSJack F Vogel filter.enable_ethtype = TRUE; 114261ae650dSJack F Vogel filter.enable_macvlan = TRUE; 114361ae650dSJack F Vogel #ifdef IXL_FDIR 114461ae650dSJack F Vogel filter.enable_fdir = TRUE; 114561ae650dSJack F Vogel #endif 11467f70bec6SEric Joyner filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; 114761ae650dSJack F Vogel if (i40e_set_filter_control(hw, &filter)) 11487f70bec6SEric Joyner device_printf(dev, "i40e_set_filter_control() failed\n"); 114961ae650dSJack F Vogel 115061ae650dSJack F Vogel /* Set up RSS */ 115161ae650dSJack F Vogel ixl_config_rss(vsi); 115261ae650dSJack F Vogel 11537f70bec6SEric Joyner /* Prepare the VSI: rings, hmc contexts, etc... */ 115461ae650dSJack F Vogel if (ixl_initialize_vsi(vsi)) { 115561ae650dSJack F Vogel device_printf(dev, "initialize vsi failed!!\n"); 115661ae650dSJack F Vogel return; 115761ae650dSJack F Vogel } 115861ae650dSJack F Vogel 115961ae650dSJack F Vogel /* Add protocol filters to list */ 116061ae650dSJack F Vogel ixl_init_filters(vsi); 116161ae650dSJack F Vogel 116261ae650dSJack F Vogel /* Setup vlan's if needed */ 116361ae650dSJack F Vogel ixl_setup_vlan_filters(vsi); 116461ae650dSJack F Vogel 116561ae650dSJack F Vogel /* Set up MSI/X routing and the ITR settings */ 116661ae650dSJack F Vogel if (ixl_enable_msix) { 1167*6c426059SEric Joyner ixl_configure_queue_intr_msix(pf); 116861ae650dSJack F Vogel ixl_configure_itr(pf); 116961ae650dSJack F Vogel } else 117061ae650dSJack F Vogel ixl_configure_legacy(pf); 117161ae650dSJack F Vogel 117261ae650dSJack F Vogel ixl_enable_rings(vsi); 117361ae650dSJack F Vogel 117461ae650dSJack F Vogel i40e_aq_set_default_vsi(hw, vsi->seid, NULL); 117561ae650dSJack F Vogel 117656c2c47bSJack F Vogel ixl_reconfigure_filters(vsi); 117756c2c47bSJack F Vogel 117861ae650dSJack F Vogel /* And now turn on interrupts */ 117961ae650dSJack F Vogel ixl_enable_intr(vsi); 118061ae650dSJack F Vogel 1181223d846dSEric Joyner /* Get link info */ 1182223d846dSEric Joyner hw->phy.get_link_info = TRUE; 1183223d846dSEric Joyner i40e_get_link_status(hw, &pf->link_up); 1184223d846dSEric Joyner ixl_update_link_status(pf); 1185223d846dSEric Joyner 1186*6c426059SEric Joyner /* Set initial advertised speed sysctl value */ 1187*6c426059SEric Joyner ixl_get_initial_advertised_speeds(pf); 1188*6c426059SEric Joyner 11897f70bec6SEric Joyner /* Start the local timer */ 11907f70bec6SEric Joyner callout_reset(&pf->timer, hz, ixl_local_timer, pf); 11917f70bec6SEric Joyner 119261ae650dSJack F Vogel /* Now inform the stack we're ready */ 119361ae650dSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 119461ae650dSJack F Vogel 119561ae650dSJack F Vogel return; 119661ae650dSJack F Vogel } 119761ae650dSJack F Vogel 1198*6c426059SEric Joyner /* For the set_advertise sysctl */ 1199*6c426059SEric Joyner static void 1200*6c426059SEric Joyner ixl_get_initial_advertised_speeds(struct ixl_pf *pf) 1201*6c426059SEric Joyner { 1202*6c426059SEric Joyner struct i40e_hw *hw = &pf->hw; 1203*6c426059SEric Joyner device_t dev = pf->dev; 1204*6c426059SEric Joyner enum i40e_status_code status; 1205*6c426059SEric Joyner struct i40e_aq_get_phy_abilities_resp abilities; 1206*6c426059SEric Joyner 1207*6c426059SEric Joyner /* Set initial sysctl values */ 1208*6c426059SEric Joyner status = i40e_aq_get_phy_capabilities(hw, FALSE, false, &abilities, 1209*6c426059SEric Joyner NULL); 1210*6c426059SEric Joyner if (status) { 1211*6c426059SEric Joyner /* Non-fatal error */ 1212*6c426059SEric Joyner device_printf(dev, "%s: i40e_aq_get_phy_capabilities() error %d\n", 1213*6c426059SEric Joyner __func__, status); 1214*6c426059SEric Joyner return; 1215*6c426059SEric Joyner } 1216*6c426059SEric Joyner 1217*6c426059SEric Joyner if (abilities.link_speed & I40E_LINK_SPEED_40GB) 1218*6c426059SEric Joyner pf->advertised_speed |= 0x10; 1219*6c426059SEric Joyner if (abilities.link_speed & I40E_LINK_SPEED_20GB) 1220*6c426059SEric Joyner pf->advertised_speed |= 0x8; 1221*6c426059SEric Joyner if (abilities.link_speed & I40E_LINK_SPEED_10GB) 1222*6c426059SEric Joyner pf->advertised_speed |= 0x4; 1223*6c426059SEric Joyner if (abilities.link_speed & I40E_LINK_SPEED_1GB) 1224*6c426059SEric Joyner pf->advertised_speed |= 0x2; 1225*6c426059SEric Joyner if (abilities.link_speed & I40E_LINK_SPEED_100MB) 1226*6c426059SEric Joyner pf->advertised_speed |= 0x1; 1227*6c426059SEric Joyner } 1228*6c426059SEric Joyner 12297f70bec6SEric Joyner static int 12307f70bec6SEric Joyner ixl_teardown_hw_structs(struct ixl_pf *pf) 12317f70bec6SEric Joyner { 12327f70bec6SEric Joyner enum i40e_status_code status = 0; 12337f70bec6SEric Joyner struct i40e_hw *hw = &pf->hw; 12347f70bec6SEric Joyner device_t dev = pf->dev; 12357f70bec6SEric Joyner 12367f70bec6SEric Joyner /* Shutdown LAN HMC */ 12377f70bec6SEric Joyner if (hw->hmc.hmc_obj) { 12387f70bec6SEric Joyner status = i40e_shutdown_lan_hmc(hw); 12397f70bec6SEric Joyner if (status) { 12407f70bec6SEric Joyner device_printf(dev, 12417f70bec6SEric Joyner "init: LAN HMC shutdown failure; status %d\n", status); 12427f70bec6SEric Joyner goto err_out; 12437f70bec6SEric Joyner } 12447f70bec6SEric Joyner } 12457f70bec6SEric Joyner 12467f70bec6SEric Joyner // XXX: This gets called when we know the adminq is inactive; 12477f70bec6SEric Joyner // so we already know it's setup when we get here. 12487f70bec6SEric Joyner 12497f70bec6SEric Joyner /* Shutdown admin queue */ 12507f70bec6SEric Joyner status = i40e_shutdown_adminq(hw); 12517f70bec6SEric Joyner if (status) 12527f70bec6SEric Joyner device_printf(dev, 12537f70bec6SEric Joyner "init: Admin Queue shutdown failure; status %d\n", status); 12547f70bec6SEric Joyner 12557f70bec6SEric Joyner err_out: 12567f70bec6SEric Joyner return (status); 12577f70bec6SEric Joyner } 12587f70bec6SEric Joyner 12597f70bec6SEric Joyner static int 12607f70bec6SEric Joyner ixl_reset(struct ixl_pf *pf) 12617f70bec6SEric Joyner { 12627f70bec6SEric Joyner struct i40e_hw *hw = &pf->hw; 12637f70bec6SEric Joyner device_t dev = pf->dev; 12647f70bec6SEric Joyner int error = 0; 12657f70bec6SEric Joyner 12667f70bec6SEric Joyner // XXX: clear_hw() actually writes to hw registers -- maybe this isn't necessary 12677f70bec6SEric Joyner i40e_clear_hw(hw); 12687f70bec6SEric Joyner error = i40e_pf_reset(hw); 12697f70bec6SEric Joyner if (error) { 12707f70bec6SEric Joyner device_printf(dev, "init: PF reset failure"); 12717f70bec6SEric Joyner error = EIO; 12727f70bec6SEric Joyner goto err_out; 12737f70bec6SEric Joyner } 12747f70bec6SEric Joyner 12757f70bec6SEric Joyner error = i40e_init_adminq(hw); 12767f70bec6SEric Joyner if (error) { 12777f70bec6SEric Joyner device_printf(dev, "init: Admin queue init failure; status code %d", error); 12787f70bec6SEric Joyner error = EIO; 12797f70bec6SEric Joyner goto err_out; 12807f70bec6SEric Joyner } 12817f70bec6SEric Joyner 12827f70bec6SEric Joyner i40e_clear_pxe_mode(hw); 12837f70bec6SEric Joyner 12847f70bec6SEric Joyner error = ixl_get_hw_capabilities(pf); 12857f70bec6SEric Joyner if (error) { 12867f70bec6SEric Joyner device_printf(dev, "init: Error retrieving HW capabilities; status code %d\n", error); 12877f70bec6SEric Joyner goto err_out; 12887f70bec6SEric Joyner } 12897f70bec6SEric Joyner 12907f70bec6SEric Joyner error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 12917f70bec6SEric Joyner hw->func_caps.num_rx_qp, 0, 0); 12927f70bec6SEric Joyner if (error) { 12937f70bec6SEric Joyner device_printf(dev, "init: LAN HMC init failed; status code %d\n", error); 12947f70bec6SEric Joyner error = EIO; 12957f70bec6SEric Joyner goto err_out; 12967f70bec6SEric Joyner } 12977f70bec6SEric Joyner 12987f70bec6SEric Joyner error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 12997f70bec6SEric Joyner if (error) { 13007f70bec6SEric Joyner device_printf(dev, "init: LAN HMC config failed; status code %d\n", error); 13017f70bec6SEric Joyner error = EIO; 13027f70bec6SEric Joyner goto err_out; 13037f70bec6SEric Joyner } 13047f70bec6SEric Joyner 13057f70bec6SEric Joyner // XXX: need to do switch config here? 13067f70bec6SEric Joyner 13077f70bec6SEric Joyner error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, 13087f70bec6SEric Joyner NULL); 13097f70bec6SEric Joyner if (error) { 13107f70bec6SEric Joyner device_printf(dev, "init: i40e_aq_set_phy_mask() failed: err %d," 13117f70bec6SEric Joyner " aq_err %d\n", error, hw->aq.asq_last_status); 13127f70bec6SEric Joyner error = EIO; 13137f70bec6SEric Joyner goto err_out; 13147f70bec6SEric Joyner } 13157f70bec6SEric Joyner 13167f70bec6SEric Joyner u8 set_fc_err_mask; 13177f70bec6SEric Joyner error = i40e_set_fc(hw, &set_fc_err_mask, true); 13187f70bec6SEric Joyner if (error) { 13197f70bec6SEric Joyner device_printf(dev, "init: setting link flow control failed; retcode %d," 13207f70bec6SEric Joyner " fc_err_mask 0x%02x\n", error, set_fc_err_mask); 13217f70bec6SEric Joyner goto err_out; 13227f70bec6SEric Joyner } 13237f70bec6SEric Joyner 13247f70bec6SEric Joyner // XXX: (Rebuild VSIs?) 13257f70bec6SEric Joyner 13261d767a8eSEric Joyner /* Firmware delay workaround */ 13277f70bec6SEric Joyner if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 13287f70bec6SEric Joyner (hw->aq.fw_maj_ver < 4)) { 13297f70bec6SEric Joyner i40e_msec_delay(75); 13307f70bec6SEric Joyner error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 13317f70bec6SEric Joyner if (error) { 13327f70bec6SEric Joyner device_printf(dev, "init: link restart failed, aq_err %d\n", 13337f70bec6SEric Joyner hw->aq.asq_last_status); 13347f70bec6SEric Joyner goto err_out; 13357f70bec6SEric Joyner } 13367f70bec6SEric Joyner } 13377f70bec6SEric Joyner 13387f70bec6SEric Joyner 13397f70bec6SEric Joyner err_out: 13407f70bec6SEric Joyner return (error); 13417f70bec6SEric Joyner } 13427f70bec6SEric Joyner 134361ae650dSJack F Vogel static void 134461ae650dSJack F Vogel ixl_init(void *arg) 134561ae650dSJack F Vogel { 134661ae650dSJack F Vogel struct ixl_pf *pf = arg; 1347*6c426059SEric Joyner device_t dev = pf->dev; 1348*6c426059SEric Joyner int error = 0; 1349223d846dSEric Joyner 13507f70bec6SEric Joyner /* 13517f70bec6SEric Joyner * If the aq is dead here, it probably means something outside of the driver 13527f70bec6SEric Joyner * did something to the adapter, like a PF reset. 13537f70bec6SEric Joyner * So rebuild the driver's state here if that occurs. 13547f70bec6SEric Joyner */ 13557f70bec6SEric Joyner if (!i40e_check_asq_alive(&pf->hw)) { 1356*6c426059SEric Joyner device_printf(dev, "Admin Queue is down; resetting...\n"); 13577f70bec6SEric Joyner IXL_PF_LOCK(pf); 13587f70bec6SEric Joyner ixl_teardown_hw_structs(pf); 13597f70bec6SEric Joyner ixl_reset(pf); 13607f70bec6SEric Joyner IXL_PF_UNLOCK(pf); 13617f70bec6SEric Joyner } 13627f70bec6SEric Joyner 1363*6c426059SEric Joyner /* 1364*6c426059SEric Joyner * Set up LAN queue interrupts here. 1365*6c426059SEric Joyner * Kernel interrupt setup functions cannot be called while holding a lock, 1366*6c426059SEric Joyner * so this is done outside of init_locked(). 1367*6c426059SEric Joyner */ 1368*6c426059SEric Joyner if (pf->msix > 1) { 1369*6c426059SEric Joyner error = ixl_setup_queue_msix(&pf->vsi); 1370*6c426059SEric Joyner if (error) 1371*6c426059SEric Joyner device_printf(dev, "ixl_setup_queue_msix() error: %d\n", 1372*6c426059SEric Joyner error); 1373*6c426059SEric Joyner error = ixl_setup_queue_tqs(&pf->vsi); 1374*6c426059SEric Joyner if (error) 1375*6c426059SEric Joyner device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", 1376*6c426059SEric Joyner error); 1377*6c426059SEric Joyner } else 1378*6c426059SEric Joyner // possibly broken 1379*6c426059SEric Joyner error = ixl_assign_vsi_legacy(pf); 1380*6c426059SEric Joyner if (error) { 1381*6c426059SEric Joyner device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", error); 1382223d846dSEric Joyner return; 1383223d846dSEric Joyner } 138461ae650dSJack F Vogel 138561ae650dSJack F Vogel IXL_PF_LOCK(pf); 138661ae650dSJack F Vogel ixl_init_locked(pf); 138761ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 138861ae650dSJack F Vogel return; 138961ae650dSJack F Vogel } 139061ae650dSJack F Vogel 139161ae650dSJack F Vogel /* 139261ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets 139361ae650dSJack F Vogel */ 139461ae650dSJack F Vogel static void 139561ae650dSJack F Vogel ixl_handle_que(void *context, int pending) 139661ae650dSJack F Vogel { 139761ae650dSJack F Vogel struct ixl_queue *que = context; 139861ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 139961ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 140061ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 140161ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 140261ae650dSJack F Vogel bool more; 140361ae650dSJack F Vogel 140461ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 140561ae650dSJack F Vogel more = ixl_rxeof(que, IXL_RX_LIMIT); 140661ae650dSJack F Vogel IXL_TX_LOCK(txr); 140761ae650dSJack F Vogel ixl_txeof(que); 140861ae650dSJack F Vogel if (!drbr_empty(ifp, txr->br)) 140961ae650dSJack F Vogel ixl_mq_start_locked(ifp, txr); 141061ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 141161ae650dSJack F Vogel if (more) { 141261ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->task); 141361ae650dSJack F Vogel return; 141461ae650dSJack F Vogel } 141561ae650dSJack F Vogel } 141661ae650dSJack F Vogel 141761ae650dSJack F Vogel /* Reenable this interrupt - hmmm */ 141861ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 141961ae650dSJack F Vogel return; 142061ae650dSJack F Vogel } 142161ae650dSJack F Vogel 142261ae650dSJack F Vogel 142361ae650dSJack F Vogel /********************************************************************* 142461ae650dSJack F Vogel * 142561ae650dSJack F Vogel * Legacy Interrupt Service routine 142661ae650dSJack F Vogel * 142761ae650dSJack F Vogel **********************************************************************/ 142861ae650dSJack F Vogel void 142961ae650dSJack F Vogel ixl_intr(void *arg) 143061ae650dSJack F Vogel { 143161ae650dSJack F Vogel struct ixl_pf *pf = arg; 143261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 143361ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 143461ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 143561ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 143661ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 143761ae650dSJack F Vogel u32 reg, icr0, mask; 143861ae650dSJack F Vogel bool more_tx, more_rx; 143961ae650dSJack F Vogel 144061ae650dSJack F Vogel ++que->irqs; 144161ae650dSJack F Vogel 144261ae650dSJack F Vogel /* Protect against spurious interrupts */ 144361ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 144461ae650dSJack F Vogel return; 144561ae650dSJack F Vogel 144661ae650dSJack F Vogel icr0 = rd32(hw, I40E_PFINT_ICR0); 144761ae650dSJack F Vogel 144861ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_DYN_CTL0); 144961ae650dSJack F Vogel reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 145061ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 145161ae650dSJack F Vogel 145261ae650dSJack F Vogel mask = rd32(hw, I40E_PFINT_ICR0_ENA); 145361ae650dSJack F Vogel 145456c2c47bSJack F Vogel #ifdef PCI_IOV 145556c2c47bSJack F Vogel if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) 145656c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->vflr_task); 145756c2c47bSJack F Vogel #endif 145856c2c47bSJack F Vogel 145961ae650dSJack F Vogel if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) { 146061ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 146161ae650dSJack F Vogel return; 146261ae650dSJack F Vogel } 146361ae650dSJack F Vogel 146461ae650dSJack F Vogel more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 146561ae650dSJack F Vogel 146661ae650dSJack F Vogel IXL_TX_LOCK(txr); 146761ae650dSJack F Vogel more_tx = ixl_txeof(que); 146861ae650dSJack F Vogel if (!drbr_empty(vsi->ifp, txr->br)) 146961ae650dSJack F Vogel more_tx = 1; 147061ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 147161ae650dSJack F Vogel 147261ae650dSJack F Vogel /* re-enable other interrupt causes */ 147361ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, mask); 147461ae650dSJack F Vogel 147561ae650dSJack F Vogel /* And now the queues */ 147661ae650dSJack F Vogel reg = rd32(hw, I40E_QINT_RQCTL(0)); 147761ae650dSJack F Vogel reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; 147861ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(0), reg); 147961ae650dSJack F Vogel 148061ae650dSJack F Vogel reg = rd32(hw, I40E_QINT_TQCTL(0)); 148161ae650dSJack F Vogel reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; 148261ae650dSJack F Vogel reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK; 148361ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(0), reg); 148461ae650dSJack F Vogel 148561ae650dSJack F Vogel ixl_enable_legacy(hw); 148661ae650dSJack F Vogel 148761ae650dSJack F Vogel return; 148861ae650dSJack F Vogel } 148961ae650dSJack F Vogel 149061ae650dSJack F Vogel 149161ae650dSJack F Vogel /********************************************************************* 149261ae650dSJack F Vogel * 149361ae650dSJack F Vogel * MSIX VSI Interrupt Service routine 149461ae650dSJack F Vogel * 149561ae650dSJack F Vogel **********************************************************************/ 149661ae650dSJack F Vogel void 149761ae650dSJack F Vogel ixl_msix_que(void *arg) 149861ae650dSJack F Vogel { 149961ae650dSJack F Vogel struct ixl_queue *que = arg; 150061ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 150161ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 150261ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 150361ae650dSJack F Vogel bool more_tx, more_rx; 150461ae650dSJack F Vogel 150561ae650dSJack F Vogel /* Protect against spurious interrupts */ 150661ae650dSJack F Vogel if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) 150761ae650dSJack F Vogel return; 150861ae650dSJack F Vogel 150961ae650dSJack F Vogel ++que->irqs; 151061ae650dSJack F Vogel 151161ae650dSJack F Vogel more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 151261ae650dSJack F Vogel 151361ae650dSJack F Vogel IXL_TX_LOCK(txr); 151461ae650dSJack F Vogel more_tx = ixl_txeof(que); 151561ae650dSJack F Vogel /* 151661ae650dSJack F Vogel ** Make certain that if the stack 151761ae650dSJack F Vogel ** has anything queued the task gets 151861ae650dSJack F Vogel ** scheduled to handle it. 151961ae650dSJack F Vogel */ 152061ae650dSJack F Vogel if (!drbr_empty(vsi->ifp, txr->br)) 152161ae650dSJack F Vogel more_tx = 1; 152261ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 152361ae650dSJack F Vogel 152461ae650dSJack F Vogel ixl_set_queue_rx_itr(que); 152561ae650dSJack F Vogel ixl_set_queue_tx_itr(que); 152661ae650dSJack F Vogel 152761ae650dSJack F Vogel if (more_tx || more_rx) 152861ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->task); 152961ae650dSJack F Vogel else 153061ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 153161ae650dSJack F Vogel 153261ae650dSJack F Vogel return; 153361ae650dSJack F Vogel } 153461ae650dSJack F Vogel 153561ae650dSJack F Vogel 153661ae650dSJack F Vogel /********************************************************************* 153761ae650dSJack F Vogel * 153861ae650dSJack F Vogel * MSIX Admin Queue Interrupt Service routine 153961ae650dSJack F Vogel * 154061ae650dSJack F Vogel **********************************************************************/ 154161ae650dSJack F Vogel static void 154261ae650dSJack F Vogel ixl_msix_adminq(void *arg) 154361ae650dSJack F Vogel { 154461ae650dSJack F Vogel struct ixl_pf *pf = arg; 154561ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 1546fdb6f38aSEric Joyner u32 reg, mask, rstat_reg; 1547fdb6f38aSEric Joyner bool do_task = FALSE; 154861ae650dSJack F Vogel 154961ae650dSJack F Vogel ++pf->admin_irq; 155061ae650dSJack F Vogel 155161ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0); 155261ae650dSJack F Vogel mask = rd32(hw, I40E_PFINT_ICR0_ENA); 155361ae650dSJack F Vogel 155461ae650dSJack F Vogel /* Check on the cause */ 1555fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) { 1556fdb6f38aSEric Joyner mask &= ~I40E_PFINT_ICR0_ADMINQ_MASK; 1557fdb6f38aSEric Joyner do_task = TRUE; 1558fdb6f38aSEric Joyner } 155961ae650dSJack F Vogel 156061ae650dSJack F Vogel if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) { 156161ae650dSJack F Vogel ixl_handle_mdd_event(pf); 1562fdb6f38aSEric Joyner mask &= ~I40E_PFINT_ICR0_MAL_DETECT_MASK; 1563fdb6f38aSEric Joyner } 1564fdb6f38aSEric Joyner 1565fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_GRST_MASK) { 1566fdb6f38aSEric Joyner device_printf(pf->dev, "Reset Requested!\n"); 1567fdb6f38aSEric Joyner rstat_reg = rd32(hw, I40E_GLGEN_RSTAT); 1568fdb6f38aSEric Joyner rstat_reg = (rstat_reg & I40E_GLGEN_RSTAT_RESET_TYPE_MASK) 1569fdb6f38aSEric Joyner >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT; 1570fdb6f38aSEric Joyner device_printf(pf->dev, "Reset type: "); 1571fdb6f38aSEric Joyner switch (rstat_reg) { 1572fdb6f38aSEric Joyner /* These others might be handled similarly to an EMPR reset */ 1573fdb6f38aSEric Joyner case I40E_RESET_CORER: 1574fdb6f38aSEric Joyner printf("CORER\n"); 1575fdb6f38aSEric Joyner break; 1576fdb6f38aSEric Joyner case I40E_RESET_GLOBR: 1577fdb6f38aSEric Joyner printf("GLOBR\n"); 1578fdb6f38aSEric Joyner break; 1579fdb6f38aSEric Joyner case I40E_RESET_EMPR: 1580fdb6f38aSEric Joyner printf("EMPR\n"); 1581fdb6f38aSEric Joyner atomic_set_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); 1582fdb6f38aSEric Joyner break; 1583fdb6f38aSEric Joyner default: 1584fdb6f38aSEric Joyner printf("?\n"); 1585fdb6f38aSEric Joyner break; 1586fdb6f38aSEric Joyner } 1587fdb6f38aSEric Joyner // overload admin queue task to check reset progress? 1588fdb6f38aSEric Joyner do_task = TRUE; 1589fdb6f38aSEric Joyner } 1590fdb6f38aSEric Joyner 1591fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_ECC_ERR_MASK) { 1592fdb6f38aSEric Joyner device_printf(pf->dev, "ECC Error detected!\n"); 1593fdb6f38aSEric Joyner } 1594fdb6f38aSEric Joyner 1595fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_HMC_ERR_MASK) { 1596fdb6f38aSEric Joyner device_printf(pf->dev, "HMC Error detected!\n"); 1597fdb6f38aSEric Joyner } 1598fdb6f38aSEric Joyner 1599fdb6f38aSEric Joyner if (reg & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) { 1600fdb6f38aSEric Joyner device_printf(pf->dev, "PCI Exception detected!\n"); 160161ae650dSJack F Vogel } 160261ae650dSJack F Vogel 160356c2c47bSJack F Vogel #ifdef PCI_IOV 160456c2c47bSJack F Vogel if (reg & I40E_PFINT_ICR0_VFLR_MASK) { 160561ae650dSJack F Vogel mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; 160656c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->vflr_task); 160756c2c47bSJack F Vogel } 160856c2c47bSJack F Vogel #endif 160961ae650dSJack F Vogel 161061ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_DYN_CTL0); 161161ae650dSJack F Vogel reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 161261ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 161361ae650dSJack F Vogel 1614fdb6f38aSEric Joyner if (do_task) 161561ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 161661ae650dSJack F Vogel } 161761ae650dSJack F Vogel 161861ae650dSJack F Vogel /********************************************************************* 161961ae650dSJack F Vogel * 162061ae650dSJack F Vogel * Media Ioctl callback 162161ae650dSJack F Vogel * 162261ae650dSJack F Vogel * This routine is called whenever the user queries the status of 162361ae650dSJack F Vogel * the interface using ifconfig. 162461ae650dSJack F Vogel * 162561ae650dSJack F Vogel **********************************************************************/ 162661ae650dSJack F Vogel static void 162761ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 162861ae650dSJack F Vogel { 162961ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 163056c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 163161ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 163261ae650dSJack F Vogel 163361ae650dSJack F Vogel INIT_DEBUGOUT("ixl_media_status: begin"); 163461ae650dSJack F Vogel IXL_PF_LOCK(pf); 163561ae650dSJack F Vogel 163656c2c47bSJack F Vogel hw->phy.get_link_info = TRUE; 1637be771cdaSJack F Vogel i40e_get_link_status(hw, &pf->link_up); 163861ae650dSJack F Vogel ixl_update_link_status(pf); 163961ae650dSJack F Vogel 164061ae650dSJack F Vogel ifmr->ifm_status = IFM_AVALID; 164161ae650dSJack F Vogel ifmr->ifm_active = IFM_ETHER; 164261ae650dSJack F Vogel 164356c2c47bSJack F Vogel if (!pf->link_up) { 164461ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 164561ae650dSJack F Vogel return; 164661ae650dSJack F Vogel } 164761ae650dSJack F Vogel 164861ae650dSJack F Vogel ifmr->ifm_status |= IFM_ACTIVE; 1649ac83ea83SEric Joyner 1650ac83ea83SEric Joyner /* Hardware always does full-duplex */ 165161ae650dSJack F Vogel ifmr->ifm_active |= IFM_FDX; 165261ae650dSJack F Vogel 165361ae650dSJack F Vogel switch (hw->phy.link_info.phy_type) { 165461ae650dSJack F Vogel /* 100 M */ 165561ae650dSJack F Vogel case I40E_PHY_TYPE_100BASE_TX: 165661ae650dSJack F Vogel ifmr->ifm_active |= IFM_100_TX; 165761ae650dSJack F Vogel break; 165861ae650dSJack F Vogel /* 1 G */ 165961ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_T: 166061ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_T; 166161ae650dSJack F Vogel break; 166261ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_SX: 166361ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_SX; 166461ae650dSJack F Vogel break; 166561ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_LX: 166661ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_LX; 166761ae650dSJack F Vogel break; 16681d767a8eSEric Joyner case I40E_PHY_TYPE_1000BASE_T_OPTICAL: 16691d767a8eSEric Joyner ifmr->ifm_active |= IFM_OTHER; 16701d767a8eSEric Joyner break; 167161ae650dSJack F Vogel /* 10 G */ 167261ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_SFPP_CU: 167361ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX; 167461ae650dSJack F Vogel break; 167561ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_SR: 167661ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_SR; 167761ae650dSJack F Vogel break; 167861ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_LR: 167961ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_LR; 168061ae650dSJack F Vogel break; 168161ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_T: 168261ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_T; 168361ae650dSJack F Vogel break; 16841d767a8eSEric Joyner case I40E_PHY_TYPE_XAUI: 16851d767a8eSEric Joyner case I40E_PHY_TYPE_XFI: 16861d767a8eSEric Joyner case I40E_PHY_TYPE_10GBASE_AOC: 16871d767a8eSEric Joyner ifmr->ifm_active |= IFM_OTHER; 16881d767a8eSEric Joyner break; 168961ae650dSJack F Vogel /* 40 G */ 169061ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_CR4: 169161ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_CR4_CU: 169261ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_CR4; 169361ae650dSJack F Vogel break; 169461ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_SR4: 169561ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_SR4; 169661ae650dSJack F Vogel break; 169761ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_LR4: 169861ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_LR4; 169961ae650dSJack F Vogel break; 17001d767a8eSEric Joyner case I40E_PHY_TYPE_XLAUI: 17011d767a8eSEric Joyner ifmr->ifm_active |= IFM_OTHER; 17021d767a8eSEric Joyner break; 1703be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE 1704be771cdaSJack F Vogel case I40E_PHY_TYPE_1000BASE_KX: 1705be771cdaSJack F Vogel ifmr->ifm_active |= IFM_1000_CX; 1706b6c8f260SJack F Vogel break; 17071d767a8eSEric Joyner case I40E_PHY_TYPE_SGMII: 17081d767a8eSEric Joyner ifmr->ifm_active |= IFM_OTHER; 17091d767a8eSEric Joyner break; 1710be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1_CU: 1711be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1: 1712be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX; 1713be771cdaSJack F Vogel break; 1714be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KX4: 1715be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_CX4; 1716be771cdaSJack F Vogel break; 1717be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KR: 1718be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_SR; 1719be771cdaSJack F Vogel break; 17201d767a8eSEric Joyner case I40E_PHY_TYPE_SFI: 17211d767a8eSEric Joyner ifmr->ifm_active |= IFM_OTHER; 17221d767a8eSEric Joyner break; 1723be771cdaSJack F Vogel case I40E_PHY_TYPE_40GBASE_KR4: 1724be771cdaSJack F Vogel case I40E_PHY_TYPE_XLPPI: 17251d767a8eSEric Joyner case I40E_PHY_TYPE_40GBASE_AOC: 1726be771cdaSJack F Vogel ifmr->ifm_active |= IFM_40G_SR4; 1727be771cdaSJack F Vogel break; 1728be771cdaSJack F Vogel #else 1729be771cdaSJack F Vogel case I40E_PHY_TYPE_1000BASE_KX: 1730be771cdaSJack F Vogel ifmr->ifm_active |= IFM_1000_KX; 1731be771cdaSJack F Vogel break; 17321d767a8eSEric Joyner case I40E_PHY_TYPE_SGMII: 17331d767a8eSEric Joyner ifmr->ifm_active |= IFM_1000_SGMII; 17341d767a8eSEric Joyner break; 1735be771cdaSJack F Vogel /* ERJ: What's the difference between these? */ 1736be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1_CU: 1737be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1: 1738be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_CR1; 1739be771cdaSJack F Vogel break; 1740be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KX4: 1741be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_KX4; 1742be771cdaSJack F Vogel break; 1743be771cdaSJack F Vogel case I40E_PHY_TYPE_10GBASE_KR: 1744be771cdaSJack F Vogel ifmr->ifm_active |= IFM_10G_KR; 1745be771cdaSJack F Vogel break; 17461d767a8eSEric Joyner case I40E_PHY_TYPE_SFI: 17471d767a8eSEric Joyner ifmr->ifm_active |= IFM_10G_SFI; 17481d767a8eSEric Joyner break; 1749ac83ea83SEric Joyner /* Our single 20G media type */ 1750be771cdaSJack F Vogel case I40E_PHY_TYPE_20GBASE_KR2: 1751be771cdaSJack F Vogel ifmr->ifm_active |= IFM_20G_KR2; 1752be771cdaSJack F Vogel break; 1753be771cdaSJack F Vogel case I40E_PHY_TYPE_40GBASE_KR4: 1754be771cdaSJack F Vogel ifmr->ifm_active |= IFM_40G_KR4; 1755be771cdaSJack F Vogel break; 1756be771cdaSJack F Vogel case I40E_PHY_TYPE_XLPPI: 17571d767a8eSEric Joyner case I40E_PHY_TYPE_40GBASE_AOC: 1758be771cdaSJack F Vogel ifmr->ifm_active |= IFM_40G_XLPPI; 1759be771cdaSJack F Vogel break; 1760be771cdaSJack F Vogel #endif 17611d767a8eSEric Joyner /* Unknown to driver */ 176261ae650dSJack F Vogel default: 176361ae650dSJack F Vogel ifmr->ifm_active |= IFM_UNKNOWN; 176461ae650dSJack F Vogel break; 176561ae650dSJack F Vogel } 176661ae650dSJack F Vogel /* Report flow control status as well */ 176761ae650dSJack F Vogel if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) 176861ae650dSJack F Vogel ifmr->ifm_active |= IFM_ETH_TXPAUSE; 176961ae650dSJack F Vogel if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) 177061ae650dSJack F Vogel ifmr->ifm_active |= IFM_ETH_RXPAUSE; 177161ae650dSJack F Vogel 177261ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 177361ae650dSJack F Vogel 177461ae650dSJack F Vogel return; 177561ae650dSJack F Vogel } 177661ae650dSJack F Vogel 1777ac83ea83SEric Joyner /* 1778ac83ea83SEric Joyner * NOTE: Fortville does not support forcing media speeds. Instead, 1779ac83ea83SEric Joyner * use the set_advertise sysctl to set the speeds Fortville 1780ac83ea83SEric Joyner * will advertise or be allowed to operate at. 1781ac83ea83SEric Joyner */ 178261ae650dSJack F Vogel static int 178361ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp) 178461ae650dSJack F Vogel { 178561ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 178661ae650dSJack F Vogel struct ifmedia *ifm = &vsi->media; 178761ae650dSJack F Vogel 178861ae650dSJack F Vogel INIT_DEBUGOUT("ixl_media_change: begin"); 178961ae650dSJack F Vogel 179061ae650dSJack F Vogel if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 179161ae650dSJack F Vogel return (EINVAL); 179261ae650dSJack F Vogel 1793ac83ea83SEric Joyner if_printf(ifp, "Media change is not supported.\n"); 179461ae650dSJack F Vogel 179561ae650dSJack F Vogel return (ENODEV); 179661ae650dSJack F Vogel } 179761ae650dSJack F Vogel 179861ae650dSJack F Vogel 179961ae650dSJack F Vogel #ifdef IXL_FDIR 180061ae650dSJack F Vogel /* 180161ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter 180261ae650dSJack F Vogel ** based on TX flow info that will keep the receive 180361ae650dSJack F Vogel ** portion of the flow on the same queue. Based on the 180461ae650dSJack F Vogel ** implementation this is only available for TCP connections 180561ae650dSJack F Vogel */ 180661ae650dSJack F Vogel void 180761ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype) 180861ae650dSJack F Vogel { 180961ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 181061ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 181161ae650dSJack F Vogel struct i40e_filter_program_desc *FDIR; 181261ae650dSJack F Vogel u32 ptype, dtype; 181361ae650dSJack F Vogel int idx; 181461ae650dSJack F Vogel 181561ae650dSJack F Vogel /* check if ATR is enabled and sample rate */ 181661ae650dSJack F Vogel if ((!ixl_enable_fdir) || (!txr->atr_rate)) 181761ae650dSJack F Vogel return; 181861ae650dSJack F Vogel /* 181961ae650dSJack F Vogel ** We sample all TCP SYN/FIN packets, 182061ae650dSJack F Vogel ** or at the selected sample rate 182161ae650dSJack F Vogel */ 182261ae650dSJack F Vogel txr->atr_count++; 182361ae650dSJack F Vogel if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) && 182461ae650dSJack F Vogel (txr->atr_count < txr->atr_rate)) 182561ae650dSJack F Vogel return; 182661ae650dSJack F Vogel txr->atr_count = 0; 182761ae650dSJack F Vogel 182861ae650dSJack F Vogel /* Get a descriptor to use */ 182961ae650dSJack F Vogel idx = txr->next_avail; 183061ae650dSJack F Vogel FDIR = (struct i40e_filter_program_desc *) &txr->base[idx]; 183161ae650dSJack F Vogel if (++idx == que->num_desc) 183261ae650dSJack F Vogel idx = 0; 183361ae650dSJack F Vogel txr->avail--; 183461ae650dSJack F Vogel txr->next_avail = idx; 183561ae650dSJack F Vogel 183661ae650dSJack F Vogel ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & 183761ae650dSJack F Vogel I40E_TXD_FLTR_QW0_QINDEX_MASK; 183861ae650dSJack F Vogel 183961ae650dSJack F Vogel ptype |= (etype == ETHERTYPE_IP) ? 184061ae650dSJack F Vogel (I40E_FILTER_PCTYPE_NONF_IPV4_TCP << 184161ae650dSJack F Vogel I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) : 184261ae650dSJack F Vogel (I40E_FILTER_PCTYPE_NONF_IPV6_TCP << 184361ae650dSJack F Vogel I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); 184461ae650dSJack F Vogel 184561ae650dSJack F Vogel ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT; 184661ae650dSJack F Vogel 184761ae650dSJack F Vogel dtype = I40E_TX_DESC_DTYPE_FILTER_PROG; 184861ae650dSJack F Vogel 184961ae650dSJack F Vogel /* 185061ae650dSJack F Vogel ** We use the TCP TH_FIN as a trigger to remove 185161ae650dSJack F Vogel ** the filter, otherwise its an update. 185261ae650dSJack F Vogel */ 185361ae650dSJack F Vogel dtype |= (th->th_flags & TH_FIN) ? 185461ae650dSJack F Vogel (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << 185561ae650dSJack F Vogel I40E_TXD_FLTR_QW1_PCMD_SHIFT) : 185661ae650dSJack F Vogel (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << 185761ae650dSJack F Vogel I40E_TXD_FLTR_QW1_PCMD_SHIFT); 185861ae650dSJack F Vogel 185961ae650dSJack F Vogel dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX << 186061ae650dSJack F Vogel I40E_TXD_FLTR_QW1_DEST_SHIFT; 186161ae650dSJack F Vogel 186261ae650dSJack F Vogel dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID << 186361ae650dSJack F Vogel I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT; 186461ae650dSJack F Vogel 186561ae650dSJack F Vogel FDIR->qindex_flex_ptype_vsi = htole32(ptype); 186661ae650dSJack F Vogel FDIR->dtype_cmd_cntindex = htole32(dtype); 186761ae650dSJack F Vogel return; 186861ae650dSJack F Vogel } 186961ae650dSJack F Vogel #endif 187061ae650dSJack F Vogel 187161ae650dSJack F Vogel 187261ae650dSJack F Vogel static void 187361ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi) 187461ae650dSJack F Vogel { 187561ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 187661ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 187761ae650dSJack F Vogel int err, mcnt = 0; 187861ae650dSJack F Vogel bool uni = FALSE, multi = FALSE; 187961ae650dSJack F Vogel 188061ae650dSJack F Vogel if (ifp->if_flags & IFF_ALLMULTI) 188161ae650dSJack F Vogel multi = TRUE; 188261ae650dSJack F Vogel else { /* Need to count the multicast addresses */ 188361ae650dSJack F Vogel struct ifmultiaddr *ifma; 188461ae650dSJack F Vogel if_maddr_rlock(ifp); 188561ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 188661ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 188761ae650dSJack F Vogel continue; 188861ae650dSJack F Vogel if (mcnt == MAX_MULTICAST_ADDR) 188961ae650dSJack F Vogel break; 189061ae650dSJack F Vogel mcnt++; 189161ae650dSJack F Vogel } 189261ae650dSJack F Vogel if_maddr_runlock(ifp); 189361ae650dSJack F Vogel } 189461ae650dSJack F Vogel 189561ae650dSJack F Vogel if (mcnt >= MAX_MULTICAST_ADDR) 189661ae650dSJack F Vogel multi = TRUE; 189761ae650dSJack F Vogel if (ifp->if_flags & IFF_PROMISC) 189861ae650dSJack F Vogel uni = TRUE; 189961ae650dSJack F Vogel 190061ae650dSJack F Vogel err = i40e_aq_set_vsi_unicast_promiscuous(hw, 190161ae650dSJack F Vogel vsi->seid, uni, NULL); 190261ae650dSJack F Vogel err = i40e_aq_set_vsi_multicast_promiscuous(hw, 190361ae650dSJack F Vogel vsi->seid, multi, NULL); 190461ae650dSJack F Vogel return; 190561ae650dSJack F Vogel } 190661ae650dSJack F Vogel 190761ae650dSJack F Vogel /********************************************************************* 190861ae650dSJack F Vogel * Filter Routines 190961ae650dSJack F Vogel * 191061ae650dSJack F Vogel * Routines for multicast and vlan filter management. 191161ae650dSJack F Vogel * 191261ae650dSJack F Vogel *********************************************************************/ 191361ae650dSJack F Vogel static void 191461ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi) 191561ae650dSJack F Vogel { 191661ae650dSJack F Vogel struct ifmultiaddr *ifma; 191761ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 191861ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 191961ae650dSJack F Vogel int mcnt = 0, flags; 192061ae650dSJack F Vogel 192161ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_add_multi: begin"); 192261ae650dSJack F Vogel 192361ae650dSJack F Vogel if_maddr_rlock(ifp); 192461ae650dSJack F Vogel /* 192561ae650dSJack F Vogel ** First just get a count, to decide if we 192661ae650dSJack F Vogel ** we simply use multicast promiscuous. 192761ae650dSJack F Vogel */ 192861ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 192961ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 193061ae650dSJack F Vogel continue; 193161ae650dSJack F Vogel mcnt++; 193261ae650dSJack F Vogel } 193361ae650dSJack F Vogel if_maddr_runlock(ifp); 193461ae650dSJack F Vogel 193561ae650dSJack F Vogel if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { 193661ae650dSJack F Vogel /* delete existing MC filters */ 193761ae650dSJack F Vogel ixl_del_hw_filters(vsi, mcnt); 193861ae650dSJack F Vogel i40e_aq_set_vsi_multicast_promiscuous(hw, 193961ae650dSJack F Vogel vsi->seid, TRUE, NULL); 194061ae650dSJack F Vogel return; 194161ae650dSJack F Vogel } 194261ae650dSJack F Vogel 194361ae650dSJack F Vogel mcnt = 0; 194461ae650dSJack F Vogel if_maddr_rlock(ifp); 194561ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 194661ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 194761ae650dSJack F Vogel continue; 194861ae650dSJack F Vogel ixl_add_mc_filter(vsi, 194961ae650dSJack F Vogel (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); 195061ae650dSJack F Vogel mcnt++; 195161ae650dSJack F Vogel } 195261ae650dSJack F Vogel if_maddr_runlock(ifp); 195361ae650dSJack F Vogel if (mcnt > 0) { 195461ae650dSJack F Vogel flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); 195561ae650dSJack F Vogel ixl_add_hw_filters(vsi, flags, mcnt); 195661ae650dSJack F Vogel } 195761ae650dSJack F Vogel 195861ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_add_multi: end"); 195961ae650dSJack F Vogel return; 196061ae650dSJack F Vogel } 196161ae650dSJack F Vogel 196261ae650dSJack F Vogel static void 196361ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi) 196461ae650dSJack F Vogel { 196561ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 196661ae650dSJack F Vogel struct ifmultiaddr *ifma; 196761ae650dSJack F Vogel struct ixl_mac_filter *f; 196861ae650dSJack F Vogel int mcnt = 0; 196961ae650dSJack F Vogel bool match = FALSE; 197061ae650dSJack F Vogel 197161ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_del_multi: begin"); 197261ae650dSJack F Vogel 197361ae650dSJack F Vogel /* Search for removed multicast addresses */ 197461ae650dSJack F Vogel if_maddr_rlock(ifp); 197561ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 197661ae650dSJack F Vogel if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) { 197761ae650dSJack F Vogel match = FALSE; 197861ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 197961ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 198061ae650dSJack F Vogel continue; 198161ae650dSJack F Vogel u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 198261ae650dSJack F Vogel if (cmp_etheraddr(f->macaddr, mc_addr)) { 198361ae650dSJack F Vogel match = TRUE; 198461ae650dSJack F Vogel break; 198561ae650dSJack F Vogel } 198661ae650dSJack F Vogel } 198761ae650dSJack F Vogel if (match == FALSE) { 198861ae650dSJack F Vogel f->flags |= IXL_FILTER_DEL; 198961ae650dSJack F Vogel mcnt++; 199061ae650dSJack F Vogel } 199161ae650dSJack F Vogel } 199261ae650dSJack F Vogel } 199361ae650dSJack F Vogel if_maddr_runlock(ifp); 199461ae650dSJack F Vogel 199561ae650dSJack F Vogel if (mcnt > 0) 199661ae650dSJack F Vogel ixl_del_hw_filters(vsi, mcnt); 199761ae650dSJack F Vogel } 199861ae650dSJack F Vogel 199961ae650dSJack F Vogel 200061ae650dSJack F Vogel /********************************************************************* 200161ae650dSJack F Vogel * Timer routine 200261ae650dSJack F Vogel * 200361ae650dSJack F Vogel * This routine checks for link status,updates statistics, 200461ae650dSJack F Vogel * and runs the watchdog check. 200561ae650dSJack F Vogel * 200695bb0504SEric Joyner * Only runs when the driver is configured UP and RUNNING. 200795bb0504SEric Joyner * 200861ae650dSJack F Vogel **********************************************************************/ 200961ae650dSJack F Vogel 201061ae650dSJack F Vogel static void 201161ae650dSJack F Vogel ixl_local_timer(void *arg) 201261ae650dSJack F Vogel { 201361ae650dSJack F Vogel struct ixl_pf *pf = arg; 201461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 201561ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 201661ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 201761ae650dSJack F Vogel device_t dev = pf->dev; 201861ae650dSJack F Vogel int hung = 0; 201961ae650dSJack F Vogel u32 mask; 202061ae650dSJack F Vogel 202161ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 202261ae650dSJack F Vogel 202361ae650dSJack F Vogel /* Fire off the adminq task */ 202461ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 202561ae650dSJack F Vogel 202661ae650dSJack F Vogel /* Update stats */ 202761ae650dSJack F Vogel ixl_update_stats_counters(pf); 202861ae650dSJack F Vogel 202961ae650dSJack F Vogel /* 203061ae650dSJack F Vogel ** Check status of the queues 203161ae650dSJack F Vogel */ 203261ae650dSJack F Vogel mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | 203361ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); 203461ae650dSJack F Vogel 203561ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++,que++) { 203661ae650dSJack F Vogel /* Any queues with outstanding work get a sw irq */ 203761ae650dSJack F Vogel if (que->busy) 203861ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask); 203961ae650dSJack F Vogel /* 204061ae650dSJack F Vogel ** Each time txeof runs without cleaning, but there 204161ae650dSJack F Vogel ** are uncleaned descriptors it increments busy. If 204261ae650dSJack F Vogel ** we get to 5 we declare it hung. 204361ae650dSJack F Vogel */ 204461ae650dSJack F Vogel if (que->busy == IXL_QUEUE_HUNG) { 204561ae650dSJack F Vogel ++hung; 204661ae650dSJack F Vogel /* Mark the queue as inactive */ 204761ae650dSJack F Vogel vsi->active_queues &= ~((u64)1 << que->me); 204861ae650dSJack F Vogel continue; 204961ae650dSJack F Vogel } else { 205061ae650dSJack F Vogel /* Check if we've come back from hung */ 205161ae650dSJack F Vogel if ((vsi->active_queues & ((u64)1 << que->me)) == 0) 205261ae650dSJack F Vogel vsi->active_queues |= ((u64)1 << que->me); 205361ae650dSJack F Vogel } 205461ae650dSJack F Vogel if (que->busy >= IXL_MAX_TX_BUSY) { 2055393c4bb1SJack F Vogel #ifdef IXL_DEBUG 205661ae650dSJack F Vogel device_printf(dev,"Warning queue %d " 205761ae650dSJack F Vogel "appears to be hung!\n", i); 2058393c4bb1SJack F Vogel #endif 205961ae650dSJack F Vogel que->busy = IXL_QUEUE_HUNG; 206061ae650dSJack F Vogel ++hung; 206161ae650dSJack F Vogel } 206261ae650dSJack F Vogel } 206361ae650dSJack F Vogel /* Only reinit if all queues show hung */ 206461ae650dSJack F Vogel if (hung == vsi->num_queues) 206561ae650dSJack F Vogel goto hung; 206661ae650dSJack F Vogel 206761ae650dSJack F Vogel callout_reset(&pf->timer, hz, ixl_local_timer, pf); 206861ae650dSJack F Vogel return; 206961ae650dSJack F Vogel 207061ae650dSJack F Vogel hung: 207161ae650dSJack F Vogel device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n"); 207261ae650dSJack F Vogel ixl_init_locked(pf); 207361ae650dSJack F Vogel } 207461ae650dSJack F Vogel 207561ae650dSJack F Vogel /* 207661ae650dSJack F Vogel ** Note: this routine updates the OS on the link state 207761ae650dSJack F Vogel ** the real check of the hardware only happens with 207861ae650dSJack F Vogel ** a link interrupt. 207961ae650dSJack F Vogel */ 208061ae650dSJack F Vogel static void 208161ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf) 208261ae650dSJack F Vogel { 208361ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 208461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 208561ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 208661ae650dSJack F Vogel device_t dev = pf->dev; 208761ae650dSJack F Vogel 208856c2c47bSJack F Vogel if (pf->link_up) { 208961ae650dSJack F Vogel if (vsi->link_active == FALSE) { 2090b6c8f260SJack F Vogel pf->fc = hw->fc.current_mode; 209161ae650dSJack F Vogel if (bootverbose) { 209261ae650dSJack F Vogel device_printf(dev,"Link is up %d Gbps %s," 209361ae650dSJack F Vogel " Flow Control: %s\n", 209456c2c47bSJack F Vogel ((pf->link_speed == 209556c2c47bSJack F Vogel I40E_LINK_SPEED_40GB)? 40:10), 2096b6c8f260SJack F Vogel "Full Duplex", ixl_fc_string[pf->fc]); 209761ae650dSJack F Vogel } 209861ae650dSJack F Vogel vsi->link_active = TRUE; 2099393c4bb1SJack F Vogel /* 2100393c4bb1SJack F Vogel ** Warn user if link speed on NPAR enabled 2101393c4bb1SJack F Vogel ** partition is not at least 10GB 2102393c4bb1SJack F Vogel */ 2103393c4bb1SJack F Vogel if (hw->func_caps.npar_enable && 210456c2c47bSJack F Vogel (hw->phy.link_info.link_speed == 210556c2c47bSJack F Vogel I40E_LINK_SPEED_1GB || 210656c2c47bSJack F Vogel hw->phy.link_info.link_speed == 210756c2c47bSJack F Vogel I40E_LINK_SPEED_100MB)) 210856c2c47bSJack F Vogel device_printf(dev, "The partition detected" 210956c2c47bSJack F Vogel "link speed that is less than 10Gbps\n"); 211061ae650dSJack F Vogel if_link_state_change(ifp, LINK_STATE_UP); 211161ae650dSJack F Vogel } 211261ae650dSJack F Vogel } else { /* Link down */ 211361ae650dSJack F Vogel if (vsi->link_active == TRUE) { 211461ae650dSJack F Vogel if (bootverbose) 211561ae650dSJack F Vogel device_printf(dev, "Link is Down\n"); 211661ae650dSJack F Vogel if_link_state_change(ifp, LINK_STATE_DOWN); 211761ae650dSJack F Vogel vsi->link_active = FALSE; 211861ae650dSJack F Vogel } 211961ae650dSJack F Vogel } 212061ae650dSJack F Vogel 212161ae650dSJack F Vogel return; 212261ae650dSJack F Vogel } 212361ae650dSJack F Vogel 2124223d846dSEric Joyner static void 2125223d846dSEric Joyner ixl_stop(struct ixl_pf *pf) 2126223d846dSEric Joyner { 2127223d846dSEric Joyner IXL_PF_LOCK(pf); 2128223d846dSEric Joyner ixl_stop_locked(pf); 2129223d846dSEric Joyner IXL_PF_UNLOCK(pf); 2130223d846dSEric Joyner 2131*6c426059SEric Joyner ixl_teardown_queue_msix(&pf->vsi); 2132223d846dSEric Joyner } 2133223d846dSEric Joyner 213461ae650dSJack F Vogel /********************************************************************* 213561ae650dSJack F Vogel * 213661ae650dSJack F Vogel * This routine disables all traffic on the adapter by issuing a 213761ae650dSJack F Vogel * global reset on the MAC and deallocates TX/RX buffers. 213861ae650dSJack F Vogel * 213961ae650dSJack F Vogel **********************************************************************/ 214061ae650dSJack F Vogel 214161ae650dSJack F Vogel static void 2142223d846dSEric Joyner ixl_stop_locked(struct ixl_pf *pf) 214361ae650dSJack F Vogel { 214461ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 214561ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 214661ae650dSJack F Vogel 214761ae650dSJack F Vogel INIT_DEBUGOUT("ixl_stop: begin\n"); 2148223d846dSEric Joyner 2149223d846dSEric Joyner IXL_PF_LOCK_ASSERT(pf); 2150223d846dSEric Joyner 2151223d846dSEric Joyner /* Stop the local timer */ 2152223d846dSEric Joyner callout_stop(&pf->timer); 2153223d846dSEric Joyner 215456c2c47bSJack F Vogel ixl_disable_rings_intr(vsi); 215561ae650dSJack F Vogel ixl_disable_rings(vsi); 215661ae650dSJack F Vogel 215761ae650dSJack F Vogel /* Tell the stack that the interface is no longer active */ 2158*6c426059SEric Joyner ifp->if_drv_flags &= ~(IFF_DRV_RUNNING); 215961ae650dSJack F Vogel } 216061ae650dSJack F Vogel 216161ae650dSJack F Vogel 216261ae650dSJack F Vogel /********************************************************************* 216361ae650dSJack F Vogel * 216461ae650dSJack F Vogel * Setup MSIX Interrupt resources and handlers for the VSI 216561ae650dSJack F Vogel * 216661ae650dSJack F Vogel **********************************************************************/ 216761ae650dSJack F Vogel static int 216861ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf) 216961ae650dSJack F Vogel { 217061ae650dSJack F Vogel device_t dev = pf->dev; 217161ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 217261ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 217361ae650dSJack F Vogel int error, rid = 0; 217461ae650dSJack F Vogel 217561ae650dSJack F Vogel if (pf->msix == 1) 217661ae650dSJack F Vogel rid = 1; 217761ae650dSJack F Vogel pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 217861ae650dSJack F Vogel &rid, RF_SHAREABLE | RF_ACTIVE); 217961ae650dSJack F Vogel if (pf->res == NULL) { 218061ae650dSJack F Vogel device_printf(dev, "Unable to allocate" 218161ae650dSJack F Vogel " bus resource: vsi legacy/msi interrupt\n"); 218261ae650dSJack F Vogel return (ENXIO); 218361ae650dSJack F Vogel } 218461ae650dSJack F Vogel 218561ae650dSJack F Vogel /* Set the handler function */ 218661ae650dSJack F Vogel error = bus_setup_intr(dev, pf->res, 218761ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 218861ae650dSJack F Vogel ixl_intr, pf, &pf->tag); 218961ae650dSJack F Vogel if (error) { 219061ae650dSJack F Vogel pf->res = NULL; 21911d767a8eSEric Joyner device_printf(dev, "Failed to register legacy/msi handler\n"); 219261ae650dSJack F Vogel return (error); 219361ae650dSJack F Vogel } 219461ae650dSJack F Vogel bus_describe_intr(dev, pf->res, pf->tag, "irq0"); 219561ae650dSJack F Vogel TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 219661ae650dSJack F Vogel TASK_INIT(&que->task, 0, ixl_handle_que, que); 219761ae650dSJack F Vogel que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 219861ae650dSJack F Vogel taskqueue_thread_enqueue, &que->tq); 219961ae650dSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 220061ae650dSJack F Vogel device_get_nameunit(dev)); 220161ae650dSJack F Vogel TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 220256c2c47bSJack F Vogel 220361ae650dSJack F Vogel pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 220461ae650dSJack F Vogel taskqueue_thread_enqueue, &pf->tq); 220561ae650dSJack F Vogel taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 220661ae650dSJack F Vogel device_get_nameunit(dev)); 220761ae650dSJack F Vogel 220861ae650dSJack F Vogel return (0); 220961ae650dSJack F Vogel } 221061ae650dSJack F Vogel 2211*6c426059SEric Joyner static int 2212*6c426059SEric Joyner ixl_setup_adminq_tq(struct ixl_pf *pf) 2213a48d00d2SEric Joyner { 2214a48d00d2SEric Joyner device_t dev = pf->dev; 2215*6c426059SEric Joyner int error = 0; 2216a48d00d2SEric Joyner 2217*6c426059SEric Joyner /* Tasklet for Admin Queue interrupts */ 2218a48d00d2SEric Joyner TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 2219a48d00d2SEric Joyner #ifdef PCI_IOV 2220a48d00d2SEric Joyner /* VFLR Tasklet */ 2221a48d00d2SEric Joyner TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf); 2222a48d00d2SEric Joyner #endif 2223*6c426059SEric Joyner /* Create and start Admin Queue taskqueue */ 2224*6c426059SEric Joyner pf->tq = taskqueue_create_fast("ixl_aq", M_NOWAIT, 2225a48d00d2SEric Joyner taskqueue_thread_enqueue, &pf->tq); 2226*6c426059SEric Joyner if (!pf->tq) { 2227*6c426059SEric Joyner device_printf(dev, "taskqueue_create_fast (for AQ) returned NULL!\n"); 2228*6c426059SEric Joyner return (ENOMEM); 2229*6c426059SEric Joyner } 2230*6c426059SEric Joyner error = taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s aq", 2231a48d00d2SEric Joyner device_get_nameunit(dev)); 2232*6c426059SEric Joyner if (error) { 2233*6c426059SEric Joyner device_printf(dev, "taskqueue_start_threads (for AQ) error: %d\n", 2234*6c426059SEric Joyner error); 2235*6c426059SEric Joyner taskqueue_free(pf->tq); 2236*6c426059SEric Joyner return (error); 2237*6c426059SEric Joyner } 2238*6c426059SEric Joyner return (0); 2239*6c426059SEric Joyner } 2240*6c426059SEric Joyner 2241*6c426059SEric Joyner static int 2242*6c426059SEric Joyner ixl_setup_queue_tqs(struct ixl_vsi *vsi) 2243*6c426059SEric Joyner { 2244*6c426059SEric Joyner struct ixl_queue *que = vsi->queues; 2245*6c426059SEric Joyner device_t dev = vsi->dev; 2246a48d00d2SEric Joyner 2247a48d00d2SEric Joyner /* Create queue tasks and start queue taskqueues */ 2248a48d00d2SEric Joyner for (int i = 0; i < vsi->num_queues; i++, que++) { 2249a48d00d2SEric Joyner TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 2250a48d00d2SEric Joyner TASK_INIT(&que->task, 0, ixl_handle_que, que); 2251a48d00d2SEric Joyner que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 2252a48d00d2SEric Joyner taskqueue_thread_enqueue, &que->tq); 2253a48d00d2SEric Joyner #ifdef RSS 2254a48d00d2SEric Joyner CPU_SETOF(cpu_id, &cpu_mask); 2255a48d00d2SEric Joyner taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, 2256a48d00d2SEric Joyner &cpu_mask, "%s (bucket %d)", 2257a48d00d2SEric Joyner device_get_nameunit(dev), cpu_id); 2258a48d00d2SEric Joyner #else 2259a48d00d2SEric Joyner taskqueue_start_threads(&que->tq, 1, PI_NET, 2260a48d00d2SEric Joyner "%s (que %d)", device_get_nameunit(dev), que->me); 2261a48d00d2SEric Joyner #endif 2262a48d00d2SEric Joyner } 2263a48d00d2SEric Joyner 2264*6c426059SEric Joyner return (0); 2265a48d00d2SEric Joyner } 2266a48d00d2SEric Joyner 2267a48d00d2SEric Joyner static void 2268*6c426059SEric Joyner ixl_free_adminq_tq(struct ixl_pf *pf) 2269a48d00d2SEric Joyner { 2270a48d00d2SEric Joyner if (pf->tq) 2271a48d00d2SEric Joyner taskqueue_free(pf->tq); 2272*6c426059SEric Joyner } 2273*6c426059SEric Joyner 2274*6c426059SEric Joyner static void 2275*6c426059SEric Joyner ixl_free_queue_tqs(struct ixl_vsi *vsi) 2276*6c426059SEric Joyner { 2277*6c426059SEric Joyner struct ixl_queue *que = vsi->queues; 2278*6c426059SEric Joyner 2279a48d00d2SEric Joyner for (int i = 0; i < vsi->num_queues; i++, que++) { 2280a48d00d2SEric Joyner if (que->tq) 2281a48d00d2SEric Joyner taskqueue_free(que->tq); 2282a48d00d2SEric Joyner } 2283a48d00d2SEric Joyner } 228461ae650dSJack F Vogel 228561ae650dSJack F Vogel static int 2286*6c426059SEric Joyner ixl_setup_adminq_msix(struct ixl_pf *pf) 228761ae650dSJack F Vogel { 228861ae650dSJack F Vogel device_t dev = pf->dev; 2289*6c426059SEric Joyner int rid, error = 0; 229061ae650dSJack F Vogel 2291*6c426059SEric Joyner /* Admin IRQ rid is 1, vector is 0 */ 2292*6c426059SEric Joyner rid = 1; 2293*6c426059SEric Joyner /* Get interrupt resource from bus */ 229461ae650dSJack F Vogel pf->res = bus_alloc_resource_any(dev, 229561ae650dSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 229661ae650dSJack F Vogel if (!pf->res) { 2297*6c426059SEric Joyner device_printf(dev, "bus_alloc_resource_any() for Admin Queue" 2298*6c426059SEric Joyner " interrupt failed [rid=%d]\n", rid); 229961ae650dSJack F Vogel return (ENXIO); 230061ae650dSJack F Vogel } 2301*6c426059SEric Joyner /* Then associate interrupt with handler */ 230261ae650dSJack F Vogel error = bus_setup_intr(dev, pf->res, 230361ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 230461ae650dSJack F Vogel ixl_msix_adminq, pf, &pf->tag); 230561ae650dSJack F Vogel if (error) { 230661ae650dSJack F Vogel pf->res = NULL; 2307*6c426059SEric Joyner device_printf(dev, "bus_setup_intr() for Admin Queue" 2308*6c426059SEric Joyner " interrupt handler failed, error %d\n", error); 2309*6c426059SEric Joyner return (ENXIO); 231061ae650dSJack F Vogel } 2311*6c426059SEric Joyner error = bus_describe_intr(dev, pf->res, pf->tag, "aq"); 2312*6c426059SEric Joyner if (error) { 2313*6c426059SEric Joyner /* Probably non-fatal? */ 2314*6c426059SEric Joyner device_printf(dev, "bus_describe_intr() for Admin Queue" 2315*6c426059SEric Joyner " interrupt name failed, error %d\n", error); 2316*6c426059SEric Joyner } 2317*6c426059SEric Joyner pf->admvec = 0; 231861ae650dSJack F Vogel 2319*6c426059SEric Joyner return (0); 2320*6c426059SEric Joyner } 2321*6c426059SEric Joyner 2322*6c426059SEric Joyner /* 2323*6c426059SEric Joyner * Allocate interrupt resources from bus and associate an interrupt handler 2324*6c426059SEric Joyner * to those for the VSI's queues. 2325*6c426059SEric Joyner */ 2326*6c426059SEric Joyner static int 2327*6c426059SEric Joyner ixl_setup_queue_msix(struct ixl_vsi *vsi) 2328*6c426059SEric Joyner { 2329*6c426059SEric Joyner device_t dev = vsi->dev; 2330*6c426059SEric Joyner struct ixl_queue *que = vsi->queues; 2331*6c426059SEric Joyner struct tx_ring *txr; 2332*6c426059SEric Joyner int error, rid, vector = 1; 2333*6c426059SEric Joyner #ifdef RSS 2334*6c426059SEric Joyner cpuset_t cpu_mask; 2335*6c426059SEric Joyner #endif 2336*6c426059SEric Joyner 2337*6c426059SEric Joyner /* Queue interrupt vector numbers start at 1 (adminq intr is 0) */ 233861ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { 2339393c4bb1SJack F Vogel int cpu_id = i; 234061ae650dSJack F Vogel rid = vector + 1; 234161ae650dSJack F Vogel txr = &que->txr; 234261ae650dSJack F Vogel que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 234361ae650dSJack F Vogel RF_SHAREABLE | RF_ACTIVE); 2344*6c426059SEric Joyner if (!que->res) { 2345*6c426059SEric Joyner device_printf(dev, "bus_alloc_resource_any() for" 2346*6c426059SEric Joyner " Queue %d interrupt failed [rid=%d]\n", 2347*6c426059SEric Joyner que->me, rid); 234861ae650dSJack F Vogel return (ENXIO); 234961ae650dSJack F Vogel } 235061ae650dSJack F Vogel /* Set the handler function */ 235161ae650dSJack F Vogel error = bus_setup_intr(dev, que->res, 235261ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 235361ae650dSJack F Vogel ixl_msix_que, que, &que->tag); 235461ae650dSJack F Vogel if (error) { 2355*6c426059SEric Joyner device_printf(dev, "bus_setup_intr() for Queue %d" 2356*6c426059SEric Joyner " interrupt handler failed, error %d\n", 2357*6c426059SEric Joyner que->me, error); 2358*6c426059SEric Joyner // TODO: Check for error from this? 2359*6c426059SEric Joyner bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 236061ae650dSJack F Vogel return (error); 236161ae650dSJack F Vogel } 2362*6c426059SEric Joyner error = bus_describe_intr(dev, que->res, que->tag, "que%d", i); 2363*6c426059SEric Joyner if (error) { 2364*6c426059SEric Joyner device_printf(dev, "bus_describe_intr() for Queue %d" 2365*6c426059SEric Joyner " interrupt name failed, error %d\n", 2366*6c426059SEric Joyner que->me, error); 2367*6c426059SEric Joyner } 236861ae650dSJack F Vogel /* Bind the vector to a CPU */ 2369393c4bb1SJack F Vogel #ifdef RSS 2370393c4bb1SJack F Vogel cpu_id = rss_getcpu(i % rss_getnumbuckets()); 2371393c4bb1SJack F Vogel #endif 2372*6c426059SEric Joyner error = bus_bind_intr(dev, que->res, cpu_id); 2373*6c426059SEric Joyner if (error) { 2374*6c426059SEric Joyner device_printf(dev, "bus_bind_intr() for Queue %d" 2375*6c426059SEric Joyner " to CPU %d failed, error %d\n", 2376*6c426059SEric Joyner que->me, cpu_id, error); 2377*6c426059SEric Joyner } 237861ae650dSJack F Vogel que->msix = vector; 237961ae650dSJack F Vogel } 238061ae650dSJack F Vogel 238161ae650dSJack F Vogel return (0); 238261ae650dSJack F Vogel } 238361ae650dSJack F Vogel 238461ae650dSJack F Vogel 238561ae650dSJack F Vogel /* 238661ae650dSJack F Vogel * Allocate MSI/X vectors 238761ae650dSJack F Vogel */ 238861ae650dSJack F Vogel static int 238961ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf) 239061ae650dSJack F Vogel { 239161ae650dSJack F Vogel device_t dev = pf->dev; 239261ae650dSJack F Vogel int rid, want, vectors, queues, available; 239361ae650dSJack F Vogel 239461ae650dSJack F Vogel /* Override by tuneable */ 239561ae650dSJack F Vogel if (ixl_enable_msix == 0) 23961d767a8eSEric Joyner goto no_msix; 239761ae650dSJack F Vogel 239861ae650dSJack F Vogel /* 239961ae650dSJack F Vogel ** When used in a virtualized environment 240061ae650dSJack F Vogel ** PCI BUSMASTER capability may not be set 240161ae650dSJack F Vogel ** so explicity set it here and rewrite 240261ae650dSJack F Vogel ** the ENABLE in the MSIX control register 240361ae650dSJack F Vogel ** at this point to cause the host to 240461ae650dSJack F Vogel ** successfully initialize us. 240561ae650dSJack F Vogel */ 240661ae650dSJack F Vogel { 240761ae650dSJack F Vogel u16 pci_cmd_word; 240861ae650dSJack F Vogel int msix_ctrl; 240961ae650dSJack F Vogel pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); 241061ae650dSJack F Vogel pci_cmd_word |= PCIM_CMD_BUSMASTEREN; 241161ae650dSJack F Vogel pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); 241261ae650dSJack F Vogel pci_find_cap(dev, PCIY_MSIX, &rid); 241361ae650dSJack F Vogel rid += PCIR_MSIX_CTRL; 241461ae650dSJack F Vogel msix_ctrl = pci_read_config(dev, rid, 2); 241561ae650dSJack F Vogel msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; 241661ae650dSJack F Vogel pci_write_config(dev, rid, msix_ctrl, 2); 241761ae650dSJack F Vogel } 241861ae650dSJack F Vogel 241961ae650dSJack F Vogel /* First try MSI/X */ 242061ae650dSJack F Vogel rid = PCIR_BAR(IXL_BAR); 242161ae650dSJack F Vogel pf->msix_mem = bus_alloc_resource_any(dev, 242261ae650dSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 242361ae650dSJack F Vogel if (!pf->msix_mem) { 242461ae650dSJack F Vogel /* May not be enabled */ 242561ae650dSJack F Vogel device_printf(pf->dev, 242661ae650dSJack F Vogel "Unable to map MSIX table\n"); 24271d767a8eSEric Joyner goto no_msix; 242861ae650dSJack F Vogel } 242961ae650dSJack F Vogel 243061ae650dSJack F Vogel available = pci_msix_count(dev); 243161ae650dSJack F Vogel if (available == 0) { /* system has msix disabled */ 243261ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 243361ae650dSJack F Vogel rid, pf->msix_mem); 243461ae650dSJack F Vogel pf->msix_mem = NULL; 24351d767a8eSEric Joyner goto no_msix; 243661ae650dSJack F Vogel } 243761ae650dSJack F Vogel 243861ae650dSJack F Vogel /* Figure out a reasonable auto config value */ 243961ae650dSJack F Vogel queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus; 244061ae650dSJack F Vogel 24411d767a8eSEric Joyner /* Override with tunable value if tunable is less than autoconfig count */ 244261ae650dSJack F Vogel if ((ixl_max_queues != 0) && (ixl_max_queues <= queues)) 244361ae650dSJack F Vogel queues = ixl_max_queues; 2444a48d00d2SEric Joyner else if ((ixl_max_queues != 0) && (ixl_max_queues > queues)) 2445a48d00d2SEric Joyner device_printf(dev, "ixl_max_queues > # of cpus, using " 2446a48d00d2SEric Joyner "autoconfig amount...\n"); 2447a48d00d2SEric Joyner /* Or limit maximum auto-configured queues to 8 */ 2448a48d00d2SEric Joyner else if ((ixl_max_queues == 0) && (queues > 8)) 2449a48d00d2SEric Joyner queues = 8; 245061ae650dSJack F Vogel 2451393c4bb1SJack F Vogel #ifdef RSS 2452393c4bb1SJack F Vogel /* If we're doing RSS, clamp at the number of RSS buckets */ 2453393c4bb1SJack F Vogel if (queues > rss_getnumbuckets()) 2454393c4bb1SJack F Vogel queues = rss_getnumbuckets(); 2455393c4bb1SJack F Vogel #endif 2456393c4bb1SJack F Vogel 245761ae650dSJack F Vogel /* 245861ae650dSJack F Vogel ** Want one vector (RX/TX pair) per queue 245961ae650dSJack F Vogel ** plus an additional for the admin queue. 246061ae650dSJack F Vogel */ 246161ae650dSJack F Vogel want = queues + 1; 246261ae650dSJack F Vogel if (want <= available) /* Have enough */ 246361ae650dSJack F Vogel vectors = want; 246461ae650dSJack F Vogel else { 246561ae650dSJack F Vogel device_printf(pf->dev, 246661ae650dSJack F Vogel "MSIX Configuration Problem, " 246761ae650dSJack F Vogel "%d vectors available but %d wanted!\n", 246861ae650dSJack F Vogel available, want); 246961ae650dSJack F Vogel return (0); /* Will go to Legacy setup */ 247061ae650dSJack F Vogel } 247161ae650dSJack F Vogel 247261ae650dSJack F Vogel if (pci_alloc_msix(dev, &vectors) == 0) { 247361ae650dSJack F Vogel device_printf(pf->dev, 247461ae650dSJack F Vogel "Using MSIX interrupts with %d vectors\n", vectors); 247561ae650dSJack F Vogel pf->msix = vectors; 247661ae650dSJack F Vogel pf->vsi.num_queues = queues; 2477393c4bb1SJack F Vogel #ifdef RSS 2478393c4bb1SJack F Vogel /* 2479393c4bb1SJack F Vogel * If we're doing RSS, the number of queues needs to 2480393c4bb1SJack F Vogel * match the number of RSS buckets that are configured. 2481393c4bb1SJack F Vogel * 2482393c4bb1SJack F Vogel * + If there's more queues than RSS buckets, we'll end 2483393c4bb1SJack F Vogel * up with queues that get no traffic. 2484393c4bb1SJack F Vogel * 2485393c4bb1SJack F Vogel * + If there's more RSS buckets than queues, we'll end 2486393c4bb1SJack F Vogel * up having multiple RSS buckets map to the same queue, 2487393c4bb1SJack F Vogel * so there'll be some contention. 2488393c4bb1SJack F Vogel */ 2489393c4bb1SJack F Vogel if (queues != rss_getnumbuckets()) { 2490393c4bb1SJack F Vogel device_printf(dev, 2491393c4bb1SJack F Vogel "%s: queues (%d) != RSS buckets (%d)" 2492393c4bb1SJack F Vogel "; performance will be impacted.\n", 2493393c4bb1SJack F Vogel __func__, queues, rss_getnumbuckets()); 2494393c4bb1SJack F Vogel } 2495393c4bb1SJack F Vogel #endif 249661ae650dSJack F Vogel return (vectors); 249761ae650dSJack F Vogel } 24981d767a8eSEric Joyner no_msix: 249961ae650dSJack F Vogel vectors = pci_msi_count(dev); 250061ae650dSJack F Vogel pf->vsi.num_queues = 1; 250161ae650dSJack F Vogel ixl_max_queues = 1; 250261ae650dSJack F Vogel ixl_enable_msix = 0; 250361ae650dSJack F Vogel if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) 250461ae650dSJack F Vogel device_printf(pf->dev, "Using an MSI interrupt\n"); 250561ae650dSJack F Vogel else { 25061d767a8eSEric Joyner vectors = 0; 250761ae650dSJack F Vogel device_printf(pf->dev, "Using a Legacy interrupt\n"); 250861ae650dSJack F Vogel } 250961ae650dSJack F Vogel return (vectors); 251061ae650dSJack F Vogel } 251161ae650dSJack F Vogel 251261ae650dSJack F Vogel /* 2513*6c426059SEric Joyner * Configure admin queue/misc interrupt cause registers in hardware. 251461ae650dSJack F Vogel */ 251561ae650dSJack F Vogel static void 2516*6c426059SEric Joyner ixl_configure_intr0_msix(struct ixl_pf *pf) 251761ae650dSJack F Vogel { 251861ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 251961ae650dSJack F Vogel u32 reg; 252061ae650dSJack F Vogel 252161ae650dSJack F Vogel /* First set up the adminq - vector 0 */ 252261ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, 0); /* disable all */ 252361ae650dSJack F Vogel rd32(hw, I40E_PFINT_ICR0); /* read to clear */ 252461ae650dSJack F Vogel 252561ae650dSJack F Vogel reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | 252661ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_GRST_MASK | 2527fdb6f38aSEric Joyner I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | 252861ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_ADMINQ_MASK | 252961ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK | 253061ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_VFLR_MASK | 253161ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK; 253261ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 253361ae650dSJack F Vogel 2534223d846dSEric Joyner /* 2535223d846dSEric Joyner * 0x7FF is the end of the queue list. 2536223d846dSEric Joyner * This means we won't use MSI-X vector 0 for a queue interrupt 2537223d846dSEric Joyner * in MSIX mode. 2538223d846dSEric Joyner */ 253961ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLST0, 0x7FF); 2540223d846dSEric Joyner /* Value is in 2 usec units, so 0x3E is 62*2 = 124 usecs. */ 2541223d846dSEric Joyner wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x3E); 254261ae650dSJack F Vogel 254361ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, 254461ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK | 254561ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK); 254661ae650dSJack F Vogel 254761ae650dSJack F Vogel wr32(hw, I40E_PFINT_STAT_CTL0, 0); 2548*6c426059SEric Joyner } 254961ae650dSJack F Vogel 2550*6c426059SEric Joyner /* 2551*6c426059SEric Joyner * Configure queue interrupt cause registers in hardware. 2552*6c426059SEric Joyner */ 2553*6c426059SEric Joyner static void 2554*6c426059SEric Joyner ixl_configure_queue_intr_msix(struct ixl_pf *pf) 2555*6c426059SEric Joyner { 2556*6c426059SEric Joyner struct i40e_hw *hw = &pf->hw; 2557*6c426059SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 2558*6c426059SEric Joyner u32 reg; 2559*6c426059SEric Joyner u16 vector = 1; 2560*6c426059SEric Joyner 256161ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, vector++) { 2562ac83ea83SEric Joyner wr32(hw, I40E_PFINT_DYN_CTLN(i), i); 256361ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLSTN(i), i); 256461ae650dSJack F Vogel 256561ae650dSJack F Vogel reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | 256661ae650dSJack F Vogel (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | 256761ae650dSJack F Vogel (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 256861ae650dSJack F Vogel (i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 256961ae650dSJack F Vogel (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); 257061ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(i), reg); 257161ae650dSJack F Vogel 257261ae650dSJack F Vogel reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK | 257361ae650dSJack F Vogel (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | 257461ae650dSJack F Vogel (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | 2575ac83ea83SEric Joyner ((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | 257661ae650dSJack F Vogel (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 2577ac83ea83SEric Joyner if (i == (vsi->num_queues - 1)) 2578ac83ea83SEric Joyner reg |= (IXL_QUEUE_EOL 2579ac83ea83SEric Joyner << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 258061ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(i), reg); 258161ae650dSJack F Vogel } 258261ae650dSJack F Vogel } 258361ae650dSJack F Vogel 258461ae650dSJack F Vogel /* 258561ae650dSJack F Vogel * Configure for MSI single vector operation 258661ae650dSJack F Vogel */ 258761ae650dSJack F Vogel static void 258861ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf) 258961ae650dSJack F Vogel { 259061ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 259161ae650dSJack F Vogel u32 reg; 259261ae650dSJack F Vogel 259361ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(0), 0); 259461ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(1), 0); 259561ae650dSJack F Vogel 259661ae650dSJack F Vogel /* Setup "other" causes */ 259761ae650dSJack F Vogel reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK 259861ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK 259961ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_GRST_MASK 260061ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK 260161ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_GPIO_MASK 260261ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK 260361ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK 260461ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK 260561ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_VFLR_MASK 260661ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_ADMINQ_MASK 260761ae650dSJack F Vogel ; 260861ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 260961ae650dSJack F Vogel 261061ae650dSJack F Vogel /* SW_ITR_IDX = 0, but don't change INTENA */ 261161ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, 261261ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK | 261361ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK); 261461ae650dSJack F Vogel /* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */ 261561ae650dSJack F Vogel wr32(hw, I40E_PFINT_STAT_CTL0, 0); 261661ae650dSJack F Vogel 261761ae650dSJack F Vogel /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ 261861ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLST0, 0); 261961ae650dSJack F Vogel 262061ae650dSJack F Vogel /* Associate the queue pair to the vector and enable the q int */ 262161ae650dSJack F Vogel reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK 262261ae650dSJack F Vogel | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) 262361ae650dSJack F Vogel | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 262461ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(0), reg); 262561ae650dSJack F Vogel 262661ae650dSJack F Vogel reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK 262761ae650dSJack F Vogel | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) 262861ae650dSJack F Vogel | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 262961ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(0), reg); 263061ae650dSJack F Vogel 263161ae650dSJack F Vogel } 263261ae650dSJack F Vogel 263361ae650dSJack F Vogel 263461ae650dSJack F Vogel /* 263561ae650dSJack F Vogel * Set the Initial ITR state 263661ae650dSJack F Vogel */ 263761ae650dSJack F Vogel static void 263861ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf) 263961ae650dSJack F Vogel { 264061ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 264161ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 264261ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 264361ae650dSJack F Vogel 264461ae650dSJack F Vogel vsi->rx_itr_setting = ixl_rx_itr; 264561ae650dSJack F Vogel if (ixl_dynamic_rx_itr) 264661ae650dSJack F Vogel vsi->rx_itr_setting |= IXL_ITR_DYNAMIC; 264761ae650dSJack F Vogel vsi->tx_itr_setting = ixl_tx_itr; 264861ae650dSJack F Vogel if (ixl_dynamic_tx_itr) 264961ae650dSJack F Vogel vsi->tx_itr_setting |= IXL_ITR_DYNAMIC; 265061ae650dSJack F Vogel 265161ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 265261ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 265361ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 265461ae650dSJack F Vogel 265561ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i), 265661ae650dSJack F Vogel vsi->rx_itr_setting); 265761ae650dSJack F Vogel rxr->itr = vsi->rx_itr_setting; 265861ae650dSJack F Vogel rxr->latency = IXL_AVE_LATENCY; 265961ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i), 266061ae650dSJack F Vogel vsi->tx_itr_setting); 266161ae650dSJack F Vogel txr->itr = vsi->tx_itr_setting; 266261ae650dSJack F Vogel txr->latency = IXL_AVE_LATENCY; 266361ae650dSJack F Vogel } 266461ae650dSJack F Vogel } 266561ae650dSJack F Vogel 266661ae650dSJack F Vogel 266761ae650dSJack F Vogel static int 266861ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf) 266961ae650dSJack F Vogel { 267061ae650dSJack F Vogel int rid; 267161ae650dSJack F Vogel device_t dev = pf->dev; 267261ae650dSJack F Vogel 267361ae650dSJack F Vogel rid = PCIR_BAR(0); 267461ae650dSJack F Vogel pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 267561ae650dSJack F Vogel &rid, RF_ACTIVE); 267661ae650dSJack F Vogel 267761ae650dSJack F Vogel if (!(pf->pci_mem)) { 26781d767a8eSEric Joyner device_printf(dev, "Unable to allocate bus resource: PCI memory\n"); 267961ae650dSJack F Vogel return (ENXIO); 268061ae650dSJack F Vogel } 268161ae650dSJack F Vogel 268261ae650dSJack F Vogel pf->osdep.mem_bus_space_tag = 268361ae650dSJack F Vogel rman_get_bustag(pf->pci_mem); 268461ae650dSJack F Vogel pf->osdep.mem_bus_space_handle = 268561ae650dSJack F Vogel rman_get_bushandle(pf->pci_mem); 268661ae650dSJack F Vogel pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); 2687cf3c0c32SRyan Stone pf->osdep.flush_reg = I40E_GLGEN_STAT; 268861ae650dSJack F Vogel pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; 268961ae650dSJack F Vogel 269061ae650dSJack F Vogel pf->hw.back = &pf->osdep; 269161ae650dSJack F Vogel 269261ae650dSJack F Vogel /* 269361ae650dSJack F Vogel ** Now setup MSI or MSI/X, should 269461ae650dSJack F Vogel ** return us the number of supported 269561ae650dSJack F Vogel ** vectors. (Will be 1 for MSI) 269661ae650dSJack F Vogel */ 269761ae650dSJack F Vogel pf->msix = ixl_init_msix(pf); 269861ae650dSJack F Vogel return (0); 269961ae650dSJack F Vogel } 270061ae650dSJack F Vogel 2701*6c426059SEric Joyner /* 2702*6c426059SEric Joyner * Teardown and release the admin queue/misc vector 2703*6c426059SEric Joyner * interrupt. 2704*6c426059SEric Joyner */ 2705*6c426059SEric Joyner static int 2706*6c426059SEric Joyner ixl_teardown_adminq_msix(struct ixl_pf *pf) 270761ae650dSJack F Vogel { 270861ae650dSJack F Vogel device_t dev = pf->dev; 2709223d846dSEric Joyner int rid; 271061ae650dSJack F Vogel 2711*6c426059SEric Joyner if (pf->admvec) /* we are doing MSIX */ 2712*6c426059SEric Joyner rid = pf->admvec + 1; 2713*6c426059SEric Joyner else 2714*6c426059SEric Joyner (pf->msix != 0) ? (rid = 1):(rid = 0); 2715*6c426059SEric Joyner 2716*6c426059SEric Joyner // TODO: Check for errors from bus_teardown_intr 2717*6c426059SEric Joyner // TODO: Check for errors from bus_release_resource 2718*6c426059SEric Joyner if (pf->tag != NULL) { 2719*6c426059SEric Joyner bus_teardown_intr(dev, pf->res, pf->tag); 2720*6c426059SEric Joyner pf->tag = NULL; 2721*6c426059SEric Joyner } 2722*6c426059SEric Joyner if (pf->res != NULL) { 2723*6c426059SEric Joyner bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); 2724*6c426059SEric Joyner pf->res = NULL; 2725*6c426059SEric Joyner } 2726*6c426059SEric Joyner 2727*6c426059SEric Joyner return (0); 2728*6c426059SEric Joyner } 2729*6c426059SEric Joyner 2730*6c426059SEric Joyner static int 2731*6c426059SEric Joyner ixl_teardown_queue_msix(struct ixl_vsi *vsi) 2732*6c426059SEric Joyner { 2733*6c426059SEric Joyner struct ixl_queue *que = vsi->queues; 2734*6c426059SEric Joyner device_t dev = vsi->dev; 2735*6c426059SEric Joyner int rid; 2736*6c426059SEric Joyner 273761ae650dSJack F Vogel /* We may get here before stations are setup */ 273861ae650dSJack F Vogel if ((!ixl_enable_msix) || (que == NULL)) 2739*6c426059SEric Joyner return (0); 274061ae650dSJack F Vogel 2741*6c426059SEric Joyner /* Release all MSIX queue resources */ 2742*6c426059SEric Joyner // TODO: Check for errors from bus_teardown_intr 2743*6c426059SEric Joyner // TODO: Check for errors from bus_release_resource 274461ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 274561ae650dSJack F Vogel rid = que->msix + 1; 274661ae650dSJack F Vogel if (que->tag != NULL) { 274761ae650dSJack F Vogel bus_teardown_intr(dev, que->res, que->tag); 274861ae650dSJack F Vogel que->tag = NULL; 274961ae650dSJack F Vogel } 2750223d846dSEric Joyner if (que->res != NULL) { 275161ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2752223d846dSEric Joyner que->res = NULL; 2753223d846dSEric Joyner } 275461ae650dSJack F Vogel } 275561ae650dSJack F Vogel 2756*6c426059SEric Joyner return (0); 2757223d846dSEric Joyner } 2758223d846dSEric Joyner 2759223d846dSEric Joyner static void 2760223d846dSEric Joyner ixl_free_pci_resources(struct ixl_pf *pf) 2761223d846dSEric Joyner { 2762223d846dSEric Joyner device_t dev = pf->dev; 2763223d846dSEric Joyner int memrid; 2764223d846dSEric Joyner 2765*6c426059SEric Joyner ixl_teardown_queue_msix(&pf->vsi); 2766*6c426059SEric Joyner ixl_teardown_adminq_msix(pf); 276761ae650dSJack F Vogel 276861ae650dSJack F Vogel if (pf->msix) 276961ae650dSJack F Vogel pci_release_msi(dev); 277061ae650dSJack F Vogel 2771223d846dSEric Joyner memrid = PCIR_BAR(IXL_BAR); 2772223d846dSEric Joyner 277361ae650dSJack F Vogel if (pf->msix_mem != NULL) 277461ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 277561ae650dSJack F Vogel memrid, pf->msix_mem); 277661ae650dSJack F Vogel 277761ae650dSJack F Vogel if (pf->pci_mem != NULL) 277861ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 277961ae650dSJack F Vogel PCIR_BAR(0), pf->pci_mem); 278061ae650dSJack F Vogel 278161ae650dSJack F Vogel return; 278261ae650dSJack F Vogel } 278361ae650dSJack F Vogel 2784e5100ee2SJack F Vogel static void 2785e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type) 2786e5100ee2SJack F Vogel { 2787e5100ee2SJack F Vogel /* Display supported media types */ 2788e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX)) 2789e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2790e5100ee2SJack F Vogel 2791e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T)) 2792e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); 279356c2c47bSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_SX)) 279456c2c47bSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 279556c2c47bSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_LX)) 279656c2c47bSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL); 2797e5100ee2SJack F Vogel 2798be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_XAUI) || 2799b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XFI) || 2800e5100ee2SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU)) 2801e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2802b6c8f260SJack F Vogel 2803e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR)) 2804e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2805e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR)) 2806e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2807e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T)) 2808e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2809e5100ee2SJack F Vogel 2810b6c8f260SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) || 2811b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) || 2812b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) || 2813b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XLAUI) || 2814b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2815e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2816e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4)) 2817e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2818e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4)) 2819e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); 2820be771cdaSJack F Vogel 2821be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE 2822be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX)) 2823be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_CX, 0, NULL); 2824be771cdaSJack F Vogel 2825be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) || 2826be771cdaSJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1) || 2827be771cdaSJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) || 2828be771cdaSJack F Vogel phy_type & (1 << I40E_PHY_TYPE_SFI)) 2829be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2830be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4)) 2831be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2832be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR)) 2833be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2834be771cdaSJack F Vogel 2835be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2836be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2837be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_XLPPI)) 2838be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2839be771cdaSJack F Vogel #else 2840be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX)) 2841be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL); 2842be771cdaSJack F Vogel 2843be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) 2844be771cdaSJack F Vogel || phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1)) 2845be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL); 2846be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC)) 2847be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL); 2848be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_SFI)) 2849be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL); 2850be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4)) 2851be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); 2852be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR)) 2853be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL); 2854be771cdaSJack F Vogel 2855be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_20GBASE_KR2)) 2856be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL); 2857be771cdaSJack F Vogel 2858be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2859be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL); 2860be771cdaSJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_XLPPI)) 2861be771cdaSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL); 2862be771cdaSJack F Vogel #endif 2863e5100ee2SJack F Vogel } 286461ae650dSJack F Vogel 286561ae650dSJack F Vogel /********************************************************************* 286661ae650dSJack F Vogel * 286761ae650dSJack F Vogel * Setup networking device structure and register an interface. 286861ae650dSJack F Vogel * 286961ae650dSJack F Vogel **********************************************************************/ 287061ae650dSJack F Vogel static int 287161ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi) 287261ae650dSJack F Vogel { 287361ae650dSJack F Vogel struct ifnet *ifp; 287461ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 287561ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 2876b6c8f260SJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 287761ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 287861ae650dSJack F Vogel 287961ae650dSJack F Vogel INIT_DEBUGOUT("ixl_setup_interface: begin"); 288061ae650dSJack F Vogel 288161ae650dSJack F Vogel ifp = vsi->ifp = if_alloc(IFT_ETHER); 288261ae650dSJack F Vogel if (ifp == NULL) { 288361ae650dSJack F Vogel device_printf(dev, "can not allocate ifnet structure\n"); 288461ae650dSJack F Vogel return (-1); 288561ae650dSJack F Vogel } 288661ae650dSJack F Vogel if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 288761ae650dSJack F Vogel ifp->if_mtu = ETHERMTU; 2888a48d00d2SEric Joyner ifp->if_baudrate = IF_Gbps(40); 288961ae650dSJack F Vogel ifp->if_init = ixl_init; 289061ae650dSJack F Vogel ifp->if_softc = vsi; 289161ae650dSJack F Vogel ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 289261ae650dSJack F Vogel ifp->if_ioctl = ixl_ioctl; 289361ae650dSJack F Vogel 2894e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036 28954b443922SGleb Smirnoff if_setgetcounterfn(ifp, ixl_get_counter); 28964b443922SGleb Smirnoff #endif 28974b443922SGleb Smirnoff 289861ae650dSJack F Vogel ifp->if_transmit = ixl_mq_start; 289961ae650dSJack F Vogel 290061ae650dSJack F Vogel ifp->if_qflush = ixl_qflush; 290161ae650dSJack F Vogel 290261ae650dSJack F Vogel ifp->if_snd.ifq_maxlen = que->num_desc - 2; 290361ae650dSJack F Vogel 290461ae650dSJack F Vogel vsi->max_frame_size = 290561ae650dSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 290661ae650dSJack F Vogel + ETHER_VLAN_ENCAP_LEN; 290761ae650dSJack F Vogel 290861ae650dSJack F Vogel /* 290961ae650dSJack F Vogel * Tell the upper layer(s) we support long frames. 291061ae650dSJack F Vogel */ 29111bffa951SGleb Smirnoff ifp->if_hdrlen = sizeof(struct ether_vlan_header); 291261ae650dSJack F Vogel 291361ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM; 291461ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; 291561ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_TSO; 291661ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_JUMBO_MTU; 291761ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_LRO; 291861ae650dSJack F Vogel 291961ae650dSJack F Vogel /* VLAN capabilties */ 292061ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 292161ae650dSJack F Vogel | IFCAP_VLAN_HWTSO 292261ae650dSJack F Vogel | IFCAP_VLAN_MTU 292361ae650dSJack F Vogel | IFCAP_VLAN_HWCSUM; 292461ae650dSJack F Vogel ifp->if_capenable = ifp->if_capabilities; 292561ae650dSJack F Vogel 292661ae650dSJack F Vogel /* 292761ae650dSJack F Vogel ** Don't turn this on by default, if vlans are 292861ae650dSJack F Vogel ** created on another pseudo device (eg. lagg) 292961ae650dSJack F Vogel ** then vlan events are not passed thru, breaking 293061ae650dSJack F Vogel ** operation, but with HW FILTER off it works. If 293161ae650dSJack F Vogel ** using vlans directly on the ixl driver you can 293261ae650dSJack F Vogel ** enable this and get full hardware tag filtering. 293361ae650dSJack F Vogel */ 293461ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 293561ae650dSJack F Vogel 293661ae650dSJack F Vogel /* 293761ae650dSJack F Vogel * Specify the media types supported by this adapter and register 293861ae650dSJack F Vogel * callbacks to update media and link information 293961ae650dSJack F Vogel */ 294061ae650dSJack F Vogel ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change, 294161ae650dSJack F Vogel ixl_media_status); 294261ae650dSJack F Vogel 2943b6c8f260SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 2944b6c8f260SJack F Vogel FALSE, TRUE, &abilities, NULL); 2945b6c8f260SJack F Vogel /* May need delay to detect fiber correctly */ 2946e5100ee2SJack F Vogel if (aq_error == I40E_ERR_UNKNOWN_PHY) { 2947e5100ee2SJack F Vogel i40e_msec_delay(200); 2948393c4bb1SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, 2949b6c8f260SJack F Vogel TRUE, &abilities, NULL); 2950b6c8f260SJack F Vogel } 2951b6c8f260SJack F Vogel if (aq_error) { 2952e5100ee2SJack F Vogel if (aq_error == I40E_ERR_UNKNOWN_PHY) 2953e5100ee2SJack F Vogel device_printf(dev, "Unknown PHY type detected!\n"); 2954e5100ee2SJack F Vogel else 2955b6c8f260SJack F Vogel device_printf(dev, 2956b6c8f260SJack F Vogel "Error getting supported media types, err %d," 2957e5100ee2SJack F Vogel " AQ error %d\n", aq_error, hw->aq.asq_last_status); 2958b6c8f260SJack F Vogel return (0); 2959b6c8f260SJack F Vogel } 2960b6c8f260SJack F Vogel 2961b6c8f260SJack F Vogel ixl_add_ifmedia(vsi, abilities.phy_type); 296261ae650dSJack F Vogel 296361ae650dSJack F Vogel /* Use autoselect media by default */ 296461ae650dSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); 296561ae650dSJack F Vogel ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); 296661ae650dSJack F Vogel 2967e5100ee2SJack F Vogel ether_ifattach(ifp, hw->mac.addr); 2968e5100ee2SJack F Vogel 296961ae650dSJack F Vogel return (0); 297061ae650dSJack F Vogel } 297161ae650dSJack F Vogel 297256c2c47bSJack F Vogel /* 2973223d846dSEric Joyner ** Run when the Admin Queue gets a link state change interrupt. 297456c2c47bSJack F Vogel */ 297556c2c47bSJack F Vogel static void 297656c2c47bSJack F Vogel ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e) 297761ae650dSJack F Vogel { 297856c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 2979223d846dSEric Joyner device_t dev = pf->dev; 298056c2c47bSJack F Vogel struct i40e_aqc_get_link_status *status = 298156c2c47bSJack F Vogel (struct i40e_aqc_get_link_status *)&e->desc.params.raw; 298261ae650dSJack F Vogel 2983223d846dSEric Joyner /* Request link status from adapter */ 298456c2c47bSJack F Vogel hw->phy.get_link_info = TRUE; 2985223d846dSEric Joyner i40e_get_link_status(hw, &pf->link_up); 2986223d846dSEric Joyner 2987223d846dSEric Joyner /* Print out message if an unqualified module is found */ 298856c2c47bSJack F Vogel if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) && 298956c2c47bSJack F Vogel (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) && 299056c2c47bSJack F Vogel (!(status->link_info & I40E_AQ_LINK_UP))) 2991223d846dSEric Joyner device_printf(dev, "Link failed because " 2992223d846dSEric Joyner "an unqualified module was detected!\n"); 299356c2c47bSJack F Vogel 2994223d846dSEric Joyner /* Update OS link info */ 2995223d846dSEric Joyner ixl_update_link_status(pf); 299661ae650dSJack F Vogel } 299761ae650dSJack F Vogel 299861ae650dSJack F Vogel /********************************************************************* 299961ae650dSJack F Vogel * 3000b6c8f260SJack F Vogel * Get Firmware Switch configuration 3001b6c8f260SJack F Vogel * - this will need to be more robust when more complex 3002b6c8f260SJack F Vogel * switch configurations are enabled. 300361ae650dSJack F Vogel * 300461ae650dSJack F Vogel **********************************************************************/ 300561ae650dSJack F Vogel static int 3006b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf) 300761ae650dSJack F Vogel { 3008b6c8f260SJack F Vogel struct i40e_hw *hw = &pf->hw; 3009b6c8f260SJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 301061ae650dSJack F Vogel device_t dev = vsi->dev; 301161ae650dSJack F Vogel struct i40e_aqc_get_switch_config_resp *sw_config; 301261ae650dSJack F Vogel u8 aq_buf[I40E_AQ_LARGE_BUF]; 301356c2c47bSJack F Vogel int ret; 301461ae650dSJack F Vogel u16 next = 0; 301561ae650dSJack F Vogel 3016b6c8f260SJack F Vogel memset(&aq_buf, 0, sizeof(aq_buf)); 301761ae650dSJack F Vogel sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 301861ae650dSJack F Vogel ret = i40e_aq_get_switch_config(hw, sw_config, 301961ae650dSJack F Vogel sizeof(aq_buf), &next, NULL); 302061ae650dSJack F Vogel if (ret) { 302156c2c47bSJack F Vogel device_printf(dev,"aq_get_switch_config failed (ret=%d)!!\n", 302256c2c47bSJack F Vogel ret); 302361ae650dSJack F Vogel return (ret); 302461ae650dSJack F Vogel } 302561ae650dSJack F Vogel #ifdef IXL_DEBUG 302656c2c47bSJack F Vogel device_printf(dev, 302756c2c47bSJack F Vogel "Switch config: header reported: %d in structure, %d total\n", 302861ae650dSJack F Vogel sw_config->header.num_reported, sw_config->header.num_total); 302956c2c47bSJack F Vogel for (int i = 0; i < sw_config->header.num_reported; i++) { 303056c2c47bSJack F Vogel device_printf(dev, 303156c2c47bSJack F Vogel "%d: type=%d seid=%d uplink=%d downlink=%d\n", i, 303256c2c47bSJack F Vogel sw_config->element[i].element_type, 303356c2c47bSJack F Vogel sw_config->element[i].seid, 303456c2c47bSJack F Vogel sw_config->element[i].uplink_seid, 303556c2c47bSJack F Vogel sw_config->element[i].downlink_seid); 303656c2c47bSJack F Vogel } 303761ae650dSJack F Vogel #endif 3038b6c8f260SJack F Vogel /* Simplified due to a single VSI at the moment */ 303956c2c47bSJack F Vogel vsi->uplink_seid = sw_config->element[0].uplink_seid; 304056c2c47bSJack F Vogel vsi->downlink_seid = sw_config->element[0].downlink_seid; 304161ae650dSJack F Vogel vsi->seid = sw_config->element[0].seid; 3042b6c8f260SJack F Vogel return (ret); 3043b6c8f260SJack F Vogel } 3044b6c8f260SJack F Vogel 3045b6c8f260SJack F Vogel /********************************************************************* 3046b6c8f260SJack F Vogel * 3047b6c8f260SJack F Vogel * Initialize the VSI: this handles contexts, which means things 3048b6c8f260SJack F Vogel * like the number of descriptors, buffer size, 3049b6c8f260SJack F Vogel * plus we init the rings thru this function. 3050b6c8f260SJack F Vogel * 3051b6c8f260SJack F Vogel **********************************************************************/ 3052b6c8f260SJack F Vogel static int 3053b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi) 3054b6c8f260SJack F Vogel { 305556c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 3056b6c8f260SJack F Vogel struct ixl_queue *que = vsi->queues; 3057b6c8f260SJack F Vogel device_t dev = vsi->dev; 3058b6c8f260SJack F Vogel struct i40e_hw *hw = vsi->hw; 3059b6c8f260SJack F Vogel struct i40e_vsi_context ctxt; 3060b6c8f260SJack F Vogel int err = 0; 306161ae650dSJack F Vogel 306261ae650dSJack F Vogel memset(&ctxt, 0, sizeof(ctxt)); 306361ae650dSJack F Vogel ctxt.seid = vsi->seid; 306456c2c47bSJack F Vogel if (pf->veb_seid != 0) 306556c2c47bSJack F Vogel ctxt.uplink_seid = pf->veb_seid; 306661ae650dSJack F Vogel ctxt.pf_num = hw->pf_id; 3067b6c8f260SJack F Vogel err = i40e_aq_get_vsi_params(hw, &ctxt, NULL); 3068b6c8f260SJack F Vogel if (err) { 30697f70bec6SEric Joyner device_printf(dev, "i40e_aq_get_vsi_params() failed, error %d\n", err); 3070b6c8f260SJack F Vogel return (err); 307161ae650dSJack F Vogel } 307261ae650dSJack F Vogel #ifdef IXL_DEBUG 30737f70bec6SEric Joyner device_printf(dev, "get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, " 307461ae650dSJack F Vogel "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, " 307561ae650dSJack F Vogel "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid, 307661ae650dSJack F Vogel ctxt.uplink_seid, ctxt.vsi_number, 307761ae650dSJack F Vogel ctxt.vsis_allocated, ctxt.vsis_unallocated, 307861ae650dSJack F Vogel ctxt.flags, ctxt.pf_num, ctxt.vf_num, 307961ae650dSJack F Vogel ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits); 308061ae650dSJack F Vogel #endif 308161ae650dSJack F Vogel /* 308261ae650dSJack F Vogel ** Set the queue and traffic class bits 308361ae650dSJack F Vogel ** - when multiple traffic classes are supported 308461ae650dSJack F Vogel ** this will need to be more robust. 308561ae650dSJack F Vogel */ 308661ae650dSJack F Vogel ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID; 308761ae650dSJack F Vogel ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG; 308861ae650dSJack F Vogel ctxt.info.queue_mapping[0] = 0; 30891d767a8eSEric Joyner /* This VSI is assigned 64 queues (we may not use all of them) */ 30907f70bec6SEric Joyner ctxt.info.tc_mapping[0] = 0x0c00; 309161ae650dSJack F Vogel 309261ae650dSJack F Vogel /* Set VLAN receive stripping mode */ 309361ae650dSJack F Vogel ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; 309461ae650dSJack F Vogel ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; 309561ae650dSJack F Vogel if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 309661ae650dSJack F Vogel ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 309761ae650dSJack F Vogel else 309861ae650dSJack F Vogel ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 309961ae650dSJack F Vogel 310061ae650dSJack F Vogel /* Keep copy of VSI info in VSI for statistic counters */ 310161ae650dSJack F Vogel memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); 310261ae650dSJack F Vogel 310361ae650dSJack F Vogel /* Reset VSI statistics */ 310461ae650dSJack F Vogel ixl_vsi_reset_stats(vsi); 310561ae650dSJack F Vogel vsi->hw_filters_add = 0; 310661ae650dSJack F Vogel vsi->hw_filters_del = 0; 310761ae650dSJack F Vogel 310856c2c47bSJack F Vogel ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF); 310956c2c47bSJack F Vogel 3110b6c8f260SJack F Vogel err = i40e_aq_update_vsi_params(hw, &ctxt, NULL); 3111b6c8f260SJack F Vogel if (err) { 31127f70bec6SEric Joyner device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d, aq_error %d\n", 31137f70bec6SEric Joyner err, hw->aq.asq_last_status); 3114b6c8f260SJack F Vogel return (err); 311561ae650dSJack F Vogel } 311661ae650dSJack F Vogel 311761ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 311861ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 311961ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 312061ae650dSJack F Vogel struct i40e_hmc_obj_txq tctx; 312161ae650dSJack F Vogel struct i40e_hmc_obj_rxq rctx; 312261ae650dSJack F Vogel u32 txctl; 312361ae650dSJack F Vogel u16 size; 312461ae650dSJack F Vogel 312561ae650dSJack F Vogel /* Setup the HMC TX Context */ 312661ae650dSJack F Vogel size = que->num_desc * sizeof(struct i40e_tx_desc); 312761ae650dSJack F Vogel memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq)); 312861ae650dSJack F Vogel tctx.new_context = 1; 312956c2c47bSJack F Vogel tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS); 313061ae650dSJack F Vogel tctx.qlen = que->num_desc; 313161ae650dSJack F Vogel tctx.fc_ena = 0; 313261ae650dSJack F Vogel tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */ 313361ae650dSJack F Vogel /* Enable HEAD writeback */ 313461ae650dSJack F Vogel tctx.head_wb_ena = 1; 313561ae650dSJack F Vogel tctx.head_wb_addr = txr->dma.pa + 313661ae650dSJack F Vogel (que->num_desc * sizeof(struct i40e_tx_desc)); 313761ae650dSJack F Vogel tctx.rdylist_act = 0; 313861ae650dSJack F Vogel err = i40e_clear_lan_tx_queue_context(hw, i); 313961ae650dSJack F Vogel if (err) { 314061ae650dSJack F Vogel device_printf(dev, "Unable to clear TX context\n"); 314161ae650dSJack F Vogel break; 314261ae650dSJack F Vogel } 314361ae650dSJack F Vogel err = i40e_set_lan_tx_queue_context(hw, i, &tctx); 314461ae650dSJack F Vogel if (err) { 314561ae650dSJack F Vogel device_printf(dev, "Unable to set TX context\n"); 314661ae650dSJack F Vogel break; 314761ae650dSJack F Vogel } 314861ae650dSJack F Vogel /* Associate the ring with this PF */ 314961ae650dSJack F Vogel txctl = I40E_QTX_CTL_PF_QUEUE; 315061ae650dSJack F Vogel txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & 315161ae650dSJack F Vogel I40E_QTX_CTL_PF_INDX_MASK); 315261ae650dSJack F Vogel wr32(hw, I40E_QTX_CTL(i), txctl); 315361ae650dSJack F Vogel ixl_flush(hw); 315461ae650dSJack F Vogel 315561ae650dSJack F Vogel /* Do ring (re)init */ 315661ae650dSJack F Vogel ixl_init_tx_ring(que); 315761ae650dSJack F Vogel 315861ae650dSJack F Vogel /* Next setup the HMC RX Context */ 315956c2c47bSJack F Vogel if (vsi->max_frame_size <= MCLBYTES) 316061ae650dSJack F Vogel rxr->mbuf_sz = MCLBYTES; 316161ae650dSJack F Vogel else 316261ae650dSJack F Vogel rxr->mbuf_sz = MJUMPAGESIZE; 316361ae650dSJack F Vogel 316461ae650dSJack F Vogel u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len; 316561ae650dSJack F Vogel 316661ae650dSJack F Vogel /* Set up an RX context for the HMC */ 316761ae650dSJack F Vogel memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq)); 316861ae650dSJack F Vogel rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT; 316961ae650dSJack F Vogel /* ignore header split for now */ 317061ae650dSJack F Vogel rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; 317161ae650dSJack F Vogel rctx.rxmax = (vsi->max_frame_size < max_rxmax) ? 317261ae650dSJack F Vogel vsi->max_frame_size : max_rxmax; 317361ae650dSJack F Vogel rctx.dtype = 0; 317461ae650dSJack F Vogel rctx.dsize = 1; /* do 32byte descriptors */ 317561ae650dSJack F Vogel rctx.hsplit_0 = 0; /* no HDR split initially */ 317656c2c47bSJack F Vogel rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS); 317761ae650dSJack F Vogel rctx.qlen = que->num_desc; 317861ae650dSJack F Vogel rctx.tphrdesc_ena = 1; 317961ae650dSJack F Vogel rctx.tphwdesc_ena = 1; 318061ae650dSJack F Vogel rctx.tphdata_ena = 0; 318161ae650dSJack F Vogel rctx.tphhead_ena = 0; 318261ae650dSJack F Vogel rctx.lrxqthresh = 2; 318361ae650dSJack F Vogel rctx.crcstrip = 1; 318461ae650dSJack F Vogel rctx.l2tsel = 1; 318561ae650dSJack F Vogel rctx.showiv = 1; 318661ae650dSJack F Vogel rctx.fc_ena = 0; 318761ae650dSJack F Vogel rctx.prefena = 1; 318861ae650dSJack F Vogel 318961ae650dSJack F Vogel err = i40e_clear_lan_rx_queue_context(hw, i); 319061ae650dSJack F Vogel if (err) { 319161ae650dSJack F Vogel device_printf(dev, 319261ae650dSJack F Vogel "Unable to clear RX context %d\n", i); 319361ae650dSJack F Vogel break; 319461ae650dSJack F Vogel } 319561ae650dSJack F Vogel err = i40e_set_lan_rx_queue_context(hw, i, &rctx); 319661ae650dSJack F Vogel if (err) { 319761ae650dSJack F Vogel device_printf(dev, "Unable to set RX context %d\n", i); 319861ae650dSJack F Vogel break; 319961ae650dSJack F Vogel } 320061ae650dSJack F Vogel err = ixl_init_rx_ring(que); 320161ae650dSJack F Vogel if (err) { 320261ae650dSJack F Vogel device_printf(dev, "Fail in init_rx_ring %d\n", i); 320361ae650dSJack F Vogel break; 320461ae650dSJack F Vogel } 3205ac83ea83SEric Joyner wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0); 320631830672SJack F Vogel #ifdef DEV_NETMAP 320731830672SJack F Vogel /* preserve queue */ 320831830672SJack F Vogel if (vsi->ifp->if_capenable & IFCAP_NETMAP) { 320931830672SJack F Vogel struct netmap_adapter *na = NA(vsi->ifp); 321031830672SJack F Vogel struct netmap_kring *kring = &na->rx_rings[i]; 321131830672SJack F Vogel int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); 321231830672SJack F Vogel wr32(vsi->hw, I40E_QRX_TAIL(que->me), t); 321331830672SJack F Vogel } else 321431830672SJack F Vogel #endif /* DEV_NETMAP */ 321561ae650dSJack F Vogel wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1); 321661ae650dSJack F Vogel } 321761ae650dSJack F Vogel return (err); 321861ae650dSJack F Vogel } 321961ae650dSJack F Vogel 322061ae650dSJack F Vogel 322161ae650dSJack F Vogel /********************************************************************* 322261ae650dSJack F Vogel * 322361ae650dSJack F Vogel * Free all VSI structs. 322461ae650dSJack F Vogel * 322561ae650dSJack F Vogel **********************************************************************/ 322661ae650dSJack F Vogel void 322761ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi) 322861ae650dSJack F Vogel { 322961ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 323061ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 323161ae650dSJack F Vogel 323261ae650dSJack F Vogel /* Free station queues */ 3233fdb6f38aSEric Joyner if (!vsi->queues) 3234fdb6f38aSEric Joyner goto free_filters; 3235fdb6f38aSEric Joyner 323661ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 323761ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 323861ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 323961ae650dSJack F Vogel 324061ae650dSJack F Vogel if (!mtx_initialized(&txr->mtx)) /* uninitialized */ 324161ae650dSJack F Vogel continue; 324261ae650dSJack F Vogel IXL_TX_LOCK(txr); 324361ae650dSJack F Vogel ixl_free_que_tx(que); 324461ae650dSJack F Vogel if (txr->base) 3245d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &txr->dma); 324661ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 324761ae650dSJack F Vogel IXL_TX_LOCK_DESTROY(txr); 324861ae650dSJack F Vogel 324961ae650dSJack F Vogel if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ 325061ae650dSJack F Vogel continue; 325161ae650dSJack F Vogel IXL_RX_LOCK(rxr); 325261ae650dSJack F Vogel ixl_free_que_rx(que); 325361ae650dSJack F Vogel if (rxr->base) 3254d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &rxr->dma); 325561ae650dSJack F Vogel IXL_RX_UNLOCK(rxr); 325661ae650dSJack F Vogel IXL_RX_LOCK_DESTROY(rxr); 325761ae650dSJack F Vogel 325861ae650dSJack F Vogel } 325961ae650dSJack F Vogel free(vsi->queues, M_DEVBUF); 326061ae650dSJack F Vogel 3261fdb6f38aSEric Joyner free_filters: 326261ae650dSJack F Vogel /* Free VSI filter list */ 326356c2c47bSJack F Vogel ixl_free_mac_filters(vsi); 326456c2c47bSJack F Vogel } 326556c2c47bSJack F Vogel 326656c2c47bSJack F Vogel static void 326756c2c47bSJack F Vogel ixl_free_mac_filters(struct ixl_vsi *vsi) 326856c2c47bSJack F Vogel { 326956c2c47bSJack F Vogel struct ixl_mac_filter *f; 327056c2c47bSJack F Vogel 327161ae650dSJack F Vogel while (!SLIST_EMPTY(&vsi->ftl)) { 327261ae650dSJack F Vogel f = SLIST_FIRST(&vsi->ftl); 327361ae650dSJack F Vogel SLIST_REMOVE_HEAD(&vsi->ftl, next); 327461ae650dSJack F Vogel free(f, M_DEVBUF); 327561ae650dSJack F Vogel } 327661ae650dSJack F Vogel } 327761ae650dSJack F Vogel 327861ae650dSJack F Vogel 327961ae650dSJack F Vogel /********************************************************************* 328061ae650dSJack F Vogel * 328161ae650dSJack F Vogel * Allocate memory for the VSI (virtual station interface) and their 328261ae650dSJack F Vogel * associated queues, rings and the descriptors associated with each, 328361ae650dSJack F Vogel * called only once at attach. 328461ae650dSJack F Vogel * 328561ae650dSJack F Vogel **********************************************************************/ 328661ae650dSJack F Vogel static int 328761ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf) 328861ae650dSJack F Vogel { 328961ae650dSJack F Vogel device_t dev = pf->dev; 329061ae650dSJack F Vogel struct ixl_vsi *vsi; 329161ae650dSJack F Vogel struct ixl_queue *que; 329261ae650dSJack F Vogel struct tx_ring *txr; 329361ae650dSJack F Vogel struct rx_ring *rxr; 329461ae650dSJack F Vogel int rsize, tsize; 329561ae650dSJack F Vogel int error = I40E_SUCCESS; 329661ae650dSJack F Vogel 329761ae650dSJack F Vogel vsi = &pf->vsi; 329861ae650dSJack F Vogel vsi->back = (void *)pf; 329961ae650dSJack F Vogel vsi->hw = &pf->hw; 330061ae650dSJack F Vogel vsi->id = 0; 330161ae650dSJack F Vogel vsi->num_vlans = 0; 330256c2c47bSJack F Vogel vsi->back = pf; 330361ae650dSJack F Vogel 330461ae650dSJack F Vogel /* Get memory for the station queues */ 330561ae650dSJack F Vogel if (!(vsi->queues = 330661ae650dSJack F Vogel (struct ixl_queue *) malloc(sizeof(struct ixl_queue) * 330761ae650dSJack F Vogel vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { 330861ae650dSJack F Vogel device_printf(dev, "Unable to allocate queue memory\n"); 330961ae650dSJack F Vogel error = ENOMEM; 331061ae650dSJack F Vogel goto early; 331161ae650dSJack F Vogel } 331261ae650dSJack F Vogel 331361ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 331461ae650dSJack F Vogel que = &vsi->queues[i]; 331561ae650dSJack F Vogel que->num_desc = ixl_ringsz; 331661ae650dSJack F Vogel que->me = i; 331761ae650dSJack F Vogel que->vsi = vsi; 331861ae650dSJack F Vogel /* mark the queue as active */ 331961ae650dSJack F Vogel vsi->active_queues |= (u64)1 << que->me; 332061ae650dSJack F Vogel txr = &que->txr; 332161ae650dSJack F Vogel txr->que = que; 332261ae650dSJack F Vogel txr->tail = I40E_QTX_TAIL(que->me); 332361ae650dSJack F Vogel 332461ae650dSJack F Vogel /* Initialize the TX lock */ 332561ae650dSJack F Vogel snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", 332661ae650dSJack F Vogel device_get_nameunit(dev), que->me); 332761ae650dSJack F Vogel mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF); 332861ae650dSJack F Vogel /* Create the TX descriptor ring */ 332961ae650dSJack F Vogel tsize = roundup2((que->num_desc * 333061ae650dSJack F Vogel sizeof(struct i40e_tx_desc)) + 333161ae650dSJack F Vogel sizeof(u32), DBA_ALIGN); 3332d94ca7cfSBjoern A. Zeeb if (i40e_allocate_dma_mem(&pf->hw, 3333d94ca7cfSBjoern A. Zeeb &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) { 333461ae650dSJack F Vogel device_printf(dev, 333561ae650dSJack F Vogel "Unable to allocate TX Descriptor memory\n"); 333661ae650dSJack F Vogel error = ENOMEM; 333761ae650dSJack F Vogel goto fail; 333861ae650dSJack F Vogel } 333961ae650dSJack F Vogel txr->base = (struct i40e_tx_desc *)txr->dma.va; 334061ae650dSJack F Vogel bzero((void *)txr->base, tsize); 334161ae650dSJack F Vogel /* Now allocate transmit soft structs for the ring */ 334261ae650dSJack F Vogel if (ixl_allocate_tx_data(que)) { 334361ae650dSJack F Vogel device_printf(dev, 334461ae650dSJack F Vogel "Critical Failure setting up TX structures\n"); 334561ae650dSJack F Vogel error = ENOMEM; 334661ae650dSJack F Vogel goto fail; 334761ae650dSJack F Vogel } 334861ae650dSJack F Vogel /* Allocate a buf ring */ 334961ae650dSJack F Vogel txr->br = buf_ring_alloc(4096, M_DEVBUF, 3350223d846dSEric Joyner M_NOWAIT, &txr->mtx); 335161ae650dSJack F Vogel if (txr->br == NULL) { 335261ae650dSJack F Vogel device_printf(dev, 335361ae650dSJack F Vogel "Critical Failure setting up TX buf ring\n"); 335461ae650dSJack F Vogel error = ENOMEM; 335561ae650dSJack F Vogel goto fail; 335661ae650dSJack F Vogel } 335761ae650dSJack F Vogel 335861ae650dSJack F Vogel /* 335961ae650dSJack F Vogel * Next the RX queues... 336061ae650dSJack F Vogel */ 336161ae650dSJack F Vogel rsize = roundup2(que->num_desc * 336261ae650dSJack F Vogel sizeof(union i40e_rx_desc), DBA_ALIGN); 336361ae650dSJack F Vogel rxr = &que->rxr; 336461ae650dSJack F Vogel rxr->que = que; 336561ae650dSJack F Vogel rxr->tail = I40E_QRX_TAIL(que->me); 336661ae650dSJack F Vogel 336761ae650dSJack F Vogel /* Initialize the RX side lock */ 336861ae650dSJack F Vogel snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", 336961ae650dSJack F Vogel device_get_nameunit(dev), que->me); 337061ae650dSJack F Vogel mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF); 337161ae650dSJack F Vogel 3372d94ca7cfSBjoern A. Zeeb if (i40e_allocate_dma_mem(&pf->hw, 3373d94ca7cfSBjoern A. Zeeb &rxr->dma, i40e_mem_reserved, rsize, 4096)) { 337461ae650dSJack F Vogel device_printf(dev, 337561ae650dSJack F Vogel "Unable to allocate RX Descriptor memory\n"); 337661ae650dSJack F Vogel error = ENOMEM; 337761ae650dSJack F Vogel goto fail; 337861ae650dSJack F Vogel } 337961ae650dSJack F Vogel rxr->base = (union i40e_rx_desc *)rxr->dma.va; 338061ae650dSJack F Vogel bzero((void *)rxr->base, rsize); 338161ae650dSJack F Vogel 338261ae650dSJack F Vogel /* Allocate receive soft structs for the ring*/ 338361ae650dSJack F Vogel if (ixl_allocate_rx_data(que)) { 338461ae650dSJack F Vogel device_printf(dev, 338561ae650dSJack F Vogel "Critical Failure setting up receive structs\n"); 338661ae650dSJack F Vogel error = ENOMEM; 338761ae650dSJack F Vogel goto fail; 338861ae650dSJack F Vogel } 338961ae650dSJack F Vogel } 339061ae650dSJack F Vogel 339161ae650dSJack F Vogel return (0); 339261ae650dSJack F Vogel 339361ae650dSJack F Vogel fail: 339461ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 339561ae650dSJack F Vogel que = &vsi->queues[i]; 339661ae650dSJack F Vogel rxr = &que->rxr; 339761ae650dSJack F Vogel txr = &que->txr; 339861ae650dSJack F Vogel if (rxr->base) 3399d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &rxr->dma); 340061ae650dSJack F Vogel if (txr->base) 3401d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &txr->dma); 340261ae650dSJack F Vogel } 340361ae650dSJack F Vogel 340461ae650dSJack F Vogel early: 340561ae650dSJack F Vogel return (error); 340661ae650dSJack F Vogel } 340761ae650dSJack F Vogel 340861ae650dSJack F Vogel /* 340961ae650dSJack F Vogel ** Provide a update to the queue RX 341061ae650dSJack F Vogel ** interrupt moderation value. 341161ae650dSJack F Vogel */ 341261ae650dSJack F Vogel static void 341361ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que) 341461ae650dSJack F Vogel { 341561ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 341661ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 341761ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 341861ae650dSJack F Vogel u16 rx_itr; 341961ae650dSJack F Vogel u16 rx_latency = 0; 342061ae650dSJack F Vogel int rx_bytes; 342161ae650dSJack F Vogel 342261ae650dSJack F Vogel 342361ae650dSJack F Vogel /* Idle, do nothing */ 342461ae650dSJack F Vogel if (rxr->bytes == 0) 342561ae650dSJack F Vogel return; 342661ae650dSJack F Vogel 342761ae650dSJack F Vogel if (ixl_dynamic_rx_itr) { 342861ae650dSJack F Vogel rx_bytes = rxr->bytes/rxr->itr; 342961ae650dSJack F Vogel rx_itr = rxr->itr; 343061ae650dSJack F Vogel 343161ae650dSJack F Vogel /* Adjust latency range */ 343261ae650dSJack F Vogel switch (rxr->latency) { 343361ae650dSJack F Vogel case IXL_LOW_LATENCY: 343461ae650dSJack F Vogel if (rx_bytes > 10) { 343561ae650dSJack F Vogel rx_latency = IXL_AVE_LATENCY; 343661ae650dSJack F Vogel rx_itr = IXL_ITR_20K; 343761ae650dSJack F Vogel } 343861ae650dSJack F Vogel break; 343961ae650dSJack F Vogel case IXL_AVE_LATENCY: 344061ae650dSJack F Vogel if (rx_bytes > 20) { 344161ae650dSJack F Vogel rx_latency = IXL_BULK_LATENCY; 344261ae650dSJack F Vogel rx_itr = IXL_ITR_8K; 344361ae650dSJack F Vogel } else if (rx_bytes <= 10) { 344461ae650dSJack F Vogel rx_latency = IXL_LOW_LATENCY; 344561ae650dSJack F Vogel rx_itr = IXL_ITR_100K; 344661ae650dSJack F Vogel } 344761ae650dSJack F Vogel break; 344861ae650dSJack F Vogel case IXL_BULK_LATENCY: 344961ae650dSJack F Vogel if (rx_bytes <= 20) { 345061ae650dSJack F Vogel rx_latency = IXL_AVE_LATENCY; 345161ae650dSJack F Vogel rx_itr = IXL_ITR_20K; 345261ae650dSJack F Vogel } 345361ae650dSJack F Vogel break; 345461ae650dSJack F Vogel } 345561ae650dSJack F Vogel 345661ae650dSJack F Vogel rxr->latency = rx_latency; 345761ae650dSJack F Vogel 345861ae650dSJack F Vogel if (rx_itr != rxr->itr) { 345961ae650dSJack F Vogel /* do an exponential smoothing */ 346061ae650dSJack F Vogel rx_itr = (10 * rx_itr * rxr->itr) / 346161ae650dSJack F Vogel ((9 * rx_itr) + rxr->itr); 346261ae650dSJack F Vogel rxr->itr = rx_itr & IXL_MAX_ITR; 346361ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 346461ae650dSJack F Vogel que->me), rxr->itr); 346561ae650dSJack F Vogel } 346661ae650dSJack F Vogel } else { /* We may have have toggled to non-dynamic */ 346761ae650dSJack F Vogel if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) 346861ae650dSJack F Vogel vsi->rx_itr_setting = ixl_rx_itr; 346961ae650dSJack F Vogel /* Update the hardware if needed */ 347061ae650dSJack F Vogel if (rxr->itr != vsi->rx_itr_setting) { 347161ae650dSJack F Vogel rxr->itr = vsi->rx_itr_setting; 347261ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 347361ae650dSJack F Vogel que->me), rxr->itr); 347461ae650dSJack F Vogel } 347561ae650dSJack F Vogel } 347661ae650dSJack F Vogel rxr->bytes = 0; 347761ae650dSJack F Vogel rxr->packets = 0; 347861ae650dSJack F Vogel return; 347961ae650dSJack F Vogel } 348061ae650dSJack F Vogel 348161ae650dSJack F Vogel 348261ae650dSJack F Vogel /* 348361ae650dSJack F Vogel ** Provide a update to the queue TX 348461ae650dSJack F Vogel ** interrupt moderation value. 348561ae650dSJack F Vogel */ 348661ae650dSJack F Vogel static void 348761ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que) 348861ae650dSJack F Vogel { 348961ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 349061ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 349161ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 349261ae650dSJack F Vogel u16 tx_itr; 349361ae650dSJack F Vogel u16 tx_latency = 0; 349461ae650dSJack F Vogel int tx_bytes; 349561ae650dSJack F Vogel 349661ae650dSJack F Vogel 349761ae650dSJack F Vogel /* Idle, do nothing */ 349861ae650dSJack F Vogel if (txr->bytes == 0) 349961ae650dSJack F Vogel return; 350061ae650dSJack F Vogel 350161ae650dSJack F Vogel if (ixl_dynamic_tx_itr) { 350261ae650dSJack F Vogel tx_bytes = txr->bytes/txr->itr; 350361ae650dSJack F Vogel tx_itr = txr->itr; 350461ae650dSJack F Vogel 350561ae650dSJack F Vogel switch (txr->latency) { 350661ae650dSJack F Vogel case IXL_LOW_LATENCY: 350761ae650dSJack F Vogel if (tx_bytes > 10) { 350861ae650dSJack F Vogel tx_latency = IXL_AVE_LATENCY; 350961ae650dSJack F Vogel tx_itr = IXL_ITR_20K; 351061ae650dSJack F Vogel } 351161ae650dSJack F Vogel break; 351261ae650dSJack F Vogel case IXL_AVE_LATENCY: 351361ae650dSJack F Vogel if (tx_bytes > 20) { 351461ae650dSJack F Vogel tx_latency = IXL_BULK_LATENCY; 351561ae650dSJack F Vogel tx_itr = IXL_ITR_8K; 351661ae650dSJack F Vogel } else if (tx_bytes <= 10) { 351761ae650dSJack F Vogel tx_latency = IXL_LOW_LATENCY; 351861ae650dSJack F Vogel tx_itr = IXL_ITR_100K; 351961ae650dSJack F Vogel } 352061ae650dSJack F Vogel break; 352161ae650dSJack F Vogel case IXL_BULK_LATENCY: 352261ae650dSJack F Vogel if (tx_bytes <= 20) { 352361ae650dSJack F Vogel tx_latency = IXL_AVE_LATENCY; 352461ae650dSJack F Vogel tx_itr = IXL_ITR_20K; 352561ae650dSJack F Vogel } 352661ae650dSJack F Vogel break; 352761ae650dSJack F Vogel } 352861ae650dSJack F Vogel 352961ae650dSJack F Vogel txr->latency = tx_latency; 353061ae650dSJack F Vogel 353161ae650dSJack F Vogel if (tx_itr != txr->itr) { 353261ae650dSJack F Vogel /* do an exponential smoothing */ 353361ae650dSJack F Vogel tx_itr = (10 * tx_itr * txr->itr) / 353461ae650dSJack F Vogel ((9 * tx_itr) + txr->itr); 353561ae650dSJack F Vogel txr->itr = tx_itr & IXL_MAX_ITR; 353661ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 353761ae650dSJack F Vogel que->me), txr->itr); 353861ae650dSJack F Vogel } 353961ae650dSJack F Vogel 354061ae650dSJack F Vogel } else { /* We may have have toggled to non-dynamic */ 354161ae650dSJack F Vogel if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC) 354261ae650dSJack F Vogel vsi->tx_itr_setting = ixl_tx_itr; 354361ae650dSJack F Vogel /* Update the hardware if needed */ 354461ae650dSJack F Vogel if (txr->itr != vsi->tx_itr_setting) { 354561ae650dSJack F Vogel txr->itr = vsi->tx_itr_setting; 354661ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 354761ae650dSJack F Vogel que->me), txr->itr); 354861ae650dSJack F Vogel } 354961ae650dSJack F Vogel } 355061ae650dSJack F Vogel txr->bytes = 0; 355161ae650dSJack F Vogel txr->packets = 0; 355261ae650dSJack F Vogel return; 355361ae650dSJack F Vogel } 355461ae650dSJack F Vogel 355556c2c47bSJack F Vogel #define QUEUE_NAME_LEN 32 355656c2c47bSJack F Vogel 355756c2c47bSJack F Vogel static void 355856c2c47bSJack F Vogel ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi, 355956c2c47bSJack F Vogel struct sysctl_ctx_list *ctx, const char *sysctl_name) 356056c2c47bSJack F Vogel { 356156c2c47bSJack F Vogel struct sysctl_oid *tree; 356256c2c47bSJack F Vogel struct sysctl_oid_list *child; 356356c2c47bSJack F Vogel struct sysctl_oid_list *vsi_list; 356456c2c47bSJack F Vogel 356556c2c47bSJack F Vogel tree = device_get_sysctl_tree(pf->dev); 356656c2c47bSJack F Vogel child = SYSCTL_CHILDREN(tree); 356756c2c47bSJack F Vogel vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name, 356856c2c47bSJack F Vogel CTLFLAG_RD, NULL, "VSI Number"); 356956c2c47bSJack F Vogel vsi_list = SYSCTL_CHILDREN(vsi->vsi_node); 357056c2c47bSJack F Vogel 357156c2c47bSJack F Vogel ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats); 357256c2c47bSJack F Vogel } 357361ae650dSJack F Vogel 357461ae650dSJack F Vogel static void 357561ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf) 357661ae650dSJack F Vogel { 357761ae650dSJack F Vogel device_t dev = pf->dev; 357861ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 357961ae650dSJack F Vogel struct ixl_queue *queues = vsi->queues; 358061ae650dSJack F Vogel struct i40e_hw_port_stats *pf_stats = &pf->stats; 358161ae650dSJack F Vogel 358261ae650dSJack F Vogel struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 358361ae650dSJack F Vogel struct sysctl_oid *tree = device_get_sysctl_tree(dev); 358461ae650dSJack F Vogel struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 358556c2c47bSJack F Vogel struct sysctl_oid_list *vsi_list; 358661ae650dSJack F Vogel 358756c2c47bSJack F Vogel struct sysctl_oid *queue_node; 358856c2c47bSJack F Vogel struct sysctl_oid_list *queue_list; 358961ae650dSJack F Vogel 359061ae650dSJack F Vogel struct tx_ring *txr; 359161ae650dSJack F Vogel struct rx_ring *rxr; 359256c2c47bSJack F Vogel char queue_namebuf[QUEUE_NAME_LEN]; 359361ae650dSJack F Vogel 359461ae650dSJack F Vogel /* Driver statistics */ 359561ae650dSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 359661ae650dSJack F Vogel CTLFLAG_RD, &pf->watchdog_events, 359761ae650dSJack F Vogel "Watchdog timeouts"); 359861ae650dSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq", 359961ae650dSJack F Vogel CTLFLAG_RD, &pf->admin_irq, 360061ae650dSJack F Vogel "Admin Queue IRQ Handled"); 360161ae650dSJack F Vogel 360256c2c47bSJack F Vogel ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf"); 360356c2c47bSJack F Vogel vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node); 360461ae650dSJack F Vogel 360561ae650dSJack F Vogel /* Queue statistics */ 360661ae650dSJack F Vogel for (int q = 0; q < vsi->num_queues; q++) { 360761ae650dSJack F Vogel snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); 360856c2c47bSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, 360956c2c47bSJack F Vogel OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #"); 361061ae650dSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 361161ae650dSJack F Vogel 361261ae650dSJack F Vogel txr = &(queues[q].txr); 361361ae650dSJack F Vogel rxr = &(queues[q].rxr); 361461ae650dSJack F Vogel 361561ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", 361661ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), 361761ae650dSJack F Vogel "m_defrag() failed"); 361861ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped", 361961ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].dropped_pkts), 362061ae650dSJack F Vogel "Driver dropped packets"); 362161ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 362261ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].irqs), 362361ae650dSJack F Vogel "irqs on this queue"); 362461ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", 362561ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].tso), 362661ae650dSJack F Vogel "TSO"); 362761ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup", 362861ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].tx_dma_setup), 362961ae650dSJack F Vogel "Driver tx dma failure in xmit"); 363061ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 363161ae650dSJack F Vogel CTLFLAG_RD, &(txr->no_desc), 363261ae650dSJack F Vogel "Queue No Descriptor Available"); 363361ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 363461ae650dSJack F Vogel CTLFLAG_RD, &(txr->total_packets), 363561ae650dSJack F Vogel "Queue Packets Transmitted"); 363661ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", 363761ae650dSJack F Vogel CTLFLAG_RD, &(txr->tx_bytes), 363861ae650dSJack F Vogel "Queue Bytes Transmitted"); 363961ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 364061ae650dSJack F Vogel CTLFLAG_RD, &(rxr->rx_packets), 364161ae650dSJack F Vogel "Queue Packets Received"); 364261ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 364361ae650dSJack F Vogel CTLFLAG_RD, &(rxr->rx_bytes), 364461ae650dSJack F Vogel "Queue Bytes Received"); 364561ae650dSJack F Vogel } 364661ae650dSJack F Vogel 364761ae650dSJack F Vogel /* MAC stats */ 364861ae650dSJack F Vogel ixl_add_sysctls_mac_stats(ctx, child, pf_stats); 364961ae650dSJack F Vogel } 365061ae650dSJack F Vogel 365161ae650dSJack F Vogel static void 365261ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx, 365361ae650dSJack F Vogel struct sysctl_oid_list *child, 365461ae650dSJack F Vogel struct i40e_eth_stats *eth_stats) 365561ae650dSJack F Vogel { 365661ae650dSJack F Vogel struct ixl_sysctl_info ctls[] = 365761ae650dSJack F Vogel { 365861ae650dSJack F Vogel {ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, 365961ae650dSJack F Vogel {ð_stats->rx_unicast, "ucast_pkts_rcvd", 366061ae650dSJack F Vogel "Unicast Packets Received"}, 366161ae650dSJack F Vogel {ð_stats->rx_multicast, "mcast_pkts_rcvd", 366261ae650dSJack F Vogel "Multicast Packets Received"}, 366361ae650dSJack F Vogel {ð_stats->rx_broadcast, "bcast_pkts_rcvd", 366461ae650dSJack F Vogel "Broadcast Packets Received"}, 366561ae650dSJack F Vogel {ð_stats->rx_discards, "rx_discards", "Discarded RX packets"}, 366661ae650dSJack F Vogel {ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, 366761ae650dSJack F Vogel {ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, 366861ae650dSJack F Vogel {ð_stats->tx_multicast, "mcast_pkts_txd", 366961ae650dSJack F Vogel "Multicast Packets Transmitted"}, 367061ae650dSJack F Vogel {ð_stats->tx_broadcast, "bcast_pkts_txd", 367161ae650dSJack F Vogel "Broadcast Packets Transmitted"}, 367261ae650dSJack F Vogel // end 367361ae650dSJack F Vogel {0,0,0} 367461ae650dSJack F Vogel }; 367561ae650dSJack F Vogel 367661ae650dSJack F Vogel struct ixl_sysctl_info *entry = ctls; 3677648970d8SPedro F. Giffuni while (entry->stat != NULL) 367861ae650dSJack F Vogel { 367961ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name, 368061ae650dSJack F Vogel CTLFLAG_RD, entry->stat, 368161ae650dSJack F Vogel entry->description); 368261ae650dSJack F Vogel entry++; 368361ae650dSJack F Vogel } 368461ae650dSJack F Vogel } 368561ae650dSJack F Vogel 368661ae650dSJack F Vogel static void 368761ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx, 368861ae650dSJack F Vogel struct sysctl_oid_list *child, 368961ae650dSJack F Vogel struct i40e_hw_port_stats *stats) 369061ae650dSJack F Vogel { 369161ae650dSJack F Vogel struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", 369261ae650dSJack F Vogel CTLFLAG_RD, NULL, "Mac Statistics"); 369361ae650dSJack F Vogel struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node); 369461ae650dSJack F Vogel 369561ae650dSJack F Vogel struct i40e_eth_stats *eth_stats = &stats->eth; 369661ae650dSJack F Vogel ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats); 369761ae650dSJack F Vogel 369861ae650dSJack F Vogel struct ixl_sysctl_info ctls[] = 369961ae650dSJack F Vogel { 370061ae650dSJack F Vogel {&stats->crc_errors, "crc_errors", "CRC Errors"}, 370161ae650dSJack F Vogel {&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"}, 370261ae650dSJack F Vogel {&stats->mac_local_faults, "local_faults", "MAC Local Faults"}, 370361ae650dSJack F Vogel {&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"}, 370461ae650dSJack F Vogel {&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"}, 370561ae650dSJack F Vogel /* Packet Reception Stats */ 370661ae650dSJack F Vogel {&stats->rx_size_64, "rx_frames_64", "64 byte frames received"}, 370761ae650dSJack F Vogel {&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"}, 370861ae650dSJack F Vogel {&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"}, 370961ae650dSJack F Vogel {&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"}, 371061ae650dSJack F Vogel {&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"}, 371161ae650dSJack F Vogel {&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"}, 371261ae650dSJack F Vogel {&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"}, 371361ae650dSJack F Vogel {&stats->rx_undersize, "rx_undersize", "Undersized packets received"}, 371461ae650dSJack F Vogel {&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"}, 371561ae650dSJack F Vogel {&stats->rx_oversize, "rx_oversized", "Oversized packets received"}, 371661ae650dSJack F Vogel {&stats->rx_jabber, "rx_jabber", "Received Jabber"}, 371761ae650dSJack F Vogel {&stats->checksum_error, "checksum_errors", "Checksum Errors"}, 371861ae650dSJack F Vogel /* Packet Transmission Stats */ 371961ae650dSJack F Vogel {&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"}, 372061ae650dSJack F Vogel {&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"}, 372161ae650dSJack F Vogel {&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"}, 372261ae650dSJack F Vogel {&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"}, 372361ae650dSJack F Vogel {&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"}, 372461ae650dSJack F Vogel {&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"}, 372561ae650dSJack F Vogel {&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"}, 372661ae650dSJack F Vogel /* Flow control */ 372761ae650dSJack F Vogel {&stats->link_xon_tx, "xon_txd", "Link XON transmitted"}, 372861ae650dSJack F Vogel {&stats->link_xon_rx, "xon_recvd", "Link XON received"}, 372961ae650dSJack F Vogel {&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"}, 373061ae650dSJack F Vogel {&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"}, 373161ae650dSJack F Vogel /* End */ 373261ae650dSJack F Vogel {0,0,0} 373361ae650dSJack F Vogel }; 373461ae650dSJack F Vogel 373561ae650dSJack F Vogel struct ixl_sysctl_info *entry = ctls; 3736648970d8SPedro F. Giffuni while (entry->stat != NULL) 373761ae650dSJack F Vogel { 373861ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name, 373961ae650dSJack F Vogel CTLFLAG_RD, entry->stat, 374061ae650dSJack F Vogel entry->description); 374161ae650dSJack F Vogel entry++; 374261ae650dSJack F Vogel } 374361ae650dSJack F Vogel } 374461ae650dSJack F Vogel 3745be771cdaSJack F Vogel 374661ae650dSJack F Vogel /* 374761ae650dSJack F Vogel ** ixl_config_rss - setup RSS 374861ae650dSJack F Vogel ** - note this is done for the single vsi 374961ae650dSJack F Vogel */ 375061ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *vsi) 375161ae650dSJack F Vogel { 375261ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 375361ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 375461ae650dSJack F Vogel u32 lut = 0; 3755393c4bb1SJack F Vogel u64 set_hena = 0, hena; 3756393c4bb1SJack F Vogel int i, j, que_id; 3757393c4bb1SJack F Vogel #ifdef RSS 3758393c4bb1SJack F Vogel u32 rss_hash_config; 3759393c4bb1SJack F Vogel u32 rss_seed[IXL_KEYSZ]; 3760393c4bb1SJack F Vogel #else 3761393c4bb1SJack F Vogel u32 rss_seed[IXL_KEYSZ] = {0x41b01687, 3762393c4bb1SJack F Vogel 0x183cfd8c, 0xce880440, 0x580cbc3c, 3763393c4bb1SJack F Vogel 0x35897377, 0x328b25e1, 0x4fa98922, 3764393c4bb1SJack F Vogel 0xb7d90c14, 0xd5bad70d, 0xcd15a2c1}; 3765393c4bb1SJack F Vogel #endif 376661ae650dSJack F Vogel 3767393c4bb1SJack F Vogel #ifdef RSS 3768393c4bb1SJack F Vogel /* Fetch the configured RSS key */ 3769393c4bb1SJack F Vogel rss_getkey((uint8_t *) &rss_seed); 3770393c4bb1SJack F Vogel #endif 377161ae650dSJack F Vogel 377261ae650dSJack F Vogel /* Fill out hash function seed */ 3773393c4bb1SJack F Vogel for (i = 0; i < IXL_KEYSZ; i++) 3774393c4bb1SJack F Vogel wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]); 377561ae650dSJack F Vogel 377661ae650dSJack F Vogel /* Enable PCTYPES for RSS: */ 3777393c4bb1SJack F Vogel #ifdef RSS 3778393c4bb1SJack F Vogel rss_hash_config = rss_gethashconfig(); 3779393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 3780393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); 3781393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 3782393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); 3783393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 3784393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP); 3785393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 3786393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); 3787df1d7a71SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 3788df1d7a71SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); 3789393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 3790393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); 3791393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 3792393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP); 3793393c4bb1SJack F Vogel #else 379461ae650dSJack F Vogel set_hena = 379561ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | 379661ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | 379761ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | 379861ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | 379961ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | 380061ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | 380161ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | 380261ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | 380361ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | 380461ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | 380561ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD); 3806393c4bb1SJack F Vogel #endif 380761ae650dSJack F Vogel hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) | 380861ae650dSJack F Vogel ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32); 380961ae650dSJack F Vogel hena |= set_hena; 381061ae650dSJack F Vogel wr32(hw, I40E_PFQF_HENA(0), (u32)hena); 381161ae650dSJack F Vogel wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); 381261ae650dSJack F Vogel 381361ae650dSJack F Vogel /* Populate the LUT with max no. of queues in round robin fashion */ 381461ae650dSJack F Vogel for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) { 381561ae650dSJack F Vogel if (j == vsi->num_queues) 381661ae650dSJack F Vogel j = 0; 3817393c4bb1SJack F Vogel #ifdef RSS 3818393c4bb1SJack F Vogel /* 3819393c4bb1SJack F Vogel * Fetch the RSS bucket id for the given indirection entry. 3820393c4bb1SJack F Vogel * Cap it at the number of configured buckets (which is 3821393c4bb1SJack F Vogel * num_queues.) 3822393c4bb1SJack F Vogel */ 3823393c4bb1SJack F Vogel que_id = rss_get_indirection_to_bucket(i); 3824dcd7b3b2SJack F Vogel que_id = que_id % vsi->num_queues; 3825393c4bb1SJack F Vogel #else 3826393c4bb1SJack F Vogel que_id = j; 3827393c4bb1SJack F Vogel #endif 382861ae650dSJack F Vogel /* lut = 4-byte sliding window of 4 lut entries */ 3829393c4bb1SJack F Vogel lut = (lut << 8) | (que_id & 383061ae650dSJack F Vogel ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1)); 383161ae650dSJack F Vogel /* On i = 3, we have 4 entries in lut; write to the register */ 383261ae650dSJack F Vogel if ((i & 3) == 3) 383361ae650dSJack F Vogel wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); 383461ae650dSJack F Vogel } 383561ae650dSJack F Vogel ixl_flush(hw); 383661ae650dSJack F Vogel } 383761ae650dSJack F Vogel 383861ae650dSJack F Vogel 383961ae650dSJack F Vogel /* 384061ae650dSJack F Vogel ** This routine is run via an vlan config EVENT, 384161ae650dSJack F Vogel ** it enables us to use the HW Filter table since 384261ae650dSJack F Vogel ** we can get the vlan id. This just creates the 384361ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will 384461ae650dSJack F Vogel ** repopulate the real table. 384561ae650dSJack F Vogel */ 384661ae650dSJack F Vogel static void 384761ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 384861ae650dSJack F Vogel { 384961ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 385061ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 385161ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 385261ae650dSJack F Vogel 385361ae650dSJack F Vogel if (ifp->if_softc != arg) /* Not our event */ 385461ae650dSJack F Vogel return; 385561ae650dSJack F Vogel 385661ae650dSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 385761ae650dSJack F Vogel return; 385861ae650dSJack F Vogel 385961ae650dSJack F Vogel IXL_PF_LOCK(pf); 386061ae650dSJack F Vogel ++vsi->num_vlans; 386161ae650dSJack F Vogel ixl_add_filter(vsi, hw->mac.addr, vtag); 386261ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 386361ae650dSJack F Vogel } 386461ae650dSJack F Vogel 386561ae650dSJack F Vogel /* 386661ae650dSJack F Vogel ** This routine is run via an vlan 386761ae650dSJack F Vogel ** unconfig EVENT, remove our entry 386861ae650dSJack F Vogel ** in the soft vfta. 386961ae650dSJack F Vogel */ 387061ae650dSJack F Vogel static void 387161ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 387261ae650dSJack F Vogel { 387361ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 387461ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 387561ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 387661ae650dSJack F Vogel 387761ae650dSJack F Vogel if (ifp->if_softc != arg) 387861ae650dSJack F Vogel return; 387961ae650dSJack F Vogel 388061ae650dSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 388161ae650dSJack F Vogel return; 388261ae650dSJack F Vogel 388361ae650dSJack F Vogel IXL_PF_LOCK(pf); 388461ae650dSJack F Vogel --vsi->num_vlans; 388561ae650dSJack F Vogel ixl_del_filter(vsi, hw->mac.addr, vtag); 388661ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 388761ae650dSJack F Vogel } 388861ae650dSJack F Vogel 388961ae650dSJack F Vogel /* 389061ae650dSJack F Vogel ** This routine updates vlan filters, called by init 389161ae650dSJack F Vogel ** it scans the filter table and then updates the hw 389261ae650dSJack F Vogel ** after a soft reset. 389361ae650dSJack F Vogel */ 389461ae650dSJack F Vogel static void 389561ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi) 389661ae650dSJack F Vogel { 389761ae650dSJack F Vogel struct ixl_mac_filter *f; 389861ae650dSJack F Vogel int cnt = 0, flags; 389961ae650dSJack F Vogel 390061ae650dSJack F Vogel if (vsi->num_vlans == 0) 390161ae650dSJack F Vogel return; 390261ae650dSJack F Vogel /* 390361ae650dSJack F Vogel ** Scan the filter list for vlan entries, 390461ae650dSJack F Vogel ** mark them for addition and then call 390561ae650dSJack F Vogel ** for the AQ update. 390661ae650dSJack F Vogel */ 390761ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 390861ae650dSJack F Vogel if (f->flags & IXL_FILTER_VLAN) { 390961ae650dSJack F Vogel f->flags |= 391061ae650dSJack F Vogel (IXL_FILTER_ADD | 391161ae650dSJack F Vogel IXL_FILTER_USED); 391261ae650dSJack F Vogel cnt++; 391361ae650dSJack F Vogel } 391461ae650dSJack F Vogel } 391561ae650dSJack F Vogel if (cnt == 0) { 391661ae650dSJack F Vogel printf("setup vlan: no filters found!\n"); 391761ae650dSJack F Vogel return; 391861ae650dSJack F Vogel } 391961ae650dSJack F Vogel flags = IXL_FILTER_VLAN; 392061ae650dSJack F Vogel flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 392161ae650dSJack F Vogel ixl_add_hw_filters(vsi, flags, cnt); 392261ae650dSJack F Vogel return; 392361ae650dSJack F Vogel } 392461ae650dSJack F Vogel 392561ae650dSJack F Vogel /* 392661ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware 392761ae650dSJack F Vogel ** needs to know about. 39281d767a8eSEric Joyner ** 39291d767a8eSEric Joyner ** Requires VSI's filter list & seid to be set before calling. 393061ae650dSJack F Vogel */ 393161ae650dSJack F Vogel static void 393261ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi) 393361ae650dSJack F Vogel { 393461ae650dSJack F Vogel /* Add broadcast address */ 393556c2c47bSJack F Vogel ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY); 39361d767a8eSEric Joyner 39371d767a8eSEric Joyner /* 39381d767a8eSEric Joyner * Prevent Tx flow control frames from being sent out by 39391d767a8eSEric Joyner * non-firmware transmitters. 39401d767a8eSEric Joyner */ 39411d767a8eSEric Joyner i40e_add_filter_to_drop_tx_flow_control_frames(vsi->hw, vsi->seid); 394261ae650dSJack F Vogel } 394361ae650dSJack F Vogel 394461ae650dSJack F Vogel /* 394561ae650dSJack F Vogel ** This routine adds mulicast filters 394661ae650dSJack F Vogel */ 394761ae650dSJack F Vogel static void 394861ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr) 394961ae650dSJack F Vogel { 395061ae650dSJack F Vogel struct ixl_mac_filter *f; 395161ae650dSJack F Vogel 395261ae650dSJack F Vogel /* Does one already exist */ 395361ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 395461ae650dSJack F Vogel if (f != NULL) 395561ae650dSJack F Vogel return; 395661ae650dSJack F Vogel 395761ae650dSJack F Vogel f = ixl_get_filter(vsi); 395861ae650dSJack F Vogel if (f == NULL) { 395961ae650dSJack F Vogel printf("WARNING: no filter available!!\n"); 396061ae650dSJack F Vogel return; 396161ae650dSJack F Vogel } 396261ae650dSJack F Vogel bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 396361ae650dSJack F Vogel f->vlan = IXL_VLAN_ANY; 396461ae650dSJack F Vogel f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED 396561ae650dSJack F Vogel | IXL_FILTER_MC); 396661ae650dSJack F Vogel 396761ae650dSJack F Vogel return; 396861ae650dSJack F Vogel } 396961ae650dSJack F Vogel 397056c2c47bSJack F Vogel static void 397156c2c47bSJack F Vogel ixl_reconfigure_filters(struct ixl_vsi *vsi) 397256c2c47bSJack F Vogel { 397356c2c47bSJack F Vogel 397456c2c47bSJack F Vogel ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs); 397556c2c47bSJack F Vogel } 397656c2c47bSJack F Vogel 397761ae650dSJack F Vogel /* 397861ae650dSJack F Vogel ** This routine adds macvlan filters 397961ae650dSJack F Vogel */ 398061ae650dSJack F Vogel static void 398161ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 398261ae650dSJack F Vogel { 398361ae650dSJack F Vogel struct ixl_mac_filter *f, *tmp; 398456c2c47bSJack F Vogel struct ixl_pf *pf; 398556c2c47bSJack F Vogel device_t dev; 398661ae650dSJack F Vogel 398761ae650dSJack F Vogel DEBUGOUT("ixl_add_filter: begin"); 398861ae650dSJack F Vogel 398956c2c47bSJack F Vogel pf = vsi->back; 399056c2c47bSJack F Vogel dev = pf->dev; 399156c2c47bSJack F Vogel 399261ae650dSJack F Vogel /* Does one already exist */ 399361ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, vlan); 399461ae650dSJack F Vogel if (f != NULL) 399561ae650dSJack F Vogel return; 399661ae650dSJack F Vogel /* 399761ae650dSJack F Vogel ** Is this the first vlan being registered, if so we 399861ae650dSJack F Vogel ** need to remove the ANY filter that indicates we are 399961ae650dSJack F Vogel ** not in a vlan, and replace that with a 0 filter. 400061ae650dSJack F Vogel */ 400161ae650dSJack F Vogel if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) { 400261ae650dSJack F Vogel tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 400361ae650dSJack F Vogel if (tmp != NULL) { 400461ae650dSJack F Vogel ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY); 400561ae650dSJack F Vogel ixl_add_filter(vsi, macaddr, 0); 400661ae650dSJack F Vogel } 400761ae650dSJack F Vogel } 400861ae650dSJack F Vogel 400961ae650dSJack F Vogel f = ixl_get_filter(vsi); 401061ae650dSJack F Vogel if (f == NULL) { 401161ae650dSJack F Vogel device_printf(dev, "WARNING: no filter available!!\n"); 401261ae650dSJack F Vogel return; 401361ae650dSJack F Vogel } 401461ae650dSJack F Vogel bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 401561ae650dSJack F Vogel f->vlan = vlan; 401661ae650dSJack F Vogel f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 401761ae650dSJack F Vogel if (f->vlan != IXL_VLAN_ANY) 401861ae650dSJack F Vogel f->flags |= IXL_FILTER_VLAN; 401956c2c47bSJack F Vogel else 402056c2c47bSJack F Vogel vsi->num_macs++; 402161ae650dSJack F Vogel 402261ae650dSJack F Vogel ixl_add_hw_filters(vsi, f->flags, 1); 402361ae650dSJack F Vogel return; 402461ae650dSJack F Vogel } 402561ae650dSJack F Vogel 402661ae650dSJack F Vogel static void 402761ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 402861ae650dSJack F Vogel { 402961ae650dSJack F Vogel struct ixl_mac_filter *f; 403061ae650dSJack F Vogel 403161ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, vlan); 403261ae650dSJack F Vogel if (f == NULL) 403361ae650dSJack F Vogel return; 403461ae650dSJack F Vogel 403561ae650dSJack F Vogel f->flags |= IXL_FILTER_DEL; 403661ae650dSJack F Vogel ixl_del_hw_filters(vsi, 1); 403756c2c47bSJack F Vogel vsi->num_macs--; 403861ae650dSJack F Vogel 403961ae650dSJack F Vogel /* Check if this is the last vlan removal */ 404061ae650dSJack F Vogel if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) { 404161ae650dSJack F Vogel /* Switch back to a non-vlan filter */ 404261ae650dSJack F Vogel ixl_del_filter(vsi, macaddr, 0); 404361ae650dSJack F Vogel ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY); 404461ae650dSJack F Vogel } 404561ae650dSJack F Vogel return; 404661ae650dSJack F Vogel } 404761ae650dSJack F Vogel 404861ae650dSJack F Vogel /* 404961ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id 405061ae650dSJack F Vogel */ 405161ae650dSJack F Vogel static struct ixl_mac_filter * 405261ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 405361ae650dSJack F Vogel { 405461ae650dSJack F Vogel struct ixl_mac_filter *f; 405561ae650dSJack F Vogel bool match = FALSE; 405661ae650dSJack F Vogel 405761ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 405861ae650dSJack F Vogel if (!cmp_etheraddr(f->macaddr, macaddr)) 405961ae650dSJack F Vogel continue; 406061ae650dSJack F Vogel if (f->vlan == vlan) { 406161ae650dSJack F Vogel match = TRUE; 406261ae650dSJack F Vogel break; 406361ae650dSJack F Vogel } 406461ae650dSJack F Vogel } 406561ae650dSJack F Vogel 406661ae650dSJack F Vogel if (!match) 406761ae650dSJack F Vogel f = NULL; 406861ae650dSJack F Vogel return (f); 406961ae650dSJack F Vogel } 407061ae650dSJack F Vogel 407161ae650dSJack F Vogel /* 407261ae650dSJack F Vogel ** This routine takes additions to the vsi filter 407361ae650dSJack F Vogel ** table and creates an Admin Queue call to create 407461ae650dSJack F Vogel ** the filters in the hardware. 407561ae650dSJack F Vogel */ 407661ae650dSJack F Vogel static void 407761ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt) 407861ae650dSJack F Vogel { 407961ae650dSJack F Vogel struct i40e_aqc_add_macvlan_element_data *a, *b; 408061ae650dSJack F Vogel struct ixl_mac_filter *f; 408156c2c47bSJack F Vogel struct ixl_pf *pf; 408256c2c47bSJack F Vogel struct i40e_hw *hw; 408356c2c47bSJack F Vogel device_t dev; 408461ae650dSJack F Vogel int err, j = 0; 408561ae650dSJack F Vogel 408656c2c47bSJack F Vogel pf = vsi->back; 408756c2c47bSJack F Vogel dev = pf->dev; 408856c2c47bSJack F Vogel hw = &pf->hw; 408956c2c47bSJack F Vogel IXL_PF_LOCK_ASSERT(pf); 409056c2c47bSJack F Vogel 409161ae650dSJack F Vogel a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt, 409261ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 409361ae650dSJack F Vogel if (a == NULL) { 4094393c4bb1SJack F Vogel device_printf(dev, "add_hw_filters failed to get memory\n"); 409561ae650dSJack F Vogel return; 409661ae650dSJack F Vogel } 409761ae650dSJack F Vogel 409861ae650dSJack F Vogel /* 409961ae650dSJack F Vogel ** Scan the filter list, each time we find one 410061ae650dSJack F Vogel ** we add it to the admin queue array and turn off 410161ae650dSJack F Vogel ** the add bit. 410261ae650dSJack F Vogel */ 410361ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 410461ae650dSJack F Vogel if (f->flags == flags) { 410561ae650dSJack F Vogel b = &a[j]; // a pox on fvl long names :) 410661ae650dSJack F Vogel bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN); 410756c2c47bSJack F Vogel if (f->vlan == IXL_VLAN_ANY) { 410856c2c47bSJack F Vogel b->vlan_tag = 0; 410956c2c47bSJack F Vogel b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN; 411056c2c47bSJack F Vogel } else { 411156c2c47bSJack F Vogel b->vlan_tag = f->vlan; 411256c2c47bSJack F Vogel b->flags = 0; 411356c2c47bSJack F Vogel } 411456c2c47bSJack F Vogel b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH; 411561ae650dSJack F Vogel f->flags &= ~IXL_FILTER_ADD; 411661ae650dSJack F Vogel j++; 411761ae650dSJack F Vogel } 411861ae650dSJack F Vogel if (j == cnt) 411961ae650dSJack F Vogel break; 412061ae650dSJack F Vogel } 412161ae650dSJack F Vogel if (j > 0) { 412261ae650dSJack F Vogel err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); 412361ae650dSJack F Vogel if (err) 4124b6c8f260SJack F Vogel device_printf(dev, "aq_add_macvlan err %d, " 4125b6c8f260SJack F Vogel "aq_error %d\n", err, hw->aq.asq_last_status); 412661ae650dSJack F Vogel else 412761ae650dSJack F Vogel vsi->hw_filters_add += j; 412861ae650dSJack F Vogel } 412961ae650dSJack F Vogel free(a, M_DEVBUF); 413061ae650dSJack F Vogel return; 413161ae650dSJack F Vogel } 413261ae650dSJack F Vogel 413361ae650dSJack F Vogel /* 413461ae650dSJack F Vogel ** This routine takes removals in the vsi filter 413561ae650dSJack F Vogel ** table and creates an Admin Queue call to delete 413661ae650dSJack F Vogel ** the filters in the hardware. 413761ae650dSJack F Vogel */ 413861ae650dSJack F Vogel static void 413961ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt) 414061ae650dSJack F Vogel { 414161ae650dSJack F Vogel struct i40e_aqc_remove_macvlan_element_data *d, *e; 414256c2c47bSJack F Vogel struct ixl_pf *pf; 414356c2c47bSJack F Vogel struct i40e_hw *hw; 414456c2c47bSJack F Vogel device_t dev; 414561ae650dSJack F Vogel struct ixl_mac_filter *f, *f_temp; 414661ae650dSJack F Vogel int err, j = 0; 414761ae650dSJack F Vogel 414861ae650dSJack F Vogel DEBUGOUT("ixl_del_hw_filters: begin\n"); 414961ae650dSJack F Vogel 415056c2c47bSJack F Vogel pf = vsi->back; 415156c2c47bSJack F Vogel hw = &pf->hw; 415256c2c47bSJack F Vogel dev = pf->dev; 415356c2c47bSJack F Vogel 415461ae650dSJack F Vogel d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt, 415561ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 415661ae650dSJack F Vogel if (d == NULL) { 415761ae650dSJack F Vogel printf("del hw filter failed to get memory\n"); 415861ae650dSJack F Vogel return; 415961ae650dSJack F Vogel } 416061ae650dSJack F Vogel 416161ae650dSJack F Vogel SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) { 416261ae650dSJack F Vogel if (f->flags & IXL_FILTER_DEL) { 416361ae650dSJack F Vogel e = &d[j]; // a pox on fvl long names :) 416461ae650dSJack F Vogel bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN); 416561ae650dSJack F Vogel e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan); 416661ae650dSJack F Vogel e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; 416761ae650dSJack F Vogel /* delete entry from vsi list */ 416861ae650dSJack F Vogel SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next); 416961ae650dSJack F Vogel free(f, M_DEVBUF); 417061ae650dSJack F Vogel j++; 417161ae650dSJack F Vogel } 417261ae650dSJack F Vogel if (j == cnt) 417361ae650dSJack F Vogel break; 417461ae650dSJack F Vogel } 417561ae650dSJack F Vogel if (j > 0) { 417661ae650dSJack F Vogel err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); 417761ae650dSJack F Vogel /* NOTE: returns ENOENT every time but seems to work fine, 417861ae650dSJack F Vogel so we'll ignore that specific error. */ 4179393c4bb1SJack F Vogel // TODO: Does this still occur on current firmwares? 418061ae650dSJack F Vogel if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { 418161ae650dSJack F Vogel int sc = 0; 418261ae650dSJack F Vogel for (int i = 0; i < j; i++) 418361ae650dSJack F Vogel sc += (!d[i].error_code); 418461ae650dSJack F Vogel vsi->hw_filters_del += sc; 418561ae650dSJack F Vogel device_printf(dev, 418661ae650dSJack F Vogel "Failed to remove %d/%d filters, aq error %d\n", 418761ae650dSJack F Vogel j - sc, j, hw->aq.asq_last_status); 418861ae650dSJack F Vogel } else 418961ae650dSJack F Vogel vsi->hw_filters_del += j; 419061ae650dSJack F Vogel } 419161ae650dSJack F Vogel free(d, M_DEVBUF); 419261ae650dSJack F Vogel 419361ae650dSJack F Vogel DEBUGOUT("ixl_del_hw_filters: end\n"); 419461ae650dSJack F Vogel return; 419561ae650dSJack F Vogel } 419661ae650dSJack F Vogel 419756c2c47bSJack F Vogel static int 419861ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi) 419961ae650dSJack F Vogel { 420056c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 420156c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 420256c2c47bSJack F Vogel int index, error; 420361ae650dSJack F Vogel u32 reg; 420461ae650dSJack F Vogel 420556c2c47bSJack F Vogel error = 0; 420661ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 420756c2c47bSJack F Vogel index = vsi->first_queue + i; 420856c2c47bSJack F Vogel i40e_pre_tx_queue_cfg(hw, index, TRUE); 420961ae650dSJack F Vogel 421056c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 421161ae650dSJack F Vogel reg |= I40E_QTX_ENA_QENA_REQ_MASK | 421261ae650dSJack F Vogel I40E_QTX_ENA_QENA_STAT_MASK; 421356c2c47bSJack F Vogel wr32(hw, I40E_QTX_ENA(index), reg); 421461ae650dSJack F Vogel /* Verify the enable took */ 421561ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 421656c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 421761ae650dSJack F Vogel if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 421861ae650dSJack F Vogel break; 421961ae650dSJack F Vogel i40e_msec_delay(10); 422061ae650dSJack F Vogel } 422156c2c47bSJack F Vogel if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) { 422256c2c47bSJack F Vogel device_printf(pf->dev, "TX queue %d disabled!\n", 422356c2c47bSJack F Vogel index); 422456c2c47bSJack F Vogel error = ETIMEDOUT; 422556c2c47bSJack F Vogel } 422661ae650dSJack F Vogel 422756c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 422861ae650dSJack F Vogel reg |= I40E_QRX_ENA_QENA_REQ_MASK | 422961ae650dSJack F Vogel I40E_QRX_ENA_QENA_STAT_MASK; 423056c2c47bSJack F Vogel wr32(hw, I40E_QRX_ENA(index), reg); 423161ae650dSJack F Vogel /* Verify the enable took */ 423261ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 423356c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 423461ae650dSJack F Vogel if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 423561ae650dSJack F Vogel break; 423661ae650dSJack F Vogel i40e_msec_delay(10); 423761ae650dSJack F Vogel } 423856c2c47bSJack F Vogel if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) { 423956c2c47bSJack F Vogel device_printf(pf->dev, "RX queue %d disabled!\n", 424056c2c47bSJack F Vogel index); 424156c2c47bSJack F Vogel error = ETIMEDOUT; 424261ae650dSJack F Vogel } 424361ae650dSJack F Vogel } 424461ae650dSJack F Vogel 424556c2c47bSJack F Vogel return (error); 424656c2c47bSJack F Vogel } 424756c2c47bSJack F Vogel 424856c2c47bSJack F Vogel static int 424961ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi) 425061ae650dSJack F Vogel { 425156c2c47bSJack F Vogel struct ixl_pf *pf = vsi->back; 425256c2c47bSJack F Vogel struct i40e_hw *hw = &pf->hw; 425356c2c47bSJack F Vogel int index, error; 425461ae650dSJack F Vogel u32 reg; 425561ae650dSJack F Vogel 425656c2c47bSJack F Vogel error = 0; 425761ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 425856c2c47bSJack F Vogel index = vsi->first_queue + i; 425956c2c47bSJack F Vogel 426056c2c47bSJack F Vogel i40e_pre_tx_queue_cfg(hw, index, FALSE); 426161ae650dSJack F Vogel i40e_usec_delay(500); 426261ae650dSJack F Vogel 426356c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 426461ae650dSJack F Vogel reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; 426556c2c47bSJack F Vogel wr32(hw, I40E_QTX_ENA(index), reg); 426661ae650dSJack F Vogel /* Verify the disable took */ 426761ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 426856c2c47bSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(index)); 426961ae650dSJack F Vogel if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK)) 427061ae650dSJack F Vogel break; 427161ae650dSJack F Vogel i40e_msec_delay(10); 427261ae650dSJack F Vogel } 427356c2c47bSJack F Vogel if (reg & I40E_QTX_ENA_QENA_STAT_MASK) { 427456c2c47bSJack F Vogel device_printf(pf->dev, "TX queue %d still enabled!\n", 427556c2c47bSJack F Vogel index); 427656c2c47bSJack F Vogel error = ETIMEDOUT; 427756c2c47bSJack F Vogel } 427861ae650dSJack F Vogel 427956c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 428061ae650dSJack F Vogel reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; 428156c2c47bSJack F Vogel wr32(hw, I40E_QRX_ENA(index), reg); 428261ae650dSJack F Vogel /* Verify the disable took */ 428361ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 428456c2c47bSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(index)); 428561ae650dSJack F Vogel if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK)) 428661ae650dSJack F Vogel break; 428761ae650dSJack F Vogel i40e_msec_delay(10); 428861ae650dSJack F Vogel } 428956c2c47bSJack F Vogel if (reg & I40E_QRX_ENA_QENA_STAT_MASK) { 429056c2c47bSJack F Vogel device_printf(pf->dev, "RX queue %d still enabled!\n", 429156c2c47bSJack F Vogel index); 429256c2c47bSJack F Vogel error = ETIMEDOUT; 429361ae650dSJack F Vogel } 429461ae650dSJack F Vogel } 429561ae650dSJack F Vogel 429656c2c47bSJack F Vogel return (error); 429756c2c47bSJack F Vogel } 429856c2c47bSJack F Vogel 429961ae650dSJack F Vogel /** 430061ae650dSJack F Vogel * ixl_handle_mdd_event 430161ae650dSJack F Vogel * 430261ae650dSJack F Vogel * Called from interrupt handler to identify possibly malicious vfs 430361ae650dSJack F Vogel * (But also detects events from the PF, as well) 430461ae650dSJack F Vogel **/ 430561ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *pf) 430661ae650dSJack F Vogel { 430761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 430861ae650dSJack F Vogel device_t dev = pf->dev; 430961ae650dSJack F Vogel bool mdd_detected = false; 431061ae650dSJack F Vogel bool pf_mdd_detected = false; 431161ae650dSJack F Vogel u32 reg; 431261ae650dSJack F Vogel 431361ae650dSJack F Vogel /* find what triggered the MDD event */ 431461ae650dSJack F Vogel reg = rd32(hw, I40E_GL_MDET_TX); 431561ae650dSJack F Vogel if (reg & I40E_GL_MDET_TX_VALID_MASK) { 431661ae650dSJack F Vogel u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >> 431761ae650dSJack F Vogel I40E_GL_MDET_TX_PF_NUM_SHIFT; 431861ae650dSJack F Vogel u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >> 431961ae650dSJack F Vogel I40E_GL_MDET_TX_EVENT_SHIFT; 432061ae650dSJack F Vogel u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >> 432161ae650dSJack F Vogel I40E_GL_MDET_TX_QUEUE_SHIFT; 432261ae650dSJack F Vogel device_printf(dev, 432361ae650dSJack F Vogel "Malicious Driver Detection event 0x%02x" 432461ae650dSJack F Vogel " on TX queue %d pf number 0x%02x\n", 432561ae650dSJack F Vogel event, queue, pf_num); 432661ae650dSJack F Vogel wr32(hw, I40E_GL_MDET_TX, 0xffffffff); 432761ae650dSJack F Vogel mdd_detected = true; 432861ae650dSJack F Vogel } 432961ae650dSJack F Vogel reg = rd32(hw, I40E_GL_MDET_RX); 433061ae650dSJack F Vogel if (reg & I40E_GL_MDET_RX_VALID_MASK) { 433161ae650dSJack F Vogel u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >> 433261ae650dSJack F Vogel I40E_GL_MDET_RX_FUNCTION_SHIFT; 433361ae650dSJack F Vogel u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >> 433461ae650dSJack F Vogel I40E_GL_MDET_RX_EVENT_SHIFT; 433561ae650dSJack F Vogel u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >> 433661ae650dSJack F Vogel I40E_GL_MDET_RX_QUEUE_SHIFT; 433761ae650dSJack F Vogel device_printf(dev, 433861ae650dSJack F Vogel "Malicious Driver Detection event 0x%02x" 433961ae650dSJack F Vogel " on RX queue %d of function 0x%02x\n", 434061ae650dSJack F Vogel event, queue, func); 434161ae650dSJack F Vogel wr32(hw, I40E_GL_MDET_RX, 0xffffffff); 434261ae650dSJack F Vogel mdd_detected = true; 434361ae650dSJack F Vogel } 434461ae650dSJack F Vogel 434561ae650dSJack F Vogel if (mdd_detected) { 434661ae650dSJack F Vogel reg = rd32(hw, I40E_PF_MDET_TX); 434761ae650dSJack F Vogel if (reg & I40E_PF_MDET_TX_VALID_MASK) { 434861ae650dSJack F Vogel wr32(hw, I40E_PF_MDET_TX, 0xFFFF); 434961ae650dSJack F Vogel device_printf(dev, 435061ae650dSJack F Vogel "MDD TX event is for this function 0x%08x", 435161ae650dSJack F Vogel reg); 435261ae650dSJack F Vogel pf_mdd_detected = true; 435361ae650dSJack F Vogel } 435461ae650dSJack F Vogel reg = rd32(hw, I40E_PF_MDET_RX); 435561ae650dSJack F Vogel if (reg & I40E_PF_MDET_RX_VALID_MASK) { 435661ae650dSJack F Vogel wr32(hw, I40E_PF_MDET_RX, 0xFFFF); 435761ae650dSJack F Vogel device_printf(dev, 435861ae650dSJack F Vogel "MDD RX event is for this function 0x%08x", 435961ae650dSJack F Vogel reg); 436061ae650dSJack F Vogel pf_mdd_detected = true; 436161ae650dSJack F Vogel } 436261ae650dSJack F Vogel } 436361ae650dSJack F Vogel 436461ae650dSJack F Vogel /* re-enable mdd interrupt cause */ 436561ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0_ENA); 436661ae650dSJack F Vogel reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 436761ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 436861ae650dSJack F Vogel ixl_flush(hw); 436961ae650dSJack F Vogel } 437061ae650dSJack F Vogel 437161ae650dSJack F Vogel static void 437261ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi) 437361ae650dSJack F Vogel { 437461ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 437561ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 437661ae650dSJack F Vogel 437761ae650dSJack F Vogel if (ixl_enable_msix) { 437861ae650dSJack F Vogel ixl_enable_adminq(hw); 437961ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) 438061ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 438161ae650dSJack F Vogel } else 438261ae650dSJack F Vogel ixl_enable_legacy(hw); 438361ae650dSJack F Vogel } 438461ae650dSJack F Vogel 438561ae650dSJack F Vogel static void 438656c2c47bSJack F Vogel ixl_disable_rings_intr(struct ixl_vsi *vsi) 438761ae650dSJack F Vogel { 438861ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 438961ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 439061ae650dSJack F Vogel 439161ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) 439261ae650dSJack F Vogel ixl_disable_queue(hw, que->me); 439356c2c47bSJack F Vogel } 439456c2c47bSJack F Vogel 439556c2c47bSJack F Vogel static void 439656c2c47bSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi) 439756c2c47bSJack F Vogel { 439856c2c47bSJack F Vogel struct i40e_hw *hw = vsi->hw; 439956c2c47bSJack F Vogel 440056c2c47bSJack F Vogel if (ixl_enable_msix) 440156c2c47bSJack F Vogel ixl_disable_adminq(hw); 440256c2c47bSJack F Vogel else 440361ae650dSJack F Vogel ixl_disable_legacy(hw); 440461ae650dSJack F Vogel } 440561ae650dSJack F Vogel 440661ae650dSJack F Vogel static void 440761ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw) 440861ae650dSJack F Vogel { 440961ae650dSJack F Vogel u32 reg; 441061ae650dSJack F Vogel 441161ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 441261ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 441361ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 441461ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 441561ae650dSJack F Vogel ixl_flush(hw); 441661ae650dSJack F Vogel } 441761ae650dSJack F Vogel 441861ae650dSJack F Vogel static void 441961ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw) 442061ae650dSJack F Vogel { 442161ae650dSJack F Vogel u32 reg; 442261ae650dSJack F Vogel 442361ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 442461ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 4425223d846dSEric Joyner ixl_flush(hw); 442661ae650dSJack F Vogel } 442761ae650dSJack F Vogel 442861ae650dSJack F Vogel static void 442961ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id) 443061ae650dSJack F Vogel { 443161ae650dSJack F Vogel u32 reg; 443261ae650dSJack F Vogel 443361ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTLN_INTENA_MASK | 443461ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | 443561ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); 443661ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 443761ae650dSJack F Vogel } 443861ae650dSJack F Vogel 443961ae650dSJack F Vogel static void 444061ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id) 444161ae650dSJack F Vogel { 444261ae650dSJack F Vogel u32 reg; 444361ae650dSJack F Vogel 444461ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; 444561ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 444661ae650dSJack F Vogel } 444761ae650dSJack F Vogel 444861ae650dSJack F Vogel static void 444961ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw) 445061ae650dSJack F Vogel { 445161ae650dSJack F Vogel u32 reg; 445261ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 445361ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 445461ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 445561ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 445661ae650dSJack F Vogel } 445761ae650dSJack F Vogel 445861ae650dSJack F Vogel static void 445961ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw) 446061ae650dSJack F Vogel { 446161ae650dSJack F Vogel u32 reg; 446261ae650dSJack F Vogel 446361ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 446461ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 446561ae650dSJack F Vogel } 446661ae650dSJack F Vogel 446761ae650dSJack F Vogel static void 446861ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf) 446961ae650dSJack F Vogel { 447061ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 447161ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 447256c2c47bSJack F Vogel struct ixl_vf *vf; 447361ae650dSJack F Vogel 447461ae650dSJack F Vogel struct i40e_hw_port_stats *nsd = &pf->stats; 447561ae650dSJack F Vogel struct i40e_hw_port_stats *osd = &pf->stats_offsets; 447661ae650dSJack F Vogel 447761ae650dSJack F Vogel /* Update hw stats */ 447861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port), 447961ae650dSJack F Vogel pf->stat_offsets_loaded, 448061ae650dSJack F Vogel &osd->crc_errors, &nsd->crc_errors); 448161ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port), 448261ae650dSJack F Vogel pf->stat_offsets_loaded, 448361ae650dSJack F Vogel &osd->illegal_bytes, &nsd->illegal_bytes); 448461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port), 448561ae650dSJack F Vogel I40E_GLPRT_GORCL(hw->port), 448661ae650dSJack F Vogel pf->stat_offsets_loaded, 448761ae650dSJack F Vogel &osd->eth.rx_bytes, &nsd->eth.rx_bytes); 448861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port), 448961ae650dSJack F Vogel I40E_GLPRT_GOTCL(hw->port), 449061ae650dSJack F Vogel pf->stat_offsets_loaded, 449161ae650dSJack F Vogel &osd->eth.tx_bytes, &nsd->eth.tx_bytes); 449261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port), 449361ae650dSJack F Vogel pf->stat_offsets_loaded, 449461ae650dSJack F Vogel &osd->eth.rx_discards, 449561ae650dSJack F Vogel &nsd->eth.rx_discards); 449661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port), 449761ae650dSJack F Vogel I40E_GLPRT_UPRCL(hw->port), 449861ae650dSJack F Vogel pf->stat_offsets_loaded, 449961ae650dSJack F Vogel &osd->eth.rx_unicast, 450061ae650dSJack F Vogel &nsd->eth.rx_unicast); 450161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port), 450261ae650dSJack F Vogel I40E_GLPRT_UPTCL(hw->port), 450361ae650dSJack F Vogel pf->stat_offsets_loaded, 450461ae650dSJack F Vogel &osd->eth.tx_unicast, 450561ae650dSJack F Vogel &nsd->eth.tx_unicast); 450661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port), 450761ae650dSJack F Vogel I40E_GLPRT_MPRCL(hw->port), 450861ae650dSJack F Vogel pf->stat_offsets_loaded, 450961ae650dSJack F Vogel &osd->eth.rx_multicast, 451061ae650dSJack F Vogel &nsd->eth.rx_multicast); 451161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port), 451261ae650dSJack F Vogel I40E_GLPRT_MPTCL(hw->port), 451361ae650dSJack F Vogel pf->stat_offsets_loaded, 451461ae650dSJack F Vogel &osd->eth.tx_multicast, 451561ae650dSJack F Vogel &nsd->eth.tx_multicast); 451661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port), 451761ae650dSJack F Vogel I40E_GLPRT_BPRCL(hw->port), 451861ae650dSJack F Vogel pf->stat_offsets_loaded, 451961ae650dSJack F Vogel &osd->eth.rx_broadcast, 452061ae650dSJack F Vogel &nsd->eth.rx_broadcast); 452161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port), 452261ae650dSJack F Vogel I40E_GLPRT_BPTCL(hw->port), 452361ae650dSJack F Vogel pf->stat_offsets_loaded, 452461ae650dSJack F Vogel &osd->eth.tx_broadcast, 452561ae650dSJack F Vogel &nsd->eth.tx_broadcast); 452661ae650dSJack F Vogel 452761ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port), 452861ae650dSJack F Vogel pf->stat_offsets_loaded, 452961ae650dSJack F Vogel &osd->tx_dropped_link_down, 453061ae650dSJack F Vogel &nsd->tx_dropped_link_down); 453161ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port), 453261ae650dSJack F Vogel pf->stat_offsets_loaded, 453361ae650dSJack F Vogel &osd->mac_local_faults, 453461ae650dSJack F Vogel &nsd->mac_local_faults); 453561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port), 453661ae650dSJack F Vogel pf->stat_offsets_loaded, 453761ae650dSJack F Vogel &osd->mac_remote_faults, 453861ae650dSJack F Vogel &nsd->mac_remote_faults); 453961ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port), 454061ae650dSJack F Vogel pf->stat_offsets_loaded, 454161ae650dSJack F Vogel &osd->rx_length_errors, 454261ae650dSJack F Vogel &nsd->rx_length_errors); 454361ae650dSJack F Vogel 454461ae650dSJack F Vogel /* Flow control (LFC) stats */ 454561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port), 454661ae650dSJack F Vogel pf->stat_offsets_loaded, 454761ae650dSJack F Vogel &osd->link_xon_rx, &nsd->link_xon_rx); 454861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port), 454961ae650dSJack F Vogel pf->stat_offsets_loaded, 455061ae650dSJack F Vogel &osd->link_xon_tx, &nsd->link_xon_tx); 455161ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port), 455261ae650dSJack F Vogel pf->stat_offsets_loaded, 455361ae650dSJack F Vogel &osd->link_xoff_rx, &nsd->link_xoff_rx); 455461ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port), 455561ae650dSJack F Vogel pf->stat_offsets_loaded, 455661ae650dSJack F Vogel &osd->link_xoff_tx, &nsd->link_xoff_tx); 455761ae650dSJack F Vogel 455861ae650dSJack F Vogel /* Packet size stats rx */ 455961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port), 456061ae650dSJack F Vogel I40E_GLPRT_PRC64L(hw->port), 456161ae650dSJack F Vogel pf->stat_offsets_loaded, 456261ae650dSJack F Vogel &osd->rx_size_64, &nsd->rx_size_64); 456361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port), 456461ae650dSJack F Vogel I40E_GLPRT_PRC127L(hw->port), 456561ae650dSJack F Vogel pf->stat_offsets_loaded, 456661ae650dSJack F Vogel &osd->rx_size_127, &nsd->rx_size_127); 456761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port), 456861ae650dSJack F Vogel I40E_GLPRT_PRC255L(hw->port), 456961ae650dSJack F Vogel pf->stat_offsets_loaded, 457061ae650dSJack F Vogel &osd->rx_size_255, &nsd->rx_size_255); 457161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port), 457261ae650dSJack F Vogel I40E_GLPRT_PRC511L(hw->port), 457361ae650dSJack F Vogel pf->stat_offsets_loaded, 457461ae650dSJack F Vogel &osd->rx_size_511, &nsd->rx_size_511); 457561ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port), 457661ae650dSJack F Vogel I40E_GLPRT_PRC1023L(hw->port), 457761ae650dSJack F Vogel pf->stat_offsets_loaded, 457861ae650dSJack F Vogel &osd->rx_size_1023, &nsd->rx_size_1023); 457961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port), 458061ae650dSJack F Vogel I40E_GLPRT_PRC1522L(hw->port), 458161ae650dSJack F Vogel pf->stat_offsets_loaded, 458261ae650dSJack F Vogel &osd->rx_size_1522, &nsd->rx_size_1522); 458361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port), 458461ae650dSJack F Vogel I40E_GLPRT_PRC9522L(hw->port), 458561ae650dSJack F Vogel pf->stat_offsets_loaded, 458661ae650dSJack F Vogel &osd->rx_size_big, &nsd->rx_size_big); 458761ae650dSJack F Vogel 458861ae650dSJack F Vogel /* Packet size stats tx */ 458961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port), 459061ae650dSJack F Vogel I40E_GLPRT_PTC64L(hw->port), 459161ae650dSJack F Vogel pf->stat_offsets_loaded, 459261ae650dSJack F Vogel &osd->tx_size_64, &nsd->tx_size_64); 459361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port), 459461ae650dSJack F Vogel I40E_GLPRT_PTC127L(hw->port), 459561ae650dSJack F Vogel pf->stat_offsets_loaded, 459661ae650dSJack F Vogel &osd->tx_size_127, &nsd->tx_size_127); 459761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port), 459861ae650dSJack F Vogel I40E_GLPRT_PTC255L(hw->port), 459961ae650dSJack F Vogel pf->stat_offsets_loaded, 460061ae650dSJack F Vogel &osd->tx_size_255, &nsd->tx_size_255); 460161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port), 460261ae650dSJack F Vogel I40E_GLPRT_PTC511L(hw->port), 460361ae650dSJack F Vogel pf->stat_offsets_loaded, 460461ae650dSJack F Vogel &osd->tx_size_511, &nsd->tx_size_511); 460561ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port), 460661ae650dSJack F Vogel I40E_GLPRT_PTC1023L(hw->port), 460761ae650dSJack F Vogel pf->stat_offsets_loaded, 460861ae650dSJack F Vogel &osd->tx_size_1023, &nsd->tx_size_1023); 460961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port), 461061ae650dSJack F Vogel I40E_GLPRT_PTC1522L(hw->port), 461161ae650dSJack F Vogel pf->stat_offsets_loaded, 461261ae650dSJack F Vogel &osd->tx_size_1522, &nsd->tx_size_1522); 461361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port), 461461ae650dSJack F Vogel I40E_GLPRT_PTC9522L(hw->port), 461561ae650dSJack F Vogel pf->stat_offsets_loaded, 461661ae650dSJack F Vogel &osd->tx_size_big, &nsd->tx_size_big); 461761ae650dSJack F Vogel 461861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port), 461961ae650dSJack F Vogel pf->stat_offsets_loaded, 462061ae650dSJack F Vogel &osd->rx_undersize, &nsd->rx_undersize); 462161ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port), 462261ae650dSJack F Vogel pf->stat_offsets_loaded, 462361ae650dSJack F Vogel &osd->rx_fragments, &nsd->rx_fragments); 462461ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port), 462561ae650dSJack F Vogel pf->stat_offsets_loaded, 462661ae650dSJack F Vogel &osd->rx_oversize, &nsd->rx_oversize); 462761ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port), 462861ae650dSJack F Vogel pf->stat_offsets_loaded, 462961ae650dSJack F Vogel &osd->rx_jabber, &nsd->rx_jabber); 463061ae650dSJack F Vogel pf->stat_offsets_loaded = true; 463161ae650dSJack F Vogel /* End hw stats */ 463261ae650dSJack F Vogel 463361ae650dSJack F Vogel /* Update vsi stats */ 463456c2c47bSJack F Vogel ixl_update_vsi_stats(vsi); 463561ae650dSJack F Vogel 463656c2c47bSJack F Vogel for (int i = 0; i < pf->num_vfs; i++) { 463756c2c47bSJack F Vogel vf = &pf->vfs[i]; 463856c2c47bSJack F Vogel if (vf->vf_flags & VF_FLAG_ENABLED) 463956c2c47bSJack F Vogel ixl_update_eth_stats(&pf->vfs[i].vsi); 464056c2c47bSJack F Vogel } 464161ae650dSJack F Vogel } 464261ae650dSJack F Vogel 4643*6c426059SEric Joyner static int 4644*6c426059SEric Joyner ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf) 4645*6c426059SEric Joyner { 4646*6c426059SEric Joyner struct i40e_hw *hw = &pf->hw; 4647*6c426059SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 4648*6c426059SEric Joyner device_t dev = pf->dev; 4649*6c426059SEric Joyner bool is_up = false; 4650*6c426059SEric Joyner int error = 0; 4651*6c426059SEric Joyner 4652*6c426059SEric Joyner is_up = !!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING); 4653*6c426059SEric Joyner 4654*6c426059SEric Joyner /* Teardown */ 4655*6c426059SEric Joyner if (is_up) 4656*6c426059SEric Joyner ixl_stop(pf); 4657*6c426059SEric Joyner error = i40e_shutdown_lan_hmc(hw); 4658*6c426059SEric Joyner if (error) 4659*6c426059SEric Joyner device_printf(dev, 4660*6c426059SEric Joyner "Shutdown LAN HMC failed with code %d\n", error); 4661*6c426059SEric Joyner ixl_disable_adminq(hw); 4662*6c426059SEric Joyner ixl_teardown_adminq_msix(pf); 4663*6c426059SEric Joyner error = i40e_shutdown_adminq(hw); 4664*6c426059SEric Joyner if (error) 4665*6c426059SEric Joyner device_printf(dev, 4666*6c426059SEric Joyner "Shutdown Admin queue failed with code %d\n", error); 4667*6c426059SEric Joyner 4668*6c426059SEric Joyner /* Setup */ 4669*6c426059SEric Joyner error = i40e_init_adminq(hw); 4670*6c426059SEric Joyner if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) { 4671*6c426059SEric Joyner device_printf(dev, "Unable to initialize Admin Queue, error %d\n", 4672*6c426059SEric Joyner error); 4673*6c426059SEric Joyner } 4674*6c426059SEric Joyner error = ixl_setup_adminq_msix(pf); 4675*6c426059SEric Joyner if (error) { 4676*6c426059SEric Joyner device_printf(dev, "ixl_setup_adminq_msix error: %d\n", 4677*6c426059SEric Joyner error); 4678*6c426059SEric Joyner } 4679*6c426059SEric Joyner ixl_configure_intr0_msix(pf); 4680*6c426059SEric Joyner ixl_enable_adminq(hw); 4681*6c426059SEric Joyner /* setup hmc */ 4682*6c426059SEric Joyner error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 4683*6c426059SEric Joyner hw->func_caps.num_rx_qp, 0, 0); 4684*6c426059SEric Joyner if (error) { 4685*6c426059SEric Joyner device_printf(dev, "init_lan_hmc failed: %d\n", error); 4686*6c426059SEric Joyner } 4687*6c426059SEric Joyner error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 4688*6c426059SEric Joyner if (error) { 4689*6c426059SEric Joyner device_printf(dev, "configure_lan_hmc failed: %d\n", error); 4690*6c426059SEric Joyner } 4691*6c426059SEric Joyner if (is_up) 4692*6c426059SEric Joyner ixl_init(pf); 4693*6c426059SEric Joyner 4694*6c426059SEric Joyner return (0); 4695*6c426059SEric Joyner } 4696*6c426059SEric Joyner 4697*6c426059SEric Joyner static void 4698*6c426059SEric Joyner ixl_handle_empr_reset(struct ixl_pf *pf) 4699*6c426059SEric Joyner { 4700*6c426059SEric Joyner struct i40e_hw *hw = &pf->hw; 4701*6c426059SEric Joyner device_t dev = pf->dev; 4702*6c426059SEric Joyner int count = 0; 4703*6c426059SEric Joyner u32 reg; 4704*6c426059SEric Joyner 4705*6c426059SEric Joyner /* Typically finishes within 3-4 seconds */ 4706*6c426059SEric Joyner while (count++ < 100) { 4707*6c426059SEric Joyner reg = rd32(hw, I40E_GLGEN_RSTAT) 4708*6c426059SEric Joyner & I40E_GLGEN_RSTAT_DEVSTATE_MASK; 4709*6c426059SEric Joyner if (reg) 4710*6c426059SEric Joyner i40e_msec_delay(100); 4711*6c426059SEric Joyner else 4712*6c426059SEric Joyner break; 4713*6c426059SEric Joyner } 4714*6c426059SEric Joyner #ifdef IXL_DEBUG 4715*6c426059SEric Joyner // Reset-related 4716*6c426059SEric Joyner device_printf(dev, "EMPR reset wait count: %d\n", count); 4717*6c426059SEric Joyner #endif 4718*6c426059SEric Joyner 4719*6c426059SEric Joyner device_printf(dev, "Rebuilding driver state...\n"); 4720*6c426059SEric Joyner ixl_rebuild_hw_structs_after_reset(pf); 4721*6c426059SEric Joyner device_printf(dev, "Rebuilding driver state done.\n"); 4722*6c426059SEric Joyner 4723*6c426059SEric Joyner atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); 4724*6c426059SEric Joyner } 4725*6c426059SEric Joyner 472661ae650dSJack F Vogel /* 472761ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts 472861ae650dSJack F Vogel ** - do outside interrupt since it might sleep 472961ae650dSJack F Vogel */ 473061ae650dSJack F Vogel static void 473161ae650dSJack F Vogel ixl_do_adminq(void *context, int pending) 473261ae650dSJack F Vogel { 473361ae650dSJack F Vogel struct ixl_pf *pf = context; 473461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 473561ae650dSJack F Vogel struct i40e_arq_event_info event; 473661ae650dSJack F Vogel i40e_status ret; 4737223d846dSEric Joyner device_t dev = pf->dev; 4738*6c426059SEric Joyner u32 loop = 0; 473961ae650dSJack F Vogel u16 opcode, result; 474061ae650dSJack F Vogel 4741fdb6f38aSEric Joyner if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { 4742*6c426059SEric Joyner /* Flag cleared at end of this function */ 4743*6c426059SEric Joyner ixl_handle_empr_reset(pf); 4744fdb6f38aSEric Joyner return; 4745fdb6f38aSEric Joyner } 4746fdb6f38aSEric Joyner 4747*6c426059SEric Joyner /* Admin Queue handling */ 4748e5100ee2SJack F Vogel event.buf_len = IXL_AQ_BUF_SZ; 4749e5100ee2SJack F Vogel event.msg_buf = malloc(event.buf_len, 475061ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 475161ae650dSJack F Vogel if (!event.msg_buf) { 4752223d846dSEric Joyner device_printf(dev, "%s: Unable to allocate memory for Admin" 4753223d846dSEric Joyner " Queue event!\n", __func__); 475461ae650dSJack F Vogel return; 475561ae650dSJack F Vogel } 475661ae650dSJack F Vogel 475756c2c47bSJack F Vogel IXL_PF_LOCK(pf); 475861ae650dSJack F Vogel /* clean and process any events */ 475961ae650dSJack F Vogel do { 476061ae650dSJack F Vogel ret = i40e_clean_arq_element(hw, &event, &result); 476161ae650dSJack F Vogel if (ret) 476261ae650dSJack F Vogel break; 476361ae650dSJack F Vogel opcode = LE16_TO_CPU(event.desc.opcode); 4764223d846dSEric Joyner #ifdef IXL_DEBUG 4765*6c426059SEric Joyner device_printf(dev, "%s: Admin Queue event: %#06x\n", __func__, 4766*6c426059SEric Joyner opcode); 4767223d846dSEric Joyner #endif 476861ae650dSJack F Vogel switch (opcode) { 476961ae650dSJack F Vogel case i40e_aqc_opc_get_link_status: 477056c2c47bSJack F Vogel ixl_link_event(pf, &event); 477161ae650dSJack F Vogel break; 477261ae650dSJack F Vogel case i40e_aqc_opc_send_msg_to_pf: 477356c2c47bSJack F Vogel #ifdef PCI_IOV 477456c2c47bSJack F Vogel ixl_handle_vf_msg(pf, &event); 477556c2c47bSJack F Vogel #endif 477661ae650dSJack F Vogel break; 477761ae650dSJack F Vogel case i40e_aqc_opc_event_lan_overflow: 477861ae650dSJack F Vogel default: 477961ae650dSJack F Vogel break; 478061ae650dSJack F Vogel } 478161ae650dSJack F Vogel 478261ae650dSJack F Vogel } while (result && (loop++ < IXL_ADM_LIMIT)); 478361ae650dSJack F Vogel 478461ae650dSJack F Vogel free(event.msg_buf, M_DEVBUF); 478561ae650dSJack F Vogel 478656c2c47bSJack F Vogel /* 478756c2c47bSJack F Vogel * If there are still messages to process, reschedule ourselves. 478856c2c47bSJack F Vogel * Otherwise, re-enable our interrupt and go to sleep. 478956c2c47bSJack F Vogel */ 479056c2c47bSJack F Vogel if (result > 0) 479156c2c47bSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 479261ae650dSJack F Vogel else 4793223d846dSEric Joyner ixl_enable_adminq(hw); 479456c2c47bSJack F Vogel 479556c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 479661ae650dSJack F Vogel } 479761ae650dSJack F Vogel 479861ae650dSJack F Vogel /** 479961ae650dSJack F Vogel * Update VSI-specific ethernet statistics counters. 480061ae650dSJack F Vogel **/ 480161ae650dSJack F Vogel void ixl_update_eth_stats(struct ixl_vsi *vsi) 480261ae650dSJack F Vogel { 480361ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 480461ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 480561ae650dSJack F Vogel struct i40e_eth_stats *es; 480661ae650dSJack F Vogel struct i40e_eth_stats *oes; 48074b443922SGleb Smirnoff struct i40e_hw_port_stats *nsd; 480861ae650dSJack F Vogel u16 stat_idx = vsi->info.stat_counter_idx; 480961ae650dSJack F Vogel 481061ae650dSJack F Vogel es = &vsi->eth_stats; 481161ae650dSJack F Vogel oes = &vsi->eth_stats_offsets; 48124b443922SGleb Smirnoff nsd = &pf->stats; 481361ae650dSJack F Vogel 481461ae650dSJack F Vogel /* Gather up the stats that the hw collects */ 481561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx), 481661ae650dSJack F Vogel vsi->stat_offsets_loaded, 481761ae650dSJack F Vogel &oes->tx_errors, &es->tx_errors); 481861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx), 481961ae650dSJack F Vogel vsi->stat_offsets_loaded, 482061ae650dSJack F Vogel &oes->rx_discards, &es->rx_discards); 482161ae650dSJack F Vogel 482261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx), 482361ae650dSJack F Vogel I40E_GLV_GORCL(stat_idx), 482461ae650dSJack F Vogel vsi->stat_offsets_loaded, 482561ae650dSJack F Vogel &oes->rx_bytes, &es->rx_bytes); 482661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx), 482761ae650dSJack F Vogel I40E_GLV_UPRCL(stat_idx), 482861ae650dSJack F Vogel vsi->stat_offsets_loaded, 482961ae650dSJack F Vogel &oes->rx_unicast, &es->rx_unicast); 483061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx), 483161ae650dSJack F Vogel I40E_GLV_MPRCL(stat_idx), 483261ae650dSJack F Vogel vsi->stat_offsets_loaded, 483361ae650dSJack F Vogel &oes->rx_multicast, &es->rx_multicast); 483461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx), 483561ae650dSJack F Vogel I40E_GLV_BPRCL(stat_idx), 483661ae650dSJack F Vogel vsi->stat_offsets_loaded, 483761ae650dSJack F Vogel &oes->rx_broadcast, &es->rx_broadcast); 483861ae650dSJack F Vogel 483961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx), 484061ae650dSJack F Vogel I40E_GLV_GOTCL(stat_idx), 484161ae650dSJack F Vogel vsi->stat_offsets_loaded, 484261ae650dSJack F Vogel &oes->tx_bytes, &es->tx_bytes); 484361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx), 484461ae650dSJack F Vogel I40E_GLV_UPTCL(stat_idx), 484561ae650dSJack F Vogel vsi->stat_offsets_loaded, 484661ae650dSJack F Vogel &oes->tx_unicast, &es->tx_unicast); 484761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx), 484861ae650dSJack F Vogel I40E_GLV_MPTCL(stat_idx), 484961ae650dSJack F Vogel vsi->stat_offsets_loaded, 485061ae650dSJack F Vogel &oes->tx_multicast, &es->tx_multicast); 485161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx), 485261ae650dSJack F Vogel I40E_GLV_BPTCL(stat_idx), 485361ae650dSJack F Vogel vsi->stat_offsets_loaded, 485461ae650dSJack F Vogel &oes->tx_broadcast, &es->tx_broadcast); 485561ae650dSJack F Vogel vsi->stat_offsets_loaded = true; 485656c2c47bSJack F Vogel } 485756c2c47bSJack F Vogel 485856c2c47bSJack F Vogel static void 485956c2c47bSJack F Vogel ixl_update_vsi_stats(struct ixl_vsi *vsi) 486056c2c47bSJack F Vogel { 486156c2c47bSJack F Vogel struct ixl_pf *pf; 486256c2c47bSJack F Vogel struct ifnet *ifp; 486356c2c47bSJack F Vogel struct i40e_eth_stats *es; 486456c2c47bSJack F Vogel u64 tx_discards; 486556c2c47bSJack F Vogel 486656c2c47bSJack F Vogel struct i40e_hw_port_stats *nsd; 486756c2c47bSJack F Vogel 486856c2c47bSJack F Vogel pf = vsi->back; 486956c2c47bSJack F Vogel ifp = vsi->ifp; 487056c2c47bSJack F Vogel es = &vsi->eth_stats; 487156c2c47bSJack F Vogel nsd = &pf->stats; 487256c2c47bSJack F Vogel 487356c2c47bSJack F Vogel ixl_update_eth_stats(vsi); 487461ae650dSJack F Vogel 48754b443922SGleb Smirnoff tx_discards = es->tx_discards + nsd->tx_dropped_link_down; 487656c2c47bSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) 48774b443922SGleb Smirnoff tx_discards += vsi->queues[i].txr.br->br_drops; 487861ae650dSJack F Vogel 48794b443922SGleb Smirnoff /* Update ifnet stats */ 48804b443922SGleb Smirnoff IXL_SET_IPACKETS(vsi, es->rx_unicast + 48814b443922SGleb Smirnoff es->rx_multicast + 48824b443922SGleb Smirnoff es->rx_broadcast); 48834b443922SGleb Smirnoff IXL_SET_OPACKETS(vsi, es->tx_unicast + 48844b443922SGleb Smirnoff es->tx_multicast + 48854b443922SGleb Smirnoff es->tx_broadcast); 48864b443922SGleb Smirnoff IXL_SET_IBYTES(vsi, es->rx_bytes); 48874b443922SGleb Smirnoff IXL_SET_OBYTES(vsi, es->tx_bytes); 48884b443922SGleb Smirnoff IXL_SET_IMCASTS(vsi, es->rx_multicast); 48894b443922SGleb Smirnoff IXL_SET_OMCASTS(vsi, es->tx_multicast); 48904b443922SGleb Smirnoff 489156c2c47bSJack F Vogel IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes + 489256c2c47bSJack F Vogel nsd->rx_undersize + nsd->rx_oversize + nsd->rx_fragments + 489356c2c47bSJack F Vogel nsd->rx_jabber); 48944b443922SGleb Smirnoff IXL_SET_OERRORS(vsi, es->tx_errors); 48954b443922SGleb Smirnoff IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards); 48964b443922SGleb Smirnoff IXL_SET_OQDROPS(vsi, tx_discards); 48974b443922SGleb Smirnoff IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol); 48984b443922SGleb Smirnoff IXL_SET_COLLISIONS(vsi, 0); 489961ae650dSJack F Vogel } 490061ae650dSJack F Vogel 490161ae650dSJack F Vogel /** 490261ae650dSJack F Vogel * Reset all of the stats for the given pf 490361ae650dSJack F Vogel **/ 490461ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf) 490561ae650dSJack F Vogel { 490661ae650dSJack F Vogel bzero(&pf->stats, sizeof(struct i40e_hw_port_stats)); 490761ae650dSJack F Vogel bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats)); 490861ae650dSJack F Vogel pf->stat_offsets_loaded = false; 490961ae650dSJack F Vogel } 491061ae650dSJack F Vogel 491161ae650dSJack F Vogel /** 491261ae650dSJack F Vogel * Resets all stats of the given vsi 491361ae650dSJack F Vogel **/ 491461ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi) 491561ae650dSJack F Vogel { 491661ae650dSJack F Vogel bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats)); 491761ae650dSJack F Vogel bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats)); 491861ae650dSJack F Vogel vsi->stat_offsets_loaded = false; 491961ae650dSJack F Vogel } 492061ae650dSJack F Vogel 492161ae650dSJack F Vogel /** 492261ae650dSJack F Vogel * Read and update a 48 bit stat from the hw 492361ae650dSJack F Vogel * 492461ae650dSJack F Vogel * Since the device stats are not reset at PFReset, they likely will not 492561ae650dSJack F Vogel * be zeroed when the driver starts. We'll save the first values read 492661ae650dSJack F Vogel * and use them as offsets to be subtracted from the raw values in order 492761ae650dSJack F Vogel * to report stats that count from zero. 492861ae650dSJack F Vogel **/ 492961ae650dSJack F Vogel static void 493061ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg, 493161ae650dSJack F Vogel bool offset_loaded, u64 *offset, u64 *stat) 493261ae650dSJack F Vogel { 493361ae650dSJack F Vogel u64 new_data; 493461ae650dSJack F Vogel 4935ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__) 493661ae650dSJack F Vogel new_data = rd64(hw, loreg); 493761ae650dSJack F Vogel #else 493861ae650dSJack F Vogel /* 493961ae650dSJack F Vogel * Use two rd32's instead of one rd64; FreeBSD versions before 494061ae650dSJack F Vogel * 10 don't support 8 byte bus reads/writes. 494161ae650dSJack F Vogel */ 494261ae650dSJack F Vogel new_data = rd32(hw, loreg); 494361ae650dSJack F Vogel new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32; 494461ae650dSJack F Vogel #endif 494561ae650dSJack F Vogel 494661ae650dSJack F Vogel if (!offset_loaded) 494761ae650dSJack F Vogel *offset = new_data; 494861ae650dSJack F Vogel if (new_data >= *offset) 494961ae650dSJack F Vogel *stat = new_data - *offset; 495061ae650dSJack F Vogel else 495161ae650dSJack F Vogel *stat = (new_data + ((u64)1 << 48)) - *offset; 495261ae650dSJack F Vogel *stat &= 0xFFFFFFFFFFFFULL; 495361ae650dSJack F Vogel } 495461ae650dSJack F Vogel 495561ae650dSJack F Vogel /** 495661ae650dSJack F Vogel * Read and update a 32 bit stat from the hw 495761ae650dSJack F Vogel **/ 495861ae650dSJack F Vogel static void 495961ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg, 496061ae650dSJack F Vogel bool offset_loaded, u64 *offset, u64 *stat) 496161ae650dSJack F Vogel { 496261ae650dSJack F Vogel u32 new_data; 496361ae650dSJack F Vogel 496461ae650dSJack F Vogel new_data = rd32(hw, reg); 496561ae650dSJack F Vogel if (!offset_loaded) 496661ae650dSJack F Vogel *offset = new_data; 496761ae650dSJack F Vogel if (new_data >= *offset) 496861ae650dSJack F Vogel *stat = (u32)(new_data - *offset); 496961ae650dSJack F Vogel else 497061ae650dSJack F Vogel *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); 497161ae650dSJack F Vogel } 497261ae650dSJack F Vogel 4973fdb6f38aSEric Joyner static void 4974fdb6f38aSEric Joyner ixl_add_device_sysctls(struct ixl_pf *pf) 4975fdb6f38aSEric Joyner { 4976fdb6f38aSEric Joyner device_t dev = pf->dev; 4977fdb6f38aSEric Joyner 4978fdb6f38aSEric Joyner /* Set up sysctls */ 4979fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4980fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4981fdb6f38aSEric Joyner OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, 498295bb0504SEric Joyner pf, 0, ixl_set_flowcntl, "I", IXL_SYSCTL_HELP_FC); 4983fdb6f38aSEric Joyner 4984fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4985fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4986fdb6f38aSEric Joyner OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, 498795bb0504SEric Joyner pf, 0, ixl_set_advertise, "I", IXL_SYSCTL_HELP_SET_ADVERTISE); 4988fdb6f38aSEric Joyner 4989fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4990fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4991fdb6f38aSEric Joyner OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD, 4992fdb6f38aSEric Joyner pf, 0, ixl_current_speed, "A", "Current Port Speed"); 4993fdb6f38aSEric Joyner 4994fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 4995fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 4996fdb6f38aSEric Joyner OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD, 4997fdb6f38aSEric Joyner pf, 0, ixl_sysctl_show_fw, "A", "Firmware version"); 4998fdb6f38aSEric Joyner 4999fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5000fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5001fdb6f38aSEric Joyner OID_AUTO, "rx_itr", CTLFLAG_RW, 5002fdb6f38aSEric Joyner &ixl_rx_itr, IXL_ITR_8K, "RX ITR"); 5003fdb6f38aSEric Joyner 5004fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5005fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5006fdb6f38aSEric Joyner OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW, 5007fdb6f38aSEric Joyner &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR"); 5008fdb6f38aSEric Joyner 5009fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5010fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5011fdb6f38aSEric Joyner OID_AUTO, "tx_itr", CTLFLAG_RW, 5012fdb6f38aSEric Joyner &ixl_tx_itr, IXL_ITR_4K, "TX ITR"); 5013fdb6f38aSEric Joyner 5014fdb6f38aSEric Joyner SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5015fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5016fdb6f38aSEric Joyner OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW, 5017fdb6f38aSEric Joyner &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR"); 5018fdb6f38aSEric Joyner 5019fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL 5020fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5021fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5022fdb6f38aSEric Joyner OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0, 5023fdb6f38aSEric Joyner ixl_debug_info, "I", "Debug Information"); 5024fdb6f38aSEric Joyner 502595bb0504SEric Joyner /* Shared-code debug message level */ 5026fdb6f38aSEric Joyner SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 5027fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5028fdb6f38aSEric Joyner OID_AUTO, "debug_mask", CTLFLAG_RW, 5029fdb6f38aSEric Joyner &pf->hw.debug_mask, 0, "Debug Message Level"); 5030fdb6f38aSEric Joyner 5031fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5032fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5033fdb6f38aSEric Joyner OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD, 503495bb0504SEric Joyner pf, 0, ixl_sysctl_link_status, "A", IXL_SYSCTL_HELP_LINK_STATUS); 5035fdb6f38aSEric Joyner 5036fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5037fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5038fdb6f38aSEric Joyner OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD, 5039fdb6f38aSEric Joyner pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities"); 5040fdb6f38aSEric Joyner 5041fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5042fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5043fdb6f38aSEric Joyner OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD, 5044fdb6f38aSEric Joyner pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List"); 5045fdb6f38aSEric Joyner 5046fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5047fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5048fdb6f38aSEric Joyner OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD, 5049fdb6f38aSEric Joyner pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation"); 5050fdb6f38aSEric Joyner 5051fdb6f38aSEric Joyner SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5052fdb6f38aSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5053fdb6f38aSEric Joyner OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD, 5054fdb6f38aSEric Joyner pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration"); 505595bb0504SEric Joyner 505695bb0504SEric Joyner #ifdef PCI_IOV 505795bb0504SEric Joyner SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 505895bb0504SEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 505995bb0504SEric Joyner OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl, 506095bb0504SEric Joyner 0, "PF/VF Virtual Channel debug level"); 506195bb0504SEric Joyner #endif 5062fdb6f38aSEric Joyner #endif 5063fdb6f38aSEric Joyner } 5064fdb6f38aSEric Joyner 506561ae650dSJack F Vogel /* 506661ae650dSJack F Vogel ** Set flow control using sysctl: 506761ae650dSJack F Vogel ** 0 - off 506861ae650dSJack F Vogel ** 1 - rx pause 506961ae650dSJack F Vogel ** 2 - tx pause 507061ae650dSJack F Vogel ** 3 - full 507161ae650dSJack F Vogel */ 507261ae650dSJack F Vogel static int 507361ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS) 507461ae650dSJack F Vogel { 507561ae650dSJack F Vogel /* 507661ae650dSJack F Vogel * TODO: ensure tx CRC by hardware should be enabled 507761ae650dSJack F Vogel * if tx flow control is enabled. 5078223d846dSEric Joyner * ^ N/A for 40G ports 507961ae650dSJack F Vogel */ 508061ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 508161ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 508261ae650dSJack F Vogel device_t dev = pf->dev; 5083*6c426059SEric Joyner int requested_fc, error = 0; 508461ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 508561ae650dSJack F Vogel u8 fc_aq_err = 0; 508661ae650dSJack F Vogel 5087b6c8f260SJack F Vogel /* Get request */ 5088*6c426059SEric Joyner requested_fc = pf->fc; 5089*6c426059SEric Joyner error = sysctl_handle_int(oidp, &requested_fc, 0, req); 509061ae650dSJack F Vogel if ((error) || (req->newptr == NULL)) 509161ae650dSJack F Vogel return (error); 5092*6c426059SEric Joyner if (requested_fc < 0 || requested_fc > 3) { 509361ae650dSJack F Vogel device_printf(dev, 509461ae650dSJack F Vogel "Invalid fc mode; valid modes are 0 through 3\n"); 509561ae650dSJack F Vogel return (EINVAL); 509661ae650dSJack F Vogel } 509761ae650dSJack F Vogel 509861ae650dSJack F Vogel /* 509961ae650dSJack F Vogel ** Changing flow control mode currently does not work on 510061ae650dSJack F Vogel ** 40GBASE-CR4 PHYs 510161ae650dSJack F Vogel */ 510261ae650dSJack F Vogel if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4 510361ae650dSJack F Vogel || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) { 510461ae650dSJack F Vogel device_printf(dev, "Changing flow control mode unsupported" 510561ae650dSJack F Vogel " on 40GBase-CR4 media.\n"); 510661ae650dSJack F Vogel return (ENODEV); 510761ae650dSJack F Vogel } 510861ae650dSJack F Vogel 510961ae650dSJack F Vogel /* Set fc ability for port */ 5110*6c426059SEric Joyner hw->fc.requested_mode = requested_fc; 511161ae650dSJack F Vogel aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE); 511261ae650dSJack F Vogel if (aq_error) { 511361ae650dSJack F Vogel device_printf(dev, 511461ae650dSJack F Vogel "%s: Error setting new fc mode %d; fc_err %#x\n", 511561ae650dSJack F Vogel __func__, aq_error, fc_aq_err); 5116223d846dSEric Joyner return (EIO); 511761ae650dSJack F Vogel } 5118*6c426059SEric Joyner pf->fc = requested_fc; 511961ae650dSJack F Vogel 5120223d846dSEric Joyner /* Get new link state */ 5121223d846dSEric Joyner i40e_msec_delay(250); 5122223d846dSEric Joyner hw->phy.get_link_info = TRUE; 5123223d846dSEric Joyner i40e_get_link_status(hw, &pf->link_up); 5124223d846dSEric Joyner 512561ae650dSJack F Vogel return (0); 512661ae650dSJack F Vogel } 512761ae650dSJack F Vogel 512861ae650dSJack F Vogel static int 512961ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS) 513061ae650dSJack F Vogel { 513161ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 513261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 513361ae650dSJack F Vogel int error = 0, index = 0; 513461ae650dSJack F Vogel 513561ae650dSJack F Vogel char *speeds[] = { 513661ae650dSJack F Vogel "Unknown", 513761ae650dSJack F Vogel "100M", 513861ae650dSJack F Vogel "1G", 513961ae650dSJack F Vogel "10G", 514061ae650dSJack F Vogel "40G", 514161ae650dSJack F Vogel "20G" 514261ae650dSJack F Vogel }; 514361ae650dSJack F Vogel 514461ae650dSJack F Vogel ixl_update_link_status(pf); 514561ae650dSJack F Vogel 514661ae650dSJack F Vogel switch (hw->phy.link_info.link_speed) { 514761ae650dSJack F Vogel case I40E_LINK_SPEED_100MB: 514861ae650dSJack F Vogel index = 1; 514961ae650dSJack F Vogel break; 515061ae650dSJack F Vogel case I40E_LINK_SPEED_1GB: 515161ae650dSJack F Vogel index = 2; 515261ae650dSJack F Vogel break; 515361ae650dSJack F Vogel case I40E_LINK_SPEED_10GB: 515461ae650dSJack F Vogel index = 3; 515561ae650dSJack F Vogel break; 515661ae650dSJack F Vogel case I40E_LINK_SPEED_40GB: 515761ae650dSJack F Vogel index = 4; 515861ae650dSJack F Vogel break; 515961ae650dSJack F Vogel case I40E_LINK_SPEED_20GB: 516061ae650dSJack F Vogel index = 5; 516161ae650dSJack F Vogel break; 516261ae650dSJack F Vogel case I40E_LINK_SPEED_UNKNOWN: 516361ae650dSJack F Vogel default: 516461ae650dSJack F Vogel index = 0; 516561ae650dSJack F Vogel break; 516661ae650dSJack F Vogel } 516761ae650dSJack F Vogel 516861ae650dSJack F Vogel error = sysctl_handle_string(oidp, speeds[index], 516961ae650dSJack F Vogel strlen(speeds[index]), req); 517061ae650dSJack F Vogel return (error); 517161ae650dSJack F Vogel } 517261ae650dSJack F Vogel 5173e5100ee2SJack F Vogel static int 5174e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds) 5175e5100ee2SJack F Vogel { 5176e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 5177e5100ee2SJack F Vogel device_t dev = pf->dev; 5178e5100ee2SJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 5179e5100ee2SJack F Vogel struct i40e_aq_set_phy_config config; 5180e5100ee2SJack F Vogel enum i40e_status_code aq_error = 0; 5181e5100ee2SJack F Vogel 5182e5100ee2SJack F Vogel /* Get current capability information */ 5183b6c8f260SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 5184b6c8f260SJack F Vogel FALSE, FALSE, &abilities, NULL); 5185e5100ee2SJack F Vogel if (aq_error) { 5186b6c8f260SJack F Vogel device_printf(dev, 5187b6c8f260SJack F Vogel "%s: Error getting phy capabilities %d," 5188e5100ee2SJack F Vogel " aq error: %d\n", __func__, aq_error, 5189e5100ee2SJack F Vogel hw->aq.asq_last_status); 5190e5100ee2SJack F Vogel return (EAGAIN); 5191e5100ee2SJack F Vogel } 5192e5100ee2SJack F Vogel 5193e5100ee2SJack F Vogel /* Prepare new config */ 5194e5100ee2SJack F Vogel bzero(&config, sizeof(config)); 5195e5100ee2SJack F Vogel config.phy_type = abilities.phy_type; 5196e5100ee2SJack F Vogel config.abilities = abilities.abilities 5197e5100ee2SJack F Vogel | I40E_AQ_PHY_ENABLE_ATOMIC_LINK; 5198e5100ee2SJack F Vogel config.eee_capability = abilities.eee_capability; 5199e5100ee2SJack F Vogel config.eeer = abilities.eeer_val; 5200e5100ee2SJack F Vogel config.low_power_ctrl = abilities.d3_lpan; 5201e5100ee2SJack F Vogel /* Translate into aq cmd link_speed */ 52021d767a8eSEric Joyner if (speeds & 0x10) 52031d767a8eSEric Joyner config.link_speed |= I40E_LINK_SPEED_40GB; 520456c2c47bSJack F Vogel if (speeds & 0x8) 520556c2c47bSJack F Vogel config.link_speed |= I40E_LINK_SPEED_20GB; 5206e5100ee2SJack F Vogel if (speeds & 0x4) 5207e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_10GB; 5208e5100ee2SJack F Vogel if (speeds & 0x2) 5209e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_1GB; 5210e5100ee2SJack F Vogel if (speeds & 0x1) 5211e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_100MB; 5212e5100ee2SJack F Vogel 5213e5100ee2SJack F Vogel /* Do aq command & restart link */ 5214e5100ee2SJack F Vogel aq_error = i40e_aq_set_phy_config(hw, &config, NULL); 5215e5100ee2SJack F Vogel if (aq_error) { 5216b6c8f260SJack F Vogel device_printf(dev, 5217b6c8f260SJack F Vogel "%s: Error setting new phy config %d," 5218e5100ee2SJack F Vogel " aq error: %d\n", __func__, aq_error, 5219e5100ee2SJack F Vogel hw->aq.asq_last_status); 5220e5100ee2SJack F Vogel return (EAGAIN); 5221e5100ee2SJack F Vogel } 5222e5100ee2SJack F Vogel 5223393c4bb1SJack F Vogel /* 5224393c4bb1SJack F Vogel ** This seems a bit heavy handed, but we 5225393c4bb1SJack F Vogel ** need to get a reinit on some devices 5226393c4bb1SJack F Vogel */ 5227393c4bb1SJack F Vogel IXL_PF_LOCK(pf); 5228223d846dSEric Joyner ixl_stop_locked(pf); 5229393c4bb1SJack F Vogel ixl_init_locked(pf); 5230393c4bb1SJack F Vogel IXL_PF_UNLOCK(pf); 5231393c4bb1SJack F Vogel 5232e5100ee2SJack F Vogel return (0); 5233e5100ee2SJack F Vogel } 5234e5100ee2SJack F Vogel 523561ae650dSJack F Vogel /* 523661ae650dSJack F Vogel ** Control link advertise speed: 523761ae650dSJack F Vogel ** Flags: 523861ae650dSJack F Vogel ** 0x1 - advertise 100 Mb 523961ae650dSJack F Vogel ** 0x2 - advertise 1G 524061ae650dSJack F Vogel ** 0x4 - advertise 10G 524156c2c47bSJack F Vogel ** 0x8 - advertise 20G 52421d767a8eSEric Joyner ** 0x10 - advertise 40G 524361ae650dSJack F Vogel ** 52441d767a8eSEric Joyner ** Set to 0 to disable link 524561ae650dSJack F Vogel */ 524661ae650dSJack F Vogel static int 524761ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS) 524861ae650dSJack F Vogel { 524961ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 525061ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 525161ae650dSJack F Vogel device_t dev = pf->dev; 525261ae650dSJack F Vogel int requested_ls = 0; 525361ae650dSJack F Vogel int error = 0; 525461ae650dSJack F Vogel 525561ae650dSJack F Vogel /* Read in new mode */ 525661ae650dSJack F Vogel requested_ls = pf->advertised_speed; 525761ae650dSJack F Vogel error = sysctl_handle_int(oidp, &requested_ls, 0, req); 525861ae650dSJack F Vogel if ((error) || (req->newptr == NULL)) 525961ae650dSJack F Vogel return (error); 526056c2c47bSJack F Vogel /* Check for sane value */ 52611d767a8eSEric Joyner if (requested_ls > 0x10) { 526256c2c47bSJack F Vogel device_printf(dev, "Invalid advertised speed; " 52631d767a8eSEric Joyner "valid modes are 0x1 through 0x10\n"); 526461ae650dSJack F Vogel return (EINVAL); 526561ae650dSJack F Vogel } 526656c2c47bSJack F Vogel /* Then check for validity based on adapter type */ 526756c2c47bSJack F Vogel switch (hw->device_id) { 526856c2c47bSJack F Vogel case I40E_DEV_ID_10G_BASE_T: 5269ac83ea83SEric Joyner case I40E_DEV_ID_10G_BASE_T4: 52701d767a8eSEric Joyner /* BaseT */ 52711d767a8eSEric Joyner if (requested_ls & ~(0x7)) { 527256c2c47bSJack F Vogel device_printf(dev, 52731d767a8eSEric Joyner "Only 100M/1G/10G speeds supported on this device.\n"); 527456c2c47bSJack F Vogel return (EINVAL); 527556c2c47bSJack F Vogel } 527656c2c47bSJack F Vogel break; 527756c2c47bSJack F Vogel case I40E_DEV_ID_20G_KR2: 5278ac83ea83SEric Joyner case I40E_DEV_ID_20G_KR2_A: 52791d767a8eSEric Joyner /* 20G */ 52801d767a8eSEric Joyner if (requested_ls & ~(0xE)) { 528156c2c47bSJack F Vogel device_printf(dev, 52821d767a8eSEric Joyner "Only 1G/10G/20G speeds supported on this device.\n"); 52831d767a8eSEric Joyner return (EINVAL); 52841d767a8eSEric Joyner } 52851d767a8eSEric Joyner break; 52861d767a8eSEric Joyner case I40E_DEV_ID_KX_B: 52871d767a8eSEric Joyner case I40E_DEV_ID_QSFP_A: 52881d767a8eSEric Joyner case I40E_DEV_ID_QSFP_B: 52891d767a8eSEric Joyner /* 40G */ 52901d767a8eSEric Joyner if (requested_ls & ~(0x10)) { 52911d767a8eSEric Joyner device_printf(dev, 52921d767a8eSEric Joyner "Only 40G speeds supported on this device.\n"); 529356c2c47bSJack F Vogel return (EINVAL); 529456c2c47bSJack F Vogel } 529556c2c47bSJack F Vogel break; 529656c2c47bSJack F Vogel default: 52971d767a8eSEric Joyner /* 10G (1G) */ 52981d767a8eSEric Joyner if (requested_ls & ~(0x6)) { 529956c2c47bSJack F Vogel device_printf(dev, 530056c2c47bSJack F Vogel "Only 1/10Gbs speeds are supported on this device.\n"); 530156c2c47bSJack F Vogel return (EINVAL); 530256c2c47bSJack F Vogel } 530356c2c47bSJack F Vogel break; 530456c2c47bSJack F Vogel } 530561ae650dSJack F Vogel 530661ae650dSJack F Vogel /* Exit if no change */ 530761ae650dSJack F Vogel if (pf->advertised_speed == requested_ls) 530861ae650dSJack F Vogel return (0); 530961ae650dSJack F Vogel 5310e5100ee2SJack F Vogel error = ixl_set_advertised_speeds(pf, requested_ls); 5311e5100ee2SJack F Vogel if (error) 5312e5100ee2SJack F Vogel return (error); 531361ae650dSJack F Vogel 531461ae650dSJack F Vogel pf->advertised_speed = requested_ls; 531561ae650dSJack F Vogel ixl_update_link_status(pf); 531661ae650dSJack F Vogel return (0); 531761ae650dSJack F Vogel } 531861ae650dSJack F Vogel 531961ae650dSJack F Vogel /* 532061ae650dSJack F Vogel ** Get the width and transaction speed of 532161ae650dSJack F Vogel ** the bus this adapter is plugged into. 532261ae650dSJack F Vogel */ 532361ae650dSJack F Vogel static u16 532461ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev) 532561ae650dSJack F Vogel { 532661ae650dSJack F Vogel u16 link; 532761ae650dSJack F Vogel u32 offset; 532861ae650dSJack F Vogel 532961ae650dSJack F Vogel /* Get the PCI Express Capabilities offset */ 533061ae650dSJack F Vogel pci_find_cap(dev, PCIY_EXPRESS, &offset); 533161ae650dSJack F Vogel 533261ae650dSJack F Vogel /* ...and read the Link Status Register */ 533361ae650dSJack F Vogel link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 533461ae650dSJack F Vogel 533561ae650dSJack F Vogel switch (link & I40E_PCI_LINK_WIDTH) { 533661ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_1: 533761ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x1; 533861ae650dSJack F Vogel break; 533961ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_2: 534061ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x2; 534161ae650dSJack F Vogel break; 534261ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_4: 534361ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x4; 534461ae650dSJack F Vogel break; 534561ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_8: 534661ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x8; 534761ae650dSJack F Vogel break; 534861ae650dSJack F Vogel default: 534961ae650dSJack F Vogel hw->bus.width = i40e_bus_width_unknown; 535061ae650dSJack F Vogel break; 535161ae650dSJack F Vogel } 535261ae650dSJack F Vogel 535361ae650dSJack F Vogel switch (link & I40E_PCI_LINK_SPEED) { 535461ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_2500: 535561ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_2500; 535661ae650dSJack F Vogel break; 535761ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_5000: 535861ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_5000; 535961ae650dSJack F Vogel break; 536061ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_8000: 536161ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_8000; 536261ae650dSJack F Vogel break; 536361ae650dSJack F Vogel default: 536461ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_unknown; 536561ae650dSJack F Vogel break; 536661ae650dSJack F Vogel } 536761ae650dSJack F Vogel 536861ae650dSJack F Vogel 536961ae650dSJack F Vogel device_printf(dev,"PCI Express Bus: Speed %s %s\n", 537061ae650dSJack F Vogel ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s": 537161ae650dSJack F Vogel (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s": 537261ae650dSJack F Vogel (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"), 537361ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" : 537461ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" : 537561ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" : 537661ae650dSJack F Vogel ("Unknown")); 537761ae650dSJack F Vogel 537861ae650dSJack F Vogel if ((hw->bus.width <= i40e_bus_width_pcie_x8) && 537961ae650dSJack F Vogel (hw->bus.speed < i40e_bus_speed_8000)) { 538061ae650dSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 538156c2c47bSJack F Vogel " for this device\n may be insufficient for" 538256c2c47bSJack F Vogel " optimal performance.\n"); 538361ae650dSJack F Vogel device_printf(dev, "For expected performance a x8 " 538461ae650dSJack F Vogel "PCIE Gen3 slot is required.\n"); 538561ae650dSJack F Vogel } 538661ae650dSJack F Vogel 538761ae650dSJack F Vogel return (link); 538861ae650dSJack F Vogel } 538961ae650dSJack F Vogel 5390e5100ee2SJack F Vogel static int 5391e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS) 5392e5100ee2SJack F Vogel { 5393e5100ee2SJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 5394e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 53951d767a8eSEric Joyner struct sbuf *sbuf; 5396e5100ee2SJack F Vogel 53971d767a8eSEric Joyner sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 53981d767a8eSEric Joyner ixl_nvm_version_str(hw, sbuf); 53991d767a8eSEric Joyner sbuf_finish(sbuf); 54001d767a8eSEric Joyner sbuf_delete(sbuf); 54011d767a8eSEric Joyner 54021d767a8eSEric Joyner return 0; 5403e5100ee2SJack F Vogel } 5404e5100ee2SJack F Vogel 5405*6c426059SEric Joyner inline void 5406*6c426059SEric Joyner ixl_print_nvm_cmd(device_t dev, struct i40e_nvm_access *nvma) 5407*6c426059SEric Joyner { 5408*6c426059SEric Joyner if ((nvma->command == I40E_NVM_READ) && 5409*6c426059SEric Joyner ((nvma->config & 0xFF) == 0xF) && 5410*6c426059SEric Joyner (((nvma->config & 0xF00) >> 8) == 0xF) && 5411*6c426059SEric Joyner (nvma->offset == 0) && 5412*6c426059SEric Joyner (nvma->data_size == 1)) { 5413*6c426059SEric Joyner // device_printf(dev, "- Get Driver Status Command\n"); 5414*6c426059SEric Joyner } 5415*6c426059SEric Joyner else if (nvma->command == I40E_NVM_READ) { 5416*6c426059SEric Joyner 5417*6c426059SEric Joyner } 5418*6c426059SEric Joyner else { 5419*6c426059SEric Joyner switch (nvma->command) { 5420*6c426059SEric Joyner case 0xB: 5421*6c426059SEric Joyner device_printf(dev, "- command: I40E_NVM_READ\n"); 5422*6c426059SEric Joyner break; 5423*6c426059SEric Joyner case 0xC: 5424*6c426059SEric Joyner device_printf(dev, "- command: I40E_NVM_WRITE\n"); 5425*6c426059SEric Joyner break; 5426*6c426059SEric Joyner default: 5427*6c426059SEric Joyner device_printf(dev, "- command: unknown 0x%08x\n", nvma->command); 5428*6c426059SEric Joyner break; 5429*6c426059SEric Joyner } 5430*6c426059SEric Joyner 5431*6c426059SEric Joyner device_printf(dev, "- config (ptr) : 0x%02x\n", nvma->config & 0xFF); 5432*6c426059SEric Joyner device_printf(dev, "- config (flags): 0x%01x\n", (nvma->config & 0xF00) >> 8); 5433*6c426059SEric Joyner device_printf(dev, "- offset : 0x%08x\n", nvma->offset); 5434*6c426059SEric Joyner device_printf(dev, "- data_s : 0x%08x\n", nvma->data_size); 5435*6c426059SEric Joyner } 5436*6c426059SEric Joyner } 5437*6c426059SEric Joyner 5438223d846dSEric Joyner static int 5439223d846dSEric Joyner ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd) 5440223d846dSEric Joyner { 5441223d846dSEric Joyner struct i40e_hw *hw = &pf->hw; 5442223d846dSEric Joyner struct i40e_nvm_access *nvma; 5443223d846dSEric Joyner device_t dev = pf->dev; 5444223d846dSEric Joyner enum i40e_status_code status = 0; 5445223d846dSEric Joyner int perrno; 5446223d846dSEric Joyner 5447223d846dSEric Joyner DEBUGFUNC("ixl_handle_nvmupd_cmd"); 5448223d846dSEric Joyner 5449*6c426059SEric Joyner /* Sanity checks */ 5450223d846dSEric Joyner if (ifd->ifd_len < sizeof(struct i40e_nvm_access) || 5451223d846dSEric Joyner ifd->ifd_data == NULL) { 5452*6c426059SEric Joyner device_printf(dev, "%s: incorrect ifdrv length or data pointer\n", 5453*6c426059SEric Joyner __func__); 5454*6c426059SEric Joyner device_printf(dev, "%s: ifdrv length: %lu, sizeof(struct i40e_nvm_access): %lu\n", 5455*6c426059SEric Joyner __func__, ifd->ifd_len, sizeof(struct i40e_nvm_access)); 5456*6c426059SEric Joyner device_printf(dev, "%s: data pointer: %p\n", __func__, 5457*6c426059SEric Joyner ifd->ifd_data); 5458223d846dSEric Joyner return (EINVAL); 5459223d846dSEric Joyner } 5460223d846dSEric Joyner 5461223d846dSEric Joyner nvma = (struct i40e_nvm_access *)ifd->ifd_data; 5462223d846dSEric Joyner 5463*6c426059SEric Joyner #ifdef IXL_DEBUG 5464*6c426059SEric Joyner ixl_print_nvm_cmd(dev, nvma); 5465*6c426059SEric Joyner #endif 5466*6c426059SEric Joyner 5467fdb6f38aSEric Joyner if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { 5468fdb6f38aSEric Joyner int count = 0; 5469fdb6f38aSEric Joyner while (count++ < 100) { 5470fdb6f38aSEric Joyner i40e_msec_delay(100); 5471fdb6f38aSEric Joyner if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) 5472fdb6f38aSEric Joyner break; 5473fdb6f38aSEric Joyner } 5474fdb6f38aSEric Joyner } 5475fdb6f38aSEric Joyner 5476fdb6f38aSEric Joyner if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) { 5477fdb6f38aSEric Joyner IXL_PF_LOCK(pf); 5478223d846dSEric Joyner status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno); 5479fdb6f38aSEric Joyner IXL_PF_UNLOCK(pf); 5480fdb6f38aSEric Joyner } else { 5481fdb6f38aSEric Joyner perrno = -EBUSY; 5482fdb6f38aSEric Joyner } 5483fdb6f38aSEric Joyner 54847f70bec6SEric Joyner if (status) 54857f70bec6SEric Joyner device_printf(dev, "i40e_nvmupd_command status %d, perrno %d\n", 54867f70bec6SEric Joyner status, perrno); 5487223d846dSEric Joyner 5488fdb6f38aSEric Joyner /* 5489fdb6f38aSEric Joyner * -EPERM is actually ERESTART, which the kernel interprets as it needing 5490fdb6f38aSEric Joyner * to run this ioctl again. So use -EACCES for -EPERM instead. 5491fdb6f38aSEric Joyner */ 54927f70bec6SEric Joyner if (perrno == -EPERM) 54937f70bec6SEric Joyner return (-EACCES); 54947f70bec6SEric Joyner else 54957f70bec6SEric Joyner return (perrno); 5496223d846dSEric Joyner } 5497e5100ee2SJack F Vogel 5498393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL 549961ae650dSJack F Vogel static int 550061ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS) 550161ae650dSJack F Vogel { 550261ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 550361ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 550461ae650dSJack F Vogel struct i40e_link_status link_status; 550561ae650dSJack F Vogel char buf[512]; 550661ae650dSJack F Vogel 550761ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 550861ae650dSJack F Vogel 550961ae650dSJack F Vogel aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL); 551061ae650dSJack F Vogel if (aq_error) { 551161ae650dSJack F Vogel printf("i40e_aq_get_link_info() error %d\n", aq_error); 551261ae650dSJack F Vogel return (EPERM); 551361ae650dSJack F Vogel } 551461ae650dSJack F Vogel 551561ae650dSJack F Vogel sprintf(buf, "\n" 551661ae650dSJack F Vogel "PHY Type : %#04x\n" 551761ae650dSJack F Vogel "Speed : %#04x\n" 551861ae650dSJack F Vogel "Link info: %#04x\n" 551961ae650dSJack F Vogel "AN info : %#04x\n" 552095bb0504SEric Joyner "Ext info : %#04x\n" 552195bb0504SEric Joyner "Max Frame: %d\n" 55221d767a8eSEric Joyner "Pacing : %#04x\n" 55231d767a8eSEric Joyner "CRC En? : %d", 552461ae650dSJack F Vogel link_status.phy_type, link_status.link_speed, 552561ae650dSJack F Vogel link_status.link_info, link_status.an_info, 552695bb0504SEric Joyner link_status.ext_info, link_status.max_frame_size, 55271d767a8eSEric Joyner link_status.pacing, link_status.crc_enable); 552861ae650dSJack F Vogel 552961ae650dSJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 553061ae650dSJack F Vogel } 553161ae650dSJack F Vogel 553261ae650dSJack F Vogel static int 553361ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS) 553461ae650dSJack F Vogel { 553561ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 553661ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 553761ae650dSJack F Vogel char buf[512]; 553861ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 553961ae650dSJack F Vogel 554056c2c47bSJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 554156c2c47bSJack F Vogel 554256c2c47bSJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 554356c2c47bSJack F Vogel TRUE, FALSE, &abilities, NULL); 554461ae650dSJack F Vogel if (aq_error) { 554561ae650dSJack F Vogel printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error); 554661ae650dSJack F Vogel return (EPERM); 554761ae650dSJack F Vogel } 554861ae650dSJack F Vogel 554961ae650dSJack F Vogel sprintf(buf, "\n" 555061ae650dSJack F Vogel "PHY Type : %#010x\n" 555161ae650dSJack F Vogel "Speed : %#04x\n" 555261ae650dSJack F Vogel "Abilities: %#04x\n" 555361ae650dSJack F Vogel "EEE cap : %#06x\n" 555461ae650dSJack F Vogel "EEER reg : %#010x\n" 555561ae650dSJack F Vogel "D3 Lpan : %#04x", 555656c2c47bSJack F Vogel abilities.phy_type, abilities.link_speed, 555756c2c47bSJack F Vogel abilities.abilities, abilities.eee_capability, 555856c2c47bSJack F Vogel abilities.eeer_val, abilities.d3_lpan); 555961ae650dSJack F Vogel 556061ae650dSJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 556161ae650dSJack F Vogel } 556261ae650dSJack F Vogel 556361ae650dSJack F Vogel static int 556461ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS) 556561ae650dSJack F Vogel { 556661ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 556761ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 556861ae650dSJack F Vogel struct ixl_mac_filter *f; 556961ae650dSJack F Vogel char *buf, *buf_i; 557061ae650dSJack F Vogel 557161ae650dSJack F Vogel int error = 0; 557261ae650dSJack F Vogel int ftl_len = 0; 557361ae650dSJack F Vogel int ftl_counter = 0; 557461ae650dSJack F Vogel int buf_len = 0; 557561ae650dSJack F Vogel int entry_len = 42; 557661ae650dSJack F Vogel 557761ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 557861ae650dSJack F Vogel ftl_len++; 557961ae650dSJack F Vogel } 558061ae650dSJack F Vogel 558161ae650dSJack F Vogel if (ftl_len < 1) { 558261ae650dSJack F Vogel sysctl_handle_string(oidp, "(none)", 6, req); 558361ae650dSJack F Vogel return (0); 558461ae650dSJack F Vogel } 558561ae650dSJack F Vogel 558661ae650dSJack F Vogel buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2; 558761ae650dSJack F Vogel buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT); 558861ae650dSJack F Vogel 558961ae650dSJack F Vogel sprintf(buf_i++, "\n"); 559061ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 559161ae650dSJack F Vogel sprintf(buf_i, 559261ae650dSJack F Vogel MAC_FORMAT ", vlan %4d, flags %#06x", 559361ae650dSJack F Vogel MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags); 559461ae650dSJack F Vogel buf_i += entry_len; 559561ae650dSJack F Vogel /* don't print '\n' for last entry */ 559661ae650dSJack F Vogel if (++ftl_counter != ftl_len) { 559761ae650dSJack F Vogel sprintf(buf_i, "\n"); 559861ae650dSJack F Vogel buf_i++; 559961ae650dSJack F Vogel } 560061ae650dSJack F Vogel } 560161ae650dSJack F Vogel 560261ae650dSJack F Vogel error = sysctl_handle_string(oidp, buf, strlen(buf), req); 560361ae650dSJack F Vogel if (error) 560461ae650dSJack F Vogel printf("sysctl error: %d\n", error); 560561ae650dSJack F Vogel free(buf, M_DEVBUF); 560661ae650dSJack F Vogel return error; 560761ae650dSJack F Vogel } 560861ae650dSJack F Vogel 560961ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14 561061ae650dSJack F Vogel static int 5611393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b) 5612393c4bb1SJack F Vogel { 5613393c4bb1SJack F Vogel const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two; 5614be771cdaSJack F Vogel one = (const struct i40e_aqc_switch_resource_alloc_element_resp *)a; 5615be771cdaSJack F Vogel two = (const struct i40e_aqc_switch_resource_alloc_element_resp *)b; 5616393c4bb1SJack F Vogel 5617393c4bb1SJack F Vogel return ((int)one->resource_type - (int)two->resource_type); 5618393c4bb1SJack F Vogel } 5619393c4bb1SJack F Vogel 5620fdb6f38aSEric Joyner /* 5621fdb6f38aSEric Joyner * Longest string length: 25 5622fdb6f38aSEric Joyner */ 5623fdb6f38aSEric Joyner static char * 5624fdb6f38aSEric Joyner ixl_switch_res_type_string(u8 type) 5625fdb6f38aSEric Joyner { 5626fdb6f38aSEric Joyner static char * ixl_switch_res_type_strings[0x14] = { 5627fdb6f38aSEric Joyner "VEB", 5628fdb6f38aSEric Joyner "VSI", 5629fdb6f38aSEric Joyner "Perfect Match MAC address", 5630fdb6f38aSEric Joyner "S-tag", 5631fdb6f38aSEric Joyner "(Reserved)", 5632fdb6f38aSEric Joyner "Multicast hash entry", 5633fdb6f38aSEric Joyner "Unicast hash entry", 5634fdb6f38aSEric Joyner "VLAN", 5635fdb6f38aSEric Joyner "VSI List entry", 5636fdb6f38aSEric Joyner "(Reserved)", 5637fdb6f38aSEric Joyner "VLAN Statistic Pool", 5638fdb6f38aSEric Joyner "Mirror Rule", 5639fdb6f38aSEric Joyner "Queue Set", 5640fdb6f38aSEric Joyner "Inner VLAN Forward filter", 5641fdb6f38aSEric Joyner "(Reserved)", 5642fdb6f38aSEric Joyner "Inner MAC", 5643fdb6f38aSEric Joyner "IP", 5644fdb6f38aSEric Joyner "GRE/VN1 Key", 5645fdb6f38aSEric Joyner "VN2 Key", 5646fdb6f38aSEric Joyner "Tunneling Port" 5647fdb6f38aSEric Joyner }; 5648fdb6f38aSEric Joyner 5649fdb6f38aSEric Joyner if (type < 0x14) 5650fdb6f38aSEric Joyner return ixl_switch_res_type_strings[type]; 5651fdb6f38aSEric Joyner else 5652fdb6f38aSEric Joyner return "(Reserved)"; 5653fdb6f38aSEric Joyner } 5654fdb6f38aSEric Joyner 5655393c4bb1SJack F Vogel static int 5656e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS) 565761ae650dSJack F Vogel { 565861ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 565961ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 566061ae650dSJack F Vogel device_t dev = pf->dev; 566161ae650dSJack F Vogel struct sbuf *buf; 566261ae650dSJack F Vogel int error = 0; 566361ae650dSJack F Vogel 566461ae650dSJack F Vogel u8 num_entries; 566561ae650dSJack F Vogel struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE]; 566661ae650dSJack F Vogel 5667a48d00d2SEric Joyner buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 566861ae650dSJack F Vogel if (!buf) { 566961ae650dSJack F Vogel device_printf(dev, "Could not allocate sbuf for output.\n"); 567061ae650dSJack F Vogel return (ENOMEM); 567161ae650dSJack F Vogel } 567261ae650dSJack F Vogel 5673393c4bb1SJack F Vogel bzero(resp, sizeof(resp)); 567461ae650dSJack F Vogel error = i40e_aq_get_switch_resource_alloc(hw, &num_entries, 567561ae650dSJack F Vogel resp, 567661ae650dSJack F Vogel IXL_SW_RES_SIZE, 567761ae650dSJack F Vogel NULL); 567861ae650dSJack F Vogel if (error) { 567956c2c47bSJack F Vogel device_printf(dev, 568056c2c47bSJack F Vogel "%s: get_switch_resource_alloc() error %d, aq error %d\n", 568161ae650dSJack F Vogel __func__, error, hw->aq.asq_last_status); 568261ae650dSJack F Vogel sbuf_delete(buf); 568361ae650dSJack F Vogel return error; 568461ae650dSJack F Vogel } 5685393c4bb1SJack F Vogel 5686393c4bb1SJack F Vogel /* Sort entries by type for display */ 5687393c4bb1SJack F Vogel qsort(resp, num_entries, 5688393c4bb1SJack F Vogel sizeof(struct i40e_aqc_switch_resource_alloc_element_resp), 5689393c4bb1SJack F Vogel &ixl_res_alloc_cmp); 569061ae650dSJack F Vogel 569161ae650dSJack F Vogel sbuf_cat(buf, "\n"); 5692393c4bb1SJack F Vogel sbuf_printf(buf, "# of entries: %d\n", num_entries); 569361ae650dSJack F Vogel sbuf_printf(buf, 5694fdb6f38aSEric Joyner #if 0 5695fdb6f38aSEric Joyner "Type | Guaranteed | Total | Used | Un-allocated\n" 5696fdb6f38aSEric Joyner " | (this) | (all) | (this) | (all) \n"); 5697fdb6f38aSEric Joyner #endif 569861ae650dSJack F Vogel " Type | Guaranteed | Total | Used | Un-allocated\n" 569961ae650dSJack F Vogel " | (this) | (all) | (this) | (all) \n"); 570061ae650dSJack F Vogel for (int i = 0; i < num_entries; i++) { 570161ae650dSJack F Vogel sbuf_printf(buf, 5702fdb6f38aSEric Joyner #if 0 570361ae650dSJack F Vogel "%#4x | %10d %5d %6d %12d", 570461ae650dSJack F Vogel resp[i].resource_type, 5705fdb6f38aSEric Joyner #endif 5706fdb6f38aSEric Joyner "%25s | %10d %5d %6d %12d", 5707fdb6f38aSEric Joyner ixl_switch_res_type_string(resp[i].resource_type), 570861ae650dSJack F Vogel resp[i].guaranteed, 570961ae650dSJack F Vogel resp[i].total, 571061ae650dSJack F Vogel resp[i].used, 571161ae650dSJack F Vogel resp[i].total_unalloced); 571261ae650dSJack F Vogel if (i < num_entries - 1) 571361ae650dSJack F Vogel sbuf_cat(buf, "\n"); 571461ae650dSJack F Vogel } 571561ae650dSJack F Vogel 571661ae650dSJack F Vogel error = sbuf_finish(buf); 5717ac83ea83SEric Joyner if (error) 5718a48d00d2SEric Joyner device_printf(dev, "Error finishing sbuf: %d\n", error); 5719a48d00d2SEric Joyner 5720ac83ea83SEric Joyner sbuf_delete(buf); 5721ac83ea83SEric Joyner return error; 5722e5100ee2SJack F Vogel } 572361ae650dSJack F Vogel 5724e5100ee2SJack F Vogel /* 5725e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and 5726e5100ee2SJack F Vogel ** finish it for caller. 5727fdb6f38aSEric Joyner ** 5728fdb6f38aSEric Joyner ** XXX: Cannot use the SEID for this, since there is no longer a 5729fdb6f38aSEric Joyner ** fixed mapping between SEID and element type. 5730e5100ee2SJack F Vogel */ 5731e5100ee2SJack F Vogel static char * 5732fdb6f38aSEric Joyner ixl_switch_element_string(struct sbuf *s, 5733fdb6f38aSEric Joyner struct i40e_aqc_switch_config_element_resp *element) 5734e5100ee2SJack F Vogel { 5735e5100ee2SJack F Vogel sbuf_clear(s); 5736e5100ee2SJack F Vogel 5737fdb6f38aSEric Joyner switch (element->element_type) { 5738fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_MAC: 5739fdb6f38aSEric Joyner sbuf_printf(s, "MAC %3d", element->element_info); 5740fdb6f38aSEric Joyner break; 5741fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_PF: 5742fdb6f38aSEric Joyner sbuf_printf(s, "PF %3d", element->element_info); 5743fdb6f38aSEric Joyner break; 5744fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_VF: 5745fdb6f38aSEric Joyner sbuf_printf(s, "VF %3d", element->element_info); 5746fdb6f38aSEric Joyner break; 5747fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_EMP: 5748e5100ee2SJack F Vogel sbuf_cat(s, "EMP"); 5749fdb6f38aSEric Joyner break; 5750fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_BMC: 5751fdb6f38aSEric Joyner sbuf_cat(s, "BMC"); 5752fdb6f38aSEric Joyner break; 5753fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_PV: 5754fdb6f38aSEric Joyner sbuf_cat(s, "PV"); 5755fdb6f38aSEric Joyner break; 5756fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_VEB: 5757fdb6f38aSEric Joyner sbuf_cat(s, "VEB"); 5758fdb6f38aSEric Joyner break; 5759fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_PA: 5760fdb6f38aSEric Joyner sbuf_cat(s, "PA"); 5761fdb6f38aSEric Joyner break; 5762fdb6f38aSEric Joyner case I40E_AQ_SW_ELEM_TYPE_VSI: 5763fdb6f38aSEric Joyner sbuf_printf(s, "VSI %3d", element->element_info); 5764fdb6f38aSEric Joyner break; 5765fdb6f38aSEric Joyner default: 5766fdb6f38aSEric Joyner sbuf_cat(s, "?"); 5767fdb6f38aSEric Joyner break; 5768fdb6f38aSEric Joyner } 5769e5100ee2SJack F Vogel 5770e5100ee2SJack F Vogel sbuf_finish(s); 5771e5100ee2SJack F Vogel return sbuf_data(s); 5772e5100ee2SJack F Vogel } 5773e5100ee2SJack F Vogel 5774e5100ee2SJack F Vogel static int 5775e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS) 5776e5100ee2SJack F Vogel { 5777e5100ee2SJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 5778e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 5779e5100ee2SJack F Vogel device_t dev = pf->dev; 5780e5100ee2SJack F Vogel struct sbuf *buf; 5781e5100ee2SJack F Vogel struct sbuf *nmbuf; 5782e5100ee2SJack F Vogel int error = 0; 5783fdb6f38aSEric Joyner u16 next = 0; 5784e5100ee2SJack F Vogel u8 aq_buf[I40E_AQ_LARGE_BUF]; 5785e5100ee2SJack F Vogel 5786e5100ee2SJack F Vogel struct i40e_aqc_get_switch_config_resp *sw_config; 5787e5100ee2SJack F Vogel sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 5788e5100ee2SJack F Vogel 5789a48d00d2SEric Joyner buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5790e5100ee2SJack F Vogel if (!buf) { 5791e5100ee2SJack F Vogel device_printf(dev, "Could not allocate sbuf for sysctl output.\n"); 5792e5100ee2SJack F Vogel return (ENOMEM); 5793e5100ee2SJack F Vogel } 5794e5100ee2SJack F Vogel 5795e5100ee2SJack F Vogel error = i40e_aq_get_switch_config(hw, sw_config, 5796e5100ee2SJack F Vogel sizeof(aq_buf), &next, NULL); 5797e5100ee2SJack F Vogel if (error) { 579856c2c47bSJack F Vogel device_printf(dev, 579956c2c47bSJack F Vogel "%s: aq_get_switch_config() error %d, aq error %d\n", 5800e5100ee2SJack F Vogel __func__, error, hw->aq.asq_last_status); 5801e5100ee2SJack F Vogel sbuf_delete(buf); 5802e5100ee2SJack F Vogel return error; 5803e5100ee2SJack F Vogel } 5804fdb6f38aSEric Joyner if (next) 5805fdb6f38aSEric Joyner device_printf(dev, "%s: TODO: get more config with SEID %d\n", 5806fdb6f38aSEric Joyner __func__, next); 5807e5100ee2SJack F Vogel 5808e5100ee2SJack F Vogel nmbuf = sbuf_new_auto(); 5809e5100ee2SJack F Vogel if (!nmbuf) { 5810e5100ee2SJack F Vogel device_printf(dev, "Could not allocate sbuf for name output.\n"); 5811a48d00d2SEric Joyner sbuf_delete(buf); 5812e5100ee2SJack F Vogel return (ENOMEM); 5813e5100ee2SJack F Vogel } 5814e5100ee2SJack F Vogel 5815e5100ee2SJack F Vogel sbuf_cat(buf, "\n"); 5816e5100ee2SJack F Vogel // Assuming <= 255 elements in switch 5817fdb6f38aSEric Joyner sbuf_printf(buf, "# of reported elements: %d\n", sw_config->header.num_reported); 5818fdb6f38aSEric Joyner sbuf_printf(buf, "total # of elements: %d\n", sw_config->header.num_total); 5819e5100ee2SJack F Vogel /* Exclude: 5820e5100ee2SJack F Vogel ** Revision -- all elements are revision 1 for now 5821e5100ee2SJack F Vogel */ 5822e5100ee2SJack F Vogel sbuf_printf(buf, 5823e5100ee2SJack F Vogel "SEID ( Name ) | Uplink | Downlink | Conn Type\n" 5824e5100ee2SJack F Vogel " | | | (uplink)\n"); 5825e5100ee2SJack F Vogel for (int i = 0; i < sw_config->header.num_reported; i++) { 5826e5100ee2SJack F Vogel // "%4d (%8s) | %8s %8s %#8x", 5827e5100ee2SJack F Vogel sbuf_printf(buf, "%4d", sw_config->element[i].seid); 5828e5100ee2SJack F Vogel sbuf_cat(buf, " "); 582956c2c47bSJack F Vogel sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf, 5830fdb6f38aSEric Joyner &sw_config->element[i])); 5831e5100ee2SJack F Vogel sbuf_cat(buf, " | "); 5832fdb6f38aSEric Joyner sbuf_printf(buf, "%8d", sw_config->element[i].uplink_seid); 5833e5100ee2SJack F Vogel sbuf_cat(buf, " "); 5834fdb6f38aSEric Joyner sbuf_printf(buf, "%8d", sw_config->element[i].downlink_seid); 5835e5100ee2SJack F Vogel sbuf_cat(buf, " "); 5836e5100ee2SJack F Vogel sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type); 5837e5100ee2SJack F Vogel if (i < sw_config->header.num_reported - 1) 5838e5100ee2SJack F Vogel sbuf_cat(buf, "\n"); 5839e5100ee2SJack F Vogel } 5840e5100ee2SJack F Vogel sbuf_delete(nmbuf); 5841e5100ee2SJack F Vogel 5842e5100ee2SJack F Vogel error = sbuf_finish(buf); 5843ac83ea83SEric Joyner if (error) 5844a48d00d2SEric Joyner device_printf(dev, "Error finishing sbuf: %d\n", error); 5845a48d00d2SEric Joyner 5846e5100ee2SJack F Vogel sbuf_delete(buf); 5847e5100ee2SJack F Vogel 5848e5100ee2SJack F Vogel return (error); 584961ae650dSJack F Vogel } 58501d767a8eSEric Joyner 58511d767a8eSEric Joyner static int 58521d767a8eSEric Joyner ixl_debug_info(SYSCTL_HANDLER_ARGS) 58531d767a8eSEric Joyner { 58541d767a8eSEric Joyner struct ixl_pf *pf; 58551d767a8eSEric Joyner int error, input = 0; 58561d767a8eSEric Joyner 58571d767a8eSEric Joyner error = sysctl_handle_int(oidp, &input, 0, req); 58581d767a8eSEric Joyner 58591d767a8eSEric Joyner if (error || !req->newptr) 58601d767a8eSEric Joyner return (error); 58611d767a8eSEric Joyner 58621d767a8eSEric Joyner if (input == 1) { 58631d767a8eSEric Joyner pf = (struct ixl_pf *)arg1; 58641d767a8eSEric Joyner ixl_print_debug_info(pf); 58651d767a8eSEric Joyner } 58661d767a8eSEric Joyner 58671d767a8eSEric Joyner return (error); 58681d767a8eSEric Joyner } 58691d767a8eSEric Joyner 58701d767a8eSEric Joyner static void 58711d767a8eSEric Joyner ixl_print_debug_info(struct ixl_pf *pf) 58721d767a8eSEric Joyner { 58731d767a8eSEric Joyner struct i40e_hw *hw = &pf->hw; 58741d767a8eSEric Joyner struct ixl_vsi *vsi = &pf->vsi; 58751d767a8eSEric Joyner struct ixl_queue *que = vsi->queues; 58761d767a8eSEric Joyner struct rx_ring *rxr = &que->rxr; 58771d767a8eSEric Joyner struct tx_ring *txr = &que->txr; 58781d767a8eSEric Joyner u32 reg; 58791d767a8eSEric Joyner 58801d767a8eSEric Joyner 58811d767a8eSEric Joyner printf("Queue irqs = %jx\n", (uintmax_t)que->irqs); 58821d767a8eSEric Joyner printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq); 58831d767a8eSEric Joyner printf("RX next check = %x\n", rxr->next_check); 58841d767a8eSEric Joyner printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done); 58851d767a8eSEric Joyner printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets); 58861d767a8eSEric Joyner printf("TX desc avail = %x\n", txr->avail); 58871d767a8eSEric Joyner 58881d767a8eSEric Joyner reg = rd32(hw, I40E_GLV_GORCL(0xc)); 58891d767a8eSEric Joyner printf("RX Bytes = %x\n", reg); 58901d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_GORCL(hw->port)); 58911d767a8eSEric Joyner printf("Port RX Bytes = %x\n", reg); 58921d767a8eSEric Joyner reg = rd32(hw, I40E_GLV_RDPC(0xc)); 58931d767a8eSEric Joyner printf("RX discard = %x\n", reg); 58941d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_RDPC(hw->port)); 58951d767a8eSEric Joyner printf("Port RX discard = %x\n", reg); 58961d767a8eSEric Joyner 58971d767a8eSEric Joyner reg = rd32(hw, I40E_GLV_TEPC(0xc)); 58981d767a8eSEric Joyner printf("TX errors = %x\n", reg); 58991d767a8eSEric Joyner reg = rd32(hw, I40E_GLV_GOTCL(0xc)); 59001d767a8eSEric Joyner printf("TX Bytes = %x\n", reg); 59011d767a8eSEric Joyner 59021d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_RUC(hw->port)); 59031d767a8eSEric Joyner printf("RX undersize = %x\n", reg); 59041d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_RFC(hw->port)); 59051d767a8eSEric Joyner printf("RX fragments = %x\n", reg); 59061d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_ROC(hw->port)); 59071d767a8eSEric Joyner printf("RX oversize = %x\n", reg); 59081d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_RLEC(hw->port)); 59091d767a8eSEric Joyner printf("RX length error = %x\n", reg); 59101d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_MRFC(hw->port)); 59111d767a8eSEric Joyner printf("mac remote fault = %x\n", reg); 59121d767a8eSEric Joyner reg = rd32(hw, I40E_GLPRT_MLFC(hw->port)); 59131d767a8eSEric Joyner printf("mac local fault = %x\n", reg); 59141d767a8eSEric Joyner } 59151d767a8eSEric Joyner 5916393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */ 591761ae650dSJack F Vogel 591856c2c47bSJack F Vogel #ifdef PCI_IOV 591956c2c47bSJack F Vogel static int 592056c2c47bSJack F Vogel ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf) 592156c2c47bSJack F Vogel { 592256c2c47bSJack F Vogel struct i40e_hw *hw; 592356c2c47bSJack F Vogel struct ixl_vsi *vsi; 592456c2c47bSJack F Vogel struct i40e_vsi_context vsi_ctx; 592556c2c47bSJack F Vogel int i; 592656c2c47bSJack F Vogel uint16_t first_queue; 592756c2c47bSJack F Vogel enum i40e_status_code code; 592856c2c47bSJack F Vogel 592956c2c47bSJack F Vogel hw = &pf->hw; 593056c2c47bSJack F Vogel vsi = &pf->vsi; 593156c2c47bSJack F Vogel 593256c2c47bSJack F Vogel vsi_ctx.pf_num = hw->pf_id; 593356c2c47bSJack F Vogel vsi_ctx.uplink_seid = pf->veb_seid; 593456c2c47bSJack F Vogel vsi_ctx.connection_type = IXL_VSI_DATA_PORT; 593556c2c47bSJack F Vogel vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num; 593656c2c47bSJack F Vogel vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF; 593756c2c47bSJack F Vogel 593856c2c47bSJack F Vogel bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); 593956c2c47bSJack F Vogel 594056c2c47bSJack F Vogel vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID); 594156c2c47bSJack F Vogel vsi_ctx.info.switch_id = htole16(0); 594256c2c47bSJack F Vogel 594356c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID); 594456c2c47bSJack F Vogel vsi_ctx.info.sec_flags = 0; 594556c2c47bSJack F Vogel if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF) 594656c2c47bSJack F Vogel vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK; 594756c2c47bSJack F Vogel 594895bb0504SEric Joyner /* TODO: If a port VLAN is set, then this needs to be changed */ 594956c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID); 595056c2c47bSJack F Vogel vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 595156c2c47bSJack F Vogel I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 595256c2c47bSJack F Vogel 595356c2c47bSJack F Vogel vsi_ctx.info.valid_sections |= 595456c2c47bSJack F Vogel htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID); 595556c2c47bSJack F Vogel vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG); 595656c2c47bSJack F Vogel first_queue = vsi->num_queues + vf->vf_num * IXLV_MAX_QUEUES; 595756c2c47bSJack F Vogel for (i = 0; i < IXLV_MAX_QUEUES; i++) 595856c2c47bSJack F Vogel vsi_ctx.info.queue_mapping[i] = htole16(first_queue + i); 595956c2c47bSJack F Vogel for (; i < nitems(vsi_ctx.info.queue_mapping); i++) 596056c2c47bSJack F Vogel vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK); 596156c2c47bSJack F Vogel 596256c2c47bSJack F Vogel vsi_ctx.info.tc_mapping[0] = htole16( 596356c2c47bSJack F Vogel (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) | 596456c2c47bSJack F Vogel (1 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)); 596556c2c47bSJack F Vogel 596656c2c47bSJack F Vogel code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL); 596756c2c47bSJack F Vogel if (code != I40E_SUCCESS) 596856c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 596956c2c47bSJack F Vogel vf->vsi.seid = vsi_ctx.seid; 597056c2c47bSJack F Vogel vf->vsi.vsi_num = vsi_ctx.vsi_number; 597156c2c47bSJack F Vogel vf->vsi.first_queue = first_queue; 597256c2c47bSJack F Vogel vf->vsi.num_queues = IXLV_MAX_QUEUES; 597356c2c47bSJack F Vogel 597456c2c47bSJack F Vogel code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL); 597556c2c47bSJack F Vogel if (code != I40E_SUCCESS) 597656c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 597756c2c47bSJack F Vogel 597856c2c47bSJack F Vogel code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL); 597956c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 598056c2c47bSJack F Vogel device_printf(pf->dev, "Failed to disable BW limit: %d\n", 598156c2c47bSJack F Vogel ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 598256c2c47bSJack F Vogel return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 598356c2c47bSJack F Vogel } 598456c2c47bSJack F Vogel 598556c2c47bSJack F Vogel memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info)); 598656c2c47bSJack F Vogel return (0); 598756c2c47bSJack F Vogel } 598856c2c47bSJack F Vogel 598956c2c47bSJack F Vogel static int 599056c2c47bSJack F Vogel ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf) 599156c2c47bSJack F Vogel { 599256c2c47bSJack F Vogel struct i40e_hw *hw; 599356c2c47bSJack F Vogel int error; 599456c2c47bSJack F Vogel 599556c2c47bSJack F Vogel hw = &pf->hw; 599656c2c47bSJack F Vogel 599756c2c47bSJack F Vogel error = ixl_vf_alloc_vsi(pf, vf); 599856c2c47bSJack F Vogel if (error != 0) 599956c2c47bSJack F Vogel return (error); 600056c2c47bSJack F Vogel 600156c2c47bSJack F Vogel vf->vsi.hw_filters_add = 0; 600256c2c47bSJack F Vogel vf->vsi.hw_filters_del = 0; 600356c2c47bSJack F Vogel ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY); 600456c2c47bSJack F Vogel ixl_reconfigure_filters(&vf->vsi); 600556c2c47bSJack F Vogel 600656c2c47bSJack F Vogel return (0); 600756c2c47bSJack F Vogel } 600856c2c47bSJack F Vogel 600956c2c47bSJack F Vogel static void 601056c2c47bSJack F Vogel ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum, 601156c2c47bSJack F Vogel uint32_t val) 601256c2c47bSJack F Vogel { 601356c2c47bSJack F Vogel uint32_t qtable; 601456c2c47bSJack F Vogel int index, shift; 601556c2c47bSJack F Vogel 601656c2c47bSJack F Vogel /* 601756c2c47bSJack F Vogel * Two queues are mapped in a single register, so we have to do some 601856c2c47bSJack F Vogel * gymnastics to convert the queue number into a register index and 601956c2c47bSJack F Vogel * shift. 602056c2c47bSJack F Vogel */ 602156c2c47bSJack F Vogel index = qnum / 2; 602256c2c47bSJack F Vogel shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT; 602356c2c47bSJack F Vogel 602456c2c47bSJack F Vogel qtable = rd32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num)); 602556c2c47bSJack F Vogel qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift); 602656c2c47bSJack F Vogel qtable |= val << shift; 602756c2c47bSJack F Vogel wr32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable); 602856c2c47bSJack F Vogel } 602956c2c47bSJack F Vogel 603056c2c47bSJack F Vogel static void 603156c2c47bSJack F Vogel ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf) 603256c2c47bSJack F Vogel { 603356c2c47bSJack F Vogel struct i40e_hw *hw; 603456c2c47bSJack F Vogel uint32_t qtable; 603556c2c47bSJack F Vogel int i; 603656c2c47bSJack F Vogel 603756c2c47bSJack F Vogel hw = &pf->hw; 603856c2c47bSJack F Vogel 603956c2c47bSJack F Vogel /* 604056c2c47bSJack F Vogel * Contiguous mappings aren't actually supported by the hardware, 604156c2c47bSJack F Vogel * so we have to use non-contiguous mappings. 604256c2c47bSJack F Vogel */ 604356c2c47bSJack F Vogel wr32(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num), 604456c2c47bSJack F Vogel I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK); 604556c2c47bSJack F Vogel 604656c2c47bSJack F Vogel wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num), 604756c2c47bSJack F Vogel I40E_VPLAN_MAPENA_TXRX_ENA_MASK); 604856c2c47bSJack F Vogel 604956c2c47bSJack F Vogel for (i = 0; i < vf->vsi.num_queues; i++) { 605056c2c47bSJack F Vogel qtable = (vf->vsi.first_queue + i) << 605156c2c47bSJack F Vogel I40E_VPLAN_QTABLE_QINDEX_SHIFT; 605256c2c47bSJack F Vogel 605356c2c47bSJack F Vogel wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable); 605456c2c47bSJack F Vogel } 605556c2c47bSJack F Vogel 605656c2c47bSJack F Vogel /* Map queues allocated to VF to its VSI. */ 605756c2c47bSJack F Vogel for (i = 0; i < vf->vsi.num_queues; i++) 605856c2c47bSJack F Vogel ixl_vf_map_vsi_queue(hw, vf, i, vf->vsi.first_queue + i); 605956c2c47bSJack F Vogel 606056c2c47bSJack F Vogel /* Set rest of VSI queues as unused. */ 606156c2c47bSJack F Vogel for (; i < IXL_MAX_VSI_QUEUES; i++) 606256c2c47bSJack F Vogel ixl_vf_map_vsi_queue(hw, vf, i, 606356c2c47bSJack F Vogel I40E_VSILAN_QTABLE_QINDEX_0_MASK); 606456c2c47bSJack F Vogel 606556c2c47bSJack F Vogel ixl_flush(hw); 606656c2c47bSJack F Vogel } 606756c2c47bSJack F Vogel 606856c2c47bSJack F Vogel static void 606956c2c47bSJack F Vogel ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi) 607056c2c47bSJack F Vogel { 607156c2c47bSJack F Vogel struct i40e_hw *hw; 607256c2c47bSJack F Vogel 607356c2c47bSJack F Vogel hw = &pf->hw; 607456c2c47bSJack F Vogel 607556c2c47bSJack F Vogel if (vsi->seid == 0) 607656c2c47bSJack F Vogel return; 607756c2c47bSJack F Vogel 607856c2c47bSJack F Vogel i40e_aq_delete_element(hw, vsi->seid, NULL); 607956c2c47bSJack F Vogel } 608056c2c47bSJack F Vogel 608156c2c47bSJack F Vogel static void 608256c2c47bSJack F Vogel ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg) 608356c2c47bSJack F Vogel { 608456c2c47bSJack F Vogel 608556c2c47bSJack F Vogel wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK); 608656c2c47bSJack F Vogel ixl_flush(hw); 608756c2c47bSJack F Vogel } 608856c2c47bSJack F Vogel 608956c2c47bSJack F Vogel static void 609056c2c47bSJack F Vogel ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg) 609156c2c47bSJack F Vogel { 609256c2c47bSJack F Vogel 609356c2c47bSJack F Vogel wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK | 609456c2c47bSJack F Vogel I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK); 609556c2c47bSJack F Vogel ixl_flush(hw); 609656c2c47bSJack F Vogel } 609756c2c47bSJack F Vogel 609856c2c47bSJack F Vogel static void 609956c2c47bSJack F Vogel ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf) 610056c2c47bSJack F Vogel { 610156c2c47bSJack F Vogel struct i40e_hw *hw; 610256c2c47bSJack F Vogel uint32_t vfint_reg, vpint_reg; 610356c2c47bSJack F Vogel int i; 610456c2c47bSJack F Vogel 610556c2c47bSJack F Vogel hw = &pf->hw; 610656c2c47bSJack F Vogel 610756c2c47bSJack F Vogel ixl_vf_vsi_release(pf, &vf->vsi); 610856c2c47bSJack F Vogel 610956c2c47bSJack F Vogel /* Index 0 has a special register. */ 611056c2c47bSJack F Vogel ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num)); 611156c2c47bSJack F Vogel 611256c2c47bSJack F Vogel for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) { 611356c2c47bSJack F Vogel vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num); 611456c2c47bSJack F Vogel ixl_vf_disable_queue_intr(hw, vfint_reg); 611556c2c47bSJack F Vogel } 611656c2c47bSJack F Vogel 611756c2c47bSJack F Vogel /* Index 0 has a special register. */ 611856c2c47bSJack F Vogel ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num)); 611956c2c47bSJack F Vogel 612056c2c47bSJack F Vogel for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) { 612156c2c47bSJack F Vogel vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num); 612256c2c47bSJack F Vogel ixl_vf_unregister_intr(hw, vpint_reg); 612356c2c47bSJack F Vogel } 612456c2c47bSJack F Vogel 612556c2c47bSJack F Vogel vf->vsi.num_queues = 0; 612656c2c47bSJack F Vogel } 612756c2c47bSJack F Vogel 612856c2c47bSJack F Vogel static int 612956c2c47bSJack F Vogel ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf) 613056c2c47bSJack F Vogel { 613156c2c47bSJack F Vogel struct i40e_hw *hw; 613256c2c47bSJack F Vogel int i; 613356c2c47bSJack F Vogel uint16_t global_vf_num; 613456c2c47bSJack F Vogel uint32_t ciad; 613556c2c47bSJack F Vogel 613656c2c47bSJack F Vogel hw = &pf->hw; 613756c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + vf->vf_num; 613856c2c47bSJack F Vogel 613956c2c47bSJack F Vogel wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS | 614056c2c47bSJack F Vogel (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT)); 614156c2c47bSJack F Vogel for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) { 614256c2c47bSJack F Vogel ciad = rd32(hw, I40E_PF_PCI_CIAD); 614356c2c47bSJack F Vogel if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0) 614456c2c47bSJack F Vogel return (0); 614556c2c47bSJack F Vogel DELAY(1); 614656c2c47bSJack F Vogel } 614756c2c47bSJack F Vogel 614856c2c47bSJack F Vogel return (ETIMEDOUT); 614956c2c47bSJack F Vogel } 615056c2c47bSJack F Vogel 615156c2c47bSJack F Vogel static void 615256c2c47bSJack F Vogel ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf) 615356c2c47bSJack F Vogel { 615456c2c47bSJack F Vogel struct i40e_hw *hw; 615556c2c47bSJack F Vogel uint32_t vfrtrig; 615656c2c47bSJack F Vogel 615756c2c47bSJack F Vogel hw = &pf->hw; 615856c2c47bSJack F Vogel 615956c2c47bSJack F Vogel vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); 616056c2c47bSJack F Vogel vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK; 616156c2c47bSJack F Vogel wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); 616256c2c47bSJack F Vogel ixl_flush(hw); 616356c2c47bSJack F Vogel 616456c2c47bSJack F Vogel ixl_reinit_vf(pf, vf); 616556c2c47bSJack F Vogel } 616656c2c47bSJack F Vogel 616756c2c47bSJack F Vogel static void 616856c2c47bSJack F Vogel ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf) 616956c2c47bSJack F Vogel { 617056c2c47bSJack F Vogel struct i40e_hw *hw; 617156c2c47bSJack F Vogel uint32_t vfrstat, vfrtrig; 617256c2c47bSJack F Vogel int i, error; 617356c2c47bSJack F Vogel 617456c2c47bSJack F Vogel hw = &pf->hw; 617556c2c47bSJack F Vogel 617656c2c47bSJack F Vogel error = ixl_flush_pcie(pf, vf); 617756c2c47bSJack F Vogel if (error != 0) 617856c2c47bSJack F Vogel device_printf(pf->dev, 617956c2c47bSJack F Vogel "Timed out waiting for PCIe activity to stop on VF-%d\n", 618056c2c47bSJack F Vogel vf->vf_num); 618156c2c47bSJack F Vogel 618256c2c47bSJack F Vogel for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) { 618356c2c47bSJack F Vogel DELAY(10); 618456c2c47bSJack F Vogel 618556c2c47bSJack F Vogel vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num)); 618656c2c47bSJack F Vogel if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK) 618756c2c47bSJack F Vogel break; 618856c2c47bSJack F Vogel } 618956c2c47bSJack F Vogel 619056c2c47bSJack F Vogel if (i == IXL_VF_RESET_TIMEOUT) 619156c2c47bSJack F Vogel device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num); 619256c2c47bSJack F Vogel 619356c2c47bSJack F Vogel wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_COMPLETED); 619456c2c47bSJack F Vogel 619556c2c47bSJack F Vogel vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); 619656c2c47bSJack F Vogel vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK; 619756c2c47bSJack F Vogel wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); 619856c2c47bSJack F Vogel 619956c2c47bSJack F Vogel if (vf->vsi.seid != 0) 620056c2c47bSJack F Vogel ixl_disable_rings(&vf->vsi); 620156c2c47bSJack F Vogel 620256c2c47bSJack F Vogel ixl_vf_release_resources(pf, vf); 620356c2c47bSJack F Vogel ixl_vf_setup_vsi(pf, vf); 620456c2c47bSJack F Vogel ixl_vf_map_queues(pf, vf); 620556c2c47bSJack F Vogel 620656c2c47bSJack F Vogel wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_VFACTIVE); 620756c2c47bSJack F Vogel ixl_flush(hw); 620856c2c47bSJack F Vogel } 620956c2c47bSJack F Vogel 621056c2c47bSJack F Vogel static const char * 621156c2c47bSJack F Vogel ixl_vc_opcode_str(uint16_t op) 621256c2c47bSJack F Vogel { 621356c2c47bSJack F Vogel 621456c2c47bSJack F Vogel switch (op) { 621556c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_VERSION: 621656c2c47bSJack F Vogel return ("VERSION"); 621756c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_RESET_VF: 621856c2c47bSJack F Vogel return ("RESET_VF"); 621956c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: 622056c2c47bSJack F Vogel return ("GET_VF_RESOURCES"); 622156c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: 622256c2c47bSJack F Vogel return ("CONFIG_TX_QUEUE"); 622356c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: 622456c2c47bSJack F Vogel return ("CONFIG_RX_QUEUE"); 622556c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: 622656c2c47bSJack F Vogel return ("CONFIG_VSI_QUEUES"); 622756c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: 622856c2c47bSJack F Vogel return ("CONFIG_IRQ_MAP"); 622956c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ENABLE_QUEUES: 623056c2c47bSJack F Vogel return ("ENABLE_QUEUES"); 623156c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DISABLE_QUEUES: 623256c2c47bSJack F Vogel return ("DISABLE_QUEUES"); 623356c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: 623456c2c47bSJack F Vogel return ("ADD_ETHER_ADDRESS"); 623556c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: 623656c2c47bSJack F Vogel return ("DEL_ETHER_ADDRESS"); 623756c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_VLAN: 623856c2c47bSJack F Vogel return ("ADD_VLAN"); 623956c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_VLAN: 624056c2c47bSJack F Vogel return ("DEL_VLAN"); 624156c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: 624256c2c47bSJack F Vogel return ("CONFIG_PROMISCUOUS_MODE"); 624356c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 624456c2c47bSJack F Vogel return ("GET_STATS"); 624556c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_FCOE: 624656c2c47bSJack F Vogel return ("FCOE"); 624756c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_EVENT: 624856c2c47bSJack F Vogel return ("EVENT"); 624956c2c47bSJack F Vogel default: 625056c2c47bSJack F Vogel return ("UNKNOWN"); 625156c2c47bSJack F Vogel } 625256c2c47bSJack F Vogel } 625356c2c47bSJack F Vogel 625456c2c47bSJack F Vogel static int 625556c2c47bSJack F Vogel ixl_vc_opcode_level(uint16_t opcode) 625656c2c47bSJack F Vogel { 625756c2c47bSJack F Vogel switch (opcode) { 625856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 625956c2c47bSJack F Vogel return (10); 626056c2c47bSJack F Vogel default: 626156c2c47bSJack F Vogel return (5); 626256c2c47bSJack F Vogel } 626356c2c47bSJack F Vogel } 626456c2c47bSJack F Vogel 626556c2c47bSJack F Vogel static void 626656c2c47bSJack F Vogel ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, 626756c2c47bSJack F Vogel enum i40e_status_code status, void *msg, uint16_t len) 626856c2c47bSJack F Vogel { 626956c2c47bSJack F Vogel struct i40e_hw *hw; 627056c2c47bSJack F Vogel int global_vf_id; 627156c2c47bSJack F Vogel 627256c2c47bSJack F Vogel hw = &pf->hw; 627356c2c47bSJack F Vogel global_vf_id = hw->func_caps.vf_base_id + vf->vf_num; 627456c2c47bSJack F Vogel 627556c2c47bSJack F Vogel I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op), 627656c2c47bSJack F Vogel "Sending msg (op=%s[%d], status=%d) to VF-%d\n", 627756c2c47bSJack F Vogel ixl_vc_opcode_str(op), op, status, vf->vf_num); 627856c2c47bSJack F Vogel 627956c2c47bSJack F Vogel i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL); 628056c2c47bSJack F Vogel } 628156c2c47bSJack F Vogel 628256c2c47bSJack F Vogel static void 628356c2c47bSJack F Vogel ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op) 628456c2c47bSJack F Vogel { 628556c2c47bSJack F Vogel 628656c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0); 628756c2c47bSJack F Vogel } 628856c2c47bSJack F Vogel 628956c2c47bSJack F Vogel static void 629056c2c47bSJack F Vogel ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, 629156c2c47bSJack F Vogel enum i40e_status_code status, const char *file, int line) 629256c2c47bSJack F Vogel { 629356c2c47bSJack F Vogel 629456c2c47bSJack F Vogel I40E_VC_DEBUG(pf, 1, 629556c2c47bSJack F Vogel "Sending NACK (op=%s[%d], err=%d) to VF-%d from %s:%d\n", 629656c2c47bSJack F Vogel ixl_vc_opcode_str(op), op, status, vf->vf_num, file, line); 629756c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, op, status, NULL, 0); 629856c2c47bSJack F Vogel } 629956c2c47bSJack F Vogel 630056c2c47bSJack F Vogel static void 630156c2c47bSJack F Vogel ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 630256c2c47bSJack F Vogel uint16_t msg_size) 630356c2c47bSJack F Vogel { 630456c2c47bSJack F Vogel struct i40e_virtchnl_version_info reply; 630556c2c47bSJack F Vogel 630656c2c47bSJack F Vogel if (msg_size != sizeof(struct i40e_virtchnl_version_info)) { 630756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_VERSION, 630856c2c47bSJack F Vogel I40E_ERR_PARAM); 630956c2c47bSJack F Vogel return; 631056c2c47bSJack F Vogel } 631156c2c47bSJack F Vogel 63121d767a8eSEric Joyner vf->version = ((struct i40e_virtchnl_version_info *)msg)->minor; 63131d767a8eSEric Joyner 631456c2c47bSJack F Vogel reply.major = I40E_VIRTCHNL_VERSION_MAJOR; 631556c2c47bSJack F Vogel reply.minor = I40E_VIRTCHNL_VERSION_MINOR; 631656c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, &reply, 631756c2c47bSJack F Vogel sizeof(reply)); 631856c2c47bSJack F Vogel } 631956c2c47bSJack F Vogel 632056c2c47bSJack F Vogel static void 632156c2c47bSJack F Vogel ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 632256c2c47bSJack F Vogel uint16_t msg_size) 632356c2c47bSJack F Vogel { 632456c2c47bSJack F Vogel 632556c2c47bSJack F Vogel if (msg_size != 0) { 632656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_RESET_VF, 632756c2c47bSJack F Vogel I40E_ERR_PARAM); 632856c2c47bSJack F Vogel return; 632956c2c47bSJack F Vogel } 633056c2c47bSJack F Vogel 633156c2c47bSJack F Vogel ixl_reset_vf(pf, vf); 633256c2c47bSJack F Vogel 633356c2c47bSJack F Vogel /* No response to a reset message. */ 633456c2c47bSJack F Vogel } 633556c2c47bSJack F Vogel 633656c2c47bSJack F Vogel static void 633756c2c47bSJack F Vogel ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 633856c2c47bSJack F Vogel uint16_t msg_size) 633956c2c47bSJack F Vogel { 634056c2c47bSJack F Vogel struct i40e_virtchnl_vf_resource reply; 634156c2c47bSJack F Vogel 63421d767a8eSEric Joyner if ((vf->version == 0 && msg_size != 0) || 63431d767a8eSEric Joyner (vf->version == 1 && msg_size != 4)) { 63441d767a8eSEric Joyner device_printf(pf->dev, "Invalid GET_VF_RESOURCES message size," 63451d767a8eSEric Joyner " for VF version %d.%d\n", I40E_VIRTCHNL_VERSION_MAJOR, 63461d767a8eSEric Joyner vf->version); 634756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, 634856c2c47bSJack F Vogel I40E_ERR_PARAM); 634956c2c47bSJack F Vogel return; 635056c2c47bSJack F Vogel } 635156c2c47bSJack F Vogel 635256c2c47bSJack F Vogel bzero(&reply, sizeof(reply)); 635356c2c47bSJack F Vogel 63541d767a8eSEric Joyner if (vf->version == I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS) 63551d767a8eSEric Joyner reply.vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2 | 63561d767a8eSEric Joyner I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | 63571d767a8eSEric Joyner I40E_VIRTCHNL_VF_OFFLOAD_VLAN; 63581d767a8eSEric Joyner else 63591d767a8eSEric Joyner reply.vf_offload_flags = *(u32 *)msg; 636056c2c47bSJack F Vogel 636156c2c47bSJack F Vogel reply.num_vsis = 1; 636256c2c47bSJack F Vogel reply.num_queue_pairs = vf->vsi.num_queues; 636356c2c47bSJack F Vogel reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf; 636456c2c47bSJack F Vogel reply.vsi_res[0].vsi_id = vf->vsi.vsi_num; 636556c2c47bSJack F Vogel reply.vsi_res[0].vsi_type = I40E_VSI_SRIOV; 636656c2c47bSJack F Vogel reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues; 636756c2c47bSJack F Vogel memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN); 636856c2c47bSJack F Vogel 636956c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, 637056c2c47bSJack F Vogel I40E_SUCCESS, &reply, sizeof(reply)); 637156c2c47bSJack F Vogel } 637256c2c47bSJack F Vogel 637356c2c47bSJack F Vogel static int 637456c2c47bSJack F Vogel ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf, 637556c2c47bSJack F Vogel struct i40e_virtchnl_txq_info *info) 637656c2c47bSJack F Vogel { 637756c2c47bSJack F Vogel struct i40e_hw *hw; 637856c2c47bSJack F Vogel struct i40e_hmc_obj_txq txq; 637956c2c47bSJack F Vogel uint16_t global_queue_num, global_vf_num; 638056c2c47bSJack F Vogel enum i40e_status_code status; 638156c2c47bSJack F Vogel uint32_t qtx_ctl; 638256c2c47bSJack F Vogel 638356c2c47bSJack F Vogel hw = &pf->hw; 638456c2c47bSJack F Vogel global_queue_num = vf->vsi.first_queue + info->queue_id; 638556c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + vf->vf_num; 638656c2c47bSJack F Vogel bzero(&txq, sizeof(txq)); 638756c2c47bSJack F Vogel 638856c2c47bSJack F Vogel status = i40e_clear_lan_tx_queue_context(hw, global_queue_num); 638956c2c47bSJack F Vogel if (status != I40E_SUCCESS) 639056c2c47bSJack F Vogel return (EINVAL); 639156c2c47bSJack F Vogel 639256c2c47bSJack F Vogel txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS; 639356c2c47bSJack F Vogel 639456c2c47bSJack F Vogel txq.head_wb_ena = info->headwb_enabled; 639556c2c47bSJack F Vogel txq.head_wb_addr = info->dma_headwb_addr; 639656c2c47bSJack F Vogel txq.qlen = info->ring_len; 639756c2c47bSJack F Vogel txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]); 639856c2c47bSJack F Vogel txq.rdylist_act = 0; 639956c2c47bSJack F Vogel 640056c2c47bSJack F Vogel status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq); 640156c2c47bSJack F Vogel if (status != I40E_SUCCESS) 640256c2c47bSJack F Vogel return (EINVAL); 640356c2c47bSJack F Vogel 640456c2c47bSJack F Vogel qtx_ctl = I40E_QTX_CTL_VF_QUEUE | 640556c2c47bSJack F Vogel (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) | 640656c2c47bSJack F Vogel (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT); 640756c2c47bSJack F Vogel wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl); 640856c2c47bSJack F Vogel ixl_flush(hw); 640956c2c47bSJack F Vogel 641056c2c47bSJack F Vogel return (0); 641156c2c47bSJack F Vogel } 641256c2c47bSJack F Vogel 641356c2c47bSJack F Vogel static int 641456c2c47bSJack F Vogel ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf, 641556c2c47bSJack F Vogel struct i40e_virtchnl_rxq_info *info) 641656c2c47bSJack F Vogel { 641756c2c47bSJack F Vogel struct i40e_hw *hw; 641856c2c47bSJack F Vogel struct i40e_hmc_obj_rxq rxq; 641956c2c47bSJack F Vogel uint16_t global_queue_num; 642056c2c47bSJack F Vogel enum i40e_status_code status; 642156c2c47bSJack F Vogel 642256c2c47bSJack F Vogel hw = &pf->hw; 642356c2c47bSJack F Vogel global_queue_num = vf->vsi.first_queue + info->queue_id; 642456c2c47bSJack F Vogel bzero(&rxq, sizeof(rxq)); 642556c2c47bSJack F Vogel 642656c2c47bSJack F Vogel if (info->databuffer_size > IXL_VF_MAX_BUFFER) 642756c2c47bSJack F Vogel return (EINVAL); 642856c2c47bSJack F Vogel 642956c2c47bSJack F Vogel if (info->max_pkt_size > IXL_VF_MAX_FRAME || 643056c2c47bSJack F Vogel info->max_pkt_size < ETHER_MIN_LEN) 643156c2c47bSJack F Vogel return (EINVAL); 643256c2c47bSJack F Vogel 643356c2c47bSJack F Vogel if (info->splithdr_enabled) { 643456c2c47bSJack F Vogel if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER) 643556c2c47bSJack F Vogel return (EINVAL); 643656c2c47bSJack F Vogel 643756c2c47bSJack F Vogel rxq.hsplit_0 = info->rx_split_pos & 643856c2c47bSJack F Vogel (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 | 643956c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP | 644056c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP | 644156c2c47bSJack F Vogel I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP); 644256c2c47bSJack F Vogel rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT; 644356c2c47bSJack F Vogel 644456c2c47bSJack F Vogel rxq.dtype = 2; 644556c2c47bSJack F Vogel } 644656c2c47bSJack F Vogel 644756c2c47bSJack F Vogel status = i40e_clear_lan_rx_queue_context(hw, global_queue_num); 644856c2c47bSJack F Vogel if (status != I40E_SUCCESS) 644956c2c47bSJack F Vogel return (EINVAL); 645056c2c47bSJack F Vogel 645156c2c47bSJack F Vogel rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS; 645256c2c47bSJack F Vogel rxq.qlen = info->ring_len; 645356c2c47bSJack F Vogel 645456c2c47bSJack F Vogel rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT; 645556c2c47bSJack F Vogel 645656c2c47bSJack F Vogel rxq.dsize = 1; 645756c2c47bSJack F Vogel rxq.crcstrip = 1; 645856c2c47bSJack F Vogel rxq.l2tsel = 1; 645956c2c47bSJack F Vogel 646056c2c47bSJack F Vogel rxq.rxmax = info->max_pkt_size; 646156c2c47bSJack F Vogel rxq.tphrdesc_ena = 1; 646256c2c47bSJack F Vogel rxq.tphwdesc_ena = 1; 646356c2c47bSJack F Vogel rxq.tphdata_ena = 1; 646456c2c47bSJack F Vogel rxq.tphhead_ena = 1; 646556c2c47bSJack F Vogel rxq.lrxqthresh = 2; 646656c2c47bSJack F Vogel rxq.prefena = 1; 646756c2c47bSJack F Vogel 646856c2c47bSJack F Vogel status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq); 646956c2c47bSJack F Vogel if (status != I40E_SUCCESS) 647056c2c47bSJack F Vogel return (EINVAL); 647156c2c47bSJack F Vogel 647256c2c47bSJack F Vogel return (0); 647356c2c47bSJack F Vogel } 647456c2c47bSJack F Vogel 647556c2c47bSJack F Vogel static void 647656c2c47bSJack F Vogel ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 647756c2c47bSJack F Vogel uint16_t msg_size) 647856c2c47bSJack F Vogel { 647956c2c47bSJack F Vogel struct i40e_virtchnl_vsi_queue_config_info *info; 648056c2c47bSJack F Vogel struct i40e_virtchnl_queue_pair_info *pair; 648156c2c47bSJack F Vogel int i; 648256c2c47bSJack F Vogel 648356c2c47bSJack F Vogel if (msg_size < sizeof(*info)) { 648456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 648556c2c47bSJack F Vogel I40E_ERR_PARAM); 648656c2c47bSJack F Vogel return; 648756c2c47bSJack F Vogel } 648856c2c47bSJack F Vogel 648956c2c47bSJack F Vogel info = msg; 649056c2c47bSJack F Vogel if (info->num_queue_pairs == 0) { 649156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 649256c2c47bSJack F Vogel I40E_ERR_PARAM); 649356c2c47bSJack F Vogel return; 649456c2c47bSJack F Vogel } 649556c2c47bSJack F Vogel 649656c2c47bSJack F Vogel if (msg_size != sizeof(*info) + info->num_queue_pairs * sizeof(*pair)) { 649756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 649856c2c47bSJack F Vogel I40E_ERR_PARAM); 649956c2c47bSJack F Vogel return; 650056c2c47bSJack F Vogel } 650156c2c47bSJack F Vogel 650256c2c47bSJack F Vogel if (info->vsi_id != vf->vsi.vsi_num) { 650356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 650456c2c47bSJack F Vogel I40E_ERR_PARAM); 650556c2c47bSJack F Vogel return; 650656c2c47bSJack F Vogel } 650756c2c47bSJack F Vogel 650856c2c47bSJack F Vogel for (i = 0; i < info->num_queue_pairs; i++) { 650956c2c47bSJack F Vogel pair = &info->qpair[i]; 651056c2c47bSJack F Vogel 651156c2c47bSJack F Vogel if (pair->txq.vsi_id != vf->vsi.vsi_num || 651256c2c47bSJack F Vogel pair->rxq.vsi_id != vf->vsi.vsi_num || 651356c2c47bSJack F Vogel pair->txq.queue_id != pair->rxq.queue_id || 651456c2c47bSJack F Vogel pair->txq.queue_id >= vf->vsi.num_queues) { 651556c2c47bSJack F Vogel 651656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 651756c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 651856c2c47bSJack F Vogel return; 651956c2c47bSJack F Vogel } 652056c2c47bSJack F Vogel 652156c2c47bSJack F Vogel if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) { 652256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 652356c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 652456c2c47bSJack F Vogel return; 652556c2c47bSJack F Vogel } 652656c2c47bSJack F Vogel 652756c2c47bSJack F Vogel if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) { 652856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 652956c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 653056c2c47bSJack F Vogel return; 653156c2c47bSJack F Vogel } 653256c2c47bSJack F Vogel } 653356c2c47bSJack F Vogel 653456c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES); 653556c2c47bSJack F Vogel } 653656c2c47bSJack F Vogel 653756c2c47bSJack F Vogel static void 653856c2c47bSJack F Vogel ixl_vf_set_qctl(struct ixl_pf *pf, 653956c2c47bSJack F Vogel const struct i40e_virtchnl_vector_map *vector, 654056c2c47bSJack F Vogel enum i40e_queue_type cur_type, uint16_t cur_queue, 654156c2c47bSJack F Vogel enum i40e_queue_type *last_type, uint16_t *last_queue) 654256c2c47bSJack F Vogel { 654356c2c47bSJack F Vogel uint32_t offset, qctl; 654456c2c47bSJack F Vogel uint16_t itr_indx; 654556c2c47bSJack F Vogel 654656c2c47bSJack F Vogel if (cur_type == I40E_QUEUE_TYPE_RX) { 654756c2c47bSJack F Vogel offset = I40E_QINT_RQCTL(cur_queue); 654856c2c47bSJack F Vogel itr_indx = vector->rxitr_idx; 654956c2c47bSJack F Vogel } else { 655056c2c47bSJack F Vogel offset = I40E_QINT_TQCTL(cur_queue); 655156c2c47bSJack F Vogel itr_indx = vector->txitr_idx; 655256c2c47bSJack F Vogel } 655356c2c47bSJack F Vogel 655456c2c47bSJack F Vogel qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 655556c2c47bSJack F Vogel (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) | 655656c2c47bSJack F Vogel (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 655756c2c47bSJack F Vogel I40E_QINT_RQCTL_CAUSE_ENA_MASK | 655856c2c47bSJack F Vogel (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT)); 655956c2c47bSJack F Vogel 656056c2c47bSJack F Vogel wr32(&pf->hw, offset, qctl); 656156c2c47bSJack F Vogel 656256c2c47bSJack F Vogel *last_type = cur_type; 656356c2c47bSJack F Vogel *last_queue = cur_queue; 656456c2c47bSJack F Vogel } 656556c2c47bSJack F Vogel 656656c2c47bSJack F Vogel static void 656756c2c47bSJack F Vogel ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf, 656856c2c47bSJack F Vogel const struct i40e_virtchnl_vector_map *vector) 656956c2c47bSJack F Vogel { 657056c2c47bSJack F Vogel struct i40e_hw *hw; 657156c2c47bSJack F Vogel u_int qindex; 657256c2c47bSJack F Vogel enum i40e_queue_type type, last_type; 657356c2c47bSJack F Vogel uint32_t lnklst_reg; 657456c2c47bSJack F Vogel uint16_t rxq_map, txq_map, cur_queue, last_queue; 657556c2c47bSJack F Vogel 657656c2c47bSJack F Vogel hw = &pf->hw; 657756c2c47bSJack F Vogel 657856c2c47bSJack F Vogel rxq_map = vector->rxq_map; 657956c2c47bSJack F Vogel txq_map = vector->txq_map; 658056c2c47bSJack F Vogel 658156c2c47bSJack F Vogel last_queue = IXL_END_OF_INTR_LNKLST; 658256c2c47bSJack F Vogel last_type = I40E_QUEUE_TYPE_RX; 658356c2c47bSJack F Vogel 658456c2c47bSJack F Vogel /* 658556c2c47bSJack F Vogel * The datasheet says to optimize performance, RX queues and TX queues 658656c2c47bSJack F Vogel * should be interleaved in the interrupt linked list, so we process 658756c2c47bSJack F Vogel * both at once here. 658856c2c47bSJack F Vogel */ 658956c2c47bSJack F Vogel while ((rxq_map != 0) || (txq_map != 0)) { 659056c2c47bSJack F Vogel if (txq_map != 0) { 659156c2c47bSJack F Vogel qindex = ffs(txq_map) - 1; 659256c2c47bSJack F Vogel type = I40E_QUEUE_TYPE_TX; 659356c2c47bSJack F Vogel cur_queue = vf->vsi.first_queue + qindex; 659456c2c47bSJack F Vogel ixl_vf_set_qctl(pf, vector, type, cur_queue, 659556c2c47bSJack F Vogel &last_type, &last_queue); 659656c2c47bSJack F Vogel txq_map &= ~(1 << qindex); 659756c2c47bSJack F Vogel } 659856c2c47bSJack F Vogel 659956c2c47bSJack F Vogel if (rxq_map != 0) { 660056c2c47bSJack F Vogel qindex = ffs(rxq_map) - 1; 660156c2c47bSJack F Vogel type = I40E_QUEUE_TYPE_RX; 660256c2c47bSJack F Vogel cur_queue = vf->vsi.first_queue + qindex; 660356c2c47bSJack F Vogel ixl_vf_set_qctl(pf, vector, type, cur_queue, 660456c2c47bSJack F Vogel &last_type, &last_queue); 660556c2c47bSJack F Vogel rxq_map &= ~(1 << qindex); 660656c2c47bSJack F Vogel } 660756c2c47bSJack F Vogel } 660856c2c47bSJack F Vogel 660956c2c47bSJack F Vogel if (vector->vector_id == 0) 661056c2c47bSJack F Vogel lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num); 661156c2c47bSJack F Vogel else 661256c2c47bSJack F Vogel lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id, 661356c2c47bSJack F Vogel vf->vf_num); 661456c2c47bSJack F Vogel wr32(hw, lnklst_reg, 661556c2c47bSJack F Vogel (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) | 661656c2c47bSJack F Vogel (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT)); 661756c2c47bSJack F Vogel 661856c2c47bSJack F Vogel ixl_flush(hw); 661956c2c47bSJack F Vogel } 662056c2c47bSJack F Vogel 662156c2c47bSJack F Vogel static void 662256c2c47bSJack F Vogel ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 662356c2c47bSJack F Vogel uint16_t msg_size) 662456c2c47bSJack F Vogel { 662556c2c47bSJack F Vogel struct i40e_virtchnl_irq_map_info *map; 662656c2c47bSJack F Vogel struct i40e_virtchnl_vector_map *vector; 662756c2c47bSJack F Vogel struct i40e_hw *hw; 662856c2c47bSJack F Vogel int i, largest_txq, largest_rxq; 662956c2c47bSJack F Vogel 663056c2c47bSJack F Vogel hw = &pf->hw; 663156c2c47bSJack F Vogel 663256c2c47bSJack F Vogel if (msg_size < sizeof(*map)) { 663356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 663456c2c47bSJack F Vogel I40E_ERR_PARAM); 663556c2c47bSJack F Vogel return; 663656c2c47bSJack F Vogel } 663756c2c47bSJack F Vogel 663856c2c47bSJack F Vogel map = msg; 663956c2c47bSJack F Vogel if (map->num_vectors == 0) { 664056c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 664156c2c47bSJack F Vogel I40E_ERR_PARAM); 664256c2c47bSJack F Vogel return; 664356c2c47bSJack F Vogel } 664456c2c47bSJack F Vogel 664556c2c47bSJack F Vogel if (msg_size != sizeof(*map) + map->num_vectors * sizeof(*vector)) { 664656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 664756c2c47bSJack F Vogel I40E_ERR_PARAM); 664856c2c47bSJack F Vogel return; 664956c2c47bSJack F Vogel } 665056c2c47bSJack F Vogel 665156c2c47bSJack F Vogel for (i = 0; i < map->num_vectors; i++) { 665256c2c47bSJack F Vogel vector = &map->vecmap[i]; 665356c2c47bSJack F Vogel 665456c2c47bSJack F Vogel if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) || 665556c2c47bSJack F Vogel vector->vsi_id != vf->vsi.vsi_num) { 665656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 665756c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM); 665856c2c47bSJack F Vogel return; 665956c2c47bSJack F Vogel } 666056c2c47bSJack F Vogel 666156c2c47bSJack F Vogel if (vector->rxq_map != 0) { 666256c2c47bSJack F Vogel largest_rxq = fls(vector->rxq_map) - 1; 666356c2c47bSJack F Vogel if (largest_rxq >= vf->vsi.num_queues) { 666456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 666556c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 666656c2c47bSJack F Vogel I40E_ERR_PARAM); 666756c2c47bSJack F Vogel return; 666856c2c47bSJack F Vogel } 666956c2c47bSJack F Vogel } 667056c2c47bSJack F Vogel 667156c2c47bSJack F Vogel if (vector->txq_map != 0) { 667256c2c47bSJack F Vogel largest_txq = fls(vector->txq_map) - 1; 667356c2c47bSJack F Vogel if (largest_txq >= vf->vsi.num_queues) { 667456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 667556c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 667656c2c47bSJack F Vogel I40E_ERR_PARAM); 667756c2c47bSJack F Vogel return; 667856c2c47bSJack F Vogel } 667956c2c47bSJack F Vogel } 668056c2c47bSJack F Vogel 668156c2c47bSJack F Vogel if (vector->rxitr_idx > IXL_MAX_ITR_IDX || 668256c2c47bSJack F Vogel vector->txitr_idx > IXL_MAX_ITR_IDX) { 668356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 668456c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 668556c2c47bSJack F Vogel I40E_ERR_PARAM); 668656c2c47bSJack F Vogel return; 668756c2c47bSJack F Vogel } 668856c2c47bSJack F Vogel 668956c2c47bSJack F Vogel ixl_vf_config_vector(pf, vf, vector); 669056c2c47bSJack F Vogel } 669156c2c47bSJack F Vogel 669256c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP); 669356c2c47bSJack F Vogel } 669456c2c47bSJack F Vogel 669556c2c47bSJack F Vogel static void 669656c2c47bSJack F Vogel ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 669756c2c47bSJack F Vogel uint16_t msg_size) 669856c2c47bSJack F Vogel { 669956c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *select; 670056c2c47bSJack F Vogel int error; 670156c2c47bSJack F Vogel 670256c2c47bSJack F Vogel if (msg_size != sizeof(*select)) { 670356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 670456c2c47bSJack F Vogel I40E_ERR_PARAM); 670556c2c47bSJack F Vogel return; 670656c2c47bSJack F Vogel } 670756c2c47bSJack F Vogel 670856c2c47bSJack F Vogel select = msg; 670956c2c47bSJack F Vogel if (select->vsi_id != vf->vsi.vsi_num || 671056c2c47bSJack F Vogel select->rx_queues == 0 || select->tx_queues == 0) { 671156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 671256c2c47bSJack F Vogel I40E_ERR_PARAM); 671356c2c47bSJack F Vogel return; 671456c2c47bSJack F Vogel } 671556c2c47bSJack F Vogel 671656c2c47bSJack F Vogel error = ixl_enable_rings(&vf->vsi); 671756c2c47bSJack F Vogel if (error) { 671856c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 671956c2c47bSJack F Vogel I40E_ERR_TIMEOUT); 672056c2c47bSJack F Vogel return; 672156c2c47bSJack F Vogel } 672256c2c47bSJack F Vogel 672356c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES); 672456c2c47bSJack F Vogel } 672556c2c47bSJack F Vogel 672656c2c47bSJack F Vogel static void 672756c2c47bSJack F Vogel ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, 672856c2c47bSJack F Vogel void *msg, uint16_t msg_size) 672956c2c47bSJack F Vogel { 673056c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *select; 673156c2c47bSJack F Vogel int error; 673256c2c47bSJack F Vogel 673356c2c47bSJack F Vogel if (msg_size != sizeof(*select)) { 673456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 673556c2c47bSJack F Vogel I40E_ERR_PARAM); 673656c2c47bSJack F Vogel return; 673756c2c47bSJack F Vogel } 673856c2c47bSJack F Vogel 673956c2c47bSJack F Vogel select = msg; 674056c2c47bSJack F Vogel if (select->vsi_id != vf->vsi.vsi_num || 674156c2c47bSJack F Vogel select->rx_queues == 0 || select->tx_queues == 0) { 674256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 674356c2c47bSJack F Vogel I40E_ERR_PARAM); 674456c2c47bSJack F Vogel return; 674556c2c47bSJack F Vogel } 674656c2c47bSJack F Vogel 674756c2c47bSJack F Vogel error = ixl_disable_rings(&vf->vsi); 674856c2c47bSJack F Vogel if (error) { 674956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 675056c2c47bSJack F Vogel I40E_ERR_TIMEOUT); 675156c2c47bSJack F Vogel return; 675256c2c47bSJack F Vogel } 675356c2c47bSJack F Vogel 675456c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES); 675556c2c47bSJack F Vogel } 675656c2c47bSJack F Vogel 675756c2c47bSJack F Vogel static boolean_t 675856c2c47bSJack F Vogel ixl_zero_mac(const uint8_t *addr) 675956c2c47bSJack F Vogel { 676056c2c47bSJack F Vogel uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0}; 676156c2c47bSJack F Vogel 676256c2c47bSJack F Vogel return (cmp_etheraddr(addr, zero)); 676356c2c47bSJack F Vogel } 676456c2c47bSJack F Vogel 676556c2c47bSJack F Vogel static boolean_t 676656c2c47bSJack F Vogel ixl_bcast_mac(const uint8_t *addr) 676756c2c47bSJack F Vogel { 676856c2c47bSJack F Vogel 676956c2c47bSJack F Vogel return (cmp_etheraddr(addr, ixl_bcast_addr)); 677056c2c47bSJack F Vogel } 677156c2c47bSJack F Vogel 677256c2c47bSJack F Vogel static int 677356c2c47bSJack F Vogel ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr) 677456c2c47bSJack F Vogel { 677556c2c47bSJack F Vogel 677656c2c47bSJack F Vogel if (ixl_zero_mac(addr) || ixl_bcast_mac(addr)) 677756c2c47bSJack F Vogel return (EINVAL); 677856c2c47bSJack F Vogel 677956c2c47bSJack F Vogel /* 678056c2c47bSJack F Vogel * If the VF is not allowed to change its MAC address, don't let it 678156c2c47bSJack F Vogel * set a MAC filter for an address that is not a multicast address and 678256c2c47bSJack F Vogel * is not its assigned MAC. 678356c2c47bSJack F Vogel */ 678456c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) && 678556c2c47bSJack F Vogel !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac))) 678656c2c47bSJack F Vogel return (EPERM); 678756c2c47bSJack F Vogel 678856c2c47bSJack F Vogel return (0); 678956c2c47bSJack F Vogel } 679056c2c47bSJack F Vogel 679156c2c47bSJack F Vogel static void 679256c2c47bSJack F Vogel ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 679356c2c47bSJack F Vogel uint16_t msg_size) 679456c2c47bSJack F Vogel { 679556c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr_list *addr_list; 679656c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr *addr; 679756c2c47bSJack F Vogel struct ixl_vsi *vsi; 679856c2c47bSJack F Vogel int i; 679956c2c47bSJack F Vogel size_t expected_size; 680056c2c47bSJack F Vogel 680156c2c47bSJack F Vogel vsi = &vf->vsi; 680256c2c47bSJack F Vogel 680356c2c47bSJack F Vogel if (msg_size < sizeof(*addr_list)) { 680456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 680556c2c47bSJack F Vogel I40E_ERR_PARAM); 680656c2c47bSJack F Vogel return; 680756c2c47bSJack F Vogel } 680856c2c47bSJack F Vogel 680956c2c47bSJack F Vogel addr_list = msg; 681056c2c47bSJack F Vogel expected_size = sizeof(*addr_list) + 681156c2c47bSJack F Vogel addr_list->num_elements * sizeof(*addr); 681256c2c47bSJack F Vogel 681356c2c47bSJack F Vogel if (addr_list->num_elements == 0 || 681456c2c47bSJack F Vogel addr_list->vsi_id != vsi->vsi_num || 681556c2c47bSJack F Vogel msg_size != expected_size) { 681656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 681756c2c47bSJack F Vogel I40E_ERR_PARAM); 681856c2c47bSJack F Vogel return; 681956c2c47bSJack F Vogel } 682056c2c47bSJack F Vogel 682156c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 682256c2c47bSJack F Vogel if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) { 682356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 682456c2c47bSJack F Vogel I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM); 682556c2c47bSJack F Vogel return; 682656c2c47bSJack F Vogel } 682756c2c47bSJack F Vogel } 682856c2c47bSJack F Vogel 682956c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 683056c2c47bSJack F Vogel addr = &addr_list->list[i]; 683156c2c47bSJack F Vogel ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY); 683256c2c47bSJack F Vogel } 683356c2c47bSJack F Vogel 683456c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS); 683556c2c47bSJack F Vogel } 683656c2c47bSJack F Vogel 683756c2c47bSJack F Vogel static void 683856c2c47bSJack F Vogel ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 683956c2c47bSJack F Vogel uint16_t msg_size) 684056c2c47bSJack F Vogel { 684156c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr_list *addr_list; 684256c2c47bSJack F Vogel struct i40e_virtchnl_ether_addr *addr; 684356c2c47bSJack F Vogel size_t expected_size; 684456c2c47bSJack F Vogel int i; 684556c2c47bSJack F Vogel 684656c2c47bSJack F Vogel if (msg_size < sizeof(*addr_list)) { 684756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 684856c2c47bSJack F Vogel I40E_ERR_PARAM); 684956c2c47bSJack F Vogel return; 685056c2c47bSJack F Vogel } 685156c2c47bSJack F Vogel 685256c2c47bSJack F Vogel addr_list = msg; 685356c2c47bSJack F Vogel expected_size = sizeof(*addr_list) + 685456c2c47bSJack F Vogel addr_list->num_elements * sizeof(*addr); 685556c2c47bSJack F Vogel 685656c2c47bSJack F Vogel if (addr_list->num_elements == 0 || 685756c2c47bSJack F Vogel addr_list->vsi_id != vf->vsi.vsi_num || 685856c2c47bSJack F Vogel msg_size != expected_size) { 685956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 686056c2c47bSJack F Vogel I40E_ERR_PARAM); 686156c2c47bSJack F Vogel return; 686256c2c47bSJack F Vogel } 686356c2c47bSJack F Vogel 686456c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 686556c2c47bSJack F Vogel addr = &addr_list->list[i]; 686656c2c47bSJack F Vogel if (ixl_zero_mac(addr->addr) || ixl_bcast_mac(addr->addr)) { 686756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 686856c2c47bSJack F Vogel I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM); 686956c2c47bSJack F Vogel return; 687056c2c47bSJack F Vogel } 687156c2c47bSJack F Vogel } 687256c2c47bSJack F Vogel 687356c2c47bSJack F Vogel for (i = 0; i < addr_list->num_elements; i++) { 687456c2c47bSJack F Vogel addr = &addr_list->list[i]; 687556c2c47bSJack F Vogel ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY); 687656c2c47bSJack F Vogel } 687756c2c47bSJack F Vogel 687856c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS); 687956c2c47bSJack F Vogel } 688056c2c47bSJack F Vogel 688156c2c47bSJack F Vogel static enum i40e_status_code 688256c2c47bSJack F Vogel ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf) 688356c2c47bSJack F Vogel { 688456c2c47bSJack F Vogel struct i40e_vsi_context vsi_ctx; 688556c2c47bSJack F Vogel 688656c2c47bSJack F Vogel vsi_ctx.seid = vf->vsi.seid; 688756c2c47bSJack F Vogel 688856c2c47bSJack F Vogel bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); 688956c2c47bSJack F Vogel vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID); 689056c2c47bSJack F Vogel vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 689156c2c47bSJack F Vogel I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 689256c2c47bSJack F Vogel return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL)); 689356c2c47bSJack F Vogel } 689456c2c47bSJack F Vogel 689556c2c47bSJack F Vogel static void 689656c2c47bSJack F Vogel ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 689756c2c47bSJack F Vogel uint16_t msg_size) 689856c2c47bSJack F Vogel { 689956c2c47bSJack F Vogel struct i40e_virtchnl_vlan_filter_list *filter_list; 690056c2c47bSJack F Vogel enum i40e_status_code code; 690156c2c47bSJack F Vogel size_t expected_size; 690256c2c47bSJack F Vogel int i; 690356c2c47bSJack F Vogel 690456c2c47bSJack F Vogel if (msg_size < sizeof(*filter_list)) { 690556c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 690656c2c47bSJack F Vogel I40E_ERR_PARAM); 690756c2c47bSJack F Vogel return; 690856c2c47bSJack F Vogel } 690956c2c47bSJack F Vogel 691056c2c47bSJack F Vogel filter_list = msg; 691156c2c47bSJack F Vogel expected_size = sizeof(*filter_list) + 691256c2c47bSJack F Vogel filter_list->num_elements * sizeof(uint16_t); 691356c2c47bSJack F Vogel if (filter_list->num_elements == 0 || 691456c2c47bSJack F Vogel filter_list->vsi_id != vf->vsi.vsi_num || 691556c2c47bSJack F Vogel msg_size != expected_size) { 691656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 691756c2c47bSJack F Vogel I40E_ERR_PARAM); 691856c2c47bSJack F Vogel return; 691956c2c47bSJack F Vogel } 692056c2c47bSJack F Vogel 692156c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) { 692256c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 692356c2c47bSJack F Vogel I40E_ERR_PARAM); 692456c2c47bSJack F Vogel return; 692556c2c47bSJack F Vogel } 692656c2c47bSJack F Vogel 692756c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) { 692856c2c47bSJack F Vogel if (filter_list->vlan_id[i] > EVL_VLID_MASK) { 692956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 693056c2c47bSJack F Vogel I40E_ERR_PARAM); 693156c2c47bSJack F Vogel return; 693256c2c47bSJack F Vogel } 693356c2c47bSJack F Vogel } 693456c2c47bSJack F Vogel 693556c2c47bSJack F Vogel code = ixl_vf_enable_vlan_strip(pf, vf); 693656c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 693756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 693856c2c47bSJack F Vogel I40E_ERR_PARAM); 693956c2c47bSJack F Vogel } 694056c2c47bSJack F Vogel 694156c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) 694256c2c47bSJack F Vogel ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]); 694356c2c47bSJack F Vogel 694456c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN); 694556c2c47bSJack F Vogel } 694656c2c47bSJack F Vogel 694756c2c47bSJack F Vogel static void 694856c2c47bSJack F Vogel ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 694956c2c47bSJack F Vogel uint16_t msg_size) 695056c2c47bSJack F Vogel { 695156c2c47bSJack F Vogel struct i40e_virtchnl_vlan_filter_list *filter_list; 695256c2c47bSJack F Vogel int i; 695356c2c47bSJack F Vogel size_t expected_size; 695456c2c47bSJack F Vogel 695556c2c47bSJack F Vogel if (msg_size < sizeof(*filter_list)) { 695656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN, 695756c2c47bSJack F Vogel I40E_ERR_PARAM); 695856c2c47bSJack F Vogel return; 695956c2c47bSJack F Vogel } 696056c2c47bSJack F Vogel 696156c2c47bSJack F Vogel filter_list = msg; 696256c2c47bSJack F Vogel expected_size = sizeof(*filter_list) + 696356c2c47bSJack F Vogel filter_list->num_elements * sizeof(uint16_t); 696456c2c47bSJack F Vogel if (filter_list->num_elements == 0 || 696556c2c47bSJack F Vogel filter_list->vsi_id != vf->vsi.vsi_num || 696656c2c47bSJack F Vogel msg_size != expected_size) { 696756c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN, 696856c2c47bSJack F Vogel I40E_ERR_PARAM); 696956c2c47bSJack F Vogel return; 697056c2c47bSJack F Vogel } 697156c2c47bSJack F Vogel 697256c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) { 697356c2c47bSJack F Vogel if (filter_list->vlan_id[i] > EVL_VLID_MASK) { 697456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 697556c2c47bSJack F Vogel I40E_ERR_PARAM); 697656c2c47bSJack F Vogel return; 697756c2c47bSJack F Vogel } 697856c2c47bSJack F Vogel } 697956c2c47bSJack F Vogel 698056c2c47bSJack F Vogel if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) { 698156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 698256c2c47bSJack F Vogel I40E_ERR_PARAM); 698356c2c47bSJack F Vogel return; 698456c2c47bSJack F Vogel } 698556c2c47bSJack F Vogel 698656c2c47bSJack F Vogel for (i = 0; i < filter_list->num_elements; i++) 698756c2c47bSJack F Vogel ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]); 698856c2c47bSJack F Vogel 698956c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN); 699056c2c47bSJack F Vogel } 699156c2c47bSJack F Vogel 699256c2c47bSJack F Vogel static void 699356c2c47bSJack F Vogel ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, 699456c2c47bSJack F Vogel void *msg, uint16_t msg_size) 699556c2c47bSJack F Vogel { 699656c2c47bSJack F Vogel struct i40e_virtchnl_promisc_info *info; 699756c2c47bSJack F Vogel enum i40e_status_code code; 699856c2c47bSJack F Vogel 699956c2c47bSJack F Vogel if (msg_size != sizeof(*info)) { 700056c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 700156c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 700256c2c47bSJack F Vogel return; 700356c2c47bSJack F Vogel } 700456c2c47bSJack F Vogel 700529899c0aSKevin Lo if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) { 700656c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 700756c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 700856c2c47bSJack F Vogel return; 700956c2c47bSJack F Vogel } 701056c2c47bSJack F Vogel 701156c2c47bSJack F Vogel info = msg; 701256c2c47bSJack F Vogel if (info->vsi_id != vf->vsi.vsi_num) { 701356c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 701456c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 701556c2c47bSJack F Vogel return; 701656c2c47bSJack F Vogel } 701756c2c47bSJack F Vogel 701856c2c47bSJack F Vogel code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id, 701956c2c47bSJack F Vogel info->flags & I40E_FLAG_VF_UNICAST_PROMISC, NULL); 702056c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 702156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 702256c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); 702356c2c47bSJack F Vogel return; 702456c2c47bSJack F Vogel } 702556c2c47bSJack F Vogel 702656c2c47bSJack F Vogel code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id, 702756c2c47bSJack F Vogel info->flags & I40E_FLAG_VF_MULTICAST_PROMISC, NULL); 702856c2c47bSJack F Vogel if (code != I40E_SUCCESS) { 702956c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, 703056c2c47bSJack F Vogel I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); 703156c2c47bSJack F Vogel return; 703256c2c47bSJack F Vogel } 703356c2c47bSJack F Vogel 703456c2c47bSJack F Vogel ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE); 703556c2c47bSJack F Vogel } 703656c2c47bSJack F Vogel 703756c2c47bSJack F Vogel static void 703856c2c47bSJack F Vogel ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 703956c2c47bSJack F Vogel uint16_t msg_size) 704056c2c47bSJack F Vogel { 704156c2c47bSJack F Vogel struct i40e_virtchnl_queue_select *queue; 704256c2c47bSJack F Vogel 704356c2c47bSJack F Vogel if (msg_size != sizeof(*queue)) { 704456c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 704556c2c47bSJack F Vogel I40E_ERR_PARAM); 704656c2c47bSJack F Vogel return; 704756c2c47bSJack F Vogel } 704856c2c47bSJack F Vogel 704956c2c47bSJack F Vogel queue = msg; 705056c2c47bSJack F Vogel if (queue->vsi_id != vf->vsi.vsi_num) { 705156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 705256c2c47bSJack F Vogel I40E_ERR_PARAM); 705356c2c47bSJack F Vogel return; 705456c2c47bSJack F Vogel } 705556c2c47bSJack F Vogel 705656c2c47bSJack F Vogel ixl_update_eth_stats(&vf->vsi); 705756c2c47bSJack F Vogel 705856c2c47bSJack F Vogel ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 705956c2c47bSJack F Vogel I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats)); 706056c2c47bSJack F Vogel } 706156c2c47bSJack F Vogel 706256c2c47bSJack F Vogel static void 706356c2c47bSJack F Vogel ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event) 706456c2c47bSJack F Vogel { 706556c2c47bSJack F Vogel struct ixl_vf *vf; 706656c2c47bSJack F Vogel void *msg; 706756c2c47bSJack F Vogel uint16_t vf_num, msg_size; 706856c2c47bSJack F Vogel uint32_t opcode; 706956c2c47bSJack F Vogel 707056c2c47bSJack F Vogel vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id; 707156c2c47bSJack F Vogel opcode = le32toh(event->desc.cookie_high); 707256c2c47bSJack F Vogel 707356c2c47bSJack F Vogel if (vf_num >= pf->num_vfs) { 707456c2c47bSJack F Vogel device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num); 707556c2c47bSJack F Vogel return; 707656c2c47bSJack F Vogel } 707756c2c47bSJack F Vogel 707856c2c47bSJack F Vogel vf = &pf->vfs[vf_num]; 707956c2c47bSJack F Vogel msg = event->msg_buf; 708056c2c47bSJack F Vogel msg_size = event->msg_len; 708156c2c47bSJack F Vogel 708256c2c47bSJack F Vogel I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode), 708356c2c47bSJack F Vogel "Got msg %s(%d) from VF-%d of size %d\n", 708456c2c47bSJack F Vogel ixl_vc_opcode_str(opcode), opcode, vf_num, msg_size); 708556c2c47bSJack F Vogel 708656c2c47bSJack F Vogel switch (opcode) { 708756c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_VERSION: 708856c2c47bSJack F Vogel ixl_vf_version_msg(pf, vf, msg, msg_size); 708956c2c47bSJack F Vogel break; 709056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_RESET_VF: 709156c2c47bSJack F Vogel ixl_vf_reset_msg(pf, vf, msg, msg_size); 709256c2c47bSJack F Vogel break; 709356c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: 709456c2c47bSJack F Vogel ixl_vf_get_resources_msg(pf, vf, msg, msg_size); 709556c2c47bSJack F Vogel break; 709656c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: 709756c2c47bSJack F Vogel ixl_vf_config_vsi_msg(pf, vf, msg, msg_size); 709856c2c47bSJack F Vogel break; 709956c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: 710056c2c47bSJack F Vogel ixl_vf_config_irq_msg(pf, vf, msg, msg_size); 710156c2c47bSJack F Vogel break; 710256c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ENABLE_QUEUES: 710356c2c47bSJack F Vogel ixl_vf_enable_queues_msg(pf, vf, msg, msg_size); 710456c2c47bSJack F Vogel break; 710556c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DISABLE_QUEUES: 710656c2c47bSJack F Vogel ixl_vf_disable_queues_msg(pf, vf, msg, msg_size); 710756c2c47bSJack F Vogel break; 710856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: 710956c2c47bSJack F Vogel ixl_vf_add_mac_msg(pf, vf, msg, msg_size); 711056c2c47bSJack F Vogel break; 711156c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: 711256c2c47bSJack F Vogel ixl_vf_del_mac_msg(pf, vf, msg, msg_size); 711356c2c47bSJack F Vogel break; 711456c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_ADD_VLAN: 711556c2c47bSJack F Vogel ixl_vf_add_vlan_msg(pf, vf, msg, msg_size); 711656c2c47bSJack F Vogel break; 711756c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_DEL_VLAN: 711856c2c47bSJack F Vogel ixl_vf_del_vlan_msg(pf, vf, msg, msg_size); 711956c2c47bSJack F Vogel break; 712056c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: 712156c2c47bSJack F Vogel ixl_vf_config_promisc_msg(pf, vf, msg, msg_size); 712256c2c47bSJack F Vogel break; 712356c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_GET_STATS: 712456c2c47bSJack F Vogel ixl_vf_get_stats_msg(pf, vf, msg, msg_size); 712556c2c47bSJack F Vogel break; 712656c2c47bSJack F Vogel 712756c2c47bSJack F Vogel /* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */ 712856c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: 712956c2c47bSJack F Vogel case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: 713056c2c47bSJack F Vogel default: 713156c2c47bSJack F Vogel i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED); 713256c2c47bSJack F Vogel break; 713356c2c47bSJack F Vogel } 713456c2c47bSJack F Vogel } 713556c2c47bSJack F Vogel 713656c2c47bSJack F Vogel /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */ 713756c2c47bSJack F Vogel static void 713856c2c47bSJack F Vogel ixl_handle_vflr(void *arg, int pending) 713956c2c47bSJack F Vogel { 714056c2c47bSJack F Vogel struct ixl_pf *pf; 714156c2c47bSJack F Vogel struct i40e_hw *hw; 714256c2c47bSJack F Vogel uint16_t global_vf_num; 714356c2c47bSJack F Vogel uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0; 714456c2c47bSJack F Vogel int i; 714556c2c47bSJack F Vogel 714656c2c47bSJack F Vogel pf = arg; 714756c2c47bSJack F Vogel hw = &pf->hw; 714856c2c47bSJack F Vogel 714956c2c47bSJack F Vogel IXL_PF_LOCK(pf); 715056c2c47bSJack F Vogel for (i = 0; i < pf->num_vfs; i++) { 715156c2c47bSJack F Vogel global_vf_num = hw->func_caps.vf_base_id + i; 715256c2c47bSJack F Vogel 715356c2c47bSJack F Vogel vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num); 715456c2c47bSJack F Vogel vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num); 715556c2c47bSJack F Vogel vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index)); 715656c2c47bSJack F Vogel if (vflrstat & vflrstat_mask) { 715756c2c47bSJack F Vogel wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index), 715856c2c47bSJack F Vogel vflrstat_mask); 715956c2c47bSJack F Vogel 716056c2c47bSJack F Vogel ixl_reinit_vf(pf, &pf->vfs[i]); 716156c2c47bSJack F Vogel } 716256c2c47bSJack F Vogel } 716356c2c47bSJack F Vogel 716456c2c47bSJack F Vogel icr0 = rd32(hw, I40E_PFINT_ICR0_ENA); 716556c2c47bSJack F Vogel icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK; 716656c2c47bSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, icr0); 716756c2c47bSJack F Vogel ixl_flush(hw); 716856c2c47bSJack F Vogel 716956c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 717056c2c47bSJack F Vogel } 717156c2c47bSJack F Vogel 717256c2c47bSJack F Vogel static int 717356c2c47bSJack F Vogel ixl_adminq_err_to_errno(enum i40e_admin_queue_err err) 717456c2c47bSJack F Vogel { 717556c2c47bSJack F Vogel 717656c2c47bSJack F Vogel switch (err) { 717756c2c47bSJack F Vogel case I40E_AQ_RC_EPERM: 717856c2c47bSJack F Vogel return (EPERM); 717956c2c47bSJack F Vogel case I40E_AQ_RC_ENOENT: 718056c2c47bSJack F Vogel return (ENOENT); 718156c2c47bSJack F Vogel case I40E_AQ_RC_ESRCH: 718256c2c47bSJack F Vogel return (ESRCH); 718356c2c47bSJack F Vogel case I40E_AQ_RC_EINTR: 718456c2c47bSJack F Vogel return (EINTR); 718556c2c47bSJack F Vogel case I40E_AQ_RC_EIO: 718656c2c47bSJack F Vogel return (EIO); 718756c2c47bSJack F Vogel case I40E_AQ_RC_ENXIO: 718856c2c47bSJack F Vogel return (ENXIO); 718956c2c47bSJack F Vogel case I40E_AQ_RC_E2BIG: 719056c2c47bSJack F Vogel return (E2BIG); 719156c2c47bSJack F Vogel case I40E_AQ_RC_EAGAIN: 719256c2c47bSJack F Vogel return (EAGAIN); 719356c2c47bSJack F Vogel case I40E_AQ_RC_ENOMEM: 719456c2c47bSJack F Vogel return (ENOMEM); 719556c2c47bSJack F Vogel case I40E_AQ_RC_EACCES: 719656c2c47bSJack F Vogel return (EACCES); 719756c2c47bSJack F Vogel case I40E_AQ_RC_EFAULT: 719856c2c47bSJack F Vogel return (EFAULT); 719956c2c47bSJack F Vogel case I40E_AQ_RC_EBUSY: 720056c2c47bSJack F Vogel return (EBUSY); 720156c2c47bSJack F Vogel case I40E_AQ_RC_EEXIST: 720256c2c47bSJack F Vogel return (EEXIST); 720356c2c47bSJack F Vogel case I40E_AQ_RC_EINVAL: 720456c2c47bSJack F Vogel return (EINVAL); 720556c2c47bSJack F Vogel case I40E_AQ_RC_ENOTTY: 720656c2c47bSJack F Vogel return (ENOTTY); 720756c2c47bSJack F Vogel case I40E_AQ_RC_ENOSPC: 720856c2c47bSJack F Vogel return (ENOSPC); 720956c2c47bSJack F Vogel case I40E_AQ_RC_ENOSYS: 721056c2c47bSJack F Vogel return (ENOSYS); 721156c2c47bSJack F Vogel case I40E_AQ_RC_ERANGE: 721256c2c47bSJack F Vogel return (ERANGE); 721356c2c47bSJack F Vogel case I40E_AQ_RC_EFLUSHED: 721456c2c47bSJack F Vogel return (EINVAL); /* No exact equivalent in errno.h */ 721556c2c47bSJack F Vogel case I40E_AQ_RC_BAD_ADDR: 721656c2c47bSJack F Vogel return (EFAULT); 721756c2c47bSJack F Vogel case I40E_AQ_RC_EMODE: 721856c2c47bSJack F Vogel return (EPERM); 721956c2c47bSJack F Vogel case I40E_AQ_RC_EFBIG: 722056c2c47bSJack F Vogel return (EFBIG); 722156c2c47bSJack F Vogel default: 722256c2c47bSJack F Vogel return (EINVAL); 722356c2c47bSJack F Vogel } 722456c2c47bSJack F Vogel } 722556c2c47bSJack F Vogel 722656c2c47bSJack F Vogel static int 7227a48d00d2SEric Joyner ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params) 722856c2c47bSJack F Vogel { 722956c2c47bSJack F Vogel struct ixl_pf *pf; 723056c2c47bSJack F Vogel struct i40e_hw *hw; 723156c2c47bSJack F Vogel struct ixl_vsi *pf_vsi; 723256c2c47bSJack F Vogel enum i40e_status_code ret; 723356c2c47bSJack F Vogel int i, error; 723456c2c47bSJack F Vogel 723556c2c47bSJack F Vogel pf = device_get_softc(dev); 723656c2c47bSJack F Vogel hw = &pf->hw; 723756c2c47bSJack F Vogel pf_vsi = &pf->vsi; 723856c2c47bSJack F Vogel 723956c2c47bSJack F Vogel IXL_PF_LOCK(pf); 724056c2c47bSJack F Vogel pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT | 724156c2c47bSJack F Vogel M_ZERO); 724256c2c47bSJack F Vogel 724356c2c47bSJack F Vogel if (pf->vfs == NULL) { 724456c2c47bSJack F Vogel error = ENOMEM; 724556c2c47bSJack F Vogel goto fail; 724656c2c47bSJack F Vogel } 724756c2c47bSJack F Vogel 724856c2c47bSJack F Vogel for (i = 0; i < num_vfs; i++) 724956c2c47bSJack F Vogel sysctl_ctx_init(&pf->vfs[i].ctx); 725056c2c47bSJack F Vogel 725156c2c47bSJack F Vogel ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid, 72521d767a8eSEric Joyner 1, FALSE, &pf->veb_seid, FALSE, NULL); 725356c2c47bSJack F Vogel if (ret != I40E_SUCCESS) { 725456c2c47bSJack F Vogel error = ixl_adminq_err_to_errno(hw->aq.asq_last_status); 725556c2c47bSJack F Vogel device_printf(dev, "add_veb failed; code=%d error=%d", ret, 725656c2c47bSJack F Vogel error); 725756c2c47bSJack F Vogel goto fail; 725856c2c47bSJack F Vogel } 725956c2c47bSJack F Vogel 7260*6c426059SEric Joyner // TODO: [Configure MSI-X here] 726156c2c47bSJack F Vogel ixl_enable_adminq(hw); 726256c2c47bSJack F Vogel 726356c2c47bSJack F Vogel pf->num_vfs = num_vfs; 726456c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 726556c2c47bSJack F Vogel return (0); 726656c2c47bSJack F Vogel 726756c2c47bSJack F Vogel fail: 726856c2c47bSJack F Vogel free(pf->vfs, M_IXL); 726956c2c47bSJack F Vogel pf->vfs = NULL; 727056c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 727156c2c47bSJack F Vogel return (error); 727256c2c47bSJack F Vogel } 727356c2c47bSJack F Vogel 727456c2c47bSJack F Vogel static void 7275a48d00d2SEric Joyner ixl_iov_uninit(device_t dev) 727656c2c47bSJack F Vogel { 727756c2c47bSJack F Vogel struct ixl_pf *pf; 727856c2c47bSJack F Vogel struct i40e_hw *hw; 727956c2c47bSJack F Vogel struct ixl_vsi *vsi; 728056c2c47bSJack F Vogel struct ifnet *ifp; 728156c2c47bSJack F Vogel struct ixl_vf *vfs; 728256c2c47bSJack F Vogel int i, num_vfs; 728356c2c47bSJack F Vogel 728456c2c47bSJack F Vogel pf = device_get_softc(dev); 728556c2c47bSJack F Vogel hw = &pf->hw; 728656c2c47bSJack F Vogel vsi = &pf->vsi; 728756c2c47bSJack F Vogel ifp = vsi->ifp; 728856c2c47bSJack F Vogel 728956c2c47bSJack F Vogel IXL_PF_LOCK(pf); 729056c2c47bSJack F Vogel for (i = 0; i < pf->num_vfs; i++) { 729156c2c47bSJack F Vogel if (pf->vfs[i].vsi.seid != 0) 729256c2c47bSJack F Vogel i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL); 729356c2c47bSJack F Vogel } 729456c2c47bSJack F Vogel 729556c2c47bSJack F Vogel if (pf->veb_seid != 0) { 729656c2c47bSJack F Vogel i40e_aq_delete_element(hw, pf->veb_seid, NULL); 729756c2c47bSJack F Vogel pf->veb_seid = 0; 729856c2c47bSJack F Vogel } 729956c2c47bSJack F Vogel 730056c2c47bSJack F Vogel if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 730156c2c47bSJack F Vogel ixl_disable_intr(vsi); 730256c2c47bSJack F Vogel 730356c2c47bSJack F Vogel vfs = pf->vfs; 730456c2c47bSJack F Vogel num_vfs = pf->num_vfs; 730556c2c47bSJack F Vogel 730656c2c47bSJack F Vogel pf->vfs = NULL; 730756c2c47bSJack F Vogel pf->num_vfs = 0; 730856c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 730956c2c47bSJack F Vogel 731056c2c47bSJack F Vogel /* Do this after the unlock as sysctl_ctx_free might sleep. */ 731156c2c47bSJack F Vogel for (i = 0; i < num_vfs; i++) 731256c2c47bSJack F Vogel sysctl_ctx_free(&vfs[i].ctx); 731356c2c47bSJack F Vogel free(vfs, M_IXL); 731456c2c47bSJack F Vogel } 731556c2c47bSJack F Vogel 731656c2c47bSJack F Vogel static int 731756c2c47bSJack F Vogel ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params) 731856c2c47bSJack F Vogel { 731956c2c47bSJack F Vogel char sysctl_name[QUEUE_NAME_LEN]; 732056c2c47bSJack F Vogel struct ixl_pf *pf; 732156c2c47bSJack F Vogel struct ixl_vf *vf; 732256c2c47bSJack F Vogel const void *mac; 732356c2c47bSJack F Vogel size_t size; 732456c2c47bSJack F Vogel int error; 732556c2c47bSJack F Vogel 732656c2c47bSJack F Vogel pf = device_get_softc(dev); 732756c2c47bSJack F Vogel vf = &pf->vfs[vfnum]; 732856c2c47bSJack F Vogel 732956c2c47bSJack F Vogel IXL_PF_LOCK(pf); 733056c2c47bSJack F Vogel vf->vf_num = vfnum; 733156c2c47bSJack F Vogel 733256c2c47bSJack F Vogel vf->vsi.back = pf; 733356c2c47bSJack F Vogel vf->vf_flags = VF_FLAG_ENABLED; 733456c2c47bSJack F Vogel SLIST_INIT(&vf->vsi.ftl); 733556c2c47bSJack F Vogel 733656c2c47bSJack F Vogel error = ixl_vf_setup_vsi(pf, vf); 733756c2c47bSJack F Vogel if (error != 0) 733856c2c47bSJack F Vogel goto out; 733956c2c47bSJack F Vogel 734056c2c47bSJack F Vogel if (nvlist_exists_binary(params, "mac-addr")) { 734156c2c47bSJack F Vogel mac = nvlist_get_binary(params, "mac-addr", &size); 734256c2c47bSJack F Vogel bcopy(mac, vf->mac, ETHER_ADDR_LEN); 734356c2c47bSJack F Vogel 734456c2c47bSJack F Vogel if (nvlist_get_bool(params, "allow-set-mac")) 734556c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_SET_MAC_CAP; 734656c2c47bSJack F Vogel } else 734756c2c47bSJack F Vogel /* 734856c2c47bSJack F Vogel * If the administrator has not specified a MAC address then 734956c2c47bSJack F Vogel * we must allow the VF to choose one. 735056c2c47bSJack F Vogel */ 735156c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_SET_MAC_CAP; 735256c2c47bSJack F Vogel 735356c2c47bSJack F Vogel if (nvlist_get_bool(params, "mac-anti-spoof")) 735456c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF; 735556c2c47bSJack F Vogel 735656c2c47bSJack F Vogel if (nvlist_get_bool(params, "allow-promisc")) 735756c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_PROMISC_CAP; 735856c2c47bSJack F Vogel 73591d767a8eSEric Joyner /* TODO: Get VLAN that PF has set for the VF */ 73601d767a8eSEric Joyner 736156c2c47bSJack F Vogel vf->vf_flags |= VF_FLAG_VLAN_CAP; 736256c2c47bSJack F Vogel 736356c2c47bSJack F Vogel ixl_reset_vf(pf, vf); 736456c2c47bSJack F Vogel out: 736556c2c47bSJack F Vogel IXL_PF_UNLOCK(pf); 736656c2c47bSJack F Vogel if (error == 0) { 736756c2c47bSJack F Vogel snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum); 736856c2c47bSJack F Vogel ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name); 736956c2c47bSJack F Vogel } 737056c2c47bSJack F Vogel 737156c2c47bSJack F Vogel return (error); 737256c2c47bSJack F Vogel } 737356c2c47bSJack F Vogel #endif /* PCI_IOV */ 7374