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 * Driver version 51758cc3dcSJack F Vogel *********************************************************************/ 52a9ca1c79SSean Bruno char ixgbe_driver_version[] = "3.1.13-k"; 53a9ca1c79SSean Bruno 54758cc3dcSJack F Vogel 55758cc3dcSJack F Vogel /********************************************************************* 56758cc3dcSJack F Vogel * PCI Device ID Table 57758cc3dcSJack F Vogel * 58758cc3dcSJack F Vogel * Used by probe to select devices to load on 59758cc3dcSJack F Vogel * Last field stores an index into ixgbe_strings 60758cc3dcSJack F Vogel * Last entry must be all 0s 61758cc3dcSJack F Vogel * 62758cc3dcSJack F Vogel * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 63758cc3dcSJack F Vogel *********************************************************************/ 64758cc3dcSJack F Vogel 65758cc3dcSJack F Vogel static ixgbe_vendor_info_t ixgbe_vendor_info_array[] = 66758cc3dcSJack F Vogel { 67758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT, 0, 0, 0}, 68758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT, 0, 0, 0}, 69758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4, 0, 0, 0}, 70758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT, 0, 0, 0}, 71758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT2, 0, 0, 0}, 72758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598, 0, 0, 0}, 73758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_DA_DUAL_PORT, 0, 0, 0}, 74758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_CX4_DUAL_PORT, 0, 0, 0}, 75758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_XF_LR, 0, 0, 0}, 76758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM, 0, 0, 0}, 77758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_SFP_LOM, 0, 0, 0}, 78758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4, 0, 0, 0}, 79758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4_MEZZ, 0, 0, 0}, 80758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP, 0, 0, 0}, 81758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_XAUI_LOM, 0, 0, 0}, 82758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_CX4, 0, 0, 0}, 83758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_T3_LOM, 0, 0, 0}, 84758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_COMBO_BACKPLANE, 0, 0, 0}, 85758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BACKPLANE_FCOE, 0, 0, 0}, 86758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF2, 0, 0, 0}, 87758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_FCOE, 0, 0, 0}, 88758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599EN_SFP, 0, 0, 0}, 89758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF_QP, 0, 0, 0}, 90758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_QSFP_SF_QP, 0, 0, 0}, 91758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T, 0, 0, 0}, 92758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T1, 0, 0, 0}, 93758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T, 0, 0, 0}, 94a9ca1c79SSean Bruno {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T1, 0, 0, 0}, 95758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KR, 0, 0, 0}, 96758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KX4, 0, 0, 0}, 97758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_10G_T, 0, 0, 0}, 98a9ca1c79SSean Bruno {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_SFP, 0, 0, 0}, 99758cc3dcSJack F Vogel /* required last entry */ 100758cc3dcSJack F Vogel {0, 0, 0, 0, 0} 101758cc3dcSJack F Vogel }; 102758cc3dcSJack F Vogel 103758cc3dcSJack F Vogel /********************************************************************* 104758cc3dcSJack F Vogel * Table of branding strings 105758cc3dcSJack F Vogel *********************************************************************/ 106758cc3dcSJack F Vogel 107758cc3dcSJack F Vogel static char *ixgbe_strings[] = { 108758cc3dcSJack F Vogel "Intel(R) PRO/10GbE PCI-Express Network Driver" 109758cc3dcSJack F Vogel }; 110758cc3dcSJack F Vogel 111758cc3dcSJack F Vogel /********************************************************************* 112758cc3dcSJack F Vogel * Function prototypes 113758cc3dcSJack F Vogel *********************************************************************/ 114758cc3dcSJack F Vogel static int ixgbe_probe(device_t); 115758cc3dcSJack F Vogel static int ixgbe_attach(device_t); 116758cc3dcSJack F Vogel static int ixgbe_detach(device_t); 117758cc3dcSJack F Vogel static int ixgbe_shutdown(device_t); 1186f37f232SEric Joyner static int ixgbe_suspend(device_t); 1196f37f232SEric Joyner static int ixgbe_resume(device_t); 120758cc3dcSJack F Vogel static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t); 121758cc3dcSJack F Vogel static void ixgbe_init(void *); 122758cc3dcSJack F Vogel static void ixgbe_init_locked(struct adapter *); 123758cc3dcSJack F Vogel static void ixgbe_stop(void *); 124758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 125758cc3dcSJack F Vogel static uint64_t ixgbe_get_counter(struct ifnet *, ift_counter); 126758cc3dcSJack F Vogel #endif 127758cc3dcSJack F Vogel static void ixgbe_add_media_types(struct adapter *); 128758cc3dcSJack F Vogel static void ixgbe_media_status(struct ifnet *, struct ifmediareq *); 129758cc3dcSJack F Vogel static int ixgbe_media_change(struct ifnet *); 130758cc3dcSJack F Vogel static void ixgbe_identify_hardware(struct adapter *); 131758cc3dcSJack F Vogel static int ixgbe_allocate_pci_resources(struct adapter *); 132a9ca1c79SSean Bruno static void ixgbe_get_slot_info(struct adapter *); 133758cc3dcSJack F Vogel static int ixgbe_allocate_msix(struct adapter *); 134758cc3dcSJack F Vogel static int ixgbe_allocate_legacy(struct adapter *); 135758cc3dcSJack F Vogel static int ixgbe_setup_msix(struct adapter *); 136758cc3dcSJack F Vogel static void ixgbe_free_pci_resources(struct adapter *); 137758cc3dcSJack F Vogel static void ixgbe_local_timer(void *); 138758cc3dcSJack F Vogel static int ixgbe_setup_interface(device_t, struct adapter *); 13948056c88SJack F Vogel static void ixgbe_config_gpie(struct adapter *); 1406f37f232SEric Joyner static void ixgbe_config_dmac(struct adapter *); 1416f37f232SEric Joyner static void ixgbe_config_delay_values(struct adapter *); 142758cc3dcSJack F Vogel static void ixgbe_config_link(struct adapter *); 1436f37f232SEric Joyner static void ixgbe_check_wol_support(struct adapter *); 1446f37f232SEric Joyner static int ixgbe_setup_low_power_mode(struct adapter *); 145758cc3dcSJack F Vogel static void ixgbe_rearm_queues(struct adapter *, u64); 146758cc3dcSJack F Vogel 147758cc3dcSJack F Vogel static void ixgbe_initialize_transmit_units(struct adapter *); 148758cc3dcSJack F Vogel static void ixgbe_initialize_receive_units(struct adapter *); 149758cc3dcSJack F Vogel static void ixgbe_enable_rx_drop(struct adapter *); 150758cc3dcSJack F Vogel static void ixgbe_disable_rx_drop(struct adapter *); 151a9ca1c79SSean Bruno static void ixgbe_initialize_rss_mapping(struct adapter *); 152758cc3dcSJack F Vogel 153758cc3dcSJack F Vogel static void ixgbe_enable_intr(struct adapter *); 154758cc3dcSJack F Vogel static void ixgbe_disable_intr(struct adapter *); 155758cc3dcSJack F Vogel static void ixgbe_update_stats_counters(struct adapter *); 156758cc3dcSJack F Vogel static void ixgbe_set_promisc(struct adapter *); 157758cc3dcSJack F Vogel static void ixgbe_set_multi(struct adapter *); 158758cc3dcSJack F Vogel static void ixgbe_update_link_status(struct adapter *); 159758cc3dcSJack F Vogel static void ixgbe_set_ivar(struct adapter *, u8, u8, s8); 160758cc3dcSJack F Vogel static void ixgbe_configure_ivars(struct adapter *); 161758cc3dcSJack F Vogel static u8 * ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); 162758cc3dcSJack F Vogel 163758cc3dcSJack F Vogel static void ixgbe_setup_vlan_hw_support(struct adapter *); 164758cc3dcSJack F Vogel static void ixgbe_register_vlan(void *, struct ifnet *, u16); 165758cc3dcSJack F Vogel static void ixgbe_unregister_vlan(void *, struct ifnet *, u16); 166758cc3dcSJack F Vogel 1676f37f232SEric Joyner static void ixgbe_add_device_sysctls(struct adapter *); 1686f37f232SEric Joyner static void ixgbe_add_hw_stats(struct adapter *); 169f2c4db54SSteven Hartland static int ixgbe_set_flowcntl(struct adapter *, int); 170f2c4db54SSteven Hartland static int ixgbe_set_advertise(struct adapter *, int); 1716f37f232SEric Joyner 1726f37f232SEric Joyner /* Sysctl handlers */ 173b0c041f8SSean Bruno static void ixgbe_set_sysctl_value(struct adapter *, const char *, 174b0c041f8SSean Bruno const char *, int *, int); 175f2c4db54SSteven Hartland static int ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS); 176f2c4db54SSteven Hartland static int ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS); 1776f37f232SEric Joyner static int ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS); 1786f37f232SEric Joyner static int ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS); 1796f37f232SEric Joyner static int ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS); 1806f37f232SEric Joyner static int ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS); 181a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG 182a9ca1c79SSean Bruno static int ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS); 183a9ca1c79SSean Bruno static int ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS); 184a9ca1c79SSean Bruno #endif 1856f37f232SEric Joyner static int ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS); 1866f37f232SEric Joyner static int ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS); 1876f37f232SEric Joyner static int ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS); 1886f37f232SEric Joyner static int ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS); 1896f37f232SEric Joyner static int ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS); 1906f37f232SEric Joyner static int ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS); 191a9ca1c79SSean Bruno static int ixgbe_sysctl_eee_tx_lpi_delay(SYSCTL_HANDLER_ARGS); 192758cc3dcSJack F Vogel 193758cc3dcSJack F Vogel /* Support for pluggable optic modules */ 194758cc3dcSJack F Vogel static bool ixgbe_sfp_probe(struct adapter *); 195758cc3dcSJack F Vogel static void ixgbe_setup_optics(struct adapter *); 196758cc3dcSJack F Vogel 197758cc3dcSJack F Vogel /* Legacy (single vector interrupt handler */ 198758cc3dcSJack F Vogel static void ixgbe_legacy_irq(void *); 199758cc3dcSJack F Vogel 200758cc3dcSJack F Vogel /* The MSI/X Interrupt handlers */ 201758cc3dcSJack F Vogel static void ixgbe_msix_que(void *); 202758cc3dcSJack F Vogel static void ixgbe_msix_link(void *); 203758cc3dcSJack F Vogel 204758cc3dcSJack F Vogel /* Deferred interrupt tasklets */ 205758cc3dcSJack F Vogel static void ixgbe_handle_que(void *, int); 206758cc3dcSJack F Vogel static void ixgbe_handle_link(void *, int); 207758cc3dcSJack F Vogel static void ixgbe_handle_msf(void *, int); 208758cc3dcSJack F Vogel static void ixgbe_handle_mod(void *, int); 2096f37f232SEric Joyner static void ixgbe_handle_phy(void *, int); 210758cc3dcSJack F Vogel 211758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 212758cc3dcSJack F Vogel static void ixgbe_reinit_fdir(void *, int); 213758cc3dcSJack F Vogel #endif 214758cc3dcSJack F Vogel 21548056c88SJack F Vogel #ifdef PCI_IOV 21648056c88SJack F Vogel static void ixgbe_ping_all_vfs(struct adapter *); 21748056c88SJack F Vogel static void ixgbe_handle_mbx(void *, int); 21848056c88SJack F Vogel static int ixgbe_init_iov(device_t, u16, const nvlist_t *); 21948056c88SJack F Vogel static void ixgbe_uninit_iov(device_t); 22048056c88SJack F Vogel static int ixgbe_add_vf(device_t, u16, const nvlist_t *); 22148056c88SJack F Vogel static void ixgbe_initialize_iov(struct adapter *); 22248056c88SJack F Vogel static void ixgbe_recalculate_max_frame(struct adapter *); 22348056c88SJack F Vogel static void ixgbe_init_vf(struct adapter *, struct ixgbe_vf *); 22448056c88SJack F Vogel #endif /* PCI_IOV */ 22548056c88SJack F Vogel 22648056c88SJack F Vogel 227758cc3dcSJack F Vogel /********************************************************************* 228758cc3dcSJack F Vogel * FreeBSD Device Interface Entry Points 229758cc3dcSJack F Vogel *********************************************************************/ 230758cc3dcSJack F Vogel 231a1edda90SAdrian Chadd static device_method_t ix_methods[] = { 232758cc3dcSJack F Vogel /* Device interface */ 233758cc3dcSJack F Vogel DEVMETHOD(device_probe, ixgbe_probe), 234758cc3dcSJack F Vogel DEVMETHOD(device_attach, ixgbe_attach), 235758cc3dcSJack F Vogel DEVMETHOD(device_detach, ixgbe_detach), 236758cc3dcSJack F Vogel DEVMETHOD(device_shutdown, ixgbe_shutdown), 2376f37f232SEric Joyner DEVMETHOD(device_suspend, ixgbe_suspend), 2386f37f232SEric Joyner DEVMETHOD(device_resume, ixgbe_resume), 23948056c88SJack F Vogel #ifdef PCI_IOV 2409e34aea2SJohn Baldwin DEVMETHOD(pci_iov_init, ixgbe_init_iov), 2419e34aea2SJohn Baldwin DEVMETHOD(pci_iov_uninit, ixgbe_uninit_iov), 2429e34aea2SJohn Baldwin DEVMETHOD(pci_iov_add_vf, ixgbe_add_vf), 24348056c88SJack F Vogel #endif /* PCI_IOV */ 244758cc3dcSJack F Vogel DEVMETHOD_END 245758cc3dcSJack F Vogel }; 246758cc3dcSJack F Vogel 247a1edda90SAdrian Chadd static driver_t ix_driver = { 248a1edda90SAdrian Chadd "ix", ix_methods, sizeof(struct adapter), 249758cc3dcSJack F Vogel }; 250758cc3dcSJack F Vogel 251a1edda90SAdrian Chadd devclass_t ix_devclass; 252a1edda90SAdrian Chadd DRIVER_MODULE(ix, pci, ix_driver, ix_devclass, 0, 0); 253758cc3dcSJack F Vogel 254a1edda90SAdrian Chadd MODULE_DEPEND(ix, pci, 1, 1, 1); 255a1edda90SAdrian Chadd MODULE_DEPEND(ix, ether, 1, 1, 1); 256847bf383SLuigi Rizzo #ifdef DEV_NETMAP 257847bf383SLuigi Rizzo MODULE_DEPEND(ix, netmap, 1, 1, 1); 258847bf383SLuigi Rizzo #endif /* DEV_NETMAP */ 259758cc3dcSJack F Vogel 260758cc3dcSJack F Vogel /* 261758cc3dcSJack F Vogel ** TUNEABLE PARAMETERS: 262758cc3dcSJack F Vogel */ 263758cc3dcSJack F Vogel 264758cc3dcSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0, 265758cc3dcSJack F Vogel "IXGBE driver parameters"); 266758cc3dcSJack F Vogel 267758cc3dcSJack F Vogel /* 268758cc3dcSJack F Vogel ** AIM: Adaptive Interrupt Moderation 269758cc3dcSJack F Vogel ** which means that the interrupt rate 270758cc3dcSJack F Vogel ** is varied over time based on the 271758cc3dcSJack F Vogel ** traffic for that interrupt vector 272758cc3dcSJack F Vogel */ 273758cc3dcSJack F Vogel static int ixgbe_enable_aim = TRUE; 274758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0, 275758cc3dcSJack F Vogel "Enable adaptive interrupt moderation"); 276758cc3dcSJack F Vogel 277758cc3dcSJack F Vogel static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY); 278758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN, 279758cc3dcSJack F Vogel &ixgbe_max_interrupt_rate, 0, "Maximum interrupts per second"); 280758cc3dcSJack F Vogel 281758cc3dcSJack F Vogel /* How many packets rxeof tries to clean at a time */ 282758cc3dcSJack F Vogel static int ixgbe_rx_process_limit = 256; 283758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, 284758cc3dcSJack F Vogel &ixgbe_rx_process_limit, 0, 285758cc3dcSJack F Vogel "Maximum number of received packets to process at a time," 286758cc3dcSJack F Vogel "-1 means unlimited"); 287758cc3dcSJack F Vogel 288758cc3dcSJack F Vogel /* How many packets txeof tries to clean at a time */ 289758cc3dcSJack F Vogel static int ixgbe_tx_process_limit = 256; 290758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, tx_process_limit, CTLFLAG_RDTUN, 291758cc3dcSJack F Vogel &ixgbe_tx_process_limit, 0, 292758cc3dcSJack F Vogel "Maximum number of sent packets to process at a time," 293758cc3dcSJack F Vogel "-1 means unlimited"); 294758cc3dcSJack F Vogel 295f2c4db54SSteven Hartland /* Flow control setting, default to full */ 296f2c4db54SSteven Hartland static int ixgbe_flow_control = ixgbe_fc_full; 297f2c4db54SSteven Hartland SYSCTL_INT(_hw_ix, OID_AUTO, flow_control, CTLFLAG_RDTUN, 298f2c4db54SSteven Hartland &ixgbe_flow_control, 0, "Default flow control used for all adapters"); 299f2c4db54SSteven Hartland 300f2c4db54SSteven Hartland /* Advertise Speed, default to 0 (auto) */ 301f2c4db54SSteven Hartland static int ixgbe_advertise_speed = 0; 302f2c4db54SSteven Hartland SYSCTL_INT(_hw_ix, OID_AUTO, advertise_speed, CTLFLAG_RDTUN, 303f2c4db54SSteven Hartland &ixgbe_advertise_speed, 0, "Default advertised speed for all adapters"); 304f2c4db54SSteven Hartland 305758cc3dcSJack F Vogel /* 306758cc3dcSJack F Vogel ** Smart speed setting, default to on 307758cc3dcSJack F Vogel ** this only works as a compile option 308758cc3dcSJack F Vogel ** right now as its during attach, set 309758cc3dcSJack F Vogel ** this to 'ixgbe_smart_speed_off' to 310758cc3dcSJack F Vogel ** disable. 311758cc3dcSJack F Vogel */ 312758cc3dcSJack F Vogel static int ixgbe_smart_speed = ixgbe_smart_speed_on; 313758cc3dcSJack F Vogel 314758cc3dcSJack F Vogel /* 315758cc3dcSJack F Vogel * MSIX should be the default for best performance, 316758cc3dcSJack F Vogel * but this allows it to be forced off for testing. 317758cc3dcSJack F Vogel */ 318758cc3dcSJack F Vogel static int ixgbe_enable_msix = 1; 319758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixgbe_enable_msix, 0, 320758cc3dcSJack F Vogel "Enable MSI-X interrupts"); 321758cc3dcSJack F Vogel 322758cc3dcSJack F Vogel /* 323758cc3dcSJack F Vogel * Number of Queues, can be set to 0, 324758cc3dcSJack F Vogel * it then autoconfigures based on the 325758cc3dcSJack F Vogel * number of cpus with a max of 8. This 326758cc3dcSJack F Vogel * can be overriden manually here. 327758cc3dcSJack F Vogel */ 328758cc3dcSJack F Vogel static int ixgbe_num_queues = 0; 329758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, num_queues, CTLFLAG_RDTUN, &ixgbe_num_queues, 0, 330758cc3dcSJack F Vogel "Number of queues to configure, 0 indicates autoconfigure"); 331758cc3dcSJack F Vogel 332758cc3dcSJack F Vogel /* 333758cc3dcSJack F Vogel ** Number of TX descriptors per ring, 334758cc3dcSJack F Vogel ** setting higher than RX as this seems 335758cc3dcSJack F Vogel ** the better performing choice. 336758cc3dcSJack F Vogel */ 337758cc3dcSJack F Vogel static int ixgbe_txd = PERFORM_TXD; 338758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, txd, CTLFLAG_RDTUN, &ixgbe_txd, 0, 339758cc3dcSJack F Vogel "Number of transmit descriptors per queue"); 340758cc3dcSJack F Vogel 341758cc3dcSJack F Vogel /* Number of RX descriptors per ring */ 342758cc3dcSJack F Vogel static int ixgbe_rxd = PERFORM_RXD; 343758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rxd, CTLFLAG_RDTUN, &ixgbe_rxd, 0, 344758cc3dcSJack F Vogel "Number of receive descriptors per queue"); 345758cc3dcSJack F Vogel 346758cc3dcSJack F Vogel /* 347758cc3dcSJack F Vogel ** Defining this on will allow the use 348758cc3dcSJack F Vogel ** of unsupported SFP+ modules, note that 349758cc3dcSJack F Vogel ** doing so you are on your own :) 350758cc3dcSJack F Vogel */ 351758cc3dcSJack F Vogel static int allow_unsupported_sfp = FALSE; 352758cc3dcSJack F Vogel TUNABLE_INT("hw.ix.unsupported_sfp", &allow_unsupported_sfp); 353758cc3dcSJack F Vogel 354758cc3dcSJack F Vogel /* Keep running tab on them for sanity check */ 355758cc3dcSJack F Vogel static int ixgbe_total_ports; 356758cc3dcSJack F Vogel 357758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 358758cc3dcSJack F Vogel /* 359758cc3dcSJack F Vogel ** Flow Director actually 'steals' 360758cc3dcSJack F Vogel ** part of the packet buffer as its 361758cc3dcSJack F Vogel ** filter pool, this variable controls 362758cc3dcSJack F Vogel ** how much it uses: 363758cc3dcSJack F Vogel ** 0 = 64K, 1 = 128K, 2 = 256K 364758cc3dcSJack F Vogel */ 365758cc3dcSJack F Vogel static int fdir_pballoc = 1; 366758cc3dcSJack F Vogel #endif 367758cc3dcSJack F Vogel 368758cc3dcSJack F Vogel #ifdef DEV_NETMAP 369758cc3dcSJack F Vogel /* 370758cc3dcSJack F Vogel * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to 371758cc3dcSJack F Vogel * be a reference on how to implement netmap support in a driver. 372758cc3dcSJack F Vogel * Additional comments are in ixgbe_netmap.h . 373758cc3dcSJack F Vogel * 374758cc3dcSJack F Vogel * <dev/netmap/ixgbe_netmap.h> contains functions for netmap support 375758cc3dcSJack F Vogel * that extend the standard driver. 376758cc3dcSJack F Vogel */ 377758cc3dcSJack F Vogel #include <dev/netmap/ixgbe_netmap.h> 378758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 379758cc3dcSJack F Vogel 38048056c88SJack F Vogel static MALLOC_DEFINE(M_IXGBE, "ix", "ix driver allocations"); 38148056c88SJack F Vogel 382758cc3dcSJack F Vogel /********************************************************************* 383758cc3dcSJack F Vogel * Device identification routine 384758cc3dcSJack F Vogel * 385758cc3dcSJack F Vogel * ixgbe_probe determines if the driver should be loaded on 386758cc3dcSJack F Vogel * adapter based on PCI vendor/device id of the adapter. 387758cc3dcSJack F Vogel * 388758cc3dcSJack F Vogel * return BUS_PROBE_DEFAULT on success, positive on failure 389758cc3dcSJack F Vogel *********************************************************************/ 390758cc3dcSJack F Vogel 391758cc3dcSJack F Vogel static int 392758cc3dcSJack F Vogel ixgbe_probe(device_t dev) 393758cc3dcSJack F Vogel { 394758cc3dcSJack F Vogel ixgbe_vendor_info_t *ent; 395758cc3dcSJack F Vogel 396758cc3dcSJack F Vogel u16 pci_vendor_id = 0; 397758cc3dcSJack F Vogel u16 pci_device_id = 0; 398758cc3dcSJack F Vogel u16 pci_subvendor_id = 0; 399758cc3dcSJack F Vogel u16 pci_subdevice_id = 0; 400758cc3dcSJack F Vogel char adapter_name[256]; 401758cc3dcSJack F Vogel 402758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_probe: begin"); 403758cc3dcSJack F Vogel 404758cc3dcSJack F Vogel pci_vendor_id = pci_get_vendor(dev); 405758cc3dcSJack F Vogel if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) 406758cc3dcSJack F Vogel return (ENXIO); 407758cc3dcSJack F Vogel 408758cc3dcSJack F Vogel pci_device_id = pci_get_device(dev); 409758cc3dcSJack F Vogel pci_subvendor_id = pci_get_subvendor(dev); 410758cc3dcSJack F Vogel pci_subdevice_id = pci_get_subdevice(dev); 411758cc3dcSJack F Vogel 412758cc3dcSJack F Vogel ent = ixgbe_vendor_info_array; 413758cc3dcSJack F Vogel while (ent->vendor_id != 0) { 414758cc3dcSJack F Vogel if ((pci_vendor_id == ent->vendor_id) && 415758cc3dcSJack F Vogel (pci_device_id == ent->device_id) && 416758cc3dcSJack F Vogel 417758cc3dcSJack F Vogel ((pci_subvendor_id == ent->subvendor_id) || 418758cc3dcSJack F Vogel (ent->subvendor_id == 0)) && 419758cc3dcSJack F Vogel 420758cc3dcSJack F Vogel ((pci_subdevice_id == ent->subdevice_id) || 421758cc3dcSJack F Vogel (ent->subdevice_id == 0))) { 422758cc3dcSJack F Vogel sprintf(adapter_name, "%s, Version - %s", 423758cc3dcSJack F Vogel ixgbe_strings[ent->index], 424758cc3dcSJack F Vogel ixgbe_driver_version); 425758cc3dcSJack F Vogel device_set_desc_copy(dev, adapter_name); 426758cc3dcSJack F Vogel ++ixgbe_total_ports; 427758cc3dcSJack F Vogel return (BUS_PROBE_DEFAULT); 428758cc3dcSJack F Vogel } 429758cc3dcSJack F Vogel ent++; 430758cc3dcSJack F Vogel } 431758cc3dcSJack F Vogel return (ENXIO); 432758cc3dcSJack F Vogel } 433758cc3dcSJack F Vogel 434758cc3dcSJack F Vogel /********************************************************************* 435758cc3dcSJack F Vogel * Device initialization routine 436758cc3dcSJack F Vogel * 437758cc3dcSJack F Vogel * The attach entry point is called when the driver is being loaded. 438758cc3dcSJack F Vogel * This routine identifies the type of hardware, allocates all resources 439758cc3dcSJack F Vogel * and initializes the hardware. 440758cc3dcSJack F Vogel * 441758cc3dcSJack F Vogel * return 0 on success, positive on failure 442758cc3dcSJack F Vogel *********************************************************************/ 443758cc3dcSJack F Vogel 444758cc3dcSJack F Vogel static int 445758cc3dcSJack F Vogel ixgbe_attach(device_t dev) 446758cc3dcSJack F Vogel { 447758cc3dcSJack F Vogel struct adapter *adapter; 448758cc3dcSJack F Vogel struct ixgbe_hw *hw; 449758cc3dcSJack F Vogel int error = 0; 450758cc3dcSJack F Vogel u16 csum; 451758cc3dcSJack F Vogel u32 ctrl_ext; 452758cc3dcSJack F Vogel 453758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_attach: begin"); 454758cc3dcSJack F Vogel 455758cc3dcSJack F Vogel /* Allocate, clear, and link in our adapter structure */ 456758cc3dcSJack F Vogel adapter = device_get_softc(dev); 457a9ca1c79SSean Bruno adapter->dev = dev; 458758cc3dcSJack F Vogel hw = &adapter->hw; 459758cc3dcSJack F Vogel 4608aa7fdbdSPatrick Kelsey #ifdef DEV_NETMAP 4618aa7fdbdSPatrick Kelsey adapter->init_locked = ixgbe_init_locked; 4628aa7fdbdSPatrick Kelsey adapter->stop_locked = ixgbe_stop; 4638aa7fdbdSPatrick Kelsey #endif 4648aa7fdbdSPatrick Kelsey 465758cc3dcSJack F Vogel /* Core Lock Init*/ 466758cc3dcSJack F Vogel IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); 467758cc3dcSJack F Vogel 468758cc3dcSJack F Vogel /* Set up the timer callout */ 469758cc3dcSJack F Vogel callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); 470758cc3dcSJack F Vogel 471758cc3dcSJack F Vogel /* Determine hardware revision */ 472758cc3dcSJack F Vogel ixgbe_identify_hardware(adapter); 473758cc3dcSJack F Vogel 474758cc3dcSJack F Vogel /* Do base PCI setup - map BAR0 */ 475758cc3dcSJack F Vogel if (ixgbe_allocate_pci_resources(adapter)) { 476758cc3dcSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 477758cc3dcSJack F Vogel error = ENXIO; 478758cc3dcSJack F Vogel goto err_out; 479758cc3dcSJack F Vogel } 480758cc3dcSJack F Vogel 481b0c041f8SSean Bruno /* Sysctls for limiting the amount of work done in the taskqueues */ 482b0c041f8SSean Bruno ixgbe_set_sysctl_value(adapter, "rx_processing_limit", 483b0c041f8SSean Bruno "max number of rx packets to process", 484b0c041f8SSean Bruno &adapter->rx_process_limit, ixgbe_rx_process_limit); 485b0c041f8SSean Bruno 486b0c041f8SSean Bruno ixgbe_set_sysctl_value(adapter, "tx_processing_limit", 487b0c041f8SSean Bruno "max number of tx packets to process", 488b0c041f8SSean Bruno &adapter->tx_process_limit, ixgbe_tx_process_limit); 489b0c041f8SSean Bruno 490758cc3dcSJack F Vogel /* Do descriptor calc and sanity checks */ 491758cc3dcSJack F Vogel if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || 492758cc3dcSJack F Vogel ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) { 493758cc3dcSJack F Vogel device_printf(dev, "TXD config issue, using default!\n"); 494758cc3dcSJack F Vogel adapter->num_tx_desc = DEFAULT_TXD; 495758cc3dcSJack F Vogel } else 496758cc3dcSJack F Vogel adapter->num_tx_desc = ixgbe_txd; 497758cc3dcSJack F Vogel 498758cc3dcSJack F Vogel /* 499758cc3dcSJack F Vogel ** With many RX rings it is easy to exceed the 500758cc3dcSJack F Vogel ** system mbuf allocation. Tuning nmbclusters 501758cc3dcSJack F Vogel ** can alleviate this. 502758cc3dcSJack F Vogel */ 503758cc3dcSJack F Vogel if (nmbclusters > 0) { 504758cc3dcSJack F Vogel int s; 505758cc3dcSJack F Vogel s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports; 506758cc3dcSJack F Vogel if (s > nmbclusters) { 507758cc3dcSJack F Vogel device_printf(dev, "RX Descriptors exceed " 508758cc3dcSJack F Vogel "system mbuf max, using default instead!\n"); 509758cc3dcSJack F Vogel ixgbe_rxd = DEFAULT_RXD; 510758cc3dcSJack F Vogel } 511758cc3dcSJack F Vogel } 512758cc3dcSJack F Vogel 513758cc3dcSJack F Vogel if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || 514758cc3dcSJack F Vogel ixgbe_rxd < MIN_RXD || ixgbe_rxd > MAX_RXD) { 515758cc3dcSJack F Vogel device_printf(dev, "RXD config issue, using default!\n"); 516758cc3dcSJack F Vogel adapter->num_rx_desc = DEFAULT_RXD; 517758cc3dcSJack F Vogel } else 518758cc3dcSJack F Vogel adapter->num_rx_desc = ixgbe_rxd; 519758cc3dcSJack F Vogel 520758cc3dcSJack F Vogel /* Allocate our TX/RX Queues */ 521758cc3dcSJack F Vogel if (ixgbe_allocate_queues(adapter)) { 522758cc3dcSJack F Vogel error = ENOMEM; 523758cc3dcSJack F Vogel goto err_out; 524758cc3dcSJack F Vogel } 525758cc3dcSJack F Vogel 526758cc3dcSJack F Vogel /* Allocate multicast array memory. */ 52748056c88SJack F Vogel adapter->mta = malloc(sizeof(*adapter->mta) * 528758cc3dcSJack F Vogel MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); 529758cc3dcSJack F Vogel if (adapter->mta == NULL) { 530758cc3dcSJack F Vogel device_printf(dev, "Can not allocate multicast setup array\n"); 531758cc3dcSJack F Vogel error = ENOMEM; 532758cc3dcSJack F Vogel goto err_late; 533758cc3dcSJack F Vogel } 534758cc3dcSJack F Vogel 535758cc3dcSJack F Vogel /* Initialize the shared code */ 536758cc3dcSJack F Vogel hw->allow_unsupported_sfp = allow_unsupported_sfp; 537758cc3dcSJack F Vogel error = ixgbe_init_shared_code(hw); 538758cc3dcSJack F Vogel if (error == IXGBE_ERR_SFP_NOT_PRESENT) { 539758cc3dcSJack F Vogel /* 540758cc3dcSJack F Vogel ** No optics in this port, set up 541758cc3dcSJack F Vogel ** so the timer routine will probe 542758cc3dcSJack F Vogel ** for later insertion. 543758cc3dcSJack F Vogel */ 544758cc3dcSJack F Vogel adapter->sfp_probe = TRUE; 545758cc3dcSJack F Vogel error = 0; 546758cc3dcSJack F Vogel } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { 547758cc3dcSJack F Vogel device_printf(dev, "Unsupported SFP+ module detected!\n"); 548758cc3dcSJack F Vogel error = EIO; 549758cc3dcSJack F Vogel goto err_late; 550758cc3dcSJack F Vogel } else if (error) { 551758cc3dcSJack F Vogel device_printf(dev, "Unable to initialize the shared code\n"); 552758cc3dcSJack F Vogel error = EIO; 553758cc3dcSJack F Vogel goto err_late; 554758cc3dcSJack F Vogel } 555758cc3dcSJack F Vogel 556758cc3dcSJack F Vogel /* Make sure we have a good EEPROM before we read from it */ 557758cc3dcSJack F Vogel if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) { 558758cc3dcSJack F Vogel device_printf(dev, "The EEPROM Checksum Is Not Valid\n"); 559758cc3dcSJack F Vogel error = EIO; 560758cc3dcSJack F Vogel goto err_late; 561758cc3dcSJack F Vogel } 562758cc3dcSJack F Vogel 563758cc3dcSJack F Vogel error = ixgbe_init_hw(hw); 564758cc3dcSJack F Vogel switch (error) { 565758cc3dcSJack F Vogel case IXGBE_ERR_EEPROM_VERSION: 566758cc3dcSJack F Vogel device_printf(dev, "This device is a pre-production adapter/" 567758cc3dcSJack F Vogel "LOM. Please be aware there may be issues associated " 568758cc3dcSJack F Vogel "with your hardware.\nIf you are experiencing problems " 569758cc3dcSJack F Vogel "please contact your Intel or hardware representative " 570758cc3dcSJack F Vogel "who provided you with this hardware.\n"); 571758cc3dcSJack F Vogel break; 572758cc3dcSJack F Vogel case IXGBE_ERR_SFP_NOT_SUPPORTED: 573758cc3dcSJack F Vogel device_printf(dev, "Unsupported SFP+ Module\n"); 574758cc3dcSJack F Vogel error = EIO; 575758cc3dcSJack F Vogel goto err_late; 576758cc3dcSJack F Vogel case IXGBE_ERR_SFP_NOT_PRESENT: 577758cc3dcSJack F Vogel device_printf(dev, "No SFP+ Module found\n"); 578758cc3dcSJack F Vogel /* falls thru */ 579758cc3dcSJack F Vogel default: 580758cc3dcSJack F Vogel break; 581758cc3dcSJack F Vogel } 582758cc3dcSJack F Vogel 583f2c4db54SSteven Hartland /* hw.ix defaults init */ 584f2c4db54SSteven Hartland ixgbe_set_advertise(adapter, ixgbe_advertise_speed); 585f2c4db54SSteven Hartland ixgbe_set_flowcntl(adapter, ixgbe_flow_control); 586f2c4db54SSteven Hartland adapter->enable_aim = ixgbe_enable_aim; 587f2c4db54SSteven Hartland 588758cc3dcSJack F Vogel if ((adapter->msix > 1) && (ixgbe_enable_msix)) 589758cc3dcSJack F Vogel error = ixgbe_allocate_msix(adapter); 590758cc3dcSJack F Vogel else 591758cc3dcSJack F Vogel error = ixgbe_allocate_legacy(adapter); 592758cc3dcSJack F Vogel if (error) 593758cc3dcSJack F Vogel goto err_late; 594758cc3dcSJack F Vogel 5951ebf555bSSteven Hartland /* Enable the optics for 82599 SFP+ fiber */ 5961ebf555bSSteven Hartland ixgbe_enable_tx_laser(hw); 5971ebf555bSSteven Hartland 5981ebf555bSSteven Hartland /* Enable power to the phy. */ 5991ebf555bSSteven Hartland ixgbe_set_phy_power(hw, TRUE); 6001ebf555bSSteven Hartland 601758cc3dcSJack F Vogel /* Setup OS specific network interface */ 602758cc3dcSJack F Vogel if (ixgbe_setup_interface(dev, adapter) != 0) 603758cc3dcSJack F Vogel goto err_late; 604758cc3dcSJack F Vogel 605758cc3dcSJack F Vogel /* Initialize statistics */ 606758cc3dcSJack F Vogel ixgbe_update_stats_counters(adapter); 607758cc3dcSJack F Vogel 608758cc3dcSJack F Vogel /* Register for VLAN events */ 609758cc3dcSJack F Vogel adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 610758cc3dcSJack F Vogel ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); 611758cc3dcSJack F Vogel adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 612758cc3dcSJack F Vogel ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); 613758cc3dcSJack F Vogel 6146f37f232SEric Joyner /* Check PCIE slot type/speed/width */ 615a9ca1c79SSean Bruno ixgbe_get_slot_info(adapter); 616758cc3dcSJack F Vogel 617a9ca1c79SSean Bruno /* Set an initial default flow control & dmac value */ 618758cc3dcSJack F Vogel adapter->fc = ixgbe_fc_full; 619a9ca1c79SSean Bruno adapter->dmac = 0; 620a9ca1c79SSean Bruno adapter->eee_enabled = 0; 621758cc3dcSJack F Vogel 62248056c88SJack F Vogel #ifdef PCI_IOV 62348056c88SJack F Vogel if ((hw->mac.type != ixgbe_mac_82598EB) && (adapter->msix > 1)) { 62448056c88SJack F Vogel nvlist_t *pf_schema, *vf_schema; 62548056c88SJack F Vogel 62648056c88SJack F Vogel hw->mbx.ops.init_params(hw); 62748056c88SJack F Vogel pf_schema = pci_iov_schema_alloc_node(); 62848056c88SJack F Vogel vf_schema = pci_iov_schema_alloc_node(); 62948056c88SJack F Vogel pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); 63048056c88SJack F Vogel pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", 63148056c88SJack F Vogel IOV_SCHEMA_HASDEFAULT, TRUE); 63248056c88SJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-set-mac", 63348056c88SJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 63448056c88SJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-promisc", 63548056c88SJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 63648056c88SJack F Vogel error = pci_iov_attach(dev, pf_schema, vf_schema); 63748056c88SJack F Vogel if (error != 0) { 63848056c88SJack F Vogel device_printf(dev, 63948056c88SJack F Vogel "Error %d setting up SR-IOV\n", error); 64048056c88SJack F Vogel } 64148056c88SJack F Vogel } 64248056c88SJack F Vogel #endif /* PCI_IOV */ 64348056c88SJack F Vogel 6446f37f232SEric Joyner /* Check for certain supported features */ 6456f37f232SEric Joyner ixgbe_check_wol_support(adapter); 6466f37f232SEric Joyner 6476f37f232SEric Joyner /* Add sysctls */ 6486f37f232SEric Joyner ixgbe_add_device_sysctls(adapter); 6496f37f232SEric Joyner ixgbe_add_hw_stats(adapter); 6506f37f232SEric Joyner 651758cc3dcSJack F Vogel /* let hardware know driver is loaded */ 652758cc3dcSJack F Vogel ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 653758cc3dcSJack F Vogel ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; 654758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 655758cc3dcSJack F Vogel 656758cc3dcSJack F Vogel #ifdef DEV_NETMAP 657758cc3dcSJack F Vogel ixgbe_netmap_attach(adapter); 658758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 659758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_attach: end"); 660758cc3dcSJack F Vogel return (0); 661758cc3dcSJack F Vogel 662758cc3dcSJack F Vogel err_late: 663758cc3dcSJack F Vogel ixgbe_free_transmit_structures(adapter); 664758cc3dcSJack F Vogel ixgbe_free_receive_structures(adapter); 665758cc3dcSJack F Vogel err_out: 666758cc3dcSJack F Vogel if (adapter->ifp != NULL) 667758cc3dcSJack F Vogel if_free(adapter->ifp); 668758cc3dcSJack F Vogel ixgbe_free_pci_resources(adapter); 669758cc3dcSJack F Vogel free(adapter->mta, M_DEVBUF); 670758cc3dcSJack F Vogel return (error); 671758cc3dcSJack F Vogel } 672758cc3dcSJack F Vogel 673758cc3dcSJack F Vogel /********************************************************************* 674758cc3dcSJack F Vogel * Device removal routine 675758cc3dcSJack F Vogel * 676758cc3dcSJack F Vogel * The detach entry point is called when the driver is being removed. 677758cc3dcSJack F Vogel * This routine stops the adapter and deallocates all the resources 678758cc3dcSJack F Vogel * that were allocated for driver operation. 679758cc3dcSJack F Vogel * 680758cc3dcSJack F Vogel * return 0 on success, positive on failure 681758cc3dcSJack F Vogel *********************************************************************/ 682758cc3dcSJack F Vogel 683758cc3dcSJack F Vogel static int 684758cc3dcSJack F Vogel ixgbe_detach(device_t dev) 685758cc3dcSJack F Vogel { 686758cc3dcSJack F Vogel struct adapter *adapter = device_get_softc(dev); 687758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 688758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 689758cc3dcSJack F Vogel u32 ctrl_ext; 690758cc3dcSJack F Vogel 691758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_detach: begin"); 692758cc3dcSJack F Vogel 693758cc3dcSJack F Vogel /* Make sure VLANS are not using driver */ 694758cc3dcSJack F Vogel if (adapter->ifp->if_vlantrunk != NULL) { 695758cc3dcSJack F Vogel device_printf(dev,"Vlan in use, detach first\n"); 696758cc3dcSJack F Vogel return (EBUSY); 697758cc3dcSJack F Vogel } 698758cc3dcSJack F Vogel 69948056c88SJack F Vogel #ifdef PCI_IOV 70048056c88SJack F Vogel if (pci_iov_detach(dev) != 0) { 70148056c88SJack F Vogel device_printf(dev, "SR-IOV in use; detach first.\n"); 70248056c88SJack F Vogel return (EBUSY); 70348056c88SJack F Vogel } 70448056c88SJack F Vogel #endif /* PCI_IOV */ 70548056c88SJack F Vogel 706a9ca1c79SSean Bruno ether_ifdetach(adapter->ifp); 7076f37f232SEric Joyner /* Stop the adapter */ 708758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 7096f37f232SEric Joyner ixgbe_setup_low_power_mode(adapter); 710758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 711758cc3dcSJack F Vogel 712758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { 713758cc3dcSJack F Vogel if (que->tq) { 714758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 715758cc3dcSJack F Vogel taskqueue_drain(que->tq, &txr->txq_task); 716758cc3dcSJack F Vogel #endif 717758cc3dcSJack F Vogel taskqueue_drain(que->tq, &que->que_task); 718758cc3dcSJack F Vogel taskqueue_free(que->tq); 719758cc3dcSJack F Vogel } 720758cc3dcSJack F Vogel } 721758cc3dcSJack F Vogel 722758cc3dcSJack F Vogel /* Drain the Link queue */ 723758cc3dcSJack F Vogel if (adapter->tq) { 724758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->link_task); 725758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->mod_task); 726758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->msf_task); 72748056c88SJack F Vogel #ifdef PCI_IOV 72848056c88SJack F Vogel taskqueue_drain(adapter->tq, &adapter->mbx_task); 72948056c88SJack F Vogel #endif 7306f37f232SEric Joyner taskqueue_drain(adapter->tq, &adapter->phy_task); 731758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 732758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->fdir_task); 733758cc3dcSJack F Vogel #endif 734758cc3dcSJack F Vogel taskqueue_free(adapter->tq); 735758cc3dcSJack F Vogel } 736758cc3dcSJack F Vogel 737758cc3dcSJack F Vogel /* let hardware know driver is unloading */ 738758cc3dcSJack F Vogel ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); 739758cc3dcSJack F Vogel ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; 740758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext); 741758cc3dcSJack F Vogel 742758cc3dcSJack F Vogel /* Unregister VLAN events */ 743758cc3dcSJack F Vogel if (adapter->vlan_attach != NULL) 744758cc3dcSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); 745758cc3dcSJack F Vogel if (adapter->vlan_detach != NULL) 746758cc3dcSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); 747758cc3dcSJack F Vogel 748758cc3dcSJack F Vogel callout_drain(&adapter->timer); 749758cc3dcSJack F Vogel #ifdef DEV_NETMAP 750758cc3dcSJack F Vogel netmap_detach(adapter->ifp); 751758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 752758cc3dcSJack F Vogel ixgbe_free_pci_resources(adapter); 753758cc3dcSJack F Vogel bus_generic_detach(dev); 754758cc3dcSJack F Vogel if_free(adapter->ifp); 755758cc3dcSJack F Vogel 756758cc3dcSJack F Vogel ixgbe_free_transmit_structures(adapter); 757758cc3dcSJack F Vogel ixgbe_free_receive_structures(adapter); 758758cc3dcSJack F Vogel free(adapter->mta, M_DEVBUF); 759758cc3dcSJack F Vogel 760758cc3dcSJack F Vogel IXGBE_CORE_LOCK_DESTROY(adapter); 761758cc3dcSJack F Vogel return (0); 762758cc3dcSJack F Vogel } 763758cc3dcSJack F Vogel 764758cc3dcSJack F Vogel /********************************************************************* 765758cc3dcSJack F Vogel * 766758cc3dcSJack F Vogel * Shutdown entry point 767758cc3dcSJack F Vogel * 768758cc3dcSJack F Vogel **********************************************************************/ 769758cc3dcSJack F Vogel 770758cc3dcSJack F Vogel static int 771758cc3dcSJack F Vogel ixgbe_shutdown(device_t dev) 772758cc3dcSJack F Vogel { 773758cc3dcSJack F Vogel struct adapter *adapter = device_get_softc(dev); 7746f37f232SEric Joyner int error = 0; 7756f37f232SEric Joyner 7766f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_shutdown: begin"); 7776f37f232SEric Joyner 778758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 7796f37f232SEric Joyner error = ixgbe_setup_low_power_mode(adapter); 780758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 7816f37f232SEric Joyner 7826f37f232SEric Joyner return (error); 7836f37f232SEric Joyner } 7846f37f232SEric Joyner 7856f37f232SEric Joyner /** 7866f37f232SEric Joyner * Methods for going from: 7876f37f232SEric Joyner * D0 -> D3: ixgbe_suspend 7886f37f232SEric Joyner * D3 -> D0: ixgbe_resume 7896f37f232SEric Joyner */ 7906f37f232SEric Joyner static int 7916f37f232SEric Joyner ixgbe_suspend(device_t dev) 7926f37f232SEric Joyner { 7936f37f232SEric Joyner struct adapter *adapter = device_get_softc(dev); 7946f37f232SEric Joyner int error = 0; 7956f37f232SEric Joyner 7966f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_suspend: begin"); 7976f37f232SEric Joyner 7986f37f232SEric Joyner IXGBE_CORE_LOCK(adapter); 7996f37f232SEric Joyner 8006f37f232SEric Joyner error = ixgbe_setup_low_power_mode(adapter); 8016f37f232SEric Joyner 8026f37f232SEric Joyner IXGBE_CORE_UNLOCK(adapter); 8036f37f232SEric Joyner 8046f37f232SEric Joyner return (error); 8056f37f232SEric Joyner } 8066f37f232SEric Joyner 8076f37f232SEric Joyner static int 8086f37f232SEric Joyner ixgbe_resume(device_t dev) 8096f37f232SEric Joyner { 8106f37f232SEric Joyner struct adapter *adapter = device_get_softc(dev); 8116f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 8126f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 8136f37f232SEric Joyner u32 wus; 8146f37f232SEric Joyner 8156f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_resume: begin"); 8166f37f232SEric Joyner 8176f37f232SEric Joyner IXGBE_CORE_LOCK(adapter); 8186f37f232SEric Joyner 8196f37f232SEric Joyner /* Read & clear WUS register */ 8206f37f232SEric Joyner wus = IXGBE_READ_REG(hw, IXGBE_WUS); 8216f37f232SEric Joyner if (wus) 8226f37f232SEric Joyner device_printf(dev, "Woken up by (WUS): %#010x\n", 8236f37f232SEric Joyner IXGBE_READ_REG(hw, IXGBE_WUS)); 8246f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); 8256f37f232SEric Joyner /* And clear WUFC until next low-power transition */ 8266f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0); 8276f37f232SEric Joyner 8286f37f232SEric Joyner /* 8296f37f232SEric Joyner * Required after D3->D0 transition; 8306f37f232SEric Joyner * will re-advertise all previous advertised speeds 8316f37f232SEric Joyner */ 8326f37f232SEric Joyner if (ifp->if_flags & IFF_UP) 8336f37f232SEric Joyner ixgbe_init_locked(adapter); 8346f37f232SEric Joyner 8356f37f232SEric Joyner IXGBE_CORE_UNLOCK(adapter); 8366f37f232SEric Joyner 837758cc3dcSJack F Vogel return (0); 838758cc3dcSJack F Vogel } 839758cc3dcSJack F Vogel 840758cc3dcSJack F Vogel 841758cc3dcSJack F Vogel /********************************************************************* 842758cc3dcSJack F Vogel * Ioctl entry point 843758cc3dcSJack F Vogel * 844758cc3dcSJack F Vogel * ixgbe_ioctl is called when the user wants to configure the 845758cc3dcSJack F Vogel * interface. 846758cc3dcSJack F Vogel * 847758cc3dcSJack F Vogel * return 0 on success, positive on failure 848758cc3dcSJack F Vogel **********************************************************************/ 849758cc3dcSJack F Vogel 850758cc3dcSJack F Vogel static int 851758cc3dcSJack F Vogel ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 852758cc3dcSJack F Vogel { 853758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 854758cc3dcSJack F Vogel struct ifreq *ifr = (struct ifreq *) data; 855758cc3dcSJack F Vogel #if defined(INET) || defined(INET6) 856758cc3dcSJack F Vogel struct ifaddr *ifa = (struct ifaddr *)data; 857758cc3dcSJack F Vogel #endif 858758cc3dcSJack F Vogel int error = 0; 859e5cb6169SSean Bruno bool avoid_reset = FALSE; 860758cc3dcSJack F Vogel 861758cc3dcSJack F Vogel switch (command) { 862758cc3dcSJack F Vogel 863758cc3dcSJack F Vogel case SIOCSIFADDR: 864758cc3dcSJack F Vogel #ifdef INET 865758cc3dcSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET) 866758cc3dcSJack F Vogel avoid_reset = TRUE; 867758cc3dcSJack F Vogel #endif 868758cc3dcSJack F Vogel #ifdef INET6 869758cc3dcSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET6) 870758cc3dcSJack F Vogel avoid_reset = TRUE; 871758cc3dcSJack F Vogel #endif 872758cc3dcSJack F Vogel /* 873758cc3dcSJack F Vogel ** Calling init results in link renegotiation, 874758cc3dcSJack F Vogel ** so we avoid doing it when possible. 875758cc3dcSJack F Vogel */ 876758cc3dcSJack F Vogel if (avoid_reset) { 877758cc3dcSJack F Vogel ifp->if_flags |= IFF_UP; 878758cc3dcSJack F Vogel if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 879758cc3dcSJack F Vogel ixgbe_init(adapter); 880a9ca1c79SSean Bruno #ifdef INET 881758cc3dcSJack F Vogel if (!(ifp->if_flags & IFF_NOARP)) 882758cc3dcSJack F Vogel arp_ifinit(ifp, ifa); 883e5cb6169SSean Bruno #endif 884758cc3dcSJack F Vogel } else 885758cc3dcSJack F Vogel error = ether_ioctl(ifp, command, data); 886758cc3dcSJack F Vogel break; 887758cc3dcSJack F Vogel case SIOCSIFMTU: 888758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 8896f37f232SEric Joyner if (ifr->ifr_mtu > IXGBE_MAX_MTU) { 890758cc3dcSJack F Vogel error = EINVAL; 891758cc3dcSJack F Vogel } else { 892758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 893758cc3dcSJack F Vogel ifp->if_mtu = ifr->ifr_mtu; 894758cc3dcSJack F Vogel adapter->max_frame_size = 8956f37f232SEric Joyner ifp->if_mtu + IXGBE_MTU_HDR; 896758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 89748056c88SJack F Vogel #ifdef PCI_IOV 89848056c88SJack F Vogel ixgbe_recalculate_max_frame(adapter); 89948056c88SJack F Vogel #endif 900758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 901758cc3dcSJack F Vogel } 902758cc3dcSJack F Vogel break; 903758cc3dcSJack F Vogel case SIOCSIFFLAGS: 904758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 905758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 906758cc3dcSJack F Vogel if (ifp->if_flags & IFF_UP) { 907758cc3dcSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 908758cc3dcSJack F Vogel if ((ifp->if_flags ^ adapter->if_flags) & 909758cc3dcSJack F Vogel (IFF_PROMISC | IFF_ALLMULTI)) { 910758cc3dcSJack F Vogel ixgbe_set_promisc(adapter); 911758cc3dcSJack F Vogel } 912758cc3dcSJack F Vogel } else 913758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 914758cc3dcSJack F Vogel } else 915758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) 916758cc3dcSJack F Vogel ixgbe_stop(adapter); 917758cc3dcSJack F Vogel adapter->if_flags = ifp->if_flags; 918758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 919758cc3dcSJack F Vogel break; 920758cc3dcSJack F Vogel case SIOCADDMULTI: 921758cc3dcSJack F Vogel case SIOCDELMULTI: 922758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); 923758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 924758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 925758cc3dcSJack F Vogel ixgbe_disable_intr(adapter); 926758cc3dcSJack F Vogel ixgbe_set_multi(adapter); 927758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 928758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 929758cc3dcSJack F Vogel } 930758cc3dcSJack F Vogel break; 931758cc3dcSJack F Vogel case SIOCSIFMEDIA: 932758cc3dcSJack F Vogel case SIOCGIFMEDIA: 933758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 934758cc3dcSJack F Vogel error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); 935758cc3dcSJack F Vogel break; 936758cc3dcSJack F Vogel case SIOCSIFCAP: 937758cc3dcSJack F Vogel { 938758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 939a9ca1c79SSean Bruno 940a9ca1c79SSean Bruno int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 941a9ca1c79SSean Bruno if (!mask) 942a9ca1c79SSean Bruno break; 943a9ca1c79SSean Bruno 944a9ca1c79SSean Bruno /* HW cannot turn these on/off separately */ 945a9ca1c79SSean Bruno if (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) { 946a9ca1c79SSean Bruno ifp->if_capenable ^= IFCAP_RXCSUM; 947a9ca1c79SSean Bruno ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 948a9ca1c79SSean Bruno } 949a9ca1c79SSean Bruno if (mask & IFCAP_TXCSUM) 950a9ca1c79SSean Bruno ifp->if_capenable ^= IFCAP_TXCSUM; 951a9ca1c79SSean Bruno if (mask & IFCAP_TXCSUM_IPV6) 952a9ca1c79SSean Bruno ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 953758cc3dcSJack F Vogel if (mask & IFCAP_TSO4) 954758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_TSO4; 955758cc3dcSJack F Vogel if (mask & IFCAP_TSO6) 956758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_TSO6; 957758cc3dcSJack F Vogel if (mask & IFCAP_LRO) 958758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_LRO; 959758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWTAGGING) 960758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 961758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWFILTER) 962758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 963758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWTSO) 964758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 965a9ca1c79SSean Bruno 966758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 967758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 968758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 969758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 970758cc3dcSJack F Vogel } 971758cc3dcSJack F Vogel VLAN_CAPABILITIES(ifp); 972758cc3dcSJack F Vogel break; 973758cc3dcSJack F Vogel } 974758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 975758cc3dcSJack F Vogel case SIOCGI2C: 976758cc3dcSJack F Vogel { 977758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 978758cc3dcSJack F Vogel struct ifi2creq i2c; 979758cc3dcSJack F Vogel int i; 980758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)"); 981758cc3dcSJack F Vogel error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); 982758cc3dcSJack F Vogel if (error != 0) 983758cc3dcSJack F Vogel break; 984758cc3dcSJack F Vogel if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { 985758cc3dcSJack F Vogel error = EINVAL; 986758cc3dcSJack F Vogel break; 987758cc3dcSJack F Vogel } 988758cc3dcSJack F Vogel if (i2c.len > sizeof(i2c.data)) { 989758cc3dcSJack F Vogel error = EINVAL; 990758cc3dcSJack F Vogel break; 991758cc3dcSJack F Vogel } 992758cc3dcSJack F Vogel 993758cc3dcSJack F Vogel for (i = 0; i < i2c.len; i++) 994758cc3dcSJack F Vogel hw->phy.ops.read_i2c_byte(hw, i2c.offset + i, 995758cc3dcSJack F Vogel i2c.dev_addr, &i2c.data[i]); 996758cc3dcSJack F Vogel error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); 997758cc3dcSJack F Vogel break; 998758cc3dcSJack F Vogel } 999758cc3dcSJack F Vogel #endif 1000758cc3dcSJack F Vogel default: 1001758cc3dcSJack F Vogel IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); 1002758cc3dcSJack F Vogel error = ether_ioctl(ifp, command, data); 1003758cc3dcSJack F Vogel break; 1004758cc3dcSJack F Vogel } 1005758cc3dcSJack F Vogel 1006758cc3dcSJack F Vogel return (error); 1007758cc3dcSJack F Vogel } 1008758cc3dcSJack F Vogel 1009a9ca1c79SSean Bruno /* 1010a9ca1c79SSean Bruno * Set the various hardware offload abilities. 1011a9ca1c79SSean Bruno * 1012a9ca1c79SSean Bruno * This takes the ifnet's if_capenable flags (e.g. set by the user using 1013a9ca1c79SSean Bruno * ifconfig) and indicates to the OS via the ifnet's if_hwassist field what 1014a9ca1c79SSean Bruno * mbuf offload flags the driver will understand. 1015a9ca1c79SSean Bruno */ 1016a9ca1c79SSean Bruno static void 1017a9ca1c79SSean Bruno ixgbe_set_if_hwassist(struct adapter *adapter) 1018a9ca1c79SSean Bruno { 1019a9ca1c79SSean Bruno struct ifnet *ifp = adapter->ifp; 10202602455cSMichael Tuexen struct ixgbe_hw *hw = &adapter->hw; 1021a9ca1c79SSean Bruno 1022a9ca1c79SSean Bruno ifp->if_hwassist = 0; 1023a9ca1c79SSean Bruno #if __FreeBSD_version >= 1000000 1024a9ca1c79SSean Bruno if (ifp->if_capenable & IFCAP_TSO4) 1025a9ca1c79SSean Bruno ifp->if_hwassist |= CSUM_IP_TSO; 1026a9ca1c79SSean Bruno if (ifp->if_capenable & IFCAP_TSO6) 1027a9ca1c79SSean Bruno ifp->if_hwassist |= CSUM_IP6_TSO; 10282602455cSMichael Tuexen if (ifp->if_capenable & IFCAP_TXCSUM) { 10292602455cSMichael Tuexen ifp->if_hwassist |= (CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP); 10302602455cSMichael Tuexen if (hw->mac.type != ixgbe_mac_82598EB) 10312602455cSMichael Tuexen ifp->if_hwassist |= CSUM_IP_SCTP; 10322602455cSMichael Tuexen } 10332602455cSMichael Tuexen if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) { 10342602455cSMichael Tuexen ifp->if_hwassist |= (CSUM_IP6_UDP | CSUM_IP6_TCP); 10352602455cSMichael Tuexen if (hw->mac.type != ixgbe_mac_82598EB) 10362602455cSMichael Tuexen ifp->if_hwassist |= CSUM_IP6_SCTP; 10372602455cSMichael Tuexen } 1038a9ca1c79SSean Bruno #else 1039a9ca1c79SSean Bruno if (ifp->if_capenable & IFCAP_TSO) 1040a9ca1c79SSean Bruno ifp->if_hwassist |= CSUM_TSO; 1041a9ca1c79SSean Bruno if (ifp->if_capenable & IFCAP_TXCSUM) { 1042a9ca1c79SSean Bruno ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 1043a9ca1c79SSean Bruno if (hw->mac.type != ixgbe_mac_82598EB) 1044a9ca1c79SSean Bruno ifp->if_hwassist |= CSUM_SCTP; 1045a9ca1c79SSean Bruno } 1046a9ca1c79SSean Bruno #endif 1047a9ca1c79SSean Bruno } 1048a9ca1c79SSean Bruno 1049758cc3dcSJack F Vogel /********************************************************************* 1050758cc3dcSJack F Vogel * Init entry point 1051758cc3dcSJack F Vogel * 1052758cc3dcSJack F Vogel * This routine is used in two ways. It is used by the stack as 1053758cc3dcSJack F Vogel * init entry point in network interface structure. It is also used 1054758cc3dcSJack F Vogel * by the driver as a hw/sw initialization routine to get to a 1055758cc3dcSJack F Vogel * consistent state. 1056758cc3dcSJack F Vogel * 1057758cc3dcSJack F Vogel * return 0 on success, positive on failure 1058758cc3dcSJack F Vogel **********************************************************************/ 1059758cc3dcSJack F Vogel #define IXGBE_MHADD_MFS_SHIFT 16 1060758cc3dcSJack F Vogel 1061758cc3dcSJack F Vogel static void 1062758cc3dcSJack F Vogel ixgbe_init_locked(struct adapter *adapter) 1063758cc3dcSJack F Vogel { 1064758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1065758cc3dcSJack F Vogel device_t dev = adapter->dev; 1066758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 106748056c88SJack F Vogel struct tx_ring *txr; 106848056c88SJack F Vogel struct rx_ring *rxr; 106948056c88SJack F Vogel u32 txdctl, mhadd; 1070758cc3dcSJack F Vogel u32 rxdctl, rxctrl; 1071a9ca1c79SSean Bruno int err = 0; 107248056c88SJack F Vogel #ifdef PCI_IOV 107348056c88SJack F Vogel enum ixgbe_iov_mode mode; 107448056c88SJack F Vogel #endif 1075758cc3dcSJack F Vogel 1076758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 1077758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_init_locked: begin"); 107848056c88SJack F Vogel 1079758cc3dcSJack F Vogel hw->adapter_stopped = FALSE; 1080758cc3dcSJack F Vogel ixgbe_stop_adapter(hw); 1081758cc3dcSJack F Vogel callout_stop(&adapter->timer); 1082758cc3dcSJack F Vogel 108348056c88SJack F Vogel #ifdef PCI_IOV 108448056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 108548056c88SJack F Vogel adapter->pool = ixgbe_max_vfs(mode); 108648056c88SJack F Vogel /* Queue indices may change with IOV mode */ 108748056c88SJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 108848056c88SJack F Vogel adapter->rx_rings[i].me = ixgbe_pf_que_index(mode, i); 108948056c88SJack F Vogel adapter->tx_rings[i].me = ixgbe_pf_que_index(mode, i); 109048056c88SJack F Vogel } 109148056c88SJack F Vogel #endif 1092758cc3dcSJack F Vogel /* reprogram the RAR[0] in case user changed it. */ 109348056c88SJack F Vogel ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, IXGBE_RAH_AV); 1094758cc3dcSJack F Vogel 1095758cc3dcSJack F Vogel /* Get the latest mac address, User can use a LAA */ 109648056c88SJack F Vogel bcopy(IF_LLADDR(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS); 109748056c88SJack F Vogel ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, 1); 1098758cc3dcSJack F Vogel hw->addr_ctrl.rar_used_count = 1; 1099758cc3dcSJack F Vogel 1100a9ca1c79SSean Bruno /* Set hardware offload abilities from ifnet flags */ 1101a9ca1c79SSean Bruno ixgbe_set_if_hwassist(adapter); 1102758cc3dcSJack F Vogel 1103758cc3dcSJack F Vogel /* Prepare transmit descriptors and buffers */ 1104758cc3dcSJack F Vogel if (ixgbe_setup_transmit_structures(adapter)) { 1105758cc3dcSJack F Vogel device_printf(dev, "Could not setup transmit structures\n"); 1106758cc3dcSJack F Vogel ixgbe_stop(adapter); 1107758cc3dcSJack F Vogel return; 1108758cc3dcSJack F Vogel } 1109758cc3dcSJack F Vogel 1110758cc3dcSJack F Vogel ixgbe_init_hw(hw); 111148056c88SJack F Vogel #ifdef PCI_IOV 111248056c88SJack F Vogel ixgbe_initialize_iov(adapter); 111348056c88SJack F Vogel #endif 1114758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(adapter); 1115758cc3dcSJack F Vogel 1116758cc3dcSJack F Vogel /* Setup Multicast table */ 1117758cc3dcSJack F Vogel ixgbe_set_multi(adapter); 1118758cc3dcSJack F Vogel 1119a9ca1c79SSean Bruno /* Determine the correct mbuf pool, based on frame size */ 112048056c88SJack F Vogel if (adapter->max_frame_size <= MCLBYTES) 1121758cc3dcSJack F Vogel adapter->rx_mbuf_sz = MCLBYTES; 112230126537SJack F Vogel else 112348056c88SJack F Vogel adapter->rx_mbuf_sz = MJUMPAGESIZE; 1124758cc3dcSJack F Vogel 1125758cc3dcSJack F Vogel /* Prepare receive descriptors and buffers */ 1126758cc3dcSJack F Vogel if (ixgbe_setup_receive_structures(adapter)) { 1127758cc3dcSJack F Vogel device_printf(dev, "Could not setup receive structures\n"); 1128758cc3dcSJack F Vogel ixgbe_stop(adapter); 1129758cc3dcSJack F Vogel return; 1130758cc3dcSJack F Vogel } 1131758cc3dcSJack F Vogel 1132758cc3dcSJack F Vogel /* Configure RX settings */ 1133758cc3dcSJack F Vogel ixgbe_initialize_receive_units(adapter); 1134758cc3dcSJack F Vogel 113548056c88SJack F Vogel /* Enable SDP & MSIX interrupts based on adapter */ 113648056c88SJack F Vogel ixgbe_config_gpie(adapter); 1137758cc3dcSJack F Vogel 1138758cc3dcSJack F Vogel /* Set MTU size */ 1139758cc3dcSJack F Vogel if (ifp->if_mtu > ETHERMTU) { 11406f37f232SEric Joyner /* aka IXGBE_MAXFRS on 82599 and newer */ 1141758cc3dcSJack F Vogel mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); 1142758cc3dcSJack F Vogel mhadd &= ~IXGBE_MHADD_MFS_MASK; 1143758cc3dcSJack F Vogel mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; 1144758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); 1145758cc3dcSJack F Vogel } 1146758cc3dcSJack F Vogel 1147758cc3dcSJack F Vogel /* Now enable all the queues */ 1148758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 114948056c88SJack F Vogel txr = &adapter->tx_rings[i]; 115048056c88SJack F Vogel txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txr->me)); 1151758cc3dcSJack F Vogel txdctl |= IXGBE_TXDCTL_ENABLE; 1152758cc3dcSJack F Vogel /* Set WTHRESH to 8, burst writeback */ 1153758cc3dcSJack F Vogel txdctl |= (8 << 16); 1154758cc3dcSJack F Vogel /* 1155758cc3dcSJack F Vogel * When the internal queue falls below PTHRESH (32), 1156758cc3dcSJack F Vogel * start prefetching as long as there are at least 1157758cc3dcSJack F Vogel * HTHRESH (1) buffers ready. The values are taken 1158758cc3dcSJack F Vogel * from the Intel linux driver 3.8.21. 1159758cc3dcSJack F Vogel * Prefetching enables tx line rate even with 1 queue. 1160758cc3dcSJack F Vogel */ 1161758cc3dcSJack F Vogel txdctl |= (32 << 0) | (1 << 8); 116248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txr->me), txdctl); 1163758cc3dcSJack F Vogel } 1164758cc3dcSJack F Vogel 116548056c88SJack F Vogel for (int i = 0, j = 0; i < adapter->num_queues; i++) { 116648056c88SJack F Vogel rxr = &adapter->rx_rings[i]; 116748056c88SJack F Vogel rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); 1168758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1169758cc3dcSJack F Vogel /* 1170758cc3dcSJack F Vogel ** PTHRESH = 21 1171758cc3dcSJack F Vogel ** HTHRESH = 4 1172758cc3dcSJack F Vogel ** WTHRESH = 8 1173758cc3dcSJack F Vogel */ 1174758cc3dcSJack F Vogel rxdctl &= ~0x3FFFFF; 1175758cc3dcSJack F Vogel rxdctl |= 0x080420; 1176758cc3dcSJack F Vogel } 1177758cc3dcSJack F Vogel rxdctl |= IXGBE_RXDCTL_ENABLE; 117848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), rxdctl); 117948056c88SJack F Vogel for (; j < 10; j++) { 118048056c88SJack F Vogel if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)) & 1181758cc3dcSJack F Vogel IXGBE_RXDCTL_ENABLE) 1182758cc3dcSJack F Vogel break; 1183758cc3dcSJack F Vogel else 1184758cc3dcSJack F Vogel msec_delay(1); 1185758cc3dcSJack F Vogel } 1186758cc3dcSJack F Vogel wmb(); 1187758cc3dcSJack F Vogel #ifdef DEV_NETMAP 1188758cc3dcSJack F Vogel /* 1189758cc3dcSJack F Vogel * In netmap mode, we must preserve the buffers made 1190758cc3dcSJack F Vogel * available to userspace before the if_init() 1191758cc3dcSJack F Vogel * (this is true by default on the TX side, because 1192758cc3dcSJack F Vogel * init makes all buffers available to userspace). 1193758cc3dcSJack F Vogel * 1194758cc3dcSJack F Vogel * netmap_reset() and the device specific routines 1195758cc3dcSJack F Vogel * (e.g. ixgbe_setup_receive_rings()) map these 1196758cc3dcSJack F Vogel * buffers at the end of the NIC ring, so here we 1197758cc3dcSJack F Vogel * must set the RDT (tail) register to make sure 1198758cc3dcSJack F Vogel * they are not overwritten. 1199758cc3dcSJack F Vogel * 1200758cc3dcSJack F Vogel * In this driver the NIC ring starts at RDH = 0, 1201758cc3dcSJack F Vogel * RDT points to the last slot available for reception (?), 1202758cc3dcSJack F Vogel * so RDT = num_rx_desc - 1 means the whole ring is available. 1203758cc3dcSJack F Vogel */ 1204758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_NETMAP) { 1205758cc3dcSJack F Vogel struct netmap_adapter *na = NA(adapter->ifp); 1206758cc3dcSJack F Vogel struct netmap_kring *kring = &na->rx_rings[i]; 1207758cc3dcSJack F Vogel int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); 1208758cc3dcSJack F Vogel 120948056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), t); 1210758cc3dcSJack F Vogel } else 1211758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 121248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), adapter->num_rx_desc - 1); 1213758cc3dcSJack F Vogel } 1214758cc3dcSJack F Vogel 1215758cc3dcSJack F Vogel /* Enable Receive engine */ 1216758cc3dcSJack F Vogel rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); 1217758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 1218758cc3dcSJack F Vogel rxctrl |= IXGBE_RXCTRL_DMBYPS; 1219758cc3dcSJack F Vogel rxctrl |= IXGBE_RXCTRL_RXEN; 1220758cc3dcSJack F Vogel ixgbe_enable_rx_dma(hw, rxctrl); 1221758cc3dcSJack F Vogel 1222758cc3dcSJack F Vogel callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); 1223758cc3dcSJack F Vogel 1224758cc3dcSJack F Vogel /* Set up MSI/X routing */ 1225758cc3dcSJack F Vogel if (ixgbe_enable_msix) { 1226758cc3dcSJack F Vogel ixgbe_configure_ivars(adapter); 1227758cc3dcSJack F Vogel /* Set up auto-mask */ 1228758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 1229758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); 1230758cc3dcSJack F Vogel else { 1231758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); 1232758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); 1233758cc3dcSJack F Vogel } 1234758cc3dcSJack F Vogel } else { /* Simple settings for Legacy/MSI */ 1235758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 0, 0, 0); 1236758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 0, 0, 1); 1237758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); 1238758cc3dcSJack F Vogel } 1239758cc3dcSJack F Vogel 1240758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 1241758cc3dcSJack F Vogel /* Init Flow director */ 1242758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 1243758cc3dcSJack F Vogel u32 hdrm = 32 << fdir_pballoc; 1244758cc3dcSJack F Vogel 1245758cc3dcSJack F Vogel hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL); 1246758cc3dcSJack F Vogel ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); 1247758cc3dcSJack F Vogel } 1248758cc3dcSJack F Vogel #endif 1249758cc3dcSJack F Vogel 1250758cc3dcSJack F Vogel /* 125148056c88SJack F Vogel * Check on any SFP devices that 125248056c88SJack F Vogel * need to be kick-started 1253758cc3dcSJack F Vogel */ 1254758cc3dcSJack F Vogel if (hw->phy.type == ixgbe_phy_none) { 1255a9ca1c79SSean Bruno err = hw->phy.ops.identify(hw); 1256758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 1257758cc3dcSJack F Vogel device_printf(dev, 1258758cc3dcSJack F Vogel "Unsupported SFP+ module type was detected.\n"); 1259758cc3dcSJack F Vogel return; 1260758cc3dcSJack F Vogel } 1261758cc3dcSJack F Vogel } 1262758cc3dcSJack F Vogel 1263758cc3dcSJack F Vogel /* Set moderation on the Link interrupt */ 1264758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR); 1265758cc3dcSJack F Vogel 12666f37f232SEric Joyner /* Configure Energy Efficient Ethernet for supported devices */ 1267a9ca1c79SSean Bruno if (hw->mac.ops.setup_eee) { 1268a9ca1c79SSean Bruno err = hw->mac.ops.setup_eee(hw, adapter->eee_enabled); 1269a9ca1c79SSean Bruno if (err) 1270a9ca1c79SSean Bruno device_printf(dev, "Error setting up EEE: %d\n", err); 1271a9ca1c79SSean Bruno } 12726f37f232SEric Joyner 12731ebf555bSSteven Hartland /* Enable power to the phy. */ 12741ebf555bSSteven Hartland ixgbe_set_phy_power(hw, TRUE); 12751ebf555bSSteven Hartland 1276758cc3dcSJack F Vogel /* Config/Enable Link */ 1277758cc3dcSJack F Vogel ixgbe_config_link(adapter); 1278758cc3dcSJack F Vogel 1279758cc3dcSJack F Vogel /* Hardware Packet Buffer & Flow Control setup */ 12806f37f232SEric Joyner ixgbe_config_delay_values(adapter); 1281758cc3dcSJack F Vogel 1282758cc3dcSJack F Vogel /* Initialize the FC settings */ 1283758cc3dcSJack F Vogel ixgbe_start_hw(hw); 1284758cc3dcSJack F Vogel 1285758cc3dcSJack F Vogel /* Set up VLAN support and filter */ 1286758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 1287758cc3dcSJack F Vogel 12886f37f232SEric Joyner /* Setup DMA Coalescing */ 12896f37f232SEric Joyner ixgbe_config_dmac(adapter); 12906f37f232SEric Joyner 1291758cc3dcSJack F Vogel /* And now turn on interrupts */ 1292758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1293758cc3dcSJack F Vogel 129448056c88SJack F Vogel #ifdef PCI_IOV 129548056c88SJack F Vogel /* Enable the use of the MBX by the VF's */ 129648056c88SJack F Vogel { 129748056c88SJack F Vogel u32 reg = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 129848056c88SJack F Vogel reg |= IXGBE_CTRL_EXT_PFRSTD; 129948056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, reg); 130048056c88SJack F Vogel } 130148056c88SJack F Vogel #endif 130248056c88SJack F Vogel 1303758cc3dcSJack F Vogel /* Now inform the stack we're ready */ 1304758cc3dcSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 1305758cc3dcSJack F Vogel 1306758cc3dcSJack F Vogel return; 1307758cc3dcSJack F Vogel } 1308758cc3dcSJack F Vogel 1309758cc3dcSJack F Vogel static void 1310758cc3dcSJack F Vogel ixgbe_init(void *arg) 1311758cc3dcSJack F Vogel { 1312758cc3dcSJack F Vogel struct adapter *adapter = arg; 1313758cc3dcSJack F Vogel 1314758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 1315758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 1316758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1317758cc3dcSJack F Vogel return; 1318758cc3dcSJack F Vogel } 1319758cc3dcSJack F Vogel 13206f37f232SEric Joyner static void 132148056c88SJack F Vogel ixgbe_config_gpie(struct adapter *adapter) 132248056c88SJack F Vogel { 132348056c88SJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 132448056c88SJack F Vogel u32 gpie; 132548056c88SJack F Vogel 132648056c88SJack F Vogel gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); 132748056c88SJack F Vogel 132848056c88SJack F Vogel /* Fan Failure Interrupt */ 132948056c88SJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) 133048056c88SJack F Vogel gpie |= IXGBE_SDP1_GPIEN; 133148056c88SJack F Vogel 133248056c88SJack F Vogel /* 133348056c88SJack F Vogel * Module detection (SDP2) 133448056c88SJack F Vogel * Media ready (SDP1) 133548056c88SJack F Vogel */ 133648056c88SJack F Vogel if (hw->mac.type == ixgbe_mac_82599EB) { 133748056c88SJack F Vogel gpie |= IXGBE_SDP2_GPIEN; 133848056c88SJack F Vogel if (hw->device_id != IXGBE_DEV_ID_82599_QSFP_SF_QP) 133948056c88SJack F Vogel gpie |= IXGBE_SDP1_GPIEN; 134048056c88SJack F Vogel } 134148056c88SJack F Vogel 134248056c88SJack F Vogel /* 134348056c88SJack F Vogel * Thermal Failure Detection (X540) 1344a9ca1c79SSean Bruno * Link Detection (X552 SFP+, X552/X557-AT) 134548056c88SJack F Vogel */ 134648056c88SJack F Vogel if (hw->mac.type == ixgbe_mac_X540 || 134748056c88SJack F Vogel hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || 134848056c88SJack F Vogel hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) 134948056c88SJack F Vogel gpie |= IXGBE_SDP0_GPIEN_X540; 135048056c88SJack F Vogel 135148056c88SJack F Vogel if (adapter->msix > 1) { 135248056c88SJack F Vogel /* Enable Enhanced MSIX mode */ 135348056c88SJack F Vogel gpie |= IXGBE_GPIE_MSIX_MODE; 135448056c88SJack F Vogel gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | 135548056c88SJack F Vogel IXGBE_GPIE_OCD; 135648056c88SJack F Vogel } 135748056c88SJack F Vogel 135848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 135948056c88SJack F Vogel return; 136048056c88SJack F Vogel } 136148056c88SJack F Vogel 136248056c88SJack F Vogel /* 136348056c88SJack F Vogel * Requires adapter->max_frame_size to be set. 136448056c88SJack F Vogel */ 136548056c88SJack F Vogel static void 13666f37f232SEric Joyner ixgbe_config_delay_values(struct adapter *adapter) 13676f37f232SEric Joyner { 13686f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 13696f37f232SEric Joyner u32 rxpb, frame, size, tmp; 13706f37f232SEric Joyner 13716f37f232SEric Joyner frame = adapter->max_frame_size; 13726f37f232SEric Joyner 13736f37f232SEric Joyner /* Calculate High Water */ 13746f37f232SEric Joyner switch (hw->mac.type) { 13756f37f232SEric Joyner case ixgbe_mac_X540: 13766f37f232SEric Joyner case ixgbe_mac_X550: 13776f37f232SEric Joyner case ixgbe_mac_X550EM_x: 13786f37f232SEric Joyner tmp = IXGBE_DV_X540(frame, frame); 13796f37f232SEric Joyner break; 13806f37f232SEric Joyner default: 13816f37f232SEric Joyner tmp = IXGBE_DV(frame, frame); 13826f37f232SEric Joyner break; 13836f37f232SEric Joyner } 13846f37f232SEric Joyner size = IXGBE_BT2KB(tmp); 13856f37f232SEric Joyner rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10; 13866f37f232SEric Joyner hw->fc.high_water[0] = rxpb - size; 13876f37f232SEric Joyner 13886f37f232SEric Joyner /* Now calculate Low Water */ 13896f37f232SEric Joyner switch (hw->mac.type) { 13906f37f232SEric Joyner case ixgbe_mac_X540: 13916f37f232SEric Joyner case ixgbe_mac_X550: 13926f37f232SEric Joyner case ixgbe_mac_X550EM_x: 13936f37f232SEric Joyner tmp = IXGBE_LOW_DV_X540(frame); 13946f37f232SEric Joyner break; 13956f37f232SEric Joyner default: 13966f37f232SEric Joyner tmp = IXGBE_LOW_DV(frame); 13976f37f232SEric Joyner break; 13986f37f232SEric Joyner } 13996f37f232SEric Joyner hw->fc.low_water[0] = IXGBE_BT2KB(tmp); 14006f37f232SEric Joyner 14016f37f232SEric Joyner hw->fc.requested_mode = adapter->fc; 14026f37f232SEric Joyner hw->fc.pause_time = IXGBE_FC_PAUSE; 14036f37f232SEric Joyner hw->fc.send_xon = TRUE; 14046f37f232SEric Joyner } 1405758cc3dcSJack F Vogel 1406758cc3dcSJack F Vogel /* 1407758cc3dcSJack F Vogel ** 1408758cc3dcSJack F Vogel ** MSIX Interrupt Handlers and Tasklets 1409758cc3dcSJack F Vogel ** 1410758cc3dcSJack F Vogel */ 1411758cc3dcSJack F Vogel 1412758cc3dcSJack F Vogel static inline void 1413758cc3dcSJack F Vogel ixgbe_enable_queue(struct adapter *adapter, u32 vector) 1414758cc3dcSJack F Vogel { 1415758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1416758cc3dcSJack F Vogel u64 queue = (u64)(1 << vector); 1417758cc3dcSJack F Vogel u32 mask; 1418758cc3dcSJack F Vogel 1419758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1420758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queue); 1421758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); 1422758cc3dcSJack F Vogel } else { 1423758cc3dcSJack F Vogel mask = (queue & 0xFFFFFFFF); 1424758cc3dcSJack F Vogel if (mask) 1425758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask); 1426758cc3dcSJack F Vogel mask = (queue >> 32); 1427758cc3dcSJack F Vogel if (mask) 1428758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask); 1429758cc3dcSJack F Vogel } 1430758cc3dcSJack F Vogel } 1431758cc3dcSJack F Vogel 1432758cc3dcSJack F Vogel static inline void 1433758cc3dcSJack F Vogel ixgbe_disable_queue(struct adapter *adapter, u32 vector) 1434758cc3dcSJack F Vogel { 1435758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1436758cc3dcSJack F Vogel u64 queue = (u64)(1 << vector); 1437758cc3dcSJack F Vogel u32 mask; 1438758cc3dcSJack F Vogel 1439758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1440758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queue); 1441758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask); 1442758cc3dcSJack F Vogel } else { 1443758cc3dcSJack F Vogel mask = (queue & 0xFFFFFFFF); 1444758cc3dcSJack F Vogel if (mask) 1445758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask); 1446758cc3dcSJack F Vogel mask = (queue >> 32); 1447758cc3dcSJack F Vogel if (mask) 1448758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask); 1449758cc3dcSJack F Vogel } 1450758cc3dcSJack F Vogel } 1451758cc3dcSJack F Vogel 1452758cc3dcSJack F Vogel static void 1453758cc3dcSJack F Vogel ixgbe_handle_que(void *context, int pending) 1454758cc3dcSJack F Vogel { 1455758cc3dcSJack F Vogel struct ix_queue *que = context; 1456758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1457758cc3dcSJack F Vogel struct tx_ring *txr = que->txr; 1458758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1459758cc3dcSJack F Vogel 1460758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 146148056c88SJack F Vogel ixgbe_rxeof(que); 1462758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1463758cc3dcSJack F Vogel ixgbe_txeof(txr); 1464758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 1465758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1466758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1467758cc3dcSJack F Vogel #else 1468758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1469758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1470758cc3dcSJack F Vogel #endif 1471758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1472758cc3dcSJack F Vogel } 1473758cc3dcSJack F Vogel 1474758cc3dcSJack F Vogel /* Reenable this interrupt */ 1475758cc3dcSJack F Vogel if (que->res != NULL) 1476758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 1477758cc3dcSJack F Vogel else 1478758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1479758cc3dcSJack F Vogel return; 1480758cc3dcSJack F Vogel } 1481758cc3dcSJack F Vogel 1482758cc3dcSJack F Vogel 1483758cc3dcSJack F Vogel /********************************************************************* 1484758cc3dcSJack F Vogel * 1485758cc3dcSJack F Vogel * Legacy Interrupt Service routine 1486758cc3dcSJack F Vogel * 1487758cc3dcSJack F Vogel **********************************************************************/ 1488758cc3dcSJack F Vogel 1489758cc3dcSJack F Vogel static void 1490758cc3dcSJack F Vogel ixgbe_legacy_irq(void *arg) 1491758cc3dcSJack F Vogel { 1492758cc3dcSJack F Vogel struct ix_queue *que = arg; 1493758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1494758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1495758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1496758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 1497758cc3dcSJack F Vogel bool more; 1498758cc3dcSJack F Vogel u32 reg_eicr; 1499758cc3dcSJack F Vogel 1500758cc3dcSJack F Vogel 1501758cc3dcSJack F Vogel reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 1502758cc3dcSJack F Vogel 1503758cc3dcSJack F Vogel ++que->irqs; 1504758cc3dcSJack F Vogel if (reg_eicr == 0) { 1505758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1506758cc3dcSJack F Vogel return; 1507758cc3dcSJack F Vogel } 1508758cc3dcSJack F Vogel 1509758cc3dcSJack F Vogel more = ixgbe_rxeof(que); 1510758cc3dcSJack F Vogel 1511758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1512758cc3dcSJack F Vogel ixgbe_txeof(txr); 1513758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX 1514758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1515758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1516758cc3dcSJack F Vogel #else 1517758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1518758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1519758cc3dcSJack F Vogel #endif 1520758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1521758cc3dcSJack F Vogel 1522758cc3dcSJack F Vogel /* Check for fan failure */ 152348056c88SJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82598AT) && 152448056c88SJack F Vogel (reg_eicr & IXGBE_EICR_GPI_SDP1)) { 1525758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " 1526758cc3dcSJack F Vogel "REPLACE IMMEDIATELY!!\n"); 1527758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 1528758cc3dcSJack F Vogel } 1529758cc3dcSJack F Vogel 1530758cc3dcSJack F Vogel /* Link status change */ 1531758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_LSC) 1532758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->link_task); 1533758cc3dcSJack F Vogel 15346f37f232SEric Joyner /* External PHY interrupt */ 15356f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && 15366f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) 15376f37f232SEric Joyner taskqueue_enqueue(adapter->tq, &adapter->phy_task); 15386f37f232SEric Joyner 1539758cc3dcSJack F Vogel if (more) 1540758cc3dcSJack F Vogel taskqueue_enqueue(que->tq, &que->que_task); 1541758cc3dcSJack F Vogel else 1542758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1543758cc3dcSJack F Vogel return; 1544758cc3dcSJack F Vogel } 1545758cc3dcSJack F Vogel 1546758cc3dcSJack F Vogel 1547758cc3dcSJack F Vogel /********************************************************************* 1548758cc3dcSJack F Vogel * 1549758cc3dcSJack F Vogel * MSIX Queue Interrupt Service routine 1550758cc3dcSJack F Vogel * 1551758cc3dcSJack F Vogel **********************************************************************/ 1552758cc3dcSJack F Vogel void 1553758cc3dcSJack F Vogel ixgbe_msix_que(void *arg) 1554758cc3dcSJack F Vogel { 1555758cc3dcSJack F Vogel struct ix_queue *que = arg; 1556758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1557758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1558758cc3dcSJack F Vogel struct tx_ring *txr = que->txr; 1559758cc3dcSJack F Vogel struct rx_ring *rxr = que->rxr; 1560758cc3dcSJack F Vogel bool more; 1561758cc3dcSJack F Vogel u32 newitr = 0; 1562758cc3dcSJack F Vogel 156348056c88SJack F Vogel 1564758cc3dcSJack F Vogel /* Protect against spurious interrupts */ 1565758cc3dcSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1566758cc3dcSJack F Vogel return; 1567758cc3dcSJack F Vogel 1568758cc3dcSJack F Vogel ixgbe_disable_queue(adapter, que->msix); 1569758cc3dcSJack F Vogel ++que->irqs; 1570758cc3dcSJack F Vogel 1571758cc3dcSJack F Vogel more = ixgbe_rxeof(que); 1572758cc3dcSJack F Vogel 1573758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1574758cc3dcSJack F Vogel ixgbe_txeof(txr); 1575758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX 1576758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(ifp->if_snd)) 1577758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1578758cc3dcSJack F Vogel #else 1579758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1580758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1581758cc3dcSJack F Vogel #endif 1582758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1583758cc3dcSJack F Vogel 1584758cc3dcSJack F Vogel /* Do AIM now? */ 1585758cc3dcSJack F Vogel 1586f2c4db54SSteven Hartland if (adapter->enable_aim == FALSE) 1587758cc3dcSJack F Vogel goto no_calc; 1588758cc3dcSJack F Vogel /* 1589758cc3dcSJack F Vogel ** Do Adaptive Interrupt Moderation: 1590758cc3dcSJack F Vogel ** - Write out last calculated setting 1591758cc3dcSJack F Vogel ** - Calculate based on average size over 1592758cc3dcSJack F Vogel ** the last interval. 1593758cc3dcSJack F Vogel */ 1594758cc3dcSJack F Vogel if (que->eitr_setting) 1595758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, 1596758cc3dcSJack F Vogel IXGBE_EITR(que->msix), que->eitr_setting); 1597758cc3dcSJack F Vogel 1598758cc3dcSJack F Vogel que->eitr_setting = 0; 1599758cc3dcSJack F Vogel 1600758cc3dcSJack F Vogel /* Idle, do nothing */ 1601758cc3dcSJack F Vogel if ((txr->bytes == 0) && (rxr->bytes == 0)) 1602758cc3dcSJack F Vogel goto no_calc; 1603758cc3dcSJack F Vogel 1604758cc3dcSJack F Vogel if ((txr->bytes) && (txr->packets)) 1605758cc3dcSJack F Vogel newitr = txr->bytes/txr->packets; 1606758cc3dcSJack F Vogel if ((rxr->bytes) && (rxr->packets)) 1607758cc3dcSJack F Vogel newitr = max(newitr, 1608758cc3dcSJack F Vogel (rxr->bytes / rxr->packets)); 1609758cc3dcSJack F Vogel newitr += 24; /* account for hardware frame, crc */ 1610758cc3dcSJack F Vogel 1611758cc3dcSJack F Vogel /* set an upper boundary */ 1612758cc3dcSJack F Vogel newitr = min(newitr, 3000); 1613758cc3dcSJack F Vogel 1614758cc3dcSJack F Vogel /* Be nice to the mid range */ 1615758cc3dcSJack F Vogel if ((newitr > 300) && (newitr < 1200)) 1616758cc3dcSJack F Vogel newitr = (newitr / 3); 1617758cc3dcSJack F Vogel else 1618758cc3dcSJack F Vogel newitr = (newitr / 2); 1619758cc3dcSJack F Vogel 1620758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) 1621758cc3dcSJack F Vogel newitr |= newitr << 16; 1622758cc3dcSJack F Vogel else 1623758cc3dcSJack F Vogel newitr |= IXGBE_EITR_CNT_WDIS; 1624758cc3dcSJack F Vogel 1625758cc3dcSJack F Vogel /* save for next interrupt */ 1626758cc3dcSJack F Vogel que->eitr_setting = newitr; 1627758cc3dcSJack F Vogel 1628758cc3dcSJack F Vogel /* Reset state */ 1629758cc3dcSJack F Vogel txr->bytes = 0; 1630758cc3dcSJack F Vogel txr->packets = 0; 1631758cc3dcSJack F Vogel rxr->bytes = 0; 1632758cc3dcSJack F Vogel rxr->packets = 0; 1633758cc3dcSJack F Vogel 1634758cc3dcSJack F Vogel no_calc: 1635758cc3dcSJack F Vogel if (more) 1636758cc3dcSJack F Vogel taskqueue_enqueue(que->tq, &que->que_task); 1637758cc3dcSJack F Vogel else 1638758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 1639758cc3dcSJack F Vogel return; 1640758cc3dcSJack F Vogel } 1641758cc3dcSJack F Vogel 1642758cc3dcSJack F Vogel 1643758cc3dcSJack F Vogel static void 1644758cc3dcSJack F Vogel ixgbe_msix_link(void *arg) 1645758cc3dcSJack F Vogel { 1646758cc3dcSJack F Vogel struct adapter *adapter = arg; 1647758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 16486f37f232SEric Joyner u32 reg_eicr, mod_mask; 1649758cc3dcSJack F Vogel 16506f37f232SEric Joyner ++adapter->link_irq; 1651758cc3dcSJack F Vogel 1652a9ca1c79SSean Bruno /* Pause other interrupts */ 1653a9ca1c79SSean Bruno IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_OTHER); 1654a9ca1c79SSean Bruno 1655758cc3dcSJack F Vogel /* First get the cause */ 1656758cc3dcSJack F Vogel reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS); 1657758cc3dcSJack F Vogel /* Be sure the queue bits are not cleared */ 1658758cc3dcSJack F Vogel reg_eicr &= ~IXGBE_EICR_RTX_QUEUE; 1659758cc3dcSJack F Vogel /* Clear interrupt with write */ 1660758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr); 1661758cc3dcSJack F Vogel 1662758cc3dcSJack F Vogel /* Link status change */ 1663a9ca1c79SSean Bruno if (reg_eicr & IXGBE_EICR_LSC) { 1664a9ca1c79SSean Bruno IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); 1665758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->link_task); 1666a9ca1c79SSean Bruno } 1667758cc3dcSJack F Vogel 1668758cc3dcSJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82598EB) { 1669758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 1670758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_FLOW_DIR) { 1671758cc3dcSJack F Vogel /* This is probably overkill :) */ 1672758cc3dcSJack F Vogel if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1)) 1673758cc3dcSJack F Vogel return; 1674758cc3dcSJack F Vogel /* Disable the interrupt */ 1675758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR); 1676758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->fdir_task); 1677758cc3dcSJack F Vogel } else 1678758cc3dcSJack F Vogel #endif 1679758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_ECC) { 1680a9ca1c79SSean Bruno device_printf(adapter->dev, "CRITICAL: ECC ERROR!! " 1681758cc3dcSJack F Vogel "Please Reboot!!\n"); 1682758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); 16836f37f232SEric Joyner } 16846f37f232SEric Joyner 16856f37f232SEric Joyner /* Check for over temp condition */ 16866f37f232SEric Joyner if (reg_eicr & IXGBE_EICR_TS) { 1687a9ca1c79SSean Bruno device_printf(adapter->dev, "CRITICAL: OVER TEMP!! " 16886f37f232SEric Joyner "PHY IS SHUT DOWN!!\n"); 16896f37f232SEric Joyner device_printf(adapter->dev, "System shutdown required!\n"); 16906f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); 16916f37f232SEric Joyner } 169248056c88SJack F Vogel #ifdef PCI_IOV 169348056c88SJack F Vogel if (reg_eicr & IXGBE_EICR_MAILBOX) 169448056c88SJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mbx_task); 169548056c88SJack F Vogel #endif 16966f37f232SEric Joyner } 16976f37f232SEric Joyner 16986f37f232SEric Joyner /* Pluggable optics-related interrupt */ 16996f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) 17006f37f232SEric Joyner mod_mask = IXGBE_EICR_GPI_SDP0_X540; 17016f37f232SEric Joyner else 17026f37f232SEric Joyner mod_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw); 1703758cc3dcSJack F Vogel 1704758cc3dcSJack F Vogel if (ixgbe_is_sfp(hw)) { 17056f37f232SEric Joyner if (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) { 1706758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 1707758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 17086f37f232SEric Joyner } else if (reg_eicr & mod_mask) { 17096f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, mod_mask); 1710758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mod_task); 1711758cc3dcSJack F Vogel } 1712758cc3dcSJack F Vogel } 1713758cc3dcSJack F Vogel 1714758cc3dcSJack F Vogel /* Check for fan failure */ 1715758cc3dcSJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82598AT) && 17166f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP1)) { 17176f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); 1718758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " 1719758cc3dcSJack F Vogel "REPLACE IMMEDIATELY!!\n"); 1720758cc3dcSJack F Vogel } 1721758cc3dcSJack F Vogel 17226f37f232SEric Joyner /* External PHY interrupt */ 17236f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && 17246f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) { 17256f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540); 17266f37f232SEric Joyner taskqueue_enqueue(adapter->tq, &adapter->phy_task); 1727758cc3dcSJack F Vogel } 1728758cc3dcSJack F Vogel 1729a9ca1c79SSean Bruno /* Re-enable other interrupts */ 1730758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); 1731758cc3dcSJack F Vogel return; 1732758cc3dcSJack F Vogel } 1733758cc3dcSJack F Vogel 1734758cc3dcSJack F Vogel /********************************************************************* 1735758cc3dcSJack F Vogel * 1736758cc3dcSJack F Vogel * Media Ioctl callback 1737758cc3dcSJack F Vogel * 1738758cc3dcSJack F Vogel * This routine is called whenever the user queries the status of 1739758cc3dcSJack F Vogel * the interface using ifconfig. 1740758cc3dcSJack F Vogel * 1741758cc3dcSJack F Vogel **********************************************************************/ 1742758cc3dcSJack F Vogel static void 1743758cc3dcSJack F Vogel ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 1744758cc3dcSJack F Vogel { 1745758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 1746758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1747758cc3dcSJack F Vogel int layer; 1748758cc3dcSJack F Vogel 1749758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_media_status: begin"); 1750758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 1751758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 1752758cc3dcSJack F Vogel 1753758cc3dcSJack F Vogel ifmr->ifm_status = IFM_AVALID; 1754758cc3dcSJack F Vogel ifmr->ifm_active = IFM_ETHER; 1755758cc3dcSJack F Vogel 1756758cc3dcSJack F Vogel if (!adapter->link_active) { 1757758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1758758cc3dcSJack F Vogel return; 1759758cc3dcSJack F Vogel } 1760758cc3dcSJack F Vogel 1761758cc3dcSJack F Vogel ifmr->ifm_status |= IFM_ACTIVE; 176248056c88SJack F Vogel layer = adapter->phy_layer; 1763758cc3dcSJack F Vogel 1764758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T || 1765758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_1000BASE_T || 1766758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) 1767758cc3dcSJack F Vogel switch (adapter->link_speed) { 1768758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1769758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 1770758cc3dcSJack F Vogel break; 1771758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1772758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_T | IFM_FDX; 1773758cc3dcSJack F Vogel break; 1774758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_100_FULL: 1775758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_100_TX | IFM_FDX; 1776758cc3dcSJack F Vogel break; 1777758cc3dcSJack F Vogel } 1778758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || 1779758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) 1780758cc3dcSJack F Vogel switch (adapter->link_speed) { 1781758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1782758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX | IFM_FDX; 1783758cc3dcSJack F Vogel break; 1784758cc3dcSJack F Vogel } 1785758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) 1786758cc3dcSJack F Vogel switch (adapter->link_speed) { 1787758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1788758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_LR | IFM_FDX; 1789758cc3dcSJack F Vogel break; 1790758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1791758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; 1792758cc3dcSJack F Vogel break; 1793758cc3dcSJack F Vogel } 1794758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM) 1795758cc3dcSJack F Vogel switch (adapter->link_speed) { 1796758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1797758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_LRM | IFM_FDX; 1798758cc3dcSJack F Vogel break; 1799758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1800758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; 1801758cc3dcSJack F Vogel break; 1802758cc3dcSJack F Vogel } 1803758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR || 1804758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) 1805758cc3dcSJack F Vogel switch (adapter->link_speed) { 1806758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1807758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; 1808758cc3dcSJack F Vogel break; 1809758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1810758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; 1811758cc3dcSJack F Vogel break; 1812758cc3dcSJack F Vogel } 1813758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) 1814758cc3dcSJack F Vogel switch (adapter->link_speed) { 1815758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1816758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; 1817758cc3dcSJack F Vogel break; 1818758cc3dcSJack F Vogel } 1819758cc3dcSJack F Vogel /* 1820758cc3dcSJack F Vogel ** XXX: These need to use the proper media types once 1821758cc3dcSJack F Vogel ** they're added. 1822758cc3dcSJack F Vogel */ 1823a9ca1c79SSean Bruno #ifndef IFM_ETH_XTYPE 1824758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) 1825758cc3dcSJack F Vogel switch (adapter->link_speed) { 1826758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 18276f37f232SEric Joyner ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; 18286f37f232SEric Joyner break; 18296f37f232SEric Joyner case IXGBE_LINK_SPEED_2_5GB_FULL: 18306f37f232SEric Joyner ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; 1831758cc3dcSJack F Vogel break; 1832758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 18336f37f232SEric Joyner ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; 1834758cc3dcSJack F Vogel break; 1835758cc3dcSJack F Vogel } 18366f37f232SEric Joyner else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 1837758cc3dcSJack F Vogel || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) 1838758cc3dcSJack F Vogel switch (adapter->link_speed) { 1839758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 18406f37f232SEric Joyner ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; 18416f37f232SEric Joyner break; 18426f37f232SEric Joyner case IXGBE_LINK_SPEED_2_5GB_FULL: 18436f37f232SEric Joyner ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; 1844758cc3dcSJack F Vogel break; 1845758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 18466f37f232SEric Joyner ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; 1847758cc3dcSJack F Vogel break; 1848758cc3dcSJack F Vogel } 1849a9ca1c79SSean Bruno #else 1850a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) 1851a9ca1c79SSean Bruno switch (adapter->link_speed) { 1852a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_10GB_FULL: 1853a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_10G_KR | IFM_FDX; 1854a9ca1c79SSean Bruno break; 1855a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_2_5GB_FULL: 1856a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; 1857a9ca1c79SSean Bruno break; 1858a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_1GB_FULL: 1859a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; 1860a9ca1c79SSean Bruno break; 1861a9ca1c79SSean Bruno } 1862a9ca1c79SSean Bruno else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 1863a9ca1c79SSean Bruno || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) 1864a9ca1c79SSean Bruno switch (adapter->link_speed) { 1865a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_10GB_FULL: 1866a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_10G_KX4 | IFM_FDX; 1867a9ca1c79SSean Bruno break; 1868a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_2_5GB_FULL: 1869a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; 1870a9ca1c79SSean Bruno break; 1871a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_1GB_FULL: 1872a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; 1873a9ca1c79SSean Bruno break; 1874a9ca1c79SSean Bruno } 1875a9ca1c79SSean Bruno #endif 1876758cc3dcSJack F Vogel 1877758cc3dcSJack F Vogel /* If nothing is recognized... */ 1878758cc3dcSJack F Vogel if (IFM_SUBTYPE(ifmr->ifm_active) == 0) 1879758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_UNKNOWN; 1880758cc3dcSJack F Vogel 1881758cc3dcSJack F Vogel #if __FreeBSD_version >= 900025 18826f37f232SEric Joyner /* Display current flow control setting used on link */ 18836f37f232SEric Joyner if (hw->fc.current_mode == ixgbe_fc_rx_pause || 18846f37f232SEric Joyner hw->fc.current_mode == ixgbe_fc_full) 1885758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_ETH_RXPAUSE; 18866f37f232SEric Joyner if (hw->fc.current_mode == ixgbe_fc_tx_pause || 18876f37f232SEric Joyner hw->fc.current_mode == ixgbe_fc_full) 1888758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_ETH_TXPAUSE; 1889758cc3dcSJack F Vogel #endif 1890758cc3dcSJack F Vogel 1891758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1892758cc3dcSJack F Vogel 1893758cc3dcSJack F Vogel return; 1894758cc3dcSJack F Vogel } 1895758cc3dcSJack F Vogel 1896758cc3dcSJack F Vogel /********************************************************************* 1897758cc3dcSJack F Vogel * 1898758cc3dcSJack F Vogel * Media Ioctl callback 1899758cc3dcSJack F Vogel * 1900758cc3dcSJack F Vogel * This routine is called when the user changes speed/duplex using 1901758cc3dcSJack F Vogel * media/mediopt option with ifconfig. 1902758cc3dcSJack F Vogel * 1903758cc3dcSJack F Vogel **********************************************************************/ 1904758cc3dcSJack F Vogel static int 1905758cc3dcSJack F Vogel ixgbe_media_change(struct ifnet * ifp) 1906758cc3dcSJack F Vogel { 1907758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 1908758cc3dcSJack F Vogel struct ifmedia *ifm = &adapter->media; 1909758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1910758cc3dcSJack F Vogel ixgbe_link_speed speed = 0; 1911758cc3dcSJack F Vogel 1912758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_media_change: begin"); 1913758cc3dcSJack F Vogel 1914758cc3dcSJack F Vogel if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1915758cc3dcSJack F Vogel return (EINVAL); 1916758cc3dcSJack F Vogel 19176f37f232SEric Joyner if (hw->phy.media_type == ixgbe_media_type_backplane) 1918a9ca1c79SSean Bruno return (ENODEV); 19196f37f232SEric Joyner 1920758cc3dcSJack F Vogel /* 1921758cc3dcSJack F Vogel ** We don't actually need to check against the supported 1922758cc3dcSJack F Vogel ** media types of the adapter; ifmedia will take care of 1923758cc3dcSJack F Vogel ** that for us. 1924758cc3dcSJack F Vogel */ 1925a9ca1c79SSean Bruno #ifndef IFM_ETH_XTYPE 1926758cc3dcSJack F Vogel switch (IFM_SUBTYPE(ifm->ifm_media)) { 1927758cc3dcSJack F Vogel case IFM_AUTO: 1928758cc3dcSJack F Vogel case IFM_10G_T: 1929758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1930758cc3dcSJack F Vogel case IFM_10G_LRM: 1931758cc3dcSJack F Vogel case IFM_10G_SR: /* KR, too */ 1932758cc3dcSJack F Vogel case IFM_10G_LR: 19336f37f232SEric Joyner case IFM_10G_CX4: /* KX4 */ 1934758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 1935758cc3dcSJack F Vogel case IFM_10G_TWINAX: 1936758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_10GB_FULL; 1937758cc3dcSJack F Vogel break; 1938758cc3dcSJack F Vogel case IFM_1000_T: 1939758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1940758cc3dcSJack F Vogel case IFM_1000_LX: 1941758cc3dcSJack F Vogel case IFM_1000_SX: 19426f37f232SEric Joyner case IFM_1000_CX: /* KX */ 1943758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 1944758cc3dcSJack F Vogel break; 1945758cc3dcSJack F Vogel case IFM_100_TX: 1946758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1947758cc3dcSJack F Vogel break; 1948758cc3dcSJack F Vogel default: 1949758cc3dcSJack F Vogel goto invalid; 1950758cc3dcSJack F Vogel } 1951a9ca1c79SSean Bruno #else 1952a9ca1c79SSean Bruno switch (IFM_SUBTYPE(ifm->ifm_media)) { 1953a9ca1c79SSean Bruno case IFM_AUTO: 1954a9ca1c79SSean Bruno case IFM_10G_T: 1955a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_100_FULL; 1956a9ca1c79SSean Bruno case IFM_10G_LRM: 1957a9ca1c79SSean Bruno case IFM_10G_KR: 1958a9ca1c79SSean Bruno case IFM_10G_LR: 1959a9ca1c79SSean Bruno case IFM_10G_KX4: 1960a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_1GB_FULL; 1961a9ca1c79SSean Bruno case IFM_10G_TWINAX: 1962a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_10GB_FULL; 1963a9ca1c79SSean Bruno break; 1964a9ca1c79SSean Bruno case IFM_1000_T: 1965a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_100_FULL; 1966a9ca1c79SSean Bruno case IFM_1000_LX: 1967a9ca1c79SSean Bruno case IFM_1000_SX: 1968a9ca1c79SSean Bruno case IFM_1000_KX: 1969a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_1GB_FULL; 1970a9ca1c79SSean Bruno break; 1971a9ca1c79SSean Bruno case IFM_100_TX: 1972a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_100_FULL; 1973a9ca1c79SSean Bruno break; 1974a9ca1c79SSean Bruno default: 1975a9ca1c79SSean Bruno goto invalid; 1976a9ca1c79SSean Bruno } 1977a9ca1c79SSean Bruno #endif 1978758cc3dcSJack F Vogel 1979758cc3dcSJack F Vogel hw->mac.autotry_restart = TRUE; 1980758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, speed, TRUE); 19811566d8d5SSteven Hartland if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) { 19821566d8d5SSteven Hartland adapter->advertise = 0; 19831566d8d5SSteven Hartland } else { 19841566d8d5SSteven Hartland if ((speed & IXGBE_LINK_SPEED_10GB_FULL) != 0) 19851566d8d5SSteven Hartland adapter->advertise |= 1 << 2; 19861566d8d5SSteven Hartland if ((speed & IXGBE_LINK_SPEED_1GB_FULL) != 0) 19871566d8d5SSteven Hartland adapter->advertise |= 1 << 1; 19881566d8d5SSteven Hartland if ((speed & IXGBE_LINK_SPEED_100_FULL) != 0) 19891566d8d5SSteven Hartland adapter->advertise |= 1 << 0; 19901566d8d5SSteven Hartland } 1991758cc3dcSJack F Vogel 1992758cc3dcSJack F Vogel return (0); 1993758cc3dcSJack F Vogel 1994758cc3dcSJack F Vogel invalid: 19956f37f232SEric Joyner device_printf(adapter->dev, "Invalid media type!\n"); 1996758cc3dcSJack F Vogel return (EINVAL); 1997758cc3dcSJack F Vogel } 1998758cc3dcSJack F Vogel 1999758cc3dcSJack F Vogel static void 2000758cc3dcSJack F Vogel ixgbe_set_promisc(struct adapter *adapter) 2001758cc3dcSJack F Vogel { 2002758cc3dcSJack F Vogel u_int32_t reg_rctl; 2003758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 2004758cc3dcSJack F Vogel int mcnt = 0; 2005758cc3dcSJack F Vogel 2006758cc3dcSJack F Vogel reg_rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); 2007758cc3dcSJack F Vogel reg_rctl &= (~IXGBE_FCTRL_UPE); 2008758cc3dcSJack F Vogel if (ifp->if_flags & IFF_ALLMULTI) 2009758cc3dcSJack F Vogel mcnt = MAX_NUM_MULTICAST_ADDRESSES; 2010758cc3dcSJack F Vogel else { 2011758cc3dcSJack F Vogel struct ifmultiaddr *ifma; 2012758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 2013758cc3dcSJack F Vogel IF_ADDR_LOCK(ifp); 2014758cc3dcSJack F Vogel #else 2015758cc3dcSJack F Vogel if_maddr_rlock(ifp); 2016758cc3dcSJack F Vogel #endif 2017758cc3dcSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2018758cc3dcSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 2019758cc3dcSJack F Vogel continue; 2020758cc3dcSJack F Vogel if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) 2021758cc3dcSJack F Vogel break; 2022758cc3dcSJack F Vogel mcnt++; 2023758cc3dcSJack F Vogel } 2024758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 2025758cc3dcSJack F Vogel IF_ADDR_UNLOCK(ifp); 2026758cc3dcSJack F Vogel #else 2027758cc3dcSJack F Vogel if_maddr_runlock(ifp); 2028758cc3dcSJack F Vogel #endif 2029758cc3dcSJack F Vogel } 2030758cc3dcSJack F Vogel if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) 2031758cc3dcSJack F Vogel reg_rctl &= (~IXGBE_FCTRL_MPE); 2032758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 2033758cc3dcSJack F Vogel 2034758cc3dcSJack F Vogel if (ifp->if_flags & IFF_PROMISC) { 2035758cc3dcSJack F Vogel reg_rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 2036758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 2037758cc3dcSJack F Vogel } else if (ifp->if_flags & IFF_ALLMULTI) { 2038758cc3dcSJack F Vogel reg_rctl |= IXGBE_FCTRL_MPE; 2039758cc3dcSJack F Vogel reg_rctl &= ~IXGBE_FCTRL_UPE; 2040758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 2041758cc3dcSJack F Vogel } 2042758cc3dcSJack F Vogel return; 2043758cc3dcSJack F Vogel } 2044758cc3dcSJack F Vogel 2045758cc3dcSJack F Vogel 2046758cc3dcSJack F Vogel /********************************************************************* 2047758cc3dcSJack F Vogel * Multicast Update 2048758cc3dcSJack F Vogel * 2049758cc3dcSJack F Vogel * This routine is called whenever multicast address list is updated. 2050758cc3dcSJack F Vogel * 2051758cc3dcSJack F Vogel **********************************************************************/ 2052758cc3dcSJack F Vogel #define IXGBE_RAR_ENTRIES 16 2053758cc3dcSJack F Vogel 2054758cc3dcSJack F Vogel static void 2055758cc3dcSJack F Vogel ixgbe_set_multi(struct adapter *adapter) 2056758cc3dcSJack F Vogel { 2057758cc3dcSJack F Vogel u32 fctrl; 2058758cc3dcSJack F Vogel u8 *update_ptr; 2059758cc3dcSJack F Vogel struct ifmultiaddr *ifma; 206048056c88SJack F Vogel struct ixgbe_mc_addr *mta; 2061758cc3dcSJack F Vogel int mcnt = 0; 2062758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 2063758cc3dcSJack F Vogel 2064758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); 2065758cc3dcSJack F Vogel 2066758cc3dcSJack F Vogel mta = adapter->mta; 206748056c88SJack F Vogel bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES); 2068758cc3dcSJack F Vogel 2069758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 2070758cc3dcSJack F Vogel IF_ADDR_LOCK(ifp); 2071758cc3dcSJack F Vogel #else 2072758cc3dcSJack F Vogel if_maddr_rlock(ifp); 2073758cc3dcSJack F Vogel #endif 2074758cc3dcSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2075758cc3dcSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 2076758cc3dcSJack F Vogel continue; 2077758cc3dcSJack F Vogel if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) 2078758cc3dcSJack F Vogel break; 2079758cc3dcSJack F Vogel bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), 208048056c88SJack F Vogel mta[mcnt].addr, IXGBE_ETH_LENGTH_OF_ADDRESS); 208148056c88SJack F Vogel mta[mcnt].vmdq = adapter->pool; 2082758cc3dcSJack F Vogel mcnt++; 2083758cc3dcSJack F Vogel } 2084758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 2085758cc3dcSJack F Vogel IF_ADDR_UNLOCK(ifp); 2086758cc3dcSJack F Vogel #else 2087758cc3dcSJack F Vogel if_maddr_runlock(ifp); 2088758cc3dcSJack F Vogel #endif 2089758cc3dcSJack F Vogel 2090758cc3dcSJack F Vogel fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); 2091758cc3dcSJack F Vogel fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 2092758cc3dcSJack F Vogel if (ifp->if_flags & IFF_PROMISC) 2093758cc3dcSJack F Vogel fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 2094758cc3dcSJack F Vogel else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES || 2095758cc3dcSJack F Vogel ifp->if_flags & IFF_ALLMULTI) { 2096758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_MPE; 2097758cc3dcSJack F Vogel fctrl &= ~IXGBE_FCTRL_UPE; 2098758cc3dcSJack F Vogel } else 2099758cc3dcSJack F Vogel fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 2100758cc3dcSJack F Vogel 2101758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); 2102758cc3dcSJack F Vogel 2103758cc3dcSJack F Vogel if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) { 210448056c88SJack F Vogel update_ptr = (u8 *)mta; 2105758cc3dcSJack F Vogel ixgbe_update_mc_addr_list(&adapter->hw, 2106758cc3dcSJack F Vogel update_ptr, mcnt, ixgbe_mc_array_itr, TRUE); 2107758cc3dcSJack F Vogel } 2108758cc3dcSJack F Vogel 2109758cc3dcSJack F Vogel return; 2110758cc3dcSJack F Vogel } 2111758cc3dcSJack F Vogel 2112758cc3dcSJack F Vogel /* 2113758cc3dcSJack F Vogel * This is an iterator function now needed by the multicast 2114758cc3dcSJack F Vogel * shared code. It simply feeds the shared code routine the 2115758cc3dcSJack F Vogel * addresses in the array of ixgbe_set_multi() one by one. 2116758cc3dcSJack F Vogel */ 2117758cc3dcSJack F Vogel static u8 * 2118758cc3dcSJack F Vogel ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) 2119758cc3dcSJack F Vogel { 212048056c88SJack F Vogel struct ixgbe_mc_addr *mta; 2121758cc3dcSJack F Vogel 212248056c88SJack F Vogel mta = (struct ixgbe_mc_addr *)*update_ptr; 212348056c88SJack F Vogel *vmdq = mta->vmdq; 212448056c88SJack F Vogel 212548056c88SJack F Vogel *update_ptr = (u8*)(mta + 1);; 212648056c88SJack F Vogel return (mta->addr); 2127758cc3dcSJack F Vogel } 2128758cc3dcSJack F Vogel 2129758cc3dcSJack F Vogel 2130758cc3dcSJack F Vogel /********************************************************************* 2131758cc3dcSJack F Vogel * Timer routine 2132758cc3dcSJack F Vogel * 2133758cc3dcSJack F Vogel * This routine checks for link status,updates statistics, 2134758cc3dcSJack F Vogel * and runs the watchdog check. 2135758cc3dcSJack F Vogel * 2136758cc3dcSJack F Vogel **********************************************************************/ 2137758cc3dcSJack F Vogel 2138758cc3dcSJack F Vogel static void 2139758cc3dcSJack F Vogel ixgbe_local_timer(void *arg) 2140758cc3dcSJack F Vogel { 2141758cc3dcSJack F Vogel struct adapter *adapter = arg; 2142758cc3dcSJack F Vogel device_t dev = adapter->dev; 2143758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2144758cc3dcSJack F Vogel u64 queues = 0; 2145758cc3dcSJack F Vogel int hung = 0; 2146758cc3dcSJack F Vogel 2147758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 2148758cc3dcSJack F Vogel 2149758cc3dcSJack F Vogel /* Check for pluggable optics */ 2150758cc3dcSJack F Vogel if (adapter->sfp_probe) 2151758cc3dcSJack F Vogel if (!ixgbe_sfp_probe(adapter)) 2152758cc3dcSJack F Vogel goto out; /* Nothing to do */ 2153758cc3dcSJack F Vogel 2154758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 2155758cc3dcSJack F Vogel ixgbe_update_stats_counters(adapter); 2156758cc3dcSJack F Vogel 2157758cc3dcSJack F Vogel /* 2158758cc3dcSJack F Vogel ** Check the TX queues status 2159758cc3dcSJack F Vogel ** - mark hung queues so we don't schedule on them 2160758cc3dcSJack F Vogel ** - watchdog only if all queues show hung 2161758cc3dcSJack F Vogel */ 2162758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 2163758cc3dcSJack F Vogel /* Keep track of queues with work for soft irq */ 2164758cc3dcSJack F Vogel if (que->txr->busy) 2165758cc3dcSJack F Vogel queues |= ((u64)1 << que->me); 2166758cc3dcSJack F Vogel /* 2167758cc3dcSJack F Vogel ** Each time txeof runs without cleaning, but there 2168758cc3dcSJack F Vogel ** are uncleaned descriptors it increments busy. If 2169758cc3dcSJack F Vogel ** we get to the MAX we declare it hung. 2170758cc3dcSJack F Vogel */ 2171758cc3dcSJack F Vogel if (que->busy == IXGBE_QUEUE_HUNG) { 2172758cc3dcSJack F Vogel ++hung; 2173758cc3dcSJack F Vogel /* Mark the queue as inactive */ 2174758cc3dcSJack F Vogel adapter->active_queues &= ~((u64)1 << que->me); 2175758cc3dcSJack F Vogel continue; 2176758cc3dcSJack F Vogel } else { 2177758cc3dcSJack F Vogel /* Check if we've come back from hung */ 2178758cc3dcSJack F Vogel if ((adapter->active_queues & ((u64)1 << que->me)) == 0) 2179758cc3dcSJack F Vogel adapter->active_queues |= ((u64)1 << que->me); 2180758cc3dcSJack F Vogel } 2181758cc3dcSJack F Vogel if (que->busy >= IXGBE_MAX_TX_BUSY) { 2182758cc3dcSJack F Vogel device_printf(dev,"Warning queue %d " 2183758cc3dcSJack F Vogel "appears to be hung!\n", i); 2184758cc3dcSJack F Vogel que->txr->busy = IXGBE_QUEUE_HUNG; 2185758cc3dcSJack F Vogel ++hung; 2186758cc3dcSJack F Vogel } 2187758cc3dcSJack F Vogel 2188758cc3dcSJack F Vogel } 2189758cc3dcSJack F Vogel 2190758cc3dcSJack F Vogel /* Only truly watchdog if all queues show hung */ 2191758cc3dcSJack F Vogel if (hung == adapter->num_queues) 2192758cc3dcSJack F Vogel goto watchdog; 2193758cc3dcSJack F Vogel else if (queues != 0) { /* Force an IRQ on queues with work */ 2194758cc3dcSJack F Vogel ixgbe_rearm_queues(adapter, queues); 2195758cc3dcSJack F Vogel } 2196758cc3dcSJack F Vogel 2197758cc3dcSJack F Vogel out: 2198758cc3dcSJack F Vogel callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); 2199758cc3dcSJack F Vogel return; 2200758cc3dcSJack F Vogel 2201758cc3dcSJack F Vogel watchdog: 2202758cc3dcSJack F Vogel device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); 2203758cc3dcSJack F Vogel adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2204758cc3dcSJack F Vogel adapter->watchdog_events++; 2205758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 2206758cc3dcSJack F Vogel } 2207758cc3dcSJack F Vogel 220848056c88SJack F Vogel 2209758cc3dcSJack F Vogel /* 2210758cc3dcSJack F Vogel ** Note: this routine updates the OS on the link state 2211758cc3dcSJack F Vogel ** the real check of the hardware only happens with 2212758cc3dcSJack F Vogel ** a link interrupt. 2213758cc3dcSJack F Vogel */ 2214758cc3dcSJack F Vogel static void 2215758cc3dcSJack F Vogel ixgbe_update_link_status(struct adapter *adapter) 2216758cc3dcSJack F Vogel { 2217758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 2218758cc3dcSJack F Vogel device_t dev = adapter->dev; 2219758cc3dcSJack F Vogel 2220758cc3dcSJack F Vogel if (adapter->link_up){ 2221758cc3dcSJack F Vogel if (adapter->link_active == FALSE) { 2222758cc3dcSJack F Vogel if (bootverbose) 2223758cc3dcSJack F Vogel device_printf(dev,"Link is up %d Gbps %s \n", 2224758cc3dcSJack F Vogel ((adapter->link_speed == 128)? 10:1), 2225758cc3dcSJack F Vogel "Full Duplex"); 2226758cc3dcSJack F Vogel adapter->link_active = TRUE; 2227758cc3dcSJack F Vogel /* Update any Flow Control changes */ 2228758cc3dcSJack F Vogel ixgbe_fc_enable(&adapter->hw); 22296f37f232SEric Joyner /* Update DMA coalescing config */ 22306f37f232SEric Joyner ixgbe_config_dmac(adapter); 2231758cc3dcSJack F Vogel if_link_state_change(ifp, LINK_STATE_UP); 223248056c88SJack F Vogel #ifdef PCI_IOV 223348056c88SJack F Vogel ixgbe_ping_all_vfs(adapter); 223448056c88SJack F Vogel #endif 2235758cc3dcSJack F Vogel } 2236758cc3dcSJack F Vogel } else { /* Link down */ 2237758cc3dcSJack F Vogel if (adapter->link_active == TRUE) { 2238758cc3dcSJack F Vogel if (bootverbose) 2239758cc3dcSJack F Vogel device_printf(dev,"Link is Down\n"); 2240758cc3dcSJack F Vogel if_link_state_change(ifp, LINK_STATE_DOWN); 2241758cc3dcSJack F Vogel adapter->link_active = FALSE; 224248056c88SJack F Vogel #ifdef PCI_IOV 224348056c88SJack F Vogel ixgbe_ping_all_vfs(adapter); 224448056c88SJack F Vogel #endif 2245758cc3dcSJack F Vogel } 2246758cc3dcSJack F Vogel } 2247758cc3dcSJack F Vogel 2248758cc3dcSJack F Vogel return; 2249758cc3dcSJack F Vogel } 2250758cc3dcSJack F Vogel 2251758cc3dcSJack F Vogel 2252758cc3dcSJack F Vogel /********************************************************************* 2253758cc3dcSJack F Vogel * 2254758cc3dcSJack F Vogel * This routine disables all traffic on the adapter by issuing a 2255758cc3dcSJack F Vogel * global reset on the MAC and deallocates TX/RX buffers. 2256758cc3dcSJack F Vogel * 2257758cc3dcSJack F Vogel **********************************************************************/ 2258758cc3dcSJack F Vogel 2259758cc3dcSJack F Vogel static void 2260758cc3dcSJack F Vogel ixgbe_stop(void *arg) 2261758cc3dcSJack F Vogel { 2262758cc3dcSJack F Vogel struct ifnet *ifp; 2263758cc3dcSJack F Vogel struct adapter *adapter = arg; 2264758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2265758cc3dcSJack F Vogel ifp = adapter->ifp; 2266758cc3dcSJack F Vogel 2267758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 2268758cc3dcSJack F Vogel 2269758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_stop: begin\n"); 2270758cc3dcSJack F Vogel ixgbe_disable_intr(adapter); 2271758cc3dcSJack F Vogel callout_stop(&adapter->timer); 2272758cc3dcSJack F Vogel 2273758cc3dcSJack F Vogel /* Let the stack know...*/ 2274758cc3dcSJack F Vogel ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2275758cc3dcSJack F Vogel 2276758cc3dcSJack F Vogel ixgbe_reset_hw(hw); 2277758cc3dcSJack F Vogel hw->adapter_stopped = FALSE; 2278758cc3dcSJack F Vogel ixgbe_stop_adapter(hw); 2279758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82599EB) 2280758cc3dcSJack F Vogel ixgbe_stop_mac_link_on_d3_82599(hw); 2281758cc3dcSJack F Vogel /* Turn off the laser - noop with no optics */ 2282758cc3dcSJack F Vogel ixgbe_disable_tx_laser(hw); 2283758cc3dcSJack F Vogel 2284758cc3dcSJack F Vogel /* Update the stack */ 2285758cc3dcSJack F Vogel adapter->link_up = FALSE; 2286758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 2287758cc3dcSJack F Vogel 2288758cc3dcSJack F Vogel /* reprogram the RAR[0] in case user changed it. */ 2289758cc3dcSJack F Vogel ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); 2290758cc3dcSJack F Vogel 2291758cc3dcSJack F Vogel return; 2292758cc3dcSJack F Vogel } 2293758cc3dcSJack F Vogel 2294758cc3dcSJack F Vogel 2295758cc3dcSJack F Vogel /********************************************************************* 2296758cc3dcSJack F Vogel * 2297758cc3dcSJack F Vogel * Determine hardware revision. 2298758cc3dcSJack F Vogel * 2299758cc3dcSJack F Vogel **********************************************************************/ 2300758cc3dcSJack F Vogel static void 2301758cc3dcSJack F Vogel ixgbe_identify_hardware(struct adapter *adapter) 2302758cc3dcSJack F Vogel { 2303758cc3dcSJack F Vogel device_t dev = adapter->dev; 2304758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2305758cc3dcSJack F Vogel 2306758cc3dcSJack F Vogel /* Save off the information about this board */ 2307758cc3dcSJack F Vogel hw->vendor_id = pci_get_vendor(dev); 2308758cc3dcSJack F Vogel hw->device_id = pci_get_device(dev); 2309758cc3dcSJack F Vogel hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 2310758cc3dcSJack F Vogel hw->subsystem_vendor_id = 2311758cc3dcSJack F Vogel pci_read_config(dev, PCIR_SUBVEND_0, 2); 2312758cc3dcSJack F Vogel hw->subsystem_device_id = 2313758cc3dcSJack F Vogel pci_read_config(dev, PCIR_SUBDEV_0, 2); 2314758cc3dcSJack F Vogel 2315758cc3dcSJack F Vogel /* 2316758cc3dcSJack F Vogel ** Make sure BUSMASTER is set 2317758cc3dcSJack F Vogel */ 2318758cc3dcSJack F Vogel pci_enable_busmaster(dev); 2319758cc3dcSJack F Vogel 2320758cc3dcSJack F Vogel /* We need this here to set the num_segs below */ 2321758cc3dcSJack F Vogel ixgbe_set_mac_type(hw); 2322758cc3dcSJack F Vogel 23236f37f232SEric Joyner /* Pick up the 82599 settings */ 2324758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 2325758cc3dcSJack F Vogel hw->phy.smart_speed = ixgbe_smart_speed; 2326758cc3dcSJack F Vogel adapter->num_segs = IXGBE_82599_SCATTER; 2327758cc3dcSJack F Vogel } else 2328758cc3dcSJack F Vogel adapter->num_segs = IXGBE_82598_SCATTER; 2329758cc3dcSJack F Vogel 2330758cc3dcSJack F Vogel return; 2331758cc3dcSJack F Vogel } 2332758cc3dcSJack F Vogel 2333758cc3dcSJack F Vogel /********************************************************************* 2334758cc3dcSJack F Vogel * 2335758cc3dcSJack F Vogel * Determine optic type 2336758cc3dcSJack F Vogel * 2337758cc3dcSJack F Vogel **********************************************************************/ 2338758cc3dcSJack F Vogel static void 2339758cc3dcSJack F Vogel ixgbe_setup_optics(struct adapter *adapter) 2340758cc3dcSJack F Vogel { 2341758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2342758cc3dcSJack F Vogel int layer; 2343758cc3dcSJack F Vogel 234448056c88SJack F Vogel layer = adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); 2345758cc3dcSJack F Vogel 2346758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) { 2347758cc3dcSJack F Vogel adapter->optics = IFM_10G_T; 2348758cc3dcSJack F Vogel return; 2349758cc3dcSJack F Vogel } 2350758cc3dcSJack F Vogel 2351758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) { 2352758cc3dcSJack F Vogel adapter->optics = IFM_1000_T; 2353758cc3dcSJack F Vogel return; 2354758cc3dcSJack F Vogel } 2355758cc3dcSJack F Vogel 2356758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) { 2357758cc3dcSJack F Vogel adapter->optics = IFM_1000_SX; 2358758cc3dcSJack F Vogel return; 2359758cc3dcSJack F Vogel } 2360758cc3dcSJack F Vogel 2361758cc3dcSJack F Vogel if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_LR | 2362758cc3dcSJack F Vogel IXGBE_PHYSICAL_LAYER_10GBASE_LRM)) { 2363758cc3dcSJack F Vogel adapter->optics = IFM_10G_LR; 2364758cc3dcSJack F Vogel return; 2365758cc3dcSJack F Vogel } 2366758cc3dcSJack F Vogel 2367758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { 2368758cc3dcSJack F Vogel adapter->optics = IFM_10G_SR; 2369758cc3dcSJack F Vogel return; 2370758cc3dcSJack F Vogel } 2371758cc3dcSJack F Vogel 2372758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU) { 2373758cc3dcSJack F Vogel adapter->optics = IFM_10G_TWINAX; 2374758cc3dcSJack F Vogel return; 2375758cc3dcSJack F Vogel } 2376758cc3dcSJack F Vogel 2377758cc3dcSJack F Vogel if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | 2378758cc3dcSJack F Vogel IXGBE_PHYSICAL_LAYER_10GBASE_CX4)) { 2379758cc3dcSJack F Vogel adapter->optics = IFM_10G_CX4; 2380758cc3dcSJack F Vogel return; 2381758cc3dcSJack F Vogel } 2382758cc3dcSJack F Vogel 2383758cc3dcSJack F Vogel /* If we get here just set the default */ 2384758cc3dcSJack F Vogel adapter->optics = IFM_ETHER | IFM_AUTO; 2385758cc3dcSJack F Vogel return; 2386758cc3dcSJack F Vogel } 2387758cc3dcSJack F Vogel 2388758cc3dcSJack F Vogel /********************************************************************* 2389758cc3dcSJack F Vogel * 2390758cc3dcSJack F Vogel * Setup the Legacy or MSI Interrupt handler 2391758cc3dcSJack F Vogel * 2392758cc3dcSJack F Vogel **********************************************************************/ 2393758cc3dcSJack F Vogel static int 2394758cc3dcSJack F Vogel ixgbe_allocate_legacy(struct adapter *adapter) 2395758cc3dcSJack F Vogel { 2396758cc3dcSJack F Vogel device_t dev = adapter->dev; 2397758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2398758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2399758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2400758cc3dcSJack F Vogel #endif 2401758cc3dcSJack F Vogel int error, rid = 0; 2402758cc3dcSJack F Vogel 2403758cc3dcSJack F Vogel /* MSI RID at 1 */ 2404758cc3dcSJack F Vogel if (adapter->msix == 1) 2405758cc3dcSJack F Vogel rid = 1; 2406758cc3dcSJack F Vogel 2407758cc3dcSJack F Vogel /* We allocate a single interrupt resource */ 2408758cc3dcSJack F Vogel adapter->res = bus_alloc_resource_any(dev, 2409758cc3dcSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 2410758cc3dcSJack F Vogel if (adapter->res == NULL) { 2411758cc3dcSJack F Vogel device_printf(dev, "Unable to allocate bus resource: " 2412758cc3dcSJack F Vogel "interrupt\n"); 2413758cc3dcSJack F Vogel return (ENXIO); 2414758cc3dcSJack F Vogel } 2415758cc3dcSJack F Vogel 2416758cc3dcSJack F Vogel /* 2417758cc3dcSJack F Vogel * Try allocating a fast interrupt and the associated deferred 2418758cc3dcSJack F Vogel * processing contexts. 2419758cc3dcSJack F Vogel */ 2420758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2421758cc3dcSJack F Vogel TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); 2422758cc3dcSJack F Vogel #endif 2423758cc3dcSJack F Vogel TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); 2424758cc3dcSJack F Vogel que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, 2425758cc3dcSJack F Vogel taskqueue_thread_enqueue, &que->tq); 2426758cc3dcSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s ixq", 2427758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2428758cc3dcSJack F Vogel 2429758cc3dcSJack F Vogel /* Tasklets for Link, SFP and Multispeed Fiber */ 2430758cc3dcSJack F Vogel TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); 2431758cc3dcSJack F Vogel TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); 2432758cc3dcSJack F Vogel TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); 24336f37f232SEric Joyner TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); 2434758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 2435758cc3dcSJack F Vogel TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); 2436758cc3dcSJack F Vogel #endif 2437758cc3dcSJack F Vogel adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, 2438758cc3dcSJack F Vogel taskqueue_thread_enqueue, &adapter->tq); 2439758cc3dcSJack F Vogel taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", 2440758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2441758cc3dcSJack F Vogel 2442758cc3dcSJack F Vogel if ((error = bus_setup_intr(dev, adapter->res, 2443758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq, 2444758cc3dcSJack F Vogel que, &adapter->tag)) != 0) { 2445758cc3dcSJack F Vogel device_printf(dev, "Failed to register fast interrupt " 2446758cc3dcSJack F Vogel "handler: %d\n", error); 2447758cc3dcSJack F Vogel taskqueue_free(que->tq); 2448758cc3dcSJack F Vogel taskqueue_free(adapter->tq); 2449758cc3dcSJack F Vogel que->tq = NULL; 2450758cc3dcSJack F Vogel adapter->tq = NULL; 2451758cc3dcSJack F Vogel return (error); 2452758cc3dcSJack F Vogel } 2453758cc3dcSJack F Vogel /* For simplicity in the handlers */ 2454758cc3dcSJack F Vogel adapter->active_queues = IXGBE_EIMS_ENABLE_MASK; 2455758cc3dcSJack F Vogel 2456758cc3dcSJack F Vogel return (0); 2457758cc3dcSJack F Vogel } 2458758cc3dcSJack F Vogel 2459758cc3dcSJack F Vogel 2460758cc3dcSJack F Vogel /********************************************************************* 2461758cc3dcSJack F Vogel * 2462758cc3dcSJack F Vogel * Setup MSIX Interrupt resources and handlers 2463758cc3dcSJack F Vogel * 2464758cc3dcSJack F Vogel **********************************************************************/ 2465758cc3dcSJack F Vogel static int 2466758cc3dcSJack F Vogel ixgbe_allocate_msix(struct adapter *adapter) 2467758cc3dcSJack F Vogel { 2468758cc3dcSJack F Vogel device_t dev = adapter->dev; 2469758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2470758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2471758cc3dcSJack F Vogel int error, rid, vector = 0; 2472758cc3dcSJack F Vogel int cpu_id = 0; 2473a1edda90SAdrian Chadd #ifdef RSS 2474a1edda90SAdrian Chadd cpuset_t cpu_mask; 2475a1edda90SAdrian Chadd #endif 2476758cc3dcSJack F Vogel 2477758cc3dcSJack F Vogel #ifdef RSS 2478758cc3dcSJack F Vogel /* 2479758cc3dcSJack F Vogel * If we're doing RSS, the number of queues needs to 2480758cc3dcSJack F Vogel * match the number of RSS buckets that are configured. 2481758cc3dcSJack F Vogel * 2482758cc3dcSJack F Vogel * + If there's more queues than RSS buckets, we'll end 2483758cc3dcSJack F Vogel * up with queues that get no traffic. 2484758cc3dcSJack F Vogel * 2485758cc3dcSJack F Vogel * + If there's more RSS buckets than queues, we'll end 2486758cc3dcSJack F Vogel * up having multiple RSS buckets map to the same queue, 2487758cc3dcSJack F Vogel * so there'll be some contention. 2488758cc3dcSJack F Vogel */ 2489758cc3dcSJack F Vogel if (adapter->num_queues != rss_getnumbuckets()) { 2490758cc3dcSJack F Vogel device_printf(dev, 2491758cc3dcSJack F Vogel "%s: number of queues (%d) != number of RSS buckets (%d)" 2492758cc3dcSJack F Vogel "; performance will be impacted.\n", 2493758cc3dcSJack F Vogel __func__, 2494758cc3dcSJack F Vogel adapter->num_queues, 2495758cc3dcSJack F Vogel rss_getnumbuckets()); 2496758cc3dcSJack F Vogel } 2497758cc3dcSJack F Vogel #endif 2498758cc3dcSJack F Vogel 2499758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { 2500758cc3dcSJack F Vogel rid = vector + 1; 2501758cc3dcSJack F Vogel que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 2502758cc3dcSJack F Vogel RF_SHAREABLE | RF_ACTIVE); 2503758cc3dcSJack F Vogel if (que->res == NULL) { 2504758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate" 2505758cc3dcSJack F Vogel " bus resource: que interrupt [%d]\n", vector); 2506758cc3dcSJack F Vogel return (ENXIO); 2507758cc3dcSJack F Vogel } 2508758cc3dcSJack F Vogel /* Set the handler function */ 2509758cc3dcSJack F Vogel error = bus_setup_intr(dev, que->res, 2510758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 2511758cc3dcSJack F Vogel ixgbe_msix_que, que, &que->tag); 2512758cc3dcSJack F Vogel if (error) { 2513758cc3dcSJack F Vogel que->res = NULL; 2514758cc3dcSJack F Vogel device_printf(dev, "Failed to register QUE handler"); 2515758cc3dcSJack F Vogel return (error); 2516758cc3dcSJack F Vogel } 2517758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504 2518a9ca1c79SSean Bruno bus_describe_intr(dev, que->res, que->tag, "q%d", i); 2519758cc3dcSJack F Vogel #endif 2520758cc3dcSJack F Vogel que->msix = vector; 2521758cc3dcSJack F Vogel adapter->active_queues |= (u64)(1 << que->msix); 2522758cc3dcSJack F Vogel #ifdef RSS 2523758cc3dcSJack F Vogel /* 2524758cc3dcSJack F Vogel * The queue ID is used as the RSS layer bucket ID. 2525758cc3dcSJack F Vogel * We look up the queue ID -> RSS CPU ID and select 2526758cc3dcSJack F Vogel * that. 2527758cc3dcSJack F Vogel */ 2528758cc3dcSJack F Vogel cpu_id = rss_getcpu(i % rss_getnumbuckets()); 2529758cc3dcSJack F Vogel #else 2530758cc3dcSJack F Vogel /* 2531758cc3dcSJack F Vogel * Bind the msix vector, and thus the 2532758cc3dcSJack F Vogel * rings to the corresponding cpu. 2533758cc3dcSJack F Vogel * 2534758cc3dcSJack F Vogel * This just happens to match the default RSS round-robin 2535758cc3dcSJack F Vogel * bucket -> queue -> CPU allocation. 2536758cc3dcSJack F Vogel */ 2537758cc3dcSJack F Vogel if (adapter->num_queues > 1) 2538758cc3dcSJack F Vogel cpu_id = i; 2539758cc3dcSJack F Vogel #endif 2540758cc3dcSJack F Vogel if (adapter->num_queues > 1) 2541758cc3dcSJack F Vogel bus_bind_intr(dev, que->res, cpu_id); 254248056c88SJack F Vogel #ifdef IXGBE_DEBUG 2543758cc3dcSJack F Vogel #ifdef RSS 2544758cc3dcSJack F Vogel device_printf(dev, 2545758cc3dcSJack F Vogel "Bound RSS bucket %d to CPU %d\n", 2546758cc3dcSJack F Vogel i, cpu_id); 2547758cc3dcSJack F Vogel #else 2548758cc3dcSJack F Vogel device_printf(dev, 2549758cc3dcSJack F Vogel "Bound queue %d to cpu %d\n", 2550758cc3dcSJack F Vogel i, cpu_id); 2551758cc3dcSJack F Vogel #endif 255248056c88SJack F Vogel #endif /* IXGBE_DEBUG */ 255348056c88SJack F Vogel 255448056c88SJack F Vogel 2555758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2556758cc3dcSJack F Vogel TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); 2557758cc3dcSJack F Vogel #endif 2558758cc3dcSJack F Vogel TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); 2559758cc3dcSJack F Vogel que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, 2560758cc3dcSJack F Vogel taskqueue_thread_enqueue, &que->tq); 2561758cc3dcSJack F Vogel #ifdef RSS 2562a1edda90SAdrian Chadd CPU_SETOF(cpu_id, &cpu_mask); 2563a1edda90SAdrian Chadd taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, 2564a1edda90SAdrian Chadd &cpu_mask, 2565758cc3dcSJack F Vogel "%s (bucket %d)", 2566758cc3dcSJack F Vogel device_get_nameunit(adapter->dev), 2567758cc3dcSJack F Vogel cpu_id); 2568758cc3dcSJack F Vogel #else 2569a9ca1c79SSean Bruno taskqueue_start_threads(&que->tq, 1, PI_NET, "%s:q%d", 2570a9ca1c79SSean Bruno device_get_nameunit(adapter->dev), i); 2571758cc3dcSJack F Vogel #endif 2572758cc3dcSJack F Vogel } 2573758cc3dcSJack F Vogel 2574758cc3dcSJack F Vogel /* and Link */ 2575758cc3dcSJack F Vogel rid = vector + 1; 2576758cc3dcSJack F Vogel adapter->res = bus_alloc_resource_any(dev, 2577758cc3dcSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 2578758cc3dcSJack F Vogel if (!adapter->res) { 2579758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate" 2580758cc3dcSJack F Vogel " bus resource: Link interrupt [%d]\n", rid); 2581758cc3dcSJack F Vogel return (ENXIO); 2582758cc3dcSJack F Vogel } 2583758cc3dcSJack F Vogel /* Set the link handler function */ 2584758cc3dcSJack F Vogel error = bus_setup_intr(dev, adapter->res, 2585758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 2586758cc3dcSJack F Vogel ixgbe_msix_link, adapter, &adapter->tag); 2587758cc3dcSJack F Vogel if (error) { 2588758cc3dcSJack F Vogel adapter->res = NULL; 2589758cc3dcSJack F Vogel device_printf(dev, "Failed to register LINK handler"); 2590758cc3dcSJack F Vogel return (error); 2591758cc3dcSJack F Vogel } 2592758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504 2593758cc3dcSJack F Vogel bus_describe_intr(dev, adapter->res, adapter->tag, "link"); 2594758cc3dcSJack F Vogel #endif 2595758cc3dcSJack F Vogel adapter->vector = vector; 2596758cc3dcSJack F Vogel /* Tasklets for Link, SFP and Multispeed Fiber */ 2597758cc3dcSJack F Vogel TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); 2598758cc3dcSJack F Vogel TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); 2599758cc3dcSJack F Vogel TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); 260048056c88SJack F Vogel #ifdef PCI_IOV 260148056c88SJack F Vogel TASK_INIT(&adapter->mbx_task, 0, ixgbe_handle_mbx, adapter); 260248056c88SJack F Vogel #endif 26036f37f232SEric Joyner TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); 2604758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 2605758cc3dcSJack F Vogel TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); 2606758cc3dcSJack F Vogel #endif 2607758cc3dcSJack F Vogel adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, 2608758cc3dcSJack F Vogel taskqueue_thread_enqueue, &adapter->tq); 2609758cc3dcSJack F Vogel taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", 2610758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2611758cc3dcSJack F Vogel 2612758cc3dcSJack F Vogel return (0); 2613758cc3dcSJack F Vogel } 2614758cc3dcSJack F Vogel 2615758cc3dcSJack F Vogel /* 2616758cc3dcSJack F Vogel * Setup Either MSI/X or MSI 2617758cc3dcSJack F Vogel */ 2618758cc3dcSJack F Vogel static int 2619758cc3dcSJack F Vogel ixgbe_setup_msix(struct adapter *adapter) 2620758cc3dcSJack F Vogel { 2621758cc3dcSJack F Vogel device_t dev = adapter->dev; 2622758cc3dcSJack F Vogel int rid, want, queues, msgs; 2623758cc3dcSJack F Vogel 2624758cc3dcSJack F Vogel /* Override by tuneable */ 2625758cc3dcSJack F Vogel if (ixgbe_enable_msix == 0) 2626758cc3dcSJack F Vogel goto msi; 2627758cc3dcSJack F Vogel 2628758cc3dcSJack F Vogel /* First try MSI/X */ 2629758cc3dcSJack F Vogel msgs = pci_msix_count(dev); 2630758cc3dcSJack F Vogel if (msgs == 0) 2631758cc3dcSJack F Vogel goto msi; 2632758cc3dcSJack F Vogel rid = PCIR_BAR(MSIX_82598_BAR); 2633758cc3dcSJack F Vogel adapter->msix_mem = bus_alloc_resource_any(dev, 2634758cc3dcSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 2635758cc3dcSJack F Vogel if (adapter->msix_mem == NULL) { 2636758cc3dcSJack F Vogel rid += 4; /* 82599 maps in higher BAR */ 2637758cc3dcSJack F Vogel adapter->msix_mem = bus_alloc_resource_any(dev, 2638758cc3dcSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 2639758cc3dcSJack F Vogel } 2640758cc3dcSJack F Vogel if (adapter->msix_mem == NULL) { 2641758cc3dcSJack F Vogel /* May not be enabled */ 2642758cc3dcSJack F Vogel device_printf(adapter->dev, 2643758cc3dcSJack F Vogel "Unable to map MSIX table \n"); 2644758cc3dcSJack F Vogel goto msi; 2645758cc3dcSJack F Vogel } 2646758cc3dcSJack F Vogel 2647758cc3dcSJack F Vogel /* Figure out a reasonable auto config value */ 2648758cc3dcSJack F Vogel queues = (mp_ncpus > (msgs - 1)) ? (msgs - 1) : mp_ncpus; 2649758cc3dcSJack F Vogel 2650758cc3dcSJack F Vogel #ifdef RSS 2651758cc3dcSJack F Vogel /* If we're doing RSS, clamp at the number of RSS buckets */ 2652758cc3dcSJack F Vogel if (queues > rss_getnumbuckets()) 2653758cc3dcSJack F Vogel queues = rss_getnumbuckets(); 2654758cc3dcSJack F Vogel #endif 2655758cc3dcSJack F Vogel 2656758cc3dcSJack F Vogel if (ixgbe_num_queues != 0) 2657758cc3dcSJack F Vogel queues = ixgbe_num_queues; 2658a9ca1c79SSean Bruno /* Set max queues to 8 when autoconfiguring */ 2659a9ca1c79SSean Bruno else if ((ixgbe_num_queues == 0) && (queues > 8)) 2660a9ca1c79SSean Bruno queues = 8; 2661758cc3dcSJack F Vogel 2662758cc3dcSJack F Vogel /* reflect correct sysctl value */ 2663758cc3dcSJack F Vogel ixgbe_num_queues = queues; 2664758cc3dcSJack F Vogel 2665758cc3dcSJack F Vogel /* 2666758cc3dcSJack F Vogel ** Want one vector (RX/TX pair) per queue 2667758cc3dcSJack F Vogel ** plus an additional for Link. 2668758cc3dcSJack F Vogel */ 2669758cc3dcSJack F Vogel want = queues + 1; 2670758cc3dcSJack F Vogel if (msgs >= want) 2671758cc3dcSJack F Vogel msgs = want; 2672758cc3dcSJack F Vogel else { 2673758cc3dcSJack F Vogel device_printf(adapter->dev, 2674758cc3dcSJack F Vogel "MSIX Configuration Problem, " 2675758cc3dcSJack F Vogel "%d vectors but %d queues wanted!\n", 2676758cc3dcSJack F Vogel msgs, want); 2677758cc3dcSJack F Vogel goto msi; 2678758cc3dcSJack F Vogel } 2679758cc3dcSJack F Vogel if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { 2680758cc3dcSJack F Vogel device_printf(adapter->dev, 2681758cc3dcSJack F Vogel "Using MSIX interrupts with %d vectors\n", msgs); 2682758cc3dcSJack F Vogel adapter->num_queues = queues; 2683758cc3dcSJack F Vogel return (msgs); 2684758cc3dcSJack F Vogel } 2685758cc3dcSJack F Vogel /* 2686758cc3dcSJack F Vogel ** If MSIX alloc failed or provided us with 2687758cc3dcSJack F Vogel ** less than needed, free and fall through to MSI 2688758cc3dcSJack F Vogel */ 2689758cc3dcSJack F Vogel pci_release_msi(dev); 2690758cc3dcSJack F Vogel 2691758cc3dcSJack F Vogel msi: 2692758cc3dcSJack F Vogel if (adapter->msix_mem != NULL) { 2693758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2694758cc3dcSJack F Vogel rid, adapter->msix_mem); 2695758cc3dcSJack F Vogel adapter->msix_mem = NULL; 2696758cc3dcSJack F Vogel } 2697758cc3dcSJack F Vogel msgs = 1; 2698758cc3dcSJack F Vogel if (pci_alloc_msi(dev, &msgs) == 0) { 2699758cc3dcSJack F Vogel device_printf(adapter->dev, "Using an MSI interrupt\n"); 2700758cc3dcSJack F Vogel return (msgs); 2701758cc3dcSJack F Vogel } 2702758cc3dcSJack F Vogel device_printf(adapter->dev, "Using a Legacy interrupt\n"); 2703758cc3dcSJack F Vogel return (0); 2704758cc3dcSJack F Vogel } 2705758cc3dcSJack F Vogel 2706758cc3dcSJack F Vogel 2707758cc3dcSJack F Vogel static int 2708758cc3dcSJack F Vogel ixgbe_allocate_pci_resources(struct adapter *adapter) 2709758cc3dcSJack F Vogel { 2710758cc3dcSJack F Vogel int rid; 2711758cc3dcSJack F Vogel device_t dev = adapter->dev; 2712758cc3dcSJack F Vogel 2713758cc3dcSJack F Vogel rid = PCIR_BAR(0); 2714758cc3dcSJack F Vogel adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2715758cc3dcSJack F Vogel &rid, RF_ACTIVE); 2716758cc3dcSJack F Vogel 2717758cc3dcSJack F Vogel if (!(adapter->pci_mem)) { 2718758cc3dcSJack F Vogel device_printf(dev, "Unable to allocate bus resource: memory\n"); 2719758cc3dcSJack F Vogel return (ENXIO); 2720758cc3dcSJack F Vogel } 2721758cc3dcSJack F Vogel 2722a9ca1c79SSean Bruno /* Save bus_space values for READ/WRITE_REG macros */ 2723758cc3dcSJack F Vogel adapter->osdep.mem_bus_space_tag = 2724758cc3dcSJack F Vogel rman_get_bustag(adapter->pci_mem); 2725758cc3dcSJack F Vogel adapter->osdep.mem_bus_space_handle = 2726758cc3dcSJack F Vogel rman_get_bushandle(adapter->pci_mem); 2727a9ca1c79SSean Bruno /* Set hw values for shared code */ 2728758cc3dcSJack F Vogel adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle; 2729a9ca1c79SSean Bruno adapter->hw.back = adapter; 2730758cc3dcSJack F Vogel 2731a9ca1c79SSean Bruno /* Default to 1 queue if MSI-X setup fails */ 2732758cc3dcSJack F Vogel adapter->num_queues = 1; 2733758cc3dcSJack F Vogel 2734758cc3dcSJack F Vogel /* 2735a9ca1c79SSean Bruno ** Now setup MSI or MSI-X, should 2736758cc3dcSJack F Vogel ** return us the number of supported 2737758cc3dcSJack F Vogel ** vectors. (Will be 1 for MSI) 2738758cc3dcSJack F Vogel */ 2739758cc3dcSJack F Vogel adapter->msix = ixgbe_setup_msix(adapter); 2740758cc3dcSJack F Vogel return (0); 2741758cc3dcSJack F Vogel } 2742758cc3dcSJack F Vogel 2743758cc3dcSJack F Vogel static void 2744758cc3dcSJack F Vogel ixgbe_free_pci_resources(struct adapter * adapter) 2745758cc3dcSJack F Vogel { 2746758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2747758cc3dcSJack F Vogel device_t dev = adapter->dev; 2748758cc3dcSJack F Vogel int rid, memrid; 2749758cc3dcSJack F Vogel 2750758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) 2751758cc3dcSJack F Vogel memrid = PCIR_BAR(MSIX_82598_BAR); 2752758cc3dcSJack F Vogel else 2753758cc3dcSJack F Vogel memrid = PCIR_BAR(MSIX_82599_BAR); 2754758cc3dcSJack F Vogel 2755758cc3dcSJack F Vogel /* 2756758cc3dcSJack F Vogel ** There is a slight possibility of a failure mode 2757758cc3dcSJack F Vogel ** in attach that will result in entering this function 2758758cc3dcSJack F Vogel ** before interrupt resources have been initialized, and 2759758cc3dcSJack F Vogel ** in that case we do not want to execute the loops below 2760758cc3dcSJack F Vogel ** We can detect this reliably by the state of the adapter 2761758cc3dcSJack F Vogel ** res pointer. 2762758cc3dcSJack F Vogel */ 2763758cc3dcSJack F Vogel if (adapter->res == NULL) 2764758cc3dcSJack F Vogel goto mem; 2765758cc3dcSJack F Vogel 2766758cc3dcSJack F Vogel /* 2767758cc3dcSJack F Vogel ** Release all msix queue resources: 2768758cc3dcSJack F Vogel */ 2769758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 2770758cc3dcSJack F Vogel rid = que->msix + 1; 2771758cc3dcSJack F Vogel if (que->tag != NULL) { 2772758cc3dcSJack F Vogel bus_teardown_intr(dev, que->res, que->tag); 2773758cc3dcSJack F Vogel que->tag = NULL; 2774758cc3dcSJack F Vogel } 2775758cc3dcSJack F Vogel if (que->res != NULL) 2776758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2777758cc3dcSJack F Vogel } 2778758cc3dcSJack F Vogel 2779758cc3dcSJack F Vogel 2780758cc3dcSJack F Vogel /* Clean the Legacy or Link interrupt last */ 2781758cc3dcSJack F Vogel if (adapter->vector) /* we are doing MSIX */ 2782758cc3dcSJack F Vogel rid = adapter->vector + 1; 2783758cc3dcSJack F Vogel else 2784758cc3dcSJack F Vogel (adapter->msix != 0) ? (rid = 1):(rid = 0); 2785758cc3dcSJack F Vogel 2786758cc3dcSJack F Vogel if (adapter->tag != NULL) { 2787758cc3dcSJack F Vogel bus_teardown_intr(dev, adapter->res, adapter->tag); 2788758cc3dcSJack F Vogel adapter->tag = NULL; 2789758cc3dcSJack F Vogel } 2790758cc3dcSJack F Vogel if (adapter->res != NULL) 2791758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); 2792758cc3dcSJack F Vogel 2793758cc3dcSJack F Vogel mem: 2794758cc3dcSJack F Vogel if (adapter->msix) 2795758cc3dcSJack F Vogel pci_release_msi(dev); 2796758cc3dcSJack F Vogel 2797758cc3dcSJack F Vogel if (adapter->msix_mem != NULL) 2798758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2799758cc3dcSJack F Vogel memrid, adapter->msix_mem); 2800758cc3dcSJack F Vogel 2801758cc3dcSJack F Vogel if (adapter->pci_mem != NULL) 2802758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2803758cc3dcSJack F Vogel PCIR_BAR(0), adapter->pci_mem); 2804758cc3dcSJack F Vogel 2805758cc3dcSJack F Vogel return; 2806758cc3dcSJack F Vogel } 2807758cc3dcSJack F Vogel 2808758cc3dcSJack F Vogel /********************************************************************* 2809758cc3dcSJack F Vogel * 2810758cc3dcSJack F Vogel * Setup networking device structure and register an interface. 2811758cc3dcSJack F Vogel * 2812758cc3dcSJack F Vogel **********************************************************************/ 2813758cc3dcSJack F Vogel static int 2814758cc3dcSJack F Vogel ixgbe_setup_interface(device_t dev, struct adapter *adapter) 2815758cc3dcSJack F Vogel { 2816758cc3dcSJack F Vogel struct ifnet *ifp; 2817758cc3dcSJack F Vogel 2818758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_setup_interface: begin"); 2819758cc3dcSJack F Vogel 2820758cc3dcSJack F Vogel ifp = adapter->ifp = if_alloc(IFT_ETHER); 2821758cc3dcSJack F Vogel if (ifp == NULL) { 2822758cc3dcSJack F Vogel device_printf(dev, "can not allocate ifnet structure\n"); 2823758cc3dcSJack F Vogel return (-1); 2824758cc3dcSJack F Vogel } 2825758cc3dcSJack F Vogel if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2826758cc3dcSJack F Vogel ifp->if_baudrate = IF_Gbps(10); 2827758cc3dcSJack F Vogel ifp->if_init = ixgbe_init; 2828758cc3dcSJack F Vogel ifp->if_softc = adapter; 2829758cc3dcSJack F Vogel ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2830758cc3dcSJack F Vogel ifp->if_ioctl = ixgbe_ioctl; 2831758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 2832758cc3dcSJack F Vogel if_setgetcounterfn(ifp, ixgbe_get_counter); 2833758cc3dcSJack F Vogel #endif 28346f37f232SEric Joyner #if __FreeBSD_version >= 1100045 28356f37f232SEric Joyner /* TSO parameters */ 28366f37f232SEric Joyner ifp->if_hw_tsomax = 65518; 28376f37f232SEric Joyner ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER; 28386f37f232SEric Joyner ifp->if_hw_tsomaxsegsize = 2048; 28396f37f232SEric Joyner #endif 2840758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2841758cc3dcSJack F Vogel ifp->if_transmit = ixgbe_mq_start; 2842758cc3dcSJack F Vogel ifp->if_qflush = ixgbe_qflush; 2843758cc3dcSJack F Vogel #else 2844758cc3dcSJack F Vogel ifp->if_start = ixgbe_start; 2845758cc3dcSJack F Vogel IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); 2846758cc3dcSJack F Vogel ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; 2847758cc3dcSJack F Vogel IFQ_SET_READY(&ifp->if_snd); 2848758cc3dcSJack F Vogel #endif 2849758cc3dcSJack F Vogel 2850758cc3dcSJack F Vogel ether_ifattach(ifp, adapter->hw.mac.addr); 2851758cc3dcSJack F Vogel 2852758cc3dcSJack F Vogel adapter->max_frame_size = 2853758cc3dcSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 2854758cc3dcSJack F Vogel 2855758cc3dcSJack F Vogel /* 2856758cc3dcSJack F Vogel * Tell the upper layer(s) we support long frames. 2857758cc3dcSJack F Vogel */ 2858758cc3dcSJack F Vogel ifp->if_hdrlen = sizeof(struct ether_vlan_header); 2859758cc3dcSJack F Vogel 2860a9ca1c79SSean Bruno /* Set capability flags */ 2861a9ca1c79SSean Bruno ifp->if_capabilities |= IFCAP_RXCSUM 2862a9ca1c79SSean Bruno | IFCAP_TXCSUM 2863a9ca1c79SSean Bruno | IFCAP_RXCSUM_IPV6 2864a9ca1c79SSean Bruno | IFCAP_TXCSUM_IPV6 2865a9ca1c79SSean Bruno | IFCAP_TSO4 2866a9ca1c79SSean Bruno | IFCAP_TSO6 2867a9ca1c79SSean Bruno | IFCAP_LRO 2868a9ca1c79SSean Bruno | IFCAP_VLAN_HWTAGGING 2869758cc3dcSJack F Vogel | IFCAP_VLAN_HWTSO 2870a9ca1c79SSean Bruno | IFCAP_VLAN_HWCSUM 2871a9ca1c79SSean Bruno | IFCAP_JUMBO_MTU 2872758cc3dcSJack F Vogel | IFCAP_VLAN_MTU 2873758cc3dcSJack F Vogel | IFCAP_HWSTATS; 2874a9ca1c79SSean Bruno 2875a9ca1c79SSean Bruno /* Enable the above capabilities by default */ 2876758cc3dcSJack F Vogel ifp->if_capenable = ifp->if_capabilities; 2877758cc3dcSJack F Vogel 2878758cc3dcSJack F Vogel /* 2879758cc3dcSJack F Vogel ** Don't turn this on by default, if vlans are 2880758cc3dcSJack F Vogel ** created on another pseudo device (eg. lagg) 2881758cc3dcSJack F Vogel ** then vlan events are not passed thru, breaking 2882758cc3dcSJack F Vogel ** operation, but with HW FILTER off it works. If 2883758cc3dcSJack F Vogel ** using vlans directly on the ixgbe driver you can 2884758cc3dcSJack F Vogel ** enable this and get full hardware tag filtering. 2885758cc3dcSJack F Vogel */ 2886758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 2887758cc3dcSJack F Vogel 2888758cc3dcSJack F Vogel /* 2889758cc3dcSJack F Vogel * Specify the media types supported by this adapter and register 2890758cc3dcSJack F Vogel * callbacks to update media and link information 2891758cc3dcSJack F Vogel */ 2892758cc3dcSJack F Vogel ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change, 2893758cc3dcSJack F Vogel ixgbe_media_status); 2894758cc3dcSJack F Vogel 2895a9ca1c79SSean Bruno adapter->phy_layer = ixgbe_get_supported_physical_layer(&adapter->hw); 2896758cc3dcSJack F Vogel ixgbe_add_media_types(adapter); 2897758cc3dcSJack F Vogel 2898a9ca1c79SSean Bruno /* Set autoselect media by default */ 2899758cc3dcSJack F Vogel ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); 2900758cc3dcSJack F Vogel 2901758cc3dcSJack F Vogel return (0); 2902758cc3dcSJack F Vogel } 2903758cc3dcSJack F Vogel 2904758cc3dcSJack F Vogel static void 2905758cc3dcSJack F Vogel ixgbe_add_media_types(struct adapter *adapter) 2906758cc3dcSJack F Vogel { 2907758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2908758cc3dcSJack F Vogel device_t dev = adapter->dev; 2909758cc3dcSJack F Vogel int layer; 2910758cc3dcSJack F Vogel 2911a9ca1c79SSean Bruno layer = adapter->phy_layer; 2912758cc3dcSJack F Vogel 2913758cc3dcSJack F Vogel /* Media types with matching FreeBSD media defines */ 2914758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) 2915758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2916758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) 2917758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); 2918758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) 2919758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2920758cc3dcSJack F Vogel 2921758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || 2922758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) 2923758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2924758cc3dcSJack F Vogel 2925a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) { 2926758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2927a9ca1c79SSean Bruno if (hw->phy.multispeed_fiber) 2928a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, NULL); 2929a9ca1c79SSean Bruno } 2930a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { 2931758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2932a9ca1c79SSean Bruno if (hw->phy.multispeed_fiber) 2933a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 2934a9ca1c79SSean Bruno } else if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) 2935a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 2936758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) 2937758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2938758cc3dcSJack F Vogel 2939a9ca1c79SSean Bruno #ifdef IFM_ETH_XTYPE 2940a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) 2941a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KR, 0, NULL); 2942a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) 2943a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); 2944a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) 2945a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_KX, 0, NULL); 2946a9ca1c79SSean Bruno #else 2947758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) { 2948758cc3dcSJack F Vogel device_printf(dev, "Media supported: 10GbaseKR\n"); 29496f37f232SEric Joyner device_printf(dev, "10GbaseKR mapped to 10GbaseSR\n"); 29506f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2951758cc3dcSJack F Vogel } 2952758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) { 2953758cc3dcSJack F Vogel device_printf(dev, "Media supported: 10GbaseKX4\n"); 29546f37f232SEric Joyner device_printf(dev, "10GbaseKX4 mapped to 10GbaseCX4\n"); 29556f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2956758cc3dcSJack F Vogel } 2957758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) { 2958758cc3dcSJack F Vogel device_printf(dev, "Media supported: 1000baseKX\n"); 29596f37f232SEric Joyner device_printf(dev, "1000baseKX mapped to 1000baseCX\n"); 29606f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_CX, 0, NULL); 2961758cc3dcSJack F Vogel } 2962a9ca1c79SSean Bruno #endif 2963a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX) 2964758cc3dcSJack F Vogel device_printf(dev, "Media supported: 1000baseBX\n"); 2965758cc3dcSJack F Vogel 2966758cc3dcSJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) { 2967758cc3dcSJack F Vogel ifmedia_add(&adapter->media, 2968758cc3dcSJack F Vogel IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 2969758cc3dcSJack F Vogel ifmedia_add(&adapter->media, 2970758cc3dcSJack F Vogel IFM_ETHER | IFM_1000_T, 0, NULL); 2971758cc3dcSJack F Vogel } 2972758cc3dcSJack F Vogel 2973758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2974758cc3dcSJack F Vogel } 2975758cc3dcSJack F Vogel 2976758cc3dcSJack F Vogel static void 2977758cc3dcSJack F Vogel ixgbe_config_link(struct adapter *adapter) 2978758cc3dcSJack F Vogel { 2979758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2980758cc3dcSJack F Vogel u32 autoneg, err = 0; 2981758cc3dcSJack F Vogel bool sfp, negotiate; 2982758cc3dcSJack F Vogel 2983758cc3dcSJack F Vogel sfp = ixgbe_is_sfp(hw); 2984758cc3dcSJack F Vogel 2985758cc3dcSJack F Vogel if (sfp) { 2986758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mod_task); 2987758cc3dcSJack F Vogel } else { 2988758cc3dcSJack F Vogel if (hw->mac.ops.check_link) 2989758cc3dcSJack F Vogel err = ixgbe_check_link(hw, &adapter->link_speed, 2990758cc3dcSJack F Vogel &adapter->link_up, FALSE); 2991758cc3dcSJack F Vogel if (err) 2992758cc3dcSJack F Vogel goto out; 2993758cc3dcSJack F Vogel autoneg = hw->phy.autoneg_advertised; 2994758cc3dcSJack F Vogel if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) 2995758cc3dcSJack F Vogel err = hw->mac.ops.get_link_capabilities(hw, 2996758cc3dcSJack F Vogel &autoneg, &negotiate); 2997758cc3dcSJack F Vogel if (err) 2998758cc3dcSJack F Vogel goto out; 2999758cc3dcSJack F Vogel if (hw->mac.ops.setup_link) 3000758cc3dcSJack F Vogel err = hw->mac.ops.setup_link(hw, 3001758cc3dcSJack F Vogel autoneg, adapter->link_up); 3002758cc3dcSJack F Vogel } 3003758cc3dcSJack F Vogel out: 3004758cc3dcSJack F Vogel return; 3005758cc3dcSJack F Vogel } 3006758cc3dcSJack F Vogel 3007758cc3dcSJack F Vogel 3008758cc3dcSJack F Vogel /********************************************************************* 3009758cc3dcSJack F Vogel * 3010758cc3dcSJack F Vogel * Enable transmit units. 3011758cc3dcSJack F Vogel * 3012758cc3dcSJack F Vogel **********************************************************************/ 3013758cc3dcSJack F Vogel static void 3014758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(struct adapter *adapter) 3015758cc3dcSJack F Vogel { 3016758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 3017758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3018758cc3dcSJack F Vogel 3019758cc3dcSJack F Vogel /* Setup the Base and Length of the Tx Descriptor Ring */ 3020758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, txr++) { 3021758cc3dcSJack F Vogel u64 tdba = txr->txdma.dma_paddr; 3022758cc3dcSJack F Vogel u32 txctrl = 0; 302348056c88SJack F Vogel int j = txr->me; 3024758cc3dcSJack F Vogel 302548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), 3026758cc3dcSJack F Vogel (tdba & 0x00000000ffffffffULL)); 302748056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); 302848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), 3029758cc3dcSJack F Vogel adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc)); 3030758cc3dcSJack F Vogel 3031758cc3dcSJack F Vogel /* Setup the HW Tx Head and Tail descriptor pointers */ 303248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); 303348056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); 3034758cc3dcSJack F Vogel 3035758cc3dcSJack F Vogel /* Cache the tail address */ 303648056c88SJack F Vogel txr->tail = IXGBE_TDT(j); 3037758cc3dcSJack F Vogel 3038758cc3dcSJack F Vogel /* Disable Head Writeback */ 3039a9ca1c79SSean Bruno /* 3040a9ca1c79SSean Bruno * Note: for X550 series devices, these registers are actually 3041a9ca1c79SSean Bruno * prefixed with TPH_ isntead of DCA_, but the addresses and 3042a9ca1c79SSean Bruno * fields remain the same. 3043a9ca1c79SSean Bruno */ 3044758cc3dcSJack F Vogel switch (hw->mac.type) { 3045758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 304648056c88SJack F Vogel txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); 3047758cc3dcSJack F Vogel break; 3048758cc3dcSJack F Vogel default: 304948056c88SJack F Vogel txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j)); 3050758cc3dcSJack F Vogel break; 3051758cc3dcSJack F Vogel } 3052758cc3dcSJack F Vogel txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; 3053758cc3dcSJack F Vogel switch (hw->mac.type) { 3054758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 305548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); 3056758cc3dcSJack F Vogel break; 3057758cc3dcSJack F Vogel default: 305848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl); 3059758cc3dcSJack F Vogel break; 3060758cc3dcSJack F Vogel } 3061758cc3dcSJack F Vogel 3062758cc3dcSJack F Vogel } 3063758cc3dcSJack F Vogel 3064758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 3065758cc3dcSJack F Vogel u32 dmatxctl, rttdcs; 306648056c88SJack F Vogel #ifdef PCI_IOV 306748056c88SJack F Vogel enum ixgbe_iov_mode mode = ixgbe_get_iov_mode(adapter); 306848056c88SJack F Vogel #endif 3069758cc3dcSJack F Vogel dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); 3070758cc3dcSJack F Vogel dmatxctl |= IXGBE_DMATXCTL_TE; 3071758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); 3072758cc3dcSJack F Vogel /* Disable arbiter to set MTQC */ 3073758cc3dcSJack F Vogel rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); 3074758cc3dcSJack F Vogel rttdcs |= IXGBE_RTTDCS_ARBDIS; 3075758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); 307648056c88SJack F Vogel #ifdef PCI_IOV 307748056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MTQC, ixgbe_get_mtqc(mode)); 307848056c88SJack F Vogel #else 3079758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); 308048056c88SJack F Vogel #endif 3081758cc3dcSJack F Vogel rttdcs &= ~IXGBE_RTTDCS_ARBDIS; 3082758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); 3083758cc3dcSJack F Vogel } 3084758cc3dcSJack F Vogel 3085758cc3dcSJack F Vogel return; 3086758cc3dcSJack F Vogel } 3087758cc3dcSJack F Vogel 3088758cc3dcSJack F Vogel static void 3089a9ca1c79SSean Bruno ixgbe_initialize_rss_mapping(struct adapter *adapter) 3090758cc3dcSJack F Vogel { 3091758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 309248056c88SJack F Vogel u32 reta = 0, mrqc, rss_key[10]; 309348056c88SJack F Vogel int queue_id, table_size, index_mult; 3094758cc3dcSJack F Vogel #ifdef RSS 309548056c88SJack F Vogel u32 rss_hash_config; 3096758cc3dcSJack F Vogel #endif 309748056c88SJack F Vogel #ifdef PCI_IOV 309848056c88SJack F Vogel enum ixgbe_iov_mode mode; 309948056c88SJack F Vogel #endif 3100758cc3dcSJack F Vogel 3101758cc3dcSJack F Vogel #ifdef RSS 3102758cc3dcSJack F Vogel /* Fetch the configured RSS key */ 3103758cc3dcSJack F Vogel rss_getkey((uint8_t *) &rss_key); 3104758cc3dcSJack F Vogel #else 3105758cc3dcSJack F Vogel /* set up random bits */ 3106758cc3dcSJack F Vogel arc4rand(&rss_key, sizeof(rss_key), 0); 3107758cc3dcSJack F Vogel #endif 3108758cc3dcSJack F Vogel 31096f37f232SEric Joyner /* Set multiplier for RETA setup and table size based on MAC */ 31106f37f232SEric Joyner index_mult = 0x1; 31116f37f232SEric Joyner table_size = 128; 31126f37f232SEric Joyner switch (adapter->hw.mac.type) { 31136f37f232SEric Joyner case ixgbe_mac_82598EB: 31146f37f232SEric Joyner index_mult = 0x11; 31156f37f232SEric Joyner break; 31166f37f232SEric Joyner case ixgbe_mac_X550: 31176f37f232SEric Joyner case ixgbe_mac_X550EM_x: 31186f37f232SEric Joyner table_size = 512; 31196f37f232SEric Joyner break; 31206f37f232SEric Joyner default: 31216f37f232SEric Joyner break; 31226f37f232SEric Joyner } 31236f37f232SEric Joyner 3124758cc3dcSJack F Vogel /* Set up the redirection table */ 312548056c88SJack F Vogel for (int i = 0, j = 0; i < table_size; i++, j++) { 3126758cc3dcSJack F Vogel if (j == adapter->num_queues) j = 0; 3127758cc3dcSJack F Vogel #ifdef RSS 3128758cc3dcSJack F Vogel /* 3129758cc3dcSJack F Vogel * Fetch the RSS bucket id for the given indirection entry. 3130758cc3dcSJack F Vogel * Cap it at the number of configured buckets (which is 3131758cc3dcSJack F Vogel * num_queues.) 3132758cc3dcSJack F Vogel */ 3133758cc3dcSJack F Vogel queue_id = rss_get_indirection_to_bucket(i); 3134758cc3dcSJack F Vogel queue_id = queue_id % adapter->num_queues; 3135758cc3dcSJack F Vogel #else 31366f37f232SEric Joyner queue_id = (j * index_mult); 3137758cc3dcSJack F Vogel #endif 3138758cc3dcSJack F Vogel /* 3139758cc3dcSJack F Vogel * The low 8 bits are for hash value (n+0); 3140758cc3dcSJack F Vogel * The next 8 bits are for hash value (n+1), etc. 3141758cc3dcSJack F Vogel */ 3142758cc3dcSJack F Vogel reta = reta >> 8; 3143758cc3dcSJack F Vogel reta = reta | ( ((uint32_t) queue_id) << 24); 3144758cc3dcSJack F Vogel if ((i & 3) == 3) { 31456f37f232SEric Joyner if (i < 128) 3146758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); 31476f37f232SEric Joyner else 31486f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), reta); 3149758cc3dcSJack F Vogel reta = 0; 3150758cc3dcSJack F Vogel } 3151758cc3dcSJack F Vogel } 3152758cc3dcSJack F Vogel 3153758cc3dcSJack F Vogel /* Now fill our hash function seeds */ 3154758cc3dcSJack F Vogel for (int i = 0; i < 10; i++) 3155758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); 3156758cc3dcSJack F Vogel 3157758cc3dcSJack F Vogel /* Perform hash on these packet types */ 3158758cc3dcSJack F Vogel #ifdef RSS 3159758cc3dcSJack F Vogel mrqc = IXGBE_MRQC_RSSEN; 3160758cc3dcSJack F Vogel rss_hash_config = rss_gethashconfig(); 3161758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 3162758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; 3163758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 3164758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; 3165758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 3166758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; 3167758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 3168758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; 3169758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 3170758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX; 3171758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) 3172758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP; 3173758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 3174758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; 3175758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) 3176758cc3dcSJack F Vogel device_printf(adapter->dev, 3177758cc3dcSJack F Vogel "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, " 3178758cc3dcSJack F Vogel "but not supported\n", __func__); 3179758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 3180758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; 3181758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) 3182758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 3183758cc3dcSJack F Vogel #else 3184758cc3dcSJack F Vogel /* 3185758cc3dcSJack F Vogel * Disable UDP - IP fragments aren't currently being handled 3186758cc3dcSJack F Vogel * and so we end up with a mix of 2-tuple and 4-tuple 3187758cc3dcSJack F Vogel * traffic. 3188758cc3dcSJack F Vogel */ 3189758cc3dcSJack F Vogel mrqc = IXGBE_MRQC_RSSEN 3190758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4 3191758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4_TCP 3192758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP 3193758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX 3194758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6 3195758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_TCP 3196758cc3dcSJack F Vogel ; 3197758cc3dcSJack F Vogel #endif /* RSS */ 319848056c88SJack F Vogel #ifdef PCI_IOV 319948056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 320048056c88SJack F Vogel mrqc |= ixgbe_get_mrqc(mode); 320148056c88SJack F Vogel #endif 3202758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 3203758cc3dcSJack F Vogel } 3204758cc3dcSJack F Vogel 3205758cc3dcSJack F Vogel 3206758cc3dcSJack F Vogel /********************************************************************* 3207758cc3dcSJack F Vogel * 3208758cc3dcSJack F Vogel * Setup receive registers and features. 3209758cc3dcSJack F Vogel * 3210758cc3dcSJack F Vogel **********************************************************************/ 3211758cc3dcSJack F Vogel #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 3212758cc3dcSJack F Vogel 3213758cc3dcSJack F Vogel #define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1) 3214758cc3dcSJack F Vogel 3215758cc3dcSJack F Vogel static void 3216758cc3dcSJack F Vogel ixgbe_initialize_receive_units(struct adapter *adapter) 3217758cc3dcSJack F Vogel { 3218758cc3dcSJack F Vogel struct rx_ring *rxr = adapter->rx_rings; 3219758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3220758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3221758cc3dcSJack F Vogel u32 bufsz, fctrl, srrctl, rxcsum; 3222758cc3dcSJack F Vogel u32 hlreg; 3223758cc3dcSJack F Vogel 3224758cc3dcSJack F Vogel /* 3225758cc3dcSJack F Vogel * Make sure receives are disabled while 3226758cc3dcSJack F Vogel * setting up the descriptor ring 3227758cc3dcSJack F Vogel */ 3228758cc3dcSJack F Vogel ixgbe_disable_rx(hw); 3229758cc3dcSJack F Vogel 3230758cc3dcSJack F Vogel /* Enable broadcasts */ 3231758cc3dcSJack F Vogel fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); 3232758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_BAM; 32336f37f232SEric Joyner if (adapter->hw.mac.type == ixgbe_mac_82598EB) { 3234758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_DPF; 3235758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_PMCF; 32366f37f232SEric Joyner } 3237758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); 3238758cc3dcSJack F Vogel 3239758cc3dcSJack F Vogel /* Set for Jumbo Frames? */ 3240758cc3dcSJack F Vogel hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); 3241758cc3dcSJack F Vogel if (ifp->if_mtu > ETHERMTU) 3242758cc3dcSJack F Vogel hlreg |= IXGBE_HLREG0_JUMBOEN; 3243758cc3dcSJack F Vogel else 3244758cc3dcSJack F Vogel hlreg &= ~IXGBE_HLREG0_JUMBOEN; 3245758cc3dcSJack F Vogel #ifdef DEV_NETMAP 3246758cc3dcSJack F Vogel /* crcstrip is conditional in netmap (in RDRXCTL too ?) */ 3247758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip) 3248758cc3dcSJack F Vogel hlreg &= ~IXGBE_HLREG0_RXCRCSTRP; 3249758cc3dcSJack F Vogel else 3250758cc3dcSJack F Vogel hlreg |= IXGBE_HLREG0_RXCRCSTRP; 3251758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 3252758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); 3253758cc3dcSJack F Vogel 3254758cc3dcSJack F Vogel bufsz = (adapter->rx_mbuf_sz + 3255758cc3dcSJack F Vogel BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; 3256758cc3dcSJack F Vogel 3257758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, rxr++) { 3258758cc3dcSJack F Vogel u64 rdba = rxr->rxdma.dma_paddr; 325948056c88SJack F Vogel int j = rxr->me; 3260758cc3dcSJack F Vogel 3261758cc3dcSJack F Vogel /* Setup the Base and Length of the Rx Descriptor Ring */ 326248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), 3263758cc3dcSJack F Vogel (rdba & 0x00000000ffffffffULL)); 326448056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32)); 326548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), 3266758cc3dcSJack F Vogel adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); 3267758cc3dcSJack F Vogel 3268758cc3dcSJack F Vogel /* Set up the SRRCTL register */ 326948056c88SJack F Vogel srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(j)); 3270758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; 3271758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; 3272758cc3dcSJack F Vogel srrctl |= bufsz; 3273758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; 3274758cc3dcSJack F Vogel 3275758cc3dcSJack F Vogel /* 3276758cc3dcSJack F Vogel * Set DROP_EN iff we have no flow control and >1 queue. 3277758cc3dcSJack F Vogel * Note that srrctl was cleared shortly before during reset, 3278758cc3dcSJack F Vogel * so we do not need to clear the bit, but do it just in case 3279758cc3dcSJack F Vogel * this code is moved elsewhere. 3280758cc3dcSJack F Vogel */ 328130126537SJack F Vogel if (adapter->num_queues > 1 && 328230126537SJack F Vogel adapter->hw.fc.requested_mode == ixgbe_fc_none) { 3283758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DROP_EN; 328430126537SJack F Vogel } else { 3285758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_DROP_EN; 328630126537SJack F Vogel } 3287758cc3dcSJack F Vogel 328848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(j), srrctl); 3289758cc3dcSJack F Vogel 3290758cc3dcSJack F Vogel /* Setup the HW Rx Head and Tail Descriptor Pointers */ 329148056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0); 329248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0); 3293758cc3dcSJack F Vogel 3294758cc3dcSJack F Vogel /* Set the driver rx tail address */ 3295758cc3dcSJack F Vogel rxr->tail = IXGBE_RDT(rxr->me); 3296758cc3dcSJack F Vogel } 3297758cc3dcSJack F Vogel 3298758cc3dcSJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82598EB) { 3299758cc3dcSJack F Vogel u32 psrtype = IXGBE_PSRTYPE_TCPHDR | 3300758cc3dcSJack F Vogel IXGBE_PSRTYPE_UDPHDR | 3301758cc3dcSJack F Vogel IXGBE_PSRTYPE_IPV4HDR | 3302758cc3dcSJack F Vogel IXGBE_PSRTYPE_IPV6HDR; 3303758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); 3304758cc3dcSJack F Vogel } 3305758cc3dcSJack F Vogel 3306758cc3dcSJack F Vogel rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 3307758cc3dcSJack F Vogel 3308a9ca1c79SSean Bruno ixgbe_initialize_rss_mapping(adapter); 3309758cc3dcSJack F Vogel 3310758cc3dcSJack F Vogel if (adapter->num_queues > 1) { 3311758cc3dcSJack F Vogel /* RSS and RX IPP Checksum are mutually exclusive */ 3312758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_PCSD; 3313758cc3dcSJack F Vogel } 3314758cc3dcSJack F Vogel 3315758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_RXCSUM) 3316758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_PCSD; 3317758cc3dcSJack F Vogel 3318a9ca1c79SSean Bruno /* This is useful for calculating UDP/IP fragment checksums */ 3319758cc3dcSJack F Vogel if (!(rxcsum & IXGBE_RXCSUM_PCSD)) 3320758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_IPPCSE; 3321758cc3dcSJack F Vogel 3322758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); 3323758cc3dcSJack F Vogel 3324758cc3dcSJack F Vogel return; 3325758cc3dcSJack F Vogel } 3326758cc3dcSJack F Vogel 3327758cc3dcSJack F Vogel 3328758cc3dcSJack F Vogel /* 3329758cc3dcSJack F Vogel ** This routine is run via an vlan config EVENT, 3330758cc3dcSJack F Vogel ** it enables us to use the HW Filter table since 3331758cc3dcSJack F Vogel ** we can get the vlan id. This just creates the 3332758cc3dcSJack F Vogel ** entry in the soft version of the VFTA, init will 3333758cc3dcSJack F Vogel ** repopulate the real table. 3334758cc3dcSJack F Vogel */ 3335758cc3dcSJack F Vogel static void 3336758cc3dcSJack F Vogel ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3337758cc3dcSJack F Vogel { 3338758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 3339758cc3dcSJack F Vogel u16 index, bit; 3340758cc3dcSJack F Vogel 3341758cc3dcSJack F Vogel if (ifp->if_softc != arg) /* Not our event */ 3342758cc3dcSJack F Vogel return; 3343758cc3dcSJack F Vogel 3344758cc3dcSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3345758cc3dcSJack F Vogel return; 3346758cc3dcSJack F Vogel 3347758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 3348758cc3dcSJack F Vogel index = (vtag >> 5) & 0x7F; 3349758cc3dcSJack F Vogel bit = vtag & 0x1F; 3350758cc3dcSJack F Vogel adapter->shadow_vfta[index] |= (1 << bit); 3351758cc3dcSJack F Vogel ++adapter->num_vlans; 3352758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 3353758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 3354758cc3dcSJack F Vogel } 3355758cc3dcSJack F Vogel 3356758cc3dcSJack F Vogel /* 3357758cc3dcSJack F Vogel ** This routine is run via an vlan 3358758cc3dcSJack F Vogel ** unconfig EVENT, remove our entry 3359758cc3dcSJack F Vogel ** in the soft vfta. 3360758cc3dcSJack F Vogel */ 3361758cc3dcSJack F Vogel static void 3362758cc3dcSJack F Vogel ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3363758cc3dcSJack F Vogel { 3364758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 3365758cc3dcSJack F Vogel u16 index, bit; 3366758cc3dcSJack F Vogel 3367758cc3dcSJack F Vogel if (ifp->if_softc != arg) 3368758cc3dcSJack F Vogel return; 3369758cc3dcSJack F Vogel 3370758cc3dcSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3371758cc3dcSJack F Vogel return; 3372758cc3dcSJack F Vogel 3373758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 3374758cc3dcSJack F Vogel index = (vtag >> 5) & 0x7F; 3375758cc3dcSJack F Vogel bit = vtag & 0x1F; 3376758cc3dcSJack F Vogel adapter->shadow_vfta[index] &= ~(1 << bit); 3377758cc3dcSJack F Vogel --adapter->num_vlans; 3378758cc3dcSJack F Vogel /* Re-init to load the changes */ 3379758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 3380758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 3381758cc3dcSJack F Vogel } 3382758cc3dcSJack F Vogel 3383758cc3dcSJack F Vogel static void 3384758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(struct adapter *adapter) 3385758cc3dcSJack F Vogel { 3386758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3387758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3388758cc3dcSJack F Vogel struct rx_ring *rxr; 3389758cc3dcSJack F Vogel u32 ctrl; 3390758cc3dcSJack F Vogel 3391758cc3dcSJack F Vogel 3392758cc3dcSJack F Vogel /* 3393758cc3dcSJack F Vogel ** We get here thru init_locked, meaning 3394758cc3dcSJack F Vogel ** a soft reset, this has already cleared 3395758cc3dcSJack F Vogel ** the VFTA and other state, so if there 3396758cc3dcSJack F Vogel ** have been no vlan's registered do nothing. 3397758cc3dcSJack F Vogel */ 3398758cc3dcSJack F Vogel if (adapter->num_vlans == 0) 3399758cc3dcSJack F Vogel return; 3400758cc3dcSJack F Vogel 3401758cc3dcSJack F Vogel /* Setup the queues for vlans */ 3402758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 3403758cc3dcSJack F Vogel rxr = &adapter->rx_rings[i]; 3404758cc3dcSJack F Vogel /* On 82599 the VLAN enable is per/queue in RXDCTL */ 3405758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 340648056c88SJack F Vogel ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); 3407758cc3dcSJack F Vogel ctrl |= IXGBE_RXDCTL_VME; 340848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl); 3409758cc3dcSJack F Vogel } 3410758cc3dcSJack F Vogel rxr->vtag_strip = TRUE; 3411758cc3dcSJack F Vogel } 3412758cc3dcSJack F Vogel 3413758cc3dcSJack F Vogel if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0) 3414758cc3dcSJack F Vogel return; 3415758cc3dcSJack F Vogel /* 3416758cc3dcSJack F Vogel ** A soft reset zero's out the VFTA, so 3417758cc3dcSJack F Vogel ** we need to repopulate it now. 3418758cc3dcSJack F Vogel */ 3419758cc3dcSJack F Vogel for (int i = 0; i < IXGBE_VFTA_SIZE; i++) 3420758cc3dcSJack F Vogel if (adapter->shadow_vfta[i] != 0) 3421758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), 3422758cc3dcSJack F Vogel adapter->shadow_vfta[i]); 3423758cc3dcSJack F Vogel 3424758cc3dcSJack F Vogel ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); 3425758cc3dcSJack F Vogel /* Enable the Filter Table if enabled */ 3426758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) { 3427758cc3dcSJack F Vogel ctrl &= ~IXGBE_VLNCTRL_CFIEN; 3428758cc3dcSJack F Vogel ctrl |= IXGBE_VLNCTRL_VFE; 3429758cc3dcSJack F Vogel } 3430758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 3431758cc3dcSJack F Vogel ctrl |= IXGBE_VLNCTRL_VME; 3432758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); 3433758cc3dcSJack F Vogel } 3434758cc3dcSJack F Vogel 3435758cc3dcSJack F Vogel static void 3436758cc3dcSJack F Vogel ixgbe_enable_intr(struct adapter *adapter) 3437758cc3dcSJack F Vogel { 3438758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3439758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 3440758cc3dcSJack F Vogel u32 mask, fwsm; 3441758cc3dcSJack F Vogel 3442758cc3dcSJack F Vogel mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); 3443758cc3dcSJack F Vogel /* Enable Fan Failure detection */ 3444758cc3dcSJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) 34456f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP1; 3446758cc3dcSJack F Vogel 3447758cc3dcSJack F Vogel switch (adapter->hw.mac.type) { 3448758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 3449758cc3dcSJack F Vogel mask |= IXGBE_EIMS_ECC; 3450758cc3dcSJack F Vogel /* Temperature sensor on some adapters */ 34516f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP0; 3452758cc3dcSJack F Vogel /* SFP+ (RX_LOS_N & MOD_ABS_N) */ 34536f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP1; 34546f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP2; 3455758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3456758cc3dcSJack F Vogel mask |= IXGBE_EIMS_FLOW_DIR; 3457758cc3dcSJack F Vogel #endif 345848056c88SJack F Vogel #ifdef PCI_IOV 345948056c88SJack F Vogel mask |= IXGBE_EIMS_MAILBOX; 346048056c88SJack F Vogel #endif 3461758cc3dcSJack F Vogel break; 3462758cc3dcSJack F Vogel case ixgbe_mac_X540: 3463758cc3dcSJack F Vogel /* Detect if Thermal Sensor is enabled */ 3464758cc3dcSJack F Vogel fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); 3465758cc3dcSJack F Vogel if (fwsm & IXGBE_FWSM_TS_ENABLED) 3466758cc3dcSJack F Vogel mask |= IXGBE_EIMS_TS; 34676f37f232SEric Joyner mask |= IXGBE_EIMS_ECC; 34686f37f232SEric Joyner #ifdef IXGBE_FDIR 34696f37f232SEric Joyner mask |= IXGBE_EIMS_FLOW_DIR; 34706f37f232SEric Joyner #endif 34716f37f232SEric Joyner break; 34726f37f232SEric Joyner case ixgbe_mac_X550: 34736f37f232SEric Joyner case ixgbe_mac_X550EM_x: 34746f37f232SEric Joyner /* MAC thermal sensor is automatically enabled */ 34756f37f232SEric Joyner mask |= IXGBE_EIMS_TS; 34766f37f232SEric Joyner /* Some devices use SDP0 for important information */ 34776f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || 34786f37f232SEric Joyner hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) 3479758cc3dcSJack F Vogel mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); 3480758cc3dcSJack F Vogel mask |= IXGBE_EIMS_ECC; 3481758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3482758cc3dcSJack F Vogel mask |= IXGBE_EIMS_FLOW_DIR; 3483758cc3dcSJack F Vogel #endif 348448056c88SJack F Vogel #ifdef PCI_IOV 348548056c88SJack F Vogel mask |= IXGBE_EIMS_MAILBOX; 348648056c88SJack F Vogel #endif 3487758cc3dcSJack F Vogel /* falls through */ 3488758cc3dcSJack F Vogel default: 3489758cc3dcSJack F Vogel break; 3490758cc3dcSJack F Vogel } 3491758cc3dcSJack F Vogel 3492758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); 3493758cc3dcSJack F Vogel 34946f37f232SEric Joyner /* With MSI-X we use auto clear */ 3495758cc3dcSJack F Vogel if (adapter->msix_mem) { 3496758cc3dcSJack F Vogel mask = IXGBE_EIMS_ENABLE_MASK; 3497758cc3dcSJack F Vogel /* Don't autoclear Link */ 3498758cc3dcSJack F Vogel mask &= ~IXGBE_EIMS_OTHER; 3499758cc3dcSJack F Vogel mask &= ~IXGBE_EIMS_LSC; 350048056c88SJack F Vogel #ifdef PCI_IOV 350148056c88SJack F Vogel mask &= ~IXGBE_EIMS_MAILBOX; 350248056c88SJack F Vogel #endif 3503758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); 3504758cc3dcSJack F Vogel } 3505758cc3dcSJack F Vogel 3506758cc3dcSJack F Vogel /* 3507758cc3dcSJack F Vogel ** Now enable all queues, this is done separately to 3508758cc3dcSJack F Vogel ** allow for handling the extended (beyond 32) MSIX 3509758cc3dcSJack F Vogel ** vectors that can be used by 82599 3510758cc3dcSJack F Vogel */ 3511758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) 3512758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 3513758cc3dcSJack F Vogel 3514758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(hw); 3515758cc3dcSJack F Vogel 3516758cc3dcSJack F Vogel return; 3517758cc3dcSJack F Vogel } 3518758cc3dcSJack F Vogel 3519758cc3dcSJack F Vogel static void 3520758cc3dcSJack F Vogel ixgbe_disable_intr(struct adapter *adapter) 3521758cc3dcSJack F Vogel { 3522758cc3dcSJack F Vogel if (adapter->msix_mem) 3523758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, 0); 3524758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) { 3525758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); 3526758cc3dcSJack F Vogel } else { 3527758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000); 3528758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0); 3529758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0); 3530758cc3dcSJack F Vogel } 3531758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(&adapter->hw); 3532758cc3dcSJack F Vogel return; 3533758cc3dcSJack F Vogel } 3534758cc3dcSJack F Vogel 3535758cc3dcSJack F Vogel /* 3536758cc3dcSJack F Vogel ** Get the width and transaction speed of 3537758cc3dcSJack F Vogel ** the slot this adapter is plugged into. 3538758cc3dcSJack F Vogel */ 3539758cc3dcSJack F Vogel static void 3540a9ca1c79SSean Bruno ixgbe_get_slot_info(struct adapter *adapter) 3541758cc3dcSJack F Vogel { 3542a9ca1c79SSean Bruno device_t dev = adapter->dev; 3543a9ca1c79SSean Bruno struct ixgbe_hw *hw = &adapter->hw; 3544758cc3dcSJack F Vogel struct ixgbe_mac_info *mac = &hw->mac; 3545758cc3dcSJack F Vogel u16 link; 3546758cc3dcSJack F Vogel u32 offset; 3547758cc3dcSJack F Vogel 3548758cc3dcSJack F Vogel /* For most devices simply call the shared code routine */ 3549758cc3dcSJack F Vogel if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) { 3550758cc3dcSJack F Vogel ixgbe_get_bus_info(hw); 3551758cc3dcSJack F Vogel /* These devices don't use PCI-E */ 35526f37f232SEric Joyner switch (hw->mac.type) { 35536f37f232SEric Joyner case ixgbe_mac_X550EM_x: 3554758cc3dcSJack F Vogel return; 35556f37f232SEric Joyner default: 3556758cc3dcSJack F Vogel goto display; 3557758cc3dcSJack F Vogel } 35586f37f232SEric Joyner } 3559758cc3dcSJack F Vogel 3560758cc3dcSJack F Vogel /* 3561758cc3dcSJack F Vogel ** For the Quad port adapter we need to parse back 3562758cc3dcSJack F Vogel ** up the PCI tree to find the speed of the expansion 3563758cc3dcSJack F Vogel ** slot into which this adapter is plugged. A bit more work. 3564758cc3dcSJack F Vogel */ 3565758cc3dcSJack F Vogel dev = device_get_parent(device_get_parent(dev)); 3566758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG 3567758cc3dcSJack F Vogel device_printf(dev, "parent pcib = %x,%x,%x\n", 3568758cc3dcSJack F Vogel pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); 3569758cc3dcSJack F Vogel #endif 3570758cc3dcSJack F Vogel dev = device_get_parent(device_get_parent(dev)); 3571758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG 3572758cc3dcSJack F Vogel device_printf(dev, "slot pcib = %x,%x,%x\n", 3573758cc3dcSJack F Vogel pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); 3574758cc3dcSJack F Vogel #endif 3575758cc3dcSJack F Vogel /* Now get the PCI Express Capabilities offset */ 3576758cc3dcSJack F Vogel pci_find_cap(dev, PCIY_EXPRESS, &offset); 3577758cc3dcSJack F Vogel /* ...and read the Link Status Register */ 3578758cc3dcSJack F Vogel link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 3579758cc3dcSJack F Vogel switch (link & IXGBE_PCI_LINK_WIDTH) { 3580758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_1: 3581758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x1; 3582758cc3dcSJack F Vogel break; 3583758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_2: 3584758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x2; 3585758cc3dcSJack F Vogel break; 3586758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_4: 3587758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x4; 3588758cc3dcSJack F Vogel break; 3589758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_8: 3590758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x8; 3591758cc3dcSJack F Vogel break; 3592758cc3dcSJack F Vogel default: 3593758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_unknown; 3594758cc3dcSJack F Vogel break; 3595758cc3dcSJack F Vogel } 3596758cc3dcSJack F Vogel 3597758cc3dcSJack F Vogel switch (link & IXGBE_PCI_LINK_SPEED) { 3598758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_2500: 3599758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_2500; 3600758cc3dcSJack F Vogel break; 3601758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_5000: 3602758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_5000; 3603758cc3dcSJack F Vogel break; 3604758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_8000: 3605758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_8000; 3606758cc3dcSJack F Vogel break; 3607758cc3dcSJack F Vogel default: 3608758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_unknown; 3609758cc3dcSJack F Vogel break; 3610758cc3dcSJack F Vogel } 3611758cc3dcSJack F Vogel 3612758cc3dcSJack F Vogel mac->ops.set_lan_id(hw); 3613758cc3dcSJack F Vogel 3614758cc3dcSJack F Vogel display: 3615758cc3dcSJack F Vogel device_printf(dev,"PCI Express Bus: Speed %s %s\n", 3616758cc3dcSJack F Vogel ((hw->bus.speed == ixgbe_bus_speed_8000) ? "8.0GT/s": 3617758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0GT/s": 3618758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5GT/s":"Unknown"), 3619758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" : 3620758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" : 3621758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" : 3622758cc3dcSJack F Vogel ("Unknown")); 3623758cc3dcSJack F Vogel 3624758cc3dcSJack F Vogel if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) && 3625758cc3dcSJack F Vogel ((hw->bus.width <= ixgbe_bus_width_pcie_x4) && 3626758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_2500))) { 3627758cc3dcSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 3628758cc3dcSJack F Vogel " for this card\n is not sufficient for" 3629758cc3dcSJack F Vogel " optimal performance.\n"); 3630758cc3dcSJack F Vogel device_printf(dev, "For optimal performance a x8 " 3631758cc3dcSJack F Vogel "PCIE, or x4 PCIE Gen2 slot is required.\n"); 3632758cc3dcSJack F Vogel } 3633758cc3dcSJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) && 3634758cc3dcSJack F Vogel ((hw->bus.width <= ixgbe_bus_width_pcie_x8) && 3635758cc3dcSJack F Vogel (hw->bus.speed < ixgbe_bus_speed_8000))) { 3636758cc3dcSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 3637758cc3dcSJack F Vogel " for this card\n is not sufficient for" 3638758cc3dcSJack F Vogel " optimal performance.\n"); 3639758cc3dcSJack F Vogel device_printf(dev, "For optimal performance a x8 " 3640758cc3dcSJack F Vogel "PCIE Gen3 slot is required.\n"); 3641758cc3dcSJack F Vogel } 3642758cc3dcSJack F Vogel 3643758cc3dcSJack F Vogel return; 3644758cc3dcSJack F Vogel } 3645758cc3dcSJack F Vogel 3646758cc3dcSJack F Vogel 3647758cc3dcSJack F Vogel /* 3648758cc3dcSJack F Vogel ** Setup the correct IVAR register for a particular MSIX interrupt 3649758cc3dcSJack F Vogel ** (yes this is all very magic and confusing :) 3650758cc3dcSJack F Vogel ** - entry is the register array entry 3651758cc3dcSJack F Vogel ** - vector is the MSIX vector for this queue 3652758cc3dcSJack F Vogel ** - type is RX/TX/MISC 3653758cc3dcSJack F Vogel */ 3654758cc3dcSJack F Vogel static void 3655758cc3dcSJack F Vogel ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) 3656758cc3dcSJack F Vogel { 3657758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3658758cc3dcSJack F Vogel u32 ivar, index; 3659758cc3dcSJack F Vogel 3660758cc3dcSJack F Vogel vector |= IXGBE_IVAR_ALLOC_VAL; 3661758cc3dcSJack F Vogel 3662758cc3dcSJack F Vogel switch (hw->mac.type) { 3663758cc3dcSJack F Vogel 3664758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 3665758cc3dcSJack F Vogel if (type == -1) 3666758cc3dcSJack F Vogel entry = IXGBE_IVAR_OTHER_CAUSES_INDEX; 3667758cc3dcSJack F Vogel else 3668758cc3dcSJack F Vogel entry += (type * 64); 3669758cc3dcSJack F Vogel index = (entry >> 2) & 0x1F; 3670758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 3671758cc3dcSJack F Vogel ivar &= ~(0xFF << (8 * (entry & 0x3))); 3672758cc3dcSJack F Vogel ivar |= (vector << (8 * (entry & 0x3))); 3673758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar); 3674758cc3dcSJack F Vogel break; 3675758cc3dcSJack F Vogel 3676758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 3677758cc3dcSJack F Vogel case ixgbe_mac_X540: 3678758cc3dcSJack F Vogel case ixgbe_mac_X550: 3679758cc3dcSJack F Vogel case ixgbe_mac_X550EM_x: 3680758cc3dcSJack F Vogel if (type == -1) { /* MISC IVAR */ 3681758cc3dcSJack F Vogel index = (entry & 1) * 8; 3682758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 3683758cc3dcSJack F Vogel ivar &= ~(0xFF << index); 3684758cc3dcSJack F Vogel ivar |= (vector << index); 3685758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 3686758cc3dcSJack F Vogel } else { /* RX/TX IVARS */ 3687758cc3dcSJack F Vogel index = (16 * (entry & 1)) + (8 * type); 3688758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1)); 3689758cc3dcSJack F Vogel ivar &= ~(0xFF << index); 3690758cc3dcSJack F Vogel ivar |= (vector << index); 3691758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar); 3692758cc3dcSJack F Vogel } 3693758cc3dcSJack F Vogel 3694758cc3dcSJack F Vogel default: 3695758cc3dcSJack F Vogel break; 3696758cc3dcSJack F Vogel } 3697758cc3dcSJack F Vogel } 3698758cc3dcSJack F Vogel 3699758cc3dcSJack F Vogel static void 3700758cc3dcSJack F Vogel ixgbe_configure_ivars(struct adapter *adapter) 3701758cc3dcSJack F Vogel { 3702758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 3703758cc3dcSJack F Vogel u32 newitr; 3704758cc3dcSJack F Vogel 3705758cc3dcSJack F Vogel if (ixgbe_max_interrupt_rate > 0) 3706758cc3dcSJack F Vogel newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8; 37076f37f232SEric Joyner else { 37086f37f232SEric Joyner /* 37096f37f232SEric Joyner ** Disable DMA coalescing if interrupt moderation is 37106f37f232SEric Joyner ** disabled. 37116f37f232SEric Joyner */ 37126f37f232SEric Joyner adapter->dmac = 0; 3713758cc3dcSJack F Vogel newitr = 0; 37146f37f232SEric Joyner } 3715758cc3dcSJack F Vogel 3716758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 371748056c88SJack F Vogel struct rx_ring *rxr = &adapter->rx_rings[i]; 371848056c88SJack F Vogel struct tx_ring *txr = &adapter->tx_rings[i]; 3719758cc3dcSJack F Vogel /* First the RX queue entry */ 372048056c88SJack F Vogel ixgbe_set_ivar(adapter, rxr->me, que->msix, 0); 3721758cc3dcSJack F Vogel /* ... and the TX */ 372248056c88SJack F Vogel ixgbe_set_ivar(adapter, txr->me, que->msix, 1); 3723758cc3dcSJack F Vogel /* Set an Initial EITR value */ 3724758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, 3725758cc3dcSJack F Vogel IXGBE_EITR(que->msix), newitr); 3726758cc3dcSJack F Vogel } 3727758cc3dcSJack F Vogel 3728758cc3dcSJack F Vogel /* For the Link interrupt */ 3729758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 1, adapter->vector, -1); 3730758cc3dcSJack F Vogel } 3731758cc3dcSJack F Vogel 3732758cc3dcSJack F Vogel /* 3733758cc3dcSJack F Vogel ** ixgbe_sfp_probe - called in the local timer to 3734758cc3dcSJack F Vogel ** determine if a port had optics inserted. 3735758cc3dcSJack F Vogel */ 373648056c88SJack F Vogel static bool 373748056c88SJack F Vogel ixgbe_sfp_probe(struct adapter *adapter) 3738758cc3dcSJack F Vogel { 3739758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3740758cc3dcSJack F Vogel device_t dev = adapter->dev; 3741758cc3dcSJack F Vogel bool result = FALSE; 3742758cc3dcSJack F Vogel 3743758cc3dcSJack F Vogel if ((hw->phy.type == ixgbe_phy_nl) && 3744758cc3dcSJack F Vogel (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { 3745758cc3dcSJack F Vogel s32 ret = hw->phy.ops.identify_sfp(hw); 3746758cc3dcSJack F Vogel if (ret) 3747758cc3dcSJack F Vogel goto out; 3748758cc3dcSJack F Vogel ret = hw->phy.ops.reset(hw); 3749758cc3dcSJack F Vogel if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3750758cc3dcSJack F Vogel device_printf(dev, "Unsupported SFP+ module detected!"); 3751a9ca1c79SSean Bruno device_printf(dev, "Reload driver with supported module.\n"); 3752758cc3dcSJack F Vogel adapter->sfp_probe = FALSE; 3753758cc3dcSJack F Vogel goto out; 3754758cc3dcSJack F Vogel } else 3755758cc3dcSJack F Vogel device_printf(dev, "SFP+ module detected!\n"); 3756758cc3dcSJack F Vogel /* We now have supported optics */ 3757758cc3dcSJack F Vogel adapter->sfp_probe = FALSE; 3758758cc3dcSJack F Vogel /* Set the optics type so system reports correctly */ 3759758cc3dcSJack F Vogel ixgbe_setup_optics(adapter); 3760758cc3dcSJack F Vogel result = TRUE; 3761758cc3dcSJack F Vogel } 3762758cc3dcSJack F Vogel out: 3763758cc3dcSJack F Vogel return (result); 3764758cc3dcSJack F Vogel } 3765758cc3dcSJack F Vogel 3766758cc3dcSJack F Vogel /* 3767758cc3dcSJack F Vogel ** Tasklet handler for MSIX Link interrupts 3768758cc3dcSJack F Vogel ** - do outside interrupt since it might sleep 3769758cc3dcSJack F Vogel */ 3770758cc3dcSJack F Vogel static void 3771758cc3dcSJack F Vogel ixgbe_handle_link(void *context, int pending) 3772758cc3dcSJack F Vogel { 3773758cc3dcSJack F Vogel struct adapter *adapter = context; 3774a9ca1c79SSean Bruno struct ixgbe_hw *hw = &adapter->hw; 3775758cc3dcSJack F Vogel 3776a9ca1c79SSean Bruno ixgbe_check_link(hw, 3777758cc3dcSJack F Vogel &adapter->link_speed, &adapter->link_up, 0); 3778758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 3779a9ca1c79SSean Bruno 3780a9ca1c79SSean Bruno /* Re-enable link interrupts */ 3781a9ca1c79SSean Bruno IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_LSC); 3782758cc3dcSJack F Vogel } 3783758cc3dcSJack F Vogel 3784758cc3dcSJack F Vogel /* 3785758cc3dcSJack F Vogel ** Tasklet for handling SFP module interrupts 3786758cc3dcSJack F Vogel */ 3787758cc3dcSJack F Vogel static void 3788758cc3dcSJack F Vogel ixgbe_handle_mod(void *context, int pending) 3789758cc3dcSJack F Vogel { 3790758cc3dcSJack F Vogel struct adapter *adapter = context; 3791758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 379297f9586eSSean Bruno enum ixgbe_phy_type orig_type = hw->phy.type; 3793758cc3dcSJack F Vogel device_t dev = adapter->dev; 3794758cc3dcSJack F Vogel u32 err; 3795758cc3dcSJack F Vogel 379697f9586eSSean Bruno IXGBE_CORE_LOCK(adapter); 379797f9586eSSean Bruno 379897f9586eSSean Bruno /* Check to see if the PHY type changed */ 379997f9586eSSean Bruno if (hw->phy.ops.identify) { 380097f9586eSSean Bruno hw->phy.type = ixgbe_phy_unknown; 380197f9586eSSean Bruno hw->phy.ops.identify(hw); 380297f9586eSSean Bruno } 380397f9586eSSean Bruno 380497f9586eSSean Bruno if (hw->phy.type != orig_type) { 380597f9586eSSean Bruno device_printf(dev, "Detected phy_type %d\n", hw->phy.type); 380697f9586eSSean Bruno 380797f9586eSSean Bruno if (hw->phy.type == ixgbe_phy_none) { 380897f9586eSSean Bruno hw->phy.sfp_type = ixgbe_sfp_type_unknown; 380997f9586eSSean Bruno goto out; 381097f9586eSSean Bruno } 381197f9586eSSean Bruno 381297f9586eSSean Bruno /* Try to do the initialization that was skipped before */ 381397f9586eSSean Bruno if (hw->phy.ops.init) 381497f9586eSSean Bruno hw->phy.ops.init(hw); 381597f9586eSSean Bruno if (hw->phy.ops.reset) 381697f9586eSSean Bruno hw->phy.ops.reset(hw); 381797f9586eSSean Bruno } 381897f9586eSSean Bruno 3819758cc3dcSJack F Vogel err = hw->phy.ops.identify_sfp(hw); 3820758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3821758cc3dcSJack F Vogel device_printf(dev, 3822758cc3dcSJack F Vogel "Unsupported SFP+ module type was detected.\n"); 382397f9586eSSean Bruno goto out; 3824758cc3dcSJack F Vogel } 382548056c88SJack F Vogel 3826758cc3dcSJack F Vogel err = hw->mac.ops.setup_sfp(hw); 3827758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3828758cc3dcSJack F Vogel device_printf(dev, 3829758cc3dcSJack F Vogel "Setup failure - unsupported SFP+ module type.\n"); 383097f9586eSSean Bruno goto out; 3831758cc3dcSJack F Vogel } 383297f9586eSSean Bruno if (hw->phy.multispeed_fiber) 3833758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 383497f9586eSSean Bruno out: 383597f9586eSSean Bruno /* Update media type */ 383697f9586eSSean Bruno switch (hw->mac.ops.get_media_type(hw)) { 383797f9586eSSean Bruno case ixgbe_media_type_fiber: 383897f9586eSSean Bruno adapter->optics = IFM_10G_SR; 383997f9586eSSean Bruno break; 384097f9586eSSean Bruno case ixgbe_media_type_copper: 384197f9586eSSean Bruno adapter->optics = IFM_10G_TWINAX; 384297f9586eSSean Bruno break; 384397f9586eSSean Bruno case ixgbe_media_type_cx4: 384497f9586eSSean Bruno adapter->optics = IFM_10G_CX4; 384597f9586eSSean Bruno break; 384697f9586eSSean Bruno default: 384797f9586eSSean Bruno adapter->optics = 0; 384897f9586eSSean Bruno break; 384997f9586eSSean Bruno } 385097f9586eSSean Bruno 385197f9586eSSean Bruno IXGBE_CORE_UNLOCK(adapter); 3852758cc3dcSJack F Vogel return; 3853758cc3dcSJack F Vogel } 3854758cc3dcSJack F Vogel 3855758cc3dcSJack F Vogel 3856758cc3dcSJack F Vogel /* 3857758cc3dcSJack F Vogel ** Tasklet for handling MSF (multispeed fiber) interrupts 3858758cc3dcSJack F Vogel */ 3859758cc3dcSJack F Vogel static void 3860758cc3dcSJack F Vogel ixgbe_handle_msf(void *context, int pending) 3861758cc3dcSJack F Vogel { 3862758cc3dcSJack F Vogel struct adapter *adapter = context; 3863758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3864758cc3dcSJack F Vogel u32 autoneg; 3865758cc3dcSJack F Vogel bool negotiate; 3866758cc3dcSJack F Vogel 386797f9586eSSean Bruno IXGBE_CORE_LOCK(adapter); 3868a9ca1c79SSean Bruno /* get_supported_phy_layer will call hw->phy.ops.identify_sfp() */ 3869a9ca1c79SSean Bruno adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); 3870758cc3dcSJack F Vogel 3871758cc3dcSJack F Vogel autoneg = hw->phy.autoneg_advertised; 3872758cc3dcSJack F Vogel if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) 3873758cc3dcSJack F Vogel hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate); 3874758cc3dcSJack F Vogel if (hw->mac.ops.setup_link) 3875758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, autoneg, TRUE); 3876758cc3dcSJack F Vogel 3877a9ca1c79SSean Bruno /* Adjust media types shown in ifconfig */ 3878758cc3dcSJack F Vogel ifmedia_removeall(&adapter->media); 3879758cc3dcSJack F Vogel ixgbe_add_media_types(adapter); 388097f9586eSSean Bruno IXGBE_CORE_UNLOCK(adapter); 3881758cc3dcSJack F Vogel return; 3882758cc3dcSJack F Vogel } 3883758cc3dcSJack F Vogel 38846f37f232SEric Joyner /* 38856f37f232SEric Joyner ** Tasklet for handling interrupts from an external PHY 38866f37f232SEric Joyner */ 38876f37f232SEric Joyner static void 38886f37f232SEric Joyner ixgbe_handle_phy(void *context, int pending) 38896f37f232SEric Joyner { 38906f37f232SEric Joyner struct adapter *adapter = context; 38916f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 38926f37f232SEric Joyner int error; 38936f37f232SEric Joyner 38946f37f232SEric Joyner error = hw->phy.ops.handle_lasi(hw); 38956f37f232SEric Joyner if (error == IXGBE_ERR_OVERTEMP) 38966f37f232SEric Joyner device_printf(adapter->dev, 38976f37f232SEric Joyner "CRITICAL: EXTERNAL PHY OVER TEMP!! " 38986f37f232SEric Joyner " PHY will downshift to lower power state!\n"); 38996f37f232SEric Joyner else if (error) 39006f37f232SEric Joyner device_printf(adapter->dev, 39016f37f232SEric Joyner "Error handling LASI interrupt: %d\n", 39026f37f232SEric Joyner error); 39036f37f232SEric Joyner return; 39046f37f232SEric Joyner } 39056f37f232SEric Joyner 3906758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3907758cc3dcSJack F Vogel /* 3908758cc3dcSJack F Vogel ** Tasklet for reinitializing the Flow Director filter table 3909758cc3dcSJack F Vogel */ 3910758cc3dcSJack F Vogel static void 3911758cc3dcSJack F Vogel ixgbe_reinit_fdir(void *context, int pending) 3912758cc3dcSJack F Vogel { 3913758cc3dcSJack F Vogel struct adapter *adapter = context; 3914758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3915758cc3dcSJack F Vogel 3916758cc3dcSJack F Vogel if (adapter->fdir_reinit != 1) /* Shouldn't happen */ 3917758cc3dcSJack F Vogel return; 3918758cc3dcSJack F Vogel ixgbe_reinit_fdir_tables_82599(&adapter->hw); 3919758cc3dcSJack F Vogel adapter->fdir_reinit = 0; 3920758cc3dcSJack F Vogel /* re-enable flow director interrupts */ 3921758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); 3922758cc3dcSJack F Vogel /* Restart the interface */ 3923758cc3dcSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 3924758cc3dcSJack F Vogel return; 3925758cc3dcSJack F Vogel } 3926758cc3dcSJack F Vogel #endif 3927758cc3dcSJack F Vogel 39286f37f232SEric Joyner /********************************************************************* 39296f37f232SEric Joyner * 39306f37f232SEric Joyner * Configure DMA Coalescing 39316f37f232SEric Joyner * 39326f37f232SEric Joyner **********************************************************************/ 39336f37f232SEric Joyner static void 39346f37f232SEric Joyner ixgbe_config_dmac(struct adapter *adapter) 39356f37f232SEric Joyner { 39366f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 39376f37f232SEric Joyner struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config; 39386f37f232SEric Joyner 39396f37f232SEric Joyner if (hw->mac.type < ixgbe_mac_X550 || 39406f37f232SEric Joyner !hw->mac.ops.dmac_config) 39416f37f232SEric Joyner return; 39426f37f232SEric Joyner 39436f37f232SEric Joyner if (dcfg->watchdog_timer ^ adapter->dmac || 39446f37f232SEric Joyner dcfg->link_speed ^ adapter->link_speed) { 39456f37f232SEric Joyner dcfg->watchdog_timer = adapter->dmac; 39466f37f232SEric Joyner dcfg->fcoe_en = false; 39476f37f232SEric Joyner dcfg->link_speed = adapter->link_speed; 39486f37f232SEric Joyner dcfg->num_tcs = 1; 39496f37f232SEric Joyner 39506f37f232SEric Joyner INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n", 39516f37f232SEric Joyner dcfg->watchdog_timer, dcfg->link_speed); 39526f37f232SEric Joyner 39536f37f232SEric Joyner hw->mac.ops.dmac_config(hw); 39546f37f232SEric Joyner } 39556f37f232SEric Joyner } 39566f37f232SEric Joyner 39576f37f232SEric Joyner /* 39586f37f232SEric Joyner * Checks whether the adapter's ports are capable of 39596f37f232SEric Joyner * Wake On LAN by reading the adapter's NVM. 39606f37f232SEric Joyner * 39616f37f232SEric Joyner * Sets each port's hw->wol_enabled value depending 39626f37f232SEric Joyner * on the value read here. 39636f37f232SEric Joyner */ 39646f37f232SEric Joyner static void 39656f37f232SEric Joyner ixgbe_check_wol_support(struct adapter *adapter) 39666f37f232SEric Joyner { 39676f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 39686f37f232SEric Joyner u16 dev_caps = 0; 39696f37f232SEric Joyner 39706f37f232SEric Joyner /* Find out WoL support for port */ 39716f37f232SEric Joyner adapter->wol_support = hw->wol_enabled = 0; 39726f37f232SEric Joyner ixgbe_get_device_caps(hw, &dev_caps); 39736f37f232SEric Joyner if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) || 39746f37f232SEric Joyner ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) && 39756f37f232SEric Joyner hw->bus.func == 0)) 39766f37f232SEric Joyner adapter->wol_support = hw->wol_enabled = 1; 39776f37f232SEric Joyner 39786f37f232SEric Joyner /* Save initial wake up filter configuration */ 39796f37f232SEric Joyner adapter->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC); 39806f37f232SEric Joyner 39816f37f232SEric Joyner return; 39826f37f232SEric Joyner } 39836f37f232SEric Joyner 39846f37f232SEric Joyner /* 39856f37f232SEric Joyner * Prepare the adapter/port for LPLU and/or WoL 39866f37f232SEric Joyner */ 39876f37f232SEric Joyner static int 39886f37f232SEric Joyner ixgbe_setup_low_power_mode(struct adapter *adapter) 39896f37f232SEric Joyner { 39906f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 39916f37f232SEric Joyner device_t dev = adapter->dev; 39926f37f232SEric Joyner s32 error = 0; 39936f37f232SEric Joyner 39946f37f232SEric Joyner mtx_assert(&adapter->core_mtx, MA_OWNED); 39956f37f232SEric Joyner 39961ebf555bSSteven Hartland if (!hw->wol_enabled) 39971ebf555bSSteven Hartland ixgbe_set_phy_power(hw, FALSE); 39981ebf555bSSteven Hartland 39996f37f232SEric Joyner /* Limit power management flow to X550EM baseT */ 40006f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T 40016f37f232SEric Joyner && hw->phy.ops.enter_lplu) { 40026f37f232SEric Joyner /* Turn off support for APM wakeup. (Using ACPI instead) */ 40036f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_GRC, 40046f37f232SEric Joyner IXGBE_READ_REG(hw, IXGBE_GRC) & ~(u32)2); 40056f37f232SEric Joyner 40066f37f232SEric Joyner /* 40076f37f232SEric Joyner * Clear Wake Up Status register to prevent any previous wakeup 40086f37f232SEric Joyner * events from waking us up immediately after we suspend. 40096f37f232SEric Joyner */ 40106f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); 40116f37f232SEric Joyner 40126f37f232SEric Joyner /* 40136f37f232SEric Joyner * Program the Wakeup Filter Control register with user filter 40146f37f232SEric Joyner * settings 40156f37f232SEric Joyner */ 40166f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUFC, adapter->wufc); 40176f37f232SEric Joyner 40186f37f232SEric Joyner /* Enable wakeups and power management in Wakeup Control */ 40196f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUC, 40206f37f232SEric Joyner IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN); 40216f37f232SEric Joyner 40226f37f232SEric Joyner /* X550EM baseT adapters need a special LPLU flow */ 40236f37f232SEric Joyner hw->phy.reset_disable = true; 40246f37f232SEric Joyner ixgbe_stop(adapter); 40256f37f232SEric Joyner error = hw->phy.ops.enter_lplu(hw); 40266f37f232SEric Joyner if (error) 40276f37f232SEric Joyner device_printf(dev, 40286f37f232SEric Joyner "Error entering LPLU: %d\n", error); 40296f37f232SEric Joyner hw->phy.reset_disable = false; 40306f37f232SEric Joyner } else { 40316f37f232SEric Joyner /* Just stop for other adapters */ 40326f37f232SEric Joyner ixgbe_stop(adapter); 40336f37f232SEric Joyner } 40346f37f232SEric Joyner 40356f37f232SEric Joyner return error; 40366f37f232SEric Joyner } 40376f37f232SEric Joyner 4038758cc3dcSJack F Vogel /********************************************************************** 4039758cc3dcSJack F Vogel * 4040758cc3dcSJack F Vogel * Update the board statistics counters. 4041758cc3dcSJack F Vogel * 4042758cc3dcSJack F Vogel **********************************************************************/ 4043758cc3dcSJack F Vogel static void 4044758cc3dcSJack F Vogel ixgbe_update_stats_counters(struct adapter *adapter) 4045758cc3dcSJack F Vogel { 4046758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 4047758cc3dcSJack F Vogel u32 missed_rx = 0, bprc, lxon, lxoff, total; 4048758cc3dcSJack F Vogel u64 total_missed_rx = 0; 4049758cc3dcSJack F Vogel 4050758cc3dcSJack F Vogel adapter->stats.pf.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); 4051758cc3dcSJack F Vogel adapter->stats.pf.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC); 4052758cc3dcSJack F Vogel adapter->stats.pf.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC); 4053758cc3dcSJack F Vogel adapter->stats.pf.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC); 4054758cc3dcSJack F Vogel 4055758cc3dcSJack F Vogel for (int i = 0; i < 16; i++) { 4056758cc3dcSJack F Vogel adapter->stats.pf.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); 4057758cc3dcSJack F Vogel adapter->stats.pf.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); 4058758cc3dcSJack F Vogel adapter->stats.pf.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); 4059758cc3dcSJack F Vogel } 4060758cc3dcSJack F Vogel adapter->stats.pf.mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC); 4061758cc3dcSJack F Vogel adapter->stats.pf.mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC); 4062758cc3dcSJack F Vogel adapter->stats.pf.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); 4063758cc3dcSJack F Vogel 4064758cc3dcSJack F Vogel /* Hardware workaround, gprc counts missed packets */ 4065758cc3dcSJack F Vogel adapter->stats.pf.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); 4066758cc3dcSJack F Vogel adapter->stats.pf.gprc -= missed_rx; 4067758cc3dcSJack F Vogel 4068758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 4069758cc3dcSJack F Vogel adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) + 4070758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); 4071758cc3dcSJack F Vogel adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) + 4072758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); 4073758cc3dcSJack F Vogel adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORL) + 4074758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); 4075758cc3dcSJack F Vogel adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); 4076758cc3dcSJack F Vogel adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); 4077758cc3dcSJack F Vogel } else { 4078758cc3dcSJack F Vogel adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); 4079758cc3dcSJack F Vogel adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); 4080758cc3dcSJack F Vogel /* 82598 only has a counter in the high register */ 4081758cc3dcSJack F Vogel adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); 4082758cc3dcSJack F Vogel adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); 4083758cc3dcSJack F Vogel adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORH); 4084758cc3dcSJack F Vogel } 4085758cc3dcSJack F Vogel 4086758cc3dcSJack F Vogel /* 4087758cc3dcSJack F Vogel * Workaround: mprc hardware is incorrectly counting 4088758cc3dcSJack F Vogel * broadcasts, so for now we subtract those. 4089758cc3dcSJack F Vogel */ 4090758cc3dcSJack F Vogel bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); 4091758cc3dcSJack F Vogel adapter->stats.pf.bprc += bprc; 4092758cc3dcSJack F Vogel adapter->stats.pf.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); 4093758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 4094758cc3dcSJack F Vogel adapter->stats.pf.mprc -= bprc; 4095758cc3dcSJack F Vogel 4096758cc3dcSJack F Vogel adapter->stats.pf.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); 4097758cc3dcSJack F Vogel adapter->stats.pf.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); 4098758cc3dcSJack F Vogel adapter->stats.pf.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); 4099758cc3dcSJack F Vogel adapter->stats.pf.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); 4100758cc3dcSJack F Vogel adapter->stats.pf.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); 4101758cc3dcSJack F Vogel adapter->stats.pf.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); 4102758cc3dcSJack F Vogel 4103758cc3dcSJack F Vogel lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); 4104758cc3dcSJack F Vogel adapter->stats.pf.lxontxc += lxon; 4105758cc3dcSJack F Vogel lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); 4106758cc3dcSJack F Vogel adapter->stats.pf.lxofftxc += lxoff; 4107758cc3dcSJack F Vogel total = lxon + lxoff; 4108758cc3dcSJack F Vogel 4109758cc3dcSJack F Vogel adapter->stats.pf.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); 4110758cc3dcSJack F Vogel adapter->stats.pf.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); 4111758cc3dcSJack F Vogel adapter->stats.pf.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); 4112758cc3dcSJack F Vogel adapter->stats.pf.gptc -= total; 4113758cc3dcSJack F Vogel adapter->stats.pf.mptc -= total; 4114758cc3dcSJack F Vogel adapter->stats.pf.ptc64 -= total; 4115758cc3dcSJack F Vogel adapter->stats.pf.gotc -= total * ETHER_MIN_LEN; 4116758cc3dcSJack F Vogel 4117758cc3dcSJack F Vogel adapter->stats.pf.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); 4118758cc3dcSJack F Vogel adapter->stats.pf.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); 4119758cc3dcSJack F Vogel adapter->stats.pf.roc += IXGBE_READ_REG(hw, IXGBE_ROC); 4120758cc3dcSJack F Vogel adapter->stats.pf.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); 4121758cc3dcSJack F Vogel adapter->stats.pf.mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC); 4122758cc3dcSJack F Vogel adapter->stats.pf.mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC); 4123758cc3dcSJack F Vogel adapter->stats.pf.mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC); 4124758cc3dcSJack F Vogel adapter->stats.pf.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); 4125758cc3dcSJack F Vogel adapter->stats.pf.tpt += IXGBE_READ_REG(hw, IXGBE_TPT); 4126758cc3dcSJack F Vogel adapter->stats.pf.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); 4127758cc3dcSJack F Vogel adapter->stats.pf.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); 4128758cc3dcSJack F Vogel adapter->stats.pf.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); 4129758cc3dcSJack F Vogel adapter->stats.pf.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); 4130758cc3dcSJack F Vogel adapter->stats.pf.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); 4131758cc3dcSJack F Vogel adapter->stats.pf.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); 4132758cc3dcSJack F Vogel adapter->stats.pf.xec += IXGBE_READ_REG(hw, IXGBE_XEC); 4133758cc3dcSJack F Vogel adapter->stats.pf.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); 4134758cc3dcSJack F Vogel adapter->stats.pf.fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST); 4135758cc3dcSJack F Vogel /* Only read FCOE on 82599 */ 4136758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 4137758cc3dcSJack F Vogel adapter->stats.pf.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); 4138758cc3dcSJack F Vogel adapter->stats.pf.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); 4139758cc3dcSJack F Vogel adapter->stats.pf.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); 4140758cc3dcSJack F Vogel adapter->stats.pf.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); 4141758cc3dcSJack F Vogel adapter->stats.pf.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); 4142758cc3dcSJack F Vogel } 4143758cc3dcSJack F Vogel 4144758cc3dcSJack F Vogel /* Fill out the OS statistics structure */ 4145758cc3dcSJack F Vogel IXGBE_SET_IPACKETS(adapter, adapter->stats.pf.gprc); 4146758cc3dcSJack F Vogel IXGBE_SET_OPACKETS(adapter, adapter->stats.pf.gptc); 4147758cc3dcSJack F Vogel IXGBE_SET_IBYTES(adapter, adapter->stats.pf.gorc); 4148758cc3dcSJack F Vogel IXGBE_SET_OBYTES(adapter, adapter->stats.pf.gotc); 4149758cc3dcSJack F Vogel IXGBE_SET_IMCASTS(adapter, adapter->stats.pf.mprc); 4150758cc3dcSJack F Vogel IXGBE_SET_OMCASTS(adapter, adapter->stats.pf.mptc); 4151758cc3dcSJack F Vogel IXGBE_SET_COLLISIONS(adapter, 0); 4152758cc3dcSJack F Vogel IXGBE_SET_IQDROPS(adapter, total_missed_rx); 4153758cc3dcSJack F Vogel IXGBE_SET_IERRORS(adapter, adapter->stats.pf.crcerrs 4154758cc3dcSJack F Vogel + adapter->stats.pf.rlec); 4155758cc3dcSJack F Vogel } 4156758cc3dcSJack F Vogel 4157758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 4158758cc3dcSJack F Vogel static uint64_t 4159758cc3dcSJack F Vogel ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt) 4160758cc3dcSJack F Vogel { 4161758cc3dcSJack F Vogel struct adapter *adapter; 4162625d12c6SJohn Baldwin struct tx_ring *txr; 4163625d12c6SJohn Baldwin uint64_t rv; 4164758cc3dcSJack F Vogel 4165758cc3dcSJack F Vogel adapter = if_getsoftc(ifp); 4166758cc3dcSJack F Vogel 4167758cc3dcSJack F Vogel switch (cnt) { 4168758cc3dcSJack F Vogel case IFCOUNTER_IPACKETS: 4169758cc3dcSJack F Vogel return (adapter->ipackets); 4170758cc3dcSJack F Vogel case IFCOUNTER_OPACKETS: 4171758cc3dcSJack F Vogel return (adapter->opackets); 4172758cc3dcSJack F Vogel case IFCOUNTER_IBYTES: 4173758cc3dcSJack F Vogel return (adapter->ibytes); 4174758cc3dcSJack F Vogel case IFCOUNTER_OBYTES: 4175758cc3dcSJack F Vogel return (adapter->obytes); 4176758cc3dcSJack F Vogel case IFCOUNTER_IMCASTS: 4177758cc3dcSJack F Vogel return (adapter->imcasts); 4178758cc3dcSJack F Vogel case IFCOUNTER_OMCASTS: 4179758cc3dcSJack F Vogel return (adapter->omcasts); 4180758cc3dcSJack F Vogel case IFCOUNTER_COLLISIONS: 4181758cc3dcSJack F Vogel return (0); 4182758cc3dcSJack F Vogel case IFCOUNTER_IQDROPS: 4183758cc3dcSJack F Vogel return (adapter->iqdrops); 4184625d12c6SJohn Baldwin case IFCOUNTER_OQDROPS: 4185625d12c6SJohn Baldwin rv = 0; 4186625d12c6SJohn Baldwin txr = adapter->tx_rings; 4187625d12c6SJohn Baldwin for (int i = 0; i < adapter->num_queues; i++, txr++) 4188625d12c6SJohn Baldwin rv += txr->br->br_drops; 4189625d12c6SJohn Baldwin return (rv); 4190758cc3dcSJack F Vogel case IFCOUNTER_IERRORS: 4191758cc3dcSJack F Vogel return (adapter->ierrors); 4192758cc3dcSJack F Vogel default: 4193758cc3dcSJack F Vogel return (if_get_counter_default(ifp, cnt)); 4194758cc3dcSJack F Vogel } 4195758cc3dcSJack F Vogel } 4196758cc3dcSJack F Vogel #endif 4197758cc3dcSJack F Vogel 4198758cc3dcSJack F Vogel /** ixgbe_sysctl_tdh_handler - Handler function 4199758cc3dcSJack F Vogel * Retrieves the TDH value from the hardware 4200758cc3dcSJack F Vogel */ 4201758cc3dcSJack F Vogel static int 4202758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS) 4203758cc3dcSJack F Vogel { 4204758cc3dcSJack F Vogel int error; 4205758cc3dcSJack F Vogel 4206758cc3dcSJack F Vogel struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); 4207758cc3dcSJack F Vogel if (!txr) return 0; 4208758cc3dcSJack F Vogel 4209758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me)); 4210758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4211758cc3dcSJack F Vogel if (error || !req->newptr) 4212758cc3dcSJack F Vogel return error; 4213758cc3dcSJack F Vogel return 0; 4214758cc3dcSJack F Vogel } 4215758cc3dcSJack F Vogel 4216758cc3dcSJack F Vogel /** ixgbe_sysctl_tdt_handler - Handler function 4217758cc3dcSJack F Vogel * Retrieves the TDT value from the hardware 4218758cc3dcSJack F Vogel */ 4219758cc3dcSJack F Vogel static int 4220758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS) 4221758cc3dcSJack F Vogel { 4222758cc3dcSJack F Vogel int error; 4223758cc3dcSJack F Vogel 4224758cc3dcSJack F Vogel struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); 4225758cc3dcSJack F Vogel if (!txr) return 0; 4226758cc3dcSJack F Vogel 4227758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me)); 4228758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4229758cc3dcSJack F Vogel if (error || !req->newptr) 4230758cc3dcSJack F Vogel return error; 4231758cc3dcSJack F Vogel return 0; 4232758cc3dcSJack F Vogel } 4233758cc3dcSJack F Vogel 4234758cc3dcSJack F Vogel /** ixgbe_sysctl_rdh_handler - Handler function 4235758cc3dcSJack F Vogel * Retrieves the RDH value from the hardware 4236758cc3dcSJack F Vogel */ 4237758cc3dcSJack F Vogel static int 4238758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS) 4239758cc3dcSJack F Vogel { 4240758cc3dcSJack F Vogel int error; 4241758cc3dcSJack F Vogel 4242758cc3dcSJack F Vogel struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); 4243758cc3dcSJack F Vogel if (!rxr) return 0; 4244758cc3dcSJack F Vogel 4245758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me)); 4246758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4247758cc3dcSJack F Vogel if (error || !req->newptr) 4248758cc3dcSJack F Vogel return error; 4249758cc3dcSJack F Vogel return 0; 4250758cc3dcSJack F Vogel } 4251758cc3dcSJack F Vogel 4252758cc3dcSJack F Vogel /** ixgbe_sysctl_rdt_handler - Handler function 4253758cc3dcSJack F Vogel * Retrieves the RDT value from the hardware 4254758cc3dcSJack F Vogel */ 4255758cc3dcSJack F Vogel static int 4256758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) 4257758cc3dcSJack F Vogel { 4258758cc3dcSJack F Vogel int error; 4259758cc3dcSJack F Vogel 4260758cc3dcSJack F Vogel struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); 4261758cc3dcSJack F Vogel if (!rxr) return 0; 4262758cc3dcSJack F Vogel 4263758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me)); 4264758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4265758cc3dcSJack F Vogel if (error || !req->newptr) 4266758cc3dcSJack F Vogel return error; 4267758cc3dcSJack F Vogel return 0; 4268758cc3dcSJack F Vogel } 4269758cc3dcSJack F Vogel 4270758cc3dcSJack F Vogel static int 4271758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS) 4272758cc3dcSJack F Vogel { 4273758cc3dcSJack F Vogel int error; 4274758cc3dcSJack F Vogel struct ix_queue *que = ((struct ix_queue *)oidp->oid_arg1); 4275758cc3dcSJack F Vogel unsigned int reg, usec, rate; 4276758cc3dcSJack F Vogel 4277758cc3dcSJack F Vogel reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix)); 4278758cc3dcSJack F Vogel usec = ((reg & 0x0FF8) >> 3); 4279758cc3dcSJack F Vogel if (usec > 0) 4280758cc3dcSJack F Vogel rate = 500000 / usec; 4281758cc3dcSJack F Vogel else 4282758cc3dcSJack F Vogel rate = 0; 4283758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &rate, 0, req); 4284758cc3dcSJack F Vogel if (error || !req->newptr) 4285758cc3dcSJack F Vogel return error; 4286758cc3dcSJack F Vogel reg &= ~0xfff; /* default, no limitation */ 4287758cc3dcSJack F Vogel ixgbe_max_interrupt_rate = 0; 4288758cc3dcSJack F Vogel if (rate > 0 && rate < 500000) { 4289758cc3dcSJack F Vogel if (rate < 1000) 4290758cc3dcSJack F Vogel rate = 1000; 4291758cc3dcSJack F Vogel ixgbe_max_interrupt_rate = rate; 4292758cc3dcSJack F Vogel reg |= ((4000000/rate) & 0xff8 ); 4293758cc3dcSJack F Vogel } 4294758cc3dcSJack F Vogel IXGBE_WRITE_REG(&que->adapter->hw, IXGBE_EITR(que->msix), reg); 4295758cc3dcSJack F Vogel return 0; 4296758cc3dcSJack F Vogel } 4297758cc3dcSJack F Vogel 42986f37f232SEric Joyner static void 42996f37f232SEric Joyner ixgbe_add_device_sysctls(struct adapter *adapter) 43006f37f232SEric Joyner { 43016f37f232SEric Joyner device_t dev = adapter->dev; 43026f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 43036f37f232SEric Joyner struct sysctl_oid_list *child; 43046f37f232SEric Joyner struct sysctl_ctx_list *ctx; 43056f37f232SEric Joyner 43066f37f232SEric Joyner ctx = device_get_sysctl_ctx(dev); 43076f37f232SEric Joyner child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 43086f37f232SEric Joyner 43096f37f232SEric Joyner /* Sysctls for all devices */ 43106f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fc", 43116f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 4312f2c4db54SSteven Hartland ixgbe_sysctl_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC); 43136f37f232SEric Joyner 43146f37f232SEric Joyner SYSCTL_ADD_INT(ctx, child, OID_AUTO, "enable_aim", 43156f37f232SEric Joyner CTLFLAG_RW, 43166f37f232SEric Joyner &ixgbe_enable_aim, 1, "Interrupt Moderation"); 43176f37f232SEric Joyner 43186f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "advertise_speed", 43196f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 4320f2c4db54SSteven Hartland ixgbe_sysctl_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED); 43216f37f232SEric Joyner 43226f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "thermal_test", 43236f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 43246f37f232SEric Joyner ixgbe_sysctl_thermal_test, "I", "Thermal Test"); 43256f37f232SEric Joyner 4326a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG 4327a9ca1c79SSean Bruno /* testing sysctls (for all devices) */ 4328a9ca1c79SSean Bruno SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "power_state", 4329a9ca1c79SSean Bruno CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 4330a9ca1c79SSean Bruno ixgbe_sysctl_power_state, "I", "PCI Power State"); 4331a9ca1c79SSean Bruno 4332a9ca1c79SSean Bruno SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config", 4333a9ca1c79SSean Bruno CTLTYPE_STRING | CTLFLAG_RD, adapter, 0, 4334a9ca1c79SSean Bruno ixgbe_sysctl_print_rss_config, "A", "Prints RSS Configuration"); 4335a9ca1c79SSean Bruno #endif 4336a9ca1c79SSean Bruno /* for X550 series devices */ 43376f37f232SEric Joyner if (hw->mac.type >= ixgbe_mac_X550) 43386f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac", 43396f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 43406f37f232SEric Joyner ixgbe_sysctl_dmac, "I", "DMA Coalesce"); 43416f37f232SEric Joyner 4342a9ca1c79SSean Bruno /* for X552 backplane devices */ 4343a9ca1c79SSean Bruno if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { 43446f37f232SEric Joyner struct sysctl_oid *eee_node; 43456f37f232SEric Joyner struct sysctl_oid_list *eee_list; 43466f37f232SEric Joyner 43476f37f232SEric Joyner eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee", 43486f37f232SEric Joyner CTLFLAG_RD, NULL, 43496f37f232SEric Joyner "Energy Efficient Ethernet sysctls"); 43506f37f232SEric Joyner eee_list = SYSCTL_CHILDREN(eee_node); 43516f37f232SEric Joyner 43526f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "enable", 43536f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 43546f37f232SEric Joyner ixgbe_sysctl_eee_enable, "I", 43556f37f232SEric Joyner "Enable or Disable EEE"); 43566f37f232SEric Joyner 43576f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "negotiated", 43586f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 43596f37f232SEric Joyner ixgbe_sysctl_eee_negotiated, "I", 43606f37f232SEric Joyner "EEE negotiated on link"); 43616f37f232SEric Joyner 43626f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_status", 43636f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 43646f37f232SEric Joyner ixgbe_sysctl_eee_tx_lpi_status, "I", 43656f37f232SEric Joyner "Whether or not TX link is in LPI state"); 43666f37f232SEric Joyner 43676f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "rx_lpi_status", 43686f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 43696f37f232SEric Joyner ixgbe_sysctl_eee_rx_lpi_status, "I", 43706f37f232SEric Joyner "Whether or not RX link is in LPI state"); 4371a9ca1c79SSean Bruno 4372a9ca1c79SSean Bruno SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_delay", 4373a9ca1c79SSean Bruno CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 4374a9ca1c79SSean Bruno ixgbe_sysctl_eee_tx_lpi_delay, "I", 4375a9ca1c79SSean Bruno "TX LPI entry delay in microseconds"); 43766f37f232SEric Joyner } 43776f37f232SEric Joyner 4378a9ca1c79SSean Bruno /* for WoL-capable devices */ 4379a9ca1c79SSean Bruno if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { 43806f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wol_enable", 43816f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 43826f37f232SEric Joyner ixgbe_sysctl_wol_enable, "I", 43836f37f232SEric Joyner "Enable/Disable Wake on LAN"); 43846f37f232SEric Joyner 43856f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wufc", 43866f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 43876f37f232SEric Joyner ixgbe_sysctl_wufc, "I", 43886f37f232SEric Joyner "Enable/Disable Wake Up Filters"); 43896f37f232SEric Joyner } 43906f37f232SEric Joyner 4391a9ca1c79SSean Bruno /* for X552/X557-AT devices */ 43926f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { 43936f37f232SEric Joyner struct sysctl_oid *phy_node; 43946f37f232SEric Joyner struct sysctl_oid_list *phy_list; 43956f37f232SEric Joyner 43966f37f232SEric Joyner phy_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "phy", 43976f37f232SEric Joyner CTLFLAG_RD, NULL, 43986f37f232SEric Joyner "External PHY sysctls"); 43996f37f232SEric Joyner phy_list = SYSCTL_CHILDREN(phy_node); 44006f37f232SEric Joyner 44016f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "temp", 44026f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 44036f37f232SEric Joyner ixgbe_sysctl_phy_temp, "I", 44046f37f232SEric Joyner "Current External PHY Temperature (Celsius)"); 44056f37f232SEric Joyner 44066f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "overtemp_occurred", 44076f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 44086f37f232SEric Joyner ixgbe_sysctl_phy_overtemp_occurred, "I", 44096f37f232SEric Joyner "External PHY High Temperature Event Occurred"); 44106f37f232SEric Joyner } 44116f37f232SEric Joyner } 44126f37f232SEric Joyner 4413758cc3dcSJack F Vogel /* 4414758cc3dcSJack F Vogel * Add sysctl variables, one per statistic, to the system. 4415758cc3dcSJack F Vogel */ 4416758cc3dcSJack F Vogel static void 4417758cc3dcSJack F Vogel ixgbe_add_hw_stats(struct adapter *adapter) 4418758cc3dcSJack F Vogel { 4419758cc3dcSJack F Vogel device_t dev = adapter->dev; 4420758cc3dcSJack F Vogel 4421758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 4422758cc3dcSJack F Vogel struct rx_ring *rxr = adapter->rx_rings; 4423758cc3dcSJack F Vogel 4424758cc3dcSJack F Vogel struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 4425758cc3dcSJack F Vogel struct sysctl_oid *tree = device_get_sysctl_tree(dev); 4426758cc3dcSJack F Vogel struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 4427758cc3dcSJack F Vogel struct ixgbe_hw_stats *stats = &adapter->stats.pf; 4428758cc3dcSJack F Vogel 4429758cc3dcSJack F Vogel struct sysctl_oid *stat_node, *queue_node; 4430758cc3dcSJack F Vogel struct sysctl_oid_list *stat_list, *queue_list; 4431758cc3dcSJack F Vogel 4432758cc3dcSJack F Vogel #define QUEUE_NAME_LEN 32 4433758cc3dcSJack F Vogel char namebuf[QUEUE_NAME_LEN]; 4434758cc3dcSJack F Vogel 4435758cc3dcSJack F Vogel /* Driver Statistics */ 4436758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", 4437758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->dropped_pkts, 4438758cc3dcSJack F Vogel "Driver dropped packets"); 4439758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", 4440758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->mbuf_defrag_failed, 4441758cc3dcSJack F Vogel "m_defrag() failed"); 4442758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 4443758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->watchdog_events, 4444758cc3dcSJack F Vogel "Watchdog timeouts"); 4445758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", 44466f37f232SEric Joyner CTLFLAG_RD, &adapter->link_irq, 4447758cc3dcSJack F Vogel "Link MSIX IRQ Handled"); 4448758cc3dcSJack F Vogel 4449758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, txr++) { 4450758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4451758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4452758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4453758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4454758cc3dcSJack F Vogel 4455758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate", 4456758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RW, &adapter->queues[i], 4457758cc3dcSJack F Vogel sizeof(&adapter->queues[i]), 4458758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler, "IU", 4459758cc3dcSJack F Vogel "Interrupt Rate"); 4460758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 4461758cc3dcSJack F Vogel CTLFLAG_RD, &(adapter->queues[i].irqs), 4462758cc3dcSJack F Vogel "irqs on this queue"); 4463758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", 4464758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), 4465758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler, "IU", 4466758cc3dcSJack F Vogel "Transmit Descriptor Head"); 4467758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", 4468758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), 4469758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler, "IU", 4470758cc3dcSJack F Vogel "Transmit Descriptor Tail"); 4471758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx", 4472758cc3dcSJack F Vogel CTLFLAG_RD, &txr->tso_tx, 4473758cc3dcSJack F Vogel "TSO"); 4474758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_tx_dma_setup", 4475758cc3dcSJack F Vogel CTLFLAG_RD, &txr->no_tx_dma_setup, 4476758cc3dcSJack F Vogel "Driver tx dma failure in xmit"); 4477758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 4478758cc3dcSJack F Vogel CTLFLAG_RD, &txr->no_desc_avail, 4479758cc3dcSJack F Vogel "Queue No Descriptor Available"); 4480758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 4481758cc3dcSJack F Vogel CTLFLAG_RD, &txr->total_packets, 4482758cc3dcSJack F Vogel "Queue Packets Transmitted"); 4483625d12c6SJohn Baldwin SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops", 4484625d12c6SJohn Baldwin CTLFLAG_RD, &txr->br->br_drops, 4485625d12c6SJohn Baldwin "Packets dropped in buf_ring"); 4486758cc3dcSJack F Vogel } 4487758cc3dcSJack F Vogel 4488758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, rxr++) { 4489758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4490758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4491758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4492758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4493758cc3dcSJack F Vogel 4494758cc3dcSJack F Vogel struct lro_ctrl *lro = &rxr->lro; 4495758cc3dcSJack F Vogel 4496758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4497758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4498758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4499758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4500758cc3dcSJack F Vogel 4501758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", 4502758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), 4503758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler, "IU", 4504758cc3dcSJack F Vogel "Receive Descriptor Head"); 4505758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", 4506758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), 4507758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler, "IU", 4508758cc3dcSJack F Vogel "Receive Descriptor Tail"); 4509758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 4510758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_packets, 4511758cc3dcSJack F Vogel "Queue Packets Received"); 4512758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 4513758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_bytes, 4514758cc3dcSJack F Vogel "Queue Bytes Received"); 4515758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies", 4516758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_copies, 4517758cc3dcSJack F Vogel "Copied RX Frames"); 4518e936121dSHans Petter Selasky SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_queued", 4519758cc3dcSJack F Vogel CTLFLAG_RD, &lro->lro_queued, 0, 4520758cc3dcSJack F Vogel "LRO Queued"); 4521e936121dSHans Petter Selasky SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_flushed", 4522758cc3dcSJack F Vogel CTLFLAG_RD, &lro->lro_flushed, 0, 4523758cc3dcSJack F Vogel "LRO Flushed"); 4524758cc3dcSJack F Vogel } 4525758cc3dcSJack F Vogel 4526758cc3dcSJack F Vogel /* MAC stats get the own sub node */ 4527758cc3dcSJack F Vogel 4528758cc3dcSJack F Vogel stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", 4529758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "MAC Statistics"); 4530758cc3dcSJack F Vogel stat_list = SYSCTL_CHILDREN(stat_node); 4531758cc3dcSJack F Vogel 4532758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs", 4533758cc3dcSJack F Vogel CTLFLAG_RD, &stats->crcerrs, 4534758cc3dcSJack F Vogel "CRC Errors"); 4535758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs", 4536758cc3dcSJack F Vogel CTLFLAG_RD, &stats->illerrc, 4537758cc3dcSJack F Vogel "Illegal Byte Errors"); 4538758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs", 4539758cc3dcSJack F Vogel CTLFLAG_RD, &stats->errbc, 4540758cc3dcSJack F Vogel "Byte Errors"); 4541758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards", 4542758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mspdc, 4543758cc3dcSJack F Vogel "MAC Short Packets Discarded"); 4544758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults", 4545758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mlfc, 4546758cc3dcSJack F Vogel "MAC Local Faults"); 4547758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults", 4548758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mrfc, 4549758cc3dcSJack F Vogel "MAC Remote Faults"); 4550758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs", 4551758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rlec, 4552758cc3dcSJack F Vogel "Receive Length Errors"); 4553758cc3dcSJack F Vogel 4554758cc3dcSJack F Vogel /* Flow Control stats */ 4555758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd", 4556758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxontxc, 4557758cc3dcSJack F Vogel "Link XON Transmitted"); 4558758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd", 4559758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxonrxc, 4560758cc3dcSJack F Vogel "Link XON Received"); 4561758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd", 4562758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxofftxc, 4563758cc3dcSJack F Vogel "Link XOFF Transmitted"); 4564758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd", 4565758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxoffrxc, 4566758cc3dcSJack F Vogel "Link XOFF Received"); 4567758cc3dcSJack F Vogel 4568758cc3dcSJack F Vogel /* Packet Reception Stats */ 4569758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd", 4570758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tor, 4571758cc3dcSJack F Vogel "Total Octets Received"); 4572758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", 4573758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gorc, 4574758cc3dcSJack F Vogel "Good Octets Received"); 4575758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd", 4576758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tpr, 4577758cc3dcSJack F Vogel "Total Packets Received"); 4578758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", 4579758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gprc, 4580758cc3dcSJack F Vogel "Good Packets Received"); 4581758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", 4582758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mprc, 4583758cc3dcSJack F Vogel "Multicast Packets Received"); 4584758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", 4585758cc3dcSJack F Vogel CTLFLAG_RD, &stats->bprc, 4586758cc3dcSJack F Vogel "Broadcast Packets Received"); 4587758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", 4588758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc64, 4589758cc3dcSJack F Vogel "64 byte frames received "); 4590758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", 4591758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc127, 4592758cc3dcSJack F Vogel "65-127 byte frames received"); 4593758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", 4594758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc255, 4595758cc3dcSJack F Vogel "128-255 byte frames received"); 4596758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", 4597758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc511, 4598758cc3dcSJack F Vogel "256-511 byte frames received"); 4599758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", 4600758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc1023, 4601758cc3dcSJack F Vogel "512-1023 byte frames received"); 4602758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", 4603758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc1522, 4604758cc3dcSJack F Vogel "1023-1522 byte frames received"); 4605758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized", 4606758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ruc, 4607758cc3dcSJack F Vogel "Receive Undersized"); 4608758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", 4609758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rfc, 4610758cc3dcSJack F Vogel "Fragmented Packets Received "); 4611758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized", 4612758cc3dcSJack F Vogel CTLFLAG_RD, &stats->roc, 4613758cc3dcSJack F Vogel "Oversized Packets Received"); 4614758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd", 4615758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rjc, 4616758cc3dcSJack F Vogel "Received Jabber"); 4617758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd", 4618758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngprc, 4619758cc3dcSJack F Vogel "Management Packets Received"); 4620758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd", 4621758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngptc, 4622758cc3dcSJack F Vogel "Management Packets Dropped"); 4623758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs", 4624758cc3dcSJack F Vogel CTLFLAG_RD, &stats->xec, 4625758cc3dcSJack F Vogel "Checksum Errors"); 4626758cc3dcSJack F Vogel 4627758cc3dcSJack F Vogel /* Packet Transmission Stats */ 4628758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", 4629758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gotc, 4630758cc3dcSJack F Vogel "Good Octets Transmitted"); 4631758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", 4632758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tpt, 4633758cc3dcSJack F Vogel "Total Packets Transmitted"); 4634758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", 4635758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gptc, 4636758cc3dcSJack F Vogel "Good Packets Transmitted"); 4637758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", 4638758cc3dcSJack F Vogel CTLFLAG_RD, &stats->bptc, 4639758cc3dcSJack F Vogel "Broadcast Packets Transmitted"); 4640758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", 4641758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mptc, 4642758cc3dcSJack F Vogel "Multicast Packets Transmitted"); 4643758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd", 4644758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngptc, 4645758cc3dcSJack F Vogel "Management Packets Transmitted"); 4646758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", 4647758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc64, 4648758cc3dcSJack F Vogel "64 byte frames transmitted "); 4649758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", 4650758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc127, 4651758cc3dcSJack F Vogel "65-127 byte frames transmitted"); 4652758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", 4653758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc255, 4654758cc3dcSJack F Vogel "128-255 byte frames transmitted"); 4655758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", 4656758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc511, 4657758cc3dcSJack F Vogel "256-511 byte frames transmitted"); 4658758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", 4659758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc1023, 4660758cc3dcSJack F Vogel "512-1023 byte frames transmitted"); 4661758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", 4662758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc1522, 4663758cc3dcSJack F Vogel "1024-1522 byte frames transmitted"); 4664758cc3dcSJack F Vogel } 4665758cc3dcSJack F Vogel 4666b0c041f8SSean Bruno static void 4667b0c041f8SSean Bruno ixgbe_set_sysctl_value(struct adapter *adapter, const char *name, 4668b0c041f8SSean Bruno const char *description, int *limit, int value) 4669b0c041f8SSean Bruno { 4670b0c041f8SSean Bruno *limit = value; 4671b0c041f8SSean Bruno SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev), 4672b0c041f8SSean Bruno SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), 4673b0c041f8SSean Bruno OID_AUTO, name, CTLFLAG_RW, limit, value, description); 4674b0c041f8SSean Bruno } 4675b0c041f8SSean Bruno 4676758cc3dcSJack F Vogel /* 4677758cc3dcSJack F Vogel ** Set flow control using sysctl: 4678758cc3dcSJack F Vogel ** Flow control values: 4679758cc3dcSJack F Vogel ** 0 - off 4680758cc3dcSJack F Vogel ** 1 - rx pause 4681758cc3dcSJack F Vogel ** 2 - tx pause 4682758cc3dcSJack F Vogel ** 3 - full 4683758cc3dcSJack F Vogel */ 4684758cc3dcSJack F Vogel static int 4685f2c4db54SSteven Hartland ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS) 4686758cc3dcSJack F Vogel { 4687f2c4db54SSteven Hartland int error, fc; 4688f2c4db54SSteven Hartland struct adapter *adapter; 4689758cc3dcSJack F Vogel 4690f2c4db54SSteven Hartland adapter = (struct adapter *) arg1; 4691f2c4db54SSteven Hartland fc = adapter->fc; 4692f2c4db54SSteven Hartland 4693f2c4db54SSteven Hartland error = sysctl_handle_int(oidp, &fc, 0, req); 4694758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4695758cc3dcSJack F Vogel return (error); 4696758cc3dcSJack F Vogel 4697758cc3dcSJack F Vogel /* Don't bother if it's not changed */ 4698f2c4db54SSteven Hartland if (adapter->fc == fc) 4699758cc3dcSJack F Vogel return (0); 4700758cc3dcSJack F Vogel 4701f2c4db54SSteven Hartland return ixgbe_set_flowcntl(adapter, fc); 4702f2c4db54SSteven Hartland } 4703f2c4db54SSteven Hartland 4704f2c4db54SSteven Hartland 4705f2c4db54SSteven Hartland static int 4706f2c4db54SSteven Hartland ixgbe_set_flowcntl(struct adapter *adapter, int fc) 4707f2c4db54SSteven Hartland { 4708f2c4db54SSteven Hartland 4709f2c4db54SSteven Hartland switch (fc) { 4710758cc3dcSJack F Vogel case ixgbe_fc_rx_pause: 4711758cc3dcSJack F Vogel case ixgbe_fc_tx_pause: 4712758cc3dcSJack F Vogel case ixgbe_fc_full: 4713758cc3dcSJack F Vogel adapter->hw.fc.requested_mode = adapter->fc; 4714758cc3dcSJack F Vogel if (adapter->num_queues > 1) 4715758cc3dcSJack F Vogel ixgbe_disable_rx_drop(adapter); 4716758cc3dcSJack F Vogel break; 4717758cc3dcSJack F Vogel case ixgbe_fc_none: 4718758cc3dcSJack F Vogel adapter->hw.fc.requested_mode = ixgbe_fc_none; 4719758cc3dcSJack F Vogel if (adapter->num_queues > 1) 4720758cc3dcSJack F Vogel ixgbe_enable_rx_drop(adapter); 4721758cc3dcSJack F Vogel break; 4722758cc3dcSJack F Vogel default: 4723758cc3dcSJack F Vogel return (EINVAL); 4724758cc3dcSJack F Vogel } 4725f2c4db54SSteven Hartland adapter->fc = fc; 4726758cc3dcSJack F Vogel /* Don't autoneg if forcing a value */ 4727758cc3dcSJack F Vogel adapter->hw.fc.disable_fc_autoneg = TRUE; 4728758cc3dcSJack F Vogel ixgbe_fc_enable(&adapter->hw); 4729f2c4db54SSteven Hartland return (0); 4730758cc3dcSJack F Vogel } 4731758cc3dcSJack F Vogel 4732758cc3dcSJack F Vogel /* 4733758cc3dcSJack F Vogel ** Control advertised link speed: 4734758cc3dcSJack F Vogel ** Flags: 4735758cc3dcSJack F Vogel ** 0x1 - advertise 100 Mb 4736758cc3dcSJack F Vogel ** 0x2 - advertise 1G 4737758cc3dcSJack F Vogel ** 0x4 - advertise 10G 4738758cc3dcSJack F Vogel */ 4739758cc3dcSJack F Vogel static int 4740f2c4db54SSteven Hartland ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS) 4741758cc3dcSJack F Vogel { 4742f2c4db54SSteven Hartland int error, advertise; 4743758cc3dcSJack F Vogel struct adapter *adapter; 4744758cc3dcSJack F Vogel 4745758cc3dcSJack F Vogel adapter = (struct adapter *) arg1; 4746f2c4db54SSteven Hartland advertise = adapter->advertise; 4747758cc3dcSJack F Vogel 4748f2c4db54SSteven Hartland error = sysctl_handle_int(oidp, &advertise, 0, req); 4749758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4750758cc3dcSJack F Vogel return (error); 4751758cc3dcSJack F Vogel 4752f2c4db54SSteven Hartland return ixgbe_set_advertise(adapter, advertise); 4753f2c4db54SSteven Hartland } 4754f2c4db54SSteven Hartland 4755f2c4db54SSteven Hartland static int 4756f2c4db54SSteven Hartland ixgbe_set_advertise(struct adapter *adapter, int advertise) 4757f2c4db54SSteven Hartland { 4758f2c4db54SSteven Hartland device_t dev; 4759f2c4db54SSteven Hartland struct ixgbe_hw *hw; 4760f2c4db54SSteven Hartland ixgbe_link_speed speed; 4761f2c4db54SSteven Hartland 4762*d775d23aSSteven Hartland /* Checks to validate new value */ 4763*d775d23aSSteven Hartland if (adapter->advertise == advertise) /* no change */ 4764*d775d23aSSteven Hartland return (0); 4765*d775d23aSSteven Hartland 4766f2c4db54SSteven Hartland hw = &adapter->hw; 4767f2c4db54SSteven Hartland dev = adapter->dev; 4768f2c4db54SSteven Hartland 4769a9ca1c79SSean Bruno /* No speed changes for backplane media */ 4770a9ca1c79SSean Bruno if (hw->phy.media_type == ixgbe_media_type_backplane) 4771a9ca1c79SSean Bruno return (ENODEV); 4772a9ca1c79SSean Bruno 4773758cc3dcSJack F Vogel if (!((hw->phy.media_type == ixgbe_media_type_copper) || 4774758cc3dcSJack F Vogel (hw->phy.multispeed_fiber))) { 4775758cc3dcSJack F Vogel device_printf(dev, 4776758cc3dcSJack F Vogel "Advertised speed can only be set on copper or " 4777758cc3dcSJack F Vogel "multispeed fiber media types.\n"); 4778758cc3dcSJack F Vogel return (EINVAL); 4779758cc3dcSJack F Vogel } 4780758cc3dcSJack F Vogel 4781f2c4db54SSteven Hartland if (advertise < 0x1 || advertise > 0x7) { 4782758cc3dcSJack F Vogel device_printf(dev, 4783758cc3dcSJack F Vogel "Invalid advertised speed; valid modes are 0x1 through 0x7\n"); 4784758cc3dcSJack F Vogel return (EINVAL); 4785758cc3dcSJack F Vogel } 4786758cc3dcSJack F Vogel 4787f2c4db54SSteven Hartland if ((advertise & 0x1) 4788758cc3dcSJack F Vogel && (hw->mac.type != ixgbe_mac_X540) 4789758cc3dcSJack F Vogel && (hw->mac.type != ixgbe_mac_X550)) { 4790758cc3dcSJack F Vogel device_printf(dev, "Set Advertise: 100Mb on X540/X550 only\n"); 4791758cc3dcSJack F Vogel return (EINVAL); 4792758cc3dcSJack F Vogel } 4793758cc3dcSJack F Vogel 4794758cc3dcSJack F Vogel /* Set new value and report new advertised mode */ 4795f2c4db54SSteven Hartland speed = 0; 4796f2c4db54SSteven Hartland if (advertise & 0x1) 4797758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 4798f2c4db54SSteven Hartland if (advertise & 0x2) 4799758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 4800f2c4db54SSteven Hartland if (advertise & 0x4) 4801758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_10GB_FULL; 4802f2c4db54SSteven Hartland adapter->advertise = advertise; 4803758cc3dcSJack F Vogel 4804758cc3dcSJack F Vogel hw->mac.autotry_restart = TRUE; 4805758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, speed, TRUE); 4806758cc3dcSJack F Vogel 4807f2c4db54SSteven Hartland return (0); 4808758cc3dcSJack F Vogel } 4809758cc3dcSJack F Vogel 4810758cc3dcSJack F Vogel /* 4811a9ca1c79SSean Bruno * The following two sysctls are for X552/X557-AT devices; 48126f37f232SEric Joyner * they deal with the external PHY used in them. 4813758cc3dcSJack F Vogel */ 4814758cc3dcSJack F Vogel static int 48156f37f232SEric Joyner ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS) 4816758cc3dcSJack F Vogel { 4817758cc3dcSJack F Vogel struct adapter *adapter = (struct adapter *) arg1; 4818758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 48196f37f232SEric Joyner u16 reg; 4820758cc3dcSJack F Vogel 48216f37f232SEric Joyner if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { 48226f37f232SEric Joyner device_printf(adapter->dev, 48236f37f232SEric Joyner "Device has no supported external thermal sensor.\n"); 48246f37f232SEric Joyner return (ENODEV); 48256f37f232SEric Joyner } 4826758cc3dcSJack F Vogel 48276f37f232SEric Joyner if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP, 48286f37f232SEric Joyner IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 48296f37f232SEric Joyner ®)) { 48306f37f232SEric Joyner device_printf(adapter->dev, 48316f37f232SEric Joyner "Error reading from PHY's current temperature register\n"); 48326f37f232SEric Joyner return (EAGAIN); 48336f37f232SEric Joyner } 48346f37f232SEric Joyner 48356f37f232SEric Joyner /* Shift temp for output */ 48366f37f232SEric Joyner reg = reg >> 8; 48376f37f232SEric Joyner 48386f37f232SEric Joyner return (sysctl_handle_int(oidp, NULL, reg, req)); 48396f37f232SEric Joyner } 48406f37f232SEric Joyner 48416f37f232SEric Joyner /* 48426f37f232SEric Joyner * Reports whether the current PHY temperature is over 48436f37f232SEric Joyner * the overtemp threshold. 48446f37f232SEric Joyner * - This is reported directly from the PHY 48456f37f232SEric Joyner */ 48466f37f232SEric Joyner static int 48476f37f232SEric Joyner ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS) 48486f37f232SEric Joyner { 48496f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 48506f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 48516f37f232SEric Joyner u16 reg; 48526f37f232SEric Joyner 48536f37f232SEric Joyner if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { 48546f37f232SEric Joyner device_printf(adapter->dev, 48556f37f232SEric Joyner "Device has no supported external thermal sensor.\n"); 48566f37f232SEric Joyner return (ENODEV); 48576f37f232SEric Joyner } 48586f37f232SEric Joyner 48596f37f232SEric Joyner if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS, 48606f37f232SEric Joyner IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 48616f37f232SEric Joyner ®)) { 48626f37f232SEric Joyner device_printf(adapter->dev, 48636f37f232SEric Joyner "Error reading from PHY's temperature status register\n"); 48646f37f232SEric Joyner return (EAGAIN); 48656f37f232SEric Joyner } 48666f37f232SEric Joyner 48676f37f232SEric Joyner /* Get occurrence bit */ 48686f37f232SEric Joyner reg = !!(reg & 0x4000); 48696f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, reg, req)); 48706f37f232SEric Joyner } 48716f37f232SEric Joyner 48726f37f232SEric Joyner /* 48736f37f232SEric Joyner ** Thermal Shutdown Trigger (internal MAC) 48746f37f232SEric Joyner ** - Set this to 1 to cause an overtemp event to occur 48756f37f232SEric Joyner */ 48766f37f232SEric Joyner static int 48776f37f232SEric Joyner ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS) 48786f37f232SEric Joyner { 48796f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 48806f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 48816f37f232SEric Joyner int error, fire = 0; 4882758cc3dcSJack F Vogel 4883758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &fire, 0, req); 4884758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4885758cc3dcSJack F Vogel return (error); 4886758cc3dcSJack F Vogel 4887758cc3dcSJack F Vogel if (fire) { 4888758cc3dcSJack F Vogel u32 reg = IXGBE_READ_REG(hw, IXGBE_EICS); 4889758cc3dcSJack F Vogel reg |= IXGBE_EICR_TS; 4890758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICS, reg); 4891758cc3dcSJack F Vogel } 4892758cc3dcSJack F Vogel 4893758cc3dcSJack F Vogel return (0); 4894758cc3dcSJack F Vogel } 4895758cc3dcSJack F Vogel 4896758cc3dcSJack F Vogel /* 48976f37f232SEric Joyner ** Manage DMA Coalescing. 48986f37f232SEric Joyner ** Control values: 48996f37f232SEric Joyner ** 0/1 - off / on (use default value of 1000) 49006f37f232SEric Joyner ** 49016f37f232SEric Joyner ** Legal timer values are: 49026f37f232SEric Joyner ** 50,100,250,500,1000,2000,5000,10000 49036f37f232SEric Joyner ** 49046f37f232SEric Joyner ** Turning off interrupt moderation will also turn this off. 49056f37f232SEric Joyner */ 49066f37f232SEric Joyner static int 49076f37f232SEric Joyner ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS) 49086f37f232SEric Joyner { 49096f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 49106f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 49116f37f232SEric Joyner int error; 4912a9ca1c79SSean Bruno u32 newval; 49136f37f232SEric Joyner 4914a9ca1c79SSean Bruno newval = adapter->dmac; 4915a9ca1c79SSean Bruno error = sysctl_handle_int(oidp, &newval, 0, req); 49166f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 49176f37f232SEric Joyner return (error); 49186f37f232SEric Joyner 4919a9ca1c79SSean Bruno switch (newval) { 49206f37f232SEric Joyner case 0: 49216f37f232SEric Joyner /* Disabled */ 4922a9ca1c79SSean Bruno adapter->dmac = 0; 49236f37f232SEric Joyner break; 4924a9ca1c79SSean Bruno case 1: 4925a9ca1c79SSean Bruno /* Enable and use default */ 49266f37f232SEric Joyner adapter->dmac = 1000; 49276f37f232SEric Joyner break; 49286f37f232SEric Joyner case 50: 49296f37f232SEric Joyner case 100: 49306f37f232SEric Joyner case 250: 49316f37f232SEric Joyner case 500: 49326f37f232SEric Joyner case 1000: 49336f37f232SEric Joyner case 2000: 49346f37f232SEric Joyner case 5000: 49356f37f232SEric Joyner case 10000: 49366f37f232SEric Joyner /* Legal values - allow */ 4937a9ca1c79SSean Bruno adapter->dmac = newval; 49386f37f232SEric Joyner break; 49396f37f232SEric Joyner default: 49406f37f232SEric Joyner /* Do nothing, illegal value */ 49416f37f232SEric Joyner return (EINVAL); 49426f37f232SEric Joyner } 49436f37f232SEric Joyner 49446f37f232SEric Joyner /* Re-initialize hardware if it's already running */ 49456f37f232SEric Joyner if (ifp->if_drv_flags & IFF_DRV_RUNNING) 49466f37f232SEric Joyner ixgbe_init(adapter); 49476f37f232SEric Joyner 49486f37f232SEric Joyner return (0); 49496f37f232SEric Joyner } 49506f37f232SEric Joyner 4951a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG 4952a9ca1c79SSean Bruno /** 4953a9ca1c79SSean Bruno * Sysctl to test power states 4954a9ca1c79SSean Bruno * Values: 4955a9ca1c79SSean Bruno * 0 - set device to D0 4956a9ca1c79SSean Bruno * 3 - set device to D3 4957a9ca1c79SSean Bruno * (none) - get current device power state 4958a9ca1c79SSean Bruno */ 4959a9ca1c79SSean Bruno static int 4960a9ca1c79SSean Bruno ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS) 4961a9ca1c79SSean Bruno { 4962a9ca1c79SSean Bruno struct adapter *adapter = (struct adapter *) arg1; 4963a9ca1c79SSean Bruno device_t dev = adapter->dev; 4964a9ca1c79SSean Bruno int curr_ps, new_ps, error = 0; 4965a9ca1c79SSean Bruno 4966a9ca1c79SSean Bruno curr_ps = new_ps = pci_get_powerstate(dev); 4967a9ca1c79SSean Bruno 4968a9ca1c79SSean Bruno error = sysctl_handle_int(oidp, &new_ps, 0, req); 4969a9ca1c79SSean Bruno if ((error) || (req->newptr == NULL)) 4970a9ca1c79SSean Bruno return (error); 4971a9ca1c79SSean Bruno 4972a9ca1c79SSean Bruno if (new_ps == curr_ps) 4973a9ca1c79SSean Bruno return (0); 4974a9ca1c79SSean Bruno 4975a9ca1c79SSean Bruno if (new_ps == 3 && curr_ps == 0) 4976a9ca1c79SSean Bruno error = DEVICE_SUSPEND(dev); 4977a9ca1c79SSean Bruno else if (new_ps == 0 && curr_ps == 3) 4978a9ca1c79SSean Bruno error = DEVICE_RESUME(dev); 4979a9ca1c79SSean Bruno else 4980a9ca1c79SSean Bruno return (EINVAL); 4981a9ca1c79SSean Bruno 4982a9ca1c79SSean Bruno device_printf(dev, "New state: %d\n", pci_get_powerstate(dev)); 4983a9ca1c79SSean Bruno 4984a9ca1c79SSean Bruno return (error); 4985a9ca1c79SSean Bruno } 4986a9ca1c79SSean Bruno #endif 49876f37f232SEric Joyner /* 49886f37f232SEric Joyner * Sysctl to enable/disable the WoL capability, if supported by the adapter. 49896f37f232SEric Joyner * Values: 49906f37f232SEric Joyner * 0 - disabled 49916f37f232SEric Joyner * 1 - enabled 49926f37f232SEric Joyner */ 49936f37f232SEric Joyner static int 49946f37f232SEric Joyner ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS) 49956f37f232SEric Joyner { 49966f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 49976f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 49986f37f232SEric Joyner int new_wol_enabled; 49996f37f232SEric Joyner int error = 0; 50006f37f232SEric Joyner 50016f37f232SEric Joyner new_wol_enabled = hw->wol_enabled; 50026f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req); 50036f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 50046f37f232SEric Joyner return (error); 5005a9ca1c79SSean Bruno new_wol_enabled = !!(new_wol_enabled); 50066f37f232SEric Joyner if (new_wol_enabled == hw->wol_enabled) 50076f37f232SEric Joyner return (0); 50086f37f232SEric Joyner 50096f37f232SEric Joyner if (new_wol_enabled > 0 && !adapter->wol_support) 50106f37f232SEric Joyner return (ENODEV); 50116f37f232SEric Joyner else 5012a9ca1c79SSean Bruno hw->wol_enabled = new_wol_enabled; 50136f37f232SEric Joyner 50146f37f232SEric Joyner return (0); 50156f37f232SEric Joyner } 50166f37f232SEric Joyner 50176f37f232SEric Joyner /* 50186f37f232SEric Joyner * Sysctl to enable/disable the Energy Efficient Ethernet capability, 50196f37f232SEric Joyner * if supported by the adapter. 50206f37f232SEric Joyner * Values: 50216f37f232SEric Joyner * 0 - disabled 50226f37f232SEric Joyner * 1 - enabled 50236f37f232SEric Joyner */ 50246f37f232SEric Joyner static int 50256f37f232SEric Joyner ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS) 50266f37f232SEric Joyner { 50276f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 502848056c88SJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 50296f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 50306f37f232SEric Joyner int new_eee_enabled, error = 0; 50316f37f232SEric Joyner 50326f37f232SEric Joyner new_eee_enabled = adapter->eee_enabled; 50336f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_eee_enabled, 0, req); 50346f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 50356f37f232SEric Joyner return (error); 5036a9ca1c79SSean Bruno new_eee_enabled = !!(new_eee_enabled); 50376f37f232SEric Joyner if (new_eee_enabled == adapter->eee_enabled) 50386f37f232SEric Joyner return (0); 50396f37f232SEric Joyner 504048056c88SJack F Vogel if (new_eee_enabled > 0 && !hw->mac.ops.setup_eee) 50416f37f232SEric Joyner return (ENODEV); 50426f37f232SEric Joyner else 5043a9ca1c79SSean Bruno adapter->eee_enabled = new_eee_enabled; 50446f37f232SEric Joyner 50456f37f232SEric Joyner /* Re-initialize hardware if it's already running */ 50466f37f232SEric Joyner if (ifp->if_drv_flags & IFF_DRV_RUNNING) 50476f37f232SEric Joyner ixgbe_init(adapter); 50486f37f232SEric Joyner 50496f37f232SEric Joyner return (0); 50506f37f232SEric Joyner } 50516f37f232SEric Joyner 50526f37f232SEric Joyner /* 50536f37f232SEric Joyner * Read-only sysctl indicating whether EEE support was negotiated 50546f37f232SEric Joyner * on the link. 50556f37f232SEric Joyner */ 50566f37f232SEric Joyner static int 50576f37f232SEric Joyner ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS) 50586f37f232SEric Joyner { 50596f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 50606f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 50616f37f232SEric Joyner bool status; 50626f37f232SEric Joyner 50636f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & IXGBE_EEE_STAT_NEG); 50646f37f232SEric Joyner 50656f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 50666f37f232SEric Joyner } 50676f37f232SEric Joyner 50686f37f232SEric Joyner /* 50696f37f232SEric Joyner * Read-only sysctl indicating whether RX Link is in LPI state. 50706f37f232SEric Joyner */ 50716f37f232SEric Joyner static int 50726f37f232SEric Joyner ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS) 50736f37f232SEric Joyner { 50746f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 50756f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 50766f37f232SEric Joyner bool status; 50776f37f232SEric Joyner 50786f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & 50796f37f232SEric Joyner IXGBE_EEE_RX_LPI_STATUS); 50806f37f232SEric Joyner 50816f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 50826f37f232SEric Joyner } 50836f37f232SEric Joyner 50846f37f232SEric Joyner /* 50856f37f232SEric Joyner * Read-only sysctl indicating whether TX Link is in LPI state. 50866f37f232SEric Joyner */ 50876f37f232SEric Joyner static int 50886f37f232SEric Joyner ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS) 50896f37f232SEric Joyner { 50906f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 50916f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 50926f37f232SEric Joyner bool status; 50936f37f232SEric Joyner 50946f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & 50956f37f232SEric Joyner IXGBE_EEE_TX_LPI_STATUS); 50966f37f232SEric Joyner 50976f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 50986f37f232SEric Joyner } 50996f37f232SEric Joyner 51006f37f232SEric Joyner /* 5101a9ca1c79SSean Bruno * Read-only sysctl indicating TX Link LPI delay 5102a9ca1c79SSean Bruno */ 5103a9ca1c79SSean Bruno static int 5104a9ca1c79SSean Bruno ixgbe_sysctl_eee_tx_lpi_delay(SYSCTL_HANDLER_ARGS) 5105a9ca1c79SSean Bruno { 5106a9ca1c79SSean Bruno struct adapter *adapter = (struct adapter *) arg1; 5107a9ca1c79SSean Bruno struct ixgbe_hw *hw = &adapter->hw; 5108a9ca1c79SSean Bruno u32 reg; 5109a9ca1c79SSean Bruno 5110a9ca1c79SSean Bruno reg = IXGBE_READ_REG(hw, IXGBE_EEE_SU); 5111a9ca1c79SSean Bruno 5112a9ca1c79SSean Bruno return (sysctl_handle_int(oidp, 0, reg >> 26, req)); 5113a9ca1c79SSean Bruno } 5114a9ca1c79SSean Bruno 5115a9ca1c79SSean Bruno /* 51166f37f232SEric Joyner * Sysctl to enable/disable the types of packets that the 51176f37f232SEric Joyner * adapter will wake up on upon receipt. 51186f37f232SEric Joyner * WUFC - Wake Up Filter Control 51196f37f232SEric Joyner * Flags: 51206f37f232SEric Joyner * 0x1 - Link Status Change 51216f37f232SEric Joyner * 0x2 - Magic Packet 51226f37f232SEric Joyner * 0x4 - Direct Exact 51236f37f232SEric Joyner * 0x8 - Directed Multicast 51246f37f232SEric Joyner * 0x10 - Broadcast 51256f37f232SEric Joyner * 0x20 - ARP/IPv4 Request Packet 51266f37f232SEric Joyner * 0x40 - Direct IPv4 Packet 51276f37f232SEric Joyner * 0x80 - Direct IPv6 Packet 51286f37f232SEric Joyner * 51296f37f232SEric Joyner * Setting another flag will cause the sysctl to return an 51306f37f232SEric Joyner * error. 51316f37f232SEric Joyner */ 51326f37f232SEric Joyner static int 51336f37f232SEric Joyner ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS) 51346f37f232SEric Joyner { 51356f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 51366f37f232SEric Joyner int error = 0; 51376f37f232SEric Joyner u32 new_wufc; 51386f37f232SEric Joyner 51396f37f232SEric Joyner new_wufc = adapter->wufc; 51406f37f232SEric Joyner 51416f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_wufc, 0, req); 51426f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 51436f37f232SEric Joyner return (error); 51446f37f232SEric Joyner if (new_wufc == adapter->wufc) 51456f37f232SEric Joyner return (0); 51466f37f232SEric Joyner 51476f37f232SEric Joyner if (new_wufc & 0xffffff00) 51486f37f232SEric Joyner return (EINVAL); 51496f37f232SEric Joyner else { 51506f37f232SEric Joyner new_wufc &= 0xff; 51516f37f232SEric Joyner new_wufc |= (0xffffff & adapter->wufc); 51526f37f232SEric Joyner adapter->wufc = new_wufc; 51536f37f232SEric Joyner } 51546f37f232SEric Joyner 51556f37f232SEric Joyner return (0); 51566f37f232SEric Joyner } 51576f37f232SEric Joyner 5158a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG 5159a9ca1c79SSean Bruno static int 5160a9ca1c79SSean Bruno ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS) 5161a9ca1c79SSean Bruno { 5162a9ca1c79SSean Bruno struct adapter *adapter = (struct adapter *)arg1; 5163a9ca1c79SSean Bruno struct ixgbe_hw *hw = &adapter->hw; 5164a9ca1c79SSean Bruno device_t dev = adapter->dev; 5165a9ca1c79SSean Bruno int error = 0, reta_size; 5166a9ca1c79SSean Bruno struct sbuf *buf; 5167a9ca1c79SSean Bruno u32 reg; 5168a9ca1c79SSean Bruno 5169a9ca1c79SSean Bruno buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5170a9ca1c79SSean Bruno if (!buf) { 5171a9ca1c79SSean Bruno device_printf(dev, "Could not allocate sbuf for output.\n"); 5172a9ca1c79SSean Bruno return (ENOMEM); 5173a9ca1c79SSean Bruno } 5174a9ca1c79SSean Bruno 5175a9ca1c79SSean Bruno // TODO: use sbufs to make a string to print out 5176a9ca1c79SSean Bruno /* Set multiplier for RETA setup and table size based on MAC */ 5177a9ca1c79SSean Bruno switch (adapter->hw.mac.type) { 5178a9ca1c79SSean Bruno case ixgbe_mac_X550: 5179a9ca1c79SSean Bruno case ixgbe_mac_X550EM_x: 5180a9ca1c79SSean Bruno reta_size = 128; 5181a9ca1c79SSean Bruno break; 5182a9ca1c79SSean Bruno default: 5183a9ca1c79SSean Bruno reta_size = 32; 5184a9ca1c79SSean Bruno break; 5185a9ca1c79SSean Bruno } 5186a9ca1c79SSean Bruno 5187a9ca1c79SSean Bruno /* Print out the redirection table */ 5188a9ca1c79SSean Bruno sbuf_cat(buf, "\n"); 5189a9ca1c79SSean Bruno for (int i = 0; i < reta_size; i++) { 5190a9ca1c79SSean Bruno if (i < 32) { 5191a9ca1c79SSean Bruno reg = IXGBE_READ_REG(hw, IXGBE_RETA(i)); 5192a9ca1c79SSean Bruno sbuf_printf(buf, "RETA(%2d): 0x%08x\n", i, reg); 5193a9ca1c79SSean Bruno } else { 5194a9ca1c79SSean Bruno reg = IXGBE_READ_REG(hw, IXGBE_ERETA(i - 32)); 5195a9ca1c79SSean Bruno sbuf_printf(buf, "ERETA(%2d): 0x%08x\n", i - 32, reg); 5196a9ca1c79SSean Bruno } 5197a9ca1c79SSean Bruno } 5198a9ca1c79SSean Bruno 5199a9ca1c79SSean Bruno // TODO: print more config 5200a9ca1c79SSean Bruno 5201a9ca1c79SSean Bruno error = sbuf_finish(buf); 5202a9ca1c79SSean Bruno if (error) 5203a9ca1c79SSean Bruno device_printf(dev, "Error finishing sbuf: %d\n", error); 5204a9ca1c79SSean Bruno 5205a9ca1c79SSean Bruno sbuf_delete(buf); 5206a9ca1c79SSean Bruno return (0); 5207a9ca1c79SSean Bruno } 5208a9ca1c79SSean Bruno #endif /* IXGBE_DEBUG */ 5209a9ca1c79SSean Bruno 52106f37f232SEric Joyner /* 5211758cc3dcSJack F Vogel ** Enable the hardware to drop packets when the buffer is 5212758cc3dcSJack F Vogel ** full. This is useful when multiqueue,so that no single 5213758cc3dcSJack F Vogel ** queue being full stalls the entire RX engine. We only 5214758cc3dcSJack F Vogel ** enable this when Multiqueue AND when Flow Control is 5215758cc3dcSJack F Vogel ** disabled. 5216758cc3dcSJack F Vogel */ 5217758cc3dcSJack F Vogel static void 5218758cc3dcSJack F Vogel ixgbe_enable_rx_drop(struct adapter *adapter) 5219758cc3dcSJack F Vogel { 5220758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 5221758cc3dcSJack F Vogel 5222758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 522348056c88SJack F Vogel struct rx_ring *rxr = &adapter->rx_rings[i]; 522448056c88SJack F Vogel u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); 5225758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DROP_EN; 522648056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); 5227758cc3dcSJack F Vogel } 522848056c88SJack F Vogel #ifdef PCI_IOV 522948056c88SJack F Vogel /* enable drop for each vf */ 523048056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 523148056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_QDE, 523248056c88SJack F Vogel (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT) | 523348056c88SJack F Vogel IXGBE_QDE_ENABLE)); 523448056c88SJack F Vogel } 523548056c88SJack F Vogel #endif 5236758cc3dcSJack F Vogel } 5237758cc3dcSJack F Vogel 5238758cc3dcSJack F Vogel static void 5239758cc3dcSJack F Vogel ixgbe_disable_rx_drop(struct adapter *adapter) 5240758cc3dcSJack F Vogel { 5241758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 5242758cc3dcSJack F Vogel 5243758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 524448056c88SJack F Vogel struct rx_ring *rxr = &adapter->rx_rings[i]; 524548056c88SJack F Vogel u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); 5246758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_DROP_EN; 524748056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); 5248758cc3dcSJack F Vogel } 524948056c88SJack F Vogel #ifdef PCI_IOV 525048056c88SJack F Vogel /* disable drop for each vf */ 525148056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 525248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_QDE, 525348056c88SJack F Vogel (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT))); 525448056c88SJack F Vogel } 525548056c88SJack F Vogel #endif 5256758cc3dcSJack F Vogel } 5257758cc3dcSJack F Vogel 5258758cc3dcSJack F Vogel static void 5259758cc3dcSJack F Vogel ixgbe_rearm_queues(struct adapter *adapter, u64 queues) 5260758cc3dcSJack F Vogel { 5261758cc3dcSJack F Vogel u32 mask; 5262758cc3dcSJack F Vogel 5263758cc3dcSJack F Vogel switch (adapter->hw.mac.type) { 5264758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 5265758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queues); 5266758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); 5267758cc3dcSJack F Vogel break; 5268758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 5269758cc3dcSJack F Vogel case ixgbe_mac_X540: 5270758cc3dcSJack F Vogel case ixgbe_mac_X550: 52716f37f232SEric Joyner case ixgbe_mac_X550EM_x: 5272758cc3dcSJack F Vogel mask = (queues & 0xFFFFFFFF); 5273758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); 5274758cc3dcSJack F Vogel mask = (queues >> 32); 5275758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); 5276758cc3dcSJack F Vogel break; 5277758cc3dcSJack F Vogel default: 5278758cc3dcSJack F Vogel break; 5279758cc3dcSJack F Vogel } 5280758cc3dcSJack F Vogel } 5281758cc3dcSJack F Vogel 528248056c88SJack F Vogel #ifdef PCI_IOV 528348056c88SJack F Vogel 528448056c88SJack F Vogel /* 528548056c88SJack F Vogel ** Support functions for SRIOV/VF management 528648056c88SJack F Vogel */ 528748056c88SJack F Vogel 528848056c88SJack F Vogel static void 528948056c88SJack F Vogel ixgbe_ping_all_vfs(struct adapter *adapter) 529048056c88SJack F Vogel { 529148056c88SJack F Vogel struct ixgbe_vf *vf; 529248056c88SJack F Vogel 529348056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 529448056c88SJack F Vogel vf = &adapter->vfs[i]; 529548056c88SJack F Vogel if (vf->flags & IXGBE_VF_ACTIVE) 529648056c88SJack F Vogel ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); 529748056c88SJack F Vogel } 529848056c88SJack F Vogel } 529948056c88SJack F Vogel 530048056c88SJack F Vogel 530148056c88SJack F Vogel static void 530248056c88SJack F Vogel ixgbe_vf_set_default_vlan(struct adapter *adapter, struct ixgbe_vf *vf, 530348056c88SJack F Vogel uint16_t tag) 530448056c88SJack F Vogel { 530548056c88SJack F Vogel struct ixgbe_hw *hw; 530648056c88SJack F Vogel uint32_t vmolr, vmvir; 530748056c88SJack F Vogel 530848056c88SJack F Vogel hw = &adapter->hw; 530948056c88SJack F Vogel 531048056c88SJack F Vogel vf->vlan_tag = tag; 531148056c88SJack F Vogel 531248056c88SJack F Vogel vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool)); 531348056c88SJack F Vogel 531448056c88SJack F Vogel /* Do not receive packets that pass inexact filters. */ 531548056c88SJack F Vogel vmolr &= ~(IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_ROPE); 531648056c88SJack F Vogel 531748056c88SJack F Vogel /* Disable Multicast Promicuous Mode. */ 531848056c88SJack F Vogel vmolr &= ~IXGBE_VMOLR_MPE; 531948056c88SJack F Vogel 532048056c88SJack F Vogel /* Accept broadcasts. */ 532148056c88SJack F Vogel vmolr |= IXGBE_VMOLR_BAM; 532248056c88SJack F Vogel 532348056c88SJack F Vogel if (tag == 0) { 532448056c88SJack F Vogel /* Accept non-vlan tagged traffic. */ 532548056c88SJack F Vogel //vmolr |= IXGBE_VMOLR_AUPE; 532648056c88SJack F Vogel 532748056c88SJack F Vogel /* Allow VM to tag outgoing traffic; no default tag. */ 532848056c88SJack F Vogel vmvir = 0; 532948056c88SJack F Vogel } else { 533048056c88SJack F Vogel /* Require vlan-tagged traffic. */ 533148056c88SJack F Vogel vmolr &= ~IXGBE_VMOLR_AUPE; 533248056c88SJack F Vogel 533348056c88SJack F Vogel /* Tag all traffic with provided vlan tag. */ 533448056c88SJack F Vogel vmvir = (tag | IXGBE_VMVIR_VLANA_DEFAULT); 533548056c88SJack F Vogel } 533648056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr); 533748056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir); 533848056c88SJack F Vogel } 533948056c88SJack F Vogel 534048056c88SJack F Vogel 534148056c88SJack F Vogel static boolean_t 534248056c88SJack F Vogel ixgbe_vf_frame_size_compatible(struct adapter *adapter, struct ixgbe_vf *vf) 534348056c88SJack F Vogel { 534448056c88SJack F Vogel 534548056c88SJack F Vogel /* 534648056c88SJack F Vogel * Frame size compatibility between PF and VF is only a problem on 534748056c88SJack F Vogel * 82599-based cards. X540 and later support any combination of jumbo 534848056c88SJack F Vogel * frames on PFs and VFs. 534948056c88SJack F Vogel */ 535048056c88SJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82599EB) 535148056c88SJack F Vogel return (TRUE); 535248056c88SJack F Vogel 535348056c88SJack F Vogel switch (vf->api_ver) { 535448056c88SJack F Vogel case IXGBE_API_VER_1_0: 535548056c88SJack F Vogel case IXGBE_API_VER_UNKNOWN: 535648056c88SJack F Vogel /* 535748056c88SJack F Vogel * On legacy (1.0 and older) VF versions, we don't support jumbo 535848056c88SJack F Vogel * frames on either the PF or the VF. 535948056c88SJack F Vogel */ 536048056c88SJack F Vogel if (adapter->max_frame_size > ETHER_MAX_LEN || 536148056c88SJack F Vogel vf->max_frame_size > ETHER_MAX_LEN) 536248056c88SJack F Vogel return (FALSE); 536348056c88SJack F Vogel 536448056c88SJack F Vogel return (TRUE); 536548056c88SJack F Vogel 536648056c88SJack F Vogel break; 536748056c88SJack F Vogel case IXGBE_API_VER_1_1: 536848056c88SJack F Vogel default: 536948056c88SJack F Vogel /* 537048056c88SJack F Vogel * 1.1 or later VF versions always work if they aren't using 537148056c88SJack F Vogel * jumbo frames. 537248056c88SJack F Vogel */ 537348056c88SJack F Vogel if (vf->max_frame_size <= ETHER_MAX_LEN) 537448056c88SJack F Vogel return (TRUE); 537548056c88SJack F Vogel 537648056c88SJack F Vogel /* 537748056c88SJack F Vogel * Jumbo frames only work with VFs if the PF is also using jumbo 537848056c88SJack F Vogel * frames. 537948056c88SJack F Vogel */ 538048056c88SJack F Vogel if (adapter->max_frame_size <= ETHER_MAX_LEN) 538148056c88SJack F Vogel return (TRUE); 538248056c88SJack F Vogel 538348056c88SJack F Vogel return (FALSE); 538448056c88SJack F Vogel 538548056c88SJack F Vogel } 538648056c88SJack F Vogel } 538748056c88SJack F Vogel 538848056c88SJack F Vogel 538948056c88SJack F Vogel static void 539048056c88SJack F Vogel ixgbe_process_vf_reset(struct adapter *adapter, struct ixgbe_vf *vf) 539148056c88SJack F Vogel { 539248056c88SJack F Vogel ixgbe_vf_set_default_vlan(adapter, vf, vf->default_vlan); 539348056c88SJack F Vogel 539448056c88SJack F Vogel // XXX clear multicast addresses 539548056c88SJack F Vogel 539648056c88SJack F Vogel ixgbe_clear_rar(&adapter->hw, vf->rar_index); 539748056c88SJack F Vogel 539848056c88SJack F Vogel vf->api_ver = IXGBE_API_VER_UNKNOWN; 539948056c88SJack F Vogel } 540048056c88SJack F Vogel 540148056c88SJack F Vogel 540248056c88SJack F Vogel static void 540348056c88SJack F Vogel ixgbe_vf_enable_transmit(struct adapter *adapter, struct ixgbe_vf *vf) 540448056c88SJack F Vogel { 540548056c88SJack F Vogel struct ixgbe_hw *hw; 540648056c88SJack F Vogel uint32_t vf_index, vfte; 540748056c88SJack F Vogel 540848056c88SJack F Vogel hw = &adapter->hw; 540948056c88SJack F Vogel 541048056c88SJack F Vogel vf_index = IXGBE_VF_INDEX(vf->pool); 541148056c88SJack F Vogel vfte = IXGBE_READ_REG(hw, IXGBE_VFTE(vf_index)); 541248056c88SJack F Vogel vfte |= IXGBE_VF_BIT(vf->pool); 541348056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_index), vfte); 541448056c88SJack F Vogel } 541548056c88SJack F Vogel 541648056c88SJack F Vogel 541748056c88SJack F Vogel static void 541848056c88SJack F Vogel ixgbe_vf_enable_receive(struct adapter *adapter, struct ixgbe_vf *vf) 541948056c88SJack F Vogel { 542048056c88SJack F Vogel struct ixgbe_hw *hw; 542148056c88SJack F Vogel uint32_t vf_index, vfre; 542248056c88SJack F Vogel 542348056c88SJack F Vogel hw = &adapter->hw; 542448056c88SJack F Vogel 542548056c88SJack F Vogel vf_index = IXGBE_VF_INDEX(vf->pool); 542648056c88SJack F Vogel vfre = IXGBE_READ_REG(hw, IXGBE_VFRE(vf_index)); 542748056c88SJack F Vogel if (ixgbe_vf_frame_size_compatible(adapter, vf)) 542848056c88SJack F Vogel vfre |= IXGBE_VF_BIT(vf->pool); 542948056c88SJack F Vogel else 543048056c88SJack F Vogel vfre &= ~IXGBE_VF_BIT(vf->pool); 543148056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_index), vfre); 543248056c88SJack F Vogel } 543348056c88SJack F Vogel 543448056c88SJack F Vogel 543548056c88SJack F Vogel static void 543648056c88SJack F Vogel ixgbe_vf_reset_msg(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 543748056c88SJack F Vogel { 543848056c88SJack F Vogel struct ixgbe_hw *hw; 543948056c88SJack F Vogel uint32_t ack; 544048056c88SJack F Vogel uint32_t resp[IXGBE_VF_PERMADDR_MSG_LEN]; 544148056c88SJack F Vogel 544248056c88SJack F Vogel hw = &adapter->hw; 544348056c88SJack F Vogel 544448056c88SJack F Vogel ixgbe_process_vf_reset(adapter, vf); 544548056c88SJack F Vogel 544648056c88SJack F Vogel if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { 544748056c88SJack F Vogel ixgbe_set_rar(&adapter->hw, vf->rar_index, 544848056c88SJack F Vogel vf->ether_addr, vf->pool, TRUE); 544948056c88SJack F Vogel ack = IXGBE_VT_MSGTYPE_ACK; 545048056c88SJack F Vogel } else 545148056c88SJack F Vogel ack = IXGBE_VT_MSGTYPE_NACK; 545248056c88SJack F Vogel 545348056c88SJack F Vogel ixgbe_vf_enable_transmit(adapter, vf); 545448056c88SJack F Vogel ixgbe_vf_enable_receive(adapter, vf); 545548056c88SJack F Vogel 545648056c88SJack F Vogel vf->flags |= IXGBE_VF_CTS; 545748056c88SJack F Vogel 545848056c88SJack F Vogel resp[0] = IXGBE_VF_RESET | ack | IXGBE_VT_MSGTYPE_CTS; 545948056c88SJack F Vogel bcopy(vf->ether_addr, &resp[1], ETHER_ADDR_LEN); 546048056c88SJack F Vogel resp[3] = hw->mac.mc_filter_type; 546148056c88SJack F Vogel ixgbe_write_mbx(hw, resp, IXGBE_VF_PERMADDR_MSG_LEN, vf->pool); 546248056c88SJack F Vogel } 546348056c88SJack F Vogel 546448056c88SJack F Vogel 546548056c88SJack F Vogel static void 546648056c88SJack F Vogel ixgbe_vf_set_mac(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 546748056c88SJack F Vogel { 546848056c88SJack F Vogel uint8_t *mac; 546948056c88SJack F Vogel 547048056c88SJack F Vogel mac = (uint8_t*)&msg[1]; 547148056c88SJack F Vogel 547248056c88SJack F Vogel /* Check that the VF has permission to change the MAC address. */ 547348056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_CAP_MAC) && ixgbe_vf_mac_changed(vf, mac)) { 547448056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 547548056c88SJack F Vogel return; 547648056c88SJack F Vogel } 547748056c88SJack F Vogel 547848056c88SJack F Vogel if (ixgbe_validate_mac_addr(mac) != 0) { 547948056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 548048056c88SJack F Vogel return; 548148056c88SJack F Vogel } 548248056c88SJack F Vogel 548348056c88SJack F Vogel bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); 548448056c88SJack F Vogel 548548056c88SJack F Vogel ixgbe_set_rar(&adapter->hw, vf->rar_index, vf->ether_addr, 548648056c88SJack F Vogel vf->pool, TRUE); 548748056c88SJack F Vogel 548848056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 548948056c88SJack F Vogel } 549048056c88SJack F Vogel 549148056c88SJack F Vogel 549248056c88SJack F Vogel /* 549348056c88SJack F Vogel ** VF multicast addresses are set by using the appropriate bit in 549448056c88SJack F Vogel ** 1 of 128 32 bit addresses (4096 possible). 549548056c88SJack F Vogel */ 549648056c88SJack F Vogel static void 549748056c88SJack F Vogel ixgbe_vf_set_mc_addr(struct adapter *adapter, struct ixgbe_vf *vf, u32 *msg) 549848056c88SJack F Vogel { 549948056c88SJack F Vogel u16 *list = (u16*)&msg[1]; 550048056c88SJack F Vogel int entries; 550148056c88SJack F Vogel u32 vmolr, vec_bit, vec_reg, mta_reg; 550248056c88SJack F Vogel 550348056c88SJack F Vogel entries = (msg[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT; 550448056c88SJack F Vogel entries = min(entries, IXGBE_MAX_VF_MC); 550548056c88SJack F Vogel 550648056c88SJack F Vogel vmolr = IXGBE_READ_REG(&adapter->hw, IXGBE_VMOLR(vf->pool)); 550748056c88SJack F Vogel 550848056c88SJack F Vogel vf->num_mc_hashes = entries; 550948056c88SJack F Vogel 551048056c88SJack F Vogel /* Set the appropriate MTA bit */ 551148056c88SJack F Vogel for (int i = 0; i < entries; i++) { 551248056c88SJack F Vogel vf->mc_hash[i] = list[i]; 551348056c88SJack F Vogel vec_reg = (vf->mc_hash[i] >> 5) & 0x7F; 551448056c88SJack F Vogel vec_bit = vf->mc_hash[i] & 0x1F; 551548056c88SJack F Vogel mta_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_MTA(vec_reg)); 551648056c88SJack F Vogel mta_reg |= (1 << vec_bit); 551748056c88SJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_MTA(vec_reg), mta_reg); 551848056c88SJack F Vogel } 551948056c88SJack F Vogel 552048056c88SJack F Vogel vmolr |= IXGBE_VMOLR_ROMPE; 552148056c88SJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_VMOLR(vf->pool), vmolr); 552248056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 552348056c88SJack F Vogel return; 552448056c88SJack F Vogel } 552548056c88SJack F Vogel 552648056c88SJack F Vogel 552748056c88SJack F Vogel static void 552848056c88SJack F Vogel ixgbe_vf_set_vlan(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 552948056c88SJack F Vogel { 553048056c88SJack F Vogel struct ixgbe_hw *hw; 553148056c88SJack F Vogel int enable; 553248056c88SJack F Vogel uint16_t tag; 553348056c88SJack F Vogel 553448056c88SJack F Vogel hw = &adapter->hw; 553548056c88SJack F Vogel enable = IXGBE_VT_MSGINFO(msg[0]); 553648056c88SJack F Vogel tag = msg[1] & IXGBE_VLVF_VLANID_MASK; 553748056c88SJack F Vogel 553848056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_CAP_VLAN)) { 553948056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 554048056c88SJack F Vogel return; 554148056c88SJack F Vogel } 554248056c88SJack F Vogel 554348056c88SJack F Vogel /* It is illegal to enable vlan tag 0. */ 554448056c88SJack F Vogel if (tag == 0 && enable != 0){ 554548056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 554648056c88SJack F Vogel return; 554748056c88SJack F Vogel } 554848056c88SJack F Vogel 554948056c88SJack F Vogel ixgbe_set_vfta(hw, tag, vf->pool, enable); 555048056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 555148056c88SJack F Vogel } 555248056c88SJack F Vogel 555348056c88SJack F Vogel 555448056c88SJack F Vogel static void 555548056c88SJack F Vogel ixgbe_vf_set_lpe(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 555648056c88SJack F Vogel { 555748056c88SJack F Vogel struct ixgbe_hw *hw; 555848056c88SJack F Vogel uint32_t vf_max_size, pf_max_size, mhadd; 555948056c88SJack F Vogel 556048056c88SJack F Vogel hw = &adapter->hw; 556148056c88SJack F Vogel vf_max_size = msg[1]; 556248056c88SJack F Vogel 556348056c88SJack F Vogel if (vf_max_size < ETHER_CRC_LEN) { 556448056c88SJack F Vogel /* We intentionally ACK invalid LPE requests. */ 556548056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 556648056c88SJack F Vogel return; 556748056c88SJack F Vogel } 556848056c88SJack F Vogel 556948056c88SJack F Vogel vf_max_size -= ETHER_CRC_LEN; 557048056c88SJack F Vogel 557148056c88SJack F Vogel if (vf_max_size > IXGBE_MAX_FRAME_SIZE) { 557248056c88SJack F Vogel /* We intentionally ACK invalid LPE requests. */ 557348056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 557448056c88SJack F Vogel return; 557548056c88SJack F Vogel } 557648056c88SJack F Vogel 557748056c88SJack F Vogel vf->max_frame_size = vf_max_size; 557848056c88SJack F Vogel ixgbe_update_max_frame(adapter, vf->max_frame_size); 557948056c88SJack F Vogel 558048056c88SJack F Vogel /* 558148056c88SJack F Vogel * We might have to disable reception to this VF if the frame size is 558248056c88SJack F Vogel * not compatible with the config on the PF. 558348056c88SJack F Vogel */ 558448056c88SJack F Vogel ixgbe_vf_enable_receive(adapter, vf); 558548056c88SJack F Vogel 558648056c88SJack F Vogel mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); 558748056c88SJack F Vogel pf_max_size = (mhadd & IXGBE_MHADD_MFS_MASK) >> IXGBE_MHADD_MFS_SHIFT; 558848056c88SJack F Vogel 558948056c88SJack F Vogel if (pf_max_size < adapter->max_frame_size) { 559048056c88SJack F Vogel mhadd &= ~IXGBE_MHADD_MFS_MASK; 559148056c88SJack F Vogel mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; 559248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); 559348056c88SJack F Vogel } 559448056c88SJack F Vogel 559548056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 559648056c88SJack F Vogel } 559748056c88SJack F Vogel 559848056c88SJack F Vogel 559948056c88SJack F Vogel static void 560048056c88SJack F Vogel ixgbe_vf_set_macvlan(struct adapter *adapter, struct ixgbe_vf *vf, 560148056c88SJack F Vogel uint32_t *msg) 560248056c88SJack F Vogel { 560348056c88SJack F Vogel //XXX implement this 560448056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 560548056c88SJack F Vogel } 560648056c88SJack F Vogel 560748056c88SJack F Vogel 560848056c88SJack F Vogel static void 560948056c88SJack F Vogel ixgbe_vf_api_negotiate(struct adapter *adapter, struct ixgbe_vf *vf, 561048056c88SJack F Vogel uint32_t *msg) 561148056c88SJack F Vogel { 561248056c88SJack F Vogel 5613c8ed84dbSPatrick Kelsey switch (msg[1]) { 561448056c88SJack F Vogel case IXGBE_API_VER_1_0: 561548056c88SJack F Vogel case IXGBE_API_VER_1_1: 5616c8ed84dbSPatrick Kelsey vf->api_ver = msg[1]; 561748056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 561848056c88SJack F Vogel break; 561948056c88SJack F Vogel default: 562048056c88SJack F Vogel vf->api_ver = IXGBE_API_VER_UNKNOWN; 562148056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 562248056c88SJack F Vogel break; 562348056c88SJack F Vogel } 562448056c88SJack F Vogel } 562548056c88SJack F Vogel 562648056c88SJack F Vogel 562748056c88SJack F Vogel static void 562848056c88SJack F Vogel ixgbe_vf_get_queues(struct adapter *adapter, struct ixgbe_vf *vf, 562948056c88SJack F Vogel uint32_t *msg) 563048056c88SJack F Vogel { 563148056c88SJack F Vogel struct ixgbe_hw *hw; 563248056c88SJack F Vogel uint32_t resp[IXGBE_VF_GET_QUEUES_RESP_LEN]; 563348056c88SJack F Vogel int num_queues; 563448056c88SJack F Vogel 563548056c88SJack F Vogel hw = &adapter->hw; 563648056c88SJack F Vogel 563748056c88SJack F Vogel /* GET_QUEUES is not supported on pre-1.1 APIs. */ 563848056c88SJack F Vogel switch (msg[0]) { 563948056c88SJack F Vogel case IXGBE_API_VER_1_0: 564048056c88SJack F Vogel case IXGBE_API_VER_UNKNOWN: 564148056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 564248056c88SJack F Vogel return; 564348056c88SJack F Vogel } 564448056c88SJack F Vogel 564548056c88SJack F Vogel resp[0] = IXGBE_VF_GET_QUEUES | IXGBE_VT_MSGTYPE_ACK | 564648056c88SJack F Vogel IXGBE_VT_MSGTYPE_CTS; 564748056c88SJack F Vogel 564848056c88SJack F Vogel num_queues = ixgbe_vf_queues(ixgbe_get_iov_mode(adapter)); 564948056c88SJack F Vogel resp[IXGBE_VF_TX_QUEUES] = num_queues; 565048056c88SJack F Vogel resp[IXGBE_VF_RX_QUEUES] = num_queues; 565148056c88SJack F Vogel resp[IXGBE_VF_TRANS_VLAN] = (vf->default_vlan != 0); 565248056c88SJack F Vogel resp[IXGBE_VF_DEF_QUEUE] = 0; 565348056c88SJack F Vogel 565448056c88SJack F Vogel ixgbe_write_mbx(hw, resp, IXGBE_VF_GET_QUEUES_RESP_LEN, vf->pool); 565548056c88SJack F Vogel } 565648056c88SJack F Vogel 565748056c88SJack F Vogel 565848056c88SJack F Vogel static void 565948056c88SJack F Vogel ixgbe_process_vf_msg(struct adapter *adapter, struct ixgbe_vf *vf) 566048056c88SJack F Vogel { 566148056c88SJack F Vogel struct ixgbe_hw *hw; 566248056c88SJack F Vogel uint32_t msg[IXGBE_VFMAILBOX_SIZE]; 566348056c88SJack F Vogel int error; 566448056c88SJack F Vogel 566548056c88SJack F Vogel hw = &adapter->hw; 566648056c88SJack F Vogel 566748056c88SJack F Vogel error = ixgbe_read_mbx(hw, msg, IXGBE_VFMAILBOX_SIZE, vf->pool); 566848056c88SJack F Vogel 566948056c88SJack F Vogel if (error != 0) 567048056c88SJack F Vogel return; 567148056c88SJack F Vogel 567248056c88SJack F Vogel CTR3(KTR_MALLOC, "%s: received msg %x from %d", 567348056c88SJack F Vogel adapter->ifp->if_xname, msg[0], vf->pool); 567448056c88SJack F Vogel if (msg[0] == IXGBE_VF_RESET) { 567548056c88SJack F Vogel ixgbe_vf_reset_msg(adapter, vf, msg); 567648056c88SJack F Vogel return; 567748056c88SJack F Vogel } 567848056c88SJack F Vogel 567948056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_CTS)) { 568048056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 568148056c88SJack F Vogel return; 568248056c88SJack F Vogel } 568348056c88SJack F Vogel 568448056c88SJack F Vogel switch (msg[0] & IXGBE_VT_MSG_MASK) { 568548056c88SJack F Vogel case IXGBE_VF_SET_MAC_ADDR: 568648056c88SJack F Vogel ixgbe_vf_set_mac(adapter, vf, msg); 568748056c88SJack F Vogel break; 568848056c88SJack F Vogel case IXGBE_VF_SET_MULTICAST: 568948056c88SJack F Vogel ixgbe_vf_set_mc_addr(adapter, vf, msg); 569048056c88SJack F Vogel break; 569148056c88SJack F Vogel case IXGBE_VF_SET_VLAN: 569248056c88SJack F Vogel ixgbe_vf_set_vlan(adapter, vf, msg); 569348056c88SJack F Vogel break; 569448056c88SJack F Vogel case IXGBE_VF_SET_LPE: 569548056c88SJack F Vogel ixgbe_vf_set_lpe(adapter, vf, msg); 569648056c88SJack F Vogel break; 569748056c88SJack F Vogel case IXGBE_VF_SET_MACVLAN: 569848056c88SJack F Vogel ixgbe_vf_set_macvlan(adapter, vf, msg); 569948056c88SJack F Vogel break; 570048056c88SJack F Vogel case IXGBE_VF_API_NEGOTIATE: 570148056c88SJack F Vogel ixgbe_vf_api_negotiate(adapter, vf, msg); 570248056c88SJack F Vogel break; 570348056c88SJack F Vogel case IXGBE_VF_GET_QUEUES: 570448056c88SJack F Vogel ixgbe_vf_get_queues(adapter, vf, msg); 570548056c88SJack F Vogel break; 570648056c88SJack F Vogel default: 570748056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 570848056c88SJack F Vogel } 570948056c88SJack F Vogel } 571048056c88SJack F Vogel 571148056c88SJack F Vogel 571248056c88SJack F Vogel /* 571348056c88SJack F Vogel * Tasklet for handling VF -> PF mailbox messages. 571448056c88SJack F Vogel */ 571548056c88SJack F Vogel static void 571648056c88SJack F Vogel ixgbe_handle_mbx(void *context, int pending) 571748056c88SJack F Vogel { 571848056c88SJack F Vogel struct adapter *adapter; 571948056c88SJack F Vogel struct ixgbe_hw *hw; 572048056c88SJack F Vogel struct ixgbe_vf *vf; 572148056c88SJack F Vogel int i; 572248056c88SJack F Vogel 572348056c88SJack F Vogel adapter = context; 572448056c88SJack F Vogel hw = &adapter->hw; 572548056c88SJack F Vogel 572648056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 572748056c88SJack F Vogel for (i = 0; i < adapter->num_vfs; i++) { 572848056c88SJack F Vogel vf = &adapter->vfs[i]; 572948056c88SJack F Vogel 573048056c88SJack F Vogel if (vf->flags & IXGBE_VF_ACTIVE) { 573148056c88SJack F Vogel if (ixgbe_check_for_rst(hw, vf->pool) == 0) 573248056c88SJack F Vogel ixgbe_process_vf_reset(adapter, vf); 573348056c88SJack F Vogel 573448056c88SJack F Vogel if (ixgbe_check_for_msg(hw, vf->pool) == 0) 573548056c88SJack F Vogel ixgbe_process_vf_msg(adapter, vf); 573648056c88SJack F Vogel 573748056c88SJack F Vogel if (ixgbe_check_for_ack(hw, vf->pool) == 0) 573848056c88SJack F Vogel ixgbe_process_vf_ack(adapter, vf); 573948056c88SJack F Vogel } 574048056c88SJack F Vogel } 574148056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 574248056c88SJack F Vogel } 574348056c88SJack F Vogel 574448056c88SJack F Vogel 574548056c88SJack F Vogel static int 574648056c88SJack F Vogel ixgbe_init_iov(device_t dev, u16 num_vfs, const nvlist_t *config) 574748056c88SJack F Vogel { 574848056c88SJack F Vogel struct adapter *adapter; 574948056c88SJack F Vogel enum ixgbe_iov_mode mode; 575048056c88SJack F Vogel 575148056c88SJack F Vogel adapter = device_get_softc(dev); 575248056c88SJack F Vogel adapter->num_vfs = num_vfs; 575348056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 575448056c88SJack F Vogel 575548056c88SJack F Vogel if (num_vfs > ixgbe_max_vfs(mode)) { 575648056c88SJack F Vogel adapter->num_vfs = 0; 575748056c88SJack F Vogel return (ENOSPC); 575848056c88SJack F Vogel } 575948056c88SJack F Vogel 576048056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 576148056c88SJack F Vogel 576248056c88SJack F Vogel adapter->vfs = malloc(sizeof(*adapter->vfs) * num_vfs, M_IXGBE, 576348056c88SJack F Vogel M_NOWAIT | M_ZERO); 576448056c88SJack F Vogel 576548056c88SJack F Vogel if (adapter->vfs == NULL) { 576648056c88SJack F Vogel adapter->num_vfs = 0; 576748056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 576848056c88SJack F Vogel return (ENOMEM); 576948056c88SJack F Vogel } 577048056c88SJack F Vogel 577148056c88SJack F Vogel ixgbe_init_locked(adapter); 577248056c88SJack F Vogel 577348056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 577448056c88SJack F Vogel 577548056c88SJack F Vogel return (0); 577648056c88SJack F Vogel } 577748056c88SJack F Vogel 577848056c88SJack F Vogel 577948056c88SJack F Vogel static void 578048056c88SJack F Vogel ixgbe_uninit_iov(device_t dev) 578148056c88SJack F Vogel { 578248056c88SJack F Vogel struct ixgbe_hw *hw; 578348056c88SJack F Vogel struct adapter *adapter; 578448056c88SJack F Vogel uint32_t pf_reg, vf_reg; 578548056c88SJack F Vogel 578648056c88SJack F Vogel adapter = device_get_softc(dev); 578748056c88SJack F Vogel hw = &adapter->hw; 578848056c88SJack F Vogel 578948056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 579048056c88SJack F Vogel 579148056c88SJack F Vogel /* Enable rx/tx for the PF and disable it for all VFs. */ 579248056c88SJack F Vogel pf_reg = IXGBE_VF_INDEX(adapter->pool); 579348056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(pf_reg), 579448056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 579548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(pf_reg), 579648056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 579748056c88SJack F Vogel 579848056c88SJack F Vogel if (pf_reg == 0) 579948056c88SJack F Vogel vf_reg = 1; 580048056c88SJack F Vogel else 580148056c88SJack F Vogel vf_reg = 0; 580248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 0); 580348056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 0); 580448056c88SJack F Vogel 580548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, 0); 580648056c88SJack F Vogel 580748056c88SJack F Vogel free(adapter->vfs, M_IXGBE); 580848056c88SJack F Vogel adapter->vfs = NULL; 580948056c88SJack F Vogel adapter->num_vfs = 0; 581048056c88SJack F Vogel 581148056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 581248056c88SJack F Vogel } 581348056c88SJack F Vogel 581448056c88SJack F Vogel 581548056c88SJack F Vogel static void 581648056c88SJack F Vogel ixgbe_initialize_iov(struct adapter *adapter) 581748056c88SJack F Vogel { 581848056c88SJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 581948056c88SJack F Vogel uint32_t mrqc, mtqc, vt_ctl, vf_reg, gcr_ext, gpie; 582048056c88SJack F Vogel enum ixgbe_iov_mode mode; 582148056c88SJack F Vogel int i; 582248056c88SJack F Vogel 582348056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 582448056c88SJack F Vogel if (mode == IXGBE_NO_VM) 582548056c88SJack F Vogel return; 582648056c88SJack F Vogel 582748056c88SJack F Vogel IXGBE_CORE_LOCK_ASSERT(adapter); 582848056c88SJack F Vogel 582948056c88SJack F Vogel mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC); 583048056c88SJack F Vogel mrqc &= ~IXGBE_MRQC_MRQE_MASK; 583148056c88SJack F Vogel 583248056c88SJack F Vogel switch (mode) { 583348056c88SJack F Vogel case IXGBE_64_VM: 583448056c88SJack F Vogel mrqc |= IXGBE_MRQC_VMDQRSS64EN; 583548056c88SJack F Vogel break; 583648056c88SJack F Vogel case IXGBE_32_VM: 583748056c88SJack F Vogel mrqc |= IXGBE_MRQC_VMDQRSS32EN; 583848056c88SJack F Vogel break; 583948056c88SJack F Vogel default: 584048056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 584148056c88SJack F Vogel } 584248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 584348056c88SJack F Vogel 584448056c88SJack F Vogel mtqc = IXGBE_MTQC_VT_ENA; 584548056c88SJack F Vogel switch (mode) { 584648056c88SJack F Vogel case IXGBE_64_VM: 584748056c88SJack F Vogel mtqc |= IXGBE_MTQC_64VF; 584848056c88SJack F Vogel break; 584948056c88SJack F Vogel case IXGBE_32_VM: 585048056c88SJack F Vogel mtqc |= IXGBE_MTQC_32VF; 585148056c88SJack F Vogel break; 585248056c88SJack F Vogel default: 585348056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 585448056c88SJack F Vogel } 585548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MTQC, mtqc); 585648056c88SJack F Vogel 585748056c88SJack F Vogel 585848056c88SJack F Vogel gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT); 585948056c88SJack F Vogel gcr_ext |= IXGBE_GCR_EXT_MSIX_EN; 586048056c88SJack F Vogel gcr_ext &= ~IXGBE_GCR_EXT_VT_MODE_MASK; 586148056c88SJack F Vogel switch (mode) { 586248056c88SJack F Vogel case IXGBE_64_VM: 586348056c88SJack F Vogel gcr_ext |= IXGBE_GCR_EXT_VT_MODE_64; 586448056c88SJack F Vogel break; 586548056c88SJack F Vogel case IXGBE_32_VM: 586648056c88SJack F Vogel gcr_ext |= IXGBE_GCR_EXT_VT_MODE_32; 586748056c88SJack F Vogel break; 586848056c88SJack F Vogel default: 586948056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 587048056c88SJack F Vogel } 587148056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext); 587248056c88SJack F Vogel 587348056c88SJack F Vogel 587448056c88SJack F Vogel gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); 587548056c88SJack F Vogel gcr_ext &= ~IXGBE_GPIE_VTMODE_MASK; 587648056c88SJack F Vogel switch (mode) { 587748056c88SJack F Vogel case IXGBE_64_VM: 587848056c88SJack F Vogel gpie |= IXGBE_GPIE_VTMODE_64; 587948056c88SJack F Vogel break; 588048056c88SJack F Vogel case IXGBE_32_VM: 588148056c88SJack F Vogel gpie |= IXGBE_GPIE_VTMODE_32; 588248056c88SJack F Vogel break; 588348056c88SJack F Vogel default: 588448056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 588548056c88SJack F Vogel } 588648056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 588748056c88SJack F Vogel 588848056c88SJack F Vogel /* Enable rx/tx for the PF. */ 588948056c88SJack F Vogel vf_reg = IXGBE_VF_INDEX(adapter->pool); 589048056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 589148056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 589248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 589348056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 589448056c88SJack F Vogel 589548056c88SJack F Vogel /* Allow VM-to-VM communication. */ 589648056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN); 589748056c88SJack F Vogel 589848056c88SJack F Vogel vt_ctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; 589948056c88SJack F Vogel vt_ctl |= (adapter->pool << IXGBE_VT_CTL_POOL_SHIFT); 590048056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vt_ctl); 590148056c88SJack F Vogel 590248056c88SJack F Vogel for (i = 0; i < adapter->num_vfs; i++) 590348056c88SJack F Vogel ixgbe_init_vf(adapter, &adapter->vfs[i]); 590448056c88SJack F Vogel } 590548056c88SJack F Vogel 590648056c88SJack F Vogel 590748056c88SJack F Vogel /* 590848056c88SJack F Vogel ** Check the max frame setting of all active VF's 590948056c88SJack F Vogel */ 591048056c88SJack F Vogel static void 591148056c88SJack F Vogel ixgbe_recalculate_max_frame(struct adapter *adapter) 591248056c88SJack F Vogel { 591348056c88SJack F Vogel struct ixgbe_vf *vf; 591448056c88SJack F Vogel 591548056c88SJack F Vogel IXGBE_CORE_LOCK_ASSERT(adapter); 591648056c88SJack F Vogel 591748056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 591848056c88SJack F Vogel vf = &adapter->vfs[i]; 591948056c88SJack F Vogel if (vf->flags & IXGBE_VF_ACTIVE) 592048056c88SJack F Vogel ixgbe_update_max_frame(adapter, vf->max_frame_size); 592148056c88SJack F Vogel } 592248056c88SJack F Vogel } 592348056c88SJack F Vogel 592448056c88SJack F Vogel 592548056c88SJack F Vogel static void 592648056c88SJack F Vogel ixgbe_init_vf(struct adapter *adapter, struct ixgbe_vf *vf) 592748056c88SJack F Vogel { 592848056c88SJack F Vogel struct ixgbe_hw *hw; 592948056c88SJack F Vogel uint32_t vf_index, pfmbimr; 593048056c88SJack F Vogel 593148056c88SJack F Vogel IXGBE_CORE_LOCK_ASSERT(adapter); 593248056c88SJack F Vogel 593348056c88SJack F Vogel hw = &adapter->hw; 593448056c88SJack F Vogel 593548056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_ACTIVE)) 593648056c88SJack F Vogel return; 593748056c88SJack F Vogel 593848056c88SJack F Vogel vf_index = IXGBE_VF_INDEX(vf->pool); 593948056c88SJack F Vogel pfmbimr = IXGBE_READ_REG(hw, IXGBE_PFMBIMR(vf_index)); 594048056c88SJack F Vogel pfmbimr |= IXGBE_VF_BIT(vf->pool); 594148056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr); 594248056c88SJack F Vogel 594348056c88SJack F Vogel ixgbe_vf_set_default_vlan(adapter, vf, vf->vlan_tag); 594448056c88SJack F Vogel 594548056c88SJack F Vogel // XXX multicast addresses 594648056c88SJack F Vogel 594748056c88SJack F Vogel if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { 594848056c88SJack F Vogel ixgbe_set_rar(&adapter->hw, vf->rar_index, 594948056c88SJack F Vogel vf->ether_addr, vf->pool, TRUE); 595048056c88SJack F Vogel } 595148056c88SJack F Vogel 595248056c88SJack F Vogel ixgbe_vf_enable_transmit(adapter, vf); 595348056c88SJack F Vogel ixgbe_vf_enable_receive(adapter, vf); 595448056c88SJack F Vogel 595548056c88SJack F Vogel ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); 595648056c88SJack F Vogel } 595748056c88SJack F Vogel 595848056c88SJack F Vogel static int 595948056c88SJack F Vogel ixgbe_add_vf(device_t dev, u16 vfnum, const nvlist_t *config) 596048056c88SJack F Vogel { 596148056c88SJack F Vogel struct adapter *adapter; 596248056c88SJack F Vogel struct ixgbe_vf *vf; 596348056c88SJack F Vogel const void *mac; 596448056c88SJack F Vogel 596548056c88SJack F Vogel adapter = device_get_softc(dev); 596648056c88SJack F Vogel 596748056c88SJack F Vogel KASSERT(vfnum < adapter->num_vfs, ("VF index %d is out of range %d", 596848056c88SJack F Vogel vfnum, adapter->num_vfs)); 596948056c88SJack F Vogel 597048056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 597148056c88SJack F Vogel vf = &adapter->vfs[vfnum]; 597248056c88SJack F Vogel vf->pool= vfnum; 597348056c88SJack F Vogel 597448056c88SJack F Vogel /* RAR[0] is used by the PF so use vfnum + 1 for VF RAR. */ 597548056c88SJack F Vogel vf->rar_index = vfnum + 1; 597648056c88SJack F Vogel vf->default_vlan = 0; 597748056c88SJack F Vogel vf->max_frame_size = ETHER_MAX_LEN; 597848056c88SJack F Vogel ixgbe_update_max_frame(adapter, vf->max_frame_size); 597948056c88SJack F Vogel 598048056c88SJack F Vogel if (nvlist_exists_binary(config, "mac-addr")) { 598148056c88SJack F Vogel mac = nvlist_get_binary(config, "mac-addr", NULL); 598248056c88SJack F Vogel bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); 598348056c88SJack F Vogel if (nvlist_get_bool(config, "allow-set-mac")) 598448056c88SJack F Vogel vf->flags |= IXGBE_VF_CAP_MAC; 598548056c88SJack F Vogel } else 598648056c88SJack F Vogel /* 598748056c88SJack F Vogel * If the administrator has not specified a MAC address then 598848056c88SJack F Vogel * we must allow the VF to choose one. 598948056c88SJack F Vogel */ 599048056c88SJack F Vogel vf->flags |= IXGBE_VF_CAP_MAC; 599148056c88SJack F Vogel 599248056c88SJack F Vogel vf->flags = IXGBE_VF_ACTIVE; 599348056c88SJack F Vogel 599448056c88SJack F Vogel ixgbe_init_vf(adapter, vf); 599548056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 599648056c88SJack F Vogel 599748056c88SJack F Vogel return (0); 599848056c88SJack F Vogel } 599948056c88SJack F Vogel #endif /* PCI_IOV */ 6000758cc3dcSJack F Vogel 6001