1758cc3dcSJack F Vogel /****************************************************************************** 2758cc3dcSJack F Vogel 3758cc3dcSJack F Vogel Copyright (c) 2001-2015, Intel Corporation 4758cc3dcSJack F Vogel All rights reserved. 5758cc3dcSJack F Vogel 6758cc3dcSJack F Vogel Redistribution and use in source and binary forms, with or without 7758cc3dcSJack F Vogel modification, are permitted provided that the following conditions are met: 8758cc3dcSJack F Vogel 9758cc3dcSJack F Vogel 1. Redistributions of source code must retain the above copyright notice, 10758cc3dcSJack F Vogel this list of conditions and the following disclaimer. 11758cc3dcSJack F Vogel 12758cc3dcSJack F Vogel 2. Redistributions in binary form must reproduce the above copyright 13758cc3dcSJack F Vogel notice, this list of conditions and the following disclaimer in the 14758cc3dcSJack F Vogel documentation and/or other materials provided with the distribution. 15758cc3dcSJack F Vogel 16758cc3dcSJack F Vogel 3. Neither the name of the Intel Corporation nor the names of its 17758cc3dcSJack F Vogel contributors may be used to endorse or promote products derived from 18758cc3dcSJack F Vogel this software without specific prior written permission. 19758cc3dcSJack F Vogel 20758cc3dcSJack F Vogel THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21758cc3dcSJack F Vogel AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22758cc3dcSJack F Vogel IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23758cc3dcSJack F Vogel ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24758cc3dcSJack F Vogel LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25758cc3dcSJack F Vogel CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26758cc3dcSJack F Vogel SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27758cc3dcSJack F Vogel INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28758cc3dcSJack F Vogel CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29758cc3dcSJack F Vogel ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30758cc3dcSJack F Vogel POSSIBILITY OF SUCH DAMAGE. 31758cc3dcSJack F Vogel 32758cc3dcSJack F Vogel ******************************************************************************/ 33758cc3dcSJack F Vogel /*$FreeBSD$*/ 34758cc3dcSJack F Vogel 35758cc3dcSJack F Vogel 36758cc3dcSJack F Vogel #ifndef IXGBE_STANDALONE_BUILD 37758cc3dcSJack F Vogel #include "opt_inet.h" 38758cc3dcSJack F Vogel #include "opt_inet6.h" 39758cc3dcSJack F Vogel #include "opt_rss.h" 40758cc3dcSJack F Vogel #endif 41758cc3dcSJack F Vogel 42758cc3dcSJack F Vogel #include "ixgbe.h" 43758cc3dcSJack F Vogel 44758cc3dcSJack F Vogel #ifdef RSS 45a1edda90SAdrian Chadd #include <net/rss_config.h> 46758cc3dcSJack F Vogel #include <netinet/in_rss.h> 47758cc3dcSJack F Vogel #endif 48758cc3dcSJack F Vogel 49758cc3dcSJack F Vogel /********************************************************************* 50758cc3dcSJack F Vogel * Driver version 51758cc3dcSJack F Vogel *********************************************************************/ 52a9ca1c79SSean Bruno char ixgbe_driver_version[] = "3.1.13-k"; 53a9ca1c79SSean Bruno 54758cc3dcSJack F Vogel 55758cc3dcSJack F Vogel /********************************************************************* 56758cc3dcSJack F Vogel * PCI Device ID Table 57758cc3dcSJack F Vogel * 58758cc3dcSJack F Vogel * Used by probe to select devices to load on 59758cc3dcSJack F Vogel * Last field stores an index into ixgbe_strings 60758cc3dcSJack F Vogel * Last entry must be all 0s 61758cc3dcSJack F Vogel * 62758cc3dcSJack F Vogel * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 63758cc3dcSJack F Vogel *********************************************************************/ 64758cc3dcSJack F Vogel 65758cc3dcSJack F Vogel static ixgbe_vendor_info_t ixgbe_vendor_info_array[] = 66758cc3dcSJack F Vogel { 67758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT, 0, 0, 0}, 68758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT, 0, 0, 0}, 69758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4, 0, 0, 0}, 70758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT, 0, 0, 0}, 71758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT2, 0, 0, 0}, 72758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598, 0, 0, 0}, 73758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_DA_DUAL_PORT, 0, 0, 0}, 74758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_CX4_DUAL_PORT, 0, 0, 0}, 75758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_XF_LR, 0, 0, 0}, 76758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM, 0, 0, 0}, 77758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_SFP_LOM, 0, 0, 0}, 78758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4, 0, 0, 0}, 79758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4_MEZZ, 0, 0, 0}, 80758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP, 0, 0, 0}, 81758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_XAUI_LOM, 0, 0, 0}, 82758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_CX4, 0, 0, 0}, 83758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_T3_LOM, 0, 0, 0}, 84758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_COMBO_BACKPLANE, 0, 0, 0}, 85758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BACKPLANE_FCOE, 0, 0, 0}, 86758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF2, 0, 0, 0}, 87758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_FCOE, 0, 0, 0}, 88758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599EN_SFP, 0, 0, 0}, 89758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF_QP, 0, 0, 0}, 90758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_QSFP_SF_QP, 0, 0, 0}, 91758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T, 0, 0, 0}, 92758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T1, 0, 0, 0}, 93758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T, 0, 0, 0}, 94a9ca1c79SSean Bruno {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T1, 0, 0, 0}, 95758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KR, 0, 0, 0}, 96758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KX4, 0, 0, 0}, 97758cc3dcSJack F Vogel {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_10G_T, 0, 0, 0}, 98a9ca1c79SSean Bruno {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_SFP, 0, 0, 0}, 99758cc3dcSJack F Vogel /* required last entry */ 100758cc3dcSJack F Vogel {0, 0, 0, 0, 0} 101758cc3dcSJack F Vogel }; 102758cc3dcSJack F Vogel 103758cc3dcSJack F Vogel /********************************************************************* 104758cc3dcSJack F Vogel * Table of branding strings 105758cc3dcSJack F Vogel *********************************************************************/ 106758cc3dcSJack F Vogel 107758cc3dcSJack F Vogel static char *ixgbe_strings[] = { 108758cc3dcSJack F Vogel "Intel(R) PRO/10GbE PCI-Express Network Driver" 109758cc3dcSJack F Vogel }; 110758cc3dcSJack F Vogel 111758cc3dcSJack F Vogel /********************************************************************* 112758cc3dcSJack F Vogel * Function prototypes 113758cc3dcSJack F Vogel *********************************************************************/ 114758cc3dcSJack F Vogel static int ixgbe_probe(device_t); 115758cc3dcSJack F Vogel static int ixgbe_attach(device_t); 116758cc3dcSJack F Vogel static int ixgbe_detach(device_t); 117758cc3dcSJack F Vogel static int ixgbe_shutdown(device_t); 1186f37f232SEric Joyner static int ixgbe_suspend(device_t); 1196f37f232SEric Joyner static int ixgbe_resume(device_t); 120758cc3dcSJack F Vogel static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t); 121758cc3dcSJack F Vogel static void ixgbe_init(void *); 122758cc3dcSJack F Vogel static void ixgbe_init_locked(struct adapter *); 123758cc3dcSJack F Vogel static void ixgbe_stop(void *); 124758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 125758cc3dcSJack F Vogel static uint64_t ixgbe_get_counter(struct ifnet *, ift_counter); 126758cc3dcSJack F Vogel #endif 127758cc3dcSJack F Vogel static void ixgbe_add_media_types(struct adapter *); 128758cc3dcSJack F Vogel static void ixgbe_media_status(struct ifnet *, struct ifmediareq *); 129758cc3dcSJack F Vogel static int ixgbe_media_change(struct ifnet *); 130758cc3dcSJack F Vogel static void ixgbe_identify_hardware(struct adapter *); 131758cc3dcSJack F Vogel static int ixgbe_allocate_pci_resources(struct adapter *); 132a9ca1c79SSean Bruno static void ixgbe_get_slot_info(struct adapter *); 133758cc3dcSJack F Vogel static int ixgbe_allocate_msix(struct adapter *); 134758cc3dcSJack F Vogel static int ixgbe_allocate_legacy(struct adapter *); 135758cc3dcSJack F Vogel static int ixgbe_setup_msix(struct adapter *); 136758cc3dcSJack F Vogel static void ixgbe_free_pci_resources(struct adapter *); 137758cc3dcSJack F Vogel static void ixgbe_local_timer(void *); 138758cc3dcSJack F Vogel static int ixgbe_setup_interface(device_t, struct adapter *); 13948056c88SJack F Vogel static void ixgbe_config_gpie(struct adapter *); 1406f37f232SEric Joyner static void ixgbe_config_dmac(struct adapter *); 1416f37f232SEric Joyner static void ixgbe_config_delay_values(struct adapter *); 142758cc3dcSJack F Vogel static void ixgbe_config_link(struct adapter *); 1436f37f232SEric Joyner static void ixgbe_check_wol_support(struct adapter *); 1446f37f232SEric Joyner static int ixgbe_setup_low_power_mode(struct adapter *); 145758cc3dcSJack F Vogel static void ixgbe_rearm_queues(struct adapter *, u64); 146758cc3dcSJack F Vogel 147758cc3dcSJack F Vogel static void ixgbe_initialize_transmit_units(struct adapter *); 148758cc3dcSJack F Vogel static void ixgbe_initialize_receive_units(struct adapter *); 149758cc3dcSJack F Vogel static void ixgbe_enable_rx_drop(struct adapter *); 150758cc3dcSJack F Vogel static void ixgbe_disable_rx_drop(struct adapter *); 151a9ca1c79SSean Bruno static void ixgbe_initialize_rss_mapping(struct adapter *); 152758cc3dcSJack F Vogel 153758cc3dcSJack F Vogel static void ixgbe_enable_intr(struct adapter *); 154758cc3dcSJack F Vogel static void ixgbe_disable_intr(struct adapter *); 155758cc3dcSJack F Vogel static void ixgbe_update_stats_counters(struct adapter *); 156758cc3dcSJack F Vogel static void ixgbe_set_promisc(struct adapter *); 157758cc3dcSJack F Vogel static void ixgbe_set_multi(struct adapter *); 158758cc3dcSJack F Vogel static void ixgbe_update_link_status(struct adapter *); 159758cc3dcSJack F Vogel static void ixgbe_set_ivar(struct adapter *, u8, u8, s8); 160758cc3dcSJack F Vogel static void ixgbe_configure_ivars(struct adapter *); 161758cc3dcSJack F Vogel static u8 * ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); 162758cc3dcSJack F Vogel 163758cc3dcSJack F Vogel static void ixgbe_setup_vlan_hw_support(struct adapter *); 164758cc3dcSJack F Vogel static void ixgbe_register_vlan(void *, struct ifnet *, u16); 165758cc3dcSJack F Vogel static void ixgbe_unregister_vlan(void *, struct ifnet *, u16); 166758cc3dcSJack F Vogel 1676f37f232SEric Joyner static void ixgbe_add_device_sysctls(struct adapter *); 1686f37f232SEric Joyner static void ixgbe_add_hw_stats(struct adapter *); 1696f37f232SEric Joyner 1706f37f232SEric Joyner /* Sysctl handlers */ 171b0c041f8SSean Bruno static void ixgbe_set_sysctl_value(struct adapter *, const char *, 172b0c041f8SSean Bruno const char *, int *, int); 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); 179a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG 180a9ca1c79SSean Bruno static int ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS); 181a9ca1c79SSean Bruno static int ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS); 182a9ca1c79SSean Bruno #endif 1836f37f232SEric Joyner static int ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS); 1846f37f232SEric Joyner static int ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS); 1856f37f232SEric Joyner static int ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS); 1866f37f232SEric Joyner static int ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS); 1876f37f232SEric Joyner static int ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS); 1886f37f232SEric Joyner static int ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS); 189a9ca1c79SSean Bruno static int ixgbe_sysctl_eee_tx_lpi_delay(SYSCTL_HANDLER_ARGS); 190758cc3dcSJack F Vogel 191758cc3dcSJack F Vogel /* Support for pluggable optic modules */ 192758cc3dcSJack F Vogel static bool ixgbe_sfp_probe(struct adapter *); 193758cc3dcSJack F Vogel static void ixgbe_setup_optics(struct adapter *); 194758cc3dcSJack F Vogel 195758cc3dcSJack F Vogel /* Legacy (single vector interrupt handler */ 196758cc3dcSJack F Vogel static void ixgbe_legacy_irq(void *); 197758cc3dcSJack F Vogel 198758cc3dcSJack F Vogel /* The MSI/X Interrupt handlers */ 199758cc3dcSJack F Vogel static void ixgbe_msix_que(void *); 200758cc3dcSJack F Vogel static void ixgbe_msix_link(void *); 201758cc3dcSJack F Vogel 202758cc3dcSJack F Vogel /* Deferred interrupt tasklets */ 203758cc3dcSJack F Vogel static void ixgbe_handle_que(void *, int); 204758cc3dcSJack F Vogel static void ixgbe_handle_link(void *, int); 205758cc3dcSJack F Vogel static void ixgbe_handle_msf(void *, int); 206758cc3dcSJack F Vogel static void ixgbe_handle_mod(void *, int); 2076f37f232SEric Joyner static void ixgbe_handle_phy(void *, int); 208758cc3dcSJack F Vogel 209758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 210758cc3dcSJack F Vogel static void ixgbe_reinit_fdir(void *, int); 211758cc3dcSJack F Vogel #endif 212758cc3dcSJack F Vogel 21348056c88SJack F Vogel #ifdef PCI_IOV 21448056c88SJack F Vogel static void ixgbe_ping_all_vfs(struct adapter *); 21548056c88SJack F Vogel static void ixgbe_handle_mbx(void *, int); 21648056c88SJack F Vogel static int ixgbe_init_iov(device_t, u16, const nvlist_t *); 21748056c88SJack F Vogel static void ixgbe_uninit_iov(device_t); 21848056c88SJack F Vogel static int ixgbe_add_vf(device_t, u16, const nvlist_t *); 21948056c88SJack F Vogel static void ixgbe_initialize_iov(struct adapter *); 22048056c88SJack F Vogel static void ixgbe_recalculate_max_frame(struct adapter *); 22148056c88SJack F Vogel static void ixgbe_init_vf(struct adapter *, struct ixgbe_vf *); 22248056c88SJack F Vogel #endif /* PCI_IOV */ 22348056c88SJack F Vogel 22448056c88SJack F Vogel 225758cc3dcSJack F Vogel /********************************************************************* 226758cc3dcSJack F Vogel * FreeBSD Device Interface Entry Points 227758cc3dcSJack F Vogel *********************************************************************/ 228758cc3dcSJack F Vogel 229a1edda90SAdrian Chadd static device_method_t ix_methods[] = { 230758cc3dcSJack F Vogel /* Device interface */ 231758cc3dcSJack F Vogel DEVMETHOD(device_probe, ixgbe_probe), 232758cc3dcSJack F Vogel DEVMETHOD(device_attach, ixgbe_attach), 233758cc3dcSJack F Vogel DEVMETHOD(device_detach, ixgbe_detach), 234758cc3dcSJack F Vogel DEVMETHOD(device_shutdown, ixgbe_shutdown), 2356f37f232SEric Joyner DEVMETHOD(device_suspend, ixgbe_suspend), 2366f37f232SEric Joyner DEVMETHOD(device_resume, ixgbe_resume), 23748056c88SJack F Vogel #ifdef PCI_IOV 2389e34aea2SJohn Baldwin DEVMETHOD(pci_iov_init, ixgbe_init_iov), 2399e34aea2SJohn Baldwin DEVMETHOD(pci_iov_uninit, ixgbe_uninit_iov), 2409e34aea2SJohn Baldwin DEVMETHOD(pci_iov_add_vf, ixgbe_add_vf), 24148056c88SJack F Vogel #endif /* PCI_IOV */ 242758cc3dcSJack F Vogel DEVMETHOD_END 243758cc3dcSJack F Vogel }; 244758cc3dcSJack F Vogel 245a1edda90SAdrian Chadd static driver_t ix_driver = { 246a1edda90SAdrian Chadd "ix", ix_methods, sizeof(struct adapter), 247758cc3dcSJack F Vogel }; 248758cc3dcSJack F Vogel 249a1edda90SAdrian Chadd devclass_t ix_devclass; 250a1edda90SAdrian Chadd DRIVER_MODULE(ix, pci, ix_driver, ix_devclass, 0, 0); 251758cc3dcSJack F Vogel 252a1edda90SAdrian Chadd MODULE_DEPEND(ix, pci, 1, 1, 1); 253a1edda90SAdrian Chadd MODULE_DEPEND(ix, ether, 1, 1, 1); 254847bf383SLuigi Rizzo #ifdef DEV_NETMAP 255847bf383SLuigi Rizzo MODULE_DEPEND(ix, netmap, 1, 1, 1); 256847bf383SLuigi Rizzo #endif /* DEV_NETMAP */ 257758cc3dcSJack F Vogel 258758cc3dcSJack F Vogel /* 259758cc3dcSJack F Vogel ** TUNEABLE PARAMETERS: 260758cc3dcSJack F Vogel */ 261758cc3dcSJack F Vogel 262758cc3dcSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0, 263758cc3dcSJack F Vogel "IXGBE driver parameters"); 264758cc3dcSJack F Vogel 265758cc3dcSJack F Vogel /* 266758cc3dcSJack F Vogel ** AIM: Adaptive Interrupt Moderation 267758cc3dcSJack F Vogel ** which means that the interrupt rate 268758cc3dcSJack F Vogel ** is varied over time based on the 269758cc3dcSJack F Vogel ** traffic for that interrupt vector 270758cc3dcSJack F Vogel */ 271758cc3dcSJack F Vogel static int ixgbe_enable_aim = TRUE; 272758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0, 273758cc3dcSJack F Vogel "Enable adaptive interrupt moderation"); 274758cc3dcSJack F Vogel 275758cc3dcSJack F Vogel static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY); 276758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN, 277758cc3dcSJack F Vogel &ixgbe_max_interrupt_rate, 0, "Maximum interrupts per second"); 278758cc3dcSJack F Vogel 279758cc3dcSJack F Vogel /* How many packets rxeof tries to clean at a time */ 280758cc3dcSJack F Vogel static int ixgbe_rx_process_limit = 256; 281758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, 282758cc3dcSJack F Vogel &ixgbe_rx_process_limit, 0, 283758cc3dcSJack F Vogel "Maximum number of received packets to process at a time," 284758cc3dcSJack F Vogel "-1 means unlimited"); 285758cc3dcSJack F Vogel 286758cc3dcSJack F Vogel /* How many packets txeof tries to clean at a time */ 287758cc3dcSJack F Vogel static int ixgbe_tx_process_limit = 256; 288758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, tx_process_limit, CTLFLAG_RDTUN, 289758cc3dcSJack F Vogel &ixgbe_tx_process_limit, 0, 290758cc3dcSJack F Vogel "Maximum number of sent packets to process at a time," 291758cc3dcSJack F Vogel "-1 means unlimited"); 292758cc3dcSJack F Vogel 293758cc3dcSJack F Vogel /* 294758cc3dcSJack F Vogel ** Smart speed setting, default to on 295758cc3dcSJack F Vogel ** this only works as a compile option 296758cc3dcSJack F Vogel ** right now as its during attach, set 297758cc3dcSJack F Vogel ** this to 'ixgbe_smart_speed_off' to 298758cc3dcSJack F Vogel ** disable. 299758cc3dcSJack F Vogel */ 300758cc3dcSJack F Vogel static int ixgbe_smart_speed = ixgbe_smart_speed_on; 301758cc3dcSJack F Vogel 302758cc3dcSJack F Vogel /* 303758cc3dcSJack F Vogel * MSIX should be the default for best performance, 304758cc3dcSJack F Vogel * but this allows it to be forced off for testing. 305758cc3dcSJack F Vogel */ 306758cc3dcSJack F Vogel static int ixgbe_enable_msix = 1; 307758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixgbe_enable_msix, 0, 308758cc3dcSJack F Vogel "Enable MSI-X interrupts"); 309758cc3dcSJack F Vogel 310758cc3dcSJack F Vogel /* 311758cc3dcSJack F Vogel * Number of Queues, can be set to 0, 312758cc3dcSJack F Vogel * it then autoconfigures based on the 313758cc3dcSJack F Vogel * number of cpus with a max of 8. This 314758cc3dcSJack F Vogel * can be overriden manually here. 315758cc3dcSJack F Vogel */ 316758cc3dcSJack F Vogel static int ixgbe_num_queues = 0; 317758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, num_queues, CTLFLAG_RDTUN, &ixgbe_num_queues, 0, 318758cc3dcSJack F Vogel "Number of queues to configure, 0 indicates autoconfigure"); 319758cc3dcSJack F Vogel 320758cc3dcSJack F Vogel /* 321758cc3dcSJack F Vogel ** Number of TX descriptors per ring, 322758cc3dcSJack F Vogel ** setting higher than RX as this seems 323758cc3dcSJack F Vogel ** the better performing choice. 324758cc3dcSJack F Vogel */ 325758cc3dcSJack F Vogel static int ixgbe_txd = PERFORM_TXD; 326758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, txd, CTLFLAG_RDTUN, &ixgbe_txd, 0, 327758cc3dcSJack F Vogel "Number of transmit descriptors per queue"); 328758cc3dcSJack F Vogel 329758cc3dcSJack F Vogel /* Number of RX descriptors per ring */ 330758cc3dcSJack F Vogel static int ixgbe_rxd = PERFORM_RXD; 331758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rxd, CTLFLAG_RDTUN, &ixgbe_rxd, 0, 332758cc3dcSJack F Vogel "Number of receive descriptors per queue"); 333758cc3dcSJack F Vogel 334758cc3dcSJack F Vogel /* 335758cc3dcSJack F Vogel ** Defining this on will allow the use 336758cc3dcSJack F Vogel ** of unsupported SFP+ modules, note that 337758cc3dcSJack F Vogel ** doing so you are on your own :) 338758cc3dcSJack F Vogel */ 339758cc3dcSJack F Vogel static int allow_unsupported_sfp = FALSE; 340758cc3dcSJack F Vogel TUNABLE_INT("hw.ix.unsupported_sfp", &allow_unsupported_sfp); 341758cc3dcSJack F Vogel 342758cc3dcSJack F Vogel /* Keep running tab on them for sanity check */ 343758cc3dcSJack F Vogel static int ixgbe_total_ports; 344758cc3dcSJack F Vogel 345758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 346758cc3dcSJack F Vogel /* 347758cc3dcSJack F Vogel ** Flow Director actually 'steals' 348758cc3dcSJack F Vogel ** part of the packet buffer as its 349758cc3dcSJack F Vogel ** filter pool, this variable controls 350758cc3dcSJack F Vogel ** how much it uses: 351758cc3dcSJack F Vogel ** 0 = 64K, 1 = 128K, 2 = 256K 352758cc3dcSJack F Vogel */ 353758cc3dcSJack F Vogel static int fdir_pballoc = 1; 354758cc3dcSJack F Vogel #endif 355758cc3dcSJack F Vogel 356758cc3dcSJack F Vogel #ifdef DEV_NETMAP 357758cc3dcSJack F Vogel /* 358758cc3dcSJack F Vogel * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to 359758cc3dcSJack F Vogel * be a reference on how to implement netmap support in a driver. 360758cc3dcSJack F Vogel * Additional comments are in ixgbe_netmap.h . 361758cc3dcSJack F Vogel * 362758cc3dcSJack F Vogel * <dev/netmap/ixgbe_netmap.h> contains functions for netmap support 363758cc3dcSJack F Vogel * that extend the standard driver. 364758cc3dcSJack F Vogel */ 365758cc3dcSJack F Vogel #include <dev/netmap/ixgbe_netmap.h> 366758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 367758cc3dcSJack F Vogel 36848056c88SJack F Vogel static MALLOC_DEFINE(M_IXGBE, "ix", "ix driver allocations"); 36948056c88SJack F Vogel 370758cc3dcSJack F Vogel /********************************************************************* 371758cc3dcSJack F Vogel * Device identification routine 372758cc3dcSJack F Vogel * 373758cc3dcSJack F Vogel * ixgbe_probe determines if the driver should be loaded on 374758cc3dcSJack F Vogel * adapter based on PCI vendor/device id of the adapter. 375758cc3dcSJack F Vogel * 376758cc3dcSJack F Vogel * return BUS_PROBE_DEFAULT on success, positive on failure 377758cc3dcSJack F Vogel *********************************************************************/ 378758cc3dcSJack F Vogel 379758cc3dcSJack F Vogel static int 380758cc3dcSJack F Vogel ixgbe_probe(device_t dev) 381758cc3dcSJack F Vogel { 382758cc3dcSJack F Vogel ixgbe_vendor_info_t *ent; 383758cc3dcSJack F Vogel 384758cc3dcSJack F Vogel u16 pci_vendor_id = 0; 385758cc3dcSJack F Vogel u16 pci_device_id = 0; 386758cc3dcSJack F Vogel u16 pci_subvendor_id = 0; 387758cc3dcSJack F Vogel u16 pci_subdevice_id = 0; 388758cc3dcSJack F Vogel char adapter_name[256]; 389758cc3dcSJack F Vogel 390758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_probe: begin"); 391758cc3dcSJack F Vogel 392758cc3dcSJack F Vogel pci_vendor_id = pci_get_vendor(dev); 393758cc3dcSJack F Vogel if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) 394758cc3dcSJack F Vogel return (ENXIO); 395758cc3dcSJack F Vogel 396758cc3dcSJack F Vogel pci_device_id = pci_get_device(dev); 397758cc3dcSJack F Vogel pci_subvendor_id = pci_get_subvendor(dev); 398758cc3dcSJack F Vogel pci_subdevice_id = pci_get_subdevice(dev); 399758cc3dcSJack F Vogel 400758cc3dcSJack F Vogel ent = ixgbe_vendor_info_array; 401758cc3dcSJack F Vogel while (ent->vendor_id != 0) { 402758cc3dcSJack F Vogel if ((pci_vendor_id == ent->vendor_id) && 403758cc3dcSJack F Vogel (pci_device_id == ent->device_id) && 404758cc3dcSJack F Vogel 405758cc3dcSJack F Vogel ((pci_subvendor_id == ent->subvendor_id) || 406758cc3dcSJack F Vogel (ent->subvendor_id == 0)) && 407758cc3dcSJack F Vogel 408758cc3dcSJack F Vogel ((pci_subdevice_id == ent->subdevice_id) || 409758cc3dcSJack F Vogel (ent->subdevice_id == 0))) { 410758cc3dcSJack F Vogel sprintf(adapter_name, "%s, Version - %s", 411758cc3dcSJack F Vogel ixgbe_strings[ent->index], 412758cc3dcSJack F Vogel ixgbe_driver_version); 413758cc3dcSJack F Vogel device_set_desc_copy(dev, adapter_name); 414758cc3dcSJack F Vogel ++ixgbe_total_ports; 415758cc3dcSJack F Vogel return (BUS_PROBE_DEFAULT); 416758cc3dcSJack F Vogel } 417758cc3dcSJack F Vogel ent++; 418758cc3dcSJack F Vogel } 419758cc3dcSJack F Vogel return (ENXIO); 420758cc3dcSJack F Vogel } 421758cc3dcSJack F Vogel 422758cc3dcSJack F Vogel /********************************************************************* 423758cc3dcSJack F Vogel * Device initialization routine 424758cc3dcSJack F Vogel * 425758cc3dcSJack F Vogel * The attach entry point is called when the driver is being loaded. 426758cc3dcSJack F Vogel * This routine identifies the type of hardware, allocates all resources 427758cc3dcSJack F Vogel * and initializes the hardware. 428758cc3dcSJack F Vogel * 429758cc3dcSJack F Vogel * return 0 on success, positive on failure 430758cc3dcSJack F Vogel *********************************************************************/ 431758cc3dcSJack F Vogel 432758cc3dcSJack F Vogel static int 433758cc3dcSJack F Vogel ixgbe_attach(device_t dev) 434758cc3dcSJack F Vogel { 435758cc3dcSJack F Vogel struct adapter *adapter; 436758cc3dcSJack F Vogel struct ixgbe_hw *hw; 437758cc3dcSJack F Vogel int error = 0; 438758cc3dcSJack F Vogel u16 csum; 439758cc3dcSJack F Vogel u32 ctrl_ext; 440758cc3dcSJack F Vogel 441758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_attach: begin"); 442758cc3dcSJack F Vogel 443758cc3dcSJack F Vogel /* Allocate, clear, and link in our adapter structure */ 444758cc3dcSJack F Vogel adapter = device_get_softc(dev); 445a9ca1c79SSean Bruno adapter->dev = dev; 446758cc3dcSJack F Vogel hw = &adapter->hw; 447758cc3dcSJack F Vogel 4488aa7fdbdSPatrick Kelsey #ifdef DEV_NETMAP 4498aa7fdbdSPatrick Kelsey adapter->init_locked = ixgbe_init_locked; 4508aa7fdbdSPatrick Kelsey adapter->stop_locked = ixgbe_stop; 4518aa7fdbdSPatrick Kelsey #endif 4528aa7fdbdSPatrick Kelsey 453758cc3dcSJack F Vogel /* Core Lock Init*/ 454758cc3dcSJack F Vogel IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); 455758cc3dcSJack F Vogel 456758cc3dcSJack F Vogel /* Set up the timer callout */ 457758cc3dcSJack F Vogel callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); 458758cc3dcSJack F Vogel 459758cc3dcSJack F Vogel /* Determine hardware revision */ 460758cc3dcSJack F Vogel ixgbe_identify_hardware(adapter); 461758cc3dcSJack F Vogel 462758cc3dcSJack F Vogel /* Do base PCI setup - map BAR0 */ 463758cc3dcSJack F Vogel if (ixgbe_allocate_pci_resources(adapter)) { 464758cc3dcSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 465758cc3dcSJack F Vogel error = ENXIO; 466758cc3dcSJack F Vogel goto err_out; 467758cc3dcSJack F Vogel } 468758cc3dcSJack F Vogel 469b0c041f8SSean Bruno /* Sysctls for limiting the amount of work done in the taskqueues */ 470b0c041f8SSean Bruno ixgbe_set_sysctl_value(adapter, "rx_processing_limit", 471b0c041f8SSean Bruno "max number of rx packets to process", 472b0c041f8SSean Bruno &adapter->rx_process_limit, ixgbe_rx_process_limit); 473b0c041f8SSean Bruno 474b0c041f8SSean Bruno ixgbe_set_sysctl_value(adapter, "tx_processing_limit", 475b0c041f8SSean Bruno "max number of tx packets to process", 476b0c041f8SSean Bruno &adapter->tx_process_limit, ixgbe_tx_process_limit); 477b0c041f8SSean Bruno 478758cc3dcSJack F Vogel /* Do descriptor calc and sanity checks */ 479758cc3dcSJack F Vogel if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || 480758cc3dcSJack F Vogel ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) { 481758cc3dcSJack F Vogel device_printf(dev, "TXD config issue, using default!\n"); 482758cc3dcSJack F Vogel adapter->num_tx_desc = DEFAULT_TXD; 483758cc3dcSJack F Vogel } else 484758cc3dcSJack F Vogel adapter->num_tx_desc = ixgbe_txd; 485758cc3dcSJack F Vogel 486758cc3dcSJack F Vogel /* 487758cc3dcSJack F Vogel ** With many RX rings it is easy to exceed the 488758cc3dcSJack F Vogel ** system mbuf allocation. Tuning nmbclusters 489758cc3dcSJack F Vogel ** can alleviate this. 490758cc3dcSJack F Vogel */ 491758cc3dcSJack F Vogel if (nmbclusters > 0) { 492758cc3dcSJack F Vogel int s; 493758cc3dcSJack F Vogel s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports; 494758cc3dcSJack F Vogel if (s > nmbclusters) { 495758cc3dcSJack F Vogel device_printf(dev, "RX Descriptors exceed " 496758cc3dcSJack F Vogel "system mbuf max, using default instead!\n"); 497758cc3dcSJack F Vogel ixgbe_rxd = DEFAULT_RXD; 498758cc3dcSJack F Vogel } 499758cc3dcSJack F Vogel } 500758cc3dcSJack F Vogel 501758cc3dcSJack F Vogel if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || 502758cc3dcSJack F Vogel ixgbe_rxd < MIN_RXD || ixgbe_rxd > MAX_RXD) { 503758cc3dcSJack F Vogel device_printf(dev, "RXD config issue, using default!\n"); 504758cc3dcSJack F Vogel adapter->num_rx_desc = DEFAULT_RXD; 505758cc3dcSJack F Vogel } else 506758cc3dcSJack F Vogel adapter->num_rx_desc = ixgbe_rxd; 507758cc3dcSJack F Vogel 508758cc3dcSJack F Vogel /* Allocate our TX/RX Queues */ 509758cc3dcSJack F Vogel if (ixgbe_allocate_queues(adapter)) { 510758cc3dcSJack F Vogel error = ENOMEM; 511758cc3dcSJack F Vogel goto err_out; 512758cc3dcSJack F Vogel } 513758cc3dcSJack F Vogel 514758cc3dcSJack F Vogel /* Allocate multicast array memory. */ 51548056c88SJack F Vogel adapter->mta = malloc(sizeof(*adapter->mta) * 516758cc3dcSJack F Vogel MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); 517758cc3dcSJack F Vogel if (adapter->mta == NULL) { 518758cc3dcSJack F Vogel device_printf(dev, "Can not allocate multicast setup array\n"); 519758cc3dcSJack F Vogel error = ENOMEM; 520758cc3dcSJack F Vogel goto err_late; 521758cc3dcSJack F Vogel } 522758cc3dcSJack F Vogel 523758cc3dcSJack F Vogel /* Initialize the shared code */ 524758cc3dcSJack F Vogel hw->allow_unsupported_sfp = allow_unsupported_sfp; 525758cc3dcSJack F Vogel error = ixgbe_init_shared_code(hw); 526758cc3dcSJack F Vogel if (error == IXGBE_ERR_SFP_NOT_PRESENT) { 527758cc3dcSJack F Vogel /* 528758cc3dcSJack F Vogel ** No optics in this port, set up 529758cc3dcSJack F Vogel ** so the timer routine will probe 530758cc3dcSJack F Vogel ** for later insertion. 531758cc3dcSJack F Vogel */ 532758cc3dcSJack F Vogel adapter->sfp_probe = TRUE; 533758cc3dcSJack F Vogel error = 0; 534758cc3dcSJack F Vogel } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { 535758cc3dcSJack F Vogel device_printf(dev, "Unsupported SFP+ module detected!\n"); 536758cc3dcSJack F Vogel error = EIO; 537758cc3dcSJack F Vogel goto err_late; 538758cc3dcSJack F Vogel } else if (error) { 539758cc3dcSJack F Vogel device_printf(dev, "Unable to initialize the shared code\n"); 540758cc3dcSJack F Vogel error = EIO; 541758cc3dcSJack F Vogel goto err_late; 542758cc3dcSJack F Vogel } 543758cc3dcSJack F Vogel 544758cc3dcSJack F Vogel /* Make sure we have a good EEPROM before we read from it */ 545758cc3dcSJack F Vogel if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) { 546758cc3dcSJack F Vogel device_printf(dev, "The EEPROM Checksum Is Not Valid\n"); 547758cc3dcSJack F Vogel error = EIO; 548758cc3dcSJack F Vogel goto err_late; 549758cc3dcSJack F Vogel } 550758cc3dcSJack F Vogel 551758cc3dcSJack F Vogel error = ixgbe_init_hw(hw); 552758cc3dcSJack F Vogel switch (error) { 553758cc3dcSJack F Vogel case IXGBE_ERR_EEPROM_VERSION: 554758cc3dcSJack F Vogel device_printf(dev, "This device is a pre-production adapter/" 555758cc3dcSJack F Vogel "LOM. Please be aware there may be issues associated " 556758cc3dcSJack F Vogel "with your hardware.\nIf you are experiencing problems " 557758cc3dcSJack F Vogel "please contact your Intel or hardware representative " 558758cc3dcSJack F Vogel "who provided you with this hardware.\n"); 559758cc3dcSJack F Vogel break; 560758cc3dcSJack F Vogel case IXGBE_ERR_SFP_NOT_SUPPORTED: 561758cc3dcSJack F Vogel device_printf(dev, "Unsupported SFP+ Module\n"); 562758cc3dcSJack F Vogel error = EIO; 563758cc3dcSJack F Vogel goto err_late; 564758cc3dcSJack F Vogel case IXGBE_ERR_SFP_NOT_PRESENT: 565758cc3dcSJack F Vogel device_printf(dev, "No SFP+ Module found\n"); 566758cc3dcSJack F Vogel /* falls thru */ 567758cc3dcSJack F Vogel default: 568758cc3dcSJack F Vogel break; 569758cc3dcSJack F Vogel } 570758cc3dcSJack F Vogel 571758cc3dcSJack F Vogel if ((adapter->msix > 1) && (ixgbe_enable_msix)) 572758cc3dcSJack F Vogel error = ixgbe_allocate_msix(adapter); 573758cc3dcSJack F Vogel else 574758cc3dcSJack F Vogel error = ixgbe_allocate_legacy(adapter); 575758cc3dcSJack F Vogel if (error) 576758cc3dcSJack F Vogel goto err_late; 577758cc3dcSJack F Vogel 578758cc3dcSJack F Vogel /* Setup OS specific network interface */ 579758cc3dcSJack F Vogel if (ixgbe_setup_interface(dev, adapter) != 0) 580758cc3dcSJack F Vogel goto err_late; 581758cc3dcSJack F Vogel 582758cc3dcSJack F Vogel /* Initialize statistics */ 583758cc3dcSJack F Vogel ixgbe_update_stats_counters(adapter); 584758cc3dcSJack F Vogel 585758cc3dcSJack F Vogel /* Register for VLAN events */ 586758cc3dcSJack F Vogel adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 587758cc3dcSJack F Vogel ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); 588758cc3dcSJack F Vogel adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 589758cc3dcSJack F Vogel ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); 590758cc3dcSJack F Vogel 5916f37f232SEric Joyner /* Check PCIE slot type/speed/width */ 592a9ca1c79SSean Bruno ixgbe_get_slot_info(adapter); 593758cc3dcSJack F Vogel 594a9ca1c79SSean Bruno /* Set an initial default flow control & dmac value */ 595758cc3dcSJack F Vogel adapter->fc = ixgbe_fc_full; 596a9ca1c79SSean Bruno adapter->dmac = 0; 597a9ca1c79SSean Bruno adapter->eee_enabled = 0; 598758cc3dcSJack F Vogel 59948056c88SJack F Vogel #ifdef PCI_IOV 60048056c88SJack F Vogel if ((hw->mac.type != ixgbe_mac_82598EB) && (adapter->msix > 1)) { 60148056c88SJack F Vogel nvlist_t *pf_schema, *vf_schema; 60248056c88SJack F Vogel 60348056c88SJack F Vogel hw->mbx.ops.init_params(hw); 60448056c88SJack F Vogel pf_schema = pci_iov_schema_alloc_node(); 60548056c88SJack F Vogel vf_schema = pci_iov_schema_alloc_node(); 60648056c88SJack F Vogel pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); 60748056c88SJack F Vogel pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", 60848056c88SJack F Vogel IOV_SCHEMA_HASDEFAULT, TRUE); 60948056c88SJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-set-mac", 61048056c88SJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 61148056c88SJack F Vogel pci_iov_schema_add_bool(vf_schema, "allow-promisc", 61248056c88SJack F Vogel IOV_SCHEMA_HASDEFAULT, FALSE); 61348056c88SJack F Vogel error = pci_iov_attach(dev, pf_schema, vf_schema); 61448056c88SJack F Vogel if (error != 0) { 61548056c88SJack F Vogel device_printf(dev, 61648056c88SJack F Vogel "Error %d setting up SR-IOV\n", error); 61748056c88SJack F Vogel } 61848056c88SJack F Vogel } 61948056c88SJack F Vogel #endif /* PCI_IOV */ 62048056c88SJack F Vogel 6216f37f232SEric Joyner /* Check for certain supported features */ 6226f37f232SEric Joyner ixgbe_check_wol_support(adapter); 6236f37f232SEric Joyner 6246f37f232SEric Joyner /* Add sysctls */ 6256f37f232SEric Joyner ixgbe_add_device_sysctls(adapter); 6266f37f232SEric Joyner ixgbe_add_hw_stats(adapter); 6276f37f232SEric Joyner 628758cc3dcSJack F Vogel /* let hardware know driver is loaded */ 629758cc3dcSJack F Vogel ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 630758cc3dcSJack F Vogel ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; 631758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 632758cc3dcSJack F Vogel 633758cc3dcSJack F Vogel #ifdef DEV_NETMAP 634758cc3dcSJack F Vogel ixgbe_netmap_attach(adapter); 635758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 636758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_attach: end"); 637758cc3dcSJack F Vogel return (0); 638758cc3dcSJack F Vogel 639758cc3dcSJack F Vogel err_late: 640758cc3dcSJack F Vogel ixgbe_free_transmit_structures(adapter); 641758cc3dcSJack F Vogel ixgbe_free_receive_structures(adapter); 642758cc3dcSJack F Vogel err_out: 643758cc3dcSJack F Vogel if (adapter->ifp != NULL) 644758cc3dcSJack F Vogel if_free(adapter->ifp); 645758cc3dcSJack F Vogel ixgbe_free_pci_resources(adapter); 646758cc3dcSJack F Vogel free(adapter->mta, M_DEVBUF); 647758cc3dcSJack F Vogel return (error); 648758cc3dcSJack F Vogel } 649758cc3dcSJack F Vogel 650758cc3dcSJack F Vogel /********************************************************************* 651758cc3dcSJack F Vogel * Device removal routine 652758cc3dcSJack F Vogel * 653758cc3dcSJack F Vogel * The detach entry point is called when the driver is being removed. 654758cc3dcSJack F Vogel * This routine stops the adapter and deallocates all the resources 655758cc3dcSJack F Vogel * that were allocated for driver operation. 656758cc3dcSJack F Vogel * 657758cc3dcSJack F Vogel * return 0 on success, positive on failure 658758cc3dcSJack F Vogel *********************************************************************/ 659758cc3dcSJack F Vogel 660758cc3dcSJack F Vogel static int 661758cc3dcSJack F Vogel ixgbe_detach(device_t dev) 662758cc3dcSJack F Vogel { 663758cc3dcSJack F Vogel struct adapter *adapter = device_get_softc(dev); 664758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 665758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 666758cc3dcSJack F Vogel u32 ctrl_ext; 667758cc3dcSJack F Vogel 668758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_detach: begin"); 669758cc3dcSJack F Vogel 670758cc3dcSJack F Vogel /* Make sure VLANS are not using driver */ 671758cc3dcSJack F Vogel if (adapter->ifp->if_vlantrunk != NULL) { 672758cc3dcSJack F Vogel device_printf(dev,"Vlan in use, detach first\n"); 673758cc3dcSJack F Vogel return (EBUSY); 674758cc3dcSJack F Vogel } 675758cc3dcSJack F Vogel 67648056c88SJack F Vogel #ifdef PCI_IOV 67748056c88SJack F Vogel if (pci_iov_detach(dev) != 0) { 67848056c88SJack F Vogel device_printf(dev, "SR-IOV in use; detach first.\n"); 67948056c88SJack F Vogel return (EBUSY); 68048056c88SJack F Vogel } 68148056c88SJack F Vogel #endif /* PCI_IOV */ 68248056c88SJack F Vogel 683a9ca1c79SSean Bruno ether_ifdetach(adapter->ifp); 6846f37f232SEric Joyner /* Stop the adapter */ 685758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 6866f37f232SEric Joyner ixgbe_setup_low_power_mode(adapter); 687758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 688758cc3dcSJack F Vogel 689758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { 690758cc3dcSJack F Vogel if (que->tq) { 691758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 692758cc3dcSJack F Vogel taskqueue_drain(que->tq, &txr->txq_task); 693758cc3dcSJack F Vogel #endif 694758cc3dcSJack F Vogel taskqueue_drain(que->tq, &que->que_task); 695758cc3dcSJack F Vogel taskqueue_free(que->tq); 696758cc3dcSJack F Vogel } 697758cc3dcSJack F Vogel } 698758cc3dcSJack F Vogel 699758cc3dcSJack F Vogel /* Drain the Link queue */ 700758cc3dcSJack F Vogel if (adapter->tq) { 701758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->link_task); 702758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->mod_task); 703758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->msf_task); 70448056c88SJack F Vogel #ifdef PCI_IOV 70548056c88SJack F Vogel taskqueue_drain(adapter->tq, &adapter->mbx_task); 70648056c88SJack F Vogel #endif 7076f37f232SEric Joyner taskqueue_drain(adapter->tq, &adapter->phy_task); 708758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 709758cc3dcSJack F Vogel taskqueue_drain(adapter->tq, &adapter->fdir_task); 710758cc3dcSJack F Vogel #endif 711758cc3dcSJack F Vogel taskqueue_free(adapter->tq); 712758cc3dcSJack F Vogel } 713758cc3dcSJack F Vogel 714758cc3dcSJack F Vogel /* let hardware know driver is unloading */ 715758cc3dcSJack F Vogel ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); 716758cc3dcSJack F Vogel ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; 717758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext); 718758cc3dcSJack F Vogel 719758cc3dcSJack F Vogel /* Unregister VLAN events */ 720758cc3dcSJack F Vogel if (adapter->vlan_attach != NULL) 721758cc3dcSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); 722758cc3dcSJack F Vogel if (adapter->vlan_detach != NULL) 723758cc3dcSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); 724758cc3dcSJack F Vogel 725758cc3dcSJack F Vogel callout_drain(&adapter->timer); 726758cc3dcSJack F Vogel #ifdef DEV_NETMAP 727758cc3dcSJack F Vogel netmap_detach(adapter->ifp); 728758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 729758cc3dcSJack F Vogel ixgbe_free_pci_resources(adapter); 730758cc3dcSJack F Vogel bus_generic_detach(dev); 731758cc3dcSJack F Vogel if_free(adapter->ifp); 732758cc3dcSJack F Vogel 733758cc3dcSJack F Vogel ixgbe_free_transmit_structures(adapter); 734758cc3dcSJack F Vogel ixgbe_free_receive_structures(adapter); 735758cc3dcSJack F Vogel free(adapter->mta, M_DEVBUF); 736758cc3dcSJack F Vogel 737758cc3dcSJack F Vogel IXGBE_CORE_LOCK_DESTROY(adapter); 738758cc3dcSJack F Vogel return (0); 739758cc3dcSJack F Vogel } 740758cc3dcSJack F Vogel 741758cc3dcSJack F Vogel /********************************************************************* 742758cc3dcSJack F Vogel * 743758cc3dcSJack F Vogel * Shutdown entry point 744758cc3dcSJack F Vogel * 745758cc3dcSJack F Vogel **********************************************************************/ 746758cc3dcSJack F Vogel 747758cc3dcSJack F Vogel static int 748758cc3dcSJack F Vogel ixgbe_shutdown(device_t dev) 749758cc3dcSJack F Vogel { 750758cc3dcSJack F Vogel struct adapter *adapter = device_get_softc(dev); 7516f37f232SEric Joyner int error = 0; 7526f37f232SEric Joyner 7536f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_shutdown: begin"); 7546f37f232SEric Joyner 755758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 7566f37f232SEric Joyner error = ixgbe_setup_low_power_mode(adapter); 757758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 7586f37f232SEric Joyner 7596f37f232SEric Joyner return (error); 7606f37f232SEric Joyner } 7616f37f232SEric Joyner 7626f37f232SEric Joyner /** 7636f37f232SEric Joyner * Methods for going from: 7646f37f232SEric Joyner * D0 -> D3: ixgbe_suspend 7656f37f232SEric Joyner * D3 -> D0: ixgbe_resume 7666f37f232SEric Joyner */ 7676f37f232SEric Joyner static int 7686f37f232SEric Joyner ixgbe_suspend(device_t dev) 7696f37f232SEric Joyner { 7706f37f232SEric Joyner struct adapter *adapter = device_get_softc(dev); 7716f37f232SEric Joyner int error = 0; 7726f37f232SEric Joyner 7736f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_suspend: begin"); 7746f37f232SEric Joyner 7756f37f232SEric Joyner IXGBE_CORE_LOCK(adapter); 7766f37f232SEric Joyner 7776f37f232SEric Joyner error = ixgbe_setup_low_power_mode(adapter); 7786f37f232SEric Joyner 7796f37f232SEric Joyner IXGBE_CORE_UNLOCK(adapter); 7806f37f232SEric Joyner 7816f37f232SEric Joyner return (error); 7826f37f232SEric Joyner } 7836f37f232SEric Joyner 7846f37f232SEric Joyner static int 7856f37f232SEric Joyner ixgbe_resume(device_t dev) 7866f37f232SEric Joyner { 7876f37f232SEric Joyner struct adapter *adapter = device_get_softc(dev); 7886f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 7896f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 7906f37f232SEric Joyner u32 wus; 7916f37f232SEric Joyner 7926f37f232SEric Joyner INIT_DEBUGOUT("ixgbe_resume: begin"); 7936f37f232SEric Joyner 7946f37f232SEric Joyner IXGBE_CORE_LOCK(adapter); 7956f37f232SEric Joyner 7966f37f232SEric Joyner /* Read & clear WUS register */ 7976f37f232SEric Joyner wus = IXGBE_READ_REG(hw, IXGBE_WUS); 7986f37f232SEric Joyner if (wus) 7996f37f232SEric Joyner device_printf(dev, "Woken up by (WUS): %#010x\n", 8006f37f232SEric Joyner IXGBE_READ_REG(hw, IXGBE_WUS)); 8016f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); 8026f37f232SEric Joyner /* And clear WUFC until next low-power transition */ 8036f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0); 8046f37f232SEric Joyner 8056f37f232SEric Joyner /* 8066f37f232SEric Joyner * Required after D3->D0 transition; 8076f37f232SEric Joyner * will re-advertise all previous advertised speeds 8086f37f232SEric Joyner */ 8096f37f232SEric Joyner if (ifp->if_flags & IFF_UP) 8106f37f232SEric Joyner ixgbe_init_locked(adapter); 8116f37f232SEric Joyner 8126f37f232SEric Joyner IXGBE_CORE_UNLOCK(adapter); 8136f37f232SEric Joyner 814758cc3dcSJack F Vogel return (0); 815758cc3dcSJack F Vogel } 816758cc3dcSJack F Vogel 817758cc3dcSJack F Vogel 818758cc3dcSJack F Vogel /********************************************************************* 819758cc3dcSJack F Vogel * Ioctl entry point 820758cc3dcSJack F Vogel * 821758cc3dcSJack F Vogel * ixgbe_ioctl is called when the user wants to configure the 822758cc3dcSJack F Vogel * interface. 823758cc3dcSJack F Vogel * 824758cc3dcSJack F Vogel * return 0 on success, positive on failure 825758cc3dcSJack F Vogel **********************************************************************/ 826758cc3dcSJack F Vogel 827758cc3dcSJack F Vogel static int 828758cc3dcSJack F Vogel ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data) 829758cc3dcSJack F Vogel { 830758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 831758cc3dcSJack F Vogel struct ifreq *ifr = (struct ifreq *) data; 832758cc3dcSJack F Vogel #if defined(INET) || defined(INET6) 833758cc3dcSJack F Vogel struct ifaddr *ifa = (struct ifaddr *)data; 834758cc3dcSJack F Vogel #endif 835758cc3dcSJack F Vogel int error = 0; 836e5cb6169SSean Bruno bool avoid_reset = FALSE; 837758cc3dcSJack F Vogel 838758cc3dcSJack F Vogel switch (command) { 839758cc3dcSJack F Vogel 840758cc3dcSJack F Vogel case SIOCSIFADDR: 841758cc3dcSJack F Vogel #ifdef INET 842758cc3dcSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET) 843758cc3dcSJack F Vogel avoid_reset = TRUE; 844758cc3dcSJack F Vogel #endif 845758cc3dcSJack F Vogel #ifdef INET6 846758cc3dcSJack F Vogel if (ifa->ifa_addr->sa_family == AF_INET6) 847758cc3dcSJack F Vogel avoid_reset = TRUE; 848758cc3dcSJack F Vogel #endif 849758cc3dcSJack F Vogel /* 850758cc3dcSJack F Vogel ** Calling init results in link renegotiation, 851758cc3dcSJack F Vogel ** so we avoid doing it when possible. 852758cc3dcSJack F Vogel */ 853758cc3dcSJack F Vogel if (avoid_reset) { 854758cc3dcSJack F Vogel ifp->if_flags |= IFF_UP; 855758cc3dcSJack F Vogel if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 856758cc3dcSJack F Vogel ixgbe_init(adapter); 857a9ca1c79SSean Bruno #ifdef INET 858758cc3dcSJack F Vogel if (!(ifp->if_flags & IFF_NOARP)) 859758cc3dcSJack F Vogel arp_ifinit(ifp, ifa); 860e5cb6169SSean Bruno #endif 861758cc3dcSJack F Vogel } else 862758cc3dcSJack F Vogel error = ether_ioctl(ifp, command, data); 863758cc3dcSJack F Vogel break; 864758cc3dcSJack F Vogel case SIOCSIFMTU: 865758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 8666f37f232SEric Joyner if (ifr->ifr_mtu > IXGBE_MAX_MTU) { 867758cc3dcSJack F Vogel error = EINVAL; 868758cc3dcSJack F Vogel } else { 869758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 870758cc3dcSJack F Vogel ifp->if_mtu = ifr->ifr_mtu; 871758cc3dcSJack F Vogel adapter->max_frame_size = 8726f37f232SEric Joyner ifp->if_mtu + IXGBE_MTU_HDR; 873758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 87448056c88SJack F Vogel #ifdef PCI_IOV 87548056c88SJack F Vogel ixgbe_recalculate_max_frame(adapter); 87648056c88SJack F Vogel #endif 877758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 878758cc3dcSJack F Vogel } 879758cc3dcSJack F Vogel break; 880758cc3dcSJack F Vogel case SIOCSIFFLAGS: 881758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); 882758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 883758cc3dcSJack F Vogel if (ifp->if_flags & IFF_UP) { 884758cc3dcSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 885758cc3dcSJack F Vogel if ((ifp->if_flags ^ adapter->if_flags) & 886758cc3dcSJack F Vogel (IFF_PROMISC | IFF_ALLMULTI)) { 887758cc3dcSJack F Vogel ixgbe_set_promisc(adapter); 888758cc3dcSJack F Vogel } 889758cc3dcSJack F Vogel } else 890758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 891758cc3dcSJack F Vogel } else 892758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) 893758cc3dcSJack F Vogel ixgbe_stop(adapter); 894758cc3dcSJack F Vogel adapter->if_flags = ifp->if_flags; 895758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 896758cc3dcSJack F Vogel break; 897758cc3dcSJack F Vogel case SIOCADDMULTI: 898758cc3dcSJack F Vogel case SIOCDELMULTI: 899758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); 900758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 901758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 902758cc3dcSJack F Vogel ixgbe_disable_intr(adapter); 903758cc3dcSJack F Vogel ixgbe_set_multi(adapter); 904758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 905758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 906758cc3dcSJack F Vogel } 907758cc3dcSJack F Vogel break; 908758cc3dcSJack F Vogel case SIOCSIFMEDIA: 909758cc3dcSJack F Vogel case SIOCGIFMEDIA: 910758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); 911758cc3dcSJack F Vogel error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); 912758cc3dcSJack F Vogel break; 913758cc3dcSJack F Vogel case SIOCSIFCAP: 914758cc3dcSJack F Vogel { 915758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); 916a9ca1c79SSean Bruno 917a9ca1c79SSean Bruno int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 918a9ca1c79SSean Bruno if (!mask) 919a9ca1c79SSean Bruno break; 920a9ca1c79SSean Bruno 921a9ca1c79SSean Bruno /* HW cannot turn these on/off separately */ 922a9ca1c79SSean Bruno if (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) { 923a9ca1c79SSean Bruno ifp->if_capenable ^= IFCAP_RXCSUM; 924a9ca1c79SSean Bruno ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 925a9ca1c79SSean Bruno } 926a9ca1c79SSean Bruno if (mask & IFCAP_TXCSUM) 927a9ca1c79SSean Bruno ifp->if_capenable ^= IFCAP_TXCSUM; 928a9ca1c79SSean Bruno if (mask & IFCAP_TXCSUM_IPV6) 929a9ca1c79SSean Bruno ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 930758cc3dcSJack F Vogel if (mask & IFCAP_TSO4) 931758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_TSO4; 932758cc3dcSJack F Vogel if (mask & IFCAP_TSO6) 933758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_TSO6; 934758cc3dcSJack F Vogel if (mask & IFCAP_LRO) 935758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_LRO; 936758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWTAGGING) 937758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 938758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWFILTER) 939758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 940758cc3dcSJack F Vogel if (mask & IFCAP_VLAN_HWTSO) 941758cc3dcSJack F Vogel ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 942a9ca1c79SSean Bruno 943758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 944758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 945758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 946758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 947758cc3dcSJack F Vogel } 948758cc3dcSJack F Vogel VLAN_CAPABILITIES(ifp); 949758cc3dcSJack F Vogel break; 950758cc3dcSJack F Vogel } 951758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 952758cc3dcSJack F Vogel case SIOCGI2C: 953758cc3dcSJack F Vogel { 954758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 955758cc3dcSJack F Vogel struct ifi2creq i2c; 956758cc3dcSJack F Vogel int i; 957758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)"); 958758cc3dcSJack F Vogel error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); 959758cc3dcSJack F Vogel if (error != 0) 960758cc3dcSJack F Vogel break; 961758cc3dcSJack F Vogel if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { 962758cc3dcSJack F Vogel error = EINVAL; 963758cc3dcSJack F Vogel break; 964758cc3dcSJack F Vogel } 965758cc3dcSJack F Vogel if (i2c.len > sizeof(i2c.data)) { 966758cc3dcSJack F Vogel error = EINVAL; 967758cc3dcSJack F Vogel break; 968758cc3dcSJack F Vogel } 969758cc3dcSJack F Vogel 970758cc3dcSJack F Vogel for (i = 0; i < i2c.len; i++) 971758cc3dcSJack F Vogel hw->phy.ops.read_i2c_byte(hw, i2c.offset + i, 972758cc3dcSJack F Vogel i2c.dev_addr, &i2c.data[i]); 973758cc3dcSJack F Vogel error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); 974758cc3dcSJack F Vogel break; 975758cc3dcSJack F Vogel } 976758cc3dcSJack F Vogel #endif 977758cc3dcSJack F Vogel default: 978758cc3dcSJack F Vogel IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); 979758cc3dcSJack F Vogel error = ether_ioctl(ifp, command, data); 980758cc3dcSJack F Vogel break; 981758cc3dcSJack F Vogel } 982758cc3dcSJack F Vogel 983758cc3dcSJack F Vogel return (error); 984758cc3dcSJack F Vogel } 985758cc3dcSJack F Vogel 986a9ca1c79SSean Bruno /* 987a9ca1c79SSean Bruno * Set the various hardware offload abilities. 988a9ca1c79SSean Bruno * 989a9ca1c79SSean Bruno * This takes the ifnet's if_capenable flags (e.g. set by the user using 990a9ca1c79SSean Bruno * ifconfig) and indicates to the OS via the ifnet's if_hwassist field what 991a9ca1c79SSean Bruno * mbuf offload flags the driver will understand. 992a9ca1c79SSean Bruno */ 993a9ca1c79SSean Bruno static void 994a9ca1c79SSean Bruno ixgbe_set_if_hwassist(struct adapter *adapter) 995a9ca1c79SSean Bruno { 996a9ca1c79SSean Bruno struct ifnet *ifp = adapter->ifp; 997a9ca1c79SSean Bruno 998a9ca1c79SSean Bruno ifp->if_hwassist = 0; 999a9ca1c79SSean Bruno #if __FreeBSD_version >= 1000000 1000a9ca1c79SSean Bruno if (ifp->if_capenable & IFCAP_TSO4) 1001a9ca1c79SSean Bruno ifp->if_hwassist |= CSUM_IP_TSO; 1002a9ca1c79SSean Bruno if (ifp->if_capenable & IFCAP_TSO6) 1003a9ca1c79SSean Bruno ifp->if_hwassist |= CSUM_IP6_TSO; 1004a9ca1c79SSean Bruno if (ifp->if_capenable & IFCAP_TXCSUM) 1005a9ca1c79SSean Bruno ifp->if_hwassist |= (CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP | 1006a9ca1c79SSean Bruno CSUM_IP_SCTP); 1007a9ca1c79SSean Bruno if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) 1008a9ca1c79SSean Bruno ifp->if_hwassist |= (CSUM_IP6_UDP | CSUM_IP6_TCP | 1009a9ca1c79SSean Bruno CSUM_IP6_SCTP); 1010a9ca1c79SSean Bruno #else 1011a9ca1c79SSean Bruno if (ifp->if_capenable & IFCAP_TSO) 1012a9ca1c79SSean Bruno ifp->if_hwassist |= CSUM_TSO; 1013a9ca1c79SSean Bruno if (ifp->if_capenable & IFCAP_TXCSUM) { 1014a9ca1c79SSean Bruno ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 1015a9ca1c79SSean Bruno struct ixgbe_hw *hw = &adapter->hw; 1016a9ca1c79SSean Bruno if (hw->mac.type != ixgbe_mac_82598EB) 1017a9ca1c79SSean Bruno ifp->if_hwassist |= CSUM_SCTP; 1018a9ca1c79SSean Bruno } 1019a9ca1c79SSean Bruno #endif 1020a9ca1c79SSean Bruno } 1021a9ca1c79SSean Bruno 1022758cc3dcSJack F Vogel /********************************************************************* 1023758cc3dcSJack F Vogel * Init entry point 1024758cc3dcSJack F Vogel * 1025758cc3dcSJack F Vogel * This routine is used in two ways. It is used by the stack as 1026758cc3dcSJack F Vogel * init entry point in network interface structure. It is also used 1027758cc3dcSJack F Vogel * by the driver as a hw/sw initialization routine to get to a 1028758cc3dcSJack F Vogel * consistent state. 1029758cc3dcSJack F Vogel * 1030758cc3dcSJack F Vogel * return 0 on success, positive on failure 1031758cc3dcSJack F Vogel **********************************************************************/ 1032758cc3dcSJack F Vogel #define IXGBE_MHADD_MFS_SHIFT 16 1033758cc3dcSJack F Vogel 1034758cc3dcSJack F Vogel static void 1035758cc3dcSJack F Vogel ixgbe_init_locked(struct adapter *adapter) 1036758cc3dcSJack F Vogel { 1037758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1038758cc3dcSJack F Vogel device_t dev = adapter->dev; 1039758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 104048056c88SJack F Vogel struct tx_ring *txr; 104148056c88SJack F Vogel struct rx_ring *rxr; 104248056c88SJack F Vogel u32 txdctl, mhadd; 1043758cc3dcSJack F Vogel u32 rxdctl, rxctrl; 1044a9ca1c79SSean Bruno int err = 0; 104548056c88SJack F Vogel #ifdef PCI_IOV 104648056c88SJack F Vogel enum ixgbe_iov_mode mode; 104748056c88SJack F Vogel #endif 1048758cc3dcSJack F Vogel 1049758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 1050758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_init_locked: begin"); 105148056c88SJack F Vogel 1052758cc3dcSJack F Vogel hw->adapter_stopped = FALSE; 1053758cc3dcSJack F Vogel ixgbe_stop_adapter(hw); 1054758cc3dcSJack F Vogel callout_stop(&adapter->timer); 1055758cc3dcSJack F Vogel 105648056c88SJack F Vogel #ifdef PCI_IOV 105748056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 105848056c88SJack F Vogel adapter->pool = ixgbe_max_vfs(mode); 105948056c88SJack F Vogel /* Queue indices may change with IOV mode */ 106048056c88SJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 106148056c88SJack F Vogel adapter->rx_rings[i].me = ixgbe_pf_que_index(mode, i); 106248056c88SJack F Vogel adapter->tx_rings[i].me = ixgbe_pf_que_index(mode, i); 106348056c88SJack F Vogel } 106448056c88SJack F Vogel #endif 1065758cc3dcSJack F Vogel /* reprogram the RAR[0] in case user changed it. */ 106648056c88SJack F Vogel ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, IXGBE_RAH_AV); 1067758cc3dcSJack F Vogel 1068758cc3dcSJack F Vogel /* Get the latest mac address, User can use a LAA */ 106948056c88SJack F Vogel bcopy(IF_LLADDR(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS); 107048056c88SJack F Vogel ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, 1); 1071758cc3dcSJack F Vogel hw->addr_ctrl.rar_used_count = 1; 1072758cc3dcSJack F Vogel 1073a9ca1c79SSean Bruno /* Set hardware offload abilities from ifnet flags */ 1074a9ca1c79SSean Bruno ixgbe_set_if_hwassist(adapter); 1075758cc3dcSJack F Vogel 1076758cc3dcSJack F Vogel /* Prepare transmit descriptors and buffers */ 1077758cc3dcSJack F Vogel if (ixgbe_setup_transmit_structures(adapter)) { 1078758cc3dcSJack F Vogel device_printf(dev, "Could not setup transmit structures\n"); 1079758cc3dcSJack F Vogel ixgbe_stop(adapter); 1080758cc3dcSJack F Vogel return; 1081758cc3dcSJack F Vogel } 1082758cc3dcSJack F Vogel 1083758cc3dcSJack F Vogel ixgbe_init_hw(hw); 108448056c88SJack F Vogel #ifdef PCI_IOV 108548056c88SJack F Vogel ixgbe_initialize_iov(adapter); 108648056c88SJack F Vogel #endif 1087758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(adapter); 1088758cc3dcSJack F Vogel 1089758cc3dcSJack F Vogel /* Setup Multicast table */ 1090758cc3dcSJack F Vogel ixgbe_set_multi(adapter); 1091758cc3dcSJack F Vogel 1092a9ca1c79SSean Bruno /* Determine the correct mbuf pool, based on frame size */ 109348056c88SJack F Vogel if (adapter->max_frame_size <= MCLBYTES) 1094758cc3dcSJack F Vogel adapter->rx_mbuf_sz = MCLBYTES; 109530126537SJack F Vogel else 109648056c88SJack F Vogel adapter->rx_mbuf_sz = MJUMPAGESIZE; 1097758cc3dcSJack F Vogel 1098758cc3dcSJack F Vogel /* Prepare receive descriptors and buffers */ 1099758cc3dcSJack F Vogel if (ixgbe_setup_receive_structures(adapter)) { 1100758cc3dcSJack F Vogel device_printf(dev, "Could not setup receive structures\n"); 1101758cc3dcSJack F Vogel ixgbe_stop(adapter); 1102758cc3dcSJack F Vogel return; 1103758cc3dcSJack F Vogel } 1104758cc3dcSJack F Vogel 1105758cc3dcSJack F Vogel /* Configure RX settings */ 1106758cc3dcSJack F Vogel ixgbe_initialize_receive_units(adapter); 1107758cc3dcSJack F Vogel 110848056c88SJack F Vogel /* Enable SDP & MSIX interrupts based on adapter */ 110948056c88SJack F Vogel ixgbe_config_gpie(adapter); 1110758cc3dcSJack F Vogel 1111758cc3dcSJack F Vogel /* Set MTU size */ 1112758cc3dcSJack F Vogel if (ifp->if_mtu > ETHERMTU) { 11136f37f232SEric Joyner /* aka IXGBE_MAXFRS on 82599 and newer */ 1114758cc3dcSJack F Vogel mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); 1115758cc3dcSJack F Vogel mhadd &= ~IXGBE_MHADD_MFS_MASK; 1116758cc3dcSJack F Vogel mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; 1117758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); 1118758cc3dcSJack F Vogel } 1119758cc3dcSJack F Vogel 1120758cc3dcSJack F Vogel /* Now enable all the queues */ 1121758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 112248056c88SJack F Vogel txr = &adapter->tx_rings[i]; 112348056c88SJack F Vogel txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txr->me)); 1124758cc3dcSJack F Vogel txdctl |= IXGBE_TXDCTL_ENABLE; 1125758cc3dcSJack F Vogel /* Set WTHRESH to 8, burst writeback */ 1126758cc3dcSJack F Vogel txdctl |= (8 << 16); 1127758cc3dcSJack F Vogel /* 1128758cc3dcSJack F Vogel * When the internal queue falls below PTHRESH (32), 1129758cc3dcSJack F Vogel * start prefetching as long as there are at least 1130758cc3dcSJack F Vogel * HTHRESH (1) buffers ready. The values are taken 1131758cc3dcSJack F Vogel * from the Intel linux driver 3.8.21. 1132758cc3dcSJack F Vogel * Prefetching enables tx line rate even with 1 queue. 1133758cc3dcSJack F Vogel */ 1134758cc3dcSJack F Vogel txdctl |= (32 << 0) | (1 << 8); 113548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txr->me), txdctl); 1136758cc3dcSJack F Vogel } 1137758cc3dcSJack F Vogel 113848056c88SJack F Vogel for (int i = 0, j = 0; i < adapter->num_queues; i++) { 113948056c88SJack F Vogel rxr = &adapter->rx_rings[i]; 114048056c88SJack F Vogel rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); 1141758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1142758cc3dcSJack F Vogel /* 1143758cc3dcSJack F Vogel ** PTHRESH = 21 1144758cc3dcSJack F Vogel ** HTHRESH = 4 1145758cc3dcSJack F Vogel ** WTHRESH = 8 1146758cc3dcSJack F Vogel */ 1147758cc3dcSJack F Vogel rxdctl &= ~0x3FFFFF; 1148758cc3dcSJack F Vogel rxdctl |= 0x080420; 1149758cc3dcSJack F Vogel } 1150758cc3dcSJack F Vogel rxdctl |= IXGBE_RXDCTL_ENABLE; 115148056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), rxdctl); 115248056c88SJack F Vogel for (; j < 10; j++) { 115348056c88SJack F Vogel if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)) & 1154758cc3dcSJack F Vogel IXGBE_RXDCTL_ENABLE) 1155758cc3dcSJack F Vogel break; 1156758cc3dcSJack F Vogel else 1157758cc3dcSJack F Vogel msec_delay(1); 1158758cc3dcSJack F Vogel } 1159758cc3dcSJack F Vogel wmb(); 1160758cc3dcSJack F Vogel #ifdef DEV_NETMAP 1161758cc3dcSJack F Vogel /* 1162758cc3dcSJack F Vogel * In netmap mode, we must preserve the buffers made 1163758cc3dcSJack F Vogel * available to userspace before the if_init() 1164758cc3dcSJack F Vogel * (this is true by default on the TX side, because 1165758cc3dcSJack F Vogel * init makes all buffers available to userspace). 1166758cc3dcSJack F Vogel * 1167758cc3dcSJack F Vogel * netmap_reset() and the device specific routines 1168758cc3dcSJack F Vogel * (e.g. ixgbe_setup_receive_rings()) map these 1169758cc3dcSJack F Vogel * buffers at the end of the NIC ring, so here we 1170758cc3dcSJack F Vogel * must set the RDT (tail) register to make sure 1171758cc3dcSJack F Vogel * they are not overwritten. 1172758cc3dcSJack F Vogel * 1173758cc3dcSJack F Vogel * In this driver the NIC ring starts at RDH = 0, 1174758cc3dcSJack F Vogel * RDT points to the last slot available for reception (?), 1175758cc3dcSJack F Vogel * so RDT = num_rx_desc - 1 means the whole ring is available. 1176758cc3dcSJack F Vogel */ 1177758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_NETMAP) { 1178758cc3dcSJack F Vogel struct netmap_adapter *na = NA(adapter->ifp); 1179758cc3dcSJack F Vogel struct netmap_kring *kring = &na->rx_rings[i]; 1180758cc3dcSJack F Vogel int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); 1181758cc3dcSJack F Vogel 118248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), t); 1183758cc3dcSJack F Vogel } else 1184758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 118548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), adapter->num_rx_desc - 1); 1186758cc3dcSJack F Vogel } 1187758cc3dcSJack F Vogel 1188758cc3dcSJack F Vogel /* Enable Receive engine */ 1189758cc3dcSJack F Vogel rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); 1190758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 1191758cc3dcSJack F Vogel rxctrl |= IXGBE_RXCTRL_DMBYPS; 1192758cc3dcSJack F Vogel rxctrl |= IXGBE_RXCTRL_RXEN; 1193758cc3dcSJack F Vogel ixgbe_enable_rx_dma(hw, rxctrl); 1194758cc3dcSJack F Vogel 1195758cc3dcSJack F Vogel callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); 1196758cc3dcSJack F Vogel 1197758cc3dcSJack F Vogel /* Set up MSI/X routing */ 1198758cc3dcSJack F Vogel if (ixgbe_enable_msix) { 1199758cc3dcSJack F Vogel ixgbe_configure_ivars(adapter); 1200758cc3dcSJack F Vogel /* Set up auto-mask */ 1201758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 1202758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); 1203758cc3dcSJack F Vogel else { 1204758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); 1205758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); 1206758cc3dcSJack F Vogel } 1207758cc3dcSJack F Vogel } else { /* Simple settings for Legacy/MSI */ 1208758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 0, 0, 0); 1209758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 0, 0, 1); 1210758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); 1211758cc3dcSJack F Vogel } 1212758cc3dcSJack F Vogel 1213758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 1214758cc3dcSJack F Vogel /* Init Flow director */ 1215758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 1216758cc3dcSJack F Vogel u32 hdrm = 32 << fdir_pballoc; 1217758cc3dcSJack F Vogel 1218758cc3dcSJack F Vogel hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL); 1219758cc3dcSJack F Vogel ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); 1220758cc3dcSJack F Vogel } 1221758cc3dcSJack F Vogel #endif 1222758cc3dcSJack F Vogel 1223758cc3dcSJack F Vogel /* 122448056c88SJack F Vogel * Check on any SFP devices that 122548056c88SJack F Vogel * need to be kick-started 1226758cc3dcSJack F Vogel */ 1227758cc3dcSJack F Vogel if (hw->phy.type == ixgbe_phy_none) { 1228a9ca1c79SSean Bruno err = hw->phy.ops.identify(hw); 1229758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 1230758cc3dcSJack F Vogel device_printf(dev, 1231758cc3dcSJack F Vogel "Unsupported SFP+ module type was detected.\n"); 1232758cc3dcSJack F Vogel return; 1233758cc3dcSJack F Vogel } 1234758cc3dcSJack F Vogel } 1235758cc3dcSJack F Vogel 1236758cc3dcSJack F Vogel /* Set moderation on the Link interrupt */ 1237758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR); 1238758cc3dcSJack F Vogel 12396f37f232SEric Joyner /* Configure Energy Efficient Ethernet for supported devices */ 1240a9ca1c79SSean Bruno if (hw->mac.ops.setup_eee) { 1241a9ca1c79SSean Bruno err = hw->mac.ops.setup_eee(hw, adapter->eee_enabled); 1242a9ca1c79SSean Bruno if (err) 1243a9ca1c79SSean Bruno device_printf(dev, "Error setting up EEE: %d\n", err); 1244a9ca1c79SSean Bruno } 12456f37f232SEric Joyner 1246758cc3dcSJack F Vogel /* Config/Enable Link */ 1247758cc3dcSJack F Vogel ixgbe_config_link(adapter); 1248758cc3dcSJack F Vogel 1249758cc3dcSJack F Vogel /* Hardware Packet Buffer & Flow Control setup */ 12506f37f232SEric Joyner ixgbe_config_delay_values(adapter); 1251758cc3dcSJack F Vogel 1252758cc3dcSJack F Vogel /* Initialize the FC settings */ 1253758cc3dcSJack F Vogel ixgbe_start_hw(hw); 1254758cc3dcSJack F Vogel 1255758cc3dcSJack F Vogel /* Set up VLAN support and filter */ 1256758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 1257758cc3dcSJack F Vogel 12586f37f232SEric Joyner /* Setup DMA Coalescing */ 12596f37f232SEric Joyner ixgbe_config_dmac(adapter); 12606f37f232SEric Joyner 1261758cc3dcSJack F Vogel /* And now turn on interrupts */ 1262758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1263758cc3dcSJack F Vogel 126448056c88SJack F Vogel #ifdef PCI_IOV 126548056c88SJack F Vogel /* Enable the use of the MBX by the VF's */ 126648056c88SJack F Vogel { 126748056c88SJack F Vogel u32 reg = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 126848056c88SJack F Vogel reg |= IXGBE_CTRL_EXT_PFRSTD; 126948056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, reg); 127048056c88SJack F Vogel } 127148056c88SJack F Vogel #endif 127248056c88SJack F Vogel 1273758cc3dcSJack F Vogel /* Now inform the stack we're ready */ 1274758cc3dcSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 1275758cc3dcSJack F Vogel 1276758cc3dcSJack F Vogel return; 1277758cc3dcSJack F Vogel } 1278758cc3dcSJack F Vogel 1279758cc3dcSJack F Vogel static void 1280758cc3dcSJack F Vogel ixgbe_init(void *arg) 1281758cc3dcSJack F Vogel { 1282758cc3dcSJack F Vogel struct adapter *adapter = arg; 1283758cc3dcSJack F Vogel 1284758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 1285758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 1286758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1287758cc3dcSJack F Vogel return; 1288758cc3dcSJack F Vogel } 1289758cc3dcSJack F Vogel 12906f37f232SEric Joyner static void 129148056c88SJack F Vogel ixgbe_config_gpie(struct adapter *adapter) 129248056c88SJack F Vogel { 129348056c88SJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 129448056c88SJack F Vogel u32 gpie; 129548056c88SJack F Vogel 129648056c88SJack F Vogel gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); 129748056c88SJack F Vogel 129848056c88SJack F Vogel /* Fan Failure Interrupt */ 129948056c88SJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) 130048056c88SJack F Vogel gpie |= IXGBE_SDP1_GPIEN; 130148056c88SJack F Vogel 130248056c88SJack F Vogel /* 130348056c88SJack F Vogel * Module detection (SDP2) 130448056c88SJack F Vogel * Media ready (SDP1) 130548056c88SJack F Vogel */ 130648056c88SJack F Vogel if (hw->mac.type == ixgbe_mac_82599EB) { 130748056c88SJack F Vogel gpie |= IXGBE_SDP2_GPIEN; 130848056c88SJack F Vogel if (hw->device_id != IXGBE_DEV_ID_82599_QSFP_SF_QP) 130948056c88SJack F Vogel gpie |= IXGBE_SDP1_GPIEN; 131048056c88SJack F Vogel } 131148056c88SJack F Vogel 131248056c88SJack F Vogel /* 131348056c88SJack F Vogel * Thermal Failure Detection (X540) 1314a9ca1c79SSean Bruno * Link Detection (X552 SFP+, X552/X557-AT) 131548056c88SJack F Vogel */ 131648056c88SJack F Vogel if (hw->mac.type == ixgbe_mac_X540 || 131748056c88SJack F Vogel hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || 131848056c88SJack F Vogel hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) 131948056c88SJack F Vogel gpie |= IXGBE_SDP0_GPIEN_X540; 132048056c88SJack F Vogel 132148056c88SJack F Vogel if (adapter->msix > 1) { 132248056c88SJack F Vogel /* Enable Enhanced MSIX mode */ 132348056c88SJack F Vogel gpie |= IXGBE_GPIE_MSIX_MODE; 132448056c88SJack F Vogel gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | 132548056c88SJack F Vogel IXGBE_GPIE_OCD; 132648056c88SJack F Vogel } 132748056c88SJack F Vogel 132848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 132948056c88SJack F Vogel return; 133048056c88SJack F Vogel } 133148056c88SJack F Vogel 133248056c88SJack F Vogel /* 133348056c88SJack F Vogel * Requires adapter->max_frame_size to be set. 133448056c88SJack F Vogel */ 133548056c88SJack F Vogel static void 13366f37f232SEric Joyner ixgbe_config_delay_values(struct adapter *adapter) 13376f37f232SEric Joyner { 13386f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 13396f37f232SEric Joyner u32 rxpb, frame, size, tmp; 13406f37f232SEric Joyner 13416f37f232SEric Joyner frame = adapter->max_frame_size; 13426f37f232SEric Joyner 13436f37f232SEric Joyner /* Calculate High Water */ 13446f37f232SEric Joyner switch (hw->mac.type) { 13456f37f232SEric Joyner case ixgbe_mac_X540: 13466f37f232SEric Joyner case ixgbe_mac_X550: 13476f37f232SEric Joyner case ixgbe_mac_X550EM_x: 13486f37f232SEric Joyner tmp = IXGBE_DV_X540(frame, frame); 13496f37f232SEric Joyner break; 13506f37f232SEric Joyner default: 13516f37f232SEric Joyner tmp = IXGBE_DV(frame, frame); 13526f37f232SEric Joyner break; 13536f37f232SEric Joyner } 13546f37f232SEric Joyner size = IXGBE_BT2KB(tmp); 13556f37f232SEric Joyner rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10; 13566f37f232SEric Joyner hw->fc.high_water[0] = rxpb - size; 13576f37f232SEric Joyner 13586f37f232SEric Joyner /* Now calculate Low Water */ 13596f37f232SEric Joyner switch (hw->mac.type) { 13606f37f232SEric Joyner case ixgbe_mac_X540: 13616f37f232SEric Joyner case ixgbe_mac_X550: 13626f37f232SEric Joyner case ixgbe_mac_X550EM_x: 13636f37f232SEric Joyner tmp = IXGBE_LOW_DV_X540(frame); 13646f37f232SEric Joyner break; 13656f37f232SEric Joyner default: 13666f37f232SEric Joyner tmp = IXGBE_LOW_DV(frame); 13676f37f232SEric Joyner break; 13686f37f232SEric Joyner } 13696f37f232SEric Joyner hw->fc.low_water[0] = IXGBE_BT2KB(tmp); 13706f37f232SEric Joyner 13716f37f232SEric Joyner hw->fc.requested_mode = adapter->fc; 13726f37f232SEric Joyner hw->fc.pause_time = IXGBE_FC_PAUSE; 13736f37f232SEric Joyner hw->fc.send_xon = TRUE; 13746f37f232SEric Joyner } 1375758cc3dcSJack F Vogel 1376758cc3dcSJack F Vogel /* 1377758cc3dcSJack F Vogel ** 1378758cc3dcSJack F Vogel ** MSIX Interrupt Handlers and Tasklets 1379758cc3dcSJack F Vogel ** 1380758cc3dcSJack F Vogel */ 1381758cc3dcSJack F Vogel 1382758cc3dcSJack F Vogel static inline void 1383758cc3dcSJack F Vogel ixgbe_enable_queue(struct adapter *adapter, u32 vector) 1384758cc3dcSJack F Vogel { 1385758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1386758cc3dcSJack F Vogel u64 queue = (u64)(1 << vector); 1387758cc3dcSJack F Vogel u32 mask; 1388758cc3dcSJack F Vogel 1389758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1390758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queue); 1391758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); 1392758cc3dcSJack F Vogel } else { 1393758cc3dcSJack F Vogel mask = (queue & 0xFFFFFFFF); 1394758cc3dcSJack F Vogel if (mask) 1395758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask); 1396758cc3dcSJack F Vogel mask = (queue >> 32); 1397758cc3dcSJack F Vogel if (mask) 1398758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask); 1399758cc3dcSJack F Vogel } 1400758cc3dcSJack F Vogel } 1401758cc3dcSJack F Vogel 1402758cc3dcSJack F Vogel static inline void 1403758cc3dcSJack F Vogel ixgbe_disable_queue(struct adapter *adapter, u32 vector) 1404758cc3dcSJack F Vogel { 1405758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1406758cc3dcSJack F Vogel u64 queue = (u64)(1 << vector); 1407758cc3dcSJack F Vogel u32 mask; 1408758cc3dcSJack F Vogel 1409758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1410758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queue); 1411758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask); 1412758cc3dcSJack F Vogel } else { 1413758cc3dcSJack F Vogel mask = (queue & 0xFFFFFFFF); 1414758cc3dcSJack F Vogel if (mask) 1415758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask); 1416758cc3dcSJack F Vogel mask = (queue >> 32); 1417758cc3dcSJack F Vogel if (mask) 1418758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask); 1419758cc3dcSJack F Vogel } 1420758cc3dcSJack F Vogel } 1421758cc3dcSJack F Vogel 1422758cc3dcSJack F Vogel static void 1423758cc3dcSJack F Vogel ixgbe_handle_que(void *context, int pending) 1424758cc3dcSJack F Vogel { 1425758cc3dcSJack F Vogel struct ix_queue *que = context; 1426758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1427758cc3dcSJack F Vogel struct tx_ring *txr = que->txr; 1428758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1429758cc3dcSJack F Vogel 1430758cc3dcSJack F Vogel if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 143148056c88SJack F Vogel ixgbe_rxeof(que); 1432758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1433758cc3dcSJack F Vogel ixgbe_txeof(txr); 1434758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 1435758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1436758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1437758cc3dcSJack F Vogel #else 1438758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1439758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1440758cc3dcSJack F Vogel #endif 1441758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1442758cc3dcSJack F Vogel } 1443758cc3dcSJack F Vogel 1444758cc3dcSJack F Vogel /* Reenable this interrupt */ 1445758cc3dcSJack F Vogel if (que->res != NULL) 1446758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 1447758cc3dcSJack F Vogel else 1448758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1449758cc3dcSJack F Vogel return; 1450758cc3dcSJack F Vogel } 1451758cc3dcSJack F Vogel 1452758cc3dcSJack F Vogel 1453758cc3dcSJack F Vogel /********************************************************************* 1454758cc3dcSJack F Vogel * 1455758cc3dcSJack F Vogel * Legacy Interrupt Service routine 1456758cc3dcSJack F Vogel * 1457758cc3dcSJack F Vogel **********************************************************************/ 1458758cc3dcSJack F Vogel 1459758cc3dcSJack F Vogel static void 1460758cc3dcSJack F Vogel ixgbe_legacy_irq(void *arg) 1461758cc3dcSJack F Vogel { 1462758cc3dcSJack F Vogel struct ix_queue *que = arg; 1463758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1464758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1465758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1466758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 1467758cc3dcSJack F Vogel bool more; 1468758cc3dcSJack F Vogel u32 reg_eicr; 1469758cc3dcSJack F Vogel 1470758cc3dcSJack F Vogel 1471758cc3dcSJack F Vogel reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 1472758cc3dcSJack F Vogel 1473758cc3dcSJack F Vogel ++que->irqs; 1474758cc3dcSJack F Vogel if (reg_eicr == 0) { 1475758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1476758cc3dcSJack F Vogel return; 1477758cc3dcSJack F Vogel } 1478758cc3dcSJack F Vogel 1479758cc3dcSJack F Vogel more = ixgbe_rxeof(que); 1480758cc3dcSJack F Vogel 1481758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1482758cc3dcSJack F Vogel ixgbe_txeof(txr); 1483758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX 1484758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1485758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1486758cc3dcSJack F Vogel #else 1487758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1488758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1489758cc3dcSJack F Vogel #endif 1490758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1491758cc3dcSJack F Vogel 1492758cc3dcSJack F Vogel /* Check for fan failure */ 149348056c88SJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82598AT) && 149448056c88SJack F Vogel (reg_eicr & IXGBE_EICR_GPI_SDP1)) { 1495758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " 1496758cc3dcSJack F Vogel "REPLACE IMMEDIATELY!!\n"); 1497758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 1498758cc3dcSJack F Vogel } 1499758cc3dcSJack F Vogel 1500758cc3dcSJack F Vogel /* Link status change */ 1501758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_LSC) 1502758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->link_task); 1503758cc3dcSJack F Vogel 15046f37f232SEric Joyner /* External PHY interrupt */ 15056f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && 15066f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) 15076f37f232SEric Joyner taskqueue_enqueue(adapter->tq, &adapter->phy_task); 15086f37f232SEric Joyner 1509758cc3dcSJack F Vogel if (more) 1510758cc3dcSJack F Vogel taskqueue_enqueue(que->tq, &que->que_task); 1511758cc3dcSJack F Vogel else 1512758cc3dcSJack F Vogel ixgbe_enable_intr(adapter); 1513758cc3dcSJack F Vogel return; 1514758cc3dcSJack F Vogel } 1515758cc3dcSJack F Vogel 1516758cc3dcSJack F Vogel 1517758cc3dcSJack F Vogel /********************************************************************* 1518758cc3dcSJack F Vogel * 1519758cc3dcSJack F Vogel * MSIX Queue Interrupt Service routine 1520758cc3dcSJack F Vogel * 1521758cc3dcSJack F Vogel **********************************************************************/ 1522758cc3dcSJack F Vogel void 1523758cc3dcSJack F Vogel ixgbe_msix_que(void *arg) 1524758cc3dcSJack F Vogel { 1525758cc3dcSJack F Vogel struct ix_queue *que = arg; 1526758cc3dcSJack F Vogel struct adapter *adapter = que->adapter; 1527758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1528758cc3dcSJack F Vogel struct tx_ring *txr = que->txr; 1529758cc3dcSJack F Vogel struct rx_ring *rxr = que->rxr; 1530758cc3dcSJack F Vogel bool more; 1531758cc3dcSJack F Vogel u32 newitr = 0; 1532758cc3dcSJack F Vogel 153348056c88SJack F Vogel 1534758cc3dcSJack F Vogel /* Protect against spurious interrupts */ 1535758cc3dcSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1536758cc3dcSJack F Vogel return; 1537758cc3dcSJack F Vogel 1538758cc3dcSJack F Vogel ixgbe_disable_queue(adapter, que->msix); 1539758cc3dcSJack F Vogel ++que->irqs; 1540758cc3dcSJack F Vogel 1541758cc3dcSJack F Vogel more = ixgbe_rxeof(que); 1542758cc3dcSJack F Vogel 1543758cc3dcSJack F Vogel IXGBE_TX_LOCK(txr); 1544758cc3dcSJack F Vogel ixgbe_txeof(txr); 1545758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX 1546758cc3dcSJack F Vogel if (!IFQ_DRV_IS_EMPTY(ifp->if_snd)) 1547758cc3dcSJack F Vogel ixgbe_start_locked(txr, ifp); 1548758cc3dcSJack F Vogel #else 1549758cc3dcSJack F Vogel if (!drbr_empty(ifp, txr->br)) 1550758cc3dcSJack F Vogel ixgbe_mq_start_locked(ifp, txr); 1551758cc3dcSJack F Vogel #endif 1552758cc3dcSJack F Vogel IXGBE_TX_UNLOCK(txr); 1553758cc3dcSJack F Vogel 1554758cc3dcSJack F Vogel /* Do AIM now? */ 1555758cc3dcSJack F Vogel 1556758cc3dcSJack F Vogel if (ixgbe_enable_aim == FALSE) 1557758cc3dcSJack F Vogel goto no_calc; 1558758cc3dcSJack F Vogel /* 1559758cc3dcSJack F Vogel ** Do Adaptive Interrupt Moderation: 1560758cc3dcSJack F Vogel ** - Write out last calculated setting 1561758cc3dcSJack F Vogel ** - Calculate based on average size over 1562758cc3dcSJack F Vogel ** the last interval. 1563758cc3dcSJack F Vogel */ 1564758cc3dcSJack F Vogel if (que->eitr_setting) 1565758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, 1566758cc3dcSJack F Vogel IXGBE_EITR(que->msix), que->eitr_setting); 1567758cc3dcSJack F Vogel 1568758cc3dcSJack F Vogel que->eitr_setting = 0; 1569758cc3dcSJack F Vogel 1570758cc3dcSJack F Vogel /* Idle, do nothing */ 1571758cc3dcSJack F Vogel if ((txr->bytes == 0) && (rxr->bytes == 0)) 1572758cc3dcSJack F Vogel goto no_calc; 1573758cc3dcSJack F Vogel 1574758cc3dcSJack F Vogel if ((txr->bytes) && (txr->packets)) 1575758cc3dcSJack F Vogel newitr = txr->bytes/txr->packets; 1576758cc3dcSJack F Vogel if ((rxr->bytes) && (rxr->packets)) 1577758cc3dcSJack F Vogel newitr = max(newitr, 1578758cc3dcSJack F Vogel (rxr->bytes / rxr->packets)); 1579758cc3dcSJack F Vogel newitr += 24; /* account for hardware frame, crc */ 1580758cc3dcSJack F Vogel 1581758cc3dcSJack F Vogel /* set an upper boundary */ 1582758cc3dcSJack F Vogel newitr = min(newitr, 3000); 1583758cc3dcSJack F Vogel 1584758cc3dcSJack F Vogel /* Be nice to the mid range */ 1585758cc3dcSJack F Vogel if ((newitr > 300) && (newitr < 1200)) 1586758cc3dcSJack F Vogel newitr = (newitr / 3); 1587758cc3dcSJack F Vogel else 1588758cc3dcSJack F Vogel newitr = (newitr / 2); 1589758cc3dcSJack F Vogel 1590758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) 1591758cc3dcSJack F Vogel newitr |= newitr << 16; 1592758cc3dcSJack F Vogel else 1593758cc3dcSJack F Vogel newitr |= IXGBE_EITR_CNT_WDIS; 1594758cc3dcSJack F Vogel 1595758cc3dcSJack F Vogel /* save for next interrupt */ 1596758cc3dcSJack F Vogel que->eitr_setting = newitr; 1597758cc3dcSJack F Vogel 1598758cc3dcSJack F Vogel /* Reset state */ 1599758cc3dcSJack F Vogel txr->bytes = 0; 1600758cc3dcSJack F Vogel txr->packets = 0; 1601758cc3dcSJack F Vogel rxr->bytes = 0; 1602758cc3dcSJack F Vogel rxr->packets = 0; 1603758cc3dcSJack F Vogel 1604758cc3dcSJack F Vogel no_calc: 1605758cc3dcSJack F Vogel if (more) 1606758cc3dcSJack F Vogel taskqueue_enqueue(que->tq, &que->que_task); 1607758cc3dcSJack F Vogel else 1608758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 1609758cc3dcSJack F Vogel return; 1610758cc3dcSJack F Vogel } 1611758cc3dcSJack F Vogel 1612758cc3dcSJack F Vogel 1613758cc3dcSJack F Vogel static void 1614758cc3dcSJack F Vogel ixgbe_msix_link(void *arg) 1615758cc3dcSJack F Vogel { 1616758cc3dcSJack F Vogel struct adapter *adapter = arg; 1617758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 16186f37f232SEric Joyner u32 reg_eicr, mod_mask; 1619758cc3dcSJack F Vogel 16206f37f232SEric Joyner ++adapter->link_irq; 1621758cc3dcSJack F Vogel 1622a9ca1c79SSean Bruno /* Pause other interrupts */ 1623a9ca1c79SSean Bruno IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_OTHER); 1624a9ca1c79SSean Bruno 1625758cc3dcSJack F Vogel /* First get the cause */ 1626758cc3dcSJack F Vogel reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS); 1627758cc3dcSJack F Vogel /* Be sure the queue bits are not cleared */ 1628758cc3dcSJack F Vogel reg_eicr &= ~IXGBE_EICR_RTX_QUEUE; 1629758cc3dcSJack F Vogel /* Clear interrupt with write */ 1630758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr); 1631758cc3dcSJack F Vogel 1632758cc3dcSJack F Vogel /* Link status change */ 1633a9ca1c79SSean Bruno if (reg_eicr & IXGBE_EICR_LSC) { 1634a9ca1c79SSean Bruno IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); 1635758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->link_task); 1636a9ca1c79SSean Bruno } 1637758cc3dcSJack F Vogel 1638758cc3dcSJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82598EB) { 1639758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 1640758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_FLOW_DIR) { 1641758cc3dcSJack F Vogel /* This is probably overkill :) */ 1642758cc3dcSJack F Vogel if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1)) 1643758cc3dcSJack F Vogel return; 1644758cc3dcSJack F Vogel /* Disable the interrupt */ 1645758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR); 1646758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->fdir_task); 1647758cc3dcSJack F Vogel } else 1648758cc3dcSJack F Vogel #endif 1649758cc3dcSJack F Vogel if (reg_eicr & IXGBE_EICR_ECC) { 1650a9ca1c79SSean Bruno device_printf(adapter->dev, "CRITICAL: ECC ERROR!! " 1651758cc3dcSJack F Vogel "Please Reboot!!\n"); 1652758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); 16536f37f232SEric Joyner } 16546f37f232SEric Joyner 16556f37f232SEric Joyner /* Check for over temp condition */ 16566f37f232SEric Joyner if (reg_eicr & IXGBE_EICR_TS) { 1657a9ca1c79SSean Bruno device_printf(adapter->dev, "CRITICAL: OVER TEMP!! " 16586f37f232SEric Joyner "PHY IS SHUT DOWN!!\n"); 16596f37f232SEric Joyner device_printf(adapter->dev, "System shutdown required!\n"); 16606f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); 16616f37f232SEric Joyner } 166248056c88SJack F Vogel #ifdef PCI_IOV 166348056c88SJack F Vogel if (reg_eicr & IXGBE_EICR_MAILBOX) 166448056c88SJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mbx_task); 166548056c88SJack F Vogel #endif 16666f37f232SEric Joyner } 16676f37f232SEric Joyner 16686f37f232SEric Joyner /* Pluggable optics-related interrupt */ 16696f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) 16706f37f232SEric Joyner mod_mask = IXGBE_EICR_GPI_SDP0_X540; 16716f37f232SEric Joyner else 16726f37f232SEric Joyner mod_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw); 1673758cc3dcSJack F Vogel 1674758cc3dcSJack F Vogel if (ixgbe_is_sfp(hw)) { 16756f37f232SEric Joyner if (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) { 1676758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 1677758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 16786f37f232SEric Joyner } else if (reg_eicr & mod_mask) { 16796f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, mod_mask); 1680758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mod_task); 1681758cc3dcSJack F Vogel } 1682758cc3dcSJack F Vogel } 1683758cc3dcSJack F Vogel 1684758cc3dcSJack F Vogel /* Check for fan failure */ 1685758cc3dcSJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82598AT) && 16866f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP1)) { 16876f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); 1688758cc3dcSJack F Vogel device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " 1689758cc3dcSJack F Vogel "REPLACE IMMEDIATELY!!\n"); 1690758cc3dcSJack F Vogel } 1691758cc3dcSJack F Vogel 16926f37f232SEric Joyner /* External PHY interrupt */ 16936f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && 16946f37f232SEric Joyner (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) { 16956f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540); 16966f37f232SEric Joyner taskqueue_enqueue(adapter->tq, &adapter->phy_task); 1697758cc3dcSJack F Vogel } 1698758cc3dcSJack F Vogel 1699a9ca1c79SSean Bruno /* Re-enable other interrupts */ 1700758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); 1701758cc3dcSJack F Vogel return; 1702758cc3dcSJack F Vogel } 1703758cc3dcSJack F Vogel 1704758cc3dcSJack F Vogel /********************************************************************* 1705758cc3dcSJack F Vogel * 1706758cc3dcSJack F Vogel * Media Ioctl callback 1707758cc3dcSJack F Vogel * 1708758cc3dcSJack F Vogel * This routine is called whenever the user queries the status of 1709758cc3dcSJack F Vogel * the interface using ifconfig. 1710758cc3dcSJack F Vogel * 1711758cc3dcSJack F Vogel **********************************************************************/ 1712758cc3dcSJack F Vogel static void 1713758cc3dcSJack F Vogel ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 1714758cc3dcSJack F Vogel { 1715758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 1716758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1717758cc3dcSJack F Vogel int layer; 1718758cc3dcSJack F Vogel 1719758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_media_status: begin"); 1720758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 1721758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 1722758cc3dcSJack F Vogel 1723758cc3dcSJack F Vogel ifmr->ifm_status = IFM_AVALID; 1724758cc3dcSJack F Vogel ifmr->ifm_active = IFM_ETHER; 1725758cc3dcSJack F Vogel 1726758cc3dcSJack F Vogel if (!adapter->link_active) { 1727758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1728758cc3dcSJack F Vogel return; 1729758cc3dcSJack F Vogel } 1730758cc3dcSJack F Vogel 1731758cc3dcSJack F Vogel ifmr->ifm_status |= IFM_ACTIVE; 173248056c88SJack F Vogel layer = adapter->phy_layer; 1733758cc3dcSJack F Vogel 1734758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T || 1735758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_1000BASE_T || 1736758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) 1737758cc3dcSJack F Vogel switch (adapter->link_speed) { 1738758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1739758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_T | IFM_FDX; 1740758cc3dcSJack F Vogel break; 1741758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1742758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_T | IFM_FDX; 1743758cc3dcSJack F Vogel break; 1744758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_100_FULL: 1745758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_100_TX | IFM_FDX; 1746758cc3dcSJack F Vogel break; 1747758cc3dcSJack F Vogel } 1748758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || 1749758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) 1750758cc3dcSJack F Vogel switch (adapter->link_speed) { 1751758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1752758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_TWINAX | IFM_FDX; 1753758cc3dcSJack F Vogel break; 1754758cc3dcSJack F Vogel } 1755758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) 1756758cc3dcSJack F Vogel switch (adapter->link_speed) { 1757758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1758758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_LR | IFM_FDX; 1759758cc3dcSJack F Vogel break; 1760758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1761758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; 1762758cc3dcSJack F Vogel break; 1763758cc3dcSJack F Vogel } 1764758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM) 1765758cc3dcSJack F Vogel switch (adapter->link_speed) { 1766758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1767758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_LRM | IFM_FDX; 1768758cc3dcSJack F Vogel break; 1769758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1770758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; 1771758cc3dcSJack F Vogel break; 1772758cc3dcSJack F Vogel } 1773758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR || 1774758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) 1775758cc3dcSJack F Vogel switch (adapter->link_speed) { 1776758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1777758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; 1778758cc3dcSJack F Vogel break; 1779758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 1780758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; 1781758cc3dcSJack F Vogel break; 1782758cc3dcSJack F Vogel } 1783758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) 1784758cc3dcSJack F Vogel switch (adapter->link_speed) { 1785758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 1786758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; 1787758cc3dcSJack F Vogel break; 1788758cc3dcSJack F Vogel } 1789758cc3dcSJack F Vogel /* 1790758cc3dcSJack F Vogel ** XXX: These need to use the proper media types once 1791758cc3dcSJack F Vogel ** they're added. 1792758cc3dcSJack F Vogel */ 1793a9ca1c79SSean Bruno #ifndef IFM_ETH_XTYPE 1794758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) 1795758cc3dcSJack F Vogel switch (adapter->link_speed) { 1796758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 17976f37f232SEric Joyner ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; 17986f37f232SEric Joyner break; 17996f37f232SEric Joyner case IXGBE_LINK_SPEED_2_5GB_FULL: 18006f37f232SEric Joyner ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; 1801758cc3dcSJack F Vogel break; 1802758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 18036f37f232SEric Joyner ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; 1804758cc3dcSJack F Vogel break; 1805758cc3dcSJack F Vogel } 18066f37f232SEric Joyner else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 1807758cc3dcSJack F Vogel || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) 1808758cc3dcSJack F Vogel switch (adapter->link_speed) { 1809758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_10GB_FULL: 18106f37f232SEric Joyner ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; 18116f37f232SEric Joyner break; 18126f37f232SEric Joyner case IXGBE_LINK_SPEED_2_5GB_FULL: 18136f37f232SEric Joyner ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; 1814758cc3dcSJack F Vogel break; 1815758cc3dcSJack F Vogel case IXGBE_LINK_SPEED_1GB_FULL: 18166f37f232SEric Joyner ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; 1817758cc3dcSJack F Vogel break; 1818758cc3dcSJack F Vogel } 1819a9ca1c79SSean Bruno #else 1820a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) 1821a9ca1c79SSean Bruno switch (adapter->link_speed) { 1822a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_10GB_FULL: 1823a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_10G_KR | IFM_FDX; 1824a9ca1c79SSean Bruno break; 1825a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_2_5GB_FULL: 1826a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; 1827a9ca1c79SSean Bruno break; 1828a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_1GB_FULL: 1829a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; 1830a9ca1c79SSean Bruno break; 1831a9ca1c79SSean Bruno } 1832a9ca1c79SSean Bruno else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 1833a9ca1c79SSean Bruno || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) 1834a9ca1c79SSean Bruno switch (adapter->link_speed) { 1835a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_10GB_FULL: 1836a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_10G_KX4 | IFM_FDX; 1837a9ca1c79SSean Bruno break; 1838a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_2_5GB_FULL: 1839a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; 1840a9ca1c79SSean Bruno break; 1841a9ca1c79SSean Bruno case IXGBE_LINK_SPEED_1GB_FULL: 1842a9ca1c79SSean Bruno ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; 1843a9ca1c79SSean Bruno break; 1844a9ca1c79SSean Bruno } 1845a9ca1c79SSean Bruno #endif 1846758cc3dcSJack F Vogel 1847758cc3dcSJack F Vogel /* If nothing is recognized... */ 1848758cc3dcSJack F Vogel if (IFM_SUBTYPE(ifmr->ifm_active) == 0) 1849758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_UNKNOWN; 1850758cc3dcSJack F Vogel 1851758cc3dcSJack F Vogel #if __FreeBSD_version >= 900025 18526f37f232SEric Joyner /* Display current flow control setting used on link */ 18536f37f232SEric Joyner if (hw->fc.current_mode == ixgbe_fc_rx_pause || 18546f37f232SEric Joyner hw->fc.current_mode == ixgbe_fc_full) 1855758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_ETH_RXPAUSE; 18566f37f232SEric Joyner if (hw->fc.current_mode == ixgbe_fc_tx_pause || 18576f37f232SEric Joyner hw->fc.current_mode == ixgbe_fc_full) 1858758cc3dcSJack F Vogel ifmr->ifm_active |= IFM_ETH_TXPAUSE; 1859758cc3dcSJack F Vogel #endif 1860758cc3dcSJack F Vogel 1861758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 1862758cc3dcSJack F Vogel 1863758cc3dcSJack F Vogel return; 1864758cc3dcSJack F Vogel } 1865758cc3dcSJack F Vogel 1866758cc3dcSJack F Vogel /********************************************************************* 1867758cc3dcSJack F Vogel * 1868758cc3dcSJack F Vogel * Media Ioctl callback 1869758cc3dcSJack F Vogel * 1870758cc3dcSJack F Vogel * This routine is called when the user changes speed/duplex using 1871758cc3dcSJack F Vogel * media/mediopt option with ifconfig. 1872758cc3dcSJack F Vogel * 1873758cc3dcSJack F Vogel **********************************************************************/ 1874758cc3dcSJack F Vogel static int 1875758cc3dcSJack F Vogel ixgbe_media_change(struct ifnet * ifp) 1876758cc3dcSJack F Vogel { 1877758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 1878758cc3dcSJack F Vogel struct ifmedia *ifm = &adapter->media; 1879758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 1880758cc3dcSJack F Vogel ixgbe_link_speed speed = 0; 1881758cc3dcSJack F Vogel 1882758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_media_change: begin"); 1883758cc3dcSJack F Vogel 1884758cc3dcSJack F Vogel if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1885758cc3dcSJack F Vogel return (EINVAL); 1886758cc3dcSJack F Vogel 18876f37f232SEric Joyner if (hw->phy.media_type == ixgbe_media_type_backplane) 1888a9ca1c79SSean Bruno return (ENODEV); 18896f37f232SEric Joyner 1890758cc3dcSJack F Vogel /* 1891758cc3dcSJack F Vogel ** We don't actually need to check against the supported 1892758cc3dcSJack F Vogel ** media types of the adapter; ifmedia will take care of 1893758cc3dcSJack F Vogel ** that for us. 1894758cc3dcSJack F Vogel */ 1895a9ca1c79SSean Bruno #ifndef IFM_ETH_XTYPE 1896758cc3dcSJack F Vogel switch (IFM_SUBTYPE(ifm->ifm_media)) { 1897758cc3dcSJack F Vogel case IFM_AUTO: 1898758cc3dcSJack F Vogel case IFM_10G_T: 1899758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1900758cc3dcSJack F Vogel case IFM_10G_LRM: 1901758cc3dcSJack F Vogel case IFM_10G_SR: /* KR, too */ 1902758cc3dcSJack F Vogel case IFM_10G_LR: 19036f37f232SEric Joyner case IFM_10G_CX4: /* KX4 */ 1904758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 1905758cc3dcSJack F Vogel case IFM_10G_TWINAX: 1906758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_10GB_FULL; 1907758cc3dcSJack F Vogel break; 1908758cc3dcSJack F Vogel case IFM_1000_T: 1909758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1910758cc3dcSJack F Vogel case IFM_1000_LX: 1911758cc3dcSJack F Vogel case IFM_1000_SX: 19126f37f232SEric Joyner case IFM_1000_CX: /* KX */ 1913758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 1914758cc3dcSJack F Vogel break; 1915758cc3dcSJack F Vogel case IFM_100_TX: 1916758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 1917758cc3dcSJack F Vogel break; 1918758cc3dcSJack F Vogel default: 1919758cc3dcSJack F Vogel goto invalid; 1920758cc3dcSJack F Vogel } 1921a9ca1c79SSean Bruno #else 1922a9ca1c79SSean Bruno switch (IFM_SUBTYPE(ifm->ifm_media)) { 1923a9ca1c79SSean Bruno case IFM_AUTO: 1924a9ca1c79SSean Bruno case IFM_10G_T: 1925a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_100_FULL; 1926a9ca1c79SSean Bruno case IFM_10G_LRM: 1927a9ca1c79SSean Bruno case IFM_10G_KR: 1928a9ca1c79SSean Bruno case IFM_10G_LR: 1929a9ca1c79SSean Bruno case IFM_10G_KX4: 1930a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_1GB_FULL; 1931a9ca1c79SSean Bruno case IFM_10G_TWINAX: 1932a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_10GB_FULL; 1933a9ca1c79SSean Bruno break; 1934a9ca1c79SSean Bruno case IFM_1000_T: 1935a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_100_FULL; 1936a9ca1c79SSean Bruno case IFM_1000_LX: 1937a9ca1c79SSean Bruno case IFM_1000_SX: 1938a9ca1c79SSean Bruno case IFM_1000_KX: 1939a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_1GB_FULL; 1940a9ca1c79SSean Bruno break; 1941a9ca1c79SSean Bruno case IFM_100_TX: 1942a9ca1c79SSean Bruno speed |= IXGBE_LINK_SPEED_100_FULL; 1943a9ca1c79SSean Bruno break; 1944a9ca1c79SSean Bruno default: 1945a9ca1c79SSean Bruno goto invalid; 1946a9ca1c79SSean Bruno } 1947a9ca1c79SSean Bruno #endif 1948758cc3dcSJack F Vogel 1949758cc3dcSJack F Vogel hw->mac.autotry_restart = TRUE; 1950758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, speed, TRUE); 1951758cc3dcSJack F Vogel adapter->advertise = 1952758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_10GB_FULL) << 2) | 1953758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_1GB_FULL) << 1) | 1954758cc3dcSJack F Vogel ((speed & IXGBE_LINK_SPEED_100_FULL) << 0); 1955758cc3dcSJack F Vogel 1956758cc3dcSJack F Vogel return (0); 1957758cc3dcSJack F Vogel 1958758cc3dcSJack F Vogel invalid: 19596f37f232SEric Joyner device_printf(adapter->dev, "Invalid media type!\n"); 1960758cc3dcSJack F Vogel return (EINVAL); 1961758cc3dcSJack F Vogel } 1962758cc3dcSJack F Vogel 1963758cc3dcSJack F Vogel static void 1964758cc3dcSJack F Vogel ixgbe_set_promisc(struct adapter *adapter) 1965758cc3dcSJack F Vogel { 1966758cc3dcSJack F Vogel u_int32_t reg_rctl; 1967758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 1968758cc3dcSJack F Vogel int mcnt = 0; 1969758cc3dcSJack F Vogel 1970758cc3dcSJack F Vogel reg_rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); 1971758cc3dcSJack F Vogel reg_rctl &= (~IXGBE_FCTRL_UPE); 1972758cc3dcSJack F Vogel if (ifp->if_flags & IFF_ALLMULTI) 1973758cc3dcSJack F Vogel mcnt = MAX_NUM_MULTICAST_ADDRESSES; 1974758cc3dcSJack F Vogel else { 1975758cc3dcSJack F Vogel struct ifmultiaddr *ifma; 1976758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1977758cc3dcSJack F Vogel IF_ADDR_LOCK(ifp); 1978758cc3dcSJack F Vogel #else 1979758cc3dcSJack F Vogel if_maddr_rlock(ifp); 1980758cc3dcSJack F Vogel #endif 1981758cc3dcSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1982758cc3dcSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 1983758cc3dcSJack F Vogel continue; 1984758cc3dcSJack F Vogel if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) 1985758cc3dcSJack F Vogel break; 1986758cc3dcSJack F Vogel mcnt++; 1987758cc3dcSJack F Vogel } 1988758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 1989758cc3dcSJack F Vogel IF_ADDR_UNLOCK(ifp); 1990758cc3dcSJack F Vogel #else 1991758cc3dcSJack F Vogel if_maddr_runlock(ifp); 1992758cc3dcSJack F Vogel #endif 1993758cc3dcSJack F Vogel } 1994758cc3dcSJack F Vogel if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) 1995758cc3dcSJack F Vogel reg_rctl &= (~IXGBE_FCTRL_MPE); 1996758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 1997758cc3dcSJack F Vogel 1998758cc3dcSJack F Vogel if (ifp->if_flags & IFF_PROMISC) { 1999758cc3dcSJack F Vogel reg_rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 2000758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 2001758cc3dcSJack F Vogel } else if (ifp->if_flags & IFF_ALLMULTI) { 2002758cc3dcSJack F Vogel reg_rctl |= IXGBE_FCTRL_MPE; 2003758cc3dcSJack F Vogel reg_rctl &= ~IXGBE_FCTRL_UPE; 2004758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); 2005758cc3dcSJack F Vogel } 2006758cc3dcSJack F Vogel return; 2007758cc3dcSJack F Vogel } 2008758cc3dcSJack F Vogel 2009758cc3dcSJack F Vogel 2010758cc3dcSJack F Vogel /********************************************************************* 2011758cc3dcSJack F Vogel * Multicast Update 2012758cc3dcSJack F Vogel * 2013758cc3dcSJack F Vogel * This routine is called whenever multicast address list is updated. 2014758cc3dcSJack F Vogel * 2015758cc3dcSJack F Vogel **********************************************************************/ 2016758cc3dcSJack F Vogel #define IXGBE_RAR_ENTRIES 16 2017758cc3dcSJack F Vogel 2018758cc3dcSJack F Vogel static void 2019758cc3dcSJack F Vogel ixgbe_set_multi(struct adapter *adapter) 2020758cc3dcSJack F Vogel { 2021758cc3dcSJack F Vogel u32 fctrl; 2022758cc3dcSJack F Vogel u8 *update_ptr; 2023758cc3dcSJack F Vogel struct ifmultiaddr *ifma; 202448056c88SJack F Vogel struct ixgbe_mc_addr *mta; 2025758cc3dcSJack F Vogel int mcnt = 0; 2026758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 2027758cc3dcSJack F Vogel 2028758cc3dcSJack F Vogel IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); 2029758cc3dcSJack F Vogel 2030758cc3dcSJack F Vogel mta = adapter->mta; 203148056c88SJack F Vogel bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES); 2032758cc3dcSJack F Vogel 2033758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 2034758cc3dcSJack F Vogel IF_ADDR_LOCK(ifp); 2035758cc3dcSJack F Vogel #else 2036758cc3dcSJack F Vogel if_maddr_rlock(ifp); 2037758cc3dcSJack F Vogel #endif 2038758cc3dcSJack F Vogel TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2039758cc3dcSJack F Vogel if (ifma->ifma_addr->sa_family != AF_LINK) 2040758cc3dcSJack F Vogel continue; 2041758cc3dcSJack F Vogel if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) 2042758cc3dcSJack F Vogel break; 2043758cc3dcSJack F Vogel bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), 204448056c88SJack F Vogel mta[mcnt].addr, IXGBE_ETH_LENGTH_OF_ADDRESS); 204548056c88SJack F Vogel mta[mcnt].vmdq = adapter->pool; 2046758cc3dcSJack F Vogel mcnt++; 2047758cc3dcSJack F Vogel } 2048758cc3dcSJack F Vogel #if __FreeBSD_version < 800000 2049758cc3dcSJack F Vogel IF_ADDR_UNLOCK(ifp); 2050758cc3dcSJack F Vogel #else 2051758cc3dcSJack F Vogel if_maddr_runlock(ifp); 2052758cc3dcSJack F Vogel #endif 2053758cc3dcSJack F Vogel 2054758cc3dcSJack F Vogel fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); 2055758cc3dcSJack F Vogel fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 2056758cc3dcSJack F Vogel if (ifp->if_flags & IFF_PROMISC) 2057758cc3dcSJack F Vogel fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 2058758cc3dcSJack F Vogel else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES || 2059758cc3dcSJack F Vogel ifp->if_flags & IFF_ALLMULTI) { 2060758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_MPE; 2061758cc3dcSJack F Vogel fctrl &= ~IXGBE_FCTRL_UPE; 2062758cc3dcSJack F Vogel } else 2063758cc3dcSJack F Vogel fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 2064758cc3dcSJack F Vogel 2065758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); 2066758cc3dcSJack F Vogel 2067758cc3dcSJack F Vogel if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) { 206848056c88SJack F Vogel update_ptr = (u8 *)mta; 2069758cc3dcSJack F Vogel ixgbe_update_mc_addr_list(&adapter->hw, 2070758cc3dcSJack F Vogel update_ptr, mcnt, ixgbe_mc_array_itr, TRUE); 2071758cc3dcSJack F Vogel } 2072758cc3dcSJack F Vogel 2073758cc3dcSJack F Vogel return; 2074758cc3dcSJack F Vogel } 2075758cc3dcSJack F Vogel 2076758cc3dcSJack F Vogel /* 2077758cc3dcSJack F Vogel * This is an iterator function now needed by the multicast 2078758cc3dcSJack F Vogel * shared code. It simply feeds the shared code routine the 2079758cc3dcSJack F Vogel * addresses in the array of ixgbe_set_multi() one by one. 2080758cc3dcSJack F Vogel */ 2081758cc3dcSJack F Vogel static u8 * 2082758cc3dcSJack F Vogel ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) 2083758cc3dcSJack F Vogel { 208448056c88SJack F Vogel struct ixgbe_mc_addr *mta; 2085758cc3dcSJack F Vogel 208648056c88SJack F Vogel mta = (struct ixgbe_mc_addr *)*update_ptr; 208748056c88SJack F Vogel *vmdq = mta->vmdq; 208848056c88SJack F Vogel 208948056c88SJack F Vogel *update_ptr = (u8*)(mta + 1);; 209048056c88SJack F Vogel return (mta->addr); 2091758cc3dcSJack F Vogel } 2092758cc3dcSJack F Vogel 2093758cc3dcSJack F Vogel 2094758cc3dcSJack F Vogel /********************************************************************* 2095758cc3dcSJack F Vogel * Timer routine 2096758cc3dcSJack F Vogel * 2097758cc3dcSJack F Vogel * This routine checks for link status,updates statistics, 2098758cc3dcSJack F Vogel * and runs the watchdog check. 2099758cc3dcSJack F Vogel * 2100758cc3dcSJack F Vogel **********************************************************************/ 2101758cc3dcSJack F Vogel 2102758cc3dcSJack F Vogel static void 2103758cc3dcSJack F Vogel ixgbe_local_timer(void *arg) 2104758cc3dcSJack F Vogel { 2105758cc3dcSJack F Vogel struct adapter *adapter = arg; 2106758cc3dcSJack F Vogel device_t dev = adapter->dev; 2107758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2108758cc3dcSJack F Vogel u64 queues = 0; 2109758cc3dcSJack F Vogel int hung = 0; 2110758cc3dcSJack F Vogel 2111758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 2112758cc3dcSJack F Vogel 2113758cc3dcSJack F Vogel /* Check for pluggable optics */ 2114758cc3dcSJack F Vogel if (adapter->sfp_probe) 2115758cc3dcSJack F Vogel if (!ixgbe_sfp_probe(adapter)) 2116758cc3dcSJack F Vogel goto out; /* Nothing to do */ 2117758cc3dcSJack F Vogel 2118758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 2119758cc3dcSJack F Vogel ixgbe_update_stats_counters(adapter); 2120758cc3dcSJack F Vogel 2121758cc3dcSJack F Vogel /* 2122758cc3dcSJack F Vogel ** Check the TX queues status 2123758cc3dcSJack F Vogel ** - mark hung queues so we don't schedule on them 2124758cc3dcSJack F Vogel ** - watchdog only if all queues show hung 2125758cc3dcSJack F Vogel */ 2126758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 2127758cc3dcSJack F Vogel /* Keep track of queues with work for soft irq */ 2128758cc3dcSJack F Vogel if (que->txr->busy) 2129758cc3dcSJack F Vogel queues |= ((u64)1 << que->me); 2130758cc3dcSJack F Vogel /* 2131758cc3dcSJack F Vogel ** Each time txeof runs without cleaning, but there 2132758cc3dcSJack F Vogel ** are uncleaned descriptors it increments busy. If 2133758cc3dcSJack F Vogel ** we get to the MAX we declare it hung. 2134758cc3dcSJack F Vogel */ 2135758cc3dcSJack F Vogel if (que->busy == IXGBE_QUEUE_HUNG) { 2136758cc3dcSJack F Vogel ++hung; 2137758cc3dcSJack F Vogel /* Mark the queue as inactive */ 2138758cc3dcSJack F Vogel adapter->active_queues &= ~((u64)1 << que->me); 2139758cc3dcSJack F Vogel continue; 2140758cc3dcSJack F Vogel } else { 2141758cc3dcSJack F Vogel /* Check if we've come back from hung */ 2142758cc3dcSJack F Vogel if ((adapter->active_queues & ((u64)1 << que->me)) == 0) 2143758cc3dcSJack F Vogel adapter->active_queues |= ((u64)1 << que->me); 2144758cc3dcSJack F Vogel } 2145758cc3dcSJack F Vogel if (que->busy >= IXGBE_MAX_TX_BUSY) { 2146758cc3dcSJack F Vogel device_printf(dev,"Warning queue %d " 2147758cc3dcSJack F Vogel "appears to be hung!\n", i); 2148758cc3dcSJack F Vogel que->txr->busy = IXGBE_QUEUE_HUNG; 2149758cc3dcSJack F Vogel ++hung; 2150758cc3dcSJack F Vogel } 2151758cc3dcSJack F Vogel 2152758cc3dcSJack F Vogel } 2153758cc3dcSJack F Vogel 2154758cc3dcSJack F Vogel /* Only truly watchdog if all queues show hung */ 2155758cc3dcSJack F Vogel if (hung == adapter->num_queues) 2156758cc3dcSJack F Vogel goto watchdog; 2157758cc3dcSJack F Vogel else if (queues != 0) { /* Force an IRQ on queues with work */ 2158758cc3dcSJack F Vogel ixgbe_rearm_queues(adapter, queues); 2159758cc3dcSJack F Vogel } 2160758cc3dcSJack F Vogel 2161758cc3dcSJack F Vogel out: 2162758cc3dcSJack F Vogel callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); 2163758cc3dcSJack F Vogel return; 2164758cc3dcSJack F Vogel 2165758cc3dcSJack F Vogel watchdog: 2166758cc3dcSJack F Vogel device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); 2167758cc3dcSJack F Vogel adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2168758cc3dcSJack F Vogel adapter->watchdog_events++; 2169758cc3dcSJack F Vogel ixgbe_init_locked(adapter); 2170758cc3dcSJack F Vogel } 2171758cc3dcSJack F Vogel 217248056c88SJack F Vogel 2173758cc3dcSJack F Vogel /* 2174758cc3dcSJack F Vogel ** Note: this routine updates the OS on the link state 2175758cc3dcSJack F Vogel ** the real check of the hardware only happens with 2176758cc3dcSJack F Vogel ** a link interrupt. 2177758cc3dcSJack F Vogel */ 2178758cc3dcSJack F Vogel static void 2179758cc3dcSJack F Vogel ixgbe_update_link_status(struct adapter *adapter) 2180758cc3dcSJack F Vogel { 2181758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 2182758cc3dcSJack F Vogel device_t dev = adapter->dev; 2183758cc3dcSJack F Vogel 2184758cc3dcSJack F Vogel if (adapter->link_up){ 2185758cc3dcSJack F Vogel if (adapter->link_active == FALSE) { 2186758cc3dcSJack F Vogel if (bootverbose) 2187758cc3dcSJack F Vogel device_printf(dev,"Link is up %d Gbps %s \n", 2188758cc3dcSJack F Vogel ((adapter->link_speed == 128)? 10:1), 2189758cc3dcSJack F Vogel "Full Duplex"); 2190758cc3dcSJack F Vogel adapter->link_active = TRUE; 2191758cc3dcSJack F Vogel /* Update any Flow Control changes */ 2192758cc3dcSJack F Vogel ixgbe_fc_enable(&adapter->hw); 21936f37f232SEric Joyner /* Update DMA coalescing config */ 21946f37f232SEric Joyner ixgbe_config_dmac(adapter); 2195758cc3dcSJack F Vogel if_link_state_change(ifp, LINK_STATE_UP); 219648056c88SJack F Vogel #ifdef PCI_IOV 219748056c88SJack F Vogel ixgbe_ping_all_vfs(adapter); 219848056c88SJack F Vogel #endif 2199758cc3dcSJack F Vogel } 2200758cc3dcSJack F Vogel } else { /* Link down */ 2201758cc3dcSJack F Vogel if (adapter->link_active == TRUE) { 2202758cc3dcSJack F Vogel if (bootverbose) 2203758cc3dcSJack F Vogel device_printf(dev,"Link is Down\n"); 2204758cc3dcSJack F Vogel if_link_state_change(ifp, LINK_STATE_DOWN); 2205758cc3dcSJack F Vogel adapter->link_active = FALSE; 220648056c88SJack F Vogel #ifdef PCI_IOV 220748056c88SJack F Vogel ixgbe_ping_all_vfs(adapter); 220848056c88SJack F Vogel #endif 2209758cc3dcSJack F Vogel } 2210758cc3dcSJack F Vogel } 2211758cc3dcSJack F Vogel 2212758cc3dcSJack F Vogel return; 2213758cc3dcSJack F Vogel } 2214758cc3dcSJack F Vogel 2215758cc3dcSJack F Vogel 2216758cc3dcSJack F Vogel /********************************************************************* 2217758cc3dcSJack F Vogel * 2218758cc3dcSJack F Vogel * This routine disables all traffic on the adapter by issuing a 2219758cc3dcSJack F Vogel * global reset on the MAC and deallocates TX/RX buffers. 2220758cc3dcSJack F Vogel * 2221758cc3dcSJack F Vogel **********************************************************************/ 2222758cc3dcSJack F Vogel 2223758cc3dcSJack F Vogel static void 2224758cc3dcSJack F Vogel ixgbe_stop(void *arg) 2225758cc3dcSJack F Vogel { 2226758cc3dcSJack F Vogel struct ifnet *ifp; 2227758cc3dcSJack F Vogel struct adapter *adapter = arg; 2228758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2229758cc3dcSJack F Vogel ifp = adapter->ifp; 2230758cc3dcSJack F Vogel 2231758cc3dcSJack F Vogel mtx_assert(&adapter->core_mtx, MA_OWNED); 2232758cc3dcSJack F Vogel 2233758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_stop: begin\n"); 2234758cc3dcSJack F Vogel ixgbe_disable_intr(adapter); 2235758cc3dcSJack F Vogel callout_stop(&adapter->timer); 2236758cc3dcSJack F Vogel 2237758cc3dcSJack F Vogel /* Let the stack know...*/ 2238758cc3dcSJack F Vogel ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2239758cc3dcSJack F Vogel 2240758cc3dcSJack F Vogel ixgbe_reset_hw(hw); 2241758cc3dcSJack F Vogel hw->adapter_stopped = FALSE; 2242758cc3dcSJack F Vogel ixgbe_stop_adapter(hw); 2243758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82599EB) 2244758cc3dcSJack F Vogel ixgbe_stop_mac_link_on_d3_82599(hw); 2245758cc3dcSJack F Vogel /* Turn off the laser - noop with no optics */ 2246758cc3dcSJack F Vogel ixgbe_disable_tx_laser(hw); 2247758cc3dcSJack F Vogel 2248758cc3dcSJack F Vogel /* Update the stack */ 2249758cc3dcSJack F Vogel adapter->link_up = FALSE; 2250758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 2251758cc3dcSJack F Vogel 2252758cc3dcSJack F Vogel /* reprogram the RAR[0] in case user changed it. */ 2253758cc3dcSJack F Vogel ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); 2254758cc3dcSJack F Vogel 2255758cc3dcSJack F Vogel return; 2256758cc3dcSJack F Vogel } 2257758cc3dcSJack F Vogel 2258758cc3dcSJack F Vogel 2259758cc3dcSJack F Vogel /********************************************************************* 2260758cc3dcSJack F Vogel * 2261758cc3dcSJack F Vogel * Determine hardware revision. 2262758cc3dcSJack F Vogel * 2263758cc3dcSJack F Vogel **********************************************************************/ 2264758cc3dcSJack F Vogel static void 2265758cc3dcSJack F Vogel ixgbe_identify_hardware(struct adapter *adapter) 2266758cc3dcSJack F Vogel { 2267758cc3dcSJack F Vogel device_t dev = adapter->dev; 2268758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2269758cc3dcSJack F Vogel 2270758cc3dcSJack F Vogel /* Save off the information about this board */ 2271758cc3dcSJack F Vogel hw->vendor_id = pci_get_vendor(dev); 2272758cc3dcSJack F Vogel hw->device_id = pci_get_device(dev); 2273758cc3dcSJack F Vogel hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 2274758cc3dcSJack F Vogel hw->subsystem_vendor_id = 2275758cc3dcSJack F Vogel pci_read_config(dev, PCIR_SUBVEND_0, 2); 2276758cc3dcSJack F Vogel hw->subsystem_device_id = 2277758cc3dcSJack F Vogel pci_read_config(dev, PCIR_SUBDEV_0, 2); 2278758cc3dcSJack F Vogel 2279758cc3dcSJack F Vogel /* 2280758cc3dcSJack F Vogel ** Make sure BUSMASTER is set 2281758cc3dcSJack F Vogel */ 2282758cc3dcSJack F Vogel pci_enable_busmaster(dev); 2283758cc3dcSJack F Vogel 2284758cc3dcSJack F Vogel /* We need this here to set the num_segs below */ 2285758cc3dcSJack F Vogel ixgbe_set_mac_type(hw); 2286758cc3dcSJack F Vogel 22876f37f232SEric Joyner /* Pick up the 82599 settings */ 2288758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 2289758cc3dcSJack F Vogel hw->phy.smart_speed = ixgbe_smart_speed; 2290758cc3dcSJack F Vogel adapter->num_segs = IXGBE_82599_SCATTER; 2291758cc3dcSJack F Vogel } else 2292758cc3dcSJack F Vogel adapter->num_segs = IXGBE_82598_SCATTER; 2293758cc3dcSJack F Vogel 2294758cc3dcSJack F Vogel return; 2295758cc3dcSJack F Vogel } 2296758cc3dcSJack F Vogel 2297758cc3dcSJack F Vogel /********************************************************************* 2298758cc3dcSJack F Vogel * 2299758cc3dcSJack F Vogel * Determine optic type 2300758cc3dcSJack F Vogel * 2301758cc3dcSJack F Vogel **********************************************************************/ 2302758cc3dcSJack F Vogel static void 2303758cc3dcSJack F Vogel ixgbe_setup_optics(struct adapter *adapter) 2304758cc3dcSJack F Vogel { 2305758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2306758cc3dcSJack F Vogel int layer; 2307758cc3dcSJack F Vogel 230848056c88SJack F Vogel layer = adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); 2309758cc3dcSJack F Vogel 2310758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) { 2311758cc3dcSJack F Vogel adapter->optics = IFM_10G_T; 2312758cc3dcSJack F Vogel return; 2313758cc3dcSJack F Vogel } 2314758cc3dcSJack F Vogel 2315758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) { 2316758cc3dcSJack F Vogel adapter->optics = IFM_1000_T; 2317758cc3dcSJack F Vogel return; 2318758cc3dcSJack F Vogel } 2319758cc3dcSJack F Vogel 2320758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) { 2321758cc3dcSJack F Vogel adapter->optics = IFM_1000_SX; 2322758cc3dcSJack F Vogel return; 2323758cc3dcSJack F Vogel } 2324758cc3dcSJack F Vogel 2325758cc3dcSJack F Vogel if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_LR | 2326758cc3dcSJack F Vogel IXGBE_PHYSICAL_LAYER_10GBASE_LRM)) { 2327758cc3dcSJack F Vogel adapter->optics = IFM_10G_LR; 2328758cc3dcSJack F Vogel return; 2329758cc3dcSJack F Vogel } 2330758cc3dcSJack F Vogel 2331758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { 2332758cc3dcSJack F Vogel adapter->optics = IFM_10G_SR; 2333758cc3dcSJack F Vogel return; 2334758cc3dcSJack F Vogel } 2335758cc3dcSJack F Vogel 2336758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU) { 2337758cc3dcSJack F Vogel adapter->optics = IFM_10G_TWINAX; 2338758cc3dcSJack F Vogel return; 2339758cc3dcSJack F Vogel } 2340758cc3dcSJack F Vogel 2341758cc3dcSJack F Vogel if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | 2342758cc3dcSJack F Vogel IXGBE_PHYSICAL_LAYER_10GBASE_CX4)) { 2343758cc3dcSJack F Vogel adapter->optics = IFM_10G_CX4; 2344758cc3dcSJack F Vogel return; 2345758cc3dcSJack F Vogel } 2346758cc3dcSJack F Vogel 2347758cc3dcSJack F Vogel /* If we get here just set the default */ 2348758cc3dcSJack F Vogel adapter->optics = IFM_ETHER | IFM_AUTO; 2349758cc3dcSJack F Vogel return; 2350758cc3dcSJack F Vogel } 2351758cc3dcSJack F Vogel 2352758cc3dcSJack F Vogel /********************************************************************* 2353758cc3dcSJack F Vogel * 2354758cc3dcSJack F Vogel * Setup the Legacy or MSI Interrupt handler 2355758cc3dcSJack F Vogel * 2356758cc3dcSJack F Vogel **********************************************************************/ 2357758cc3dcSJack F Vogel static int 2358758cc3dcSJack F Vogel ixgbe_allocate_legacy(struct adapter *adapter) 2359758cc3dcSJack F Vogel { 2360758cc3dcSJack F Vogel device_t dev = adapter->dev; 2361758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2362758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2363758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2364758cc3dcSJack F Vogel #endif 2365758cc3dcSJack F Vogel int error, rid = 0; 2366758cc3dcSJack F Vogel 2367758cc3dcSJack F Vogel /* MSI RID at 1 */ 2368758cc3dcSJack F Vogel if (adapter->msix == 1) 2369758cc3dcSJack F Vogel rid = 1; 2370758cc3dcSJack F Vogel 2371758cc3dcSJack F Vogel /* We allocate a single interrupt resource */ 2372758cc3dcSJack F Vogel adapter->res = bus_alloc_resource_any(dev, 2373758cc3dcSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 2374758cc3dcSJack F Vogel if (adapter->res == NULL) { 2375758cc3dcSJack F Vogel device_printf(dev, "Unable to allocate bus resource: " 2376758cc3dcSJack F Vogel "interrupt\n"); 2377758cc3dcSJack F Vogel return (ENXIO); 2378758cc3dcSJack F Vogel } 2379758cc3dcSJack F Vogel 2380758cc3dcSJack F Vogel /* 2381758cc3dcSJack F Vogel * Try allocating a fast interrupt and the associated deferred 2382758cc3dcSJack F Vogel * processing contexts. 2383758cc3dcSJack F Vogel */ 2384758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2385758cc3dcSJack F Vogel TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); 2386758cc3dcSJack F Vogel #endif 2387758cc3dcSJack F Vogel TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); 2388758cc3dcSJack F Vogel que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, 2389758cc3dcSJack F Vogel taskqueue_thread_enqueue, &que->tq); 2390758cc3dcSJack F Vogel taskqueue_start_threads(&que->tq, 1, PI_NET, "%s ixq", 2391758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2392758cc3dcSJack F Vogel 2393758cc3dcSJack F Vogel /* Tasklets for Link, SFP and Multispeed Fiber */ 2394758cc3dcSJack F Vogel TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); 2395758cc3dcSJack F Vogel TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); 2396758cc3dcSJack F Vogel TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); 23976f37f232SEric Joyner TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); 2398758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 2399758cc3dcSJack F Vogel TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); 2400758cc3dcSJack F Vogel #endif 2401758cc3dcSJack F Vogel adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, 2402758cc3dcSJack F Vogel taskqueue_thread_enqueue, &adapter->tq); 2403758cc3dcSJack F Vogel taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", 2404758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2405758cc3dcSJack F Vogel 2406758cc3dcSJack F Vogel if ((error = bus_setup_intr(dev, adapter->res, 2407758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq, 2408758cc3dcSJack F Vogel que, &adapter->tag)) != 0) { 2409758cc3dcSJack F Vogel device_printf(dev, "Failed to register fast interrupt " 2410758cc3dcSJack F Vogel "handler: %d\n", error); 2411758cc3dcSJack F Vogel taskqueue_free(que->tq); 2412758cc3dcSJack F Vogel taskqueue_free(adapter->tq); 2413758cc3dcSJack F Vogel que->tq = NULL; 2414758cc3dcSJack F Vogel adapter->tq = NULL; 2415758cc3dcSJack F Vogel return (error); 2416758cc3dcSJack F Vogel } 2417758cc3dcSJack F Vogel /* For simplicity in the handlers */ 2418758cc3dcSJack F Vogel adapter->active_queues = IXGBE_EIMS_ENABLE_MASK; 2419758cc3dcSJack F Vogel 2420758cc3dcSJack F Vogel return (0); 2421758cc3dcSJack F Vogel } 2422758cc3dcSJack F Vogel 2423758cc3dcSJack F Vogel 2424758cc3dcSJack F Vogel /********************************************************************* 2425758cc3dcSJack F Vogel * 2426758cc3dcSJack F Vogel * Setup MSIX Interrupt resources and handlers 2427758cc3dcSJack F Vogel * 2428758cc3dcSJack F Vogel **********************************************************************/ 2429758cc3dcSJack F Vogel static int 2430758cc3dcSJack F Vogel ixgbe_allocate_msix(struct adapter *adapter) 2431758cc3dcSJack F Vogel { 2432758cc3dcSJack F Vogel device_t dev = adapter->dev; 2433758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2434758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2435758cc3dcSJack F Vogel int error, rid, vector = 0; 2436758cc3dcSJack F Vogel int cpu_id = 0; 2437a1edda90SAdrian Chadd #ifdef RSS 2438a1edda90SAdrian Chadd cpuset_t cpu_mask; 2439a1edda90SAdrian Chadd #endif 2440758cc3dcSJack F Vogel 2441758cc3dcSJack F Vogel #ifdef RSS 2442758cc3dcSJack F Vogel /* 2443758cc3dcSJack F Vogel * If we're doing RSS, the number of queues needs to 2444758cc3dcSJack F Vogel * match the number of RSS buckets that are configured. 2445758cc3dcSJack F Vogel * 2446758cc3dcSJack F Vogel * + If there's more queues than RSS buckets, we'll end 2447758cc3dcSJack F Vogel * up with queues that get no traffic. 2448758cc3dcSJack F Vogel * 2449758cc3dcSJack F Vogel * + If there's more RSS buckets than queues, we'll end 2450758cc3dcSJack F Vogel * up having multiple RSS buckets map to the same queue, 2451758cc3dcSJack F Vogel * so there'll be some contention. 2452758cc3dcSJack F Vogel */ 2453758cc3dcSJack F Vogel if (adapter->num_queues != rss_getnumbuckets()) { 2454758cc3dcSJack F Vogel device_printf(dev, 2455758cc3dcSJack F Vogel "%s: number of queues (%d) != number of RSS buckets (%d)" 2456758cc3dcSJack F Vogel "; performance will be impacted.\n", 2457758cc3dcSJack F Vogel __func__, 2458758cc3dcSJack F Vogel adapter->num_queues, 2459758cc3dcSJack F Vogel rss_getnumbuckets()); 2460758cc3dcSJack F Vogel } 2461758cc3dcSJack F Vogel #endif 2462758cc3dcSJack F Vogel 2463758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { 2464758cc3dcSJack F Vogel rid = vector + 1; 2465758cc3dcSJack F Vogel que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 2466758cc3dcSJack F Vogel RF_SHAREABLE | RF_ACTIVE); 2467758cc3dcSJack F Vogel if (que->res == NULL) { 2468758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate" 2469758cc3dcSJack F Vogel " bus resource: que interrupt [%d]\n", vector); 2470758cc3dcSJack F Vogel return (ENXIO); 2471758cc3dcSJack F Vogel } 2472758cc3dcSJack F Vogel /* Set the handler function */ 2473758cc3dcSJack F Vogel error = bus_setup_intr(dev, que->res, 2474758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 2475758cc3dcSJack F Vogel ixgbe_msix_que, que, &que->tag); 2476758cc3dcSJack F Vogel if (error) { 2477758cc3dcSJack F Vogel que->res = NULL; 2478758cc3dcSJack F Vogel device_printf(dev, "Failed to register QUE handler"); 2479758cc3dcSJack F Vogel return (error); 2480758cc3dcSJack F Vogel } 2481758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504 2482a9ca1c79SSean Bruno bus_describe_intr(dev, que->res, que->tag, "q%d", i); 2483758cc3dcSJack F Vogel #endif 2484758cc3dcSJack F Vogel que->msix = vector; 2485758cc3dcSJack F Vogel adapter->active_queues |= (u64)(1 << que->msix); 2486758cc3dcSJack F Vogel #ifdef RSS 2487758cc3dcSJack F Vogel /* 2488758cc3dcSJack F Vogel * The queue ID is used as the RSS layer bucket ID. 2489758cc3dcSJack F Vogel * We look up the queue ID -> RSS CPU ID and select 2490758cc3dcSJack F Vogel * that. 2491758cc3dcSJack F Vogel */ 2492758cc3dcSJack F Vogel cpu_id = rss_getcpu(i % rss_getnumbuckets()); 2493758cc3dcSJack F Vogel #else 2494758cc3dcSJack F Vogel /* 2495758cc3dcSJack F Vogel * Bind the msix vector, and thus the 2496758cc3dcSJack F Vogel * rings to the corresponding cpu. 2497758cc3dcSJack F Vogel * 2498758cc3dcSJack F Vogel * This just happens to match the default RSS round-robin 2499758cc3dcSJack F Vogel * bucket -> queue -> CPU allocation. 2500758cc3dcSJack F Vogel */ 2501758cc3dcSJack F Vogel if (adapter->num_queues > 1) 2502758cc3dcSJack F Vogel cpu_id = i; 2503758cc3dcSJack F Vogel #endif 2504758cc3dcSJack F Vogel if (adapter->num_queues > 1) 2505758cc3dcSJack F Vogel bus_bind_intr(dev, que->res, cpu_id); 250648056c88SJack F Vogel #ifdef IXGBE_DEBUG 2507758cc3dcSJack F Vogel #ifdef RSS 2508758cc3dcSJack F Vogel device_printf(dev, 2509758cc3dcSJack F Vogel "Bound RSS bucket %d to CPU %d\n", 2510758cc3dcSJack F Vogel i, cpu_id); 2511758cc3dcSJack F Vogel #else 2512758cc3dcSJack F Vogel device_printf(dev, 2513758cc3dcSJack F Vogel "Bound queue %d to cpu %d\n", 2514758cc3dcSJack F Vogel i, cpu_id); 2515758cc3dcSJack F Vogel #endif 251648056c88SJack F Vogel #endif /* IXGBE_DEBUG */ 251748056c88SJack F Vogel 251848056c88SJack F Vogel 2519758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2520758cc3dcSJack F Vogel TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); 2521758cc3dcSJack F Vogel #endif 2522758cc3dcSJack F Vogel TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); 2523758cc3dcSJack F Vogel que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, 2524758cc3dcSJack F Vogel taskqueue_thread_enqueue, &que->tq); 2525758cc3dcSJack F Vogel #ifdef RSS 2526a1edda90SAdrian Chadd CPU_SETOF(cpu_id, &cpu_mask); 2527a1edda90SAdrian Chadd taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, 2528a1edda90SAdrian Chadd &cpu_mask, 2529758cc3dcSJack F Vogel "%s (bucket %d)", 2530758cc3dcSJack F Vogel device_get_nameunit(adapter->dev), 2531758cc3dcSJack F Vogel cpu_id); 2532758cc3dcSJack F Vogel #else 2533a9ca1c79SSean Bruno taskqueue_start_threads(&que->tq, 1, PI_NET, "%s:q%d", 2534a9ca1c79SSean Bruno device_get_nameunit(adapter->dev), i); 2535758cc3dcSJack F Vogel #endif 2536758cc3dcSJack F Vogel } 2537758cc3dcSJack F Vogel 2538758cc3dcSJack F Vogel /* and Link */ 2539758cc3dcSJack F Vogel rid = vector + 1; 2540758cc3dcSJack F Vogel adapter->res = bus_alloc_resource_any(dev, 2541758cc3dcSJack F Vogel SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); 2542758cc3dcSJack F Vogel if (!adapter->res) { 2543758cc3dcSJack F Vogel device_printf(dev,"Unable to allocate" 2544758cc3dcSJack F Vogel " bus resource: Link interrupt [%d]\n", rid); 2545758cc3dcSJack F Vogel return (ENXIO); 2546758cc3dcSJack F Vogel } 2547758cc3dcSJack F Vogel /* Set the link handler function */ 2548758cc3dcSJack F Vogel error = bus_setup_intr(dev, adapter->res, 2549758cc3dcSJack F Vogel INTR_TYPE_NET | INTR_MPSAFE, NULL, 2550758cc3dcSJack F Vogel ixgbe_msix_link, adapter, &adapter->tag); 2551758cc3dcSJack F Vogel if (error) { 2552758cc3dcSJack F Vogel adapter->res = NULL; 2553758cc3dcSJack F Vogel device_printf(dev, "Failed to register LINK handler"); 2554758cc3dcSJack F Vogel return (error); 2555758cc3dcSJack F Vogel } 2556758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504 2557758cc3dcSJack F Vogel bus_describe_intr(dev, adapter->res, adapter->tag, "link"); 2558758cc3dcSJack F Vogel #endif 2559758cc3dcSJack F Vogel adapter->vector = vector; 2560758cc3dcSJack F Vogel /* Tasklets for Link, SFP and Multispeed Fiber */ 2561758cc3dcSJack F Vogel TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); 2562758cc3dcSJack F Vogel TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); 2563758cc3dcSJack F Vogel TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); 256448056c88SJack F Vogel #ifdef PCI_IOV 256548056c88SJack F Vogel TASK_INIT(&adapter->mbx_task, 0, ixgbe_handle_mbx, adapter); 256648056c88SJack F Vogel #endif 25676f37f232SEric Joyner TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); 2568758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 2569758cc3dcSJack F Vogel TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); 2570758cc3dcSJack F Vogel #endif 2571758cc3dcSJack F Vogel adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, 2572758cc3dcSJack F Vogel taskqueue_thread_enqueue, &adapter->tq); 2573758cc3dcSJack F Vogel taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", 2574758cc3dcSJack F Vogel device_get_nameunit(adapter->dev)); 2575758cc3dcSJack F Vogel 2576758cc3dcSJack F Vogel return (0); 2577758cc3dcSJack F Vogel } 2578758cc3dcSJack F Vogel 2579758cc3dcSJack F Vogel /* 2580758cc3dcSJack F Vogel * Setup Either MSI/X or MSI 2581758cc3dcSJack F Vogel */ 2582758cc3dcSJack F Vogel static int 2583758cc3dcSJack F Vogel ixgbe_setup_msix(struct adapter *adapter) 2584758cc3dcSJack F Vogel { 2585758cc3dcSJack F Vogel device_t dev = adapter->dev; 2586758cc3dcSJack F Vogel int rid, want, queues, msgs; 2587758cc3dcSJack F Vogel 2588758cc3dcSJack F Vogel /* Override by tuneable */ 2589758cc3dcSJack F Vogel if (ixgbe_enable_msix == 0) 2590758cc3dcSJack F Vogel goto msi; 2591758cc3dcSJack F Vogel 2592758cc3dcSJack F Vogel /* First try MSI/X */ 2593758cc3dcSJack F Vogel msgs = pci_msix_count(dev); 2594758cc3dcSJack F Vogel if (msgs == 0) 2595758cc3dcSJack F Vogel goto msi; 2596758cc3dcSJack F Vogel rid = PCIR_BAR(MSIX_82598_BAR); 2597758cc3dcSJack F Vogel adapter->msix_mem = bus_alloc_resource_any(dev, 2598758cc3dcSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 2599758cc3dcSJack F Vogel if (adapter->msix_mem == NULL) { 2600758cc3dcSJack F Vogel rid += 4; /* 82599 maps in higher BAR */ 2601758cc3dcSJack F Vogel adapter->msix_mem = bus_alloc_resource_any(dev, 2602758cc3dcSJack F Vogel SYS_RES_MEMORY, &rid, RF_ACTIVE); 2603758cc3dcSJack F Vogel } 2604758cc3dcSJack F Vogel if (adapter->msix_mem == NULL) { 2605758cc3dcSJack F Vogel /* May not be enabled */ 2606758cc3dcSJack F Vogel device_printf(adapter->dev, 2607758cc3dcSJack F Vogel "Unable to map MSIX table \n"); 2608758cc3dcSJack F Vogel goto msi; 2609758cc3dcSJack F Vogel } 2610758cc3dcSJack F Vogel 2611758cc3dcSJack F Vogel /* Figure out a reasonable auto config value */ 2612758cc3dcSJack F Vogel queues = (mp_ncpus > (msgs - 1)) ? (msgs - 1) : mp_ncpus; 2613758cc3dcSJack F Vogel 2614758cc3dcSJack F Vogel #ifdef RSS 2615758cc3dcSJack F Vogel /* If we're doing RSS, clamp at the number of RSS buckets */ 2616758cc3dcSJack F Vogel if (queues > rss_getnumbuckets()) 2617758cc3dcSJack F Vogel queues = rss_getnumbuckets(); 2618758cc3dcSJack F Vogel #endif 2619758cc3dcSJack F Vogel 2620758cc3dcSJack F Vogel if (ixgbe_num_queues != 0) 2621758cc3dcSJack F Vogel queues = ixgbe_num_queues; 2622a9ca1c79SSean Bruno /* Set max queues to 8 when autoconfiguring */ 2623a9ca1c79SSean Bruno else if ((ixgbe_num_queues == 0) && (queues > 8)) 2624a9ca1c79SSean Bruno queues = 8; 2625758cc3dcSJack F Vogel 2626758cc3dcSJack F Vogel /* reflect correct sysctl value */ 2627758cc3dcSJack F Vogel ixgbe_num_queues = queues; 2628758cc3dcSJack F Vogel 2629758cc3dcSJack F Vogel /* 2630758cc3dcSJack F Vogel ** Want one vector (RX/TX pair) per queue 2631758cc3dcSJack F Vogel ** plus an additional for Link. 2632758cc3dcSJack F Vogel */ 2633758cc3dcSJack F Vogel want = queues + 1; 2634758cc3dcSJack F Vogel if (msgs >= want) 2635758cc3dcSJack F Vogel msgs = want; 2636758cc3dcSJack F Vogel else { 2637758cc3dcSJack F Vogel device_printf(adapter->dev, 2638758cc3dcSJack F Vogel "MSIX Configuration Problem, " 2639758cc3dcSJack F Vogel "%d vectors but %d queues wanted!\n", 2640758cc3dcSJack F Vogel msgs, want); 2641758cc3dcSJack F Vogel goto msi; 2642758cc3dcSJack F Vogel } 2643758cc3dcSJack F Vogel if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { 2644758cc3dcSJack F Vogel device_printf(adapter->dev, 2645758cc3dcSJack F Vogel "Using MSIX interrupts with %d vectors\n", msgs); 2646758cc3dcSJack F Vogel adapter->num_queues = queues; 2647758cc3dcSJack F Vogel return (msgs); 2648758cc3dcSJack F Vogel } 2649758cc3dcSJack F Vogel /* 2650758cc3dcSJack F Vogel ** If MSIX alloc failed or provided us with 2651758cc3dcSJack F Vogel ** less than needed, free and fall through to MSI 2652758cc3dcSJack F Vogel */ 2653758cc3dcSJack F Vogel pci_release_msi(dev); 2654758cc3dcSJack F Vogel 2655758cc3dcSJack F Vogel msi: 2656758cc3dcSJack F Vogel if (adapter->msix_mem != NULL) { 2657758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2658758cc3dcSJack F Vogel rid, adapter->msix_mem); 2659758cc3dcSJack F Vogel adapter->msix_mem = NULL; 2660758cc3dcSJack F Vogel } 2661758cc3dcSJack F Vogel msgs = 1; 2662758cc3dcSJack F Vogel if (pci_alloc_msi(dev, &msgs) == 0) { 2663758cc3dcSJack F Vogel device_printf(adapter->dev, "Using an MSI interrupt\n"); 2664758cc3dcSJack F Vogel return (msgs); 2665758cc3dcSJack F Vogel } 2666758cc3dcSJack F Vogel device_printf(adapter->dev, "Using a Legacy interrupt\n"); 2667758cc3dcSJack F Vogel return (0); 2668758cc3dcSJack F Vogel } 2669758cc3dcSJack F Vogel 2670758cc3dcSJack F Vogel 2671758cc3dcSJack F Vogel static int 2672758cc3dcSJack F Vogel ixgbe_allocate_pci_resources(struct adapter *adapter) 2673758cc3dcSJack F Vogel { 2674758cc3dcSJack F Vogel int rid; 2675758cc3dcSJack F Vogel device_t dev = adapter->dev; 2676758cc3dcSJack F Vogel 2677758cc3dcSJack F Vogel rid = PCIR_BAR(0); 2678758cc3dcSJack F Vogel adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2679758cc3dcSJack F Vogel &rid, RF_ACTIVE); 2680758cc3dcSJack F Vogel 2681758cc3dcSJack F Vogel if (!(adapter->pci_mem)) { 2682758cc3dcSJack F Vogel device_printf(dev, "Unable to allocate bus resource: memory\n"); 2683758cc3dcSJack F Vogel return (ENXIO); 2684758cc3dcSJack F Vogel } 2685758cc3dcSJack F Vogel 2686a9ca1c79SSean Bruno /* Save bus_space values for READ/WRITE_REG macros */ 2687758cc3dcSJack F Vogel adapter->osdep.mem_bus_space_tag = 2688758cc3dcSJack F Vogel rman_get_bustag(adapter->pci_mem); 2689758cc3dcSJack F Vogel adapter->osdep.mem_bus_space_handle = 2690758cc3dcSJack F Vogel rman_get_bushandle(adapter->pci_mem); 2691a9ca1c79SSean Bruno /* Set hw values for shared code */ 2692758cc3dcSJack F Vogel adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle; 2693a9ca1c79SSean Bruno adapter->hw.back = adapter; 2694758cc3dcSJack F Vogel 2695a9ca1c79SSean Bruno /* Default to 1 queue if MSI-X setup fails */ 2696758cc3dcSJack F Vogel adapter->num_queues = 1; 2697758cc3dcSJack F Vogel 2698758cc3dcSJack F Vogel /* 2699a9ca1c79SSean Bruno ** Now setup MSI or MSI-X, should 2700758cc3dcSJack F Vogel ** return us the number of supported 2701758cc3dcSJack F Vogel ** vectors. (Will be 1 for MSI) 2702758cc3dcSJack F Vogel */ 2703758cc3dcSJack F Vogel adapter->msix = ixgbe_setup_msix(adapter); 2704758cc3dcSJack F Vogel return (0); 2705758cc3dcSJack F Vogel } 2706758cc3dcSJack F Vogel 2707758cc3dcSJack F Vogel static void 2708758cc3dcSJack F Vogel ixgbe_free_pci_resources(struct adapter * adapter) 2709758cc3dcSJack F Vogel { 2710758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 2711758cc3dcSJack F Vogel device_t dev = adapter->dev; 2712758cc3dcSJack F Vogel int rid, memrid; 2713758cc3dcSJack F Vogel 2714758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) 2715758cc3dcSJack F Vogel memrid = PCIR_BAR(MSIX_82598_BAR); 2716758cc3dcSJack F Vogel else 2717758cc3dcSJack F Vogel memrid = PCIR_BAR(MSIX_82599_BAR); 2718758cc3dcSJack F Vogel 2719758cc3dcSJack F Vogel /* 2720758cc3dcSJack F Vogel ** There is a slight possibility of a failure mode 2721758cc3dcSJack F Vogel ** in attach that will result in entering this function 2722758cc3dcSJack F Vogel ** before interrupt resources have been initialized, and 2723758cc3dcSJack F Vogel ** in that case we do not want to execute the loops below 2724758cc3dcSJack F Vogel ** We can detect this reliably by the state of the adapter 2725758cc3dcSJack F Vogel ** res pointer. 2726758cc3dcSJack F Vogel */ 2727758cc3dcSJack F Vogel if (adapter->res == NULL) 2728758cc3dcSJack F Vogel goto mem; 2729758cc3dcSJack F Vogel 2730758cc3dcSJack F Vogel /* 2731758cc3dcSJack F Vogel ** Release all msix queue resources: 2732758cc3dcSJack F Vogel */ 2733758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 2734758cc3dcSJack F Vogel rid = que->msix + 1; 2735758cc3dcSJack F Vogel if (que->tag != NULL) { 2736758cc3dcSJack F Vogel bus_teardown_intr(dev, que->res, que->tag); 2737758cc3dcSJack F Vogel que->tag = NULL; 2738758cc3dcSJack F Vogel } 2739758cc3dcSJack F Vogel if (que->res != NULL) 2740758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); 2741758cc3dcSJack F Vogel } 2742758cc3dcSJack F Vogel 2743758cc3dcSJack F Vogel 2744758cc3dcSJack F Vogel /* Clean the Legacy or Link interrupt last */ 2745758cc3dcSJack F Vogel if (adapter->vector) /* we are doing MSIX */ 2746758cc3dcSJack F Vogel rid = adapter->vector + 1; 2747758cc3dcSJack F Vogel else 2748758cc3dcSJack F Vogel (adapter->msix != 0) ? (rid = 1):(rid = 0); 2749758cc3dcSJack F Vogel 2750758cc3dcSJack F Vogel if (adapter->tag != NULL) { 2751758cc3dcSJack F Vogel bus_teardown_intr(dev, adapter->res, adapter->tag); 2752758cc3dcSJack F Vogel adapter->tag = NULL; 2753758cc3dcSJack F Vogel } 2754758cc3dcSJack F Vogel if (adapter->res != NULL) 2755758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); 2756758cc3dcSJack F Vogel 2757758cc3dcSJack F Vogel mem: 2758758cc3dcSJack F Vogel if (adapter->msix) 2759758cc3dcSJack F Vogel pci_release_msi(dev); 2760758cc3dcSJack F Vogel 2761758cc3dcSJack F Vogel if (adapter->msix_mem != NULL) 2762758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2763758cc3dcSJack F Vogel memrid, adapter->msix_mem); 2764758cc3dcSJack F Vogel 2765758cc3dcSJack F Vogel if (adapter->pci_mem != NULL) 2766758cc3dcSJack F Vogel bus_release_resource(dev, SYS_RES_MEMORY, 2767758cc3dcSJack F Vogel PCIR_BAR(0), adapter->pci_mem); 2768758cc3dcSJack F Vogel 2769758cc3dcSJack F Vogel return; 2770758cc3dcSJack F Vogel } 2771758cc3dcSJack F Vogel 2772758cc3dcSJack F Vogel /********************************************************************* 2773758cc3dcSJack F Vogel * 2774758cc3dcSJack F Vogel * Setup networking device structure and register an interface. 2775758cc3dcSJack F Vogel * 2776758cc3dcSJack F Vogel **********************************************************************/ 2777758cc3dcSJack F Vogel static int 2778758cc3dcSJack F Vogel ixgbe_setup_interface(device_t dev, struct adapter *adapter) 2779758cc3dcSJack F Vogel { 2780758cc3dcSJack F Vogel struct ifnet *ifp; 2781758cc3dcSJack F Vogel 2782758cc3dcSJack F Vogel INIT_DEBUGOUT("ixgbe_setup_interface: begin"); 2783758cc3dcSJack F Vogel 2784758cc3dcSJack F Vogel ifp = adapter->ifp = if_alloc(IFT_ETHER); 2785758cc3dcSJack F Vogel if (ifp == NULL) { 2786758cc3dcSJack F Vogel device_printf(dev, "can not allocate ifnet structure\n"); 2787758cc3dcSJack F Vogel return (-1); 2788758cc3dcSJack F Vogel } 2789758cc3dcSJack F Vogel if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2790758cc3dcSJack F Vogel ifp->if_baudrate = IF_Gbps(10); 2791758cc3dcSJack F Vogel ifp->if_init = ixgbe_init; 2792758cc3dcSJack F Vogel ifp->if_softc = adapter; 2793758cc3dcSJack F Vogel ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2794758cc3dcSJack F Vogel ifp->if_ioctl = ixgbe_ioctl; 2795758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 2796758cc3dcSJack F Vogel if_setgetcounterfn(ifp, ixgbe_get_counter); 2797758cc3dcSJack F Vogel #endif 27986f37f232SEric Joyner #if __FreeBSD_version >= 1100045 27996f37f232SEric Joyner /* TSO parameters */ 28006f37f232SEric Joyner ifp->if_hw_tsomax = 65518; 28016f37f232SEric Joyner ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER; 28026f37f232SEric Joyner ifp->if_hw_tsomaxsegsize = 2048; 28036f37f232SEric Joyner #endif 2804758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX 2805758cc3dcSJack F Vogel ifp->if_transmit = ixgbe_mq_start; 2806758cc3dcSJack F Vogel ifp->if_qflush = ixgbe_qflush; 2807758cc3dcSJack F Vogel #else 2808758cc3dcSJack F Vogel ifp->if_start = ixgbe_start; 2809758cc3dcSJack F Vogel IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); 2810758cc3dcSJack F Vogel ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; 2811758cc3dcSJack F Vogel IFQ_SET_READY(&ifp->if_snd); 2812758cc3dcSJack F Vogel #endif 2813758cc3dcSJack F Vogel 2814758cc3dcSJack F Vogel ether_ifattach(ifp, adapter->hw.mac.addr); 2815758cc3dcSJack F Vogel 2816758cc3dcSJack F Vogel adapter->max_frame_size = 2817758cc3dcSJack F Vogel ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 2818758cc3dcSJack F Vogel 2819758cc3dcSJack F Vogel /* 2820758cc3dcSJack F Vogel * Tell the upper layer(s) we support long frames. 2821758cc3dcSJack F Vogel */ 2822758cc3dcSJack F Vogel ifp->if_hdrlen = sizeof(struct ether_vlan_header); 2823758cc3dcSJack F Vogel 2824a9ca1c79SSean Bruno /* Set capability flags */ 2825a9ca1c79SSean Bruno ifp->if_capabilities |= IFCAP_RXCSUM 2826a9ca1c79SSean Bruno | IFCAP_TXCSUM 2827a9ca1c79SSean Bruno | IFCAP_RXCSUM_IPV6 2828a9ca1c79SSean Bruno | IFCAP_TXCSUM_IPV6 2829a9ca1c79SSean Bruno | IFCAP_TSO4 2830a9ca1c79SSean Bruno | IFCAP_TSO6 2831a9ca1c79SSean Bruno | IFCAP_LRO 2832a9ca1c79SSean Bruno | IFCAP_VLAN_HWTAGGING 2833758cc3dcSJack F Vogel | IFCAP_VLAN_HWTSO 2834a9ca1c79SSean Bruno | IFCAP_VLAN_HWCSUM 2835a9ca1c79SSean Bruno | IFCAP_JUMBO_MTU 2836758cc3dcSJack F Vogel | IFCAP_VLAN_MTU 2837758cc3dcSJack F Vogel | IFCAP_HWSTATS; 2838a9ca1c79SSean Bruno 2839a9ca1c79SSean Bruno /* Enable the above capabilities by default */ 2840758cc3dcSJack F Vogel ifp->if_capenable = ifp->if_capabilities; 2841758cc3dcSJack F Vogel 2842758cc3dcSJack F Vogel /* 2843758cc3dcSJack F Vogel ** Don't turn this on by default, if vlans are 2844758cc3dcSJack F Vogel ** created on another pseudo device (eg. lagg) 2845758cc3dcSJack F Vogel ** then vlan events are not passed thru, breaking 2846758cc3dcSJack F Vogel ** operation, but with HW FILTER off it works. If 2847758cc3dcSJack F Vogel ** using vlans directly on the ixgbe driver you can 2848758cc3dcSJack F Vogel ** enable this and get full hardware tag filtering. 2849758cc3dcSJack F Vogel */ 2850758cc3dcSJack F Vogel ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 2851758cc3dcSJack F Vogel 2852758cc3dcSJack F Vogel /* 2853758cc3dcSJack F Vogel * Specify the media types supported by this adapter and register 2854758cc3dcSJack F Vogel * callbacks to update media and link information 2855758cc3dcSJack F Vogel */ 2856758cc3dcSJack F Vogel ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change, 2857758cc3dcSJack F Vogel ixgbe_media_status); 2858758cc3dcSJack F Vogel 2859a9ca1c79SSean Bruno adapter->phy_layer = ixgbe_get_supported_physical_layer(&adapter->hw); 2860758cc3dcSJack F Vogel ixgbe_add_media_types(adapter); 2861758cc3dcSJack F Vogel 2862a9ca1c79SSean Bruno /* Set autoselect media by default */ 2863758cc3dcSJack F Vogel ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); 2864758cc3dcSJack F Vogel 2865758cc3dcSJack F Vogel return (0); 2866758cc3dcSJack F Vogel } 2867758cc3dcSJack F Vogel 2868758cc3dcSJack F Vogel static void 2869758cc3dcSJack F Vogel ixgbe_add_media_types(struct adapter *adapter) 2870758cc3dcSJack F Vogel { 2871758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2872758cc3dcSJack F Vogel device_t dev = adapter->dev; 2873758cc3dcSJack F Vogel int layer; 2874758cc3dcSJack F Vogel 2875a9ca1c79SSean Bruno layer = adapter->phy_layer; 2876758cc3dcSJack F Vogel 2877758cc3dcSJack F Vogel /* Media types with matching FreeBSD media defines */ 2878758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) 2879758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL); 2880758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) 2881758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); 2882758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) 2883758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); 2884758cc3dcSJack F Vogel 2885758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || 2886758cc3dcSJack F Vogel layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) 2887758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); 2888758cc3dcSJack F Vogel 2889a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) { 2890758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 2891a9ca1c79SSean Bruno if (hw->phy.multispeed_fiber) 2892a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, NULL); 2893a9ca1c79SSean Bruno } 2894a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { 2895758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2896a9ca1c79SSean Bruno if (hw->phy.multispeed_fiber) 2897a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 2898a9ca1c79SSean Bruno } else if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) 2899a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); 2900758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) 2901758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2902758cc3dcSJack F Vogel 2903a9ca1c79SSean Bruno #ifdef IFM_ETH_XTYPE 2904a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) 2905a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KR, 0, NULL); 2906a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) 2907a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); 2908a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) 2909a9ca1c79SSean Bruno ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_KX, 0, NULL); 2910a9ca1c79SSean Bruno #else 2911758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) { 2912758cc3dcSJack F Vogel device_printf(dev, "Media supported: 10GbaseKR\n"); 29136f37f232SEric Joyner device_printf(dev, "10GbaseKR mapped to 10GbaseSR\n"); 29146f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 2915758cc3dcSJack F Vogel } 2916758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) { 2917758cc3dcSJack F Vogel device_printf(dev, "Media supported: 10GbaseKX4\n"); 29186f37f232SEric Joyner device_printf(dev, "10GbaseKX4 mapped to 10GbaseCX4\n"); 29196f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); 2920758cc3dcSJack F Vogel } 2921758cc3dcSJack F Vogel if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) { 2922758cc3dcSJack F Vogel device_printf(dev, "Media supported: 1000baseKX\n"); 29236f37f232SEric Joyner device_printf(dev, "1000baseKX mapped to 1000baseCX\n"); 29246f37f232SEric Joyner ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_CX, 0, NULL); 2925758cc3dcSJack F Vogel } 2926a9ca1c79SSean Bruno #endif 2927a9ca1c79SSean Bruno if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX) 2928758cc3dcSJack F Vogel device_printf(dev, "Media supported: 1000baseBX\n"); 2929758cc3dcSJack F Vogel 2930758cc3dcSJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) { 2931758cc3dcSJack F Vogel ifmedia_add(&adapter->media, 2932758cc3dcSJack F Vogel IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 2933758cc3dcSJack F Vogel ifmedia_add(&adapter->media, 2934758cc3dcSJack F Vogel IFM_ETHER | IFM_1000_T, 0, NULL); 2935758cc3dcSJack F Vogel } 2936758cc3dcSJack F Vogel 2937758cc3dcSJack F Vogel ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2938758cc3dcSJack F Vogel } 2939758cc3dcSJack F Vogel 2940758cc3dcSJack F Vogel static void 2941758cc3dcSJack F Vogel ixgbe_config_link(struct adapter *adapter) 2942758cc3dcSJack F Vogel { 2943758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2944758cc3dcSJack F Vogel u32 autoneg, err = 0; 2945758cc3dcSJack F Vogel bool sfp, negotiate; 2946758cc3dcSJack F Vogel 2947758cc3dcSJack F Vogel sfp = ixgbe_is_sfp(hw); 2948758cc3dcSJack F Vogel 2949758cc3dcSJack F Vogel if (sfp) { 2950758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->mod_task); 2951758cc3dcSJack F Vogel } else { 2952758cc3dcSJack F Vogel if (hw->mac.ops.check_link) 2953758cc3dcSJack F Vogel err = ixgbe_check_link(hw, &adapter->link_speed, 2954758cc3dcSJack F Vogel &adapter->link_up, FALSE); 2955758cc3dcSJack F Vogel if (err) 2956758cc3dcSJack F Vogel goto out; 2957758cc3dcSJack F Vogel autoneg = hw->phy.autoneg_advertised; 2958758cc3dcSJack F Vogel if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) 2959758cc3dcSJack F Vogel err = hw->mac.ops.get_link_capabilities(hw, 2960758cc3dcSJack F Vogel &autoneg, &negotiate); 2961758cc3dcSJack F Vogel if (err) 2962758cc3dcSJack F Vogel goto out; 2963758cc3dcSJack F Vogel if (hw->mac.ops.setup_link) 2964758cc3dcSJack F Vogel err = hw->mac.ops.setup_link(hw, 2965758cc3dcSJack F Vogel autoneg, adapter->link_up); 2966758cc3dcSJack F Vogel } 2967758cc3dcSJack F Vogel out: 2968758cc3dcSJack F Vogel return; 2969758cc3dcSJack F Vogel } 2970758cc3dcSJack F Vogel 2971758cc3dcSJack F Vogel 2972758cc3dcSJack F Vogel /********************************************************************* 2973758cc3dcSJack F Vogel * 2974758cc3dcSJack F Vogel * Enable transmit units. 2975758cc3dcSJack F Vogel * 2976758cc3dcSJack F Vogel **********************************************************************/ 2977758cc3dcSJack F Vogel static void 2978758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(struct adapter *adapter) 2979758cc3dcSJack F Vogel { 2980758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 2981758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 2982758cc3dcSJack F Vogel 2983758cc3dcSJack F Vogel /* Setup the Base and Length of the Tx Descriptor Ring */ 2984758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, txr++) { 2985758cc3dcSJack F Vogel u64 tdba = txr->txdma.dma_paddr; 2986758cc3dcSJack F Vogel u32 txctrl = 0; 298748056c88SJack F Vogel int j = txr->me; 2988758cc3dcSJack F Vogel 298948056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), 2990758cc3dcSJack F Vogel (tdba & 0x00000000ffffffffULL)); 299148056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); 299248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), 2993758cc3dcSJack F Vogel adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc)); 2994758cc3dcSJack F Vogel 2995758cc3dcSJack F Vogel /* Setup the HW Tx Head and Tail descriptor pointers */ 299648056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); 299748056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); 2998758cc3dcSJack F Vogel 2999758cc3dcSJack F Vogel /* Cache the tail address */ 300048056c88SJack F Vogel txr->tail = IXGBE_TDT(j); 3001758cc3dcSJack F Vogel 3002758cc3dcSJack F Vogel /* Disable Head Writeback */ 3003a9ca1c79SSean Bruno /* 3004a9ca1c79SSean Bruno * Note: for X550 series devices, these registers are actually 3005a9ca1c79SSean Bruno * prefixed with TPH_ isntead of DCA_, but the addresses and 3006a9ca1c79SSean Bruno * fields remain the same. 3007a9ca1c79SSean Bruno */ 3008758cc3dcSJack F Vogel switch (hw->mac.type) { 3009758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 301048056c88SJack F Vogel txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); 3011758cc3dcSJack F Vogel break; 3012758cc3dcSJack F Vogel default: 301348056c88SJack F Vogel txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j)); 3014758cc3dcSJack F Vogel break; 3015758cc3dcSJack F Vogel } 3016758cc3dcSJack F Vogel txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; 3017758cc3dcSJack F Vogel switch (hw->mac.type) { 3018758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 301948056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); 3020758cc3dcSJack F Vogel break; 3021758cc3dcSJack F Vogel default: 302248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl); 3023758cc3dcSJack F Vogel break; 3024758cc3dcSJack F Vogel } 3025758cc3dcSJack F Vogel 3026758cc3dcSJack F Vogel } 3027758cc3dcSJack F Vogel 3028758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 3029758cc3dcSJack F Vogel u32 dmatxctl, rttdcs; 303048056c88SJack F Vogel #ifdef PCI_IOV 303148056c88SJack F Vogel enum ixgbe_iov_mode mode = ixgbe_get_iov_mode(adapter); 303248056c88SJack F Vogel #endif 3033758cc3dcSJack F Vogel dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); 3034758cc3dcSJack F Vogel dmatxctl |= IXGBE_DMATXCTL_TE; 3035758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); 3036758cc3dcSJack F Vogel /* Disable arbiter to set MTQC */ 3037758cc3dcSJack F Vogel rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); 3038758cc3dcSJack F Vogel rttdcs |= IXGBE_RTTDCS_ARBDIS; 3039758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); 304048056c88SJack F Vogel #ifdef PCI_IOV 304148056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MTQC, ixgbe_get_mtqc(mode)); 304248056c88SJack F Vogel #else 3043758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); 304448056c88SJack F Vogel #endif 3045758cc3dcSJack F Vogel rttdcs &= ~IXGBE_RTTDCS_ARBDIS; 3046758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); 3047758cc3dcSJack F Vogel } 3048758cc3dcSJack F Vogel 3049758cc3dcSJack F Vogel return; 3050758cc3dcSJack F Vogel } 3051758cc3dcSJack F Vogel 3052758cc3dcSJack F Vogel static void 3053a9ca1c79SSean Bruno ixgbe_initialize_rss_mapping(struct adapter *adapter) 3054758cc3dcSJack F Vogel { 3055758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 305648056c88SJack F Vogel u32 reta = 0, mrqc, rss_key[10]; 305748056c88SJack F Vogel int queue_id, table_size, index_mult; 3058758cc3dcSJack F Vogel #ifdef RSS 305948056c88SJack F Vogel u32 rss_hash_config; 3060758cc3dcSJack F Vogel #endif 306148056c88SJack F Vogel #ifdef PCI_IOV 306248056c88SJack F Vogel enum ixgbe_iov_mode mode; 306348056c88SJack F Vogel #endif 3064758cc3dcSJack F Vogel 3065758cc3dcSJack F Vogel #ifdef RSS 3066758cc3dcSJack F Vogel /* Fetch the configured RSS key */ 3067758cc3dcSJack F Vogel rss_getkey((uint8_t *) &rss_key); 3068758cc3dcSJack F Vogel #else 3069758cc3dcSJack F Vogel /* set up random bits */ 3070758cc3dcSJack F Vogel arc4rand(&rss_key, sizeof(rss_key), 0); 3071758cc3dcSJack F Vogel #endif 3072758cc3dcSJack F Vogel 30736f37f232SEric Joyner /* Set multiplier for RETA setup and table size based on MAC */ 30746f37f232SEric Joyner index_mult = 0x1; 30756f37f232SEric Joyner table_size = 128; 30766f37f232SEric Joyner switch (adapter->hw.mac.type) { 30776f37f232SEric Joyner case ixgbe_mac_82598EB: 30786f37f232SEric Joyner index_mult = 0x11; 30796f37f232SEric Joyner break; 30806f37f232SEric Joyner case ixgbe_mac_X550: 30816f37f232SEric Joyner case ixgbe_mac_X550EM_x: 30826f37f232SEric Joyner table_size = 512; 30836f37f232SEric Joyner break; 30846f37f232SEric Joyner default: 30856f37f232SEric Joyner break; 30866f37f232SEric Joyner } 30876f37f232SEric Joyner 3088758cc3dcSJack F Vogel /* Set up the redirection table */ 308948056c88SJack F Vogel for (int i = 0, j = 0; i < table_size; i++, j++) { 3090758cc3dcSJack F Vogel if (j == adapter->num_queues) j = 0; 3091758cc3dcSJack F Vogel #ifdef RSS 3092758cc3dcSJack F Vogel /* 3093758cc3dcSJack F Vogel * Fetch the RSS bucket id for the given indirection entry. 3094758cc3dcSJack F Vogel * Cap it at the number of configured buckets (which is 3095758cc3dcSJack F Vogel * num_queues.) 3096758cc3dcSJack F Vogel */ 3097758cc3dcSJack F Vogel queue_id = rss_get_indirection_to_bucket(i); 3098758cc3dcSJack F Vogel queue_id = queue_id % adapter->num_queues; 3099758cc3dcSJack F Vogel #else 31006f37f232SEric Joyner queue_id = (j * index_mult); 3101758cc3dcSJack F Vogel #endif 3102758cc3dcSJack F Vogel /* 3103758cc3dcSJack F Vogel * The low 8 bits are for hash value (n+0); 3104758cc3dcSJack F Vogel * The next 8 bits are for hash value (n+1), etc. 3105758cc3dcSJack F Vogel */ 3106758cc3dcSJack F Vogel reta = reta >> 8; 3107758cc3dcSJack F Vogel reta = reta | ( ((uint32_t) queue_id) << 24); 3108758cc3dcSJack F Vogel if ((i & 3) == 3) { 31096f37f232SEric Joyner if (i < 128) 3110758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); 31116f37f232SEric Joyner else 31126f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), reta); 3113758cc3dcSJack F Vogel reta = 0; 3114758cc3dcSJack F Vogel } 3115758cc3dcSJack F Vogel } 3116758cc3dcSJack F Vogel 3117758cc3dcSJack F Vogel /* Now fill our hash function seeds */ 3118758cc3dcSJack F Vogel for (int i = 0; i < 10; i++) 3119758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); 3120758cc3dcSJack F Vogel 3121758cc3dcSJack F Vogel /* Perform hash on these packet types */ 3122758cc3dcSJack F Vogel #ifdef RSS 3123758cc3dcSJack F Vogel mrqc = IXGBE_MRQC_RSSEN; 3124758cc3dcSJack F Vogel rss_hash_config = rss_gethashconfig(); 3125758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 3126758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; 3127758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 3128758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; 3129758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 3130758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; 3131758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 3132758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; 3133758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 3134758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX; 3135758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) 3136758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP; 3137758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 3138758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; 3139758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) 3140758cc3dcSJack F Vogel device_printf(adapter->dev, 3141758cc3dcSJack F Vogel "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, " 3142758cc3dcSJack F Vogel "but not supported\n", __func__); 3143758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 3144758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; 3145758cc3dcSJack F Vogel if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) 3146758cc3dcSJack F Vogel mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 3147758cc3dcSJack F Vogel #else 3148758cc3dcSJack F Vogel /* 3149758cc3dcSJack F Vogel * Disable UDP - IP fragments aren't currently being handled 3150758cc3dcSJack F Vogel * and so we end up with a mix of 2-tuple and 4-tuple 3151758cc3dcSJack F Vogel * traffic. 3152758cc3dcSJack F Vogel */ 3153758cc3dcSJack F Vogel mrqc = IXGBE_MRQC_RSSEN 3154758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4 3155758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV4_TCP 3156758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP 3157758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_EX 3158758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6 3159758cc3dcSJack F Vogel | IXGBE_MRQC_RSS_FIELD_IPV6_TCP 3160758cc3dcSJack F Vogel ; 3161758cc3dcSJack F Vogel #endif /* RSS */ 316248056c88SJack F Vogel #ifdef PCI_IOV 316348056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 316448056c88SJack F Vogel mrqc |= ixgbe_get_mrqc(mode); 316548056c88SJack F Vogel #endif 3166758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 3167758cc3dcSJack F Vogel } 3168758cc3dcSJack F Vogel 3169758cc3dcSJack F Vogel 3170758cc3dcSJack F Vogel /********************************************************************* 3171758cc3dcSJack F Vogel * 3172758cc3dcSJack F Vogel * Setup receive registers and features. 3173758cc3dcSJack F Vogel * 3174758cc3dcSJack F Vogel **********************************************************************/ 3175758cc3dcSJack F Vogel #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 3176758cc3dcSJack F Vogel 3177758cc3dcSJack F Vogel #define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1) 3178758cc3dcSJack F Vogel 3179758cc3dcSJack F Vogel static void 3180758cc3dcSJack F Vogel ixgbe_initialize_receive_units(struct adapter *adapter) 3181758cc3dcSJack F Vogel { 3182758cc3dcSJack F Vogel struct rx_ring *rxr = adapter->rx_rings; 3183758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3184758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3185758cc3dcSJack F Vogel u32 bufsz, fctrl, srrctl, rxcsum; 3186758cc3dcSJack F Vogel u32 hlreg; 3187758cc3dcSJack F Vogel 3188758cc3dcSJack F Vogel /* 3189758cc3dcSJack F Vogel * Make sure receives are disabled while 3190758cc3dcSJack F Vogel * setting up the descriptor ring 3191758cc3dcSJack F Vogel */ 3192758cc3dcSJack F Vogel ixgbe_disable_rx(hw); 3193758cc3dcSJack F Vogel 3194758cc3dcSJack F Vogel /* Enable broadcasts */ 3195758cc3dcSJack F Vogel fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); 3196758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_BAM; 31976f37f232SEric Joyner if (adapter->hw.mac.type == ixgbe_mac_82598EB) { 3198758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_DPF; 3199758cc3dcSJack F Vogel fctrl |= IXGBE_FCTRL_PMCF; 32006f37f232SEric Joyner } 3201758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); 3202758cc3dcSJack F Vogel 3203758cc3dcSJack F Vogel /* Set for Jumbo Frames? */ 3204758cc3dcSJack F Vogel hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); 3205758cc3dcSJack F Vogel if (ifp->if_mtu > ETHERMTU) 3206758cc3dcSJack F Vogel hlreg |= IXGBE_HLREG0_JUMBOEN; 3207758cc3dcSJack F Vogel else 3208758cc3dcSJack F Vogel hlreg &= ~IXGBE_HLREG0_JUMBOEN; 3209758cc3dcSJack F Vogel #ifdef DEV_NETMAP 3210758cc3dcSJack F Vogel /* crcstrip is conditional in netmap (in RDRXCTL too ?) */ 3211758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip) 3212758cc3dcSJack F Vogel hlreg &= ~IXGBE_HLREG0_RXCRCSTRP; 3213758cc3dcSJack F Vogel else 3214758cc3dcSJack F Vogel hlreg |= IXGBE_HLREG0_RXCRCSTRP; 3215758cc3dcSJack F Vogel #endif /* DEV_NETMAP */ 3216758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); 3217758cc3dcSJack F Vogel 3218758cc3dcSJack F Vogel bufsz = (adapter->rx_mbuf_sz + 3219758cc3dcSJack F Vogel BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; 3220758cc3dcSJack F Vogel 3221758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, rxr++) { 3222758cc3dcSJack F Vogel u64 rdba = rxr->rxdma.dma_paddr; 322348056c88SJack F Vogel int j = rxr->me; 3224758cc3dcSJack F Vogel 3225758cc3dcSJack F Vogel /* Setup the Base and Length of the Rx Descriptor Ring */ 322648056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), 3227758cc3dcSJack F Vogel (rdba & 0x00000000ffffffffULL)); 322848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32)); 322948056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), 3230758cc3dcSJack F Vogel adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); 3231758cc3dcSJack F Vogel 3232758cc3dcSJack F Vogel /* Set up the SRRCTL register */ 323348056c88SJack F Vogel srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(j)); 3234758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; 3235758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; 3236758cc3dcSJack F Vogel srrctl |= bufsz; 3237758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; 3238758cc3dcSJack F Vogel 3239758cc3dcSJack F Vogel /* 3240758cc3dcSJack F Vogel * Set DROP_EN iff we have no flow control and >1 queue. 3241758cc3dcSJack F Vogel * Note that srrctl was cleared shortly before during reset, 3242758cc3dcSJack F Vogel * so we do not need to clear the bit, but do it just in case 3243758cc3dcSJack F Vogel * this code is moved elsewhere. 3244758cc3dcSJack F Vogel */ 324530126537SJack F Vogel if (adapter->num_queues > 1 && 324630126537SJack F Vogel adapter->hw.fc.requested_mode == ixgbe_fc_none) { 3247758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DROP_EN; 324830126537SJack F Vogel } else { 3249758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_DROP_EN; 325030126537SJack F Vogel } 3251758cc3dcSJack F Vogel 325248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(j), srrctl); 3253758cc3dcSJack F Vogel 3254758cc3dcSJack F Vogel /* Setup the HW Rx Head and Tail Descriptor Pointers */ 325548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0); 325648056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0); 3257758cc3dcSJack F Vogel 3258758cc3dcSJack F Vogel /* Set the driver rx tail address */ 3259758cc3dcSJack F Vogel rxr->tail = IXGBE_RDT(rxr->me); 3260758cc3dcSJack F Vogel } 3261758cc3dcSJack F Vogel 3262758cc3dcSJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82598EB) { 3263758cc3dcSJack F Vogel u32 psrtype = IXGBE_PSRTYPE_TCPHDR | 3264758cc3dcSJack F Vogel IXGBE_PSRTYPE_UDPHDR | 3265758cc3dcSJack F Vogel IXGBE_PSRTYPE_IPV4HDR | 3266758cc3dcSJack F Vogel IXGBE_PSRTYPE_IPV6HDR; 3267758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); 3268758cc3dcSJack F Vogel } 3269758cc3dcSJack F Vogel 3270758cc3dcSJack F Vogel rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 3271758cc3dcSJack F Vogel 3272a9ca1c79SSean Bruno ixgbe_initialize_rss_mapping(adapter); 3273758cc3dcSJack F Vogel 3274758cc3dcSJack F Vogel if (adapter->num_queues > 1) { 3275758cc3dcSJack F Vogel /* RSS and RX IPP Checksum are mutually exclusive */ 3276758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_PCSD; 3277758cc3dcSJack F Vogel } 3278758cc3dcSJack F Vogel 3279758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_RXCSUM) 3280758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_PCSD; 3281758cc3dcSJack F Vogel 3282a9ca1c79SSean Bruno /* This is useful for calculating UDP/IP fragment checksums */ 3283758cc3dcSJack F Vogel if (!(rxcsum & IXGBE_RXCSUM_PCSD)) 3284758cc3dcSJack F Vogel rxcsum |= IXGBE_RXCSUM_IPPCSE; 3285758cc3dcSJack F Vogel 3286758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); 3287758cc3dcSJack F Vogel 3288758cc3dcSJack F Vogel return; 3289758cc3dcSJack F Vogel } 3290758cc3dcSJack F Vogel 3291758cc3dcSJack F Vogel 3292758cc3dcSJack F Vogel /* 3293758cc3dcSJack F Vogel ** This routine is run via an vlan config EVENT, 3294758cc3dcSJack F Vogel ** it enables us to use the HW Filter table since 3295758cc3dcSJack F Vogel ** we can get the vlan id. This just creates the 3296758cc3dcSJack F Vogel ** entry in the soft version of the VFTA, init will 3297758cc3dcSJack F Vogel ** repopulate the real table. 3298758cc3dcSJack F Vogel */ 3299758cc3dcSJack F Vogel static void 3300758cc3dcSJack F Vogel ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3301758cc3dcSJack F Vogel { 3302758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 3303758cc3dcSJack F Vogel u16 index, bit; 3304758cc3dcSJack F Vogel 3305758cc3dcSJack F Vogel if (ifp->if_softc != arg) /* Not our event */ 3306758cc3dcSJack F Vogel return; 3307758cc3dcSJack F Vogel 3308758cc3dcSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3309758cc3dcSJack F Vogel return; 3310758cc3dcSJack F Vogel 3311758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 3312758cc3dcSJack F Vogel index = (vtag >> 5) & 0x7F; 3313758cc3dcSJack F Vogel bit = vtag & 0x1F; 3314758cc3dcSJack F Vogel adapter->shadow_vfta[index] |= (1 << bit); 3315758cc3dcSJack F Vogel ++adapter->num_vlans; 3316758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 3317758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 3318758cc3dcSJack F Vogel } 3319758cc3dcSJack F Vogel 3320758cc3dcSJack F Vogel /* 3321758cc3dcSJack F Vogel ** This routine is run via an vlan 3322758cc3dcSJack F Vogel ** unconfig EVENT, remove our entry 3323758cc3dcSJack F Vogel ** in the soft vfta. 3324758cc3dcSJack F Vogel */ 3325758cc3dcSJack F Vogel static void 3326758cc3dcSJack F Vogel ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) 3327758cc3dcSJack F Vogel { 3328758cc3dcSJack F Vogel struct adapter *adapter = ifp->if_softc; 3329758cc3dcSJack F Vogel u16 index, bit; 3330758cc3dcSJack F Vogel 3331758cc3dcSJack F Vogel if (ifp->if_softc != arg) 3332758cc3dcSJack F Vogel return; 3333758cc3dcSJack F Vogel 3334758cc3dcSJack F Vogel if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 3335758cc3dcSJack F Vogel return; 3336758cc3dcSJack F Vogel 3337758cc3dcSJack F Vogel IXGBE_CORE_LOCK(adapter); 3338758cc3dcSJack F Vogel index = (vtag >> 5) & 0x7F; 3339758cc3dcSJack F Vogel bit = vtag & 0x1F; 3340758cc3dcSJack F Vogel adapter->shadow_vfta[index] &= ~(1 << bit); 3341758cc3dcSJack F Vogel --adapter->num_vlans; 3342758cc3dcSJack F Vogel /* Re-init to load the changes */ 3343758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(adapter); 3344758cc3dcSJack F Vogel IXGBE_CORE_UNLOCK(adapter); 3345758cc3dcSJack F Vogel } 3346758cc3dcSJack F Vogel 3347758cc3dcSJack F Vogel static void 3348758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(struct adapter *adapter) 3349758cc3dcSJack F Vogel { 3350758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3351758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3352758cc3dcSJack F Vogel struct rx_ring *rxr; 3353758cc3dcSJack F Vogel u32 ctrl; 3354758cc3dcSJack F Vogel 3355758cc3dcSJack F Vogel 3356758cc3dcSJack F Vogel /* 3357758cc3dcSJack F Vogel ** We get here thru init_locked, meaning 3358758cc3dcSJack F Vogel ** a soft reset, this has already cleared 3359758cc3dcSJack F Vogel ** the VFTA and other state, so if there 3360758cc3dcSJack F Vogel ** have been no vlan's registered do nothing. 3361758cc3dcSJack F Vogel */ 3362758cc3dcSJack F Vogel if (adapter->num_vlans == 0) 3363758cc3dcSJack F Vogel return; 3364758cc3dcSJack F Vogel 3365758cc3dcSJack F Vogel /* Setup the queues for vlans */ 3366758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 3367758cc3dcSJack F Vogel rxr = &adapter->rx_rings[i]; 3368758cc3dcSJack F Vogel /* On 82599 the VLAN enable is per/queue in RXDCTL */ 3369758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 337048056c88SJack F Vogel ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); 3371758cc3dcSJack F Vogel ctrl |= IXGBE_RXDCTL_VME; 337248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl); 3373758cc3dcSJack F Vogel } 3374758cc3dcSJack F Vogel rxr->vtag_strip = TRUE; 3375758cc3dcSJack F Vogel } 3376758cc3dcSJack F Vogel 3377758cc3dcSJack F Vogel if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0) 3378758cc3dcSJack F Vogel return; 3379758cc3dcSJack F Vogel /* 3380758cc3dcSJack F Vogel ** A soft reset zero's out the VFTA, so 3381758cc3dcSJack F Vogel ** we need to repopulate it now. 3382758cc3dcSJack F Vogel */ 3383758cc3dcSJack F Vogel for (int i = 0; i < IXGBE_VFTA_SIZE; i++) 3384758cc3dcSJack F Vogel if (adapter->shadow_vfta[i] != 0) 3385758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), 3386758cc3dcSJack F Vogel adapter->shadow_vfta[i]); 3387758cc3dcSJack F Vogel 3388758cc3dcSJack F Vogel ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); 3389758cc3dcSJack F Vogel /* Enable the Filter Table if enabled */ 3390758cc3dcSJack F Vogel if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) { 3391758cc3dcSJack F Vogel ctrl &= ~IXGBE_VLNCTRL_CFIEN; 3392758cc3dcSJack F Vogel ctrl |= IXGBE_VLNCTRL_VFE; 3393758cc3dcSJack F Vogel } 3394758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 3395758cc3dcSJack F Vogel ctrl |= IXGBE_VLNCTRL_VME; 3396758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); 3397758cc3dcSJack F Vogel } 3398758cc3dcSJack F Vogel 3399758cc3dcSJack F Vogel static void 3400758cc3dcSJack F Vogel ixgbe_enable_intr(struct adapter *adapter) 3401758cc3dcSJack F Vogel { 3402758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3403758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 3404758cc3dcSJack F Vogel u32 mask, fwsm; 3405758cc3dcSJack F Vogel 3406758cc3dcSJack F Vogel mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); 3407758cc3dcSJack F Vogel /* Enable Fan Failure detection */ 3408758cc3dcSJack F Vogel if (hw->device_id == IXGBE_DEV_ID_82598AT) 34096f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP1; 3410758cc3dcSJack F Vogel 3411758cc3dcSJack F Vogel switch (adapter->hw.mac.type) { 3412758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 3413758cc3dcSJack F Vogel mask |= IXGBE_EIMS_ECC; 3414758cc3dcSJack F Vogel /* Temperature sensor on some adapters */ 34156f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP0; 3416758cc3dcSJack F Vogel /* SFP+ (RX_LOS_N & MOD_ABS_N) */ 34176f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP1; 34186f37f232SEric Joyner mask |= IXGBE_EIMS_GPI_SDP2; 3419758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3420758cc3dcSJack F Vogel mask |= IXGBE_EIMS_FLOW_DIR; 3421758cc3dcSJack F Vogel #endif 342248056c88SJack F Vogel #ifdef PCI_IOV 342348056c88SJack F Vogel mask |= IXGBE_EIMS_MAILBOX; 342448056c88SJack F Vogel #endif 3425758cc3dcSJack F Vogel break; 3426758cc3dcSJack F Vogel case ixgbe_mac_X540: 3427758cc3dcSJack F Vogel /* Detect if Thermal Sensor is enabled */ 3428758cc3dcSJack F Vogel fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); 3429758cc3dcSJack F Vogel if (fwsm & IXGBE_FWSM_TS_ENABLED) 3430758cc3dcSJack F Vogel mask |= IXGBE_EIMS_TS; 34316f37f232SEric Joyner mask |= IXGBE_EIMS_ECC; 34326f37f232SEric Joyner #ifdef IXGBE_FDIR 34336f37f232SEric Joyner mask |= IXGBE_EIMS_FLOW_DIR; 34346f37f232SEric Joyner #endif 34356f37f232SEric Joyner break; 34366f37f232SEric Joyner case ixgbe_mac_X550: 34376f37f232SEric Joyner case ixgbe_mac_X550EM_x: 34386f37f232SEric Joyner /* MAC thermal sensor is automatically enabled */ 34396f37f232SEric Joyner mask |= IXGBE_EIMS_TS; 34406f37f232SEric Joyner /* Some devices use SDP0 for important information */ 34416f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || 34426f37f232SEric Joyner hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) 3443758cc3dcSJack F Vogel mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); 3444758cc3dcSJack F Vogel mask |= IXGBE_EIMS_ECC; 3445758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3446758cc3dcSJack F Vogel mask |= IXGBE_EIMS_FLOW_DIR; 3447758cc3dcSJack F Vogel #endif 344848056c88SJack F Vogel #ifdef PCI_IOV 344948056c88SJack F Vogel mask |= IXGBE_EIMS_MAILBOX; 345048056c88SJack F Vogel #endif 3451758cc3dcSJack F Vogel /* falls through */ 3452758cc3dcSJack F Vogel default: 3453758cc3dcSJack F Vogel break; 3454758cc3dcSJack F Vogel } 3455758cc3dcSJack F Vogel 3456758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); 3457758cc3dcSJack F Vogel 34586f37f232SEric Joyner /* With MSI-X we use auto clear */ 3459758cc3dcSJack F Vogel if (adapter->msix_mem) { 3460758cc3dcSJack F Vogel mask = IXGBE_EIMS_ENABLE_MASK; 3461758cc3dcSJack F Vogel /* Don't autoclear Link */ 3462758cc3dcSJack F Vogel mask &= ~IXGBE_EIMS_OTHER; 3463758cc3dcSJack F Vogel mask &= ~IXGBE_EIMS_LSC; 346448056c88SJack F Vogel #ifdef PCI_IOV 346548056c88SJack F Vogel mask &= ~IXGBE_EIMS_MAILBOX; 346648056c88SJack F Vogel #endif 3467758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); 3468758cc3dcSJack F Vogel } 3469758cc3dcSJack F Vogel 3470758cc3dcSJack F Vogel /* 3471758cc3dcSJack F Vogel ** Now enable all queues, this is done separately to 3472758cc3dcSJack F Vogel ** allow for handling the extended (beyond 32) MSIX 3473758cc3dcSJack F Vogel ** vectors that can be used by 82599 3474758cc3dcSJack F Vogel */ 3475758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) 3476758cc3dcSJack F Vogel ixgbe_enable_queue(adapter, que->msix); 3477758cc3dcSJack F Vogel 3478758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(hw); 3479758cc3dcSJack F Vogel 3480758cc3dcSJack F Vogel return; 3481758cc3dcSJack F Vogel } 3482758cc3dcSJack F Vogel 3483758cc3dcSJack F Vogel static void 3484758cc3dcSJack F Vogel ixgbe_disable_intr(struct adapter *adapter) 3485758cc3dcSJack F Vogel { 3486758cc3dcSJack F Vogel if (adapter->msix_mem) 3487758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, 0); 3488758cc3dcSJack F Vogel if (adapter->hw.mac.type == ixgbe_mac_82598EB) { 3489758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); 3490758cc3dcSJack F Vogel } else { 3491758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000); 3492758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0); 3493758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0); 3494758cc3dcSJack F Vogel } 3495758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(&adapter->hw); 3496758cc3dcSJack F Vogel return; 3497758cc3dcSJack F Vogel } 3498758cc3dcSJack F Vogel 3499758cc3dcSJack F Vogel /* 3500758cc3dcSJack F Vogel ** Get the width and transaction speed of 3501758cc3dcSJack F Vogel ** the slot this adapter is plugged into. 3502758cc3dcSJack F Vogel */ 3503758cc3dcSJack F Vogel static void 3504a9ca1c79SSean Bruno ixgbe_get_slot_info(struct adapter *adapter) 3505758cc3dcSJack F Vogel { 3506a9ca1c79SSean Bruno device_t dev = adapter->dev; 3507a9ca1c79SSean Bruno struct ixgbe_hw *hw = &adapter->hw; 3508758cc3dcSJack F Vogel struct ixgbe_mac_info *mac = &hw->mac; 3509758cc3dcSJack F Vogel u16 link; 3510758cc3dcSJack F Vogel u32 offset; 3511758cc3dcSJack F Vogel 3512758cc3dcSJack F Vogel /* For most devices simply call the shared code routine */ 3513758cc3dcSJack F Vogel if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) { 3514758cc3dcSJack F Vogel ixgbe_get_bus_info(hw); 3515758cc3dcSJack F Vogel /* These devices don't use PCI-E */ 35166f37f232SEric Joyner switch (hw->mac.type) { 35176f37f232SEric Joyner case ixgbe_mac_X550EM_x: 3518758cc3dcSJack F Vogel return; 35196f37f232SEric Joyner default: 3520758cc3dcSJack F Vogel goto display; 3521758cc3dcSJack F Vogel } 35226f37f232SEric Joyner } 3523758cc3dcSJack F Vogel 3524758cc3dcSJack F Vogel /* 3525758cc3dcSJack F Vogel ** For the Quad port adapter we need to parse back 3526758cc3dcSJack F Vogel ** up the PCI tree to find the speed of the expansion 3527758cc3dcSJack F Vogel ** slot into which this adapter is plugged. A bit more work. 3528758cc3dcSJack F Vogel */ 3529758cc3dcSJack F Vogel dev = device_get_parent(device_get_parent(dev)); 3530758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG 3531758cc3dcSJack F Vogel device_printf(dev, "parent pcib = %x,%x,%x\n", 3532758cc3dcSJack F Vogel pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); 3533758cc3dcSJack F Vogel #endif 3534758cc3dcSJack F Vogel dev = device_get_parent(device_get_parent(dev)); 3535758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG 3536758cc3dcSJack F Vogel device_printf(dev, "slot pcib = %x,%x,%x\n", 3537758cc3dcSJack F Vogel pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); 3538758cc3dcSJack F Vogel #endif 3539758cc3dcSJack F Vogel /* Now get the PCI Express Capabilities offset */ 3540758cc3dcSJack F Vogel pci_find_cap(dev, PCIY_EXPRESS, &offset); 3541758cc3dcSJack F Vogel /* ...and read the Link Status Register */ 3542758cc3dcSJack F Vogel link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); 3543758cc3dcSJack F Vogel switch (link & IXGBE_PCI_LINK_WIDTH) { 3544758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_1: 3545758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x1; 3546758cc3dcSJack F Vogel break; 3547758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_2: 3548758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x2; 3549758cc3dcSJack F Vogel break; 3550758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_4: 3551758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x4; 3552758cc3dcSJack F Vogel break; 3553758cc3dcSJack F Vogel case IXGBE_PCI_LINK_WIDTH_8: 3554758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_pcie_x8; 3555758cc3dcSJack F Vogel break; 3556758cc3dcSJack F Vogel default: 3557758cc3dcSJack F Vogel hw->bus.width = ixgbe_bus_width_unknown; 3558758cc3dcSJack F Vogel break; 3559758cc3dcSJack F Vogel } 3560758cc3dcSJack F Vogel 3561758cc3dcSJack F Vogel switch (link & IXGBE_PCI_LINK_SPEED) { 3562758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_2500: 3563758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_2500; 3564758cc3dcSJack F Vogel break; 3565758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_5000: 3566758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_5000; 3567758cc3dcSJack F Vogel break; 3568758cc3dcSJack F Vogel case IXGBE_PCI_LINK_SPEED_8000: 3569758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_8000; 3570758cc3dcSJack F Vogel break; 3571758cc3dcSJack F Vogel default: 3572758cc3dcSJack F Vogel hw->bus.speed = ixgbe_bus_speed_unknown; 3573758cc3dcSJack F Vogel break; 3574758cc3dcSJack F Vogel } 3575758cc3dcSJack F Vogel 3576758cc3dcSJack F Vogel mac->ops.set_lan_id(hw); 3577758cc3dcSJack F Vogel 3578758cc3dcSJack F Vogel display: 3579758cc3dcSJack F Vogel device_printf(dev,"PCI Express Bus: Speed %s %s\n", 3580758cc3dcSJack F Vogel ((hw->bus.speed == ixgbe_bus_speed_8000) ? "8.0GT/s": 3581758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0GT/s": 3582758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5GT/s":"Unknown"), 3583758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" : 3584758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" : 3585758cc3dcSJack F Vogel (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" : 3586758cc3dcSJack F Vogel ("Unknown")); 3587758cc3dcSJack F Vogel 3588758cc3dcSJack F Vogel if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) && 3589758cc3dcSJack F Vogel ((hw->bus.width <= ixgbe_bus_width_pcie_x4) && 3590758cc3dcSJack F Vogel (hw->bus.speed == ixgbe_bus_speed_2500))) { 3591758cc3dcSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 3592758cc3dcSJack F Vogel " for this card\n is not sufficient for" 3593758cc3dcSJack F Vogel " optimal performance.\n"); 3594758cc3dcSJack F Vogel device_printf(dev, "For optimal performance a x8 " 3595758cc3dcSJack F Vogel "PCIE, or x4 PCIE Gen2 slot is required.\n"); 3596758cc3dcSJack F Vogel } 3597758cc3dcSJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) && 3598758cc3dcSJack F Vogel ((hw->bus.width <= ixgbe_bus_width_pcie_x8) && 3599758cc3dcSJack F Vogel (hw->bus.speed < ixgbe_bus_speed_8000))) { 3600758cc3dcSJack F Vogel device_printf(dev, "PCI-Express bandwidth available" 3601758cc3dcSJack F Vogel " for this card\n is not sufficient for" 3602758cc3dcSJack F Vogel " optimal performance.\n"); 3603758cc3dcSJack F Vogel device_printf(dev, "For optimal performance a x8 " 3604758cc3dcSJack F Vogel "PCIE Gen3 slot is required.\n"); 3605758cc3dcSJack F Vogel } 3606758cc3dcSJack F Vogel 3607758cc3dcSJack F Vogel return; 3608758cc3dcSJack F Vogel } 3609758cc3dcSJack F Vogel 3610758cc3dcSJack F Vogel 3611758cc3dcSJack F Vogel /* 3612758cc3dcSJack F Vogel ** Setup the correct IVAR register for a particular MSIX interrupt 3613758cc3dcSJack F Vogel ** (yes this is all very magic and confusing :) 3614758cc3dcSJack F Vogel ** - entry is the register array entry 3615758cc3dcSJack F Vogel ** - vector is the MSIX vector for this queue 3616758cc3dcSJack F Vogel ** - type is RX/TX/MISC 3617758cc3dcSJack F Vogel */ 3618758cc3dcSJack F Vogel static void 3619758cc3dcSJack F Vogel ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) 3620758cc3dcSJack F Vogel { 3621758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3622758cc3dcSJack F Vogel u32 ivar, index; 3623758cc3dcSJack F Vogel 3624758cc3dcSJack F Vogel vector |= IXGBE_IVAR_ALLOC_VAL; 3625758cc3dcSJack F Vogel 3626758cc3dcSJack F Vogel switch (hw->mac.type) { 3627758cc3dcSJack F Vogel 3628758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 3629758cc3dcSJack F Vogel if (type == -1) 3630758cc3dcSJack F Vogel entry = IXGBE_IVAR_OTHER_CAUSES_INDEX; 3631758cc3dcSJack F Vogel else 3632758cc3dcSJack F Vogel entry += (type * 64); 3633758cc3dcSJack F Vogel index = (entry >> 2) & 0x1F; 3634758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 3635758cc3dcSJack F Vogel ivar &= ~(0xFF << (8 * (entry & 0x3))); 3636758cc3dcSJack F Vogel ivar |= (vector << (8 * (entry & 0x3))); 3637758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar); 3638758cc3dcSJack F Vogel break; 3639758cc3dcSJack F Vogel 3640758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 3641758cc3dcSJack F Vogel case ixgbe_mac_X540: 3642758cc3dcSJack F Vogel case ixgbe_mac_X550: 3643758cc3dcSJack F Vogel case ixgbe_mac_X550EM_x: 3644758cc3dcSJack F Vogel if (type == -1) { /* MISC IVAR */ 3645758cc3dcSJack F Vogel index = (entry & 1) * 8; 3646758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 3647758cc3dcSJack F Vogel ivar &= ~(0xFF << index); 3648758cc3dcSJack F Vogel ivar |= (vector << index); 3649758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 3650758cc3dcSJack F Vogel } else { /* RX/TX IVARS */ 3651758cc3dcSJack F Vogel index = (16 * (entry & 1)) + (8 * type); 3652758cc3dcSJack F Vogel ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1)); 3653758cc3dcSJack F Vogel ivar &= ~(0xFF << index); 3654758cc3dcSJack F Vogel ivar |= (vector << index); 3655758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar); 3656758cc3dcSJack F Vogel } 3657758cc3dcSJack F Vogel 3658758cc3dcSJack F Vogel default: 3659758cc3dcSJack F Vogel break; 3660758cc3dcSJack F Vogel } 3661758cc3dcSJack F Vogel } 3662758cc3dcSJack F Vogel 3663758cc3dcSJack F Vogel static void 3664758cc3dcSJack F Vogel ixgbe_configure_ivars(struct adapter *adapter) 3665758cc3dcSJack F Vogel { 3666758cc3dcSJack F Vogel struct ix_queue *que = adapter->queues; 3667758cc3dcSJack F Vogel u32 newitr; 3668758cc3dcSJack F Vogel 3669758cc3dcSJack F Vogel if (ixgbe_max_interrupt_rate > 0) 3670758cc3dcSJack F Vogel newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8; 36716f37f232SEric Joyner else { 36726f37f232SEric Joyner /* 36736f37f232SEric Joyner ** Disable DMA coalescing if interrupt moderation is 36746f37f232SEric Joyner ** disabled. 36756f37f232SEric Joyner */ 36766f37f232SEric Joyner adapter->dmac = 0; 3677758cc3dcSJack F Vogel newitr = 0; 36786f37f232SEric Joyner } 3679758cc3dcSJack F Vogel 3680758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, que++) { 368148056c88SJack F Vogel struct rx_ring *rxr = &adapter->rx_rings[i]; 368248056c88SJack F Vogel struct tx_ring *txr = &adapter->tx_rings[i]; 3683758cc3dcSJack F Vogel /* First the RX queue entry */ 368448056c88SJack F Vogel ixgbe_set_ivar(adapter, rxr->me, que->msix, 0); 3685758cc3dcSJack F Vogel /* ... and the TX */ 368648056c88SJack F Vogel ixgbe_set_ivar(adapter, txr->me, que->msix, 1); 3687758cc3dcSJack F Vogel /* Set an Initial EITR value */ 3688758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, 3689758cc3dcSJack F Vogel IXGBE_EITR(que->msix), newitr); 3690758cc3dcSJack F Vogel } 3691758cc3dcSJack F Vogel 3692758cc3dcSJack F Vogel /* For the Link interrupt */ 3693758cc3dcSJack F Vogel ixgbe_set_ivar(adapter, 1, adapter->vector, -1); 3694758cc3dcSJack F Vogel } 3695758cc3dcSJack F Vogel 3696758cc3dcSJack F Vogel /* 3697758cc3dcSJack F Vogel ** ixgbe_sfp_probe - called in the local timer to 3698758cc3dcSJack F Vogel ** determine if a port had optics inserted. 3699758cc3dcSJack F Vogel */ 370048056c88SJack F Vogel static bool 370148056c88SJack F Vogel ixgbe_sfp_probe(struct adapter *adapter) 3702758cc3dcSJack F Vogel { 3703758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3704758cc3dcSJack F Vogel device_t dev = adapter->dev; 3705758cc3dcSJack F Vogel bool result = FALSE; 3706758cc3dcSJack F Vogel 3707758cc3dcSJack F Vogel if ((hw->phy.type == ixgbe_phy_nl) && 3708758cc3dcSJack F Vogel (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { 3709758cc3dcSJack F Vogel s32 ret = hw->phy.ops.identify_sfp(hw); 3710758cc3dcSJack F Vogel if (ret) 3711758cc3dcSJack F Vogel goto out; 3712758cc3dcSJack F Vogel ret = hw->phy.ops.reset(hw); 3713758cc3dcSJack F Vogel if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3714758cc3dcSJack F Vogel device_printf(dev, "Unsupported SFP+ module detected!"); 3715a9ca1c79SSean Bruno device_printf(dev, "Reload driver with supported module.\n"); 3716758cc3dcSJack F Vogel adapter->sfp_probe = FALSE; 3717758cc3dcSJack F Vogel goto out; 3718758cc3dcSJack F Vogel } else 3719758cc3dcSJack F Vogel device_printf(dev, "SFP+ module detected!\n"); 3720758cc3dcSJack F Vogel /* We now have supported optics */ 3721758cc3dcSJack F Vogel adapter->sfp_probe = FALSE; 3722758cc3dcSJack F Vogel /* Set the optics type so system reports correctly */ 3723758cc3dcSJack F Vogel ixgbe_setup_optics(adapter); 3724758cc3dcSJack F Vogel result = TRUE; 3725758cc3dcSJack F Vogel } 3726758cc3dcSJack F Vogel out: 3727758cc3dcSJack F Vogel return (result); 3728758cc3dcSJack F Vogel } 3729758cc3dcSJack F Vogel 3730758cc3dcSJack F Vogel /* 3731758cc3dcSJack F Vogel ** Tasklet handler for MSIX Link interrupts 3732758cc3dcSJack F Vogel ** - do outside interrupt since it might sleep 3733758cc3dcSJack F Vogel */ 3734758cc3dcSJack F Vogel static void 3735758cc3dcSJack F Vogel ixgbe_handle_link(void *context, int pending) 3736758cc3dcSJack F Vogel { 3737758cc3dcSJack F Vogel struct adapter *adapter = context; 3738a9ca1c79SSean Bruno struct ixgbe_hw *hw = &adapter->hw; 3739758cc3dcSJack F Vogel 3740a9ca1c79SSean Bruno ixgbe_check_link(hw, 3741758cc3dcSJack F Vogel &adapter->link_speed, &adapter->link_up, 0); 3742758cc3dcSJack F Vogel ixgbe_update_link_status(adapter); 3743a9ca1c79SSean Bruno 3744a9ca1c79SSean Bruno /* Re-enable link interrupts */ 3745a9ca1c79SSean Bruno IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_LSC); 3746758cc3dcSJack F Vogel } 3747758cc3dcSJack F Vogel 3748758cc3dcSJack F Vogel /* 3749758cc3dcSJack F Vogel ** Tasklet for handling SFP module interrupts 3750758cc3dcSJack F Vogel */ 3751758cc3dcSJack F Vogel static void 3752758cc3dcSJack F Vogel ixgbe_handle_mod(void *context, int pending) 3753758cc3dcSJack F Vogel { 3754758cc3dcSJack F Vogel struct adapter *adapter = context; 3755758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3756*97f9586eSSean Bruno enum ixgbe_phy_type orig_type = hw->phy.type; 3757758cc3dcSJack F Vogel device_t dev = adapter->dev; 3758758cc3dcSJack F Vogel u32 err; 3759758cc3dcSJack F Vogel 3760*97f9586eSSean Bruno IXGBE_CORE_LOCK(adapter); 3761*97f9586eSSean Bruno 3762*97f9586eSSean Bruno /* Check to see if the PHY type changed */ 3763*97f9586eSSean Bruno if (hw->phy.ops.identify) { 3764*97f9586eSSean Bruno hw->phy.type = ixgbe_phy_unknown; 3765*97f9586eSSean Bruno hw->phy.ops.identify(hw); 3766*97f9586eSSean Bruno } 3767*97f9586eSSean Bruno 3768*97f9586eSSean Bruno if (hw->phy.type != orig_type) { 3769*97f9586eSSean Bruno device_printf(dev, "Detected phy_type %d\n", hw->phy.type); 3770*97f9586eSSean Bruno 3771*97f9586eSSean Bruno if (hw->phy.type == ixgbe_phy_none) { 3772*97f9586eSSean Bruno hw->phy.sfp_type = ixgbe_sfp_type_unknown; 3773*97f9586eSSean Bruno goto out; 3774*97f9586eSSean Bruno } 3775*97f9586eSSean Bruno 3776*97f9586eSSean Bruno /* Try to do the initialization that was skipped before */ 3777*97f9586eSSean Bruno if (hw->phy.ops.init) 3778*97f9586eSSean Bruno hw->phy.ops.init(hw); 3779*97f9586eSSean Bruno if (hw->phy.ops.reset) 3780*97f9586eSSean Bruno hw->phy.ops.reset(hw); 3781*97f9586eSSean Bruno } 3782*97f9586eSSean Bruno 3783758cc3dcSJack F Vogel err = hw->phy.ops.identify_sfp(hw); 3784758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3785758cc3dcSJack F Vogel device_printf(dev, 3786758cc3dcSJack F Vogel "Unsupported SFP+ module type was detected.\n"); 3787*97f9586eSSean Bruno goto out; 3788758cc3dcSJack F Vogel } 378948056c88SJack F Vogel 3790758cc3dcSJack F Vogel err = hw->mac.ops.setup_sfp(hw); 3791758cc3dcSJack F Vogel if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { 3792758cc3dcSJack F Vogel device_printf(dev, 3793758cc3dcSJack F Vogel "Setup failure - unsupported SFP+ module type.\n"); 3794*97f9586eSSean Bruno goto out; 3795758cc3dcSJack F Vogel } 3796*97f9586eSSean Bruno if (hw->phy.multispeed_fiber) 3797758cc3dcSJack F Vogel taskqueue_enqueue(adapter->tq, &adapter->msf_task); 3798*97f9586eSSean Bruno out: 3799*97f9586eSSean Bruno /* Update media type */ 3800*97f9586eSSean Bruno switch (hw->mac.ops.get_media_type(hw)) { 3801*97f9586eSSean Bruno case ixgbe_media_type_fiber: 3802*97f9586eSSean Bruno adapter->optics = IFM_10G_SR; 3803*97f9586eSSean Bruno break; 3804*97f9586eSSean Bruno case ixgbe_media_type_copper: 3805*97f9586eSSean Bruno adapter->optics = IFM_10G_TWINAX; 3806*97f9586eSSean Bruno break; 3807*97f9586eSSean Bruno case ixgbe_media_type_cx4: 3808*97f9586eSSean Bruno adapter->optics = IFM_10G_CX4; 3809*97f9586eSSean Bruno break; 3810*97f9586eSSean Bruno default: 3811*97f9586eSSean Bruno adapter->optics = 0; 3812*97f9586eSSean Bruno break; 3813*97f9586eSSean Bruno } 3814*97f9586eSSean Bruno 3815*97f9586eSSean Bruno IXGBE_CORE_UNLOCK(adapter); 3816758cc3dcSJack F Vogel return; 3817758cc3dcSJack F Vogel } 3818758cc3dcSJack F Vogel 3819758cc3dcSJack F Vogel 3820758cc3dcSJack F Vogel /* 3821758cc3dcSJack F Vogel ** Tasklet for handling MSF (multispeed fiber) interrupts 3822758cc3dcSJack F Vogel */ 3823758cc3dcSJack F Vogel static void 3824758cc3dcSJack F Vogel ixgbe_handle_msf(void *context, int pending) 3825758cc3dcSJack F Vogel { 3826758cc3dcSJack F Vogel struct adapter *adapter = context; 3827758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 3828758cc3dcSJack F Vogel u32 autoneg; 3829758cc3dcSJack F Vogel bool negotiate; 3830758cc3dcSJack F Vogel 3831*97f9586eSSean Bruno IXGBE_CORE_LOCK(adapter); 3832a9ca1c79SSean Bruno /* get_supported_phy_layer will call hw->phy.ops.identify_sfp() */ 3833a9ca1c79SSean Bruno adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); 3834758cc3dcSJack F Vogel 3835758cc3dcSJack F Vogel autoneg = hw->phy.autoneg_advertised; 3836758cc3dcSJack F Vogel if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) 3837758cc3dcSJack F Vogel hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate); 3838758cc3dcSJack F Vogel if (hw->mac.ops.setup_link) 3839758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, autoneg, TRUE); 3840758cc3dcSJack F Vogel 3841a9ca1c79SSean Bruno /* Adjust media types shown in ifconfig */ 3842758cc3dcSJack F Vogel ifmedia_removeall(&adapter->media); 3843758cc3dcSJack F Vogel ixgbe_add_media_types(adapter); 3844*97f9586eSSean Bruno IXGBE_CORE_UNLOCK(adapter); 3845758cc3dcSJack F Vogel return; 3846758cc3dcSJack F Vogel } 3847758cc3dcSJack F Vogel 38486f37f232SEric Joyner /* 38496f37f232SEric Joyner ** Tasklet for handling interrupts from an external PHY 38506f37f232SEric Joyner */ 38516f37f232SEric Joyner static void 38526f37f232SEric Joyner ixgbe_handle_phy(void *context, int pending) 38536f37f232SEric Joyner { 38546f37f232SEric Joyner struct adapter *adapter = context; 38556f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 38566f37f232SEric Joyner int error; 38576f37f232SEric Joyner 38586f37f232SEric Joyner error = hw->phy.ops.handle_lasi(hw); 38596f37f232SEric Joyner if (error == IXGBE_ERR_OVERTEMP) 38606f37f232SEric Joyner device_printf(adapter->dev, 38616f37f232SEric Joyner "CRITICAL: EXTERNAL PHY OVER TEMP!! " 38626f37f232SEric Joyner " PHY will downshift to lower power state!\n"); 38636f37f232SEric Joyner else if (error) 38646f37f232SEric Joyner device_printf(adapter->dev, 38656f37f232SEric Joyner "Error handling LASI interrupt: %d\n", 38666f37f232SEric Joyner error); 38676f37f232SEric Joyner return; 38686f37f232SEric Joyner } 38696f37f232SEric Joyner 3870758cc3dcSJack F Vogel #ifdef IXGBE_FDIR 3871758cc3dcSJack F Vogel /* 3872758cc3dcSJack F Vogel ** Tasklet for reinitializing the Flow Director filter table 3873758cc3dcSJack F Vogel */ 3874758cc3dcSJack F Vogel static void 3875758cc3dcSJack F Vogel ixgbe_reinit_fdir(void *context, int pending) 3876758cc3dcSJack F Vogel { 3877758cc3dcSJack F Vogel struct adapter *adapter = context; 3878758cc3dcSJack F Vogel struct ifnet *ifp = adapter->ifp; 3879758cc3dcSJack F Vogel 3880758cc3dcSJack F Vogel if (adapter->fdir_reinit != 1) /* Shouldn't happen */ 3881758cc3dcSJack F Vogel return; 3882758cc3dcSJack F Vogel ixgbe_reinit_fdir_tables_82599(&adapter->hw); 3883758cc3dcSJack F Vogel adapter->fdir_reinit = 0; 3884758cc3dcSJack F Vogel /* re-enable flow director interrupts */ 3885758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); 3886758cc3dcSJack F Vogel /* Restart the interface */ 3887758cc3dcSJack F Vogel ifp->if_drv_flags |= IFF_DRV_RUNNING; 3888758cc3dcSJack F Vogel return; 3889758cc3dcSJack F Vogel } 3890758cc3dcSJack F Vogel #endif 3891758cc3dcSJack F Vogel 38926f37f232SEric Joyner /********************************************************************* 38936f37f232SEric Joyner * 38946f37f232SEric Joyner * Configure DMA Coalescing 38956f37f232SEric Joyner * 38966f37f232SEric Joyner **********************************************************************/ 38976f37f232SEric Joyner static void 38986f37f232SEric Joyner ixgbe_config_dmac(struct adapter *adapter) 38996f37f232SEric Joyner { 39006f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 39016f37f232SEric Joyner struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config; 39026f37f232SEric Joyner 39036f37f232SEric Joyner if (hw->mac.type < ixgbe_mac_X550 || 39046f37f232SEric Joyner !hw->mac.ops.dmac_config) 39056f37f232SEric Joyner return; 39066f37f232SEric Joyner 39076f37f232SEric Joyner if (dcfg->watchdog_timer ^ adapter->dmac || 39086f37f232SEric Joyner dcfg->link_speed ^ adapter->link_speed) { 39096f37f232SEric Joyner dcfg->watchdog_timer = adapter->dmac; 39106f37f232SEric Joyner dcfg->fcoe_en = false; 39116f37f232SEric Joyner dcfg->link_speed = adapter->link_speed; 39126f37f232SEric Joyner dcfg->num_tcs = 1; 39136f37f232SEric Joyner 39146f37f232SEric Joyner INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n", 39156f37f232SEric Joyner dcfg->watchdog_timer, dcfg->link_speed); 39166f37f232SEric Joyner 39176f37f232SEric Joyner hw->mac.ops.dmac_config(hw); 39186f37f232SEric Joyner } 39196f37f232SEric Joyner } 39206f37f232SEric Joyner 39216f37f232SEric Joyner /* 39226f37f232SEric Joyner * Checks whether the adapter's ports are capable of 39236f37f232SEric Joyner * Wake On LAN by reading the adapter's NVM. 39246f37f232SEric Joyner * 39256f37f232SEric Joyner * Sets each port's hw->wol_enabled value depending 39266f37f232SEric Joyner * on the value read here. 39276f37f232SEric Joyner */ 39286f37f232SEric Joyner static void 39296f37f232SEric Joyner ixgbe_check_wol_support(struct adapter *adapter) 39306f37f232SEric Joyner { 39316f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 39326f37f232SEric Joyner u16 dev_caps = 0; 39336f37f232SEric Joyner 39346f37f232SEric Joyner /* Find out WoL support for port */ 39356f37f232SEric Joyner adapter->wol_support = hw->wol_enabled = 0; 39366f37f232SEric Joyner ixgbe_get_device_caps(hw, &dev_caps); 39376f37f232SEric Joyner if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) || 39386f37f232SEric Joyner ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) && 39396f37f232SEric Joyner hw->bus.func == 0)) 39406f37f232SEric Joyner adapter->wol_support = hw->wol_enabled = 1; 39416f37f232SEric Joyner 39426f37f232SEric Joyner /* Save initial wake up filter configuration */ 39436f37f232SEric Joyner adapter->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC); 39446f37f232SEric Joyner 39456f37f232SEric Joyner return; 39466f37f232SEric Joyner } 39476f37f232SEric Joyner 39486f37f232SEric Joyner /* 39496f37f232SEric Joyner * Prepare the adapter/port for LPLU and/or WoL 39506f37f232SEric Joyner */ 39516f37f232SEric Joyner static int 39526f37f232SEric Joyner ixgbe_setup_low_power_mode(struct adapter *adapter) 39536f37f232SEric Joyner { 39546f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 39556f37f232SEric Joyner device_t dev = adapter->dev; 39566f37f232SEric Joyner s32 error = 0; 39576f37f232SEric Joyner 39586f37f232SEric Joyner mtx_assert(&adapter->core_mtx, MA_OWNED); 39596f37f232SEric Joyner 39606f37f232SEric Joyner /* Limit power management flow to X550EM baseT */ 39616f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T 39626f37f232SEric Joyner && hw->phy.ops.enter_lplu) { 39636f37f232SEric Joyner /* Turn off support for APM wakeup. (Using ACPI instead) */ 39646f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_GRC, 39656f37f232SEric Joyner IXGBE_READ_REG(hw, IXGBE_GRC) & ~(u32)2); 39666f37f232SEric Joyner 39676f37f232SEric Joyner /* 39686f37f232SEric Joyner * Clear Wake Up Status register to prevent any previous wakeup 39696f37f232SEric Joyner * events from waking us up immediately after we suspend. 39706f37f232SEric Joyner */ 39716f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); 39726f37f232SEric Joyner 39736f37f232SEric Joyner /* 39746f37f232SEric Joyner * Program the Wakeup Filter Control register with user filter 39756f37f232SEric Joyner * settings 39766f37f232SEric Joyner */ 39776f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUFC, adapter->wufc); 39786f37f232SEric Joyner 39796f37f232SEric Joyner /* Enable wakeups and power management in Wakeup Control */ 39806f37f232SEric Joyner IXGBE_WRITE_REG(hw, IXGBE_WUC, 39816f37f232SEric Joyner IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN); 39826f37f232SEric Joyner 39836f37f232SEric Joyner /* X550EM baseT adapters need a special LPLU flow */ 39846f37f232SEric Joyner hw->phy.reset_disable = true; 39856f37f232SEric Joyner ixgbe_stop(adapter); 39866f37f232SEric Joyner error = hw->phy.ops.enter_lplu(hw); 39876f37f232SEric Joyner if (error) 39886f37f232SEric Joyner device_printf(dev, 39896f37f232SEric Joyner "Error entering LPLU: %d\n", error); 39906f37f232SEric Joyner hw->phy.reset_disable = false; 39916f37f232SEric Joyner } else { 39926f37f232SEric Joyner /* Just stop for other adapters */ 39936f37f232SEric Joyner ixgbe_stop(adapter); 39946f37f232SEric Joyner } 39956f37f232SEric Joyner 39966f37f232SEric Joyner return error; 39976f37f232SEric Joyner } 39986f37f232SEric Joyner 3999758cc3dcSJack F Vogel /********************************************************************** 4000758cc3dcSJack F Vogel * 4001758cc3dcSJack F Vogel * Update the board statistics counters. 4002758cc3dcSJack F Vogel * 4003758cc3dcSJack F Vogel **********************************************************************/ 4004758cc3dcSJack F Vogel static void 4005758cc3dcSJack F Vogel ixgbe_update_stats_counters(struct adapter *adapter) 4006758cc3dcSJack F Vogel { 4007758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 4008758cc3dcSJack F Vogel u32 missed_rx = 0, bprc, lxon, lxoff, total; 4009758cc3dcSJack F Vogel u64 total_missed_rx = 0; 4010758cc3dcSJack F Vogel 4011758cc3dcSJack F Vogel adapter->stats.pf.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); 4012758cc3dcSJack F Vogel adapter->stats.pf.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC); 4013758cc3dcSJack F Vogel adapter->stats.pf.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC); 4014758cc3dcSJack F Vogel adapter->stats.pf.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC); 4015758cc3dcSJack F Vogel 4016758cc3dcSJack F Vogel for (int i = 0; i < 16; i++) { 4017758cc3dcSJack F Vogel adapter->stats.pf.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); 4018758cc3dcSJack F Vogel adapter->stats.pf.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); 4019758cc3dcSJack F Vogel adapter->stats.pf.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); 4020758cc3dcSJack F Vogel } 4021758cc3dcSJack F Vogel adapter->stats.pf.mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC); 4022758cc3dcSJack F Vogel adapter->stats.pf.mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC); 4023758cc3dcSJack F Vogel adapter->stats.pf.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); 4024758cc3dcSJack F Vogel 4025758cc3dcSJack F Vogel /* Hardware workaround, gprc counts missed packets */ 4026758cc3dcSJack F Vogel adapter->stats.pf.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); 4027758cc3dcSJack F Vogel adapter->stats.pf.gprc -= missed_rx; 4028758cc3dcSJack F Vogel 4029758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 4030758cc3dcSJack F Vogel adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) + 4031758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); 4032758cc3dcSJack F Vogel adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) + 4033758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); 4034758cc3dcSJack F Vogel adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORL) + 4035758cc3dcSJack F Vogel ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); 4036758cc3dcSJack F Vogel adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); 4037758cc3dcSJack F Vogel adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); 4038758cc3dcSJack F Vogel } else { 4039758cc3dcSJack F Vogel adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); 4040758cc3dcSJack F Vogel adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); 4041758cc3dcSJack F Vogel /* 82598 only has a counter in the high register */ 4042758cc3dcSJack F Vogel adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); 4043758cc3dcSJack F Vogel adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); 4044758cc3dcSJack F Vogel adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORH); 4045758cc3dcSJack F Vogel } 4046758cc3dcSJack F Vogel 4047758cc3dcSJack F Vogel /* 4048758cc3dcSJack F Vogel * Workaround: mprc hardware is incorrectly counting 4049758cc3dcSJack F Vogel * broadcasts, so for now we subtract those. 4050758cc3dcSJack F Vogel */ 4051758cc3dcSJack F Vogel bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); 4052758cc3dcSJack F Vogel adapter->stats.pf.bprc += bprc; 4053758cc3dcSJack F Vogel adapter->stats.pf.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); 4054758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 4055758cc3dcSJack F Vogel adapter->stats.pf.mprc -= bprc; 4056758cc3dcSJack F Vogel 4057758cc3dcSJack F Vogel adapter->stats.pf.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); 4058758cc3dcSJack F Vogel adapter->stats.pf.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); 4059758cc3dcSJack F Vogel adapter->stats.pf.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); 4060758cc3dcSJack F Vogel adapter->stats.pf.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); 4061758cc3dcSJack F Vogel adapter->stats.pf.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); 4062758cc3dcSJack F Vogel adapter->stats.pf.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); 4063758cc3dcSJack F Vogel 4064758cc3dcSJack F Vogel lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); 4065758cc3dcSJack F Vogel adapter->stats.pf.lxontxc += lxon; 4066758cc3dcSJack F Vogel lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); 4067758cc3dcSJack F Vogel adapter->stats.pf.lxofftxc += lxoff; 4068758cc3dcSJack F Vogel total = lxon + lxoff; 4069758cc3dcSJack F Vogel 4070758cc3dcSJack F Vogel adapter->stats.pf.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); 4071758cc3dcSJack F Vogel adapter->stats.pf.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); 4072758cc3dcSJack F Vogel adapter->stats.pf.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); 4073758cc3dcSJack F Vogel adapter->stats.pf.gptc -= total; 4074758cc3dcSJack F Vogel adapter->stats.pf.mptc -= total; 4075758cc3dcSJack F Vogel adapter->stats.pf.ptc64 -= total; 4076758cc3dcSJack F Vogel adapter->stats.pf.gotc -= total * ETHER_MIN_LEN; 4077758cc3dcSJack F Vogel 4078758cc3dcSJack F Vogel adapter->stats.pf.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); 4079758cc3dcSJack F Vogel adapter->stats.pf.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); 4080758cc3dcSJack F Vogel adapter->stats.pf.roc += IXGBE_READ_REG(hw, IXGBE_ROC); 4081758cc3dcSJack F Vogel adapter->stats.pf.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); 4082758cc3dcSJack F Vogel adapter->stats.pf.mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC); 4083758cc3dcSJack F Vogel adapter->stats.pf.mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC); 4084758cc3dcSJack F Vogel adapter->stats.pf.mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC); 4085758cc3dcSJack F Vogel adapter->stats.pf.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); 4086758cc3dcSJack F Vogel adapter->stats.pf.tpt += IXGBE_READ_REG(hw, IXGBE_TPT); 4087758cc3dcSJack F Vogel adapter->stats.pf.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); 4088758cc3dcSJack F Vogel adapter->stats.pf.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); 4089758cc3dcSJack F Vogel adapter->stats.pf.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); 4090758cc3dcSJack F Vogel adapter->stats.pf.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); 4091758cc3dcSJack F Vogel adapter->stats.pf.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); 4092758cc3dcSJack F Vogel adapter->stats.pf.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); 4093758cc3dcSJack F Vogel adapter->stats.pf.xec += IXGBE_READ_REG(hw, IXGBE_XEC); 4094758cc3dcSJack F Vogel adapter->stats.pf.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); 4095758cc3dcSJack F Vogel adapter->stats.pf.fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST); 4096758cc3dcSJack F Vogel /* Only read FCOE on 82599 */ 4097758cc3dcSJack F Vogel if (hw->mac.type != ixgbe_mac_82598EB) { 4098758cc3dcSJack F Vogel adapter->stats.pf.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); 4099758cc3dcSJack F Vogel adapter->stats.pf.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); 4100758cc3dcSJack F Vogel adapter->stats.pf.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); 4101758cc3dcSJack F Vogel adapter->stats.pf.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); 4102758cc3dcSJack F Vogel adapter->stats.pf.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); 4103758cc3dcSJack F Vogel } 4104758cc3dcSJack F Vogel 4105758cc3dcSJack F Vogel /* Fill out the OS statistics structure */ 4106758cc3dcSJack F Vogel IXGBE_SET_IPACKETS(adapter, adapter->stats.pf.gprc); 4107758cc3dcSJack F Vogel IXGBE_SET_OPACKETS(adapter, adapter->stats.pf.gptc); 4108758cc3dcSJack F Vogel IXGBE_SET_IBYTES(adapter, adapter->stats.pf.gorc); 4109758cc3dcSJack F Vogel IXGBE_SET_OBYTES(adapter, adapter->stats.pf.gotc); 4110758cc3dcSJack F Vogel IXGBE_SET_IMCASTS(adapter, adapter->stats.pf.mprc); 4111758cc3dcSJack F Vogel IXGBE_SET_OMCASTS(adapter, adapter->stats.pf.mptc); 4112758cc3dcSJack F Vogel IXGBE_SET_COLLISIONS(adapter, 0); 4113758cc3dcSJack F Vogel IXGBE_SET_IQDROPS(adapter, total_missed_rx); 4114758cc3dcSJack F Vogel IXGBE_SET_IERRORS(adapter, adapter->stats.pf.crcerrs 4115758cc3dcSJack F Vogel + adapter->stats.pf.rlec); 4116758cc3dcSJack F Vogel } 4117758cc3dcSJack F Vogel 4118758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036 4119758cc3dcSJack F Vogel static uint64_t 4120758cc3dcSJack F Vogel ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt) 4121758cc3dcSJack F Vogel { 4122758cc3dcSJack F Vogel struct adapter *adapter; 4123625d12c6SJohn Baldwin struct tx_ring *txr; 4124625d12c6SJohn Baldwin uint64_t rv; 4125758cc3dcSJack F Vogel 4126758cc3dcSJack F Vogel adapter = if_getsoftc(ifp); 4127758cc3dcSJack F Vogel 4128758cc3dcSJack F Vogel switch (cnt) { 4129758cc3dcSJack F Vogel case IFCOUNTER_IPACKETS: 4130758cc3dcSJack F Vogel return (adapter->ipackets); 4131758cc3dcSJack F Vogel case IFCOUNTER_OPACKETS: 4132758cc3dcSJack F Vogel return (adapter->opackets); 4133758cc3dcSJack F Vogel case IFCOUNTER_IBYTES: 4134758cc3dcSJack F Vogel return (adapter->ibytes); 4135758cc3dcSJack F Vogel case IFCOUNTER_OBYTES: 4136758cc3dcSJack F Vogel return (adapter->obytes); 4137758cc3dcSJack F Vogel case IFCOUNTER_IMCASTS: 4138758cc3dcSJack F Vogel return (adapter->imcasts); 4139758cc3dcSJack F Vogel case IFCOUNTER_OMCASTS: 4140758cc3dcSJack F Vogel return (adapter->omcasts); 4141758cc3dcSJack F Vogel case IFCOUNTER_COLLISIONS: 4142758cc3dcSJack F Vogel return (0); 4143758cc3dcSJack F Vogel case IFCOUNTER_IQDROPS: 4144758cc3dcSJack F Vogel return (adapter->iqdrops); 4145625d12c6SJohn Baldwin case IFCOUNTER_OQDROPS: 4146625d12c6SJohn Baldwin rv = 0; 4147625d12c6SJohn Baldwin txr = adapter->tx_rings; 4148625d12c6SJohn Baldwin for (int i = 0; i < adapter->num_queues; i++, txr++) 4149625d12c6SJohn Baldwin rv += txr->br->br_drops; 4150625d12c6SJohn Baldwin return (rv); 4151758cc3dcSJack F Vogel case IFCOUNTER_IERRORS: 4152758cc3dcSJack F Vogel return (adapter->ierrors); 4153758cc3dcSJack F Vogel default: 4154758cc3dcSJack F Vogel return (if_get_counter_default(ifp, cnt)); 4155758cc3dcSJack F Vogel } 4156758cc3dcSJack F Vogel } 4157758cc3dcSJack F Vogel #endif 4158758cc3dcSJack F Vogel 4159758cc3dcSJack F Vogel /** ixgbe_sysctl_tdh_handler - Handler function 4160758cc3dcSJack F Vogel * Retrieves the TDH value from the hardware 4161758cc3dcSJack F Vogel */ 4162758cc3dcSJack F Vogel static int 4163758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS) 4164758cc3dcSJack F Vogel { 4165758cc3dcSJack F Vogel int error; 4166758cc3dcSJack F Vogel 4167758cc3dcSJack F Vogel struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); 4168758cc3dcSJack F Vogel if (!txr) return 0; 4169758cc3dcSJack F Vogel 4170758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me)); 4171758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4172758cc3dcSJack F Vogel if (error || !req->newptr) 4173758cc3dcSJack F Vogel return error; 4174758cc3dcSJack F Vogel return 0; 4175758cc3dcSJack F Vogel } 4176758cc3dcSJack F Vogel 4177758cc3dcSJack F Vogel /** ixgbe_sysctl_tdt_handler - Handler function 4178758cc3dcSJack F Vogel * Retrieves the TDT value from the hardware 4179758cc3dcSJack F Vogel */ 4180758cc3dcSJack F Vogel static int 4181758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS) 4182758cc3dcSJack F Vogel { 4183758cc3dcSJack F Vogel int error; 4184758cc3dcSJack F Vogel 4185758cc3dcSJack F Vogel struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); 4186758cc3dcSJack F Vogel if (!txr) return 0; 4187758cc3dcSJack F Vogel 4188758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me)); 4189758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4190758cc3dcSJack F Vogel if (error || !req->newptr) 4191758cc3dcSJack F Vogel return error; 4192758cc3dcSJack F Vogel return 0; 4193758cc3dcSJack F Vogel } 4194758cc3dcSJack F Vogel 4195758cc3dcSJack F Vogel /** ixgbe_sysctl_rdh_handler - Handler function 4196758cc3dcSJack F Vogel * Retrieves the RDH value from the hardware 4197758cc3dcSJack F Vogel */ 4198758cc3dcSJack F Vogel static int 4199758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS) 4200758cc3dcSJack F Vogel { 4201758cc3dcSJack F Vogel int error; 4202758cc3dcSJack F Vogel 4203758cc3dcSJack F Vogel struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); 4204758cc3dcSJack F Vogel if (!rxr) return 0; 4205758cc3dcSJack F Vogel 4206758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me)); 4207758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4208758cc3dcSJack F Vogel if (error || !req->newptr) 4209758cc3dcSJack F Vogel return error; 4210758cc3dcSJack F Vogel return 0; 4211758cc3dcSJack F Vogel } 4212758cc3dcSJack F Vogel 4213758cc3dcSJack F Vogel /** ixgbe_sysctl_rdt_handler - Handler function 4214758cc3dcSJack F Vogel * Retrieves the RDT value from the hardware 4215758cc3dcSJack F Vogel */ 4216758cc3dcSJack F Vogel static int 4217758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) 4218758cc3dcSJack F Vogel { 4219758cc3dcSJack F Vogel int error; 4220758cc3dcSJack F Vogel 4221758cc3dcSJack F Vogel struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); 4222758cc3dcSJack F Vogel if (!rxr) return 0; 4223758cc3dcSJack F Vogel 4224758cc3dcSJack F Vogel unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me)); 4225758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &val, 0, req); 4226758cc3dcSJack F Vogel if (error || !req->newptr) 4227758cc3dcSJack F Vogel return error; 4228758cc3dcSJack F Vogel return 0; 4229758cc3dcSJack F Vogel } 4230758cc3dcSJack F Vogel 4231758cc3dcSJack F Vogel static int 4232758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS) 4233758cc3dcSJack F Vogel { 4234758cc3dcSJack F Vogel int error; 4235758cc3dcSJack F Vogel struct ix_queue *que = ((struct ix_queue *)oidp->oid_arg1); 4236758cc3dcSJack F Vogel unsigned int reg, usec, rate; 4237758cc3dcSJack F Vogel 4238758cc3dcSJack F Vogel reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix)); 4239758cc3dcSJack F Vogel usec = ((reg & 0x0FF8) >> 3); 4240758cc3dcSJack F Vogel if (usec > 0) 4241758cc3dcSJack F Vogel rate = 500000 / usec; 4242758cc3dcSJack F Vogel else 4243758cc3dcSJack F Vogel rate = 0; 4244758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &rate, 0, req); 4245758cc3dcSJack F Vogel if (error || !req->newptr) 4246758cc3dcSJack F Vogel return error; 4247758cc3dcSJack F Vogel reg &= ~0xfff; /* default, no limitation */ 4248758cc3dcSJack F Vogel ixgbe_max_interrupt_rate = 0; 4249758cc3dcSJack F Vogel if (rate > 0 && rate < 500000) { 4250758cc3dcSJack F Vogel if (rate < 1000) 4251758cc3dcSJack F Vogel rate = 1000; 4252758cc3dcSJack F Vogel ixgbe_max_interrupt_rate = rate; 4253758cc3dcSJack F Vogel reg |= ((4000000/rate) & 0xff8 ); 4254758cc3dcSJack F Vogel } 4255758cc3dcSJack F Vogel IXGBE_WRITE_REG(&que->adapter->hw, IXGBE_EITR(que->msix), reg); 4256758cc3dcSJack F Vogel return 0; 4257758cc3dcSJack F Vogel } 4258758cc3dcSJack F Vogel 42596f37f232SEric Joyner static void 42606f37f232SEric Joyner ixgbe_add_device_sysctls(struct adapter *adapter) 42616f37f232SEric Joyner { 42626f37f232SEric Joyner device_t dev = adapter->dev; 42636f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 42646f37f232SEric Joyner struct sysctl_oid_list *child; 42656f37f232SEric Joyner struct sysctl_ctx_list *ctx; 42666f37f232SEric Joyner 42676f37f232SEric Joyner ctx = device_get_sysctl_ctx(dev); 42686f37f232SEric Joyner child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 42696f37f232SEric Joyner 42706f37f232SEric Joyner /* Sysctls for all devices */ 42716f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fc", 42726f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 42736f37f232SEric Joyner ixgbe_set_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC); 42746f37f232SEric Joyner 42756f37f232SEric Joyner SYSCTL_ADD_INT(ctx, child, OID_AUTO, "enable_aim", 42766f37f232SEric Joyner CTLFLAG_RW, 42776f37f232SEric Joyner &ixgbe_enable_aim, 1, "Interrupt Moderation"); 42786f37f232SEric Joyner 42796f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "advertise_speed", 42806f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 42816f37f232SEric Joyner ixgbe_set_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED); 42826f37f232SEric Joyner 42836f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "thermal_test", 42846f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 42856f37f232SEric Joyner ixgbe_sysctl_thermal_test, "I", "Thermal Test"); 42866f37f232SEric Joyner 4287a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG 4288a9ca1c79SSean Bruno /* testing sysctls (for all devices) */ 4289a9ca1c79SSean Bruno SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "power_state", 4290a9ca1c79SSean Bruno CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 4291a9ca1c79SSean Bruno ixgbe_sysctl_power_state, "I", "PCI Power State"); 4292a9ca1c79SSean Bruno 4293a9ca1c79SSean Bruno SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config", 4294a9ca1c79SSean Bruno CTLTYPE_STRING | CTLFLAG_RD, adapter, 0, 4295a9ca1c79SSean Bruno ixgbe_sysctl_print_rss_config, "A", "Prints RSS Configuration"); 4296a9ca1c79SSean Bruno #endif 4297a9ca1c79SSean Bruno /* for X550 series devices */ 42986f37f232SEric Joyner if (hw->mac.type >= ixgbe_mac_X550) 42996f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac", 43006f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 43016f37f232SEric Joyner ixgbe_sysctl_dmac, "I", "DMA Coalesce"); 43026f37f232SEric Joyner 4303a9ca1c79SSean Bruno /* for X552 backplane devices */ 4304a9ca1c79SSean Bruno if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { 43056f37f232SEric Joyner struct sysctl_oid *eee_node; 43066f37f232SEric Joyner struct sysctl_oid_list *eee_list; 43076f37f232SEric Joyner 43086f37f232SEric Joyner eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee", 43096f37f232SEric Joyner CTLFLAG_RD, NULL, 43106f37f232SEric Joyner "Energy Efficient Ethernet sysctls"); 43116f37f232SEric Joyner eee_list = SYSCTL_CHILDREN(eee_node); 43126f37f232SEric Joyner 43136f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "enable", 43146f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 43156f37f232SEric Joyner ixgbe_sysctl_eee_enable, "I", 43166f37f232SEric Joyner "Enable or Disable EEE"); 43176f37f232SEric Joyner 43186f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "negotiated", 43196f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 43206f37f232SEric Joyner ixgbe_sysctl_eee_negotiated, "I", 43216f37f232SEric Joyner "EEE negotiated on link"); 43226f37f232SEric Joyner 43236f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_status", 43246f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 43256f37f232SEric Joyner ixgbe_sysctl_eee_tx_lpi_status, "I", 43266f37f232SEric Joyner "Whether or not TX link is in LPI state"); 43276f37f232SEric Joyner 43286f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "rx_lpi_status", 43296f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 43306f37f232SEric Joyner ixgbe_sysctl_eee_rx_lpi_status, "I", 43316f37f232SEric Joyner "Whether or not RX link is in LPI state"); 4332a9ca1c79SSean Bruno 4333a9ca1c79SSean Bruno SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_delay", 4334a9ca1c79SSean Bruno CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 4335a9ca1c79SSean Bruno ixgbe_sysctl_eee_tx_lpi_delay, "I", 4336a9ca1c79SSean Bruno "TX LPI entry delay in microseconds"); 43376f37f232SEric Joyner } 43386f37f232SEric Joyner 4339a9ca1c79SSean Bruno /* for WoL-capable devices */ 4340a9ca1c79SSean Bruno if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { 43416f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wol_enable", 43426f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 43436f37f232SEric Joyner ixgbe_sysctl_wol_enable, "I", 43446f37f232SEric Joyner "Enable/Disable Wake on LAN"); 43456f37f232SEric Joyner 43466f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wufc", 43476f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RW, adapter, 0, 43486f37f232SEric Joyner ixgbe_sysctl_wufc, "I", 43496f37f232SEric Joyner "Enable/Disable Wake Up Filters"); 43506f37f232SEric Joyner } 43516f37f232SEric Joyner 4352a9ca1c79SSean Bruno /* for X552/X557-AT devices */ 43536f37f232SEric Joyner if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { 43546f37f232SEric Joyner struct sysctl_oid *phy_node; 43556f37f232SEric Joyner struct sysctl_oid_list *phy_list; 43566f37f232SEric Joyner 43576f37f232SEric Joyner phy_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "phy", 43586f37f232SEric Joyner CTLFLAG_RD, NULL, 43596f37f232SEric Joyner "External PHY sysctls"); 43606f37f232SEric Joyner phy_list = SYSCTL_CHILDREN(phy_node); 43616f37f232SEric Joyner 43626f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "temp", 43636f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 43646f37f232SEric Joyner ixgbe_sysctl_phy_temp, "I", 43656f37f232SEric Joyner "Current External PHY Temperature (Celsius)"); 43666f37f232SEric Joyner 43676f37f232SEric Joyner SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "overtemp_occurred", 43686f37f232SEric Joyner CTLTYPE_INT | CTLFLAG_RD, adapter, 0, 43696f37f232SEric Joyner ixgbe_sysctl_phy_overtemp_occurred, "I", 43706f37f232SEric Joyner "External PHY High Temperature Event Occurred"); 43716f37f232SEric Joyner } 43726f37f232SEric Joyner } 43736f37f232SEric Joyner 4374758cc3dcSJack F Vogel /* 4375758cc3dcSJack F Vogel * Add sysctl variables, one per statistic, to the system. 4376758cc3dcSJack F Vogel */ 4377758cc3dcSJack F Vogel static void 4378758cc3dcSJack F Vogel ixgbe_add_hw_stats(struct adapter *adapter) 4379758cc3dcSJack F Vogel { 4380758cc3dcSJack F Vogel device_t dev = adapter->dev; 4381758cc3dcSJack F Vogel 4382758cc3dcSJack F Vogel struct tx_ring *txr = adapter->tx_rings; 4383758cc3dcSJack F Vogel struct rx_ring *rxr = adapter->rx_rings; 4384758cc3dcSJack F Vogel 4385758cc3dcSJack F Vogel struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 4386758cc3dcSJack F Vogel struct sysctl_oid *tree = device_get_sysctl_tree(dev); 4387758cc3dcSJack F Vogel struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 4388758cc3dcSJack F Vogel struct ixgbe_hw_stats *stats = &adapter->stats.pf; 4389758cc3dcSJack F Vogel 4390758cc3dcSJack F Vogel struct sysctl_oid *stat_node, *queue_node; 4391758cc3dcSJack F Vogel struct sysctl_oid_list *stat_list, *queue_list; 4392758cc3dcSJack F Vogel 4393758cc3dcSJack F Vogel #define QUEUE_NAME_LEN 32 4394758cc3dcSJack F Vogel char namebuf[QUEUE_NAME_LEN]; 4395758cc3dcSJack F Vogel 4396758cc3dcSJack F Vogel /* Driver Statistics */ 4397758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", 4398758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->dropped_pkts, 4399758cc3dcSJack F Vogel "Driver dropped packets"); 4400758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", 4401758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->mbuf_defrag_failed, 4402758cc3dcSJack F Vogel "m_defrag() failed"); 4403758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", 4404758cc3dcSJack F Vogel CTLFLAG_RD, &adapter->watchdog_events, 4405758cc3dcSJack F Vogel "Watchdog timeouts"); 4406758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", 44076f37f232SEric Joyner CTLFLAG_RD, &adapter->link_irq, 4408758cc3dcSJack F Vogel "Link MSIX IRQ Handled"); 4409758cc3dcSJack F Vogel 4410758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, txr++) { 4411758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4412758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4413758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4414758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4415758cc3dcSJack F Vogel 4416758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate", 4417758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RW, &adapter->queues[i], 4418758cc3dcSJack F Vogel sizeof(&adapter->queues[i]), 4419758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler, "IU", 4420758cc3dcSJack F Vogel "Interrupt Rate"); 4421758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", 4422758cc3dcSJack F Vogel CTLFLAG_RD, &(adapter->queues[i].irqs), 4423758cc3dcSJack F Vogel "irqs on this queue"); 4424758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", 4425758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), 4426758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler, "IU", 4427758cc3dcSJack F Vogel "Transmit Descriptor Head"); 4428758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", 4429758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), 4430758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler, "IU", 4431758cc3dcSJack F Vogel "Transmit Descriptor Tail"); 4432758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx", 4433758cc3dcSJack F Vogel CTLFLAG_RD, &txr->tso_tx, 4434758cc3dcSJack F Vogel "TSO"); 4435758cc3dcSJack F Vogel SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_tx_dma_setup", 4436758cc3dcSJack F Vogel CTLFLAG_RD, &txr->no_tx_dma_setup, 4437758cc3dcSJack F Vogel "Driver tx dma failure in xmit"); 4438758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", 4439758cc3dcSJack F Vogel CTLFLAG_RD, &txr->no_desc_avail, 4440758cc3dcSJack F Vogel "Queue No Descriptor Available"); 4441758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", 4442758cc3dcSJack F Vogel CTLFLAG_RD, &txr->total_packets, 4443758cc3dcSJack F Vogel "Queue Packets Transmitted"); 4444625d12c6SJohn Baldwin SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops", 4445625d12c6SJohn Baldwin CTLFLAG_RD, &txr->br->br_drops, 4446625d12c6SJohn Baldwin "Packets dropped in buf_ring"); 4447758cc3dcSJack F Vogel } 4448758cc3dcSJack F Vogel 4449758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++, rxr++) { 4450758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4451758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4452758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4453758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4454758cc3dcSJack F Vogel 4455758cc3dcSJack F Vogel struct lro_ctrl *lro = &rxr->lro; 4456758cc3dcSJack F Vogel 4457758cc3dcSJack F Vogel snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); 4458758cc3dcSJack F Vogel queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 4459758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "Queue Name"); 4460758cc3dcSJack F Vogel queue_list = SYSCTL_CHILDREN(queue_node); 4461758cc3dcSJack F Vogel 4462758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", 4463758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), 4464758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler, "IU", 4465758cc3dcSJack F Vogel "Receive Descriptor Head"); 4466758cc3dcSJack F Vogel SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", 4467758cc3dcSJack F Vogel CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), 4468758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler, "IU", 4469758cc3dcSJack F Vogel "Receive Descriptor Tail"); 4470758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", 4471758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_packets, 4472758cc3dcSJack F Vogel "Queue Packets Received"); 4473758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", 4474758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_bytes, 4475758cc3dcSJack F Vogel "Queue Bytes Received"); 4476758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies", 4477758cc3dcSJack F Vogel CTLFLAG_RD, &rxr->rx_copies, 4478758cc3dcSJack F Vogel "Copied RX Frames"); 4479758cc3dcSJack F Vogel SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_queued", 4480758cc3dcSJack F Vogel CTLFLAG_RD, &lro->lro_queued, 0, 4481758cc3dcSJack F Vogel "LRO Queued"); 4482758cc3dcSJack F Vogel SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_flushed", 4483758cc3dcSJack F Vogel CTLFLAG_RD, &lro->lro_flushed, 0, 4484758cc3dcSJack F Vogel "LRO Flushed"); 4485758cc3dcSJack F Vogel } 4486758cc3dcSJack F Vogel 4487758cc3dcSJack F Vogel /* MAC stats get the own sub node */ 4488758cc3dcSJack F Vogel 4489758cc3dcSJack F Vogel stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", 4490758cc3dcSJack F Vogel CTLFLAG_RD, NULL, "MAC Statistics"); 4491758cc3dcSJack F Vogel stat_list = SYSCTL_CHILDREN(stat_node); 4492758cc3dcSJack F Vogel 4493758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs", 4494758cc3dcSJack F Vogel CTLFLAG_RD, &stats->crcerrs, 4495758cc3dcSJack F Vogel "CRC Errors"); 4496758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs", 4497758cc3dcSJack F Vogel CTLFLAG_RD, &stats->illerrc, 4498758cc3dcSJack F Vogel "Illegal Byte Errors"); 4499758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs", 4500758cc3dcSJack F Vogel CTLFLAG_RD, &stats->errbc, 4501758cc3dcSJack F Vogel "Byte Errors"); 4502758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards", 4503758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mspdc, 4504758cc3dcSJack F Vogel "MAC Short Packets Discarded"); 4505758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults", 4506758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mlfc, 4507758cc3dcSJack F Vogel "MAC Local Faults"); 4508758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults", 4509758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mrfc, 4510758cc3dcSJack F Vogel "MAC Remote Faults"); 4511758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs", 4512758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rlec, 4513758cc3dcSJack F Vogel "Receive Length Errors"); 4514758cc3dcSJack F Vogel 4515758cc3dcSJack F Vogel /* Flow Control stats */ 4516758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd", 4517758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxontxc, 4518758cc3dcSJack F Vogel "Link XON Transmitted"); 4519758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd", 4520758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxonrxc, 4521758cc3dcSJack F Vogel "Link XON Received"); 4522758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd", 4523758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxofftxc, 4524758cc3dcSJack F Vogel "Link XOFF Transmitted"); 4525758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd", 4526758cc3dcSJack F Vogel CTLFLAG_RD, &stats->lxoffrxc, 4527758cc3dcSJack F Vogel "Link XOFF Received"); 4528758cc3dcSJack F Vogel 4529758cc3dcSJack F Vogel /* Packet Reception Stats */ 4530758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd", 4531758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tor, 4532758cc3dcSJack F Vogel "Total Octets Received"); 4533758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", 4534758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gorc, 4535758cc3dcSJack F Vogel "Good Octets Received"); 4536758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd", 4537758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tpr, 4538758cc3dcSJack F Vogel "Total Packets Received"); 4539758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", 4540758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gprc, 4541758cc3dcSJack F Vogel "Good Packets Received"); 4542758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", 4543758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mprc, 4544758cc3dcSJack F Vogel "Multicast Packets Received"); 4545758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", 4546758cc3dcSJack F Vogel CTLFLAG_RD, &stats->bprc, 4547758cc3dcSJack F Vogel "Broadcast Packets Received"); 4548758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", 4549758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc64, 4550758cc3dcSJack F Vogel "64 byte frames received "); 4551758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", 4552758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc127, 4553758cc3dcSJack F Vogel "65-127 byte frames received"); 4554758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", 4555758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc255, 4556758cc3dcSJack F Vogel "128-255 byte frames received"); 4557758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", 4558758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc511, 4559758cc3dcSJack F Vogel "256-511 byte frames received"); 4560758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", 4561758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc1023, 4562758cc3dcSJack F Vogel "512-1023 byte frames received"); 4563758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", 4564758cc3dcSJack F Vogel CTLFLAG_RD, &stats->prc1522, 4565758cc3dcSJack F Vogel "1023-1522 byte frames received"); 4566758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized", 4567758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ruc, 4568758cc3dcSJack F Vogel "Receive Undersized"); 4569758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", 4570758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rfc, 4571758cc3dcSJack F Vogel "Fragmented Packets Received "); 4572758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized", 4573758cc3dcSJack F Vogel CTLFLAG_RD, &stats->roc, 4574758cc3dcSJack F Vogel "Oversized Packets Received"); 4575758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd", 4576758cc3dcSJack F Vogel CTLFLAG_RD, &stats->rjc, 4577758cc3dcSJack F Vogel "Received Jabber"); 4578758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd", 4579758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngprc, 4580758cc3dcSJack F Vogel "Management Packets Received"); 4581758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd", 4582758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngptc, 4583758cc3dcSJack F Vogel "Management Packets Dropped"); 4584758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs", 4585758cc3dcSJack F Vogel CTLFLAG_RD, &stats->xec, 4586758cc3dcSJack F Vogel "Checksum Errors"); 4587758cc3dcSJack F Vogel 4588758cc3dcSJack F Vogel /* Packet Transmission Stats */ 4589758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", 4590758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gotc, 4591758cc3dcSJack F Vogel "Good Octets Transmitted"); 4592758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", 4593758cc3dcSJack F Vogel CTLFLAG_RD, &stats->tpt, 4594758cc3dcSJack F Vogel "Total Packets Transmitted"); 4595758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", 4596758cc3dcSJack F Vogel CTLFLAG_RD, &stats->gptc, 4597758cc3dcSJack F Vogel "Good Packets Transmitted"); 4598758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", 4599758cc3dcSJack F Vogel CTLFLAG_RD, &stats->bptc, 4600758cc3dcSJack F Vogel "Broadcast Packets Transmitted"); 4601758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", 4602758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mptc, 4603758cc3dcSJack F Vogel "Multicast Packets Transmitted"); 4604758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd", 4605758cc3dcSJack F Vogel CTLFLAG_RD, &stats->mngptc, 4606758cc3dcSJack F Vogel "Management Packets Transmitted"); 4607758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", 4608758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc64, 4609758cc3dcSJack F Vogel "64 byte frames transmitted "); 4610758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", 4611758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc127, 4612758cc3dcSJack F Vogel "65-127 byte frames transmitted"); 4613758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", 4614758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc255, 4615758cc3dcSJack F Vogel "128-255 byte frames transmitted"); 4616758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", 4617758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc511, 4618758cc3dcSJack F Vogel "256-511 byte frames transmitted"); 4619758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", 4620758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc1023, 4621758cc3dcSJack F Vogel "512-1023 byte frames transmitted"); 4622758cc3dcSJack F Vogel SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", 4623758cc3dcSJack F Vogel CTLFLAG_RD, &stats->ptc1522, 4624758cc3dcSJack F Vogel "1024-1522 byte frames transmitted"); 4625758cc3dcSJack F Vogel } 4626758cc3dcSJack F Vogel 4627b0c041f8SSean Bruno static void 4628b0c041f8SSean Bruno ixgbe_set_sysctl_value(struct adapter *adapter, const char *name, 4629b0c041f8SSean Bruno const char *description, int *limit, int value) 4630b0c041f8SSean Bruno { 4631b0c041f8SSean Bruno *limit = value; 4632b0c041f8SSean Bruno SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev), 4633b0c041f8SSean Bruno SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), 4634b0c041f8SSean Bruno OID_AUTO, name, CTLFLAG_RW, limit, value, description); 4635b0c041f8SSean Bruno } 4636b0c041f8SSean Bruno 4637758cc3dcSJack F Vogel /* 4638758cc3dcSJack F Vogel ** Set flow control using sysctl: 4639758cc3dcSJack F Vogel ** Flow control values: 4640758cc3dcSJack F Vogel ** 0 - off 4641758cc3dcSJack F Vogel ** 1 - rx pause 4642758cc3dcSJack F Vogel ** 2 - tx pause 4643758cc3dcSJack F Vogel ** 3 - full 4644758cc3dcSJack F Vogel */ 4645758cc3dcSJack F Vogel static int 4646758cc3dcSJack F Vogel ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS) 4647758cc3dcSJack F Vogel { 4648758cc3dcSJack F Vogel int error, last; 4649758cc3dcSJack F Vogel struct adapter *adapter = (struct adapter *) arg1; 4650758cc3dcSJack F Vogel 4651758cc3dcSJack F Vogel last = adapter->fc; 4652758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &adapter->fc, 0, req); 4653758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4654758cc3dcSJack F Vogel return (error); 4655758cc3dcSJack F Vogel 4656758cc3dcSJack F Vogel /* Don't bother if it's not changed */ 4657758cc3dcSJack F Vogel if (adapter->fc == last) 4658758cc3dcSJack F Vogel return (0); 4659758cc3dcSJack F Vogel 4660758cc3dcSJack F Vogel switch (adapter->fc) { 4661758cc3dcSJack F Vogel case ixgbe_fc_rx_pause: 4662758cc3dcSJack F Vogel case ixgbe_fc_tx_pause: 4663758cc3dcSJack F Vogel case ixgbe_fc_full: 4664758cc3dcSJack F Vogel adapter->hw.fc.requested_mode = adapter->fc; 4665758cc3dcSJack F Vogel if (adapter->num_queues > 1) 4666758cc3dcSJack F Vogel ixgbe_disable_rx_drop(adapter); 4667758cc3dcSJack F Vogel break; 4668758cc3dcSJack F Vogel case ixgbe_fc_none: 4669758cc3dcSJack F Vogel adapter->hw.fc.requested_mode = ixgbe_fc_none; 4670758cc3dcSJack F Vogel if (adapter->num_queues > 1) 4671758cc3dcSJack F Vogel ixgbe_enable_rx_drop(adapter); 4672758cc3dcSJack F Vogel break; 4673758cc3dcSJack F Vogel default: 4674758cc3dcSJack F Vogel adapter->fc = last; 4675758cc3dcSJack F Vogel return (EINVAL); 4676758cc3dcSJack F Vogel } 4677758cc3dcSJack F Vogel /* Don't autoneg if forcing a value */ 4678758cc3dcSJack F Vogel adapter->hw.fc.disable_fc_autoneg = TRUE; 4679758cc3dcSJack F Vogel ixgbe_fc_enable(&adapter->hw); 4680758cc3dcSJack F Vogel return error; 4681758cc3dcSJack F Vogel } 4682758cc3dcSJack F Vogel 4683758cc3dcSJack F Vogel /* 4684758cc3dcSJack F Vogel ** Control advertised link speed: 4685758cc3dcSJack F Vogel ** Flags: 4686758cc3dcSJack F Vogel ** 0x1 - advertise 100 Mb 4687758cc3dcSJack F Vogel ** 0x2 - advertise 1G 4688758cc3dcSJack F Vogel ** 0x4 - advertise 10G 4689758cc3dcSJack F Vogel */ 4690758cc3dcSJack F Vogel static int 4691758cc3dcSJack F Vogel ixgbe_set_advertise(SYSCTL_HANDLER_ARGS) 4692758cc3dcSJack F Vogel { 4693758cc3dcSJack F Vogel int error = 0, requested; 4694758cc3dcSJack F Vogel struct adapter *adapter; 4695758cc3dcSJack F Vogel device_t dev; 4696758cc3dcSJack F Vogel struct ixgbe_hw *hw; 4697758cc3dcSJack F Vogel ixgbe_link_speed speed = 0; 4698758cc3dcSJack F Vogel 4699758cc3dcSJack F Vogel adapter = (struct adapter *) arg1; 4700758cc3dcSJack F Vogel dev = adapter->dev; 4701758cc3dcSJack F Vogel hw = &adapter->hw; 4702758cc3dcSJack F Vogel 4703758cc3dcSJack F Vogel requested = adapter->advertise; 4704758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &requested, 0, req); 4705758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4706758cc3dcSJack F Vogel return (error); 4707758cc3dcSJack F Vogel 4708a9ca1c79SSean Bruno /* No speed changes for backplane media */ 4709a9ca1c79SSean Bruno if (hw->phy.media_type == ixgbe_media_type_backplane) 4710a9ca1c79SSean Bruno return (ENODEV); 4711a9ca1c79SSean Bruno 4712758cc3dcSJack F Vogel /* Checks to validate new value */ 4713758cc3dcSJack F Vogel if (adapter->advertise == requested) /* no change */ 4714758cc3dcSJack F Vogel return (0); 4715758cc3dcSJack F Vogel 4716758cc3dcSJack F Vogel if (!((hw->phy.media_type == ixgbe_media_type_copper) || 4717758cc3dcSJack F Vogel (hw->phy.multispeed_fiber))) { 4718758cc3dcSJack F Vogel device_printf(dev, 4719758cc3dcSJack F Vogel "Advertised speed can only be set on copper or " 4720758cc3dcSJack F Vogel "multispeed fiber media types.\n"); 4721758cc3dcSJack F Vogel return (EINVAL); 4722758cc3dcSJack F Vogel } 4723758cc3dcSJack F Vogel 4724758cc3dcSJack F Vogel if (requested < 0x1 || requested > 0x7) { 4725758cc3dcSJack F Vogel device_printf(dev, 4726758cc3dcSJack F Vogel "Invalid advertised speed; valid modes are 0x1 through 0x7\n"); 4727758cc3dcSJack F Vogel return (EINVAL); 4728758cc3dcSJack F Vogel } 4729758cc3dcSJack F Vogel 4730758cc3dcSJack F Vogel if ((requested & 0x1) 4731758cc3dcSJack F Vogel && (hw->mac.type != ixgbe_mac_X540) 4732758cc3dcSJack F Vogel && (hw->mac.type != ixgbe_mac_X550)) { 4733758cc3dcSJack F Vogel device_printf(dev, "Set Advertise: 100Mb on X540/X550 only\n"); 4734758cc3dcSJack F Vogel return (EINVAL); 4735758cc3dcSJack F Vogel } 4736758cc3dcSJack F Vogel 4737758cc3dcSJack F Vogel /* Set new value and report new advertised mode */ 4738758cc3dcSJack F Vogel if (requested & 0x1) 4739758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_100_FULL; 4740758cc3dcSJack F Vogel if (requested & 0x2) 4741758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_1GB_FULL; 4742758cc3dcSJack F Vogel if (requested & 0x4) 4743758cc3dcSJack F Vogel speed |= IXGBE_LINK_SPEED_10GB_FULL; 4744758cc3dcSJack F Vogel 4745758cc3dcSJack F Vogel hw->mac.autotry_restart = TRUE; 4746758cc3dcSJack F Vogel hw->mac.ops.setup_link(hw, speed, TRUE); 4747758cc3dcSJack F Vogel adapter->advertise = requested; 4748758cc3dcSJack F Vogel 4749758cc3dcSJack F Vogel return (error); 4750758cc3dcSJack F Vogel } 4751758cc3dcSJack F Vogel 4752758cc3dcSJack F Vogel /* 4753a9ca1c79SSean Bruno * The following two sysctls are for X552/X557-AT devices; 47546f37f232SEric Joyner * they deal with the external PHY used in them. 4755758cc3dcSJack F Vogel */ 4756758cc3dcSJack F Vogel static int 47576f37f232SEric Joyner ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS) 4758758cc3dcSJack F Vogel { 4759758cc3dcSJack F Vogel struct adapter *adapter = (struct adapter *) arg1; 4760758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 47616f37f232SEric Joyner u16 reg; 4762758cc3dcSJack F Vogel 47636f37f232SEric Joyner if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { 47646f37f232SEric Joyner device_printf(adapter->dev, 47656f37f232SEric Joyner "Device has no supported external thermal sensor.\n"); 47666f37f232SEric Joyner return (ENODEV); 47676f37f232SEric Joyner } 4768758cc3dcSJack F Vogel 47696f37f232SEric Joyner if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP, 47706f37f232SEric Joyner IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 47716f37f232SEric Joyner ®)) { 47726f37f232SEric Joyner device_printf(adapter->dev, 47736f37f232SEric Joyner "Error reading from PHY's current temperature register\n"); 47746f37f232SEric Joyner return (EAGAIN); 47756f37f232SEric Joyner } 47766f37f232SEric Joyner 47776f37f232SEric Joyner /* Shift temp for output */ 47786f37f232SEric Joyner reg = reg >> 8; 47796f37f232SEric Joyner 47806f37f232SEric Joyner return (sysctl_handle_int(oidp, NULL, reg, req)); 47816f37f232SEric Joyner } 47826f37f232SEric Joyner 47836f37f232SEric Joyner /* 47846f37f232SEric Joyner * Reports whether the current PHY temperature is over 47856f37f232SEric Joyner * the overtemp threshold. 47866f37f232SEric Joyner * - This is reported directly from the PHY 47876f37f232SEric Joyner */ 47886f37f232SEric Joyner static int 47896f37f232SEric Joyner ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS) 47906f37f232SEric Joyner { 47916f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 47926f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 47936f37f232SEric Joyner u16 reg; 47946f37f232SEric Joyner 47956f37f232SEric Joyner if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { 47966f37f232SEric Joyner device_printf(adapter->dev, 47976f37f232SEric Joyner "Device has no supported external thermal sensor.\n"); 47986f37f232SEric Joyner return (ENODEV); 47996f37f232SEric Joyner } 48006f37f232SEric Joyner 48016f37f232SEric Joyner if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS, 48026f37f232SEric Joyner IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 48036f37f232SEric Joyner ®)) { 48046f37f232SEric Joyner device_printf(adapter->dev, 48056f37f232SEric Joyner "Error reading from PHY's temperature status register\n"); 48066f37f232SEric Joyner return (EAGAIN); 48076f37f232SEric Joyner } 48086f37f232SEric Joyner 48096f37f232SEric Joyner /* Get occurrence bit */ 48106f37f232SEric Joyner reg = !!(reg & 0x4000); 48116f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, reg, req)); 48126f37f232SEric Joyner } 48136f37f232SEric Joyner 48146f37f232SEric Joyner /* 48156f37f232SEric Joyner ** Thermal Shutdown Trigger (internal MAC) 48166f37f232SEric Joyner ** - Set this to 1 to cause an overtemp event to occur 48176f37f232SEric Joyner */ 48186f37f232SEric Joyner static int 48196f37f232SEric Joyner ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS) 48206f37f232SEric Joyner { 48216f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 48226f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 48236f37f232SEric Joyner int error, fire = 0; 4824758cc3dcSJack F Vogel 4825758cc3dcSJack F Vogel error = sysctl_handle_int(oidp, &fire, 0, req); 4826758cc3dcSJack F Vogel if ((error) || (req->newptr == NULL)) 4827758cc3dcSJack F Vogel return (error); 4828758cc3dcSJack F Vogel 4829758cc3dcSJack F Vogel if (fire) { 4830758cc3dcSJack F Vogel u32 reg = IXGBE_READ_REG(hw, IXGBE_EICS); 4831758cc3dcSJack F Vogel reg |= IXGBE_EICR_TS; 4832758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_EICS, reg); 4833758cc3dcSJack F Vogel } 4834758cc3dcSJack F Vogel 4835758cc3dcSJack F Vogel return (0); 4836758cc3dcSJack F Vogel } 4837758cc3dcSJack F Vogel 4838758cc3dcSJack F Vogel /* 48396f37f232SEric Joyner ** Manage DMA Coalescing. 48406f37f232SEric Joyner ** Control values: 48416f37f232SEric Joyner ** 0/1 - off / on (use default value of 1000) 48426f37f232SEric Joyner ** 48436f37f232SEric Joyner ** Legal timer values are: 48446f37f232SEric Joyner ** 50,100,250,500,1000,2000,5000,10000 48456f37f232SEric Joyner ** 48466f37f232SEric Joyner ** Turning off interrupt moderation will also turn this off. 48476f37f232SEric Joyner */ 48486f37f232SEric Joyner static int 48496f37f232SEric Joyner ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS) 48506f37f232SEric Joyner { 48516f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 48526f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 48536f37f232SEric Joyner int error; 4854a9ca1c79SSean Bruno u32 newval; 48556f37f232SEric Joyner 4856a9ca1c79SSean Bruno newval = adapter->dmac; 4857a9ca1c79SSean Bruno error = sysctl_handle_int(oidp, &newval, 0, req); 48586f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 48596f37f232SEric Joyner return (error); 48606f37f232SEric Joyner 4861a9ca1c79SSean Bruno switch (newval) { 48626f37f232SEric Joyner case 0: 48636f37f232SEric Joyner /* Disabled */ 4864a9ca1c79SSean Bruno adapter->dmac = 0; 48656f37f232SEric Joyner break; 4866a9ca1c79SSean Bruno case 1: 4867a9ca1c79SSean Bruno /* Enable and use default */ 48686f37f232SEric Joyner adapter->dmac = 1000; 48696f37f232SEric Joyner break; 48706f37f232SEric Joyner case 50: 48716f37f232SEric Joyner case 100: 48726f37f232SEric Joyner case 250: 48736f37f232SEric Joyner case 500: 48746f37f232SEric Joyner case 1000: 48756f37f232SEric Joyner case 2000: 48766f37f232SEric Joyner case 5000: 48776f37f232SEric Joyner case 10000: 48786f37f232SEric Joyner /* Legal values - allow */ 4879a9ca1c79SSean Bruno adapter->dmac = newval; 48806f37f232SEric Joyner break; 48816f37f232SEric Joyner default: 48826f37f232SEric Joyner /* Do nothing, illegal value */ 48836f37f232SEric Joyner return (EINVAL); 48846f37f232SEric Joyner } 48856f37f232SEric Joyner 48866f37f232SEric Joyner /* Re-initialize hardware if it's already running */ 48876f37f232SEric Joyner if (ifp->if_drv_flags & IFF_DRV_RUNNING) 48886f37f232SEric Joyner ixgbe_init(adapter); 48896f37f232SEric Joyner 48906f37f232SEric Joyner return (0); 48916f37f232SEric Joyner } 48926f37f232SEric Joyner 4893a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG 4894a9ca1c79SSean Bruno /** 4895a9ca1c79SSean Bruno * Sysctl to test power states 4896a9ca1c79SSean Bruno * Values: 4897a9ca1c79SSean Bruno * 0 - set device to D0 4898a9ca1c79SSean Bruno * 3 - set device to D3 4899a9ca1c79SSean Bruno * (none) - get current device power state 4900a9ca1c79SSean Bruno */ 4901a9ca1c79SSean Bruno static int 4902a9ca1c79SSean Bruno ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS) 4903a9ca1c79SSean Bruno { 4904a9ca1c79SSean Bruno struct adapter *adapter = (struct adapter *) arg1; 4905a9ca1c79SSean Bruno device_t dev = adapter->dev; 4906a9ca1c79SSean Bruno int curr_ps, new_ps, error = 0; 4907a9ca1c79SSean Bruno 4908a9ca1c79SSean Bruno curr_ps = new_ps = pci_get_powerstate(dev); 4909a9ca1c79SSean Bruno 4910a9ca1c79SSean Bruno error = sysctl_handle_int(oidp, &new_ps, 0, req); 4911a9ca1c79SSean Bruno if ((error) || (req->newptr == NULL)) 4912a9ca1c79SSean Bruno return (error); 4913a9ca1c79SSean Bruno 4914a9ca1c79SSean Bruno if (new_ps == curr_ps) 4915a9ca1c79SSean Bruno return (0); 4916a9ca1c79SSean Bruno 4917a9ca1c79SSean Bruno if (new_ps == 3 && curr_ps == 0) 4918a9ca1c79SSean Bruno error = DEVICE_SUSPEND(dev); 4919a9ca1c79SSean Bruno else if (new_ps == 0 && curr_ps == 3) 4920a9ca1c79SSean Bruno error = DEVICE_RESUME(dev); 4921a9ca1c79SSean Bruno else 4922a9ca1c79SSean Bruno return (EINVAL); 4923a9ca1c79SSean Bruno 4924a9ca1c79SSean Bruno device_printf(dev, "New state: %d\n", pci_get_powerstate(dev)); 4925a9ca1c79SSean Bruno 4926a9ca1c79SSean Bruno return (error); 4927a9ca1c79SSean Bruno } 4928a9ca1c79SSean Bruno #endif 49296f37f232SEric Joyner /* 49306f37f232SEric Joyner * Sysctl to enable/disable the WoL capability, if supported by the adapter. 49316f37f232SEric Joyner * Values: 49326f37f232SEric Joyner * 0 - disabled 49336f37f232SEric Joyner * 1 - enabled 49346f37f232SEric Joyner */ 49356f37f232SEric Joyner static int 49366f37f232SEric Joyner ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS) 49376f37f232SEric Joyner { 49386f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 49396f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 49406f37f232SEric Joyner int new_wol_enabled; 49416f37f232SEric Joyner int error = 0; 49426f37f232SEric Joyner 49436f37f232SEric Joyner new_wol_enabled = hw->wol_enabled; 49446f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req); 49456f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 49466f37f232SEric Joyner return (error); 4947a9ca1c79SSean Bruno new_wol_enabled = !!(new_wol_enabled); 49486f37f232SEric Joyner if (new_wol_enabled == hw->wol_enabled) 49496f37f232SEric Joyner return (0); 49506f37f232SEric Joyner 49516f37f232SEric Joyner if (new_wol_enabled > 0 && !adapter->wol_support) 49526f37f232SEric Joyner return (ENODEV); 49536f37f232SEric Joyner else 4954a9ca1c79SSean Bruno hw->wol_enabled = new_wol_enabled; 49556f37f232SEric Joyner 49566f37f232SEric Joyner return (0); 49576f37f232SEric Joyner } 49586f37f232SEric Joyner 49596f37f232SEric Joyner /* 49606f37f232SEric Joyner * Sysctl to enable/disable the Energy Efficient Ethernet capability, 49616f37f232SEric Joyner * if supported by the adapter. 49626f37f232SEric Joyner * Values: 49636f37f232SEric Joyner * 0 - disabled 49646f37f232SEric Joyner * 1 - enabled 49656f37f232SEric Joyner */ 49666f37f232SEric Joyner static int 49676f37f232SEric Joyner ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS) 49686f37f232SEric Joyner { 49696f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 497048056c88SJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 49716f37f232SEric Joyner struct ifnet *ifp = adapter->ifp; 49726f37f232SEric Joyner int new_eee_enabled, error = 0; 49736f37f232SEric Joyner 49746f37f232SEric Joyner new_eee_enabled = adapter->eee_enabled; 49756f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_eee_enabled, 0, req); 49766f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 49776f37f232SEric Joyner return (error); 4978a9ca1c79SSean Bruno new_eee_enabled = !!(new_eee_enabled); 49796f37f232SEric Joyner if (new_eee_enabled == adapter->eee_enabled) 49806f37f232SEric Joyner return (0); 49816f37f232SEric Joyner 498248056c88SJack F Vogel if (new_eee_enabled > 0 && !hw->mac.ops.setup_eee) 49836f37f232SEric Joyner return (ENODEV); 49846f37f232SEric Joyner else 4985a9ca1c79SSean Bruno adapter->eee_enabled = new_eee_enabled; 49866f37f232SEric Joyner 49876f37f232SEric Joyner /* Re-initialize hardware if it's already running */ 49886f37f232SEric Joyner if (ifp->if_drv_flags & IFF_DRV_RUNNING) 49896f37f232SEric Joyner ixgbe_init(adapter); 49906f37f232SEric Joyner 49916f37f232SEric Joyner return (0); 49926f37f232SEric Joyner } 49936f37f232SEric Joyner 49946f37f232SEric Joyner /* 49956f37f232SEric Joyner * Read-only sysctl indicating whether EEE support was negotiated 49966f37f232SEric Joyner * on the link. 49976f37f232SEric Joyner */ 49986f37f232SEric Joyner static int 49996f37f232SEric Joyner ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS) 50006f37f232SEric Joyner { 50016f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 50026f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 50036f37f232SEric Joyner bool status; 50046f37f232SEric Joyner 50056f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & IXGBE_EEE_STAT_NEG); 50066f37f232SEric Joyner 50076f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 50086f37f232SEric Joyner } 50096f37f232SEric Joyner 50106f37f232SEric Joyner /* 50116f37f232SEric Joyner * Read-only sysctl indicating whether RX Link is in LPI state. 50126f37f232SEric Joyner */ 50136f37f232SEric Joyner static int 50146f37f232SEric Joyner ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS) 50156f37f232SEric Joyner { 50166f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 50176f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 50186f37f232SEric Joyner bool status; 50196f37f232SEric Joyner 50206f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & 50216f37f232SEric Joyner IXGBE_EEE_RX_LPI_STATUS); 50226f37f232SEric Joyner 50236f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 50246f37f232SEric Joyner } 50256f37f232SEric Joyner 50266f37f232SEric Joyner /* 50276f37f232SEric Joyner * Read-only sysctl indicating whether TX Link is in LPI state. 50286f37f232SEric Joyner */ 50296f37f232SEric Joyner static int 50306f37f232SEric Joyner ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS) 50316f37f232SEric Joyner { 50326f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 50336f37f232SEric Joyner struct ixgbe_hw *hw = &adapter->hw; 50346f37f232SEric Joyner bool status; 50356f37f232SEric Joyner 50366f37f232SEric Joyner status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & 50376f37f232SEric Joyner IXGBE_EEE_TX_LPI_STATUS); 50386f37f232SEric Joyner 50396f37f232SEric Joyner return (sysctl_handle_int(oidp, 0, status, req)); 50406f37f232SEric Joyner } 50416f37f232SEric Joyner 50426f37f232SEric Joyner /* 5043a9ca1c79SSean Bruno * Read-only sysctl indicating TX Link LPI delay 5044a9ca1c79SSean Bruno */ 5045a9ca1c79SSean Bruno static int 5046a9ca1c79SSean Bruno ixgbe_sysctl_eee_tx_lpi_delay(SYSCTL_HANDLER_ARGS) 5047a9ca1c79SSean Bruno { 5048a9ca1c79SSean Bruno struct adapter *adapter = (struct adapter *) arg1; 5049a9ca1c79SSean Bruno struct ixgbe_hw *hw = &adapter->hw; 5050a9ca1c79SSean Bruno u32 reg; 5051a9ca1c79SSean Bruno 5052a9ca1c79SSean Bruno reg = IXGBE_READ_REG(hw, IXGBE_EEE_SU); 5053a9ca1c79SSean Bruno 5054a9ca1c79SSean Bruno return (sysctl_handle_int(oidp, 0, reg >> 26, req)); 5055a9ca1c79SSean Bruno } 5056a9ca1c79SSean Bruno 5057a9ca1c79SSean Bruno /* 50586f37f232SEric Joyner * Sysctl to enable/disable the types of packets that the 50596f37f232SEric Joyner * adapter will wake up on upon receipt. 50606f37f232SEric Joyner * WUFC - Wake Up Filter Control 50616f37f232SEric Joyner * Flags: 50626f37f232SEric Joyner * 0x1 - Link Status Change 50636f37f232SEric Joyner * 0x2 - Magic Packet 50646f37f232SEric Joyner * 0x4 - Direct Exact 50656f37f232SEric Joyner * 0x8 - Directed Multicast 50666f37f232SEric Joyner * 0x10 - Broadcast 50676f37f232SEric Joyner * 0x20 - ARP/IPv4 Request Packet 50686f37f232SEric Joyner * 0x40 - Direct IPv4 Packet 50696f37f232SEric Joyner * 0x80 - Direct IPv6 Packet 50706f37f232SEric Joyner * 50716f37f232SEric Joyner * Setting another flag will cause the sysctl to return an 50726f37f232SEric Joyner * error. 50736f37f232SEric Joyner */ 50746f37f232SEric Joyner static int 50756f37f232SEric Joyner ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS) 50766f37f232SEric Joyner { 50776f37f232SEric Joyner struct adapter *adapter = (struct adapter *) arg1; 50786f37f232SEric Joyner int error = 0; 50796f37f232SEric Joyner u32 new_wufc; 50806f37f232SEric Joyner 50816f37f232SEric Joyner new_wufc = adapter->wufc; 50826f37f232SEric Joyner 50836f37f232SEric Joyner error = sysctl_handle_int(oidp, &new_wufc, 0, req); 50846f37f232SEric Joyner if ((error) || (req->newptr == NULL)) 50856f37f232SEric Joyner return (error); 50866f37f232SEric Joyner if (new_wufc == adapter->wufc) 50876f37f232SEric Joyner return (0); 50886f37f232SEric Joyner 50896f37f232SEric Joyner if (new_wufc & 0xffffff00) 50906f37f232SEric Joyner return (EINVAL); 50916f37f232SEric Joyner else { 50926f37f232SEric Joyner new_wufc &= 0xff; 50936f37f232SEric Joyner new_wufc |= (0xffffff & adapter->wufc); 50946f37f232SEric Joyner adapter->wufc = new_wufc; 50956f37f232SEric Joyner } 50966f37f232SEric Joyner 50976f37f232SEric Joyner return (0); 50986f37f232SEric Joyner } 50996f37f232SEric Joyner 5100a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG 5101a9ca1c79SSean Bruno static int 5102a9ca1c79SSean Bruno ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS) 5103a9ca1c79SSean Bruno { 5104a9ca1c79SSean Bruno struct adapter *adapter = (struct adapter *)arg1; 5105a9ca1c79SSean Bruno struct ixgbe_hw *hw = &adapter->hw; 5106a9ca1c79SSean Bruno device_t dev = adapter->dev; 5107a9ca1c79SSean Bruno int error = 0, reta_size; 5108a9ca1c79SSean Bruno struct sbuf *buf; 5109a9ca1c79SSean Bruno u32 reg; 5110a9ca1c79SSean Bruno 5111a9ca1c79SSean Bruno buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5112a9ca1c79SSean Bruno if (!buf) { 5113a9ca1c79SSean Bruno device_printf(dev, "Could not allocate sbuf for output.\n"); 5114a9ca1c79SSean Bruno return (ENOMEM); 5115a9ca1c79SSean Bruno } 5116a9ca1c79SSean Bruno 5117a9ca1c79SSean Bruno // TODO: use sbufs to make a string to print out 5118a9ca1c79SSean Bruno /* Set multiplier for RETA setup and table size based on MAC */ 5119a9ca1c79SSean Bruno switch (adapter->hw.mac.type) { 5120a9ca1c79SSean Bruno case ixgbe_mac_X550: 5121a9ca1c79SSean Bruno case ixgbe_mac_X550EM_x: 5122a9ca1c79SSean Bruno reta_size = 128; 5123a9ca1c79SSean Bruno break; 5124a9ca1c79SSean Bruno default: 5125a9ca1c79SSean Bruno reta_size = 32; 5126a9ca1c79SSean Bruno break; 5127a9ca1c79SSean Bruno } 5128a9ca1c79SSean Bruno 5129a9ca1c79SSean Bruno /* Print out the redirection table */ 5130a9ca1c79SSean Bruno sbuf_cat(buf, "\n"); 5131a9ca1c79SSean Bruno for (int i = 0; i < reta_size; i++) { 5132a9ca1c79SSean Bruno if (i < 32) { 5133a9ca1c79SSean Bruno reg = IXGBE_READ_REG(hw, IXGBE_RETA(i)); 5134a9ca1c79SSean Bruno sbuf_printf(buf, "RETA(%2d): 0x%08x\n", i, reg); 5135a9ca1c79SSean Bruno } else { 5136a9ca1c79SSean Bruno reg = IXGBE_READ_REG(hw, IXGBE_ERETA(i - 32)); 5137a9ca1c79SSean Bruno sbuf_printf(buf, "ERETA(%2d): 0x%08x\n", i - 32, reg); 5138a9ca1c79SSean Bruno } 5139a9ca1c79SSean Bruno } 5140a9ca1c79SSean Bruno 5141a9ca1c79SSean Bruno // TODO: print more config 5142a9ca1c79SSean Bruno 5143a9ca1c79SSean Bruno error = sbuf_finish(buf); 5144a9ca1c79SSean Bruno if (error) 5145a9ca1c79SSean Bruno device_printf(dev, "Error finishing sbuf: %d\n", error); 5146a9ca1c79SSean Bruno 5147a9ca1c79SSean Bruno sbuf_delete(buf); 5148a9ca1c79SSean Bruno return (0); 5149a9ca1c79SSean Bruno } 5150a9ca1c79SSean Bruno #endif /* IXGBE_DEBUG */ 5151a9ca1c79SSean Bruno 51526f37f232SEric Joyner /* 5153758cc3dcSJack F Vogel ** Enable the hardware to drop packets when the buffer is 5154758cc3dcSJack F Vogel ** full. This is useful when multiqueue,so that no single 5155758cc3dcSJack F Vogel ** queue being full stalls the entire RX engine. We only 5156758cc3dcSJack F Vogel ** enable this when Multiqueue AND when Flow Control is 5157758cc3dcSJack F Vogel ** disabled. 5158758cc3dcSJack F Vogel */ 5159758cc3dcSJack F Vogel static void 5160758cc3dcSJack F Vogel ixgbe_enable_rx_drop(struct adapter *adapter) 5161758cc3dcSJack F Vogel { 5162758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 5163758cc3dcSJack F Vogel 5164758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 516548056c88SJack F Vogel struct rx_ring *rxr = &adapter->rx_rings[i]; 516648056c88SJack F Vogel u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); 5167758cc3dcSJack F Vogel srrctl |= IXGBE_SRRCTL_DROP_EN; 516848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); 5169758cc3dcSJack F Vogel } 517048056c88SJack F Vogel #ifdef PCI_IOV 517148056c88SJack F Vogel /* enable drop for each vf */ 517248056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 517348056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_QDE, 517448056c88SJack F Vogel (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT) | 517548056c88SJack F Vogel IXGBE_QDE_ENABLE)); 517648056c88SJack F Vogel } 517748056c88SJack F Vogel #endif 5178758cc3dcSJack F Vogel } 5179758cc3dcSJack F Vogel 5180758cc3dcSJack F Vogel static void 5181758cc3dcSJack F Vogel ixgbe_disable_rx_drop(struct adapter *adapter) 5182758cc3dcSJack F Vogel { 5183758cc3dcSJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 5184758cc3dcSJack F Vogel 5185758cc3dcSJack F Vogel for (int i = 0; i < adapter->num_queues; i++) { 518648056c88SJack F Vogel struct rx_ring *rxr = &adapter->rx_rings[i]; 518748056c88SJack F Vogel u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); 5188758cc3dcSJack F Vogel srrctl &= ~IXGBE_SRRCTL_DROP_EN; 518948056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); 5190758cc3dcSJack F Vogel } 519148056c88SJack F Vogel #ifdef PCI_IOV 519248056c88SJack F Vogel /* disable drop for each vf */ 519348056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 519448056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_QDE, 519548056c88SJack F Vogel (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT))); 519648056c88SJack F Vogel } 519748056c88SJack F Vogel #endif 5198758cc3dcSJack F Vogel } 5199758cc3dcSJack F Vogel 5200758cc3dcSJack F Vogel static void 5201758cc3dcSJack F Vogel ixgbe_rearm_queues(struct adapter *adapter, u64 queues) 5202758cc3dcSJack F Vogel { 5203758cc3dcSJack F Vogel u32 mask; 5204758cc3dcSJack F Vogel 5205758cc3dcSJack F Vogel switch (adapter->hw.mac.type) { 5206758cc3dcSJack F Vogel case ixgbe_mac_82598EB: 5207758cc3dcSJack F Vogel mask = (IXGBE_EIMS_RTX_QUEUE & queues); 5208758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); 5209758cc3dcSJack F Vogel break; 5210758cc3dcSJack F Vogel case ixgbe_mac_82599EB: 5211758cc3dcSJack F Vogel case ixgbe_mac_X540: 5212758cc3dcSJack F Vogel case ixgbe_mac_X550: 52136f37f232SEric Joyner case ixgbe_mac_X550EM_x: 5214758cc3dcSJack F Vogel mask = (queues & 0xFFFFFFFF); 5215758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); 5216758cc3dcSJack F Vogel mask = (queues >> 32); 5217758cc3dcSJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); 5218758cc3dcSJack F Vogel break; 5219758cc3dcSJack F Vogel default: 5220758cc3dcSJack F Vogel break; 5221758cc3dcSJack F Vogel } 5222758cc3dcSJack F Vogel } 5223758cc3dcSJack F Vogel 522448056c88SJack F Vogel #ifdef PCI_IOV 522548056c88SJack F Vogel 522648056c88SJack F Vogel /* 522748056c88SJack F Vogel ** Support functions for SRIOV/VF management 522848056c88SJack F Vogel */ 522948056c88SJack F Vogel 523048056c88SJack F Vogel static void 523148056c88SJack F Vogel ixgbe_ping_all_vfs(struct adapter *adapter) 523248056c88SJack F Vogel { 523348056c88SJack F Vogel struct ixgbe_vf *vf; 523448056c88SJack F Vogel 523548056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 523648056c88SJack F Vogel vf = &adapter->vfs[i]; 523748056c88SJack F Vogel if (vf->flags & IXGBE_VF_ACTIVE) 523848056c88SJack F Vogel ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); 523948056c88SJack F Vogel } 524048056c88SJack F Vogel } 524148056c88SJack F Vogel 524248056c88SJack F Vogel 524348056c88SJack F Vogel static void 524448056c88SJack F Vogel ixgbe_vf_set_default_vlan(struct adapter *adapter, struct ixgbe_vf *vf, 524548056c88SJack F Vogel uint16_t tag) 524648056c88SJack F Vogel { 524748056c88SJack F Vogel struct ixgbe_hw *hw; 524848056c88SJack F Vogel uint32_t vmolr, vmvir; 524948056c88SJack F Vogel 525048056c88SJack F Vogel hw = &adapter->hw; 525148056c88SJack F Vogel 525248056c88SJack F Vogel vf->vlan_tag = tag; 525348056c88SJack F Vogel 525448056c88SJack F Vogel vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool)); 525548056c88SJack F Vogel 525648056c88SJack F Vogel /* Do not receive packets that pass inexact filters. */ 525748056c88SJack F Vogel vmolr &= ~(IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_ROPE); 525848056c88SJack F Vogel 525948056c88SJack F Vogel /* Disable Multicast Promicuous Mode. */ 526048056c88SJack F Vogel vmolr &= ~IXGBE_VMOLR_MPE; 526148056c88SJack F Vogel 526248056c88SJack F Vogel /* Accept broadcasts. */ 526348056c88SJack F Vogel vmolr |= IXGBE_VMOLR_BAM; 526448056c88SJack F Vogel 526548056c88SJack F Vogel if (tag == 0) { 526648056c88SJack F Vogel /* Accept non-vlan tagged traffic. */ 526748056c88SJack F Vogel //vmolr |= IXGBE_VMOLR_AUPE; 526848056c88SJack F Vogel 526948056c88SJack F Vogel /* Allow VM to tag outgoing traffic; no default tag. */ 527048056c88SJack F Vogel vmvir = 0; 527148056c88SJack F Vogel } else { 527248056c88SJack F Vogel /* Require vlan-tagged traffic. */ 527348056c88SJack F Vogel vmolr &= ~IXGBE_VMOLR_AUPE; 527448056c88SJack F Vogel 527548056c88SJack F Vogel /* Tag all traffic with provided vlan tag. */ 527648056c88SJack F Vogel vmvir = (tag | IXGBE_VMVIR_VLANA_DEFAULT); 527748056c88SJack F Vogel } 527848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr); 527948056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir); 528048056c88SJack F Vogel } 528148056c88SJack F Vogel 528248056c88SJack F Vogel 528348056c88SJack F Vogel static boolean_t 528448056c88SJack F Vogel ixgbe_vf_frame_size_compatible(struct adapter *adapter, struct ixgbe_vf *vf) 528548056c88SJack F Vogel { 528648056c88SJack F Vogel 528748056c88SJack F Vogel /* 528848056c88SJack F Vogel * Frame size compatibility between PF and VF is only a problem on 528948056c88SJack F Vogel * 82599-based cards. X540 and later support any combination of jumbo 529048056c88SJack F Vogel * frames on PFs and VFs. 529148056c88SJack F Vogel */ 529248056c88SJack F Vogel if (adapter->hw.mac.type != ixgbe_mac_82599EB) 529348056c88SJack F Vogel return (TRUE); 529448056c88SJack F Vogel 529548056c88SJack F Vogel switch (vf->api_ver) { 529648056c88SJack F Vogel case IXGBE_API_VER_1_0: 529748056c88SJack F Vogel case IXGBE_API_VER_UNKNOWN: 529848056c88SJack F Vogel /* 529948056c88SJack F Vogel * On legacy (1.0 and older) VF versions, we don't support jumbo 530048056c88SJack F Vogel * frames on either the PF or the VF. 530148056c88SJack F Vogel */ 530248056c88SJack F Vogel if (adapter->max_frame_size > ETHER_MAX_LEN || 530348056c88SJack F Vogel vf->max_frame_size > ETHER_MAX_LEN) 530448056c88SJack F Vogel return (FALSE); 530548056c88SJack F Vogel 530648056c88SJack F Vogel return (TRUE); 530748056c88SJack F Vogel 530848056c88SJack F Vogel break; 530948056c88SJack F Vogel case IXGBE_API_VER_1_1: 531048056c88SJack F Vogel default: 531148056c88SJack F Vogel /* 531248056c88SJack F Vogel * 1.1 or later VF versions always work if they aren't using 531348056c88SJack F Vogel * jumbo frames. 531448056c88SJack F Vogel */ 531548056c88SJack F Vogel if (vf->max_frame_size <= ETHER_MAX_LEN) 531648056c88SJack F Vogel return (TRUE); 531748056c88SJack F Vogel 531848056c88SJack F Vogel /* 531948056c88SJack F Vogel * Jumbo frames only work with VFs if the PF is also using jumbo 532048056c88SJack F Vogel * frames. 532148056c88SJack F Vogel */ 532248056c88SJack F Vogel if (adapter->max_frame_size <= ETHER_MAX_LEN) 532348056c88SJack F Vogel return (TRUE); 532448056c88SJack F Vogel 532548056c88SJack F Vogel return (FALSE); 532648056c88SJack F Vogel 532748056c88SJack F Vogel } 532848056c88SJack F Vogel } 532948056c88SJack F Vogel 533048056c88SJack F Vogel 533148056c88SJack F Vogel static void 533248056c88SJack F Vogel ixgbe_process_vf_reset(struct adapter *adapter, struct ixgbe_vf *vf) 533348056c88SJack F Vogel { 533448056c88SJack F Vogel ixgbe_vf_set_default_vlan(adapter, vf, vf->default_vlan); 533548056c88SJack F Vogel 533648056c88SJack F Vogel // XXX clear multicast addresses 533748056c88SJack F Vogel 533848056c88SJack F Vogel ixgbe_clear_rar(&adapter->hw, vf->rar_index); 533948056c88SJack F Vogel 534048056c88SJack F Vogel vf->api_ver = IXGBE_API_VER_UNKNOWN; 534148056c88SJack F Vogel } 534248056c88SJack F Vogel 534348056c88SJack F Vogel 534448056c88SJack F Vogel static void 534548056c88SJack F Vogel ixgbe_vf_enable_transmit(struct adapter *adapter, struct ixgbe_vf *vf) 534648056c88SJack F Vogel { 534748056c88SJack F Vogel struct ixgbe_hw *hw; 534848056c88SJack F Vogel uint32_t vf_index, vfte; 534948056c88SJack F Vogel 535048056c88SJack F Vogel hw = &adapter->hw; 535148056c88SJack F Vogel 535248056c88SJack F Vogel vf_index = IXGBE_VF_INDEX(vf->pool); 535348056c88SJack F Vogel vfte = IXGBE_READ_REG(hw, IXGBE_VFTE(vf_index)); 535448056c88SJack F Vogel vfte |= IXGBE_VF_BIT(vf->pool); 535548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_index), vfte); 535648056c88SJack F Vogel } 535748056c88SJack F Vogel 535848056c88SJack F Vogel 535948056c88SJack F Vogel static void 536048056c88SJack F Vogel ixgbe_vf_enable_receive(struct adapter *adapter, struct ixgbe_vf *vf) 536148056c88SJack F Vogel { 536248056c88SJack F Vogel struct ixgbe_hw *hw; 536348056c88SJack F Vogel uint32_t vf_index, vfre; 536448056c88SJack F Vogel 536548056c88SJack F Vogel hw = &adapter->hw; 536648056c88SJack F Vogel 536748056c88SJack F Vogel vf_index = IXGBE_VF_INDEX(vf->pool); 536848056c88SJack F Vogel vfre = IXGBE_READ_REG(hw, IXGBE_VFRE(vf_index)); 536948056c88SJack F Vogel if (ixgbe_vf_frame_size_compatible(adapter, vf)) 537048056c88SJack F Vogel vfre |= IXGBE_VF_BIT(vf->pool); 537148056c88SJack F Vogel else 537248056c88SJack F Vogel vfre &= ~IXGBE_VF_BIT(vf->pool); 537348056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_index), vfre); 537448056c88SJack F Vogel } 537548056c88SJack F Vogel 537648056c88SJack F Vogel 537748056c88SJack F Vogel static void 537848056c88SJack F Vogel ixgbe_vf_reset_msg(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 537948056c88SJack F Vogel { 538048056c88SJack F Vogel struct ixgbe_hw *hw; 538148056c88SJack F Vogel uint32_t ack; 538248056c88SJack F Vogel uint32_t resp[IXGBE_VF_PERMADDR_MSG_LEN]; 538348056c88SJack F Vogel 538448056c88SJack F Vogel hw = &adapter->hw; 538548056c88SJack F Vogel 538648056c88SJack F Vogel ixgbe_process_vf_reset(adapter, vf); 538748056c88SJack F Vogel 538848056c88SJack F Vogel if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { 538948056c88SJack F Vogel ixgbe_set_rar(&adapter->hw, vf->rar_index, 539048056c88SJack F Vogel vf->ether_addr, vf->pool, TRUE); 539148056c88SJack F Vogel ack = IXGBE_VT_MSGTYPE_ACK; 539248056c88SJack F Vogel } else 539348056c88SJack F Vogel ack = IXGBE_VT_MSGTYPE_NACK; 539448056c88SJack F Vogel 539548056c88SJack F Vogel ixgbe_vf_enable_transmit(adapter, vf); 539648056c88SJack F Vogel ixgbe_vf_enable_receive(adapter, vf); 539748056c88SJack F Vogel 539848056c88SJack F Vogel vf->flags |= IXGBE_VF_CTS; 539948056c88SJack F Vogel 540048056c88SJack F Vogel resp[0] = IXGBE_VF_RESET | ack | IXGBE_VT_MSGTYPE_CTS; 540148056c88SJack F Vogel bcopy(vf->ether_addr, &resp[1], ETHER_ADDR_LEN); 540248056c88SJack F Vogel resp[3] = hw->mac.mc_filter_type; 540348056c88SJack F Vogel ixgbe_write_mbx(hw, resp, IXGBE_VF_PERMADDR_MSG_LEN, vf->pool); 540448056c88SJack F Vogel } 540548056c88SJack F Vogel 540648056c88SJack F Vogel 540748056c88SJack F Vogel static void 540848056c88SJack F Vogel ixgbe_vf_set_mac(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 540948056c88SJack F Vogel { 541048056c88SJack F Vogel uint8_t *mac; 541148056c88SJack F Vogel 541248056c88SJack F Vogel mac = (uint8_t*)&msg[1]; 541348056c88SJack F Vogel 541448056c88SJack F Vogel /* Check that the VF has permission to change the MAC address. */ 541548056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_CAP_MAC) && ixgbe_vf_mac_changed(vf, mac)) { 541648056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 541748056c88SJack F Vogel return; 541848056c88SJack F Vogel } 541948056c88SJack F Vogel 542048056c88SJack F Vogel if (ixgbe_validate_mac_addr(mac) != 0) { 542148056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 542248056c88SJack F Vogel return; 542348056c88SJack F Vogel } 542448056c88SJack F Vogel 542548056c88SJack F Vogel bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); 542648056c88SJack F Vogel 542748056c88SJack F Vogel ixgbe_set_rar(&adapter->hw, vf->rar_index, vf->ether_addr, 542848056c88SJack F Vogel vf->pool, TRUE); 542948056c88SJack F Vogel 543048056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 543148056c88SJack F Vogel } 543248056c88SJack F Vogel 543348056c88SJack F Vogel 543448056c88SJack F Vogel /* 543548056c88SJack F Vogel ** VF multicast addresses are set by using the appropriate bit in 543648056c88SJack F Vogel ** 1 of 128 32 bit addresses (4096 possible). 543748056c88SJack F Vogel */ 543848056c88SJack F Vogel static void 543948056c88SJack F Vogel ixgbe_vf_set_mc_addr(struct adapter *adapter, struct ixgbe_vf *vf, u32 *msg) 544048056c88SJack F Vogel { 544148056c88SJack F Vogel u16 *list = (u16*)&msg[1]; 544248056c88SJack F Vogel int entries; 544348056c88SJack F Vogel u32 vmolr, vec_bit, vec_reg, mta_reg; 544448056c88SJack F Vogel 544548056c88SJack F Vogel entries = (msg[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT; 544648056c88SJack F Vogel entries = min(entries, IXGBE_MAX_VF_MC); 544748056c88SJack F Vogel 544848056c88SJack F Vogel vmolr = IXGBE_READ_REG(&adapter->hw, IXGBE_VMOLR(vf->pool)); 544948056c88SJack F Vogel 545048056c88SJack F Vogel vf->num_mc_hashes = entries; 545148056c88SJack F Vogel 545248056c88SJack F Vogel /* Set the appropriate MTA bit */ 545348056c88SJack F Vogel for (int i = 0; i < entries; i++) { 545448056c88SJack F Vogel vf->mc_hash[i] = list[i]; 545548056c88SJack F Vogel vec_reg = (vf->mc_hash[i] >> 5) & 0x7F; 545648056c88SJack F Vogel vec_bit = vf->mc_hash[i] & 0x1F; 545748056c88SJack F Vogel mta_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_MTA(vec_reg)); 545848056c88SJack F Vogel mta_reg |= (1 << vec_bit); 545948056c88SJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_MTA(vec_reg), mta_reg); 546048056c88SJack F Vogel } 546148056c88SJack F Vogel 546248056c88SJack F Vogel vmolr |= IXGBE_VMOLR_ROMPE; 546348056c88SJack F Vogel IXGBE_WRITE_REG(&adapter->hw, IXGBE_VMOLR(vf->pool), vmolr); 546448056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 546548056c88SJack F Vogel return; 546648056c88SJack F Vogel } 546748056c88SJack F Vogel 546848056c88SJack F Vogel 546948056c88SJack F Vogel static void 547048056c88SJack F Vogel ixgbe_vf_set_vlan(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 547148056c88SJack F Vogel { 547248056c88SJack F Vogel struct ixgbe_hw *hw; 547348056c88SJack F Vogel int enable; 547448056c88SJack F Vogel uint16_t tag; 547548056c88SJack F Vogel 547648056c88SJack F Vogel hw = &adapter->hw; 547748056c88SJack F Vogel enable = IXGBE_VT_MSGINFO(msg[0]); 547848056c88SJack F Vogel tag = msg[1] & IXGBE_VLVF_VLANID_MASK; 547948056c88SJack F Vogel 548048056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_CAP_VLAN)) { 548148056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 548248056c88SJack F Vogel return; 548348056c88SJack F Vogel } 548448056c88SJack F Vogel 548548056c88SJack F Vogel /* It is illegal to enable vlan tag 0. */ 548648056c88SJack F Vogel if (tag == 0 && enable != 0){ 548748056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 548848056c88SJack F Vogel return; 548948056c88SJack F Vogel } 549048056c88SJack F Vogel 549148056c88SJack F Vogel ixgbe_set_vfta(hw, tag, vf->pool, enable); 549248056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 549348056c88SJack F Vogel } 549448056c88SJack F Vogel 549548056c88SJack F Vogel 549648056c88SJack F Vogel static void 549748056c88SJack F Vogel ixgbe_vf_set_lpe(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) 549848056c88SJack F Vogel { 549948056c88SJack F Vogel struct ixgbe_hw *hw; 550048056c88SJack F Vogel uint32_t vf_max_size, pf_max_size, mhadd; 550148056c88SJack F Vogel 550248056c88SJack F Vogel hw = &adapter->hw; 550348056c88SJack F Vogel vf_max_size = msg[1]; 550448056c88SJack F Vogel 550548056c88SJack F Vogel if (vf_max_size < ETHER_CRC_LEN) { 550648056c88SJack F Vogel /* We intentionally ACK invalid LPE requests. */ 550748056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 550848056c88SJack F Vogel return; 550948056c88SJack F Vogel } 551048056c88SJack F Vogel 551148056c88SJack F Vogel vf_max_size -= ETHER_CRC_LEN; 551248056c88SJack F Vogel 551348056c88SJack F Vogel if (vf_max_size > IXGBE_MAX_FRAME_SIZE) { 551448056c88SJack F Vogel /* We intentionally ACK invalid LPE requests. */ 551548056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 551648056c88SJack F Vogel return; 551748056c88SJack F Vogel } 551848056c88SJack F Vogel 551948056c88SJack F Vogel vf->max_frame_size = vf_max_size; 552048056c88SJack F Vogel ixgbe_update_max_frame(adapter, vf->max_frame_size); 552148056c88SJack F Vogel 552248056c88SJack F Vogel /* 552348056c88SJack F Vogel * We might have to disable reception to this VF if the frame size is 552448056c88SJack F Vogel * not compatible with the config on the PF. 552548056c88SJack F Vogel */ 552648056c88SJack F Vogel ixgbe_vf_enable_receive(adapter, vf); 552748056c88SJack F Vogel 552848056c88SJack F Vogel mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); 552948056c88SJack F Vogel pf_max_size = (mhadd & IXGBE_MHADD_MFS_MASK) >> IXGBE_MHADD_MFS_SHIFT; 553048056c88SJack F Vogel 553148056c88SJack F Vogel if (pf_max_size < adapter->max_frame_size) { 553248056c88SJack F Vogel mhadd &= ~IXGBE_MHADD_MFS_MASK; 553348056c88SJack F Vogel mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; 553448056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); 553548056c88SJack F Vogel } 553648056c88SJack F Vogel 553748056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 553848056c88SJack F Vogel } 553948056c88SJack F Vogel 554048056c88SJack F Vogel 554148056c88SJack F Vogel static void 554248056c88SJack F Vogel ixgbe_vf_set_macvlan(struct adapter *adapter, struct ixgbe_vf *vf, 554348056c88SJack F Vogel uint32_t *msg) 554448056c88SJack F Vogel { 554548056c88SJack F Vogel //XXX implement this 554648056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 554748056c88SJack F Vogel } 554848056c88SJack F Vogel 554948056c88SJack F Vogel 555048056c88SJack F Vogel static void 555148056c88SJack F Vogel ixgbe_vf_api_negotiate(struct adapter *adapter, struct ixgbe_vf *vf, 555248056c88SJack F Vogel uint32_t *msg) 555348056c88SJack F Vogel { 555448056c88SJack F Vogel 5555c8ed84dbSPatrick Kelsey switch (msg[1]) { 555648056c88SJack F Vogel case IXGBE_API_VER_1_0: 555748056c88SJack F Vogel case IXGBE_API_VER_1_1: 5558c8ed84dbSPatrick Kelsey vf->api_ver = msg[1]; 555948056c88SJack F Vogel ixgbe_send_vf_ack(adapter, vf, msg[0]); 556048056c88SJack F Vogel break; 556148056c88SJack F Vogel default: 556248056c88SJack F Vogel vf->api_ver = IXGBE_API_VER_UNKNOWN; 556348056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 556448056c88SJack F Vogel break; 556548056c88SJack F Vogel } 556648056c88SJack F Vogel } 556748056c88SJack F Vogel 556848056c88SJack F Vogel 556948056c88SJack F Vogel static void 557048056c88SJack F Vogel ixgbe_vf_get_queues(struct adapter *adapter, struct ixgbe_vf *vf, 557148056c88SJack F Vogel uint32_t *msg) 557248056c88SJack F Vogel { 557348056c88SJack F Vogel struct ixgbe_hw *hw; 557448056c88SJack F Vogel uint32_t resp[IXGBE_VF_GET_QUEUES_RESP_LEN]; 557548056c88SJack F Vogel int num_queues; 557648056c88SJack F Vogel 557748056c88SJack F Vogel hw = &adapter->hw; 557848056c88SJack F Vogel 557948056c88SJack F Vogel /* GET_QUEUES is not supported on pre-1.1 APIs. */ 558048056c88SJack F Vogel switch (msg[0]) { 558148056c88SJack F Vogel case IXGBE_API_VER_1_0: 558248056c88SJack F Vogel case IXGBE_API_VER_UNKNOWN: 558348056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 558448056c88SJack F Vogel return; 558548056c88SJack F Vogel } 558648056c88SJack F Vogel 558748056c88SJack F Vogel resp[0] = IXGBE_VF_GET_QUEUES | IXGBE_VT_MSGTYPE_ACK | 558848056c88SJack F Vogel IXGBE_VT_MSGTYPE_CTS; 558948056c88SJack F Vogel 559048056c88SJack F Vogel num_queues = ixgbe_vf_queues(ixgbe_get_iov_mode(adapter)); 559148056c88SJack F Vogel resp[IXGBE_VF_TX_QUEUES] = num_queues; 559248056c88SJack F Vogel resp[IXGBE_VF_RX_QUEUES] = num_queues; 559348056c88SJack F Vogel resp[IXGBE_VF_TRANS_VLAN] = (vf->default_vlan != 0); 559448056c88SJack F Vogel resp[IXGBE_VF_DEF_QUEUE] = 0; 559548056c88SJack F Vogel 559648056c88SJack F Vogel ixgbe_write_mbx(hw, resp, IXGBE_VF_GET_QUEUES_RESP_LEN, vf->pool); 559748056c88SJack F Vogel } 559848056c88SJack F Vogel 559948056c88SJack F Vogel 560048056c88SJack F Vogel static void 560148056c88SJack F Vogel ixgbe_process_vf_msg(struct adapter *adapter, struct ixgbe_vf *vf) 560248056c88SJack F Vogel { 560348056c88SJack F Vogel struct ixgbe_hw *hw; 560448056c88SJack F Vogel uint32_t msg[IXGBE_VFMAILBOX_SIZE]; 560548056c88SJack F Vogel int error; 560648056c88SJack F Vogel 560748056c88SJack F Vogel hw = &adapter->hw; 560848056c88SJack F Vogel 560948056c88SJack F Vogel error = ixgbe_read_mbx(hw, msg, IXGBE_VFMAILBOX_SIZE, vf->pool); 561048056c88SJack F Vogel 561148056c88SJack F Vogel if (error != 0) 561248056c88SJack F Vogel return; 561348056c88SJack F Vogel 561448056c88SJack F Vogel CTR3(KTR_MALLOC, "%s: received msg %x from %d", 561548056c88SJack F Vogel adapter->ifp->if_xname, msg[0], vf->pool); 561648056c88SJack F Vogel if (msg[0] == IXGBE_VF_RESET) { 561748056c88SJack F Vogel ixgbe_vf_reset_msg(adapter, vf, msg); 561848056c88SJack F Vogel return; 561948056c88SJack F Vogel } 562048056c88SJack F Vogel 562148056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_CTS)) { 562248056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 562348056c88SJack F Vogel return; 562448056c88SJack F Vogel } 562548056c88SJack F Vogel 562648056c88SJack F Vogel switch (msg[0] & IXGBE_VT_MSG_MASK) { 562748056c88SJack F Vogel case IXGBE_VF_SET_MAC_ADDR: 562848056c88SJack F Vogel ixgbe_vf_set_mac(adapter, vf, msg); 562948056c88SJack F Vogel break; 563048056c88SJack F Vogel case IXGBE_VF_SET_MULTICAST: 563148056c88SJack F Vogel ixgbe_vf_set_mc_addr(adapter, vf, msg); 563248056c88SJack F Vogel break; 563348056c88SJack F Vogel case IXGBE_VF_SET_VLAN: 563448056c88SJack F Vogel ixgbe_vf_set_vlan(adapter, vf, msg); 563548056c88SJack F Vogel break; 563648056c88SJack F Vogel case IXGBE_VF_SET_LPE: 563748056c88SJack F Vogel ixgbe_vf_set_lpe(adapter, vf, msg); 563848056c88SJack F Vogel break; 563948056c88SJack F Vogel case IXGBE_VF_SET_MACVLAN: 564048056c88SJack F Vogel ixgbe_vf_set_macvlan(adapter, vf, msg); 564148056c88SJack F Vogel break; 564248056c88SJack F Vogel case IXGBE_VF_API_NEGOTIATE: 564348056c88SJack F Vogel ixgbe_vf_api_negotiate(adapter, vf, msg); 564448056c88SJack F Vogel break; 564548056c88SJack F Vogel case IXGBE_VF_GET_QUEUES: 564648056c88SJack F Vogel ixgbe_vf_get_queues(adapter, vf, msg); 564748056c88SJack F Vogel break; 564848056c88SJack F Vogel default: 564948056c88SJack F Vogel ixgbe_send_vf_nack(adapter, vf, msg[0]); 565048056c88SJack F Vogel } 565148056c88SJack F Vogel } 565248056c88SJack F Vogel 565348056c88SJack F Vogel 565448056c88SJack F Vogel /* 565548056c88SJack F Vogel * Tasklet for handling VF -> PF mailbox messages. 565648056c88SJack F Vogel */ 565748056c88SJack F Vogel static void 565848056c88SJack F Vogel ixgbe_handle_mbx(void *context, int pending) 565948056c88SJack F Vogel { 566048056c88SJack F Vogel struct adapter *adapter; 566148056c88SJack F Vogel struct ixgbe_hw *hw; 566248056c88SJack F Vogel struct ixgbe_vf *vf; 566348056c88SJack F Vogel int i; 566448056c88SJack F Vogel 566548056c88SJack F Vogel adapter = context; 566648056c88SJack F Vogel hw = &adapter->hw; 566748056c88SJack F Vogel 566848056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 566948056c88SJack F Vogel for (i = 0; i < adapter->num_vfs; i++) { 567048056c88SJack F Vogel vf = &adapter->vfs[i]; 567148056c88SJack F Vogel 567248056c88SJack F Vogel if (vf->flags & IXGBE_VF_ACTIVE) { 567348056c88SJack F Vogel if (ixgbe_check_for_rst(hw, vf->pool) == 0) 567448056c88SJack F Vogel ixgbe_process_vf_reset(adapter, vf); 567548056c88SJack F Vogel 567648056c88SJack F Vogel if (ixgbe_check_for_msg(hw, vf->pool) == 0) 567748056c88SJack F Vogel ixgbe_process_vf_msg(adapter, vf); 567848056c88SJack F Vogel 567948056c88SJack F Vogel if (ixgbe_check_for_ack(hw, vf->pool) == 0) 568048056c88SJack F Vogel ixgbe_process_vf_ack(adapter, vf); 568148056c88SJack F Vogel } 568248056c88SJack F Vogel } 568348056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 568448056c88SJack F Vogel } 568548056c88SJack F Vogel 568648056c88SJack F Vogel 568748056c88SJack F Vogel static int 568848056c88SJack F Vogel ixgbe_init_iov(device_t dev, u16 num_vfs, const nvlist_t *config) 568948056c88SJack F Vogel { 569048056c88SJack F Vogel struct adapter *adapter; 569148056c88SJack F Vogel enum ixgbe_iov_mode mode; 569248056c88SJack F Vogel 569348056c88SJack F Vogel adapter = device_get_softc(dev); 569448056c88SJack F Vogel adapter->num_vfs = num_vfs; 569548056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 569648056c88SJack F Vogel 569748056c88SJack F Vogel if (num_vfs > ixgbe_max_vfs(mode)) { 569848056c88SJack F Vogel adapter->num_vfs = 0; 569948056c88SJack F Vogel return (ENOSPC); 570048056c88SJack F Vogel } 570148056c88SJack F Vogel 570248056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 570348056c88SJack F Vogel 570448056c88SJack F Vogel adapter->vfs = malloc(sizeof(*adapter->vfs) * num_vfs, M_IXGBE, 570548056c88SJack F Vogel M_NOWAIT | M_ZERO); 570648056c88SJack F Vogel 570748056c88SJack F Vogel if (adapter->vfs == NULL) { 570848056c88SJack F Vogel adapter->num_vfs = 0; 570948056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 571048056c88SJack F Vogel return (ENOMEM); 571148056c88SJack F Vogel } 571248056c88SJack F Vogel 571348056c88SJack F Vogel ixgbe_init_locked(adapter); 571448056c88SJack F Vogel 571548056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 571648056c88SJack F Vogel 571748056c88SJack F Vogel return (0); 571848056c88SJack F Vogel } 571948056c88SJack F Vogel 572048056c88SJack F Vogel 572148056c88SJack F Vogel static void 572248056c88SJack F Vogel ixgbe_uninit_iov(device_t dev) 572348056c88SJack F Vogel { 572448056c88SJack F Vogel struct ixgbe_hw *hw; 572548056c88SJack F Vogel struct adapter *adapter; 572648056c88SJack F Vogel uint32_t pf_reg, vf_reg; 572748056c88SJack F Vogel 572848056c88SJack F Vogel adapter = device_get_softc(dev); 572948056c88SJack F Vogel hw = &adapter->hw; 573048056c88SJack F Vogel 573148056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 573248056c88SJack F Vogel 573348056c88SJack F Vogel /* Enable rx/tx for the PF and disable it for all VFs. */ 573448056c88SJack F Vogel pf_reg = IXGBE_VF_INDEX(adapter->pool); 573548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(pf_reg), 573648056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 573748056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(pf_reg), 573848056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 573948056c88SJack F Vogel 574048056c88SJack F Vogel if (pf_reg == 0) 574148056c88SJack F Vogel vf_reg = 1; 574248056c88SJack F Vogel else 574348056c88SJack F Vogel vf_reg = 0; 574448056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 0); 574548056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 0); 574648056c88SJack F Vogel 574748056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, 0); 574848056c88SJack F Vogel 574948056c88SJack F Vogel free(adapter->vfs, M_IXGBE); 575048056c88SJack F Vogel adapter->vfs = NULL; 575148056c88SJack F Vogel adapter->num_vfs = 0; 575248056c88SJack F Vogel 575348056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 575448056c88SJack F Vogel } 575548056c88SJack F Vogel 575648056c88SJack F Vogel 575748056c88SJack F Vogel static void 575848056c88SJack F Vogel ixgbe_initialize_iov(struct adapter *adapter) 575948056c88SJack F Vogel { 576048056c88SJack F Vogel struct ixgbe_hw *hw = &adapter->hw; 576148056c88SJack F Vogel uint32_t mrqc, mtqc, vt_ctl, vf_reg, gcr_ext, gpie; 576248056c88SJack F Vogel enum ixgbe_iov_mode mode; 576348056c88SJack F Vogel int i; 576448056c88SJack F Vogel 576548056c88SJack F Vogel mode = ixgbe_get_iov_mode(adapter); 576648056c88SJack F Vogel if (mode == IXGBE_NO_VM) 576748056c88SJack F Vogel return; 576848056c88SJack F Vogel 576948056c88SJack F Vogel IXGBE_CORE_LOCK_ASSERT(adapter); 577048056c88SJack F Vogel 577148056c88SJack F Vogel mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC); 577248056c88SJack F Vogel mrqc &= ~IXGBE_MRQC_MRQE_MASK; 577348056c88SJack F Vogel 577448056c88SJack F Vogel switch (mode) { 577548056c88SJack F Vogel case IXGBE_64_VM: 577648056c88SJack F Vogel mrqc |= IXGBE_MRQC_VMDQRSS64EN; 577748056c88SJack F Vogel break; 577848056c88SJack F Vogel case IXGBE_32_VM: 577948056c88SJack F Vogel mrqc |= IXGBE_MRQC_VMDQRSS32EN; 578048056c88SJack F Vogel break; 578148056c88SJack F Vogel default: 578248056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 578348056c88SJack F Vogel } 578448056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 578548056c88SJack F Vogel 578648056c88SJack F Vogel mtqc = IXGBE_MTQC_VT_ENA; 578748056c88SJack F Vogel switch (mode) { 578848056c88SJack F Vogel case IXGBE_64_VM: 578948056c88SJack F Vogel mtqc |= IXGBE_MTQC_64VF; 579048056c88SJack F Vogel break; 579148056c88SJack F Vogel case IXGBE_32_VM: 579248056c88SJack F Vogel mtqc |= IXGBE_MTQC_32VF; 579348056c88SJack F Vogel break; 579448056c88SJack F Vogel default: 579548056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 579648056c88SJack F Vogel } 579748056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MTQC, mtqc); 579848056c88SJack F Vogel 579948056c88SJack F Vogel 580048056c88SJack F Vogel gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT); 580148056c88SJack F Vogel gcr_ext |= IXGBE_GCR_EXT_MSIX_EN; 580248056c88SJack F Vogel gcr_ext &= ~IXGBE_GCR_EXT_VT_MODE_MASK; 580348056c88SJack F Vogel switch (mode) { 580448056c88SJack F Vogel case IXGBE_64_VM: 580548056c88SJack F Vogel gcr_ext |= IXGBE_GCR_EXT_VT_MODE_64; 580648056c88SJack F Vogel break; 580748056c88SJack F Vogel case IXGBE_32_VM: 580848056c88SJack F Vogel gcr_ext |= IXGBE_GCR_EXT_VT_MODE_32; 580948056c88SJack F Vogel break; 581048056c88SJack F Vogel default: 581148056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 581248056c88SJack F Vogel } 581348056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext); 581448056c88SJack F Vogel 581548056c88SJack F Vogel 581648056c88SJack F Vogel gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); 581748056c88SJack F Vogel gcr_ext &= ~IXGBE_GPIE_VTMODE_MASK; 581848056c88SJack F Vogel switch (mode) { 581948056c88SJack F Vogel case IXGBE_64_VM: 582048056c88SJack F Vogel gpie |= IXGBE_GPIE_VTMODE_64; 582148056c88SJack F Vogel break; 582248056c88SJack F Vogel case IXGBE_32_VM: 582348056c88SJack F Vogel gpie |= IXGBE_GPIE_VTMODE_32; 582448056c88SJack F Vogel break; 582548056c88SJack F Vogel default: 582648056c88SJack F Vogel panic("Unexpected SR-IOV mode %d", mode); 582748056c88SJack F Vogel } 582848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 582948056c88SJack F Vogel 583048056c88SJack F Vogel /* Enable rx/tx for the PF. */ 583148056c88SJack F Vogel vf_reg = IXGBE_VF_INDEX(adapter->pool); 583248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 583348056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 583448056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 583548056c88SJack F Vogel IXGBE_VF_BIT(adapter->pool)); 583648056c88SJack F Vogel 583748056c88SJack F Vogel /* Allow VM-to-VM communication. */ 583848056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN); 583948056c88SJack F Vogel 584048056c88SJack F Vogel vt_ctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; 584148056c88SJack F Vogel vt_ctl |= (adapter->pool << IXGBE_VT_CTL_POOL_SHIFT); 584248056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vt_ctl); 584348056c88SJack F Vogel 584448056c88SJack F Vogel for (i = 0; i < adapter->num_vfs; i++) 584548056c88SJack F Vogel ixgbe_init_vf(adapter, &adapter->vfs[i]); 584648056c88SJack F Vogel } 584748056c88SJack F Vogel 584848056c88SJack F Vogel 584948056c88SJack F Vogel /* 585048056c88SJack F Vogel ** Check the max frame setting of all active VF's 585148056c88SJack F Vogel */ 585248056c88SJack F Vogel static void 585348056c88SJack F Vogel ixgbe_recalculate_max_frame(struct adapter *adapter) 585448056c88SJack F Vogel { 585548056c88SJack F Vogel struct ixgbe_vf *vf; 585648056c88SJack F Vogel 585748056c88SJack F Vogel IXGBE_CORE_LOCK_ASSERT(adapter); 585848056c88SJack F Vogel 585948056c88SJack F Vogel for (int i = 0; i < adapter->num_vfs; i++) { 586048056c88SJack F Vogel vf = &adapter->vfs[i]; 586148056c88SJack F Vogel if (vf->flags & IXGBE_VF_ACTIVE) 586248056c88SJack F Vogel ixgbe_update_max_frame(adapter, vf->max_frame_size); 586348056c88SJack F Vogel } 586448056c88SJack F Vogel } 586548056c88SJack F Vogel 586648056c88SJack F Vogel 586748056c88SJack F Vogel static void 586848056c88SJack F Vogel ixgbe_init_vf(struct adapter *adapter, struct ixgbe_vf *vf) 586948056c88SJack F Vogel { 587048056c88SJack F Vogel struct ixgbe_hw *hw; 587148056c88SJack F Vogel uint32_t vf_index, pfmbimr; 587248056c88SJack F Vogel 587348056c88SJack F Vogel IXGBE_CORE_LOCK_ASSERT(adapter); 587448056c88SJack F Vogel 587548056c88SJack F Vogel hw = &adapter->hw; 587648056c88SJack F Vogel 587748056c88SJack F Vogel if (!(vf->flags & IXGBE_VF_ACTIVE)) 587848056c88SJack F Vogel return; 587948056c88SJack F Vogel 588048056c88SJack F Vogel vf_index = IXGBE_VF_INDEX(vf->pool); 588148056c88SJack F Vogel pfmbimr = IXGBE_READ_REG(hw, IXGBE_PFMBIMR(vf_index)); 588248056c88SJack F Vogel pfmbimr |= IXGBE_VF_BIT(vf->pool); 588348056c88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr); 588448056c88SJack F Vogel 588548056c88SJack F Vogel ixgbe_vf_set_default_vlan(adapter, vf, vf->vlan_tag); 588648056c88SJack F Vogel 588748056c88SJack F Vogel // XXX multicast addresses 588848056c88SJack F Vogel 588948056c88SJack F Vogel if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { 589048056c88SJack F Vogel ixgbe_set_rar(&adapter->hw, vf->rar_index, 589148056c88SJack F Vogel vf->ether_addr, vf->pool, TRUE); 589248056c88SJack F Vogel } 589348056c88SJack F Vogel 589448056c88SJack F Vogel ixgbe_vf_enable_transmit(adapter, vf); 589548056c88SJack F Vogel ixgbe_vf_enable_receive(adapter, vf); 589648056c88SJack F Vogel 589748056c88SJack F Vogel ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); 589848056c88SJack F Vogel } 589948056c88SJack F Vogel 590048056c88SJack F Vogel static int 590148056c88SJack F Vogel ixgbe_add_vf(device_t dev, u16 vfnum, const nvlist_t *config) 590248056c88SJack F Vogel { 590348056c88SJack F Vogel struct adapter *adapter; 590448056c88SJack F Vogel struct ixgbe_vf *vf; 590548056c88SJack F Vogel const void *mac; 590648056c88SJack F Vogel 590748056c88SJack F Vogel adapter = device_get_softc(dev); 590848056c88SJack F Vogel 590948056c88SJack F Vogel KASSERT(vfnum < adapter->num_vfs, ("VF index %d is out of range %d", 591048056c88SJack F Vogel vfnum, adapter->num_vfs)); 591148056c88SJack F Vogel 591248056c88SJack F Vogel IXGBE_CORE_LOCK(adapter); 591348056c88SJack F Vogel vf = &adapter->vfs[vfnum]; 591448056c88SJack F Vogel vf->pool= vfnum; 591548056c88SJack F Vogel 591648056c88SJack F Vogel /* RAR[0] is used by the PF so use vfnum + 1 for VF RAR. */ 591748056c88SJack F Vogel vf->rar_index = vfnum + 1; 591848056c88SJack F Vogel vf->default_vlan = 0; 591948056c88SJack F Vogel vf->max_frame_size = ETHER_MAX_LEN; 592048056c88SJack F Vogel ixgbe_update_max_frame(adapter, vf->max_frame_size); 592148056c88SJack F Vogel 592248056c88SJack F Vogel if (nvlist_exists_binary(config, "mac-addr")) { 592348056c88SJack F Vogel mac = nvlist_get_binary(config, "mac-addr", NULL); 592448056c88SJack F Vogel bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); 592548056c88SJack F Vogel if (nvlist_get_bool(config, "allow-set-mac")) 592648056c88SJack F Vogel vf->flags |= IXGBE_VF_CAP_MAC; 592748056c88SJack F Vogel } else 592848056c88SJack F Vogel /* 592948056c88SJack F Vogel * If the administrator has not specified a MAC address then 593048056c88SJack F Vogel * we must allow the VF to choose one. 593148056c88SJack F Vogel */ 593248056c88SJack F Vogel vf->flags |= IXGBE_VF_CAP_MAC; 593348056c88SJack F Vogel 593448056c88SJack F Vogel vf->flags = IXGBE_VF_ACTIVE; 593548056c88SJack F Vogel 593648056c88SJack F Vogel ixgbe_init_vf(adapter, vf); 593748056c88SJack F Vogel IXGBE_CORE_UNLOCK(adapter); 593848056c88SJack F Vogel 593948056c88SJack F Vogel return (0); 594048056c88SJack F Vogel } 594148056c88SJack F Vogel #endif /* PCI_IOV */ 5942758cc3dcSJack F Vogel 5943