if_ixl.c revision 266423
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/i40e/if_i40e.c 266423 2014-05-19 01:21:02Z jfv $*/ 34266423Sjfv 35266423Sjfv#include "opt_inet.h" 36266423Sjfv#include "opt_inet6.h" 37266423Sjfv#include "i40e.h" 38266423Sjfv#include "i40e_pf.h" 39266423Sjfv 40266423Sjfv/********************************************************************* 41266423Sjfv * Driver version 42266423Sjfv *********************************************************************/ 43266423Sjfvchar i40e_driver_version[] = "0.6.9 - Beta Release"; 44266423Sjfv 45266423Sjfv/********************************************************************* 46266423Sjfv * PCI Device ID Table 47266423Sjfv * 48266423Sjfv * Used by probe to select devices to load on 49266423Sjfv * Last field stores an index into i40e_strings 50266423Sjfv * Last entry must be all 0s 51266423Sjfv * 52266423Sjfv * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 53266423Sjfv *********************************************************************/ 54266423Sjfv 55266423Sjfvstatic i40e_vendor_info_t i40e_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}, 64266423Sjfv /* required last entry */ 65266423Sjfv {0, 0, 0, 0, 0} 66266423Sjfv}; 67266423Sjfv 68266423Sjfv/********************************************************************* 69266423Sjfv * Table of branding strings 70266423Sjfv *********************************************************************/ 71266423Sjfv 72266423Sjfvstatic char *i40e_strings[] = { 73266423Sjfv "Intel(R) Ethernet Connection XL710 Driver" 74266423Sjfv}; 75266423Sjfv 76266423Sjfv 77266423Sjfv/********************************************************************* 78266423Sjfv * Function prototypes 79266423Sjfv *********************************************************************/ 80266423Sjfvstatic int i40e_probe(device_t); 81266423Sjfvstatic int i40e_attach(device_t); 82266423Sjfvstatic int i40e_detach(device_t); 83266423Sjfvstatic int i40e_shutdown(device_t); 84266423Sjfvstatic int i40e_get_hw_capabilities(struct i40e_pf *); 85266423Sjfvstatic void i40e_cap_txcsum_tso(struct i40e_vsi *, struct ifnet *, int); 86266423Sjfvstatic int i40e_ioctl(struct ifnet *, u_long, caddr_t); 87266423Sjfvstatic void i40e_init(void *); 88266423Sjfvstatic void i40e_init_locked(struct i40e_pf *); 89266423Sjfvstatic void i40e_stop(struct i40e_pf *); 90266423Sjfvstatic void i40e_media_status(struct ifnet *, struct ifmediareq *); 91266423Sjfvstatic int i40e_media_change(struct ifnet *); 92266423Sjfvstatic void i40e_update_link_status(struct i40e_pf *); 93266423Sjfvstatic int i40e_allocate_pci_resources(struct i40e_pf *); 94266423Sjfvstatic u16 i40e_get_bus_info(struct i40e_hw *, device_t); 95266423Sjfvstatic int i40e_setup_stations(struct i40e_pf *); 96266423Sjfvstatic int i40e_setup_vsi(struct i40e_vsi *); 97266423Sjfvstatic int i40e_initialize_vsi(struct i40e_vsi *); 98266423Sjfvstatic int i40e_assign_vsi_msix(struct i40e_pf *); 99266423Sjfvstatic int i40e_assign_vsi_legacy(struct i40e_pf *); 100266423Sjfvstatic int i40e_init_msix(struct i40e_pf *); 101266423Sjfvstatic void i40e_configure_msix(struct i40e_pf *); 102266423Sjfvstatic void i40e_configure_itr(struct i40e_pf *); 103266423Sjfvstatic void i40e_configure_legacy(struct i40e_pf *); 104266423Sjfvstatic void i40e_free_pci_resources(struct i40e_pf *); 105266423Sjfvstatic void i40e_local_timer(void *); 106266423Sjfvstatic int i40e_setup_interface(device_t, struct i40e_vsi *); 107266423Sjfvstatic bool i40e_config_link(struct i40e_hw *); 108266423Sjfvstatic void i40e_config_rss(struct i40e_vsi *); 109266423Sjfvstatic void i40e_set_queue_rx_itr(struct i40e_queue *); 110266423Sjfvstatic void i40e_set_queue_tx_itr(struct i40e_queue *); 111266423Sjfv 112266423Sjfvstatic void i40e_enable_rings(struct i40e_vsi *); 113266423Sjfvstatic void i40e_disable_rings(struct i40e_vsi *); 114266423Sjfvstatic void i40e_enable_intr(struct i40e_vsi *); 115266423Sjfvstatic void i40e_disable_intr(struct i40e_vsi *); 116266423Sjfv 117266423Sjfvstatic void i40e_enable_adminq(struct i40e_hw *); 118266423Sjfvstatic void i40e_disable_adminq(struct i40e_hw *); 119266423Sjfvstatic void i40e_enable_queue(struct i40e_hw *, int); 120266423Sjfvstatic void i40e_disable_queue(struct i40e_hw *, int); 121266423Sjfvstatic void i40e_enable_legacy(struct i40e_hw *); 122266423Sjfvstatic void i40e_disable_legacy(struct i40e_hw *); 123266423Sjfv 124266423Sjfvstatic void i40e_set_promisc(struct i40e_vsi *); 125266423Sjfvstatic void i40e_add_multi(struct i40e_vsi *); 126266423Sjfvstatic void i40e_del_multi(struct i40e_vsi *); 127266423Sjfvstatic void i40e_register_vlan(void *, struct ifnet *, u16); 128266423Sjfvstatic void i40e_unregister_vlan(void *, struct ifnet *, u16); 129266423Sjfvstatic void i40e_setup_vlan_filters(struct i40e_vsi *); 130266423Sjfv 131266423Sjfvstatic void i40e_init_filters(struct i40e_vsi *); 132266423Sjfvstatic void i40e_add_filter(struct i40e_vsi *, u8 *, s16 vlan); 133266423Sjfvstatic void i40e_del_filter(struct i40e_vsi *, u8 *, s16 vlan); 134266423Sjfvstatic void i40e_add_hw_filters(struct i40e_vsi *, int, int); 135266423Sjfvstatic void i40e_del_hw_filters(struct i40e_vsi *, int); 136266423Sjfvstatic struct i40e_mac_filter * 137266423Sjfv i40e_find_filter(struct i40e_vsi *, u8 *, s16); 138266423Sjfvstatic void i40e_add_mc_filter(struct i40e_vsi *, u8 *); 139266423Sjfv 140266423Sjfv/* Sysctl debug interface */ 141266423Sjfvstatic int i40e_debug_info(SYSCTL_HANDLER_ARGS); 142266423Sjfvstatic void i40e_print_debug_info(struct i40e_pf *); 143266423Sjfv 144266423Sjfv/* The MSI/X Interrupt handlers */ 145266423Sjfvstatic void i40e_intr(void *); 146266423Sjfvstatic void i40e_msix_que(void *); 147266423Sjfvstatic void i40e_msix_adminq(void *); 148266423Sjfv 149266423Sjfv/* Deferred interrupt tasklets */ 150266423Sjfvstatic void i40e_do_adminq(void *, int); 151266423Sjfv 152266423Sjfv/* Sysctl handlers */ 153266423Sjfvstatic int i40e_set_flowcntl(SYSCTL_HANDLER_ARGS); 154266423Sjfv 155266423Sjfv/* Statistics */ 156266423Sjfvstatic void i40e_add_hw_stats(struct i40e_pf *); 157266423Sjfvstatic void i40e_add_sysctls_mac_stats(struct sysctl_ctx_list *, 158266423Sjfv struct sysctl_oid_list *, struct i40e_hw_port_stats *); 159266423Sjfvstatic void i40e_add_sysctls_eth_stats(struct sysctl_ctx_list *, 160266423Sjfv struct sysctl_oid_list *, 161266423Sjfv struct i40e_eth_stats *); 162266423Sjfvstatic void i40e_update_stats_counters(struct i40e_pf *); 163266423Sjfvstatic void i40e_update_eth_stats(struct i40e_vsi *); 164266423Sjfvstatic void i40e_pf_reset_stats(struct i40e_pf *); 165266423Sjfvstatic void i40e_vsi_reset_stats(struct i40e_vsi *); 166266423Sjfvstatic void i40e_stat_update48(struct i40e_hw *, u32, u32, bool, 167266423Sjfv u64 *, u64 *); 168266423Sjfvstatic void i40e_stat_update32(struct i40e_hw *, u32, bool, 169266423Sjfv u64 *, u64 *); 170266423Sjfv 171266423Sjfv#ifdef I40E_DEBUG 172266423Sjfvstatic int i40e_sysctl_link_status(SYSCTL_HANDLER_ARGS); 173266423Sjfvstatic int i40e_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS); 174266423Sjfvstatic int i40e_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS); 175266423Sjfv#endif 176266423Sjfv 177266423Sjfv/********************************************************************* 178266423Sjfv * FreeBSD Device Interface Entry Points 179266423Sjfv *********************************************************************/ 180266423Sjfv 181266423Sjfvstatic device_method_t i40e_methods[] = { 182266423Sjfv /* Device interface */ 183266423Sjfv DEVMETHOD(device_probe, i40e_probe), 184266423Sjfv DEVMETHOD(device_attach, i40e_attach), 185266423Sjfv DEVMETHOD(device_detach, i40e_detach), 186266423Sjfv DEVMETHOD(device_shutdown, i40e_shutdown), 187266423Sjfv {0, 0} 188266423Sjfv}; 189266423Sjfv 190266423Sjfvstatic driver_t i40e_driver = { 191266423Sjfv "i40e", i40e_methods, sizeof(struct i40e_pf), 192266423Sjfv}; 193266423Sjfv 194266423Sjfvdevclass_t i40e_devclass; 195266423SjfvDRIVER_MODULE(i40e, pci, i40e_driver, i40e_devclass, 0, 0); 196266423Sjfv 197266423SjfvMODULE_DEPEND(i40e, pci, 1, 1, 1); 198266423SjfvMODULE_DEPEND(i40e, ether, 1, 1, 1); 199266423Sjfv 200266423Sjfv/* 201266423Sjfv * MSIX should be the default for best performance, 202266423Sjfv * but this allows it to be forced off for testing. 203266423Sjfv */ 204266423Sjfvstatic int i40e_enable_msix = 1; 205266423SjfvTUNABLE_INT("hw.i40e.enable_msix", &i40e_enable_msix); 206266423Sjfv 207266423Sjfv/* 208266423Sjfv** Number of descriptors per ring: 209266423Sjfv** - TX and RX are the same size 210266423Sjfv*/ 211266423Sjfvstatic int i40e_ringsz = DEFAULT_RING; 212266423SjfvTUNABLE_INT("hw.i40e.ringsz", &i40e_ringsz); 213266423Sjfv 214266423Sjfv/* 215266423Sjfv** This can be set manually, if left as 0 the 216266423Sjfv** number of queues will be calculated based 217266423Sjfv** on cpus and msix vectors available. 218266423Sjfv*/ 219266423Sjfvint i40e_max_queues = 0; 220266423SjfvTUNABLE_INT("hw.i40e.max_queues", &i40e_max_queues); 221266423Sjfv 222266423Sjfv/* 223266423Sjfv** Controls for Interrupt Throttling 224266423Sjfv** - true/false for dynamic adjustment 225266423Sjfv** - default values for static ITR 226266423Sjfv*/ 227266423Sjfvint i40e_dynamic_rx_itr = 0; 228266423SjfvTUNABLE_INT("hw.i40e.dynamic_rx_itr", &i40e_dynamic_rx_itr); 229266423Sjfvint i40e_dynamic_tx_itr = 0; 230266423SjfvTUNABLE_INT("hw.i40e.dynamic_tx_itr", &i40e_dynamic_tx_itr); 231266423Sjfv 232266423Sjfvint i40e_rx_itr = I40E_ITR_8K; 233266423SjfvTUNABLE_INT("hw.i40e.rx_itr", &i40e_rx_itr); 234266423Sjfvint i40e_tx_itr = I40E_ITR_4K; 235266423SjfvTUNABLE_INT("hw.i40e.tx_itr", &i40e_tx_itr); 236266423Sjfv 237266423Sjfv#ifdef I40E_FDIR 238266423Sjfvstatic int i40e_enable_fdir = 1; 239266423SjfvTUNABLE_INT("hw.i40e.enable_fdir", &i40e_enable_fdir); 240266423Sjfv/* Rate at which we sample */ 241266423Sjfvint i40e_atr_rate = 20; 242266423SjfvTUNABLE_INT("hw.i40e.atr_rate", &i40e_atr_rate); 243266423Sjfv#endif 244266423Sjfv 245266423Sjfv 246266423Sjfvstatic char *i40e_fc_string[6] = { 247266423Sjfv "None", 248266423Sjfv "Rx", 249266423Sjfv "Tx", 250266423Sjfv "Full", 251266423Sjfv "Priority", 252266423Sjfv "Default" 253266423Sjfv}; 254266423Sjfv 255266423Sjfv/********************************************************************* 256266423Sjfv * Device identification routine 257266423Sjfv * 258266423Sjfv * i40e_probe determines if the driver should be loaded on 259266423Sjfv * the hardware based on PCI vendor/device id of the device. 260266423Sjfv * 261266423Sjfv * return BUS_PROBE_DEFAULT on success, positive on failure 262266423Sjfv *********************************************************************/ 263266423Sjfv 264266423Sjfvstatic int 265266423Sjfvi40e_probe(device_t dev) 266266423Sjfv{ 267266423Sjfv i40e_vendor_info_t *ent; 268266423Sjfv 269266423Sjfv u16 pci_vendor_id, pci_device_id; 270266423Sjfv u16 pci_subvendor_id, pci_subdevice_id; 271266423Sjfv char device_name[256]; 272266423Sjfv 273266423Sjfv INIT_DEBUGOUT("i40e_probe: begin"); 274266423Sjfv 275266423Sjfv pci_vendor_id = pci_get_vendor(dev); 276266423Sjfv if (pci_vendor_id != I40E_INTEL_VENDOR_ID) 277266423Sjfv return (ENXIO); 278266423Sjfv 279266423Sjfv pci_device_id = pci_get_device(dev); 280266423Sjfv pci_subvendor_id = pci_get_subvendor(dev); 281266423Sjfv pci_subdevice_id = pci_get_subdevice(dev); 282266423Sjfv 283266423Sjfv ent = i40e_vendor_info_array; 284266423Sjfv while (ent->vendor_id != 0) { 285266423Sjfv if ((pci_vendor_id == ent->vendor_id) && 286266423Sjfv (pci_device_id == ent->device_id) && 287266423Sjfv 288266423Sjfv ((pci_subvendor_id == ent->subvendor_id) || 289266423Sjfv (ent->subvendor_id == 0)) && 290266423Sjfv 291266423Sjfv ((pci_subdevice_id == ent->subdevice_id) || 292266423Sjfv (ent->subdevice_id == 0))) { 293266423Sjfv sprintf(device_name, "%s, Version - %s", 294266423Sjfv i40e_strings[ent->index], 295266423Sjfv i40e_driver_version); 296266423Sjfv device_set_desc_copy(dev, device_name); 297266423Sjfv return (BUS_PROBE_DEFAULT); 298266423Sjfv } 299266423Sjfv ent++; 300266423Sjfv } 301266423Sjfv return (ENXIO); 302266423Sjfv} 303266423Sjfv 304266423Sjfv/********************************************************************* 305266423Sjfv * Device initialization routine 306266423Sjfv * 307266423Sjfv * The attach entry point is called when the driver is being loaded. 308266423Sjfv * This routine identifies the type of hardware, allocates all resources 309266423Sjfv * and initializes the hardware. 310266423Sjfv * 311266423Sjfv * return 0 on success, positive on failure 312266423Sjfv *********************************************************************/ 313266423Sjfv 314266423Sjfvstatic int 315266423Sjfvi40e_attach(device_t dev) 316266423Sjfv{ 317266423Sjfv struct i40e_pf *pf; 318266423Sjfv struct i40e_hw *hw; 319266423Sjfv struct i40e_vsi *vsi; 320266423Sjfv u16 bus; 321266423Sjfv u32 reg; 322266423Sjfv int error = 0; 323266423Sjfv 324266423Sjfv INIT_DEBUGOUT("i40e_attach: begin"); 325266423Sjfv 326266423Sjfv /* Allocate, clear, and link in our primary soft structure */ 327266423Sjfv pf = device_get_softc(dev); 328266423Sjfv pf->dev = pf->osdep.dev = dev; 329266423Sjfv hw = &pf->hw; 330266423Sjfv 331266423Sjfv /* 332266423Sjfv ** Note this assumes we have a single embedded VSI, 333266423Sjfv ** this could be enhanced later to allocate multiple 334266423Sjfv */ 335266423Sjfv vsi = &pf->vsi; 336266423Sjfv vsi->dev = pf->dev; 337266423Sjfv 338266423Sjfv /* Core Lock Init*/ 339266423Sjfv I40E_PF_LOCK_INIT(pf, device_get_nameunit(dev)); 340266423Sjfv 341266423Sjfv /* Set up the timer callout */ 342266423Sjfv callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); 343266423Sjfv 344266423Sjfv /* Set up sysctls */ 345266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 346266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 347266423Sjfv OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, 348266423Sjfv pf, 0, i40e_set_flowcntl, "I", "Flow Control"); 349266423Sjfv 350266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 351266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 352266423Sjfv OID_AUTO, "rx_itr", CTLTYPE_INT | CTLFLAG_RW, 353266423Sjfv &i40e_rx_itr, I40E_ITR_8K, "RX ITR"); 354266423Sjfv 355266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 356266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 357266423Sjfv OID_AUTO, "dynamic_rx_itr", CTLTYPE_INT | CTLFLAG_RW, 358266423Sjfv &i40e_dynamic_rx_itr, 0, "Dynamic RX ITR"); 359266423Sjfv 360266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 361266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 362266423Sjfv OID_AUTO, "tx_itr", CTLTYPE_INT | CTLFLAG_RW, 363266423Sjfv &i40e_tx_itr, I40E_ITR_4K, "TX ITR"); 364266423Sjfv 365266423Sjfv SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 366266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 367266423Sjfv OID_AUTO, "dynamic_tx_itr", CTLTYPE_INT | CTLFLAG_RW, 368266423Sjfv &i40e_dynamic_tx_itr, 0, "Dynamic TX ITR"); 369266423Sjfv 370266423Sjfv#ifdef I40E_DEBUG 371266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 372266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 373266423Sjfv OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD, 374266423Sjfv pf, 0, i40e_sysctl_link_status, "A", "Current Link Status"); 375266423Sjfv 376266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 377266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 378266423Sjfv OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD, 379266423Sjfv pf, 0, i40e_sysctl_phy_abilities, "A", "PHY Abilities"); 380266423Sjfv 381266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 382266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 383266423Sjfv OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD, 384266423Sjfv pf, 0, i40e_sysctl_sw_filter_list, "A", "SW Filter List"); 385266423Sjfv#endif 386266423Sjfv 387266423Sjfv /* Save off the information about this board */ 388266423Sjfv hw->vendor_id = pci_get_vendor(dev); 389266423Sjfv hw->device_id = pci_get_device(dev); 390266423Sjfv hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 391266423Sjfv hw->subsystem_vendor_id = 392266423Sjfv pci_read_config(dev, PCIR_SUBVEND_0, 2); 393266423Sjfv hw->subsystem_device_id = 394266423Sjfv pci_read_config(dev, PCIR_SUBDEV_0, 2); 395266423Sjfv 396266423Sjfv hw->bus.device = pci_get_device(dev); 397266423Sjfv hw->bus.func = pci_get_function(dev); 398266423Sjfv 399266423Sjfv /* Do PCI setup - map BAR0, etc */ 400266423Sjfv if (i40e_allocate_pci_resources(pf)) { 401266423Sjfv device_printf(dev, "Allocation of PCI resources failed\n"); 402266423Sjfv error = ENXIO; 403266423Sjfv goto err_out; 404266423Sjfv } 405266423Sjfv 406266423Sjfv /* Create for initial debugging use */ 407266423Sjfv SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 408266423Sjfv SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 409266423Sjfv OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0, 410266423Sjfv i40e_debug_info, "I", "Debug Information"); 411266423Sjfv 412266423Sjfv /* Workaround to keep ARI detection off */ 413266423Sjfv reg = rd32(hw, I40E_GLPCI_CAPSUP); 414266423Sjfv reg &= ~I40E_GLPCI_CAPSUP_ARI_EN_MASK; 415266423Sjfv wr32(hw, I40E_GLPCI_CAPSUP, reg); 416266423Sjfv 417266423Sjfv /* Establish a clean starting point */ 418266423Sjfv error = i40e_pf_reset(hw); 419266423Sjfv if (error) { 420266423Sjfv // TODO: Remove EMPR reset 421266423Sjfv /* Use the heavy hammer, force a firmware reset */ 422266423Sjfv reg = rd32(&pf->hw, I40E_GLGEN_RSTENA_EMP); 423266423Sjfv reg |= I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_MASK; 424266423Sjfv wr32(&pf->hw, I40E_GLGEN_RSTENA_EMP, reg); 425266423Sjfv /* force the reset */ 426266423Sjfv reg = rd32(&pf->hw, I40E_GLGEN_RTRIG); 427266423Sjfv reg |= I40E_GLGEN_RTRIG_EMPFWR_MASK; 428266423Sjfv wr32(&pf->hw, I40E_GLGEN_RTRIG, reg); 429266423Sjfv i40e_flush(hw); 430266423Sjfv 431266423Sjfv error = i40e_pf_reset(hw); 432266423Sjfv if (error) { 433266423Sjfv device_printf(dev,"PF reset failure %x\n", error); 434266423Sjfv error = EIO; 435266423Sjfv goto err_out; 436266423Sjfv } 437266423Sjfv } 438266423Sjfv 439266423Sjfv /* Set admin queue parameters */ 440266423Sjfv hw->aq.num_arq_entries = I40E_AQ_LEN; 441266423Sjfv hw->aq.num_asq_entries = I40E_AQ_LEN; 442266423Sjfv hw->aq.arq_buf_size = I40E_AQ_BUFSZ; 443266423Sjfv hw->aq.asq_buf_size = I40E_AQ_BUFSZ; 444266423Sjfv 445266423Sjfv /* Initialize the shared code */ 446266423Sjfv error = i40e_init_shared_code(hw); 447266423Sjfv if (error) { 448266423Sjfv device_printf(dev,"Unable to initialize the shared code\n"); 449266423Sjfv error = EIO; 450266423Sjfv goto err_out; 451266423Sjfv } 452266423Sjfv 453266423Sjfv /* Set up the admin queue */ 454266423Sjfv error = i40e_init_adminq(hw); 455266423Sjfv if (error) { 456266423Sjfv device_printf(dev, "Admin Queue setup failure!\n"); 457266423Sjfv goto err_out; 458266423Sjfv } 459266423Sjfv 460266423Sjfv#ifdef I40E_DEBUG 461266423Sjfv device_printf(dev,"Firmware version: %d.%d " 462266423Sjfv "API version %d.%d NVM track %x version %x\n", 463266423Sjfv hw->aq.fw_maj_ver, hw->aq.fw_min_ver, 464266423Sjfv hw->aq.api_maj_ver, hw->aq.api_min_ver, 465266423Sjfv hw->nvm.eetrack, hw->nvm.version); 466266423Sjfv#endif 467266423Sjfv 468266423Sjfv /* Clear PXE mode */ 469266423Sjfv i40e_clear_pxe_mode(hw); 470266423Sjfv 471266423Sjfv /* Get capabilities from the device */ 472266423Sjfv error = i40e_get_hw_capabilities(pf); 473266423Sjfv if (error) { 474266423Sjfv device_printf(dev, "HW capabilities failure!\n"); 475266423Sjfv goto err_get_cap; 476266423Sjfv } 477266423Sjfv 478266423Sjfv /* Set up host memory cache */ 479266423Sjfv error = i40e_init_lan_hmc(hw, vsi->num_queues, vsi->num_queues, 0, 0); 480266423Sjfv if (error) { 481266423Sjfv device_printf(dev, "init_lan_hmc failed: %d\n", error); 482266423Sjfv goto err_get_cap; 483266423Sjfv } 484266423Sjfv 485266423Sjfv error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 486266423Sjfv if (error) { 487266423Sjfv device_printf(dev, "configure_lan_hmc failed: %d\n", error); 488266423Sjfv goto err_mac_hmc; 489266423Sjfv } 490266423Sjfv 491266423Sjfv i40e_get_mac_addr(hw, hw->mac.addr); 492266423Sjfv error = i40e_validate_mac_addr(hw->mac.addr); 493266423Sjfv if (error) { 494266423Sjfv device_printf(dev, "validate_mac_addr failed: %d\n", error); 495266423Sjfv goto err_mac_hmc; 496266423Sjfv } 497266423Sjfv bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 498266423Sjfv i40e_get_port_mac_addr(hw, hw->mac.port_addr); 499266423Sjfv 500266423Sjfv if (i40e_setup_stations(pf) != 0) { 501266423Sjfv device_printf(dev, "setup stations failed!\n"); 502266423Sjfv error = ENOMEM; 503266423Sjfv goto err_mac_hmc; 504266423Sjfv } 505266423Sjfv 506266423Sjfv /* Initialize mac filter list for VSI */ 507266423Sjfv SLIST_INIT(&vsi->ftl); 508266423Sjfv 509266423Sjfv /* Set up interrupt routing here */ 510266423Sjfv if (pf->msix > 1) 511266423Sjfv error = i40e_assign_vsi_msix(pf); 512266423Sjfv else 513266423Sjfv error = i40e_assign_vsi_legacy(pf); 514266423Sjfv if (error) 515266423Sjfv goto err_late; 516266423Sjfv 517266423Sjfv /* Determine link state */ 518266423Sjfv vsi->link_up = i40e_config_link(hw); 519266423Sjfv 520266423Sjfv /* Setup OS specific network interface */ 521266423Sjfv if (i40e_setup_interface(dev, vsi) != 0) 522266423Sjfv goto err_late; 523266423Sjfv 524266423Sjfv /* Get the bus configuration and set the shared code */ 525266423Sjfv bus = i40e_get_bus_info(hw, dev); 526266423Sjfv i40e_set_pci_config_data(hw, bus); 527266423Sjfv 528266423Sjfv /* Initialize statistics */ 529266423Sjfv i40e_pf_reset_stats(pf); 530266423Sjfv i40e_update_stats_counters(pf); 531266423Sjfv i40e_add_hw_stats(pf); 532266423Sjfv 533266423Sjfv /* Register for VLAN events */ 534266423Sjfv vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 535266423Sjfv i40e_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); 536266423Sjfv vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 537266423Sjfv i40e_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); 538266423Sjfv 539266423Sjfv INIT_DEBUGOUT("i40e_attach: end"); 540266423Sjfv return (0); 541266423Sjfv 542266423Sjfverr_late: 543266423Sjfv i40e_free_vsi(vsi); 544266423Sjfverr_mac_hmc: 545266423Sjfv i40e_shutdown_lan_hmc(hw); 546266423Sjfverr_get_cap: 547266423Sjfv i40e_shutdown_adminq(hw); 548266423Sjfverr_out: 549266423Sjfv if (vsi->ifp != NULL) 550266423Sjfv if_free(vsi->ifp); 551266423Sjfv i40e_free_pci_resources(pf); 552266423Sjfv I40E_PF_LOCK_DESTROY(pf); 553266423Sjfv return (error); 554266423Sjfv} 555266423Sjfv 556266423Sjfv/********************************************************************* 557266423Sjfv * Device removal routine 558266423Sjfv * 559266423Sjfv * The detach entry point is called when the driver is being removed. 560266423Sjfv * This routine stops the adapter and deallocates all the resources 561266423Sjfv * that were allocated for driver operation. 562266423Sjfv * 563266423Sjfv * return 0 on success, positive on failure 564266423Sjfv *********************************************************************/ 565266423Sjfv 566266423Sjfvstatic int 567266423Sjfvi40e_detach(device_t dev) 568266423Sjfv{ 569266423Sjfv struct i40e_pf *pf = device_get_softc(dev); 570266423Sjfv struct i40e_hw *hw = &pf->hw; 571266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 572266423Sjfv struct i40e_queue *que = vsi->queues; 573266423Sjfv i40e_status status; 574266423Sjfv u32 reg; 575266423Sjfv 576266423Sjfv INIT_DEBUGOUT("i40e_detach: begin"); 577266423Sjfv 578266423Sjfv /* Make sure VLANS are not using driver */ 579266423Sjfv if (vsi->ifp->if_vlantrunk != NULL) { 580266423Sjfv device_printf(dev,"Vlan in use, detach first\n"); 581266423Sjfv return (EBUSY); 582266423Sjfv } 583266423Sjfv 584266423Sjfv I40E_PF_LOCK(pf); 585266423Sjfv i40e_stop(pf); 586266423Sjfv I40E_PF_UNLOCK(pf); 587266423Sjfv 588266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 589266423Sjfv if (que->tq) { 590266423Sjfv taskqueue_drain(que->tq, &que->task); 591266423Sjfv taskqueue_drain(que->tq, &que->tx_task); 592266423Sjfv taskqueue_free(que->tq); 593266423Sjfv } 594266423Sjfv } 595266423Sjfv 596266423Sjfv /* Drain other tasks here */ 597266423Sjfv 598266423Sjfv /* Shutdown LAN HMC */ 599266423Sjfv status = i40e_shutdown_lan_hmc(hw); 600266423Sjfv if (status) 601266423Sjfv device_printf(dev, 602266423Sjfv "Shutdown LAN HMC failed with code %d\n", status); 603266423Sjfv 604266423Sjfv /* Shutdown admin queue */ 605266423Sjfv status = i40e_shutdown_adminq(hw); 606266423Sjfv if (status) 607266423Sjfv device_printf(dev, 608266423Sjfv "Shutdown Admin queue failed with code %d\n", status); 609266423Sjfv 610266423Sjfv /* Now force a pf reset */ 611266423Sjfv reg = rd32(hw, I40E_PFGEN_CTRL); 612266423Sjfv reg |= I40E_PFGEN_CTRL_PFSWR_MASK; 613266423Sjfv wr32(hw, I40E_PFGEN_CTRL, reg); 614266423Sjfv //i40e_pf_reset(hw); 615266423Sjfv i40e_flush(hw); 616266423Sjfv 617266423Sjfv /* Unregister VLAN events */ 618266423Sjfv if (vsi->vlan_attach != NULL) 619266423Sjfv EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); 620266423Sjfv if (vsi->vlan_detach != NULL) 621266423Sjfv EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); 622266423Sjfv 623266423Sjfv ether_ifdetach(vsi->ifp); 624266423Sjfv callout_drain(&pf->timer); 625266423Sjfv 626266423Sjfv 627266423Sjfv i40e_free_pci_resources(pf); 628266423Sjfv bus_generic_detach(dev); 629266423Sjfv if_free(vsi->ifp); 630266423Sjfv i40e_free_vsi(vsi); 631266423Sjfv I40E_PF_LOCK_DESTROY(pf); 632266423Sjfv return (0); 633266423Sjfv} 634266423Sjfv 635266423Sjfv/********************************************************************* 636266423Sjfv * 637266423Sjfv * Shutdown entry point 638266423Sjfv * 639266423Sjfv **********************************************************************/ 640266423Sjfv 641266423Sjfvstatic int 642266423Sjfvi40e_shutdown(device_t dev) 643266423Sjfv{ 644266423Sjfv struct i40e_pf *pf = device_get_softc(dev); 645266423Sjfv I40E_PF_LOCK(pf); 646266423Sjfv i40e_stop(pf); 647266423Sjfv I40E_PF_UNLOCK(pf); 648266423Sjfv return (0); 649266423Sjfv} 650266423Sjfv 651266423Sjfv 652266423Sjfv/********************************************************************* 653266423Sjfv * 654266423Sjfv * Get the hardware capabilities 655266423Sjfv * 656266423Sjfv **********************************************************************/ 657266423Sjfv 658266423Sjfvstatic int 659266423Sjfvi40e_get_hw_capabilities(struct i40e_pf *pf) 660266423Sjfv{ 661266423Sjfv struct i40e_aqc_list_capabilities_element_resp *buf; 662266423Sjfv struct i40e_hw *hw = &pf->hw; 663266423Sjfv device_t dev = pf->dev; 664266423Sjfv int error, len; 665266423Sjfv u16 needed; 666266423Sjfv bool again = TRUE; 667266423Sjfv 668266423Sjfv len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); 669266423Sjfvretry: 670266423Sjfv if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *) 671266423Sjfv malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) { 672266423Sjfv device_printf(dev, "Unable to allocate cap memory\n"); 673266423Sjfv return (ENOMEM); 674266423Sjfv } 675266423Sjfv 676266423Sjfv /* This populates the hw struct */ 677266423Sjfv error = i40e_aq_discover_capabilities(hw, buf, len, 678266423Sjfv &needed, i40e_aqc_opc_list_func_capabilities, NULL); 679266423Sjfv free(buf, M_DEVBUF); 680266423Sjfv if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && 681266423Sjfv (again == TRUE)) { 682266423Sjfv /* retry once with a larger buffer */ 683266423Sjfv again = FALSE; 684266423Sjfv len = needed; 685266423Sjfv goto retry; 686266423Sjfv } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { 687266423Sjfv device_printf(dev, "capability discovery failed: %d\n", 688266423Sjfv pf->hw.aq.asq_last_status); 689266423Sjfv return (ENODEV); 690266423Sjfv } 691266423Sjfv 692266423Sjfv /* Capture this PF's starting queue pair */ 693266423Sjfv pf->qbase = hw->func_caps.base_queue; 694266423Sjfv 695266423Sjfv#ifdef I40E_DEBUG 696266423Sjfv device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, " 697266423Sjfv "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", 698266423Sjfv hw->pf_id, hw->func_caps.num_vfs, 699266423Sjfv hw->func_caps.num_msix_vectors, 700266423Sjfv hw->func_caps.num_msix_vectors_vf, 701266423Sjfv hw->func_caps.fd_filters_guaranteed, 702266423Sjfv hw->func_caps.fd_filters_best_effort, 703266423Sjfv hw->func_caps.num_tx_qp, 704266423Sjfv hw->func_caps.num_rx_qp, 705266423Sjfv hw->func_caps.base_queue); 706266423Sjfv#endif 707266423Sjfv return (error); 708266423Sjfv} 709266423Sjfv 710266423Sjfvstatic void 711266423Sjfvi40e_cap_txcsum_tso(struct i40e_vsi *vsi, struct ifnet *ifp, int mask) 712266423Sjfv{ 713266423Sjfv device_t dev = vsi->dev; 714266423Sjfv 715266423Sjfv /* Enable/disable TXCSUM/TSO4 */ 716266423Sjfv if (!(ifp->if_capenable & IFCAP_TXCSUM) 717266423Sjfv && !(ifp->if_capenable & IFCAP_TSO4)) { 718266423Sjfv if (mask & IFCAP_TXCSUM) { 719266423Sjfv ifp->if_capenable |= IFCAP_TXCSUM; 720266423Sjfv /* enable TXCSUM, restore TSO if previously enabled */ 721266423Sjfv if (vsi->flags & I40E_FLAGS_KEEP_TSO4) { 722266423Sjfv vsi->flags &= ~I40E_FLAGS_KEEP_TSO4; 723266423Sjfv ifp->if_capenable |= IFCAP_TSO4; 724266423Sjfv } 725266423Sjfv } 726266423Sjfv else if (mask & IFCAP_TSO4) { 727266423Sjfv ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); 728266423Sjfv vsi->flags &= ~I40E_FLAGS_KEEP_TSO4; 729266423Sjfv device_printf(dev, 730266423Sjfv "TSO4 requires txcsum, enabling both...\n"); 731266423Sjfv } 732266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM) 733266423Sjfv && !(ifp->if_capenable & IFCAP_TSO4)) { 734266423Sjfv if (mask & IFCAP_TXCSUM) 735266423Sjfv ifp->if_capenable &= ~IFCAP_TXCSUM; 736266423Sjfv else if (mask & IFCAP_TSO4) 737266423Sjfv ifp->if_capenable |= IFCAP_TSO4; 738266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM) 739266423Sjfv && (ifp->if_capenable & IFCAP_TSO4)) { 740266423Sjfv if (mask & IFCAP_TXCSUM) { 741266423Sjfv vsi->flags |= I40E_FLAGS_KEEP_TSO4; 742266423Sjfv ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); 743266423Sjfv device_printf(dev, 744266423Sjfv "TSO4 requires txcsum, disabling both...\n"); 745266423Sjfv } else if (mask & IFCAP_TSO4) 746266423Sjfv ifp->if_capenable &= ~IFCAP_TSO4; 747266423Sjfv } 748266423Sjfv 749266423Sjfv /* Enable/disable TXCSUM_IPV6/TSO6 */ 750266423Sjfv if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) 751266423Sjfv && !(ifp->if_capenable & IFCAP_TSO6)) { 752266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) { 753266423Sjfv ifp->if_capenable |= IFCAP_TXCSUM_IPV6; 754266423Sjfv if (vsi->flags & I40E_FLAGS_KEEP_TSO6) { 755266423Sjfv vsi->flags &= ~I40E_FLAGS_KEEP_TSO6; 756266423Sjfv ifp->if_capenable |= IFCAP_TSO6; 757266423Sjfv } 758266423Sjfv } else if (mask & IFCAP_TSO6) { 759266423Sjfv ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 760266423Sjfv vsi->flags &= ~I40E_FLAGS_KEEP_TSO6; 761266423Sjfv device_printf(dev, 762266423Sjfv "TSO6 requires txcsum6, enabling both...\n"); 763266423Sjfv } 764266423Sjfv } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 765266423Sjfv && !(ifp->if_capenable & IFCAP_TSO6)) { 766266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) 767266423Sjfv ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; 768266423Sjfv else if (mask & IFCAP_TSO6) 769266423Sjfv ifp->if_capenable |= IFCAP_TSO6; 770266423Sjfv } else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6) 771266423Sjfv && (ifp->if_capenable & IFCAP_TSO6)) { 772266423Sjfv if (mask & IFCAP_TXCSUM_IPV6) { 773266423Sjfv vsi->flags |= I40E_FLAGS_KEEP_TSO6; 774266423Sjfv ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); 775266423Sjfv device_printf(dev, 776266423Sjfv "TSO6 requires txcsum6, disabling both...\n"); 777266423Sjfv } else if (mask & IFCAP_TSO6) 778266423Sjfv ifp->if_capenable &= ~IFCAP_TSO6; 779266423Sjfv } 780266423Sjfv} 781266423Sjfv 782266423Sjfv/********************************************************************* 783266423Sjfv * Ioctl entry point 784266423Sjfv * 785266423Sjfv * i40e_ioctl is called when the user wants to configure the 786266423Sjfv * interface. 787266423Sjfv * 788266423Sjfv * return 0 on success, positive on failure 789266423Sjfv **********************************************************************/ 790266423Sjfv 791266423Sjfvstatic int 792266423Sjfvi40e_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 793266423Sjfv{ 794266423Sjfv struct i40e_vsi *vsi = ifp->if_softc; 795266423Sjfv struct i40e_pf *pf = (struct i40e_pf *)vsi->back; 796266423Sjfv struct ifreq *ifr = (struct ifreq *) data; 797266423Sjfv#if defined(INET) || defined(INET6) 798266423Sjfv struct ifaddr *ifa = (struct ifaddr *)data; 799266423Sjfv bool avoid_reset = FALSE; 800266423Sjfv#endif 801266423Sjfv int error = 0; 802266423Sjfv 803266423Sjfv switch (command) { 804266423Sjfv 805266423Sjfv case SIOCSIFADDR: 806266423Sjfv#ifdef INET 807266423Sjfv if (ifa->ifa_addr->sa_family == AF_INET) 808266423Sjfv avoid_reset = TRUE; 809266423Sjfv#endif 810266423Sjfv#ifdef INET6 811266423Sjfv if (ifa->ifa_addr->sa_family == AF_INET6) 812266423Sjfv avoid_reset = TRUE; 813266423Sjfv#endif 814266423Sjfv#if defined(INET) || defined(INET6) 815266423Sjfv /* 816266423Sjfv ** Calling init results in link renegotiation, 817266423Sjfv ** so we avoid doing it when possible. 818266423Sjfv */ 819266423Sjfv if (avoid_reset) { 820266423Sjfv ifp->if_flags |= IFF_UP; 821266423Sjfv if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 822266423Sjfv i40e_init(pf); 823266423Sjfv if (!(ifp->if_flags & IFF_NOARP)) 824266423Sjfv arp_ifinit(ifp, ifa); 825266423Sjfv } else 826266423Sjfv error = ether_ioctl(ifp, command, data); 827266423Sjfv break; 828266423Sjfv#endif 829266423Sjfv case SIOCSIFMTU: 830266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 831266423Sjfv if (ifr->ifr_mtu > I40E_MAX_FRAME - 832266423Sjfv ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) { 833266423Sjfv error = EINVAL; 834266423Sjfv } else { 835266423Sjfv I40E_PF_LOCK(pf); 836266423Sjfv ifp->if_mtu = ifr->ifr_mtu; 837266423Sjfv vsi->max_frame_size = 838266423Sjfv ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 839266423Sjfv + ETHER_VLAN_ENCAP_LEN; 840266423Sjfv i40e_init_locked(pf); 841266423Sjfv I40E_PF_UNLOCK(pf); 842266423Sjfv } 843266423Sjfv break; 844266423Sjfv case SIOCSIFFLAGS: 845266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 846266423Sjfv I40E_PF_LOCK(pf); 847266423Sjfv if (ifp->if_flags & IFF_UP) { 848266423Sjfv if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 849266423Sjfv if ((ifp->if_flags ^ pf->if_flags) & 850266423Sjfv (IFF_PROMISC | IFF_ALLMULTI)) { 851266423Sjfv i40e_set_promisc(vsi); 852266423Sjfv } 853266423Sjfv } else 854266423Sjfv i40e_init_locked(pf); 855266423Sjfv } else 856266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) 857266423Sjfv i40e_stop(pf); 858266423Sjfv pf->if_flags = ifp->if_flags; 859266423Sjfv I40E_PF_UNLOCK(pf); 860266423Sjfv break; 861266423Sjfv case SIOCADDMULTI: 862266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); 863266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 864266423Sjfv I40E_PF_LOCK(pf); 865266423Sjfv i40e_disable_intr(vsi); 866266423Sjfv i40e_add_multi(vsi); 867266423Sjfv i40e_enable_intr(vsi); 868266423Sjfv I40E_PF_UNLOCK(pf); 869266423Sjfv } 870266423Sjfv break; 871266423Sjfv case SIOCDELMULTI: 872266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); 873266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 874266423Sjfv I40E_PF_LOCK(pf); 875266423Sjfv i40e_disable_intr(vsi); 876266423Sjfv i40e_del_multi(vsi); 877266423Sjfv i40e_enable_intr(vsi); 878266423Sjfv I40E_PF_UNLOCK(pf); 879266423Sjfv } 880266423Sjfv break; 881266423Sjfv case SIOCSIFMEDIA: 882266423Sjfv case SIOCGIFMEDIA: 883266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 884266423Sjfv error = ifmedia_ioctl(ifp, ifr, &vsi->media, command); 885266423Sjfv break; 886266423Sjfv case SIOCSIFCAP: 887266423Sjfv { 888266423Sjfv int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 889266423Sjfv IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 890266423Sjfv 891266423Sjfv i40e_cap_txcsum_tso(vsi, ifp, mask); 892266423Sjfv 893266423Sjfv if (mask & IFCAP_RXCSUM) 894266423Sjfv ifp->if_capenable ^= IFCAP_RXCSUM; 895266423Sjfv if (mask & IFCAP_RXCSUM_IPV6) 896266423Sjfv ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 897266423Sjfv if (mask & IFCAP_LRO) 898266423Sjfv ifp->if_capenable ^= IFCAP_LRO; 899266423Sjfv if (mask & IFCAP_VLAN_HWTAGGING) 900266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 901266423Sjfv if (mask & IFCAP_VLAN_HWFILTER) 902266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 903266423Sjfv if (mask & IFCAP_VLAN_HWTSO) 904266423Sjfv ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 905266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 906266423Sjfv I40E_PF_LOCK(pf); 907266423Sjfv i40e_init_locked(pf); 908266423Sjfv I40E_PF_UNLOCK(pf); 909266423Sjfv } 910266423Sjfv VLAN_CAPABILITIES(ifp); 911266423Sjfv 912266423Sjfv break; 913266423Sjfv } 914266423Sjfv 915266423Sjfv default: 916266423Sjfv IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); 917266423Sjfv error = ether_ioctl(ifp, command, data); 918266423Sjfv break; 919266423Sjfv } 920266423Sjfv 921266423Sjfv return (error); 922266423Sjfv} 923266423Sjfv 924266423Sjfv 925266423Sjfv/********************************************************************* 926266423Sjfv * Init entry point 927266423Sjfv * 928266423Sjfv * This routine is used in two ways. It is used by the stack as 929266423Sjfv * init entry point in network interface structure. It is also used 930266423Sjfv * by the driver as a hw/sw initialization routine to get to a 931266423Sjfv * consistent state. 932266423Sjfv * 933266423Sjfv * return 0 on success, positive on failure 934266423Sjfv **********************************************************************/ 935266423Sjfv 936266423Sjfvstatic void 937266423Sjfvi40e_init_locked(struct i40e_pf *pf) 938266423Sjfv{ 939266423Sjfv struct i40e_hw *hw = &pf->hw; 940266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 941266423Sjfv struct ifnet *ifp = vsi->ifp; 942266423Sjfv device_t dev = pf->dev; 943266423Sjfv struct i40e_filter_control_settings filter; 944266423Sjfv u8 tmpaddr[ETHER_ADDR_LEN]; 945266423Sjfv int ret; 946266423Sjfv 947266423Sjfv mtx_assert(&pf->pf_mtx, MA_OWNED); 948266423Sjfv INIT_DEBUGOUT("i40e_init: begin"); 949266423Sjfv i40e_stop(pf); 950266423Sjfv 951266423Sjfv /* Get the latest mac address... User might use a LAA */ 952266423Sjfv bcopy(IF_LLADDR(vsi->ifp), tmpaddr, 953266423Sjfv I40E_ETH_LENGTH_OF_ADDRESS); 954266423Sjfv if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && 955266423Sjfv i40e_validate_mac_addr(tmpaddr)) { 956266423Sjfv bcopy(tmpaddr, hw->mac.addr, 957266423Sjfv I40E_ETH_LENGTH_OF_ADDRESS); 958266423Sjfv ret = i40e_aq_mac_address_write(hw, 959266423Sjfv I40E_AQC_WRITE_TYPE_LAA_ONLY, 960266423Sjfv hw->mac.addr, NULL); 961266423Sjfv if (ret) { 962266423Sjfv device_printf(dev, "LLA address" 963266423Sjfv "change failed!!\n"); 964266423Sjfv return; 965266423Sjfv } 966266423Sjfv } 967266423Sjfv 968266423Sjfv /* Set the various hardware offload abilities */ 969266423Sjfv ifp->if_hwassist = 0; 970266423Sjfv if (ifp->if_capenable & IFCAP_TSO) 971266423Sjfv ifp->if_hwassist |= CSUM_TSO; 972266423Sjfv if (ifp->if_capenable & IFCAP_TXCSUM) 973266423Sjfv ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 974266423Sjfv if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 975266423Sjfv ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); 976266423Sjfv 977266423Sjfv /* Set up the device filtering */ 978266423Sjfv bzero(&filter, sizeof(filter)); 979266423Sjfv filter.enable_ethtype = TRUE; 980266423Sjfv filter.enable_macvlan = TRUE; 981266423Sjfv#ifdef I40E_FDIR 982266423Sjfv filter.enable_fdir = TRUE; 983266423Sjfv#endif 984266423Sjfv if (i40e_set_filter_control(hw, &filter)) 985266423Sjfv device_printf(dev, "set_filter_control() failed\n"); 986266423Sjfv 987266423Sjfv /* Set up RSS */ 988266423Sjfv i40e_config_rss(vsi); 989266423Sjfv 990266423Sjfv /* Setup the VSI */ 991266423Sjfv i40e_setup_vsi(vsi); 992266423Sjfv 993266423Sjfv /* 994266423Sjfv ** Prepare the rings, hmc contexts, etc... 995266423Sjfv */ 996266423Sjfv if (i40e_initialize_vsi(vsi)) { 997266423Sjfv device_printf(dev,"initialize vsi failed!!\n"); 998266423Sjfv return; 999266423Sjfv } 1000266423Sjfv 1001266423Sjfv /* Add protocol filters to list */ 1002266423Sjfv i40e_init_filters(vsi); 1003266423Sjfv 1004266423Sjfv /* Setup vlan's if needed */ 1005266423Sjfv i40e_setup_vlan_filters(vsi); 1006266423Sjfv 1007266423Sjfv /* Start the local timer */ 1008266423Sjfv callout_reset(&pf->timer, hz, i40e_local_timer, pf); 1009266423Sjfv 1010266423Sjfv /* Set up MSI/X routing and the ITR settings */ 1011266423Sjfv if (i40e_enable_msix) { 1012266423Sjfv i40e_configure_msix(pf); 1013266423Sjfv i40e_configure_itr(pf); 1014266423Sjfv } else 1015266423Sjfv i40e_configure_legacy(pf); 1016266423Sjfv 1017266423Sjfv /* 1018266423Sjfv ** Only a temporary workaround for RX hangs 1019266423Sjfv */ 1020266423Sjfv if (rd32(hw, I40E_PRTRPB_SLW) != 0x30000) 1021266423Sjfv wr32(hw, I40E_PRTRPB_SLW, 0x30000); 1022266423Sjfv 1023266423Sjfv i40e_enable_rings(vsi); 1024266423Sjfv 1025266423Sjfv i40e_aq_set_default_vsi(hw, vsi->seid, NULL); 1026266423Sjfv 1027266423Sjfv /* Flow control setup */ 1028266423Sjfv /* NOTE: flow control currently doesn't work correctly */ 1029266423Sjfv // i40e_set_fc_mode(pf, I40E_FC_FULL); 1030266423Sjfv 1031266423Sjfv /* Set MTU in hardware*/ 1032266423Sjfv if (ifp->if_mtu > ETHERMTU) { 1033266423Sjfv int aq_error = 1034266423Sjfv i40e_aq_set_mac_config(hw, vsi->max_frame_size, 1035266423Sjfv TRUE, 0, NULL); 1036266423Sjfv if (aq_error) 1037266423Sjfv device_printf(vsi->dev, 1038266423Sjfv "aq_set_mac_config in init error, code %d\n", 1039266423Sjfv aq_error); 1040266423Sjfv } 1041266423Sjfv 1042266423Sjfv /* And now turn on interrupts */ 1043266423Sjfv i40e_enable_intr(vsi); 1044266423Sjfv 1045266423Sjfv /* Now inform the stack we're ready */ 1046266423Sjfv ifp->if_drv_flags |= IFF_DRV_RUNNING; 1047266423Sjfv ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1048266423Sjfv 1049266423Sjfv return; 1050266423Sjfv} 1051266423Sjfv 1052266423Sjfvstatic void 1053266423Sjfvi40e_init(void *arg) 1054266423Sjfv{ 1055266423Sjfv struct i40e_pf *pf = arg; 1056266423Sjfv 1057266423Sjfv I40E_PF_LOCK(pf); 1058266423Sjfv i40e_init_locked(pf); 1059266423Sjfv I40E_PF_UNLOCK(pf); 1060266423Sjfv return; 1061266423Sjfv} 1062266423Sjfv 1063266423Sjfv/* 1064266423Sjfv** 1065266423Sjfv** MSIX Interrupt Handlers and Tasklets 1066266423Sjfv** 1067266423Sjfv*/ 1068266423Sjfvstatic void 1069266423Sjfvi40e_handle_que(void *context, int pending) 1070266423Sjfv{ 1071266423Sjfv struct i40e_queue *que = context; 1072266423Sjfv struct i40e_vsi *vsi = que->vsi; 1073266423Sjfv struct i40e_hw *hw = vsi->hw; 1074266423Sjfv struct tx_ring *txr = &que->txr; 1075266423Sjfv struct ifnet *ifp = vsi->ifp; 1076266423Sjfv bool more; 1077266423Sjfv 1078266423Sjfv if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1079266423Sjfv more = i40e_rxeof(que, I40E_RX_LIMIT); 1080266423Sjfv I40E_TX_LOCK(txr); 1081266423Sjfv i40e_txeof(que); 1082266423Sjfv if (!drbr_empty(ifp, txr->br)) 1083266423Sjfv i40e_mq_start_locked(ifp, txr); 1084266423Sjfv I40E_TX_UNLOCK(txr); 1085266423Sjfv if (more) { 1086266423Sjfv taskqueue_enqueue(que->tq, &que->task); 1087266423Sjfv return; 1088266423Sjfv } 1089266423Sjfv } 1090266423Sjfv 1091266423Sjfv /* Reenable this interrupt - hmmm */ 1092266423Sjfv i40e_enable_queue(hw, que->me); 1093266423Sjfv return; 1094266423Sjfv} 1095266423Sjfv 1096266423Sjfv 1097266423Sjfv/********************************************************************* 1098266423Sjfv * 1099266423Sjfv * Legacy Interrupt Service routine 1100266423Sjfv * 1101266423Sjfv **********************************************************************/ 1102266423Sjfvvoid 1103266423Sjfvi40e_intr(void *arg) 1104266423Sjfv{ 1105266423Sjfv struct i40e_pf *pf = arg; 1106266423Sjfv struct i40e_hw *hw = &pf->hw; 1107266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 1108266423Sjfv struct i40e_queue *que = vsi->queues; 1109266423Sjfv struct ifnet *ifp = vsi->ifp; 1110266423Sjfv struct tx_ring *txr = &que->txr; 1111266423Sjfv u32 reg, icr0, mask; 1112266423Sjfv bool more_tx, more_rx; 1113266423Sjfv 1114266423Sjfv ++que->irqs; 1115266423Sjfv 1116266423Sjfv /* Protect against spurious interrupts */ 1117266423Sjfv if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1118266423Sjfv return; 1119266423Sjfv 1120266423Sjfv icr0 = rd32(hw, I40E_PFINT_ICR0); 1121266423Sjfv 1122266423Sjfv reg = rd32(hw, I40E_PFINT_DYN_CTL0); 1123266423Sjfv reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 1124266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 1125266423Sjfv 1126266423Sjfv mask = rd32(hw, I40E_PFINT_ICR0_ENA); 1127266423Sjfv 1128266423Sjfv if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) { 1129266423Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 1130266423Sjfv return; 1131266423Sjfv } 1132266423Sjfv 1133266423Sjfv more_rx = i40e_rxeof(que, I40E_RX_LIMIT); 1134266423Sjfv 1135266423Sjfv I40E_TX_LOCK(txr); 1136266423Sjfv more_tx = i40e_txeof(que); 1137266423Sjfv if (!drbr_empty(vsi->ifp, txr->br)) 1138266423Sjfv more_tx = 1; 1139266423Sjfv I40E_TX_UNLOCK(txr); 1140266423Sjfv 1141266423Sjfv /* re-enable other interrupt causes */ 1142266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, mask); 1143266423Sjfv 1144266423Sjfv /* And now the queues */ 1145266423Sjfv reg = rd32(hw, I40E_QINT_RQCTL(0)); 1146266423Sjfv reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; 1147266423Sjfv wr32(hw, I40E_QINT_RQCTL(0), reg); 1148266423Sjfv 1149266423Sjfv reg = rd32(hw, I40E_QINT_TQCTL(0)); 1150266423Sjfv reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; 1151266423Sjfv reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK; 1152266423Sjfv wr32(hw, I40E_QINT_TQCTL(0), reg); 1153266423Sjfv 1154266423Sjfv i40e_enable_legacy(hw); 1155266423Sjfv 1156266423Sjfv return; 1157266423Sjfv} 1158266423Sjfv 1159266423Sjfv 1160266423Sjfv/********************************************************************* 1161266423Sjfv * 1162266423Sjfv * MSIX VSI Interrupt Service routine 1163266423Sjfv * 1164266423Sjfv **********************************************************************/ 1165266423Sjfvvoid 1166266423Sjfvi40e_msix_que(void *arg) 1167266423Sjfv{ 1168266423Sjfv struct i40e_queue *que = arg; 1169266423Sjfv struct i40e_vsi *vsi = que->vsi; 1170266423Sjfv struct i40e_hw *hw = vsi->hw; 1171266423Sjfv struct tx_ring *txr = &que->txr; 1172266423Sjfv bool more_tx, more_rx; 1173266423Sjfv 1174266423Sjfv ++que->irqs; 1175266423Sjfv 1176266423Sjfv more_rx = i40e_rxeof(que, I40E_RX_LIMIT); 1177266423Sjfv 1178266423Sjfv I40E_TX_LOCK(txr); 1179266423Sjfv more_tx = i40e_txeof(que); 1180266423Sjfv /* 1181266423Sjfv ** Make certain that if the stack 1182266423Sjfv ** has anything queued the task gets 1183266423Sjfv ** scheduled to handle it. 1184266423Sjfv */ 1185266423Sjfv if (!drbr_empty(vsi->ifp, txr->br)) 1186266423Sjfv more_tx = 1; 1187266423Sjfv I40E_TX_UNLOCK(txr); 1188266423Sjfv 1189266423Sjfv i40e_set_queue_rx_itr(que); 1190266423Sjfv i40e_set_queue_tx_itr(que); 1191266423Sjfv 1192266423Sjfv if (more_tx || more_rx) 1193266423Sjfv taskqueue_enqueue(que->tq, &que->task); 1194266423Sjfv else 1195266423Sjfv i40e_enable_queue(hw, que->me); 1196266423Sjfv 1197266423Sjfv return; 1198266423Sjfv} 1199266423Sjfv 1200266423Sjfv 1201266423Sjfv/********************************************************************* 1202266423Sjfv * 1203266423Sjfv * MSIX Admin Queue Interrupt Service routine 1204266423Sjfv * 1205266423Sjfv **********************************************************************/ 1206266423Sjfvstatic void 1207266423Sjfvi40e_msix_adminq(void *arg) 1208266423Sjfv{ 1209266423Sjfv struct i40e_pf *pf = arg; 1210266423Sjfv struct i40e_hw *hw = &pf->hw; 1211266423Sjfv u32 reg, mask; 1212266423Sjfv 1213266423Sjfv ++pf->admin_irq; 1214266423Sjfv 1215266423Sjfv reg = rd32(hw, I40E_PFINT_ICR0); 1216266423Sjfv mask = rd32(hw, I40E_PFINT_ICR0_ENA); 1217266423Sjfv 1218266423Sjfv /* Check on the cause */ 1219266423Sjfv if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) 1220266423Sjfv mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 1221266423Sjfv 1222266423Sjfv if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) 1223266423Sjfv mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; 1224266423Sjfv 1225266423Sjfv if (reg & I40E_PFINT_ICR0_VFLR_MASK) 1226266423Sjfv mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; 1227266423Sjfv 1228266423Sjfv reg = rd32(hw, I40E_PFINT_DYN_CTL0); 1229266423Sjfv reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; 1230266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 1231266423Sjfv 1232266423Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 1233266423Sjfv return; 1234266423Sjfv} 1235266423Sjfv 1236266423Sjfv/********************************************************************* 1237266423Sjfv * 1238266423Sjfv * Media Ioctl callback 1239266423Sjfv * 1240266423Sjfv * This routine is called whenever the user queries the status of 1241266423Sjfv * the interface using ifconfig. 1242266423Sjfv * 1243266423Sjfv **********************************************************************/ 1244266423Sjfvstatic void 1245266423Sjfvi40e_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 1246266423Sjfv{ 1247266423Sjfv struct i40e_vsi *vsi = ifp->if_softc; 1248266423Sjfv struct i40e_pf *pf = (struct i40e_pf *)vsi->back; 1249266423Sjfv struct i40e_hw *hw = &pf->hw; 1250266423Sjfv 1251266423Sjfv INIT_DEBUGOUT("i40e_media_status: begin"); 1252266423Sjfv I40E_PF_LOCK(pf); 1253266423Sjfv 1254266423Sjfv i40e_update_link_status(pf); 1255266423Sjfv 1256266423Sjfv ifmr->ifm_status = IFM_AVALID; 1257266423Sjfv ifmr->ifm_active = IFM_ETHER; 1258266423Sjfv 1259266423Sjfv if (!vsi->link_up) { 1260266423Sjfv I40E_PF_UNLOCK(pf); 1261266423Sjfv return; 1262266423Sjfv } 1263266423Sjfv 1264266423Sjfv ifmr->ifm_status |= IFM_ACTIVE; 1265266423Sjfv /* Hardware is always full-duplex */ 1266266423Sjfv ifmr->ifm_active |= IFM_FDX; 1267266423Sjfv 1268266423Sjfv switch (hw->phy.link_info.phy_type) { 1269266423Sjfv /* 100 M */ 1270266423Sjfv case I40E_PHY_TYPE_100BASE_TX: 1271266423Sjfv ifmr->ifm_active |= IFM_100_TX; 1272266423Sjfv break; 1273266423Sjfv /* 1 G */ 1274266423Sjfv case I40E_PHY_TYPE_1000BASE_T: 1275266423Sjfv ifmr->ifm_active |= IFM_1000_T; 1276266423Sjfv break; 1277266423Sjfv /* 10 G */ 1278266423Sjfv case I40E_PHY_TYPE_10GBASE_CR1_CU: 1279266423Sjfv case I40E_PHY_TYPE_10GBASE_SFPP_CU: 1280266423Sjfv ifmr->ifm_active |= IFM_10G_TWINAX; 1281266423Sjfv break; 1282266423Sjfv case I40E_PHY_TYPE_10GBASE_SR: 1283266423Sjfv ifmr->ifm_active |= IFM_10G_SR; 1284266423Sjfv break; 1285266423Sjfv case I40E_PHY_TYPE_10GBASE_LR: 1286266423Sjfv ifmr->ifm_active |= IFM_10G_LR; 1287266423Sjfv break; 1288266423Sjfv /* 40 G */ 1289266423Sjfv case I40E_PHY_TYPE_40GBASE_CR4: 1290266423Sjfv case I40E_PHY_TYPE_40GBASE_CR4_CU: 1291266423Sjfv ifmr->ifm_active |= IFM_40G_CR4; 1292266423Sjfv break; 1293266423Sjfv case I40E_PHY_TYPE_40GBASE_SR4: 1294266423Sjfv ifmr->ifm_active |= IFM_40G_SR4; 1295266423Sjfv break; 1296266423Sjfv case I40E_PHY_TYPE_40GBASE_LR4: 1297266423Sjfv ifmr->ifm_active |= IFM_40G_LR4; 1298266423Sjfv break; 1299266423Sjfv /* 1300266423Sjfv * FreeBSD doesn't know about the other phy 1301266423Sjfv * types this hardware supports. 1302266423Sjfv */ 1303266423Sjfv default: 1304266423Sjfv ifmr->ifm_active |= IFM_UNKNOWN; 1305266423Sjfv break; 1306266423Sjfv } 1307266423Sjfv /* Report flow control status as well */ 1308266423Sjfv /* TODO: Something special if PFC is enabled instead */ 1309266423Sjfv if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) 1310266423Sjfv ifmr->ifm_active |= IFM_ETH_TXPAUSE; 1311266423Sjfv if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) 1312266423Sjfv ifmr->ifm_active |= IFM_ETH_RXPAUSE; 1313266423Sjfv 1314266423Sjfv I40E_PF_UNLOCK(pf); 1315266423Sjfv 1316266423Sjfv return; 1317266423Sjfv} 1318266423Sjfv 1319266423Sjfv/********************************************************************* 1320266423Sjfv * 1321266423Sjfv * Media Ioctl callback 1322266423Sjfv * 1323266423Sjfv * This routine is called when the user changes speed/duplex using 1324266423Sjfv * media/mediopt option with ifconfig. 1325266423Sjfv * 1326266423Sjfv **********************************************************************/ 1327266423Sjfvstatic int 1328266423Sjfvi40e_media_change(struct ifnet * ifp) 1329266423Sjfv{ 1330266423Sjfv struct i40e_vsi *vsi = ifp->if_softc; 1331266423Sjfv struct ifmedia *ifm = &vsi->media; 1332266423Sjfv 1333266423Sjfv INIT_DEBUGOUT("i40e_media_change: begin"); 1334266423Sjfv 1335266423Sjfv if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1336266423Sjfv return (EINVAL); 1337266423Sjfv 1338266423Sjfv return (0); 1339266423Sjfv} 1340266423Sjfv 1341266423Sjfv 1342266423Sjfv#ifdef I40E_FDIR 1343266423Sjfv/* 1344266423Sjfv** ATR: Application Targetted Receive - creates a filter 1345266423Sjfv** based on TX flow info that will keep the receive 1346266423Sjfv** portion of the flow on the same queue. Based on the 1347266423Sjfv** implementation this is only available for TCP connections 1348266423Sjfv*/ 1349266423Sjfvvoid 1350266423Sjfvi40e_atr(struct i40e_queue *que, struct tcphdr *th, int etype) 1351266423Sjfv{ 1352266423Sjfv struct i40e_vsi *vsi = que->vsi; 1353266423Sjfv struct tx_ring *txr = &que->txr; 1354266423Sjfv struct i40e_filter_program_desc *FDIR; 1355266423Sjfv u32 ptype, dtype; 1356266423Sjfv int idx; 1357266423Sjfv 1358266423Sjfv /* check if ATR is enabled and sample rate */ 1359266423Sjfv if ((!i40e_enable_fdir) || (!txr->atr_rate)) 1360266423Sjfv return; 1361266423Sjfv /* 1362266423Sjfv ** We sample all TCP SYN/FIN packets, 1363266423Sjfv ** or at the selected sample rate 1364266423Sjfv */ 1365266423Sjfv txr->atr_count++; 1366266423Sjfv if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) && 1367266423Sjfv (txr->atr_count < txr->atr_rate)) 1368266423Sjfv return; 1369266423Sjfv txr->atr_count = 0; 1370266423Sjfv 1371266423Sjfv /* Get a descriptor to use */ 1372266423Sjfv idx = txr->next_avail; 1373266423Sjfv FDIR = (struct i40e_filter_program_desc *) &txr->base[idx]; 1374266423Sjfv if (++idx == que->num_desc) 1375266423Sjfv idx = 0; 1376266423Sjfv txr->avail--; 1377266423Sjfv txr->next_avail = idx; 1378266423Sjfv 1379266423Sjfv ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & 1380266423Sjfv I40E_TXD_FLTR_QW0_QINDEX_MASK; 1381266423Sjfv 1382266423Sjfv ptype |= (etype == ETHERTYPE_IP) ? 1383266423Sjfv (I40E_FILTER_PCTYPE_NONF_IPV4_TCP << 1384266423Sjfv I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) : 1385266423Sjfv (I40E_FILTER_PCTYPE_NONF_IPV6_TCP << 1386266423Sjfv I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); 1387266423Sjfv 1388266423Sjfv ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT; 1389266423Sjfv 1390266423Sjfv dtype = I40E_TX_DESC_DTYPE_FILTER_PROG; 1391266423Sjfv 1392266423Sjfv /* 1393266423Sjfv ** We use the TCP TH_FIN as a trigger to remove 1394266423Sjfv ** the filter, otherwise its an update. 1395266423Sjfv */ 1396266423Sjfv dtype |= (th->th_flags & TH_FIN) ? 1397266423Sjfv (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << 1398266423Sjfv I40E_TXD_FLTR_QW1_PCMD_SHIFT) : 1399266423Sjfv (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << 1400266423Sjfv I40E_TXD_FLTR_QW1_PCMD_SHIFT); 1401266423Sjfv 1402266423Sjfv dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX << 1403266423Sjfv I40E_TXD_FLTR_QW1_DEST_SHIFT; 1404266423Sjfv 1405266423Sjfv dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID << 1406266423Sjfv I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT; 1407266423Sjfv 1408266423Sjfv FDIR->qindex_flex_ptype_vsi = htole32(ptype); 1409266423Sjfv FDIR->dtype_cmd_cntindex = htole32(dtype); 1410266423Sjfv return; 1411266423Sjfv} 1412266423Sjfv#endif 1413266423Sjfv 1414266423Sjfv 1415266423Sjfvstatic void 1416266423Sjfvi40e_set_promisc(struct i40e_vsi *vsi) 1417266423Sjfv{ 1418266423Sjfv struct ifnet *ifp = vsi->ifp; 1419266423Sjfv struct i40e_hw *hw = vsi->hw; 1420266423Sjfv int err, mcnt = 0; 1421266423Sjfv bool uni = FALSE, multi = FALSE; 1422266423Sjfv 1423266423Sjfv if (ifp->if_flags & IFF_ALLMULTI) 1424266423Sjfv multi = TRUE; 1425266423Sjfv else { /* Need to count the multicast addresses */ 1426266423Sjfv struct ifmultiaddr *ifma; 1427266423Sjfv if_maddr_rlock(ifp); 1428266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1429266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1430266423Sjfv continue; 1431266423Sjfv if (mcnt == MAX_MULTICAST_ADDR) 1432266423Sjfv break; 1433266423Sjfv mcnt++; 1434266423Sjfv } 1435266423Sjfv if_maddr_runlock(ifp); 1436266423Sjfv } 1437266423Sjfv 1438266423Sjfv if (mcnt >= MAX_MULTICAST_ADDR) 1439266423Sjfv multi = TRUE; 1440266423Sjfv if (ifp->if_flags & IFF_PROMISC) 1441266423Sjfv uni = TRUE; 1442266423Sjfv 1443266423Sjfv err = i40e_aq_set_vsi_unicast_promiscuous(hw, 1444266423Sjfv vsi->seid, uni, NULL); 1445266423Sjfv err = i40e_aq_set_vsi_multicast_promiscuous(hw, 1446266423Sjfv vsi->seid, multi, NULL); 1447266423Sjfv return; 1448266423Sjfv} 1449266423Sjfv 1450266423Sjfv/********************************************************************* 1451266423Sjfv * Filter Routines 1452266423Sjfv * 1453266423Sjfv * Routines for multicast and vlan filter management. 1454266423Sjfv * 1455266423Sjfv *********************************************************************/ 1456266423Sjfvstatic void 1457266423Sjfvi40e_add_multi(struct i40e_vsi *vsi) 1458266423Sjfv{ 1459266423Sjfv struct ifmultiaddr *ifma; 1460266423Sjfv struct ifnet *ifp = vsi->ifp; 1461266423Sjfv struct i40e_hw *hw = vsi->hw; 1462266423Sjfv int mcnt = 0, flags; 1463266423Sjfv 1464266423Sjfv IOCTL_DEBUGOUT("i40e_add_multi: begin"); 1465266423Sjfv 1466266423Sjfv if_maddr_rlock(ifp); 1467266423Sjfv /* 1468266423Sjfv ** First just get a count, to decide if we 1469266423Sjfv ** we simply use multicast promiscuous. 1470266423Sjfv */ 1471266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1472266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1473266423Sjfv continue; 1474266423Sjfv mcnt++; 1475266423Sjfv } 1476266423Sjfv if_maddr_runlock(ifp); 1477266423Sjfv 1478266423Sjfv if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { 1479266423Sjfv /* delete existing MC filters */ 1480266423Sjfv i40e_del_hw_filters(vsi, mcnt); 1481266423Sjfv i40e_aq_set_vsi_multicast_promiscuous(hw, 1482266423Sjfv vsi->seid, TRUE, NULL); 1483266423Sjfv return; 1484266423Sjfv } 1485266423Sjfv 1486266423Sjfv mcnt = 0; 1487266423Sjfv if_maddr_rlock(ifp); 1488266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1489266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1490266423Sjfv continue; 1491266423Sjfv i40e_add_mc_filter(vsi, 1492266423Sjfv (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); 1493266423Sjfv mcnt++; 1494266423Sjfv } 1495266423Sjfv if_maddr_runlock(ifp); 1496266423Sjfv if (mcnt > 0) { 1497266423Sjfv flags = (I40E_FILTER_ADD | I40E_FILTER_USED | I40E_FILTER_MC); 1498266423Sjfv i40e_add_hw_filters(vsi, flags, mcnt); 1499266423Sjfv } 1500266423Sjfv 1501266423Sjfv IOCTL_DEBUGOUT("i40e_add_multi: end"); 1502266423Sjfv return; 1503266423Sjfv} 1504266423Sjfv 1505266423Sjfvstatic void 1506266423Sjfvi40e_del_multi(struct i40e_vsi *vsi) 1507266423Sjfv{ 1508266423Sjfv struct ifnet *ifp = vsi->ifp; 1509266423Sjfv struct ifmultiaddr *ifma; 1510266423Sjfv struct i40e_mac_filter *f; 1511266423Sjfv int mcnt = 0; 1512266423Sjfv bool match = FALSE; 1513266423Sjfv 1514266423Sjfv IOCTL_DEBUGOUT("i40e_del_multi: begin"); 1515266423Sjfv 1516266423Sjfv /* Search for removed multicast addresses */ 1517266423Sjfv if_maddr_rlock(ifp); 1518266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 1519266423Sjfv if ((f->flags & I40E_FILTER_USED) && (f->flags & I40E_FILTER_MC)) { 1520266423Sjfv match = FALSE; 1521266423Sjfv TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1522266423Sjfv if (ifma->ifma_addr->sa_family != AF_LINK) 1523266423Sjfv continue; 1524266423Sjfv u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 1525266423Sjfv if (cmp_etheraddr(f->macaddr, mc_addr)) { 1526266423Sjfv match = TRUE; 1527266423Sjfv break; 1528266423Sjfv } 1529266423Sjfv } 1530266423Sjfv if (match == FALSE) { 1531266423Sjfv f->flags |= I40E_FILTER_DEL; 1532266423Sjfv mcnt++; 1533266423Sjfv } 1534266423Sjfv } 1535266423Sjfv } 1536266423Sjfv if_maddr_runlock(ifp); 1537266423Sjfv 1538266423Sjfv if (mcnt > 0) 1539266423Sjfv i40e_del_hw_filters(vsi, mcnt); 1540266423Sjfv} 1541266423Sjfv 1542266423Sjfv 1543266423Sjfv/********************************************************************* 1544266423Sjfv * Timer routine 1545266423Sjfv * 1546266423Sjfv * This routine checks for link status,updates statistics, 1547266423Sjfv * and runs the watchdog check. 1548266423Sjfv * 1549266423Sjfv **********************************************************************/ 1550266423Sjfv 1551266423Sjfvstatic void 1552266423Sjfvi40e_local_timer(void *arg) 1553266423Sjfv{ 1554266423Sjfv struct i40e_pf *pf = arg; 1555266423Sjfv struct i40e_hw *hw = &pf->hw; 1556266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 1557266423Sjfv struct i40e_queue *que = vsi->queues; 1558266423Sjfv device_t dev = pf->dev; 1559266423Sjfv int hung = 0; 1560266423Sjfv u32 mask; 1561266423Sjfv 1562266423Sjfv mtx_assert(&pf->pf_mtx, MA_OWNED); 1563266423Sjfv 1564266423Sjfv /* Fire off the adminq task */ 1565266423Sjfv taskqueue_enqueue(pf->tq, &pf->adminq); 1566266423Sjfv 1567266423Sjfv /* Update stats */ 1568266423Sjfv i40e_update_stats_counters(pf); 1569266423Sjfv 1570266423Sjfv /* 1571266423Sjfv ** Check status on the queues for a hang 1572266423Sjfv */ 1573266423Sjfv mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | 1574266423Sjfv I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); 1575266423Sjfv 1576266423Sjfv for (int i = 0; i < vsi->num_queues; i++,que++) { 1577266423Sjfv /* Any queues with outstanding work get a sw irq */ 1578266423Sjfv if (que->busy) 1579266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask); 1580266423Sjfv /* 1581266423Sjfv ** Each time txeof runs without cleaning, but there 1582266423Sjfv ** are uncleaned descriptors it increments busy. If 1583266423Sjfv ** we get to 5 we declare it hung. 1584266423Sjfv */ 1585266423Sjfv if (que->busy >= I40E_MAX_TX_BUSY) { 1586266423Sjfv device_printf(dev,"Warning queue %d " 1587266423Sjfv "appears to be hung!", i); 1588266423Sjfv ++hung; 1589266423Sjfv } 1590266423Sjfv } 1591266423Sjfv /* Only reinit if all queues show hung */ 1592266423Sjfv if (hung == vsi->num_queues) 1593266423Sjfv goto hung; 1594266423Sjfv 1595266423Sjfv callout_reset(&pf->timer, hz, i40e_local_timer, pf); 1596266423Sjfv return; 1597266423Sjfv 1598266423Sjfvhung: 1599266423Sjfv device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n"); 1600266423Sjfv i40e_init_locked(pf); 1601266423Sjfv} 1602266423Sjfv 1603266423Sjfv/* 1604266423Sjfv** Note: this routine updates the OS on the link state 1605266423Sjfv** the real check of the hardware only happens with 1606266423Sjfv** a link interrupt. 1607266423Sjfv*/ 1608266423Sjfvstatic void 1609266423Sjfvi40e_update_link_status(struct i40e_pf *pf) 1610266423Sjfv{ 1611266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 1612266423Sjfv struct i40e_hw *hw = &pf->hw; 1613266423Sjfv struct ifnet *ifp = vsi->ifp; 1614266423Sjfv device_t dev = pf->dev; 1615266423Sjfv enum i40e_fc_mode fc; 1616266423Sjfv 1617266423Sjfv 1618266423Sjfv if (vsi->link_up){ 1619266423Sjfv if (vsi->link_active == FALSE) { 1620266423Sjfv i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 1621266423Sjfv if (bootverbose) { 1622266423Sjfv fc = hw->fc.current_mode; 1623266423Sjfv device_printf(dev,"Link is up %d Gbps %s," 1624266423Sjfv " Flow Control: %s\n", 1625266423Sjfv ((vsi->link_speed == I40E_LINK_SPEED_40GB)? 40:10), 1626266423Sjfv "Full Duplex", i40e_fc_string[fc]); 1627266423Sjfv } 1628266423Sjfv vsi->link_active = TRUE; 1629266423Sjfv if_link_state_change(ifp, LINK_STATE_UP); 1630266423Sjfv } 1631266423Sjfv } else { /* Link down */ 1632266423Sjfv if (vsi->link_active == TRUE) { 1633266423Sjfv if (bootverbose) 1634266423Sjfv device_printf(dev,"Link is Down\n"); 1635266423Sjfv if_link_state_change(ifp, LINK_STATE_DOWN); 1636266423Sjfv vsi->link_active = FALSE; 1637266423Sjfv } 1638266423Sjfv } 1639266423Sjfv 1640266423Sjfv return; 1641266423Sjfv} 1642266423Sjfv 1643266423Sjfv/********************************************************************* 1644266423Sjfv * 1645266423Sjfv * This routine disables all traffic on the adapter by issuing a 1646266423Sjfv * global reset on the MAC and deallocates TX/RX buffers. 1647266423Sjfv * 1648266423Sjfv **********************************************************************/ 1649266423Sjfv 1650266423Sjfvstatic void 1651266423Sjfvi40e_stop(struct i40e_pf *pf) 1652266423Sjfv{ 1653266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 1654266423Sjfv struct ifnet *ifp = vsi->ifp; 1655266423Sjfv 1656266423Sjfv mtx_assert(&pf->pf_mtx, MA_OWNED); 1657266423Sjfv 1658266423Sjfv INIT_DEBUGOUT("i40e_stop: begin\n"); 1659266423Sjfv i40e_disable_intr(vsi); 1660266423Sjfv i40e_disable_rings(vsi); 1661266423Sjfv 1662266423Sjfv /* Tell the stack that the interface is no longer active */ 1663266423Sjfv ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1664266423Sjfv 1665266423Sjfv /* Stop the local timer */ 1666266423Sjfv callout_stop(&pf->timer); 1667266423Sjfv 1668266423Sjfv return; 1669266423Sjfv} 1670266423Sjfv 1671266423Sjfv 1672266423Sjfv/********************************************************************* 1673266423Sjfv * 1674266423Sjfv * Setup MSIX Interrupt resources and handlers for the VSI 1675266423Sjfv * 1676266423Sjfv **********************************************************************/ 1677266423Sjfvstatic int 1678266423Sjfvi40e_assign_vsi_legacy(struct i40e_pf *pf) 1679266423Sjfv{ 1680266423Sjfv device_t dev = pf->dev; 1681266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 1682266423Sjfv struct i40e_queue *que = vsi->queues; 1683266423Sjfv int error, rid = 0; 1684266423Sjfv 1685266423Sjfv if (pf->msix == 1) 1686266423Sjfv rid = 1; 1687266423Sjfv pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 1688266423Sjfv &rid, RF_SHAREABLE | RF_ACTIVE); 1689266423Sjfv if (pf->res == NULL) { 1690266423Sjfv device_printf(dev,"Unable to allocate" 1691266423Sjfv " bus resource: vsi legacy/msi interrupt\n"); 1692266423Sjfv return (ENXIO); 1693266423Sjfv } 1694266423Sjfv 1695266423Sjfv /* Set the handler function */ 1696266423Sjfv error = bus_setup_intr(dev, pf->res, 1697266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 1698266423Sjfv i40e_intr, pf, &pf->tag); 1699266423Sjfv if (error) { 1700266423Sjfv pf->res = NULL; 1701266423Sjfv device_printf(dev, "Failed to register legacy/msi handler"); 1702266423Sjfv return (error); 1703266423Sjfv } 1704266423Sjfv bus_describe_intr(dev, pf->res, pf->tag, "irq0"); 1705266423Sjfv TASK_INIT(&que->tx_task, 0, i40e_deferred_mq_start, que); 1706266423Sjfv TASK_INIT(&que->task, 0, i40e_handle_que, que); 1707266423Sjfv que->tq = taskqueue_create_fast("i40e_que", M_NOWAIT, 1708266423Sjfv taskqueue_thread_enqueue, &que->tq); 1709266423Sjfv taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 1710266423Sjfv device_get_nameunit(dev)); 1711266423Sjfv TASK_INIT(&pf->adminq, 0, i40e_do_adminq, pf); 1712266423Sjfv pf->tq = taskqueue_create_fast("i40e_adm", M_NOWAIT, 1713266423Sjfv taskqueue_thread_enqueue, &pf->tq); 1714266423Sjfv taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 1715266423Sjfv device_get_nameunit(dev)); 1716266423Sjfv 1717266423Sjfv return (0); 1718266423Sjfv} 1719266423Sjfv 1720266423Sjfv 1721266423Sjfv/********************************************************************* 1722266423Sjfv * 1723266423Sjfv * Setup MSIX Interrupt resources and handlers for the VSI 1724266423Sjfv * 1725266423Sjfv **********************************************************************/ 1726266423Sjfvstatic int 1727266423Sjfvi40e_assign_vsi_msix(struct i40e_pf *pf) 1728266423Sjfv{ 1729266423Sjfv device_t dev = pf->dev; 1730266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 1731266423Sjfv struct i40e_queue *que = vsi->queues; 1732266423Sjfv struct tx_ring *txr; 1733266423Sjfv int error, rid, vector = 0; 1734266423Sjfv 1735266423Sjfv /* Admin Que is vector 0*/ 1736266423Sjfv rid = vector + 1; 1737266423Sjfv pf->res = bus_alloc_resource_any(dev, 1738266423Sjfv SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 1739266423Sjfv if (!pf->res) { 1740266423Sjfv device_printf(dev,"Unable to allocate" 1741266423Sjfv " bus resource: Adminq interrupt [%d]\n", rid); 1742266423Sjfv return (ENXIO); 1743266423Sjfv } 1744266423Sjfv /* Set the adminq vector and handler */ 1745266423Sjfv error = bus_setup_intr(dev, pf->res, 1746266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 1747266423Sjfv i40e_msix_adminq, pf, &pf->tag); 1748266423Sjfv if (error) { 1749266423Sjfv pf->res = NULL; 1750266423Sjfv device_printf(dev, "Failed to register Admin que handler"); 1751266423Sjfv return (error); 1752266423Sjfv } 1753266423Sjfv bus_describe_intr(dev, pf->res, pf->tag, "aq"); 1754266423Sjfv pf->admvec = vector; 1755266423Sjfv /* Tasklet for Admin Queue */ 1756266423Sjfv TASK_INIT(&pf->adminq, 0, i40e_do_adminq, pf); 1757266423Sjfv pf->tq = taskqueue_create_fast("i40e_adm", M_NOWAIT, 1758266423Sjfv taskqueue_thread_enqueue, &pf->tq); 1759266423Sjfv taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", 1760266423Sjfv device_get_nameunit(pf->dev)); 1761266423Sjfv ++vector; 1762266423Sjfv 1763266423Sjfv /* Now set up the stations */ 1764266423Sjfv for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { 1765266423Sjfv rid = vector + 1; 1766266423Sjfv txr = &que->txr; 1767266423Sjfv que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1768266423Sjfv RF_SHAREABLE | RF_ACTIVE); 1769266423Sjfv if (que->res == NULL) { 1770266423Sjfv device_printf(dev,"Unable to allocate" 1771266423Sjfv " bus resource: que interrupt [%d]\n", vector); 1772266423Sjfv return (ENXIO); 1773266423Sjfv } 1774266423Sjfv /* Set the handler function */ 1775266423Sjfv error = bus_setup_intr(dev, que->res, 1776266423Sjfv INTR_TYPE_NET | INTR_MPSAFE, NULL, 1777266423Sjfv i40e_msix_que, que, &que->tag); 1778266423Sjfv if (error) { 1779266423Sjfv que->res = NULL; 1780266423Sjfv device_printf(dev, "Failed to register que handler"); 1781266423Sjfv return (error); 1782266423Sjfv } 1783266423Sjfv bus_describe_intr(dev, que->res, que->tag, "q%d", i); 1784266423Sjfv /* Bind the vector to a CPU */ 1785266423Sjfv bus_bind_intr(dev, que->res, i); 1786266423Sjfv que->msix = vector; 1787266423Sjfv TASK_INIT(&que->tx_task, 0, i40e_deferred_mq_start, que); 1788266423Sjfv TASK_INIT(&que->task, 0, i40e_handle_que, que); 1789266423Sjfv que->tq = taskqueue_create_fast("i40e_que", M_NOWAIT, 1790266423Sjfv taskqueue_thread_enqueue, &que->tq); 1791266423Sjfv taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 1792266423Sjfv device_get_nameunit(pf->dev)); 1793266423Sjfv } 1794266423Sjfv 1795266423Sjfv return (0); 1796266423Sjfv} 1797266423Sjfv 1798266423Sjfv 1799266423Sjfv/* 1800266423Sjfv * Allocate MSI/X vectors 1801266423Sjfv */ 1802266423Sjfvstatic int 1803266423Sjfvi40e_init_msix(struct i40e_pf *pf) 1804266423Sjfv{ 1805266423Sjfv device_t dev = pf->dev; 1806266423Sjfv int rid, want, vectors, queues, available; 1807266423Sjfv 1808266423Sjfv /* Override by tuneable */ 1809266423Sjfv if (i40e_enable_msix == 0) 1810266423Sjfv goto msi; 1811266423Sjfv 1812266423Sjfv /* First try MSI/X */ 1813266423Sjfv rid = PCIR_BAR(I40E_BAR); 1814266423Sjfv pf->msix_mem = bus_alloc_resource_any(dev, 1815266423Sjfv SYS_RES_MEMORY, &rid, RF_ACTIVE); 1816266423Sjfv if (!pf->msix_mem) { 1817266423Sjfv /* May not be enabled */ 1818266423Sjfv device_printf(pf->dev, 1819266423Sjfv "Unable to map MSIX table \n"); 1820266423Sjfv goto msi; 1821266423Sjfv } 1822266423Sjfv 1823266423Sjfv available = pci_msix_count(dev); 1824266423Sjfv if (available == 0) { /* system has msix disabled */ 1825266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 1826266423Sjfv rid, pf->msix_mem); 1827266423Sjfv pf->msix_mem = NULL; 1828266423Sjfv goto msi; 1829266423Sjfv } 1830266423Sjfv 1831266423Sjfv /* Figure out a reasonable auto config value */ 1832266423Sjfv queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus; 1833266423Sjfv 1834266423Sjfv /* Override with hardcoded value if sane */ 1835266423Sjfv if ((i40e_max_queues != 0) && (i40e_max_queues <= queues)) 1836266423Sjfv queues = i40e_max_queues; 1837266423Sjfv 1838266423Sjfv /* 1839266423Sjfv ** Want one vector (RX/TX pair) per queue 1840266423Sjfv ** plus an additional for the admin queue. 1841266423Sjfv */ 1842266423Sjfv want = queues + 1; 1843266423Sjfv if (want <= available) /* Have enough */ 1844266423Sjfv vectors = want; 1845266423Sjfv else { 1846266423Sjfv device_printf(pf->dev, 1847266423Sjfv "MSIX Configuration Problem, " 1848266423Sjfv "%d vectors available but %d wanted!\n", 1849266423Sjfv available, want); 1850266423Sjfv return (0); /* Will go to Legacy setup */ 1851266423Sjfv } 1852266423Sjfv 1853266423Sjfv // NOTE this is all simplified based on ONE VSI 1854266423Sjfv if (pci_alloc_msix(dev, &vectors) == 0) { 1855266423Sjfv device_printf(pf->dev, 1856266423Sjfv "Using MSIX interrupts with %d vectors\n", vectors); 1857266423Sjfv pf->msix = vectors; 1858266423Sjfv pf->vsi.num_queues = queues; 1859266423Sjfv return (vectors); 1860266423Sjfv } 1861266423Sjfvmsi: 1862266423Sjfv vectors = pci_msi_count(dev); 1863266423Sjfv pf->vsi.num_queues = 1; 1864266423Sjfv pf->msix = 1; 1865266423Sjfv i40e_max_queues = 1; 1866266423Sjfv i40e_enable_msix = 0; 1867266423Sjfv if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) 1868266423Sjfv device_printf(pf->dev,"Using an MSI interrupt\n"); 1869266423Sjfv else { 1870266423Sjfv pf->msix = 0; 1871266423Sjfv device_printf(pf->dev,"Using a Legacy interrupt\n"); 1872266423Sjfv } 1873266423Sjfv return (vectors); 1874266423Sjfv} 1875266423Sjfv 1876266423Sjfv 1877266423Sjfv/* 1878266423Sjfv * Plumb MSI/X vectors 1879266423Sjfv */ 1880266423Sjfvstatic void 1881266423Sjfvi40e_configure_msix(struct i40e_pf *pf) 1882266423Sjfv{ 1883266423Sjfv struct i40e_hw *hw = &pf->hw; 1884266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 1885266423Sjfv u32 reg; 1886266423Sjfv u16 vector = 1; 1887266423Sjfv 1888266423Sjfv /* First set up the adminq - vector 0 */ 1889266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, 0); /* disable all */ 1890266423Sjfv rd32(hw, I40E_PFINT_ICR0); /* read to clear */ 1891266423Sjfv 1892266423Sjfv reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | 1893266423Sjfv I40E_PFINT_ICR0_ENA_GRST_MASK | 1894266423Sjfv I40E_PFINT_ICR0_HMC_ERR_MASK | 1895266423Sjfv I40E_PFINT_ICR0_ENA_ADMINQ_MASK | 1896266423Sjfv I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK | 1897266423Sjfv I40E_PFINT_ICR0_ENA_VFLR_MASK | 1898266423Sjfv I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK; 1899266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 1900266423Sjfv 1901266423Sjfv wr32(hw, I40E_PFINT_LNKLST0, 0x7FF); 1902266423Sjfv wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), 0x003E); 1903266423Sjfv 1904266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, 1905266423Sjfv I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK | 1906266423Sjfv I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK); 1907266423Sjfv 1908266423Sjfv wr32(hw, I40E_PFINT_STAT_CTL0, 0); 1909266423Sjfv 1910266423Sjfv /* Next configure the queues */ 1911266423Sjfv for (int i = 0; i < vsi->num_queues; i++, vector++) { 1912266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(i), i); 1913266423Sjfv wr32(hw, I40E_PFINT_LNKLSTN(i), i); 1914266423Sjfv 1915266423Sjfv reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | 1916266423Sjfv (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | 1917266423Sjfv (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 1918266423Sjfv (i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 1919266423Sjfv (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); 1920266423Sjfv wr32(hw, I40E_QINT_RQCTL(i), reg); 1921266423Sjfv 1922266423Sjfv reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK | 1923266423Sjfv (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | 1924266423Sjfv (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | 1925266423Sjfv ((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | 1926266423Sjfv (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 1927266423Sjfv if (i == (vsi->num_queues - 1)) 1928266423Sjfv reg |= (I40E_QUEUE_EOL 1929266423Sjfv << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 1930266423Sjfv wr32(hw, I40E_QINT_TQCTL(i), reg); 1931266423Sjfv } 1932266423Sjfv} 1933266423Sjfv 1934266423Sjfv/* 1935266423Sjfv * Configure for MSI single vector operation 1936266423Sjfv */ 1937266423Sjfvstatic void 1938266423Sjfvi40e_configure_legacy(struct i40e_pf *pf) 1939266423Sjfv{ 1940266423Sjfv struct i40e_hw *hw = &pf->hw; 1941266423Sjfv u32 reg; 1942266423Sjfv 1943266423Sjfv 1944266423Sjfv wr32(hw, I40E_PFINT_ITR0(0), 0); 1945266423Sjfv wr32(hw, I40E_PFINT_ITR0(1), 0); 1946266423Sjfv 1947266423Sjfv 1948266423Sjfv /* Setup "other" causes */ 1949266423Sjfv reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK 1950266423Sjfv | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK 1951266423Sjfv | I40E_PFINT_ICR0_ENA_GRST_MASK 1952266423Sjfv | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK 1953266423Sjfv | I40E_PFINT_ICR0_ENA_GPIO_MASK 1954266423Sjfv | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK 1955266423Sjfv | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK 1956266423Sjfv | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK 1957266423Sjfv | I40E_PFINT_ICR0_ENA_VFLR_MASK 1958266423Sjfv | I40E_PFINT_ICR0_ENA_ADMINQ_MASK 1959266423Sjfv ; 1960266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 1961266423Sjfv 1962266423Sjfv /* SW_ITR_IDX = 0, but don't change INTENA */ 1963266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, 1964266423Sjfv I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK | 1965266423Sjfv I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK); 1966266423Sjfv /* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */ 1967266423Sjfv wr32(hw, I40E_PFINT_STAT_CTL0, 0); 1968266423Sjfv 1969266423Sjfv /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ 1970266423Sjfv wr32(hw, I40E_PFINT_LNKLST0, 0); 1971266423Sjfv 1972266423Sjfv /* Associate the queue pair to the vector and enable the q int */ 1973266423Sjfv reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK 1974266423Sjfv | (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) 1975266423Sjfv | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 1976266423Sjfv wr32(hw, I40E_QINT_RQCTL(0), reg); 1977266423Sjfv 1978266423Sjfv reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK 1979266423Sjfv | (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) 1980266423Sjfv | (I40E_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); 1981266423Sjfv wr32(hw, I40E_QINT_TQCTL(0), reg); 1982266423Sjfv 1983266423Sjfv /* Next enable the queue pair */ 1984266423Sjfv reg = rd32(hw, I40E_QTX_ENA(0)); 1985266423Sjfv reg |= I40E_QTX_ENA_QENA_REQ_MASK; 1986266423Sjfv wr32(hw, I40E_QTX_ENA(0), reg); 1987266423Sjfv 1988266423Sjfv reg = rd32(hw, I40E_QRX_ENA(0)); 1989266423Sjfv reg |= I40E_QRX_ENA_QENA_REQ_MASK; 1990266423Sjfv wr32(hw, I40E_QRX_ENA(0), reg); 1991266423Sjfv} 1992266423Sjfv 1993266423Sjfv 1994266423Sjfv/* 1995266423Sjfv * Set the Initial ITR state 1996266423Sjfv */ 1997266423Sjfvstatic void 1998266423Sjfvi40e_configure_itr(struct i40e_pf *pf) 1999266423Sjfv{ 2000266423Sjfv struct i40e_hw *hw = &pf->hw; 2001266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 2002266423Sjfv struct i40e_queue *que = vsi->queues; 2003266423Sjfv 2004266423Sjfv vsi->rx_itr_setting = i40e_rx_itr; 2005266423Sjfv if (i40e_dynamic_rx_itr) 2006266423Sjfv vsi->rx_itr_setting |= I40E_ITR_DYNAMIC; 2007266423Sjfv vsi->tx_itr_setting = i40e_tx_itr; 2008266423Sjfv if (i40e_dynamic_tx_itr) 2009266423Sjfv vsi->tx_itr_setting |= I40E_ITR_DYNAMIC; 2010266423Sjfv 2011266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2012266423Sjfv struct tx_ring *txr = &que->txr; 2013266423Sjfv struct rx_ring *rxr = &que->rxr; 2014266423Sjfv 2015266423Sjfv wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, i), 2016266423Sjfv vsi->rx_itr_setting); 2017266423Sjfv rxr->itr = vsi->rx_itr_setting; 2018266423Sjfv rxr->latency = I40E_AVE_LATENCY; 2019266423Sjfv wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, i), 2020266423Sjfv vsi->tx_itr_setting); 2021266423Sjfv txr->itr = vsi->tx_itr_setting; 2022266423Sjfv txr->latency = I40E_AVE_LATENCY; 2023266423Sjfv } 2024266423Sjfv} 2025266423Sjfv 2026266423Sjfv 2027266423Sjfvstatic int 2028266423Sjfvi40e_allocate_pci_resources(struct i40e_pf *pf) 2029266423Sjfv{ 2030266423Sjfv int rid; 2031266423Sjfv device_t dev = pf->dev; 2032266423Sjfv 2033266423Sjfv rid = PCIR_BAR(0); 2034266423Sjfv pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2035266423Sjfv &rid, RF_ACTIVE); 2036266423Sjfv 2037266423Sjfv if (!(pf->pci_mem)) { 2038266423Sjfv device_printf(dev,"Unable to allocate bus resource: memory\n"); 2039266423Sjfv return (ENXIO); 2040266423Sjfv } 2041266423Sjfv 2042266423Sjfv pf->osdep.mem_bus_space_tag = 2043266423Sjfv rman_get_bustag(pf->pci_mem); 2044266423Sjfv pf->osdep.mem_bus_space_handle = 2045266423Sjfv rman_get_bushandle(pf->pci_mem); 2046266423Sjfv pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; 2047266423Sjfv 2048266423Sjfv pf->hw.back = &pf->osdep; 2049266423Sjfv 2050266423Sjfv /* 2051266423Sjfv ** Now setup MSI or MSI/X, should 2052266423Sjfv ** return us the number of supported 2053266423Sjfv ** vectors. (Will be 1 for MSI) 2054266423Sjfv */ 2055266423Sjfv pf->msix = i40e_init_msix(pf); 2056266423Sjfv return (0); 2057266423Sjfv} 2058266423Sjfv 2059266423Sjfvstatic void 2060266423Sjfvi40e_free_pci_resources(struct i40e_pf * pf) 2061266423Sjfv{ 2062266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 2063266423Sjfv struct i40e_queue *que = vsi->queues; 2064266423Sjfv device_t dev = pf->dev; 2065266423Sjfv int rid, memrid; 2066266423Sjfv 2067266423Sjfv memrid = PCIR_BAR(I40E_BAR); 2068266423Sjfv 2069266423Sjfv /* We may get here before stations are setup */ 2070266423Sjfv if ((!i40e_enable_msix) || (que == NULL)) 2071266423Sjfv goto early; 2072266423Sjfv 2073266423Sjfv /* 2074266423Sjfv ** Release all msix VSI resources: 2075266423Sjfv */ 2076266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2077266423Sjfv rid = que->msix + 1; 2078266423Sjfv if (que->tag != NULL) { 2079266423Sjfv bus_teardown_intr(dev, que->res, que->tag); 2080266423Sjfv que->tag = NULL; 2081266423Sjfv } 2082266423Sjfv if (que->res != NULL) 2083266423Sjfv bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2084266423Sjfv } 2085266423Sjfv 2086266423Sjfvearly: 2087266423Sjfv /* Clean the AdminQ interrupt last */ 2088266423Sjfv if (pf->admvec) /* we are doing MSIX */ 2089266423Sjfv rid = pf->admvec + 1; 2090266423Sjfv else 2091266423Sjfv (pf->msix != 0) ? (rid = 1):(rid = 0); 2092266423Sjfv 2093266423Sjfv if (pf->tag != NULL) { 2094266423Sjfv bus_teardown_intr(dev, pf->res, pf->tag); 2095266423Sjfv pf->tag = NULL; 2096266423Sjfv } 2097266423Sjfv if (pf->res != NULL) 2098266423Sjfv bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); 2099266423Sjfv 2100266423Sjfv if (pf->msix) 2101266423Sjfv pci_release_msi(dev); 2102266423Sjfv 2103266423Sjfv if (pf->msix_mem != NULL) 2104266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 2105266423Sjfv memrid, pf->msix_mem); 2106266423Sjfv 2107266423Sjfv if (pf->pci_mem != NULL) 2108266423Sjfv bus_release_resource(dev, SYS_RES_MEMORY, 2109266423Sjfv PCIR_BAR(0), pf->pci_mem); 2110266423Sjfv 2111266423Sjfv return; 2112266423Sjfv} 2113266423Sjfv 2114266423Sjfv 2115266423Sjfv/********************************************************************* 2116266423Sjfv * 2117266423Sjfv * Setup networking device structure and register an interface. 2118266423Sjfv * 2119266423Sjfv **********************************************************************/ 2120266423Sjfvstatic int 2121266423Sjfvi40e_setup_interface(device_t dev, struct i40e_vsi *vsi) 2122266423Sjfv{ 2123266423Sjfv struct ifnet *ifp; 2124266423Sjfv struct i40e_hw *hw = vsi->hw; 2125266423Sjfv struct i40e_queue *que = vsi->queues; 2126266423Sjfv struct i40e_aq_get_phy_abilities_resp abilities_resp; 2127266423Sjfv enum i40e_status_code aq_error = 0; 2128266423Sjfv 2129266423Sjfv INIT_DEBUGOUT("i40e_setup_interface: begin"); 2130266423Sjfv 2131266423Sjfv ifp = vsi->ifp = if_alloc(IFT_ETHER); 2132266423Sjfv if (ifp == NULL) { 2133266423Sjfv device_printf(dev, "can not allocate ifnet structure\n"); 2134266423Sjfv return (-1); 2135266423Sjfv } 2136266423Sjfv if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2137266423Sjfv ifp->if_mtu = ETHERMTU; 2138266423Sjfv ifp->if_baudrate = 4000000000; // ?? 2139266423Sjfv ifp->if_init = i40e_init; 2140266423Sjfv ifp->if_softc = vsi; 2141266423Sjfv ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2142266423Sjfv ifp->if_ioctl = i40e_ioctl; 2143266423Sjfv 2144266423Sjfv ifp->if_transmit = i40e_mq_start; 2145266423Sjfv 2146266423Sjfv ifp->if_qflush = i40e_qflush; 2147266423Sjfv 2148266423Sjfv ifp->if_snd.ifq_maxlen = que->num_desc - 2; 2149266423Sjfv 2150266423Sjfv ether_ifattach(ifp, hw->mac.addr); 2151266423Sjfv 2152266423Sjfv vsi->max_frame_size = 2153266423Sjfv ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN 2154266423Sjfv + ETHER_VLAN_ENCAP_LEN; 2155266423Sjfv 2156266423Sjfv /* 2157266423Sjfv * Tell the upper layer(s) we support long frames. 2158266423Sjfv */ 2159266423Sjfv ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 2160266423Sjfv 2161266423Sjfv ifp->if_capabilities |= IFCAP_HWCSUM; 2162266423Sjfv ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; 2163266423Sjfv ifp->if_capabilities |= IFCAP_TSO; 2164266423Sjfv ifp->if_capabilities |= IFCAP_JUMBO_MTU; 2165266423Sjfv ifp->if_capabilities |= IFCAP_LRO; 2166266423Sjfv 2167266423Sjfv /* VLAN capabilties */ 2168266423Sjfv ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 2169266423Sjfv | IFCAP_VLAN_HWTSO 2170266423Sjfv | IFCAP_VLAN_MTU 2171266423Sjfv | IFCAP_VLAN_HWCSUM; 2172266423Sjfv ifp->if_capenable = ifp->if_capabilities; 2173266423Sjfv 2174266423Sjfv /* 2175266423Sjfv ** Don't turn this on by default, if vlans are 2176266423Sjfv ** created on another pseudo device (eg. lagg) 2177266423Sjfv ** then vlan events are not passed thru, breaking 2178266423Sjfv ** operation, but with HW FILTER off it works. If 2179266423Sjfv ** using vlans directly on the i40e driver you can 2180266423Sjfv ** enable this and get full hardware tag filtering. 2181266423Sjfv */ 2182266423Sjfv ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 2183266423Sjfv 2184266423Sjfv /* 2185266423Sjfv * Specify the media types supported by this adapter and register 2186266423Sjfv * callbacks to update media and link information 2187266423Sjfv */ 2188266423Sjfv ifmedia_init(&vsi->media, IFM_IMASK, i40e_media_change, 2189266423Sjfv i40e_media_status); 2190266423Sjfv 2191266423Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, TRUE, &abilities_resp, NULL); 2192266423Sjfv if (aq_error) { 2193266423Sjfv printf("Error getting supported media types, AQ error %d\n", aq_error); 2194266423Sjfv return (EPERM); 2195266423Sjfv } 2196266423Sjfv 2197266423Sjfv /* Display PHY's supported media types */ 2198266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_100BASE_TX)) 2199266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2200266423Sjfv 2201266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_1000BASE_T)) 2202266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); 2203266423Sjfv 2204266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) || 2205266423Sjfv abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU)) 2206266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2207266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR)) 2208266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2209266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR)) 2210266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2211266423Sjfv 2212266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) || 2213266423Sjfv abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4)) 2214266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); 2215266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4)) 2216266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); 2217266423Sjfv if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4)) 2218266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); 2219266423Sjfv 2220266423Sjfv /* Use autoselect media by default */ 2221266423Sjfv ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2222266423Sjfv ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); 2223266423Sjfv 2224266423Sjfv return (0); 2225266423Sjfv} 2226266423Sjfv 2227266423Sjfvstatic bool 2228266423Sjfvi40e_config_link(struct i40e_hw *hw) 2229266423Sjfv{ 2230266423Sjfv bool check; 2231266423Sjfv 2232266423Sjfv i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 2233266423Sjfv check = i40e_get_link_status(hw); 2234266423Sjfv#ifdef I40E_DEBUG 2235266423Sjfv printf("Link is %s\n", check ? "up":"down"); 2236266423Sjfv#endif 2237266423Sjfv return (check); 2238266423Sjfv} 2239266423Sjfv 2240266423Sjfv/********************************************************************* 2241266423Sjfv * 2242266423Sjfv * Initialize this VSI 2243266423Sjfv * 2244266423Sjfv **********************************************************************/ 2245266423Sjfvstatic int 2246266423Sjfvi40e_setup_vsi(struct i40e_vsi *vsi) 2247266423Sjfv{ 2248266423Sjfv struct i40e_hw *hw = vsi->hw; 2249266423Sjfv device_t dev = vsi->dev; 2250266423Sjfv struct i40e_aqc_get_switch_config_resp *sw_config; 2251266423Sjfv struct i40e_vsi_context ctxt; 2252266423Sjfv u8 aq_buf[I40E_AQ_LARGE_BUF]; 2253266423Sjfv int ret = I40E_SUCCESS; 2254266423Sjfv u16 next = 0; 2255266423Sjfv 2256266423Sjfv sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 2257266423Sjfv ret = i40e_aq_get_switch_config(hw, sw_config, 2258266423Sjfv sizeof(aq_buf), &next, NULL); 2259266423Sjfv if (ret) { 2260266423Sjfv device_printf(dev,"aq_get_switch_config failed!!\n"); 2261266423Sjfv return (ret); 2262266423Sjfv } 2263266423Sjfv#ifdef I40E_DEBUG 2264266423Sjfv printf("Switch config: header reported: %d in structure, %d total\n", 2265266423Sjfv sw_config->header.num_reported, sw_config->header.num_total); 2266266423Sjfv printf("type=%d seid=%d uplink=%d downlink=%d\n", 2267266423Sjfv sw_config->element[0].element_type, 2268266423Sjfv sw_config->element[0].seid, 2269266423Sjfv sw_config->element[0].uplink_seid, 2270266423Sjfv sw_config->element[0].downlink_seid); 2271266423Sjfv#endif 2272266423Sjfv /* Save off this important value */ 2273266423Sjfv vsi->seid = sw_config->element[0].seid; 2274266423Sjfv 2275266423Sjfv memset(&ctxt, 0, sizeof(ctxt)); 2276266423Sjfv ctxt.seid = vsi->seid; 2277266423Sjfv ctxt.pf_num = hw->pf_id; 2278266423Sjfv ret = i40e_aq_get_vsi_params(hw, &ctxt, NULL); 2279266423Sjfv if (ret) { 2280266423Sjfv device_printf(dev,"get vsi params failed %x!!\n", ret); 2281266423Sjfv return (ret); 2282266423Sjfv } 2283266423Sjfv#ifdef I40E_DEBUG 2284266423Sjfv printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, " 2285266423Sjfv "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, " 2286266423Sjfv "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid, 2287266423Sjfv ctxt.uplink_seid, ctxt.vsi_number, 2288266423Sjfv ctxt.vsis_allocated, ctxt.vsis_unallocated, 2289266423Sjfv ctxt.flags, ctxt.pf_num, ctxt.vf_num, 2290266423Sjfv ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits); 2291266423Sjfv#endif 2292266423Sjfv /* 2293266423Sjfv ** Set the queue and traffic class bits 2294266423Sjfv ** - when multiple traffic classes are supported 2295266423Sjfv ** this will need to be more robust. 2296266423Sjfv */ 2297266423Sjfv ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID; 2298266423Sjfv ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG; 2299266423Sjfv ctxt.info.queue_mapping[0] = 0; 2300266423Sjfv ctxt.info.tc_mapping[0] = 0x0800; 2301266423Sjfv 2302266423Sjfv /* Set VLAN receive stripping mode */ 2303266423Sjfv ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; 2304266423Sjfv ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; 2305266423Sjfv if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 2306266423Sjfv ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; 2307266423Sjfv else 2308266423Sjfv ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 2309266423Sjfv 2310266423Sjfv /* Keep copy of VSI info in VSI for statistic counters */ 2311266423Sjfv memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); 2312266423Sjfv 2313266423Sjfv /* Reset VSI statistics */ 2314266423Sjfv i40e_vsi_reset_stats(vsi); 2315266423Sjfv vsi->hw_filters_add = 0; 2316266423Sjfv vsi->hw_filters_del = 0; 2317266423Sjfv 2318266423Sjfv ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); 2319266423Sjfv if (ret) 2320266423Sjfv device_printf(dev,"update vsi params failed %x!!\n", 2321266423Sjfv hw->aq.asq_last_status); 2322266423Sjfv return (ret); 2323266423Sjfv} 2324266423Sjfv 2325266423Sjfv 2326266423Sjfv/********************************************************************* 2327266423Sjfv * 2328266423Sjfv * Initialize the VSI: this handles contexts, which means things 2329266423Sjfv * like the number of descriptors, buffer size, 2330266423Sjfv * plus we init the rings thru this function. 2331266423Sjfv * 2332266423Sjfv **********************************************************************/ 2333266423Sjfvstatic int 2334266423Sjfvi40e_initialize_vsi(struct i40e_vsi *vsi) 2335266423Sjfv{ 2336266423Sjfv struct i40e_queue *que = vsi->queues; 2337266423Sjfv device_t dev = vsi->dev; 2338266423Sjfv struct i40e_hw *hw = vsi->hw; 2339266423Sjfv int err = 0; 2340266423Sjfv 2341266423Sjfv 2342266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2343266423Sjfv struct tx_ring *txr = &que->txr; 2344266423Sjfv struct rx_ring *rxr = &que->rxr; 2345266423Sjfv struct i40e_hmc_obj_txq tctx; 2346266423Sjfv struct i40e_hmc_obj_rxq rctx; 2347266423Sjfv u32 txctl; 2348266423Sjfv u16 size; 2349266423Sjfv 2350266423Sjfv 2351266423Sjfv /* Setup the HMC TX Context */ 2352266423Sjfv size = que->num_desc * sizeof(struct i40e_tx_desc); 2353266423Sjfv memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq)); 2354266423Sjfv tctx.new_context = 1; 2355266423Sjfv tctx.base = (txr->dma.pa/128); 2356266423Sjfv tctx.qlen = que->num_desc; 2357266423Sjfv tctx.fc_ena = 0; 2358266423Sjfv tctx.rdylist = vsi->info.qs_handle[0]; 2359266423Sjfv tctx.rdylist_act = 0; 2360266423Sjfv err = i40e_clear_lan_tx_queue_context(hw, i); 2361266423Sjfv if (err) { 2362266423Sjfv device_printf(dev, "Unable to clear TX context\n"); 2363266423Sjfv break; 2364266423Sjfv } 2365266423Sjfv err = i40e_set_lan_tx_queue_context(hw, i, &tctx); 2366266423Sjfv if (err) { 2367266423Sjfv device_printf(dev, "Unable to set TX context\n"); 2368266423Sjfv break; 2369266423Sjfv } 2370266423Sjfv /* Associate the ring with this PF */ 2371266423Sjfv txctl = I40E_QTX_CTL_PF_QUEUE; 2372266423Sjfv txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & 2373266423Sjfv I40E_QTX_CTL_PF_INDX_MASK); 2374266423Sjfv wr32(hw, I40E_QTX_CTL(i), txctl); 2375266423Sjfv i40e_flush(hw); 2376266423Sjfv 2377266423Sjfv /* Do ring (re)init */ 2378266423Sjfv i40e_init_tx_ring(que); 2379266423Sjfv 2380266423Sjfv /* Next setup the HMC RX Context */ 2381266423Sjfv if (vsi->max_frame_size <= 2048) 2382266423Sjfv rxr->mbuf_sz = MCLBYTES; 2383266423Sjfv else 2384266423Sjfv rxr->mbuf_sz = MJUMPAGESIZE; 2385266423Sjfv 2386266423Sjfv u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len; 2387266423Sjfv 2388266423Sjfv /* Set up an RX context for the HMC */ 2389266423Sjfv memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq)); 2390266423Sjfv rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT; 2391266423Sjfv /* ignore header split for now */ 2392266423Sjfv rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; 2393266423Sjfv rctx.rxmax = (vsi->max_frame_size < max_rxmax) ? 2394266423Sjfv vsi->max_frame_size : max_rxmax; 2395266423Sjfv rctx.dtype = 0; 2396266423Sjfv rctx.dsize = 1; /* do 32byte descriptors */ 2397266423Sjfv rctx.hsplit_0 = 0; /* no HDR split initially */ 2398266423Sjfv rctx.base = (rxr->dma.pa/128); 2399266423Sjfv rctx.qlen = que->num_desc; 2400266423Sjfv rctx.tphrdesc_ena = 1; 2401266423Sjfv rctx.tphwdesc_ena = 1; 2402266423Sjfv rctx.tphdata_ena = 0; 2403266423Sjfv rctx.tphhead_ena = 0; 2404266423Sjfv#ifdef FORTVILLE_A0_SUPPORT 2405266423Sjfv rctx.lrxqthresh = 0; 2406266423Sjfv#else 2407266423Sjfv rctx.lrxqthresh = 2; 2408266423Sjfv#endif 2409266423Sjfv rctx.crcstrip = 1; 2410266423Sjfv rctx.l2tsel = 1; 2411266423Sjfv rctx.showiv = 1; 2412266423Sjfv rctx.fc_ena = 0; 2413266423Sjfv rctx.prefena = 1; 2414266423Sjfv 2415266423Sjfv err = i40e_clear_lan_rx_queue_context(hw, i); 2416266423Sjfv if (err) { 2417266423Sjfv device_printf(dev, 2418266423Sjfv "Unable to clear RX context %d\n", i); 2419266423Sjfv break; 2420266423Sjfv } 2421266423Sjfv err = i40e_set_lan_rx_queue_context(hw, i, &rctx); 2422266423Sjfv if (err) { 2423266423Sjfv device_printf(dev, "Unable to set RX context %d\n", i); 2424266423Sjfv break; 2425266423Sjfv } 2426266423Sjfv err = i40e_init_rx_ring(que); 2427266423Sjfv if (err) { 2428266423Sjfv device_printf(dev, "Fail in init_rx_ring %d\n", i); 2429266423Sjfv break; 2430266423Sjfv } 2431266423Sjfv wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0); 2432266423Sjfv wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1); 2433266423Sjfv } 2434266423Sjfv return (err); 2435266423Sjfv} 2436266423Sjfv 2437266423Sjfv 2438266423Sjfv/********************************************************************* 2439266423Sjfv * 2440266423Sjfv * Free all VSI structs. 2441266423Sjfv * 2442266423Sjfv **********************************************************************/ 2443266423Sjfvvoid 2444266423Sjfvi40e_free_vsi(struct i40e_vsi *vsi) 2445266423Sjfv{ 2446266423Sjfv struct i40e_pf *pf = (struct i40e_pf *)vsi->back; 2447266423Sjfv struct i40e_queue *que = vsi->queues; 2448266423Sjfv struct i40e_mac_filter *f; 2449266423Sjfv 2450266423Sjfv /* Free station queues */ 2451266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) { 2452266423Sjfv struct tx_ring *txr = &que->txr; 2453266423Sjfv struct rx_ring *rxr = &que->rxr; 2454266423Sjfv 2455266423Sjfv if (!mtx_initialized(&txr->mtx)) /* uninitialized */ 2456266423Sjfv continue; 2457266423Sjfv I40E_TX_LOCK(txr); 2458266423Sjfv i40e_free_que_tx(que); 2459266423Sjfv if (txr->base) 2460266423Sjfv i40e_free_dma(&pf->hw, &txr->dma); 2461266423Sjfv I40E_TX_UNLOCK(txr); 2462266423Sjfv I40E_TX_LOCK_DESTROY(txr); 2463266423Sjfv 2464266423Sjfv if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ 2465266423Sjfv continue; 2466266423Sjfv I40E_RX_LOCK(rxr); 2467266423Sjfv i40e_free_que_rx(que); 2468266423Sjfv if (rxr->base) 2469266423Sjfv i40e_free_dma(&pf->hw, &rxr->dma); 2470266423Sjfv I40E_RX_UNLOCK(rxr); 2471266423Sjfv I40E_RX_LOCK_DESTROY(rxr); 2472266423Sjfv 2473266423Sjfv } 2474266423Sjfv free(vsi->queues, M_DEVBUF); 2475266423Sjfv 2476266423Sjfv /* Free VSI filter list */ 2477266423Sjfv while (!SLIST_EMPTY(&vsi->ftl)) { 2478266423Sjfv f = SLIST_FIRST(&vsi->ftl); 2479266423Sjfv SLIST_REMOVE_HEAD(&vsi->ftl, next); 2480266423Sjfv free(f, M_DEVBUF); 2481266423Sjfv } 2482266423Sjfv} 2483266423Sjfv 2484266423Sjfv 2485266423Sjfv/********************************************************************* 2486266423Sjfv * 2487266423Sjfv * Allocate memory for the VSI (virtual station interface) and their 2488266423Sjfv * associated queues, rings and the descriptors associated with each, 2489266423Sjfv * called only once at attach. 2490266423Sjfv * 2491266423Sjfv **********************************************************************/ 2492266423Sjfvstatic int 2493266423Sjfvi40e_setup_stations(struct i40e_pf *pf) 2494266423Sjfv{ 2495266423Sjfv device_t dev = pf->dev; 2496266423Sjfv struct i40e_vsi *vsi; 2497266423Sjfv struct i40e_queue *que; 2498266423Sjfv struct tx_ring *txr; 2499266423Sjfv struct rx_ring *rxr; 2500266423Sjfv int rsize, tsize; 2501266423Sjfv int error = I40E_SUCCESS; 2502266423Sjfv 2503266423Sjfv vsi = &pf->vsi; 2504266423Sjfv vsi->back = (void *)pf; 2505266423Sjfv vsi->hw = &pf->hw; 2506266423Sjfv vsi->id = 0; 2507266423Sjfv vsi->num_vlans = 0; 2508266423Sjfv 2509266423Sjfv /* Get memory for the station queues */ 2510266423Sjfv if (!(vsi->queues = 2511266423Sjfv (struct i40e_queue *) malloc(sizeof(struct i40e_queue) * 2512266423Sjfv vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { 2513266423Sjfv device_printf(dev, "Unable to allocate queue memory\n"); 2514266423Sjfv error = ENOMEM; 2515266423Sjfv goto early; 2516266423Sjfv } 2517266423Sjfv 2518266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 2519266423Sjfv que = &vsi->queues[i]; 2520266423Sjfv que->num_desc = i40e_ringsz; 2521266423Sjfv que->me = i; 2522266423Sjfv que->vsi = vsi; 2523266423Sjfv txr = &que->txr; 2524266423Sjfv txr->que = que; 2525266423Sjfv 2526266423Sjfv /* Initialize the TX lock */ 2527266423Sjfv snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", 2528266423Sjfv device_get_nameunit(dev), que->me); 2529266423Sjfv mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF); 2530266423Sjfv /* Create the TX descriptor ring */ 2531266423Sjfv tsize = roundup2(que->num_desc * 2532266423Sjfv sizeof(struct i40e_tx_desc), DBA_ALIGN); 2533266423Sjfv if (i40e_allocate_dma(&pf->hw, 2534266423Sjfv &txr->dma, tsize, DBA_ALIGN)) { 2535266423Sjfv device_printf(dev, 2536266423Sjfv "Unable to allocate TX Descriptor memory\n"); 2537266423Sjfv error = ENOMEM; 2538266423Sjfv goto fail; 2539266423Sjfv } 2540266423Sjfv txr->base = (struct i40e_tx_desc *)txr->dma.va; 2541266423Sjfv bzero((void *)txr->base, tsize); 2542266423Sjfv /* Now allocate transmit soft structs for the ring */ 2543266423Sjfv if (i40e_allocate_tx_data(que)) { 2544266423Sjfv device_printf(dev, 2545266423Sjfv "Critical Failure setting up TX structures\n"); 2546266423Sjfv error = ENOMEM; 2547266423Sjfv goto fail; 2548266423Sjfv } 2549266423Sjfv /* Allocate a buf ring */ 2550266423Sjfv txr->br = buf_ring_alloc(4096, M_DEVBUF, 2551266423Sjfv M_WAITOK, &txr->mtx); 2552266423Sjfv if (txr->br == NULL) { 2553266423Sjfv device_printf(dev, 2554266423Sjfv "Critical Failure setting up TX buf ring\n"); 2555266423Sjfv error = ENOMEM; 2556266423Sjfv goto fail; 2557266423Sjfv } 2558266423Sjfv 2559266423Sjfv /* 2560266423Sjfv * Next the RX queues... 2561266423Sjfv */ 2562266423Sjfv rsize = roundup2(que->num_desc * 2563266423Sjfv sizeof(union i40e_rx_desc), DBA_ALIGN); 2564266423Sjfv rxr = &que->rxr; 2565266423Sjfv rxr->que = que; 2566266423Sjfv 2567266423Sjfv /* Initialize the RX side lock */ 2568266423Sjfv snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", 2569266423Sjfv device_get_nameunit(dev), que->me); 2570266423Sjfv mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF); 2571266423Sjfv 2572266423Sjfv if (i40e_allocate_dma(&pf->hw, 2573266423Sjfv &rxr->dma, rsize, 4096)) { 2574266423Sjfv device_printf(dev, 2575266423Sjfv "Unable to allocate RX Descriptor memory\n"); 2576266423Sjfv error = ENOMEM; 2577266423Sjfv goto fail; 2578266423Sjfv } 2579266423Sjfv rxr->base = (union i40e_rx_desc *)rxr->dma.va; 2580266423Sjfv bzero((void *)rxr->base, rsize); 2581266423Sjfv 2582266423Sjfv /* Allocate receive soft structs for the ring*/ 2583266423Sjfv if (i40e_allocate_rx_data(que)) { 2584266423Sjfv device_printf(dev, 2585266423Sjfv "Critical Failure setting up receive structs\n"); 2586266423Sjfv error = ENOMEM; 2587266423Sjfv goto fail; 2588266423Sjfv } 2589266423Sjfv } 2590266423Sjfv 2591266423Sjfv return (0); 2592266423Sjfv 2593266423Sjfvfail: 2594266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 2595266423Sjfv que = &vsi->queues[i]; 2596266423Sjfv rxr = &que->rxr; 2597266423Sjfv txr = &que->txr; 2598266423Sjfv if (rxr->base) 2599266423Sjfv i40e_free_dma(&pf->hw, &rxr->dma); 2600266423Sjfv if (txr->base) 2601266423Sjfv i40e_free_dma(&pf->hw, &txr->dma); 2602266423Sjfv } 2603266423Sjfv 2604266423Sjfvearly: 2605266423Sjfv return (error); 2606266423Sjfv} 2607266423Sjfv 2608266423Sjfv/* 2609266423Sjfv** Provide a update to the queue RX 2610266423Sjfv** interrupt moderation value. 2611266423Sjfv*/ 2612266423Sjfvstatic void 2613266423Sjfvi40e_set_queue_rx_itr(struct i40e_queue *que) 2614266423Sjfv{ 2615266423Sjfv struct i40e_vsi *vsi = que->vsi; 2616266423Sjfv struct i40e_hw *hw = vsi->hw; 2617266423Sjfv struct rx_ring *rxr = &que->rxr; 2618266423Sjfv u16 rx_itr; 2619266423Sjfv u16 rx_latency = 0; 2620266423Sjfv int rx_bytes; 2621266423Sjfv 2622266423Sjfv 2623266423Sjfv /* Idle, do nothing */ 2624266423Sjfv if (rxr->bytes == 0) 2625266423Sjfv return; 2626266423Sjfv 2627266423Sjfv if (i40e_dynamic_rx_itr) { 2628266423Sjfv rx_bytes = rxr->bytes/rxr->itr; 2629266423Sjfv rx_itr = rxr->itr; 2630266423Sjfv 2631266423Sjfv /* Adjust latency range */ 2632266423Sjfv switch (rxr->latency) { 2633266423Sjfv case I40E_LOW_LATENCY: 2634266423Sjfv if (rx_bytes > 10) { 2635266423Sjfv rx_latency = I40E_AVE_LATENCY; 2636266423Sjfv rx_itr = I40E_ITR_20K; 2637266423Sjfv } 2638266423Sjfv break; 2639266423Sjfv case I40E_AVE_LATENCY: 2640266423Sjfv if (rx_bytes > 20) { 2641266423Sjfv rx_latency = I40E_BULK_LATENCY; 2642266423Sjfv rx_itr = I40E_ITR_8K; 2643266423Sjfv } else if (rx_bytes <= 10) { 2644266423Sjfv rx_latency = I40E_LOW_LATENCY; 2645266423Sjfv rx_itr = I40E_ITR_100K; 2646266423Sjfv } 2647266423Sjfv break; 2648266423Sjfv case I40E_BULK_LATENCY: 2649266423Sjfv if (rx_bytes <= 20) { 2650266423Sjfv rx_latency = I40E_AVE_LATENCY; 2651266423Sjfv rx_itr = I40E_ITR_20K; 2652266423Sjfv } 2653266423Sjfv break; 2654266423Sjfv } 2655266423Sjfv 2656266423Sjfv rxr->latency = rx_latency; 2657266423Sjfv 2658266423Sjfv if (rx_itr != rxr->itr) { 2659266423Sjfv /* do an exponential smoothing */ 2660266423Sjfv rx_itr = (10 * rx_itr * rxr->itr) / 2661266423Sjfv ((9 * rx_itr) + rxr->itr); 2662266423Sjfv rxr->itr = rx_itr & I40E_MAX_ITR; 2663266423Sjfv wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, 2664266423Sjfv que->me), rxr->itr); 2665266423Sjfv } 2666266423Sjfv } else { /* We may have have toggled to non-dynamic */ 2667266423Sjfv if (vsi->rx_itr_setting & I40E_ITR_DYNAMIC) 2668266423Sjfv vsi->rx_itr_setting = i40e_rx_itr; 2669266423Sjfv /* Update the hardware if needed */ 2670266423Sjfv if (rxr->itr != vsi->rx_itr_setting) { 2671266423Sjfv rxr->itr = vsi->rx_itr_setting; 2672266423Sjfv wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, 2673266423Sjfv que->me), rxr->itr); 2674266423Sjfv } 2675266423Sjfv } 2676266423Sjfv rxr->bytes = 0; 2677266423Sjfv rxr->packets = 0; 2678266423Sjfv return; 2679266423Sjfv} 2680266423Sjfv 2681266423Sjfv 2682266423Sjfv/* 2683266423Sjfv** Provide a update to the queue TX 2684266423Sjfv** interrupt moderation value. 2685266423Sjfv*/ 2686266423Sjfvstatic void 2687266423Sjfvi40e_set_queue_tx_itr(struct i40e_queue *que) 2688266423Sjfv{ 2689266423Sjfv struct i40e_vsi *vsi = que->vsi; 2690266423Sjfv struct i40e_hw *hw = vsi->hw; 2691266423Sjfv struct tx_ring *txr = &que->txr; 2692266423Sjfv u16 tx_itr; 2693266423Sjfv u16 tx_latency = 0; 2694266423Sjfv int tx_bytes; 2695266423Sjfv 2696266423Sjfv 2697266423Sjfv /* Idle, do nothing */ 2698266423Sjfv if (txr->bytes == 0) 2699266423Sjfv return; 2700266423Sjfv 2701266423Sjfv if (i40e_dynamic_rx_itr) { 2702266423Sjfv tx_bytes = txr->bytes/txr->itr; 2703266423Sjfv tx_itr = txr->itr; 2704266423Sjfv 2705266423Sjfv switch (txr->latency) { 2706266423Sjfv case I40E_LOW_LATENCY: 2707266423Sjfv if (tx_bytes > 10) { 2708266423Sjfv tx_latency = I40E_AVE_LATENCY; 2709266423Sjfv tx_itr = I40E_ITR_20K; 2710266423Sjfv } 2711266423Sjfv break; 2712266423Sjfv case I40E_AVE_LATENCY: 2713266423Sjfv if (tx_bytes > 20) { 2714266423Sjfv tx_latency = I40E_BULK_LATENCY; 2715266423Sjfv tx_itr = I40E_ITR_8K; 2716266423Sjfv } else if (tx_bytes <= 10) { 2717266423Sjfv tx_latency = I40E_LOW_LATENCY; 2718266423Sjfv tx_itr = I40E_ITR_100K; 2719266423Sjfv } 2720266423Sjfv break; 2721266423Sjfv case I40E_BULK_LATENCY: 2722266423Sjfv if (tx_bytes <= 20) { 2723266423Sjfv tx_latency = I40E_AVE_LATENCY; 2724266423Sjfv tx_itr = I40E_ITR_20K; 2725266423Sjfv } 2726266423Sjfv break; 2727266423Sjfv } 2728266423Sjfv 2729266423Sjfv txr->latency = tx_latency; 2730266423Sjfv 2731266423Sjfv if (tx_itr != txr->itr) { 2732266423Sjfv /* do an exponential smoothing */ 2733266423Sjfv tx_itr = (10 * tx_itr * txr->itr) / 2734266423Sjfv ((9 * tx_itr) + txr->itr); 2735266423Sjfv txr->itr = tx_itr & I40E_MAX_ITR; 2736266423Sjfv wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, 2737266423Sjfv que->me), txr->itr); 2738266423Sjfv } 2739266423Sjfv 2740266423Sjfv } else { /* We may have have toggled to non-dynamic */ 2741266423Sjfv if (vsi->tx_itr_setting & I40E_ITR_DYNAMIC) 2742266423Sjfv vsi->tx_itr_setting = i40e_tx_itr; 2743266423Sjfv /* Update the hardware if needed */ 2744266423Sjfv if (txr->itr != vsi->tx_itr_setting) { 2745266423Sjfv txr->itr = vsi->tx_itr_setting; 2746266423Sjfv wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, 2747266423Sjfv que->me), txr->itr); 2748266423Sjfv } 2749266423Sjfv } 2750266423Sjfv txr->bytes = 0; 2751266423Sjfv txr->packets = 0; 2752266423Sjfv return; 2753266423Sjfv} 2754266423Sjfv 2755266423Sjfv 2756266423Sjfvstatic void 2757266423Sjfvi40e_add_hw_stats(struct i40e_pf *pf) 2758266423Sjfv{ 2759266423Sjfv device_t dev = pf->dev; 2760266423Sjfv 2761266423Sjfv struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 2762266423Sjfv struct sysctl_oid *tree = device_get_sysctl_tree(dev); 2763266423Sjfv struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 2764266423Sjfv 2765266423Sjfv struct sysctl_oid *vsi_node, *queue_node; 2766266423Sjfv struct sysctl_oid_list *vsi_list, *queue_list; 2767266423Sjfv 2768266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 2769266423Sjfv struct i40e_eth_stats *vsi_stats = &vsi->eth_stats; 2770266423Sjfv struct i40e_hw_port_stats *pf_stats = &pf->stats; 2771266423Sjfv 2772266423Sjfv /* Driver statistics */ 2773266423Sjfv SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 2774266423Sjfv CTLFLAG_RD, &pf->watchdog_events, 2775266423Sjfv "Watchdog timeouts"); 2776266423Sjfv SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq", 2777266423Sjfv CTLFLAG_RD, &pf->admin_irq, 2778266423Sjfv "Admin Queue IRQ Handled"); 2779266423Sjfv 2780266423Sjfv /* VSI statistics */ 2781266423Sjfv#define QUEUE_NAME_LEN 32 2782266423Sjfv char vsi_namebuf[QUEUE_NAME_LEN]; 2783266423Sjfv char queue_namebuf[QUEUE_NAME_LEN]; 2784266423Sjfv 2785266423Sjfv snprintf(vsi_namebuf, QUEUE_NAME_LEN, "vsi%d", vsi->info.stat_counter_idx); 2786266423Sjfv vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, vsi_namebuf, 2787266423Sjfv CTLFLAG_RD, NULL, "VSI Number"); 2788266423Sjfv vsi_list = SYSCTL_CHILDREN(vsi_node); 2789266423Sjfv 2790266423Sjfv i40e_add_sysctls_eth_stats(ctx, vsi_list, vsi_stats); 2791266423Sjfv 2792266423Sjfv /* Queue statistics */ 2793266423Sjfv struct i40e_queue *queues = vsi->queues; 2794266423Sjfv struct tx_ring *txr; 2795266423Sjfv struct rx_ring *rxr; 2796266423Sjfv for (int q = 0; q < vsi->num_queues; q++) { 2797266423Sjfv snprintf(queue_namebuf, QUEUE_NAME_LEN, "queue%d", q); 2798266423Sjfv queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, OID_AUTO, queue_namebuf, 2799266423Sjfv CTLFLAG_RD, NULL, "Queue Name"); 2800266423Sjfv queue_list = SYSCTL_CHILDREN(queue_node); 2801266423Sjfv 2802266423Sjfv SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", 2803266423Sjfv CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), 2804266423Sjfv "m_defrag() failed"); 2805266423Sjfv SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "dropped", 2806266423Sjfv CTLFLAG_RD, &(queues[q].dropped_pkts), 2807266423Sjfv "Driver dropped packets"); 2808266423Sjfv 2809266423Sjfv txr = &(queues[q].txr); 2810266423Sjfv /* ERJ - Need: 2811266423Sjfv * i40e_sysctl_interrupt_rate_handler 2812266423Sjfv * i40e_sysctl_tdh_handler 2813266423Sjfv * i40e_sysctl_tdt_handler 2814266423Sjfv * 2815266423Sjfv * i40e_sysctl_rdh_handler 2816266423Sjfv * i40e_sysctl_rdt_handler 2817266423Sjfv * rx_copies 2818266423Sjfv * LRO stats 2819266423Sjfv */ 2820266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 2821266423Sjfv CTLFLAG_RD, &(queues[q].irqs), 2822266423Sjfv "irqs on this queue"); 2823266423Sjfv SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx", 2824266423Sjfv CTLFLAG_RD, &(queues[q].tso), 2825266423Sjfv "TSO"); 2826266423Sjfv SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tx_dma_setup", 2827266423Sjfv CTLFLAG_RD, &(queues[q].tx_dma_setup), 2828266423Sjfv "Driver tx dma failure in xmit"); 2829266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 2830266423Sjfv CTLFLAG_RD, &(txr->no_desc), 2831266423Sjfv "Queue No Descriptor Available"); 2832266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 2833266423Sjfv CTLFLAG_RD, &(txr->total_packets), 2834266423Sjfv "Queue Packets Transmitted"); 2835266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", 2836266423Sjfv CTLFLAG_RD, &(txr->bytes), 2837266423Sjfv "Queue Bytes Transmitted"); 2838266423Sjfv 2839266423Sjfv rxr = &(queues[q].rxr); 2840266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 2841266423Sjfv CTLFLAG_RD, &(rxr->rx_packets), 2842266423Sjfv "Queue Packets Received"); 2843266423Sjfv SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 2844266423Sjfv CTLFLAG_RD, &(rxr->rx_bytes), 2845266423Sjfv "Queue Bytes Received"); 2846266423Sjfv } 2847266423Sjfv 2848266423Sjfv /* MAC stats */ 2849266423Sjfv i40e_add_sysctls_mac_stats(ctx, child, pf_stats); 2850266423Sjfv} 2851266423Sjfv 2852266423Sjfvstatic void 2853266423Sjfvi40e_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx, 2854266423Sjfv struct sysctl_oid_list *child, 2855266423Sjfv struct i40e_eth_stats *eth_stats) 2856266423Sjfv{ 2857266423Sjfv struct i40e_sysctl_info ctls[] = 2858266423Sjfv { 2859266423Sjfv {ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, 2860266423Sjfv {ð_stats->rx_unicast, "ucast_pkts_rcvd", 2861266423Sjfv "Unicast Packets Received"}, 2862266423Sjfv {ð_stats->rx_multicast, "mcast_pkts_rcvd", 2863266423Sjfv "Multicast Packets Received"}, 2864266423Sjfv {ð_stats->rx_broadcast, "bcast_pkts_rcvd", 2865266423Sjfv "Broadcast Packets Received"}, 2866266423Sjfv // Add description 2867266423Sjfv {ð_stats->rx_discards, "rx_discards", "?"}, 2868266423Sjfv {ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, 2869266423Sjfv {ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, 2870266423Sjfv {ð_stats->tx_multicast, "mcast_pkts_txd", 2871266423Sjfv "Multicast Packets Transmitted"}, 2872266423Sjfv {ð_stats->tx_broadcast, "bcast_pkts_txd", 2873266423Sjfv "Broadcast Packets Transmitted"}, 2874266423Sjfv // Add description 2875266423Sjfv {ð_stats->tx_discards, "tx_discards", "?"}, 2876266423Sjfv // end 2877266423Sjfv {0,0,0} 2878266423Sjfv }; 2879266423Sjfv 2880266423Sjfv struct i40e_sysctl_info *entry = ctls; 2881266423Sjfv while (entry->stat != 0) 2882266423Sjfv { 2883266423Sjfv SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name, 2884266423Sjfv CTLFLAG_RD, entry->stat, 2885266423Sjfv entry->description); 2886266423Sjfv entry++; 2887266423Sjfv } 2888266423Sjfv} 2889266423Sjfv 2890266423Sjfvstatic void 2891266423Sjfvi40e_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx, 2892266423Sjfv struct sysctl_oid_list *child, 2893266423Sjfv struct i40e_hw_port_stats *stats) 2894266423Sjfv{ 2895266423Sjfv struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", 2896266423Sjfv CTLFLAG_RD, NULL, "Mac Statistics"); 2897266423Sjfv struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node); 2898266423Sjfv 2899266423Sjfv struct i40e_eth_stats *eth_stats = &stats->eth; 2900266423Sjfv i40e_add_sysctls_eth_stats(ctx, stat_list, eth_stats); 2901266423Sjfv 2902266423Sjfv struct i40e_sysctl_info ctls[] = 2903266423Sjfv { 2904266423Sjfv {&stats->crc_errors, "crc_errors", "CRC Errors"}, 2905266423Sjfv {&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"}, 2906266423Sjfv {&stats->mac_local_faults, "local_faults", "MAC Local Faults"}, 2907266423Sjfv {&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"}, 2908266423Sjfv {&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"}, 2909266423Sjfv /* Packet Reception Stats */ 2910266423Sjfv {&stats->rx_size_64, "rx_frames_64", "64 byte frames received"}, 2911266423Sjfv {&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"}, 2912266423Sjfv {&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"}, 2913266423Sjfv {&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"}, 2914266423Sjfv {&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"}, 2915266423Sjfv {&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"}, 2916266423Sjfv {&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"}, 2917266423Sjfv {&stats->rx_undersize, "rx_undersize", "Undersized packets received"}, 2918266423Sjfv {&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"}, 2919266423Sjfv {&stats->rx_oversize, "rx_oversized", "Oversized packets received"}, 2920266423Sjfv {&stats->rx_jabber, "rx_jabber", "Received Jabber"}, 2921266423Sjfv {&stats->checksum_error, "checksum_errors", "Checksum Errors"}, 2922266423Sjfv /* Packet Transmission Stats */ 2923266423Sjfv {&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"}, 2924266423Sjfv {&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"}, 2925266423Sjfv {&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"}, 2926266423Sjfv {&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"}, 2927266423Sjfv {&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"}, 2928266423Sjfv {&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"}, 2929266423Sjfv {&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"}, 2930266423Sjfv /* Flow control */ 2931266423Sjfv {&stats->link_xon_tx, "xon_txd", "Link XON transmitted"}, 2932266423Sjfv {&stats->link_xon_rx, "xon_recvd", "Link XON received"}, 2933266423Sjfv {&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"}, 2934266423Sjfv {&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"}, 2935266423Sjfv /* End */ 2936266423Sjfv {0,0,0} 2937266423Sjfv }; 2938266423Sjfv 2939266423Sjfv struct i40e_sysctl_info *entry = ctls; 2940266423Sjfv while (entry->stat != 0) 2941266423Sjfv { 2942266423Sjfv SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name, 2943266423Sjfv CTLFLAG_RD, entry->stat, 2944266423Sjfv entry->description); 2945266423Sjfv entry++; 2946266423Sjfv } 2947266423Sjfv} 2948266423Sjfv 2949266423Sjfv/* 2950266423Sjfv** i40e_config_rss - setup RSS 2951266423Sjfv** - note this is done for the single vsi 2952266423Sjfv*/ 2953266423Sjfvstatic void i40e_config_rss(struct i40e_vsi *vsi) 2954266423Sjfv{ 2955266423Sjfv struct i40e_pf *pf = (struct i40e_pf *)vsi->back; 2956266423Sjfv struct i40e_hw *hw = vsi->hw; 2957266423Sjfv u32 lut = 0; 2958266423Sjfv u64 set_hena, hena; 2959266423Sjfv int i, j; 2960266423Sjfv 2961266423Sjfv static const u32 seed[I40E_PFQF_HKEY_MAX_INDEX + 1] = {0x41b01687, 2962266423Sjfv 0x183cfd8c, 0xce880440, 0x580cbc3c, 0x35897377, 2963266423Sjfv 0x328b25e1, 0x4fa98922, 0xb7d90c14, 0xd5bad70d, 2964266423Sjfv 0xcd15a2c1, 0xe8580225, 0x4a1e9d11, 0xfe5731be}; 2965266423Sjfv 2966266423Sjfv /* Fill out hash function seed */ 2967266423Sjfv for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) 2968266423Sjfv wr32(hw, I40E_PFQF_HKEY(i), seed[i]); 2969266423Sjfv 2970266423Sjfv /* Enable PCTYPES for RSS: */ 2971266423Sjfv set_hena = 2972266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | 2973266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | 2974266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | 2975266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | 2976266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | 2977266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | 2978266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | 2979266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | 2980266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | 2981266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | 2982266423Sjfv ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD); 2983266423Sjfv 2984266423Sjfv hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) | 2985266423Sjfv ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32); 2986266423Sjfv hena |= set_hena; 2987266423Sjfv wr32(hw, I40E_PFQF_HENA(0), (u32)hena); 2988266423Sjfv wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); 2989266423Sjfv 2990266423Sjfv /* Populate the LUT with max no. of queues in round robin fashion */ 2991266423Sjfv for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) { 2992266423Sjfv if (j == vsi->num_queues) 2993266423Sjfv j = 0; 2994266423Sjfv /* lut = 4-byte sliding window of 4 lut entries */ 2995266423Sjfv lut = (lut << 8) | (j & 2996266423Sjfv ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1)); 2997266423Sjfv /* On i = 3, we have 4 entries in lut; write to the register */ 2998266423Sjfv if ((i & 3) == 3) 2999266423Sjfv wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); 3000266423Sjfv } 3001266423Sjfv i40e_flush(hw); 3002266423Sjfv} 3003266423Sjfv 3004266423Sjfv 3005266423Sjfv/* 3006266423Sjfv** This routine is run via an vlan config EVENT, 3007266423Sjfv** it enables us to use the HW Filter table since 3008266423Sjfv** we can get the vlan id. This just creates the 3009266423Sjfv** entry in the soft version of the VFTA, init will 3010266423Sjfv** repopulate the real table. 3011266423Sjfv*/ 3012266423Sjfvstatic void 3013266423Sjfvi40e_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3014266423Sjfv{ 3015266423Sjfv struct i40e_vsi *vsi = ifp->if_softc; 3016266423Sjfv struct i40e_hw *hw = vsi->hw; 3017266423Sjfv struct i40e_pf *pf = (struct i40e_pf *)vsi->back; 3018266423Sjfv 3019266423Sjfv if (ifp->if_softc != arg) /* Not our event */ 3020266423Sjfv return; 3021266423Sjfv 3022266423Sjfv if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3023266423Sjfv return; 3024266423Sjfv 3025266423Sjfv I40E_PF_LOCK(pf); 3026266423Sjfv ++vsi->num_vlans; 3027266423Sjfv i40e_add_filter(vsi, hw->mac.addr, vtag); 3028266423Sjfv I40E_PF_UNLOCK(pf); 3029266423Sjfv} 3030266423Sjfv 3031266423Sjfv/* 3032266423Sjfv** This routine is run via an vlan 3033266423Sjfv** unconfig EVENT, remove our entry 3034266423Sjfv** in the soft vfta. 3035266423Sjfv*/ 3036266423Sjfvstatic void 3037266423Sjfvi40e_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3038266423Sjfv{ 3039266423Sjfv struct i40e_vsi *vsi = ifp->if_softc; 3040266423Sjfv struct i40e_hw *hw = vsi->hw; 3041266423Sjfv struct i40e_pf *pf = (struct i40e_pf *)vsi->back; 3042266423Sjfv 3043266423Sjfv if (ifp->if_softc != arg) 3044266423Sjfv return; 3045266423Sjfv 3046266423Sjfv if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3047266423Sjfv return; 3048266423Sjfv 3049266423Sjfv I40E_PF_LOCK(pf); 3050266423Sjfv --vsi->num_vlans; 3051266423Sjfv i40e_del_filter(vsi, hw->mac.addr, vtag); 3052266423Sjfv I40E_PF_UNLOCK(pf); 3053266423Sjfv} 3054266423Sjfv 3055266423Sjfv/* 3056266423Sjfv** This routine updates vlan filters, called by init 3057266423Sjfv** it scans the filter table and then updates the hw 3058266423Sjfv** after a soft reset. 3059266423Sjfv*/ 3060266423Sjfvstatic void 3061266423Sjfvi40e_setup_vlan_filters(struct i40e_vsi *vsi) 3062266423Sjfv{ 3063266423Sjfv struct i40e_mac_filter *f; 3064266423Sjfv int cnt = 0, flags; 3065266423Sjfv 3066266423Sjfv if (vsi->num_vlans == 0) 3067266423Sjfv return; 3068266423Sjfv /* 3069266423Sjfv ** Scan the filter list for vlan entries, 3070266423Sjfv ** mark them for addition and then call 3071266423Sjfv ** for the AQ update. 3072266423Sjfv */ 3073266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 3074266423Sjfv if (f->flags & I40E_FILTER_VLAN) { 3075266423Sjfv f->flags |= 3076266423Sjfv (I40E_FILTER_ADD | 3077266423Sjfv I40E_FILTER_USED); 3078266423Sjfv cnt++; 3079266423Sjfv } 3080266423Sjfv } 3081266423Sjfv if (cnt == 0) { 3082266423Sjfv printf("setup vlan: no filters found!\n"); 3083266423Sjfv return; 3084266423Sjfv } 3085266423Sjfv flags = I40E_FILTER_VLAN; 3086266423Sjfv flags |= (I40E_FILTER_ADD | I40E_FILTER_USED); 3087266423Sjfv i40e_add_hw_filters(vsi, flags, cnt); 3088266423Sjfv return; 3089266423Sjfv} 3090266423Sjfv 3091266423Sjfv/* 3092266423Sjfv** Initialize filter list and add filters that the hardware 3093266423Sjfv** needs to know about. 3094266423Sjfv*/ 3095266423Sjfvstatic void 3096266423Sjfvi40e_init_filters(struct i40e_vsi *vsi) 3097266423Sjfv{ 3098266423Sjfv /* Protocol addresses */ 3099266423Sjfv /* - Flow control multicast */ 3100266423Sjfv u8 mc[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x01}; 3101266423Sjfv i40e_add_filter(vsi, mc, I40E_VLAN_ANY); 3102266423Sjfv /* TODO: other protocols */ 3103266423Sjfv} 3104266423Sjfv 3105266423Sjfv/* 3106266423Sjfv** This routine adds mulicast filters 3107266423Sjfv*/ 3108266423Sjfvstatic void 3109266423Sjfvi40e_add_mc_filter(struct i40e_vsi *vsi, u8 *macaddr) 3110266423Sjfv{ 3111266423Sjfv struct i40e_mac_filter *f; 3112266423Sjfv 3113266423Sjfv /* Does one already exist */ 3114266423Sjfv f = i40e_find_filter(vsi, macaddr, I40E_VLAN_ANY); 3115266423Sjfv if (f != NULL) 3116266423Sjfv return; 3117266423Sjfv 3118266423Sjfv f = i40e_get_filter(vsi); 3119266423Sjfv if (f == NULL) { 3120266423Sjfv printf("WARNING: no filter available!!\n"); 3121266423Sjfv return; 3122266423Sjfv } 3123266423Sjfv bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 3124266423Sjfv f->vlan = I40E_VLAN_ANY; 3125266423Sjfv f->flags |= (I40E_FILTER_ADD | I40E_FILTER_USED 3126266423Sjfv | I40E_FILTER_MC); 3127266423Sjfv 3128266423Sjfv return; 3129266423Sjfv} 3130266423Sjfv 3131266423Sjfv/* 3132266423Sjfv** This routine adds macvlan filters 3133266423Sjfv*/ 3134266423Sjfvstatic void 3135266423Sjfvi40e_add_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan) 3136266423Sjfv{ 3137266423Sjfv struct i40e_mac_filter *f, *tmp; 3138266423Sjfv device_t dev = vsi->dev; 3139266423Sjfv 3140266423Sjfv DEBUGOUT("i40e_add_filter: begin"); 3141266423Sjfv 3142266423Sjfv /* Does one already exist */ 3143266423Sjfv f = i40e_find_filter(vsi, macaddr, vlan); 3144266423Sjfv if (f != NULL) 3145266423Sjfv return; 3146266423Sjfv /* 3147266423Sjfv ** Is this the first vlan being registered, if so we 3148266423Sjfv ** need to remove the ANY filter that indicates we are 3149266423Sjfv ** not in a vlan, and replace that with a 0 filter. 3150266423Sjfv */ 3151266423Sjfv if ((vlan != I40E_VLAN_ANY) && (vsi->num_vlans == 1)) { 3152266423Sjfv tmp = i40e_find_filter(vsi, macaddr, I40E_VLAN_ANY); 3153266423Sjfv if (tmp != NULL) { 3154266423Sjfv i40e_del_filter(vsi, macaddr, I40E_VLAN_ANY); 3155266423Sjfv i40e_add_filter(vsi, macaddr, 0); 3156266423Sjfv } 3157266423Sjfv } 3158266423Sjfv 3159266423Sjfv f = i40e_get_filter(vsi); 3160266423Sjfv if (f == NULL) { 3161266423Sjfv device_printf(dev, "WARNING: no filter available!!\n"); 3162266423Sjfv return; 3163266423Sjfv } 3164266423Sjfv bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 3165266423Sjfv f->vlan = vlan; 3166266423Sjfv f->flags |= (I40E_FILTER_ADD | I40E_FILTER_USED); 3167266423Sjfv if (f->vlan != I40E_VLAN_ANY) 3168266423Sjfv f->flags |= I40E_FILTER_VLAN; 3169266423Sjfv 3170266423Sjfv i40e_add_hw_filters(vsi, f->flags, 1); 3171266423Sjfv return; 3172266423Sjfv} 3173266423Sjfv 3174266423Sjfvstatic void 3175266423Sjfvi40e_del_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan) 3176266423Sjfv{ 3177266423Sjfv struct i40e_mac_filter *f; 3178266423Sjfv 3179266423Sjfv f = i40e_find_filter(vsi, macaddr, vlan); 3180266423Sjfv if (f == NULL) 3181266423Sjfv return; 3182266423Sjfv 3183266423Sjfv f->flags |= I40E_FILTER_DEL; 3184266423Sjfv i40e_del_hw_filters(vsi, 1); 3185266423Sjfv 3186266423Sjfv /* Check if this is the last vlan removal */ 3187266423Sjfv if (vlan != I40E_VLAN_ANY && vsi->num_vlans == 0) { 3188266423Sjfv /* Switch back to a non-vlan filter */ 3189266423Sjfv i40e_del_filter(vsi, macaddr, 0); 3190266423Sjfv i40e_add_filter(vsi, macaddr, I40E_VLAN_ANY); 3191266423Sjfv } 3192266423Sjfv return; 3193266423Sjfv} 3194266423Sjfv 3195266423Sjfv/* 3196266423Sjfv** Find the filter with both matching mac addr and vlan id 3197266423Sjfv*/ 3198266423Sjfvstatic struct i40e_mac_filter * 3199266423Sjfvi40e_find_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan) 3200266423Sjfv{ 3201266423Sjfv struct i40e_mac_filter *f; 3202266423Sjfv bool match = FALSE; 3203266423Sjfv 3204266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 3205266423Sjfv if (!cmp_etheraddr(f->macaddr, macaddr)) 3206266423Sjfv continue; 3207266423Sjfv if (f->vlan == vlan) { 3208266423Sjfv match = TRUE; 3209266423Sjfv break; 3210266423Sjfv } 3211266423Sjfv } 3212266423Sjfv 3213266423Sjfv if (!match) 3214266423Sjfv f = NULL; 3215266423Sjfv return (f); 3216266423Sjfv} 3217266423Sjfv 3218266423Sjfv/* 3219266423Sjfv** This routine takes additions to the vsi filter 3220266423Sjfv** table and creates an Admin Queue call to create 3221266423Sjfv** the filters in the hardware. 3222266423Sjfv*/ 3223266423Sjfvstatic void 3224266423Sjfvi40e_add_hw_filters(struct i40e_vsi *vsi, int flags, int cnt) 3225266423Sjfv{ 3226266423Sjfv struct i40e_aqc_add_macvlan_element_data *a, *b; 3227266423Sjfv struct i40e_mac_filter *f; 3228266423Sjfv struct i40e_hw *hw = vsi->hw; 3229266423Sjfv device_t dev = vsi->dev; 3230266423Sjfv int err, j = 0; 3231266423Sjfv 3232266423Sjfv a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt, 3233266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 3234266423Sjfv if (a == NULL) { 3235266423Sjfv device_printf(dev, "add hw filter failed to get memory\n"); 3236266423Sjfv return; 3237266423Sjfv } 3238266423Sjfv 3239266423Sjfv /* 3240266423Sjfv ** Scan the filter list, each time we find one 3241266423Sjfv ** we add it to the admin queue array and turn off 3242266423Sjfv ** the add bit. 3243266423Sjfv */ 3244266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 3245266423Sjfv if (f->flags == flags) { 3246266423Sjfv b = &a[j]; // a pox on fvl long names :) 3247266423Sjfv bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN); 3248266423Sjfv b->vlan_tag = 3249266423Sjfv (f->vlan == I40E_VLAN_ANY ? 0 : f->vlan); 3250266423Sjfv b->flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH; 3251266423Sjfv f->flags &= ~I40E_FILTER_ADD; 3252266423Sjfv j++; 3253266423Sjfv } 3254266423Sjfv if (j == cnt) 3255266423Sjfv break; 3256266423Sjfv } 3257266423Sjfv if (j > 0) { 3258266423Sjfv err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); 3259266423Sjfv if (err) 3260266423Sjfv device_printf(dev, "aq_add_macvlan failure %d\n", 3261266423Sjfv hw->aq.asq_last_status); 3262266423Sjfv else 3263266423Sjfv vsi->hw_filters_add += j; 3264266423Sjfv } 3265266423Sjfv free(a, M_DEVBUF); 3266266423Sjfv return; 3267266423Sjfv} 3268266423Sjfv 3269266423Sjfv/* 3270266423Sjfv** This routine takes removals in the vsi filter 3271266423Sjfv** table and creates an Admin Queue call to delete 3272266423Sjfv** the filters in the hardware. 3273266423Sjfv*/ 3274266423Sjfvstatic void 3275266423Sjfvi40e_del_hw_filters(struct i40e_vsi *vsi, int cnt) 3276266423Sjfv{ 3277266423Sjfv struct i40e_aqc_remove_macvlan_element_data *d, *e; 3278266423Sjfv struct i40e_hw *hw = vsi->hw; 3279266423Sjfv device_t dev = vsi->dev; 3280266423Sjfv struct i40e_mac_filter *f, *f_temp; 3281266423Sjfv int err, j = 0; 3282266423Sjfv 3283266423Sjfv DEBUGOUT("i40e_del_hw_filters: begin\n"); 3284266423Sjfv 3285266423Sjfv d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt, 3286266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 3287266423Sjfv if (d == NULL) { 3288266423Sjfv printf("del hw filter failed to get memory\n"); 3289266423Sjfv return; 3290266423Sjfv } 3291266423Sjfv 3292266423Sjfv SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) { 3293266423Sjfv if (f->flags & I40E_FILTER_DEL) { 3294266423Sjfv e = &d[j]; // a pox on fvl long names :) 3295266423Sjfv bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN); 3296266423Sjfv e->vlan_tag = (f->vlan == I40E_VLAN_ANY ? 0 : f->vlan); 3297266423Sjfv e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; 3298266423Sjfv /* delete entry from vsi list */ 3299266423Sjfv SLIST_REMOVE(&vsi->ftl, f, i40e_mac_filter, next); 3300266423Sjfv free(f, M_DEVBUF); 3301266423Sjfv j++; 3302266423Sjfv } 3303266423Sjfv if (j == cnt) 3304266423Sjfv break; 3305266423Sjfv } 3306266423Sjfv if (j > 0) { 3307266423Sjfv err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); 3308266423Sjfv /* NOTE: returns ENOENT every time but seems to work fine, 3309266423Sjfv so we'll ignore that specific error. */ 3310266423Sjfv if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { 3311266423Sjfv int sc = 0; 3312266423Sjfv for (int i = 0; i < j; i++) 3313266423Sjfv sc += (!d[i].error_code); 3314266423Sjfv vsi->hw_filters_del += sc; 3315266423Sjfv device_printf(dev, 3316266423Sjfv "Failed to remove %d/%d filters, aq error %d\n", 3317266423Sjfv j - sc, j, hw->aq.asq_last_status); 3318266423Sjfv } else 3319266423Sjfv vsi->hw_filters_del += j; 3320266423Sjfv } 3321266423Sjfv free(d, M_DEVBUF); 3322266423Sjfv 3323266423Sjfv DEBUGOUT("i40e_del_hw_filters: end\n"); 3324266423Sjfv return; 3325266423Sjfv} 3326266423Sjfv 3327266423Sjfv 3328266423Sjfvstatic void 3329266423Sjfvi40e_enable_rings(struct i40e_vsi *vsi) 3330266423Sjfv{ 3331266423Sjfv struct i40e_hw *hw = vsi->hw; 3332266423Sjfv u32 reg; 3333266423Sjfv 3334266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 3335266423Sjfv // ERJ: pre_tx_queue_cfg is B0-only? 3336266423Sjfv i40e_pre_tx_queue_cfg(hw, i, TRUE); 3337266423Sjfv 3338266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3339266423Sjfv reg |= I40E_QTX_ENA_QENA_REQ_MASK | 3340266423Sjfv I40E_QTX_ENA_QENA_STAT_MASK; 3341266423Sjfv wr32(hw, I40E_QTX_ENA(i), reg); 3342266423Sjfv /* Verify the enable took */ 3343266423Sjfv for (int j = 0; j < 10; j++) { 3344266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3345266423Sjfv if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 3346266423Sjfv break; 3347266423Sjfv i40e_msec_delay(10); 3348266423Sjfv } 3349266423Sjfv if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) 3350266423Sjfv printf("TX queue %d disabled!\n", i); 3351266423Sjfv 3352266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3353266423Sjfv reg |= I40E_QRX_ENA_QENA_REQ_MASK | 3354266423Sjfv I40E_QRX_ENA_QENA_STAT_MASK; 3355266423Sjfv wr32(hw, I40E_QRX_ENA(i), reg); 3356266423Sjfv /* Verify the enable took */ 3357266423Sjfv for (int j = 0; j < 10; j++) { 3358266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3359266423Sjfv if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 3360266423Sjfv break; 3361266423Sjfv i40e_msec_delay(10); 3362266423Sjfv } 3363266423Sjfv if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) 3364266423Sjfv printf("RX queue %d disabled!\n", i); 3365266423Sjfv } 3366266423Sjfv} 3367266423Sjfv 3368266423Sjfvstatic void 3369266423Sjfvi40e_disable_rings(struct i40e_vsi *vsi) 3370266423Sjfv{ 3371266423Sjfv struct i40e_hw *hw = vsi->hw; 3372266423Sjfv u32 reg; 3373266423Sjfv 3374266423Sjfv for (int i = 0; i < vsi->num_queues; i++) { 3375266423Sjfv // ERJ 3376266423Sjfv // this step can be executed concurrently for each queue 3377266423Sjfv i40e_pre_tx_queue_cfg(hw, i, FALSE); 3378266423Sjfv // min 100usec for 2x10, 400usec for 1x10 3379266423Sjfv i40e_usec_delay(500); 3380266423Sjfv 3381266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3382266423Sjfv reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; 3383266423Sjfv wr32(hw, I40E_QTX_ENA(i), reg); 3384266423Sjfv /* Verify the disable took */ 3385266423Sjfv for (int j = 0; j < 10; j++) { 3386266423Sjfv reg = rd32(hw, I40E_QTX_ENA(i)); 3387266423Sjfv if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK)) 3388266423Sjfv break; 3389266423Sjfv i40e_msec_delay(10); 3390266423Sjfv } 3391266423Sjfv if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 3392266423Sjfv printf("TX queue %d still enabled!\n", i); 3393266423Sjfv 3394266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3395266423Sjfv reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; 3396266423Sjfv wr32(hw, I40E_QRX_ENA(i), reg); 3397266423Sjfv /* Verify the disable took */ 3398266423Sjfv for (int j = 0; j < 10; j++) { 3399266423Sjfv reg = rd32(hw, I40E_QRX_ENA(i)); 3400266423Sjfv if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK)) 3401266423Sjfv break; 3402266423Sjfv i40e_msec_delay(10); 3403266423Sjfv } 3404266423Sjfv if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 3405266423Sjfv printf("RX queue %d still enabled!\n", i); 3406266423Sjfv } 3407266423Sjfv} 3408266423Sjfv 3409266423Sjfvstatic void 3410266423Sjfvi40e_enable_intr(struct i40e_vsi *vsi) 3411266423Sjfv{ 3412266423Sjfv struct i40e_hw *hw = vsi->hw; 3413266423Sjfv struct i40e_queue *que = vsi->queues; 3414266423Sjfv 3415266423Sjfv if (i40e_enable_msix) { 3416266423Sjfv i40e_enable_adminq(hw); 3417266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) 3418266423Sjfv i40e_enable_queue(hw, que->me); 3419266423Sjfv } else 3420266423Sjfv i40e_enable_legacy(hw); 3421266423Sjfv} 3422266423Sjfv 3423266423Sjfvstatic void 3424266423Sjfvi40e_disable_intr(struct i40e_vsi *vsi) 3425266423Sjfv{ 3426266423Sjfv struct i40e_hw *hw = vsi->hw; 3427266423Sjfv struct i40e_queue *que = vsi->queues; 3428266423Sjfv 3429266423Sjfv if (i40e_enable_msix) { 3430266423Sjfv i40e_disable_adminq(hw); 3431266423Sjfv for (int i = 0; i < vsi->num_queues; i++, que++) 3432266423Sjfv i40e_disable_queue(hw, que->me); 3433266423Sjfv } else 3434266423Sjfv i40e_disable_legacy(hw); 3435266423Sjfv} 3436266423Sjfv 3437266423Sjfvstatic void 3438266423Sjfvi40e_enable_adminq(struct i40e_hw *hw) 3439266423Sjfv{ 3440266423Sjfv u32 reg; 3441266423Sjfv 3442266423Sjfv reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 3443266423Sjfv I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 3444266423Sjfv (I40E_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 3445266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3446266423Sjfv i40e_flush(hw); 3447266423Sjfv return; 3448266423Sjfv} 3449266423Sjfv 3450266423Sjfvstatic void 3451266423Sjfvi40e_disable_adminq(struct i40e_hw *hw) 3452266423Sjfv{ 3453266423Sjfv u32 reg; 3454266423Sjfv 3455266423Sjfv reg = I40E_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 3456266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3457266423Sjfv 3458266423Sjfv return; 3459266423Sjfv} 3460266423Sjfv 3461266423Sjfvstatic void 3462266423Sjfvi40e_enable_queue(struct i40e_hw *hw, int id) 3463266423Sjfv{ 3464266423Sjfv u32 reg; 3465266423Sjfv 3466266423Sjfv reg = I40E_PFINT_DYN_CTLN_INTENA_MASK | 3467266423Sjfv I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | 3468266423Sjfv (I40E_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); 3469266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 3470266423Sjfv} 3471266423Sjfv 3472266423Sjfvstatic void 3473266423Sjfvi40e_disable_queue(struct i40e_hw *hw, int id) 3474266423Sjfv{ 3475266423Sjfv u32 reg; 3476266423Sjfv 3477266423Sjfv reg = I40E_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; 3478266423Sjfv wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); 3479266423Sjfv 3480266423Sjfv return; 3481266423Sjfv} 3482266423Sjfv 3483266423Sjfvstatic void 3484266423Sjfvi40e_enable_legacy(struct i40e_hw *hw) 3485266423Sjfv{ 3486266423Sjfv u32 reg; 3487266423Sjfv reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 3488266423Sjfv I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 3489266423Sjfv (I40E_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 3490266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3491266423Sjfv} 3492266423Sjfv 3493266423Sjfvstatic void 3494266423Sjfvi40e_disable_legacy(struct i40e_hw *hw) 3495266423Sjfv{ 3496266423Sjfv u32 reg; 3497266423Sjfv 3498266423Sjfv reg = I40E_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 3499266423Sjfv wr32(hw, I40E_PFINT_DYN_CTL0, reg); 3500266423Sjfv 3501266423Sjfv return; 3502266423Sjfv} 3503266423Sjfv 3504266423Sjfvstatic void 3505266423Sjfvi40e_update_stats_counters(struct i40e_pf *pf) 3506266423Sjfv{ 3507266423Sjfv struct i40e_hw *hw = &pf->hw; 3508266423Sjfv struct i40e_hw_port_stats *nsd = &pf->stats; 3509266423Sjfv struct i40e_hw_port_stats *osd = &pf->stats_offsets; 3510266423Sjfv 3511266423Sjfv /* Update hw stats */ 3512266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port), 3513266423Sjfv pf->stat_offsets_loaded, 3514266423Sjfv &osd->crc_errors, &nsd->crc_errors); 3515266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port), 3516266423Sjfv pf->stat_offsets_loaded, 3517266423Sjfv &osd->illegal_bytes, &nsd->illegal_bytes); 3518266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_GORCH(hw->port), 3519266423Sjfv I40E_GLPRT_GORCL(hw->port), 3520266423Sjfv pf->stat_offsets_loaded, 3521266423Sjfv &osd->eth.rx_bytes, &nsd->eth.rx_bytes); 3522266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port), 3523266423Sjfv I40E_GLPRT_GOTCL(hw->port), 3524266423Sjfv pf->stat_offsets_loaded, 3525266423Sjfv &osd->eth.tx_bytes, &nsd->eth.tx_bytes); 3526266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_RDPC(hw->port), 3527266423Sjfv pf->stat_offsets_loaded, 3528266423Sjfv &osd->eth.rx_discards, 3529266423Sjfv &nsd->eth.rx_discards); 3530266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_TDPC(hw->port), 3531266423Sjfv pf->stat_offsets_loaded, 3532266423Sjfv &osd->eth.tx_discards, 3533266423Sjfv &nsd->eth.tx_discards); 3534266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port), 3535266423Sjfv I40E_GLPRT_UPRCL(hw->port), 3536266423Sjfv pf->stat_offsets_loaded, 3537266423Sjfv &osd->eth.rx_unicast, 3538266423Sjfv &nsd->eth.rx_unicast); 3539266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port), 3540266423Sjfv I40E_GLPRT_UPTCL(hw->port), 3541266423Sjfv pf->stat_offsets_loaded, 3542266423Sjfv &osd->eth.tx_unicast, 3543266423Sjfv &nsd->eth.tx_unicast); 3544266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port), 3545266423Sjfv I40E_GLPRT_MPRCL(hw->port), 3546266423Sjfv pf->stat_offsets_loaded, 3547266423Sjfv &osd->eth.rx_multicast, 3548266423Sjfv &nsd->eth.rx_multicast); 3549266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port), 3550266423Sjfv I40E_GLPRT_MPTCL(hw->port), 3551266423Sjfv pf->stat_offsets_loaded, 3552266423Sjfv &osd->eth.tx_multicast, 3553266423Sjfv &nsd->eth.tx_multicast); 3554266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port), 3555266423Sjfv I40E_GLPRT_BPRCL(hw->port), 3556266423Sjfv pf->stat_offsets_loaded, 3557266423Sjfv &osd->eth.rx_broadcast, 3558266423Sjfv &nsd->eth.rx_broadcast); 3559266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port), 3560266423Sjfv I40E_GLPRT_BPTCL(hw->port), 3561266423Sjfv pf->stat_offsets_loaded, 3562266423Sjfv &osd->eth.tx_broadcast, 3563266423Sjfv &nsd->eth.tx_broadcast); 3564266423Sjfv 3565266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port), 3566266423Sjfv pf->stat_offsets_loaded, 3567266423Sjfv &osd->tx_dropped_link_down, 3568266423Sjfv &nsd->tx_dropped_link_down); 3569266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_MLFC(hw->port), 3570266423Sjfv pf->stat_offsets_loaded, 3571266423Sjfv &osd->mac_local_faults, 3572266423Sjfv &nsd->mac_local_faults); 3573266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_MRFC(hw->port), 3574266423Sjfv pf->stat_offsets_loaded, 3575266423Sjfv &osd->mac_remote_faults, 3576266423Sjfv &nsd->mac_remote_faults); 3577266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_RLEC(hw->port), 3578266423Sjfv pf->stat_offsets_loaded, 3579266423Sjfv &osd->rx_length_errors, 3580266423Sjfv &nsd->rx_length_errors); 3581266423Sjfv 3582266423Sjfv /* Update flow control stats */ 3583266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port), 3584266423Sjfv pf->stat_offsets_loaded, 3585266423Sjfv &osd->link_xon_rx, &nsd->link_xon_rx); 3586266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port), 3587266423Sjfv pf->stat_offsets_loaded, 3588266423Sjfv &osd->link_xon_tx, &nsd->link_xon_tx); 3589266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port), 3590266423Sjfv pf->stat_offsets_loaded, 3591266423Sjfv &osd->link_xoff_rx, &nsd->link_xoff_rx); 3592266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port), 3593266423Sjfv pf->stat_offsets_loaded, 3594266423Sjfv &osd->link_xoff_tx, &nsd->link_xoff_tx); 3595266423Sjfv 3596266423Sjfv /* 3597266423Sjfv * Uncomment these out when priority flow control 3598266423Sjfv * is implemented. 3599266423Sjfv */ 3600266423Sjfv#if 0 3601266423Sjfv for (int i = 0; i < 8; i++) { 3602266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_PXONRXC(hw->port, i), 3603266423Sjfv pf->stat_offsets_loaded, 3604266423Sjfv &osd->priority_xon_rx[i], 3605266423Sjfv &nsd->priority_xon_rx[i]); 3606266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_PXONTXC(hw->port, i), 3607266423Sjfv pf->stat_offsets_loaded, 3608266423Sjfv &osd->priority_xon_tx[i], 3609266423Sjfv &nsd->priority_xon_tx[i]); 3610266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_PXOFFTXC(hw->port, i), 3611266423Sjfv pf->stat_offsets_loaded, 3612266423Sjfv &osd->priority_xoff_tx[i], 3613266423Sjfv &nsd->priority_xoff_tx[i]); 3614266423Sjfv i40e_stat_update32(hw, 3615266423Sjfv I40E_GLPRT_RXON2OFFCNT(hw->port, i), 3616266423Sjfv pf->stat_offsets_loaded, 3617266423Sjfv &osd->priority_xon_2_xoff[i], 3618266423Sjfv &nsd->priority_xon_2_xoff[i]); 3619266423Sjfv } 3620266423Sjfv#endif 3621266423Sjfv 3622266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port), 3623266423Sjfv I40E_GLPRT_PRC64L(hw->port), 3624266423Sjfv pf->stat_offsets_loaded, 3625266423Sjfv &osd->rx_size_64, &nsd->rx_size_64); 3626266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port), 3627266423Sjfv I40E_GLPRT_PRC127L(hw->port), 3628266423Sjfv pf->stat_offsets_loaded, 3629266423Sjfv &osd->rx_size_127, &nsd->rx_size_127); 3630266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port), 3631266423Sjfv I40E_GLPRT_PRC255L(hw->port), 3632266423Sjfv pf->stat_offsets_loaded, 3633266423Sjfv &osd->rx_size_255, &nsd->rx_size_255); 3634266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port), 3635266423Sjfv I40E_GLPRT_PRC511L(hw->port), 3636266423Sjfv pf->stat_offsets_loaded, 3637266423Sjfv &osd->rx_size_511, &nsd->rx_size_511); 3638266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port), 3639266423Sjfv I40E_GLPRT_PRC1023L(hw->port), 3640266423Sjfv pf->stat_offsets_loaded, 3641266423Sjfv &osd->rx_size_1023, &nsd->rx_size_1023); 3642266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port), 3643266423Sjfv I40E_GLPRT_PRC1522L(hw->port), 3644266423Sjfv pf->stat_offsets_loaded, 3645266423Sjfv &osd->rx_size_1522, &nsd->rx_size_1522); 3646266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port), 3647266423Sjfv I40E_GLPRT_PRC9522L(hw->port), 3648266423Sjfv pf->stat_offsets_loaded, 3649266423Sjfv &osd->rx_size_big, &nsd->rx_size_big); 3650266423Sjfv 3651266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port), 3652266423Sjfv I40E_GLPRT_PTC64L(hw->port), 3653266423Sjfv pf->stat_offsets_loaded, 3654266423Sjfv &osd->tx_size_64, &nsd->tx_size_64); 3655266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port), 3656266423Sjfv I40E_GLPRT_PTC127L(hw->port), 3657266423Sjfv pf->stat_offsets_loaded, 3658266423Sjfv &osd->tx_size_127, &nsd->tx_size_127); 3659266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port), 3660266423Sjfv I40E_GLPRT_PTC255L(hw->port), 3661266423Sjfv pf->stat_offsets_loaded, 3662266423Sjfv &osd->tx_size_255, &nsd->tx_size_255); 3663266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port), 3664266423Sjfv I40E_GLPRT_PTC511L(hw->port), 3665266423Sjfv pf->stat_offsets_loaded, 3666266423Sjfv &osd->tx_size_511, &nsd->tx_size_511); 3667266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port), 3668266423Sjfv I40E_GLPRT_PTC1023L(hw->port), 3669266423Sjfv pf->stat_offsets_loaded, 3670266423Sjfv &osd->tx_size_1023, &nsd->tx_size_1023); 3671266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port), 3672266423Sjfv I40E_GLPRT_PTC1522L(hw->port), 3673266423Sjfv pf->stat_offsets_loaded, 3674266423Sjfv &osd->tx_size_1522, &nsd->tx_size_1522); 3675266423Sjfv i40e_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port), 3676266423Sjfv I40E_GLPRT_PTC9522L(hw->port), 3677266423Sjfv pf->stat_offsets_loaded, 3678266423Sjfv &osd->tx_size_big, &nsd->tx_size_big); 3679266423Sjfv 3680266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_RUC(hw->port), 3681266423Sjfv pf->stat_offsets_loaded, 3682266423Sjfv &osd->rx_undersize, &nsd->rx_undersize); 3683266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_RFC(hw->port), 3684266423Sjfv pf->stat_offsets_loaded, 3685266423Sjfv &osd->rx_fragments, &nsd->rx_fragments); 3686266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_ROC(hw->port), 3687266423Sjfv pf->stat_offsets_loaded, 3688266423Sjfv &osd->rx_oversize, &nsd->rx_oversize); 3689266423Sjfv i40e_stat_update32(hw, I40E_GLPRT_RJC(hw->port), 3690266423Sjfv pf->stat_offsets_loaded, 3691266423Sjfv &osd->rx_jabber, &nsd->rx_jabber); 3692266423Sjfv pf->stat_offsets_loaded = true; 3693266423Sjfv /* End pf-only stats */ 3694266423Sjfv 3695266423Sjfv /* Update vsi stats */ 3696266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 3697266423Sjfv i40e_update_eth_stats(vsi); 3698266423Sjfv 3699266423Sjfv /* ERJ - does something need these statistics? 3700266423Sjfv u64 rx_p = 0, rx_b = 0, tx_p = 0, tx_b = 0; 3701266423Sjfv u64 tx_no_desc; 3702266423Sjfv u64 rx_split, rx_discarded, rx_not_done; 3703266423Sjfv for (u16 q = 0; q < vsi->num_queues; q++) 3704266423Sjfv { 3705266423Sjfv struct i40e_queue *p = &vsi->queues[q]; 3706266423Sjfv 3707266423Sjfv rx_p += p->rxr.packets; 3708266423Sjfv tx_p += p->txr.packets; 3709266423Sjfv rx_b += p->rxr.bytes; 3710266423Sjfv tx_b += p->txr.bytes; 3711266423Sjfv 3712266423Sjfv tx_no_desc += p->txr.no_desc; 3713266423Sjfv rx_split += p->rxr.split; 3714266423Sjfv rx_discarded += p->rxr.discarded; 3715266423Sjfv rx_not_done += p->rxr.not_done; 3716266423Sjfv } 3717266423Sjfv */ 3718266423Sjfv 3719266423Sjfv /* OS statistics */ 3720266423Sjfv struct ifnet *ifp = vsi->ifp; 3721266423Sjfv 3722266423Sjfv // ifp->if_ipackets = rx_p; // no gprc 3723266423Sjfv // ifp->if_opackets = tx_p; // no gptc 3724266423Sjfv ifp->if_ibytes = nsd->eth.rx_bytes; 3725266423Sjfv ifp->if_obytes = nsd->eth.tx_bytes; 3726266423Sjfv ifp->if_imcasts = nsd->eth.rx_multicast; 3727266423Sjfv ifp->if_omcasts = nsd->eth.tx_multicast; 3728266423Sjfv ifp->if_collisions = 0; 3729266423Sjfv 3730266423Sjfv /* Rx Errors */ 3731266423Sjfv // Linux uses illegal_bytes instead of rx_length_errors 3732266423Sjfv ifp->if_ierrors = nsd->crc_errors + nsd->illegal_bytes; 3733266423Sjfv} 3734266423Sjfv 3735266423Sjfv/* 3736266423Sjfv** Tasklet handler for MSIX Adminq interrupts 3737266423Sjfv** - do outside interrupt since it might sleep 3738266423Sjfv*/ 3739266423Sjfvstatic void 3740266423Sjfvi40e_do_adminq(void *context, int pending) 3741266423Sjfv{ 3742266423Sjfv struct i40e_pf *pf = context; 3743266423Sjfv struct i40e_hw *hw = &pf->hw; 3744266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 3745266423Sjfv struct i40e_arq_event_info event; 3746266423Sjfv i40e_status ret; 3747266423Sjfv u32 reg, loop = 0; 3748266423Sjfv u16 opcode, result; 3749266423Sjfv 3750266423Sjfv event.msg_size = I40E_AQ_BUF_SZ; 3751266423Sjfv event.msg_buf = malloc(event.msg_size, 3752266423Sjfv M_DEVBUF, M_NOWAIT | M_ZERO); 3753266423Sjfv if (!event.msg_buf) { 3754266423Sjfv printf("Unable to allocate adminq memory\n"); 3755266423Sjfv return; 3756266423Sjfv } 3757266423Sjfv 3758266423Sjfv /* clean and process any events */ 3759266423Sjfv do { 3760266423Sjfv ret = i40e_clean_arq_element(hw, &event, &result); 3761266423Sjfv if (ret) 3762266423Sjfv break; 3763266423Sjfv opcode = LE16_TO_CPU(event.desc.opcode); 3764266423Sjfv switch (opcode) { 3765266423Sjfv case i40e_aqc_opc_get_link_status: 3766266423Sjfv vsi->link_up = i40e_config_link(hw); 3767266423Sjfv i40e_update_link_status(pf); 3768266423Sjfv break; 3769266423Sjfv case i40e_aqc_opc_send_msg_to_pf: 3770266423Sjfv /* process pf/vf communication here */ 3771266423Sjfv break; 3772266423Sjfv case i40e_aqc_opc_event_lan_overflow: 3773266423Sjfv break; 3774266423Sjfv default: 3775266423Sjfv#ifdef I40E_DEBUG 3776266423Sjfv printf("AdminQ unknown event %x\n", opcode); 3777266423Sjfv#endif 3778266423Sjfv break; 3779266423Sjfv } 3780266423Sjfv 3781266423Sjfv } while (result && (loop++ < I40E_ADM_LIMIT)); 3782266423Sjfv 3783266423Sjfv reg = rd32(hw, I40E_PFINT_ICR0_ENA); 3784266423Sjfv reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 3785266423Sjfv wr32(hw, I40E_PFINT_ICR0_ENA, reg); 3786266423Sjfv free(event.msg_buf, M_DEVBUF); 3787266423Sjfv 3788266423Sjfv if (pf->msix > 1) 3789266423Sjfv i40e_enable_adminq(&pf->hw); 3790266423Sjfv else 3791266423Sjfv i40e_enable_intr(vsi); 3792266423Sjfv} 3793266423Sjfv 3794266423Sjfvstatic int 3795266423Sjfvi40e_debug_info(SYSCTL_HANDLER_ARGS) 3796266423Sjfv{ 3797266423Sjfv struct i40e_pf *pf; 3798266423Sjfv int error, input = 0; 3799266423Sjfv 3800266423Sjfv error = sysctl_handle_int(oidp, &input, 0, req); 3801266423Sjfv 3802266423Sjfv if (error || !req->newptr) 3803266423Sjfv return (error); 3804266423Sjfv 3805266423Sjfv if (input == 1) { 3806266423Sjfv pf = (struct i40e_pf *)arg1; 3807266423Sjfv i40e_print_debug_info(pf); 3808266423Sjfv } 3809266423Sjfv 3810266423Sjfv return (error); 3811266423Sjfv} 3812266423Sjfv 3813266423Sjfvstatic void 3814266423Sjfvi40e_print_debug_info(struct i40e_pf *pf) 3815266423Sjfv{ 3816266423Sjfv struct i40e_hw *hw = &pf->hw; 3817266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 3818266423Sjfv struct i40e_queue *que = vsi->queues; 3819266423Sjfv struct rx_ring *rxr = &que->rxr; 3820266423Sjfv struct tx_ring *txr = &que->txr; 3821266423Sjfv u32 reg; 3822266423Sjfv 3823266423Sjfv 3824266423Sjfv printf("Queue irqs = %lx\n", que->irqs); 3825266423Sjfv printf("AdminQ irqs = %lx\n", pf->admin_irq); 3826266423Sjfv printf("RX next check = %x\n", rxr->next_check); 3827266423Sjfv printf("RX not ready = %lx\n", rxr->not_done); 3828266423Sjfv printf("RX packets = %lx\n", rxr->rx_packets); 3829266423Sjfv printf("TX desc avail = %x\n", txr->avail); 3830266423Sjfv 3831266423Sjfv reg = rd32(hw, I40E_GLV_GORCL(0xc)); 3832266423Sjfv printf("RX Bytes = %x\n", reg); 3833266423Sjfv reg = rd32(hw, I40E_GLPRT_GORCL(hw->port)); 3834266423Sjfv printf("Port RX Bytes = %x\n", reg); 3835266423Sjfv reg = rd32(hw, I40E_GLV_RDPC(0xc)); 3836266423Sjfv printf("RX discard = %x\n", reg); 3837266423Sjfv reg = rd32(hw, I40E_GLPRT_RDPC(hw->port)); 3838266423Sjfv printf("Port RX discard = %x\n", reg); 3839266423Sjfv 3840266423Sjfv reg = rd32(hw, I40E_GLV_TEPC(0xc)); 3841266423Sjfv printf("TX errors = %x\n", reg); 3842266423Sjfv reg = rd32(hw, I40E_GLV_GOTCL(0xc)); 3843266423Sjfv printf("TX Bytes = %x\n", reg); 3844266423Sjfv 3845266423Sjfv reg = rd32(hw, I40E_GLPRT_RUC(hw->port)); 3846266423Sjfv printf("RX undersize = %x\n", reg); 3847266423Sjfv reg = rd32(hw, I40E_GLPRT_RFC(hw->port)); 3848266423Sjfv printf("RX fragments = %x\n", reg); 3849266423Sjfv reg = rd32(hw, I40E_GLPRT_ROC(hw->port)); 3850266423Sjfv printf("RX oversize = %x\n", reg); 3851266423Sjfv reg = rd32(hw, I40E_GLPRT_RLEC(hw->port)); 3852266423Sjfv printf("RX length error = %x\n", reg); 3853266423Sjfv reg = rd32(hw, I40E_GLPRT_MRFC(hw->port)); 3854266423Sjfv printf("mac remote fault = %x\n", reg); 3855266423Sjfv reg = rd32(hw, I40E_GLPRT_MLFC(hw->port)); 3856266423Sjfv printf("mac local fault = %x\n", reg); 3857266423Sjfv} 3858266423Sjfv 3859266423Sjfv/** 3860266423Sjfv * Update VSI-specific ethernet statistics counters. 3861266423Sjfv **/ 3862266423Sjfvvoid i40e_update_eth_stats(struct i40e_vsi *vsi) 3863266423Sjfv{ 3864266423Sjfv struct i40e_pf *pf = (struct i40e_pf *)vsi->back; 3865266423Sjfv struct i40e_hw *hw = &pf->hw; 3866266423Sjfv struct i40e_eth_stats *es; 3867266423Sjfv struct i40e_eth_stats *oes; 3868266423Sjfv u16 stat_idx = vsi->info.stat_counter_idx; 3869266423Sjfv 3870266423Sjfv es = &vsi->eth_stats; 3871266423Sjfv oes = &vsi->eth_stats_offsets; 3872266423Sjfv 3873266423Sjfv /* Gather up the stats that the hw collects */ 3874266423Sjfv i40e_stat_update32(hw, I40E_GLV_TEPC(stat_idx), 3875266423Sjfv vsi->stat_offsets_loaded, 3876266423Sjfv &oes->tx_errors, &es->tx_errors); 3877266423Sjfv i40e_stat_update32(hw, I40E_GLV_RDPC(stat_idx), 3878266423Sjfv vsi->stat_offsets_loaded, 3879266423Sjfv &oes->rx_discards, &es->rx_discards); 3880266423Sjfv 3881266423Sjfv i40e_stat_update48(hw, I40E_GLV_GORCH(stat_idx), 3882266423Sjfv I40E_GLV_GORCL(stat_idx), 3883266423Sjfv vsi->stat_offsets_loaded, 3884266423Sjfv &oes->rx_bytes, &es->rx_bytes); 3885266423Sjfv i40e_stat_update48(hw, I40E_GLV_UPRCH(stat_idx), 3886266423Sjfv I40E_GLV_UPRCL(stat_idx), 3887266423Sjfv vsi->stat_offsets_loaded, 3888266423Sjfv &oes->rx_unicast, &es->rx_unicast); 3889266423Sjfv i40e_stat_update48(hw, I40E_GLV_MPRCH(stat_idx), 3890266423Sjfv I40E_GLV_MPRCL(stat_idx), 3891266423Sjfv vsi->stat_offsets_loaded, 3892266423Sjfv &oes->rx_multicast, &es->rx_multicast); 3893266423Sjfv i40e_stat_update48(hw, I40E_GLV_BPRCH(stat_idx), 3894266423Sjfv I40E_GLV_BPRCL(stat_idx), 3895266423Sjfv vsi->stat_offsets_loaded, 3896266423Sjfv &oes->rx_broadcast, &es->rx_broadcast); 3897266423Sjfv 3898266423Sjfv i40e_stat_update48(hw, I40E_GLV_GOTCH(stat_idx), 3899266423Sjfv I40E_GLV_GOTCL(stat_idx), 3900266423Sjfv vsi->stat_offsets_loaded, 3901266423Sjfv &oes->tx_bytes, &es->tx_bytes); 3902266423Sjfv i40e_stat_update48(hw, I40E_GLV_UPTCH(stat_idx), 3903266423Sjfv I40E_GLV_UPTCL(stat_idx), 3904266423Sjfv vsi->stat_offsets_loaded, 3905266423Sjfv &oes->tx_unicast, &es->tx_unicast); 3906266423Sjfv i40e_stat_update48(hw, I40E_GLV_MPTCH(stat_idx), 3907266423Sjfv I40E_GLV_MPTCL(stat_idx), 3908266423Sjfv vsi->stat_offsets_loaded, 3909266423Sjfv &oes->tx_multicast, &es->tx_multicast); 3910266423Sjfv i40e_stat_update48(hw, I40E_GLV_BPTCH(stat_idx), 3911266423Sjfv I40E_GLV_BPTCL(stat_idx), 3912266423Sjfv vsi->stat_offsets_loaded, 3913266423Sjfv &oes->tx_broadcast, &es->tx_broadcast); 3914266423Sjfv vsi->stat_offsets_loaded = true; 3915266423Sjfv} 3916266423Sjfv 3917266423Sjfv/** 3918266423Sjfv * Reset all of the stats for the given pf 3919266423Sjfv **/ 3920266423Sjfvvoid i40e_pf_reset_stats(struct i40e_pf *pf) 3921266423Sjfv{ 3922266423Sjfv bzero(&pf->stats, sizeof(struct i40e_hw_port_stats)); 3923266423Sjfv bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats)); 3924266423Sjfv pf->stat_offsets_loaded = false; 3925266423Sjfv} 3926266423Sjfv 3927266423Sjfv/** 3928266423Sjfv * Resets all stats of the given vsi 3929266423Sjfv **/ 3930266423Sjfvvoid i40e_vsi_reset_stats(struct i40e_vsi *vsi) 3931266423Sjfv{ 3932266423Sjfv bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats)); 3933266423Sjfv bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats)); 3934266423Sjfv vsi->stat_offsets_loaded = false; 3935266423Sjfv} 3936266423Sjfv 3937266423Sjfv/** 3938266423Sjfv * Read and update a 48 bit stat from the hw 3939266423Sjfv * 3940266423Sjfv * Since the device stats are not reset at PFReset, they likely will not 3941266423Sjfv * be zeroed when the driver starts. We'll save the first values read 3942266423Sjfv * and use them as offsets to be subtracted from the raw values in order 3943266423Sjfv * to report stats that count from zero. 3944266423Sjfv **/ 3945266423Sjfvstatic void 3946266423Sjfvi40e_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg, 3947266423Sjfv bool offset_loaded, u64 *offset, u64 *stat) 3948266423Sjfv{ 3949266423Sjfv u64 new_data; 3950266423Sjfv 3951266423Sjfv#if __FreeBSD__ >= 10 && __amd64__ 3952266423Sjfv new_data = rd64(hw, loreg); 3953266423Sjfv#else 3954266423Sjfv /* 3955266423Sjfv * Use two rd32's instead of one rd64 because FreeBSD versions before 3956266423Sjfv * 10 don't support 8 byte bus reads/writes. 3957266423Sjfv */ 3958266423Sjfv new_data = rd32(hw, loreg); 3959266423Sjfv new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32; 3960266423Sjfv#endif 3961266423Sjfv 3962266423Sjfv if (!offset_loaded) 3963266423Sjfv *offset = new_data; 3964266423Sjfv if (new_data >= *offset) 3965266423Sjfv *stat = new_data - *offset; 3966266423Sjfv else 3967266423Sjfv *stat = (new_data + ((u64)1 << 48)) - *offset; 3968266423Sjfv *stat &= 0xFFFFFFFFFFFFULL; 3969266423Sjfv} 3970266423Sjfv 3971266423Sjfv/** 3972266423Sjfv * Read and update a 32 bit stat from the hw 3973266423Sjfv **/ 3974266423Sjfvstatic void 3975266423Sjfvi40e_stat_update32(struct i40e_hw *hw, u32 reg, 3976266423Sjfv bool offset_loaded, u64 *offset, u64 *stat) 3977266423Sjfv{ 3978266423Sjfv u32 new_data; 3979266423Sjfv 3980266423Sjfv new_data = rd32(hw, reg); 3981266423Sjfv if (!offset_loaded) 3982266423Sjfv *offset = new_data; 3983266423Sjfv if (new_data >= *offset) 3984266423Sjfv *stat = (u32)(new_data - *offset); 3985266423Sjfv else 3986266423Sjfv *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); 3987266423Sjfv} 3988266423Sjfv 3989266423Sjfv/* 3990266423Sjfv** Set flow control using sysctl: 3991266423Sjfv** Flow control values: 3992266423Sjfv** 0 - off 3993266423Sjfv** 1 - rx pause 3994266423Sjfv** 2 - tx pause 3995266423Sjfv** 3 - full 3996266423Sjfv*/ 3997266423Sjfvstatic int 3998266423Sjfvi40e_set_flowcntl(SYSCTL_HANDLER_ARGS) 3999266423Sjfv{ 4000266423Sjfv /* 4001266423Sjfv * TODO: ensure flow control is disabled if 4002266423Sjfv * priority flow control is enabled 4003266423Sjfv * 4004266423Sjfv * TODO: ensure tx CRC by hardware should be enabled 4005266423Sjfv * if tx flow control is enabled. 4006266423Sjfv */ 4007266423Sjfv struct i40e_pf *pf = (struct i40e_pf *)arg1; 4008266423Sjfv struct i40e_hw *hw = &pf->hw; 4009266423Sjfv device_t dev = pf->dev; 4010266423Sjfv struct i40e_aq_get_phy_abilities_resp abilities; 4011266423Sjfv int requested_fc = 0, error = 0; 4012266423Sjfv enum i40e_status_code aq_error = 0; 4013266423Sjfv u8 fc_aq_err = 0; 4014266423Sjfv 4015266423Sjfv /* Get current capability information */ 4016266423Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, FALSE, &abilities, NULL); 4017266423Sjfv if (aq_error) 4018266423Sjfv device_printf(dev, "Error getting phy capabilities %d," 4019266423Sjfv " aq error: %d\n", aq_error, hw->aq.asq_last_status); 4020266423Sjfv 4021266423Sjfv if ((abilities.abilities & I40E_AQ_PHY_FLAG_PAUSE_TX) && 4022266423Sjfv (abilities.abilities & I40E_AQ_PHY_FLAG_PAUSE_RX)) 4023266423Sjfv hw->fc.current_mode = I40E_FC_FULL; 4024266423Sjfv else if (abilities.abilities & I40E_AQ_PHY_FLAG_PAUSE_TX) 4025266423Sjfv hw->fc.current_mode = I40E_FC_TX_PAUSE; 4026266423Sjfv else if (abilities.abilities & I40E_AQ_PHY_FLAG_PAUSE_RX) 4027266423Sjfv hw->fc.current_mode = I40E_FC_RX_PAUSE; 4028266423Sjfv else 4029266423Sjfv hw->fc.current_mode = I40E_FC_NONE; 4030266423Sjfv 4031266423Sjfv /* Read in new mode */ 4032266423Sjfv requested_fc = hw->fc.current_mode; 4033266423Sjfv error = sysctl_handle_int(oidp, &requested_fc, 0, req); 4034266423Sjfv if ((error) || (req->newptr == NULL)) 4035266423Sjfv goto no_set; 4036266423Sjfv if (requested_fc < 0 || requested_fc > 3) { 4037266423Sjfv device_printf(dev, 4038266423Sjfv "Invalid fc mode; valid modes are 0 through 3\n"); 4039266423Sjfv return (EINVAL); 4040266423Sjfv } 4041266423Sjfv 4042266423Sjfv /* Set fc ability for port */ 4043266423Sjfv hw->fc.requested_mode = requested_fc; 4044266423Sjfv i40e_set_fc(hw, &fc_aq_err, TRUE); 4045266423Sjfv 4046266423Sjfv // DEBUG: Verify flow control setting was successfully set 4047266423Sjfv if (hw->fc.current_mode != hw->fc.requested_mode) { 4048266423Sjfv device_printf(dev, "FC set failure:\n"); 4049266423Sjfv device_printf(dev, "Current: %s / Requested: %s\n", 4050266423Sjfv i40e_fc_string[hw->fc.current_mode], 4051266423Sjfv i40e_fc_string[hw->fc.requested_mode]); 4052266423Sjfv } 4053266423Sjfv 4054266423Sjfvno_set:; 4055266423Sjfv#ifdef I40E_DEBUG 4056266423Sjfv /* Print FC registers */ 4057266423Sjfv u32 reg = 0; 4058266423Sjfv printf("Current FC mode: %s\n", i40e_fc_string[hw->fc.current_mode]); 4059266423Sjfv if (i40e_is_40G_device(hw->device_id)) { 4060266423Sjfv // XXX: Why are these names so long? 4061266423Sjfv reg = rd32(hw, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP); 4062266423Sjfv printf("PRTMAC_HSEC_CTL_RX_ENABLE_GPP (LFC) : %s\n", 4063266423Sjfv ON_OFF_STR(reg & I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_MASK)); 4064266423Sjfv 4065266423Sjfv reg = rd32(hw, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP); 4066266423Sjfv printf("PRTMAC_HSEC_CTL_RX_ENABLE_PPP (PFC) : %s\n", 4067266423Sjfv ON_OFF_STR(reg & I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_MASK)); 4068266423Sjfv 4069266423Sjfv reg = rd32(hw, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE); 4070266423Sjfv printf("PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE (LFC) : %s\n", 4071266423Sjfv ON_OFF_STR(reg & I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_MASK)); 4072266423Sjfv 4073266423Sjfv reg = rd32(hw, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE); 4074266423Sjfv printf("PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE (LFC) : %s\n", 4075266423Sjfv ON_OFF_STR(reg & I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_MASK)); 4076266423Sjfv 4077266423Sjfv reg = rd32(hw, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(8)); 4078266423Sjfv printf("PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER (LFC): %#010x\n", reg); 4079266423Sjfv 4080266423Sjfv reg = rd32(hw, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA(8)); 4081266423Sjfv printf("PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA (LFC) : %#010x\n", 4082266423Sjfv reg & I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_MASK); 4083266423Sjfv } else { 4084266423Sjfv reg = rd32(hw, I40E_PRTDCB_MFLCN); 4085266423Sjfv printf("PRTDCB_MFLCN :\n"); 4086266423Sjfv printf("- PMCF (Pass MAC Control Frames): %s\n", 4087266423Sjfv ON_OFF_STR(reg & I40E_PRTDCB_MFLCN_PMCF_MASK)); 4088266423Sjfv printf("- DPF (Discard Pause Frames) : %s\n", 4089266423Sjfv ON_OFF_STR(reg & I40E_PRTDCB_MFLCN_DPF_MASK)); 4090266423Sjfv printf("- RPFCM (Rx PFC Mode) : %s\n", 4091266423Sjfv ON_OFF_STR(reg & I40E_PRTDCB_MFLCN_RPFCM_MASK)); 4092266423Sjfv printf("- RFCE (Rx LFC Mode) : %s\n", 4093266423Sjfv ON_OFF_STR(reg & I40E_PRTDCB_MFLCN_RFCE_MASK)); 4094266423Sjfv printf("- RPFCE (Rx PFC Enable Bitmap) : %#04x\n", 4095266423Sjfv reg & I40E_PRTDCB_MFLCN_RPFCE_MASK); 4096266423Sjfv reg = rd32(hw, I40E_PRTDCB_FCCFG); 4097266423Sjfv printf("PRTDCB_FCCFG :\n"); 4098266423Sjfv u8 tfce = reg & I40E_PRTDCB_FCCFG_TFCE_MASK; 4099266423Sjfv printf("- TFCE (Tx FC Enable) : %s\n", 4100266423Sjfv (tfce == 3) ? "Reserved" : 4101266423Sjfv (tfce == 2) ? "PFC Enabled" : 4102266423Sjfv (tfce == 1) ? "LFC Enabled" : 4103266423Sjfv "Tx FC Disabled"); 4104266423Sjfv reg = rd32(hw, I40E_PRTDCB_FCTTVN(0)); 4105266423Sjfv printf("PRTDCB_FCCTTVN (LFC) : %#06x\n", 4106266423Sjfv reg & I40E_PRTDCB_FCTTVN_TTV_2N_MASK); 4107266423Sjfv reg = rd32(hw, I40E_PRTDCB_FCRTV); 4108266423Sjfv printf("PRTDCB_FCRTV (Pause ref thresh) : %#06x\n", 4109266423Sjfv reg & I40E_PRTDCB_FCRTV_FC_REFRESH_TH_MASK); 4110266423Sjfv reg = rd32(hw, I40E_PRTDCB_TC2PFC); 4111266423Sjfv printf("PRTDCB_TC2PFC is 0xff : %s\n", 4112266423Sjfv ((reg & I40E_PRTDCB_TC2PFC_TC2PFC_MASK) == 0xFF) 4113266423Sjfv ? "Yes" : "No"); 4114266423Sjfv } 4115266423Sjfv#endif 4116266423Sjfv return (error); 4117266423Sjfv} 4118266423Sjfv 4119266423Sjfv/* 4120266423Sjfv** Get the width and transaction speed of 4121266423Sjfv** the bus this adapter is plugged into. 4122266423Sjfv*/ 4123266423Sjfvstatic u16 4124266423Sjfvi40e_get_bus_info(struct i40e_hw *hw, device_t dev) 4125266423Sjfv{ 4126266423Sjfv u16 link; 4127266423Sjfv u32 offset; 4128266423Sjfv 4129266423Sjfv 4130266423Sjfv /* Get the PCI Express Capabilities offset */ 4131266423Sjfv pci_find_cap(dev, PCIY_EXPRESS, &offset); 4132266423Sjfv 4133266423Sjfv /* ...and read the Link Status Register */ 4134266423Sjfv link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 4135266423Sjfv 4136266423Sjfv switch (link & I40E_PCI_LINK_WIDTH) { 4137266423Sjfv case I40E_PCI_LINK_WIDTH_1: 4138266423Sjfv hw->bus.width = i40e_bus_width_pcie_x1; 4139266423Sjfv break; 4140266423Sjfv case I40E_PCI_LINK_WIDTH_2: 4141266423Sjfv hw->bus.width = i40e_bus_width_pcie_x2; 4142266423Sjfv break; 4143266423Sjfv case I40E_PCI_LINK_WIDTH_4: 4144266423Sjfv hw->bus.width = i40e_bus_width_pcie_x4; 4145266423Sjfv break; 4146266423Sjfv case I40E_PCI_LINK_WIDTH_8: 4147266423Sjfv hw->bus.width = i40e_bus_width_pcie_x8; 4148266423Sjfv break; 4149266423Sjfv default: 4150266423Sjfv hw->bus.width = i40e_bus_width_unknown; 4151266423Sjfv break; 4152266423Sjfv } 4153266423Sjfv 4154266423Sjfv switch (link & I40E_PCI_LINK_SPEED) { 4155266423Sjfv case I40E_PCI_LINK_SPEED_2500: 4156266423Sjfv hw->bus.speed = i40e_bus_speed_2500; 4157266423Sjfv break; 4158266423Sjfv case I40E_PCI_LINK_SPEED_5000: 4159266423Sjfv hw->bus.speed = i40e_bus_speed_5000; 4160266423Sjfv break; 4161266423Sjfv case I40E_PCI_LINK_SPEED_8000: 4162266423Sjfv hw->bus.speed = i40e_bus_speed_8000; 4163266423Sjfv break; 4164266423Sjfv default: 4165266423Sjfv hw->bus.speed = i40e_bus_speed_unknown; 4166266423Sjfv break; 4167266423Sjfv } 4168266423Sjfv 4169266423Sjfv 4170266423Sjfv device_printf(dev,"PCI Express Bus: Speed %s %s\n", 4171266423Sjfv ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s": 4172266423Sjfv (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s": 4173266423Sjfv (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"), 4174266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" : 4175266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" : 4176266423Sjfv (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" : 4177266423Sjfv ("Unknown")); 4178266423Sjfv 4179266423Sjfv if ((hw->bus.width <= i40e_bus_width_pcie_x8) && 4180266423Sjfv (hw->bus.speed < i40e_bus_speed_8000)) { 4181266423Sjfv device_printf(dev, "PCI-Express bandwidth available" 4182266423Sjfv " for this device\n is not sufficient for" 4183266423Sjfv " normal operation.\n"); 4184266423Sjfv device_printf(dev, "For expected performance a x8 " 4185266423Sjfv "PCIE Gen3 slot is required.\n"); 4186266423Sjfv } 4187266423Sjfv 4188266423Sjfv return (link); 4189266423Sjfv} 4190266423Sjfv 4191266423Sjfv#ifdef I40E_DEBUG 4192266423Sjfvstatic int 4193266423Sjfvi40e_sysctl_link_status(SYSCTL_HANDLER_ARGS) 4194266423Sjfv{ 4195266423Sjfv struct i40e_pf *pf = (struct i40e_pf *)arg1; 4196266423Sjfv struct i40e_hw *hw = &pf->hw; 4197266423Sjfv struct i40e_link_status link_status; 4198266423Sjfv char buf[512]; 4199266423Sjfv 4200266423Sjfv enum i40e_status_code aq_error = 0; 4201266423Sjfv 4202266423Sjfv aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL); 4203266423Sjfv if (aq_error) { 4204266423Sjfv printf("i40e_aq_get_link_info() error %d\n", aq_error); 4205266423Sjfv return (EPERM); 4206266423Sjfv } 4207266423Sjfv 4208266423Sjfv sprintf(buf, "\n" 4209266423Sjfv "PHY Type : %#04x\n" 4210266423Sjfv "Speed : %#04x\n" 4211266423Sjfv "Link info: %#04x\n" 4212266423Sjfv "AN info : %#04x\n" 4213266423Sjfv "Ext info : %#04x", 4214266423Sjfv link_status.phy_type, link_status.link_speed, 4215266423Sjfv link_status.link_info, link_status.an_info, 4216266423Sjfv link_status.ext_info); 4217266423Sjfv 4218266423Sjfv return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 4219266423Sjfv} 4220266423Sjfv 4221266423Sjfvstatic int 4222266423Sjfvi40e_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS) 4223266423Sjfv{ 4224266423Sjfv struct i40e_pf *pf = (struct i40e_pf *)arg1; 4225266423Sjfv struct i40e_hw *hw = &pf->hw; 4226266423Sjfv struct i40e_aq_get_phy_abilities_resp abilities_resp; 4227266423Sjfv char buf[512]; 4228266423Sjfv 4229266423Sjfv enum i40e_status_code aq_error = 0; 4230266423Sjfv 4231266423Sjfv // TODO: Print out list of qualified modules as well? 4232266423Sjfv aq_error = i40e_aq_get_phy_capabilities(hw, TRUE, FALSE, &abilities_resp, NULL); 4233266423Sjfv if (aq_error) { 4234266423Sjfv printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error); 4235266423Sjfv return (EPERM); 4236266423Sjfv } 4237266423Sjfv 4238266423Sjfv sprintf(buf, "\n" 4239266423Sjfv "PHY Type : %#010x\n" 4240266423Sjfv "Speed : %#04x\n" 4241266423Sjfv "Abilities: %#04x\n" 4242266423Sjfv "EEE cap : %#06x\n" 4243266423Sjfv "EEER reg : %#010x\n" 4244266423Sjfv "D3 Lpan : %#04x", 4245266423Sjfv abilities_resp.phy_type, abilities_resp.link_speed, 4246266423Sjfv abilities_resp.abilities, abilities_resp.eee_capability, 4247266423Sjfv abilities_resp.eeer_val, abilities_resp.d3_lpan); 4248266423Sjfv 4249266423Sjfv return (sysctl_handle_string(oidp, buf, strlen(buf), req)); 4250266423Sjfv} 4251266423Sjfv 4252266423Sjfvstatic int 4253266423Sjfvi40e_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS) 4254266423Sjfv{ 4255266423Sjfv struct i40e_pf *pf = (struct i40e_pf *)arg1; 4256266423Sjfv struct i40e_vsi *vsi = &pf->vsi; 4257266423Sjfv struct i40e_mac_filter *f; 4258266423Sjfv char *buf, *buf_i; 4259266423Sjfv 4260266423Sjfv int error = 0; 4261266423Sjfv int ftl_len = 0; 4262266423Sjfv int ftl_counter = 0; 4263266423Sjfv int buf_len = 0; 4264266423Sjfv int entry_len = 42; 4265266423Sjfv 4266266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 4267266423Sjfv ftl_len++; 4268266423Sjfv } 4269266423Sjfv 4270266423Sjfv if (ftl_len < 1) { 4271266423Sjfv sysctl_handle_string(oidp, "(none)", 6, req); 4272266423Sjfv return (0); 4273266423Sjfv } 4274266423Sjfv 4275266423Sjfv buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2; 4276266423Sjfv buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT); 4277266423Sjfv 4278266423Sjfv sprintf(buf_i++, "\n"); 4279266423Sjfv SLIST_FOREACH(f, &vsi->ftl, next) { 4280266423Sjfv sprintf(buf_i, 4281266423Sjfv MAC_FORMAT ", vlan %4d, flags %#06x", 4282266423Sjfv MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags); 4283266423Sjfv buf_i += entry_len; 4284266423Sjfv /* don't print '\n' for last entry */ 4285266423Sjfv if (++ftl_counter != ftl_len) { 4286266423Sjfv sprintf(buf_i, "\n"); 4287266423Sjfv buf_i++; 4288266423Sjfv } 4289266423Sjfv } 4290266423Sjfv 4291266423Sjfv error = sysctl_handle_string(oidp, buf, strlen(buf), req); 4292266423Sjfv if (error) 4293266423Sjfv printf("sysctl error: %d\n", error); 4294266423Sjfv free(buf, M_DEVBUF); 4295266423Sjfv return error; 4296266423Sjfv} 4297266423Sjfv#endif 4298266423Sjfv 4299