if_ixl.c revision 279033
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 279033 2015-02-20 00:40:26Z jfv $*/ 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 *********************************************************************/ 51279033Sjfvchar ixl_driver_version[] = "1.3.6"; 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_A, 0, 0, 0}, 67266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0}, 68266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0}, 69266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0}, 70266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0}, 71266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0}, 72270346Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 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 *); 99270346Sjfvstatic void ixl_media_status(struct ifnet *, struct ifmediareq *); 100270346Sjfvstatic int ixl_media_change(struct ifnet *); 101270346Sjfvstatic void ixl_update_link_status(struct ixl_pf *); 102270346Sjfvstatic int ixl_allocate_pci_resources(struct ixl_pf *); 103270346Sjfvstatic u16 ixl_get_bus_info(struct i40e_hw *, device_t); 104270346Sjfvstatic int ixl_setup_stations(struct ixl_pf *); 105279033Sjfvstatic int ixl_switch_config(struct ixl_pf *); 106270346Sjfvstatic int ixl_initialize_vsi(struct ixl_vsi *); 107270346Sjfvstatic int ixl_assign_vsi_msix(struct ixl_pf *); 108270346Sjfvstatic int ixl_assign_vsi_legacy(struct ixl_pf *); 109270346Sjfvstatic int ixl_init_msix(struct ixl_pf *); 110270346Sjfvstatic void ixl_configure_msix(struct ixl_pf *); 111270346Sjfvstatic void ixl_configure_itr(struct ixl_pf *); 112270346Sjfvstatic void ixl_configure_legacy(struct ixl_pf *); 113270346Sjfvstatic void ixl_free_pci_resources(struct ixl_pf *); 114270346Sjfvstatic void ixl_local_timer(void *); 115270346Sjfvstatic int ixl_setup_interface(device_t, struct ixl_vsi *); 116270346Sjfvstatic bool ixl_config_link(struct i40e_hw *); 117270346Sjfvstatic void ixl_config_rss(struct ixl_vsi *); 118270346Sjfvstatic void ixl_set_queue_rx_itr(struct ixl_queue *); 119270346Sjfvstatic void ixl_set_queue_tx_itr(struct ixl_queue *); 120274205Sjfvstatic int ixl_set_advertised_speeds(struct ixl_pf *, int); 121266423Sjfv 122270346Sjfvstatic void ixl_enable_rings(struct ixl_vsi *); 123270346Sjfvstatic void ixl_disable_rings(struct ixl_vsi *); 124270346Sjfvstatic void ixl_enable_intr(struct ixl_vsi *); 125270346Sjfvstatic void ixl_disable_intr(struct ixl_vsi *); 126266423Sjfv 127270346Sjfvstatic void ixl_enable_adminq(struct i40e_hw *); 128270346Sjfvstatic void ixl_disable_adminq(struct i40e_hw *); 129270346Sjfvstatic void ixl_enable_queue(struct i40e_hw *, int); 130270346Sjfvstatic void ixl_disable_queue(struct i40e_hw *, int); 131270346Sjfvstatic void ixl_enable_legacy(struct i40e_hw *); 132270346Sjfvstatic void ixl_disable_legacy(struct i40e_hw *); 133266423Sjfv 134270346Sjfvstatic void ixl_set_promisc(struct ixl_vsi *); 135270346Sjfvstatic void ixl_add_multi(struct ixl_vsi *); 136270346Sjfvstatic void ixl_del_multi(struct ixl_vsi *); 137270346Sjfvstatic void ixl_register_vlan(void *, struct ifnet *, u16); 138270346Sjfvstatic void ixl_unregister_vlan(void *, struct ifnet *, u16); 139270346Sjfvstatic void ixl_setup_vlan_filters(struct ixl_vsi *); 140266423Sjfv 141270346Sjfvstatic void ixl_init_filters(struct ixl_vsi *); 142270346Sjfvstatic void ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan); 143270346Sjfvstatic void ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan); 144270346Sjfvstatic void ixl_add_hw_filters(struct ixl_vsi *, int, int); 145270346Sjfvstatic void ixl_del_hw_filters(struct ixl_vsi *, int); 146270346Sjfvstatic struct ixl_mac_filter * 147270346Sjfv ixl_find_filter(struct ixl_vsi *, u8 *, s16); 148270346Sjfvstatic void ixl_add_mc_filter(struct ixl_vsi *, u8 *); 149266423Sjfv 150266423Sjfv/* Sysctl debug interface */ 151270346Sjfvstatic int ixl_debug_info(SYSCTL_HANDLER_ARGS); 152270346Sjfvstatic void ixl_print_debug_info(struct ixl_pf *); 153266423Sjfv 154266423Sjfv/* The MSI/X Interrupt handlers */ 155270346Sjfvstatic void ixl_intr(void *); 156270346Sjfvstatic void ixl_msix_que(void *); 157270346Sjfvstatic void ixl_msix_adminq(void *); 158270346Sjfvstatic void ixl_handle_mdd_event(struct ixl_pf *); 159266423Sjfv 160266423Sjfv/* Deferred interrupt tasklets */ 161270346Sjfvstatic void ixl_do_adminq(void *, int); 162266423Sjfv 163266423Sjfv/* Sysctl handlers */ 164270346Sjfvstatic int ixl_set_flowcntl(SYSCTL_HANDLER_ARGS); 165270346Sjfvstatic int ixl_set_advertise(SYSCTL_HANDLER_ARGS); 166270346Sjfvstatic int ixl_current_speed(SYSCTL_HANDLER_ARGS); 167274205Sjfvstatic int ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS); 168266423Sjfv 169266423Sjfv/* Statistics */ 170270346Sjfvstatic void ixl_add_hw_stats(struct ixl_pf *); 171270346Sjfvstatic void ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *, 172266423Sjfv struct sysctl_oid_list *, struct i40e_hw_port_stats *); 173270346Sjfvstatic void ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *, 174266423Sjfv struct sysctl_oid_list *, 175266423Sjfv struct i40e_eth_stats *); 176270346Sjfvstatic void ixl_update_stats_counters(struct ixl_pf *); 177270346Sjfvstatic void ixl_update_eth_stats(struct ixl_vsi *); 178270346Sjfvstatic void ixl_pf_reset_stats(struct ixl_pf *); 179270346Sjfvstatic void ixl_vsi_reset_stats(struct ixl_vsi *); 180270346Sjfvstatic void ixl_stat_update48(struct i40e_hw *, u32, u32, bool, 181266423Sjfv u64 *, u64 *); 182270346Sjfvstatic void ixl_stat_update32(struct i40e_hw *, u32, bool, 183266423Sjfv u64 *, u64 *); 184266423Sjfv 185277084Sjfv#ifdef IXL_DEBUG_SYSCTL 186270346Sjfvstatic int ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS); 187270346Sjfvstatic int ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS); 188270346Sjfvstatic int ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS); 189274205Sjfvstatic int ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS); 190274205Sjfvstatic int ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS); 191270346Sjfvstatic int ixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS); 192266423Sjfv#endif 193266423Sjfv 194266423Sjfv/********************************************************************* 195266423Sjfv * FreeBSD Device Interface Entry Points 196266423Sjfv *********************************************************************/ 197266423Sjfv 198270346Sjfvstatic device_method_t ixl_methods[] = { 199266423Sjfv /* Device interface */ 200270346Sjfv DEVMETHOD(device_probe, ixl_probe), 201270346Sjfv DEVMETHOD(device_attach, ixl_attach), 202270346Sjfv DEVMETHOD(device_detach, ixl_detach), 203270346Sjfv DEVMETHOD(device_shutdown, ixl_shutdown), 204266423Sjfv {0, 0} 205266423Sjfv}; 206266423Sjfv 207270346Sjfvstatic driver_t ixl_driver = { 208270346Sjfv "ixl", ixl_methods, sizeof(struct ixl_pf), 209266423Sjfv}; 210266423Sjfv 211270346Sjfvdevclass_t ixl_devclass; 212270346SjfvDRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); 213266423Sjfv 214270346SjfvMODULE_DEPEND(ixl, pci, 1, 1, 1); 215270346SjfvMODULE_DEPEND(ixl, ether, 1, 1, 1); 216266423Sjfv 217266423Sjfv/* 218269198Sjfv** Global reset mutex 219269198Sjfv*/ 220270346Sjfvstatic struct mtx ixl_reset_mtx; 221269198Sjfv 222269198Sjfv/* 223270346Sjfv** TUNEABLE PARAMETERS: 224270346Sjfv*/ 225270346Sjfv 226270346Sjfvstatic SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, 227270346Sjfv "IXL driver parameters"); 228270346Sjfv 229270346Sjfv/* 230266423Sjfv * MSIX should be the default for best performance, 231266423Sjfv * but this allows it to be forced off for testing. 232266423Sjfv */ 233270346Sjfvstatic int ixl_enable_msix = 1; 234270346SjfvTUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); 235270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, 236270346Sjfv "Enable MSI-X interrupts"); 237266423Sjfv 238266423Sjfv/* 239266423Sjfv** Number of descriptors per ring: 240266423Sjfv** - TX and RX are the same size 241266423Sjfv*/ 242270346Sjfvstatic int ixl_ringsz = DEFAULT_RING; 243270346SjfvTUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz); 244270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN, 245270346Sjfv &ixl_ringsz, 0, "Descriptor Ring Size"); 246266423Sjfv 247266423Sjfv/* 248266423Sjfv** This can be set manually, if left as 0 the 249266423Sjfv** number of queues will be calculated based 250266423Sjfv** on cpus and msix vectors available. 251266423Sjfv*/ 252270346Sjfvint ixl_max_queues = 0; 253270346SjfvTUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues); 254270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN, 255270346Sjfv &ixl_max_queues, 0, "Number of Queues"); 256266423Sjfv 257266423Sjfv/* 258266423Sjfv** Controls for Interrupt Throttling 259266423Sjfv** - true/false for dynamic adjustment 260266423Sjfv** - default values for static ITR 261266423Sjfv*/ 262270346Sjfvint ixl_dynamic_rx_itr = 0; 263270346SjfvTUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr); 264270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, 265270346Sjfv &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); 266266423Sjfv 267270346Sjfvint ixl_dynamic_tx_itr = 0; 268270346SjfvTUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr); 269270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, 270270346Sjfv &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); 271266423Sjfv 272270346Sjfvint ixl_rx_itr = IXL_ITR_8K; 273270346SjfvTUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr); 274270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, 275270346Sjfv &ixl_rx_itr, 0, "RX Interrupt Rate"); 276270346Sjfv 277270346Sjfvint ixl_tx_itr = IXL_ITR_4K; 278270346SjfvTUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); 279270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, 280270346Sjfv &ixl_tx_itr, 0, "TX Interrupt Rate"); 281270346Sjfv 282270346Sjfv#ifdef IXL_FDIR 283270346Sjfvstatic int ixl_enable_fdir = 1; 284270346SjfvTUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir); 285266423Sjfv/* Rate at which we sample */ 286270346Sjfvint ixl_atr_rate = 20; 287270346SjfvTUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate); 288266423Sjfv#endif 289266423Sjfv 290274205Sjfv 291270346Sjfvstatic char *ixl_fc_string[6] = { 292266423Sjfv "None", 293266423Sjfv "Rx", 294266423Sjfv "Tx", 295266423Sjfv "Full", 296266423Sjfv "Priority", 297266423Sjfv "Default" 298266423Sjfv}; 299266423Sjfv 300269198Sjfv 301266423Sjfv/********************************************************************* 302266423Sjfv * Device identification routine 303266423Sjfv * 304270346Sjfv * ixl_probe determines if the driver should be loaded on 305266423Sjfv * the hardware based on PCI vendor/device id of the device. 306266423Sjfv * 307266423Sjfv * return BUS_PROBE_DEFAULT on success, positive on failure 308266423Sjfv *********************************************************************/ 309266423Sjfv 310266423Sjfvstatic int 311270346Sjfvixl_probe(device_t dev) 312266423Sjfv{ 313270346Sjfv ixl_vendor_info_t *ent; 314266423Sjfv 315266423Sjfv u16 pci_vendor_id, pci_device_id; 316266423Sjfv u16 pci_subvendor_id, pci_subdevice_id; 317266423Sjfv char device_name[256]; 318269198Sjfv static bool lock_init = FALSE; 319266423Sjfv 320270346Sjfv INIT_DEBUGOUT("ixl_probe: begin"); 321266423Sjfv 322266423Sjfv pci_vendor_id = pci_get_vendor(dev); 323266423Sjfv if (pci_vendor_id != I40E_INTEL_VENDOR_ID) 324266423Sjfv return (ENXIO); 325266423Sjfv 326266423Sjfv pci_device_id = pci_get_device(dev); 327266423Sjfv pci_subvendor_id = pci_get_subvendor(dev); 328266423Sjfv pci_subdevice_id = pci_get_subdevice(dev); 329266423Sjfv 330270346Sjfv ent = ixl_vendor_info_array; 331266423Sjfv while (ent->vendor_id != 0) { 332266423Sjfv if ((pci_vendor_id == ent->vendor_id) && 333266423Sjfv (pci_device_id == ent->device_id) && 334266423Sjfv 335266423Sjfv ((pci_subvendor_id == ent->subvendor_id) || 336266423Sjfv (ent->subvendor_id == 0)) && 337266423Sjfv 338266423Sjfv ((pci_subdevice_id == ent->subdevice_id) || 339266423Sjfv (ent->subdevice_id == 0))) { 340266423Sjfv sprintf(device_name, "%s, Version - %s", 341270346Sjfv ixl_strings[ent->index], 342270346Sjfv ixl_driver_version); 343266423Sjfv device_set_desc_copy(dev, device_name); 344269198Sjfv /* One shot mutex init */ 345269198Sjfv if (lock_init == FALSE) { 346269198Sjfv lock_init = TRUE; 347270346Sjfv mtx_init(&ixl_reset_mtx, 348270346Sjfv "ixl_reset", 349270346Sjfv "IXL RESET Lock", MTX_DEF); 350269198Sjfv } 351266423Sjfv return (BUS_PROBE_DEFAULT); 352266423Sjfv } 353266423Sjfv ent++; 354266423Sjfv } 355266423Sjfv return (ENXIO); 356266423Sjfv} 357266423Sjfv 358266423Sjfv/********************************************************************* 359266423Sjfv * Device initialization routine 360266423Sjfv * 361266423Sjfv * The attach entry point is called when the driver is being loaded. 362266423Sjfv * This routine identifies the type of hardware, allocates all resources 363266423Sjfv * and initializes the hardware. 364266423Sjfv * 365266423Sjfv * return 0 on success, positive on failure 366266423Sjfv *********************************************************************/ 367266423Sjfv 368266423Sjfvstatic int 369270346Sjfvixl_attach(device_t dev) 370266423Sjfv{ 371270346Sjfv struct ixl_pf *pf; 372266423Sjfv struct i40e_hw *hw; 373270346Sjfv struct ixl_vsi *vsi; 374266423Sjfv u16 bus; 375266423Sjfv int error = 0; 376266423Sjfv 377270346Sjfv INIT_DEBUGOUT("ixl_attach: begin"); 378266423Sjfv 379266423Sjfv /* Allocate, clear, and link in our primary soft structure */ 380266423Sjfv pf = device_get_softc(dev); 381266423Sjfv pf->dev = pf->osdep.dev = dev; 382266423Sjfv hw = &pf->hw; 383266423Sjfv 384266423Sjfv /* 385266423Sjfv ** Note this assumes we have a single embedded VSI, 386266423Sjfv ** this could be enhanced later to allocate multiple 387266423Sjfv */ 388266423Sjfv vsi = &pf->vsi; 389266423Sjfv vsi->dev = pf->dev; 390266423Sjfv 391266423Sjfv /* Core Lock Init*/ 392270346Sjfv IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev)); 393266423Sjfv 394266423Sjfv /* Set up the timer callout */ 395266423Sjfv callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); 396266423Sjfv 397266423Sjfv /* Set up sysctls */ 398266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 399266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 400266423Sjfv OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, 401270346Sjfv pf, 0, ixl_set_flowcntl, "I", "Flow Control"); 402266423Sjfv 403269198Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 404269198Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 405269198Sjfv OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, 406270346Sjfv pf, 0, ixl_set_advertise, "I", "Advertised Speed"); 407269198Sjfv 408270346Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 409270346Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 410270346Sjfv OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD, 411270346Sjfv pf, 0, ixl_current_speed, "A", "Current Port Speed"); 412270346Sjfv 413274205Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 414274205Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 415274205Sjfv OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD, 416274205Sjfv pf, 0, ixl_sysctl_show_fw, "A", "Firmware version"); 417274205Sjfv 418266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 419266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 420273377Shselasky OID_AUTO, "rx_itr", CTLFLAG_RW, 421270346Sjfv &ixl_rx_itr, IXL_ITR_8K, "RX ITR"); 422266423Sjfv 423266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 424266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 425273377Shselasky OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW, 426270346Sjfv &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR"); 427266423Sjfv 428266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 429266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 430273377Shselasky OID_AUTO, "tx_itr", CTLFLAG_RW, 431270346Sjfv &ixl_tx_itr, IXL_ITR_4K, "TX ITR"); 432266423Sjfv 433266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 434266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 435273377Shselasky OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW, 436270346Sjfv &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR"); 437266423Sjfv 438277084Sjfv#ifdef IXL_DEBUG_SYSCTL 439266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 440266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 441266423Sjfv OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD, 442270346Sjfv pf, 0, ixl_sysctl_link_status, "A", "Current Link Status"); 443266423Sjfv 444266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 445266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 446266423Sjfv OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD, 447270346Sjfv pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities"); 448266423Sjfv 449266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 450266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 451266423Sjfv OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD, 452270346Sjfv pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List"); 453269198Sjfv 454269198Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 455269198Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 456274205Sjfv OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD, 457274205Sjfv pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation"); 458269198Sjfv 459269198Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 460269198Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 461274205Sjfv OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD, 462274205Sjfv pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration"); 463274205Sjfv 464274205Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 465274205Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 466269198Sjfv OID_AUTO, "dump_desc", CTLTYPE_INT | CTLFLAG_WR, 467270346Sjfv pf, 0, ixl_sysctl_dump_txd, "I", "Desc dump"); 468266423Sjfv#endif 469266423Sjfv 470274205Sjfv /* Save off the PCI information */ 471266423Sjfv hw->vendor_id = pci_get_vendor(dev); 472266423Sjfv hw->device_id = pci_get_device(dev); 473266423Sjfv hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 474266423Sjfv hw->subsystem_vendor_id = 475266423Sjfv pci_read_config(dev, PCIR_SUBVEND_0, 2); 476266423Sjfv hw->subsystem_device_id = 477266423Sjfv pci_read_config(dev, PCIR_SUBDEV_0, 2); 478266423Sjfv 479269198Sjfv hw->bus.device = pci_get_slot(dev); 480266423Sjfv hw->bus.func = pci_get_function(dev); 481266423Sjfv 482266423Sjfv /* Do PCI setup - map BAR0, etc */ 483270346Sjfv if (ixl_allocate_pci_resources(pf)) { 484266423Sjfv device_printf(dev, "Allocation of PCI resources failed\n"); 485266423Sjfv error = ENXIO; 486266423Sjfv goto err_out; 487266423Sjfv } 488266423Sjfv 489266423Sjfv /* Create for initial debugging use */ 490266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 491266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 492266423Sjfv OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0, 493270346Sjfv ixl_debug_info, "I", "Debug Information"); 494266423Sjfv 495266423Sjfv 496266423Sjfv /* Establish a clean starting point */ 497269198Sjfv i40e_clear_hw(hw); 498266423Sjfv error = i40e_pf_reset(hw); 499266423Sjfv if (error) { 500269198Sjfv device_printf(dev,"PF reset failure %x\n", error); 501269198Sjfv error = EIO; 502269198Sjfv goto err_out; 503269198Sjfv } 504266423Sjfv 505266423Sjfv /* Set admin queue parameters */ 506270346Sjfv hw->aq.num_arq_entries = IXL_AQ_LEN; 507270346Sjfv hw->aq.num_asq_entries = IXL_AQ_LEN; 508270346Sjfv hw->aq.arq_buf_size = IXL_AQ_BUFSZ; 509270346Sjfv hw->aq.asq_buf_size = IXL_AQ_BUFSZ; 510266423Sjfv 511266423Sjfv /* Initialize the shared code */ 512266423Sjfv error = i40e_init_shared_code(hw); 513266423Sjfv if (error) { 514266423Sjfv device_printf(dev,"Unable to initialize the shared code\n"); 515266423Sjfv error = EIO; 516266423Sjfv goto err_out; 517266423Sjfv } 518266423Sjfv 519266423Sjfv /* Set up the admin queue */ 520266423Sjfv error = i40e_init_adminq(hw); 521266423Sjfv if (error) { 522269198Sjfv device_printf(dev, "The driver for the device stopped " 523269198Sjfv "because the NVM image is newer than expected.\n" 524269198Sjfv "You must install the most recent version of " 525269198Sjfv " the network driver.\n"); 526266423Sjfv goto err_out; 527266423Sjfv } 528270346Sjfv device_printf(dev, "%s\n", ixl_fw_version_str(hw)); 529266423Sjfv 530269198Sjfv if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 531269198Sjfv hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) 532269198Sjfv device_printf(dev, "The driver for the device detected " 533269198Sjfv "a newer version of the NVM image than expected.\n" 534269198Sjfv "Please install the most recent version of the network driver.\n"); 535269198Sjfv else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || 536269198Sjfv hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) 537269198Sjfv device_printf(dev, "The driver for the device detected " 538269198Sjfv "an older version of the NVM image than expected.\n" 539269198Sjfv "Please update the NVM image.\n"); 540266423Sjfv 541266423Sjfv /* Clear PXE mode */ 542266423Sjfv i40e_clear_pxe_mode(hw); 543266423Sjfv 544266423Sjfv /* Get capabilities from the device */ 545270346Sjfv error = ixl_get_hw_capabilities(pf); 546266423Sjfv if (error) { 547266423Sjfv device_printf(dev, "HW capabilities failure!\n"); 548266423Sjfv goto err_get_cap; 549266423Sjfv } 550266423Sjfv 551266423Sjfv /* Set up host memory cache */ 552266423Sjfv error = i40e_init_lan_hmc(hw, vsi->num_queues, vsi->num_queues, 0, 0); 553266423Sjfv if (error) { 554266423Sjfv device_printf(dev, "init_lan_hmc failed: %d\n", error); 555266423Sjfv goto err_get_cap; 556266423Sjfv } 557266423Sjfv 558266423Sjfv error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 559266423Sjfv if (error) { 560266423Sjfv device_printf(dev, "configure_lan_hmc failed: %d\n", error); 561266423Sjfv goto err_mac_hmc; 562266423Sjfv } 563266423Sjfv 564269198Sjfv /* Disable LLDP from the firmware */ 565269198Sjfv i40e_aq_stop_lldp(hw, TRUE, NULL); 566269198Sjfv 567266423Sjfv i40e_get_mac_addr(hw, hw->mac.addr); 568266423Sjfv error = i40e_validate_mac_addr(hw->mac.addr); 569266423Sjfv if (error) { 570266423Sjfv device_printf(dev, "validate_mac_addr failed: %d\n", error); 571266423Sjfv goto err_mac_hmc; 572266423Sjfv } 573266423Sjfv bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 574266423Sjfv i40e_get_port_mac_addr(hw, hw->mac.port_addr); 575266423Sjfv 576274205Sjfv /* Set up VSI and queues */ 577270346Sjfv if (ixl_setup_stations(pf) != 0) { 578266423Sjfv device_printf(dev, "setup stations failed!\n"); 579266423Sjfv error = ENOMEM; 580266423Sjfv goto err_mac_hmc; 581266423Sjfv } 582266423Sjfv 583266423Sjfv /* Initialize mac filter list for VSI */ 584266423Sjfv SLIST_INIT(&vsi->ftl); 585266423Sjfv 586266423Sjfv /* Set up interrupt routing here */ 587266423Sjfv if (pf->msix > 1) 588270346Sjfv error = ixl_assign_vsi_msix(pf); 589266423Sjfv else 590270346Sjfv error = ixl_assign_vsi_legacy(pf); 591266423Sjfv if (error) 592266423Sjfv goto err_late; 593266423Sjfv 594279033Sjfv if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 595279033Sjfv (hw->aq.fw_maj_ver < 4)) { 596279033Sjfv i40e_msec_delay(75); 597279033Sjfv error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 598279033Sjfv if (error) 599279033Sjfv device_printf(dev, "link restart failed, aq_err=%d\n", 600279033Sjfv pf->hw.aq.asq_last_status); 601270346Sjfv } 602279033Sjfv 603266423Sjfv /* Determine link state */ 604270346Sjfv vsi->link_up = ixl_config_link(hw); 605266423Sjfv 606269198Sjfv /* Report if Unqualified modules are found */ 607269198Sjfv if ((vsi->link_up == FALSE) && 608269198Sjfv (pf->hw.phy.link_info.link_info & 609269198Sjfv I40E_AQ_MEDIA_AVAILABLE) && 610269198Sjfv (!(pf->hw.phy.link_info.an_info & 611269198Sjfv I40E_AQ_QUALIFIED_MODULE))) 612269198Sjfv device_printf(dev, "Link failed because " 613269198Sjfv "an unqualified module was detected\n"); 614269198Sjfv 615266423Sjfv /* Setup OS specific network interface */ 616274205Sjfv if (ixl_setup_interface(dev, vsi) != 0) { 617274205Sjfv device_printf(dev, "interface setup failed!\n"); 618274205Sjfv error = EIO; 619266423Sjfv goto err_late; 620274205Sjfv } 621266423Sjfv 622279033Sjfv error = ixl_switch_config(pf); 623279033Sjfv if (error) { 624279033Sjfv device_printf(dev, "Initial switch config failed: %d\n", error); 625279033Sjfv goto err_mac_hmc; 626279033Sjfv } 627279033Sjfv 628279033Sjfv /* Limit phy interrupts to link and modules failure */ 629279033Sjfv error = i40e_aq_set_phy_int_mask(hw, 630279033Sjfv I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL); 631279033Sjfv if (error) 632279033Sjfv device_printf(dev, "set phy mask failed: %d\n", error); 633279033Sjfv 634266423Sjfv /* Get the bus configuration and set the shared code */ 635270346Sjfv bus = ixl_get_bus_info(hw, dev); 636266423Sjfv i40e_set_pci_config_data(hw, bus); 637266423Sjfv 638266423Sjfv /* Initialize statistics */ 639270346Sjfv ixl_pf_reset_stats(pf); 640270346Sjfv ixl_update_stats_counters(pf); 641270346Sjfv ixl_add_hw_stats(pf); 642266423Sjfv 643266423Sjfv /* Register for VLAN events */ 644266423Sjfv vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 645270346Sjfv ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); 646266423Sjfv vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 647270346Sjfv ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); 648266423Sjfv 649274205Sjfv 650270346Sjfv INIT_DEBUGOUT("ixl_attach: end"); 651266423Sjfv return (0); 652266423Sjfv 653266423Sjfverr_late: 654274205Sjfv if (vsi->ifp != NULL) 655274205Sjfv if_free(vsi->ifp); 656266423Sjfverr_mac_hmc: 657266423Sjfv i40e_shutdown_lan_hmc(hw); 658266423Sjfverr_get_cap: 659266423Sjfv i40e_shutdown_adminq(hw); 660266423Sjfverr_out: 661270346Sjfv ixl_free_pci_resources(pf); 662274205Sjfv ixl_free_vsi(vsi); 663270346Sjfv IXL_PF_LOCK_DESTROY(pf); 664266423Sjfv return (error); 665266423Sjfv} 666266423Sjfv 667266423Sjfv/********************************************************************* 668266423Sjfv * Device removal routine 669266423Sjfv * 670266423Sjfv * The detach entry point is called when the driver is being removed. 671266423Sjfv * This routine stops the adapter and deallocates all the resources 672266423Sjfv * that were allocated for driver operation. 673266423Sjfv * 674266423Sjfv * return 0 on success, positive on failure 675266423Sjfv *********************************************************************/ 676266423Sjfv 677266423Sjfvstatic int 678270346Sjfvixl_detach(device_t dev) 679266423Sjfv{ 680270346Sjfv struct ixl_pf *pf = device_get_softc(dev); 681266423Sjfv struct i40e_hw *hw = &pf->hw; 682270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 683270346Sjfv struct ixl_queue *que = vsi->queues; 684266423Sjfv i40e_status status; 685266423Sjfv 686270346Sjfv INIT_DEBUGOUT("ixl_detach: begin"); 687266423Sjfv 688266423Sjfv /* Make sure VLANS are not using driver */ 689266423Sjfv if (vsi->ifp->if_vlantrunk != NULL) { 690266423Sjfv device_printf(dev,"Vlan in use, detach first\n"); 691266423Sjfv return (EBUSY); 692266423Sjfv } 693266423Sjfv 694279033Sjfv ether_ifdetach(vsi->ifp); 695279033Sjfv if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) { 696279033Sjfv IXL_PF_LOCK(pf); 697279033Sjfv ixl_stop(pf); 698279033Sjfv IXL_PF_UNLOCK(pf); 699279033Sjfv } 700266423Sjfv 701266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 702266423Sjfv if (que->tq) { 703266423Sjfv taskqueue_drain(que->tq, &que->task); 704266423Sjfv taskqueue_drain(que->tq, &que->tx_task); 705266423Sjfv taskqueue_free(que->tq); 706266423Sjfv } 707266423Sjfv } 708266423Sjfv 709266423Sjfv /* Shutdown LAN HMC */ 710266423Sjfv status = i40e_shutdown_lan_hmc(hw); 711266423Sjfv if (status) 712266423Sjfv device_printf(dev, 713266423Sjfv "Shutdown LAN HMC failed with code %d\n", status); 714266423Sjfv 715266423Sjfv /* Shutdown admin queue */ 716266423Sjfv status = i40e_shutdown_adminq(hw); 717266423Sjfv if (status) 718266423Sjfv device_printf(dev, 719266423Sjfv "Shutdown Admin queue failed with code %d\n", status); 720266423Sjfv 721266423Sjfv /* Unregister VLAN events */ 722266423Sjfv if (vsi->vlan_attach != NULL) 723266423Sjfv EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); 724266423Sjfv if (vsi->vlan_detach != NULL) 725266423Sjfv EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); 726266423Sjfv 727266423Sjfv callout_drain(&pf->timer); 728266423Sjfv 729274205Sjfv 730270346Sjfv ixl_free_pci_resources(pf); 731266423Sjfv bus_generic_detach(dev); 732266423Sjfv if_free(vsi->ifp); 733270346Sjfv ixl_free_vsi(vsi); 734270346Sjfv IXL_PF_LOCK_DESTROY(pf); 735266423Sjfv return (0); 736266423Sjfv} 737266423Sjfv 738266423Sjfv/********************************************************************* 739266423Sjfv * 740266423Sjfv * Shutdown entry point 741266423Sjfv * 742266423Sjfv **********************************************************************/ 743266423Sjfv 744266423Sjfvstatic int 745270346Sjfvixl_shutdown(device_t dev) 746266423Sjfv{ 747270346Sjfv struct ixl_pf *pf = device_get_softc(dev); 748270346Sjfv IXL_PF_LOCK(pf); 749270346Sjfv ixl_stop(pf); 750270346Sjfv IXL_PF_UNLOCK(pf); 751266423Sjfv return (0); 752266423Sjfv} 753266423Sjfv 754266423Sjfv 755266423Sjfv/********************************************************************* 756266423Sjfv * 757266423Sjfv * Get the hardware capabilities 758266423Sjfv * 759266423Sjfv **********************************************************************/ 760266423Sjfv 761266423Sjfvstatic int 762270346Sjfvixl_get_hw_capabilities(struct ixl_pf *pf) 763266423Sjfv{ 764266423Sjfv struct i40e_aqc_list_capabilities_element_resp *buf; 765266423Sjfv struct i40e_hw *hw = &pf->hw; 766266423Sjfv device_t dev = pf->dev; 767266423Sjfv int error, len; 768266423Sjfv u16 needed; 769266423Sjfv bool again = TRUE; 770266423Sjfv 771266423Sjfv len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); 772266423Sjfvretry: 773266423Sjfv if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *) 774266423Sjfv malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) { 775266423Sjfv device_printf(dev, "Unable to allocate cap memory\n"); 776266423Sjfv return (ENOMEM); 777266423Sjfv } 778266423Sjfv 779266423Sjfv /* This populates the hw struct */ 780266423Sjfv error = i40e_aq_discover_capabilities(hw, buf, len, 781266423Sjfv &needed, i40e_aqc_opc_list_func_capabilities, NULL); 782266423Sjfv free(buf, M_DEVBUF); 783266423Sjfv if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && 784266423Sjfv (again == TRUE)) { 785266423Sjfv /* retry once with a larger buffer */ 786266423Sjfv again = FALSE; 787266423Sjfv len = needed; 788266423Sjfv goto retry; 789266423Sjfv } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { 790266423Sjfv device_printf(dev, "capability discovery failed: %d\n", 791266423Sjfv pf->hw.aq.asq_last_status); 792266423Sjfv return (ENODEV); 793266423Sjfv } 794266423Sjfv 795266423Sjfv /* Capture this PF's starting queue pair */ 796266423Sjfv pf->qbase = hw->func_caps.base_queue; 797266423Sjfv 798270346Sjfv#ifdef IXL_DEBUG 799266423Sjfv device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, " 800266423Sjfv "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", 801266423Sjfv hw->pf_id, hw->func_caps.num_vfs, 802266423Sjfv hw->func_caps.num_msix_vectors, 803266423Sjfv hw->func_caps.num_msix_vectors_vf, 804266423Sjfv hw->func_caps.fd_filters_guaranteed, 805266423Sjfv hw->func_caps.fd_filters_best_effort, 806266423Sjfv hw->func_caps.num_tx_qp, 807266423Sjfv hw->func_caps.num_rx_qp, 808266423Sjfv hw->func_caps.base_queue); 809266423Sjfv#endif 810266423Sjfv return (error); 811266423Sjfv} 812266423Sjfv 813266423Sjfvstatic void 814270346Sjfvixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) 815266423Sjfv{ 816266423Sjfv device_t dev = vsi->dev; 817266423Sjfv 818266423Sjfv /* Enable/disable TXCSUM/TSO4 */ 819266423Sjfv if (!(ifp->if_capenable & IFCAP_TXCSUM) 820266423Sjfv && !(ifp->if_capenable & IFCAP_TSO4)) { 821266423Sjfv if (mask & IFCAP_TXCSUM) { 822266423Sjfv ifp->if_capenable |= IFCAP_TXCSUM; 823266423Sjfv /* enable TXCSUM, restore TSO if previously enabled */ 824270346Sjfv if (vsi->flags & IXL_FLAGS_KEEP_TSO4) { 825270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 826266423Sjfv ifp->if_capenable |= IFCAP_TSO4; 827266423Sjfv } 828266423Sjfv } 829266423Sjfv else if (mask & IFCAP_TSO4) { 830266423Sjfv ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); 831270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 832266423Sjfv device_printf(dev, 833266423Sjfv "TSO4 requires txcsum, enabling both...\n"); 834266423Sjfv } 835266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM) 836266423Sjfv && !(ifp->if_capenable & IFCAP_TSO4)) { 837266423Sjfv if (mask & IFCAP_TXCSUM) 838266423Sjfv ifp->if_capenable &= ~IFCAP_TXCSUM; 839266423Sjfv else if (mask & IFCAP_TSO4) 840266423Sjfv ifp->if_capenable |= IFCAP_TSO4; 841266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM) 842266423Sjfv && (ifp->if_capenable & IFCAP_TSO4)) { 843266423Sjfv if (mask & IFCAP_TXCSUM) { 844270346Sjfv vsi->flags |= IXL_FLAGS_KEEP_TSO4; 845266423Sjfv ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); 846266423Sjfv device_printf(dev, 847266423Sjfv "TSO4 requires txcsum, disabling both...\n"); 848266423Sjfv } else if (mask & IFCAP_TSO4) 849266423Sjfv ifp->if_capenable &= ~IFCAP_TSO4; 850266423Sjfv } 851266423Sjfv 852266423Sjfv /* Enable/disable TXCSUM_IPV6/TSO6 */ 853266423Sjfv if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) 854266423Sjfv && !(ifp->if_capenable & IFCAP_TSO6)) { 855266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) { 856266423Sjfv ifp->if_capenable |= IFCAP_TXCSUM_IPV6; 857270346Sjfv if (vsi->flags & IXL_FLAGS_KEEP_TSO6) { 858270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 859266423Sjfv ifp->if_capenable |= IFCAP_TSO6; 860266423Sjfv } 861266423Sjfv } else if (mask & IFCAP_TSO6) { 862266423Sjfv ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 863270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 864266423Sjfv device_printf(dev, 865266423Sjfv "TSO6 requires txcsum6, enabling both...\n"); 866266423Sjfv } 867266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 868266423Sjfv && !(ifp->if_capenable & IFCAP_TSO6)) { 869266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) 870266423Sjfv ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; 871266423Sjfv else if (mask & IFCAP_TSO6) 872266423Sjfv ifp->if_capenable |= IFCAP_TSO6; 873266423Sjfv } else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 874266423Sjfv && (ifp->if_capenable & IFCAP_TSO6)) { 875266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) { 876270346Sjfv vsi->flags |= IXL_FLAGS_KEEP_TSO6; 877266423Sjfv ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 878266423Sjfv device_printf(dev, 879266423Sjfv "TSO6 requires txcsum6, disabling both...\n"); 880266423Sjfv } else if (mask & IFCAP_TSO6) 881266423Sjfv ifp->if_capenable &= ~IFCAP_TSO6; 882266423Sjfv } 883266423Sjfv} 884266423Sjfv 885266423Sjfv/********************************************************************* 886266423Sjfv * Ioctl entry point 887266423Sjfv * 888270346Sjfv * ixl_ioctl is called when the user wants to configure the 889266423Sjfv * interface. 890266423Sjfv * 891266423Sjfv * return 0 on success, positive on failure 892266423Sjfv **********************************************************************/ 893266423Sjfv 894266423Sjfvstatic int 895270346Sjfvixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 896266423Sjfv{ 897270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 898270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 899266423Sjfv struct ifreq *ifr = (struct ifreq *) data; 900266423Sjfv#if defined(INET) || defined(INET6) 901266423Sjfv struct ifaddr *ifa = (struct ifaddr *)data; 902266423Sjfv bool avoid_reset = FALSE; 903266423Sjfv#endif 904266423Sjfv int error = 0; 905266423Sjfv 906266423Sjfv switch (command) { 907266423Sjfv 908266423Sjfv case SIOCSIFADDR: 909266423Sjfv#ifdef INET 910266423Sjfv if (ifa->ifa_addr->sa_family == AF_INET) 911266423Sjfv avoid_reset = TRUE; 912266423Sjfv#endif 913266423Sjfv#ifdef INET6 914266423Sjfv if (ifa->ifa_addr->sa_family == AF_INET6) 915266423Sjfv avoid_reset = TRUE; 916266423Sjfv#endif 917266423Sjfv#if defined(INET) || defined(INET6) 918266423Sjfv /* 919266423Sjfv ** Calling init results in link renegotiation, 920266423Sjfv ** so we avoid doing it when possible. 921266423Sjfv */ 922266423Sjfv if (avoid_reset) { 923266423Sjfv ifp->if_flags |= IFF_UP; 924266423Sjfv if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 925270346Sjfv ixl_init(pf); 926271900Sbz#ifdef INET 927266423Sjfv if (!(ifp->if_flags & IFF_NOARP)) 928266423Sjfv arp_ifinit(ifp, ifa); 929271900Sbz#endif 930266423Sjfv } else 931266423Sjfv error = ether_ioctl(ifp, command, data); 932266423Sjfv break; 933266423Sjfv#endif 934266423Sjfv case SIOCSIFMTU: 935266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 936270346Sjfv if (ifr->ifr_mtu > IXL_MAX_FRAME - 937266423Sjfv ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) { 938266423Sjfv error = EINVAL; 939266423Sjfv } else { 940270346Sjfv IXL_PF_LOCK(pf); 941266423Sjfv ifp->if_mtu = ifr->ifr_mtu; 942266423Sjfv vsi->max_frame_size = 943266423Sjfv ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 944266423Sjfv + ETHER_VLAN_ENCAP_LEN; 945270346Sjfv ixl_init_locked(pf); 946270346Sjfv IXL_PF_UNLOCK(pf); 947266423Sjfv } 948266423Sjfv break; 949266423Sjfv case SIOCSIFFLAGS: 950266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 951270346Sjfv IXL_PF_LOCK(pf); 952266423Sjfv if (ifp->if_flags & IFF_UP) { 953266423Sjfv if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 954266423Sjfv if ((ifp->if_flags ^ pf->if_flags) & 955266423Sjfv (IFF_PROMISC | IFF_ALLMULTI)) { 956270346Sjfv ixl_set_promisc(vsi); 957266423Sjfv } 958266423Sjfv } else 959270346Sjfv ixl_init_locked(pf); 960266423Sjfv } else 961266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) 962270346Sjfv ixl_stop(pf); 963266423Sjfv pf->if_flags = ifp->if_flags; 964270346Sjfv IXL_PF_UNLOCK(pf); 965266423Sjfv break; 966266423Sjfv case SIOCADDMULTI: 967266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); 968266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 969270346Sjfv IXL_PF_LOCK(pf); 970270346Sjfv ixl_disable_intr(vsi); 971270346Sjfv ixl_add_multi(vsi); 972270346Sjfv ixl_enable_intr(vsi); 973270346Sjfv IXL_PF_UNLOCK(pf); 974266423Sjfv } 975266423Sjfv break; 976266423Sjfv case SIOCDELMULTI: 977266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); 978266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 979270346Sjfv IXL_PF_LOCK(pf); 980270346Sjfv ixl_disable_intr(vsi); 981270346Sjfv ixl_del_multi(vsi); 982270346Sjfv ixl_enable_intr(vsi); 983270346Sjfv IXL_PF_UNLOCK(pf); 984266423Sjfv } 985266423Sjfv break; 986266423Sjfv case SIOCSIFMEDIA: 987266423Sjfv case SIOCGIFMEDIA: 988266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 989266423Sjfv error = ifmedia_ioctl(ifp, ifr, &vsi->media, command); 990266423Sjfv break; 991266423Sjfv case SIOCSIFCAP: 992266423Sjfv { 993266423Sjfv int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 994266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 995266423Sjfv 996270346Sjfv ixl_cap_txcsum_tso(vsi, ifp, mask); 997266423Sjfv 998266423Sjfv if (mask & IFCAP_RXCSUM) 999266423Sjfv ifp->if_capenable ^= IFCAP_RXCSUM; 1000266423Sjfv if (mask & IFCAP_RXCSUM_IPV6) 1001266423Sjfv ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1002266423Sjfv if (mask & IFCAP_LRO) 1003266423Sjfv ifp->if_capenable ^= IFCAP_LRO; 1004266423Sjfv if (mask & IFCAP_VLAN_HWTAGGING) 1005266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1006266423Sjfv if (mask & IFCAP_VLAN_HWFILTER) 1007266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 1008266423Sjfv if (mask & IFCAP_VLAN_HWTSO) 1009266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1010266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1011270346Sjfv IXL_PF_LOCK(pf); 1012270346Sjfv ixl_init_locked(pf); 1013270346Sjfv IXL_PF_UNLOCK(pf); 1014266423Sjfv } 1015266423Sjfv VLAN_CAPABILITIES(ifp); 1016266423Sjfv 1017266423Sjfv break; 1018266423Sjfv } 1019266423Sjfv 1020266423Sjfv default: 1021270346Sjfv IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command); 1022266423Sjfv error = ether_ioctl(ifp, command, data); 1023266423Sjfv break; 1024266423Sjfv } 1025266423Sjfv 1026266423Sjfv return (error); 1027266423Sjfv} 1028266423Sjfv 1029266423Sjfv 1030266423Sjfv/********************************************************************* 1031266423Sjfv * Init entry point 1032266423Sjfv * 1033266423Sjfv * This routine is used in two ways. It is used by the stack as 1034266423Sjfv * init entry point in network interface structure. It is also used 1035266423Sjfv * by the driver as a hw/sw initialization routine to get to a 1036266423Sjfv * consistent state. 1037266423Sjfv * 1038266423Sjfv * return 0 on success, positive on failure 1039266423Sjfv **********************************************************************/ 1040266423Sjfv 1041266423Sjfvstatic void 1042270346Sjfvixl_init_locked(struct ixl_pf *pf) 1043266423Sjfv{ 1044266423Sjfv struct i40e_hw *hw = &pf->hw; 1045270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1046266423Sjfv struct ifnet *ifp = vsi->ifp; 1047266423Sjfv device_t dev = pf->dev; 1048266423Sjfv struct i40e_filter_control_settings filter; 1049266423Sjfv u8 tmpaddr[ETHER_ADDR_LEN]; 1050266423Sjfv int ret; 1051266423Sjfv 1052266423Sjfv mtx_assert(&pf->pf_mtx, MA_OWNED); 1053270346Sjfv INIT_DEBUGOUT("ixl_init: begin"); 1054270346Sjfv ixl_stop(pf); 1055266423Sjfv 1056266423Sjfv /* Get the latest mac address... User might use a LAA */ 1057266423Sjfv bcopy(IF_LLADDR(vsi->ifp), tmpaddr, 1058266423Sjfv I40E_ETH_LENGTH_OF_ADDRESS); 1059266423Sjfv if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && 1060266423Sjfv i40e_validate_mac_addr(tmpaddr)) { 1061266423Sjfv bcopy(tmpaddr, hw->mac.addr, 1062266423Sjfv I40E_ETH_LENGTH_OF_ADDRESS); 1063266423Sjfv ret = i40e_aq_mac_address_write(hw, 1064266423Sjfv I40E_AQC_WRITE_TYPE_LAA_ONLY, 1065266423Sjfv hw->mac.addr, NULL); 1066266423Sjfv if (ret) { 1067266423Sjfv device_printf(dev, "LLA address" 1068266423Sjfv "change failed!!\n"); 1069266423Sjfv return; 1070266423Sjfv } 1071266423Sjfv } 1072266423Sjfv 1073266423Sjfv /* Set the various hardware offload abilities */ 1074266423Sjfv ifp->if_hwassist = 0; 1075266423Sjfv if (ifp->if_capenable & IFCAP_TSO) 1076266423Sjfv ifp->if_hwassist |= CSUM_TSO; 1077266423Sjfv if (ifp->if_capenable & IFCAP_TXCSUM) 1078266423Sjfv ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 1079266423Sjfv if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 1080266423Sjfv ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); 1081266423Sjfv 1082266423Sjfv /* Set up the device filtering */ 1083266423Sjfv bzero(&filter, sizeof(filter)); 1084266423Sjfv filter.enable_ethtype = TRUE; 1085266423Sjfv filter.enable_macvlan = TRUE; 1086270346Sjfv#ifdef IXL_FDIR 1087266423Sjfv filter.enable_fdir = TRUE; 1088266423Sjfv#endif 1089266423Sjfv if (i40e_set_filter_control(hw, &filter)) 1090266423Sjfv device_printf(dev, "set_filter_control() failed\n"); 1091266423Sjfv 1092266423Sjfv /* Set up RSS */ 1093270346Sjfv ixl_config_rss(vsi); 1094266423Sjfv 1095266423Sjfv /* 1096279033Sjfv ** Prepare the VSI: rings, hmc contexts, etc... 1097266423Sjfv */ 1098270346Sjfv if (ixl_initialize_vsi(vsi)) { 1099270346Sjfv device_printf(dev, "initialize vsi failed!!\n"); 1100266423Sjfv return; 1101266423Sjfv } 1102266423Sjfv 1103266423Sjfv /* Add protocol filters to list */ 1104270346Sjfv ixl_init_filters(vsi); 1105266423Sjfv 1106266423Sjfv /* Setup vlan's if needed */ 1107270346Sjfv ixl_setup_vlan_filters(vsi); 1108266423Sjfv 1109266423Sjfv /* Start the local timer */ 1110270346Sjfv callout_reset(&pf->timer, hz, ixl_local_timer, pf); 1111266423Sjfv 1112266423Sjfv /* Set up MSI/X routing and the ITR settings */ 1113270346Sjfv if (ixl_enable_msix) { 1114270346Sjfv ixl_configure_msix(pf); 1115270346Sjfv ixl_configure_itr(pf); 1116266423Sjfv } else 1117270346Sjfv ixl_configure_legacy(pf); 1118266423Sjfv 1119270346Sjfv ixl_enable_rings(vsi); 1120266423Sjfv 1121266423Sjfv i40e_aq_set_default_vsi(hw, vsi->seid, NULL); 1122266423Sjfv 1123266423Sjfv /* Set MTU in hardware*/ 1124270346Sjfv int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size, 1125270346Sjfv TRUE, 0, NULL); 1126270346Sjfv if (aq_error) 1127270346Sjfv device_printf(vsi->dev, 1128270346Sjfv "aq_set_mac_config in init error, code %d\n", 1129270346Sjfv aq_error); 1130266423Sjfv 1131266423Sjfv /* And now turn on interrupts */ 1132270346Sjfv ixl_enable_intr(vsi); 1133266423Sjfv 1134266423Sjfv /* Now inform the stack we're ready */ 1135266423Sjfv ifp->if_drv_flags |= IFF_DRV_RUNNING; 1136266423Sjfv ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1137266423Sjfv 1138266423Sjfv return; 1139266423Sjfv} 1140266423Sjfv 1141266423Sjfvstatic void 1142270346Sjfvixl_init(void *arg) 1143266423Sjfv{ 1144270346Sjfv struct ixl_pf *pf = arg; 1145266423Sjfv 1146270346Sjfv IXL_PF_LOCK(pf); 1147270346Sjfv ixl_init_locked(pf); 1148270346Sjfv IXL_PF_UNLOCK(pf); 1149266423Sjfv return; 1150266423Sjfv} 1151266423Sjfv 1152266423Sjfv/* 1153266423Sjfv** 1154266423Sjfv** MSIX Interrupt Handlers and Tasklets 1155266423Sjfv** 1156266423Sjfv*/ 1157266423Sjfvstatic void 1158270346Sjfvixl_handle_que(void *context, int pending) 1159266423Sjfv{ 1160270346Sjfv struct ixl_queue *que = context; 1161270346Sjfv struct ixl_vsi *vsi = que->vsi; 1162266423Sjfv struct i40e_hw *hw = vsi->hw; 1163266423Sjfv struct tx_ring *txr = &que->txr; 1164266423Sjfv struct ifnet *ifp = vsi->ifp; 1165266423Sjfv bool more; 1166266423Sjfv 1167266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1168270346Sjfv more = ixl_rxeof(que, IXL_RX_LIMIT); 1169270346Sjfv IXL_TX_LOCK(txr); 1170270346Sjfv ixl_txeof(que); 1171266423Sjfv if (!drbr_empty(ifp, txr->br)) 1172270346Sjfv ixl_mq_start_locked(ifp, txr); 1173270346Sjfv IXL_TX_UNLOCK(txr); 1174266423Sjfv if (more) { 1175266423Sjfv taskqueue_enqueue(que->tq, &que->task); 1176266423Sjfv return; 1177266423Sjfv } 1178266423Sjfv } 1179266423Sjfv 1180266423Sjfv /* Reenable this interrupt - hmmm */ 1181270346Sjfv ixl_enable_queue(hw, que->me); 1182266423Sjfv return; 1183266423Sjfv} 1184266423Sjfv 1185266423Sjfv 1186266423Sjfv/********************************************************************* 1187266423Sjfv * 1188266423Sjfv * Legacy Interrupt Service routine 1189266423Sjfv * 1190266423Sjfv **********************************************************************/ 1191266423Sjfvvoid 1192270346Sjfvixl_intr(void *arg) 1193266423Sjfv{ 1194270346Sjfv struct ixl_pf *pf = arg; 1195266423Sjfv struct i40e_hw *hw = &pf->hw; 1196270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1197270346Sjfv struct ixl_queue *que = vsi->queues; 1198266423Sjfv struct ifnet *ifp = vsi->ifp; 1199266423Sjfv struct tx_ring *txr = &que->txr; 1200266423Sjfv u32 reg, icr0, mask; 1201266423Sjfv bool more_tx, more_rx; 1202266423Sjfv 1203266423Sjfv ++que->irqs; 1204266423Sjfv 1205266423Sjfv /* Protect against spurious interrupts */ 1206266423Sjfv if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1207266423Sjfv return; 1208266423Sjfv 1209266423Sjfv icr0 = rd32(hw, I40E_PFINT_ICR0); 1210266423Sjfv 1211266423Sjfv reg = rd32(hw, I40E_PFINT_DYN_CTL0); 1212266423Sjfv reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 1213266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 1214266423Sjfv 1215266423Sjfv mask = rd32(hw, I40E_PFINT_ICR0_ENA); 1216266423Sjfv 1217266423Sjfv if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) { 1218266423Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 1219266423Sjfv return; 1220266423Sjfv } 1221266423Sjfv 1222270346Sjfv more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 1223266423Sjfv 1224270346Sjfv IXL_TX_LOCK(txr); 1225270346Sjfv more_tx = ixl_txeof(que); 1226266423Sjfv if (!drbr_empty(vsi->ifp, txr->br)) 1227266423Sjfv more_tx = 1; 1228270346Sjfv IXL_TX_UNLOCK(txr); 1229266423Sjfv 1230266423Sjfv /* re-enable other interrupt causes */ 1231266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, mask); 1232266423Sjfv 1233266423Sjfv /* And now the queues */ 1234266423Sjfv reg = rd32(hw, I40E_QINT_RQCTL(0)); 1235266423Sjfv reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; 1236266423Sjfv wr32(hw, I40E_QINT_RQCTL(0), reg); 1237266423Sjfv 1238266423Sjfv reg = rd32(hw, I40E_QINT_TQCTL(0)); 1239266423Sjfv reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; 1240266423Sjfv reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK; 1241266423Sjfv wr32(hw, I40E_QINT_TQCTL(0), reg); 1242266423Sjfv 1243270346Sjfv ixl_enable_legacy(hw); 1244266423Sjfv 1245266423Sjfv return; 1246266423Sjfv} 1247266423Sjfv 1248266423Sjfv 1249266423Sjfv/********************************************************************* 1250266423Sjfv * 1251266423Sjfv * MSIX VSI Interrupt Service routine 1252266423Sjfv * 1253266423Sjfv **********************************************************************/ 1254266423Sjfvvoid 1255270346Sjfvixl_msix_que(void *arg) 1256266423Sjfv{ 1257270346Sjfv struct ixl_queue *que = arg; 1258270346Sjfv struct ixl_vsi *vsi = que->vsi; 1259266423Sjfv struct i40e_hw *hw = vsi->hw; 1260266423Sjfv struct tx_ring *txr = &que->txr; 1261266423Sjfv bool more_tx, more_rx; 1262266423Sjfv 1263269198Sjfv /* Protect against spurious interrupts */ 1264269198Sjfv if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) 1265269198Sjfv return; 1266269198Sjfv 1267266423Sjfv ++que->irqs; 1268266423Sjfv 1269270346Sjfv more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 1270266423Sjfv 1271270346Sjfv IXL_TX_LOCK(txr); 1272270346Sjfv more_tx = ixl_txeof(que); 1273266423Sjfv /* 1274266423Sjfv ** Make certain that if the stack 1275266423Sjfv ** has anything queued the task gets 1276266423Sjfv ** scheduled to handle it. 1277266423Sjfv */ 1278266423Sjfv if (!drbr_empty(vsi->ifp, txr->br)) 1279266423Sjfv more_tx = 1; 1280270346Sjfv IXL_TX_UNLOCK(txr); 1281266423Sjfv 1282270346Sjfv ixl_set_queue_rx_itr(que); 1283270346Sjfv ixl_set_queue_tx_itr(que); 1284266423Sjfv 1285266423Sjfv if (more_tx || more_rx) 1286266423Sjfv taskqueue_enqueue(que->tq, &que->task); 1287266423Sjfv else 1288270346Sjfv ixl_enable_queue(hw, que->me); 1289266423Sjfv 1290266423Sjfv return; 1291266423Sjfv} 1292266423Sjfv 1293266423Sjfv 1294266423Sjfv/********************************************************************* 1295266423Sjfv * 1296266423Sjfv * MSIX Admin Queue Interrupt Service routine 1297266423Sjfv * 1298266423Sjfv **********************************************************************/ 1299266423Sjfvstatic void 1300270346Sjfvixl_msix_adminq(void *arg) 1301266423Sjfv{ 1302270346Sjfv struct ixl_pf *pf = arg; 1303266423Sjfv struct i40e_hw *hw = &pf->hw; 1304266423Sjfv u32 reg, mask; 1305266423Sjfv 1306266423Sjfv ++pf->admin_irq; 1307266423Sjfv 1308266423Sjfv reg = rd32(hw, I40E_PFINT_ICR0); 1309266423Sjfv mask = rd32(hw, I40E_PFINT_ICR0_ENA); 1310266423Sjfv 1311266423Sjfv /* Check on the cause */ 1312266423Sjfv if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) 1313266423Sjfv mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 1314266423Sjfv 1315269198Sjfv if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) { 1316270346Sjfv ixl_handle_mdd_event(pf); 1317266423Sjfv mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 1318269198Sjfv } 1319266423Sjfv 1320266423Sjfv if (reg & I40E_PFINT_ICR0_VFLR_MASK) 1321266423Sjfv mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; 1322266423Sjfv 1323266423Sjfv reg = rd32(hw, I40E_PFINT_DYN_CTL0); 1324266423Sjfv reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 1325266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 1326266423Sjfv 1327266423Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 1328266423Sjfv return; 1329266423Sjfv} 1330266423Sjfv 1331266423Sjfv/********************************************************************* 1332266423Sjfv * 1333266423Sjfv * Media Ioctl callback 1334266423Sjfv * 1335266423Sjfv * This routine is called whenever the user queries the status of 1336266423Sjfv * the interface using ifconfig. 1337266423Sjfv * 1338266423Sjfv **********************************************************************/ 1339266423Sjfvstatic void 1340270346Sjfvixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 1341266423Sjfv{ 1342270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 1343270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 1344266423Sjfv struct i40e_hw *hw = &pf->hw; 1345266423Sjfv 1346270346Sjfv INIT_DEBUGOUT("ixl_media_status: begin"); 1347270346Sjfv IXL_PF_LOCK(pf); 1348266423Sjfv 1349270346Sjfv ixl_update_link_status(pf); 1350266423Sjfv 1351266423Sjfv ifmr->ifm_status = IFM_AVALID; 1352266423Sjfv ifmr->ifm_active = IFM_ETHER; 1353266423Sjfv 1354266423Sjfv if (!vsi->link_up) { 1355270346Sjfv IXL_PF_UNLOCK(pf); 1356266423Sjfv return; 1357266423Sjfv } 1358266423Sjfv 1359266423Sjfv ifmr->ifm_status |= IFM_ACTIVE; 1360266423Sjfv /* Hardware is always full-duplex */ 1361266423Sjfv ifmr->ifm_active |= IFM_FDX; 1362266423Sjfv 1363266423Sjfv switch (hw->phy.link_info.phy_type) { 1364266423Sjfv /* 100 M */ 1365266423Sjfv case I40E_PHY_TYPE_100BASE_TX: 1366266423Sjfv ifmr->ifm_active |= IFM_100_TX; 1367266423Sjfv break; 1368266423Sjfv /* 1 G */ 1369266423Sjfv case I40E_PHY_TYPE_1000BASE_T: 1370266423Sjfv ifmr->ifm_active |= IFM_1000_T; 1371266423Sjfv break; 1372269198Sjfv case I40E_PHY_TYPE_1000BASE_SX: 1373269198Sjfv ifmr->ifm_active |= IFM_1000_SX; 1374269198Sjfv break; 1375269198Sjfv case I40E_PHY_TYPE_1000BASE_LX: 1376269198Sjfv ifmr->ifm_active |= IFM_1000_LX; 1377269198Sjfv break; 1378266423Sjfv /* 10 G */ 1379279033Sjfv case I40E_PHY_TYPE_10GBASE_CR1: 1380266423Sjfv case I40E_PHY_TYPE_10GBASE_CR1_CU: 1381266423Sjfv case I40E_PHY_TYPE_10GBASE_SFPP_CU: 1382279033Sjfv /* Using this until a real KR media type */ 1383279033Sjfv case I40E_PHY_TYPE_10GBASE_KR: 1384279033Sjfv case I40E_PHY_TYPE_10GBASE_KX4: 1385266423Sjfv ifmr->ifm_active |= IFM_10G_TWINAX; 1386266423Sjfv break; 1387266423Sjfv case I40E_PHY_TYPE_10GBASE_SR: 1388266423Sjfv ifmr->ifm_active |= IFM_10G_SR; 1389266423Sjfv break; 1390266423Sjfv case I40E_PHY_TYPE_10GBASE_LR: 1391266423Sjfv ifmr->ifm_active |= IFM_10G_LR; 1392266423Sjfv break; 1393270346Sjfv case I40E_PHY_TYPE_10GBASE_T: 1394270346Sjfv ifmr->ifm_active |= IFM_10G_T; 1395270346Sjfv break; 1396266423Sjfv /* 40 G */ 1397266423Sjfv case I40E_PHY_TYPE_40GBASE_CR4: 1398266423Sjfv case I40E_PHY_TYPE_40GBASE_CR4_CU: 1399266423Sjfv ifmr->ifm_active |= IFM_40G_CR4; 1400266423Sjfv break; 1401266423Sjfv case I40E_PHY_TYPE_40GBASE_SR4: 1402266423Sjfv ifmr->ifm_active |= IFM_40G_SR4; 1403266423Sjfv break; 1404266423Sjfv case I40E_PHY_TYPE_40GBASE_LR4: 1405266423Sjfv ifmr->ifm_active |= IFM_40G_LR4; 1406266423Sjfv break; 1407279033Sjfv /* 1408279033Sjfv ** Set these to CR4 because OS does not 1409279033Sjfv ** have types available yet. 1410279033Sjfv */ 1411279033Sjfv case I40E_PHY_TYPE_40GBASE_KR4: 1412279033Sjfv case I40E_PHY_TYPE_XLAUI: 1413279033Sjfv case I40E_PHY_TYPE_XLPPI: 1414279033Sjfv case I40E_PHY_TYPE_40GBASE_AOC: 1415279033Sjfv ifmr->ifm_active |= IFM_40G_CR4; 1416279033Sjfv break; 1417266423Sjfv default: 1418266423Sjfv ifmr->ifm_active |= IFM_UNKNOWN; 1419266423Sjfv break; 1420266423Sjfv } 1421266423Sjfv /* Report flow control status as well */ 1422266423Sjfv if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) 1423266423Sjfv ifmr->ifm_active |= IFM_ETH_TXPAUSE; 1424266423Sjfv if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) 1425266423Sjfv ifmr->ifm_active |= IFM_ETH_RXPAUSE; 1426266423Sjfv 1427270346Sjfv IXL_PF_UNLOCK(pf); 1428266423Sjfv 1429266423Sjfv return; 1430266423Sjfv} 1431266423Sjfv 1432266423Sjfv/********************************************************************* 1433266423Sjfv * 1434266423Sjfv * Media Ioctl callback 1435266423Sjfv * 1436266423Sjfv * This routine is called when the user changes speed/duplex using 1437266423Sjfv * media/mediopt option with ifconfig. 1438266423Sjfv * 1439266423Sjfv **********************************************************************/ 1440266423Sjfvstatic int 1441270346Sjfvixl_media_change(struct ifnet * ifp) 1442266423Sjfv{ 1443270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 1444266423Sjfv struct ifmedia *ifm = &vsi->media; 1445266423Sjfv 1446270346Sjfv INIT_DEBUGOUT("ixl_media_change: begin"); 1447266423Sjfv 1448266423Sjfv if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1449266423Sjfv return (EINVAL); 1450266423Sjfv 1451269198Sjfv if_printf(ifp, "Media change is currently not supported.\n"); 1452269198Sjfv 1453269198Sjfv return (ENODEV); 1454266423Sjfv} 1455266423Sjfv 1456266423Sjfv 1457270346Sjfv#ifdef IXL_FDIR 1458266423Sjfv/* 1459266423Sjfv** ATR: Application Targetted Receive - creates a filter 1460266423Sjfv** based on TX flow info that will keep the receive 1461266423Sjfv** portion of the flow on the same queue. Based on the 1462266423Sjfv** implementation this is only available for TCP connections 1463266423Sjfv*/ 1464266423Sjfvvoid 1465270346Sjfvixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype) 1466266423Sjfv{ 1467270346Sjfv struct ixl_vsi *vsi = que->vsi; 1468266423Sjfv struct tx_ring *txr = &que->txr; 1469266423Sjfv struct i40e_filter_program_desc *FDIR; 1470266423Sjfv u32 ptype, dtype; 1471266423Sjfv int idx; 1472266423Sjfv 1473266423Sjfv /* check if ATR is enabled and sample rate */ 1474270346Sjfv if ((!ixl_enable_fdir) || (!txr->atr_rate)) 1475266423Sjfv return; 1476266423Sjfv /* 1477266423Sjfv ** We sample all TCP SYN/FIN packets, 1478266423Sjfv ** or at the selected sample rate 1479266423Sjfv */ 1480266423Sjfv txr->atr_count++; 1481266423Sjfv if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) && 1482266423Sjfv (txr->atr_count < txr->atr_rate)) 1483266423Sjfv return; 1484266423Sjfv txr->atr_count = 0; 1485266423Sjfv 1486266423Sjfv /* Get a descriptor to use */ 1487266423Sjfv idx = txr->next_avail; 1488266423Sjfv FDIR = (struct i40e_filter_program_desc *) &txr->base[idx]; 1489266423Sjfv if (++idx == que->num_desc) 1490266423Sjfv idx = 0; 1491266423Sjfv txr->avail--; 1492266423Sjfv txr->next_avail = idx; 1493266423Sjfv 1494266423Sjfv ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & 1495266423Sjfv I40E_TXD_FLTR_QW0_QINDEX_MASK; 1496266423Sjfv 1497266423Sjfv ptype |= (etype == ETHERTYPE_IP) ? 1498266423Sjfv (I40E_FILTER_PCTYPE_NONF_IPV4_TCP << 1499266423Sjfv I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) : 1500266423Sjfv (I40E_FILTER_PCTYPE_NONF_IPV6_TCP << 1501266423Sjfv I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); 1502266423Sjfv 1503266423Sjfv ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT; 1504266423Sjfv 1505266423Sjfv dtype = I40E_TX_DESC_DTYPE_FILTER_PROG; 1506266423Sjfv 1507266423Sjfv /* 1508266423Sjfv ** We use the TCP TH_FIN as a trigger to remove 1509266423Sjfv ** the filter, otherwise its an update. 1510266423Sjfv */ 1511266423Sjfv dtype |= (th->th_flags & TH_FIN) ? 1512266423Sjfv (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << 1513266423Sjfv I40E_TXD_FLTR_QW1_PCMD_SHIFT) : 1514266423Sjfv (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << 1515266423Sjfv I40E_TXD_FLTR_QW1_PCMD_SHIFT); 1516266423Sjfv 1517266423Sjfv dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX << 1518266423Sjfv I40E_TXD_FLTR_QW1_DEST_SHIFT; 1519266423Sjfv 1520266423Sjfv dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID << 1521266423Sjfv I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT; 1522266423Sjfv 1523266423Sjfv FDIR->qindex_flex_ptype_vsi = htole32(ptype); 1524266423Sjfv FDIR->dtype_cmd_cntindex = htole32(dtype); 1525266423Sjfv return; 1526266423Sjfv} 1527266423Sjfv#endif 1528266423Sjfv 1529266423Sjfv 1530266423Sjfvstatic void 1531270346Sjfvixl_set_promisc(struct ixl_vsi *vsi) 1532266423Sjfv{ 1533266423Sjfv struct ifnet *ifp = vsi->ifp; 1534266423Sjfv struct i40e_hw *hw = vsi->hw; 1535266423Sjfv int err, mcnt = 0; 1536266423Sjfv bool uni = FALSE, multi = FALSE; 1537266423Sjfv 1538266423Sjfv if (ifp->if_flags & IFF_ALLMULTI) 1539266423Sjfv multi = TRUE; 1540266423Sjfv else { /* Need to count the multicast addresses */ 1541266423Sjfv struct ifmultiaddr *ifma; 1542266423Sjfv if_maddr_rlock(ifp); 1543266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1544266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1545266423Sjfv continue; 1546266423Sjfv if (mcnt == MAX_MULTICAST_ADDR) 1547266423Sjfv break; 1548266423Sjfv mcnt++; 1549266423Sjfv } 1550266423Sjfv if_maddr_runlock(ifp); 1551266423Sjfv } 1552266423Sjfv 1553266423Sjfv if (mcnt >= MAX_MULTICAST_ADDR) 1554266423Sjfv multi = TRUE; 1555266423Sjfv if (ifp->if_flags & IFF_PROMISC) 1556266423Sjfv uni = TRUE; 1557266423Sjfv 1558266423Sjfv err = i40e_aq_set_vsi_unicast_promiscuous(hw, 1559266423Sjfv vsi->seid, uni, NULL); 1560266423Sjfv err = i40e_aq_set_vsi_multicast_promiscuous(hw, 1561266423Sjfv vsi->seid, multi, NULL); 1562266423Sjfv return; 1563266423Sjfv} 1564266423Sjfv 1565266423Sjfv/********************************************************************* 1566266423Sjfv * Filter Routines 1567266423Sjfv * 1568266423Sjfv * Routines for multicast and vlan filter management. 1569266423Sjfv * 1570266423Sjfv *********************************************************************/ 1571266423Sjfvstatic void 1572270346Sjfvixl_add_multi(struct ixl_vsi *vsi) 1573266423Sjfv{ 1574266423Sjfv struct ifmultiaddr *ifma; 1575266423Sjfv struct ifnet *ifp = vsi->ifp; 1576266423Sjfv struct i40e_hw *hw = vsi->hw; 1577266423Sjfv int mcnt = 0, flags; 1578266423Sjfv 1579270346Sjfv IOCTL_DEBUGOUT("ixl_add_multi: begin"); 1580266423Sjfv 1581266423Sjfv if_maddr_rlock(ifp); 1582266423Sjfv /* 1583266423Sjfv ** First just get a count, to decide if we 1584266423Sjfv ** we simply use multicast promiscuous. 1585266423Sjfv */ 1586266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1587266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1588266423Sjfv continue; 1589266423Sjfv mcnt++; 1590266423Sjfv } 1591266423Sjfv if_maddr_runlock(ifp); 1592266423Sjfv 1593266423Sjfv if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { 1594266423Sjfv /* delete existing MC filters */ 1595270346Sjfv ixl_del_hw_filters(vsi, mcnt); 1596266423Sjfv i40e_aq_set_vsi_multicast_promiscuous(hw, 1597266423Sjfv vsi->seid, TRUE, NULL); 1598266423Sjfv return; 1599266423Sjfv } 1600266423Sjfv 1601266423Sjfv mcnt = 0; 1602266423Sjfv if_maddr_rlock(ifp); 1603266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1604266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1605266423Sjfv continue; 1606270346Sjfv ixl_add_mc_filter(vsi, 1607266423Sjfv (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); 1608266423Sjfv mcnt++; 1609266423Sjfv } 1610266423Sjfv if_maddr_runlock(ifp); 1611266423Sjfv if (mcnt > 0) { 1612270346Sjfv flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); 1613270346Sjfv ixl_add_hw_filters(vsi, flags, mcnt); 1614266423Sjfv } 1615266423Sjfv 1616270346Sjfv IOCTL_DEBUGOUT("ixl_add_multi: end"); 1617266423Sjfv return; 1618266423Sjfv} 1619266423Sjfv 1620266423Sjfvstatic void 1621270346Sjfvixl_del_multi(struct ixl_vsi *vsi) 1622266423Sjfv{ 1623266423Sjfv struct ifnet *ifp = vsi->ifp; 1624266423Sjfv struct ifmultiaddr *ifma; 1625270346Sjfv struct ixl_mac_filter *f; 1626266423Sjfv int mcnt = 0; 1627266423Sjfv bool match = FALSE; 1628266423Sjfv 1629270346Sjfv IOCTL_DEBUGOUT("ixl_del_multi: begin"); 1630266423Sjfv 1631266423Sjfv /* Search for removed multicast addresses */ 1632266423Sjfv if_maddr_rlock(ifp); 1633266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 1634270346Sjfv if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) { 1635266423Sjfv match = FALSE; 1636266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1637266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1638266423Sjfv continue; 1639266423Sjfv u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 1640266423Sjfv if (cmp_etheraddr(f->macaddr, mc_addr)) { 1641266423Sjfv match = TRUE; 1642266423Sjfv break; 1643266423Sjfv } 1644266423Sjfv } 1645266423Sjfv if (match == FALSE) { 1646270346Sjfv f->flags |= IXL_FILTER_DEL; 1647266423Sjfv mcnt++; 1648266423Sjfv } 1649266423Sjfv } 1650266423Sjfv } 1651266423Sjfv if_maddr_runlock(ifp); 1652266423Sjfv 1653266423Sjfv if (mcnt > 0) 1654270346Sjfv ixl_del_hw_filters(vsi, mcnt); 1655266423Sjfv} 1656266423Sjfv 1657266423Sjfv 1658266423Sjfv/********************************************************************* 1659266423Sjfv * Timer routine 1660266423Sjfv * 1661266423Sjfv * This routine checks for link status,updates statistics, 1662266423Sjfv * and runs the watchdog check. 1663266423Sjfv * 1664266423Sjfv **********************************************************************/ 1665266423Sjfv 1666266423Sjfvstatic void 1667270346Sjfvixl_local_timer(void *arg) 1668266423Sjfv{ 1669270346Sjfv struct ixl_pf *pf = arg; 1670266423Sjfv struct i40e_hw *hw = &pf->hw; 1671270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1672270346Sjfv struct ixl_queue *que = vsi->queues; 1673266423Sjfv device_t dev = pf->dev; 1674266423Sjfv int hung = 0; 1675266423Sjfv u32 mask; 1676266423Sjfv 1677266423Sjfv mtx_assert(&pf->pf_mtx, MA_OWNED); 1678266423Sjfv 1679266423Sjfv /* Fire off the adminq task */ 1680266423Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 1681266423Sjfv 1682266423Sjfv /* Update stats */ 1683270346Sjfv ixl_update_stats_counters(pf); 1684266423Sjfv 1685266423Sjfv /* 1686269198Sjfv ** Check status of the queues 1687266423Sjfv */ 1688266423Sjfv mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | 1689266423Sjfv I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); 1690266423Sjfv 1691266423Sjfv for (int i = 0; i < vsi->num_queues; i++,que++) { 1692266423Sjfv /* Any queues with outstanding work get a sw irq */ 1693266423Sjfv if (que->busy) 1694266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask); 1695266423Sjfv /* 1696266423Sjfv ** Each time txeof runs without cleaning, but there 1697266423Sjfv ** are uncleaned descriptors it increments busy. If 1698266423Sjfv ** we get to 5 we declare it hung. 1699266423Sjfv */ 1700270346Sjfv if (que->busy == IXL_QUEUE_HUNG) { 1701269198Sjfv ++hung; 1702269198Sjfv /* Mark the queue as inactive */ 1703269198Sjfv vsi->active_queues &= ~((u64)1 << que->me); 1704269198Sjfv continue; 1705269198Sjfv } else { 1706269198Sjfv /* Check if we've come back from hung */ 1707269198Sjfv if ((vsi->active_queues & ((u64)1 << que->me)) == 0) 1708269198Sjfv vsi->active_queues |= ((u64)1 << que->me); 1709269198Sjfv } 1710270346Sjfv if (que->busy >= IXL_MAX_TX_BUSY) { 1711277084Sjfv#ifdef IXL_DEBUG 1712266423Sjfv device_printf(dev,"Warning queue %d " 1713269198Sjfv "appears to be hung!\n", i); 1714277084Sjfv#endif 1715270346Sjfv que->busy = IXL_QUEUE_HUNG; 1716266423Sjfv ++hung; 1717266423Sjfv } 1718266423Sjfv } 1719266423Sjfv /* Only reinit if all queues show hung */ 1720266423Sjfv if (hung == vsi->num_queues) 1721266423Sjfv goto hung; 1722266423Sjfv 1723270346Sjfv callout_reset(&pf->timer, hz, ixl_local_timer, pf); 1724266423Sjfv return; 1725266423Sjfv 1726266423Sjfvhung: 1727266423Sjfv device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n"); 1728270346Sjfv ixl_init_locked(pf); 1729266423Sjfv} 1730266423Sjfv 1731266423Sjfv/* 1732266423Sjfv** Note: this routine updates the OS on the link state 1733266423Sjfv** the real check of the hardware only happens with 1734266423Sjfv** a link interrupt. 1735266423Sjfv*/ 1736266423Sjfvstatic void 1737270346Sjfvixl_update_link_status(struct ixl_pf *pf) 1738266423Sjfv{ 1739270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1740266423Sjfv struct i40e_hw *hw = &pf->hw; 1741266423Sjfv struct ifnet *ifp = vsi->ifp; 1742266423Sjfv device_t dev = pf->dev; 1743266423Sjfv 1744266423Sjfv 1745266423Sjfv if (vsi->link_up){ 1746266423Sjfv if (vsi->link_active == FALSE) { 1747266423Sjfv i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 1748279033Sjfv pf->fc = hw->fc.current_mode; 1749266423Sjfv if (bootverbose) { 1750266423Sjfv device_printf(dev,"Link is up %d Gbps %s," 1751266423Sjfv " Flow Control: %s\n", 1752266423Sjfv ((vsi->link_speed == I40E_LINK_SPEED_40GB)? 40:10), 1753279033Sjfv "Full Duplex", ixl_fc_string[pf->fc]); 1754266423Sjfv } 1755266423Sjfv vsi->link_active = TRUE; 1756277084Sjfv /* 1757277084Sjfv ** Warn user if link speed on NPAR enabled 1758277084Sjfv ** partition is not at least 10GB 1759277084Sjfv */ 1760277084Sjfv if (hw->func_caps.npar_enable && 1761277084Sjfv (hw->phy.link_info.link_speed == I40E_LINK_SPEED_1GB || 1762277084Sjfv hw->phy.link_info.link_speed == I40E_LINK_SPEED_100MB)) 1763277084Sjfv device_printf(dev, "The partition detected link" 1764277084Sjfv "speed that is less than 10Gbps\n"); 1765266423Sjfv if_link_state_change(ifp, LINK_STATE_UP); 1766266423Sjfv } 1767266423Sjfv } else { /* Link down */ 1768266423Sjfv if (vsi->link_active == TRUE) { 1769266423Sjfv if (bootverbose) 1770266423Sjfv device_printf(dev,"Link is Down\n"); 1771266423Sjfv if_link_state_change(ifp, LINK_STATE_DOWN); 1772266423Sjfv vsi->link_active = FALSE; 1773266423Sjfv } 1774266423Sjfv } 1775266423Sjfv 1776266423Sjfv return; 1777266423Sjfv} 1778266423Sjfv 1779266423Sjfv/********************************************************************* 1780266423Sjfv * 1781266423Sjfv * This routine disables all traffic on the adapter by issuing a 1782266423Sjfv * global reset on the MAC and deallocates TX/RX buffers. 1783266423Sjfv * 1784266423Sjfv **********************************************************************/ 1785266423Sjfv 1786266423Sjfvstatic void 1787270346Sjfvixl_stop(struct ixl_pf *pf) 1788266423Sjfv{ 1789270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1790266423Sjfv struct ifnet *ifp = vsi->ifp; 1791266423Sjfv 1792266423Sjfv mtx_assert(&pf->pf_mtx, MA_OWNED); 1793266423Sjfv 1794270346Sjfv INIT_DEBUGOUT("ixl_stop: begin\n"); 1795270346Sjfv ixl_disable_intr(vsi); 1796270346Sjfv ixl_disable_rings(vsi); 1797266423Sjfv 1798266423Sjfv /* Tell the stack that the interface is no longer active */ 1799266423Sjfv ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1800266423Sjfv 1801266423Sjfv /* Stop the local timer */ 1802266423Sjfv callout_stop(&pf->timer); 1803266423Sjfv 1804266423Sjfv return; 1805266423Sjfv} 1806266423Sjfv 1807266423Sjfv 1808266423Sjfv/********************************************************************* 1809266423Sjfv * 1810266423Sjfv * Setup MSIX Interrupt resources and handlers for the VSI 1811266423Sjfv * 1812266423Sjfv **********************************************************************/ 1813266423Sjfvstatic int 1814270346Sjfvixl_assign_vsi_legacy(struct ixl_pf *pf) 1815266423Sjfv{ 1816266423Sjfv device_t dev = pf->dev; 1817270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1818270346Sjfv struct ixl_queue *que = vsi->queues; 1819266423Sjfv int error, rid = 0; 1820266423Sjfv 1821266423Sjfv if (pf->msix == 1) 1822266423Sjfv rid = 1; 1823266423Sjfv pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 1824266423Sjfv &rid, RF_SHAREABLE | RF_ACTIVE); 1825266423Sjfv if (pf->res == NULL) { 1826266423Sjfv device_printf(dev,"Unable to allocate" 1827266423Sjfv " bus resource: vsi legacy/msi interrupt\n"); 1828266423Sjfv return (ENXIO); 1829266423Sjfv } 1830266423Sjfv 1831266423Sjfv /* Set the handler function */ 1832266423Sjfv error = bus_setup_intr(dev, pf->res, 1833266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 1834270346Sjfv ixl_intr, pf, &pf->tag); 1835266423Sjfv if (error) { 1836266423Sjfv pf->res = NULL; 1837266423Sjfv device_printf(dev, "Failed to register legacy/msi handler"); 1838266423Sjfv return (error); 1839266423Sjfv } 1840266423Sjfv bus_describe_intr(dev, pf->res, pf->tag, "irq0"); 1841270346Sjfv TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 1842270346Sjfv TASK_INIT(&que->task, 0, ixl_handle_que, que); 1843270346Sjfv que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 1844266423Sjfv taskqueue_thread_enqueue, &que->tq); 1845266423Sjfv taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 1846266423Sjfv device_get_nameunit(dev)); 1847270346Sjfv TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 1848270346Sjfv pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 1849266423Sjfv taskqueue_thread_enqueue, &pf->tq); 1850266423Sjfv taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 1851266423Sjfv device_get_nameunit(dev)); 1852266423Sjfv 1853266423Sjfv return (0); 1854266423Sjfv} 1855266423Sjfv 1856266423Sjfv 1857266423Sjfv/********************************************************************* 1858266423Sjfv * 1859266423Sjfv * Setup MSIX Interrupt resources and handlers for the VSI 1860266423Sjfv * 1861266423Sjfv **********************************************************************/ 1862266423Sjfvstatic int 1863270346Sjfvixl_assign_vsi_msix(struct ixl_pf *pf) 1864266423Sjfv{ 1865266423Sjfv device_t dev = pf->dev; 1866270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1867270346Sjfv struct ixl_queue *que = vsi->queues; 1868266423Sjfv struct tx_ring *txr; 1869266423Sjfv int error, rid, vector = 0; 1870266423Sjfv 1871266423Sjfv /* Admin Que is vector 0*/ 1872266423Sjfv rid = vector + 1; 1873266423Sjfv pf->res = bus_alloc_resource_any(dev, 1874266423Sjfv SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 1875266423Sjfv if (!pf->res) { 1876266423Sjfv device_printf(dev,"Unable to allocate" 1877266423Sjfv " bus resource: Adminq interrupt [%d]\n", rid); 1878266423Sjfv return (ENXIO); 1879266423Sjfv } 1880266423Sjfv /* Set the adminq vector and handler */ 1881266423Sjfv error = bus_setup_intr(dev, pf->res, 1882266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 1883270346Sjfv ixl_msix_adminq, pf, &pf->tag); 1884266423Sjfv if (error) { 1885266423Sjfv pf->res = NULL; 1886266423Sjfv device_printf(dev, "Failed to register Admin que handler"); 1887266423Sjfv return (error); 1888266423Sjfv } 1889266423Sjfv bus_describe_intr(dev, pf->res, pf->tag, "aq"); 1890266423Sjfv pf->admvec = vector; 1891266423Sjfv /* Tasklet for Admin Queue */ 1892270346Sjfv TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 1893270346Sjfv pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 1894266423Sjfv taskqueue_thread_enqueue, &pf->tq); 1895266423Sjfv taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 1896266423Sjfv device_get_nameunit(pf->dev)); 1897266423Sjfv ++vector; 1898266423Sjfv 1899266423Sjfv /* Now set up the stations */ 1900266423Sjfv for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { 1901277084Sjfv int cpu_id = i; 1902266423Sjfv rid = vector + 1; 1903266423Sjfv txr = &que->txr; 1904266423Sjfv que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1905266423Sjfv RF_SHAREABLE | RF_ACTIVE); 1906266423Sjfv if (que->res == NULL) { 1907266423Sjfv device_printf(dev,"Unable to allocate" 1908266423Sjfv " bus resource: que interrupt [%d]\n", vector); 1909266423Sjfv return (ENXIO); 1910266423Sjfv } 1911266423Sjfv /* Set the handler function */ 1912266423Sjfv error = bus_setup_intr(dev, que->res, 1913266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 1914270346Sjfv ixl_msix_que, que, &que->tag); 1915266423Sjfv if (error) { 1916266423Sjfv que->res = NULL; 1917266423Sjfv device_printf(dev, "Failed to register que handler"); 1918266423Sjfv return (error); 1919266423Sjfv } 1920266423Sjfv bus_describe_intr(dev, que->res, que->tag, "q%d", i); 1921266423Sjfv /* Bind the vector to a CPU */ 1922277084Sjfv#ifdef RSS 1923277084Sjfv cpu_id = rss_getcpu(i % rss_getnumbuckets()); 1924277084Sjfv#endif 1925277084Sjfv bus_bind_intr(dev, que->res, cpu_id); 1926266423Sjfv que->msix = vector; 1927270346Sjfv TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 1928270346Sjfv TASK_INIT(&que->task, 0, ixl_handle_que, que); 1929270346Sjfv que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 1930266423Sjfv taskqueue_thread_enqueue, &que->tq); 1931277084Sjfv#ifdef RSS 1932277084Sjfv taskqueue_start_threads_pinned(&que->tq, 1, PI_NET, 1933277084Sjfv cpu_id, "%s (bucket %d)", 1934277084Sjfv device_get_nameunit(dev), cpu_id); 1935277084Sjfv#else 1936277084Sjfv taskqueue_start_threads(&que->tq, 1, PI_NET, 1937277084Sjfv "%s que", device_get_nameunit(dev)); 1938277084Sjfv#endif 1939266423Sjfv } 1940266423Sjfv 1941266423Sjfv return (0); 1942266423Sjfv} 1943266423Sjfv 1944266423Sjfv 1945266423Sjfv/* 1946266423Sjfv * Allocate MSI/X vectors 1947266423Sjfv */ 1948266423Sjfvstatic int 1949270346Sjfvixl_init_msix(struct ixl_pf *pf) 1950266423Sjfv{ 1951266423Sjfv device_t dev = pf->dev; 1952266423Sjfv int rid, want, vectors, queues, available; 1953266423Sjfv 1954266423Sjfv /* Override by tuneable */ 1955270346Sjfv if (ixl_enable_msix == 0) 1956266423Sjfv goto msi; 1957266423Sjfv 1958269198Sjfv /* 1959269198Sjfv ** When used in a virtualized environment 1960269198Sjfv ** PCI BUSMASTER capability may not be set 1961269198Sjfv ** so explicity set it here and rewrite 1962269198Sjfv ** the ENABLE in the MSIX control register 1963269198Sjfv ** at this point to cause the host to 1964269198Sjfv ** successfully initialize us. 1965269198Sjfv */ 1966269198Sjfv { 1967269198Sjfv u16 pci_cmd_word; 1968269198Sjfv int msix_ctrl; 1969269198Sjfv pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); 1970269198Sjfv pci_cmd_word |= PCIM_CMD_BUSMASTEREN; 1971269198Sjfv pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); 1972269198Sjfv pci_find_cap(dev, PCIY_MSIX, &rid); 1973269198Sjfv rid += PCIR_MSIX_CTRL; 1974269198Sjfv msix_ctrl = pci_read_config(dev, rid, 2); 1975269198Sjfv msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; 1976269198Sjfv pci_write_config(dev, rid, msix_ctrl, 2); 1977269198Sjfv } 1978269198Sjfv 1979266423Sjfv /* First try MSI/X */ 1980270346Sjfv rid = PCIR_BAR(IXL_BAR); 1981266423Sjfv pf->msix_mem = bus_alloc_resource_any(dev, 1982266423Sjfv SYS_RES_MEMORY, &rid, RF_ACTIVE); 1983266423Sjfv if (!pf->msix_mem) { 1984266423Sjfv /* May not be enabled */ 1985266423Sjfv device_printf(pf->dev, 1986266423Sjfv "Unable to map MSIX table \n"); 1987266423Sjfv goto msi; 1988266423Sjfv } 1989266423Sjfv 1990266423Sjfv available = pci_msix_count(dev); 1991266423Sjfv if (available == 0) { /* system has msix disabled */ 1992266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 1993266423Sjfv rid, pf->msix_mem); 1994266423Sjfv pf->msix_mem = NULL; 1995266423Sjfv goto msi; 1996266423Sjfv } 1997266423Sjfv 1998266423Sjfv /* Figure out a reasonable auto config value */ 1999266423Sjfv queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus; 2000266423Sjfv 2001266423Sjfv /* Override with hardcoded value if sane */ 2002270346Sjfv if ((ixl_max_queues != 0) && (ixl_max_queues <= queues)) 2003270346Sjfv queues = ixl_max_queues; 2004266423Sjfv 2005277084Sjfv#ifdef RSS 2006277084Sjfv /* If we're doing RSS, clamp at the number of RSS buckets */ 2007277084Sjfv if (queues > rss_getnumbuckets()) 2008277084Sjfv queues = rss_getnumbuckets(); 2009277084Sjfv#endif 2010277084Sjfv 2011266423Sjfv /* 2012266423Sjfv ** Want one vector (RX/TX pair) per queue 2013266423Sjfv ** plus an additional for the admin queue. 2014266423Sjfv */ 2015266423Sjfv want = queues + 1; 2016266423Sjfv if (want <= available) /* Have enough */ 2017266423Sjfv vectors = want; 2018266423Sjfv else { 2019266423Sjfv device_printf(pf->dev, 2020266423Sjfv "MSIX Configuration Problem, " 2021266423Sjfv "%d vectors available but %d wanted!\n", 2022266423Sjfv available, want); 2023266423Sjfv return (0); /* Will go to Legacy setup */ 2024266423Sjfv } 2025266423Sjfv 2026266423Sjfv if (pci_alloc_msix(dev, &vectors) == 0) { 2027266423Sjfv device_printf(pf->dev, 2028266423Sjfv "Using MSIX interrupts with %d vectors\n", vectors); 2029266423Sjfv pf->msix = vectors; 2030266423Sjfv pf->vsi.num_queues = queues; 2031277084Sjfv#ifdef RSS 2032277084Sjfv /* 2033277084Sjfv * If we're doing RSS, the number of queues needs to 2034277084Sjfv * match the number of RSS buckets that are configured. 2035277084Sjfv * 2036277084Sjfv * + If there's more queues than RSS buckets, we'll end 2037277084Sjfv * up with queues that get no traffic. 2038277084Sjfv * 2039277084Sjfv * + If there's more RSS buckets than queues, we'll end 2040277084Sjfv * up having multiple RSS buckets map to the same queue, 2041277084Sjfv * so there'll be some contention. 2042277084Sjfv */ 2043277084Sjfv if (queues != rss_getnumbuckets()) { 2044277084Sjfv device_printf(dev, 2045277084Sjfv "%s: queues (%d) != RSS buckets (%d)" 2046277084Sjfv "; performance will be impacted.\n", 2047277084Sjfv __func__, queues, rss_getnumbuckets()); 2048277084Sjfv } 2049277084Sjfv#endif 2050266423Sjfv return (vectors); 2051266423Sjfv } 2052266423Sjfvmsi: 2053266423Sjfv vectors = pci_msi_count(dev); 2054266423Sjfv pf->vsi.num_queues = 1; 2055266423Sjfv pf->msix = 1; 2056270346Sjfv ixl_max_queues = 1; 2057270346Sjfv ixl_enable_msix = 0; 2058266423Sjfv if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) 2059266423Sjfv device_printf(pf->dev,"Using an MSI interrupt\n"); 2060266423Sjfv else { 2061266423Sjfv pf->msix = 0; 2062266423Sjfv device_printf(pf->dev,"Using a Legacy interrupt\n"); 2063266423Sjfv } 2064266423Sjfv return (vectors); 2065266423Sjfv} 2066266423Sjfv 2067266423Sjfv 2068266423Sjfv/* 2069266423Sjfv * Plumb MSI/X vectors 2070266423Sjfv */ 2071266423Sjfvstatic void 2072270346Sjfvixl_configure_msix(struct ixl_pf *pf) 2073266423Sjfv{ 2074266423Sjfv struct i40e_hw *hw = &pf->hw; 2075270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2076266423Sjfv u32 reg; 2077266423Sjfv u16 vector = 1; 2078266423Sjfv 2079266423Sjfv /* First set up the adminq - vector 0 */ 2080266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, 0); /* disable all */ 2081266423Sjfv rd32(hw, I40E_PFINT_ICR0); /* read to clear */ 2082266423Sjfv 2083266423Sjfv reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | 2084266423Sjfv I40E_PFINT_ICR0_ENA_GRST_MASK | 2085266423Sjfv I40E_PFINT_ICR0_HMC_ERR_MASK | 2086266423Sjfv I40E_PFINT_ICR0_ENA_ADMINQ_MASK | 2087266423Sjfv I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK | 2088266423Sjfv I40E_PFINT_ICR0_ENA_VFLR_MASK | 2089266423Sjfv I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK; 2090266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 2091266423Sjfv 2092266423Sjfv wr32(hw, I40E_PFINT_LNKLST0, 0x7FF); 2093270346Sjfv wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x003E); 2094266423Sjfv 2095266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, 2096266423Sjfv I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK | 2097266423Sjfv I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK); 2098266423Sjfv 2099266423Sjfv wr32(hw, I40E_PFINT_STAT_CTL0, 0); 2100266423Sjfv 2101266423Sjfv /* Next configure the queues */ 2102266423Sjfv for (int i = 0; i < vsi->num_queues; i++, vector++) { 2103266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(i), i); 2104266423Sjfv wr32(hw, I40E_PFINT_LNKLSTN(i), i); 2105266423Sjfv 2106266423Sjfv reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | 2107270346Sjfv (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | 2108266423Sjfv (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 2109266423Sjfv (i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 2110266423Sjfv (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); 2111266423Sjfv wr32(hw, I40E_QINT_RQCTL(i), reg); 2112266423Sjfv 2113266423Sjfv reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK | 2114270346Sjfv (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | 2115266423Sjfv (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | 2116266423Sjfv ((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | 2117266423Sjfv (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 2118266423Sjfv if (i == (vsi->num_queues - 1)) 2119270346Sjfv reg |= (IXL_QUEUE_EOL 2120266423Sjfv << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 2121266423Sjfv wr32(hw, I40E_QINT_TQCTL(i), reg); 2122266423Sjfv } 2123266423Sjfv} 2124266423Sjfv 2125266423Sjfv/* 2126266423Sjfv * Configure for MSI single vector operation 2127266423Sjfv */ 2128266423Sjfvstatic void 2129270346Sjfvixl_configure_legacy(struct ixl_pf *pf) 2130266423Sjfv{ 2131266423Sjfv struct i40e_hw *hw = &pf->hw; 2132266423Sjfv u32 reg; 2133266423Sjfv 2134266423Sjfv 2135266423Sjfv wr32(hw, I40E_PFINT_ITR0(0), 0); 2136266423Sjfv wr32(hw, I40E_PFINT_ITR0(1), 0); 2137266423Sjfv 2138266423Sjfv 2139266423Sjfv /* Setup "other" causes */ 2140266423Sjfv reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK 2141266423Sjfv | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK 2142266423Sjfv | I40E_PFINT_ICR0_ENA_GRST_MASK 2143266423Sjfv | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK 2144266423Sjfv | I40E_PFINT_ICR0_ENA_GPIO_MASK 2145266423Sjfv | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK 2146266423Sjfv | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK 2147266423Sjfv | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK 2148266423Sjfv | I40E_PFINT_ICR0_ENA_VFLR_MASK 2149266423Sjfv | I40E_PFINT_ICR0_ENA_ADMINQ_MASK 2150266423Sjfv ; 2151266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 2152266423Sjfv 2153266423Sjfv /* SW_ITR_IDX = 0, but don't change INTENA */ 2154266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, 2155266423Sjfv I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK | 2156266423Sjfv I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK); 2157266423Sjfv /* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */ 2158266423Sjfv wr32(hw, I40E_PFINT_STAT_CTL0, 0); 2159266423Sjfv 2160266423Sjfv /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ 2161266423Sjfv wr32(hw, I40E_PFINT_LNKLST0, 0); 2162266423Sjfv 2163266423Sjfv /* Associate the queue pair to the vector and enable the q int */ 2164266423Sjfv reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK 2165270346Sjfv | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) 2166266423Sjfv | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 2167266423Sjfv wr32(hw, I40E_QINT_RQCTL(0), reg); 2168266423Sjfv 2169266423Sjfv reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK 2170270346Sjfv | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) 2171270346Sjfv | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 2172266423Sjfv wr32(hw, I40E_QINT_TQCTL(0), reg); 2173266423Sjfv 2174266423Sjfv /* Next enable the queue pair */ 2175266423Sjfv reg = rd32(hw, I40E_QTX_ENA(0)); 2176266423Sjfv reg |= I40E_QTX_ENA_QENA_REQ_MASK; 2177266423Sjfv wr32(hw, I40E_QTX_ENA(0), reg); 2178266423Sjfv 2179266423Sjfv reg = rd32(hw, I40E_QRX_ENA(0)); 2180266423Sjfv reg |= I40E_QRX_ENA_QENA_REQ_MASK; 2181266423Sjfv wr32(hw, I40E_QRX_ENA(0), reg); 2182266423Sjfv} 2183266423Sjfv 2184266423Sjfv 2185266423Sjfv/* 2186266423Sjfv * Set the Initial ITR state 2187266423Sjfv */ 2188266423Sjfvstatic void 2189270346Sjfvixl_configure_itr(struct ixl_pf *pf) 2190266423Sjfv{ 2191266423Sjfv struct i40e_hw *hw = &pf->hw; 2192270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2193270346Sjfv struct ixl_queue *que = vsi->queues; 2194266423Sjfv 2195270346Sjfv vsi->rx_itr_setting = ixl_rx_itr; 2196270346Sjfv if (ixl_dynamic_rx_itr) 2197270346Sjfv vsi->rx_itr_setting |= IXL_ITR_DYNAMIC; 2198270346Sjfv vsi->tx_itr_setting = ixl_tx_itr; 2199270346Sjfv if (ixl_dynamic_tx_itr) 2200270346Sjfv vsi->tx_itr_setting |= IXL_ITR_DYNAMIC; 2201266423Sjfv 2202266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2203266423Sjfv struct tx_ring *txr = &que->txr; 2204266423Sjfv struct rx_ring *rxr = &que->rxr; 2205266423Sjfv 2206270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i), 2207266423Sjfv vsi->rx_itr_setting); 2208266423Sjfv rxr->itr = vsi->rx_itr_setting; 2209270346Sjfv rxr->latency = IXL_AVE_LATENCY; 2210270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i), 2211266423Sjfv vsi->tx_itr_setting); 2212266423Sjfv txr->itr = vsi->tx_itr_setting; 2213270346Sjfv txr->latency = IXL_AVE_LATENCY; 2214266423Sjfv } 2215266423Sjfv} 2216266423Sjfv 2217266423Sjfv 2218266423Sjfvstatic int 2219270346Sjfvixl_allocate_pci_resources(struct ixl_pf *pf) 2220266423Sjfv{ 2221266423Sjfv int rid; 2222266423Sjfv device_t dev = pf->dev; 2223266423Sjfv 2224266423Sjfv rid = PCIR_BAR(0); 2225266423Sjfv pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2226266423Sjfv &rid, RF_ACTIVE); 2227266423Sjfv 2228266423Sjfv if (!(pf->pci_mem)) { 2229266423Sjfv device_printf(dev,"Unable to allocate bus resource: memory\n"); 2230266423Sjfv return (ENXIO); 2231266423Sjfv } 2232266423Sjfv 2233266423Sjfv pf->osdep.mem_bus_space_tag = 2234266423Sjfv rman_get_bustag(pf->pci_mem); 2235266423Sjfv pf->osdep.mem_bus_space_handle = 2236266423Sjfv rman_get_bushandle(pf->pci_mem); 2237270346Sjfv pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); 2238272285Srstone pf->osdep.flush_reg = I40E_GLGEN_STAT; 2239266423Sjfv pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; 2240266423Sjfv 2241266423Sjfv pf->hw.back = &pf->osdep; 2242266423Sjfv 2243266423Sjfv /* 2244266423Sjfv ** Now setup MSI or MSI/X, should 2245266423Sjfv ** return us the number of supported 2246266423Sjfv ** vectors. (Will be 1 for MSI) 2247266423Sjfv */ 2248270346Sjfv pf->msix = ixl_init_msix(pf); 2249266423Sjfv return (0); 2250266423Sjfv} 2251266423Sjfv 2252266423Sjfvstatic void 2253270346Sjfvixl_free_pci_resources(struct ixl_pf * pf) 2254266423Sjfv{ 2255270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2256270346Sjfv struct ixl_queue *que = vsi->queues; 2257266423Sjfv device_t dev = pf->dev; 2258266423Sjfv int rid, memrid; 2259266423Sjfv 2260270346Sjfv memrid = PCIR_BAR(IXL_BAR); 2261266423Sjfv 2262266423Sjfv /* We may get here before stations are setup */ 2263270346Sjfv if ((!ixl_enable_msix) || (que == NULL)) 2264266423Sjfv goto early; 2265266423Sjfv 2266266423Sjfv /* 2267266423Sjfv ** Release all msix VSI resources: 2268266423Sjfv */ 2269266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2270266423Sjfv rid = que->msix + 1; 2271266423Sjfv if (que->tag != NULL) { 2272266423Sjfv bus_teardown_intr(dev, que->res, que->tag); 2273266423Sjfv que->tag = NULL; 2274266423Sjfv } 2275266423Sjfv if (que->res != NULL) 2276266423Sjfv bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2277266423Sjfv } 2278266423Sjfv 2279266423Sjfvearly: 2280266423Sjfv /* Clean the AdminQ interrupt last */ 2281266423Sjfv if (pf->admvec) /* we are doing MSIX */ 2282266423Sjfv rid = pf->admvec + 1; 2283266423Sjfv else 2284266423Sjfv (pf->msix != 0) ? (rid = 1):(rid = 0); 2285266423Sjfv 2286266423Sjfv if (pf->tag != NULL) { 2287266423Sjfv bus_teardown_intr(dev, pf->res, pf->tag); 2288266423Sjfv pf->tag = NULL; 2289266423Sjfv } 2290266423Sjfv if (pf->res != NULL) 2291266423Sjfv bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); 2292266423Sjfv 2293266423Sjfv if (pf->msix) 2294266423Sjfv pci_release_msi(dev); 2295266423Sjfv 2296266423Sjfv if (pf->msix_mem != NULL) 2297266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 2298266423Sjfv memrid, pf->msix_mem); 2299266423Sjfv 2300266423Sjfv if (pf->pci_mem != NULL) 2301266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 2302266423Sjfv PCIR_BAR(0), pf->pci_mem); 2303266423Sjfv 2304266423Sjfv return; 2305266423Sjfv} 2306266423Sjfv 2307274205Sjfvstatic void 2308274205Sjfvixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type) 2309274205Sjfv{ 2310274205Sjfv /* Display supported media types */ 2311274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX)) 2312274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2313266423Sjfv 2314274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T)) 2315274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); 2316274205Sjfv 2317274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) || 2318279033Sjfv phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4) || 2319279033Sjfv phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR) || 2320279033Sjfv phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) || 2321279033Sjfv phy_type & (1 << I40E_PHY_TYPE_XAUI) || 2322279033Sjfv phy_type & (1 << I40E_PHY_TYPE_XFI) || 2323279033Sjfv phy_type & (1 << I40E_PHY_TYPE_SFI) || 2324274205Sjfv phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU)) 2325274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2326279033Sjfv 2327274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR)) 2328274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2329274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR)) 2330274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2331274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T)) 2332274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2333274205Sjfv 2334279033Sjfv if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) || 2335279033Sjfv phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) || 2336279033Sjfv phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) || 2337279033Sjfv phy_type & (1 << I40E_PHY_TYPE_XLAUI) || 2338279033Sjfv phy_type & (1 << I40E_PHY_TYPE_XLPPI) || 2339279033Sjfv /* KR4 uses CR4 until the OS has the real media type */ 2340279033Sjfv phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) 2341274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2342279033Sjfv 2343274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4)) 2344274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2345274205Sjfv if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4)) 2346274205Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); 2347274205Sjfv} 2348274205Sjfv 2349266423Sjfv/********************************************************************* 2350266423Sjfv * 2351266423Sjfv * Setup networking device structure and register an interface. 2352266423Sjfv * 2353266423Sjfv **********************************************************************/ 2354266423Sjfvstatic int 2355270346Sjfvixl_setup_interface(device_t dev, struct ixl_vsi *vsi) 2356266423Sjfv{ 2357266423Sjfv struct ifnet *ifp; 2358266423Sjfv struct i40e_hw *hw = vsi->hw; 2359270346Sjfv struct ixl_queue *que = vsi->queues; 2360279033Sjfv struct i40e_aq_get_phy_abilities_resp abilities; 2361266423Sjfv enum i40e_status_code aq_error = 0; 2362266423Sjfv 2363270346Sjfv INIT_DEBUGOUT("ixl_setup_interface: begin"); 2364266423Sjfv 2365266423Sjfv ifp = vsi->ifp = if_alloc(IFT_ETHER); 2366266423Sjfv if (ifp == NULL) { 2367266423Sjfv device_printf(dev, "can not allocate ifnet structure\n"); 2368266423Sjfv return (-1); 2369266423Sjfv } 2370266423Sjfv if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2371266423Sjfv ifp->if_mtu = ETHERMTU; 2372266423Sjfv ifp->if_baudrate = 4000000000; // ?? 2373270346Sjfv ifp->if_init = ixl_init; 2374266423Sjfv ifp->if_softc = vsi; 2375266423Sjfv ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2376270346Sjfv ifp->if_ioctl = ixl_ioctl; 2377266423Sjfv 2378274205Sjfv#if __FreeBSD_version >= 1100036 2379272227Sglebius if_setgetcounterfn(ifp, ixl_get_counter); 2380272227Sglebius#endif 2381272227Sglebius 2382270346Sjfv ifp->if_transmit = ixl_mq_start; 2383266423Sjfv 2384270346Sjfv ifp->if_qflush = ixl_qflush; 2385266423Sjfv 2386266423Sjfv ifp->if_snd.ifq_maxlen = que->num_desc - 2; 2387266423Sjfv 2388266423Sjfv vsi->max_frame_size = 2389266423Sjfv ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 2390266423Sjfv + ETHER_VLAN_ENCAP_LEN; 2391266423Sjfv 2392266423Sjfv /* 2393266423Sjfv * Tell the upper layer(s) we support long frames. 2394266423Sjfv */ 2395270856Sglebius ifp->if_hdrlen = sizeof(struct ether_vlan_header); 2396266423Sjfv 2397266423Sjfv ifp->if_capabilities |= IFCAP_HWCSUM; 2398266423Sjfv ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; 2399266423Sjfv ifp->if_capabilities |= IFCAP_TSO; 2400266423Sjfv ifp->if_capabilities |= IFCAP_JUMBO_MTU; 2401266423Sjfv ifp->if_capabilities |= IFCAP_LRO; 2402266423Sjfv 2403266423Sjfv /* VLAN capabilties */ 2404266423Sjfv ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 2405266423Sjfv | IFCAP_VLAN_HWTSO 2406266423Sjfv | IFCAP_VLAN_MTU 2407266423Sjfv | IFCAP_VLAN_HWCSUM; 2408266423Sjfv ifp->if_capenable = ifp->if_capabilities; 2409266423Sjfv 2410266423Sjfv /* 2411266423Sjfv ** Don't turn this on by default, if vlans are 2412266423Sjfv ** created on another pseudo device (eg. lagg) 2413266423Sjfv ** then vlan events are not passed thru, breaking 2414266423Sjfv ** operation, but with HW FILTER off it works. If 2415270346Sjfv ** using vlans directly on the ixl driver you can 2416266423Sjfv ** enable this and get full hardware tag filtering. 2417266423Sjfv */ 2418266423Sjfv ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 2419266423Sjfv 2420266423Sjfv /* 2421266423Sjfv * Specify the media types supported by this adapter and register 2422266423Sjfv * callbacks to update media and link information 2423266423Sjfv */ 2424270346Sjfv ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change, 2425270346Sjfv ixl_media_status); 2426266423Sjfv 2427279033Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, 2428279033Sjfv FALSE, TRUE, &abilities, NULL); 2429279033Sjfv /* May need delay to detect fiber correctly */ 2430274205Sjfv if (aq_error == I40E_ERR_UNKNOWN_PHY) { 2431274205Sjfv i40e_msec_delay(200); 2432277084Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, 2433279033Sjfv TRUE, &abilities, NULL); 2434279033Sjfv } 2435279033Sjfv if (aq_error) { 2436274205Sjfv if (aq_error == I40E_ERR_UNKNOWN_PHY) 2437274205Sjfv device_printf(dev, "Unknown PHY type detected!\n"); 2438274205Sjfv else 2439279033Sjfv device_printf(dev, 2440279033Sjfv "Error getting supported media types, err %d," 2441279033Sjfv " AQ error %d\n", aq_error, hw->aq.asq_last_status); 2442279033Sjfv return (0); 2443279033Sjfv } 2444266423Sjfv 2445279033Sjfv ixl_add_ifmedia(vsi, abilities.phy_type); 2446279033Sjfv 2447266423Sjfv /* Use autoselect media by default */ 2448266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2449266423Sjfv ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); 2450266423Sjfv 2451274205Sjfv ether_ifattach(ifp, hw->mac.addr); 2452274205Sjfv 2453266423Sjfv return (0); 2454266423Sjfv} 2455266423Sjfv 2456266423Sjfvstatic bool 2457270346Sjfvixl_config_link(struct i40e_hw *hw) 2458266423Sjfv{ 2459266423Sjfv bool check; 2460266423Sjfv 2461266423Sjfv i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 2462266423Sjfv check = i40e_get_link_status(hw); 2463270346Sjfv#ifdef IXL_DEBUG 2464266423Sjfv printf("Link is %s\n", check ? "up":"down"); 2465266423Sjfv#endif 2466266423Sjfv return (check); 2467266423Sjfv} 2468266423Sjfv 2469266423Sjfv/********************************************************************* 2470266423Sjfv * 2471279033Sjfv * Get Firmware Switch configuration 2472279033Sjfv * - this will need to be more robust when more complex 2473279033Sjfv * switch configurations are enabled. 2474266423Sjfv * 2475266423Sjfv **********************************************************************/ 2476266423Sjfvstatic int 2477279033Sjfvixl_switch_config(struct ixl_pf *pf) 2478266423Sjfv{ 2479279033Sjfv struct i40e_hw *hw = &pf->hw; 2480279033Sjfv struct ixl_vsi *vsi = &pf->vsi; 2481266423Sjfv device_t dev = vsi->dev; 2482266423Sjfv struct i40e_aqc_get_switch_config_resp *sw_config; 2483266423Sjfv u8 aq_buf[I40E_AQ_LARGE_BUF]; 2484266423Sjfv int ret = I40E_SUCCESS; 2485266423Sjfv u16 next = 0; 2486266423Sjfv 2487279033Sjfv memset(&aq_buf, 0, sizeof(aq_buf)); 2488266423Sjfv sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 2489266423Sjfv ret = i40e_aq_get_switch_config(hw, sw_config, 2490266423Sjfv sizeof(aq_buf), &next, NULL); 2491266423Sjfv if (ret) { 2492266423Sjfv device_printf(dev,"aq_get_switch_config failed!!\n"); 2493266423Sjfv return (ret); 2494266423Sjfv } 2495270346Sjfv#ifdef IXL_DEBUG 2496266423Sjfv printf("Switch config: header reported: %d in structure, %d total\n", 2497266423Sjfv sw_config->header.num_reported, sw_config->header.num_total); 2498266423Sjfv printf("type=%d seid=%d uplink=%d downlink=%d\n", 2499266423Sjfv sw_config->element[0].element_type, 2500266423Sjfv sw_config->element[0].seid, 2501266423Sjfv sw_config->element[0].uplink_seid, 2502266423Sjfv sw_config->element[0].downlink_seid); 2503266423Sjfv#endif 2504279033Sjfv /* Simplified due to a single VSI at the moment */ 2505266423Sjfv vsi->seid = sw_config->element[0].seid; 2506279033Sjfv return (ret); 2507279033Sjfv} 2508266423Sjfv 2509279033Sjfv/********************************************************************* 2510279033Sjfv * 2511279033Sjfv * Initialize the VSI: this handles contexts, which means things 2512279033Sjfv * like the number of descriptors, buffer size, 2513279033Sjfv * plus we init the rings thru this function. 2514279033Sjfv * 2515279033Sjfv **********************************************************************/ 2516279033Sjfvstatic int 2517279033Sjfvixl_initialize_vsi(struct ixl_vsi *vsi) 2518279033Sjfv{ 2519279033Sjfv struct ixl_queue *que = vsi->queues; 2520279033Sjfv device_t dev = vsi->dev; 2521279033Sjfv struct i40e_hw *hw = vsi->hw; 2522279033Sjfv struct i40e_vsi_context ctxt; 2523279033Sjfv int err = 0; 2524279033Sjfv 2525266423Sjfv memset(&ctxt, 0, sizeof(ctxt)); 2526266423Sjfv ctxt.seid = vsi->seid; 2527266423Sjfv ctxt.pf_num = hw->pf_id; 2528279033Sjfv err = i40e_aq_get_vsi_params(hw, &ctxt, NULL); 2529279033Sjfv if (err) { 2530279033Sjfv device_printf(dev,"get vsi params failed %x!!\n", err); 2531279033Sjfv return (err); 2532266423Sjfv } 2533270346Sjfv#ifdef IXL_DEBUG 2534266423Sjfv printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, " 2535266423Sjfv "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, " 2536266423Sjfv "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid, 2537266423Sjfv ctxt.uplink_seid, ctxt.vsi_number, 2538266423Sjfv ctxt.vsis_allocated, ctxt.vsis_unallocated, 2539266423Sjfv ctxt.flags, ctxt.pf_num, ctxt.vf_num, 2540266423Sjfv ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits); 2541266423Sjfv#endif 2542266423Sjfv /* 2543266423Sjfv ** Set the queue and traffic class bits 2544266423Sjfv ** - when multiple traffic classes are supported 2545266423Sjfv ** this will need to be more robust. 2546266423Sjfv */ 2547266423Sjfv ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID; 2548266423Sjfv ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG; 2549266423Sjfv ctxt.info.queue_mapping[0] = 0; 2550266423Sjfv ctxt.info.tc_mapping[0] = 0x0800; 2551266423Sjfv 2552266423Sjfv /* Set VLAN receive stripping mode */ 2553266423Sjfv ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; 2554266423Sjfv ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; 2555266423Sjfv if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 2556266423Sjfv ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 2557266423Sjfv else 2558266423Sjfv ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 2559266423Sjfv 2560266423Sjfv /* Keep copy of VSI info in VSI for statistic counters */ 2561266423Sjfv memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); 2562266423Sjfv 2563266423Sjfv /* Reset VSI statistics */ 2564270346Sjfv ixl_vsi_reset_stats(vsi); 2565266423Sjfv vsi->hw_filters_add = 0; 2566266423Sjfv vsi->hw_filters_del = 0; 2567266423Sjfv 2568279033Sjfv err = i40e_aq_update_vsi_params(hw, &ctxt, NULL); 2569279033Sjfv if (err) { 2570266423Sjfv device_printf(dev,"update vsi params failed %x!!\n", 2571266423Sjfv hw->aq.asq_last_status); 2572279033Sjfv return (err); 2573279033Sjfv } 2574266423Sjfv 2575266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2576266423Sjfv struct tx_ring *txr = &que->txr; 2577266423Sjfv struct rx_ring *rxr = &que->rxr; 2578266423Sjfv struct i40e_hmc_obj_txq tctx; 2579266423Sjfv struct i40e_hmc_obj_rxq rctx; 2580266423Sjfv u32 txctl; 2581266423Sjfv u16 size; 2582266423Sjfv 2583266423Sjfv 2584266423Sjfv /* Setup the HMC TX Context */ 2585266423Sjfv size = que->num_desc * sizeof(struct i40e_tx_desc); 2586266423Sjfv memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq)); 2587266423Sjfv tctx.new_context = 1; 2588266423Sjfv tctx.base = (txr->dma.pa/128); 2589266423Sjfv tctx.qlen = que->num_desc; 2590266423Sjfv tctx.fc_ena = 0; 2591269198Sjfv tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */ 2592269198Sjfv /* Enable HEAD writeback */ 2593269198Sjfv tctx.head_wb_ena = 1; 2594269198Sjfv tctx.head_wb_addr = txr->dma.pa + 2595269198Sjfv (que->num_desc * sizeof(struct i40e_tx_desc)); 2596266423Sjfv tctx.rdylist_act = 0; 2597266423Sjfv err = i40e_clear_lan_tx_queue_context(hw, i); 2598266423Sjfv if (err) { 2599266423Sjfv device_printf(dev, "Unable to clear TX context\n"); 2600266423Sjfv break; 2601266423Sjfv } 2602266423Sjfv err = i40e_set_lan_tx_queue_context(hw, i, &tctx); 2603266423Sjfv if (err) { 2604266423Sjfv device_printf(dev, "Unable to set TX context\n"); 2605266423Sjfv break; 2606266423Sjfv } 2607266423Sjfv /* Associate the ring with this PF */ 2608266423Sjfv txctl = I40E_QTX_CTL_PF_QUEUE; 2609266423Sjfv txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & 2610266423Sjfv I40E_QTX_CTL_PF_INDX_MASK); 2611266423Sjfv wr32(hw, I40E_QTX_CTL(i), txctl); 2612270346Sjfv ixl_flush(hw); 2613266423Sjfv 2614266423Sjfv /* Do ring (re)init */ 2615270346Sjfv ixl_init_tx_ring(que); 2616266423Sjfv 2617266423Sjfv /* Next setup the HMC RX Context */ 2618266423Sjfv if (vsi->max_frame_size <= 2048) 2619266423Sjfv rxr->mbuf_sz = MCLBYTES; 2620266423Sjfv else 2621266423Sjfv rxr->mbuf_sz = MJUMPAGESIZE; 2622266423Sjfv 2623266423Sjfv u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len; 2624266423Sjfv 2625266423Sjfv /* Set up an RX context for the HMC */ 2626266423Sjfv memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq)); 2627266423Sjfv rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT; 2628266423Sjfv /* ignore header split for now */ 2629266423Sjfv rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; 2630266423Sjfv rctx.rxmax = (vsi->max_frame_size < max_rxmax) ? 2631266423Sjfv vsi->max_frame_size : max_rxmax; 2632266423Sjfv rctx.dtype = 0; 2633266423Sjfv rctx.dsize = 1; /* do 32byte descriptors */ 2634266423Sjfv rctx.hsplit_0 = 0; /* no HDR split initially */ 2635266423Sjfv rctx.base = (rxr->dma.pa/128); 2636266423Sjfv rctx.qlen = que->num_desc; 2637266423Sjfv rctx.tphrdesc_ena = 1; 2638266423Sjfv rctx.tphwdesc_ena = 1; 2639266423Sjfv rctx.tphdata_ena = 0; 2640266423Sjfv rctx.tphhead_ena = 0; 2641266423Sjfv rctx.lrxqthresh = 2; 2642266423Sjfv rctx.crcstrip = 1; 2643266423Sjfv rctx.l2tsel = 1; 2644266423Sjfv rctx.showiv = 1; 2645266423Sjfv rctx.fc_ena = 0; 2646266423Sjfv rctx.prefena = 1; 2647266423Sjfv 2648266423Sjfv err = i40e_clear_lan_rx_queue_context(hw, i); 2649266423Sjfv if (err) { 2650266423Sjfv device_printf(dev, 2651266423Sjfv "Unable to clear RX context %d\n", i); 2652266423Sjfv break; 2653266423Sjfv } 2654266423Sjfv err = i40e_set_lan_rx_queue_context(hw, i, &rctx); 2655266423Sjfv if (err) { 2656266423Sjfv device_printf(dev, "Unable to set RX context %d\n", i); 2657266423Sjfv break; 2658266423Sjfv } 2659270346Sjfv err = ixl_init_rx_ring(que); 2660266423Sjfv if (err) { 2661266423Sjfv device_printf(dev, "Fail in init_rx_ring %d\n", i); 2662266423Sjfv break; 2663266423Sjfv } 2664266423Sjfv wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0); 2665266423Sjfv wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1); 2666266423Sjfv } 2667266423Sjfv return (err); 2668266423Sjfv} 2669266423Sjfv 2670266423Sjfv 2671266423Sjfv/********************************************************************* 2672266423Sjfv * 2673266423Sjfv * Free all VSI structs. 2674266423Sjfv * 2675266423Sjfv **********************************************************************/ 2676266423Sjfvvoid 2677270346Sjfvixl_free_vsi(struct ixl_vsi *vsi) 2678266423Sjfv{ 2679270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 2680270346Sjfv struct ixl_queue *que = vsi->queues; 2681270346Sjfv struct ixl_mac_filter *f; 2682266423Sjfv 2683266423Sjfv /* Free station queues */ 2684266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2685266423Sjfv struct tx_ring *txr = &que->txr; 2686266423Sjfv struct rx_ring *rxr = &que->rxr; 2687266423Sjfv 2688266423Sjfv if (!mtx_initialized(&txr->mtx)) /* uninitialized */ 2689266423Sjfv continue; 2690270346Sjfv IXL_TX_LOCK(txr); 2691270346Sjfv ixl_free_que_tx(que); 2692266423Sjfv if (txr->base) 2693271834Sbz i40e_free_dma_mem(&pf->hw, &txr->dma); 2694270346Sjfv IXL_TX_UNLOCK(txr); 2695270346Sjfv IXL_TX_LOCK_DESTROY(txr); 2696266423Sjfv 2697266423Sjfv if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ 2698266423Sjfv continue; 2699270346Sjfv IXL_RX_LOCK(rxr); 2700270346Sjfv ixl_free_que_rx(que); 2701266423Sjfv if (rxr->base) 2702271834Sbz i40e_free_dma_mem(&pf->hw, &rxr->dma); 2703270346Sjfv IXL_RX_UNLOCK(rxr); 2704270346Sjfv IXL_RX_LOCK_DESTROY(rxr); 2705266423Sjfv 2706266423Sjfv } 2707266423Sjfv free(vsi->queues, M_DEVBUF); 2708266423Sjfv 2709266423Sjfv /* Free VSI filter list */ 2710266423Sjfv while (!SLIST_EMPTY(&vsi->ftl)) { 2711266423Sjfv f = SLIST_FIRST(&vsi->ftl); 2712266423Sjfv SLIST_REMOVE_HEAD(&vsi->ftl, next); 2713266423Sjfv free(f, M_DEVBUF); 2714266423Sjfv } 2715266423Sjfv} 2716266423Sjfv 2717266423Sjfv 2718266423Sjfv/********************************************************************* 2719266423Sjfv * 2720266423Sjfv * Allocate memory for the VSI (virtual station interface) and their 2721266423Sjfv * associated queues, rings and the descriptors associated with each, 2722266423Sjfv * called only once at attach. 2723266423Sjfv * 2724266423Sjfv **********************************************************************/ 2725266423Sjfvstatic int 2726270346Sjfvixl_setup_stations(struct ixl_pf *pf) 2727266423Sjfv{ 2728266423Sjfv device_t dev = pf->dev; 2729270346Sjfv struct ixl_vsi *vsi; 2730270346Sjfv struct ixl_queue *que; 2731266423Sjfv struct tx_ring *txr; 2732266423Sjfv struct rx_ring *rxr; 2733266423Sjfv int rsize, tsize; 2734266423Sjfv int error = I40E_SUCCESS; 2735266423Sjfv 2736266423Sjfv vsi = &pf->vsi; 2737266423Sjfv vsi->back = (void *)pf; 2738266423Sjfv vsi->hw = &pf->hw; 2739266423Sjfv vsi->id = 0; 2740266423Sjfv vsi->num_vlans = 0; 2741266423Sjfv 2742266423Sjfv /* Get memory for the station queues */ 2743266423Sjfv if (!(vsi->queues = 2744270346Sjfv (struct ixl_queue *) malloc(sizeof(struct ixl_queue) * 2745266423Sjfv vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { 2746266423Sjfv device_printf(dev, "Unable to allocate queue memory\n"); 2747266423Sjfv error = ENOMEM; 2748266423Sjfv goto early; 2749266423Sjfv } 2750266423Sjfv 2751266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 2752266423Sjfv que = &vsi->queues[i]; 2753270346Sjfv que->num_desc = ixl_ringsz; 2754266423Sjfv que->me = i; 2755266423Sjfv que->vsi = vsi; 2756269198Sjfv /* mark the queue as active */ 2757269198Sjfv vsi->active_queues |= (u64)1 << que->me; 2758266423Sjfv txr = &que->txr; 2759266423Sjfv txr->que = que; 2760269198Sjfv txr->tail = I40E_QTX_TAIL(que->me); 2761266423Sjfv 2762266423Sjfv /* Initialize the TX lock */ 2763266423Sjfv snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", 2764266423Sjfv device_get_nameunit(dev), que->me); 2765266423Sjfv mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF); 2766266423Sjfv /* Create the TX descriptor ring */ 2767269198Sjfv tsize = roundup2((que->num_desc * 2768269198Sjfv sizeof(struct i40e_tx_desc)) + 2769269198Sjfv sizeof(u32), DBA_ALIGN); 2770271834Sbz if (i40e_allocate_dma_mem(&pf->hw, 2771271834Sbz &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) { 2772266423Sjfv device_printf(dev, 2773266423Sjfv "Unable to allocate TX Descriptor memory\n"); 2774266423Sjfv error = ENOMEM; 2775266423Sjfv goto fail; 2776266423Sjfv } 2777266423Sjfv txr->base = (struct i40e_tx_desc *)txr->dma.va; 2778266423Sjfv bzero((void *)txr->base, tsize); 2779266423Sjfv /* Now allocate transmit soft structs for the ring */ 2780270346Sjfv if (ixl_allocate_tx_data(que)) { 2781266423Sjfv device_printf(dev, 2782266423Sjfv "Critical Failure setting up TX structures\n"); 2783266423Sjfv error = ENOMEM; 2784266423Sjfv goto fail; 2785266423Sjfv } 2786266423Sjfv /* Allocate a buf ring */ 2787266423Sjfv txr->br = buf_ring_alloc(4096, M_DEVBUF, 2788266423Sjfv M_WAITOK, &txr->mtx); 2789266423Sjfv if (txr->br == NULL) { 2790266423Sjfv device_printf(dev, 2791266423Sjfv "Critical Failure setting up TX buf ring\n"); 2792266423Sjfv error = ENOMEM; 2793266423Sjfv goto fail; 2794266423Sjfv } 2795266423Sjfv 2796266423Sjfv /* 2797266423Sjfv * Next the RX queues... 2798266423Sjfv */ 2799266423Sjfv rsize = roundup2(que->num_desc * 2800266423Sjfv sizeof(union i40e_rx_desc), DBA_ALIGN); 2801266423Sjfv rxr = &que->rxr; 2802266423Sjfv rxr->que = que; 2803269198Sjfv rxr->tail = I40E_QRX_TAIL(que->me); 2804266423Sjfv 2805266423Sjfv /* Initialize the RX side lock */ 2806266423Sjfv snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", 2807266423Sjfv device_get_nameunit(dev), que->me); 2808266423Sjfv mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF); 2809266423Sjfv 2810271834Sbz if (i40e_allocate_dma_mem(&pf->hw, 2811271834Sbz &rxr->dma, i40e_mem_reserved, rsize, 4096)) { 2812266423Sjfv device_printf(dev, 2813266423Sjfv "Unable to allocate RX Descriptor memory\n"); 2814266423Sjfv error = ENOMEM; 2815266423Sjfv goto fail; 2816266423Sjfv } 2817266423Sjfv rxr->base = (union i40e_rx_desc *)rxr->dma.va; 2818266423Sjfv bzero((void *)rxr->base, rsize); 2819266423Sjfv 2820266423Sjfv /* Allocate receive soft structs for the ring*/ 2821270346Sjfv if (ixl_allocate_rx_data(que)) { 2822266423Sjfv device_printf(dev, 2823266423Sjfv "Critical Failure setting up receive structs\n"); 2824266423Sjfv error = ENOMEM; 2825266423Sjfv goto fail; 2826266423Sjfv } 2827266423Sjfv } 2828266423Sjfv 2829266423Sjfv return (0); 2830266423Sjfv 2831266423Sjfvfail: 2832266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 2833266423Sjfv que = &vsi->queues[i]; 2834266423Sjfv rxr = &que->rxr; 2835266423Sjfv txr = &que->txr; 2836266423Sjfv if (rxr->base) 2837271834Sbz i40e_free_dma_mem(&pf->hw, &rxr->dma); 2838266423Sjfv if (txr->base) 2839271834Sbz i40e_free_dma_mem(&pf->hw, &txr->dma); 2840266423Sjfv } 2841266423Sjfv 2842266423Sjfvearly: 2843266423Sjfv return (error); 2844266423Sjfv} 2845266423Sjfv 2846266423Sjfv/* 2847266423Sjfv** Provide a update to the queue RX 2848266423Sjfv** interrupt moderation value. 2849266423Sjfv*/ 2850266423Sjfvstatic void 2851270346Sjfvixl_set_queue_rx_itr(struct ixl_queue *que) 2852266423Sjfv{ 2853270346Sjfv struct ixl_vsi *vsi = que->vsi; 2854266423Sjfv struct i40e_hw *hw = vsi->hw; 2855266423Sjfv struct rx_ring *rxr = &que->rxr; 2856266423Sjfv u16 rx_itr; 2857266423Sjfv u16 rx_latency = 0; 2858266423Sjfv int rx_bytes; 2859266423Sjfv 2860266423Sjfv 2861266423Sjfv /* Idle, do nothing */ 2862266423Sjfv if (rxr->bytes == 0) 2863266423Sjfv return; 2864266423Sjfv 2865270346Sjfv if (ixl_dynamic_rx_itr) { 2866266423Sjfv rx_bytes = rxr->bytes/rxr->itr; 2867266423Sjfv rx_itr = rxr->itr; 2868266423Sjfv 2869266423Sjfv /* Adjust latency range */ 2870266423Sjfv switch (rxr->latency) { 2871270346Sjfv case IXL_LOW_LATENCY: 2872266423Sjfv if (rx_bytes > 10) { 2873270346Sjfv rx_latency = IXL_AVE_LATENCY; 2874270346Sjfv rx_itr = IXL_ITR_20K; 2875266423Sjfv } 2876266423Sjfv break; 2877270346Sjfv case IXL_AVE_LATENCY: 2878266423Sjfv if (rx_bytes > 20) { 2879270346Sjfv rx_latency = IXL_BULK_LATENCY; 2880270346Sjfv rx_itr = IXL_ITR_8K; 2881266423Sjfv } else if (rx_bytes <= 10) { 2882270346Sjfv rx_latency = IXL_LOW_LATENCY; 2883270346Sjfv rx_itr = IXL_ITR_100K; 2884266423Sjfv } 2885266423Sjfv break; 2886270346Sjfv case IXL_BULK_LATENCY: 2887266423Sjfv if (rx_bytes <= 20) { 2888270346Sjfv rx_latency = IXL_AVE_LATENCY; 2889270346Sjfv rx_itr = IXL_ITR_20K; 2890266423Sjfv } 2891266423Sjfv break; 2892266423Sjfv } 2893266423Sjfv 2894266423Sjfv rxr->latency = rx_latency; 2895266423Sjfv 2896266423Sjfv if (rx_itr != rxr->itr) { 2897266423Sjfv /* do an exponential smoothing */ 2898266423Sjfv rx_itr = (10 * rx_itr * rxr->itr) / 2899266423Sjfv ((9 * rx_itr) + rxr->itr); 2900270346Sjfv rxr->itr = rx_itr & IXL_MAX_ITR; 2901270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 2902266423Sjfv que->me), rxr->itr); 2903266423Sjfv } 2904266423Sjfv } else { /* We may have have toggled to non-dynamic */ 2905270346Sjfv if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) 2906270346Sjfv vsi->rx_itr_setting = ixl_rx_itr; 2907266423Sjfv /* Update the hardware if needed */ 2908266423Sjfv if (rxr->itr != vsi->rx_itr_setting) { 2909266423Sjfv rxr->itr = vsi->rx_itr_setting; 2910270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 2911266423Sjfv que->me), rxr->itr); 2912266423Sjfv } 2913266423Sjfv } 2914266423Sjfv rxr->bytes = 0; 2915266423Sjfv rxr->packets = 0; 2916266423Sjfv return; 2917266423Sjfv} 2918266423Sjfv 2919266423Sjfv 2920266423Sjfv/* 2921266423Sjfv** Provide a update to the queue TX 2922266423Sjfv** interrupt moderation value. 2923266423Sjfv*/ 2924266423Sjfvstatic void 2925270346Sjfvixl_set_queue_tx_itr(struct ixl_queue *que) 2926266423Sjfv{ 2927270346Sjfv struct ixl_vsi *vsi = que->vsi; 2928266423Sjfv struct i40e_hw *hw = vsi->hw; 2929266423Sjfv struct tx_ring *txr = &que->txr; 2930266423Sjfv u16 tx_itr; 2931266423Sjfv u16 tx_latency = 0; 2932266423Sjfv int tx_bytes; 2933266423Sjfv 2934266423Sjfv 2935266423Sjfv /* Idle, do nothing */ 2936266423Sjfv if (txr->bytes == 0) 2937266423Sjfv return; 2938266423Sjfv 2939270346Sjfv if (ixl_dynamic_tx_itr) { 2940266423Sjfv tx_bytes = txr->bytes/txr->itr; 2941266423Sjfv tx_itr = txr->itr; 2942266423Sjfv 2943266423Sjfv switch (txr->latency) { 2944270346Sjfv case IXL_LOW_LATENCY: 2945266423Sjfv if (tx_bytes > 10) { 2946270346Sjfv tx_latency = IXL_AVE_LATENCY; 2947270346Sjfv tx_itr = IXL_ITR_20K; 2948266423Sjfv } 2949266423Sjfv break; 2950270346Sjfv case IXL_AVE_LATENCY: 2951266423Sjfv if (tx_bytes > 20) { 2952270346Sjfv tx_latency = IXL_BULK_LATENCY; 2953270346Sjfv tx_itr = IXL_ITR_8K; 2954266423Sjfv } else if (tx_bytes <= 10) { 2955270346Sjfv tx_latency = IXL_LOW_LATENCY; 2956270346Sjfv tx_itr = IXL_ITR_100K; 2957266423Sjfv } 2958266423Sjfv break; 2959270346Sjfv case IXL_BULK_LATENCY: 2960266423Sjfv if (tx_bytes <= 20) { 2961270346Sjfv tx_latency = IXL_AVE_LATENCY; 2962270346Sjfv tx_itr = IXL_ITR_20K; 2963266423Sjfv } 2964266423Sjfv break; 2965266423Sjfv } 2966266423Sjfv 2967266423Sjfv txr->latency = tx_latency; 2968266423Sjfv 2969266423Sjfv if (tx_itr != txr->itr) { 2970266423Sjfv /* do an exponential smoothing */ 2971266423Sjfv tx_itr = (10 * tx_itr * txr->itr) / 2972266423Sjfv ((9 * tx_itr) + txr->itr); 2973270346Sjfv txr->itr = tx_itr & IXL_MAX_ITR; 2974270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 2975266423Sjfv que->me), txr->itr); 2976266423Sjfv } 2977266423Sjfv 2978266423Sjfv } else { /* We may have have toggled to non-dynamic */ 2979270346Sjfv if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC) 2980270346Sjfv vsi->tx_itr_setting = ixl_tx_itr; 2981266423Sjfv /* Update the hardware if needed */ 2982266423Sjfv if (txr->itr != vsi->tx_itr_setting) { 2983266423Sjfv txr->itr = vsi->tx_itr_setting; 2984270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 2985266423Sjfv que->me), txr->itr); 2986266423Sjfv } 2987266423Sjfv } 2988266423Sjfv txr->bytes = 0; 2989266423Sjfv txr->packets = 0; 2990266423Sjfv return; 2991266423Sjfv} 2992266423Sjfv 2993266423Sjfv 2994266423Sjfvstatic void 2995270346Sjfvixl_add_hw_stats(struct ixl_pf *pf) 2996266423Sjfv{ 2997266423Sjfv device_t dev = pf->dev; 2998270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2999270346Sjfv struct ixl_queue *queues = vsi->queues; 3000269198Sjfv struct i40e_eth_stats *vsi_stats = &vsi->eth_stats; 3001269198Sjfv struct i40e_hw_port_stats *pf_stats = &pf->stats; 3002266423Sjfv 3003266423Sjfv struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 3004266423Sjfv struct sysctl_oid *tree = device_get_sysctl_tree(dev); 3005266423Sjfv struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 3006266423Sjfv 3007266423Sjfv struct sysctl_oid *vsi_node, *queue_node; 3008266423Sjfv struct sysctl_oid_list *vsi_list, *queue_list; 3009266423Sjfv 3010269198Sjfv struct tx_ring *txr; 3011269198Sjfv struct rx_ring *rxr; 3012266423Sjfv 3013266423Sjfv /* Driver statistics */ 3014266423Sjfv SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 3015266423Sjfv CTLFLAG_RD, &pf->watchdog_events, 3016266423Sjfv "Watchdog timeouts"); 3017266423Sjfv SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq", 3018266423Sjfv CTLFLAG_RD, &pf->admin_irq, 3019266423Sjfv "Admin Queue IRQ Handled"); 3020266423Sjfv 3021266423Sjfv /* VSI statistics */ 3022266423Sjfv#define QUEUE_NAME_LEN 32 3023266423Sjfv char queue_namebuf[QUEUE_NAME_LEN]; 3024266423Sjfv 3025269198Sjfv // ERJ: Only one vsi now, re-do when >1 VSI enabled 3026269198Sjfv // snprintf(vsi_namebuf, QUEUE_NAME_LEN, "vsi%d", vsi->info.stat_counter_idx); 3027269198Sjfv vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "vsi", 3028269198Sjfv CTLFLAG_RD, NULL, "VSI-specific stats"); 3029266423Sjfv vsi_list = SYSCTL_CHILDREN(vsi_node); 3030266423Sjfv 3031270346Sjfv ixl_add_sysctls_eth_stats(ctx, vsi_list, vsi_stats); 3032266423Sjfv 3033266423Sjfv /* Queue statistics */ 3034266423Sjfv for (int q = 0; q < vsi->num_queues; q++) { 3035269198Sjfv snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); 3036266423Sjfv queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, OID_AUTO, queue_namebuf, 3037269198Sjfv CTLFLAG_RD, NULL, "Queue #"); 3038266423Sjfv queue_list = SYSCTL_CHILDREN(queue_node); 3039266423Sjfv 3040269198Sjfv txr = &(queues[q].txr); 3041269198Sjfv rxr = &(queues[q].rxr); 3042269198Sjfv 3043269198Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", 3044266423Sjfv CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), 3045266423Sjfv "m_defrag() failed"); 3046269198Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped", 3047266423Sjfv CTLFLAG_RD, &(queues[q].dropped_pkts), 3048266423Sjfv "Driver dropped packets"); 3049266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 3050266423Sjfv CTLFLAG_RD, &(queues[q].irqs), 3051266423Sjfv "irqs on this queue"); 3052269198Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", 3053266423Sjfv CTLFLAG_RD, &(queues[q].tso), 3054266423Sjfv "TSO"); 3055269198Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup", 3056266423Sjfv CTLFLAG_RD, &(queues[q].tx_dma_setup), 3057266423Sjfv "Driver tx dma failure in xmit"); 3058266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 3059266423Sjfv CTLFLAG_RD, &(txr->no_desc), 3060266423Sjfv "Queue No Descriptor Available"); 3061266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 3062266423Sjfv CTLFLAG_RD, &(txr->total_packets), 3063266423Sjfv "Queue Packets Transmitted"); 3064266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", 3065270346Sjfv CTLFLAG_RD, &(txr->tx_bytes), 3066266423Sjfv "Queue Bytes Transmitted"); 3067266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 3068266423Sjfv CTLFLAG_RD, &(rxr->rx_packets), 3069266423Sjfv "Queue Packets Received"); 3070266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 3071266423Sjfv CTLFLAG_RD, &(rxr->rx_bytes), 3072266423Sjfv "Queue Bytes Received"); 3073266423Sjfv } 3074266423Sjfv 3075266423Sjfv /* MAC stats */ 3076270346Sjfv ixl_add_sysctls_mac_stats(ctx, child, pf_stats); 3077266423Sjfv} 3078266423Sjfv 3079266423Sjfvstatic void 3080270346Sjfvixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx, 3081266423Sjfv struct sysctl_oid_list *child, 3082266423Sjfv struct i40e_eth_stats *eth_stats) 3083266423Sjfv{ 3084270346Sjfv struct ixl_sysctl_info ctls[] = 3085266423Sjfv { 3086266423Sjfv {ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, 3087266423Sjfv {ð_stats->rx_unicast, "ucast_pkts_rcvd", 3088266423Sjfv "Unicast Packets Received"}, 3089266423Sjfv {ð_stats->rx_multicast, "mcast_pkts_rcvd", 3090266423Sjfv "Multicast Packets Received"}, 3091266423Sjfv {ð_stats->rx_broadcast, "bcast_pkts_rcvd", 3092266423Sjfv "Broadcast Packets Received"}, 3093269198Sjfv {ð_stats->rx_discards, "rx_discards", "Discarded RX packets"}, 3094266423Sjfv {ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, 3095266423Sjfv {ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, 3096266423Sjfv {ð_stats->tx_multicast, "mcast_pkts_txd", 3097266423Sjfv "Multicast Packets Transmitted"}, 3098266423Sjfv {ð_stats->tx_broadcast, "bcast_pkts_txd", 3099266423Sjfv "Broadcast Packets Transmitted"}, 3100266423Sjfv // end 3101266423Sjfv {0,0,0} 3102266423Sjfv }; 3103266423Sjfv 3104270346Sjfv struct ixl_sysctl_info *entry = ctls; 3105266423Sjfv while (entry->stat != 0) 3106266423Sjfv { 3107266423Sjfv SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name, 3108266423Sjfv CTLFLAG_RD, entry->stat, 3109266423Sjfv entry->description); 3110266423Sjfv entry++; 3111266423Sjfv } 3112266423Sjfv} 3113266423Sjfv 3114266423Sjfvstatic void 3115270346Sjfvixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx, 3116266423Sjfv struct sysctl_oid_list *child, 3117266423Sjfv struct i40e_hw_port_stats *stats) 3118266423Sjfv{ 3119269198Sjfv struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", 3120266423Sjfv CTLFLAG_RD, NULL, "Mac Statistics"); 3121266423Sjfv struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node); 3122266423Sjfv 3123266423Sjfv struct i40e_eth_stats *eth_stats = &stats->eth; 3124270346Sjfv ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats); 3125266423Sjfv 3126270346Sjfv struct ixl_sysctl_info ctls[] = 3127266423Sjfv { 3128266423Sjfv {&stats->crc_errors, "crc_errors", "CRC Errors"}, 3129266423Sjfv {&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"}, 3130266423Sjfv {&stats->mac_local_faults, "local_faults", "MAC Local Faults"}, 3131266423Sjfv {&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"}, 3132266423Sjfv {&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"}, 3133266423Sjfv /* Packet Reception Stats */ 3134266423Sjfv {&stats->rx_size_64, "rx_frames_64", "64 byte frames received"}, 3135266423Sjfv {&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"}, 3136266423Sjfv {&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"}, 3137266423Sjfv {&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"}, 3138266423Sjfv {&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"}, 3139266423Sjfv {&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"}, 3140266423Sjfv {&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"}, 3141266423Sjfv {&stats->rx_undersize, "rx_undersize", "Undersized packets received"}, 3142266423Sjfv {&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"}, 3143266423Sjfv {&stats->rx_oversize, "rx_oversized", "Oversized packets received"}, 3144266423Sjfv {&stats->rx_jabber, "rx_jabber", "Received Jabber"}, 3145266423Sjfv {&stats->checksum_error, "checksum_errors", "Checksum Errors"}, 3146266423Sjfv /* Packet Transmission Stats */ 3147266423Sjfv {&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"}, 3148266423Sjfv {&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"}, 3149266423Sjfv {&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"}, 3150266423Sjfv {&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"}, 3151266423Sjfv {&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"}, 3152266423Sjfv {&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"}, 3153266423Sjfv {&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"}, 3154266423Sjfv /* Flow control */ 3155266423Sjfv {&stats->link_xon_tx, "xon_txd", "Link XON transmitted"}, 3156266423Sjfv {&stats->link_xon_rx, "xon_recvd", "Link XON received"}, 3157266423Sjfv {&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"}, 3158266423Sjfv {&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"}, 3159266423Sjfv /* End */ 3160266423Sjfv {0,0,0} 3161266423Sjfv }; 3162266423Sjfv 3163270346Sjfv struct ixl_sysctl_info *entry = ctls; 3164266423Sjfv while (entry->stat != 0) 3165266423Sjfv { 3166266423Sjfv SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name, 3167266423Sjfv CTLFLAG_RD, entry->stat, 3168266423Sjfv entry->description); 3169266423Sjfv entry++; 3170266423Sjfv } 3171266423Sjfv} 3172266423Sjfv 3173266423Sjfv/* 3174270346Sjfv** ixl_config_rss - setup RSS 3175266423Sjfv** - note this is done for the single vsi 3176266423Sjfv*/ 3177270346Sjfvstatic void ixl_config_rss(struct ixl_vsi *vsi) 3178266423Sjfv{ 3179270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 3180266423Sjfv struct i40e_hw *hw = vsi->hw; 3181266423Sjfv u32 lut = 0; 3182277084Sjfv u64 set_hena = 0, hena; 3183277084Sjfv int i, j, que_id; 3184277084Sjfv#ifdef RSS 3185277084Sjfv u32 rss_hash_config; 3186277084Sjfv u32 rss_seed[IXL_KEYSZ]; 3187277084Sjfv#else 3188277084Sjfv u32 rss_seed[IXL_KEYSZ] = {0x41b01687, 3189277084Sjfv 0x183cfd8c, 0xce880440, 0x580cbc3c, 3190277084Sjfv 0x35897377, 0x328b25e1, 0x4fa98922, 3191277084Sjfv 0xb7d90c14, 0xd5bad70d, 0xcd15a2c1}; 3192277084Sjfv#endif 3193266423Sjfv 3194277084Sjfv#ifdef RSS 3195277084Sjfv /* Fetch the configured RSS key */ 3196277084Sjfv rss_getkey((uint8_t *) &rss_seed); 3197277084Sjfv#endif 3198266423Sjfv 3199266423Sjfv /* Fill out hash function seed */ 3200277084Sjfv for (i = 0; i < IXL_KEYSZ; i++) 3201277084Sjfv wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]); 3202266423Sjfv 3203266423Sjfv /* Enable PCTYPES for RSS: */ 3204277084Sjfv#ifdef RSS 3205277084Sjfv rss_hash_config = rss_gethashconfig(); 3206277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 3207277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); 3208277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 3209277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); 3210277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 3211277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP); 3212277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 3213277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); 3214279033Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 3215277151Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); 3216277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 3217277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); 3218277084Sjfv if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 3219277084Sjfv set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP); 3220277084Sjfv#else 3221266423Sjfv set_hena = 3222266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | 3223266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | 3224266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | 3225266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | 3226266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | 3227266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | 3228266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | 3229266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | 3230266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | 3231266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | 3232266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD); 3233277084Sjfv#endif 3234266423Sjfv hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) | 3235266423Sjfv ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32); 3236266423Sjfv hena |= set_hena; 3237266423Sjfv wr32(hw, I40E_PFQF_HENA(0), (u32)hena); 3238266423Sjfv wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); 3239266423Sjfv 3240266423Sjfv /* Populate the LUT with max no. of queues in round robin fashion */ 3241266423Sjfv for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) { 3242266423Sjfv if (j == vsi->num_queues) 3243266423Sjfv j = 0; 3244277084Sjfv#ifdef RSS 3245277084Sjfv /* 3246277084Sjfv * Fetch the RSS bucket id for the given indirection entry. 3247277084Sjfv * Cap it at the number of configured buckets (which is 3248277084Sjfv * num_queues.) 3249277084Sjfv */ 3250277084Sjfv que_id = rss_get_indirection_to_bucket(i); 3251277262Sjfv que_id = que_id % vsi->num_queues; 3252277084Sjfv#else 3253277084Sjfv que_id = j; 3254277084Sjfv#endif 3255266423Sjfv /* lut = 4-byte sliding window of 4 lut entries */ 3256277084Sjfv lut = (lut << 8) | (que_id & 3257266423Sjfv ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1)); 3258266423Sjfv /* On i = 3, we have 4 entries in lut; write to the register */ 3259266423Sjfv if ((i & 3) == 3) 3260266423Sjfv wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); 3261266423Sjfv } 3262270346Sjfv ixl_flush(hw); 3263266423Sjfv} 3264266423Sjfv 3265266423Sjfv 3266266423Sjfv/* 3267266423Sjfv** This routine is run via an vlan config EVENT, 3268266423Sjfv** it enables us to use the HW Filter table since 3269266423Sjfv** we can get the vlan id. This just creates the 3270266423Sjfv** entry in the soft version of the VFTA, init will 3271266423Sjfv** repopulate the real table. 3272266423Sjfv*/ 3273266423Sjfvstatic void 3274270346Sjfvixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3275266423Sjfv{ 3276270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 3277266423Sjfv struct i40e_hw *hw = vsi->hw; 3278270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 3279266423Sjfv 3280266423Sjfv if (ifp->if_softc != arg) /* Not our event */ 3281266423Sjfv return; 3282266423Sjfv 3283266423Sjfv if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3284266423Sjfv return; 3285266423Sjfv 3286270346Sjfv IXL_PF_LOCK(pf); 3287266423Sjfv ++vsi->num_vlans; 3288270346Sjfv ixl_add_filter(vsi, hw->mac.addr, vtag); 3289270346Sjfv IXL_PF_UNLOCK(pf); 3290266423Sjfv} 3291266423Sjfv 3292266423Sjfv/* 3293266423Sjfv** This routine is run via an vlan 3294266423Sjfv** unconfig EVENT, remove our entry 3295266423Sjfv** in the soft vfta. 3296266423Sjfv*/ 3297266423Sjfvstatic void 3298270346Sjfvixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3299266423Sjfv{ 3300270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 3301266423Sjfv struct i40e_hw *hw = vsi->hw; 3302270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 3303266423Sjfv 3304266423Sjfv if (ifp->if_softc != arg) 3305266423Sjfv return; 3306266423Sjfv 3307266423Sjfv if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3308266423Sjfv return; 3309266423Sjfv 3310270346Sjfv IXL_PF_LOCK(pf); 3311266423Sjfv --vsi->num_vlans; 3312270346Sjfv ixl_del_filter(vsi, hw->mac.addr, vtag); 3313270346Sjfv IXL_PF_UNLOCK(pf); 3314266423Sjfv} 3315266423Sjfv 3316266423Sjfv/* 3317266423Sjfv** This routine updates vlan filters, called by init 3318266423Sjfv** it scans the filter table and then updates the hw 3319266423Sjfv** after a soft reset. 3320266423Sjfv*/ 3321266423Sjfvstatic void 3322270346Sjfvixl_setup_vlan_filters(struct ixl_vsi *vsi) 3323266423Sjfv{ 3324270346Sjfv struct ixl_mac_filter *f; 3325266423Sjfv int cnt = 0, flags; 3326266423Sjfv 3327266423Sjfv if (vsi->num_vlans == 0) 3328266423Sjfv return; 3329266423Sjfv /* 3330266423Sjfv ** Scan the filter list for vlan entries, 3331266423Sjfv ** mark them for addition and then call 3332266423Sjfv ** for the AQ update. 3333266423Sjfv */ 3334266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 3335270346Sjfv if (f->flags & IXL_FILTER_VLAN) { 3336266423Sjfv f->flags |= 3337270346Sjfv (IXL_FILTER_ADD | 3338270346Sjfv IXL_FILTER_USED); 3339266423Sjfv cnt++; 3340266423Sjfv } 3341266423Sjfv } 3342266423Sjfv if (cnt == 0) { 3343266423Sjfv printf("setup vlan: no filters found!\n"); 3344266423Sjfv return; 3345266423Sjfv } 3346270346Sjfv flags = IXL_FILTER_VLAN; 3347270346Sjfv flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 3348270346Sjfv ixl_add_hw_filters(vsi, flags, cnt); 3349266423Sjfv return; 3350266423Sjfv} 3351266423Sjfv 3352266423Sjfv/* 3353266423Sjfv** Initialize filter list and add filters that the hardware 3354266423Sjfv** needs to know about. 3355266423Sjfv*/ 3356266423Sjfvstatic void 3357270346Sjfvixl_init_filters(struct ixl_vsi *vsi) 3358266423Sjfv{ 3359269198Sjfv /* Add broadcast address */ 3360269198Sjfv u8 bc[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 3361270346Sjfv ixl_add_filter(vsi, bc, IXL_VLAN_ANY); 3362266423Sjfv} 3363266423Sjfv 3364266423Sjfv/* 3365266423Sjfv** This routine adds mulicast filters 3366266423Sjfv*/ 3367266423Sjfvstatic void 3368270346Sjfvixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr) 3369266423Sjfv{ 3370270346Sjfv struct ixl_mac_filter *f; 3371266423Sjfv 3372266423Sjfv /* Does one already exist */ 3373270346Sjfv f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 3374266423Sjfv if (f != NULL) 3375266423Sjfv return; 3376266423Sjfv 3377270346Sjfv f = ixl_get_filter(vsi); 3378266423Sjfv if (f == NULL) { 3379266423Sjfv printf("WARNING: no filter available!!\n"); 3380266423Sjfv return; 3381266423Sjfv } 3382266423Sjfv bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 3383270346Sjfv f->vlan = IXL_VLAN_ANY; 3384270346Sjfv f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED 3385270346Sjfv | IXL_FILTER_MC); 3386266423Sjfv 3387266423Sjfv return; 3388266423Sjfv} 3389266423Sjfv 3390266423Sjfv/* 3391266423Sjfv** This routine adds macvlan filters 3392266423Sjfv*/ 3393266423Sjfvstatic void 3394270346Sjfvixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 3395266423Sjfv{ 3396270346Sjfv struct ixl_mac_filter *f, *tmp; 3397266423Sjfv device_t dev = vsi->dev; 3398266423Sjfv 3399270346Sjfv DEBUGOUT("ixl_add_filter: begin"); 3400266423Sjfv 3401266423Sjfv /* Does one already exist */ 3402270346Sjfv f = ixl_find_filter(vsi, macaddr, vlan); 3403266423Sjfv if (f != NULL) 3404266423Sjfv return; 3405266423Sjfv /* 3406266423Sjfv ** Is this the first vlan being registered, if so we 3407266423Sjfv ** need to remove the ANY filter that indicates we are 3408266423Sjfv ** not in a vlan, and replace that with a 0 filter. 3409266423Sjfv */ 3410270346Sjfv if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) { 3411270346Sjfv tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 3412266423Sjfv if (tmp != NULL) { 3413270346Sjfv ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY); 3414270346Sjfv ixl_add_filter(vsi, macaddr, 0); 3415266423Sjfv } 3416266423Sjfv } 3417266423Sjfv 3418270346Sjfv f = ixl_get_filter(vsi); 3419266423Sjfv if (f == NULL) { 3420266423Sjfv device_printf(dev, "WARNING: no filter available!!\n"); 3421266423Sjfv return; 3422266423Sjfv } 3423266423Sjfv bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 3424266423Sjfv f->vlan = vlan; 3425270346Sjfv f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 3426270346Sjfv if (f->vlan != IXL_VLAN_ANY) 3427270346Sjfv f->flags |= IXL_FILTER_VLAN; 3428266423Sjfv 3429270346Sjfv ixl_add_hw_filters(vsi, f->flags, 1); 3430266423Sjfv return; 3431266423Sjfv} 3432266423Sjfv 3433266423Sjfvstatic void 3434270346Sjfvixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 3435266423Sjfv{ 3436270346Sjfv struct ixl_mac_filter *f; 3437266423Sjfv 3438270346Sjfv f = ixl_find_filter(vsi, macaddr, vlan); 3439266423Sjfv if (f == NULL) 3440266423Sjfv return; 3441266423Sjfv 3442270346Sjfv f->flags |= IXL_FILTER_DEL; 3443270346Sjfv ixl_del_hw_filters(vsi, 1); 3444266423Sjfv 3445266423Sjfv /* Check if this is the last vlan removal */ 3446270346Sjfv if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) { 3447266423Sjfv /* Switch back to a non-vlan filter */ 3448270346Sjfv ixl_del_filter(vsi, macaddr, 0); 3449270346Sjfv ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY); 3450266423Sjfv } 3451266423Sjfv return; 3452266423Sjfv} 3453266423Sjfv 3454266423Sjfv/* 3455266423Sjfv** Find the filter with both matching mac addr and vlan id 3456266423Sjfv*/ 3457270346Sjfvstatic struct ixl_mac_filter * 3458270346Sjfvixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 3459266423Sjfv{ 3460270346Sjfv struct ixl_mac_filter *f; 3461266423Sjfv bool match = FALSE; 3462266423Sjfv 3463266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 3464266423Sjfv if (!cmp_etheraddr(f->macaddr, macaddr)) 3465266423Sjfv continue; 3466266423Sjfv if (f->vlan == vlan) { 3467266423Sjfv match = TRUE; 3468266423Sjfv break; 3469266423Sjfv } 3470266423Sjfv } 3471266423Sjfv 3472266423Sjfv if (!match) 3473266423Sjfv f = NULL; 3474266423Sjfv return (f); 3475266423Sjfv} 3476266423Sjfv 3477266423Sjfv/* 3478266423Sjfv** This routine takes additions to the vsi filter 3479266423Sjfv** table and creates an Admin Queue call to create 3480266423Sjfv** the filters in the hardware. 3481266423Sjfv*/ 3482266423Sjfvstatic void 3483270346Sjfvixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt) 3484266423Sjfv{ 3485266423Sjfv struct i40e_aqc_add_macvlan_element_data *a, *b; 3486270346Sjfv struct ixl_mac_filter *f; 3487266423Sjfv struct i40e_hw *hw = vsi->hw; 3488266423Sjfv device_t dev = vsi->dev; 3489266423Sjfv int err, j = 0; 3490266423Sjfv 3491266423Sjfv a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt, 3492266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 3493266423Sjfv if (a == NULL) { 3494277084Sjfv device_printf(dev, "add_hw_filters failed to get memory\n"); 3495266423Sjfv return; 3496266423Sjfv } 3497266423Sjfv 3498266423Sjfv /* 3499266423Sjfv ** Scan the filter list, each time we find one 3500266423Sjfv ** we add it to the admin queue array and turn off 3501266423Sjfv ** the add bit. 3502266423Sjfv */ 3503266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 3504266423Sjfv if (f->flags == flags) { 3505266423Sjfv b = &a[j]; // a pox on fvl long names :) 3506266423Sjfv bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN); 3507266423Sjfv b->vlan_tag = 3508270346Sjfv (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan); 3509266423Sjfv b->flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH; 3510270346Sjfv f->flags &= ~IXL_FILTER_ADD; 3511266423Sjfv j++; 3512266423Sjfv } 3513266423Sjfv if (j == cnt) 3514266423Sjfv break; 3515266423Sjfv } 3516266423Sjfv if (j > 0) { 3517266423Sjfv err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); 3518266423Sjfv if (err) 3519279033Sjfv device_printf(dev, "aq_add_macvlan err %d, " 3520279033Sjfv "aq_error %d\n", err, hw->aq.asq_last_status); 3521266423Sjfv else 3522266423Sjfv vsi->hw_filters_add += j; 3523266423Sjfv } 3524266423Sjfv free(a, M_DEVBUF); 3525266423Sjfv return; 3526266423Sjfv} 3527266423Sjfv 3528266423Sjfv/* 3529266423Sjfv** This routine takes removals in the vsi filter 3530266423Sjfv** table and creates an Admin Queue call to delete 3531266423Sjfv** the filters in the hardware. 3532266423Sjfv*/ 3533266423Sjfvstatic void 3534270346Sjfvixl_del_hw_filters(struct ixl_vsi *vsi, int cnt) 3535266423Sjfv{ 3536266423Sjfv struct i40e_aqc_remove_macvlan_element_data *d, *e; 3537266423Sjfv struct i40e_hw *hw = vsi->hw; 3538266423Sjfv device_t dev = vsi->dev; 3539270346Sjfv struct ixl_mac_filter *f, *f_temp; 3540266423Sjfv int err, j = 0; 3541266423Sjfv 3542270346Sjfv DEBUGOUT("ixl_del_hw_filters: begin\n"); 3543266423Sjfv 3544266423Sjfv d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt, 3545266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 3546266423Sjfv if (d == NULL) { 3547266423Sjfv printf("del hw filter failed to get memory\n"); 3548266423Sjfv return; 3549266423Sjfv } 3550266423Sjfv 3551266423Sjfv SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) { 3552270346Sjfv if (f->flags & IXL_FILTER_DEL) { 3553266423Sjfv e = &d[j]; // a pox on fvl long names :) 3554266423Sjfv bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN); 3555270346Sjfv e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan); 3556266423Sjfv e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; 3557266423Sjfv /* delete entry from vsi list */ 3558270346Sjfv SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next); 3559266423Sjfv free(f, M_DEVBUF); 3560266423Sjfv j++; 3561266423Sjfv } 3562266423Sjfv if (j == cnt) 3563266423Sjfv break; 3564266423Sjfv } 3565266423Sjfv if (j > 0) { 3566266423Sjfv err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); 3567266423Sjfv /* NOTE: returns ENOENT every time but seems to work fine, 3568266423Sjfv so we'll ignore that specific error. */ 3569277084Sjfv // TODO: Does this still occur on current firmwares? 3570266423Sjfv if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { 3571266423Sjfv int sc = 0; 3572266423Sjfv for (int i = 0; i < j; i++) 3573266423Sjfv sc += (!d[i].error_code); 3574266423Sjfv vsi->hw_filters_del += sc; 3575266423Sjfv device_printf(dev, 3576266423Sjfv "Failed to remove %d/%d filters, aq error %d\n", 3577266423Sjfv j - sc, j, hw->aq.asq_last_status); 3578266423Sjfv } else 3579266423Sjfv vsi->hw_filters_del += j; 3580266423Sjfv } 3581266423Sjfv free(d, M_DEVBUF); 3582266423Sjfv 3583270346Sjfv DEBUGOUT("ixl_del_hw_filters: end\n"); 3584266423Sjfv return; 3585266423Sjfv} 3586266423Sjfv 3587266423Sjfv 3588266423Sjfvstatic void 3589270346Sjfvixl_enable_rings(struct ixl_vsi *vsi) 3590266423Sjfv{ 3591266423Sjfv struct i40e_hw *hw = vsi->hw; 3592266423Sjfv u32 reg; 3593266423Sjfv 3594266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 3595266423Sjfv i40e_pre_tx_queue_cfg(hw, i, TRUE); 3596266423Sjfv 3597266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3598266423Sjfv reg |= I40E_QTX_ENA_QENA_REQ_MASK | 3599266423Sjfv I40E_QTX_ENA_QENA_STAT_MASK; 3600266423Sjfv wr32(hw, I40E_QTX_ENA(i), reg); 3601266423Sjfv /* Verify the enable took */ 3602266423Sjfv for (int j = 0; j < 10; j++) { 3603266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3604266423Sjfv if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 3605266423Sjfv break; 3606266423Sjfv i40e_msec_delay(10); 3607266423Sjfv } 3608266423Sjfv if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) 3609266423Sjfv printf("TX queue %d disabled!\n", i); 3610266423Sjfv 3611266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3612266423Sjfv reg |= I40E_QRX_ENA_QENA_REQ_MASK | 3613266423Sjfv I40E_QRX_ENA_QENA_STAT_MASK; 3614266423Sjfv wr32(hw, I40E_QRX_ENA(i), reg); 3615266423Sjfv /* Verify the enable took */ 3616266423Sjfv for (int j = 0; j < 10; j++) { 3617266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3618266423Sjfv if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 3619266423Sjfv break; 3620266423Sjfv i40e_msec_delay(10); 3621266423Sjfv } 3622266423Sjfv if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) 3623266423Sjfv printf("RX queue %d disabled!\n", i); 3624266423Sjfv } 3625266423Sjfv} 3626266423Sjfv 3627266423Sjfvstatic void 3628270346Sjfvixl_disable_rings(struct ixl_vsi *vsi) 3629266423Sjfv{ 3630266423Sjfv struct i40e_hw *hw = vsi->hw; 3631266423Sjfv u32 reg; 3632266423Sjfv 3633266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 3634266423Sjfv i40e_pre_tx_queue_cfg(hw, i, FALSE); 3635266423Sjfv i40e_usec_delay(500); 3636266423Sjfv 3637266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3638266423Sjfv reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; 3639266423Sjfv wr32(hw, I40E_QTX_ENA(i), reg); 3640266423Sjfv /* Verify the disable took */ 3641266423Sjfv for (int j = 0; j < 10; j++) { 3642266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3643266423Sjfv if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK)) 3644266423Sjfv break; 3645266423Sjfv i40e_msec_delay(10); 3646266423Sjfv } 3647266423Sjfv if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 3648266423Sjfv printf("TX queue %d still enabled!\n", i); 3649266423Sjfv 3650266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3651266423Sjfv reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; 3652266423Sjfv wr32(hw, I40E_QRX_ENA(i), reg); 3653266423Sjfv /* Verify the disable took */ 3654266423Sjfv for (int j = 0; j < 10; j++) { 3655266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3656266423Sjfv if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK)) 3657266423Sjfv break; 3658266423Sjfv i40e_msec_delay(10); 3659266423Sjfv } 3660266423Sjfv if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 3661266423Sjfv printf("RX queue %d still enabled!\n", i); 3662266423Sjfv } 3663266423Sjfv} 3664266423Sjfv 3665269198Sjfv/** 3666270346Sjfv * ixl_handle_mdd_event 3667269198Sjfv * 3668269198Sjfv * Called from interrupt handler to identify possibly malicious vfs 3669269198Sjfv * (But also detects events from the PF, as well) 3670269198Sjfv **/ 3671270346Sjfvstatic void ixl_handle_mdd_event(struct ixl_pf *pf) 3672269198Sjfv{ 3673269198Sjfv struct i40e_hw *hw = &pf->hw; 3674269198Sjfv device_t dev = pf->dev; 3675269198Sjfv bool mdd_detected = false; 3676269198Sjfv bool pf_mdd_detected = false; 3677269198Sjfv u32 reg; 3678269198Sjfv 3679269198Sjfv /* find what triggered the MDD event */ 3680269198Sjfv reg = rd32(hw, I40E_GL_MDET_TX); 3681269198Sjfv if (reg & I40E_GL_MDET_TX_VALID_MASK) { 3682269198Sjfv u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >> 3683269198Sjfv I40E_GL_MDET_TX_PF_NUM_SHIFT; 3684269198Sjfv u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >> 3685269198Sjfv I40E_GL_MDET_TX_EVENT_SHIFT; 3686269198Sjfv u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >> 3687269198Sjfv I40E_GL_MDET_TX_QUEUE_SHIFT; 3688269198Sjfv device_printf(dev, 3689269198Sjfv "Malicious Driver Detection event 0x%02x" 3690269198Sjfv " on TX queue %d pf number 0x%02x\n", 3691269198Sjfv event, queue, pf_num); 3692269198Sjfv wr32(hw, I40E_GL_MDET_TX, 0xffffffff); 3693269198Sjfv mdd_detected = true; 3694269198Sjfv } 3695269198Sjfv reg = rd32(hw, I40E_GL_MDET_RX); 3696269198Sjfv if (reg & I40E_GL_MDET_RX_VALID_MASK) { 3697269198Sjfv u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >> 3698269198Sjfv I40E_GL_MDET_RX_FUNCTION_SHIFT; 3699269198Sjfv u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >> 3700269198Sjfv I40E_GL_MDET_RX_EVENT_SHIFT; 3701269198Sjfv u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >> 3702269198Sjfv I40E_GL_MDET_RX_QUEUE_SHIFT; 3703269198Sjfv device_printf(dev, 3704269198Sjfv "Malicious Driver Detection event 0x%02x" 3705269198Sjfv " on RX queue %d of function 0x%02x\n", 3706269198Sjfv event, queue, func); 3707269198Sjfv wr32(hw, I40E_GL_MDET_RX, 0xffffffff); 3708269198Sjfv mdd_detected = true; 3709269198Sjfv } 3710269198Sjfv 3711269198Sjfv if (mdd_detected) { 3712269198Sjfv reg = rd32(hw, I40E_PF_MDET_TX); 3713269198Sjfv if (reg & I40E_PF_MDET_TX_VALID_MASK) { 3714269198Sjfv wr32(hw, I40E_PF_MDET_TX, 0xFFFF); 3715269198Sjfv device_printf(dev, 3716269198Sjfv "MDD TX event is for this function 0x%08x", 3717269198Sjfv reg); 3718269198Sjfv pf_mdd_detected = true; 3719269198Sjfv } 3720269198Sjfv reg = rd32(hw, I40E_PF_MDET_RX); 3721269198Sjfv if (reg & I40E_PF_MDET_RX_VALID_MASK) { 3722269198Sjfv wr32(hw, I40E_PF_MDET_RX, 0xFFFF); 3723269198Sjfv device_printf(dev, 3724269198Sjfv "MDD RX event is for this function 0x%08x", 3725269198Sjfv reg); 3726269198Sjfv pf_mdd_detected = true; 3727269198Sjfv } 3728269198Sjfv } 3729269198Sjfv 3730269198Sjfv /* re-enable mdd interrupt cause */ 3731269198Sjfv reg = rd32(hw, I40E_PFINT_ICR0_ENA); 3732269198Sjfv reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 3733269198Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 3734270346Sjfv ixl_flush(hw); 3735269198Sjfv} 3736269198Sjfv 3737266423Sjfvstatic void 3738270346Sjfvixl_enable_intr(struct ixl_vsi *vsi) 3739266423Sjfv{ 3740266423Sjfv struct i40e_hw *hw = vsi->hw; 3741270346Sjfv struct ixl_queue *que = vsi->queues; 3742266423Sjfv 3743270346Sjfv if (ixl_enable_msix) { 3744270346Sjfv ixl_enable_adminq(hw); 3745266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) 3746270346Sjfv ixl_enable_queue(hw, que->me); 3747266423Sjfv } else 3748270346Sjfv ixl_enable_legacy(hw); 3749266423Sjfv} 3750266423Sjfv 3751266423Sjfvstatic void 3752270346Sjfvixl_disable_intr(struct ixl_vsi *vsi) 3753266423Sjfv{ 3754266423Sjfv struct i40e_hw *hw = vsi->hw; 3755270346Sjfv struct ixl_queue *que = vsi->queues; 3756266423Sjfv 3757270346Sjfv if (ixl_enable_msix) { 3758270346Sjfv ixl_disable_adminq(hw); 3759266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) 3760270346Sjfv ixl_disable_queue(hw, que->me); 3761266423Sjfv } else 3762270346Sjfv ixl_disable_legacy(hw); 3763266423Sjfv} 3764266423Sjfv 3765266423Sjfvstatic void 3766270346Sjfvixl_enable_adminq(struct i40e_hw *hw) 3767266423Sjfv{ 3768266423Sjfv u32 reg; 3769266423Sjfv 3770266423Sjfv reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 3771266423Sjfv I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 3772270346Sjfv (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 3773266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3774270346Sjfv ixl_flush(hw); 3775266423Sjfv return; 3776266423Sjfv} 3777266423Sjfv 3778266423Sjfvstatic void 3779270346Sjfvixl_disable_adminq(struct i40e_hw *hw) 3780266423Sjfv{ 3781266423Sjfv u32 reg; 3782266423Sjfv 3783270346Sjfv reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 3784266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3785266423Sjfv 3786266423Sjfv return; 3787266423Sjfv} 3788266423Sjfv 3789266423Sjfvstatic void 3790270346Sjfvixl_enable_queue(struct i40e_hw *hw, int id) 3791266423Sjfv{ 3792266423Sjfv u32 reg; 3793266423Sjfv 3794266423Sjfv reg = I40E_PFINT_DYN_CTLN_INTENA_MASK | 3795266423Sjfv I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | 3796270346Sjfv (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); 3797266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 3798266423Sjfv} 3799266423Sjfv 3800266423Sjfvstatic void 3801270346Sjfvixl_disable_queue(struct i40e_hw *hw, int id) 3802266423Sjfv{ 3803266423Sjfv u32 reg; 3804266423Sjfv 3805270346Sjfv reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; 3806266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 3807266423Sjfv 3808266423Sjfv return; 3809266423Sjfv} 3810266423Sjfv 3811266423Sjfvstatic void 3812270346Sjfvixl_enable_legacy(struct i40e_hw *hw) 3813266423Sjfv{ 3814266423Sjfv u32 reg; 3815266423Sjfv reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 3816266423Sjfv I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 3817270346Sjfv (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 3818266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3819266423Sjfv} 3820266423Sjfv 3821266423Sjfvstatic void 3822270346Sjfvixl_disable_legacy(struct i40e_hw *hw) 3823266423Sjfv{ 3824266423Sjfv u32 reg; 3825266423Sjfv 3826270346Sjfv reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 3827266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3828266423Sjfv 3829266423Sjfv return; 3830266423Sjfv} 3831266423Sjfv 3832266423Sjfvstatic void 3833270346Sjfvixl_update_stats_counters(struct ixl_pf *pf) 3834266423Sjfv{ 3835266423Sjfv struct i40e_hw *hw = &pf->hw; 3836270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 3837269198Sjfv 3838266423Sjfv struct i40e_hw_port_stats *nsd = &pf->stats; 3839266423Sjfv struct i40e_hw_port_stats *osd = &pf->stats_offsets; 3840266423Sjfv 3841266423Sjfv /* Update hw stats */ 3842270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port), 3843266423Sjfv pf->stat_offsets_loaded, 3844266423Sjfv &osd->crc_errors, &nsd->crc_errors); 3845270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port), 3846266423Sjfv pf->stat_offsets_loaded, 3847266423Sjfv &osd->illegal_bytes, &nsd->illegal_bytes); 3848270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port), 3849266423Sjfv I40E_GLPRT_GORCL(hw->port), 3850266423Sjfv pf->stat_offsets_loaded, 3851266423Sjfv &osd->eth.rx_bytes, &nsd->eth.rx_bytes); 3852270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port), 3853266423Sjfv I40E_GLPRT_GOTCL(hw->port), 3854266423Sjfv pf->stat_offsets_loaded, 3855266423Sjfv &osd->eth.tx_bytes, &nsd->eth.tx_bytes); 3856270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port), 3857266423Sjfv pf->stat_offsets_loaded, 3858266423Sjfv &osd->eth.rx_discards, 3859266423Sjfv &nsd->eth.rx_discards); 3860270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port), 3861266423Sjfv I40E_GLPRT_UPRCL(hw->port), 3862266423Sjfv pf->stat_offsets_loaded, 3863266423Sjfv &osd->eth.rx_unicast, 3864266423Sjfv &nsd->eth.rx_unicast); 3865270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port), 3866266423Sjfv I40E_GLPRT_UPTCL(hw->port), 3867266423Sjfv pf->stat_offsets_loaded, 3868266423Sjfv &osd->eth.tx_unicast, 3869266423Sjfv &nsd->eth.tx_unicast); 3870270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port), 3871266423Sjfv I40E_GLPRT_MPRCL(hw->port), 3872266423Sjfv pf->stat_offsets_loaded, 3873266423Sjfv &osd->eth.rx_multicast, 3874266423Sjfv &nsd->eth.rx_multicast); 3875270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port), 3876266423Sjfv I40E_GLPRT_MPTCL(hw->port), 3877266423Sjfv pf->stat_offsets_loaded, 3878266423Sjfv &osd->eth.tx_multicast, 3879266423Sjfv &nsd->eth.tx_multicast); 3880270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port), 3881266423Sjfv I40E_GLPRT_BPRCL(hw->port), 3882266423Sjfv pf->stat_offsets_loaded, 3883266423Sjfv &osd->eth.rx_broadcast, 3884266423Sjfv &nsd->eth.rx_broadcast); 3885270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port), 3886266423Sjfv I40E_GLPRT_BPTCL(hw->port), 3887266423Sjfv pf->stat_offsets_loaded, 3888266423Sjfv &osd->eth.tx_broadcast, 3889266423Sjfv &nsd->eth.tx_broadcast); 3890266423Sjfv 3891270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port), 3892266423Sjfv pf->stat_offsets_loaded, 3893266423Sjfv &osd->tx_dropped_link_down, 3894266423Sjfv &nsd->tx_dropped_link_down); 3895270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port), 3896266423Sjfv pf->stat_offsets_loaded, 3897266423Sjfv &osd->mac_local_faults, 3898266423Sjfv &nsd->mac_local_faults); 3899270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port), 3900266423Sjfv pf->stat_offsets_loaded, 3901266423Sjfv &osd->mac_remote_faults, 3902266423Sjfv &nsd->mac_remote_faults); 3903270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port), 3904266423Sjfv pf->stat_offsets_loaded, 3905266423Sjfv &osd->rx_length_errors, 3906266423Sjfv &nsd->rx_length_errors); 3907266423Sjfv 3908269198Sjfv /* Flow control (LFC) stats */ 3909270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port), 3910266423Sjfv pf->stat_offsets_loaded, 3911266423Sjfv &osd->link_xon_rx, &nsd->link_xon_rx); 3912270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port), 3913266423Sjfv pf->stat_offsets_loaded, 3914266423Sjfv &osd->link_xon_tx, &nsd->link_xon_tx); 3915270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port), 3916266423Sjfv pf->stat_offsets_loaded, 3917266423Sjfv &osd->link_xoff_rx, &nsd->link_xoff_rx); 3918270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port), 3919266423Sjfv pf->stat_offsets_loaded, 3920266423Sjfv &osd->link_xoff_tx, &nsd->link_xoff_tx); 3921266423Sjfv 3922269198Sjfv /* Packet size stats rx */ 3923270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port), 3924266423Sjfv I40E_GLPRT_PRC64L(hw->port), 3925266423Sjfv pf->stat_offsets_loaded, 3926266423Sjfv &osd->rx_size_64, &nsd->rx_size_64); 3927270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port), 3928266423Sjfv I40E_GLPRT_PRC127L(hw->port), 3929266423Sjfv pf->stat_offsets_loaded, 3930266423Sjfv &osd->rx_size_127, &nsd->rx_size_127); 3931270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port), 3932266423Sjfv I40E_GLPRT_PRC255L(hw->port), 3933266423Sjfv pf->stat_offsets_loaded, 3934266423Sjfv &osd->rx_size_255, &nsd->rx_size_255); 3935270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port), 3936266423Sjfv I40E_GLPRT_PRC511L(hw->port), 3937266423Sjfv pf->stat_offsets_loaded, 3938266423Sjfv &osd->rx_size_511, &nsd->rx_size_511); 3939270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port), 3940266423Sjfv I40E_GLPRT_PRC1023L(hw->port), 3941266423Sjfv pf->stat_offsets_loaded, 3942266423Sjfv &osd->rx_size_1023, &nsd->rx_size_1023); 3943270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port), 3944266423Sjfv I40E_GLPRT_PRC1522L(hw->port), 3945266423Sjfv pf->stat_offsets_loaded, 3946266423Sjfv &osd->rx_size_1522, &nsd->rx_size_1522); 3947270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port), 3948266423Sjfv I40E_GLPRT_PRC9522L(hw->port), 3949266423Sjfv pf->stat_offsets_loaded, 3950266423Sjfv &osd->rx_size_big, &nsd->rx_size_big); 3951266423Sjfv 3952269198Sjfv /* Packet size stats tx */ 3953270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port), 3954266423Sjfv I40E_GLPRT_PTC64L(hw->port), 3955266423Sjfv pf->stat_offsets_loaded, 3956266423Sjfv &osd->tx_size_64, &nsd->tx_size_64); 3957270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port), 3958266423Sjfv I40E_GLPRT_PTC127L(hw->port), 3959266423Sjfv pf->stat_offsets_loaded, 3960266423Sjfv &osd->tx_size_127, &nsd->tx_size_127); 3961270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port), 3962266423Sjfv I40E_GLPRT_PTC255L(hw->port), 3963266423Sjfv pf->stat_offsets_loaded, 3964266423Sjfv &osd->tx_size_255, &nsd->tx_size_255); 3965270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port), 3966266423Sjfv I40E_GLPRT_PTC511L(hw->port), 3967266423Sjfv pf->stat_offsets_loaded, 3968266423Sjfv &osd->tx_size_511, &nsd->tx_size_511); 3969270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port), 3970266423Sjfv I40E_GLPRT_PTC1023L(hw->port), 3971266423Sjfv pf->stat_offsets_loaded, 3972266423Sjfv &osd->tx_size_1023, &nsd->tx_size_1023); 3973270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port), 3974266423Sjfv I40E_GLPRT_PTC1522L(hw->port), 3975266423Sjfv pf->stat_offsets_loaded, 3976266423Sjfv &osd->tx_size_1522, &nsd->tx_size_1522); 3977270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port), 3978266423Sjfv I40E_GLPRT_PTC9522L(hw->port), 3979266423Sjfv pf->stat_offsets_loaded, 3980266423Sjfv &osd->tx_size_big, &nsd->tx_size_big); 3981266423Sjfv 3982270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port), 3983266423Sjfv pf->stat_offsets_loaded, 3984266423Sjfv &osd->rx_undersize, &nsd->rx_undersize); 3985270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port), 3986266423Sjfv pf->stat_offsets_loaded, 3987266423Sjfv &osd->rx_fragments, &nsd->rx_fragments); 3988270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port), 3989266423Sjfv pf->stat_offsets_loaded, 3990266423Sjfv &osd->rx_oversize, &nsd->rx_oversize); 3991270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port), 3992266423Sjfv pf->stat_offsets_loaded, 3993266423Sjfv &osd->rx_jabber, &nsd->rx_jabber); 3994266423Sjfv pf->stat_offsets_loaded = true; 3995269198Sjfv /* End hw stats */ 3996266423Sjfv 3997266423Sjfv /* Update vsi stats */ 3998270346Sjfv ixl_update_eth_stats(vsi); 3999266423Sjfv 4000266423Sjfv /* OS statistics */ 4001269198Sjfv // ERJ - these are per-port, update all vsis? 4002272227Sglebius IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes); 4003266423Sjfv} 4004266423Sjfv 4005266423Sjfv/* 4006266423Sjfv** Tasklet handler for MSIX Adminq interrupts 4007266423Sjfv** - do outside interrupt since it might sleep 4008266423Sjfv*/ 4009266423Sjfvstatic void 4010270346Sjfvixl_do_adminq(void *context, int pending) 4011266423Sjfv{ 4012270346Sjfv struct ixl_pf *pf = context; 4013266423Sjfv struct i40e_hw *hw = &pf->hw; 4014270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 4015266423Sjfv struct i40e_arq_event_info event; 4016266423Sjfv i40e_status ret; 4017266423Sjfv u32 reg, loop = 0; 4018266423Sjfv u16 opcode, result; 4019266423Sjfv 4020274205Sjfv event.buf_len = IXL_AQ_BUF_SZ; 4021274205Sjfv event.msg_buf = malloc(event.buf_len, 4022266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 4023266423Sjfv if (!event.msg_buf) { 4024266423Sjfv printf("Unable to allocate adminq memory\n"); 4025266423Sjfv return; 4026266423Sjfv } 4027266423Sjfv 4028266423Sjfv /* clean and process any events */ 4029266423Sjfv do { 4030266423Sjfv ret = i40e_clean_arq_element(hw, &event, &result); 4031266423Sjfv if (ret) 4032266423Sjfv break; 4033266423Sjfv opcode = LE16_TO_CPU(event.desc.opcode); 4034266423Sjfv switch (opcode) { 4035266423Sjfv case i40e_aqc_opc_get_link_status: 4036270346Sjfv vsi->link_up = ixl_config_link(hw); 4037270346Sjfv ixl_update_link_status(pf); 4038266423Sjfv break; 4039266423Sjfv case i40e_aqc_opc_send_msg_to_pf: 4040266423Sjfv /* process pf/vf communication here */ 4041266423Sjfv break; 4042266423Sjfv case i40e_aqc_opc_event_lan_overflow: 4043266423Sjfv break; 4044266423Sjfv default: 4045270346Sjfv#ifdef IXL_DEBUG 4046266423Sjfv printf("AdminQ unknown event %x\n", opcode); 4047266423Sjfv#endif 4048266423Sjfv break; 4049266423Sjfv } 4050266423Sjfv 4051270346Sjfv } while (result && (loop++ < IXL_ADM_LIMIT)); 4052266423Sjfv 4053266423Sjfv reg = rd32(hw, I40E_PFINT_ICR0_ENA); 4054269198Sjfv reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 4055266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 4056266423Sjfv free(event.msg_buf, M_DEVBUF); 4057266423Sjfv 4058266423Sjfv if (pf->msix > 1) 4059270346Sjfv ixl_enable_adminq(&pf->hw); 4060266423Sjfv else 4061270346Sjfv ixl_enable_intr(vsi); 4062266423Sjfv} 4063266423Sjfv 4064266423Sjfvstatic int 4065270346Sjfvixl_debug_info(SYSCTL_HANDLER_ARGS) 4066266423Sjfv{ 4067270346Sjfv struct ixl_pf *pf; 4068266423Sjfv int error, input = 0; 4069266423Sjfv 4070266423Sjfv error = sysctl_handle_int(oidp, &input, 0, req); 4071266423Sjfv 4072266423Sjfv if (error || !req->newptr) 4073266423Sjfv return (error); 4074266423Sjfv 4075266423Sjfv if (input == 1) { 4076270346Sjfv pf = (struct ixl_pf *)arg1; 4077270346Sjfv ixl_print_debug_info(pf); 4078266423Sjfv } 4079266423Sjfv 4080266423Sjfv return (error); 4081266423Sjfv} 4082266423Sjfv 4083266423Sjfvstatic void 4084270346Sjfvixl_print_debug_info(struct ixl_pf *pf) 4085266423Sjfv{ 4086266423Sjfv struct i40e_hw *hw = &pf->hw; 4087270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 4088270346Sjfv struct ixl_queue *que = vsi->queues; 4089266423Sjfv struct rx_ring *rxr = &que->rxr; 4090266423Sjfv struct tx_ring *txr = &que->txr; 4091266423Sjfv u32 reg; 4092266423Sjfv 4093266423Sjfv 4094270799Sbz printf("Queue irqs = %jx\n", (uintmax_t)que->irqs); 4095270799Sbz printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq); 4096266423Sjfv printf("RX next check = %x\n", rxr->next_check); 4097270799Sbz printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done); 4098270799Sbz printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets); 4099266423Sjfv printf("TX desc avail = %x\n", txr->avail); 4100266423Sjfv 4101266423Sjfv reg = rd32(hw, I40E_GLV_GORCL(0xc)); 4102266423Sjfv printf("RX Bytes = %x\n", reg); 4103266423Sjfv reg = rd32(hw, I40E_GLPRT_GORCL(hw->port)); 4104266423Sjfv printf("Port RX Bytes = %x\n", reg); 4105266423Sjfv reg = rd32(hw, I40E_GLV_RDPC(0xc)); 4106266423Sjfv printf("RX discard = %x\n", reg); 4107266423Sjfv reg = rd32(hw, I40E_GLPRT_RDPC(hw->port)); 4108266423Sjfv printf("Port RX discard = %x\n", reg); 4109266423Sjfv 4110266423Sjfv reg = rd32(hw, I40E_GLV_TEPC(0xc)); 4111266423Sjfv printf("TX errors = %x\n", reg); 4112266423Sjfv reg = rd32(hw, I40E_GLV_GOTCL(0xc)); 4113266423Sjfv printf("TX Bytes = %x\n", reg); 4114266423Sjfv 4115266423Sjfv reg = rd32(hw, I40E_GLPRT_RUC(hw->port)); 4116266423Sjfv printf("RX undersize = %x\n", reg); 4117266423Sjfv reg = rd32(hw, I40E_GLPRT_RFC(hw->port)); 4118266423Sjfv printf("RX fragments = %x\n", reg); 4119266423Sjfv reg = rd32(hw, I40E_GLPRT_ROC(hw->port)); 4120266423Sjfv printf("RX oversize = %x\n", reg); 4121266423Sjfv reg = rd32(hw, I40E_GLPRT_RLEC(hw->port)); 4122266423Sjfv printf("RX length error = %x\n", reg); 4123266423Sjfv reg = rd32(hw, I40E_GLPRT_MRFC(hw->port)); 4124266423Sjfv printf("mac remote fault = %x\n", reg); 4125266423Sjfv reg = rd32(hw, I40E_GLPRT_MLFC(hw->port)); 4126266423Sjfv printf("mac local fault = %x\n", reg); 4127266423Sjfv} 4128266423Sjfv 4129266423Sjfv/** 4130266423Sjfv * Update VSI-specific ethernet statistics counters. 4131266423Sjfv **/ 4132270346Sjfvvoid ixl_update_eth_stats(struct ixl_vsi *vsi) 4133266423Sjfv{ 4134270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 4135266423Sjfv struct i40e_hw *hw = &pf->hw; 4136266423Sjfv struct i40e_eth_stats *es; 4137266423Sjfv struct i40e_eth_stats *oes; 4138272227Sglebius int i; 4139272227Sglebius uint64_t tx_discards; 4140272227Sglebius struct i40e_hw_port_stats *nsd; 4141266423Sjfv u16 stat_idx = vsi->info.stat_counter_idx; 4142266423Sjfv 4143266423Sjfv es = &vsi->eth_stats; 4144266423Sjfv oes = &vsi->eth_stats_offsets; 4145272227Sglebius nsd = &pf->stats; 4146266423Sjfv 4147266423Sjfv /* Gather up the stats that the hw collects */ 4148270346Sjfv ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx), 4149266423Sjfv vsi->stat_offsets_loaded, 4150266423Sjfv &oes->tx_errors, &es->tx_errors); 4151270346Sjfv ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx), 4152266423Sjfv vsi->stat_offsets_loaded, 4153266423Sjfv &oes->rx_discards, &es->rx_discards); 4154266423Sjfv 4155270346Sjfv ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx), 4156266423Sjfv I40E_GLV_GORCL(stat_idx), 4157266423Sjfv vsi->stat_offsets_loaded, 4158266423Sjfv &oes->rx_bytes, &es->rx_bytes); 4159270346Sjfv ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx), 4160266423Sjfv I40E_GLV_UPRCL(stat_idx), 4161266423Sjfv vsi->stat_offsets_loaded, 4162266423Sjfv &oes->rx_unicast, &es->rx_unicast); 4163270346Sjfv ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx), 4164266423Sjfv I40E_GLV_MPRCL(stat_idx), 4165266423Sjfv vsi->stat_offsets_loaded, 4166266423Sjfv &oes->rx_multicast, &es->rx_multicast); 4167270346Sjfv ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx), 4168266423Sjfv I40E_GLV_BPRCL(stat_idx), 4169266423Sjfv vsi->stat_offsets_loaded, 4170266423Sjfv &oes->rx_broadcast, &es->rx_broadcast); 4171266423Sjfv 4172270346Sjfv ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx), 4173266423Sjfv I40E_GLV_GOTCL(stat_idx), 4174266423Sjfv vsi->stat_offsets_loaded, 4175266423Sjfv &oes->tx_bytes, &es->tx_bytes); 4176270346Sjfv ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx), 4177266423Sjfv I40E_GLV_UPTCL(stat_idx), 4178266423Sjfv vsi->stat_offsets_loaded, 4179266423Sjfv &oes->tx_unicast, &es->tx_unicast); 4180270346Sjfv ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx), 4181266423Sjfv I40E_GLV_MPTCL(stat_idx), 4182266423Sjfv vsi->stat_offsets_loaded, 4183266423Sjfv &oes->tx_multicast, &es->tx_multicast); 4184270346Sjfv ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx), 4185266423Sjfv I40E_GLV_BPTCL(stat_idx), 4186266423Sjfv vsi->stat_offsets_loaded, 4187266423Sjfv &oes->tx_broadcast, &es->tx_broadcast); 4188266423Sjfv vsi->stat_offsets_loaded = true; 4189269198Sjfv 4190272227Sglebius tx_discards = es->tx_discards + nsd->tx_dropped_link_down; 4191272227Sglebius for (i = 0; i < vsi->num_queues; i++) 4192272227Sglebius tx_discards += vsi->queues[i].txr.br->br_drops; 4193272227Sglebius 4194269198Sjfv /* Update ifnet stats */ 4195272227Sglebius IXL_SET_IPACKETS(vsi, es->rx_unicast + 4196269198Sjfv es->rx_multicast + 4197272227Sglebius es->rx_broadcast); 4198272227Sglebius IXL_SET_OPACKETS(vsi, es->tx_unicast + 4199269198Sjfv es->tx_multicast + 4200272227Sglebius es->tx_broadcast); 4201272227Sglebius IXL_SET_IBYTES(vsi, es->rx_bytes); 4202272227Sglebius IXL_SET_OBYTES(vsi, es->tx_bytes); 4203272227Sglebius IXL_SET_IMCASTS(vsi, es->rx_multicast); 4204272227Sglebius IXL_SET_OMCASTS(vsi, es->tx_multicast); 4205269198Sjfv 4206272227Sglebius IXL_SET_OERRORS(vsi, es->tx_errors); 4207272227Sglebius IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards); 4208272227Sglebius IXL_SET_OQDROPS(vsi, tx_discards); 4209272227Sglebius IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol); 4210272227Sglebius IXL_SET_COLLISIONS(vsi, 0); 4211266423Sjfv} 4212266423Sjfv 4213266423Sjfv/** 4214266423Sjfv * Reset all of the stats for the given pf 4215266423Sjfv **/ 4216270346Sjfvvoid ixl_pf_reset_stats(struct ixl_pf *pf) 4217266423Sjfv{ 4218266423Sjfv bzero(&pf->stats, sizeof(struct i40e_hw_port_stats)); 4219266423Sjfv bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats)); 4220266423Sjfv pf->stat_offsets_loaded = false; 4221266423Sjfv} 4222266423Sjfv 4223266423Sjfv/** 4224266423Sjfv * Resets all stats of the given vsi 4225266423Sjfv **/ 4226270346Sjfvvoid ixl_vsi_reset_stats(struct ixl_vsi *vsi) 4227266423Sjfv{ 4228266423Sjfv bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats)); 4229266423Sjfv bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats)); 4230266423Sjfv vsi->stat_offsets_loaded = false; 4231266423Sjfv} 4232266423Sjfv 4233266423Sjfv/** 4234266423Sjfv * Read and update a 48 bit stat from the hw 4235266423Sjfv * 4236266423Sjfv * Since the device stats are not reset at PFReset, they likely will not 4237266423Sjfv * be zeroed when the driver starts. We'll save the first values read 4238266423Sjfv * and use them as offsets to be subtracted from the raw values in order 4239266423Sjfv * to report stats that count from zero. 4240266423Sjfv **/ 4241266423Sjfvstatic void 4242270346Sjfvixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg, 4243266423Sjfv bool offset_loaded, u64 *offset, u64 *stat) 4244266423Sjfv{ 4245266423Sjfv u64 new_data; 4246266423Sjfv 4247270799Sbz#if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__) 4248266423Sjfv new_data = rd64(hw, loreg); 4249266423Sjfv#else 4250266423Sjfv /* 4251269198Sjfv * Use two rd32's instead of one rd64; FreeBSD versions before 4252266423Sjfv * 10 don't support 8 byte bus reads/writes. 4253266423Sjfv */ 4254266423Sjfv new_data = rd32(hw, loreg); 4255266423Sjfv new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32; 4256266423Sjfv#endif 4257266423Sjfv 4258266423Sjfv if (!offset_loaded) 4259266423Sjfv *offset = new_data; 4260266423Sjfv if (new_data >= *offset) 4261266423Sjfv *stat = new_data - *offset; 4262266423Sjfv else 4263266423Sjfv *stat = (new_data + ((u64)1 << 48)) - *offset; 4264266423Sjfv *stat &= 0xFFFFFFFFFFFFULL; 4265266423Sjfv} 4266266423Sjfv 4267266423Sjfv/** 4268266423Sjfv * Read and update a 32 bit stat from the hw 4269266423Sjfv **/ 4270266423Sjfvstatic void 4271270346Sjfvixl_stat_update32(struct i40e_hw *hw, u32 reg, 4272266423Sjfv bool offset_loaded, u64 *offset, u64 *stat) 4273266423Sjfv{ 4274266423Sjfv u32 new_data; 4275266423Sjfv 4276266423Sjfv new_data = rd32(hw, reg); 4277266423Sjfv if (!offset_loaded) 4278266423Sjfv *offset = new_data; 4279266423Sjfv if (new_data >= *offset) 4280266423Sjfv *stat = (u32)(new_data - *offset); 4281266423Sjfv else 4282266423Sjfv *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); 4283266423Sjfv} 4284266423Sjfv 4285266423Sjfv/* 4286266423Sjfv** Set flow control using sysctl: 4287266423Sjfv** 0 - off 4288266423Sjfv** 1 - rx pause 4289266423Sjfv** 2 - tx pause 4290266423Sjfv** 3 - full 4291266423Sjfv*/ 4292266423Sjfvstatic int 4293270346Sjfvixl_set_flowcntl(SYSCTL_HANDLER_ARGS) 4294266423Sjfv{ 4295266423Sjfv /* 4296266423Sjfv * TODO: ensure flow control is disabled if 4297266423Sjfv * priority flow control is enabled 4298266423Sjfv * 4299266423Sjfv * TODO: ensure tx CRC by hardware should be enabled 4300266423Sjfv * if tx flow control is enabled. 4301266423Sjfv */ 4302270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4303266423Sjfv struct i40e_hw *hw = &pf->hw; 4304266423Sjfv device_t dev = pf->dev; 4305279033Sjfv int error = 0; 4306266423Sjfv enum i40e_status_code aq_error = 0; 4307266423Sjfv u8 fc_aq_err = 0; 4308266423Sjfv 4309279033Sjfv /* Get request */ 4310279033Sjfv error = sysctl_handle_int(oidp, &pf->fc, 0, req); 4311266423Sjfv if ((error) || (req->newptr == NULL)) 4312269198Sjfv return (error); 4313279033Sjfv if (pf->fc < 0 || pf->fc > 3) { 4314266423Sjfv device_printf(dev, 4315266423Sjfv "Invalid fc mode; valid modes are 0 through 3\n"); 4316266423Sjfv return (EINVAL); 4317266423Sjfv } 4318266423Sjfv 4319269198Sjfv /* 4320269198Sjfv ** Changing flow control mode currently does not work on 4321269198Sjfv ** 40GBASE-CR4 PHYs 4322269198Sjfv */ 4323269198Sjfv if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4 4324269198Sjfv || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) { 4325269198Sjfv device_printf(dev, "Changing flow control mode unsupported" 4326269198Sjfv " on 40GBase-CR4 media.\n"); 4327269198Sjfv return (ENODEV); 4328269198Sjfv } 4329269198Sjfv 4330266423Sjfv /* Set fc ability for port */ 4331279033Sjfv hw->fc.requested_mode = pf->fc; 4332269198Sjfv aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE); 4333269198Sjfv if (aq_error) { 4334269198Sjfv device_printf(dev, 4335269198Sjfv "%s: Error setting new fc mode %d; fc_err %#x\n", 4336269198Sjfv __func__, aq_error, fc_aq_err); 4337269198Sjfv return (EAGAIN); 4338269198Sjfv } 4339266423Sjfv 4340269198Sjfv return (0); 4341269198Sjfv} 4342266423Sjfv 4343270346Sjfvstatic int 4344270346Sjfvixl_current_speed(SYSCTL_HANDLER_ARGS) 4345270346Sjfv{ 4346270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4347270346Sjfv struct i40e_hw *hw = &pf->hw; 4348270346Sjfv int error = 0, index = 0; 4349270346Sjfv 4350270346Sjfv char *speeds[] = { 4351270346Sjfv "Unknown", 4352270346Sjfv "100M", 4353270346Sjfv "1G", 4354270346Sjfv "10G", 4355270346Sjfv "40G", 4356270346Sjfv "20G" 4357270346Sjfv }; 4358270346Sjfv 4359270346Sjfv ixl_update_link_status(pf); 4360270346Sjfv 4361270346Sjfv switch (hw->phy.link_info.link_speed) { 4362270346Sjfv case I40E_LINK_SPEED_100MB: 4363270346Sjfv index = 1; 4364270346Sjfv break; 4365270346Sjfv case I40E_LINK_SPEED_1GB: 4366270346Sjfv index = 2; 4367270346Sjfv break; 4368270346Sjfv case I40E_LINK_SPEED_10GB: 4369270346Sjfv index = 3; 4370270346Sjfv break; 4371270346Sjfv case I40E_LINK_SPEED_40GB: 4372270346Sjfv index = 4; 4373270346Sjfv break; 4374270346Sjfv case I40E_LINK_SPEED_20GB: 4375270346Sjfv index = 5; 4376270346Sjfv break; 4377270346Sjfv case I40E_LINK_SPEED_UNKNOWN: 4378270346Sjfv default: 4379270346Sjfv index = 0; 4380270346Sjfv break; 4381270346Sjfv } 4382270346Sjfv 4383270346Sjfv error = sysctl_handle_string(oidp, speeds[index], 4384270346Sjfv strlen(speeds[index]), req); 4385270346Sjfv return (error); 4386270346Sjfv} 4387270346Sjfv 4388274205Sjfvstatic int 4389274205Sjfvixl_set_advertised_speeds(struct ixl_pf *pf, int speeds) 4390274205Sjfv{ 4391274205Sjfv struct i40e_hw *hw = &pf->hw; 4392274205Sjfv device_t dev = pf->dev; 4393274205Sjfv struct i40e_aq_get_phy_abilities_resp abilities; 4394274205Sjfv struct i40e_aq_set_phy_config config; 4395274205Sjfv enum i40e_status_code aq_error = 0; 4396274205Sjfv 4397274205Sjfv /* Get current capability information */ 4398279033Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, 4399279033Sjfv FALSE, FALSE, &abilities, NULL); 4400274205Sjfv if (aq_error) { 4401279033Sjfv device_printf(dev, 4402279033Sjfv "%s: Error getting phy capabilities %d," 4403274205Sjfv " aq error: %d\n", __func__, aq_error, 4404274205Sjfv hw->aq.asq_last_status); 4405274205Sjfv return (EAGAIN); 4406274205Sjfv } 4407274205Sjfv 4408274205Sjfv /* Prepare new config */ 4409274205Sjfv bzero(&config, sizeof(config)); 4410274205Sjfv config.phy_type = abilities.phy_type; 4411274205Sjfv config.abilities = abilities.abilities 4412274205Sjfv | I40E_AQ_PHY_ENABLE_ATOMIC_LINK; 4413274205Sjfv config.eee_capability = abilities.eee_capability; 4414274205Sjfv config.eeer = abilities.eeer_val; 4415274205Sjfv config.low_power_ctrl = abilities.d3_lpan; 4416274205Sjfv /* Translate into aq cmd link_speed */ 4417274205Sjfv if (speeds & 0x4) 4418274205Sjfv config.link_speed |= I40E_LINK_SPEED_10GB; 4419274205Sjfv if (speeds & 0x2) 4420274205Sjfv config.link_speed |= I40E_LINK_SPEED_1GB; 4421274205Sjfv if (speeds & 0x1) 4422274205Sjfv config.link_speed |= I40E_LINK_SPEED_100MB; 4423274205Sjfv 4424274205Sjfv /* Do aq command & restart link */ 4425274205Sjfv aq_error = i40e_aq_set_phy_config(hw, &config, NULL); 4426274205Sjfv if (aq_error) { 4427279033Sjfv device_printf(dev, 4428279033Sjfv "%s: Error setting new phy config %d," 4429274205Sjfv " aq error: %d\n", __func__, aq_error, 4430274205Sjfv hw->aq.asq_last_status); 4431274205Sjfv return (EAGAIN); 4432274205Sjfv } 4433274205Sjfv 4434277084Sjfv /* 4435277084Sjfv ** This seems a bit heavy handed, but we 4436277084Sjfv ** need to get a reinit on some devices 4437277084Sjfv */ 4438277084Sjfv IXL_PF_LOCK(pf); 4439277084Sjfv ixl_stop(pf); 4440277084Sjfv ixl_init_locked(pf); 4441277084Sjfv IXL_PF_UNLOCK(pf); 4442277084Sjfv 4443274205Sjfv return (0); 4444274205Sjfv} 4445274205Sjfv 4446269198Sjfv/* 4447269198Sjfv** Control link advertise speed: 4448270346Sjfv** Flags: 4449270346Sjfv** 0x1 - advertise 100 Mb 4450270346Sjfv** 0x2 - advertise 1G 4451270346Sjfv** 0x4 - advertise 10G 4452269198Sjfv** 4453269198Sjfv** Does not work on 40G devices. 4454269198Sjfv*/ 4455269198Sjfvstatic int 4456270346Sjfvixl_set_advertise(SYSCTL_HANDLER_ARGS) 4457269198Sjfv{ 4458270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4459269198Sjfv struct i40e_hw *hw = &pf->hw; 4460269198Sjfv device_t dev = pf->dev; 4461270346Sjfv int requested_ls = 0; 4462269198Sjfv int error = 0; 4463266423Sjfv 4464269198Sjfv /* 4465269198Sjfv ** FW doesn't support changing advertised speed 4466269198Sjfv ** for 40G devices; speed is always 40G. 4467269198Sjfv */ 4468269198Sjfv if (i40e_is_40G_device(hw->device_id)) 4469269198Sjfv return (ENODEV); 4470266423Sjfv 4471269198Sjfv /* Read in new mode */ 4472270346Sjfv requested_ls = pf->advertised_speed; 4473269198Sjfv error = sysctl_handle_int(oidp, &requested_ls, 0, req); 4474269198Sjfv if ((error) || (req->newptr == NULL)) 4475269198Sjfv return (error); 4476270346Sjfv if (requested_ls < 1 || requested_ls > 7) { 4477269198Sjfv device_printf(dev, 4478270346Sjfv "Invalid advertised speed; valid modes are 0x1 through 0x7\n"); 4479269198Sjfv return (EINVAL); 4480266423Sjfv } 4481269198Sjfv 4482269198Sjfv /* Exit if no change */ 4483270346Sjfv if (pf->advertised_speed == requested_ls) 4484269198Sjfv return (0); 4485269198Sjfv 4486274205Sjfv error = ixl_set_advertised_speeds(pf, requested_ls); 4487274205Sjfv if (error) 4488274205Sjfv return (error); 4489270346Sjfv 4490270346Sjfv pf->advertised_speed = requested_ls; 4491270346Sjfv ixl_update_link_status(pf); 4492269198Sjfv return (0); 4493266423Sjfv} 4494266423Sjfv 4495266423Sjfv/* 4496266423Sjfv** Get the width and transaction speed of 4497266423Sjfv** the bus this adapter is plugged into. 4498266423Sjfv*/ 4499266423Sjfvstatic u16 4500270346Sjfvixl_get_bus_info(struct i40e_hw *hw, device_t dev) 4501266423Sjfv{ 4502266423Sjfv u16 link; 4503266423Sjfv u32 offset; 4504266423Sjfv 4505266423Sjfv 4506266423Sjfv /* Get the PCI Express Capabilities offset */ 4507266423Sjfv pci_find_cap(dev, PCIY_EXPRESS, &offset); 4508266423Sjfv 4509266423Sjfv /* ...and read the Link Status Register */ 4510266423Sjfv link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 4511266423Sjfv 4512266423Sjfv switch (link & I40E_PCI_LINK_WIDTH) { 4513266423Sjfv case I40E_PCI_LINK_WIDTH_1: 4514266423Sjfv hw->bus.width = i40e_bus_width_pcie_x1; 4515266423Sjfv break; 4516266423Sjfv case I40E_PCI_LINK_WIDTH_2: 4517266423Sjfv hw->bus.width = i40e_bus_width_pcie_x2; 4518266423Sjfv break; 4519266423Sjfv case I40E_PCI_LINK_WIDTH_4: 4520266423Sjfv hw->bus.width = i40e_bus_width_pcie_x4; 4521266423Sjfv break; 4522266423Sjfv case I40E_PCI_LINK_WIDTH_8: 4523266423Sjfv hw->bus.width = i40e_bus_width_pcie_x8; 4524266423Sjfv break; 4525266423Sjfv default: 4526266423Sjfv hw->bus.width = i40e_bus_width_unknown; 4527266423Sjfv break; 4528266423Sjfv } 4529266423Sjfv 4530266423Sjfv switch (link & I40E_PCI_LINK_SPEED) { 4531266423Sjfv case I40E_PCI_LINK_SPEED_2500: 4532266423Sjfv hw->bus.speed = i40e_bus_speed_2500; 4533266423Sjfv break; 4534266423Sjfv case I40E_PCI_LINK_SPEED_5000: 4535266423Sjfv hw->bus.speed = i40e_bus_speed_5000; 4536266423Sjfv break; 4537266423Sjfv case I40E_PCI_LINK_SPEED_8000: 4538266423Sjfv hw->bus.speed = i40e_bus_speed_8000; 4539266423Sjfv break; 4540266423Sjfv default: 4541266423Sjfv hw->bus.speed = i40e_bus_speed_unknown; 4542266423Sjfv break; 4543266423Sjfv } 4544266423Sjfv 4545266423Sjfv 4546266423Sjfv device_printf(dev,"PCI Express Bus: Speed %s %s\n", 4547266423Sjfv ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s": 4548266423Sjfv (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s": 4549266423Sjfv (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"), 4550266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" : 4551266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" : 4552266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" : 4553266423Sjfv ("Unknown")); 4554266423Sjfv 4555266423Sjfv if ((hw->bus.width <= i40e_bus_width_pcie_x8) && 4556266423Sjfv (hw->bus.speed < i40e_bus_speed_8000)) { 4557266423Sjfv device_printf(dev, "PCI-Express bandwidth available" 4558266423Sjfv " for this device\n is not sufficient for" 4559266423Sjfv " normal operation.\n"); 4560266423Sjfv device_printf(dev, "For expected performance a x8 " 4561266423Sjfv "PCIE Gen3 slot is required.\n"); 4562266423Sjfv } 4563266423Sjfv 4564266423Sjfv return (link); 4565266423Sjfv} 4566266423Sjfv 4567274205Sjfvstatic int 4568274205Sjfvixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS) 4569274205Sjfv{ 4570274205Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4571274205Sjfv struct i40e_hw *hw = &pf->hw; 4572274205Sjfv char buf[32]; 4573274205Sjfv 4574274205Sjfv snprintf(buf, sizeof(buf), 4575274205Sjfv "f%d.%d a%d.%d n%02x.%02x e%08x", 4576274205Sjfv hw->aq.fw_maj_ver, hw->aq.fw_min_ver, 4577274205Sjfv hw->aq.api_maj_ver, hw->aq.api_min_ver, 4578274205Sjfv (hw->nvm.version & IXL_NVM_VERSION_HI_MASK) >> 4579274205Sjfv IXL_NVM_VERSION_HI_SHIFT, 4580274205Sjfv (hw->nvm.version & IXL_NVM_VERSION_LO_MASK) >> 4581274205Sjfv IXL_NVM_VERSION_LO_SHIFT, 4582274205Sjfv hw->nvm.eetrack); 4583274205Sjfv return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 4584274205Sjfv} 4585274205Sjfv 4586274205Sjfv 4587277084Sjfv#ifdef IXL_DEBUG_SYSCTL 4588266423Sjfvstatic int 4589270346Sjfvixl_sysctl_link_status(SYSCTL_HANDLER_ARGS) 4590266423Sjfv{ 4591270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4592266423Sjfv struct i40e_hw *hw = &pf->hw; 4593266423Sjfv struct i40e_link_status link_status; 4594266423Sjfv char buf[512]; 4595266423Sjfv 4596266423Sjfv enum i40e_status_code aq_error = 0; 4597266423Sjfv 4598266423Sjfv aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL); 4599266423Sjfv if (aq_error) { 4600266423Sjfv printf("i40e_aq_get_link_info() error %d\n", aq_error); 4601266423Sjfv return (EPERM); 4602266423Sjfv } 4603266423Sjfv 4604266423Sjfv sprintf(buf, "\n" 4605266423Sjfv "PHY Type : %#04x\n" 4606266423Sjfv "Speed : %#04x\n" 4607266423Sjfv "Link info: %#04x\n" 4608266423Sjfv "AN info : %#04x\n" 4609266423Sjfv "Ext info : %#04x", 4610266423Sjfv link_status.phy_type, link_status.link_speed, 4611266423Sjfv link_status.link_info, link_status.an_info, 4612266423Sjfv link_status.ext_info); 4613266423Sjfv 4614266423Sjfv return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 4615266423Sjfv} 4616266423Sjfv 4617266423Sjfvstatic int 4618270346Sjfvixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS) 4619266423Sjfv{ 4620270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4621266423Sjfv struct i40e_hw *hw = &pf->hw; 4622266423Sjfv struct i40e_aq_get_phy_abilities_resp abilities_resp; 4623266423Sjfv char buf[512]; 4624266423Sjfv 4625266423Sjfv enum i40e_status_code aq_error = 0; 4626266423Sjfv 4627266423Sjfv // TODO: Print out list of qualified modules as well? 4628266423Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, TRUE, FALSE, &abilities_resp, NULL); 4629266423Sjfv if (aq_error) { 4630266423Sjfv printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error); 4631266423Sjfv return (EPERM); 4632266423Sjfv } 4633266423Sjfv 4634266423Sjfv sprintf(buf, "\n" 4635266423Sjfv "PHY Type : %#010x\n" 4636266423Sjfv "Speed : %#04x\n" 4637266423Sjfv "Abilities: %#04x\n" 4638266423Sjfv "EEE cap : %#06x\n" 4639266423Sjfv "EEER reg : %#010x\n" 4640266423Sjfv "D3 Lpan : %#04x", 4641266423Sjfv abilities_resp.phy_type, abilities_resp.link_speed, 4642266423Sjfv abilities_resp.abilities, abilities_resp.eee_capability, 4643266423Sjfv abilities_resp.eeer_val, abilities_resp.d3_lpan); 4644266423Sjfv 4645266423Sjfv return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 4646266423Sjfv} 4647266423Sjfv 4648266423Sjfvstatic int 4649270346Sjfvixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS) 4650266423Sjfv{ 4651270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4652270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 4653270346Sjfv struct ixl_mac_filter *f; 4654266423Sjfv char *buf, *buf_i; 4655266423Sjfv 4656266423Sjfv int error = 0; 4657266423Sjfv int ftl_len = 0; 4658266423Sjfv int ftl_counter = 0; 4659266423Sjfv int buf_len = 0; 4660266423Sjfv int entry_len = 42; 4661266423Sjfv 4662266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 4663266423Sjfv ftl_len++; 4664266423Sjfv } 4665266423Sjfv 4666266423Sjfv if (ftl_len < 1) { 4667266423Sjfv sysctl_handle_string(oidp, "(none)", 6, req); 4668266423Sjfv return (0); 4669266423Sjfv } 4670266423Sjfv 4671266423Sjfv buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2; 4672266423Sjfv buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT); 4673266423Sjfv 4674266423Sjfv sprintf(buf_i++, "\n"); 4675266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 4676266423Sjfv sprintf(buf_i, 4677266423Sjfv MAC_FORMAT ", vlan %4d, flags %#06x", 4678266423Sjfv MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags); 4679266423Sjfv buf_i += entry_len; 4680266423Sjfv /* don't print '\n' for last entry */ 4681266423Sjfv if (++ftl_counter != ftl_len) { 4682266423Sjfv sprintf(buf_i, "\n"); 4683266423Sjfv buf_i++; 4684266423Sjfv } 4685266423Sjfv } 4686266423Sjfv 4687266423Sjfv error = sysctl_handle_string(oidp, buf, strlen(buf), req); 4688266423Sjfv if (error) 4689266423Sjfv printf("sysctl error: %d\n", error); 4690266423Sjfv free(buf, M_DEVBUF); 4691266423Sjfv return error; 4692266423Sjfv} 4693269198Sjfv 4694270346Sjfv#define IXL_SW_RES_SIZE 0x14 4695269198Sjfvstatic int 4696277084Sjfvixl_res_alloc_cmp(const void *a, const void *b) 4697277084Sjfv{ 4698277084Sjfv const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two; 4699277084Sjfv one = (struct i40e_aqc_switch_resource_alloc_element_resp *)a; 4700277084Sjfv two = (struct i40e_aqc_switch_resource_alloc_element_resp *)b; 4701277084Sjfv 4702277084Sjfv return ((int)one->resource_type - (int)two->resource_type); 4703277084Sjfv} 4704277084Sjfv 4705277084Sjfvstatic int 4706274205Sjfvixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS) 4707269198Sjfv{ 4708270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4709269198Sjfv struct i40e_hw *hw = &pf->hw; 4710269198Sjfv device_t dev = pf->dev; 4711269198Sjfv struct sbuf *buf; 4712269198Sjfv int error = 0; 4713269198Sjfv 4714269198Sjfv u8 num_entries; 4715270346Sjfv struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE]; 4716269198Sjfv 4717269198Sjfv buf = sbuf_new_for_sysctl(NULL, NULL, 0, req); 4718269198Sjfv if (!buf) { 4719269198Sjfv device_printf(dev, "Could not allocate sbuf for output.\n"); 4720269198Sjfv return (ENOMEM); 4721269198Sjfv } 4722269198Sjfv 4723277084Sjfv bzero(resp, sizeof(resp)); 4724269198Sjfv error = i40e_aq_get_switch_resource_alloc(hw, &num_entries, 4725269198Sjfv resp, 4726270346Sjfv IXL_SW_RES_SIZE, 4727269198Sjfv NULL); 4728269198Sjfv if (error) { 4729269198Sjfv device_printf(dev, "%s: get_switch_resource_alloc() error %d, aq error %d\n", 4730269198Sjfv __func__, error, hw->aq.asq_last_status); 4731269198Sjfv sbuf_delete(buf); 4732269198Sjfv return error; 4733269198Sjfv } 4734269198Sjfv 4735277084Sjfv /* Sort entries by type for display */ 4736277084Sjfv qsort(resp, num_entries, 4737277084Sjfv sizeof(struct i40e_aqc_switch_resource_alloc_element_resp), 4738277084Sjfv &ixl_res_alloc_cmp); 4739277084Sjfv 4740269198Sjfv sbuf_cat(buf, "\n"); 4741277084Sjfv sbuf_printf(buf, "# of entries: %d\n", num_entries); 4742269198Sjfv sbuf_printf(buf, 4743269198Sjfv "Type | Guaranteed | Total | Used | Un-allocated\n" 4744269198Sjfv " | (this) | (all) | (this) | (all) \n"); 4745269198Sjfv for (int i = 0; i < num_entries; i++) { 4746269198Sjfv sbuf_printf(buf, 4747269198Sjfv "%#4x | %10d %5d %6d %12d", 4748269198Sjfv resp[i].resource_type, 4749269198Sjfv resp[i].guaranteed, 4750269198Sjfv resp[i].total, 4751269198Sjfv resp[i].used, 4752269198Sjfv resp[i].total_unalloced); 4753269198Sjfv if (i < num_entries - 1) 4754269198Sjfv sbuf_cat(buf, "\n"); 4755269198Sjfv } 4756269198Sjfv 4757269198Sjfv error = sbuf_finish(buf); 4758269198Sjfv if (error) { 4759269198Sjfv device_printf(dev, "Error finishing sbuf: %d\n", error); 4760269198Sjfv sbuf_delete(buf); 4761269198Sjfv return error; 4762269198Sjfv } 4763269198Sjfv 4764269198Sjfv error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req); 4765269198Sjfv if (error) 4766269198Sjfv device_printf(dev, "sysctl error: %d\n", error); 4767269198Sjfv sbuf_delete(buf); 4768269198Sjfv return error; 4769274205Sjfv} 4770269198Sjfv 4771274205Sjfv/* 4772274205Sjfv** Caller must init and delete sbuf; this function will clear and 4773274205Sjfv** finish it for caller. 4774274205Sjfv*/ 4775274205Sjfvstatic char * 4776274205Sjfvixl_switch_element_string(struct sbuf *s, u16 seid, bool uplink) 4777274205Sjfv{ 4778274205Sjfv sbuf_clear(s); 4779274205Sjfv 4780274205Sjfv if (seid == 0 && uplink) 4781274205Sjfv sbuf_cat(s, "Network"); 4782274205Sjfv else if (seid == 0) 4783274205Sjfv sbuf_cat(s, "Host"); 4784274205Sjfv else if (seid == 1) 4785274205Sjfv sbuf_cat(s, "EMP"); 4786274205Sjfv else if (seid <= 5) 4787274205Sjfv sbuf_printf(s, "MAC %d", seid - 2); 4788274205Sjfv else if (seid <= 15) 4789274205Sjfv sbuf_cat(s, "Reserved"); 4790274205Sjfv else if (seid <= 31) 4791274205Sjfv sbuf_printf(s, "PF %d", seid - 16); 4792274205Sjfv else if (seid <= 159) 4793274205Sjfv sbuf_printf(s, "VF %d", seid - 32); 4794274205Sjfv else if (seid <= 287) 4795274205Sjfv sbuf_cat(s, "Reserved"); 4796274205Sjfv else if (seid <= 511) 4797274205Sjfv sbuf_cat(s, "Other"); // for other structures 4798274205Sjfv else if (seid <= 895) 4799274205Sjfv sbuf_printf(s, "VSI %d", seid - 512); 4800274205Sjfv else if (seid <= 1023) 4801274205Sjfv sbuf_printf(s, "Reserved"); 4802274205Sjfv else 4803274205Sjfv sbuf_cat(s, "Invalid"); 4804274205Sjfv 4805274205Sjfv sbuf_finish(s); 4806274205Sjfv return sbuf_data(s); 4807269198Sjfv} 4808269198Sjfv 4809274205Sjfvstatic int 4810274205Sjfvixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS) 4811274205Sjfv{ 4812274205Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4813274205Sjfv struct i40e_hw *hw = &pf->hw; 4814274205Sjfv device_t dev = pf->dev; 4815274205Sjfv struct sbuf *buf; 4816274205Sjfv struct sbuf *nmbuf; 4817274205Sjfv int error = 0; 4818274205Sjfv u8 aq_buf[I40E_AQ_LARGE_BUF]; 4819274205Sjfv 4820274205Sjfv u16 next = 0; 4821274205Sjfv struct i40e_aqc_get_switch_config_resp *sw_config; 4822274205Sjfv sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 4823274205Sjfv 4824274205Sjfv buf = sbuf_new_for_sysctl(NULL, NULL, 0, req); 4825274205Sjfv if (!buf) { 4826274205Sjfv device_printf(dev, "Could not allocate sbuf for sysctl output.\n"); 4827274205Sjfv return (ENOMEM); 4828274205Sjfv } 4829274205Sjfv 4830274205Sjfv error = i40e_aq_get_switch_config(hw, sw_config, 4831274205Sjfv sizeof(aq_buf), &next, NULL); 4832274205Sjfv if (error) { 4833274205Sjfv device_printf(dev, "%s: aq_get_switch_config() error %d, aq error %d\n", 4834274205Sjfv __func__, error, hw->aq.asq_last_status); 4835274205Sjfv sbuf_delete(buf); 4836274205Sjfv return error; 4837274205Sjfv } 4838274205Sjfv 4839274205Sjfv nmbuf = sbuf_new_auto(); 4840274205Sjfv if (!nmbuf) { 4841274205Sjfv device_printf(dev, "Could not allocate sbuf for name output.\n"); 4842274205Sjfv return (ENOMEM); 4843274205Sjfv } 4844274205Sjfv 4845274205Sjfv sbuf_cat(buf, "\n"); 4846274205Sjfv // Assuming <= 255 elements in switch 4847274205Sjfv sbuf_printf(buf, "# of elements: %d\n", sw_config->header.num_reported); 4848274205Sjfv /* Exclude: 4849274205Sjfv ** Revision -- all elements are revision 1 for now 4850274205Sjfv */ 4851274205Sjfv sbuf_printf(buf, 4852274205Sjfv "SEID ( Name ) | Uplink | Downlink | Conn Type\n" 4853274205Sjfv " | | | (uplink)\n"); 4854274205Sjfv for (int i = 0; i < sw_config->header.num_reported; i++) { 4855274205Sjfv // "%4d (%8s) | %8s %8s %#8x", 4856274205Sjfv sbuf_printf(buf, "%4d", sw_config->element[i].seid); 4857274205Sjfv sbuf_cat(buf, " "); 4858274205Sjfv sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf, sw_config->element[i].seid, false)); 4859274205Sjfv sbuf_cat(buf, " | "); 4860274205Sjfv sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, sw_config->element[i].uplink_seid, true)); 4861274205Sjfv sbuf_cat(buf, " "); 4862274205Sjfv sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, sw_config->element[i].downlink_seid, false)); 4863274205Sjfv sbuf_cat(buf, " "); 4864274205Sjfv sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type); 4865274205Sjfv if (i < sw_config->header.num_reported - 1) 4866274205Sjfv sbuf_cat(buf, "\n"); 4867274205Sjfv } 4868274205Sjfv sbuf_delete(nmbuf); 4869274205Sjfv 4870274205Sjfv error = sbuf_finish(buf); 4871274205Sjfv if (error) { 4872274205Sjfv device_printf(dev, "Error finishing sbuf: %d\n", error); 4873274205Sjfv sbuf_delete(buf); 4874274205Sjfv return error; 4875274205Sjfv } 4876274205Sjfv 4877274205Sjfv error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req); 4878274205Sjfv if (error) 4879274205Sjfv device_printf(dev, "sysctl error: %d\n", error); 4880274205Sjfv sbuf_delete(buf); 4881274205Sjfv 4882274205Sjfv return (error); 4883274205Sjfv} 4884274205Sjfv 4885269198Sjfv/* 4886269198Sjfv** Dump TX desc given index. 4887269198Sjfv** Doesn't work; don't use. 4888269198Sjfv** TODO: Also needs a queue index input! 4889269198Sjfv**/ 4890269198Sjfvstatic int 4891270346Sjfvixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS) 4892269198Sjfv{ 4893270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4894269198Sjfv device_t dev = pf->dev; 4895269198Sjfv struct sbuf *buf; 4896269198Sjfv int error = 0; 4897269198Sjfv 4898269198Sjfv u16 desc_idx = 0; 4899269198Sjfv 4900269198Sjfv buf = sbuf_new_for_sysctl(NULL, NULL, 0, req); 4901269198Sjfv if (!buf) { 4902269198Sjfv device_printf(dev, "Could not allocate sbuf for output.\n"); 4903269198Sjfv return (ENOMEM); 4904269198Sjfv } 4905269198Sjfv 4906269198Sjfv /* Read in index */ 4907269198Sjfv error = sysctl_handle_int(oidp, &desc_idx, 0, req); 4908269198Sjfv if (error) 4909269198Sjfv return (error); 4910269198Sjfv if (req->newptr == NULL) 4911269198Sjfv return (EIO); // fix 4912269198Sjfv if (desc_idx > 1024) { // fix 4913269198Sjfv device_printf(dev, 4914269198Sjfv "Invalid descriptor index, needs to be < 1024\n"); // fix 4915269198Sjfv return (EINVAL); 4916269198Sjfv } 4917269198Sjfv 4918269198Sjfv // Don't use this sysctl yet 4919269198Sjfv if (TRUE) 4920269198Sjfv return (ENODEV); 4921269198Sjfv 4922269198Sjfv sbuf_cat(buf, "\n"); 4923269198Sjfv 4924269198Sjfv // set to queue 1? 4925270346Sjfv struct ixl_queue *que = pf->vsi.queues; 4926269198Sjfv struct tx_ring *txr = &(que[1].txr); 4927269198Sjfv struct i40e_tx_desc *txd = &txr->base[desc_idx]; 4928269198Sjfv 4929269198Sjfv sbuf_printf(buf, "Que: %d, Desc: %d\n", que->me, desc_idx); 4930269198Sjfv sbuf_printf(buf, "Addr: %#18lx\n", txd->buffer_addr); 4931269198Sjfv sbuf_printf(buf, "Opts: %#18lx\n", txd->cmd_type_offset_bsz); 4932269198Sjfv 4933269198Sjfv error = sbuf_finish(buf); 4934269198Sjfv if (error) { 4935269198Sjfv device_printf(dev, "Error finishing sbuf: %d\n", error); 4936269198Sjfv sbuf_delete(buf); 4937269198Sjfv return error; 4938269198Sjfv } 4939269198Sjfv 4940269198Sjfv error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req); 4941269198Sjfv if (error) 4942269198Sjfv device_printf(dev, "sysctl error: %d\n", error); 4943269198Sjfv sbuf_delete(buf); 4944269198Sjfv return error; 4945269198Sjfv} 4946277084Sjfv#endif /* IXL_DEBUG_SYSCTL */ 4947266423Sjfv 4948