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 *********************************************************************/ 57*6f37f232SEric Joyner char ixgbe_driver_version[] = "2.8.3"; 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); 120*6f37f232SEric Joyner static int ixgbe_suspend(device_t); 121*6f37f232SEric Joyner static int ixgbe_resume(device_t); 122758cc3dcSJack F Vogel static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t); 123758cc3dcSJack F Vogel static void ixgbe_init(void *); 124758cc3dcSJack F Vogel static void ixgbe_init_locked(struct adapter *); 125758cc3dcSJack F Vogel static void ixgbe_stop(void *); 126758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 127758cc3dcSJack F Vogel static uint64_t ixgbe_get_counter(struct ifnet *, ift_counter); 128758cc3dcSJack F Vogel #endif 129758cc3dcSJack F Vogel static void ixgbe_add_media_types(struct adapter *); 130758cc3dcSJack F Vogel static void ixgbe_media_status(struct ifnet *, struct ifmediareq *); 131758cc3dcSJack F Vogel static int ixgbe_media_change(struct ifnet *); 132758cc3dcSJack F Vogel static void ixgbe_identify_hardware(struct adapter *); 133758cc3dcSJack F Vogel static int ixgbe_allocate_pci_resources(struct adapter *); 134758cc3dcSJack F Vogel static void ixgbe_get_slot_info(struct ixgbe_hw *); 135758cc3dcSJack F Vogel static int ixgbe_allocate_msix(struct adapter *); 136758cc3dcSJack F Vogel static int ixgbe_allocate_legacy(struct adapter *); 137758cc3dcSJack F Vogel static int ixgbe_setup_msix(struct adapter *); 138758cc3dcSJack F Vogel static void ixgbe_free_pci_resources(struct adapter *); 139758cc3dcSJack F Vogel static void ixgbe_local_timer(void *); 140758cc3dcSJack F Vogel static int ixgbe_setup_interface(device_t, struct adapter *); 141*6f37f232SEric Joyner static void ixgbe_config_dmac(struct adapter *); 142*6f37f232SEric Joyner static void ixgbe_config_delay_values(struct adapter *); 143758cc3dcSJack F Vogel static void ixgbe_config_link(struct adapter *); 144*6f37f232SEric Joyner static void ixgbe_check_eee_support(struct adapter *); 145*6f37f232SEric Joyner static void ixgbe_check_wol_support(struct adapter *); 146*6f37f232SEric Joyner static int ixgbe_setup_low_power_mode(struct adapter *); 147758cc3dcSJack F Vogel static void ixgbe_rearm_queues(struct adapter *, u64); 148758cc3dcSJack F Vogel 149758cc3dcSJack F Vogel static void ixgbe_initialize_transmit_units(struct adapter *); 150758cc3dcSJack F Vogel static void ixgbe_initialize_receive_units(struct adapter *); 151758cc3dcSJack F Vogel static void ixgbe_enable_rx_drop(struct adapter *); 152758cc3dcSJack F Vogel static void ixgbe_disable_rx_drop(struct adapter *); 153758cc3dcSJack F Vogel 154758cc3dcSJack F Vogel static void ixgbe_enable_intr(struct adapter *); 155758cc3dcSJack F Vogel static void ixgbe_disable_intr(struct adapter *); 156758cc3dcSJack F Vogel static void ixgbe_update_stats_counters(struct adapter *); 157758cc3dcSJack F Vogel static void ixgbe_set_promisc(struct adapter *); 158758cc3dcSJack F Vogel static void ixgbe_set_multi(struct adapter *); 159758cc3dcSJack F Vogel static void ixgbe_update_link_status(struct adapter *); 160758cc3dcSJack F Vogel static void ixgbe_set_ivar(struct adapter *, u8, u8, s8); 161758cc3dcSJack F Vogel static void ixgbe_configure_ivars(struct adapter *); 162758cc3dcSJack F Vogel static u8 * ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); 163758cc3dcSJack F Vogel 164758cc3dcSJack F Vogel static void ixgbe_setup_vlan_hw_support(struct adapter *); 165758cc3dcSJack F Vogel static void ixgbe_register_vlan(void *, struct ifnet *, u16); 166758cc3dcSJack F Vogel static void ixgbe_unregister_vlan(void *, struct ifnet *, u16); 167758cc3dcSJack F Vogel 168*6f37f232SEric Joyner static void ixgbe_add_device_sysctls(struct adapter *); 169*6f37f232SEric Joyner static void ixgbe_add_hw_stats(struct adapter *); 170*6f37f232SEric Joyner 171*6f37f232SEric Joyner /* Sysctl handlers */ 172*6f37f232SEric Joyner static int ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS); 173*6f37f232SEric Joyner static int ixgbe_set_advertise(SYSCTL_HANDLER_ARGS); 174*6f37f232SEric Joyner static int ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS); 175*6f37f232SEric Joyner static int ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS); 176*6f37f232SEric Joyner static int ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS); 177*6f37f232SEric Joyner static int ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS); 178*6f37f232SEric Joyner static int ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS); 179*6f37f232SEric Joyner static int ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS); 180*6f37f232SEric Joyner static int ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS); 181*6f37f232SEric Joyner static int ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS); 182*6f37f232SEric Joyner static int ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS); 183*6f37f232SEric Joyner static int ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS); 184758cc3dcSJack F Vogel 185758cc3dcSJack F Vogel /* Support for pluggable optic modules */ 186758cc3dcSJack F Vogel static bool ixgbe_sfp_probe(struct adapter *); 187758cc3dcSJack F Vogel static void ixgbe_setup_optics(struct adapter *); 188758cc3dcSJack F Vogel 189758cc3dcSJack F Vogel /* Legacy (single vector interrupt handler */ 190758cc3dcSJack F Vogel static void ixgbe_legacy_irq(void *); 191758cc3dcSJack F Vogel 192758cc3dcSJack F Vogel /* The MSI/X Interrupt handlers */ 193758cc3dcSJack F Vogel static void ixgbe_msix_que(void *); 194758cc3dcSJack F Vogel static void ixgbe_msix_link(void *); 195758cc3dcSJack F Vogel 196758cc3dcSJack F Vogel /* Deferred interrupt tasklets */ 197758cc3dcSJack F Vogel static void ixgbe_handle_que(void *, int); 198758cc3dcSJack F Vogel static void ixgbe_handle_link(void *, int); 199758cc3dcSJack F Vogel static void ixgbe_handle_msf(void *, int); 200758cc3dcSJack F Vogel static void ixgbe_handle_mod(void *, int); 201*6f37f232SEric Joyner static void ixgbe_handle_phy(void *, int); 202758cc3dcSJack F Vogel 203758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 204758cc3dcSJack F Vogel static void ixgbe_reinit_fdir(void *, int); 205758cc3dcSJack F Vogel #endif 206758cc3dcSJack F Vogel 207758cc3dcSJack F Vogel 208758cc3dcSJack F Vogel /* Missing shared code prototype */ 209758cc3dcSJack F Vogel extern void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw); 210758cc3dcSJack F Vogel 211758cc3dcSJack F Vogel /********************************************************************* 212758cc3dcSJack F Vogel * FreeBSD Device Interface Entry Points 213758cc3dcSJack F Vogel *********************************************************************/ 214758cc3dcSJack F Vogel 215a1edda90SAdrian Chadd static device_method_t ix_methods[] = { 216758cc3dcSJack F Vogel /* Device interface */ 217758cc3dcSJack F Vogel DEVMETHOD(device_probe, ixgbe_probe), 218758cc3dcSJack F Vogel DEVMETHOD(device_attach, ixgbe_attach), 219758cc3dcSJack F Vogel DEVMETHOD(device_detach, ixgbe_detach), 220758cc3dcSJack F Vogel DEVMETHOD(device_shutdown, ixgbe_shutdown), 221*6f37f232SEric Joyner DEVMETHOD(device_suspend, ixgbe_suspend), 222*6f37f232SEric Joyner DEVMETHOD(device_resume, ixgbe_resume), 223758cc3dcSJack F Vogel DEVMETHOD_END 224758cc3dcSJack F Vogel }; 225758cc3dcSJack F Vogel 226a1edda90SAdrian Chadd static driver_t ix_driver = { 227a1edda90SAdrian Chadd "ix", ix_methods, sizeof(struct adapter), 228758cc3dcSJack F Vogel }; 229758cc3dcSJack F Vogel 230a1edda90SAdrian Chadd devclass_t ix_devclass; 231a1edda90SAdrian Chadd DRIVER_MODULE(ix, pci, ix_driver, ix_devclass, 0, 0); 232758cc3dcSJack F Vogel 233a1edda90SAdrian Chadd MODULE_DEPEND(ix, pci, 1, 1, 1); 234a1edda90SAdrian Chadd MODULE_DEPEND(ix, ether, 1, 1, 1); 235758cc3dcSJack F Vogel 236758cc3dcSJack F Vogel /* 237758cc3dcSJack F Vogel ** TUNEABLE PARAMETERS: 238758cc3dcSJack F Vogel */ 239758cc3dcSJack F Vogel 240758cc3dcSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0, 241758cc3dcSJack F Vogel "IXGBE driver parameters"); 242758cc3dcSJack F Vogel 243758cc3dcSJack F Vogel /* 244758cc3dcSJack F Vogel ** AIM: Adaptive Interrupt Moderation 245758cc3dcSJack F Vogel ** which means that the interrupt rate 246758cc3dcSJack F Vogel ** is varied over time based on the 247758cc3dcSJack F Vogel ** traffic for that interrupt vector 248758cc3dcSJack F Vogel */ 249758cc3dcSJack F Vogel static int ixgbe_enable_aim = TRUE; 250758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0, 251758cc3dcSJack F Vogel "Enable adaptive interrupt moderation"); 252758cc3dcSJack F Vogel 253758cc3dcSJack F Vogel static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY); 254758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN, 255758cc3dcSJack F Vogel &ixgbe_max_interrupt_rate, 0, "Maximum interrupts per second"); 256758cc3dcSJack F Vogel 257758cc3dcSJack F Vogel /* How many packets rxeof tries to clean at a time */ 258758cc3dcSJack F Vogel static int ixgbe_rx_process_limit = 256; 259758cc3dcSJack F Vogel TUNABLE_INT("hw.ixgbe.rx_process_limit", &ixgbe_rx_process_limit); 260758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, 261758cc3dcSJack F Vogel &ixgbe_rx_process_limit, 0, 262758cc3dcSJack F Vogel "Maximum number of received packets to process at a time," 263758cc3dcSJack F Vogel "-1 means unlimited"); 264758cc3dcSJack F Vogel 265758cc3dcSJack F Vogel /* How many packets txeof tries to clean at a time */ 266758cc3dcSJack F Vogel static int ixgbe_tx_process_limit = 256; 267758cc3dcSJack F Vogel TUNABLE_INT("hw.ixgbe.tx_process_limit", &ixgbe_tx_process_limit); 268758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, tx_process_limit, CTLFLAG_RDTUN, 269758cc3dcSJack F Vogel &ixgbe_tx_process_limit, 0, 270758cc3dcSJack F Vogel "Maximum number of sent packets to process at a time," 271758cc3dcSJack F Vogel "-1 means unlimited"); 272758cc3dcSJack F Vogel 273758cc3dcSJack F Vogel /* 274758cc3dcSJack F Vogel ** Smart speed setting, default to on 275758cc3dcSJack F Vogel ** this only works as a compile option 276758cc3dcSJack F Vogel ** right now as its during attach, set 277758cc3dcSJack F Vogel ** this to 'ixgbe_smart_speed_off' to 278758cc3dcSJack F Vogel ** disable. 279758cc3dcSJack F Vogel */ 280758cc3dcSJack F Vogel static int ixgbe_smart_speed = ixgbe_smart_speed_on; 281758cc3dcSJack F Vogel 282758cc3dcSJack F Vogel /* 283758cc3dcSJack F Vogel * MSIX should be the default for best performance, 284758cc3dcSJack F Vogel * but this allows it to be forced off for testing. 285758cc3dcSJack F Vogel */ 286758cc3dcSJack F Vogel static int ixgbe_enable_msix = 1; 287758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixgbe_enable_msix, 0, 288758cc3dcSJack F Vogel "Enable MSI-X interrupts"); 289758cc3dcSJack F Vogel 290758cc3dcSJack F Vogel /* 291758cc3dcSJack F Vogel * Number of Queues, can be set to 0, 292758cc3dcSJack F Vogel * it then autoconfigures based on the 293758cc3dcSJack F Vogel * number of cpus with a max of 8. This 294758cc3dcSJack F Vogel * can be overriden manually here. 295758cc3dcSJack F Vogel */ 296758cc3dcSJack F Vogel static int ixgbe_num_queues = 0; 297758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, num_queues, CTLFLAG_RDTUN, &ixgbe_num_queues, 0, 298758cc3dcSJack F Vogel "Number of queues to configure, 0 indicates autoconfigure"); 299758cc3dcSJack F Vogel 300758cc3dcSJack F Vogel /* 301758cc3dcSJack F Vogel ** Number of TX descriptors per ring, 302758cc3dcSJack F Vogel ** setting higher than RX as this seems 303758cc3dcSJack F Vogel ** the better performing choice. 304758cc3dcSJack F Vogel */ 305758cc3dcSJack F Vogel static int ixgbe_txd = PERFORM_TXD; 306758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, txd, CTLFLAG_RDTUN, &ixgbe_txd, 0, 307758cc3dcSJack F Vogel "Number of transmit descriptors per queue"); 308758cc3dcSJack F Vogel 309758cc3dcSJack F Vogel /* Number of RX descriptors per ring */ 310758cc3dcSJack F Vogel static int ixgbe_rxd = PERFORM_RXD; 311758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rxd, CTLFLAG_RDTUN, &ixgbe_rxd, 0, 312758cc3dcSJack F Vogel "Number of receive descriptors per queue"); 313758cc3dcSJack F Vogel 314758cc3dcSJack F Vogel /* 315758cc3dcSJack F Vogel ** Defining this on will allow the use 316758cc3dcSJack F Vogel ** of unsupported SFP+ modules, note that 317758cc3dcSJack F Vogel ** doing so you are on your own :) 318758cc3dcSJack F Vogel */ 319758cc3dcSJack F Vogel static int allow_unsupported_sfp = FALSE; 320758cc3dcSJack F Vogel TUNABLE_INT("hw.ix.unsupported_sfp", &allow_unsupported_sfp); 321758cc3dcSJack F Vogel 322758cc3dcSJack F Vogel /* Keep running tab on them for sanity check */ 323758cc3dcSJack F Vogel static int ixgbe_total_ports; 324758cc3dcSJack F Vogel 325758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 326758cc3dcSJack F Vogel /* 327758cc3dcSJack F Vogel ** Flow Director actually 'steals' 328758cc3dcSJack F Vogel ** part of the packet buffer as its 329758cc3dcSJack F Vogel ** filter pool, this variable controls 330758cc3dcSJack F Vogel ** how much it uses: 331758cc3dcSJack F Vogel ** 0 = 64K, 1 = 128K, 2 = 256K 332758cc3dcSJack F Vogel */ 333758cc3dcSJack F Vogel static int fdir_pballoc = 1; 334758cc3dcSJack F Vogel #endif 335758cc3dcSJack F Vogel 336758cc3dcSJack F Vogel #ifdef DEV_NETMAP 337758cc3dcSJack F Vogel /* 338758cc3dcSJack F Vogel * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to 339758cc3dcSJack F Vogel * be a reference on how to implement netmap support in a driver. 340758cc3dcSJack F Vogel * Additional comments are in ixgbe_netmap.h . 341758cc3dcSJack F Vogel * 342758cc3dcSJack F Vogel * <dev/netmap/ixgbe_netmap.h> contains functions for netmap support 343758cc3dcSJack F Vogel * that extend the standard driver. 344758cc3dcSJack F Vogel */ 345758cc3dcSJack F Vogel #include <dev/netmap/ixgbe_netmap.h> 346758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 347758cc3dcSJack F Vogel 348758cc3dcSJack F Vogel /********************************************************************* 349758cc3dcSJack F Vogel * Device identification routine 350758cc3dcSJack F Vogel * 351758cc3dcSJack F Vogel * ixgbe_probe determines if the driver should be loaded on 352758cc3dcSJack F Vogel * adapter based on PCI vendor/device id of the adapter. 353758cc3dcSJack F Vogel * 354758cc3dcSJack F Vogel * return BUS_PROBE_DEFAULT on success, positive on failure 355758cc3dcSJack F Vogel *********************************************************************/ 356758cc3dcSJack F Vogel 357758cc3dcSJack F Vogel static int 358758cc3dcSJack F Vogel ixgbe_probe(device_t dev) 359758cc3dcSJack F Vogel { 360758cc3dcSJack F Vogel ixgbe_vendor_info_t *ent; 361758cc3dcSJack F Vogel 362758cc3dcSJack F Vogel u16 pci_vendor_id = 0; 363758cc3dcSJack F Vogel u16 pci_device_id = 0; 364758cc3dcSJack F Vogel u16 pci_subvendor_id = 0; 365758cc3dcSJack F Vogel u16 pci_subdevice_id = 0; 366758cc3dcSJack F Vogel char adapter_name[256]; 367758cc3dcSJack F Vogel 368758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_probe: begin"); 369758cc3dcSJack F Vogel 370758cc3dcSJack F Vogel pci_vendor_id = pci_get_vendor(dev); 371758cc3dcSJack F Vogel if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) 372758cc3dcSJack F Vogel return (ENXIO); 373758cc3dcSJack F Vogel 374758cc3dcSJack F Vogel pci_device_id = pci_get_device(dev); 375758cc3dcSJack F Vogel pci_subvendor_id = pci_get_subvendor(dev); 376758cc3dcSJack F Vogel pci_subdevice_id = pci_get_subdevice(dev); 377758cc3dcSJack F Vogel 378758cc3dcSJack F Vogel ent = ixgbe_vendor_info_array; 379758cc3dcSJack F Vogel while (ent->vendor_id != 0) { 380758cc3dcSJack F Vogel if ((pci_vendor_id == ent->vendor_id) && 381758cc3dcSJack F Vogel (pci_device_id == ent->device_id) && 382758cc3dcSJack F Vogel 383758cc3dcSJack F Vogel ((pci_subvendor_id == ent->subvendor_id) || 384758cc3dcSJack F Vogel (ent->subvendor_id == 0)) && 385758cc3dcSJack F Vogel 386758cc3dcSJack F Vogel ((pci_subdevice_id == ent->subdevice_id) || 387758cc3dcSJack F Vogel (ent->subdevice_id == 0))) { 388758cc3dcSJack F Vogel sprintf(adapter_name, "%s, Version - %s", 389758cc3dcSJack F Vogel ixgbe_strings[ent->index], 390758cc3dcSJack F Vogel ixgbe_driver_version); 391758cc3dcSJack F Vogel device_set_desc_copy(dev, adapter_name); 392758cc3dcSJack F Vogel ++ixgbe_total_ports; 393758cc3dcSJack F Vogel return (BUS_PROBE_DEFAULT); 394758cc3dcSJack F Vogel } 395758cc3dcSJack F Vogel ent++; 396758cc3dcSJack F Vogel } 397758cc3dcSJack F Vogel return (ENXIO); 398758cc3dcSJack F Vogel } 399758cc3dcSJack F Vogel 400758cc3dcSJack F Vogel /********************************************************************* 401758cc3dcSJack F Vogel * Device initialization routine 402758cc3dcSJack F Vogel * 403758cc3dcSJack F Vogel * The attach entry point is called when the driver is being loaded. 404758cc3dcSJack F Vogel * This routine identifies the type of hardware, allocates all resources 405758cc3dcSJack F Vogel * and initializes the hardware. 406758cc3dcSJack F Vogel * 407758cc3dcSJack F Vogel * return 0 on success, positive on failure 408758cc3dcSJack F Vogel *********************************************************************/ 409758cc3dcSJack F Vogel 410758cc3dcSJack F Vogel static int 411758cc3dcSJack F Vogel ixgbe_attach(device_t dev) 412758cc3dcSJack F Vogel { 413758cc3dcSJack F Vogel struct adapter *adapter; 414758cc3dcSJack F Vogel struct ixgbe_hw *hw; 415758cc3dcSJack F Vogel int error = 0; 416758cc3dcSJack F Vogel u16 csum; 417758cc3dcSJack F Vogel u32 ctrl_ext; 418758cc3dcSJack F Vogel 419758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_attach: begin"); 420758cc3dcSJack F Vogel 421758cc3dcSJack F Vogel /* Allocate, clear, and link in our adapter structure */ 422758cc3dcSJack F Vogel adapter = device_get_softc(dev); 423758cc3dcSJack F Vogel adapter->dev = adapter->osdep.dev = dev; 424758cc3dcSJack F Vogel hw = &adapter->hw; 425758cc3dcSJack F Vogel 426758cc3dcSJack F Vogel /* Core Lock Init*/ 427758cc3dcSJack F Vogel IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); 428758cc3dcSJack F Vogel 429758cc3dcSJack F Vogel /* Set up the timer callout */ 430758cc3dcSJack F Vogel callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); 431758cc3dcSJack F Vogel 432758cc3dcSJack F Vogel /* Determine hardware revision */ 433758cc3dcSJack F Vogel ixgbe_identify_hardware(adapter); 434758cc3dcSJack F Vogel 435758cc3dcSJack F Vogel /* Do base PCI setup - map BAR0 */ 436758cc3dcSJack F Vogel if (ixgbe_allocate_pci_resources(adapter)) { 437758cc3dcSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 438758cc3dcSJack F Vogel error = ENXIO; 439758cc3dcSJack F Vogel goto err_out; 440758cc3dcSJack F Vogel } 441758cc3dcSJack F Vogel 442758cc3dcSJack F Vogel /* Do descriptor calc and sanity checks */ 443758cc3dcSJack F Vogel if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || 444758cc3dcSJack F Vogel ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) { 445758cc3dcSJack F Vogel device_printf(dev, "TXD config issue, using default!\n"); 446758cc3dcSJack F Vogel adapter->num_tx_desc = DEFAULT_TXD; 447758cc3dcSJack F Vogel } else 448758cc3dcSJack F Vogel adapter->num_tx_desc = ixgbe_txd; 449758cc3dcSJack F Vogel 450758cc3dcSJack F Vogel /* 451758cc3dcSJack F Vogel ** With many RX rings it is easy to exceed the 452758cc3dcSJack F Vogel ** system mbuf allocation. Tuning nmbclusters 453758cc3dcSJack F Vogel ** can alleviate this. 454758cc3dcSJack F Vogel */ 455758cc3dcSJack F Vogel if (nmbclusters > 0) { 456758cc3dcSJack F Vogel int s; 457758cc3dcSJack F Vogel s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports; 458758cc3dcSJack F Vogel if (s > nmbclusters) { 459758cc3dcSJack F Vogel device_printf(dev, "RX Descriptors exceed " 460758cc3dcSJack F Vogel "system mbuf max, using default instead!\n"); 461758cc3dcSJack F Vogel ixgbe_rxd = DEFAULT_RXD; 462758cc3dcSJack F Vogel } 463758cc3dcSJack F Vogel } 464758cc3dcSJack F Vogel 465758cc3dcSJack F Vogel if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || 466758cc3dcSJack F Vogel ixgbe_rxd < MIN_RXD || ixgbe_rxd > MAX_RXD) { 467758cc3dcSJack F Vogel device_printf(dev, "RXD config issue, using default!\n"); 468758cc3dcSJack F Vogel adapter->num_rx_desc = DEFAULT_RXD; 469758cc3dcSJack F Vogel } else 470758cc3dcSJack F Vogel adapter->num_rx_desc = ixgbe_rxd; 471758cc3dcSJack F Vogel 472758cc3dcSJack F Vogel /* Allocate our TX/RX Queues */ 473758cc3dcSJack F Vogel if (ixgbe_allocate_queues(adapter)) { 474758cc3dcSJack F Vogel error = ENOMEM; 475758cc3dcSJack F Vogel goto err_out; 476758cc3dcSJack F Vogel } 477758cc3dcSJack F Vogel 478758cc3dcSJack F Vogel /* Allocate multicast array memory. */ 479758cc3dcSJack F Vogel adapter->mta = malloc(sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS * 480758cc3dcSJack F Vogel MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); 481758cc3dcSJack F Vogel if (adapter->mta == NULL) { 482758cc3dcSJack F Vogel device_printf(dev, "Can not allocate multicast setup array\n"); 483758cc3dcSJack F Vogel error = ENOMEM; 484758cc3dcSJack F Vogel goto err_late; 485758cc3dcSJack F Vogel } 486758cc3dcSJack F Vogel 487758cc3dcSJack F Vogel /* Initialize the shared code */ 488758cc3dcSJack F Vogel hw->allow_unsupported_sfp = allow_unsupported_sfp; 489758cc3dcSJack F Vogel error = ixgbe_init_shared_code(hw); 490758cc3dcSJack F Vogel if (error == IXGBE_ERR_SFP_NOT_PRESENT) { 491758cc3dcSJack F Vogel /* 492758cc3dcSJack F Vogel ** No optics in this port, set up 493758cc3dcSJack F Vogel ** so the timer routine will probe 494758cc3dcSJack F Vogel ** for later insertion. 495758cc3dcSJack F Vogel */ 496758cc3dcSJack F Vogel adapter->sfp_probe = TRUE; 497758cc3dcSJack F Vogel error = 0; 498758cc3dcSJack F Vogel } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { 499758cc3dcSJack F Vogel device_printf(dev,"Unsupported SFP+ module detected!\n"); 500758cc3dcSJack F Vogel error = EIO; 501758cc3dcSJack F Vogel goto err_late; 502758cc3dcSJack F Vogel } else if (error) { 503758cc3dcSJack F Vogel device_printf(dev,"Unable to initialize the shared code\n"); 504758cc3dcSJack F Vogel error = EIO; 505758cc3dcSJack F Vogel goto err_late; 506758cc3dcSJack F Vogel } 507758cc3dcSJack F Vogel 508758cc3dcSJack F Vogel /* Make sure we have a good EEPROM before we read from it */ 509758cc3dcSJack F Vogel if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) { 510758cc3dcSJack F Vogel device_printf(dev,"The EEPROM Checksum Is Not Valid\n"); 511758cc3dcSJack F Vogel error = EIO; 512758cc3dcSJack F Vogel goto err_late; 513758cc3dcSJack F Vogel } 514758cc3dcSJack F Vogel 515758cc3dcSJack F Vogel error = ixgbe_init_hw(hw); 516758cc3dcSJack F Vogel switch (error) { 517758cc3dcSJack F Vogel case IXGBE_ERR_EEPROM_VERSION: 518758cc3dcSJack F Vogel device_printf(dev, "This device is a pre-production adapter/" 519758cc3dcSJack F Vogel "LOM. Please be aware there may be issues associated " 520758cc3dcSJack F Vogel "with your hardware.\n If you are experiencing problems " 521758cc3dcSJack F Vogel "please contact your Intel or hardware representative " 522758cc3dcSJack F Vogel "who provided you with this hardware.\n"); 523758cc3dcSJack F Vogel break; 524758cc3dcSJack F Vogel case IXGBE_ERR_SFP_NOT_SUPPORTED: 525758cc3dcSJack F Vogel device_printf(dev,"Unsupported SFP+ Module\n"); 526758cc3dcSJack F Vogel error = EIO; 527758cc3dcSJack F Vogel goto err_late; 528758cc3dcSJack F Vogel case IXGBE_ERR_SFP_NOT_PRESENT: 529758cc3dcSJack F Vogel device_printf(dev,"No SFP+ Module found\n"); 530758cc3dcSJack F Vogel /* falls thru */ 531758cc3dcSJack F Vogel default: 532758cc3dcSJack F Vogel break; 533758cc3dcSJack F Vogel } 534758cc3dcSJack F Vogel 535758cc3dcSJack F Vogel /* Detect and set physical type */ 536758cc3dcSJack F Vogel ixgbe_setup_optics(adapter); 537758cc3dcSJack F Vogel 538758cc3dcSJack F Vogel if ((adapter->msix > 1) && (ixgbe_enable_msix)) 539758cc3dcSJack F Vogel error = ixgbe_allocate_msix(adapter); 540758cc3dcSJack F Vogel else 541758cc3dcSJack F Vogel error = ixgbe_allocate_legacy(adapter); 542758cc3dcSJack F Vogel if (error) 543758cc3dcSJack F Vogel goto err_late; 544758cc3dcSJack F Vogel 545758cc3dcSJack F Vogel /* Setup OS specific network interface */ 546758cc3dcSJack F Vogel if (ixgbe_setup_interface(dev, adapter) != 0) 547758cc3dcSJack F Vogel goto err_late; 548758cc3dcSJack F Vogel 549758cc3dcSJack F Vogel /* Initialize statistics */ 550758cc3dcSJack F Vogel ixgbe_update_stats_counters(adapter); 551758cc3dcSJack F Vogel 552758cc3dcSJack F Vogel /* Register for VLAN events */ 553758cc3dcSJack F Vogel adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 554758cc3dcSJack F Vogel ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); 555758cc3dcSJack F Vogel adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 556758cc3dcSJack F Vogel ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); 557758cc3dcSJack F Vogel 558*6f37f232SEric Joyner /* Check PCIE slot type/speed/width */ 559758cc3dcSJack F Vogel ixgbe_get_slot_info(hw); 560758cc3dcSJack F Vogel 561758cc3dcSJack F Vogel 562758cc3dcSJack F Vogel /* Set an initial default flow control value */ 563758cc3dcSJack F Vogel adapter->fc = ixgbe_fc_full; 564758cc3dcSJack F Vogel 565*6f37f232SEric Joyner /* Check for certain supported features */ 566*6f37f232SEric Joyner ixgbe_check_wol_support(adapter); 567*6f37f232SEric Joyner ixgbe_check_eee_support(adapter); 568*6f37f232SEric Joyner 569*6f37f232SEric Joyner /* Add sysctls */ 570*6f37f232SEric Joyner ixgbe_add_device_sysctls(adapter); 571*6f37f232SEric Joyner ixgbe_add_hw_stats(adapter); 572*6f37f232SEric Joyner 573758cc3dcSJack F Vogel /* let hardware know driver is loaded */ 574758cc3dcSJack F Vogel ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 575758cc3dcSJack F Vogel ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; 576758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 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 621*6f37f232SEric Joyner /* Stop the adapter */ 622758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 623*6f37f232SEric Joyner ixgbe_setup_low_power_mode(adapter); 624758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 625758cc3dcSJack F Vogel 626758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { 627758cc3dcSJack F Vogel if (que->tq) { 628758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 629758cc3dcSJack F Vogel taskqueue_drain(que->tq, &txr->txq_task); 630758cc3dcSJack F Vogel #endif 631758cc3dcSJack F Vogel taskqueue_drain(que->tq, &que->que_task); 632758cc3dcSJack F Vogel taskqueue_free(que->tq); 633758cc3dcSJack F Vogel } 634758cc3dcSJack F Vogel } 635758cc3dcSJack F Vogel 636758cc3dcSJack F Vogel /* Drain the Link queue */ 637758cc3dcSJack F Vogel if (adapter->tq) { 638758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->link_task); 639758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->mod_task); 640758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->msf_task); 641*6f37f232SEric Joyner taskqueue_drain(adapter->tq, &adapter->phy_task); 642758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 643758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->fdir_task); 644758cc3dcSJack F Vogel #endif 645758cc3dcSJack F Vogel taskqueue_free(adapter->tq); 646758cc3dcSJack F Vogel } 647758cc3dcSJack F Vogel 648758cc3dcSJack F Vogel /* let hardware know driver is unloading */ 649758cc3dcSJack F Vogel ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); 650758cc3dcSJack F Vogel ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; 651758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext); 652758cc3dcSJack F Vogel 653758cc3dcSJack F Vogel /* Unregister VLAN events */ 654758cc3dcSJack F Vogel if (adapter->vlan_attach != NULL) 655758cc3dcSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); 656758cc3dcSJack F Vogel if (adapter->vlan_detach != NULL) 657758cc3dcSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); 658758cc3dcSJack F Vogel 659758cc3dcSJack F Vogel ether_ifdetach(adapter->ifp); 660758cc3dcSJack F Vogel callout_drain(&adapter->timer); 661758cc3dcSJack F Vogel #ifdef DEV_NETMAP 662758cc3dcSJack F Vogel netmap_detach(adapter->ifp); 663758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 664758cc3dcSJack F Vogel ixgbe_free_pci_resources(adapter); 665758cc3dcSJack F Vogel bus_generic_detach(dev); 666758cc3dcSJack F Vogel if_free(adapter->ifp); 667758cc3dcSJack F Vogel 668758cc3dcSJack F Vogel ixgbe_free_transmit_structures(adapter); 669758cc3dcSJack F Vogel ixgbe_free_receive_structures(adapter); 670758cc3dcSJack F Vogel free(adapter->mta, M_DEVBUF); 671758cc3dcSJack F Vogel 672758cc3dcSJack F Vogel IXGBE_CORE_LOCK_DESTROY(adapter); 673758cc3dcSJack F Vogel return (0); 674758cc3dcSJack F Vogel } 675758cc3dcSJack F Vogel 676758cc3dcSJack F Vogel /********************************************************************* 677758cc3dcSJack F Vogel * 678758cc3dcSJack F Vogel * Shutdown entry point 679758cc3dcSJack F Vogel * 680758cc3dcSJack F Vogel **********************************************************************/ 681758cc3dcSJack F Vogel 682758cc3dcSJack F Vogel static int 683758cc3dcSJack F Vogel ixgbe_shutdown(device_t dev) 684758cc3dcSJack F Vogel { 685758cc3dcSJack F Vogel struct adapter *adapter = device_get_softc(dev); 686*6f37f232SEric Joyner int error = 0; 687*6f37f232SEric Joyner 688*6f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_shutdown: begin"); 689*6f37f232SEric Joyner 690758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 691*6f37f232SEric Joyner error = ixgbe_setup_low_power_mode(adapter); 692758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 693*6f37f232SEric Joyner 694*6f37f232SEric Joyner return (error); 695*6f37f232SEric Joyner } 696*6f37f232SEric Joyner 697*6f37f232SEric Joyner /** 698*6f37f232SEric Joyner * Methods for going from: 699*6f37f232SEric Joyner * D0 -> D3: ixgbe_suspend 700*6f37f232SEric Joyner * D3 -> D0: ixgbe_resume 701*6f37f232SEric Joyner */ 702*6f37f232SEric Joyner static int 703*6f37f232SEric Joyner ixgbe_suspend(device_t dev) 704*6f37f232SEric Joyner { 705*6f37f232SEric Joyner struct adapter *adapter = device_get_softc(dev); 706*6f37f232SEric Joyner int error = 0; 707*6f37f232SEric Joyner 708*6f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_suspend: begin"); 709*6f37f232SEric Joyner 710*6f37f232SEric Joyner IXGBE_CORE_LOCK(adapter); 711*6f37f232SEric Joyner 712*6f37f232SEric Joyner error = ixgbe_setup_low_power_mode(adapter); 713*6f37f232SEric Joyner 714*6f37f232SEric Joyner /* Save state and power down */ 715*6f37f232SEric Joyner pci_save_state(dev); 716*6f37f232SEric Joyner pci_set_powerstate(dev, PCI_POWERSTATE_D3); 717*6f37f232SEric Joyner 718*6f37f232SEric Joyner IXGBE_CORE_UNLOCK(adapter); 719*6f37f232SEric Joyner 720*6f37f232SEric Joyner return (error); 721*6f37f232SEric Joyner } 722*6f37f232SEric Joyner 723*6f37f232SEric Joyner static int 724*6f37f232SEric Joyner ixgbe_resume(device_t dev) 725*6f37f232SEric Joyner { 726*6f37f232SEric Joyner struct adapter *adapter = device_get_softc(dev); 727*6f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 728*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 729*6f37f232SEric Joyner u32 wus; 730*6f37f232SEric Joyner 731*6f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_resume: begin"); 732*6f37f232SEric Joyner 733*6f37f232SEric Joyner IXGBE_CORE_LOCK(adapter); 734*6f37f232SEric Joyner 735*6f37f232SEric Joyner pci_set_powerstate(dev, PCI_POWERSTATE_D0); 736*6f37f232SEric Joyner pci_restore_state(dev); 737*6f37f232SEric Joyner 738*6f37f232SEric Joyner /* Read & clear WUS register */ 739*6f37f232SEric Joyner wus = IXGBE_READ_REG(hw, IXGBE_WUS); 740*6f37f232SEric Joyner if (wus) 741*6f37f232SEric Joyner device_printf(dev, "Woken up by (WUS): %#010x\n", 742*6f37f232SEric Joyner IXGBE_READ_REG(hw, IXGBE_WUS)); 743*6f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); 744*6f37f232SEric Joyner /* And clear WUFC until next low-power transition */ 745*6f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0); 746*6f37f232SEric Joyner 747*6f37f232SEric Joyner /* 748*6f37f232SEric Joyner * Required after D3->D0 transition; 749*6f37f232SEric Joyner * will re-advertise all previous advertised speeds 750*6f37f232SEric Joyner */ 751*6f37f232SEric Joyner if (ifp->if_flags & IFF_UP) 752*6f37f232SEric Joyner ixgbe_init_locked(adapter); 753*6f37f232SEric Joyner 754*6f37f232SEric Joyner IXGBE_CORE_UNLOCK(adapter); 755*6f37f232SEric Joyner 756*6f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_resume: end"); 757758cc3dcSJack F Vogel return (0); 758758cc3dcSJack F Vogel } 759758cc3dcSJack F Vogel 760758cc3dcSJack F Vogel 761758cc3dcSJack F Vogel /********************************************************************* 762758cc3dcSJack F Vogel * Ioctl entry point 763758cc3dcSJack F Vogel * 764758cc3dcSJack F Vogel * ixgbe_ioctl is called when the user wants to configure the 765758cc3dcSJack F Vogel * interface. 766758cc3dcSJack F Vogel * 767758cc3dcSJack F Vogel * return 0 on success, positive on failure 768758cc3dcSJack F Vogel **********************************************************************/ 769758cc3dcSJack F Vogel 770758cc3dcSJack F Vogel static int 771758cc3dcSJack F Vogel ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 772758cc3dcSJack F Vogel { 773758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 774758cc3dcSJack F Vogel struct ifreq *ifr = (struct ifreq *) data; 775758cc3dcSJack F Vogel #if defined(INET) || defined(INET6) 776758cc3dcSJack F Vogel struct ifaddr *ifa = (struct ifaddr *)data; 777758cc3dcSJack F Vogel bool avoid_reset = FALSE; 778758cc3dcSJack F Vogel #endif 779758cc3dcSJack F Vogel int error = 0; 780758cc3dcSJack F Vogel 781758cc3dcSJack F Vogel switch (command) { 782758cc3dcSJack F Vogel 783758cc3dcSJack F Vogel case SIOCSIFADDR: 784758cc3dcSJack F Vogel #ifdef INET 785758cc3dcSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET) 786758cc3dcSJack F Vogel avoid_reset = TRUE; 787758cc3dcSJack F Vogel #endif 788758cc3dcSJack F Vogel #ifdef INET6 789758cc3dcSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET6) 790758cc3dcSJack F Vogel avoid_reset = TRUE; 791758cc3dcSJack F Vogel #endif 792758cc3dcSJack F Vogel #if defined(INET) || defined(INET6) 793758cc3dcSJack F Vogel /* 794758cc3dcSJack F Vogel ** Calling init results in link renegotiation, 795758cc3dcSJack F Vogel ** so we avoid doing it when possible. 796758cc3dcSJack F Vogel */ 797758cc3dcSJack F Vogel if (avoid_reset) { 798758cc3dcSJack F Vogel ifp->if_flags |= IFF_UP; 799758cc3dcSJack F Vogel if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 800758cc3dcSJack F Vogel ixgbe_init(adapter); 801758cc3dcSJack F Vogel if (!(ifp->if_flags & IFF_NOARP)) 802758cc3dcSJack F Vogel arp_ifinit(ifp, ifa); 803758cc3dcSJack F Vogel } else 804758cc3dcSJack F Vogel error = ether_ioctl(ifp, command, data); 805758cc3dcSJack F Vogel #endif 806758cc3dcSJack F Vogel break; 807758cc3dcSJack F Vogel case SIOCSIFMTU: 808758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 809*6f37f232SEric Joyner if (ifr->ifr_mtu > IXGBE_MAX_MTU) { 810758cc3dcSJack F Vogel error = EINVAL; 811758cc3dcSJack F Vogel } else { 812758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 813758cc3dcSJack F Vogel ifp->if_mtu = ifr->ifr_mtu; 814758cc3dcSJack F Vogel adapter->max_frame_size = 815*6f37f232SEric Joyner ifp->if_mtu + IXGBE_MTU_HDR; 816758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 817758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 818758cc3dcSJack F Vogel } 819758cc3dcSJack F Vogel break; 820758cc3dcSJack F Vogel case SIOCSIFFLAGS: 821758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 822758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 823758cc3dcSJack F Vogel if (ifp->if_flags & IFF_UP) { 824758cc3dcSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 825758cc3dcSJack F Vogel if ((ifp->if_flags ^ adapter->if_flags) & 826758cc3dcSJack F Vogel (IFF_PROMISC | IFF_ALLMULTI)) { 827758cc3dcSJack F Vogel ixgbe_set_promisc(adapter); 828758cc3dcSJack F Vogel } 829758cc3dcSJack F Vogel } else 830758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 831758cc3dcSJack F Vogel } else 832758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) 833758cc3dcSJack F Vogel ixgbe_stop(adapter); 834758cc3dcSJack F Vogel adapter->if_flags = ifp->if_flags; 835758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 836758cc3dcSJack F Vogel break; 837758cc3dcSJack F Vogel case SIOCADDMULTI: 838758cc3dcSJack F Vogel case SIOCDELMULTI: 839758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); 840758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 841758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 842758cc3dcSJack F Vogel ixgbe_disable_intr(adapter); 843758cc3dcSJack F Vogel ixgbe_set_multi(adapter); 844758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 845758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 846758cc3dcSJack F Vogel } 847758cc3dcSJack F Vogel break; 848758cc3dcSJack F Vogel case SIOCSIFMEDIA: 849758cc3dcSJack F Vogel case SIOCGIFMEDIA: 850758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 851758cc3dcSJack F Vogel error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); 852758cc3dcSJack F Vogel break; 853758cc3dcSJack F Vogel case SIOCSIFCAP: 854758cc3dcSJack F Vogel { 855758cc3dcSJack F Vogel int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 856758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 857758cc3dcSJack F Vogel if (mask & IFCAP_HWCSUM) 858758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_HWCSUM; 859758cc3dcSJack F Vogel if (mask & IFCAP_TSO4) 860758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_TSO4; 861758cc3dcSJack F Vogel if (mask & IFCAP_TSO6) 862758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_TSO6; 863758cc3dcSJack F Vogel if (mask & IFCAP_LRO) 864758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_LRO; 865758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWTAGGING) 866758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 867758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWFILTER) 868758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 869758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWTSO) 870758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 871758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 872758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 873758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 874758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 875758cc3dcSJack F Vogel } 876758cc3dcSJack F Vogel VLAN_CAPABILITIES(ifp); 877758cc3dcSJack F Vogel break; 878758cc3dcSJack F Vogel } 879758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 880758cc3dcSJack F Vogel case SIOCGI2C: 881758cc3dcSJack F Vogel { 882758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 883758cc3dcSJack F Vogel struct ifi2creq i2c; 884758cc3dcSJack F Vogel int i; 885758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)"); 886758cc3dcSJack F Vogel error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); 887758cc3dcSJack F Vogel if (error != 0) 888758cc3dcSJack F Vogel break; 889758cc3dcSJack F Vogel if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { 890758cc3dcSJack F Vogel error = EINVAL; 891758cc3dcSJack F Vogel break; 892758cc3dcSJack F Vogel } 893758cc3dcSJack F Vogel if (i2c.len > sizeof(i2c.data)) { 894758cc3dcSJack F Vogel error = EINVAL; 895758cc3dcSJack F Vogel break; 896758cc3dcSJack F Vogel } 897758cc3dcSJack F Vogel 898758cc3dcSJack F Vogel for (i = 0; i < i2c.len; i++) 899758cc3dcSJack F Vogel hw->phy.ops.read_i2c_byte(hw, i2c.offset + i, 900758cc3dcSJack F Vogel i2c.dev_addr, &i2c.data[i]); 901758cc3dcSJack F Vogel error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); 902758cc3dcSJack F Vogel break; 903758cc3dcSJack F Vogel } 904758cc3dcSJack F Vogel #endif 905758cc3dcSJack F Vogel default: 906758cc3dcSJack F Vogel IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); 907758cc3dcSJack F Vogel error = ether_ioctl(ifp, command, data); 908758cc3dcSJack F Vogel break; 909758cc3dcSJack F Vogel } 910758cc3dcSJack F Vogel 911758cc3dcSJack F Vogel return (error); 912758cc3dcSJack F Vogel } 913758cc3dcSJack F Vogel 914758cc3dcSJack F Vogel /********************************************************************* 915758cc3dcSJack F Vogel * Init entry point 916758cc3dcSJack F Vogel * 917758cc3dcSJack F Vogel * This routine is used in two ways. It is used by the stack as 918758cc3dcSJack F Vogel * init entry point in network interface structure. It is also used 919758cc3dcSJack F Vogel * by the driver as a hw/sw initialization routine to get to a 920758cc3dcSJack F Vogel * consistent state. 921758cc3dcSJack F Vogel * 922758cc3dcSJack F Vogel * return 0 on success, positive on failure 923758cc3dcSJack F Vogel **********************************************************************/ 924758cc3dcSJack F Vogel #define IXGBE_MHADD_MFS_SHIFT 16 925758cc3dcSJack F Vogel 926758cc3dcSJack F Vogel static void 927758cc3dcSJack F Vogel ixgbe_init_locked(struct adapter *adapter) 928758cc3dcSJack F Vogel { 929758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 930758cc3dcSJack F Vogel device_t dev = adapter->dev; 931758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 932758cc3dcSJack F Vogel u32 k, txdctl, mhadd, gpie; 933758cc3dcSJack F Vogel u32 rxdctl, rxctrl; 934758cc3dcSJack F Vogel 935758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 936758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_init_locked: begin"); 937758cc3dcSJack F Vogel hw->adapter_stopped = FALSE; 938758cc3dcSJack F Vogel ixgbe_stop_adapter(hw); 939758cc3dcSJack F Vogel callout_stop(&adapter->timer); 940758cc3dcSJack F Vogel 941758cc3dcSJack F Vogel /* reprogram the RAR[0] in case user changed it. */ 942758cc3dcSJack F Vogel ixgbe_set_rar(hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); 943758cc3dcSJack F Vogel 944758cc3dcSJack F Vogel /* Get the latest mac address, User can use a LAA */ 945758cc3dcSJack F Vogel bcopy(IF_LLADDR(adapter->ifp), hw->mac.addr, 946758cc3dcSJack F Vogel IXGBE_ETH_LENGTH_OF_ADDRESS); 947758cc3dcSJack F Vogel ixgbe_set_rar(hw, 0, hw->mac.addr, 0, 1); 948758cc3dcSJack F Vogel hw->addr_ctrl.rar_used_count = 1; 949758cc3dcSJack F Vogel 950758cc3dcSJack F Vogel /* Set the various hardware offload abilities */ 951758cc3dcSJack F Vogel ifp->if_hwassist = 0; 952758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_TSO) 953758cc3dcSJack F Vogel ifp->if_hwassist |= CSUM_TSO; 954758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM) { 955758cc3dcSJack F Vogel ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 956758cc3dcSJack F Vogel #if __FreeBSD_version >= 800000 957758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) 958758cc3dcSJack F Vogel ifp->if_hwassist |= CSUM_SCTP; 959758cc3dcSJack F Vogel #endif 960758cc3dcSJack F Vogel } 961758cc3dcSJack F Vogel 962758cc3dcSJack F Vogel /* Prepare transmit descriptors and buffers */ 963758cc3dcSJack F Vogel if (ixgbe_setup_transmit_structures(adapter)) { 964758cc3dcSJack F Vogel device_printf(dev, "Could not setup transmit structures\n"); 965758cc3dcSJack F Vogel ixgbe_stop(adapter); 966758cc3dcSJack F Vogel return; 967758cc3dcSJack F Vogel } 968758cc3dcSJack F Vogel 969758cc3dcSJack F Vogel ixgbe_init_hw(hw); 970758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(adapter); 971758cc3dcSJack F Vogel 972758cc3dcSJack F Vogel /* Setup Multicast table */ 973758cc3dcSJack F Vogel ixgbe_set_multi(adapter); 974758cc3dcSJack F Vogel 975758cc3dcSJack F Vogel /* 976758cc3dcSJack F Vogel ** Determine the correct mbuf pool 977758cc3dcSJack F Vogel ** for doing jumbo frames 978758cc3dcSJack F Vogel */ 979758cc3dcSJack F Vogel if (adapter->max_frame_size <= 2048) 980758cc3dcSJack F Vogel adapter->rx_mbuf_sz = MCLBYTES; 981758cc3dcSJack F Vogel else if (adapter->max_frame_size <= 4096) 982758cc3dcSJack F Vogel adapter->rx_mbuf_sz = MJUMPAGESIZE; 983758cc3dcSJack F Vogel else if (adapter->max_frame_size <= 9216) 984758cc3dcSJack F Vogel adapter->rx_mbuf_sz = MJUM9BYTES; 985758cc3dcSJack F Vogel else 986758cc3dcSJack F Vogel adapter->rx_mbuf_sz = MJUM16BYTES; 987758cc3dcSJack F Vogel 988758cc3dcSJack F Vogel /* Prepare receive descriptors and buffers */ 989758cc3dcSJack F Vogel if (ixgbe_setup_receive_structures(adapter)) { 990758cc3dcSJack F Vogel device_printf(dev, "Could not setup receive structures\n"); 991758cc3dcSJack F Vogel ixgbe_stop(adapter); 992758cc3dcSJack F Vogel return; 993758cc3dcSJack F Vogel } 994758cc3dcSJack F Vogel 995758cc3dcSJack F Vogel /* Configure RX settings */ 996758cc3dcSJack F Vogel ixgbe_initialize_receive_units(adapter); 997758cc3dcSJack F Vogel 998758cc3dcSJack F Vogel gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE); 999758cc3dcSJack F Vogel 1000758cc3dcSJack F Vogel /* Enable Fan Failure Interrupt */ 1001758cc3dcSJack F Vogel gpie |= IXGBE_SDP1_GPIEN_BY_MAC(hw); 1002758cc3dcSJack F Vogel 1003758cc3dcSJack F Vogel /* Add for Module detection */ 1004758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82599EB) 1005*6f37f232SEric Joyner gpie |= IXGBE_SDP2_GPIEN; 1006758cc3dcSJack F Vogel 1007*6f37f232SEric Joyner /* 1008*6f37f232SEric Joyner * Thermal Failure Detection (X540) 1009*6f37f232SEric Joyner * Link Detection (X552) 1010*6f37f232SEric Joyner */ 1011*6f37f232SEric Joyner if (hw->mac.type == ixgbe_mac_X540 || 1012*6f37f232SEric Joyner hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || 1013*6f37f232SEric Joyner hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) 1014*6f37f232SEric Joyner gpie |= IXGBE_SDP0_GPIEN_X540; 1015758cc3dcSJack F Vogel 1016758cc3dcSJack F Vogel if (adapter->msix > 1) { 1017758cc3dcSJack F Vogel /* Enable Enhanced MSIX mode */ 1018758cc3dcSJack F Vogel gpie |= IXGBE_GPIE_MSIX_MODE; 1019758cc3dcSJack F Vogel gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | 1020758cc3dcSJack F Vogel IXGBE_GPIE_OCD; 1021758cc3dcSJack F Vogel } 1022758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 1023758cc3dcSJack F Vogel 1024758cc3dcSJack F Vogel /* Set MTU size */ 1025758cc3dcSJack F Vogel if (ifp->if_mtu > ETHERMTU) { 1026*6f37f232SEric Joyner /* aka IXGBE_MAXFRS on 82599 and newer */ 1027758cc3dcSJack F Vogel mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); 1028758cc3dcSJack F Vogel mhadd &= ~IXGBE_MHADD_MFS_MASK; 1029758cc3dcSJack F Vogel mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; 1030758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); 1031758cc3dcSJack F Vogel } 1032758cc3dcSJack F Vogel 1033758cc3dcSJack F Vogel /* Now enable all the queues */ 1034758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 1035758cc3dcSJack F Vogel txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); 1036758cc3dcSJack F Vogel txdctl |= IXGBE_TXDCTL_ENABLE; 1037758cc3dcSJack F Vogel /* Set WTHRESH to 8, burst writeback */ 1038758cc3dcSJack F Vogel txdctl |= (8 << 16); 1039758cc3dcSJack F Vogel /* 1040758cc3dcSJack F Vogel * When the internal queue falls below PTHRESH (32), 1041758cc3dcSJack F Vogel * start prefetching as long as there are at least 1042758cc3dcSJack F Vogel * HTHRESH (1) buffers ready. The values are taken 1043758cc3dcSJack F Vogel * from the Intel linux driver 3.8.21. 1044758cc3dcSJack F Vogel * Prefetching enables tx line rate even with 1 queue. 1045758cc3dcSJack F Vogel */ 1046758cc3dcSJack F Vogel txdctl |= (32 << 0) | (1 << 8); 1047758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), txdctl); 1048758cc3dcSJack F Vogel } 1049758cc3dcSJack F Vogel 1050758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 1051758cc3dcSJack F Vogel rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); 1052758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1053758cc3dcSJack F Vogel /* 1054758cc3dcSJack F Vogel ** PTHRESH = 21 1055758cc3dcSJack F Vogel ** HTHRESH = 4 1056758cc3dcSJack F Vogel ** WTHRESH = 8 1057758cc3dcSJack F Vogel */ 1058758cc3dcSJack F Vogel rxdctl &= ~0x3FFFFF; 1059758cc3dcSJack F Vogel rxdctl |= 0x080420; 1060758cc3dcSJack F Vogel } 1061758cc3dcSJack F Vogel rxdctl |= IXGBE_RXDCTL_ENABLE; 1062758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), rxdctl); 1063758cc3dcSJack F Vogel for (k = 0; k < 10; k++) { 1064758cc3dcSJack F Vogel if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)) & 1065758cc3dcSJack F Vogel IXGBE_RXDCTL_ENABLE) 1066758cc3dcSJack F Vogel break; 1067758cc3dcSJack F Vogel else 1068758cc3dcSJack F Vogel msec_delay(1); 1069758cc3dcSJack F Vogel } 1070758cc3dcSJack F Vogel wmb(); 1071758cc3dcSJack F Vogel #ifdef DEV_NETMAP 1072758cc3dcSJack F Vogel /* 1073758cc3dcSJack F Vogel * In netmap mode, we must preserve the buffers made 1074758cc3dcSJack F Vogel * available to userspace before the if_init() 1075758cc3dcSJack F Vogel * (this is true by default on the TX side, because 1076758cc3dcSJack F Vogel * init makes all buffers available to userspace). 1077758cc3dcSJack F Vogel * 1078758cc3dcSJack F Vogel * netmap_reset() and the device specific routines 1079758cc3dcSJack F Vogel * (e.g. ixgbe_setup_receive_rings()) map these 1080758cc3dcSJack F Vogel * buffers at the end of the NIC ring, so here we 1081758cc3dcSJack F Vogel * must set the RDT (tail) register to make sure 1082758cc3dcSJack F Vogel * they are not overwritten. 1083758cc3dcSJack F Vogel * 1084758cc3dcSJack F Vogel * In this driver the NIC ring starts at RDH = 0, 1085758cc3dcSJack F Vogel * RDT points to the last slot available for reception (?), 1086758cc3dcSJack F Vogel * so RDT = num_rx_desc - 1 means the whole ring is available. 1087758cc3dcSJack F Vogel */ 1088758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_NETMAP) { 1089758cc3dcSJack F Vogel struct netmap_adapter *na = NA(adapter->ifp); 1090758cc3dcSJack F Vogel struct netmap_kring *kring = &na->rx_rings[i]; 1091758cc3dcSJack F Vogel int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); 1092758cc3dcSJack F Vogel 1093758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(i), t); 1094758cc3dcSJack F Vogel } else 1095758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 1096758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(i), adapter->num_rx_desc - 1); 1097758cc3dcSJack F Vogel } 1098758cc3dcSJack F Vogel 1099758cc3dcSJack F Vogel /* Enable Receive engine */ 1100758cc3dcSJack F Vogel rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); 1101758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 1102758cc3dcSJack F Vogel rxctrl |= IXGBE_RXCTRL_DMBYPS; 1103758cc3dcSJack F Vogel rxctrl |= IXGBE_RXCTRL_RXEN; 1104758cc3dcSJack F Vogel ixgbe_enable_rx_dma(hw, rxctrl); 1105758cc3dcSJack F Vogel 1106758cc3dcSJack F Vogel callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); 1107758cc3dcSJack F Vogel 1108758cc3dcSJack F Vogel /* Set up MSI/X routing */ 1109758cc3dcSJack F Vogel if (ixgbe_enable_msix) { 1110758cc3dcSJack F Vogel ixgbe_configure_ivars(adapter); 1111758cc3dcSJack F Vogel /* Set up auto-mask */ 1112758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 1113758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); 1114758cc3dcSJack F Vogel else { 1115758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); 1116758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); 1117758cc3dcSJack F Vogel } 1118758cc3dcSJack F Vogel } else { /* Simple settings for Legacy/MSI */ 1119758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 0, 0, 0); 1120758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 0, 0, 1); 1121758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); 1122758cc3dcSJack F Vogel } 1123758cc3dcSJack F Vogel 1124758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 1125758cc3dcSJack F Vogel /* Init Flow director */ 1126758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 1127758cc3dcSJack F Vogel u32 hdrm = 32 << fdir_pballoc; 1128758cc3dcSJack F Vogel 1129758cc3dcSJack F Vogel hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL); 1130758cc3dcSJack F Vogel ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); 1131758cc3dcSJack F Vogel } 1132758cc3dcSJack F Vogel #endif 1133758cc3dcSJack F Vogel 1134758cc3dcSJack F Vogel /* 1135758cc3dcSJack F Vogel ** Check on any SFP devices that 1136758cc3dcSJack F Vogel ** need to be kick-started 1137758cc3dcSJack F Vogel */ 1138758cc3dcSJack F Vogel if (hw->phy.type == ixgbe_phy_none) { 1139758cc3dcSJack F Vogel int err = hw->phy.ops.identify(hw); 1140758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 1141758cc3dcSJack F Vogel device_printf(dev, 1142758cc3dcSJack F Vogel "Unsupported SFP+ module type was detected.\n"); 1143758cc3dcSJack F Vogel return; 1144758cc3dcSJack F Vogel } 1145758cc3dcSJack F Vogel } 1146758cc3dcSJack F Vogel 1147758cc3dcSJack F Vogel /* Set moderation on the Link interrupt */ 1148758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR); 1149758cc3dcSJack F Vogel 1150*6f37f232SEric Joyner /* Configure Energy Efficient Ethernet for supported devices */ 1151*6f37f232SEric Joyner if (adapter->eee_support) 1152*6f37f232SEric Joyner ixgbe_setup_eee(hw, adapter->eee_enabled); 1153*6f37f232SEric Joyner 1154758cc3dcSJack F Vogel /* Config/Enable Link */ 1155758cc3dcSJack F Vogel ixgbe_config_link(adapter); 1156758cc3dcSJack F Vogel 1157758cc3dcSJack F Vogel /* Hardware Packet Buffer & Flow Control setup */ 1158*6f37f232SEric Joyner ixgbe_config_delay_values(adapter); 1159758cc3dcSJack F Vogel 1160758cc3dcSJack F Vogel /* Initialize the FC settings */ 1161758cc3dcSJack F Vogel ixgbe_start_hw(hw); 1162758cc3dcSJack F Vogel 1163758cc3dcSJack F Vogel /* Set up VLAN support and filter */ 1164758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 1165758cc3dcSJack F Vogel 1166*6f37f232SEric Joyner /* Setup DMA Coalescing */ 1167*6f37f232SEric Joyner ixgbe_config_dmac(adapter); 1168*6f37f232SEric Joyner 1169758cc3dcSJack F Vogel /* And now turn on interrupts */ 1170758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1171758cc3dcSJack F Vogel 1172758cc3dcSJack F Vogel /* Now inform the stack we're ready */ 1173758cc3dcSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 1174758cc3dcSJack F Vogel 1175758cc3dcSJack F Vogel return; 1176758cc3dcSJack F Vogel } 1177758cc3dcSJack F Vogel 1178758cc3dcSJack F Vogel static void 1179758cc3dcSJack F Vogel ixgbe_init(void *arg) 1180758cc3dcSJack F Vogel { 1181758cc3dcSJack F Vogel struct adapter *adapter = arg; 1182758cc3dcSJack F Vogel 1183758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 1184758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 1185758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1186758cc3dcSJack F Vogel return; 1187758cc3dcSJack F Vogel } 1188758cc3dcSJack F Vogel 1189*6f37f232SEric Joyner static void 1190*6f37f232SEric Joyner ixgbe_config_delay_values(struct adapter *adapter) 1191*6f37f232SEric Joyner { 1192*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 1193*6f37f232SEric Joyner u32 rxpb, frame, size, tmp; 1194*6f37f232SEric Joyner 1195*6f37f232SEric Joyner frame = adapter->max_frame_size; 1196*6f37f232SEric Joyner 1197*6f37f232SEric Joyner /* Calculate High Water */ 1198*6f37f232SEric Joyner switch (hw->mac.type) { 1199*6f37f232SEric Joyner case ixgbe_mac_X540: 1200*6f37f232SEric Joyner case ixgbe_mac_X550: 1201*6f37f232SEric Joyner case ixgbe_mac_X550EM_x: 1202*6f37f232SEric Joyner tmp = IXGBE_DV_X540(frame, frame); 1203*6f37f232SEric Joyner break; 1204*6f37f232SEric Joyner default: 1205*6f37f232SEric Joyner tmp = IXGBE_DV(frame, frame); 1206*6f37f232SEric Joyner break; 1207*6f37f232SEric Joyner } 1208*6f37f232SEric Joyner size = IXGBE_BT2KB(tmp); 1209*6f37f232SEric Joyner rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10; 1210*6f37f232SEric Joyner hw->fc.high_water[0] = rxpb - size; 1211*6f37f232SEric Joyner 1212*6f37f232SEric Joyner /* Now calculate Low Water */ 1213*6f37f232SEric Joyner switch (hw->mac.type) { 1214*6f37f232SEric Joyner case ixgbe_mac_X540: 1215*6f37f232SEric Joyner case ixgbe_mac_X550: 1216*6f37f232SEric Joyner case ixgbe_mac_X550EM_x: 1217*6f37f232SEric Joyner tmp = IXGBE_LOW_DV_X540(frame); 1218*6f37f232SEric Joyner break; 1219*6f37f232SEric Joyner default: 1220*6f37f232SEric Joyner tmp = IXGBE_LOW_DV(frame); 1221*6f37f232SEric Joyner break; 1222*6f37f232SEric Joyner } 1223*6f37f232SEric Joyner hw->fc.low_water[0] = IXGBE_BT2KB(tmp); 1224*6f37f232SEric Joyner 1225*6f37f232SEric Joyner hw->fc.requested_mode = adapter->fc; 1226*6f37f232SEric Joyner hw->fc.pause_time = IXGBE_FC_PAUSE; 1227*6f37f232SEric Joyner hw->fc.send_xon = TRUE; 1228*6f37f232SEric Joyner } 1229758cc3dcSJack F Vogel 1230758cc3dcSJack F Vogel /* 1231758cc3dcSJack F Vogel ** 1232758cc3dcSJack F Vogel ** MSIX Interrupt Handlers and Tasklets 1233758cc3dcSJack F Vogel ** 1234758cc3dcSJack F Vogel */ 1235758cc3dcSJack F Vogel 1236758cc3dcSJack F Vogel static inline void 1237758cc3dcSJack F Vogel ixgbe_enable_queue(struct adapter *adapter, u32 vector) 1238758cc3dcSJack F Vogel { 1239758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1240758cc3dcSJack F Vogel u64 queue = (u64)(1 << vector); 1241758cc3dcSJack F Vogel u32 mask; 1242758cc3dcSJack F Vogel 1243758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1244758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queue); 1245758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); 1246758cc3dcSJack F Vogel } else { 1247758cc3dcSJack F Vogel mask = (queue & 0xFFFFFFFF); 1248758cc3dcSJack F Vogel if (mask) 1249758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask); 1250758cc3dcSJack F Vogel mask = (queue >> 32); 1251758cc3dcSJack F Vogel if (mask) 1252758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask); 1253758cc3dcSJack F Vogel } 1254758cc3dcSJack F Vogel } 1255758cc3dcSJack F Vogel 1256758cc3dcSJack F Vogel static inline void 1257758cc3dcSJack F Vogel ixgbe_disable_queue(struct adapter *adapter, u32 vector) 1258758cc3dcSJack F Vogel { 1259758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1260758cc3dcSJack F Vogel u64 queue = (u64)(1 << vector); 1261758cc3dcSJack F Vogel u32 mask; 1262758cc3dcSJack F Vogel 1263758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1264758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queue); 1265758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask); 1266758cc3dcSJack F Vogel } else { 1267758cc3dcSJack F Vogel mask = (queue & 0xFFFFFFFF); 1268758cc3dcSJack F Vogel if (mask) 1269758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask); 1270758cc3dcSJack F Vogel mask = (queue >> 32); 1271758cc3dcSJack F Vogel if (mask) 1272758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask); 1273758cc3dcSJack F Vogel } 1274758cc3dcSJack F Vogel } 1275758cc3dcSJack F Vogel 1276758cc3dcSJack F Vogel static void 1277758cc3dcSJack F Vogel ixgbe_handle_que(void *context, int pending) 1278758cc3dcSJack F Vogel { 1279758cc3dcSJack F Vogel struct ix_queue *que = context; 1280758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1281758cc3dcSJack F Vogel struct tx_ring *txr = que->txr; 1282758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1283*6f37f232SEric Joyner bool more; 1284758cc3dcSJack F Vogel 1285758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1286*6f37f232SEric Joyner more = ixgbe_rxeof(que); 1287758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1288758cc3dcSJack F Vogel ixgbe_txeof(txr); 1289758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 1290758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1291758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1292758cc3dcSJack F Vogel #else 1293758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1294758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1295758cc3dcSJack F Vogel #endif 1296758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1297758cc3dcSJack F Vogel } 1298758cc3dcSJack F Vogel 1299758cc3dcSJack F Vogel /* Reenable this interrupt */ 1300758cc3dcSJack F Vogel if (que->res != NULL) 1301758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 1302758cc3dcSJack F Vogel else 1303758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1304758cc3dcSJack F Vogel return; 1305758cc3dcSJack F Vogel } 1306758cc3dcSJack F Vogel 1307758cc3dcSJack F Vogel 1308758cc3dcSJack F Vogel /********************************************************************* 1309758cc3dcSJack F Vogel * 1310758cc3dcSJack F Vogel * Legacy Interrupt Service routine 1311758cc3dcSJack F Vogel * 1312758cc3dcSJack F Vogel **********************************************************************/ 1313758cc3dcSJack F Vogel 1314758cc3dcSJack F Vogel static void 1315758cc3dcSJack F Vogel ixgbe_legacy_irq(void *arg) 1316758cc3dcSJack F Vogel { 1317758cc3dcSJack F Vogel struct ix_queue *que = arg; 1318758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1319758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1320758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1321758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 1322758cc3dcSJack F Vogel bool more; 1323758cc3dcSJack F Vogel u32 reg_eicr; 1324758cc3dcSJack F Vogel 1325758cc3dcSJack F Vogel 1326758cc3dcSJack F Vogel reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 1327758cc3dcSJack F Vogel 1328758cc3dcSJack F Vogel ++que->irqs; 1329758cc3dcSJack F Vogel if (reg_eicr == 0) { 1330758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1331758cc3dcSJack F Vogel return; 1332758cc3dcSJack F Vogel } 1333758cc3dcSJack F Vogel 1334758cc3dcSJack F Vogel more = ixgbe_rxeof(que); 1335758cc3dcSJack F Vogel 1336758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1337758cc3dcSJack F Vogel ixgbe_txeof(txr); 1338758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX 1339758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1340758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1341758cc3dcSJack F Vogel #else 1342758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1343758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1344758cc3dcSJack F Vogel #endif 1345758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1346758cc3dcSJack F Vogel 1347758cc3dcSJack F Vogel /* Check for fan failure */ 1348758cc3dcSJack F Vogel if ((hw->phy.media_type == ixgbe_media_type_copper) && 1349758cc3dcSJack F Vogel (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) { 1350758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " 1351758cc3dcSJack F Vogel "REPLACE IMMEDIATELY!!\n"); 1352758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 1353758cc3dcSJack F Vogel } 1354758cc3dcSJack F Vogel 1355758cc3dcSJack F Vogel /* Link status change */ 1356758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_LSC) 1357758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->link_task); 1358758cc3dcSJack F Vogel 1359*6f37f232SEric Joyner /* External PHY interrupt */ 1360*6f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && 1361*6f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) 1362*6f37f232SEric Joyner taskqueue_enqueue(adapter->tq, &adapter->phy_task); 1363*6f37f232SEric Joyner 1364758cc3dcSJack F Vogel if (more) 1365758cc3dcSJack F Vogel taskqueue_enqueue(que->tq, &que->que_task); 1366758cc3dcSJack F Vogel else 1367758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1368758cc3dcSJack F Vogel return; 1369758cc3dcSJack F Vogel } 1370758cc3dcSJack F Vogel 1371758cc3dcSJack F Vogel 1372758cc3dcSJack F Vogel /********************************************************************* 1373758cc3dcSJack F Vogel * 1374758cc3dcSJack F Vogel * MSIX Queue Interrupt Service routine 1375758cc3dcSJack F Vogel * 1376758cc3dcSJack F Vogel **********************************************************************/ 1377758cc3dcSJack F Vogel void 1378758cc3dcSJack F Vogel ixgbe_msix_que(void *arg) 1379758cc3dcSJack F Vogel { 1380758cc3dcSJack F Vogel struct ix_queue *que = arg; 1381758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1382758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1383758cc3dcSJack F Vogel struct tx_ring *txr = que->txr; 1384758cc3dcSJack F Vogel struct rx_ring *rxr = que->rxr; 1385758cc3dcSJack F Vogel bool more; 1386758cc3dcSJack F Vogel u32 newitr = 0; 1387758cc3dcSJack F Vogel 1388758cc3dcSJack F Vogel /* Protect against spurious interrupts */ 1389758cc3dcSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1390758cc3dcSJack F Vogel return; 1391758cc3dcSJack F Vogel 1392758cc3dcSJack F Vogel ixgbe_disable_queue(adapter, que->msix); 1393758cc3dcSJack F Vogel ++que->irqs; 1394758cc3dcSJack F Vogel 1395758cc3dcSJack F Vogel more = ixgbe_rxeof(que); 1396758cc3dcSJack F Vogel 1397758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1398758cc3dcSJack F Vogel ixgbe_txeof(txr); 1399758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX 1400758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(ifp->if_snd)) 1401758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1402758cc3dcSJack F Vogel #else 1403758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1404758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1405758cc3dcSJack F Vogel #endif 1406758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1407758cc3dcSJack F Vogel 1408758cc3dcSJack F Vogel /* Do AIM now? */ 1409758cc3dcSJack F Vogel 1410758cc3dcSJack F Vogel if (ixgbe_enable_aim == FALSE) 1411758cc3dcSJack F Vogel goto no_calc; 1412758cc3dcSJack F Vogel /* 1413758cc3dcSJack F Vogel ** Do Adaptive Interrupt Moderation: 1414758cc3dcSJack F Vogel ** - Write out last calculated setting 1415758cc3dcSJack F Vogel ** - Calculate based on average size over 1416758cc3dcSJack F Vogel ** the last interval. 1417758cc3dcSJack F Vogel */ 1418758cc3dcSJack F Vogel if (que->eitr_setting) 1419758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, 1420758cc3dcSJack F Vogel IXGBE_EITR(que->msix), que->eitr_setting); 1421758cc3dcSJack F Vogel 1422758cc3dcSJack F Vogel que->eitr_setting = 0; 1423758cc3dcSJack F Vogel 1424758cc3dcSJack F Vogel /* Idle, do nothing */ 1425758cc3dcSJack F Vogel if ((txr->bytes == 0) && (rxr->bytes == 0)) 1426758cc3dcSJack F Vogel goto no_calc; 1427758cc3dcSJack F Vogel 1428758cc3dcSJack F Vogel if ((txr->bytes) && (txr->packets)) 1429758cc3dcSJack F Vogel newitr = txr->bytes/txr->packets; 1430758cc3dcSJack F Vogel if ((rxr->bytes) && (rxr->packets)) 1431758cc3dcSJack F Vogel newitr = max(newitr, 1432758cc3dcSJack F Vogel (rxr->bytes / rxr->packets)); 1433758cc3dcSJack F Vogel newitr += 24; /* account for hardware frame, crc */ 1434758cc3dcSJack F Vogel 1435758cc3dcSJack F Vogel /* set an upper boundary */ 1436758cc3dcSJack F Vogel newitr = min(newitr, 3000); 1437758cc3dcSJack F Vogel 1438758cc3dcSJack F Vogel /* Be nice to the mid range */ 1439758cc3dcSJack F Vogel if ((newitr > 300) && (newitr < 1200)) 1440758cc3dcSJack F Vogel newitr = (newitr / 3); 1441758cc3dcSJack F Vogel else 1442758cc3dcSJack F Vogel newitr = (newitr / 2); 1443758cc3dcSJack F Vogel 1444758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) 1445758cc3dcSJack F Vogel newitr |= newitr << 16; 1446758cc3dcSJack F Vogel else 1447758cc3dcSJack F Vogel newitr |= IXGBE_EITR_CNT_WDIS; 1448758cc3dcSJack F Vogel 1449758cc3dcSJack F Vogel /* save for next interrupt */ 1450758cc3dcSJack F Vogel que->eitr_setting = newitr; 1451758cc3dcSJack F Vogel 1452758cc3dcSJack F Vogel /* Reset state */ 1453758cc3dcSJack F Vogel txr->bytes = 0; 1454758cc3dcSJack F Vogel txr->packets = 0; 1455758cc3dcSJack F Vogel rxr->bytes = 0; 1456758cc3dcSJack F Vogel rxr->packets = 0; 1457758cc3dcSJack F Vogel 1458758cc3dcSJack F Vogel no_calc: 1459758cc3dcSJack F Vogel if (more) 1460758cc3dcSJack F Vogel taskqueue_enqueue(que->tq, &que->que_task); 1461758cc3dcSJack F Vogel else 1462758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 1463758cc3dcSJack F Vogel return; 1464758cc3dcSJack F Vogel } 1465758cc3dcSJack F Vogel 1466758cc3dcSJack F Vogel 1467758cc3dcSJack F Vogel static void 1468758cc3dcSJack F Vogel ixgbe_msix_link(void *arg) 1469758cc3dcSJack F Vogel { 1470758cc3dcSJack F Vogel struct adapter *adapter = arg; 1471758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1472*6f37f232SEric Joyner u32 reg_eicr, mod_mask; 1473758cc3dcSJack F Vogel 1474*6f37f232SEric Joyner ++adapter->link_irq; 1475758cc3dcSJack F Vogel 1476758cc3dcSJack F Vogel /* First get the cause */ 1477758cc3dcSJack F Vogel reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS); 1478758cc3dcSJack F Vogel /* Be sure the queue bits are not cleared */ 1479758cc3dcSJack F Vogel reg_eicr &= ~IXGBE_EICR_RTX_QUEUE; 1480758cc3dcSJack F Vogel /* Clear interrupt with write */ 1481758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr); 1482758cc3dcSJack F Vogel 1483758cc3dcSJack F Vogel /* Link status change */ 1484758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_LSC) 1485758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->link_task); 1486758cc3dcSJack F Vogel 1487758cc3dcSJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82598EB) { 1488758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 1489758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_FLOW_DIR) { 1490758cc3dcSJack F Vogel /* This is probably overkill :) */ 1491758cc3dcSJack F Vogel if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1)) 1492758cc3dcSJack F Vogel return; 1493758cc3dcSJack F Vogel /* Disable the interrupt */ 1494758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR); 1495758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->fdir_task); 1496758cc3dcSJack F Vogel } else 1497758cc3dcSJack F Vogel #endif 1498758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_ECC) { 1499758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: ECC ERROR!! " 1500758cc3dcSJack F Vogel "Please Reboot!!\n"); 1501758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); 1502*6f37f232SEric Joyner } 1503*6f37f232SEric Joyner 1504*6f37f232SEric Joyner /* Check for over temp condition */ 1505*6f37f232SEric Joyner if (reg_eicr & IXGBE_EICR_TS) { 1506*6f37f232SEric Joyner device_printf(adapter->dev, "\nCRITICAL: OVER TEMP!! " 1507*6f37f232SEric Joyner "PHY IS SHUT DOWN!!\n"); 1508*6f37f232SEric Joyner device_printf(adapter->dev, "System shutdown required!\n"); 1509*6f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); 1510*6f37f232SEric Joyner } 1511*6f37f232SEric Joyner } 1512*6f37f232SEric Joyner 1513*6f37f232SEric Joyner /* Pluggable optics-related interrupt */ 1514*6f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) 1515*6f37f232SEric Joyner mod_mask = IXGBE_EICR_GPI_SDP0_X540; 1516*6f37f232SEric Joyner else 1517*6f37f232SEric Joyner mod_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw); 1518758cc3dcSJack F Vogel 1519758cc3dcSJack F Vogel if (ixgbe_is_sfp(hw)) { 1520*6f37f232SEric Joyner if (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) { 1521758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 1522758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 1523*6f37f232SEric Joyner } else if (reg_eicr & mod_mask) { 1524*6f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, mod_mask); 1525758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mod_task); 1526758cc3dcSJack F Vogel } 1527758cc3dcSJack F Vogel } 1528758cc3dcSJack F Vogel 1529758cc3dcSJack F Vogel /* Check for fan failure */ 1530758cc3dcSJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82598AT) && 1531*6f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP1)) { 1532*6f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); 1533758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " 1534758cc3dcSJack F Vogel "REPLACE IMMEDIATELY!!\n"); 1535758cc3dcSJack F Vogel } 1536758cc3dcSJack F Vogel 1537*6f37f232SEric Joyner /* External PHY interrupt */ 1538*6f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && 1539*6f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) { 1540*6f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540); 1541*6f37f232SEric Joyner taskqueue_enqueue(adapter->tq, &adapter->phy_task); 1542758cc3dcSJack F Vogel } 1543758cc3dcSJack F Vogel 1544758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); 1545758cc3dcSJack F Vogel return; 1546758cc3dcSJack F Vogel } 1547758cc3dcSJack F Vogel 1548758cc3dcSJack F Vogel /********************************************************************* 1549758cc3dcSJack F Vogel * 1550758cc3dcSJack F Vogel * Media Ioctl callback 1551758cc3dcSJack F Vogel * 1552758cc3dcSJack F Vogel * This routine is called whenever the user queries the status of 1553758cc3dcSJack F Vogel * the interface using ifconfig. 1554758cc3dcSJack F Vogel * 1555758cc3dcSJack F Vogel **********************************************************************/ 1556758cc3dcSJack F Vogel static void 1557758cc3dcSJack F Vogel ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 1558758cc3dcSJack F Vogel { 1559758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 1560758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1561758cc3dcSJack F Vogel int layer; 1562758cc3dcSJack F Vogel 1563758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_media_status: begin"); 1564758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 1565758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 1566758cc3dcSJack F Vogel 1567758cc3dcSJack F Vogel ifmr->ifm_status = IFM_AVALID; 1568758cc3dcSJack F Vogel ifmr->ifm_active = IFM_ETHER; 1569758cc3dcSJack F Vogel 1570758cc3dcSJack F Vogel if (!adapter->link_active) { 1571758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1572758cc3dcSJack F Vogel return; 1573758cc3dcSJack F Vogel } 1574758cc3dcSJack F Vogel 1575758cc3dcSJack F Vogel ifmr->ifm_status |= IFM_ACTIVE; 1576758cc3dcSJack F Vogel layer = ixgbe_get_supported_physical_layer(hw); 1577758cc3dcSJack F Vogel 1578758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T || 1579758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_1000BASE_T || 1580758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) 1581758cc3dcSJack F Vogel switch (adapter->link_speed) { 1582758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1583758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 1584758cc3dcSJack F Vogel break; 1585758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1586758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_T | IFM_FDX; 1587758cc3dcSJack F Vogel break; 1588758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_100_FULL: 1589758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_100_TX | IFM_FDX; 1590758cc3dcSJack F Vogel break; 1591758cc3dcSJack F Vogel } 1592758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || 1593758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) 1594758cc3dcSJack F Vogel switch (adapter->link_speed) { 1595758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1596758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX | IFM_FDX; 1597758cc3dcSJack F Vogel break; 1598758cc3dcSJack F Vogel } 1599758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) 1600758cc3dcSJack F Vogel switch (adapter->link_speed) { 1601758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1602758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_LR | IFM_FDX; 1603758cc3dcSJack F Vogel break; 1604758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1605758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; 1606758cc3dcSJack F Vogel break; 1607758cc3dcSJack F Vogel } 1608758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM) 1609758cc3dcSJack F Vogel switch (adapter->link_speed) { 1610758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1611758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_LRM | IFM_FDX; 1612758cc3dcSJack F Vogel break; 1613758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1614758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; 1615758cc3dcSJack F Vogel break; 1616758cc3dcSJack F Vogel } 1617758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR || 1618758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) 1619758cc3dcSJack F Vogel switch (adapter->link_speed) { 1620758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1621758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; 1622758cc3dcSJack F Vogel break; 1623758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1624758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; 1625758cc3dcSJack F Vogel break; 1626758cc3dcSJack F Vogel } 1627758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) 1628758cc3dcSJack F Vogel switch (adapter->link_speed) { 1629758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1630758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; 1631758cc3dcSJack F Vogel break; 1632758cc3dcSJack F Vogel } 1633758cc3dcSJack F Vogel /* 1634758cc3dcSJack F Vogel ** XXX: These need to use the proper media types once 1635758cc3dcSJack F Vogel ** they're added. 1636758cc3dcSJack F Vogel */ 1637758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) 1638758cc3dcSJack F Vogel switch (adapter->link_speed) { 1639758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1640*6f37f232SEric Joyner ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; 1641*6f37f232SEric Joyner break; 1642*6f37f232SEric Joyner case IXGBE_LINK_SPEED_2_5GB_FULL: 1643*6f37f232SEric Joyner ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; 1644758cc3dcSJack F Vogel break; 1645758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1646*6f37f232SEric Joyner ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; 1647758cc3dcSJack F Vogel break; 1648758cc3dcSJack F Vogel } 1649*6f37f232SEric Joyner else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 1650758cc3dcSJack F Vogel || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) 1651758cc3dcSJack F Vogel switch (adapter->link_speed) { 1652758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1653*6f37f232SEric Joyner ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; 1654*6f37f232SEric Joyner break; 1655*6f37f232SEric Joyner case IXGBE_LINK_SPEED_2_5GB_FULL: 1656*6f37f232SEric Joyner ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; 1657758cc3dcSJack F Vogel break; 1658758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1659*6f37f232SEric Joyner ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; 1660758cc3dcSJack F Vogel break; 1661758cc3dcSJack F Vogel } 1662758cc3dcSJack F Vogel 1663758cc3dcSJack F Vogel /* If nothing is recognized... */ 1664758cc3dcSJack F Vogel if (IFM_SUBTYPE(ifmr->ifm_active) == 0) 1665758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_UNKNOWN; 1666758cc3dcSJack F Vogel 1667758cc3dcSJack F Vogel #if __FreeBSD_version >= 900025 1668*6f37f232SEric Joyner /* Display current flow control setting used on link */ 1669*6f37f232SEric Joyner if (hw->fc.current_mode == ixgbe_fc_rx_pause || 1670*6f37f232SEric Joyner hw->fc.current_mode == ixgbe_fc_full) 1671758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_ETH_RXPAUSE; 1672*6f37f232SEric Joyner if (hw->fc.current_mode == ixgbe_fc_tx_pause || 1673*6f37f232SEric Joyner hw->fc.current_mode == ixgbe_fc_full) 1674758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_ETH_TXPAUSE; 1675758cc3dcSJack F Vogel #endif 1676758cc3dcSJack F Vogel 1677758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1678758cc3dcSJack F Vogel 1679758cc3dcSJack F Vogel return; 1680758cc3dcSJack F Vogel } 1681758cc3dcSJack F Vogel 1682758cc3dcSJack F Vogel /********************************************************************* 1683758cc3dcSJack F Vogel * 1684758cc3dcSJack F Vogel * Media Ioctl callback 1685758cc3dcSJack F Vogel * 1686758cc3dcSJack F Vogel * This routine is called when the user changes speed/duplex using 1687758cc3dcSJack F Vogel * media/mediopt option with ifconfig. 1688758cc3dcSJack F Vogel * 1689758cc3dcSJack F Vogel **********************************************************************/ 1690758cc3dcSJack F Vogel static int 1691758cc3dcSJack F Vogel ixgbe_media_change(struct ifnet * ifp) 1692758cc3dcSJack F Vogel { 1693758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 1694758cc3dcSJack F Vogel struct ifmedia *ifm = &adapter->media; 1695758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1696758cc3dcSJack F Vogel ixgbe_link_speed speed = 0; 1697758cc3dcSJack F Vogel 1698758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_media_change: begin"); 1699758cc3dcSJack F Vogel 1700758cc3dcSJack F Vogel if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1701758cc3dcSJack F Vogel return (EINVAL); 1702758cc3dcSJack F Vogel 1703*6f37f232SEric Joyner if (hw->phy.media_type == ixgbe_media_type_backplane) 1704*6f37f232SEric Joyner return (EPERM); 1705*6f37f232SEric Joyner 1706758cc3dcSJack F Vogel /* 1707758cc3dcSJack F Vogel ** We don't actually need to check against the supported 1708758cc3dcSJack F Vogel ** media types of the adapter; ifmedia will take care of 1709758cc3dcSJack F Vogel ** that for us. 1710758cc3dcSJack F Vogel */ 1711758cc3dcSJack F Vogel switch (IFM_SUBTYPE(ifm->ifm_media)) { 1712758cc3dcSJack F Vogel case IFM_AUTO: 1713758cc3dcSJack F Vogel case IFM_10G_T: 1714758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1715758cc3dcSJack F Vogel case IFM_10G_LRM: 1716758cc3dcSJack F Vogel case IFM_10G_SR: /* KR, too */ 1717758cc3dcSJack F Vogel case IFM_10G_LR: 1718*6f37f232SEric Joyner case IFM_10G_CX4: /* KX4 */ 1719758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 1720758cc3dcSJack F Vogel case IFM_10G_TWINAX: 1721758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_10GB_FULL; 1722758cc3dcSJack F Vogel break; 1723758cc3dcSJack F Vogel case IFM_1000_T: 1724758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1725758cc3dcSJack F Vogel case IFM_1000_LX: 1726758cc3dcSJack F Vogel case IFM_1000_SX: 1727*6f37f232SEric Joyner case IFM_1000_CX: /* KX */ 1728758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 1729758cc3dcSJack F Vogel break; 1730758cc3dcSJack F Vogel case IFM_100_TX: 1731758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1732758cc3dcSJack F Vogel break; 1733758cc3dcSJack F Vogel default: 1734758cc3dcSJack F Vogel goto invalid; 1735758cc3dcSJack F Vogel } 1736758cc3dcSJack F Vogel 1737758cc3dcSJack F Vogel hw->mac.autotry_restart = TRUE; 1738758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, speed, TRUE); 1739758cc3dcSJack F Vogel adapter->advertise = 1740758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_10GB_FULL) << 2) | 1741758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_1GB_FULL) << 1) | 1742758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_100_FULL) << 0); 1743758cc3dcSJack F Vogel 1744758cc3dcSJack F Vogel return (0); 1745758cc3dcSJack F Vogel 1746758cc3dcSJack F Vogel invalid: 1747*6f37f232SEric Joyner device_printf(adapter->dev, "Invalid media type!\n"); 1748758cc3dcSJack F Vogel return (EINVAL); 1749758cc3dcSJack F Vogel } 1750758cc3dcSJack F Vogel 1751758cc3dcSJack F Vogel static void 1752758cc3dcSJack F Vogel ixgbe_set_promisc(struct adapter *adapter) 1753758cc3dcSJack F Vogel { 1754758cc3dcSJack F Vogel u_int32_t reg_rctl; 1755758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1756758cc3dcSJack F Vogel int mcnt = 0; 1757758cc3dcSJack F Vogel 1758758cc3dcSJack F Vogel reg_rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); 1759758cc3dcSJack F Vogel reg_rctl &= (~IXGBE_FCTRL_UPE); 1760758cc3dcSJack F Vogel if (ifp->if_flags & IFF_ALLMULTI) 1761758cc3dcSJack F Vogel mcnt = MAX_NUM_MULTICAST_ADDRESSES; 1762758cc3dcSJack F Vogel else { 1763758cc3dcSJack F Vogel struct ifmultiaddr *ifma; 1764758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1765758cc3dcSJack F Vogel IF_ADDR_LOCK(ifp); 1766758cc3dcSJack F Vogel #else 1767758cc3dcSJack F Vogel if_maddr_rlock(ifp); 1768758cc3dcSJack F Vogel #endif 1769758cc3dcSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1770758cc3dcSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 1771758cc3dcSJack F Vogel continue; 1772758cc3dcSJack F Vogel if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) 1773758cc3dcSJack F Vogel break; 1774758cc3dcSJack F Vogel mcnt++; 1775758cc3dcSJack F Vogel } 1776758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1777758cc3dcSJack F Vogel IF_ADDR_UNLOCK(ifp); 1778758cc3dcSJack F Vogel #else 1779758cc3dcSJack F Vogel if_maddr_runlock(ifp); 1780758cc3dcSJack F Vogel #endif 1781758cc3dcSJack F Vogel } 1782758cc3dcSJack F Vogel if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) 1783758cc3dcSJack F Vogel reg_rctl &= (~IXGBE_FCTRL_MPE); 1784758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 1785758cc3dcSJack F Vogel 1786758cc3dcSJack F Vogel if (ifp->if_flags & IFF_PROMISC) { 1787758cc3dcSJack F Vogel reg_rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1788758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 1789758cc3dcSJack F Vogel } else if (ifp->if_flags & IFF_ALLMULTI) { 1790758cc3dcSJack F Vogel reg_rctl |= IXGBE_FCTRL_MPE; 1791758cc3dcSJack F Vogel reg_rctl &= ~IXGBE_FCTRL_UPE; 1792758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 1793758cc3dcSJack F Vogel } 1794758cc3dcSJack F Vogel return; 1795758cc3dcSJack F Vogel } 1796758cc3dcSJack F Vogel 1797758cc3dcSJack F Vogel 1798758cc3dcSJack F Vogel /********************************************************************* 1799758cc3dcSJack F Vogel * Multicast Update 1800758cc3dcSJack F Vogel * 1801758cc3dcSJack F Vogel * This routine is called whenever multicast address list is updated. 1802758cc3dcSJack F Vogel * 1803758cc3dcSJack F Vogel **********************************************************************/ 1804758cc3dcSJack F Vogel #define IXGBE_RAR_ENTRIES 16 1805758cc3dcSJack F Vogel 1806758cc3dcSJack F Vogel static void 1807758cc3dcSJack F Vogel ixgbe_set_multi(struct adapter *adapter) 1808758cc3dcSJack F Vogel { 1809758cc3dcSJack F Vogel u32 fctrl; 1810758cc3dcSJack F Vogel u8 *mta; 1811758cc3dcSJack F Vogel u8 *update_ptr; 1812758cc3dcSJack F Vogel struct ifmultiaddr *ifma; 1813758cc3dcSJack F Vogel int mcnt = 0; 1814758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1815758cc3dcSJack F Vogel 1816758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); 1817758cc3dcSJack F Vogel 1818758cc3dcSJack F Vogel mta = adapter->mta; 1819758cc3dcSJack F Vogel bzero(mta, sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS * 1820758cc3dcSJack F Vogel MAX_NUM_MULTICAST_ADDRESSES); 1821758cc3dcSJack F Vogel 1822758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1823758cc3dcSJack F Vogel IF_ADDR_LOCK(ifp); 1824758cc3dcSJack F Vogel #else 1825758cc3dcSJack F Vogel if_maddr_rlock(ifp); 1826758cc3dcSJack F Vogel #endif 1827758cc3dcSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1828758cc3dcSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 1829758cc3dcSJack F Vogel continue; 1830758cc3dcSJack F Vogel if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) 1831758cc3dcSJack F Vogel break; 1832758cc3dcSJack F Vogel bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), 1833758cc3dcSJack F Vogel &mta[mcnt * IXGBE_ETH_LENGTH_OF_ADDRESS], 1834758cc3dcSJack F Vogel IXGBE_ETH_LENGTH_OF_ADDRESS); 1835758cc3dcSJack F Vogel mcnt++; 1836758cc3dcSJack F Vogel } 1837758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1838758cc3dcSJack F Vogel IF_ADDR_UNLOCK(ifp); 1839758cc3dcSJack F Vogel #else 1840758cc3dcSJack F Vogel if_maddr_runlock(ifp); 1841758cc3dcSJack F Vogel #endif 1842758cc3dcSJack F Vogel 1843758cc3dcSJack F Vogel fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); 1844758cc3dcSJack F Vogel fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1845758cc3dcSJack F Vogel if (ifp->if_flags & IFF_PROMISC) 1846758cc3dcSJack F Vogel fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1847758cc3dcSJack F Vogel else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES || 1848758cc3dcSJack F Vogel ifp->if_flags & IFF_ALLMULTI) { 1849758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_MPE; 1850758cc3dcSJack F Vogel fctrl &= ~IXGBE_FCTRL_UPE; 1851758cc3dcSJack F Vogel } else 1852758cc3dcSJack F Vogel fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1853758cc3dcSJack F Vogel 1854758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); 1855758cc3dcSJack F Vogel 1856758cc3dcSJack F Vogel if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) { 1857758cc3dcSJack F Vogel update_ptr = mta; 1858758cc3dcSJack F Vogel ixgbe_update_mc_addr_list(&adapter->hw, 1859758cc3dcSJack F Vogel update_ptr, mcnt, ixgbe_mc_array_itr, TRUE); 1860758cc3dcSJack F Vogel } 1861758cc3dcSJack F Vogel 1862758cc3dcSJack F Vogel return; 1863758cc3dcSJack F Vogel } 1864758cc3dcSJack F Vogel 1865758cc3dcSJack F Vogel /* 1866758cc3dcSJack F Vogel * This is an iterator function now needed by the multicast 1867758cc3dcSJack F Vogel * shared code. It simply feeds the shared code routine the 1868758cc3dcSJack F Vogel * addresses in the array of ixgbe_set_multi() one by one. 1869758cc3dcSJack F Vogel */ 1870758cc3dcSJack F Vogel static u8 * 1871758cc3dcSJack F Vogel ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) 1872758cc3dcSJack F Vogel { 1873758cc3dcSJack F Vogel u8 *addr = *update_ptr; 1874758cc3dcSJack F Vogel u8 *newptr; 1875758cc3dcSJack F Vogel *vmdq = 0; 1876758cc3dcSJack F Vogel 1877758cc3dcSJack F Vogel newptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; 1878758cc3dcSJack F Vogel *update_ptr = newptr; 1879758cc3dcSJack F Vogel return addr; 1880758cc3dcSJack F Vogel } 1881758cc3dcSJack F Vogel 1882758cc3dcSJack F Vogel 1883758cc3dcSJack F Vogel /********************************************************************* 1884758cc3dcSJack F Vogel * Timer routine 1885758cc3dcSJack F Vogel * 1886758cc3dcSJack F Vogel * This routine checks for link status,updates statistics, 1887758cc3dcSJack F Vogel * and runs the watchdog check. 1888758cc3dcSJack F Vogel * 1889758cc3dcSJack F Vogel **********************************************************************/ 1890758cc3dcSJack F Vogel 1891758cc3dcSJack F Vogel static void 1892758cc3dcSJack F Vogel ixgbe_local_timer(void *arg) 1893758cc3dcSJack F Vogel { 1894758cc3dcSJack F Vogel struct adapter *adapter = arg; 1895758cc3dcSJack F Vogel device_t dev = adapter->dev; 1896758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 1897758cc3dcSJack F Vogel u64 queues = 0; 1898758cc3dcSJack F Vogel int hung = 0; 1899758cc3dcSJack F Vogel 1900758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 1901758cc3dcSJack F Vogel 1902758cc3dcSJack F Vogel /* Check for pluggable optics */ 1903758cc3dcSJack F Vogel if (adapter->sfp_probe) 1904758cc3dcSJack F Vogel if (!ixgbe_sfp_probe(adapter)) 1905758cc3dcSJack F Vogel goto out; /* Nothing to do */ 1906758cc3dcSJack F Vogel 1907758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 1908758cc3dcSJack F Vogel ixgbe_update_stats_counters(adapter); 1909758cc3dcSJack F Vogel 1910758cc3dcSJack F Vogel /* 1911758cc3dcSJack F Vogel ** Check the TX queues status 1912758cc3dcSJack F Vogel ** - mark hung queues so we don't schedule on them 1913758cc3dcSJack F Vogel ** - watchdog only if all queues show hung 1914758cc3dcSJack F Vogel */ 1915758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 1916758cc3dcSJack F Vogel /* Keep track of queues with work for soft irq */ 1917758cc3dcSJack F Vogel if (que->txr->busy) 1918758cc3dcSJack F Vogel queues |= ((u64)1 << que->me); 1919758cc3dcSJack F Vogel /* 1920758cc3dcSJack F Vogel ** Each time txeof runs without cleaning, but there 1921758cc3dcSJack F Vogel ** are uncleaned descriptors it increments busy. If 1922758cc3dcSJack F Vogel ** we get to the MAX we declare it hung. 1923758cc3dcSJack F Vogel */ 1924758cc3dcSJack F Vogel if (que->busy == IXGBE_QUEUE_HUNG) { 1925758cc3dcSJack F Vogel ++hung; 1926758cc3dcSJack F Vogel /* Mark the queue as inactive */ 1927758cc3dcSJack F Vogel adapter->active_queues &= ~((u64)1 << que->me); 1928758cc3dcSJack F Vogel continue; 1929758cc3dcSJack F Vogel } else { 1930758cc3dcSJack F Vogel /* Check if we've come back from hung */ 1931758cc3dcSJack F Vogel if ((adapter->active_queues & ((u64)1 << que->me)) == 0) 1932758cc3dcSJack F Vogel adapter->active_queues |= ((u64)1 << que->me); 1933758cc3dcSJack F Vogel } 1934758cc3dcSJack F Vogel if (que->busy >= IXGBE_MAX_TX_BUSY) { 1935758cc3dcSJack F Vogel device_printf(dev,"Warning queue %d " 1936758cc3dcSJack F Vogel "appears to be hung!\n", i); 1937758cc3dcSJack F Vogel que->txr->busy = IXGBE_QUEUE_HUNG; 1938758cc3dcSJack F Vogel ++hung; 1939758cc3dcSJack F Vogel } 1940758cc3dcSJack F Vogel 1941758cc3dcSJack F Vogel } 1942758cc3dcSJack F Vogel 1943758cc3dcSJack F Vogel /* Only truly watchdog if all queues show hung */ 1944758cc3dcSJack F Vogel if (hung == adapter->num_queues) 1945758cc3dcSJack F Vogel goto watchdog; 1946758cc3dcSJack F Vogel else if (queues != 0) { /* Force an IRQ on queues with work */ 1947758cc3dcSJack F Vogel ixgbe_rearm_queues(adapter, queues); 1948758cc3dcSJack F Vogel } 1949758cc3dcSJack F Vogel 1950758cc3dcSJack F Vogel out: 1951758cc3dcSJack F Vogel callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); 1952758cc3dcSJack F Vogel return; 1953758cc3dcSJack F Vogel 1954758cc3dcSJack F Vogel watchdog: 1955758cc3dcSJack F Vogel device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); 1956758cc3dcSJack F Vogel adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1957758cc3dcSJack F Vogel adapter->watchdog_events++; 1958758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 1959758cc3dcSJack F Vogel } 1960758cc3dcSJack F Vogel 1961758cc3dcSJack F Vogel /* 1962758cc3dcSJack F Vogel ** Note: this routine updates the OS on the link state 1963758cc3dcSJack F Vogel ** the real check of the hardware only happens with 1964758cc3dcSJack F Vogel ** a link interrupt. 1965758cc3dcSJack F Vogel */ 1966758cc3dcSJack F Vogel static void 1967758cc3dcSJack F Vogel ixgbe_update_link_status(struct adapter *adapter) 1968758cc3dcSJack F Vogel { 1969758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1970758cc3dcSJack F Vogel device_t dev = adapter->dev; 1971758cc3dcSJack F Vogel 1972758cc3dcSJack F Vogel if (adapter->link_up){ 1973758cc3dcSJack F Vogel if (adapter->link_active == FALSE) { 1974758cc3dcSJack F Vogel if (bootverbose) 1975758cc3dcSJack F Vogel device_printf(dev,"Link is up %d Gbps %s \n", 1976758cc3dcSJack F Vogel ((adapter->link_speed == 128)? 10:1), 1977758cc3dcSJack F Vogel "Full Duplex"); 1978758cc3dcSJack F Vogel adapter->link_active = TRUE; 1979758cc3dcSJack F Vogel /* Update any Flow Control changes */ 1980758cc3dcSJack F Vogel ixgbe_fc_enable(&adapter->hw); 1981*6f37f232SEric Joyner /* Update DMA coalescing config */ 1982*6f37f232SEric Joyner ixgbe_config_dmac(adapter); 1983758cc3dcSJack F Vogel if_link_state_change(ifp, LINK_STATE_UP); 1984758cc3dcSJack F Vogel } 1985758cc3dcSJack F Vogel } else { /* Link down */ 1986758cc3dcSJack F Vogel if (adapter->link_active == TRUE) { 1987758cc3dcSJack F Vogel if (bootverbose) 1988758cc3dcSJack F Vogel device_printf(dev,"Link is Down\n"); 1989758cc3dcSJack F Vogel if_link_state_change(ifp, LINK_STATE_DOWN); 1990758cc3dcSJack F Vogel adapter->link_active = FALSE; 1991758cc3dcSJack F Vogel } 1992758cc3dcSJack F Vogel } 1993758cc3dcSJack F Vogel 1994758cc3dcSJack F Vogel return; 1995758cc3dcSJack F Vogel } 1996758cc3dcSJack F Vogel 1997758cc3dcSJack F Vogel 1998758cc3dcSJack F Vogel /********************************************************************* 1999758cc3dcSJack F Vogel * 2000758cc3dcSJack F Vogel * This routine disables all traffic on the adapter by issuing a 2001758cc3dcSJack F Vogel * global reset on the MAC and deallocates TX/RX buffers. 2002758cc3dcSJack F Vogel * 2003758cc3dcSJack F Vogel **********************************************************************/ 2004758cc3dcSJack F Vogel 2005758cc3dcSJack F Vogel static void 2006758cc3dcSJack F Vogel ixgbe_stop(void *arg) 2007758cc3dcSJack F Vogel { 2008758cc3dcSJack F Vogel struct ifnet *ifp; 2009758cc3dcSJack F Vogel struct adapter *adapter = arg; 2010758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2011758cc3dcSJack F Vogel ifp = adapter->ifp; 2012758cc3dcSJack F Vogel 2013758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 2014758cc3dcSJack F Vogel 2015758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_stop: begin\n"); 2016758cc3dcSJack F Vogel ixgbe_disable_intr(adapter); 2017758cc3dcSJack F Vogel callout_stop(&adapter->timer); 2018758cc3dcSJack F Vogel 2019758cc3dcSJack F Vogel /* Let the stack know...*/ 2020758cc3dcSJack F Vogel ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2021758cc3dcSJack F Vogel 2022758cc3dcSJack F Vogel ixgbe_reset_hw(hw); 2023758cc3dcSJack F Vogel hw->adapter_stopped = FALSE; 2024758cc3dcSJack F Vogel ixgbe_stop_adapter(hw); 2025758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82599EB) 2026758cc3dcSJack F Vogel ixgbe_stop_mac_link_on_d3_82599(hw); 2027758cc3dcSJack F Vogel /* Turn off the laser - noop with no optics */ 2028758cc3dcSJack F Vogel ixgbe_disable_tx_laser(hw); 2029758cc3dcSJack F Vogel 2030758cc3dcSJack F Vogel /* Update the stack */ 2031758cc3dcSJack F Vogel adapter->link_up = FALSE; 2032758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 2033758cc3dcSJack F Vogel 2034758cc3dcSJack F Vogel /* reprogram the RAR[0] in case user changed it. */ 2035758cc3dcSJack F Vogel ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); 2036758cc3dcSJack F Vogel 2037758cc3dcSJack F Vogel return; 2038758cc3dcSJack F Vogel } 2039758cc3dcSJack F Vogel 2040758cc3dcSJack F Vogel 2041758cc3dcSJack F Vogel /********************************************************************* 2042758cc3dcSJack F Vogel * 2043758cc3dcSJack F Vogel * Determine hardware revision. 2044758cc3dcSJack F Vogel * 2045758cc3dcSJack F Vogel **********************************************************************/ 2046758cc3dcSJack F Vogel static void 2047758cc3dcSJack F Vogel ixgbe_identify_hardware(struct adapter *adapter) 2048758cc3dcSJack F Vogel { 2049758cc3dcSJack F Vogel device_t dev = adapter->dev; 2050758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2051758cc3dcSJack F Vogel 2052758cc3dcSJack F Vogel /* Save off the information about this board */ 2053758cc3dcSJack F Vogel hw->vendor_id = pci_get_vendor(dev); 2054758cc3dcSJack F Vogel hw->device_id = pci_get_device(dev); 2055758cc3dcSJack F Vogel hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 2056758cc3dcSJack F Vogel hw->subsystem_vendor_id = 2057758cc3dcSJack F Vogel pci_read_config(dev, PCIR_SUBVEND_0, 2); 2058758cc3dcSJack F Vogel hw->subsystem_device_id = 2059758cc3dcSJack F Vogel pci_read_config(dev, PCIR_SUBDEV_0, 2); 2060758cc3dcSJack F Vogel 2061758cc3dcSJack F Vogel /* 2062758cc3dcSJack F Vogel ** Make sure BUSMASTER is set 2063758cc3dcSJack F Vogel */ 2064758cc3dcSJack F Vogel pci_enable_busmaster(dev); 2065758cc3dcSJack F Vogel 2066758cc3dcSJack F Vogel /* We need this here to set the num_segs below */ 2067758cc3dcSJack F Vogel ixgbe_set_mac_type(hw); 2068758cc3dcSJack F Vogel 2069*6f37f232SEric Joyner /* Pick up the 82599 settings */ 2070758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 2071758cc3dcSJack F Vogel hw->phy.smart_speed = ixgbe_smart_speed; 2072758cc3dcSJack F Vogel adapter->num_segs = IXGBE_82599_SCATTER; 2073758cc3dcSJack F Vogel } else 2074758cc3dcSJack F Vogel adapter->num_segs = IXGBE_82598_SCATTER; 2075758cc3dcSJack F Vogel 2076758cc3dcSJack F Vogel return; 2077758cc3dcSJack F Vogel } 2078758cc3dcSJack F Vogel 2079758cc3dcSJack F Vogel /********************************************************************* 2080758cc3dcSJack F Vogel * 2081758cc3dcSJack F Vogel * Determine optic type 2082758cc3dcSJack F Vogel * 2083758cc3dcSJack F Vogel **********************************************************************/ 2084758cc3dcSJack F Vogel static void 2085758cc3dcSJack F Vogel ixgbe_setup_optics(struct adapter *adapter) 2086758cc3dcSJack F Vogel { 2087758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2088758cc3dcSJack F Vogel int layer; 2089758cc3dcSJack F Vogel 2090758cc3dcSJack F Vogel layer = ixgbe_get_supported_physical_layer(hw); 2091758cc3dcSJack F Vogel 2092758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) { 2093758cc3dcSJack F Vogel adapter->optics = IFM_10G_T; 2094758cc3dcSJack F Vogel return; 2095758cc3dcSJack F Vogel } 2096758cc3dcSJack F Vogel 2097758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) { 2098758cc3dcSJack F Vogel adapter->optics = IFM_1000_T; 2099758cc3dcSJack F Vogel return; 2100758cc3dcSJack F Vogel } 2101758cc3dcSJack F Vogel 2102758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) { 2103758cc3dcSJack F Vogel adapter->optics = IFM_1000_SX; 2104758cc3dcSJack F Vogel return; 2105758cc3dcSJack F Vogel } 2106758cc3dcSJack F Vogel 2107758cc3dcSJack F Vogel if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_LR | 2108758cc3dcSJack F Vogel IXGBE_PHYSICAL_LAYER_10GBASE_LRM)) { 2109758cc3dcSJack F Vogel adapter->optics = IFM_10G_LR; 2110758cc3dcSJack F Vogel return; 2111758cc3dcSJack F Vogel } 2112758cc3dcSJack F Vogel 2113758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { 2114758cc3dcSJack F Vogel adapter->optics = IFM_10G_SR; 2115758cc3dcSJack F Vogel return; 2116758cc3dcSJack F Vogel } 2117758cc3dcSJack F Vogel 2118758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU) { 2119758cc3dcSJack F Vogel adapter->optics = IFM_10G_TWINAX; 2120758cc3dcSJack F Vogel return; 2121758cc3dcSJack F Vogel } 2122758cc3dcSJack F Vogel 2123758cc3dcSJack F Vogel if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | 2124758cc3dcSJack F Vogel IXGBE_PHYSICAL_LAYER_10GBASE_CX4)) { 2125758cc3dcSJack F Vogel adapter->optics = IFM_10G_CX4; 2126758cc3dcSJack F Vogel return; 2127758cc3dcSJack F Vogel } 2128758cc3dcSJack F Vogel 2129758cc3dcSJack F Vogel /* If we get here just set the default */ 2130758cc3dcSJack F Vogel adapter->optics = IFM_ETHER | IFM_AUTO; 2131758cc3dcSJack F Vogel return; 2132758cc3dcSJack F Vogel } 2133758cc3dcSJack F Vogel 2134758cc3dcSJack F Vogel /********************************************************************* 2135758cc3dcSJack F Vogel * 2136758cc3dcSJack F Vogel * Setup the Legacy or MSI Interrupt handler 2137758cc3dcSJack F Vogel * 2138758cc3dcSJack F Vogel **********************************************************************/ 2139758cc3dcSJack F Vogel static int 2140758cc3dcSJack F Vogel ixgbe_allocate_legacy(struct adapter *adapter) 2141758cc3dcSJack F Vogel { 2142758cc3dcSJack F Vogel device_t dev = adapter->dev; 2143758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2144758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2145758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2146758cc3dcSJack F Vogel #endif 2147758cc3dcSJack F Vogel int error, rid = 0; 2148758cc3dcSJack F Vogel 2149758cc3dcSJack F Vogel /* MSI RID at 1 */ 2150758cc3dcSJack F Vogel if (adapter->msix == 1) 2151758cc3dcSJack F Vogel rid = 1; 2152758cc3dcSJack F Vogel 2153758cc3dcSJack F Vogel /* We allocate a single interrupt resource */ 2154758cc3dcSJack F Vogel adapter->res = bus_alloc_resource_any(dev, 2155758cc3dcSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 2156758cc3dcSJack F Vogel if (adapter->res == NULL) { 2157758cc3dcSJack F Vogel device_printf(dev, "Unable to allocate bus resource: " 2158758cc3dcSJack F Vogel "interrupt\n"); 2159758cc3dcSJack F Vogel return (ENXIO); 2160758cc3dcSJack F Vogel } 2161758cc3dcSJack F Vogel 2162758cc3dcSJack F Vogel /* 2163758cc3dcSJack F Vogel * Try allocating a fast interrupt and the associated deferred 2164758cc3dcSJack F Vogel * processing contexts. 2165758cc3dcSJack F Vogel */ 2166758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2167758cc3dcSJack F Vogel TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); 2168758cc3dcSJack F Vogel #endif 2169758cc3dcSJack F Vogel TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); 2170758cc3dcSJack F Vogel que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, 2171758cc3dcSJack F Vogel taskqueue_thread_enqueue, &que->tq); 2172758cc3dcSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s ixq", 2173758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2174758cc3dcSJack F Vogel 2175758cc3dcSJack F Vogel /* Tasklets for Link, SFP and Multispeed Fiber */ 2176758cc3dcSJack F Vogel TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); 2177758cc3dcSJack F Vogel TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); 2178758cc3dcSJack F Vogel TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); 2179*6f37f232SEric Joyner TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); 2180758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 2181758cc3dcSJack F Vogel TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); 2182758cc3dcSJack F Vogel #endif 2183758cc3dcSJack F Vogel adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, 2184758cc3dcSJack F Vogel taskqueue_thread_enqueue, &adapter->tq); 2185758cc3dcSJack F Vogel taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", 2186758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2187758cc3dcSJack F Vogel 2188758cc3dcSJack F Vogel if ((error = bus_setup_intr(dev, adapter->res, 2189758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq, 2190758cc3dcSJack F Vogel que, &adapter->tag)) != 0) { 2191758cc3dcSJack F Vogel device_printf(dev, "Failed to register fast interrupt " 2192758cc3dcSJack F Vogel "handler: %d\n", error); 2193758cc3dcSJack F Vogel taskqueue_free(que->tq); 2194758cc3dcSJack F Vogel taskqueue_free(adapter->tq); 2195758cc3dcSJack F Vogel que->tq = NULL; 2196758cc3dcSJack F Vogel adapter->tq = NULL; 2197758cc3dcSJack F Vogel return (error); 2198758cc3dcSJack F Vogel } 2199758cc3dcSJack F Vogel /* For simplicity in the handlers */ 2200758cc3dcSJack F Vogel adapter->active_queues = IXGBE_EIMS_ENABLE_MASK; 2201758cc3dcSJack F Vogel 2202758cc3dcSJack F Vogel return (0); 2203758cc3dcSJack F Vogel } 2204758cc3dcSJack F Vogel 2205758cc3dcSJack F Vogel 2206758cc3dcSJack F Vogel /********************************************************************* 2207758cc3dcSJack F Vogel * 2208758cc3dcSJack F Vogel * Setup MSIX Interrupt resources and handlers 2209758cc3dcSJack F Vogel * 2210758cc3dcSJack F Vogel **********************************************************************/ 2211758cc3dcSJack F Vogel static int 2212758cc3dcSJack F Vogel ixgbe_allocate_msix(struct adapter *adapter) 2213758cc3dcSJack F Vogel { 2214758cc3dcSJack F Vogel device_t dev = adapter->dev; 2215758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2216758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2217758cc3dcSJack F Vogel int error, rid, vector = 0; 2218758cc3dcSJack F Vogel int cpu_id = 0; 2219a1edda90SAdrian Chadd #ifdef RSS 2220a1edda90SAdrian Chadd cpuset_t cpu_mask; 2221a1edda90SAdrian Chadd #endif 2222758cc3dcSJack F Vogel 2223758cc3dcSJack F Vogel #ifdef RSS 2224758cc3dcSJack F Vogel /* 2225758cc3dcSJack F Vogel * If we're doing RSS, the number of queues needs to 2226758cc3dcSJack F Vogel * match the number of RSS buckets that are configured. 2227758cc3dcSJack F Vogel * 2228758cc3dcSJack F Vogel * + If there's more queues than RSS buckets, we'll end 2229758cc3dcSJack F Vogel * up with queues that get no traffic. 2230758cc3dcSJack F Vogel * 2231758cc3dcSJack F Vogel * + If there's more RSS buckets than queues, we'll end 2232758cc3dcSJack F Vogel * up having multiple RSS buckets map to the same queue, 2233758cc3dcSJack F Vogel * so there'll be some contention. 2234758cc3dcSJack F Vogel */ 2235758cc3dcSJack F Vogel if (adapter->num_queues != rss_getnumbuckets()) { 2236758cc3dcSJack F Vogel device_printf(dev, 2237758cc3dcSJack F Vogel "%s: number of queues (%d) != number of RSS buckets (%d)" 2238758cc3dcSJack F Vogel "; performance will be impacted.\n", 2239758cc3dcSJack F Vogel __func__, 2240758cc3dcSJack F Vogel adapter->num_queues, 2241758cc3dcSJack F Vogel rss_getnumbuckets()); 2242758cc3dcSJack F Vogel } 2243758cc3dcSJack F Vogel #endif 2244758cc3dcSJack F Vogel 2245758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { 2246758cc3dcSJack F Vogel rid = vector + 1; 2247758cc3dcSJack F Vogel que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 2248758cc3dcSJack F Vogel RF_SHAREABLE | RF_ACTIVE); 2249758cc3dcSJack F Vogel if (que->res == NULL) { 2250758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate" 2251758cc3dcSJack F Vogel " bus resource: que interrupt [%d]\n", vector); 2252758cc3dcSJack F Vogel return (ENXIO); 2253758cc3dcSJack F Vogel } 2254758cc3dcSJack F Vogel /* Set the handler function */ 2255758cc3dcSJack F Vogel error = bus_setup_intr(dev, que->res, 2256758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 2257758cc3dcSJack F Vogel ixgbe_msix_que, que, &que->tag); 2258758cc3dcSJack F Vogel if (error) { 2259758cc3dcSJack F Vogel que->res = NULL; 2260758cc3dcSJack F Vogel device_printf(dev, "Failed to register QUE handler"); 2261758cc3dcSJack F Vogel return (error); 2262758cc3dcSJack F Vogel } 2263758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504 2264758cc3dcSJack F Vogel bus_describe_intr(dev, que->res, que->tag, "que %d", i); 2265758cc3dcSJack F Vogel #endif 2266758cc3dcSJack F Vogel que->msix = vector; 2267758cc3dcSJack F Vogel adapter->active_queues |= (u64)(1 << que->msix); 2268758cc3dcSJack F Vogel #ifdef RSS 2269758cc3dcSJack F Vogel /* 2270758cc3dcSJack F Vogel * The queue ID is used as the RSS layer bucket ID. 2271758cc3dcSJack F Vogel * We look up the queue ID -> RSS CPU ID and select 2272758cc3dcSJack F Vogel * that. 2273758cc3dcSJack F Vogel */ 2274758cc3dcSJack F Vogel cpu_id = rss_getcpu(i % rss_getnumbuckets()); 2275758cc3dcSJack F Vogel #else 2276758cc3dcSJack F Vogel /* 2277758cc3dcSJack F Vogel * Bind the msix vector, and thus the 2278758cc3dcSJack F Vogel * rings to the corresponding cpu. 2279758cc3dcSJack F Vogel * 2280758cc3dcSJack F Vogel * This just happens to match the default RSS round-robin 2281758cc3dcSJack F Vogel * bucket -> queue -> CPU allocation. 2282758cc3dcSJack F Vogel */ 2283758cc3dcSJack F Vogel if (adapter->num_queues > 1) 2284758cc3dcSJack F Vogel cpu_id = i; 2285758cc3dcSJack F Vogel #endif 2286758cc3dcSJack F Vogel if (adapter->num_queues > 1) 2287758cc3dcSJack F Vogel bus_bind_intr(dev, que->res, cpu_id); 2288758cc3dcSJack F Vogel 2289758cc3dcSJack F Vogel #ifdef RSS 2290758cc3dcSJack F Vogel device_printf(dev, 2291758cc3dcSJack F Vogel "Bound RSS bucket %d to CPU %d\n", 2292758cc3dcSJack F Vogel i, cpu_id); 2293758cc3dcSJack F Vogel #else 2294*6f37f232SEric Joyner if (bootverbose) 2295758cc3dcSJack F Vogel device_printf(dev, 2296758cc3dcSJack F Vogel "Bound queue %d to cpu %d\n", 2297758cc3dcSJack F Vogel i, cpu_id); 2298758cc3dcSJack F Vogel #endif 2299758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2300758cc3dcSJack F Vogel TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); 2301758cc3dcSJack F Vogel #endif 2302758cc3dcSJack F Vogel TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); 2303758cc3dcSJack F Vogel que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, 2304758cc3dcSJack F Vogel taskqueue_thread_enqueue, &que->tq); 2305758cc3dcSJack F Vogel #ifdef RSS 2306a1edda90SAdrian Chadd CPU_SETOF(cpu_id, &cpu_mask); 2307a1edda90SAdrian Chadd taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, 2308a1edda90SAdrian Chadd &cpu_mask, 2309758cc3dcSJack F Vogel "%s (bucket %d)", 2310758cc3dcSJack F Vogel device_get_nameunit(adapter->dev), 2311758cc3dcSJack F Vogel cpu_id); 2312758cc3dcSJack F Vogel #else 2313758cc3dcSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 2314758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2315758cc3dcSJack F Vogel #endif 2316758cc3dcSJack F Vogel } 2317758cc3dcSJack F Vogel 2318758cc3dcSJack F Vogel /* and Link */ 2319758cc3dcSJack F Vogel rid = vector + 1; 2320758cc3dcSJack F Vogel adapter->res = bus_alloc_resource_any(dev, 2321758cc3dcSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 2322758cc3dcSJack F Vogel if (!adapter->res) { 2323758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate" 2324758cc3dcSJack F Vogel " bus resource: Link interrupt [%d]\n", rid); 2325758cc3dcSJack F Vogel return (ENXIO); 2326758cc3dcSJack F Vogel } 2327758cc3dcSJack F Vogel /* Set the link handler function */ 2328758cc3dcSJack F Vogel error = bus_setup_intr(dev, adapter->res, 2329758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 2330758cc3dcSJack F Vogel ixgbe_msix_link, adapter, &adapter->tag); 2331758cc3dcSJack F Vogel if (error) { 2332758cc3dcSJack F Vogel adapter->res = NULL; 2333758cc3dcSJack F Vogel device_printf(dev, "Failed to register LINK handler"); 2334758cc3dcSJack F Vogel return (error); 2335758cc3dcSJack F Vogel } 2336758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504 2337758cc3dcSJack F Vogel bus_describe_intr(dev, adapter->res, adapter->tag, "link"); 2338758cc3dcSJack F Vogel #endif 2339758cc3dcSJack F Vogel adapter->vector = vector; 2340758cc3dcSJack F Vogel /* Tasklets for Link, SFP and Multispeed Fiber */ 2341758cc3dcSJack F Vogel TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); 2342758cc3dcSJack F Vogel TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); 2343758cc3dcSJack F Vogel TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); 2344*6f37f232SEric Joyner TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); 2345758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 2346758cc3dcSJack F Vogel TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); 2347758cc3dcSJack F Vogel #endif 2348758cc3dcSJack F Vogel adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, 2349758cc3dcSJack F Vogel taskqueue_thread_enqueue, &adapter->tq); 2350758cc3dcSJack F Vogel taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", 2351758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2352758cc3dcSJack F Vogel 2353758cc3dcSJack F Vogel return (0); 2354758cc3dcSJack F Vogel } 2355758cc3dcSJack F Vogel 2356758cc3dcSJack F Vogel /* 2357758cc3dcSJack F Vogel * Setup Either MSI/X or MSI 2358758cc3dcSJack F Vogel */ 2359758cc3dcSJack F Vogel static int 2360758cc3dcSJack F Vogel ixgbe_setup_msix(struct adapter *adapter) 2361758cc3dcSJack F Vogel { 2362758cc3dcSJack F Vogel device_t dev = adapter->dev; 2363758cc3dcSJack F Vogel int rid, want, queues, msgs; 2364758cc3dcSJack F Vogel 2365758cc3dcSJack F Vogel /* Override by tuneable */ 2366758cc3dcSJack F Vogel if (ixgbe_enable_msix == 0) 2367758cc3dcSJack F Vogel goto msi; 2368758cc3dcSJack F Vogel 2369758cc3dcSJack F Vogel /* First try MSI/X */ 2370758cc3dcSJack F Vogel msgs = pci_msix_count(dev); 2371758cc3dcSJack F Vogel if (msgs == 0) 2372758cc3dcSJack F Vogel goto msi; 2373758cc3dcSJack F Vogel rid = PCIR_BAR(MSIX_82598_BAR); 2374758cc3dcSJack F Vogel adapter->msix_mem = bus_alloc_resource_any(dev, 2375758cc3dcSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 2376758cc3dcSJack F Vogel if (adapter->msix_mem == NULL) { 2377758cc3dcSJack F Vogel rid += 4; /* 82599 maps in higher BAR */ 2378758cc3dcSJack F Vogel adapter->msix_mem = bus_alloc_resource_any(dev, 2379758cc3dcSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 2380758cc3dcSJack F Vogel } 2381758cc3dcSJack F Vogel if (adapter->msix_mem == NULL) { 2382758cc3dcSJack F Vogel /* May not be enabled */ 2383758cc3dcSJack F Vogel device_printf(adapter->dev, 2384758cc3dcSJack F Vogel "Unable to map MSIX table \n"); 2385758cc3dcSJack F Vogel goto msi; 2386758cc3dcSJack F Vogel } 2387758cc3dcSJack F Vogel 2388758cc3dcSJack F Vogel /* Figure out a reasonable auto config value */ 2389758cc3dcSJack F Vogel queues = (mp_ncpus > (msgs-1)) ? (msgs-1) : mp_ncpus; 2390758cc3dcSJack F Vogel 2391758cc3dcSJack F Vogel #ifdef RSS 2392758cc3dcSJack F Vogel /* If we're doing RSS, clamp at the number of RSS buckets */ 2393758cc3dcSJack F Vogel if (queues > rss_getnumbuckets()) 2394758cc3dcSJack F Vogel queues = rss_getnumbuckets(); 2395758cc3dcSJack F Vogel #endif 2396758cc3dcSJack F Vogel 2397758cc3dcSJack F Vogel if (ixgbe_num_queues != 0) 2398758cc3dcSJack F Vogel queues = ixgbe_num_queues; 2399758cc3dcSJack F Vogel 2400758cc3dcSJack F Vogel /* reflect correct sysctl value */ 2401758cc3dcSJack F Vogel ixgbe_num_queues = queues; 2402758cc3dcSJack F Vogel 2403758cc3dcSJack F Vogel /* 2404758cc3dcSJack F Vogel ** Want one vector (RX/TX pair) per queue 2405758cc3dcSJack F Vogel ** plus an additional for Link. 2406758cc3dcSJack F Vogel */ 2407758cc3dcSJack F Vogel want = queues + 1; 2408758cc3dcSJack F Vogel if (msgs >= want) 2409758cc3dcSJack F Vogel msgs = want; 2410758cc3dcSJack F Vogel else { 2411758cc3dcSJack F Vogel device_printf(adapter->dev, 2412758cc3dcSJack F Vogel "MSIX Configuration Problem, " 2413758cc3dcSJack F Vogel "%d vectors but %d queues wanted!\n", 2414758cc3dcSJack F Vogel msgs, want); 2415758cc3dcSJack F Vogel goto msi; 2416758cc3dcSJack F Vogel } 2417758cc3dcSJack F Vogel if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { 2418758cc3dcSJack F Vogel device_printf(adapter->dev, 2419758cc3dcSJack F Vogel "Using MSIX interrupts with %d vectors\n", msgs); 2420758cc3dcSJack F Vogel adapter->num_queues = queues; 2421758cc3dcSJack F Vogel return (msgs); 2422758cc3dcSJack F Vogel } 2423758cc3dcSJack F Vogel /* 2424758cc3dcSJack F Vogel ** If MSIX alloc failed or provided us with 2425758cc3dcSJack F Vogel ** less than needed, free and fall through to MSI 2426758cc3dcSJack F Vogel */ 2427758cc3dcSJack F Vogel pci_release_msi(dev); 2428758cc3dcSJack F Vogel 2429758cc3dcSJack F Vogel msi: 2430758cc3dcSJack F Vogel if (adapter->msix_mem != NULL) { 2431758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2432758cc3dcSJack F Vogel rid, adapter->msix_mem); 2433758cc3dcSJack F Vogel adapter->msix_mem = NULL; 2434758cc3dcSJack F Vogel } 2435758cc3dcSJack F Vogel msgs = 1; 2436758cc3dcSJack F Vogel if (pci_alloc_msi(dev, &msgs) == 0) { 2437758cc3dcSJack F Vogel device_printf(adapter->dev,"Using an MSI interrupt\n"); 2438758cc3dcSJack F Vogel return (msgs); 2439758cc3dcSJack F Vogel } 2440758cc3dcSJack F Vogel device_printf(adapter->dev,"Using a Legacy interrupt\n"); 2441758cc3dcSJack F Vogel return (0); 2442758cc3dcSJack F Vogel } 2443758cc3dcSJack F Vogel 2444758cc3dcSJack F Vogel 2445758cc3dcSJack F Vogel static int 2446758cc3dcSJack F Vogel ixgbe_allocate_pci_resources(struct adapter *adapter) 2447758cc3dcSJack F Vogel { 2448758cc3dcSJack F Vogel int rid; 2449758cc3dcSJack F Vogel device_t dev = adapter->dev; 2450758cc3dcSJack F Vogel 2451758cc3dcSJack F Vogel rid = PCIR_BAR(0); 2452758cc3dcSJack F Vogel adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2453758cc3dcSJack F Vogel &rid, RF_ACTIVE); 2454758cc3dcSJack F Vogel 2455758cc3dcSJack F Vogel if (!(adapter->pci_mem)) { 2456758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate bus resource: memory\n"); 2457758cc3dcSJack F Vogel return (ENXIO); 2458758cc3dcSJack F Vogel } 2459758cc3dcSJack F Vogel 2460758cc3dcSJack F Vogel adapter->osdep.mem_bus_space_tag = 2461758cc3dcSJack F Vogel rman_get_bustag(adapter->pci_mem); 2462758cc3dcSJack F Vogel adapter->osdep.mem_bus_space_handle = 2463758cc3dcSJack F Vogel rman_get_bushandle(adapter->pci_mem); 2464758cc3dcSJack F Vogel adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle; 2465758cc3dcSJack F Vogel 2466758cc3dcSJack F Vogel /* Legacy defaults */ 2467758cc3dcSJack F Vogel adapter->num_queues = 1; 2468758cc3dcSJack F Vogel adapter->hw.back = &adapter->osdep; 2469758cc3dcSJack F Vogel 2470758cc3dcSJack F Vogel /* 2471758cc3dcSJack F Vogel ** Now setup MSI or MSI/X, should 2472758cc3dcSJack F Vogel ** return us the number of supported 2473758cc3dcSJack F Vogel ** vectors. (Will be 1 for MSI) 2474758cc3dcSJack F Vogel */ 2475758cc3dcSJack F Vogel adapter->msix = ixgbe_setup_msix(adapter); 2476758cc3dcSJack F Vogel return (0); 2477758cc3dcSJack F Vogel } 2478758cc3dcSJack F Vogel 2479758cc3dcSJack F Vogel static void 2480758cc3dcSJack F Vogel ixgbe_free_pci_resources(struct adapter * adapter) 2481758cc3dcSJack F Vogel { 2482758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2483758cc3dcSJack F Vogel device_t dev = adapter->dev; 2484758cc3dcSJack F Vogel int rid, memrid; 2485758cc3dcSJack F Vogel 2486758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) 2487758cc3dcSJack F Vogel memrid = PCIR_BAR(MSIX_82598_BAR); 2488758cc3dcSJack F Vogel else 2489758cc3dcSJack F Vogel memrid = PCIR_BAR(MSIX_82599_BAR); 2490758cc3dcSJack F Vogel 2491758cc3dcSJack F Vogel /* 2492758cc3dcSJack F Vogel ** There is a slight possibility of a failure mode 2493758cc3dcSJack F Vogel ** in attach that will result in entering this function 2494758cc3dcSJack F Vogel ** before interrupt resources have been initialized, and 2495758cc3dcSJack F Vogel ** in that case we do not want to execute the loops below 2496758cc3dcSJack F Vogel ** We can detect this reliably by the state of the adapter 2497758cc3dcSJack F Vogel ** res pointer. 2498758cc3dcSJack F Vogel */ 2499758cc3dcSJack F Vogel if (adapter->res == NULL) 2500758cc3dcSJack F Vogel goto mem; 2501758cc3dcSJack F Vogel 2502758cc3dcSJack F Vogel /* 2503758cc3dcSJack F Vogel ** Release all msix queue resources: 2504758cc3dcSJack F Vogel */ 2505758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 2506758cc3dcSJack F Vogel rid = que->msix + 1; 2507758cc3dcSJack F Vogel if (que->tag != NULL) { 2508758cc3dcSJack F Vogel bus_teardown_intr(dev, que->res, que->tag); 2509758cc3dcSJack F Vogel que->tag = NULL; 2510758cc3dcSJack F Vogel } 2511758cc3dcSJack F Vogel if (que->res != NULL) 2512758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2513758cc3dcSJack F Vogel } 2514758cc3dcSJack F Vogel 2515758cc3dcSJack F Vogel 2516758cc3dcSJack F Vogel /* Clean the Legacy or Link interrupt last */ 2517758cc3dcSJack F Vogel if (adapter->vector) /* we are doing MSIX */ 2518758cc3dcSJack F Vogel rid = adapter->vector + 1; 2519758cc3dcSJack F Vogel else 2520758cc3dcSJack F Vogel (adapter->msix != 0) ? (rid = 1):(rid = 0); 2521758cc3dcSJack F Vogel 2522758cc3dcSJack F Vogel if (adapter->tag != NULL) { 2523758cc3dcSJack F Vogel bus_teardown_intr(dev, adapter->res, adapter->tag); 2524758cc3dcSJack F Vogel adapter->tag = NULL; 2525758cc3dcSJack F Vogel } 2526758cc3dcSJack F Vogel if (adapter->res != NULL) 2527758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); 2528758cc3dcSJack F Vogel 2529758cc3dcSJack F Vogel mem: 2530758cc3dcSJack F Vogel if (adapter->msix) 2531758cc3dcSJack F Vogel pci_release_msi(dev); 2532758cc3dcSJack F Vogel 2533758cc3dcSJack F Vogel if (adapter->msix_mem != NULL) 2534758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2535758cc3dcSJack F Vogel memrid, adapter->msix_mem); 2536758cc3dcSJack F Vogel 2537758cc3dcSJack F Vogel if (adapter->pci_mem != NULL) 2538758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2539758cc3dcSJack F Vogel PCIR_BAR(0), adapter->pci_mem); 2540758cc3dcSJack F Vogel 2541758cc3dcSJack F Vogel return; 2542758cc3dcSJack F Vogel } 2543758cc3dcSJack F Vogel 2544758cc3dcSJack F Vogel /********************************************************************* 2545758cc3dcSJack F Vogel * 2546758cc3dcSJack F Vogel * Setup networking device structure and register an interface. 2547758cc3dcSJack F Vogel * 2548758cc3dcSJack F Vogel **********************************************************************/ 2549758cc3dcSJack F Vogel static int 2550758cc3dcSJack F Vogel ixgbe_setup_interface(device_t dev, struct adapter *adapter) 2551758cc3dcSJack F Vogel { 2552758cc3dcSJack F Vogel struct ifnet *ifp; 2553758cc3dcSJack F Vogel 2554758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_setup_interface: begin"); 2555758cc3dcSJack F Vogel 2556758cc3dcSJack F Vogel ifp = adapter->ifp = if_alloc(IFT_ETHER); 2557758cc3dcSJack F Vogel if (ifp == NULL) { 2558758cc3dcSJack F Vogel device_printf(dev, "can not allocate ifnet structure\n"); 2559758cc3dcSJack F Vogel return (-1); 2560758cc3dcSJack F Vogel } 2561758cc3dcSJack F Vogel if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2562758cc3dcSJack F Vogel ifp->if_baudrate = IF_Gbps(10); 2563758cc3dcSJack F Vogel ifp->if_init = ixgbe_init; 2564758cc3dcSJack F Vogel ifp->if_softc = adapter; 2565758cc3dcSJack F Vogel ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2566758cc3dcSJack F Vogel ifp->if_ioctl = ixgbe_ioctl; 2567758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 2568758cc3dcSJack F Vogel if_setgetcounterfn(ifp, ixgbe_get_counter); 2569758cc3dcSJack F Vogel #endif 2570*6f37f232SEric Joyner #if __FreeBSD_version >= 1100045 2571*6f37f232SEric Joyner /* TSO parameters */ 2572*6f37f232SEric Joyner ifp->if_hw_tsomax = 65518; 2573*6f37f232SEric Joyner ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER; 2574*6f37f232SEric Joyner ifp->if_hw_tsomaxsegsize = 2048; 2575*6f37f232SEric Joyner #endif 2576758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2577758cc3dcSJack F Vogel ifp->if_transmit = ixgbe_mq_start; 2578758cc3dcSJack F Vogel ifp->if_qflush = ixgbe_qflush; 2579758cc3dcSJack F Vogel #else 2580758cc3dcSJack F Vogel ifp->if_start = ixgbe_start; 2581758cc3dcSJack F Vogel IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); 2582758cc3dcSJack F Vogel ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; 2583758cc3dcSJack F Vogel IFQ_SET_READY(&ifp->if_snd); 2584758cc3dcSJack F Vogel #endif 2585758cc3dcSJack F Vogel 2586758cc3dcSJack F Vogel ether_ifattach(ifp, adapter->hw.mac.addr); 2587758cc3dcSJack F Vogel 2588758cc3dcSJack F Vogel adapter->max_frame_size = 2589758cc3dcSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 2590758cc3dcSJack F Vogel 2591758cc3dcSJack F Vogel /* 2592758cc3dcSJack F Vogel * Tell the upper layer(s) we support long frames. 2593758cc3dcSJack F Vogel */ 2594758cc3dcSJack F Vogel ifp->if_hdrlen = sizeof(struct ether_vlan_header); 2595758cc3dcSJack F Vogel 2596758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO | IFCAP_VLAN_HWCSUM; 2597758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_JUMBO_MTU; 2598758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_LRO; 2599758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 2600758cc3dcSJack F Vogel | IFCAP_VLAN_HWTSO 2601758cc3dcSJack F Vogel | IFCAP_VLAN_MTU 2602758cc3dcSJack F Vogel | IFCAP_HWSTATS; 2603758cc3dcSJack F Vogel ifp->if_capenable = ifp->if_capabilities; 2604758cc3dcSJack F Vogel 2605758cc3dcSJack F Vogel /* 2606758cc3dcSJack F Vogel ** Don't turn this on by default, if vlans are 2607758cc3dcSJack F Vogel ** created on another pseudo device (eg. lagg) 2608758cc3dcSJack F Vogel ** then vlan events are not passed thru, breaking 2609758cc3dcSJack F Vogel ** operation, but with HW FILTER off it works. If 2610758cc3dcSJack F Vogel ** using vlans directly on the ixgbe driver you can 2611758cc3dcSJack F Vogel ** enable this and get full hardware tag filtering. 2612758cc3dcSJack F Vogel */ 2613758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 2614758cc3dcSJack F Vogel 2615758cc3dcSJack F Vogel /* 2616758cc3dcSJack F Vogel * Specify the media types supported by this adapter and register 2617758cc3dcSJack F Vogel * callbacks to update media and link information 2618758cc3dcSJack F Vogel */ 2619758cc3dcSJack F Vogel ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change, 2620758cc3dcSJack F Vogel ixgbe_media_status); 2621758cc3dcSJack F Vogel 2622758cc3dcSJack F Vogel ixgbe_add_media_types(adapter); 2623758cc3dcSJack F Vogel 2624758cc3dcSJack F Vogel /* Autoselect media by default */ 2625758cc3dcSJack F Vogel ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); 2626758cc3dcSJack F Vogel 2627758cc3dcSJack F Vogel return (0); 2628758cc3dcSJack F Vogel } 2629758cc3dcSJack F Vogel 2630758cc3dcSJack F Vogel static void 2631758cc3dcSJack F Vogel ixgbe_add_media_types(struct adapter *adapter) 2632758cc3dcSJack F Vogel { 2633758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2634758cc3dcSJack F Vogel device_t dev = adapter->dev; 2635758cc3dcSJack F Vogel int layer; 2636758cc3dcSJack F Vogel 2637758cc3dcSJack F Vogel layer = ixgbe_get_supported_physical_layer(hw); 2638758cc3dcSJack F Vogel 2639758cc3dcSJack F Vogel /* Media types with matching FreeBSD media defines */ 2640758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) 2641758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2642758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) 2643758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); 2644758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) 2645758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2646758cc3dcSJack F Vogel 2647758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || 2648758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) 2649758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2650758cc3dcSJack F Vogel 2651758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) 2652758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2653758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) 2654758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2655758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) 2656758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2657758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) 2658758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 2659758cc3dcSJack F Vogel 2660758cc3dcSJack F Vogel /* 2661758cc3dcSJack F Vogel ** Other (no matching FreeBSD media type): 2662758cc3dcSJack F Vogel ** To workaround this, we'll assign these completely 2663758cc3dcSJack F Vogel ** inappropriate media types. 2664758cc3dcSJack F Vogel */ 2665758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) { 2666758cc3dcSJack F Vogel device_printf(dev, "Media supported: 10GbaseKR\n"); 2667*6f37f232SEric Joyner device_printf(dev, "10GbaseKR mapped to 10GbaseSR\n"); 2668*6f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2669758cc3dcSJack F Vogel } 2670758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) { 2671758cc3dcSJack F Vogel device_printf(dev, "Media supported: 10GbaseKX4\n"); 2672*6f37f232SEric Joyner device_printf(dev, "10GbaseKX4 mapped to 10GbaseCX4\n"); 2673*6f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2674758cc3dcSJack F Vogel } 2675758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) { 2676758cc3dcSJack F Vogel device_printf(dev, "Media supported: 1000baseKX\n"); 2677*6f37f232SEric Joyner device_printf(dev, "1000baseKX mapped to 1000baseCX\n"); 2678*6f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_CX, 0, NULL); 2679758cc3dcSJack F Vogel } 2680758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX) { 2681758cc3dcSJack F Vogel /* Someday, someone will care about you... */ 2682758cc3dcSJack F Vogel device_printf(dev, "Media supported: 1000baseBX\n"); 2683758cc3dcSJack F Vogel } 2684758cc3dcSJack F Vogel 2685758cc3dcSJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) { 2686758cc3dcSJack F Vogel ifmedia_add(&adapter->media, 2687758cc3dcSJack F Vogel IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 2688758cc3dcSJack F Vogel ifmedia_add(&adapter->media, 2689758cc3dcSJack F Vogel IFM_ETHER | IFM_1000_T, 0, NULL); 2690758cc3dcSJack F Vogel } 2691758cc3dcSJack F Vogel 2692758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2693758cc3dcSJack F Vogel } 2694758cc3dcSJack F Vogel 2695758cc3dcSJack F Vogel static void 2696758cc3dcSJack F Vogel ixgbe_config_link(struct adapter *adapter) 2697758cc3dcSJack F Vogel { 2698758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2699758cc3dcSJack F Vogel u32 autoneg, err = 0; 2700758cc3dcSJack F Vogel bool sfp, negotiate; 2701758cc3dcSJack F Vogel 2702758cc3dcSJack F Vogel sfp = ixgbe_is_sfp(hw); 2703758cc3dcSJack F Vogel 2704758cc3dcSJack F Vogel if (sfp) { 2705758cc3dcSJack F Vogel if (hw->phy.multispeed_fiber) { 2706758cc3dcSJack F Vogel hw->mac.ops.setup_sfp(hw); 2707758cc3dcSJack F Vogel ixgbe_enable_tx_laser(hw); 2708758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 2709758cc3dcSJack F Vogel } else 2710758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mod_task); 2711758cc3dcSJack F Vogel } else { 2712758cc3dcSJack F Vogel if (hw->mac.ops.check_link) 2713758cc3dcSJack F Vogel err = ixgbe_check_link(hw, &adapter->link_speed, 2714758cc3dcSJack F Vogel &adapter->link_up, FALSE); 2715758cc3dcSJack F Vogel if (err) 2716758cc3dcSJack F Vogel goto out; 2717758cc3dcSJack F Vogel autoneg = hw->phy.autoneg_advertised; 2718758cc3dcSJack F Vogel if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) 2719758cc3dcSJack F Vogel err = hw->mac.ops.get_link_capabilities(hw, 2720758cc3dcSJack F Vogel &autoneg, &negotiate); 2721758cc3dcSJack F Vogel if (err) 2722758cc3dcSJack F Vogel goto out; 2723758cc3dcSJack F Vogel if (hw->mac.ops.setup_link) 2724758cc3dcSJack F Vogel err = hw->mac.ops.setup_link(hw, 2725758cc3dcSJack F Vogel autoneg, adapter->link_up); 2726758cc3dcSJack F Vogel } 2727758cc3dcSJack F Vogel out: 2728758cc3dcSJack F Vogel return; 2729758cc3dcSJack F Vogel } 2730758cc3dcSJack F Vogel 2731758cc3dcSJack F Vogel 2732758cc3dcSJack F Vogel /********************************************************************* 2733758cc3dcSJack F Vogel * 2734758cc3dcSJack F Vogel * Enable transmit units. 2735758cc3dcSJack F Vogel * 2736758cc3dcSJack F Vogel **********************************************************************/ 2737758cc3dcSJack F Vogel static void 2738758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(struct adapter *adapter) 2739758cc3dcSJack F Vogel { 2740758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2741758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2742758cc3dcSJack F Vogel 2743758cc3dcSJack F Vogel /* Setup the Base and Length of the Tx Descriptor Ring */ 2744758cc3dcSJack F Vogel 2745758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, txr++) { 2746758cc3dcSJack F Vogel u64 tdba = txr->txdma.dma_paddr; 2747758cc3dcSJack F Vogel u32 txctrl = 0; 2748758cc3dcSJack F Vogel 2749758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), 2750758cc3dcSJack F Vogel (tdba & 0x00000000ffffffffULL)); 2751758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (tdba >> 32)); 2752758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i), 2753758cc3dcSJack F Vogel adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc)); 2754758cc3dcSJack F Vogel 2755758cc3dcSJack F Vogel /* Setup the HW Tx Head and Tail descriptor pointers */ 2756758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0); 2757758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0); 2758758cc3dcSJack F Vogel 2759758cc3dcSJack F Vogel /* Cache the tail address */ 2760758cc3dcSJack F Vogel txr->tail = IXGBE_TDT(txr->me); 2761758cc3dcSJack F Vogel 2762758cc3dcSJack F Vogel /* Set the processing limit */ 2763758cc3dcSJack F Vogel txr->process_limit = ixgbe_tx_process_limit; 2764758cc3dcSJack F Vogel 2765758cc3dcSJack F Vogel /* Disable Head Writeback */ 2766758cc3dcSJack F Vogel switch (hw->mac.type) { 2767758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 2768758cc3dcSJack F Vogel txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); 2769758cc3dcSJack F Vogel break; 2770758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 2771758cc3dcSJack F Vogel case ixgbe_mac_X540: 2772758cc3dcSJack F Vogel default: 2773758cc3dcSJack F Vogel txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i)); 2774758cc3dcSJack F Vogel break; 2775758cc3dcSJack F Vogel } 2776758cc3dcSJack F Vogel txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; 2777758cc3dcSJack F Vogel switch (hw->mac.type) { 2778758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 2779758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl); 2780758cc3dcSJack F Vogel break; 2781758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 2782758cc3dcSJack F Vogel case ixgbe_mac_X540: 2783758cc3dcSJack F Vogel default: 2784758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(i), txctrl); 2785758cc3dcSJack F Vogel break; 2786758cc3dcSJack F Vogel } 2787758cc3dcSJack F Vogel 2788758cc3dcSJack F Vogel } 2789758cc3dcSJack F Vogel 2790758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 2791758cc3dcSJack F Vogel u32 dmatxctl, rttdcs; 2792758cc3dcSJack F Vogel dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); 2793758cc3dcSJack F Vogel dmatxctl |= IXGBE_DMATXCTL_TE; 2794758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); 2795758cc3dcSJack F Vogel /* Disable arbiter to set MTQC */ 2796758cc3dcSJack F Vogel rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); 2797758cc3dcSJack F Vogel rttdcs |= IXGBE_RTTDCS_ARBDIS; 2798758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); 2799758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); 2800758cc3dcSJack F Vogel rttdcs &= ~IXGBE_RTTDCS_ARBDIS; 2801758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); 2802758cc3dcSJack F Vogel } 2803758cc3dcSJack F Vogel 2804758cc3dcSJack F Vogel return; 2805758cc3dcSJack F Vogel } 2806758cc3dcSJack F Vogel 2807758cc3dcSJack F Vogel static void 2808758cc3dcSJack F Vogel ixgbe_initialise_rss_mapping(struct adapter *adapter) 2809758cc3dcSJack F Vogel { 2810758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2811758cc3dcSJack F Vogel uint32_t reta; 2812*6f37f232SEric Joyner int i, j, queue_id, table_size; 2813*6f37f232SEric Joyner int index_mult; 2814758cc3dcSJack F Vogel uint32_t rss_key[10]; 2815758cc3dcSJack F Vogel uint32_t mrqc; 2816758cc3dcSJack F Vogel #ifdef RSS 2817758cc3dcSJack F Vogel uint32_t rss_hash_config; 2818758cc3dcSJack F Vogel #endif 2819758cc3dcSJack F Vogel 2820758cc3dcSJack F Vogel /* Setup RSS */ 2821758cc3dcSJack F Vogel reta = 0; 2822758cc3dcSJack F Vogel 2823758cc3dcSJack F Vogel #ifdef RSS 2824758cc3dcSJack F Vogel /* Fetch the configured RSS key */ 2825758cc3dcSJack F Vogel rss_getkey((uint8_t *) &rss_key); 2826758cc3dcSJack F Vogel #else 2827758cc3dcSJack F Vogel /* set up random bits */ 2828758cc3dcSJack F Vogel arc4rand(&rss_key, sizeof(rss_key), 0); 2829758cc3dcSJack F Vogel #endif 2830758cc3dcSJack F Vogel 2831*6f37f232SEric Joyner /* Set multiplier for RETA setup and table size based on MAC */ 2832*6f37f232SEric Joyner index_mult = 0x1; 2833*6f37f232SEric Joyner table_size = 128; 2834*6f37f232SEric Joyner switch (adapter->hw.mac.type) { 2835*6f37f232SEric Joyner case ixgbe_mac_82598EB: 2836*6f37f232SEric Joyner index_mult = 0x11; 2837*6f37f232SEric Joyner break; 2838*6f37f232SEric Joyner case ixgbe_mac_X550: 2839*6f37f232SEric Joyner case ixgbe_mac_X550EM_x: 2840*6f37f232SEric Joyner table_size = 512; 2841*6f37f232SEric Joyner break; 2842*6f37f232SEric Joyner default: 2843*6f37f232SEric Joyner break; 2844*6f37f232SEric Joyner } 2845*6f37f232SEric Joyner 2846758cc3dcSJack F Vogel /* Set up the redirection table */ 2847*6f37f232SEric Joyner for (i = 0, j = 0; i < table_size; i++, j++) { 2848758cc3dcSJack F Vogel if (j == adapter->num_queues) j = 0; 2849758cc3dcSJack F Vogel #ifdef RSS 2850758cc3dcSJack F Vogel /* 2851758cc3dcSJack F Vogel * Fetch the RSS bucket id for the given indirection entry. 2852758cc3dcSJack F Vogel * Cap it at the number of configured buckets (which is 2853758cc3dcSJack F Vogel * num_queues.) 2854758cc3dcSJack F Vogel */ 2855758cc3dcSJack F Vogel queue_id = rss_get_indirection_to_bucket(i); 2856758cc3dcSJack F Vogel queue_id = queue_id % adapter->num_queues; 2857758cc3dcSJack F Vogel #else 2858*6f37f232SEric Joyner queue_id = (j * index_mult); 2859758cc3dcSJack F Vogel #endif 2860758cc3dcSJack F Vogel /* 2861758cc3dcSJack F Vogel * The low 8 bits are for hash value (n+0); 2862758cc3dcSJack F Vogel * The next 8 bits are for hash value (n+1), etc. 2863758cc3dcSJack F Vogel */ 2864758cc3dcSJack F Vogel reta = reta >> 8; 2865758cc3dcSJack F Vogel reta = reta | ( ((uint32_t) queue_id) << 24); 2866758cc3dcSJack F Vogel if ((i & 3) == 3) { 2867*6f37f232SEric Joyner if (i < 128) 2868758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); 2869*6f37f232SEric Joyner else 2870*6f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), reta); 2871758cc3dcSJack F Vogel reta = 0; 2872758cc3dcSJack F Vogel } 2873758cc3dcSJack F Vogel } 2874758cc3dcSJack F Vogel 2875758cc3dcSJack F Vogel /* Now fill our hash function seeds */ 2876758cc3dcSJack F Vogel for (int i = 0; i < 10; i++) 2877758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); 2878758cc3dcSJack F Vogel 2879758cc3dcSJack F Vogel /* Perform hash on these packet types */ 2880758cc3dcSJack F Vogel #ifdef RSS 2881758cc3dcSJack F Vogel mrqc = IXGBE_MRQC_RSSEN; 2882758cc3dcSJack F Vogel rss_hash_config = rss_gethashconfig(); 2883758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 2884758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; 2885758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 2886758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; 2887758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 2888758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; 2889758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 2890758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; 2891758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 2892758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX; 2893758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) 2894758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP; 2895758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 2896758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; 2897758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) 2898758cc3dcSJack F Vogel device_printf(adapter->dev, 2899758cc3dcSJack F Vogel "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, " 2900758cc3dcSJack F Vogel "but not supported\n", __func__); 2901758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 2902758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; 2903758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) 2904758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 2905758cc3dcSJack F Vogel #else 2906758cc3dcSJack F Vogel /* 2907758cc3dcSJack F Vogel * Disable UDP - IP fragments aren't currently being handled 2908758cc3dcSJack F Vogel * and so we end up with a mix of 2-tuple and 4-tuple 2909758cc3dcSJack F Vogel * traffic. 2910758cc3dcSJack F Vogel */ 2911758cc3dcSJack F Vogel mrqc = IXGBE_MRQC_RSSEN 2912758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4 2913758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4_TCP 2914758cc3dcSJack F Vogel #if 0 2915758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4_UDP 2916758cc3dcSJack F Vogel #endif 2917758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP 2918758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX 2919758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6 2920758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_TCP 2921758cc3dcSJack F Vogel #if 0 2922758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_UDP 2923758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP 2924758cc3dcSJack F Vogel #endif 2925758cc3dcSJack F Vogel ; 2926758cc3dcSJack F Vogel #endif /* RSS */ 2927758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 2928758cc3dcSJack F Vogel } 2929758cc3dcSJack F Vogel 2930758cc3dcSJack F Vogel 2931758cc3dcSJack F Vogel /********************************************************************* 2932758cc3dcSJack F Vogel * 2933758cc3dcSJack F Vogel * Setup receive registers and features. 2934758cc3dcSJack F Vogel * 2935758cc3dcSJack F Vogel **********************************************************************/ 2936758cc3dcSJack F Vogel #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 2937758cc3dcSJack F Vogel 2938758cc3dcSJack F Vogel #define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1) 2939758cc3dcSJack F Vogel 2940758cc3dcSJack F Vogel static void 2941758cc3dcSJack F Vogel ixgbe_initialize_receive_units(struct adapter *adapter) 2942758cc3dcSJack F Vogel { 2943758cc3dcSJack F Vogel struct rx_ring *rxr = adapter->rx_rings; 2944758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2945758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 2946758cc3dcSJack F Vogel u32 bufsz, fctrl, srrctl, rxcsum; 2947758cc3dcSJack F Vogel u32 hlreg; 2948758cc3dcSJack F Vogel 2949758cc3dcSJack F Vogel 2950758cc3dcSJack F Vogel /* 2951758cc3dcSJack F Vogel * Make sure receives are disabled while 2952758cc3dcSJack F Vogel * setting up the descriptor ring 2953758cc3dcSJack F Vogel */ 2954758cc3dcSJack F Vogel ixgbe_disable_rx(hw); 2955758cc3dcSJack F Vogel 2956758cc3dcSJack F Vogel /* Enable broadcasts */ 2957758cc3dcSJack F Vogel fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); 2958758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_BAM; 2959*6f37f232SEric Joyner if (adapter->hw.mac.type == ixgbe_mac_82598EB) { 2960758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_DPF; 2961758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_PMCF; 2962*6f37f232SEric Joyner } 2963758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); 2964758cc3dcSJack F Vogel 2965758cc3dcSJack F Vogel /* Set for Jumbo Frames? */ 2966758cc3dcSJack F Vogel hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); 2967758cc3dcSJack F Vogel if (ifp->if_mtu > ETHERMTU) 2968758cc3dcSJack F Vogel hlreg |= IXGBE_HLREG0_JUMBOEN; 2969758cc3dcSJack F Vogel else 2970758cc3dcSJack F Vogel hlreg &= ~IXGBE_HLREG0_JUMBOEN; 2971758cc3dcSJack F Vogel #ifdef DEV_NETMAP 2972758cc3dcSJack F Vogel /* crcstrip is conditional in netmap (in RDRXCTL too ?) */ 2973758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip) 2974758cc3dcSJack F Vogel hlreg &= ~IXGBE_HLREG0_RXCRCSTRP; 2975758cc3dcSJack F Vogel else 2976758cc3dcSJack F Vogel hlreg |= IXGBE_HLREG0_RXCRCSTRP; 2977758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 2978758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); 2979758cc3dcSJack F Vogel 2980758cc3dcSJack F Vogel bufsz = (adapter->rx_mbuf_sz + 2981758cc3dcSJack F Vogel BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; 2982758cc3dcSJack F Vogel 2983758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, rxr++) { 2984758cc3dcSJack F Vogel u64 rdba = rxr->rxdma.dma_paddr; 2985758cc3dcSJack F Vogel 2986758cc3dcSJack F Vogel /* Setup the Base and Length of the Rx Descriptor Ring */ 2987758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), 2988758cc3dcSJack F Vogel (rdba & 0x00000000ffffffffULL)); 2989758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32)); 2990758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), 2991758cc3dcSJack F Vogel adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); 2992758cc3dcSJack F Vogel 2993758cc3dcSJack F Vogel /* Set up the SRRCTL register */ 2994758cc3dcSJack F Vogel srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); 2995758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; 2996758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; 2997758cc3dcSJack F Vogel srrctl |= bufsz; 2998758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; 2999758cc3dcSJack F Vogel 3000758cc3dcSJack F Vogel /* 3001758cc3dcSJack F Vogel * Set DROP_EN iff we have no flow control and >1 queue. 3002758cc3dcSJack F Vogel * Note that srrctl was cleared shortly before during reset, 3003758cc3dcSJack F Vogel * so we do not need to clear the bit, but do it just in case 3004758cc3dcSJack F Vogel * this code is moved elsewhere. 3005758cc3dcSJack F Vogel */ 3006758cc3dcSJack F Vogel if (adapter->num_queues > 1 && 3007758cc3dcSJack F Vogel adapter->hw.fc.requested_mode == ixgbe_fc_none) { 3008758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DROP_EN; 3009758cc3dcSJack F Vogel } else { 3010758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_DROP_EN; 3011758cc3dcSJack F Vogel } 3012758cc3dcSJack F Vogel 3013758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); 3014758cc3dcSJack F Vogel 3015758cc3dcSJack F Vogel /* Setup the HW Rx Head and Tail Descriptor Pointers */ 3016758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0); 3017758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0); 3018758cc3dcSJack F Vogel 3019758cc3dcSJack F Vogel /* Set the processing limit */ 3020758cc3dcSJack F Vogel rxr->process_limit = ixgbe_rx_process_limit; 3021758cc3dcSJack F Vogel 3022758cc3dcSJack F Vogel /* Set the driver rx tail address */ 3023758cc3dcSJack F Vogel rxr->tail = IXGBE_RDT(rxr->me); 3024758cc3dcSJack F Vogel } 3025758cc3dcSJack F Vogel 3026758cc3dcSJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82598EB) { 3027758cc3dcSJack F Vogel u32 psrtype = IXGBE_PSRTYPE_TCPHDR | 3028758cc3dcSJack F Vogel IXGBE_PSRTYPE_UDPHDR | 3029758cc3dcSJack F Vogel IXGBE_PSRTYPE_IPV4HDR | 3030758cc3dcSJack F Vogel IXGBE_PSRTYPE_IPV6HDR; 3031758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); 3032758cc3dcSJack F Vogel } 3033758cc3dcSJack F Vogel 3034758cc3dcSJack F Vogel rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 3035758cc3dcSJack F Vogel 3036758cc3dcSJack F Vogel ixgbe_initialise_rss_mapping(adapter); 3037758cc3dcSJack F Vogel 3038758cc3dcSJack F Vogel if (adapter->num_queues > 1) { 3039758cc3dcSJack F Vogel /* RSS and RX IPP Checksum are mutually exclusive */ 3040758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_PCSD; 3041758cc3dcSJack F Vogel } 3042758cc3dcSJack F Vogel 3043758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_RXCSUM) 3044758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_PCSD; 3045758cc3dcSJack F Vogel 3046758cc3dcSJack F Vogel if (!(rxcsum & IXGBE_RXCSUM_PCSD)) 3047758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_IPPCSE; 3048758cc3dcSJack F Vogel 3049758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); 3050758cc3dcSJack F Vogel 3051758cc3dcSJack F Vogel return; 3052758cc3dcSJack F Vogel } 3053758cc3dcSJack F Vogel 3054758cc3dcSJack F Vogel 3055758cc3dcSJack F Vogel /* 3056758cc3dcSJack F Vogel ** This routine is run via an vlan config EVENT, 3057758cc3dcSJack F Vogel ** it enables us to use the HW Filter table since 3058758cc3dcSJack F Vogel ** we can get the vlan id. This just creates the 3059758cc3dcSJack F Vogel ** entry in the soft version of the VFTA, init will 3060758cc3dcSJack F Vogel ** repopulate the real table. 3061758cc3dcSJack F Vogel */ 3062758cc3dcSJack F Vogel static void 3063758cc3dcSJack F Vogel ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3064758cc3dcSJack F Vogel { 3065758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 3066758cc3dcSJack F Vogel u16 index, bit; 3067758cc3dcSJack F Vogel 3068758cc3dcSJack F Vogel if (ifp->if_softc != arg) /* Not our event */ 3069758cc3dcSJack F Vogel return; 3070758cc3dcSJack F Vogel 3071758cc3dcSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3072758cc3dcSJack F Vogel return; 3073758cc3dcSJack F Vogel 3074758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 3075758cc3dcSJack F Vogel index = (vtag >> 5) & 0x7F; 3076758cc3dcSJack F Vogel bit = vtag & 0x1F; 3077758cc3dcSJack F Vogel adapter->shadow_vfta[index] |= (1 << bit); 3078758cc3dcSJack F Vogel ++adapter->num_vlans; 3079758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 3080758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 3081758cc3dcSJack F Vogel } 3082758cc3dcSJack F Vogel 3083758cc3dcSJack F Vogel /* 3084758cc3dcSJack F Vogel ** This routine is run via an vlan 3085758cc3dcSJack F Vogel ** unconfig EVENT, remove our entry 3086758cc3dcSJack F Vogel ** in the soft vfta. 3087758cc3dcSJack F Vogel */ 3088758cc3dcSJack F Vogel static void 3089758cc3dcSJack F Vogel ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3090758cc3dcSJack F Vogel { 3091758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 3092758cc3dcSJack F Vogel u16 index, bit; 3093758cc3dcSJack F Vogel 3094758cc3dcSJack F Vogel if (ifp->if_softc != arg) 3095758cc3dcSJack F Vogel return; 3096758cc3dcSJack F Vogel 3097758cc3dcSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3098758cc3dcSJack F Vogel return; 3099758cc3dcSJack F Vogel 3100758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 3101758cc3dcSJack F Vogel index = (vtag >> 5) & 0x7F; 3102758cc3dcSJack F Vogel bit = vtag & 0x1F; 3103758cc3dcSJack F Vogel adapter->shadow_vfta[index] &= ~(1 << bit); 3104758cc3dcSJack F Vogel --adapter->num_vlans; 3105758cc3dcSJack F Vogel /* Re-init to load the changes */ 3106758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 3107758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 3108758cc3dcSJack F Vogel } 3109758cc3dcSJack F Vogel 3110758cc3dcSJack F Vogel static void 3111758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(struct adapter *adapter) 3112758cc3dcSJack F Vogel { 3113758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3114758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3115758cc3dcSJack F Vogel struct rx_ring *rxr; 3116758cc3dcSJack F Vogel u32 ctrl; 3117758cc3dcSJack F Vogel 3118758cc3dcSJack F Vogel 3119758cc3dcSJack F Vogel /* 3120758cc3dcSJack F Vogel ** We get here thru init_locked, meaning 3121758cc3dcSJack F Vogel ** a soft reset, this has already cleared 3122758cc3dcSJack F Vogel ** the VFTA and other state, so if there 3123758cc3dcSJack F Vogel ** have been no vlan's registered do nothing. 3124758cc3dcSJack F Vogel */ 3125758cc3dcSJack F Vogel if (adapter->num_vlans == 0) 3126758cc3dcSJack F Vogel return; 3127758cc3dcSJack F Vogel 3128758cc3dcSJack F Vogel /* Setup the queues for vlans */ 3129758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 3130758cc3dcSJack F Vogel rxr = &adapter->rx_rings[i]; 3131758cc3dcSJack F Vogel /* On 82599 the VLAN enable is per/queue in RXDCTL */ 3132758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 3133758cc3dcSJack F Vogel ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); 3134758cc3dcSJack F Vogel ctrl |= IXGBE_RXDCTL_VME; 3135758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), ctrl); 3136758cc3dcSJack F Vogel } 3137758cc3dcSJack F Vogel rxr->vtag_strip = TRUE; 3138758cc3dcSJack F Vogel } 3139758cc3dcSJack F Vogel 3140758cc3dcSJack F Vogel if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0) 3141758cc3dcSJack F Vogel return; 3142758cc3dcSJack F Vogel /* 3143758cc3dcSJack F Vogel ** A soft reset zero's out the VFTA, so 3144758cc3dcSJack F Vogel ** we need to repopulate it now. 3145758cc3dcSJack F Vogel */ 3146758cc3dcSJack F Vogel for (int i = 0; i < IXGBE_VFTA_SIZE; i++) 3147758cc3dcSJack F Vogel if (adapter->shadow_vfta[i] != 0) 3148758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), 3149758cc3dcSJack F Vogel adapter->shadow_vfta[i]); 3150758cc3dcSJack F Vogel 3151758cc3dcSJack F Vogel ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); 3152758cc3dcSJack F Vogel /* Enable the Filter Table if enabled */ 3153758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) { 3154758cc3dcSJack F Vogel ctrl &= ~IXGBE_VLNCTRL_CFIEN; 3155758cc3dcSJack F Vogel ctrl |= IXGBE_VLNCTRL_VFE; 3156758cc3dcSJack F Vogel } 3157758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 3158758cc3dcSJack F Vogel ctrl |= IXGBE_VLNCTRL_VME; 3159758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); 3160758cc3dcSJack F Vogel } 3161758cc3dcSJack F Vogel 3162758cc3dcSJack F Vogel static void 3163758cc3dcSJack F Vogel ixgbe_enable_intr(struct adapter *adapter) 3164758cc3dcSJack F Vogel { 3165758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3166758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 3167758cc3dcSJack F Vogel u32 mask, fwsm; 3168758cc3dcSJack F Vogel 3169758cc3dcSJack F Vogel mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); 3170758cc3dcSJack F Vogel /* Enable Fan Failure detection */ 3171758cc3dcSJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) 3172*6f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP1; 3173758cc3dcSJack F Vogel 3174758cc3dcSJack F Vogel switch (adapter->hw.mac.type) { 3175758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 3176758cc3dcSJack F Vogel mask |= IXGBE_EIMS_ECC; 3177758cc3dcSJack F Vogel /* Temperature sensor on some adapters */ 3178*6f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP0; 3179758cc3dcSJack F Vogel /* SFP+ (RX_LOS_N & MOD_ABS_N) */ 3180*6f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP1; 3181*6f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP2; 3182758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3183758cc3dcSJack F Vogel mask |= IXGBE_EIMS_FLOW_DIR; 3184758cc3dcSJack F Vogel #endif 3185758cc3dcSJack F Vogel break; 3186758cc3dcSJack F Vogel case ixgbe_mac_X540: 3187758cc3dcSJack F Vogel /* Detect if Thermal Sensor is enabled */ 3188758cc3dcSJack F Vogel fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); 3189758cc3dcSJack F Vogel if (fwsm & IXGBE_FWSM_TS_ENABLED) 3190758cc3dcSJack F Vogel mask |= IXGBE_EIMS_TS; 3191*6f37f232SEric Joyner mask |= IXGBE_EIMS_ECC; 3192*6f37f232SEric Joyner #ifdef IXGBE_FDIR 3193*6f37f232SEric Joyner mask |= IXGBE_EIMS_FLOW_DIR; 3194*6f37f232SEric Joyner #endif 3195*6f37f232SEric Joyner break; 3196*6f37f232SEric Joyner case ixgbe_mac_X550: 3197*6f37f232SEric Joyner case ixgbe_mac_X550EM_x: 3198*6f37f232SEric Joyner /* MAC thermal sensor is automatically enabled */ 3199*6f37f232SEric Joyner mask |= IXGBE_EIMS_TS; 3200*6f37f232SEric Joyner /* Some devices use SDP0 for important information */ 3201*6f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || 3202*6f37f232SEric Joyner hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) 3203758cc3dcSJack F Vogel mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); 3204758cc3dcSJack F Vogel mask |= IXGBE_EIMS_ECC; 3205758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3206758cc3dcSJack F Vogel mask |= IXGBE_EIMS_FLOW_DIR; 3207758cc3dcSJack F Vogel #endif 3208758cc3dcSJack F Vogel /* falls through */ 3209758cc3dcSJack F Vogel default: 3210758cc3dcSJack F Vogel break; 3211758cc3dcSJack F Vogel } 3212758cc3dcSJack F Vogel 3213758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); 3214758cc3dcSJack F Vogel 3215*6f37f232SEric Joyner /* With MSI-X we use auto clear */ 3216758cc3dcSJack F Vogel if (adapter->msix_mem) { 3217758cc3dcSJack F Vogel mask = IXGBE_EIMS_ENABLE_MASK; 3218758cc3dcSJack F Vogel /* Don't autoclear Link */ 3219758cc3dcSJack F Vogel mask &= ~IXGBE_EIMS_OTHER; 3220758cc3dcSJack F Vogel mask &= ~IXGBE_EIMS_LSC; 3221758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); 3222758cc3dcSJack F Vogel } 3223758cc3dcSJack F Vogel 3224758cc3dcSJack F Vogel /* 3225758cc3dcSJack F Vogel ** Now enable all queues, this is done separately to 3226758cc3dcSJack F Vogel ** allow for handling the extended (beyond 32) MSIX 3227758cc3dcSJack F Vogel ** vectors that can be used by 82599 3228758cc3dcSJack F Vogel */ 3229758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) 3230758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 3231758cc3dcSJack F Vogel 3232758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(hw); 3233758cc3dcSJack F Vogel 3234758cc3dcSJack F Vogel return; 3235758cc3dcSJack F Vogel } 3236758cc3dcSJack F Vogel 3237758cc3dcSJack F Vogel static void 3238758cc3dcSJack F Vogel ixgbe_disable_intr(struct adapter *adapter) 3239758cc3dcSJack F Vogel { 3240758cc3dcSJack F Vogel if (adapter->msix_mem) 3241758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, 0); 3242758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) { 3243758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); 3244758cc3dcSJack F Vogel } else { 3245758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000); 3246758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0); 3247758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0); 3248758cc3dcSJack F Vogel } 3249758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(&adapter->hw); 3250758cc3dcSJack F Vogel return; 3251758cc3dcSJack F Vogel } 3252758cc3dcSJack F Vogel 3253758cc3dcSJack F Vogel /* 3254758cc3dcSJack F Vogel ** Get the width and transaction speed of 3255758cc3dcSJack F Vogel ** the slot this adapter is plugged into. 3256758cc3dcSJack F Vogel */ 3257758cc3dcSJack F Vogel static void 3258758cc3dcSJack F Vogel ixgbe_get_slot_info(struct ixgbe_hw *hw) 3259758cc3dcSJack F Vogel { 3260758cc3dcSJack F Vogel device_t dev = ((struct ixgbe_osdep *)hw->back)->dev; 3261758cc3dcSJack F Vogel struct ixgbe_mac_info *mac = &hw->mac; 3262758cc3dcSJack F Vogel u16 link; 3263758cc3dcSJack F Vogel u32 offset; 3264758cc3dcSJack F Vogel 3265758cc3dcSJack F Vogel /* For most devices simply call the shared code routine */ 3266758cc3dcSJack F Vogel if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) { 3267758cc3dcSJack F Vogel ixgbe_get_bus_info(hw); 3268758cc3dcSJack F Vogel /* These devices don't use PCI-E */ 3269*6f37f232SEric Joyner switch (hw->mac.type) { 3270*6f37f232SEric Joyner case ixgbe_mac_X550EM_x: 3271758cc3dcSJack F Vogel return; 3272*6f37f232SEric Joyner default: 3273758cc3dcSJack F Vogel goto display; 3274758cc3dcSJack F Vogel } 3275*6f37f232SEric Joyner } 3276758cc3dcSJack F Vogel 3277758cc3dcSJack F Vogel /* 3278758cc3dcSJack F Vogel ** For the Quad port adapter we need to parse back 3279758cc3dcSJack F Vogel ** up the PCI tree to find the speed of the expansion 3280758cc3dcSJack F Vogel ** slot into which this adapter is plugged. A bit more work. 3281758cc3dcSJack F Vogel */ 3282758cc3dcSJack F Vogel dev = device_get_parent(device_get_parent(dev)); 3283758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG 3284758cc3dcSJack F Vogel device_printf(dev, "parent pcib = %x,%x,%x\n", 3285758cc3dcSJack F Vogel pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); 3286758cc3dcSJack F Vogel #endif 3287758cc3dcSJack F Vogel dev = device_get_parent(device_get_parent(dev)); 3288758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG 3289758cc3dcSJack F Vogel device_printf(dev, "slot pcib = %x,%x,%x\n", 3290758cc3dcSJack F Vogel pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); 3291758cc3dcSJack F Vogel #endif 3292758cc3dcSJack F Vogel /* Now get the PCI Express Capabilities offset */ 3293758cc3dcSJack F Vogel pci_find_cap(dev, PCIY_EXPRESS, &offset); 3294758cc3dcSJack F Vogel /* ...and read the Link Status Register */ 3295758cc3dcSJack F Vogel link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 3296758cc3dcSJack F Vogel switch (link & IXGBE_PCI_LINK_WIDTH) { 3297758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_1: 3298758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x1; 3299758cc3dcSJack F Vogel break; 3300758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_2: 3301758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x2; 3302758cc3dcSJack F Vogel break; 3303758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_4: 3304758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x4; 3305758cc3dcSJack F Vogel break; 3306758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_8: 3307758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x8; 3308758cc3dcSJack F Vogel break; 3309758cc3dcSJack F Vogel default: 3310758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_unknown; 3311758cc3dcSJack F Vogel break; 3312758cc3dcSJack F Vogel } 3313758cc3dcSJack F Vogel 3314758cc3dcSJack F Vogel switch (link & IXGBE_PCI_LINK_SPEED) { 3315758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_2500: 3316758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_2500; 3317758cc3dcSJack F Vogel break; 3318758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_5000: 3319758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_5000; 3320758cc3dcSJack F Vogel break; 3321758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_8000: 3322758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_8000; 3323758cc3dcSJack F Vogel break; 3324758cc3dcSJack F Vogel default: 3325758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_unknown; 3326758cc3dcSJack F Vogel break; 3327758cc3dcSJack F Vogel } 3328758cc3dcSJack F Vogel 3329758cc3dcSJack F Vogel mac->ops.set_lan_id(hw); 3330758cc3dcSJack F Vogel 3331758cc3dcSJack F Vogel display: 3332758cc3dcSJack F Vogel device_printf(dev,"PCI Express Bus: Speed %s %s\n", 3333758cc3dcSJack F Vogel ((hw->bus.speed == ixgbe_bus_speed_8000) ? "8.0GT/s": 3334758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0GT/s": 3335758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5GT/s":"Unknown"), 3336758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" : 3337758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" : 3338758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" : 3339758cc3dcSJack F Vogel ("Unknown")); 3340758cc3dcSJack F Vogel 3341758cc3dcSJack F Vogel if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) && 3342758cc3dcSJack F Vogel ((hw->bus.width <= ixgbe_bus_width_pcie_x4) && 3343758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_2500))) { 3344758cc3dcSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 3345758cc3dcSJack F Vogel " for this card\n is not sufficient for" 3346758cc3dcSJack F Vogel " optimal performance.\n"); 3347758cc3dcSJack F Vogel device_printf(dev, "For optimal performance a x8 " 3348758cc3dcSJack F Vogel "PCIE, or x4 PCIE Gen2 slot is required.\n"); 3349758cc3dcSJack F Vogel } 3350758cc3dcSJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) && 3351758cc3dcSJack F Vogel ((hw->bus.width <= ixgbe_bus_width_pcie_x8) && 3352758cc3dcSJack F Vogel (hw->bus.speed < ixgbe_bus_speed_8000))) { 3353758cc3dcSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 3354758cc3dcSJack F Vogel " for this card\n is not sufficient for" 3355758cc3dcSJack F Vogel " optimal performance.\n"); 3356758cc3dcSJack F Vogel device_printf(dev, "For optimal performance a x8 " 3357758cc3dcSJack F Vogel "PCIE Gen3 slot is required.\n"); 3358758cc3dcSJack F Vogel } 3359758cc3dcSJack F Vogel 3360758cc3dcSJack F Vogel return; 3361758cc3dcSJack F Vogel } 3362758cc3dcSJack F Vogel 3363758cc3dcSJack F Vogel 3364758cc3dcSJack F Vogel /* 3365758cc3dcSJack F Vogel ** Setup the correct IVAR register for a particular MSIX interrupt 3366758cc3dcSJack F Vogel ** (yes this is all very magic and confusing :) 3367758cc3dcSJack F Vogel ** - entry is the register array entry 3368758cc3dcSJack F Vogel ** - vector is the MSIX vector for this queue 3369758cc3dcSJack F Vogel ** - type is RX/TX/MISC 3370758cc3dcSJack F Vogel */ 3371758cc3dcSJack F Vogel static void 3372758cc3dcSJack F Vogel ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) 3373758cc3dcSJack F Vogel { 3374758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3375758cc3dcSJack F Vogel u32 ivar, index; 3376758cc3dcSJack F Vogel 3377758cc3dcSJack F Vogel vector |= IXGBE_IVAR_ALLOC_VAL; 3378758cc3dcSJack F Vogel 3379758cc3dcSJack F Vogel switch (hw->mac.type) { 3380758cc3dcSJack F Vogel 3381758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 3382758cc3dcSJack F Vogel if (type == -1) 3383758cc3dcSJack F Vogel entry = IXGBE_IVAR_OTHER_CAUSES_INDEX; 3384758cc3dcSJack F Vogel else 3385758cc3dcSJack F Vogel entry += (type * 64); 3386758cc3dcSJack F Vogel index = (entry >> 2) & 0x1F; 3387758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 3388758cc3dcSJack F Vogel ivar &= ~(0xFF << (8 * (entry & 0x3))); 3389758cc3dcSJack F Vogel ivar |= (vector << (8 * (entry & 0x3))); 3390758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar); 3391758cc3dcSJack F Vogel break; 3392758cc3dcSJack F Vogel 3393758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 3394758cc3dcSJack F Vogel case ixgbe_mac_X540: 3395758cc3dcSJack F Vogel case ixgbe_mac_X550: 3396758cc3dcSJack F Vogel case ixgbe_mac_X550EM_x: 3397758cc3dcSJack F Vogel if (type == -1) { /* MISC IVAR */ 3398758cc3dcSJack F Vogel index = (entry & 1) * 8; 3399758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 3400758cc3dcSJack F Vogel ivar &= ~(0xFF << index); 3401758cc3dcSJack F Vogel ivar |= (vector << index); 3402758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 3403758cc3dcSJack F Vogel } else { /* RX/TX IVARS */ 3404758cc3dcSJack F Vogel index = (16 * (entry & 1)) + (8 * type); 3405758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1)); 3406758cc3dcSJack F Vogel ivar &= ~(0xFF << index); 3407758cc3dcSJack F Vogel ivar |= (vector << index); 3408758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar); 3409758cc3dcSJack F Vogel } 3410758cc3dcSJack F Vogel 3411758cc3dcSJack F Vogel default: 3412758cc3dcSJack F Vogel break; 3413758cc3dcSJack F Vogel } 3414758cc3dcSJack F Vogel } 3415758cc3dcSJack F Vogel 3416758cc3dcSJack F Vogel static void 3417758cc3dcSJack F Vogel ixgbe_configure_ivars(struct adapter *adapter) 3418758cc3dcSJack F Vogel { 3419758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 3420758cc3dcSJack F Vogel u32 newitr; 3421758cc3dcSJack F Vogel 3422758cc3dcSJack F Vogel if (ixgbe_max_interrupt_rate > 0) 3423758cc3dcSJack F Vogel newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8; 3424*6f37f232SEric Joyner else { 3425*6f37f232SEric Joyner /* 3426*6f37f232SEric Joyner ** Disable DMA coalescing if interrupt moderation is 3427*6f37f232SEric Joyner ** disabled. 3428*6f37f232SEric Joyner */ 3429*6f37f232SEric Joyner adapter->dmac = 0; 3430758cc3dcSJack F Vogel newitr = 0; 3431*6f37f232SEric Joyner } 3432758cc3dcSJack F Vogel 3433758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 3434758cc3dcSJack F Vogel /* First the RX queue entry */ 3435758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, i, que->msix, 0); 3436758cc3dcSJack F Vogel /* ... and the TX */ 3437758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, i, que->msix, 1); 3438758cc3dcSJack F Vogel /* Set an Initial EITR value */ 3439758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, 3440758cc3dcSJack F Vogel IXGBE_EITR(que->msix), newitr); 3441758cc3dcSJack F Vogel } 3442758cc3dcSJack F Vogel 3443758cc3dcSJack F Vogel /* For the Link interrupt */ 3444758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 1, adapter->vector, -1); 3445758cc3dcSJack F Vogel } 3446758cc3dcSJack F Vogel 3447758cc3dcSJack F Vogel /* 3448758cc3dcSJack F Vogel ** ixgbe_sfp_probe - called in the local timer to 3449758cc3dcSJack F Vogel ** determine if a port had optics inserted. 3450758cc3dcSJack F Vogel */ 3451758cc3dcSJack F Vogel static bool ixgbe_sfp_probe(struct adapter *adapter) 3452758cc3dcSJack F Vogel { 3453758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3454758cc3dcSJack F Vogel device_t dev = adapter->dev; 3455758cc3dcSJack F Vogel bool result = FALSE; 3456758cc3dcSJack F Vogel 3457758cc3dcSJack F Vogel if ((hw->phy.type == ixgbe_phy_nl) && 3458758cc3dcSJack F Vogel (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { 3459758cc3dcSJack F Vogel s32 ret = hw->phy.ops.identify_sfp(hw); 3460758cc3dcSJack F Vogel if (ret) 3461758cc3dcSJack F Vogel goto out; 3462758cc3dcSJack F Vogel ret = hw->phy.ops.reset(hw); 3463758cc3dcSJack F Vogel if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3464758cc3dcSJack F Vogel device_printf(dev,"Unsupported SFP+ module detected!"); 3465758cc3dcSJack F Vogel printf(" Reload driver with supported module.\n"); 3466758cc3dcSJack F Vogel adapter->sfp_probe = FALSE; 3467758cc3dcSJack F Vogel goto out; 3468758cc3dcSJack F Vogel } else 3469758cc3dcSJack F Vogel device_printf(dev,"SFP+ module detected!\n"); 3470758cc3dcSJack F Vogel /* We now have supported optics */ 3471758cc3dcSJack F Vogel adapter->sfp_probe = FALSE; 3472758cc3dcSJack F Vogel /* Set the optics type so system reports correctly */ 3473758cc3dcSJack F Vogel ixgbe_setup_optics(adapter); 3474758cc3dcSJack F Vogel result = TRUE; 3475758cc3dcSJack F Vogel } 3476758cc3dcSJack F Vogel out: 3477758cc3dcSJack F Vogel return (result); 3478758cc3dcSJack F Vogel } 3479758cc3dcSJack F Vogel 3480758cc3dcSJack F Vogel /* 3481758cc3dcSJack F Vogel ** Tasklet handler for MSIX Link interrupts 3482758cc3dcSJack F Vogel ** - do outside interrupt since it might sleep 3483758cc3dcSJack F Vogel */ 3484758cc3dcSJack F Vogel static void 3485758cc3dcSJack F Vogel ixgbe_handle_link(void *context, int pending) 3486758cc3dcSJack F Vogel { 3487758cc3dcSJack F Vogel struct adapter *adapter = context; 3488758cc3dcSJack F Vogel 3489758cc3dcSJack F Vogel ixgbe_check_link(&adapter->hw, 3490758cc3dcSJack F Vogel &adapter->link_speed, &adapter->link_up, 0); 3491758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 3492758cc3dcSJack F Vogel } 3493758cc3dcSJack F Vogel 3494758cc3dcSJack F Vogel /* 3495758cc3dcSJack F Vogel ** Tasklet for handling SFP module interrupts 3496758cc3dcSJack F Vogel */ 3497758cc3dcSJack F Vogel static void 3498758cc3dcSJack F Vogel ixgbe_handle_mod(void *context, int pending) 3499758cc3dcSJack F Vogel { 3500758cc3dcSJack F Vogel struct adapter *adapter = context; 3501758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3502758cc3dcSJack F Vogel device_t dev = adapter->dev; 3503758cc3dcSJack F Vogel u32 err; 3504758cc3dcSJack F Vogel 3505758cc3dcSJack F Vogel err = hw->phy.ops.identify_sfp(hw); 3506758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3507758cc3dcSJack F Vogel device_printf(dev, 3508758cc3dcSJack F Vogel "Unsupported SFP+ module type was detected.\n"); 3509758cc3dcSJack F Vogel return; 3510758cc3dcSJack F Vogel } 3511758cc3dcSJack F Vogel err = hw->mac.ops.setup_sfp(hw); 3512758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3513758cc3dcSJack F Vogel device_printf(dev, 3514758cc3dcSJack F Vogel "Setup failure - unsupported SFP+ module type.\n"); 3515758cc3dcSJack F Vogel return; 3516758cc3dcSJack F Vogel } 3517758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 3518758cc3dcSJack F Vogel return; 3519758cc3dcSJack F Vogel } 3520758cc3dcSJack F Vogel 3521758cc3dcSJack F Vogel 3522758cc3dcSJack F Vogel /* 3523758cc3dcSJack F Vogel ** Tasklet for handling MSF (multispeed fiber) interrupts 3524758cc3dcSJack F Vogel */ 3525758cc3dcSJack F Vogel static void 3526758cc3dcSJack F Vogel ixgbe_handle_msf(void *context, int pending) 3527758cc3dcSJack F Vogel { 3528758cc3dcSJack F Vogel struct adapter *adapter = context; 3529758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3530758cc3dcSJack F Vogel u32 autoneg; 3531758cc3dcSJack F Vogel bool negotiate; 3532758cc3dcSJack F Vogel int err; 3533758cc3dcSJack F Vogel 3534758cc3dcSJack F Vogel err = hw->phy.ops.identify_sfp(hw); 3535758cc3dcSJack F Vogel if (!err) { 3536758cc3dcSJack F Vogel ixgbe_setup_optics(adapter); 3537758cc3dcSJack F Vogel INIT_DEBUGOUT1("ixgbe_sfp_probe: flags: %X\n", adapter->optics); 3538758cc3dcSJack F Vogel } 3539758cc3dcSJack F Vogel 3540758cc3dcSJack F Vogel autoneg = hw->phy.autoneg_advertised; 3541758cc3dcSJack F Vogel if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) 3542758cc3dcSJack F Vogel hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate); 3543758cc3dcSJack F Vogel if (hw->mac.ops.setup_link) 3544758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, autoneg, TRUE); 3545758cc3dcSJack F Vogel 3546758cc3dcSJack F Vogel ifmedia_removeall(&adapter->media); 3547758cc3dcSJack F Vogel ixgbe_add_media_types(adapter); 3548758cc3dcSJack F Vogel return; 3549758cc3dcSJack F Vogel } 3550758cc3dcSJack F Vogel 3551*6f37f232SEric Joyner /* 3552*6f37f232SEric Joyner ** Tasklet for handling interrupts from an external PHY 3553*6f37f232SEric Joyner */ 3554*6f37f232SEric Joyner static void 3555*6f37f232SEric Joyner ixgbe_handle_phy(void *context, int pending) 3556*6f37f232SEric Joyner { 3557*6f37f232SEric Joyner struct adapter *adapter = context; 3558*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 3559*6f37f232SEric Joyner int error; 3560*6f37f232SEric Joyner 3561*6f37f232SEric Joyner error = hw->phy.ops.handle_lasi(hw); 3562*6f37f232SEric Joyner if (error == IXGBE_ERR_OVERTEMP) 3563*6f37f232SEric Joyner device_printf(adapter->dev, 3564*6f37f232SEric Joyner "CRITICAL: EXTERNAL PHY OVER TEMP!! " 3565*6f37f232SEric Joyner " PHY will downshift to lower power state!\n"); 3566*6f37f232SEric Joyner else if (error) 3567*6f37f232SEric Joyner device_printf(adapter->dev, 3568*6f37f232SEric Joyner "Error handling LASI interrupt: %d\n", 3569*6f37f232SEric Joyner error); 3570*6f37f232SEric Joyner return; 3571*6f37f232SEric Joyner } 3572*6f37f232SEric Joyner 3573758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3574758cc3dcSJack F Vogel /* 3575758cc3dcSJack F Vogel ** Tasklet for reinitializing the Flow Director filter table 3576758cc3dcSJack F Vogel */ 3577758cc3dcSJack F Vogel static void 3578758cc3dcSJack F Vogel ixgbe_reinit_fdir(void *context, int pending) 3579758cc3dcSJack F Vogel { 3580758cc3dcSJack F Vogel struct adapter *adapter = context; 3581758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3582758cc3dcSJack F Vogel 3583758cc3dcSJack F Vogel if (adapter->fdir_reinit != 1) /* Shouldn't happen */ 3584758cc3dcSJack F Vogel return; 3585758cc3dcSJack F Vogel ixgbe_reinit_fdir_tables_82599(&adapter->hw); 3586758cc3dcSJack F Vogel adapter->fdir_reinit = 0; 3587758cc3dcSJack F Vogel /* re-enable flow director interrupts */ 3588758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); 3589758cc3dcSJack F Vogel /* Restart the interface */ 3590758cc3dcSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 3591758cc3dcSJack F Vogel return; 3592758cc3dcSJack F Vogel } 3593758cc3dcSJack F Vogel #endif 3594758cc3dcSJack F Vogel 3595*6f37f232SEric Joyner /********************************************************************* 3596*6f37f232SEric Joyner * 3597*6f37f232SEric Joyner * Configure DMA Coalescing 3598*6f37f232SEric Joyner * 3599*6f37f232SEric Joyner **********************************************************************/ 3600*6f37f232SEric Joyner static void 3601*6f37f232SEric Joyner ixgbe_config_dmac(struct adapter *adapter) 3602*6f37f232SEric Joyner { 3603*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 3604*6f37f232SEric Joyner struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config; 3605*6f37f232SEric Joyner 3606*6f37f232SEric Joyner if (hw->mac.type < ixgbe_mac_X550 || 3607*6f37f232SEric Joyner !hw->mac.ops.dmac_config) 3608*6f37f232SEric Joyner return; 3609*6f37f232SEric Joyner 3610*6f37f232SEric Joyner if (dcfg->watchdog_timer ^ adapter->dmac || 3611*6f37f232SEric Joyner dcfg->link_speed ^ adapter->link_speed) { 3612*6f37f232SEric Joyner dcfg->watchdog_timer = adapter->dmac; 3613*6f37f232SEric Joyner dcfg->fcoe_en = false; 3614*6f37f232SEric Joyner dcfg->link_speed = adapter->link_speed; 3615*6f37f232SEric Joyner dcfg->num_tcs = 1; 3616*6f37f232SEric Joyner 3617*6f37f232SEric Joyner INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n", 3618*6f37f232SEric Joyner dcfg->watchdog_timer, dcfg->link_speed); 3619*6f37f232SEric Joyner 3620*6f37f232SEric Joyner hw->mac.ops.dmac_config(hw); 3621*6f37f232SEric Joyner } 3622*6f37f232SEric Joyner } 3623*6f37f232SEric Joyner 3624*6f37f232SEric Joyner /* 3625*6f37f232SEric Joyner * Checks whether the adapter supports Energy Efficient Ethernet 3626*6f37f232SEric Joyner * or not, based on device ID. 3627*6f37f232SEric Joyner */ 3628*6f37f232SEric Joyner static void 3629*6f37f232SEric Joyner ixgbe_check_eee_support(struct adapter *adapter) 3630*6f37f232SEric Joyner { 3631*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 3632*6f37f232SEric Joyner 3633*6f37f232SEric Joyner adapter->eee_support = adapter->eee_enabled = 3634*6f37f232SEric Joyner (hw->device_id == IXGBE_DEV_ID_X550T || 3635*6f37f232SEric Joyner hw->device_id == IXGBE_DEV_ID_X550EM_X_KR); 3636*6f37f232SEric Joyner } 3637*6f37f232SEric Joyner 3638*6f37f232SEric Joyner /* 3639*6f37f232SEric Joyner * Checks whether the adapter's ports are capable of 3640*6f37f232SEric Joyner * Wake On LAN by reading the adapter's NVM. 3641*6f37f232SEric Joyner * 3642*6f37f232SEric Joyner * Sets each port's hw->wol_enabled value depending 3643*6f37f232SEric Joyner * on the value read here. 3644*6f37f232SEric Joyner */ 3645*6f37f232SEric Joyner static void 3646*6f37f232SEric Joyner ixgbe_check_wol_support(struct adapter *adapter) 3647*6f37f232SEric Joyner { 3648*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 3649*6f37f232SEric Joyner u16 dev_caps = 0; 3650*6f37f232SEric Joyner 3651*6f37f232SEric Joyner /* Find out WoL support for port */ 3652*6f37f232SEric Joyner adapter->wol_support = hw->wol_enabled = 0; 3653*6f37f232SEric Joyner ixgbe_get_device_caps(hw, &dev_caps); 3654*6f37f232SEric Joyner if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) || 3655*6f37f232SEric Joyner ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) && 3656*6f37f232SEric Joyner hw->bus.func == 0)) 3657*6f37f232SEric Joyner adapter->wol_support = hw->wol_enabled = 1; 3658*6f37f232SEric Joyner 3659*6f37f232SEric Joyner /* Save initial wake up filter configuration */ 3660*6f37f232SEric Joyner adapter->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC); 3661*6f37f232SEric Joyner 3662*6f37f232SEric Joyner return; 3663*6f37f232SEric Joyner } 3664*6f37f232SEric Joyner 3665*6f37f232SEric Joyner /* 3666*6f37f232SEric Joyner * Prepare the adapter/port for LPLU and/or WoL 3667*6f37f232SEric Joyner */ 3668*6f37f232SEric Joyner static int 3669*6f37f232SEric Joyner ixgbe_setup_low_power_mode(struct adapter *adapter) 3670*6f37f232SEric Joyner { 3671*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 3672*6f37f232SEric Joyner device_t dev = adapter->dev; 3673*6f37f232SEric Joyner s32 error = 0; 3674*6f37f232SEric Joyner 3675*6f37f232SEric Joyner mtx_assert(&adapter->core_mtx, MA_OWNED); 3676*6f37f232SEric Joyner 3677*6f37f232SEric Joyner /* Limit power management flow to X550EM baseT */ 3678*6f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T 3679*6f37f232SEric Joyner && hw->phy.ops.enter_lplu) { 3680*6f37f232SEric Joyner /* Turn off support for APM wakeup. (Using ACPI instead) */ 3681*6f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_GRC, 3682*6f37f232SEric Joyner IXGBE_READ_REG(hw, IXGBE_GRC) & ~(u32)2); 3683*6f37f232SEric Joyner 3684*6f37f232SEric Joyner /* 3685*6f37f232SEric Joyner * Clear Wake Up Status register to prevent any previous wakeup 3686*6f37f232SEric Joyner * events from waking us up immediately after we suspend. 3687*6f37f232SEric Joyner */ 3688*6f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); 3689*6f37f232SEric Joyner 3690*6f37f232SEric Joyner /* 3691*6f37f232SEric Joyner * Program the Wakeup Filter Control register with user filter 3692*6f37f232SEric Joyner * settings 3693*6f37f232SEric Joyner */ 3694*6f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUFC, adapter->wufc); 3695*6f37f232SEric Joyner 3696*6f37f232SEric Joyner /* Enable wakeups and power management in Wakeup Control */ 3697*6f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUC, 3698*6f37f232SEric Joyner IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN); 3699*6f37f232SEric Joyner 3700*6f37f232SEric Joyner /* X550EM baseT adapters need a special LPLU flow */ 3701*6f37f232SEric Joyner hw->phy.reset_disable = true; 3702*6f37f232SEric Joyner ixgbe_stop(adapter); 3703*6f37f232SEric Joyner error = hw->phy.ops.enter_lplu(hw); 3704*6f37f232SEric Joyner if (error) 3705*6f37f232SEric Joyner device_printf(dev, 3706*6f37f232SEric Joyner "Error entering LPLU: %d\n", error); 3707*6f37f232SEric Joyner hw->phy.reset_disable = false; 3708*6f37f232SEric Joyner } else { 3709*6f37f232SEric Joyner /* Just stop for other adapters */ 3710*6f37f232SEric Joyner ixgbe_stop(adapter); 3711*6f37f232SEric Joyner } 3712*6f37f232SEric Joyner 3713*6f37f232SEric Joyner return error; 3714*6f37f232SEric Joyner } 3715*6f37f232SEric Joyner 3716758cc3dcSJack F Vogel /********************************************************************** 3717758cc3dcSJack F Vogel * 3718758cc3dcSJack F Vogel * Update the board statistics counters. 3719758cc3dcSJack F Vogel * 3720758cc3dcSJack F Vogel **********************************************************************/ 3721758cc3dcSJack F Vogel static void 3722758cc3dcSJack F Vogel ixgbe_update_stats_counters(struct adapter *adapter) 3723758cc3dcSJack F Vogel { 3724758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3725758cc3dcSJack F Vogel u32 missed_rx = 0, bprc, lxon, lxoff, total; 3726758cc3dcSJack F Vogel u64 total_missed_rx = 0; 3727758cc3dcSJack F Vogel 3728758cc3dcSJack F Vogel adapter->stats.pf.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); 3729758cc3dcSJack F Vogel adapter->stats.pf.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC); 3730758cc3dcSJack F Vogel adapter->stats.pf.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC); 3731758cc3dcSJack F Vogel adapter->stats.pf.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC); 3732758cc3dcSJack F Vogel 3733758cc3dcSJack F Vogel for (int i = 0; i < 16; i++) { 3734758cc3dcSJack F Vogel adapter->stats.pf.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); 3735758cc3dcSJack F Vogel adapter->stats.pf.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); 3736758cc3dcSJack F Vogel adapter->stats.pf.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); 3737758cc3dcSJack F Vogel } 3738758cc3dcSJack F Vogel adapter->stats.pf.mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC); 3739758cc3dcSJack F Vogel adapter->stats.pf.mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC); 3740758cc3dcSJack F Vogel adapter->stats.pf.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); 3741758cc3dcSJack F Vogel 3742758cc3dcSJack F Vogel /* Hardware workaround, gprc counts missed packets */ 3743758cc3dcSJack F Vogel adapter->stats.pf.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); 3744758cc3dcSJack F Vogel adapter->stats.pf.gprc -= missed_rx; 3745758cc3dcSJack F Vogel 3746758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 3747758cc3dcSJack F Vogel adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) + 3748758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); 3749758cc3dcSJack F Vogel adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) + 3750758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); 3751758cc3dcSJack F Vogel adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORL) + 3752758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); 3753758cc3dcSJack F Vogel adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); 3754758cc3dcSJack F Vogel adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); 3755758cc3dcSJack F Vogel } else { 3756758cc3dcSJack F Vogel adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); 3757758cc3dcSJack F Vogel adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); 3758758cc3dcSJack F Vogel /* 82598 only has a counter in the high register */ 3759758cc3dcSJack F Vogel adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); 3760758cc3dcSJack F Vogel adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); 3761758cc3dcSJack F Vogel adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORH); 3762758cc3dcSJack F Vogel } 3763758cc3dcSJack F Vogel 3764758cc3dcSJack F Vogel /* 3765758cc3dcSJack F Vogel * Workaround: mprc hardware is incorrectly counting 3766758cc3dcSJack F Vogel * broadcasts, so for now we subtract those. 3767758cc3dcSJack F Vogel */ 3768758cc3dcSJack F Vogel bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); 3769758cc3dcSJack F Vogel adapter->stats.pf.bprc += bprc; 3770758cc3dcSJack F Vogel adapter->stats.pf.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); 3771758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 3772758cc3dcSJack F Vogel adapter->stats.pf.mprc -= bprc; 3773758cc3dcSJack F Vogel 3774758cc3dcSJack F Vogel adapter->stats.pf.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); 3775758cc3dcSJack F Vogel adapter->stats.pf.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); 3776758cc3dcSJack F Vogel adapter->stats.pf.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); 3777758cc3dcSJack F Vogel adapter->stats.pf.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); 3778758cc3dcSJack F Vogel adapter->stats.pf.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); 3779758cc3dcSJack F Vogel adapter->stats.pf.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); 3780758cc3dcSJack F Vogel 3781758cc3dcSJack F Vogel lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); 3782758cc3dcSJack F Vogel adapter->stats.pf.lxontxc += lxon; 3783758cc3dcSJack F Vogel lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); 3784758cc3dcSJack F Vogel adapter->stats.pf.lxofftxc += lxoff; 3785758cc3dcSJack F Vogel total = lxon + lxoff; 3786758cc3dcSJack F Vogel 3787758cc3dcSJack F Vogel adapter->stats.pf.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); 3788758cc3dcSJack F Vogel adapter->stats.pf.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); 3789758cc3dcSJack F Vogel adapter->stats.pf.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); 3790758cc3dcSJack F Vogel adapter->stats.pf.gptc -= total; 3791758cc3dcSJack F Vogel adapter->stats.pf.mptc -= total; 3792758cc3dcSJack F Vogel adapter->stats.pf.ptc64 -= total; 3793758cc3dcSJack F Vogel adapter->stats.pf.gotc -= total * ETHER_MIN_LEN; 3794758cc3dcSJack F Vogel 3795758cc3dcSJack F Vogel adapter->stats.pf.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); 3796758cc3dcSJack F Vogel adapter->stats.pf.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); 3797758cc3dcSJack F Vogel adapter->stats.pf.roc += IXGBE_READ_REG(hw, IXGBE_ROC); 3798758cc3dcSJack F Vogel adapter->stats.pf.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); 3799758cc3dcSJack F Vogel adapter->stats.pf.mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC); 3800758cc3dcSJack F Vogel adapter->stats.pf.mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC); 3801758cc3dcSJack F Vogel adapter->stats.pf.mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC); 3802758cc3dcSJack F Vogel adapter->stats.pf.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); 3803758cc3dcSJack F Vogel adapter->stats.pf.tpt += IXGBE_READ_REG(hw, IXGBE_TPT); 3804758cc3dcSJack F Vogel adapter->stats.pf.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); 3805758cc3dcSJack F Vogel adapter->stats.pf.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); 3806758cc3dcSJack F Vogel adapter->stats.pf.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); 3807758cc3dcSJack F Vogel adapter->stats.pf.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); 3808758cc3dcSJack F Vogel adapter->stats.pf.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); 3809758cc3dcSJack F Vogel adapter->stats.pf.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); 3810758cc3dcSJack F Vogel adapter->stats.pf.xec += IXGBE_READ_REG(hw, IXGBE_XEC); 3811758cc3dcSJack F Vogel adapter->stats.pf.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); 3812758cc3dcSJack F Vogel adapter->stats.pf.fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST); 3813758cc3dcSJack F Vogel /* Only read FCOE on 82599 */ 3814758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 3815758cc3dcSJack F Vogel adapter->stats.pf.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); 3816758cc3dcSJack F Vogel adapter->stats.pf.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); 3817758cc3dcSJack F Vogel adapter->stats.pf.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); 3818758cc3dcSJack F Vogel adapter->stats.pf.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); 3819758cc3dcSJack F Vogel adapter->stats.pf.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); 3820758cc3dcSJack F Vogel } 3821758cc3dcSJack F Vogel 3822758cc3dcSJack F Vogel /* Fill out the OS statistics structure */ 3823758cc3dcSJack F Vogel IXGBE_SET_IPACKETS(adapter, adapter->stats.pf.gprc); 3824758cc3dcSJack F Vogel IXGBE_SET_OPACKETS(adapter, adapter->stats.pf.gptc); 3825758cc3dcSJack F Vogel IXGBE_SET_IBYTES(adapter, adapter->stats.pf.gorc); 3826758cc3dcSJack F Vogel IXGBE_SET_OBYTES(adapter, adapter->stats.pf.gotc); 3827758cc3dcSJack F Vogel IXGBE_SET_IMCASTS(adapter, adapter->stats.pf.mprc); 3828758cc3dcSJack F Vogel IXGBE_SET_OMCASTS(adapter, adapter->stats.pf.mptc); 3829758cc3dcSJack F Vogel IXGBE_SET_COLLISIONS(adapter, 0); 3830758cc3dcSJack F Vogel IXGBE_SET_IQDROPS(adapter, total_missed_rx); 3831758cc3dcSJack F Vogel IXGBE_SET_IERRORS(adapter, adapter->stats.pf.crcerrs 3832758cc3dcSJack F Vogel + adapter->stats.pf.rlec); 3833758cc3dcSJack F Vogel } 3834758cc3dcSJack F Vogel 3835758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 3836758cc3dcSJack F Vogel static uint64_t 3837758cc3dcSJack F Vogel ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt) 3838758cc3dcSJack F Vogel { 3839758cc3dcSJack F Vogel struct adapter *adapter; 3840625d12c6SJohn Baldwin struct tx_ring *txr; 3841625d12c6SJohn Baldwin uint64_t rv; 3842758cc3dcSJack F Vogel 3843758cc3dcSJack F Vogel adapter = if_getsoftc(ifp); 3844758cc3dcSJack F Vogel 3845758cc3dcSJack F Vogel switch (cnt) { 3846758cc3dcSJack F Vogel case IFCOUNTER_IPACKETS: 3847758cc3dcSJack F Vogel return (adapter->ipackets); 3848758cc3dcSJack F Vogel case IFCOUNTER_OPACKETS: 3849758cc3dcSJack F Vogel return (adapter->opackets); 3850758cc3dcSJack F Vogel case IFCOUNTER_IBYTES: 3851758cc3dcSJack F Vogel return (adapter->ibytes); 3852758cc3dcSJack F Vogel case IFCOUNTER_OBYTES: 3853758cc3dcSJack F Vogel return (adapter->obytes); 3854758cc3dcSJack F Vogel case IFCOUNTER_IMCASTS: 3855758cc3dcSJack F Vogel return (adapter->imcasts); 3856758cc3dcSJack F Vogel case IFCOUNTER_OMCASTS: 3857758cc3dcSJack F Vogel return (adapter->omcasts); 3858758cc3dcSJack F Vogel case IFCOUNTER_COLLISIONS: 3859758cc3dcSJack F Vogel return (0); 3860758cc3dcSJack F Vogel case IFCOUNTER_IQDROPS: 3861758cc3dcSJack F Vogel return (adapter->iqdrops); 3862625d12c6SJohn Baldwin case IFCOUNTER_OQDROPS: 3863625d12c6SJohn Baldwin rv = 0; 3864625d12c6SJohn Baldwin txr = adapter->tx_rings; 3865625d12c6SJohn Baldwin for (int i = 0; i < adapter->num_queues; i++, txr++) 3866625d12c6SJohn Baldwin rv += txr->br->br_drops; 3867625d12c6SJohn Baldwin return (rv); 3868758cc3dcSJack F Vogel case IFCOUNTER_IERRORS: 3869758cc3dcSJack F Vogel return (adapter->ierrors); 3870758cc3dcSJack F Vogel default: 3871758cc3dcSJack F Vogel return (if_get_counter_default(ifp, cnt)); 3872758cc3dcSJack F Vogel } 3873758cc3dcSJack F Vogel } 3874758cc3dcSJack F Vogel #endif 3875758cc3dcSJack F Vogel 3876758cc3dcSJack F Vogel /** ixgbe_sysctl_tdh_handler - Handler function 3877758cc3dcSJack F Vogel * Retrieves the TDH value from the hardware 3878758cc3dcSJack F Vogel */ 3879758cc3dcSJack F Vogel static int 3880758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS) 3881758cc3dcSJack F Vogel { 3882758cc3dcSJack F Vogel int error; 3883758cc3dcSJack F Vogel 3884758cc3dcSJack F Vogel struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); 3885758cc3dcSJack F Vogel if (!txr) return 0; 3886758cc3dcSJack F Vogel 3887758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me)); 3888758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 3889758cc3dcSJack F Vogel if (error || !req->newptr) 3890758cc3dcSJack F Vogel return error; 3891758cc3dcSJack F Vogel return 0; 3892758cc3dcSJack F Vogel } 3893758cc3dcSJack F Vogel 3894758cc3dcSJack F Vogel /** ixgbe_sysctl_tdt_handler - Handler function 3895758cc3dcSJack F Vogel * Retrieves the TDT value from the hardware 3896758cc3dcSJack F Vogel */ 3897758cc3dcSJack F Vogel static int 3898758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS) 3899758cc3dcSJack F Vogel { 3900758cc3dcSJack F Vogel int error; 3901758cc3dcSJack F Vogel 3902758cc3dcSJack F Vogel struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); 3903758cc3dcSJack F Vogel if (!txr) return 0; 3904758cc3dcSJack F Vogel 3905758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me)); 3906758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 3907758cc3dcSJack F Vogel if (error || !req->newptr) 3908758cc3dcSJack F Vogel return error; 3909758cc3dcSJack F Vogel return 0; 3910758cc3dcSJack F Vogel } 3911758cc3dcSJack F Vogel 3912758cc3dcSJack F Vogel /** ixgbe_sysctl_rdh_handler - Handler function 3913758cc3dcSJack F Vogel * Retrieves the RDH value from the hardware 3914758cc3dcSJack F Vogel */ 3915758cc3dcSJack F Vogel static int 3916758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS) 3917758cc3dcSJack F Vogel { 3918758cc3dcSJack F Vogel int error; 3919758cc3dcSJack F Vogel 3920758cc3dcSJack F Vogel struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); 3921758cc3dcSJack F Vogel if (!rxr) return 0; 3922758cc3dcSJack F Vogel 3923758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me)); 3924758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 3925758cc3dcSJack F Vogel if (error || !req->newptr) 3926758cc3dcSJack F Vogel return error; 3927758cc3dcSJack F Vogel return 0; 3928758cc3dcSJack F Vogel } 3929758cc3dcSJack F Vogel 3930758cc3dcSJack F Vogel /** ixgbe_sysctl_rdt_handler - Handler function 3931758cc3dcSJack F Vogel * Retrieves the RDT value from the hardware 3932758cc3dcSJack F Vogel */ 3933758cc3dcSJack F Vogel static int 3934758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) 3935758cc3dcSJack F Vogel { 3936758cc3dcSJack F Vogel int error; 3937758cc3dcSJack F Vogel 3938758cc3dcSJack F Vogel struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); 3939758cc3dcSJack F Vogel if (!rxr) return 0; 3940758cc3dcSJack F Vogel 3941758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me)); 3942758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 3943758cc3dcSJack F Vogel if (error || !req->newptr) 3944758cc3dcSJack F Vogel return error; 3945758cc3dcSJack F Vogel return 0; 3946758cc3dcSJack F Vogel } 3947758cc3dcSJack F Vogel 3948758cc3dcSJack F Vogel static int 3949758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS) 3950758cc3dcSJack F Vogel { 3951758cc3dcSJack F Vogel int error; 3952758cc3dcSJack F Vogel struct ix_queue *que = ((struct ix_queue *)oidp->oid_arg1); 3953758cc3dcSJack F Vogel unsigned int reg, usec, rate; 3954758cc3dcSJack F Vogel 3955758cc3dcSJack F Vogel reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix)); 3956758cc3dcSJack F Vogel usec = ((reg & 0x0FF8) >> 3); 3957758cc3dcSJack F Vogel if (usec > 0) 3958758cc3dcSJack F Vogel rate = 500000 / usec; 3959758cc3dcSJack F Vogel else 3960758cc3dcSJack F Vogel rate = 0; 3961758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &rate, 0, req); 3962758cc3dcSJack F Vogel if (error || !req->newptr) 3963758cc3dcSJack F Vogel return error; 3964758cc3dcSJack F Vogel reg &= ~0xfff; /* default, no limitation */ 3965758cc3dcSJack F Vogel ixgbe_max_interrupt_rate = 0; 3966758cc3dcSJack F Vogel if (rate > 0 && rate < 500000) { 3967758cc3dcSJack F Vogel if (rate < 1000) 3968758cc3dcSJack F Vogel rate = 1000; 3969758cc3dcSJack F Vogel ixgbe_max_interrupt_rate = rate; 3970758cc3dcSJack F Vogel reg |= ((4000000/rate) & 0xff8 ); 3971758cc3dcSJack F Vogel } 3972758cc3dcSJack F Vogel IXGBE_WRITE_REG(&que->adapter->hw, IXGBE_EITR(que->msix), reg); 3973758cc3dcSJack F Vogel return 0; 3974758cc3dcSJack F Vogel } 3975758cc3dcSJack F Vogel 3976*6f37f232SEric Joyner static void 3977*6f37f232SEric Joyner ixgbe_add_device_sysctls(struct adapter *adapter) 3978*6f37f232SEric Joyner { 3979*6f37f232SEric Joyner device_t dev = adapter->dev; 3980*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 3981*6f37f232SEric Joyner struct sysctl_oid_list *child; 3982*6f37f232SEric Joyner struct sysctl_ctx_list *ctx; 3983*6f37f232SEric Joyner 3984*6f37f232SEric Joyner ctx = device_get_sysctl_ctx(dev); 3985*6f37f232SEric Joyner child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 3986*6f37f232SEric Joyner 3987*6f37f232SEric Joyner /* Sysctls for all devices */ 3988*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fc", 3989*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 3990*6f37f232SEric Joyner ixgbe_set_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC); 3991*6f37f232SEric Joyner 3992*6f37f232SEric Joyner SYSCTL_ADD_INT(ctx, child, OID_AUTO, "enable_aim", 3993*6f37f232SEric Joyner CTLFLAG_RW, 3994*6f37f232SEric Joyner &ixgbe_enable_aim, 1, "Interrupt Moderation"); 3995*6f37f232SEric Joyner 3996*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "advertise_speed", 3997*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 3998*6f37f232SEric Joyner ixgbe_set_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED); 3999*6f37f232SEric Joyner 4000*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "thermal_test", 4001*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 4002*6f37f232SEric Joyner ixgbe_sysctl_thermal_test, "I", "Thermal Test"); 4003*6f37f232SEric Joyner 4004*6f37f232SEric Joyner /* for X550 devices */ 4005*6f37f232SEric Joyner if (hw->mac.type >= ixgbe_mac_X550) 4006*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac", 4007*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 4008*6f37f232SEric Joyner ixgbe_sysctl_dmac, "I", "DMA Coalesce"); 4009*6f37f232SEric Joyner 4010*6f37f232SEric Joyner /* for X550T and X550EM backplane devices */ 4011*6f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550T || 4012*6f37f232SEric Joyner hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { 4013*6f37f232SEric Joyner struct sysctl_oid *eee_node; 4014*6f37f232SEric Joyner struct sysctl_oid_list *eee_list; 4015*6f37f232SEric Joyner 4016*6f37f232SEric Joyner eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee", 4017*6f37f232SEric Joyner CTLFLAG_RD, NULL, 4018*6f37f232SEric Joyner "Energy Efficient Ethernet sysctls"); 4019*6f37f232SEric Joyner eee_list = SYSCTL_CHILDREN(eee_node); 4020*6f37f232SEric Joyner 4021*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "enable", 4022*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 4023*6f37f232SEric Joyner ixgbe_sysctl_eee_enable, "I", 4024*6f37f232SEric Joyner "Enable or Disable EEE"); 4025*6f37f232SEric Joyner 4026*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "negotiated", 4027*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 4028*6f37f232SEric Joyner ixgbe_sysctl_eee_negotiated, "I", 4029*6f37f232SEric Joyner "EEE negotiated on link"); 4030*6f37f232SEric Joyner 4031*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_status", 4032*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 4033*6f37f232SEric Joyner ixgbe_sysctl_eee_tx_lpi_status, "I", 4034*6f37f232SEric Joyner "Whether or not TX link is in LPI state"); 4035*6f37f232SEric Joyner 4036*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "rx_lpi_status", 4037*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 4038*6f37f232SEric Joyner ixgbe_sysctl_eee_rx_lpi_status, "I", 4039*6f37f232SEric Joyner "Whether or not RX link is in LPI state"); 4040*6f37f232SEric Joyner } 4041*6f37f232SEric Joyner 4042*6f37f232SEric Joyner /* for certain 10GBaseT devices */ 4043*6f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550T || 4044*6f37f232SEric Joyner hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { 4045*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wol_enable", 4046*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 4047*6f37f232SEric Joyner ixgbe_sysctl_wol_enable, "I", 4048*6f37f232SEric Joyner "Enable/Disable Wake on LAN"); 4049*6f37f232SEric Joyner 4050*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wufc", 4051*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 4052*6f37f232SEric Joyner ixgbe_sysctl_wufc, "I", 4053*6f37f232SEric Joyner "Enable/Disable Wake Up Filters"); 4054*6f37f232SEric Joyner } 4055*6f37f232SEric Joyner 4056*6f37f232SEric Joyner /* for X550EM 10GBaseT devices */ 4057*6f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { 4058*6f37f232SEric Joyner struct sysctl_oid *phy_node; 4059*6f37f232SEric Joyner struct sysctl_oid_list *phy_list; 4060*6f37f232SEric Joyner 4061*6f37f232SEric Joyner phy_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "phy", 4062*6f37f232SEric Joyner CTLFLAG_RD, NULL, 4063*6f37f232SEric Joyner "External PHY sysctls"); 4064*6f37f232SEric Joyner phy_list = SYSCTL_CHILDREN(phy_node); 4065*6f37f232SEric Joyner 4066*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "temp", 4067*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 4068*6f37f232SEric Joyner ixgbe_sysctl_phy_temp, "I", 4069*6f37f232SEric Joyner "Current External PHY Temperature (Celsius)"); 4070*6f37f232SEric Joyner 4071*6f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "overtemp_occurred", 4072*6f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 4073*6f37f232SEric Joyner ixgbe_sysctl_phy_overtemp_occurred, "I", 4074*6f37f232SEric Joyner "External PHY High Temperature Event Occurred"); 4075*6f37f232SEric Joyner } 4076*6f37f232SEric Joyner } 4077*6f37f232SEric Joyner 4078758cc3dcSJack F Vogel /* 4079758cc3dcSJack F Vogel * Add sysctl variables, one per statistic, to the system. 4080758cc3dcSJack F Vogel */ 4081758cc3dcSJack F Vogel static void 4082758cc3dcSJack F Vogel ixgbe_add_hw_stats(struct adapter *adapter) 4083758cc3dcSJack F Vogel { 4084758cc3dcSJack F Vogel device_t dev = adapter->dev; 4085758cc3dcSJack F Vogel 4086758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 4087758cc3dcSJack F Vogel struct rx_ring *rxr = adapter->rx_rings; 4088758cc3dcSJack F Vogel 4089758cc3dcSJack F Vogel struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 4090758cc3dcSJack F Vogel struct sysctl_oid *tree = device_get_sysctl_tree(dev); 4091758cc3dcSJack F Vogel struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 4092758cc3dcSJack F Vogel struct ixgbe_hw_stats *stats = &adapter->stats.pf; 4093758cc3dcSJack F Vogel 4094758cc3dcSJack F Vogel struct sysctl_oid *stat_node, *queue_node; 4095758cc3dcSJack F Vogel struct sysctl_oid_list *stat_list, *queue_list; 4096758cc3dcSJack F Vogel 4097758cc3dcSJack F Vogel #define QUEUE_NAME_LEN 32 4098758cc3dcSJack F Vogel char namebuf[QUEUE_NAME_LEN]; 4099758cc3dcSJack F Vogel 4100758cc3dcSJack F Vogel /* Driver Statistics */ 4101758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", 4102758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->dropped_pkts, 4103758cc3dcSJack F Vogel "Driver dropped packets"); 4104758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", 4105758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->mbuf_defrag_failed, 4106758cc3dcSJack F Vogel "m_defrag() failed"); 4107758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 4108758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->watchdog_events, 4109758cc3dcSJack F Vogel "Watchdog timeouts"); 4110758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", 4111*6f37f232SEric Joyner CTLFLAG_RD, &adapter->link_irq, 4112758cc3dcSJack F Vogel "Link MSIX IRQ Handled"); 4113758cc3dcSJack F Vogel 4114758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, txr++) { 4115758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4116758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4117758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4118758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4119758cc3dcSJack F Vogel 4120758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate", 4121758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RW, &adapter->queues[i], 4122758cc3dcSJack F Vogel sizeof(&adapter->queues[i]), 4123758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler, "IU", 4124758cc3dcSJack F Vogel "Interrupt Rate"); 4125758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 4126758cc3dcSJack F Vogel CTLFLAG_RD, &(adapter->queues[i].irqs), 4127758cc3dcSJack F Vogel "irqs on this queue"); 4128758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", 4129758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), 4130758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler, "IU", 4131758cc3dcSJack F Vogel "Transmit Descriptor Head"); 4132758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", 4133758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), 4134758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler, "IU", 4135758cc3dcSJack F Vogel "Transmit Descriptor Tail"); 4136758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx", 4137758cc3dcSJack F Vogel CTLFLAG_RD, &txr->tso_tx, 4138758cc3dcSJack F Vogel "TSO"); 4139758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_tx_dma_setup", 4140758cc3dcSJack F Vogel CTLFLAG_RD, &txr->no_tx_dma_setup, 4141758cc3dcSJack F Vogel "Driver tx dma failure in xmit"); 4142758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 4143758cc3dcSJack F Vogel CTLFLAG_RD, &txr->no_desc_avail, 4144758cc3dcSJack F Vogel "Queue No Descriptor Available"); 4145758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 4146758cc3dcSJack F Vogel CTLFLAG_RD, &txr->total_packets, 4147758cc3dcSJack F Vogel "Queue Packets Transmitted"); 4148625d12c6SJohn Baldwin SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops", 4149625d12c6SJohn Baldwin CTLFLAG_RD, &txr->br->br_drops, 4150625d12c6SJohn Baldwin "Packets dropped in buf_ring"); 4151758cc3dcSJack F Vogel } 4152758cc3dcSJack F Vogel 4153758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, rxr++) { 4154758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4155758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4156758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4157758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4158758cc3dcSJack F Vogel 4159758cc3dcSJack F Vogel struct lro_ctrl *lro = &rxr->lro; 4160758cc3dcSJack F Vogel 4161758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4162758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4163758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4164758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4165758cc3dcSJack F Vogel 4166758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", 4167758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), 4168758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler, "IU", 4169758cc3dcSJack F Vogel "Receive Descriptor Head"); 4170758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", 4171758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), 4172758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler, "IU", 4173758cc3dcSJack F Vogel "Receive Descriptor Tail"); 4174758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 4175758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_packets, 4176758cc3dcSJack F Vogel "Queue Packets Received"); 4177758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 4178758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_bytes, 4179758cc3dcSJack F Vogel "Queue Bytes Received"); 4180758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies", 4181758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_copies, 4182758cc3dcSJack F Vogel "Copied RX Frames"); 4183758cc3dcSJack F Vogel SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_queued", 4184758cc3dcSJack F Vogel CTLFLAG_RD, &lro->lro_queued, 0, 4185758cc3dcSJack F Vogel "LRO Queued"); 4186758cc3dcSJack F Vogel SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_flushed", 4187758cc3dcSJack F Vogel CTLFLAG_RD, &lro->lro_flushed, 0, 4188758cc3dcSJack F Vogel "LRO Flushed"); 4189758cc3dcSJack F Vogel } 4190758cc3dcSJack F Vogel 4191758cc3dcSJack F Vogel /* MAC stats get the own sub node */ 4192758cc3dcSJack F Vogel 4193758cc3dcSJack F Vogel stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", 4194758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "MAC Statistics"); 4195758cc3dcSJack F Vogel stat_list = SYSCTL_CHILDREN(stat_node); 4196758cc3dcSJack F Vogel 4197758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs", 4198758cc3dcSJack F Vogel CTLFLAG_RD, &stats->crcerrs, 4199758cc3dcSJack F Vogel "CRC Errors"); 4200758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs", 4201758cc3dcSJack F Vogel CTLFLAG_RD, &stats->illerrc, 4202758cc3dcSJack F Vogel "Illegal Byte Errors"); 4203758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs", 4204758cc3dcSJack F Vogel CTLFLAG_RD, &stats->errbc, 4205758cc3dcSJack F Vogel "Byte Errors"); 4206758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards", 4207758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mspdc, 4208758cc3dcSJack F Vogel "MAC Short Packets Discarded"); 4209758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults", 4210758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mlfc, 4211758cc3dcSJack F Vogel "MAC Local Faults"); 4212758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults", 4213758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mrfc, 4214758cc3dcSJack F Vogel "MAC Remote Faults"); 4215758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs", 4216758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rlec, 4217758cc3dcSJack F Vogel "Receive Length Errors"); 4218758cc3dcSJack F Vogel 4219758cc3dcSJack F Vogel /* Flow Control stats */ 4220758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd", 4221758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxontxc, 4222758cc3dcSJack F Vogel "Link XON Transmitted"); 4223758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd", 4224758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxonrxc, 4225758cc3dcSJack F Vogel "Link XON Received"); 4226758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd", 4227758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxofftxc, 4228758cc3dcSJack F Vogel "Link XOFF Transmitted"); 4229758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd", 4230758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxoffrxc, 4231758cc3dcSJack F Vogel "Link XOFF Received"); 4232758cc3dcSJack F Vogel 4233758cc3dcSJack F Vogel /* Packet Reception Stats */ 4234758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd", 4235758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tor, 4236758cc3dcSJack F Vogel "Total Octets Received"); 4237758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", 4238758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gorc, 4239758cc3dcSJack F Vogel "Good Octets Received"); 4240758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd", 4241758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tpr, 4242758cc3dcSJack F Vogel "Total Packets Received"); 4243758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", 4244758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gprc, 4245758cc3dcSJack F Vogel "Good Packets Received"); 4246758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", 4247758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mprc, 4248758cc3dcSJack F Vogel "Multicast Packets Received"); 4249758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", 4250758cc3dcSJack F Vogel CTLFLAG_RD, &stats->bprc, 4251758cc3dcSJack F Vogel "Broadcast Packets Received"); 4252758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", 4253758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc64, 4254758cc3dcSJack F Vogel "64 byte frames received "); 4255758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", 4256758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc127, 4257758cc3dcSJack F Vogel "65-127 byte frames received"); 4258758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", 4259758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc255, 4260758cc3dcSJack F Vogel "128-255 byte frames received"); 4261758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", 4262758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc511, 4263758cc3dcSJack F Vogel "256-511 byte frames received"); 4264758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", 4265758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc1023, 4266758cc3dcSJack F Vogel "512-1023 byte frames received"); 4267758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", 4268758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc1522, 4269758cc3dcSJack F Vogel "1023-1522 byte frames received"); 4270758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized", 4271758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ruc, 4272758cc3dcSJack F Vogel "Receive Undersized"); 4273758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", 4274758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rfc, 4275758cc3dcSJack F Vogel "Fragmented Packets Received "); 4276758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized", 4277758cc3dcSJack F Vogel CTLFLAG_RD, &stats->roc, 4278758cc3dcSJack F Vogel "Oversized Packets Received"); 4279758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd", 4280758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rjc, 4281758cc3dcSJack F Vogel "Received Jabber"); 4282758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd", 4283758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngprc, 4284758cc3dcSJack F Vogel "Management Packets Received"); 4285758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd", 4286758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngptc, 4287758cc3dcSJack F Vogel "Management Packets Dropped"); 4288758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs", 4289758cc3dcSJack F Vogel CTLFLAG_RD, &stats->xec, 4290758cc3dcSJack F Vogel "Checksum Errors"); 4291758cc3dcSJack F Vogel 4292758cc3dcSJack F Vogel /* Packet Transmission Stats */ 4293758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", 4294758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gotc, 4295758cc3dcSJack F Vogel "Good Octets Transmitted"); 4296758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", 4297758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tpt, 4298758cc3dcSJack F Vogel "Total Packets Transmitted"); 4299758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", 4300758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gptc, 4301758cc3dcSJack F Vogel "Good Packets Transmitted"); 4302758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", 4303758cc3dcSJack F Vogel CTLFLAG_RD, &stats->bptc, 4304758cc3dcSJack F Vogel "Broadcast Packets Transmitted"); 4305758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", 4306758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mptc, 4307758cc3dcSJack F Vogel "Multicast Packets Transmitted"); 4308758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd", 4309758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngptc, 4310758cc3dcSJack F Vogel "Management Packets Transmitted"); 4311758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", 4312758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc64, 4313758cc3dcSJack F Vogel "64 byte frames transmitted "); 4314758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", 4315758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc127, 4316758cc3dcSJack F Vogel "65-127 byte frames transmitted"); 4317758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", 4318758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc255, 4319758cc3dcSJack F Vogel "128-255 byte frames transmitted"); 4320758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", 4321758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc511, 4322758cc3dcSJack F Vogel "256-511 byte frames transmitted"); 4323758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", 4324758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc1023, 4325758cc3dcSJack F Vogel "512-1023 byte frames transmitted"); 4326758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", 4327758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc1522, 4328758cc3dcSJack F Vogel "1024-1522 byte frames transmitted"); 4329758cc3dcSJack F Vogel } 4330758cc3dcSJack F Vogel 4331758cc3dcSJack F Vogel /* 4332758cc3dcSJack F Vogel ** Set flow control using sysctl: 4333758cc3dcSJack F Vogel ** Flow control values: 4334758cc3dcSJack F Vogel ** 0 - off 4335758cc3dcSJack F Vogel ** 1 - rx pause 4336758cc3dcSJack F Vogel ** 2 - tx pause 4337758cc3dcSJack F Vogel ** 3 - full 4338758cc3dcSJack F Vogel */ 4339758cc3dcSJack F Vogel static int 4340758cc3dcSJack F Vogel ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS) 4341758cc3dcSJack F Vogel { 4342758cc3dcSJack F Vogel int error, last; 4343758cc3dcSJack F Vogel struct adapter *adapter = (struct adapter *) arg1; 4344758cc3dcSJack F Vogel 4345758cc3dcSJack F Vogel last = adapter->fc; 4346758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &adapter->fc, 0, req); 4347758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4348758cc3dcSJack F Vogel return (error); 4349758cc3dcSJack F Vogel 4350758cc3dcSJack F Vogel /* Don't bother if it's not changed */ 4351758cc3dcSJack F Vogel if (adapter->fc == last) 4352758cc3dcSJack F Vogel return (0); 4353758cc3dcSJack F Vogel 4354758cc3dcSJack F Vogel switch (adapter->fc) { 4355758cc3dcSJack F Vogel case ixgbe_fc_rx_pause: 4356758cc3dcSJack F Vogel case ixgbe_fc_tx_pause: 4357758cc3dcSJack F Vogel case ixgbe_fc_full: 4358758cc3dcSJack F Vogel adapter->hw.fc.requested_mode = adapter->fc; 4359758cc3dcSJack F Vogel if (adapter->num_queues > 1) 4360758cc3dcSJack F Vogel ixgbe_disable_rx_drop(adapter); 4361758cc3dcSJack F Vogel break; 4362758cc3dcSJack F Vogel case ixgbe_fc_none: 4363758cc3dcSJack F Vogel adapter->hw.fc.requested_mode = ixgbe_fc_none; 4364758cc3dcSJack F Vogel if (adapter->num_queues > 1) 4365758cc3dcSJack F Vogel ixgbe_enable_rx_drop(adapter); 4366758cc3dcSJack F Vogel break; 4367758cc3dcSJack F Vogel default: 4368758cc3dcSJack F Vogel adapter->fc = last; 4369758cc3dcSJack F Vogel return (EINVAL); 4370758cc3dcSJack F Vogel } 4371758cc3dcSJack F Vogel /* Don't autoneg if forcing a value */ 4372758cc3dcSJack F Vogel adapter->hw.fc.disable_fc_autoneg = TRUE; 4373758cc3dcSJack F Vogel ixgbe_fc_enable(&adapter->hw); 4374758cc3dcSJack F Vogel return error; 4375758cc3dcSJack F Vogel } 4376758cc3dcSJack F Vogel 4377758cc3dcSJack F Vogel /* 4378758cc3dcSJack F Vogel ** Control advertised link speed: 4379758cc3dcSJack F Vogel ** Flags: 4380758cc3dcSJack F Vogel ** 0x1 - advertise 100 Mb 4381758cc3dcSJack F Vogel ** 0x2 - advertise 1G 4382758cc3dcSJack F Vogel ** 0x4 - advertise 10G 4383758cc3dcSJack F Vogel */ 4384758cc3dcSJack F Vogel static int 4385758cc3dcSJack F Vogel ixgbe_set_advertise(SYSCTL_HANDLER_ARGS) 4386758cc3dcSJack F Vogel { 4387758cc3dcSJack F Vogel int error = 0, requested; 4388758cc3dcSJack F Vogel struct adapter *adapter; 4389758cc3dcSJack F Vogel device_t dev; 4390758cc3dcSJack F Vogel struct ixgbe_hw *hw; 4391758cc3dcSJack F Vogel ixgbe_link_speed speed = 0; 4392758cc3dcSJack F Vogel 4393758cc3dcSJack F Vogel adapter = (struct adapter *) arg1; 4394758cc3dcSJack F Vogel dev = adapter->dev; 4395758cc3dcSJack F Vogel hw = &adapter->hw; 4396758cc3dcSJack F Vogel 4397758cc3dcSJack F Vogel requested = adapter->advertise; 4398758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &requested, 0, req); 4399758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4400758cc3dcSJack F Vogel return (error); 4401758cc3dcSJack F Vogel 4402758cc3dcSJack F Vogel /* Checks to validate new value */ 4403758cc3dcSJack F Vogel if (adapter->advertise == requested) /* no change */ 4404758cc3dcSJack F Vogel return (0); 4405758cc3dcSJack F Vogel 4406758cc3dcSJack F Vogel if (!((hw->phy.media_type == ixgbe_media_type_copper) || 4407758cc3dcSJack F Vogel (hw->phy.multispeed_fiber))) { 4408758cc3dcSJack F Vogel device_printf(dev, 4409758cc3dcSJack F Vogel "Advertised speed can only be set on copper or " 4410758cc3dcSJack F Vogel "multispeed fiber media types.\n"); 4411758cc3dcSJack F Vogel return (EINVAL); 4412758cc3dcSJack F Vogel } 4413758cc3dcSJack F Vogel 4414758cc3dcSJack F Vogel if (requested < 0x1 || requested > 0x7) { 4415758cc3dcSJack F Vogel device_printf(dev, 4416758cc3dcSJack F Vogel "Invalid advertised speed; valid modes are 0x1 through 0x7\n"); 4417758cc3dcSJack F Vogel return (EINVAL); 4418758cc3dcSJack F Vogel } 4419758cc3dcSJack F Vogel 4420758cc3dcSJack F Vogel if ((requested & 0x1) 4421758cc3dcSJack F Vogel && (hw->mac.type != ixgbe_mac_X540) 4422758cc3dcSJack F Vogel && (hw->mac.type != ixgbe_mac_X550)) { 4423758cc3dcSJack F Vogel device_printf(dev, "Set Advertise: 100Mb on X540/X550 only\n"); 4424758cc3dcSJack F Vogel return (EINVAL); 4425758cc3dcSJack F Vogel } 4426758cc3dcSJack F Vogel 4427758cc3dcSJack F Vogel /* Set new value and report new advertised mode */ 4428758cc3dcSJack F Vogel if (requested & 0x1) 4429758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 4430758cc3dcSJack F Vogel if (requested & 0x2) 4431758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 4432758cc3dcSJack F Vogel if (requested & 0x4) 4433758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_10GB_FULL; 4434758cc3dcSJack F Vogel 4435758cc3dcSJack F Vogel hw->mac.autotry_restart = TRUE; 4436758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, speed, TRUE); 4437758cc3dcSJack F Vogel adapter->advertise = requested; 4438758cc3dcSJack F Vogel 4439758cc3dcSJack F Vogel return (error); 4440758cc3dcSJack F Vogel } 4441758cc3dcSJack F Vogel 4442758cc3dcSJack F Vogel /* 4443*6f37f232SEric Joyner * The following two sysctls are for X550 BaseT devices; 4444*6f37f232SEric Joyner * they deal with the external PHY used in them. 4445758cc3dcSJack F Vogel */ 4446758cc3dcSJack F Vogel static int 4447*6f37f232SEric Joyner ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS) 4448758cc3dcSJack F Vogel { 4449758cc3dcSJack F Vogel struct adapter *adapter = (struct adapter *) arg1; 4450758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 4451*6f37f232SEric Joyner u16 reg; 4452758cc3dcSJack F Vogel 4453*6f37f232SEric Joyner if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { 4454*6f37f232SEric Joyner device_printf(adapter->dev, 4455*6f37f232SEric Joyner "Device has no supported external thermal sensor.\n"); 4456*6f37f232SEric Joyner return (ENODEV); 4457*6f37f232SEric Joyner } 4458758cc3dcSJack F Vogel 4459*6f37f232SEric Joyner if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP, 4460*6f37f232SEric Joyner IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 4461*6f37f232SEric Joyner ®)) { 4462*6f37f232SEric Joyner device_printf(adapter->dev, 4463*6f37f232SEric Joyner "Error reading from PHY's current temperature register\n"); 4464*6f37f232SEric Joyner return (EAGAIN); 4465*6f37f232SEric Joyner } 4466*6f37f232SEric Joyner 4467*6f37f232SEric Joyner /* Shift temp for output */ 4468*6f37f232SEric Joyner reg = reg >> 8; 4469*6f37f232SEric Joyner 4470*6f37f232SEric Joyner return (sysctl_handle_int(oidp, NULL, reg, req)); 4471*6f37f232SEric Joyner } 4472*6f37f232SEric Joyner 4473*6f37f232SEric Joyner /* 4474*6f37f232SEric Joyner * Reports whether the current PHY temperature is over 4475*6f37f232SEric Joyner * the overtemp threshold. 4476*6f37f232SEric Joyner * - This is reported directly from the PHY 4477*6f37f232SEric Joyner */ 4478*6f37f232SEric Joyner static int 4479*6f37f232SEric Joyner ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS) 4480*6f37f232SEric Joyner { 4481*6f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 4482*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 4483*6f37f232SEric Joyner u16 reg; 4484*6f37f232SEric Joyner 4485*6f37f232SEric Joyner if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { 4486*6f37f232SEric Joyner device_printf(adapter->dev, 4487*6f37f232SEric Joyner "Device has no supported external thermal sensor.\n"); 4488*6f37f232SEric Joyner return (ENODEV); 4489*6f37f232SEric Joyner } 4490*6f37f232SEric Joyner 4491*6f37f232SEric Joyner if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS, 4492*6f37f232SEric Joyner IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 4493*6f37f232SEric Joyner ®)) { 4494*6f37f232SEric Joyner device_printf(adapter->dev, 4495*6f37f232SEric Joyner "Error reading from PHY's temperature status register\n"); 4496*6f37f232SEric Joyner return (EAGAIN); 4497*6f37f232SEric Joyner } 4498*6f37f232SEric Joyner 4499*6f37f232SEric Joyner /* Get occurrence bit */ 4500*6f37f232SEric Joyner reg = !!(reg & 0x4000); 4501*6f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, reg, req)); 4502*6f37f232SEric Joyner } 4503*6f37f232SEric Joyner 4504*6f37f232SEric Joyner /* 4505*6f37f232SEric Joyner ** Thermal Shutdown Trigger (internal MAC) 4506*6f37f232SEric Joyner ** - Set this to 1 to cause an overtemp event to occur 4507*6f37f232SEric Joyner */ 4508*6f37f232SEric Joyner static int 4509*6f37f232SEric Joyner ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS) 4510*6f37f232SEric Joyner { 4511*6f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 4512*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 4513*6f37f232SEric Joyner int error, fire = 0; 4514758cc3dcSJack F Vogel 4515758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &fire, 0, req); 4516758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4517758cc3dcSJack F Vogel return (error); 4518758cc3dcSJack F Vogel 4519758cc3dcSJack F Vogel if (fire) { 4520758cc3dcSJack F Vogel u32 reg = IXGBE_READ_REG(hw, IXGBE_EICS); 4521758cc3dcSJack F Vogel reg |= IXGBE_EICR_TS; 4522758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICS, reg); 4523758cc3dcSJack F Vogel } 4524758cc3dcSJack F Vogel 4525758cc3dcSJack F Vogel return (0); 4526758cc3dcSJack F Vogel } 4527758cc3dcSJack F Vogel 4528758cc3dcSJack F Vogel /* 4529*6f37f232SEric Joyner ** Manage DMA Coalescing. 4530*6f37f232SEric Joyner ** Control values: 4531*6f37f232SEric Joyner ** 0/1 - off / on (use default value of 1000) 4532*6f37f232SEric Joyner ** 4533*6f37f232SEric Joyner ** Legal timer values are: 4534*6f37f232SEric Joyner ** 50,100,250,500,1000,2000,5000,10000 4535*6f37f232SEric Joyner ** 4536*6f37f232SEric Joyner ** Turning off interrupt moderation will also turn this off. 4537*6f37f232SEric Joyner */ 4538*6f37f232SEric Joyner static int 4539*6f37f232SEric Joyner ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS) 4540*6f37f232SEric Joyner { 4541*6f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 4542*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 4543*6f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 4544*6f37f232SEric Joyner int error; 4545*6f37f232SEric Joyner u16 oldval; 4546*6f37f232SEric Joyner 4547*6f37f232SEric Joyner oldval = adapter->dmac; 4548*6f37f232SEric Joyner error = sysctl_handle_int(oidp, &adapter->dmac, 0, req); 4549*6f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 4550*6f37f232SEric Joyner return (error); 4551*6f37f232SEric Joyner 4552*6f37f232SEric Joyner switch (hw->mac.type) { 4553*6f37f232SEric Joyner case ixgbe_mac_X550: 4554*6f37f232SEric Joyner case ixgbe_mac_X550EM_x: 4555*6f37f232SEric Joyner break; 4556*6f37f232SEric Joyner default: 4557*6f37f232SEric Joyner device_printf(adapter->dev, 4558*6f37f232SEric Joyner "DMA Coalescing is only supported on X550 devices\n"); 4559*6f37f232SEric Joyner return (ENODEV); 4560*6f37f232SEric Joyner } 4561*6f37f232SEric Joyner 4562*6f37f232SEric Joyner switch (adapter->dmac) { 4563*6f37f232SEric Joyner case 0: 4564*6f37f232SEric Joyner /* Disabled */ 4565*6f37f232SEric Joyner break; 4566*6f37f232SEric Joyner case 1: /* Enable and use default */ 4567*6f37f232SEric Joyner adapter->dmac = 1000; 4568*6f37f232SEric Joyner break; 4569*6f37f232SEric Joyner case 50: 4570*6f37f232SEric Joyner case 100: 4571*6f37f232SEric Joyner case 250: 4572*6f37f232SEric Joyner case 500: 4573*6f37f232SEric Joyner case 1000: 4574*6f37f232SEric Joyner case 2000: 4575*6f37f232SEric Joyner case 5000: 4576*6f37f232SEric Joyner case 10000: 4577*6f37f232SEric Joyner /* Legal values - allow */ 4578*6f37f232SEric Joyner break; 4579*6f37f232SEric Joyner default: 4580*6f37f232SEric Joyner /* Do nothing, illegal value */ 4581*6f37f232SEric Joyner adapter->dmac = oldval; 4582*6f37f232SEric Joyner return (EINVAL); 4583*6f37f232SEric Joyner } 4584*6f37f232SEric Joyner 4585*6f37f232SEric Joyner /* Re-initialize hardware if it's already running */ 4586*6f37f232SEric Joyner if (ifp->if_drv_flags & IFF_DRV_RUNNING) 4587*6f37f232SEric Joyner ixgbe_init(adapter); 4588*6f37f232SEric Joyner 4589*6f37f232SEric Joyner return (0); 4590*6f37f232SEric Joyner } 4591*6f37f232SEric Joyner 4592*6f37f232SEric Joyner /* 4593*6f37f232SEric Joyner * Sysctl to enable/disable the WoL capability, if supported by the adapter. 4594*6f37f232SEric Joyner * Values: 4595*6f37f232SEric Joyner * 0 - disabled 4596*6f37f232SEric Joyner * 1 - enabled 4597*6f37f232SEric Joyner */ 4598*6f37f232SEric Joyner static int 4599*6f37f232SEric Joyner ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS) 4600*6f37f232SEric Joyner { 4601*6f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 4602*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 4603*6f37f232SEric Joyner int new_wol_enabled; 4604*6f37f232SEric Joyner int error = 0; 4605*6f37f232SEric Joyner 4606*6f37f232SEric Joyner new_wol_enabled = hw->wol_enabled; 4607*6f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req); 4608*6f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 4609*6f37f232SEric Joyner return (error); 4610*6f37f232SEric Joyner if (new_wol_enabled == hw->wol_enabled) 4611*6f37f232SEric Joyner return (0); 4612*6f37f232SEric Joyner 4613*6f37f232SEric Joyner if (new_wol_enabled > 0 && !adapter->wol_support) 4614*6f37f232SEric Joyner return (ENODEV); 4615*6f37f232SEric Joyner else 4616*6f37f232SEric Joyner hw->wol_enabled = !!(new_wol_enabled); 4617*6f37f232SEric Joyner 4618*6f37f232SEric Joyner return (0); 4619*6f37f232SEric Joyner } 4620*6f37f232SEric Joyner 4621*6f37f232SEric Joyner /* 4622*6f37f232SEric Joyner * Sysctl to enable/disable the Energy Efficient Ethernet capability, 4623*6f37f232SEric Joyner * if supported by the adapter. 4624*6f37f232SEric Joyner * Values: 4625*6f37f232SEric Joyner * 0 - disabled 4626*6f37f232SEric Joyner * 1 - enabled 4627*6f37f232SEric Joyner */ 4628*6f37f232SEric Joyner static int 4629*6f37f232SEric Joyner ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS) 4630*6f37f232SEric Joyner { 4631*6f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 4632*6f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 4633*6f37f232SEric Joyner int new_eee_enabled, error = 0; 4634*6f37f232SEric Joyner 4635*6f37f232SEric Joyner new_eee_enabled = adapter->eee_enabled; 4636*6f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_eee_enabled, 0, req); 4637*6f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 4638*6f37f232SEric Joyner return (error); 4639*6f37f232SEric Joyner if (new_eee_enabled == adapter->eee_enabled) 4640*6f37f232SEric Joyner return (0); 4641*6f37f232SEric Joyner 4642*6f37f232SEric Joyner if (new_eee_enabled > 0 && !adapter->eee_support) 4643*6f37f232SEric Joyner return (ENODEV); 4644*6f37f232SEric Joyner else 4645*6f37f232SEric Joyner adapter->eee_enabled = !!(new_eee_enabled); 4646*6f37f232SEric Joyner 4647*6f37f232SEric Joyner /* Re-initialize hardware if it's already running */ 4648*6f37f232SEric Joyner if (ifp->if_drv_flags & IFF_DRV_RUNNING) 4649*6f37f232SEric Joyner ixgbe_init(adapter); 4650*6f37f232SEric Joyner 4651*6f37f232SEric Joyner return (0); 4652*6f37f232SEric Joyner } 4653*6f37f232SEric Joyner 4654*6f37f232SEric Joyner /* 4655*6f37f232SEric Joyner * Read-only sysctl indicating whether EEE support was negotiated 4656*6f37f232SEric Joyner * on the link. 4657*6f37f232SEric Joyner */ 4658*6f37f232SEric Joyner static int 4659*6f37f232SEric Joyner ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS) 4660*6f37f232SEric Joyner { 4661*6f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 4662*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 4663*6f37f232SEric Joyner bool status; 4664*6f37f232SEric Joyner 4665*6f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & IXGBE_EEE_STAT_NEG); 4666*6f37f232SEric Joyner 4667*6f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 4668*6f37f232SEric Joyner } 4669*6f37f232SEric Joyner 4670*6f37f232SEric Joyner /* 4671*6f37f232SEric Joyner * Read-only sysctl indicating whether RX Link is in LPI state. 4672*6f37f232SEric Joyner */ 4673*6f37f232SEric Joyner static int 4674*6f37f232SEric Joyner ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS) 4675*6f37f232SEric Joyner { 4676*6f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 4677*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 4678*6f37f232SEric Joyner bool status; 4679*6f37f232SEric Joyner 4680*6f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & 4681*6f37f232SEric Joyner IXGBE_EEE_RX_LPI_STATUS); 4682*6f37f232SEric Joyner 4683*6f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 4684*6f37f232SEric Joyner } 4685*6f37f232SEric Joyner 4686*6f37f232SEric Joyner /* 4687*6f37f232SEric Joyner * Read-only sysctl indicating whether TX Link is in LPI state. 4688*6f37f232SEric Joyner */ 4689*6f37f232SEric Joyner static int 4690*6f37f232SEric Joyner ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS) 4691*6f37f232SEric Joyner { 4692*6f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 4693*6f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 4694*6f37f232SEric Joyner bool status; 4695*6f37f232SEric Joyner 4696*6f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & 4697*6f37f232SEric Joyner IXGBE_EEE_TX_LPI_STATUS); 4698*6f37f232SEric Joyner 4699*6f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 4700*6f37f232SEric Joyner } 4701*6f37f232SEric Joyner 4702*6f37f232SEric Joyner /* 4703*6f37f232SEric Joyner * Sysctl to enable/disable the types of packets that the 4704*6f37f232SEric Joyner * adapter will wake up on upon receipt. 4705*6f37f232SEric Joyner * WUFC - Wake Up Filter Control 4706*6f37f232SEric Joyner * Flags: 4707*6f37f232SEric Joyner * 0x1 - Link Status Change 4708*6f37f232SEric Joyner * 0x2 - Magic Packet 4709*6f37f232SEric Joyner * 0x4 - Direct Exact 4710*6f37f232SEric Joyner * 0x8 - Directed Multicast 4711*6f37f232SEric Joyner * 0x10 - Broadcast 4712*6f37f232SEric Joyner * 0x20 - ARP/IPv4 Request Packet 4713*6f37f232SEric Joyner * 0x40 - Direct IPv4 Packet 4714*6f37f232SEric Joyner * 0x80 - Direct IPv6 Packet 4715*6f37f232SEric Joyner * 4716*6f37f232SEric Joyner * Setting another flag will cause the sysctl to return an 4717*6f37f232SEric Joyner * error. 4718*6f37f232SEric Joyner */ 4719*6f37f232SEric Joyner static int 4720*6f37f232SEric Joyner ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS) 4721*6f37f232SEric Joyner { 4722*6f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 4723*6f37f232SEric Joyner int error = 0; 4724*6f37f232SEric Joyner u32 new_wufc; 4725*6f37f232SEric Joyner 4726*6f37f232SEric Joyner new_wufc = adapter->wufc; 4727*6f37f232SEric Joyner 4728*6f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_wufc, 0, req); 4729*6f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 4730*6f37f232SEric Joyner return (error); 4731*6f37f232SEric Joyner if (new_wufc == adapter->wufc) 4732*6f37f232SEric Joyner return (0); 4733*6f37f232SEric Joyner 4734*6f37f232SEric Joyner if (new_wufc & 0xffffff00) 4735*6f37f232SEric Joyner return (EINVAL); 4736*6f37f232SEric Joyner else { 4737*6f37f232SEric Joyner new_wufc &= 0xff; 4738*6f37f232SEric Joyner new_wufc |= (0xffffff & adapter->wufc); 4739*6f37f232SEric Joyner adapter->wufc = new_wufc; 4740*6f37f232SEric Joyner } 4741*6f37f232SEric Joyner 4742*6f37f232SEric Joyner return (0); 4743*6f37f232SEric Joyner } 4744*6f37f232SEric Joyner 4745*6f37f232SEric Joyner /* 4746758cc3dcSJack F Vogel ** Enable the hardware to drop packets when the buffer is 4747758cc3dcSJack F Vogel ** full. This is useful when multiqueue,so that no single 4748758cc3dcSJack F Vogel ** queue being full stalls the entire RX engine. We only 4749758cc3dcSJack F Vogel ** enable this when Multiqueue AND when Flow Control is 4750758cc3dcSJack F Vogel ** disabled. 4751758cc3dcSJack F Vogel */ 4752758cc3dcSJack F Vogel static void 4753758cc3dcSJack F Vogel ixgbe_enable_rx_drop(struct adapter *adapter) 4754758cc3dcSJack F Vogel { 4755758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 4756758cc3dcSJack F Vogel 4757758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 4758758cc3dcSJack F Vogel u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); 4759758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DROP_EN; 4760758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); 4761758cc3dcSJack F Vogel } 4762758cc3dcSJack F Vogel } 4763758cc3dcSJack F Vogel 4764758cc3dcSJack F Vogel static void 4765758cc3dcSJack F Vogel ixgbe_disable_rx_drop(struct adapter *adapter) 4766758cc3dcSJack F Vogel { 4767758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 4768758cc3dcSJack F Vogel 4769758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 4770758cc3dcSJack F Vogel u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); 4771758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_DROP_EN; 4772758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); 4773758cc3dcSJack F Vogel } 4774758cc3dcSJack F Vogel } 4775758cc3dcSJack F Vogel 4776758cc3dcSJack F Vogel static void 4777758cc3dcSJack F Vogel ixgbe_rearm_queues(struct adapter *adapter, u64 queues) 4778758cc3dcSJack F Vogel { 4779758cc3dcSJack F Vogel u32 mask; 4780758cc3dcSJack F Vogel 4781758cc3dcSJack F Vogel switch (adapter->hw.mac.type) { 4782758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 4783758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queues); 4784758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); 4785758cc3dcSJack F Vogel break; 4786758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 4787758cc3dcSJack F Vogel case ixgbe_mac_X540: 4788758cc3dcSJack F Vogel case ixgbe_mac_X550: 4789*6f37f232SEric Joyner case ixgbe_mac_X550EM_x: 4790758cc3dcSJack F Vogel mask = (queues & 0xFFFFFFFF); 4791758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); 4792758cc3dcSJack F Vogel mask = (queues >> 32); 4793758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); 4794758cc3dcSJack F Vogel break; 4795758cc3dcSJack F Vogel default: 4796758cc3dcSJack F Vogel break; 4797758cc3dcSJack F Vogel } 4798758cc3dcSJack F Vogel } 4799758cc3dcSJack F Vogel 4800758cc3dcSJack F Vogel 4801