ixl_pf_main.c revision 299556
1266423Sjfv/****************************************************************************** 2266423Sjfv 3279033Sjfv Copyright (c) 2013-2015, Intel Corporation 4266423Sjfv All rights reserved. 5266423Sjfv 6266423Sjfv Redistribution and use in source and binary forms, with or without 7266423Sjfv modification, are permitted provided that the following conditions are met: 8266423Sjfv 9266423Sjfv 1. Redistributions of source code must retain the above copyright notice, 10266423Sjfv this list of conditions and the following disclaimer. 11266423Sjfv 12266423Sjfv 2. Redistributions in binary form must reproduce the above copyright 13266423Sjfv notice, this list of conditions and the following disclaimer in the 14266423Sjfv documentation and/or other materials provided with the distribution. 15266423Sjfv 16266423Sjfv 3. Neither the name of the Intel Corporation nor the names of its 17266423Sjfv contributors may be used to endorse or promote products derived from 18266423Sjfv this software without specific prior written permission. 19266423Sjfv 20266423Sjfv THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21266423Sjfv AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22266423Sjfv IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23266423Sjfv ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24266423Sjfv LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25266423Sjfv CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26266423Sjfv SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27266423Sjfv INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28266423Sjfv CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29266423Sjfv ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30266423Sjfv POSSIBILITY OF SUCH DAMAGE. 31266423Sjfv 32266423Sjfv******************************************************************************/ 33266423Sjfv/*$FreeBSD: head/sys/dev/ixl/if_ixl.c 299556 2016-05-12 18:22:34Z erj $*/ 34266423Sjfv 35279033Sjfv#ifndef IXL_STANDALONE_BUILD 36266423Sjfv#include "opt_inet.h" 37266423Sjfv#include "opt_inet6.h" 38277084Sjfv#include "opt_rss.h" 39279033Sjfv#endif 40279033Sjfv 41270346Sjfv#include "ixl.h" 42270346Sjfv#include "ixl_pf.h" 43269198Sjfv 44277262Sjfv#ifdef RSS 45277262Sjfv#include <net/rss_config.h> 46277262Sjfv#endif 47277262Sjfv 48266423Sjfv/********************************************************************* 49266423Sjfv * Driver version 50266423Sjfv *********************************************************************/ 51299555Serjchar ixl_driver_version[] = "1.4.27-k"; 52266423Sjfv 53266423Sjfv/********************************************************************* 54266423Sjfv * PCI Device ID Table 55266423Sjfv * 56266423Sjfv * Used by probe to select devices to load on 57270346Sjfv * Last field stores an index into ixl_strings 58266423Sjfv * Last entry must be all 0s 59266423Sjfv * 60266423Sjfv * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 61266423Sjfv *********************************************************************/ 62266423Sjfv 63270346Sjfvstatic ixl_vendor_info_t ixl_vendor_info_array[] = 64266423Sjfv{ 65266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0}, 66266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0}, 67266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0}, 68266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0}, 69266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0}, 70266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0}, 71270346Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0}, 72284049Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0}, 73266423Sjfv /* required last entry */ 74266423Sjfv {0, 0, 0, 0, 0} 75266423Sjfv}; 76266423Sjfv 77266423Sjfv/********************************************************************* 78266423Sjfv * Table of branding strings 79266423Sjfv *********************************************************************/ 80266423Sjfv 81270346Sjfvstatic char *ixl_strings[] = { 82266423Sjfv "Intel(R) Ethernet Connection XL710 Driver" 83266423Sjfv}; 84266423Sjfv 85266423Sjfv 86266423Sjfv/********************************************************************* 87266423Sjfv * Function prototypes 88266423Sjfv *********************************************************************/ 89270346Sjfvstatic int ixl_probe(device_t); 90270346Sjfvstatic int ixl_attach(device_t); 91270346Sjfvstatic int ixl_detach(device_t); 92270346Sjfvstatic int ixl_shutdown(device_t); 93270346Sjfvstatic int ixl_get_hw_capabilities(struct ixl_pf *); 94270346Sjfvstatic void ixl_cap_txcsum_tso(struct ixl_vsi *, struct ifnet *, int); 95270346Sjfvstatic int ixl_ioctl(struct ifnet *, u_long, caddr_t); 96270346Sjfvstatic void ixl_init(void *); 97270346Sjfvstatic void ixl_init_locked(struct ixl_pf *); 98270346Sjfvstatic void ixl_stop(struct ixl_pf *); 99299547Serjstatic void ixl_stop_locked(struct ixl_pf *); 100270346Sjfvstatic void ixl_media_status(struct ifnet *, struct ifmediareq *); 101270346Sjfvstatic int ixl_media_change(struct ifnet *); 102270346Sjfvstatic void ixl_update_link_status(struct ixl_pf *); 103270346Sjfvstatic int ixl_allocate_pci_resources(struct ixl_pf *); 104270346Sjfvstatic u16 ixl_get_bus_info(struct i40e_hw *, device_t); 105270346Sjfvstatic int ixl_setup_stations(struct ixl_pf *); 106279033Sjfvstatic int ixl_switch_config(struct ixl_pf *); 107270346Sjfvstatic int ixl_initialize_vsi(struct ixl_vsi *); 108299553Serj 109299553Serjstatic int ixl_setup_adminq_msix(struct ixl_pf *); 110299553Serjstatic int ixl_setup_adminq_tq(struct ixl_pf *); 111299553Serjstatic int ixl_setup_queue_msix(struct ixl_vsi *); 112299553Serjstatic int ixl_setup_queue_tqs(struct ixl_vsi *); 113299553Serjstatic int ixl_teardown_adminq_msix(struct ixl_pf *); 114299553Serjstatic int ixl_teardown_queue_msix(struct ixl_vsi *); 115299553Serjstatic void ixl_configure_intr0_msix(struct ixl_pf *); 116299553Serjstatic void ixl_configure_queue_intr_msix(struct ixl_pf *); 117299553Serjstatic void ixl_free_queue_tqs(struct ixl_vsi *); 118299553Serjstatic void ixl_free_adminq_tq(struct ixl_pf *); 119299553Serj 120270346Sjfvstatic int ixl_assign_vsi_legacy(struct ixl_pf *); 121270346Sjfvstatic int ixl_init_msix(struct ixl_pf *); 122270346Sjfvstatic void ixl_configure_itr(struct ixl_pf *); 123270346Sjfvstatic void ixl_configure_legacy(struct ixl_pf *); 124270346Sjfvstatic void ixl_free_pci_resources(struct ixl_pf *); 125270346Sjfvstatic void ixl_local_timer(void *); 126270346Sjfvstatic int ixl_setup_interface(device_t, struct ixl_vsi *); 127279858Sjfvstatic void ixl_link_event(struct ixl_pf *, struct i40e_arq_event_info *); 128270346Sjfvstatic void ixl_config_rss(struct ixl_vsi *); 129270346Sjfvstatic void ixl_set_queue_rx_itr(struct ixl_queue *); 130270346Sjfvstatic void ixl_set_queue_tx_itr(struct ixl_queue *); 131274205Sjfvstatic int ixl_set_advertised_speeds(struct ixl_pf *, int); 132299553Serjstatic void ixl_get_initial_advertised_speeds(struct ixl_pf *); 133266423Sjfv 134279858Sjfvstatic int ixl_enable_rings(struct ixl_vsi *); 135279858Sjfvstatic int ixl_disable_rings(struct ixl_vsi *); 136279858Sjfvstatic void ixl_enable_intr(struct ixl_vsi *); 137279858Sjfvstatic void ixl_disable_intr(struct ixl_vsi *); 138279858Sjfvstatic void ixl_disable_rings_intr(struct ixl_vsi *); 139266423Sjfv 140270346Sjfvstatic void ixl_enable_adminq(struct i40e_hw *); 141270346Sjfvstatic void ixl_disable_adminq(struct i40e_hw *); 142270346Sjfvstatic void ixl_enable_queue(struct i40e_hw *, int); 143270346Sjfvstatic void ixl_disable_queue(struct i40e_hw *, int); 144270346Sjfvstatic void ixl_enable_legacy(struct i40e_hw *); 145270346Sjfvstatic void ixl_disable_legacy(struct i40e_hw *); 146266423Sjfv 147270346Sjfvstatic void ixl_set_promisc(struct ixl_vsi *); 148270346Sjfvstatic void ixl_add_multi(struct ixl_vsi *); 149270346Sjfvstatic void ixl_del_multi(struct ixl_vsi *); 150270346Sjfvstatic void ixl_register_vlan(void *, struct ifnet *, u16); 151270346Sjfvstatic void ixl_unregister_vlan(void *, struct ifnet *, u16); 152270346Sjfvstatic void ixl_setup_vlan_filters(struct ixl_vsi *); 153266423Sjfv 154270346Sjfvstatic void ixl_init_filters(struct ixl_vsi *); 155279858Sjfvstatic void ixl_reconfigure_filters(struct ixl_vsi *vsi); 156270346Sjfvstatic void ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan); 157270346Sjfvstatic void ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan); 158270346Sjfvstatic void ixl_add_hw_filters(struct ixl_vsi *, int, int); 159270346Sjfvstatic void ixl_del_hw_filters(struct ixl_vsi *, int); 160270346Sjfvstatic struct ixl_mac_filter * 161270346Sjfv ixl_find_filter(struct ixl_vsi *, u8 *, s16); 162270346Sjfvstatic void ixl_add_mc_filter(struct ixl_vsi *, u8 *); 163279858Sjfvstatic void ixl_free_mac_filters(struct ixl_vsi *vsi); 164266423Sjfv 165299549Serj/* Sysctls*/ 166299549Serjstatic void ixl_add_device_sysctls(struct ixl_pf *); 167279858Sjfv 168299549Serjstatic int ixl_set_flowcntl(SYSCTL_HANDLER_ARGS); 169299549Serjstatic int ixl_set_advertise(SYSCTL_HANDLER_ARGS); 170299549Serjstatic int ixl_current_speed(SYSCTL_HANDLER_ARGS); 171299549Serjstatic int ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS); 172299549Serj 173299549Serj#ifdef IXL_DEBUG_SYSCTL 174299552Serjstatic int ixl_debug_info(SYSCTL_HANDLER_ARGS); 175299552Serjstatic void ixl_print_debug_info(struct ixl_pf *); 176299552Serj 177299549Serjstatic int ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS); 178299549Serjstatic int ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS); 179299549Serjstatic int ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS); 180299549Serjstatic int ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS); 181299549Serjstatic int ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS); 182299549Serj#endif 183299549Serj 184266423Sjfv/* The MSI/X Interrupt handlers */ 185270346Sjfvstatic void ixl_intr(void *); 186270346Sjfvstatic void ixl_msix_que(void *); 187270346Sjfvstatic void ixl_msix_adminq(void *); 188270346Sjfvstatic void ixl_handle_mdd_event(struct ixl_pf *); 189266423Sjfv 190266423Sjfv/* Deferred interrupt tasklets */ 191270346Sjfvstatic void ixl_do_adminq(void *, int); 192266423Sjfv 193266423Sjfv/* Statistics */ 194270346Sjfvstatic void ixl_add_hw_stats(struct ixl_pf *); 195270346Sjfvstatic void ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *, 196266423Sjfv struct sysctl_oid_list *, struct i40e_hw_port_stats *); 197270346Sjfvstatic void ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *, 198266423Sjfv struct sysctl_oid_list *, 199266423Sjfv struct i40e_eth_stats *); 200270346Sjfvstatic void ixl_update_stats_counters(struct ixl_pf *); 201270346Sjfvstatic void ixl_update_eth_stats(struct ixl_vsi *); 202279858Sjfvstatic void ixl_update_vsi_stats(struct ixl_vsi *); 203270346Sjfvstatic void ixl_pf_reset_stats(struct ixl_pf *); 204270346Sjfvstatic void ixl_vsi_reset_stats(struct ixl_vsi *); 205270346Sjfvstatic void ixl_stat_update48(struct i40e_hw *, u32, u32, bool, 206266423Sjfv u64 *, u64 *); 207270346Sjfvstatic void ixl_stat_update32(struct i40e_hw *, u32, bool, 208266423Sjfv u64 *, u64 *); 209299547Serj/* NVM update */ 210299547Serjstatic int ixl_handle_nvmupd_cmd(struct ixl_pf *, struct ifdrv *); 211299553Serjstatic void ixl_handle_empr_reset(struct ixl_pf *); 212299553Serjstatic int ixl_rebuild_hw_structs_after_reset(struct ixl_pf *); 213266423Sjfv 214299554Serj/* Debug helper functions */ 215299554Serj#ifdef IXL_DEBUG 216299554Serjstatic void ixl_print_nvm_cmd(device_t, struct i40e_nvm_access *); 217299554Serj#endif 218266423Sjfv 219279858Sjfv#ifdef PCI_IOV 220279858Sjfvstatic int ixl_adminq_err_to_errno(enum i40e_admin_queue_err err); 221279858Sjfv 222299546Serjstatic int ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t*); 223299546Serjstatic void ixl_iov_uninit(device_t dev); 224279858Sjfvstatic int ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t*); 225279858Sjfv 226279858Sjfvstatic void ixl_handle_vf_msg(struct ixl_pf *, 227279858Sjfv struct i40e_arq_event_info *); 228279858Sjfvstatic void ixl_handle_vflr(void *arg, int pending); 229279858Sjfv 230279858Sjfvstatic void ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf); 231279858Sjfvstatic void ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf); 232279858Sjfv#endif 233279858Sjfv 234266423Sjfv/********************************************************************* 235266423Sjfv * FreeBSD Device Interface Entry Points 236266423Sjfv *********************************************************************/ 237266423Sjfv 238270346Sjfvstatic device_method_t ixl_methods[] = { 239266423Sjfv /* Device interface */ 240270346Sjfv DEVMETHOD(device_probe, ixl_probe), 241270346Sjfv DEVMETHOD(device_attach, ixl_attach), 242270346Sjfv DEVMETHOD(device_detach, ixl_detach), 243270346Sjfv DEVMETHOD(device_shutdown, ixl_shutdown), 244279858Sjfv#ifdef PCI_IOV 245299546Serj DEVMETHOD(pci_iov_init, ixl_iov_init), 246299546Serj DEVMETHOD(pci_iov_uninit, ixl_iov_uninit), 247299546Serj DEVMETHOD(pci_iov_add_vf, ixl_add_vf), 248279858Sjfv#endif 249266423Sjfv {0, 0} 250266423Sjfv}; 251266423Sjfv 252270346Sjfvstatic driver_t ixl_driver = { 253270346Sjfv "ixl", ixl_methods, sizeof(struct ixl_pf), 254266423Sjfv}; 255266423Sjfv 256270346Sjfvdevclass_t ixl_devclass; 257270346SjfvDRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); 258266423Sjfv 259270346SjfvMODULE_DEPEND(ixl, pci, 1, 1, 1); 260270346SjfvMODULE_DEPEND(ixl, ether, 1, 1, 1); 261279860Sjfv#ifdef DEV_NETMAP 262279860SjfvMODULE_DEPEND(ixl, netmap, 1, 1, 1); 263279860Sjfv#endif /* DEV_NETMAP */ 264279860Sjfv 265266423Sjfv/* 266269198Sjfv** Global reset mutex 267269198Sjfv*/ 268270346Sjfvstatic struct mtx ixl_reset_mtx; 269269198Sjfv 270269198Sjfv/* 271270346Sjfv** TUNEABLE PARAMETERS: 272270346Sjfv*/ 273270346Sjfv 274270346Sjfvstatic SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, 275270346Sjfv "IXL driver parameters"); 276270346Sjfv 277270346Sjfv/* 278266423Sjfv * MSIX should be the default for best performance, 279266423Sjfv * but this allows it to be forced off for testing. 280266423Sjfv */ 281270346Sjfvstatic int ixl_enable_msix = 1; 282270346SjfvTUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); 283270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, 284270346Sjfv "Enable MSI-X interrupts"); 285266423Sjfv 286266423Sjfv/* 287266423Sjfv** Number of descriptors per ring: 288266423Sjfv** - TX and RX are the same size 289266423Sjfv*/ 290270346Sjfvstatic int ixl_ringsz = DEFAULT_RING; 291270346SjfvTUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz); 292270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN, 293270346Sjfv &ixl_ringsz, 0, "Descriptor Ring Size"); 294266423Sjfv 295266423Sjfv/* 296266423Sjfv** This can be set manually, if left as 0 the 297266423Sjfv** number of queues will be calculated based 298266423Sjfv** on cpus and msix vectors available. 299266423Sjfv*/ 300270346Sjfvint ixl_max_queues = 0; 301270346SjfvTUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues); 302270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN, 303270346Sjfv &ixl_max_queues, 0, "Number of Queues"); 304266423Sjfv 305266423Sjfv/* 306266423Sjfv** Controls for Interrupt Throttling 307266423Sjfv** - true/false for dynamic adjustment 308266423Sjfv** - default values for static ITR 309266423Sjfv*/ 310299554Serjint ixl_dynamic_rx_itr = 1; 311270346SjfvTUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr); 312270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, 313270346Sjfv &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); 314266423Sjfv 315299554Serjint ixl_dynamic_tx_itr = 1; 316270346SjfvTUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr); 317270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, 318270346Sjfv &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); 319266423Sjfv 320270346Sjfvint ixl_rx_itr = IXL_ITR_8K; 321270346SjfvTUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr); 322270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, 323270346Sjfv &ixl_rx_itr, 0, "RX Interrupt Rate"); 324270346Sjfv 325270346Sjfvint ixl_tx_itr = IXL_ITR_4K; 326270346SjfvTUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); 327270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, 328270346Sjfv &ixl_tx_itr, 0, "TX Interrupt Rate"); 329270346Sjfv 330270346Sjfv#ifdef IXL_FDIR 331270346Sjfvstatic int ixl_enable_fdir = 1; 332270346SjfvTUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir); 333266423Sjfv/* Rate at which we sample */ 334270346Sjfvint ixl_atr_rate = 20; 335270346SjfvTUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate); 336266423Sjfv#endif 337266423Sjfv 338279860Sjfv#ifdef DEV_NETMAP 339279860Sjfv#define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */ 340279860Sjfv#include <dev/netmap/if_ixl_netmap.h> 341279860Sjfv#endif /* DEV_NETMAP */ 342274205Sjfv 343270346Sjfvstatic char *ixl_fc_string[6] = { 344266423Sjfv "None", 345266423Sjfv "Rx", 346266423Sjfv "Tx", 347266423Sjfv "Full", 348266423Sjfv "Priority", 349266423Sjfv "Default" 350266423Sjfv}; 351266423Sjfv 352279858Sjfvstatic MALLOC_DEFINE(M_IXL, "ixl", "ixl driver allocations"); 353269198Sjfv 354279858Sjfvstatic uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] = 355279858Sjfv {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 356279858Sjfv 357266423Sjfv/********************************************************************* 358266423Sjfv * Device identification routine 359266423Sjfv * 360270346Sjfv * ixl_probe determines if the driver should be loaded on 361266423Sjfv * the hardware based on PCI vendor/device id of the device. 362266423Sjfv * 363266423Sjfv * return BUS_PROBE_DEFAULT on success, positive on failure 364266423Sjfv *********************************************************************/ 365266423Sjfv 366266423Sjfvstatic int 367270346Sjfvixl_probe(device_t dev) 368266423Sjfv{ 369270346Sjfv ixl_vendor_info_t *ent; 370266423Sjfv 371266423Sjfv u16 pci_vendor_id, pci_device_id; 372266423Sjfv u16 pci_subvendor_id, pci_subdevice_id; 373266423Sjfv char device_name[256]; 374269198Sjfv static bool lock_init = FALSE; 375266423Sjfv 376299552Serj#if 0 377270346Sjfv INIT_DEBUGOUT("ixl_probe: begin"); 378299552Serj#endif 379266423Sjfv pci_vendor_id = pci_get_vendor(dev); 380266423Sjfv if (pci_vendor_id != I40E_INTEL_VENDOR_ID) 381266423Sjfv return (ENXIO); 382266423Sjfv 383266423Sjfv pci_device_id = pci_get_device(dev); 384266423Sjfv pci_subvendor_id = pci_get_subvendor(dev); 385266423Sjfv pci_subdevice_id = pci_get_subdevice(dev); 386266423Sjfv 387270346Sjfv ent = ixl_vendor_info_array; 388266423Sjfv while (ent->vendor_id != 0) { 389266423Sjfv if ((pci_vendor_id == ent->vendor_id) && 390266423Sjfv (pci_device_id == ent->device_id) && 391266423Sjfv 392266423Sjfv ((pci_subvendor_id == ent->subvendor_id) || 393266423Sjfv (ent->subvendor_id == 0)) && 394266423Sjfv 395266423Sjfv ((pci_subdevice_id == ent->subdevice_id) || 396266423Sjfv (ent->subdevice_id == 0))) { 397266423Sjfv sprintf(device_name, "%s, Version - %s", 398270346Sjfv ixl_strings[ent->index], 399270346Sjfv ixl_driver_version); 400266423Sjfv device_set_desc_copy(dev, device_name); 401269198Sjfv /* One shot mutex init */ 402269198Sjfv if (lock_init == FALSE) { 403269198Sjfv lock_init = TRUE; 404270346Sjfv mtx_init(&ixl_reset_mtx, 405270346Sjfv "ixl_reset", 406270346Sjfv "IXL RESET Lock", MTX_DEF); 407269198Sjfv } 408266423Sjfv return (BUS_PROBE_DEFAULT); 409266423Sjfv } 410266423Sjfv ent++; 411266423Sjfv } 412266423Sjfv return (ENXIO); 413266423Sjfv} 414266423Sjfv 415266423Sjfv/********************************************************************* 416266423Sjfv * Device initialization routine 417266423Sjfv * 418266423Sjfv * The attach entry point is called when the driver is being loaded. 419266423Sjfv * This routine identifies the type of hardware, allocates all resources 420266423Sjfv * and initializes the hardware. 421266423Sjfv * 422266423Sjfv * return 0 on success, positive on failure 423266423Sjfv *********************************************************************/ 424266423Sjfv 425266423Sjfvstatic int 426270346Sjfvixl_attach(device_t dev) 427266423Sjfv{ 428270346Sjfv struct ixl_pf *pf; 429266423Sjfv struct i40e_hw *hw; 430299552Serj struct ixl_vsi *vsi; 431266423Sjfv u16 bus; 432266423Sjfv int error = 0; 433279858Sjfv#ifdef PCI_IOV 434279858Sjfv nvlist_t *pf_schema, *vf_schema; 435279858Sjfv int iov_error; 436279858Sjfv#endif 437266423Sjfv 438270346Sjfv INIT_DEBUGOUT("ixl_attach: begin"); 439266423Sjfv 440266423Sjfv /* Allocate, clear, and link in our primary soft structure */ 441266423Sjfv pf = device_get_softc(dev); 442266423Sjfv pf->dev = pf->osdep.dev = dev; 443266423Sjfv hw = &pf->hw; 444266423Sjfv 445266423Sjfv /* 446266423Sjfv ** Note this assumes we have a single embedded VSI, 447266423Sjfv ** this could be enhanced later to allocate multiple 448266423Sjfv */ 449266423Sjfv vsi = &pf->vsi; 450266423Sjfv vsi->dev = pf->dev; 451266423Sjfv 452266423Sjfv /* Core Lock Init*/ 453270346Sjfv IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev)); 454266423Sjfv 455266423Sjfv /* Set up the timer callout */ 456266423Sjfv callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); 457266423Sjfv 458274205Sjfv /* Save off the PCI information */ 459266423Sjfv hw->vendor_id = pci_get_vendor(dev); 460266423Sjfv hw->device_id = pci_get_device(dev); 461266423Sjfv hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 462266423Sjfv hw->subsystem_vendor_id = 463266423Sjfv pci_read_config(dev, PCIR_SUBVEND_0, 2); 464266423Sjfv hw->subsystem_device_id = 465266423Sjfv pci_read_config(dev, PCIR_SUBDEV_0, 2); 466266423Sjfv 467269198Sjfv hw->bus.device = pci_get_slot(dev); 468266423Sjfv hw->bus.func = pci_get_function(dev); 469266423Sjfv 470279858Sjfv pf->vc_debug_lvl = 1; 471279858Sjfv 472266423Sjfv /* Do PCI setup - map BAR0, etc */ 473270346Sjfv if (ixl_allocate_pci_resources(pf)) { 474266423Sjfv device_printf(dev, "Allocation of PCI resources failed\n"); 475266423Sjfv error = ENXIO; 476266423Sjfv goto err_out; 477266423Sjfv } 478266423Sjfv 479266423Sjfv /* Establish a clean starting point */ 480269198Sjfv i40e_clear_hw(hw); 481266423Sjfv error = i40e_pf_reset(hw); 482266423Sjfv if (error) { 483299549Serj device_printf(dev, "PF reset failure %d\n", error); 484269198Sjfv error = EIO; 485269198Sjfv goto err_out; 486269198Sjfv } 487266423Sjfv 488266423Sjfv /* Set admin queue parameters */ 489270346Sjfv hw->aq.num_arq_entries = IXL_AQ_LEN; 490270346Sjfv hw->aq.num_asq_entries = IXL_AQ_LEN; 491270346Sjfv hw->aq.arq_buf_size = IXL_AQ_BUFSZ; 492270346Sjfv hw->aq.asq_buf_size = IXL_AQ_BUFSZ; 493266423Sjfv 494299549Serj /* Initialize mac filter list for VSI */ 495299549Serj SLIST_INIT(&vsi->ftl); 496299549Serj 497266423Sjfv /* Initialize the shared code */ 498266423Sjfv error = i40e_init_shared_code(hw); 499266423Sjfv if (error) { 500299549Serj device_printf(dev, "Unable to initialize shared code, error %d\n", 501299549Serj error); 502266423Sjfv error = EIO; 503266423Sjfv goto err_out; 504266423Sjfv } 505266423Sjfv 506266423Sjfv /* Set up the admin queue */ 507266423Sjfv error = i40e_init_adminq(hw); 508299549Serj if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) { 509299549Serj device_printf(dev, "Unable to initialize Admin Queue, error %d\n", 510299549Serj error); 511299549Serj error = EIO; 512299549Serj goto err_out; 513299549Serj } 514299552Serj ixl_print_nvm_version(pf); 515299552Serj 516299549Serj if (error == I40E_ERR_FIRMWARE_API_VERSION) { 517269198Sjfv device_printf(dev, "The driver for the device stopped " 518269198Sjfv "because the NVM image is newer than expected.\n" 519269198Sjfv "You must install the most recent version of " 520299549Serj "the network driver.\n"); 521299549Serj error = EIO; 522266423Sjfv goto err_out; 523266423Sjfv } 524266423Sjfv 525269198Sjfv if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 526269198Sjfv hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) 527269198Sjfv device_printf(dev, "The driver for the device detected " 528269198Sjfv "a newer version of the NVM image than expected.\n" 529269198Sjfv "Please install the most recent version of the network driver.\n"); 530269198Sjfv else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || 531269198Sjfv hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) 532269198Sjfv device_printf(dev, "The driver for the device detected " 533269198Sjfv "an older version of the NVM image than expected.\n" 534269198Sjfv "Please update the NVM image.\n"); 535266423Sjfv 536266423Sjfv /* Clear PXE mode */ 537266423Sjfv i40e_clear_pxe_mode(hw); 538266423Sjfv 539266423Sjfv /* Get capabilities from the device */ 540270346Sjfv error = ixl_get_hw_capabilities(pf); 541266423Sjfv if (error) { 542266423Sjfv device_printf(dev, "HW capabilities failure!\n"); 543266423Sjfv goto err_get_cap; 544266423Sjfv } 545266423Sjfv 546266423Sjfv /* Set up host memory cache */ 547279858Sjfv error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 548279858Sjfv hw->func_caps.num_rx_qp, 0, 0); 549266423Sjfv if (error) { 550266423Sjfv device_printf(dev, "init_lan_hmc failed: %d\n", error); 551266423Sjfv goto err_get_cap; 552266423Sjfv } 553266423Sjfv 554266423Sjfv error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 555266423Sjfv if (error) { 556266423Sjfv device_printf(dev, "configure_lan_hmc failed: %d\n", error); 557266423Sjfv goto err_mac_hmc; 558266423Sjfv } 559266423Sjfv 560299555Serj /* Disable LLDP from the firmware for certain NVM versions */ 561299555Serj if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || 562299555Serj (pf->hw.aq.fw_maj_ver < 4)) 563299555Serj i40e_aq_stop_lldp(hw, TRUE, NULL); 564269198Sjfv 565266423Sjfv i40e_get_mac_addr(hw, hw->mac.addr); 566266423Sjfv error = i40e_validate_mac_addr(hw->mac.addr); 567266423Sjfv if (error) { 568266423Sjfv device_printf(dev, "validate_mac_addr failed: %d\n", error); 569266423Sjfv goto err_mac_hmc; 570266423Sjfv } 571266423Sjfv bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 572266423Sjfv i40e_get_port_mac_addr(hw, hw->mac.port_addr); 573266423Sjfv 574274205Sjfv /* Set up VSI and queues */ 575270346Sjfv if (ixl_setup_stations(pf) != 0) { 576266423Sjfv device_printf(dev, "setup stations failed!\n"); 577266423Sjfv error = ENOMEM; 578266423Sjfv goto err_mac_hmc; 579266423Sjfv } 580266423Sjfv 581279033Sjfv if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 582279033Sjfv (hw->aq.fw_maj_ver < 4)) { 583279033Sjfv i40e_msec_delay(75); 584279033Sjfv error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 585299547Serj if (error) { 586279033Sjfv device_printf(dev, "link restart failed, aq_err=%d\n", 587279033Sjfv pf->hw.aq.asq_last_status); 588299547Serj goto err_late; 589299547Serj } 590270346Sjfv } 591279033Sjfv 592266423Sjfv /* Determine link state */ 593299547Serj hw->phy.get_link_info = TRUE; 594284049Sjfv i40e_get_link_status(hw, &pf->link_up); 595266423Sjfv 596299547Serj /* Setup OS network interface / ifnet */ 597274205Sjfv if (ixl_setup_interface(dev, vsi) != 0) { 598274205Sjfv device_printf(dev, "interface setup failed!\n"); 599274205Sjfv error = EIO; 600266423Sjfv goto err_late; 601274205Sjfv } 602266423Sjfv 603279033Sjfv error = ixl_switch_config(pf); 604279033Sjfv if (error) { 605299553Serj device_printf(dev, "Initial ixl_switch_config() failed: %d\n", 606299553Serj error); 607299546Serj goto err_late; 608279033Sjfv } 609279033Sjfv 610299547Serj /* Limit PHY interrupts to link, autoneg, and modules failure */ 611299548Serj error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, 612299547Serj NULL); 613299547Serj if (error) { 614299547Serj device_printf(dev, "i40e_aq_set_phy_mask() failed: err %d," 615299547Serj " aq_err %d\n", error, hw->aq.asq_last_status); 616299547Serj goto err_late; 617299547Serj } 618279033Sjfv 619299553Serj /* Get the bus configuration and set the shared code's config */ 620270346Sjfv bus = ixl_get_bus_info(hw, dev); 621266423Sjfv i40e_set_pci_config_data(hw, bus); 622266423Sjfv 623299553Serj /* 624299553Serj * In MSI-X mode, initialize the Admin Queue interrupt, 625299553Serj * so userland tools can communicate with the adapter regardless of 626299553Serj * the ifnet interface's status. 627299553Serj */ 628299553Serj if (pf->msix > 1) { 629299553Serj error = ixl_setup_adminq_msix(pf); 630299553Serj if (error) { 631299553Serj device_printf(dev, "ixl_setup_adminq_msix error: %d\n", 632299553Serj error); 633299553Serj goto err_late; 634299553Serj } 635299553Serj error = ixl_setup_adminq_tq(pf); 636299553Serj if (error) { 637299553Serj device_printf(dev, "ixl_setup_adminq_tq error: %d\n", 638299553Serj error); 639299553Serj goto err_late; 640299553Serj } 641299553Serj ixl_configure_intr0_msix(pf); 642299553Serj ixl_enable_adminq(hw); 643299553Serj } 644299546Serj 645299549Serj /* Initialize statistics & add sysctls */ 646299549Serj ixl_add_device_sysctls(pf); 647299549Serj 648270346Sjfv ixl_pf_reset_stats(pf); 649270346Sjfv ixl_update_stats_counters(pf); 650270346Sjfv ixl_add_hw_stats(pf); 651266423Sjfv 652266423Sjfv /* Register for VLAN events */ 653266423Sjfv vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 654270346Sjfv ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); 655266423Sjfv vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 656270346Sjfv ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); 657266423Sjfv 658279858Sjfv#ifdef PCI_IOV 659279858Sjfv /* SR-IOV is only supported when MSI-X is in use. */ 660279858Sjfv if (pf->msix > 1) { 661279858Sjfv pf_schema = pci_iov_schema_alloc_node(); 662279858Sjfv vf_schema = pci_iov_schema_alloc_node(); 663279858Sjfv pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); 664279858Sjfv pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", 665279858Sjfv IOV_SCHEMA_HASDEFAULT, TRUE); 666279858Sjfv pci_iov_schema_add_bool(vf_schema, "allow-set-mac", 667279858Sjfv IOV_SCHEMA_HASDEFAULT, FALSE); 668279858Sjfv pci_iov_schema_add_bool(vf_schema, "allow-promisc", 669279858Sjfv IOV_SCHEMA_HASDEFAULT, FALSE); 670274205Sjfv 671279858Sjfv iov_error = pci_iov_attach(dev, pf_schema, vf_schema); 672299552Serj if (iov_error != 0) { 673279858Sjfv device_printf(dev, 674279858Sjfv "Failed to initialize SR-IOV (error=%d)\n", 675279858Sjfv iov_error); 676299552Serj } else 677299552Serj device_printf(dev, "SR-IOV ready\n"); 678279858Sjfv } 679279858Sjfv#endif 680279858Sjfv 681279860Sjfv#ifdef DEV_NETMAP 682279860Sjfv ixl_netmap_attach(vsi); 683279860Sjfv#endif /* DEV_NETMAP */ 684270346Sjfv INIT_DEBUGOUT("ixl_attach: end"); 685266423Sjfv return (0); 686266423Sjfv 687266423Sjfverr_late: 688274205Sjfv if (vsi->ifp != NULL) 689274205Sjfv if_free(vsi->ifp); 690266423Sjfverr_mac_hmc: 691266423Sjfv i40e_shutdown_lan_hmc(hw); 692266423Sjfverr_get_cap: 693266423Sjfv i40e_shutdown_adminq(hw); 694266423Sjfverr_out: 695270346Sjfv ixl_free_pci_resources(pf); 696274205Sjfv ixl_free_vsi(vsi); 697270346Sjfv IXL_PF_LOCK_DESTROY(pf); 698266423Sjfv return (error); 699266423Sjfv} 700266423Sjfv 701266423Sjfv/********************************************************************* 702266423Sjfv * Device removal routine 703266423Sjfv * 704266423Sjfv * The detach entry point is called when the driver is being removed. 705266423Sjfv * This routine stops the adapter and deallocates all the resources 706266423Sjfv * that were allocated for driver operation. 707266423Sjfv * 708266423Sjfv * return 0 on success, positive on failure 709266423Sjfv *********************************************************************/ 710266423Sjfv 711266423Sjfvstatic int 712270346Sjfvixl_detach(device_t dev) 713266423Sjfv{ 714270346Sjfv struct ixl_pf *pf = device_get_softc(dev); 715266423Sjfv struct i40e_hw *hw = &pf->hw; 716270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 717299553Serj enum i40e_status_code status; 718279858Sjfv#ifdef PCI_IOV 719279858Sjfv int error; 720279858Sjfv#endif 721266423Sjfv 722270346Sjfv INIT_DEBUGOUT("ixl_detach: begin"); 723266423Sjfv 724266423Sjfv /* Make sure VLANS are not using driver */ 725266423Sjfv if (vsi->ifp->if_vlantrunk != NULL) { 726299553Serj device_printf(dev, "Vlan in use, detach first\n"); 727266423Sjfv return (EBUSY); 728266423Sjfv } 729266423Sjfv 730279858Sjfv#ifdef PCI_IOV 731279858Sjfv error = pci_iov_detach(dev); 732279858Sjfv if (error != 0) { 733279858Sjfv device_printf(dev, "SR-IOV in use; detach first.\n"); 734279858Sjfv return (error); 735279858Sjfv } 736279858Sjfv#endif 737279858Sjfv 738279033Sjfv ether_ifdetach(vsi->ifp); 739299547Serj if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) 740279033Sjfv ixl_stop(pf); 741266423Sjfv 742299553Serj ixl_free_queue_tqs(vsi); 743266423Sjfv 744266423Sjfv /* Shutdown LAN HMC */ 745266423Sjfv status = i40e_shutdown_lan_hmc(hw); 746266423Sjfv if (status) 747266423Sjfv device_printf(dev, 748266423Sjfv "Shutdown LAN HMC failed with code %d\n", status); 749266423Sjfv 750266423Sjfv /* Shutdown admin queue */ 751299553Serj ixl_disable_adminq(hw); 752299553Serj ixl_free_adminq_tq(pf); 753299553Serj ixl_teardown_adminq_msix(pf); 754266423Sjfv status = i40e_shutdown_adminq(hw); 755266423Sjfv if (status) 756266423Sjfv device_printf(dev, 757266423Sjfv "Shutdown Admin queue failed with code %d\n", status); 758266423Sjfv 759266423Sjfv /* Unregister VLAN events */ 760266423Sjfv if (vsi->vlan_attach != NULL) 761266423Sjfv EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); 762266423Sjfv if (vsi->vlan_detach != NULL) 763266423Sjfv EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); 764266423Sjfv 765266423Sjfv callout_drain(&pf->timer); 766279860Sjfv#ifdef DEV_NETMAP 767279860Sjfv netmap_detach(vsi->ifp); 768279860Sjfv#endif /* DEV_NETMAP */ 769270346Sjfv ixl_free_pci_resources(pf); 770266423Sjfv bus_generic_detach(dev); 771266423Sjfv if_free(vsi->ifp); 772270346Sjfv ixl_free_vsi(vsi); 773270346Sjfv IXL_PF_LOCK_DESTROY(pf); 774266423Sjfv return (0); 775266423Sjfv} 776266423Sjfv 777266423Sjfv/********************************************************************* 778266423Sjfv * 779266423Sjfv * Shutdown entry point 780266423Sjfv * 781266423Sjfv **********************************************************************/ 782266423Sjfv 783266423Sjfvstatic int 784270346Sjfvixl_shutdown(device_t dev) 785266423Sjfv{ 786270346Sjfv struct ixl_pf *pf = device_get_softc(dev); 787270346Sjfv ixl_stop(pf); 788266423Sjfv return (0); 789266423Sjfv} 790266423Sjfv 791266423Sjfv 792266423Sjfv/********************************************************************* 793266423Sjfv * 794266423Sjfv * Get the hardware capabilities 795266423Sjfv * 796266423Sjfv **********************************************************************/ 797266423Sjfv 798266423Sjfvstatic int 799270346Sjfvixl_get_hw_capabilities(struct ixl_pf *pf) 800266423Sjfv{ 801266423Sjfv struct i40e_aqc_list_capabilities_element_resp *buf; 802266423Sjfv struct i40e_hw *hw = &pf->hw; 803266423Sjfv device_t dev = pf->dev; 804266423Sjfv int error, len; 805266423Sjfv u16 needed; 806266423Sjfv bool again = TRUE; 807266423Sjfv 808266423Sjfv len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); 809266423Sjfvretry: 810266423Sjfv if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *) 811266423Sjfv malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) { 812266423Sjfv device_printf(dev, "Unable to allocate cap memory\n"); 813266423Sjfv return (ENOMEM); 814266423Sjfv } 815266423Sjfv 816266423Sjfv /* This populates the hw struct */ 817266423Sjfv error = i40e_aq_discover_capabilities(hw, buf, len, 818266423Sjfv &needed, i40e_aqc_opc_list_func_capabilities, NULL); 819266423Sjfv free(buf, M_DEVBUF); 820266423Sjfv if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && 821266423Sjfv (again == TRUE)) { 822266423Sjfv /* retry once with a larger buffer */ 823266423Sjfv again = FALSE; 824266423Sjfv len = needed; 825266423Sjfv goto retry; 826266423Sjfv } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { 827266423Sjfv device_printf(dev, "capability discovery failed: %d\n", 828266423Sjfv pf->hw.aq.asq_last_status); 829266423Sjfv return (ENODEV); 830266423Sjfv } 831266423Sjfv 832266423Sjfv /* Capture this PF's starting queue pair */ 833266423Sjfv pf->qbase = hw->func_caps.base_queue; 834266423Sjfv 835270346Sjfv#ifdef IXL_DEBUG 836299553Serj device_printf(dev, "pf_id=%d, num_vfs=%d, msix_pf=%d, " 837266423Sjfv "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", 838266423Sjfv hw->pf_id, hw->func_caps.num_vfs, 839266423Sjfv hw->func_caps.num_msix_vectors, 840266423Sjfv hw->func_caps.num_msix_vectors_vf, 841266423Sjfv hw->func_caps.fd_filters_guaranteed, 842266423Sjfv hw->func_caps.fd_filters_best_effort, 843266423Sjfv hw->func_caps.num_tx_qp, 844266423Sjfv hw->func_caps.num_rx_qp, 845266423Sjfv hw->func_caps.base_queue); 846266423Sjfv#endif 847266423Sjfv return (error); 848266423Sjfv} 849266423Sjfv 850266423Sjfvstatic void 851270346Sjfvixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) 852266423Sjfv{ 853266423Sjfv device_t dev = vsi->dev; 854266423Sjfv 855266423Sjfv /* Enable/disable TXCSUM/TSO4 */ 856266423Sjfv if (!(ifp->if_capenable & IFCAP_TXCSUM) 857266423Sjfv && !(ifp->if_capenable & IFCAP_TSO4)) { 858266423Sjfv if (mask & IFCAP_TXCSUM) { 859266423Sjfv ifp->if_capenable |= IFCAP_TXCSUM; 860266423Sjfv /* enable TXCSUM, restore TSO if previously enabled */ 861270346Sjfv if (vsi->flags & IXL_FLAGS_KEEP_TSO4) { 862270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 863266423Sjfv ifp->if_capenable |= IFCAP_TSO4; 864266423Sjfv } 865266423Sjfv } 866266423Sjfv else if (mask & IFCAP_TSO4) { 867266423Sjfv ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); 868270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 869266423Sjfv device_printf(dev, 870266423Sjfv "TSO4 requires txcsum, enabling both...\n"); 871266423Sjfv } 872266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM) 873266423Sjfv && !(ifp->if_capenable & IFCAP_TSO4)) { 874266423Sjfv if (mask & IFCAP_TXCSUM) 875266423Sjfv ifp->if_capenable &= ~IFCAP_TXCSUM; 876266423Sjfv else if (mask & IFCAP_TSO4) 877266423Sjfv ifp->if_capenable |= IFCAP_TSO4; 878266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM) 879266423Sjfv && (ifp->if_capenable & IFCAP_TSO4)) { 880266423Sjfv if (mask & IFCAP_TXCSUM) { 881270346Sjfv vsi->flags |= IXL_FLAGS_KEEP_TSO4; 882266423Sjfv ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); 883266423Sjfv device_printf(dev, 884266423Sjfv "TSO4 requires txcsum, disabling both...\n"); 885266423Sjfv } else if (mask & IFCAP_TSO4) 886266423Sjfv ifp->if_capenable &= ~IFCAP_TSO4; 887266423Sjfv } 888266423Sjfv 889266423Sjfv /* Enable/disable TXCSUM_IPV6/TSO6 */ 890266423Sjfv if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) 891266423Sjfv && !(ifp->if_capenable & IFCAP_TSO6)) { 892266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) { 893266423Sjfv ifp->if_capenable |= IFCAP_TXCSUM_IPV6; 894270346Sjfv if (vsi->flags & IXL_FLAGS_KEEP_TSO6) { 895270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 896266423Sjfv ifp->if_capenable |= IFCAP_TSO6; 897266423Sjfv } 898266423Sjfv } else if (mask & IFCAP_TSO6) { 899266423Sjfv ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 900270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 901266423Sjfv device_printf(dev, 902266423Sjfv "TSO6 requires txcsum6, enabling both...\n"); 903266423Sjfv } 904266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 905266423Sjfv && !(ifp->if_capenable & IFCAP_TSO6)) { 906266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) 907266423Sjfv ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; 908266423Sjfv else if (mask & IFCAP_TSO6) 909266423Sjfv ifp->if_capenable |= IFCAP_TSO6; 910266423Sjfv } else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 911266423Sjfv && (ifp->if_capenable & IFCAP_TSO6)) { 912266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) { 913270346Sjfv vsi->flags |= IXL_FLAGS_KEEP_TSO6; 914266423Sjfv ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 915266423Sjfv device_printf(dev, 916266423Sjfv "TSO6 requires txcsum6, disabling both...\n"); 917266423Sjfv } else if (mask & IFCAP_TSO6) 918266423Sjfv ifp->if_capenable &= ~IFCAP_TSO6; 919266423Sjfv } 920266423Sjfv} 921266423Sjfv 922266423Sjfv/********************************************************************* 923266423Sjfv * Ioctl entry point 924266423Sjfv * 925270346Sjfv * ixl_ioctl is called when the user wants to configure the 926266423Sjfv * interface. 927266423Sjfv * 928266423Sjfv * return 0 on success, positive on failure 929266423Sjfv **********************************************************************/ 930266423Sjfv 931266423Sjfvstatic int 932270346Sjfvixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 933266423Sjfv{ 934270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 935279858Sjfv struct ixl_pf *pf = vsi->back; 936299547Serj struct ifreq *ifr = (struct ifreq *)data; 937299547Serj struct ifdrv *ifd = (struct ifdrv *)data; 938266423Sjfv#if defined(INET) || defined(INET6) 939266423Sjfv struct ifaddr *ifa = (struct ifaddr *)data; 940266423Sjfv bool avoid_reset = FALSE; 941266423Sjfv#endif 942266423Sjfv int error = 0; 943266423Sjfv 944266423Sjfv switch (command) { 945266423Sjfv 946266423Sjfv case SIOCSIFADDR: 947266423Sjfv#ifdef INET 948266423Sjfv if (ifa->ifa_addr->sa_family == AF_INET) 949266423Sjfv avoid_reset = TRUE; 950266423Sjfv#endif 951266423Sjfv#ifdef INET6 952266423Sjfv if (ifa->ifa_addr->sa_family == AF_INET6) 953266423Sjfv avoid_reset = TRUE; 954266423Sjfv#endif 955266423Sjfv#if defined(INET) || defined(INET6) 956266423Sjfv /* 957266423Sjfv ** Calling init results in link renegotiation, 958266423Sjfv ** so we avoid doing it when possible. 959266423Sjfv */ 960266423Sjfv if (avoid_reset) { 961266423Sjfv ifp->if_flags |= IFF_UP; 962266423Sjfv if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 963270346Sjfv ixl_init(pf); 964271900Sbz#ifdef INET 965266423Sjfv if (!(ifp->if_flags & IFF_NOARP)) 966266423Sjfv arp_ifinit(ifp, ifa); 967271900Sbz#endif 968266423Sjfv } else 969266423Sjfv error = ether_ioctl(ifp, command, data); 970266423Sjfv break; 971266423Sjfv#endif 972266423Sjfv case SIOCSIFMTU: 973266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 974270346Sjfv if (ifr->ifr_mtu > IXL_MAX_FRAME - 975266423Sjfv ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) { 976266423Sjfv error = EINVAL; 977266423Sjfv } else { 978270346Sjfv IXL_PF_LOCK(pf); 979266423Sjfv ifp->if_mtu = ifr->ifr_mtu; 980266423Sjfv vsi->max_frame_size = 981266423Sjfv ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 982266423Sjfv + ETHER_VLAN_ENCAP_LEN; 983270346Sjfv ixl_init_locked(pf); 984270346Sjfv IXL_PF_UNLOCK(pf); 985266423Sjfv } 986266423Sjfv break; 987266423Sjfv case SIOCSIFFLAGS: 988266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 989270346Sjfv IXL_PF_LOCK(pf); 990266423Sjfv if (ifp->if_flags & IFF_UP) { 991266423Sjfv if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 992266423Sjfv if ((ifp->if_flags ^ pf->if_flags) & 993266423Sjfv (IFF_PROMISC | IFF_ALLMULTI)) { 994270346Sjfv ixl_set_promisc(vsi); 995266423Sjfv } 996299547Serj } else { 997299547Serj IXL_PF_UNLOCK(pf); 998299547Serj ixl_init(pf); 999299547Serj IXL_PF_LOCK(pf); 1000299547Serj } 1001299547Serj } else { 1002299547Serj if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1003299547Serj IXL_PF_UNLOCK(pf); 1004270346Sjfv ixl_stop(pf); 1005299547Serj IXL_PF_LOCK(pf); 1006299547Serj } 1007299547Serj } 1008266423Sjfv pf->if_flags = ifp->if_flags; 1009270346Sjfv IXL_PF_UNLOCK(pf); 1010266423Sjfv break; 1011299547Serj case SIOCSDRVSPEC: 1012299547Serj case SIOCGDRVSPEC: 1013299547Serj IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific " 1014299547Serj "Info)\n"); 1015299547Serj 1016299547Serj /* NVM update command */ 1017299547Serj if (ifd->ifd_cmd == I40E_NVM_ACCESS) 1018299547Serj error = ixl_handle_nvmupd_cmd(pf, ifd); 1019299547Serj else 1020299547Serj error = EINVAL; 1021299547Serj break; 1022266423Sjfv case SIOCADDMULTI: 1023266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); 1024266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1025270346Sjfv IXL_PF_LOCK(pf); 1026270346Sjfv ixl_disable_intr(vsi); 1027270346Sjfv ixl_add_multi(vsi); 1028270346Sjfv ixl_enable_intr(vsi); 1029270346Sjfv IXL_PF_UNLOCK(pf); 1030266423Sjfv } 1031266423Sjfv break; 1032266423Sjfv case SIOCDELMULTI: 1033266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); 1034266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1035270346Sjfv IXL_PF_LOCK(pf); 1036270346Sjfv ixl_disable_intr(vsi); 1037270346Sjfv ixl_del_multi(vsi); 1038270346Sjfv ixl_enable_intr(vsi); 1039270346Sjfv IXL_PF_UNLOCK(pf); 1040266423Sjfv } 1041266423Sjfv break; 1042266423Sjfv case SIOCSIFMEDIA: 1043266423Sjfv case SIOCGIFMEDIA: 1044284049Sjfv#ifdef IFM_ETH_XTYPE 1045284049Sjfv case SIOCGIFXMEDIA: 1046284049Sjfv#endif 1047266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 1048266423Sjfv error = ifmedia_ioctl(ifp, ifr, &vsi->media, command); 1049266423Sjfv break; 1050266423Sjfv case SIOCSIFCAP: 1051266423Sjfv { 1052266423Sjfv int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1053266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 1054266423Sjfv 1055270346Sjfv ixl_cap_txcsum_tso(vsi, ifp, mask); 1056266423Sjfv 1057266423Sjfv if (mask & IFCAP_RXCSUM) 1058266423Sjfv ifp->if_capenable ^= IFCAP_RXCSUM; 1059266423Sjfv if (mask & IFCAP_RXCSUM_IPV6) 1060266423Sjfv ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1061266423Sjfv if (mask & IFCAP_LRO) 1062266423Sjfv ifp->if_capenable ^= IFCAP_LRO; 1063266423Sjfv if (mask & IFCAP_VLAN_HWTAGGING) 1064266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1065266423Sjfv if (mask & IFCAP_VLAN_HWFILTER) 1066266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 1067266423Sjfv if (mask & IFCAP_VLAN_HWTSO) 1068266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1069266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1070270346Sjfv IXL_PF_LOCK(pf); 1071270346Sjfv ixl_init_locked(pf); 1072270346Sjfv IXL_PF_UNLOCK(pf); 1073266423Sjfv } 1074266423Sjfv VLAN_CAPABILITIES(ifp); 1075266423Sjfv 1076266423Sjfv break; 1077266423Sjfv } 1078266423Sjfv 1079266423Sjfv default: 1080270346Sjfv IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command); 1081266423Sjfv error = ether_ioctl(ifp, command, data); 1082266423Sjfv break; 1083266423Sjfv } 1084266423Sjfv 1085266423Sjfv return (error); 1086266423Sjfv} 1087266423Sjfv 1088266423Sjfv 1089266423Sjfv/********************************************************************* 1090266423Sjfv * Init entry point 1091266423Sjfv * 1092266423Sjfv * This routine is used in two ways. It is used by the stack as 1093266423Sjfv * init entry point in network interface structure. It is also used 1094266423Sjfv * by the driver as a hw/sw initialization routine to get to a 1095266423Sjfv * consistent state. 1096266423Sjfv * 1097266423Sjfv * return 0 on success, positive on failure 1098266423Sjfv **********************************************************************/ 1099266423Sjfv 1100266423Sjfvstatic void 1101270346Sjfvixl_init_locked(struct ixl_pf *pf) 1102266423Sjfv{ 1103266423Sjfv struct i40e_hw *hw = &pf->hw; 1104270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1105266423Sjfv struct ifnet *ifp = vsi->ifp; 1106266423Sjfv device_t dev = pf->dev; 1107266423Sjfv struct i40e_filter_control_settings filter; 1108266423Sjfv u8 tmpaddr[ETHER_ADDR_LEN]; 1109266423Sjfv int ret; 1110266423Sjfv 1111266423Sjfv mtx_assert(&pf->pf_mtx, MA_OWNED); 1112299554Serj INIT_DEBUGOUT("ixl_init_locked: begin"); 1113266423Sjfv 1114299547Serj ixl_stop_locked(pf); 1115299547Serj 1116266423Sjfv /* Get the latest mac address... User might use a LAA */ 1117266423Sjfv bcopy(IF_LLADDR(vsi->ifp), tmpaddr, 1118266423Sjfv I40E_ETH_LENGTH_OF_ADDRESS); 1119299546Serj if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && 1120299546Serj (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { 1121299546Serj ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); 1122266423Sjfv bcopy(tmpaddr, hw->mac.addr, 1123266423Sjfv I40E_ETH_LENGTH_OF_ADDRESS); 1124266423Sjfv ret = i40e_aq_mac_address_write(hw, 1125266423Sjfv I40E_AQC_WRITE_TYPE_LAA_ONLY, 1126266423Sjfv hw->mac.addr, NULL); 1127266423Sjfv if (ret) { 1128266423Sjfv device_printf(dev, "LLA address" 1129266423Sjfv "change failed!!\n"); 1130266423Sjfv return; 1131266423Sjfv } 1132266423Sjfv } 1133266423Sjfv 1134299551Serj ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); 1135299551Serj 1136266423Sjfv /* Set the various hardware offload abilities */ 1137266423Sjfv ifp->if_hwassist = 0; 1138266423Sjfv if (ifp->if_capenable & IFCAP_TSO) 1139266423Sjfv ifp->if_hwassist |= CSUM_TSO; 1140266423Sjfv if (ifp->if_capenable & IFCAP_TXCSUM) 1141266423Sjfv ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 1142266423Sjfv if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 1143266423Sjfv ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); 1144266423Sjfv 1145266423Sjfv /* Set up the device filtering */ 1146266423Sjfv bzero(&filter, sizeof(filter)); 1147266423Sjfv filter.enable_ethtype = TRUE; 1148266423Sjfv filter.enable_macvlan = TRUE; 1149270346Sjfv#ifdef IXL_FDIR 1150266423Sjfv filter.enable_fdir = TRUE; 1151266423Sjfv#endif 1152299548Serj filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; 1153266423Sjfv if (i40e_set_filter_control(hw, &filter)) 1154299548Serj device_printf(dev, "i40e_set_filter_control() failed\n"); 1155266423Sjfv 1156266423Sjfv /* Set up RSS */ 1157270346Sjfv ixl_config_rss(vsi); 1158266423Sjfv 1159299548Serj /* Prepare the VSI: rings, hmc contexts, etc... */ 1160270346Sjfv if (ixl_initialize_vsi(vsi)) { 1161270346Sjfv device_printf(dev, "initialize vsi failed!!\n"); 1162266423Sjfv return; 1163266423Sjfv } 1164266423Sjfv 1165266423Sjfv /* Add protocol filters to list */ 1166270346Sjfv ixl_init_filters(vsi); 1167266423Sjfv 1168266423Sjfv /* Setup vlan's if needed */ 1169270346Sjfv ixl_setup_vlan_filters(vsi); 1170266423Sjfv 1171266423Sjfv /* Set up MSI/X routing and the ITR settings */ 1172270346Sjfv if (ixl_enable_msix) { 1173299553Serj ixl_configure_queue_intr_msix(pf); 1174270346Sjfv ixl_configure_itr(pf); 1175266423Sjfv } else 1176270346Sjfv ixl_configure_legacy(pf); 1177266423Sjfv 1178270346Sjfv ixl_enable_rings(vsi); 1179266423Sjfv 1180266423Sjfv i40e_aq_set_default_vsi(hw, vsi->seid, NULL); 1181266423Sjfv 1182279858Sjfv ixl_reconfigure_filters(vsi); 1183279858Sjfv 1184266423Sjfv /* And now turn on interrupts */ 1185270346Sjfv ixl_enable_intr(vsi); 1186266423Sjfv 1187299547Serj /* Get link info */ 1188299547Serj hw->phy.get_link_info = TRUE; 1189299547Serj i40e_get_link_status(hw, &pf->link_up); 1190299547Serj ixl_update_link_status(pf); 1191299547Serj 1192299553Serj /* Set initial advertised speed sysctl value */ 1193299553Serj ixl_get_initial_advertised_speeds(pf); 1194299553Serj 1195299548Serj /* Start the local timer */ 1196299548Serj callout_reset(&pf->timer, hz, ixl_local_timer, pf); 1197299548Serj 1198266423Sjfv /* Now inform the stack we're ready */ 1199266423Sjfv ifp->if_drv_flags |= IFF_DRV_RUNNING; 1200266423Sjfv 1201266423Sjfv return; 1202266423Sjfv} 1203266423Sjfv 1204299553Serj/* For the set_advertise sysctl */ 1205299553Serjstatic void 1206299553Serjixl_get_initial_advertised_speeds(struct ixl_pf *pf) 1207299553Serj{ 1208299553Serj struct i40e_hw *hw = &pf->hw; 1209299553Serj device_t dev = pf->dev; 1210299553Serj enum i40e_status_code status; 1211299553Serj struct i40e_aq_get_phy_abilities_resp abilities; 1212299553Serj 1213299553Serj /* Set initial sysctl values */ 1214299553Serj status = i40e_aq_get_phy_capabilities(hw, FALSE, false, &abilities, 1215299553Serj NULL); 1216299553Serj if (status) { 1217299553Serj /* Non-fatal error */ 1218299553Serj device_printf(dev, "%s: i40e_aq_get_phy_capabilities() error %d\n", 1219299553Serj __func__, status); 1220299553Serj return; 1221299553Serj } 1222299553Serj 1223299553Serj if (abilities.link_speed & I40E_LINK_SPEED_40GB) 1224299553Serj pf->advertised_speed |= 0x10; 1225299553Serj if (abilities.link_speed & I40E_LINK_SPEED_20GB) 1226299553Serj pf->advertised_speed |= 0x8; 1227299553Serj if (abilities.link_speed & I40E_LINK_SPEED_10GB) 1228299553Serj pf->advertised_speed |= 0x4; 1229299553Serj if (abilities.link_speed & I40E_LINK_SPEED_1GB) 1230299553Serj pf->advertised_speed |= 0x2; 1231299553Serj if (abilities.link_speed & I40E_LINK_SPEED_100MB) 1232299553Serj pf->advertised_speed |= 0x1; 1233299553Serj} 1234299553Serj 1235299548Serjstatic int 1236299548Serjixl_teardown_hw_structs(struct ixl_pf *pf) 1237299548Serj{ 1238299548Serj enum i40e_status_code status = 0; 1239299548Serj struct i40e_hw *hw = &pf->hw; 1240299548Serj device_t dev = pf->dev; 1241299548Serj 1242299548Serj /* Shutdown LAN HMC */ 1243299548Serj if (hw->hmc.hmc_obj) { 1244299548Serj status = i40e_shutdown_lan_hmc(hw); 1245299548Serj if (status) { 1246299548Serj device_printf(dev, 1247299548Serj "init: LAN HMC shutdown failure; status %d\n", status); 1248299548Serj goto err_out; 1249299548Serj } 1250299548Serj } 1251299548Serj 1252299548Serj // XXX: This gets called when we know the adminq is inactive; 1253299548Serj // so we already know it's setup when we get here. 1254299548Serj 1255299548Serj /* Shutdown admin queue */ 1256299548Serj status = i40e_shutdown_adminq(hw); 1257299548Serj if (status) 1258299548Serj device_printf(dev, 1259299548Serj "init: Admin Queue shutdown failure; status %d\n", status); 1260299548Serj 1261299548Serjerr_out: 1262299548Serj return (status); 1263299548Serj} 1264299548Serj 1265299548Serjstatic int 1266299548Serjixl_reset(struct ixl_pf *pf) 1267299548Serj{ 1268299548Serj struct i40e_hw *hw = &pf->hw; 1269299548Serj device_t dev = pf->dev; 1270299554Serj u8 set_fc_err_mask; 1271299548Serj int error = 0; 1272299548Serj 1273299548Serj // XXX: clear_hw() actually writes to hw registers -- maybe this isn't necessary 1274299548Serj i40e_clear_hw(hw); 1275299548Serj error = i40e_pf_reset(hw); 1276299548Serj if (error) { 1277299548Serj device_printf(dev, "init: PF reset failure"); 1278299548Serj error = EIO; 1279299548Serj goto err_out; 1280299548Serj } 1281299548Serj 1282299548Serj error = i40e_init_adminq(hw); 1283299548Serj if (error) { 1284299554Serj device_printf(dev, "init: Admin queue init failure;" 1285299554Serj " status code %d", error); 1286299548Serj error = EIO; 1287299548Serj goto err_out; 1288299548Serj } 1289299548Serj 1290299548Serj i40e_clear_pxe_mode(hw); 1291299548Serj 1292299548Serj error = ixl_get_hw_capabilities(pf); 1293299548Serj if (error) { 1294299554Serj device_printf(dev, "init: Error retrieving HW capabilities;" 1295299554Serj " status code %d\n", error); 1296299548Serj goto err_out; 1297299548Serj } 1298299548Serj 1299299548Serj error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 1300299548Serj hw->func_caps.num_rx_qp, 0, 0); 1301299548Serj if (error) { 1302299554Serj device_printf(dev, "init: LAN HMC init failed; status code %d\n", 1303299554Serj error); 1304299548Serj error = EIO; 1305299548Serj goto err_out; 1306299548Serj } 1307299548Serj 1308299548Serj error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 1309299548Serj if (error) { 1310299554Serj device_printf(dev, "init: LAN HMC config failed; status code %d\n", 1311299554Serj error); 1312299548Serj error = EIO; 1313299548Serj goto err_out; 1314299548Serj } 1315299548Serj 1316299554Serj // XXX: possible fix for panic, but our failure recovery is still broken 1317299554Serj error = ixl_switch_config(pf); 1318299554Serj if (error) { 1319299554Serj device_printf(dev, "init: ixl_switch_config() failed: %d\n", 1320299554Serj error); 1321299554Serj goto err_out; 1322299554Serj } 1323299548Serj 1324299548Serj error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, 1325299548Serj NULL); 1326299548Serj if (error) { 1327299548Serj device_printf(dev, "init: i40e_aq_set_phy_mask() failed: err %d," 1328299548Serj " aq_err %d\n", error, hw->aq.asq_last_status); 1329299548Serj error = EIO; 1330299548Serj goto err_out; 1331299548Serj } 1332299548Serj 1333299548Serj error = i40e_set_fc(hw, &set_fc_err_mask, true); 1334299548Serj if (error) { 1335299548Serj device_printf(dev, "init: setting link flow control failed; retcode %d," 1336299548Serj " fc_err_mask 0x%02x\n", error, set_fc_err_mask); 1337299548Serj goto err_out; 1338299548Serj } 1339299548Serj 1340299548Serj // XXX: (Rebuild VSIs?) 1341299548Serj 1342299552Serj /* Firmware delay workaround */ 1343299548Serj if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 1344299548Serj (hw->aq.fw_maj_ver < 4)) { 1345299548Serj i40e_msec_delay(75); 1346299548Serj error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 1347299548Serj if (error) { 1348299548Serj device_printf(dev, "init: link restart failed, aq_err %d\n", 1349299548Serj hw->aq.asq_last_status); 1350299548Serj goto err_out; 1351299548Serj } 1352299548Serj } 1353299548Serj 1354299548Serj 1355299548Serjerr_out: 1356299548Serj return (error); 1357299548Serj} 1358299548Serj 1359266423Sjfvstatic void 1360270346Sjfvixl_init(void *arg) 1361266423Sjfv{ 1362270346Sjfv struct ixl_pf *pf = arg; 1363299554Serj struct ixl_vsi *vsi = &pf->vsi; 1364299553Serj device_t dev = pf->dev; 1365299553Serj int error = 0; 1366266423Sjfv 1367299548Serj /* 1368299548Serj * If the aq is dead here, it probably means something outside of the driver 1369299548Serj * did something to the adapter, like a PF reset. 1370299548Serj * So rebuild the driver's state here if that occurs. 1371299548Serj */ 1372299548Serj if (!i40e_check_asq_alive(&pf->hw)) { 1373299553Serj device_printf(dev, "Admin Queue is down; resetting...\n"); 1374299548Serj IXL_PF_LOCK(pf); 1375299548Serj ixl_teardown_hw_structs(pf); 1376299548Serj ixl_reset(pf); 1377299548Serj IXL_PF_UNLOCK(pf); 1378299548Serj } 1379299548Serj 1380299553Serj /* 1381299553Serj * Set up LAN queue interrupts here. 1382299553Serj * Kernel interrupt setup functions cannot be called while holding a lock, 1383299553Serj * so this is done outside of init_locked(). 1384299553Serj */ 1385299553Serj if (pf->msix > 1) { 1386299554Serj /* Teardown existing interrupts, if they exist */ 1387299554Serj ixl_teardown_queue_msix(vsi); 1388299554Serj ixl_free_queue_tqs(vsi); 1389299554Serj /* Then set them up again */ 1390299554Serj error = ixl_setup_queue_msix(vsi); 1391299553Serj if (error) 1392299553Serj device_printf(dev, "ixl_setup_queue_msix() error: %d\n", 1393299553Serj error); 1394299554Serj error = ixl_setup_queue_tqs(vsi); 1395299553Serj if (error) 1396299553Serj device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", 1397299553Serj error); 1398299553Serj } else 1399299553Serj // possibly broken 1400299553Serj error = ixl_assign_vsi_legacy(pf); 1401299553Serj if (error) { 1402299553Serj device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", error); 1403299547Serj return; 1404299547Serj } 1405299547Serj 1406270346Sjfv IXL_PF_LOCK(pf); 1407270346Sjfv ixl_init_locked(pf); 1408270346Sjfv IXL_PF_UNLOCK(pf); 1409266423Sjfv} 1410266423Sjfv 1411266423Sjfv/* 1412266423Sjfv** MSIX Interrupt Handlers and Tasklets 1413266423Sjfv*/ 1414266423Sjfvstatic void 1415270346Sjfvixl_handle_que(void *context, int pending) 1416266423Sjfv{ 1417270346Sjfv struct ixl_queue *que = context; 1418270346Sjfv struct ixl_vsi *vsi = que->vsi; 1419266423Sjfv struct i40e_hw *hw = vsi->hw; 1420266423Sjfv struct tx_ring *txr = &que->txr; 1421266423Sjfv struct ifnet *ifp = vsi->ifp; 1422266423Sjfv bool more; 1423266423Sjfv 1424266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1425270346Sjfv more = ixl_rxeof(que, IXL_RX_LIMIT); 1426270346Sjfv IXL_TX_LOCK(txr); 1427270346Sjfv ixl_txeof(que); 1428266423Sjfv if (!drbr_empty(ifp, txr->br)) 1429270346Sjfv ixl_mq_start_locked(ifp, txr); 1430270346Sjfv IXL_TX_UNLOCK(txr); 1431266423Sjfv if (more) { 1432266423Sjfv taskqueue_enqueue(que->tq, &que->task); 1433266423Sjfv return; 1434266423Sjfv } 1435266423Sjfv } 1436266423Sjfv 1437266423Sjfv /* Reenable this interrupt - hmmm */ 1438270346Sjfv ixl_enable_queue(hw, que->me); 1439266423Sjfv return; 1440266423Sjfv} 1441266423Sjfv 1442266423Sjfv 1443266423Sjfv/********************************************************************* 1444266423Sjfv * 1445266423Sjfv * Legacy Interrupt Service routine 1446266423Sjfv * 1447266423Sjfv **********************************************************************/ 1448266423Sjfvvoid 1449270346Sjfvixl_intr(void *arg) 1450266423Sjfv{ 1451270346Sjfv struct ixl_pf *pf = arg; 1452266423Sjfv struct i40e_hw *hw = &pf->hw; 1453270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1454270346Sjfv struct ixl_queue *que = vsi->queues; 1455266423Sjfv struct ifnet *ifp = vsi->ifp; 1456266423Sjfv struct tx_ring *txr = &que->txr; 1457266423Sjfv u32 reg, icr0, mask; 1458266423Sjfv bool more_tx, more_rx; 1459266423Sjfv 1460266423Sjfv ++que->irqs; 1461266423Sjfv 1462266423Sjfv /* Protect against spurious interrupts */ 1463266423Sjfv if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1464266423Sjfv return; 1465266423Sjfv 1466266423Sjfv icr0 = rd32(hw, I40E_PFINT_ICR0); 1467266423Sjfv 1468266423Sjfv reg = rd32(hw, I40E_PFINT_DYN_CTL0); 1469266423Sjfv reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 1470266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 1471266423Sjfv 1472266423Sjfv mask = rd32(hw, I40E_PFINT_ICR0_ENA); 1473266423Sjfv 1474279858Sjfv#ifdef PCI_IOV 1475279858Sjfv if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) 1476279858Sjfv taskqueue_enqueue(pf->tq, &pf->vflr_task); 1477279858Sjfv#endif 1478279858Sjfv 1479266423Sjfv if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) { 1480266423Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 1481266423Sjfv return; 1482266423Sjfv } 1483266423Sjfv 1484270346Sjfv more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 1485266423Sjfv 1486270346Sjfv IXL_TX_LOCK(txr); 1487270346Sjfv more_tx = ixl_txeof(que); 1488266423Sjfv if (!drbr_empty(vsi->ifp, txr->br)) 1489266423Sjfv more_tx = 1; 1490270346Sjfv IXL_TX_UNLOCK(txr); 1491266423Sjfv 1492266423Sjfv /* re-enable other interrupt causes */ 1493266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, mask); 1494266423Sjfv 1495266423Sjfv /* And now the queues */ 1496266423Sjfv reg = rd32(hw, I40E_QINT_RQCTL(0)); 1497266423Sjfv reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; 1498266423Sjfv wr32(hw, I40E_QINT_RQCTL(0), reg); 1499266423Sjfv 1500266423Sjfv reg = rd32(hw, I40E_QINT_TQCTL(0)); 1501266423Sjfv reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; 1502266423Sjfv reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK; 1503266423Sjfv wr32(hw, I40E_QINT_TQCTL(0), reg); 1504266423Sjfv 1505270346Sjfv ixl_enable_legacy(hw); 1506266423Sjfv 1507266423Sjfv return; 1508266423Sjfv} 1509266423Sjfv 1510266423Sjfv 1511266423Sjfv/********************************************************************* 1512266423Sjfv * 1513266423Sjfv * MSIX VSI Interrupt Service routine 1514266423Sjfv * 1515266423Sjfv **********************************************************************/ 1516266423Sjfvvoid 1517270346Sjfvixl_msix_que(void *arg) 1518266423Sjfv{ 1519270346Sjfv struct ixl_queue *que = arg; 1520270346Sjfv struct ixl_vsi *vsi = que->vsi; 1521266423Sjfv struct i40e_hw *hw = vsi->hw; 1522266423Sjfv struct tx_ring *txr = &que->txr; 1523266423Sjfv bool more_tx, more_rx; 1524266423Sjfv 1525269198Sjfv /* Protect against spurious interrupts */ 1526269198Sjfv if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) 1527269198Sjfv return; 1528269198Sjfv 1529266423Sjfv ++que->irqs; 1530266423Sjfv 1531270346Sjfv more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 1532266423Sjfv 1533270346Sjfv IXL_TX_LOCK(txr); 1534270346Sjfv more_tx = ixl_txeof(que); 1535266423Sjfv /* 1536266423Sjfv ** Make certain that if the stack 1537266423Sjfv ** has anything queued the task gets 1538266423Sjfv ** scheduled to handle it. 1539266423Sjfv */ 1540266423Sjfv if (!drbr_empty(vsi->ifp, txr->br)) 1541266423Sjfv more_tx = 1; 1542270346Sjfv IXL_TX_UNLOCK(txr); 1543266423Sjfv 1544270346Sjfv ixl_set_queue_rx_itr(que); 1545270346Sjfv ixl_set_queue_tx_itr(que); 1546266423Sjfv 1547266423Sjfv if (more_tx || more_rx) 1548266423Sjfv taskqueue_enqueue(que->tq, &que->task); 1549266423Sjfv else 1550270346Sjfv ixl_enable_queue(hw, que->me); 1551266423Sjfv 1552266423Sjfv return; 1553266423Sjfv} 1554266423Sjfv 1555266423Sjfv 1556266423Sjfv/********************************************************************* 1557266423Sjfv * 1558266423Sjfv * MSIX Admin Queue Interrupt Service routine 1559266423Sjfv * 1560266423Sjfv **********************************************************************/ 1561266423Sjfvstatic void 1562270346Sjfvixl_msix_adminq(void *arg) 1563266423Sjfv{ 1564270346Sjfv struct ixl_pf *pf = arg; 1565266423Sjfv struct i40e_hw *hw = &pf->hw; 1566299549Serj u32 reg, mask, rstat_reg; 1567299549Serj bool do_task = FALSE; 1568266423Sjfv 1569266423Sjfv ++pf->admin_irq; 1570266423Sjfv 1571266423Sjfv reg = rd32(hw, I40E_PFINT_ICR0); 1572266423Sjfv mask = rd32(hw, I40E_PFINT_ICR0_ENA); 1573266423Sjfv 1574266423Sjfv /* Check on the cause */ 1575299549Serj if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) { 1576299549Serj mask &= ~I40E_PFINT_ICR0_ADMINQ_MASK; 1577299549Serj do_task = TRUE; 1578299549Serj } 1579266423Sjfv 1580269198Sjfv if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) { 1581270346Sjfv ixl_handle_mdd_event(pf); 1582299549Serj mask &= ~I40E_PFINT_ICR0_MAL_DETECT_MASK; 1583269198Sjfv } 1584266423Sjfv 1585299549Serj if (reg & I40E_PFINT_ICR0_GRST_MASK) { 1586299549Serj device_printf(pf->dev, "Reset Requested!\n"); 1587299549Serj rstat_reg = rd32(hw, I40E_GLGEN_RSTAT); 1588299549Serj rstat_reg = (rstat_reg & I40E_GLGEN_RSTAT_RESET_TYPE_MASK) 1589299549Serj >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT; 1590299549Serj device_printf(pf->dev, "Reset type: "); 1591299549Serj switch (rstat_reg) { 1592299549Serj /* These others might be handled similarly to an EMPR reset */ 1593299549Serj case I40E_RESET_CORER: 1594299549Serj printf("CORER\n"); 1595299549Serj break; 1596299549Serj case I40E_RESET_GLOBR: 1597299549Serj printf("GLOBR\n"); 1598299549Serj break; 1599299549Serj case I40E_RESET_EMPR: 1600299549Serj printf("EMPR\n"); 1601299549Serj atomic_set_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); 1602299549Serj break; 1603299549Serj default: 1604299549Serj printf("?\n"); 1605299549Serj break; 1606299549Serj } 1607299549Serj // overload admin queue task to check reset progress? 1608299549Serj do_task = TRUE; 1609299549Serj } 1610299549Serj 1611299549Serj if (reg & I40E_PFINT_ICR0_ECC_ERR_MASK) { 1612299549Serj device_printf(pf->dev, "ECC Error detected!\n"); 1613299549Serj } 1614299549Serj 1615299549Serj if (reg & I40E_PFINT_ICR0_HMC_ERR_MASK) { 1616299549Serj device_printf(pf->dev, "HMC Error detected!\n"); 1617299549Serj } 1618299549Serj 1619299549Serj if (reg & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) { 1620299549Serj device_printf(pf->dev, "PCI Exception detected!\n"); 1621299549Serj } 1622299549Serj 1623279858Sjfv#ifdef PCI_IOV 1624279858Sjfv if (reg & I40E_PFINT_ICR0_VFLR_MASK) { 1625266423Sjfv mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; 1626279858Sjfv taskqueue_enqueue(pf->tq, &pf->vflr_task); 1627279858Sjfv } 1628279858Sjfv#endif 1629266423Sjfv 1630266423Sjfv reg = rd32(hw, I40E_PFINT_DYN_CTL0); 1631266423Sjfv reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 1632266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 1633266423Sjfv 1634299549Serj if (do_task) 1635299549Serj taskqueue_enqueue(pf->tq, &pf->adminq); 1636266423Sjfv} 1637266423Sjfv 1638266423Sjfv/********************************************************************* 1639266423Sjfv * 1640266423Sjfv * Media Ioctl callback 1641266423Sjfv * 1642266423Sjfv * This routine is called whenever the user queries the status of 1643266423Sjfv * the interface using ifconfig. 1644266423Sjfv * 1645266423Sjfv **********************************************************************/ 1646266423Sjfvstatic void 1647270346Sjfvixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 1648266423Sjfv{ 1649270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 1650279858Sjfv struct ixl_pf *pf = vsi->back; 1651266423Sjfv struct i40e_hw *hw = &pf->hw; 1652266423Sjfv 1653270346Sjfv INIT_DEBUGOUT("ixl_media_status: begin"); 1654270346Sjfv IXL_PF_LOCK(pf); 1655266423Sjfv 1656279858Sjfv hw->phy.get_link_info = TRUE; 1657284049Sjfv i40e_get_link_status(hw, &pf->link_up); 1658270346Sjfv ixl_update_link_status(pf); 1659266423Sjfv 1660266423Sjfv ifmr->ifm_status = IFM_AVALID; 1661266423Sjfv ifmr->ifm_active = IFM_ETHER; 1662266423Sjfv 1663279858Sjfv if (!pf->link_up) { 1664270346Sjfv IXL_PF_UNLOCK(pf); 1665266423Sjfv return; 1666266423Sjfv } 1667266423Sjfv 1668266423Sjfv ifmr->ifm_status |= IFM_ACTIVE; 1669299545Serj 1670299545Serj /* Hardware always does full-duplex */ 1671266423Sjfv ifmr->ifm_active |= IFM_FDX; 1672266423Sjfv 1673266423Sjfv switch (hw->phy.link_info.phy_type) { 1674266423Sjfv /* 100 M */ 1675266423Sjfv case I40E_PHY_TYPE_100BASE_TX: 1676266423Sjfv ifmr->ifm_active |= IFM_100_TX; 1677266423Sjfv break; 1678266423Sjfv /* 1 G */ 1679266423Sjfv case I40E_PHY_TYPE_1000BASE_T: 1680266423Sjfv ifmr->ifm_active |= IFM_1000_T; 1681266423Sjfv break; 1682269198Sjfv case I40E_PHY_TYPE_1000BASE_SX: 1683269198Sjfv ifmr->ifm_active |= IFM_1000_SX; 1684269198Sjfv break; 1685269198Sjfv case I40E_PHY_TYPE_1000BASE_LX: 1686269198Sjfv ifmr->ifm_active |= IFM_1000_LX; 1687269198Sjfv break; 1688299552Serj case I40E_PHY_TYPE_1000BASE_T_OPTICAL: 1689299552Serj ifmr->ifm_active |= IFM_OTHER; 1690299552Serj break; 1691266423Sjfv /* 10 G */ 1692266423Sjfv case I40E_PHY_TYPE_10GBASE_SFPP_CU: 1693266423Sjfv ifmr->ifm_active |= IFM_10G_TWINAX; 1694266423Sjfv break; 1695266423Sjfv case I40E_PHY_TYPE_10GBASE_SR: 1696266423Sjfv ifmr->ifm_active |= IFM_10G_SR; 1697266423Sjfv break; 1698266423Sjfv case I40E_PHY_TYPE_10GBASE_LR: 1699266423Sjfv ifmr->ifm_active |= IFM_10G_LR; 1700266423Sjfv break; 1701270346Sjfv case I40E_PHY_TYPE_10GBASE_T: 1702270346Sjfv ifmr->ifm_active |= IFM_10G_T; 1703270346Sjfv break; 1704299552Serj case I40E_PHY_TYPE_XAUI: 1705299552Serj case I40E_PHY_TYPE_XFI: 1706299552Serj case I40E_PHY_TYPE_10GBASE_AOC: 1707299552Serj ifmr->ifm_active |= IFM_OTHER; 1708299552Serj break; 1709266423Sjfv /* 40 G */ 1710266423Sjfv case I40E_PHY_TYPE_40GBASE_CR4: 1711266423Sjfv case I40E_PHY_TYPE_40GBASE_CR4_CU: 1712266423Sjfv ifmr->ifm_active |= IFM_40G_CR4; 1713266423Sjfv break; 1714266423Sjfv case I40E_PHY_TYPE_40GBASE_SR4: 1715266423Sjfv ifmr->ifm_active |= IFM_40G_SR4; 1716266423Sjfv break; 1717266423Sjfv case I40E_PHY_TYPE_40GBASE_LR4: 1718266423Sjfv ifmr->ifm_active |= IFM_40G_LR4; 1719266423Sjfv break; 1720299552Serj case I40E_PHY_TYPE_XLAUI: 1721299552Serj ifmr->ifm_active |= IFM_OTHER; 1722299552Serj break; 1723284049Sjfv#ifndef IFM_ETH_XTYPE 1724284049Sjfv case I40E_PHY_TYPE_1000BASE_KX: 1725284049Sjfv ifmr->ifm_active |= IFM_1000_CX; 1726284049Sjfv break; 1727299552Serj case I40E_PHY_TYPE_SGMII: 1728299552Serj ifmr->ifm_active |= IFM_OTHER; 1729299552Serj break; 1730284049Sjfv case I40E_PHY_TYPE_10GBASE_CR1_CU: 1731284049Sjfv case I40E_PHY_TYPE_10GBASE_CR1: 1732284049Sjfv ifmr->ifm_active |= IFM_10G_TWINAX; 1733284049Sjfv break; 1734284049Sjfv case I40E_PHY_TYPE_10GBASE_KX4: 1735284049Sjfv ifmr->ifm_active |= IFM_10G_CX4; 1736284049Sjfv break; 1737284049Sjfv case I40E_PHY_TYPE_10GBASE_KR: 1738284049Sjfv ifmr->ifm_active |= IFM_10G_SR; 1739284049Sjfv break; 1740299552Serj case I40E_PHY_TYPE_SFI: 1741299552Serj ifmr->ifm_active |= IFM_OTHER; 1742299552Serj break; 1743279033Sjfv case I40E_PHY_TYPE_40GBASE_KR4: 1744279033Sjfv case I40E_PHY_TYPE_XLPPI: 1745299552Serj case I40E_PHY_TYPE_40GBASE_AOC: 1746284049Sjfv ifmr->ifm_active |= IFM_40G_SR4; 1747279033Sjfv break; 1748284049Sjfv#else 1749284049Sjfv case I40E_PHY_TYPE_1000BASE_KX: 1750284049Sjfv ifmr->ifm_active |= IFM_1000_KX; 1751284049Sjfv break; 1752299552Serj case I40E_PHY_TYPE_SGMII: 1753299552Serj ifmr->ifm_active |= IFM_1000_SGMII; 1754299552Serj break; 1755284049Sjfv /* ERJ: What's the difference between these? */ 1756284049Sjfv case I40E_PHY_TYPE_10GBASE_CR1_CU: 1757284049Sjfv case I40E_PHY_TYPE_10GBASE_CR1: 1758284049Sjfv ifmr->ifm_active |= IFM_10G_CR1; 1759284049Sjfv break; 1760284049Sjfv case I40E_PHY_TYPE_10GBASE_KX4: 1761284049Sjfv ifmr->ifm_active |= IFM_10G_KX4; 1762284049Sjfv break; 1763284049Sjfv case I40E_PHY_TYPE_10GBASE_KR: 1764284049Sjfv ifmr->ifm_active |= IFM_10G_KR; 1765284049Sjfv break; 1766299552Serj case I40E_PHY_TYPE_SFI: 1767299552Serj ifmr->ifm_active |= IFM_10G_SFI; 1768299552Serj break; 1769299545Serj /* Our single 20G media type */ 1770284049Sjfv case I40E_PHY_TYPE_20GBASE_KR2: 1771284049Sjfv ifmr->ifm_active |= IFM_20G_KR2; 1772284049Sjfv break; 1773284049Sjfv case I40E_PHY_TYPE_40GBASE_KR4: 1774284049Sjfv ifmr->ifm_active |= IFM_40G_KR4; 1775284049Sjfv break; 1776284049Sjfv case I40E_PHY_TYPE_XLPPI: 1777299552Serj case I40E_PHY_TYPE_40GBASE_AOC: 1778284049Sjfv ifmr->ifm_active |= IFM_40G_XLPPI; 1779284049Sjfv break; 1780284049Sjfv#endif 1781299552Serj /* Unknown to driver */ 1782266423Sjfv default: 1783266423Sjfv ifmr->ifm_active |= IFM_UNKNOWN; 1784266423Sjfv break; 1785266423Sjfv } 1786266423Sjfv /* Report flow control status as well */ 1787266423Sjfv if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) 1788266423Sjfv ifmr->ifm_active |= IFM_ETH_TXPAUSE; 1789266423Sjfv if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) 1790266423Sjfv ifmr->ifm_active |= IFM_ETH_RXPAUSE; 1791266423Sjfv 1792270346Sjfv IXL_PF_UNLOCK(pf); 1793266423Sjfv 1794266423Sjfv return; 1795266423Sjfv} 1796266423Sjfv 1797299545Serj/* 1798299545Serj * NOTE: Fortville does not support forcing media speeds. Instead, 1799299545Serj * use the set_advertise sysctl to set the speeds Fortville 1800299545Serj * will advertise or be allowed to operate at. 1801299545Serj */ 1802266423Sjfvstatic int 1803270346Sjfvixl_media_change(struct ifnet * ifp) 1804266423Sjfv{ 1805270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 1806266423Sjfv struct ifmedia *ifm = &vsi->media; 1807266423Sjfv 1808270346Sjfv INIT_DEBUGOUT("ixl_media_change: begin"); 1809266423Sjfv 1810266423Sjfv if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1811266423Sjfv return (EINVAL); 1812266423Sjfv 1813299545Serj if_printf(ifp, "Media change is not supported.\n"); 1814269198Sjfv 1815269198Sjfv return (ENODEV); 1816266423Sjfv} 1817266423Sjfv 1818266423Sjfv 1819270346Sjfv#ifdef IXL_FDIR 1820266423Sjfv/* 1821266423Sjfv** ATR: Application Targetted Receive - creates a filter 1822266423Sjfv** based on TX flow info that will keep the receive 1823266423Sjfv** portion of the flow on the same queue. Based on the 1824266423Sjfv** implementation this is only available for TCP connections 1825266423Sjfv*/ 1826266423Sjfvvoid 1827270346Sjfvixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype) 1828266423Sjfv{ 1829270346Sjfv struct ixl_vsi *vsi = que->vsi; 1830266423Sjfv struct tx_ring *txr = &que->txr; 1831266423Sjfv struct i40e_filter_program_desc *FDIR; 1832266423Sjfv u32 ptype, dtype; 1833266423Sjfv int idx; 1834266423Sjfv 1835266423Sjfv /* check if ATR is enabled and sample rate */ 1836270346Sjfv if ((!ixl_enable_fdir) || (!txr->atr_rate)) 1837266423Sjfv return; 1838266423Sjfv /* 1839266423Sjfv ** We sample all TCP SYN/FIN packets, 1840266423Sjfv ** or at the selected sample rate 1841266423Sjfv */ 1842266423Sjfv txr->atr_count++; 1843266423Sjfv if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) && 1844266423Sjfv (txr->atr_count < txr->atr_rate)) 1845266423Sjfv return; 1846266423Sjfv txr->atr_count = 0; 1847266423Sjfv 1848266423Sjfv /* Get a descriptor to use */ 1849266423Sjfv idx = txr->next_avail; 1850266423Sjfv FDIR = (struct i40e_filter_program_desc *) &txr->base[idx]; 1851266423Sjfv if (++idx == que->num_desc) 1852266423Sjfv idx = 0; 1853266423Sjfv txr->avail--; 1854266423Sjfv txr->next_avail = idx; 1855266423Sjfv 1856266423Sjfv ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & 1857266423Sjfv I40E_TXD_FLTR_QW0_QINDEX_MASK; 1858266423Sjfv 1859266423Sjfv ptype |= (etype == ETHERTYPE_IP) ? 1860266423Sjfv (I40E_FILTER_PCTYPE_NONF_IPV4_TCP << 1861266423Sjfv I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) : 1862266423Sjfv (I40E_FILTER_PCTYPE_NONF_IPV6_TCP << 1863266423Sjfv I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); 1864266423Sjfv 1865266423Sjfv ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT; 1866266423Sjfv 1867266423Sjfv dtype = I40E_TX_DESC_DTYPE_FILTER_PROG; 1868266423Sjfv 1869266423Sjfv /* 1870266423Sjfv ** We use the TCP TH_FIN as a trigger to remove 1871266423Sjfv ** the filter, otherwise its an update. 1872266423Sjfv */ 1873266423Sjfv dtype |= (th->th_flags & TH_FIN) ? 1874266423Sjfv (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << 1875266423Sjfv I40E_TXD_FLTR_QW1_PCMD_SHIFT) : 1876266423Sjfv (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << 1877266423Sjfv I40E_TXD_FLTR_QW1_PCMD_SHIFT); 1878266423Sjfv 1879266423Sjfv dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX << 1880266423Sjfv I40E_TXD_FLTR_QW1_DEST_SHIFT; 1881266423Sjfv 1882266423Sjfv dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID << 1883266423Sjfv I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT; 1884266423Sjfv 1885266423Sjfv FDIR->qindex_flex_ptype_vsi = htole32(ptype); 1886266423Sjfv FDIR->dtype_cmd_cntindex = htole32(dtype); 1887266423Sjfv return; 1888266423Sjfv} 1889266423Sjfv#endif 1890266423Sjfv 1891266423Sjfv 1892266423Sjfvstatic void 1893270346Sjfvixl_set_promisc(struct ixl_vsi *vsi) 1894266423Sjfv{ 1895266423Sjfv struct ifnet *ifp = vsi->ifp; 1896266423Sjfv struct i40e_hw *hw = vsi->hw; 1897266423Sjfv int err, mcnt = 0; 1898266423Sjfv bool uni = FALSE, multi = FALSE; 1899266423Sjfv 1900266423Sjfv if (ifp->if_flags & IFF_ALLMULTI) 1901266423Sjfv multi = TRUE; 1902266423Sjfv else { /* Need to count the multicast addresses */ 1903266423Sjfv struct ifmultiaddr *ifma; 1904266423Sjfv if_maddr_rlock(ifp); 1905266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1906266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1907266423Sjfv continue; 1908266423Sjfv if (mcnt == MAX_MULTICAST_ADDR) 1909266423Sjfv break; 1910266423Sjfv mcnt++; 1911266423Sjfv } 1912266423Sjfv if_maddr_runlock(ifp); 1913266423Sjfv } 1914266423Sjfv 1915266423Sjfv if (mcnt >= MAX_MULTICAST_ADDR) 1916266423Sjfv multi = TRUE; 1917266423Sjfv if (ifp->if_flags & IFF_PROMISC) 1918266423Sjfv uni = TRUE; 1919266423Sjfv 1920266423Sjfv err = i40e_aq_set_vsi_unicast_promiscuous(hw, 1921266423Sjfv vsi->seid, uni, NULL); 1922266423Sjfv err = i40e_aq_set_vsi_multicast_promiscuous(hw, 1923266423Sjfv vsi->seid, multi, NULL); 1924266423Sjfv return; 1925266423Sjfv} 1926266423Sjfv 1927266423Sjfv/********************************************************************* 1928266423Sjfv * Filter Routines 1929266423Sjfv * 1930266423Sjfv * Routines for multicast and vlan filter management. 1931266423Sjfv * 1932266423Sjfv *********************************************************************/ 1933266423Sjfvstatic void 1934270346Sjfvixl_add_multi(struct ixl_vsi *vsi) 1935266423Sjfv{ 1936266423Sjfv struct ifmultiaddr *ifma; 1937266423Sjfv struct ifnet *ifp = vsi->ifp; 1938266423Sjfv struct i40e_hw *hw = vsi->hw; 1939266423Sjfv int mcnt = 0, flags; 1940266423Sjfv 1941270346Sjfv IOCTL_DEBUGOUT("ixl_add_multi: begin"); 1942266423Sjfv 1943266423Sjfv if_maddr_rlock(ifp); 1944266423Sjfv /* 1945266423Sjfv ** First just get a count, to decide if we 1946266423Sjfv ** we simply use multicast promiscuous. 1947266423Sjfv */ 1948266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1949266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1950266423Sjfv continue; 1951266423Sjfv mcnt++; 1952266423Sjfv } 1953266423Sjfv if_maddr_runlock(ifp); 1954266423Sjfv 1955266423Sjfv if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { 1956266423Sjfv /* delete existing MC filters */ 1957270346Sjfv ixl_del_hw_filters(vsi, mcnt); 1958266423Sjfv i40e_aq_set_vsi_multicast_promiscuous(hw, 1959266423Sjfv vsi->seid, TRUE, NULL); 1960266423Sjfv return; 1961266423Sjfv } 1962266423Sjfv 1963266423Sjfv mcnt = 0; 1964266423Sjfv if_maddr_rlock(ifp); 1965266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1966266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1967266423Sjfv continue; 1968270346Sjfv ixl_add_mc_filter(vsi, 1969266423Sjfv (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); 1970266423Sjfv mcnt++; 1971266423Sjfv } 1972266423Sjfv if_maddr_runlock(ifp); 1973266423Sjfv if (mcnt > 0) { 1974270346Sjfv flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); 1975270346Sjfv ixl_add_hw_filters(vsi, flags, mcnt); 1976266423Sjfv } 1977266423Sjfv 1978270346Sjfv IOCTL_DEBUGOUT("ixl_add_multi: end"); 1979266423Sjfv return; 1980266423Sjfv} 1981266423Sjfv 1982266423Sjfvstatic void 1983270346Sjfvixl_del_multi(struct ixl_vsi *vsi) 1984266423Sjfv{ 1985266423Sjfv struct ifnet *ifp = vsi->ifp; 1986266423Sjfv struct ifmultiaddr *ifma; 1987270346Sjfv struct ixl_mac_filter *f; 1988266423Sjfv int mcnt = 0; 1989266423Sjfv bool match = FALSE; 1990266423Sjfv 1991270346Sjfv IOCTL_DEBUGOUT("ixl_del_multi: begin"); 1992266423Sjfv 1993266423Sjfv /* Search for removed multicast addresses */ 1994266423Sjfv if_maddr_rlock(ifp); 1995266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 1996270346Sjfv if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) { 1997266423Sjfv match = FALSE; 1998266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1999266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 2000266423Sjfv continue; 2001266423Sjfv u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2002266423Sjfv if (cmp_etheraddr(f->macaddr, mc_addr)) { 2003266423Sjfv match = TRUE; 2004266423Sjfv break; 2005266423Sjfv } 2006266423Sjfv } 2007266423Sjfv if (match == FALSE) { 2008270346Sjfv f->flags |= IXL_FILTER_DEL; 2009266423Sjfv mcnt++; 2010266423Sjfv } 2011266423Sjfv } 2012266423Sjfv } 2013266423Sjfv if_maddr_runlock(ifp); 2014266423Sjfv 2015266423Sjfv if (mcnt > 0) 2016270346Sjfv ixl_del_hw_filters(vsi, mcnt); 2017266423Sjfv} 2018266423Sjfv 2019266423Sjfv 2020266423Sjfv/********************************************************************* 2021266423Sjfv * Timer routine 2022266423Sjfv * 2023266423Sjfv * This routine checks for link status,updates statistics, 2024266423Sjfv * and runs the watchdog check. 2025266423Sjfv * 2026299551Serj * Only runs when the driver is configured UP and RUNNING. 2027299551Serj * 2028266423Sjfv **********************************************************************/ 2029266423Sjfv 2030266423Sjfvstatic void 2031270346Sjfvixl_local_timer(void *arg) 2032266423Sjfv{ 2033270346Sjfv struct ixl_pf *pf = arg; 2034266423Sjfv struct i40e_hw *hw = &pf->hw; 2035270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2036270346Sjfv struct ixl_queue *que = vsi->queues; 2037266423Sjfv device_t dev = pf->dev; 2038266423Sjfv int hung = 0; 2039266423Sjfv u32 mask; 2040266423Sjfv 2041266423Sjfv mtx_assert(&pf->pf_mtx, MA_OWNED); 2042266423Sjfv 2043266423Sjfv /* Fire off the adminq task */ 2044266423Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 2045266423Sjfv 2046266423Sjfv /* Update stats */ 2047270346Sjfv ixl_update_stats_counters(pf); 2048266423Sjfv 2049266423Sjfv /* 2050269198Sjfv ** Check status of the queues 2051266423Sjfv */ 2052266423Sjfv mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | 2053266423Sjfv I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); 2054266423Sjfv 2055299554Serj for (int i = 0; i < vsi->num_queues; i++, que++) { 2056266423Sjfv /* Any queues with outstanding work get a sw irq */ 2057266423Sjfv if (que->busy) 2058266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask); 2059266423Sjfv /* 2060266423Sjfv ** Each time txeof runs without cleaning, but there 2061266423Sjfv ** are uncleaned descriptors it increments busy. If 2062266423Sjfv ** we get to 5 we declare it hung. 2063266423Sjfv */ 2064270346Sjfv if (que->busy == IXL_QUEUE_HUNG) { 2065269198Sjfv ++hung; 2066269198Sjfv /* Mark the queue as inactive */ 2067269198Sjfv vsi->active_queues &= ~((u64)1 << que->me); 2068269198Sjfv continue; 2069269198Sjfv } else { 2070269198Sjfv /* Check if we've come back from hung */ 2071269198Sjfv if ((vsi->active_queues & ((u64)1 << que->me)) == 0) 2072269198Sjfv vsi->active_queues |= ((u64)1 << que->me); 2073269198Sjfv } 2074270346Sjfv if (que->busy >= IXL_MAX_TX_BUSY) { 2075277084Sjfv#ifdef IXL_DEBUG 2076266423Sjfv device_printf(dev,"Warning queue %d " 2077269198Sjfv "appears to be hung!\n", i); 2078277084Sjfv#endif 2079270346Sjfv que->busy = IXL_QUEUE_HUNG; 2080266423Sjfv ++hung; 2081266423Sjfv } 2082266423Sjfv } 2083266423Sjfv /* Only reinit if all queues show hung */ 2084266423Sjfv if (hung == vsi->num_queues) 2085266423Sjfv goto hung; 2086266423Sjfv 2087270346Sjfv callout_reset(&pf->timer, hz, ixl_local_timer, pf); 2088266423Sjfv return; 2089266423Sjfv 2090266423Sjfvhung: 2091266423Sjfv device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n"); 2092270346Sjfv ixl_init_locked(pf); 2093266423Sjfv} 2094266423Sjfv 2095266423Sjfv/* 2096266423Sjfv** Note: this routine updates the OS on the link state 2097266423Sjfv** the real check of the hardware only happens with 2098266423Sjfv** a link interrupt. 2099266423Sjfv*/ 2100266423Sjfvstatic void 2101270346Sjfvixl_update_link_status(struct ixl_pf *pf) 2102266423Sjfv{ 2103270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2104266423Sjfv struct i40e_hw *hw = &pf->hw; 2105266423Sjfv struct ifnet *ifp = vsi->ifp; 2106266423Sjfv device_t dev = pf->dev; 2107266423Sjfv 2108299547Serj if (pf->link_up) { 2109266423Sjfv if (vsi->link_active == FALSE) { 2110279033Sjfv pf->fc = hw->fc.current_mode; 2111266423Sjfv if (bootverbose) { 2112266423Sjfv device_printf(dev,"Link is up %d Gbps %s," 2113266423Sjfv " Flow Control: %s\n", 2114279858Sjfv ((pf->link_speed == 2115279858Sjfv I40E_LINK_SPEED_40GB)? 40:10), 2116279033Sjfv "Full Duplex", ixl_fc_string[pf->fc]); 2117266423Sjfv } 2118266423Sjfv vsi->link_active = TRUE; 2119277084Sjfv /* 2120277084Sjfv ** Warn user if link speed on NPAR enabled 2121277084Sjfv ** partition is not at least 10GB 2122277084Sjfv */ 2123277084Sjfv if (hw->func_caps.npar_enable && 2124279858Sjfv (hw->phy.link_info.link_speed == 2125279858Sjfv I40E_LINK_SPEED_1GB || 2126279858Sjfv hw->phy.link_info.link_speed == 2127279858Sjfv I40E_LINK_SPEED_100MB)) 2128279858Sjfv device_printf(dev, "The partition detected" 2129279858Sjfv "link speed that is less than 10Gbps\n"); 2130266423Sjfv if_link_state_change(ifp, LINK_STATE_UP); 2131266423Sjfv } 2132266423Sjfv } else { /* Link down */ 2133266423Sjfv if (vsi->link_active == TRUE) { 2134266423Sjfv if (bootverbose) 2135299547Serj device_printf(dev, "Link is Down\n"); 2136266423Sjfv if_link_state_change(ifp, LINK_STATE_DOWN); 2137266423Sjfv vsi->link_active = FALSE; 2138266423Sjfv } 2139266423Sjfv } 2140266423Sjfv 2141266423Sjfv return; 2142266423Sjfv} 2143266423Sjfv 2144299547Serjstatic void 2145299547Serjixl_stop(struct ixl_pf *pf) 2146299547Serj{ 2147299547Serj IXL_PF_LOCK(pf); 2148299547Serj ixl_stop_locked(pf); 2149299547Serj IXL_PF_UNLOCK(pf); 2150299547Serj 2151299553Serj ixl_teardown_queue_msix(&pf->vsi); 2152299554Serj ixl_free_queue_tqs(&pf->vsi); 2153299547Serj} 2154299547Serj 2155266423Sjfv/********************************************************************* 2156266423Sjfv * 2157266423Sjfv * This routine disables all traffic on the adapter by issuing a 2158266423Sjfv * global reset on the MAC and deallocates TX/RX buffers. 2159266423Sjfv * 2160266423Sjfv **********************************************************************/ 2161266423Sjfv 2162266423Sjfvstatic void 2163299547Serjixl_stop_locked(struct ixl_pf *pf) 2164266423Sjfv{ 2165270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2166266423Sjfv struct ifnet *ifp = vsi->ifp; 2167266423Sjfv 2168299547Serj INIT_DEBUGOUT("ixl_stop: begin\n"); 2169266423Sjfv 2170299547Serj IXL_PF_LOCK_ASSERT(pf); 2171299547Serj 2172299547Serj /* Stop the local timer */ 2173299547Serj callout_stop(&pf->timer); 2174299547Serj 2175299553Serj ixl_disable_rings_intr(vsi); 2176270346Sjfv ixl_disable_rings(vsi); 2177266423Sjfv 2178266423Sjfv /* Tell the stack that the interface is no longer active */ 2179299553Serj ifp->if_drv_flags &= ~(IFF_DRV_RUNNING); 2180266423Sjfv} 2181266423Sjfv 2182266423Sjfv 2183266423Sjfv/********************************************************************* 2184266423Sjfv * 2185266423Sjfv * Setup MSIX Interrupt resources and handlers for the VSI 2186266423Sjfv * 2187266423Sjfv **********************************************************************/ 2188266423Sjfvstatic int 2189270346Sjfvixl_assign_vsi_legacy(struct ixl_pf *pf) 2190266423Sjfv{ 2191266423Sjfv device_t dev = pf->dev; 2192270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2193270346Sjfv struct ixl_queue *que = vsi->queues; 2194266423Sjfv int error, rid = 0; 2195266423Sjfv 2196266423Sjfv if (pf->msix == 1) 2197266423Sjfv rid = 1; 2198266423Sjfv pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 2199266423Sjfv &rid, RF_SHAREABLE | RF_ACTIVE); 2200266423Sjfv if (pf->res == NULL) { 2201299548Serj device_printf(dev, "Unable to allocate" 2202266423Sjfv " bus resource: vsi legacy/msi interrupt\n"); 2203266423Sjfv return (ENXIO); 2204266423Sjfv } 2205266423Sjfv 2206266423Sjfv /* Set the handler function */ 2207266423Sjfv error = bus_setup_intr(dev, pf->res, 2208266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 2209270346Sjfv ixl_intr, pf, &pf->tag); 2210266423Sjfv if (error) { 2211266423Sjfv pf->res = NULL; 2212299552Serj device_printf(dev, "Failed to register legacy/msi handler\n"); 2213266423Sjfv return (error); 2214266423Sjfv } 2215266423Sjfv bus_describe_intr(dev, pf->res, pf->tag, "irq0"); 2216270346Sjfv TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 2217270346Sjfv TASK_INIT(&que->task, 0, ixl_handle_que, que); 2218270346Sjfv que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 2219266423Sjfv taskqueue_thread_enqueue, &que->tq); 2220266423Sjfv taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 2221266423Sjfv device_get_nameunit(dev)); 2222270346Sjfv TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 2223279858Sjfv 2224270346Sjfv pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 2225266423Sjfv taskqueue_thread_enqueue, &pf->tq); 2226266423Sjfv taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 2227266423Sjfv device_get_nameunit(dev)); 2228266423Sjfv 2229266423Sjfv return (0); 2230266423Sjfv} 2231266423Sjfv 2232299553Serjstatic int 2233299553Serjixl_setup_adminq_tq(struct ixl_pf *pf) 2234299546Serj{ 2235299546Serj device_t dev = pf->dev; 2236299553Serj int error = 0; 2237266423Sjfv 2238299553Serj /* Tasklet for Admin Queue interrupts */ 2239299546Serj TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 2240299546Serj#ifdef PCI_IOV 2241299546Serj /* VFLR Tasklet */ 2242299546Serj TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf); 2243299546Serj#endif 2244299553Serj /* Create and start Admin Queue taskqueue */ 2245299553Serj pf->tq = taskqueue_create_fast("ixl_aq", M_NOWAIT, 2246299546Serj taskqueue_thread_enqueue, &pf->tq); 2247299553Serj if (!pf->tq) { 2248299553Serj device_printf(dev, "taskqueue_create_fast (for AQ) returned NULL!\n"); 2249299553Serj return (ENOMEM); 2250299553Serj } 2251299553Serj error = taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s aq", 2252299546Serj device_get_nameunit(dev)); 2253299553Serj if (error) { 2254299553Serj device_printf(dev, "taskqueue_start_threads (for AQ) error: %d\n", 2255299553Serj error); 2256299553Serj taskqueue_free(pf->tq); 2257299553Serj return (error); 2258299553Serj } 2259299553Serj return (0); 2260299553Serj} 2261299546Serj 2262299553Serjstatic int 2263299553Serjixl_setup_queue_tqs(struct ixl_vsi *vsi) 2264299553Serj{ 2265299553Serj struct ixl_queue *que = vsi->queues; 2266299553Serj device_t dev = vsi->dev; 2267299553Serj 2268299546Serj /* Create queue tasks and start queue taskqueues */ 2269299546Serj for (int i = 0; i < vsi->num_queues; i++, que++) { 2270299546Serj TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 2271299546Serj TASK_INIT(&que->task, 0, ixl_handle_que, que); 2272299546Serj que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 2273299546Serj taskqueue_thread_enqueue, &que->tq); 2274299546Serj#ifdef RSS 2275299546Serj CPU_SETOF(cpu_id, &cpu_mask); 2276299546Serj taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, 2277299546Serj &cpu_mask, "%s (bucket %d)", 2278299546Serj device_get_nameunit(dev), cpu_id); 2279299546Serj#else 2280299546Serj taskqueue_start_threads(&que->tq, 1, PI_NET, 2281299546Serj "%s (que %d)", device_get_nameunit(dev), que->me); 2282299546Serj#endif 2283299546Serj } 2284299546Serj 2285299553Serj return (0); 2286299546Serj} 2287299546Serj 2288299546Serjstatic void 2289299553Serjixl_free_adminq_tq(struct ixl_pf *pf) 2290299546Serj{ 2291299554Serj if (pf->tq) { 2292299553Serj taskqueue_free(pf->tq); 2293299554Serj pf->tq = NULL; 2294299554Serj } 2295299553Serj} 2296299553Serj 2297299553Serjstatic void 2298299553Serjixl_free_queue_tqs(struct ixl_vsi *vsi) 2299299553Serj{ 2300299554Serj struct ixl_queue *que = vsi->queues; 2301299546Serj 2302299546Serj for (int i = 0; i < vsi->num_queues; i++, que++) { 2303299554Serj if (que->tq) { 2304299546Serj taskqueue_free(que->tq); 2305299554Serj que->tq = NULL; 2306299554Serj } 2307299546Serj } 2308299546Serj} 2309299546Serj 2310266423Sjfvstatic int 2311299553Serjixl_setup_adminq_msix(struct ixl_pf *pf) 2312266423Sjfv{ 2313299553Serj device_t dev = pf->dev; 2314299553Serj int rid, error = 0; 2315266423Sjfv 2316299553Serj /* Admin IRQ rid is 1, vector is 0 */ 2317299553Serj rid = 1; 2318299553Serj /* Get interrupt resource from bus */ 2319266423Sjfv pf->res = bus_alloc_resource_any(dev, 2320266423Sjfv SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 2321266423Sjfv if (!pf->res) { 2322299553Serj device_printf(dev, "bus_alloc_resource_any() for Admin Queue" 2323299553Serj " interrupt failed [rid=%d]\n", rid); 2324266423Sjfv return (ENXIO); 2325266423Sjfv } 2326299553Serj /* Then associate interrupt with handler */ 2327266423Sjfv error = bus_setup_intr(dev, pf->res, 2328266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 2329270346Sjfv ixl_msix_adminq, pf, &pf->tag); 2330266423Sjfv if (error) { 2331266423Sjfv pf->res = NULL; 2332299553Serj device_printf(dev, "bus_setup_intr() for Admin Queue" 2333299553Serj " interrupt handler failed, error %d\n", error); 2334299553Serj return (ENXIO); 2335266423Sjfv } 2336299553Serj error = bus_describe_intr(dev, pf->res, pf->tag, "aq"); 2337299553Serj if (error) { 2338299553Serj /* Probably non-fatal? */ 2339299553Serj device_printf(dev, "bus_describe_intr() for Admin Queue" 2340299553Serj " interrupt name failed, error %d\n", error); 2341299553Serj } 2342299553Serj pf->admvec = 0; 2343266423Sjfv 2344299553Serj return (0); 2345299553Serj} 2346299553Serj 2347299553Serj/* 2348299553Serj * Allocate interrupt resources from bus and associate an interrupt handler 2349299553Serj * to those for the VSI's queues. 2350299553Serj */ 2351299553Serjstatic int 2352299553Serjixl_setup_queue_msix(struct ixl_vsi *vsi) 2353299553Serj{ 2354299553Serj device_t dev = vsi->dev; 2355299553Serj struct ixl_queue *que = vsi->queues; 2356299553Serj struct tx_ring *txr; 2357299553Serj int error, rid, vector = 1; 2358299553Serj#ifdef RSS 2359299553Serj cpuset_t cpu_mask; 2360299553Serj#endif 2361299553Serj 2362299553Serj /* Queue interrupt vector numbers start at 1 (adminq intr is 0) */ 2363266423Sjfv for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { 2364277084Sjfv int cpu_id = i; 2365266423Sjfv rid = vector + 1; 2366266423Sjfv txr = &que->txr; 2367266423Sjfv que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 2368266423Sjfv RF_SHAREABLE | RF_ACTIVE); 2369299553Serj if (!que->res) { 2370299553Serj device_printf(dev, "bus_alloc_resource_any() for" 2371299553Serj " Queue %d interrupt failed [rid=%d]\n", 2372299553Serj que->me, rid); 2373266423Sjfv return (ENXIO); 2374266423Sjfv } 2375266423Sjfv /* Set the handler function */ 2376266423Sjfv error = bus_setup_intr(dev, que->res, 2377266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 2378270346Sjfv ixl_msix_que, que, &que->tag); 2379266423Sjfv if (error) { 2380299553Serj device_printf(dev, "bus_setup_intr() for Queue %d" 2381299553Serj " interrupt handler failed, error %d\n", 2382299553Serj que->me, error); 2383299553Serj // TODO: Check for error from this? 2384299553Serj bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2385266423Sjfv return (error); 2386266423Sjfv } 2387299554Serj error = bus_describe_intr(dev, que->res, que->tag, "q%d", i); 2388299553Serj if (error) { 2389299553Serj device_printf(dev, "bus_describe_intr() for Queue %d" 2390299553Serj " interrupt name failed, error %d\n", 2391299553Serj que->me, error); 2392299553Serj } 2393266423Sjfv /* Bind the vector to a CPU */ 2394277084Sjfv#ifdef RSS 2395277084Sjfv cpu_id = rss_getcpu(i % rss_getnumbuckets()); 2396277084Sjfv#endif 2397299553Serj error = bus_bind_intr(dev, que->res, cpu_id); 2398299553Serj if (error) { 2399299553Serj device_printf(dev, "bus_bind_intr() for Queue %d" 2400299553Serj " to CPU %d failed, error %d\n", 2401299553Serj que->me, cpu_id, error); 2402299553Serj } 2403266423Sjfv que->msix = vector; 2404266423Sjfv } 2405266423Sjfv 2406266423Sjfv return (0); 2407266423Sjfv} 2408266423Sjfv 2409266423Sjfv 2410266423Sjfv/* 2411266423Sjfv * Allocate MSI/X vectors 2412266423Sjfv */ 2413266423Sjfvstatic int 2414270346Sjfvixl_init_msix(struct ixl_pf *pf) 2415266423Sjfv{ 2416266423Sjfv device_t dev = pf->dev; 2417266423Sjfv int rid, want, vectors, queues, available; 2418266423Sjfv 2419266423Sjfv /* Override by tuneable */ 2420270346Sjfv if (ixl_enable_msix == 0) 2421299552Serj goto no_msix; 2422266423Sjfv 2423269198Sjfv /* 2424269198Sjfv ** When used in a virtualized environment 2425269198Sjfv ** PCI BUSMASTER capability may not be set 2426269198Sjfv ** so explicity set it here and rewrite 2427269198Sjfv ** the ENABLE in the MSIX control register 2428269198Sjfv ** at this point to cause the host to 2429269198Sjfv ** successfully initialize us. 2430269198Sjfv */ 2431269198Sjfv { 2432269198Sjfv u16 pci_cmd_word; 2433269198Sjfv int msix_ctrl; 2434269198Sjfv pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); 2435269198Sjfv pci_cmd_word |= PCIM_CMD_BUSMASTEREN; 2436269198Sjfv pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); 2437269198Sjfv pci_find_cap(dev, PCIY_MSIX, &rid); 2438269198Sjfv rid += PCIR_MSIX_CTRL; 2439269198Sjfv msix_ctrl = pci_read_config(dev, rid, 2); 2440269198Sjfv msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; 2441269198Sjfv pci_write_config(dev, rid, msix_ctrl, 2); 2442269198Sjfv } 2443269198Sjfv 2444266423Sjfv /* First try MSI/X */ 2445270346Sjfv rid = PCIR_BAR(IXL_BAR); 2446266423Sjfv pf->msix_mem = bus_alloc_resource_any(dev, 2447266423Sjfv SYS_RES_MEMORY, &rid, RF_ACTIVE); 2448266423Sjfv if (!pf->msix_mem) { 2449266423Sjfv /* May not be enabled */ 2450266423Sjfv device_printf(pf->dev, 2451299549Serj "Unable to map MSIX table\n"); 2452299552Serj goto no_msix; 2453266423Sjfv } 2454266423Sjfv 2455266423Sjfv available = pci_msix_count(dev); 2456266423Sjfv if (available == 0) { /* system has msix disabled */ 2457266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 2458266423Sjfv rid, pf->msix_mem); 2459266423Sjfv pf->msix_mem = NULL; 2460299552Serj goto no_msix; 2461266423Sjfv } 2462266423Sjfv 2463266423Sjfv /* Figure out a reasonable auto config value */ 2464266423Sjfv queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus; 2465266423Sjfv 2466299552Serj /* Override with tunable value if tunable is less than autoconfig count */ 2467270346Sjfv if ((ixl_max_queues != 0) && (ixl_max_queues <= queues)) 2468270346Sjfv queues = ixl_max_queues; 2469299546Serj else if ((ixl_max_queues != 0) && (ixl_max_queues > queues)) 2470299546Serj device_printf(dev, "ixl_max_queues > # of cpus, using " 2471299546Serj "autoconfig amount...\n"); 2472299546Serj /* Or limit maximum auto-configured queues to 8 */ 2473299546Serj else if ((ixl_max_queues == 0) && (queues > 8)) 2474299546Serj queues = 8; 2475266423Sjfv 2476277084Sjfv#ifdef RSS 2477277084Sjfv /* If we're doing RSS, clamp at the number of RSS buckets */ 2478277084Sjfv if (queues > rss_getnumbuckets()) 2479277084Sjfv queues = rss_getnumbuckets(); 2480277084Sjfv#endif 2481277084Sjfv 2482266423Sjfv /* 2483266423Sjfv ** Want one vector (RX/TX pair) per queue 2484266423Sjfv ** plus an additional for the admin queue. 2485266423Sjfv */ 2486266423Sjfv want = queues + 1; 2487266423Sjfv if (want <= available) /* Have enough */ 2488266423Sjfv vectors = want; 2489266423Sjfv else { 2490266423Sjfv device_printf(pf->dev, 2491266423Sjfv "MSIX Configuration Problem, " 2492266423Sjfv "%d vectors available but %d wanted!\n", 2493266423Sjfv available, want); 2494266423Sjfv return (0); /* Will go to Legacy setup */ 2495266423Sjfv } 2496266423Sjfv 2497266423Sjfv if (pci_alloc_msix(dev, &vectors) == 0) { 2498266423Sjfv device_printf(pf->dev, 2499266423Sjfv "Using MSIX interrupts with %d vectors\n", vectors); 2500266423Sjfv pf->msix = vectors; 2501266423Sjfv pf->vsi.num_queues = queues; 2502277084Sjfv#ifdef RSS 2503277084Sjfv /* 2504277084Sjfv * If we're doing RSS, the number of queues needs to 2505277084Sjfv * match the number of RSS buckets that are configured. 2506277084Sjfv * 2507277084Sjfv * + If there's more queues than RSS buckets, we'll end 2508277084Sjfv * up with queues that get no traffic. 2509277084Sjfv * 2510277084Sjfv * + If there's more RSS buckets than queues, we'll end 2511277084Sjfv * up having multiple RSS buckets map to the same queue, 2512277084Sjfv * so there'll be some contention. 2513277084Sjfv */ 2514277084Sjfv if (queues != rss_getnumbuckets()) { 2515277084Sjfv device_printf(dev, 2516277084Sjfv "%s: queues (%d) != RSS buckets (%d)" 2517277084Sjfv "; performance will be impacted.\n", 2518277084Sjfv __func__, queues, rss_getnumbuckets()); 2519277084Sjfv } 2520277084Sjfv#endif 2521266423Sjfv return (vectors); 2522266423Sjfv } 2523299552Serjno_msix: 2524299552Serj vectors = pci_msi_count(dev); 2525266423Sjfv pf->vsi.num_queues = 1; 2526270346Sjfv ixl_max_queues = 1; 2527270346Sjfv ixl_enable_msix = 0; 2528299552Serj if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) 2529299547Serj device_printf(pf->dev, "Using an MSI interrupt\n"); 2530266423Sjfv else { 2531299552Serj vectors = 0; 2532299547Serj device_printf(pf->dev, "Using a Legacy interrupt\n"); 2533266423Sjfv } 2534266423Sjfv return (vectors); 2535266423Sjfv} 2536266423Sjfv 2537266423Sjfv/* 2538299553Serj * Configure admin queue/misc interrupt cause registers in hardware. 2539266423Sjfv */ 2540266423Sjfvstatic void 2541299553Serjixl_configure_intr0_msix(struct ixl_pf *pf) 2542266423Sjfv{ 2543299553Serj struct i40e_hw *hw = &pf->hw; 2544299553Serj u32 reg; 2545266423Sjfv 2546266423Sjfv /* First set up the adminq - vector 0 */ 2547266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, 0); /* disable all */ 2548266423Sjfv rd32(hw, I40E_PFINT_ICR0); /* read to clear */ 2549266423Sjfv 2550266423Sjfv reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | 2551266423Sjfv I40E_PFINT_ICR0_ENA_GRST_MASK | 2552299549Serj I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | 2553266423Sjfv I40E_PFINT_ICR0_ENA_ADMINQ_MASK | 2554266423Sjfv I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK | 2555266423Sjfv I40E_PFINT_ICR0_ENA_VFLR_MASK | 2556266423Sjfv I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK; 2557266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 2558266423Sjfv 2559299547Serj /* 2560299547Serj * 0x7FF is the end of the queue list. 2561299547Serj * This means we won't use MSI-X vector 0 for a queue interrupt 2562299547Serj * in MSIX mode. 2563299547Serj */ 2564266423Sjfv wr32(hw, I40E_PFINT_LNKLST0, 0x7FF); 2565299547Serj /* Value is in 2 usec units, so 0x3E is 62*2 = 124 usecs. */ 2566299547Serj wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x3E); 2567266423Sjfv 2568266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, 2569266423Sjfv I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK | 2570266423Sjfv I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK); 2571266423Sjfv 2572266423Sjfv wr32(hw, I40E_PFINT_STAT_CTL0, 0); 2573299553Serj} 2574266423Sjfv 2575299553Serj/* 2576299553Serj * Configure queue interrupt cause registers in hardware. 2577299553Serj */ 2578299553Serjstatic void 2579299553Serjixl_configure_queue_intr_msix(struct ixl_pf *pf) 2580299553Serj{ 2581299553Serj struct i40e_hw *hw = &pf->hw; 2582299553Serj struct ixl_vsi *vsi = &pf->vsi; 2583299553Serj u32 reg; 2584299553Serj u16 vector = 1; 2585299553Serj 2586266423Sjfv for (int i = 0; i < vsi->num_queues; i++, vector++) { 2587299555Serj wr32(hw, I40E_PFINT_DYN_CTLN(i), 0); 2588299555Serj /* First queue type is RX / 0 */ 2589266423Sjfv wr32(hw, I40E_PFINT_LNKLSTN(i), i); 2590266423Sjfv 2591266423Sjfv reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | 2592270346Sjfv (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | 2593266423Sjfv (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 2594266423Sjfv (i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 2595266423Sjfv (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); 2596266423Sjfv wr32(hw, I40E_QINT_RQCTL(i), reg); 2597266423Sjfv 2598266423Sjfv reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK | 2599270346Sjfv (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | 2600266423Sjfv (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | 2601299555Serj (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | 2602266423Sjfv (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 2603266423Sjfv wr32(hw, I40E_QINT_TQCTL(i), reg); 2604266423Sjfv } 2605266423Sjfv} 2606266423Sjfv 2607266423Sjfv/* 2608266423Sjfv * Configure for MSI single vector operation 2609266423Sjfv */ 2610266423Sjfvstatic void 2611270346Sjfvixl_configure_legacy(struct ixl_pf *pf) 2612266423Sjfv{ 2613266423Sjfv struct i40e_hw *hw = &pf->hw; 2614266423Sjfv u32 reg; 2615266423Sjfv 2616266423Sjfv wr32(hw, I40E_PFINT_ITR0(0), 0); 2617266423Sjfv wr32(hw, I40E_PFINT_ITR0(1), 0); 2618266423Sjfv 2619266423Sjfv /* Setup "other" causes */ 2620266423Sjfv reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK 2621266423Sjfv | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK 2622266423Sjfv | I40E_PFINT_ICR0_ENA_GRST_MASK 2623266423Sjfv | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK 2624266423Sjfv | I40E_PFINT_ICR0_ENA_GPIO_MASK 2625266423Sjfv | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK 2626266423Sjfv | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK 2627266423Sjfv | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK 2628266423Sjfv | I40E_PFINT_ICR0_ENA_VFLR_MASK 2629266423Sjfv | I40E_PFINT_ICR0_ENA_ADMINQ_MASK 2630266423Sjfv ; 2631266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 2632266423Sjfv 2633266423Sjfv /* SW_ITR_IDX = 0, but don't change INTENA */ 2634266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, 2635266423Sjfv I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK | 2636266423Sjfv I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK); 2637266423Sjfv /* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */ 2638266423Sjfv wr32(hw, I40E_PFINT_STAT_CTL0, 0); 2639266423Sjfv 2640266423Sjfv /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ 2641266423Sjfv wr32(hw, I40E_PFINT_LNKLST0, 0); 2642266423Sjfv 2643266423Sjfv /* Associate the queue pair to the vector and enable the q int */ 2644266423Sjfv reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK 2645270346Sjfv | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) 2646266423Sjfv | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 2647266423Sjfv wr32(hw, I40E_QINT_RQCTL(0), reg); 2648266423Sjfv 2649266423Sjfv reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK 2650270346Sjfv | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) 2651270346Sjfv | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 2652266423Sjfv wr32(hw, I40E_QINT_TQCTL(0), reg); 2653266423Sjfv} 2654266423Sjfv 2655266423Sjfv 2656266423Sjfv/* 2657299554Serj * Get initial ITR values from tunable values. 2658266423Sjfv */ 2659266423Sjfvstatic void 2660270346Sjfvixl_configure_itr(struct ixl_pf *pf) 2661266423Sjfv{ 2662266423Sjfv struct i40e_hw *hw = &pf->hw; 2663270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2664270346Sjfv struct ixl_queue *que = vsi->queues; 2665266423Sjfv 2666270346Sjfv vsi->rx_itr_setting = ixl_rx_itr; 2667270346Sjfv vsi->tx_itr_setting = ixl_tx_itr; 2668266423Sjfv 2669266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2670266423Sjfv struct tx_ring *txr = &que->txr; 2671266423Sjfv struct rx_ring *rxr = &que->rxr; 2672266423Sjfv 2673270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i), 2674266423Sjfv vsi->rx_itr_setting); 2675266423Sjfv rxr->itr = vsi->rx_itr_setting; 2676270346Sjfv rxr->latency = IXL_AVE_LATENCY; 2677299554Serj 2678270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i), 2679266423Sjfv vsi->tx_itr_setting); 2680266423Sjfv txr->itr = vsi->tx_itr_setting; 2681270346Sjfv txr->latency = IXL_AVE_LATENCY; 2682266423Sjfv } 2683266423Sjfv} 2684266423Sjfv 2685266423Sjfv 2686266423Sjfvstatic int 2687270346Sjfvixl_allocate_pci_resources(struct ixl_pf *pf) 2688266423Sjfv{ 2689266423Sjfv int rid; 2690266423Sjfv device_t dev = pf->dev; 2691266423Sjfv 2692266423Sjfv rid = PCIR_BAR(0); 2693266423Sjfv pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2694266423Sjfv &rid, RF_ACTIVE); 2695266423Sjfv 2696266423Sjfv if (!(pf->pci_mem)) { 2697299552Serj device_printf(dev, "Unable to allocate bus resource: PCI memory\n"); 2698266423Sjfv return (ENXIO); 2699266423Sjfv } 2700266423Sjfv 2701266423Sjfv pf->osdep.mem_bus_space_tag = 2702266423Sjfv rman_get_bustag(pf->pci_mem); 2703266423Sjfv pf->osdep.mem_bus_space_handle = 2704266423Sjfv rman_get_bushandle(pf->pci_mem); 2705270346Sjfv pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); 2706272285Srstone pf->osdep.flush_reg = I40E_GLGEN_STAT; 2707266423Sjfv pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; 2708266423Sjfv 2709266423Sjfv pf->hw.back = &pf->osdep; 2710266423Sjfv 2711266423Sjfv /* 2712266423Sjfv ** Now setup MSI or MSI/X, should 2713266423Sjfv ** return us the number of supported 2714266423Sjfv ** vectors. (Will be 1 for MSI) 2715266423Sjfv */ 2716270346Sjfv pf->msix = ixl_init_msix(pf); 2717266423Sjfv return (0); 2718266423Sjfv} 2719266423Sjfv 2720299553Serj/* 2721299553Serj * Teardown and release the admin queue/misc vector 2722299553Serj * interrupt. 2723299553Serj */ 2724299553Serjstatic int 2725299553Serjixl_teardown_adminq_msix(struct ixl_pf *pf) 2726266423Sjfv{ 2727266423Sjfv device_t dev = pf->dev; 2728299553Serj int rid; 2729266423Sjfv 2730299553Serj if (pf->admvec) /* we are doing MSIX */ 2731299553Serj rid = pf->admvec + 1; 2732299553Serj else 2733299553Serj (pf->msix != 0) ? (rid = 1):(rid = 0); 2734299553Serj 2735299553Serj // TODO: Check for errors from bus_teardown_intr 2736299553Serj // TODO: Check for errors from bus_release_resource 2737299553Serj if (pf->tag != NULL) { 2738299553Serj bus_teardown_intr(dev, pf->res, pf->tag); 2739299553Serj pf->tag = NULL; 2740299553Serj } 2741299553Serj if (pf->res != NULL) { 2742299553Serj bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); 2743299553Serj pf->res = NULL; 2744299553Serj } 2745299553Serj 2746299553Serj return (0); 2747299553Serj} 2748299553Serj 2749299553Serjstatic int 2750299553Serjixl_teardown_queue_msix(struct ixl_vsi *vsi) 2751299553Serj{ 2752299553Serj struct ixl_queue *que = vsi->queues; 2753299553Serj device_t dev = vsi->dev; 2754299554Serj int rid, error = 0; 2755299553Serj 2756266423Sjfv /* We may get here before stations are setup */ 2757270346Sjfv if ((!ixl_enable_msix) || (que == NULL)) 2758299553Serj return (0); 2759266423Sjfv 2760299553Serj /* Release all MSIX queue resources */ 2761266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2762266423Sjfv rid = que->msix + 1; 2763266423Sjfv if (que->tag != NULL) { 2764299554Serj error = bus_teardown_intr(dev, que->res, que->tag); 2765299554Serj if (error) { 2766299554Serj device_printf(dev, "bus_teardown_intr() for" 2767299554Serj " Queue %d interrupt failed\n", 2768299554Serj que->me); 2769299554Serj // return (ENXIO); 2770299554Serj } 2771266423Sjfv que->tag = NULL; 2772266423Sjfv } 2773299547Serj if (que->res != NULL) { 2774299554Serj error = bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2775299554Serj if (error) { 2776299554Serj device_printf(dev, "bus_release_resource() for" 2777299554Serj " Queue %d interrupt failed [rid=%d]\n", 2778299554Serj que->me, rid); 2779299554Serj // return (ENXIO); 2780299554Serj } 2781299547Serj que->res = NULL; 2782299547Serj } 2783266423Sjfv } 2784266423Sjfv 2785299553Serj return (0); 2786299547Serj} 2787266423Sjfv 2788299547Serjstatic void 2789299547Serjixl_free_pci_resources(struct ixl_pf *pf) 2790299547Serj{ 2791299547Serj device_t dev = pf->dev; 2792299547Serj int memrid; 2793299547Serj 2794299553Serj ixl_teardown_queue_msix(&pf->vsi); 2795299553Serj ixl_teardown_adminq_msix(pf); 2796299547Serj 2797266423Sjfv if (pf->msix) 2798266423Sjfv pci_release_msi(dev); 2799266423Sjfv 2800299547Serj memrid = PCIR_BAR(IXL_BAR); 2801299547Serj 2802266423Sjfv if (pf->msix_mem != NULL) 2803266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 2804266423Sjfv memrid, pf->msix_mem); 2805266423Sjfv 2806266423Sjfv if (pf->pci_mem != NULL) 2807266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 2808266423Sjfv PCIR_BAR(0), pf->pci_mem); 2809266423Sjfv 2810266423Sjfv return; 2811266423Sjfv} 2812266423Sjfv 2813274205Sjfvstatic void 2814274205Sjfvixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type) 2815274205Sjfv{ 2816274205Sjfv /* Display supported media types */ 2817274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX)) 2818274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2819266423Sjfv 2820274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T)) 2821274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); 2822279858Sjfv if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_SX)) 2823279858Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 2824279858Sjfv if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_LX)) 2825279858Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL); 2826274205Sjfv 2827284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_XAUI) || 2828279033Sjfv phy_type & (1 << I40E_PHY_TYPE_XFI) || 2829274205Sjfv phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU)) 2830274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2831279033Sjfv 2832274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR)) 2833274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2834274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR)) 2835274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2836274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T)) 2837274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2838274205Sjfv 2839279033Sjfv if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) || 2840279033Sjfv phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) || 2841279033Sjfv phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) || 2842279033Sjfv phy_type & (1 << I40E_PHY_TYPE_XLAUI) || 2843279033Sjfv phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2844274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2845274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4)) 2846274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2847274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4)) 2848274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); 2849284049Sjfv 2850284049Sjfv#ifndef IFM_ETH_XTYPE 2851284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX)) 2852284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_CX, 0, NULL); 2853284049Sjfv 2854284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) || 2855284049Sjfv phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1) || 2856284049Sjfv phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) || 2857284049Sjfv phy_type & (1 << I40E_PHY_TYPE_SFI)) 2858284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2859284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4)) 2860284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2861284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR)) 2862284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2863284049Sjfv 2864284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2865284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2866284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_XLPPI)) 2867284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2868284049Sjfv#else 2869284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX)) 2870284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL); 2871284049Sjfv 2872284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) 2873284049Sjfv || phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1)) 2874284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL); 2875284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC)) 2876284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL); 2877284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_SFI)) 2878284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL); 2879284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4)) 2880284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); 2881284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR)) 2882284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL); 2883284049Sjfv 2884284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_20GBASE_KR2)) 2885284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL); 2886284049Sjfv 2887284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2888284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL); 2889284049Sjfv if (phy_type & (1 << I40E_PHY_TYPE_XLPPI)) 2890284049Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL); 2891284049Sjfv#endif 2892274205Sjfv} 2893274205Sjfv 2894266423Sjfv/********************************************************************* 2895266423Sjfv * 2896266423Sjfv * Setup networking device structure and register an interface. 2897266423Sjfv * 2898266423Sjfv **********************************************************************/ 2899266423Sjfvstatic int 2900270346Sjfvixl_setup_interface(device_t dev, struct ixl_vsi *vsi) 2901266423Sjfv{ 2902266423Sjfv struct ifnet *ifp; 2903266423Sjfv struct i40e_hw *hw = vsi->hw; 2904270346Sjfv struct ixl_queue *que = vsi->queues; 2905279033Sjfv struct i40e_aq_get_phy_abilities_resp abilities; 2906266423Sjfv enum i40e_status_code aq_error = 0; 2907266423Sjfv 2908270346Sjfv INIT_DEBUGOUT("ixl_setup_interface: begin"); 2909266423Sjfv 2910266423Sjfv ifp = vsi->ifp = if_alloc(IFT_ETHER); 2911266423Sjfv if (ifp == NULL) { 2912266423Sjfv device_printf(dev, "can not allocate ifnet structure\n"); 2913266423Sjfv return (-1); 2914266423Sjfv } 2915266423Sjfv if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2916266423Sjfv ifp->if_mtu = ETHERMTU; 2917299546Serj ifp->if_baudrate = IF_Gbps(40); 2918270346Sjfv ifp->if_init = ixl_init; 2919266423Sjfv ifp->if_softc = vsi; 2920266423Sjfv ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2921270346Sjfv ifp->if_ioctl = ixl_ioctl; 2922266423Sjfv 2923274205Sjfv#if __FreeBSD_version >= 1100036 2924272227Sglebius if_setgetcounterfn(ifp, ixl_get_counter); 2925272227Sglebius#endif 2926272227Sglebius 2927270346Sjfv ifp->if_transmit = ixl_mq_start; 2928266423Sjfv 2929270346Sjfv ifp->if_qflush = ixl_qflush; 2930266423Sjfv 2931266423Sjfv ifp->if_snd.ifq_maxlen = que->num_desc - 2; 2932266423Sjfv 2933266423Sjfv vsi->max_frame_size = 2934266423Sjfv ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 2935266423Sjfv + ETHER_VLAN_ENCAP_LEN; 2936266423Sjfv 2937266423Sjfv /* 2938266423Sjfv * Tell the upper layer(s) we support long frames. 2939266423Sjfv */ 2940270856Sglebius ifp->if_hdrlen = sizeof(struct ether_vlan_header); 2941266423Sjfv 2942266423Sjfv ifp->if_capabilities |= IFCAP_HWCSUM; 2943266423Sjfv ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; 2944266423Sjfv ifp->if_capabilities |= IFCAP_TSO; 2945266423Sjfv ifp->if_capabilities |= IFCAP_JUMBO_MTU; 2946266423Sjfv ifp->if_capabilities |= IFCAP_LRO; 2947266423Sjfv 2948266423Sjfv /* VLAN capabilties */ 2949266423Sjfv ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 2950266423Sjfv | IFCAP_VLAN_HWTSO 2951266423Sjfv | IFCAP_VLAN_MTU 2952266423Sjfv | IFCAP_VLAN_HWCSUM; 2953266423Sjfv ifp->if_capenable = ifp->if_capabilities; 2954266423Sjfv 2955266423Sjfv /* 2956266423Sjfv ** Don't turn this on by default, if vlans are 2957266423Sjfv ** created on another pseudo device (eg. lagg) 2958266423Sjfv ** then vlan events are not passed thru, breaking 2959266423Sjfv ** operation, but with HW FILTER off it works. If 2960270346Sjfv ** using vlans directly on the ixl driver you can 2961266423Sjfv ** enable this and get full hardware tag filtering. 2962266423Sjfv */ 2963266423Sjfv ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 2964266423Sjfv 2965266423Sjfv /* 2966266423Sjfv * Specify the media types supported by this adapter and register 2967266423Sjfv * callbacks to update media and link information 2968266423Sjfv */ 2969270346Sjfv ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change, 2970270346Sjfv ixl_media_status); 2971266423Sjfv 2972279033Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, 2973279033Sjfv FALSE, TRUE, &abilities, NULL); 2974279033Sjfv /* May need delay to detect fiber correctly */ 2975274205Sjfv if (aq_error == I40E_ERR_UNKNOWN_PHY) { 2976274205Sjfv i40e_msec_delay(200); 2977277084Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, 2978279033Sjfv TRUE, &abilities, NULL); 2979279033Sjfv } 2980279033Sjfv if (aq_error) { 2981274205Sjfv if (aq_error == I40E_ERR_UNKNOWN_PHY) 2982274205Sjfv device_printf(dev, "Unknown PHY type detected!\n"); 2983274205Sjfv else 2984279033Sjfv device_printf(dev, 2985279033Sjfv "Error getting supported media types, err %d," 2986279033Sjfv " AQ error %d\n", aq_error, hw->aq.asq_last_status); 2987279033Sjfv return (0); 2988279033Sjfv } 2989266423Sjfv 2990279033Sjfv ixl_add_ifmedia(vsi, abilities.phy_type); 2991279033Sjfv 2992266423Sjfv /* Use autoselect media by default */ 2993266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2994266423Sjfv ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); 2995266423Sjfv 2996274205Sjfv ether_ifattach(ifp, hw->mac.addr); 2997274205Sjfv 2998266423Sjfv return (0); 2999266423Sjfv} 3000266423Sjfv 3001279858Sjfv/* 3002299547Serj** Run when the Admin Queue gets a link state change interrupt. 3003279858Sjfv*/ 3004279858Sjfvstatic void 3005279858Sjfvixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e) 3006266423Sjfv{ 3007279858Sjfv struct i40e_hw *hw = &pf->hw; 3008299547Serj device_t dev = pf->dev; 3009279858Sjfv struct i40e_aqc_get_link_status *status = 3010279858Sjfv (struct i40e_aqc_get_link_status *)&e->desc.params.raw; 3011266423Sjfv 3012299547Serj /* Request link status from adapter */ 3013279858Sjfv hw->phy.get_link_info = TRUE; 3014299547Serj i40e_get_link_status(hw, &pf->link_up); 3015299547Serj 3016299547Serj /* Print out message if an unqualified module is found */ 3017279858Sjfv if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) && 3018279858Sjfv (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) && 3019279858Sjfv (!(status->link_info & I40E_AQ_LINK_UP))) 3020299547Serj device_printf(dev, "Link failed because " 3021299547Serj "an unqualified module was detected!\n"); 3022279858Sjfv 3023299547Serj /* Update OS link info */ 3024299547Serj ixl_update_link_status(pf); 3025266423Sjfv} 3026266423Sjfv 3027266423Sjfv/********************************************************************* 3028266423Sjfv * 3029279033Sjfv * Get Firmware Switch configuration 3030279033Sjfv * - this will need to be more robust when more complex 3031279033Sjfv * switch configurations are enabled. 3032266423Sjfv * 3033266423Sjfv **********************************************************************/ 3034266423Sjfvstatic int 3035279033Sjfvixl_switch_config(struct ixl_pf *pf) 3036266423Sjfv{ 3037279033Sjfv struct i40e_hw *hw = &pf->hw; 3038279033Sjfv struct ixl_vsi *vsi = &pf->vsi; 3039266423Sjfv device_t dev = vsi->dev; 3040266423Sjfv struct i40e_aqc_get_switch_config_resp *sw_config; 3041266423Sjfv u8 aq_buf[I40E_AQ_LARGE_BUF]; 3042279858Sjfv int ret; 3043266423Sjfv u16 next = 0; 3044266423Sjfv 3045279033Sjfv memset(&aq_buf, 0, sizeof(aq_buf)); 3046266423Sjfv sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 3047266423Sjfv ret = i40e_aq_get_switch_config(hw, sw_config, 3048266423Sjfv sizeof(aq_buf), &next, NULL); 3049266423Sjfv if (ret) { 3050299554Serj device_printf(dev, "aq_get_switch_config() failed, error %d," 3051299554Serj " aq_error %d\n", ret, pf->hw.aq.asq_last_status); 3052266423Sjfv return (ret); 3053266423Sjfv } 3054270346Sjfv#ifdef IXL_DEBUG 3055279858Sjfv device_printf(dev, 3056279858Sjfv "Switch config: header reported: %d in structure, %d total\n", 3057266423Sjfv sw_config->header.num_reported, sw_config->header.num_total); 3058279858Sjfv for (int i = 0; i < sw_config->header.num_reported; i++) { 3059279858Sjfv device_printf(dev, 3060279858Sjfv "%d: type=%d seid=%d uplink=%d downlink=%d\n", i, 3061279858Sjfv sw_config->element[i].element_type, 3062279858Sjfv sw_config->element[i].seid, 3063279858Sjfv sw_config->element[i].uplink_seid, 3064279858Sjfv sw_config->element[i].downlink_seid); 3065279858Sjfv } 3066266423Sjfv#endif 3067279033Sjfv /* Simplified due to a single VSI at the moment */ 3068279858Sjfv vsi->uplink_seid = sw_config->element[0].uplink_seid; 3069279858Sjfv vsi->downlink_seid = sw_config->element[0].downlink_seid; 3070266423Sjfv vsi->seid = sw_config->element[0].seid; 3071279033Sjfv return (ret); 3072279033Sjfv} 3073266423Sjfv 3074279033Sjfv/********************************************************************* 3075279033Sjfv * 3076279033Sjfv * Initialize the VSI: this handles contexts, which means things 3077279033Sjfv * like the number of descriptors, buffer size, 3078279033Sjfv * plus we init the rings thru this function. 3079279033Sjfv * 3080279033Sjfv **********************************************************************/ 3081279033Sjfvstatic int 3082279033Sjfvixl_initialize_vsi(struct ixl_vsi *vsi) 3083279033Sjfv{ 3084279858Sjfv struct ixl_pf *pf = vsi->back; 3085279033Sjfv struct ixl_queue *que = vsi->queues; 3086279033Sjfv device_t dev = vsi->dev; 3087279033Sjfv struct i40e_hw *hw = vsi->hw; 3088279033Sjfv struct i40e_vsi_context ctxt; 3089279033Sjfv int err = 0; 3090279033Sjfv 3091266423Sjfv memset(&ctxt, 0, sizeof(ctxt)); 3092266423Sjfv ctxt.seid = vsi->seid; 3093279858Sjfv if (pf->veb_seid != 0) 3094279858Sjfv ctxt.uplink_seid = pf->veb_seid; 3095266423Sjfv ctxt.pf_num = hw->pf_id; 3096279033Sjfv err = i40e_aq_get_vsi_params(hw, &ctxt, NULL); 3097279033Sjfv if (err) { 3098299554Serj device_printf(dev, "i40e_aq_get_vsi_params() failed, error %d" 3099299554Serj " aq_error %d\n", err, hw->aq.asq_last_status); 3100279033Sjfv return (err); 3101266423Sjfv } 3102270346Sjfv#ifdef IXL_DEBUG 3103299548Serj device_printf(dev, "get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, " 3104266423Sjfv "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, " 3105266423Sjfv "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid, 3106266423Sjfv ctxt.uplink_seid, ctxt.vsi_number, 3107266423Sjfv ctxt.vsis_allocated, ctxt.vsis_unallocated, 3108266423Sjfv ctxt.flags, ctxt.pf_num, ctxt.vf_num, 3109266423Sjfv ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits); 3110266423Sjfv#endif 3111266423Sjfv /* 3112266423Sjfv ** Set the queue and traffic class bits 3113266423Sjfv ** - when multiple traffic classes are supported 3114266423Sjfv ** this will need to be more robust. 3115266423Sjfv */ 3116266423Sjfv ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID; 3117266423Sjfv ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG; 3118299556Serj /* In contig mode, que_mapping[0] is first queue index used by this VSI */ 3119299556Serj ctxt.info.queue_mapping[0] = 0; 3120299556Serj /* 3121299556Serj * This VSI will only use traffic class 0; start traffic class 0's 3122299556Serj * queue allocation at queue 0, and assign it 64 (2^6) queues (though 3123299556Serj * the driver may not use all of them). 3124299556Serj */ 3125299556Serj ctxt.info.tc_mapping[0] = ((0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) 3126299556Serj & I40E_AQ_VSI_TC_QUE_OFFSET_MASK) | 3127299556Serj ((6 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT) 3128299556Serj & I40E_AQ_VSI_TC_QUE_NUMBER_MASK); 3129266423Sjfv 3130266423Sjfv /* Set VLAN receive stripping mode */ 3131266423Sjfv ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; 3132266423Sjfv ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; 3133266423Sjfv if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 3134299548Serj ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 3135266423Sjfv else 3136299548Serj ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 3137266423Sjfv 3138266423Sjfv /* Keep copy of VSI info in VSI for statistic counters */ 3139266423Sjfv memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); 3140266423Sjfv 3141266423Sjfv /* Reset VSI statistics */ 3142270346Sjfv ixl_vsi_reset_stats(vsi); 3143266423Sjfv vsi->hw_filters_add = 0; 3144266423Sjfv vsi->hw_filters_del = 0; 3145266423Sjfv 3146279858Sjfv ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF); 3147279858Sjfv 3148279033Sjfv err = i40e_aq_update_vsi_params(hw, &ctxt, NULL); 3149279033Sjfv if (err) { 3150299548Serj device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d, aq_error %d\n", 3151299548Serj err, hw->aq.asq_last_status); 3152279033Sjfv return (err); 3153279033Sjfv } 3154266423Sjfv 3155266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 3156266423Sjfv struct tx_ring *txr = &que->txr; 3157266423Sjfv struct rx_ring *rxr = &que->rxr; 3158266423Sjfv struct i40e_hmc_obj_txq tctx; 3159266423Sjfv struct i40e_hmc_obj_rxq rctx; 3160266423Sjfv u32 txctl; 3161266423Sjfv u16 size; 3162266423Sjfv 3163266423Sjfv /* Setup the HMC TX Context */ 3164266423Sjfv size = que->num_desc * sizeof(struct i40e_tx_desc); 3165266423Sjfv memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq)); 3166266423Sjfv tctx.new_context = 1; 3167279858Sjfv tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS); 3168266423Sjfv tctx.qlen = que->num_desc; 3169266423Sjfv tctx.fc_ena = 0; 3170269198Sjfv tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */ 3171269198Sjfv /* Enable HEAD writeback */ 3172269198Sjfv tctx.head_wb_ena = 1; 3173269198Sjfv tctx.head_wb_addr = txr->dma.pa + 3174269198Sjfv (que->num_desc * sizeof(struct i40e_tx_desc)); 3175266423Sjfv tctx.rdylist_act = 0; 3176266423Sjfv err = i40e_clear_lan_tx_queue_context(hw, i); 3177266423Sjfv if (err) { 3178266423Sjfv device_printf(dev, "Unable to clear TX context\n"); 3179266423Sjfv break; 3180266423Sjfv } 3181266423Sjfv err = i40e_set_lan_tx_queue_context(hw, i, &tctx); 3182266423Sjfv if (err) { 3183266423Sjfv device_printf(dev, "Unable to set TX context\n"); 3184266423Sjfv break; 3185266423Sjfv } 3186266423Sjfv /* Associate the ring with this PF */ 3187266423Sjfv txctl = I40E_QTX_CTL_PF_QUEUE; 3188266423Sjfv txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & 3189266423Sjfv I40E_QTX_CTL_PF_INDX_MASK); 3190266423Sjfv wr32(hw, I40E_QTX_CTL(i), txctl); 3191270346Sjfv ixl_flush(hw); 3192266423Sjfv 3193266423Sjfv /* Do ring (re)init */ 3194270346Sjfv ixl_init_tx_ring(que); 3195266423Sjfv 3196266423Sjfv /* Next setup the HMC RX Context */ 3197279858Sjfv if (vsi->max_frame_size <= MCLBYTES) 3198266423Sjfv rxr->mbuf_sz = MCLBYTES; 3199266423Sjfv else 3200266423Sjfv rxr->mbuf_sz = MJUMPAGESIZE; 3201266423Sjfv 3202266423Sjfv u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len; 3203266423Sjfv 3204266423Sjfv /* Set up an RX context for the HMC */ 3205266423Sjfv memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq)); 3206266423Sjfv rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT; 3207266423Sjfv /* ignore header split for now */ 3208266423Sjfv rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; 3209266423Sjfv rctx.rxmax = (vsi->max_frame_size < max_rxmax) ? 3210266423Sjfv vsi->max_frame_size : max_rxmax; 3211266423Sjfv rctx.dtype = 0; 3212266423Sjfv rctx.dsize = 1; /* do 32byte descriptors */ 3213266423Sjfv rctx.hsplit_0 = 0; /* no HDR split initially */ 3214279858Sjfv rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS); 3215266423Sjfv rctx.qlen = que->num_desc; 3216266423Sjfv rctx.tphrdesc_ena = 1; 3217266423Sjfv rctx.tphwdesc_ena = 1; 3218266423Sjfv rctx.tphdata_ena = 0; 3219266423Sjfv rctx.tphhead_ena = 0; 3220266423Sjfv rctx.lrxqthresh = 2; 3221266423Sjfv rctx.crcstrip = 1; 3222266423Sjfv rctx.l2tsel = 1; 3223266423Sjfv rctx.showiv = 1; 3224266423Sjfv rctx.fc_ena = 0; 3225266423Sjfv rctx.prefena = 1; 3226266423Sjfv 3227266423Sjfv err = i40e_clear_lan_rx_queue_context(hw, i); 3228266423Sjfv if (err) { 3229266423Sjfv device_printf(dev, 3230266423Sjfv "Unable to clear RX context %d\n", i); 3231266423Sjfv break; 3232266423Sjfv } 3233266423Sjfv err = i40e_set_lan_rx_queue_context(hw, i, &rctx); 3234266423Sjfv if (err) { 3235266423Sjfv device_printf(dev, "Unable to set RX context %d\n", i); 3236266423Sjfv break; 3237266423Sjfv } 3238270346Sjfv err = ixl_init_rx_ring(que); 3239266423Sjfv if (err) { 3240266423Sjfv device_printf(dev, "Fail in init_rx_ring %d\n", i); 3241266423Sjfv break; 3242266423Sjfv } 3243279860Sjfv#ifdef DEV_NETMAP 3244279860Sjfv /* preserve queue */ 3245279860Sjfv if (vsi->ifp->if_capenable & IFCAP_NETMAP) { 3246279860Sjfv struct netmap_adapter *na = NA(vsi->ifp); 3247279860Sjfv struct netmap_kring *kring = &na->rx_rings[i]; 3248279860Sjfv int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); 3249279860Sjfv wr32(vsi->hw, I40E_QRX_TAIL(que->me), t); 3250279860Sjfv } else 3251279860Sjfv#endif /* DEV_NETMAP */ 3252266423Sjfv wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1); 3253266423Sjfv } 3254266423Sjfv return (err); 3255266423Sjfv} 3256266423Sjfv 3257266423Sjfv 3258266423Sjfv/********************************************************************* 3259266423Sjfv * 3260266423Sjfv * Free all VSI structs. 3261266423Sjfv * 3262266423Sjfv **********************************************************************/ 3263266423Sjfvvoid 3264270346Sjfvixl_free_vsi(struct ixl_vsi *vsi) 3265266423Sjfv{ 3266270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 3267270346Sjfv struct ixl_queue *que = vsi->queues; 3268266423Sjfv 3269266423Sjfv /* Free station queues */ 3270299549Serj if (!vsi->queues) 3271299549Serj goto free_filters; 3272299549Serj 3273266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 3274266423Sjfv struct tx_ring *txr = &que->txr; 3275266423Sjfv struct rx_ring *rxr = &que->rxr; 3276266423Sjfv 3277266423Sjfv if (!mtx_initialized(&txr->mtx)) /* uninitialized */ 3278266423Sjfv continue; 3279270346Sjfv IXL_TX_LOCK(txr); 3280270346Sjfv ixl_free_que_tx(que); 3281266423Sjfv if (txr->base) 3282271834Sbz i40e_free_dma_mem(&pf->hw, &txr->dma); 3283270346Sjfv IXL_TX_UNLOCK(txr); 3284270346Sjfv IXL_TX_LOCK_DESTROY(txr); 3285266423Sjfv 3286266423Sjfv if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ 3287266423Sjfv continue; 3288270346Sjfv IXL_RX_LOCK(rxr); 3289270346Sjfv ixl_free_que_rx(que); 3290266423Sjfv if (rxr->base) 3291271834Sbz i40e_free_dma_mem(&pf->hw, &rxr->dma); 3292270346Sjfv IXL_RX_UNLOCK(rxr); 3293270346Sjfv IXL_RX_LOCK_DESTROY(rxr); 3294266423Sjfv 3295266423Sjfv } 3296266423Sjfv free(vsi->queues, M_DEVBUF); 3297266423Sjfv 3298299549Serjfree_filters: 3299266423Sjfv /* Free VSI filter list */ 3300279858Sjfv ixl_free_mac_filters(vsi); 3301279858Sjfv} 3302279858Sjfv 3303279858Sjfvstatic void 3304279858Sjfvixl_free_mac_filters(struct ixl_vsi *vsi) 3305279858Sjfv{ 3306279858Sjfv struct ixl_mac_filter *f; 3307279858Sjfv 3308266423Sjfv while (!SLIST_EMPTY(&vsi->ftl)) { 3309266423Sjfv f = SLIST_FIRST(&vsi->ftl); 3310266423Sjfv SLIST_REMOVE_HEAD(&vsi->ftl, next); 3311266423Sjfv free(f, M_DEVBUF); 3312266423Sjfv } 3313266423Sjfv} 3314266423Sjfv 3315266423Sjfv 3316266423Sjfv/********************************************************************* 3317266423Sjfv * 3318266423Sjfv * Allocate memory for the VSI (virtual station interface) and their 3319266423Sjfv * associated queues, rings and the descriptors associated with each, 3320266423Sjfv * called only once at attach. 3321266423Sjfv * 3322266423Sjfv **********************************************************************/ 3323266423Sjfvstatic int 3324270346Sjfvixl_setup_stations(struct ixl_pf *pf) 3325266423Sjfv{ 3326266423Sjfv device_t dev = pf->dev; 3327270346Sjfv struct ixl_vsi *vsi; 3328270346Sjfv struct ixl_queue *que; 3329266423Sjfv struct tx_ring *txr; 3330266423Sjfv struct rx_ring *rxr; 3331266423Sjfv int rsize, tsize; 3332266423Sjfv int error = I40E_SUCCESS; 3333266423Sjfv 3334266423Sjfv vsi = &pf->vsi; 3335266423Sjfv vsi->back = (void *)pf; 3336266423Sjfv vsi->hw = &pf->hw; 3337266423Sjfv vsi->id = 0; 3338266423Sjfv vsi->num_vlans = 0; 3339279858Sjfv vsi->back = pf; 3340266423Sjfv 3341266423Sjfv /* Get memory for the station queues */ 3342266423Sjfv if (!(vsi->queues = 3343270346Sjfv (struct ixl_queue *) malloc(sizeof(struct ixl_queue) * 3344266423Sjfv vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { 3345266423Sjfv device_printf(dev, "Unable to allocate queue memory\n"); 3346266423Sjfv error = ENOMEM; 3347266423Sjfv goto early; 3348266423Sjfv } 3349266423Sjfv 3350266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 3351266423Sjfv que = &vsi->queues[i]; 3352270346Sjfv que->num_desc = ixl_ringsz; 3353266423Sjfv que->me = i; 3354266423Sjfv que->vsi = vsi; 3355269198Sjfv /* mark the queue as active */ 3356269198Sjfv vsi->active_queues |= (u64)1 << que->me; 3357266423Sjfv txr = &que->txr; 3358266423Sjfv txr->que = que; 3359269198Sjfv txr->tail = I40E_QTX_TAIL(que->me); 3360266423Sjfv 3361266423Sjfv /* Initialize the TX lock */ 3362266423Sjfv snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", 3363266423Sjfv device_get_nameunit(dev), que->me); 3364266423Sjfv mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF); 3365266423Sjfv /* Create the TX descriptor ring */ 3366269198Sjfv tsize = roundup2((que->num_desc * 3367269198Sjfv sizeof(struct i40e_tx_desc)) + 3368269198Sjfv sizeof(u32), DBA_ALIGN); 3369271834Sbz if (i40e_allocate_dma_mem(&pf->hw, 3370271834Sbz &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) { 3371266423Sjfv device_printf(dev, 3372266423Sjfv "Unable to allocate TX Descriptor memory\n"); 3373266423Sjfv error = ENOMEM; 3374266423Sjfv goto fail; 3375266423Sjfv } 3376266423Sjfv txr->base = (struct i40e_tx_desc *)txr->dma.va; 3377266423Sjfv bzero((void *)txr->base, tsize); 3378266423Sjfv /* Now allocate transmit soft structs for the ring */ 3379270346Sjfv if (ixl_allocate_tx_data(que)) { 3380266423Sjfv device_printf(dev, 3381266423Sjfv "Critical Failure setting up TX structures\n"); 3382266423Sjfv error = ENOMEM; 3383266423Sjfv goto fail; 3384266423Sjfv } 3385266423Sjfv /* Allocate a buf ring */ 3386266423Sjfv txr->br = buf_ring_alloc(4096, M_DEVBUF, 3387299547Serj M_NOWAIT, &txr->mtx); 3388266423Sjfv if (txr->br == NULL) { 3389266423Sjfv device_printf(dev, 3390266423Sjfv "Critical Failure setting up TX buf ring\n"); 3391266423Sjfv error = ENOMEM; 3392266423Sjfv goto fail; 3393266423Sjfv } 3394266423Sjfv 3395266423Sjfv /* 3396266423Sjfv * Next the RX queues... 3397266423Sjfv */ 3398266423Sjfv rsize = roundup2(que->num_desc * 3399266423Sjfv sizeof(union i40e_rx_desc), DBA_ALIGN); 3400266423Sjfv rxr = &que->rxr; 3401266423Sjfv rxr->que = que; 3402269198Sjfv rxr->tail = I40E_QRX_TAIL(que->me); 3403266423Sjfv 3404266423Sjfv /* Initialize the RX side lock */ 3405266423Sjfv snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", 3406266423Sjfv device_get_nameunit(dev), que->me); 3407266423Sjfv mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF); 3408266423Sjfv 3409271834Sbz if (i40e_allocate_dma_mem(&pf->hw, 3410271834Sbz &rxr->dma, i40e_mem_reserved, rsize, 4096)) { 3411266423Sjfv device_printf(dev, 3412266423Sjfv "Unable to allocate RX Descriptor memory\n"); 3413266423Sjfv error = ENOMEM; 3414266423Sjfv goto fail; 3415266423Sjfv } 3416266423Sjfv rxr->base = (union i40e_rx_desc *)rxr->dma.va; 3417266423Sjfv bzero((void *)rxr->base, rsize); 3418266423Sjfv 3419266423Sjfv /* Allocate receive soft structs for the ring*/ 3420270346Sjfv if (ixl_allocate_rx_data(que)) { 3421266423Sjfv device_printf(dev, 3422266423Sjfv "Critical Failure setting up receive structs\n"); 3423266423Sjfv error = ENOMEM; 3424266423Sjfv goto fail; 3425266423Sjfv } 3426266423Sjfv } 3427266423Sjfv 3428266423Sjfv return (0); 3429266423Sjfv 3430266423Sjfvfail: 3431266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 3432266423Sjfv que = &vsi->queues[i]; 3433266423Sjfv rxr = &que->rxr; 3434266423Sjfv txr = &que->txr; 3435266423Sjfv if (rxr->base) 3436271834Sbz i40e_free_dma_mem(&pf->hw, &rxr->dma); 3437266423Sjfv if (txr->base) 3438271834Sbz i40e_free_dma_mem(&pf->hw, &txr->dma); 3439266423Sjfv } 3440266423Sjfv 3441266423Sjfvearly: 3442266423Sjfv return (error); 3443266423Sjfv} 3444266423Sjfv 3445266423Sjfv/* 3446266423Sjfv** Provide a update to the queue RX 3447266423Sjfv** interrupt moderation value. 3448266423Sjfv*/ 3449266423Sjfvstatic void 3450270346Sjfvixl_set_queue_rx_itr(struct ixl_queue *que) 3451266423Sjfv{ 3452270346Sjfv struct ixl_vsi *vsi = que->vsi; 3453266423Sjfv struct i40e_hw *hw = vsi->hw; 3454266423Sjfv struct rx_ring *rxr = &que->rxr; 3455266423Sjfv u16 rx_itr; 3456266423Sjfv u16 rx_latency = 0; 3457266423Sjfv int rx_bytes; 3458266423Sjfv 3459266423Sjfv /* Idle, do nothing */ 3460266423Sjfv if (rxr->bytes == 0) 3461266423Sjfv return; 3462266423Sjfv 3463270346Sjfv if (ixl_dynamic_rx_itr) { 3464266423Sjfv rx_bytes = rxr->bytes/rxr->itr; 3465266423Sjfv rx_itr = rxr->itr; 3466266423Sjfv 3467266423Sjfv /* Adjust latency range */ 3468266423Sjfv switch (rxr->latency) { 3469270346Sjfv case IXL_LOW_LATENCY: 3470266423Sjfv if (rx_bytes > 10) { 3471270346Sjfv rx_latency = IXL_AVE_LATENCY; 3472270346Sjfv rx_itr = IXL_ITR_20K; 3473266423Sjfv } 3474266423Sjfv break; 3475270346Sjfv case IXL_AVE_LATENCY: 3476266423Sjfv if (rx_bytes > 20) { 3477270346Sjfv rx_latency = IXL_BULK_LATENCY; 3478270346Sjfv rx_itr = IXL_ITR_8K; 3479266423Sjfv } else if (rx_bytes <= 10) { 3480270346Sjfv rx_latency = IXL_LOW_LATENCY; 3481270346Sjfv rx_itr = IXL_ITR_100K; 3482266423Sjfv } 3483266423Sjfv break; 3484270346Sjfv case IXL_BULK_LATENCY: 3485266423Sjfv if (rx_bytes <= 20) { 3486270346Sjfv rx_latency = IXL_AVE_LATENCY; 3487270346Sjfv rx_itr = IXL_ITR_20K; 3488266423Sjfv } 3489266423Sjfv break; 3490266423Sjfv } 3491266423Sjfv 3492266423Sjfv rxr->latency = rx_latency; 3493266423Sjfv 3494266423Sjfv if (rx_itr != rxr->itr) { 3495266423Sjfv /* do an exponential smoothing */ 3496266423Sjfv rx_itr = (10 * rx_itr * rxr->itr) / 3497266423Sjfv ((9 * rx_itr) + rxr->itr); 3498270346Sjfv rxr->itr = rx_itr & IXL_MAX_ITR; 3499270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 3500266423Sjfv que->me), rxr->itr); 3501266423Sjfv } 3502266423Sjfv } else { /* We may have have toggled to non-dynamic */ 3503270346Sjfv if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) 3504270346Sjfv vsi->rx_itr_setting = ixl_rx_itr; 3505266423Sjfv /* Update the hardware if needed */ 3506266423Sjfv if (rxr->itr != vsi->rx_itr_setting) { 3507266423Sjfv rxr->itr = vsi->rx_itr_setting; 3508270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 3509266423Sjfv que->me), rxr->itr); 3510266423Sjfv } 3511266423Sjfv } 3512266423Sjfv rxr->bytes = 0; 3513266423Sjfv rxr->packets = 0; 3514266423Sjfv return; 3515266423Sjfv} 3516266423Sjfv 3517266423Sjfv 3518266423Sjfv/* 3519266423Sjfv** Provide a update to the queue TX 3520266423Sjfv** interrupt moderation value. 3521266423Sjfv*/ 3522266423Sjfvstatic void 3523270346Sjfvixl_set_queue_tx_itr(struct ixl_queue *que) 3524266423Sjfv{ 3525270346Sjfv struct ixl_vsi *vsi = que->vsi; 3526266423Sjfv struct i40e_hw *hw = vsi->hw; 3527266423Sjfv struct tx_ring *txr = &que->txr; 3528266423Sjfv u16 tx_itr; 3529266423Sjfv u16 tx_latency = 0; 3530266423Sjfv int tx_bytes; 3531266423Sjfv 3532266423Sjfv 3533266423Sjfv /* Idle, do nothing */ 3534266423Sjfv if (txr->bytes == 0) 3535266423Sjfv return; 3536266423Sjfv 3537270346Sjfv if (ixl_dynamic_tx_itr) { 3538266423Sjfv tx_bytes = txr->bytes/txr->itr; 3539266423Sjfv tx_itr = txr->itr; 3540266423Sjfv 3541266423Sjfv switch (txr->latency) { 3542270346Sjfv case IXL_LOW_LATENCY: 3543266423Sjfv if (tx_bytes > 10) { 3544270346Sjfv tx_latency = IXL_AVE_LATENCY; 3545270346Sjfv tx_itr = IXL_ITR_20K; 3546266423Sjfv } 3547266423Sjfv break; 3548270346Sjfv case IXL_AVE_LATENCY: 3549266423Sjfv if (tx_bytes > 20) { 3550270346Sjfv tx_latency = IXL_BULK_LATENCY; 3551270346Sjfv tx_itr = IXL_ITR_8K; 3552266423Sjfv } else if (tx_bytes <= 10) { 3553270346Sjfv tx_latency = IXL_LOW_LATENCY; 3554270346Sjfv tx_itr = IXL_ITR_100K; 3555266423Sjfv } 3556266423Sjfv break; 3557270346Sjfv case IXL_BULK_LATENCY: 3558266423Sjfv if (tx_bytes <= 20) { 3559270346Sjfv tx_latency = IXL_AVE_LATENCY; 3560270346Sjfv tx_itr = IXL_ITR_20K; 3561266423Sjfv } 3562266423Sjfv break; 3563266423Sjfv } 3564266423Sjfv 3565266423Sjfv txr->latency = tx_latency; 3566266423Sjfv 3567266423Sjfv if (tx_itr != txr->itr) { 3568266423Sjfv /* do an exponential smoothing */ 3569266423Sjfv tx_itr = (10 * tx_itr * txr->itr) / 3570266423Sjfv ((9 * tx_itr) + txr->itr); 3571270346Sjfv txr->itr = tx_itr & IXL_MAX_ITR; 3572270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 3573266423Sjfv que->me), txr->itr); 3574266423Sjfv } 3575266423Sjfv 3576266423Sjfv } else { /* We may have have toggled to non-dynamic */ 3577270346Sjfv if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC) 3578270346Sjfv vsi->tx_itr_setting = ixl_tx_itr; 3579266423Sjfv /* Update the hardware if needed */ 3580266423Sjfv if (txr->itr != vsi->tx_itr_setting) { 3581266423Sjfv txr->itr = vsi->tx_itr_setting; 3582270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 3583266423Sjfv que->me), txr->itr); 3584266423Sjfv } 3585266423Sjfv } 3586266423Sjfv txr->bytes = 0; 3587266423Sjfv txr->packets = 0; 3588266423Sjfv return; 3589266423Sjfv} 3590266423Sjfv 3591279858Sjfv#define QUEUE_NAME_LEN 32 3592266423Sjfv 3593266423Sjfvstatic void 3594279858Sjfvixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi, 3595279858Sjfv struct sysctl_ctx_list *ctx, const char *sysctl_name) 3596279858Sjfv{ 3597279858Sjfv struct sysctl_oid *tree; 3598279858Sjfv struct sysctl_oid_list *child; 3599279858Sjfv struct sysctl_oid_list *vsi_list; 3600279858Sjfv 3601279858Sjfv tree = device_get_sysctl_tree(pf->dev); 3602279858Sjfv child = SYSCTL_CHILDREN(tree); 3603279858Sjfv vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name, 3604279858Sjfv CTLFLAG_RD, NULL, "VSI Number"); 3605279858Sjfv vsi_list = SYSCTL_CHILDREN(vsi->vsi_node); 3606279858Sjfv 3607279858Sjfv ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats); 3608279858Sjfv} 3609279858Sjfv 3610299554Serj#ifdef IXL_DEBUG 3611299554Serj/** 3612299554Serj * ixl_sysctl_qtx_tail_handler 3613299554Serj * Retrieves I40E_QTX_TAIL value from hardware 3614299554Serj * for a sysctl. 3615299554Serj */ 3616299554Serjstatic int 3617299554Serjixl_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS) 3618299554Serj{ 3619299554Serj struct ixl_queue *que; 3620299554Serj int error; 3621299554Serj u32 val; 3622299554Serj 3623299554Serj que = ((struct ixl_queue *)oidp->oid_arg1); 3624299554Serj if (!que) return 0; 3625299554Serj 3626299554Serj val = rd32(que->vsi->hw, que->txr.tail); 3627299554Serj error = sysctl_handle_int(oidp, &val, 0, req); 3628299554Serj if (error || !req->newptr) 3629299554Serj return error; 3630299554Serj return (0); 3631299554Serj} 3632299554Serj 3633299554Serj/** 3634299554Serj * ixl_sysctl_qrx_tail_handler 3635299554Serj * Retrieves I40E_QRX_TAIL value from hardware 3636299554Serj * for a sysctl. 3637299554Serj */ 3638299554Serjstatic int 3639299554Serjixl_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS) 3640299554Serj{ 3641299554Serj struct ixl_queue *que; 3642299554Serj int error; 3643299554Serj u32 val; 3644299554Serj 3645299554Serj que = ((struct ixl_queue *)oidp->oid_arg1); 3646299554Serj if (!que) return 0; 3647299554Serj 3648299554Serj val = rd32(que->vsi->hw, que->rxr.tail); 3649299554Serj error = sysctl_handle_int(oidp, &val, 0, req); 3650299554Serj if (error || !req->newptr) 3651299554Serj return error; 3652299554Serj return (0); 3653299554Serj} 3654299554Serj#endif 3655299554Serj 3656279858Sjfvstatic void 3657270346Sjfvixl_add_hw_stats(struct ixl_pf *pf) 3658266423Sjfv{ 3659266423Sjfv device_t dev = pf->dev; 3660270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 3661270346Sjfv struct ixl_queue *queues = vsi->queues; 3662269198Sjfv struct i40e_hw_port_stats *pf_stats = &pf->stats; 3663266423Sjfv 3664266423Sjfv struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 3665266423Sjfv struct sysctl_oid *tree = device_get_sysctl_tree(dev); 3666266423Sjfv struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 3667279858Sjfv struct sysctl_oid_list *vsi_list; 3668266423Sjfv 3669279858Sjfv struct sysctl_oid *queue_node; 3670279858Sjfv struct sysctl_oid_list *queue_list; 3671266423Sjfv 3672269198Sjfv struct tx_ring *txr; 3673269198Sjfv struct rx_ring *rxr; 3674279858Sjfv char queue_namebuf[QUEUE_NAME_LEN]; 3675266423Sjfv 3676266423Sjfv /* Driver statistics */ 3677266423Sjfv SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 3678266423Sjfv CTLFLAG_RD, &pf->watchdog_events, 3679266423Sjfv "Watchdog timeouts"); 3680266423Sjfv SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq", 3681266423Sjfv CTLFLAG_RD, &pf->admin_irq, 3682266423Sjfv "Admin Queue IRQ Handled"); 3683266423Sjfv 3684279858Sjfv ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf"); 3685279858Sjfv vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node); 3686266423Sjfv 3687266423Sjfv /* Queue statistics */ 3688266423Sjfv for (int q = 0; q < vsi->num_queues; q++) { 3689269198Sjfv snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); 3690279858Sjfv queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, 3691279858Sjfv OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #"); 3692266423Sjfv queue_list = SYSCTL_CHILDREN(queue_node); 3693266423Sjfv 3694269198Sjfv txr = &(queues[q].txr); 3695269198Sjfv rxr = &(queues[q].rxr); 3696269198Sjfv 3697269198Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", 3698266423Sjfv CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), 3699266423Sjfv "m_defrag() failed"); 3700266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 3701266423Sjfv CTLFLAG_RD, &(queues[q].irqs), 3702266423Sjfv "irqs on this queue"); 3703269198Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", 3704266423Sjfv CTLFLAG_RD, &(queues[q].tso), 3705266423Sjfv "TSO"); 3706269198Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup", 3707266423Sjfv CTLFLAG_RD, &(queues[q].tx_dma_setup), 3708266423Sjfv "Driver tx dma failure in xmit"); 3709266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 3710266423Sjfv CTLFLAG_RD, &(txr->no_desc), 3711266423Sjfv "Queue No Descriptor Available"); 3712266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 3713266423Sjfv CTLFLAG_RD, &(txr->total_packets), 3714266423Sjfv "Queue Packets Transmitted"); 3715266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", 3716270346Sjfv CTLFLAG_RD, &(txr->tx_bytes), 3717266423Sjfv "Queue Bytes Transmitted"); 3718266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 3719266423Sjfv CTLFLAG_RD, &(rxr->rx_packets), 3720266423Sjfv "Queue Packets Received"); 3721266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 3722266423Sjfv CTLFLAG_RD, &(rxr->rx_bytes), 3723266423Sjfv "Queue Bytes Received"); 3724299554Serj SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_desc_err", 3725299554Serj CTLFLAG_RD, &(rxr->desc_errs), 3726299554Serj "Queue Rx Descriptor Errors"); 3727299554Serj SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_itr", 3728299554Serj CTLFLAG_RD, &(rxr->itr), 0, 3729299554Serj "Queue Rx ITR Interval"); 3730299554Serj SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "tx_itr", 3731299554Serj CTLFLAG_RD, &(txr->itr), 0, 3732299554Serj "Queue Tx ITR Interval"); 3733299554Serj // Not actual latency; just a calculated value to put in a register 3734299554Serj // TODO: Put in better descriptions here 3735299554Serj SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_latency", 3736299554Serj CTLFLAG_RD, &(rxr->latency), 0, 3737299554Serj "Queue Rx ITRL Average Interval"); 3738299554Serj SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "tx_latency", 3739299554Serj CTLFLAG_RD, &(txr->latency), 0, 3740299554Serj "Queue Tx ITRL Average Interval"); 3741299554Serj 3742299554Serj#ifdef IXL_DEBUG 3743299554Serj SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_not_done", 3744299554Serj CTLFLAG_RD, &(rxr->not_done), 3745299554Serj "Queue Rx Descriptors not Done"); 3746299554Serj SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_next_refresh", 3747299554Serj CTLFLAG_RD, &(rxr->next_refresh), 0, 3748299554Serj "Queue Rx Descriptors not Done"); 3749299554Serj SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_next_check", 3750299554Serj CTLFLAG_RD, &(rxr->next_check), 0, 3751299554Serj "Queue Rx Descriptors not Done"); 3752299554Serj SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qtx_tail", 3753299554Serj CTLTYPE_UINT | CTLFLAG_RD, &queues[q], 3754299554Serj sizeof(struct ixl_queue), 3755299554Serj ixl_sysctl_qtx_tail_handler, "IU", 3756299554Serj "Queue Transmit Descriptor Tail"); 3757299554Serj SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qrx_tail", 3758299554Serj CTLTYPE_UINT | CTLFLAG_RD, &queues[q], 3759299554Serj sizeof(struct ixl_queue), 3760299554Serj ixl_sysctl_qrx_tail_handler, "IU", 3761299554Serj "Queue Receive Descriptor Tail"); 3762299554Serj#endif 3763266423Sjfv } 3764266423Sjfv 3765266423Sjfv /* MAC stats */ 3766270346Sjfv ixl_add_sysctls_mac_stats(ctx, child, pf_stats); 3767266423Sjfv} 3768266423Sjfv 3769266423Sjfvstatic void 3770270346Sjfvixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx, 3771266423Sjfv struct sysctl_oid_list *child, 3772266423Sjfv struct i40e_eth_stats *eth_stats) 3773266423Sjfv{ 3774270346Sjfv struct ixl_sysctl_info ctls[] = 3775266423Sjfv { 3776266423Sjfv {ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, 3777266423Sjfv {ð_stats->rx_unicast, "ucast_pkts_rcvd", 3778266423Sjfv "Unicast Packets Received"}, 3779266423Sjfv {ð_stats->rx_multicast, "mcast_pkts_rcvd", 3780266423Sjfv "Multicast Packets Received"}, 3781266423Sjfv {ð_stats->rx_broadcast, "bcast_pkts_rcvd", 3782266423Sjfv "Broadcast Packets Received"}, 3783269198Sjfv {ð_stats->rx_discards, "rx_discards", "Discarded RX packets"}, 3784266423Sjfv {ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, 3785266423Sjfv {ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, 3786266423Sjfv {ð_stats->tx_multicast, "mcast_pkts_txd", 3787266423Sjfv "Multicast Packets Transmitted"}, 3788266423Sjfv {ð_stats->tx_broadcast, "bcast_pkts_txd", 3789266423Sjfv "Broadcast Packets Transmitted"}, 3790266423Sjfv // end 3791266423Sjfv {0,0,0} 3792266423Sjfv }; 3793266423Sjfv 3794270346Sjfv struct ixl_sysctl_info *entry = ctls; 3795297753Spfg while (entry->stat != NULL) 3796266423Sjfv { 3797266423Sjfv SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name, 3798266423Sjfv CTLFLAG_RD, entry->stat, 3799266423Sjfv entry->description); 3800266423Sjfv entry++; 3801266423Sjfv } 3802266423Sjfv} 3803266423Sjfv 3804266423Sjfvstatic void 3805270346Sjfvixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx, 3806266423Sjfv struct sysctl_oid_list *child, 3807266423Sjfv struct i40e_hw_port_stats *stats) 3808266423Sjfv{ 3809269198Sjfv struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", 3810266423Sjfv CTLFLAG_RD, NULL, "Mac Statistics"); 3811266423Sjfv struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node); 3812266423Sjfv 3813266423Sjfv struct i40e_eth_stats *eth_stats = &stats->eth; 3814270346Sjfv ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats); 3815266423Sjfv 3816270346Sjfv struct ixl_sysctl_info ctls[] = 3817266423Sjfv { 3818266423Sjfv {&stats->crc_errors, "crc_errors", "CRC Errors"}, 3819266423Sjfv {&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"}, 3820266423Sjfv {&stats->mac_local_faults, "local_faults", "MAC Local Faults"}, 3821266423Sjfv {&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"}, 3822266423Sjfv {&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"}, 3823266423Sjfv /* Packet Reception Stats */ 3824266423Sjfv {&stats->rx_size_64, "rx_frames_64", "64 byte frames received"}, 3825266423Sjfv {&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"}, 3826266423Sjfv {&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"}, 3827266423Sjfv {&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"}, 3828266423Sjfv {&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"}, 3829266423Sjfv {&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"}, 3830266423Sjfv {&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"}, 3831266423Sjfv {&stats->rx_undersize, "rx_undersize", "Undersized packets received"}, 3832266423Sjfv {&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"}, 3833266423Sjfv {&stats->rx_oversize, "rx_oversized", "Oversized packets received"}, 3834266423Sjfv {&stats->rx_jabber, "rx_jabber", "Received Jabber"}, 3835266423Sjfv {&stats->checksum_error, "checksum_errors", "Checksum Errors"}, 3836266423Sjfv /* Packet Transmission Stats */ 3837266423Sjfv {&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"}, 3838266423Sjfv {&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"}, 3839266423Sjfv {&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"}, 3840266423Sjfv {&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"}, 3841266423Sjfv {&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"}, 3842266423Sjfv {&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"}, 3843266423Sjfv {&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"}, 3844266423Sjfv /* Flow control */ 3845266423Sjfv {&stats->link_xon_tx, "xon_txd", "Link XON transmitted"}, 3846266423Sjfv {&stats->link_xon_rx, "xon_recvd", "Link XON received"}, 3847266423Sjfv {&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"}, 3848266423Sjfv {&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"}, 3849266423Sjfv /* End */ 3850266423Sjfv {0,0,0} 3851266423Sjfv }; 3852266423Sjfv 3853270346Sjfv struct ixl_sysctl_info *entry = ctls; 3854297753Spfg while (entry->stat != NULL) 3855266423Sjfv { 3856266423Sjfv SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name, 3857266423Sjfv CTLFLAG_RD, entry->stat, 3858266423Sjfv entry->description); 3859266423Sjfv entry++; 3860266423Sjfv } 3861266423Sjfv} 3862266423Sjfv 3863284049Sjfv 3864266423Sjfv/* 3865270346Sjfv** ixl_config_rss - setup RSS 3866266423Sjfv** - note this is done for the single vsi 3867266423Sjfv*/ 3868299554Serjstatic void 3869299554Serjixl_config_rss(struct ixl_vsi *vsi) 3870266423Sjfv{ 3871270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 3872266423Sjfv struct i40e_hw *hw = vsi->hw; 3873266423Sjfv u32 lut = 0; 3874277084Sjfv u64 set_hena = 0, hena; 3875277084Sjfv int i, j, que_id; 3876277084Sjfv#ifdef RSS 3877277084Sjfv u32 rss_hash_config; 3878277084Sjfv u32 rss_seed[IXL_KEYSZ]; 3879277084Sjfv#else 3880277084Sjfv u32 rss_seed[IXL_KEYSZ] = {0x41b01687, 3881277084Sjfv 0x183cfd8c, 0xce880440, 0x580cbc3c, 3882277084Sjfv 0x35897377, 0x328b25e1, 0x4fa98922, 3883277084Sjfv 0xb7d90c14, 0xd5bad70d, 0xcd15a2c1}; 3884277084Sjfv#endif 3885266423Sjfv 3886277084Sjfv#ifdef RSS 3887277084Sjfv /* Fetch the configured RSS key */ 3888277084Sjfv rss_getkey((uint8_t *) &rss_seed); 3889277084Sjfv#endif 3890266423Sjfv 3891266423Sjfv /* Fill out hash function seed */ 3892277084Sjfv for (i = 0; i < IXL_KEYSZ; i++) 3893299555Serj i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), rss_seed[i]); 3894266423Sjfv 3895266423Sjfv /* Enable PCTYPES for RSS: */ 3896277084Sjfv#ifdef RSS 3897277084Sjfv rss_hash_config = rss_gethashconfig(); 3898277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 3899277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); 3900277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 3901277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); 3902277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 3903277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP); 3904277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 3905277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); 3906279033Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 3907277151Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); 3908277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 3909277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); 3910277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 3911277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP); 3912277084Sjfv#else 3913266423Sjfv set_hena = 3914266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | 3915266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | 3916266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | 3917266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | 3918266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | 3919266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | 3920266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | 3921266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | 3922266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | 3923266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | 3924266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD); 3925277084Sjfv#endif 3926299555Serj hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) | 3927299555Serj ((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32); 3928266423Sjfv hena |= set_hena; 3929299555Serj i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena); 3930299555Serj i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); 3931266423Sjfv 3932266423Sjfv /* Populate the LUT with max no. of queues in round robin fashion */ 3933266423Sjfv for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) { 3934266423Sjfv if (j == vsi->num_queues) 3935266423Sjfv j = 0; 3936277084Sjfv#ifdef RSS 3937277084Sjfv /* 3938277084Sjfv * Fetch the RSS bucket id for the given indirection entry. 3939277084Sjfv * Cap it at the number of configured buckets (which is 3940277084Sjfv * num_queues.) 3941277084Sjfv */ 3942277084Sjfv que_id = rss_get_indirection_to_bucket(i); 3943277262Sjfv que_id = que_id % vsi->num_queues; 3944277084Sjfv#else 3945277084Sjfv que_id = j; 3946277084Sjfv#endif 3947266423Sjfv /* lut = 4-byte sliding window of 4 lut entries */ 3948277084Sjfv lut = (lut << 8) | (que_id & 3949266423Sjfv ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1)); 3950266423Sjfv /* On i = 3, we have 4 entries in lut; write to the register */ 3951266423Sjfv if ((i & 3) == 3) 3952266423Sjfv wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); 3953266423Sjfv } 3954270346Sjfv ixl_flush(hw); 3955266423Sjfv} 3956266423Sjfv 3957266423Sjfv 3958266423Sjfv/* 3959266423Sjfv** This routine is run via an vlan config EVENT, 3960266423Sjfv** it enables us to use the HW Filter table since 3961266423Sjfv** we can get the vlan id. This just creates the 3962266423Sjfv** entry in the soft version of the VFTA, init will 3963266423Sjfv** repopulate the real table. 3964266423Sjfv*/ 3965266423Sjfvstatic void 3966270346Sjfvixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3967266423Sjfv{ 3968270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 3969266423Sjfv struct i40e_hw *hw = vsi->hw; 3970270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 3971266423Sjfv 3972266423Sjfv if (ifp->if_softc != arg) /* Not our event */ 3973266423Sjfv return; 3974266423Sjfv 3975266423Sjfv if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3976266423Sjfv return; 3977266423Sjfv 3978270346Sjfv IXL_PF_LOCK(pf); 3979266423Sjfv ++vsi->num_vlans; 3980270346Sjfv ixl_add_filter(vsi, hw->mac.addr, vtag); 3981270346Sjfv IXL_PF_UNLOCK(pf); 3982266423Sjfv} 3983266423Sjfv 3984266423Sjfv/* 3985266423Sjfv** This routine is run via an vlan 3986266423Sjfv** unconfig EVENT, remove our entry 3987266423Sjfv** in the soft vfta. 3988266423Sjfv*/ 3989266423Sjfvstatic void 3990270346Sjfvixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3991266423Sjfv{ 3992270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 3993266423Sjfv struct i40e_hw *hw = vsi->hw; 3994270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 3995266423Sjfv 3996266423Sjfv if (ifp->if_softc != arg) 3997266423Sjfv return; 3998266423Sjfv 3999266423Sjfv if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 4000266423Sjfv return; 4001266423Sjfv 4002270346Sjfv IXL_PF_LOCK(pf); 4003266423Sjfv --vsi->num_vlans; 4004270346Sjfv ixl_del_filter(vsi, hw->mac.addr, vtag); 4005270346Sjfv IXL_PF_UNLOCK(pf); 4006266423Sjfv} 4007266423Sjfv 4008266423Sjfv/* 4009266423Sjfv** This routine updates vlan filters, called by init 4010266423Sjfv** it scans the filter table and then updates the hw 4011266423Sjfv** after a soft reset. 4012266423Sjfv*/ 4013266423Sjfvstatic void 4014270346Sjfvixl_setup_vlan_filters(struct ixl_vsi *vsi) 4015266423Sjfv{ 4016270346Sjfv struct ixl_mac_filter *f; 4017266423Sjfv int cnt = 0, flags; 4018266423Sjfv 4019266423Sjfv if (vsi->num_vlans == 0) 4020266423Sjfv return; 4021266423Sjfv /* 4022266423Sjfv ** Scan the filter list for vlan entries, 4023266423Sjfv ** mark them for addition and then call 4024266423Sjfv ** for the AQ update. 4025266423Sjfv */ 4026266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 4027270346Sjfv if (f->flags & IXL_FILTER_VLAN) { 4028266423Sjfv f->flags |= 4029270346Sjfv (IXL_FILTER_ADD | 4030270346Sjfv IXL_FILTER_USED); 4031266423Sjfv cnt++; 4032266423Sjfv } 4033266423Sjfv } 4034266423Sjfv if (cnt == 0) { 4035266423Sjfv printf("setup vlan: no filters found!\n"); 4036266423Sjfv return; 4037266423Sjfv } 4038270346Sjfv flags = IXL_FILTER_VLAN; 4039270346Sjfv flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 4040270346Sjfv ixl_add_hw_filters(vsi, flags, cnt); 4041266423Sjfv return; 4042266423Sjfv} 4043266423Sjfv 4044266423Sjfv/* 4045266423Sjfv** Initialize filter list and add filters that the hardware 4046266423Sjfv** needs to know about. 4047299552Serj** 4048299552Serj** Requires VSI's filter list & seid to be set before calling. 4049266423Sjfv*/ 4050266423Sjfvstatic void 4051270346Sjfvixl_init_filters(struct ixl_vsi *vsi) 4052266423Sjfv{ 4053269198Sjfv /* Add broadcast address */ 4054279858Sjfv ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY); 4055299552Serj 4056299552Serj /* 4057299552Serj * Prevent Tx flow control frames from being sent out by 4058299552Serj * non-firmware transmitters. 4059299552Serj */ 4060299552Serj i40e_add_filter_to_drop_tx_flow_control_frames(vsi->hw, vsi->seid); 4061266423Sjfv} 4062266423Sjfv 4063266423Sjfv/* 4064266423Sjfv** This routine adds mulicast filters 4065266423Sjfv*/ 4066266423Sjfvstatic void 4067270346Sjfvixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr) 4068266423Sjfv{ 4069270346Sjfv struct ixl_mac_filter *f; 4070266423Sjfv 4071266423Sjfv /* Does one already exist */ 4072270346Sjfv f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 4073266423Sjfv if (f != NULL) 4074266423Sjfv return; 4075266423Sjfv 4076270346Sjfv f = ixl_get_filter(vsi); 4077266423Sjfv if (f == NULL) { 4078266423Sjfv printf("WARNING: no filter available!!\n"); 4079266423Sjfv return; 4080266423Sjfv } 4081266423Sjfv bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 4082270346Sjfv f->vlan = IXL_VLAN_ANY; 4083270346Sjfv f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED 4084270346Sjfv | IXL_FILTER_MC); 4085266423Sjfv 4086266423Sjfv return; 4087266423Sjfv} 4088266423Sjfv 4089279858Sjfvstatic void 4090279858Sjfvixl_reconfigure_filters(struct ixl_vsi *vsi) 4091279858Sjfv{ 4092279858Sjfv 4093279858Sjfv ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs); 4094279858Sjfv} 4095279858Sjfv 4096266423Sjfv/* 4097266423Sjfv** This routine adds macvlan filters 4098266423Sjfv*/ 4099266423Sjfvstatic void 4100270346Sjfvixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 4101266423Sjfv{ 4102270346Sjfv struct ixl_mac_filter *f, *tmp; 4103279858Sjfv struct ixl_pf *pf; 4104279858Sjfv device_t dev; 4105266423Sjfv 4106270346Sjfv DEBUGOUT("ixl_add_filter: begin"); 4107266423Sjfv 4108279858Sjfv pf = vsi->back; 4109279858Sjfv dev = pf->dev; 4110279858Sjfv 4111266423Sjfv /* Does one already exist */ 4112270346Sjfv f = ixl_find_filter(vsi, macaddr, vlan); 4113266423Sjfv if (f != NULL) 4114266423Sjfv return; 4115266423Sjfv /* 4116266423Sjfv ** Is this the first vlan being registered, if so we 4117266423Sjfv ** need to remove the ANY filter that indicates we are 4118266423Sjfv ** not in a vlan, and replace that with a 0 filter. 4119266423Sjfv */ 4120270346Sjfv if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) { 4121270346Sjfv tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 4122266423Sjfv if (tmp != NULL) { 4123270346Sjfv ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY); 4124270346Sjfv ixl_add_filter(vsi, macaddr, 0); 4125266423Sjfv } 4126266423Sjfv } 4127266423Sjfv 4128270346Sjfv f = ixl_get_filter(vsi); 4129266423Sjfv if (f == NULL) { 4130266423Sjfv device_printf(dev, "WARNING: no filter available!!\n"); 4131266423Sjfv return; 4132266423Sjfv } 4133266423Sjfv bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 4134266423Sjfv f->vlan = vlan; 4135270346Sjfv f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 4136270346Sjfv if (f->vlan != IXL_VLAN_ANY) 4137270346Sjfv f->flags |= IXL_FILTER_VLAN; 4138279858Sjfv else 4139279858Sjfv vsi->num_macs++; 4140266423Sjfv 4141270346Sjfv ixl_add_hw_filters(vsi, f->flags, 1); 4142266423Sjfv return; 4143266423Sjfv} 4144266423Sjfv 4145266423Sjfvstatic void 4146270346Sjfvixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 4147266423Sjfv{ 4148270346Sjfv struct ixl_mac_filter *f; 4149266423Sjfv 4150270346Sjfv f = ixl_find_filter(vsi, macaddr, vlan); 4151266423Sjfv if (f == NULL) 4152266423Sjfv return; 4153266423Sjfv 4154270346Sjfv f->flags |= IXL_FILTER_DEL; 4155270346Sjfv ixl_del_hw_filters(vsi, 1); 4156279858Sjfv vsi->num_macs--; 4157266423Sjfv 4158266423Sjfv /* Check if this is the last vlan removal */ 4159270346Sjfv if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) { 4160266423Sjfv /* Switch back to a non-vlan filter */ 4161270346Sjfv ixl_del_filter(vsi, macaddr, 0); 4162270346Sjfv ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY); 4163266423Sjfv } 4164266423Sjfv return; 4165266423Sjfv} 4166266423Sjfv 4167266423Sjfv/* 4168266423Sjfv** Find the filter with both matching mac addr and vlan id 4169266423Sjfv*/ 4170270346Sjfvstatic struct ixl_mac_filter * 4171270346Sjfvixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 4172266423Sjfv{ 4173270346Sjfv struct ixl_mac_filter *f; 4174266423Sjfv bool match = FALSE; 4175266423Sjfv 4176266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 4177266423Sjfv if (!cmp_etheraddr(f->macaddr, macaddr)) 4178266423Sjfv continue; 4179266423Sjfv if (f->vlan == vlan) { 4180266423Sjfv match = TRUE; 4181266423Sjfv break; 4182266423Sjfv } 4183266423Sjfv } 4184266423Sjfv 4185266423Sjfv if (!match) 4186266423Sjfv f = NULL; 4187266423Sjfv return (f); 4188266423Sjfv} 4189266423Sjfv 4190266423Sjfv/* 4191266423Sjfv** This routine takes additions to the vsi filter 4192266423Sjfv** table and creates an Admin Queue call to create 4193266423Sjfv** the filters in the hardware. 4194266423Sjfv*/ 4195266423Sjfvstatic void 4196270346Sjfvixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt) 4197266423Sjfv{ 4198266423Sjfv struct i40e_aqc_add_macvlan_element_data *a, *b; 4199270346Sjfv struct ixl_mac_filter *f; 4200279858Sjfv struct ixl_pf *pf; 4201279858Sjfv struct i40e_hw *hw; 4202279858Sjfv device_t dev; 4203279858Sjfv int err, j = 0; 4204266423Sjfv 4205279858Sjfv pf = vsi->back; 4206279858Sjfv dev = pf->dev; 4207279858Sjfv hw = &pf->hw; 4208279858Sjfv IXL_PF_LOCK_ASSERT(pf); 4209279858Sjfv 4210266423Sjfv a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt, 4211266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 4212266423Sjfv if (a == NULL) { 4213277084Sjfv device_printf(dev, "add_hw_filters failed to get memory\n"); 4214266423Sjfv return; 4215266423Sjfv } 4216266423Sjfv 4217266423Sjfv /* 4218266423Sjfv ** Scan the filter list, each time we find one 4219266423Sjfv ** we add it to the admin queue array and turn off 4220266423Sjfv ** the add bit. 4221266423Sjfv */ 4222266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 4223266423Sjfv if (f->flags == flags) { 4224266423Sjfv b = &a[j]; // a pox on fvl long names :) 4225266423Sjfv bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN); 4226279858Sjfv if (f->vlan == IXL_VLAN_ANY) { 4227279858Sjfv b->vlan_tag = 0; 4228279858Sjfv b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN; 4229279858Sjfv } else { 4230279858Sjfv b->vlan_tag = f->vlan; 4231279858Sjfv b->flags = 0; 4232279858Sjfv } 4233279858Sjfv b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH; 4234270346Sjfv f->flags &= ~IXL_FILTER_ADD; 4235266423Sjfv j++; 4236266423Sjfv } 4237266423Sjfv if (j == cnt) 4238266423Sjfv break; 4239266423Sjfv } 4240266423Sjfv if (j > 0) { 4241266423Sjfv err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); 4242266423Sjfv if (err) 4243279033Sjfv device_printf(dev, "aq_add_macvlan err %d, " 4244279033Sjfv "aq_error %d\n", err, hw->aq.asq_last_status); 4245266423Sjfv else 4246266423Sjfv vsi->hw_filters_add += j; 4247266423Sjfv } 4248266423Sjfv free(a, M_DEVBUF); 4249266423Sjfv return; 4250266423Sjfv} 4251266423Sjfv 4252266423Sjfv/* 4253266423Sjfv** This routine takes removals in the vsi filter 4254266423Sjfv** table and creates an Admin Queue call to delete 4255266423Sjfv** the filters in the hardware. 4256266423Sjfv*/ 4257266423Sjfvstatic void 4258270346Sjfvixl_del_hw_filters(struct ixl_vsi *vsi, int cnt) 4259266423Sjfv{ 4260266423Sjfv struct i40e_aqc_remove_macvlan_element_data *d, *e; 4261279858Sjfv struct ixl_pf *pf; 4262279858Sjfv struct i40e_hw *hw; 4263279858Sjfv device_t dev; 4264270346Sjfv struct ixl_mac_filter *f, *f_temp; 4265266423Sjfv int err, j = 0; 4266266423Sjfv 4267270346Sjfv DEBUGOUT("ixl_del_hw_filters: begin\n"); 4268266423Sjfv 4269279858Sjfv pf = vsi->back; 4270279858Sjfv hw = &pf->hw; 4271279858Sjfv dev = pf->dev; 4272279858Sjfv 4273266423Sjfv d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt, 4274266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 4275266423Sjfv if (d == NULL) { 4276266423Sjfv printf("del hw filter failed to get memory\n"); 4277266423Sjfv return; 4278266423Sjfv } 4279266423Sjfv 4280266423Sjfv SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) { 4281270346Sjfv if (f->flags & IXL_FILTER_DEL) { 4282266423Sjfv e = &d[j]; // a pox on fvl long names :) 4283266423Sjfv bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN); 4284270346Sjfv e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan); 4285266423Sjfv e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; 4286266423Sjfv /* delete entry from vsi list */ 4287270346Sjfv SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next); 4288266423Sjfv free(f, M_DEVBUF); 4289266423Sjfv j++; 4290266423Sjfv } 4291266423Sjfv if (j == cnt) 4292266423Sjfv break; 4293266423Sjfv } 4294266423Sjfv if (j > 0) { 4295266423Sjfv err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); 4296266423Sjfv /* NOTE: returns ENOENT every time but seems to work fine, 4297266423Sjfv so we'll ignore that specific error. */ 4298277084Sjfv // TODO: Does this still occur on current firmwares? 4299266423Sjfv if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { 4300266423Sjfv int sc = 0; 4301266423Sjfv for (int i = 0; i < j; i++) 4302266423Sjfv sc += (!d[i].error_code); 4303266423Sjfv vsi->hw_filters_del += sc; 4304266423Sjfv device_printf(dev, 4305266423Sjfv "Failed to remove %d/%d filters, aq error %d\n", 4306266423Sjfv j - sc, j, hw->aq.asq_last_status); 4307266423Sjfv } else 4308266423Sjfv vsi->hw_filters_del += j; 4309266423Sjfv } 4310266423Sjfv free(d, M_DEVBUF); 4311266423Sjfv 4312270346Sjfv DEBUGOUT("ixl_del_hw_filters: end\n"); 4313266423Sjfv return; 4314266423Sjfv} 4315266423Sjfv 4316279858Sjfvstatic int 4317270346Sjfvixl_enable_rings(struct ixl_vsi *vsi) 4318266423Sjfv{ 4319279858Sjfv struct ixl_pf *pf = vsi->back; 4320279858Sjfv struct i40e_hw *hw = &pf->hw; 4321279858Sjfv int index, error; 4322266423Sjfv u32 reg; 4323266423Sjfv 4324279858Sjfv error = 0; 4325266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 4326279858Sjfv index = vsi->first_queue + i; 4327279858Sjfv i40e_pre_tx_queue_cfg(hw, index, TRUE); 4328266423Sjfv 4329279858Sjfv reg = rd32(hw, I40E_QTX_ENA(index)); 4330266423Sjfv reg |= I40E_QTX_ENA_QENA_REQ_MASK | 4331266423Sjfv I40E_QTX_ENA_QENA_STAT_MASK; 4332279858Sjfv wr32(hw, I40E_QTX_ENA(index), reg); 4333266423Sjfv /* Verify the enable took */ 4334266423Sjfv for (int j = 0; j < 10; j++) { 4335279858Sjfv reg = rd32(hw, I40E_QTX_ENA(index)); 4336266423Sjfv if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 4337266423Sjfv break; 4338266423Sjfv i40e_msec_delay(10); 4339266423Sjfv } 4340279858Sjfv if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) { 4341279858Sjfv device_printf(pf->dev, "TX queue %d disabled!\n", 4342279858Sjfv index); 4343279858Sjfv error = ETIMEDOUT; 4344279858Sjfv } 4345266423Sjfv 4346279858Sjfv reg = rd32(hw, I40E_QRX_ENA(index)); 4347266423Sjfv reg |= I40E_QRX_ENA_QENA_REQ_MASK | 4348266423Sjfv I40E_QRX_ENA_QENA_STAT_MASK; 4349279858Sjfv wr32(hw, I40E_QRX_ENA(index), reg); 4350266423Sjfv /* Verify the enable took */ 4351266423Sjfv for (int j = 0; j < 10; j++) { 4352279858Sjfv reg = rd32(hw, I40E_QRX_ENA(index)); 4353266423Sjfv if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 4354266423Sjfv break; 4355266423Sjfv i40e_msec_delay(10); 4356266423Sjfv } 4357279858Sjfv if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) { 4358279858Sjfv device_printf(pf->dev, "RX queue %d disabled!\n", 4359279858Sjfv index); 4360279858Sjfv error = ETIMEDOUT; 4361279858Sjfv } 4362266423Sjfv } 4363279858Sjfv 4364279858Sjfv return (error); 4365266423Sjfv} 4366266423Sjfv 4367279858Sjfvstatic int 4368270346Sjfvixl_disable_rings(struct ixl_vsi *vsi) 4369266423Sjfv{ 4370279858Sjfv struct ixl_pf *pf = vsi->back; 4371279858Sjfv struct i40e_hw *hw = &pf->hw; 4372279858Sjfv int index, error; 4373266423Sjfv u32 reg; 4374266423Sjfv 4375279858Sjfv error = 0; 4376266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 4377279858Sjfv index = vsi->first_queue + i; 4378279858Sjfv 4379279858Sjfv i40e_pre_tx_queue_cfg(hw, index, FALSE); 4380266423Sjfv i40e_usec_delay(500); 4381266423Sjfv 4382279858Sjfv reg = rd32(hw, I40E_QTX_ENA(index)); 4383266423Sjfv reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; 4384279858Sjfv wr32(hw, I40E_QTX_ENA(index), reg); 4385266423Sjfv /* Verify the disable took */ 4386266423Sjfv for (int j = 0; j < 10; j++) { 4387279858Sjfv reg = rd32(hw, I40E_QTX_ENA(index)); 4388266423Sjfv if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK)) 4389266423Sjfv break; 4390266423Sjfv i40e_msec_delay(10); 4391266423Sjfv } 4392279858Sjfv if (reg & I40E_QTX_ENA_QENA_STAT_MASK) { 4393279858Sjfv device_printf(pf->dev, "TX queue %d still enabled!\n", 4394279858Sjfv index); 4395279858Sjfv error = ETIMEDOUT; 4396279858Sjfv } 4397266423Sjfv 4398279858Sjfv reg = rd32(hw, I40E_QRX_ENA(index)); 4399266423Sjfv reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; 4400279858Sjfv wr32(hw, I40E_QRX_ENA(index), reg); 4401266423Sjfv /* Verify the disable took */ 4402266423Sjfv for (int j = 0; j < 10; j++) { 4403279858Sjfv reg = rd32(hw, I40E_QRX_ENA(index)); 4404266423Sjfv if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK)) 4405266423Sjfv break; 4406266423Sjfv i40e_msec_delay(10); 4407266423Sjfv } 4408279858Sjfv if (reg & I40E_QRX_ENA_QENA_STAT_MASK) { 4409279858Sjfv device_printf(pf->dev, "RX queue %d still enabled!\n", 4410279858Sjfv index); 4411279858Sjfv error = ETIMEDOUT; 4412279858Sjfv } 4413266423Sjfv } 4414279858Sjfv 4415279858Sjfv return (error); 4416266423Sjfv} 4417266423Sjfv 4418269198Sjfv/** 4419270346Sjfv * ixl_handle_mdd_event 4420269198Sjfv * 4421269198Sjfv * Called from interrupt handler to identify possibly malicious vfs 4422269198Sjfv * (But also detects events from the PF, as well) 4423269198Sjfv **/ 4424299554Serjstatic void 4425299554Serjixl_handle_mdd_event(struct ixl_pf *pf) 4426269198Sjfv{ 4427269198Sjfv struct i40e_hw *hw = &pf->hw; 4428269198Sjfv device_t dev = pf->dev; 4429269198Sjfv bool mdd_detected = false; 4430269198Sjfv bool pf_mdd_detected = false; 4431269198Sjfv u32 reg; 4432269198Sjfv 4433269198Sjfv /* find what triggered the MDD event */ 4434269198Sjfv reg = rd32(hw, I40E_GL_MDET_TX); 4435269198Sjfv if (reg & I40E_GL_MDET_TX_VALID_MASK) { 4436269198Sjfv u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >> 4437269198Sjfv I40E_GL_MDET_TX_PF_NUM_SHIFT; 4438269198Sjfv u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >> 4439269198Sjfv I40E_GL_MDET_TX_EVENT_SHIFT; 4440269198Sjfv u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >> 4441269198Sjfv I40E_GL_MDET_TX_QUEUE_SHIFT; 4442269198Sjfv device_printf(dev, 4443269198Sjfv "Malicious Driver Detection event 0x%02x" 4444269198Sjfv " on TX queue %d pf number 0x%02x\n", 4445269198Sjfv event, queue, pf_num); 4446269198Sjfv wr32(hw, I40E_GL_MDET_TX, 0xffffffff); 4447269198Sjfv mdd_detected = true; 4448269198Sjfv } 4449269198Sjfv reg = rd32(hw, I40E_GL_MDET_RX); 4450269198Sjfv if (reg & I40E_GL_MDET_RX_VALID_MASK) { 4451269198Sjfv u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >> 4452269198Sjfv I40E_GL_MDET_RX_FUNCTION_SHIFT; 4453269198Sjfv u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >> 4454269198Sjfv I40E_GL_MDET_RX_EVENT_SHIFT; 4455269198Sjfv u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >> 4456269198Sjfv I40E_GL_MDET_RX_QUEUE_SHIFT; 4457269198Sjfv device_printf(dev, 4458269198Sjfv "Malicious Driver Detection event 0x%02x" 4459269198Sjfv " on RX queue %d of function 0x%02x\n", 4460269198Sjfv event, queue, func); 4461269198Sjfv wr32(hw, I40E_GL_MDET_RX, 0xffffffff); 4462269198Sjfv mdd_detected = true; 4463269198Sjfv } 4464269198Sjfv 4465269198Sjfv if (mdd_detected) { 4466269198Sjfv reg = rd32(hw, I40E_PF_MDET_TX); 4467269198Sjfv if (reg & I40E_PF_MDET_TX_VALID_MASK) { 4468269198Sjfv wr32(hw, I40E_PF_MDET_TX, 0xFFFF); 4469269198Sjfv device_printf(dev, 4470269198Sjfv "MDD TX event is for this function 0x%08x", 4471269198Sjfv reg); 4472269198Sjfv pf_mdd_detected = true; 4473269198Sjfv } 4474269198Sjfv reg = rd32(hw, I40E_PF_MDET_RX); 4475269198Sjfv if (reg & I40E_PF_MDET_RX_VALID_MASK) { 4476269198Sjfv wr32(hw, I40E_PF_MDET_RX, 0xFFFF); 4477269198Sjfv device_printf(dev, 4478269198Sjfv "MDD RX event is for this function 0x%08x", 4479269198Sjfv reg); 4480269198Sjfv pf_mdd_detected = true; 4481269198Sjfv } 4482269198Sjfv } 4483269198Sjfv 4484269198Sjfv /* re-enable mdd interrupt cause */ 4485269198Sjfv reg = rd32(hw, I40E_PFINT_ICR0_ENA); 4486269198Sjfv reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 4487269198Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 4488270346Sjfv ixl_flush(hw); 4489269198Sjfv} 4490269198Sjfv 4491266423Sjfvstatic void 4492270346Sjfvixl_enable_intr(struct ixl_vsi *vsi) 4493266423Sjfv{ 4494266423Sjfv struct i40e_hw *hw = vsi->hw; 4495270346Sjfv struct ixl_queue *que = vsi->queues; 4496266423Sjfv 4497270346Sjfv if (ixl_enable_msix) { 4498266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) 4499270346Sjfv ixl_enable_queue(hw, que->me); 4500266423Sjfv } else 4501270346Sjfv ixl_enable_legacy(hw); 4502266423Sjfv} 4503266423Sjfv 4504266423Sjfvstatic void 4505279858Sjfvixl_disable_rings_intr(struct ixl_vsi *vsi) 4506266423Sjfv{ 4507266423Sjfv struct i40e_hw *hw = vsi->hw; 4508270346Sjfv struct ixl_queue *que = vsi->queues; 4509266423Sjfv 4510279858Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) 4511279858Sjfv ixl_disable_queue(hw, que->me); 4512279858Sjfv} 4513279858Sjfv 4514279858Sjfvstatic void 4515279858Sjfvixl_disable_intr(struct ixl_vsi *vsi) 4516279858Sjfv{ 4517279858Sjfv struct i40e_hw *hw = vsi->hw; 4518279858Sjfv 4519279858Sjfv if (ixl_enable_msix) 4520270346Sjfv ixl_disable_adminq(hw); 4521279858Sjfv else 4522270346Sjfv ixl_disable_legacy(hw); 4523266423Sjfv} 4524266423Sjfv 4525266423Sjfvstatic void 4526270346Sjfvixl_enable_adminq(struct i40e_hw *hw) 4527266423Sjfv{ 4528266423Sjfv u32 reg; 4529266423Sjfv 4530266423Sjfv reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 4531266423Sjfv I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 4532270346Sjfv (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 4533266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 4534270346Sjfv ixl_flush(hw); 4535266423Sjfv} 4536266423Sjfv 4537266423Sjfvstatic void 4538270346Sjfvixl_disable_adminq(struct i40e_hw *hw) 4539266423Sjfv{ 4540266423Sjfv u32 reg; 4541266423Sjfv 4542270346Sjfv reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 4543266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 4544299547Serj ixl_flush(hw); 4545266423Sjfv} 4546266423Sjfv 4547266423Sjfvstatic void 4548270346Sjfvixl_enable_queue(struct i40e_hw *hw, int id) 4549266423Sjfv{ 4550266423Sjfv u32 reg; 4551266423Sjfv 4552266423Sjfv reg = I40E_PFINT_DYN_CTLN_INTENA_MASK | 4553266423Sjfv I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | 4554270346Sjfv (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); 4555266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 4556266423Sjfv} 4557266423Sjfv 4558266423Sjfvstatic void 4559270346Sjfvixl_disable_queue(struct i40e_hw *hw, int id) 4560266423Sjfv{ 4561266423Sjfv u32 reg; 4562266423Sjfv 4563270346Sjfv reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; 4564266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 4565266423Sjfv} 4566266423Sjfv 4567266423Sjfvstatic void 4568270346Sjfvixl_enable_legacy(struct i40e_hw *hw) 4569266423Sjfv{ 4570266423Sjfv u32 reg; 4571266423Sjfv reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 4572266423Sjfv I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 4573270346Sjfv (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 4574266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 4575266423Sjfv} 4576266423Sjfv 4577266423Sjfvstatic void 4578270346Sjfvixl_disable_legacy(struct i40e_hw *hw) 4579266423Sjfv{ 4580266423Sjfv u32 reg; 4581266423Sjfv 4582270346Sjfv reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 4583266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 4584266423Sjfv} 4585266423Sjfv 4586266423Sjfvstatic void 4587270346Sjfvixl_update_stats_counters(struct ixl_pf *pf) 4588266423Sjfv{ 4589266423Sjfv struct i40e_hw *hw = &pf->hw; 4590279858Sjfv struct ixl_vsi *vsi = &pf->vsi; 4591279858Sjfv struct ixl_vf *vf; 4592269198Sjfv 4593266423Sjfv struct i40e_hw_port_stats *nsd = &pf->stats; 4594266423Sjfv struct i40e_hw_port_stats *osd = &pf->stats_offsets; 4595266423Sjfv 4596266423Sjfv /* Update hw stats */ 4597270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port), 4598266423Sjfv pf->stat_offsets_loaded, 4599266423Sjfv &osd->crc_errors, &nsd->crc_errors); 4600270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port), 4601266423Sjfv pf->stat_offsets_loaded, 4602266423Sjfv &osd->illegal_bytes, &nsd->illegal_bytes); 4603270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port), 4604266423Sjfv I40E_GLPRT_GORCL(hw->port), 4605266423Sjfv pf->stat_offsets_loaded, 4606266423Sjfv &osd->eth.rx_bytes, &nsd->eth.rx_bytes); 4607270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port), 4608266423Sjfv I40E_GLPRT_GOTCL(hw->port), 4609266423Sjfv pf->stat_offsets_loaded, 4610266423Sjfv &osd->eth.tx_bytes, &nsd->eth.tx_bytes); 4611270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port), 4612266423Sjfv pf->stat_offsets_loaded, 4613266423Sjfv &osd->eth.rx_discards, 4614266423Sjfv &nsd->eth.rx_discards); 4615270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port), 4616266423Sjfv I40E_GLPRT_UPRCL(hw->port), 4617266423Sjfv pf->stat_offsets_loaded, 4618266423Sjfv &osd->eth.rx_unicast, 4619266423Sjfv &nsd->eth.rx_unicast); 4620270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port), 4621266423Sjfv I40E_GLPRT_UPTCL(hw->port), 4622266423Sjfv pf->stat_offsets_loaded, 4623266423Sjfv &osd->eth.tx_unicast, 4624266423Sjfv &nsd->eth.tx_unicast); 4625270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port), 4626266423Sjfv I40E_GLPRT_MPRCL(hw->port), 4627266423Sjfv pf->stat_offsets_loaded, 4628266423Sjfv &osd->eth.rx_multicast, 4629266423Sjfv &nsd->eth.rx_multicast); 4630270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port), 4631266423Sjfv I40E_GLPRT_MPTCL(hw->port), 4632266423Sjfv pf->stat_offsets_loaded, 4633266423Sjfv &osd->eth.tx_multicast, 4634266423Sjfv &nsd->eth.tx_multicast); 4635270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port), 4636266423Sjfv I40E_GLPRT_BPRCL(hw->port), 4637266423Sjfv pf->stat_offsets_loaded, 4638266423Sjfv &osd->eth.rx_broadcast, 4639266423Sjfv &nsd->eth.rx_broadcast); 4640270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port), 4641266423Sjfv I40E_GLPRT_BPTCL(hw->port), 4642266423Sjfv pf->stat_offsets_loaded, 4643266423Sjfv &osd->eth.tx_broadcast, 4644266423Sjfv &nsd->eth.tx_broadcast); 4645266423Sjfv 4646270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port), 4647266423Sjfv pf->stat_offsets_loaded, 4648266423Sjfv &osd->tx_dropped_link_down, 4649266423Sjfv &nsd->tx_dropped_link_down); 4650270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port), 4651266423Sjfv pf->stat_offsets_loaded, 4652266423Sjfv &osd->mac_local_faults, 4653266423Sjfv &nsd->mac_local_faults); 4654270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port), 4655266423Sjfv pf->stat_offsets_loaded, 4656266423Sjfv &osd->mac_remote_faults, 4657266423Sjfv &nsd->mac_remote_faults); 4658270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port), 4659266423Sjfv pf->stat_offsets_loaded, 4660266423Sjfv &osd->rx_length_errors, 4661266423Sjfv &nsd->rx_length_errors); 4662266423Sjfv 4663269198Sjfv /* Flow control (LFC) stats */ 4664270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port), 4665266423Sjfv pf->stat_offsets_loaded, 4666266423Sjfv &osd->link_xon_rx, &nsd->link_xon_rx); 4667270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port), 4668266423Sjfv pf->stat_offsets_loaded, 4669266423Sjfv &osd->link_xon_tx, &nsd->link_xon_tx); 4670270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port), 4671266423Sjfv pf->stat_offsets_loaded, 4672266423Sjfv &osd->link_xoff_rx, &nsd->link_xoff_rx); 4673270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port), 4674266423Sjfv pf->stat_offsets_loaded, 4675266423Sjfv &osd->link_xoff_tx, &nsd->link_xoff_tx); 4676266423Sjfv 4677269198Sjfv /* Packet size stats rx */ 4678270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port), 4679266423Sjfv I40E_GLPRT_PRC64L(hw->port), 4680266423Sjfv pf->stat_offsets_loaded, 4681266423Sjfv &osd->rx_size_64, &nsd->rx_size_64); 4682270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port), 4683266423Sjfv I40E_GLPRT_PRC127L(hw->port), 4684266423Sjfv pf->stat_offsets_loaded, 4685266423Sjfv &osd->rx_size_127, &nsd->rx_size_127); 4686270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port), 4687266423Sjfv I40E_GLPRT_PRC255L(hw->port), 4688266423Sjfv pf->stat_offsets_loaded, 4689266423Sjfv &osd->rx_size_255, &nsd->rx_size_255); 4690270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port), 4691266423Sjfv I40E_GLPRT_PRC511L(hw->port), 4692266423Sjfv pf->stat_offsets_loaded, 4693266423Sjfv &osd->rx_size_511, &nsd->rx_size_511); 4694270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port), 4695266423Sjfv I40E_GLPRT_PRC1023L(hw->port), 4696266423Sjfv pf->stat_offsets_loaded, 4697266423Sjfv &osd->rx_size_1023, &nsd->rx_size_1023); 4698270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port), 4699266423Sjfv I40E_GLPRT_PRC1522L(hw->port), 4700266423Sjfv pf->stat_offsets_loaded, 4701266423Sjfv &osd->rx_size_1522, &nsd->rx_size_1522); 4702270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port), 4703266423Sjfv I40E_GLPRT_PRC9522L(hw->port), 4704266423Sjfv pf->stat_offsets_loaded, 4705266423Sjfv &osd->rx_size_big, &nsd->rx_size_big); 4706266423Sjfv 4707269198Sjfv /* Packet size stats tx */ 4708270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port), 4709266423Sjfv I40E_GLPRT_PTC64L(hw->port), 4710266423Sjfv pf->stat_offsets_loaded, 4711266423Sjfv &osd->tx_size_64, &nsd->tx_size_64); 4712270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port), 4713266423Sjfv I40E_GLPRT_PTC127L(hw->port), 4714266423Sjfv pf->stat_offsets_loaded, 4715266423Sjfv &osd->tx_size_127, &nsd->tx_size_127); 4716270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port), 4717266423Sjfv I40E_GLPRT_PTC255L(hw->port), 4718266423Sjfv pf->stat_offsets_loaded, 4719266423Sjfv &osd->tx_size_255, &nsd->tx_size_255); 4720270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port), 4721266423Sjfv I40E_GLPRT_PTC511L(hw->port), 4722266423Sjfv pf->stat_offsets_loaded, 4723266423Sjfv &osd->tx_size_511, &nsd->tx_size_511); 4724270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port), 4725266423Sjfv I40E_GLPRT_PTC1023L(hw->port), 4726266423Sjfv pf->stat_offsets_loaded, 4727266423Sjfv &osd->tx_size_1023, &nsd->tx_size_1023); 4728270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port), 4729266423Sjfv I40E_GLPRT_PTC1522L(hw->port), 4730266423Sjfv pf->stat_offsets_loaded, 4731266423Sjfv &osd->tx_size_1522, &nsd->tx_size_1522); 4732270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port), 4733266423Sjfv I40E_GLPRT_PTC9522L(hw->port), 4734266423Sjfv pf->stat_offsets_loaded, 4735266423Sjfv &osd->tx_size_big, &nsd->tx_size_big); 4736266423Sjfv 4737270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port), 4738266423Sjfv pf->stat_offsets_loaded, 4739266423Sjfv &osd->rx_undersize, &nsd->rx_undersize); 4740270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port), 4741266423Sjfv pf->stat_offsets_loaded, 4742266423Sjfv &osd->rx_fragments, &nsd->rx_fragments); 4743270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port), 4744266423Sjfv pf->stat_offsets_loaded, 4745266423Sjfv &osd->rx_oversize, &nsd->rx_oversize); 4746270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port), 4747266423Sjfv pf->stat_offsets_loaded, 4748266423Sjfv &osd->rx_jabber, &nsd->rx_jabber); 4749266423Sjfv pf->stat_offsets_loaded = true; 4750269198Sjfv /* End hw stats */ 4751266423Sjfv 4752266423Sjfv /* Update vsi stats */ 4753279858Sjfv ixl_update_vsi_stats(vsi); 4754266423Sjfv 4755279858Sjfv for (int i = 0; i < pf->num_vfs; i++) { 4756279858Sjfv vf = &pf->vfs[i]; 4757279858Sjfv if (vf->vf_flags & VF_FLAG_ENABLED) 4758279858Sjfv ixl_update_eth_stats(&pf->vfs[i].vsi); 4759279858Sjfv } 4760266423Sjfv} 4761266423Sjfv 4762299553Serjstatic int 4763299553Serjixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf) 4764299553Serj{ 4765299553Serj struct i40e_hw *hw = &pf->hw; 4766299553Serj struct ixl_vsi *vsi = &pf->vsi; 4767299553Serj device_t dev = pf->dev; 4768299553Serj bool is_up = false; 4769299553Serj int error = 0; 4770299553Serj 4771299553Serj is_up = !!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING); 4772299553Serj 4773299553Serj /* Teardown */ 4774299553Serj if (is_up) 4775299553Serj ixl_stop(pf); 4776299553Serj error = i40e_shutdown_lan_hmc(hw); 4777299553Serj if (error) 4778299553Serj device_printf(dev, 4779299553Serj "Shutdown LAN HMC failed with code %d\n", error); 4780299553Serj ixl_disable_adminq(hw); 4781299553Serj ixl_teardown_adminq_msix(pf); 4782299553Serj error = i40e_shutdown_adminq(hw); 4783299553Serj if (error) 4784299553Serj device_printf(dev, 4785299553Serj "Shutdown Admin queue failed with code %d\n", error); 4786299553Serj 4787299553Serj /* Setup */ 4788299553Serj error = i40e_init_adminq(hw); 4789299553Serj if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) { 4790299553Serj device_printf(dev, "Unable to initialize Admin Queue, error %d\n", 4791299553Serj error); 4792299553Serj } 4793299553Serj error = ixl_setup_adminq_msix(pf); 4794299553Serj if (error) { 4795299553Serj device_printf(dev, "ixl_setup_adminq_msix error: %d\n", 4796299553Serj error); 4797299553Serj } 4798299553Serj ixl_configure_intr0_msix(pf); 4799299553Serj ixl_enable_adminq(hw); 4800299553Serj error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 4801299553Serj hw->func_caps.num_rx_qp, 0, 0); 4802299553Serj if (error) { 4803299553Serj device_printf(dev, "init_lan_hmc failed: %d\n", error); 4804299553Serj } 4805299553Serj error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 4806299553Serj if (error) { 4807299553Serj device_printf(dev, "configure_lan_hmc failed: %d\n", error); 4808299553Serj } 4809299553Serj if (is_up) 4810299553Serj ixl_init(pf); 4811299553Serj 4812299553Serj return (0); 4813299553Serj} 4814299553Serj 4815299553Serjstatic void 4816299553Serjixl_handle_empr_reset(struct ixl_pf *pf) 4817299553Serj{ 4818299553Serj struct i40e_hw *hw = &pf->hw; 4819299553Serj device_t dev = pf->dev; 4820299553Serj int count = 0; 4821299553Serj u32 reg; 4822299553Serj 4823299553Serj /* Typically finishes within 3-4 seconds */ 4824299553Serj while (count++ < 100) { 4825299553Serj reg = rd32(hw, I40E_GLGEN_RSTAT) 4826299553Serj & I40E_GLGEN_RSTAT_DEVSTATE_MASK; 4827299553Serj if (reg) 4828299553Serj i40e_msec_delay(100); 4829299553Serj else 4830299553Serj break; 4831299553Serj } 4832299553Serj#ifdef IXL_DEBUG 4833299553Serj // Reset-related 4834299553Serj device_printf(dev, "EMPR reset wait count: %d\n", count); 4835299553Serj#endif 4836299553Serj 4837299553Serj device_printf(dev, "Rebuilding driver state...\n"); 4838299553Serj ixl_rebuild_hw_structs_after_reset(pf); 4839299553Serj device_printf(dev, "Rebuilding driver state done.\n"); 4840299553Serj 4841299553Serj atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); 4842299553Serj} 4843299553Serj 4844266423Sjfv/* 4845266423Sjfv** Tasklet handler for MSIX Adminq interrupts 4846266423Sjfv** - do outside interrupt since it might sleep 4847266423Sjfv*/ 4848266423Sjfvstatic void 4849270346Sjfvixl_do_adminq(void *context, int pending) 4850266423Sjfv{ 4851270346Sjfv struct ixl_pf *pf = context; 4852266423Sjfv struct i40e_hw *hw = &pf->hw; 4853266423Sjfv struct i40e_arq_event_info event; 4854266423Sjfv i40e_status ret; 4855299547Serj device_t dev = pf->dev; 4856299553Serj u32 loop = 0; 4857266423Sjfv u16 opcode, result; 4858266423Sjfv 4859299549Serj if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { 4860299553Serj /* Flag cleared at end of this function */ 4861299553Serj ixl_handle_empr_reset(pf); 4862299549Serj return; 4863299549Serj } 4864299549Serj 4865299553Serj /* Admin Queue handling */ 4866274205Sjfv event.buf_len = IXL_AQ_BUF_SZ; 4867274205Sjfv event.msg_buf = malloc(event.buf_len, 4868266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 4869266423Sjfv if (!event.msg_buf) { 4870299547Serj device_printf(dev, "%s: Unable to allocate memory for Admin" 4871299547Serj " Queue event!\n", __func__); 4872266423Sjfv return; 4873266423Sjfv } 4874266423Sjfv 4875279858Sjfv IXL_PF_LOCK(pf); 4876266423Sjfv /* clean and process any events */ 4877266423Sjfv do { 4878266423Sjfv ret = i40e_clean_arq_element(hw, &event, &result); 4879266423Sjfv if (ret) 4880266423Sjfv break; 4881266423Sjfv opcode = LE16_TO_CPU(event.desc.opcode); 4882299547Serj#ifdef IXL_DEBUG 4883299553Serj device_printf(dev, "%s: Admin Queue event: %#06x\n", __func__, 4884299553Serj opcode); 4885299547Serj#endif 4886266423Sjfv switch (opcode) { 4887266423Sjfv case i40e_aqc_opc_get_link_status: 4888279858Sjfv ixl_link_event(pf, &event); 4889266423Sjfv break; 4890266423Sjfv case i40e_aqc_opc_send_msg_to_pf: 4891279858Sjfv#ifdef PCI_IOV 4892279858Sjfv ixl_handle_vf_msg(pf, &event); 4893279858Sjfv#endif 4894266423Sjfv break; 4895266423Sjfv case i40e_aqc_opc_event_lan_overflow: 4896266423Sjfv default: 4897266423Sjfv break; 4898266423Sjfv } 4899266423Sjfv 4900270346Sjfv } while (result && (loop++ < IXL_ADM_LIMIT)); 4901266423Sjfv 4902266423Sjfv free(event.msg_buf, M_DEVBUF); 4903266423Sjfv 4904279858Sjfv /* 4905279858Sjfv * If there are still messages to process, reschedule ourselves. 4906279858Sjfv * Otherwise, re-enable our interrupt and go to sleep. 4907279858Sjfv */ 4908279858Sjfv if (result > 0) 4909279858Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 4910266423Sjfv else 4911299547Serj ixl_enable_adminq(hw); 4912279858Sjfv 4913279858Sjfv IXL_PF_UNLOCK(pf); 4914266423Sjfv} 4915266423Sjfv 4916266423Sjfv/** 4917266423Sjfv * Update VSI-specific ethernet statistics counters. 4918266423Sjfv **/ 4919299554Serjvoid 4920299554Serjixl_update_eth_stats(struct ixl_vsi *vsi) 4921266423Sjfv{ 4922270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 4923266423Sjfv struct i40e_hw *hw = &pf->hw; 4924266423Sjfv struct i40e_eth_stats *es; 4925266423Sjfv struct i40e_eth_stats *oes; 4926272227Sglebius struct i40e_hw_port_stats *nsd; 4927266423Sjfv u16 stat_idx = vsi->info.stat_counter_idx; 4928266423Sjfv 4929266423Sjfv es = &vsi->eth_stats; 4930266423Sjfv oes = &vsi->eth_stats_offsets; 4931272227Sglebius nsd = &pf->stats; 4932266423Sjfv 4933266423Sjfv /* Gather up the stats that the hw collects */ 4934270346Sjfv ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx), 4935266423Sjfv vsi->stat_offsets_loaded, 4936266423Sjfv &oes->tx_errors, &es->tx_errors); 4937270346Sjfv ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx), 4938266423Sjfv vsi->stat_offsets_loaded, 4939266423Sjfv &oes->rx_discards, &es->rx_discards); 4940266423Sjfv 4941270346Sjfv ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx), 4942266423Sjfv I40E_GLV_GORCL(stat_idx), 4943266423Sjfv vsi->stat_offsets_loaded, 4944266423Sjfv &oes->rx_bytes, &es->rx_bytes); 4945270346Sjfv ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx), 4946266423Sjfv I40E_GLV_UPRCL(stat_idx), 4947266423Sjfv vsi->stat_offsets_loaded, 4948266423Sjfv &oes->rx_unicast, &es->rx_unicast); 4949270346Sjfv ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx), 4950266423Sjfv I40E_GLV_MPRCL(stat_idx), 4951266423Sjfv vsi->stat_offsets_loaded, 4952266423Sjfv &oes->rx_multicast, &es->rx_multicast); 4953270346Sjfv ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx), 4954266423Sjfv I40E_GLV_BPRCL(stat_idx), 4955266423Sjfv vsi->stat_offsets_loaded, 4956266423Sjfv &oes->rx_broadcast, &es->rx_broadcast); 4957266423Sjfv 4958270346Sjfv ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx), 4959266423Sjfv I40E_GLV_GOTCL(stat_idx), 4960266423Sjfv vsi->stat_offsets_loaded, 4961266423Sjfv &oes->tx_bytes, &es->tx_bytes); 4962270346Sjfv ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx), 4963266423Sjfv I40E_GLV_UPTCL(stat_idx), 4964266423Sjfv vsi->stat_offsets_loaded, 4965266423Sjfv &oes->tx_unicast, &es->tx_unicast); 4966270346Sjfv ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx), 4967266423Sjfv I40E_GLV_MPTCL(stat_idx), 4968266423Sjfv vsi->stat_offsets_loaded, 4969266423Sjfv &oes->tx_multicast, &es->tx_multicast); 4970270346Sjfv ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx), 4971266423Sjfv I40E_GLV_BPTCL(stat_idx), 4972266423Sjfv vsi->stat_offsets_loaded, 4973266423Sjfv &oes->tx_broadcast, &es->tx_broadcast); 4974266423Sjfv vsi->stat_offsets_loaded = true; 4975279858Sjfv} 4976269198Sjfv 4977279858Sjfvstatic void 4978279858Sjfvixl_update_vsi_stats(struct ixl_vsi *vsi) 4979279858Sjfv{ 4980279858Sjfv struct ixl_pf *pf; 4981279858Sjfv struct ifnet *ifp; 4982279858Sjfv struct i40e_eth_stats *es; 4983279858Sjfv u64 tx_discards; 4984279858Sjfv 4985279858Sjfv struct i40e_hw_port_stats *nsd; 4986279858Sjfv 4987279858Sjfv pf = vsi->back; 4988279858Sjfv ifp = vsi->ifp; 4989279858Sjfv es = &vsi->eth_stats; 4990279858Sjfv nsd = &pf->stats; 4991279858Sjfv 4992279858Sjfv ixl_update_eth_stats(vsi); 4993279858Sjfv 4994272227Sglebius tx_discards = es->tx_discards + nsd->tx_dropped_link_down; 4995279858Sjfv for (int i = 0; i < vsi->num_queues; i++) 4996272227Sglebius tx_discards += vsi->queues[i].txr.br->br_drops; 4997272227Sglebius 4998269198Sjfv /* Update ifnet stats */ 4999272227Sglebius IXL_SET_IPACKETS(vsi, es->rx_unicast + 5000269198Sjfv es->rx_multicast + 5001272227Sglebius es->rx_broadcast); 5002272227Sglebius IXL_SET_OPACKETS(vsi, es->tx_unicast + 5003269198Sjfv es->tx_multicast + 5004272227Sglebius es->tx_broadcast); 5005272227Sglebius IXL_SET_IBYTES(vsi, es->rx_bytes); 5006272227Sglebius IXL_SET_OBYTES(vsi, es->tx_bytes); 5007272227Sglebius IXL_SET_IMCASTS(vsi, es->rx_multicast); 5008272227Sglebius IXL_SET_OMCASTS(vsi, es->tx_multicast); 5009269198Sjfv 5010279858Sjfv IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes + 5011279858Sjfv nsd->rx_undersize + nsd->rx_oversize + nsd->rx_fragments + 5012279858Sjfv nsd->rx_jabber); 5013272227Sglebius IXL_SET_OERRORS(vsi, es->tx_errors); 5014272227Sglebius IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards); 5015272227Sglebius IXL_SET_OQDROPS(vsi, tx_discards); 5016272227Sglebius IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol); 5017272227Sglebius IXL_SET_COLLISIONS(vsi, 0); 5018266423Sjfv} 5019266423Sjfv 5020266423Sjfv/** 5021266423Sjfv * Reset all of the stats for the given pf 5022266423Sjfv **/ 5023270346Sjfvvoid ixl_pf_reset_stats(struct ixl_pf *pf) 5024266423Sjfv{ 5025266423Sjfv bzero(&pf->stats, sizeof(struct i40e_hw_port_stats)); 5026266423Sjfv bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats)); 5027266423Sjfv pf->stat_offsets_loaded = false; 5028266423Sjfv} 5029266423Sjfv 5030266423Sjfv/** 5031266423Sjfv * Resets all stats of the given vsi 5032266423Sjfv **/ 5033270346Sjfvvoid ixl_vsi_reset_stats(struct ixl_vsi *vsi) 5034266423Sjfv{ 5035266423Sjfv bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats)); 5036266423Sjfv bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats)); 5037266423Sjfv vsi->stat_offsets_loaded = false; 5038266423Sjfv} 5039266423Sjfv 5040266423Sjfv/** 5041266423Sjfv * Read and update a 48 bit stat from the hw 5042266423Sjfv * 5043266423Sjfv * Since the device stats are not reset at PFReset, they likely will not 5044266423Sjfv * be zeroed when the driver starts. We'll save the first values read 5045266423Sjfv * and use them as offsets to be subtracted from the raw values in order 5046266423Sjfv * to report stats that count from zero. 5047266423Sjfv **/ 5048266423Sjfvstatic void 5049270346Sjfvixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg, 5050266423Sjfv bool offset_loaded, u64 *offset, u64 *stat) 5051266423Sjfv{ 5052266423Sjfv u64 new_data; 5053266423Sjfv 5054270799Sbz#if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__) 5055266423Sjfv new_data = rd64(hw, loreg); 5056266423Sjfv#else 5057266423Sjfv /* 5058269198Sjfv * Use two rd32's instead of one rd64; FreeBSD versions before 5059266423Sjfv * 10 don't support 8 byte bus reads/writes. 5060266423Sjfv */ 5061266423Sjfv new_data = rd32(hw, loreg); 5062266423Sjfv new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32; 5063266423Sjfv#endif 5064266423Sjfv 5065266423Sjfv if (!offset_loaded) 5066266423Sjfv *offset = new_data; 5067266423Sjfv if (new_data >= *offset) 5068266423Sjfv *stat = new_data - *offset; 5069266423Sjfv else 5070266423Sjfv *stat = (new_data + ((u64)1 << 48)) - *offset; 5071266423Sjfv *stat &= 0xFFFFFFFFFFFFULL; 5072266423Sjfv} 5073266423Sjfv 5074266423Sjfv/** 5075266423Sjfv * Read and update a 32 bit stat from the hw 5076266423Sjfv **/ 5077266423Sjfvstatic void 5078270346Sjfvixl_stat_update32(struct i40e_hw *hw, u32 reg, 5079266423Sjfv bool offset_loaded, u64 *offset, u64 *stat) 5080266423Sjfv{ 5081266423Sjfv u32 new_data; 5082266423Sjfv 5083266423Sjfv new_data = rd32(hw, reg); 5084266423Sjfv if (!offset_loaded) 5085266423Sjfv *offset = new_data; 5086266423Sjfv if (new_data >= *offset) 5087266423Sjfv *stat = (u32)(new_data - *offset); 5088266423Sjfv else 5089266423Sjfv *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); 5090266423Sjfv} 5091266423Sjfv 5092299549Serjstatic void 5093299549Serjixl_add_device_sysctls(struct ixl_pf *pf) 5094299549Serj{ 5095299549Serj device_t dev = pf->dev; 5096299549Serj 5097299549Serj /* Set up sysctls */ 5098299549Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5099299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5100299549Serj OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, 5101299551Serj pf, 0, ixl_set_flowcntl, "I", IXL_SYSCTL_HELP_FC); 5102299549Serj 5103299549Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5104299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5105299549Serj OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, 5106299551Serj pf, 0, ixl_set_advertise, "I", IXL_SYSCTL_HELP_SET_ADVERTISE); 5107299549Serj 5108299549Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5109299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5110299549Serj OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD, 5111299549Serj pf, 0, ixl_current_speed, "A", "Current Port Speed"); 5112299549Serj 5113299549Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5114299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5115299549Serj OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD, 5116299549Serj pf, 0, ixl_sysctl_show_fw, "A", "Firmware version"); 5117299549Serj 5118299554Serj#if 0 5119299549Serj SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5120299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5121299549Serj OID_AUTO, "rx_itr", CTLFLAG_RW, 5122299554Serj &ixl_rx_itr, 0, "RX ITR"); 5123299549Serj 5124299549Serj SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5125299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5126299549Serj OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW, 5127299549Serj &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR"); 5128299549Serj 5129299549Serj SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5130299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5131299549Serj OID_AUTO, "tx_itr", CTLFLAG_RW, 5132299554Serj &ixl_tx_itr, 0, "TX ITR"); 5133299549Serj 5134299549Serj SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 5135299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5136299549Serj OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW, 5137299549Serj &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR"); 5138299554Serj#endif 5139299549Serj 5140299549Serj#ifdef IXL_DEBUG_SYSCTL 5141299549Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5142299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5143299549Serj OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0, 5144299549Serj ixl_debug_info, "I", "Debug Information"); 5145299549Serj 5146299551Serj /* Shared-code debug message level */ 5147299549Serj SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 5148299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5149299549Serj OID_AUTO, "debug_mask", CTLFLAG_RW, 5150299549Serj &pf->hw.debug_mask, 0, "Debug Message Level"); 5151299549Serj 5152299549Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5153299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5154299549Serj OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD, 5155299551Serj pf, 0, ixl_sysctl_link_status, "A", IXL_SYSCTL_HELP_LINK_STATUS); 5156299549Serj 5157299549Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5158299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5159299549Serj OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD, 5160299549Serj pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities"); 5161299549Serj 5162299549Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5163299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5164299549Serj OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD, 5165299549Serj pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List"); 5166299549Serj 5167299549Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5168299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5169299549Serj OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD, 5170299549Serj pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation"); 5171299549Serj 5172299549Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 5173299549Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5174299549Serj OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD, 5175299549Serj pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration"); 5176299551Serj 5177299551Serj#ifdef PCI_IOV 5178299551Serj SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 5179299551Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 5180299551Serj OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl, 5181299551Serj 0, "PF/VF Virtual Channel debug level"); 5182299549Serj#endif 5183299551Serj#endif 5184299549Serj} 5185299549Serj 5186266423Sjfv/* 5187266423Sjfv** Set flow control using sysctl: 5188266423Sjfv** 0 - off 5189266423Sjfv** 1 - rx pause 5190266423Sjfv** 2 - tx pause 5191266423Sjfv** 3 - full 5192266423Sjfv*/ 5193266423Sjfvstatic int 5194270346Sjfvixl_set_flowcntl(SYSCTL_HANDLER_ARGS) 5195266423Sjfv{ 5196266423Sjfv /* 5197266423Sjfv * TODO: ensure tx CRC by hardware should be enabled 5198266423Sjfv * if tx flow control is enabled. 5199299547Serj * ^ N/A for 40G ports 5200266423Sjfv */ 5201270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 5202266423Sjfv struct i40e_hw *hw = &pf->hw; 5203266423Sjfv device_t dev = pf->dev; 5204299553Serj int requested_fc, error = 0; 5205266423Sjfv enum i40e_status_code aq_error = 0; 5206266423Sjfv u8 fc_aq_err = 0; 5207266423Sjfv 5208279033Sjfv /* Get request */ 5209299553Serj requested_fc = pf->fc; 5210299553Serj error = sysctl_handle_int(oidp, &requested_fc, 0, req); 5211266423Sjfv if ((error) || (req->newptr == NULL)) 5212269198Sjfv return (error); 5213299553Serj if (requested_fc < 0 || requested_fc > 3) { 5214266423Sjfv device_printf(dev, 5215266423Sjfv "Invalid fc mode; valid modes are 0 through 3\n"); 5216266423Sjfv return (EINVAL); 5217266423Sjfv } 5218266423Sjfv 5219266423Sjfv /* Set fc ability for port */ 5220299553Serj hw->fc.requested_mode = requested_fc; 5221269198Sjfv aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE); 5222269198Sjfv if (aq_error) { 5223269198Sjfv device_printf(dev, 5224269198Sjfv "%s: Error setting new fc mode %d; fc_err %#x\n", 5225269198Sjfv __func__, aq_error, fc_aq_err); 5226299547Serj return (EIO); 5227269198Sjfv } 5228299553Serj pf->fc = requested_fc; 5229266423Sjfv 5230299547Serj /* Get new link state */ 5231299547Serj i40e_msec_delay(250); 5232299547Serj hw->phy.get_link_info = TRUE; 5233299547Serj i40e_get_link_status(hw, &pf->link_up); 5234299547Serj 5235269198Sjfv return (0); 5236269198Sjfv} 5237266423Sjfv 5238270346Sjfvstatic int 5239270346Sjfvixl_current_speed(SYSCTL_HANDLER_ARGS) 5240270346Sjfv{ 5241270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 5242270346Sjfv struct i40e_hw *hw = &pf->hw; 5243270346Sjfv int error = 0, index = 0; 5244270346Sjfv 5245270346Sjfv char *speeds[] = { 5246270346Sjfv "Unknown", 5247270346Sjfv "100M", 5248270346Sjfv "1G", 5249270346Sjfv "10G", 5250270346Sjfv "40G", 5251270346Sjfv "20G" 5252270346Sjfv }; 5253270346Sjfv 5254270346Sjfv ixl_update_link_status(pf); 5255270346Sjfv 5256270346Sjfv switch (hw->phy.link_info.link_speed) { 5257270346Sjfv case I40E_LINK_SPEED_100MB: 5258270346Sjfv index = 1; 5259270346Sjfv break; 5260270346Sjfv case I40E_LINK_SPEED_1GB: 5261270346Sjfv index = 2; 5262270346Sjfv break; 5263270346Sjfv case I40E_LINK_SPEED_10GB: 5264270346Sjfv index = 3; 5265270346Sjfv break; 5266270346Sjfv case I40E_LINK_SPEED_40GB: 5267270346Sjfv index = 4; 5268270346Sjfv break; 5269270346Sjfv case I40E_LINK_SPEED_20GB: 5270270346Sjfv index = 5; 5271270346Sjfv break; 5272270346Sjfv case I40E_LINK_SPEED_UNKNOWN: 5273270346Sjfv default: 5274270346Sjfv index = 0; 5275270346Sjfv break; 5276270346Sjfv } 5277270346Sjfv 5278270346Sjfv error = sysctl_handle_string(oidp, speeds[index], 5279270346Sjfv strlen(speeds[index]), req); 5280270346Sjfv return (error); 5281270346Sjfv} 5282270346Sjfv 5283274205Sjfvstatic int 5284274205Sjfvixl_set_advertised_speeds(struct ixl_pf *pf, int speeds) 5285274205Sjfv{ 5286274205Sjfv struct i40e_hw *hw = &pf->hw; 5287274205Sjfv device_t dev = pf->dev; 5288274205Sjfv struct i40e_aq_get_phy_abilities_resp abilities; 5289274205Sjfv struct i40e_aq_set_phy_config config; 5290274205Sjfv enum i40e_status_code aq_error = 0; 5291274205Sjfv 5292274205Sjfv /* Get current capability information */ 5293279033Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, 5294279033Sjfv FALSE, FALSE, &abilities, NULL); 5295274205Sjfv if (aq_error) { 5296279033Sjfv device_printf(dev, 5297279033Sjfv "%s: Error getting phy capabilities %d," 5298274205Sjfv " aq error: %d\n", __func__, aq_error, 5299274205Sjfv hw->aq.asq_last_status); 5300274205Sjfv return (EAGAIN); 5301274205Sjfv } 5302274205Sjfv 5303274205Sjfv /* Prepare new config */ 5304274205Sjfv bzero(&config, sizeof(config)); 5305274205Sjfv config.phy_type = abilities.phy_type; 5306274205Sjfv config.abilities = abilities.abilities 5307274205Sjfv | I40E_AQ_PHY_ENABLE_ATOMIC_LINK; 5308274205Sjfv config.eee_capability = abilities.eee_capability; 5309274205Sjfv config.eeer = abilities.eeer_val; 5310274205Sjfv config.low_power_ctrl = abilities.d3_lpan; 5311274205Sjfv /* Translate into aq cmd link_speed */ 5312299552Serj if (speeds & 0x10) 5313299552Serj config.link_speed |= I40E_LINK_SPEED_40GB; 5314279858Sjfv if (speeds & 0x8) 5315279858Sjfv config.link_speed |= I40E_LINK_SPEED_20GB; 5316274205Sjfv if (speeds & 0x4) 5317274205Sjfv config.link_speed |= I40E_LINK_SPEED_10GB; 5318274205Sjfv if (speeds & 0x2) 5319274205Sjfv config.link_speed |= I40E_LINK_SPEED_1GB; 5320274205Sjfv if (speeds & 0x1) 5321274205Sjfv config.link_speed |= I40E_LINK_SPEED_100MB; 5322274205Sjfv 5323274205Sjfv /* Do aq command & restart link */ 5324274205Sjfv aq_error = i40e_aq_set_phy_config(hw, &config, NULL); 5325274205Sjfv if (aq_error) { 5326279033Sjfv device_printf(dev, 5327279033Sjfv "%s: Error setting new phy config %d," 5328274205Sjfv " aq error: %d\n", __func__, aq_error, 5329274205Sjfv hw->aq.asq_last_status); 5330274205Sjfv return (EAGAIN); 5331274205Sjfv } 5332274205Sjfv 5333277084Sjfv /* 5334277084Sjfv ** This seems a bit heavy handed, but we 5335277084Sjfv ** need to get a reinit on some devices 5336277084Sjfv */ 5337277084Sjfv IXL_PF_LOCK(pf); 5338299547Serj ixl_stop_locked(pf); 5339277084Sjfv ixl_init_locked(pf); 5340277084Sjfv IXL_PF_UNLOCK(pf); 5341277084Sjfv 5342274205Sjfv return (0); 5343274205Sjfv} 5344274205Sjfv 5345269198Sjfv/* 5346269198Sjfv** Control link advertise speed: 5347270346Sjfv** Flags: 5348299552Serj** 0x1 - advertise 100 Mb 5349299552Serj** 0x2 - advertise 1G 5350299552Serj** 0x4 - advertise 10G 5351299552Serj** 0x8 - advertise 20G 5352299552Serj** 0x10 - advertise 40G 5353269198Sjfv** 5354299552Serj** Set to 0 to disable link 5355269198Sjfv*/ 5356269198Sjfvstatic int 5357270346Sjfvixl_set_advertise(SYSCTL_HANDLER_ARGS) 5358269198Sjfv{ 5359270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 5360269198Sjfv struct i40e_hw *hw = &pf->hw; 5361269198Sjfv device_t dev = pf->dev; 5362270346Sjfv int requested_ls = 0; 5363269198Sjfv int error = 0; 5364266423Sjfv 5365269198Sjfv /* Read in new mode */ 5366270346Sjfv requested_ls = pf->advertised_speed; 5367269198Sjfv error = sysctl_handle_int(oidp, &requested_ls, 0, req); 5368269198Sjfv if ((error) || (req->newptr == NULL)) 5369269198Sjfv return (error); 5370279858Sjfv /* Check for sane value */ 5371299552Serj if (requested_ls > 0x10) { 5372279858Sjfv device_printf(dev, "Invalid advertised speed; " 5373299552Serj "valid modes are 0x1 through 0x10\n"); 5374269198Sjfv return (EINVAL); 5375266423Sjfv } 5376279858Sjfv /* Then check for validity based on adapter type */ 5377279858Sjfv switch (hw->device_id) { 5378279858Sjfv case I40E_DEV_ID_10G_BASE_T: 5379299545Serj case I40E_DEV_ID_10G_BASE_T4: 5380299552Serj /* BaseT */ 5381299552Serj if (requested_ls & ~(0x7)) { 5382279858Sjfv device_printf(dev, 5383299552Serj "Only 100M/1G/10G speeds supported on this device.\n"); 5384279858Sjfv return (EINVAL); 5385279858Sjfv } 5386279858Sjfv break; 5387279858Sjfv case I40E_DEV_ID_20G_KR2: 5388299545Serj case I40E_DEV_ID_20G_KR2_A: 5389299552Serj /* 20G */ 5390299552Serj if (requested_ls & ~(0xE)) { 5391279858Sjfv device_printf(dev, 5392299552Serj "Only 1G/10G/20G speeds supported on this device.\n"); 5393279858Sjfv return (EINVAL); 5394279858Sjfv } 5395279858Sjfv break; 5396299552Serj case I40E_DEV_ID_KX_B: 5397299552Serj case I40E_DEV_ID_QSFP_A: 5398299552Serj case I40E_DEV_ID_QSFP_B: 5399299552Serj /* 40G */ 5400299552Serj if (requested_ls & ~(0x10)) { 5401299552Serj device_printf(dev, 5402299552Serj "Only 40G speeds supported on this device.\n"); 5403299552Serj return (EINVAL); 5404299552Serj } 5405299552Serj break; 5406279858Sjfv default: 5407299552Serj /* 10G (1G) */ 5408299552Serj if (requested_ls & ~(0x6)) { 5409279858Sjfv device_printf(dev, 5410279858Sjfv "Only 1/10Gbs speeds are supported on this device.\n"); 5411279858Sjfv return (EINVAL); 5412279858Sjfv } 5413279858Sjfv break; 5414279858Sjfv } 5415269198Sjfv 5416269198Sjfv /* Exit if no change */ 5417270346Sjfv if (pf->advertised_speed == requested_ls) 5418269198Sjfv return (0); 5419269198Sjfv 5420274205Sjfv error = ixl_set_advertised_speeds(pf, requested_ls); 5421274205Sjfv if (error) 5422274205Sjfv return (error); 5423270346Sjfv 5424270346Sjfv pf->advertised_speed = requested_ls; 5425270346Sjfv ixl_update_link_status(pf); 5426269198Sjfv return (0); 5427266423Sjfv} 5428266423Sjfv 5429266423Sjfv/* 5430266423Sjfv** Get the width and transaction speed of 5431266423Sjfv** the bus this adapter is plugged into. 5432266423Sjfv*/ 5433266423Sjfvstatic u16 5434270346Sjfvixl_get_bus_info(struct i40e_hw *hw, device_t dev) 5435266423Sjfv{ 5436266423Sjfv u16 link; 5437266423Sjfv u32 offset; 5438266423Sjfv 5439266423Sjfv /* Get the PCI Express Capabilities offset */ 5440266423Sjfv pci_find_cap(dev, PCIY_EXPRESS, &offset); 5441266423Sjfv 5442266423Sjfv /* ...and read the Link Status Register */ 5443266423Sjfv link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 5444266423Sjfv 5445266423Sjfv switch (link & I40E_PCI_LINK_WIDTH) { 5446266423Sjfv case I40E_PCI_LINK_WIDTH_1: 5447266423Sjfv hw->bus.width = i40e_bus_width_pcie_x1; 5448266423Sjfv break; 5449266423Sjfv case I40E_PCI_LINK_WIDTH_2: 5450266423Sjfv hw->bus.width = i40e_bus_width_pcie_x2; 5451266423Sjfv break; 5452266423Sjfv case I40E_PCI_LINK_WIDTH_4: 5453266423Sjfv hw->bus.width = i40e_bus_width_pcie_x4; 5454266423Sjfv break; 5455266423Sjfv case I40E_PCI_LINK_WIDTH_8: 5456266423Sjfv hw->bus.width = i40e_bus_width_pcie_x8; 5457266423Sjfv break; 5458266423Sjfv default: 5459266423Sjfv hw->bus.width = i40e_bus_width_unknown; 5460266423Sjfv break; 5461266423Sjfv } 5462266423Sjfv 5463266423Sjfv switch (link & I40E_PCI_LINK_SPEED) { 5464266423Sjfv case I40E_PCI_LINK_SPEED_2500: 5465266423Sjfv hw->bus.speed = i40e_bus_speed_2500; 5466266423Sjfv break; 5467266423Sjfv case I40E_PCI_LINK_SPEED_5000: 5468266423Sjfv hw->bus.speed = i40e_bus_speed_5000; 5469266423Sjfv break; 5470266423Sjfv case I40E_PCI_LINK_SPEED_8000: 5471266423Sjfv hw->bus.speed = i40e_bus_speed_8000; 5472266423Sjfv break; 5473266423Sjfv default: 5474266423Sjfv hw->bus.speed = i40e_bus_speed_unknown; 5475266423Sjfv break; 5476266423Sjfv } 5477266423Sjfv 5478266423Sjfv device_printf(dev,"PCI Express Bus: Speed %s %s\n", 5479266423Sjfv ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s": 5480266423Sjfv (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s": 5481266423Sjfv (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"), 5482266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" : 5483266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" : 5484266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" : 5485266423Sjfv ("Unknown")); 5486266423Sjfv 5487266423Sjfv if ((hw->bus.width <= i40e_bus_width_pcie_x8) && 5488266423Sjfv (hw->bus.speed < i40e_bus_speed_8000)) { 5489266423Sjfv device_printf(dev, "PCI-Express bandwidth available" 5490279858Sjfv " for this device\n may be insufficient for" 5491279858Sjfv " optimal performance.\n"); 5492266423Sjfv device_printf(dev, "For expected performance a x8 " 5493266423Sjfv "PCIE Gen3 slot is required.\n"); 5494266423Sjfv } 5495266423Sjfv 5496266423Sjfv return (link); 5497266423Sjfv} 5498266423Sjfv 5499274205Sjfvstatic int 5500274205Sjfvixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS) 5501274205Sjfv{ 5502274205Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 5503274205Sjfv struct i40e_hw *hw = &pf->hw; 5504299552Serj struct sbuf *sbuf; 5505274205Sjfv 5506299552Serj sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5507299552Serj ixl_nvm_version_str(hw, sbuf); 5508299552Serj sbuf_finish(sbuf); 5509299552Serj sbuf_delete(sbuf); 5510299552Serj 5511299552Serj return 0; 5512274205Sjfv} 5513274205Sjfv 5514299554Serj#ifdef IXL_DEBUG 5515299554Serjstatic void 5516299553Serjixl_print_nvm_cmd(device_t dev, struct i40e_nvm_access *nvma) 5517299553Serj{ 5518299553Serj if ((nvma->command == I40E_NVM_READ) && 5519299553Serj ((nvma->config & 0xFF) == 0xF) && 5520299553Serj (((nvma->config & 0xF00) >> 8) == 0xF) && 5521299553Serj (nvma->offset == 0) && 5522299553Serj (nvma->data_size == 1)) { 5523299553Serj // device_printf(dev, "- Get Driver Status Command\n"); 5524299553Serj } 5525299553Serj else if (nvma->command == I40E_NVM_READ) { 5526299553Serj 5527299553Serj } 5528299553Serj else { 5529299553Serj switch (nvma->command) { 5530299553Serj case 0xB: 5531299553Serj device_printf(dev, "- command: I40E_NVM_READ\n"); 5532299553Serj break; 5533299553Serj case 0xC: 5534299553Serj device_printf(dev, "- command: I40E_NVM_WRITE\n"); 5535299553Serj break; 5536299553Serj default: 5537299553Serj device_printf(dev, "- command: unknown 0x%08x\n", nvma->command); 5538299553Serj break; 5539299553Serj } 5540299553Serj 5541299553Serj device_printf(dev, "- config (ptr) : 0x%02x\n", nvma->config & 0xFF); 5542299553Serj device_printf(dev, "- config (flags): 0x%01x\n", (nvma->config & 0xF00) >> 8); 5543299553Serj device_printf(dev, "- offset : 0x%08x\n", nvma->offset); 5544299553Serj device_printf(dev, "- data_s : 0x%08x\n", nvma->data_size); 5545299553Serj } 5546299553Serj} 5547299554Serj#endif 5548299553Serj 5549299547Serjstatic int 5550299547Serjixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd) 5551299547Serj{ 5552299547Serj struct i40e_hw *hw = &pf->hw; 5553299547Serj struct i40e_nvm_access *nvma; 5554299547Serj device_t dev = pf->dev; 5555299547Serj enum i40e_status_code status = 0; 5556299547Serj int perrno; 5557274205Sjfv 5558299547Serj DEBUGFUNC("ixl_handle_nvmupd_cmd"); 5559299547Serj 5560299553Serj /* Sanity checks */ 5561299547Serj if (ifd->ifd_len < sizeof(struct i40e_nvm_access) || 5562299547Serj ifd->ifd_data == NULL) { 5563299553Serj device_printf(dev, "%s: incorrect ifdrv length or data pointer\n", 5564299553Serj __func__); 5565299553Serj device_printf(dev, "%s: ifdrv length: %lu, sizeof(struct i40e_nvm_access): %lu\n", 5566299553Serj __func__, ifd->ifd_len, sizeof(struct i40e_nvm_access)); 5567299553Serj device_printf(dev, "%s: data pointer: %p\n", __func__, 5568299553Serj ifd->ifd_data); 5569299547Serj return (EINVAL); 5570299547Serj } 5571299547Serj 5572299547Serj nvma = (struct i40e_nvm_access *)ifd->ifd_data; 5573299547Serj 5574299553Serj#ifdef IXL_DEBUG 5575299553Serj ixl_print_nvm_cmd(dev, nvma); 5576299553Serj#endif 5577299553Serj 5578299549Serj if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { 5579299549Serj int count = 0; 5580299549Serj while (count++ < 100) { 5581299549Serj i40e_msec_delay(100); 5582299549Serj if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) 5583299549Serj break; 5584299549Serj } 5585299549Serj } 5586299549Serj 5587299549Serj if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) { 5588299549Serj IXL_PF_LOCK(pf); 5589299549Serj status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno); 5590299549Serj IXL_PF_UNLOCK(pf); 5591299549Serj } else { 5592299549Serj perrno = -EBUSY; 5593299549Serj } 5594299549Serj 5595299548Serj if (status) 5596299548Serj device_printf(dev, "i40e_nvmupd_command status %d, perrno %d\n", 5597299548Serj status, perrno); 5598299547Serj 5599299549Serj /* 5600299549Serj * -EPERM is actually ERESTART, which the kernel interprets as it needing 5601299549Serj * to run this ioctl again. So use -EACCES for -EPERM instead. 5602299549Serj */ 5603299548Serj if (perrno == -EPERM) 5604299548Serj return (-EACCES); 5605299548Serj else 5606299548Serj return (perrno); 5607299547Serj} 5608299547Serj 5609277084Sjfv#ifdef IXL_DEBUG_SYSCTL 5610266423Sjfvstatic int 5611270346Sjfvixl_sysctl_link_status(SYSCTL_HANDLER_ARGS) 5612266423Sjfv{ 5613270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 5614266423Sjfv struct i40e_hw *hw = &pf->hw; 5615266423Sjfv struct i40e_link_status link_status; 5616266423Sjfv char buf[512]; 5617266423Sjfv 5618266423Sjfv enum i40e_status_code aq_error = 0; 5619266423Sjfv 5620266423Sjfv aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL); 5621266423Sjfv if (aq_error) { 5622266423Sjfv printf("i40e_aq_get_link_info() error %d\n", aq_error); 5623266423Sjfv return (EPERM); 5624266423Sjfv } 5625266423Sjfv 5626266423Sjfv sprintf(buf, "\n" 5627266423Sjfv "PHY Type : %#04x\n" 5628266423Sjfv "Speed : %#04x\n" 5629266423Sjfv "Link info: %#04x\n" 5630266423Sjfv "AN info : %#04x\n" 5631299551Serj "Ext info : %#04x\n" 5632299551Serj "Max Frame: %d\n" 5633299552Serj "Pacing : %#04x\n" 5634299552Serj "CRC En? : %d", 5635266423Sjfv link_status.phy_type, link_status.link_speed, 5636266423Sjfv link_status.link_info, link_status.an_info, 5637299551Serj link_status.ext_info, link_status.max_frame_size, 5638299552Serj link_status.pacing, link_status.crc_enable); 5639266423Sjfv 5640266423Sjfv return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 5641266423Sjfv} 5642266423Sjfv 5643266423Sjfvstatic int 5644270346Sjfvixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS) 5645266423Sjfv{ 5646279858Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 5647279858Sjfv struct i40e_hw *hw = &pf->hw; 5648279858Sjfv char buf[512]; 5649279858Sjfv enum i40e_status_code aq_error = 0; 5650266423Sjfv 5651279858Sjfv struct i40e_aq_get_phy_abilities_resp abilities; 5652266423Sjfv 5653279858Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, 5654279858Sjfv TRUE, FALSE, &abilities, NULL); 5655266423Sjfv if (aq_error) { 5656266423Sjfv printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error); 5657266423Sjfv return (EPERM); 5658266423Sjfv } 5659266423Sjfv 5660266423Sjfv sprintf(buf, "\n" 5661266423Sjfv "PHY Type : %#010x\n" 5662266423Sjfv "Speed : %#04x\n" 5663266423Sjfv "Abilities: %#04x\n" 5664266423Sjfv "EEE cap : %#06x\n" 5665266423Sjfv "EEER reg : %#010x\n" 5666266423Sjfv "D3 Lpan : %#04x", 5667279858Sjfv abilities.phy_type, abilities.link_speed, 5668279858Sjfv abilities.abilities, abilities.eee_capability, 5669279858Sjfv abilities.eeer_val, abilities.d3_lpan); 5670266423Sjfv 5671266423Sjfv return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 5672266423Sjfv} 5673266423Sjfv 5674266423Sjfvstatic int 5675270346Sjfvixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS) 5676266423Sjfv{ 5677270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 5678270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 5679270346Sjfv struct ixl_mac_filter *f; 5680266423Sjfv char *buf, *buf_i; 5681266423Sjfv 5682266423Sjfv int error = 0; 5683266423Sjfv int ftl_len = 0; 5684266423Sjfv int ftl_counter = 0; 5685266423Sjfv int buf_len = 0; 5686266423Sjfv int entry_len = 42; 5687266423Sjfv 5688266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 5689266423Sjfv ftl_len++; 5690266423Sjfv } 5691266423Sjfv 5692266423Sjfv if (ftl_len < 1) { 5693266423Sjfv sysctl_handle_string(oidp, "(none)", 6, req); 5694266423Sjfv return (0); 5695266423Sjfv } 5696266423Sjfv 5697266423Sjfv buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2; 5698266423Sjfv buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT); 5699266423Sjfv 5700266423Sjfv sprintf(buf_i++, "\n"); 5701266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 5702266423Sjfv sprintf(buf_i, 5703266423Sjfv MAC_FORMAT ", vlan %4d, flags %#06x", 5704266423Sjfv MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags); 5705266423Sjfv buf_i += entry_len; 5706266423Sjfv /* don't print '\n' for last entry */ 5707266423Sjfv if (++ftl_counter != ftl_len) { 5708266423Sjfv sprintf(buf_i, "\n"); 5709266423Sjfv buf_i++; 5710266423Sjfv } 5711266423Sjfv } 5712266423Sjfv 5713266423Sjfv error = sysctl_handle_string(oidp, buf, strlen(buf), req); 5714266423Sjfv if (error) 5715266423Sjfv printf("sysctl error: %d\n", error); 5716266423Sjfv free(buf, M_DEVBUF); 5717266423Sjfv return error; 5718266423Sjfv} 5719269198Sjfv 5720270346Sjfv#define IXL_SW_RES_SIZE 0x14 5721269198Sjfvstatic int 5722277084Sjfvixl_res_alloc_cmp(const void *a, const void *b) 5723277084Sjfv{ 5724277084Sjfv const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two; 5725284049Sjfv one = (const struct i40e_aqc_switch_resource_alloc_element_resp *)a; 5726284049Sjfv two = (const struct i40e_aqc_switch_resource_alloc_element_resp *)b; 5727277084Sjfv 5728277084Sjfv return ((int)one->resource_type - (int)two->resource_type); 5729277084Sjfv} 5730277084Sjfv 5731299549Serj/* 5732299549Serj * Longest string length: 25 5733299549Serj */ 5734299549Serjstatic char * 5735299549Serjixl_switch_res_type_string(u8 type) 5736299549Serj{ 5737299549Serj static char * ixl_switch_res_type_strings[0x14] = { 5738299549Serj "VEB", 5739299549Serj "VSI", 5740299549Serj "Perfect Match MAC address", 5741299549Serj "S-tag", 5742299549Serj "(Reserved)", 5743299549Serj "Multicast hash entry", 5744299549Serj "Unicast hash entry", 5745299549Serj "VLAN", 5746299549Serj "VSI List entry", 5747299549Serj "(Reserved)", 5748299549Serj "VLAN Statistic Pool", 5749299549Serj "Mirror Rule", 5750299549Serj "Queue Set", 5751299549Serj "Inner VLAN Forward filter", 5752299549Serj "(Reserved)", 5753299549Serj "Inner MAC", 5754299549Serj "IP", 5755299549Serj "GRE/VN1 Key", 5756299549Serj "VN2 Key", 5757299549Serj "Tunneling Port" 5758299549Serj }; 5759299549Serj 5760299549Serj if (type < 0x14) 5761299549Serj return ixl_switch_res_type_strings[type]; 5762299549Serj else 5763299549Serj return "(Reserved)"; 5764299549Serj} 5765299549Serj 5766277084Sjfvstatic int 5767274205Sjfvixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS) 5768269198Sjfv{ 5769270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 5770269198Sjfv struct i40e_hw *hw = &pf->hw; 5771269198Sjfv device_t dev = pf->dev; 5772269198Sjfv struct sbuf *buf; 5773269198Sjfv int error = 0; 5774269198Sjfv 5775269198Sjfv u8 num_entries; 5776270346Sjfv struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE]; 5777269198Sjfv 5778299546Serj buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5779269198Sjfv if (!buf) { 5780269198Sjfv device_printf(dev, "Could not allocate sbuf for output.\n"); 5781269198Sjfv return (ENOMEM); 5782269198Sjfv } 5783269198Sjfv 5784277084Sjfv bzero(resp, sizeof(resp)); 5785269198Sjfv error = i40e_aq_get_switch_resource_alloc(hw, &num_entries, 5786269198Sjfv resp, 5787270346Sjfv IXL_SW_RES_SIZE, 5788269198Sjfv NULL); 5789269198Sjfv if (error) { 5790279858Sjfv device_printf(dev, 5791279858Sjfv "%s: get_switch_resource_alloc() error %d, aq error %d\n", 5792269198Sjfv __func__, error, hw->aq.asq_last_status); 5793269198Sjfv sbuf_delete(buf); 5794269198Sjfv return error; 5795269198Sjfv } 5796269198Sjfv 5797277084Sjfv /* Sort entries by type for display */ 5798277084Sjfv qsort(resp, num_entries, 5799277084Sjfv sizeof(struct i40e_aqc_switch_resource_alloc_element_resp), 5800277084Sjfv &ixl_res_alloc_cmp); 5801277084Sjfv 5802269198Sjfv sbuf_cat(buf, "\n"); 5803277084Sjfv sbuf_printf(buf, "# of entries: %d\n", num_entries); 5804269198Sjfv sbuf_printf(buf, 5805299549Serj " Type | Guaranteed | Total | Used | Un-allocated\n" 5806299549Serj " | (this) | (all) | (this) | (all) \n"); 5807269198Sjfv for (int i = 0; i < num_entries; i++) { 5808269198Sjfv sbuf_printf(buf, 5809299549Serj "%25s | %10d %5d %6d %12d", 5810299549Serj ixl_switch_res_type_string(resp[i].resource_type), 5811269198Sjfv resp[i].guaranteed, 5812269198Sjfv resp[i].total, 5813269198Sjfv resp[i].used, 5814269198Sjfv resp[i].total_unalloced); 5815269198Sjfv if (i < num_entries - 1) 5816269198Sjfv sbuf_cat(buf, "\n"); 5817269198Sjfv } 5818269198Sjfv 5819269198Sjfv error = sbuf_finish(buf); 5820299546Serj if (error) 5821299545Serj device_printf(dev, "Error finishing sbuf: %d\n", error); 5822299545Serj 5823290708Ssmh sbuf_delete(buf); 5824299545Serj return error; 5825274205Sjfv} 5826269198Sjfv 5827274205Sjfv/* 5828274205Sjfv** Caller must init and delete sbuf; this function will clear and 5829274205Sjfv** finish it for caller. 5830299549Serj** 5831299549Serj** XXX: Cannot use the SEID for this, since there is no longer a 5832299549Serj** fixed mapping between SEID and element type. 5833274205Sjfv*/ 5834274205Sjfvstatic char * 5835299549Serjixl_switch_element_string(struct sbuf *s, 5836299549Serj struct i40e_aqc_switch_config_element_resp *element) 5837274205Sjfv{ 5838274205Sjfv sbuf_clear(s); 5839274205Sjfv 5840299549Serj switch (element->element_type) { 5841299549Serj case I40E_AQ_SW_ELEM_TYPE_MAC: 5842299549Serj sbuf_printf(s, "MAC %3d", element->element_info); 5843299549Serj break; 5844299549Serj case I40E_AQ_SW_ELEM_TYPE_PF: 5845299549Serj sbuf_printf(s, "PF %3d", element->element_info); 5846299549Serj break; 5847299549Serj case I40E_AQ_SW_ELEM_TYPE_VF: 5848299549Serj sbuf_printf(s, "VF %3d", element->element_info); 5849299549Serj break; 5850299549Serj case I40E_AQ_SW_ELEM_TYPE_EMP: 5851274205Sjfv sbuf_cat(s, "EMP"); 5852299549Serj break; 5853299549Serj case I40E_AQ_SW_ELEM_TYPE_BMC: 5854299549Serj sbuf_cat(s, "BMC"); 5855299549Serj break; 5856299549Serj case I40E_AQ_SW_ELEM_TYPE_PV: 5857299549Serj sbuf_cat(s, "PV"); 5858299549Serj break; 5859299549Serj case I40E_AQ_SW_ELEM_TYPE_VEB: 5860299549Serj sbuf_cat(s, "VEB"); 5861299549Serj break; 5862299549Serj case I40E_AQ_SW_ELEM_TYPE_PA: 5863299549Serj sbuf_cat(s, "PA"); 5864299549Serj break; 5865299549Serj case I40E_AQ_SW_ELEM_TYPE_VSI: 5866299549Serj sbuf_printf(s, "VSI %3d", element->element_info); 5867299549Serj break; 5868299549Serj default: 5869299549Serj sbuf_cat(s, "?"); 5870299549Serj break; 5871299549Serj } 5872274205Sjfv 5873274205Sjfv sbuf_finish(s); 5874274205Sjfv return sbuf_data(s); 5875269198Sjfv} 5876269198Sjfv 5877274205Sjfvstatic int 5878274205Sjfvixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS) 5879274205Sjfv{ 5880274205Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 5881274205Sjfv struct i40e_hw *hw = &pf->hw; 5882274205Sjfv device_t dev = pf->dev; 5883274205Sjfv struct sbuf *buf; 5884274205Sjfv struct sbuf *nmbuf; 5885274205Sjfv int error = 0; 5886299549Serj u16 next = 0; 5887274205Sjfv u8 aq_buf[I40E_AQ_LARGE_BUF]; 5888274205Sjfv 5889274205Sjfv struct i40e_aqc_get_switch_config_resp *sw_config; 5890274205Sjfv sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 5891274205Sjfv 5892299546Serj buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5893274205Sjfv if (!buf) { 5894274205Sjfv device_printf(dev, "Could not allocate sbuf for sysctl output.\n"); 5895274205Sjfv return (ENOMEM); 5896274205Sjfv } 5897274205Sjfv 5898274205Sjfv error = i40e_aq_get_switch_config(hw, sw_config, 5899274205Sjfv sizeof(aq_buf), &next, NULL); 5900274205Sjfv if (error) { 5901279858Sjfv device_printf(dev, 5902279858Sjfv "%s: aq_get_switch_config() error %d, aq error %d\n", 5903274205Sjfv __func__, error, hw->aq.asq_last_status); 5904274205Sjfv sbuf_delete(buf); 5905274205Sjfv return error; 5906274205Sjfv } 5907299549Serj if (next) 5908299549Serj device_printf(dev, "%s: TODO: get more config with SEID %d\n", 5909299549Serj __func__, next); 5910274205Sjfv 5911274205Sjfv nmbuf = sbuf_new_auto(); 5912274205Sjfv if (!nmbuf) { 5913274205Sjfv device_printf(dev, "Could not allocate sbuf for name output.\n"); 5914299546Serj sbuf_delete(buf); 5915274205Sjfv return (ENOMEM); 5916274205Sjfv } 5917274205Sjfv 5918274205Sjfv sbuf_cat(buf, "\n"); 5919274205Sjfv // Assuming <= 255 elements in switch 5920299549Serj sbuf_printf(buf, "# of reported elements: %d\n", sw_config->header.num_reported); 5921299549Serj sbuf_printf(buf, "total # of elements: %d\n", sw_config->header.num_total); 5922274205Sjfv /* Exclude: 5923274205Sjfv ** Revision -- all elements are revision 1 for now 5924274205Sjfv */ 5925274205Sjfv sbuf_printf(buf, 5926274205Sjfv "SEID ( Name ) | Uplink | Downlink | Conn Type\n" 5927274205Sjfv " | | | (uplink)\n"); 5928274205Sjfv for (int i = 0; i < sw_config->header.num_reported; i++) { 5929274205Sjfv // "%4d (%8s) | %8s %8s %#8x", 5930274205Sjfv sbuf_printf(buf, "%4d", sw_config->element[i].seid); 5931274205Sjfv sbuf_cat(buf, " "); 5932279858Sjfv sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf, 5933299549Serj &sw_config->element[i])); 5934274205Sjfv sbuf_cat(buf, " | "); 5935299549Serj sbuf_printf(buf, "%8d", sw_config->element[i].uplink_seid); 5936274205Sjfv sbuf_cat(buf, " "); 5937299549Serj sbuf_printf(buf, "%8d", sw_config->element[i].downlink_seid); 5938274205Sjfv sbuf_cat(buf, " "); 5939274205Sjfv sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type); 5940274205Sjfv if (i < sw_config->header.num_reported - 1) 5941274205Sjfv sbuf_cat(buf, "\n"); 5942274205Sjfv } 5943274205Sjfv sbuf_delete(nmbuf); 5944274205Sjfv 5945274205Sjfv error = sbuf_finish(buf); 5946299546Serj if (error) 5947299545Serj device_printf(dev, "Error finishing sbuf: %d\n", error); 5948299545Serj 5949274205Sjfv sbuf_delete(buf); 5950274205Sjfv 5951274205Sjfv return (error); 5952274205Sjfv} 5953299552Serj 5954299552Serjstatic int 5955299552Serjixl_debug_info(SYSCTL_HANDLER_ARGS) 5956299552Serj{ 5957299552Serj struct ixl_pf *pf; 5958299552Serj int error, input = 0; 5959299552Serj 5960299552Serj error = sysctl_handle_int(oidp, &input, 0, req); 5961299552Serj 5962299552Serj if (error || !req->newptr) 5963299552Serj return (error); 5964299552Serj 5965299552Serj if (input == 1) { 5966299552Serj pf = (struct ixl_pf *)arg1; 5967299552Serj ixl_print_debug_info(pf); 5968299552Serj } 5969299552Serj 5970299552Serj return (error); 5971299552Serj} 5972299552Serj 5973299552Serjstatic void 5974299552Serjixl_print_debug_info(struct ixl_pf *pf) 5975299552Serj{ 5976299552Serj struct i40e_hw *hw = &pf->hw; 5977299552Serj struct ixl_vsi *vsi = &pf->vsi; 5978299552Serj struct ixl_queue *que = vsi->queues; 5979299552Serj struct rx_ring *rxr = &que->rxr; 5980299552Serj struct tx_ring *txr = &que->txr; 5981299552Serj u32 reg; 5982299552Serj 5983299552Serj 5984299552Serj printf("Queue irqs = %jx\n", (uintmax_t)que->irqs); 5985299552Serj printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq); 5986299552Serj printf("RX next check = %x\n", rxr->next_check); 5987299552Serj printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done); 5988299552Serj printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets); 5989299552Serj printf("TX desc avail = %x\n", txr->avail); 5990299552Serj 5991299552Serj reg = rd32(hw, I40E_GLV_GORCL(0xc)); 5992299552Serj printf("RX Bytes = %x\n", reg); 5993299552Serj reg = rd32(hw, I40E_GLPRT_GORCL(hw->port)); 5994299552Serj printf("Port RX Bytes = %x\n", reg); 5995299552Serj reg = rd32(hw, I40E_GLV_RDPC(0xc)); 5996299552Serj printf("RX discard = %x\n", reg); 5997299552Serj reg = rd32(hw, I40E_GLPRT_RDPC(hw->port)); 5998299552Serj printf("Port RX discard = %x\n", reg); 5999299552Serj 6000299552Serj reg = rd32(hw, I40E_GLV_TEPC(0xc)); 6001299552Serj printf("TX errors = %x\n", reg); 6002299552Serj reg = rd32(hw, I40E_GLV_GOTCL(0xc)); 6003299552Serj printf("TX Bytes = %x\n", reg); 6004299552Serj 6005299552Serj reg = rd32(hw, I40E_GLPRT_RUC(hw->port)); 6006299552Serj printf("RX undersize = %x\n", reg); 6007299552Serj reg = rd32(hw, I40E_GLPRT_RFC(hw->port)); 6008299552Serj printf("RX fragments = %x\n", reg); 6009299552Serj reg = rd32(hw, I40E_GLPRT_ROC(hw->port)); 6010299552Serj printf("RX oversize = %x\n", reg); 6011299552Serj reg = rd32(hw, I40E_GLPRT_RLEC(hw->port)); 6012299552Serj printf("RX length error = %x\n", reg); 6013299552Serj reg = rd32(hw, I40E_GLPRT_MRFC(hw->port)); 6014299552Serj printf("mac remote fault = %x\n", reg); 6015299552Serj reg = rd32(hw, I40E_GLPRT_MLFC(hw->port)); 6016299552Serj printf("mac local fault = %x\n", reg); 6017299552Serj} 6018299552Serj 6019279858Sjfv#endif /* IXL_DEBUG_SYSCTL */ 6020274205Sjfv 6021279858Sjfv#ifdef PCI_IOV 6022269198Sjfvstatic int 6023279858Sjfvixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf) 6024269198Sjfv{ 6025279858Sjfv struct i40e_hw *hw; 6026279858Sjfv struct ixl_vsi *vsi; 6027279858Sjfv struct i40e_vsi_context vsi_ctx; 6028279858Sjfv int i; 6029279858Sjfv uint16_t first_queue; 6030279858Sjfv enum i40e_status_code code; 6031269198Sjfv 6032279858Sjfv hw = &pf->hw; 6033279858Sjfv vsi = &pf->vsi; 6034269198Sjfv 6035279858Sjfv vsi_ctx.pf_num = hw->pf_id; 6036279858Sjfv vsi_ctx.uplink_seid = pf->veb_seid; 6037279858Sjfv vsi_ctx.connection_type = IXL_VSI_DATA_PORT; 6038279858Sjfv vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num; 6039279858Sjfv vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF; 6040279858Sjfv 6041279858Sjfv bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); 6042279858Sjfv 6043279858Sjfv vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID); 6044279858Sjfv vsi_ctx.info.switch_id = htole16(0); 6045279858Sjfv 6046279858Sjfv vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID); 6047279858Sjfv vsi_ctx.info.sec_flags = 0; 6048279858Sjfv if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF) 6049279858Sjfv vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK; 6050279858Sjfv 6051299551Serj /* TODO: If a port VLAN is set, then this needs to be changed */ 6052279858Sjfv vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID); 6053279858Sjfv vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 6054279858Sjfv I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 6055279858Sjfv 6056279858Sjfv vsi_ctx.info.valid_sections |= 6057279858Sjfv htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID); 6058279858Sjfv vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG); 6059279858Sjfv first_queue = vsi->num_queues + vf->vf_num * IXLV_MAX_QUEUES; 6060279858Sjfv for (i = 0; i < IXLV_MAX_QUEUES; i++) 6061279858Sjfv vsi_ctx.info.queue_mapping[i] = htole16(first_queue + i); 6062279858Sjfv for (; i < nitems(vsi_ctx.info.queue_mapping); i++) 6063279858Sjfv vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK); 6064279858Sjfv 6065279858Sjfv vsi_ctx.info.tc_mapping[0] = htole16( 6066279858Sjfv (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) | 6067279858Sjfv (1 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)); 6068279858Sjfv 6069279858Sjfv code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL); 6070279858Sjfv if (code != I40E_SUCCESS) 6071279858Sjfv return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 6072279858Sjfv vf->vsi.seid = vsi_ctx.seid; 6073279858Sjfv vf->vsi.vsi_num = vsi_ctx.vsi_number; 6074279858Sjfv vf->vsi.first_queue = first_queue; 6075279858Sjfv vf->vsi.num_queues = IXLV_MAX_QUEUES; 6076279858Sjfv 6077279858Sjfv code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL); 6078279858Sjfv if (code != I40E_SUCCESS) 6079279858Sjfv return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 6080279858Sjfv 6081279858Sjfv code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL); 6082279858Sjfv if (code != I40E_SUCCESS) { 6083279858Sjfv device_printf(pf->dev, "Failed to disable BW limit: %d\n", 6084279858Sjfv ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 6085279858Sjfv return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); 6086269198Sjfv } 6087269198Sjfv 6088279858Sjfv memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info)); 6089279858Sjfv return (0); 6090279858Sjfv} 6091279858Sjfv 6092279858Sjfvstatic int 6093279858Sjfvixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf) 6094279858Sjfv{ 6095279858Sjfv struct i40e_hw *hw; 6096279858Sjfv int error; 6097279858Sjfv 6098279858Sjfv hw = &pf->hw; 6099279858Sjfv 6100279858Sjfv error = ixl_vf_alloc_vsi(pf, vf); 6101279858Sjfv if (error != 0) 6102269198Sjfv return (error); 6103279858Sjfv 6104279858Sjfv vf->vsi.hw_filters_add = 0; 6105279858Sjfv vf->vsi.hw_filters_del = 0; 6106279858Sjfv ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY); 6107279858Sjfv ixl_reconfigure_filters(&vf->vsi); 6108279858Sjfv 6109279858Sjfv return (0); 6110279858Sjfv} 6111279858Sjfv 6112279858Sjfvstatic void 6113279858Sjfvixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum, 6114279858Sjfv uint32_t val) 6115279858Sjfv{ 6116279858Sjfv uint32_t qtable; 6117279858Sjfv int index, shift; 6118279858Sjfv 6119279858Sjfv /* 6120279858Sjfv * Two queues are mapped in a single register, so we have to do some 6121279858Sjfv * gymnastics to convert the queue number into a register index and 6122279858Sjfv * shift. 6123279858Sjfv */ 6124279858Sjfv index = qnum / 2; 6125279858Sjfv shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT; 6126279858Sjfv 6127299555Serj qtable = i40e_read_rx_ctl(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num)); 6128279858Sjfv qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift); 6129279858Sjfv qtable |= val << shift; 6130299555Serj i40e_write_rx_ctl(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable); 6131279858Sjfv} 6132279858Sjfv 6133279858Sjfvstatic void 6134279858Sjfvixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf) 6135279858Sjfv{ 6136279858Sjfv struct i40e_hw *hw; 6137279858Sjfv uint32_t qtable; 6138279858Sjfv int i; 6139279858Sjfv 6140279858Sjfv hw = &pf->hw; 6141279858Sjfv 6142279858Sjfv /* 6143279858Sjfv * Contiguous mappings aren't actually supported by the hardware, 6144279858Sjfv * so we have to use non-contiguous mappings. 6145279858Sjfv */ 6146299555Serj i40e_write_rx_ctl(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num), 6147279858Sjfv I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK); 6148279858Sjfv 6149279858Sjfv wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num), 6150279858Sjfv I40E_VPLAN_MAPENA_TXRX_ENA_MASK); 6151279858Sjfv 6152279858Sjfv for (i = 0; i < vf->vsi.num_queues; i++) { 6153279858Sjfv qtable = (vf->vsi.first_queue + i) << 6154279858Sjfv I40E_VPLAN_QTABLE_QINDEX_SHIFT; 6155279858Sjfv 6156279858Sjfv wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable); 6157279858Sjfv } 6158279858Sjfv 6159279858Sjfv /* Map queues allocated to VF to its VSI. */ 6160279858Sjfv for (i = 0; i < vf->vsi.num_queues; i++) 6161279858Sjfv ixl_vf_map_vsi_queue(hw, vf, i, vf->vsi.first_queue + i); 6162279858Sjfv 6163279858Sjfv /* Set rest of VSI queues as unused. */ 6164279858Sjfv for (; i < IXL_MAX_VSI_QUEUES; i++) 6165279858Sjfv ixl_vf_map_vsi_queue(hw, vf, i, 6166279858Sjfv I40E_VSILAN_QTABLE_QINDEX_0_MASK); 6167279858Sjfv 6168279858Sjfv ixl_flush(hw); 6169279858Sjfv} 6170279858Sjfv 6171279858Sjfvstatic void 6172279858Sjfvixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi) 6173279858Sjfv{ 6174279858Sjfv struct i40e_hw *hw; 6175279858Sjfv 6176279858Sjfv hw = &pf->hw; 6177279858Sjfv 6178279858Sjfv if (vsi->seid == 0) 6179279858Sjfv return; 6180279858Sjfv 6181279858Sjfv i40e_aq_delete_element(hw, vsi->seid, NULL); 6182279858Sjfv} 6183279858Sjfv 6184279858Sjfvstatic void 6185279858Sjfvixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg) 6186279858Sjfv{ 6187279858Sjfv 6188279858Sjfv wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK); 6189279858Sjfv ixl_flush(hw); 6190279858Sjfv} 6191279858Sjfv 6192279858Sjfvstatic void 6193279858Sjfvixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg) 6194279858Sjfv{ 6195279858Sjfv 6196279858Sjfv wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK | 6197279858Sjfv I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK); 6198279858Sjfv ixl_flush(hw); 6199279858Sjfv} 6200279858Sjfv 6201279858Sjfvstatic void 6202279858Sjfvixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf) 6203279858Sjfv{ 6204279858Sjfv struct i40e_hw *hw; 6205279858Sjfv uint32_t vfint_reg, vpint_reg; 6206279858Sjfv int i; 6207279858Sjfv 6208279858Sjfv hw = &pf->hw; 6209279858Sjfv 6210279858Sjfv ixl_vf_vsi_release(pf, &vf->vsi); 6211279858Sjfv 6212279858Sjfv /* Index 0 has a special register. */ 6213279858Sjfv ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num)); 6214279858Sjfv 6215279858Sjfv for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) { 6216279858Sjfv vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num); 6217279858Sjfv ixl_vf_disable_queue_intr(hw, vfint_reg); 6218279858Sjfv } 6219279858Sjfv 6220279858Sjfv /* Index 0 has a special register. */ 6221279858Sjfv ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num)); 6222279858Sjfv 6223279858Sjfv for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) { 6224279858Sjfv vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num); 6225279858Sjfv ixl_vf_unregister_intr(hw, vpint_reg); 6226279858Sjfv } 6227279858Sjfv 6228279858Sjfv vf->vsi.num_queues = 0; 6229279858Sjfv} 6230279858Sjfv 6231279858Sjfvstatic int 6232279858Sjfvixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf) 6233279858Sjfv{ 6234279858Sjfv struct i40e_hw *hw; 6235279858Sjfv int i; 6236279858Sjfv uint16_t global_vf_num; 6237279858Sjfv uint32_t ciad; 6238279858Sjfv 6239279858Sjfv hw = &pf->hw; 6240279858Sjfv global_vf_num = hw->func_caps.vf_base_id + vf->vf_num; 6241279858Sjfv 6242279858Sjfv wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS | 6243279858Sjfv (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT)); 6244279858Sjfv for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) { 6245279858Sjfv ciad = rd32(hw, I40E_PF_PCI_CIAD); 6246279858Sjfv if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0) 6247279858Sjfv return (0); 6248279858Sjfv DELAY(1); 6249279858Sjfv } 6250279858Sjfv 6251279858Sjfv return (ETIMEDOUT); 6252279858Sjfv} 6253279858Sjfv 6254279858Sjfvstatic void 6255279858Sjfvixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf) 6256279858Sjfv{ 6257279858Sjfv struct i40e_hw *hw; 6258279858Sjfv uint32_t vfrtrig; 6259279858Sjfv 6260279858Sjfv hw = &pf->hw; 6261279858Sjfv 6262279858Sjfv vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); 6263279858Sjfv vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK; 6264279858Sjfv wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); 6265279858Sjfv ixl_flush(hw); 6266279858Sjfv 6267279858Sjfv ixl_reinit_vf(pf, vf); 6268279858Sjfv} 6269279858Sjfv 6270279858Sjfvstatic void 6271279858Sjfvixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf) 6272279858Sjfv{ 6273279858Sjfv struct i40e_hw *hw; 6274279858Sjfv uint32_t vfrstat, vfrtrig; 6275279858Sjfv int i, error; 6276279858Sjfv 6277279858Sjfv hw = &pf->hw; 6278279858Sjfv 6279279858Sjfv error = ixl_flush_pcie(pf, vf); 6280279858Sjfv if (error != 0) 6281279858Sjfv device_printf(pf->dev, 6282279858Sjfv "Timed out waiting for PCIe activity to stop on VF-%d\n", 6283279858Sjfv vf->vf_num); 6284279858Sjfv 6285279858Sjfv for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) { 6286279858Sjfv DELAY(10); 6287279858Sjfv 6288279858Sjfv vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num)); 6289279858Sjfv if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK) 6290279858Sjfv break; 6291279858Sjfv } 6292279858Sjfv 6293279858Sjfv if (i == IXL_VF_RESET_TIMEOUT) 6294279858Sjfv device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num); 6295279858Sjfv 6296279858Sjfv wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_COMPLETED); 6297279858Sjfv 6298279858Sjfv vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); 6299279858Sjfv vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK; 6300279858Sjfv wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); 6301279858Sjfv 6302279858Sjfv if (vf->vsi.seid != 0) 6303279858Sjfv ixl_disable_rings(&vf->vsi); 6304279858Sjfv 6305279858Sjfv ixl_vf_release_resources(pf, vf); 6306279858Sjfv ixl_vf_setup_vsi(pf, vf); 6307279858Sjfv ixl_vf_map_queues(pf, vf); 6308279858Sjfv 6309279858Sjfv wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_VFACTIVE); 6310279858Sjfv ixl_flush(hw); 6311279858Sjfv} 6312279858Sjfv 6313279858Sjfvstatic const char * 6314279858Sjfvixl_vc_opcode_str(uint16_t op) 6315279858Sjfv{ 6316279858Sjfv 6317279858Sjfv switch (op) { 6318279858Sjfv case I40E_VIRTCHNL_OP_VERSION: 6319279858Sjfv return ("VERSION"); 6320279858Sjfv case I40E_VIRTCHNL_OP_RESET_VF: 6321279858Sjfv return ("RESET_VF"); 6322279858Sjfv case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: 6323279858Sjfv return ("GET_VF_RESOURCES"); 6324279858Sjfv case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: 6325279858Sjfv return ("CONFIG_TX_QUEUE"); 6326279858Sjfv case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: 6327279858Sjfv return ("CONFIG_RX_QUEUE"); 6328279858Sjfv case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: 6329279858Sjfv return ("CONFIG_VSI_QUEUES"); 6330279858Sjfv case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: 6331279858Sjfv return ("CONFIG_IRQ_MAP"); 6332279858Sjfv case I40E_VIRTCHNL_OP_ENABLE_QUEUES: 6333279858Sjfv return ("ENABLE_QUEUES"); 6334279858Sjfv case I40E_VIRTCHNL_OP_DISABLE_QUEUES: 6335279858Sjfv return ("DISABLE_QUEUES"); 6336279858Sjfv case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: 6337279858Sjfv return ("ADD_ETHER_ADDRESS"); 6338279858Sjfv case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: 6339279858Sjfv return ("DEL_ETHER_ADDRESS"); 6340279858Sjfv case I40E_VIRTCHNL_OP_ADD_VLAN: 6341279858Sjfv return ("ADD_VLAN"); 6342279858Sjfv case I40E_VIRTCHNL_OP_DEL_VLAN: 6343279858Sjfv return ("DEL_VLAN"); 6344279858Sjfv case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: 6345279858Sjfv return ("CONFIG_PROMISCUOUS_MODE"); 6346279858Sjfv case I40E_VIRTCHNL_OP_GET_STATS: 6347279858Sjfv return ("GET_STATS"); 6348279858Sjfv case I40E_VIRTCHNL_OP_FCOE: 6349279858Sjfv return ("FCOE"); 6350279858Sjfv case I40E_VIRTCHNL_OP_EVENT: 6351279858Sjfv return ("EVENT"); 6352279858Sjfv default: 6353279858Sjfv return ("UNKNOWN"); 6354279858Sjfv } 6355279858Sjfv} 6356279858Sjfv 6357279858Sjfvstatic int 6358279858Sjfvixl_vc_opcode_level(uint16_t opcode) 6359279858Sjfv{ 6360279858Sjfv switch (opcode) { 6361279858Sjfv case I40E_VIRTCHNL_OP_GET_STATS: 6362279858Sjfv return (10); 6363279858Sjfv default: 6364279858Sjfv return (5); 6365279858Sjfv } 6366279858Sjfv} 6367279858Sjfv 6368279858Sjfvstatic void 6369279858Sjfvixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, 6370279858Sjfv enum i40e_status_code status, void *msg, uint16_t len) 6371279858Sjfv{ 6372279858Sjfv struct i40e_hw *hw; 6373279858Sjfv int global_vf_id; 6374279858Sjfv 6375279858Sjfv hw = &pf->hw; 6376279858Sjfv global_vf_id = hw->func_caps.vf_base_id + vf->vf_num; 6377279858Sjfv 6378279858Sjfv I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op), 6379279858Sjfv "Sending msg (op=%s[%d], status=%d) to VF-%d\n", 6380279858Sjfv ixl_vc_opcode_str(op), op, status, vf->vf_num); 6381279858Sjfv 6382279858Sjfv i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL); 6383279858Sjfv} 6384279858Sjfv 6385279858Sjfvstatic void 6386279858Sjfvixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op) 6387279858Sjfv{ 6388279858Sjfv 6389279858Sjfv ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0); 6390279858Sjfv} 6391279858Sjfv 6392279858Sjfvstatic void 6393279858Sjfvixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, 6394279858Sjfv enum i40e_status_code status, const char *file, int line) 6395279858Sjfv{ 6396279858Sjfv 6397279858Sjfv I40E_VC_DEBUG(pf, 1, 6398279858Sjfv "Sending NACK (op=%s[%d], err=%d) to VF-%d from %s:%d\n", 6399279858Sjfv ixl_vc_opcode_str(op), op, status, vf->vf_num, file, line); 6400279858Sjfv ixl_send_vf_msg(pf, vf, op, status, NULL, 0); 6401279858Sjfv} 6402279858Sjfv 6403279858Sjfvstatic void 6404279858Sjfvixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6405279858Sjfv uint16_t msg_size) 6406279858Sjfv{ 6407279858Sjfv struct i40e_virtchnl_version_info reply; 6408279858Sjfv 6409279858Sjfv if (msg_size != sizeof(struct i40e_virtchnl_version_info)) { 6410279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_VERSION, 6411279858Sjfv I40E_ERR_PARAM); 6412279858Sjfv return; 6413279858Sjfv } 6414279858Sjfv 6415299552Serj vf->version = ((struct i40e_virtchnl_version_info *)msg)->minor; 6416299552Serj 6417279858Sjfv reply.major = I40E_VIRTCHNL_VERSION_MAJOR; 6418279858Sjfv reply.minor = I40E_VIRTCHNL_VERSION_MINOR; 6419279858Sjfv ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, &reply, 6420279858Sjfv sizeof(reply)); 6421279858Sjfv} 6422279858Sjfv 6423279858Sjfvstatic void 6424279858Sjfvixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6425279858Sjfv uint16_t msg_size) 6426279858Sjfv{ 6427279858Sjfv 6428279858Sjfv if (msg_size != 0) { 6429279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_RESET_VF, 6430279858Sjfv I40E_ERR_PARAM); 6431279858Sjfv return; 6432279858Sjfv } 6433279858Sjfv 6434279858Sjfv ixl_reset_vf(pf, vf); 6435279858Sjfv 6436279858Sjfv /* No response to a reset message. */ 6437279858Sjfv} 6438279858Sjfv 6439279858Sjfvstatic void 6440279858Sjfvixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6441279858Sjfv uint16_t msg_size) 6442279858Sjfv{ 6443279858Sjfv struct i40e_virtchnl_vf_resource reply; 6444279858Sjfv 6445299552Serj if ((vf->version == 0 && msg_size != 0) || 6446299552Serj (vf->version == 1 && msg_size != 4)) { 6447299552Serj device_printf(pf->dev, "Invalid GET_VF_RESOURCES message size," 6448299552Serj " for VF version %d.%d\n", I40E_VIRTCHNL_VERSION_MAJOR, 6449299552Serj vf->version); 6450279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, 6451279858Sjfv I40E_ERR_PARAM); 6452279858Sjfv return; 6453279858Sjfv } 6454279858Sjfv 6455279858Sjfv bzero(&reply, sizeof(reply)); 6456279858Sjfv 6457299552Serj if (vf->version == I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS) 6458299552Serj reply.vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2 | 6459299552Serj I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | 6460299552Serj I40E_VIRTCHNL_VF_OFFLOAD_VLAN; 6461299552Serj else 6462299552Serj reply.vf_offload_flags = *(u32 *)msg; 6463279858Sjfv 6464279858Sjfv reply.num_vsis = 1; 6465279858Sjfv reply.num_queue_pairs = vf->vsi.num_queues; 6466279858Sjfv reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf; 6467279858Sjfv reply.vsi_res[0].vsi_id = vf->vsi.vsi_num; 6468279858Sjfv reply.vsi_res[0].vsi_type = I40E_VSI_SRIOV; 6469279858Sjfv reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues; 6470279858Sjfv memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN); 6471279858Sjfv 6472279858Sjfv ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, 6473279858Sjfv I40E_SUCCESS, &reply, sizeof(reply)); 6474279858Sjfv} 6475279858Sjfv 6476279858Sjfvstatic int 6477279858Sjfvixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf, 6478279858Sjfv struct i40e_virtchnl_txq_info *info) 6479279858Sjfv{ 6480279858Sjfv struct i40e_hw *hw; 6481279858Sjfv struct i40e_hmc_obj_txq txq; 6482279858Sjfv uint16_t global_queue_num, global_vf_num; 6483279858Sjfv enum i40e_status_code status; 6484279858Sjfv uint32_t qtx_ctl; 6485279858Sjfv 6486279858Sjfv hw = &pf->hw; 6487279858Sjfv global_queue_num = vf->vsi.first_queue + info->queue_id; 6488279858Sjfv global_vf_num = hw->func_caps.vf_base_id + vf->vf_num; 6489279858Sjfv bzero(&txq, sizeof(txq)); 6490279858Sjfv 6491279858Sjfv status = i40e_clear_lan_tx_queue_context(hw, global_queue_num); 6492279858Sjfv if (status != I40E_SUCCESS) 6493269198Sjfv return (EINVAL); 6494279858Sjfv 6495279858Sjfv txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS; 6496279858Sjfv 6497279858Sjfv txq.head_wb_ena = info->headwb_enabled; 6498279858Sjfv txq.head_wb_addr = info->dma_headwb_addr; 6499279858Sjfv txq.qlen = info->ring_len; 6500279858Sjfv txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]); 6501279858Sjfv txq.rdylist_act = 0; 6502279858Sjfv 6503279858Sjfv status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq); 6504279858Sjfv if (status != I40E_SUCCESS) 6505279858Sjfv return (EINVAL); 6506279858Sjfv 6507279858Sjfv qtx_ctl = I40E_QTX_CTL_VF_QUEUE | 6508279858Sjfv (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) | 6509279858Sjfv (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT); 6510279858Sjfv wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl); 6511279858Sjfv ixl_flush(hw); 6512279858Sjfv 6513279858Sjfv return (0); 6514279858Sjfv} 6515279858Sjfv 6516279858Sjfvstatic int 6517279858Sjfvixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf, 6518279858Sjfv struct i40e_virtchnl_rxq_info *info) 6519279858Sjfv{ 6520279858Sjfv struct i40e_hw *hw; 6521279858Sjfv struct i40e_hmc_obj_rxq rxq; 6522279858Sjfv uint16_t global_queue_num; 6523279858Sjfv enum i40e_status_code status; 6524279858Sjfv 6525279858Sjfv hw = &pf->hw; 6526279858Sjfv global_queue_num = vf->vsi.first_queue + info->queue_id; 6527279858Sjfv bzero(&rxq, sizeof(rxq)); 6528279858Sjfv 6529279858Sjfv if (info->databuffer_size > IXL_VF_MAX_BUFFER) 6530279858Sjfv return (EINVAL); 6531279858Sjfv 6532279858Sjfv if (info->max_pkt_size > IXL_VF_MAX_FRAME || 6533279858Sjfv info->max_pkt_size < ETHER_MIN_LEN) 6534279858Sjfv return (EINVAL); 6535279858Sjfv 6536279858Sjfv if (info->splithdr_enabled) { 6537279858Sjfv if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER) 6538279858Sjfv return (EINVAL); 6539279858Sjfv 6540279858Sjfv rxq.hsplit_0 = info->rx_split_pos & 6541279858Sjfv (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 | 6542279858Sjfv I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP | 6543279858Sjfv I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP | 6544279858Sjfv I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP); 6545279858Sjfv rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT; 6546279858Sjfv 6547279858Sjfv rxq.dtype = 2; 6548269198Sjfv } 6549269198Sjfv 6550279858Sjfv status = i40e_clear_lan_rx_queue_context(hw, global_queue_num); 6551279858Sjfv if (status != I40E_SUCCESS) 6552279858Sjfv return (EINVAL); 6553269198Sjfv 6554279858Sjfv rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS; 6555279858Sjfv rxq.qlen = info->ring_len; 6556269198Sjfv 6557279858Sjfv rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT; 6558269198Sjfv 6559279858Sjfv rxq.dsize = 1; 6560279858Sjfv rxq.crcstrip = 1; 6561279858Sjfv rxq.l2tsel = 1; 6562269198Sjfv 6563279858Sjfv rxq.rxmax = info->max_pkt_size; 6564279858Sjfv rxq.tphrdesc_ena = 1; 6565279858Sjfv rxq.tphwdesc_ena = 1; 6566279858Sjfv rxq.tphdata_ena = 1; 6567279858Sjfv rxq.tphhead_ena = 1; 6568279858Sjfv rxq.lrxqthresh = 2; 6569279858Sjfv rxq.prefena = 1; 6570279858Sjfv 6571279858Sjfv status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq); 6572279858Sjfv if (status != I40E_SUCCESS) 6573279858Sjfv return (EINVAL); 6574279858Sjfv 6575279858Sjfv return (0); 6576279858Sjfv} 6577279858Sjfv 6578279858Sjfvstatic void 6579279858Sjfvixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6580279858Sjfv uint16_t msg_size) 6581279858Sjfv{ 6582279858Sjfv struct i40e_virtchnl_vsi_queue_config_info *info; 6583279858Sjfv struct i40e_virtchnl_queue_pair_info *pair; 6584279858Sjfv int i; 6585279858Sjfv 6586279858Sjfv if (msg_size < sizeof(*info)) { 6587279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 6588279858Sjfv I40E_ERR_PARAM); 6589279858Sjfv return; 6590279858Sjfv } 6591279858Sjfv 6592279858Sjfv info = msg; 6593279858Sjfv if (info->num_queue_pairs == 0) { 6594279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 6595279858Sjfv I40E_ERR_PARAM); 6596279858Sjfv return; 6597279858Sjfv } 6598279858Sjfv 6599279858Sjfv if (msg_size != sizeof(*info) + info->num_queue_pairs * sizeof(*pair)) { 6600279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 6601279858Sjfv I40E_ERR_PARAM); 6602279858Sjfv return; 6603279858Sjfv } 6604279858Sjfv 6605279858Sjfv if (info->vsi_id != vf->vsi.vsi_num) { 6606279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, 6607279858Sjfv I40E_ERR_PARAM); 6608279858Sjfv return; 6609279858Sjfv } 6610279858Sjfv 6611279858Sjfv for (i = 0; i < info->num_queue_pairs; i++) { 6612279858Sjfv pair = &info->qpair[i]; 6613279858Sjfv 6614279858Sjfv if (pair->txq.vsi_id != vf->vsi.vsi_num || 6615279858Sjfv pair->rxq.vsi_id != vf->vsi.vsi_num || 6616279858Sjfv pair->txq.queue_id != pair->rxq.queue_id || 6617279858Sjfv pair->txq.queue_id >= vf->vsi.num_queues) { 6618279858Sjfv 6619279858Sjfv i40e_send_vf_nack(pf, vf, 6620279858Sjfv I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 6621279858Sjfv return; 6622279858Sjfv } 6623279858Sjfv 6624279858Sjfv if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) { 6625279858Sjfv i40e_send_vf_nack(pf, vf, 6626279858Sjfv I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 6627279858Sjfv return; 6628279858Sjfv } 6629279858Sjfv 6630279858Sjfv if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) { 6631279858Sjfv i40e_send_vf_nack(pf, vf, 6632279858Sjfv I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); 6633279858Sjfv return; 6634279858Sjfv } 6635279858Sjfv } 6636279858Sjfv 6637279858Sjfv ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES); 6638279858Sjfv} 6639279858Sjfv 6640279858Sjfvstatic void 6641279858Sjfvixl_vf_set_qctl(struct ixl_pf *pf, 6642279858Sjfv const struct i40e_virtchnl_vector_map *vector, 6643279858Sjfv enum i40e_queue_type cur_type, uint16_t cur_queue, 6644279858Sjfv enum i40e_queue_type *last_type, uint16_t *last_queue) 6645279858Sjfv{ 6646279858Sjfv uint32_t offset, qctl; 6647279858Sjfv uint16_t itr_indx; 6648279858Sjfv 6649279858Sjfv if (cur_type == I40E_QUEUE_TYPE_RX) { 6650279858Sjfv offset = I40E_QINT_RQCTL(cur_queue); 6651279858Sjfv itr_indx = vector->rxitr_idx; 6652279858Sjfv } else { 6653279858Sjfv offset = I40E_QINT_TQCTL(cur_queue); 6654279858Sjfv itr_indx = vector->txitr_idx; 6655279858Sjfv } 6656279858Sjfv 6657279858Sjfv qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 6658279858Sjfv (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) | 6659279858Sjfv (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 6660279858Sjfv I40E_QINT_RQCTL_CAUSE_ENA_MASK | 6661279858Sjfv (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT)); 6662279858Sjfv 6663279858Sjfv wr32(&pf->hw, offset, qctl); 6664279858Sjfv 6665279858Sjfv *last_type = cur_type; 6666279858Sjfv *last_queue = cur_queue; 6667279858Sjfv} 6668279858Sjfv 6669279858Sjfvstatic void 6670279858Sjfvixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf, 6671279858Sjfv const struct i40e_virtchnl_vector_map *vector) 6672279858Sjfv{ 6673279858Sjfv struct i40e_hw *hw; 6674279858Sjfv u_int qindex; 6675279858Sjfv enum i40e_queue_type type, last_type; 6676279858Sjfv uint32_t lnklst_reg; 6677279858Sjfv uint16_t rxq_map, txq_map, cur_queue, last_queue; 6678279858Sjfv 6679279858Sjfv hw = &pf->hw; 6680279858Sjfv 6681279858Sjfv rxq_map = vector->rxq_map; 6682279858Sjfv txq_map = vector->txq_map; 6683279858Sjfv 6684279858Sjfv last_queue = IXL_END_OF_INTR_LNKLST; 6685279858Sjfv last_type = I40E_QUEUE_TYPE_RX; 6686279858Sjfv 6687279858Sjfv /* 6688279858Sjfv * The datasheet says to optimize performance, RX queues and TX queues 6689279858Sjfv * should be interleaved in the interrupt linked list, so we process 6690279858Sjfv * both at once here. 6691279858Sjfv */ 6692279858Sjfv while ((rxq_map != 0) || (txq_map != 0)) { 6693279858Sjfv if (txq_map != 0) { 6694279858Sjfv qindex = ffs(txq_map) - 1; 6695279858Sjfv type = I40E_QUEUE_TYPE_TX; 6696279858Sjfv cur_queue = vf->vsi.first_queue + qindex; 6697279858Sjfv ixl_vf_set_qctl(pf, vector, type, cur_queue, 6698279858Sjfv &last_type, &last_queue); 6699279858Sjfv txq_map &= ~(1 << qindex); 6700279858Sjfv } 6701279858Sjfv 6702279858Sjfv if (rxq_map != 0) { 6703279858Sjfv qindex = ffs(rxq_map) - 1; 6704279858Sjfv type = I40E_QUEUE_TYPE_RX; 6705279858Sjfv cur_queue = vf->vsi.first_queue + qindex; 6706279858Sjfv ixl_vf_set_qctl(pf, vector, type, cur_queue, 6707279858Sjfv &last_type, &last_queue); 6708279858Sjfv rxq_map &= ~(1 << qindex); 6709279858Sjfv } 6710279858Sjfv } 6711279858Sjfv 6712279858Sjfv if (vector->vector_id == 0) 6713279858Sjfv lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num); 6714279858Sjfv else 6715279858Sjfv lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id, 6716279858Sjfv vf->vf_num); 6717279858Sjfv wr32(hw, lnklst_reg, 6718279858Sjfv (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) | 6719279858Sjfv (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT)); 6720279858Sjfv 6721279858Sjfv ixl_flush(hw); 6722279858Sjfv} 6723279858Sjfv 6724279858Sjfvstatic void 6725279858Sjfvixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6726279858Sjfv uint16_t msg_size) 6727279858Sjfv{ 6728279858Sjfv struct i40e_virtchnl_irq_map_info *map; 6729279858Sjfv struct i40e_virtchnl_vector_map *vector; 6730279858Sjfv struct i40e_hw *hw; 6731279858Sjfv int i, largest_txq, largest_rxq; 6732279858Sjfv 6733279858Sjfv hw = &pf->hw; 6734279858Sjfv 6735279858Sjfv if (msg_size < sizeof(*map)) { 6736279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 6737279858Sjfv I40E_ERR_PARAM); 6738279858Sjfv return; 6739279858Sjfv } 6740279858Sjfv 6741279858Sjfv map = msg; 6742279858Sjfv if (map->num_vectors == 0) { 6743279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 6744279858Sjfv I40E_ERR_PARAM); 6745279858Sjfv return; 6746279858Sjfv } 6747279858Sjfv 6748279858Sjfv if (msg_size != sizeof(*map) + map->num_vectors * sizeof(*vector)) { 6749279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 6750279858Sjfv I40E_ERR_PARAM); 6751279858Sjfv return; 6752279858Sjfv } 6753279858Sjfv 6754279858Sjfv for (i = 0; i < map->num_vectors; i++) { 6755279858Sjfv vector = &map->vecmap[i]; 6756279858Sjfv 6757279858Sjfv if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) || 6758279858Sjfv vector->vsi_id != vf->vsi.vsi_num) { 6759279858Sjfv i40e_send_vf_nack(pf, vf, 6760279858Sjfv I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM); 6761279858Sjfv return; 6762279858Sjfv } 6763279858Sjfv 6764279858Sjfv if (vector->rxq_map != 0) { 6765279858Sjfv largest_rxq = fls(vector->rxq_map) - 1; 6766279858Sjfv if (largest_rxq >= vf->vsi.num_queues) { 6767279858Sjfv i40e_send_vf_nack(pf, vf, 6768279858Sjfv I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 6769279858Sjfv I40E_ERR_PARAM); 6770279858Sjfv return; 6771279858Sjfv } 6772279858Sjfv } 6773279858Sjfv 6774279858Sjfv if (vector->txq_map != 0) { 6775279858Sjfv largest_txq = fls(vector->txq_map) - 1; 6776279858Sjfv if (largest_txq >= vf->vsi.num_queues) { 6777279858Sjfv i40e_send_vf_nack(pf, vf, 6778279858Sjfv I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 6779279858Sjfv I40E_ERR_PARAM); 6780279858Sjfv return; 6781279858Sjfv } 6782279858Sjfv } 6783279858Sjfv 6784279858Sjfv if (vector->rxitr_idx > IXL_MAX_ITR_IDX || 6785279858Sjfv vector->txitr_idx > IXL_MAX_ITR_IDX) { 6786279858Sjfv i40e_send_vf_nack(pf, vf, 6787279858Sjfv I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, 6788279858Sjfv I40E_ERR_PARAM); 6789279858Sjfv return; 6790279858Sjfv } 6791279858Sjfv 6792279858Sjfv ixl_vf_config_vector(pf, vf, vector); 6793279858Sjfv } 6794279858Sjfv 6795279858Sjfv ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP); 6796279858Sjfv} 6797279858Sjfv 6798279858Sjfvstatic void 6799279858Sjfvixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6800279858Sjfv uint16_t msg_size) 6801279858Sjfv{ 6802279858Sjfv struct i40e_virtchnl_queue_select *select; 6803279858Sjfv int error; 6804279858Sjfv 6805279858Sjfv if (msg_size != sizeof(*select)) { 6806279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 6807279858Sjfv I40E_ERR_PARAM); 6808279858Sjfv return; 6809279858Sjfv } 6810279858Sjfv 6811279858Sjfv select = msg; 6812279858Sjfv if (select->vsi_id != vf->vsi.vsi_num || 6813279858Sjfv select->rx_queues == 0 || select->tx_queues == 0) { 6814279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 6815279858Sjfv I40E_ERR_PARAM); 6816279858Sjfv return; 6817279858Sjfv } 6818279858Sjfv 6819279858Sjfv error = ixl_enable_rings(&vf->vsi); 6820269198Sjfv if (error) { 6821279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, 6822279858Sjfv I40E_ERR_TIMEOUT); 6823279858Sjfv return; 6824269198Sjfv } 6825269198Sjfv 6826279858Sjfv ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES); 6827269198Sjfv} 6828266423Sjfv 6829279858Sjfvstatic void 6830279858Sjfvixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, 6831279858Sjfv void *msg, uint16_t msg_size) 6832279858Sjfv{ 6833279858Sjfv struct i40e_virtchnl_queue_select *select; 6834279858Sjfv int error; 6835279858Sjfv 6836279858Sjfv if (msg_size != sizeof(*select)) { 6837279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 6838279858Sjfv I40E_ERR_PARAM); 6839279858Sjfv return; 6840279858Sjfv } 6841279858Sjfv 6842279858Sjfv select = msg; 6843279858Sjfv if (select->vsi_id != vf->vsi.vsi_num || 6844279858Sjfv select->rx_queues == 0 || select->tx_queues == 0) { 6845279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 6846279858Sjfv I40E_ERR_PARAM); 6847279858Sjfv return; 6848279858Sjfv } 6849279858Sjfv 6850279858Sjfv error = ixl_disable_rings(&vf->vsi); 6851279858Sjfv if (error) { 6852279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, 6853279858Sjfv I40E_ERR_TIMEOUT); 6854279858Sjfv return; 6855279858Sjfv } 6856279858Sjfv 6857279858Sjfv ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES); 6858279858Sjfv} 6859279858Sjfv 6860279858Sjfvstatic boolean_t 6861279858Sjfvixl_zero_mac(const uint8_t *addr) 6862279858Sjfv{ 6863279858Sjfv uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0}; 6864279858Sjfv 6865279858Sjfv return (cmp_etheraddr(addr, zero)); 6866279858Sjfv} 6867279858Sjfv 6868279858Sjfvstatic boolean_t 6869279858Sjfvixl_bcast_mac(const uint8_t *addr) 6870279858Sjfv{ 6871279858Sjfv 6872279858Sjfv return (cmp_etheraddr(addr, ixl_bcast_addr)); 6873279858Sjfv} 6874279858Sjfv 6875279858Sjfvstatic int 6876279858Sjfvixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr) 6877279858Sjfv{ 6878279858Sjfv 6879279858Sjfv if (ixl_zero_mac(addr) || ixl_bcast_mac(addr)) 6880279858Sjfv return (EINVAL); 6881279858Sjfv 6882279858Sjfv /* 6883279858Sjfv * If the VF is not allowed to change its MAC address, don't let it 6884279858Sjfv * set a MAC filter for an address that is not a multicast address and 6885279858Sjfv * is not its assigned MAC. 6886279858Sjfv */ 6887279858Sjfv if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) && 6888279858Sjfv !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac))) 6889279858Sjfv return (EPERM); 6890279858Sjfv 6891279858Sjfv return (0); 6892279858Sjfv} 6893279858Sjfv 6894279858Sjfvstatic void 6895279858Sjfvixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6896279858Sjfv uint16_t msg_size) 6897279858Sjfv{ 6898279858Sjfv struct i40e_virtchnl_ether_addr_list *addr_list; 6899279858Sjfv struct i40e_virtchnl_ether_addr *addr; 6900279858Sjfv struct ixl_vsi *vsi; 6901279858Sjfv int i; 6902279858Sjfv size_t expected_size; 6903279858Sjfv 6904279858Sjfv vsi = &vf->vsi; 6905279858Sjfv 6906279858Sjfv if (msg_size < sizeof(*addr_list)) { 6907279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 6908279858Sjfv I40E_ERR_PARAM); 6909279858Sjfv return; 6910279858Sjfv } 6911279858Sjfv 6912279858Sjfv addr_list = msg; 6913279858Sjfv expected_size = sizeof(*addr_list) + 6914279858Sjfv addr_list->num_elements * sizeof(*addr); 6915279858Sjfv 6916279858Sjfv if (addr_list->num_elements == 0 || 6917279858Sjfv addr_list->vsi_id != vsi->vsi_num || 6918279858Sjfv msg_size != expected_size) { 6919279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 6920279858Sjfv I40E_ERR_PARAM); 6921279858Sjfv return; 6922279858Sjfv } 6923279858Sjfv 6924279858Sjfv for (i = 0; i < addr_list->num_elements; i++) { 6925279858Sjfv if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) { 6926279858Sjfv i40e_send_vf_nack(pf, vf, 6927279858Sjfv I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM); 6928279858Sjfv return; 6929279858Sjfv } 6930279858Sjfv } 6931279858Sjfv 6932279858Sjfv for (i = 0; i < addr_list->num_elements; i++) { 6933279858Sjfv addr = &addr_list->list[i]; 6934279858Sjfv ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY); 6935279858Sjfv } 6936279858Sjfv 6937279858Sjfv ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS); 6938279858Sjfv} 6939279858Sjfv 6940279858Sjfvstatic void 6941279858Sjfvixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 6942279858Sjfv uint16_t msg_size) 6943279858Sjfv{ 6944279858Sjfv struct i40e_virtchnl_ether_addr_list *addr_list; 6945279858Sjfv struct i40e_virtchnl_ether_addr *addr; 6946279858Sjfv size_t expected_size; 6947279858Sjfv int i; 6948279858Sjfv 6949279858Sjfv if (msg_size < sizeof(*addr_list)) { 6950279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 6951279858Sjfv I40E_ERR_PARAM); 6952279858Sjfv return; 6953279858Sjfv } 6954279858Sjfv 6955279858Sjfv addr_list = msg; 6956279858Sjfv expected_size = sizeof(*addr_list) + 6957279858Sjfv addr_list->num_elements * sizeof(*addr); 6958279858Sjfv 6959279858Sjfv if (addr_list->num_elements == 0 || 6960279858Sjfv addr_list->vsi_id != vf->vsi.vsi_num || 6961279858Sjfv msg_size != expected_size) { 6962279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, 6963279858Sjfv I40E_ERR_PARAM); 6964279858Sjfv return; 6965279858Sjfv } 6966279858Sjfv 6967279858Sjfv for (i = 0; i < addr_list->num_elements; i++) { 6968279858Sjfv addr = &addr_list->list[i]; 6969279858Sjfv if (ixl_zero_mac(addr->addr) || ixl_bcast_mac(addr->addr)) { 6970279858Sjfv i40e_send_vf_nack(pf, vf, 6971279858Sjfv I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM); 6972279858Sjfv return; 6973279858Sjfv } 6974279858Sjfv } 6975279858Sjfv 6976279858Sjfv for (i = 0; i < addr_list->num_elements; i++) { 6977279858Sjfv addr = &addr_list->list[i]; 6978279858Sjfv ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY); 6979279858Sjfv } 6980279858Sjfv 6981279858Sjfv ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS); 6982279858Sjfv} 6983279858Sjfv 6984279858Sjfvstatic enum i40e_status_code 6985279858Sjfvixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf) 6986279858Sjfv{ 6987279858Sjfv struct i40e_vsi_context vsi_ctx; 6988279858Sjfv 6989279858Sjfv vsi_ctx.seid = vf->vsi.seid; 6990279858Sjfv 6991279858Sjfv bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); 6992279858Sjfv vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID); 6993279858Sjfv vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 6994279858Sjfv I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 6995279858Sjfv return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL)); 6996279858Sjfv} 6997279858Sjfv 6998279858Sjfvstatic void 6999279858Sjfvixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 7000279858Sjfv uint16_t msg_size) 7001279858Sjfv{ 7002279858Sjfv struct i40e_virtchnl_vlan_filter_list *filter_list; 7003279858Sjfv enum i40e_status_code code; 7004279858Sjfv size_t expected_size; 7005279858Sjfv int i; 7006279858Sjfv 7007279858Sjfv if (msg_size < sizeof(*filter_list)) { 7008279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 7009279858Sjfv I40E_ERR_PARAM); 7010279858Sjfv return; 7011279858Sjfv } 7012279858Sjfv 7013279858Sjfv filter_list = msg; 7014279858Sjfv expected_size = sizeof(*filter_list) + 7015279858Sjfv filter_list->num_elements * sizeof(uint16_t); 7016279858Sjfv if (filter_list->num_elements == 0 || 7017279858Sjfv filter_list->vsi_id != vf->vsi.vsi_num || 7018279858Sjfv msg_size != expected_size) { 7019279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 7020279858Sjfv I40E_ERR_PARAM); 7021279858Sjfv return; 7022279858Sjfv } 7023279858Sjfv 7024279858Sjfv if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) { 7025279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 7026279858Sjfv I40E_ERR_PARAM); 7027279858Sjfv return; 7028279858Sjfv } 7029279858Sjfv 7030279858Sjfv for (i = 0; i < filter_list->num_elements; i++) { 7031279858Sjfv if (filter_list->vlan_id[i] > EVL_VLID_MASK) { 7032279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 7033279858Sjfv I40E_ERR_PARAM); 7034279858Sjfv return; 7035279858Sjfv } 7036279858Sjfv } 7037279858Sjfv 7038279858Sjfv code = ixl_vf_enable_vlan_strip(pf, vf); 7039279858Sjfv if (code != I40E_SUCCESS) { 7040279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 7041279858Sjfv I40E_ERR_PARAM); 7042279858Sjfv } 7043279858Sjfv 7044279858Sjfv for (i = 0; i < filter_list->num_elements; i++) 7045279858Sjfv ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]); 7046279858Sjfv 7047279858Sjfv ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN); 7048279858Sjfv} 7049279858Sjfv 7050279858Sjfvstatic void 7051279858Sjfvixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 7052279858Sjfv uint16_t msg_size) 7053279858Sjfv{ 7054279858Sjfv struct i40e_virtchnl_vlan_filter_list *filter_list; 7055279858Sjfv int i; 7056279858Sjfv size_t expected_size; 7057279858Sjfv 7058279858Sjfv if (msg_size < sizeof(*filter_list)) { 7059279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN, 7060279858Sjfv I40E_ERR_PARAM); 7061279858Sjfv return; 7062279858Sjfv } 7063279858Sjfv 7064279858Sjfv filter_list = msg; 7065279858Sjfv expected_size = sizeof(*filter_list) + 7066279858Sjfv filter_list->num_elements * sizeof(uint16_t); 7067279858Sjfv if (filter_list->num_elements == 0 || 7068279858Sjfv filter_list->vsi_id != vf->vsi.vsi_num || 7069279858Sjfv msg_size != expected_size) { 7070279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN, 7071279858Sjfv I40E_ERR_PARAM); 7072279858Sjfv return; 7073279858Sjfv } 7074279858Sjfv 7075279858Sjfv for (i = 0; i < filter_list->num_elements; i++) { 7076279858Sjfv if (filter_list->vlan_id[i] > EVL_VLID_MASK) { 7077279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 7078279858Sjfv I40E_ERR_PARAM); 7079279858Sjfv return; 7080279858Sjfv } 7081279858Sjfv } 7082279858Sjfv 7083279858Sjfv if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) { 7084279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN, 7085279858Sjfv I40E_ERR_PARAM); 7086279858Sjfv return; 7087279858Sjfv } 7088279858Sjfv 7089279858Sjfv for (i = 0; i < filter_list->num_elements; i++) 7090279858Sjfv ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]); 7091279858Sjfv 7092279858Sjfv ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN); 7093279858Sjfv} 7094279858Sjfv 7095279858Sjfvstatic void 7096279858Sjfvixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, 7097279858Sjfv void *msg, uint16_t msg_size) 7098279858Sjfv{ 7099279858Sjfv struct i40e_virtchnl_promisc_info *info; 7100279858Sjfv enum i40e_status_code code; 7101279858Sjfv 7102279858Sjfv if (msg_size != sizeof(*info)) { 7103279858Sjfv i40e_send_vf_nack(pf, vf, 7104279858Sjfv I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 7105279858Sjfv return; 7106279858Sjfv } 7107279858Sjfv 7108295787Skevlo if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) { 7109279858Sjfv i40e_send_vf_nack(pf, vf, 7110279858Sjfv I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 7111279858Sjfv return; 7112279858Sjfv } 7113279858Sjfv 7114279858Sjfv info = msg; 7115279858Sjfv if (info->vsi_id != vf->vsi.vsi_num) { 7116279858Sjfv i40e_send_vf_nack(pf, vf, 7117279858Sjfv I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); 7118279858Sjfv return; 7119279858Sjfv } 7120279858Sjfv 7121279858Sjfv code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id, 7122279858Sjfv info->flags & I40E_FLAG_VF_UNICAST_PROMISC, NULL); 7123279858Sjfv if (code != I40E_SUCCESS) { 7124279858Sjfv i40e_send_vf_nack(pf, vf, 7125279858Sjfv I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); 7126279858Sjfv return; 7127279858Sjfv } 7128279858Sjfv 7129279858Sjfv code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id, 7130279858Sjfv info->flags & I40E_FLAG_VF_MULTICAST_PROMISC, NULL); 7131279858Sjfv if (code != I40E_SUCCESS) { 7132279858Sjfv i40e_send_vf_nack(pf, vf, 7133279858Sjfv I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); 7134279858Sjfv return; 7135279858Sjfv } 7136279858Sjfv 7137279858Sjfv ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE); 7138279858Sjfv} 7139279858Sjfv 7140279858Sjfvstatic void 7141279858Sjfvixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, 7142279858Sjfv uint16_t msg_size) 7143279858Sjfv{ 7144279858Sjfv struct i40e_virtchnl_queue_select *queue; 7145279858Sjfv 7146279858Sjfv if (msg_size != sizeof(*queue)) { 7147279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 7148279858Sjfv I40E_ERR_PARAM); 7149279858Sjfv return; 7150279858Sjfv } 7151279858Sjfv 7152279858Sjfv queue = msg; 7153279858Sjfv if (queue->vsi_id != vf->vsi.vsi_num) { 7154279858Sjfv i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 7155279858Sjfv I40E_ERR_PARAM); 7156279858Sjfv return; 7157279858Sjfv } 7158279858Sjfv 7159279858Sjfv ixl_update_eth_stats(&vf->vsi); 7160279858Sjfv 7161279858Sjfv ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_STATS, 7162279858Sjfv I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats)); 7163279858Sjfv} 7164279858Sjfv 7165279858Sjfvstatic void 7166279858Sjfvixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event) 7167279858Sjfv{ 7168279858Sjfv struct ixl_vf *vf; 7169279858Sjfv void *msg; 7170279858Sjfv uint16_t vf_num, msg_size; 7171279858Sjfv uint32_t opcode; 7172279858Sjfv 7173279858Sjfv vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id; 7174279858Sjfv opcode = le32toh(event->desc.cookie_high); 7175279858Sjfv 7176279858Sjfv if (vf_num >= pf->num_vfs) { 7177279858Sjfv device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num); 7178279858Sjfv return; 7179279858Sjfv } 7180279858Sjfv 7181279858Sjfv vf = &pf->vfs[vf_num]; 7182279858Sjfv msg = event->msg_buf; 7183279858Sjfv msg_size = event->msg_len; 7184279858Sjfv 7185279858Sjfv I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode), 7186279858Sjfv "Got msg %s(%d) from VF-%d of size %d\n", 7187279858Sjfv ixl_vc_opcode_str(opcode), opcode, vf_num, msg_size); 7188279858Sjfv 7189279858Sjfv switch (opcode) { 7190279858Sjfv case I40E_VIRTCHNL_OP_VERSION: 7191279858Sjfv ixl_vf_version_msg(pf, vf, msg, msg_size); 7192279858Sjfv break; 7193279858Sjfv case I40E_VIRTCHNL_OP_RESET_VF: 7194279858Sjfv ixl_vf_reset_msg(pf, vf, msg, msg_size); 7195279858Sjfv break; 7196279858Sjfv case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: 7197279858Sjfv ixl_vf_get_resources_msg(pf, vf, msg, msg_size); 7198279858Sjfv break; 7199279858Sjfv case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: 7200279858Sjfv ixl_vf_config_vsi_msg(pf, vf, msg, msg_size); 7201279858Sjfv break; 7202279858Sjfv case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: 7203279858Sjfv ixl_vf_config_irq_msg(pf, vf, msg, msg_size); 7204279858Sjfv break; 7205279858Sjfv case I40E_VIRTCHNL_OP_ENABLE_QUEUES: 7206279858Sjfv ixl_vf_enable_queues_msg(pf, vf, msg, msg_size); 7207279858Sjfv break; 7208279858Sjfv case I40E_VIRTCHNL_OP_DISABLE_QUEUES: 7209279858Sjfv ixl_vf_disable_queues_msg(pf, vf, msg, msg_size); 7210279858Sjfv break; 7211279858Sjfv case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: 7212279858Sjfv ixl_vf_add_mac_msg(pf, vf, msg, msg_size); 7213279858Sjfv break; 7214279858Sjfv case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: 7215279858Sjfv ixl_vf_del_mac_msg(pf, vf, msg, msg_size); 7216279858Sjfv break; 7217279858Sjfv case I40E_VIRTCHNL_OP_ADD_VLAN: 7218279858Sjfv ixl_vf_add_vlan_msg(pf, vf, msg, msg_size); 7219279858Sjfv break; 7220279858Sjfv case I40E_VIRTCHNL_OP_DEL_VLAN: 7221279858Sjfv ixl_vf_del_vlan_msg(pf, vf, msg, msg_size); 7222279858Sjfv break; 7223279858Sjfv case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: 7224279858Sjfv ixl_vf_config_promisc_msg(pf, vf, msg, msg_size); 7225279858Sjfv break; 7226279858Sjfv case I40E_VIRTCHNL_OP_GET_STATS: 7227279858Sjfv ixl_vf_get_stats_msg(pf, vf, msg, msg_size); 7228279858Sjfv break; 7229279858Sjfv 7230279858Sjfv /* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */ 7231279858Sjfv case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: 7232279858Sjfv case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: 7233279858Sjfv default: 7234279858Sjfv i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED); 7235279858Sjfv break; 7236279858Sjfv } 7237279858Sjfv} 7238279858Sjfv 7239279858Sjfv/* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */ 7240279858Sjfvstatic void 7241279858Sjfvixl_handle_vflr(void *arg, int pending) 7242279858Sjfv{ 7243279858Sjfv struct ixl_pf *pf; 7244279858Sjfv struct i40e_hw *hw; 7245279858Sjfv uint16_t global_vf_num; 7246279858Sjfv uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0; 7247279858Sjfv int i; 7248279858Sjfv 7249279858Sjfv pf = arg; 7250279858Sjfv hw = &pf->hw; 7251279858Sjfv 7252279858Sjfv IXL_PF_LOCK(pf); 7253279858Sjfv for (i = 0; i < pf->num_vfs; i++) { 7254279858Sjfv global_vf_num = hw->func_caps.vf_base_id + i; 7255279858Sjfv 7256279858Sjfv vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num); 7257279858Sjfv vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num); 7258279858Sjfv vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index)); 7259279858Sjfv if (vflrstat & vflrstat_mask) { 7260279858Sjfv wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index), 7261279858Sjfv vflrstat_mask); 7262279858Sjfv 7263279858Sjfv ixl_reinit_vf(pf, &pf->vfs[i]); 7264279858Sjfv } 7265279858Sjfv } 7266279858Sjfv 7267279858Sjfv icr0 = rd32(hw, I40E_PFINT_ICR0_ENA); 7268279858Sjfv icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK; 7269279858Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, icr0); 7270279858Sjfv ixl_flush(hw); 7271279858Sjfv 7272279858Sjfv IXL_PF_UNLOCK(pf); 7273279858Sjfv} 7274279858Sjfv 7275279858Sjfvstatic int 7276279858Sjfvixl_adminq_err_to_errno(enum i40e_admin_queue_err err) 7277279858Sjfv{ 7278279858Sjfv 7279279858Sjfv switch (err) { 7280279858Sjfv case I40E_AQ_RC_EPERM: 7281279858Sjfv return (EPERM); 7282279858Sjfv case I40E_AQ_RC_ENOENT: 7283279858Sjfv return (ENOENT); 7284279858Sjfv case I40E_AQ_RC_ESRCH: 7285279858Sjfv return (ESRCH); 7286279858Sjfv case I40E_AQ_RC_EINTR: 7287279858Sjfv return (EINTR); 7288279858Sjfv case I40E_AQ_RC_EIO: 7289279858Sjfv return (EIO); 7290279858Sjfv case I40E_AQ_RC_ENXIO: 7291279858Sjfv return (ENXIO); 7292279858Sjfv case I40E_AQ_RC_E2BIG: 7293279858Sjfv return (E2BIG); 7294279858Sjfv case I40E_AQ_RC_EAGAIN: 7295279858Sjfv return (EAGAIN); 7296279858Sjfv case I40E_AQ_RC_ENOMEM: 7297279858Sjfv return (ENOMEM); 7298279858Sjfv case I40E_AQ_RC_EACCES: 7299279858Sjfv return (EACCES); 7300279858Sjfv case I40E_AQ_RC_EFAULT: 7301279858Sjfv return (EFAULT); 7302279858Sjfv case I40E_AQ_RC_EBUSY: 7303279858Sjfv return (EBUSY); 7304279858Sjfv case I40E_AQ_RC_EEXIST: 7305279858Sjfv return (EEXIST); 7306279858Sjfv case I40E_AQ_RC_EINVAL: 7307279858Sjfv return (EINVAL); 7308279858Sjfv case I40E_AQ_RC_ENOTTY: 7309279858Sjfv return (ENOTTY); 7310279858Sjfv case I40E_AQ_RC_ENOSPC: 7311279858Sjfv return (ENOSPC); 7312279858Sjfv case I40E_AQ_RC_ENOSYS: 7313279858Sjfv return (ENOSYS); 7314279858Sjfv case I40E_AQ_RC_ERANGE: 7315279858Sjfv return (ERANGE); 7316279858Sjfv case I40E_AQ_RC_EFLUSHED: 7317279858Sjfv return (EINVAL); /* No exact equivalent in errno.h */ 7318279858Sjfv case I40E_AQ_RC_BAD_ADDR: 7319279858Sjfv return (EFAULT); 7320279858Sjfv case I40E_AQ_RC_EMODE: 7321279858Sjfv return (EPERM); 7322279858Sjfv case I40E_AQ_RC_EFBIG: 7323279858Sjfv return (EFBIG); 7324279858Sjfv default: 7325279858Sjfv return (EINVAL); 7326279858Sjfv } 7327279858Sjfv} 7328279858Sjfv 7329279858Sjfvstatic int 7330299546Serjixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params) 7331279858Sjfv{ 7332279858Sjfv struct ixl_pf *pf; 7333279858Sjfv struct i40e_hw *hw; 7334279858Sjfv struct ixl_vsi *pf_vsi; 7335279858Sjfv enum i40e_status_code ret; 7336279858Sjfv int i, error; 7337279858Sjfv 7338279858Sjfv pf = device_get_softc(dev); 7339279858Sjfv hw = &pf->hw; 7340279858Sjfv pf_vsi = &pf->vsi; 7341279858Sjfv 7342279858Sjfv IXL_PF_LOCK(pf); 7343279858Sjfv pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT | 7344279858Sjfv M_ZERO); 7345279858Sjfv 7346279858Sjfv if (pf->vfs == NULL) { 7347279858Sjfv error = ENOMEM; 7348279858Sjfv goto fail; 7349279858Sjfv } 7350279858Sjfv 7351279858Sjfv for (i = 0; i < num_vfs; i++) 7352279858Sjfv sysctl_ctx_init(&pf->vfs[i].ctx); 7353279858Sjfv 7354279858Sjfv ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid, 7355299552Serj 1, FALSE, &pf->veb_seid, FALSE, NULL); 7356279858Sjfv if (ret != I40E_SUCCESS) { 7357279858Sjfv error = ixl_adminq_err_to_errno(hw->aq.asq_last_status); 7358279858Sjfv device_printf(dev, "add_veb failed; code=%d error=%d", ret, 7359279858Sjfv error); 7360279858Sjfv goto fail; 7361279858Sjfv } 7362279858Sjfv 7363299553Serj // TODO: [Configure MSI-X here] 7364279858Sjfv ixl_enable_adminq(hw); 7365279858Sjfv 7366279858Sjfv pf->num_vfs = num_vfs; 7367279858Sjfv IXL_PF_UNLOCK(pf); 7368279858Sjfv return (0); 7369279858Sjfv 7370279858Sjfvfail: 7371279858Sjfv free(pf->vfs, M_IXL); 7372279858Sjfv pf->vfs = NULL; 7373279858Sjfv IXL_PF_UNLOCK(pf); 7374279858Sjfv return (error); 7375279858Sjfv} 7376279858Sjfv 7377279858Sjfvstatic void 7378299546Serjixl_iov_uninit(device_t dev) 7379279858Sjfv{ 7380279858Sjfv struct ixl_pf *pf; 7381279858Sjfv struct i40e_hw *hw; 7382279858Sjfv struct ixl_vsi *vsi; 7383279858Sjfv struct ifnet *ifp; 7384279858Sjfv struct ixl_vf *vfs; 7385279858Sjfv int i, num_vfs; 7386279858Sjfv 7387279858Sjfv pf = device_get_softc(dev); 7388279858Sjfv hw = &pf->hw; 7389279858Sjfv vsi = &pf->vsi; 7390279858Sjfv ifp = vsi->ifp; 7391279858Sjfv 7392279858Sjfv IXL_PF_LOCK(pf); 7393279858Sjfv for (i = 0; i < pf->num_vfs; i++) { 7394279858Sjfv if (pf->vfs[i].vsi.seid != 0) 7395279858Sjfv i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL); 7396279858Sjfv } 7397279858Sjfv 7398279858Sjfv if (pf->veb_seid != 0) { 7399279858Sjfv i40e_aq_delete_element(hw, pf->veb_seid, NULL); 7400279858Sjfv pf->veb_seid = 0; 7401279858Sjfv } 7402279858Sjfv 7403279858Sjfv if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 7404279858Sjfv ixl_disable_intr(vsi); 7405279858Sjfv 7406279858Sjfv vfs = pf->vfs; 7407279858Sjfv num_vfs = pf->num_vfs; 7408279858Sjfv 7409279858Sjfv pf->vfs = NULL; 7410279858Sjfv pf->num_vfs = 0; 7411279858Sjfv IXL_PF_UNLOCK(pf); 7412279858Sjfv 7413279858Sjfv /* Do this after the unlock as sysctl_ctx_free might sleep. */ 7414279858Sjfv for (i = 0; i < num_vfs; i++) 7415279858Sjfv sysctl_ctx_free(&vfs[i].ctx); 7416279858Sjfv free(vfs, M_IXL); 7417279858Sjfv} 7418279858Sjfv 7419279858Sjfvstatic int 7420279858Sjfvixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params) 7421279858Sjfv{ 7422279858Sjfv char sysctl_name[QUEUE_NAME_LEN]; 7423279858Sjfv struct ixl_pf *pf; 7424279858Sjfv struct ixl_vf *vf; 7425279858Sjfv const void *mac; 7426279858Sjfv size_t size; 7427279858Sjfv int error; 7428279858Sjfv 7429279858Sjfv pf = device_get_softc(dev); 7430279858Sjfv vf = &pf->vfs[vfnum]; 7431279858Sjfv 7432279858Sjfv IXL_PF_LOCK(pf); 7433279858Sjfv vf->vf_num = vfnum; 7434279858Sjfv 7435279858Sjfv vf->vsi.back = pf; 7436279858Sjfv vf->vf_flags = VF_FLAG_ENABLED; 7437279858Sjfv SLIST_INIT(&vf->vsi.ftl); 7438279858Sjfv 7439279858Sjfv error = ixl_vf_setup_vsi(pf, vf); 7440279858Sjfv if (error != 0) 7441279858Sjfv goto out; 7442279858Sjfv 7443279858Sjfv if (nvlist_exists_binary(params, "mac-addr")) { 7444279858Sjfv mac = nvlist_get_binary(params, "mac-addr", &size); 7445279858Sjfv bcopy(mac, vf->mac, ETHER_ADDR_LEN); 7446279858Sjfv 7447279858Sjfv if (nvlist_get_bool(params, "allow-set-mac")) 7448279858Sjfv vf->vf_flags |= VF_FLAG_SET_MAC_CAP; 7449279858Sjfv } else 7450279858Sjfv /* 7451279858Sjfv * If the administrator has not specified a MAC address then 7452279858Sjfv * we must allow the VF to choose one. 7453279858Sjfv */ 7454279858Sjfv vf->vf_flags |= VF_FLAG_SET_MAC_CAP; 7455279858Sjfv 7456279858Sjfv if (nvlist_get_bool(params, "mac-anti-spoof")) 7457279858Sjfv vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF; 7458279858Sjfv 7459279858Sjfv if (nvlist_get_bool(params, "allow-promisc")) 7460279858Sjfv vf->vf_flags |= VF_FLAG_PROMISC_CAP; 7461279858Sjfv 7462299552Serj /* TODO: Get VLAN that PF has set for the VF */ 7463299552Serj 7464279858Sjfv vf->vf_flags |= VF_FLAG_VLAN_CAP; 7465279858Sjfv 7466279858Sjfv ixl_reset_vf(pf, vf); 7467279858Sjfvout: 7468279858Sjfv IXL_PF_UNLOCK(pf); 7469279858Sjfv if (error == 0) { 7470279858Sjfv snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum); 7471279858Sjfv ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name); 7472279858Sjfv } 7473279858Sjfv 7474279858Sjfv return (error); 7475279858Sjfv} 7476279858Sjfv#endif /* PCI_IOV */ 7477