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 *********************************************************************/ 51b6c8f260SJack F Vogel char ixl_driver_version[] = "1.3.6"; 5261ae650dSJack F Vogel 5361ae650dSJack F Vogel /********************************************************************* 5461ae650dSJack F Vogel * PCI Device ID Table 5561ae650dSJack F Vogel * 5661ae650dSJack F Vogel * Used by probe to select devices to load on 5761ae650dSJack F Vogel * Last field stores an index into ixl_strings 5861ae650dSJack F Vogel * Last entry must be all 0s 5961ae650dSJack F Vogel * 6061ae650dSJack F Vogel * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 6161ae650dSJack F Vogel *********************************************************************/ 6261ae650dSJack F Vogel 6361ae650dSJack F Vogel static ixl_vendor_info_t ixl_vendor_info_array[] = 6461ae650dSJack F Vogel { 6561ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0}, 6661ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_A, 0, 0, 0}, 6761ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0}, 6861ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0}, 6961ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0}, 7061ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0}, 7161ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0}, 7261ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0}, 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 *); 9961ae650dSJack F Vogel static void ixl_media_status(struct ifnet *, struct ifmediareq *); 10061ae650dSJack F Vogel static int ixl_media_change(struct ifnet *); 10161ae650dSJack F Vogel static void ixl_update_link_status(struct ixl_pf *); 10261ae650dSJack F Vogel static int ixl_allocate_pci_resources(struct ixl_pf *); 10361ae650dSJack F Vogel static u16 ixl_get_bus_info(struct i40e_hw *, device_t); 10461ae650dSJack F Vogel static int ixl_setup_stations(struct ixl_pf *); 105b6c8f260SJack F Vogel static int ixl_switch_config(struct ixl_pf *); 10661ae650dSJack F Vogel static int ixl_initialize_vsi(struct ixl_vsi *); 10761ae650dSJack F Vogel static int ixl_assign_vsi_msix(struct ixl_pf *); 10861ae650dSJack F Vogel static int ixl_assign_vsi_legacy(struct ixl_pf *); 10961ae650dSJack F Vogel static int ixl_init_msix(struct ixl_pf *); 11061ae650dSJack F Vogel static void ixl_configure_msix(struct ixl_pf *); 11161ae650dSJack F Vogel static void ixl_configure_itr(struct ixl_pf *); 11261ae650dSJack F Vogel static void ixl_configure_legacy(struct ixl_pf *); 11361ae650dSJack F Vogel static void ixl_free_pci_resources(struct ixl_pf *); 11461ae650dSJack F Vogel static void ixl_local_timer(void *); 11561ae650dSJack F Vogel static int ixl_setup_interface(device_t, struct ixl_vsi *); 11661ae650dSJack F Vogel static bool ixl_config_link(struct i40e_hw *); 11761ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *); 11861ae650dSJack F Vogel static void ixl_set_queue_rx_itr(struct ixl_queue *); 11961ae650dSJack F Vogel static void ixl_set_queue_tx_itr(struct ixl_queue *); 120e5100ee2SJack F Vogel static int ixl_set_advertised_speeds(struct ixl_pf *, int); 12161ae650dSJack F Vogel 12261ae650dSJack F Vogel static void ixl_enable_rings(struct ixl_vsi *); 12361ae650dSJack F Vogel static void ixl_disable_rings(struct ixl_vsi *); 12461ae650dSJack F Vogel static void ixl_enable_intr(struct ixl_vsi *); 12561ae650dSJack F Vogel static void ixl_disable_intr(struct ixl_vsi *); 12661ae650dSJack F Vogel 12761ae650dSJack F Vogel static void ixl_enable_adminq(struct i40e_hw *); 12861ae650dSJack F Vogel static void ixl_disable_adminq(struct i40e_hw *); 12961ae650dSJack F Vogel static void ixl_enable_queue(struct i40e_hw *, int); 13061ae650dSJack F Vogel static void ixl_disable_queue(struct i40e_hw *, int); 13161ae650dSJack F Vogel static void ixl_enable_legacy(struct i40e_hw *); 13261ae650dSJack F Vogel static void ixl_disable_legacy(struct i40e_hw *); 13361ae650dSJack F Vogel 13461ae650dSJack F Vogel static void ixl_set_promisc(struct ixl_vsi *); 13561ae650dSJack F Vogel static void ixl_add_multi(struct ixl_vsi *); 13661ae650dSJack F Vogel static void ixl_del_multi(struct ixl_vsi *); 13761ae650dSJack F Vogel static void ixl_register_vlan(void *, struct ifnet *, u16); 13861ae650dSJack F Vogel static void ixl_unregister_vlan(void *, struct ifnet *, u16); 13961ae650dSJack F Vogel static void ixl_setup_vlan_filters(struct ixl_vsi *); 14061ae650dSJack F Vogel 14161ae650dSJack F Vogel static void ixl_init_filters(struct ixl_vsi *); 14261ae650dSJack F Vogel static void ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan); 14361ae650dSJack F Vogel static void ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan); 14461ae650dSJack F Vogel static void ixl_add_hw_filters(struct ixl_vsi *, int, int); 14561ae650dSJack F Vogel static void ixl_del_hw_filters(struct ixl_vsi *, int); 14661ae650dSJack F Vogel static struct ixl_mac_filter * 14761ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *, u8 *, s16); 14861ae650dSJack F Vogel static void ixl_add_mc_filter(struct ixl_vsi *, u8 *); 14961ae650dSJack F Vogel 15061ae650dSJack F Vogel /* Sysctl debug interface */ 15161ae650dSJack F Vogel static int ixl_debug_info(SYSCTL_HANDLER_ARGS); 15261ae650dSJack F Vogel static void ixl_print_debug_info(struct ixl_pf *); 15361ae650dSJack F Vogel 15461ae650dSJack F Vogel /* The MSI/X Interrupt handlers */ 15561ae650dSJack F Vogel static void ixl_intr(void *); 15661ae650dSJack F Vogel static void ixl_msix_que(void *); 15761ae650dSJack F Vogel static void ixl_msix_adminq(void *); 15861ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *); 15961ae650dSJack F Vogel 16061ae650dSJack F Vogel /* Deferred interrupt tasklets */ 16161ae650dSJack F Vogel static void ixl_do_adminq(void *, int); 16261ae650dSJack F Vogel 16361ae650dSJack F Vogel /* Sysctl handlers */ 16461ae650dSJack F Vogel static int ixl_set_flowcntl(SYSCTL_HANDLER_ARGS); 16561ae650dSJack F Vogel static int ixl_set_advertise(SYSCTL_HANDLER_ARGS); 16661ae650dSJack F Vogel static int ixl_current_speed(SYSCTL_HANDLER_ARGS); 167e5100ee2SJack F Vogel static int ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS); 16861ae650dSJack F Vogel 16961ae650dSJack F Vogel /* Statistics */ 17061ae650dSJack F Vogel static void ixl_add_hw_stats(struct ixl_pf *); 17161ae650dSJack F Vogel static void ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *, 17261ae650dSJack F Vogel struct sysctl_oid_list *, struct i40e_hw_port_stats *); 17361ae650dSJack F Vogel static void ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *, 17461ae650dSJack F Vogel struct sysctl_oid_list *, 17561ae650dSJack F Vogel struct i40e_eth_stats *); 17661ae650dSJack F Vogel static void ixl_update_stats_counters(struct ixl_pf *); 17761ae650dSJack F Vogel static void ixl_update_eth_stats(struct ixl_vsi *); 17861ae650dSJack F Vogel static void ixl_pf_reset_stats(struct ixl_pf *); 17961ae650dSJack F Vogel static void ixl_vsi_reset_stats(struct ixl_vsi *); 18061ae650dSJack F Vogel static void ixl_stat_update48(struct i40e_hw *, u32, u32, bool, 18161ae650dSJack F Vogel u64 *, u64 *); 18261ae650dSJack F Vogel static void ixl_stat_update32(struct i40e_hw *, u32, bool, 18361ae650dSJack F Vogel u64 *, u64 *); 18461ae650dSJack F Vogel 185393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL 18661ae650dSJack F Vogel static int ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS); 18761ae650dSJack F Vogel static int ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS); 18861ae650dSJack F Vogel static int ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS); 189e5100ee2SJack F Vogel static int ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS); 190e5100ee2SJack F Vogel static int ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS); 19161ae650dSJack F Vogel static int ixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS); 19261ae650dSJack F Vogel #endif 19361ae650dSJack F Vogel 19461ae650dSJack F Vogel /********************************************************************* 19561ae650dSJack F Vogel * FreeBSD Device Interface Entry Points 19661ae650dSJack F Vogel *********************************************************************/ 19761ae650dSJack F Vogel 19861ae650dSJack F Vogel static device_method_t ixl_methods[] = { 19961ae650dSJack F Vogel /* Device interface */ 20061ae650dSJack F Vogel DEVMETHOD(device_probe, ixl_probe), 20161ae650dSJack F Vogel DEVMETHOD(device_attach, ixl_attach), 20261ae650dSJack F Vogel DEVMETHOD(device_detach, ixl_detach), 20361ae650dSJack F Vogel DEVMETHOD(device_shutdown, ixl_shutdown), 20461ae650dSJack F Vogel {0, 0} 20561ae650dSJack F Vogel }; 20661ae650dSJack F Vogel 20761ae650dSJack F Vogel static driver_t ixl_driver = { 20861ae650dSJack F Vogel "ixl", ixl_methods, sizeof(struct ixl_pf), 20961ae650dSJack F Vogel }; 21061ae650dSJack F Vogel 21161ae650dSJack F Vogel devclass_t ixl_devclass; 21261ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); 21361ae650dSJack F Vogel 21461ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1); 21561ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1); 216bc8b78d3SLuigi Rizzo #ifdef DEV_NETMAP 217bc8b78d3SLuigi Rizzo MODULE_DEPEND(ixl, netmap, 1, 1, 1); 218bc8b78d3SLuigi Rizzo #endif /* DEV_NETMAP */ 21961ae650dSJack F Vogel 22061ae650dSJack F Vogel /* 22161ae650dSJack F Vogel ** Global reset mutex 22261ae650dSJack F Vogel */ 22361ae650dSJack F Vogel static struct mtx ixl_reset_mtx; 22461ae650dSJack F Vogel 22561ae650dSJack F Vogel /* 22661ae650dSJack F Vogel ** TUNEABLE PARAMETERS: 22761ae650dSJack F Vogel */ 22861ae650dSJack F Vogel 22961ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, 23061ae650dSJack F Vogel "IXL driver parameters"); 23161ae650dSJack F Vogel 23261ae650dSJack F Vogel /* 23361ae650dSJack F Vogel * MSIX should be the default for best performance, 23461ae650dSJack F Vogel * but this allows it to be forced off for testing. 23561ae650dSJack F Vogel */ 23661ae650dSJack F Vogel static int ixl_enable_msix = 1; 23761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); 23861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, 23961ae650dSJack F Vogel "Enable MSI-X interrupts"); 24061ae650dSJack F Vogel 24161ae650dSJack F Vogel /* 24261ae650dSJack F Vogel ** Number of descriptors per ring: 24361ae650dSJack F Vogel ** - TX and RX are the same size 24461ae650dSJack F Vogel */ 24561ae650dSJack F Vogel static int ixl_ringsz = DEFAULT_RING; 24661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz); 24761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN, 24861ae650dSJack F Vogel &ixl_ringsz, 0, "Descriptor Ring Size"); 24961ae650dSJack F Vogel 25061ae650dSJack F Vogel /* 25161ae650dSJack F Vogel ** This can be set manually, if left as 0 the 25261ae650dSJack F Vogel ** number of queues will be calculated based 25361ae650dSJack F Vogel ** on cpus and msix vectors available. 25461ae650dSJack F Vogel */ 25561ae650dSJack F Vogel int ixl_max_queues = 0; 25661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues); 25761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN, 25861ae650dSJack F Vogel &ixl_max_queues, 0, "Number of Queues"); 25961ae650dSJack F Vogel 26061ae650dSJack F Vogel /* 26161ae650dSJack F Vogel ** Controls for Interrupt Throttling 26261ae650dSJack F Vogel ** - true/false for dynamic adjustment 26361ae650dSJack F Vogel ** - default values for static ITR 26461ae650dSJack F Vogel */ 26561ae650dSJack F Vogel int ixl_dynamic_rx_itr = 0; 26661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr); 26761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, 26861ae650dSJack F Vogel &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); 26961ae650dSJack F Vogel 27061ae650dSJack F Vogel int ixl_dynamic_tx_itr = 0; 27161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr); 27261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, 27361ae650dSJack F Vogel &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); 27461ae650dSJack F Vogel 27561ae650dSJack F Vogel int ixl_rx_itr = IXL_ITR_8K; 27661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr); 27761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, 27861ae650dSJack F Vogel &ixl_rx_itr, 0, "RX Interrupt Rate"); 27961ae650dSJack F Vogel 28061ae650dSJack F Vogel int ixl_tx_itr = IXL_ITR_4K; 28161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); 28261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, 28361ae650dSJack F Vogel &ixl_tx_itr, 0, "TX Interrupt Rate"); 28461ae650dSJack F Vogel 28561ae650dSJack F Vogel #ifdef IXL_FDIR 28661ae650dSJack F Vogel static int ixl_enable_fdir = 1; 28761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir); 28861ae650dSJack F Vogel /* Rate at which we sample */ 28961ae650dSJack F Vogel int ixl_atr_rate = 20; 29061ae650dSJack F Vogel TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate); 29161ae650dSJack F Vogel #endif 29261ae650dSJack F Vogel 293bc8b78d3SLuigi Rizzo #ifdef DEV_NETMAP 294bc8b78d3SLuigi Rizzo #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */ 295bc8b78d3SLuigi Rizzo #include <dev/netmap/if_ixl_netmap.h> 296bc8b78d3SLuigi Rizzo #endif /* DEV_NETMAP */ 297e5100ee2SJack F Vogel 29861ae650dSJack F Vogel static char *ixl_fc_string[6] = { 29961ae650dSJack F Vogel "None", 30061ae650dSJack F Vogel "Rx", 30161ae650dSJack F Vogel "Tx", 30261ae650dSJack F Vogel "Full", 30361ae650dSJack F Vogel "Priority", 30461ae650dSJack F Vogel "Default" 30561ae650dSJack F Vogel }; 30661ae650dSJack F Vogel 30761ae650dSJack F Vogel 30861ae650dSJack F Vogel /********************************************************************* 30961ae650dSJack F Vogel * Device identification routine 31061ae650dSJack F Vogel * 31161ae650dSJack F Vogel * ixl_probe determines if the driver should be loaded on 31261ae650dSJack F Vogel * the hardware based on PCI vendor/device id of the device. 31361ae650dSJack F Vogel * 31461ae650dSJack F Vogel * return BUS_PROBE_DEFAULT on success, positive on failure 31561ae650dSJack F Vogel *********************************************************************/ 31661ae650dSJack F Vogel 31761ae650dSJack F Vogel static int 31861ae650dSJack F Vogel ixl_probe(device_t dev) 31961ae650dSJack F Vogel { 32061ae650dSJack F Vogel ixl_vendor_info_t *ent; 32161ae650dSJack F Vogel 32261ae650dSJack F Vogel u16 pci_vendor_id, pci_device_id; 32361ae650dSJack F Vogel u16 pci_subvendor_id, pci_subdevice_id; 32461ae650dSJack F Vogel char device_name[256]; 32561ae650dSJack F Vogel static bool lock_init = FALSE; 32661ae650dSJack F Vogel 32761ae650dSJack F Vogel INIT_DEBUGOUT("ixl_probe: begin"); 32861ae650dSJack F Vogel 32961ae650dSJack F Vogel pci_vendor_id = pci_get_vendor(dev); 33061ae650dSJack F Vogel if (pci_vendor_id != I40E_INTEL_VENDOR_ID) 33161ae650dSJack F Vogel return (ENXIO); 33261ae650dSJack F Vogel 33361ae650dSJack F Vogel pci_device_id = pci_get_device(dev); 33461ae650dSJack F Vogel pci_subvendor_id = pci_get_subvendor(dev); 33561ae650dSJack F Vogel pci_subdevice_id = pci_get_subdevice(dev); 33661ae650dSJack F Vogel 33761ae650dSJack F Vogel ent = ixl_vendor_info_array; 33861ae650dSJack F Vogel while (ent->vendor_id != 0) { 33961ae650dSJack F Vogel if ((pci_vendor_id == ent->vendor_id) && 34061ae650dSJack F Vogel (pci_device_id == ent->device_id) && 34161ae650dSJack F Vogel 34261ae650dSJack F Vogel ((pci_subvendor_id == ent->subvendor_id) || 34361ae650dSJack F Vogel (ent->subvendor_id == 0)) && 34461ae650dSJack F Vogel 34561ae650dSJack F Vogel ((pci_subdevice_id == ent->subdevice_id) || 34661ae650dSJack F Vogel (ent->subdevice_id == 0))) { 34761ae650dSJack F Vogel sprintf(device_name, "%s, Version - %s", 34861ae650dSJack F Vogel ixl_strings[ent->index], 34961ae650dSJack F Vogel ixl_driver_version); 35061ae650dSJack F Vogel device_set_desc_copy(dev, device_name); 35161ae650dSJack F Vogel /* One shot mutex init */ 35261ae650dSJack F Vogel if (lock_init == FALSE) { 35361ae650dSJack F Vogel lock_init = TRUE; 35461ae650dSJack F Vogel mtx_init(&ixl_reset_mtx, 35561ae650dSJack F Vogel "ixl_reset", 35661ae650dSJack F Vogel "IXL RESET Lock", MTX_DEF); 35761ae650dSJack F Vogel } 35861ae650dSJack F Vogel return (BUS_PROBE_DEFAULT); 35961ae650dSJack F Vogel } 36061ae650dSJack F Vogel ent++; 36161ae650dSJack F Vogel } 36261ae650dSJack F Vogel return (ENXIO); 36361ae650dSJack F Vogel } 36461ae650dSJack F Vogel 36561ae650dSJack F Vogel /********************************************************************* 36661ae650dSJack F Vogel * Device initialization routine 36761ae650dSJack F Vogel * 36861ae650dSJack F Vogel * The attach entry point is called when the driver is being loaded. 36961ae650dSJack F Vogel * This routine identifies the type of hardware, allocates all resources 37061ae650dSJack F Vogel * and initializes the hardware. 37161ae650dSJack F Vogel * 37261ae650dSJack F Vogel * return 0 on success, positive on failure 37361ae650dSJack F Vogel *********************************************************************/ 37461ae650dSJack F Vogel 37561ae650dSJack F Vogel static int 37661ae650dSJack F Vogel ixl_attach(device_t dev) 37761ae650dSJack F Vogel { 37861ae650dSJack F Vogel struct ixl_pf *pf; 37961ae650dSJack F Vogel struct i40e_hw *hw; 38061ae650dSJack F Vogel struct ixl_vsi *vsi; 38161ae650dSJack F Vogel u16 bus; 38261ae650dSJack F Vogel int error = 0; 38361ae650dSJack F Vogel 38461ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: begin"); 38561ae650dSJack F Vogel 38661ae650dSJack F Vogel /* Allocate, clear, and link in our primary soft structure */ 38761ae650dSJack F Vogel pf = device_get_softc(dev); 38861ae650dSJack F Vogel pf->dev = pf->osdep.dev = dev; 38961ae650dSJack F Vogel hw = &pf->hw; 39061ae650dSJack F Vogel 39161ae650dSJack F Vogel /* 39261ae650dSJack F Vogel ** Note this assumes we have a single embedded VSI, 39361ae650dSJack F Vogel ** this could be enhanced later to allocate multiple 39461ae650dSJack F Vogel */ 39561ae650dSJack F Vogel vsi = &pf->vsi; 39661ae650dSJack F Vogel vsi->dev = pf->dev; 39761ae650dSJack F Vogel 39861ae650dSJack F Vogel /* Core Lock Init*/ 39961ae650dSJack F Vogel IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev)); 40061ae650dSJack F Vogel 40161ae650dSJack F Vogel /* Set up the timer callout */ 40261ae650dSJack F Vogel callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); 40361ae650dSJack F Vogel 40461ae650dSJack F Vogel /* Set up sysctls */ 40561ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 40661ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 40761ae650dSJack F Vogel OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, 40861ae650dSJack F Vogel pf, 0, ixl_set_flowcntl, "I", "Flow Control"); 40961ae650dSJack F Vogel 41061ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 41161ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 41261ae650dSJack F Vogel OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, 41361ae650dSJack F Vogel pf, 0, ixl_set_advertise, "I", "Advertised Speed"); 41461ae650dSJack F Vogel 41561ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 41661ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 41761ae650dSJack F Vogel OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD, 41861ae650dSJack F Vogel pf, 0, ixl_current_speed, "A", "Current Port Speed"); 41961ae650dSJack F Vogel 420e5100ee2SJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 421e5100ee2SJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 422e5100ee2SJack F Vogel OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD, 423e5100ee2SJack F Vogel pf, 0, ixl_sysctl_show_fw, "A", "Firmware version"); 424e5100ee2SJack F Vogel 42561ae650dSJack F Vogel SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 42661ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 427f0188618SHans Petter Selasky OID_AUTO, "rx_itr", CTLFLAG_RW, 42861ae650dSJack F Vogel &ixl_rx_itr, IXL_ITR_8K, "RX ITR"); 42961ae650dSJack F Vogel 43061ae650dSJack F Vogel SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 43161ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 432f0188618SHans Petter Selasky OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW, 43361ae650dSJack F Vogel &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR"); 43461ae650dSJack F Vogel 43561ae650dSJack F Vogel SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 43661ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 437f0188618SHans Petter Selasky OID_AUTO, "tx_itr", CTLFLAG_RW, 43861ae650dSJack F Vogel &ixl_tx_itr, IXL_ITR_4K, "TX ITR"); 43961ae650dSJack F Vogel 44061ae650dSJack F Vogel SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 44161ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 442f0188618SHans Petter Selasky OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW, 44361ae650dSJack F Vogel &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR"); 44461ae650dSJack F Vogel 445393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL 44661ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 44761ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 44861ae650dSJack F Vogel OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD, 44961ae650dSJack F Vogel pf, 0, ixl_sysctl_link_status, "A", "Current Link Status"); 45061ae650dSJack F Vogel 45161ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 45261ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 45361ae650dSJack F Vogel OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD, 45461ae650dSJack F Vogel pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities"); 45561ae650dSJack F Vogel 45661ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 45761ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 45861ae650dSJack F Vogel OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD, 45961ae650dSJack F Vogel pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List"); 46061ae650dSJack F Vogel 46161ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 46261ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 463e5100ee2SJack F Vogel OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD, 464e5100ee2SJack F Vogel pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation"); 465e5100ee2SJack F Vogel 466e5100ee2SJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 467e5100ee2SJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 468e5100ee2SJack F Vogel OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD, 469e5100ee2SJack F Vogel pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration"); 47061ae650dSJack F Vogel 47161ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 47261ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 47361ae650dSJack F Vogel OID_AUTO, "dump_desc", CTLTYPE_INT | CTLFLAG_WR, 47461ae650dSJack F Vogel pf, 0, ixl_sysctl_dump_txd, "I", "Desc dump"); 47561ae650dSJack F Vogel #endif 47661ae650dSJack F Vogel 477e5100ee2SJack F Vogel /* Save off the PCI information */ 47861ae650dSJack F Vogel hw->vendor_id = pci_get_vendor(dev); 47961ae650dSJack F Vogel hw->device_id = pci_get_device(dev); 48061ae650dSJack F Vogel hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 48161ae650dSJack F Vogel hw->subsystem_vendor_id = 48261ae650dSJack F Vogel pci_read_config(dev, PCIR_SUBVEND_0, 2); 48361ae650dSJack F Vogel hw->subsystem_device_id = 48461ae650dSJack F Vogel pci_read_config(dev, PCIR_SUBDEV_0, 2); 48561ae650dSJack F Vogel 48661ae650dSJack F Vogel hw->bus.device = pci_get_slot(dev); 48761ae650dSJack F Vogel hw->bus.func = pci_get_function(dev); 48861ae650dSJack F Vogel 48961ae650dSJack F Vogel /* Do PCI setup - map BAR0, etc */ 49061ae650dSJack F Vogel if (ixl_allocate_pci_resources(pf)) { 49161ae650dSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 49261ae650dSJack F Vogel error = ENXIO; 49361ae650dSJack F Vogel goto err_out; 49461ae650dSJack F Vogel } 49561ae650dSJack F Vogel 49661ae650dSJack F Vogel /* Create for initial debugging use */ 49761ae650dSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 49861ae650dSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 49961ae650dSJack F Vogel OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0, 50061ae650dSJack F Vogel ixl_debug_info, "I", "Debug Information"); 50161ae650dSJack F Vogel 50261ae650dSJack F Vogel 50361ae650dSJack F Vogel /* Establish a clean starting point */ 50461ae650dSJack F Vogel i40e_clear_hw(hw); 50561ae650dSJack F Vogel error = i40e_pf_reset(hw); 50661ae650dSJack F Vogel if (error) { 50761ae650dSJack F Vogel device_printf(dev,"PF reset failure %x\n", error); 50861ae650dSJack F Vogel error = EIO; 50961ae650dSJack F Vogel goto err_out; 51061ae650dSJack F Vogel } 51161ae650dSJack F Vogel 51261ae650dSJack F Vogel /* Set admin queue parameters */ 51361ae650dSJack F Vogel hw->aq.num_arq_entries = IXL_AQ_LEN; 51461ae650dSJack F Vogel hw->aq.num_asq_entries = IXL_AQ_LEN; 51561ae650dSJack F Vogel hw->aq.arq_buf_size = IXL_AQ_BUFSZ; 51661ae650dSJack F Vogel hw->aq.asq_buf_size = IXL_AQ_BUFSZ; 51761ae650dSJack F Vogel 51861ae650dSJack F Vogel /* Initialize the shared code */ 51961ae650dSJack F Vogel error = i40e_init_shared_code(hw); 52061ae650dSJack F Vogel if (error) { 52161ae650dSJack F Vogel device_printf(dev,"Unable to initialize the shared code\n"); 52261ae650dSJack F Vogel error = EIO; 52361ae650dSJack F Vogel goto err_out; 52461ae650dSJack F Vogel } 52561ae650dSJack F Vogel 52661ae650dSJack F Vogel /* Set up the admin queue */ 52761ae650dSJack F Vogel error = i40e_init_adminq(hw); 52861ae650dSJack F Vogel if (error) { 52961ae650dSJack F Vogel device_printf(dev, "The driver for the device stopped " 53061ae650dSJack F Vogel "because the NVM image is newer than expected.\n" 53161ae650dSJack F Vogel "You must install the most recent version of " 53261ae650dSJack F Vogel " the network driver.\n"); 53361ae650dSJack F Vogel goto err_out; 53461ae650dSJack F Vogel } 53561ae650dSJack F Vogel device_printf(dev, "%s\n", ixl_fw_version_str(hw)); 53661ae650dSJack F Vogel 53761ae650dSJack F Vogel if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 53861ae650dSJack F Vogel hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) 53961ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 54061ae650dSJack F Vogel "a newer version of the NVM image than expected.\n" 54161ae650dSJack F Vogel "Please install the most recent version of the network driver.\n"); 54261ae650dSJack F Vogel else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || 54361ae650dSJack F Vogel hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) 54461ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 54561ae650dSJack F Vogel "an older version of the NVM image than expected.\n" 54661ae650dSJack F Vogel "Please update the NVM image.\n"); 54761ae650dSJack F Vogel 54861ae650dSJack F Vogel /* Clear PXE mode */ 54961ae650dSJack F Vogel i40e_clear_pxe_mode(hw); 55061ae650dSJack F Vogel 55161ae650dSJack F Vogel /* Get capabilities from the device */ 55261ae650dSJack F Vogel error = ixl_get_hw_capabilities(pf); 55361ae650dSJack F Vogel if (error) { 55461ae650dSJack F Vogel device_printf(dev, "HW capabilities failure!\n"); 55561ae650dSJack F Vogel goto err_get_cap; 55661ae650dSJack F Vogel } 55761ae650dSJack F Vogel 55861ae650dSJack F Vogel /* Set up host memory cache */ 55961ae650dSJack F Vogel error = i40e_init_lan_hmc(hw, vsi->num_queues, vsi->num_queues, 0, 0); 56061ae650dSJack F Vogel if (error) { 56161ae650dSJack F Vogel device_printf(dev, "init_lan_hmc failed: %d\n", error); 56261ae650dSJack F Vogel goto err_get_cap; 56361ae650dSJack F Vogel } 56461ae650dSJack F Vogel 56561ae650dSJack F Vogel error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 56661ae650dSJack F Vogel if (error) { 56761ae650dSJack F Vogel device_printf(dev, "configure_lan_hmc failed: %d\n", error); 56861ae650dSJack F Vogel goto err_mac_hmc; 56961ae650dSJack F Vogel } 57061ae650dSJack F Vogel 57161ae650dSJack F Vogel /* Disable LLDP from the firmware */ 57261ae650dSJack F Vogel i40e_aq_stop_lldp(hw, TRUE, NULL); 57361ae650dSJack F Vogel 57461ae650dSJack F Vogel i40e_get_mac_addr(hw, hw->mac.addr); 57561ae650dSJack F Vogel error = i40e_validate_mac_addr(hw->mac.addr); 57661ae650dSJack F Vogel if (error) { 57761ae650dSJack F Vogel device_printf(dev, "validate_mac_addr failed: %d\n", error); 57861ae650dSJack F Vogel goto err_mac_hmc; 57961ae650dSJack F Vogel } 58061ae650dSJack F Vogel bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 58161ae650dSJack F Vogel i40e_get_port_mac_addr(hw, hw->mac.port_addr); 58261ae650dSJack F Vogel 583e5100ee2SJack F Vogel /* Set up VSI and queues */ 58461ae650dSJack F Vogel if (ixl_setup_stations(pf) != 0) { 58561ae650dSJack F Vogel device_printf(dev, "setup stations failed!\n"); 58661ae650dSJack F Vogel error = ENOMEM; 58761ae650dSJack F Vogel goto err_mac_hmc; 58861ae650dSJack F Vogel } 58961ae650dSJack F Vogel 59061ae650dSJack F Vogel /* Initialize mac filter list for VSI */ 59161ae650dSJack F Vogel SLIST_INIT(&vsi->ftl); 59261ae650dSJack F Vogel 59361ae650dSJack F Vogel /* Set up interrupt routing here */ 59461ae650dSJack F Vogel if (pf->msix > 1) 59561ae650dSJack F Vogel error = ixl_assign_vsi_msix(pf); 59661ae650dSJack F Vogel else 59761ae650dSJack F Vogel error = ixl_assign_vsi_legacy(pf); 59861ae650dSJack F Vogel if (error) 59961ae650dSJack F Vogel goto err_late; 60061ae650dSJack F Vogel 601b6c8f260SJack F Vogel if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 602b6c8f260SJack F Vogel (hw->aq.fw_maj_ver < 4)) { 60361ae650dSJack F Vogel i40e_msec_delay(75); 60461ae650dSJack F Vogel error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 605b6c8f260SJack F Vogel if (error) 60661ae650dSJack F Vogel device_printf(dev, "link restart failed, aq_err=%d\n", 60761ae650dSJack F Vogel pf->hw.aq.asq_last_status); 60861ae650dSJack F Vogel } 60961ae650dSJack F Vogel 61061ae650dSJack F Vogel /* Determine link state */ 61161ae650dSJack F Vogel vsi->link_up = ixl_config_link(hw); 61261ae650dSJack F Vogel 61361ae650dSJack F Vogel /* Report if Unqualified modules are found */ 61461ae650dSJack F Vogel if ((vsi->link_up == FALSE) && 61561ae650dSJack F Vogel (pf->hw.phy.link_info.link_info & 61661ae650dSJack F Vogel I40E_AQ_MEDIA_AVAILABLE) && 61761ae650dSJack F Vogel (!(pf->hw.phy.link_info.an_info & 61861ae650dSJack F Vogel I40E_AQ_QUALIFIED_MODULE))) 61961ae650dSJack F Vogel device_printf(dev, "Link failed because " 62061ae650dSJack F Vogel "an unqualified module was detected\n"); 62161ae650dSJack F Vogel 62261ae650dSJack F Vogel /* Setup OS specific network interface */ 623e5100ee2SJack F Vogel if (ixl_setup_interface(dev, vsi) != 0) { 624e5100ee2SJack F Vogel device_printf(dev, "interface setup failed!\n"); 625e5100ee2SJack F Vogel error = EIO; 62661ae650dSJack F Vogel goto err_late; 627e5100ee2SJack F Vogel } 62861ae650dSJack F Vogel 629b6c8f260SJack F Vogel error = ixl_switch_config(pf); 630b6c8f260SJack F Vogel if (error) { 631b6c8f260SJack F Vogel device_printf(dev, "Initial switch config failed: %d\n", error); 632b6c8f260SJack F Vogel goto err_mac_hmc; 633b6c8f260SJack F Vogel } 634b6c8f260SJack F Vogel 635b6c8f260SJack F Vogel /* Limit phy interrupts to link and modules failure */ 636b6c8f260SJack F Vogel error = i40e_aq_set_phy_int_mask(hw, 637b6c8f260SJack F Vogel I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL); 638b6c8f260SJack F Vogel if (error) 639b6c8f260SJack F Vogel device_printf(dev, "set phy mask failed: %d\n", error); 640b6c8f260SJack F Vogel 64161ae650dSJack F Vogel /* Get the bus configuration and set the shared code */ 64261ae650dSJack F Vogel bus = ixl_get_bus_info(hw, dev); 64361ae650dSJack F Vogel i40e_set_pci_config_data(hw, bus); 64461ae650dSJack F Vogel 64561ae650dSJack F Vogel /* Initialize statistics */ 64661ae650dSJack F Vogel ixl_pf_reset_stats(pf); 64761ae650dSJack F Vogel ixl_update_stats_counters(pf); 64861ae650dSJack F Vogel ixl_add_hw_stats(pf); 64961ae650dSJack F Vogel 65061ae650dSJack F Vogel /* Register for VLAN events */ 65161ae650dSJack F Vogel vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 65261ae650dSJack F Vogel ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); 65361ae650dSJack F Vogel vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 65461ae650dSJack F Vogel ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); 65561ae650dSJack F Vogel 656e5100ee2SJack F Vogel 657bc8b78d3SLuigi Rizzo #ifdef DEV_NETMAP 658bc8b78d3SLuigi Rizzo ixl_netmap_attach(vsi); 659bc8b78d3SLuigi Rizzo #endif /* DEV_NETMAP */ 66061ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: end"); 66161ae650dSJack F Vogel return (0); 66261ae650dSJack F Vogel 66361ae650dSJack F Vogel err_late: 664e5100ee2SJack F Vogel if (vsi->ifp != NULL) 665e5100ee2SJack F Vogel if_free(vsi->ifp); 66661ae650dSJack F Vogel err_mac_hmc: 66761ae650dSJack F Vogel i40e_shutdown_lan_hmc(hw); 66861ae650dSJack F Vogel err_get_cap: 66961ae650dSJack F Vogel i40e_shutdown_adminq(hw); 67061ae650dSJack F Vogel err_out: 67161ae650dSJack F Vogel ixl_free_pci_resources(pf); 672e5100ee2SJack F Vogel ixl_free_vsi(vsi); 67361ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 67461ae650dSJack F Vogel return (error); 67561ae650dSJack F Vogel } 67661ae650dSJack F Vogel 67761ae650dSJack F Vogel /********************************************************************* 67861ae650dSJack F Vogel * Device removal routine 67961ae650dSJack F Vogel * 68061ae650dSJack F Vogel * The detach entry point is called when the driver is being removed. 68161ae650dSJack F Vogel * This routine stops the adapter and deallocates all the resources 68261ae650dSJack F Vogel * that were allocated for driver operation. 68361ae650dSJack F Vogel * 68461ae650dSJack F Vogel * return 0 on success, positive on failure 68561ae650dSJack F Vogel *********************************************************************/ 68661ae650dSJack F Vogel 68761ae650dSJack F Vogel static int 68861ae650dSJack F Vogel ixl_detach(device_t dev) 68961ae650dSJack F Vogel { 69061ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 69161ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 69261ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 69361ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 69461ae650dSJack F Vogel i40e_status status; 69561ae650dSJack F Vogel 69661ae650dSJack F Vogel INIT_DEBUGOUT("ixl_detach: begin"); 69761ae650dSJack F Vogel 69861ae650dSJack F Vogel /* Make sure VLANS are not using driver */ 69961ae650dSJack F Vogel if (vsi->ifp->if_vlantrunk != NULL) { 70061ae650dSJack F Vogel device_printf(dev,"Vlan in use, detach first\n"); 70161ae650dSJack F Vogel return (EBUSY); 70261ae650dSJack F Vogel } 70361ae650dSJack F Vogel 704b6c8f260SJack F Vogel ether_ifdetach(vsi->ifp); 705b6c8f260SJack F Vogel if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) { 70661ae650dSJack F Vogel IXL_PF_LOCK(pf); 70761ae650dSJack F Vogel ixl_stop(pf); 70861ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 709b6c8f260SJack F Vogel } 71061ae650dSJack F Vogel 71161ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 71261ae650dSJack F Vogel if (que->tq) { 71361ae650dSJack F Vogel taskqueue_drain(que->tq, &que->task); 71461ae650dSJack F Vogel taskqueue_drain(que->tq, &que->tx_task); 71561ae650dSJack F Vogel taskqueue_free(que->tq); 71661ae650dSJack F Vogel } 71761ae650dSJack F Vogel } 71861ae650dSJack F Vogel 71961ae650dSJack F Vogel /* Shutdown LAN HMC */ 72061ae650dSJack F Vogel status = i40e_shutdown_lan_hmc(hw); 72161ae650dSJack F Vogel if (status) 72261ae650dSJack F Vogel device_printf(dev, 72361ae650dSJack F Vogel "Shutdown LAN HMC failed with code %d\n", status); 72461ae650dSJack F Vogel 72561ae650dSJack F Vogel /* Shutdown admin queue */ 72661ae650dSJack F Vogel status = i40e_shutdown_adminq(hw); 72761ae650dSJack F Vogel if (status) 72861ae650dSJack F Vogel device_printf(dev, 72961ae650dSJack F Vogel "Shutdown Admin queue failed with code %d\n", status); 73061ae650dSJack F Vogel 73161ae650dSJack F Vogel /* Unregister VLAN events */ 73261ae650dSJack F Vogel if (vsi->vlan_attach != NULL) 73361ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); 73461ae650dSJack F Vogel if (vsi->vlan_detach != NULL) 73561ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); 73661ae650dSJack F Vogel 73761ae650dSJack F Vogel callout_drain(&pf->timer); 738bc8b78d3SLuigi Rizzo #ifdef DEV_NETMAP 739bc8b78d3SLuigi Rizzo netmap_detach(vsi->ifp); 740bc8b78d3SLuigi Rizzo #endif /* DEV_NETMAP */ 74161ae650dSJack F Vogel 742e5100ee2SJack F Vogel 74361ae650dSJack F Vogel ixl_free_pci_resources(pf); 74461ae650dSJack F Vogel bus_generic_detach(dev); 74561ae650dSJack F Vogel if_free(vsi->ifp); 74661ae650dSJack F Vogel ixl_free_vsi(vsi); 74761ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 74861ae650dSJack F Vogel return (0); 74961ae650dSJack F Vogel } 75061ae650dSJack F Vogel 75161ae650dSJack F Vogel /********************************************************************* 75261ae650dSJack F Vogel * 75361ae650dSJack F Vogel * Shutdown entry point 75461ae650dSJack F Vogel * 75561ae650dSJack F Vogel **********************************************************************/ 75661ae650dSJack F Vogel 75761ae650dSJack F Vogel static int 75861ae650dSJack F Vogel ixl_shutdown(device_t dev) 75961ae650dSJack F Vogel { 76061ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 76161ae650dSJack F Vogel IXL_PF_LOCK(pf); 76261ae650dSJack F Vogel ixl_stop(pf); 76361ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 76461ae650dSJack F Vogel return (0); 76561ae650dSJack F Vogel } 76661ae650dSJack F Vogel 76761ae650dSJack F Vogel 76861ae650dSJack F Vogel /********************************************************************* 76961ae650dSJack F Vogel * 77061ae650dSJack F Vogel * Get the hardware capabilities 77161ae650dSJack F Vogel * 77261ae650dSJack F Vogel **********************************************************************/ 77361ae650dSJack F Vogel 77461ae650dSJack F Vogel static int 77561ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf) 77661ae650dSJack F Vogel { 77761ae650dSJack F Vogel struct i40e_aqc_list_capabilities_element_resp *buf; 77861ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 77961ae650dSJack F Vogel device_t dev = pf->dev; 78061ae650dSJack F Vogel int error, len; 78161ae650dSJack F Vogel u16 needed; 78261ae650dSJack F Vogel bool again = TRUE; 78361ae650dSJack F Vogel 78461ae650dSJack F Vogel len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); 78561ae650dSJack F Vogel retry: 78661ae650dSJack F Vogel if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *) 78761ae650dSJack F Vogel malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) { 78861ae650dSJack F Vogel device_printf(dev, "Unable to allocate cap memory\n"); 78961ae650dSJack F Vogel return (ENOMEM); 79061ae650dSJack F Vogel } 79161ae650dSJack F Vogel 79261ae650dSJack F Vogel /* This populates the hw struct */ 79361ae650dSJack F Vogel error = i40e_aq_discover_capabilities(hw, buf, len, 79461ae650dSJack F Vogel &needed, i40e_aqc_opc_list_func_capabilities, NULL); 79561ae650dSJack F Vogel free(buf, M_DEVBUF); 79661ae650dSJack F Vogel if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && 79761ae650dSJack F Vogel (again == TRUE)) { 79861ae650dSJack F Vogel /* retry once with a larger buffer */ 79961ae650dSJack F Vogel again = FALSE; 80061ae650dSJack F Vogel len = needed; 80161ae650dSJack F Vogel goto retry; 80261ae650dSJack F Vogel } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { 80361ae650dSJack F Vogel device_printf(dev, "capability discovery failed: %d\n", 80461ae650dSJack F Vogel pf->hw.aq.asq_last_status); 80561ae650dSJack F Vogel return (ENODEV); 80661ae650dSJack F Vogel } 80761ae650dSJack F Vogel 80861ae650dSJack F Vogel /* Capture this PF's starting queue pair */ 80961ae650dSJack F Vogel pf->qbase = hw->func_caps.base_queue; 81061ae650dSJack F Vogel 81161ae650dSJack F Vogel #ifdef IXL_DEBUG 81261ae650dSJack F Vogel device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, " 81361ae650dSJack F Vogel "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", 81461ae650dSJack F Vogel hw->pf_id, hw->func_caps.num_vfs, 81561ae650dSJack F Vogel hw->func_caps.num_msix_vectors, 81661ae650dSJack F Vogel hw->func_caps.num_msix_vectors_vf, 81761ae650dSJack F Vogel hw->func_caps.fd_filters_guaranteed, 81861ae650dSJack F Vogel hw->func_caps.fd_filters_best_effort, 81961ae650dSJack F Vogel hw->func_caps.num_tx_qp, 82061ae650dSJack F Vogel hw->func_caps.num_rx_qp, 82161ae650dSJack F Vogel hw->func_caps.base_queue); 82261ae650dSJack F Vogel #endif 82361ae650dSJack F Vogel return (error); 82461ae650dSJack F Vogel } 82561ae650dSJack F Vogel 82661ae650dSJack F Vogel static void 82761ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) 82861ae650dSJack F Vogel { 82961ae650dSJack F Vogel device_t dev = vsi->dev; 83061ae650dSJack F Vogel 83161ae650dSJack F Vogel /* Enable/disable TXCSUM/TSO4 */ 83261ae650dSJack F Vogel if (!(ifp->if_capenable & IFCAP_TXCSUM) 83361ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO4)) { 83461ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) { 83561ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TXCSUM; 83661ae650dSJack F Vogel /* enable TXCSUM, restore TSO if previously enabled */ 83761ae650dSJack F Vogel if (vsi->flags & IXL_FLAGS_KEEP_TSO4) { 83861ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 83961ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO4; 84061ae650dSJack F Vogel } 84161ae650dSJack F Vogel } 84261ae650dSJack F Vogel else if (mask & IFCAP_TSO4) { 84361ae650dSJack F Vogel ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); 84461ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 84561ae650dSJack F Vogel device_printf(dev, 84661ae650dSJack F Vogel "TSO4 requires txcsum, enabling both...\n"); 84761ae650dSJack F Vogel } 84861ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM) 84961ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO4)) { 85061ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) 85161ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TXCSUM; 85261ae650dSJack F Vogel else if (mask & IFCAP_TSO4) 85361ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO4; 85461ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM) 85561ae650dSJack F Vogel && (ifp->if_capenable & IFCAP_TSO4)) { 85661ae650dSJack F Vogel if (mask & IFCAP_TXCSUM) { 85761ae650dSJack F Vogel vsi->flags |= IXL_FLAGS_KEEP_TSO4; 85861ae650dSJack F Vogel ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); 85961ae650dSJack F Vogel device_printf(dev, 86061ae650dSJack F Vogel "TSO4 requires txcsum, disabling both...\n"); 86161ae650dSJack F Vogel } else if (mask & IFCAP_TSO4) 86261ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TSO4; 86361ae650dSJack F Vogel } 86461ae650dSJack F Vogel 86561ae650dSJack F Vogel /* Enable/disable TXCSUM_IPV6/TSO6 */ 86661ae650dSJack F Vogel if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) 86761ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO6)) { 86861ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) { 86961ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TXCSUM_IPV6; 87061ae650dSJack F Vogel if (vsi->flags & IXL_FLAGS_KEEP_TSO6) { 87161ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 87261ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO6; 87361ae650dSJack F Vogel } 87461ae650dSJack F Vogel } else if (mask & IFCAP_TSO6) { 87561ae650dSJack F Vogel ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 87661ae650dSJack F Vogel vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 87761ae650dSJack F Vogel device_printf(dev, 87861ae650dSJack F Vogel "TSO6 requires txcsum6, enabling both...\n"); 87961ae650dSJack F Vogel } 88061ae650dSJack F Vogel } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 88161ae650dSJack F Vogel && !(ifp->if_capenable & IFCAP_TSO6)) { 88261ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) 88361ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; 88461ae650dSJack F Vogel else if (mask & IFCAP_TSO6) 88561ae650dSJack F Vogel ifp->if_capenable |= IFCAP_TSO6; 88661ae650dSJack F Vogel } else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 88761ae650dSJack F Vogel && (ifp->if_capenable & IFCAP_TSO6)) { 88861ae650dSJack F Vogel if (mask & IFCAP_TXCSUM_IPV6) { 88961ae650dSJack F Vogel vsi->flags |= IXL_FLAGS_KEEP_TSO6; 89061ae650dSJack F Vogel ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 89161ae650dSJack F Vogel device_printf(dev, 89261ae650dSJack F Vogel "TSO6 requires txcsum6, disabling both...\n"); 89361ae650dSJack F Vogel } else if (mask & IFCAP_TSO6) 89461ae650dSJack F Vogel ifp->if_capenable &= ~IFCAP_TSO6; 89561ae650dSJack F Vogel } 89661ae650dSJack F Vogel } 89761ae650dSJack F Vogel 89861ae650dSJack F Vogel /********************************************************************* 89961ae650dSJack F Vogel * Ioctl entry point 90061ae650dSJack F Vogel * 90161ae650dSJack F Vogel * ixl_ioctl is called when the user wants to configure the 90261ae650dSJack F Vogel * interface. 90361ae650dSJack F Vogel * 90461ae650dSJack F Vogel * return 0 on success, positive on failure 90561ae650dSJack F Vogel **********************************************************************/ 90661ae650dSJack F Vogel 90761ae650dSJack F Vogel static int 90861ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 90961ae650dSJack F Vogel { 91061ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 91161ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 91261ae650dSJack F Vogel struct ifreq *ifr = (struct ifreq *) data; 91361ae650dSJack F Vogel #if defined(INET) || defined(INET6) 91461ae650dSJack F Vogel struct ifaddr *ifa = (struct ifaddr *)data; 91561ae650dSJack F Vogel bool avoid_reset = FALSE; 91661ae650dSJack F Vogel #endif 91761ae650dSJack F Vogel int error = 0; 91861ae650dSJack F Vogel 91961ae650dSJack F Vogel switch (command) { 92061ae650dSJack F Vogel 92161ae650dSJack F Vogel case SIOCSIFADDR: 92261ae650dSJack F Vogel #ifdef INET 92361ae650dSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET) 92461ae650dSJack F Vogel avoid_reset = TRUE; 92561ae650dSJack F Vogel #endif 92661ae650dSJack F Vogel #ifdef INET6 92761ae650dSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET6) 92861ae650dSJack F Vogel avoid_reset = TRUE; 92961ae650dSJack F Vogel #endif 93061ae650dSJack F Vogel #if defined(INET) || defined(INET6) 93161ae650dSJack F Vogel /* 93261ae650dSJack F Vogel ** Calling init results in link renegotiation, 93361ae650dSJack F Vogel ** so we avoid doing it when possible. 93461ae650dSJack F Vogel */ 93561ae650dSJack F Vogel if (avoid_reset) { 93661ae650dSJack F Vogel ifp->if_flags |= IFF_UP; 93761ae650dSJack F Vogel if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 93861ae650dSJack F Vogel ixl_init(pf); 9397e0dde7dSBjoern A. Zeeb #ifdef INET 94061ae650dSJack F Vogel if (!(ifp->if_flags & IFF_NOARP)) 94161ae650dSJack F Vogel arp_ifinit(ifp, ifa); 9427e0dde7dSBjoern A. Zeeb #endif 94361ae650dSJack F Vogel } else 94461ae650dSJack F Vogel error = ether_ioctl(ifp, command, data); 94561ae650dSJack F Vogel break; 94661ae650dSJack F Vogel #endif 94761ae650dSJack F Vogel case SIOCSIFMTU: 94861ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 94961ae650dSJack F Vogel if (ifr->ifr_mtu > IXL_MAX_FRAME - 95061ae650dSJack F Vogel ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) { 95161ae650dSJack F Vogel error = EINVAL; 95261ae650dSJack F Vogel } else { 95361ae650dSJack F Vogel IXL_PF_LOCK(pf); 95461ae650dSJack F Vogel ifp->if_mtu = ifr->ifr_mtu; 95561ae650dSJack F Vogel vsi->max_frame_size = 95661ae650dSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 95761ae650dSJack F Vogel + ETHER_VLAN_ENCAP_LEN; 95861ae650dSJack F Vogel ixl_init_locked(pf); 95961ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 96061ae650dSJack F Vogel } 96161ae650dSJack F Vogel break; 96261ae650dSJack F Vogel case SIOCSIFFLAGS: 96361ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 96461ae650dSJack F Vogel IXL_PF_LOCK(pf); 96561ae650dSJack F Vogel if (ifp->if_flags & IFF_UP) { 96661ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 96761ae650dSJack F Vogel if ((ifp->if_flags ^ pf->if_flags) & 96861ae650dSJack F Vogel (IFF_PROMISC | IFF_ALLMULTI)) { 96961ae650dSJack F Vogel ixl_set_promisc(vsi); 97061ae650dSJack F Vogel } 97161ae650dSJack F Vogel } else 97261ae650dSJack F Vogel ixl_init_locked(pf); 97361ae650dSJack F Vogel } else 97461ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) 97561ae650dSJack F Vogel ixl_stop(pf); 97661ae650dSJack F Vogel pf->if_flags = ifp->if_flags; 97761ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 97861ae650dSJack F Vogel break; 97961ae650dSJack F Vogel case SIOCADDMULTI: 98061ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); 98161ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 98261ae650dSJack F Vogel IXL_PF_LOCK(pf); 98361ae650dSJack F Vogel ixl_disable_intr(vsi); 98461ae650dSJack F Vogel ixl_add_multi(vsi); 98561ae650dSJack F Vogel ixl_enable_intr(vsi); 98661ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 98761ae650dSJack F Vogel } 98861ae650dSJack F Vogel break; 98961ae650dSJack F Vogel case SIOCDELMULTI: 99061ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); 99161ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 99261ae650dSJack F Vogel IXL_PF_LOCK(pf); 99361ae650dSJack F Vogel ixl_disable_intr(vsi); 99461ae650dSJack F Vogel ixl_del_multi(vsi); 99561ae650dSJack F Vogel ixl_enable_intr(vsi); 99661ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 99761ae650dSJack F Vogel } 99861ae650dSJack F Vogel break; 99961ae650dSJack F Vogel case SIOCSIFMEDIA: 100061ae650dSJack F Vogel case SIOCGIFMEDIA: 100161ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 100261ae650dSJack F Vogel error = ifmedia_ioctl(ifp, ifr, &vsi->media, command); 100361ae650dSJack F Vogel break; 100461ae650dSJack F Vogel case SIOCSIFCAP: 100561ae650dSJack F Vogel { 100661ae650dSJack F Vogel int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 100761ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 100861ae650dSJack F Vogel 100961ae650dSJack F Vogel ixl_cap_txcsum_tso(vsi, ifp, mask); 101061ae650dSJack F Vogel 101161ae650dSJack F Vogel if (mask & IFCAP_RXCSUM) 101261ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_RXCSUM; 101361ae650dSJack F Vogel if (mask & IFCAP_RXCSUM_IPV6) 101461ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 101561ae650dSJack F Vogel if (mask & IFCAP_LRO) 101661ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_LRO; 101761ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWTAGGING) 101861ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 101961ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWFILTER) 102061ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 102161ae650dSJack F Vogel if (mask & IFCAP_VLAN_HWTSO) 102261ae650dSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 102361ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 102461ae650dSJack F Vogel IXL_PF_LOCK(pf); 102561ae650dSJack F Vogel ixl_init_locked(pf); 102661ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 102761ae650dSJack F Vogel } 102861ae650dSJack F Vogel VLAN_CAPABILITIES(ifp); 102961ae650dSJack F Vogel 103061ae650dSJack F Vogel break; 103161ae650dSJack F Vogel } 103261ae650dSJack F Vogel 103361ae650dSJack F Vogel default: 103461ae650dSJack F Vogel IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command); 103561ae650dSJack F Vogel error = ether_ioctl(ifp, command, data); 103661ae650dSJack F Vogel break; 103761ae650dSJack F Vogel } 103861ae650dSJack F Vogel 103961ae650dSJack F Vogel return (error); 104061ae650dSJack F Vogel } 104161ae650dSJack F Vogel 104261ae650dSJack F Vogel 104361ae650dSJack F Vogel /********************************************************************* 104461ae650dSJack F Vogel * Init entry point 104561ae650dSJack F Vogel * 104661ae650dSJack F Vogel * This routine is used in two ways. It is used by the stack as 104761ae650dSJack F Vogel * init entry point in network interface structure. It is also used 104861ae650dSJack F Vogel * by the driver as a hw/sw initialization routine to get to a 104961ae650dSJack F Vogel * consistent state. 105061ae650dSJack F Vogel * 105161ae650dSJack F Vogel * return 0 on success, positive on failure 105261ae650dSJack F Vogel **********************************************************************/ 105361ae650dSJack F Vogel 105461ae650dSJack F Vogel static void 105561ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf) 105661ae650dSJack F Vogel { 105761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 105861ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 105961ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 106061ae650dSJack F Vogel device_t dev = pf->dev; 106161ae650dSJack F Vogel struct i40e_filter_control_settings filter; 106261ae650dSJack F Vogel u8 tmpaddr[ETHER_ADDR_LEN]; 106361ae650dSJack F Vogel int ret; 106461ae650dSJack F Vogel 106561ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 106661ae650dSJack F Vogel INIT_DEBUGOUT("ixl_init: begin"); 106761ae650dSJack F Vogel ixl_stop(pf); 106861ae650dSJack F Vogel 106961ae650dSJack F Vogel /* Get the latest mac address... User might use a LAA */ 107061ae650dSJack F Vogel bcopy(IF_LLADDR(vsi->ifp), tmpaddr, 107161ae650dSJack F Vogel I40E_ETH_LENGTH_OF_ADDRESS); 107261ae650dSJack F Vogel if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && 107361ae650dSJack F Vogel i40e_validate_mac_addr(tmpaddr)) { 107461ae650dSJack F Vogel bcopy(tmpaddr, hw->mac.addr, 107561ae650dSJack F Vogel I40E_ETH_LENGTH_OF_ADDRESS); 107661ae650dSJack F Vogel ret = i40e_aq_mac_address_write(hw, 107761ae650dSJack F Vogel I40E_AQC_WRITE_TYPE_LAA_ONLY, 107861ae650dSJack F Vogel hw->mac.addr, NULL); 107961ae650dSJack F Vogel if (ret) { 108061ae650dSJack F Vogel device_printf(dev, "LLA address" 108161ae650dSJack F Vogel "change failed!!\n"); 108261ae650dSJack F Vogel return; 108361ae650dSJack F Vogel } 108461ae650dSJack F Vogel } 108561ae650dSJack F Vogel 108661ae650dSJack F Vogel /* Set the various hardware offload abilities */ 108761ae650dSJack F Vogel ifp->if_hwassist = 0; 108861ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TSO) 108961ae650dSJack F Vogel ifp->if_hwassist |= CSUM_TSO; 109061ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM) 109161ae650dSJack F Vogel ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 109261ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 109361ae650dSJack F Vogel ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); 109461ae650dSJack F Vogel 109561ae650dSJack F Vogel /* Set up the device filtering */ 109661ae650dSJack F Vogel bzero(&filter, sizeof(filter)); 109761ae650dSJack F Vogel filter.enable_ethtype = TRUE; 109861ae650dSJack F Vogel filter.enable_macvlan = TRUE; 109961ae650dSJack F Vogel #ifdef IXL_FDIR 110061ae650dSJack F Vogel filter.enable_fdir = TRUE; 110161ae650dSJack F Vogel #endif 110261ae650dSJack F Vogel if (i40e_set_filter_control(hw, &filter)) 110361ae650dSJack F Vogel device_printf(dev, "set_filter_control() failed\n"); 110461ae650dSJack F Vogel 110561ae650dSJack F Vogel /* Set up RSS */ 110661ae650dSJack F Vogel ixl_config_rss(vsi); 110761ae650dSJack F Vogel 110861ae650dSJack F Vogel /* 1109b6c8f260SJack F Vogel ** Prepare the VSI: rings, hmc contexts, etc... 111061ae650dSJack F Vogel */ 111161ae650dSJack F Vogel if (ixl_initialize_vsi(vsi)) { 111261ae650dSJack F Vogel device_printf(dev, "initialize vsi failed!!\n"); 111361ae650dSJack F Vogel return; 111461ae650dSJack F Vogel } 111561ae650dSJack F Vogel 111661ae650dSJack F Vogel /* Add protocol filters to list */ 111761ae650dSJack F Vogel ixl_init_filters(vsi); 111861ae650dSJack F Vogel 111961ae650dSJack F Vogel /* Setup vlan's if needed */ 112061ae650dSJack F Vogel ixl_setup_vlan_filters(vsi); 112161ae650dSJack F Vogel 112261ae650dSJack F Vogel /* Start the local timer */ 112361ae650dSJack F Vogel callout_reset(&pf->timer, hz, ixl_local_timer, pf); 112461ae650dSJack F Vogel 112561ae650dSJack F Vogel /* Set up MSI/X routing and the ITR settings */ 112661ae650dSJack F Vogel if (ixl_enable_msix) { 112761ae650dSJack F Vogel ixl_configure_msix(pf); 112861ae650dSJack F Vogel ixl_configure_itr(pf); 112961ae650dSJack F Vogel } else 113061ae650dSJack F Vogel ixl_configure_legacy(pf); 113161ae650dSJack F Vogel 113261ae650dSJack F Vogel ixl_enable_rings(vsi); 113361ae650dSJack F Vogel 113461ae650dSJack F Vogel i40e_aq_set_default_vsi(hw, vsi->seid, NULL); 113561ae650dSJack F Vogel 113661ae650dSJack F Vogel /* Set MTU in hardware*/ 113761ae650dSJack F Vogel int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size, 113861ae650dSJack F Vogel TRUE, 0, NULL); 113961ae650dSJack F Vogel if (aq_error) 114061ae650dSJack F Vogel device_printf(vsi->dev, 114161ae650dSJack F Vogel "aq_set_mac_config in init error, code %d\n", 114261ae650dSJack F Vogel aq_error); 114361ae650dSJack F Vogel 114461ae650dSJack F Vogel /* And now turn on interrupts */ 114561ae650dSJack F Vogel ixl_enable_intr(vsi); 114661ae650dSJack F Vogel 114761ae650dSJack F Vogel /* Now inform the stack we're ready */ 114861ae650dSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 114961ae650dSJack F Vogel ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 115061ae650dSJack F Vogel 115161ae650dSJack F Vogel return; 115261ae650dSJack F Vogel } 115361ae650dSJack F Vogel 115461ae650dSJack F Vogel static void 115561ae650dSJack F Vogel ixl_init(void *arg) 115661ae650dSJack F Vogel { 115761ae650dSJack F Vogel struct ixl_pf *pf = arg; 115861ae650dSJack F Vogel 115961ae650dSJack F Vogel IXL_PF_LOCK(pf); 116061ae650dSJack F Vogel ixl_init_locked(pf); 116161ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 116261ae650dSJack F Vogel return; 116361ae650dSJack F Vogel } 116461ae650dSJack F Vogel 116561ae650dSJack F Vogel /* 116661ae650dSJack F Vogel ** 116761ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets 116861ae650dSJack F Vogel ** 116961ae650dSJack F Vogel */ 117061ae650dSJack F Vogel static void 117161ae650dSJack F Vogel ixl_handle_que(void *context, int pending) 117261ae650dSJack F Vogel { 117361ae650dSJack F Vogel struct ixl_queue *que = context; 117461ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 117561ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 117661ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 117761ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 117861ae650dSJack F Vogel bool more; 117961ae650dSJack F Vogel 118061ae650dSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 118161ae650dSJack F Vogel more = ixl_rxeof(que, IXL_RX_LIMIT); 118261ae650dSJack F Vogel IXL_TX_LOCK(txr); 118361ae650dSJack F Vogel ixl_txeof(que); 118461ae650dSJack F Vogel if (!drbr_empty(ifp, txr->br)) 118561ae650dSJack F Vogel ixl_mq_start_locked(ifp, txr); 118661ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 118761ae650dSJack F Vogel if (more) { 118861ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->task); 118961ae650dSJack F Vogel return; 119061ae650dSJack F Vogel } 119161ae650dSJack F Vogel } 119261ae650dSJack F Vogel 119361ae650dSJack F Vogel /* Reenable this interrupt - hmmm */ 119461ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 119561ae650dSJack F Vogel return; 119661ae650dSJack F Vogel } 119761ae650dSJack F Vogel 119861ae650dSJack F Vogel 119961ae650dSJack F Vogel /********************************************************************* 120061ae650dSJack F Vogel * 120161ae650dSJack F Vogel * Legacy Interrupt Service routine 120261ae650dSJack F Vogel * 120361ae650dSJack F Vogel **********************************************************************/ 120461ae650dSJack F Vogel void 120561ae650dSJack F Vogel ixl_intr(void *arg) 120661ae650dSJack F Vogel { 120761ae650dSJack F Vogel struct ixl_pf *pf = arg; 120861ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 120961ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 121061ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 121161ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 121261ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 121361ae650dSJack F Vogel u32 reg, icr0, mask; 121461ae650dSJack F Vogel bool more_tx, more_rx; 121561ae650dSJack F Vogel 121661ae650dSJack F Vogel ++que->irqs; 121761ae650dSJack F Vogel 121861ae650dSJack F Vogel /* Protect against spurious interrupts */ 121961ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 122061ae650dSJack F Vogel return; 122161ae650dSJack F Vogel 122261ae650dSJack F Vogel icr0 = rd32(hw, I40E_PFINT_ICR0); 122361ae650dSJack F Vogel 122461ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_DYN_CTL0); 122561ae650dSJack F Vogel reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 122661ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 122761ae650dSJack F Vogel 122861ae650dSJack F Vogel mask = rd32(hw, I40E_PFINT_ICR0_ENA); 122961ae650dSJack F Vogel 123061ae650dSJack F Vogel if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) { 123161ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 123261ae650dSJack F Vogel return; 123361ae650dSJack F Vogel } 123461ae650dSJack F Vogel 123561ae650dSJack F Vogel more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 123661ae650dSJack F Vogel 123761ae650dSJack F Vogel IXL_TX_LOCK(txr); 123861ae650dSJack F Vogel more_tx = ixl_txeof(que); 123961ae650dSJack F Vogel if (!drbr_empty(vsi->ifp, txr->br)) 124061ae650dSJack F Vogel more_tx = 1; 124161ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 124261ae650dSJack F Vogel 124361ae650dSJack F Vogel /* re-enable other interrupt causes */ 124461ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, mask); 124561ae650dSJack F Vogel 124661ae650dSJack F Vogel /* And now the queues */ 124761ae650dSJack F Vogel reg = rd32(hw, I40E_QINT_RQCTL(0)); 124861ae650dSJack F Vogel reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; 124961ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(0), reg); 125061ae650dSJack F Vogel 125161ae650dSJack F Vogel reg = rd32(hw, I40E_QINT_TQCTL(0)); 125261ae650dSJack F Vogel reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; 125361ae650dSJack F Vogel reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK; 125461ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(0), reg); 125561ae650dSJack F Vogel 125661ae650dSJack F Vogel ixl_enable_legacy(hw); 125761ae650dSJack F Vogel 125861ae650dSJack F Vogel return; 125961ae650dSJack F Vogel } 126061ae650dSJack F Vogel 126161ae650dSJack F Vogel 126261ae650dSJack F Vogel /********************************************************************* 126361ae650dSJack F Vogel * 126461ae650dSJack F Vogel * MSIX VSI Interrupt Service routine 126561ae650dSJack F Vogel * 126661ae650dSJack F Vogel **********************************************************************/ 126761ae650dSJack F Vogel void 126861ae650dSJack F Vogel ixl_msix_que(void *arg) 126961ae650dSJack F Vogel { 127061ae650dSJack F Vogel struct ixl_queue *que = arg; 127161ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 127261ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 127361ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 127461ae650dSJack F Vogel bool more_tx, more_rx; 127561ae650dSJack F Vogel 127661ae650dSJack F Vogel /* Protect against spurious interrupts */ 127761ae650dSJack F Vogel if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) 127861ae650dSJack F Vogel return; 127961ae650dSJack F Vogel 128061ae650dSJack F Vogel ++que->irqs; 128161ae650dSJack F Vogel 128261ae650dSJack F Vogel more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 128361ae650dSJack F Vogel 128461ae650dSJack F Vogel IXL_TX_LOCK(txr); 128561ae650dSJack F Vogel more_tx = ixl_txeof(que); 128661ae650dSJack F Vogel /* 128761ae650dSJack F Vogel ** Make certain that if the stack 128861ae650dSJack F Vogel ** has anything queued the task gets 128961ae650dSJack F Vogel ** scheduled to handle it. 129061ae650dSJack F Vogel */ 129161ae650dSJack F Vogel if (!drbr_empty(vsi->ifp, txr->br)) 129261ae650dSJack F Vogel more_tx = 1; 129361ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 129461ae650dSJack F Vogel 129561ae650dSJack F Vogel ixl_set_queue_rx_itr(que); 129661ae650dSJack F Vogel ixl_set_queue_tx_itr(que); 129761ae650dSJack F Vogel 129861ae650dSJack F Vogel if (more_tx || more_rx) 129961ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->task); 130061ae650dSJack F Vogel else 130161ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 130261ae650dSJack F Vogel 130361ae650dSJack F Vogel return; 130461ae650dSJack F Vogel } 130561ae650dSJack F Vogel 130661ae650dSJack F Vogel 130761ae650dSJack F Vogel /********************************************************************* 130861ae650dSJack F Vogel * 130961ae650dSJack F Vogel * MSIX Admin Queue Interrupt Service routine 131061ae650dSJack F Vogel * 131161ae650dSJack F Vogel **********************************************************************/ 131261ae650dSJack F Vogel static void 131361ae650dSJack F Vogel ixl_msix_adminq(void *arg) 131461ae650dSJack F Vogel { 131561ae650dSJack F Vogel struct ixl_pf *pf = arg; 131661ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 131761ae650dSJack F Vogel u32 reg, mask; 131861ae650dSJack F Vogel 131961ae650dSJack F Vogel ++pf->admin_irq; 132061ae650dSJack F Vogel 132161ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0); 132261ae650dSJack F Vogel mask = rd32(hw, I40E_PFINT_ICR0_ENA); 132361ae650dSJack F Vogel 132461ae650dSJack F Vogel /* Check on the cause */ 132561ae650dSJack F Vogel if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) 132661ae650dSJack F Vogel mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 132761ae650dSJack F Vogel 132861ae650dSJack F Vogel if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) { 132961ae650dSJack F Vogel ixl_handle_mdd_event(pf); 133061ae650dSJack F Vogel mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 133161ae650dSJack F Vogel } 133261ae650dSJack F Vogel 133361ae650dSJack F Vogel if (reg & I40E_PFINT_ICR0_VFLR_MASK) 133461ae650dSJack F Vogel mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; 133561ae650dSJack F Vogel 133661ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_DYN_CTL0); 133761ae650dSJack F Vogel reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 133861ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 133961ae650dSJack F Vogel 134061ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 134161ae650dSJack F Vogel return; 134261ae650dSJack F Vogel } 134361ae650dSJack F Vogel 134461ae650dSJack F Vogel /********************************************************************* 134561ae650dSJack F Vogel * 134661ae650dSJack F Vogel * Media Ioctl callback 134761ae650dSJack F Vogel * 134861ae650dSJack F Vogel * This routine is called whenever the user queries the status of 134961ae650dSJack F Vogel * the interface using ifconfig. 135061ae650dSJack F Vogel * 135161ae650dSJack F Vogel **********************************************************************/ 135261ae650dSJack F Vogel static void 135361ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 135461ae650dSJack F Vogel { 135561ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 135661ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 135761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 135861ae650dSJack F Vogel 135961ae650dSJack F Vogel INIT_DEBUGOUT("ixl_media_status: begin"); 136061ae650dSJack F Vogel IXL_PF_LOCK(pf); 136161ae650dSJack F Vogel 136261ae650dSJack F Vogel ixl_update_link_status(pf); 136361ae650dSJack F Vogel 136461ae650dSJack F Vogel ifmr->ifm_status = IFM_AVALID; 136561ae650dSJack F Vogel ifmr->ifm_active = IFM_ETHER; 136661ae650dSJack F Vogel 136761ae650dSJack F Vogel if (!vsi->link_up) { 136861ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 136961ae650dSJack F Vogel return; 137061ae650dSJack F Vogel } 137161ae650dSJack F Vogel 137261ae650dSJack F Vogel ifmr->ifm_status |= IFM_ACTIVE; 137361ae650dSJack F Vogel /* Hardware is always full-duplex */ 137461ae650dSJack F Vogel ifmr->ifm_active |= IFM_FDX; 137561ae650dSJack F Vogel 137661ae650dSJack F Vogel switch (hw->phy.link_info.phy_type) { 137761ae650dSJack F Vogel /* 100 M */ 137861ae650dSJack F Vogel case I40E_PHY_TYPE_100BASE_TX: 137961ae650dSJack F Vogel ifmr->ifm_active |= IFM_100_TX; 138061ae650dSJack F Vogel break; 138161ae650dSJack F Vogel /* 1 G */ 138261ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_T: 138361ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_T; 138461ae650dSJack F Vogel break; 138561ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_SX: 138661ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_SX; 138761ae650dSJack F Vogel break; 138861ae650dSJack F Vogel case I40E_PHY_TYPE_1000BASE_LX: 138961ae650dSJack F Vogel ifmr->ifm_active |= IFM_1000_LX; 139061ae650dSJack F Vogel break; 139161ae650dSJack F Vogel /* 10 G */ 1392b6c8f260SJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1: 139361ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_CR1_CU: 139461ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_SFPP_CU: 1395b6c8f260SJack F Vogel /* Using this until a real KR media type */ 1396b6c8f260SJack F Vogel case I40E_PHY_TYPE_10GBASE_KR: 1397b6c8f260SJack F Vogel case I40E_PHY_TYPE_10GBASE_KX4: 139861ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX; 139961ae650dSJack F Vogel break; 140061ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_SR: 140161ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_SR; 140261ae650dSJack F Vogel break; 140361ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_LR: 140461ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_LR; 140561ae650dSJack F Vogel break; 140661ae650dSJack F Vogel case I40E_PHY_TYPE_10GBASE_T: 140761ae650dSJack F Vogel ifmr->ifm_active |= IFM_10G_T; 140861ae650dSJack F Vogel break; 140961ae650dSJack F Vogel /* 40 G */ 141061ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_CR4: 141161ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_CR4_CU: 141261ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_CR4; 141361ae650dSJack F Vogel break; 141461ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_SR4: 141561ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_SR4; 141661ae650dSJack F Vogel break; 141761ae650dSJack F Vogel case I40E_PHY_TYPE_40GBASE_LR4: 141861ae650dSJack F Vogel ifmr->ifm_active |= IFM_40G_LR4; 141961ae650dSJack F Vogel break; 1420b6c8f260SJack F Vogel /* 1421b6c8f260SJack F Vogel ** Set these to CR4 because OS does not 1422b6c8f260SJack F Vogel ** have types available yet. 1423b6c8f260SJack F Vogel */ 1424b6c8f260SJack F Vogel case I40E_PHY_TYPE_40GBASE_KR4: 1425b6c8f260SJack F Vogel case I40E_PHY_TYPE_XLAUI: 1426b6c8f260SJack F Vogel case I40E_PHY_TYPE_XLPPI: 1427b6c8f260SJack F Vogel case I40E_PHY_TYPE_40GBASE_AOC: 1428b6c8f260SJack F Vogel ifmr->ifm_active |= IFM_40G_CR4; 1429b6c8f260SJack F Vogel break; 143061ae650dSJack F Vogel default: 143161ae650dSJack F Vogel ifmr->ifm_active |= IFM_UNKNOWN; 143261ae650dSJack F Vogel break; 143361ae650dSJack F Vogel } 143461ae650dSJack F Vogel /* Report flow control status as well */ 143561ae650dSJack F Vogel if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) 143661ae650dSJack F Vogel ifmr->ifm_active |= IFM_ETH_TXPAUSE; 143761ae650dSJack F Vogel if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) 143861ae650dSJack F Vogel ifmr->ifm_active |= IFM_ETH_RXPAUSE; 143961ae650dSJack F Vogel 144061ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 144161ae650dSJack F Vogel 144261ae650dSJack F Vogel return; 144361ae650dSJack F Vogel } 144461ae650dSJack F Vogel 144561ae650dSJack F Vogel /********************************************************************* 144661ae650dSJack F Vogel * 144761ae650dSJack F Vogel * Media Ioctl callback 144861ae650dSJack F Vogel * 144961ae650dSJack F Vogel * This routine is called when the user changes speed/duplex using 145061ae650dSJack F Vogel * media/mediopt option with ifconfig. 145161ae650dSJack F Vogel * 145261ae650dSJack F Vogel **********************************************************************/ 145361ae650dSJack F Vogel static int 145461ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp) 145561ae650dSJack F Vogel { 145661ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 145761ae650dSJack F Vogel struct ifmedia *ifm = &vsi->media; 145861ae650dSJack F Vogel 145961ae650dSJack F Vogel INIT_DEBUGOUT("ixl_media_change: begin"); 146061ae650dSJack F Vogel 146161ae650dSJack F Vogel if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 146261ae650dSJack F Vogel return (EINVAL); 146361ae650dSJack F Vogel 146461ae650dSJack F Vogel if_printf(ifp, "Media change is currently not supported.\n"); 146561ae650dSJack F Vogel 146661ae650dSJack F Vogel return (ENODEV); 146761ae650dSJack F Vogel } 146861ae650dSJack F Vogel 146961ae650dSJack F Vogel 147061ae650dSJack F Vogel #ifdef IXL_FDIR 147161ae650dSJack F Vogel /* 147261ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter 147361ae650dSJack F Vogel ** based on TX flow info that will keep the receive 147461ae650dSJack F Vogel ** portion of the flow on the same queue. Based on the 147561ae650dSJack F Vogel ** implementation this is only available for TCP connections 147661ae650dSJack F Vogel */ 147761ae650dSJack F Vogel void 147861ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype) 147961ae650dSJack F Vogel { 148061ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 148161ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 148261ae650dSJack F Vogel struct i40e_filter_program_desc *FDIR; 148361ae650dSJack F Vogel u32 ptype, dtype; 148461ae650dSJack F Vogel int idx; 148561ae650dSJack F Vogel 148661ae650dSJack F Vogel /* check if ATR is enabled and sample rate */ 148761ae650dSJack F Vogel if ((!ixl_enable_fdir) || (!txr->atr_rate)) 148861ae650dSJack F Vogel return; 148961ae650dSJack F Vogel /* 149061ae650dSJack F Vogel ** We sample all TCP SYN/FIN packets, 149161ae650dSJack F Vogel ** or at the selected sample rate 149261ae650dSJack F Vogel */ 149361ae650dSJack F Vogel txr->atr_count++; 149461ae650dSJack F Vogel if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) && 149561ae650dSJack F Vogel (txr->atr_count < txr->atr_rate)) 149661ae650dSJack F Vogel return; 149761ae650dSJack F Vogel txr->atr_count = 0; 149861ae650dSJack F Vogel 149961ae650dSJack F Vogel /* Get a descriptor to use */ 150061ae650dSJack F Vogel idx = txr->next_avail; 150161ae650dSJack F Vogel FDIR = (struct i40e_filter_program_desc *) &txr->base[idx]; 150261ae650dSJack F Vogel if (++idx == que->num_desc) 150361ae650dSJack F Vogel idx = 0; 150461ae650dSJack F Vogel txr->avail--; 150561ae650dSJack F Vogel txr->next_avail = idx; 150661ae650dSJack F Vogel 150761ae650dSJack F Vogel ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & 150861ae650dSJack F Vogel I40E_TXD_FLTR_QW0_QINDEX_MASK; 150961ae650dSJack F Vogel 151061ae650dSJack F Vogel ptype |= (etype == ETHERTYPE_IP) ? 151161ae650dSJack F Vogel (I40E_FILTER_PCTYPE_NONF_IPV4_TCP << 151261ae650dSJack F Vogel I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) : 151361ae650dSJack F Vogel (I40E_FILTER_PCTYPE_NONF_IPV6_TCP << 151461ae650dSJack F Vogel I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); 151561ae650dSJack F Vogel 151661ae650dSJack F Vogel ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT; 151761ae650dSJack F Vogel 151861ae650dSJack F Vogel dtype = I40E_TX_DESC_DTYPE_FILTER_PROG; 151961ae650dSJack F Vogel 152061ae650dSJack F Vogel /* 152161ae650dSJack F Vogel ** We use the TCP TH_FIN as a trigger to remove 152261ae650dSJack F Vogel ** the filter, otherwise its an update. 152361ae650dSJack F Vogel */ 152461ae650dSJack F Vogel dtype |= (th->th_flags & TH_FIN) ? 152561ae650dSJack F Vogel (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << 152661ae650dSJack F Vogel I40E_TXD_FLTR_QW1_PCMD_SHIFT) : 152761ae650dSJack F Vogel (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << 152861ae650dSJack F Vogel I40E_TXD_FLTR_QW1_PCMD_SHIFT); 152961ae650dSJack F Vogel 153061ae650dSJack F Vogel dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX << 153161ae650dSJack F Vogel I40E_TXD_FLTR_QW1_DEST_SHIFT; 153261ae650dSJack F Vogel 153361ae650dSJack F Vogel dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID << 153461ae650dSJack F Vogel I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT; 153561ae650dSJack F Vogel 153661ae650dSJack F Vogel FDIR->qindex_flex_ptype_vsi = htole32(ptype); 153761ae650dSJack F Vogel FDIR->dtype_cmd_cntindex = htole32(dtype); 153861ae650dSJack F Vogel return; 153961ae650dSJack F Vogel } 154061ae650dSJack F Vogel #endif 154161ae650dSJack F Vogel 154261ae650dSJack F Vogel 154361ae650dSJack F Vogel static void 154461ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi) 154561ae650dSJack F Vogel { 154661ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 154761ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 154861ae650dSJack F Vogel int err, mcnt = 0; 154961ae650dSJack F Vogel bool uni = FALSE, multi = FALSE; 155061ae650dSJack F Vogel 155161ae650dSJack F Vogel if (ifp->if_flags & IFF_ALLMULTI) 155261ae650dSJack F Vogel multi = TRUE; 155361ae650dSJack F Vogel else { /* Need to count the multicast addresses */ 155461ae650dSJack F Vogel struct ifmultiaddr *ifma; 155561ae650dSJack F Vogel if_maddr_rlock(ifp); 155661ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 155761ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 155861ae650dSJack F Vogel continue; 155961ae650dSJack F Vogel if (mcnt == MAX_MULTICAST_ADDR) 156061ae650dSJack F Vogel break; 156161ae650dSJack F Vogel mcnt++; 156261ae650dSJack F Vogel } 156361ae650dSJack F Vogel if_maddr_runlock(ifp); 156461ae650dSJack F Vogel } 156561ae650dSJack F Vogel 156661ae650dSJack F Vogel if (mcnt >= MAX_MULTICAST_ADDR) 156761ae650dSJack F Vogel multi = TRUE; 156861ae650dSJack F Vogel if (ifp->if_flags & IFF_PROMISC) 156961ae650dSJack F Vogel uni = TRUE; 157061ae650dSJack F Vogel 157161ae650dSJack F Vogel err = i40e_aq_set_vsi_unicast_promiscuous(hw, 157261ae650dSJack F Vogel vsi->seid, uni, NULL); 157361ae650dSJack F Vogel err = i40e_aq_set_vsi_multicast_promiscuous(hw, 157461ae650dSJack F Vogel vsi->seid, multi, NULL); 157561ae650dSJack F Vogel return; 157661ae650dSJack F Vogel } 157761ae650dSJack F Vogel 157861ae650dSJack F Vogel /********************************************************************* 157961ae650dSJack F Vogel * Filter Routines 158061ae650dSJack F Vogel * 158161ae650dSJack F Vogel * Routines for multicast and vlan filter management. 158261ae650dSJack F Vogel * 158361ae650dSJack F Vogel *********************************************************************/ 158461ae650dSJack F Vogel static void 158561ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi) 158661ae650dSJack F Vogel { 158761ae650dSJack F Vogel struct ifmultiaddr *ifma; 158861ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 158961ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 159061ae650dSJack F Vogel int mcnt = 0, flags; 159161ae650dSJack F Vogel 159261ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_add_multi: begin"); 159361ae650dSJack F Vogel 159461ae650dSJack F Vogel if_maddr_rlock(ifp); 159561ae650dSJack F Vogel /* 159661ae650dSJack F Vogel ** First just get a count, to decide if we 159761ae650dSJack F Vogel ** we simply use multicast promiscuous. 159861ae650dSJack F Vogel */ 159961ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 160061ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 160161ae650dSJack F Vogel continue; 160261ae650dSJack F Vogel mcnt++; 160361ae650dSJack F Vogel } 160461ae650dSJack F Vogel if_maddr_runlock(ifp); 160561ae650dSJack F Vogel 160661ae650dSJack F Vogel if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { 160761ae650dSJack F Vogel /* delete existing MC filters */ 160861ae650dSJack F Vogel ixl_del_hw_filters(vsi, mcnt); 160961ae650dSJack F Vogel i40e_aq_set_vsi_multicast_promiscuous(hw, 161061ae650dSJack F Vogel vsi->seid, TRUE, NULL); 161161ae650dSJack F Vogel return; 161261ae650dSJack F Vogel } 161361ae650dSJack F Vogel 161461ae650dSJack F Vogel mcnt = 0; 161561ae650dSJack F Vogel if_maddr_rlock(ifp); 161661ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 161761ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 161861ae650dSJack F Vogel continue; 161961ae650dSJack F Vogel ixl_add_mc_filter(vsi, 162061ae650dSJack F Vogel (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); 162161ae650dSJack F Vogel mcnt++; 162261ae650dSJack F Vogel } 162361ae650dSJack F Vogel if_maddr_runlock(ifp); 162461ae650dSJack F Vogel if (mcnt > 0) { 162561ae650dSJack F Vogel flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); 162661ae650dSJack F Vogel ixl_add_hw_filters(vsi, flags, mcnt); 162761ae650dSJack F Vogel } 162861ae650dSJack F Vogel 162961ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_add_multi: end"); 163061ae650dSJack F Vogel return; 163161ae650dSJack F Vogel } 163261ae650dSJack F Vogel 163361ae650dSJack F Vogel static void 163461ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi) 163561ae650dSJack F Vogel { 163661ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 163761ae650dSJack F Vogel struct ifmultiaddr *ifma; 163861ae650dSJack F Vogel struct ixl_mac_filter *f; 163961ae650dSJack F Vogel int mcnt = 0; 164061ae650dSJack F Vogel bool match = FALSE; 164161ae650dSJack F Vogel 164261ae650dSJack F Vogel IOCTL_DEBUGOUT("ixl_del_multi: begin"); 164361ae650dSJack F Vogel 164461ae650dSJack F Vogel /* Search for removed multicast addresses */ 164561ae650dSJack F Vogel if_maddr_rlock(ifp); 164661ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 164761ae650dSJack F Vogel if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) { 164861ae650dSJack F Vogel match = FALSE; 164961ae650dSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 165061ae650dSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 165161ae650dSJack F Vogel continue; 165261ae650dSJack F Vogel u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 165361ae650dSJack F Vogel if (cmp_etheraddr(f->macaddr, mc_addr)) { 165461ae650dSJack F Vogel match = TRUE; 165561ae650dSJack F Vogel break; 165661ae650dSJack F Vogel } 165761ae650dSJack F Vogel } 165861ae650dSJack F Vogel if (match == FALSE) { 165961ae650dSJack F Vogel f->flags |= IXL_FILTER_DEL; 166061ae650dSJack F Vogel mcnt++; 166161ae650dSJack F Vogel } 166261ae650dSJack F Vogel } 166361ae650dSJack F Vogel } 166461ae650dSJack F Vogel if_maddr_runlock(ifp); 166561ae650dSJack F Vogel 166661ae650dSJack F Vogel if (mcnt > 0) 166761ae650dSJack F Vogel ixl_del_hw_filters(vsi, mcnt); 166861ae650dSJack F Vogel } 166961ae650dSJack F Vogel 167061ae650dSJack F Vogel 167161ae650dSJack F Vogel /********************************************************************* 167261ae650dSJack F Vogel * Timer routine 167361ae650dSJack F Vogel * 167461ae650dSJack F Vogel * This routine checks for link status,updates statistics, 167561ae650dSJack F Vogel * and runs the watchdog check. 167661ae650dSJack F Vogel * 167761ae650dSJack F Vogel **********************************************************************/ 167861ae650dSJack F Vogel 167961ae650dSJack F Vogel static void 168061ae650dSJack F Vogel ixl_local_timer(void *arg) 168161ae650dSJack F Vogel { 168261ae650dSJack F Vogel struct ixl_pf *pf = arg; 168361ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 168461ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 168561ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 168661ae650dSJack F Vogel device_t dev = pf->dev; 168761ae650dSJack F Vogel int hung = 0; 168861ae650dSJack F Vogel u32 mask; 168961ae650dSJack F Vogel 169061ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 169161ae650dSJack F Vogel 169261ae650dSJack F Vogel /* Fire off the adminq task */ 169361ae650dSJack F Vogel taskqueue_enqueue(pf->tq, &pf->adminq); 169461ae650dSJack F Vogel 169561ae650dSJack F Vogel /* Update stats */ 169661ae650dSJack F Vogel ixl_update_stats_counters(pf); 169761ae650dSJack F Vogel 169861ae650dSJack F Vogel /* 169961ae650dSJack F Vogel ** Check status of the queues 170061ae650dSJack F Vogel */ 170161ae650dSJack F Vogel mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | 170261ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); 170361ae650dSJack F Vogel 170461ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++,que++) { 170561ae650dSJack F Vogel /* Any queues with outstanding work get a sw irq */ 170661ae650dSJack F Vogel if (que->busy) 170761ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask); 170861ae650dSJack F Vogel /* 170961ae650dSJack F Vogel ** Each time txeof runs without cleaning, but there 171061ae650dSJack F Vogel ** are uncleaned descriptors it increments busy. If 171161ae650dSJack F Vogel ** we get to 5 we declare it hung. 171261ae650dSJack F Vogel */ 171361ae650dSJack F Vogel if (que->busy == IXL_QUEUE_HUNG) { 171461ae650dSJack F Vogel ++hung; 171561ae650dSJack F Vogel /* Mark the queue as inactive */ 171661ae650dSJack F Vogel vsi->active_queues &= ~((u64)1 << que->me); 171761ae650dSJack F Vogel continue; 171861ae650dSJack F Vogel } else { 171961ae650dSJack F Vogel /* Check if we've come back from hung */ 172061ae650dSJack F Vogel if ((vsi->active_queues & ((u64)1 << que->me)) == 0) 172161ae650dSJack F Vogel vsi->active_queues |= ((u64)1 << que->me); 172261ae650dSJack F Vogel } 172361ae650dSJack F Vogel if (que->busy >= IXL_MAX_TX_BUSY) { 1724393c4bb1SJack F Vogel #ifdef IXL_DEBUG 172561ae650dSJack F Vogel device_printf(dev,"Warning queue %d " 172661ae650dSJack F Vogel "appears to be hung!\n", i); 1727393c4bb1SJack F Vogel #endif 172861ae650dSJack F Vogel que->busy = IXL_QUEUE_HUNG; 172961ae650dSJack F Vogel ++hung; 173061ae650dSJack F Vogel } 173161ae650dSJack F Vogel } 173261ae650dSJack F Vogel /* Only reinit if all queues show hung */ 173361ae650dSJack F Vogel if (hung == vsi->num_queues) 173461ae650dSJack F Vogel goto hung; 173561ae650dSJack F Vogel 173661ae650dSJack F Vogel callout_reset(&pf->timer, hz, ixl_local_timer, pf); 173761ae650dSJack F Vogel return; 173861ae650dSJack F Vogel 173961ae650dSJack F Vogel hung: 174061ae650dSJack F Vogel device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n"); 174161ae650dSJack F Vogel ixl_init_locked(pf); 174261ae650dSJack F Vogel } 174361ae650dSJack F Vogel 174461ae650dSJack F Vogel /* 174561ae650dSJack F Vogel ** Note: this routine updates the OS on the link state 174661ae650dSJack F Vogel ** the real check of the hardware only happens with 174761ae650dSJack F Vogel ** a link interrupt. 174861ae650dSJack F Vogel */ 174961ae650dSJack F Vogel static void 175061ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf) 175161ae650dSJack F Vogel { 175261ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 175361ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 175461ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 175561ae650dSJack F Vogel device_t dev = pf->dev; 175661ae650dSJack F Vogel 175761ae650dSJack F Vogel 175861ae650dSJack F Vogel if (vsi->link_up){ 175961ae650dSJack F Vogel if (vsi->link_active == FALSE) { 176061ae650dSJack F Vogel i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 1761b6c8f260SJack F Vogel pf->fc = hw->fc.current_mode; 176261ae650dSJack F Vogel if (bootverbose) { 176361ae650dSJack F Vogel device_printf(dev,"Link is up %d Gbps %s," 176461ae650dSJack F Vogel " Flow Control: %s\n", 176561ae650dSJack F Vogel ((vsi->link_speed == I40E_LINK_SPEED_40GB)? 40:10), 1766b6c8f260SJack F Vogel "Full Duplex", ixl_fc_string[pf->fc]); 176761ae650dSJack F Vogel } 176861ae650dSJack F Vogel vsi->link_active = TRUE; 1769393c4bb1SJack F Vogel /* 1770393c4bb1SJack F Vogel ** Warn user if link speed on NPAR enabled 1771393c4bb1SJack F Vogel ** partition is not at least 10GB 1772393c4bb1SJack F Vogel */ 1773393c4bb1SJack F Vogel if (hw->func_caps.npar_enable && 1774393c4bb1SJack F Vogel (hw->phy.link_info.link_speed == I40E_LINK_SPEED_1GB || 1775393c4bb1SJack F Vogel hw->phy.link_info.link_speed == I40E_LINK_SPEED_100MB)) 1776393c4bb1SJack F Vogel device_printf(dev, "The partition detected link" 1777393c4bb1SJack F Vogel "speed that is less than 10Gbps\n"); 177861ae650dSJack F Vogel if_link_state_change(ifp, LINK_STATE_UP); 177961ae650dSJack F Vogel } 178061ae650dSJack F Vogel } else { /* Link down */ 178161ae650dSJack F Vogel if (vsi->link_active == TRUE) { 178261ae650dSJack F Vogel if (bootverbose) 178361ae650dSJack F Vogel device_printf(dev,"Link is Down\n"); 178461ae650dSJack F Vogel if_link_state_change(ifp, LINK_STATE_DOWN); 178561ae650dSJack F Vogel vsi->link_active = FALSE; 178661ae650dSJack F Vogel } 178761ae650dSJack F Vogel } 178861ae650dSJack F Vogel 178961ae650dSJack F Vogel return; 179061ae650dSJack F Vogel } 179161ae650dSJack F Vogel 179261ae650dSJack F Vogel /********************************************************************* 179361ae650dSJack F Vogel * 179461ae650dSJack F Vogel * This routine disables all traffic on the adapter by issuing a 179561ae650dSJack F Vogel * global reset on the MAC and deallocates TX/RX buffers. 179661ae650dSJack F Vogel * 179761ae650dSJack F Vogel **********************************************************************/ 179861ae650dSJack F Vogel 179961ae650dSJack F Vogel static void 180061ae650dSJack F Vogel ixl_stop(struct ixl_pf *pf) 180161ae650dSJack F Vogel { 180261ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 180361ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 180461ae650dSJack F Vogel 180561ae650dSJack F Vogel mtx_assert(&pf->pf_mtx, MA_OWNED); 180661ae650dSJack F Vogel 180761ae650dSJack F Vogel INIT_DEBUGOUT("ixl_stop: begin\n"); 180861ae650dSJack F Vogel ixl_disable_intr(vsi); 180961ae650dSJack F Vogel ixl_disable_rings(vsi); 181061ae650dSJack F Vogel 181161ae650dSJack F Vogel /* Tell the stack that the interface is no longer active */ 181261ae650dSJack F Vogel ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 181361ae650dSJack F Vogel 181461ae650dSJack F Vogel /* Stop the local timer */ 181561ae650dSJack F Vogel callout_stop(&pf->timer); 181661ae650dSJack F Vogel 181761ae650dSJack F Vogel return; 181861ae650dSJack F Vogel } 181961ae650dSJack F Vogel 182061ae650dSJack F Vogel 182161ae650dSJack F Vogel /********************************************************************* 182261ae650dSJack F Vogel * 182361ae650dSJack F Vogel * Setup MSIX Interrupt resources and handlers for the VSI 182461ae650dSJack F Vogel * 182561ae650dSJack F Vogel **********************************************************************/ 182661ae650dSJack F Vogel static int 182761ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf) 182861ae650dSJack F Vogel { 182961ae650dSJack F Vogel device_t dev = pf->dev; 183061ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 183161ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 183261ae650dSJack F Vogel int error, rid = 0; 183361ae650dSJack F Vogel 183461ae650dSJack F Vogel if (pf->msix == 1) 183561ae650dSJack F Vogel rid = 1; 183661ae650dSJack F Vogel pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 183761ae650dSJack F Vogel &rid, RF_SHAREABLE | RF_ACTIVE); 183861ae650dSJack F Vogel if (pf->res == NULL) { 183961ae650dSJack F Vogel device_printf(dev,"Unable to allocate" 184061ae650dSJack F Vogel " bus resource: vsi legacy/msi interrupt\n"); 184161ae650dSJack F Vogel return (ENXIO); 184261ae650dSJack F Vogel } 184361ae650dSJack F Vogel 184461ae650dSJack F Vogel /* Set the handler function */ 184561ae650dSJack F Vogel error = bus_setup_intr(dev, pf->res, 184661ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 184761ae650dSJack F Vogel ixl_intr, pf, &pf->tag); 184861ae650dSJack F Vogel if (error) { 184961ae650dSJack F Vogel pf->res = NULL; 185061ae650dSJack F Vogel device_printf(dev, "Failed to register legacy/msi handler"); 185161ae650dSJack F Vogel return (error); 185261ae650dSJack F Vogel } 185361ae650dSJack F Vogel bus_describe_intr(dev, pf->res, pf->tag, "irq0"); 185461ae650dSJack F Vogel TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 185561ae650dSJack F Vogel TASK_INIT(&que->task, 0, ixl_handle_que, que); 185661ae650dSJack F Vogel que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 185761ae650dSJack F Vogel taskqueue_thread_enqueue, &que->tq); 185861ae650dSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 185961ae650dSJack F Vogel device_get_nameunit(dev)); 186061ae650dSJack F Vogel TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 186161ae650dSJack F Vogel pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 186261ae650dSJack F Vogel taskqueue_thread_enqueue, &pf->tq); 186361ae650dSJack F Vogel taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 186461ae650dSJack F Vogel device_get_nameunit(dev)); 186561ae650dSJack F Vogel 186661ae650dSJack F Vogel return (0); 186761ae650dSJack F Vogel } 186861ae650dSJack F Vogel 186961ae650dSJack F Vogel 187061ae650dSJack F Vogel /********************************************************************* 187161ae650dSJack F Vogel * 187261ae650dSJack F Vogel * Setup MSIX Interrupt resources and handlers for the VSI 187361ae650dSJack F Vogel * 187461ae650dSJack F Vogel **********************************************************************/ 187561ae650dSJack F Vogel static int 187661ae650dSJack F Vogel ixl_assign_vsi_msix(struct ixl_pf *pf) 187761ae650dSJack F Vogel { 187861ae650dSJack F Vogel device_t dev = pf->dev; 187961ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 188061ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 188161ae650dSJack F Vogel struct tx_ring *txr; 188261ae650dSJack F Vogel int error, rid, vector = 0; 18839756bd59SAdrian Chadd #ifdef RSS 18849756bd59SAdrian Chadd cpuset_t cpu_mask; 18859756bd59SAdrian Chadd #endif 188661ae650dSJack F Vogel 188761ae650dSJack F Vogel /* Admin Que is vector 0*/ 188861ae650dSJack F Vogel rid = vector + 1; 188961ae650dSJack F Vogel pf->res = bus_alloc_resource_any(dev, 189061ae650dSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 189161ae650dSJack F Vogel if (!pf->res) { 189261ae650dSJack F Vogel device_printf(dev,"Unable to allocate" 189361ae650dSJack F Vogel " bus resource: Adminq interrupt [%d]\n", rid); 189461ae650dSJack F Vogel return (ENXIO); 189561ae650dSJack F Vogel } 189661ae650dSJack F Vogel /* Set the adminq vector and handler */ 189761ae650dSJack F Vogel error = bus_setup_intr(dev, pf->res, 189861ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 189961ae650dSJack F Vogel ixl_msix_adminq, pf, &pf->tag); 190061ae650dSJack F Vogel if (error) { 190161ae650dSJack F Vogel pf->res = NULL; 190261ae650dSJack F Vogel device_printf(dev, "Failed to register Admin que handler"); 190361ae650dSJack F Vogel return (error); 190461ae650dSJack F Vogel } 190561ae650dSJack F Vogel bus_describe_intr(dev, pf->res, pf->tag, "aq"); 190661ae650dSJack F Vogel pf->admvec = vector; 190761ae650dSJack F Vogel /* Tasklet for Admin Queue */ 190861ae650dSJack F Vogel TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 190961ae650dSJack F Vogel pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 191061ae650dSJack F Vogel taskqueue_thread_enqueue, &pf->tq); 191161ae650dSJack F Vogel taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 191261ae650dSJack F Vogel device_get_nameunit(pf->dev)); 191361ae650dSJack F Vogel ++vector; 191461ae650dSJack F Vogel 191561ae650dSJack F Vogel /* Now set up the stations */ 191661ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { 1917393c4bb1SJack F Vogel int cpu_id = i; 191861ae650dSJack F Vogel rid = vector + 1; 191961ae650dSJack F Vogel txr = &que->txr; 192061ae650dSJack F Vogel que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 192161ae650dSJack F Vogel RF_SHAREABLE | RF_ACTIVE); 192261ae650dSJack F Vogel if (que->res == NULL) { 192361ae650dSJack F Vogel device_printf(dev,"Unable to allocate" 192461ae650dSJack F Vogel " bus resource: que interrupt [%d]\n", vector); 192561ae650dSJack F Vogel return (ENXIO); 192661ae650dSJack F Vogel } 192761ae650dSJack F Vogel /* Set the handler function */ 192861ae650dSJack F Vogel error = bus_setup_intr(dev, que->res, 192961ae650dSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 193061ae650dSJack F Vogel ixl_msix_que, que, &que->tag); 193161ae650dSJack F Vogel if (error) { 193261ae650dSJack F Vogel que->res = NULL; 193361ae650dSJack F Vogel device_printf(dev, "Failed to register que handler"); 193461ae650dSJack F Vogel return (error); 193561ae650dSJack F Vogel } 193661ae650dSJack F Vogel bus_describe_intr(dev, que->res, que->tag, "q%d", i); 193761ae650dSJack F Vogel /* Bind the vector to a CPU */ 1938393c4bb1SJack F Vogel #ifdef RSS 1939393c4bb1SJack F Vogel cpu_id = rss_getcpu(i % rss_getnumbuckets()); 1940393c4bb1SJack F Vogel #endif 1941393c4bb1SJack F Vogel bus_bind_intr(dev, que->res, cpu_id); 194261ae650dSJack F Vogel que->msix = vector; 194361ae650dSJack F Vogel TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 194461ae650dSJack F Vogel TASK_INIT(&que->task, 0, ixl_handle_que, que); 194561ae650dSJack F Vogel que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 194661ae650dSJack F Vogel taskqueue_thread_enqueue, &que->tq); 1947393c4bb1SJack F Vogel #ifdef RSS 1948*977dc4e2SAdrian Chadd CPU_SETOF(cpu_id, &cpu_mask); 19499756bd59SAdrian Chadd taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, 19509756bd59SAdrian Chadd &cpu_mask, "%s (bucket %d)", 1951393c4bb1SJack F Vogel device_get_nameunit(dev), cpu_id); 1952393c4bb1SJack F Vogel #else 1953393c4bb1SJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, 1954393c4bb1SJack F Vogel "%s que", device_get_nameunit(dev)); 1955393c4bb1SJack F Vogel #endif 195661ae650dSJack F Vogel } 195761ae650dSJack F Vogel 195861ae650dSJack F Vogel return (0); 195961ae650dSJack F Vogel } 196061ae650dSJack F Vogel 196161ae650dSJack F Vogel 196261ae650dSJack F Vogel /* 196361ae650dSJack F Vogel * Allocate MSI/X vectors 196461ae650dSJack F Vogel */ 196561ae650dSJack F Vogel static int 196661ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf) 196761ae650dSJack F Vogel { 196861ae650dSJack F Vogel device_t dev = pf->dev; 196961ae650dSJack F Vogel int rid, want, vectors, queues, available; 197061ae650dSJack F Vogel 197161ae650dSJack F Vogel /* Override by tuneable */ 197261ae650dSJack F Vogel if (ixl_enable_msix == 0) 197361ae650dSJack F Vogel goto msi; 197461ae650dSJack F Vogel 197561ae650dSJack F Vogel /* 197661ae650dSJack F Vogel ** When used in a virtualized environment 197761ae650dSJack F Vogel ** PCI BUSMASTER capability may not be set 197861ae650dSJack F Vogel ** so explicity set it here and rewrite 197961ae650dSJack F Vogel ** the ENABLE in the MSIX control register 198061ae650dSJack F Vogel ** at this point to cause the host to 198161ae650dSJack F Vogel ** successfully initialize us. 198261ae650dSJack F Vogel */ 198361ae650dSJack F Vogel { 198461ae650dSJack F Vogel u16 pci_cmd_word; 198561ae650dSJack F Vogel int msix_ctrl; 198661ae650dSJack F Vogel pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); 198761ae650dSJack F Vogel pci_cmd_word |= PCIM_CMD_BUSMASTEREN; 198861ae650dSJack F Vogel pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); 198961ae650dSJack F Vogel pci_find_cap(dev, PCIY_MSIX, &rid); 199061ae650dSJack F Vogel rid += PCIR_MSIX_CTRL; 199161ae650dSJack F Vogel msix_ctrl = pci_read_config(dev, rid, 2); 199261ae650dSJack F Vogel msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; 199361ae650dSJack F Vogel pci_write_config(dev, rid, msix_ctrl, 2); 199461ae650dSJack F Vogel } 199561ae650dSJack F Vogel 199661ae650dSJack F Vogel /* First try MSI/X */ 199761ae650dSJack F Vogel rid = PCIR_BAR(IXL_BAR); 199861ae650dSJack F Vogel pf->msix_mem = bus_alloc_resource_any(dev, 199961ae650dSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 200061ae650dSJack F Vogel if (!pf->msix_mem) { 200161ae650dSJack F Vogel /* May not be enabled */ 200261ae650dSJack F Vogel device_printf(pf->dev, 200361ae650dSJack F Vogel "Unable to map MSIX table \n"); 200461ae650dSJack F Vogel goto msi; 200561ae650dSJack F Vogel } 200661ae650dSJack F Vogel 200761ae650dSJack F Vogel available = pci_msix_count(dev); 200861ae650dSJack F Vogel if (available == 0) { /* system has msix disabled */ 200961ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 201061ae650dSJack F Vogel rid, pf->msix_mem); 201161ae650dSJack F Vogel pf->msix_mem = NULL; 201261ae650dSJack F Vogel goto msi; 201361ae650dSJack F Vogel } 201461ae650dSJack F Vogel 201561ae650dSJack F Vogel /* Figure out a reasonable auto config value */ 201661ae650dSJack F Vogel queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus; 201761ae650dSJack F Vogel 201861ae650dSJack F Vogel /* Override with hardcoded value if sane */ 201961ae650dSJack F Vogel if ((ixl_max_queues != 0) && (ixl_max_queues <= queues)) 202061ae650dSJack F Vogel queues = ixl_max_queues; 202161ae650dSJack F Vogel 2022393c4bb1SJack F Vogel #ifdef RSS 2023393c4bb1SJack F Vogel /* If we're doing RSS, clamp at the number of RSS buckets */ 2024393c4bb1SJack F Vogel if (queues > rss_getnumbuckets()) 2025393c4bb1SJack F Vogel queues = rss_getnumbuckets(); 2026393c4bb1SJack F Vogel #endif 2027393c4bb1SJack F Vogel 202861ae650dSJack F Vogel /* 202961ae650dSJack F Vogel ** Want one vector (RX/TX pair) per queue 203061ae650dSJack F Vogel ** plus an additional for the admin queue. 203161ae650dSJack F Vogel */ 203261ae650dSJack F Vogel want = queues + 1; 203361ae650dSJack F Vogel if (want <= available) /* Have enough */ 203461ae650dSJack F Vogel vectors = want; 203561ae650dSJack F Vogel else { 203661ae650dSJack F Vogel device_printf(pf->dev, 203761ae650dSJack F Vogel "MSIX Configuration Problem, " 203861ae650dSJack F Vogel "%d vectors available but %d wanted!\n", 203961ae650dSJack F Vogel available, want); 204061ae650dSJack F Vogel return (0); /* Will go to Legacy setup */ 204161ae650dSJack F Vogel } 204261ae650dSJack F Vogel 204361ae650dSJack F Vogel if (pci_alloc_msix(dev, &vectors) == 0) { 204461ae650dSJack F Vogel device_printf(pf->dev, 204561ae650dSJack F Vogel "Using MSIX interrupts with %d vectors\n", vectors); 204661ae650dSJack F Vogel pf->msix = vectors; 204761ae650dSJack F Vogel pf->vsi.num_queues = queues; 2048393c4bb1SJack F Vogel #ifdef RSS 2049393c4bb1SJack F Vogel /* 2050393c4bb1SJack F Vogel * If we're doing RSS, the number of queues needs to 2051393c4bb1SJack F Vogel * match the number of RSS buckets that are configured. 2052393c4bb1SJack F Vogel * 2053393c4bb1SJack F Vogel * + If there's more queues than RSS buckets, we'll end 2054393c4bb1SJack F Vogel * up with queues that get no traffic. 2055393c4bb1SJack F Vogel * 2056393c4bb1SJack F Vogel * + If there's more RSS buckets than queues, we'll end 2057393c4bb1SJack F Vogel * up having multiple RSS buckets map to the same queue, 2058393c4bb1SJack F Vogel * so there'll be some contention. 2059393c4bb1SJack F Vogel */ 2060393c4bb1SJack F Vogel if (queues != rss_getnumbuckets()) { 2061393c4bb1SJack F Vogel device_printf(dev, 2062393c4bb1SJack F Vogel "%s: queues (%d) != RSS buckets (%d)" 2063393c4bb1SJack F Vogel "; performance will be impacted.\n", 2064393c4bb1SJack F Vogel __func__, queues, rss_getnumbuckets()); 2065393c4bb1SJack F Vogel } 2066393c4bb1SJack F Vogel #endif 206761ae650dSJack F Vogel return (vectors); 206861ae650dSJack F Vogel } 206961ae650dSJack F Vogel msi: 207061ae650dSJack F Vogel vectors = pci_msi_count(dev); 207161ae650dSJack F Vogel pf->vsi.num_queues = 1; 207261ae650dSJack F Vogel pf->msix = 1; 207361ae650dSJack F Vogel ixl_max_queues = 1; 207461ae650dSJack F Vogel ixl_enable_msix = 0; 207561ae650dSJack F Vogel if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) 207661ae650dSJack F Vogel device_printf(pf->dev,"Using an MSI interrupt\n"); 207761ae650dSJack F Vogel else { 207861ae650dSJack F Vogel pf->msix = 0; 207961ae650dSJack F Vogel device_printf(pf->dev,"Using a Legacy interrupt\n"); 208061ae650dSJack F Vogel } 208161ae650dSJack F Vogel return (vectors); 208261ae650dSJack F Vogel } 208361ae650dSJack F Vogel 208461ae650dSJack F Vogel 208561ae650dSJack F Vogel /* 208661ae650dSJack F Vogel * Plumb MSI/X vectors 208761ae650dSJack F Vogel */ 208861ae650dSJack F Vogel static void 208961ae650dSJack F Vogel ixl_configure_msix(struct ixl_pf *pf) 209061ae650dSJack F Vogel { 209161ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 209261ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 209361ae650dSJack F Vogel u32 reg; 209461ae650dSJack F Vogel u16 vector = 1; 209561ae650dSJack F Vogel 209661ae650dSJack F Vogel /* First set up the adminq - vector 0 */ 209761ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, 0); /* disable all */ 209861ae650dSJack F Vogel rd32(hw, I40E_PFINT_ICR0); /* read to clear */ 209961ae650dSJack F Vogel 210061ae650dSJack F Vogel reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | 210161ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_GRST_MASK | 210261ae650dSJack F Vogel I40E_PFINT_ICR0_HMC_ERR_MASK | 210361ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_ADMINQ_MASK | 210461ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK | 210561ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_VFLR_MASK | 210661ae650dSJack F Vogel I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK; 210761ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 210861ae650dSJack F Vogel 210961ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLST0, 0x7FF); 211061ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x003E); 211161ae650dSJack F Vogel 211261ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, 211361ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK | 211461ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK); 211561ae650dSJack F Vogel 211661ae650dSJack F Vogel wr32(hw, I40E_PFINT_STAT_CTL0, 0); 211761ae650dSJack F Vogel 211861ae650dSJack F Vogel /* Next configure the queues */ 211961ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, vector++) { 212061ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(i), i); 212161ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLSTN(i), i); 212261ae650dSJack F Vogel 212361ae650dSJack F Vogel reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | 212461ae650dSJack F Vogel (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | 212561ae650dSJack F Vogel (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 212661ae650dSJack F Vogel (i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 212761ae650dSJack F Vogel (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); 212861ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(i), reg); 212961ae650dSJack F Vogel 213061ae650dSJack F Vogel reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK | 213161ae650dSJack F Vogel (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | 213261ae650dSJack F Vogel (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | 213361ae650dSJack F Vogel ((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | 213461ae650dSJack F Vogel (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 213561ae650dSJack F Vogel if (i == (vsi->num_queues - 1)) 213661ae650dSJack F Vogel reg |= (IXL_QUEUE_EOL 213761ae650dSJack F Vogel << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 213861ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(i), reg); 213961ae650dSJack F Vogel } 214061ae650dSJack F Vogel } 214161ae650dSJack F Vogel 214261ae650dSJack F Vogel /* 214361ae650dSJack F Vogel * Configure for MSI single vector operation 214461ae650dSJack F Vogel */ 214561ae650dSJack F Vogel static void 214661ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf) 214761ae650dSJack F Vogel { 214861ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 214961ae650dSJack F Vogel u32 reg; 215061ae650dSJack F Vogel 215161ae650dSJack F Vogel 215261ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(0), 0); 215361ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITR0(1), 0); 215461ae650dSJack F Vogel 215561ae650dSJack F Vogel 215661ae650dSJack F Vogel /* Setup "other" causes */ 215761ae650dSJack F Vogel reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK 215861ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK 215961ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_GRST_MASK 216061ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK 216161ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_GPIO_MASK 216261ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK 216361ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK 216461ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK 216561ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_VFLR_MASK 216661ae650dSJack F Vogel | I40E_PFINT_ICR0_ENA_ADMINQ_MASK 216761ae650dSJack F Vogel ; 216861ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 216961ae650dSJack F Vogel 217061ae650dSJack F Vogel /* SW_ITR_IDX = 0, but don't change INTENA */ 217161ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, 217261ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK | 217361ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK); 217461ae650dSJack F Vogel /* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */ 217561ae650dSJack F Vogel wr32(hw, I40E_PFINT_STAT_CTL0, 0); 217661ae650dSJack F Vogel 217761ae650dSJack F Vogel /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ 217861ae650dSJack F Vogel wr32(hw, I40E_PFINT_LNKLST0, 0); 217961ae650dSJack F Vogel 218061ae650dSJack F Vogel /* Associate the queue pair to the vector and enable the q int */ 218161ae650dSJack F Vogel reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK 218261ae650dSJack F Vogel | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) 218361ae650dSJack F Vogel | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 218461ae650dSJack F Vogel wr32(hw, I40E_QINT_RQCTL(0), reg); 218561ae650dSJack F Vogel 218661ae650dSJack F Vogel reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK 218761ae650dSJack F Vogel | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) 218861ae650dSJack F Vogel | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 218961ae650dSJack F Vogel wr32(hw, I40E_QINT_TQCTL(0), reg); 219061ae650dSJack F Vogel 219161ae650dSJack F Vogel /* Next enable the queue pair */ 219261ae650dSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(0)); 219361ae650dSJack F Vogel reg |= I40E_QTX_ENA_QENA_REQ_MASK; 219461ae650dSJack F Vogel wr32(hw, I40E_QTX_ENA(0), reg); 219561ae650dSJack F Vogel 219661ae650dSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(0)); 219761ae650dSJack F Vogel reg |= I40E_QRX_ENA_QENA_REQ_MASK; 219861ae650dSJack F Vogel wr32(hw, I40E_QRX_ENA(0), reg); 219961ae650dSJack F Vogel } 220061ae650dSJack F Vogel 220161ae650dSJack F Vogel 220261ae650dSJack F Vogel /* 220361ae650dSJack F Vogel * Set the Initial ITR state 220461ae650dSJack F Vogel */ 220561ae650dSJack F Vogel static void 220661ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf) 220761ae650dSJack F Vogel { 220861ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 220961ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 221061ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 221161ae650dSJack F Vogel 221261ae650dSJack F Vogel vsi->rx_itr_setting = ixl_rx_itr; 221361ae650dSJack F Vogel if (ixl_dynamic_rx_itr) 221461ae650dSJack F Vogel vsi->rx_itr_setting |= IXL_ITR_DYNAMIC; 221561ae650dSJack F Vogel vsi->tx_itr_setting = ixl_tx_itr; 221661ae650dSJack F Vogel if (ixl_dynamic_tx_itr) 221761ae650dSJack F Vogel vsi->tx_itr_setting |= IXL_ITR_DYNAMIC; 221861ae650dSJack F Vogel 221961ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 222061ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 222161ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 222261ae650dSJack F Vogel 222361ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i), 222461ae650dSJack F Vogel vsi->rx_itr_setting); 222561ae650dSJack F Vogel rxr->itr = vsi->rx_itr_setting; 222661ae650dSJack F Vogel rxr->latency = IXL_AVE_LATENCY; 222761ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i), 222861ae650dSJack F Vogel vsi->tx_itr_setting); 222961ae650dSJack F Vogel txr->itr = vsi->tx_itr_setting; 223061ae650dSJack F Vogel txr->latency = IXL_AVE_LATENCY; 223161ae650dSJack F Vogel } 223261ae650dSJack F Vogel } 223361ae650dSJack F Vogel 223461ae650dSJack F Vogel 223561ae650dSJack F Vogel static int 223661ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf) 223761ae650dSJack F Vogel { 223861ae650dSJack F Vogel int rid; 223961ae650dSJack F Vogel device_t dev = pf->dev; 224061ae650dSJack F Vogel 224161ae650dSJack F Vogel rid = PCIR_BAR(0); 224261ae650dSJack F Vogel pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 224361ae650dSJack F Vogel &rid, RF_ACTIVE); 224461ae650dSJack F Vogel 224561ae650dSJack F Vogel if (!(pf->pci_mem)) { 224661ae650dSJack F Vogel device_printf(dev,"Unable to allocate bus resource: memory\n"); 224761ae650dSJack F Vogel return (ENXIO); 224861ae650dSJack F Vogel } 224961ae650dSJack F Vogel 225061ae650dSJack F Vogel pf->osdep.mem_bus_space_tag = 225161ae650dSJack F Vogel rman_get_bustag(pf->pci_mem); 225261ae650dSJack F Vogel pf->osdep.mem_bus_space_handle = 225361ae650dSJack F Vogel rman_get_bushandle(pf->pci_mem); 225461ae650dSJack F Vogel pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); 2255cf3c0c32SRyan Stone pf->osdep.flush_reg = I40E_GLGEN_STAT; 225661ae650dSJack F Vogel pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; 225761ae650dSJack F Vogel 225861ae650dSJack F Vogel pf->hw.back = &pf->osdep; 225961ae650dSJack F Vogel 226061ae650dSJack F Vogel /* 226161ae650dSJack F Vogel ** Now setup MSI or MSI/X, should 226261ae650dSJack F Vogel ** return us the number of supported 226361ae650dSJack F Vogel ** vectors. (Will be 1 for MSI) 226461ae650dSJack F Vogel */ 226561ae650dSJack F Vogel pf->msix = ixl_init_msix(pf); 226661ae650dSJack F Vogel return (0); 226761ae650dSJack F Vogel } 226861ae650dSJack F Vogel 226961ae650dSJack F Vogel static void 227061ae650dSJack F Vogel ixl_free_pci_resources(struct ixl_pf * pf) 227161ae650dSJack F Vogel { 227261ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 227361ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 227461ae650dSJack F Vogel device_t dev = pf->dev; 227561ae650dSJack F Vogel int rid, memrid; 227661ae650dSJack F Vogel 227761ae650dSJack F Vogel memrid = PCIR_BAR(IXL_BAR); 227861ae650dSJack F Vogel 227961ae650dSJack F Vogel /* We may get here before stations are setup */ 228061ae650dSJack F Vogel if ((!ixl_enable_msix) || (que == NULL)) 228161ae650dSJack F Vogel goto early; 228261ae650dSJack F Vogel 228361ae650dSJack F Vogel /* 228461ae650dSJack F Vogel ** Release all msix VSI resources: 228561ae650dSJack F Vogel */ 228661ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 228761ae650dSJack F Vogel rid = que->msix + 1; 228861ae650dSJack F Vogel if (que->tag != NULL) { 228961ae650dSJack F Vogel bus_teardown_intr(dev, que->res, que->tag); 229061ae650dSJack F Vogel que->tag = NULL; 229161ae650dSJack F Vogel } 229261ae650dSJack F Vogel if (que->res != NULL) 229361ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 229461ae650dSJack F Vogel } 229561ae650dSJack F Vogel 229661ae650dSJack F Vogel early: 229761ae650dSJack F Vogel /* Clean the AdminQ interrupt last */ 229861ae650dSJack F Vogel if (pf->admvec) /* we are doing MSIX */ 229961ae650dSJack F Vogel rid = pf->admvec + 1; 230061ae650dSJack F Vogel else 230161ae650dSJack F Vogel (pf->msix != 0) ? (rid = 1):(rid = 0); 230261ae650dSJack F Vogel 230361ae650dSJack F Vogel if (pf->tag != NULL) { 230461ae650dSJack F Vogel bus_teardown_intr(dev, pf->res, pf->tag); 230561ae650dSJack F Vogel pf->tag = NULL; 230661ae650dSJack F Vogel } 230761ae650dSJack F Vogel if (pf->res != NULL) 230861ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); 230961ae650dSJack F Vogel 231061ae650dSJack F Vogel if (pf->msix) 231161ae650dSJack F Vogel pci_release_msi(dev); 231261ae650dSJack F Vogel 231361ae650dSJack F Vogel if (pf->msix_mem != NULL) 231461ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 231561ae650dSJack F Vogel memrid, pf->msix_mem); 231661ae650dSJack F Vogel 231761ae650dSJack F Vogel if (pf->pci_mem != NULL) 231861ae650dSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 231961ae650dSJack F Vogel PCIR_BAR(0), pf->pci_mem); 232061ae650dSJack F Vogel 232161ae650dSJack F Vogel return; 232261ae650dSJack F Vogel } 232361ae650dSJack F Vogel 2324e5100ee2SJack F Vogel static void 2325e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type) 2326e5100ee2SJack F Vogel { 2327e5100ee2SJack F Vogel /* Display supported media types */ 2328e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX)) 2329e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2330e5100ee2SJack F Vogel 2331e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T)) 2332e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); 2333e5100ee2SJack F Vogel 2334e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) || 2335b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4) || 2336b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR) || 2337b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) || 2338b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XAUI) || 2339b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XFI) || 2340b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_SFI) || 2341e5100ee2SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU)) 2342e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2343b6c8f260SJack F Vogel 2344e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR)) 2345e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2346e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR)) 2347e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2348e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T)) 2349e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2350e5100ee2SJack F Vogel 2351b6c8f260SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) || 2352b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) || 2353b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) || 2354b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XLAUI) || 2355b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_XLPPI) || 2356b6c8f260SJack F Vogel /* KR4 uses CR4 until the OS has the real media type */ 2357b6c8f260SJack F Vogel phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2358e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2359b6c8f260SJack F Vogel 2360e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4)) 2361e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2362e5100ee2SJack F Vogel if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4)) 2363e5100ee2SJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); 2364e5100ee2SJack F Vogel } 236561ae650dSJack F Vogel 236661ae650dSJack F Vogel /********************************************************************* 236761ae650dSJack F Vogel * 236861ae650dSJack F Vogel * Setup networking device structure and register an interface. 236961ae650dSJack F Vogel * 237061ae650dSJack F Vogel **********************************************************************/ 237161ae650dSJack F Vogel static int 237261ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi) 237361ae650dSJack F Vogel { 237461ae650dSJack F Vogel struct ifnet *ifp; 237561ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 237661ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 2377b6c8f260SJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 237861ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 237961ae650dSJack F Vogel 238061ae650dSJack F Vogel INIT_DEBUGOUT("ixl_setup_interface: begin"); 238161ae650dSJack F Vogel 238261ae650dSJack F Vogel ifp = vsi->ifp = if_alloc(IFT_ETHER); 238361ae650dSJack F Vogel if (ifp == NULL) { 238461ae650dSJack F Vogel device_printf(dev, "can not allocate ifnet structure\n"); 238561ae650dSJack F Vogel return (-1); 238661ae650dSJack F Vogel } 238761ae650dSJack F Vogel if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 238861ae650dSJack F Vogel ifp->if_mtu = ETHERMTU; 238961ae650dSJack F Vogel ifp->if_baudrate = 4000000000; // ?? 239061ae650dSJack F Vogel ifp->if_init = ixl_init; 239161ae650dSJack F Vogel ifp->if_softc = vsi; 239261ae650dSJack F Vogel ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 239361ae650dSJack F Vogel ifp->if_ioctl = ixl_ioctl; 239461ae650dSJack F Vogel 2395e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036 23964b443922SGleb Smirnoff if_setgetcounterfn(ifp, ixl_get_counter); 23974b443922SGleb Smirnoff #endif 23984b443922SGleb Smirnoff 239961ae650dSJack F Vogel ifp->if_transmit = ixl_mq_start; 240061ae650dSJack F Vogel 240161ae650dSJack F Vogel ifp->if_qflush = ixl_qflush; 240261ae650dSJack F Vogel 240361ae650dSJack F Vogel ifp->if_snd.ifq_maxlen = que->num_desc - 2; 240461ae650dSJack F Vogel 240561ae650dSJack F Vogel vsi->max_frame_size = 240661ae650dSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 240761ae650dSJack F Vogel + ETHER_VLAN_ENCAP_LEN; 240861ae650dSJack F Vogel 240961ae650dSJack F Vogel /* 241061ae650dSJack F Vogel * Tell the upper layer(s) we support long frames. 241161ae650dSJack F Vogel */ 24121bffa951SGleb Smirnoff ifp->if_hdrlen = sizeof(struct ether_vlan_header); 241361ae650dSJack F Vogel 241461ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM; 241561ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; 241661ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_TSO; 241761ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_JUMBO_MTU; 241861ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_LRO; 241961ae650dSJack F Vogel 242061ae650dSJack F Vogel /* VLAN capabilties */ 242161ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 242261ae650dSJack F Vogel | IFCAP_VLAN_HWTSO 242361ae650dSJack F Vogel | IFCAP_VLAN_MTU 242461ae650dSJack F Vogel | IFCAP_VLAN_HWCSUM; 242561ae650dSJack F Vogel ifp->if_capenable = ifp->if_capabilities; 242661ae650dSJack F Vogel 242761ae650dSJack F Vogel /* 242861ae650dSJack F Vogel ** Don't turn this on by default, if vlans are 242961ae650dSJack F Vogel ** created on another pseudo device (eg. lagg) 243061ae650dSJack F Vogel ** then vlan events are not passed thru, breaking 243161ae650dSJack F Vogel ** operation, but with HW FILTER off it works. If 243261ae650dSJack F Vogel ** using vlans directly on the ixl driver you can 243361ae650dSJack F Vogel ** enable this and get full hardware tag filtering. 243461ae650dSJack F Vogel */ 243561ae650dSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 243661ae650dSJack F Vogel 243761ae650dSJack F Vogel /* 243861ae650dSJack F Vogel * Specify the media types supported by this adapter and register 243961ae650dSJack F Vogel * callbacks to update media and link information 244061ae650dSJack F Vogel */ 244161ae650dSJack F Vogel ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change, 244261ae650dSJack F Vogel ixl_media_status); 244361ae650dSJack F Vogel 2444b6c8f260SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 2445b6c8f260SJack F Vogel FALSE, TRUE, &abilities, NULL); 2446b6c8f260SJack F Vogel /* May need delay to detect fiber correctly */ 2447e5100ee2SJack F Vogel if (aq_error == I40E_ERR_UNKNOWN_PHY) { 2448e5100ee2SJack F Vogel i40e_msec_delay(200); 2449393c4bb1SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, 2450b6c8f260SJack F Vogel TRUE, &abilities, NULL); 2451b6c8f260SJack F Vogel } 2452b6c8f260SJack F Vogel if (aq_error) { 2453e5100ee2SJack F Vogel if (aq_error == I40E_ERR_UNKNOWN_PHY) 2454e5100ee2SJack F Vogel device_printf(dev, "Unknown PHY type detected!\n"); 2455e5100ee2SJack F Vogel else 2456b6c8f260SJack F Vogel device_printf(dev, 2457b6c8f260SJack F Vogel "Error getting supported media types, err %d," 2458e5100ee2SJack F Vogel " AQ error %d\n", aq_error, hw->aq.asq_last_status); 2459b6c8f260SJack F Vogel return (0); 2460b6c8f260SJack F Vogel } 2461b6c8f260SJack F Vogel 2462b6c8f260SJack F Vogel ixl_add_ifmedia(vsi, abilities.phy_type); 246361ae650dSJack F Vogel 246461ae650dSJack F Vogel /* Use autoselect media by default */ 246561ae650dSJack F Vogel ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); 246661ae650dSJack F Vogel ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); 246761ae650dSJack F Vogel 2468e5100ee2SJack F Vogel ether_ifattach(ifp, hw->mac.addr); 2469e5100ee2SJack F Vogel 247061ae650dSJack F Vogel return (0); 247161ae650dSJack F Vogel } 247261ae650dSJack F Vogel 247361ae650dSJack F Vogel static bool 247461ae650dSJack F Vogel ixl_config_link(struct i40e_hw *hw) 247561ae650dSJack F Vogel { 247661ae650dSJack F Vogel bool check; 247761ae650dSJack F Vogel 247861ae650dSJack F Vogel i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 247961ae650dSJack F Vogel check = i40e_get_link_status(hw); 248061ae650dSJack F Vogel #ifdef IXL_DEBUG 248161ae650dSJack F Vogel printf("Link is %s\n", check ? "up":"down"); 248261ae650dSJack F Vogel #endif 248361ae650dSJack F Vogel return (check); 248461ae650dSJack F Vogel } 248561ae650dSJack F Vogel 248661ae650dSJack F Vogel /********************************************************************* 248761ae650dSJack F Vogel * 2488b6c8f260SJack F Vogel * Get Firmware Switch configuration 2489b6c8f260SJack F Vogel * - this will need to be more robust when more complex 2490b6c8f260SJack F Vogel * switch configurations are enabled. 249161ae650dSJack F Vogel * 249261ae650dSJack F Vogel **********************************************************************/ 249361ae650dSJack F Vogel static int 2494b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf) 249561ae650dSJack F Vogel { 2496b6c8f260SJack F Vogel struct i40e_hw *hw = &pf->hw; 2497b6c8f260SJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 249861ae650dSJack F Vogel device_t dev = vsi->dev; 249961ae650dSJack F Vogel struct i40e_aqc_get_switch_config_resp *sw_config; 250061ae650dSJack F Vogel u8 aq_buf[I40E_AQ_LARGE_BUF]; 250161ae650dSJack F Vogel int ret = I40E_SUCCESS; 250261ae650dSJack F Vogel u16 next = 0; 250361ae650dSJack F Vogel 2504b6c8f260SJack F Vogel memset(&aq_buf, 0, sizeof(aq_buf)); 250561ae650dSJack F Vogel sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 250661ae650dSJack F Vogel ret = i40e_aq_get_switch_config(hw, sw_config, 250761ae650dSJack F Vogel sizeof(aq_buf), &next, NULL); 250861ae650dSJack F Vogel if (ret) { 250961ae650dSJack F Vogel device_printf(dev,"aq_get_switch_config failed!!\n"); 251061ae650dSJack F Vogel return (ret); 251161ae650dSJack F Vogel } 251261ae650dSJack F Vogel #ifdef IXL_DEBUG 251361ae650dSJack F Vogel printf("Switch config: header reported: %d in structure, %d total\n", 251461ae650dSJack F Vogel sw_config->header.num_reported, sw_config->header.num_total); 251561ae650dSJack F Vogel printf("type=%d seid=%d uplink=%d downlink=%d\n", 251661ae650dSJack F Vogel sw_config->element[0].element_type, 251761ae650dSJack F Vogel sw_config->element[0].seid, 251861ae650dSJack F Vogel sw_config->element[0].uplink_seid, 251961ae650dSJack F Vogel sw_config->element[0].downlink_seid); 252061ae650dSJack F Vogel #endif 2521b6c8f260SJack F Vogel /* Simplified due to a single VSI at the moment */ 252261ae650dSJack F Vogel vsi->seid = sw_config->element[0].seid; 2523b6c8f260SJack F Vogel return (ret); 2524b6c8f260SJack F Vogel } 2525b6c8f260SJack F Vogel 2526b6c8f260SJack F Vogel /********************************************************************* 2527b6c8f260SJack F Vogel * 2528b6c8f260SJack F Vogel * Initialize the VSI: this handles contexts, which means things 2529b6c8f260SJack F Vogel * like the number of descriptors, buffer size, 2530b6c8f260SJack F Vogel * plus we init the rings thru this function. 2531b6c8f260SJack F Vogel * 2532b6c8f260SJack F Vogel **********************************************************************/ 2533b6c8f260SJack F Vogel static int 2534b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi) 2535b6c8f260SJack F Vogel { 2536b6c8f260SJack F Vogel struct ixl_queue *que = vsi->queues; 2537b6c8f260SJack F Vogel device_t dev = vsi->dev; 2538b6c8f260SJack F Vogel struct i40e_hw *hw = vsi->hw; 2539b6c8f260SJack F Vogel struct i40e_vsi_context ctxt; 2540b6c8f260SJack F Vogel int err = 0; 254161ae650dSJack F Vogel 254261ae650dSJack F Vogel memset(&ctxt, 0, sizeof(ctxt)); 254361ae650dSJack F Vogel ctxt.seid = vsi->seid; 254461ae650dSJack F Vogel ctxt.pf_num = hw->pf_id; 2545b6c8f260SJack F Vogel err = i40e_aq_get_vsi_params(hw, &ctxt, NULL); 2546b6c8f260SJack F Vogel if (err) { 2547b6c8f260SJack F Vogel device_printf(dev,"get vsi params failed %x!!\n", err); 2548b6c8f260SJack F Vogel return (err); 254961ae650dSJack F Vogel } 255061ae650dSJack F Vogel #ifdef IXL_DEBUG 255161ae650dSJack F Vogel printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, " 255261ae650dSJack F Vogel "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, " 255361ae650dSJack F Vogel "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid, 255461ae650dSJack F Vogel ctxt.uplink_seid, ctxt.vsi_number, 255561ae650dSJack F Vogel ctxt.vsis_allocated, ctxt.vsis_unallocated, 255661ae650dSJack F Vogel ctxt.flags, ctxt.pf_num, ctxt.vf_num, 255761ae650dSJack F Vogel ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits); 255861ae650dSJack F Vogel #endif 255961ae650dSJack F Vogel /* 256061ae650dSJack F Vogel ** Set the queue and traffic class bits 256161ae650dSJack F Vogel ** - when multiple traffic classes are supported 256261ae650dSJack F Vogel ** this will need to be more robust. 256361ae650dSJack F Vogel */ 256461ae650dSJack F Vogel ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID; 256561ae650dSJack F Vogel ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG; 256661ae650dSJack F Vogel ctxt.info.queue_mapping[0] = 0; 256761ae650dSJack F Vogel ctxt.info.tc_mapping[0] = 0x0800; 256861ae650dSJack F Vogel 256961ae650dSJack F Vogel /* Set VLAN receive stripping mode */ 257061ae650dSJack F Vogel ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; 257161ae650dSJack F Vogel ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; 257261ae650dSJack F Vogel if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 257361ae650dSJack F Vogel ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 257461ae650dSJack F Vogel else 257561ae650dSJack F Vogel ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 257661ae650dSJack F Vogel 257761ae650dSJack F Vogel /* Keep copy of VSI info in VSI for statistic counters */ 257861ae650dSJack F Vogel memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); 257961ae650dSJack F Vogel 258061ae650dSJack F Vogel /* Reset VSI statistics */ 258161ae650dSJack F Vogel ixl_vsi_reset_stats(vsi); 258261ae650dSJack F Vogel vsi->hw_filters_add = 0; 258361ae650dSJack F Vogel vsi->hw_filters_del = 0; 258461ae650dSJack F Vogel 2585b6c8f260SJack F Vogel err = i40e_aq_update_vsi_params(hw, &ctxt, NULL); 2586b6c8f260SJack F Vogel if (err) { 258761ae650dSJack F Vogel device_printf(dev,"update vsi params failed %x!!\n", 258861ae650dSJack F Vogel hw->aq.asq_last_status); 2589b6c8f260SJack F Vogel return (err); 259061ae650dSJack F Vogel } 259161ae650dSJack F Vogel 259261ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 259361ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 259461ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 259561ae650dSJack F Vogel struct i40e_hmc_obj_txq tctx; 259661ae650dSJack F Vogel struct i40e_hmc_obj_rxq rctx; 259761ae650dSJack F Vogel u32 txctl; 259861ae650dSJack F Vogel u16 size; 259961ae650dSJack F Vogel 260061ae650dSJack F Vogel 260161ae650dSJack F Vogel /* Setup the HMC TX Context */ 260261ae650dSJack F Vogel size = que->num_desc * sizeof(struct i40e_tx_desc); 260361ae650dSJack F Vogel memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq)); 260461ae650dSJack F Vogel tctx.new_context = 1; 260561ae650dSJack F Vogel tctx.base = (txr->dma.pa/128); 260661ae650dSJack F Vogel tctx.qlen = que->num_desc; 260761ae650dSJack F Vogel tctx.fc_ena = 0; 260861ae650dSJack F Vogel tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */ 260961ae650dSJack F Vogel /* Enable HEAD writeback */ 261061ae650dSJack F Vogel tctx.head_wb_ena = 1; 261161ae650dSJack F Vogel tctx.head_wb_addr = txr->dma.pa + 261261ae650dSJack F Vogel (que->num_desc * sizeof(struct i40e_tx_desc)); 261361ae650dSJack F Vogel tctx.rdylist_act = 0; 261461ae650dSJack F Vogel err = i40e_clear_lan_tx_queue_context(hw, i); 261561ae650dSJack F Vogel if (err) { 261661ae650dSJack F Vogel device_printf(dev, "Unable to clear TX context\n"); 261761ae650dSJack F Vogel break; 261861ae650dSJack F Vogel } 261961ae650dSJack F Vogel err = i40e_set_lan_tx_queue_context(hw, i, &tctx); 262061ae650dSJack F Vogel if (err) { 262161ae650dSJack F Vogel device_printf(dev, "Unable to set TX context\n"); 262261ae650dSJack F Vogel break; 262361ae650dSJack F Vogel } 262461ae650dSJack F Vogel /* Associate the ring with this PF */ 262561ae650dSJack F Vogel txctl = I40E_QTX_CTL_PF_QUEUE; 262661ae650dSJack F Vogel txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & 262761ae650dSJack F Vogel I40E_QTX_CTL_PF_INDX_MASK); 262861ae650dSJack F Vogel wr32(hw, I40E_QTX_CTL(i), txctl); 262961ae650dSJack F Vogel ixl_flush(hw); 263061ae650dSJack F Vogel 263161ae650dSJack F Vogel /* Do ring (re)init */ 263261ae650dSJack F Vogel ixl_init_tx_ring(que); 263361ae650dSJack F Vogel 263461ae650dSJack F Vogel /* Next setup the HMC RX Context */ 263561ae650dSJack F Vogel if (vsi->max_frame_size <= 2048) 263661ae650dSJack F Vogel rxr->mbuf_sz = MCLBYTES; 263761ae650dSJack F Vogel else 263861ae650dSJack F Vogel rxr->mbuf_sz = MJUMPAGESIZE; 263961ae650dSJack F Vogel 264061ae650dSJack F Vogel u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len; 264161ae650dSJack F Vogel 264261ae650dSJack F Vogel /* Set up an RX context for the HMC */ 264361ae650dSJack F Vogel memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq)); 264461ae650dSJack F Vogel rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT; 264561ae650dSJack F Vogel /* ignore header split for now */ 264661ae650dSJack F Vogel rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; 264761ae650dSJack F Vogel rctx.rxmax = (vsi->max_frame_size < max_rxmax) ? 264861ae650dSJack F Vogel vsi->max_frame_size : max_rxmax; 264961ae650dSJack F Vogel rctx.dtype = 0; 265061ae650dSJack F Vogel rctx.dsize = 1; /* do 32byte descriptors */ 265161ae650dSJack F Vogel rctx.hsplit_0 = 0; /* no HDR split initially */ 265261ae650dSJack F Vogel rctx.base = (rxr->dma.pa/128); 265361ae650dSJack F Vogel rctx.qlen = que->num_desc; 265461ae650dSJack F Vogel rctx.tphrdesc_ena = 1; 265561ae650dSJack F Vogel rctx.tphwdesc_ena = 1; 265661ae650dSJack F Vogel rctx.tphdata_ena = 0; 265761ae650dSJack F Vogel rctx.tphhead_ena = 0; 265861ae650dSJack F Vogel rctx.lrxqthresh = 2; 265961ae650dSJack F Vogel rctx.crcstrip = 1; 266061ae650dSJack F Vogel rctx.l2tsel = 1; 266161ae650dSJack F Vogel rctx.showiv = 1; 266261ae650dSJack F Vogel rctx.fc_ena = 0; 266361ae650dSJack F Vogel rctx.prefena = 1; 266461ae650dSJack F Vogel 266561ae650dSJack F Vogel err = i40e_clear_lan_rx_queue_context(hw, i); 266661ae650dSJack F Vogel if (err) { 266761ae650dSJack F Vogel device_printf(dev, 266861ae650dSJack F Vogel "Unable to clear RX context %d\n", i); 266961ae650dSJack F Vogel break; 267061ae650dSJack F Vogel } 267161ae650dSJack F Vogel err = i40e_set_lan_rx_queue_context(hw, i, &rctx); 267261ae650dSJack F Vogel if (err) { 267361ae650dSJack F Vogel device_printf(dev, "Unable to set RX context %d\n", i); 267461ae650dSJack F Vogel break; 267561ae650dSJack F Vogel } 267661ae650dSJack F Vogel err = ixl_init_rx_ring(que); 267761ae650dSJack F Vogel if (err) { 267861ae650dSJack F Vogel device_printf(dev, "Fail in init_rx_ring %d\n", i); 267961ae650dSJack F Vogel break; 268061ae650dSJack F Vogel } 268161ae650dSJack F Vogel wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0); 2682bc8b78d3SLuigi Rizzo #ifdef DEV_NETMAP 2683bc8b78d3SLuigi Rizzo /* preserve queue */ 2684bc8b78d3SLuigi Rizzo if (vsi->ifp->if_capenable & IFCAP_NETMAP) { 2685bc8b78d3SLuigi Rizzo struct netmap_adapter *na = NA(vsi->ifp); 2686bc8b78d3SLuigi Rizzo struct netmap_kring *kring = &na->rx_rings[i]; 2687bc8b78d3SLuigi Rizzo int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); 2688bc8b78d3SLuigi Rizzo wr32(vsi->hw, I40E_QRX_TAIL(que->me), t); 2689bc8b78d3SLuigi Rizzo } else 2690bc8b78d3SLuigi Rizzo #endif /* DEV_NETMAP */ 269161ae650dSJack F Vogel wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1); 269261ae650dSJack F Vogel } 269361ae650dSJack F Vogel return (err); 269461ae650dSJack F Vogel } 269561ae650dSJack F Vogel 269661ae650dSJack F Vogel 269761ae650dSJack F Vogel /********************************************************************* 269861ae650dSJack F Vogel * 269961ae650dSJack F Vogel * Free all VSI structs. 270061ae650dSJack F Vogel * 270161ae650dSJack F Vogel **********************************************************************/ 270261ae650dSJack F Vogel void 270361ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi) 270461ae650dSJack F Vogel { 270561ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 270661ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 270761ae650dSJack F Vogel struct ixl_mac_filter *f; 270861ae650dSJack F Vogel 270961ae650dSJack F Vogel /* Free station queues */ 271061ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) { 271161ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 271261ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 271361ae650dSJack F Vogel 271461ae650dSJack F Vogel if (!mtx_initialized(&txr->mtx)) /* uninitialized */ 271561ae650dSJack F Vogel continue; 271661ae650dSJack F Vogel IXL_TX_LOCK(txr); 271761ae650dSJack F Vogel ixl_free_que_tx(que); 271861ae650dSJack F Vogel if (txr->base) 2719d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &txr->dma); 272061ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 272161ae650dSJack F Vogel IXL_TX_LOCK_DESTROY(txr); 272261ae650dSJack F Vogel 272361ae650dSJack F Vogel if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ 272461ae650dSJack F Vogel continue; 272561ae650dSJack F Vogel IXL_RX_LOCK(rxr); 272661ae650dSJack F Vogel ixl_free_que_rx(que); 272761ae650dSJack F Vogel if (rxr->base) 2728d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &rxr->dma); 272961ae650dSJack F Vogel IXL_RX_UNLOCK(rxr); 273061ae650dSJack F Vogel IXL_RX_LOCK_DESTROY(rxr); 273161ae650dSJack F Vogel 273261ae650dSJack F Vogel } 273361ae650dSJack F Vogel free(vsi->queues, M_DEVBUF); 273461ae650dSJack F Vogel 273561ae650dSJack F Vogel /* Free VSI filter list */ 273661ae650dSJack F Vogel while (!SLIST_EMPTY(&vsi->ftl)) { 273761ae650dSJack F Vogel f = SLIST_FIRST(&vsi->ftl); 273861ae650dSJack F Vogel SLIST_REMOVE_HEAD(&vsi->ftl, next); 273961ae650dSJack F Vogel free(f, M_DEVBUF); 274061ae650dSJack F Vogel } 274161ae650dSJack F Vogel } 274261ae650dSJack F Vogel 274361ae650dSJack F Vogel 274461ae650dSJack F Vogel /********************************************************************* 274561ae650dSJack F Vogel * 274661ae650dSJack F Vogel * Allocate memory for the VSI (virtual station interface) and their 274761ae650dSJack F Vogel * associated queues, rings and the descriptors associated with each, 274861ae650dSJack F Vogel * called only once at attach. 274961ae650dSJack F Vogel * 275061ae650dSJack F Vogel **********************************************************************/ 275161ae650dSJack F Vogel static int 275261ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf) 275361ae650dSJack F Vogel { 275461ae650dSJack F Vogel device_t dev = pf->dev; 275561ae650dSJack F Vogel struct ixl_vsi *vsi; 275661ae650dSJack F Vogel struct ixl_queue *que; 275761ae650dSJack F Vogel struct tx_ring *txr; 275861ae650dSJack F Vogel struct rx_ring *rxr; 275961ae650dSJack F Vogel int rsize, tsize; 276061ae650dSJack F Vogel int error = I40E_SUCCESS; 276161ae650dSJack F Vogel 276261ae650dSJack F Vogel vsi = &pf->vsi; 276361ae650dSJack F Vogel vsi->back = (void *)pf; 276461ae650dSJack F Vogel vsi->hw = &pf->hw; 276561ae650dSJack F Vogel vsi->id = 0; 276661ae650dSJack F Vogel vsi->num_vlans = 0; 276761ae650dSJack F Vogel 276861ae650dSJack F Vogel /* Get memory for the station queues */ 276961ae650dSJack F Vogel if (!(vsi->queues = 277061ae650dSJack F Vogel (struct ixl_queue *) malloc(sizeof(struct ixl_queue) * 277161ae650dSJack F Vogel vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { 277261ae650dSJack F Vogel device_printf(dev, "Unable to allocate queue memory\n"); 277361ae650dSJack F Vogel error = ENOMEM; 277461ae650dSJack F Vogel goto early; 277561ae650dSJack F Vogel } 277661ae650dSJack F Vogel 277761ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 277861ae650dSJack F Vogel que = &vsi->queues[i]; 277961ae650dSJack F Vogel que->num_desc = ixl_ringsz; 278061ae650dSJack F Vogel que->me = i; 278161ae650dSJack F Vogel que->vsi = vsi; 278261ae650dSJack F Vogel /* mark the queue as active */ 278361ae650dSJack F Vogel vsi->active_queues |= (u64)1 << que->me; 278461ae650dSJack F Vogel txr = &que->txr; 278561ae650dSJack F Vogel txr->que = que; 278661ae650dSJack F Vogel txr->tail = I40E_QTX_TAIL(que->me); 278761ae650dSJack F Vogel 278861ae650dSJack F Vogel /* Initialize the TX lock */ 278961ae650dSJack F Vogel snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", 279061ae650dSJack F Vogel device_get_nameunit(dev), que->me); 279161ae650dSJack F Vogel mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF); 279261ae650dSJack F Vogel /* Create the TX descriptor ring */ 279361ae650dSJack F Vogel tsize = roundup2((que->num_desc * 279461ae650dSJack F Vogel sizeof(struct i40e_tx_desc)) + 279561ae650dSJack F Vogel sizeof(u32), DBA_ALIGN); 2796d94ca7cfSBjoern A. Zeeb if (i40e_allocate_dma_mem(&pf->hw, 2797d94ca7cfSBjoern A. Zeeb &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) { 279861ae650dSJack F Vogel device_printf(dev, 279961ae650dSJack F Vogel "Unable to allocate TX Descriptor memory\n"); 280061ae650dSJack F Vogel error = ENOMEM; 280161ae650dSJack F Vogel goto fail; 280261ae650dSJack F Vogel } 280361ae650dSJack F Vogel txr->base = (struct i40e_tx_desc *)txr->dma.va; 280461ae650dSJack F Vogel bzero((void *)txr->base, tsize); 280561ae650dSJack F Vogel /* Now allocate transmit soft structs for the ring */ 280661ae650dSJack F Vogel if (ixl_allocate_tx_data(que)) { 280761ae650dSJack F Vogel device_printf(dev, 280861ae650dSJack F Vogel "Critical Failure setting up TX structures\n"); 280961ae650dSJack F Vogel error = ENOMEM; 281061ae650dSJack F Vogel goto fail; 281161ae650dSJack F Vogel } 281261ae650dSJack F Vogel /* Allocate a buf ring */ 281361ae650dSJack F Vogel txr->br = buf_ring_alloc(4096, M_DEVBUF, 281461ae650dSJack F Vogel M_WAITOK, &txr->mtx); 281561ae650dSJack F Vogel if (txr->br == NULL) { 281661ae650dSJack F Vogel device_printf(dev, 281761ae650dSJack F Vogel "Critical Failure setting up TX buf ring\n"); 281861ae650dSJack F Vogel error = ENOMEM; 281961ae650dSJack F Vogel goto fail; 282061ae650dSJack F Vogel } 282161ae650dSJack F Vogel 282261ae650dSJack F Vogel /* 282361ae650dSJack F Vogel * Next the RX queues... 282461ae650dSJack F Vogel */ 282561ae650dSJack F Vogel rsize = roundup2(que->num_desc * 282661ae650dSJack F Vogel sizeof(union i40e_rx_desc), DBA_ALIGN); 282761ae650dSJack F Vogel rxr = &que->rxr; 282861ae650dSJack F Vogel rxr->que = que; 282961ae650dSJack F Vogel rxr->tail = I40E_QRX_TAIL(que->me); 283061ae650dSJack F Vogel 283161ae650dSJack F Vogel /* Initialize the RX side lock */ 283261ae650dSJack F Vogel snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", 283361ae650dSJack F Vogel device_get_nameunit(dev), que->me); 283461ae650dSJack F Vogel mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF); 283561ae650dSJack F Vogel 2836d94ca7cfSBjoern A. Zeeb if (i40e_allocate_dma_mem(&pf->hw, 2837d94ca7cfSBjoern A. Zeeb &rxr->dma, i40e_mem_reserved, rsize, 4096)) { 283861ae650dSJack F Vogel device_printf(dev, 283961ae650dSJack F Vogel "Unable to allocate RX Descriptor memory\n"); 284061ae650dSJack F Vogel error = ENOMEM; 284161ae650dSJack F Vogel goto fail; 284261ae650dSJack F Vogel } 284361ae650dSJack F Vogel rxr->base = (union i40e_rx_desc *)rxr->dma.va; 284461ae650dSJack F Vogel bzero((void *)rxr->base, rsize); 284561ae650dSJack F Vogel 284661ae650dSJack F Vogel /* Allocate receive soft structs for the ring*/ 284761ae650dSJack F Vogel if (ixl_allocate_rx_data(que)) { 284861ae650dSJack F Vogel device_printf(dev, 284961ae650dSJack F Vogel "Critical Failure setting up receive structs\n"); 285061ae650dSJack F Vogel error = ENOMEM; 285161ae650dSJack F Vogel goto fail; 285261ae650dSJack F Vogel } 285361ae650dSJack F Vogel } 285461ae650dSJack F Vogel 285561ae650dSJack F Vogel return (0); 285661ae650dSJack F Vogel 285761ae650dSJack F Vogel fail: 285861ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 285961ae650dSJack F Vogel que = &vsi->queues[i]; 286061ae650dSJack F Vogel rxr = &que->rxr; 286161ae650dSJack F Vogel txr = &que->txr; 286261ae650dSJack F Vogel if (rxr->base) 2863d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &rxr->dma); 286461ae650dSJack F Vogel if (txr->base) 2865d94ca7cfSBjoern A. Zeeb i40e_free_dma_mem(&pf->hw, &txr->dma); 286661ae650dSJack F Vogel } 286761ae650dSJack F Vogel 286861ae650dSJack F Vogel early: 286961ae650dSJack F Vogel return (error); 287061ae650dSJack F Vogel } 287161ae650dSJack F Vogel 287261ae650dSJack F Vogel /* 287361ae650dSJack F Vogel ** Provide a update to the queue RX 287461ae650dSJack F Vogel ** interrupt moderation value. 287561ae650dSJack F Vogel */ 287661ae650dSJack F Vogel static void 287761ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que) 287861ae650dSJack F Vogel { 287961ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 288061ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 288161ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 288261ae650dSJack F Vogel u16 rx_itr; 288361ae650dSJack F Vogel u16 rx_latency = 0; 288461ae650dSJack F Vogel int rx_bytes; 288561ae650dSJack F Vogel 288661ae650dSJack F Vogel 288761ae650dSJack F Vogel /* Idle, do nothing */ 288861ae650dSJack F Vogel if (rxr->bytes == 0) 288961ae650dSJack F Vogel return; 289061ae650dSJack F Vogel 289161ae650dSJack F Vogel if (ixl_dynamic_rx_itr) { 289261ae650dSJack F Vogel rx_bytes = rxr->bytes/rxr->itr; 289361ae650dSJack F Vogel rx_itr = rxr->itr; 289461ae650dSJack F Vogel 289561ae650dSJack F Vogel /* Adjust latency range */ 289661ae650dSJack F Vogel switch (rxr->latency) { 289761ae650dSJack F Vogel case IXL_LOW_LATENCY: 289861ae650dSJack F Vogel if (rx_bytes > 10) { 289961ae650dSJack F Vogel rx_latency = IXL_AVE_LATENCY; 290061ae650dSJack F Vogel rx_itr = IXL_ITR_20K; 290161ae650dSJack F Vogel } 290261ae650dSJack F Vogel break; 290361ae650dSJack F Vogel case IXL_AVE_LATENCY: 290461ae650dSJack F Vogel if (rx_bytes > 20) { 290561ae650dSJack F Vogel rx_latency = IXL_BULK_LATENCY; 290661ae650dSJack F Vogel rx_itr = IXL_ITR_8K; 290761ae650dSJack F Vogel } else if (rx_bytes <= 10) { 290861ae650dSJack F Vogel rx_latency = IXL_LOW_LATENCY; 290961ae650dSJack F Vogel rx_itr = IXL_ITR_100K; 291061ae650dSJack F Vogel } 291161ae650dSJack F Vogel break; 291261ae650dSJack F Vogel case IXL_BULK_LATENCY: 291361ae650dSJack F Vogel if (rx_bytes <= 20) { 291461ae650dSJack F Vogel rx_latency = IXL_AVE_LATENCY; 291561ae650dSJack F Vogel rx_itr = IXL_ITR_20K; 291661ae650dSJack F Vogel } 291761ae650dSJack F Vogel break; 291861ae650dSJack F Vogel } 291961ae650dSJack F Vogel 292061ae650dSJack F Vogel rxr->latency = rx_latency; 292161ae650dSJack F Vogel 292261ae650dSJack F Vogel if (rx_itr != rxr->itr) { 292361ae650dSJack F Vogel /* do an exponential smoothing */ 292461ae650dSJack F Vogel rx_itr = (10 * rx_itr * rxr->itr) / 292561ae650dSJack F Vogel ((9 * rx_itr) + rxr->itr); 292661ae650dSJack F Vogel rxr->itr = rx_itr & IXL_MAX_ITR; 292761ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 292861ae650dSJack F Vogel que->me), rxr->itr); 292961ae650dSJack F Vogel } 293061ae650dSJack F Vogel } else { /* We may have have toggled to non-dynamic */ 293161ae650dSJack F Vogel if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) 293261ae650dSJack F Vogel vsi->rx_itr_setting = ixl_rx_itr; 293361ae650dSJack F Vogel /* Update the hardware if needed */ 293461ae650dSJack F Vogel if (rxr->itr != vsi->rx_itr_setting) { 293561ae650dSJack F Vogel rxr->itr = vsi->rx_itr_setting; 293661ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 293761ae650dSJack F Vogel que->me), rxr->itr); 293861ae650dSJack F Vogel } 293961ae650dSJack F Vogel } 294061ae650dSJack F Vogel rxr->bytes = 0; 294161ae650dSJack F Vogel rxr->packets = 0; 294261ae650dSJack F Vogel return; 294361ae650dSJack F Vogel } 294461ae650dSJack F Vogel 294561ae650dSJack F Vogel 294661ae650dSJack F Vogel /* 294761ae650dSJack F Vogel ** Provide a update to the queue TX 294861ae650dSJack F Vogel ** interrupt moderation value. 294961ae650dSJack F Vogel */ 295061ae650dSJack F Vogel static void 295161ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que) 295261ae650dSJack F Vogel { 295361ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 295461ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 295561ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 295661ae650dSJack F Vogel u16 tx_itr; 295761ae650dSJack F Vogel u16 tx_latency = 0; 295861ae650dSJack F Vogel int tx_bytes; 295961ae650dSJack F Vogel 296061ae650dSJack F Vogel 296161ae650dSJack F Vogel /* Idle, do nothing */ 296261ae650dSJack F Vogel if (txr->bytes == 0) 296361ae650dSJack F Vogel return; 296461ae650dSJack F Vogel 296561ae650dSJack F Vogel if (ixl_dynamic_tx_itr) { 296661ae650dSJack F Vogel tx_bytes = txr->bytes/txr->itr; 296761ae650dSJack F Vogel tx_itr = txr->itr; 296861ae650dSJack F Vogel 296961ae650dSJack F Vogel switch (txr->latency) { 297061ae650dSJack F Vogel case IXL_LOW_LATENCY: 297161ae650dSJack F Vogel if (tx_bytes > 10) { 297261ae650dSJack F Vogel tx_latency = IXL_AVE_LATENCY; 297361ae650dSJack F Vogel tx_itr = IXL_ITR_20K; 297461ae650dSJack F Vogel } 297561ae650dSJack F Vogel break; 297661ae650dSJack F Vogel case IXL_AVE_LATENCY: 297761ae650dSJack F Vogel if (tx_bytes > 20) { 297861ae650dSJack F Vogel tx_latency = IXL_BULK_LATENCY; 297961ae650dSJack F Vogel tx_itr = IXL_ITR_8K; 298061ae650dSJack F Vogel } else if (tx_bytes <= 10) { 298161ae650dSJack F Vogel tx_latency = IXL_LOW_LATENCY; 298261ae650dSJack F Vogel tx_itr = IXL_ITR_100K; 298361ae650dSJack F Vogel } 298461ae650dSJack F Vogel break; 298561ae650dSJack F Vogel case IXL_BULK_LATENCY: 298661ae650dSJack F Vogel if (tx_bytes <= 20) { 298761ae650dSJack F Vogel tx_latency = IXL_AVE_LATENCY; 298861ae650dSJack F Vogel tx_itr = IXL_ITR_20K; 298961ae650dSJack F Vogel } 299061ae650dSJack F Vogel break; 299161ae650dSJack F Vogel } 299261ae650dSJack F Vogel 299361ae650dSJack F Vogel txr->latency = tx_latency; 299461ae650dSJack F Vogel 299561ae650dSJack F Vogel if (tx_itr != txr->itr) { 299661ae650dSJack F Vogel /* do an exponential smoothing */ 299761ae650dSJack F Vogel tx_itr = (10 * tx_itr * txr->itr) / 299861ae650dSJack F Vogel ((9 * tx_itr) + txr->itr); 299961ae650dSJack F Vogel txr->itr = tx_itr & IXL_MAX_ITR; 300061ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 300161ae650dSJack F Vogel que->me), txr->itr); 300261ae650dSJack F Vogel } 300361ae650dSJack F Vogel 300461ae650dSJack F Vogel } else { /* We may have have toggled to non-dynamic */ 300561ae650dSJack F Vogel if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC) 300661ae650dSJack F Vogel vsi->tx_itr_setting = ixl_tx_itr; 300761ae650dSJack F Vogel /* Update the hardware if needed */ 300861ae650dSJack F Vogel if (txr->itr != vsi->tx_itr_setting) { 300961ae650dSJack F Vogel txr->itr = vsi->tx_itr_setting; 301061ae650dSJack F Vogel wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 301161ae650dSJack F Vogel que->me), txr->itr); 301261ae650dSJack F Vogel } 301361ae650dSJack F Vogel } 301461ae650dSJack F Vogel txr->bytes = 0; 301561ae650dSJack F Vogel txr->packets = 0; 301661ae650dSJack F Vogel return; 301761ae650dSJack F Vogel } 301861ae650dSJack F Vogel 301961ae650dSJack F Vogel 302061ae650dSJack F Vogel static void 302161ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf) 302261ae650dSJack F Vogel { 302361ae650dSJack F Vogel device_t dev = pf->dev; 302461ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 302561ae650dSJack F Vogel struct ixl_queue *queues = vsi->queues; 302661ae650dSJack F Vogel struct i40e_eth_stats *vsi_stats = &vsi->eth_stats; 302761ae650dSJack F Vogel struct i40e_hw_port_stats *pf_stats = &pf->stats; 302861ae650dSJack F Vogel 302961ae650dSJack F Vogel struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 303061ae650dSJack F Vogel struct sysctl_oid *tree = device_get_sysctl_tree(dev); 303161ae650dSJack F Vogel struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 303261ae650dSJack F Vogel 303361ae650dSJack F Vogel struct sysctl_oid *vsi_node, *queue_node; 303461ae650dSJack F Vogel struct sysctl_oid_list *vsi_list, *queue_list; 303561ae650dSJack F Vogel 303661ae650dSJack F Vogel struct tx_ring *txr; 303761ae650dSJack F Vogel struct rx_ring *rxr; 303861ae650dSJack F Vogel 303961ae650dSJack F Vogel /* Driver statistics */ 304061ae650dSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 304161ae650dSJack F Vogel CTLFLAG_RD, &pf->watchdog_events, 304261ae650dSJack F Vogel "Watchdog timeouts"); 304361ae650dSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq", 304461ae650dSJack F Vogel CTLFLAG_RD, &pf->admin_irq, 304561ae650dSJack F Vogel "Admin Queue IRQ Handled"); 304661ae650dSJack F Vogel 304761ae650dSJack F Vogel /* VSI statistics */ 304861ae650dSJack F Vogel #define QUEUE_NAME_LEN 32 304961ae650dSJack F Vogel char queue_namebuf[QUEUE_NAME_LEN]; 305061ae650dSJack F Vogel 305161ae650dSJack F Vogel // ERJ: Only one vsi now, re-do when >1 VSI enabled 305261ae650dSJack F Vogel // snprintf(vsi_namebuf, QUEUE_NAME_LEN, "vsi%d", vsi->info.stat_counter_idx); 305361ae650dSJack F Vogel vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "vsi", 305461ae650dSJack F Vogel CTLFLAG_RD, NULL, "VSI-specific stats"); 305561ae650dSJack F Vogel vsi_list = SYSCTL_CHILDREN(vsi_node); 305661ae650dSJack F Vogel 305761ae650dSJack F Vogel ixl_add_sysctls_eth_stats(ctx, vsi_list, vsi_stats); 305861ae650dSJack F Vogel 305961ae650dSJack F Vogel /* Queue statistics */ 306061ae650dSJack F Vogel for (int q = 0; q < vsi->num_queues; q++) { 306161ae650dSJack F Vogel snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); 306261ae650dSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, OID_AUTO, queue_namebuf, 306361ae650dSJack F Vogel CTLFLAG_RD, NULL, "Queue #"); 306461ae650dSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 306561ae650dSJack F Vogel 306661ae650dSJack F Vogel txr = &(queues[q].txr); 306761ae650dSJack F Vogel rxr = &(queues[q].rxr); 306861ae650dSJack F Vogel 306961ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", 307061ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), 307161ae650dSJack F Vogel "m_defrag() failed"); 307261ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped", 307361ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].dropped_pkts), 307461ae650dSJack F Vogel "Driver dropped packets"); 307561ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 307661ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].irqs), 307761ae650dSJack F Vogel "irqs on this queue"); 307861ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", 307961ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].tso), 308061ae650dSJack F Vogel "TSO"); 308161ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup", 308261ae650dSJack F Vogel CTLFLAG_RD, &(queues[q].tx_dma_setup), 308361ae650dSJack F Vogel "Driver tx dma failure in xmit"); 308461ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 308561ae650dSJack F Vogel CTLFLAG_RD, &(txr->no_desc), 308661ae650dSJack F Vogel "Queue No Descriptor Available"); 308761ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 308861ae650dSJack F Vogel CTLFLAG_RD, &(txr->total_packets), 308961ae650dSJack F Vogel "Queue Packets Transmitted"); 309061ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", 309161ae650dSJack F Vogel CTLFLAG_RD, &(txr->tx_bytes), 309261ae650dSJack F Vogel "Queue Bytes Transmitted"); 309361ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 309461ae650dSJack F Vogel CTLFLAG_RD, &(rxr->rx_packets), 309561ae650dSJack F Vogel "Queue Packets Received"); 309661ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 309761ae650dSJack F Vogel CTLFLAG_RD, &(rxr->rx_bytes), 309861ae650dSJack F Vogel "Queue Bytes Received"); 309961ae650dSJack F Vogel } 310061ae650dSJack F Vogel 310161ae650dSJack F Vogel /* MAC stats */ 310261ae650dSJack F Vogel ixl_add_sysctls_mac_stats(ctx, child, pf_stats); 310361ae650dSJack F Vogel } 310461ae650dSJack F Vogel 310561ae650dSJack F Vogel static void 310661ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx, 310761ae650dSJack F Vogel struct sysctl_oid_list *child, 310861ae650dSJack F Vogel struct i40e_eth_stats *eth_stats) 310961ae650dSJack F Vogel { 311061ae650dSJack F Vogel struct ixl_sysctl_info ctls[] = 311161ae650dSJack F Vogel { 311261ae650dSJack F Vogel {ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, 311361ae650dSJack F Vogel {ð_stats->rx_unicast, "ucast_pkts_rcvd", 311461ae650dSJack F Vogel "Unicast Packets Received"}, 311561ae650dSJack F Vogel {ð_stats->rx_multicast, "mcast_pkts_rcvd", 311661ae650dSJack F Vogel "Multicast Packets Received"}, 311761ae650dSJack F Vogel {ð_stats->rx_broadcast, "bcast_pkts_rcvd", 311861ae650dSJack F Vogel "Broadcast Packets Received"}, 311961ae650dSJack F Vogel {ð_stats->rx_discards, "rx_discards", "Discarded RX packets"}, 312061ae650dSJack F Vogel {ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, 312161ae650dSJack F Vogel {ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, 312261ae650dSJack F Vogel {ð_stats->tx_multicast, "mcast_pkts_txd", 312361ae650dSJack F Vogel "Multicast Packets Transmitted"}, 312461ae650dSJack F Vogel {ð_stats->tx_broadcast, "bcast_pkts_txd", 312561ae650dSJack F Vogel "Broadcast Packets Transmitted"}, 312661ae650dSJack F Vogel // end 312761ae650dSJack F Vogel {0,0,0} 312861ae650dSJack F Vogel }; 312961ae650dSJack F Vogel 313061ae650dSJack F Vogel struct ixl_sysctl_info *entry = ctls; 313161ae650dSJack F Vogel while (entry->stat != 0) 313261ae650dSJack F Vogel { 313361ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name, 313461ae650dSJack F Vogel CTLFLAG_RD, entry->stat, 313561ae650dSJack F Vogel entry->description); 313661ae650dSJack F Vogel entry++; 313761ae650dSJack F Vogel } 313861ae650dSJack F Vogel } 313961ae650dSJack F Vogel 314061ae650dSJack F Vogel static void 314161ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx, 314261ae650dSJack F Vogel struct sysctl_oid_list *child, 314361ae650dSJack F Vogel struct i40e_hw_port_stats *stats) 314461ae650dSJack F Vogel { 314561ae650dSJack F Vogel struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", 314661ae650dSJack F Vogel CTLFLAG_RD, NULL, "Mac Statistics"); 314761ae650dSJack F Vogel struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node); 314861ae650dSJack F Vogel 314961ae650dSJack F Vogel struct i40e_eth_stats *eth_stats = &stats->eth; 315061ae650dSJack F Vogel ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats); 315161ae650dSJack F Vogel 315261ae650dSJack F Vogel struct ixl_sysctl_info ctls[] = 315361ae650dSJack F Vogel { 315461ae650dSJack F Vogel {&stats->crc_errors, "crc_errors", "CRC Errors"}, 315561ae650dSJack F Vogel {&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"}, 315661ae650dSJack F Vogel {&stats->mac_local_faults, "local_faults", "MAC Local Faults"}, 315761ae650dSJack F Vogel {&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"}, 315861ae650dSJack F Vogel {&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"}, 315961ae650dSJack F Vogel /* Packet Reception Stats */ 316061ae650dSJack F Vogel {&stats->rx_size_64, "rx_frames_64", "64 byte frames received"}, 316161ae650dSJack F Vogel {&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"}, 316261ae650dSJack F Vogel {&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"}, 316361ae650dSJack F Vogel {&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"}, 316461ae650dSJack F Vogel {&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"}, 316561ae650dSJack F Vogel {&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"}, 316661ae650dSJack F Vogel {&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"}, 316761ae650dSJack F Vogel {&stats->rx_undersize, "rx_undersize", "Undersized packets received"}, 316861ae650dSJack F Vogel {&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"}, 316961ae650dSJack F Vogel {&stats->rx_oversize, "rx_oversized", "Oversized packets received"}, 317061ae650dSJack F Vogel {&stats->rx_jabber, "rx_jabber", "Received Jabber"}, 317161ae650dSJack F Vogel {&stats->checksum_error, "checksum_errors", "Checksum Errors"}, 317261ae650dSJack F Vogel /* Packet Transmission Stats */ 317361ae650dSJack F Vogel {&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"}, 317461ae650dSJack F Vogel {&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"}, 317561ae650dSJack F Vogel {&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"}, 317661ae650dSJack F Vogel {&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"}, 317761ae650dSJack F Vogel {&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"}, 317861ae650dSJack F Vogel {&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"}, 317961ae650dSJack F Vogel {&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"}, 318061ae650dSJack F Vogel /* Flow control */ 318161ae650dSJack F Vogel {&stats->link_xon_tx, "xon_txd", "Link XON transmitted"}, 318261ae650dSJack F Vogel {&stats->link_xon_rx, "xon_recvd", "Link XON received"}, 318361ae650dSJack F Vogel {&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"}, 318461ae650dSJack F Vogel {&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"}, 318561ae650dSJack F Vogel /* End */ 318661ae650dSJack F Vogel {0,0,0} 318761ae650dSJack F Vogel }; 318861ae650dSJack F Vogel 318961ae650dSJack F Vogel struct ixl_sysctl_info *entry = ctls; 319061ae650dSJack F Vogel while (entry->stat != 0) 319161ae650dSJack F Vogel { 319261ae650dSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name, 319361ae650dSJack F Vogel CTLFLAG_RD, entry->stat, 319461ae650dSJack F Vogel entry->description); 319561ae650dSJack F Vogel entry++; 319661ae650dSJack F Vogel } 319761ae650dSJack F Vogel } 319861ae650dSJack F Vogel 319961ae650dSJack F Vogel /* 320061ae650dSJack F Vogel ** ixl_config_rss - setup RSS 320161ae650dSJack F Vogel ** - note this is done for the single vsi 320261ae650dSJack F Vogel */ 320361ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *vsi) 320461ae650dSJack F Vogel { 320561ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 320661ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 320761ae650dSJack F Vogel u32 lut = 0; 3208393c4bb1SJack F Vogel u64 set_hena = 0, hena; 3209393c4bb1SJack F Vogel int i, j, que_id; 3210393c4bb1SJack F Vogel #ifdef RSS 3211393c4bb1SJack F Vogel u32 rss_hash_config; 3212393c4bb1SJack F Vogel u32 rss_seed[IXL_KEYSZ]; 3213393c4bb1SJack F Vogel #else 3214393c4bb1SJack F Vogel u32 rss_seed[IXL_KEYSZ] = {0x41b01687, 3215393c4bb1SJack F Vogel 0x183cfd8c, 0xce880440, 0x580cbc3c, 3216393c4bb1SJack F Vogel 0x35897377, 0x328b25e1, 0x4fa98922, 3217393c4bb1SJack F Vogel 0xb7d90c14, 0xd5bad70d, 0xcd15a2c1}; 3218393c4bb1SJack F Vogel #endif 321961ae650dSJack F Vogel 3220393c4bb1SJack F Vogel #ifdef RSS 3221393c4bb1SJack F Vogel /* Fetch the configured RSS key */ 3222393c4bb1SJack F Vogel rss_getkey((uint8_t *) &rss_seed); 3223393c4bb1SJack F Vogel #endif 322461ae650dSJack F Vogel 322561ae650dSJack F Vogel /* Fill out hash function seed */ 3226393c4bb1SJack F Vogel for (i = 0; i < IXL_KEYSZ; i++) 3227393c4bb1SJack F Vogel wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]); 322861ae650dSJack F Vogel 322961ae650dSJack F Vogel /* Enable PCTYPES for RSS: */ 3230393c4bb1SJack F Vogel #ifdef RSS 3231393c4bb1SJack F Vogel rss_hash_config = rss_gethashconfig(); 3232393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 3233393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); 3234393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 3235393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); 3236393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 3237393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP); 3238393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 3239393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); 3240df1d7a71SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 3241df1d7a71SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); 3242393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 3243393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); 3244393c4bb1SJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 3245393c4bb1SJack F Vogel set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP); 3246393c4bb1SJack F Vogel #else 324761ae650dSJack F Vogel set_hena = 324861ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | 324961ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | 325061ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | 325161ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | 325261ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | 325361ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | 325461ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | 325561ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | 325661ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | 325761ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | 325861ae650dSJack F Vogel ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD); 3259393c4bb1SJack F Vogel #endif 326061ae650dSJack F Vogel hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) | 326161ae650dSJack F Vogel ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32); 326261ae650dSJack F Vogel hena |= set_hena; 326361ae650dSJack F Vogel wr32(hw, I40E_PFQF_HENA(0), (u32)hena); 326461ae650dSJack F Vogel wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); 326561ae650dSJack F Vogel 326661ae650dSJack F Vogel /* Populate the LUT with max no. of queues in round robin fashion */ 326761ae650dSJack F Vogel for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) { 326861ae650dSJack F Vogel if (j == vsi->num_queues) 326961ae650dSJack F Vogel j = 0; 3270393c4bb1SJack F Vogel #ifdef RSS 3271393c4bb1SJack F Vogel /* 3272393c4bb1SJack F Vogel * Fetch the RSS bucket id for the given indirection entry. 3273393c4bb1SJack F Vogel * Cap it at the number of configured buckets (which is 3274393c4bb1SJack F Vogel * num_queues.) 3275393c4bb1SJack F Vogel */ 3276393c4bb1SJack F Vogel que_id = rss_get_indirection_to_bucket(i); 3277dcd7b3b2SJack F Vogel que_id = que_id % vsi->num_queues; 3278393c4bb1SJack F Vogel #else 3279393c4bb1SJack F Vogel que_id = j; 3280393c4bb1SJack F Vogel #endif 328161ae650dSJack F Vogel /* lut = 4-byte sliding window of 4 lut entries */ 3282393c4bb1SJack F Vogel lut = (lut << 8) | (que_id & 328361ae650dSJack F Vogel ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1)); 328461ae650dSJack F Vogel /* On i = 3, we have 4 entries in lut; write to the register */ 328561ae650dSJack F Vogel if ((i & 3) == 3) 328661ae650dSJack F Vogel wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); 328761ae650dSJack F Vogel } 328861ae650dSJack F Vogel ixl_flush(hw); 328961ae650dSJack F Vogel } 329061ae650dSJack F Vogel 329161ae650dSJack F Vogel 329261ae650dSJack F Vogel /* 329361ae650dSJack F Vogel ** This routine is run via an vlan config EVENT, 329461ae650dSJack F Vogel ** it enables us to use the HW Filter table since 329561ae650dSJack F Vogel ** we can get the vlan id. This just creates the 329661ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will 329761ae650dSJack F Vogel ** repopulate the real table. 329861ae650dSJack F Vogel */ 329961ae650dSJack F Vogel static void 330061ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 330161ae650dSJack F Vogel { 330261ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 330361ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 330461ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 330561ae650dSJack F Vogel 330661ae650dSJack F Vogel if (ifp->if_softc != arg) /* Not our event */ 330761ae650dSJack F Vogel return; 330861ae650dSJack F Vogel 330961ae650dSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 331061ae650dSJack F Vogel return; 331161ae650dSJack F Vogel 331261ae650dSJack F Vogel IXL_PF_LOCK(pf); 331361ae650dSJack F Vogel ++vsi->num_vlans; 331461ae650dSJack F Vogel ixl_add_filter(vsi, hw->mac.addr, vtag); 331561ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 331661ae650dSJack F Vogel } 331761ae650dSJack F Vogel 331861ae650dSJack F Vogel /* 331961ae650dSJack F Vogel ** This routine is run via an vlan 332061ae650dSJack F Vogel ** unconfig EVENT, remove our entry 332161ae650dSJack F Vogel ** in the soft vfta. 332261ae650dSJack F Vogel */ 332361ae650dSJack F Vogel static void 332461ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 332561ae650dSJack F Vogel { 332661ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 332761ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 332861ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 332961ae650dSJack F Vogel 333061ae650dSJack F Vogel if (ifp->if_softc != arg) 333161ae650dSJack F Vogel return; 333261ae650dSJack F Vogel 333361ae650dSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 333461ae650dSJack F Vogel return; 333561ae650dSJack F Vogel 333661ae650dSJack F Vogel IXL_PF_LOCK(pf); 333761ae650dSJack F Vogel --vsi->num_vlans; 333861ae650dSJack F Vogel ixl_del_filter(vsi, hw->mac.addr, vtag); 333961ae650dSJack F Vogel IXL_PF_UNLOCK(pf); 334061ae650dSJack F Vogel } 334161ae650dSJack F Vogel 334261ae650dSJack F Vogel /* 334361ae650dSJack F Vogel ** This routine updates vlan filters, called by init 334461ae650dSJack F Vogel ** it scans the filter table and then updates the hw 334561ae650dSJack F Vogel ** after a soft reset. 334661ae650dSJack F Vogel */ 334761ae650dSJack F Vogel static void 334861ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi) 334961ae650dSJack F Vogel { 335061ae650dSJack F Vogel struct ixl_mac_filter *f; 335161ae650dSJack F Vogel int cnt = 0, flags; 335261ae650dSJack F Vogel 335361ae650dSJack F Vogel if (vsi->num_vlans == 0) 335461ae650dSJack F Vogel return; 335561ae650dSJack F Vogel /* 335661ae650dSJack F Vogel ** Scan the filter list for vlan entries, 335761ae650dSJack F Vogel ** mark them for addition and then call 335861ae650dSJack F Vogel ** for the AQ update. 335961ae650dSJack F Vogel */ 336061ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 336161ae650dSJack F Vogel if (f->flags & IXL_FILTER_VLAN) { 336261ae650dSJack F Vogel f->flags |= 336361ae650dSJack F Vogel (IXL_FILTER_ADD | 336461ae650dSJack F Vogel IXL_FILTER_USED); 336561ae650dSJack F Vogel cnt++; 336661ae650dSJack F Vogel } 336761ae650dSJack F Vogel } 336861ae650dSJack F Vogel if (cnt == 0) { 336961ae650dSJack F Vogel printf("setup vlan: no filters found!\n"); 337061ae650dSJack F Vogel return; 337161ae650dSJack F Vogel } 337261ae650dSJack F Vogel flags = IXL_FILTER_VLAN; 337361ae650dSJack F Vogel flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 337461ae650dSJack F Vogel ixl_add_hw_filters(vsi, flags, cnt); 337561ae650dSJack F Vogel return; 337661ae650dSJack F Vogel } 337761ae650dSJack F Vogel 337861ae650dSJack F Vogel /* 337961ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware 338061ae650dSJack F Vogel ** needs to know about. 338161ae650dSJack F Vogel */ 338261ae650dSJack F Vogel static void 338361ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi) 338461ae650dSJack F Vogel { 338561ae650dSJack F Vogel /* Add broadcast address */ 338661ae650dSJack F Vogel u8 bc[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 338761ae650dSJack F Vogel ixl_add_filter(vsi, bc, IXL_VLAN_ANY); 338861ae650dSJack F Vogel } 338961ae650dSJack F Vogel 339061ae650dSJack F Vogel /* 339161ae650dSJack F Vogel ** This routine adds mulicast filters 339261ae650dSJack F Vogel */ 339361ae650dSJack F Vogel static void 339461ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr) 339561ae650dSJack F Vogel { 339661ae650dSJack F Vogel struct ixl_mac_filter *f; 339761ae650dSJack F Vogel 339861ae650dSJack F Vogel /* Does one already exist */ 339961ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 340061ae650dSJack F Vogel if (f != NULL) 340161ae650dSJack F Vogel return; 340261ae650dSJack F Vogel 340361ae650dSJack F Vogel f = ixl_get_filter(vsi); 340461ae650dSJack F Vogel if (f == NULL) { 340561ae650dSJack F Vogel printf("WARNING: no filter available!!\n"); 340661ae650dSJack F Vogel return; 340761ae650dSJack F Vogel } 340861ae650dSJack F Vogel bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 340961ae650dSJack F Vogel f->vlan = IXL_VLAN_ANY; 341061ae650dSJack F Vogel f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED 341161ae650dSJack F Vogel | IXL_FILTER_MC); 341261ae650dSJack F Vogel 341361ae650dSJack F Vogel return; 341461ae650dSJack F Vogel } 341561ae650dSJack F Vogel 341661ae650dSJack F Vogel /* 341761ae650dSJack F Vogel ** This routine adds macvlan filters 341861ae650dSJack F Vogel */ 341961ae650dSJack F Vogel static void 342061ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 342161ae650dSJack F Vogel { 342261ae650dSJack F Vogel struct ixl_mac_filter *f, *tmp; 342361ae650dSJack F Vogel device_t dev = vsi->dev; 342461ae650dSJack F Vogel 342561ae650dSJack F Vogel DEBUGOUT("ixl_add_filter: begin"); 342661ae650dSJack F Vogel 342761ae650dSJack F Vogel /* Does one already exist */ 342861ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, vlan); 342961ae650dSJack F Vogel if (f != NULL) 343061ae650dSJack F Vogel return; 343161ae650dSJack F Vogel /* 343261ae650dSJack F Vogel ** Is this the first vlan being registered, if so we 343361ae650dSJack F Vogel ** need to remove the ANY filter that indicates we are 343461ae650dSJack F Vogel ** not in a vlan, and replace that with a 0 filter. 343561ae650dSJack F Vogel */ 343661ae650dSJack F Vogel if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) { 343761ae650dSJack F Vogel tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 343861ae650dSJack F Vogel if (tmp != NULL) { 343961ae650dSJack F Vogel ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY); 344061ae650dSJack F Vogel ixl_add_filter(vsi, macaddr, 0); 344161ae650dSJack F Vogel } 344261ae650dSJack F Vogel } 344361ae650dSJack F Vogel 344461ae650dSJack F Vogel f = ixl_get_filter(vsi); 344561ae650dSJack F Vogel if (f == NULL) { 344661ae650dSJack F Vogel device_printf(dev, "WARNING: no filter available!!\n"); 344761ae650dSJack F Vogel return; 344861ae650dSJack F Vogel } 344961ae650dSJack F Vogel bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 345061ae650dSJack F Vogel f->vlan = vlan; 345161ae650dSJack F Vogel f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 345261ae650dSJack F Vogel if (f->vlan != IXL_VLAN_ANY) 345361ae650dSJack F Vogel f->flags |= IXL_FILTER_VLAN; 345461ae650dSJack F Vogel 345561ae650dSJack F Vogel ixl_add_hw_filters(vsi, f->flags, 1); 345661ae650dSJack F Vogel return; 345761ae650dSJack F Vogel } 345861ae650dSJack F Vogel 345961ae650dSJack F Vogel static void 346061ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 346161ae650dSJack F Vogel { 346261ae650dSJack F Vogel struct ixl_mac_filter *f; 346361ae650dSJack F Vogel 346461ae650dSJack F Vogel f = ixl_find_filter(vsi, macaddr, vlan); 346561ae650dSJack F Vogel if (f == NULL) 346661ae650dSJack F Vogel return; 346761ae650dSJack F Vogel 346861ae650dSJack F Vogel f->flags |= IXL_FILTER_DEL; 346961ae650dSJack F Vogel ixl_del_hw_filters(vsi, 1); 347061ae650dSJack F Vogel 347161ae650dSJack F Vogel /* Check if this is the last vlan removal */ 347261ae650dSJack F Vogel if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) { 347361ae650dSJack F Vogel /* Switch back to a non-vlan filter */ 347461ae650dSJack F Vogel ixl_del_filter(vsi, macaddr, 0); 347561ae650dSJack F Vogel ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY); 347661ae650dSJack F Vogel } 347761ae650dSJack F Vogel return; 347861ae650dSJack F Vogel } 347961ae650dSJack F Vogel 348061ae650dSJack F Vogel /* 348161ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id 348261ae650dSJack F Vogel */ 348361ae650dSJack F Vogel static struct ixl_mac_filter * 348461ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 348561ae650dSJack F Vogel { 348661ae650dSJack F Vogel struct ixl_mac_filter *f; 348761ae650dSJack F Vogel bool match = FALSE; 348861ae650dSJack F Vogel 348961ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 349061ae650dSJack F Vogel if (!cmp_etheraddr(f->macaddr, macaddr)) 349161ae650dSJack F Vogel continue; 349261ae650dSJack F Vogel if (f->vlan == vlan) { 349361ae650dSJack F Vogel match = TRUE; 349461ae650dSJack F Vogel break; 349561ae650dSJack F Vogel } 349661ae650dSJack F Vogel } 349761ae650dSJack F Vogel 349861ae650dSJack F Vogel if (!match) 349961ae650dSJack F Vogel f = NULL; 350061ae650dSJack F Vogel return (f); 350161ae650dSJack F Vogel } 350261ae650dSJack F Vogel 350361ae650dSJack F Vogel /* 350461ae650dSJack F Vogel ** This routine takes additions to the vsi filter 350561ae650dSJack F Vogel ** table and creates an Admin Queue call to create 350661ae650dSJack F Vogel ** the filters in the hardware. 350761ae650dSJack F Vogel */ 350861ae650dSJack F Vogel static void 350961ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt) 351061ae650dSJack F Vogel { 351161ae650dSJack F Vogel struct i40e_aqc_add_macvlan_element_data *a, *b; 351261ae650dSJack F Vogel struct ixl_mac_filter *f; 351361ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 351461ae650dSJack F Vogel device_t dev = vsi->dev; 351561ae650dSJack F Vogel int err, j = 0; 351661ae650dSJack F Vogel 351761ae650dSJack F Vogel a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt, 351861ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 351961ae650dSJack F Vogel if (a == NULL) { 3520393c4bb1SJack F Vogel device_printf(dev, "add_hw_filters failed to get memory\n"); 352161ae650dSJack F Vogel return; 352261ae650dSJack F Vogel } 352361ae650dSJack F Vogel 352461ae650dSJack F Vogel /* 352561ae650dSJack F Vogel ** Scan the filter list, each time we find one 352661ae650dSJack F Vogel ** we add it to the admin queue array and turn off 352761ae650dSJack F Vogel ** the add bit. 352861ae650dSJack F Vogel */ 352961ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 353061ae650dSJack F Vogel if (f->flags == flags) { 353161ae650dSJack F Vogel b = &a[j]; // a pox on fvl long names :) 353261ae650dSJack F Vogel bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN); 353361ae650dSJack F Vogel b->vlan_tag = 353461ae650dSJack F Vogel (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan); 353561ae650dSJack F Vogel b->flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH; 353661ae650dSJack F Vogel f->flags &= ~IXL_FILTER_ADD; 353761ae650dSJack F Vogel j++; 353861ae650dSJack F Vogel } 353961ae650dSJack F Vogel if (j == cnt) 354061ae650dSJack F Vogel break; 354161ae650dSJack F Vogel } 354261ae650dSJack F Vogel if (j > 0) { 354361ae650dSJack F Vogel err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); 354461ae650dSJack F Vogel if (err) 3545b6c8f260SJack F Vogel device_printf(dev, "aq_add_macvlan err %d, " 3546b6c8f260SJack F Vogel "aq_error %d\n", err, hw->aq.asq_last_status); 354761ae650dSJack F Vogel else 354861ae650dSJack F Vogel vsi->hw_filters_add += j; 354961ae650dSJack F Vogel } 355061ae650dSJack F Vogel free(a, M_DEVBUF); 355161ae650dSJack F Vogel return; 355261ae650dSJack F Vogel } 355361ae650dSJack F Vogel 355461ae650dSJack F Vogel /* 355561ae650dSJack F Vogel ** This routine takes removals in the vsi filter 355661ae650dSJack F Vogel ** table and creates an Admin Queue call to delete 355761ae650dSJack F Vogel ** the filters in the hardware. 355861ae650dSJack F Vogel */ 355961ae650dSJack F Vogel static void 356061ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt) 356161ae650dSJack F Vogel { 356261ae650dSJack F Vogel struct i40e_aqc_remove_macvlan_element_data *d, *e; 356361ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 356461ae650dSJack F Vogel device_t dev = vsi->dev; 356561ae650dSJack F Vogel struct ixl_mac_filter *f, *f_temp; 356661ae650dSJack F Vogel int err, j = 0; 356761ae650dSJack F Vogel 356861ae650dSJack F Vogel DEBUGOUT("ixl_del_hw_filters: begin\n"); 356961ae650dSJack F Vogel 357061ae650dSJack F Vogel d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt, 357161ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 357261ae650dSJack F Vogel if (d == NULL) { 357361ae650dSJack F Vogel printf("del hw filter failed to get memory\n"); 357461ae650dSJack F Vogel return; 357561ae650dSJack F Vogel } 357661ae650dSJack F Vogel 357761ae650dSJack F Vogel SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) { 357861ae650dSJack F Vogel if (f->flags & IXL_FILTER_DEL) { 357961ae650dSJack F Vogel e = &d[j]; // a pox on fvl long names :) 358061ae650dSJack F Vogel bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN); 358161ae650dSJack F Vogel e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan); 358261ae650dSJack F Vogel e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; 358361ae650dSJack F Vogel /* delete entry from vsi list */ 358461ae650dSJack F Vogel SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next); 358561ae650dSJack F Vogel free(f, M_DEVBUF); 358661ae650dSJack F Vogel j++; 358761ae650dSJack F Vogel } 358861ae650dSJack F Vogel if (j == cnt) 358961ae650dSJack F Vogel break; 359061ae650dSJack F Vogel } 359161ae650dSJack F Vogel if (j > 0) { 359261ae650dSJack F Vogel err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); 359361ae650dSJack F Vogel /* NOTE: returns ENOENT every time but seems to work fine, 359461ae650dSJack F Vogel so we'll ignore that specific error. */ 3595393c4bb1SJack F Vogel // TODO: Does this still occur on current firmwares? 359661ae650dSJack F Vogel if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { 359761ae650dSJack F Vogel int sc = 0; 359861ae650dSJack F Vogel for (int i = 0; i < j; i++) 359961ae650dSJack F Vogel sc += (!d[i].error_code); 360061ae650dSJack F Vogel vsi->hw_filters_del += sc; 360161ae650dSJack F Vogel device_printf(dev, 360261ae650dSJack F Vogel "Failed to remove %d/%d filters, aq error %d\n", 360361ae650dSJack F Vogel j - sc, j, hw->aq.asq_last_status); 360461ae650dSJack F Vogel } else 360561ae650dSJack F Vogel vsi->hw_filters_del += j; 360661ae650dSJack F Vogel } 360761ae650dSJack F Vogel free(d, M_DEVBUF); 360861ae650dSJack F Vogel 360961ae650dSJack F Vogel DEBUGOUT("ixl_del_hw_filters: end\n"); 361061ae650dSJack F Vogel return; 361161ae650dSJack F Vogel } 361261ae650dSJack F Vogel 361361ae650dSJack F Vogel 361461ae650dSJack F Vogel static void 361561ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi) 361661ae650dSJack F Vogel { 361761ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 361861ae650dSJack F Vogel u32 reg; 361961ae650dSJack F Vogel 362061ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 362161ae650dSJack F Vogel i40e_pre_tx_queue_cfg(hw, i, TRUE); 362261ae650dSJack F Vogel 362361ae650dSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(i)); 362461ae650dSJack F Vogel reg |= I40E_QTX_ENA_QENA_REQ_MASK | 362561ae650dSJack F Vogel I40E_QTX_ENA_QENA_STAT_MASK; 362661ae650dSJack F Vogel wr32(hw, I40E_QTX_ENA(i), reg); 362761ae650dSJack F Vogel /* Verify the enable took */ 362861ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 362961ae650dSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(i)); 363061ae650dSJack F Vogel if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 363161ae650dSJack F Vogel break; 363261ae650dSJack F Vogel i40e_msec_delay(10); 363361ae650dSJack F Vogel } 363461ae650dSJack F Vogel if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) 363561ae650dSJack F Vogel printf("TX queue %d disabled!\n", i); 363661ae650dSJack F Vogel 363761ae650dSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(i)); 363861ae650dSJack F Vogel reg |= I40E_QRX_ENA_QENA_REQ_MASK | 363961ae650dSJack F Vogel I40E_QRX_ENA_QENA_STAT_MASK; 364061ae650dSJack F Vogel wr32(hw, I40E_QRX_ENA(i), reg); 364161ae650dSJack F Vogel /* Verify the enable took */ 364261ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 364361ae650dSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(i)); 364461ae650dSJack F Vogel if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 364561ae650dSJack F Vogel break; 364661ae650dSJack F Vogel i40e_msec_delay(10); 364761ae650dSJack F Vogel } 364861ae650dSJack F Vogel if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) 364961ae650dSJack F Vogel printf("RX queue %d disabled!\n", i); 365061ae650dSJack F Vogel } 365161ae650dSJack F Vogel } 365261ae650dSJack F Vogel 365361ae650dSJack F Vogel static void 365461ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi) 365561ae650dSJack F Vogel { 365661ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 365761ae650dSJack F Vogel u32 reg; 365861ae650dSJack F Vogel 365961ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 366061ae650dSJack F Vogel i40e_pre_tx_queue_cfg(hw, i, FALSE); 366161ae650dSJack F Vogel i40e_usec_delay(500); 366261ae650dSJack F Vogel 366361ae650dSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(i)); 366461ae650dSJack F Vogel reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; 366561ae650dSJack F Vogel wr32(hw, I40E_QTX_ENA(i), reg); 366661ae650dSJack F Vogel /* Verify the disable took */ 366761ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 366861ae650dSJack F Vogel reg = rd32(hw, I40E_QTX_ENA(i)); 366961ae650dSJack F Vogel if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK)) 367061ae650dSJack F Vogel break; 367161ae650dSJack F Vogel i40e_msec_delay(10); 367261ae650dSJack F Vogel } 367361ae650dSJack F Vogel if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 367461ae650dSJack F Vogel printf("TX queue %d still enabled!\n", i); 367561ae650dSJack F Vogel 367661ae650dSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(i)); 367761ae650dSJack F Vogel reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; 367861ae650dSJack F Vogel wr32(hw, I40E_QRX_ENA(i), reg); 367961ae650dSJack F Vogel /* Verify the disable took */ 368061ae650dSJack F Vogel for (int j = 0; j < 10; j++) { 368161ae650dSJack F Vogel reg = rd32(hw, I40E_QRX_ENA(i)); 368261ae650dSJack F Vogel if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK)) 368361ae650dSJack F Vogel break; 368461ae650dSJack F Vogel i40e_msec_delay(10); 368561ae650dSJack F Vogel } 368661ae650dSJack F Vogel if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 368761ae650dSJack F Vogel printf("RX queue %d still enabled!\n", i); 368861ae650dSJack F Vogel } 368961ae650dSJack F Vogel } 369061ae650dSJack F Vogel 369161ae650dSJack F Vogel /** 369261ae650dSJack F Vogel * ixl_handle_mdd_event 369361ae650dSJack F Vogel * 369461ae650dSJack F Vogel * Called from interrupt handler to identify possibly malicious vfs 369561ae650dSJack F Vogel * (But also detects events from the PF, as well) 369661ae650dSJack F Vogel **/ 369761ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *pf) 369861ae650dSJack F Vogel { 369961ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 370061ae650dSJack F Vogel device_t dev = pf->dev; 370161ae650dSJack F Vogel bool mdd_detected = false; 370261ae650dSJack F Vogel bool pf_mdd_detected = false; 370361ae650dSJack F Vogel u32 reg; 370461ae650dSJack F Vogel 370561ae650dSJack F Vogel /* find what triggered the MDD event */ 370661ae650dSJack F Vogel reg = rd32(hw, I40E_GL_MDET_TX); 370761ae650dSJack F Vogel if (reg & I40E_GL_MDET_TX_VALID_MASK) { 370861ae650dSJack F Vogel u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >> 370961ae650dSJack F Vogel I40E_GL_MDET_TX_PF_NUM_SHIFT; 371061ae650dSJack F Vogel u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >> 371161ae650dSJack F Vogel I40E_GL_MDET_TX_EVENT_SHIFT; 371261ae650dSJack F Vogel u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >> 371361ae650dSJack F Vogel I40E_GL_MDET_TX_QUEUE_SHIFT; 371461ae650dSJack F Vogel device_printf(dev, 371561ae650dSJack F Vogel "Malicious Driver Detection event 0x%02x" 371661ae650dSJack F Vogel " on TX queue %d pf number 0x%02x\n", 371761ae650dSJack F Vogel event, queue, pf_num); 371861ae650dSJack F Vogel wr32(hw, I40E_GL_MDET_TX, 0xffffffff); 371961ae650dSJack F Vogel mdd_detected = true; 372061ae650dSJack F Vogel } 372161ae650dSJack F Vogel reg = rd32(hw, I40E_GL_MDET_RX); 372261ae650dSJack F Vogel if (reg & I40E_GL_MDET_RX_VALID_MASK) { 372361ae650dSJack F Vogel u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >> 372461ae650dSJack F Vogel I40E_GL_MDET_RX_FUNCTION_SHIFT; 372561ae650dSJack F Vogel u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >> 372661ae650dSJack F Vogel I40E_GL_MDET_RX_EVENT_SHIFT; 372761ae650dSJack F Vogel u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >> 372861ae650dSJack F Vogel I40E_GL_MDET_RX_QUEUE_SHIFT; 372961ae650dSJack F Vogel device_printf(dev, 373061ae650dSJack F Vogel "Malicious Driver Detection event 0x%02x" 373161ae650dSJack F Vogel " on RX queue %d of function 0x%02x\n", 373261ae650dSJack F Vogel event, queue, func); 373361ae650dSJack F Vogel wr32(hw, I40E_GL_MDET_RX, 0xffffffff); 373461ae650dSJack F Vogel mdd_detected = true; 373561ae650dSJack F Vogel } 373661ae650dSJack F Vogel 373761ae650dSJack F Vogel if (mdd_detected) { 373861ae650dSJack F Vogel reg = rd32(hw, I40E_PF_MDET_TX); 373961ae650dSJack F Vogel if (reg & I40E_PF_MDET_TX_VALID_MASK) { 374061ae650dSJack F Vogel wr32(hw, I40E_PF_MDET_TX, 0xFFFF); 374161ae650dSJack F Vogel device_printf(dev, 374261ae650dSJack F Vogel "MDD TX event is for this function 0x%08x", 374361ae650dSJack F Vogel reg); 374461ae650dSJack F Vogel pf_mdd_detected = true; 374561ae650dSJack F Vogel } 374661ae650dSJack F Vogel reg = rd32(hw, I40E_PF_MDET_RX); 374761ae650dSJack F Vogel if (reg & I40E_PF_MDET_RX_VALID_MASK) { 374861ae650dSJack F Vogel wr32(hw, I40E_PF_MDET_RX, 0xFFFF); 374961ae650dSJack F Vogel device_printf(dev, 375061ae650dSJack F Vogel "MDD RX event is for this function 0x%08x", 375161ae650dSJack F Vogel reg); 375261ae650dSJack F Vogel pf_mdd_detected = true; 375361ae650dSJack F Vogel } 375461ae650dSJack F Vogel } 375561ae650dSJack F Vogel 375661ae650dSJack F Vogel /* re-enable mdd interrupt cause */ 375761ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0_ENA); 375861ae650dSJack F Vogel reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 375961ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 376061ae650dSJack F Vogel ixl_flush(hw); 376161ae650dSJack F Vogel } 376261ae650dSJack F Vogel 376361ae650dSJack F Vogel static void 376461ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi) 376561ae650dSJack F Vogel { 376661ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 376761ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 376861ae650dSJack F Vogel 376961ae650dSJack F Vogel if (ixl_enable_msix) { 377061ae650dSJack F Vogel ixl_enable_adminq(hw); 377161ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) 377261ae650dSJack F Vogel ixl_enable_queue(hw, que->me); 377361ae650dSJack F Vogel } else 377461ae650dSJack F Vogel ixl_enable_legacy(hw); 377561ae650dSJack F Vogel } 377661ae650dSJack F Vogel 377761ae650dSJack F Vogel static void 377861ae650dSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi) 377961ae650dSJack F Vogel { 378061ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 378161ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 378261ae650dSJack F Vogel 378361ae650dSJack F Vogel if (ixl_enable_msix) { 378461ae650dSJack F Vogel ixl_disable_adminq(hw); 378561ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++, que++) 378661ae650dSJack F Vogel ixl_disable_queue(hw, que->me); 378761ae650dSJack F Vogel } else 378861ae650dSJack F Vogel ixl_disable_legacy(hw); 378961ae650dSJack F Vogel } 379061ae650dSJack F Vogel 379161ae650dSJack F Vogel static void 379261ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw) 379361ae650dSJack F Vogel { 379461ae650dSJack F Vogel u32 reg; 379561ae650dSJack F Vogel 379661ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 379761ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 379861ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 379961ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 380061ae650dSJack F Vogel ixl_flush(hw); 380161ae650dSJack F Vogel return; 380261ae650dSJack F Vogel } 380361ae650dSJack F Vogel 380461ae650dSJack F Vogel static void 380561ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw) 380661ae650dSJack F Vogel { 380761ae650dSJack F Vogel u32 reg; 380861ae650dSJack F Vogel 380961ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 381061ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 381161ae650dSJack F Vogel 381261ae650dSJack F Vogel return; 381361ae650dSJack F Vogel } 381461ae650dSJack F Vogel 381561ae650dSJack F Vogel static void 381661ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id) 381761ae650dSJack F Vogel { 381861ae650dSJack F Vogel u32 reg; 381961ae650dSJack F Vogel 382061ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTLN_INTENA_MASK | 382161ae650dSJack F Vogel I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | 382261ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); 382361ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 382461ae650dSJack F Vogel } 382561ae650dSJack F Vogel 382661ae650dSJack F Vogel static void 382761ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id) 382861ae650dSJack F Vogel { 382961ae650dSJack F Vogel u32 reg; 383061ae650dSJack F Vogel 383161ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; 383261ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 383361ae650dSJack F Vogel 383461ae650dSJack F Vogel return; 383561ae650dSJack F Vogel } 383661ae650dSJack F Vogel 383761ae650dSJack F Vogel static void 383861ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw) 383961ae650dSJack F Vogel { 384061ae650dSJack F Vogel u32 reg; 384161ae650dSJack F Vogel reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 384261ae650dSJack F Vogel I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 384361ae650dSJack F Vogel (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 384461ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 384561ae650dSJack F Vogel } 384661ae650dSJack F Vogel 384761ae650dSJack F Vogel static void 384861ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw) 384961ae650dSJack F Vogel { 385061ae650dSJack F Vogel u32 reg; 385161ae650dSJack F Vogel 385261ae650dSJack F Vogel reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 385361ae650dSJack F Vogel wr32(hw, I40E_PFINT_DYN_CTL0, reg); 385461ae650dSJack F Vogel 385561ae650dSJack F Vogel return; 385661ae650dSJack F Vogel } 385761ae650dSJack F Vogel 385861ae650dSJack F Vogel static void 385961ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf) 386061ae650dSJack F Vogel { 386161ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 386261ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 386361ae650dSJack F Vogel 386461ae650dSJack F Vogel struct i40e_hw_port_stats *nsd = &pf->stats; 386561ae650dSJack F Vogel struct i40e_hw_port_stats *osd = &pf->stats_offsets; 386661ae650dSJack F Vogel 386761ae650dSJack F Vogel /* Update hw stats */ 386861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port), 386961ae650dSJack F Vogel pf->stat_offsets_loaded, 387061ae650dSJack F Vogel &osd->crc_errors, &nsd->crc_errors); 387161ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port), 387261ae650dSJack F Vogel pf->stat_offsets_loaded, 387361ae650dSJack F Vogel &osd->illegal_bytes, &nsd->illegal_bytes); 387461ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port), 387561ae650dSJack F Vogel I40E_GLPRT_GORCL(hw->port), 387661ae650dSJack F Vogel pf->stat_offsets_loaded, 387761ae650dSJack F Vogel &osd->eth.rx_bytes, &nsd->eth.rx_bytes); 387861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port), 387961ae650dSJack F Vogel I40E_GLPRT_GOTCL(hw->port), 388061ae650dSJack F Vogel pf->stat_offsets_loaded, 388161ae650dSJack F Vogel &osd->eth.tx_bytes, &nsd->eth.tx_bytes); 388261ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port), 388361ae650dSJack F Vogel pf->stat_offsets_loaded, 388461ae650dSJack F Vogel &osd->eth.rx_discards, 388561ae650dSJack F Vogel &nsd->eth.rx_discards); 388661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port), 388761ae650dSJack F Vogel I40E_GLPRT_UPRCL(hw->port), 388861ae650dSJack F Vogel pf->stat_offsets_loaded, 388961ae650dSJack F Vogel &osd->eth.rx_unicast, 389061ae650dSJack F Vogel &nsd->eth.rx_unicast); 389161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port), 389261ae650dSJack F Vogel I40E_GLPRT_UPTCL(hw->port), 389361ae650dSJack F Vogel pf->stat_offsets_loaded, 389461ae650dSJack F Vogel &osd->eth.tx_unicast, 389561ae650dSJack F Vogel &nsd->eth.tx_unicast); 389661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port), 389761ae650dSJack F Vogel I40E_GLPRT_MPRCL(hw->port), 389861ae650dSJack F Vogel pf->stat_offsets_loaded, 389961ae650dSJack F Vogel &osd->eth.rx_multicast, 390061ae650dSJack F Vogel &nsd->eth.rx_multicast); 390161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port), 390261ae650dSJack F Vogel I40E_GLPRT_MPTCL(hw->port), 390361ae650dSJack F Vogel pf->stat_offsets_loaded, 390461ae650dSJack F Vogel &osd->eth.tx_multicast, 390561ae650dSJack F Vogel &nsd->eth.tx_multicast); 390661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port), 390761ae650dSJack F Vogel I40E_GLPRT_BPRCL(hw->port), 390861ae650dSJack F Vogel pf->stat_offsets_loaded, 390961ae650dSJack F Vogel &osd->eth.rx_broadcast, 391061ae650dSJack F Vogel &nsd->eth.rx_broadcast); 391161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port), 391261ae650dSJack F Vogel I40E_GLPRT_BPTCL(hw->port), 391361ae650dSJack F Vogel pf->stat_offsets_loaded, 391461ae650dSJack F Vogel &osd->eth.tx_broadcast, 391561ae650dSJack F Vogel &nsd->eth.tx_broadcast); 391661ae650dSJack F Vogel 391761ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port), 391861ae650dSJack F Vogel pf->stat_offsets_loaded, 391961ae650dSJack F Vogel &osd->tx_dropped_link_down, 392061ae650dSJack F Vogel &nsd->tx_dropped_link_down); 392161ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port), 392261ae650dSJack F Vogel pf->stat_offsets_loaded, 392361ae650dSJack F Vogel &osd->mac_local_faults, 392461ae650dSJack F Vogel &nsd->mac_local_faults); 392561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port), 392661ae650dSJack F Vogel pf->stat_offsets_loaded, 392761ae650dSJack F Vogel &osd->mac_remote_faults, 392861ae650dSJack F Vogel &nsd->mac_remote_faults); 392961ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port), 393061ae650dSJack F Vogel pf->stat_offsets_loaded, 393161ae650dSJack F Vogel &osd->rx_length_errors, 393261ae650dSJack F Vogel &nsd->rx_length_errors); 393361ae650dSJack F Vogel 393461ae650dSJack F Vogel /* Flow control (LFC) stats */ 393561ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port), 393661ae650dSJack F Vogel pf->stat_offsets_loaded, 393761ae650dSJack F Vogel &osd->link_xon_rx, &nsd->link_xon_rx); 393861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port), 393961ae650dSJack F Vogel pf->stat_offsets_loaded, 394061ae650dSJack F Vogel &osd->link_xon_tx, &nsd->link_xon_tx); 394161ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port), 394261ae650dSJack F Vogel pf->stat_offsets_loaded, 394361ae650dSJack F Vogel &osd->link_xoff_rx, &nsd->link_xoff_rx); 394461ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port), 394561ae650dSJack F Vogel pf->stat_offsets_loaded, 394661ae650dSJack F Vogel &osd->link_xoff_tx, &nsd->link_xoff_tx); 394761ae650dSJack F Vogel 394861ae650dSJack F Vogel /* Packet size stats rx */ 394961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port), 395061ae650dSJack F Vogel I40E_GLPRT_PRC64L(hw->port), 395161ae650dSJack F Vogel pf->stat_offsets_loaded, 395261ae650dSJack F Vogel &osd->rx_size_64, &nsd->rx_size_64); 395361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port), 395461ae650dSJack F Vogel I40E_GLPRT_PRC127L(hw->port), 395561ae650dSJack F Vogel pf->stat_offsets_loaded, 395661ae650dSJack F Vogel &osd->rx_size_127, &nsd->rx_size_127); 395761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port), 395861ae650dSJack F Vogel I40E_GLPRT_PRC255L(hw->port), 395961ae650dSJack F Vogel pf->stat_offsets_loaded, 396061ae650dSJack F Vogel &osd->rx_size_255, &nsd->rx_size_255); 396161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port), 396261ae650dSJack F Vogel I40E_GLPRT_PRC511L(hw->port), 396361ae650dSJack F Vogel pf->stat_offsets_loaded, 396461ae650dSJack F Vogel &osd->rx_size_511, &nsd->rx_size_511); 396561ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port), 396661ae650dSJack F Vogel I40E_GLPRT_PRC1023L(hw->port), 396761ae650dSJack F Vogel pf->stat_offsets_loaded, 396861ae650dSJack F Vogel &osd->rx_size_1023, &nsd->rx_size_1023); 396961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port), 397061ae650dSJack F Vogel I40E_GLPRT_PRC1522L(hw->port), 397161ae650dSJack F Vogel pf->stat_offsets_loaded, 397261ae650dSJack F Vogel &osd->rx_size_1522, &nsd->rx_size_1522); 397361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port), 397461ae650dSJack F Vogel I40E_GLPRT_PRC9522L(hw->port), 397561ae650dSJack F Vogel pf->stat_offsets_loaded, 397661ae650dSJack F Vogel &osd->rx_size_big, &nsd->rx_size_big); 397761ae650dSJack F Vogel 397861ae650dSJack F Vogel /* Packet size stats tx */ 397961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port), 398061ae650dSJack F Vogel I40E_GLPRT_PTC64L(hw->port), 398161ae650dSJack F Vogel pf->stat_offsets_loaded, 398261ae650dSJack F Vogel &osd->tx_size_64, &nsd->tx_size_64); 398361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port), 398461ae650dSJack F Vogel I40E_GLPRT_PTC127L(hw->port), 398561ae650dSJack F Vogel pf->stat_offsets_loaded, 398661ae650dSJack F Vogel &osd->tx_size_127, &nsd->tx_size_127); 398761ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port), 398861ae650dSJack F Vogel I40E_GLPRT_PTC255L(hw->port), 398961ae650dSJack F Vogel pf->stat_offsets_loaded, 399061ae650dSJack F Vogel &osd->tx_size_255, &nsd->tx_size_255); 399161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port), 399261ae650dSJack F Vogel I40E_GLPRT_PTC511L(hw->port), 399361ae650dSJack F Vogel pf->stat_offsets_loaded, 399461ae650dSJack F Vogel &osd->tx_size_511, &nsd->tx_size_511); 399561ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port), 399661ae650dSJack F Vogel I40E_GLPRT_PTC1023L(hw->port), 399761ae650dSJack F Vogel pf->stat_offsets_loaded, 399861ae650dSJack F Vogel &osd->tx_size_1023, &nsd->tx_size_1023); 399961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port), 400061ae650dSJack F Vogel I40E_GLPRT_PTC1522L(hw->port), 400161ae650dSJack F Vogel pf->stat_offsets_loaded, 400261ae650dSJack F Vogel &osd->tx_size_1522, &nsd->tx_size_1522); 400361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port), 400461ae650dSJack F Vogel I40E_GLPRT_PTC9522L(hw->port), 400561ae650dSJack F Vogel pf->stat_offsets_loaded, 400661ae650dSJack F Vogel &osd->tx_size_big, &nsd->tx_size_big); 400761ae650dSJack F Vogel 400861ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port), 400961ae650dSJack F Vogel pf->stat_offsets_loaded, 401061ae650dSJack F Vogel &osd->rx_undersize, &nsd->rx_undersize); 401161ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port), 401261ae650dSJack F Vogel pf->stat_offsets_loaded, 401361ae650dSJack F Vogel &osd->rx_fragments, &nsd->rx_fragments); 401461ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port), 401561ae650dSJack F Vogel pf->stat_offsets_loaded, 401661ae650dSJack F Vogel &osd->rx_oversize, &nsd->rx_oversize); 401761ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port), 401861ae650dSJack F Vogel pf->stat_offsets_loaded, 401961ae650dSJack F Vogel &osd->rx_jabber, &nsd->rx_jabber); 402061ae650dSJack F Vogel pf->stat_offsets_loaded = true; 402161ae650dSJack F Vogel /* End hw stats */ 402261ae650dSJack F Vogel 402361ae650dSJack F Vogel /* Update vsi stats */ 402461ae650dSJack F Vogel ixl_update_eth_stats(vsi); 402561ae650dSJack F Vogel 402661ae650dSJack F Vogel /* OS statistics */ 402761ae650dSJack F Vogel // ERJ - these are per-port, update all vsis? 40284b443922SGleb Smirnoff IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes); 402961ae650dSJack F Vogel } 403061ae650dSJack F Vogel 403161ae650dSJack F Vogel /* 403261ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts 403361ae650dSJack F Vogel ** - do outside interrupt since it might sleep 403461ae650dSJack F Vogel */ 403561ae650dSJack F Vogel static void 403661ae650dSJack F Vogel ixl_do_adminq(void *context, int pending) 403761ae650dSJack F Vogel { 403861ae650dSJack F Vogel struct ixl_pf *pf = context; 403961ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 404061ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 404161ae650dSJack F Vogel struct i40e_arq_event_info event; 404261ae650dSJack F Vogel i40e_status ret; 404361ae650dSJack F Vogel u32 reg, loop = 0; 404461ae650dSJack F Vogel u16 opcode, result; 404561ae650dSJack F Vogel 4046e5100ee2SJack F Vogel event.buf_len = IXL_AQ_BUF_SZ; 4047e5100ee2SJack F Vogel event.msg_buf = malloc(event.buf_len, 404861ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO); 404961ae650dSJack F Vogel if (!event.msg_buf) { 405061ae650dSJack F Vogel printf("Unable to allocate adminq memory\n"); 405161ae650dSJack F Vogel return; 405261ae650dSJack F Vogel } 405361ae650dSJack F Vogel 405461ae650dSJack F Vogel /* clean and process any events */ 405561ae650dSJack F Vogel do { 405661ae650dSJack F Vogel ret = i40e_clean_arq_element(hw, &event, &result); 405761ae650dSJack F Vogel if (ret) 405861ae650dSJack F Vogel break; 405961ae650dSJack F Vogel opcode = LE16_TO_CPU(event.desc.opcode); 406061ae650dSJack F Vogel switch (opcode) { 406161ae650dSJack F Vogel case i40e_aqc_opc_get_link_status: 406261ae650dSJack F Vogel vsi->link_up = ixl_config_link(hw); 406361ae650dSJack F Vogel ixl_update_link_status(pf); 406461ae650dSJack F Vogel break; 406561ae650dSJack F Vogel case i40e_aqc_opc_send_msg_to_pf: 406661ae650dSJack F Vogel /* process pf/vf communication here */ 406761ae650dSJack F Vogel break; 406861ae650dSJack F Vogel case i40e_aqc_opc_event_lan_overflow: 406961ae650dSJack F Vogel break; 407061ae650dSJack F Vogel default: 407161ae650dSJack F Vogel #ifdef IXL_DEBUG 407261ae650dSJack F Vogel printf("AdminQ unknown event %x\n", opcode); 407361ae650dSJack F Vogel #endif 407461ae650dSJack F Vogel break; 407561ae650dSJack F Vogel } 407661ae650dSJack F Vogel 407761ae650dSJack F Vogel } while (result && (loop++ < IXL_ADM_LIMIT)); 407861ae650dSJack F Vogel 407961ae650dSJack F Vogel reg = rd32(hw, I40E_PFINT_ICR0_ENA); 408061ae650dSJack F Vogel reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 408161ae650dSJack F Vogel wr32(hw, I40E_PFINT_ICR0_ENA, reg); 408261ae650dSJack F Vogel free(event.msg_buf, M_DEVBUF); 408361ae650dSJack F Vogel 408461ae650dSJack F Vogel if (pf->msix > 1) 408561ae650dSJack F Vogel ixl_enable_adminq(&pf->hw); 408661ae650dSJack F Vogel else 408761ae650dSJack F Vogel ixl_enable_intr(vsi); 408861ae650dSJack F Vogel } 408961ae650dSJack F Vogel 409061ae650dSJack F Vogel static int 409161ae650dSJack F Vogel ixl_debug_info(SYSCTL_HANDLER_ARGS) 409261ae650dSJack F Vogel { 409361ae650dSJack F Vogel struct ixl_pf *pf; 409461ae650dSJack F Vogel int error, input = 0; 409561ae650dSJack F Vogel 409661ae650dSJack F Vogel error = sysctl_handle_int(oidp, &input, 0, req); 409761ae650dSJack F Vogel 409861ae650dSJack F Vogel if (error || !req->newptr) 409961ae650dSJack F Vogel return (error); 410061ae650dSJack F Vogel 410161ae650dSJack F Vogel if (input == 1) { 410261ae650dSJack F Vogel pf = (struct ixl_pf *)arg1; 410361ae650dSJack F Vogel ixl_print_debug_info(pf); 410461ae650dSJack F Vogel } 410561ae650dSJack F Vogel 410661ae650dSJack F Vogel return (error); 410761ae650dSJack F Vogel } 410861ae650dSJack F Vogel 410961ae650dSJack F Vogel static void 411061ae650dSJack F Vogel ixl_print_debug_info(struct ixl_pf *pf) 411161ae650dSJack F Vogel { 411261ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 411361ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 411461ae650dSJack F Vogel struct ixl_queue *que = vsi->queues; 411561ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 411661ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 411761ae650dSJack F Vogel u32 reg; 411861ae650dSJack F Vogel 411961ae650dSJack F Vogel 4120ff21e856SBjoern A. Zeeb printf("Queue irqs = %jx\n", (uintmax_t)que->irqs); 4121ff21e856SBjoern A. Zeeb printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq); 412261ae650dSJack F Vogel printf("RX next check = %x\n", rxr->next_check); 4123ff21e856SBjoern A. Zeeb printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done); 4124ff21e856SBjoern A. Zeeb printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets); 412561ae650dSJack F Vogel printf("TX desc avail = %x\n", txr->avail); 412661ae650dSJack F Vogel 412761ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_GORCL(0xc)); 412861ae650dSJack F Vogel printf("RX Bytes = %x\n", reg); 412961ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_GORCL(hw->port)); 413061ae650dSJack F Vogel printf("Port RX Bytes = %x\n", reg); 413161ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_RDPC(0xc)); 413261ae650dSJack F Vogel printf("RX discard = %x\n", reg); 413361ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RDPC(hw->port)); 413461ae650dSJack F Vogel printf("Port RX discard = %x\n", reg); 413561ae650dSJack F Vogel 413661ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_TEPC(0xc)); 413761ae650dSJack F Vogel printf("TX errors = %x\n", reg); 413861ae650dSJack F Vogel reg = rd32(hw, I40E_GLV_GOTCL(0xc)); 413961ae650dSJack F Vogel printf("TX Bytes = %x\n", reg); 414061ae650dSJack F Vogel 414161ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RUC(hw->port)); 414261ae650dSJack F Vogel printf("RX undersize = %x\n", reg); 414361ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RFC(hw->port)); 414461ae650dSJack F Vogel printf("RX fragments = %x\n", reg); 414561ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_ROC(hw->port)); 414661ae650dSJack F Vogel printf("RX oversize = %x\n", reg); 414761ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_RLEC(hw->port)); 414861ae650dSJack F Vogel printf("RX length error = %x\n", reg); 414961ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_MRFC(hw->port)); 415061ae650dSJack F Vogel printf("mac remote fault = %x\n", reg); 415161ae650dSJack F Vogel reg = rd32(hw, I40E_GLPRT_MLFC(hw->port)); 415261ae650dSJack F Vogel printf("mac local fault = %x\n", reg); 415361ae650dSJack F Vogel } 415461ae650dSJack F Vogel 415561ae650dSJack F Vogel /** 415661ae650dSJack F Vogel * Update VSI-specific ethernet statistics counters. 415761ae650dSJack F Vogel **/ 415861ae650dSJack F Vogel void ixl_update_eth_stats(struct ixl_vsi *vsi) 415961ae650dSJack F Vogel { 416061ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 416161ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 416261ae650dSJack F Vogel struct i40e_eth_stats *es; 416361ae650dSJack F Vogel struct i40e_eth_stats *oes; 41644b443922SGleb Smirnoff int i; 41654b443922SGleb Smirnoff uint64_t tx_discards; 41664b443922SGleb Smirnoff struct i40e_hw_port_stats *nsd; 416761ae650dSJack F Vogel u16 stat_idx = vsi->info.stat_counter_idx; 416861ae650dSJack F Vogel 416961ae650dSJack F Vogel es = &vsi->eth_stats; 417061ae650dSJack F Vogel oes = &vsi->eth_stats_offsets; 41714b443922SGleb Smirnoff nsd = &pf->stats; 417261ae650dSJack F Vogel 417361ae650dSJack F Vogel /* Gather up the stats that the hw collects */ 417461ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx), 417561ae650dSJack F Vogel vsi->stat_offsets_loaded, 417661ae650dSJack F Vogel &oes->tx_errors, &es->tx_errors); 417761ae650dSJack F Vogel ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx), 417861ae650dSJack F Vogel vsi->stat_offsets_loaded, 417961ae650dSJack F Vogel &oes->rx_discards, &es->rx_discards); 418061ae650dSJack F Vogel 418161ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx), 418261ae650dSJack F Vogel I40E_GLV_GORCL(stat_idx), 418361ae650dSJack F Vogel vsi->stat_offsets_loaded, 418461ae650dSJack F Vogel &oes->rx_bytes, &es->rx_bytes); 418561ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx), 418661ae650dSJack F Vogel I40E_GLV_UPRCL(stat_idx), 418761ae650dSJack F Vogel vsi->stat_offsets_loaded, 418861ae650dSJack F Vogel &oes->rx_unicast, &es->rx_unicast); 418961ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx), 419061ae650dSJack F Vogel I40E_GLV_MPRCL(stat_idx), 419161ae650dSJack F Vogel vsi->stat_offsets_loaded, 419261ae650dSJack F Vogel &oes->rx_multicast, &es->rx_multicast); 419361ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx), 419461ae650dSJack F Vogel I40E_GLV_BPRCL(stat_idx), 419561ae650dSJack F Vogel vsi->stat_offsets_loaded, 419661ae650dSJack F Vogel &oes->rx_broadcast, &es->rx_broadcast); 419761ae650dSJack F Vogel 419861ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx), 419961ae650dSJack F Vogel I40E_GLV_GOTCL(stat_idx), 420061ae650dSJack F Vogel vsi->stat_offsets_loaded, 420161ae650dSJack F Vogel &oes->tx_bytes, &es->tx_bytes); 420261ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx), 420361ae650dSJack F Vogel I40E_GLV_UPTCL(stat_idx), 420461ae650dSJack F Vogel vsi->stat_offsets_loaded, 420561ae650dSJack F Vogel &oes->tx_unicast, &es->tx_unicast); 420661ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx), 420761ae650dSJack F Vogel I40E_GLV_MPTCL(stat_idx), 420861ae650dSJack F Vogel vsi->stat_offsets_loaded, 420961ae650dSJack F Vogel &oes->tx_multicast, &es->tx_multicast); 421061ae650dSJack F Vogel ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx), 421161ae650dSJack F Vogel I40E_GLV_BPTCL(stat_idx), 421261ae650dSJack F Vogel vsi->stat_offsets_loaded, 421361ae650dSJack F Vogel &oes->tx_broadcast, &es->tx_broadcast); 421461ae650dSJack F Vogel vsi->stat_offsets_loaded = true; 421561ae650dSJack F Vogel 42164b443922SGleb Smirnoff tx_discards = es->tx_discards + nsd->tx_dropped_link_down; 42174b443922SGleb Smirnoff for (i = 0; i < vsi->num_queues; i++) 42184b443922SGleb Smirnoff tx_discards += vsi->queues[i].txr.br->br_drops; 421961ae650dSJack F Vogel 42204b443922SGleb Smirnoff /* Update ifnet stats */ 42214b443922SGleb Smirnoff IXL_SET_IPACKETS(vsi, es->rx_unicast + 42224b443922SGleb Smirnoff es->rx_multicast + 42234b443922SGleb Smirnoff es->rx_broadcast); 42244b443922SGleb Smirnoff IXL_SET_OPACKETS(vsi, es->tx_unicast + 42254b443922SGleb Smirnoff es->tx_multicast + 42264b443922SGleb Smirnoff es->tx_broadcast); 42274b443922SGleb Smirnoff IXL_SET_IBYTES(vsi, es->rx_bytes); 42284b443922SGleb Smirnoff IXL_SET_OBYTES(vsi, es->tx_bytes); 42294b443922SGleb Smirnoff IXL_SET_IMCASTS(vsi, es->rx_multicast); 42304b443922SGleb Smirnoff IXL_SET_OMCASTS(vsi, es->tx_multicast); 42314b443922SGleb Smirnoff 42324b443922SGleb Smirnoff IXL_SET_OERRORS(vsi, es->tx_errors); 42334b443922SGleb Smirnoff IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards); 42344b443922SGleb Smirnoff IXL_SET_OQDROPS(vsi, tx_discards); 42354b443922SGleb Smirnoff IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol); 42364b443922SGleb Smirnoff IXL_SET_COLLISIONS(vsi, 0); 423761ae650dSJack F Vogel } 423861ae650dSJack F Vogel 423961ae650dSJack F Vogel /** 424061ae650dSJack F Vogel * Reset all of the stats for the given pf 424161ae650dSJack F Vogel **/ 424261ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf) 424361ae650dSJack F Vogel { 424461ae650dSJack F Vogel bzero(&pf->stats, sizeof(struct i40e_hw_port_stats)); 424561ae650dSJack F Vogel bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats)); 424661ae650dSJack F Vogel pf->stat_offsets_loaded = false; 424761ae650dSJack F Vogel } 424861ae650dSJack F Vogel 424961ae650dSJack F Vogel /** 425061ae650dSJack F Vogel * Resets all stats of the given vsi 425161ae650dSJack F Vogel **/ 425261ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi) 425361ae650dSJack F Vogel { 425461ae650dSJack F Vogel bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats)); 425561ae650dSJack F Vogel bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats)); 425661ae650dSJack F Vogel vsi->stat_offsets_loaded = false; 425761ae650dSJack F Vogel } 425861ae650dSJack F Vogel 425961ae650dSJack F Vogel /** 426061ae650dSJack F Vogel * Read and update a 48 bit stat from the hw 426161ae650dSJack F Vogel * 426261ae650dSJack F Vogel * Since the device stats are not reset at PFReset, they likely will not 426361ae650dSJack F Vogel * be zeroed when the driver starts. We'll save the first values read 426461ae650dSJack F Vogel * and use them as offsets to be subtracted from the raw values in order 426561ae650dSJack F Vogel * to report stats that count from zero. 426661ae650dSJack F Vogel **/ 426761ae650dSJack F Vogel static void 426861ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg, 426961ae650dSJack F Vogel bool offset_loaded, u64 *offset, u64 *stat) 427061ae650dSJack F Vogel { 427161ae650dSJack F Vogel u64 new_data; 427261ae650dSJack F Vogel 4273ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__) 427461ae650dSJack F Vogel new_data = rd64(hw, loreg); 427561ae650dSJack F Vogel #else 427661ae650dSJack F Vogel /* 427761ae650dSJack F Vogel * Use two rd32's instead of one rd64; FreeBSD versions before 427861ae650dSJack F Vogel * 10 don't support 8 byte bus reads/writes. 427961ae650dSJack F Vogel */ 428061ae650dSJack F Vogel new_data = rd32(hw, loreg); 428161ae650dSJack F Vogel new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32; 428261ae650dSJack F Vogel #endif 428361ae650dSJack F Vogel 428461ae650dSJack F Vogel if (!offset_loaded) 428561ae650dSJack F Vogel *offset = new_data; 428661ae650dSJack F Vogel if (new_data >= *offset) 428761ae650dSJack F Vogel *stat = new_data - *offset; 428861ae650dSJack F Vogel else 428961ae650dSJack F Vogel *stat = (new_data + ((u64)1 << 48)) - *offset; 429061ae650dSJack F Vogel *stat &= 0xFFFFFFFFFFFFULL; 429161ae650dSJack F Vogel } 429261ae650dSJack F Vogel 429361ae650dSJack F Vogel /** 429461ae650dSJack F Vogel * Read and update a 32 bit stat from the hw 429561ae650dSJack F Vogel **/ 429661ae650dSJack F Vogel static void 429761ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg, 429861ae650dSJack F Vogel bool offset_loaded, u64 *offset, u64 *stat) 429961ae650dSJack F Vogel { 430061ae650dSJack F Vogel u32 new_data; 430161ae650dSJack F Vogel 430261ae650dSJack F Vogel new_data = rd32(hw, reg); 430361ae650dSJack F Vogel if (!offset_loaded) 430461ae650dSJack F Vogel *offset = new_data; 430561ae650dSJack F Vogel if (new_data >= *offset) 430661ae650dSJack F Vogel *stat = (u32)(new_data - *offset); 430761ae650dSJack F Vogel else 430861ae650dSJack F Vogel *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); 430961ae650dSJack F Vogel } 431061ae650dSJack F Vogel 431161ae650dSJack F Vogel /* 431261ae650dSJack F Vogel ** Set flow control using sysctl: 431361ae650dSJack F Vogel ** 0 - off 431461ae650dSJack F Vogel ** 1 - rx pause 431561ae650dSJack F Vogel ** 2 - tx pause 431661ae650dSJack F Vogel ** 3 - full 431761ae650dSJack F Vogel */ 431861ae650dSJack F Vogel static int 431961ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS) 432061ae650dSJack F Vogel { 432161ae650dSJack F Vogel /* 432261ae650dSJack F Vogel * TODO: ensure flow control is disabled if 432361ae650dSJack F Vogel * priority flow control is enabled 432461ae650dSJack F Vogel * 432561ae650dSJack F Vogel * TODO: ensure tx CRC by hardware should be enabled 432661ae650dSJack F Vogel * if tx flow control is enabled. 432761ae650dSJack F Vogel */ 432861ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 432961ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 433061ae650dSJack F Vogel device_t dev = pf->dev; 4331b6c8f260SJack F Vogel int error = 0; 433261ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 433361ae650dSJack F Vogel u8 fc_aq_err = 0; 433461ae650dSJack F Vogel 4335b6c8f260SJack F Vogel /* Get request */ 4336b6c8f260SJack F Vogel error = sysctl_handle_int(oidp, &pf->fc, 0, req); 433761ae650dSJack F Vogel if ((error) || (req->newptr == NULL)) 433861ae650dSJack F Vogel return (error); 4339b6c8f260SJack F Vogel if (pf->fc < 0 || pf->fc > 3) { 434061ae650dSJack F Vogel device_printf(dev, 434161ae650dSJack F Vogel "Invalid fc mode; valid modes are 0 through 3\n"); 434261ae650dSJack F Vogel return (EINVAL); 434361ae650dSJack F Vogel } 434461ae650dSJack F Vogel 434561ae650dSJack F Vogel /* 434661ae650dSJack F Vogel ** Changing flow control mode currently does not work on 434761ae650dSJack F Vogel ** 40GBASE-CR4 PHYs 434861ae650dSJack F Vogel */ 434961ae650dSJack F Vogel if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4 435061ae650dSJack F Vogel || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) { 435161ae650dSJack F Vogel device_printf(dev, "Changing flow control mode unsupported" 435261ae650dSJack F Vogel " on 40GBase-CR4 media.\n"); 435361ae650dSJack F Vogel return (ENODEV); 435461ae650dSJack F Vogel } 435561ae650dSJack F Vogel 435661ae650dSJack F Vogel /* Set fc ability for port */ 4357b6c8f260SJack F Vogel hw->fc.requested_mode = pf->fc; 435861ae650dSJack F Vogel aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE); 435961ae650dSJack F Vogel if (aq_error) { 436061ae650dSJack F Vogel device_printf(dev, 436161ae650dSJack F Vogel "%s: Error setting new fc mode %d; fc_err %#x\n", 436261ae650dSJack F Vogel __func__, aq_error, fc_aq_err); 436361ae650dSJack F Vogel return (EAGAIN); 436461ae650dSJack F Vogel } 436561ae650dSJack F Vogel 436661ae650dSJack F Vogel return (0); 436761ae650dSJack F Vogel } 436861ae650dSJack F Vogel 436961ae650dSJack F Vogel static int 437061ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS) 437161ae650dSJack F Vogel { 437261ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 437361ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 437461ae650dSJack F Vogel int error = 0, index = 0; 437561ae650dSJack F Vogel 437661ae650dSJack F Vogel char *speeds[] = { 437761ae650dSJack F Vogel "Unknown", 437861ae650dSJack F Vogel "100M", 437961ae650dSJack F Vogel "1G", 438061ae650dSJack F Vogel "10G", 438161ae650dSJack F Vogel "40G", 438261ae650dSJack F Vogel "20G" 438361ae650dSJack F Vogel }; 438461ae650dSJack F Vogel 438561ae650dSJack F Vogel ixl_update_link_status(pf); 438661ae650dSJack F Vogel 438761ae650dSJack F Vogel switch (hw->phy.link_info.link_speed) { 438861ae650dSJack F Vogel case I40E_LINK_SPEED_100MB: 438961ae650dSJack F Vogel index = 1; 439061ae650dSJack F Vogel break; 439161ae650dSJack F Vogel case I40E_LINK_SPEED_1GB: 439261ae650dSJack F Vogel index = 2; 439361ae650dSJack F Vogel break; 439461ae650dSJack F Vogel case I40E_LINK_SPEED_10GB: 439561ae650dSJack F Vogel index = 3; 439661ae650dSJack F Vogel break; 439761ae650dSJack F Vogel case I40E_LINK_SPEED_40GB: 439861ae650dSJack F Vogel index = 4; 439961ae650dSJack F Vogel break; 440061ae650dSJack F Vogel case I40E_LINK_SPEED_20GB: 440161ae650dSJack F Vogel index = 5; 440261ae650dSJack F Vogel break; 440361ae650dSJack F Vogel case I40E_LINK_SPEED_UNKNOWN: 440461ae650dSJack F Vogel default: 440561ae650dSJack F Vogel index = 0; 440661ae650dSJack F Vogel break; 440761ae650dSJack F Vogel } 440861ae650dSJack F Vogel 440961ae650dSJack F Vogel error = sysctl_handle_string(oidp, speeds[index], 441061ae650dSJack F Vogel strlen(speeds[index]), req); 441161ae650dSJack F Vogel return (error); 441261ae650dSJack F Vogel } 441361ae650dSJack F Vogel 4414e5100ee2SJack F Vogel static int 4415e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds) 4416e5100ee2SJack F Vogel { 4417e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 4418e5100ee2SJack F Vogel device_t dev = pf->dev; 4419e5100ee2SJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities; 4420e5100ee2SJack F Vogel struct i40e_aq_set_phy_config config; 4421e5100ee2SJack F Vogel enum i40e_status_code aq_error = 0; 4422e5100ee2SJack F Vogel 4423e5100ee2SJack F Vogel /* Get current capability information */ 4424b6c8f260SJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, 4425b6c8f260SJack F Vogel FALSE, FALSE, &abilities, NULL); 4426e5100ee2SJack F Vogel if (aq_error) { 4427b6c8f260SJack F Vogel device_printf(dev, 4428b6c8f260SJack F Vogel "%s: Error getting phy capabilities %d," 4429e5100ee2SJack F Vogel " aq error: %d\n", __func__, aq_error, 4430e5100ee2SJack F Vogel hw->aq.asq_last_status); 4431e5100ee2SJack F Vogel return (EAGAIN); 4432e5100ee2SJack F Vogel } 4433e5100ee2SJack F Vogel 4434e5100ee2SJack F Vogel /* Prepare new config */ 4435e5100ee2SJack F Vogel bzero(&config, sizeof(config)); 4436e5100ee2SJack F Vogel config.phy_type = abilities.phy_type; 4437e5100ee2SJack F Vogel config.abilities = abilities.abilities 4438e5100ee2SJack F Vogel | I40E_AQ_PHY_ENABLE_ATOMIC_LINK; 4439e5100ee2SJack F Vogel config.eee_capability = abilities.eee_capability; 4440e5100ee2SJack F Vogel config.eeer = abilities.eeer_val; 4441e5100ee2SJack F Vogel config.low_power_ctrl = abilities.d3_lpan; 4442e5100ee2SJack F Vogel /* Translate into aq cmd link_speed */ 4443e5100ee2SJack F Vogel if (speeds & 0x4) 4444e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_10GB; 4445e5100ee2SJack F Vogel if (speeds & 0x2) 4446e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_1GB; 4447e5100ee2SJack F Vogel if (speeds & 0x1) 4448e5100ee2SJack F Vogel config.link_speed |= I40E_LINK_SPEED_100MB; 4449e5100ee2SJack F Vogel 4450e5100ee2SJack F Vogel /* Do aq command & restart link */ 4451e5100ee2SJack F Vogel aq_error = i40e_aq_set_phy_config(hw, &config, NULL); 4452e5100ee2SJack F Vogel if (aq_error) { 4453b6c8f260SJack F Vogel device_printf(dev, 4454b6c8f260SJack F Vogel "%s: Error setting new phy config %d," 4455e5100ee2SJack F Vogel " aq error: %d\n", __func__, aq_error, 4456e5100ee2SJack F Vogel hw->aq.asq_last_status); 4457e5100ee2SJack F Vogel return (EAGAIN); 4458e5100ee2SJack F Vogel } 4459e5100ee2SJack F Vogel 4460393c4bb1SJack F Vogel /* 4461393c4bb1SJack F Vogel ** This seems a bit heavy handed, but we 4462393c4bb1SJack F Vogel ** need to get a reinit on some devices 4463393c4bb1SJack F Vogel */ 4464393c4bb1SJack F Vogel IXL_PF_LOCK(pf); 4465393c4bb1SJack F Vogel ixl_stop(pf); 4466393c4bb1SJack F Vogel ixl_init_locked(pf); 4467393c4bb1SJack F Vogel IXL_PF_UNLOCK(pf); 4468393c4bb1SJack F Vogel 4469e5100ee2SJack F Vogel return (0); 4470e5100ee2SJack F Vogel } 4471e5100ee2SJack F Vogel 447261ae650dSJack F Vogel /* 447361ae650dSJack F Vogel ** Control link advertise speed: 447461ae650dSJack F Vogel ** Flags: 447561ae650dSJack F Vogel ** 0x1 - advertise 100 Mb 447661ae650dSJack F Vogel ** 0x2 - advertise 1G 447761ae650dSJack F Vogel ** 0x4 - advertise 10G 447861ae650dSJack F Vogel ** 447961ae650dSJack F Vogel ** Does not work on 40G devices. 448061ae650dSJack F Vogel */ 448161ae650dSJack F Vogel static int 448261ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS) 448361ae650dSJack F Vogel { 448461ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 448561ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 448661ae650dSJack F Vogel device_t dev = pf->dev; 448761ae650dSJack F Vogel int requested_ls = 0; 448861ae650dSJack F Vogel int error = 0; 448961ae650dSJack F Vogel 449061ae650dSJack F Vogel /* 449161ae650dSJack F Vogel ** FW doesn't support changing advertised speed 449261ae650dSJack F Vogel ** for 40G devices; speed is always 40G. 449361ae650dSJack F Vogel */ 449461ae650dSJack F Vogel if (i40e_is_40G_device(hw->device_id)) 449561ae650dSJack F Vogel return (ENODEV); 449661ae650dSJack F Vogel 449761ae650dSJack F Vogel /* Read in new mode */ 449861ae650dSJack F Vogel requested_ls = pf->advertised_speed; 449961ae650dSJack F Vogel error = sysctl_handle_int(oidp, &requested_ls, 0, req); 450061ae650dSJack F Vogel if ((error) || (req->newptr == NULL)) 450161ae650dSJack F Vogel return (error); 450261ae650dSJack F Vogel if (requested_ls < 1 || requested_ls > 7) { 450361ae650dSJack F Vogel device_printf(dev, 450461ae650dSJack F Vogel "Invalid advertised speed; valid modes are 0x1 through 0x7\n"); 450561ae650dSJack F Vogel return (EINVAL); 450661ae650dSJack F Vogel } 450761ae650dSJack F Vogel 450861ae650dSJack F Vogel /* Exit if no change */ 450961ae650dSJack F Vogel if (pf->advertised_speed == requested_ls) 451061ae650dSJack F Vogel return (0); 451161ae650dSJack F Vogel 4512e5100ee2SJack F Vogel error = ixl_set_advertised_speeds(pf, requested_ls); 4513e5100ee2SJack F Vogel if (error) 4514e5100ee2SJack F Vogel return (error); 451561ae650dSJack F Vogel 451661ae650dSJack F Vogel pf->advertised_speed = requested_ls; 451761ae650dSJack F Vogel ixl_update_link_status(pf); 451861ae650dSJack F Vogel return (0); 451961ae650dSJack F Vogel } 452061ae650dSJack F Vogel 452161ae650dSJack F Vogel /* 452261ae650dSJack F Vogel ** Get the width and transaction speed of 452361ae650dSJack F Vogel ** the bus this adapter is plugged into. 452461ae650dSJack F Vogel */ 452561ae650dSJack F Vogel static u16 452661ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev) 452761ae650dSJack F Vogel { 452861ae650dSJack F Vogel u16 link; 452961ae650dSJack F Vogel u32 offset; 453061ae650dSJack F Vogel 453161ae650dSJack F Vogel 453261ae650dSJack F Vogel /* Get the PCI Express Capabilities offset */ 453361ae650dSJack F Vogel pci_find_cap(dev, PCIY_EXPRESS, &offset); 453461ae650dSJack F Vogel 453561ae650dSJack F Vogel /* ...and read the Link Status Register */ 453661ae650dSJack F Vogel link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 453761ae650dSJack F Vogel 453861ae650dSJack F Vogel switch (link & I40E_PCI_LINK_WIDTH) { 453961ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_1: 454061ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x1; 454161ae650dSJack F Vogel break; 454261ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_2: 454361ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x2; 454461ae650dSJack F Vogel break; 454561ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_4: 454661ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x4; 454761ae650dSJack F Vogel break; 454861ae650dSJack F Vogel case I40E_PCI_LINK_WIDTH_8: 454961ae650dSJack F Vogel hw->bus.width = i40e_bus_width_pcie_x8; 455061ae650dSJack F Vogel break; 455161ae650dSJack F Vogel default: 455261ae650dSJack F Vogel hw->bus.width = i40e_bus_width_unknown; 455361ae650dSJack F Vogel break; 455461ae650dSJack F Vogel } 455561ae650dSJack F Vogel 455661ae650dSJack F Vogel switch (link & I40E_PCI_LINK_SPEED) { 455761ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_2500: 455861ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_2500; 455961ae650dSJack F Vogel break; 456061ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_5000: 456161ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_5000; 456261ae650dSJack F Vogel break; 456361ae650dSJack F Vogel case I40E_PCI_LINK_SPEED_8000: 456461ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_8000; 456561ae650dSJack F Vogel break; 456661ae650dSJack F Vogel default: 456761ae650dSJack F Vogel hw->bus.speed = i40e_bus_speed_unknown; 456861ae650dSJack F Vogel break; 456961ae650dSJack F Vogel } 457061ae650dSJack F Vogel 457161ae650dSJack F Vogel 457261ae650dSJack F Vogel device_printf(dev,"PCI Express Bus: Speed %s %s\n", 457361ae650dSJack F Vogel ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s": 457461ae650dSJack F Vogel (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s": 457561ae650dSJack F Vogel (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"), 457661ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" : 457761ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" : 457861ae650dSJack F Vogel (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" : 457961ae650dSJack F Vogel ("Unknown")); 458061ae650dSJack F Vogel 458161ae650dSJack F Vogel if ((hw->bus.width <= i40e_bus_width_pcie_x8) && 458261ae650dSJack F Vogel (hw->bus.speed < i40e_bus_speed_8000)) { 458361ae650dSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 458461ae650dSJack F Vogel " for this device\n is not sufficient for" 458561ae650dSJack F Vogel " normal operation.\n"); 458661ae650dSJack F Vogel device_printf(dev, "For expected performance a x8 " 458761ae650dSJack F Vogel "PCIE Gen3 slot is required.\n"); 458861ae650dSJack F Vogel } 458961ae650dSJack F Vogel 459061ae650dSJack F Vogel return (link); 459161ae650dSJack F Vogel } 459261ae650dSJack F Vogel 4593e5100ee2SJack F Vogel static int 4594e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS) 4595e5100ee2SJack F Vogel { 4596e5100ee2SJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 4597e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 4598e5100ee2SJack F Vogel char buf[32]; 4599e5100ee2SJack F Vogel 4600e5100ee2SJack F Vogel snprintf(buf, sizeof(buf), 4601e5100ee2SJack F Vogel "f%d.%d a%d.%d n%02x.%02x e%08x", 4602e5100ee2SJack F Vogel hw->aq.fw_maj_ver, hw->aq.fw_min_ver, 4603e5100ee2SJack F Vogel hw->aq.api_maj_ver, hw->aq.api_min_ver, 4604e5100ee2SJack F Vogel (hw->nvm.version & IXL_NVM_VERSION_HI_MASK) >> 4605e5100ee2SJack F Vogel IXL_NVM_VERSION_HI_SHIFT, 4606e5100ee2SJack F Vogel (hw->nvm.version & IXL_NVM_VERSION_LO_MASK) >> 4607e5100ee2SJack F Vogel IXL_NVM_VERSION_LO_SHIFT, 4608e5100ee2SJack F Vogel hw->nvm.eetrack); 4609e5100ee2SJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 4610e5100ee2SJack F Vogel } 4611e5100ee2SJack F Vogel 4612e5100ee2SJack F Vogel 4613393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL 461461ae650dSJack F Vogel static int 461561ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS) 461661ae650dSJack F Vogel { 461761ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 461861ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 461961ae650dSJack F Vogel struct i40e_link_status link_status; 462061ae650dSJack F Vogel char buf[512]; 462161ae650dSJack F Vogel 462261ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 462361ae650dSJack F Vogel 462461ae650dSJack F Vogel aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL); 462561ae650dSJack F Vogel if (aq_error) { 462661ae650dSJack F Vogel printf("i40e_aq_get_link_info() error %d\n", aq_error); 462761ae650dSJack F Vogel return (EPERM); 462861ae650dSJack F Vogel } 462961ae650dSJack F Vogel 463061ae650dSJack F Vogel sprintf(buf, "\n" 463161ae650dSJack F Vogel "PHY Type : %#04x\n" 463261ae650dSJack F Vogel "Speed : %#04x\n" 463361ae650dSJack F Vogel "Link info: %#04x\n" 463461ae650dSJack F Vogel "AN info : %#04x\n" 463561ae650dSJack F Vogel "Ext info : %#04x", 463661ae650dSJack F Vogel link_status.phy_type, link_status.link_speed, 463761ae650dSJack F Vogel link_status.link_info, link_status.an_info, 463861ae650dSJack F Vogel link_status.ext_info); 463961ae650dSJack F Vogel 464061ae650dSJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 464161ae650dSJack F Vogel } 464261ae650dSJack F Vogel 464361ae650dSJack F Vogel static int 464461ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS) 464561ae650dSJack F Vogel { 464661ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 464761ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 464861ae650dSJack F Vogel struct i40e_aq_get_phy_abilities_resp abilities_resp; 464961ae650dSJack F Vogel char buf[512]; 465061ae650dSJack F Vogel 465161ae650dSJack F Vogel enum i40e_status_code aq_error = 0; 465261ae650dSJack F Vogel 465361ae650dSJack F Vogel // TODO: Print out list of qualified modules as well? 465461ae650dSJack F Vogel aq_error = i40e_aq_get_phy_capabilities(hw, TRUE, FALSE, &abilities_resp, NULL); 465561ae650dSJack F Vogel if (aq_error) { 465661ae650dSJack F Vogel printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error); 465761ae650dSJack F Vogel return (EPERM); 465861ae650dSJack F Vogel } 465961ae650dSJack F Vogel 466061ae650dSJack F Vogel sprintf(buf, "\n" 466161ae650dSJack F Vogel "PHY Type : %#010x\n" 466261ae650dSJack F Vogel "Speed : %#04x\n" 466361ae650dSJack F Vogel "Abilities: %#04x\n" 466461ae650dSJack F Vogel "EEE cap : %#06x\n" 466561ae650dSJack F Vogel "EEER reg : %#010x\n" 466661ae650dSJack F Vogel "D3 Lpan : %#04x", 466761ae650dSJack F Vogel abilities_resp.phy_type, abilities_resp.link_speed, 466861ae650dSJack F Vogel abilities_resp.abilities, abilities_resp.eee_capability, 466961ae650dSJack F Vogel abilities_resp.eeer_val, abilities_resp.d3_lpan); 467061ae650dSJack F Vogel 467161ae650dSJack F Vogel return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 467261ae650dSJack F Vogel } 467361ae650dSJack F Vogel 467461ae650dSJack F Vogel static int 467561ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS) 467661ae650dSJack F Vogel { 467761ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 467861ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 467961ae650dSJack F Vogel struct ixl_mac_filter *f; 468061ae650dSJack F Vogel char *buf, *buf_i; 468161ae650dSJack F Vogel 468261ae650dSJack F Vogel int error = 0; 468361ae650dSJack F Vogel int ftl_len = 0; 468461ae650dSJack F Vogel int ftl_counter = 0; 468561ae650dSJack F Vogel int buf_len = 0; 468661ae650dSJack F Vogel int entry_len = 42; 468761ae650dSJack F Vogel 468861ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 468961ae650dSJack F Vogel ftl_len++; 469061ae650dSJack F Vogel } 469161ae650dSJack F Vogel 469261ae650dSJack F Vogel if (ftl_len < 1) { 469361ae650dSJack F Vogel sysctl_handle_string(oidp, "(none)", 6, req); 469461ae650dSJack F Vogel return (0); 469561ae650dSJack F Vogel } 469661ae650dSJack F Vogel 469761ae650dSJack F Vogel buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2; 469861ae650dSJack F Vogel buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT); 469961ae650dSJack F Vogel 470061ae650dSJack F Vogel sprintf(buf_i++, "\n"); 470161ae650dSJack F Vogel SLIST_FOREACH(f, &vsi->ftl, next) { 470261ae650dSJack F Vogel sprintf(buf_i, 470361ae650dSJack F Vogel MAC_FORMAT ", vlan %4d, flags %#06x", 470461ae650dSJack F Vogel MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags); 470561ae650dSJack F Vogel buf_i += entry_len; 470661ae650dSJack F Vogel /* don't print '\n' for last entry */ 470761ae650dSJack F Vogel if (++ftl_counter != ftl_len) { 470861ae650dSJack F Vogel sprintf(buf_i, "\n"); 470961ae650dSJack F Vogel buf_i++; 471061ae650dSJack F Vogel } 471161ae650dSJack F Vogel } 471261ae650dSJack F Vogel 471361ae650dSJack F Vogel error = sysctl_handle_string(oidp, buf, strlen(buf), req); 471461ae650dSJack F Vogel if (error) 471561ae650dSJack F Vogel printf("sysctl error: %d\n", error); 471661ae650dSJack F Vogel free(buf, M_DEVBUF); 471761ae650dSJack F Vogel return error; 471861ae650dSJack F Vogel } 471961ae650dSJack F Vogel 472061ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14 472161ae650dSJack F Vogel static int 4722393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b) 4723393c4bb1SJack F Vogel { 4724393c4bb1SJack F Vogel const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two; 4725393c4bb1SJack F Vogel one = (struct i40e_aqc_switch_resource_alloc_element_resp *)a; 4726393c4bb1SJack F Vogel two = (struct i40e_aqc_switch_resource_alloc_element_resp *)b; 4727393c4bb1SJack F Vogel 4728393c4bb1SJack F Vogel return ((int)one->resource_type - (int)two->resource_type); 4729393c4bb1SJack F Vogel } 4730393c4bb1SJack F Vogel 4731393c4bb1SJack F Vogel static int 4732e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS) 473361ae650dSJack F Vogel { 473461ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 473561ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 473661ae650dSJack F Vogel device_t dev = pf->dev; 473761ae650dSJack F Vogel struct sbuf *buf; 473861ae650dSJack F Vogel int error = 0; 473961ae650dSJack F Vogel 474061ae650dSJack F Vogel u8 num_entries; 474161ae650dSJack F Vogel struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE]; 474261ae650dSJack F Vogel 474361ae650dSJack F Vogel buf = sbuf_new_for_sysctl(NULL, NULL, 0, req); 474461ae650dSJack F Vogel if (!buf) { 474561ae650dSJack F Vogel device_printf(dev, "Could not allocate sbuf for output.\n"); 474661ae650dSJack F Vogel return (ENOMEM); 474761ae650dSJack F Vogel } 474861ae650dSJack F Vogel 4749393c4bb1SJack F Vogel bzero(resp, sizeof(resp)); 475061ae650dSJack F Vogel error = i40e_aq_get_switch_resource_alloc(hw, &num_entries, 475161ae650dSJack F Vogel resp, 475261ae650dSJack F Vogel IXL_SW_RES_SIZE, 475361ae650dSJack F Vogel NULL); 475461ae650dSJack F Vogel if (error) { 475561ae650dSJack F Vogel device_printf(dev, "%s: get_switch_resource_alloc() error %d, aq error %d\n", 475661ae650dSJack F Vogel __func__, error, hw->aq.asq_last_status); 475761ae650dSJack F Vogel sbuf_delete(buf); 475861ae650dSJack F Vogel return error; 475961ae650dSJack F Vogel } 4760393c4bb1SJack F Vogel 4761393c4bb1SJack F Vogel /* Sort entries by type for display */ 4762393c4bb1SJack F Vogel qsort(resp, num_entries, 4763393c4bb1SJack F Vogel sizeof(struct i40e_aqc_switch_resource_alloc_element_resp), 4764393c4bb1SJack F Vogel &ixl_res_alloc_cmp); 476561ae650dSJack F Vogel 476661ae650dSJack F Vogel sbuf_cat(buf, "\n"); 4767393c4bb1SJack F Vogel sbuf_printf(buf, "# of entries: %d\n", num_entries); 476861ae650dSJack F Vogel sbuf_printf(buf, 476961ae650dSJack F Vogel "Type | Guaranteed | Total | Used | Un-allocated\n" 477061ae650dSJack F Vogel " | (this) | (all) | (this) | (all) \n"); 477161ae650dSJack F Vogel for (int i = 0; i < num_entries; i++) { 477261ae650dSJack F Vogel sbuf_printf(buf, 477361ae650dSJack F Vogel "%#4x | %10d %5d %6d %12d", 477461ae650dSJack F Vogel resp[i].resource_type, 477561ae650dSJack F Vogel resp[i].guaranteed, 477661ae650dSJack F Vogel resp[i].total, 477761ae650dSJack F Vogel resp[i].used, 477861ae650dSJack F Vogel resp[i].total_unalloced); 477961ae650dSJack F Vogel if (i < num_entries - 1) 478061ae650dSJack F Vogel sbuf_cat(buf, "\n"); 478161ae650dSJack F Vogel } 478261ae650dSJack F Vogel 478361ae650dSJack F Vogel error = sbuf_finish(buf); 478461ae650dSJack F Vogel if (error) { 478561ae650dSJack F Vogel device_printf(dev, "Error finishing sbuf: %d\n", error); 478661ae650dSJack F Vogel sbuf_delete(buf); 478761ae650dSJack F Vogel return error; 478861ae650dSJack F Vogel } 478961ae650dSJack F Vogel 479061ae650dSJack F Vogel error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req); 479161ae650dSJack F Vogel if (error) 479261ae650dSJack F Vogel device_printf(dev, "sysctl error: %d\n", error); 479361ae650dSJack F Vogel sbuf_delete(buf); 479461ae650dSJack F Vogel return error; 4795e5100ee2SJack F Vogel } 479661ae650dSJack F Vogel 4797e5100ee2SJack F Vogel /* 4798e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and 4799e5100ee2SJack F Vogel ** finish it for caller. 4800e5100ee2SJack F Vogel */ 4801e5100ee2SJack F Vogel static char * 4802e5100ee2SJack F Vogel ixl_switch_element_string(struct sbuf *s, u16 seid, bool uplink) 4803e5100ee2SJack F Vogel { 4804e5100ee2SJack F Vogel sbuf_clear(s); 4805e5100ee2SJack F Vogel 4806e5100ee2SJack F Vogel if (seid == 0 && uplink) 4807e5100ee2SJack F Vogel sbuf_cat(s, "Network"); 4808e5100ee2SJack F Vogel else if (seid == 0) 4809e5100ee2SJack F Vogel sbuf_cat(s, "Host"); 4810e5100ee2SJack F Vogel else if (seid == 1) 4811e5100ee2SJack F Vogel sbuf_cat(s, "EMP"); 4812e5100ee2SJack F Vogel else if (seid <= 5) 4813e5100ee2SJack F Vogel sbuf_printf(s, "MAC %d", seid - 2); 4814e5100ee2SJack F Vogel else if (seid <= 15) 4815e5100ee2SJack F Vogel sbuf_cat(s, "Reserved"); 4816e5100ee2SJack F Vogel else if (seid <= 31) 4817e5100ee2SJack F Vogel sbuf_printf(s, "PF %d", seid - 16); 4818e5100ee2SJack F Vogel else if (seid <= 159) 4819e5100ee2SJack F Vogel sbuf_printf(s, "VF %d", seid - 32); 4820e5100ee2SJack F Vogel else if (seid <= 287) 4821e5100ee2SJack F Vogel sbuf_cat(s, "Reserved"); 4822e5100ee2SJack F Vogel else if (seid <= 511) 4823e5100ee2SJack F Vogel sbuf_cat(s, "Other"); // for other structures 4824e5100ee2SJack F Vogel else if (seid <= 895) 4825e5100ee2SJack F Vogel sbuf_printf(s, "VSI %d", seid - 512); 4826e5100ee2SJack F Vogel else if (seid <= 1023) 4827e5100ee2SJack F Vogel sbuf_printf(s, "Reserved"); 4828e5100ee2SJack F Vogel else 4829e5100ee2SJack F Vogel sbuf_cat(s, "Invalid"); 4830e5100ee2SJack F Vogel 4831e5100ee2SJack F Vogel sbuf_finish(s); 4832e5100ee2SJack F Vogel return sbuf_data(s); 4833e5100ee2SJack F Vogel } 4834e5100ee2SJack F Vogel 4835e5100ee2SJack F Vogel static int 4836e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS) 4837e5100ee2SJack F Vogel { 4838e5100ee2SJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 4839e5100ee2SJack F Vogel struct i40e_hw *hw = &pf->hw; 4840e5100ee2SJack F Vogel device_t dev = pf->dev; 4841e5100ee2SJack F Vogel struct sbuf *buf; 4842e5100ee2SJack F Vogel struct sbuf *nmbuf; 4843e5100ee2SJack F Vogel int error = 0; 4844e5100ee2SJack F Vogel u8 aq_buf[I40E_AQ_LARGE_BUF]; 4845e5100ee2SJack F Vogel 4846e5100ee2SJack F Vogel u16 next = 0; 4847e5100ee2SJack F Vogel struct i40e_aqc_get_switch_config_resp *sw_config; 4848e5100ee2SJack F Vogel sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 4849e5100ee2SJack F Vogel 4850e5100ee2SJack F Vogel buf = sbuf_new_for_sysctl(NULL, NULL, 0, req); 4851e5100ee2SJack F Vogel if (!buf) { 4852e5100ee2SJack F Vogel device_printf(dev, "Could not allocate sbuf for sysctl output.\n"); 4853e5100ee2SJack F Vogel return (ENOMEM); 4854e5100ee2SJack F Vogel } 4855e5100ee2SJack F Vogel 4856e5100ee2SJack F Vogel error = i40e_aq_get_switch_config(hw, sw_config, 4857e5100ee2SJack F Vogel sizeof(aq_buf), &next, NULL); 4858e5100ee2SJack F Vogel if (error) { 4859e5100ee2SJack F Vogel device_printf(dev, "%s: aq_get_switch_config() error %d, aq error %d\n", 4860e5100ee2SJack F Vogel __func__, error, hw->aq.asq_last_status); 4861e5100ee2SJack F Vogel sbuf_delete(buf); 4862e5100ee2SJack F Vogel return error; 4863e5100ee2SJack F Vogel } 4864e5100ee2SJack F Vogel 4865e5100ee2SJack F Vogel nmbuf = sbuf_new_auto(); 4866e5100ee2SJack F Vogel if (!nmbuf) { 4867e5100ee2SJack F Vogel device_printf(dev, "Could not allocate sbuf for name output.\n"); 4868e5100ee2SJack F Vogel return (ENOMEM); 4869e5100ee2SJack F Vogel } 4870e5100ee2SJack F Vogel 4871e5100ee2SJack F Vogel sbuf_cat(buf, "\n"); 4872e5100ee2SJack F Vogel // Assuming <= 255 elements in switch 4873e5100ee2SJack F Vogel sbuf_printf(buf, "# of elements: %d\n", sw_config->header.num_reported); 4874e5100ee2SJack F Vogel /* Exclude: 4875e5100ee2SJack F Vogel ** Revision -- all elements are revision 1 for now 4876e5100ee2SJack F Vogel */ 4877e5100ee2SJack F Vogel sbuf_printf(buf, 4878e5100ee2SJack F Vogel "SEID ( Name ) | Uplink | Downlink | Conn Type\n" 4879e5100ee2SJack F Vogel " | | | (uplink)\n"); 4880e5100ee2SJack F Vogel for (int i = 0; i < sw_config->header.num_reported; i++) { 4881e5100ee2SJack F Vogel // "%4d (%8s) | %8s %8s %#8x", 4882e5100ee2SJack F Vogel sbuf_printf(buf, "%4d", sw_config->element[i].seid); 4883e5100ee2SJack F Vogel sbuf_cat(buf, " "); 4884e5100ee2SJack F Vogel sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf, sw_config->element[i].seid, false)); 4885e5100ee2SJack F Vogel sbuf_cat(buf, " | "); 4886e5100ee2SJack F Vogel sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, sw_config->element[i].uplink_seid, true)); 4887e5100ee2SJack F Vogel sbuf_cat(buf, " "); 4888e5100ee2SJack F Vogel sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, sw_config->element[i].downlink_seid, false)); 4889e5100ee2SJack F Vogel sbuf_cat(buf, " "); 4890e5100ee2SJack F Vogel sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type); 4891e5100ee2SJack F Vogel if (i < sw_config->header.num_reported - 1) 4892e5100ee2SJack F Vogel sbuf_cat(buf, "\n"); 4893e5100ee2SJack F Vogel } 4894e5100ee2SJack F Vogel sbuf_delete(nmbuf); 4895e5100ee2SJack F Vogel 4896e5100ee2SJack F Vogel error = sbuf_finish(buf); 4897e5100ee2SJack F Vogel if (error) { 4898e5100ee2SJack F Vogel device_printf(dev, "Error finishing sbuf: %d\n", error); 4899e5100ee2SJack F Vogel sbuf_delete(buf); 4900e5100ee2SJack F Vogel return error; 4901e5100ee2SJack F Vogel } 4902e5100ee2SJack F Vogel 4903e5100ee2SJack F Vogel error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req); 4904e5100ee2SJack F Vogel if (error) 4905e5100ee2SJack F Vogel device_printf(dev, "sysctl error: %d\n", error); 4906e5100ee2SJack F Vogel sbuf_delete(buf); 4907e5100ee2SJack F Vogel 4908e5100ee2SJack F Vogel return (error); 490961ae650dSJack F Vogel } 491061ae650dSJack F Vogel 491161ae650dSJack F Vogel /* 491261ae650dSJack F Vogel ** Dump TX desc given index. 491361ae650dSJack F Vogel ** Doesn't work; don't use. 491461ae650dSJack F Vogel ** TODO: Also needs a queue index input! 491561ae650dSJack F Vogel **/ 491661ae650dSJack F Vogel static int 491761ae650dSJack F Vogel ixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS) 491861ae650dSJack F Vogel { 491961ae650dSJack F Vogel struct ixl_pf *pf = (struct ixl_pf *)arg1; 492061ae650dSJack F Vogel device_t dev = pf->dev; 492161ae650dSJack F Vogel struct sbuf *buf; 492261ae650dSJack F Vogel int error = 0; 492361ae650dSJack F Vogel 492461ae650dSJack F Vogel u16 desc_idx = 0; 492561ae650dSJack F Vogel 492661ae650dSJack F Vogel buf = sbuf_new_for_sysctl(NULL, NULL, 0, req); 492761ae650dSJack F Vogel if (!buf) { 492861ae650dSJack F Vogel device_printf(dev, "Could not allocate sbuf for output.\n"); 492961ae650dSJack F Vogel return (ENOMEM); 493061ae650dSJack F Vogel } 493161ae650dSJack F Vogel 493261ae650dSJack F Vogel /* Read in index */ 493361ae650dSJack F Vogel error = sysctl_handle_int(oidp, &desc_idx, 0, req); 493461ae650dSJack F Vogel if (error) 493561ae650dSJack F Vogel return (error); 493661ae650dSJack F Vogel if (req->newptr == NULL) 493761ae650dSJack F Vogel return (EIO); // fix 493861ae650dSJack F Vogel if (desc_idx > 1024) { // fix 493961ae650dSJack F Vogel device_printf(dev, 494061ae650dSJack F Vogel "Invalid descriptor index, needs to be < 1024\n"); // fix 494161ae650dSJack F Vogel return (EINVAL); 494261ae650dSJack F Vogel } 494361ae650dSJack F Vogel 494461ae650dSJack F Vogel // Don't use this sysctl yet 494561ae650dSJack F Vogel if (TRUE) 494661ae650dSJack F Vogel return (ENODEV); 494761ae650dSJack F Vogel 494861ae650dSJack F Vogel sbuf_cat(buf, "\n"); 494961ae650dSJack F Vogel 495061ae650dSJack F Vogel // set to queue 1? 495161ae650dSJack F Vogel struct ixl_queue *que = pf->vsi.queues; 495261ae650dSJack F Vogel struct tx_ring *txr = &(que[1].txr); 495361ae650dSJack F Vogel struct i40e_tx_desc *txd = &txr->base[desc_idx]; 495461ae650dSJack F Vogel 495561ae650dSJack F Vogel sbuf_printf(buf, "Que: %d, Desc: %d\n", que->me, desc_idx); 495661ae650dSJack F Vogel sbuf_printf(buf, "Addr: %#18lx\n", txd->buffer_addr); 495761ae650dSJack F Vogel sbuf_printf(buf, "Opts: %#18lx\n", txd->cmd_type_offset_bsz); 495861ae650dSJack F Vogel 495961ae650dSJack F Vogel error = sbuf_finish(buf); 496061ae650dSJack F Vogel if (error) { 496161ae650dSJack F Vogel device_printf(dev, "Error finishing sbuf: %d\n", error); 496261ae650dSJack F Vogel sbuf_delete(buf); 496361ae650dSJack F Vogel return error; 496461ae650dSJack F Vogel } 496561ae650dSJack F Vogel 496661ae650dSJack F Vogel error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req); 496761ae650dSJack F Vogel if (error) 496861ae650dSJack F Vogel device_printf(dev, "sysctl error: %d\n", error); 496961ae650dSJack F Vogel sbuf_delete(buf); 497061ae650dSJack F Vogel return error; 497161ae650dSJack F Vogel } 4972393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */ 497361ae650dSJack F Vogel 4974