1758cc3dcSJack F Vogel /****************************************************************************** 2758cc3dcSJack F Vogel 3758cc3dcSJack F Vogel Copyright (c) 2001-2015, Intel Corporation 4758cc3dcSJack F Vogel All rights reserved. 5758cc3dcSJack F Vogel 6758cc3dcSJack F Vogel Redistribution and use in source and binary forms, with or without 7758cc3dcSJack F Vogel modification, are permitted provided that the following conditions are met: 8758cc3dcSJack F Vogel 9758cc3dcSJack F Vogel 1. Redistributions of source code must retain the above copyright notice, 10758cc3dcSJack F Vogel this list of conditions and the following disclaimer. 11758cc3dcSJack F Vogel 12758cc3dcSJack F Vogel 2. Redistributions in binary form must reproduce the above copyright 13758cc3dcSJack F Vogel notice, this list of conditions and the following disclaimer in the 14758cc3dcSJack F Vogel documentation and/or other materials provided with the distribution. 15758cc3dcSJack F Vogel 16758cc3dcSJack F Vogel 3. Neither the name of the Intel Corporation nor the names of its 17758cc3dcSJack F Vogel contributors may be used to endorse or promote products derived from 18758cc3dcSJack F Vogel this software without specific prior written permission. 19758cc3dcSJack F Vogel 20758cc3dcSJack F Vogel THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21758cc3dcSJack F Vogel AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22758cc3dcSJack F Vogel IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23758cc3dcSJack F Vogel ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24758cc3dcSJack F Vogel LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25758cc3dcSJack F Vogel CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26758cc3dcSJack F Vogel SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27758cc3dcSJack F Vogel INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28758cc3dcSJack F Vogel CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29758cc3dcSJack F Vogel ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30758cc3dcSJack F Vogel POSSIBILITY OF SUCH DAMAGE. 31758cc3dcSJack F Vogel 32758cc3dcSJack F Vogel ******************************************************************************/ 33758cc3dcSJack F Vogel /*$FreeBSD$*/ 34758cc3dcSJack F Vogel 35758cc3dcSJack F Vogel 36758cc3dcSJack F Vogel #ifndef IXGBE_STANDALONE_BUILD 37758cc3dcSJack F Vogel #include "opt_inet.h" 38758cc3dcSJack F Vogel #include "opt_inet6.h" 39758cc3dcSJack F Vogel #include "opt_rss.h" 40758cc3dcSJack F Vogel #endif 41758cc3dcSJack F Vogel 42758cc3dcSJack F Vogel #include "ixgbe.h" 43758cc3dcSJack F Vogel 44758cc3dcSJack F Vogel #ifdef RSS 45a1edda90SAdrian Chadd #include <net/rss_config.h> 46758cc3dcSJack F Vogel #include <netinet/in_rss.h> 47758cc3dcSJack F Vogel #endif 48758cc3dcSJack F Vogel 49758cc3dcSJack F Vogel /********************************************************************* 50758cc3dcSJack F Vogel * Set this to one to display debug statistics 51758cc3dcSJack F Vogel *********************************************************************/ 52758cc3dcSJack F Vogel int ixgbe_display_debug_stats = 0; 53758cc3dcSJack F Vogel 54758cc3dcSJack F Vogel /********************************************************************* 55758cc3dcSJack F Vogel * Driver version 56758cc3dcSJack F Vogel *********************************************************************/ 57*48056c88SJack F Vogel char ixgbe_driver_version[] = "3.1.0"; 58758cc3dcSJack F Vogel 59758cc3dcSJack F Vogel /********************************************************************* 60758cc3dcSJack F Vogel * PCI Device ID Table 61758cc3dcSJack F Vogel * 62758cc3dcSJack F Vogel * Used by probe to select devices to load on 63758cc3dcSJack F Vogel * Last field stores an index into ixgbe_strings 64758cc3dcSJack F Vogel * Last entry must be all 0s 65758cc3dcSJack F Vogel * 66758cc3dcSJack F Vogel * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 67758cc3dcSJack F Vogel *********************************************************************/ 68758cc3dcSJack F Vogel 69758cc3dcSJack F Vogel static ixgbe_vendor_info_t ixgbe_vendor_info_array[] = 70758cc3dcSJack F Vogel { 71758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT, 0, 0, 0}, 72758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT, 0, 0, 0}, 73758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4, 0, 0, 0}, 74758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT, 0, 0, 0}, 75758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT2, 0, 0, 0}, 76758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598, 0, 0, 0}, 77758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_DA_DUAL_PORT, 0, 0, 0}, 78758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_CX4_DUAL_PORT, 0, 0, 0}, 79758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_XF_LR, 0, 0, 0}, 80758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM, 0, 0, 0}, 81758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_SFP_LOM, 0, 0, 0}, 82758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4, 0, 0, 0}, 83758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4_MEZZ, 0, 0, 0}, 84758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP, 0, 0, 0}, 85758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_XAUI_LOM, 0, 0, 0}, 86758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_CX4, 0, 0, 0}, 87758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_T3_LOM, 0, 0, 0}, 88758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_COMBO_BACKPLANE, 0, 0, 0}, 89758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BACKPLANE_FCOE, 0, 0, 0}, 90758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF2, 0, 0, 0}, 91758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_FCOE, 0, 0, 0}, 92758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599EN_SFP, 0, 0, 0}, 93758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF_QP, 0, 0, 0}, 94758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_QSFP_SF_QP, 0, 0, 0}, 95758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T, 0, 0, 0}, 96758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T1, 0, 0, 0}, 97758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T, 0, 0, 0}, 98758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KR, 0, 0, 0}, 99758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KX4, 0, 0, 0}, 100758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_10G_T, 0, 0, 0}, 101758cc3dcSJack F Vogel /* required last entry */ 102758cc3dcSJack F Vogel {0, 0, 0, 0, 0} 103758cc3dcSJack F Vogel }; 104758cc3dcSJack F Vogel 105758cc3dcSJack F Vogel /********************************************************************* 106758cc3dcSJack F Vogel * Table of branding strings 107758cc3dcSJack F Vogel *********************************************************************/ 108758cc3dcSJack F Vogel 109758cc3dcSJack F Vogel static char *ixgbe_strings[] = { 110758cc3dcSJack F Vogel "Intel(R) PRO/10GbE PCI-Express Network Driver" 111758cc3dcSJack F Vogel }; 112758cc3dcSJack F Vogel 113758cc3dcSJack F Vogel /********************************************************************* 114758cc3dcSJack F Vogel * Function prototypes 115758cc3dcSJack F Vogel *********************************************************************/ 116758cc3dcSJack F Vogel static int ixgbe_probe(device_t); 117758cc3dcSJack F Vogel static int ixgbe_attach(device_t); 118758cc3dcSJack F Vogel static int ixgbe_detach(device_t); 119758cc3dcSJack F Vogel static int ixgbe_shutdown(device_t); 1206f37f232SEric Joyner static int ixgbe_suspend(device_t); 1216f37f232SEric Joyner static int ixgbe_resume(device_t); 122758cc3dcSJack F Vogel static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t); 123758cc3dcSJack F Vogel static void ixgbe_init(void *); 124758cc3dcSJack F Vogel static void ixgbe_init_locked(struct adapter *); 125758cc3dcSJack F Vogel static void ixgbe_stop(void *); 126758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 127758cc3dcSJack F Vogel static uint64_t ixgbe_get_counter(struct ifnet *, ift_counter); 128758cc3dcSJack F Vogel #endif 129758cc3dcSJack F Vogel static void ixgbe_add_media_types(struct adapter *); 130758cc3dcSJack F Vogel static void ixgbe_media_status(struct ifnet *, struct ifmediareq *); 131758cc3dcSJack F Vogel static int ixgbe_media_change(struct ifnet *); 132758cc3dcSJack F Vogel static void ixgbe_identify_hardware(struct adapter *); 133758cc3dcSJack F Vogel static int ixgbe_allocate_pci_resources(struct adapter *); 134758cc3dcSJack F Vogel static void ixgbe_get_slot_info(struct ixgbe_hw *); 135758cc3dcSJack F Vogel static int ixgbe_allocate_msix(struct adapter *); 136758cc3dcSJack F Vogel static int ixgbe_allocate_legacy(struct adapter *); 137758cc3dcSJack F Vogel static int ixgbe_setup_msix(struct adapter *); 138758cc3dcSJack F Vogel static void ixgbe_free_pci_resources(struct adapter *); 139758cc3dcSJack F Vogel static void ixgbe_local_timer(void *); 140758cc3dcSJack F Vogel static int ixgbe_setup_interface(device_t, struct adapter *); 141*48056c88SJack F Vogel static void ixgbe_config_gpie(struct adapter *); 1426f37f232SEric Joyner static void ixgbe_config_dmac(struct adapter *); 1436f37f232SEric Joyner static void ixgbe_config_delay_values(struct adapter *); 144758cc3dcSJack F Vogel static void ixgbe_config_link(struct adapter *); 1456f37f232SEric Joyner static void ixgbe_check_eee_support(struct adapter *); 1466f37f232SEric Joyner static void ixgbe_check_wol_support(struct adapter *); 1476f37f232SEric Joyner static int ixgbe_setup_low_power_mode(struct adapter *); 148758cc3dcSJack F Vogel static void ixgbe_rearm_queues(struct adapter *, u64); 149758cc3dcSJack F Vogel 150758cc3dcSJack F Vogel static void ixgbe_initialize_transmit_units(struct adapter *); 151758cc3dcSJack F Vogel static void ixgbe_initialize_receive_units(struct adapter *); 152758cc3dcSJack F Vogel static void ixgbe_enable_rx_drop(struct adapter *); 153758cc3dcSJack F Vogel static void ixgbe_disable_rx_drop(struct adapter *); 154758cc3dcSJack F Vogel 155758cc3dcSJack F Vogel static void ixgbe_enable_intr(struct adapter *); 156758cc3dcSJack F Vogel static void ixgbe_disable_intr(struct adapter *); 157758cc3dcSJack F Vogel static void ixgbe_update_stats_counters(struct adapter *); 158758cc3dcSJack F Vogel static void ixgbe_set_promisc(struct adapter *); 159758cc3dcSJack F Vogel static void ixgbe_set_multi(struct adapter *); 160758cc3dcSJack F Vogel static void ixgbe_update_link_status(struct adapter *); 161758cc3dcSJack F Vogel static void ixgbe_set_ivar(struct adapter *, u8, u8, s8); 162758cc3dcSJack F Vogel static void ixgbe_configure_ivars(struct adapter *); 163758cc3dcSJack F Vogel static u8 * ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); 164758cc3dcSJack F Vogel 165758cc3dcSJack F Vogel static void ixgbe_setup_vlan_hw_support(struct adapter *); 166758cc3dcSJack F Vogel static void ixgbe_register_vlan(void *, struct ifnet *, u16); 167758cc3dcSJack F Vogel static void ixgbe_unregister_vlan(void *, struct ifnet *, u16); 168758cc3dcSJack F Vogel 1696f37f232SEric Joyner static void ixgbe_add_device_sysctls(struct adapter *); 1706f37f232SEric Joyner static void ixgbe_add_hw_stats(struct adapter *); 1716f37f232SEric Joyner 1726f37f232SEric Joyner /* Sysctl handlers */ 1736f37f232SEric Joyner static int ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS); 1746f37f232SEric Joyner static int ixgbe_set_advertise(SYSCTL_HANDLER_ARGS); 1756f37f232SEric Joyner static int ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS); 1766f37f232SEric Joyner static int ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS); 1776f37f232SEric Joyner static int ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS); 1786f37f232SEric Joyner static int ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS); 1796f37f232SEric Joyner static int ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS); 1806f37f232SEric Joyner static int ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS); 1816f37f232SEric Joyner static int ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS); 1826f37f232SEric Joyner static int ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS); 1836f37f232SEric Joyner static int ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS); 1846f37f232SEric Joyner static int ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS); 185758cc3dcSJack F Vogel 186758cc3dcSJack F Vogel /* Support for pluggable optic modules */ 187758cc3dcSJack F Vogel static bool ixgbe_sfp_probe(struct adapter *); 188758cc3dcSJack F Vogel static void ixgbe_setup_optics(struct adapter *); 189758cc3dcSJack F Vogel 190758cc3dcSJack F Vogel /* Legacy (single vector interrupt handler */ 191758cc3dcSJack F Vogel static void ixgbe_legacy_irq(void *); 192758cc3dcSJack F Vogel 193758cc3dcSJack F Vogel /* The MSI/X Interrupt handlers */ 194758cc3dcSJack F Vogel static void ixgbe_msix_que(void *); 195758cc3dcSJack F Vogel static void ixgbe_msix_link(void *); 196758cc3dcSJack F Vogel 197758cc3dcSJack F Vogel /* Deferred interrupt tasklets */ 198758cc3dcSJack F Vogel static void ixgbe_handle_que(void *, int); 199758cc3dcSJack F Vogel static void ixgbe_handle_link(void *, int); 200758cc3dcSJack F Vogel static void ixgbe_handle_msf(void *, int); 201758cc3dcSJack F Vogel static void ixgbe_handle_mod(void *, int); 2026f37f232SEric Joyner static void ixgbe_handle_phy(void *, int); 203758cc3dcSJack F Vogel 204758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 205758cc3dcSJack F Vogel static void ixgbe_reinit_fdir(void *, int); 206758cc3dcSJack F Vogel #endif 207758cc3dcSJack F Vogel 208*48056c88SJack F Vogel #ifdef PCI_IOV 209*48056c88SJack F Vogel static void ixgbe_ping_all_vfs(struct adapter *); 210*48056c88SJack F Vogel static void ixgbe_handle_mbx(void *, int); 211*48056c88SJack F Vogel static int ixgbe_init_iov(device_t, u16, const nvlist_t *); 212*48056c88SJack F Vogel static void ixgbe_uninit_iov(device_t); 213*48056c88SJack F Vogel static int ixgbe_add_vf(device_t, u16, const nvlist_t *); 214*48056c88SJack F Vogel static void ixgbe_initialize_iov(struct adapter *); 215*48056c88SJack F Vogel static void ixgbe_recalculate_max_frame(struct adapter *); 216*48056c88SJack F Vogel static void ixgbe_init_vf(struct adapter *, struct ixgbe_vf *); 217*48056c88SJack F Vogel #endif /* PCI_IOV */ 218*48056c88SJack F Vogel 219*48056c88SJack F Vogel 220758cc3dcSJack F Vogel /********************************************************************* 221758cc3dcSJack F Vogel * FreeBSD Device Interface Entry Points 222758cc3dcSJack F Vogel *********************************************************************/ 223758cc3dcSJack F Vogel 224a1edda90SAdrian Chadd static device_method_t ix_methods[] = { 225758cc3dcSJack F Vogel /* Device interface */ 226758cc3dcSJack F Vogel DEVMETHOD(device_probe, ixgbe_probe), 227758cc3dcSJack F Vogel DEVMETHOD(device_attach, ixgbe_attach), 228758cc3dcSJack F Vogel DEVMETHOD(device_detach, ixgbe_detach), 229758cc3dcSJack F Vogel DEVMETHOD(device_shutdown, ixgbe_shutdown), 2306f37f232SEric Joyner DEVMETHOD(device_suspend, ixgbe_suspend), 2316f37f232SEric Joyner DEVMETHOD(device_resume, ixgbe_resume), 232*48056c88SJack F Vogel #ifdef PCI_IOV 233*48056c88SJack F Vogel DEVMETHOD(pci_init_iov, ixgbe_init_iov), 234*48056c88SJack F Vogel DEVMETHOD(pci_uninit_iov, ixgbe_uninit_iov), 235*48056c88SJack F Vogel DEVMETHOD(pci_add_vf, ixgbe_add_vf), 236*48056c88SJack F Vogel #endif /* PCI_IOV */ 237758cc3dcSJack F Vogel DEVMETHOD_END 238758cc3dcSJack F Vogel }; 239758cc3dcSJack F Vogel 240a1edda90SAdrian Chadd static driver_t ix_driver = { 241a1edda90SAdrian Chadd "ix", ix_methods, sizeof(struct adapter), 242758cc3dcSJack F Vogel }; 243758cc3dcSJack F Vogel 244a1edda90SAdrian Chadd devclass_t ix_devclass; 245a1edda90SAdrian Chadd DRIVER_MODULE(ix, pci, ix_driver, ix_devclass, 0, 0); 246758cc3dcSJack F Vogel 247a1edda90SAdrian Chadd MODULE_DEPEND(ix, pci, 1, 1, 1); 248a1edda90SAdrian Chadd MODULE_DEPEND(ix, ether, 1, 1, 1); 249758cc3dcSJack F Vogel 250758cc3dcSJack F Vogel /* 251758cc3dcSJack F Vogel ** TUNEABLE PARAMETERS: 252758cc3dcSJack F Vogel */ 253758cc3dcSJack F Vogel 254758cc3dcSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0, 255758cc3dcSJack F Vogel "IXGBE driver parameters"); 256758cc3dcSJack F Vogel 257758cc3dcSJack F Vogel /* 258758cc3dcSJack F Vogel ** AIM: Adaptive Interrupt Moderation 259758cc3dcSJack F Vogel ** which means that the interrupt rate 260758cc3dcSJack F Vogel ** is varied over time based on the 261758cc3dcSJack F Vogel ** traffic for that interrupt vector 262758cc3dcSJack F Vogel */ 263758cc3dcSJack F Vogel static int ixgbe_enable_aim = TRUE; 264758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0, 265758cc3dcSJack F Vogel "Enable adaptive interrupt moderation"); 266758cc3dcSJack F Vogel 267758cc3dcSJack F Vogel static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY); 268758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN, 269758cc3dcSJack F Vogel &ixgbe_max_interrupt_rate, 0, "Maximum interrupts per second"); 270758cc3dcSJack F Vogel 271758cc3dcSJack F Vogel /* How many packets rxeof tries to clean at a time */ 272758cc3dcSJack F Vogel static int ixgbe_rx_process_limit = 256; 273758cc3dcSJack F Vogel TUNABLE_INT("hw.ixgbe.rx_process_limit", &ixgbe_rx_process_limit); 274758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, 275758cc3dcSJack F Vogel &ixgbe_rx_process_limit, 0, 276758cc3dcSJack F Vogel "Maximum number of received packets to process at a time," 277758cc3dcSJack F Vogel "-1 means unlimited"); 278758cc3dcSJack F Vogel 279758cc3dcSJack F Vogel /* How many packets txeof tries to clean at a time */ 280758cc3dcSJack F Vogel static int ixgbe_tx_process_limit = 256; 281758cc3dcSJack F Vogel TUNABLE_INT("hw.ixgbe.tx_process_limit", &ixgbe_tx_process_limit); 282758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, tx_process_limit, CTLFLAG_RDTUN, 283758cc3dcSJack F Vogel &ixgbe_tx_process_limit, 0, 284758cc3dcSJack F Vogel "Maximum number of sent packets to process at a time," 285758cc3dcSJack F Vogel "-1 means unlimited"); 286758cc3dcSJack F Vogel 287758cc3dcSJack F Vogel /* 288758cc3dcSJack F Vogel ** Smart speed setting, default to on 289758cc3dcSJack F Vogel ** this only works as a compile option 290758cc3dcSJack F Vogel ** right now as its during attach, set 291758cc3dcSJack F Vogel ** this to 'ixgbe_smart_speed_off' to 292758cc3dcSJack F Vogel ** disable. 293758cc3dcSJack F Vogel */ 294758cc3dcSJack F Vogel static int ixgbe_smart_speed = ixgbe_smart_speed_on; 295758cc3dcSJack F Vogel 296758cc3dcSJack F Vogel /* 297758cc3dcSJack F Vogel * MSIX should be the default for best performance, 298758cc3dcSJack F Vogel * but this allows it to be forced off for testing. 299758cc3dcSJack F Vogel */ 300758cc3dcSJack F Vogel static int ixgbe_enable_msix = 1; 301758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixgbe_enable_msix, 0, 302758cc3dcSJack F Vogel "Enable MSI-X interrupts"); 303758cc3dcSJack F Vogel 304758cc3dcSJack F Vogel /* 305758cc3dcSJack F Vogel * Number of Queues, can be set to 0, 306758cc3dcSJack F Vogel * it then autoconfigures based on the 307758cc3dcSJack F Vogel * number of cpus with a max of 8. This 308758cc3dcSJack F Vogel * can be overriden manually here. 309758cc3dcSJack F Vogel */ 310758cc3dcSJack F Vogel static int ixgbe_num_queues = 0; 311758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, num_queues, CTLFLAG_RDTUN, &ixgbe_num_queues, 0, 312758cc3dcSJack F Vogel "Number of queues to configure, 0 indicates autoconfigure"); 313758cc3dcSJack F Vogel 314758cc3dcSJack F Vogel /* 315758cc3dcSJack F Vogel ** Number of TX descriptors per ring, 316758cc3dcSJack F Vogel ** setting higher than RX as this seems 317758cc3dcSJack F Vogel ** the better performing choice. 318758cc3dcSJack F Vogel */ 319758cc3dcSJack F Vogel static int ixgbe_txd = PERFORM_TXD; 320758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, txd, CTLFLAG_RDTUN, &ixgbe_txd, 0, 321758cc3dcSJack F Vogel "Number of transmit descriptors per queue"); 322758cc3dcSJack F Vogel 323758cc3dcSJack F Vogel /* Number of RX descriptors per ring */ 324758cc3dcSJack F Vogel static int ixgbe_rxd = PERFORM_RXD; 325758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rxd, CTLFLAG_RDTUN, &ixgbe_rxd, 0, 326758cc3dcSJack F Vogel "Number of receive descriptors per queue"); 327758cc3dcSJack F Vogel 328758cc3dcSJack F Vogel /* 329758cc3dcSJack F Vogel ** Defining this on will allow the use 330758cc3dcSJack F Vogel ** of unsupported SFP+ modules, note that 331758cc3dcSJack F Vogel ** doing so you are on your own :) 332758cc3dcSJack F Vogel */ 333758cc3dcSJack F Vogel static int allow_unsupported_sfp = FALSE; 334758cc3dcSJack F Vogel TUNABLE_INT("hw.ix.unsupported_sfp", &allow_unsupported_sfp); 335758cc3dcSJack F Vogel 336758cc3dcSJack F Vogel /* Keep running tab on them for sanity check */ 337758cc3dcSJack F Vogel static int ixgbe_total_ports; 338758cc3dcSJack F Vogel 339758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 340758cc3dcSJack F Vogel /* 341758cc3dcSJack F Vogel ** Flow Director actually 'steals' 342758cc3dcSJack F Vogel ** part of the packet buffer as its 343758cc3dcSJack F Vogel ** filter pool, this variable controls 344758cc3dcSJack F Vogel ** how much it uses: 345758cc3dcSJack F Vogel ** 0 = 64K, 1 = 128K, 2 = 256K 346758cc3dcSJack F Vogel */ 347758cc3dcSJack F Vogel static int fdir_pballoc = 1; 348758cc3dcSJack F Vogel #endif 349758cc3dcSJack F Vogel 350758cc3dcSJack F Vogel #ifdef DEV_NETMAP 351758cc3dcSJack F Vogel /* 352758cc3dcSJack F Vogel * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to 353758cc3dcSJack F Vogel * be a reference on how to implement netmap support in a driver. 354758cc3dcSJack F Vogel * Additional comments are in ixgbe_netmap.h . 355758cc3dcSJack F Vogel * 356758cc3dcSJack F Vogel * <dev/netmap/ixgbe_netmap.h> contains functions for netmap support 357758cc3dcSJack F Vogel * that extend the standard driver. 358758cc3dcSJack F Vogel */ 359758cc3dcSJack F Vogel #include <dev/netmap/ixgbe_netmap.h> 360758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 361758cc3dcSJack F Vogel 362*48056c88SJack F Vogel static MALLOC_DEFINE(M_IXGBE, "ix", "ix driver allocations"); 363*48056c88SJack F Vogel 364758cc3dcSJack F Vogel /********************************************************************* 365758cc3dcSJack F Vogel * Device identification routine 366758cc3dcSJack F Vogel * 367758cc3dcSJack F Vogel * ixgbe_probe determines if the driver should be loaded on 368758cc3dcSJack F Vogel * adapter based on PCI vendor/device id of the adapter. 369758cc3dcSJack F Vogel * 370758cc3dcSJack F Vogel * return BUS_PROBE_DEFAULT on success, positive on failure 371758cc3dcSJack F Vogel *********************************************************************/ 372758cc3dcSJack F Vogel 373758cc3dcSJack F Vogel static int 374758cc3dcSJack F Vogel ixgbe_probe(device_t dev) 375758cc3dcSJack F Vogel { 376758cc3dcSJack F Vogel ixgbe_vendor_info_t *ent; 377758cc3dcSJack F Vogel 378758cc3dcSJack F Vogel u16 pci_vendor_id = 0; 379758cc3dcSJack F Vogel u16 pci_device_id = 0; 380758cc3dcSJack F Vogel u16 pci_subvendor_id = 0; 381758cc3dcSJack F Vogel u16 pci_subdevice_id = 0; 382758cc3dcSJack F Vogel char adapter_name[256]; 383758cc3dcSJack F Vogel 384758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_probe: begin"); 385758cc3dcSJack F Vogel 386758cc3dcSJack F Vogel pci_vendor_id = pci_get_vendor(dev); 387758cc3dcSJack F Vogel if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) 388758cc3dcSJack F Vogel return (ENXIO); 389758cc3dcSJack F Vogel 390758cc3dcSJack F Vogel pci_device_id = pci_get_device(dev); 391758cc3dcSJack F Vogel pci_subvendor_id = pci_get_subvendor(dev); 392758cc3dcSJack F Vogel pci_subdevice_id = pci_get_subdevice(dev); 393758cc3dcSJack F Vogel 394758cc3dcSJack F Vogel ent = ixgbe_vendor_info_array; 395758cc3dcSJack F Vogel while (ent->vendor_id != 0) { 396758cc3dcSJack F Vogel if ((pci_vendor_id == ent->vendor_id) && 397758cc3dcSJack F Vogel (pci_device_id == ent->device_id) && 398758cc3dcSJack F Vogel 399758cc3dcSJack F Vogel ((pci_subvendor_id == ent->subvendor_id) || 400758cc3dcSJack F Vogel (ent->subvendor_id == 0)) && 401758cc3dcSJack F Vogel 402758cc3dcSJack F Vogel ((pci_subdevice_id == ent->subdevice_id) || 403758cc3dcSJack F Vogel (ent->subdevice_id == 0))) { 404758cc3dcSJack F Vogel sprintf(adapter_name, "%s, Version - %s", 405758cc3dcSJack F Vogel ixgbe_strings[ent->index], 406758cc3dcSJack F Vogel ixgbe_driver_version); 407758cc3dcSJack F Vogel device_set_desc_copy(dev, adapter_name); 408758cc3dcSJack F Vogel ++ixgbe_total_ports; 409758cc3dcSJack F Vogel return (BUS_PROBE_DEFAULT); 410758cc3dcSJack F Vogel } 411758cc3dcSJack F Vogel ent++; 412758cc3dcSJack F Vogel } 413758cc3dcSJack F Vogel return (ENXIO); 414758cc3dcSJack F Vogel } 415758cc3dcSJack F Vogel 416758cc3dcSJack F Vogel /********************************************************************* 417758cc3dcSJack F Vogel * Device initialization routine 418758cc3dcSJack F Vogel * 419758cc3dcSJack F Vogel * The attach entry point is called when the driver is being loaded. 420758cc3dcSJack F Vogel * This routine identifies the type of hardware, allocates all resources 421758cc3dcSJack F Vogel * and initializes the hardware. 422758cc3dcSJack F Vogel * 423758cc3dcSJack F Vogel * return 0 on success, positive on failure 424758cc3dcSJack F Vogel *********************************************************************/ 425758cc3dcSJack F Vogel 426758cc3dcSJack F Vogel static int 427758cc3dcSJack F Vogel ixgbe_attach(device_t dev) 428758cc3dcSJack F Vogel { 429758cc3dcSJack F Vogel struct adapter *adapter; 430758cc3dcSJack F Vogel struct ixgbe_hw *hw; 431758cc3dcSJack F Vogel int error = 0; 432758cc3dcSJack F Vogel u16 csum; 433758cc3dcSJack F Vogel u32 ctrl_ext; 434758cc3dcSJack F Vogel 435758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_attach: begin"); 436758cc3dcSJack F Vogel 437758cc3dcSJack F Vogel /* Allocate, clear, and link in our adapter structure */ 438758cc3dcSJack F Vogel adapter = device_get_softc(dev); 439758cc3dcSJack F Vogel adapter->dev = adapter->osdep.dev = dev; 440758cc3dcSJack F Vogel hw = &adapter->hw; 441758cc3dcSJack F Vogel 442758cc3dcSJack F Vogel /* Core Lock Init*/ 443758cc3dcSJack F Vogel IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); 444758cc3dcSJack F Vogel 445758cc3dcSJack F Vogel /* Set up the timer callout */ 446758cc3dcSJack F Vogel callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); 447758cc3dcSJack F Vogel 448758cc3dcSJack F Vogel /* Determine hardware revision */ 449758cc3dcSJack F Vogel ixgbe_identify_hardware(adapter); 450758cc3dcSJack F Vogel 451758cc3dcSJack F Vogel /* Do base PCI setup - map BAR0 */ 452758cc3dcSJack F Vogel if (ixgbe_allocate_pci_resources(adapter)) { 453758cc3dcSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 454758cc3dcSJack F Vogel error = ENXIO; 455758cc3dcSJack F Vogel goto err_out; 456758cc3dcSJack F Vogel } 457758cc3dcSJack F Vogel 458758cc3dcSJack F Vogel /* Do descriptor calc and sanity checks */ 459758cc3dcSJack F Vogel if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || 460758cc3dcSJack F Vogel ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) { 461758cc3dcSJack F Vogel device_printf(dev, "TXD config issue, using default!\n"); 462758cc3dcSJack F Vogel adapter->num_tx_desc = DEFAULT_TXD; 463758cc3dcSJack F Vogel } else 464758cc3dcSJack F Vogel adapter->num_tx_desc = ixgbe_txd; 465758cc3dcSJack F Vogel 466758cc3dcSJack F Vogel /* 467758cc3dcSJack F Vogel ** With many RX rings it is easy to exceed the 468758cc3dcSJack F Vogel ** system mbuf allocation. Tuning nmbclusters 469758cc3dcSJack F Vogel ** can alleviate this. 470758cc3dcSJack F Vogel */ 471758cc3dcSJack F Vogel if (nmbclusters > 0) { 472758cc3dcSJack F Vogel int s; 473758cc3dcSJack F Vogel s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports; 474758cc3dcSJack F Vogel if (s > nmbclusters) { 475758cc3dcSJack F Vogel device_printf(dev, "RX Descriptors exceed " 476758cc3dcSJack F Vogel "system mbuf max, using default instead!\n"); 477758cc3dcSJack F Vogel ixgbe_rxd = DEFAULT_RXD; 478758cc3dcSJack F Vogel } 479758cc3dcSJack F Vogel } 480758cc3dcSJack F Vogel 481758cc3dcSJack F Vogel if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || 482758cc3dcSJack F Vogel ixgbe_rxd < MIN_RXD || ixgbe_rxd > MAX_RXD) { 483758cc3dcSJack F Vogel device_printf(dev, "RXD config issue, using default!\n"); 484758cc3dcSJack F Vogel adapter->num_rx_desc = DEFAULT_RXD; 485758cc3dcSJack F Vogel } else 486758cc3dcSJack F Vogel adapter->num_rx_desc = ixgbe_rxd; 487758cc3dcSJack F Vogel 488758cc3dcSJack F Vogel /* Allocate our TX/RX Queues */ 489758cc3dcSJack F Vogel if (ixgbe_allocate_queues(adapter)) { 490758cc3dcSJack F Vogel error = ENOMEM; 491758cc3dcSJack F Vogel goto err_out; 492758cc3dcSJack F Vogel } 493758cc3dcSJack F Vogel 494758cc3dcSJack F Vogel /* Allocate multicast array memory. */ 495*48056c88SJack F Vogel adapter->mta = malloc(sizeof(*adapter->mta) * 496758cc3dcSJack F Vogel MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); 497758cc3dcSJack F Vogel if (adapter->mta == NULL) { 498758cc3dcSJack F Vogel device_printf(dev, "Can not allocate multicast setup array\n"); 499758cc3dcSJack F Vogel error = ENOMEM; 500758cc3dcSJack F Vogel goto err_late; 501758cc3dcSJack F Vogel } 502758cc3dcSJack F Vogel 503758cc3dcSJack F Vogel /* Initialize the shared code */ 504758cc3dcSJack F Vogel hw->allow_unsupported_sfp = allow_unsupported_sfp; 505758cc3dcSJack F Vogel error = ixgbe_init_shared_code(hw); 506758cc3dcSJack F Vogel if (error == IXGBE_ERR_SFP_NOT_PRESENT) { 507758cc3dcSJack F Vogel /* 508758cc3dcSJack F Vogel ** No optics in this port, set up 509758cc3dcSJack F Vogel ** so the timer routine will probe 510758cc3dcSJack F Vogel ** for later insertion. 511758cc3dcSJack F Vogel */ 512758cc3dcSJack F Vogel adapter->sfp_probe = TRUE; 513758cc3dcSJack F Vogel error = 0; 514758cc3dcSJack F Vogel } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { 515758cc3dcSJack F Vogel device_printf(dev,"Unsupported SFP+ module detected!\n"); 516758cc3dcSJack F Vogel error = EIO; 517758cc3dcSJack F Vogel goto err_late; 518758cc3dcSJack F Vogel } else if (error) { 519758cc3dcSJack F Vogel device_printf(dev,"Unable to initialize the shared code\n"); 520758cc3dcSJack F Vogel error = EIO; 521758cc3dcSJack F Vogel goto err_late; 522758cc3dcSJack F Vogel } 523758cc3dcSJack F Vogel 524758cc3dcSJack F Vogel /* Make sure we have a good EEPROM before we read from it */ 525758cc3dcSJack F Vogel if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) { 526758cc3dcSJack F Vogel device_printf(dev,"The EEPROM Checksum Is Not Valid\n"); 527758cc3dcSJack F Vogel error = EIO; 528758cc3dcSJack F Vogel goto err_late; 529758cc3dcSJack F Vogel } 530758cc3dcSJack F Vogel 531758cc3dcSJack F Vogel error = ixgbe_init_hw(hw); 532758cc3dcSJack F Vogel switch (error) { 533758cc3dcSJack F Vogel case IXGBE_ERR_EEPROM_VERSION: 534758cc3dcSJack F Vogel device_printf(dev, "This device is a pre-production adapter/" 535758cc3dcSJack F Vogel "LOM. Please be aware there may be issues associated " 536758cc3dcSJack F Vogel "with your hardware.\n If you are experiencing problems " 537758cc3dcSJack F Vogel "please contact your Intel or hardware representative " 538758cc3dcSJack F Vogel "who provided you with this hardware.\n"); 539758cc3dcSJack F Vogel break; 540758cc3dcSJack F Vogel case IXGBE_ERR_SFP_NOT_SUPPORTED: 541758cc3dcSJack F Vogel device_printf(dev,"Unsupported SFP+ Module\n"); 542758cc3dcSJack F Vogel error = EIO; 543758cc3dcSJack F Vogel goto err_late; 544758cc3dcSJack F Vogel case IXGBE_ERR_SFP_NOT_PRESENT: 545758cc3dcSJack F Vogel device_printf(dev,"No SFP+ Module found\n"); 546758cc3dcSJack F Vogel /* falls thru */ 547758cc3dcSJack F Vogel default: 548758cc3dcSJack F Vogel break; 549758cc3dcSJack F Vogel } 550758cc3dcSJack F Vogel 551758cc3dcSJack F Vogel /* Detect and set physical type */ 552758cc3dcSJack F Vogel ixgbe_setup_optics(adapter); 553758cc3dcSJack F Vogel 554758cc3dcSJack F Vogel if ((adapter->msix > 1) && (ixgbe_enable_msix)) 555758cc3dcSJack F Vogel error = ixgbe_allocate_msix(adapter); 556758cc3dcSJack F Vogel else 557758cc3dcSJack F Vogel error = ixgbe_allocate_legacy(adapter); 558758cc3dcSJack F Vogel if (error) 559758cc3dcSJack F Vogel goto err_late; 560758cc3dcSJack F Vogel 561758cc3dcSJack F Vogel /* Setup OS specific network interface */ 562758cc3dcSJack F Vogel if (ixgbe_setup_interface(dev, adapter) != 0) 563758cc3dcSJack F Vogel goto err_late; 564758cc3dcSJack F Vogel 565758cc3dcSJack F Vogel /* Initialize statistics */ 566758cc3dcSJack F Vogel ixgbe_update_stats_counters(adapter); 567758cc3dcSJack F Vogel 568758cc3dcSJack F Vogel /* Register for VLAN events */ 569758cc3dcSJack F Vogel adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 570758cc3dcSJack F Vogel ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); 571758cc3dcSJack F Vogel adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 572758cc3dcSJack F Vogel ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); 573758cc3dcSJack F Vogel 5746f37f232SEric Joyner /* Check PCIE slot type/speed/width */ 575758cc3dcSJack F Vogel ixgbe_get_slot_info(hw); 576758cc3dcSJack F Vogel 577758cc3dcSJack F Vogel 578758cc3dcSJack F Vogel /* Set an initial default flow control value */ 579758cc3dcSJack F Vogel adapter->fc = ixgbe_fc_full; 580758cc3dcSJack F Vogel 581*48056c88SJack F Vogel #ifdef PCI_IOV 582*48056c88SJack F Vogel if ((hw->mac.type != ixgbe_mac_82598EB) && (adapter->msix > 1)) { 583*48056c88SJack F Vogel nvlist_t *pf_schema, *vf_schema; 584*48056c88SJack F Vogel 585*48056c88SJack F Vogel hw->mbx.ops.init_params(hw); 586*48056c88SJack F Vogel pf_schema = pci_iov_schema_alloc_node(); 587*48056c88SJack F Vogel vf_schema = pci_iov_schema_alloc_node(); 588*48056c88SJack F Vogel pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); 589*48056c88SJack F Vogel pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", 590*48056c88SJack F Vogel IOV_SCHEMA_HASDEFAULT, TRUE); 591*48056c88SJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-set-mac", 592*48056c88SJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 593*48056c88SJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-promisc", 594*48056c88SJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 595*48056c88SJack F Vogel error = pci_iov_attach(dev, pf_schema, vf_schema); 596*48056c88SJack F Vogel if (error != 0) { 597*48056c88SJack F Vogel device_printf(dev, 598*48056c88SJack F Vogel "Error %d setting up SR-IOV\n", error); 599*48056c88SJack F Vogel } 600*48056c88SJack F Vogel } 601*48056c88SJack F Vogel #endif /* PCI_IOV */ 602*48056c88SJack F Vogel 6036f37f232SEric Joyner /* Check for certain supported features */ 6046f37f232SEric Joyner ixgbe_check_wol_support(adapter); 6056f37f232SEric Joyner ixgbe_check_eee_support(adapter); 6066f37f232SEric Joyner 6076f37f232SEric Joyner /* Add sysctls */ 6086f37f232SEric Joyner ixgbe_add_device_sysctls(adapter); 6096f37f232SEric Joyner ixgbe_add_hw_stats(adapter); 6106f37f232SEric Joyner 611758cc3dcSJack F Vogel /* let hardware know driver is loaded */ 612758cc3dcSJack F Vogel ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 613758cc3dcSJack F Vogel ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; 614758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 615758cc3dcSJack F Vogel 616758cc3dcSJack F Vogel #ifdef DEV_NETMAP 617758cc3dcSJack F Vogel ixgbe_netmap_attach(adapter); 618758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 619758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_attach: end"); 620758cc3dcSJack F Vogel return (0); 621758cc3dcSJack F Vogel 622758cc3dcSJack F Vogel err_late: 623758cc3dcSJack F Vogel ixgbe_free_transmit_structures(adapter); 624758cc3dcSJack F Vogel ixgbe_free_receive_structures(adapter); 625758cc3dcSJack F Vogel err_out: 626758cc3dcSJack F Vogel if (adapter->ifp != NULL) 627758cc3dcSJack F Vogel if_free(adapter->ifp); 628758cc3dcSJack F Vogel ixgbe_free_pci_resources(adapter); 629758cc3dcSJack F Vogel free(adapter->mta, M_DEVBUF); 630758cc3dcSJack F Vogel return (error); 631758cc3dcSJack F Vogel } 632758cc3dcSJack F Vogel 633758cc3dcSJack F Vogel /********************************************************************* 634758cc3dcSJack F Vogel * Device removal routine 635758cc3dcSJack F Vogel * 636758cc3dcSJack F Vogel * The detach entry point is called when the driver is being removed. 637758cc3dcSJack F Vogel * This routine stops the adapter and deallocates all the resources 638758cc3dcSJack F Vogel * that were allocated for driver operation. 639758cc3dcSJack F Vogel * 640758cc3dcSJack F Vogel * return 0 on success, positive on failure 641758cc3dcSJack F Vogel *********************************************************************/ 642758cc3dcSJack F Vogel 643758cc3dcSJack F Vogel static int 644758cc3dcSJack F Vogel ixgbe_detach(device_t dev) 645758cc3dcSJack F Vogel { 646758cc3dcSJack F Vogel struct adapter *adapter = device_get_softc(dev); 647758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 648758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 649758cc3dcSJack F Vogel u32 ctrl_ext; 650758cc3dcSJack F Vogel 651758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_detach: begin"); 652758cc3dcSJack F Vogel 653758cc3dcSJack F Vogel /* Make sure VLANS are not using driver */ 654758cc3dcSJack F Vogel if (adapter->ifp->if_vlantrunk != NULL) { 655758cc3dcSJack F Vogel device_printf(dev,"Vlan in use, detach first\n"); 656758cc3dcSJack F Vogel return (EBUSY); 657758cc3dcSJack F Vogel } 658758cc3dcSJack F Vogel 659*48056c88SJack F Vogel #ifdef PCI_IOV 660*48056c88SJack F Vogel if (pci_iov_detach(dev) != 0) { 661*48056c88SJack F Vogel device_printf(dev, "SR-IOV in use; detach first.\n"); 662*48056c88SJack F Vogel return (EBUSY); 663*48056c88SJack F Vogel } 664*48056c88SJack F Vogel #endif /* PCI_IOV */ 665*48056c88SJack F Vogel 6666f37f232SEric Joyner /* Stop the adapter */ 667758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 6686f37f232SEric Joyner ixgbe_setup_low_power_mode(adapter); 669758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 670758cc3dcSJack F Vogel 671758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { 672758cc3dcSJack F Vogel if (que->tq) { 673758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 674758cc3dcSJack F Vogel taskqueue_drain(que->tq, &txr->txq_task); 675758cc3dcSJack F Vogel #endif 676758cc3dcSJack F Vogel taskqueue_drain(que->tq, &que->que_task); 677758cc3dcSJack F Vogel taskqueue_free(que->tq); 678758cc3dcSJack F Vogel } 679758cc3dcSJack F Vogel } 680758cc3dcSJack F Vogel 681758cc3dcSJack F Vogel /* Drain the Link queue */ 682758cc3dcSJack F Vogel if (adapter->tq) { 683758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->link_task); 684758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->mod_task); 685758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->msf_task); 686*48056c88SJack F Vogel #ifdef PCI_IOV 687*48056c88SJack F Vogel taskqueue_drain(adapter->tq, &adapter->mbx_task); 688*48056c88SJack F Vogel #endif 6896f37f232SEric Joyner taskqueue_drain(adapter->tq, &adapter->phy_task); 690758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 691758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->fdir_task); 692758cc3dcSJack F Vogel #endif 693758cc3dcSJack F Vogel taskqueue_free(adapter->tq); 694758cc3dcSJack F Vogel } 695758cc3dcSJack F Vogel 696758cc3dcSJack F Vogel /* let hardware know driver is unloading */ 697758cc3dcSJack F Vogel ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); 698758cc3dcSJack F Vogel ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; 699758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext); 700758cc3dcSJack F Vogel 701758cc3dcSJack F Vogel /* Unregister VLAN events */ 702758cc3dcSJack F Vogel if (adapter->vlan_attach != NULL) 703758cc3dcSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); 704758cc3dcSJack F Vogel if (adapter->vlan_detach != NULL) 705758cc3dcSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); 706758cc3dcSJack F Vogel 707758cc3dcSJack F Vogel ether_ifdetach(adapter->ifp); 708758cc3dcSJack F Vogel callout_drain(&adapter->timer); 709758cc3dcSJack F Vogel #ifdef DEV_NETMAP 710758cc3dcSJack F Vogel netmap_detach(adapter->ifp); 711758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 712758cc3dcSJack F Vogel ixgbe_free_pci_resources(adapter); 713758cc3dcSJack F Vogel bus_generic_detach(dev); 714758cc3dcSJack F Vogel if_free(adapter->ifp); 715758cc3dcSJack F Vogel 716758cc3dcSJack F Vogel ixgbe_free_transmit_structures(adapter); 717758cc3dcSJack F Vogel ixgbe_free_receive_structures(adapter); 718758cc3dcSJack F Vogel free(adapter->mta, M_DEVBUF); 719758cc3dcSJack F Vogel 720758cc3dcSJack F Vogel IXGBE_CORE_LOCK_DESTROY(adapter); 721758cc3dcSJack F Vogel return (0); 722758cc3dcSJack F Vogel } 723758cc3dcSJack F Vogel 724758cc3dcSJack F Vogel /********************************************************************* 725758cc3dcSJack F Vogel * 726758cc3dcSJack F Vogel * Shutdown entry point 727758cc3dcSJack F Vogel * 728758cc3dcSJack F Vogel **********************************************************************/ 729758cc3dcSJack F Vogel 730758cc3dcSJack F Vogel static int 731758cc3dcSJack F Vogel ixgbe_shutdown(device_t dev) 732758cc3dcSJack F Vogel { 733758cc3dcSJack F Vogel struct adapter *adapter = device_get_softc(dev); 7346f37f232SEric Joyner int error = 0; 7356f37f232SEric Joyner 7366f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_shutdown: begin"); 7376f37f232SEric Joyner 738758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 7396f37f232SEric Joyner error = ixgbe_setup_low_power_mode(adapter); 740758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 7416f37f232SEric Joyner 7426f37f232SEric Joyner return (error); 7436f37f232SEric Joyner } 7446f37f232SEric Joyner 7456f37f232SEric Joyner /** 7466f37f232SEric Joyner * Methods for going from: 7476f37f232SEric Joyner * D0 -> D3: ixgbe_suspend 7486f37f232SEric Joyner * D3 -> D0: ixgbe_resume 7496f37f232SEric Joyner */ 7506f37f232SEric Joyner static int 7516f37f232SEric Joyner ixgbe_suspend(device_t dev) 7526f37f232SEric Joyner { 7536f37f232SEric Joyner struct adapter *adapter = device_get_softc(dev); 7546f37f232SEric Joyner int error = 0; 7556f37f232SEric Joyner 7566f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_suspend: begin"); 7576f37f232SEric Joyner 7586f37f232SEric Joyner IXGBE_CORE_LOCK(adapter); 7596f37f232SEric Joyner 7606f37f232SEric Joyner error = ixgbe_setup_low_power_mode(adapter); 7616f37f232SEric Joyner 7626f37f232SEric Joyner /* Save state and power down */ 7636f37f232SEric Joyner pci_save_state(dev); 7646f37f232SEric Joyner pci_set_powerstate(dev, PCI_POWERSTATE_D3); 7656f37f232SEric Joyner 7666f37f232SEric Joyner IXGBE_CORE_UNLOCK(adapter); 7676f37f232SEric Joyner 7686f37f232SEric Joyner return (error); 7696f37f232SEric Joyner } 7706f37f232SEric Joyner 7716f37f232SEric Joyner static int 7726f37f232SEric Joyner ixgbe_resume(device_t dev) 7736f37f232SEric Joyner { 7746f37f232SEric Joyner struct adapter *adapter = device_get_softc(dev); 7756f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 7766f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 7776f37f232SEric Joyner u32 wus; 7786f37f232SEric Joyner 7796f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_resume: begin"); 7806f37f232SEric Joyner 7816f37f232SEric Joyner IXGBE_CORE_LOCK(adapter); 7826f37f232SEric Joyner 7836f37f232SEric Joyner pci_set_powerstate(dev, PCI_POWERSTATE_D0); 7846f37f232SEric Joyner pci_restore_state(dev); 7856f37f232SEric Joyner 7866f37f232SEric Joyner /* Read & clear WUS register */ 7876f37f232SEric Joyner wus = IXGBE_READ_REG(hw, IXGBE_WUS); 7886f37f232SEric Joyner if (wus) 7896f37f232SEric Joyner device_printf(dev, "Woken up by (WUS): %#010x\n", 7906f37f232SEric Joyner IXGBE_READ_REG(hw, IXGBE_WUS)); 7916f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); 7926f37f232SEric Joyner /* And clear WUFC until next low-power transition */ 7936f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0); 7946f37f232SEric Joyner 7956f37f232SEric Joyner /* 7966f37f232SEric Joyner * Required after D3->D0 transition; 7976f37f232SEric Joyner * will re-advertise all previous advertised speeds 7986f37f232SEric Joyner */ 7996f37f232SEric Joyner if (ifp->if_flags & IFF_UP) 8006f37f232SEric Joyner ixgbe_init_locked(adapter); 8016f37f232SEric Joyner 8026f37f232SEric Joyner IXGBE_CORE_UNLOCK(adapter); 8036f37f232SEric Joyner 8046f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_resume: end"); 805758cc3dcSJack F Vogel return (0); 806758cc3dcSJack F Vogel } 807758cc3dcSJack F Vogel 808758cc3dcSJack F Vogel 809758cc3dcSJack F Vogel /********************************************************************* 810758cc3dcSJack F Vogel * Ioctl entry point 811758cc3dcSJack F Vogel * 812758cc3dcSJack F Vogel * ixgbe_ioctl is called when the user wants to configure the 813758cc3dcSJack F Vogel * interface. 814758cc3dcSJack F Vogel * 815758cc3dcSJack F Vogel * return 0 on success, positive on failure 816758cc3dcSJack F Vogel **********************************************************************/ 817758cc3dcSJack F Vogel 818758cc3dcSJack F Vogel static int 819758cc3dcSJack F Vogel ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 820758cc3dcSJack F Vogel { 821758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 822758cc3dcSJack F Vogel struct ifreq *ifr = (struct ifreq *) data; 823758cc3dcSJack F Vogel #if defined(INET) || defined(INET6) 824758cc3dcSJack F Vogel struct ifaddr *ifa = (struct ifaddr *)data; 825758cc3dcSJack F Vogel bool avoid_reset = FALSE; 826758cc3dcSJack F Vogel #endif 827758cc3dcSJack F Vogel int error = 0; 828758cc3dcSJack F Vogel 829758cc3dcSJack F Vogel switch (command) { 830758cc3dcSJack F Vogel 831758cc3dcSJack F Vogel case SIOCSIFADDR: 832758cc3dcSJack F Vogel #ifdef INET 833758cc3dcSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET) 834758cc3dcSJack F Vogel avoid_reset = TRUE; 835758cc3dcSJack F Vogel #endif 836758cc3dcSJack F Vogel #ifdef INET6 837758cc3dcSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET6) 838758cc3dcSJack F Vogel avoid_reset = TRUE; 839758cc3dcSJack F Vogel #endif 840758cc3dcSJack F Vogel #if defined(INET) || defined(INET6) 841758cc3dcSJack F Vogel /* 842758cc3dcSJack F Vogel ** Calling init results in link renegotiation, 843758cc3dcSJack F Vogel ** so we avoid doing it when possible. 844758cc3dcSJack F Vogel */ 845758cc3dcSJack F Vogel if (avoid_reset) { 846758cc3dcSJack F Vogel ifp->if_flags |= IFF_UP; 847758cc3dcSJack F Vogel if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 848758cc3dcSJack F Vogel ixgbe_init(adapter); 849758cc3dcSJack F Vogel if (!(ifp->if_flags & IFF_NOARP)) 850758cc3dcSJack F Vogel arp_ifinit(ifp, ifa); 851758cc3dcSJack F Vogel } else 852758cc3dcSJack F Vogel error = ether_ioctl(ifp, command, data); 853758cc3dcSJack F Vogel #endif 854758cc3dcSJack F Vogel break; 855758cc3dcSJack F Vogel case SIOCSIFMTU: 856758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 8576f37f232SEric Joyner if (ifr->ifr_mtu > IXGBE_MAX_MTU) { 858758cc3dcSJack F Vogel error = EINVAL; 859758cc3dcSJack F Vogel } else { 860758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 861758cc3dcSJack F Vogel ifp->if_mtu = ifr->ifr_mtu; 862758cc3dcSJack F Vogel adapter->max_frame_size = 8636f37f232SEric Joyner ifp->if_mtu + IXGBE_MTU_HDR; 864758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 865*48056c88SJack F Vogel #ifdef PCI_IOV 866*48056c88SJack F Vogel ixgbe_recalculate_max_frame(adapter); 867*48056c88SJack F Vogel #endif 868758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 869758cc3dcSJack F Vogel } 870758cc3dcSJack F Vogel break; 871758cc3dcSJack F Vogel case SIOCSIFFLAGS: 872758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 873758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 874758cc3dcSJack F Vogel if (ifp->if_flags & IFF_UP) { 875758cc3dcSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 876758cc3dcSJack F Vogel if ((ifp->if_flags ^ adapter->if_flags) & 877758cc3dcSJack F Vogel (IFF_PROMISC | IFF_ALLMULTI)) { 878758cc3dcSJack F Vogel ixgbe_set_promisc(adapter); 879758cc3dcSJack F Vogel } 880758cc3dcSJack F Vogel } else 881758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 882758cc3dcSJack F Vogel } else 883758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) 884758cc3dcSJack F Vogel ixgbe_stop(adapter); 885758cc3dcSJack F Vogel adapter->if_flags = ifp->if_flags; 886758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 887758cc3dcSJack F Vogel break; 888758cc3dcSJack F Vogel case SIOCADDMULTI: 889758cc3dcSJack F Vogel case SIOCDELMULTI: 890758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); 891758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 892758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 893758cc3dcSJack F Vogel ixgbe_disable_intr(adapter); 894758cc3dcSJack F Vogel ixgbe_set_multi(adapter); 895758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 896758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 897758cc3dcSJack F Vogel } 898758cc3dcSJack F Vogel break; 899758cc3dcSJack F Vogel case SIOCSIFMEDIA: 900758cc3dcSJack F Vogel case SIOCGIFMEDIA: 901758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 902758cc3dcSJack F Vogel error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); 903758cc3dcSJack F Vogel break; 904758cc3dcSJack F Vogel case SIOCSIFCAP: 905758cc3dcSJack F Vogel { 906758cc3dcSJack F Vogel int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 907758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 908758cc3dcSJack F Vogel if (mask & IFCAP_HWCSUM) 909758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_HWCSUM; 910758cc3dcSJack F Vogel if (mask & IFCAP_TSO4) 911758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_TSO4; 912758cc3dcSJack F Vogel if (mask & IFCAP_TSO6) 913758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_TSO6; 914758cc3dcSJack F Vogel if (mask & IFCAP_LRO) 915758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_LRO; 916758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWTAGGING) 917758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 918758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWFILTER) 919758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 920758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWTSO) 921758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 922758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 923758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 924758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 925758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 926758cc3dcSJack F Vogel } 927758cc3dcSJack F Vogel VLAN_CAPABILITIES(ifp); 928758cc3dcSJack F Vogel break; 929758cc3dcSJack F Vogel } 930758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 931758cc3dcSJack F Vogel case SIOCGI2C: 932758cc3dcSJack F Vogel { 933758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 934758cc3dcSJack F Vogel struct ifi2creq i2c; 935758cc3dcSJack F Vogel int i; 936758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)"); 937758cc3dcSJack F Vogel error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); 938758cc3dcSJack F Vogel if (error != 0) 939758cc3dcSJack F Vogel break; 940758cc3dcSJack F Vogel if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { 941758cc3dcSJack F Vogel error = EINVAL; 942758cc3dcSJack F Vogel break; 943758cc3dcSJack F Vogel } 944758cc3dcSJack F Vogel if (i2c.len > sizeof(i2c.data)) { 945758cc3dcSJack F Vogel error = EINVAL; 946758cc3dcSJack F Vogel break; 947758cc3dcSJack F Vogel } 948758cc3dcSJack F Vogel 949758cc3dcSJack F Vogel for (i = 0; i < i2c.len; i++) 950758cc3dcSJack F Vogel hw->phy.ops.read_i2c_byte(hw, i2c.offset + i, 951758cc3dcSJack F Vogel i2c.dev_addr, &i2c.data[i]); 952758cc3dcSJack F Vogel error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); 953758cc3dcSJack F Vogel break; 954758cc3dcSJack F Vogel } 955758cc3dcSJack F Vogel #endif 956758cc3dcSJack F Vogel default: 957758cc3dcSJack F Vogel IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); 958758cc3dcSJack F Vogel error = ether_ioctl(ifp, command, data); 959758cc3dcSJack F Vogel break; 960758cc3dcSJack F Vogel } 961758cc3dcSJack F Vogel 962758cc3dcSJack F Vogel return (error); 963758cc3dcSJack F Vogel } 964758cc3dcSJack F Vogel 965758cc3dcSJack F Vogel /********************************************************************* 966758cc3dcSJack F Vogel * Init entry point 967758cc3dcSJack F Vogel * 968758cc3dcSJack F Vogel * This routine is used in two ways. It is used by the stack as 969758cc3dcSJack F Vogel * init entry point in network interface structure. It is also used 970758cc3dcSJack F Vogel * by the driver as a hw/sw initialization routine to get to a 971758cc3dcSJack F Vogel * consistent state. 972758cc3dcSJack F Vogel * 973758cc3dcSJack F Vogel * return 0 on success, positive on failure 974758cc3dcSJack F Vogel **********************************************************************/ 975758cc3dcSJack F Vogel #define IXGBE_MHADD_MFS_SHIFT 16 976758cc3dcSJack F Vogel 977758cc3dcSJack F Vogel static void 978758cc3dcSJack F Vogel ixgbe_init_locked(struct adapter *adapter) 979758cc3dcSJack F Vogel { 980758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 981758cc3dcSJack F Vogel device_t dev = adapter->dev; 982758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 983*48056c88SJack F Vogel struct tx_ring *txr; 984*48056c88SJack F Vogel struct rx_ring *rxr; 985*48056c88SJack F Vogel u32 txdctl, mhadd; 986758cc3dcSJack F Vogel u32 rxdctl, rxctrl; 987*48056c88SJack F Vogel #ifdef PCI_IOV 988*48056c88SJack F Vogel enum ixgbe_iov_mode mode; 989*48056c88SJack F Vogel #endif 990758cc3dcSJack F Vogel 991758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 992758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_init_locked: begin"); 993*48056c88SJack F Vogel 994758cc3dcSJack F Vogel hw->adapter_stopped = FALSE; 995758cc3dcSJack F Vogel ixgbe_stop_adapter(hw); 996758cc3dcSJack F Vogel callout_stop(&adapter->timer); 997758cc3dcSJack F Vogel 998*48056c88SJack F Vogel #ifdef PCI_IOV 999*48056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 1000*48056c88SJack F Vogel adapter->pool = ixgbe_max_vfs(mode); 1001*48056c88SJack F Vogel /* Queue indices may change with IOV mode */ 1002*48056c88SJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 1003*48056c88SJack F Vogel adapter->rx_rings[i].me = ixgbe_pf_que_index(mode, i); 1004*48056c88SJack F Vogel adapter->tx_rings[i].me = ixgbe_pf_que_index(mode, i); 1005*48056c88SJack F Vogel } 1006*48056c88SJack F Vogel #endif 1007758cc3dcSJack F Vogel /* reprogram the RAR[0] in case user changed it. */ 1008*48056c88SJack F Vogel ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, IXGBE_RAH_AV); 1009758cc3dcSJack F Vogel 1010758cc3dcSJack F Vogel /* Get the latest mac address, User can use a LAA */ 1011*48056c88SJack F Vogel bcopy(IF_LLADDR(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS); 1012*48056c88SJack F Vogel ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, 1); 1013758cc3dcSJack F Vogel hw->addr_ctrl.rar_used_count = 1; 1014758cc3dcSJack F Vogel 1015758cc3dcSJack F Vogel /* Set the various hardware offload abilities */ 1016758cc3dcSJack F Vogel ifp->if_hwassist = 0; 1017758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_TSO) 1018758cc3dcSJack F Vogel ifp->if_hwassist |= CSUM_TSO; 1019758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_TXCSUM) { 1020758cc3dcSJack F Vogel ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 1021758cc3dcSJack F Vogel #if __FreeBSD_version >= 800000 1022758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) 1023758cc3dcSJack F Vogel ifp->if_hwassist |= CSUM_SCTP; 1024758cc3dcSJack F Vogel #endif 1025758cc3dcSJack F Vogel } 1026758cc3dcSJack F Vogel 1027758cc3dcSJack F Vogel /* Prepare transmit descriptors and buffers */ 1028758cc3dcSJack F Vogel if (ixgbe_setup_transmit_structures(adapter)) { 1029758cc3dcSJack F Vogel device_printf(dev, "Could not setup transmit structures\n"); 1030758cc3dcSJack F Vogel ixgbe_stop(adapter); 1031758cc3dcSJack F Vogel return; 1032758cc3dcSJack F Vogel } 1033758cc3dcSJack F Vogel 1034758cc3dcSJack F Vogel ixgbe_init_hw(hw); 1035*48056c88SJack F Vogel #ifdef PCI_IOV 1036*48056c88SJack F Vogel ixgbe_initialize_iov(adapter); 1037*48056c88SJack F Vogel #endif 1038758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(adapter); 1039758cc3dcSJack F Vogel 1040758cc3dcSJack F Vogel /* Setup Multicast table */ 1041758cc3dcSJack F Vogel ixgbe_set_multi(adapter); 1042758cc3dcSJack F Vogel 1043758cc3dcSJack F Vogel /* 1044758cc3dcSJack F Vogel ** Determine the correct mbuf pool 1045758cc3dcSJack F Vogel ** for doing jumbo frames 1046758cc3dcSJack F Vogel */ 1047*48056c88SJack F Vogel if (adapter->max_frame_size <= MCLBYTES) 1048758cc3dcSJack F Vogel adapter->rx_mbuf_sz = MCLBYTES; 104930126537SJack F Vogel else 1050*48056c88SJack F Vogel adapter->rx_mbuf_sz = MJUMPAGESIZE; 1051758cc3dcSJack F Vogel 1052758cc3dcSJack F Vogel /* Prepare receive descriptors and buffers */ 1053758cc3dcSJack F Vogel if (ixgbe_setup_receive_structures(adapter)) { 1054758cc3dcSJack F Vogel device_printf(dev, "Could not setup receive structures\n"); 1055758cc3dcSJack F Vogel ixgbe_stop(adapter); 1056758cc3dcSJack F Vogel return; 1057758cc3dcSJack F Vogel } 1058758cc3dcSJack F Vogel 1059758cc3dcSJack F Vogel /* Configure RX settings */ 1060758cc3dcSJack F Vogel ixgbe_initialize_receive_units(adapter); 1061758cc3dcSJack F Vogel 1062*48056c88SJack F Vogel /* Enable SDP & MSIX interrupts based on adapter */ 1063*48056c88SJack F Vogel ixgbe_config_gpie(adapter); 1064758cc3dcSJack F Vogel 1065758cc3dcSJack F Vogel /* Set MTU size */ 1066758cc3dcSJack F Vogel if (ifp->if_mtu > ETHERMTU) { 10676f37f232SEric Joyner /* aka IXGBE_MAXFRS on 82599 and newer */ 1068758cc3dcSJack F Vogel mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); 1069758cc3dcSJack F Vogel mhadd &= ~IXGBE_MHADD_MFS_MASK; 1070758cc3dcSJack F Vogel mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; 1071758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); 1072758cc3dcSJack F Vogel } 1073758cc3dcSJack F Vogel 1074758cc3dcSJack F Vogel /* Now enable all the queues */ 1075758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 1076*48056c88SJack F Vogel txr = &adapter->tx_rings[i]; 1077*48056c88SJack F Vogel txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txr->me)); 1078758cc3dcSJack F Vogel txdctl |= IXGBE_TXDCTL_ENABLE; 1079758cc3dcSJack F Vogel /* Set WTHRESH to 8, burst writeback */ 1080758cc3dcSJack F Vogel txdctl |= (8 << 16); 1081758cc3dcSJack F Vogel /* 1082758cc3dcSJack F Vogel * When the internal queue falls below PTHRESH (32), 1083758cc3dcSJack F Vogel * start prefetching as long as there are at least 1084758cc3dcSJack F Vogel * HTHRESH (1) buffers ready. The values are taken 1085758cc3dcSJack F Vogel * from the Intel linux driver 3.8.21. 1086758cc3dcSJack F Vogel * Prefetching enables tx line rate even with 1 queue. 1087758cc3dcSJack F Vogel */ 1088758cc3dcSJack F Vogel txdctl |= (32 << 0) | (1 << 8); 1089*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txr->me), txdctl); 1090758cc3dcSJack F Vogel } 1091758cc3dcSJack F Vogel 1092*48056c88SJack F Vogel for (int i = 0, j = 0; i < adapter->num_queues; i++) { 1093*48056c88SJack F Vogel rxr = &adapter->rx_rings[i]; 1094*48056c88SJack F Vogel rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); 1095758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1096758cc3dcSJack F Vogel /* 1097758cc3dcSJack F Vogel ** PTHRESH = 21 1098758cc3dcSJack F Vogel ** HTHRESH = 4 1099758cc3dcSJack F Vogel ** WTHRESH = 8 1100758cc3dcSJack F Vogel */ 1101758cc3dcSJack F Vogel rxdctl &= ~0x3FFFFF; 1102758cc3dcSJack F Vogel rxdctl |= 0x080420; 1103758cc3dcSJack F Vogel } 1104758cc3dcSJack F Vogel rxdctl |= IXGBE_RXDCTL_ENABLE; 1105*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), rxdctl); 1106*48056c88SJack F Vogel for (; j < 10; j++) { 1107*48056c88SJack F Vogel if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)) & 1108758cc3dcSJack F Vogel IXGBE_RXDCTL_ENABLE) 1109758cc3dcSJack F Vogel break; 1110758cc3dcSJack F Vogel else 1111758cc3dcSJack F Vogel msec_delay(1); 1112758cc3dcSJack F Vogel } 1113758cc3dcSJack F Vogel wmb(); 1114758cc3dcSJack F Vogel #ifdef DEV_NETMAP 1115758cc3dcSJack F Vogel /* 1116758cc3dcSJack F Vogel * In netmap mode, we must preserve the buffers made 1117758cc3dcSJack F Vogel * available to userspace before the if_init() 1118758cc3dcSJack F Vogel * (this is true by default on the TX side, because 1119758cc3dcSJack F Vogel * init makes all buffers available to userspace). 1120758cc3dcSJack F Vogel * 1121758cc3dcSJack F Vogel * netmap_reset() and the device specific routines 1122758cc3dcSJack F Vogel * (e.g. ixgbe_setup_receive_rings()) map these 1123758cc3dcSJack F Vogel * buffers at the end of the NIC ring, so here we 1124758cc3dcSJack F Vogel * must set the RDT (tail) register to make sure 1125758cc3dcSJack F Vogel * they are not overwritten. 1126758cc3dcSJack F Vogel * 1127758cc3dcSJack F Vogel * In this driver the NIC ring starts at RDH = 0, 1128758cc3dcSJack F Vogel * RDT points to the last slot available for reception (?), 1129758cc3dcSJack F Vogel * so RDT = num_rx_desc - 1 means the whole ring is available. 1130758cc3dcSJack F Vogel */ 1131758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_NETMAP) { 1132758cc3dcSJack F Vogel struct netmap_adapter *na = NA(adapter->ifp); 1133758cc3dcSJack F Vogel struct netmap_kring *kring = &na->rx_rings[i]; 1134758cc3dcSJack F Vogel int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); 1135758cc3dcSJack F Vogel 1136*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), t); 1137758cc3dcSJack F Vogel } else 1138758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 1139*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), adapter->num_rx_desc - 1); 1140758cc3dcSJack F Vogel } 1141758cc3dcSJack F Vogel 1142758cc3dcSJack F Vogel /* Enable Receive engine */ 1143758cc3dcSJack F Vogel rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); 1144758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 1145758cc3dcSJack F Vogel rxctrl |= IXGBE_RXCTRL_DMBYPS; 1146758cc3dcSJack F Vogel rxctrl |= IXGBE_RXCTRL_RXEN; 1147758cc3dcSJack F Vogel ixgbe_enable_rx_dma(hw, rxctrl); 1148758cc3dcSJack F Vogel 1149758cc3dcSJack F Vogel callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); 1150758cc3dcSJack F Vogel 1151758cc3dcSJack F Vogel /* Set up MSI/X routing */ 1152758cc3dcSJack F Vogel if (ixgbe_enable_msix) { 1153758cc3dcSJack F Vogel ixgbe_configure_ivars(adapter); 1154758cc3dcSJack F Vogel /* Set up auto-mask */ 1155758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 1156758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); 1157758cc3dcSJack F Vogel else { 1158758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); 1159758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); 1160758cc3dcSJack F Vogel } 1161758cc3dcSJack F Vogel } else { /* Simple settings for Legacy/MSI */ 1162758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 0, 0, 0); 1163758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 0, 0, 1); 1164758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); 1165758cc3dcSJack F Vogel } 1166758cc3dcSJack F Vogel 1167758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 1168758cc3dcSJack F Vogel /* Init Flow director */ 1169758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 1170758cc3dcSJack F Vogel u32 hdrm = 32 << fdir_pballoc; 1171758cc3dcSJack F Vogel 1172758cc3dcSJack F Vogel hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL); 1173758cc3dcSJack F Vogel ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); 1174758cc3dcSJack F Vogel } 1175758cc3dcSJack F Vogel #endif 1176758cc3dcSJack F Vogel 1177758cc3dcSJack F Vogel /* 1178*48056c88SJack F Vogel * Check on any SFP devices that 1179*48056c88SJack F Vogel * need to be kick-started 1180758cc3dcSJack F Vogel */ 1181758cc3dcSJack F Vogel if (hw->phy.type == ixgbe_phy_none) { 1182758cc3dcSJack F Vogel int err = hw->phy.ops.identify(hw); 1183758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 1184758cc3dcSJack F Vogel device_printf(dev, 1185758cc3dcSJack F Vogel "Unsupported SFP+ module type was detected.\n"); 1186758cc3dcSJack F Vogel return; 1187758cc3dcSJack F Vogel } 1188758cc3dcSJack F Vogel } 1189758cc3dcSJack F Vogel 1190758cc3dcSJack F Vogel /* Set moderation on the Link interrupt */ 1191758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR); 1192758cc3dcSJack F Vogel 11936f37f232SEric Joyner /* Configure Energy Efficient Ethernet for supported devices */ 11946f37f232SEric Joyner ixgbe_setup_eee(hw, adapter->eee_enabled); 11956f37f232SEric Joyner 1196758cc3dcSJack F Vogel /* Config/Enable Link */ 1197758cc3dcSJack F Vogel ixgbe_config_link(adapter); 1198758cc3dcSJack F Vogel 1199758cc3dcSJack F Vogel /* Hardware Packet Buffer & Flow Control setup */ 12006f37f232SEric Joyner ixgbe_config_delay_values(adapter); 1201758cc3dcSJack F Vogel 1202758cc3dcSJack F Vogel /* Initialize the FC settings */ 1203758cc3dcSJack F Vogel ixgbe_start_hw(hw); 1204758cc3dcSJack F Vogel 1205758cc3dcSJack F Vogel /* Set up VLAN support and filter */ 1206758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 1207758cc3dcSJack F Vogel 12086f37f232SEric Joyner /* Setup DMA Coalescing */ 12096f37f232SEric Joyner ixgbe_config_dmac(adapter); 12106f37f232SEric Joyner 1211758cc3dcSJack F Vogel /* And now turn on interrupts */ 1212758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1213758cc3dcSJack F Vogel 1214*48056c88SJack F Vogel #ifdef PCI_IOV 1215*48056c88SJack F Vogel /* Enable the use of the MBX by the VF's */ 1216*48056c88SJack F Vogel { 1217*48056c88SJack F Vogel u32 reg = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 1218*48056c88SJack F Vogel reg |= IXGBE_CTRL_EXT_PFRSTD; 1219*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, reg); 1220*48056c88SJack F Vogel } 1221*48056c88SJack F Vogel #endif 1222*48056c88SJack F Vogel 1223758cc3dcSJack F Vogel /* Now inform the stack we're ready */ 1224758cc3dcSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 1225758cc3dcSJack F Vogel 1226758cc3dcSJack F Vogel return; 1227758cc3dcSJack F Vogel } 1228758cc3dcSJack F Vogel 1229758cc3dcSJack F Vogel static void 1230758cc3dcSJack F Vogel ixgbe_init(void *arg) 1231758cc3dcSJack F Vogel { 1232758cc3dcSJack F Vogel struct adapter *adapter = arg; 1233758cc3dcSJack F Vogel 1234758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 1235758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 1236758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1237758cc3dcSJack F Vogel return; 1238758cc3dcSJack F Vogel } 1239758cc3dcSJack F Vogel 12406f37f232SEric Joyner static void 1241*48056c88SJack F Vogel ixgbe_config_gpie(struct adapter *adapter) 1242*48056c88SJack F Vogel { 1243*48056c88SJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1244*48056c88SJack F Vogel u32 gpie; 1245*48056c88SJack F Vogel 1246*48056c88SJack F Vogel gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); 1247*48056c88SJack F Vogel 1248*48056c88SJack F Vogel /* Fan Failure Interrupt */ 1249*48056c88SJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) 1250*48056c88SJack F Vogel gpie |= IXGBE_SDP1_GPIEN; 1251*48056c88SJack F Vogel 1252*48056c88SJack F Vogel /* 1253*48056c88SJack F Vogel * Module detection (SDP2) 1254*48056c88SJack F Vogel * Media ready (SDP1) 1255*48056c88SJack F Vogel */ 1256*48056c88SJack F Vogel if (hw->mac.type == ixgbe_mac_82599EB) { 1257*48056c88SJack F Vogel gpie |= IXGBE_SDP2_GPIEN; 1258*48056c88SJack F Vogel if (hw->device_id != IXGBE_DEV_ID_82599_QSFP_SF_QP) 1259*48056c88SJack F Vogel gpie |= IXGBE_SDP1_GPIEN; 1260*48056c88SJack F Vogel } 1261*48056c88SJack F Vogel 1262*48056c88SJack F Vogel /* 1263*48056c88SJack F Vogel * Thermal Failure Detection (X540) 1264*48056c88SJack F Vogel * Link Detection (X557) 1265*48056c88SJack F Vogel */ 1266*48056c88SJack F Vogel if (hw->mac.type == ixgbe_mac_X540 || 1267*48056c88SJack F Vogel hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || 1268*48056c88SJack F Vogel hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) 1269*48056c88SJack F Vogel gpie |= IXGBE_SDP0_GPIEN_X540; 1270*48056c88SJack F Vogel 1271*48056c88SJack F Vogel if (adapter->msix > 1) { 1272*48056c88SJack F Vogel /* Enable Enhanced MSIX mode */ 1273*48056c88SJack F Vogel gpie |= IXGBE_GPIE_MSIX_MODE; 1274*48056c88SJack F Vogel gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | 1275*48056c88SJack F Vogel IXGBE_GPIE_OCD; 1276*48056c88SJack F Vogel } 1277*48056c88SJack F Vogel 1278*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 1279*48056c88SJack F Vogel return; 1280*48056c88SJack F Vogel } 1281*48056c88SJack F Vogel 1282*48056c88SJack F Vogel /* 1283*48056c88SJack F Vogel * Requires adapter->max_frame_size to be set. 1284*48056c88SJack F Vogel */ 1285*48056c88SJack F Vogel static void 12866f37f232SEric Joyner ixgbe_config_delay_values(struct adapter *adapter) 12876f37f232SEric Joyner { 12886f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 12896f37f232SEric Joyner u32 rxpb, frame, size, tmp; 12906f37f232SEric Joyner 12916f37f232SEric Joyner frame = adapter->max_frame_size; 12926f37f232SEric Joyner 12936f37f232SEric Joyner /* Calculate High Water */ 12946f37f232SEric Joyner switch (hw->mac.type) { 12956f37f232SEric Joyner case ixgbe_mac_X540: 12966f37f232SEric Joyner case ixgbe_mac_X550: 12976f37f232SEric Joyner case ixgbe_mac_X550EM_x: 12986f37f232SEric Joyner tmp = IXGBE_DV_X540(frame, frame); 12996f37f232SEric Joyner break; 13006f37f232SEric Joyner default: 13016f37f232SEric Joyner tmp = IXGBE_DV(frame, frame); 13026f37f232SEric Joyner break; 13036f37f232SEric Joyner } 13046f37f232SEric Joyner size = IXGBE_BT2KB(tmp); 13056f37f232SEric Joyner rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10; 13066f37f232SEric Joyner hw->fc.high_water[0] = rxpb - size; 13076f37f232SEric Joyner 13086f37f232SEric Joyner /* Now calculate Low Water */ 13096f37f232SEric Joyner switch (hw->mac.type) { 13106f37f232SEric Joyner case ixgbe_mac_X540: 13116f37f232SEric Joyner case ixgbe_mac_X550: 13126f37f232SEric Joyner case ixgbe_mac_X550EM_x: 13136f37f232SEric Joyner tmp = IXGBE_LOW_DV_X540(frame); 13146f37f232SEric Joyner break; 13156f37f232SEric Joyner default: 13166f37f232SEric Joyner tmp = IXGBE_LOW_DV(frame); 13176f37f232SEric Joyner break; 13186f37f232SEric Joyner } 13196f37f232SEric Joyner hw->fc.low_water[0] = IXGBE_BT2KB(tmp); 13206f37f232SEric Joyner 13216f37f232SEric Joyner hw->fc.requested_mode = adapter->fc; 13226f37f232SEric Joyner hw->fc.pause_time = IXGBE_FC_PAUSE; 13236f37f232SEric Joyner hw->fc.send_xon = TRUE; 13246f37f232SEric Joyner } 1325758cc3dcSJack F Vogel 1326758cc3dcSJack F Vogel /* 1327758cc3dcSJack F Vogel ** 1328758cc3dcSJack F Vogel ** MSIX Interrupt Handlers and Tasklets 1329758cc3dcSJack F Vogel ** 1330758cc3dcSJack F Vogel */ 1331758cc3dcSJack F Vogel 1332758cc3dcSJack F Vogel static inline void 1333758cc3dcSJack F Vogel ixgbe_enable_queue(struct adapter *adapter, u32 vector) 1334758cc3dcSJack F Vogel { 1335758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1336758cc3dcSJack F Vogel u64 queue = (u64)(1 << vector); 1337758cc3dcSJack F Vogel u32 mask; 1338758cc3dcSJack F Vogel 1339758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1340758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queue); 1341758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); 1342758cc3dcSJack F Vogel } else { 1343758cc3dcSJack F Vogel mask = (queue & 0xFFFFFFFF); 1344758cc3dcSJack F Vogel if (mask) 1345758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask); 1346758cc3dcSJack F Vogel mask = (queue >> 32); 1347758cc3dcSJack F Vogel if (mask) 1348758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask); 1349758cc3dcSJack F Vogel } 1350758cc3dcSJack F Vogel } 1351758cc3dcSJack F Vogel 1352758cc3dcSJack F Vogel static inline void 1353758cc3dcSJack F Vogel ixgbe_disable_queue(struct adapter *adapter, u32 vector) 1354758cc3dcSJack F Vogel { 1355758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1356758cc3dcSJack F Vogel u64 queue = (u64)(1 << vector); 1357758cc3dcSJack F Vogel u32 mask; 1358758cc3dcSJack F Vogel 1359758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1360758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queue); 1361758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask); 1362758cc3dcSJack F Vogel } else { 1363758cc3dcSJack F Vogel mask = (queue & 0xFFFFFFFF); 1364758cc3dcSJack F Vogel if (mask) 1365758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask); 1366758cc3dcSJack F Vogel mask = (queue >> 32); 1367758cc3dcSJack F Vogel if (mask) 1368758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask); 1369758cc3dcSJack F Vogel } 1370758cc3dcSJack F Vogel } 1371758cc3dcSJack F Vogel 1372758cc3dcSJack F Vogel static void 1373758cc3dcSJack F Vogel ixgbe_handle_que(void *context, int pending) 1374758cc3dcSJack F Vogel { 1375758cc3dcSJack F Vogel struct ix_queue *que = context; 1376758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1377758cc3dcSJack F Vogel struct tx_ring *txr = que->txr; 1378758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1379758cc3dcSJack F Vogel 1380758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1381*48056c88SJack F Vogel ixgbe_rxeof(que); 1382758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1383758cc3dcSJack F Vogel ixgbe_txeof(txr); 1384758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 1385758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1386758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1387758cc3dcSJack F Vogel #else 1388758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1389758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1390758cc3dcSJack F Vogel #endif 1391758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1392758cc3dcSJack F Vogel } 1393758cc3dcSJack F Vogel 1394758cc3dcSJack F Vogel /* Reenable this interrupt */ 1395758cc3dcSJack F Vogel if (que->res != NULL) 1396758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 1397758cc3dcSJack F Vogel else 1398758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1399758cc3dcSJack F Vogel return; 1400758cc3dcSJack F Vogel } 1401758cc3dcSJack F Vogel 1402758cc3dcSJack F Vogel 1403758cc3dcSJack F Vogel /********************************************************************* 1404758cc3dcSJack F Vogel * 1405758cc3dcSJack F Vogel * Legacy Interrupt Service routine 1406758cc3dcSJack F Vogel * 1407758cc3dcSJack F Vogel **********************************************************************/ 1408758cc3dcSJack F Vogel 1409758cc3dcSJack F Vogel static void 1410758cc3dcSJack F Vogel ixgbe_legacy_irq(void *arg) 1411758cc3dcSJack F Vogel { 1412758cc3dcSJack F Vogel struct ix_queue *que = arg; 1413758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1414758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1415758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1416758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 1417758cc3dcSJack F Vogel bool more; 1418758cc3dcSJack F Vogel u32 reg_eicr; 1419758cc3dcSJack F Vogel 1420758cc3dcSJack F Vogel 1421758cc3dcSJack F Vogel reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 1422758cc3dcSJack F Vogel 1423758cc3dcSJack F Vogel ++que->irqs; 1424758cc3dcSJack F Vogel if (reg_eicr == 0) { 1425758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1426758cc3dcSJack F Vogel return; 1427758cc3dcSJack F Vogel } 1428758cc3dcSJack F Vogel 1429758cc3dcSJack F Vogel more = ixgbe_rxeof(que); 1430758cc3dcSJack F Vogel 1431758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1432758cc3dcSJack F Vogel ixgbe_txeof(txr); 1433758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX 1434758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1435758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1436758cc3dcSJack F Vogel #else 1437758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1438758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1439758cc3dcSJack F Vogel #endif 1440758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1441758cc3dcSJack F Vogel 1442758cc3dcSJack F Vogel /* Check for fan failure */ 1443*48056c88SJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82598AT) && 1444*48056c88SJack F Vogel (reg_eicr & IXGBE_EICR_GPI_SDP1)) { 1445758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " 1446758cc3dcSJack F Vogel "REPLACE IMMEDIATELY!!\n"); 1447758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 1448758cc3dcSJack F Vogel } 1449758cc3dcSJack F Vogel 1450758cc3dcSJack F Vogel /* Link status change */ 1451758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_LSC) 1452758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->link_task); 1453758cc3dcSJack F Vogel 14546f37f232SEric Joyner /* External PHY interrupt */ 14556f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && 14566f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) 14576f37f232SEric Joyner taskqueue_enqueue(adapter->tq, &adapter->phy_task); 14586f37f232SEric Joyner 1459758cc3dcSJack F Vogel if (more) 1460758cc3dcSJack F Vogel taskqueue_enqueue(que->tq, &que->que_task); 1461758cc3dcSJack F Vogel else 1462758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1463758cc3dcSJack F Vogel return; 1464758cc3dcSJack F Vogel } 1465758cc3dcSJack F Vogel 1466758cc3dcSJack F Vogel 1467758cc3dcSJack F Vogel /********************************************************************* 1468758cc3dcSJack F Vogel * 1469758cc3dcSJack F Vogel * MSIX Queue Interrupt Service routine 1470758cc3dcSJack F Vogel * 1471758cc3dcSJack F Vogel **********************************************************************/ 1472758cc3dcSJack F Vogel void 1473758cc3dcSJack F Vogel ixgbe_msix_que(void *arg) 1474758cc3dcSJack F Vogel { 1475758cc3dcSJack F Vogel struct ix_queue *que = arg; 1476758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1477758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1478758cc3dcSJack F Vogel struct tx_ring *txr = que->txr; 1479758cc3dcSJack F Vogel struct rx_ring *rxr = que->rxr; 1480758cc3dcSJack F Vogel bool more; 1481758cc3dcSJack F Vogel u32 newitr = 0; 1482758cc3dcSJack F Vogel 1483*48056c88SJack F Vogel 1484758cc3dcSJack F Vogel /* Protect against spurious interrupts */ 1485758cc3dcSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1486758cc3dcSJack F Vogel return; 1487758cc3dcSJack F Vogel 1488758cc3dcSJack F Vogel ixgbe_disable_queue(adapter, que->msix); 1489758cc3dcSJack F Vogel ++que->irqs; 1490758cc3dcSJack F Vogel 1491758cc3dcSJack F Vogel more = ixgbe_rxeof(que); 1492758cc3dcSJack F Vogel 1493758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1494758cc3dcSJack F Vogel ixgbe_txeof(txr); 1495758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX 1496758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(ifp->if_snd)) 1497758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1498758cc3dcSJack F Vogel #else 1499758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1500758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1501758cc3dcSJack F Vogel #endif 1502758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1503758cc3dcSJack F Vogel 1504758cc3dcSJack F Vogel /* Do AIM now? */ 1505758cc3dcSJack F Vogel 1506758cc3dcSJack F Vogel if (ixgbe_enable_aim == FALSE) 1507758cc3dcSJack F Vogel goto no_calc; 1508758cc3dcSJack F Vogel /* 1509758cc3dcSJack F Vogel ** Do Adaptive Interrupt Moderation: 1510758cc3dcSJack F Vogel ** - Write out last calculated setting 1511758cc3dcSJack F Vogel ** - Calculate based on average size over 1512758cc3dcSJack F Vogel ** the last interval. 1513758cc3dcSJack F Vogel */ 1514758cc3dcSJack F Vogel if (que->eitr_setting) 1515758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, 1516758cc3dcSJack F Vogel IXGBE_EITR(que->msix), que->eitr_setting); 1517758cc3dcSJack F Vogel 1518758cc3dcSJack F Vogel que->eitr_setting = 0; 1519758cc3dcSJack F Vogel 1520758cc3dcSJack F Vogel /* Idle, do nothing */ 1521758cc3dcSJack F Vogel if ((txr->bytes == 0) && (rxr->bytes == 0)) 1522758cc3dcSJack F Vogel goto no_calc; 1523758cc3dcSJack F Vogel 1524758cc3dcSJack F Vogel if ((txr->bytes) && (txr->packets)) 1525758cc3dcSJack F Vogel newitr = txr->bytes/txr->packets; 1526758cc3dcSJack F Vogel if ((rxr->bytes) && (rxr->packets)) 1527758cc3dcSJack F Vogel newitr = max(newitr, 1528758cc3dcSJack F Vogel (rxr->bytes / rxr->packets)); 1529758cc3dcSJack F Vogel newitr += 24; /* account for hardware frame, crc */ 1530758cc3dcSJack F Vogel 1531758cc3dcSJack F Vogel /* set an upper boundary */ 1532758cc3dcSJack F Vogel newitr = min(newitr, 3000); 1533758cc3dcSJack F Vogel 1534758cc3dcSJack F Vogel /* Be nice to the mid range */ 1535758cc3dcSJack F Vogel if ((newitr > 300) && (newitr < 1200)) 1536758cc3dcSJack F Vogel newitr = (newitr / 3); 1537758cc3dcSJack F Vogel else 1538758cc3dcSJack F Vogel newitr = (newitr / 2); 1539758cc3dcSJack F Vogel 1540758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) 1541758cc3dcSJack F Vogel newitr |= newitr << 16; 1542758cc3dcSJack F Vogel else 1543758cc3dcSJack F Vogel newitr |= IXGBE_EITR_CNT_WDIS; 1544758cc3dcSJack F Vogel 1545758cc3dcSJack F Vogel /* save for next interrupt */ 1546758cc3dcSJack F Vogel que->eitr_setting = newitr; 1547758cc3dcSJack F Vogel 1548758cc3dcSJack F Vogel /* Reset state */ 1549758cc3dcSJack F Vogel txr->bytes = 0; 1550758cc3dcSJack F Vogel txr->packets = 0; 1551758cc3dcSJack F Vogel rxr->bytes = 0; 1552758cc3dcSJack F Vogel rxr->packets = 0; 1553758cc3dcSJack F Vogel 1554758cc3dcSJack F Vogel no_calc: 1555758cc3dcSJack F Vogel if (more) 1556758cc3dcSJack F Vogel taskqueue_enqueue(que->tq, &que->que_task); 1557758cc3dcSJack F Vogel else 1558758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 1559758cc3dcSJack F Vogel return; 1560758cc3dcSJack F Vogel } 1561758cc3dcSJack F Vogel 1562758cc3dcSJack F Vogel 1563758cc3dcSJack F Vogel static void 1564758cc3dcSJack F Vogel ixgbe_msix_link(void *arg) 1565758cc3dcSJack F Vogel { 1566758cc3dcSJack F Vogel struct adapter *adapter = arg; 1567758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 15686f37f232SEric Joyner u32 reg_eicr, mod_mask; 1569758cc3dcSJack F Vogel 15706f37f232SEric Joyner ++adapter->link_irq; 1571758cc3dcSJack F Vogel 1572758cc3dcSJack F Vogel /* First get the cause */ 1573758cc3dcSJack F Vogel reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS); 1574758cc3dcSJack F Vogel /* Be sure the queue bits are not cleared */ 1575758cc3dcSJack F Vogel reg_eicr &= ~IXGBE_EICR_RTX_QUEUE; 1576758cc3dcSJack F Vogel /* Clear interrupt with write */ 1577758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr); 1578758cc3dcSJack F Vogel 1579758cc3dcSJack F Vogel /* Link status change */ 1580758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_LSC) 1581758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->link_task); 1582758cc3dcSJack F Vogel 1583758cc3dcSJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82598EB) { 1584758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 1585758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_FLOW_DIR) { 1586758cc3dcSJack F Vogel /* This is probably overkill :) */ 1587758cc3dcSJack F Vogel if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1)) 1588758cc3dcSJack F Vogel return; 1589758cc3dcSJack F Vogel /* Disable the interrupt */ 1590758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR); 1591758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->fdir_task); 1592758cc3dcSJack F Vogel } else 1593758cc3dcSJack F Vogel #endif 1594758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_ECC) { 1595758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: ECC ERROR!! " 1596758cc3dcSJack F Vogel "Please Reboot!!\n"); 1597758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); 15986f37f232SEric Joyner } 15996f37f232SEric Joyner 16006f37f232SEric Joyner /* Check for over temp condition */ 16016f37f232SEric Joyner if (reg_eicr & IXGBE_EICR_TS) { 16026f37f232SEric Joyner device_printf(adapter->dev, "\nCRITICAL: OVER TEMP!! " 16036f37f232SEric Joyner "PHY IS SHUT DOWN!!\n"); 16046f37f232SEric Joyner device_printf(adapter->dev, "System shutdown required!\n"); 16056f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); 16066f37f232SEric Joyner } 1607*48056c88SJack F Vogel #ifdef PCI_IOV 1608*48056c88SJack F Vogel if (reg_eicr & IXGBE_EICR_MAILBOX) 1609*48056c88SJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mbx_task); 1610*48056c88SJack F Vogel #endif 16116f37f232SEric Joyner } 16126f37f232SEric Joyner 16136f37f232SEric Joyner /* Pluggable optics-related interrupt */ 16146f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) 16156f37f232SEric Joyner mod_mask = IXGBE_EICR_GPI_SDP0_X540; 16166f37f232SEric Joyner else 16176f37f232SEric Joyner mod_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw); 1618758cc3dcSJack F Vogel 1619758cc3dcSJack F Vogel if (ixgbe_is_sfp(hw)) { 16206f37f232SEric Joyner if (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) { 1621758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 1622758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 16236f37f232SEric Joyner } else if (reg_eicr & mod_mask) { 16246f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, mod_mask); 1625758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mod_task); 1626758cc3dcSJack F Vogel } 1627758cc3dcSJack F Vogel } 1628758cc3dcSJack F Vogel 1629758cc3dcSJack F Vogel /* Check for fan failure */ 1630758cc3dcSJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82598AT) && 16316f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP1)) { 16326f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); 1633758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " 1634758cc3dcSJack F Vogel "REPLACE IMMEDIATELY!!\n"); 1635758cc3dcSJack F Vogel } 1636758cc3dcSJack F Vogel 16376f37f232SEric Joyner /* External PHY interrupt */ 16386f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && 16396f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) { 16406f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540); 16416f37f232SEric Joyner taskqueue_enqueue(adapter->tq, &adapter->phy_task); 1642758cc3dcSJack F Vogel } 1643758cc3dcSJack F Vogel 1644758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); 1645758cc3dcSJack F Vogel return; 1646758cc3dcSJack F Vogel } 1647758cc3dcSJack F Vogel 1648758cc3dcSJack F Vogel /********************************************************************* 1649758cc3dcSJack F Vogel * 1650758cc3dcSJack F Vogel * Media Ioctl callback 1651758cc3dcSJack F Vogel * 1652758cc3dcSJack F Vogel * This routine is called whenever the user queries the status of 1653758cc3dcSJack F Vogel * the interface using ifconfig. 1654758cc3dcSJack F Vogel * 1655758cc3dcSJack F Vogel **********************************************************************/ 1656758cc3dcSJack F Vogel static void 1657758cc3dcSJack F Vogel ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 1658758cc3dcSJack F Vogel { 1659758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 1660758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1661758cc3dcSJack F Vogel int layer; 1662758cc3dcSJack F Vogel 1663758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_media_status: begin"); 1664758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 1665758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 1666758cc3dcSJack F Vogel 1667758cc3dcSJack F Vogel ifmr->ifm_status = IFM_AVALID; 1668758cc3dcSJack F Vogel ifmr->ifm_active = IFM_ETHER; 1669758cc3dcSJack F Vogel 1670758cc3dcSJack F Vogel if (!adapter->link_active) { 1671758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1672758cc3dcSJack F Vogel return; 1673758cc3dcSJack F Vogel } 1674758cc3dcSJack F Vogel 1675758cc3dcSJack F Vogel ifmr->ifm_status |= IFM_ACTIVE; 1676*48056c88SJack F Vogel layer = adapter->phy_layer; 1677758cc3dcSJack F Vogel 1678758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T || 1679758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_1000BASE_T || 1680758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) 1681758cc3dcSJack F Vogel switch (adapter->link_speed) { 1682758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1683758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 1684758cc3dcSJack F Vogel break; 1685758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1686758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_T | IFM_FDX; 1687758cc3dcSJack F Vogel break; 1688758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_100_FULL: 1689758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_100_TX | IFM_FDX; 1690758cc3dcSJack F Vogel break; 1691758cc3dcSJack F Vogel } 1692758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || 1693758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) 1694758cc3dcSJack F Vogel switch (adapter->link_speed) { 1695758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1696758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX | IFM_FDX; 1697758cc3dcSJack F Vogel break; 1698758cc3dcSJack F Vogel } 1699758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) 1700758cc3dcSJack F Vogel switch (adapter->link_speed) { 1701758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1702758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_LR | IFM_FDX; 1703758cc3dcSJack F Vogel break; 1704758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1705758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; 1706758cc3dcSJack F Vogel break; 1707758cc3dcSJack F Vogel } 1708758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM) 1709758cc3dcSJack F Vogel switch (adapter->link_speed) { 1710758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1711758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_LRM | IFM_FDX; 1712758cc3dcSJack F Vogel break; 1713758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1714758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; 1715758cc3dcSJack F Vogel break; 1716758cc3dcSJack F Vogel } 1717758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR || 1718758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) 1719758cc3dcSJack F Vogel switch (adapter->link_speed) { 1720758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1721758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; 1722758cc3dcSJack F Vogel break; 1723758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1724758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; 1725758cc3dcSJack F Vogel break; 1726758cc3dcSJack F Vogel } 1727758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) 1728758cc3dcSJack F Vogel switch (adapter->link_speed) { 1729758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1730758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; 1731758cc3dcSJack F Vogel break; 1732758cc3dcSJack F Vogel } 1733758cc3dcSJack F Vogel /* 1734758cc3dcSJack F Vogel ** XXX: These need to use the proper media types once 1735758cc3dcSJack F Vogel ** they're added. 1736758cc3dcSJack F Vogel */ 1737758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) 1738758cc3dcSJack F Vogel switch (adapter->link_speed) { 1739758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 17406f37f232SEric Joyner ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; 17416f37f232SEric Joyner break; 17426f37f232SEric Joyner case IXGBE_LINK_SPEED_2_5GB_FULL: 17436f37f232SEric Joyner ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; 1744758cc3dcSJack F Vogel break; 1745758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 17466f37f232SEric Joyner ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; 1747758cc3dcSJack F Vogel break; 1748758cc3dcSJack F Vogel } 17496f37f232SEric Joyner else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 1750758cc3dcSJack F Vogel || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) 1751758cc3dcSJack F Vogel switch (adapter->link_speed) { 1752758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 17536f37f232SEric Joyner ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; 17546f37f232SEric Joyner break; 17556f37f232SEric Joyner case IXGBE_LINK_SPEED_2_5GB_FULL: 17566f37f232SEric Joyner ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; 1757758cc3dcSJack F Vogel break; 1758758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 17596f37f232SEric Joyner ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; 1760758cc3dcSJack F Vogel break; 1761758cc3dcSJack F Vogel } 1762758cc3dcSJack F Vogel 1763758cc3dcSJack F Vogel /* If nothing is recognized... */ 1764758cc3dcSJack F Vogel if (IFM_SUBTYPE(ifmr->ifm_active) == 0) 1765758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_UNKNOWN; 1766758cc3dcSJack F Vogel 1767758cc3dcSJack F Vogel #if __FreeBSD_version >= 900025 17686f37f232SEric Joyner /* Display current flow control setting used on link */ 17696f37f232SEric Joyner if (hw->fc.current_mode == ixgbe_fc_rx_pause || 17706f37f232SEric Joyner hw->fc.current_mode == ixgbe_fc_full) 1771758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_ETH_RXPAUSE; 17726f37f232SEric Joyner if (hw->fc.current_mode == ixgbe_fc_tx_pause || 17736f37f232SEric Joyner hw->fc.current_mode == ixgbe_fc_full) 1774758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_ETH_TXPAUSE; 1775758cc3dcSJack F Vogel #endif 1776758cc3dcSJack F Vogel 1777758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1778758cc3dcSJack F Vogel 1779758cc3dcSJack F Vogel return; 1780758cc3dcSJack F Vogel } 1781758cc3dcSJack F Vogel 1782758cc3dcSJack F Vogel /********************************************************************* 1783758cc3dcSJack F Vogel * 1784758cc3dcSJack F Vogel * Media Ioctl callback 1785758cc3dcSJack F Vogel * 1786758cc3dcSJack F Vogel * This routine is called when the user changes speed/duplex using 1787758cc3dcSJack F Vogel * media/mediopt option with ifconfig. 1788758cc3dcSJack F Vogel * 1789758cc3dcSJack F Vogel **********************************************************************/ 1790758cc3dcSJack F Vogel static int 1791758cc3dcSJack F Vogel ixgbe_media_change(struct ifnet * ifp) 1792758cc3dcSJack F Vogel { 1793758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 1794758cc3dcSJack F Vogel struct ifmedia *ifm = &adapter->media; 1795758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1796758cc3dcSJack F Vogel ixgbe_link_speed speed = 0; 1797758cc3dcSJack F Vogel 1798758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_media_change: begin"); 1799758cc3dcSJack F Vogel 1800758cc3dcSJack F Vogel if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1801758cc3dcSJack F Vogel return (EINVAL); 1802758cc3dcSJack F Vogel 18036f37f232SEric Joyner if (hw->phy.media_type == ixgbe_media_type_backplane) 18046f37f232SEric Joyner return (EPERM); 18056f37f232SEric Joyner 1806758cc3dcSJack F Vogel /* 1807758cc3dcSJack F Vogel ** We don't actually need to check against the supported 1808758cc3dcSJack F Vogel ** media types of the adapter; ifmedia will take care of 1809758cc3dcSJack F Vogel ** that for us. 1810758cc3dcSJack F Vogel */ 1811758cc3dcSJack F Vogel switch (IFM_SUBTYPE(ifm->ifm_media)) { 1812758cc3dcSJack F Vogel case IFM_AUTO: 1813758cc3dcSJack F Vogel case IFM_10G_T: 1814758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1815758cc3dcSJack F Vogel case IFM_10G_LRM: 1816758cc3dcSJack F Vogel case IFM_10G_SR: /* KR, too */ 1817758cc3dcSJack F Vogel case IFM_10G_LR: 18186f37f232SEric Joyner case IFM_10G_CX4: /* KX4 */ 1819758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 1820758cc3dcSJack F Vogel case IFM_10G_TWINAX: 1821758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_10GB_FULL; 1822758cc3dcSJack F Vogel break; 1823758cc3dcSJack F Vogel case IFM_1000_T: 1824758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1825758cc3dcSJack F Vogel case IFM_1000_LX: 1826758cc3dcSJack F Vogel case IFM_1000_SX: 18276f37f232SEric Joyner case IFM_1000_CX: /* KX */ 1828758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 1829758cc3dcSJack F Vogel break; 1830758cc3dcSJack F Vogel case IFM_100_TX: 1831758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1832758cc3dcSJack F Vogel break; 1833758cc3dcSJack F Vogel default: 1834758cc3dcSJack F Vogel goto invalid; 1835758cc3dcSJack F Vogel } 1836758cc3dcSJack F Vogel 1837758cc3dcSJack F Vogel hw->mac.autotry_restart = TRUE; 1838758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, speed, TRUE); 1839758cc3dcSJack F Vogel adapter->advertise = 1840758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_10GB_FULL) << 2) | 1841758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_1GB_FULL) << 1) | 1842758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_100_FULL) << 0); 1843758cc3dcSJack F Vogel 1844758cc3dcSJack F Vogel return (0); 1845758cc3dcSJack F Vogel 1846758cc3dcSJack F Vogel invalid: 18476f37f232SEric Joyner device_printf(adapter->dev, "Invalid media type!\n"); 1848758cc3dcSJack F Vogel return (EINVAL); 1849758cc3dcSJack F Vogel } 1850758cc3dcSJack F Vogel 1851758cc3dcSJack F Vogel static void 1852758cc3dcSJack F Vogel ixgbe_set_promisc(struct adapter *adapter) 1853758cc3dcSJack F Vogel { 1854758cc3dcSJack F Vogel u_int32_t reg_rctl; 1855758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1856758cc3dcSJack F Vogel int mcnt = 0; 1857758cc3dcSJack F Vogel 1858758cc3dcSJack F Vogel reg_rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); 1859758cc3dcSJack F Vogel reg_rctl &= (~IXGBE_FCTRL_UPE); 1860758cc3dcSJack F Vogel if (ifp->if_flags & IFF_ALLMULTI) 1861758cc3dcSJack F Vogel mcnt = MAX_NUM_MULTICAST_ADDRESSES; 1862758cc3dcSJack F Vogel else { 1863758cc3dcSJack F Vogel struct ifmultiaddr *ifma; 1864758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1865758cc3dcSJack F Vogel IF_ADDR_LOCK(ifp); 1866758cc3dcSJack F Vogel #else 1867758cc3dcSJack F Vogel if_maddr_rlock(ifp); 1868758cc3dcSJack F Vogel #endif 1869758cc3dcSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1870758cc3dcSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 1871758cc3dcSJack F Vogel continue; 1872758cc3dcSJack F Vogel if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) 1873758cc3dcSJack F Vogel break; 1874758cc3dcSJack F Vogel mcnt++; 1875758cc3dcSJack F Vogel } 1876758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1877758cc3dcSJack F Vogel IF_ADDR_UNLOCK(ifp); 1878758cc3dcSJack F Vogel #else 1879758cc3dcSJack F Vogel if_maddr_runlock(ifp); 1880758cc3dcSJack F Vogel #endif 1881758cc3dcSJack F Vogel } 1882758cc3dcSJack F Vogel if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) 1883758cc3dcSJack F Vogel reg_rctl &= (~IXGBE_FCTRL_MPE); 1884758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 1885758cc3dcSJack F Vogel 1886758cc3dcSJack F Vogel if (ifp->if_flags & IFF_PROMISC) { 1887758cc3dcSJack F Vogel reg_rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1888758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 1889758cc3dcSJack F Vogel } else if (ifp->if_flags & IFF_ALLMULTI) { 1890758cc3dcSJack F Vogel reg_rctl |= IXGBE_FCTRL_MPE; 1891758cc3dcSJack F Vogel reg_rctl &= ~IXGBE_FCTRL_UPE; 1892758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 1893758cc3dcSJack F Vogel } 1894758cc3dcSJack F Vogel return; 1895758cc3dcSJack F Vogel } 1896758cc3dcSJack F Vogel 1897758cc3dcSJack F Vogel 1898758cc3dcSJack F Vogel /********************************************************************* 1899758cc3dcSJack F Vogel * Multicast Update 1900758cc3dcSJack F Vogel * 1901758cc3dcSJack F Vogel * This routine is called whenever multicast address list is updated. 1902758cc3dcSJack F Vogel * 1903758cc3dcSJack F Vogel **********************************************************************/ 1904758cc3dcSJack F Vogel #define IXGBE_RAR_ENTRIES 16 1905758cc3dcSJack F Vogel 1906758cc3dcSJack F Vogel static void 1907758cc3dcSJack F Vogel ixgbe_set_multi(struct adapter *adapter) 1908758cc3dcSJack F Vogel { 1909758cc3dcSJack F Vogel u32 fctrl; 1910758cc3dcSJack F Vogel u8 *update_ptr; 1911758cc3dcSJack F Vogel struct ifmultiaddr *ifma; 1912*48056c88SJack F Vogel struct ixgbe_mc_addr *mta; 1913758cc3dcSJack F Vogel int mcnt = 0; 1914758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1915758cc3dcSJack F Vogel 1916758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); 1917758cc3dcSJack F Vogel 1918758cc3dcSJack F Vogel mta = adapter->mta; 1919*48056c88SJack F Vogel bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES); 1920758cc3dcSJack F Vogel 1921758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1922758cc3dcSJack F Vogel IF_ADDR_LOCK(ifp); 1923758cc3dcSJack F Vogel #else 1924758cc3dcSJack F Vogel if_maddr_rlock(ifp); 1925758cc3dcSJack F Vogel #endif 1926758cc3dcSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1927758cc3dcSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 1928758cc3dcSJack F Vogel continue; 1929758cc3dcSJack F Vogel if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) 1930758cc3dcSJack F Vogel break; 1931758cc3dcSJack F Vogel bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), 1932*48056c88SJack F Vogel mta[mcnt].addr, IXGBE_ETH_LENGTH_OF_ADDRESS); 1933*48056c88SJack F Vogel mta[mcnt].vmdq = adapter->pool; 1934758cc3dcSJack F Vogel mcnt++; 1935758cc3dcSJack F Vogel } 1936758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1937758cc3dcSJack F Vogel IF_ADDR_UNLOCK(ifp); 1938758cc3dcSJack F Vogel #else 1939758cc3dcSJack F Vogel if_maddr_runlock(ifp); 1940758cc3dcSJack F Vogel #endif 1941758cc3dcSJack F Vogel 1942758cc3dcSJack F Vogel fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); 1943758cc3dcSJack F Vogel fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1944758cc3dcSJack F Vogel if (ifp->if_flags & IFF_PROMISC) 1945758cc3dcSJack F Vogel fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1946758cc3dcSJack F Vogel else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES || 1947758cc3dcSJack F Vogel ifp->if_flags & IFF_ALLMULTI) { 1948758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_MPE; 1949758cc3dcSJack F Vogel fctrl &= ~IXGBE_FCTRL_UPE; 1950758cc3dcSJack F Vogel } else 1951758cc3dcSJack F Vogel fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 1952758cc3dcSJack F Vogel 1953758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); 1954758cc3dcSJack F Vogel 1955758cc3dcSJack F Vogel if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) { 1956*48056c88SJack F Vogel update_ptr = (u8 *)mta; 1957758cc3dcSJack F Vogel ixgbe_update_mc_addr_list(&adapter->hw, 1958758cc3dcSJack F Vogel update_ptr, mcnt, ixgbe_mc_array_itr, TRUE); 1959758cc3dcSJack F Vogel } 1960758cc3dcSJack F Vogel 1961758cc3dcSJack F Vogel return; 1962758cc3dcSJack F Vogel } 1963758cc3dcSJack F Vogel 1964758cc3dcSJack F Vogel /* 1965758cc3dcSJack F Vogel * This is an iterator function now needed by the multicast 1966758cc3dcSJack F Vogel * shared code. It simply feeds the shared code routine the 1967758cc3dcSJack F Vogel * addresses in the array of ixgbe_set_multi() one by one. 1968758cc3dcSJack F Vogel */ 1969758cc3dcSJack F Vogel static u8 * 1970758cc3dcSJack F Vogel ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) 1971758cc3dcSJack F Vogel { 1972*48056c88SJack F Vogel struct ixgbe_mc_addr *mta; 1973758cc3dcSJack F Vogel 1974*48056c88SJack F Vogel mta = (struct ixgbe_mc_addr *)*update_ptr; 1975*48056c88SJack F Vogel *vmdq = mta->vmdq; 1976*48056c88SJack F Vogel 1977*48056c88SJack F Vogel *update_ptr = (u8*)(mta + 1);; 1978*48056c88SJack F Vogel return (mta->addr); 1979758cc3dcSJack F Vogel } 1980758cc3dcSJack F Vogel 1981758cc3dcSJack F Vogel 1982758cc3dcSJack F Vogel /********************************************************************* 1983758cc3dcSJack F Vogel * Timer routine 1984758cc3dcSJack F Vogel * 1985758cc3dcSJack F Vogel * This routine checks for link status,updates statistics, 1986758cc3dcSJack F Vogel * and runs the watchdog check. 1987758cc3dcSJack F Vogel * 1988758cc3dcSJack F Vogel **********************************************************************/ 1989758cc3dcSJack F Vogel 1990758cc3dcSJack F Vogel static void 1991758cc3dcSJack F Vogel ixgbe_local_timer(void *arg) 1992758cc3dcSJack F Vogel { 1993758cc3dcSJack F Vogel struct adapter *adapter = arg; 1994758cc3dcSJack F Vogel device_t dev = adapter->dev; 1995758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 1996758cc3dcSJack F Vogel u64 queues = 0; 1997758cc3dcSJack F Vogel int hung = 0; 1998758cc3dcSJack F Vogel 1999758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 2000758cc3dcSJack F Vogel 2001758cc3dcSJack F Vogel /* Check for pluggable optics */ 2002758cc3dcSJack F Vogel if (adapter->sfp_probe) 2003758cc3dcSJack F Vogel if (!ixgbe_sfp_probe(adapter)) 2004758cc3dcSJack F Vogel goto out; /* Nothing to do */ 2005758cc3dcSJack F Vogel 2006758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 2007758cc3dcSJack F Vogel ixgbe_update_stats_counters(adapter); 2008758cc3dcSJack F Vogel 2009758cc3dcSJack F Vogel /* 2010758cc3dcSJack F Vogel ** Check the TX queues status 2011758cc3dcSJack F Vogel ** - mark hung queues so we don't schedule on them 2012758cc3dcSJack F Vogel ** - watchdog only if all queues show hung 2013758cc3dcSJack F Vogel */ 2014758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 2015758cc3dcSJack F Vogel /* Keep track of queues with work for soft irq */ 2016758cc3dcSJack F Vogel if (que->txr->busy) 2017758cc3dcSJack F Vogel queues |= ((u64)1 << que->me); 2018758cc3dcSJack F Vogel /* 2019758cc3dcSJack F Vogel ** Each time txeof runs without cleaning, but there 2020758cc3dcSJack F Vogel ** are uncleaned descriptors it increments busy. If 2021758cc3dcSJack F Vogel ** we get to the MAX we declare it hung. 2022758cc3dcSJack F Vogel */ 2023758cc3dcSJack F Vogel if (que->busy == IXGBE_QUEUE_HUNG) { 2024758cc3dcSJack F Vogel ++hung; 2025758cc3dcSJack F Vogel /* Mark the queue as inactive */ 2026758cc3dcSJack F Vogel adapter->active_queues &= ~((u64)1 << que->me); 2027758cc3dcSJack F Vogel continue; 2028758cc3dcSJack F Vogel } else { 2029758cc3dcSJack F Vogel /* Check if we've come back from hung */ 2030758cc3dcSJack F Vogel if ((adapter->active_queues & ((u64)1 << que->me)) == 0) 2031758cc3dcSJack F Vogel adapter->active_queues |= ((u64)1 << que->me); 2032758cc3dcSJack F Vogel } 2033758cc3dcSJack F Vogel if (que->busy >= IXGBE_MAX_TX_BUSY) { 2034758cc3dcSJack F Vogel device_printf(dev,"Warning queue %d " 2035758cc3dcSJack F Vogel "appears to be hung!\n", i); 2036758cc3dcSJack F Vogel que->txr->busy = IXGBE_QUEUE_HUNG; 2037758cc3dcSJack F Vogel ++hung; 2038758cc3dcSJack F Vogel } 2039758cc3dcSJack F Vogel 2040758cc3dcSJack F Vogel } 2041758cc3dcSJack F Vogel 2042758cc3dcSJack F Vogel /* Only truly watchdog if all queues show hung */ 2043758cc3dcSJack F Vogel if (hung == adapter->num_queues) 2044758cc3dcSJack F Vogel goto watchdog; 2045758cc3dcSJack F Vogel else if (queues != 0) { /* Force an IRQ on queues with work */ 2046758cc3dcSJack F Vogel ixgbe_rearm_queues(adapter, queues); 2047758cc3dcSJack F Vogel } 2048758cc3dcSJack F Vogel 2049758cc3dcSJack F Vogel out: 2050758cc3dcSJack F Vogel callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); 2051758cc3dcSJack F Vogel return; 2052758cc3dcSJack F Vogel 2053758cc3dcSJack F Vogel watchdog: 2054758cc3dcSJack F Vogel device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); 2055758cc3dcSJack F Vogel adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2056758cc3dcSJack F Vogel adapter->watchdog_events++; 2057758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 2058758cc3dcSJack F Vogel } 2059758cc3dcSJack F Vogel 2060*48056c88SJack F Vogel 2061758cc3dcSJack F Vogel /* 2062758cc3dcSJack F Vogel ** Note: this routine updates the OS on the link state 2063758cc3dcSJack F Vogel ** the real check of the hardware only happens with 2064758cc3dcSJack F Vogel ** a link interrupt. 2065758cc3dcSJack F Vogel */ 2066758cc3dcSJack F Vogel static void 2067758cc3dcSJack F Vogel ixgbe_update_link_status(struct adapter *adapter) 2068758cc3dcSJack F Vogel { 2069758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 2070758cc3dcSJack F Vogel device_t dev = adapter->dev; 2071758cc3dcSJack F Vogel 2072758cc3dcSJack F Vogel if (adapter->link_up){ 2073758cc3dcSJack F Vogel if (adapter->link_active == FALSE) { 2074758cc3dcSJack F Vogel if (bootverbose) 2075758cc3dcSJack F Vogel device_printf(dev,"Link is up %d Gbps %s \n", 2076758cc3dcSJack F Vogel ((adapter->link_speed == 128)? 10:1), 2077758cc3dcSJack F Vogel "Full Duplex"); 2078758cc3dcSJack F Vogel adapter->link_active = TRUE; 2079758cc3dcSJack F Vogel /* Update any Flow Control changes */ 2080758cc3dcSJack F Vogel ixgbe_fc_enable(&adapter->hw); 20816f37f232SEric Joyner /* Update DMA coalescing config */ 20826f37f232SEric Joyner ixgbe_config_dmac(adapter); 2083758cc3dcSJack F Vogel if_link_state_change(ifp, LINK_STATE_UP); 2084*48056c88SJack F Vogel #ifdef PCI_IOV 2085*48056c88SJack F Vogel ixgbe_ping_all_vfs(adapter); 2086*48056c88SJack F Vogel #endif 2087758cc3dcSJack F Vogel } 2088758cc3dcSJack F Vogel } else { /* Link down */ 2089758cc3dcSJack F Vogel if (adapter->link_active == TRUE) { 2090758cc3dcSJack F Vogel if (bootverbose) 2091758cc3dcSJack F Vogel device_printf(dev,"Link is Down\n"); 2092758cc3dcSJack F Vogel if_link_state_change(ifp, LINK_STATE_DOWN); 2093758cc3dcSJack F Vogel adapter->link_active = FALSE; 2094*48056c88SJack F Vogel #ifdef PCI_IOV 2095*48056c88SJack F Vogel ixgbe_ping_all_vfs(adapter); 2096*48056c88SJack F Vogel #endif 2097758cc3dcSJack F Vogel } 2098758cc3dcSJack F Vogel } 2099758cc3dcSJack F Vogel 2100758cc3dcSJack F Vogel return; 2101758cc3dcSJack F Vogel } 2102758cc3dcSJack F Vogel 2103758cc3dcSJack F Vogel 2104758cc3dcSJack F Vogel /********************************************************************* 2105758cc3dcSJack F Vogel * 2106758cc3dcSJack F Vogel * This routine disables all traffic on the adapter by issuing a 2107758cc3dcSJack F Vogel * global reset on the MAC and deallocates TX/RX buffers. 2108758cc3dcSJack F Vogel * 2109758cc3dcSJack F Vogel **********************************************************************/ 2110758cc3dcSJack F Vogel 2111758cc3dcSJack F Vogel static void 2112758cc3dcSJack F Vogel ixgbe_stop(void *arg) 2113758cc3dcSJack F Vogel { 2114758cc3dcSJack F Vogel struct ifnet *ifp; 2115758cc3dcSJack F Vogel struct adapter *adapter = arg; 2116758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2117758cc3dcSJack F Vogel ifp = adapter->ifp; 2118758cc3dcSJack F Vogel 2119758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 2120758cc3dcSJack F Vogel 2121758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_stop: begin\n"); 2122758cc3dcSJack F Vogel ixgbe_disable_intr(adapter); 2123758cc3dcSJack F Vogel callout_stop(&adapter->timer); 2124758cc3dcSJack F Vogel 2125758cc3dcSJack F Vogel /* Let the stack know...*/ 2126758cc3dcSJack F Vogel ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2127758cc3dcSJack F Vogel 2128758cc3dcSJack F Vogel ixgbe_reset_hw(hw); 2129758cc3dcSJack F Vogel hw->adapter_stopped = FALSE; 2130758cc3dcSJack F Vogel ixgbe_stop_adapter(hw); 2131758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82599EB) 2132758cc3dcSJack F Vogel ixgbe_stop_mac_link_on_d3_82599(hw); 2133758cc3dcSJack F Vogel /* Turn off the laser - noop with no optics */ 2134758cc3dcSJack F Vogel ixgbe_disable_tx_laser(hw); 2135758cc3dcSJack F Vogel 2136758cc3dcSJack F Vogel /* Update the stack */ 2137758cc3dcSJack F Vogel adapter->link_up = FALSE; 2138758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 2139758cc3dcSJack F Vogel 2140758cc3dcSJack F Vogel /* reprogram the RAR[0] in case user changed it. */ 2141758cc3dcSJack F Vogel ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); 2142758cc3dcSJack F Vogel 2143758cc3dcSJack F Vogel return; 2144758cc3dcSJack F Vogel } 2145758cc3dcSJack F Vogel 2146758cc3dcSJack F Vogel 2147758cc3dcSJack F Vogel /********************************************************************* 2148758cc3dcSJack F Vogel * 2149758cc3dcSJack F Vogel * Determine hardware revision. 2150758cc3dcSJack F Vogel * 2151758cc3dcSJack F Vogel **********************************************************************/ 2152758cc3dcSJack F Vogel static void 2153758cc3dcSJack F Vogel ixgbe_identify_hardware(struct adapter *adapter) 2154758cc3dcSJack F Vogel { 2155758cc3dcSJack F Vogel device_t dev = adapter->dev; 2156758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2157758cc3dcSJack F Vogel 2158758cc3dcSJack F Vogel /* Save off the information about this board */ 2159758cc3dcSJack F Vogel hw->vendor_id = pci_get_vendor(dev); 2160758cc3dcSJack F Vogel hw->device_id = pci_get_device(dev); 2161758cc3dcSJack F Vogel hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 2162758cc3dcSJack F Vogel hw->subsystem_vendor_id = 2163758cc3dcSJack F Vogel pci_read_config(dev, PCIR_SUBVEND_0, 2); 2164758cc3dcSJack F Vogel hw->subsystem_device_id = 2165758cc3dcSJack F Vogel pci_read_config(dev, PCIR_SUBDEV_0, 2); 2166758cc3dcSJack F Vogel 2167758cc3dcSJack F Vogel /* 2168758cc3dcSJack F Vogel ** Make sure BUSMASTER is set 2169758cc3dcSJack F Vogel */ 2170758cc3dcSJack F Vogel pci_enable_busmaster(dev); 2171758cc3dcSJack F Vogel 2172758cc3dcSJack F Vogel /* We need this here to set the num_segs below */ 2173758cc3dcSJack F Vogel ixgbe_set_mac_type(hw); 2174758cc3dcSJack F Vogel 21756f37f232SEric Joyner /* Pick up the 82599 settings */ 2176758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 2177758cc3dcSJack F Vogel hw->phy.smart_speed = ixgbe_smart_speed; 2178758cc3dcSJack F Vogel adapter->num_segs = IXGBE_82599_SCATTER; 2179758cc3dcSJack F Vogel } else 2180758cc3dcSJack F Vogel adapter->num_segs = IXGBE_82598_SCATTER; 2181758cc3dcSJack F Vogel 2182758cc3dcSJack F Vogel return; 2183758cc3dcSJack F Vogel } 2184758cc3dcSJack F Vogel 2185758cc3dcSJack F Vogel /********************************************************************* 2186758cc3dcSJack F Vogel * 2187758cc3dcSJack F Vogel * Determine optic type 2188758cc3dcSJack F Vogel * 2189758cc3dcSJack F Vogel **********************************************************************/ 2190758cc3dcSJack F Vogel static void 2191758cc3dcSJack F Vogel ixgbe_setup_optics(struct adapter *adapter) 2192758cc3dcSJack F Vogel { 2193758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2194758cc3dcSJack F Vogel int layer; 2195758cc3dcSJack F Vogel 2196*48056c88SJack F Vogel layer = adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); 2197758cc3dcSJack F Vogel 2198758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) { 2199758cc3dcSJack F Vogel adapter->optics = IFM_10G_T; 2200758cc3dcSJack F Vogel return; 2201758cc3dcSJack F Vogel } 2202758cc3dcSJack F Vogel 2203758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) { 2204758cc3dcSJack F Vogel adapter->optics = IFM_1000_T; 2205758cc3dcSJack F Vogel return; 2206758cc3dcSJack F Vogel } 2207758cc3dcSJack F Vogel 2208758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) { 2209758cc3dcSJack F Vogel adapter->optics = IFM_1000_SX; 2210758cc3dcSJack F Vogel return; 2211758cc3dcSJack F Vogel } 2212758cc3dcSJack F Vogel 2213758cc3dcSJack F Vogel if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_LR | 2214758cc3dcSJack F Vogel IXGBE_PHYSICAL_LAYER_10GBASE_LRM)) { 2215758cc3dcSJack F Vogel adapter->optics = IFM_10G_LR; 2216758cc3dcSJack F Vogel return; 2217758cc3dcSJack F Vogel } 2218758cc3dcSJack F Vogel 2219758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { 2220758cc3dcSJack F Vogel adapter->optics = IFM_10G_SR; 2221758cc3dcSJack F Vogel return; 2222758cc3dcSJack F Vogel } 2223758cc3dcSJack F Vogel 2224758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU) { 2225758cc3dcSJack F Vogel adapter->optics = IFM_10G_TWINAX; 2226758cc3dcSJack F Vogel return; 2227758cc3dcSJack F Vogel } 2228758cc3dcSJack F Vogel 2229758cc3dcSJack F Vogel if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | 2230758cc3dcSJack F Vogel IXGBE_PHYSICAL_LAYER_10GBASE_CX4)) { 2231758cc3dcSJack F Vogel adapter->optics = IFM_10G_CX4; 2232758cc3dcSJack F Vogel return; 2233758cc3dcSJack F Vogel } 2234758cc3dcSJack F Vogel 2235758cc3dcSJack F Vogel /* If we get here just set the default */ 2236758cc3dcSJack F Vogel adapter->optics = IFM_ETHER | IFM_AUTO; 2237758cc3dcSJack F Vogel return; 2238758cc3dcSJack F Vogel } 2239758cc3dcSJack F Vogel 2240758cc3dcSJack F Vogel /********************************************************************* 2241758cc3dcSJack F Vogel * 2242758cc3dcSJack F Vogel * Setup the Legacy or MSI Interrupt handler 2243758cc3dcSJack F Vogel * 2244758cc3dcSJack F Vogel **********************************************************************/ 2245758cc3dcSJack F Vogel static int 2246758cc3dcSJack F Vogel ixgbe_allocate_legacy(struct adapter *adapter) 2247758cc3dcSJack F Vogel { 2248758cc3dcSJack F Vogel device_t dev = adapter->dev; 2249758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2250758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2251758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2252758cc3dcSJack F Vogel #endif 2253758cc3dcSJack F Vogel int error, rid = 0; 2254758cc3dcSJack F Vogel 2255758cc3dcSJack F Vogel /* MSI RID at 1 */ 2256758cc3dcSJack F Vogel if (adapter->msix == 1) 2257758cc3dcSJack F Vogel rid = 1; 2258758cc3dcSJack F Vogel 2259758cc3dcSJack F Vogel /* We allocate a single interrupt resource */ 2260758cc3dcSJack F Vogel adapter->res = bus_alloc_resource_any(dev, 2261758cc3dcSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 2262758cc3dcSJack F Vogel if (adapter->res == NULL) { 2263758cc3dcSJack F Vogel device_printf(dev, "Unable to allocate bus resource: " 2264758cc3dcSJack F Vogel "interrupt\n"); 2265758cc3dcSJack F Vogel return (ENXIO); 2266758cc3dcSJack F Vogel } 2267758cc3dcSJack F Vogel 2268758cc3dcSJack F Vogel /* 2269758cc3dcSJack F Vogel * Try allocating a fast interrupt and the associated deferred 2270758cc3dcSJack F Vogel * processing contexts. 2271758cc3dcSJack F Vogel */ 2272758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2273758cc3dcSJack F Vogel TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); 2274758cc3dcSJack F Vogel #endif 2275758cc3dcSJack F Vogel TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); 2276758cc3dcSJack F Vogel que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, 2277758cc3dcSJack F Vogel taskqueue_thread_enqueue, &que->tq); 2278758cc3dcSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s ixq", 2279758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2280758cc3dcSJack F Vogel 2281758cc3dcSJack F Vogel /* Tasklets for Link, SFP and Multispeed Fiber */ 2282758cc3dcSJack F Vogel TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); 2283758cc3dcSJack F Vogel TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); 2284758cc3dcSJack F Vogel TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); 22856f37f232SEric Joyner TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); 2286758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 2287758cc3dcSJack F Vogel TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); 2288758cc3dcSJack F Vogel #endif 2289758cc3dcSJack F Vogel adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, 2290758cc3dcSJack F Vogel taskqueue_thread_enqueue, &adapter->tq); 2291758cc3dcSJack F Vogel taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", 2292758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2293758cc3dcSJack F Vogel 2294758cc3dcSJack F Vogel if ((error = bus_setup_intr(dev, adapter->res, 2295758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq, 2296758cc3dcSJack F Vogel que, &adapter->tag)) != 0) { 2297758cc3dcSJack F Vogel device_printf(dev, "Failed to register fast interrupt " 2298758cc3dcSJack F Vogel "handler: %d\n", error); 2299758cc3dcSJack F Vogel taskqueue_free(que->tq); 2300758cc3dcSJack F Vogel taskqueue_free(adapter->tq); 2301758cc3dcSJack F Vogel que->tq = NULL; 2302758cc3dcSJack F Vogel adapter->tq = NULL; 2303758cc3dcSJack F Vogel return (error); 2304758cc3dcSJack F Vogel } 2305758cc3dcSJack F Vogel /* For simplicity in the handlers */ 2306758cc3dcSJack F Vogel adapter->active_queues = IXGBE_EIMS_ENABLE_MASK; 2307758cc3dcSJack F Vogel 2308758cc3dcSJack F Vogel return (0); 2309758cc3dcSJack F Vogel } 2310758cc3dcSJack F Vogel 2311758cc3dcSJack F Vogel 2312758cc3dcSJack F Vogel /********************************************************************* 2313758cc3dcSJack F Vogel * 2314758cc3dcSJack F Vogel * Setup MSIX Interrupt resources and handlers 2315758cc3dcSJack F Vogel * 2316758cc3dcSJack F Vogel **********************************************************************/ 2317758cc3dcSJack F Vogel static int 2318758cc3dcSJack F Vogel ixgbe_allocate_msix(struct adapter *adapter) 2319758cc3dcSJack F Vogel { 2320758cc3dcSJack F Vogel device_t dev = adapter->dev; 2321758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2322758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2323758cc3dcSJack F Vogel int error, rid, vector = 0; 2324758cc3dcSJack F Vogel int cpu_id = 0; 2325a1edda90SAdrian Chadd #ifdef RSS 2326a1edda90SAdrian Chadd cpuset_t cpu_mask; 2327a1edda90SAdrian Chadd #endif 2328758cc3dcSJack F Vogel 2329758cc3dcSJack F Vogel #ifdef RSS 2330758cc3dcSJack F Vogel /* 2331758cc3dcSJack F Vogel * If we're doing RSS, the number of queues needs to 2332758cc3dcSJack F Vogel * match the number of RSS buckets that are configured. 2333758cc3dcSJack F Vogel * 2334758cc3dcSJack F Vogel * + If there's more queues than RSS buckets, we'll end 2335758cc3dcSJack F Vogel * up with queues that get no traffic. 2336758cc3dcSJack F Vogel * 2337758cc3dcSJack F Vogel * + If there's more RSS buckets than queues, we'll end 2338758cc3dcSJack F Vogel * up having multiple RSS buckets map to the same queue, 2339758cc3dcSJack F Vogel * so there'll be some contention. 2340758cc3dcSJack F Vogel */ 2341758cc3dcSJack F Vogel if (adapter->num_queues != rss_getnumbuckets()) { 2342758cc3dcSJack F Vogel device_printf(dev, 2343758cc3dcSJack F Vogel "%s: number of queues (%d) != number of RSS buckets (%d)" 2344758cc3dcSJack F Vogel "; performance will be impacted.\n", 2345758cc3dcSJack F Vogel __func__, 2346758cc3dcSJack F Vogel adapter->num_queues, 2347758cc3dcSJack F Vogel rss_getnumbuckets()); 2348758cc3dcSJack F Vogel } 2349758cc3dcSJack F Vogel #endif 2350758cc3dcSJack F Vogel 2351758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { 2352758cc3dcSJack F Vogel rid = vector + 1; 2353758cc3dcSJack F Vogel que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 2354758cc3dcSJack F Vogel RF_SHAREABLE | RF_ACTIVE); 2355758cc3dcSJack F Vogel if (que->res == NULL) { 2356758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate" 2357758cc3dcSJack F Vogel " bus resource: que interrupt [%d]\n", vector); 2358758cc3dcSJack F Vogel return (ENXIO); 2359758cc3dcSJack F Vogel } 2360758cc3dcSJack F Vogel /* Set the handler function */ 2361758cc3dcSJack F Vogel error = bus_setup_intr(dev, que->res, 2362758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 2363758cc3dcSJack F Vogel ixgbe_msix_que, que, &que->tag); 2364758cc3dcSJack F Vogel if (error) { 2365758cc3dcSJack F Vogel que->res = NULL; 2366758cc3dcSJack F Vogel device_printf(dev, "Failed to register QUE handler"); 2367758cc3dcSJack F Vogel return (error); 2368758cc3dcSJack F Vogel } 2369758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504 2370758cc3dcSJack F Vogel bus_describe_intr(dev, que->res, que->tag, "que %d", i); 2371758cc3dcSJack F Vogel #endif 2372758cc3dcSJack F Vogel que->msix = vector; 2373758cc3dcSJack F Vogel adapter->active_queues |= (u64)(1 << que->msix); 2374758cc3dcSJack F Vogel #ifdef RSS 2375758cc3dcSJack F Vogel /* 2376758cc3dcSJack F Vogel * The queue ID is used as the RSS layer bucket ID. 2377758cc3dcSJack F Vogel * We look up the queue ID -> RSS CPU ID and select 2378758cc3dcSJack F Vogel * that. 2379758cc3dcSJack F Vogel */ 2380758cc3dcSJack F Vogel cpu_id = rss_getcpu(i % rss_getnumbuckets()); 2381758cc3dcSJack F Vogel #else 2382758cc3dcSJack F Vogel /* 2383758cc3dcSJack F Vogel * Bind the msix vector, and thus the 2384758cc3dcSJack F Vogel * rings to the corresponding cpu. 2385758cc3dcSJack F Vogel * 2386758cc3dcSJack F Vogel * This just happens to match the default RSS round-robin 2387758cc3dcSJack F Vogel * bucket -> queue -> CPU allocation. 2388758cc3dcSJack F Vogel */ 2389758cc3dcSJack F Vogel if (adapter->num_queues > 1) 2390758cc3dcSJack F Vogel cpu_id = i; 2391758cc3dcSJack F Vogel #endif 2392758cc3dcSJack F Vogel if (adapter->num_queues > 1) 2393758cc3dcSJack F Vogel bus_bind_intr(dev, que->res, cpu_id); 2394*48056c88SJack F Vogel #ifdef IXGBE_DEBUG 2395758cc3dcSJack F Vogel #ifdef RSS 2396758cc3dcSJack F Vogel device_printf(dev, 2397758cc3dcSJack F Vogel "Bound RSS bucket %d to CPU %d\n", 2398758cc3dcSJack F Vogel i, cpu_id); 2399758cc3dcSJack F Vogel #else 2400758cc3dcSJack F Vogel device_printf(dev, 2401758cc3dcSJack F Vogel "Bound queue %d to cpu %d\n", 2402758cc3dcSJack F Vogel i, cpu_id); 2403758cc3dcSJack F Vogel #endif 2404*48056c88SJack F Vogel #endif /* IXGBE_DEBUG */ 2405*48056c88SJack F Vogel 2406*48056c88SJack F Vogel 2407758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2408758cc3dcSJack F Vogel TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); 2409758cc3dcSJack F Vogel #endif 2410758cc3dcSJack F Vogel TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); 2411758cc3dcSJack F Vogel que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, 2412758cc3dcSJack F Vogel taskqueue_thread_enqueue, &que->tq); 2413758cc3dcSJack F Vogel #ifdef RSS 2414a1edda90SAdrian Chadd CPU_SETOF(cpu_id, &cpu_mask); 2415a1edda90SAdrian Chadd taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, 2416a1edda90SAdrian Chadd &cpu_mask, 2417758cc3dcSJack F Vogel "%s (bucket %d)", 2418758cc3dcSJack F Vogel device_get_nameunit(adapter->dev), 2419758cc3dcSJack F Vogel cpu_id); 2420758cc3dcSJack F Vogel #else 2421758cc3dcSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", 2422758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2423758cc3dcSJack F Vogel #endif 2424758cc3dcSJack F Vogel } 2425758cc3dcSJack F Vogel 2426758cc3dcSJack F Vogel /* and Link */ 2427758cc3dcSJack F Vogel rid = vector + 1; 2428758cc3dcSJack F Vogel adapter->res = bus_alloc_resource_any(dev, 2429758cc3dcSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 2430758cc3dcSJack F Vogel if (!adapter->res) { 2431758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate" 2432758cc3dcSJack F Vogel " bus resource: Link interrupt [%d]\n", rid); 2433758cc3dcSJack F Vogel return (ENXIO); 2434758cc3dcSJack F Vogel } 2435758cc3dcSJack F Vogel /* Set the link handler function */ 2436758cc3dcSJack F Vogel error = bus_setup_intr(dev, adapter->res, 2437758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 2438758cc3dcSJack F Vogel ixgbe_msix_link, adapter, &adapter->tag); 2439758cc3dcSJack F Vogel if (error) { 2440758cc3dcSJack F Vogel adapter->res = NULL; 2441758cc3dcSJack F Vogel device_printf(dev, "Failed to register LINK handler"); 2442758cc3dcSJack F Vogel return (error); 2443758cc3dcSJack F Vogel } 2444758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504 2445758cc3dcSJack F Vogel bus_describe_intr(dev, adapter->res, adapter->tag, "link"); 2446758cc3dcSJack F Vogel #endif 2447758cc3dcSJack F Vogel adapter->vector = vector; 2448758cc3dcSJack F Vogel /* Tasklets for Link, SFP and Multispeed Fiber */ 2449758cc3dcSJack F Vogel TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); 2450758cc3dcSJack F Vogel TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); 2451758cc3dcSJack F Vogel TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); 2452*48056c88SJack F Vogel #ifdef PCI_IOV 2453*48056c88SJack F Vogel TASK_INIT(&adapter->mbx_task, 0, ixgbe_handle_mbx, adapter); 2454*48056c88SJack F Vogel #endif 24556f37f232SEric Joyner TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); 2456758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 2457758cc3dcSJack F Vogel TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); 2458758cc3dcSJack F Vogel #endif 2459758cc3dcSJack F Vogel adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, 2460758cc3dcSJack F Vogel taskqueue_thread_enqueue, &adapter->tq); 2461758cc3dcSJack F Vogel taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", 2462758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2463758cc3dcSJack F Vogel 2464758cc3dcSJack F Vogel return (0); 2465758cc3dcSJack F Vogel } 2466758cc3dcSJack F Vogel 2467758cc3dcSJack F Vogel /* 2468758cc3dcSJack F Vogel * Setup Either MSI/X or MSI 2469758cc3dcSJack F Vogel */ 2470758cc3dcSJack F Vogel static int 2471758cc3dcSJack F Vogel ixgbe_setup_msix(struct adapter *adapter) 2472758cc3dcSJack F Vogel { 2473758cc3dcSJack F Vogel device_t dev = adapter->dev; 2474758cc3dcSJack F Vogel int rid, want, queues, msgs; 2475758cc3dcSJack F Vogel 2476758cc3dcSJack F Vogel /* Override by tuneable */ 2477758cc3dcSJack F Vogel if (ixgbe_enable_msix == 0) 2478758cc3dcSJack F Vogel goto msi; 2479758cc3dcSJack F Vogel 2480758cc3dcSJack F Vogel /* First try MSI/X */ 2481758cc3dcSJack F Vogel msgs = pci_msix_count(dev); 2482758cc3dcSJack F Vogel if (msgs == 0) 2483758cc3dcSJack F Vogel goto msi; 2484758cc3dcSJack F Vogel rid = PCIR_BAR(MSIX_82598_BAR); 2485758cc3dcSJack F Vogel adapter->msix_mem = bus_alloc_resource_any(dev, 2486758cc3dcSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 2487758cc3dcSJack F Vogel if (adapter->msix_mem == NULL) { 2488758cc3dcSJack F Vogel rid += 4; /* 82599 maps in higher BAR */ 2489758cc3dcSJack F Vogel adapter->msix_mem = bus_alloc_resource_any(dev, 2490758cc3dcSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 2491758cc3dcSJack F Vogel } 2492758cc3dcSJack F Vogel if (adapter->msix_mem == NULL) { 2493758cc3dcSJack F Vogel /* May not be enabled */ 2494758cc3dcSJack F Vogel device_printf(adapter->dev, 2495758cc3dcSJack F Vogel "Unable to map MSIX table \n"); 2496758cc3dcSJack F Vogel goto msi; 2497758cc3dcSJack F Vogel } 2498758cc3dcSJack F Vogel 2499758cc3dcSJack F Vogel /* Figure out a reasonable auto config value */ 2500758cc3dcSJack F Vogel queues = (mp_ncpus > (msgs-1)) ? (msgs-1) : mp_ncpus; 2501758cc3dcSJack F Vogel 2502758cc3dcSJack F Vogel #ifdef RSS 2503758cc3dcSJack F Vogel /* If we're doing RSS, clamp at the number of RSS buckets */ 2504758cc3dcSJack F Vogel if (queues > rss_getnumbuckets()) 2505758cc3dcSJack F Vogel queues = rss_getnumbuckets(); 2506758cc3dcSJack F Vogel #endif 2507758cc3dcSJack F Vogel 2508758cc3dcSJack F Vogel if (ixgbe_num_queues != 0) 2509758cc3dcSJack F Vogel queues = ixgbe_num_queues; 2510758cc3dcSJack F Vogel 2511758cc3dcSJack F Vogel /* reflect correct sysctl value */ 2512758cc3dcSJack F Vogel ixgbe_num_queues = queues; 2513758cc3dcSJack F Vogel 2514758cc3dcSJack F Vogel /* 2515758cc3dcSJack F Vogel ** Want one vector (RX/TX pair) per queue 2516758cc3dcSJack F Vogel ** plus an additional for Link. 2517758cc3dcSJack F Vogel */ 2518758cc3dcSJack F Vogel want = queues + 1; 2519758cc3dcSJack F Vogel if (msgs >= want) 2520758cc3dcSJack F Vogel msgs = want; 2521758cc3dcSJack F Vogel else { 2522758cc3dcSJack F Vogel device_printf(adapter->dev, 2523758cc3dcSJack F Vogel "MSIX Configuration Problem, " 2524758cc3dcSJack F Vogel "%d vectors but %d queues wanted!\n", 2525758cc3dcSJack F Vogel msgs, want); 2526758cc3dcSJack F Vogel goto msi; 2527758cc3dcSJack F Vogel } 2528758cc3dcSJack F Vogel if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { 2529758cc3dcSJack F Vogel device_printf(adapter->dev, 2530758cc3dcSJack F Vogel "Using MSIX interrupts with %d vectors\n", msgs); 2531758cc3dcSJack F Vogel adapter->num_queues = queues; 2532758cc3dcSJack F Vogel return (msgs); 2533758cc3dcSJack F Vogel } 2534758cc3dcSJack F Vogel /* 2535758cc3dcSJack F Vogel ** If MSIX alloc failed or provided us with 2536758cc3dcSJack F Vogel ** less than needed, free and fall through to MSI 2537758cc3dcSJack F Vogel */ 2538758cc3dcSJack F Vogel pci_release_msi(dev); 2539758cc3dcSJack F Vogel 2540758cc3dcSJack F Vogel msi: 2541758cc3dcSJack F Vogel if (adapter->msix_mem != NULL) { 2542758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2543758cc3dcSJack F Vogel rid, adapter->msix_mem); 2544758cc3dcSJack F Vogel adapter->msix_mem = NULL; 2545758cc3dcSJack F Vogel } 2546758cc3dcSJack F Vogel msgs = 1; 2547758cc3dcSJack F Vogel if (pci_alloc_msi(dev, &msgs) == 0) { 2548758cc3dcSJack F Vogel device_printf(adapter->dev,"Using an MSI interrupt\n"); 2549758cc3dcSJack F Vogel return (msgs); 2550758cc3dcSJack F Vogel } 2551758cc3dcSJack F Vogel device_printf(adapter->dev,"Using a Legacy interrupt\n"); 2552758cc3dcSJack F Vogel return (0); 2553758cc3dcSJack F Vogel } 2554758cc3dcSJack F Vogel 2555758cc3dcSJack F Vogel 2556758cc3dcSJack F Vogel static int 2557758cc3dcSJack F Vogel ixgbe_allocate_pci_resources(struct adapter *adapter) 2558758cc3dcSJack F Vogel { 2559758cc3dcSJack F Vogel int rid; 2560758cc3dcSJack F Vogel device_t dev = adapter->dev; 2561758cc3dcSJack F Vogel 2562758cc3dcSJack F Vogel rid = PCIR_BAR(0); 2563758cc3dcSJack F Vogel adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2564758cc3dcSJack F Vogel &rid, RF_ACTIVE); 2565758cc3dcSJack F Vogel 2566758cc3dcSJack F Vogel if (!(adapter->pci_mem)) { 2567758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate bus resource: memory\n"); 2568758cc3dcSJack F Vogel return (ENXIO); 2569758cc3dcSJack F Vogel } 2570758cc3dcSJack F Vogel 2571758cc3dcSJack F Vogel adapter->osdep.mem_bus_space_tag = 2572758cc3dcSJack F Vogel rman_get_bustag(adapter->pci_mem); 2573758cc3dcSJack F Vogel adapter->osdep.mem_bus_space_handle = 2574758cc3dcSJack F Vogel rman_get_bushandle(adapter->pci_mem); 2575758cc3dcSJack F Vogel adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle; 2576758cc3dcSJack F Vogel 2577758cc3dcSJack F Vogel /* Legacy defaults */ 2578758cc3dcSJack F Vogel adapter->num_queues = 1; 2579758cc3dcSJack F Vogel adapter->hw.back = &adapter->osdep; 2580758cc3dcSJack F Vogel 2581758cc3dcSJack F Vogel /* 2582758cc3dcSJack F Vogel ** Now setup MSI or MSI/X, should 2583758cc3dcSJack F Vogel ** return us the number of supported 2584758cc3dcSJack F Vogel ** vectors. (Will be 1 for MSI) 2585758cc3dcSJack F Vogel */ 2586758cc3dcSJack F Vogel adapter->msix = ixgbe_setup_msix(adapter); 2587758cc3dcSJack F Vogel return (0); 2588758cc3dcSJack F Vogel } 2589758cc3dcSJack F Vogel 2590758cc3dcSJack F Vogel static void 2591758cc3dcSJack F Vogel ixgbe_free_pci_resources(struct adapter * adapter) 2592758cc3dcSJack F Vogel { 2593758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2594758cc3dcSJack F Vogel device_t dev = adapter->dev; 2595758cc3dcSJack F Vogel int rid, memrid; 2596758cc3dcSJack F Vogel 2597758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) 2598758cc3dcSJack F Vogel memrid = PCIR_BAR(MSIX_82598_BAR); 2599758cc3dcSJack F Vogel else 2600758cc3dcSJack F Vogel memrid = PCIR_BAR(MSIX_82599_BAR); 2601758cc3dcSJack F Vogel 2602758cc3dcSJack F Vogel /* 2603758cc3dcSJack F Vogel ** There is a slight possibility of a failure mode 2604758cc3dcSJack F Vogel ** in attach that will result in entering this function 2605758cc3dcSJack F Vogel ** before interrupt resources have been initialized, and 2606758cc3dcSJack F Vogel ** in that case we do not want to execute the loops below 2607758cc3dcSJack F Vogel ** We can detect this reliably by the state of the adapter 2608758cc3dcSJack F Vogel ** res pointer. 2609758cc3dcSJack F Vogel */ 2610758cc3dcSJack F Vogel if (adapter->res == NULL) 2611758cc3dcSJack F Vogel goto mem; 2612758cc3dcSJack F Vogel 2613758cc3dcSJack F Vogel /* 2614758cc3dcSJack F Vogel ** Release all msix queue resources: 2615758cc3dcSJack F Vogel */ 2616758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 2617758cc3dcSJack F Vogel rid = que->msix + 1; 2618758cc3dcSJack F Vogel if (que->tag != NULL) { 2619758cc3dcSJack F Vogel bus_teardown_intr(dev, que->res, que->tag); 2620758cc3dcSJack F Vogel que->tag = NULL; 2621758cc3dcSJack F Vogel } 2622758cc3dcSJack F Vogel if (que->res != NULL) 2623758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2624758cc3dcSJack F Vogel } 2625758cc3dcSJack F Vogel 2626758cc3dcSJack F Vogel 2627758cc3dcSJack F Vogel /* Clean the Legacy or Link interrupt last */ 2628758cc3dcSJack F Vogel if (adapter->vector) /* we are doing MSIX */ 2629758cc3dcSJack F Vogel rid = adapter->vector + 1; 2630758cc3dcSJack F Vogel else 2631758cc3dcSJack F Vogel (adapter->msix != 0) ? (rid = 1):(rid = 0); 2632758cc3dcSJack F Vogel 2633758cc3dcSJack F Vogel if (adapter->tag != NULL) { 2634758cc3dcSJack F Vogel bus_teardown_intr(dev, adapter->res, adapter->tag); 2635758cc3dcSJack F Vogel adapter->tag = NULL; 2636758cc3dcSJack F Vogel } 2637758cc3dcSJack F Vogel if (adapter->res != NULL) 2638758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); 2639758cc3dcSJack F Vogel 2640758cc3dcSJack F Vogel mem: 2641758cc3dcSJack F Vogel if (adapter->msix) 2642758cc3dcSJack F Vogel pci_release_msi(dev); 2643758cc3dcSJack F Vogel 2644758cc3dcSJack F Vogel if (adapter->msix_mem != NULL) 2645758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2646758cc3dcSJack F Vogel memrid, adapter->msix_mem); 2647758cc3dcSJack F Vogel 2648758cc3dcSJack F Vogel if (adapter->pci_mem != NULL) 2649758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2650758cc3dcSJack F Vogel PCIR_BAR(0), adapter->pci_mem); 2651758cc3dcSJack F Vogel 2652758cc3dcSJack F Vogel return; 2653758cc3dcSJack F Vogel } 2654758cc3dcSJack F Vogel 2655758cc3dcSJack F Vogel /********************************************************************* 2656758cc3dcSJack F Vogel * 2657758cc3dcSJack F Vogel * Setup networking device structure and register an interface. 2658758cc3dcSJack F Vogel * 2659758cc3dcSJack F Vogel **********************************************************************/ 2660758cc3dcSJack F Vogel static int 2661758cc3dcSJack F Vogel ixgbe_setup_interface(device_t dev, struct adapter *adapter) 2662758cc3dcSJack F Vogel { 2663758cc3dcSJack F Vogel struct ifnet *ifp; 2664758cc3dcSJack F Vogel 2665758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_setup_interface: begin"); 2666758cc3dcSJack F Vogel 2667758cc3dcSJack F Vogel ifp = adapter->ifp = if_alloc(IFT_ETHER); 2668758cc3dcSJack F Vogel if (ifp == NULL) { 2669758cc3dcSJack F Vogel device_printf(dev, "can not allocate ifnet structure\n"); 2670758cc3dcSJack F Vogel return (-1); 2671758cc3dcSJack F Vogel } 2672758cc3dcSJack F Vogel if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2673758cc3dcSJack F Vogel ifp->if_baudrate = IF_Gbps(10); 2674758cc3dcSJack F Vogel ifp->if_init = ixgbe_init; 2675758cc3dcSJack F Vogel ifp->if_softc = adapter; 2676758cc3dcSJack F Vogel ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2677758cc3dcSJack F Vogel ifp->if_ioctl = ixgbe_ioctl; 2678758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 2679758cc3dcSJack F Vogel if_setgetcounterfn(ifp, ixgbe_get_counter); 2680758cc3dcSJack F Vogel #endif 26816f37f232SEric Joyner #if __FreeBSD_version >= 1100045 26826f37f232SEric Joyner /* TSO parameters */ 26836f37f232SEric Joyner ifp->if_hw_tsomax = 65518; 26846f37f232SEric Joyner ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER; 26856f37f232SEric Joyner ifp->if_hw_tsomaxsegsize = 2048; 26866f37f232SEric Joyner #endif 2687758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2688758cc3dcSJack F Vogel ifp->if_transmit = ixgbe_mq_start; 2689758cc3dcSJack F Vogel ifp->if_qflush = ixgbe_qflush; 2690758cc3dcSJack F Vogel #else 2691758cc3dcSJack F Vogel ifp->if_start = ixgbe_start; 2692758cc3dcSJack F Vogel IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); 2693758cc3dcSJack F Vogel ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; 2694758cc3dcSJack F Vogel IFQ_SET_READY(&ifp->if_snd); 2695758cc3dcSJack F Vogel #endif 2696758cc3dcSJack F Vogel 2697758cc3dcSJack F Vogel ether_ifattach(ifp, adapter->hw.mac.addr); 2698758cc3dcSJack F Vogel 2699758cc3dcSJack F Vogel adapter->max_frame_size = 2700758cc3dcSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 2701758cc3dcSJack F Vogel 2702758cc3dcSJack F Vogel /* 2703758cc3dcSJack F Vogel * Tell the upper layer(s) we support long frames. 2704758cc3dcSJack F Vogel */ 2705758cc3dcSJack F Vogel ifp->if_hdrlen = sizeof(struct ether_vlan_header); 2706758cc3dcSJack F Vogel 2707758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO | IFCAP_VLAN_HWCSUM; 2708758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_JUMBO_MTU; 2709758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_LRO; 2710758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING 2711758cc3dcSJack F Vogel | IFCAP_VLAN_HWTSO 2712758cc3dcSJack F Vogel | IFCAP_VLAN_MTU 2713758cc3dcSJack F Vogel | IFCAP_HWSTATS; 2714758cc3dcSJack F Vogel ifp->if_capenable = ifp->if_capabilities; 2715758cc3dcSJack F Vogel 2716758cc3dcSJack F Vogel /* 2717758cc3dcSJack F Vogel ** Don't turn this on by default, if vlans are 2718758cc3dcSJack F Vogel ** created on another pseudo device (eg. lagg) 2719758cc3dcSJack F Vogel ** then vlan events are not passed thru, breaking 2720758cc3dcSJack F Vogel ** operation, but with HW FILTER off it works. If 2721758cc3dcSJack F Vogel ** using vlans directly on the ixgbe driver you can 2722758cc3dcSJack F Vogel ** enable this and get full hardware tag filtering. 2723758cc3dcSJack F Vogel */ 2724758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 2725758cc3dcSJack F Vogel 2726758cc3dcSJack F Vogel /* 2727758cc3dcSJack F Vogel * Specify the media types supported by this adapter and register 2728758cc3dcSJack F Vogel * callbacks to update media and link information 2729758cc3dcSJack F Vogel */ 2730758cc3dcSJack F Vogel ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change, 2731758cc3dcSJack F Vogel ixgbe_media_status); 2732758cc3dcSJack F Vogel 2733758cc3dcSJack F Vogel ixgbe_add_media_types(adapter); 2734758cc3dcSJack F Vogel 2735758cc3dcSJack F Vogel /* Autoselect media by default */ 2736758cc3dcSJack F Vogel ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); 2737758cc3dcSJack F Vogel 2738758cc3dcSJack F Vogel return (0); 2739758cc3dcSJack F Vogel } 2740758cc3dcSJack F Vogel 2741758cc3dcSJack F Vogel static void 2742758cc3dcSJack F Vogel ixgbe_add_media_types(struct adapter *adapter) 2743758cc3dcSJack F Vogel { 2744758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2745758cc3dcSJack F Vogel device_t dev = adapter->dev; 2746758cc3dcSJack F Vogel int layer; 2747758cc3dcSJack F Vogel 2748*48056c88SJack F Vogel layer = adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); 2749758cc3dcSJack F Vogel 2750758cc3dcSJack F Vogel /* Media types with matching FreeBSD media defines */ 2751758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) 2752758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2753758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) 2754758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); 2755758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) 2756758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2757758cc3dcSJack F Vogel 2758758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || 2759758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) 2760758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2761758cc3dcSJack F Vogel 2762758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) 2763758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2764758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) 2765758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2766758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) 2767758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2768758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) 2769758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 2770758cc3dcSJack F Vogel 2771758cc3dcSJack F Vogel /* 2772758cc3dcSJack F Vogel ** Other (no matching FreeBSD media type): 2773758cc3dcSJack F Vogel ** To workaround this, we'll assign these completely 2774758cc3dcSJack F Vogel ** inappropriate media types. 2775758cc3dcSJack F Vogel */ 2776758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) { 2777758cc3dcSJack F Vogel device_printf(dev, "Media supported: 10GbaseKR\n"); 27786f37f232SEric Joyner device_printf(dev, "10GbaseKR mapped to 10GbaseSR\n"); 27796f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2780758cc3dcSJack F Vogel } 2781758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) { 2782758cc3dcSJack F Vogel device_printf(dev, "Media supported: 10GbaseKX4\n"); 27836f37f232SEric Joyner device_printf(dev, "10GbaseKX4 mapped to 10GbaseCX4\n"); 27846f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2785758cc3dcSJack F Vogel } 2786758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) { 2787758cc3dcSJack F Vogel device_printf(dev, "Media supported: 1000baseKX\n"); 27886f37f232SEric Joyner device_printf(dev, "1000baseKX mapped to 1000baseCX\n"); 27896f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_CX, 0, NULL); 2790758cc3dcSJack F Vogel } 2791758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX) { 2792758cc3dcSJack F Vogel /* Someday, someone will care about you... */ 2793758cc3dcSJack F Vogel device_printf(dev, "Media supported: 1000baseBX\n"); 2794758cc3dcSJack F Vogel } 2795758cc3dcSJack F Vogel 2796758cc3dcSJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) { 2797758cc3dcSJack F Vogel ifmedia_add(&adapter->media, 2798758cc3dcSJack F Vogel IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 2799758cc3dcSJack F Vogel ifmedia_add(&adapter->media, 2800758cc3dcSJack F Vogel IFM_ETHER | IFM_1000_T, 0, NULL); 2801758cc3dcSJack F Vogel } 2802758cc3dcSJack F Vogel 2803758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2804758cc3dcSJack F Vogel } 2805758cc3dcSJack F Vogel 2806758cc3dcSJack F Vogel static void 2807758cc3dcSJack F Vogel ixgbe_config_link(struct adapter *adapter) 2808758cc3dcSJack F Vogel { 2809758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2810758cc3dcSJack F Vogel u32 autoneg, err = 0; 2811758cc3dcSJack F Vogel bool sfp, negotiate; 2812758cc3dcSJack F Vogel 2813758cc3dcSJack F Vogel sfp = ixgbe_is_sfp(hw); 2814758cc3dcSJack F Vogel 2815758cc3dcSJack F Vogel if (sfp) { 2816758cc3dcSJack F Vogel if (hw->phy.multispeed_fiber) { 2817758cc3dcSJack F Vogel hw->mac.ops.setup_sfp(hw); 2818758cc3dcSJack F Vogel ixgbe_enable_tx_laser(hw); 2819758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 2820758cc3dcSJack F Vogel } else 2821758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mod_task); 2822758cc3dcSJack F Vogel } else { 2823758cc3dcSJack F Vogel if (hw->mac.ops.check_link) 2824758cc3dcSJack F Vogel err = ixgbe_check_link(hw, &adapter->link_speed, 2825758cc3dcSJack F Vogel &adapter->link_up, FALSE); 2826758cc3dcSJack F Vogel if (err) 2827758cc3dcSJack F Vogel goto out; 2828758cc3dcSJack F Vogel autoneg = hw->phy.autoneg_advertised; 2829758cc3dcSJack F Vogel if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) 2830758cc3dcSJack F Vogel err = hw->mac.ops.get_link_capabilities(hw, 2831758cc3dcSJack F Vogel &autoneg, &negotiate); 2832758cc3dcSJack F Vogel if (err) 2833758cc3dcSJack F Vogel goto out; 2834758cc3dcSJack F Vogel if (hw->mac.ops.setup_link) 2835758cc3dcSJack F Vogel err = hw->mac.ops.setup_link(hw, 2836758cc3dcSJack F Vogel autoneg, adapter->link_up); 2837758cc3dcSJack F Vogel } 2838758cc3dcSJack F Vogel out: 2839758cc3dcSJack F Vogel return; 2840758cc3dcSJack F Vogel } 2841758cc3dcSJack F Vogel 2842758cc3dcSJack F Vogel 2843758cc3dcSJack F Vogel /********************************************************************* 2844758cc3dcSJack F Vogel * 2845758cc3dcSJack F Vogel * Enable transmit units. 2846758cc3dcSJack F Vogel * 2847758cc3dcSJack F Vogel **********************************************************************/ 2848758cc3dcSJack F Vogel static void 2849758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(struct adapter *adapter) 2850758cc3dcSJack F Vogel { 2851758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2852758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2853758cc3dcSJack F Vogel 2854758cc3dcSJack F Vogel /* Setup the Base and Length of the Tx Descriptor Ring */ 2855758cc3dcSJack F Vogel 2856758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, txr++) { 2857758cc3dcSJack F Vogel u64 tdba = txr->txdma.dma_paddr; 2858758cc3dcSJack F Vogel u32 txctrl = 0; 2859*48056c88SJack F Vogel int j = txr->me; 2860758cc3dcSJack F Vogel 2861*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), 2862758cc3dcSJack F Vogel (tdba & 0x00000000ffffffffULL)); 2863*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); 2864*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), 2865758cc3dcSJack F Vogel adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc)); 2866758cc3dcSJack F Vogel 2867758cc3dcSJack F Vogel /* Setup the HW Tx Head and Tail descriptor pointers */ 2868*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); 2869*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); 2870758cc3dcSJack F Vogel 2871758cc3dcSJack F Vogel /* Cache the tail address */ 2872*48056c88SJack F Vogel txr->tail = IXGBE_TDT(j); 2873758cc3dcSJack F Vogel 2874758cc3dcSJack F Vogel /* Set the processing limit */ 2875758cc3dcSJack F Vogel txr->process_limit = ixgbe_tx_process_limit; 2876758cc3dcSJack F Vogel 2877758cc3dcSJack F Vogel /* Disable Head Writeback */ 2878758cc3dcSJack F Vogel switch (hw->mac.type) { 2879758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 2880*48056c88SJack F Vogel txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); 2881758cc3dcSJack F Vogel break; 2882758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 2883758cc3dcSJack F Vogel case ixgbe_mac_X540: 2884758cc3dcSJack F Vogel default: 2885*48056c88SJack F Vogel txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j)); 2886758cc3dcSJack F Vogel break; 2887758cc3dcSJack F Vogel } 2888758cc3dcSJack F Vogel txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; 2889758cc3dcSJack F Vogel switch (hw->mac.type) { 2890758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 2891*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); 2892758cc3dcSJack F Vogel break; 2893758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 2894758cc3dcSJack F Vogel case ixgbe_mac_X540: 2895758cc3dcSJack F Vogel default: 2896*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl); 2897758cc3dcSJack F Vogel break; 2898758cc3dcSJack F Vogel } 2899758cc3dcSJack F Vogel 2900758cc3dcSJack F Vogel } 2901758cc3dcSJack F Vogel 2902758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 2903758cc3dcSJack F Vogel u32 dmatxctl, rttdcs; 2904*48056c88SJack F Vogel #ifdef PCI_IOV 2905*48056c88SJack F Vogel enum ixgbe_iov_mode mode = ixgbe_get_iov_mode(adapter); 2906*48056c88SJack F Vogel #endif 2907758cc3dcSJack F Vogel dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); 2908758cc3dcSJack F Vogel dmatxctl |= IXGBE_DMATXCTL_TE; 2909758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); 2910758cc3dcSJack F Vogel /* Disable arbiter to set MTQC */ 2911758cc3dcSJack F Vogel rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); 2912758cc3dcSJack F Vogel rttdcs |= IXGBE_RTTDCS_ARBDIS; 2913758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); 2914*48056c88SJack F Vogel #ifdef PCI_IOV 2915*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MTQC, ixgbe_get_mtqc(mode)); 2916*48056c88SJack F Vogel #else 2917758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); 2918*48056c88SJack F Vogel #endif 2919758cc3dcSJack F Vogel rttdcs &= ~IXGBE_RTTDCS_ARBDIS; 2920758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); 2921758cc3dcSJack F Vogel } 2922758cc3dcSJack F Vogel 2923758cc3dcSJack F Vogel return; 2924758cc3dcSJack F Vogel } 2925758cc3dcSJack F Vogel 2926758cc3dcSJack F Vogel static void 2927758cc3dcSJack F Vogel ixgbe_initialise_rss_mapping(struct adapter *adapter) 2928758cc3dcSJack F Vogel { 2929758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2930*48056c88SJack F Vogel u32 reta = 0, mrqc, rss_key[10]; 2931*48056c88SJack F Vogel int queue_id, table_size, index_mult; 2932758cc3dcSJack F Vogel #ifdef RSS 2933*48056c88SJack F Vogel u32 rss_hash_config; 2934758cc3dcSJack F Vogel #endif 2935*48056c88SJack F Vogel #ifdef PCI_IOV 2936*48056c88SJack F Vogel enum ixgbe_iov_mode mode; 2937*48056c88SJack F Vogel #endif 2938758cc3dcSJack F Vogel 2939758cc3dcSJack F Vogel #ifdef RSS 2940758cc3dcSJack F Vogel /* Fetch the configured RSS key */ 2941758cc3dcSJack F Vogel rss_getkey((uint8_t *) &rss_key); 2942758cc3dcSJack F Vogel #else 2943758cc3dcSJack F Vogel /* set up random bits */ 2944758cc3dcSJack F Vogel arc4rand(&rss_key, sizeof(rss_key), 0); 2945758cc3dcSJack F Vogel #endif 2946758cc3dcSJack F Vogel 29476f37f232SEric Joyner /* Set multiplier for RETA setup and table size based on MAC */ 29486f37f232SEric Joyner index_mult = 0x1; 29496f37f232SEric Joyner table_size = 128; 29506f37f232SEric Joyner switch (adapter->hw.mac.type) { 29516f37f232SEric Joyner case ixgbe_mac_82598EB: 29526f37f232SEric Joyner index_mult = 0x11; 29536f37f232SEric Joyner break; 29546f37f232SEric Joyner case ixgbe_mac_X550: 29556f37f232SEric Joyner case ixgbe_mac_X550EM_x: 29566f37f232SEric Joyner table_size = 512; 29576f37f232SEric Joyner break; 29586f37f232SEric Joyner default: 29596f37f232SEric Joyner break; 29606f37f232SEric Joyner } 29616f37f232SEric Joyner 2962758cc3dcSJack F Vogel /* Set up the redirection table */ 2963*48056c88SJack F Vogel for (int i = 0, j = 0; i < table_size; i++, j++) { 2964758cc3dcSJack F Vogel if (j == adapter->num_queues) j = 0; 2965758cc3dcSJack F Vogel #ifdef RSS 2966758cc3dcSJack F Vogel /* 2967758cc3dcSJack F Vogel * Fetch the RSS bucket id for the given indirection entry. 2968758cc3dcSJack F Vogel * Cap it at the number of configured buckets (which is 2969758cc3dcSJack F Vogel * num_queues.) 2970758cc3dcSJack F Vogel */ 2971758cc3dcSJack F Vogel queue_id = rss_get_indirection_to_bucket(i); 2972758cc3dcSJack F Vogel queue_id = queue_id % adapter->num_queues; 2973758cc3dcSJack F Vogel #else 29746f37f232SEric Joyner queue_id = (j * index_mult); 2975758cc3dcSJack F Vogel #endif 2976758cc3dcSJack F Vogel /* 2977758cc3dcSJack F Vogel * The low 8 bits are for hash value (n+0); 2978758cc3dcSJack F Vogel * The next 8 bits are for hash value (n+1), etc. 2979758cc3dcSJack F Vogel */ 2980758cc3dcSJack F Vogel reta = reta >> 8; 2981758cc3dcSJack F Vogel reta = reta | ( ((uint32_t) queue_id) << 24); 2982758cc3dcSJack F Vogel if ((i & 3) == 3) { 29836f37f232SEric Joyner if (i < 128) 2984758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); 29856f37f232SEric Joyner else 29866f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), reta); 2987758cc3dcSJack F Vogel reta = 0; 2988758cc3dcSJack F Vogel } 2989758cc3dcSJack F Vogel } 2990758cc3dcSJack F Vogel 2991758cc3dcSJack F Vogel /* Now fill our hash function seeds */ 2992758cc3dcSJack F Vogel for (int i = 0; i < 10; i++) 2993758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); 2994758cc3dcSJack F Vogel 2995758cc3dcSJack F Vogel /* Perform hash on these packet types */ 2996758cc3dcSJack F Vogel #ifdef RSS 2997758cc3dcSJack F Vogel mrqc = IXGBE_MRQC_RSSEN; 2998758cc3dcSJack F Vogel rss_hash_config = rss_gethashconfig(); 2999758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 3000758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; 3001758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 3002758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; 3003758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 3004758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; 3005758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 3006758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; 3007758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 3008758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX; 3009758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) 3010758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP; 3011758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 3012758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; 3013758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) 3014758cc3dcSJack F Vogel device_printf(adapter->dev, 3015758cc3dcSJack F Vogel "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, " 3016758cc3dcSJack F Vogel "but not supported\n", __func__); 3017758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 3018758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; 3019758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) 3020758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 3021758cc3dcSJack F Vogel #else 3022758cc3dcSJack F Vogel /* 3023758cc3dcSJack F Vogel * Disable UDP - IP fragments aren't currently being handled 3024758cc3dcSJack F Vogel * and so we end up with a mix of 2-tuple and 4-tuple 3025758cc3dcSJack F Vogel * traffic. 3026758cc3dcSJack F Vogel */ 3027758cc3dcSJack F Vogel mrqc = IXGBE_MRQC_RSSEN 3028758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4 3029758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4_TCP 3030758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP 3031758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX 3032758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6 3033758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_TCP 3034758cc3dcSJack F Vogel ; 3035758cc3dcSJack F Vogel #endif /* RSS */ 3036*48056c88SJack F Vogel #ifdef PCI_IOV 3037*48056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 3038*48056c88SJack F Vogel mrqc |= ixgbe_get_mrqc(mode); 3039*48056c88SJack F Vogel #endif 3040758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 3041758cc3dcSJack F Vogel } 3042758cc3dcSJack F Vogel 3043758cc3dcSJack F Vogel 3044758cc3dcSJack F Vogel /********************************************************************* 3045758cc3dcSJack F Vogel * 3046758cc3dcSJack F Vogel * Setup receive registers and features. 3047758cc3dcSJack F Vogel * 3048758cc3dcSJack F Vogel **********************************************************************/ 3049758cc3dcSJack F Vogel #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 3050758cc3dcSJack F Vogel 3051758cc3dcSJack F Vogel #define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1) 3052758cc3dcSJack F Vogel 3053758cc3dcSJack F Vogel static void 3054758cc3dcSJack F Vogel ixgbe_initialize_receive_units(struct adapter *adapter) 3055758cc3dcSJack F Vogel { 3056758cc3dcSJack F Vogel struct rx_ring *rxr = adapter->rx_rings; 3057758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3058758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3059758cc3dcSJack F Vogel u32 bufsz, fctrl, srrctl, rxcsum; 3060758cc3dcSJack F Vogel u32 hlreg; 3061758cc3dcSJack F Vogel 3062758cc3dcSJack F Vogel 3063758cc3dcSJack F Vogel /* 3064758cc3dcSJack F Vogel * Make sure receives are disabled while 3065758cc3dcSJack F Vogel * setting up the descriptor ring 3066758cc3dcSJack F Vogel */ 3067758cc3dcSJack F Vogel ixgbe_disable_rx(hw); 3068758cc3dcSJack F Vogel 3069758cc3dcSJack F Vogel /* Enable broadcasts */ 3070758cc3dcSJack F Vogel fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); 3071758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_BAM; 30726f37f232SEric Joyner if (adapter->hw.mac.type == ixgbe_mac_82598EB) { 3073758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_DPF; 3074758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_PMCF; 30756f37f232SEric Joyner } 3076758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); 3077758cc3dcSJack F Vogel 3078758cc3dcSJack F Vogel /* Set for Jumbo Frames? */ 3079758cc3dcSJack F Vogel hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); 3080758cc3dcSJack F Vogel if (ifp->if_mtu > ETHERMTU) 3081758cc3dcSJack F Vogel hlreg |= IXGBE_HLREG0_JUMBOEN; 3082758cc3dcSJack F Vogel else 3083758cc3dcSJack F Vogel hlreg &= ~IXGBE_HLREG0_JUMBOEN; 3084758cc3dcSJack F Vogel #ifdef DEV_NETMAP 3085758cc3dcSJack F Vogel /* crcstrip is conditional in netmap (in RDRXCTL too ?) */ 3086758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip) 3087758cc3dcSJack F Vogel hlreg &= ~IXGBE_HLREG0_RXCRCSTRP; 3088758cc3dcSJack F Vogel else 3089758cc3dcSJack F Vogel hlreg |= IXGBE_HLREG0_RXCRCSTRP; 3090758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 3091758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); 3092758cc3dcSJack F Vogel 3093758cc3dcSJack F Vogel bufsz = (adapter->rx_mbuf_sz + 3094758cc3dcSJack F Vogel BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; 3095758cc3dcSJack F Vogel 3096758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, rxr++) { 3097758cc3dcSJack F Vogel u64 rdba = rxr->rxdma.dma_paddr; 3098*48056c88SJack F Vogel int j = rxr->me; 3099758cc3dcSJack F Vogel 3100758cc3dcSJack F Vogel /* Setup the Base and Length of the Rx Descriptor Ring */ 3101*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), 3102758cc3dcSJack F Vogel (rdba & 0x00000000ffffffffULL)); 3103*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32)); 3104*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), 3105758cc3dcSJack F Vogel adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); 3106758cc3dcSJack F Vogel 3107758cc3dcSJack F Vogel /* Set up the SRRCTL register */ 3108*48056c88SJack F Vogel srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(j)); 3109758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; 3110758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; 3111758cc3dcSJack F Vogel srrctl |= bufsz; 3112758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; 3113758cc3dcSJack F Vogel 3114758cc3dcSJack F Vogel /* 3115758cc3dcSJack F Vogel * Set DROP_EN iff we have no flow control and >1 queue. 3116758cc3dcSJack F Vogel * Note that srrctl was cleared shortly before during reset, 3117758cc3dcSJack F Vogel * so we do not need to clear the bit, but do it just in case 3118758cc3dcSJack F Vogel * this code is moved elsewhere. 3119758cc3dcSJack F Vogel */ 312030126537SJack F Vogel if (adapter->num_queues > 1 && 312130126537SJack F Vogel adapter->hw.fc.requested_mode == ixgbe_fc_none) { 3122758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DROP_EN; 312330126537SJack F Vogel } else { 3124758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_DROP_EN; 312530126537SJack F Vogel } 3126758cc3dcSJack F Vogel 3127*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(j), srrctl); 3128758cc3dcSJack F Vogel 3129758cc3dcSJack F Vogel /* Setup the HW Rx Head and Tail Descriptor Pointers */ 3130*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0); 3131*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0); 3132758cc3dcSJack F Vogel 3133758cc3dcSJack F Vogel /* Set the processing limit */ 3134758cc3dcSJack F Vogel rxr->process_limit = ixgbe_rx_process_limit; 3135758cc3dcSJack F Vogel 3136758cc3dcSJack F Vogel /* Set the driver rx tail address */ 3137758cc3dcSJack F Vogel rxr->tail = IXGBE_RDT(rxr->me); 3138758cc3dcSJack F Vogel } 3139758cc3dcSJack F Vogel 3140758cc3dcSJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82598EB) { 3141758cc3dcSJack F Vogel u32 psrtype = IXGBE_PSRTYPE_TCPHDR | 3142758cc3dcSJack F Vogel IXGBE_PSRTYPE_UDPHDR | 3143758cc3dcSJack F Vogel IXGBE_PSRTYPE_IPV4HDR | 3144758cc3dcSJack F Vogel IXGBE_PSRTYPE_IPV6HDR; 3145758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); 3146758cc3dcSJack F Vogel } 3147758cc3dcSJack F Vogel 3148758cc3dcSJack F Vogel rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 3149758cc3dcSJack F Vogel 3150758cc3dcSJack F Vogel ixgbe_initialise_rss_mapping(adapter); 3151758cc3dcSJack F Vogel 3152758cc3dcSJack F Vogel if (adapter->num_queues > 1) { 3153758cc3dcSJack F Vogel /* RSS and RX IPP Checksum are mutually exclusive */ 3154758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_PCSD; 3155758cc3dcSJack F Vogel } 3156758cc3dcSJack F Vogel 3157758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_RXCSUM) 3158758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_PCSD; 3159758cc3dcSJack F Vogel 3160758cc3dcSJack F Vogel if (!(rxcsum & IXGBE_RXCSUM_PCSD)) 3161758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_IPPCSE; 3162758cc3dcSJack F Vogel 3163758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); 3164758cc3dcSJack F Vogel 3165758cc3dcSJack F Vogel return; 3166758cc3dcSJack F Vogel } 3167758cc3dcSJack F Vogel 3168758cc3dcSJack F Vogel 3169758cc3dcSJack F Vogel /* 3170758cc3dcSJack F Vogel ** This routine is run via an vlan config EVENT, 3171758cc3dcSJack F Vogel ** it enables us to use the HW Filter table since 3172758cc3dcSJack F Vogel ** we can get the vlan id. This just creates the 3173758cc3dcSJack F Vogel ** entry in the soft version of the VFTA, init will 3174758cc3dcSJack F Vogel ** repopulate the real table. 3175758cc3dcSJack F Vogel */ 3176758cc3dcSJack F Vogel static void 3177758cc3dcSJack F Vogel ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3178758cc3dcSJack F Vogel { 3179758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 3180758cc3dcSJack F Vogel u16 index, bit; 3181758cc3dcSJack F Vogel 3182758cc3dcSJack F Vogel if (ifp->if_softc != arg) /* Not our event */ 3183758cc3dcSJack F Vogel return; 3184758cc3dcSJack F Vogel 3185758cc3dcSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3186758cc3dcSJack F Vogel return; 3187758cc3dcSJack F Vogel 3188758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 3189758cc3dcSJack F Vogel index = (vtag >> 5) & 0x7F; 3190758cc3dcSJack F Vogel bit = vtag & 0x1F; 3191758cc3dcSJack F Vogel adapter->shadow_vfta[index] |= (1 << bit); 3192758cc3dcSJack F Vogel ++adapter->num_vlans; 3193758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 3194758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 3195758cc3dcSJack F Vogel } 3196758cc3dcSJack F Vogel 3197758cc3dcSJack F Vogel /* 3198758cc3dcSJack F Vogel ** This routine is run via an vlan 3199758cc3dcSJack F Vogel ** unconfig EVENT, remove our entry 3200758cc3dcSJack F Vogel ** in the soft vfta. 3201758cc3dcSJack F Vogel */ 3202758cc3dcSJack F Vogel static void 3203758cc3dcSJack F Vogel ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3204758cc3dcSJack F Vogel { 3205758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 3206758cc3dcSJack F Vogel u16 index, bit; 3207758cc3dcSJack F Vogel 3208758cc3dcSJack F Vogel if (ifp->if_softc != arg) 3209758cc3dcSJack F Vogel return; 3210758cc3dcSJack F Vogel 3211758cc3dcSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3212758cc3dcSJack F Vogel return; 3213758cc3dcSJack F Vogel 3214758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 3215758cc3dcSJack F Vogel index = (vtag >> 5) & 0x7F; 3216758cc3dcSJack F Vogel bit = vtag & 0x1F; 3217758cc3dcSJack F Vogel adapter->shadow_vfta[index] &= ~(1 << bit); 3218758cc3dcSJack F Vogel --adapter->num_vlans; 3219758cc3dcSJack F Vogel /* Re-init to load the changes */ 3220758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 3221758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 3222758cc3dcSJack F Vogel } 3223758cc3dcSJack F Vogel 3224758cc3dcSJack F Vogel static void 3225758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(struct adapter *adapter) 3226758cc3dcSJack F Vogel { 3227758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3228758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3229758cc3dcSJack F Vogel struct rx_ring *rxr; 3230758cc3dcSJack F Vogel u32 ctrl; 3231758cc3dcSJack F Vogel 3232758cc3dcSJack F Vogel 3233758cc3dcSJack F Vogel /* 3234758cc3dcSJack F Vogel ** We get here thru init_locked, meaning 3235758cc3dcSJack F Vogel ** a soft reset, this has already cleared 3236758cc3dcSJack F Vogel ** the VFTA and other state, so if there 3237758cc3dcSJack F Vogel ** have been no vlan's registered do nothing. 3238758cc3dcSJack F Vogel */ 3239758cc3dcSJack F Vogel if (adapter->num_vlans == 0) 3240758cc3dcSJack F Vogel return; 3241758cc3dcSJack F Vogel 3242758cc3dcSJack F Vogel /* Setup the queues for vlans */ 3243758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 3244758cc3dcSJack F Vogel rxr = &adapter->rx_rings[i]; 3245758cc3dcSJack F Vogel /* On 82599 the VLAN enable is per/queue in RXDCTL */ 3246758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 3247*48056c88SJack F Vogel ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); 3248758cc3dcSJack F Vogel ctrl |= IXGBE_RXDCTL_VME; 3249*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl); 3250758cc3dcSJack F Vogel } 3251758cc3dcSJack F Vogel rxr->vtag_strip = TRUE; 3252758cc3dcSJack F Vogel } 3253758cc3dcSJack F Vogel 3254758cc3dcSJack F Vogel if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0) 3255758cc3dcSJack F Vogel return; 3256758cc3dcSJack F Vogel /* 3257758cc3dcSJack F Vogel ** A soft reset zero's out the VFTA, so 3258758cc3dcSJack F Vogel ** we need to repopulate it now. 3259758cc3dcSJack F Vogel */ 3260758cc3dcSJack F Vogel for (int i = 0; i < IXGBE_VFTA_SIZE; i++) 3261758cc3dcSJack F Vogel if (adapter->shadow_vfta[i] != 0) 3262758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), 3263758cc3dcSJack F Vogel adapter->shadow_vfta[i]); 3264758cc3dcSJack F Vogel 3265758cc3dcSJack F Vogel ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); 3266758cc3dcSJack F Vogel /* Enable the Filter Table if enabled */ 3267758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) { 3268758cc3dcSJack F Vogel ctrl &= ~IXGBE_VLNCTRL_CFIEN; 3269758cc3dcSJack F Vogel ctrl |= IXGBE_VLNCTRL_VFE; 3270758cc3dcSJack F Vogel } 3271758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 3272758cc3dcSJack F Vogel ctrl |= IXGBE_VLNCTRL_VME; 3273758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); 3274758cc3dcSJack F Vogel } 3275758cc3dcSJack F Vogel 3276758cc3dcSJack F Vogel static void 3277758cc3dcSJack F Vogel ixgbe_enable_intr(struct adapter *adapter) 3278758cc3dcSJack F Vogel { 3279758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3280758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 3281758cc3dcSJack F Vogel u32 mask, fwsm; 3282758cc3dcSJack F Vogel 3283758cc3dcSJack F Vogel mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); 3284758cc3dcSJack F Vogel /* Enable Fan Failure detection */ 3285758cc3dcSJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) 32866f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP1; 3287758cc3dcSJack F Vogel 3288758cc3dcSJack F Vogel switch (adapter->hw.mac.type) { 3289758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 3290758cc3dcSJack F Vogel mask |= IXGBE_EIMS_ECC; 3291758cc3dcSJack F Vogel /* Temperature sensor on some adapters */ 32926f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP0; 3293758cc3dcSJack F Vogel /* SFP+ (RX_LOS_N & MOD_ABS_N) */ 32946f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP1; 32956f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP2; 3296758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3297758cc3dcSJack F Vogel mask |= IXGBE_EIMS_FLOW_DIR; 3298758cc3dcSJack F Vogel #endif 3299*48056c88SJack F Vogel #ifdef PCI_IOV 3300*48056c88SJack F Vogel mask |= IXGBE_EIMS_MAILBOX; 3301*48056c88SJack F Vogel #endif 3302758cc3dcSJack F Vogel break; 3303758cc3dcSJack F Vogel case ixgbe_mac_X540: 3304758cc3dcSJack F Vogel /* Detect if Thermal Sensor is enabled */ 3305758cc3dcSJack F Vogel fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); 3306758cc3dcSJack F Vogel if (fwsm & IXGBE_FWSM_TS_ENABLED) 3307758cc3dcSJack F Vogel mask |= IXGBE_EIMS_TS; 33086f37f232SEric Joyner mask |= IXGBE_EIMS_ECC; 33096f37f232SEric Joyner #ifdef IXGBE_FDIR 33106f37f232SEric Joyner mask |= IXGBE_EIMS_FLOW_DIR; 33116f37f232SEric Joyner #endif 33126f37f232SEric Joyner break; 33136f37f232SEric Joyner case ixgbe_mac_X550: 33146f37f232SEric Joyner case ixgbe_mac_X550EM_x: 33156f37f232SEric Joyner /* MAC thermal sensor is automatically enabled */ 33166f37f232SEric Joyner mask |= IXGBE_EIMS_TS; 33176f37f232SEric Joyner /* Some devices use SDP0 for important information */ 33186f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || 33196f37f232SEric Joyner hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) 3320758cc3dcSJack F Vogel mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); 3321758cc3dcSJack F Vogel mask |= IXGBE_EIMS_ECC; 3322758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3323758cc3dcSJack F Vogel mask |= IXGBE_EIMS_FLOW_DIR; 3324758cc3dcSJack F Vogel #endif 3325*48056c88SJack F Vogel #ifdef PCI_IOV 3326*48056c88SJack F Vogel mask |= IXGBE_EIMS_MAILBOX; 3327*48056c88SJack F Vogel #endif 3328758cc3dcSJack F Vogel /* falls through */ 3329758cc3dcSJack F Vogel default: 3330758cc3dcSJack F Vogel break; 3331758cc3dcSJack F Vogel } 3332758cc3dcSJack F Vogel 3333758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); 3334758cc3dcSJack F Vogel 33356f37f232SEric Joyner /* With MSI-X we use auto clear */ 3336758cc3dcSJack F Vogel if (adapter->msix_mem) { 3337758cc3dcSJack F Vogel mask = IXGBE_EIMS_ENABLE_MASK; 3338758cc3dcSJack F Vogel /* Don't autoclear Link */ 3339758cc3dcSJack F Vogel mask &= ~IXGBE_EIMS_OTHER; 3340758cc3dcSJack F Vogel mask &= ~IXGBE_EIMS_LSC; 3341*48056c88SJack F Vogel #ifdef PCI_IOV 3342*48056c88SJack F Vogel mask &= ~IXGBE_EIMS_MAILBOX; 3343*48056c88SJack F Vogel #endif 3344758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); 3345758cc3dcSJack F Vogel } 3346758cc3dcSJack F Vogel 3347758cc3dcSJack F Vogel /* 3348758cc3dcSJack F Vogel ** Now enable all queues, this is done separately to 3349758cc3dcSJack F Vogel ** allow for handling the extended (beyond 32) MSIX 3350758cc3dcSJack F Vogel ** vectors that can be used by 82599 3351758cc3dcSJack F Vogel */ 3352758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) 3353758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 3354758cc3dcSJack F Vogel 3355758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(hw); 3356758cc3dcSJack F Vogel 3357758cc3dcSJack F Vogel return; 3358758cc3dcSJack F Vogel } 3359758cc3dcSJack F Vogel 3360758cc3dcSJack F Vogel static void 3361758cc3dcSJack F Vogel ixgbe_disable_intr(struct adapter *adapter) 3362758cc3dcSJack F Vogel { 3363758cc3dcSJack F Vogel if (adapter->msix_mem) 3364758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, 0); 3365758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) { 3366758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); 3367758cc3dcSJack F Vogel } else { 3368758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000); 3369758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0); 3370758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0); 3371758cc3dcSJack F Vogel } 3372758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(&adapter->hw); 3373758cc3dcSJack F Vogel return; 3374758cc3dcSJack F Vogel } 3375758cc3dcSJack F Vogel 3376758cc3dcSJack F Vogel /* 3377758cc3dcSJack F Vogel ** Get the width and transaction speed of 3378758cc3dcSJack F Vogel ** the slot this adapter is plugged into. 3379758cc3dcSJack F Vogel */ 3380758cc3dcSJack F Vogel static void 3381758cc3dcSJack F Vogel ixgbe_get_slot_info(struct ixgbe_hw *hw) 3382758cc3dcSJack F Vogel { 3383758cc3dcSJack F Vogel device_t dev = ((struct ixgbe_osdep *)hw->back)->dev; 3384758cc3dcSJack F Vogel struct ixgbe_mac_info *mac = &hw->mac; 3385758cc3dcSJack F Vogel u16 link; 3386758cc3dcSJack F Vogel u32 offset; 3387758cc3dcSJack F Vogel 3388758cc3dcSJack F Vogel /* For most devices simply call the shared code routine */ 3389758cc3dcSJack F Vogel if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) { 3390758cc3dcSJack F Vogel ixgbe_get_bus_info(hw); 3391758cc3dcSJack F Vogel /* These devices don't use PCI-E */ 33926f37f232SEric Joyner switch (hw->mac.type) { 33936f37f232SEric Joyner case ixgbe_mac_X550EM_x: 3394758cc3dcSJack F Vogel return; 33956f37f232SEric Joyner default: 3396758cc3dcSJack F Vogel goto display; 3397758cc3dcSJack F Vogel } 33986f37f232SEric Joyner } 3399758cc3dcSJack F Vogel 3400758cc3dcSJack F Vogel /* 3401758cc3dcSJack F Vogel ** For the Quad port adapter we need to parse back 3402758cc3dcSJack F Vogel ** up the PCI tree to find the speed of the expansion 3403758cc3dcSJack F Vogel ** slot into which this adapter is plugged. A bit more work. 3404758cc3dcSJack F Vogel */ 3405758cc3dcSJack F Vogel dev = device_get_parent(device_get_parent(dev)); 3406758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG 3407758cc3dcSJack F Vogel device_printf(dev, "parent pcib = %x,%x,%x\n", 3408758cc3dcSJack F Vogel pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); 3409758cc3dcSJack F Vogel #endif 3410758cc3dcSJack F Vogel dev = device_get_parent(device_get_parent(dev)); 3411758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG 3412758cc3dcSJack F Vogel device_printf(dev, "slot pcib = %x,%x,%x\n", 3413758cc3dcSJack F Vogel pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); 3414758cc3dcSJack F Vogel #endif 3415758cc3dcSJack F Vogel /* Now get the PCI Express Capabilities offset */ 3416758cc3dcSJack F Vogel pci_find_cap(dev, PCIY_EXPRESS, &offset); 3417758cc3dcSJack F Vogel /* ...and read the Link Status Register */ 3418758cc3dcSJack F Vogel link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 3419758cc3dcSJack F Vogel switch (link & IXGBE_PCI_LINK_WIDTH) { 3420758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_1: 3421758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x1; 3422758cc3dcSJack F Vogel break; 3423758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_2: 3424758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x2; 3425758cc3dcSJack F Vogel break; 3426758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_4: 3427758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x4; 3428758cc3dcSJack F Vogel break; 3429758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_8: 3430758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x8; 3431758cc3dcSJack F Vogel break; 3432758cc3dcSJack F Vogel default: 3433758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_unknown; 3434758cc3dcSJack F Vogel break; 3435758cc3dcSJack F Vogel } 3436758cc3dcSJack F Vogel 3437758cc3dcSJack F Vogel switch (link & IXGBE_PCI_LINK_SPEED) { 3438758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_2500: 3439758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_2500; 3440758cc3dcSJack F Vogel break; 3441758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_5000: 3442758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_5000; 3443758cc3dcSJack F Vogel break; 3444758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_8000: 3445758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_8000; 3446758cc3dcSJack F Vogel break; 3447758cc3dcSJack F Vogel default: 3448758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_unknown; 3449758cc3dcSJack F Vogel break; 3450758cc3dcSJack F Vogel } 3451758cc3dcSJack F Vogel 3452758cc3dcSJack F Vogel mac->ops.set_lan_id(hw); 3453758cc3dcSJack F Vogel 3454758cc3dcSJack F Vogel display: 3455758cc3dcSJack F Vogel device_printf(dev,"PCI Express Bus: Speed %s %s\n", 3456758cc3dcSJack F Vogel ((hw->bus.speed == ixgbe_bus_speed_8000) ? "8.0GT/s": 3457758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0GT/s": 3458758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5GT/s":"Unknown"), 3459758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" : 3460758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" : 3461758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" : 3462758cc3dcSJack F Vogel ("Unknown")); 3463758cc3dcSJack F Vogel 3464758cc3dcSJack F Vogel if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) && 3465758cc3dcSJack F Vogel ((hw->bus.width <= ixgbe_bus_width_pcie_x4) && 3466758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_2500))) { 3467758cc3dcSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 3468758cc3dcSJack F Vogel " for this card\n is not sufficient for" 3469758cc3dcSJack F Vogel " optimal performance.\n"); 3470758cc3dcSJack F Vogel device_printf(dev, "For optimal performance a x8 " 3471758cc3dcSJack F Vogel "PCIE, or x4 PCIE Gen2 slot is required.\n"); 3472758cc3dcSJack F Vogel } 3473758cc3dcSJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) && 3474758cc3dcSJack F Vogel ((hw->bus.width <= ixgbe_bus_width_pcie_x8) && 3475758cc3dcSJack F Vogel (hw->bus.speed < ixgbe_bus_speed_8000))) { 3476758cc3dcSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 3477758cc3dcSJack F Vogel " for this card\n is not sufficient for" 3478758cc3dcSJack F Vogel " optimal performance.\n"); 3479758cc3dcSJack F Vogel device_printf(dev, "For optimal performance a x8 " 3480758cc3dcSJack F Vogel "PCIE Gen3 slot is required.\n"); 3481758cc3dcSJack F Vogel } 3482758cc3dcSJack F Vogel 3483758cc3dcSJack F Vogel return; 3484758cc3dcSJack F Vogel } 3485758cc3dcSJack F Vogel 3486758cc3dcSJack F Vogel 3487758cc3dcSJack F Vogel /* 3488758cc3dcSJack F Vogel ** Setup the correct IVAR register for a particular MSIX interrupt 3489758cc3dcSJack F Vogel ** (yes this is all very magic and confusing :) 3490758cc3dcSJack F Vogel ** - entry is the register array entry 3491758cc3dcSJack F Vogel ** - vector is the MSIX vector for this queue 3492758cc3dcSJack F Vogel ** - type is RX/TX/MISC 3493758cc3dcSJack F Vogel */ 3494758cc3dcSJack F Vogel static void 3495758cc3dcSJack F Vogel ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) 3496758cc3dcSJack F Vogel { 3497758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3498758cc3dcSJack F Vogel u32 ivar, index; 3499758cc3dcSJack F Vogel 3500758cc3dcSJack F Vogel vector |= IXGBE_IVAR_ALLOC_VAL; 3501758cc3dcSJack F Vogel 3502758cc3dcSJack F Vogel switch (hw->mac.type) { 3503758cc3dcSJack F Vogel 3504758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 3505758cc3dcSJack F Vogel if (type == -1) 3506758cc3dcSJack F Vogel entry = IXGBE_IVAR_OTHER_CAUSES_INDEX; 3507758cc3dcSJack F Vogel else 3508758cc3dcSJack F Vogel entry += (type * 64); 3509758cc3dcSJack F Vogel index = (entry >> 2) & 0x1F; 3510758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 3511758cc3dcSJack F Vogel ivar &= ~(0xFF << (8 * (entry & 0x3))); 3512758cc3dcSJack F Vogel ivar |= (vector << (8 * (entry & 0x3))); 3513758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar); 3514758cc3dcSJack F Vogel break; 3515758cc3dcSJack F Vogel 3516758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 3517758cc3dcSJack F Vogel case ixgbe_mac_X540: 3518758cc3dcSJack F Vogel case ixgbe_mac_X550: 3519758cc3dcSJack F Vogel case ixgbe_mac_X550EM_x: 3520758cc3dcSJack F Vogel if (type == -1) { /* MISC IVAR */ 3521758cc3dcSJack F Vogel index = (entry & 1) * 8; 3522758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 3523758cc3dcSJack F Vogel ivar &= ~(0xFF << index); 3524758cc3dcSJack F Vogel ivar |= (vector << index); 3525758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 3526758cc3dcSJack F Vogel } else { /* RX/TX IVARS */ 3527758cc3dcSJack F Vogel index = (16 * (entry & 1)) + (8 * type); 3528758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1)); 3529758cc3dcSJack F Vogel ivar &= ~(0xFF << index); 3530758cc3dcSJack F Vogel ivar |= (vector << index); 3531758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar); 3532758cc3dcSJack F Vogel } 3533758cc3dcSJack F Vogel 3534758cc3dcSJack F Vogel default: 3535758cc3dcSJack F Vogel break; 3536758cc3dcSJack F Vogel } 3537758cc3dcSJack F Vogel } 3538758cc3dcSJack F Vogel 3539758cc3dcSJack F Vogel static void 3540758cc3dcSJack F Vogel ixgbe_configure_ivars(struct adapter *adapter) 3541758cc3dcSJack F Vogel { 3542758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 3543758cc3dcSJack F Vogel u32 newitr; 3544758cc3dcSJack F Vogel 3545758cc3dcSJack F Vogel if (ixgbe_max_interrupt_rate > 0) 3546758cc3dcSJack F Vogel newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8; 35476f37f232SEric Joyner else { 35486f37f232SEric Joyner /* 35496f37f232SEric Joyner ** Disable DMA coalescing if interrupt moderation is 35506f37f232SEric Joyner ** disabled. 35516f37f232SEric Joyner */ 35526f37f232SEric Joyner adapter->dmac = 0; 3553758cc3dcSJack F Vogel newitr = 0; 35546f37f232SEric Joyner } 3555758cc3dcSJack F Vogel 3556758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 3557*48056c88SJack F Vogel struct rx_ring *rxr = &adapter->rx_rings[i]; 3558*48056c88SJack F Vogel struct tx_ring *txr = &adapter->tx_rings[i]; 3559758cc3dcSJack F Vogel /* First the RX queue entry */ 3560*48056c88SJack F Vogel ixgbe_set_ivar(adapter, rxr->me, que->msix, 0); 3561758cc3dcSJack F Vogel /* ... and the TX */ 3562*48056c88SJack F Vogel ixgbe_set_ivar(adapter, txr->me, que->msix, 1); 3563758cc3dcSJack F Vogel /* Set an Initial EITR value */ 3564758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, 3565758cc3dcSJack F Vogel IXGBE_EITR(que->msix), newitr); 3566758cc3dcSJack F Vogel } 3567758cc3dcSJack F Vogel 3568758cc3dcSJack F Vogel /* For the Link interrupt */ 3569758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 1, adapter->vector, -1); 3570758cc3dcSJack F Vogel } 3571758cc3dcSJack F Vogel 3572758cc3dcSJack F Vogel /* 3573758cc3dcSJack F Vogel ** ixgbe_sfp_probe - called in the local timer to 3574758cc3dcSJack F Vogel ** determine if a port had optics inserted. 3575758cc3dcSJack F Vogel */ 3576*48056c88SJack F Vogel static bool 3577*48056c88SJack F Vogel ixgbe_sfp_probe(struct adapter *adapter) 3578758cc3dcSJack F Vogel { 3579758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3580758cc3dcSJack F Vogel device_t dev = adapter->dev; 3581758cc3dcSJack F Vogel bool result = FALSE; 3582758cc3dcSJack F Vogel 3583758cc3dcSJack F Vogel if ((hw->phy.type == ixgbe_phy_nl) && 3584758cc3dcSJack F Vogel (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { 3585758cc3dcSJack F Vogel s32 ret = hw->phy.ops.identify_sfp(hw); 3586758cc3dcSJack F Vogel if (ret) 3587758cc3dcSJack F Vogel goto out; 3588758cc3dcSJack F Vogel ret = hw->phy.ops.reset(hw); 3589758cc3dcSJack F Vogel if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3590758cc3dcSJack F Vogel device_printf(dev,"Unsupported SFP+ module detected!"); 3591758cc3dcSJack F Vogel printf(" Reload driver with supported module.\n"); 3592758cc3dcSJack F Vogel adapter->sfp_probe = FALSE; 3593758cc3dcSJack F Vogel goto out; 3594758cc3dcSJack F Vogel } else 3595758cc3dcSJack F Vogel device_printf(dev,"SFP+ module detected!\n"); 3596758cc3dcSJack F Vogel /* We now have supported optics */ 3597758cc3dcSJack F Vogel adapter->sfp_probe = FALSE; 3598758cc3dcSJack F Vogel /* Set the optics type so system reports correctly */ 3599758cc3dcSJack F Vogel ixgbe_setup_optics(adapter); 3600758cc3dcSJack F Vogel result = TRUE; 3601758cc3dcSJack F Vogel } 3602758cc3dcSJack F Vogel out: 3603758cc3dcSJack F Vogel return (result); 3604758cc3dcSJack F Vogel } 3605758cc3dcSJack F Vogel 3606758cc3dcSJack F Vogel /* 3607758cc3dcSJack F Vogel ** Tasklet handler for MSIX Link interrupts 3608758cc3dcSJack F Vogel ** - do outside interrupt since it might sleep 3609758cc3dcSJack F Vogel */ 3610758cc3dcSJack F Vogel static void 3611758cc3dcSJack F Vogel ixgbe_handle_link(void *context, int pending) 3612758cc3dcSJack F Vogel { 3613758cc3dcSJack F Vogel struct adapter *adapter = context; 3614758cc3dcSJack F Vogel 3615758cc3dcSJack F Vogel ixgbe_check_link(&adapter->hw, 3616758cc3dcSJack F Vogel &adapter->link_speed, &adapter->link_up, 0); 3617758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 3618758cc3dcSJack F Vogel } 3619758cc3dcSJack F Vogel 3620758cc3dcSJack F Vogel /* 3621758cc3dcSJack F Vogel ** Tasklet for handling SFP module interrupts 3622758cc3dcSJack F Vogel */ 3623758cc3dcSJack F Vogel static void 3624758cc3dcSJack F Vogel ixgbe_handle_mod(void *context, int pending) 3625758cc3dcSJack F Vogel { 3626758cc3dcSJack F Vogel struct adapter *adapter = context; 3627758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3628758cc3dcSJack F Vogel device_t dev = adapter->dev; 3629758cc3dcSJack F Vogel u32 err; 3630758cc3dcSJack F Vogel 3631758cc3dcSJack F Vogel err = hw->phy.ops.identify_sfp(hw); 3632758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3633758cc3dcSJack F Vogel device_printf(dev, 3634758cc3dcSJack F Vogel "Unsupported SFP+ module type was detected.\n"); 3635758cc3dcSJack F Vogel return; 3636758cc3dcSJack F Vogel } 3637*48056c88SJack F Vogel 3638758cc3dcSJack F Vogel err = hw->mac.ops.setup_sfp(hw); 3639758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3640758cc3dcSJack F Vogel device_printf(dev, 3641758cc3dcSJack F Vogel "Setup failure - unsupported SFP+ module type.\n"); 3642758cc3dcSJack F Vogel return; 3643758cc3dcSJack F Vogel } 3644758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 3645758cc3dcSJack F Vogel return; 3646758cc3dcSJack F Vogel } 3647758cc3dcSJack F Vogel 3648758cc3dcSJack F Vogel 3649758cc3dcSJack F Vogel /* 3650758cc3dcSJack F Vogel ** Tasklet for handling MSF (multispeed fiber) interrupts 3651758cc3dcSJack F Vogel */ 3652758cc3dcSJack F Vogel static void 3653758cc3dcSJack F Vogel ixgbe_handle_msf(void *context, int pending) 3654758cc3dcSJack F Vogel { 3655758cc3dcSJack F Vogel struct adapter *adapter = context; 3656758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3657758cc3dcSJack F Vogel u32 autoneg; 3658758cc3dcSJack F Vogel bool negotiate; 3659758cc3dcSJack F Vogel int err; 3660758cc3dcSJack F Vogel 3661758cc3dcSJack F Vogel err = hw->phy.ops.identify_sfp(hw); 3662758cc3dcSJack F Vogel if (!err) { 3663758cc3dcSJack F Vogel ixgbe_setup_optics(adapter); 3664758cc3dcSJack F Vogel INIT_DEBUGOUT1("ixgbe_sfp_probe: flags: %X\n", adapter->optics); 3665758cc3dcSJack F Vogel } 3666758cc3dcSJack F Vogel 3667758cc3dcSJack F Vogel autoneg = hw->phy.autoneg_advertised; 3668758cc3dcSJack F Vogel if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) 3669758cc3dcSJack F Vogel hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate); 3670758cc3dcSJack F Vogel if (hw->mac.ops.setup_link) 3671758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, autoneg, TRUE); 3672758cc3dcSJack F Vogel 3673758cc3dcSJack F Vogel ifmedia_removeall(&adapter->media); 3674758cc3dcSJack F Vogel ixgbe_add_media_types(adapter); 3675758cc3dcSJack F Vogel return; 3676758cc3dcSJack F Vogel } 3677758cc3dcSJack F Vogel 36786f37f232SEric Joyner /* 36796f37f232SEric Joyner ** Tasklet for handling interrupts from an external PHY 36806f37f232SEric Joyner */ 36816f37f232SEric Joyner static void 36826f37f232SEric Joyner ixgbe_handle_phy(void *context, int pending) 36836f37f232SEric Joyner { 36846f37f232SEric Joyner struct adapter *adapter = context; 36856f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 36866f37f232SEric Joyner int error; 36876f37f232SEric Joyner 36886f37f232SEric Joyner error = hw->phy.ops.handle_lasi(hw); 36896f37f232SEric Joyner if (error == IXGBE_ERR_OVERTEMP) 36906f37f232SEric Joyner device_printf(adapter->dev, 36916f37f232SEric Joyner "CRITICAL: EXTERNAL PHY OVER TEMP!! " 36926f37f232SEric Joyner " PHY will downshift to lower power state!\n"); 36936f37f232SEric Joyner else if (error) 36946f37f232SEric Joyner device_printf(adapter->dev, 36956f37f232SEric Joyner "Error handling LASI interrupt: %d\n", 36966f37f232SEric Joyner error); 36976f37f232SEric Joyner return; 36986f37f232SEric Joyner } 36996f37f232SEric Joyner 3700758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3701758cc3dcSJack F Vogel /* 3702758cc3dcSJack F Vogel ** Tasklet for reinitializing the Flow Director filter table 3703758cc3dcSJack F Vogel */ 3704758cc3dcSJack F Vogel static void 3705758cc3dcSJack F Vogel ixgbe_reinit_fdir(void *context, int pending) 3706758cc3dcSJack F Vogel { 3707758cc3dcSJack F Vogel struct adapter *adapter = context; 3708758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3709758cc3dcSJack F Vogel 3710758cc3dcSJack F Vogel if (adapter->fdir_reinit != 1) /* Shouldn't happen */ 3711758cc3dcSJack F Vogel return; 3712758cc3dcSJack F Vogel ixgbe_reinit_fdir_tables_82599(&adapter->hw); 3713758cc3dcSJack F Vogel adapter->fdir_reinit = 0; 3714758cc3dcSJack F Vogel /* re-enable flow director interrupts */ 3715758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); 3716758cc3dcSJack F Vogel /* Restart the interface */ 3717758cc3dcSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 3718758cc3dcSJack F Vogel return; 3719758cc3dcSJack F Vogel } 3720758cc3dcSJack F Vogel #endif 3721758cc3dcSJack F Vogel 37226f37f232SEric Joyner /********************************************************************* 37236f37f232SEric Joyner * 37246f37f232SEric Joyner * Configure DMA Coalescing 37256f37f232SEric Joyner * 37266f37f232SEric Joyner **********************************************************************/ 37276f37f232SEric Joyner static void 37286f37f232SEric Joyner ixgbe_config_dmac(struct adapter *adapter) 37296f37f232SEric Joyner { 37306f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 37316f37f232SEric Joyner struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config; 37326f37f232SEric Joyner 37336f37f232SEric Joyner if (hw->mac.type < ixgbe_mac_X550 || 37346f37f232SEric Joyner !hw->mac.ops.dmac_config) 37356f37f232SEric Joyner return; 37366f37f232SEric Joyner 37376f37f232SEric Joyner if (dcfg->watchdog_timer ^ adapter->dmac || 37386f37f232SEric Joyner dcfg->link_speed ^ adapter->link_speed) { 37396f37f232SEric Joyner dcfg->watchdog_timer = adapter->dmac; 37406f37f232SEric Joyner dcfg->fcoe_en = false; 37416f37f232SEric Joyner dcfg->link_speed = adapter->link_speed; 37426f37f232SEric Joyner dcfg->num_tcs = 1; 37436f37f232SEric Joyner 37446f37f232SEric Joyner INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n", 37456f37f232SEric Joyner dcfg->watchdog_timer, dcfg->link_speed); 37466f37f232SEric Joyner 37476f37f232SEric Joyner hw->mac.ops.dmac_config(hw); 37486f37f232SEric Joyner } 37496f37f232SEric Joyner } 37506f37f232SEric Joyner 37516f37f232SEric Joyner /* 37526f37f232SEric Joyner * Checks whether the adapter supports Energy Efficient Ethernet 37536f37f232SEric Joyner * or not, based on device ID. 37546f37f232SEric Joyner */ 37556f37f232SEric Joyner static void 37566f37f232SEric Joyner ixgbe_check_eee_support(struct adapter *adapter) 37576f37f232SEric Joyner { 37586f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 37596f37f232SEric Joyner 3760*48056c88SJack F Vogel adapter->eee_enabled = !!(hw->mac.ops.setup_eee); 37616f37f232SEric Joyner } 37626f37f232SEric Joyner 37636f37f232SEric Joyner /* 37646f37f232SEric Joyner * Checks whether the adapter's ports are capable of 37656f37f232SEric Joyner * Wake On LAN by reading the adapter's NVM. 37666f37f232SEric Joyner * 37676f37f232SEric Joyner * Sets each port's hw->wol_enabled value depending 37686f37f232SEric Joyner * on the value read here. 37696f37f232SEric Joyner */ 37706f37f232SEric Joyner static void 37716f37f232SEric Joyner ixgbe_check_wol_support(struct adapter *adapter) 37726f37f232SEric Joyner { 37736f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 37746f37f232SEric Joyner u16 dev_caps = 0; 37756f37f232SEric Joyner 37766f37f232SEric Joyner /* Find out WoL support for port */ 37776f37f232SEric Joyner adapter->wol_support = hw->wol_enabled = 0; 37786f37f232SEric Joyner ixgbe_get_device_caps(hw, &dev_caps); 37796f37f232SEric Joyner if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) || 37806f37f232SEric Joyner ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) && 37816f37f232SEric Joyner hw->bus.func == 0)) 37826f37f232SEric Joyner adapter->wol_support = hw->wol_enabled = 1; 37836f37f232SEric Joyner 37846f37f232SEric Joyner /* Save initial wake up filter configuration */ 37856f37f232SEric Joyner adapter->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC); 37866f37f232SEric Joyner 37876f37f232SEric Joyner return; 37886f37f232SEric Joyner } 37896f37f232SEric Joyner 37906f37f232SEric Joyner /* 37916f37f232SEric Joyner * Prepare the adapter/port for LPLU and/or WoL 37926f37f232SEric Joyner */ 37936f37f232SEric Joyner static int 37946f37f232SEric Joyner ixgbe_setup_low_power_mode(struct adapter *adapter) 37956f37f232SEric Joyner { 37966f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 37976f37f232SEric Joyner device_t dev = adapter->dev; 37986f37f232SEric Joyner s32 error = 0; 37996f37f232SEric Joyner 38006f37f232SEric Joyner mtx_assert(&adapter->core_mtx, MA_OWNED); 38016f37f232SEric Joyner 38026f37f232SEric Joyner /* Limit power management flow to X550EM baseT */ 38036f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T 38046f37f232SEric Joyner && hw->phy.ops.enter_lplu) { 38056f37f232SEric Joyner /* Turn off support for APM wakeup. (Using ACPI instead) */ 38066f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_GRC, 38076f37f232SEric Joyner IXGBE_READ_REG(hw, IXGBE_GRC) & ~(u32)2); 38086f37f232SEric Joyner 38096f37f232SEric Joyner /* 38106f37f232SEric Joyner * Clear Wake Up Status register to prevent any previous wakeup 38116f37f232SEric Joyner * events from waking us up immediately after we suspend. 38126f37f232SEric Joyner */ 38136f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); 38146f37f232SEric Joyner 38156f37f232SEric Joyner /* 38166f37f232SEric Joyner * Program the Wakeup Filter Control register with user filter 38176f37f232SEric Joyner * settings 38186f37f232SEric Joyner */ 38196f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUFC, adapter->wufc); 38206f37f232SEric Joyner 38216f37f232SEric Joyner /* Enable wakeups and power management in Wakeup Control */ 38226f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUC, 38236f37f232SEric Joyner IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN); 38246f37f232SEric Joyner 38256f37f232SEric Joyner /* X550EM baseT adapters need a special LPLU flow */ 38266f37f232SEric Joyner hw->phy.reset_disable = true; 38276f37f232SEric Joyner ixgbe_stop(adapter); 38286f37f232SEric Joyner error = hw->phy.ops.enter_lplu(hw); 38296f37f232SEric Joyner if (error) 38306f37f232SEric Joyner device_printf(dev, 38316f37f232SEric Joyner "Error entering LPLU: %d\n", error); 38326f37f232SEric Joyner hw->phy.reset_disable = false; 38336f37f232SEric Joyner } else { 38346f37f232SEric Joyner /* Just stop for other adapters */ 38356f37f232SEric Joyner ixgbe_stop(adapter); 38366f37f232SEric Joyner } 38376f37f232SEric Joyner 38386f37f232SEric Joyner return error; 38396f37f232SEric Joyner } 38406f37f232SEric Joyner 3841758cc3dcSJack F Vogel /********************************************************************** 3842758cc3dcSJack F Vogel * 3843758cc3dcSJack F Vogel * Update the board statistics counters. 3844758cc3dcSJack F Vogel * 3845758cc3dcSJack F Vogel **********************************************************************/ 3846758cc3dcSJack F Vogel static void 3847758cc3dcSJack F Vogel ixgbe_update_stats_counters(struct adapter *adapter) 3848758cc3dcSJack F Vogel { 3849758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3850758cc3dcSJack F Vogel u32 missed_rx = 0, bprc, lxon, lxoff, total; 3851758cc3dcSJack F Vogel u64 total_missed_rx = 0; 3852758cc3dcSJack F Vogel 3853758cc3dcSJack F Vogel adapter->stats.pf.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); 3854758cc3dcSJack F Vogel adapter->stats.pf.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC); 3855758cc3dcSJack F Vogel adapter->stats.pf.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC); 3856758cc3dcSJack F Vogel adapter->stats.pf.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC); 3857758cc3dcSJack F Vogel 3858758cc3dcSJack F Vogel for (int i = 0; i < 16; i++) { 3859758cc3dcSJack F Vogel adapter->stats.pf.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); 3860758cc3dcSJack F Vogel adapter->stats.pf.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); 3861758cc3dcSJack F Vogel adapter->stats.pf.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); 3862758cc3dcSJack F Vogel } 3863758cc3dcSJack F Vogel adapter->stats.pf.mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC); 3864758cc3dcSJack F Vogel adapter->stats.pf.mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC); 3865758cc3dcSJack F Vogel adapter->stats.pf.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); 3866758cc3dcSJack F Vogel 3867758cc3dcSJack F Vogel /* Hardware workaround, gprc counts missed packets */ 3868758cc3dcSJack F Vogel adapter->stats.pf.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); 3869758cc3dcSJack F Vogel adapter->stats.pf.gprc -= missed_rx; 3870758cc3dcSJack F Vogel 3871758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 3872758cc3dcSJack F Vogel adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) + 3873758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); 3874758cc3dcSJack F Vogel adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) + 3875758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); 3876758cc3dcSJack F Vogel adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORL) + 3877758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); 3878758cc3dcSJack F Vogel adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); 3879758cc3dcSJack F Vogel adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); 3880758cc3dcSJack F Vogel } else { 3881758cc3dcSJack F Vogel adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); 3882758cc3dcSJack F Vogel adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); 3883758cc3dcSJack F Vogel /* 82598 only has a counter in the high register */ 3884758cc3dcSJack F Vogel adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); 3885758cc3dcSJack F Vogel adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); 3886758cc3dcSJack F Vogel adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORH); 3887758cc3dcSJack F Vogel } 3888758cc3dcSJack F Vogel 3889758cc3dcSJack F Vogel /* 3890758cc3dcSJack F Vogel * Workaround: mprc hardware is incorrectly counting 3891758cc3dcSJack F Vogel * broadcasts, so for now we subtract those. 3892758cc3dcSJack F Vogel */ 3893758cc3dcSJack F Vogel bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); 3894758cc3dcSJack F Vogel adapter->stats.pf.bprc += bprc; 3895758cc3dcSJack F Vogel adapter->stats.pf.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); 3896758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 3897758cc3dcSJack F Vogel adapter->stats.pf.mprc -= bprc; 3898758cc3dcSJack F Vogel 3899758cc3dcSJack F Vogel adapter->stats.pf.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); 3900758cc3dcSJack F Vogel adapter->stats.pf.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); 3901758cc3dcSJack F Vogel adapter->stats.pf.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); 3902758cc3dcSJack F Vogel adapter->stats.pf.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); 3903758cc3dcSJack F Vogel adapter->stats.pf.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); 3904758cc3dcSJack F Vogel adapter->stats.pf.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); 3905758cc3dcSJack F Vogel 3906758cc3dcSJack F Vogel lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); 3907758cc3dcSJack F Vogel adapter->stats.pf.lxontxc += lxon; 3908758cc3dcSJack F Vogel lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); 3909758cc3dcSJack F Vogel adapter->stats.pf.lxofftxc += lxoff; 3910758cc3dcSJack F Vogel total = lxon + lxoff; 3911758cc3dcSJack F Vogel 3912758cc3dcSJack F Vogel adapter->stats.pf.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); 3913758cc3dcSJack F Vogel adapter->stats.pf.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); 3914758cc3dcSJack F Vogel adapter->stats.pf.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); 3915758cc3dcSJack F Vogel adapter->stats.pf.gptc -= total; 3916758cc3dcSJack F Vogel adapter->stats.pf.mptc -= total; 3917758cc3dcSJack F Vogel adapter->stats.pf.ptc64 -= total; 3918758cc3dcSJack F Vogel adapter->stats.pf.gotc -= total * ETHER_MIN_LEN; 3919758cc3dcSJack F Vogel 3920758cc3dcSJack F Vogel adapter->stats.pf.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); 3921758cc3dcSJack F Vogel adapter->stats.pf.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); 3922758cc3dcSJack F Vogel adapter->stats.pf.roc += IXGBE_READ_REG(hw, IXGBE_ROC); 3923758cc3dcSJack F Vogel adapter->stats.pf.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); 3924758cc3dcSJack F Vogel adapter->stats.pf.mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC); 3925758cc3dcSJack F Vogel adapter->stats.pf.mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC); 3926758cc3dcSJack F Vogel adapter->stats.pf.mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC); 3927758cc3dcSJack F Vogel adapter->stats.pf.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); 3928758cc3dcSJack F Vogel adapter->stats.pf.tpt += IXGBE_READ_REG(hw, IXGBE_TPT); 3929758cc3dcSJack F Vogel adapter->stats.pf.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); 3930758cc3dcSJack F Vogel adapter->stats.pf.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); 3931758cc3dcSJack F Vogel adapter->stats.pf.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); 3932758cc3dcSJack F Vogel adapter->stats.pf.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); 3933758cc3dcSJack F Vogel adapter->stats.pf.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); 3934758cc3dcSJack F Vogel adapter->stats.pf.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); 3935758cc3dcSJack F Vogel adapter->stats.pf.xec += IXGBE_READ_REG(hw, IXGBE_XEC); 3936758cc3dcSJack F Vogel adapter->stats.pf.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); 3937758cc3dcSJack F Vogel adapter->stats.pf.fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST); 3938758cc3dcSJack F Vogel /* Only read FCOE on 82599 */ 3939758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 3940758cc3dcSJack F Vogel adapter->stats.pf.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); 3941758cc3dcSJack F Vogel adapter->stats.pf.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); 3942758cc3dcSJack F Vogel adapter->stats.pf.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); 3943758cc3dcSJack F Vogel adapter->stats.pf.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); 3944758cc3dcSJack F Vogel adapter->stats.pf.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); 3945758cc3dcSJack F Vogel } 3946758cc3dcSJack F Vogel 3947758cc3dcSJack F Vogel /* Fill out the OS statistics structure */ 3948758cc3dcSJack F Vogel IXGBE_SET_IPACKETS(adapter, adapter->stats.pf.gprc); 3949758cc3dcSJack F Vogel IXGBE_SET_OPACKETS(adapter, adapter->stats.pf.gptc); 3950758cc3dcSJack F Vogel IXGBE_SET_IBYTES(adapter, adapter->stats.pf.gorc); 3951758cc3dcSJack F Vogel IXGBE_SET_OBYTES(adapter, adapter->stats.pf.gotc); 3952758cc3dcSJack F Vogel IXGBE_SET_IMCASTS(adapter, adapter->stats.pf.mprc); 3953758cc3dcSJack F Vogel IXGBE_SET_OMCASTS(adapter, adapter->stats.pf.mptc); 3954758cc3dcSJack F Vogel IXGBE_SET_COLLISIONS(adapter, 0); 3955758cc3dcSJack F Vogel IXGBE_SET_IQDROPS(adapter, total_missed_rx); 3956758cc3dcSJack F Vogel IXGBE_SET_IERRORS(adapter, adapter->stats.pf.crcerrs 3957758cc3dcSJack F Vogel + adapter->stats.pf.rlec); 3958758cc3dcSJack F Vogel } 3959758cc3dcSJack F Vogel 3960758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 3961758cc3dcSJack F Vogel static uint64_t 3962758cc3dcSJack F Vogel ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt) 3963758cc3dcSJack F Vogel { 3964758cc3dcSJack F Vogel struct adapter *adapter; 3965625d12c6SJohn Baldwin struct tx_ring *txr; 3966625d12c6SJohn Baldwin uint64_t rv; 3967758cc3dcSJack F Vogel 3968758cc3dcSJack F Vogel adapter = if_getsoftc(ifp); 3969758cc3dcSJack F Vogel 3970758cc3dcSJack F Vogel switch (cnt) { 3971758cc3dcSJack F Vogel case IFCOUNTER_IPACKETS: 3972758cc3dcSJack F Vogel return (adapter->ipackets); 3973758cc3dcSJack F Vogel case IFCOUNTER_OPACKETS: 3974758cc3dcSJack F Vogel return (adapter->opackets); 3975758cc3dcSJack F Vogel case IFCOUNTER_IBYTES: 3976758cc3dcSJack F Vogel return (adapter->ibytes); 3977758cc3dcSJack F Vogel case IFCOUNTER_OBYTES: 3978758cc3dcSJack F Vogel return (adapter->obytes); 3979758cc3dcSJack F Vogel case IFCOUNTER_IMCASTS: 3980758cc3dcSJack F Vogel return (adapter->imcasts); 3981758cc3dcSJack F Vogel case IFCOUNTER_OMCASTS: 3982758cc3dcSJack F Vogel return (adapter->omcasts); 3983758cc3dcSJack F Vogel case IFCOUNTER_COLLISIONS: 3984758cc3dcSJack F Vogel return (0); 3985758cc3dcSJack F Vogel case IFCOUNTER_IQDROPS: 3986758cc3dcSJack F Vogel return (adapter->iqdrops); 3987625d12c6SJohn Baldwin case IFCOUNTER_OQDROPS: 3988625d12c6SJohn Baldwin rv = 0; 3989625d12c6SJohn Baldwin txr = adapter->tx_rings; 3990625d12c6SJohn Baldwin for (int i = 0; i < adapter->num_queues; i++, txr++) 3991625d12c6SJohn Baldwin rv += txr->br->br_drops; 3992625d12c6SJohn Baldwin return (rv); 3993758cc3dcSJack F Vogel case IFCOUNTER_IERRORS: 3994758cc3dcSJack F Vogel return (adapter->ierrors); 3995758cc3dcSJack F Vogel default: 3996758cc3dcSJack F Vogel return (if_get_counter_default(ifp, cnt)); 3997758cc3dcSJack F Vogel } 3998758cc3dcSJack F Vogel } 3999758cc3dcSJack F Vogel #endif 4000758cc3dcSJack F Vogel 4001758cc3dcSJack F Vogel /** ixgbe_sysctl_tdh_handler - Handler function 4002758cc3dcSJack F Vogel * Retrieves the TDH value from the hardware 4003758cc3dcSJack F Vogel */ 4004758cc3dcSJack F Vogel static int 4005758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS) 4006758cc3dcSJack F Vogel { 4007758cc3dcSJack F Vogel int error; 4008758cc3dcSJack F Vogel 4009758cc3dcSJack F Vogel struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); 4010758cc3dcSJack F Vogel if (!txr) return 0; 4011758cc3dcSJack F Vogel 4012758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me)); 4013758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4014758cc3dcSJack F Vogel if (error || !req->newptr) 4015758cc3dcSJack F Vogel return error; 4016758cc3dcSJack F Vogel return 0; 4017758cc3dcSJack F Vogel } 4018758cc3dcSJack F Vogel 4019758cc3dcSJack F Vogel /** ixgbe_sysctl_tdt_handler - Handler function 4020758cc3dcSJack F Vogel * Retrieves the TDT value from the hardware 4021758cc3dcSJack F Vogel */ 4022758cc3dcSJack F Vogel static int 4023758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS) 4024758cc3dcSJack F Vogel { 4025758cc3dcSJack F Vogel int error; 4026758cc3dcSJack F Vogel 4027758cc3dcSJack F Vogel struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); 4028758cc3dcSJack F Vogel if (!txr) return 0; 4029758cc3dcSJack F Vogel 4030758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me)); 4031758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4032758cc3dcSJack F Vogel if (error || !req->newptr) 4033758cc3dcSJack F Vogel return error; 4034758cc3dcSJack F Vogel return 0; 4035758cc3dcSJack F Vogel } 4036758cc3dcSJack F Vogel 4037758cc3dcSJack F Vogel /** ixgbe_sysctl_rdh_handler - Handler function 4038758cc3dcSJack F Vogel * Retrieves the RDH value from the hardware 4039758cc3dcSJack F Vogel */ 4040758cc3dcSJack F Vogel static int 4041758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS) 4042758cc3dcSJack F Vogel { 4043758cc3dcSJack F Vogel int error; 4044758cc3dcSJack F Vogel 4045758cc3dcSJack F Vogel struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); 4046758cc3dcSJack F Vogel if (!rxr) return 0; 4047758cc3dcSJack F Vogel 4048758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me)); 4049758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4050758cc3dcSJack F Vogel if (error || !req->newptr) 4051758cc3dcSJack F Vogel return error; 4052758cc3dcSJack F Vogel return 0; 4053758cc3dcSJack F Vogel } 4054758cc3dcSJack F Vogel 4055758cc3dcSJack F Vogel /** ixgbe_sysctl_rdt_handler - Handler function 4056758cc3dcSJack F Vogel * Retrieves the RDT value from the hardware 4057758cc3dcSJack F Vogel */ 4058758cc3dcSJack F Vogel static int 4059758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) 4060758cc3dcSJack F Vogel { 4061758cc3dcSJack F Vogel int error; 4062758cc3dcSJack F Vogel 4063758cc3dcSJack F Vogel struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); 4064758cc3dcSJack F Vogel if (!rxr) return 0; 4065758cc3dcSJack F Vogel 4066758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me)); 4067758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4068758cc3dcSJack F Vogel if (error || !req->newptr) 4069758cc3dcSJack F Vogel return error; 4070758cc3dcSJack F Vogel return 0; 4071758cc3dcSJack F Vogel } 4072758cc3dcSJack F Vogel 4073758cc3dcSJack F Vogel static int 4074758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS) 4075758cc3dcSJack F Vogel { 4076758cc3dcSJack F Vogel int error; 4077758cc3dcSJack F Vogel struct ix_queue *que = ((struct ix_queue *)oidp->oid_arg1); 4078758cc3dcSJack F Vogel unsigned int reg, usec, rate; 4079758cc3dcSJack F Vogel 4080758cc3dcSJack F Vogel reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix)); 4081758cc3dcSJack F Vogel usec = ((reg & 0x0FF8) >> 3); 4082758cc3dcSJack F Vogel if (usec > 0) 4083758cc3dcSJack F Vogel rate = 500000 / usec; 4084758cc3dcSJack F Vogel else 4085758cc3dcSJack F Vogel rate = 0; 4086758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &rate, 0, req); 4087758cc3dcSJack F Vogel if (error || !req->newptr) 4088758cc3dcSJack F Vogel return error; 4089758cc3dcSJack F Vogel reg &= ~0xfff; /* default, no limitation */ 4090758cc3dcSJack F Vogel ixgbe_max_interrupt_rate = 0; 4091758cc3dcSJack F Vogel if (rate > 0 && rate < 500000) { 4092758cc3dcSJack F Vogel if (rate < 1000) 4093758cc3dcSJack F Vogel rate = 1000; 4094758cc3dcSJack F Vogel ixgbe_max_interrupt_rate = rate; 4095758cc3dcSJack F Vogel reg |= ((4000000/rate) & 0xff8 ); 4096758cc3dcSJack F Vogel } 4097758cc3dcSJack F Vogel IXGBE_WRITE_REG(&que->adapter->hw, IXGBE_EITR(que->msix), reg); 4098758cc3dcSJack F Vogel return 0; 4099758cc3dcSJack F Vogel } 4100758cc3dcSJack F Vogel 41016f37f232SEric Joyner static void 41026f37f232SEric Joyner ixgbe_add_device_sysctls(struct adapter *adapter) 41036f37f232SEric Joyner { 41046f37f232SEric Joyner device_t dev = adapter->dev; 41056f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 41066f37f232SEric Joyner struct sysctl_oid_list *child; 41076f37f232SEric Joyner struct sysctl_ctx_list *ctx; 41086f37f232SEric Joyner 41096f37f232SEric Joyner ctx = device_get_sysctl_ctx(dev); 41106f37f232SEric Joyner child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 41116f37f232SEric Joyner 41126f37f232SEric Joyner /* Sysctls for all devices */ 41136f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fc", 41146f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 41156f37f232SEric Joyner ixgbe_set_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC); 41166f37f232SEric Joyner 41176f37f232SEric Joyner SYSCTL_ADD_INT(ctx, child, OID_AUTO, "enable_aim", 41186f37f232SEric Joyner CTLFLAG_RW, 41196f37f232SEric Joyner &ixgbe_enable_aim, 1, "Interrupt Moderation"); 41206f37f232SEric Joyner 41216f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "advertise_speed", 41226f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 41236f37f232SEric Joyner ixgbe_set_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED); 41246f37f232SEric Joyner 41256f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "thermal_test", 41266f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 41276f37f232SEric Joyner ixgbe_sysctl_thermal_test, "I", "Thermal Test"); 41286f37f232SEric Joyner 41296f37f232SEric Joyner /* for X550 devices */ 41306f37f232SEric Joyner if (hw->mac.type >= ixgbe_mac_X550) 41316f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac", 41326f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 41336f37f232SEric Joyner ixgbe_sysctl_dmac, "I", "DMA Coalesce"); 41346f37f232SEric Joyner 41356f37f232SEric Joyner /* for X550T and X550EM backplane devices */ 4136*48056c88SJack F Vogel if (hw->mac.ops.setup_eee) { 41376f37f232SEric Joyner struct sysctl_oid *eee_node; 41386f37f232SEric Joyner struct sysctl_oid_list *eee_list; 41396f37f232SEric Joyner 41406f37f232SEric Joyner eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee", 41416f37f232SEric Joyner CTLFLAG_RD, NULL, 41426f37f232SEric Joyner "Energy Efficient Ethernet sysctls"); 41436f37f232SEric Joyner eee_list = SYSCTL_CHILDREN(eee_node); 41446f37f232SEric Joyner 41456f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "enable", 41466f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 41476f37f232SEric Joyner ixgbe_sysctl_eee_enable, "I", 41486f37f232SEric Joyner "Enable or Disable EEE"); 41496f37f232SEric Joyner 41506f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "negotiated", 41516f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 41526f37f232SEric Joyner ixgbe_sysctl_eee_negotiated, "I", 41536f37f232SEric Joyner "EEE negotiated on link"); 41546f37f232SEric Joyner 41556f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_status", 41566f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 41576f37f232SEric Joyner ixgbe_sysctl_eee_tx_lpi_status, "I", 41586f37f232SEric Joyner "Whether or not TX link is in LPI state"); 41596f37f232SEric Joyner 41606f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "rx_lpi_status", 41616f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 41626f37f232SEric Joyner ixgbe_sysctl_eee_rx_lpi_status, "I", 41636f37f232SEric Joyner "Whether or not RX link is in LPI state"); 41646f37f232SEric Joyner } 41656f37f232SEric Joyner 41666f37f232SEric Joyner /* for certain 10GBaseT devices */ 41676f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550T || 41686f37f232SEric Joyner hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { 41696f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wol_enable", 41706f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 41716f37f232SEric Joyner ixgbe_sysctl_wol_enable, "I", 41726f37f232SEric Joyner "Enable/Disable Wake on LAN"); 41736f37f232SEric Joyner 41746f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wufc", 41756f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 41766f37f232SEric Joyner ixgbe_sysctl_wufc, "I", 41776f37f232SEric Joyner "Enable/Disable Wake Up Filters"); 41786f37f232SEric Joyner } 41796f37f232SEric Joyner 41806f37f232SEric Joyner /* for X550EM 10GBaseT devices */ 41816f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { 41826f37f232SEric Joyner struct sysctl_oid *phy_node; 41836f37f232SEric Joyner struct sysctl_oid_list *phy_list; 41846f37f232SEric Joyner 41856f37f232SEric Joyner phy_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "phy", 41866f37f232SEric Joyner CTLFLAG_RD, NULL, 41876f37f232SEric Joyner "External PHY sysctls"); 41886f37f232SEric Joyner phy_list = SYSCTL_CHILDREN(phy_node); 41896f37f232SEric Joyner 41906f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "temp", 41916f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 41926f37f232SEric Joyner ixgbe_sysctl_phy_temp, "I", 41936f37f232SEric Joyner "Current External PHY Temperature (Celsius)"); 41946f37f232SEric Joyner 41956f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "overtemp_occurred", 41966f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 41976f37f232SEric Joyner ixgbe_sysctl_phy_overtemp_occurred, "I", 41986f37f232SEric Joyner "External PHY High Temperature Event Occurred"); 41996f37f232SEric Joyner } 42006f37f232SEric Joyner } 42016f37f232SEric Joyner 4202758cc3dcSJack F Vogel /* 4203758cc3dcSJack F Vogel * Add sysctl variables, one per statistic, to the system. 4204758cc3dcSJack F Vogel */ 4205758cc3dcSJack F Vogel static void 4206758cc3dcSJack F Vogel ixgbe_add_hw_stats(struct adapter *adapter) 4207758cc3dcSJack F Vogel { 4208758cc3dcSJack F Vogel device_t dev = adapter->dev; 4209758cc3dcSJack F Vogel 4210758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 4211758cc3dcSJack F Vogel struct rx_ring *rxr = adapter->rx_rings; 4212758cc3dcSJack F Vogel 4213758cc3dcSJack F Vogel struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 4214758cc3dcSJack F Vogel struct sysctl_oid *tree = device_get_sysctl_tree(dev); 4215758cc3dcSJack F Vogel struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 4216758cc3dcSJack F Vogel struct ixgbe_hw_stats *stats = &adapter->stats.pf; 4217758cc3dcSJack F Vogel 4218758cc3dcSJack F Vogel struct sysctl_oid *stat_node, *queue_node; 4219758cc3dcSJack F Vogel struct sysctl_oid_list *stat_list, *queue_list; 4220758cc3dcSJack F Vogel 4221758cc3dcSJack F Vogel #define QUEUE_NAME_LEN 32 4222758cc3dcSJack F Vogel char namebuf[QUEUE_NAME_LEN]; 4223758cc3dcSJack F Vogel 4224758cc3dcSJack F Vogel /* Driver Statistics */ 4225758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", 4226758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->dropped_pkts, 4227758cc3dcSJack F Vogel "Driver dropped packets"); 4228758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", 4229758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->mbuf_defrag_failed, 4230758cc3dcSJack F Vogel "m_defrag() failed"); 4231758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 4232758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->watchdog_events, 4233758cc3dcSJack F Vogel "Watchdog timeouts"); 4234758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", 42356f37f232SEric Joyner CTLFLAG_RD, &adapter->link_irq, 4236758cc3dcSJack F Vogel "Link MSIX IRQ Handled"); 4237758cc3dcSJack F Vogel 4238758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, txr++) { 4239758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4240758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4241758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4242758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4243758cc3dcSJack F Vogel 4244758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate", 4245758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RW, &adapter->queues[i], 4246758cc3dcSJack F Vogel sizeof(&adapter->queues[i]), 4247758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler, "IU", 4248758cc3dcSJack F Vogel "Interrupt Rate"); 4249758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 4250758cc3dcSJack F Vogel CTLFLAG_RD, &(adapter->queues[i].irqs), 4251758cc3dcSJack F Vogel "irqs on this queue"); 4252758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", 4253758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), 4254758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler, "IU", 4255758cc3dcSJack F Vogel "Transmit Descriptor Head"); 4256758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", 4257758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), 4258758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler, "IU", 4259758cc3dcSJack F Vogel "Transmit Descriptor Tail"); 4260758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx", 4261758cc3dcSJack F Vogel CTLFLAG_RD, &txr->tso_tx, 4262758cc3dcSJack F Vogel "TSO"); 4263758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_tx_dma_setup", 4264758cc3dcSJack F Vogel CTLFLAG_RD, &txr->no_tx_dma_setup, 4265758cc3dcSJack F Vogel "Driver tx dma failure in xmit"); 4266758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 4267758cc3dcSJack F Vogel CTLFLAG_RD, &txr->no_desc_avail, 4268758cc3dcSJack F Vogel "Queue No Descriptor Available"); 4269758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 4270758cc3dcSJack F Vogel CTLFLAG_RD, &txr->total_packets, 4271758cc3dcSJack F Vogel "Queue Packets Transmitted"); 4272625d12c6SJohn Baldwin SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops", 4273625d12c6SJohn Baldwin CTLFLAG_RD, &txr->br->br_drops, 4274625d12c6SJohn Baldwin "Packets dropped in buf_ring"); 4275758cc3dcSJack F Vogel } 4276758cc3dcSJack F Vogel 4277758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, rxr++) { 4278758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4279758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4280758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4281758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4282758cc3dcSJack F Vogel 4283758cc3dcSJack F Vogel struct lro_ctrl *lro = &rxr->lro; 4284758cc3dcSJack F Vogel 4285758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4286758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4287758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4288758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4289758cc3dcSJack F Vogel 4290758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", 4291758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), 4292758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler, "IU", 4293758cc3dcSJack F Vogel "Receive Descriptor Head"); 4294758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", 4295758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), 4296758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler, "IU", 4297758cc3dcSJack F Vogel "Receive Descriptor Tail"); 4298758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 4299758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_packets, 4300758cc3dcSJack F Vogel "Queue Packets Received"); 4301758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 4302758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_bytes, 4303758cc3dcSJack F Vogel "Queue Bytes Received"); 4304758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies", 4305758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_copies, 4306758cc3dcSJack F Vogel "Copied RX Frames"); 4307758cc3dcSJack F Vogel SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_queued", 4308758cc3dcSJack F Vogel CTLFLAG_RD, &lro->lro_queued, 0, 4309758cc3dcSJack F Vogel "LRO Queued"); 4310758cc3dcSJack F Vogel SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_flushed", 4311758cc3dcSJack F Vogel CTLFLAG_RD, &lro->lro_flushed, 0, 4312758cc3dcSJack F Vogel "LRO Flushed"); 4313758cc3dcSJack F Vogel } 4314758cc3dcSJack F Vogel 4315758cc3dcSJack F Vogel /* MAC stats get the own sub node */ 4316758cc3dcSJack F Vogel 4317758cc3dcSJack F Vogel stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", 4318758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "MAC Statistics"); 4319758cc3dcSJack F Vogel stat_list = SYSCTL_CHILDREN(stat_node); 4320758cc3dcSJack F Vogel 4321758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs", 4322758cc3dcSJack F Vogel CTLFLAG_RD, &stats->crcerrs, 4323758cc3dcSJack F Vogel "CRC Errors"); 4324758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs", 4325758cc3dcSJack F Vogel CTLFLAG_RD, &stats->illerrc, 4326758cc3dcSJack F Vogel "Illegal Byte Errors"); 4327758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs", 4328758cc3dcSJack F Vogel CTLFLAG_RD, &stats->errbc, 4329758cc3dcSJack F Vogel "Byte Errors"); 4330758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards", 4331758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mspdc, 4332758cc3dcSJack F Vogel "MAC Short Packets Discarded"); 4333758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults", 4334758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mlfc, 4335758cc3dcSJack F Vogel "MAC Local Faults"); 4336758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults", 4337758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mrfc, 4338758cc3dcSJack F Vogel "MAC Remote Faults"); 4339758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs", 4340758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rlec, 4341758cc3dcSJack F Vogel "Receive Length Errors"); 4342758cc3dcSJack F Vogel 4343758cc3dcSJack F Vogel /* Flow Control stats */ 4344758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd", 4345758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxontxc, 4346758cc3dcSJack F Vogel "Link XON Transmitted"); 4347758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd", 4348758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxonrxc, 4349758cc3dcSJack F Vogel "Link XON Received"); 4350758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd", 4351758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxofftxc, 4352758cc3dcSJack F Vogel "Link XOFF Transmitted"); 4353758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd", 4354758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxoffrxc, 4355758cc3dcSJack F Vogel "Link XOFF Received"); 4356758cc3dcSJack F Vogel 4357758cc3dcSJack F Vogel /* Packet Reception Stats */ 4358758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd", 4359758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tor, 4360758cc3dcSJack F Vogel "Total Octets Received"); 4361758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", 4362758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gorc, 4363758cc3dcSJack F Vogel "Good Octets Received"); 4364758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd", 4365758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tpr, 4366758cc3dcSJack F Vogel "Total Packets Received"); 4367758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", 4368758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gprc, 4369758cc3dcSJack F Vogel "Good Packets Received"); 4370758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", 4371758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mprc, 4372758cc3dcSJack F Vogel "Multicast Packets Received"); 4373758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", 4374758cc3dcSJack F Vogel CTLFLAG_RD, &stats->bprc, 4375758cc3dcSJack F Vogel "Broadcast Packets Received"); 4376758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", 4377758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc64, 4378758cc3dcSJack F Vogel "64 byte frames received "); 4379758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", 4380758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc127, 4381758cc3dcSJack F Vogel "65-127 byte frames received"); 4382758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", 4383758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc255, 4384758cc3dcSJack F Vogel "128-255 byte frames received"); 4385758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", 4386758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc511, 4387758cc3dcSJack F Vogel "256-511 byte frames received"); 4388758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", 4389758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc1023, 4390758cc3dcSJack F Vogel "512-1023 byte frames received"); 4391758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", 4392758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc1522, 4393758cc3dcSJack F Vogel "1023-1522 byte frames received"); 4394758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized", 4395758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ruc, 4396758cc3dcSJack F Vogel "Receive Undersized"); 4397758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", 4398758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rfc, 4399758cc3dcSJack F Vogel "Fragmented Packets Received "); 4400758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized", 4401758cc3dcSJack F Vogel CTLFLAG_RD, &stats->roc, 4402758cc3dcSJack F Vogel "Oversized Packets Received"); 4403758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd", 4404758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rjc, 4405758cc3dcSJack F Vogel "Received Jabber"); 4406758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd", 4407758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngprc, 4408758cc3dcSJack F Vogel "Management Packets Received"); 4409758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd", 4410758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngptc, 4411758cc3dcSJack F Vogel "Management Packets Dropped"); 4412758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs", 4413758cc3dcSJack F Vogel CTLFLAG_RD, &stats->xec, 4414758cc3dcSJack F Vogel "Checksum Errors"); 4415758cc3dcSJack F Vogel 4416758cc3dcSJack F Vogel /* Packet Transmission Stats */ 4417758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", 4418758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gotc, 4419758cc3dcSJack F Vogel "Good Octets Transmitted"); 4420758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", 4421758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tpt, 4422758cc3dcSJack F Vogel "Total Packets Transmitted"); 4423758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", 4424758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gptc, 4425758cc3dcSJack F Vogel "Good Packets Transmitted"); 4426758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", 4427758cc3dcSJack F Vogel CTLFLAG_RD, &stats->bptc, 4428758cc3dcSJack F Vogel "Broadcast Packets Transmitted"); 4429758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", 4430758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mptc, 4431758cc3dcSJack F Vogel "Multicast Packets Transmitted"); 4432758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd", 4433758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngptc, 4434758cc3dcSJack F Vogel "Management Packets Transmitted"); 4435758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", 4436758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc64, 4437758cc3dcSJack F Vogel "64 byte frames transmitted "); 4438758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", 4439758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc127, 4440758cc3dcSJack F Vogel "65-127 byte frames transmitted"); 4441758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", 4442758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc255, 4443758cc3dcSJack F Vogel "128-255 byte frames transmitted"); 4444758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", 4445758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc511, 4446758cc3dcSJack F Vogel "256-511 byte frames transmitted"); 4447758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", 4448758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc1023, 4449758cc3dcSJack F Vogel "512-1023 byte frames transmitted"); 4450758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", 4451758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc1522, 4452758cc3dcSJack F Vogel "1024-1522 byte frames transmitted"); 4453758cc3dcSJack F Vogel } 4454758cc3dcSJack F Vogel 4455758cc3dcSJack F Vogel /* 4456758cc3dcSJack F Vogel ** Set flow control using sysctl: 4457758cc3dcSJack F Vogel ** Flow control values: 4458758cc3dcSJack F Vogel ** 0 - off 4459758cc3dcSJack F Vogel ** 1 - rx pause 4460758cc3dcSJack F Vogel ** 2 - tx pause 4461758cc3dcSJack F Vogel ** 3 - full 4462758cc3dcSJack F Vogel */ 4463758cc3dcSJack F Vogel static int 4464758cc3dcSJack F Vogel ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS) 4465758cc3dcSJack F Vogel { 4466758cc3dcSJack F Vogel int error, last; 4467758cc3dcSJack F Vogel struct adapter *adapter = (struct adapter *) arg1; 4468758cc3dcSJack F Vogel 4469758cc3dcSJack F Vogel last = adapter->fc; 4470758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &adapter->fc, 0, req); 4471758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4472758cc3dcSJack F Vogel return (error); 4473758cc3dcSJack F Vogel 4474758cc3dcSJack F Vogel /* Don't bother if it's not changed */ 4475758cc3dcSJack F Vogel if (adapter->fc == last) 4476758cc3dcSJack F Vogel return (0); 4477758cc3dcSJack F Vogel 4478758cc3dcSJack F Vogel switch (adapter->fc) { 4479758cc3dcSJack F Vogel case ixgbe_fc_rx_pause: 4480758cc3dcSJack F Vogel case ixgbe_fc_tx_pause: 4481758cc3dcSJack F Vogel case ixgbe_fc_full: 4482758cc3dcSJack F Vogel adapter->hw.fc.requested_mode = adapter->fc; 4483758cc3dcSJack F Vogel if (adapter->num_queues > 1) 4484758cc3dcSJack F Vogel ixgbe_disable_rx_drop(adapter); 4485758cc3dcSJack F Vogel break; 4486758cc3dcSJack F Vogel case ixgbe_fc_none: 4487758cc3dcSJack F Vogel adapter->hw.fc.requested_mode = ixgbe_fc_none; 4488758cc3dcSJack F Vogel if (adapter->num_queues > 1) 4489758cc3dcSJack F Vogel ixgbe_enable_rx_drop(adapter); 4490758cc3dcSJack F Vogel break; 4491758cc3dcSJack F Vogel default: 4492758cc3dcSJack F Vogel adapter->fc = last; 4493758cc3dcSJack F Vogel return (EINVAL); 4494758cc3dcSJack F Vogel } 4495758cc3dcSJack F Vogel /* Don't autoneg if forcing a value */ 4496758cc3dcSJack F Vogel adapter->hw.fc.disable_fc_autoneg = TRUE; 4497758cc3dcSJack F Vogel ixgbe_fc_enable(&adapter->hw); 4498758cc3dcSJack F Vogel return error; 4499758cc3dcSJack F Vogel } 4500758cc3dcSJack F Vogel 4501758cc3dcSJack F Vogel /* 4502758cc3dcSJack F Vogel ** Control advertised link speed: 4503758cc3dcSJack F Vogel ** Flags: 4504758cc3dcSJack F Vogel ** 0x1 - advertise 100 Mb 4505758cc3dcSJack F Vogel ** 0x2 - advertise 1G 4506758cc3dcSJack F Vogel ** 0x4 - advertise 10G 4507758cc3dcSJack F Vogel */ 4508758cc3dcSJack F Vogel static int 4509758cc3dcSJack F Vogel ixgbe_set_advertise(SYSCTL_HANDLER_ARGS) 4510758cc3dcSJack F Vogel { 4511758cc3dcSJack F Vogel int error = 0, requested; 4512758cc3dcSJack F Vogel struct adapter *adapter; 4513758cc3dcSJack F Vogel device_t dev; 4514758cc3dcSJack F Vogel struct ixgbe_hw *hw; 4515758cc3dcSJack F Vogel ixgbe_link_speed speed = 0; 4516758cc3dcSJack F Vogel 4517758cc3dcSJack F Vogel adapter = (struct adapter *) arg1; 4518758cc3dcSJack F Vogel dev = adapter->dev; 4519758cc3dcSJack F Vogel hw = &adapter->hw; 4520758cc3dcSJack F Vogel 4521758cc3dcSJack F Vogel requested = adapter->advertise; 4522758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &requested, 0, req); 4523758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4524758cc3dcSJack F Vogel return (error); 4525758cc3dcSJack F Vogel 4526758cc3dcSJack F Vogel /* Checks to validate new value */ 4527758cc3dcSJack F Vogel if (adapter->advertise == requested) /* no change */ 4528758cc3dcSJack F Vogel return (0); 4529758cc3dcSJack F Vogel 4530758cc3dcSJack F Vogel if (!((hw->phy.media_type == ixgbe_media_type_copper) || 4531758cc3dcSJack F Vogel (hw->phy.multispeed_fiber))) { 4532758cc3dcSJack F Vogel device_printf(dev, 4533758cc3dcSJack F Vogel "Advertised speed can only be set on copper or " 4534758cc3dcSJack F Vogel "multispeed fiber media types.\n"); 4535758cc3dcSJack F Vogel return (EINVAL); 4536758cc3dcSJack F Vogel } 4537758cc3dcSJack F Vogel 4538758cc3dcSJack F Vogel if (requested < 0x1 || requested > 0x7) { 4539758cc3dcSJack F Vogel device_printf(dev, 4540758cc3dcSJack F Vogel "Invalid advertised speed; valid modes are 0x1 through 0x7\n"); 4541758cc3dcSJack F Vogel return (EINVAL); 4542758cc3dcSJack F Vogel } 4543758cc3dcSJack F Vogel 4544758cc3dcSJack F Vogel if ((requested & 0x1) 4545758cc3dcSJack F Vogel && (hw->mac.type != ixgbe_mac_X540) 4546758cc3dcSJack F Vogel && (hw->mac.type != ixgbe_mac_X550)) { 4547758cc3dcSJack F Vogel device_printf(dev, "Set Advertise: 100Mb on X540/X550 only\n"); 4548758cc3dcSJack F Vogel return (EINVAL); 4549758cc3dcSJack F Vogel } 4550758cc3dcSJack F Vogel 4551758cc3dcSJack F Vogel /* Set new value and report new advertised mode */ 4552758cc3dcSJack F Vogel if (requested & 0x1) 4553758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 4554758cc3dcSJack F Vogel if (requested & 0x2) 4555758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 4556758cc3dcSJack F Vogel if (requested & 0x4) 4557758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_10GB_FULL; 4558758cc3dcSJack F Vogel 4559758cc3dcSJack F Vogel hw->mac.autotry_restart = TRUE; 4560758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, speed, TRUE); 4561758cc3dcSJack F Vogel adapter->advertise = requested; 4562758cc3dcSJack F Vogel 4563758cc3dcSJack F Vogel return (error); 4564758cc3dcSJack F Vogel } 4565758cc3dcSJack F Vogel 4566758cc3dcSJack F Vogel /* 45676f37f232SEric Joyner * The following two sysctls are for X550 BaseT devices; 45686f37f232SEric Joyner * they deal with the external PHY used in them. 4569758cc3dcSJack F Vogel */ 4570758cc3dcSJack F Vogel static int 45716f37f232SEric Joyner ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS) 4572758cc3dcSJack F Vogel { 4573758cc3dcSJack F Vogel struct adapter *adapter = (struct adapter *) arg1; 4574758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 45756f37f232SEric Joyner u16 reg; 4576758cc3dcSJack F Vogel 45776f37f232SEric Joyner if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { 45786f37f232SEric Joyner device_printf(adapter->dev, 45796f37f232SEric Joyner "Device has no supported external thermal sensor.\n"); 45806f37f232SEric Joyner return (ENODEV); 45816f37f232SEric Joyner } 4582758cc3dcSJack F Vogel 45836f37f232SEric Joyner if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP, 45846f37f232SEric Joyner IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 45856f37f232SEric Joyner ®)) { 45866f37f232SEric Joyner device_printf(adapter->dev, 45876f37f232SEric Joyner "Error reading from PHY's current temperature register\n"); 45886f37f232SEric Joyner return (EAGAIN); 45896f37f232SEric Joyner } 45906f37f232SEric Joyner 45916f37f232SEric Joyner /* Shift temp for output */ 45926f37f232SEric Joyner reg = reg >> 8; 45936f37f232SEric Joyner 45946f37f232SEric Joyner return (sysctl_handle_int(oidp, NULL, reg, req)); 45956f37f232SEric Joyner } 45966f37f232SEric Joyner 45976f37f232SEric Joyner /* 45986f37f232SEric Joyner * Reports whether the current PHY temperature is over 45996f37f232SEric Joyner * the overtemp threshold. 46006f37f232SEric Joyner * - This is reported directly from the PHY 46016f37f232SEric Joyner */ 46026f37f232SEric Joyner static int 46036f37f232SEric Joyner ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS) 46046f37f232SEric Joyner { 46056f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 46066f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 46076f37f232SEric Joyner u16 reg; 46086f37f232SEric Joyner 46096f37f232SEric Joyner if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { 46106f37f232SEric Joyner device_printf(adapter->dev, 46116f37f232SEric Joyner "Device has no supported external thermal sensor.\n"); 46126f37f232SEric Joyner return (ENODEV); 46136f37f232SEric Joyner } 46146f37f232SEric Joyner 46156f37f232SEric Joyner if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS, 46166f37f232SEric Joyner IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 46176f37f232SEric Joyner ®)) { 46186f37f232SEric Joyner device_printf(adapter->dev, 46196f37f232SEric Joyner "Error reading from PHY's temperature status register\n"); 46206f37f232SEric Joyner return (EAGAIN); 46216f37f232SEric Joyner } 46226f37f232SEric Joyner 46236f37f232SEric Joyner /* Get occurrence bit */ 46246f37f232SEric Joyner reg = !!(reg & 0x4000); 46256f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, reg, req)); 46266f37f232SEric Joyner } 46276f37f232SEric Joyner 46286f37f232SEric Joyner /* 46296f37f232SEric Joyner ** Thermal Shutdown Trigger (internal MAC) 46306f37f232SEric Joyner ** - Set this to 1 to cause an overtemp event to occur 46316f37f232SEric Joyner */ 46326f37f232SEric Joyner static int 46336f37f232SEric Joyner ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS) 46346f37f232SEric Joyner { 46356f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 46366f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 46376f37f232SEric Joyner int error, fire = 0; 4638758cc3dcSJack F Vogel 4639758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &fire, 0, req); 4640758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4641758cc3dcSJack F Vogel return (error); 4642758cc3dcSJack F Vogel 4643758cc3dcSJack F Vogel if (fire) { 4644758cc3dcSJack F Vogel u32 reg = IXGBE_READ_REG(hw, IXGBE_EICS); 4645758cc3dcSJack F Vogel reg |= IXGBE_EICR_TS; 4646758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICS, reg); 4647758cc3dcSJack F Vogel } 4648758cc3dcSJack F Vogel 4649758cc3dcSJack F Vogel return (0); 4650758cc3dcSJack F Vogel } 4651758cc3dcSJack F Vogel 4652758cc3dcSJack F Vogel /* 46536f37f232SEric Joyner ** Manage DMA Coalescing. 46546f37f232SEric Joyner ** Control values: 46556f37f232SEric Joyner ** 0/1 - off / on (use default value of 1000) 46566f37f232SEric Joyner ** 46576f37f232SEric Joyner ** Legal timer values are: 46586f37f232SEric Joyner ** 50,100,250,500,1000,2000,5000,10000 46596f37f232SEric Joyner ** 46606f37f232SEric Joyner ** Turning off interrupt moderation will also turn this off. 46616f37f232SEric Joyner */ 46626f37f232SEric Joyner static int 46636f37f232SEric Joyner ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS) 46646f37f232SEric Joyner { 46656f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 46666f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 46676f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 46686f37f232SEric Joyner int error; 46696f37f232SEric Joyner u16 oldval; 46706f37f232SEric Joyner 46716f37f232SEric Joyner oldval = adapter->dmac; 46726f37f232SEric Joyner error = sysctl_handle_int(oidp, &adapter->dmac, 0, req); 46736f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 46746f37f232SEric Joyner return (error); 46756f37f232SEric Joyner 46766f37f232SEric Joyner switch (hw->mac.type) { 46776f37f232SEric Joyner case ixgbe_mac_X550: 46786f37f232SEric Joyner case ixgbe_mac_X550EM_x: 46796f37f232SEric Joyner break; 46806f37f232SEric Joyner default: 46816f37f232SEric Joyner device_printf(adapter->dev, 46826f37f232SEric Joyner "DMA Coalescing is only supported on X550 devices\n"); 46836f37f232SEric Joyner return (ENODEV); 46846f37f232SEric Joyner } 46856f37f232SEric Joyner 46866f37f232SEric Joyner switch (adapter->dmac) { 46876f37f232SEric Joyner case 0: 46886f37f232SEric Joyner /* Disabled */ 46896f37f232SEric Joyner break; 46906f37f232SEric Joyner case 1: /* Enable and use default */ 46916f37f232SEric Joyner adapter->dmac = 1000; 46926f37f232SEric Joyner break; 46936f37f232SEric Joyner case 50: 46946f37f232SEric Joyner case 100: 46956f37f232SEric Joyner case 250: 46966f37f232SEric Joyner case 500: 46976f37f232SEric Joyner case 1000: 46986f37f232SEric Joyner case 2000: 46996f37f232SEric Joyner case 5000: 47006f37f232SEric Joyner case 10000: 47016f37f232SEric Joyner /* Legal values - allow */ 47026f37f232SEric Joyner break; 47036f37f232SEric Joyner default: 47046f37f232SEric Joyner /* Do nothing, illegal value */ 47056f37f232SEric Joyner adapter->dmac = oldval; 47066f37f232SEric Joyner return (EINVAL); 47076f37f232SEric Joyner } 47086f37f232SEric Joyner 47096f37f232SEric Joyner /* Re-initialize hardware if it's already running */ 47106f37f232SEric Joyner if (ifp->if_drv_flags & IFF_DRV_RUNNING) 47116f37f232SEric Joyner ixgbe_init(adapter); 47126f37f232SEric Joyner 47136f37f232SEric Joyner return (0); 47146f37f232SEric Joyner } 47156f37f232SEric Joyner 47166f37f232SEric Joyner /* 47176f37f232SEric Joyner * Sysctl to enable/disable the WoL capability, if supported by the adapter. 47186f37f232SEric Joyner * Values: 47196f37f232SEric Joyner * 0 - disabled 47206f37f232SEric Joyner * 1 - enabled 47216f37f232SEric Joyner */ 47226f37f232SEric Joyner static int 47236f37f232SEric Joyner ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS) 47246f37f232SEric Joyner { 47256f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 47266f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 47276f37f232SEric Joyner int new_wol_enabled; 47286f37f232SEric Joyner int error = 0; 47296f37f232SEric Joyner 47306f37f232SEric Joyner new_wol_enabled = hw->wol_enabled; 47316f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req); 47326f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 47336f37f232SEric Joyner return (error); 47346f37f232SEric Joyner if (new_wol_enabled == hw->wol_enabled) 47356f37f232SEric Joyner return (0); 47366f37f232SEric Joyner 47376f37f232SEric Joyner if (new_wol_enabled > 0 && !adapter->wol_support) 47386f37f232SEric Joyner return (ENODEV); 47396f37f232SEric Joyner else 47406f37f232SEric Joyner hw->wol_enabled = !!(new_wol_enabled); 47416f37f232SEric Joyner 47426f37f232SEric Joyner return (0); 47436f37f232SEric Joyner } 47446f37f232SEric Joyner 47456f37f232SEric Joyner /* 47466f37f232SEric Joyner * Sysctl to enable/disable the Energy Efficient Ethernet capability, 47476f37f232SEric Joyner * if supported by the adapter. 47486f37f232SEric Joyner * Values: 47496f37f232SEric Joyner * 0 - disabled 47506f37f232SEric Joyner * 1 - enabled 47516f37f232SEric Joyner */ 47526f37f232SEric Joyner static int 47536f37f232SEric Joyner ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS) 47546f37f232SEric Joyner { 47556f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 4756*48056c88SJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 47576f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 47586f37f232SEric Joyner int new_eee_enabled, error = 0; 47596f37f232SEric Joyner 47606f37f232SEric Joyner new_eee_enabled = adapter->eee_enabled; 47616f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_eee_enabled, 0, req); 47626f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 47636f37f232SEric Joyner return (error); 47646f37f232SEric Joyner if (new_eee_enabled == adapter->eee_enabled) 47656f37f232SEric Joyner return (0); 47666f37f232SEric Joyner 4767*48056c88SJack F Vogel if (new_eee_enabled > 0 && !hw->mac.ops.setup_eee) 47686f37f232SEric Joyner return (ENODEV); 47696f37f232SEric Joyner else 47706f37f232SEric Joyner adapter->eee_enabled = !!(new_eee_enabled); 47716f37f232SEric Joyner 47726f37f232SEric Joyner /* Re-initialize hardware if it's already running */ 47736f37f232SEric Joyner if (ifp->if_drv_flags & IFF_DRV_RUNNING) 47746f37f232SEric Joyner ixgbe_init(adapter); 47756f37f232SEric Joyner 47766f37f232SEric Joyner return (0); 47776f37f232SEric Joyner } 47786f37f232SEric Joyner 47796f37f232SEric Joyner /* 47806f37f232SEric Joyner * Read-only sysctl indicating whether EEE support was negotiated 47816f37f232SEric Joyner * on the link. 47826f37f232SEric Joyner */ 47836f37f232SEric Joyner static int 47846f37f232SEric Joyner ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS) 47856f37f232SEric Joyner { 47866f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 47876f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 47886f37f232SEric Joyner bool status; 47896f37f232SEric Joyner 47906f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & IXGBE_EEE_STAT_NEG); 47916f37f232SEric Joyner 47926f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 47936f37f232SEric Joyner } 47946f37f232SEric Joyner 47956f37f232SEric Joyner /* 47966f37f232SEric Joyner * Read-only sysctl indicating whether RX Link is in LPI state. 47976f37f232SEric Joyner */ 47986f37f232SEric Joyner static int 47996f37f232SEric Joyner ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS) 48006f37f232SEric Joyner { 48016f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 48026f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 48036f37f232SEric Joyner bool status; 48046f37f232SEric Joyner 48056f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & 48066f37f232SEric Joyner IXGBE_EEE_RX_LPI_STATUS); 48076f37f232SEric Joyner 48086f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 48096f37f232SEric Joyner } 48106f37f232SEric Joyner 48116f37f232SEric Joyner /* 48126f37f232SEric Joyner * Read-only sysctl indicating whether TX Link is in LPI state. 48136f37f232SEric Joyner */ 48146f37f232SEric Joyner static int 48156f37f232SEric Joyner ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS) 48166f37f232SEric Joyner { 48176f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 48186f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 48196f37f232SEric Joyner bool status; 48206f37f232SEric Joyner 48216f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & 48226f37f232SEric Joyner IXGBE_EEE_TX_LPI_STATUS); 48236f37f232SEric Joyner 48246f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 48256f37f232SEric Joyner } 48266f37f232SEric Joyner 48276f37f232SEric Joyner /* 48286f37f232SEric Joyner * Sysctl to enable/disable the types of packets that the 48296f37f232SEric Joyner * adapter will wake up on upon receipt. 48306f37f232SEric Joyner * WUFC - Wake Up Filter Control 48316f37f232SEric Joyner * Flags: 48326f37f232SEric Joyner * 0x1 - Link Status Change 48336f37f232SEric Joyner * 0x2 - Magic Packet 48346f37f232SEric Joyner * 0x4 - Direct Exact 48356f37f232SEric Joyner * 0x8 - Directed Multicast 48366f37f232SEric Joyner * 0x10 - Broadcast 48376f37f232SEric Joyner * 0x20 - ARP/IPv4 Request Packet 48386f37f232SEric Joyner * 0x40 - Direct IPv4 Packet 48396f37f232SEric Joyner * 0x80 - Direct IPv6 Packet 48406f37f232SEric Joyner * 48416f37f232SEric Joyner * Setting another flag will cause the sysctl to return an 48426f37f232SEric Joyner * error. 48436f37f232SEric Joyner */ 48446f37f232SEric Joyner static int 48456f37f232SEric Joyner ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS) 48466f37f232SEric Joyner { 48476f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 48486f37f232SEric Joyner int error = 0; 48496f37f232SEric Joyner u32 new_wufc; 48506f37f232SEric Joyner 48516f37f232SEric Joyner new_wufc = adapter->wufc; 48526f37f232SEric Joyner 48536f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_wufc, 0, req); 48546f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 48556f37f232SEric Joyner return (error); 48566f37f232SEric Joyner if (new_wufc == adapter->wufc) 48576f37f232SEric Joyner return (0); 48586f37f232SEric Joyner 48596f37f232SEric Joyner if (new_wufc & 0xffffff00) 48606f37f232SEric Joyner return (EINVAL); 48616f37f232SEric Joyner else { 48626f37f232SEric Joyner new_wufc &= 0xff; 48636f37f232SEric Joyner new_wufc |= (0xffffff & adapter->wufc); 48646f37f232SEric Joyner adapter->wufc = new_wufc; 48656f37f232SEric Joyner } 48666f37f232SEric Joyner 48676f37f232SEric Joyner return (0); 48686f37f232SEric Joyner } 48696f37f232SEric Joyner 48706f37f232SEric Joyner /* 4871758cc3dcSJack F Vogel ** Enable the hardware to drop packets when the buffer is 4872758cc3dcSJack F Vogel ** full. This is useful when multiqueue,so that no single 4873758cc3dcSJack F Vogel ** queue being full stalls the entire RX engine. We only 4874758cc3dcSJack F Vogel ** enable this when Multiqueue AND when Flow Control is 4875758cc3dcSJack F Vogel ** disabled. 4876758cc3dcSJack F Vogel */ 4877758cc3dcSJack F Vogel static void 4878758cc3dcSJack F Vogel ixgbe_enable_rx_drop(struct adapter *adapter) 4879758cc3dcSJack F Vogel { 4880758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 4881758cc3dcSJack F Vogel 4882758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 4883*48056c88SJack F Vogel struct rx_ring *rxr = &adapter->rx_rings[i]; 4884*48056c88SJack F Vogel u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); 4885758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DROP_EN; 4886*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); 4887758cc3dcSJack F Vogel } 4888*48056c88SJack F Vogel #ifdef PCI_IOV 4889*48056c88SJack F Vogel /* enable drop for each vf */ 4890*48056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 4891*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_QDE, 4892*48056c88SJack F Vogel (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT) | 4893*48056c88SJack F Vogel IXGBE_QDE_ENABLE)); 4894*48056c88SJack F Vogel } 4895*48056c88SJack F Vogel #endif 4896758cc3dcSJack F Vogel } 4897758cc3dcSJack F Vogel 4898758cc3dcSJack F Vogel static void 4899758cc3dcSJack F Vogel ixgbe_disable_rx_drop(struct adapter *adapter) 4900758cc3dcSJack F Vogel { 4901758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 4902758cc3dcSJack F Vogel 4903758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 4904*48056c88SJack F Vogel struct rx_ring *rxr = &adapter->rx_rings[i]; 4905*48056c88SJack F Vogel u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); 4906758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_DROP_EN; 4907*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); 4908758cc3dcSJack F Vogel } 4909*48056c88SJack F Vogel #ifdef PCI_IOV 4910*48056c88SJack F Vogel /* disable drop for each vf */ 4911*48056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 4912*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_QDE, 4913*48056c88SJack F Vogel (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT))); 4914*48056c88SJack F Vogel } 4915*48056c88SJack F Vogel #endif 4916758cc3dcSJack F Vogel } 4917758cc3dcSJack F Vogel 4918758cc3dcSJack F Vogel static void 4919758cc3dcSJack F Vogel ixgbe_rearm_queues(struct adapter *adapter, u64 queues) 4920758cc3dcSJack F Vogel { 4921758cc3dcSJack F Vogel u32 mask; 4922758cc3dcSJack F Vogel 4923758cc3dcSJack F Vogel switch (adapter->hw.mac.type) { 4924758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 4925758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queues); 4926758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); 4927758cc3dcSJack F Vogel break; 4928758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 4929758cc3dcSJack F Vogel case ixgbe_mac_X540: 4930758cc3dcSJack F Vogel case ixgbe_mac_X550: 49316f37f232SEric Joyner case ixgbe_mac_X550EM_x: 4932758cc3dcSJack F Vogel mask = (queues & 0xFFFFFFFF); 4933758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); 4934758cc3dcSJack F Vogel mask = (queues >> 32); 4935758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); 4936758cc3dcSJack F Vogel break; 4937758cc3dcSJack F Vogel default: 4938758cc3dcSJack F Vogel break; 4939758cc3dcSJack F Vogel } 4940758cc3dcSJack F Vogel } 4941758cc3dcSJack F Vogel 4942*48056c88SJack F Vogel #ifdef PCI_IOV 4943*48056c88SJack F Vogel 4944*48056c88SJack F Vogel /* 4945*48056c88SJack F Vogel ** Support functions for SRIOV/VF management 4946*48056c88SJack F Vogel */ 4947*48056c88SJack F Vogel 4948*48056c88SJack F Vogel static void 4949*48056c88SJack F Vogel ixgbe_ping_all_vfs(struct adapter *adapter) 4950*48056c88SJack F Vogel { 4951*48056c88SJack F Vogel struct ixgbe_vf *vf; 4952*48056c88SJack F Vogel 4953*48056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 4954*48056c88SJack F Vogel vf = &adapter->vfs[i]; 4955*48056c88SJack F Vogel if (vf->flags & IXGBE_VF_ACTIVE) 4956*48056c88SJack F Vogel ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); 4957*48056c88SJack F Vogel } 4958*48056c88SJack F Vogel } 4959*48056c88SJack F Vogel 4960*48056c88SJack F Vogel 4961*48056c88SJack F Vogel static void 4962*48056c88SJack F Vogel ixgbe_vf_set_default_vlan(struct adapter *adapter, struct ixgbe_vf *vf, 4963*48056c88SJack F Vogel uint16_t tag) 4964*48056c88SJack F Vogel { 4965*48056c88SJack F Vogel struct ixgbe_hw *hw; 4966*48056c88SJack F Vogel uint32_t vmolr, vmvir; 4967*48056c88SJack F Vogel 4968*48056c88SJack F Vogel hw = &adapter->hw; 4969*48056c88SJack F Vogel 4970*48056c88SJack F Vogel vf->vlan_tag = tag; 4971*48056c88SJack F Vogel 4972*48056c88SJack F Vogel vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool)); 4973*48056c88SJack F Vogel 4974*48056c88SJack F Vogel /* Do not receive packets that pass inexact filters. */ 4975*48056c88SJack F Vogel vmolr &= ~(IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_ROPE); 4976*48056c88SJack F Vogel 4977*48056c88SJack F Vogel /* Disable Multicast Promicuous Mode. */ 4978*48056c88SJack F Vogel vmolr &= ~IXGBE_VMOLR_MPE; 4979*48056c88SJack F Vogel 4980*48056c88SJack F Vogel /* Accept broadcasts. */ 4981*48056c88SJack F Vogel vmolr |= IXGBE_VMOLR_BAM; 4982*48056c88SJack F Vogel 4983*48056c88SJack F Vogel if (tag == 0) { 4984*48056c88SJack F Vogel /* Accept non-vlan tagged traffic. */ 4985*48056c88SJack F Vogel //vmolr |= IXGBE_VMOLR_AUPE; 4986*48056c88SJack F Vogel 4987*48056c88SJack F Vogel /* Allow VM to tag outgoing traffic; no default tag. */ 4988*48056c88SJack F Vogel vmvir = 0; 4989*48056c88SJack F Vogel } else { 4990*48056c88SJack F Vogel /* Require vlan-tagged traffic. */ 4991*48056c88SJack F Vogel vmolr &= ~IXGBE_VMOLR_AUPE; 4992*48056c88SJack F Vogel 4993*48056c88SJack F Vogel /* Tag all traffic with provided vlan tag. */ 4994*48056c88SJack F Vogel vmvir = (tag | IXGBE_VMVIR_VLANA_DEFAULT); 4995*48056c88SJack F Vogel } 4996*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr); 4997*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir); 4998*48056c88SJack F Vogel } 4999*48056c88SJack F Vogel 5000*48056c88SJack F Vogel 5001*48056c88SJack F Vogel static boolean_t 5002*48056c88SJack F Vogel ixgbe_vf_frame_size_compatible(struct adapter *adapter, struct ixgbe_vf *vf) 5003*48056c88SJack F Vogel { 5004*48056c88SJack F Vogel 5005*48056c88SJack F Vogel /* 5006*48056c88SJack F Vogel * Frame size compatibility between PF and VF is only a problem on 5007*48056c88SJack F Vogel * 82599-based cards. X540 and later support any combination of jumbo 5008*48056c88SJack F Vogel * frames on PFs and VFs. 5009*48056c88SJack F Vogel */ 5010*48056c88SJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82599EB) 5011*48056c88SJack F Vogel return (TRUE); 5012*48056c88SJack F Vogel 5013*48056c88SJack F Vogel switch (vf->api_ver) { 5014*48056c88SJack F Vogel case IXGBE_API_VER_1_0: 5015*48056c88SJack F Vogel case IXGBE_API_VER_UNKNOWN: 5016*48056c88SJack F Vogel /* 5017*48056c88SJack F Vogel * On legacy (1.0 and older) VF versions, we don't support jumbo 5018*48056c88SJack F Vogel * frames on either the PF or the VF. 5019*48056c88SJack F Vogel */ 5020*48056c88SJack F Vogel if (adapter->max_frame_size > ETHER_MAX_LEN || 5021*48056c88SJack F Vogel vf->max_frame_size > ETHER_MAX_LEN) 5022*48056c88SJack F Vogel return (FALSE); 5023*48056c88SJack F Vogel 5024*48056c88SJack F Vogel return (TRUE); 5025*48056c88SJack F Vogel 5026*48056c88SJack F Vogel break; 5027*48056c88SJack F Vogel case IXGBE_API_VER_1_1: 5028*48056c88SJack F Vogel default: 5029*48056c88SJack F Vogel /* 5030*48056c88SJack F Vogel * 1.1 or later VF versions always work if they aren't using 5031*48056c88SJack F Vogel * jumbo frames. 5032*48056c88SJack F Vogel */ 5033*48056c88SJack F Vogel if (vf->max_frame_size <= ETHER_MAX_LEN) 5034*48056c88SJack F Vogel return (TRUE); 5035*48056c88SJack F Vogel 5036*48056c88SJack F Vogel /* 5037*48056c88SJack F Vogel * Jumbo frames only work with VFs if the PF is also using jumbo 5038*48056c88SJack F Vogel * frames. 5039*48056c88SJack F Vogel */ 5040*48056c88SJack F Vogel if (adapter->max_frame_size <= ETHER_MAX_LEN) 5041*48056c88SJack F Vogel return (TRUE); 5042*48056c88SJack F Vogel 5043*48056c88SJack F Vogel return (FALSE); 5044*48056c88SJack F Vogel 5045*48056c88SJack F Vogel } 5046*48056c88SJack F Vogel } 5047*48056c88SJack F Vogel 5048*48056c88SJack F Vogel 5049*48056c88SJack F Vogel static void 5050*48056c88SJack F Vogel ixgbe_process_vf_reset(struct adapter *adapter, struct ixgbe_vf *vf) 5051*48056c88SJack F Vogel { 5052*48056c88SJack F Vogel ixgbe_vf_set_default_vlan(adapter, vf, vf->default_vlan); 5053*48056c88SJack F Vogel 5054*48056c88SJack F Vogel // XXX clear multicast addresses 5055*48056c88SJack F Vogel 5056*48056c88SJack F Vogel ixgbe_clear_rar(&adapter->hw, vf->rar_index); 5057*48056c88SJack F Vogel 5058*48056c88SJack F Vogel vf->api_ver = IXGBE_API_VER_UNKNOWN; 5059*48056c88SJack F Vogel } 5060*48056c88SJack F Vogel 5061*48056c88SJack F Vogel 5062*48056c88SJack F Vogel static void 5063*48056c88SJack F Vogel ixgbe_vf_enable_transmit(struct adapter *adapter, struct ixgbe_vf *vf) 5064*48056c88SJack F Vogel { 5065*48056c88SJack F Vogel struct ixgbe_hw *hw; 5066*48056c88SJack F Vogel uint32_t vf_index, vfte; 5067*48056c88SJack F Vogel 5068*48056c88SJack F Vogel hw = &adapter->hw; 5069*48056c88SJack F Vogel 5070*48056c88SJack F Vogel vf_index = IXGBE_VF_INDEX(vf->pool); 5071*48056c88SJack F Vogel vfte = IXGBE_READ_REG(hw, IXGBE_VFTE(vf_index)); 5072*48056c88SJack F Vogel vfte |= IXGBE_VF_BIT(vf->pool); 5073*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_index), vfte); 5074*48056c88SJack F Vogel } 5075*48056c88SJack F Vogel 5076*48056c88SJack F Vogel 5077*48056c88SJack F Vogel static void 5078*48056c88SJack F Vogel ixgbe_vf_enable_receive(struct adapter *adapter, struct ixgbe_vf *vf) 5079*48056c88SJack F Vogel { 5080*48056c88SJack F Vogel struct ixgbe_hw *hw; 5081*48056c88SJack F Vogel uint32_t vf_index, vfre; 5082*48056c88SJack F Vogel 5083*48056c88SJack F Vogel hw = &adapter->hw; 5084*48056c88SJack F Vogel 5085*48056c88SJack F Vogel vf_index = IXGBE_VF_INDEX(vf->pool); 5086*48056c88SJack F Vogel vfre = IXGBE_READ_REG(hw, IXGBE_VFRE(vf_index)); 5087*48056c88SJack F Vogel if (ixgbe_vf_frame_size_compatible(adapter, vf)) 5088*48056c88SJack F Vogel vfre |= IXGBE_VF_BIT(vf->pool); 5089*48056c88SJack F Vogel else 5090*48056c88SJack F Vogel vfre &= ~IXGBE_VF_BIT(vf->pool); 5091*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_index), vfre); 5092*48056c88SJack F Vogel } 5093*48056c88SJack F Vogel 5094*48056c88SJack F Vogel 5095*48056c88SJack F Vogel static void 5096*48056c88SJack F Vogel ixgbe_vf_reset_msg(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 5097*48056c88SJack F Vogel { 5098*48056c88SJack F Vogel struct ixgbe_hw *hw; 5099*48056c88SJack F Vogel uint32_t ack; 5100*48056c88SJack F Vogel uint32_t resp[IXGBE_VF_PERMADDR_MSG_LEN]; 5101*48056c88SJack F Vogel 5102*48056c88SJack F Vogel hw = &adapter->hw; 5103*48056c88SJack F Vogel 5104*48056c88SJack F Vogel ixgbe_process_vf_reset(adapter, vf); 5105*48056c88SJack F Vogel 5106*48056c88SJack F Vogel if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { 5107*48056c88SJack F Vogel ixgbe_set_rar(&adapter->hw, vf->rar_index, 5108*48056c88SJack F Vogel vf->ether_addr, vf->pool, TRUE); 5109*48056c88SJack F Vogel ack = IXGBE_VT_MSGTYPE_ACK; 5110*48056c88SJack F Vogel } else 5111*48056c88SJack F Vogel ack = IXGBE_VT_MSGTYPE_NACK; 5112*48056c88SJack F Vogel 5113*48056c88SJack F Vogel ixgbe_vf_enable_transmit(adapter, vf); 5114*48056c88SJack F Vogel ixgbe_vf_enable_receive(adapter, vf); 5115*48056c88SJack F Vogel 5116*48056c88SJack F Vogel vf->flags |= IXGBE_VF_CTS; 5117*48056c88SJack F Vogel 5118*48056c88SJack F Vogel resp[0] = IXGBE_VF_RESET | ack | IXGBE_VT_MSGTYPE_CTS; 5119*48056c88SJack F Vogel bcopy(vf->ether_addr, &resp[1], ETHER_ADDR_LEN); 5120*48056c88SJack F Vogel resp[3] = hw->mac.mc_filter_type; 5121*48056c88SJack F Vogel ixgbe_write_mbx(hw, resp, IXGBE_VF_PERMADDR_MSG_LEN, vf->pool); 5122*48056c88SJack F Vogel } 5123*48056c88SJack F Vogel 5124*48056c88SJack F Vogel 5125*48056c88SJack F Vogel static void 5126*48056c88SJack F Vogel ixgbe_vf_set_mac(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 5127*48056c88SJack F Vogel { 5128*48056c88SJack F Vogel uint8_t *mac; 5129*48056c88SJack F Vogel 5130*48056c88SJack F Vogel mac = (uint8_t*)&msg[1]; 5131*48056c88SJack F Vogel 5132*48056c88SJack F Vogel /* Check that the VF has permission to change the MAC address. */ 5133*48056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_CAP_MAC) && ixgbe_vf_mac_changed(vf, mac)) { 5134*48056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 5135*48056c88SJack F Vogel return; 5136*48056c88SJack F Vogel } 5137*48056c88SJack F Vogel 5138*48056c88SJack F Vogel if (ixgbe_validate_mac_addr(mac) != 0) { 5139*48056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 5140*48056c88SJack F Vogel return; 5141*48056c88SJack F Vogel } 5142*48056c88SJack F Vogel 5143*48056c88SJack F Vogel bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); 5144*48056c88SJack F Vogel 5145*48056c88SJack F Vogel ixgbe_set_rar(&adapter->hw, vf->rar_index, vf->ether_addr, 5146*48056c88SJack F Vogel vf->pool, TRUE); 5147*48056c88SJack F Vogel 5148*48056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 5149*48056c88SJack F Vogel } 5150*48056c88SJack F Vogel 5151*48056c88SJack F Vogel 5152*48056c88SJack F Vogel /* 5153*48056c88SJack F Vogel ** VF multicast addresses are set by using the appropriate bit in 5154*48056c88SJack F Vogel ** 1 of 128 32 bit addresses (4096 possible). 5155*48056c88SJack F Vogel */ 5156*48056c88SJack F Vogel static void 5157*48056c88SJack F Vogel ixgbe_vf_set_mc_addr(struct adapter *adapter, struct ixgbe_vf *vf, u32 *msg) 5158*48056c88SJack F Vogel { 5159*48056c88SJack F Vogel u16 *list = (u16*)&msg[1]; 5160*48056c88SJack F Vogel int entries; 5161*48056c88SJack F Vogel u32 vmolr, vec_bit, vec_reg, mta_reg; 5162*48056c88SJack F Vogel 5163*48056c88SJack F Vogel entries = (msg[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT; 5164*48056c88SJack F Vogel entries = min(entries, IXGBE_MAX_VF_MC); 5165*48056c88SJack F Vogel 5166*48056c88SJack F Vogel vmolr = IXGBE_READ_REG(&adapter->hw, IXGBE_VMOLR(vf->pool)); 5167*48056c88SJack F Vogel 5168*48056c88SJack F Vogel vf->num_mc_hashes = entries; 5169*48056c88SJack F Vogel 5170*48056c88SJack F Vogel /* Set the appropriate MTA bit */ 5171*48056c88SJack F Vogel for (int i = 0; i < entries; i++) { 5172*48056c88SJack F Vogel vf->mc_hash[i] = list[i]; 5173*48056c88SJack F Vogel vec_reg = (vf->mc_hash[i] >> 5) & 0x7F; 5174*48056c88SJack F Vogel vec_bit = vf->mc_hash[i] & 0x1F; 5175*48056c88SJack F Vogel mta_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_MTA(vec_reg)); 5176*48056c88SJack F Vogel mta_reg |= (1 << vec_bit); 5177*48056c88SJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_MTA(vec_reg), mta_reg); 5178*48056c88SJack F Vogel } 5179*48056c88SJack F Vogel 5180*48056c88SJack F Vogel vmolr |= IXGBE_VMOLR_ROMPE; 5181*48056c88SJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_VMOLR(vf->pool), vmolr); 5182*48056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 5183*48056c88SJack F Vogel return; 5184*48056c88SJack F Vogel } 5185*48056c88SJack F Vogel 5186*48056c88SJack F Vogel 5187*48056c88SJack F Vogel static void 5188*48056c88SJack F Vogel ixgbe_vf_set_vlan(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 5189*48056c88SJack F Vogel { 5190*48056c88SJack F Vogel struct ixgbe_hw *hw; 5191*48056c88SJack F Vogel int enable; 5192*48056c88SJack F Vogel uint16_t tag; 5193*48056c88SJack F Vogel 5194*48056c88SJack F Vogel hw = &adapter->hw; 5195*48056c88SJack F Vogel enable = IXGBE_VT_MSGINFO(msg[0]); 5196*48056c88SJack F Vogel tag = msg[1] & IXGBE_VLVF_VLANID_MASK; 5197*48056c88SJack F Vogel 5198*48056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_CAP_VLAN)) { 5199*48056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 5200*48056c88SJack F Vogel return; 5201*48056c88SJack F Vogel } 5202*48056c88SJack F Vogel 5203*48056c88SJack F Vogel /* It is illegal to enable vlan tag 0. */ 5204*48056c88SJack F Vogel if (tag == 0 && enable != 0){ 5205*48056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 5206*48056c88SJack F Vogel return; 5207*48056c88SJack F Vogel } 5208*48056c88SJack F Vogel 5209*48056c88SJack F Vogel ixgbe_set_vfta(hw, tag, vf->pool, enable); 5210*48056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 5211*48056c88SJack F Vogel } 5212*48056c88SJack F Vogel 5213*48056c88SJack F Vogel 5214*48056c88SJack F Vogel static void 5215*48056c88SJack F Vogel ixgbe_vf_set_lpe(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 5216*48056c88SJack F Vogel { 5217*48056c88SJack F Vogel struct ixgbe_hw *hw; 5218*48056c88SJack F Vogel uint32_t vf_max_size, pf_max_size, mhadd; 5219*48056c88SJack F Vogel 5220*48056c88SJack F Vogel hw = &adapter->hw; 5221*48056c88SJack F Vogel vf_max_size = msg[1]; 5222*48056c88SJack F Vogel 5223*48056c88SJack F Vogel if (vf_max_size < ETHER_CRC_LEN) { 5224*48056c88SJack F Vogel /* We intentionally ACK invalid LPE requests. */ 5225*48056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 5226*48056c88SJack F Vogel return; 5227*48056c88SJack F Vogel } 5228*48056c88SJack F Vogel 5229*48056c88SJack F Vogel vf_max_size -= ETHER_CRC_LEN; 5230*48056c88SJack F Vogel 5231*48056c88SJack F Vogel if (vf_max_size > IXGBE_MAX_FRAME_SIZE) { 5232*48056c88SJack F Vogel /* We intentionally ACK invalid LPE requests. */ 5233*48056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 5234*48056c88SJack F Vogel return; 5235*48056c88SJack F Vogel } 5236*48056c88SJack F Vogel 5237*48056c88SJack F Vogel vf->max_frame_size = vf_max_size; 5238*48056c88SJack F Vogel ixgbe_update_max_frame(adapter, vf->max_frame_size); 5239*48056c88SJack F Vogel 5240*48056c88SJack F Vogel /* 5241*48056c88SJack F Vogel * We might have to disable reception to this VF if the frame size is 5242*48056c88SJack F Vogel * not compatible with the config on the PF. 5243*48056c88SJack F Vogel */ 5244*48056c88SJack F Vogel ixgbe_vf_enable_receive(adapter, vf); 5245*48056c88SJack F Vogel 5246*48056c88SJack F Vogel mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); 5247*48056c88SJack F Vogel pf_max_size = (mhadd & IXGBE_MHADD_MFS_MASK) >> IXGBE_MHADD_MFS_SHIFT; 5248*48056c88SJack F Vogel 5249*48056c88SJack F Vogel if (pf_max_size < adapter->max_frame_size) { 5250*48056c88SJack F Vogel mhadd &= ~IXGBE_MHADD_MFS_MASK; 5251*48056c88SJack F Vogel mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; 5252*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); 5253*48056c88SJack F Vogel } 5254*48056c88SJack F Vogel 5255*48056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 5256*48056c88SJack F Vogel } 5257*48056c88SJack F Vogel 5258*48056c88SJack F Vogel 5259*48056c88SJack F Vogel static void 5260*48056c88SJack F Vogel ixgbe_vf_set_macvlan(struct adapter *adapter, struct ixgbe_vf *vf, 5261*48056c88SJack F Vogel uint32_t *msg) 5262*48056c88SJack F Vogel { 5263*48056c88SJack F Vogel //XXX implement this 5264*48056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 5265*48056c88SJack F Vogel } 5266*48056c88SJack F Vogel 5267*48056c88SJack F Vogel 5268*48056c88SJack F Vogel static void 5269*48056c88SJack F Vogel ixgbe_vf_api_negotiate(struct adapter *adapter, struct ixgbe_vf *vf, 5270*48056c88SJack F Vogel uint32_t *msg) 5271*48056c88SJack F Vogel { 5272*48056c88SJack F Vogel 5273*48056c88SJack F Vogel switch (msg[0]) { 5274*48056c88SJack F Vogel case IXGBE_API_VER_1_0: 5275*48056c88SJack F Vogel case IXGBE_API_VER_1_1: 5276*48056c88SJack F Vogel vf->api_ver = msg[0]; 5277*48056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 5278*48056c88SJack F Vogel break; 5279*48056c88SJack F Vogel default: 5280*48056c88SJack F Vogel vf->api_ver = IXGBE_API_VER_UNKNOWN; 5281*48056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 5282*48056c88SJack F Vogel break; 5283*48056c88SJack F Vogel } 5284*48056c88SJack F Vogel } 5285*48056c88SJack F Vogel 5286*48056c88SJack F Vogel 5287*48056c88SJack F Vogel static void 5288*48056c88SJack F Vogel ixgbe_vf_get_queues(struct adapter *adapter, struct ixgbe_vf *vf, 5289*48056c88SJack F Vogel uint32_t *msg) 5290*48056c88SJack F Vogel { 5291*48056c88SJack F Vogel struct ixgbe_hw *hw; 5292*48056c88SJack F Vogel uint32_t resp[IXGBE_VF_GET_QUEUES_RESP_LEN]; 5293*48056c88SJack F Vogel int num_queues; 5294*48056c88SJack F Vogel 5295*48056c88SJack F Vogel hw = &adapter->hw; 5296*48056c88SJack F Vogel 5297*48056c88SJack F Vogel /* GET_QUEUES is not supported on pre-1.1 APIs. */ 5298*48056c88SJack F Vogel switch (msg[0]) { 5299*48056c88SJack F Vogel case IXGBE_API_VER_1_0: 5300*48056c88SJack F Vogel case IXGBE_API_VER_UNKNOWN: 5301*48056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 5302*48056c88SJack F Vogel return; 5303*48056c88SJack F Vogel } 5304*48056c88SJack F Vogel 5305*48056c88SJack F Vogel resp[0] = IXGBE_VF_GET_QUEUES | IXGBE_VT_MSGTYPE_ACK | 5306*48056c88SJack F Vogel IXGBE_VT_MSGTYPE_CTS; 5307*48056c88SJack F Vogel 5308*48056c88SJack F Vogel num_queues = ixgbe_vf_queues(ixgbe_get_iov_mode(adapter)); 5309*48056c88SJack F Vogel resp[IXGBE_VF_TX_QUEUES] = num_queues; 5310*48056c88SJack F Vogel resp[IXGBE_VF_RX_QUEUES] = num_queues; 5311*48056c88SJack F Vogel resp[IXGBE_VF_TRANS_VLAN] = (vf->default_vlan != 0); 5312*48056c88SJack F Vogel resp[IXGBE_VF_DEF_QUEUE] = 0; 5313*48056c88SJack F Vogel 5314*48056c88SJack F Vogel ixgbe_write_mbx(hw, resp, IXGBE_VF_GET_QUEUES_RESP_LEN, vf->pool); 5315*48056c88SJack F Vogel } 5316*48056c88SJack F Vogel 5317*48056c88SJack F Vogel 5318*48056c88SJack F Vogel static void 5319*48056c88SJack F Vogel ixgbe_process_vf_msg(struct adapter *adapter, struct ixgbe_vf *vf) 5320*48056c88SJack F Vogel { 5321*48056c88SJack F Vogel struct ixgbe_hw *hw; 5322*48056c88SJack F Vogel uint32_t msg[IXGBE_VFMAILBOX_SIZE]; 5323*48056c88SJack F Vogel int error; 5324*48056c88SJack F Vogel 5325*48056c88SJack F Vogel hw = &adapter->hw; 5326*48056c88SJack F Vogel 5327*48056c88SJack F Vogel error = ixgbe_read_mbx(hw, msg, IXGBE_VFMAILBOX_SIZE, vf->pool); 5328*48056c88SJack F Vogel 5329*48056c88SJack F Vogel if (error != 0) 5330*48056c88SJack F Vogel return; 5331*48056c88SJack F Vogel 5332*48056c88SJack F Vogel CTR3(KTR_MALLOC, "%s: received msg %x from %d", 5333*48056c88SJack F Vogel adapter->ifp->if_xname, msg[0], vf->pool); 5334*48056c88SJack F Vogel if (msg[0] == IXGBE_VF_RESET) { 5335*48056c88SJack F Vogel ixgbe_vf_reset_msg(adapter, vf, msg); 5336*48056c88SJack F Vogel return; 5337*48056c88SJack F Vogel } 5338*48056c88SJack F Vogel 5339*48056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_CTS)) { 5340*48056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 5341*48056c88SJack F Vogel return; 5342*48056c88SJack F Vogel } 5343*48056c88SJack F Vogel 5344*48056c88SJack F Vogel switch (msg[0] & IXGBE_VT_MSG_MASK) { 5345*48056c88SJack F Vogel case IXGBE_VF_SET_MAC_ADDR: 5346*48056c88SJack F Vogel ixgbe_vf_set_mac(adapter, vf, msg); 5347*48056c88SJack F Vogel break; 5348*48056c88SJack F Vogel case IXGBE_VF_SET_MULTICAST: 5349*48056c88SJack F Vogel ixgbe_vf_set_mc_addr(adapter, vf, msg); 5350*48056c88SJack F Vogel break; 5351*48056c88SJack F Vogel case IXGBE_VF_SET_VLAN: 5352*48056c88SJack F Vogel ixgbe_vf_set_vlan(adapter, vf, msg); 5353*48056c88SJack F Vogel break; 5354*48056c88SJack F Vogel case IXGBE_VF_SET_LPE: 5355*48056c88SJack F Vogel ixgbe_vf_set_lpe(adapter, vf, msg); 5356*48056c88SJack F Vogel break; 5357*48056c88SJack F Vogel case IXGBE_VF_SET_MACVLAN: 5358*48056c88SJack F Vogel ixgbe_vf_set_macvlan(adapter, vf, msg); 5359*48056c88SJack F Vogel break; 5360*48056c88SJack F Vogel case IXGBE_VF_API_NEGOTIATE: 5361*48056c88SJack F Vogel ixgbe_vf_api_negotiate(adapter, vf, msg); 5362*48056c88SJack F Vogel break; 5363*48056c88SJack F Vogel case IXGBE_VF_GET_QUEUES: 5364*48056c88SJack F Vogel ixgbe_vf_get_queues(adapter, vf, msg); 5365*48056c88SJack F Vogel break; 5366*48056c88SJack F Vogel default: 5367*48056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 5368*48056c88SJack F Vogel } 5369*48056c88SJack F Vogel } 5370*48056c88SJack F Vogel 5371*48056c88SJack F Vogel 5372*48056c88SJack F Vogel /* 5373*48056c88SJack F Vogel * Tasklet for handling VF -> PF mailbox messages. 5374*48056c88SJack F Vogel */ 5375*48056c88SJack F Vogel static void 5376*48056c88SJack F Vogel ixgbe_handle_mbx(void *context, int pending) 5377*48056c88SJack F Vogel { 5378*48056c88SJack F Vogel struct adapter *adapter; 5379*48056c88SJack F Vogel struct ixgbe_hw *hw; 5380*48056c88SJack F Vogel struct ixgbe_vf *vf; 5381*48056c88SJack F Vogel int i; 5382*48056c88SJack F Vogel 5383*48056c88SJack F Vogel adapter = context; 5384*48056c88SJack F Vogel hw = &adapter->hw; 5385*48056c88SJack F Vogel 5386*48056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 5387*48056c88SJack F Vogel for (i = 0; i < adapter->num_vfs; i++) { 5388*48056c88SJack F Vogel vf = &adapter->vfs[i]; 5389*48056c88SJack F Vogel 5390*48056c88SJack F Vogel if (vf->flags & IXGBE_VF_ACTIVE) { 5391*48056c88SJack F Vogel if (ixgbe_check_for_rst(hw, vf->pool) == 0) 5392*48056c88SJack F Vogel ixgbe_process_vf_reset(adapter, vf); 5393*48056c88SJack F Vogel 5394*48056c88SJack F Vogel if (ixgbe_check_for_msg(hw, vf->pool) == 0) 5395*48056c88SJack F Vogel ixgbe_process_vf_msg(adapter, vf); 5396*48056c88SJack F Vogel 5397*48056c88SJack F Vogel if (ixgbe_check_for_ack(hw, vf->pool) == 0) 5398*48056c88SJack F Vogel ixgbe_process_vf_ack(adapter, vf); 5399*48056c88SJack F Vogel } 5400*48056c88SJack F Vogel } 5401*48056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 5402*48056c88SJack F Vogel } 5403*48056c88SJack F Vogel 5404*48056c88SJack F Vogel 5405*48056c88SJack F Vogel static int 5406*48056c88SJack F Vogel ixgbe_init_iov(device_t dev, u16 num_vfs, const nvlist_t *config) 5407*48056c88SJack F Vogel { 5408*48056c88SJack F Vogel struct adapter *adapter; 5409*48056c88SJack F Vogel enum ixgbe_iov_mode mode; 5410*48056c88SJack F Vogel 5411*48056c88SJack F Vogel adapter = device_get_softc(dev); 5412*48056c88SJack F Vogel adapter->num_vfs = num_vfs; 5413*48056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 5414*48056c88SJack F Vogel 5415*48056c88SJack F Vogel if (num_vfs > ixgbe_max_vfs(mode)) { 5416*48056c88SJack F Vogel adapter->num_vfs = 0; 5417*48056c88SJack F Vogel return (ENOSPC); 5418*48056c88SJack F Vogel } 5419*48056c88SJack F Vogel 5420*48056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 5421*48056c88SJack F Vogel 5422*48056c88SJack F Vogel adapter->vfs = malloc(sizeof(*adapter->vfs) * num_vfs, M_IXGBE, 5423*48056c88SJack F Vogel M_NOWAIT | M_ZERO); 5424*48056c88SJack F Vogel 5425*48056c88SJack F Vogel if (adapter->vfs == NULL) { 5426*48056c88SJack F Vogel adapter->num_vfs = 0; 5427*48056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 5428*48056c88SJack F Vogel return (ENOMEM); 5429*48056c88SJack F Vogel } 5430*48056c88SJack F Vogel 5431*48056c88SJack F Vogel ixgbe_init_locked(adapter); 5432*48056c88SJack F Vogel 5433*48056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 5434*48056c88SJack F Vogel 5435*48056c88SJack F Vogel return (0); 5436*48056c88SJack F Vogel } 5437*48056c88SJack F Vogel 5438*48056c88SJack F Vogel 5439*48056c88SJack F Vogel static void 5440*48056c88SJack F Vogel ixgbe_uninit_iov(device_t dev) 5441*48056c88SJack F Vogel { 5442*48056c88SJack F Vogel struct ixgbe_hw *hw; 5443*48056c88SJack F Vogel struct adapter *adapter; 5444*48056c88SJack F Vogel uint32_t pf_reg, vf_reg; 5445*48056c88SJack F Vogel 5446*48056c88SJack F Vogel adapter = device_get_softc(dev); 5447*48056c88SJack F Vogel hw = &adapter->hw; 5448*48056c88SJack F Vogel 5449*48056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 5450*48056c88SJack F Vogel 5451*48056c88SJack F Vogel /* Enable rx/tx for the PF and disable it for all VFs. */ 5452*48056c88SJack F Vogel pf_reg = IXGBE_VF_INDEX(adapter->pool); 5453*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(pf_reg), 5454*48056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 5455*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(pf_reg), 5456*48056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 5457*48056c88SJack F Vogel 5458*48056c88SJack F Vogel if (pf_reg == 0) 5459*48056c88SJack F Vogel vf_reg = 1; 5460*48056c88SJack F Vogel else 5461*48056c88SJack F Vogel vf_reg = 0; 5462*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 0); 5463*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 0); 5464*48056c88SJack F Vogel 5465*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, 0); 5466*48056c88SJack F Vogel 5467*48056c88SJack F Vogel free(adapter->vfs, M_IXGBE); 5468*48056c88SJack F Vogel adapter->vfs = NULL; 5469*48056c88SJack F Vogel adapter->num_vfs = 0; 5470*48056c88SJack F Vogel 5471*48056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 5472*48056c88SJack F Vogel } 5473*48056c88SJack F Vogel 5474*48056c88SJack F Vogel 5475*48056c88SJack F Vogel static void 5476*48056c88SJack F Vogel ixgbe_initialize_iov(struct adapter *adapter) 5477*48056c88SJack F Vogel { 5478*48056c88SJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 5479*48056c88SJack F Vogel uint32_t mrqc, mtqc, vt_ctl, vf_reg, gcr_ext, gpie; 5480*48056c88SJack F Vogel enum ixgbe_iov_mode mode; 5481*48056c88SJack F Vogel int i; 5482*48056c88SJack F Vogel 5483*48056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 5484*48056c88SJack F Vogel if (mode == IXGBE_NO_VM) 5485*48056c88SJack F Vogel return; 5486*48056c88SJack F Vogel 5487*48056c88SJack F Vogel IXGBE_CORE_LOCK_ASSERT(adapter); 5488*48056c88SJack F Vogel 5489*48056c88SJack F Vogel mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC); 5490*48056c88SJack F Vogel mrqc &= ~IXGBE_MRQC_MRQE_MASK; 5491*48056c88SJack F Vogel 5492*48056c88SJack F Vogel switch (mode) { 5493*48056c88SJack F Vogel case IXGBE_64_VM: 5494*48056c88SJack F Vogel mrqc |= IXGBE_MRQC_VMDQRSS64EN; 5495*48056c88SJack F Vogel break; 5496*48056c88SJack F Vogel case IXGBE_32_VM: 5497*48056c88SJack F Vogel mrqc |= IXGBE_MRQC_VMDQRSS32EN; 5498*48056c88SJack F Vogel break; 5499*48056c88SJack F Vogel default: 5500*48056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 5501*48056c88SJack F Vogel } 5502*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 5503*48056c88SJack F Vogel 5504*48056c88SJack F Vogel mtqc = IXGBE_MTQC_VT_ENA; 5505*48056c88SJack F Vogel switch (mode) { 5506*48056c88SJack F Vogel case IXGBE_64_VM: 5507*48056c88SJack F Vogel mtqc |= IXGBE_MTQC_64VF; 5508*48056c88SJack F Vogel break; 5509*48056c88SJack F Vogel case IXGBE_32_VM: 5510*48056c88SJack F Vogel mtqc |= IXGBE_MTQC_32VF; 5511*48056c88SJack F Vogel break; 5512*48056c88SJack F Vogel default: 5513*48056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 5514*48056c88SJack F Vogel } 5515*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MTQC, mtqc); 5516*48056c88SJack F Vogel 5517*48056c88SJack F Vogel 5518*48056c88SJack F Vogel gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT); 5519*48056c88SJack F Vogel gcr_ext |= IXGBE_GCR_EXT_MSIX_EN; 5520*48056c88SJack F Vogel gcr_ext &= ~IXGBE_GCR_EXT_VT_MODE_MASK; 5521*48056c88SJack F Vogel switch (mode) { 5522*48056c88SJack F Vogel case IXGBE_64_VM: 5523*48056c88SJack F Vogel gcr_ext |= IXGBE_GCR_EXT_VT_MODE_64; 5524*48056c88SJack F Vogel break; 5525*48056c88SJack F Vogel case IXGBE_32_VM: 5526*48056c88SJack F Vogel gcr_ext |= IXGBE_GCR_EXT_VT_MODE_32; 5527*48056c88SJack F Vogel break; 5528*48056c88SJack F Vogel default: 5529*48056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 5530*48056c88SJack F Vogel } 5531*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext); 5532*48056c88SJack F Vogel 5533*48056c88SJack F Vogel 5534*48056c88SJack F Vogel gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); 5535*48056c88SJack F Vogel gcr_ext &= ~IXGBE_GPIE_VTMODE_MASK; 5536*48056c88SJack F Vogel switch (mode) { 5537*48056c88SJack F Vogel case IXGBE_64_VM: 5538*48056c88SJack F Vogel gpie |= IXGBE_GPIE_VTMODE_64; 5539*48056c88SJack F Vogel break; 5540*48056c88SJack F Vogel case IXGBE_32_VM: 5541*48056c88SJack F Vogel gpie |= IXGBE_GPIE_VTMODE_32; 5542*48056c88SJack F Vogel break; 5543*48056c88SJack F Vogel default: 5544*48056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 5545*48056c88SJack F Vogel } 5546*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 5547*48056c88SJack F Vogel 5548*48056c88SJack F Vogel /* Enable rx/tx for the PF. */ 5549*48056c88SJack F Vogel vf_reg = IXGBE_VF_INDEX(adapter->pool); 5550*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 5551*48056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 5552*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 5553*48056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 5554*48056c88SJack F Vogel 5555*48056c88SJack F Vogel /* Allow VM-to-VM communication. */ 5556*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN); 5557*48056c88SJack F Vogel 5558*48056c88SJack F Vogel vt_ctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; 5559*48056c88SJack F Vogel vt_ctl |= (adapter->pool << IXGBE_VT_CTL_POOL_SHIFT); 5560*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vt_ctl); 5561*48056c88SJack F Vogel 5562*48056c88SJack F Vogel for (i = 0; i < adapter->num_vfs; i++) 5563*48056c88SJack F Vogel ixgbe_init_vf(adapter, &adapter->vfs[i]); 5564*48056c88SJack F Vogel } 5565*48056c88SJack F Vogel 5566*48056c88SJack F Vogel 5567*48056c88SJack F Vogel /* 5568*48056c88SJack F Vogel ** Check the max frame setting of all active VF's 5569*48056c88SJack F Vogel */ 5570*48056c88SJack F Vogel static void 5571*48056c88SJack F Vogel ixgbe_recalculate_max_frame(struct adapter *adapter) 5572*48056c88SJack F Vogel { 5573*48056c88SJack F Vogel struct ixgbe_vf *vf; 5574*48056c88SJack F Vogel 5575*48056c88SJack F Vogel IXGBE_CORE_LOCK_ASSERT(adapter); 5576*48056c88SJack F Vogel 5577*48056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 5578*48056c88SJack F Vogel vf = &adapter->vfs[i]; 5579*48056c88SJack F Vogel if (vf->flags & IXGBE_VF_ACTIVE) 5580*48056c88SJack F Vogel ixgbe_update_max_frame(adapter, vf->max_frame_size); 5581*48056c88SJack F Vogel } 5582*48056c88SJack F Vogel } 5583*48056c88SJack F Vogel 5584*48056c88SJack F Vogel 5585*48056c88SJack F Vogel static void 5586*48056c88SJack F Vogel ixgbe_init_vf(struct adapter *adapter, struct ixgbe_vf *vf) 5587*48056c88SJack F Vogel { 5588*48056c88SJack F Vogel struct ixgbe_hw *hw; 5589*48056c88SJack F Vogel uint32_t vf_index, pfmbimr; 5590*48056c88SJack F Vogel 5591*48056c88SJack F Vogel IXGBE_CORE_LOCK_ASSERT(adapter); 5592*48056c88SJack F Vogel 5593*48056c88SJack F Vogel hw = &adapter->hw; 5594*48056c88SJack F Vogel 5595*48056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_ACTIVE)) 5596*48056c88SJack F Vogel return; 5597*48056c88SJack F Vogel 5598*48056c88SJack F Vogel vf_index = IXGBE_VF_INDEX(vf->pool); 5599*48056c88SJack F Vogel pfmbimr = IXGBE_READ_REG(hw, IXGBE_PFMBIMR(vf_index)); 5600*48056c88SJack F Vogel pfmbimr |= IXGBE_VF_BIT(vf->pool); 5601*48056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr); 5602*48056c88SJack F Vogel 5603*48056c88SJack F Vogel ixgbe_vf_set_default_vlan(adapter, vf, vf->vlan_tag); 5604*48056c88SJack F Vogel 5605*48056c88SJack F Vogel // XXX multicast addresses 5606*48056c88SJack F Vogel 5607*48056c88SJack F Vogel if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { 5608*48056c88SJack F Vogel ixgbe_set_rar(&adapter->hw, vf->rar_index, 5609*48056c88SJack F Vogel vf->ether_addr, vf->pool, TRUE); 5610*48056c88SJack F Vogel } 5611*48056c88SJack F Vogel 5612*48056c88SJack F Vogel ixgbe_vf_enable_transmit(adapter, vf); 5613*48056c88SJack F Vogel ixgbe_vf_enable_receive(adapter, vf); 5614*48056c88SJack F Vogel 5615*48056c88SJack F Vogel ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); 5616*48056c88SJack F Vogel } 5617*48056c88SJack F Vogel 5618*48056c88SJack F Vogel static int 5619*48056c88SJack F Vogel ixgbe_add_vf(device_t dev, u16 vfnum, const nvlist_t *config) 5620*48056c88SJack F Vogel { 5621*48056c88SJack F Vogel struct adapter *adapter; 5622*48056c88SJack F Vogel struct ixgbe_vf *vf; 5623*48056c88SJack F Vogel const void *mac; 5624*48056c88SJack F Vogel 5625*48056c88SJack F Vogel adapter = device_get_softc(dev); 5626*48056c88SJack F Vogel 5627*48056c88SJack F Vogel KASSERT(vfnum < adapter->num_vfs, ("VF index %d is out of range %d", 5628*48056c88SJack F Vogel vfnum, adapter->num_vfs)); 5629*48056c88SJack F Vogel 5630*48056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 5631*48056c88SJack F Vogel vf = &adapter->vfs[vfnum]; 5632*48056c88SJack F Vogel vf->pool= vfnum; 5633*48056c88SJack F Vogel 5634*48056c88SJack F Vogel /* RAR[0] is used by the PF so use vfnum + 1 for VF RAR. */ 5635*48056c88SJack F Vogel vf->rar_index = vfnum + 1; 5636*48056c88SJack F Vogel vf->default_vlan = 0; 5637*48056c88SJack F Vogel vf->max_frame_size = ETHER_MAX_LEN; 5638*48056c88SJack F Vogel ixgbe_update_max_frame(adapter, vf->max_frame_size); 5639*48056c88SJack F Vogel 5640*48056c88SJack F Vogel if (nvlist_exists_binary(config, "mac-addr")) { 5641*48056c88SJack F Vogel mac = nvlist_get_binary(config, "mac-addr", NULL); 5642*48056c88SJack F Vogel bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); 5643*48056c88SJack F Vogel if (nvlist_get_bool(config, "allow-set-mac")) 5644*48056c88SJack F Vogel vf->flags |= IXGBE_VF_CAP_MAC; 5645*48056c88SJack F Vogel } else 5646*48056c88SJack F Vogel /* 5647*48056c88SJack F Vogel * If the administrator has not specified a MAC address then 5648*48056c88SJack F Vogel * we must allow the VF to choose one. 5649*48056c88SJack F Vogel */ 5650*48056c88SJack F Vogel vf->flags |= IXGBE_VF_CAP_MAC; 5651*48056c88SJack F Vogel 5652*48056c88SJack F Vogel vf->flags = IXGBE_VF_ACTIVE; 5653*48056c88SJack F Vogel 5654*48056c88SJack F Vogel ixgbe_init_vf(adapter, vf); 5655*48056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 5656*48056c88SJack F Vogel 5657*48056c88SJack F Vogel return (0); 5658*48056c88SJack F Vogel } 5659*48056c88SJack F Vogel #endif /* PCI_IOV */ 5660758cc3dcSJack F Vogel 5661