if_ixl.c revision 270346
1266423Sjfv/****************************************************************************** 2266423Sjfv 3266423Sjfv Copyright (c) 2013-2014, 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 270346 2014-08-22 18:59:19Z jfv $*/ 34266423Sjfv 35266423Sjfv#include "opt_inet.h" 36266423Sjfv#include "opt_inet6.h" 37270346Sjfv#include "ixl.h" 38270346Sjfv#include "ixl_pf.h" 39269198Sjfv 40266423Sjfv/********************************************************************* 41266423Sjfv * Driver version 42266423Sjfv *********************************************************************/ 43270346Sjfvchar ixl_driver_version[] = "1.2.2"; 44266423Sjfv 45266423Sjfv/********************************************************************* 46266423Sjfv * PCI Device ID Table 47266423Sjfv * 48266423Sjfv * Used by probe to select devices to load on 49270346Sjfv * Last field stores an index into ixl_strings 50266423Sjfv * Last entry must be all 0s 51266423Sjfv * 52266423Sjfv * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 53266423Sjfv *********************************************************************/ 54266423Sjfv 55270346Sjfvstatic ixl_vendor_info_t ixl_vendor_info_array[] = 56266423Sjfv{ 57266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0}, 58266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_A, 0, 0, 0}, 59266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0}, 60266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0}, 61266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0}, 62266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0}, 63266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0}, 64270346Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0}, 65266423Sjfv /* required last entry */ 66266423Sjfv {0, 0, 0, 0, 0} 67266423Sjfv}; 68266423Sjfv 69266423Sjfv/********************************************************************* 70266423Sjfv * Table of branding strings 71266423Sjfv *********************************************************************/ 72266423Sjfv 73270346Sjfvstatic char *ixl_strings[] = { 74266423Sjfv "Intel(R) Ethernet Connection XL710 Driver" 75266423Sjfv}; 76266423Sjfv 77266423Sjfv 78266423Sjfv/********************************************************************* 79266423Sjfv * Function prototypes 80266423Sjfv *********************************************************************/ 81270346Sjfvstatic int ixl_probe(device_t); 82270346Sjfvstatic int ixl_attach(device_t); 83270346Sjfvstatic int ixl_detach(device_t); 84270346Sjfvstatic int ixl_shutdown(device_t); 85270346Sjfvstatic int ixl_get_hw_capabilities(struct ixl_pf *); 86270346Sjfvstatic void ixl_cap_txcsum_tso(struct ixl_vsi *, struct ifnet *, int); 87270346Sjfvstatic int ixl_ioctl(struct ifnet *, u_long, caddr_t); 88270346Sjfvstatic void ixl_init(void *); 89270346Sjfvstatic void ixl_init_locked(struct ixl_pf *); 90270346Sjfvstatic void ixl_stop(struct ixl_pf *); 91270346Sjfvstatic void ixl_media_status(struct ifnet *, struct ifmediareq *); 92270346Sjfvstatic int ixl_media_change(struct ifnet *); 93270346Sjfvstatic void ixl_update_link_status(struct ixl_pf *); 94270346Sjfvstatic int ixl_allocate_pci_resources(struct ixl_pf *); 95270346Sjfvstatic u16 ixl_get_bus_info(struct i40e_hw *, device_t); 96270346Sjfvstatic int ixl_setup_stations(struct ixl_pf *); 97270346Sjfvstatic int ixl_setup_vsi(struct ixl_vsi *); 98270346Sjfvstatic int ixl_initialize_vsi(struct ixl_vsi *); 99270346Sjfvstatic int ixl_assign_vsi_msix(struct ixl_pf *); 100270346Sjfvstatic int ixl_assign_vsi_legacy(struct ixl_pf *); 101270346Sjfvstatic int ixl_init_msix(struct ixl_pf *); 102270346Sjfvstatic void ixl_configure_msix(struct ixl_pf *); 103270346Sjfvstatic void ixl_configure_itr(struct ixl_pf *); 104270346Sjfvstatic void ixl_configure_legacy(struct ixl_pf *); 105270346Sjfvstatic void ixl_free_pci_resources(struct ixl_pf *); 106270346Sjfvstatic void ixl_local_timer(void *); 107270346Sjfvstatic int ixl_setup_interface(device_t, struct ixl_vsi *); 108270346Sjfvstatic bool ixl_config_link(struct i40e_hw *); 109270346Sjfvstatic void ixl_config_rss(struct ixl_vsi *); 110270346Sjfvstatic void ixl_set_queue_rx_itr(struct ixl_queue *); 111270346Sjfvstatic void ixl_set_queue_tx_itr(struct ixl_queue *); 112266423Sjfv 113270346Sjfvstatic void ixl_enable_rings(struct ixl_vsi *); 114270346Sjfvstatic void ixl_disable_rings(struct ixl_vsi *); 115270346Sjfvstatic void ixl_enable_intr(struct ixl_vsi *); 116270346Sjfvstatic void ixl_disable_intr(struct ixl_vsi *); 117266423Sjfv 118270346Sjfvstatic void ixl_enable_adminq(struct i40e_hw *); 119270346Sjfvstatic void ixl_disable_adminq(struct i40e_hw *); 120270346Sjfvstatic void ixl_enable_queue(struct i40e_hw *, int); 121270346Sjfvstatic void ixl_disable_queue(struct i40e_hw *, int); 122270346Sjfvstatic void ixl_enable_legacy(struct i40e_hw *); 123270346Sjfvstatic void ixl_disable_legacy(struct i40e_hw *); 124266423Sjfv 125270346Sjfvstatic void ixl_set_promisc(struct ixl_vsi *); 126270346Sjfvstatic void ixl_add_multi(struct ixl_vsi *); 127270346Sjfvstatic void ixl_del_multi(struct ixl_vsi *); 128270346Sjfvstatic void ixl_register_vlan(void *, struct ifnet *, u16); 129270346Sjfvstatic void ixl_unregister_vlan(void *, struct ifnet *, u16); 130270346Sjfvstatic void ixl_setup_vlan_filters(struct ixl_vsi *); 131266423Sjfv 132270346Sjfvstatic void ixl_init_filters(struct ixl_vsi *); 133270346Sjfvstatic void ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan); 134270346Sjfvstatic void ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan); 135270346Sjfvstatic void ixl_add_hw_filters(struct ixl_vsi *, int, int); 136270346Sjfvstatic void ixl_del_hw_filters(struct ixl_vsi *, int); 137270346Sjfvstatic struct ixl_mac_filter * 138270346Sjfv ixl_find_filter(struct ixl_vsi *, u8 *, s16); 139270346Sjfvstatic void ixl_add_mc_filter(struct ixl_vsi *, u8 *); 140266423Sjfv 141266423Sjfv/* Sysctl debug interface */ 142270346Sjfvstatic int ixl_debug_info(SYSCTL_HANDLER_ARGS); 143270346Sjfvstatic void ixl_print_debug_info(struct ixl_pf *); 144266423Sjfv 145266423Sjfv/* The MSI/X Interrupt handlers */ 146270346Sjfvstatic void ixl_intr(void *); 147270346Sjfvstatic void ixl_msix_que(void *); 148270346Sjfvstatic void ixl_msix_adminq(void *); 149270346Sjfvstatic void ixl_handle_mdd_event(struct ixl_pf *); 150266423Sjfv 151266423Sjfv/* Deferred interrupt tasklets */ 152270346Sjfvstatic void ixl_do_adminq(void *, int); 153266423Sjfv 154266423Sjfv/* Sysctl handlers */ 155270346Sjfvstatic int ixl_set_flowcntl(SYSCTL_HANDLER_ARGS); 156270346Sjfvstatic int ixl_set_advertise(SYSCTL_HANDLER_ARGS); 157270346Sjfvstatic int ixl_current_speed(SYSCTL_HANDLER_ARGS); 158266423Sjfv 159266423Sjfv/* Statistics */ 160270346Sjfvstatic void ixl_add_hw_stats(struct ixl_pf *); 161270346Sjfvstatic void ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *, 162266423Sjfv struct sysctl_oid_list *, struct i40e_hw_port_stats *); 163270346Sjfvstatic void ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *, 164266423Sjfv struct sysctl_oid_list *, 165266423Sjfv struct i40e_eth_stats *); 166270346Sjfvstatic void ixl_update_stats_counters(struct ixl_pf *); 167270346Sjfvstatic void ixl_update_eth_stats(struct ixl_vsi *); 168270346Sjfvstatic void ixl_pf_reset_stats(struct ixl_pf *); 169270346Sjfvstatic void ixl_vsi_reset_stats(struct ixl_vsi *); 170270346Sjfvstatic void ixl_stat_update48(struct i40e_hw *, u32, u32, bool, 171266423Sjfv u64 *, u64 *); 172270346Sjfvstatic void ixl_stat_update32(struct i40e_hw *, u32, bool, 173266423Sjfv u64 *, u64 *); 174266423Sjfv 175270346Sjfv#ifdef IXL_DEBUG 176270346Sjfvstatic int ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS); 177270346Sjfvstatic int ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS); 178270346Sjfvstatic int ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS); 179270346Sjfvstatic int ixl_sysctl_hw_res_info(SYSCTL_HANDLER_ARGS); 180270346Sjfvstatic int ixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS); 181266423Sjfv#endif 182266423Sjfv 183266423Sjfv/********************************************************************* 184266423Sjfv * FreeBSD Device Interface Entry Points 185266423Sjfv *********************************************************************/ 186266423Sjfv 187270346Sjfvstatic device_method_t ixl_methods[] = { 188266423Sjfv /* Device interface */ 189270346Sjfv DEVMETHOD(device_probe, ixl_probe), 190270346Sjfv DEVMETHOD(device_attach, ixl_attach), 191270346Sjfv DEVMETHOD(device_detach, ixl_detach), 192270346Sjfv DEVMETHOD(device_shutdown, ixl_shutdown), 193266423Sjfv {0, 0} 194266423Sjfv}; 195266423Sjfv 196270346Sjfvstatic driver_t ixl_driver = { 197270346Sjfv "ixl", ixl_methods, sizeof(struct ixl_pf), 198266423Sjfv}; 199266423Sjfv 200270346Sjfvdevclass_t ixl_devclass; 201270346SjfvDRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); 202266423Sjfv 203270346SjfvMODULE_DEPEND(ixl, pci, 1, 1, 1); 204270346SjfvMODULE_DEPEND(ixl, ether, 1, 1, 1); 205266423Sjfv 206266423Sjfv/* 207269198Sjfv** Global reset mutex 208269198Sjfv*/ 209270346Sjfvstatic struct mtx ixl_reset_mtx; 210269198Sjfv 211269198Sjfv/* 212270346Sjfv** TUNEABLE PARAMETERS: 213270346Sjfv*/ 214270346Sjfv 215270346Sjfvstatic SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, 216270346Sjfv "IXL driver parameters"); 217270346Sjfv 218270346Sjfv/* 219266423Sjfv * MSIX should be the default for best performance, 220266423Sjfv * but this allows it to be forced off for testing. 221266423Sjfv */ 222270346Sjfvstatic int ixl_enable_msix = 1; 223270346SjfvTUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); 224270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, 225270346Sjfv "Enable MSI-X interrupts"); 226266423Sjfv 227266423Sjfv/* 228266423Sjfv** Number of descriptors per ring: 229266423Sjfv** - TX and RX are the same size 230266423Sjfv*/ 231270346Sjfvstatic int ixl_ringsz = DEFAULT_RING; 232270346SjfvTUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz); 233270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN, 234270346Sjfv &ixl_ringsz, 0, "Descriptor Ring Size"); 235266423Sjfv 236266423Sjfv/* 237266423Sjfv** This can be set manually, if left as 0 the 238266423Sjfv** number of queues will be calculated based 239266423Sjfv** on cpus and msix vectors available. 240266423Sjfv*/ 241270346Sjfvint ixl_max_queues = 0; 242270346SjfvTUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues); 243270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN, 244270346Sjfv &ixl_max_queues, 0, "Number of Queues"); 245266423Sjfv 246266423Sjfv/* 247266423Sjfv** Controls for Interrupt Throttling 248266423Sjfv** - true/false for dynamic adjustment 249266423Sjfv** - default values for static ITR 250266423Sjfv*/ 251270346Sjfvint ixl_dynamic_rx_itr = 0; 252270346SjfvTUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr); 253270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, 254270346Sjfv &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); 255266423Sjfv 256270346Sjfvint ixl_dynamic_tx_itr = 0; 257270346SjfvTUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr); 258270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, 259270346Sjfv &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); 260266423Sjfv 261270346Sjfvint ixl_rx_itr = IXL_ITR_8K; 262270346SjfvTUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr); 263270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, 264270346Sjfv &ixl_rx_itr, 0, "RX Interrupt Rate"); 265270346Sjfv 266270346Sjfvint ixl_tx_itr = IXL_ITR_4K; 267270346SjfvTUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); 268270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, 269270346Sjfv &ixl_tx_itr, 0, "TX Interrupt Rate"); 270270346Sjfv 271270346Sjfv#ifdef IXL_FDIR 272270346Sjfvstatic int ixl_enable_fdir = 1; 273270346SjfvTUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir); 274266423Sjfv/* Rate at which we sample */ 275270346Sjfvint ixl_atr_rate = 20; 276270346SjfvTUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate); 277266423Sjfv#endif 278266423Sjfv 279270346Sjfv#ifdef DEV_NETMAP 280270346Sjfv#include <dev/netmap/if_ixl_netmap.h> 281270346Sjfv#endif /* DEV_NETMAP */ 282266423Sjfv 283270346Sjfvstatic char *ixl_fc_string[6] = { 284266423Sjfv "None", 285266423Sjfv "Rx", 286266423Sjfv "Tx", 287266423Sjfv "Full", 288266423Sjfv "Priority", 289266423Sjfv "Default" 290266423Sjfv}; 291266423Sjfv 292269198Sjfv 293266423Sjfv/********************************************************************* 294266423Sjfv * Device identification routine 295266423Sjfv * 296270346Sjfv * ixl_probe determines if the driver should be loaded on 297266423Sjfv * the hardware based on PCI vendor/device id of the device. 298266423Sjfv * 299266423Sjfv * return BUS_PROBE_DEFAULT on success, positive on failure 300266423Sjfv *********************************************************************/ 301266423Sjfv 302266423Sjfvstatic int 303270346Sjfvixl_probe(device_t dev) 304266423Sjfv{ 305270346Sjfv ixl_vendor_info_t *ent; 306266423Sjfv 307266423Sjfv u16 pci_vendor_id, pci_device_id; 308266423Sjfv u16 pci_subvendor_id, pci_subdevice_id; 309266423Sjfv char device_name[256]; 310269198Sjfv static bool lock_init = FALSE; 311266423Sjfv 312270346Sjfv INIT_DEBUGOUT("ixl_probe: begin"); 313266423Sjfv 314266423Sjfv pci_vendor_id = pci_get_vendor(dev); 315266423Sjfv if (pci_vendor_id != I40E_INTEL_VENDOR_ID) 316266423Sjfv return (ENXIO); 317266423Sjfv 318266423Sjfv pci_device_id = pci_get_device(dev); 319266423Sjfv pci_subvendor_id = pci_get_subvendor(dev); 320266423Sjfv pci_subdevice_id = pci_get_subdevice(dev); 321266423Sjfv 322270346Sjfv ent = ixl_vendor_info_array; 323266423Sjfv while (ent->vendor_id != 0) { 324266423Sjfv if ((pci_vendor_id == ent->vendor_id) && 325266423Sjfv (pci_device_id == ent->device_id) && 326266423Sjfv 327266423Sjfv ((pci_subvendor_id == ent->subvendor_id) || 328266423Sjfv (ent->subvendor_id == 0)) && 329266423Sjfv 330266423Sjfv ((pci_subdevice_id == ent->subdevice_id) || 331266423Sjfv (ent->subdevice_id == 0))) { 332266423Sjfv sprintf(device_name, "%s, Version - %s", 333270346Sjfv ixl_strings[ent->index], 334270346Sjfv ixl_driver_version); 335266423Sjfv device_set_desc_copy(dev, device_name); 336269198Sjfv /* One shot mutex init */ 337269198Sjfv if (lock_init == FALSE) { 338269198Sjfv lock_init = TRUE; 339270346Sjfv mtx_init(&ixl_reset_mtx, 340270346Sjfv "ixl_reset", 341270346Sjfv "IXL RESET Lock", MTX_DEF); 342269198Sjfv } 343266423Sjfv return (BUS_PROBE_DEFAULT); 344266423Sjfv } 345266423Sjfv ent++; 346266423Sjfv } 347266423Sjfv return (ENXIO); 348266423Sjfv} 349266423Sjfv 350266423Sjfv/********************************************************************* 351266423Sjfv * Device initialization routine 352266423Sjfv * 353266423Sjfv * The attach entry point is called when the driver is being loaded. 354266423Sjfv * This routine identifies the type of hardware, allocates all resources 355266423Sjfv * and initializes the hardware. 356266423Sjfv * 357266423Sjfv * return 0 on success, positive on failure 358266423Sjfv *********************************************************************/ 359266423Sjfv 360266423Sjfvstatic int 361270346Sjfvixl_attach(device_t dev) 362266423Sjfv{ 363270346Sjfv struct ixl_pf *pf; 364266423Sjfv struct i40e_hw *hw; 365270346Sjfv struct ixl_vsi *vsi; 366266423Sjfv u16 bus; 367266423Sjfv int error = 0; 368266423Sjfv 369270346Sjfv INIT_DEBUGOUT("ixl_attach: begin"); 370266423Sjfv 371266423Sjfv /* Allocate, clear, and link in our primary soft structure */ 372266423Sjfv pf = device_get_softc(dev); 373266423Sjfv pf->dev = pf->osdep.dev = dev; 374266423Sjfv hw = &pf->hw; 375266423Sjfv 376266423Sjfv /* 377266423Sjfv ** Note this assumes we have a single embedded VSI, 378266423Sjfv ** this could be enhanced later to allocate multiple 379266423Sjfv */ 380266423Sjfv vsi = &pf->vsi; 381266423Sjfv vsi->dev = pf->dev; 382266423Sjfv 383266423Sjfv /* Core Lock Init*/ 384270346Sjfv IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev)); 385266423Sjfv 386266423Sjfv /* Set up the timer callout */ 387266423Sjfv callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); 388266423Sjfv 389266423Sjfv /* Set up sysctls */ 390266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 391266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 392266423Sjfv OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, 393270346Sjfv pf, 0, ixl_set_flowcntl, "I", "Flow Control"); 394266423Sjfv 395269198Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 396269198Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 397269198Sjfv OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, 398270346Sjfv pf, 0, ixl_set_advertise, "I", "Advertised Speed"); 399269198Sjfv 400270346Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 401270346Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 402270346Sjfv OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD, 403270346Sjfv pf, 0, ixl_current_speed, "A", "Current Port Speed"); 404270346Sjfv 405266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 406266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 407266423Sjfv OID_AUTO, "rx_itr", CTLTYPE_INT | CTLFLAG_RW, 408270346Sjfv &ixl_rx_itr, IXL_ITR_8K, "RX ITR"); 409266423Sjfv 410266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 411266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 412266423Sjfv OID_AUTO, "dynamic_rx_itr", CTLTYPE_INT | CTLFLAG_RW, 413270346Sjfv &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR"); 414266423Sjfv 415266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 416266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 417266423Sjfv OID_AUTO, "tx_itr", CTLTYPE_INT | CTLFLAG_RW, 418270346Sjfv &ixl_tx_itr, IXL_ITR_4K, "TX ITR"); 419266423Sjfv 420266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 421266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 422266423Sjfv OID_AUTO, "dynamic_tx_itr", CTLTYPE_INT | CTLFLAG_RW, 423270346Sjfv &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR"); 424266423Sjfv 425270346Sjfv#ifdef IXL_DEBUG 426266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 427266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 428266423Sjfv OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD, 429270346Sjfv pf, 0, ixl_sysctl_link_status, "A", "Current Link Status"); 430266423Sjfv 431266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 432266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 433266423Sjfv OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD, 434270346Sjfv pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities"); 435266423Sjfv 436266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 437266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 438266423Sjfv OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD, 439270346Sjfv pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List"); 440269198Sjfv 441269198Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 442269198Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 443269198Sjfv OID_AUTO, "hw_res_info", CTLTYPE_STRING | CTLFLAG_RD, 444270346Sjfv pf, 0, ixl_sysctl_hw_res_info, "A", "HW Resource Allocation"); 445269198Sjfv 446269198Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 447269198Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 448269198Sjfv OID_AUTO, "dump_desc", CTLTYPE_INT | CTLFLAG_WR, 449270346Sjfv pf, 0, ixl_sysctl_dump_txd, "I", "Desc dump"); 450266423Sjfv#endif 451266423Sjfv 452266423Sjfv /* Save off the information about this board */ 453266423Sjfv hw->vendor_id = pci_get_vendor(dev); 454266423Sjfv hw->device_id = pci_get_device(dev); 455266423Sjfv hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 456266423Sjfv hw->subsystem_vendor_id = 457266423Sjfv pci_read_config(dev, PCIR_SUBVEND_0, 2); 458266423Sjfv hw->subsystem_device_id = 459266423Sjfv pci_read_config(dev, PCIR_SUBDEV_0, 2); 460266423Sjfv 461269198Sjfv hw->bus.device = pci_get_slot(dev); 462266423Sjfv hw->bus.func = pci_get_function(dev); 463266423Sjfv 464266423Sjfv /* Do PCI setup - map BAR0, etc */ 465270346Sjfv if (ixl_allocate_pci_resources(pf)) { 466266423Sjfv device_printf(dev, "Allocation of PCI resources failed\n"); 467266423Sjfv error = ENXIO; 468266423Sjfv goto err_out; 469266423Sjfv } 470266423Sjfv 471266423Sjfv /* Create for initial debugging use */ 472266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 473266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 474266423Sjfv OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0, 475270346Sjfv ixl_debug_info, "I", "Debug Information"); 476266423Sjfv 477266423Sjfv 478266423Sjfv /* Establish a clean starting point */ 479269198Sjfv i40e_clear_hw(hw); 480266423Sjfv error = i40e_pf_reset(hw); 481266423Sjfv if (error) { 482269198Sjfv device_printf(dev,"PF reset failure %x\n", error); 483269198Sjfv error = EIO; 484269198Sjfv goto err_out; 485269198Sjfv } 486266423Sjfv 487269198Sjfv /* For now always do an initial CORE reset on first device */ 488269198Sjfv { 489270346Sjfv static int ixl_dev_count; 490270346Sjfv static int ixl_dev_track[32]; 491269198Sjfv u32 my_dev; 492269198Sjfv int i, found = FALSE; 493269198Sjfv u16 bus = pci_get_bus(dev); 494269198Sjfv 495270346Sjfv mtx_lock(&ixl_reset_mtx); 496269198Sjfv my_dev = (bus << 8) | hw->bus.device; 497269198Sjfv 498270346Sjfv for (i = 0; i < ixl_dev_count; i++) { 499270346Sjfv if (ixl_dev_track[i] == my_dev) 500269198Sjfv found = TRUE; 501266423Sjfv } 502269198Sjfv 503269198Sjfv if (!found) { 504269198Sjfv u32 reg; 505269198Sjfv 506270346Sjfv ixl_dev_track[ixl_dev_count] = my_dev; 507270346Sjfv ixl_dev_count++; 508269198Sjfv 509270346Sjfv INIT_DEBUGOUT("Initial CORE RESET\n"); 510269198Sjfv wr32(hw, I40E_GLGEN_RTRIG, I40E_GLGEN_RTRIG_CORER_MASK); 511270346Sjfv ixl_flush(hw); 512269198Sjfv i = 50; 513269198Sjfv do { 514269198Sjfv i40e_msec_delay(50); 515269198Sjfv reg = rd32(hw, I40E_GLGEN_RSTAT); 516269198Sjfv if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK)) 517269198Sjfv break; 518269198Sjfv } while (i--); 519269198Sjfv 520269198Sjfv /* paranoia */ 521269198Sjfv wr32(hw, I40E_PF_ATQLEN, 0); 522269198Sjfv wr32(hw, I40E_PF_ATQBAL, 0); 523269198Sjfv wr32(hw, I40E_PF_ATQBAH, 0); 524269198Sjfv i40e_clear_pxe_mode(hw); 525269198Sjfv } 526270346Sjfv mtx_unlock(&ixl_reset_mtx); 527266423Sjfv } 528266423Sjfv 529266423Sjfv /* Set admin queue parameters */ 530270346Sjfv hw->aq.num_arq_entries = IXL_AQ_LEN; 531270346Sjfv hw->aq.num_asq_entries = IXL_AQ_LEN; 532270346Sjfv hw->aq.arq_buf_size = IXL_AQ_BUFSZ; 533270346Sjfv hw->aq.asq_buf_size = IXL_AQ_BUFSZ; 534266423Sjfv 535266423Sjfv /* Initialize the shared code */ 536266423Sjfv error = i40e_init_shared_code(hw); 537266423Sjfv if (error) { 538266423Sjfv device_printf(dev,"Unable to initialize the shared code\n"); 539266423Sjfv error = EIO; 540266423Sjfv goto err_out; 541266423Sjfv } 542266423Sjfv 543266423Sjfv /* Set up the admin queue */ 544266423Sjfv error = i40e_init_adminq(hw); 545266423Sjfv if (error) { 546269198Sjfv device_printf(dev, "The driver for the device stopped " 547269198Sjfv "because the NVM image is newer than expected.\n" 548269198Sjfv "You must install the most recent version of " 549269198Sjfv " the network driver.\n"); 550266423Sjfv goto err_out; 551266423Sjfv } 552270346Sjfv device_printf(dev, "%s\n", ixl_fw_version_str(hw)); 553266423Sjfv 554269198Sjfv if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 555269198Sjfv hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) 556269198Sjfv device_printf(dev, "The driver for the device detected " 557269198Sjfv "a newer version of the NVM image than expected.\n" 558269198Sjfv "Please install the most recent version of the network driver.\n"); 559269198Sjfv else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || 560269198Sjfv hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) 561269198Sjfv device_printf(dev, "The driver for the device detected " 562269198Sjfv "an older version of the NVM image than expected.\n" 563269198Sjfv "Please update the NVM image.\n"); 564266423Sjfv 565266423Sjfv /* Clear PXE mode */ 566266423Sjfv i40e_clear_pxe_mode(hw); 567266423Sjfv 568266423Sjfv /* Get capabilities from the device */ 569270346Sjfv error = ixl_get_hw_capabilities(pf); 570266423Sjfv if (error) { 571266423Sjfv device_printf(dev, "HW capabilities failure!\n"); 572266423Sjfv goto err_get_cap; 573266423Sjfv } 574266423Sjfv 575266423Sjfv /* Set up host memory cache */ 576266423Sjfv error = i40e_init_lan_hmc(hw, vsi->num_queues, vsi->num_queues, 0, 0); 577266423Sjfv if (error) { 578266423Sjfv device_printf(dev, "init_lan_hmc failed: %d\n", error); 579266423Sjfv goto err_get_cap; 580266423Sjfv } 581266423Sjfv 582266423Sjfv error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 583266423Sjfv if (error) { 584266423Sjfv device_printf(dev, "configure_lan_hmc failed: %d\n", error); 585266423Sjfv goto err_mac_hmc; 586266423Sjfv } 587266423Sjfv 588269198Sjfv /* Disable LLDP from the firmware */ 589269198Sjfv i40e_aq_stop_lldp(hw, TRUE, NULL); 590269198Sjfv 591266423Sjfv i40e_get_mac_addr(hw, hw->mac.addr); 592266423Sjfv error = i40e_validate_mac_addr(hw->mac.addr); 593266423Sjfv if (error) { 594266423Sjfv device_printf(dev, "validate_mac_addr failed: %d\n", error); 595266423Sjfv goto err_mac_hmc; 596266423Sjfv } 597266423Sjfv bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 598266423Sjfv i40e_get_port_mac_addr(hw, hw->mac.port_addr); 599266423Sjfv 600270346Sjfv if (ixl_setup_stations(pf) != 0) { 601266423Sjfv device_printf(dev, "setup stations failed!\n"); 602266423Sjfv error = ENOMEM; 603266423Sjfv goto err_mac_hmc; 604266423Sjfv } 605266423Sjfv 606266423Sjfv /* Initialize mac filter list for VSI */ 607266423Sjfv SLIST_INIT(&vsi->ftl); 608266423Sjfv 609266423Sjfv /* Set up interrupt routing here */ 610266423Sjfv if (pf->msix > 1) 611270346Sjfv error = ixl_assign_vsi_msix(pf); 612266423Sjfv else 613270346Sjfv error = ixl_assign_vsi_legacy(pf); 614266423Sjfv if (error) 615266423Sjfv goto err_late; 616266423Sjfv 617270346Sjfv i40e_msec_delay(75); 618270346Sjfv error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 619270346Sjfv if (error) { 620270346Sjfv device_printf(dev, "link restart failed, aq_err=%d\n", 621270346Sjfv pf->hw.aq.asq_last_status); 622270346Sjfv } 623270346Sjfv 624266423Sjfv /* Determine link state */ 625270346Sjfv vsi->link_up = ixl_config_link(hw); 626266423Sjfv 627269198Sjfv /* Report if Unqualified modules are found */ 628269198Sjfv if ((vsi->link_up == FALSE) && 629269198Sjfv (pf->hw.phy.link_info.link_info & 630269198Sjfv I40E_AQ_MEDIA_AVAILABLE) && 631269198Sjfv (!(pf->hw.phy.link_info.an_info & 632269198Sjfv I40E_AQ_QUALIFIED_MODULE))) 633269198Sjfv device_printf(dev, "Link failed because " 634269198Sjfv "an unqualified module was detected\n"); 635269198Sjfv 636266423Sjfv /* Setup OS specific network interface */ 637270346Sjfv if (ixl_setup_interface(dev, vsi) != 0) 638266423Sjfv goto err_late; 639266423Sjfv 640266423Sjfv /* Get the bus configuration and set the shared code */ 641270346Sjfv bus = ixl_get_bus_info(hw, dev); 642266423Sjfv i40e_set_pci_config_data(hw, bus); 643266423Sjfv 644266423Sjfv /* Initialize statistics */ 645270346Sjfv ixl_pf_reset_stats(pf); 646270346Sjfv ixl_update_stats_counters(pf); 647270346Sjfv ixl_add_hw_stats(pf); 648266423Sjfv 649266423Sjfv /* Register for VLAN events */ 650266423Sjfv vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 651270346Sjfv ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); 652266423Sjfv vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 653270346Sjfv ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); 654266423Sjfv 655270346Sjfv#ifdef DEV_NETMAP 656270346Sjfv ixl_netmap_attach(pf); 657270346Sjfv#endif /* DEV_NETMAP */ 658269198Sjfv 659270346Sjfv INIT_DEBUGOUT("ixl_attach: end"); 660266423Sjfv return (0); 661266423Sjfv 662266423Sjfverr_late: 663270346Sjfv ixl_free_vsi(vsi); 664266423Sjfverr_mac_hmc: 665266423Sjfv i40e_shutdown_lan_hmc(hw); 666266423Sjfverr_get_cap: 667266423Sjfv i40e_shutdown_adminq(hw); 668266423Sjfverr_out: 669266423Sjfv if (vsi->ifp != NULL) 670266423Sjfv if_free(vsi->ifp); 671270346Sjfv ixl_free_pci_resources(pf); 672270346Sjfv IXL_PF_LOCK_DESTROY(pf); 673266423Sjfv return (error); 674266423Sjfv} 675266423Sjfv 676266423Sjfv/********************************************************************* 677266423Sjfv * Device removal routine 678266423Sjfv * 679266423Sjfv * The detach entry point is called when the driver is being removed. 680266423Sjfv * This routine stops the adapter and deallocates all the resources 681266423Sjfv * that were allocated for driver operation. 682266423Sjfv * 683266423Sjfv * return 0 on success, positive on failure 684266423Sjfv *********************************************************************/ 685266423Sjfv 686266423Sjfvstatic int 687270346Sjfvixl_detach(device_t dev) 688266423Sjfv{ 689270346Sjfv struct ixl_pf *pf = device_get_softc(dev); 690266423Sjfv struct i40e_hw *hw = &pf->hw; 691270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 692270346Sjfv struct ixl_queue *que = vsi->queues; 693266423Sjfv i40e_status status; 694266423Sjfv 695270346Sjfv INIT_DEBUGOUT("ixl_detach: begin"); 696266423Sjfv 697266423Sjfv /* Make sure VLANS are not using driver */ 698266423Sjfv if (vsi->ifp->if_vlantrunk != NULL) { 699266423Sjfv device_printf(dev,"Vlan in use, detach first\n"); 700266423Sjfv return (EBUSY); 701266423Sjfv } 702266423Sjfv 703270346Sjfv IXL_PF_LOCK(pf); 704270346Sjfv ixl_stop(pf); 705270346Sjfv IXL_PF_UNLOCK(pf); 706266423Sjfv 707266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 708266423Sjfv if (que->tq) { 709266423Sjfv taskqueue_drain(que->tq, &que->task); 710266423Sjfv taskqueue_drain(que->tq, &que->tx_task); 711266423Sjfv taskqueue_free(que->tq); 712266423Sjfv } 713266423Sjfv } 714266423Sjfv 715266423Sjfv /* Shutdown LAN HMC */ 716266423Sjfv status = i40e_shutdown_lan_hmc(hw); 717266423Sjfv if (status) 718266423Sjfv device_printf(dev, 719266423Sjfv "Shutdown LAN HMC failed with code %d\n", status); 720266423Sjfv 721266423Sjfv /* Shutdown admin queue */ 722266423Sjfv status = i40e_shutdown_adminq(hw); 723266423Sjfv if (status) 724266423Sjfv device_printf(dev, 725266423Sjfv "Shutdown Admin queue failed with code %d\n", status); 726266423Sjfv 727266423Sjfv /* Unregister VLAN events */ 728266423Sjfv if (vsi->vlan_attach != NULL) 729266423Sjfv EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); 730266423Sjfv if (vsi->vlan_detach != NULL) 731266423Sjfv EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); 732266423Sjfv 733266423Sjfv ether_ifdetach(vsi->ifp); 734266423Sjfv callout_drain(&pf->timer); 735266423Sjfv 736270346Sjfv#ifdef DEV_NETMAP 737270346Sjfv netmap_detach(vsi->ifp); 738270346Sjfv#endif /* DEV_NETMAP */ 739266423Sjfv 740270346Sjfv ixl_free_pci_resources(pf); 741266423Sjfv bus_generic_detach(dev); 742266423Sjfv if_free(vsi->ifp); 743270346Sjfv ixl_free_vsi(vsi); 744270346Sjfv IXL_PF_LOCK_DESTROY(pf); 745266423Sjfv return (0); 746266423Sjfv} 747266423Sjfv 748266423Sjfv/********************************************************************* 749266423Sjfv * 750266423Sjfv * Shutdown entry point 751266423Sjfv * 752266423Sjfv **********************************************************************/ 753266423Sjfv 754266423Sjfvstatic int 755270346Sjfvixl_shutdown(device_t dev) 756266423Sjfv{ 757270346Sjfv struct ixl_pf *pf = device_get_softc(dev); 758270346Sjfv IXL_PF_LOCK(pf); 759270346Sjfv ixl_stop(pf); 760270346Sjfv IXL_PF_UNLOCK(pf); 761266423Sjfv return (0); 762266423Sjfv} 763266423Sjfv 764266423Sjfv 765266423Sjfv/********************************************************************* 766266423Sjfv * 767266423Sjfv * Get the hardware capabilities 768266423Sjfv * 769266423Sjfv **********************************************************************/ 770266423Sjfv 771266423Sjfvstatic int 772270346Sjfvixl_get_hw_capabilities(struct ixl_pf *pf) 773266423Sjfv{ 774266423Sjfv struct i40e_aqc_list_capabilities_element_resp *buf; 775266423Sjfv struct i40e_hw *hw = &pf->hw; 776266423Sjfv device_t dev = pf->dev; 777266423Sjfv int error, len; 778266423Sjfv u16 needed; 779266423Sjfv bool again = TRUE; 780266423Sjfv 781266423Sjfv len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); 782266423Sjfvretry: 783266423Sjfv if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *) 784266423Sjfv malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) { 785266423Sjfv device_printf(dev, "Unable to allocate cap memory\n"); 786266423Sjfv return (ENOMEM); 787266423Sjfv } 788266423Sjfv 789266423Sjfv /* This populates the hw struct */ 790266423Sjfv error = i40e_aq_discover_capabilities(hw, buf, len, 791266423Sjfv &needed, i40e_aqc_opc_list_func_capabilities, NULL); 792266423Sjfv free(buf, M_DEVBUF); 793266423Sjfv if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && 794266423Sjfv (again == TRUE)) { 795266423Sjfv /* retry once with a larger buffer */ 796266423Sjfv again = FALSE; 797266423Sjfv len = needed; 798266423Sjfv goto retry; 799266423Sjfv } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { 800266423Sjfv device_printf(dev, "capability discovery failed: %d\n", 801266423Sjfv pf->hw.aq.asq_last_status); 802266423Sjfv return (ENODEV); 803266423Sjfv } 804266423Sjfv 805266423Sjfv /* Capture this PF's starting queue pair */ 806266423Sjfv pf->qbase = hw->func_caps.base_queue; 807266423Sjfv 808270346Sjfv#ifdef IXL_DEBUG 809266423Sjfv device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, " 810266423Sjfv "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", 811266423Sjfv hw->pf_id, hw->func_caps.num_vfs, 812266423Sjfv hw->func_caps.num_msix_vectors, 813266423Sjfv hw->func_caps.num_msix_vectors_vf, 814266423Sjfv hw->func_caps.fd_filters_guaranteed, 815266423Sjfv hw->func_caps.fd_filters_best_effort, 816266423Sjfv hw->func_caps.num_tx_qp, 817266423Sjfv hw->func_caps.num_rx_qp, 818266423Sjfv hw->func_caps.base_queue); 819266423Sjfv#endif 820266423Sjfv return (error); 821266423Sjfv} 822266423Sjfv 823266423Sjfvstatic void 824270346Sjfvixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) 825266423Sjfv{ 826266423Sjfv device_t dev = vsi->dev; 827266423Sjfv 828266423Sjfv /* Enable/disable TXCSUM/TSO4 */ 829266423Sjfv if (!(ifp->if_capenable & IFCAP_TXCSUM) 830266423Sjfv && !(ifp->if_capenable & IFCAP_TSO4)) { 831266423Sjfv if (mask & IFCAP_TXCSUM) { 832266423Sjfv ifp->if_capenable |= IFCAP_TXCSUM; 833266423Sjfv /* enable TXCSUM, restore TSO if previously enabled */ 834270346Sjfv if (vsi->flags & IXL_FLAGS_KEEP_TSO4) { 835270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 836266423Sjfv ifp->if_capenable |= IFCAP_TSO4; 837266423Sjfv } 838266423Sjfv } 839266423Sjfv else if (mask & IFCAP_TSO4) { 840266423Sjfv ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); 841270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; 842266423Sjfv device_printf(dev, 843266423Sjfv "TSO4 requires txcsum, enabling both...\n"); 844266423Sjfv } 845266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM) 846266423Sjfv && !(ifp->if_capenable & IFCAP_TSO4)) { 847266423Sjfv if (mask & IFCAP_TXCSUM) 848266423Sjfv ifp->if_capenable &= ~IFCAP_TXCSUM; 849266423Sjfv else if (mask & IFCAP_TSO4) 850266423Sjfv ifp->if_capenable |= IFCAP_TSO4; 851266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM) 852266423Sjfv && (ifp->if_capenable & IFCAP_TSO4)) { 853266423Sjfv if (mask & IFCAP_TXCSUM) { 854270346Sjfv vsi->flags |= IXL_FLAGS_KEEP_TSO4; 855266423Sjfv ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); 856266423Sjfv device_printf(dev, 857266423Sjfv "TSO4 requires txcsum, disabling both...\n"); 858266423Sjfv } else if (mask & IFCAP_TSO4) 859266423Sjfv ifp->if_capenable &= ~IFCAP_TSO4; 860266423Sjfv } 861266423Sjfv 862266423Sjfv /* Enable/disable TXCSUM_IPV6/TSO6 */ 863266423Sjfv if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) 864266423Sjfv && !(ifp->if_capenable & IFCAP_TSO6)) { 865266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) { 866266423Sjfv ifp->if_capenable |= IFCAP_TXCSUM_IPV6; 867270346Sjfv if (vsi->flags & IXL_FLAGS_KEEP_TSO6) { 868270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 869266423Sjfv ifp->if_capenable |= IFCAP_TSO6; 870266423Sjfv } 871266423Sjfv } else if (mask & IFCAP_TSO6) { 872266423Sjfv ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 873270346Sjfv vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; 874266423Sjfv device_printf(dev, 875266423Sjfv "TSO6 requires txcsum6, enabling both...\n"); 876266423Sjfv } 877266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 878266423Sjfv && !(ifp->if_capenable & IFCAP_TSO6)) { 879266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) 880266423Sjfv ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; 881266423Sjfv else if (mask & IFCAP_TSO6) 882266423Sjfv ifp->if_capenable |= IFCAP_TSO6; 883266423Sjfv } else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 884266423Sjfv && (ifp->if_capenable & IFCAP_TSO6)) { 885266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) { 886270346Sjfv vsi->flags |= IXL_FLAGS_KEEP_TSO6; 887266423Sjfv ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 888266423Sjfv device_printf(dev, 889266423Sjfv "TSO6 requires txcsum6, disabling both...\n"); 890266423Sjfv } else if (mask & IFCAP_TSO6) 891266423Sjfv ifp->if_capenable &= ~IFCAP_TSO6; 892266423Sjfv } 893266423Sjfv} 894266423Sjfv 895266423Sjfv/********************************************************************* 896266423Sjfv * Ioctl entry point 897266423Sjfv * 898270346Sjfv * ixl_ioctl is called when the user wants to configure the 899266423Sjfv * interface. 900266423Sjfv * 901266423Sjfv * return 0 on success, positive on failure 902266423Sjfv **********************************************************************/ 903266423Sjfv 904266423Sjfvstatic int 905270346Sjfvixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 906266423Sjfv{ 907270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 908270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 909266423Sjfv struct ifreq *ifr = (struct ifreq *) data; 910266423Sjfv#if defined(INET) || defined(INET6) 911266423Sjfv struct ifaddr *ifa = (struct ifaddr *)data; 912266423Sjfv bool avoid_reset = FALSE; 913266423Sjfv#endif 914266423Sjfv int error = 0; 915266423Sjfv 916266423Sjfv switch (command) { 917266423Sjfv 918266423Sjfv case SIOCSIFADDR: 919266423Sjfv#ifdef INET 920266423Sjfv if (ifa->ifa_addr->sa_family == AF_INET) 921266423Sjfv avoid_reset = TRUE; 922266423Sjfv#endif 923266423Sjfv#ifdef INET6 924266423Sjfv if (ifa->ifa_addr->sa_family == AF_INET6) 925266423Sjfv avoid_reset = TRUE; 926266423Sjfv#endif 927266423Sjfv#if defined(INET) || defined(INET6) 928266423Sjfv /* 929266423Sjfv ** Calling init results in link renegotiation, 930266423Sjfv ** so we avoid doing it when possible. 931266423Sjfv */ 932266423Sjfv if (avoid_reset) { 933266423Sjfv ifp->if_flags |= IFF_UP; 934266423Sjfv if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 935270346Sjfv ixl_init(pf); 936266423Sjfv if (!(ifp->if_flags & IFF_NOARP)) 937266423Sjfv arp_ifinit(ifp, ifa); 938266423Sjfv } else 939266423Sjfv error = ether_ioctl(ifp, command, data); 940266423Sjfv break; 941266423Sjfv#endif 942266423Sjfv case SIOCSIFMTU: 943266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 944270346Sjfv if (ifr->ifr_mtu > IXL_MAX_FRAME - 945266423Sjfv ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) { 946266423Sjfv error = EINVAL; 947266423Sjfv } else { 948270346Sjfv IXL_PF_LOCK(pf); 949266423Sjfv ifp->if_mtu = ifr->ifr_mtu; 950266423Sjfv vsi->max_frame_size = 951266423Sjfv ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 952266423Sjfv + ETHER_VLAN_ENCAP_LEN; 953270346Sjfv ixl_init_locked(pf); 954270346Sjfv IXL_PF_UNLOCK(pf); 955266423Sjfv } 956266423Sjfv break; 957266423Sjfv case SIOCSIFFLAGS: 958266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 959270346Sjfv IXL_PF_LOCK(pf); 960266423Sjfv if (ifp->if_flags & IFF_UP) { 961266423Sjfv if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 962266423Sjfv if ((ifp->if_flags ^ pf->if_flags) & 963266423Sjfv (IFF_PROMISC | IFF_ALLMULTI)) { 964270346Sjfv ixl_set_promisc(vsi); 965266423Sjfv } 966266423Sjfv } else 967270346Sjfv ixl_init_locked(pf); 968266423Sjfv } else 969266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) 970270346Sjfv ixl_stop(pf); 971266423Sjfv pf->if_flags = ifp->if_flags; 972270346Sjfv IXL_PF_UNLOCK(pf); 973266423Sjfv break; 974266423Sjfv case SIOCADDMULTI: 975266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); 976266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 977270346Sjfv IXL_PF_LOCK(pf); 978270346Sjfv ixl_disable_intr(vsi); 979270346Sjfv ixl_add_multi(vsi); 980270346Sjfv ixl_enable_intr(vsi); 981270346Sjfv IXL_PF_UNLOCK(pf); 982266423Sjfv } 983266423Sjfv break; 984266423Sjfv case SIOCDELMULTI: 985266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); 986266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 987270346Sjfv IXL_PF_LOCK(pf); 988270346Sjfv ixl_disable_intr(vsi); 989270346Sjfv ixl_del_multi(vsi); 990270346Sjfv ixl_enable_intr(vsi); 991270346Sjfv IXL_PF_UNLOCK(pf); 992266423Sjfv } 993266423Sjfv break; 994266423Sjfv case SIOCSIFMEDIA: 995266423Sjfv case SIOCGIFMEDIA: 996266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 997266423Sjfv error = ifmedia_ioctl(ifp, ifr, &vsi->media, command); 998266423Sjfv break; 999266423Sjfv case SIOCSIFCAP: 1000266423Sjfv { 1001266423Sjfv int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1002266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 1003266423Sjfv 1004270346Sjfv ixl_cap_txcsum_tso(vsi, ifp, mask); 1005266423Sjfv 1006266423Sjfv if (mask & IFCAP_RXCSUM) 1007266423Sjfv ifp->if_capenable ^= IFCAP_RXCSUM; 1008266423Sjfv if (mask & IFCAP_RXCSUM_IPV6) 1009266423Sjfv ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1010266423Sjfv if (mask & IFCAP_LRO) 1011266423Sjfv ifp->if_capenable ^= IFCAP_LRO; 1012266423Sjfv if (mask & IFCAP_VLAN_HWTAGGING) 1013266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1014266423Sjfv if (mask & IFCAP_VLAN_HWFILTER) 1015266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 1016266423Sjfv if (mask & IFCAP_VLAN_HWTSO) 1017266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1018266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1019270346Sjfv IXL_PF_LOCK(pf); 1020270346Sjfv ixl_init_locked(pf); 1021270346Sjfv IXL_PF_UNLOCK(pf); 1022266423Sjfv } 1023266423Sjfv VLAN_CAPABILITIES(ifp); 1024266423Sjfv 1025266423Sjfv break; 1026266423Sjfv } 1027266423Sjfv 1028266423Sjfv default: 1029270346Sjfv IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command); 1030266423Sjfv error = ether_ioctl(ifp, command, data); 1031266423Sjfv break; 1032266423Sjfv } 1033266423Sjfv 1034266423Sjfv return (error); 1035266423Sjfv} 1036266423Sjfv 1037266423Sjfv 1038266423Sjfv/********************************************************************* 1039266423Sjfv * Init entry point 1040266423Sjfv * 1041266423Sjfv * This routine is used in two ways. It is used by the stack as 1042266423Sjfv * init entry point in network interface structure. It is also used 1043266423Sjfv * by the driver as a hw/sw initialization routine to get to a 1044266423Sjfv * consistent state. 1045266423Sjfv * 1046266423Sjfv * return 0 on success, positive on failure 1047266423Sjfv **********************************************************************/ 1048266423Sjfv 1049266423Sjfvstatic void 1050270346Sjfvixl_init_locked(struct ixl_pf *pf) 1051266423Sjfv{ 1052266423Sjfv struct i40e_hw *hw = &pf->hw; 1053270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1054266423Sjfv struct ifnet *ifp = vsi->ifp; 1055266423Sjfv device_t dev = pf->dev; 1056266423Sjfv struct i40e_filter_control_settings filter; 1057266423Sjfv u8 tmpaddr[ETHER_ADDR_LEN]; 1058266423Sjfv int ret; 1059266423Sjfv 1060266423Sjfv mtx_assert(&pf->pf_mtx, MA_OWNED); 1061270346Sjfv INIT_DEBUGOUT("ixl_init: begin"); 1062270346Sjfv ixl_stop(pf); 1063266423Sjfv 1064266423Sjfv /* Get the latest mac address... User might use a LAA */ 1065266423Sjfv bcopy(IF_LLADDR(vsi->ifp), tmpaddr, 1066266423Sjfv I40E_ETH_LENGTH_OF_ADDRESS); 1067266423Sjfv if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && 1068266423Sjfv i40e_validate_mac_addr(tmpaddr)) { 1069266423Sjfv bcopy(tmpaddr, hw->mac.addr, 1070266423Sjfv I40E_ETH_LENGTH_OF_ADDRESS); 1071266423Sjfv ret = i40e_aq_mac_address_write(hw, 1072266423Sjfv I40E_AQC_WRITE_TYPE_LAA_ONLY, 1073266423Sjfv hw->mac.addr, NULL); 1074266423Sjfv if (ret) { 1075266423Sjfv device_printf(dev, "LLA address" 1076266423Sjfv "change failed!!\n"); 1077266423Sjfv return; 1078266423Sjfv } 1079266423Sjfv } 1080266423Sjfv 1081266423Sjfv /* Set the various hardware offload abilities */ 1082266423Sjfv ifp->if_hwassist = 0; 1083266423Sjfv if (ifp->if_capenable & IFCAP_TSO) 1084266423Sjfv ifp->if_hwassist |= CSUM_TSO; 1085266423Sjfv if (ifp->if_capenable & IFCAP_TXCSUM) 1086266423Sjfv ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 1087266423Sjfv if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 1088266423Sjfv ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); 1089266423Sjfv 1090266423Sjfv /* Set up the device filtering */ 1091266423Sjfv bzero(&filter, sizeof(filter)); 1092266423Sjfv filter.enable_ethtype = TRUE; 1093266423Sjfv filter.enable_macvlan = TRUE; 1094270346Sjfv#ifdef IXL_FDIR 1095266423Sjfv filter.enable_fdir = TRUE; 1096266423Sjfv#endif 1097266423Sjfv if (i40e_set_filter_control(hw, &filter)) 1098266423Sjfv device_printf(dev, "set_filter_control() failed\n"); 1099266423Sjfv 1100266423Sjfv /* Set up RSS */ 1101270346Sjfv ixl_config_rss(vsi); 1102266423Sjfv 1103266423Sjfv /* Setup the VSI */ 1104270346Sjfv ixl_setup_vsi(vsi); 1105266423Sjfv 1106266423Sjfv /* 1107266423Sjfv ** Prepare the rings, hmc contexts, etc... 1108266423Sjfv */ 1109270346Sjfv if (ixl_initialize_vsi(vsi)) { 1110270346Sjfv device_printf(dev, "initialize vsi failed!!\n"); 1111266423Sjfv return; 1112266423Sjfv } 1113266423Sjfv 1114266423Sjfv /* Add protocol filters to list */ 1115270346Sjfv ixl_init_filters(vsi); 1116266423Sjfv 1117266423Sjfv /* Setup vlan's if needed */ 1118270346Sjfv ixl_setup_vlan_filters(vsi); 1119266423Sjfv 1120266423Sjfv /* Start the local timer */ 1121270346Sjfv callout_reset(&pf->timer, hz, ixl_local_timer, pf); 1122266423Sjfv 1123266423Sjfv /* Set up MSI/X routing and the ITR settings */ 1124270346Sjfv if (ixl_enable_msix) { 1125270346Sjfv ixl_configure_msix(pf); 1126270346Sjfv ixl_configure_itr(pf); 1127266423Sjfv } else 1128270346Sjfv ixl_configure_legacy(pf); 1129266423Sjfv 1130270346Sjfv ixl_enable_rings(vsi); 1131266423Sjfv 1132266423Sjfv i40e_aq_set_default_vsi(hw, vsi->seid, NULL); 1133266423Sjfv 1134266423Sjfv /* Set MTU in hardware*/ 1135270346Sjfv int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size, 1136270346Sjfv TRUE, 0, NULL); 1137270346Sjfv if (aq_error) 1138270346Sjfv device_printf(vsi->dev, 1139270346Sjfv "aq_set_mac_config in init error, code %d\n", 1140270346Sjfv aq_error); 1141266423Sjfv 1142266423Sjfv /* And now turn on interrupts */ 1143270346Sjfv ixl_enable_intr(vsi); 1144266423Sjfv 1145266423Sjfv /* Now inform the stack we're ready */ 1146266423Sjfv ifp->if_drv_flags |= IFF_DRV_RUNNING; 1147266423Sjfv ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1148266423Sjfv 1149266423Sjfv return; 1150266423Sjfv} 1151266423Sjfv 1152266423Sjfvstatic void 1153270346Sjfvixl_init(void *arg) 1154266423Sjfv{ 1155270346Sjfv struct ixl_pf *pf = arg; 1156266423Sjfv 1157270346Sjfv IXL_PF_LOCK(pf); 1158270346Sjfv ixl_init_locked(pf); 1159270346Sjfv IXL_PF_UNLOCK(pf); 1160266423Sjfv return; 1161266423Sjfv} 1162266423Sjfv 1163266423Sjfv/* 1164266423Sjfv** 1165266423Sjfv** MSIX Interrupt Handlers and Tasklets 1166266423Sjfv** 1167266423Sjfv*/ 1168266423Sjfvstatic void 1169270346Sjfvixl_handle_que(void *context, int pending) 1170266423Sjfv{ 1171270346Sjfv struct ixl_queue *que = context; 1172270346Sjfv struct ixl_vsi *vsi = que->vsi; 1173266423Sjfv struct i40e_hw *hw = vsi->hw; 1174266423Sjfv struct tx_ring *txr = &que->txr; 1175266423Sjfv struct ifnet *ifp = vsi->ifp; 1176266423Sjfv bool more; 1177266423Sjfv 1178266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1179270346Sjfv more = ixl_rxeof(que, IXL_RX_LIMIT); 1180270346Sjfv IXL_TX_LOCK(txr); 1181270346Sjfv ixl_txeof(que); 1182266423Sjfv if (!drbr_empty(ifp, txr->br)) 1183270346Sjfv ixl_mq_start_locked(ifp, txr); 1184270346Sjfv IXL_TX_UNLOCK(txr); 1185266423Sjfv if (more) { 1186266423Sjfv taskqueue_enqueue(que->tq, &que->task); 1187266423Sjfv return; 1188266423Sjfv } 1189266423Sjfv } 1190266423Sjfv 1191266423Sjfv /* Reenable this interrupt - hmmm */ 1192270346Sjfv ixl_enable_queue(hw, que->me); 1193266423Sjfv return; 1194266423Sjfv} 1195266423Sjfv 1196266423Sjfv 1197266423Sjfv/********************************************************************* 1198266423Sjfv * 1199266423Sjfv * Legacy Interrupt Service routine 1200266423Sjfv * 1201266423Sjfv **********************************************************************/ 1202266423Sjfvvoid 1203270346Sjfvixl_intr(void *arg) 1204266423Sjfv{ 1205270346Sjfv struct ixl_pf *pf = arg; 1206266423Sjfv struct i40e_hw *hw = &pf->hw; 1207270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1208270346Sjfv struct ixl_queue *que = vsi->queues; 1209266423Sjfv struct ifnet *ifp = vsi->ifp; 1210266423Sjfv struct tx_ring *txr = &que->txr; 1211266423Sjfv u32 reg, icr0, mask; 1212266423Sjfv bool more_tx, more_rx; 1213266423Sjfv 1214266423Sjfv ++que->irqs; 1215266423Sjfv 1216266423Sjfv /* Protect against spurious interrupts */ 1217266423Sjfv if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1218266423Sjfv return; 1219266423Sjfv 1220266423Sjfv icr0 = rd32(hw, I40E_PFINT_ICR0); 1221266423Sjfv 1222266423Sjfv reg = rd32(hw, I40E_PFINT_DYN_CTL0); 1223266423Sjfv reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 1224266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 1225266423Sjfv 1226266423Sjfv mask = rd32(hw, I40E_PFINT_ICR0_ENA); 1227266423Sjfv 1228266423Sjfv if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) { 1229266423Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 1230266423Sjfv return; 1231266423Sjfv } 1232266423Sjfv 1233270346Sjfv more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 1234266423Sjfv 1235270346Sjfv IXL_TX_LOCK(txr); 1236270346Sjfv more_tx = ixl_txeof(que); 1237266423Sjfv if (!drbr_empty(vsi->ifp, txr->br)) 1238266423Sjfv more_tx = 1; 1239270346Sjfv IXL_TX_UNLOCK(txr); 1240266423Sjfv 1241266423Sjfv /* re-enable other interrupt causes */ 1242266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, mask); 1243266423Sjfv 1244266423Sjfv /* And now the queues */ 1245266423Sjfv reg = rd32(hw, I40E_QINT_RQCTL(0)); 1246266423Sjfv reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; 1247266423Sjfv wr32(hw, I40E_QINT_RQCTL(0), reg); 1248266423Sjfv 1249266423Sjfv reg = rd32(hw, I40E_QINT_TQCTL(0)); 1250266423Sjfv reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; 1251266423Sjfv reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK; 1252266423Sjfv wr32(hw, I40E_QINT_TQCTL(0), reg); 1253266423Sjfv 1254270346Sjfv ixl_enable_legacy(hw); 1255266423Sjfv 1256266423Sjfv return; 1257266423Sjfv} 1258266423Sjfv 1259266423Sjfv 1260266423Sjfv/********************************************************************* 1261266423Sjfv * 1262266423Sjfv * MSIX VSI Interrupt Service routine 1263266423Sjfv * 1264266423Sjfv **********************************************************************/ 1265266423Sjfvvoid 1266270346Sjfvixl_msix_que(void *arg) 1267266423Sjfv{ 1268270346Sjfv struct ixl_queue *que = arg; 1269270346Sjfv struct ixl_vsi *vsi = que->vsi; 1270266423Sjfv struct i40e_hw *hw = vsi->hw; 1271266423Sjfv struct tx_ring *txr = &que->txr; 1272266423Sjfv bool more_tx, more_rx; 1273266423Sjfv 1274269198Sjfv /* Protect against spurious interrupts */ 1275269198Sjfv if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) 1276269198Sjfv return; 1277269198Sjfv 1278266423Sjfv ++que->irqs; 1279266423Sjfv 1280270346Sjfv more_rx = ixl_rxeof(que, IXL_RX_LIMIT); 1281266423Sjfv 1282270346Sjfv IXL_TX_LOCK(txr); 1283270346Sjfv more_tx = ixl_txeof(que); 1284266423Sjfv /* 1285266423Sjfv ** Make certain that if the stack 1286266423Sjfv ** has anything queued the task gets 1287266423Sjfv ** scheduled to handle it. 1288266423Sjfv */ 1289266423Sjfv if (!drbr_empty(vsi->ifp, txr->br)) 1290266423Sjfv more_tx = 1; 1291270346Sjfv IXL_TX_UNLOCK(txr); 1292266423Sjfv 1293270346Sjfv ixl_set_queue_rx_itr(que); 1294270346Sjfv ixl_set_queue_tx_itr(que); 1295266423Sjfv 1296266423Sjfv if (more_tx || more_rx) 1297266423Sjfv taskqueue_enqueue(que->tq, &que->task); 1298266423Sjfv else 1299270346Sjfv ixl_enable_queue(hw, que->me); 1300266423Sjfv 1301266423Sjfv return; 1302266423Sjfv} 1303266423Sjfv 1304266423Sjfv 1305266423Sjfv/********************************************************************* 1306266423Sjfv * 1307266423Sjfv * MSIX Admin Queue Interrupt Service routine 1308266423Sjfv * 1309266423Sjfv **********************************************************************/ 1310266423Sjfvstatic void 1311270346Sjfvixl_msix_adminq(void *arg) 1312266423Sjfv{ 1313270346Sjfv struct ixl_pf *pf = arg; 1314266423Sjfv struct i40e_hw *hw = &pf->hw; 1315266423Sjfv u32 reg, mask; 1316266423Sjfv 1317266423Sjfv ++pf->admin_irq; 1318266423Sjfv 1319266423Sjfv reg = rd32(hw, I40E_PFINT_ICR0); 1320266423Sjfv mask = rd32(hw, I40E_PFINT_ICR0_ENA); 1321266423Sjfv 1322266423Sjfv /* Check on the cause */ 1323266423Sjfv if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) 1324266423Sjfv mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 1325266423Sjfv 1326269198Sjfv if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) { 1327270346Sjfv ixl_handle_mdd_event(pf); 1328266423Sjfv mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 1329269198Sjfv } 1330266423Sjfv 1331266423Sjfv if (reg & I40E_PFINT_ICR0_VFLR_MASK) 1332266423Sjfv mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; 1333266423Sjfv 1334266423Sjfv reg = rd32(hw, I40E_PFINT_DYN_CTL0); 1335266423Sjfv reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 1336266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 1337266423Sjfv 1338266423Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 1339266423Sjfv return; 1340266423Sjfv} 1341266423Sjfv 1342266423Sjfv/********************************************************************* 1343266423Sjfv * 1344266423Sjfv * Media Ioctl callback 1345266423Sjfv * 1346266423Sjfv * This routine is called whenever the user queries the status of 1347266423Sjfv * the interface using ifconfig. 1348266423Sjfv * 1349266423Sjfv **********************************************************************/ 1350266423Sjfvstatic void 1351270346Sjfvixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 1352266423Sjfv{ 1353270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 1354270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 1355266423Sjfv struct i40e_hw *hw = &pf->hw; 1356266423Sjfv 1357270346Sjfv INIT_DEBUGOUT("ixl_media_status: begin"); 1358270346Sjfv IXL_PF_LOCK(pf); 1359266423Sjfv 1360270346Sjfv ixl_update_link_status(pf); 1361266423Sjfv 1362266423Sjfv ifmr->ifm_status = IFM_AVALID; 1363266423Sjfv ifmr->ifm_active = IFM_ETHER; 1364266423Sjfv 1365266423Sjfv if (!vsi->link_up) { 1366270346Sjfv IXL_PF_UNLOCK(pf); 1367266423Sjfv return; 1368266423Sjfv } 1369266423Sjfv 1370266423Sjfv ifmr->ifm_status |= IFM_ACTIVE; 1371266423Sjfv /* Hardware is always full-duplex */ 1372266423Sjfv ifmr->ifm_active |= IFM_FDX; 1373266423Sjfv 1374266423Sjfv switch (hw->phy.link_info.phy_type) { 1375266423Sjfv /* 100 M */ 1376266423Sjfv case I40E_PHY_TYPE_100BASE_TX: 1377266423Sjfv ifmr->ifm_active |= IFM_100_TX; 1378266423Sjfv break; 1379266423Sjfv /* 1 G */ 1380266423Sjfv case I40E_PHY_TYPE_1000BASE_T: 1381266423Sjfv ifmr->ifm_active |= IFM_1000_T; 1382266423Sjfv break; 1383269198Sjfv case I40E_PHY_TYPE_1000BASE_SX: 1384269198Sjfv ifmr->ifm_active |= IFM_1000_SX; 1385269198Sjfv break; 1386269198Sjfv case I40E_PHY_TYPE_1000BASE_LX: 1387269198Sjfv ifmr->ifm_active |= IFM_1000_LX; 1388269198Sjfv break; 1389266423Sjfv /* 10 G */ 1390266423Sjfv case I40E_PHY_TYPE_10GBASE_CR1_CU: 1391266423Sjfv case I40E_PHY_TYPE_10GBASE_SFPP_CU: 1392266423Sjfv ifmr->ifm_active |= IFM_10G_TWINAX; 1393266423Sjfv break; 1394266423Sjfv case I40E_PHY_TYPE_10GBASE_SR: 1395266423Sjfv ifmr->ifm_active |= IFM_10G_SR; 1396266423Sjfv break; 1397266423Sjfv case I40E_PHY_TYPE_10GBASE_LR: 1398266423Sjfv ifmr->ifm_active |= IFM_10G_LR; 1399266423Sjfv break; 1400270346Sjfv case I40E_PHY_TYPE_10GBASE_T: 1401270346Sjfv ifmr->ifm_active |= IFM_10G_T; 1402270346Sjfv break; 1403266423Sjfv /* 40 G */ 1404266423Sjfv case I40E_PHY_TYPE_40GBASE_CR4: 1405266423Sjfv case I40E_PHY_TYPE_40GBASE_CR4_CU: 1406266423Sjfv ifmr->ifm_active |= IFM_40G_CR4; 1407266423Sjfv break; 1408266423Sjfv case I40E_PHY_TYPE_40GBASE_SR4: 1409266423Sjfv ifmr->ifm_active |= IFM_40G_SR4; 1410266423Sjfv break; 1411266423Sjfv case I40E_PHY_TYPE_40GBASE_LR4: 1412266423Sjfv ifmr->ifm_active |= IFM_40G_LR4; 1413266423Sjfv break; 1414266423Sjfv default: 1415266423Sjfv ifmr->ifm_active |= IFM_UNKNOWN; 1416266423Sjfv break; 1417266423Sjfv } 1418266423Sjfv /* Report flow control status as well */ 1419266423Sjfv if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) 1420266423Sjfv ifmr->ifm_active |= IFM_ETH_TXPAUSE; 1421266423Sjfv if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) 1422266423Sjfv ifmr->ifm_active |= IFM_ETH_RXPAUSE; 1423266423Sjfv 1424270346Sjfv IXL_PF_UNLOCK(pf); 1425266423Sjfv 1426266423Sjfv return; 1427266423Sjfv} 1428266423Sjfv 1429266423Sjfv/********************************************************************* 1430266423Sjfv * 1431266423Sjfv * Media Ioctl callback 1432266423Sjfv * 1433266423Sjfv * This routine is called when the user changes speed/duplex using 1434266423Sjfv * media/mediopt option with ifconfig. 1435266423Sjfv * 1436266423Sjfv **********************************************************************/ 1437266423Sjfvstatic int 1438270346Sjfvixl_media_change(struct ifnet * ifp) 1439266423Sjfv{ 1440270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 1441266423Sjfv struct ifmedia *ifm = &vsi->media; 1442266423Sjfv 1443270346Sjfv INIT_DEBUGOUT("ixl_media_change: begin"); 1444266423Sjfv 1445266423Sjfv if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1446266423Sjfv return (EINVAL); 1447266423Sjfv 1448269198Sjfv if_printf(ifp, "Media change is currently not supported.\n"); 1449269198Sjfv 1450269198Sjfv return (ENODEV); 1451266423Sjfv} 1452266423Sjfv 1453266423Sjfv 1454270346Sjfv#ifdef IXL_FDIR 1455266423Sjfv/* 1456266423Sjfv** ATR: Application Targetted Receive - creates a filter 1457266423Sjfv** based on TX flow info that will keep the receive 1458266423Sjfv** portion of the flow on the same queue. Based on the 1459266423Sjfv** implementation this is only available for TCP connections 1460266423Sjfv*/ 1461266423Sjfvvoid 1462270346Sjfvixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype) 1463266423Sjfv{ 1464270346Sjfv struct ixl_vsi *vsi = que->vsi; 1465266423Sjfv struct tx_ring *txr = &que->txr; 1466266423Sjfv struct i40e_filter_program_desc *FDIR; 1467266423Sjfv u32 ptype, dtype; 1468266423Sjfv int idx; 1469266423Sjfv 1470266423Sjfv /* check if ATR is enabled and sample rate */ 1471270346Sjfv if ((!ixl_enable_fdir) || (!txr->atr_rate)) 1472266423Sjfv return; 1473266423Sjfv /* 1474266423Sjfv ** We sample all TCP SYN/FIN packets, 1475266423Sjfv ** or at the selected sample rate 1476266423Sjfv */ 1477266423Sjfv txr->atr_count++; 1478266423Sjfv if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) && 1479266423Sjfv (txr->atr_count < txr->atr_rate)) 1480266423Sjfv return; 1481266423Sjfv txr->atr_count = 0; 1482266423Sjfv 1483266423Sjfv /* Get a descriptor to use */ 1484266423Sjfv idx = txr->next_avail; 1485266423Sjfv FDIR = (struct i40e_filter_program_desc *) &txr->base[idx]; 1486266423Sjfv if (++idx == que->num_desc) 1487266423Sjfv idx = 0; 1488266423Sjfv txr->avail--; 1489266423Sjfv txr->next_avail = idx; 1490266423Sjfv 1491266423Sjfv ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & 1492266423Sjfv I40E_TXD_FLTR_QW0_QINDEX_MASK; 1493266423Sjfv 1494266423Sjfv ptype |= (etype == ETHERTYPE_IP) ? 1495266423Sjfv (I40E_FILTER_PCTYPE_NONF_IPV4_TCP << 1496266423Sjfv I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) : 1497266423Sjfv (I40E_FILTER_PCTYPE_NONF_IPV6_TCP << 1498266423Sjfv I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); 1499266423Sjfv 1500266423Sjfv ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT; 1501266423Sjfv 1502266423Sjfv dtype = I40E_TX_DESC_DTYPE_FILTER_PROG; 1503266423Sjfv 1504266423Sjfv /* 1505266423Sjfv ** We use the TCP TH_FIN as a trigger to remove 1506266423Sjfv ** the filter, otherwise its an update. 1507266423Sjfv */ 1508266423Sjfv dtype |= (th->th_flags & TH_FIN) ? 1509266423Sjfv (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << 1510266423Sjfv I40E_TXD_FLTR_QW1_PCMD_SHIFT) : 1511266423Sjfv (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << 1512266423Sjfv I40E_TXD_FLTR_QW1_PCMD_SHIFT); 1513266423Sjfv 1514266423Sjfv dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX << 1515266423Sjfv I40E_TXD_FLTR_QW1_DEST_SHIFT; 1516266423Sjfv 1517266423Sjfv dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID << 1518266423Sjfv I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT; 1519266423Sjfv 1520266423Sjfv FDIR->qindex_flex_ptype_vsi = htole32(ptype); 1521266423Sjfv FDIR->dtype_cmd_cntindex = htole32(dtype); 1522266423Sjfv return; 1523266423Sjfv} 1524266423Sjfv#endif 1525266423Sjfv 1526266423Sjfv 1527266423Sjfvstatic void 1528270346Sjfvixl_set_promisc(struct ixl_vsi *vsi) 1529266423Sjfv{ 1530266423Sjfv struct ifnet *ifp = vsi->ifp; 1531266423Sjfv struct i40e_hw *hw = vsi->hw; 1532266423Sjfv int err, mcnt = 0; 1533266423Sjfv bool uni = FALSE, multi = FALSE; 1534266423Sjfv 1535266423Sjfv if (ifp->if_flags & IFF_ALLMULTI) 1536266423Sjfv multi = TRUE; 1537266423Sjfv else { /* Need to count the multicast addresses */ 1538266423Sjfv struct ifmultiaddr *ifma; 1539266423Sjfv if_maddr_rlock(ifp); 1540266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1541266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1542266423Sjfv continue; 1543266423Sjfv if (mcnt == MAX_MULTICAST_ADDR) 1544266423Sjfv break; 1545266423Sjfv mcnt++; 1546266423Sjfv } 1547266423Sjfv if_maddr_runlock(ifp); 1548266423Sjfv } 1549266423Sjfv 1550266423Sjfv if (mcnt >= MAX_MULTICAST_ADDR) 1551266423Sjfv multi = TRUE; 1552266423Sjfv if (ifp->if_flags & IFF_PROMISC) 1553266423Sjfv uni = TRUE; 1554266423Sjfv 1555266423Sjfv err = i40e_aq_set_vsi_unicast_promiscuous(hw, 1556266423Sjfv vsi->seid, uni, NULL); 1557266423Sjfv err = i40e_aq_set_vsi_multicast_promiscuous(hw, 1558266423Sjfv vsi->seid, multi, NULL); 1559266423Sjfv return; 1560266423Sjfv} 1561266423Sjfv 1562266423Sjfv/********************************************************************* 1563266423Sjfv * Filter Routines 1564266423Sjfv * 1565266423Sjfv * Routines for multicast and vlan filter management. 1566266423Sjfv * 1567266423Sjfv *********************************************************************/ 1568266423Sjfvstatic void 1569270346Sjfvixl_add_multi(struct ixl_vsi *vsi) 1570266423Sjfv{ 1571266423Sjfv struct ifmultiaddr *ifma; 1572266423Sjfv struct ifnet *ifp = vsi->ifp; 1573266423Sjfv struct i40e_hw *hw = vsi->hw; 1574266423Sjfv int mcnt = 0, flags; 1575266423Sjfv 1576270346Sjfv IOCTL_DEBUGOUT("ixl_add_multi: begin"); 1577266423Sjfv 1578266423Sjfv if_maddr_rlock(ifp); 1579266423Sjfv /* 1580266423Sjfv ** First just get a count, to decide if we 1581266423Sjfv ** we simply use multicast promiscuous. 1582266423Sjfv */ 1583266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1584266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1585266423Sjfv continue; 1586266423Sjfv mcnt++; 1587266423Sjfv } 1588266423Sjfv if_maddr_runlock(ifp); 1589266423Sjfv 1590266423Sjfv if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { 1591266423Sjfv /* delete existing MC filters */ 1592270346Sjfv ixl_del_hw_filters(vsi, mcnt); 1593266423Sjfv i40e_aq_set_vsi_multicast_promiscuous(hw, 1594266423Sjfv vsi->seid, TRUE, NULL); 1595266423Sjfv return; 1596266423Sjfv } 1597266423Sjfv 1598266423Sjfv mcnt = 0; 1599266423Sjfv if_maddr_rlock(ifp); 1600266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1601266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1602266423Sjfv continue; 1603270346Sjfv ixl_add_mc_filter(vsi, 1604266423Sjfv (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); 1605266423Sjfv mcnt++; 1606266423Sjfv } 1607266423Sjfv if_maddr_runlock(ifp); 1608266423Sjfv if (mcnt > 0) { 1609270346Sjfv flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); 1610270346Sjfv ixl_add_hw_filters(vsi, flags, mcnt); 1611266423Sjfv } 1612266423Sjfv 1613270346Sjfv IOCTL_DEBUGOUT("ixl_add_multi: end"); 1614266423Sjfv return; 1615266423Sjfv} 1616266423Sjfv 1617266423Sjfvstatic void 1618270346Sjfvixl_del_multi(struct ixl_vsi *vsi) 1619266423Sjfv{ 1620266423Sjfv struct ifnet *ifp = vsi->ifp; 1621266423Sjfv struct ifmultiaddr *ifma; 1622270346Sjfv struct ixl_mac_filter *f; 1623266423Sjfv int mcnt = 0; 1624266423Sjfv bool match = FALSE; 1625266423Sjfv 1626270346Sjfv IOCTL_DEBUGOUT("ixl_del_multi: begin"); 1627266423Sjfv 1628266423Sjfv /* Search for removed multicast addresses */ 1629266423Sjfv if_maddr_rlock(ifp); 1630266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 1631270346Sjfv if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) { 1632266423Sjfv match = FALSE; 1633266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1634266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1635266423Sjfv continue; 1636266423Sjfv u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 1637266423Sjfv if (cmp_etheraddr(f->macaddr, mc_addr)) { 1638266423Sjfv match = TRUE; 1639266423Sjfv break; 1640266423Sjfv } 1641266423Sjfv } 1642266423Sjfv if (match == FALSE) { 1643270346Sjfv f->flags |= IXL_FILTER_DEL; 1644266423Sjfv mcnt++; 1645266423Sjfv } 1646266423Sjfv } 1647266423Sjfv } 1648266423Sjfv if_maddr_runlock(ifp); 1649266423Sjfv 1650266423Sjfv if (mcnt > 0) 1651270346Sjfv ixl_del_hw_filters(vsi, mcnt); 1652266423Sjfv} 1653266423Sjfv 1654266423Sjfv 1655266423Sjfv/********************************************************************* 1656266423Sjfv * Timer routine 1657266423Sjfv * 1658266423Sjfv * This routine checks for link status,updates statistics, 1659266423Sjfv * and runs the watchdog check. 1660266423Sjfv * 1661266423Sjfv **********************************************************************/ 1662266423Sjfv 1663266423Sjfvstatic void 1664270346Sjfvixl_local_timer(void *arg) 1665266423Sjfv{ 1666270346Sjfv struct ixl_pf *pf = arg; 1667266423Sjfv struct i40e_hw *hw = &pf->hw; 1668270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1669270346Sjfv struct ixl_queue *que = vsi->queues; 1670266423Sjfv device_t dev = pf->dev; 1671266423Sjfv int hung = 0; 1672266423Sjfv u32 mask; 1673266423Sjfv 1674266423Sjfv mtx_assert(&pf->pf_mtx, MA_OWNED); 1675266423Sjfv 1676266423Sjfv /* Fire off the adminq task */ 1677266423Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 1678266423Sjfv 1679266423Sjfv /* Update stats */ 1680270346Sjfv ixl_update_stats_counters(pf); 1681266423Sjfv 1682266423Sjfv /* 1683269198Sjfv ** Check status of the queues 1684266423Sjfv */ 1685266423Sjfv mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | 1686266423Sjfv I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); 1687266423Sjfv 1688266423Sjfv for (int i = 0; i < vsi->num_queues; i++,que++) { 1689266423Sjfv /* Any queues with outstanding work get a sw irq */ 1690266423Sjfv if (que->busy) 1691266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask); 1692266423Sjfv /* 1693266423Sjfv ** Each time txeof runs without cleaning, but there 1694266423Sjfv ** are uncleaned descriptors it increments busy. If 1695266423Sjfv ** we get to 5 we declare it hung. 1696266423Sjfv */ 1697270346Sjfv if (que->busy == IXL_QUEUE_HUNG) { 1698269198Sjfv ++hung; 1699269198Sjfv /* Mark the queue as inactive */ 1700269198Sjfv vsi->active_queues &= ~((u64)1 << que->me); 1701269198Sjfv continue; 1702269198Sjfv } else { 1703269198Sjfv /* Check if we've come back from hung */ 1704269198Sjfv if ((vsi->active_queues & ((u64)1 << que->me)) == 0) 1705269198Sjfv vsi->active_queues |= ((u64)1 << que->me); 1706269198Sjfv } 1707270346Sjfv if (que->busy >= IXL_MAX_TX_BUSY) { 1708266423Sjfv device_printf(dev,"Warning queue %d " 1709269198Sjfv "appears to be hung!\n", i); 1710270346Sjfv que->busy = IXL_QUEUE_HUNG; 1711266423Sjfv ++hung; 1712266423Sjfv } 1713266423Sjfv } 1714266423Sjfv /* Only reinit if all queues show hung */ 1715266423Sjfv if (hung == vsi->num_queues) 1716266423Sjfv goto hung; 1717266423Sjfv 1718270346Sjfv callout_reset(&pf->timer, hz, ixl_local_timer, pf); 1719266423Sjfv return; 1720266423Sjfv 1721266423Sjfvhung: 1722266423Sjfv device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n"); 1723270346Sjfv ixl_init_locked(pf); 1724266423Sjfv} 1725266423Sjfv 1726266423Sjfv/* 1727266423Sjfv** Note: this routine updates the OS on the link state 1728266423Sjfv** the real check of the hardware only happens with 1729266423Sjfv** a link interrupt. 1730266423Sjfv*/ 1731266423Sjfvstatic void 1732270346Sjfvixl_update_link_status(struct ixl_pf *pf) 1733266423Sjfv{ 1734270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1735266423Sjfv struct i40e_hw *hw = &pf->hw; 1736266423Sjfv struct ifnet *ifp = vsi->ifp; 1737266423Sjfv device_t dev = pf->dev; 1738266423Sjfv enum i40e_fc_mode fc; 1739266423Sjfv 1740266423Sjfv 1741266423Sjfv if (vsi->link_up){ 1742266423Sjfv if (vsi->link_active == FALSE) { 1743266423Sjfv i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 1744266423Sjfv if (bootverbose) { 1745266423Sjfv fc = hw->fc.current_mode; 1746266423Sjfv device_printf(dev,"Link is up %d Gbps %s," 1747266423Sjfv " Flow Control: %s\n", 1748266423Sjfv ((vsi->link_speed == I40E_LINK_SPEED_40GB)? 40:10), 1749270346Sjfv "Full Duplex", ixl_fc_string[fc]); 1750266423Sjfv } 1751266423Sjfv vsi->link_active = TRUE; 1752266423Sjfv if_link_state_change(ifp, LINK_STATE_UP); 1753266423Sjfv } 1754266423Sjfv } else { /* Link down */ 1755266423Sjfv if (vsi->link_active == TRUE) { 1756266423Sjfv if (bootverbose) 1757266423Sjfv device_printf(dev,"Link is Down\n"); 1758266423Sjfv if_link_state_change(ifp, LINK_STATE_DOWN); 1759266423Sjfv vsi->link_active = FALSE; 1760266423Sjfv } 1761266423Sjfv } 1762266423Sjfv 1763266423Sjfv return; 1764266423Sjfv} 1765266423Sjfv 1766266423Sjfv/********************************************************************* 1767266423Sjfv * 1768266423Sjfv * This routine disables all traffic on the adapter by issuing a 1769266423Sjfv * global reset on the MAC and deallocates TX/RX buffers. 1770266423Sjfv * 1771266423Sjfv **********************************************************************/ 1772266423Sjfv 1773266423Sjfvstatic void 1774270346Sjfvixl_stop(struct ixl_pf *pf) 1775266423Sjfv{ 1776270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1777266423Sjfv struct ifnet *ifp = vsi->ifp; 1778266423Sjfv 1779266423Sjfv mtx_assert(&pf->pf_mtx, MA_OWNED); 1780266423Sjfv 1781270346Sjfv INIT_DEBUGOUT("ixl_stop: begin\n"); 1782270346Sjfv ixl_disable_intr(vsi); 1783270346Sjfv ixl_disable_rings(vsi); 1784266423Sjfv 1785266423Sjfv /* Tell the stack that the interface is no longer active */ 1786266423Sjfv ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1787266423Sjfv 1788266423Sjfv /* Stop the local timer */ 1789266423Sjfv callout_stop(&pf->timer); 1790266423Sjfv 1791266423Sjfv return; 1792266423Sjfv} 1793266423Sjfv 1794266423Sjfv 1795266423Sjfv/********************************************************************* 1796266423Sjfv * 1797266423Sjfv * Setup MSIX Interrupt resources and handlers for the VSI 1798266423Sjfv * 1799266423Sjfv **********************************************************************/ 1800266423Sjfvstatic int 1801270346Sjfvixl_assign_vsi_legacy(struct ixl_pf *pf) 1802266423Sjfv{ 1803266423Sjfv device_t dev = pf->dev; 1804270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1805270346Sjfv struct ixl_queue *que = vsi->queues; 1806266423Sjfv int error, rid = 0; 1807266423Sjfv 1808266423Sjfv if (pf->msix == 1) 1809266423Sjfv rid = 1; 1810266423Sjfv pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 1811266423Sjfv &rid, RF_SHAREABLE | RF_ACTIVE); 1812266423Sjfv if (pf->res == NULL) { 1813266423Sjfv device_printf(dev,"Unable to allocate" 1814266423Sjfv " bus resource: vsi legacy/msi interrupt\n"); 1815266423Sjfv return (ENXIO); 1816266423Sjfv } 1817266423Sjfv 1818266423Sjfv /* Set the handler function */ 1819266423Sjfv error = bus_setup_intr(dev, pf->res, 1820266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 1821270346Sjfv ixl_intr, pf, &pf->tag); 1822266423Sjfv if (error) { 1823266423Sjfv pf->res = NULL; 1824266423Sjfv device_printf(dev, "Failed to register legacy/msi handler"); 1825266423Sjfv return (error); 1826266423Sjfv } 1827266423Sjfv bus_describe_intr(dev, pf->res, pf->tag, "irq0"); 1828270346Sjfv TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 1829270346Sjfv TASK_INIT(&que->task, 0, ixl_handle_que, que); 1830270346Sjfv que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 1831266423Sjfv taskqueue_thread_enqueue, &que->tq); 1832266423Sjfv taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 1833266423Sjfv device_get_nameunit(dev)); 1834270346Sjfv TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 1835270346Sjfv pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 1836266423Sjfv taskqueue_thread_enqueue, &pf->tq); 1837266423Sjfv taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 1838266423Sjfv device_get_nameunit(dev)); 1839266423Sjfv 1840266423Sjfv return (0); 1841266423Sjfv} 1842266423Sjfv 1843266423Sjfv 1844266423Sjfv/********************************************************************* 1845266423Sjfv * 1846266423Sjfv * Setup MSIX Interrupt resources and handlers for the VSI 1847266423Sjfv * 1848266423Sjfv **********************************************************************/ 1849266423Sjfvstatic int 1850270346Sjfvixl_assign_vsi_msix(struct ixl_pf *pf) 1851266423Sjfv{ 1852266423Sjfv device_t dev = pf->dev; 1853270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 1854270346Sjfv struct ixl_queue *que = vsi->queues; 1855266423Sjfv struct tx_ring *txr; 1856266423Sjfv int error, rid, vector = 0; 1857266423Sjfv 1858266423Sjfv /* Admin Que is vector 0*/ 1859266423Sjfv rid = vector + 1; 1860266423Sjfv pf->res = bus_alloc_resource_any(dev, 1861266423Sjfv SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 1862266423Sjfv if (!pf->res) { 1863266423Sjfv device_printf(dev,"Unable to allocate" 1864266423Sjfv " bus resource: Adminq interrupt [%d]\n", rid); 1865266423Sjfv return (ENXIO); 1866266423Sjfv } 1867266423Sjfv /* Set the adminq vector and handler */ 1868266423Sjfv error = bus_setup_intr(dev, pf->res, 1869266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 1870270346Sjfv ixl_msix_adminq, pf, &pf->tag); 1871266423Sjfv if (error) { 1872266423Sjfv pf->res = NULL; 1873266423Sjfv device_printf(dev, "Failed to register Admin que handler"); 1874266423Sjfv return (error); 1875266423Sjfv } 1876266423Sjfv bus_describe_intr(dev, pf->res, pf->tag, "aq"); 1877266423Sjfv pf->admvec = vector; 1878266423Sjfv /* Tasklet for Admin Queue */ 1879270346Sjfv TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); 1880270346Sjfv pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, 1881266423Sjfv taskqueue_thread_enqueue, &pf->tq); 1882266423Sjfv taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 1883266423Sjfv device_get_nameunit(pf->dev)); 1884266423Sjfv ++vector; 1885266423Sjfv 1886266423Sjfv /* Now set up the stations */ 1887266423Sjfv for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { 1888266423Sjfv rid = vector + 1; 1889266423Sjfv txr = &que->txr; 1890266423Sjfv que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1891266423Sjfv RF_SHAREABLE | RF_ACTIVE); 1892266423Sjfv if (que->res == NULL) { 1893266423Sjfv device_printf(dev,"Unable to allocate" 1894266423Sjfv " bus resource: que interrupt [%d]\n", vector); 1895266423Sjfv return (ENXIO); 1896266423Sjfv } 1897266423Sjfv /* Set the handler function */ 1898266423Sjfv error = bus_setup_intr(dev, que->res, 1899266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 1900270346Sjfv ixl_msix_que, que, &que->tag); 1901266423Sjfv if (error) { 1902266423Sjfv que->res = NULL; 1903266423Sjfv device_printf(dev, "Failed to register que handler"); 1904266423Sjfv return (error); 1905266423Sjfv } 1906266423Sjfv bus_describe_intr(dev, que->res, que->tag, "q%d", i); 1907266423Sjfv /* Bind the vector to a CPU */ 1908266423Sjfv bus_bind_intr(dev, que->res, i); 1909266423Sjfv que->msix = vector; 1910270346Sjfv TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); 1911270346Sjfv TASK_INIT(&que->task, 0, ixl_handle_que, que); 1912270346Sjfv que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, 1913266423Sjfv taskqueue_thread_enqueue, &que->tq); 1914266423Sjfv taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 1915266423Sjfv device_get_nameunit(pf->dev)); 1916266423Sjfv } 1917266423Sjfv 1918266423Sjfv return (0); 1919266423Sjfv} 1920266423Sjfv 1921266423Sjfv 1922266423Sjfv/* 1923266423Sjfv * Allocate MSI/X vectors 1924266423Sjfv */ 1925266423Sjfvstatic int 1926270346Sjfvixl_init_msix(struct ixl_pf *pf) 1927266423Sjfv{ 1928266423Sjfv device_t dev = pf->dev; 1929266423Sjfv int rid, want, vectors, queues, available; 1930266423Sjfv 1931266423Sjfv /* Override by tuneable */ 1932270346Sjfv if (ixl_enable_msix == 0) 1933266423Sjfv goto msi; 1934266423Sjfv 1935269198Sjfv /* 1936269198Sjfv ** When used in a virtualized environment 1937269198Sjfv ** PCI BUSMASTER capability may not be set 1938269198Sjfv ** so explicity set it here and rewrite 1939269198Sjfv ** the ENABLE in the MSIX control register 1940269198Sjfv ** at this point to cause the host to 1941269198Sjfv ** successfully initialize us. 1942269198Sjfv */ 1943269198Sjfv { 1944269198Sjfv u16 pci_cmd_word; 1945269198Sjfv int msix_ctrl; 1946269198Sjfv pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); 1947269198Sjfv pci_cmd_word |= PCIM_CMD_BUSMASTEREN; 1948269198Sjfv pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); 1949269198Sjfv pci_find_cap(dev, PCIY_MSIX, &rid); 1950269198Sjfv rid += PCIR_MSIX_CTRL; 1951269198Sjfv msix_ctrl = pci_read_config(dev, rid, 2); 1952269198Sjfv msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; 1953269198Sjfv pci_write_config(dev, rid, msix_ctrl, 2); 1954269198Sjfv } 1955269198Sjfv 1956266423Sjfv /* First try MSI/X */ 1957270346Sjfv rid = PCIR_BAR(IXL_BAR); 1958266423Sjfv pf->msix_mem = bus_alloc_resource_any(dev, 1959266423Sjfv SYS_RES_MEMORY, &rid, RF_ACTIVE); 1960266423Sjfv if (!pf->msix_mem) { 1961266423Sjfv /* May not be enabled */ 1962266423Sjfv device_printf(pf->dev, 1963266423Sjfv "Unable to map MSIX table \n"); 1964266423Sjfv goto msi; 1965266423Sjfv } 1966266423Sjfv 1967266423Sjfv available = pci_msix_count(dev); 1968266423Sjfv if (available == 0) { /* system has msix disabled */ 1969266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 1970266423Sjfv rid, pf->msix_mem); 1971266423Sjfv pf->msix_mem = NULL; 1972266423Sjfv goto msi; 1973266423Sjfv } 1974266423Sjfv 1975266423Sjfv /* Figure out a reasonable auto config value */ 1976266423Sjfv queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus; 1977266423Sjfv 1978266423Sjfv /* Override with hardcoded value if sane */ 1979270346Sjfv if ((ixl_max_queues != 0) && (ixl_max_queues <= queues)) 1980270346Sjfv queues = ixl_max_queues; 1981266423Sjfv 1982266423Sjfv /* 1983266423Sjfv ** Want one vector (RX/TX pair) per queue 1984266423Sjfv ** plus an additional for the admin queue. 1985266423Sjfv */ 1986266423Sjfv want = queues + 1; 1987266423Sjfv if (want <= available) /* Have enough */ 1988266423Sjfv vectors = want; 1989266423Sjfv else { 1990266423Sjfv device_printf(pf->dev, 1991266423Sjfv "MSIX Configuration Problem, " 1992266423Sjfv "%d vectors available but %d wanted!\n", 1993266423Sjfv available, want); 1994266423Sjfv return (0); /* Will go to Legacy setup */ 1995266423Sjfv } 1996266423Sjfv 1997266423Sjfv if (pci_alloc_msix(dev, &vectors) == 0) { 1998266423Sjfv device_printf(pf->dev, 1999266423Sjfv "Using MSIX interrupts with %d vectors\n", vectors); 2000266423Sjfv pf->msix = vectors; 2001266423Sjfv pf->vsi.num_queues = queues; 2002266423Sjfv return (vectors); 2003266423Sjfv } 2004266423Sjfvmsi: 2005266423Sjfv vectors = pci_msi_count(dev); 2006266423Sjfv pf->vsi.num_queues = 1; 2007266423Sjfv pf->msix = 1; 2008270346Sjfv ixl_max_queues = 1; 2009270346Sjfv ixl_enable_msix = 0; 2010266423Sjfv if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) 2011266423Sjfv device_printf(pf->dev,"Using an MSI interrupt\n"); 2012266423Sjfv else { 2013266423Sjfv pf->msix = 0; 2014266423Sjfv device_printf(pf->dev,"Using a Legacy interrupt\n"); 2015266423Sjfv } 2016266423Sjfv return (vectors); 2017266423Sjfv} 2018266423Sjfv 2019266423Sjfv 2020266423Sjfv/* 2021266423Sjfv * Plumb MSI/X vectors 2022266423Sjfv */ 2023266423Sjfvstatic void 2024270346Sjfvixl_configure_msix(struct ixl_pf *pf) 2025266423Sjfv{ 2026266423Sjfv struct i40e_hw *hw = &pf->hw; 2027270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2028266423Sjfv u32 reg; 2029266423Sjfv u16 vector = 1; 2030266423Sjfv 2031266423Sjfv /* First set up the adminq - vector 0 */ 2032266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, 0); /* disable all */ 2033266423Sjfv rd32(hw, I40E_PFINT_ICR0); /* read to clear */ 2034266423Sjfv 2035266423Sjfv reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | 2036266423Sjfv I40E_PFINT_ICR0_ENA_GRST_MASK | 2037266423Sjfv I40E_PFINT_ICR0_HMC_ERR_MASK | 2038266423Sjfv I40E_PFINT_ICR0_ENA_ADMINQ_MASK | 2039266423Sjfv I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK | 2040266423Sjfv I40E_PFINT_ICR0_ENA_VFLR_MASK | 2041266423Sjfv I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK; 2042266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 2043266423Sjfv 2044266423Sjfv wr32(hw, I40E_PFINT_LNKLST0, 0x7FF); 2045270346Sjfv wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x003E); 2046266423Sjfv 2047266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, 2048266423Sjfv I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK | 2049266423Sjfv I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK); 2050266423Sjfv 2051266423Sjfv wr32(hw, I40E_PFINT_STAT_CTL0, 0); 2052266423Sjfv 2053266423Sjfv /* Next configure the queues */ 2054266423Sjfv for (int i = 0; i < vsi->num_queues; i++, vector++) { 2055266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(i), i); 2056266423Sjfv wr32(hw, I40E_PFINT_LNKLSTN(i), i); 2057266423Sjfv 2058266423Sjfv reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | 2059270346Sjfv (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | 2060266423Sjfv (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 2061266423Sjfv (i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 2062266423Sjfv (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); 2063266423Sjfv wr32(hw, I40E_QINT_RQCTL(i), reg); 2064266423Sjfv 2065266423Sjfv reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK | 2066270346Sjfv (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | 2067266423Sjfv (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | 2068266423Sjfv ((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | 2069266423Sjfv (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 2070266423Sjfv if (i == (vsi->num_queues - 1)) 2071270346Sjfv reg |= (IXL_QUEUE_EOL 2072266423Sjfv << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 2073266423Sjfv wr32(hw, I40E_QINT_TQCTL(i), reg); 2074266423Sjfv } 2075266423Sjfv} 2076266423Sjfv 2077266423Sjfv/* 2078266423Sjfv * Configure for MSI single vector operation 2079266423Sjfv */ 2080266423Sjfvstatic void 2081270346Sjfvixl_configure_legacy(struct ixl_pf *pf) 2082266423Sjfv{ 2083266423Sjfv struct i40e_hw *hw = &pf->hw; 2084266423Sjfv u32 reg; 2085266423Sjfv 2086266423Sjfv 2087266423Sjfv wr32(hw, I40E_PFINT_ITR0(0), 0); 2088266423Sjfv wr32(hw, I40E_PFINT_ITR0(1), 0); 2089266423Sjfv 2090266423Sjfv 2091266423Sjfv /* Setup "other" causes */ 2092266423Sjfv reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK 2093266423Sjfv | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK 2094266423Sjfv | I40E_PFINT_ICR0_ENA_GRST_MASK 2095266423Sjfv | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK 2096266423Sjfv | I40E_PFINT_ICR0_ENA_GPIO_MASK 2097266423Sjfv | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK 2098266423Sjfv | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK 2099266423Sjfv | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK 2100266423Sjfv | I40E_PFINT_ICR0_ENA_VFLR_MASK 2101266423Sjfv | I40E_PFINT_ICR0_ENA_ADMINQ_MASK 2102266423Sjfv ; 2103266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 2104266423Sjfv 2105266423Sjfv /* SW_ITR_IDX = 0, but don't change INTENA */ 2106266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, 2107266423Sjfv I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK | 2108266423Sjfv I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK); 2109266423Sjfv /* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */ 2110266423Sjfv wr32(hw, I40E_PFINT_STAT_CTL0, 0); 2111266423Sjfv 2112266423Sjfv /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ 2113266423Sjfv wr32(hw, I40E_PFINT_LNKLST0, 0); 2114266423Sjfv 2115266423Sjfv /* Associate the queue pair to the vector and enable the q int */ 2116266423Sjfv reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK 2117270346Sjfv | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) 2118266423Sjfv | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 2119266423Sjfv wr32(hw, I40E_QINT_RQCTL(0), reg); 2120266423Sjfv 2121266423Sjfv reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK 2122270346Sjfv | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) 2123270346Sjfv | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 2124266423Sjfv wr32(hw, I40E_QINT_TQCTL(0), reg); 2125266423Sjfv 2126266423Sjfv /* Next enable the queue pair */ 2127266423Sjfv reg = rd32(hw, I40E_QTX_ENA(0)); 2128266423Sjfv reg |= I40E_QTX_ENA_QENA_REQ_MASK; 2129266423Sjfv wr32(hw, I40E_QTX_ENA(0), reg); 2130266423Sjfv 2131266423Sjfv reg = rd32(hw, I40E_QRX_ENA(0)); 2132266423Sjfv reg |= I40E_QRX_ENA_QENA_REQ_MASK; 2133266423Sjfv wr32(hw, I40E_QRX_ENA(0), reg); 2134266423Sjfv} 2135266423Sjfv 2136266423Sjfv 2137266423Sjfv/* 2138266423Sjfv * Set the Initial ITR state 2139266423Sjfv */ 2140266423Sjfvstatic void 2141270346Sjfvixl_configure_itr(struct ixl_pf *pf) 2142266423Sjfv{ 2143266423Sjfv struct i40e_hw *hw = &pf->hw; 2144270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2145270346Sjfv struct ixl_queue *que = vsi->queues; 2146266423Sjfv 2147270346Sjfv vsi->rx_itr_setting = ixl_rx_itr; 2148270346Sjfv if (ixl_dynamic_rx_itr) 2149270346Sjfv vsi->rx_itr_setting |= IXL_ITR_DYNAMIC; 2150270346Sjfv vsi->tx_itr_setting = ixl_tx_itr; 2151270346Sjfv if (ixl_dynamic_tx_itr) 2152270346Sjfv vsi->tx_itr_setting |= IXL_ITR_DYNAMIC; 2153266423Sjfv 2154266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2155266423Sjfv struct tx_ring *txr = &que->txr; 2156266423Sjfv struct rx_ring *rxr = &que->rxr; 2157266423Sjfv 2158270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i), 2159266423Sjfv vsi->rx_itr_setting); 2160266423Sjfv rxr->itr = vsi->rx_itr_setting; 2161270346Sjfv rxr->latency = IXL_AVE_LATENCY; 2162270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i), 2163266423Sjfv vsi->tx_itr_setting); 2164266423Sjfv txr->itr = vsi->tx_itr_setting; 2165270346Sjfv txr->latency = IXL_AVE_LATENCY; 2166266423Sjfv } 2167266423Sjfv} 2168266423Sjfv 2169266423Sjfv 2170266423Sjfvstatic int 2171270346Sjfvixl_allocate_pci_resources(struct ixl_pf *pf) 2172266423Sjfv{ 2173266423Sjfv int rid; 2174266423Sjfv device_t dev = pf->dev; 2175266423Sjfv 2176266423Sjfv rid = PCIR_BAR(0); 2177266423Sjfv pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2178266423Sjfv &rid, RF_ACTIVE); 2179266423Sjfv 2180266423Sjfv if (!(pf->pci_mem)) { 2181266423Sjfv device_printf(dev,"Unable to allocate bus resource: memory\n"); 2182266423Sjfv return (ENXIO); 2183266423Sjfv } 2184266423Sjfv 2185266423Sjfv pf->osdep.mem_bus_space_tag = 2186266423Sjfv rman_get_bustag(pf->pci_mem); 2187266423Sjfv pf->osdep.mem_bus_space_handle = 2188266423Sjfv rman_get_bushandle(pf->pci_mem); 2189270346Sjfv pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); 2190266423Sjfv pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; 2191266423Sjfv 2192266423Sjfv pf->hw.back = &pf->osdep; 2193266423Sjfv 2194266423Sjfv /* 2195266423Sjfv ** Now setup MSI or MSI/X, should 2196266423Sjfv ** return us the number of supported 2197266423Sjfv ** vectors. (Will be 1 for MSI) 2198266423Sjfv */ 2199270346Sjfv pf->msix = ixl_init_msix(pf); 2200266423Sjfv return (0); 2201266423Sjfv} 2202266423Sjfv 2203266423Sjfvstatic void 2204270346Sjfvixl_free_pci_resources(struct ixl_pf * pf) 2205266423Sjfv{ 2206270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2207270346Sjfv struct ixl_queue *que = vsi->queues; 2208266423Sjfv device_t dev = pf->dev; 2209266423Sjfv int rid, memrid; 2210266423Sjfv 2211270346Sjfv memrid = PCIR_BAR(IXL_BAR); 2212266423Sjfv 2213266423Sjfv /* We may get here before stations are setup */ 2214270346Sjfv if ((!ixl_enable_msix) || (que == NULL)) 2215266423Sjfv goto early; 2216266423Sjfv 2217266423Sjfv /* 2218266423Sjfv ** Release all msix VSI resources: 2219266423Sjfv */ 2220266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2221266423Sjfv rid = que->msix + 1; 2222266423Sjfv if (que->tag != NULL) { 2223266423Sjfv bus_teardown_intr(dev, que->res, que->tag); 2224266423Sjfv que->tag = NULL; 2225266423Sjfv } 2226266423Sjfv if (que->res != NULL) 2227266423Sjfv bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2228266423Sjfv } 2229266423Sjfv 2230266423Sjfvearly: 2231266423Sjfv /* Clean the AdminQ interrupt last */ 2232266423Sjfv if (pf->admvec) /* we are doing MSIX */ 2233266423Sjfv rid = pf->admvec + 1; 2234266423Sjfv else 2235266423Sjfv (pf->msix != 0) ? (rid = 1):(rid = 0); 2236266423Sjfv 2237266423Sjfv if (pf->tag != NULL) { 2238266423Sjfv bus_teardown_intr(dev, pf->res, pf->tag); 2239266423Sjfv pf->tag = NULL; 2240266423Sjfv } 2241266423Sjfv if (pf->res != NULL) 2242266423Sjfv bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); 2243266423Sjfv 2244266423Sjfv if (pf->msix) 2245266423Sjfv pci_release_msi(dev); 2246266423Sjfv 2247266423Sjfv if (pf->msix_mem != NULL) 2248266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 2249266423Sjfv memrid, pf->msix_mem); 2250266423Sjfv 2251266423Sjfv if (pf->pci_mem != NULL) 2252266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 2253266423Sjfv PCIR_BAR(0), pf->pci_mem); 2254266423Sjfv 2255266423Sjfv return; 2256266423Sjfv} 2257266423Sjfv 2258266423Sjfv 2259266423Sjfv/********************************************************************* 2260266423Sjfv * 2261266423Sjfv * Setup networking device structure and register an interface. 2262266423Sjfv * 2263266423Sjfv **********************************************************************/ 2264266423Sjfvstatic int 2265270346Sjfvixl_setup_interface(device_t dev, struct ixl_vsi *vsi) 2266266423Sjfv{ 2267266423Sjfv struct ifnet *ifp; 2268266423Sjfv struct i40e_hw *hw = vsi->hw; 2269270346Sjfv struct ixl_queue *que = vsi->queues; 2270266423Sjfv struct i40e_aq_get_phy_abilities_resp abilities_resp; 2271266423Sjfv enum i40e_status_code aq_error = 0; 2272266423Sjfv 2273270346Sjfv INIT_DEBUGOUT("ixl_setup_interface: begin"); 2274266423Sjfv 2275266423Sjfv ifp = vsi->ifp = if_alloc(IFT_ETHER); 2276266423Sjfv if (ifp == NULL) { 2277266423Sjfv device_printf(dev, "can not allocate ifnet structure\n"); 2278266423Sjfv return (-1); 2279266423Sjfv } 2280266423Sjfv if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2281266423Sjfv ifp->if_mtu = ETHERMTU; 2282266423Sjfv ifp->if_baudrate = 4000000000; // ?? 2283270346Sjfv ifp->if_init = ixl_init; 2284266423Sjfv ifp->if_softc = vsi; 2285266423Sjfv ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2286270346Sjfv ifp->if_ioctl = ixl_ioctl; 2287266423Sjfv 2288270346Sjfv ifp->if_transmit = ixl_mq_start; 2289266423Sjfv 2290270346Sjfv ifp->if_qflush = ixl_qflush; 2291266423Sjfv 2292266423Sjfv ifp->if_snd.ifq_maxlen = que->num_desc - 2; 2293266423Sjfv 2294266423Sjfv ether_ifattach(ifp, hw->mac.addr); 2295266423Sjfv 2296266423Sjfv vsi->max_frame_size = 2297266423Sjfv ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 2298266423Sjfv + ETHER_VLAN_ENCAP_LEN; 2299266423Sjfv 2300266423Sjfv /* 2301266423Sjfv * Tell the upper layer(s) we support long frames. 2302266423Sjfv */ 2303266423Sjfv ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 2304266423Sjfv 2305266423Sjfv ifp->if_capabilities |= IFCAP_HWCSUM; 2306266423Sjfv ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; 2307266423Sjfv ifp->if_capabilities |= IFCAP_TSO; 2308266423Sjfv ifp->if_capabilities |= IFCAP_JUMBO_MTU; 2309266423Sjfv ifp->if_capabilities |= IFCAP_LRO; 2310266423Sjfv 2311266423Sjfv /* VLAN capabilties */ 2312266423Sjfv ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 2313266423Sjfv | IFCAP_VLAN_HWTSO 2314266423Sjfv | IFCAP_VLAN_MTU 2315266423Sjfv | IFCAP_VLAN_HWCSUM; 2316266423Sjfv ifp->if_capenable = ifp->if_capabilities; 2317266423Sjfv 2318266423Sjfv /* 2319266423Sjfv ** Don't turn this on by default, if vlans are 2320266423Sjfv ** created on another pseudo device (eg. lagg) 2321266423Sjfv ** then vlan events are not passed thru, breaking 2322266423Sjfv ** operation, but with HW FILTER off it works. If 2323270346Sjfv ** using vlans directly on the ixl driver you can 2324266423Sjfv ** enable this and get full hardware tag filtering. 2325266423Sjfv */ 2326266423Sjfv ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 2327266423Sjfv 2328266423Sjfv /* 2329266423Sjfv * Specify the media types supported by this adapter and register 2330266423Sjfv * callbacks to update media and link information 2331266423Sjfv */ 2332270346Sjfv ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change, 2333270346Sjfv ixl_media_status); 2334266423Sjfv 2335266423Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, TRUE, &abilities_resp, NULL); 2336266423Sjfv if (aq_error) { 2337266423Sjfv printf("Error getting supported media types, AQ error %d\n", aq_error); 2338266423Sjfv return (EPERM); 2339266423Sjfv } 2340266423Sjfv 2341269198Sjfv /* Display supported media types */ 2342266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_100BASE_TX)) 2343266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2344266423Sjfv 2345266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_1000BASE_T)) 2346266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); 2347266423Sjfv 2348266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) || 2349266423Sjfv abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU)) 2350266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2351266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR)) 2352266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2353266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR)) 2354266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2355270346Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_T)) 2356270346Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2357266423Sjfv 2358266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) || 2359266423Sjfv abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4)) 2360266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2361266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4)) 2362266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2363266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4)) 2364266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); 2365266423Sjfv 2366266423Sjfv /* Use autoselect media by default */ 2367266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2368266423Sjfv ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); 2369266423Sjfv 2370266423Sjfv return (0); 2371266423Sjfv} 2372266423Sjfv 2373266423Sjfvstatic bool 2374270346Sjfvixl_config_link(struct i40e_hw *hw) 2375266423Sjfv{ 2376266423Sjfv bool check; 2377266423Sjfv 2378266423Sjfv i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 2379266423Sjfv check = i40e_get_link_status(hw); 2380270346Sjfv#ifdef IXL_DEBUG 2381266423Sjfv printf("Link is %s\n", check ? "up":"down"); 2382266423Sjfv#endif 2383266423Sjfv return (check); 2384266423Sjfv} 2385266423Sjfv 2386266423Sjfv/********************************************************************* 2387266423Sjfv * 2388266423Sjfv * Initialize this VSI 2389266423Sjfv * 2390266423Sjfv **********************************************************************/ 2391266423Sjfvstatic int 2392270346Sjfvixl_setup_vsi(struct ixl_vsi *vsi) 2393266423Sjfv{ 2394266423Sjfv struct i40e_hw *hw = vsi->hw; 2395266423Sjfv device_t dev = vsi->dev; 2396266423Sjfv struct i40e_aqc_get_switch_config_resp *sw_config; 2397266423Sjfv struct i40e_vsi_context ctxt; 2398266423Sjfv u8 aq_buf[I40E_AQ_LARGE_BUF]; 2399266423Sjfv int ret = I40E_SUCCESS; 2400266423Sjfv u16 next = 0; 2401266423Sjfv 2402266423Sjfv sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 2403266423Sjfv ret = i40e_aq_get_switch_config(hw, sw_config, 2404266423Sjfv sizeof(aq_buf), &next, NULL); 2405266423Sjfv if (ret) { 2406266423Sjfv device_printf(dev,"aq_get_switch_config failed!!\n"); 2407266423Sjfv return (ret); 2408266423Sjfv } 2409270346Sjfv#ifdef IXL_DEBUG 2410266423Sjfv printf("Switch config: header reported: %d in structure, %d total\n", 2411266423Sjfv sw_config->header.num_reported, sw_config->header.num_total); 2412266423Sjfv printf("type=%d seid=%d uplink=%d downlink=%d\n", 2413266423Sjfv sw_config->element[0].element_type, 2414266423Sjfv sw_config->element[0].seid, 2415266423Sjfv sw_config->element[0].uplink_seid, 2416266423Sjfv sw_config->element[0].downlink_seid); 2417266423Sjfv#endif 2418266423Sjfv /* Save off this important value */ 2419266423Sjfv vsi->seid = sw_config->element[0].seid; 2420266423Sjfv 2421266423Sjfv memset(&ctxt, 0, sizeof(ctxt)); 2422266423Sjfv ctxt.seid = vsi->seid; 2423266423Sjfv ctxt.pf_num = hw->pf_id; 2424266423Sjfv ret = i40e_aq_get_vsi_params(hw, &ctxt, NULL); 2425266423Sjfv if (ret) { 2426266423Sjfv device_printf(dev,"get vsi params failed %x!!\n", ret); 2427266423Sjfv return (ret); 2428266423Sjfv } 2429270346Sjfv#ifdef IXL_DEBUG 2430266423Sjfv printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, " 2431266423Sjfv "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, " 2432266423Sjfv "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid, 2433266423Sjfv ctxt.uplink_seid, ctxt.vsi_number, 2434266423Sjfv ctxt.vsis_allocated, ctxt.vsis_unallocated, 2435266423Sjfv ctxt.flags, ctxt.pf_num, ctxt.vf_num, 2436266423Sjfv ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits); 2437266423Sjfv#endif 2438266423Sjfv /* 2439266423Sjfv ** Set the queue and traffic class bits 2440266423Sjfv ** - when multiple traffic classes are supported 2441266423Sjfv ** this will need to be more robust. 2442266423Sjfv */ 2443266423Sjfv ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID; 2444266423Sjfv ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG; 2445266423Sjfv ctxt.info.queue_mapping[0] = 0; 2446266423Sjfv ctxt.info.tc_mapping[0] = 0x0800; 2447266423Sjfv 2448266423Sjfv /* Set VLAN receive stripping mode */ 2449266423Sjfv ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; 2450266423Sjfv ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; 2451266423Sjfv if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 2452266423Sjfv ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 2453266423Sjfv else 2454266423Sjfv ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 2455266423Sjfv 2456266423Sjfv /* Keep copy of VSI info in VSI for statistic counters */ 2457266423Sjfv memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); 2458266423Sjfv 2459266423Sjfv /* Reset VSI statistics */ 2460270346Sjfv ixl_vsi_reset_stats(vsi); 2461266423Sjfv vsi->hw_filters_add = 0; 2462266423Sjfv vsi->hw_filters_del = 0; 2463266423Sjfv 2464266423Sjfv ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); 2465266423Sjfv if (ret) 2466266423Sjfv device_printf(dev,"update vsi params failed %x!!\n", 2467266423Sjfv hw->aq.asq_last_status); 2468266423Sjfv return (ret); 2469266423Sjfv} 2470266423Sjfv 2471266423Sjfv 2472266423Sjfv/********************************************************************* 2473266423Sjfv * 2474266423Sjfv * Initialize the VSI: this handles contexts, which means things 2475266423Sjfv * like the number of descriptors, buffer size, 2476266423Sjfv * plus we init the rings thru this function. 2477266423Sjfv * 2478266423Sjfv **********************************************************************/ 2479266423Sjfvstatic int 2480270346Sjfvixl_initialize_vsi(struct ixl_vsi *vsi) 2481266423Sjfv{ 2482270346Sjfv struct ixl_queue *que = vsi->queues; 2483266423Sjfv device_t dev = vsi->dev; 2484266423Sjfv struct i40e_hw *hw = vsi->hw; 2485266423Sjfv int err = 0; 2486266423Sjfv 2487266423Sjfv 2488266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2489266423Sjfv struct tx_ring *txr = &que->txr; 2490266423Sjfv struct rx_ring *rxr = &que->rxr; 2491266423Sjfv struct i40e_hmc_obj_txq tctx; 2492266423Sjfv struct i40e_hmc_obj_rxq rctx; 2493266423Sjfv u32 txctl; 2494266423Sjfv u16 size; 2495266423Sjfv 2496266423Sjfv 2497266423Sjfv /* Setup the HMC TX Context */ 2498266423Sjfv size = que->num_desc * sizeof(struct i40e_tx_desc); 2499266423Sjfv memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq)); 2500266423Sjfv tctx.new_context = 1; 2501266423Sjfv tctx.base = (txr->dma.pa/128); 2502266423Sjfv tctx.qlen = que->num_desc; 2503266423Sjfv tctx.fc_ena = 0; 2504269198Sjfv tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */ 2505269198Sjfv /* Enable HEAD writeback */ 2506269198Sjfv tctx.head_wb_ena = 1; 2507269198Sjfv tctx.head_wb_addr = txr->dma.pa + 2508269198Sjfv (que->num_desc * sizeof(struct i40e_tx_desc)); 2509266423Sjfv tctx.rdylist_act = 0; 2510266423Sjfv err = i40e_clear_lan_tx_queue_context(hw, i); 2511266423Sjfv if (err) { 2512266423Sjfv device_printf(dev, "Unable to clear TX context\n"); 2513266423Sjfv break; 2514266423Sjfv } 2515266423Sjfv err = i40e_set_lan_tx_queue_context(hw, i, &tctx); 2516266423Sjfv if (err) { 2517266423Sjfv device_printf(dev, "Unable to set TX context\n"); 2518266423Sjfv break; 2519266423Sjfv } 2520266423Sjfv /* Associate the ring with this PF */ 2521266423Sjfv txctl = I40E_QTX_CTL_PF_QUEUE; 2522266423Sjfv txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & 2523266423Sjfv I40E_QTX_CTL_PF_INDX_MASK); 2524266423Sjfv wr32(hw, I40E_QTX_CTL(i), txctl); 2525270346Sjfv ixl_flush(hw); 2526266423Sjfv 2527266423Sjfv /* Do ring (re)init */ 2528270346Sjfv ixl_init_tx_ring(que); 2529266423Sjfv 2530266423Sjfv /* Next setup the HMC RX Context */ 2531266423Sjfv if (vsi->max_frame_size <= 2048) 2532266423Sjfv rxr->mbuf_sz = MCLBYTES; 2533266423Sjfv else 2534266423Sjfv rxr->mbuf_sz = MJUMPAGESIZE; 2535266423Sjfv 2536266423Sjfv u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len; 2537266423Sjfv 2538266423Sjfv /* Set up an RX context for the HMC */ 2539266423Sjfv memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq)); 2540266423Sjfv rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT; 2541266423Sjfv /* ignore header split for now */ 2542266423Sjfv rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; 2543266423Sjfv rctx.rxmax = (vsi->max_frame_size < max_rxmax) ? 2544266423Sjfv vsi->max_frame_size : max_rxmax; 2545266423Sjfv rctx.dtype = 0; 2546266423Sjfv rctx.dsize = 1; /* do 32byte descriptors */ 2547266423Sjfv rctx.hsplit_0 = 0; /* no HDR split initially */ 2548266423Sjfv rctx.base = (rxr->dma.pa/128); 2549266423Sjfv rctx.qlen = que->num_desc; 2550266423Sjfv rctx.tphrdesc_ena = 1; 2551266423Sjfv rctx.tphwdesc_ena = 1; 2552266423Sjfv rctx.tphdata_ena = 0; 2553266423Sjfv rctx.tphhead_ena = 0; 2554266423Sjfv rctx.lrxqthresh = 2; 2555270346Sjfv#ifdef DEV_NETMAP 2556270346Sjfv /* "CRC strip in netmap is conditional" */ 2557270346Sjfv if (vsi->ifp->if_capenable & IFCAP_NETMAP && !ixl_crcstrip) 2558270346Sjfv rctx.crcstrip = 0; 2559270346Sjfv else 2560270346Sjfv#endif /* DEV_NETMAP */ 2561266423Sjfv rctx.crcstrip = 1; 2562266423Sjfv rctx.l2tsel = 1; 2563266423Sjfv rctx.showiv = 1; 2564266423Sjfv rctx.fc_ena = 0; 2565266423Sjfv rctx.prefena = 1; 2566266423Sjfv 2567266423Sjfv err = i40e_clear_lan_rx_queue_context(hw, i); 2568266423Sjfv if (err) { 2569266423Sjfv device_printf(dev, 2570266423Sjfv "Unable to clear RX context %d\n", i); 2571266423Sjfv break; 2572266423Sjfv } 2573266423Sjfv err = i40e_set_lan_rx_queue_context(hw, i, &rctx); 2574266423Sjfv if (err) { 2575266423Sjfv device_printf(dev, "Unable to set RX context %d\n", i); 2576266423Sjfv break; 2577266423Sjfv } 2578270346Sjfv err = ixl_init_rx_ring(que); 2579266423Sjfv if (err) { 2580266423Sjfv device_printf(dev, "Fail in init_rx_ring %d\n", i); 2581266423Sjfv break; 2582266423Sjfv } 2583266423Sjfv wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0); 2584270346Sjfv#ifdef DEV_NETMAP 2585270346Sjfv /* TODO appropriately comment 2586270346Sjfv * Code based on netmap code in ixgbe_init_locked() 2587270346Sjfv * Messes with what the software sets as queue 2588270346Sjfv * descriptor tail in hardware. 2589270346Sjfv */ 2590270346Sjfv if (vsi->ifp->if_capenable & IFCAP_NETMAP) 2591270346Sjfv { 2592270346Sjfv struct netmap_adapter *na = NA(vsi->ifp); 2593270346Sjfv struct netmap_kring *kring = &na->rx_rings[que->me]; 2594270346Sjfv int t = na->num_rx_desc - 1 - kring->nr_hwavail; 2595270346Sjfv 2596270346Sjfv wr32(vsi->hw, I40E_QRX_TAIL(que->me), t); 2597270346Sjfv } else 2598270346Sjfv#endif /* DEV_NETMAP */ 2599266423Sjfv wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1); 2600266423Sjfv } 2601266423Sjfv return (err); 2602266423Sjfv} 2603266423Sjfv 2604266423Sjfv 2605266423Sjfv/********************************************************************* 2606266423Sjfv * 2607266423Sjfv * Free all VSI structs. 2608266423Sjfv * 2609266423Sjfv **********************************************************************/ 2610266423Sjfvvoid 2611270346Sjfvixl_free_vsi(struct ixl_vsi *vsi) 2612266423Sjfv{ 2613270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 2614270346Sjfv struct ixl_queue *que = vsi->queues; 2615270346Sjfv struct ixl_mac_filter *f; 2616266423Sjfv 2617266423Sjfv /* Free station queues */ 2618266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2619266423Sjfv struct tx_ring *txr = &que->txr; 2620266423Sjfv struct rx_ring *rxr = &que->rxr; 2621266423Sjfv 2622266423Sjfv if (!mtx_initialized(&txr->mtx)) /* uninitialized */ 2623266423Sjfv continue; 2624270346Sjfv IXL_TX_LOCK(txr); 2625270346Sjfv ixl_free_que_tx(que); 2626266423Sjfv if (txr->base) 2627266423Sjfv i40e_free_dma(&pf->hw, &txr->dma); 2628270346Sjfv IXL_TX_UNLOCK(txr); 2629270346Sjfv IXL_TX_LOCK_DESTROY(txr); 2630266423Sjfv 2631266423Sjfv if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ 2632266423Sjfv continue; 2633270346Sjfv IXL_RX_LOCK(rxr); 2634270346Sjfv ixl_free_que_rx(que); 2635266423Sjfv if (rxr->base) 2636266423Sjfv i40e_free_dma(&pf->hw, &rxr->dma); 2637270346Sjfv IXL_RX_UNLOCK(rxr); 2638270346Sjfv IXL_RX_LOCK_DESTROY(rxr); 2639266423Sjfv 2640266423Sjfv } 2641266423Sjfv free(vsi->queues, M_DEVBUF); 2642266423Sjfv 2643266423Sjfv /* Free VSI filter list */ 2644266423Sjfv while (!SLIST_EMPTY(&vsi->ftl)) { 2645266423Sjfv f = SLIST_FIRST(&vsi->ftl); 2646266423Sjfv SLIST_REMOVE_HEAD(&vsi->ftl, next); 2647266423Sjfv free(f, M_DEVBUF); 2648266423Sjfv } 2649266423Sjfv} 2650266423Sjfv 2651266423Sjfv 2652266423Sjfv/********************************************************************* 2653266423Sjfv * 2654266423Sjfv * Allocate memory for the VSI (virtual station interface) and their 2655266423Sjfv * associated queues, rings and the descriptors associated with each, 2656266423Sjfv * called only once at attach. 2657266423Sjfv * 2658266423Sjfv **********************************************************************/ 2659266423Sjfvstatic int 2660270346Sjfvixl_setup_stations(struct ixl_pf *pf) 2661266423Sjfv{ 2662266423Sjfv device_t dev = pf->dev; 2663270346Sjfv struct ixl_vsi *vsi; 2664270346Sjfv struct ixl_queue *que; 2665266423Sjfv struct tx_ring *txr; 2666266423Sjfv struct rx_ring *rxr; 2667266423Sjfv int rsize, tsize; 2668266423Sjfv int error = I40E_SUCCESS; 2669266423Sjfv 2670266423Sjfv vsi = &pf->vsi; 2671266423Sjfv vsi->back = (void *)pf; 2672266423Sjfv vsi->hw = &pf->hw; 2673266423Sjfv vsi->id = 0; 2674266423Sjfv vsi->num_vlans = 0; 2675266423Sjfv 2676266423Sjfv /* Get memory for the station queues */ 2677266423Sjfv if (!(vsi->queues = 2678270346Sjfv (struct ixl_queue *) malloc(sizeof(struct ixl_queue) * 2679266423Sjfv vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { 2680266423Sjfv device_printf(dev, "Unable to allocate queue memory\n"); 2681266423Sjfv error = ENOMEM; 2682266423Sjfv goto early; 2683266423Sjfv } 2684266423Sjfv 2685266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 2686266423Sjfv que = &vsi->queues[i]; 2687270346Sjfv que->num_desc = ixl_ringsz; 2688266423Sjfv que->me = i; 2689266423Sjfv que->vsi = vsi; 2690269198Sjfv /* mark the queue as active */ 2691269198Sjfv vsi->active_queues |= (u64)1 << que->me; 2692266423Sjfv txr = &que->txr; 2693266423Sjfv txr->que = que; 2694269198Sjfv txr->tail = I40E_QTX_TAIL(que->me); 2695266423Sjfv 2696266423Sjfv /* Initialize the TX lock */ 2697266423Sjfv snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", 2698266423Sjfv device_get_nameunit(dev), que->me); 2699266423Sjfv mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF); 2700266423Sjfv /* Create the TX descriptor ring */ 2701269198Sjfv tsize = roundup2((que->num_desc * 2702269198Sjfv sizeof(struct i40e_tx_desc)) + 2703269198Sjfv sizeof(u32), DBA_ALIGN); 2704266423Sjfv if (i40e_allocate_dma(&pf->hw, 2705266423Sjfv &txr->dma, tsize, DBA_ALIGN)) { 2706266423Sjfv device_printf(dev, 2707266423Sjfv "Unable to allocate TX Descriptor memory\n"); 2708266423Sjfv error = ENOMEM; 2709266423Sjfv goto fail; 2710266423Sjfv } 2711266423Sjfv txr->base = (struct i40e_tx_desc *)txr->dma.va; 2712266423Sjfv bzero((void *)txr->base, tsize); 2713266423Sjfv /* Now allocate transmit soft structs for the ring */ 2714270346Sjfv if (ixl_allocate_tx_data(que)) { 2715266423Sjfv device_printf(dev, 2716266423Sjfv "Critical Failure setting up TX structures\n"); 2717266423Sjfv error = ENOMEM; 2718266423Sjfv goto fail; 2719266423Sjfv } 2720266423Sjfv /* Allocate a buf ring */ 2721266423Sjfv txr->br = buf_ring_alloc(4096, M_DEVBUF, 2722266423Sjfv M_WAITOK, &txr->mtx); 2723266423Sjfv if (txr->br == NULL) { 2724266423Sjfv device_printf(dev, 2725266423Sjfv "Critical Failure setting up TX buf ring\n"); 2726266423Sjfv error = ENOMEM; 2727266423Sjfv goto fail; 2728266423Sjfv } 2729266423Sjfv 2730266423Sjfv /* 2731266423Sjfv * Next the RX queues... 2732266423Sjfv */ 2733266423Sjfv rsize = roundup2(que->num_desc * 2734266423Sjfv sizeof(union i40e_rx_desc), DBA_ALIGN); 2735266423Sjfv rxr = &que->rxr; 2736266423Sjfv rxr->que = que; 2737269198Sjfv rxr->tail = I40E_QRX_TAIL(que->me); 2738266423Sjfv 2739266423Sjfv /* Initialize the RX side lock */ 2740266423Sjfv snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", 2741266423Sjfv device_get_nameunit(dev), que->me); 2742266423Sjfv mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF); 2743266423Sjfv 2744266423Sjfv if (i40e_allocate_dma(&pf->hw, 2745266423Sjfv &rxr->dma, rsize, 4096)) { 2746266423Sjfv device_printf(dev, 2747266423Sjfv "Unable to allocate RX Descriptor memory\n"); 2748266423Sjfv error = ENOMEM; 2749266423Sjfv goto fail; 2750266423Sjfv } 2751266423Sjfv rxr->base = (union i40e_rx_desc *)rxr->dma.va; 2752266423Sjfv bzero((void *)rxr->base, rsize); 2753266423Sjfv 2754266423Sjfv /* Allocate receive soft structs for the ring*/ 2755270346Sjfv if (ixl_allocate_rx_data(que)) { 2756266423Sjfv device_printf(dev, 2757266423Sjfv "Critical Failure setting up receive structs\n"); 2758266423Sjfv error = ENOMEM; 2759266423Sjfv goto fail; 2760266423Sjfv } 2761266423Sjfv } 2762266423Sjfv 2763266423Sjfv return (0); 2764266423Sjfv 2765266423Sjfvfail: 2766266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 2767266423Sjfv que = &vsi->queues[i]; 2768266423Sjfv rxr = &que->rxr; 2769266423Sjfv txr = &que->txr; 2770266423Sjfv if (rxr->base) 2771266423Sjfv i40e_free_dma(&pf->hw, &rxr->dma); 2772266423Sjfv if (txr->base) 2773266423Sjfv i40e_free_dma(&pf->hw, &txr->dma); 2774266423Sjfv } 2775266423Sjfv 2776266423Sjfvearly: 2777266423Sjfv return (error); 2778266423Sjfv} 2779266423Sjfv 2780266423Sjfv/* 2781266423Sjfv** Provide a update to the queue RX 2782266423Sjfv** interrupt moderation value. 2783266423Sjfv*/ 2784266423Sjfvstatic void 2785270346Sjfvixl_set_queue_rx_itr(struct ixl_queue *que) 2786266423Sjfv{ 2787270346Sjfv struct ixl_vsi *vsi = que->vsi; 2788266423Sjfv struct i40e_hw *hw = vsi->hw; 2789266423Sjfv struct rx_ring *rxr = &que->rxr; 2790266423Sjfv u16 rx_itr; 2791266423Sjfv u16 rx_latency = 0; 2792266423Sjfv int rx_bytes; 2793266423Sjfv 2794266423Sjfv 2795266423Sjfv /* Idle, do nothing */ 2796266423Sjfv if (rxr->bytes == 0) 2797266423Sjfv return; 2798266423Sjfv 2799270346Sjfv if (ixl_dynamic_rx_itr) { 2800266423Sjfv rx_bytes = rxr->bytes/rxr->itr; 2801266423Sjfv rx_itr = rxr->itr; 2802266423Sjfv 2803266423Sjfv /* Adjust latency range */ 2804266423Sjfv switch (rxr->latency) { 2805270346Sjfv case IXL_LOW_LATENCY: 2806266423Sjfv if (rx_bytes > 10) { 2807270346Sjfv rx_latency = IXL_AVE_LATENCY; 2808270346Sjfv rx_itr = IXL_ITR_20K; 2809266423Sjfv } 2810266423Sjfv break; 2811270346Sjfv case IXL_AVE_LATENCY: 2812266423Sjfv if (rx_bytes > 20) { 2813270346Sjfv rx_latency = IXL_BULK_LATENCY; 2814270346Sjfv rx_itr = IXL_ITR_8K; 2815266423Sjfv } else if (rx_bytes <= 10) { 2816270346Sjfv rx_latency = IXL_LOW_LATENCY; 2817270346Sjfv rx_itr = IXL_ITR_100K; 2818266423Sjfv } 2819266423Sjfv break; 2820270346Sjfv case IXL_BULK_LATENCY: 2821266423Sjfv if (rx_bytes <= 20) { 2822270346Sjfv rx_latency = IXL_AVE_LATENCY; 2823270346Sjfv rx_itr = IXL_ITR_20K; 2824266423Sjfv } 2825266423Sjfv break; 2826266423Sjfv } 2827266423Sjfv 2828266423Sjfv rxr->latency = rx_latency; 2829266423Sjfv 2830266423Sjfv if (rx_itr != rxr->itr) { 2831266423Sjfv /* do an exponential smoothing */ 2832266423Sjfv rx_itr = (10 * rx_itr * rxr->itr) / 2833266423Sjfv ((9 * rx_itr) + rxr->itr); 2834270346Sjfv rxr->itr = rx_itr & IXL_MAX_ITR; 2835270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 2836266423Sjfv que->me), rxr->itr); 2837266423Sjfv } 2838266423Sjfv } else { /* We may have have toggled to non-dynamic */ 2839270346Sjfv if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) 2840270346Sjfv vsi->rx_itr_setting = ixl_rx_itr; 2841266423Sjfv /* Update the hardware if needed */ 2842266423Sjfv if (rxr->itr != vsi->rx_itr_setting) { 2843266423Sjfv rxr->itr = vsi->rx_itr_setting; 2844270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, 2845266423Sjfv que->me), rxr->itr); 2846266423Sjfv } 2847266423Sjfv } 2848266423Sjfv rxr->bytes = 0; 2849266423Sjfv rxr->packets = 0; 2850266423Sjfv return; 2851266423Sjfv} 2852266423Sjfv 2853266423Sjfv 2854266423Sjfv/* 2855266423Sjfv** Provide a update to the queue TX 2856266423Sjfv** interrupt moderation value. 2857266423Sjfv*/ 2858266423Sjfvstatic void 2859270346Sjfvixl_set_queue_tx_itr(struct ixl_queue *que) 2860266423Sjfv{ 2861270346Sjfv struct ixl_vsi *vsi = que->vsi; 2862266423Sjfv struct i40e_hw *hw = vsi->hw; 2863266423Sjfv struct tx_ring *txr = &que->txr; 2864266423Sjfv u16 tx_itr; 2865266423Sjfv u16 tx_latency = 0; 2866266423Sjfv int tx_bytes; 2867266423Sjfv 2868266423Sjfv 2869266423Sjfv /* Idle, do nothing */ 2870266423Sjfv if (txr->bytes == 0) 2871266423Sjfv return; 2872266423Sjfv 2873270346Sjfv if (ixl_dynamic_tx_itr) { 2874266423Sjfv tx_bytes = txr->bytes/txr->itr; 2875266423Sjfv tx_itr = txr->itr; 2876266423Sjfv 2877266423Sjfv switch (txr->latency) { 2878270346Sjfv case IXL_LOW_LATENCY: 2879266423Sjfv if (tx_bytes > 10) { 2880270346Sjfv tx_latency = IXL_AVE_LATENCY; 2881270346Sjfv tx_itr = IXL_ITR_20K; 2882266423Sjfv } 2883266423Sjfv break; 2884270346Sjfv case IXL_AVE_LATENCY: 2885266423Sjfv if (tx_bytes > 20) { 2886270346Sjfv tx_latency = IXL_BULK_LATENCY; 2887270346Sjfv tx_itr = IXL_ITR_8K; 2888266423Sjfv } else if (tx_bytes <= 10) { 2889270346Sjfv tx_latency = IXL_LOW_LATENCY; 2890270346Sjfv tx_itr = IXL_ITR_100K; 2891266423Sjfv } 2892266423Sjfv break; 2893270346Sjfv case IXL_BULK_LATENCY: 2894266423Sjfv if (tx_bytes <= 20) { 2895270346Sjfv tx_latency = IXL_AVE_LATENCY; 2896270346Sjfv tx_itr = IXL_ITR_20K; 2897266423Sjfv } 2898266423Sjfv break; 2899266423Sjfv } 2900266423Sjfv 2901266423Sjfv txr->latency = tx_latency; 2902266423Sjfv 2903266423Sjfv if (tx_itr != txr->itr) { 2904266423Sjfv /* do an exponential smoothing */ 2905266423Sjfv tx_itr = (10 * tx_itr * txr->itr) / 2906266423Sjfv ((9 * tx_itr) + txr->itr); 2907270346Sjfv txr->itr = tx_itr & IXL_MAX_ITR; 2908270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 2909266423Sjfv que->me), txr->itr); 2910266423Sjfv } 2911266423Sjfv 2912266423Sjfv } else { /* We may have have toggled to non-dynamic */ 2913270346Sjfv if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC) 2914270346Sjfv vsi->tx_itr_setting = ixl_tx_itr; 2915266423Sjfv /* Update the hardware if needed */ 2916266423Sjfv if (txr->itr != vsi->tx_itr_setting) { 2917266423Sjfv txr->itr = vsi->tx_itr_setting; 2918270346Sjfv wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, 2919266423Sjfv que->me), txr->itr); 2920266423Sjfv } 2921266423Sjfv } 2922266423Sjfv txr->bytes = 0; 2923266423Sjfv txr->packets = 0; 2924266423Sjfv return; 2925266423Sjfv} 2926266423Sjfv 2927266423Sjfv 2928266423Sjfvstatic void 2929270346Sjfvixl_add_hw_stats(struct ixl_pf *pf) 2930266423Sjfv{ 2931266423Sjfv device_t dev = pf->dev; 2932270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 2933270346Sjfv struct ixl_queue *queues = vsi->queues; 2934269198Sjfv struct i40e_eth_stats *vsi_stats = &vsi->eth_stats; 2935269198Sjfv struct i40e_hw_port_stats *pf_stats = &pf->stats; 2936266423Sjfv 2937266423Sjfv struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 2938266423Sjfv struct sysctl_oid *tree = device_get_sysctl_tree(dev); 2939266423Sjfv struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 2940266423Sjfv 2941266423Sjfv struct sysctl_oid *vsi_node, *queue_node; 2942266423Sjfv struct sysctl_oid_list *vsi_list, *queue_list; 2943266423Sjfv 2944269198Sjfv struct tx_ring *txr; 2945269198Sjfv struct rx_ring *rxr; 2946266423Sjfv 2947266423Sjfv /* Driver statistics */ 2948266423Sjfv SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 2949266423Sjfv CTLFLAG_RD, &pf->watchdog_events, 2950266423Sjfv "Watchdog timeouts"); 2951266423Sjfv SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq", 2952266423Sjfv CTLFLAG_RD, &pf->admin_irq, 2953266423Sjfv "Admin Queue IRQ Handled"); 2954266423Sjfv 2955266423Sjfv /* VSI statistics */ 2956266423Sjfv#define QUEUE_NAME_LEN 32 2957266423Sjfv char queue_namebuf[QUEUE_NAME_LEN]; 2958266423Sjfv 2959269198Sjfv // ERJ: Only one vsi now, re-do when >1 VSI enabled 2960269198Sjfv // snprintf(vsi_namebuf, QUEUE_NAME_LEN, "vsi%d", vsi->info.stat_counter_idx); 2961269198Sjfv vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "vsi", 2962269198Sjfv CTLFLAG_RD, NULL, "VSI-specific stats"); 2963266423Sjfv vsi_list = SYSCTL_CHILDREN(vsi_node); 2964266423Sjfv 2965270346Sjfv ixl_add_sysctls_eth_stats(ctx, vsi_list, vsi_stats); 2966266423Sjfv 2967266423Sjfv /* Queue statistics */ 2968266423Sjfv for (int q = 0; q < vsi->num_queues; q++) { 2969269198Sjfv snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); 2970266423Sjfv queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, OID_AUTO, queue_namebuf, 2971269198Sjfv CTLFLAG_RD, NULL, "Queue #"); 2972266423Sjfv queue_list = SYSCTL_CHILDREN(queue_node); 2973266423Sjfv 2974269198Sjfv txr = &(queues[q].txr); 2975269198Sjfv rxr = &(queues[q].rxr); 2976269198Sjfv 2977269198Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", 2978266423Sjfv CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), 2979266423Sjfv "m_defrag() failed"); 2980269198Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped", 2981266423Sjfv CTLFLAG_RD, &(queues[q].dropped_pkts), 2982266423Sjfv "Driver dropped packets"); 2983266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 2984266423Sjfv CTLFLAG_RD, &(queues[q].irqs), 2985266423Sjfv "irqs on this queue"); 2986269198Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", 2987266423Sjfv CTLFLAG_RD, &(queues[q].tso), 2988266423Sjfv "TSO"); 2989269198Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup", 2990266423Sjfv CTLFLAG_RD, &(queues[q].tx_dma_setup), 2991266423Sjfv "Driver tx dma failure in xmit"); 2992266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 2993266423Sjfv CTLFLAG_RD, &(txr->no_desc), 2994266423Sjfv "Queue No Descriptor Available"); 2995266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 2996266423Sjfv CTLFLAG_RD, &(txr->total_packets), 2997266423Sjfv "Queue Packets Transmitted"); 2998266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", 2999270346Sjfv CTLFLAG_RD, &(txr->tx_bytes), 3000266423Sjfv "Queue Bytes Transmitted"); 3001266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 3002266423Sjfv CTLFLAG_RD, &(rxr->rx_packets), 3003266423Sjfv "Queue Packets Received"); 3004266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 3005266423Sjfv CTLFLAG_RD, &(rxr->rx_bytes), 3006266423Sjfv "Queue Bytes Received"); 3007266423Sjfv } 3008266423Sjfv 3009266423Sjfv /* MAC stats */ 3010270346Sjfv ixl_add_sysctls_mac_stats(ctx, child, pf_stats); 3011266423Sjfv} 3012266423Sjfv 3013266423Sjfvstatic void 3014270346Sjfvixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx, 3015266423Sjfv struct sysctl_oid_list *child, 3016266423Sjfv struct i40e_eth_stats *eth_stats) 3017266423Sjfv{ 3018270346Sjfv struct ixl_sysctl_info ctls[] = 3019266423Sjfv { 3020266423Sjfv {ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, 3021266423Sjfv {ð_stats->rx_unicast, "ucast_pkts_rcvd", 3022266423Sjfv "Unicast Packets Received"}, 3023266423Sjfv {ð_stats->rx_multicast, "mcast_pkts_rcvd", 3024266423Sjfv "Multicast Packets Received"}, 3025266423Sjfv {ð_stats->rx_broadcast, "bcast_pkts_rcvd", 3026266423Sjfv "Broadcast Packets Received"}, 3027269198Sjfv {ð_stats->rx_discards, "rx_discards", "Discarded RX packets"}, 3028266423Sjfv {ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, 3029266423Sjfv {ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, 3030266423Sjfv {ð_stats->tx_multicast, "mcast_pkts_txd", 3031266423Sjfv "Multicast Packets Transmitted"}, 3032266423Sjfv {ð_stats->tx_broadcast, "bcast_pkts_txd", 3033266423Sjfv "Broadcast Packets Transmitted"}, 3034269198Sjfv {ð_stats->tx_discards, "tx_discards", "Discarded TX packets"}, 3035266423Sjfv // end 3036266423Sjfv {0,0,0} 3037266423Sjfv }; 3038266423Sjfv 3039270346Sjfv struct ixl_sysctl_info *entry = ctls; 3040266423Sjfv while (entry->stat != 0) 3041266423Sjfv { 3042266423Sjfv SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name, 3043266423Sjfv CTLFLAG_RD, entry->stat, 3044266423Sjfv entry->description); 3045266423Sjfv entry++; 3046266423Sjfv } 3047266423Sjfv} 3048266423Sjfv 3049266423Sjfvstatic void 3050270346Sjfvixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx, 3051266423Sjfv struct sysctl_oid_list *child, 3052266423Sjfv struct i40e_hw_port_stats *stats) 3053266423Sjfv{ 3054269198Sjfv struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", 3055266423Sjfv CTLFLAG_RD, NULL, "Mac Statistics"); 3056266423Sjfv struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node); 3057266423Sjfv 3058266423Sjfv struct i40e_eth_stats *eth_stats = &stats->eth; 3059270346Sjfv ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats); 3060266423Sjfv 3061270346Sjfv struct ixl_sysctl_info ctls[] = 3062266423Sjfv { 3063266423Sjfv {&stats->crc_errors, "crc_errors", "CRC Errors"}, 3064266423Sjfv {&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"}, 3065266423Sjfv {&stats->mac_local_faults, "local_faults", "MAC Local Faults"}, 3066266423Sjfv {&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"}, 3067266423Sjfv {&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"}, 3068266423Sjfv /* Packet Reception Stats */ 3069266423Sjfv {&stats->rx_size_64, "rx_frames_64", "64 byte frames received"}, 3070266423Sjfv {&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"}, 3071266423Sjfv {&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"}, 3072266423Sjfv {&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"}, 3073266423Sjfv {&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"}, 3074266423Sjfv {&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"}, 3075266423Sjfv {&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"}, 3076266423Sjfv {&stats->rx_undersize, "rx_undersize", "Undersized packets received"}, 3077266423Sjfv {&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"}, 3078266423Sjfv {&stats->rx_oversize, "rx_oversized", "Oversized packets received"}, 3079266423Sjfv {&stats->rx_jabber, "rx_jabber", "Received Jabber"}, 3080266423Sjfv {&stats->checksum_error, "checksum_errors", "Checksum Errors"}, 3081266423Sjfv /* Packet Transmission Stats */ 3082266423Sjfv {&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"}, 3083266423Sjfv {&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"}, 3084266423Sjfv {&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"}, 3085266423Sjfv {&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"}, 3086266423Sjfv {&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"}, 3087266423Sjfv {&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"}, 3088266423Sjfv {&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"}, 3089266423Sjfv /* Flow control */ 3090266423Sjfv {&stats->link_xon_tx, "xon_txd", "Link XON transmitted"}, 3091266423Sjfv {&stats->link_xon_rx, "xon_recvd", "Link XON received"}, 3092266423Sjfv {&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"}, 3093266423Sjfv {&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"}, 3094266423Sjfv /* End */ 3095266423Sjfv {0,0,0} 3096266423Sjfv }; 3097266423Sjfv 3098270346Sjfv struct ixl_sysctl_info *entry = ctls; 3099266423Sjfv while (entry->stat != 0) 3100266423Sjfv { 3101266423Sjfv SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name, 3102266423Sjfv CTLFLAG_RD, entry->stat, 3103266423Sjfv entry->description); 3104266423Sjfv entry++; 3105266423Sjfv } 3106266423Sjfv} 3107266423Sjfv 3108266423Sjfv/* 3109270346Sjfv** ixl_config_rss - setup RSS 3110266423Sjfv** - note this is done for the single vsi 3111266423Sjfv*/ 3112270346Sjfvstatic void ixl_config_rss(struct ixl_vsi *vsi) 3113266423Sjfv{ 3114270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 3115266423Sjfv struct i40e_hw *hw = vsi->hw; 3116266423Sjfv u32 lut = 0; 3117266423Sjfv u64 set_hena, hena; 3118266423Sjfv int i, j; 3119266423Sjfv 3120266423Sjfv static const u32 seed[I40E_PFQF_HKEY_MAX_INDEX + 1] = {0x41b01687, 3121266423Sjfv 0x183cfd8c, 0xce880440, 0x580cbc3c, 0x35897377, 3122266423Sjfv 0x328b25e1, 0x4fa98922, 0xb7d90c14, 0xd5bad70d, 3123266423Sjfv 0xcd15a2c1, 0xe8580225, 0x4a1e9d11, 0xfe5731be}; 3124266423Sjfv 3125266423Sjfv /* Fill out hash function seed */ 3126266423Sjfv for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) 3127266423Sjfv wr32(hw, I40E_PFQF_HKEY(i), seed[i]); 3128266423Sjfv 3129266423Sjfv /* Enable PCTYPES for RSS: */ 3130266423Sjfv set_hena = 3131266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | 3132266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | 3133266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | 3134266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | 3135266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | 3136266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | 3137266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | 3138266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | 3139266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | 3140266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | 3141266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD); 3142266423Sjfv 3143266423Sjfv hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) | 3144266423Sjfv ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32); 3145266423Sjfv hena |= set_hena; 3146266423Sjfv wr32(hw, I40E_PFQF_HENA(0), (u32)hena); 3147266423Sjfv wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); 3148266423Sjfv 3149266423Sjfv /* Populate the LUT with max no. of queues in round robin fashion */ 3150266423Sjfv for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) { 3151266423Sjfv if (j == vsi->num_queues) 3152266423Sjfv j = 0; 3153266423Sjfv /* lut = 4-byte sliding window of 4 lut entries */ 3154266423Sjfv lut = (lut << 8) | (j & 3155266423Sjfv ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1)); 3156266423Sjfv /* On i = 3, we have 4 entries in lut; write to the register */ 3157266423Sjfv if ((i & 3) == 3) 3158266423Sjfv wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); 3159266423Sjfv } 3160270346Sjfv ixl_flush(hw); 3161266423Sjfv} 3162266423Sjfv 3163266423Sjfv 3164266423Sjfv/* 3165266423Sjfv** This routine is run via an vlan config EVENT, 3166266423Sjfv** it enables us to use the HW Filter table since 3167266423Sjfv** we can get the vlan id. This just creates the 3168266423Sjfv** entry in the soft version of the VFTA, init will 3169266423Sjfv** repopulate the real table. 3170266423Sjfv*/ 3171266423Sjfvstatic void 3172270346Sjfvixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3173266423Sjfv{ 3174270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 3175266423Sjfv struct i40e_hw *hw = vsi->hw; 3176270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 3177266423Sjfv 3178266423Sjfv if (ifp->if_softc != arg) /* Not our event */ 3179266423Sjfv return; 3180266423Sjfv 3181266423Sjfv if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3182266423Sjfv return; 3183266423Sjfv 3184270346Sjfv IXL_PF_LOCK(pf); 3185266423Sjfv ++vsi->num_vlans; 3186270346Sjfv ixl_add_filter(vsi, hw->mac.addr, vtag); 3187270346Sjfv IXL_PF_UNLOCK(pf); 3188266423Sjfv} 3189266423Sjfv 3190266423Sjfv/* 3191266423Sjfv** This routine is run via an vlan 3192266423Sjfv** unconfig EVENT, remove our entry 3193266423Sjfv** in the soft vfta. 3194266423Sjfv*/ 3195266423Sjfvstatic void 3196270346Sjfvixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3197266423Sjfv{ 3198270346Sjfv struct ixl_vsi *vsi = ifp->if_softc; 3199266423Sjfv struct i40e_hw *hw = vsi->hw; 3200270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 3201266423Sjfv 3202266423Sjfv if (ifp->if_softc != arg) 3203266423Sjfv return; 3204266423Sjfv 3205266423Sjfv if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3206266423Sjfv return; 3207266423Sjfv 3208270346Sjfv IXL_PF_LOCK(pf); 3209266423Sjfv --vsi->num_vlans; 3210270346Sjfv ixl_del_filter(vsi, hw->mac.addr, vtag); 3211270346Sjfv IXL_PF_UNLOCK(pf); 3212266423Sjfv} 3213266423Sjfv 3214266423Sjfv/* 3215266423Sjfv** This routine updates vlan filters, called by init 3216266423Sjfv** it scans the filter table and then updates the hw 3217266423Sjfv** after a soft reset. 3218266423Sjfv*/ 3219266423Sjfvstatic void 3220270346Sjfvixl_setup_vlan_filters(struct ixl_vsi *vsi) 3221266423Sjfv{ 3222270346Sjfv struct ixl_mac_filter *f; 3223266423Sjfv int cnt = 0, flags; 3224266423Sjfv 3225266423Sjfv if (vsi->num_vlans == 0) 3226266423Sjfv return; 3227266423Sjfv /* 3228266423Sjfv ** Scan the filter list for vlan entries, 3229266423Sjfv ** mark them for addition and then call 3230266423Sjfv ** for the AQ update. 3231266423Sjfv */ 3232266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 3233270346Sjfv if (f->flags & IXL_FILTER_VLAN) { 3234266423Sjfv f->flags |= 3235270346Sjfv (IXL_FILTER_ADD | 3236270346Sjfv IXL_FILTER_USED); 3237266423Sjfv cnt++; 3238266423Sjfv } 3239266423Sjfv } 3240266423Sjfv if (cnt == 0) { 3241266423Sjfv printf("setup vlan: no filters found!\n"); 3242266423Sjfv return; 3243266423Sjfv } 3244270346Sjfv flags = IXL_FILTER_VLAN; 3245270346Sjfv flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 3246270346Sjfv ixl_add_hw_filters(vsi, flags, cnt); 3247266423Sjfv return; 3248266423Sjfv} 3249266423Sjfv 3250266423Sjfv/* 3251266423Sjfv** Initialize filter list and add filters that the hardware 3252266423Sjfv** needs to know about. 3253266423Sjfv*/ 3254266423Sjfvstatic void 3255270346Sjfvixl_init_filters(struct ixl_vsi *vsi) 3256266423Sjfv{ 3257269198Sjfv /* Add broadcast address */ 3258269198Sjfv u8 bc[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 3259270346Sjfv ixl_add_filter(vsi, bc, IXL_VLAN_ANY); 3260266423Sjfv} 3261266423Sjfv 3262266423Sjfv/* 3263266423Sjfv** This routine adds mulicast filters 3264266423Sjfv*/ 3265266423Sjfvstatic void 3266270346Sjfvixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr) 3267266423Sjfv{ 3268270346Sjfv struct ixl_mac_filter *f; 3269266423Sjfv 3270266423Sjfv /* Does one already exist */ 3271270346Sjfv f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 3272266423Sjfv if (f != NULL) 3273266423Sjfv return; 3274266423Sjfv 3275270346Sjfv f = ixl_get_filter(vsi); 3276266423Sjfv if (f == NULL) { 3277266423Sjfv printf("WARNING: no filter available!!\n"); 3278266423Sjfv return; 3279266423Sjfv } 3280266423Sjfv bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 3281270346Sjfv f->vlan = IXL_VLAN_ANY; 3282270346Sjfv f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED 3283270346Sjfv | IXL_FILTER_MC); 3284266423Sjfv 3285266423Sjfv return; 3286266423Sjfv} 3287266423Sjfv 3288266423Sjfv/* 3289266423Sjfv** This routine adds macvlan filters 3290266423Sjfv*/ 3291266423Sjfvstatic void 3292270346Sjfvixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 3293266423Sjfv{ 3294270346Sjfv struct ixl_mac_filter *f, *tmp; 3295266423Sjfv device_t dev = vsi->dev; 3296266423Sjfv 3297270346Sjfv DEBUGOUT("ixl_add_filter: begin"); 3298266423Sjfv 3299266423Sjfv /* Does one already exist */ 3300270346Sjfv f = ixl_find_filter(vsi, macaddr, vlan); 3301266423Sjfv if (f != NULL) 3302266423Sjfv return; 3303266423Sjfv /* 3304266423Sjfv ** Is this the first vlan being registered, if so we 3305266423Sjfv ** need to remove the ANY filter that indicates we are 3306266423Sjfv ** not in a vlan, and replace that with a 0 filter. 3307266423Sjfv */ 3308270346Sjfv if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) { 3309270346Sjfv tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY); 3310266423Sjfv if (tmp != NULL) { 3311270346Sjfv ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY); 3312270346Sjfv ixl_add_filter(vsi, macaddr, 0); 3313266423Sjfv } 3314266423Sjfv } 3315266423Sjfv 3316270346Sjfv f = ixl_get_filter(vsi); 3317266423Sjfv if (f == NULL) { 3318266423Sjfv device_printf(dev, "WARNING: no filter available!!\n"); 3319266423Sjfv return; 3320266423Sjfv } 3321266423Sjfv bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 3322266423Sjfv f->vlan = vlan; 3323270346Sjfv f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); 3324270346Sjfv if (f->vlan != IXL_VLAN_ANY) 3325270346Sjfv f->flags |= IXL_FILTER_VLAN; 3326266423Sjfv 3327270346Sjfv ixl_add_hw_filters(vsi, f->flags, 1); 3328266423Sjfv return; 3329266423Sjfv} 3330266423Sjfv 3331266423Sjfvstatic void 3332270346Sjfvixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 3333266423Sjfv{ 3334270346Sjfv struct ixl_mac_filter *f; 3335266423Sjfv 3336270346Sjfv f = ixl_find_filter(vsi, macaddr, vlan); 3337266423Sjfv if (f == NULL) 3338266423Sjfv return; 3339266423Sjfv 3340270346Sjfv f->flags |= IXL_FILTER_DEL; 3341270346Sjfv ixl_del_hw_filters(vsi, 1); 3342266423Sjfv 3343266423Sjfv /* Check if this is the last vlan removal */ 3344270346Sjfv if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) { 3345266423Sjfv /* Switch back to a non-vlan filter */ 3346270346Sjfv ixl_del_filter(vsi, macaddr, 0); 3347270346Sjfv ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY); 3348266423Sjfv } 3349266423Sjfv return; 3350266423Sjfv} 3351266423Sjfv 3352266423Sjfv/* 3353266423Sjfv** Find the filter with both matching mac addr and vlan id 3354266423Sjfv*/ 3355270346Sjfvstatic struct ixl_mac_filter * 3356270346Sjfvixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan) 3357266423Sjfv{ 3358270346Sjfv struct ixl_mac_filter *f; 3359266423Sjfv bool match = FALSE; 3360266423Sjfv 3361266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 3362266423Sjfv if (!cmp_etheraddr(f->macaddr, macaddr)) 3363266423Sjfv continue; 3364266423Sjfv if (f->vlan == vlan) { 3365266423Sjfv match = TRUE; 3366266423Sjfv break; 3367266423Sjfv } 3368266423Sjfv } 3369266423Sjfv 3370266423Sjfv if (!match) 3371266423Sjfv f = NULL; 3372266423Sjfv return (f); 3373266423Sjfv} 3374266423Sjfv 3375266423Sjfv/* 3376266423Sjfv** This routine takes additions to the vsi filter 3377266423Sjfv** table and creates an Admin Queue call to create 3378266423Sjfv** the filters in the hardware. 3379266423Sjfv*/ 3380266423Sjfvstatic void 3381270346Sjfvixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt) 3382266423Sjfv{ 3383266423Sjfv struct i40e_aqc_add_macvlan_element_data *a, *b; 3384270346Sjfv struct ixl_mac_filter *f; 3385266423Sjfv struct i40e_hw *hw = vsi->hw; 3386266423Sjfv device_t dev = vsi->dev; 3387266423Sjfv int err, j = 0; 3388266423Sjfv 3389266423Sjfv a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt, 3390266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 3391266423Sjfv if (a == NULL) { 3392266423Sjfv device_printf(dev, "add hw filter failed to get memory\n"); 3393266423Sjfv return; 3394266423Sjfv } 3395266423Sjfv 3396266423Sjfv /* 3397266423Sjfv ** Scan the filter list, each time we find one 3398266423Sjfv ** we add it to the admin queue array and turn off 3399266423Sjfv ** the add bit. 3400266423Sjfv */ 3401266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 3402266423Sjfv if (f->flags == flags) { 3403266423Sjfv b = &a[j]; // a pox on fvl long names :) 3404266423Sjfv bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN); 3405266423Sjfv b->vlan_tag = 3406270346Sjfv (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan); 3407266423Sjfv b->flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH; 3408270346Sjfv f->flags &= ~IXL_FILTER_ADD; 3409266423Sjfv j++; 3410266423Sjfv } 3411266423Sjfv if (j == cnt) 3412266423Sjfv break; 3413266423Sjfv } 3414266423Sjfv if (j > 0) { 3415266423Sjfv err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); 3416266423Sjfv if (err) 3417266423Sjfv device_printf(dev, "aq_add_macvlan failure %d\n", 3418266423Sjfv hw->aq.asq_last_status); 3419266423Sjfv else 3420266423Sjfv vsi->hw_filters_add += j; 3421266423Sjfv } 3422266423Sjfv free(a, M_DEVBUF); 3423266423Sjfv return; 3424266423Sjfv} 3425266423Sjfv 3426266423Sjfv/* 3427266423Sjfv** This routine takes removals in the vsi filter 3428266423Sjfv** table and creates an Admin Queue call to delete 3429266423Sjfv** the filters in the hardware. 3430266423Sjfv*/ 3431266423Sjfvstatic void 3432270346Sjfvixl_del_hw_filters(struct ixl_vsi *vsi, int cnt) 3433266423Sjfv{ 3434266423Sjfv struct i40e_aqc_remove_macvlan_element_data *d, *e; 3435266423Sjfv struct i40e_hw *hw = vsi->hw; 3436266423Sjfv device_t dev = vsi->dev; 3437270346Sjfv struct ixl_mac_filter *f, *f_temp; 3438266423Sjfv int err, j = 0; 3439266423Sjfv 3440270346Sjfv DEBUGOUT("ixl_del_hw_filters: begin\n"); 3441266423Sjfv 3442266423Sjfv d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt, 3443266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 3444266423Sjfv if (d == NULL) { 3445266423Sjfv printf("del hw filter failed to get memory\n"); 3446266423Sjfv return; 3447266423Sjfv } 3448266423Sjfv 3449266423Sjfv SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) { 3450270346Sjfv if (f->flags & IXL_FILTER_DEL) { 3451266423Sjfv e = &d[j]; // a pox on fvl long names :) 3452266423Sjfv bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN); 3453270346Sjfv e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan); 3454266423Sjfv e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; 3455266423Sjfv /* delete entry from vsi list */ 3456270346Sjfv SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next); 3457266423Sjfv free(f, M_DEVBUF); 3458266423Sjfv j++; 3459266423Sjfv } 3460266423Sjfv if (j == cnt) 3461266423Sjfv break; 3462266423Sjfv } 3463266423Sjfv if (j > 0) { 3464266423Sjfv err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); 3465266423Sjfv /* NOTE: returns ENOENT every time but seems to work fine, 3466266423Sjfv so we'll ignore that specific error. */ 3467266423Sjfv if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { 3468266423Sjfv int sc = 0; 3469266423Sjfv for (int i = 0; i < j; i++) 3470266423Sjfv sc += (!d[i].error_code); 3471266423Sjfv vsi->hw_filters_del += sc; 3472266423Sjfv device_printf(dev, 3473266423Sjfv "Failed to remove %d/%d filters, aq error %d\n", 3474266423Sjfv j - sc, j, hw->aq.asq_last_status); 3475266423Sjfv } else 3476266423Sjfv vsi->hw_filters_del += j; 3477266423Sjfv } 3478266423Sjfv free(d, M_DEVBUF); 3479266423Sjfv 3480270346Sjfv DEBUGOUT("ixl_del_hw_filters: end\n"); 3481266423Sjfv return; 3482266423Sjfv} 3483266423Sjfv 3484266423Sjfv 3485266423Sjfvstatic void 3486270346Sjfvixl_enable_rings(struct ixl_vsi *vsi) 3487266423Sjfv{ 3488266423Sjfv struct i40e_hw *hw = vsi->hw; 3489266423Sjfv u32 reg; 3490266423Sjfv 3491266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 3492266423Sjfv i40e_pre_tx_queue_cfg(hw, i, TRUE); 3493266423Sjfv 3494266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3495266423Sjfv reg |= I40E_QTX_ENA_QENA_REQ_MASK | 3496266423Sjfv I40E_QTX_ENA_QENA_STAT_MASK; 3497266423Sjfv wr32(hw, I40E_QTX_ENA(i), reg); 3498266423Sjfv /* Verify the enable took */ 3499266423Sjfv for (int j = 0; j < 10; j++) { 3500266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3501266423Sjfv if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 3502266423Sjfv break; 3503266423Sjfv i40e_msec_delay(10); 3504266423Sjfv } 3505266423Sjfv if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) 3506266423Sjfv printf("TX queue %d disabled!\n", i); 3507266423Sjfv 3508266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3509266423Sjfv reg |= I40E_QRX_ENA_QENA_REQ_MASK | 3510266423Sjfv I40E_QRX_ENA_QENA_STAT_MASK; 3511266423Sjfv wr32(hw, I40E_QRX_ENA(i), reg); 3512266423Sjfv /* Verify the enable took */ 3513266423Sjfv for (int j = 0; j < 10; j++) { 3514266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3515266423Sjfv if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 3516266423Sjfv break; 3517266423Sjfv i40e_msec_delay(10); 3518266423Sjfv } 3519266423Sjfv if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) 3520266423Sjfv printf("RX queue %d disabled!\n", i); 3521266423Sjfv } 3522266423Sjfv} 3523266423Sjfv 3524266423Sjfvstatic void 3525270346Sjfvixl_disable_rings(struct ixl_vsi *vsi) 3526266423Sjfv{ 3527266423Sjfv struct i40e_hw *hw = vsi->hw; 3528266423Sjfv u32 reg; 3529266423Sjfv 3530266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 3531266423Sjfv i40e_pre_tx_queue_cfg(hw, i, FALSE); 3532266423Sjfv i40e_usec_delay(500); 3533266423Sjfv 3534266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3535266423Sjfv reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; 3536266423Sjfv wr32(hw, I40E_QTX_ENA(i), reg); 3537266423Sjfv /* Verify the disable took */ 3538266423Sjfv for (int j = 0; j < 10; j++) { 3539266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3540266423Sjfv if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK)) 3541266423Sjfv break; 3542266423Sjfv i40e_msec_delay(10); 3543266423Sjfv } 3544266423Sjfv if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 3545266423Sjfv printf("TX queue %d still enabled!\n", i); 3546266423Sjfv 3547266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3548266423Sjfv reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; 3549266423Sjfv wr32(hw, I40E_QRX_ENA(i), reg); 3550266423Sjfv /* Verify the disable took */ 3551266423Sjfv for (int j = 0; j < 10; j++) { 3552266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3553266423Sjfv if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK)) 3554266423Sjfv break; 3555266423Sjfv i40e_msec_delay(10); 3556266423Sjfv } 3557266423Sjfv if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 3558266423Sjfv printf("RX queue %d still enabled!\n", i); 3559266423Sjfv } 3560266423Sjfv} 3561266423Sjfv 3562269198Sjfv/** 3563270346Sjfv * ixl_handle_mdd_event 3564269198Sjfv * 3565269198Sjfv * Called from interrupt handler to identify possibly malicious vfs 3566269198Sjfv * (But also detects events from the PF, as well) 3567269198Sjfv **/ 3568270346Sjfvstatic void ixl_handle_mdd_event(struct ixl_pf *pf) 3569269198Sjfv{ 3570269198Sjfv struct i40e_hw *hw = &pf->hw; 3571269198Sjfv device_t dev = pf->dev; 3572269198Sjfv bool mdd_detected = false; 3573269198Sjfv bool pf_mdd_detected = false; 3574269198Sjfv u32 reg; 3575269198Sjfv 3576269198Sjfv /* find what triggered the MDD event */ 3577269198Sjfv reg = rd32(hw, I40E_GL_MDET_TX); 3578269198Sjfv if (reg & I40E_GL_MDET_TX_VALID_MASK) { 3579269198Sjfv u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >> 3580269198Sjfv I40E_GL_MDET_TX_PF_NUM_SHIFT; 3581269198Sjfv u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >> 3582269198Sjfv I40E_GL_MDET_TX_EVENT_SHIFT; 3583269198Sjfv u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >> 3584269198Sjfv I40E_GL_MDET_TX_QUEUE_SHIFT; 3585269198Sjfv device_printf(dev, 3586269198Sjfv "Malicious Driver Detection event 0x%02x" 3587269198Sjfv " on TX queue %d pf number 0x%02x\n", 3588269198Sjfv event, queue, pf_num); 3589269198Sjfv wr32(hw, I40E_GL_MDET_TX, 0xffffffff); 3590269198Sjfv mdd_detected = true; 3591269198Sjfv } 3592269198Sjfv reg = rd32(hw, I40E_GL_MDET_RX); 3593269198Sjfv if (reg & I40E_GL_MDET_RX_VALID_MASK) { 3594269198Sjfv u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >> 3595269198Sjfv I40E_GL_MDET_RX_FUNCTION_SHIFT; 3596269198Sjfv u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >> 3597269198Sjfv I40E_GL_MDET_RX_EVENT_SHIFT; 3598269198Sjfv u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >> 3599269198Sjfv I40E_GL_MDET_RX_QUEUE_SHIFT; 3600269198Sjfv device_printf(dev, 3601269198Sjfv "Malicious Driver Detection event 0x%02x" 3602269198Sjfv " on RX queue %d of function 0x%02x\n", 3603269198Sjfv event, queue, func); 3604269198Sjfv wr32(hw, I40E_GL_MDET_RX, 0xffffffff); 3605269198Sjfv mdd_detected = true; 3606269198Sjfv } 3607269198Sjfv 3608269198Sjfv if (mdd_detected) { 3609269198Sjfv reg = rd32(hw, I40E_PF_MDET_TX); 3610269198Sjfv if (reg & I40E_PF_MDET_TX_VALID_MASK) { 3611269198Sjfv wr32(hw, I40E_PF_MDET_TX, 0xFFFF); 3612269198Sjfv device_printf(dev, 3613269198Sjfv "MDD TX event is for this function 0x%08x", 3614269198Sjfv reg); 3615269198Sjfv pf_mdd_detected = true; 3616269198Sjfv } 3617269198Sjfv reg = rd32(hw, I40E_PF_MDET_RX); 3618269198Sjfv if (reg & I40E_PF_MDET_RX_VALID_MASK) { 3619269198Sjfv wr32(hw, I40E_PF_MDET_RX, 0xFFFF); 3620269198Sjfv device_printf(dev, 3621269198Sjfv "MDD RX event is for this function 0x%08x", 3622269198Sjfv reg); 3623269198Sjfv pf_mdd_detected = true; 3624269198Sjfv } 3625269198Sjfv } 3626269198Sjfv 3627269198Sjfv /* re-enable mdd interrupt cause */ 3628269198Sjfv reg = rd32(hw, I40E_PFINT_ICR0_ENA); 3629269198Sjfv reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 3630269198Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 3631270346Sjfv ixl_flush(hw); 3632269198Sjfv} 3633269198Sjfv 3634266423Sjfvstatic void 3635270346Sjfvixl_enable_intr(struct ixl_vsi *vsi) 3636266423Sjfv{ 3637266423Sjfv struct i40e_hw *hw = vsi->hw; 3638270346Sjfv struct ixl_queue *que = vsi->queues; 3639266423Sjfv 3640270346Sjfv if (ixl_enable_msix) { 3641270346Sjfv ixl_enable_adminq(hw); 3642266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) 3643270346Sjfv ixl_enable_queue(hw, que->me); 3644266423Sjfv } else 3645270346Sjfv ixl_enable_legacy(hw); 3646266423Sjfv} 3647266423Sjfv 3648266423Sjfvstatic void 3649270346Sjfvixl_disable_intr(struct ixl_vsi *vsi) 3650266423Sjfv{ 3651266423Sjfv struct i40e_hw *hw = vsi->hw; 3652270346Sjfv struct ixl_queue *que = vsi->queues; 3653266423Sjfv 3654270346Sjfv if (ixl_enable_msix) { 3655270346Sjfv ixl_disable_adminq(hw); 3656266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) 3657270346Sjfv ixl_disable_queue(hw, que->me); 3658266423Sjfv } else 3659270346Sjfv ixl_disable_legacy(hw); 3660266423Sjfv} 3661266423Sjfv 3662266423Sjfvstatic void 3663270346Sjfvixl_enable_adminq(struct i40e_hw *hw) 3664266423Sjfv{ 3665266423Sjfv u32 reg; 3666266423Sjfv 3667266423Sjfv reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 3668266423Sjfv I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 3669270346Sjfv (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 3670266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3671270346Sjfv ixl_flush(hw); 3672266423Sjfv return; 3673266423Sjfv} 3674266423Sjfv 3675266423Sjfvstatic void 3676270346Sjfvixl_disable_adminq(struct i40e_hw *hw) 3677266423Sjfv{ 3678266423Sjfv u32 reg; 3679266423Sjfv 3680270346Sjfv reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 3681266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3682266423Sjfv 3683266423Sjfv return; 3684266423Sjfv} 3685266423Sjfv 3686266423Sjfvstatic void 3687270346Sjfvixl_enable_queue(struct i40e_hw *hw, int id) 3688266423Sjfv{ 3689266423Sjfv u32 reg; 3690266423Sjfv 3691266423Sjfv reg = I40E_PFINT_DYN_CTLN_INTENA_MASK | 3692266423Sjfv I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | 3693270346Sjfv (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); 3694266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 3695266423Sjfv} 3696266423Sjfv 3697266423Sjfvstatic void 3698270346Sjfvixl_disable_queue(struct i40e_hw *hw, int id) 3699266423Sjfv{ 3700266423Sjfv u32 reg; 3701266423Sjfv 3702270346Sjfv reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; 3703266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 3704266423Sjfv 3705266423Sjfv return; 3706266423Sjfv} 3707266423Sjfv 3708266423Sjfvstatic void 3709270346Sjfvixl_enable_legacy(struct i40e_hw *hw) 3710266423Sjfv{ 3711266423Sjfv u32 reg; 3712266423Sjfv reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 3713266423Sjfv I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 3714270346Sjfv (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 3715266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3716266423Sjfv} 3717266423Sjfv 3718266423Sjfvstatic void 3719270346Sjfvixl_disable_legacy(struct i40e_hw *hw) 3720266423Sjfv{ 3721266423Sjfv u32 reg; 3722266423Sjfv 3723270346Sjfv reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 3724266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3725266423Sjfv 3726266423Sjfv return; 3727266423Sjfv} 3728266423Sjfv 3729266423Sjfvstatic void 3730270346Sjfvixl_update_stats_counters(struct ixl_pf *pf) 3731266423Sjfv{ 3732266423Sjfv struct i40e_hw *hw = &pf->hw; 3733270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 3734269198Sjfv struct ifnet *ifp = vsi->ifp; 3735269198Sjfv 3736266423Sjfv struct i40e_hw_port_stats *nsd = &pf->stats; 3737266423Sjfv struct i40e_hw_port_stats *osd = &pf->stats_offsets; 3738266423Sjfv 3739266423Sjfv /* Update hw stats */ 3740270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port), 3741266423Sjfv pf->stat_offsets_loaded, 3742266423Sjfv &osd->crc_errors, &nsd->crc_errors); 3743270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port), 3744266423Sjfv pf->stat_offsets_loaded, 3745266423Sjfv &osd->illegal_bytes, &nsd->illegal_bytes); 3746270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port), 3747266423Sjfv I40E_GLPRT_GORCL(hw->port), 3748266423Sjfv pf->stat_offsets_loaded, 3749266423Sjfv &osd->eth.rx_bytes, &nsd->eth.rx_bytes); 3750270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port), 3751266423Sjfv I40E_GLPRT_GOTCL(hw->port), 3752266423Sjfv pf->stat_offsets_loaded, 3753266423Sjfv &osd->eth.tx_bytes, &nsd->eth.tx_bytes); 3754270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port), 3755266423Sjfv pf->stat_offsets_loaded, 3756266423Sjfv &osd->eth.rx_discards, 3757266423Sjfv &nsd->eth.rx_discards); 3758270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_TDPC(hw->port), 3759266423Sjfv pf->stat_offsets_loaded, 3760266423Sjfv &osd->eth.tx_discards, 3761266423Sjfv &nsd->eth.tx_discards); 3762270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port), 3763266423Sjfv I40E_GLPRT_UPRCL(hw->port), 3764266423Sjfv pf->stat_offsets_loaded, 3765266423Sjfv &osd->eth.rx_unicast, 3766266423Sjfv &nsd->eth.rx_unicast); 3767270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port), 3768266423Sjfv I40E_GLPRT_UPTCL(hw->port), 3769266423Sjfv pf->stat_offsets_loaded, 3770266423Sjfv &osd->eth.tx_unicast, 3771266423Sjfv &nsd->eth.tx_unicast); 3772270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port), 3773266423Sjfv I40E_GLPRT_MPRCL(hw->port), 3774266423Sjfv pf->stat_offsets_loaded, 3775266423Sjfv &osd->eth.rx_multicast, 3776266423Sjfv &nsd->eth.rx_multicast); 3777270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port), 3778266423Sjfv I40E_GLPRT_MPTCL(hw->port), 3779266423Sjfv pf->stat_offsets_loaded, 3780266423Sjfv &osd->eth.tx_multicast, 3781266423Sjfv &nsd->eth.tx_multicast); 3782270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port), 3783266423Sjfv I40E_GLPRT_BPRCL(hw->port), 3784266423Sjfv pf->stat_offsets_loaded, 3785266423Sjfv &osd->eth.rx_broadcast, 3786266423Sjfv &nsd->eth.rx_broadcast); 3787270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port), 3788266423Sjfv I40E_GLPRT_BPTCL(hw->port), 3789266423Sjfv pf->stat_offsets_loaded, 3790266423Sjfv &osd->eth.tx_broadcast, 3791266423Sjfv &nsd->eth.tx_broadcast); 3792266423Sjfv 3793270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port), 3794266423Sjfv pf->stat_offsets_loaded, 3795266423Sjfv &osd->tx_dropped_link_down, 3796266423Sjfv &nsd->tx_dropped_link_down); 3797270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port), 3798266423Sjfv pf->stat_offsets_loaded, 3799266423Sjfv &osd->mac_local_faults, 3800266423Sjfv &nsd->mac_local_faults); 3801270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port), 3802266423Sjfv pf->stat_offsets_loaded, 3803266423Sjfv &osd->mac_remote_faults, 3804266423Sjfv &nsd->mac_remote_faults); 3805270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port), 3806266423Sjfv pf->stat_offsets_loaded, 3807266423Sjfv &osd->rx_length_errors, 3808266423Sjfv &nsd->rx_length_errors); 3809266423Sjfv 3810269198Sjfv /* Flow control (LFC) stats */ 3811270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port), 3812266423Sjfv pf->stat_offsets_loaded, 3813266423Sjfv &osd->link_xon_rx, &nsd->link_xon_rx); 3814270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port), 3815266423Sjfv pf->stat_offsets_loaded, 3816266423Sjfv &osd->link_xon_tx, &nsd->link_xon_tx); 3817270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port), 3818266423Sjfv pf->stat_offsets_loaded, 3819266423Sjfv &osd->link_xoff_rx, &nsd->link_xoff_rx); 3820270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port), 3821266423Sjfv pf->stat_offsets_loaded, 3822266423Sjfv &osd->link_xoff_tx, &nsd->link_xoff_tx); 3823266423Sjfv 3824269198Sjfv /* Priority flow control stats */ 3825266423Sjfv#if 0 3826266423Sjfv for (int i = 0; i < 8; i++) { 3827270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_PXONRXC(hw->port, i), 3828266423Sjfv pf->stat_offsets_loaded, 3829266423Sjfv &osd->priority_xon_rx[i], 3830266423Sjfv &nsd->priority_xon_rx[i]); 3831270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_PXONTXC(hw->port, i), 3832266423Sjfv pf->stat_offsets_loaded, 3833266423Sjfv &osd->priority_xon_tx[i], 3834266423Sjfv &nsd->priority_xon_tx[i]); 3835270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_PXOFFTXC(hw->port, i), 3836266423Sjfv pf->stat_offsets_loaded, 3837266423Sjfv &osd->priority_xoff_tx[i], 3838266423Sjfv &nsd->priority_xoff_tx[i]); 3839270346Sjfv ixl_stat_update32(hw, 3840266423Sjfv I40E_GLPRT_RXON2OFFCNT(hw->port, i), 3841266423Sjfv pf->stat_offsets_loaded, 3842266423Sjfv &osd->priority_xon_2_xoff[i], 3843266423Sjfv &nsd->priority_xon_2_xoff[i]); 3844266423Sjfv } 3845266423Sjfv#endif 3846266423Sjfv 3847269198Sjfv /* Packet size stats rx */ 3848270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port), 3849266423Sjfv I40E_GLPRT_PRC64L(hw->port), 3850266423Sjfv pf->stat_offsets_loaded, 3851266423Sjfv &osd->rx_size_64, &nsd->rx_size_64); 3852270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port), 3853266423Sjfv I40E_GLPRT_PRC127L(hw->port), 3854266423Sjfv pf->stat_offsets_loaded, 3855266423Sjfv &osd->rx_size_127, &nsd->rx_size_127); 3856270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port), 3857266423Sjfv I40E_GLPRT_PRC255L(hw->port), 3858266423Sjfv pf->stat_offsets_loaded, 3859266423Sjfv &osd->rx_size_255, &nsd->rx_size_255); 3860270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port), 3861266423Sjfv I40E_GLPRT_PRC511L(hw->port), 3862266423Sjfv pf->stat_offsets_loaded, 3863266423Sjfv &osd->rx_size_511, &nsd->rx_size_511); 3864270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port), 3865266423Sjfv I40E_GLPRT_PRC1023L(hw->port), 3866266423Sjfv pf->stat_offsets_loaded, 3867266423Sjfv &osd->rx_size_1023, &nsd->rx_size_1023); 3868270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port), 3869266423Sjfv I40E_GLPRT_PRC1522L(hw->port), 3870266423Sjfv pf->stat_offsets_loaded, 3871266423Sjfv &osd->rx_size_1522, &nsd->rx_size_1522); 3872270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port), 3873266423Sjfv I40E_GLPRT_PRC9522L(hw->port), 3874266423Sjfv pf->stat_offsets_loaded, 3875266423Sjfv &osd->rx_size_big, &nsd->rx_size_big); 3876266423Sjfv 3877269198Sjfv /* Packet size stats tx */ 3878270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port), 3879266423Sjfv I40E_GLPRT_PTC64L(hw->port), 3880266423Sjfv pf->stat_offsets_loaded, 3881266423Sjfv &osd->tx_size_64, &nsd->tx_size_64); 3882270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port), 3883266423Sjfv I40E_GLPRT_PTC127L(hw->port), 3884266423Sjfv pf->stat_offsets_loaded, 3885266423Sjfv &osd->tx_size_127, &nsd->tx_size_127); 3886270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port), 3887266423Sjfv I40E_GLPRT_PTC255L(hw->port), 3888266423Sjfv pf->stat_offsets_loaded, 3889266423Sjfv &osd->tx_size_255, &nsd->tx_size_255); 3890270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port), 3891266423Sjfv I40E_GLPRT_PTC511L(hw->port), 3892266423Sjfv pf->stat_offsets_loaded, 3893266423Sjfv &osd->tx_size_511, &nsd->tx_size_511); 3894270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port), 3895266423Sjfv I40E_GLPRT_PTC1023L(hw->port), 3896266423Sjfv pf->stat_offsets_loaded, 3897266423Sjfv &osd->tx_size_1023, &nsd->tx_size_1023); 3898270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port), 3899266423Sjfv I40E_GLPRT_PTC1522L(hw->port), 3900266423Sjfv pf->stat_offsets_loaded, 3901266423Sjfv &osd->tx_size_1522, &nsd->tx_size_1522); 3902270346Sjfv ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port), 3903266423Sjfv I40E_GLPRT_PTC9522L(hw->port), 3904266423Sjfv pf->stat_offsets_loaded, 3905266423Sjfv &osd->tx_size_big, &nsd->tx_size_big); 3906266423Sjfv 3907270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port), 3908266423Sjfv pf->stat_offsets_loaded, 3909266423Sjfv &osd->rx_undersize, &nsd->rx_undersize); 3910270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port), 3911266423Sjfv pf->stat_offsets_loaded, 3912266423Sjfv &osd->rx_fragments, &nsd->rx_fragments); 3913270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port), 3914266423Sjfv pf->stat_offsets_loaded, 3915266423Sjfv &osd->rx_oversize, &nsd->rx_oversize); 3916270346Sjfv ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port), 3917266423Sjfv pf->stat_offsets_loaded, 3918266423Sjfv &osd->rx_jabber, &nsd->rx_jabber); 3919266423Sjfv pf->stat_offsets_loaded = true; 3920269198Sjfv /* End hw stats */ 3921266423Sjfv 3922266423Sjfv /* Update vsi stats */ 3923270346Sjfv ixl_update_eth_stats(vsi); 3924266423Sjfv 3925266423Sjfv /* OS statistics */ 3926269198Sjfv // ERJ - these are per-port, update all vsis? 3927266423Sjfv ifp->if_ierrors = nsd->crc_errors + nsd->illegal_bytes; 3928266423Sjfv} 3929266423Sjfv 3930266423Sjfv/* 3931266423Sjfv** Tasklet handler for MSIX Adminq interrupts 3932266423Sjfv** - do outside interrupt since it might sleep 3933266423Sjfv*/ 3934266423Sjfvstatic void 3935270346Sjfvixl_do_adminq(void *context, int pending) 3936266423Sjfv{ 3937270346Sjfv struct ixl_pf *pf = context; 3938266423Sjfv struct i40e_hw *hw = &pf->hw; 3939270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 3940266423Sjfv struct i40e_arq_event_info event; 3941266423Sjfv i40e_status ret; 3942266423Sjfv u32 reg, loop = 0; 3943266423Sjfv u16 opcode, result; 3944266423Sjfv 3945270346Sjfv event.msg_len = IXL_AQ_BUF_SZ; 3946270346Sjfv event.msg_buf = malloc(event.msg_len, 3947266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 3948266423Sjfv if (!event.msg_buf) { 3949266423Sjfv printf("Unable to allocate adminq memory\n"); 3950266423Sjfv return; 3951266423Sjfv } 3952266423Sjfv 3953266423Sjfv /* clean and process any events */ 3954266423Sjfv do { 3955266423Sjfv ret = i40e_clean_arq_element(hw, &event, &result); 3956266423Sjfv if (ret) 3957266423Sjfv break; 3958266423Sjfv opcode = LE16_TO_CPU(event.desc.opcode); 3959266423Sjfv switch (opcode) { 3960266423Sjfv case i40e_aqc_opc_get_link_status: 3961270346Sjfv vsi->link_up = ixl_config_link(hw); 3962270346Sjfv ixl_update_link_status(pf); 3963266423Sjfv break; 3964266423Sjfv case i40e_aqc_opc_send_msg_to_pf: 3965266423Sjfv /* process pf/vf communication here */ 3966266423Sjfv break; 3967266423Sjfv case i40e_aqc_opc_event_lan_overflow: 3968266423Sjfv break; 3969266423Sjfv default: 3970270346Sjfv#ifdef IXL_DEBUG 3971266423Sjfv printf("AdminQ unknown event %x\n", opcode); 3972266423Sjfv#endif 3973266423Sjfv break; 3974266423Sjfv } 3975266423Sjfv 3976270346Sjfv } while (result && (loop++ < IXL_ADM_LIMIT)); 3977266423Sjfv 3978266423Sjfv reg = rd32(hw, I40E_PFINT_ICR0_ENA); 3979269198Sjfv reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 3980266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 3981266423Sjfv free(event.msg_buf, M_DEVBUF); 3982266423Sjfv 3983266423Sjfv if (pf->msix > 1) 3984270346Sjfv ixl_enable_adminq(&pf->hw); 3985266423Sjfv else 3986270346Sjfv ixl_enable_intr(vsi); 3987266423Sjfv} 3988266423Sjfv 3989266423Sjfvstatic int 3990270346Sjfvixl_debug_info(SYSCTL_HANDLER_ARGS) 3991266423Sjfv{ 3992270346Sjfv struct ixl_pf *pf; 3993266423Sjfv int error, input = 0; 3994266423Sjfv 3995266423Sjfv error = sysctl_handle_int(oidp, &input, 0, req); 3996266423Sjfv 3997266423Sjfv if (error || !req->newptr) 3998266423Sjfv return (error); 3999266423Sjfv 4000266423Sjfv if (input == 1) { 4001270346Sjfv pf = (struct ixl_pf *)arg1; 4002270346Sjfv ixl_print_debug_info(pf); 4003266423Sjfv } 4004266423Sjfv 4005266423Sjfv return (error); 4006266423Sjfv} 4007266423Sjfv 4008266423Sjfvstatic void 4009270346Sjfvixl_print_debug_info(struct ixl_pf *pf) 4010266423Sjfv{ 4011266423Sjfv struct i40e_hw *hw = &pf->hw; 4012270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 4013270346Sjfv struct ixl_queue *que = vsi->queues; 4014266423Sjfv struct rx_ring *rxr = &que->rxr; 4015266423Sjfv struct tx_ring *txr = &que->txr; 4016266423Sjfv u32 reg; 4017266423Sjfv 4018266423Sjfv 4019266423Sjfv printf("Queue irqs = %lx\n", que->irqs); 4020266423Sjfv printf("AdminQ irqs = %lx\n", pf->admin_irq); 4021266423Sjfv printf("RX next check = %x\n", rxr->next_check); 4022266423Sjfv printf("RX not ready = %lx\n", rxr->not_done); 4023266423Sjfv printf("RX packets = %lx\n", rxr->rx_packets); 4024266423Sjfv printf("TX desc avail = %x\n", txr->avail); 4025266423Sjfv 4026266423Sjfv reg = rd32(hw, I40E_GLV_GORCL(0xc)); 4027266423Sjfv printf("RX Bytes = %x\n", reg); 4028266423Sjfv reg = rd32(hw, I40E_GLPRT_GORCL(hw->port)); 4029266423Sjfv printf("Port RX Bytes = %x\n", reg); 4030266423Sjfv reg = rd32(hw, I40E_GLV_RDPC(0xc)); 4031266423Sjfv printf("RX discard = %x\n", reg); 4032266423Sjfv reg = rd32(hw, I40E_GLPRT_RDPC(hw->port)); 4033266423Sjfv printf("Port RX discard = %x\n", reg); 4034266423Sjfv 4035266423Sjfv reg = rd32(hw, I40E_GLV_TEPC(0xc)); 4036266423Sjfv printf("TX errors = %x\n", reg); 4037266423Sjfv reg = rd32(hw, I40E_GLV_GOTCL(0xc)); 4038266423Sjfv printf("TX Bytes = %x\n", reg); 4039266423Sjfv 4040266423Sjfv reg = rd32(hw, I40E_GLPRT_RUC(hw->port)); 4041266423Sjfv printf("RX undersize = %x\n", reg); 4042266423Sjfv reg = rd32(hw, I40E_GLPRT_RFC(hw->port)); 4043266423Sjfv printf("RX fragments = %x\n", reg); 4044266423Sjfv reg = rd32(hw, I40E_GLPRT_ROC(hw->port)); 4045266423Sjfv printf("RX oversize = %x\n", reg); 4046266423Sjfv reg = rd32(hw, I40E_GLPRT_RLEC(hw->port)); 4047266423Sjfv printf("RX length error = %x\n", reg); 4048266423Sjfv reg = rd32(hw, I40E_GLPRT_MRFC(hw->port)); 4049266423Sjfv printf("mac remote fault = %x\n", reg); 4050266423Sjfv reg = rd32(hw, I40E_GLPRT_MLFC(hw->port)); 4051266423Sjfv printf("mac local fault = %x\n", reg); 4052266423Sjfv} 4053266423Sjfv 4054266423Sjfv/** 4055266423Sjfv * Update VSI-specific ethernet statistics counters. 4056266423Sjfv **/ 4057270346Sjfvvoid ixl_update_eth_stats(struct ixl_vsi *vsi) 4058266423Sjfv{ 4059270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)vsi->back; 4060266423Sjfv struct i40e_hw *hw = &pf->hw; 4061269198Sjfv struct ifnet *ifp = vsi->ifp; 4062266423Sjfv struct i40e_eth_stats *es; 4063266423Sjfv struct i40e_eth_stats *oes; 4064266423Sjfv u16 stat_idx = vsi->info.stat_counter_idx; 4065266423Sjfv 4066266423Sjfv es = &vsi->eth_stats; 4067266423Sjfv oes = &vsi->eth_stats_offsets; 4068266423Sjfv 4069266423Sjfv /* Gather up the stats that the hw collects */ 4070270346Sjfv ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx), 4071266423Sjfv vsi->stat_offsets_loaded, 4072266423Sjfv &oes->tx_errors, &es->tx_errors); 4073270346Sjfv ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx), 4074266423Sjfv vsi->stat_offsets_loaded, 4075266423Sjfv &oes->rx_discards, &es->rx_discards); 4076266423Sjfv 4077270346Sjfv ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx), 4078266423Sjfv I40E_GLV_GORCL(stat_idx), 4079266423Sjfv vsi->stat_offsets_loaded, 4080266423Sjfv &oes->rx_bytes, &es->rx_bytes); 4081270346Sjfv ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx), 4082266423Sjfv I40E_GLV_UPRCL(stat_idx), 4083266423Sjfv vsi->stat_offsets_loaded, 4084266423Sjfv &oes->rx_unicast, &es->rx_unicast); 4085270346Sjfv ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx), 4086266423Sjfv I40E_GLV_MPRCL(stat_idx), 4087266423Sjfv vsi->stat_offsets_loaded, 4088266423Sjfv &oes->rx_multicast, &es->rx_multicast); 4089270346Sjfv ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx), 4090266423Sjfv I40E_GLV_BPRCL(stat_idx), 4091266423Sjfv vsi->stat_offsets_loaded, 4092266423Sjfv &oes->rx_broadcast, &es->rx_broadcast); 4093266423Sjfv 4094270346Sjfv ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx), 4095266423Sjfv I40E_GLV_GOTCL(stat_idx), 4096266423Sjfv vsi->stat_offsets_loaded, 4097266423Sjfv &oes->tx_bytes, &es->tx_bytes); 4098270346Sjfv ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx), 4099266423Sjfv I40E_GLV_UPTCL(stat_idx), 4100266423Sjfv vsi->stat_offsets_loaded, 4101266423Sjfv &oes->tx_unicast, &es->tx_unicast); 4102270346Sjfv ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx), 4103266423Sjfv I40E_GLV_MPTCL(stat_idx), 4104266423Sjfv vsi->stat_offsets_loaded, 4105266423Sjfv &oes->tx_multicast, &es->tx_multicast); 4106270346Sjfv ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx), 4107266423Sjfv I40E_GLV_BPTCL(stat_idx), 4108266423Sjfv vsi->stat_offsets_loaded, 4109266423Sjfv &oes->tx_broadcast, &es->tx_broadcast); 4110266423Sjfv vsi->stat_offsets_loaded = true; 4111269198Sjfv 4112269198Sjfv /* Update ifnet stats */ 4113269198Sjfv ifp->if_ipackets = es->rx_unicast + 4114269198Sjfv es->rx_multicast + 4115269198Sjfv es->rx_broadcast; 4116269198Sjfv ifp->if_opackets = es->tx_unicast + 4117269198Sjfv es->tx_multicast + 4118269198Sjfv es->tx_broadcast; 4119269198Sjfv ifp->if_ibytes = es->rx_bytes; 4120269198Sjfv ifp->if_obytes = es->tx_bytes; 4121269198Sjfv ifp->if_imcasts = es->rx_multicast; 4122269198Sjfv ifp->if_omcasts = es->tx_multicast; 4123269198Sjfv 4124269198Sjfv ifp->if_oerrors = es->tx_errors; 4125269198Sjfv ifp->if_iqdrops = es->rx_discards; 4126269198Sjfv ifp->if_noproto = es->rx_unknown_protocol; 4127269198Sjfv ifp->if_collisions = 0; 4128266423Sjfv} 4129266423Sjfv 4130266423Sjfv/** 4131266423Sjfv * Reset all of the stats for the given pf 4132266423Sjfv **/ 4133270346Sjfvvoid ixl_pf_reset_stats(struct ixl_pf *pf) 4134266423Sjfv{ 4135266423Sjfv bzero(&pf->stats, sizeof(struct i40e_hw_port_stats)); 4136266423Sjfv bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats)); 4137266423Sjfv pf->stat_offsets_loaded = false; 4138266423Sjfv} 4139266423Sjfv 4140266423Sjfv/** 4141266423Sjfv * Resets all stats of the given vsi 4142266423Sjfv **/ 4143270346Sjfvvoid ixl_vsi_reset_stats(struct ixl_vsi *vsi) 4144266423Sjfv{ 4145266423Sjfv bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats)); 4146266423Sjfv bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats)); 4147266423Sjfv vsi->stat_offsets_loaded = false; 4148266423Sjfv} 4149266423Sjfv 4150266423Sjfv/** 4151266423Sjfv * Read and update a 48 bit stat from the hw 4152266423Sjfv * 4153266423Sjfv * Since the device stats are not reset at PFReset, they likely will not 4154266423Sjfv * be zeroed when the driver starts. We'll save the first values read 4155266423Sjfv * and use them as offsets to be subtracted from the raw values in order 4156266423Sjfv * to report stats that count from zero. 4157266423Sjfv **/ 4158266423Sjfvstatic void 4159270346Sjfvixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg, 4160266423Sjfv bool offset_loaded, u64 *offset, u64 *stat) 4161266423Sjfv{ 4162266423Sjfv u64 new_data; 4163266423Sjfv 4164266423Sjfv#if __FreeBSD__ >= 10 && __amd64__ 4165266423Sjfv new_data = rd64(hw, loreg); 4166266423Sjfv#else 4167266423Sjfv /* 4168269198Sjfv * Use two rd32's instead of one rd64; FreeBSD versions before 4169266423Sjfv * 10 don't support 8 byte bus reads/writes. 4170266423Sjfv */ 4171266423Sjfv new_data = rd32(hw, loreg); 4172266423Sjfv new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32; 4173266423Sjfv#endif 4174266423Sjfv 4175266423Sjfv if (!offset_loaded) 4176266423Sjfv *offset = new_data; 4177266423Sjfv if (new_data >= *offset) 4178266423Sjfv *stat = new_data - *offset; 4179266423Sjfv else 4180266423Sjfv *stat = (new_data + ((u64)1 << 48)) - *offset; 4181266423Sjfv *stat &= 0xFFFFFFFFFFFFULL; 4182266423Sjfv} 4183266423Sjfv 4184266423Sjfv/** 4185266423Sjfv * Read and update a 32 bit stat from the hw 4186266423Sjfv **/ 4187266423Sjfvstatic void 4188270346Sjfvixl_stat_update32(struct i40e_hw *hw, u32 reg, 4189266423Sjfv bool offset_loaded, u64 *offset, u64 *stat) 4190266423Sjfv{ 4191266423Sjfv u32 new_data; 4192266423Sjfv 4193266423Sjfv new_data = rd32(hw, reg); 4194266423Sjfv if (!offset_loaded) 4195266423Sjfv *offset = new_data; 4196266423Sjfv if (new_data >= *offset) 4197266423Sjfv *stat = (u32)(new_data - *offset); 4198266423Sjfv else 4199266423Sjfv *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); 4200266423Sjfv} 4201266423Sjfv 4202266423Sjfv/* 4203266423Sjfv** Set flow control using sysctl: 4204266423Sjfv** 0 - off 4205266423Sjfv** 1 - rx pause 4206266423Sjfv** 2 - tx pause 4207266423Sjfv** 3 - full 4208266423Sjfv*/ 4209266423Sjfvstatic int 4210270346Sjfvixl_set_flowcntl(SYSCTL_HANDLER_ARGS) 4211266423Sjfv{ 4212266423Sjfv /* 4213266423Sjfv * TODO: ensure flow control is disabled if 4214266423Sjfv * priority flow control is enabled 4215266423Sjfv * 4216266423Sjfv * TODO: ensure tx CRC by hardware should be enabled 4217266423Sjfv * if tx flow control is enabled. 4218266423Sjfv */ 4219270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4220266423Sjfv struct i40e_hw *hw = &pf->hw; 4221266423Sjfv device_t dev = pf->dev; 4222266423Sjfv int requested_fc = 0, error = 0; 4223266423Sjfv enum i40e_status_code aq_error = 0; 4224266423Sjfv u8 fc_aq_err = 0; 4225266423Sjfv 4226269198Sjfv aq_error = i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 4227269198Sjfv if (aq_error) { 4228269198Sjfv device_printf(dev, 4229269198Sjfv "%s: Error retrieving link info from aq, %d\n", 4230269198Sjfv __func__, aq_error); 4231269198Sjfv return (EAGAIN); 4232269198Sjfv } 4233266423Sjfv 4234266423Sjfv /* Read in new mode */ 4235266423Sjfv requested_fc = hw->fc.current_mode; 4236266423Sjfv error = sysctl_handle_int(oidp, &requested_fc, 0, req); 4237266423Sjfv if ((error) || (req->newptr == NULL)) 4238269198Sjfv return (error); 4239266423Sjfv if (requested_fc < 0 || requested_fc > 3) { 4240266423Sjfv device_printf(dev, 4241266423Sjfv "Invalid fc mode; valid modes are 0 through 3\n"); 4242266423Sjfv return (EINVAL); 4243266423Sjfv } 4244266423Sjfv 4245269198Sjfv /* 4246269198Sjfv ** Changing flow control mode currently does not work on 4247269198Sjfv ** 40GBASE-CR4 PHYs 4248269198Sjfv */ 4249269198Sjfv if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4 4250269198Sjfv || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) { 4251269198Sjfv device_printf(dev, "Changing flow control mode unsupported" 4252269198Sjfv " on 40GBase-CR4 media.\n"); 4253269198Sjfv return (ENODEV); 4254269198Sjfv } 4255269198Sjfv 4256266423Sjfv /* Set fc ability for port */ 4257266423Sjfv hw->fc.requested_mode = requested_fc; 4258269198Sjfv aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE); 4259269198Sjfv if (aq_error) { 4260269198Sjfv device_printf(dev, 4261269198Sjfv "%s: Error setting new fc mode %d; fc_err %#x\n", 4262269198Sjfv __func__, aq_error, fc_aq_err); 4263269198Sjfv return (EAGAIN); 4264269198Sjfv } 4265266423Sjfv 4266266423Sjfv if (hw->fc.current_mode != hw->fc.requested_mode) { 4267269198Sjfv device_printf(dev, "%s: FC set failure:\n", __func__); 4268269198Sjfv device_printf(dev, "%s: Current: %s / Requested: %s\n", 4269269198Sjfv __func__, 4270270346Sjfv ixl_fc_string[hw->fc.current_mode], 4271270346Sjfv ixl_fc_string[hw->fc.requested_mode]); 4272266423Sjfv } 4273266423Sjfv 4274269198Sjfv return (0); 4275269198Sjfv} 4276266423Sjfv 4277270346Sjfvstatic int 4278270346Sjfvixl_current_speed(SYSCTL_HANDLER_ARGS) 4279270346Sjfv{ 4280270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4281270346Sjfv struct i40e_hw *hw = &pf->hw; 4282270346Sjfv int error = 0, index = 0; 4283270346Sjfv 4284270346Sjfv char *speeds[] = { 4285270346Sjfv "Unknown", 4286270346Sjfv "100M", 4287270346Sjfv "1G", 4288270346Sjfv "10G", 4289270346Sjfv "40G", 4290270346Sjfv "20G" 4291270346Sjfv }; 4292270346Sjfv 4293270346Sjfv ixl_update_link_status(pf); 4294270346Sjfv 4295270346Sjfv switch (hw->phy.link_info.link_speed) { 4296270346Sjfv case I40E_LINK_SPEED_100MB: 4297270346Sjfv index = 1; 4298270346Sjfv break; 4299270346Sjfv case I40E_LINK_SPEED_1GB: 4300270346Sjfv index = 2; 4301270346Sjfv break; 4302270346Sjfv case I40E_LINK_SPEED_10GB: 4303270346Sjfv index = 3; 4304270346Sjfv break; 4305270346Sjfv case I40E_LINK_SPEED_40GB: 4306270346Sjfv index = 4; 4307270346Sjfv break; 4308270346Sjfv case I40E_LINK_SPEED_20GB: 4309270346Sjfv index = 5; 4310270346Sjfv break; 4311270346Sjfv case I40E_LINK_SPEED_UNKNOWN: 4312270346Sjfv default: 4313270346Sjfv index = 0; 4314270346Sjfv break; 4315270346Sjfv } 4316270346Sjfv 4317270346Sjfv error = sysctl_handle_string(oidp, speeds[index], 4318270346Sjfv strlen(speeds[index]), req); 4319270346Sjfv return (error); 4320270346Sjfv} 4321270346Sjfv 4322269198Sjfv/* 4323269198Sjfv** Control link advertise speed: 4324270346Sjfv** Flags: 4325270346Sjfv** 0x1 - advertise 100 Mb 4326270346Sjfv** 0x2 - advertise 1G 4327270346Sjfv** 0x4 - advertise 10G 4328269198Sjfv** 4329269198Sjfv** Does not work on 40G devices. 4330269198Sjfv*/ 4331269198Sjfvstatic int 4332270346Sjfvixl_set_advertise(SYSCTL_HANDLER_ARGS) 4333269198Sjfv{ 4334270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4335269198Sjfv struct i40e_hw *hw = &pf->hw; 4336269198Sjfv device_t dev = pf->dev; 4337269198Sjfv struct i40e_aq_get_phy_abilities_resp abilities; 4338269198Sjfv struct i40e_aq_set_phy_config config; 4339270346Sjfv int requested_ls = 0; 4340269198Sjfv enum i40e_status_code aq_error = 0; 4341269198Sjfv int error = 0; 4342266423Sjfv 4343269198Sjfv /* 4344269198Sjfv ** FW doesn't support changing advertised speed 4345269198Sjfv ** for 40G devices; speed is always 40G. 4346269198Sjfv */ 4347269198Sjfv if (i40e_is_40G_device(hw->device_id)) 4348269198Sjfv return (ENODEV); 4349266423Sjfv 4350269198Sjfv /* Read in new mode */ 4351270346Sjfv requested_ls = pf->advertised_speed; 4352269198Sjfv error = sysctl_handle_int(oidp, &requested_ls, 0, req); 4353269198Sjfv if ((error) || (req->newptr == NULL)) 4354269198Sjfv return (error); 4355270346Sjfv if (requested_ls < 1 || requested_ls > 7) { 4356269198Sjfv device_printf(dev, 4357270346Sjfv "Invalid advertised speed; valid modes are 0x1 through 0x7\n"); 4358269198Sjfv return (EINVAL); 4359266423Sjfv } 4360269198Sjfv 4361269198Sjfv /* Exit if no change */ 4362270346Sjfv if (pf->advertised_speed == requested_ls) 4363269198Sjfv return (0); 4364269198Sjfv 4365270346Sjfv /* Get current capability information */ 4366270346Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, FALSE, &abilities, NULL); 4367270346Sjfv if (aq_error) { 4368270346Sjfv device_printf(dev, "%s: Error getting phy capabilities %d," 4369270346Sjfv " aq error: %d\n", __func__, aq_error, 4370270346Sjfv hw->aq.asq_last_status); 4371270346Sjfv return (EAGAIN); 4372270346Sjfv } 4373270346Sjfv 4374269198Sjfv /* Prepare new config */ 4375269198Sjfv bzero(&config, sizeof(config)); 4376269198Sjfv config.phy_type = abilities.phy_type; 4377269198Sjfv config.abilities = abilities.abilities 4378269198Sjfv | I40E_AQ_PHY_ENABLE_ATOMIC_LINK; 4379269198Sjfv config.eee_capability = abilities.eee_capability; 4380269198Sjfv config.eeer = abilities.eeer_val; 4381269198Sjfv config.low_power_ctrl = abilities.d3_lpan; 4382269198Sjfv /* Translate into aq cmd link_speed */ 4383270346Sjfv if (requested_ls & 0x4) 4384270346Sjfv config.link_speed |= I40E_LINK_SPEED_10GB; 4385270346Sjfv if (requested_ls & 0x2) 4386270346Sjfv config.link_speed |= I40E_LINK_SPEED_1GB; 4387270346Sjfv if (requested_ls & 0x1) 4388270346Sjfv config.link_speed |= I40E_LINK_SPEED_100MB; 4389269198Sjfv 4390269198Sjfv /* Do aq command & restart link */ 4391269198Sjfv aq_error = i40e_aq_set_phy_config(hw, &config, NULL); 4392269198Sjfv if (aq_error) { 4393269198Sjfv device_printf(dev, "%s: Error setting new phy config %d," 4394269198Sjfv " aq error: %d\n", __func__, aq_error, 4395269198Sjfv hw->aq.asq_last_status); 4396269198Sjfv return (EAGAIN); 4397269198Sjfv } 4398269198Sjfv 4399270346Sjfv pf->advertised_speed = requested_ls; 4400270346Sjfv ixl_update_link_status(pf); 4401269198Sjfv return (0); 4402266423Sjfv} 4403266423Sjfv 4404266423Sjfv/* 4405266423Sjfv** Get the width and transaction speed of 4406266423Sjfv** the bus this adapter is plugged into. 4407266423Sjfv*/ 4408266423Sjfvstatic u16 4409270346Sjfvixl_get_bus_info(struct i40e_hw *hw, device_t dev) 4410266423Sjfv{ 4411266423Sjfv u16 link; 4412266423Sjfv u32 offset; 4413266423Sjfv 4414266423Sjfv 4415266423Sjfv /* Get the PCI Express Capabilities offset */ 4416266423Sjfv pci_find_cap(dev, PCIY_EXPRESS, &offset); 4417266423Sjfv 4418266423Sjfv /* ...and read the Link Status Register */ 4419266423Sjfv link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 4420266423Sjfv 4421266423Sjfv switch (link & I40E_PCI_LINK_WIDTH) { 4422266423Sjfv case I40E_PCI_LINK_WIDTH_1: 4423266423Sjfv hw->bus.width = i40e_bus_width_pcie_x1; 4424266423Sjfv break; 4425266423Sjfv case I40E_PCI_LINK_WIDTH_2: 4426266423Sjfv hw->bus.width = i40e_bus_width_pcie_x2; 4427266423Sjfv break; 4428266423Sjfv case I40E_PCI_LINK_WIDTH_4: 4429266423Sjfv hw->bus.width = i40e_bus_width_pcie_x4; 4430266423Sjfv break; 4431266423Sjfv case I40E_PCI_LINK_WIDTH_8: 4432266423Sjfv hw->bus.width = i40e_bus_width_pcie_x8; 4433266423Sjfv break; 4434266423Sjfv default: 4435266423Sjfv hw->bus.width = i40e_bus_width_unknown; 4436266423Sjfv break; 4437266423Sjfv } 4438266423Sjfv 4439266423Sjfv switch (link & I40E_PCI_LINK_SPEED) { 4440266423Sjfv case I40E_PCI_LINK_SPEED_2500: 4441266423Sjfv hw->bus.speed = i40e_bus_speed_2500; 4442266423Sjfv break; 4443266423Sjfv case I40E_PCI_LINK_SPEED_5000: 4444266423Sjfv hw->bus.speed = i40e_bus_speed_5000; 4445266423Sjfv break; 4446266423Sjfv case I40E_PCI_LINK_SPEED_8000: 4447266423Sjfv hw->bus.speed = i40e_bus_speed_8000; 4448266423Sjfv break; 4449266423Sjfv default: 4450266423Sjfv hw->bus.speed = i40e_bus_speed_unknown; 4451266423Sjfv break; 4452266423Sjfv } 4453266423Sjfv 4454266423Sjfv 4455266423Sjfv device_printf(dev,"PCI Express Bus: Speed %s %s\n", 4456266423Sjfv ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s": 4457266423Sjfv (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s": 4458266423Sjfv (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"), 4459266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" : 4460266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" : 4461266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" : 4462266423Sjfv ("Unknown")); 4463266423Sjfv 4464266423Sjfv if ((hw->bus.width <= i40e_bus_width_pcie_x8) && 4465266423Sjfv (hw->bus.speed < i40e_bus_speed_8000)) { 4466266423Sjfv device_printf(dev, "PCI-Express bandwidth available" 4467266423Sjfv " for this device\n is not sufficient for" 4468266423Sjfv " normal operation.\n"); 4469266423Sjfv device_printf(dev, "For expected performance a x8 " 4470266423Sjfv "PCIE Gen3 slot is required.\n"); 4471266423Sjfv } 4472266423Sjfv 4473266423Sjfv return (link); 4474266423Sjfv} 4475266423Sjfv 4476270346Sjfv#ifdef IXL_DEBUG 4477266423Sjfvstatic int 4478270346Sjfvixl_sysctl_link_status(SYSCTL_HANDLER_ARGS) 4479266423Sjfv{ 4480270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4481266423Sjfv struct i40e_hw *hw = &pf->hw; 4482266423Sjfv struct i40e_link_status link_status; 4483266423Sjfv char buf[512]; 4484266423Sjfv 4485266423Sjfv enum i40e_status_code aq_error = 0; 4486266423Sjfv 4487266423Sjfv aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL); 4488266423Sjfv if (aq_error) { 4489266423Sjfv printf("i40e_aq_get_link_info() error %d\n", aq_error); 4490266423Sjfv return (EPERM); 4491266423Sjfv } 4492266423Sjfv 4493266423Sjfv sprintf(buf, "\n" 4494266423Sjfv "PHY Type : %#04x\n" 4495266423Sjfv "Speed : %#04x\n" 4496266423Sjfv "Link info: %#04x\n" 4497266423Sjfv "AN info : %#04x\n" 4498266423Sjfv "Ext info : %#04x", 4499266423Sjfv link_status.phy_type, link_status.link_speed, 4500266423Sjfv link_status.link_info, link_status.an_info, 4501266423Sjfv link_status.ext_info); 4502266423Sjfv 4503266423Sjfv return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 4504266423Sjfv} 4505266423Sjfv 4506266423Sjfvstatic int 4507270346Sjfvixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS) 4508266423Sjfv{ 4509270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4510266423Sjfv struct i40e_hw *hw = &pf->hw; 4511266423Sjfv struct i40e_aq_get_phy_abilities_resp abilities_resp; 4512266423Sjfv char buf[512]; 4513266423Sjfv 4514266423Sjfv enum i40e_status_code aq_error = 0; 4515266423Sjfv 4516266423Sjfv // TODO: Print out list of qualified modules as well? 4517266423Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, TRUE, FALSE, &abilities_resp, NULL); 4518266423Sjfv if (aq_error) { 4519266423Sjfv printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error); 4520266423Sjfv return (EPERM); 4521266423Sjfv } 4522266423Sjfv 4523266423Sjfv sprintf(buf, "\n" 4524266423Sjfv "PHY Type : %#010x\n" 4525266423Sjfv "Speed : %#04x\n" 4526266423Sjfv "Abilities: %#04x\n" 4527266423Sjfv "EEE cap : %#06x\n" 4528266423Sjfv "EEER reg : %#010x\n" 4529266423Sjfv "D3 Lpan : %#04x", 4530266423Sjfv abilities_resp.phy_type, abilities_resp.link_speed, 4531266423Sjfv abilities_resp.abilities, abilities_resp.eee_capability, 4532266423Sjfv abilities_resp.eeer_val, abilities_resp.d3_lpan); 4533266423Sjfv 4534266423Sjfv return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 4535266423Sjfv} 4536266423Sjfv 4537266423Sjfvstatic int 4538270346Sjfvixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS) 4539266423Sjfv{ 4540270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4541270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 4542270346Sjfv struct ixl_mac_filter *f; 4543266423Sjfv char *buf, *buf_i; 4544266423Sjfv 4545266423Sjfv int error = 0; 4546266423Sjfv int ftl_len = 0; 4547266423Sjfv int ftl_counter = 0; 4548266423Sjfv int buf_len = 0; 4549266423Sjfv int entry_len = 42; 4550266423Sjfv 4551266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 4552266423Sjfv ftl_len++; 4553266423Sjfv } 4554266423Sjfv 4555266423Sjfv if (ftl_len < 1) { 4556266423Sjfv sysctl_handle_string(oidp, "(none)", 6, req); 4557266423Sjfv return (0); 4558266423Sjfv } 4559266423Sjfv 4560266423Sjfv buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2; 4561266423Sjfv buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT); 4562266423Sjfv 4563266423Sjfv sprintf(buf_i++, "\n"); 4564266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 4565266423Sjfv sprintf(buf_i, 4566266423Sjfv MAC_FORMAT ", vlan %4d, flags %#06x", 4567266423Sjfv MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags); 4568266423Sjfv buf_i += entry_len; 4569266423Sjfv /* don't print '\n' for last entry */ 4570266423Sjfv if (++ftl_counter != ftl_len) { 4571266423Sjfv sprintf(buf_i, "\n"); 4572266423Sjfv buf_i++; 4573266423Sjfv } 4574266423Sjfv } 4575266423Sjfv 4576266423Sjfv error = sysctl_handle_string(oidp, buf, strlen(buf), req); 4577266423Sjfv if (error) 4578266423Sjfv printf("sysctl error: %d\n", error); 4579266423Sjfv free(buf, M_DEVBUF); 4580266423Sjfv return error; 4581266423Sjfv} 4582269198Sjfv 4583270346Sjfv#define IXL_SW_RES_SIZE 0x14 4584269198Sjfvstatic int 4585270346Sjfvixl_sysctl_hw_res_info(SYSCTL_HANDLER_ARGS) 4586269198Sjfv{ 4587270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4588269198Sjfv struct i40e_hw *hw = &pf->hw; 4589269198Sjfv device_t dev = pf->dev; 4590269198Sjfv struct sbuf *buf; 4591269198Sjfv int error = 0; 4592269198Sjfv 4593269198Sjfv u8 num_entries; 4594270346Sjfv struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE]; 4595269198Sjfv 4596269198Sjfv buf = sbuf_new_for_sysctl(NULL, NULL, 0, req); 4597269198Sjfv if (!buf) { 4598269198Sjfv device_printf(dev, "Could not allocate sbuf for output.\n"); 4599269198Sjfv return (ENOMEM); 4600269198Sjfv } 4601269198Sjfv 4602269198Sjfv error = i40e_aq_get_switch_resource_alloc(hw, &num_entries, 4603269198Sjfv resp, 4604270346Sjfv IXL_SW_RES_SIZE, 4605269198Sjfv NULL); 4606269198Sjfv if (error) { 4607269198Sjfv device_printf(dev, "%s: get_switch_resource_alloc() error %d, aq error %d\n", 4608269198Sjfv __func__, error, hw->aq.asq_last_status); 4609269198Sjfv sbuf_delete(buf); 4610269198Sjfv return error; 4611269198Sjfv } 4612269198Sjfv device_printf(dev, "Num_entries: %d\n", num_entries); 4613269198Sjfv 4614269198Sjfv sbuf_cat(buf, "\n"); 4615269198Sjfv sbuf_printf(buf, 4616269198Sjfv "Type | Guaranteed | Total | Used | Un-allocated\n" 4617269198Sjfv " | (this) | (all) | (this) | (all) \n"); 4618269198Sjfv for (int i = 0; i < num_entries; i++) { 4619269198Sjfv sbuf_printf(buf, 4620269198Sjfv "%#4x | %10d %5d %6d %12d", 4621269198Sjfv resp[i].resource_type, 4622269198Sjfv resp[i].guaranteed, 4623269198Sjfv resp[i].total, 4624269198Sjfv resp[i].used, 4625269198Sjfv resp[i].total_unalloced); 4626269198Sjfv if (i < num_entries - 1) 4627269198Sjfv sbuf_cat(buf, "\n"); 4628269198Sjfv } 4629269198Sjfv 4630269198Sjfv error = sbuf_finish(buf); 4631269198Sjfv if (error) { 4632269198Sjfv device_printf(dev, "Error finishing sbuf: %d\n", error); 4633269198Sjfv sbuf_delete(buf); 4634269198Sjfv return error; 4635269198Sjfv } 4636269198Sjfv 4637269198Sjfv error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req); 4638269198Sjfv if (error) 4639269198Sjfv device_printf(dev, "sysctl error: %d\n", error); 4640269198Sjfv sbuf_delete(buf); 4641269198Sjfv return error; 4642269198Sjfv 4643269198Sjfv} 4644269198Sjfv 4645269198Sjfv/* 4646269198Sjfv** Dump TX desc given index. 4647269198Sjfv** Doesn't work; don't use. 4648269198Sjfv** TODO: Also needs a queue index input! 4649269198Sjfv**/ 4650269198Sjfvstatic int 4651270346Sjfvixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS) 4652269198Sjfv{ 4653270346Sjfv struct ixl_pf *pf = (struct ixl_pf *)arg1; 4654269198Sjfv device_t dev = pf->dev; 4655269198Sjfv struct sbuf *buf; 4656269198Sjfv int error = 0; 4657269198Sjfv 4658269198Sjfv u16 desc_idx = 0; 4659269198Sjfv 4660269198Sjfv buf = sbuf_new_for_sysctl(NULL, NULL, 0, req); 4661269198Sjfv if (!buf) { 4662269198Sjfv device_printf(dev, "Could not allocate sbuf for output.\n"); 4663269198Sjfv return (ENOMEM); 4664269198Sjfv } 4665269198Sjfv 4666269198Sjfv /* Read in index */ 4667269198Sjfv error = sysctl_handle_int(oidp, &desc_idx, 0, req); 4668269198Sjfv if (error) 4669269198Sjfv return (error); 4670269198Sjfv if (req->newptr == NULL) 4671269198Sjfv return (EIO); // fix 4672269198Sjfv if (desc_idx > 1024) { // fix 4673269198Sjfv device_printf(dev, 4674269198Sjfv "Invalid descriptor index, needs to be < 1024\n"); // fix 4675269198Sjfv return (EINVAL); 4676269198Sjfv } 4677269198Sjfv 4678269198Sjfv // Don't use this sysctl yet 4679269198Sjfv if (TRUE) 4680269198Sjfv return (ENODEV); 4681269198Sjfv 4682269198Sjfv sbuf_cat(buf, "\n"); 4683269198Sjfv 4684269198Sjfv // set to queue 1? 4685270346Sjfv struct ixl_queue *que = pf->vsi.queues; 4686269198Sjfv struct tx_ring *txr = &(que[1].txr); 4687269198Sjfv struct i40e_tx_desc *txd = &txr->base[desc_idx]; 4688269198Sjfv 4689269198Sjfv sbuf_printf(buf, "Que: %d, Desc: %d\n", que->me, desc_idx); 4690269198Sjfv sbuf_printf(buf, "Addr: %#18lx\n", txd->buffer_addr); 4691269198Sjfv sbuf_printf(buf, "Opts: %#18lx\n", txd->cmd_type_offset_bsz); 4692269198Sjfv 4693269198Sjfv error = sbuf_finish(buf); 4694269198Sjfv if (error) { 4695269198Sjfv device_printf(dev, "Error finishing sbuf: %d\n", error); 4696269198Sjfv sbuf_delete(buf); 4697269198Sjfv return error; 4698269198Sjfv } 4699269198Sjfv 4700269198Sjfv error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req); 4701269198Sjfv if (error) 4702269198Sjfv device_printf(dev, "sysctl error: %d\n", error); 4703269198Sjfv sbuf_delete(buf); 4704269198Sjfv return error; 4705269198Sjfv} 4706266423Sjfv#endif 4707266423Sjfv 4708