1758cc3dcSJack F Vogel /****************************************************************************** 2758cc3dcSJack F Vogel 3758cc3dcSJack F Vogel Copyright (c) 2001-2015, Intel Corporation 4758cc3dcSJack F Vogel All rights reserved. 5758cc3dcSJack F Vogel 6758cc3dcSJack F Vogel Redistribution and use in source and binary forms, with or without 7758cc3dcSJack F Vogel modification, are permitted provided that the following conditions are met: 8758cc3dcSJack F Vogel 9758cc3dcSJack F Vogel 1. Redistributions of source code must retain the above copyright notice, 10758cc3dcSJack F Vogel this list of conditions and the following disclaimer. 11758cc3dcSJack F Vogel 12758cc3dcSJack F Vogel 2. Redistributions in binary form must reproduce the above copyright 13758cc3dcSJack F Vogel notice, this list of conditions and the following disclaimer in the 14758cc3dcSJack F Vogel documentation and/or other materials provided with the distribution. 15758cc3dcSJack F Vogel 16758cc3dcSJack F Vogel 3. Neither the name of the Intel Corporation nor the names of its 17758cc3dcSJack F Vogel contributors may be used to endorse or promote products derived from 18758cc3dcSJack F Vogel this software without specific prior written permission. 19758cc3dcSJack F Vogel 20758cc3dcSJack F Vogel THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21758cc3dcSJack F Vogel AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22758cc3dcSJack F Vogel IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23758cc3dcSJack F Vogel ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24758cc3dcSJack F Vogel LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25758cc3dcSJack F Vogel CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26758cc3dcSJack F Vogel SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27758cc3dcSJack F Vogel INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28758cc3dcSJack F Vogel CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29758cc3dcSJack F Vogel ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30758cc3dcSJack F Vogel POSSIBILITY OF SUCH DAMAGE. 31758cc3dcSJack F Vogel 32758cc3dcSJack F Vogel ******************************************************************************/ 33758cc3dcSJack F Vogel /*$FreeBSD$*/ 34758cc3dcSJack F Vogel 35758cc3dcSJack F Vogel 36758cc3dcSJack F Vogel #ifndef IXGBE_STANDALONE_BUILD 37758cc3dcSJack F Vogel #include "opt_inet.h" 38758cc3dcSJack F Vogel #include "opt_inet6.h" 39758cc3dcSJack F Vogel #include "opt_rss.h" 40758cc3dcSJack F Vogel #endif 41758cc3dcSJack F Vogel 42758cc3dcSJack F Vogel #include "ixgbe.h" 43758cc3dcSJack F Vogel 44758cc3dcSJack F Vogel #ifdef RSS 45a1edda90SAdrian Chadd #include <net/rss_config.h> 46758cc3dcSJack F Vogel #include <netinet/in_rss.h> 47758cc3dcSJack F Vogel #endif 48758cc3dcSJack F Vogel 49758cc3dcSJack F Vogel /********************************************************************* 50758cc3dcSJack F Vogel * Set this to one to display debug statistics 51758cc3dcSJack F Vogel *********************************************************************/ 52758cc3dcSJack F Vogel int ixgbe_display_debug_stats = 0; 53758cc3dcSJack F Vogel 54758cc3dcSJack F Vogel /********************************************************************* 55758cc3dcSJack F Vogel * Driver version 56758cc3dcSJack F Vogel *********************************************************************/ 57758cc3dcSJack F Vogel char ixgbe_driver_version[] = "2.7.4"; 58758cc3dcSJack F Vogel 59758cc3dcSJack F Vogel /********************************************************************* 60758cc3dcSJack F Vogel * PCI Device ID Table 61758cc3dcSJack F Vogel * 62758cc3dcSJack F Vogel * Used by probe to select devices to load on 63758cc3dcSJack F Vogel * Last field stores an index into ixgbe_strings 64758cc3dcSJack F Vogel * Last entry must be all 0s 65758cc3dcSJack F Vogel * 66758cc3dcSJack F Vogel * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 67758cc3dcSJack F Vogel *********************************************************************/ 68758cc3dcSJack F Vogel 69758cc3dcSJack F Vogel static ixgbe_vendor_info_t ixgbe_vendor_info_array[] = 70758cc3dcSJack F Vogel { 71758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT, 0, 0, 0}, 72758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT, 0, 0, 0}, 73758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4, 0, 0, 0}, 74758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT, 0, 0, 0}, 75758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT2, 0, 0, 0}, 76758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598, 0, 0, 0}, 77758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_DA_DUAL_PORT, 0, 0, 0}, 78758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_CX4_DUAL_PORT, 0, 0, 0}, 79758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_XF_LR, 0, 0, 0}, 80758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM, 0, 0, 0}, 81758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_SFP_LOM, 0, 0, 0}, 82758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4, 0, 0, 0}, 83758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4_MEZZ, 0, 0, 0}, 84758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP, 0, 0, 0}, 85758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_XAUI_LOM, 0, 0, 0}, 86758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_CX4, 0, 0, 0}, 87758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_T3_LOM, 0, 0, 0}, 88758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_COMBO_BACKPLANE, 0, 0, 0}, 89758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BACKPLANE_FCOE, 0, 0, 0}, 90758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF2, 0, 0, 0}, 91758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_FCOE, 0, 0, 0}, 92758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599EN_SFP, 0, 0, 0}, 93758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF_QP, 0, 0, 0}, 94758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_QSFP_SF_QP, 0, 0, 0}, 95758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T, 0, 0, 0}, 96758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T1, 0, 0, 0}, 97758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T, 0, 0, 0}, 98758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KR, 0, 0, 0}, 99758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KX4, 0, 0, 0}, 100758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_10G_T, 0, 0, 0}, 101758cc3dcSJack F Vogel /* required last entry */ 102758cc3dcSJack F Vogel {0, 0, 0, 0, 0} 103758cc3dcSJack F Vogel }; 104758cc3dcSJack F Vogel 105758cc3dcSJack F Vogel /********************************************************************* 106758cc3dcSJack F Vogel * Table of branding strings 107758cc3dcSJack F Vogel *********************************************************************/ 108758cc3dcSJack F Vogel 109758cc3dcSJack F Vogel static char *ixgbe_strings[] = { 110758cc3dcSJack F Vogel "Intel(R) PRO/10GbE PCI-Express Network Driver" 111758cc3dcSJack F Vogel }; 112758cc3dcSJack F Vogel 113758cc3dcSJack F Vogel /********************************************************************* 114758cc3dcSJack F Vogel * Function prototypes 115758cc3dcSJack F Vogel *********************************************************************/ 116758cc3dcSJack F Vogel static int ixgbe_probe(device_t); 117758cc3dcSJack F Vogel static int ixgbe_attach(device_t); 118758cc3dcSJack F Vogel static int ixgbe_detach(device_t); 119758cc3dcSJack F Vogel static int ixgbe_shutdown(device_t); 120758cc3dcSJack F Vogel static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t); 121758cc3dcSJack F Vogel static void ixgbe_init(void *); 122758cc3dcSJack F Vogel static void ixgbe_init_locked(struct adapter *); 123758cc3dcSJack F Vogel static void ixgbe_stop(void *); 124758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 125758cc3dcSJack F Vogel static uint64_t ixgbe_get_counter(struct ifnet *, ift_counter); 126758cc3dcSJack F Vogel #endif 127758cc3dcSJack F Vogel static void ixgbe_add_media_types(struct adapter *); 128758cc3dcSJack F Vogel static void ixgbe_media_status(struct ifnet *, struct ifmediareq *); 129758cc3dcSJack F Vogel static int ixgbe_media_change(struct ifnet *); 130758cc3dcSJack F Vogel static void ixgbe_identify_hardware(struct adapter *); 131758cc3dcSJack F Vogel static int ixgbe_allocate_pci_resources(struct adapter *); 132758cc3dcSJack F Vogel static void ixgbe_get_slot_info(struct ixgbe_hw *); 133758cc3dcSJack F Vogel static int ixgbe_allocate_msix(struct adapter *); 134758cc3dcSJack F Vogel static int ixgbe_allocate_legacy(struct adapter *); 135758cc3dcSJack F Vogel static int ixgbe_setup_msix(struct adapter *); 136758cc3dcSJack F Vogel static void ixgbe_free_pci_resources(struct adapter *); 137758cc3dcSJack F Vogel static void ixgbe_local_timer(void *); 138758cc3dcSJack F Vogel static int ixgbe_setup_interface(device_t, struct adapter *); 139758cc3dcSJack F Vogel static void ixgbe_config_link(struct adapter *); 140758cc3dcSJack F Vogel static void ixgbe_rearm_queues(struct adapter *, u64); 141758cc3dcSJack F Vogel 142758cc3dcSJack F Vogel static void ixgbe_initialize_transmit_units(struct adapter *); 143758cc3dcSJack F Vogel static void ixgbe_initialize_receive_units(struct adapter *); 144758cc3dcSJack F Vogel static void ixgbe_enable_rx_drop(struct adapter *); 145758cc3dcSJack F Vogel static void ixgbe_disable_rx_drop(struct adapter *); 146758cc3dcSJack F Vogel 147758cc3dcSJack F Vogel static void ixgbe_enable_intr(struct adapter *); 148758cc3dcSJack F Vogel static void ixgbe_disable_intr(struct adapter *); 149758cc3dcSJack F Vogel static void ixgbe_update_stats_counters(struct adapter *); 150758cc3dcSJack F Vogel static void ixgbe_set_promisc(struct adapter *); 151758cc3dcSJack F Vogel static void ixgbe_set_multi(struct adapter *); 152758cc3dcSJack F Vogel static void ixgbe_update_link_status(struct adapter *); 153758cc3dcSJack F Vogel static int ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS); 154758cc3dcSJack F Vogel static int ixgbe_set_advertise(SYSCTL_HANDLER_ARGS); 155758cc3dcSJack F Vogel static int ixgbe_set_thermal_test(SYSCTL_HANDLER_ARGS); 156758cc3dcSJack F Vogel static void ixgbe_set_ivar(struct adapter *, u8, u8, s8); 157758cc3dcSJack F Vogel static void ixgbe_configure_ivars(struct adapter *); 158758cc3dcSJack F Vogel static u8 * ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); 159758cc3dcSJack F Vogel 160758cc3dcSJack F Vogel static void ixgbe_setup_vlan_hw_support(struct adapter *); 161758cc3dcSJack F Vogel static void ixgbe_register_vlan(void *, struct ifnet *, u16); 162758cc3dcSJack F Vogel static void ixgbe_unregister_vlan(void *, struct ifnet *, u16); 163758cc3dcSJack F Vogel 164758cc3dcSJack F Vogel static void ixgbe_add_hw_stats(struct adapter *adapter); 165758cc3dcSJack F Vogel 166758cc3dcSJack F Vogel /* Support for pluggable optic modules */ 167758cc3dcSJack F Vogel static bool ixgbe_sfp_probe(struct adapter *); 168758cc3dcSJack F Vogel static void ixgbe_setup_optics(struct adapter *); 169758cc3dcSJack F Vogel 170758cc3dcSJack F Vogel /* Legacy (single vector interrupt handler */ 171758cc3dcSJack F Vogel static void ixgbe_legacy_irq(void *); 172758cc3dcSJack F Vogel 173758cc3dcSJack F Vogel /* The MSI/X Interrupt handlers */ 174758cc3dcSJack F Vogel static void ixgbe_msix_que(void *); 175758cc3dcSJack F Vogel static void ixgbe_msix_link(void *); 176758cc3dcSJack F Vogel 177758cc3dcSJack F Vogel /* Deferred interrupt tasklets */ 178758cc3dcSJack F Vogel static void ixgbe_handle_que(void *, int); 179758cc3dcSJack F Vogel static void ixgbe_handle_link(void *, int); 180758cc3dcSJack F Vogel static void ixgbe_handle_msf(void *, int); 181758cc3dcSJack F Vogel static void ixgbe_handle_mod(void *, int); 182758cc3dcSJack F Vogel 183758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 184758cc3dcSJack F Vogel static void ixgbe_reinit_fdir(void *, int); 185758cc3dcSJack F Vogel #endif 186758cc3dcSJack F Vogel 187758cc3dcSJack F Vogel 188758cc3dcSJack F Vogel /* Missing shared code prototype */ 189758cc3dcSJack F Vogel extern void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw); 190758cc3dcSJack F Vogel 191758cc3dcSJack F Vogel /********************************************************************* 192758cc3dcSJack F Vogel * FreeBSD Device Interface Entry Points 193758cc3dcSJack F Vogel *********************************************************************/ 194758cc3dcSJack F Vogel 195a1edda90SAdrian Chadd static device_method_t ix_methods[] = { 196758cc3dcSJack F Vogel /* Device interface */ 197758cc3dcSJack F Vogel DEVMETHOD(device_probe, ixgbe_probe), 198758cc3dcSJack F Vogel DEVMETHOD(device_attach, ixgbe_attach), 199758cc3dcSJack F Vogel DEVMETHOD(device_detach, ixgbe_detach), 200758cc3dcSJack F Vogel DEVMETHOD(device_shutdown, ixgbe_shutdown), 201758cc3dcSJack F Vogel DEVMETHOD_END 202758cc3dcSJack F Vogel }; 203758cc3dcSJack F Vogel 204a1edda90SAdrian Chadd static driver_t ix_driver = { 205a1edda90SAdrian Chadd "ix", ix_methods, sizeof(struct adapter), 206758cc3dcSJack F Vogel }; 207758cc3dcSJack F Vogel 208a1edda90SAdrian Chadd devclass_t ix_devclass; 209a1edda90SAdrian Chadd DRIVER_MODULE(ix, pci, ix_driver, ix_devclass, 0, 0); 210758cc3dcSJack F Vogel 211a1edda90SAdrian Chadd MODULE_DEPEND(ix, pci, 1, 1, 1); 212a1edda90SAdrian Chadd MODULE_DEPEND(ix, ether, 1, 1, 1); 213758cc3dcSJack F Vogel 214758cc3dcSJack F Vogel /* 215758cc3dcSJack F Vogel ** TUNEABLE PARAMETERS: 216758cc3dcSJack F Vogel */ 217758cc3dcSJack F Vogel 218758cc3dcSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0, 219758cc3dcSJack F Vogel "IXGBE driver parameters"); 220758cc3dcSJack F Vogel 221758cc3dcSJack F Vogel /* 222758cc3dcSJack F Vogel ** AIM: Adaptive Interrupt Moderation 223758cc3dcSJack F Vogel ** which means that the interrupt rate 224758cc3dcSJack F Vogel ** is varied over time based on the 225758cc3dcSJack F Vogel ** traffic for that interrupt vector 226758cc3dcSJack F Vogel */ 227758cc3dcSJack F Vogel static int ixgbe_enable_aim = TRUE; 228758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0, 229758cc3dcSJack F Vogel "Enable adaptive interrupt moderation"); 230758cc3dcSJack F Vogel 231758cc3dcSJack F Vogel static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY); 232758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN, 233758cc3dcSJack F Vogel &ixgbe_max_interrupt_rate, 0, "Maximum interrupts per second"); 234758cc3dcSJack F Vogel 235758cc3dcSJack F Vogel /* How many packets rxeof tries to clean at a time */ 236758cc3dcSJack F Vogel static int ixgbe_rx_process_limit = 256; 237758cc3dcSJack F Vogel TUNABLE_INT("hw.ixgbe.rx_process_limit", &ixgbe_rx_process_limit); 238758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, 239758cc3dcSJack F Vogel &ixgbe_rx_process_limit, 0, 240758cc3dcSJack F Vogel "Maximum number of received packets to process at a time," 241758cc3dcSJack F Vogel "-1 means unlimited"); 242758cc3dcSJack F Vogel 243758cc3dcSJack F Vogel /* How many packets txeof tries to clean at a time */ 244758cc3dcSJack F Vogel static int ixgbe_tx_process_limit = 256; 245758cc3dcSJack F Vogel TUNABLE_INT("hw.ixgbe.tx_process_limit", &ixgbe_tx_process_limit); 246758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, tx_process_limit, CTLFLAG_RDTUN, 247758cc3dcSJack F Vogel &ixgbe_tx_process_limit, 0, 248758cc3dcSJack F Vogel "Maximum number of sent packets to process at a time," 249758cc3dcSJack F Vogel "-1 means unlimited"); 250758cc3dcSJack F Vogel 251758cc3dcSJack F Vogel /* 252758cc3dcSJack F Vogel ** Smart speed setting, default to on 253758cc3dcSJack F Vogel ** this only works as a compile option 254758cc3dcSJack F Vogel ** right now as its during attach, set 255758cc3dcSJack F Vogel ** this to 'ixgbe_smart_speed_off' to 256758cc3dcSJack F Vogel ** disable. 257758cc3dcSJack F Vogel */ 258758cc3dcSJack F Vogel static int ixgbe_smart_speed = ixgbe_smart_speed_on; 259758cc3dcSJack F Vogel 260758cc3dcSJack F Vogel /* 261758cc3dcSJack F Vogel * MSIX should be the default for best performance, 262758cc3dcSJack F Vogel * but this allows it to be forced off for testing. 263758cc3dcSJack F Vogel */ 264758cc3dcSJack F Vogel static int ixgbe_enable_msix = 1; 265758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixgbe_enable_msix, 0, 266758cc3dcSJack F Vogel "Enable MSI-X interrupts"); 267758cc3dcSJack F Vogel 268758cc3dcSJack F Vogel /* 269758cc3dcSJack F Vogel * Number of Queues, can be set to 0, 270758cc3dcSJack F Vogel * it then autoconfigures based on the 271758cc3dcSJack F Vogel * number of cpus with a max of 8. This 272758cc3dcSJack F Vogel * can be overriden manually here. 273758cc3dcSJack F Vogel */ 274758cc3dcSJack F Vogel static int ixgbe_num_queues = 0; 275758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, num_queues, CTLFLAG_RDTUN, &ixgbe_num_queues, 0, 276758cc3dcSJack F Vogel "Number of queues to configure, 0 indicates autoconfigure"); 277758cc3dcSJack F Vogel 278758cc3dcSJack F Vogel /* 279758cc3dcSJack F Vogel ** Number of TX descriptors per ring, 280758cc3dcSJack F Vogel ** setting higher than RX as this seems 281758cc3dcSJack F Vogel ** the better performing choice. 282758cc3dcSJack F Vogel */ 283758cc3dcSJack F Vogel static int ixgbe_txd = PERFORM_TXD; 284758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, txd, CTLFLAG_RDTUN, &ixgbe_txd, 0, 285758cc3dcSJack F Vogel "Number of transmit descriptors per queue"); 286758cc3dcSJack F Vogel 287758cc3dcSJack F Vogel /* Number of RX descriptors per ring */ 288758cc3dcSJack F Vogel static int ixgbe_rxd = PERFORM_RXD; 289758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rxd, CTLFLAG_RDTUN, &ixgbe_rxd, 0, 290758cc3dcSJack F Vogel "Number of receive descriptors per queue"); 291758cc3dcSJack F Vogel 292758cc3dcSJack F Vogel /* 293758cc3dcSJack F Vogel ** Defining this on will allow the use 294758cc3dcSJack F Vogel ** of unsupported SFP+ modules, note that 295758cc3dcSJack F Vogel ** doing so you are on your own :) 296758cc3dcSJack F Vogel */ 297758cc3dcSJack F Vogel static int allow_unsupported_sfp = FALSE; 298758cc3dcSJack F Vogel TUNABLE_INT("hw.ix.unsupported_sfp", &allow_unsupported_sfp); 299758cc3dcSJack F Vogel 300758cc3dcSJack F Vogel /* Keep running tab on them for sanity check */ 301758cc3dcSJack F Vogel static int ixgbe_total_ports; 302758cc3dcSJack F Vogel 303758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 304758cc3dcSJack F Vogel /* 305758cc3dcSJack F Vogel ** Flow Director actually 'steals' 306758cc3dcSJack F Vogel ** part of the packet buffer as its 307758cc3dcSJack F Vogel ** filter pool, this variable controls 308758cc3dcSJack F Vogel ** how much it uses: 309758cc3dcSJack F Vogel ** 0 = 64K, 1 = 128K, 2 = 256K 310758cc3dcSJack F Vogel */ 311758cc3dcSJack F Vogel static int fdir_pballoc = 1; 312758cc3dcSJack F Vogel #endif 313758cc3dcSJack F Vogel 314758cc3dcSJack F Vogel #ifdef DEV_NETMAP 315758cc3dcSJack F Vogel /* 316758cc3dcSJack F Vogel * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to 317758cc3dcSJack F Vogel * be a reference on how to implement netmap support in a driver. 318758cc3dcSJack F Vogel * Additional comments are in ixgbe_netmap.h . 319758cc3dcSJack F Vogel * 320758cc3dcSJack F Vogel * <dev/netmap/ixgbe_netmap.h> contains functions for netmap support 321758cc3dcSJack F Vogel * that extend the standard driver. 322758cc3dcSJack F Vogel */ 323758cc3dcSJack F Vogel #include <dev/netmap/ixgbe_netmap.h> 324758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 325758cc3dcSJack F Vogel 326758cc3dcSJack F Vogel /********************************************************************* 327758cc3dcSJack F Vogel * Device identification routine 328758cc3dcSJack F Vogel * 329758cc3dcSJack F Vogel * ixgbe_probe determines if the driver should be loaded on 330758cc3dcSJack F Vogel * adapter based on PCI vendor/device id of the adapter. 331758cc3dcSJack F Vogel * 332758cc3dcSJack F Vogel * return BUS_PROBE_DEFAULT on success, positive on failure 333758cc3dcSJack F Vogel *********************************************************************/ 334758cc3dcSJack F Vogel 335758cc3dcSJack F Vogel static int 336758cc3dcSJack F Vogel ixgbe_probe(device_t dev) 337758cc3dcSJack F Vogel { 338758cc3dcSJack F Vogel ixgbe_vendor_info_t *ent; 339758cc3dcSJack F Vogel 340758cc3dcSJack F Vogel u16 pci_vendor_id = 0; 341758cc3dcSJack F Vogel u16 pci_device_id = 0; 342758cc3dcSJack F Vogel u16 pci_subvendor_id = 0; 343758cc3dcSJack F Vogel u16 pci_subdevice_id = 0; 344758cc3dcSJack F Vogel char adapter_name[256]; 345758cc3dcSJack F Vogel 346758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_probe: begin"); 347758cc3dcSJack F Vogel 348758cc3dcSJack F Vogel pci_vendor_id = pci_get_vendor(dev); 349758cc3dcSJack F Vogel if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) 350758cc3dcSJack F Vogel return (ENXIO); 351758cc3dcSJack F Vogel 352758cc3dcSJack F Vogel pci_device_id = pci_get_device(dev); 353758cc3dcSJack F Vogel pci_subvendor_id = pci_get_subvendor(dev); 354758cc3dcSJack F Vogel pci_subdevice_id = pci_get_subdevice(dev); 355758cc3dcSJack F Vogel 356758cc3dcSJack F Vogel ent = ixgbe_vendor_info_array; 357758cc3dcSJack F Vogel while (ent->vendor_id != 0) { 358758cc3dcSJack F Vogel if ((pci_vendor_id == ent->vendor_id) && 359758cc3dcSJack F Vogel (pci_device_id == ent->device_id) && 360758cc3dcSJack F Vogel 361758cc3dcSJack F Vogel ((pci_subvendor_id == ent->subvendor_id) || 362758cc3dcSJack F Vogel (ent->subvendor_id == 0)) && 363758cc3dcSJack F Vogel 364758cc3dcSJack F Vogel ((pci_subdevice_id == ent->subdevice_id) || 365758cc3dcSJack F Vogel (ent->subdevice_id == 0))) { 366758cc3dcSJack F Vogel sprintf(adapter_name, "%s, Version - %s", 367758cc3dcSJack F Vogel ixgbe_strings[ent->index], 368758cc3dcSJack F Vogel ixgbe_driver_version); 369758cc3dcSJack F Vogel device_set_desc_copy(dev, adapter_name); 370758cc3dcSJack F Vogel ++ixgbe_total_ports; 371758cc3dcSJack F Vogel return (BUS_PROBE_DEFAULT); 372758cc3dcSJack F Vogel } 373758cc3dcSJack F Vogel ent++; 374758cc3dcSJack F Vogel } 375758cc3dcSJack F Vogel return (ENXIO); 376758cc3dcSJack F Vogel } 377758cc3dcSJack F Vogel 378758cc3dcSJack F Vogel /********************************************************************* 379758cc3dcSJack F Vogel * Device initialization routine 380758cc3dcSJack F Vogel * 381758cc3dcSJack F Vogel * The attach entry point is called when the driver is being loaded. 382758cc3dcSJack F Vogel * This routine identifies the type of hardware, allocates all resources 383758cc3dcSJack F Vogel * and initializes the hardware. 384758cc3dcSJack F Vogel * 385758cc3dcSJack F Vogel * return 0 on success, positive on failure 386758cc3dcSJack F Vogel *********************************************************************/ 387758cc3dcSJack F Vogel 388758cc3dcSJack F Vogel static int 389758cc3dcSJack F Vogel ixgbe_attach(device_t dev) 390758cc3dcSJack F Vogel { 391758cc3dcSJack F Vogel struct adapter *adapter; 392758cc3dcSJack F Vogel struct ixgbe_hw *hw; 393758cc3dcSJack F Vogel int error = 0; 394758cc3dcSJack F Vogel u16 csum; 395758cc3dcSJack F Vogel u32 ctrl_ext; 396758cc3dcSJack F Vogel 397758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_attach: begin"); 398758cc3dcSJack F Vogel 399758cc3dcSJack F Vogel /* Allocate, clear, and link in our adapter structure */ 400758cc3dcSJack F Vogel adapter = device_get_softc(dev); 401758cc3dcSJack F Vogel adapter->dev = adapter->osdep.dev = dev; 402758cc3dcSJack F Vogel hw = &adapter->hw; 403758cc3dcSJack F Vogel 404758cc3dcSJack F Vogel /* Core Lock Init*/ 405758cc3dcSJack F Vogel IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); 406758cc3dcSJack F Vogel 407758cc3dcSJack F Vogel /* SYSCTL APIs */ 408758cc3dcSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 409758cc3dcSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 410758cc3dcSJack F Vogel OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, 411758cc3dcSJack F Vogel adapter, 0, ixgbe_set_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC); 412758cc3dcSJack F Vogel 413758cc3dcSJack F Vogel SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 414758cc3dcSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 415758cc3dcSJack F Vogel OID_AUTO, "enable_aim", CTLFLAG_RW, 416758cc3dcSJack F Vogel &ixgbe_enable_aim, 1, "Interrupt Moderation"); 417758cc3dcSJack F Vogel 418758cc3dcSJack F Vogel /* 419758cc3dcSJack F Vogel ** Allow a kind of speed control by forcing the autoneg 420758cc3dcSJack F Vogel ** advertised speed list to only a certain value, this 421758cc3dcSJack F Vogel ** supports 1G on 82599 devices, and 100Mb on x540. 422758cc3dcSJack F Vogel */ 423758cc3dcSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 424758cc3dcSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 425758cc3dcSJack F Vogel OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, 426758cc3dcSJack F Vogel adapter, 0, ixgbe_set_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED); 427758cc3dcSJack F Vogel 428758cc3dcSJack F Vogel SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 429758cc3dcSJack F Vogel SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 430758cc3dcSJack F Vogel OID_AUTO, "ts", CTLTYPE_INT | CTLFLAG_RW, adapter, 431758cc3dcSJack F Vogel 0, ixgbe_set_thermal_test, "I", "Thermal Test"); 432758cc3dcSJack F Vogel 433758cc3dcSJack F Vogel /* Set up the timer callout */ 434758cc3dcSJack F Vogel callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); 435758cc3dcSJack F Vogel 436758cc3dcSJack F Vogel /* Determine hardware revision */ 437758cc3dcSJack F Vogel ixgbe_identify_hardware(adapter); 438758cc3dcSJack F Vogel 439758cc3dcSJack F Vogel /* Do base PCI setup - map BAR0 */ 440758cc3dcSJack F Vogel if (ixgbe_allocate_pci_resources(adapter)) { 441758cc3dcSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 442758cc3dcSJack F Vogel error = ENXIO; 443758cc3dcSJack F Vogel goto err_out; 444758cc3dcSJack F Vogel } 445758cc3dcSJack F Vogel 446758cc3dcSJack F Vogel /* Do descriptor calc and sanity checks */ 447758cc3dcSJack F Vogel if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || 448758cc3dcSJack F Vogel ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) { 449758cc3dcSJack F Vogel device_printf(dev, "TXD config issue, using default!\n"); 450758cc3dcSJack F Vogel adapter->num_tx_desc = DEFAULT_TXD; 451758cc3dcSJack F Vogel } else 452758cc3dcSJack F Vogel adapter->num_tx_desc = ixgbe_txd; 453758cc3dcSJack F Vogel 454758cc3dcSJack F Vogel /* 455758cc3dcSJack F Vogel ** With many RX rings it is easy to exceed the 456758cc3dcSJack F Vogel ** system mbuf allocation. Tuning nmbclusters 457758cc3dcSJack F Vogel ** can alleviate this. 458758cc3dcSJack F Vogel */ 459758cc3dcSJack F Vogel if (nmbclusters > 0) { 460758cc3dcSJack F Vogel int s; 461758cc3dcSJack F Vogel s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports; 462758cc3dcSJack F Vogel if (s > nmbclusters) { 463758cc3dcSJack F Vogel device_printf(dev, "RX Descriptors exceed " 464758cc3dcSJack F Vogel "system mbuf max, using default instead!\n"); 465758cc3dcSJack F Vogel ixgbe_rxd = DEFAULT_RXD; 466758cc3dcSJack F Vogel } 467758cc3dcSJack F Vogel } 468758cc3dcSJack F Vogel 469758cc3dcSJack F Vogel if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || 470758cc3dcSJack F Vogel ixgbe_rxd < MIN_RXD || ixgbe_rxd > MAX_RXD) { 471758cc3dcSJack F Vogel device_printf(dev, "RXD config issue, using default!\n"); 472758cc3dcSJack F Vogel adapter->num_rx_desc = DEFAULT_RXD; 473758cc3dcSJack F Vogel } else 474758cc3dcSJack F Vogel adapter->num_rx_desc = ixgbe_rxd; 475758cc3dcSJack F Vogel 476758cc3dcSJack F Vogel /* Allocate our TX/RX Queues */ 477758cc3dcSJack F Vogel if (ixgbe_allocate_queues(adapter)) { 478758cc3dcSJack F Vogel error = ENOMEM; 479758cc3dcSJack F Vogel goto err_out; 480758cc3dcSJack F Vogel } 481758cc3dcSJack F Vogel 482758cc3dcSJack F Vogel /* Allocate multicast array memory. */ 483758cc3dcSJack F Vogel adapter->mta = malloc(sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS * 484758cc3dcSJack F Vogel MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); 485758cc3dcSJack F Vogel if (adapter->mta == NULL) { 486758cc3dcSJack F Vogel device_printf(dev, "Can not allocate multicast setup array\n"); 487758cc3dcSJack F Vogel error = ENOMEM; 488758cc3dcSJack F Vogel goto err_late; 489758cc3dcSJack F Vogel } 490758cc3dcSJack F Vogel 491758cc3dcSJack F Vogel /* Initialize the shared code */ 492758cc3dcSJack F Vogel hw->allow_unsupported_sfp = allow_unsupported_sfp; 493758cc3dcSJack F Vogel error = ixgbe_init_shared_code(hw); 494758cc3dcSJack F Vogel if (error == IXGBE_ERR_SFP_NOT_PRESENT) { 495758cc3dcSJack F Vogel /* 496758cc3dcSJack F Vogel ** No optics in this port, set up 497758cc3dcSJack F Vogel ** so the timer routine will probe 498758cc3dcSJack F Vogel ** for later insertion. 499758cc3dcSJack F Vogel */ 500758cc3dcSJack F Vogel adapter->sfp_probe = TRUE; 501758cc3dcSJack F Vogel error = 0; 502758cc3dcSJack F Vogel } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { 503758cc3dcSJack F Vogel device_printf(dev,"Unsupported SFP+ module detected!\n"); 504758cc3dcSJack F Vogel error = EIO; 505758cc3dcSJack F Vogel goto err_late; 506758cc3dcSJack F Vogel } else if (error) { 507758cc3dcSJack F Vogel device_printf(dev,"Unable to initialize the shared code\n"); 508758cc3dcSJack F Vogel error = EIO; 509758cc3dcSJack F Vogel goto err_late; 510758cc3dcSJack F Vogel } 511758cc3dcSJack F Vogel 512758cc3dcSJack F Vogel /* Make sure we have a good EEPROM before we read from it */ 513758cc3dcSJack F Vogel if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) { 514758cc3dcSJack F Vogel device_printf(dev,"The EEPROM Checksum Is Not Valid\n"); 515758cc3dcSJack F Vogel error = EIO; 516758cc3dcSJack F Vogel goto err_late; 517758cc3dcSJack F Vogel } 518758cc3dcSJack F Vogel 519758cc3dcSJack F Vogel error = ixgbe_init_hw(hw); 520758cc3dcSJack F Vogel switch (error) { 521758cc3dcSJack F Vogel case IXGBE_ERR_EEPROM_VERSION: 522758cc3dcSJack F Vogel device_printf(dev, "This device is a pre-production adapter/" 523758cc3dcSJack F Vogel "LOM. Please be aware there may be issues associated " 524758cc3dcSJack F Vogel "with your hardware.\n If you are experiencing problems " 525758cc3dcSJack F Vogel "please contact your Intel or hardware representative " 526758cc3dcSJack F Vogel "who provided you with this hardware.\n"); 527758cc3dcSJack F Vogel break; 528758cc3dcSJack F Vogel case IXGBE_ERR_SFP_NOT_SUPPORTED: 529758cc3dcSJack F Vogel device_printf(dev,"Unsupported SFP+ Module\n"); 530758cc3dcSJack F Vogel error = EIO; 531758cc3dcSJack F Vogel goto err_late; 532758cc3dcSJack F Vogel case IXGBE_ERR_SFP_NOT_PRESENT: 533758cc3dcSJack F Vogel device_printf(dev,"No SFP+ Module found\n"); 534758cc3dcSJack F Vogel /* falls thru */ 535758cc3dcSJack F Vogel default: 536758cc3dcSJack F Vogel break; 537758cc3dcSJack F Vogel } 538758cc3dcSJack F Vogel 539758cc3dcSJack F Vogel /* Detect and set physical type */ 540758cc3dcSJack F Vogel ixgbe_setup_optics(adapter); 541758cc3dcSJack F Vogel 542758cc3dcSJack F Vogel if ((adapter->msix > 1) && (ixgbe_enable_msix)) 543758cc3dcSJack F Vogel error = ixgbe_allocate_msix(adapter); 544758cc3dcSJack F Vogel else 545758cc3dcSJack F Vogel error = ixgbe_allocate_legacy(adapter); 546758cc3dcSJack F Vogel if (error) 547758cc3dcSJack F Vogel goto err_late; 548758cc3dcSJack F Vogel 549758cc3dcSJack F Vogel /* Setup OS specific network interface */ 550758cc3dcSJack F Vogel if (ixgbe_setup_interface(dev, adapter) != 0) 551758cc3dcSJack F Vogel goto err_late; 552758cc3dcSJack F Vogel 553758cc3dcSJack F Vogel /* Initialize statistics */ 554758cc3dcSJack F Vogel ixgbe_update_stats_counters(adapter); 555758cc3dcSJack F Vogel 556758cc3dcSJack F Vogel /* Register for VLAN events */ 557758cc3dcSJack F Vogel adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 558758cc3dcSJack F Vogel ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); 559758cc3dcSJack F Vogel adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 560758cc3dcSJack F Vogel ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); 561758cc3dcSJack F Vogel 562758cc3dcSJack F Vogel /* 563758cc3dcSJack F Vogel ** Check PCIE slot type/speed/width 564758cc3dcSJack F Vogel */ 565758cc3dcSJack F Vogel ixgbe_get_slot_info(hw); 566758cc3dcSJack F Vogel 567758cc3dcSJack F Vogel 568758cc3dcSJack F Vogel /* Set an initial default flow control value */ 569758cc3dcSJack F Vogel adapter->fc = ixgbe_fc_full; 570758cc3dcSJack F Vogel 571758cc3dcSJack F Vogel /* let hardware know driver is loaded */ 572758cc3dcSJack F Vogel ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 573758cc3dcSJack F Vogel ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; 574758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 575758cc3dcSJack F Vogel 576758cc3dcSJack F Vogel ixgbe_add_hw_stats(adapter); 577758cc3dcSJack F Vogel 578758cc3dcSJack F Vogel #ifdef DEV_NETMAP 579758cc3dcSJack F Vogel ixgbe_netmap_attach(adapter); 580758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 581758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_attach: end"); 582758cc3dcSJack F Vogel return (0); 583758cc3dcSJack F Vogel 584758cc3dcSJack F Vogel err_late: 585758cc3dcSJack F Vogel ixgbe_free_transmit_structures(adapter); 586758cc3dcSJack F Vogel ixgbe_free_receive_structures(adapter); 587758cc3dcSJack F Vogel err_out: 588758cc3dcSJack F Vogel if (adapter->ifp != NULL) 589758cc3dcSJack F Vogel if_free(adapter->ifp); 590758cc3dcSJack F Vogel ixgbe_free_pci_resources(adapter); 591758cc3dcSJack F Vogel free(adapter->mta, M_DEVBUF); 592758cc3dcSJack F Vogel return (error); 593758cc3dcSJack F Vogel } 594758cc3dcSJack F Vogel 595758cc3dcSJack F Vogel /********************************************************************* 596758cc3dcSJack F Vogel * Device removal routine 597758cc3dcSJack F Vogel * 598758cc3dcSJack F Vogel * The detach entry point is called when the driver is being removed. 599758cc3dcSJack F Vogel * This routine stops the adapter and deallocates all the resources 600758cc3dcSJack F Vogel * that were allocated for driver operation. 601758cc3dcSJack F Vogel * 602758cc3dcSJack F Vogel * return 0 on success, positive on failure 603758cc3dcSJack F Vogel *********************************************************************/ 604758cc3dcSJack F Vogel 605758cc3dcSJack F Vogel static int 606758cc3dcSJack F Vogel ixgbe_detach(device_t dev) 607758cc3dcSJack F Vogel { 608758cc3dcSJack F Vogel struct adapter *adapter = device_get_softc(dev); 609758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 610758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 611758cc3dcSJack F Vogel u32 ctrl_ext; 612758cc3dcSJack F Vogel 613758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_detach: begin"); 614758cc3dcSJack F Vogel 615758cc3dcSJack F Vogel /* Make sure VLANS are not using driver */ 616758cc3dcSJack F Vogel if (adapter->ifp->if_vlantrunk != NULL) { 617758cc3dcSJack F Vogel device_printf(dev,"Vlan in use, detach first\n"); 618758cc3dcSJack F Vogel return (EBUSY); 619758cc3dcSJack F Vogel } 620758cc3dcSJack F Vogel 621758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 622758cc3dcSJack F Vogel ixgbe_stop(adapter); 623758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 624758cc3dcSJack F Vogel 625758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { 626758cc3dcSJack F Vogel if (que->tq) { 627758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 628758cc3dcSJack F Vogel taskqueue_drain(que->tq, &txr->txq_task); 629758cc3dcSJack F Vogel #endif 630758cc3dcSJack F Vogel taskqueue_drain(que->tq, &que->que_task); 631758cc3dcSJack F Vogel taskqueue_free(que->tq); 632758cc3dcSJack F Vogel } 633758cc3dcSJack F Vogel } 634758cc3dcSJack F Vogel 635758cc3dcSJack F Vogel /* Drain the Link queue */ 636758cc3dcSJack F Vogel if (adapter->tq) { 637758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->link_task); 638758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->mod_task); 639758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->msf_task); 640758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 641758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->fdir_task); 642758cc3dcSJack F Vogel #endif 643758cc3dcSJack F Vogel taskqueue_free(adapter->tq); 644758cc3dcSJack F Vogel } 645758cc3dcSJack F Vogel 646758cc3dcSJack F Vogel /* let hardware know driver is unloading */ 647758cc3dcSJack F Vogel ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); 648758cc3dcSJack F Vogel ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; 649758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext); 650758cc3dcSJack F Vogel 651758cc3dcSJack F Vogel /* Unregister VLAN events */ 652758cc3dcSJack F Vogel if (adapter->vlan_attach != NULL) 653758cc3dcSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); 654758cc3dcSJack F Vogel if (adapter->vlan_detach != NULL) 655758cc3dcSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); 656758cc3dcSJack F Vogel 657758cc3dcSJack F Vogel ether_ifdetach(adapter->ifp); 658758cc3dcSJack F Vogel callout_drain(&adapter->timer); 659758cc3dcSJack F Vogel #ifdef DEV_NETMAP 660758cc3dcSJack F Vogel netmap_detach(adapter->ifp); 661758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 662758cc3dcSJack F Vogel ixgbe_free_pci_resources(adapter); 663758cc3dcSJack F Vogel bus_generic_detach(dev); 664758cc3dcSJack F Vogel if_free(adapter->ifp); 665758cc3dcSJack F Vogel 666758cc3dcSJack F Vogel ixgbe_free_transmit_structures(adapter); 667758cc3dcSJack F Vogel ixgbe_free_receive_structures(adapter); 668758cc3dcSJack F Vogel free(adapter->mta, M_DEVBUF); 669758cc3dcSJack F Vogel 670758cc3dcSJack F Vogel IXGBE_CORE_LOCK_DESTROY(adapter); 671758cc3dcSJack F Vogel return (0); 672758cc3dcSJack F Vogel } 673758cc3dcSJack F Vogel 674758cc3dcSJack F Vogel /********************************************************************* 675758cc3dcSJack F Vogel * 676758cc3dcSJack F Vogel * Shutdown entry point 677758cc3dcSJack F Vogel * 678758cc3dcSJack F Vogel **********************************************************************/ 679758cc3dcSJack F Vogel 680758cc3dcSJack F Vogel static int 681758cc3dcSJack F Vogel ixgbe_shutdown(device_t dev) 682758cc3dcSJack F Vogel { 683758cc3dcSJack F Vogel struct adapter *adapter = device_get_softc(dev); 684758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 685758cc3dcSJack F Vogel ixgbe_stop(adapter); 686758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 687758cc3dcSJack F Vogel return (0); 688758cc3dcSJack F Vogel } 689758cc3dcSJack F Vogel 690758cc3dcSJack F Vogel 691758cc3dcSJack F Vogel /********************************************************************* 692758cc3dcSJack F Vogel * Ioctl entry point 693758cc3dcSJack F Vogel * 694758cc3dcSJack F Vogel * ixgbe_ioctl is called when the user wants to configure the 695758cc3dcSJack F Vogel * interface. 696758cc3dcSJack F Vogel * 697758cc3dcSJack F Vogel * return 0 on success, positive on failure 698758cc3dcSJack F Vogel **********************************************************************/ 699758cc3dcSJack F Vogel 700758cc3dcSJack F Vogel static int 701758cc3dcSJack F Vogel ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 702758cc3dcSJack F Vogel { 703758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 704758cc3dcSJack F Vogel struct ifreq *ifr = (struct ifreq *) data; 705758cc3dcSJack F Vogel #if defined(INET) || defined(INET6) 706758cc3dcSJack F Vogel struct ifaddr *ifa = (struct ifaddr *)data; 707758cc3dcSJack F Vogel bool avoid_reset = FALSE; 708758cc3dcSJack F Vogel #endif 709758cc3dcSJack F Vogel int error = 0; 710758cc3dcSJack F Vogel 711758cc3dcSJack F Vogel switch (command) { 712758cc3dcSJack F Vogel 713758cc3dcSJack F Vogel case SIOCSIFADDR: 714758cc3dcSJack F Vogel #ifdef INET 715758cc3dcSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET) 716758cc3dcSJack F Vogel avoid_reset = TRUE; 717758cc3dcSJack F Vogel #endif 718758cc3dcSJack F Vogel #ifdef INET6 719758cc3dcSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET6) 720758cc3dcSJack F Vogel avoid_reset = TRUE; 721758cc3dcSJack F Vogel #endif 722758cc3dcSJack F Vogel #if defined(INET) || defined(INET6) 723758cc3dcSJack F Vogel /* 724758cc3dcSJack F Vogel ** Calling init results in link renegotiation, 725758cc3dcSJack F Vogel ** so we avoid doing it when possible. 726758cc3dcSJack F Vogel */ 727758cc3dcSJack F Vogel if (avoid_reset) { 728758cc3dcSJack F Vogel ifp->if_flags |= IFF_UP; 729758cc3dcSJack F Vogel if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 730758cc3dcSJack F Vogel ixgbe_init(adapter); 731758cc3dcSJack F Vogel if (!(ifp->if_flags & IFF_NOARP)) 732758cc3dcSJack F Vogel arp_ifinit(ifp, ifa); 733758cc3dcSJack F Vogel } else 734758cc3dcSJack F Vogel error = ether_ioctl(ifp, command, data); 735758cc3dcSJack F Vogel #endif 736758cc3dcSJack F Vogel break; 737758cc3dcSJack F Vogel case SIOCSIFMTU: 738758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 739758cc3dcSJack F Vogel if (ifr->ifr_mtu > IXGBE_MAX_FRAME_SIZE - ETHER_HDR_LEN) { 740758cc3dcSJack F Vogel error = EINVAL; 741758cc3dcSJack F Vogel } else { 742758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 743758cc3dcSJack F Vogel ifp->if_mtu = ifr->ifr_mtu; 744758cc3dcSJack F Vogel adapter->max_frame_size = 745758cc3dcSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 746758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 747758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 748758cc3dcSJack F Vogel } 749758cc3dcSJack F Vogel break; 750758cc3dcSJack F Vogel case SIOCSIFFLAGS: 751758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 752758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 753758cc3dcSJack F Vogel if (ifp->if_flags & IFF_UP) { 754758cc3dcSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 755758cc3dcSJack F Vogel if ((ifp->if_flags ^ adapter->if_flags) & 756758cc3dcSJack F Vogel (IFF_PROMISC | IFF_ALLMULTI)) { 757758cc3dcSJack F Vogel ixgbe_set_promisc(adapter); 758758cc3dcSJack F Vogel } 759758cc3dcSJack F Vogel } else 760758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 761758cc3dcSJack F Vogel } else 762758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) 763758cc3dcSJack F Vogel ixgbe_stop(adapter); 764758cc3dcSJack F Vogel adapter->if_flags = ifp->if_flags; 765758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 766758cc3dcSJack F Vogel break; 767758cc3dcSJack F Vogel case SIOCADDMULTI: 768758cc3dcSJack F Vogel case SIOCDELMULTI: 769758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); 770758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 771758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 772758cc3dcSJack F Vogel ixgbe_disable_intr(adapter); 773758cc3dcSJack F Vogel ixgbe_set_multi(adapter); 774758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 775758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 776758cc3dcSJack F Vogel } 777758cc3dcSJack F Vogel break; 778758cc3dcSJack F Vogel case SIOCSIFMEDIA: 779758cc3dcSJack F Vogel case SIOCGIFMEDIA: 780758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 781758cc3dcSJack F Vogel error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); 782758cc3dcSJack F Vogel break; 783758cc3dcSJack F Vogel case SIOCSIFCAP: 784758cc3dcSJack F Vogel { 785758cc3dcSJack F Vogel int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 786758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 787758cc3dcSJack F Vogel if (mask & IFCAP_HWCSUM) 788758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_HWCSUM; 789758cc3dcSJack F Vogel if (mask & IFCAP_TSO4) 790758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_TSO4; 791758cc3dcSJack F Vogel if (mask & IFCAP_TSO6) 792758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_TSO6; 793758cc3dcSJack F Vogel if (mask & IFCAP_LRO) 794758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_LRO; 795758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWTAGGING) 796758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 797758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWFILTER) 798758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 799758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWTSO) 800758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 801758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 802758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 803758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 804758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 805758cc3dcSJack F Vogel } 806758cc3dcSJack F Vogel VLAN_CAPABILITIES(ifp); 807758cc3dcSJack F Vogel break; 808758cc3dcSJack F Vogel } 809758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 810758cc3dcSJack F Vogel case SIOCGI2C: 811758cc3dcSJack F Vogel { 812758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 813758cc3dcSJack F Vogel struct ifi2creq i2c; 814758cc3dcSJack F Vogel int i; 815758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)"); 816758cc3dcSJack F Vogel error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); 817758cc3dcSJack F Vogel if (error != 0) 818758cc3dcSJack F Vogel break; 819758cc3dcSJack F Vogel if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { 820758cc3dcSJack F Vogel error = EINVAL; 821758cc3dcSJack F Vogel break; 822758cc3dcSJack F Vogel } 823758cc3dcSJack F Vogel if (i2c.len > sizeof(i2c.data)) { 824758cc3dcSJack F Vogel error = EINVAL; 825758cc3dcSJack F Vogel break; 826758cc3dcSJack F Vogel } 827758cc3dcSJack F Vogel 828758cc3dcSJack F Vogel for (i = 0; i < i2c.len; i++) 829758cc3dcSJack F Vogel hw->phy.ops.read_i2c_byte(hw, i2c.offset + i, 830758cc3dcSJack F Vogel i2c.dev_addr, &i2c.data[i]); 831758cc3dcSJack F Vogel error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); 832758cc3dcSJack F Vogel break; 833758cc3dcSJack F Vogel } 834758cc3dcSJack F Vogel #endif 835758cc3dcSJack F Vogel default: 836758cc3dcSJack F Vogel IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); 837758cc3dcSJack F Vogel error = ether_ioctl(ifp, command, data); 838758cc3dcSJack F Vogel break; 839758cc3dcSJack F Vogel } 840758cc3dcSJack F Vogel 841758cc3dcSJack F Vogel return (error); 842758cc3dcSJack F Vogel } 843758cc3dcSJack F Vogel 844758cc3dcSJack F Vogel /********************************************************************* 845758cc3dcSJack F Vogel * Init entry point 846758cc3dcSJack F Vogel * 847758cc3dcSJack F Vogel * This routine is used in two ways. It is used by the stack as 848758cc3dcSJack F Vogel * init entry point in network interface structure. It is also used 849758cc3dcSJack F Vogel * by the driver as a hw/sw initialization routine to get to a 850758cc3dcSJack F Vogel * consistent state. 851758cc3dcSJack F Vogel * 852758cc3dcSJack F Vogel * return 0 on success, positive on failure 853758cc3dcSJack F Vogel **********************************************************************/ 854758cc3dcSJack F Vogel #define IXGBE_MHADD_MFS_SHIFT 16 855758cc3dcSJack F Vogel 856758cc3dcSJack F Vogel static void 857758cc3dcSJack F Vogel ixgbe_init_locked(struct adapter *adapter) 858758cc3dcSJack F Vogel { 859758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 860758cc3dcSJack F Vogel device_t dev = adapter->dev; 861758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 862758cc3dcSJack F Vogel u32 k, txdctl, mhadd, gpie; 863758cc3dcSJack F Vogel u32 rxdctl, rxctrl; 864758cc3dcSJack F Vogel 865758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 866758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_init_locked: begin"); 867758cc3dcSJack F Vogel hw->adapter_stopped = FALSE; 868758cc3dcSJack F Vogel ixgbe_stop_adapter(hw); 869758cc3dcSJack F Vogel callout_stop(&adapter->timer); 870758cc3dcSJack F Vogel 871758cc3dcSJack F Vogel /* reprogram the RAR[0] in case user changed it. */ 872758cc3dcSJack F Vogel ixgbe_set_rar(hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); 873758cc3dcSJack F Vogel 874758cc3dcSJack F Vogel /* Get the latest mac address, User can use a LAA */ 875758cc3dcSJack F Vogel bcopy(IF_LLADDR(adapter->ifp), hw->mac.addr, 876758cc3dcSJack F Vogel IXGBE_ETH_LENGTH_OF_ADDRESS); 877758cc3dcSJack F Vogel ixgbe_set_rar(hw, 0, hw->mac.addr, 0, 1); 878758cc3dcSJack F Vogel hw->addr_ctrl.rar_used_count = 1; 879758cc3dcSJack F Vogel 880758cc3dcSJack F Vogel /* Set the various hardware offload abilities */ 881758cc3dcSJack F Vogel ifp->if_hwassist = 0; 882758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_TSO) 883758cc3dcSJack F Vogel ifp->if_hwassist |= CSUM_TSO; 884758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM) { 885758cc3dcSJack F Vogel ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 886758cc3dcSJack F Vogel #if __FreeBSD_version >= 800000 887758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) 888758cc3dcSJack F Vogel ifp->if_hwassist |= CSUM_SCTP; 889758cc3dcSJack F Vogel #endif 890758cc3dcSJack F Vogel } 891758cc3dcSJack F Vogel 892758cc3dcSJack F Vogel /* Prepare transmit descriptors and buffers */ 893758cc3dcSJack F Vogel if (ixgbe_setup_transmit_structures(adapter)) { 894758cc3dcSJack F Vogel device_printf(dev,"Could not setup transmit structures\n"); 895758cc3dcSJack F Vogel ixgbe_stop(adapter); 896758cc3dcSJack F Vogel return; 897758cc3dcSJack F Vogel } 898758cc3dcSJack F Vogel 899758cc3dcSJack F Vogel ixgbe_init_hw(hw); 900758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(adapter); 901758cc3dcSJack F Vogel 902758cc3dcSJack F Vogel /* Setup Multicast table */ 903758cc3dcSJack F Vogel ixgbe_set_multi(adapter); 904758cc3dcSJack F Vogel 905758cc3dcSJack F Vogel /* 906758cc3dcSJack F Vogel ** Determine the correct mbuf pool 907758cc3dcSJack F Vogel ** for doing jumbo frames 908758cc3dcSJack F Vogel */ 909758cc3dcSJack F Vogel if (adapter->max_frame_size <= 2048) 910758cc3dcSJack F Vogel adapter->rx_mbuf_sz = MCLBYTES; 911758cc3dcSJack F Vogel else if (adapter->max_frame_size <= 4096) 912758cc3dcSJack F Vogel adapter->rx_mbuf_sz = MJUMPAGESIZE; 913758cc3dcSJack F Vogel else if (adapter->max_frame_size <= 9216) 914758cc3dcSJack F Vogel adapter->rx_mbuf_sz = MJUM9BYTES; 915758cc3dcSJack F Vogel else 916758cc3dcSJack F Vogel adapter->rx_mbuf_sz = MJUM16BYTES; 917758cc3dcSJack F Vogel 918758cc3dcSJack F Vogel /* Prepare receive descriptors and buffers */ 919758cc3dcSJack F Vogel if (ixgbe_setup_receive_structures(adapter)) { 920758cc3dcSJack F Vogel device_printf(dev,"Could not setup receive structures\n"); 921758cc3dcSJack F Vogel ixgbe_stop(adapter); 922758cc3dcSJack F Vogel return; 923758cc3dcSJack F Vogel } 924758cc3dcSJack F Vogel 925758cc3dcSJack F Vogel /* Configure RX settings */ 926758cc3dcSJack F Vogel ixgbe_initialize_receive_units(adapter); 927758cc3dcSJack F Vogel 928758cc3dcSJack F Vogel gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE); 929758cc3dcSJack F Vogel 930758cc3dcSJack F Vogel /* Enable Fan Failure Interrupt */ 931758cc3dcSJack F Vogel gpie |= IXGBE_SDP1_GPIEN_BY_MAC(hw); 932758cc3dcSJack F Vogel 933758cc3dcSJack F Vogel /* Add for Module detection */ 934758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82599EB) 935758cc3dcSJack F Vogel gpie |= IXGBE_SDP2_GPIEN_BY_MAC(hw); 936758cc3dcSJack F Vogel 937758cc3dcSJack F Vogel /* Thermal Failure Detection */ 938758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_X540) 939758cc3dcSJack F Vogel gpie |= IXGBE_SDP0_GPIEN_BY_MAC(hw); 940758cc3dcSJack F Vogel 941758cc3dcSJack F Vogel if (adapter->msix > 1) { 942758cc3dcSJack F Vogel /* Enable Enhanced MSIX mode */ 943758cc3dcSJack F Vogel gpie |= IXGBE_GPIE_MSIX_MODE; 944758cc3dcSJack F Vogel gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | 945758cc3dcSJack F Vogel IXGBE_GPIE_OCD; 946758cc3dcSJack F Vogel } 947758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 948758cc3dcSJack F Vogel 949758cc3dcSJack F Vogel /* Set MTU size */ 950758cc3dcSJack F Vogel if (ifp->if_mtu > ETHERMTU) { 951758cc3dcSJack F Vogel mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); 952758cc3dcSJack F Vogel mhadd &= ~IXGBE_MHADD_MFS_MASK; 953758cc3dcSJack F Vogel mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; 954758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); 955758cc3dcSJack F Vogel } 956758cc3dcSJack F Vogel 957758cc3dcSJack F Vogel /* Now enable all the queues */ 958758cc3dcSJack F Vogel 959758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 960758cc3dcSJack F Vogel txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); 961758cc3dcSJack F Vogel txdctl |= IXGBE_TXDCTL_ENABLE; 962758cc3dcSJack F Vogel /* Set WTHRESH to 8, burst writeback */ 963758cc3dcSJack F Vogel txdctl |= (8 << 16); 964758cc3dcSJack F Vogel /* 965758cc3dcSJack F Vogel * When the internal queue falls below PTHRESH (32), 966758cc3dcSJack F Vogel * start prefetching as long as there are at least 967758cc3dcSJack F Vogel * HTHRESH (1) buffers ready. The values are taken 968758cc3dcSJack F Vogel * from the Intel linux driver 3.8.21. 969758cc3dcSJack F Vogel * Prefetching enables tx line rate even with 1 queue. 970758cc3dcSJack F Vogel */ 971758cc3dcSJack F Vogel txdctl |= (32 << 0) | (1 << 8); 972758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), txdctl); 973758cc3dcSJack F Vogel } 974758cc3dcSJack F Vogel 975758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 976758cc3dcSJack F Vogel rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); 977758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 978758cc3dcSJack F Vogel /* 979758cc3dcSJack F Vogel ** PTHRESH = 21 980758cc3dcSJack F Vogel ** HTHRESH = 4 981758cc3dcSJack F Vogel ** WTHRESH = 8 982758cc3dcSJack F Vogel */ 983758cc3dcSJack F Vogel rxdctl &= ~0x3FFFFF; 984758cc3dcSJack F Vogel rxdctl |= 0x080420; 985758cc3dcSJack F Vogel } 986758cc3dcSJack F Vogel rxdctl |= IXGBE_RXDCTL_ENABLE; 987758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), rxdctl); 988758cc3dcSJack F Vogel for (k = 0; k < 10; k++) { 989758cc3dcSJack F Vogel if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)) & 990758cc3dcSJack F Vogel IXGBE_RXDCTL_ENABLE) 991758cc3dcSJack F Vogel break; 992758cc3dcSJack F Vogel else 993758cc3dcSJack F Vogel msec_delay(1); 994758cc3dcSJack F Vogel } 995758cc3dcSJack F Vogel wmb(); 996758cc3dcSJack F Vogel #ifdef DEV_NETMAP 997758cc3dcSJack F Vogel /* 998758cc3dcSJack F Vogel * In netmap mode, we must preserve the buffers made 999758cc3dcSJack F Vogel * available to userspace before the if_init() 1000758cc3dcSJack F Vogel * (this is true by default on the TX side, because 1001758cc3dcSJack F Vogel * init makes all buffers available to userspace). 1002758cc3dcSJack F Vogel * 1003758cc3dcSJack F Vogel * netmap_reset() and the device specific routines 1004758cc3dcSJack F Vogel * (e.g. ixgbe_setup_receive_rings()) map these 1005758cc3dcSJack F Vogel * buffers at the end of the NIC ring, so here we 1006758cc3dcSJack F Vogel * must set the RDT (tail) register to make sure 1007758cc3dcSJack F Vogel * they are not overwritten. 1008758cc3dcSJack F Vogel * 1009758cc3dcSJack F Vogel * In this driver the NIC ring starts at RDH = 0, 1010758cc3dcSJack F Vogel * RDT points to the last slot available for reception (?), 1011758cc3dcSJack F Vogel * so RDT = num_rx_desc - 1 means the whole ring is available. 1012758cc3dcSJack F Vogel */ 1013758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_NETMAP) { 1014758cc3dcSJack F Vogel struct netmap_adapter *na = NA(adapter->ifp); 1015758cc3dcSJack F Vogel struct netmap_kring *kring = &na->rx_rings[i]; 1016758cc3dcSJack F Vogel int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); 1017758cc3dcSJack F Vogel 1018758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(i), t); 1019758cc3dcSJack F Vogel } else 1020758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 1021758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(i), adapter->num_rx_desc - 1); 1022758cc3dcSJack F Vogel } 1023758cc3dcSJack F Vogel 1024758cc3dcSJack F Vogel /* Enable Receive engine */ 1025758cc3dcSJack F Vogel rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); 1026758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 1027758cc3dcSJack F Vogel rxctrl |= IXGBE_RXCTRL_DMBYPS; 1028758cc3dcSJack F Vogel rxctrl |= IXGBE_RXCTRL_RXEN; 1029758cc3dcSJack F Vogel ixgbe_enable_rx_dma(hw, rxctrl); 1030758cc3dcSJack F Vogel 1031758cc3dcSJack F Vogel callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); 1032758cc3dcSJack F Vogel 1033758cc3dcSJack F Vogel /* Set up MSI/X routing */ 1034758cc3dcSJack F Vogel if (ixgbe_enable_msix) { 1035758cc3dcSJack F Vogel ixgbe_configure_ivars(adapter); 1036758cc3dcSJack F Vogel /* Set up auto-mask */ 1037758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 1038758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); 1039758cc3dcSJack F Vogel else { 1040758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); 1041758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); 1042758cc3dcSJack F Vogel } 1043758cc3dcSJack F Vogel } else { /* Simple settings for Legacy/MSI */ 1044758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 0, 0, 0); 1045758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 0, 0, 1); 1046758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); 1047758cc3dcSJack F Vogel } 1048758cc3dcSJack F Vogel 1049758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 1050758cc3dcSJack F Vogel /* Init Flow director */ 1051758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 1052758cc3dcSJack F Vogel u32 hdrm = 32 << fdir_pballoc; 1053758cc3dcSJack F Vogel 1054758cc3dcSJack F Vogel hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL); 1055758cc3dcSJack F Vogel ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); 1056758cc3dcSJack F Vogel } 1057758cc3dcSJack F Vogel #endif 1058758cc3dcSJack F Vogel 1059758cc3dcSJack F Vogel /* 1060758cc3dcSJack F Vogel ** Check on any SFP devices that 1061758cc3dcSJack F Vogel ** need to be kick-started 1062758cc3dcSJack F Vogel */ 1063758cc3dcSJack F Vogel if (hw->phy.type == ixgbe_phy_none) { 1064758cc3dcSJack F Vogel int err = hw->phy.ops.identify(hw); 1065758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 1066758cc3dcSJack F Vogel device_printf(dev, 1067758cc3dcSJack F Vogel "Unsupported SFP+ module type was detected.\n"); 1068758cc3dcSJack F Vogel return; 1069758cc3dcSJack F Vogel } 1070758cc3dcSJack F Vogel } 1071758cc3dcSJack F Vogel 1072758cc3dcSJack F Vogel /* Set moderation on the Link interrupt */ 1073758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR); 1074758cc3dcSJack F Vogel 1075758cc3dcSJack F Vogel /* Config/Enable Link */ 1076758cc3dcSJack F Vogel ixgbe_config_link(adapter); 1077758cc3dcSJack F Vogel 1078758cc3dcSJack F Vogel /* Hardware Packet Buffer & Flow Control setup */ 1079758cc3dcSJack F Vogel { 1080758cc3dcSJack F Vogel u32 rxpb, frame, size, tmp; 1081758cc3dcSJack F Vogel 1082758cc3dcSJack F Vogel frame = adapter->max_frame_size; 1083758cc3dcSJack F Vogel 1084758cc3dcSJack F Vogel /* Calculate High Water */ 1085758cc3dcSJack F Vogel switch (hw->mac.type) { 1086758cc3dcSJack F Vogel case ixgbe_mac_X540: 1087758cc3dcSJack F Vogel case ixgbe_mac_X550: 1088758cc3dcSJack F Vogel case ixgbe_mac_X550EM_a: 1089758cc3dcSJack F Vogel case ixgbe_mac_X550EM_x: 1090758cc3dcSJack F Vogel tmp = IXGBE_DV_X540(frame, frame); 1091758cc3dcSJack F Vogel break; 1092758cc3dcSJack F Vogel default: 1093758cc3dcSJack F Vogel tmp = IXGBE_DV(frame, frame); 1094758cc3dcSJack F Vogel break; 1095758cc3dcSJack F Vogel } 1096758cc3dcSJack F Vogel size = IXGBE_BT2KB(tmp); 1097758cc3dcSJack F Vogel rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10; 1098758cc3dcSJack F Vogel hw->fc.high_water[0] = rxpb - size; 1099758cc3dcSJack F Vogel 1100758cc3dcSJack F Vogel /* Now calculate Low Water */ 1101758cc3dcSJack F Vogel switch (hw->mac.type) { 1102758cc3dcSJack F Vogel case ixgbe_mac_X540: 1103758cc3dcSJack F Vogel case ixgbe_mac_X550: 1104758cc3dcSJack F Vogel case ixgbe_mac_X550EM_a: 1105758cc3dcSJack F Vogel case ixgbe_mac_X550EM_x: 1106758cc3dcSJack F Vogel tmp = IXGBE_LOW_DV_X540(frame); 1107758cc3dcSJack F Vogel break; 1108758cc3dcSJack F Vogel default: 1109758cc3dcSJack F Vogel tmp = IXGBE_LOW_DV(frame); 1110758cc3dcSJack F Vogel break; 1111758cc3dcSJack F Vogel } 1112758cc3dcSJack F Vogel hw->fc.low_water[0] = IXGBE_BT2KB(tmp); 1113758cc3dcSJack F Vogel 1114758cc3dcSJack F Vogel hw->fc.requested_mode = adapter->fc; 1115758cc3dcSJack F Vogel hw->fc.pause_time = IXGBE_FC_PAUSE; 1116758cc3dcSJack F Vogel hw->fc.send_xon = TRUE; 1117758cc3dcSJack F Vogel } 1118758cc3dcSJack F Vogel /* Initialize the FC settings */ 1119758cc3dcSJack F Vogel ixgbe_start_hw(hw); 1120758cc3dcSJack F Vogel 1121758cc3dcSJack F Vogel /* Set up VLAN support and filter */ 1122758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 1123758cc3dcSJack F Vogel 1124758cc3dcSJack F Vogel /* And now turn on interrupts */ 1125758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1126758cc3dcSJack F Vogel 1127758cc3dcSJack F Vogel /* Now inform the stack we're ready */ 1128758cc3dcSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 1129758cc3dcSJack F Vogel 1130758cc3dcSJack F Vogel return; 1131758cc3dcSJack F Vogel } 1132758cc3dcSJack F Vogel 1133758cc3dcSJack F Vogel static void 1134758cc3dcSJack F Vogel ixgbe_init(void *arg) 1135758cc3dcSJack F Vogel { 1136758cc3dcSJack F Vogel struct adapter *adapter = arg; 1137758cc3dcSJack F Vogel 1138758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 1139758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 1140758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1141758cc3dcSJack F Vogel return; 1142758cc3dcSJack F Vogel } 1143758cc3dcSJack F Vogel 1144758cc3dcSJack F Vogel 1145758cc3dcSJack F Vogel /* 1146758cc3dcSJack F Vogel ** 1147758cc3dcSJack F Vogel ** MSIX Interrupt Handlers and Tasklets 1148758cc3dcSJack F Vogel ** 1149758cc3dcSJack F Vogel */ 1150758cc3dcSJack F Vogel 1151758cc3dcSJack F Vogel static inline void 1152758cc3dcSJack F Vogel ixgbe_enable_queue(struct adapter *adapter, u32 vector) 1153758cc3dcSJack F Vogel { 1154758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1155758cc3dcSJack F Vogel u64 queue = (u64)(1 << vector); 1156758cc3dcSJack F Vogel u32 mask; 1157758cc3dcSJack F Vogel 1158758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1159758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queue); 1160758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); 1161758cc3dcSJack F Vogel } else { 1162758cc3dcSJack F Vogel mask = (queue & 0xFFFFFFFF); 1163758cc3dcSJack F Vogel if (mask) 1164758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask); 1165758cc3dcSJack F Vogel mask = (queue >> 32); 1166758cc3dcSJack F Vogel if (mask) 1167758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask); 1168758cc3dcSJack F Vogel } 1169758cc3dcSJack F Vogel } 1170758cc3dcSJack F Vogel 1171758cc3dcSJack F Vogel static inline void 1172758cc3dcSJack F Vogel ixgbe_disable_queue(struct adapter *adapter, u32 vector) 1173758cc3dcSJack F Vogel { 1174758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1175758cc3dcSJack F Vogel u64 queue = (u64)(1 << vector); 1176758cc3dcSJack F Vogel u32 mask; 1177758cc3dcSJack F Vogel 1178758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1179758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queue); 1180758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask); 1181758cc3dcSJack F Vogel } else { 1182758cc3dcSJack F Vogel mask = (queue & 0xFFFFFFFF); 1183758cc3dcSJack F Vogel if (mask) 1184758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask); 1185758cc3dcSJack F Vogel mask = (queue >> 32); 1186758cc3dcSJack F Vogel if (mask) 1187758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask); 1188758cc3dcSJack F Vogel } 1189758cc3dcSJack F Vogel } 1190758cc3dcSJack F Vogel 1191758cc3dcSJack F Vogel static void 1192758cc3dcSJack F Vogel ixgbe_handle_que(void *context, int pending) 1193758cc3dcSJack F Vogel { 1194758cc3dcSJack F Vogel struct ix_queue *que = context; 1195758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1196758cc3dcSJack F Vogel struct tx_ring *txr = que->txr; 1197758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1198758cc3dcSJack F Vogel 1199758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 120032e85f85SMarcelo Araujo ixgbe_rxeof(que); 1201758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1202758cc3dcSJack F Vogel ixgbe_txeof(txr); 1203758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 1204758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1205758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1206758cc3dcSJack F Vogel #else 1207758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1208758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1209758cc3dcSJack F Vogel #endif 1210758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1211758cc3dcSJack F Vogel } 1212758cc3dcSJack F Vogel 1213758cc3dcSJack F Vogel /* Reenable this interrupt */ 1214758cc3dcSJack F Vogel if (que->res != NULL) 1215758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 1216758cc3dcSJack F Vogel else 1217758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1218758cc3dcSJack F Vogel return; 1219758cc3dcSJack F Vogel } 1220758cc3dcSJack F Vogel 1221758cc3dcSJack F Vogel 1222758cc3dcSJack F Vogel /********************************************************************* 1223758cc3dcSJack F Vogel * 1224758cc3dcSJack F Vogel * Legacy Interrupt Service routine 1225758cc3dcSJack F Vogel * 1226758cc3dcSJack F Vogel **********************************************************************/ 1227758cc3dcSJack F Vogel 1228758cc3dcSJack F Vogel static void 1229758cc3dcSJack F Vogel ixgbe_legacy_irq(void *arg) 1230758cc3dcSJack F Vogel { 1231758cc3dcSJack F Vogel struct ix_queue *que = arg; 1232758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1233758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1234758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1235758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 1236758cc3dcSJack F Vogel bool more; 1237758cc3dcSJack F Vogel u32 reg_eicr; 1238758cc3dcSJack F Vogel 1239758cc3dcSJack F Vogel 1240758cc3dcSJack F Vogel reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 1241758cc3dcSJack F Vogel 1242758cc3dcSJack F Vogel ++que->irqs; 1243758cc3dcSJack F Vogel if (reg_eicr == 0) { 1244758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1245758cc3dcSJack F Vogel return; 1246758cc3dcSJack F Vogel } 1247758cc3dcSJack F Vogel 1248758cc3dcSJack F Vogel more = ixgbe_rxeof(que); 1249758cc3dcSJack F Vogel 1250758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1251758cc3dcSJack F Vogel ixgbe_txeof(txr); 1252758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX 1253758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1254758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1255758cc3dcSJack F Vogel #else 1256758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1257758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1258758cc3dcSJack F Vogel #endif 1259758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1260758cc3dcSJack F Vogel 1261758cc3dcSJack F Vogel /* Check for fan failure */ 1262758cc3dcSJack F Vogel if ((hw->phy.media_type == ixgbe_media_type_copper) && 1263758cc3dcSJack F Vogel (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) { 1264758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " 1265758cc3dcSJack F Vogel "REPLACE IMMEDIATELY!!\n"); 1266758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 1267758cc3dcSJack F Vogel } 1268758cc3dcSJack F Vogel 1269758cc3dcSJack F Vogel /* Link status change */ 1270758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_LSC) 1271758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->link_task); 1272758cc3dcSJack F Vogel 1273758cc3dcSJack F Vogel if (more) 1274758cc3dcSJack F Vogel taskqueue_enqueue(que->tq, &que->que_task); 1275758cc3dcSJack F Vogel else 1276758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1277758cc3dcSJack F Vogel return; 1278758cc3dcSJack F Vogel } 1279758cc3dcSJack F Vogel 1280758cc3dcSJack F Vogel 1281758cc3dcSJack F Vogel /********************************************************************* 1282758cc3dcSJack F Vogel * 1283758cc3dcSJack F Vogel * MSIX Queue Interrupt Service routine 1284758cc3dcSJack F Vogel * 1285758cc3dcSJack F Vogel **********************************************************************/ 1286758cc3dcSJack F Vogel void 1287758cc3dcSJack F Vogel ixgbe_msix_que(void *arg) 1288758cc3dcSJack F Vogel { 1289758cc3dcSJack F Vogel struct ix_queue *que = arg; 1290758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1291758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1292758cc3dcSJack F Vogel struct tx_ring *txr = que->txr; 1293758cc3dcSJack F Vogel struct rx_ring *rxr = que->rxr; 1294758cc3dcSJack F Vogel bool more; 1295758cc3dcSJack F Vogel u32 newitr = 0; 1296758cc3dcSJack F Vogel 1297758cc3dcSJack F Vogel /* Protect against spurious interrupts */ 1298758cc3dcSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1299758cc3dcSJack F Vogel return; 1300758cc3dcSJack F Vogel 1301758cc3dcSJack F Vogel ixgbe_disable_queue(adapter, que->msix); 1302758cc3dcSJack F Vogel ++que->irqs; 1303758cc3dcSJack F Vogel 1304758cc3dcSJack F Vogel more = ixgbe_rxeof(que); 1305758cc3dcSJack F Vogel 1306758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1307758cc3dcSJack F Vogel ixgbe_txeof(txr); 1308758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX 1309758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(ifp->if_snd)) 1310758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1311758cc3dcSJack F Vogel #else 1312758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1313758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1314758cc3dcSJack F Vogel #endif 1315758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1316758cc3dcSJack F Vogel 1317758cc3dcSJack F Vogel /* Do AIM now? */ 1318758cc3dcSJack F Vogel 1319758cc3dcSJack F Vogel if (ixgbe_enable_aim == FALSE) 1320758cc3dcSJack F Vogel goto no_calc; 1321758cc3dcSJack F Vogel /* 1322758cc3dcSJack F Vogel ** Do Adaptive Interrupt Moderation: 1323758cc3dcSJack F Vogel ** - Write out last calculated setting 1324758cc3dcSJack F Vogel ** - Calculate based on average size over 1325758cc3dcSJack F Vogel ** the last interval. 1326758cc3dcSJack F Vogel */ 1327758cc3dcSJack F Vogel if (que->eitr_setting) 1328758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, 1329758cc3dcSJack F Vogel IXGBE_EITR(que->msix), que->eitr_setting); 1330758cc3dcSJack F Vogel 1331758cc3dcSJack F Vogel que->eitr_setting = 0; 1332758cc3dcSJack F Vogel 1333758cc3dcSJack F Vogel /* Idle, do nothing */ 1334758cc3dcSJack F Vogel if ((txr->bytes == 0) && (rxr->bytes == 0)) 1335758cc3dcSJack F Vogel goto no_calc; 1336758cc3dcSJack F Vogel 1337758cc3dcSJack F Vogel if ((txr->bytes) && (txr->packets)) 1338758cc3dcSJack F Vogel newitr = txr->bytes/txr->packets; 1339758cc3dcSJack F Vogel if ((rxr->bytes) && (rxr->packets)) 1340758cc3dcSJack F Vogel newitr = max(newitr, 1341758cc3dcSJack F Vogel (rxr->bytes / rxr->packets)); 1342758cc3dcSJack F Vogel newitr += 24; /* account for hardware frame, crc */ 1343758cc3dcSJack F Vogel 1344758cc3dcSJack F Vogel /* set an upper boundary */ 1345758cc3dcSJack F Vogel newitr = min(newitr, 3000); 1346758cc3dcSJack F Vogel 1347758cc3dcSJack F Vogel /* Be nice to the mid range */ 1348758cc3dcSJack F Vogel if ((newitr > 300) && (newitr < 1200)) 1349758cc3dcSJack F Vogel newitr = (newitr / 3); 1350758cc3dcSJack F Vogel else 1351758cc3dcSJack F Vogel newitr = (newitr / 2); 1352758cc3dcSJack F Vogel 1353758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) 1354758cc3dcSJack F Vogel newitr |= newitr << 16; 1355758cc3dcSJack F Vogel else 1356758cc3dcSJack F Vogel newitr |= IXGBE_EITR_CNT_WDIS; 1357758cc3dcSJack F Vogel 1358758cc3dcSJack F Vogel /* save for next interrupt */ 1359758cc3dcSJack F Vogel que->eitr_setting = newitr; 1360758cc3dcSJack F Vogel 1361758cc3dcSJack F Vogel /* Reset state */ 1362758cc3dcSJack F Vogel txr->bytes = 0; 1363758cc3dcSJack F Vogel txr->packets = 0; 1364758cc3dcSJack F Vogel rxr->bytes = 0; 1365758cc3dcSJack F Vogel rxr->packets = 0; 1366758cc3dcSJack F Vogel 1367758cc3dcSJack F Vogel no_calc: 1368758cc3dcSJack F Vogel if (more) 1369758cc3dcSJack F Vogel taskqueue_enqueue(que->tq, &que->que_task); 1370758cc3dcSJack F Vogel else 1371758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 1372758cc3dcSJack F Vogel return; 1373758cc3dcSJack F Vogel } 1374758cc3dcSJack F Vogel 1375758cc3dcSJack F Vogel 1376758cc3dcSJack F Vogel static void 1377758cc3dcSJack F Vogel ixgbe_msix_link(void *arg) 1378758cc3dcSJack F Vogel { 1379758cc3dcSJack F Vogel struct adapter *adapter = arg; 1380758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1381758cc3dcSJack F Vogel u32 reg_eicr; 1382758cc3dcSJack F Vogel 1383758cc3dcSJack F Vogel ++adapter->vector_irq; 1384758cc3dcSJack F Vogel 1385758cc3dcSJack F Vogel /* First get the cause */ 1386758cc3dcSJack F Vogel reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS); 1387758cc3dcSJack F Vogel /* Be sure the queue bits are not cleared */ 1388758cc3dcSJack F Vogel reg_eicr &= ~IXGBE_EICR_RTX_QUEUE; 1389758cc3dcSJack F Vogel /* Clear interrupt with write */ 1390758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr); 1391758cc3dcSJack F Vogel 1392758cc3dcSJack F Vogel /* Link status change */ 1393758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_LSC) 1394758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->link_task); 1395758cc3dcSJack F Vogel 1396758cc3dcSJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82598EB) { 1397758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 1398758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_FLOW_DIR) { 1399758cc3dcSJack F Vogel /* This is probably overkill :) */ 1400758cc3dcSJack F Vogel if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1)) 1401758cc3dcSJack F Vogel return; 1402758cc3dcSJack F Vogel /* Disable the interrupt */ 1403758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR); 1404758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->fdir_task); 1405758cc3dcSJack F Vogel } else 1406758cc3dcSJack F Vogel #endif 1407758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_ECC) { 1408758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: ECC ERROR!! " 1409758cc3dcSJack F Vogel "Please Reboot!!\n"); 1410758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); 1411758cc3dcSJack F Vogel } else 1412758cc3dcSJack F Vogel 1413758cc3dcSJack F Vogel if (ixgbe_is_sfp(hw)) { 1414758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_GPI_SDP1) { 1415758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 1416758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 1417758cc3dcSJack F Vogel } else if (reg_eicr & IXGBE_EICR_GPI_SDP2) { 1418758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2_BY_MAC(hw)); 1419758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mod_task); 1420758cc3dcSJack F Vogel } 1421758cc3dcSJack F Vogel } 1422758cc3dcSJack F Vogel } 1423758cc3dcSJack F Vogel 1424758cc3dcSJack F Vogel /* Check for fan failure */ 1425758cc3dcSJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82598AT) && 1426758cc3dcSJack F Vogel (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) { 1427758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " 1428758cc3dcSJack F Vogel "REPLACE IMMEDIATELY!!\n"); 1429758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 1430758cc3dcSJack F Vogel } 1431758cc3dcSJack F Vogel 1432758cc3dcSJack F Vogel /* Check for over temp condition */ 1433758cc3dcSJack F Vogel switch (hw->mac.type) { 1434758cc3dcSJack F Vogel case ixgbe_mac_X540: 1435758cc3dcSJack F Vogel case ixgbe_mac_X550: 1436758cc3dcSJack F Vogel case ixgbe_mac_X550EM_a: 1437758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_TS) { 1438758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: OVER TEMP!! " 1439758cc3dcSJack F Vogel "PHY IS SHUT DOWN!!\n"); 1440758cc3dcSJack F Vogel device_printf(adapter->dev, "System shutdown required\n"); 1441758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); 1442758cc3dcSJack F Vogel } 1443758cc3dcSJack F Vogel break; 1444758cc3dcSJack F Vogel default: 1445758cc3dcSJack F Vogel /* Other MACs have no thermal sensor interrupt */ 1446758cc3dcSJack F Vogel break; 1447758cc3dcSJack F Vogel } 1448758cc3dcSJack F Vogel 1449758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); 1450758cc3dcSJack F Vogel return; 1451758cc3dcSJack F Vogel } 1452758cc3dcSJack F Vogel 1453758cc3dcSJack F Vogel /********************************************************************* 1454758cc3dcSJack F Vogel * 1455758cc3dcSJack F Vogel * Media Ioctl callback 1456758cc3dcSJack F Vogel * 1457758cc3dcSJack F Vogel * This routine is called whenever the user queries the status of 1458758cc3dcSJack F Vogel * the interface using ifconfig. 1459758cc3dcSJack F Vogel * 1460758cc3dcSJack F Vogel **********************************************************************/ 1461758cc3dcSJack F Vogel static void 1462758cc3dcSJack F Vogel ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 1463758cc3dcSJack F Vogel { 1464758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 1465758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1466758cc3dcSJack F Vogel int layer; 1467758cc3dcSJack F Vogel 1468758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_media_status: begin"); 1469758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 1470758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 1471758cc3dcSJack F Vogel 1472758cc3dcSJack F Vogel ifmr->ifm_status = IFM_AVALID; 1473758cc3dcSJack F Vogel ifmr->ifm_active = IFM_ETHER; 1474758cc3dcSJack F Vogel 1475758cc3dcSJack F Vogel if (!adapter->link_active) { 1476758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1477758cc3dcSJack F Vogel return; 1478758cc3dcSJack F Vogel } 1479758cc3dcSJack F Vogel 1480758cc3dcSJack F Vogel ifmr->ifm_status |= IFM_ACTIVE; 1481758cc3dcSJack F Vogel layer = ixgbe_get_supported_physical_layer(hw); 1482758cc3dcSJack F Vogel 1483758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T || 1484758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_1000BASE_T || 1485758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) 1486758cc3dcSJack F Vogel switch (adapter->link_speed) { 1487758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1488758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 1489758cc3dcSJack F Vogel break; 1490758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1491758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_T | IFM_FDX; 1492758cc3dcSJack F Vogel break; 1493758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_100_FULL: 1494758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_100_TX | IFM_FDX; 1495758cc3dcSJack F Vogel break; 1496758cc3dcSJack F Vogel } 1497758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || 1498758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) 1499758cc3dcSJack F Vogel switch (adapter->link_speed) { 1500758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1501758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX | IFM_FDX; 1502758cc3dcSJack F Vogel break; 1503758cc3dcSJack F Vogel } 1504758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) 1505758cc3dcSJack F Vogel switch (adapter->link_speed) { 1506758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1507758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_LR | IFM_FDX; 1508758cc3dcSJack F Vogel break; 1509758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1510758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; 1511758cc3dcSJack F Vogel break; 1512758cc3dcSJack F Vogel } 1513758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM) 1514758cc3dcSJack F Vogel switch (adapter->link_speed) { 1515758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1516758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_LRM | IFM_FDX; 1517758cc3dcSJack F Vogel break; 1518758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1519758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; 1520758cc3dcSJack F Vogel break; 1521758cc3dcSJack F Vogel } 1522758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR || 1523758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) 1524758cc3dcSJack F Vogel switch (adapter->link_speed) { 1525758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1526758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; 1527758cc3dcSJack F Vogel break; 1528758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1529758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; 1530758cc3dcSJack F Vogel break; 1531758cc3dcSJack F Vogel } 1532758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) 1533758cc3dcSJack F Vogel switch (adapter->link_speed) { 1534758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1535758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; 1536758cc3dcSJack F Vogel break; 1537758cc3dcSJack F Vogel } 1538758cc3dcSJack F Vogel /* 1539758cc3dcSJack F Vogel ** XXX: These need to use the proper media types once 1540758cc3dcSJack F Vogel ** they're added. 1541758cc3dcSJack F Vogel */ 1542758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) 1543758cc3dcSJack F Vogel switch (adapter->link_speed) { 1544758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1545758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10_T | IFM_FDX; 1546758cc3dcSJack F Vogel break; 1547758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1548758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10_5 | IFM_FDX; 1549758cc3dcSJack F Vogel break; 1550758cc3dcSJack F Vogel } 1551758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 1552758cc3dcSJack F Vogel || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) 1553758cc3dcSJack F Vogel switch (adapter->link_speed) { 1554758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1555758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10_2 | IFM_FDX; 1556758cc3dcSJack F Vogel break; 1557758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1558758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10_5 | IFM_FDX; 1559758cc3dcSJack F Vogel break; 1560758cc3dcSJack F Vogel } 1561758cc3dcSJack F Vogel 1562758cc3dcSJack F Vogel /* If nothing is recognized... */ 1563758cc3dcSJack F Vogel if (IFM_SUBTYPE(ifmr->ifm_active) == 0) 1564758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_UNKNOWN; 1565758cc3dcSJack F Vogel 1566758cc3dcSJack F Vogel #if __FreeBSD_version >= 900025 1567758cc3dcSJack F Vogel /* Flow control setting */ 1568758cc3dcSJack F Vogel if (adapter->fc == ixgbe_fc_rx_pause || adapter->fc == ixgbe_fc_full) 1569758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_ETH_RXPAUSE; 1570758cc3dcSJack F Vogel if (adapter->fc == ixgbe_fc_tx_pause || adapter->fc == ixgbe_fc_full) 1571758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_ETH_TXPAUSE; 1572758cc3dcSJack F Vogel #endif 1573758cc3dcSJack F Vogel 1574758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1575758cc3dcSJack F Vogel 1576758cc3dcSJack F Vogel return; 1577758cc3dcSJack F Vogel } 1578758cc3dcSJack F Vogel 1579758cc3dcSJack F Vogel /********************************************************************* 1580758cc3dcSJack F Vogel * 1581758cc3dcSJack F Vogel * Media Ioctl callback 1582758cc3dcSJack F Vogel * 1583758cc3dcSJack F Vogel * This routine is called when the user changes speed/duplex using 1584758cc3dcSJack F Vogel * media/mediopt option with ifconfig. 1585758cc3dcSJack F Vogel * 1586758cc3dcSJack F Vogel **********************************************************************/ 1587758cc3dcSJack F Vogel static int 1588758cc3dcSJack F Vogel ixgbe_media_change(struct ifnet * ifp) 1589758cc3dcSJack F Vogel { 1590758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 1591758cc3dcSJack F Vogel struct ifmedia *ifm = &adapter->media; 1592758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1593758cc3dcSJack F Vogel ixgbe_link_speed speed = 0; 1594758cc3dcSJack F Vogel 1595758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_media_change: begin"); 1596758cc3dcSJack F Vogel 1597758cc3dcSJack F Vogel if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1598758cc3dcSJack F Vogel return (EINVAL); 1599758cc3dcSJack F Vogel 1600758cc3dcSJack F Vogel /* 1601758cc3dcSJack F Vogel ** We don't actually need to check against the supported 1602758cc3dcSJack F Vogel ** media types of the adapter; ifmedia will take care of 1603758cc3dcSJack F Vogel ** that for us. 1604758cc3dcSJack F Vogel ** NOTE: this relies on falling thru the switch 1605758cc3dcSJack F Vogel ** to get all the values set, it can be confusing. 1606758cc3dcSJack F Vogel */ 1607758cc3dcSJack F Vogel switch (IFM_SUBTYPE(ifm->ifm_media)) { 1608758cc3dcSJack F Vogel case IFM_AUTO: 1609758cc3dcSJack F Vogel case IFM_10G_T: 1610758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1611758cc3dcSJack F Vogel case IFM_10G_LRM: 1612758cc3dcSJack F Vogel case IFM_10G_SR: /* KR, too */ 1613758cc3dcSJack F Vogel case IFM_10G_LR: 1614758cc3dcSJack F Vogel case IFM_10G_CX4: /* KX4 for now */ 1615758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 1616758cc3dcSJack F Vogel case IFM_10G_TWINAX: 1617758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_10GB_FULL; 1618758cc3dcSJack F Vogel break; 1619758cc3dcSJack F Vogel case IFM_1000_T: 1620758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1621758cc3dcSJack F Vogel case IFM_1000_LX: 1622758cc3dcSJack F Vogel case IFM_1000_SX: 1623758cc3dcSJack F Vogel case IFM_1000_CX: /* KX until there's real support */ 1624758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 1625758cc3dcSJack F Vogel break; 1626758cc3dcSJack F Vogel case IFM_100_TX: 1627758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1628758cc3dcSJack F Vogel break; 1629758cc3dcSJack F Vogel default: 1630758cc3dcSJack F Vogel goto invalid; 1631758cc3dcSJack F Vogel } 1632758cc3dcSJack F Vogel 1633758cc3dcSJack F Vogel hw->mac.autotry_restart = TRUE; 1634758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, speed, TRUE); 1635758cc3dcSJack F Vogel adapter->advertise = 1636758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_10GB_FULL) << 2) | 1637758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_1GB_FULL) << 1) | 1638758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_100_FULL) << 0); 1639758cc3dcSJack F Vogel 1640758cc3dcSJack F Vogel return (0); 1641758cc3dcSJack F Vogel 1642758cc3dcSJack F Vogel invalid: 1643758cc3dcSJack F Vogel device_printf(adapter->dev, "Invalid media type\n"); 1644758cc3dcSJack F Vogel return (EINVAL); 1645758cc3dcSJack F Vogel } 1646758cc3dcSJack F Vogel 1647758cc3dcSJack F Vogel static void 1648758cc3dcSJack F Vogel ixgbe_set_promisc(struct adapter *adapter) 1649758cc3dcSJack F Vogel { 1650758cc3dcSJack F Vogel u_int32_t reg_rctl; 1651758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1652758cc3dcSJack F Vogel int mcnt = 0; 1653758cc3dcSJack F Vogel 1654758cc3dcSJack F Vogel reg_rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); 1655758cc3dcSJack F Vogel reg_rctl &= (~IXGBE_FCTRL_UPE); 1656758cc3dcSJack F Vogel if (ifp->if_flags & IFF_ALLMULTI) 1657758cc3dcSJack F Vogel mcnt = MAX_NUM_MULTICAST_ADDRESSES; 1658758cc3dcSJack F Vogel else { 1659758cc3dcSJack F Vogel struct ifmultiaddr *ifma; 1660758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1661758cc3dcSJack F Vogel IF_ADDR_LOCK(ifp); 1662758cc3dcSJack F Vogel #else 1663758cc3dcSJack F Vogel if_maddr_rlock(ifp); 1664758cc3dcSJack F Vogel #endif 1665758cc3dcSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1666758cc3dcSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 1667758cc3dcSJack F Vogel continue; 1668758cc3dcSJack F Vogel if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) 1669758cc3dcSJack F Vogel break; 1670758cc3dcSJack F Vogel mcnt++; 1671758cc3dcSJack F Vogel } 1672758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1673758cc3dcSJack F Vogel IF_ADDR_UNLOCK(ifp); 1674758cc3dcSJack F Vogel #else 1675758cc3dcSJack F Vogel if_maddr_runlock(ifp); 1676758cc3dcSJack F Vogel #endif 1677758cc3dcSJack F Vogel } 1678758cc3dcSJack F Vogel if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) 1679758cc3dcSJack F Vogel reg_rctl &= (~IXGBE_FCTRL_MPE); 1680758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 1681758cc3dcSJack F Vogel 1682758cc3dcSJack F Vogel if (ifp->if_flags & IFF_PROMISC) { 1683758cc3dcSJack F Vogel reg_rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1684758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 1685758cc3dcSJack F Vogel } else if (ifp->if_flags & IFF_ALLMULTI) { 1686758cc3dcSJack F Vogel reg_rctl |= IXGBE_FCTRL_MPE; 1687758cc3dcSJack F Vogel reg_rctl &= ~IXGBE_FCTRL_UPE; 1688758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 1689758cc3dcSJack F Vogel } 1690758cc3dcSJack F Vogel return; 1691758cc3dcSJack F Vogel } 1692758cc3dcSJack F Vogel 1693758cc3dcSJack F Vogel 1694758cc3dcSJack F Vogel /********************************************************************* 1695758cc3dcSJack F Vogel * Multicast Update 1696758cc3dcSJack F Vogel * 1697758cc3dcSJack F Vogel * This routine is called whenever multicast address list is updated. 1698758cc3dcSJack F Vogel * 1699758cc3dcSJack F Vogel **********************************************************************/ 1700758cc3dcSJack F Vogel #define IXGBE_RAR_ENTRIES 16 1701758cc3dcSJack F Vogel 1702758cc3dcSJack F Vogel static void 1703758cc3dcSJack F Vogel ixgbe_set_multi(struct adapter *adapter) 1704758cc3dcSJack F Vogel { 1705758cc3dcSJack F Vogel u32 fctrl; 1706758cc3dcSJack F Vogel u8 *mta; 1707758cc3dcSJack F Vogel u8 *update_ptr; 1708758cc3dcSJack F Vogel struct ifmultiaddr *ifma; 1709758cc3dcSJack F Vogel int mcnt = 0; 1710758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1711758cc3dcSJack F Vogel 1712758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); 1713758cc3dcSJack F Vogel 1714758cc3dcSJack F Vogel mta = adapter->mta; 1715758cc3dcSJack F Vogel bzero(mta, sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS * 1716758cc3dcSJack F Vogel MAX_NUM_MULTICAST_ADDRESSES); 1717758cc3dcSJack F Vogel 1718758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1719758cc3dcSJack F Vogel IF_ADDR_LOCK(ifp); 1720758cc3dcSJack F Vogel #else 1721758cc3dcSJack F Vogel if_maddr_rlock(ifp); 1722758cc3dcSJack F Vogel #endif 1723758cc3dcSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1724758cc3dcSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 1725758cc3dcSJack F Vogel continue; 1726758cc3dcSJack F Vogel if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) 1727758cc3dcSJack F Vogel break; 1728758cc3dcSJack F Vogel bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), 1729758cc3dcSJack F Vogel &mta[mcnt * IXGBE_ETH_LENGTH_OF_ADDRESS], 1730758cc3dcSJack F Vogel IXGBE_ETH_LENGTH_OF_ADDRESS); 1731758cc3dcSJack F Vogel mcnt++; 1732758cc3dcSJack F Vogel } 1733758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1734758cc3dcSJack F Vogel IF_ADDR_UNLOCK(ifp); 1735758cc3dcSJack F Vogel #else 1736758cc3dcSJack F Vogel if_maddr_runlock(ifp); 1737758cc3dcSJack F Vogel #endif 1738758cc3dcSJack F Vogel 1739758cc3dcSJack F Vogel fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); 1740758cc3dcSJack F Vogel fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1741758cc3dcSJack F Vogel if (ifp->if_flags & IFF_PROMISC) 1742758cc3dcSJack F Vogel fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1743758cc3dcSJack F Vogel else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES || 1744758cc3dcSJack F Vogel ifp->if_flags & IFF_ALLMULTI) { 1745758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_MPE; 1746758cc3dcSJack F Vogel fctrl &= ~IXGBE_FCTRL_UPE; 1747758cc3dcSJack F Vogel } else 1748758cc3dcSJack F Vogel fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1749758cc3dcSJack F Vogel 1750758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); 1751758cc3dcSJack F Vogel 1752758cc3dcSJack F Vogel if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) { 1753758cc3dcSJack F Vogel update_ptr = mta; 1754758cc3dcSJack F Vogel ixgbe_update_mc_addr_list(&adapter->hw, 1755758cc3dcSJack F Vogel update_ptr, mcnt, ixgbe_mc_array_itr, TRUE); 1756758cc3dcSJack F Vogel } 1757758cc3dcSJack F Vogel 1758758cc3dcSJack F Vogel return; 1759758cc3dcSJack F Vogel } 1760758cc3dcSJack F Vogel 1761758cc3dcSJack F Vogel /* 1762758cc3dcSJack F Vogel * This is an iterator function now needed by the multicast 1763758cc3dcSJack F Vogel * shared code. It simply feeds the shared code routine the 1764758cc3dcSJack F Vogel * addresses in the array of ixgbe_set_multi() one by one. 1765758cc3dcSJack F Vogel */ 1766758cc3dcSJack F Vogel static u8 * 1767758cc3dcSJack F Vogel ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) 1768758cc3dcSJack F Vogel { 1769758cc3dcSJack F Vogel u8 *addr = *update_ptr; 1770758cc3dcSJack F Vogel u8 *newptr; 1771758cc3dcSJack F Vogel *vmdq = 0; 1772758cc3dcSJack F Vogel 1773758cc3dcSJack F Vogel newptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; 1774758cc3dcSJack F Vogel *update_ptr = newptr; 1775758cc3dcSJack F Vogel return addr; 1776758cc3dcSJack F Vogel } 1777758cc3dcSJack F Vogel 1778758cc3dcSJack F Vogel 1779758cc3dcSJack F Vogel /********************************************************************* 1780758cc3dcSJack F Vogel * Timer routine 1781758cc3dcSJack F Vogel * 1782758cc3dcSJack F Vogel * This routine checks for link status,updates statistics, 1783758cc3dcSJack F Vogel * and runs the watchdog check. 1784758cc3dcSJack F Vogel * 1785758cc3dcSJack F Vogel **********************************************************************/ 1786758cc3dcSJack F Vogel 1787758cc3dcSJack F Vogel static void 1788758cc3dcSJack F Vogel ixgbe_local_timer(void *arg) 1789758cc3dcSJack F Vogel { 1790758cc3dcSJack F Vogel struct adapter *adapter = arg; 1791758cc3dcSJack F Vogel device_t dev = adapter->dev; 1792758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 1793758cc3dcSJack F Vogel u64 queues = 0; 1794758cc3dcSJack F Vogel int hung = 0; 1795758cc3dcSJack F Vogel 1796758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 1797758cc3dcSJack F Vogel 1798758cc3dcSJack F Vogel /* Check for pluggable optics */ 1799758cc3dcSJack F Vogel if (adapter->sfp_probe) 1800758cc3dcSJack F Vogel if (!ixgbe_sfp_probe(adapter)) 1801758cc3dcSJack F Vogel goto out; /* Nothing to do */ 1802758cc3dcSJack F Vogel 1803758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 1804758cc3dcSJack F Vogel ixgbe_update_stats_counters(adapter); 1805758cc3dcSJack F Vogel 1806758cc3dcSJack F Vogel /* 1807758cc3dcSJack F Vogel ** Check the TX queues status 1808758cc3dcSJack F Vogel ** - mark hung queues so we don't schedule on them 1809758cc3dcSJack F Vogel ** - watchdog only if all queues show hung 1810758cc3dcSJack F Vogel */ 1811758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 1812758cc3dcSJack F Vogel /* Keep track of queues with work for soft irq */ 1813758cc3dcSJack F Vogel if (que->txr->busy) 1814758cc3dcSJack F Vogel queues |= ((u64)1 << que->me); 1815758cc3dcSJack F Vogel /* 1816758cc3dcSJack F Vogel ** Each time txeof runs without cleaning, but there 1817758cc3dcSJack F Vogel ** are uncleaned descriptors it increments busy. If 1818758cc3dcSJack F Vogel ** we get to the MAX we declare it hung. 1819758cc3dcSJack F Vogel */ 1820758cc3dcSJack F Vogel if (que->busy == IXGBE_QUEUE_HUNG) { 1821758cc3dcSJack F Vogel ++hung; 1822758cc3dcSJack F Vogel /* Mark the queue as inactive */ 1823758cc3dcSJack F Vogel adapter->active_queues &= ~((u64)1 << que->me); 1824758cc3dcSJack F Vogel continue; 1825758cc3dcSJack F Vogel } else { 1826758cc3dcSJack F Vogel /* Check if we've come back from hung */ 1827758cc3dcSJack F Vogel if ((adapter->active_queues & ((u64)1 << que->me)) == 0) 1828758cc3dcSJack F Vogel adapter->active_queues |= ((u64)1 << que->me); 1829758cc3dcSJack F Vogel } 1830758cc3dcSJack F Vogel if (que->busy >= IXGBE_MAX_TX_BUSY) { 1831758cc3dcSJack F Vogel device_printf(dev,"Warning queue %d " 1832758cc3dcSJack F Vogel "appears to be hung!\n", i); 1833758cc3dcSJack F Vogel que->txr->busy = IXGBE_QUEUE_HUNG; 1834758cc3dcSJack F Vogel ++hung; 1835758cc3dcSJack F Vogel } 1836758cc3dcSJack F Vogel 1837758cc3dcSJack F Vogel } 1838758cc3dcSJack F Vogel 1839758cc3dcSJack F Vogel /* Only truly watchdog if all queues show hung */ 1840758cc3dcSJack F Vogel if (hung == adapter->num_queues) 1841758cc3dcSJack F Vogel goto watchdog; 1842758cc3dcSJack F Vogel else if (queues != 0) { /* Force an IRQ on queues with work */ 1843758cc3dcSJack F Vogel ixgbe_rearm_queues(adapter, queues); 1844758cc3dcSJack F Vogel } 1845758cc3dcSJack F Vogel 1846758cc3dcSJack F Vogel out: 1847758cc3dcSJack F Vogel callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); 1848758cc3dcSJack F Vogel return; 1849758cc3dcSJack F Vogel 1850758cc3dcSJack F Vogel watchdog: 1851758cc3dcSJack F Vogel device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); 1852758cc3dcSJack F Vogel adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1853758cc3dcSJack F Vogel adapter->watchdog_events++; 1854758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 1855758cc3dcSJack F Vogel } 1856758cc3dcSJack F Vogel 1857758cc3dcSJack F Vogel /* 1858758cc3dcSJack F Vogel ** Note: this routine updates the OS on the link state 1859758cc3dcSJack F Vogel ** the real check of the hardware only happens with 1860758cc3dcSJack F Vogel ** a link interrupt. 1861758cc3dcSJack F Vogel */ 1862758cc3dcSJack F Vogel static void 1863758cc3dcSJack F Vogel ixgbe_update_link_status(struct adapter *adapter) 1864758cc3dcSJack F Vogel { 1865758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1866758cc3dcSJack F Vogel device_t dev = adapter->dev; 1867758cc3dcSJack F Vogel 1868758cc3dcSJack F Vogel 1869758cc3dcSJack F Vogel if (adapter->link_up){ 1870758cc3dcSJack F Vogel if (adapter->link_active == FALSE) { 1871758cc3dcSJack F Vogel if (bootverbose) 1872758cc3dcSJack F Vogel device_printf(dev,"Link is up %d Gbps %s \n", 1873758cc3dcSJack F Vogel ((adapter->link_speed == 128)? 10:1), 1874758cc3dcSJack F Vogel "Full Duplex"); 1875758cc3dcSJack F Vogel adapter->link_active = TRUE; 1876758cc3dcSJack F Vogel /* Update any Flow Control changes */ 1877758cc3dcSJack F Vogel ixgbe_fc_enable(&adapter->hw); 1878758cc3dcSJack F Vogel if_link_state_change(ifp, LINK_STATE_UP); 1879758cc3dcSJack F Vogel } 1880758cc3dcSJack F Vogel } else { /* Link down */ 1881758cc3dcSJack F Vogel if (adapter->link_active == TRUE) { 1882758cc3dcSJack F Vogel if (bootverbose) 1883758cc3dcSJack F Vogel device_printf(dev,"Link is Down\n"); 1884758cc3dcSJack F Vogel if_link_state_change(ifp, LINK_STATE_DOWN); 1885758cc3dcSJack F Vogel adapter->link_active = FALSE; 1886758cc3dcSJack F Vogel } 1887758cc3dcSJack F Vogel } 1888758cc3dcSJack F Vogel 1889758cc3dcSJack F Vogel return; 1890758cc3dcSJack F Vogel } 1891758cc3dcSJack F Vogel 1892758cc3dcSJack F Vogel 1893758cc3dcSJack F Vogel /********************************************************************* 1894758cc3dcSJack F Vogel * 1895758cc3dcSJack F Vogel * This routine disables all traffic on the adapter by issuing a 1896758cc3dcSJack F Vogel * global reset on the MAC and deallocates TX/RX buffers. 1897758cc3dcSJack F Vogel * 1898758cc3dcSJack F Vogel **********************************************************************/ 1899758cc3dcSJack F Vogel 1900758cc3dcSJack F Vogel static void 1901758cc3dcSJack F Vogel ixgbe_stop(void *arg) 1902758cc3dcSJack F Vogel { 1903758cc3dcSJack F Vogel struct ifnet *ifp; 1904758cc3dcSJack F Vogel struct adapter *adapter = arg; 1905758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1906758cc3dcSJack F Vogel ifp = adapter->ifp; 1907758cc3dcSJack F Vogel 1908758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 1909758cc3dcSJack F Vogel 1910758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_stop: begin\n"); 1911758cc3dcSJack F Vogel ixgbe_disable_intr(adapter); 1912758cc3dcSJack F Vogel callout_stop(&adapter->timer); 1913758cc3dcSJack F Vogel 1914758cc3dcSJack F Vogel /* Let the stack know...*/ 1915758cc3dcSJack F Vogel ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1916758cc3dcSJack F Vogel 1917758cc3dcSJack F Vogel ixgbe_reset_hw(hw); 1918758cc3dcSJack F Vogel hw->adapter_stopped = FALSE; 1919758cc3dcSJack F Vogel ixgbe_stop_adapter(hw); 1920758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82599EB) 1921758cc3dcSJack F Vogel ixgbe_stop_mac_link_on_d3_82599(hw); 1922758cc3dcSJack F Vogel /* Turn off the laser - noop with no optics */ 1923758cc3dcSJack F Vogel ixgbe_disable_tx_laser(hw); 1924758cc3dcSJack F Vogel 1925758cc3dcSJack F Vogel /* Update the stack */ 1926758cc3dcSJack F Vogel adapter->link_up = FALSE; 1927758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 1928758cc3dcSJack F Vogel 1929758cc3dcSJack F Vogel /* reprogram the RAR[0] in case user changed it. */ 1930758cc3dcSJack F Vogel ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); 1931758cc3dcSJack F Vogel 1932758cc3dcSJack F Vogel return; 1933758cc3dcSJack F Vogel } 1934758cc3dcSJack F Vogel 1935758cc3dcSJack F Vogel 1936758cc3dcSJack F Vogel /********************************************************************* 1937758cc3dcSJack F Vogel * 1938758cc3dcSJack F Vogel * Determine hardware revision. 1939758cc3dcSJack F Vogel * 1940758cc3dcSJack F Vogel **********************************************************************/ 1941758cc3dcSJack F Vogel static void 1942758cc3dcSJack F Vogel ixgbe_identify_hardware(struct adapter *adapter) 1943758cc3dcSJack F Vogel { 1944758cc3dcSJack F Vogel device_t dev = adapter->dev; 1945758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1946758cc3dcSJack F Vogel 1947758cc3dcSJack F Vogel /* Save off the information about this board */ 1948758cc3dcSJack F Vogel hw->vendor_id = pci_get_vendor(dev); 1949758cc3dcSJack F Vogel hw->device_id = pci_get_device(dev); 1950758cc3dcSJack F Vogel hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 1951758cc3dcSJack F Vogel hw->subsystem_vendor_id = 1952758cc3dcSJack F Vogel pci_read_config(dev, PCIR_SUBVEND_0, 2); 1953758cc3dcSJack F Vogel hw->subsystem_device_id = 1954758cc3dcSJack F Vogel pci_read_config(dev, PCIR_SUBDEV_0, 2); 1955758cc3dcSJack F Vogel 1956758cc3dcSJack F Vogel /* 1957758cc3dcSJack F Vogel ** Make sure BUSMASTER is set 1958758cc3dcSJack F Vogel */ 1959758cc3dcSJack F Vogel pci_enable_busmaster(dev); 1960758cc3dcSJack F Vogel 1961758cc3dcSJack F Vogel /* We need this here to set the num_segs below */ 1962758cc3dcSJack F Vogel ixgbe_set_mac_type(hw); 1963758cc3dcSJack F Vogel 1964758cc3dcSJack F Vogel /* Pick up the 82599 and VF settings */ 1965758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 1966758cc3dcSJack F Vogel hw->phy.smart_speed = ixgbe_smart_speed; 1967758cc3dcSJack F Vogel adapter->num_segs = IXGBE_82599_SCATTER; 1968758cc3dcSJack F Vogel } else 1969758cc3dcSJack F Vogel adapter->num_segs = IXGBE_82598_SCATTER; 1970758cc3dcSJack F Vogel 1971758cc3dcSJack F Vogel return; 1972758cc3dcSJack F Vogel } 1973758cc3dcSJack F Vogel 1974758cc3dcSJack F Vogel /********************************************************************* 1975758cc3dcSJack F Vogel * 1976758cc3dcSJack F Vogel * Determine optic type 1977758cc3dcSJack F Vogel * 1978758cc3dcSJack F Vogel **********************************************************************/ 1979758cc3dcSJack F Vogel static void 1980758cc3dcSJack F Vogel ixgbe_setup_optics(struct adapter *adapter) 1981758cc3dcSJack F Vogel { 1982758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1983758cc3dcSJack F Vogel int layer; 1984758cc3dcSJack F Vogel 1985758cc3dcSJack F Vogel layer = ixgbe_get_supported_physical_layer(hw); 1986758cc3dcSJack F Vogel 1987758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) { 1988758cc3dcSJack F Vogel adapter->optics = IFM_10G_T; 1989758cc3dcSJack F Vogel return; 1990758cc3dcSJack F Vogel } 1991758cc3dcSJack F Vogel 1992758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) { 1993758cc3dcSJack F Vogel adapter->optics = IFM_1000_T; 1994758cc3dcSJack F Vogel return; 1995758cc3dcSJack F Vogel } 1996758cc3dcSJack F Vogel 1997758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) { 1998758cc3dcSJack F Vogel adapter->optics = IFM_1000_SX; 1999758cc3dcSJack F Vogel return; 2000758cc3dcSJack F Vogel } 2001758cc3dcSJack F Vogel 2002758cc3dcSJack F Vogel if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_LR | 2003758cc3dcSJack F Vogel IXGBE_PHYSICAL_LAYER_10GBASE_LRM)) { 2004758cc3dcSJack F Vogel adapter->optics = IFM_10G_LR; 2005758cc3dcSJack F Vogel return; 2006758cc3dcSJack F Vogel } 2007758cc3dcSJack F Vogel 2008758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { 2009758cc3dcSJack F Vogel adapter->optics = IFM_10G_SR; 2010758cc3dcSJack F Vogel return; 2011758cc3dcSJack F Vogel } 2012758cc3dcSJack F Vogel 2013758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU) { 2014758cc3dcSJack F Vogel adapter->optics = IFM_10G_TWINAX; 2015758cc3dcSJack F Vogel return; 2016758cc3dcSJack F Vogel } 2017758cc3dcSJack F Vogel 2018758cc3dcSJack F Vogel if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | 2019758cc3dcSJack F Vogel IXGBE_PHYSICAL_LAYER_10GBASE_CX4)) { 2020758cc3dcSJack F Vogel adapter->optics = IFM_10G_CX4; 2021758cc3dcSJack F Vogel return; 2022758cc3dcSJack F Vogel } 2023758cc3dcSJack F Vogel 2024758cc3dcSJack F Vogel /* If we get here just set the default */ 2025758cc3dcSJack F Vogel adapter->optics = IFM_ETHER | IFM_AUTO; 2026758cc3dcSJack F Vogel return; 2027758cc3dcSJack F Vogel } 2028758cc3dcSJack F Vogel 2029758cc3dcSJack F Vogel /********************************************************************* 2030758cc3dcSJack F Vogel * 2031758cc3dcSJack F Vogel * Setup the Legacy or MSI Interrupt handler 2032758cc3dcSJack F Vogel * 2033758cc3dcSJack F Vogel **********************************************************************/ 2034758cc3dcSJack F Vogel static int 2035758cc3dcSJack F Vogel ixgbe_allocate_legacy(struct adapter *adapter) 2036758cc3dcSJack F Vogel { 2037758cc3dcSJack F Vogel device_t dev = adapter->dev; 2038758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2039758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2040758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2041758cc3dcSJack F Vogel #endif 2042758cc3dcSJack F Vogel int error, rid = 0; 2043758cc3dcSJack F Vogel 2044758cc3dcSJack F Vogel /* MSI RID at 1 */ 2045758cc3dcSJack F Vogel if (adapter->msix == 1) 2046758cc3dcSJack F Vogel rid = 1; 2047758cc3dcSJack F Vogel 2048758cc3dcSJack F Vogel /* We allocate a single interrupt resource */ 2049758cc3dcSJack F Vogel adapter->res = bus_alloc_resource_any(dev, 2050758cc3dcSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 2051758cc3dcSJack F Vogel if (adapter->res == NULL) { 2052758cc3dcSJack F Vogel device_printf(dev, "Unable to allocate bus resource: " 2053758cc3dcSJack F Vogel "interrupt\n"); 2054758cc3dcSJack F Vogel return (ENXIO); 2055758cc3dcSJack F Vogel } 2056758cc3dcSJack F Vogel 2057758cc3dcSJack F Vogel /* 2058758cc3dcSJack F Vogel * Try allocating a fast interrupt and the associated deferred 2059758cc3dcSJack F Vogel * processing contexts. 2060758cc3dcSJack F Vogel */ 2061758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2062758cc3dcSJack F Vogel TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); 2063758cc3dcSJack F Vogel #endif 2064758cc3dcSJack F Vogel TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); 2065758cc3dcSJack F Vogel que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, 2066758cc3dcSJack F Vogel taskqueue_thread_enqueue, &que->tq); 2067758cc3dcSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s ixq", 2068758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2069758cc3dcSJack F Vogel 2070758cc3dcSJack F Vogel /* Tasklets for Link, SFP and Multispeed Fiber */ 2071758cc3dcSJack F Vogel TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); 2072758cc3dcSJack F Vogel TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); 2073758cc3dcSJack F Vogel TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); 2074758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 2075758cc3dcSJack F Vogel TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); 2076758cc3dcSJack F Vogel #endif 2077758cc3dcSJack F Vogel adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, 2078758cc3dcSJack F Vogel taskqueue_thread_enqueue, &adapter->tq); 2079758cc3dcSJack F Vogel taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", 2080758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2081758cc3dcSJack F Vogel 2082758cc3dcSJack F Vogel if ((error = bus_setup_intr(dev, adapter->res, 2083758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq, 2084758cc3dcSJack F Vogel que, &adapter->tag)) != 0) { 2085758cc3dcSJack F Vogel device_printf(dev, "Failed to register fast interrupt " 2086758cc3dcSJack F Vogel "handler: %d\n", error); 2087758cc3dcSJack F Vogel taskqueue_free(que->tq); 2088758cc3dcSJack F Vogel taskqueue_free(adapter->tq); 2089758cc3dcSJack F Vogel que->tq = NULL; 2090758cc3dcSJack F Vogel adapter->tq = NULL; 2091758cc3dcSJack F Vogel return (error); 2092758cc3dcSJack F Vogel } 2093758cc3dcSJack F Vogel /* For simplicity in the handlers */ 2094758cc3dcSJack F Vogel adapter->active_queues = IXGBE_EIMS_ENABLE_MASK; 2095758cc3dcSJack F Vogel 2096758cc3dcSJack F Vogel return (0); 2097758cc3dcSJack F Vogel } 2098758cc3dcSJack F Vogel 2099758cc3dcSJack F Vogel 2100758cc3dcSJack F Vogel /********************************************************************* 2101758cc3dcSJack F Vogel * 2102758cc3dcSJack F Vogel * Setup MSIX Interrupt resources and handlers 2103758cc3dcSJack F Vogel * 2104758cc3dcSJack F Vogel **********************************************************************/ 2105758cc3dcSJack F Vogel static int 2106758cc3dcSJack F Vogel ixgbe_allocate_msix(struct adapter *adapter) 2107758cc3dcSJack F Vogel { 2108758cc3dcSJack F Vogel device_t dev = adapter->dev; 2109758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2110758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2111758cc3dcSJack F Vogel int error, rid, vector = 0; 2112758cc3dcSJack F Vogel int cpu_id = 0; 2113a1edda90SAdrian Chadd #ifdef RSS 2114a1edda90SAdrian Chadd cpuset_t cpu_mask; 2115a1edda90SAdrian Chadd #endif 2116758cc3dcSJack F Vogel 2117758cc3dcSJack F Vogel #ifdef RSS 2118758cc3dcSJack F Vogel /* 2119758cc3dcSJack F Vogel * If we're doing RSS, the number of queues needs to 2120758cc3dcSJack F Vogel * match the number of RSS buckets that are configured. 2121758cc3dcSJack F Vogel * 2122758cc3dcSJack F Vogel * + If there's more queues than RSS buckets, we'll end 2123758cc3dcSJack F Vogel * up with queues that get no traffic. 2124758cc3dcSJack F Vogel * 2125758cc3dcSJack F Vogel * + If there's more RSS buckets than queues, we'll end 2126758cc3dcSJack F Vogel * up having multiple RSS buckets map to the same queue, 2127758cc3dcSJack F Vogel * so there'll be some contention. 2128758cc3dcSJack F Vogel */ 2129758cc3dcSJack F Vogel if (adapter->num_queues != rss_getnumbuckets()) { 2130758cc3dcSJack F Vogel device_printf(dev, 2131758cc3dcSJack F Vogel "%s: number of queues (%d) != number of RSS buckets (%d)" 2132758cc3dcSJack F Vogel "; performance will be impacted.\n", 2133758cc3dcSJack F Vogel __func__, 2134758cc3dcSJack F Vogel adapter->num_queues, 2135758cc3dcSJack F Vogel rss_getnumbuckets()); 2136758cc3dcSJack F Vogel } 2137758cc3dcSJack F Vogel #endif 2138758cc3dcSJack F Vogel 2139758cc3dcSJack F Vogel 2140758cc3dcSJack F Vogel 2141758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { 2142758cc3dcSJack F Vogel rid = vector + 1; 2143758cc3dcSJack F Vogel que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 2144758cc3dcSJack F Vogel RF_SHAREABLE | RF_ACTIVE); 2145758cc3dcSJack F Vogel if (que->res == NULL) { 2146758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate" 2147758cc3dcSJack F Vogel " bus resource: que interrupt [%d]\n", vector); 2148758cc3dcSJack F Vogel return (ENXIO); 2149758cc3dcSJack F Vogel } 2150758cc3dcSJack F Vogel /* Set the handler function */ 2151758cc3dcSJack F Vogel error = bus_setup_intr(dev, que->res, 2152758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 2153758cc3dcSJack F Vogel ixgbe_msix_que, que, &que->tag); 2154758cc3dcSJack F Vogel if (error) { 2155758cc3dcSJack F Vogel que->res = NULL; 2156758cc3dcSJack F Vogel device_printf(dev, "Failed to register QUE handler"); 2157758cc3dcSJack F Vogel return (error); 2158758cc3dcSJack F Vogel } 2159758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504 2160758cc3dcSJack F Vogel bus_describe_intr(dev, que->res, que->tag, "que %d", i); 2161758cc3dcSJack F Vogel #endif 2162758cc3dcSJack F Vogel que->msix = vector; 2163758cc3dcSJack F Vogel adapter->active_queues |= (u64)(1 << que->msix); 2164758cc3dcSJack F Vogel #ifdef RSS 2165758cc3dcSJack F Vogel /* 2166758cc3dcSJack F Vogel * The queue ID is used as the RSS layer bucket ID. 2167758cc3dcSJack F Vogel * We look up the queue ID -> RSS CPU ID and select 2168758cc3dcSJack F Vogel * that. 2169758cc3dcSJack F Vogel */ 2170758cc3dcSJack F Vogel cpu_id = rss_getcpu(i % rss_getnumbuckets()); 2171758cc3dcSJack F Vogel #else 2172758cc3dcSJack F Vogel /* 2173758cc3dcSJack F Vogel * Bind the msix vector, and thus the 2174758cc3dcSJack F Vogel * rings to the corresponding cpu. 2175758cc3dcSJack F Vogel * 2176758cc3dcSJack F Vogel * This just happens to match the default RSS round-robin 2177758cc3dcSJack F Vogel * bucket -> queue -> CPU allocation. 2178758cc3dcSJack F Vogel */ 2179758cc3dcSJack F Vogel if (adapter->num_queues > 1) 2180758cc3dcSJack F Vogel cpu_id = i; 2181758cc3dcSJack F Vogel #endif 2182758cc3dcSJack F Vogel if (adapter->num_queues > 1) 2183758cc3dcSJack F Vogel bus_bind_intr(dev, que->res, cpu_id); 2184758cc3dcSJack F Vogel 2185758cc3dcSJack F Vogel #ifdef RSS 2186758cc3dcSJack F Vogel device_printf(dev, 2187758cc3dcSJack F Vogel "Bound RSS bucket %d to CPU %d\n", 2188758cc3dcSJack F Vogel i, cpu_id); 2189758cc3dcSJack F Vogel #else 2190758cc3dcSJack F Vogel #if 0 // This is too noisy 2191758cc3dcSJack F Vogel device_printf(dev, 2192758cc3dcSJack F Vogel "Bound queue %d to cpu %d\n", 2193758cc3dcSJack F Vogel i, cpu_id); 2194758cc3dcSJack F Vogel #endif 2195758cc3dcSJack F Vogel #endif 2196758cc3dcSJack F Vogel 2197758cc3dcSJack F Vogel 2198758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2199758cc3dcSJack F Vogel TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); 2200758cc3dcSJack F Vogel #endif 2201758cc3dcSJack F Vogel TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); 2202758cc3dcSJack F Vogel que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, 2203758cc3dcSJack F Vogel taskqueue_thread_enqueue, &que->tq); 2204758cc3dcSJack F Vogel #ifdef RSS 2205a1edda90SAdrian Chadd CPU_SETOF(cpu_id, &cpu_mask); 2206a1edda90SAdrian Chadd taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, 2207a1edda90SAdrian Chadd &cpu_mask, 2208758cc3dcSJack F Vogel "%s (bucket %d)", 2209758cc3dcSJack F Vogel device_get_nameunit(adapter->dev), 2210758cc3dcSJack F Vogel cpu_id); 2211758cc3dcSJack F Vogel #else 2212758cc3dcSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 2213758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2214758cc3dcSJack F Vogel #endif 2215758cc3dcSJack F Vogel } 2216758cc3dcSJack F Vogel 2217758cc3dcSJack F Vogel /* and Link */ 2218758cc3dcSJack F Vogel rid = vector + 1; 2219758cc3dcSJack F Vogel adapter->res = bus_alloc_resource_any(dev, 2220758cc3dcSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 2221758cc3dcSJack F Vogel if (!adapter->res) { 2222758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate" 2223758cc3dcSJack F Vogel " bus resource: Link interrupt [%d]\n", rid); 2224758cc3dcSJack F Vogel return (ENXIO); 2225758cc3dcSJack F Vogel } 2226758cc3dcSJack F Vogel /* Set the link handler function */ 2227758cc3dcSJack F Vogel error = bus_setup_intr(dev, adapter->res, 2228758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 2229758cc3dcSJack F Vogel ixgbe_msix_link, adapter, &adapter->tag); 2230758cc3dcSJack F Vogel if (error) { 2231758cc3dcSJack F Vogel adapter->res = NULL; 2232758cc3dcSJack F Vogel device_printf(dev, "Failed to register LINK handler"); 2233758cc3dcSJack F Vogel return (error); 2234758cc3dcSJack F Vogel } 2235758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504 2236758cc3dcSJack F Vogel bus_describe_intr(dev, adapter->res, adapter->tag, "link"); 2237758cc3dcSJack F Vogel #endif 2238758cc3dcSJack F Vogel adapter->vector = vector; 2239758cc3dcSJack F Vogel /* Tasklets for Link, SFP and Multispeed Fiber */ 2240758cc3dcSJack F Vogel TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); 2241758cc3dcSJack F Vogel TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); 2242758cc3dcSJack F Vogel TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); 2243758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 2244758cc3dcSJack F Vogel TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); 2245758cc3dcSJack F Vogel #endif 2246758cc3dcSJack F Vogel adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, 2247758cc3dcSJack F Vogel taskqueue_thread_enqueue, &adapter->tq); 2248758cc3dcSJack F Vogel taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", 2249758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2250758cc3dcSJack F Vogel 2251758cc3dcSJack F Vogel return (0); 2252758cc3dcSJack F Vogel } 2253758cc3dcSJack F Vogel 2254758cc3dcSJack F Vogel /* 2255758cc3dcSJack F Vogel * Setup Either MSI/X or MSI 2256758cc3dcSJack F Vogel */ 2257758cc3dcSJack F Vogel static int 2258758cc3dcSJack F Vogel ixgbe_setup_msix(struct adapter *adapter) 2259758cc3dcSJack F Vogel { 2260758cc3dcSJack F Vogel device_t dev = adapter->dev; 2261758cc3dcSJack F Vogel int rid, want, queues, msgs; 2262758cc3dcSJack F Vogel 2263758cc3dcSJack F Vogel /* Override by tuneable */ 2264758cc3dcSJack F Vogel if (ixgbe_enable_msix == 0) 2265758cc3dcSJack F Vogel goto msi; 2266758cc3dcSJack F Vogel 2267758cc3dcSJack F Vogel /* First try MSI/X */ 2268758cc3dcSJack F Vogel msgs = pci_msix_count(dev); 2269758cc3dcSJack F Vogel if (msgs == 0) 2270758cc3dcSJack F Vogel goto msi; 2271758cc3dcSJack F Vogel rid = PCIR_BAR(MSIX_82598_BAR); 2272758cc3dcSJack F Vogel adapter->msix_mem = bus_alloc_resource_any(dev, 2273758cc3dcSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 2274758cc3dcSJack F Vogel if (adapter->msix_mem == NULL) { 2275758cc3dcSJack F Vogel rid += 4; /* 82599 maps in higher BAR */ 2276758cc3dcSJack F Vogel adapter->msix_mem = bus_alloc_resource_any(dev, 2277758cc3dcSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 2278758cc3dcSJack F Vogel } 2279758cc3dcSJack F Vogel if (adapter->msix_mem == NULL) { 2280758cc3dcSJack F Vogel /* May not be enabled */ 2281758cc3dcSJack F Vogel device_printf(adapter->dev, 2282758cc3dcSJack F Vogel "Unable to map MSIX table \n"); 2283758cc3dcSJack F Vogel goto msi; 2284758cc3dcSJack F Vogel } 2285758cc3dcSJack F Vogel 2286758cc3dcSJack F Vogel /* Figure out a reasonable auto config value */ 2287758cc3dcSJack F Vogel queues = (mp_ncpus > (msgs-1)) ? (msgs-1) : mp_ncpus; 2288758cc3dcSJack F Vogel 2289758cc3dcSJack F Vogel #ifdef RSS 2290758cc3dcSJack F Vogel /* If we're doing RSS, clamp at the number of RSS buckets */ 2291758cc3dcSJack F Vogel if (queues > rss_getnumbuckets()) 2292758cc3dcSJack F Vogel queues = rss_getnumbuckets(); 2293758cc3dcSJack F Vogel #endif 2294758cc3dcSJack F Vogel 2295758cc3dcSJack F Vogel if (ixgbe_num_queues != 0) 2296758cc3dcSJack F Vogel queues = ixgbe_num_queues; 2297758cc3dcSJack F Vogel 2298758cc3dcSJack F Vogel /* reflect correct sysctl value */ 2299758cc3dcSJack F Vogel ixgbe_num_queues = queues; 2300758cc3dcSJack F Vogel 2301758cc3dcSJack F Vogel /* 2302758cc3dcSJack F Vogel ** Want one vector (RX/TX pair) per queue 2303758cc3dcSJack F Vogel ** plus an additional for Link. 2304758cc3dcSJack F Vogel */ 2305758cc3dcSJack F Vogel want = queues + 1; 2306758cc3dcSJack F Vogel if (msgs >= want) 2307758cc3dcSJack F Vogel msgs = want; 2308758cc3dcSJack F Vogel else { 2309758cc3dcSJack F Vogel device_printf(adapter->dev, 2310758cc3dcSJack F Vogel "MSIX Configuration Problem, " 2311758cc3dcSJack F Vogel "%d vectors but %d queues wanted!\n", 2312758cc3dcSJack F Vogel msgs, want); 2313758cc3dcSJack F Vogel goto msi; 2314758cc3dcSJack F Vogel } 2315758cc3dcSJack F Vogel if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { 2316758cc3dcSJack F Vogel device_printf(adapter->dev, 2317758cc3dcSJack F Vogel "Using MSIX interrupts with %d vectors\n", msgs); 2318758cc3dcSJack F Vogel adapter->num_queues = queues; 2319758cc3dcSJack F Vogel return (msgs); 2320758cc3dcSJack F Vogel } 2321758cc3dcSJack F Vogel /* 2322758cc3dcSJack F Vogel ** If MSIX alloc failed or provided us with 2323758cc3dcSJack F Vogel ** less than needed, free and fall through to MSI 2324758cc3dcSJack F Vogel */ 2325758cc3dcSJack F Vogel pci_release_msi(dev); 2326758cc3dcSJack F Vogel 2327758cc3dcSJack F Vogel msi: 2328758cc3dcSJack F Vogel if (adapter->msix_mem != NULL) { 2329758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2330758cc3dcSJack F Vogel rid, adapter->msix_mem); 2331758cc3dcSJack F Vogel adapter->msix_mem = NULL; 2332758cc3dcSJack F Vogel } 2333758cc3dcSJack F Vogel msgs = 1; 2334758cc3dcSJack F Vogel if (pci_alloc_msi(dev, &msgs) == 0) { 2335758cc3dcSJack F Vogel device_printf(adapter->dev,"Using an MSI interrupt\n"); 2336758cc3dcSJack F Vogel return (msgs); 2337758cc3dcSJack F Vogel } 2338758cc3dcSJack F Vogel device_printf(adapter->dev,"Using a Legacy interrupt\n"); 2339758cc3dcSJack F Vogel return (0); 2340758cc3dcSJack F Vogel } 2341758cc3dcSJack F Vogel 2342758cc3dcSJack F Vogel 2343758cc3dcSJack F Vogel static int 2344758cc3dcSJack F Vogel ixgbe_allocate_pci_resources(struct adapter *adapter) 2345758cc3dcSJack F Vogel { 2346758cc3dcSJack F Vogel int rid; 2347758cc3dcSJack F Vogel device_t dev = adapter->dev; 2348758cc3dcSJack F Vogel 2349758cc3dcSJack F Vogel rid = PCIR_BAR(0); 2350758cc3dcSJack F Vogel adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2351758cc3dcSJack F Vogel &rid, RF_ACTIVE); 2352758cc3dcSJack F Vogel 2353758cc3dcSJack F Vogel if (!(adapter->pci_mem)) { 2354758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate bus resource: memory\n"); 2355758cc3dcSJack F Vogel return (ENXIO); 2356758cc3dcSJack F Vogel } 2357758cc3dcSJack F Vogel 2358758cc3dcSJack F Vogel adapter->osdep.mem_bus_space_tag = 2359758cc3dcSJack F Vogel rman_get_bustag(adapter->pci_mem); 2360758cc3dcSJack F Vogel adapter->osdep.mem_bus_space_handle = 2361758cc3dcSJack F Vogel rman_get_bushandle(adapter->pci_mem); 2362758cc3dcSJack F Vogel adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle; 2363758cc3dcSJack F Vogel 2364758cc3dcSJack F Vogel /* Legacy defaults */ 2365758cc3dcSJack F Vogel adapter->num_queues = 1; 2366758cc3dcSJack F Vogel adapter->hw.back = &adapter->osdep; 2367758cc3dcSJack F Vogel 2368758cc3dcSJack F Vogel /* 2369758cc3dcSJack F Vogel ** Now setup MSI or MSI/X, should 2370758cc3dcSJack F Vogel ** return us the number of supported 2371758cc3dcSJack F Vogel ** vectors. (Will be 1 for MSI) 2372758cc3dcSJack F Vogel */ 2373758cc3dcSJack F Vogel adapter->msix = ixgbe_setup_msix(adapter); 2374758cc3dcSJack F Vogel return (0); 2375758cc3dcSJack F Vogel } 2376758cc3dcSJack F Vogel 2377758cc3dcSJack F Vogel static void 2378758cc3dcSJack F Vogel ixgbe_free_pci_resources(struct adapter * adapter) 2379758cc3dcSJack F Vogel { 2380758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2381758cc3dcSJack F Vogel device_t dev = adapter->dev; 2382758cc3dcSJack F Vogel int rid, memrid; 2383758cc3dcSJack F Vogel 2384758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) 2385758cc3dcSJack F Vogel memrid = PCIR_BAR(MSIX_82598_BAR); 2386758cc3dcSJack F Vogel else 2387758cc3dcSJack F Vogel memrid = PCIR_BAR(MSIX_82599_BAR); 2388758cc3dcSJack F Vogel 2389758cc3dcSJack F Vogel /* 2390758cc3dcSJack F Vogel ** There is a slight possibility of a failure mode 2391758cc3dcSJack F Vogel ** in attach that will result in entering this function 2392758cc3dcSJack F Vogel ** before interrupt resources have been initialized, and 2393758cc3dcSJack F Vogel ** in that case we do not want to execute the loops below 2394758cc3dcSJack F Vogel ** We can detect this reliably by the state of the adapter 2395758cc3dcSJack F Vogel ** res pointer. 2396758cc3dcSJack F Vogel */ 2397758cc3dcSJack F Vogel if (adapter->res == NULL) 2398758cc3dcSJack F Vogel goto mem; 2399758cc3dcSJack F Vogel 2400758cc3dcSJack F Vogel /* 2401758cc3dcSJack F Vogel ** Release all msix queue resources: 2402758cc3dcSJack F Vogel */ 2403758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 2404758cc3dcSJack F Vogel rid = que->msix + 1; 2405758cc3dcSJack F Vogel if (que->tag != NULL) { 2406758cc3dcSJack F Vogel bus_teardown_intr(dev, que->res, que->tag); 2407758cc3dcSJack F Vogel que->tag = NULL; 2408758cc3dcSJack F Vogel } 2409758cc3dcSJack F Vogel if (que->res != NULL) 2410758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2411758cc3dcSJack F Vogel } 2412758cc3dcSJack F Vogel 2413758cc3dcSJack F Vogel 2414758cc3dcSJack F Vogel /* Clean the Legacy or Link interrupt last */ 2415758cc3dcSJack F Vogel if (adapter->vector) /* we are doing MSIX */ 2416758cc3dcSJack F Vogel rid = adapter->vector + 1; 2417758cc3dcSJack F Vogel else 2418758cc3dcSJack F Vogel (adapter->msix != 0) ? (rid = 1):(rid = 0); 2419758cc3dcSJack F Vogel 2420758cc3dcSJack F Vogel if (adapter->tag != NULL) { 2421758cc3dcSJack F Vogel bus_teardown_intr(dev, adapter->res, adapter->tag); 2422758cc3dcSJack F Vogel adapter->tag = NULL; 2423758cc3dcSJack F Vogel } 2424758cc3dcSJack F Vogel if (adapter->res != NULL) 2425758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); 2426758cc3dcSJack F Vogel 2427758cc3dcSJack F Vogel mem: 2428758cc3dcSJack F Vogel if (adapter->msix) 2429758cc3dcSJack F Vogel pci_release_msi(dev); 2430758cc3dcSJack F Vogel 2431758cc3dcSJack F Vogel if (adapter->msix_mem != NULL) 2432758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2433758cc3dcSJack F Vogel memrid, adapter->msix_mem); 2434758cc3dcSJack F Vogel 2435758cc3dcSJack F Vogel if (adapter->pci_mem != NULL) 2436758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2437758cc3dcSJack F Vogel PCIR_BAR(0), adapter->pci_mem); 2438758cc3dcSJack F Vogel 2439758cc3dcSJack F Vogel return; 2440758cc3dcSJack F Vogel } 2441758cc3dcSJack F Vogel 2442758cc3dcSJack F Vogel /********************************************************************* 2443758cc3dcSJack F Vogel * 2444758cc3dcSJack F Vogel * Setup networking device structure and register an interface. 2445758cc3dcSJack F Vogel * 2446758cc3dcSJack F Vogel **********************************************************************/ 2447758cc3dcSJack F Vogel static int 2448758cc3dcSJack F Vogel ixgbe_setup_interface(device_t dev, struct adapter *adapter) 2449758cc3dcSJack F Vogel { 2450758cc3dcSJack F Vogel struct ifnet *ifp; 2451758cc3dcSJack F Vogel 2452758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_setup_interface: begin"); 2453758cc3dcSJack F Vogel 2454758cc3dcSJack F Vogel ifp = adapter->ifp = if_alloc(IFT_ETHER); 2455758cc3dcSJack F Vogel if (ifp == NULL) { 2456758cc3dcSJack F Vogel device_printf(dev, "can not allocate ifnet structure\n"); 2457758cc3dcSJack F Vogel return (-1); 2458758cc3dcSJack F Vogel } 2459758cc3dcSJack F Vogel if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2460758cc3dcSJack F Vogel ifp->if_baudrate = IF_Gbps(10); 2461758cc3dcSJack F Vogel ifp->if_init = ixgbe_init; 2462758cc3dcSJack F Vogel ifp->if_softc = adapter; 2463758cc3dcSJack F Vogel ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2464758cc3dcSJack F Vogel ifp->if_ioctl = ixgbe_ioctl; 2465758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 2466758cc3dcSJack F Vogel if_setgetcounterfn(ifp, ixgbe_get_counter); 2467758cc3dcSJack F Vogel #endif 2468758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2469758cc3dcSJack F Vogel ifp->if_transmit = ixgbe_mq_start; 2470758cc3dcSJack F Vogel ifp->if_qflush = ixgbe_qflush; 2471758cc3dcSJack F Vogel #else 2472758cc3dcSJack F Vogel ifp->if_start = ixgbe_start; 2473758cc3dcSJack F Vogel IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); 2474758cc3dcSJack F Vogel ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; 2475758cc3dcSJack F Vogel IFQ_SET_READY(&ifp->if_snd); 2476758cc3dcSJack F Vogel #endif 2477758cc3dcSJack F Vogel 2478758cc3dcSJack F Vogel ether_ifattach(ifp, adapter->hw.mac.addr); 2479758cc3dcSJack F Vogel 2480758cc3dcSJack F Vogel adapter->max_frame_size = 2481758cc3dcSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 2482758cc3dcSJack F Vogel 2483758cc3dcSJack F Vogel /* 2484758cc3dcSJack F Vogel * Tell the upper layer(s) we support long frames. 2485758cc3dcSJack F Vogel */ 2486758cc3dcSJack F Vogel ifp->if_hdrlen = sizeof(struct ether_vlan_header); 2487758cc3dcSJack F Vogel 2488758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO | IFCAP_VLAN_HWCSUM; 2489758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_JUMBO_MTU; 2490758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_LRO; 2491758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 2492758cc3dcSJack F Vogel | IFCAP_VLAN_HWTSO 2493758cc3dcSJack F Vogel | IFCAP_VLAN_MTU 2494758cc3dcSJack F Vogel | IFCAP_HWSTATS; 2495758cc3dcSJack F Vogel ifp->if_capenable = ifp->if_capabilities; 2496758cc3dcSJack F Vogel 2497758cc3dcSJack F Vogel /* 2498758cc3dcSJack F Vogel ** Don't turn this on by default, if vlans are 2499758cc3dcSJack F Vogel ** created on another pseudo device (eg. lagg) 2500758cc3dcSJack F Vogel ** then vlan events are not passed thru, breaking 2501758cc3dcSJack F Vogel ** operation, but with HW FILTER off it works. If 2502758cc3dcSJack F Vogel ** using vlans directly on the ixgbe driver you can 2503758cc3dcSJack F Vogel ** enable this and get full hardware tag filtering. 2504758cc3dcSJack F Vogel */ 2505758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 2506758cc3dcSJack F Vogel 2507758cc3dcSJack F Vogel /* 2508758cc3dcSJack F Vogel * Specify the media types supported by this adapter and register 2509758cc3dcSJack F Vogel * callbacks to update media and link information 2510758cc3dcSJack F Vogel */ 2511758cc3dcSJack F Vogel ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change, 2512758cc3dcSJack F Vogel ixgbe_media_status); 2513758cc3dcSJack F Vogel 2514758cc3dcSJack F Vogel ixgbe_add_media_types(adapter); 2515758cc3dcSJack F Vogel 2516758cc3dcSJack F Vogel /* Autoselect media by default */ 2517758cc3dcSJack F Vogel ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); 2518758cc3dcSJack F Vogel 2519758cc3dcSJack F Vogel return (0); 2520758cc3dcSJack F Vogel } 2521758cc3dcSJack F Vogel 2522758cc3dcSJack F Vogel static void 2523758cc3dcSJack F Vogel ixgbe_add_media_types(struct adapter *adapter) 2524758cc3dcSJack F Vogel { 2525758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2526758cc3dcSJack F Vogel device_t dev = adapter->dev; 2527758cc3dcSJack F Vogel int layer; 2528758cc3dcSJack F Vogel 2529758cc3dcSJack F Vogel layer = ixgbe_get_supported_physical_layer(hw); 2530758cc3dcSJack F Vogel 2531758cc3dcSJack F Vogel /* Media types with matching FreeBSD media defines */ 2532758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) 2533758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2534758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) 2535758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); 2536758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) 2537758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2538758cc3dcSJack F Vogel 2539758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || 2540758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) 2541758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2542758cc3dcSJack F Vogel 2543758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) 2544758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2545758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) 2546758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2547758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) 2548758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2549758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) 2550758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 2551758cc3dcSJack F Vogel #if 0 2552758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_LX) 2553758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, NULL); 2554758cc3dcSJack F Vogel #endif 2555758cc3dcSJack F Vogel 2556758cc3dcSJack F Vogel /* 2557758cc3dcSJack F Vogel ** Other (no matching FreeBSD media type): 2558758cc3dcSJack F Vogel ** To workaround this, we'll assign these completely 2559758cc3dcSJack F Vogel ** inappropriate media types. 2560758cc3dcSJack F Vogel */ 2561758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) { 2562758cc3dcSJack F Vogel device_printf(dev, "Media supported: 10GbaseKR\n"); 2563758cc3dcSJack F Vogel device_printf(dev, "10GbaseKR mapped to 10baseT\n"); 2564758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T, 0, NULL); 2565758cc3dcSJack F Vogel } 2566758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) { 2567758cc3dcSJack F Vogel device_printf(dev, "Media supported: 10GbaseKX4\n"); 2568758cc3dcSJack F Vogel device_printf(dev, "10GbaseKX4 mapped to 10base2\n"); 2569758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_2, 0, NULL); 2570758cc3dcSJack F Vogel } 2571758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) { 2572758cc3dcSJack F Vogel device_printf(dev, "Media supported: 1000baseKX\n"); 2573758cc3dcSJack F Vogel device_printf(dev, "1000baseKX mapped to 10base5\n"); 2574758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_5, 0, NULL); 2575758cc3dcSJack F Vogel } 2576758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX) { 2577758cc3dcSJack F Vogel /* Someday, someone will care about you... */ 2578758cc3dcSJack F Vogel device_printf(dev, "Media supported: 1000baseBX\n"); 2579758cc3dcSJack F Vogel } 2580758cc3dcSJack F Vogel 2581758cc3dcSJack F Vogel /* Very old */ 2582758cc3dcSJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) { 2583758cc3dcSJack F Vogel ifmedia_add(&adapter->media, 2584758cc3dcSJack F Vogel IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 2585758cc3dcSJack F Vogel ifmedia_add(&adapter->media, 2586758cc3dcSJack F Vogel IFM_ETHER | IFM_1000_T, 0, NULL); 2587758cc3dcSJack F Vogel } 2588758cc3dcSJack F Vogel 2589758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2590758cc3dcSJack F Vogel } 2591758cc3dcSJack F Vogel 2592758cc3dcSJack F Vogel static void 2593758cc3dcSJack F Vogel ixgbe_config_link(struct adapter *adapter) 2594758cc3dcSJack F Vogel { 2595758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2596758cc3dcSJack F Vogel u32 autoneg, err = 0; 2597758cc3dcSJack F Vogel bool sfp, negotiate; 2598758cc3dcSJack F Vogel 2599758cc3dcSJack F Vogel sfp = ixgbe_is_sfp(hw); 2600758cc3dcSJack F Vogel 2601758cc3dcSJack F Vogel if (sfp) { 2602758cc3dcSJack F Vogel if (hw->phy.multispeed_fiber) { 2603758cc3dcSJack F Vogel hw->mac.ops.setup_sfp(hw); 2604758cc3dcSJack F Vogel ixgbe_enable_tx_laser(hw); 2605758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 2606758cc3dcSJack F Vogel } else 2607758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mod_task); 2608758cc3dcSJack F Vogel } else { 2609758cc3dcSJack F Vogel if (hw->mac.ops.check_link) 2610758cc3dcSJack F Vogel err = ixgbe_check_link(hw, &adapter->link_speed, 2611758cc3dcSJack F Vogel &adapter->link_up, FALSE); 2612758cc3dcSJack F Vogel if (err) 2613758cc3dcSJack F Vogel goto out; 2614758cc3dcSJack F Vogel autoneg = hw->phy.autoneg_advertised; 2615758cc3dcSJack F Vogel if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) 2616758cc3dcSJack F Vogel err = hw->mac.ops.get_link_capabilities(hw, 2617758cc3dcSJack F Vogel &autoneg, &negotiate); 2618758cc3dcSJack F Vogel if (err) 2619758cc3dcSJack F Vogel goto out; 2620758cc3dcSJack F Vogel if (hw->mac.ops.setup_link) 2621758cc3dcSJack F Vogel err = hw->mac.ops.setup_link(hw, 2622758cc3dcSJack F Vogel autoneg, adapter->link_up); 2623758cc3dcSJack F Vogel } 2624758cc3dcSJack F Vogel out: 2625758cc3dcSJack F Vogel return; 2626758cc3dcSJack F Vogel } 2627758cc3dcSJack F Vogel 2628758cc3dcSJack F Vogel 2629758cc3dcSJack F Vogel /********************************************************************* 2630758cc3dcSJack F Vogel * 2631758cc3dcSJack F Vogel * Enable transmit units. 2632758cc3dcSJack F Vogel * 2633758cc3dcSJack F Vogel **********************************************************************/ 2634758cc3dcSJack F Vogel static void 2635758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(struct adapter *adapter) 2636758cc3dcSJack F Vogel { 2637758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2638758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2639758cc3dcSJack F Vogel 2640758cc3dcSJack F Vogel /* Setup the Base and Length of the Tx Descriptor Ring */ 2641758cc3dcSJack F Vogel 2642758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, txr++) { 2643758cc3dcSJack F Vogel u64 tdba = txr->txdma.dma_paddr; 2644758cc3dcSJack F Vogel u32 txctrl = 0; 2645758cc3dcSJack F Vogel 2646758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), 2647758cc3dcSJack F Vogel (tdba & 0x00000000ffffffffULL)); 2648758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (tdba >> 32)); 2649758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i), 2650758cc3dcSJack F Vogel adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc)); 2651758cc3dcSJack F Vogel 2652758cc3dcSJack F Vogel /* Setup the HW Tx Head and Tail descriptor pointers */ 2653758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0); 2654758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0); 2655758cc3dcSJack F Vogel 2656758cc3dcSJack F Vogel /* Cache the tail address */ 2657758cc3dcSJack F Vogel txr->tail = IXGBE_TDT(txr->me); 2658758cc3dcSJack F Vogel 2659758cc3dcSJack F Vogel /* Set the processing limit */ 2660758cc3dcSJack F Vogel txr->process_limit = ixgbe_tx_process_limit; 2661758cc3dcSJack F Vogel 2662758cc3dcSJack F Vogel /* Disable Head Writeback */ 2663758cc3dcSJack F Vogel switch (hw->mac.type) { 2664758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 2665758cc3dcSJack F Vogel txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); 2666758cc3dcSJack F Vogel break; 2667758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 2668758cc3dcSJack F Vogel case ixgbe_mac_X540: 2669758cc3dcSJack F Vogel default: 2670758cc3dcSJack F Vogel txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i)); 2671758cc3dcSJack F Vogel break; 2672758cc3dcSJack F Vogel } 2673758cc3dcSJack F Vogel txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; 2674758cc3dcSJack F Vogel switch (hw->mac.type) { 2675758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 2676758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl); 2677758cc3dcSJack F Vogel break; 2678758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 2679758cc3dcSJack F Vogel case ixgbe_mac_X540: 2680758cc3dcSJack F Vogel default: 2681758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(i), txctrl); 2682758cc3dcSJack F Vogel break; 2683758cc3dcSJack F Vogel } 2684758cc3dcSJack F Vogel 2685758cc3dcSJack F Vogel } 2686758cc3dcSJack F Vogel 2687758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 2688758cc3dcSJack F Vogel u32 dmatxctl, rttdcs; 2689758cc3dcSJack F Vogel dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); 2690758cc3dcSJack F Vogel dmatxctl |= IXGBE_DMATXCTL_TE; 2691758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); 2692758cc3dcSJack F Vogel /* Disable arbiter to set MTQC */ 2693758cc3dcSJack F Vogel rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); 2694758cc3dcSJack F Vogel rttdcs |= IXGBE_RTTDCS_ARBDIS; 2695758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); 2696758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); 2697758cc3dcSJack F Vogel rttdcs &= ~IXGBE_RTTDCS_ARBDIS; 2698758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); 2699758cc3dcSJack F Vogel } 2700758cc3dcSJack F Vogel 2701758cc3dcSJack F Vogel return; 2702758cc3dcSJack F Vogel } 2703758cc3dcSJack F Vogel 2704758cc3dcSJack F Vogel static void 2705758cc3dcSJack F Vogel ixgbe_initialise_rss_mapping(struct adapter *adapter) 2706758cc3dcSJack F Vogel { 2707758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2708758cc3dcSJack F Vogel uint32_t reta; 2709758cc3dcSJack F Vogel int i, j, queue_id; 2710758cc3dcSJack F Vogel uint32_t rss_key[10]; 2711758cc3dcSJack F Vogel uint32_t mrqc; 2712758cc3dcSJack F Vogel #ifdef RSS 2713758cc3dcSJack F Vogel uint32_t rss_hash_config; 2714758cc3dcSJack F Vogel #endif 2715758cc3dcSJack F Vogel 2716758cc3dcSJack F Vogel /* Setup RSS */ 2717758cc3dcSJack F Vogel reta = 0; 2718758cc3dcSJack F Vogel 2719758cc3dcSJack F Vogel #ifdef RSS 2720758cc3dcSJack F Vogel /* Fetch the configured RSS key */ 2721758cc3dcSJack F Vogel rss_getkey((uint8_t *) &rss_key); 2722758cc3dcSJack F Vogel #else 2723758cc3dcSJack F Vogel /* set up random bits */ 2724758cc3dcSJack F Vogel arc4rand(&rss_key, sizeof(rss_key), 0); 2725758cc3dcSJack F Vogel #endif 2726758cc3dcSJack F Vogel 2727758cc3dcSJack F Vogel /* Set up the redirection table */ 2728758cc3dcSJack F Vogel for (i = 0, j = 0; i < 128; i++, j++) { 2729758cc3dcSJack F Vogel if (j == adapter->num_queues) j = 0; 2730758cc3dcSJack F Vogel #ifdef RSS 2731758cc3dcSJack F Vogel /* 2732758cc3dcSJack F Vogel * Fetch the RSS bucket id for the given indirection entry. 2733758cc3dcSJack F Vogel * Cap it at the number of configured buckets (which is 2734758cc3dcSJack F Vogel * num_queues.) 2735758cc3dcSJack F Vogel */ 2736758cc3dcSJack F Vogel queue_id = rss_get_indirection_to_bucket(i); 2737758cc3dcSJack F Vogel queue_id = queue_id % adapter->num_queues; 2738758cc3dcSJack F Vogel #else 2739758cc3dcSJack F Vogel queue_id = (j * 0x11); 2740758cc3dcSJack F Vogel #endif 2741758cc3dcSJack F Vogel /* 2742758cc3dcSJack F Vogel * The low 8 bits are for hash value (n+0); 2743758cc3dcSJack F Vogel * The next 8 bits are for hash value (n+1), etc. 2744758cc3dcSJack F Vogel */ 2745758cc3dcSJack F Vogel reta = reta >> 8; 2746758cc3dcSJack F Vogel reta = reta | ( ((uint32_t) queue_id) << 24); 2747758cc3dcSJack F Vogel if ((i & 3) == 3) { 2748758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); 2749758cc3dcSJack F Vogel reta = 0; 2750758cc3dcSJack F Vogel } 2751758cc3dcSJack F Vogel } 2752758cc3dcSJack F Vogel 2753758cc3dcSJack F Vogel /* Now fill our hash function seeds */ 2754758cc3dcSJack F Vogel for (int i = 0; i < 10; i++) 2755758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); 2756758cc3dcSJack F Vogel 2757758cc3dcSJack F Vogel /* Perform hash on these packet types */ 2758758cc3dcSJack F Vogel #ifdef RSS 2759758cc3dcSJack F Vogel mrqc = IXGBE_MRQC_RSSEN; 2760758cc3dcSJack F Vogel rss_hash_config = rss_gethashconfig(); 2761758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 2762758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; 2763758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 2764758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; 2765758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 2766758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; 2767758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 2768758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; 2769758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 2770758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX; 2771758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) 2772758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP; 2773758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 2774758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; 2775758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) 2776758cc3dcSJack F Vogel device_printf(adapter->dev, 2777758cc3dcSJack F Vogel "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, " 2778758cc3dcSJack F Vogel "but not supported\n", __func__); 2779758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 2780758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; 2781758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) 2782758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 2783758cc3dcSJack F Vogel #else 2784758cc3dcSJack F Vogel /* 2785758cc3dcSJack F Vogel * Disable UDP - IP fragments aren't currently being handled 2786758cc3dcSJack F Vogel * and so we end up with a mix of 2-tuple and 4-tuple 2787758cc3dcSJack F Vogel * traffic. 2788758cc3dcSJack F Vogel */ 2789758cc3dcSJack F Vogel mrqc = IXGBE_MRQC_RSSEN 2790758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4 2791758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4_TCP 2792758cc3dcSJack F Vogel #if 0 2793758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4_UDP 2794758cc3dcSJack F Vogel #endif 2795758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP 2796758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX 2797758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6 2798758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_TCP 2799758cc3dcSJack F Vogel #if 0 2800758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_UDP 2801758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP 2802758cc3dcSJack F Vogel #endif 2803758cc3dcSJack F Vogel ; 2804758cc3dcSJack F Vogel #endif /* RSS */ 2805758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 2806758cc3dcSJack F Vogel } 2807758cc3dcSJack F Vogel 2808758cc3dcSJack F Vogel 2809758cc3dcSJack F Vogel /********************************************************************* 2810758cc3dcSJack F Vogel * 2811758cc3dcSJack F Vogel * Setup receive registers and features. 2812758cc3dcSJack F Vogel * 2813758cc3dcSJack F Vogel **********************************************************************/ 2814758cc3dcSJack F Vogel #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 2815758cc3dcSJack F Vogel 2816758cc3dcSJack F Vogel #define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1) 2817758cc3dcSJack F Vogel 2818758cc3dcSJack F Vogel static void 2819758cc3dcSJack F Vogel ixgbe_initialize_receive_units(struct adapter *adapter) 2820758cc3dcSJack F Vogel { 2821758cc3dcSJack F Vogel struct rx_ring *rxr = adapter->rx_rings; 2822758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2823758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 2824758cc3dcSJack F Vogel u32 bufsz, fctrl, srrctl, rxcsum; 2825758cc3dcSJack F Vogel u32 hlreg; 2826758cc3dcSJack F Vogel 2827758cc3dcSJack F Vogel 2828758cc3dcSJack F Vogel /* 2829758cc3dcSJack F Vogel * Make sure receives are disabled while 2830758cc3dcSJack F Vogel * setting up the descriptor ring 2831758cc3dcSJack F Vogel */ 2832758cc3dcSJack F Vogel ixgbe_disable_rx(hw); 2833758cc3dcSJack F Vogel 2834758cc3dcSJack F Vogel /* Enable broadcasts */ 2835758cc3dcSJack F Vogel fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); 2836758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_BAM; 2837758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_DPF; 2838758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_PMCF; 2839758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); 2840758cc3dcSJack F Vogel 2841758cc3dcSJack F Vogel /* Set for Jumbo Frames? */ 2842758cc3dcSJack F Vogel hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); 2843758cc3dcSJack F Vogel if (ifp->if_mtu > ETHERMTU) 2844758cc3dcSJack F Vogel hlreg |= IXGBE_HLREG0_JUMBOEN; 2845758cc3dcSJack F Vogel else 2846758cc3dcSJack F Vogel hlreg &= ~IXGBE_HLREG0_JUMBOEN; 2847758cc3dcSJack F Vogel #ifdef DEV_NETMAP 2848758cc3dcSJack F Vogel /* crcstrip is conditional in netmap (in RDRXCTL too ?) */ 2849758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip) 2850758cc3dcSJack F Vogel hlreg &= ~IXGBE_HLREG0_RXCRCSTRP; 2851758cc3dcSJack F Vogel else 2852758cc3dcSJack F Vogel hlreg |= IXGBE_HLREG0_RXCRCSTRP; 2853758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 2854758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); 2855758cc3dcSJack F Vogel 2856758cc3dcSJack F Vogel bufsz = (adapter->rx_mbuf_sz + 2857758cc3dcSJack F Vogel BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; 2858758cc3dcSJack F Vogel 2859758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, rxr++) { 2860758cc3dcSJack F Vogel u64 rdba = rxr->rxdma.dma_paddr; 2861758cc3dcSJack F Vogel 2862758cc3dcSJack F Vogel /* Setup the Base and Length of the Rx Descriptor Ring */ 2863758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), 2864758cc3dcSJack F Vogel (rdba & 0x00000000ffffffffULL)); 2865758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32)); 2866758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), 2867758cc3dcSJack F Vogel adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); 2868758cc3dcSJack F Vogel 2869758cc3dcSJack F Vogel /* Set up the SRRCTL register */ 2870758cc3dcSJack F Vogel srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); 2871758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; 2872758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; 2873758cc3dcSJack F Vogel srrctl |= bufsz; 2874758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; 2875758cc3dcSJack F Vogel 2876758cc3dcSJack F Vogel /* 2877758cc3dcSJack F Vogel * Set DROP_EN iff we have no flow control and >1 queue. 2878758cc3dcSJack F Vogel * Note that srrctl was cleared shortly before during reset, 2879758cc3dcSJack F Vogel * so we do not need to clear the bit, but do it just in case 2880758cc3dcSJack F Vogel * this code is moved elsewhere. 2881758cc3dcSJack F Vogel */ 2882758cc3dcSJack F Vogel if (adapter->num_queues > 1 && 2883758cc3dcSJack F Vogel adapter->hw.fc.requested_mode == ixgbe_fc_none) { 2884758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DROP_EN; 2885758cc3dcSJack F Vogel } else { 2886758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_DROP_EN; 2887758cc3dcSJack F Vogel } 2888758cc3dcSJack F Vogel 2889758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); 2890758cc3dcSJack F Vogel 2891758cc3dcSJack F Vogel /* Setup the HW Rx Head and Tail Descriptor Pointers */ 2892758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0); 2893758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0); 2894758cc3dcSJack F Vogel 2895758cc3dcSJack F Vogel /* Set the processing limit */ 2896758cc3dcSJack F Vogel rxr->process_limit = ixgbe_rx_process_limit; 2897758cc3dcSJack F Vogel 2898758cc3dcSJack F Vogel /* Set the driver rx tail address */ 2899758cc3dcSJack F Vogel rxr->tail = IXGBE_RDT(rxr->me); 2900758cc3dcSJack F Vogel } 2901758cc3dcSJack F Vogel 2902758cc3dcSJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82598EB) { 2903758cc3dcSJack F Vogel u32 psrtype = IXGBE_PSRTYPE_TCPHDR | 2904758cc3dcSJack F Vogel IXGBE_PSRTYPE_UDPHDR | 2905758cc3dcSJack F Vogel IXGBE_PSRTYPE_IPV4HDR | 2906758cc3dcSJack F Vogel IXGBE_PSRTYPE_IPV6HDR; 2907758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); 2908758cc3dcSJack F Vogel } 2909758cc3dcSJack F Vogel 2910758cc3dcSJack F Vogel rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 2911758cc3dcSJack F Vogel 2912758cc3dcSJack F Vogel ixgbe_initialise_rss_mapping(adapter); 2913758cc3dcSJack F Vogel 2914758cc3dcSJack F Vogel if (adapter->num_queues > 1) { 2915758cc3dcSJack F Vogel /* RSS and RX IPP Checksum are mutually exclusive */ 2916758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_PCSD; 2917758cc3dcSJack F Vogel } 2918758cc3dcSJack F Vogel 2919758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_RXCSUM) 2920758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_PCSD; 2921758cc3dcSJack F Vogel 2922758cc3dcSJack F Vogel if (!(rxcsum & IXGBE_RXCSUM_PCSD)) 2923758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_IPPCSE; 2924758cc3dcSJack F Vogel 2925758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); 2926758cc3dcSJack F Vogel 2927758cc3dcSJack F Vogel return; 2928758cc3dcSJack F Vogel } 2929758cc3dcSJack F Vogel 2930758cc3dcSJack F Vogel 2931758cc3dcSJack F Vogel /* 2932758cc3dcSJack F Vogel ** This routine is run via an vlan config EVENT, 2933758cc3dcSJack F Vogel ** it enables us to use the HW Filter table since 2934758cc3dcSJack F Vogel ** we can get the vlan id. This just creates the 2935758cc3dcSJack F Vogel ** entry in the soft version of the VFTA, init will 2936758cc3dcSJack F Vogel ** repopulate the real table. 2937758cc3dcSJack F Vogel */ 2938758cc3dcSJack F Vogel static void 2939758cc3dcSJack F Vogel ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 2940758cc3dcSJack F Vogel { 2941758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 2942758cc3dcSJack F Vogel u16 index, bit; 2943758cc3dcSJack F Vogel 2944758cc3dcSJack F Vogel if (ifp->if_softc != arg) /* Not our event */ 2945758cc3dcSJack F Vogel return; 2946758cc3dcSJack F Vogel 2947758cc3dcSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 2948758cc3dcSJack F Vogel return; 2949758cc3dcSJack F Vogel 2950758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 2951758cc3dcSJack F Vogel index = (vtag >> 5) & 0x7F; 2952758cc3dcSJack F Vogel bit = vtag & 0x1F; 2953758cc3dcSJack F Vogel adapter->shadow_vfta[index] |= (1 << bit); 2954758cc3dcSJack F Vogel ++adapter->num_vlans; 2955758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 2956758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 2957758cc3dcSJack F Vogel } 2958758cc3dcSJack F Vogel 2959758cc3dcSJack F Vogel /* 2960758cc3dcSJack F Vogel ** This routine is run via an vlan 2961758cc3dcSJack F Vogel ** unconfig EVENT, remove our entry 2962758cc3dcSJack F Vogel ** in the soft vfta. 2963758cc3dcSJack F Vogel */ 2964758cc3dcSJack F Vogel static void 2965758cc3dcSJack F Vogel ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 2966758cc3dcSJack F Vogel { 2967758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 2968758cc3dcSJack F Vogel u16 index, bit; 2969758cc3dcSJack F Vogel 2970758cc3dcSJack F Vogel if (ifp->if_softc != arg) 2971758cc3dcSJack F Vogel return; 2972758cc3dcSJack F Vogel 2973758cc3dcSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 2974758cc3dcSJack F Vogel return; 2975758cc3dcSJack F Vogel 2976758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 2977758cc3dcSJack F Vogel index = (vtag >> 5) & 0x7F; 2978758cc3dcSJack F Vogel bit = vtag & 0x1F; 2979758cc3dcSJack F Vogel adapter->shadow_vfta[index] &= ~(1 << bit); 2980758cc3dcSJack F Vogel --adapter->num_vlans; 2981758cc3dcSJack F Vogel /* Re-init to load the changes */ 2982758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 2983758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 2984758cc3dcSJack F Vogel } 2985758cc3dcSJack F Vogel 2986758cc3dcSJack F Vogel static void 2987758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(struct adapter *adapter) 2988758cc3dcSJack F Vogel { 2989758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 2990758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2991758cc3dcSJack F Vogel struct rx_ring *rxr; 2992758cc3dcSJack F Vogel u32 ctrl; 2993758cc3dcSJack F Vogel 2994758cc3dcSJack F Vogel 2995758cc3dcSJack F Vogel /* 2996758cc3dcSJack F Vogel ** We get here thru init_locked, meaning 2997758cc3dcSJack F Vogel ** a soft reset, this has already cleared 2998758cc3dcSJack F Vogel ** the VFTA and other state, so if there 2999758cc3dcSJack F Vogel ** have been no vlan's registered do nothing. 3000758cc3dcSJack F Vogel */ 3001758cc3dcSJack F Vogel if (adapter->num_vlans == 0) 3002758cc3dcSJack F Vogel return; 3003758cc3dcSJack F Vogel 3004758cc3dcSJack F Vogel /* Setup the queues for vlans */ 3005758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 3006758cc3dcSJack F Vogel rxr = &adapter->rx_rings[i]; 3007758cc3dcSJack F Vogel /* On 82599 the VLAN enable is per/queue in RXDCTL */ 3008758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 3009758cc3dcSJack F Vogel ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); 3010758cc3dcSJack F Vogel ctrl |= IXGBE_RXDCTL_VME; 3011758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), ctrl); 3012758cc3dcSJack F Vogel } 3013758cc3dcSJack F Vogel rxr->vtag_strip = TRUE; 3014758cc3dcSJack F Vogel } 3015758cc3dcSJack F Vogel 3016758cc3dcSJack F Vogel if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0) 3017758cc3dcSJack F Vogel return; 3018758cc3dcSJack F Vogel /* 3019758cc3dcSJack F Vogel ** A soft reset zero's out the VFTA, so 3020758cc3dcSJack F Vogel ** we need to repopulate it now. 3021758cc3dcSJack F Vogel */ 3022758cc3dcSJack F Vogel for (int i = 0; i < IXGBE_VFTA_SIZE; i++) 3023758cc3dcSJack F Vogel if (adapter->shadow_vfta[i] != 0) 3024758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), 3025758cc3dcSJack F Vogel adapter->shadow_vfta[i]); 3026758cc3dcSJack F Vogel 3027758cc3dcSJack F Vogel ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); 3028758cc3dcSJack F Vogel /* Enable the Filter Table if enabled */ 3029758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) { 3030758cc3dcSJack F Vogel ctrl &= ~IXGBE_VLNCTRL_CFIEN; 3031758cc3dcSJack F Vogel ctrl |= IXGBE_VLNCTRL_VFE; 3032758cc3dcSJack F Vogel } 3033758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 3034758cc3dcSJack F Vogel ctrl |= IXGBE_VLNCTRL_VME; 3035758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); 3036758cc3dcSJack F Vogel } 3037758cc3dcSJack F Vogel 3038758cc3dcSJack F Vogel static void 3039758cc3dcSJack F Vogel ixgbe_enable_intr(struct adapter *adapter) 3040758cc3dcSJack F Vogel { 3041758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3042758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 3043758cc3dcSJack F Vogel u32 mask, fwsm; 3044758cc3dcSJack F Vogel 3045758cc3dcSJack F Vogel mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); 3046758cc3dcSJack F Vogel /* Enable Fan Failure detection */ 3047758cc3dcSJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) 3048758cc3dcSJack F Vogel mask |= IXGBE_EIMS_GPI_SDP1_BY_MAC(hw); 3049758cc3dcSJack F Vogel 3050758cc3dcSJack F Vogel switch (adapter->hw.mac.type) { 3051758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 3052758cc3dcSJack F Vogel mask |= IXGBE_EIMS_ECC; 3053758cc3dcSJack F Vogel /* Temperature sensor on some adapters */ 3054758cc3dcSJack F Vogel mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); 3055758cc3dcSJack F Vogel /* SFP+ (RX_LOS_N & MOD_ABS_N) */ 3056758cc3dcSJack F Vogel mask |= IXGBE_EIMS_GPI_SDP1_BY_MAC(hw); 3057758cc3dcSJack F Vogel mask |= IXGBE_EIMS_GPI_SDP2_BY_MAC(hw); 3058758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3059758cc3dcSJack F Vogel mask |= IXGBE_EIMS_FLOW_DIR; 3060758cc3dcSJack F Vogel #endif 3061758cc3dcSJack F Vogel break; 3062758cc3dcSJack F Vogel case ixgbe_mac_X540: 3063758cc3dcSJack F Vogel case ixgbe_mac_X550: 3064758cc3dcSJack F Vogel case ixgbe_mac_X550EM_a: 3065758cc3dcSJack F Vogel case ixgbe_mac_X550EM_x: 3066758cc3dcSJack F Vogel /* Detect if Thermal Sensor is enabled */ 3067758cc3dcSJack F Vogel fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); 3068758cc3dcSJack F Vogel if (fwsm & IXGBE_FWSM_TS_ENABLED) 3069758cc3dcSJack F Vogel mask |= IXGBE_EIMS_TS; 3070758cc3dcSJack F Vogel /* XXX: Which SFP mode line does this look at? */ 3071758cc3dcSJack F Vogel if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) 3072758cc3dcSJack F Vogel mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); 3073758cc3dcSJack F Vogel mask |= IXGBE_EIMS_ECC; 3074758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3075758cc3dcSJack F Vogel mask |= IXGBE_EIMS_FLOW_DIR; 3076758cc3dcSJack F Vogel #endif 3077758cc3dcSJack F Vogel /* falls through */ 3078758cc3dcSJack F Vogel default: 3079758cc3dcSJack F Vogel break; 3080758cc3dcSJack F Vogel } 3081758cc3dcSJack F Vogel 3082758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); 3083758cc3dcSJack F Vogel 3084758cc3dcSJack F Vogel /* With RSS we use auto clear */ 3085758cc3dcSJack F Vogel if (adapter->msix_mem) { 3086758cc3dcSJack F Vogel mask = IXGBE_EIMS_ENABLE_MASK; 3087758cc3dcSJack F Vogel /* Don't autoclear Link */ 3088758cc3dcSJack F Vogel mask &= ~IXGBE_EIMS_OTHER; 3089758cc3dcSJack F Vogel mask &= ~IXGBE_EIMS_LSC; 3090758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); 3091758cc3dcSJack F Vogel } 3092758cc3dcSJack F Vogel 3093758cc3dcSJack F Vogel /* 3094758cc3dcSJack F Vogel ** Now enable all queues, this is done separately to 3095758cc3dcSJack F Vogel ** allow for handling the extended (beyond 32) MSIX 3096758cc3dcSJack F Vogel ** vectors that can be used by 82599 3097758cc3dcSJack F Vogel */ 3098758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) 3099758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 3100758cc3dcSJack F Vogel 3101758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(hw); 3102758cc3dcSJack F Vogel 3103758cc3dcSJack F Vogel return; 3104758cc3dcSJack F Vogel } 3105758cc3dcSJack F Vogel 3106758cc3dcSJack F Vogel static void 3107758cc3dcSJack F Vogel ixgbe_disable_intr(struct adapter *adapter) 3108758cc3dcSJack F Vogel { 3109758cc3dcSJack F Vogel if (adapter->msix_mem) 3110758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, 0); 3111758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) { 3112758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); 3113758cc3dcSJack F Vogel } else { 3114758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000); 3115758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0); 3116758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0); 3117758cc3dcSJack F Vogel } 3118758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(&adapter->hw); 3119758cc3dcSJack F Vogel return; 3120758cc3dcSJack F Vogel } 3121758cc3dcSJack F Vogel 3122758cc3dcSJack F Vogel /* 3123758cc3dcSJack F Vogel ** Get the width and transaction speed of 3124758cc3dcSJack F Vogel ** the slot this adapter is plugged into. 3125758cc3dcSJack F Vogel */ 3126758cc3dcSJack F Vogel static void 3127758cc3dcSJack F Vogel ixgbe_get_slot_info(struct ixgbe_hw *hw) 3128758cc3dcSJack F Vogel { 3129758cc3dcSJack F Vogel device_t dev = ((struct ixgbe_osdep *)hw->back)->dev; 3130758cc3dcSJack F Vogel struct ixgbe_mac_info *mac = &hw->mac; 3131758cc3dcSJack F Vogel u16 link; 3132758cc3dcSJack F Vogel u32 offset; 3133758cc3dcSJack F Vogel 3134758cc3dcSJack F Vogel /* For most devices simply call the shared code routine */ 3135758cc3dcSJack F Vogel if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) { 3136758cc3dcSJack F Vogel ixgbe_get_bus_info(hw); 3137758cc3dcSJack F Vogel /* These devices don't use PCI-E */ 3138758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_X550EM_x 3139758cc3dcSJack F Vogel || hw->mac.type == ixgbe_mac_X550EM_a) 3140758cc3dcSJack F Vogel return; 3141758cc3dcSJack F Vogel goto display; 3142758cc3dcSJack F Vogel } 3143758cc3dcSJack F Vogel 3144758cc3dcSJack F Vogel /* 3145758cc3dcSJack F Vogel ** For the Quad port adapter we need to parse back 3146758cc3dcSJack F Vogel ** up the PCI tree to find the speed of the expansion 3147758cc3dcSJack F Vogel ** slot into which this adapter is plugged. A bit more work. 3148758cc3dcSJack F Vogel */ 3149758cc3dcSJack F Vogel dev = device_get_parent(device_get_parent(dev)); 3150758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG 3151758cc3dcSJack F Vogel device_printf(dev, "parent pcib = %x,%x,%x\n", 3152758cc3dcSJack F Vogel pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); 3153758cc3dcSJack F Vogel #endif 3154758cc3dcSJack F Vogel dev = device_get_parent(device_get_parent(dev)); 3155758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG 3156758cc3dcSJack F Vogel device_printf(dev, "slot pcib = %x,%x,%x\n", 3157758cc3dcSJack F Vogel pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); 3158758cc3dcSJack F Vogel #endif 3159758cc3dcSJack F Vogel /* Now get the PCI Express Capabilities offset */ 3160758cc3dcSJack F Vogel pci_find_cap(dev, PCIY_EXPRESS, &offset); 3161758cc3dcSJack F Vogel /* ...and read the Link Status Register */ 3162758cc3dcSJack F Vogel link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 3163758cc3dcSJack F Vogel switch (link & IXGBE_PCI_LINK_WIDTH) { 3164758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_1: 3165758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x1; 3166758cc3dcSJack F Vogel break; 3167758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_2: 3168758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x2; 3169758cc3dcSJack F Vogel break; 3170758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_4: 3171758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x4; 3172758cc3dcSJack F Vogel break; 3173758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_8: 3174758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x8; 3175758cc3dcSJack F Vogel break; 3176758cc3dcSJack F Vogel default: 3177758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_unknown; 3178758cc3dcSJack F Vogel break; 3179758cc3dcSJack F Vogel } 3180758cc3dcSJack F Vogel 3181758cc3dcSJack F Vogel switch (link & IXGBE_PCI_LINK_SPEED) { 3182758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_2500: 3183758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_2500; 3184758cc3dcSJack F Vogel break; 3185758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_5000: 3186758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_5000; 3187758cc3dcSJack F Vogel break; 3188758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_8000: 3189758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_8000; 3190758cc3dcSJack F Vogel break; 3191758cc3dcSJack F Vogel default: 3192758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_unknown; 3193758cc3dcSJack F Vogel break; 3194758cc3dcSJack F Vogel } 3195758cc3dcSJack F Vogel 3196758cc3dcSJack F Vogel mac->ops.set_lan_id(hw); 3197758cc3dcSJack F Vogel 3198758cc3dcSJack F Vogel display: 3199758cc3dcSJack F Vogel device_printf(dev,"PCI Express Bus: Speed %s %s\n", 3200758cc3dcSJack F Vogel ((hw->bus.speed == ixgbe_bus_speed_8000) ? "8.0GT/s": 3201758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0GT/s": 3202758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5GT/s":"Unknown"), 3203758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" : 3204758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" : 3205758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" : 3206758cc3dcSJack F Vogel ("Unknown")); 3207758cc3dcSJack F Vogel 3208758cc3dcSJack F Vogel if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) && 3209758cc3dcSJack F Vogel ((hw->bus.width <= ixgbe_bus_width_pcie_x4) && 3210758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_2500))) { 3211758cc3dcSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 3212758cc3dcSJack F Vogel " for this card\n is not sufficient for" 3213758cc3dcSJack F Vogel " optimal performance.\n"); 3214758cc3dcSJack F Vogel device_printf(dev, "For optimal performance a x8 " 3215758cc3dcSJack F Vogel "PCIE, or x4 PCIE Gen2 slot is required.\n"); 3216758cc3dcSJack F Vogel } 3217758cc3dcSJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) && 3218758cc3dcSJack F Vogel ((hw->bus.width <= ixgbe_bus_width_pcie_x8) && 3219758cc3dcSJack F Vogel (hw->bus.speed < ixgbe_bus_speed_8000))) { 3220758cc3dcSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 3221758cc3dcSJack F Vogel " for this card\n is not sufficient for" 3222758cc3dcSJack F Vogel " optimal performance.\n"); 3223758cc3dcSJack F Vogel device_printf(dev, "For optimal performance a x8 " 3224758cc3dcSJack F Vogel "PCIE Gen3 slot is required.\n"); 3225758cc3dcSJack F Vogel } 3226758cc3dcSJack F Vogel 3227758cc3dcSJack F Vogel return; 3228758cc3dcSJack F Vogel } 3229758cc3dcSJack F Vogel 3230758cc3dcSJack F Vogel 3231758cc3dcSJack F Vogel /* 3232758cc3dcSJack F Vogel ** Setup the correct IVAR register for a particular MSIX interrupt 3233758cc3dcSJack F Vogel ** (yes this is all very magic and confusing :) 3234758cc3dcSJack F Vogel ** - entry is the register array entry 3235758cc3dcSJack F Vogel ** - vector is the MSIX vector for this queue 3236758cc3dcSJack F Vogel ** - type is RX/TX/MISC 3237758cc3dcSJack F Vogel */ 3238758cc3dcSJack F Vogel static void 3239758cc3dcSJack F Vogel ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) 3240758cc3dcSJack F Vogel { 3241758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3242758cc3dcSJack F Vogel u32 ivar, index; 3243758cc3dcSJack F Vogel 3244758cc3dcSJack F Vogel vector |= IXGBE_IVAR_ALLOC_VAL; 3245758cc3dcSJack F Vogel 3246758cc3dcSJack F Vogel switch (hw->mac.type) { 3247758cc3dcSJack F Vogel 3248758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 3249758cc3dcSJack F Vogel if (type == -1) 3250758cc3dcSJack F Vogel entry = IXGBE_IVAR_OTHER_CAUSES_INDEX; 3251758cc3dcSJack F Vogel else 3252758cc3dcSJack F Vogel entry += (type * 64); 3253758cc3dcSJack F Vogel index = (entry >> 2) & 0x1F; 3254758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 3255758cc3dcSJack F Vogel ivar &= ~(0xFF << (8 * (entry & 0x3))); 3256758cc3dcSJack F Vogel ivar |= (vector << (8 * (entry & 0x3))); 3257758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar); 3258758cc3dcSJack F Vogel break; 3259758cc3dcSJack F Vogel 3260758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 3261758cc3dcSJack F Vogel case ixgbe_mac_X540: 3262758cc3dcSJack F Vogel case ixgbe_mac_X550: 3263758cc3dcSJack F Vogel case ixgbe_mac_X550EM_a: 3264758cc3dcSJack F Vogel case ixgbe_mac_X550EM_x: 3265758cc3dcSJack F Vogel if (type == -1) { /* MISC IVAR */ 3266758cc3dcSJack F Vogel index = (entry & 1) * 8; 3267758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 3268758cc3dcSJack F Vogel ivar &= ~(0xFF << index); 3269758cc3dcSJack F Vogel ivar |= (vector << index); 3270758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 3271758cc3dcSJack F Vogel } else { /* RX/TX IVARS */ 3272758cc3dcSJack F Vogel index = (16 * (entry & 1)) + (8 * type); 3273758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1)); 3274758cc3dcSJack F Vogel ivar &= ~(0xFF << index); 3275758cc3dcSJack F Vogel ivar |= (vector << index); 3276758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar); 3277758cc3dcSJack F Vogel } 3278758cc3dcSJack F Vogel 3279758cc3dcSJack F Vogel default: 3280758cc3dcSJack F Vogel break; 3281758cc3dcSJack F Vogel } 3282758cc3dcSJack F Vogel } 3283758cc3dcSJack F Vogel 3284758cc3dcSJack F Vogel static void 3285758cc3dcSJack F Vogel ixgbe_configure_ivars(struct adapter *adapter) 3286758cc3dcSJack F Vogel { 3287758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 3288758cc3dcSJack F Vogel u32 newitr; 3289758cc3dcSJack F Vogel 3290758cc3dcSJack F Vogel if (ixgbe_max_interrupt_rate > 0) 3291758cc3dcSJack F Vogel newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8; 3292758cc3dcSJack F Vogel else 3293758cc3dcSJack F Vogel newitr = 0; 3294758cc3dcSJack F Vogel 3295758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 3296758cc3dcSJack F Vogel /* First the RX queue entry */ 3297758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, i, que->msix, 0); 3298758cc3dcSJack F Vogel /* ... and the TX */ 3299758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, i, que->msix, 1); 3300758cc3dcSJack F Vogel /* Set an Initial EITR value */ 3301758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, 3302758cc3dcSJack F Vogel IXGBE_EITR(que->msix), newitr); 3303758cc3dcSJack F Vogel } 3304758cc3dcSJack F Vogel 3305758cc3dcSJack F Vogel /* For the Link interrupt */ 3306758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 1, adapter->vector, -1); 3307758cc3dcSJack F Vogel } 3308758cc3dcSJack F Vogel 3309758cc3dcSJack F Vogel /* 3310758cc3dcSJack F Vogel ** ixgbe_sfp_probe - called in the local timer to 3311758cc3dcSJack F Vogel ** determine if a port had optics inserted. 3312758cc3dcSJack F Vogel */ 3313758cc3dcSJack F Vogel static bool ixgbe_sfp_probe(struct adapter *adapter) 3314758cc3dcSJack F Vogel { 3315758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3316758cc3dcSJack F Vogel device_t dev = adapter->dev; 3317758cc3dcSJack F Vogel bool result = FALSE; 3318758cc3dcSJack F Vogel 3319758cc3dcSJack F Vogel if ((hw->phy.type == ixgbe_phy_nl) && 3320758cc3dcSJack F Vogel (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { 3321758cc3dcSJack F Vogel s32 ret = hw->phy.ops.identify_sfp(hw); 3322758cc3dcSJack F Vogel if (ret) 3323758cc3dcSJack F Vogel goto out; 3324758cc3dcSJack F Vogel ret = hw->phy.ops.reset(hw); 3325758cc3dcSJack F Vogel if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3326758cc3dcSJack F Vogel device_printf(dev,"Unsupported SFP+ module detected!"); 3327758cc3dcSJack F Vogel printf(" Reload driver with supported module.\n"); 3328758cc3dcSJack F Vogel adapter->sfp_probe = FALSE; 3329758cc3dcSJack F Vogel goto out; 3330758cc3dcSJack F Vogel } else 3331758cc3dcSJack F Vogel device_printf(dev,"SFP+ module detected!\n"); 3332758cc3dcSJack F Vogel /* We now have supported optics */ 3333758cc3dcSJack F Vogel adapter->sfp_probe = FALSE; 3334758cc3dcSJack F Vogel /* Set the optics type so system reports correctly */ 3335758cc3dcSJack F Vogel ixgbe_setup_optics(adapter); 3336758cc3dcSJack F Vogel result = TRUE; 3337758cc3dcSJack F Vogel } 3338758cc3dcSJack F Vogel out: 3339758cc3dcSJack F Vogel return (result); 3340758cc3dcSJack F Vogel } 3341758cc3dcSJack F Vogel 3342758cc3dcSJack F Vogel /* 3343758cc3dcSJack F Vogel ** Tasklet handler for MSIX Link interrupts 3344758cc3dcSJack F Vogel ** - do outside interrupt since it might sleep 3345758cc3dcSJack F Vogel */ 3346758cc3dcSJack F Vogel static void 3347758cc3dcSJack F Vogel ixgbe_handle_link(void *context, int pending) 3348758cc3dcSJack F Vogel { 3349758cc3dcSJack F Vogel struct adapter *adapter = context; 3350758cc3dcSJack F Vogel 3351758cc3dcSJack F Vogel ixgbe_check_link(&adapter->hw, 3352758cc3dcSJack F Vogel &adapter->link_speed, &adapter->link_up, 0); 3353758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 3354758cc3dcSJack F Vogel } 3355758cc3dcSJack F Vogel 3356758cc3dcSJack F Vogel /* 3357758cc3dcSJack F Vogel ** Tasklet for handling SFP module interrupts 3358758cc3dcSJack F Vogel */ 3359758cc3dcSJack F Vogel static void 3360758cc3dcSJack F Vogel ixgbe_handle_mod(void *context, int pending) 3361758cc3dcSJack F Vogel { 3362758cc3dcSJack F Vogel struct adapter *adapter = context; 3363758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3364758cc3dcSJack F Vogel device_t dev = adapter->dev; 3365758cc3dcSJack F Vogel u32 err; 3366758cc3dcSJack F Vogel 3367758cc3dcSJack F Vogel err = hw->phy.ops.identify_sfp(hw); 3368758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3369758cc3dcSJack F Vogel device_printf(dev, 3370758cc3dcSJack F Vogel "Unsupported SFP+ module type was detected.\n"); 3371758cc3dcSJack F Vogel return; 3372758cc3dcSJack F Vogel } 3373758cc3dcSJack F Vogel err = hw->mac.ops.setup_sfp(hw); 3374758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3375758cc3dcSJack F Vogel device_printf(dev, 3376758cc3dcSJack F Vogel "Setup failure - unsupported SFP+ module type.\n"); 3377758cc3dcSJack F Vogel return; 3378758cc3dcSJack F Vogel } 3379758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 3380758cc3dcSJack F Vogel return; 3381758cc3dcSJack F Vogel } 3382758cc3dcSJack F Vogel 3383758cc3dcSJack F Vogel 3384758cc3dcSJack F Vogel /* 3385758cc3dcSJack F Vogel ** Tasklet for handling MSF (multispeed fiber) interrupts 3386758cc3dcSJack F Vogel */ 3387758cc3dcSJack F Vogel static void 3388758cc3dcSJack F Vogel ixgbe_handle_msf(void *context, int pending) 3389758cc3dcSJack F Vogel { 3390758cc3dcSJack F Vogel struct adapter *adapter = context; 3391758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3392758cc3dcSJack F Vogel u32 autoneg; 3393758cc3dcSJack F Vogel bool negotiate; 3394758cc3dcSJack F Vogel int err; 3395758cc3dcSJack F Vogel 3396758cc3dcSJack F Vogel err = hw->phy.ops.identify_sfp(hw); 3397758cc3dcSJack F Vogel if (!err) { 3398758cc3dcSJack F Vogel ixgbe_setup_optics(adapter); 3399758cc3dcSJack F Vogel INIT_DEBUGOUT1("ixgbe_sfp_probe: flags: %X\n", adapter->optics); 3400758cc3dcSJack F Vogel } 3401758cc3dcSJack F Vogel 3402758cc3dcSJack F Vogel autoneg = hw->phy.autoneg_advertised; 3403758cc3dcSJack F Vogel if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) 3404758cc3dcSJack F Vogel hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate); 3405758cc3dcSJack F Vogel if (hw->mac.ops.setup_link) 3406758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, autoneg, TRUE); 3407758cc3dcSJack F Vogel 3408758cc3dcSJack F Vogel ifmedia_removeall(&adapter->media); 3409758cc3dcSJack F Vogel ixgbe_add_media_types(adapter); 3410758cc3dcSJack F Vogel return; 3411758cc3dcSJack F Vogel } 3412758cc3dcSJack F Vogel 3413758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3414758cc3dcSJack F Vogel /* 3415758cc3dcSJack F Vogel ** Tasklet for reinitializing the Flow Director filter table 3416758cc3dcSJack F Vogel */ 3417758cc3dcSJack F Vogel static void 3418758cc3dcSJack F Vogel ixgbe_reinit_fdir(void *context, int pending) 3419758cc3dcSJack F Vogel { 3420758cc3dcSJack F Vogel struct adapter *adapter = context; 3421758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3422758cc3dcSJack F Vogel 3423758cc3dcSJack F Vogel if (adapter->fdir_reinit != 1) /* Shouldn't happen */ 3424758cc3dcSJack F Vogel return; 3425758cc3dcSJack F Vogel ixgbe_reinit_fdir_tables_82599(&adapter->hw); 3426758cc3dcSJack F Vogel adapter->fdir_reinit = 0; 3427758cc3dcSJack F Vogel /* re-enable flow director interrupts */ 3428758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); 3429758cc3dcSJack F Vogel /* Restart the interface */ 3430758cc3dcSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 3431758cc3dcSJack F Vogel return; 3432758cc3dcSJack F Vogel } 3433758cc3dcSJack F Vogel #endif 3434758cc3dcSJack F Vogel 3435758cc3dcSJack F Vogel /********************************************************************** 3436758cc3dcSJack F Vogel * 3437758cc3dcSJack F Vogel * Update the board statistics counters. 3438758cc3dcSJack F Vogel * 3439758cc3dcSJack F Vogel **********************************************************************/ 3440758cc3dcSJack F Vogel static void 3441758cc3dcSJack F Vogel ixgbe_update_stats_counters(struct adapter *adapter) 3442758cc3dcSJack F Vogel { 3443758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3444758cc3dcSJack F Vogel u32 missed_rx = 0, bprc, lxon, lxoff, total; 3445758cc3dcSJack F Vogel u64 total_missed_rx = 0; 3446758cc3dcSJack F Vogel 3447758cc3dcSJack F Vogel adapter->stats.pf.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); 3448758cc3dcSJack F Vogel adapter->stats.pf.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC); 3449758cc3dcSJack F Vogel adapter->stats.pf.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC); 3450758cc3dcSJack F Vogel adapter->stats.pf.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC); 3451758cc3dcSJack F Vogel 3452758cc3dcSJack F Vogel /* 3453758cc3dcSJack F Vogel ** Note: these are for the 8 possible traffic classes, 3454758cc3dcSJack F Vogel ** which in current implementation is unused, 3455758cc3dcSJack F Vogel ** therefore only 0 should read real data. 3456758cc3dcSJack F Vogel */ 3457758cc3dcSJack F Vogel for (int i = 0; i < 8; i++) { 3458758cc3dcSJack F Vogel u32 mp; 3459758cc3dcSJack F Vogel mp = IXGBE_READ_REG(hw, IXGBE_MPC(i)); 3460758cc3dcSJack F Vogel /* missed_rx tallies misses for the gprc workaround */ 3461758cc3dcSJack F Vogel missed_rx += mp; 3462758cc3dcSJack F Vogel /* global total per queue */ 3463758cc3dcSJack F Vogel adapter->stats.pf.mpc[i] += mp; 3464758cc3dcSJack F Vogel /* total for stats display */ 3465758cc3dcSJack F Vogel total_missed_rx += adapter->stats.pf.mpc[i]; 3466758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 3467758cc3dcSJack F Vogel adapter->stats.pf.rnbc[i] += 3468758cc3dcSJack F Vogel IXGBE_READ_REG(hw, IXGBE_RNBC(i)); 3469758cc3dcSJack F Vogel adapter->stats.pf.qbtc[i] += 3470758cc3dcSJack F Vogel IXGBE_READ_REG(hw, IXGBE_QBTC(i)); 3471758cc3dcSJack F Vogel adapter->stats.pf.qbrc[i] += 3472758cc3dcSJack F Vogel IXGBE_READ_REG(hw, IXGBE_QBRC(i)); 3473758cc3dcSJack F Vogel adapter->stats.pf.pxonrxc[i] += 3474758cc3dcSJack F Vogel IXGBE_READ_REG(hw, IXGBE_PXONRXC(i)); 3475758cc3dcSJack F Vogel } else 3476758cc3dcSJack F Vogel adapter->stats.pf.pxonrxc[i] += 3477758cc3dcSJack F Vogel IXGBE_READ_REG(hw, IXGBE_PXONRXCNT(i)); 3478758cc3dcSJack F Vogel adapter->stats.pf.pxontxc[i] += 3479758cc3dcSJack F Vogel IXGBE_READ_REG(hw, IXGBE_PXONTXC(i)); 3480758cc3dcSJack F Vogel adapter->stats.pf.pxofftxc[i] += 3481758cc3dcSJack F Vogel IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i)); 3482758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_X550EM_x) 3483758cc3dcSJack F Vogel adapter->stats.pf.pxoffrxc[i] += 3484758cc3dcSJack F Vogel IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i)); 3485758cc3dcSJack F Vogel adapter->stats.pf.pxon2offc[i] += 3486758cc3dcSJack F Vogel IXGBE_READ_REG(hw, IXGBE_PXON2OFFCNT(i)); 3487758cc3dcSJack F Vogel } 3488758cc3dcSJack F Vogel for (int i = 0; i < 16; i++) { 3489758cc3dcSJack F Vogel adapter->stats.pf.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); 3490758cc3dcSJack F Vogel adapter->stats.pf.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); 3491758cc3dcSJack F Vogel adapter->stats.pf.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); 3492758cc3dcSJack F Vogel } 3493758cc3dcSJack F Vogel adapter->stats.pf.mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC); 3494758cc3dcSJack F Vogel adapter->stats.pf.mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC); 3495758cc3dcSJack F Vogel adapter->stats.pf.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); 3496758cc3dcSJack F Vogel 3497758cc3dcSJack F Vogel /* Hardware workaround, gprc counts missed packets */ 3498758cc3dcSJack F Vogel adapter->stats.pf.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); 3499758cc3dcSJack F Vogel adapter->stats.pf.gprc -= missed_rx; 3500758cc3dcSJack F Vogel 3501758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 3502758cc3dcSJack F Vogel adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) + 3503758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); 3504758cc3dcSJack F Vogel adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) + 3505758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); 3506758cc3dcSJack F Vogel adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORL) + 3507758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); 3508758cc3dcSJack F Vogel adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); 3509758cc3dcSJack F Vogel adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); 3510758cc3dcSJack F Vogel } else { 3511758cc3dcSJack F Vogel adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); 3512758cc3dcSJack F Vogel adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); 3513758cc3dcSJack F Vogel /* 82598 only has a counter in the high register */ 3514758cc3dcSJack F Vogel adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); 3515758cc3dcSJack F Vogel adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); 3516758cc3dcSJack F Vogel adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORH); 3517758cc3dcSJack F Vogel } 3518758cc3dcSJack F Vogel 3519758cc3dcSJack F Vogel /* 3520758cc3dcSJack F Vogel * Workaround: mprc hardware is incorrectly counting 3521758cc3dcSJack F Vogel * broadcasts, so for now we subtract those. 3522758cc3dcSJack F Vogel */ 3523758cc3dcSJack F Vogel bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); 3524758cc3dcSJack F Vogel adapter->stats.pf.bprc += bprc; 3525758cc3dcSJack F Vogel adapter->stats.pf.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); 3526758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 3527758cc3dcSJack F Vogel adapter->stats.pf.mprc -= bprc; 3528758cc3dcSJack F Vogel 3529758cc3dcSJack F Vogel adapter->stats.pf.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); 3530758cc3dcSJack F Vogel adapter->stats.pf.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); 3531758cc3dcSJack F Vogel adapter->stats.pf.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); 3532758cc3dcSJack F Vogel adapter->stats.pf.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); 3533758cc3dcSJack F Vogel adapter->stats.pf.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); 3534758cc3dcSJack F Vogel adapter->stats.pf.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); 3535758cc3dcSJack F Vogel 3536758cc3dcSJack F Vogel lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); 3537758cc3dcSJack F Vogel adapter->stats.pf.lxontxc += lxon; 3538758cc3dcSJack F Vogel lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); 3539758cc3dcSJack F Vogel adapter->stats.pf.lxofftxc += lxoff; 3540758cc3dcSJack F Vogel total = lxon + lxoff; 3541758cc3dcSJack F Vogel 3542758cc3dcSJack F Vogel adapter->stats.pf.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); 3543758cc3dcSJack F Vogel adapter->stats.pf.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); 3544758cc3dcSJack F Vogel adapter->stats.pf.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); 3545758cc3dcSJack F Vogel adapter->stats.pf.gptc -= total; 3546758cc3dcSJack F Vogel adapter->stats.pf.mptc -= total; 3547758cc3dcSJack F Vogel adapter->stats.pf.ptc64 -= total; 3548758cc3dcSJack F Vogel adapter->stats.pf.gotc -= total * ETHER_MIN_LEN; 3549758cc3dcSJack F Vogel 3550758cc3dcSJack F Vogel adapter->stats.pf.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); 3551758cc3dcSJack F Vogel adapter->stats.pf.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); 3552758cc3dcSJack F Vogel adapter->stats.pf.roc += IXGBE_READ_REG(hw, IXGBE_ROC); 3553758cc3dcSJack F Vogel adapter->stats.pf.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); 3554758cc3dcSJack F Vogel adapter->stats.pf.mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC); 3555758cc3dcSJack F Vogel adapter->stats.pf.mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC); 3556758cc3dcSJack F Vogel adapter->stats.pf.mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC); 3557758cc3dcSJack F Vogel adapter->stats.pf.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); 3558758cc3dcSJack F Vogel adapter->stats.pf.tpt += IXGBE_READ_REG(hw, IXGBE_TPT); 3559758cc3dcSJack F Vogel adapter->stats.pf.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); 3560758cc3dcSJack F Vogel adapter->stats.pf.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); 3561758cc3dcSJack F Vogel adapter->stats.pf.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); 3562758cc3dcSJack F Vogel adapter->stats.pf.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); 3563758cc3dcSJack F Vogel adapter->stats.pf.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); 3564758cc3dcSJack F Vogel adapter->stats.pf.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); 3565758cc3dcSJack F Vogel adapter->stats.pf.xec += IXGBE_READ_REG(hw, IXGBE_XEC); 3566758cc3dcSJack F Vogel adapter->stats.pf.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); 3567758cc3dcSJack F Vogel adapter->stats.pf.fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST); 3568758cc3dcSJack F Vogel /* Only read FCOE on 82599 */ 3569758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 3570758cc3dcSJack F Vogel adapter->stats.pf.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); 3571758cc3dcSJack F Vogel adapter->stats.pf.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); 3572758cc3dcSJack F Vogel adapter->stats.pf.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); 3573758cc3dcSJack F Vogel adapter->stats.pf.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); 3574758cc3dcSJack F Vogel adapter->stats.pf.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); 3575758cc3dcSJack F Vogel } 3576758cc3dcSJack F Vogel 3577758cc3dcSJack F Vogel /* Fill out the OS statistics structure */ 3578758cc3dcSJack F Vogel IXGBE_SET_IPACKETS(adapter, adapter->stats.pf.gprc); 3579758cc3dcSJack F Vogel IXGBE_SET_OPACKETS(adapter, adapter->stats.pf.gptc); 3580758cc3dcSJack F Vogel IXGBE_SET_IBYTES(adapter, adapter->stats.pf.gorc); 3581758cc3dcSJack F Vogel IXGBE_SET_OBYTES(adapter, adapter->stats.pf.gotc); 3582758cc3dcSJack F Vogel IXGBE_SET_IMCASTS(adapter, adapter->stats.pf.mprc); 3583758cc3dcSJack F Vogel IXGBE_SET_OMCASTS(adapter, adapter->stats.pf.mptc); 3584758cc3dcSJack F Vogel IXGBE_SET_COLLISIONS(adapter, 0); 3585758cc3dcSJack F Vogel IXGBE_SET_IQDROPS(adapter, total_missed_rx); 3586758cc3dcSJack F Vogel IXGBE_SET_IERRORS(adapter, adapter->stats.pf.crcerrs 3587758cc3dcSJack F Vogel + adapter->stats.pf.rlec); 3588758cc3dcSJack F Vogel } 3589758cc3dcSJack F Vogel 3590758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 3591758cc3dcSJack F Vogel static uint64_t 3592758cc3dcSJack F Vogel ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt) 3593758cc3dcSJack F Vogel { 3594758cc3dcSJack F Vogel struct adapter *adapter; 3595*625d12c6SJohn Baldwin struct tx_ring *txr; 3596*625d12c6SJohn Baldwin uint64_t rv; 3597758cc3dcSJack F Vogel 3598758cc3dcSJack F Vogel adapter = if_getsoftc(ifp); 3599758cc3dcSJack F Vogel 3600758cc3dcSJack F Vogel switch (cnt) { 3601758cc3dcSJack F Vogel case IFCOUNTER_IPACKETS: 3602758cc3dcSJack F Vogel return (adapter->ipackets); 3603758cc3dcSJack F Vogel case IFCOUNTER_OPACKETS: 3604758cc3dcSJack F Vogel return (adapter->opackets); 3605758cc3dcSJack F Vogel case IFCOUNTER_IBYTES: 3606758cc3dcSJack F Vogel return (adapter->ibytes); 3607758cc3dcSJack F Vogel case IFCOUNTER_OBYTES: 3608758cc3dcSJack F Vogel return (adapter->obytes); 3609758cc3dcSJack F Vogel case IFCOUNTER_IMCASTS: 3610758cc3dcSJack F Vogel return (adapter->imcasts); 3611758cc3dcSJack F Vogel case IFCOUNTER_OMCASTS: 3612758cc3dcSJack F Vogel return (adapter->omcasts); 3613758cc3dcSJack F Vogel case IFCOUNTER_COLLISIONS: 3614758cc3dcSJack F Vogel return (0); 3615758cc3dcSJack F Vogel case IFCOUNTER_IQDROPS: 3616758cc3dcSJack F Vogel return (adapter->iqdrops); 3617*625d12c6SJohn Baldwin case IFCOUNTER_OQDROPS: 3618*625d12c6SJohn Baldwin rv = 0; 3619*625d12c6SJohn Baldwin txr = adapter->tx_rings; 3620*625d12c6SJohn Baldwin for (int i = 0; i < adapter->num_queues; i++, txr++) 3621*625d12c6SJohn Baldwin rv += txr->br->br_drops; 3622*625d12c6SJohn Baldwin return (rv); 3623758cc3dcSJack F Vogel case IFCOUNTER_IERRORS: 3624758cc3dcSJack F Vogel return (adapter->ierrors); 3625758cc3dcSJack F Vogel default: 3626758cc3dcSJack F Vogel return (if_get_counter_default(ifp, cnt)); 3627758cc3dcSJack F Vogel } 3628758cc3dcSJack F Vogel } 3629758cc3dcSJack F Vogel #endif 3630758cc3dcSJack F Vogel 3631758cc3dcSJack F Vogel /** ixgbe_sysctl_tdh_handler - Handler function 3632758cc3dcSJack F Vogel * Retrieves the TDH value from the hardware 3633758cc3dcSJack F Vogel */ 3634758cc3dcSJack F Vogel static int 3635758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS) 3636758cc3dcSJack F Vogel { 3637758cc3dcSJack F Vogel int error; 3638758cc3dcSJack F Vogel 3639758cc3dcSJack F Vogel struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); 3640758cc3dcSJack F Vogel if (!txr) return 0; 3641758cc3dcSJack F Vogel 3642758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me)); 3643758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 3644758cc3dcSJack F Vogel if (error || !req->newptr) 3645758cc3dcSJack F Vogel return error; 3646758cc3dcSJack F Vogel return 0; 3647758cc3dcSJack F Vogel } 3648758cc3dcSJack F Vogel 3649758cc3dcSJack F Vogel /** ixgbe_sysctl_tdt_handler - Handler function 3650758cc3dcSJack F Vogel * Retrieves the TDT value from the hardware 3651758cc3dcSJack F Vogel */ 3652758cc3dcSJack F Vogel static int 3653758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS) 3654758cc3dcSJack F Vogel { 3655758cc3dcSJack F Vogel int error; 3656758cc3dcSJack F Vogel 3657758cc3dcSJack F Vogel struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); 3658758cc3dcSJack F Vogel if (!txr) return 0; 3659758cc3dcSJack F Vogel 3660758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me)); 3661758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 3662758cc3dcSJack F Vogel if (error || !req->newptr) 3663758cc3dcSJack F Vogel return error; 3664758cc3dcSJack F Vogel return 0; 3665758cc3dcSJack F Vogel } 3666758cc3dcSJack F Vogel 3667758cc3dcSJack F Vogel /** ixgbe_sysctl_rdh_handler - Handler function 3668758cc3dcSJack F Vogel * Retrieves the RDH value from the hardware 3669758cc3dcSJack F Vogel */ 3670758cc3dcSJack F Vogel static int 3671758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS) 3672758cc3dcSJack F Vogel { 3673758cc3dcSJack F Vogel int error; 3674758cc3dcSJack F Vogel 3675758cc3dcSJack F Vogel struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); 3676758cc3dcSJack F Vogel if (!rxr) return 0; 3677758cc3dcSJack F Vogel 3678758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me)); 3679758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 3680758cc3dcSJack F Vogel if (error || !req->newptr) 3681758cc3dcSJack F Vogel return error; 3682758cc3dcSJack F Vogel return 0; 3683758cc3dcSJack F Vogel } 3684758cc3dcSJack F Vogel 3685758cc3dcSJack F Vogel /** ixgbe_sysctl_rdt_handler - Handler function 3686758cc3dcSJack F Vogel * Retrieves the RDT value from the hardware 3687758cc3dcSJack F Vogel */ 3688758cc3dcSJack F Vogel static int 3689758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) 3690758cc3dcSJack F Vogel { 3691758cc3dcSJack F Vogel int error; 3692758cc3dcSJack F Vogel 3693758cc3dcSJack F Vogel struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); 3694758cc3dcSJack F Vogel if (!rxr) return 0; 3695758cc3dcSJack F Vogel 3696758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me)); 3697758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 3698758cc3dcSJack F Vogel if (error || !req->newptr) 3699758cc3dcSJack F Vogel return error; 3700758cc3dcSJack F Vogel return 0; 3701758cc3dcSJack F Vogel } 3702758cc3dcSJack F Vogel 3703758cc3dcSJack F Vogel static int 3704758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS) 3705758cc3dcSJack F Vogel { 3706758cc3dcSJack F Vogel int error; 3707758cc3dcSJack F Vogel struct ix_queue *que = ((struct ix_queue *)oidp->oid_arg1); 3708758cc3dcSJack F Vogel unsigned int reg, usec, rate; 3709758cc3dcSJack F Vogel 3710758cc3dcSJack F Vogel reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix)); 3711758cc3dcSJack F Vogel usec = ((reg & 0x0FF8) >> 3); 3712758cc3dcSJack F Vogel if (usec > 0) 3713758cc3dcSJack F Vogel rate = 500000 / usec; 3714758cc3dcSJack F Vogel else 3715758cc3dcSJack F Vogel rate = 0; 3716758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &rate, 0, req); 3717758cc3dcSJack F Vogel if (error || !req->newptr) 3718758cc3dcSJack F Vogel return error; 3719758cc3dcSJack F Vogel reg &= ~0xfff; /* default, no limitation */ 3720758cc3dcSJack F Vogel ixgbe_max_interrupt_rate = 0; 3721758cc3dcSJack F Vogel if (rate > 0 && rate < 500000) { 3722758cc3dcSJack F Vogel if (rate < 1000) 3723758cc3dcSJack F Vogel rate = 1000; 3724758cc3dcSJack F Vogel ixgbe_max_interrupt_rate = rate; 3725758cc3dcSJack F Vogel reg |= ((4000000/rate) & 0xff8 ); 3726758cc3dcSJack F Vogel } 3727758cc3dcSJack F Vogel IXGBE_WRITE_REG(&que->adapter->hw, IXGBE_EITR(que->msix), reg); 3728758cc3dcSJack F Vogel return 0; 3729758cc3dcSJack F Vogel } 3730758cc3dcSJack F Vogel 3731758cc3dcSJack F Vogel /* 3732758cc3dcSJack F Vogel * Add sysctl variables, one per statistic, to the system. 3733758cc3dcSJack F Vogel */ 3734758cc3dcSJack F Vogel static void 3735758cc3dcSJack F Vogel ixgbe_add_hw_stats(struct adapter *adapter) 3736758cc3dcSJack F Vogel { 3737758cc3dcSJack F Vogel device_t dev = adapter->dev; 3738758cc3dcSJack F Vogel 3739758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 3740758cc3dcSJack F Vogel struct rx_ring *rxr = adapter->rx_rings; 3741758cc3dcSJack F Vogel 3742758cc3dcSJack F Vogel struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 3743758cc3dcSJack F Vogel struct sysctl_oid *tree = device_get_sysctl_tree(dev); 3744758cc3dcSJack F Vogel struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 3745758cc3dcSJack F Vogel struct ixgbe_hw_stats *stats = &adapter->stats.pf; 3746758cc3dcSJack F Vogel 3747758cc3dcSJack F Vogel struct sysctl_oid *stat_node, *queue_node; 3748758cc3dcSJack F Vogel struct sysctl_oid_list *stat_list, *queue_list; 3749758cc3dcSJack F Vogel 3750758cc3dcSJack F Vogel #define QUEUE_NAME_LEN 32 3751758cc3dcSJack F Vogel char namebuf[QUEUE_NAME_LEN]; 3752758cc3dcSJack F Vogel 3753758cc3dcSJack F Vogel /* Driver Statistics */ 3754758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", 3755758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->dropped_pkts, 3756758cc3dcSJack F Vogel "Driver dropped packets"); 3757758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", 3758758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->mbuf_defrag_failed, 3759758cc3dcSJack F Vogel "m_defrag() failed"); 3760758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 3761758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->watchdog_events, 3762758cc3dcSJack F Vogel "Watchdog timeouts"); 3763758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", 3764758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->vector_irq, 3765758cc3dcSJack F Vogel "Link MSIX IRQ Handled"); 3766758cc3dcSJack F Vogel 3767758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, txr++) { 3768758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 3769758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 3770758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 3771758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 3772758cc3dcSJack F Vogel 3773758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate", 3774758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RW, &adapter->queues[i], 3775758cc3dcSJack F Vogel sizeof(&adapter->queues[i]), 3776758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler, "IU", 3777758cc3dcSJack F Vogel "Interrupt Rate"); 3778758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 3779758cc3dcSJack F Vogel CTLFLAG_RD, &(adapter->queues[i].irqs), 3780758cc3dcSJack F Vogel "irqs on this queue"); 3781758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", 3782758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), 3783758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler, "IU", 3784758cc3dcSJack F Vogel "Transmit Descriptor Head"); 3785758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", 3786758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), 3787758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler, "IU", 3788758cc3dcSJack F Vogel "Transmit Descriptor Tail"); 3789758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx", 3790758cc3dcSJack F Vogel CTLFLAG_RD, &txr->tso_tx, 3791758cc3dcSJack F Vogel "TSO"); 3792758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_tx_dma_setup", 3793758cc3dcSJack F Vogel CTLFLAG_RD, &txr->no_tx_dma_setup, 3794758cc3dcSJack F Vogel "Driver tx dma failure in xmit"); 3795758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 3796758cc3dcSJack F Vogel CTLFLAG_RD, &txr->no_desc_avail, 3797758cc3dcSJack F Vogel "Queue No Descriptor Available"); 3798758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 3799758cc3dcSJack F Vogel CTLFLAG_RD, &txr->total_packets, 3800758cc3dcSJack F Vogel "Queue Packets Transmitted"); 3801*625d12c6SJohn Baldwin SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops", 3802*625d12c6SJohn Baldwin CTLFLAG_RD, &txr->br->br_drops, 3803*625d12c6SJohn Baldwin "Packets dropped in buf_ring"); 3804758cc3dcSJack F Vogel } 3805758cc3dcSJack F Vogel 3806758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, rxr++) { 3807758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 3808758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 3809758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 3810758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 3811758cc3dcSJack F Vogel 3812758cc3dcSJack F Vogel struct lro_ctrl *lro = &rxr->lro; 3813758cc3dcSJack F Vogel 3814758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 3815758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 3816758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 3817758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 3818758cc3dcSJack F Vogel 3819758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", 3820758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), 3821758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler, "IU", 3822758cc3dcSJack F Vogel "Receive Descriptor Head"); 3823758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", 3824758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), 3825758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler, "IU", 3826758cc3dcSJack F Vogel "Receive Descriptor Tail"); 3827758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 3828758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_packets, 3829758cc3dcSJack F Vogel "Queue Packets Received"); 3830758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 3831758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_bytes, 3832758cc3dcSJack F Vogel "Queue Bytes Received"); 3833758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies", 3834758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_copies, 3835758cc3dcSJack F Vogel "Copied RX Frames"); 3836758cc3dcSJack F Vogel SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_queued", 3837758cc3dcSJack F Vogel CTLFLAG_RD, &lro->lro_queued, 0, 3838758cc3dcSJack F Vogel "LRO Queued"); 3839758cc3dcSJack F Vogel SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_flushed", 3840758cc3dcSJack F Vogel CTLFLAG_RD, &lro->lro_flushed, 0, 3841758cc3dcSJack F Vogel "LRO Flushed"); 3842758cc3dcSJack F Vogel } 3843758cc3dcSJack F Vogel 3844758cc3dcSJack F Vogel /* MAC stats get the own sub node */ 3845758cc3dcSJack F Vogel 3846758cc3dcSJack F Vogel stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", 3847758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "MAC Statistics"); 3848758cc3dcSJack F Vogel stat_list = SYSCTL_CHILDREN(stat_node); 3849758cc3dcSJack F Vogel 3850758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs", 3851758cc3dcSJack F Vogel CTLFLAG_RD, &stats->crcerrs, 3852758cc3dcSJack F Vogel "CRC Errors"); 3853758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs", 3854758cc3dcSJack F Vogel CTLFLAG_RD, &stats->illerrc, 3855758cc3dcSJack F Vogel "Illegal Byte Errors"); 3856758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs", 3857758cc3dcSJack F Vogel CTLFLAG_RD, &stats->errbc, 3858758cc3dcSJack F Vogel "Byte Errors"); 3859758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards", 3860758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mspdc, 3861758cc3dcSJack F Vogel "MAC Short Packets Discarded"); 3862758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults", 3863758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mlfc, 3864758cc3dcSJack F Vogel "MAC Local Faults"); 3865758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults", 3866758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mrfc, 3867758cc3dcSJack F Vogel "MAC Remote Faults"); 3868758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs", 3869758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rlec, 3870758cc3dcSJack F Vogel "Receive Length Errors"); 3871758cc3dcSJack F Vogel 3872758cc3dcSJack F Vogel /* Flow Control stats */ 3873758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd", 3874758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxontxc, 3875758cc3dcSJack F Vogel "Link XON Transmitted"); 3876758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd", 3877758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxonrxc, 3878758cc3dcSJack F Vogel "Link XON Received"); 3879758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd", 3880758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxofftxc, 3881758cc3dcSJack F Vogel "Link XOFF Transmitted"); 3882758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd", 3883758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxoffrxc, 3884758cc3dcSJack F Vogel "Link XOFF Received"); 3885758cc3dcSJack F Vogel 3886758cc3dcSJack F Vogel /* Packet Reception Stats */ 3887758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd", 3888758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tor, 3889758cc3dcSJack F Vogel "Total Octets Received"); 3890758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", 3891758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gorc, 3892758cc3dcSJack F Vogel "Good Octets Received"); 3893758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd", 3894758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tpr, 3895758cc3dcSJack F Vogel "Total Packets Received"); 3896758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", 3897758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gprc, 3898758cc3dcSJack F Vogel "Good Packets Received"); 3899758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", 3900758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mprc, 3901758cc3dcSJack F Vogel "Multicast Packets Received"); 3902758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", 3903758cc3dcSJack F Vogel CTLFLAG_RD, &stats->bprc, 3904758cc3dcSJack F Vogel "Broadcast Packets Received"); 3905758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", 3906758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc64, 3907758cc3dcSJack F Vogel "64 byte frames received "); 3908758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", 3909758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc127, 3910758cc3dcSJack F Vogel "65-127 byte frames received"); 3911758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", 3912758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc255, 3913758cc3dcSJack F Vogel "128-255 byte frames received"); 3914758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", 3915758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc511, 3916758cc3dcSJack F Vogel "256-511 byte frames received"); 3917758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", 3918758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc1023, 3919758cc3dcSJack F Vogel "512-1023 byte frames received"); 3920758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", 3921758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc1522, 3922758cc3dcSJack F Vogel "1023-1522 byte frames received"); 3923758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized", 3924758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ruc, 3925758cc3dcSJack F Vogel "Receive Undersized"); 3926758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", 3927758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rfc, 3928758cc3dcSJack F Vogel "Fragmented Packets Received "); 3929758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized", 3930758cc3dcSJack F Vogel CTLFLAG_RD, &stats->roc, 3931758cc3dcSJack F Vogel "Oversized Packets Received"); 3932758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd", 3933758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rjc, 3934758cc3dcSJack F Vogel "Received Jabber"); 3935758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd", 3936758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngprc, 3937758cc3dcSJack F Vogel "Management Packets Received"); 3938758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd", 3939758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngptc, 3940758cc3dcSJack F Vogel "Management Packets Dropped"); 3941758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs", 3942758cc3dcSJack F Vogel CTLFLAG_RD, &stats->xec, 3943758cc3dcSJack F Vogel "Checksum Errors"); 3944758cc3dcSJack F Vogel 3945758cc3dcSJack F Vogel /* Packet Transmission Stats */ 3946758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", 3947758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gotc, 3948758cc3dcSJack F Vogel "Good Octets Transmitted"); 3949758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", 3950758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tpt, 3951758cc3dcSJack F Vogel "Total Packets Transmitted"); 3952758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", 3953758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gptc, 3954758cc3dcSJack F Vogel "Good Packets Transmitted"); 3955758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", 3956758cc3dcSJack F Vogel CTLFLAG_RD, &stats->bptc, 3957758cc3dcSJack F Vogel "Broadcast Packets Transmitted"); 3958758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", 3959758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mptc, 3960758cc3dcSJack F Vogel "Multicast Packets Transmitted"); 3961758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd", 3962758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngptc, 3963758cc3dcSJack F Vogel "Management Packets Transmitted"); 3964758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", 3965758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc64, 3966758cc3dcSJack F Vogel "64 byte frames transmitted "); 3967758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", 3968758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc127, 3969758cc3dcSJack F Vogel "65-127 byte frames transmitted"); 3970758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", 3971758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc255, 3972758cc3dcSJack F Vogel "128-255 byte frames transmitted"); 3973758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", 3974758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc511, 3975758cc3dcSJack F Vogel "256-511 byte frames transmitted"); 3976758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", 3977758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc1023, 3978758cc3dcSJack F Vogel "512-1023 byte frames transmitted"); 3979758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", 3980758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc1522, 3981758cc3dcSJack F Vogel "1024-1522 byte frames transmitted"); 3982758cc3dcSJack F Vogel } 3983758cc3dcSJack F Vogel 3984758cc3dcSJack F Vogel /* 3985758cc3dcSJack F Vogel ** Set flow control using sysctl: 3986758cc3dcSJack F Vogel ** Flow control values: 3987758cc3dcSJack F Vogel ** 0 - off 3988758cc3dcSJack F Vogel ** 1 - rx pause 3989758cc3dcSJack F Vogel ** 2 - tx pause 3990758cc3dcSJack F Vogel ** 3 - full 3991758cc3dcSJack F Vogel */ 3992758cc3dcSJack F Vogel static int 3993758cc3dcSJack F Vogel ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS) 3994758cc3dcSJack F Vogel { 3995758cc3dcSJack F Vogel int error, last; 3996758cc3dcSJack F Vogel struct adapter *adapter = (struct adapter *) arg1; 3997758cc3dcSJack F Vogel 3998758cc3dcSJack F Vogel last = adapter->fc; 3999758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &adapter->fc, 0, req); 4000758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4001758cc3dcSJack F Vogel return (error); 4002758cc3dcSJack F Vogel 4003758cc3dcSJack F Vogel /* Don't bother if it's not changed */ 4004758cc3dcSJack F Vogel if (adapter->fc == last) 4005758cc3dcSJack F Vogel return (0); 4006758cc3dcSJack F Vogel 4007758cc3dcSJack F Vogel switch (adapter->fc) { 4008758cc3dcSJack F Vogel case ixgbe_fc_rx_pause: 4009758cc3dcSJack F Vogel case ixgbe_fc_tx_pause: 4010758cc3dcSJack F Vogel case ixgbe_fc_full: 4011758cc3dcSJack F Vogel adapter->hw.fc.requested_mode = adapter->fc; 4012758cc3dcSJack F Vogel if (adapter->num_queues > 1) 4013758cc3dcSJack F Vogel ixgbe_disable_rx_drop(adapter); 4014758cc3dcSJack F Vogel break; 4015758cc3dcSJack F Vogel case ixgbe_fc_none: 4016758cc3dcSJack F Vogel adapter->hw.fc.requested_mode = ixgbe_fc_none; 4017758cc3dcSJack F Vogel if (adapter->num_queues > 1) 4018758cc3dcSJack F Vogel ixgbe_enable_rx_drop(adapter); 4019758cc3dcSJack F Vogel break; 4020758cc3dcSJack F Vogel default: 4021758cc3dcSJack F Vogel adapter->fc = last; 4022758cc3dcSJack F Vogel return (EINVAL); 4023758cc3dcSJack F Vogel } 4024758cc3dcSJack F Vogel /* Don't autoneg if forcing a value */ 4025758cc3dcSJack F Vogel adapter->hw.fc.disable_fc_autoneg = TRUE; 4026758cc3dcSJack F Vogel ixgbe_fc_enable(&adapter->hw); 4027758cc3dcSJack F Vogel return error; 4028758cc3dcSJack F Vogel } 4029758cc3dcSJack F Vogel 4030758cc3dcSJack F Vogel /* 4031758cc3dcSJack F Vogel ** Control advertised link speed: 4032758cc3dcSJack F Vogel ** Flags: 4033758cc3dcSJack F Vogel ** 0x1 - advertise 100 Mb 4034758cc3dcSJack F Vogel ** 0x2 - advertise 1G 4035758cc3dcSJack F Vogel ** 0x4 - advertise 10G 4036758cc3dcSJack F Vogel */ 4037758cc3dcSJack F Vogel static int 4038758cc3dcSJack F Vogel ixgbe_set_advertise(SYSCTL_HANDLER_ARGS) 4039758cc3dcSJack F Vogel { 4040758cc3dcSJack F Vogel int error = 0, requested; 4041758cc3dcSJack F Vogel struct adapter *adapter; 4042758cc3dcSJack F Vogel device_t dev; 4043758cc3dcSJack F Vogel struct ixgbe_hw *hw; 4044758cc3dcSJack F Vogel ixgbe_link_speed speed = 0; 4045758cc3dcSJack F Vogel 4046758cc3dcSJack F Vogel adapter = (struct adapter *) arg1; 4047758cc3dcSJack F Vogel dev = adapter->dev; 4048758cc3dcSJack F Vogel hw = &adapter->hw; 4049758cc3dcSJack F Vogel 4050758cc3dcSJack F Vogel requested = adapter->advertise; 4051758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &requested, 0, req); 4052758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4053758cc3dcSJack F Vogel return (error); 4054758cc3dcSJack F Vogel 4055758cc3dcSJack F Vogel /* Checks to validate new value */ 4056758cc3dcSJack F Vogel if (adapter->advertise == requested) /* no change */ 4057758cc3dcSJack F Vogel return (0); 4058758cc3dcSJack F Vogel 4059758cc3dcSJack F Vogel if (!((hw->phy.media_type == ixgbe_media_type_copper) || 4060758cc3dcSJack F Vogel (hw->phy.multispeed_fiber))) { 4061758cc3dcSJack F Vogel device_printf(dev, 4062758cc3dcSJack F Vogel "Advertised speed can only be set on copper or " 4063758cc3dcSJack F Vogel "multispeed fiber media types.\n"); 4064758cc3dcSJack F Vogel return (EINVAL); 4065758cc3dcSJack F Vogel } 4066758cc3dcSJack F Vogel 4067758cc3dcSJack F Vogel if (requested < 0x1 || requested > 0x7) { 4068758cc3dcSJack F Vogel device_printf(dev, 4069758cc3dcSJack F Vogel "Invalid advertised speed; valid modes are 0x1 through 0x7\n"); 4070758cc3dcSJack F Vogel return (EINVAL); 4071758cc3dcSJack F Vogel } 4072758cc3dcSJack F Vogel 4073758cc3dcSJack F Vogel if ((requested & 0x1) 4074758cc3dcSJack F Vogel && (hw->mac.type != ixgbe_mac_X540) 4075758cc3dcSJack F Vogel && (hw->mac.type != ixgbe_mac_X550)) { 4076758cc3dcSJack F Vogel device_printf(dev, "Set Advertise: 100Mb on X540/X550 only\n"); 4077758cc3dcSJack F Vogel return (EINVAL); 4078758cc3dcSJack F Vogel } 4079758cc3dcSJack F Vogel 4080758cc3dcSJack F Vogel /* Set new value and report new advertised mode */ 4081758cc3dcSJack F Vogel if (requested & 0x1) 4082758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 4083758cc3dcSJack F Vogel if (requested & 0x2) 4084758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 4085758cc3dcSJack F Vogel if (requested & 0x4) 4086758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_10GB_FULL; 4087758cc3dcSJack F Vogel 4088758cc3dcSJack F Vogel hw->mac.autotry_restart = TRUE; 4089758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, speed, TRUE); 4090758cc3dcSJack F Vogel adapter->advertise = requested; 4091758cc3dcSJack F Vogel 4092758cc3dcSJack F Vogel return (error); 4093758cc3dcSJack F Vogel } 4094758cc3dcSJack F Vogel 4095758cc3dcSJack F Vogel /* 4096758cc3dcSJack F Vogel ** Thermal Shutdown Trigger 4097758cc3dcSJack F Vogel ** - cause a Thermal Overtemp IRQ 4098758cc3dcSJack F Vogel ** - this now requires firmware enabling 4099758cc3dcSJack F Vogel */ 4100758cc3dcSJack F Vogel static int 4101758cc3dcSJack F Vogel ixgbe_set_thermal_test(SYSCTL_HANDLER_ARGS) 4102758cc3dcSJack F Vogel { 4103758cc3dcSJack F Vogel int error, fire = 0; 4104758cc3dcSJack F Vogel struct adapter *adapter = (struct adapter *) arg1; 4105758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 4106758cc3dcSJack F Vogel 4107758cc3dcSJack F Vogel 4108758cc3dcSJack F Vogel if (hw->mac.type < ixgbe_mac_X540) 4109758cc3dcSJack F Vogel return (0); 4110758cc3dcSJack F Vogel 4111758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &fire, 0, req); 4112758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4113758cc3dcSJack F Vogel return (error); 4114758cc3dcSJack F Vogel 4115758cc3dcSJack F Vogel if (fire) { 4116758cc3dcSJack F Vogel u32 reg = IXGBE_READ_REG(hw, IXGBE_EICS); 4117758cc3dcSJack F Vogel reg |= IXGBE_EICR_TS; 4118758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICS, reg); 4119758cc3dcSJack F Vogel } 4120758cc3dcSJack F Vogel 4121758cc3dcSJack F Vogel return (0); 4122758cc3dcSJack F Vogel } 4123758cc3dcSJack F Vogel 4124758cc3dcSJack F Vogel /* 4125758cc3dcSJack F Vogel ** Enable the hardware to drop packets when the buffer is 4126758cc3dcSJack F Vogel ** full. This is useful when multiqueue,so that no single 4127758cc3dcSJack F Vogel ** queue being full stalls the entire RX engine. We only 4128758cc3dcSJack F Vogel ** enable this when Multiqueue AND when Flow Control is 4129758cc3dcSJack F Vogel ** disabled. 4130758cc3dcSJack F Vogel */ 4131758cc3dcSJack F Vogel static void 4132758cc3dcSJack F Vogel ixgbe_enable_rx_drop(struct adapter *adapter) 4133758cc3dcSJack F Vogel { 4134758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 4135758cc3dcSJack F Vogel 4136758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 4137758cc3dcSJack F Vogel u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); 4138758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DROP_EN; 4139758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); 4140758cc3dcSJack F Vogel } 4141758cc3dcSJack F Vogel } 4142758cc3dcSJack F Vogel 4143758cc3dcSJack F Vogel static void 4144758cc3dcSJack F Vogel ixgbe_disable_rx_drop(struct adapter *adapter) 4145758cc3dcSJack F Vogel { 4146758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 4147758cc3dcSJack F Vogel 4148758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 4149758cc3dcSJack F Vogel u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); 4150758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_DROP_EN; 4151758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); 4152758cc3dcSJack F Vogel } 4153758cc3dcSJack F Vogel } 4154758cc3dcSJack F Vogel 4155758cc3dcSJack F Vogel static void 4156758cc3dcSJack F Vogel ixgbe_rearm_queues(struct adapter *adapter, u64 queues) 4157758cc3dcSJack F Vogel { 4158758cc3dcSJack F Vogel u32 mask; 4159758cc3dcSJack F Vogel 4160758cc3dcSJack F Vogel switch (adapter->hw.mac.type) { 4161758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 4162758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queues); 4163758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); 4164758cc3dcSJack F Vogel break; 4165758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 4166758cc3dcSJack F Vogel case ixgbe_mac_X540: 4167758cc3dcSJack F Vogel case ixgbe_mac_X550: 4168758cc3dcSJack F Vogel mask = (queues & 0xFFFFFFFF); 4169758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); 4170758cc3dcSJack F Vogel mask = (queues >> 32); 4171758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); 4172758cc3dcSJack F Vogel break; 4173758cc3dcSJack F Vogel default: 4174758cc3dcSJack F Vogel break; 4175758cc3dcSJack F Vogel } 4176758cc3dcSJack F Vogel } 4177758cc3dcSJack F Vogel 4178758cc3dcSJack F Vogel 4179