xref: /freebsd/sys/dev/ixgbe/if_ix.c (revision 48ddd1b9f88753c6875566fbb67bc622453e4993)
1758cc3dcSJack F Vogel /******************************************************************************
2758cc3dcSJack F Vogel 
38eb6488eSEric Joyner   Copyright (c) 2001-2017, 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 
34758cc3dcSJack F Vogel #include "opt_inet.h"
35758cc3dcSJack F Vogel #include "opt_inet6.h"
36758cc3dcSJack F Vogel #include "opt_rss.h"
37758cc3dcSJack F Vogel 
38758cc3dcSJack F Vogel #include "ixgbe.h"
39c19c7afeSEric Joyner #include "ixgbe_sriov.h"
40c19c7afeSEric Joyner #include "ifdi_if.h"
41c19c7afeSEric Joyner 
42c19c7afeSEric Joyner #include <net/netmap.h>
43c19c7afeSEric Joyner #include <dev/netmap/netmap_kern.h>
44758cc3dcSJack F Vogel 
458eb6488eSEric Joyner /************************************************************************
46758cc3dcSJack F Vogel  * Driver version
478eb6488eSEric Joyner  ************************************************************************/
4851e23514SMarius Strobl static const char ixgbe_driver_version[] = "4.0.1-k";
49a9ca1c79SSean Bruno 
508eb6488eSEric Joyner /************************************************************************
51758cc3dcSJack F Vogel  * PCI Device ID Table
52758cc3dcSJack F Vogel  *
53758cc3dcSJack F Vogel  *   Used by probe to select devices to load on
54758cc3dcSJack F Vogel  *   Last field stores an index into ixgbe_strings
55758cc3dcSJack F Vogel  *   Last entry must be all 0s
56758cc3dcSJack F Vogel  *
57758cc3dcSJack F Vogel  *   { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
588eb6488eSEric Joyner  ************************************************************************/
5951e23514SMarius Strobl static const pci_vendor_info_t ixgbe_vendor_info_array[] =
60758cc3dcSJack F Vogel {
61fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT,  "Intel(R) 82598EB AF (Dual Fiber)"),
62fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT,  "Intel(R) 82598EB AF (Fiber)"),
63fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4,  "Intel(R) 82598EB AT (CX4)"),
64fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT,  "Intel(R) 82598EB AT"),
65fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT2,  "Intel(R) 82598EB AT2"),
66fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598,  "Intel(R) 82598"),
67fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_DA_DUAL_PORT,  "Intel(R) 82598EB AF DA (Dual Fiber)"),
68fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_CX4_DUAL_PORT,  "Intel(R) 82598EB AT (Dual CX4)"),
69fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_XF_LR,  "Intel(R) 82598EB AF (Dual Fiber LR)"),
70fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM,  "Intel(R) 82598EB AF (Dual Fiber SR)"),
71fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_SFP_LOM,  "Intel(R) 82598EB LOM"),
72fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4,  "Intel(R) X520 82599 (KX4)"),
73fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4_MEZZ,  "Intel(R) X520 82599 (KX4 Mezzanine)"),
74fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP,  "Intel(R) X520 82599ES (SFI/SFP+)"),
75fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_XAUI_LOM,  "Intel(R) X520 82599 (XAUI/BX4)"),
76fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_CX4,  "Intel(R) X520 82599 (Dual CX4)"),
77fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_T3_LOM,  "Intel(R) X520-T 82599 LOM"),
789228ac3aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_LS,  "Intel(R) X520 82599 LS"),
79fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_COMBO_BACKPLANE,  "Intel(R) X520 82599 (Combined Backplane)"),
80fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BACKPLANE_FCOE,  "Intel(R) X520 82599 (Backplane w/FCoE)"),
81fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF2,  "Intel(R) X520 82599 (Dual SFP+)"),
82fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_FCOE,  "Intel(R) X520 82599 (Dual SFP+ w/FCoE)"),
83fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599EN_SFP,  "Intel(R) X520-1 82599EN (SFP+)"),
84fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF_QP,  "Intel(R) X520-4 82599 (Quad SFP+)"),
85fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_QSFP_SF_QP,  "Intel(R) X520-Q1 82599 (QSFP+)"),
86fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T,  "Intel(R) X540-AT2"),
87fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T1,  "Intel(R) X540-T1"),
88fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T,  "Intel(R) X550-T2"),
89fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T1, "Intel(R) X550-T1"),
90fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KR,  "Intel(R) X552 (KR Backplane)"),
91fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KX4,  "Intel(R) X552 (KX4 Backplane)"),
92fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_10G_T,  "Intel(R) X552/X557-AT (10GBASE-T)"),
93fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_1G_T,  "Intel(R) X552 (1000BASE-T)"),
94fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_SFP, "Intel(R) X552 (SFP+)"),
95fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_KR, "Intel(R) X553 (KR Backplane)"),
96fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_KR_L, "Intel(R) X553 L (KR Backplane)"),
97fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SFP, "Intel(R) X553 (SFP+)"),
98fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SFP_N, "Intel(R) X553 N (SFP+)"),
99fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SGMII, "Intel(R) X553 (1GbE SGMII)"),
100fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SGMII_L, "Intel(R) X553 L (1GbE SGMII)"),
101fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_10G_T, "Intel(R) X553/X557-AT (10GBASE-T)"),
102fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_1G_T, "Intel(R) X553 (1GbE)"),
103fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_1G_T_L, "Intel(R) X553 L (1GbE)"),
104fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540_BYPASS, "Intel(R) X540-T2 (Bypass)"),
105fdbcd35aSKevin Bowling   PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BYPASS, "Intel(R) X520 82599 (Bypass)"),
106758cc3dcSJack F Vogel 	/* required last entry */
107c19c7afeSEric Joyner   PVID_END
108758cc3dcSJack F Vogel };
109758cc3dcSJack F Vogel 
110b1d5caf3SKevin Bowling static void *ixgbe_register(device_t);
111b1d5caf3SKevin Bowling static int  ixgbe_if_attach_pre(if_ctx_t);
112b1d5caf3SKevin Bowling static int  ixgbe_if_attach_post(if_ctx_t);
113b1d5caf3SKevin Bowling static int  ixgbe_if_detach(if_ctx_t);
114b1d5caf3SKevin Bowling static int  ixgbe_if_shutdown(if_ctx_t);
115b1d5caf3SKevin Bowling static int  ixgbe_if_suspend(if_ctx_t);
116b1d5caf3SKevin Bowling static int  ixgbe_if_resume(if_ctx_t);
117c19c7afeSEric Joyner 
118b1d5caf3SKevin Bowling static void ixgbe_if_stop(if_ctx_t);
119b1d5caf3SKevin Bowling void ixgbe_if_enable_intr(if_ctx_t);
120b1d5caf3SKevin Bowling static void ixgbe_if_disable_intr(if_ctx_t);
121b1d5caf3SKevin Bowling static void ixgbe_link_intr_enable(if_ctx_t);
122b1d5caf3SKevin Bowling static int  ixgbe_if_rx_queue_intr_enable(if_ctx_t, uint16_t);
123b1d5caf3SKevin Bowling static void ixgbe_if_media_status(if_ctx_t, struct ifmediareq *);
124b1d5caf3SKevin Bowling static int  ixgbe_if_media_change(if_ctx_t);
125c19c7afeSEric Joyner static int  ixgbe_if_msix_intr_assign(if_ctx_t, int);
126b1d5caf3SKevin Bowling static int  ixgbe_if_mtu_set(if_ctx_t, uint32_t);
127b1d5caf3SKevin Bowling static void ixgbe_if_crcstrip_set(if_ctx_t, int, int);
128b1d5caf3SKevin Bowling static void ixgbe_if_multi_set(if_ctx_t);
129b1d5caf3SKevin Bowling static int  ixgbe_if_promisc_set(if_ctx_t, int);
130b1d5caf3SKevin Bowling static int  ixgbe_if_tx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int, int);
131b1d5caf3SKevin Bowling static int  ixgbe_if_rx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int, int);
132b1d5caf3SKevin Bowling static void ixgbe_if_queues_free(if_ctx_t);
133b1d5caf3SKevin Bowling static void ixgbe_if_timer(if_ctx_t, uint16_t);
134b1d5caf3SKevin Bowling static void ixgbe_if_update_admin_status(if_ctx_t);
135b1d5caf3SKevin Bowling static void ixgbe_if_vlan_register(if_ctx_t, u16);
136b1d5caf3SKevin Bowling static void ixgbe_if_vlan_unregister(if_ctx_t, u16);
137b1d5caf3SKevin Bowling static int  ixgbe_if_i2c_req(if_ctx_t, struct ifi2creq *);
138b1d5caf3SKevin Bowling static bool ixgbe_if_needs_restart(if_ctx_t, enum iflib_restart_event);
139b1d5caf3SKevin Bowling int ixgbe_intr(void *);
140758cc3dcSJack F Vogel 
1418eb6488eSEric Joyner /************************************************************************
142758cc3dcSJack F Vogel  * Function prototypes
1438eb6488eSEric Joyner  ************************************************************************/
144c19c7afeSEric Joyner static uint64_t ixgbe_if_get_counter(if_ctx_t, ift_counter);
145758cc3dcSJack F Vogel 
146b1d5caf3SKevin Bowling static void ixgbe_enable_queue(struct ixgbe_softc *, u32);
147b1d5caf3SKevin Bowling static void ixgbe_disable_queue(struct ixgbe_softc *, u32);
148b1d5caf3SKevin Bowling static void ixgbe_add_device_sysctls(if_ctx_t);
149b1d5caf3SKevin Bowling static int  ixgbe_allocate_pci_resources(if_ctx_t);
150b1d5caf3SKevin Bowling static int  ixgbe_setup_low_power_mode(if_ctx_t);
151c19c7afeSEric Joyner 
152b1d5caf3SKevin Bowling static void ixgbe_config_dmac(struct ixgbe_softc *);
153b1d5caf3SKevin Bowling static void ixgbe_configure_ivars(struct ixgbe_softc *);
154b1d5caf3SKevin Bowling static void ixgbe_set_ivar(struct ixgbe_softc *, u8, u8, s8);
155c19c7afeSEric Joyner static u8   *ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *);
156b1d5caf3SKevin Bowling static bool ixgbe_sfp_probe(if_ctx_t);
157c19c7afeSEric Joyner 
158b1d5caf3SKevin Bowling static void ixgbe_free_pci_resources(if_ctx_t);
159c19c7afeSEric Joyner 
160b1d5caf3SKevin Bowling static int  ixgbe_msix_link(void *);
161b1d5caf3SKevin Bowling static int  ixgbe_msix_que(void *);
162b1d5caf3SKevin Bowling static void ixgbe_initialize_rss_mapping(struct ixgbe_softc *);
163b1d5caf3SKevin Bowling static void ixgbe_initialize_receive_units(if_ctx_t);
164b1d5caf3SKevin Bowling static void ixgbe_initialize_transmit_units(if_ctx_t);
165c19c7afeSEric Joyner 
166b1d5caf3SKevin Bowling static int  ixgbe_setup_interface(if_ctx_t);
167b1d5caf3SKevin Bowling static void ixgbe_init_device_features(struct ixgbe_softc *);
168b1d5caf3SKevin Bowling static void ixgbe_check_fan_failure(struct ixgbe_softc *, u32, bool);
1697660e4eaSKevin Bowling static void ixgbe_sbuf_fw_version(struct ixgbe_hw *, struct sbuf *);
170b1d5caf3SKevin Bowling static void ixgbe_print_fw_version(if_ctx_t);
171b1d5caf3SKevin Bowling static void ixgbe_add_media_types(if_ctx_t);
172b1d5caf3SKevin Bowling static void ixgbe_update_stats_counters(struct ixgbe_softc *);
173b1d5caf3SKevin Bowling static void ixgbe_config_link(if_ctx_t);
174b1d5caf3SKevin Bowling static void ixgbe_get_slot_info(struct ixgbe_softc *);
175f72de14eSKevin Bowling static void ixgbe_fw_mode_timer(void *);
176b1d5caf3SKevin Bowling static void ixgbe_check_wol_support(struct ixgbe_softc *);
177b1d5caf3SKevin Bowling static void ixgbe_enable_rx_drop(struct ixgbe_softc *);
178b1d5caf3SKevin Bowling static void ixgbe_disable_rx_drop(struct ixgbe_softc *);
179758cc3dcSJack F Vogel 
180b1d5caf3SKevin Bowling static void ixgbe_add_hw_stats(struct ixgbe_softc *);
181b1d5caf3SKevin Bowling static int  ixgbe_set_flowcntl(struct ixgbe_softc *, int);
182b1d5caf3SKevin Bowling static int  ixgbe_set_advertise(struct ixgbe_softc *, int);
183d381c807SPiotr Pietruszewski static int  ixgbe_get_default_advertise(struct ixgbe_softc *);
184b1d5caf3SKevin Bowling static void ixgbe_setup_vlan_hw_support(if_ctx_t);
185b1d5caf3SKevin Bowling static void ixgbe_config_gpie(struct ixgbe_softc *);
186b1d5caf3SKevin Bowling static void ixgbe_config_delay_values(struct ixgbe_softc *);
1876f37f232SEric Joyner 
1886f37f232SEric Joyner /* Sysctl handlers */
189f2c4db54SSteven Hartland static int  ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS);
190f2c4db54SSteven Hartland static int  ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS);
1918eb6488eSEric Joyner static int  ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS);
1926f37f232SEric Joyner static int  ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS);
1936f37f232SEric Joyner static int  ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS);
1946f37f232SEric Joyner static int  ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS);
1957660e4eaSKevin Bowling static int  ixgbe_sysctl_print_fw_version(SYSCTL_HANDLER_ARGS);
196a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
197a9ca1c79SSean Bruno static int  ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS);
198a9ca1c79SSean Bruno static int  ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS);
199a9ca1c79SSean Bruno #endif
2008eb6488eSEric Joyner static int  ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS);
2018eb6488eSEric Joyner static int  ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS);
2028eb6488eSEric Joyner static int  ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS);
2038eb6488eSEric Joyner static int  ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS);
2048eb6488eSEric Joyner static int  ixgbe_sysctl_eee_state(SYSCTL_HANDLER_ARGS);
2056f37f232SEric Joyner static int  ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS);
2066f37f232SEric Joyner static int  ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS);
207758cc3dcSJack F Vogel 
208758cc3dcSJack F Vogel /* Deferred interrupt tasklets */
209c19c7afeSEric Joyner static void ixgbe_handle_msf(void *);
210c19c7afeSEric Joyner static void ixgbe_handle_mod(void *);
211c19c7afeSEric Joyner static void ixgbe_handle_phy(void *);
212758cc3dcSJack F Vogel 
2138eb6488eSEric Joyner /************************************************************************
214758cc3dcSJack F Vogel  *  FreeBSD Device Interface Entry Points
2158eb6488eSEric Joyner  ************************************************************************/
216a1edda90SAdrian Chadd static device_method_t ix_methods[] = {
217758cc3dcSJack F Vogel 	/* Device interface */
218c19c7afeSEric Joyner 	DEVMETHOD(device_register, ixgbe_register),
219c19c7afeSEric Joyner 	DEVMETHOD(device_probe, iflib_device_probe),
220c19c7afeSEric Joyner 	DEVMETHOD(device_attach, iflib_device_attach),
221c19c7afeSEric Joyner 	DEVMETHOD(device_detach, iflib_device_detach),
222c19c7afeSEric Joyner 	DEVMETHOD(device_shutdown, iflib_device_shutdown),
223c19c7afeSEric Joyner 	DEVMETHOD(device_suspend, iflib_device_suspend),
224c19c7afeSEric Joyner 	DEVMETHOD(device_resume, iflib_device_resume),
22548056c88SJack F Vogel #ifdef PCI_IOV
226c19c7afeSEric Joyner 	DEVMETHOD(pci_iov_init, iflib_device_iov_init),
227c19c7afeSEric Joyner 	DEVMETHOD(pci_iov_uninit, iflib_device_iov_uninit),
228c19c7afeSEric Joyner 	DEVMETHOD(pci_iov_add_vf, iflib_device_iov_add_vf),
22948056c88SJack F Vogel #endif /* PCI_IOV */
230758cc3dcSJack F Vogel 	DEVMETHOD_END
231758cc3dcSJack F Vogel };
232758cc3dcSJack F Vogel 
233a1edda90SAdrian Chadd static driver_t ix_driver = {
234b1d5caf3SKevin Bowling 	"ix", ix_methods, sizeof(struct ixgbe_softc),
235758cc3dcSJack F Vogel };
236758cc3dcSJack F Vogel 
237964c2b3aSJohn Baldwin DRIVER_MODULE(ix, pci, ix_driver, 0, 0);
238937b0f25SYuri Pankov IFLIB_PNP_INFO(pci, ix_driver, ixgbe_vendor_info_array);
239a1edda90SAdrian Chadd MODULE_DEPEND(ix, pci, 1, 1, 1);
240a1edda90SAdrian Chadd MODULE_DEPEND(ix, ether, 1, 1, 1);
241c19c7afeSEric Joyner MODULE_DEPEND(ix, iflib, 1, 1, 1);
242c19c7afeSEric Joyner 
243c19c7afeSEric Joyner static device_method_t ixgbe_if_methods[] = {
244c19c7afeSEric Joyner 	DEVMETHOD(ifdi_attach_pre, ixgbe_if_attach_pre),
245c19c7afeSEric Joyner 	DEVMETHOD(ifdi_attach_post, ixgbe_if_attach_post),
246c19c7afeSEric Joyner 	DEVMETHOD(ifdi_detach, ixgbe_if_detach),
247c19c7afeSEric Joyner 	DEVMETHOD(ifdi_shutdown, ixgbe_if_shutdown),
248c19c7afeSEric Joyner 	DEVMETHOD(ifdi_suspend, ixgbe_if_suspend),
249c19c7afeSEric Joyner 	DEVMETHOD(ifdi_resume, ixgbe_if_resume),
250c19c7afeSEric Joyner 	DEVMETHOD(ifdi_init, ixgbe_if_init),
251c19c7afeSEric Joyner 	DEVMETHOD(ifdi_stop, ixgbe_if_stop),
252c19c7afeSEric Joyner 	DEVMETHOD(ifdi_msix_intr_assign, ixgbe_if_msix_intr_assign),
253c19c7afeSEric Joyner 	DEVMETHOD(ifdi_intr_enable, ixgbe_if_enable_intr),
254c19c7afeSEric Joyner 	DEVMETHOD(ifdi_intr_disable, ixgbe_if_disable_intr),
255b2c1e8e6SEric Joyner 	DEVMETHOD(ifdi_link_intr_enable, ixgbe_link_intr_enable),
256c19c7afeSEric Joyner 	DEVMETHOD(ifdi_tx_queue_intr_enable, ixgbe_if_rx_queue_intr_enable),
257c19c7afeSEric Joyner 	DEVMETHOD(ifdi_rx_queue_intr_enable, ixgbe_if_rx_queue_intr_enable),
258c19c7afeSEric Joyner 	DEVMETHOD(ifdi_tx_queues_alloc, ixgbe_if_tx_queues_alloc),
259c19c7afeSEric Joyner 	DEVMETHOD(ifdi_rx_queues_alloc, ixgbe_if_rx_queues_alloc),
260c19c7afeSEric Joyner 	DEVMETHOD(ifdi_queues_free, ixgbe_if_queues_free),
261c19c7afeSEric Joyner 	DEVMETHOD(ifdi_update_admin_status, ixgbe_if_update_admin_status),
262c19c7afeSEric Joyner 	DEVMETHOD(ifdi_multi_set, ixgbe_if_multi_set),
263c19c7afeSEric Joyner 	DEVMETHOD(ifdi_mtu_set, ixgbe_if_mtu_set),
264c19c7afeSEric Joyner 	DEVMETHOD(ifdi_crcstrip_set, ixgbe_if_crcstrip_set),
265c19c7afeSEric Joyner 	DEVMETHOD(ifdi_media_status, ixgbe_if_media_status),
266c19c7afeSEric Joyner 	DEVMETHOD(ifdi_media_change, ixgbe_if_media_change),
267c19c7afeSEric Joyner 	DEVMETHOD(ifdi_promisc_set, ixgbe_if_promisc_set),
268c19c7afeSEric Joyner 	DEVMETHOD(ifdi_timer, ixgbe_if_timer),
269c19c7afeSEric Joyner 	DEVMETHOD(ifdi_vlan_register, ixgbe_if_vlan_register),
270c19c7afeSEric Joyner 	DEVMETHOD(ifdi_vlan_unregister, ixgbe_if_vlan_unregister),
271c19c7afeSEric Joyner 	DEVMETHOD(ifdi_get_counter, ixgbe_if_get_counter),
272bca38080SAndrew Gallatin 	DEVMETHOD(ifdi_i2c_req, ixgbe_if_i2c_req),
273cf150917SEric Joyner 	DEVMETHOD(ifdi_needs_restart, ixgbe_if_needs_restart),
274c19c7afeSEric Joyner #ifdef PCI_IOV
275c19c7afeSEric Joyner 	DEVMETHOD(ifdi_iov_init, ixgbe_if_iov_init),
276c19c7afeSEric Joyner 	DEVMETHOD(ifdi_iov_uninit, ixgbe_if_iov_uninit),
277c19c7afeSEric Joyner 	DEVMETHOD(ifdi_iov_vf_add, ixgbe_if_iov_vf_add),
278c19c7afeSEric Joyner #endif /* PCI_IOV */
279c19c7afeSEric Joyner 	DEVMETHOD_END
280c19c7afeSEric Joyner };
281758cc3dcSJack F Vogel 
282758cc3dcSJack F Vogel /*
2838eb6488eSEric Joyner  * TUNEABLE PARAMETERS:
284758cc3dcSJack F Vogel  */
285758cc3dcSJack F Vogel 
28620b91f0aSPawel Biernacki static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
28720b91f0aSPawel Biernacki     "IXGBE driver parameters");
288c19c7afeSEric Joyner static driver_t ixgbe_if_driver = {
289b1d5caf3SKevin Bowling   "ixgbe_if", ixgbe_if_methods, sizeof(struct ixgbe_softc)
290c19c7afeSEric Joyner };
291758cc3dcSJack F Vogel 
292758cc3dcSJack F Vogel static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY);
293758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN,
294758cc3dcSJack F Vogel     &ixgbe_max_interrupt_rate, 0, "Maximum interrupts per second");
295758cc3dcSJack F Vogel 
296f2c4db54SSteven Hartland /* Flow control setting, default to full */
297f2c4db54SSteven Hartland static int ixgbe_flow_control = ixgbe_fc_full;
298f2c4db54SSteven Hartland SYSCTL_INT(_hw_ix, OID_AUTO, flow_control, CTLFLAG_RDTUN,
299f2c4db54SSteven Hartland     &ixgbe_flow_control, 0, "Default flow control used for all adapters");
300f2c4db54SSteven Hartland 
301f2c4db54SSteven Hartland /* Advertise Speed, default to 0 (auto) */
302f2c4db54SSteven Hartland static int ixgbe_advertise_speed = 0;
303f2c4db54SSteven Hartland SYSCTL_INT(_hw_ix, OID_AUTO, advertise_speed, CTLFLAG_RDTUN,
304f2c4db54SSteven Hartland     &ixgbe_advertise_speed, 0, "Default advertised speed for all adapters");
305f2c4db54SSteven Hartland 
306758cc3dcSJack F Vogel /*
3078eb6488eSEric Joyner  * Smart speed setting, default to on
3088eb6488eSEric Joyner  * this only works as a compile option
3098eb6488eSEric Joyner  * right now as its during attach, set
3108eb6488eSEric Joyner  * this to 'ixgbe_smart_speed_off' to
3118eb6488eSEric Joyner  * disable.
312758cc3dcSJack F Vogel  */
313758cc3dcSJack F Vogel static int ixgbe_smart_speed = ixgbe_smart_speed_on;
314758cc3dcSJack F Vogel 
315758cc3dcSJack F Vogel /*
3168eb6488eSEric Joyner  * MSI-X should be the default for best performance,
317758cc3dcSJack F Vogel  * but this allows it to be forced off for testing.
318758cc3dcSJack F Vogel  */
319758cc3dcSJack F Vogel static int ixgbe_enable_msix = 1;
320758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixgbe_enable_msix, 0,
321758cc3dcSJack F Vogel     "Enable MSI-X interrupts");
322758cc3dcSJack F Vogel 
323758cc3dcSJack F Vogel /*
3248eb6488eSEric Joyner  * Defining this on will allow the use
3258eb6488eSEric Joyner  * of unsupported SFP+ modules, note that
3268eb6488eSEric Joyner  * doing so you are on your own :)
327758cc3dcSJack F Vogel  */
32879b36ec9SKevin Bowling static int allow_unsupported_sfp = false;
329fb6aa95dSSean Bruno SYSCTL_INT(_hw_ix, OID_AUTO, unsupported_sfp, CTLFLAG_RDTUN,
3308eb6488eSEric Joyner     &allow_unsupported_sfp, 0,
3318eb6488eSEric Joyner     "Allow unsupported SFP modules...use at your own risk");
3328eb6488eSEric Joyner 
3338eb6488eSEric Joyner /*
3348eb6488eSEric Joyner  * Not sure if Flow Director is fully baked,
3358eb6488eSEric Joyner  * so we'll default to turning it off.
3368eb6488eSEric Joyner  */
3378eb6488eSEric Joyner static int ixgbe_enable_fdir = 0;
3388eb6488eSEric Joyner SYSCTL_INT(_hw_ix, OID_AUTO, enable_fdir, CTLFLAG_RDTUN, &ixgbe_enable_fdir, 0,
3398eb6488eSEric Joyner     "Enable Flow Director");
3408eb6488eSEric Joyner 
3418eb6488eSEric Joyner /* Receive-Side Scaling */
3428eb6488eSEric Joyner static int ixgbe_enable_rss = 1;
3438eb6488eSEric Joyner SYSCTL_INT(_hw_ix, OID_AUTO, enable_rss, CTLFLAG_RDTUN, &ixgbe_enable_rss, 0,
3448eb6488eSEric Joyner     "Enable Receive-Side Scaling (RSS)");
345758cc3dcSJack F Vogel 
34664881da4SSai Rajesh Tallamraju /*
34764881da4SSai Rajesh Tallamraju  * AIM: Adaptive Interrupt Moderation
34864881da4SSai Rajesh Tallamraju  * which means that the interrupt rate
34964881da4SSai Rajesh Tallamraju  * is varied over time based on the
35064881da4SSai Rajesh Tallamraju  * traffic for that interrupt vector
35164881da4SSai Rajesh Tallamraju  */
35279b36ec9SKevin Bowling static int ixgbe_enable_aim = false;
35364881da4SSai Rajesh Tallamraju SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0,
35464881da4SSai Rajesh Tallamraju     "Enable adaptive interrupt moderation");
35564881da4SSai Rajesh Tallamraju 
356c19c7afeSEric Joyner #if 0
357758cc3dcSJack F Vogel /* Keep running tab on them for sanity check */
358758cc3dcSJack F Vogel static int ixgbe_total_ports;
359c19c7afeSEric Joyner #endif
360758cc3dcSJack F Vogel 
3618eb6488eSEric Joyner MALLOC_DEFINE(M_IXGBE, "ix", "ix driver allocations");
362758cc3dcSJack F Vogel 
363c19c7afeSEric Joyner /*
364c19c7afeSEric Joyner  * For Flow Director: this is the number of TX packets we sample
365c19c7afeSEric Joyner  * for the filter pool, this means every 20th packet will be probed.
366c19c7afeSEric Joyner  *
367c19c7afeSEric Joyner  * This feature can be disabled by setting this to 0.
368c19c7afeSEric Joyner  */
369c19c7afeSEric Joyner static int atr_sample_rate = 20;
370c19c7afeSEric Joyner 
371c19c7afeSEric Joyner extern struct if_txrx ixgbe_txrx;
372c19c7afeSEric Joyner 
373c19c7afeSEric Joyner static struct if_shared_ctx ixgbe_sctx_init = {
374c19c7afeSEric Joyner 	.isc_magic = IFLIB_MAGIC,
375c19c7afeSEric Joyner 	.isc_q_align = PAGE_SIZE,/* max(DBA_ALIGN, PAGE_SIZE) */
3767f87c040SMarius Strobl 	.isc_tx_maxsize = IXGBE_TSO_SIZE + sizeof(struct ether_vlan_header),
377c19c7afeSEric Joyner 	.isc_tx_maxsegsize = PAGE_SIZE,
3787f87c040SMarius Strobl 	.isc_tso_maxsize = IXGBE_TSO_SIZE + sizeof(struct ether_vlan_header),
3797f87c040SMarius Strobl 	.isc_tso_maxsegsize = PAGE_SIZE,
380c19c7afeSEric Joyner 	.isc_rx_maxsize = PAGE_SIZE*4,
381c19c7afeSEric Joyner 	.isc_rx_nsegments = 1,
382c19c7afeSEric Joyner 	.isc_rx_maxsegsize = PAGE_SIZE*4,
383c19c7afeSEric Joyner 	.isc_nfl = 1,
384c19c7afeSEric Joyner 	.isc_ntxqs = 1,
385c19c7afeSEric Joyner 	.isc_nrxqs = 1,
386c19c7afeSEric Joyner 
387c19c7afeSEric Joyner 	.isc_admin_intrcnt = 1,
388c19c7afeSEric Joyner 	.isc_vendor_info = ixgbe_vendor_info_array,
389c19c7afeSEric Joyner 	.isc_driver_version = ixgbe_driver_version,
390c19c7afeSEric Joyner 	.isc_driver = &ixgbe_if_driver,
3917aad1f4eSEric Joyner 	.isc_flags = IFLIB_TSO_INIT_IP,
392c19c7afeSEric Joyner 
393c19c7afeSEric Joyner 	.isc_nrxd_min = {MIN_RXD},
394c19c7afeSEric Joyner 	.isc_ntxd_min = {MIN_TXD},
395c19c7afeSEric Joyner 	.isc_nrxd_max = {MAX_RXD},
396c19c7afeSEric Joyner 	.isc_ntxd_max = {MAX_TXD},
397c19c7afeSEric Joyner 	.isc_nrxd_default = {DEFAULT_RXD},
398c19c7afeSEric Joyner 	.isc_ntxd_default = {DEFAULT_TXD},
399c19c7afeSEric Joyner };
400c19c7afeSEric Joyner 
401c19c7afeSEric Joyner /************************************************************************
402c19c7afeSEric Joyner  * ixgbe_if_tx_queues_alloc
403c19c7afeSEric Joyner  ************************************************************************/
404c19c7afeSEric Joyner static int
405c19c7afeSEric Joyner ixgbe_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
406c19c7afeSEric Joyner     int ntxqs, int ntxqsets)
407c19c7afeSEric Joyner {
408b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
409b1d5caf3SKevin Bowling 	if_softc_ctx_t     scctx = sc->shared;
410c19c7afeSEric Joyner 	struct ix_tx_queue *que;
411c19c7afeSEric Joyner 	int                i, j, error;
412c19c7afeSEric Joyner 
413b1d5caf3SKevin Bowling 	MPASS(sc->num_tx_queues > 0);
414b1d5caf3SKevin Bowling 	MPASS(sc->num_tx_queues == ntxqsets);
415c19c7afeSEric Joyner 	MPASS(ntxqs == 1);
416c19c7afeSEric Joyner 
417c19c7afeSEric Joyner 	/* Allocate queue structure memory */
418b1d5caf3SKevin Bowling 	sc->tx_queues =
419c19c7afeSEric Joyner 	    (struct ix_tx_queue *)malloc(sizeof(struct ix_tx_queue) * ntxqsets,
420c19c7afeSEric Joyner 	                                 M_IXGBE, M_NOWAIT | M_ZERO);
421b1d5caf3SKevin Bowling 	if (!sc->tx_queues) {
422c19c7afeSEric Joyner 		device_printf(iflib_get_dev(ctx),
423c19c7afeSEric Joyner 		    "Unable to allocate TX ring memory\n");
424c19c7afeSEric Joyner 		return (ENOMEM);
425c19c7afeSEric Joyner 	}
426c19c7afeSEric Joyner 
427b1d5caf3SKevin Bowling 	for (i = 0, que = sc->tx_queues; i < ntxqsets; i++, que++) {
428c19c7afeSEric Joyner 		struct tx_ring *txr = &que->txr;
429c19c7afeSEric Joyner 
430c19c7afeSEric Joyner 		/* In case SR-IOV is enabled, align the index properly */
431b1d5caf3SKevin Bowling 		txr->me = ixgbe_vf_que_index(sc->iov_mode, sc->pool,
432c19c7afeSEric Joyner 		    i);
433c19c7afeSEric Joyner 
434b1d5caf3SKevin Bowling 		txr->sc = que->sc = sc;
435c19c7afeSEric Joyner 
436c19c7afeSEric Joyner 		/* Allocate report status array */
437c19c7afeSEric Joyner 		txr->tx_rsq = (qidx_t *)malloc(sizeof(qidx_t) * scctx->isc_ntxd[0], M_IXGBE, M_NOWAIT | M_ZERO);
438c19c7afeSEric Joyner 		if (txr->tx_rsq == NULL) {
439c19c7afeSEric Joyner 			error = ENOMEM;
440c19c7afeSEric Joyner 			goto fail;
441c19c7afeSEric Joyner 		}
442c19c7afeSEric Joyner 		for (j = 0; j < scctx->isc_ntxd[0]; j++)
443c19c7afeSEric Joyner 			txr->tx_rsq[j] = QIDX_INVALID;
444c19c7afeSEric Joyner 		/* get the virtual and physical address of the hardware queues */
445c19c7afeSEric Joyner 		txr->tail = IXGBE_TDT(txr->me);
446c19c7afeSEric Joyner 		txr->tx_base = (union ixgbe_adv_tx_desc *)vaddrs[i];
447c19c7afeSEric Joyner 		txr->tx_paddr = paddrs[i];
448c19c7afeSEric Joyner 
449c19c7afeSEric Joyner 		txr->bytes = 0;
450c19c7afeSEric Joyner 		txr->total_packets = 0;
451c19c7afeSEric Joyner 
452c19c7afeSEric Joyner 		/* Set the rate at which we sample packets */
453b1d5caf3SKevin Bowling 		if (sc->feat_en & IXGBE_FEATURE_FDIR)
454c19c7afeSEric Joyner 			txr->atr_sample = atr_sample_rate;
455c19c7afeSEric Joyner 
456c19c7afeSEric Joyner 	}
457c19c7afeSEric Joyner 
458c19c7afeSEric Joyner 	device_printf(iflib_get_dev(ctx), "allocated for %d queues\n",
459b1d5caf3SKevin Bowling 	    sc->num_tx_queues);
460c19c7afeSEric Joyner 
461c19c7afeSEric Joyner 	return (0);
462c19c7afeSEric Joyner 
463c19c7afeSEric Joyner fail:
464c19c7afeSEric Joyner 	ixgbe_if_queues_free(ctx);
465c19c7afeSEric Joyner 
466c19c7afeSEric Joyner 	return (error);
467c19c7afeSEric Joyner } /* ixgbe_if_tx_queues_alloc */
468c19c7afeSEric Joyner 
469c19c7afeSEric Joyner /************************************************************************
470c19c7afeSEric Joyner  * ixgbe_if_rx_queues_alloc
471c19c7afeSEric Joyner  ************************************************************************/
472c19c7afeSEric Joyner static int
473c19c7afeSEric Joyner ixgbe_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
474c19c7afeSEric Joyner     int nrxqs, int nrxqsets)
475c19c7afeSEric Joyner {
476b1d5caf3SKevin Bowling 	struct ixgbe_softc     *sc = iflib_get_softc(ctx);
477c19c7afeSEric Joyner 	struct ix_rx_queue *que;
478c19c7afeSEric Joyner 	int                i;
479c19c7afeSEric Joyner 
480b1d5caf3SKevin Bowling 	MPASS(sc->num_rx_queues > 0);
481b1d5caf3SKevin Bowling 	MPASS(sc->num_rx_queues == nrxqsets);
482c19c7afeSEric Joyner 	MPASS(nrxqs == 1);
483c19c7afeSEric Joyner 
484c19c7afeSEric Joyner 	/* Allocate queue structure memory */
485b1d5caf3SKevin Bowling 	sc->rx_queues =
486c19c7afeSEric Joyner 	    (struct ix_rx_queue *)malloc(sizeof(struct ix_rx_queue)*nrxqsets,
487c19c7afeSEric Joyner 	                                 M_IXGBE, M_NOWAIT | M_ZERO);
488b1d5caf3SKevin Bowling 	if (!sc->rx_queues) {
489c19c7afeSEric Joyner 		device_printf(iflib_get_dev(ctx),
490c19c7afeSEric Joyner 		    "Unable to allocate TX ring memory\n");
491c19c7afeSEric Joyner 		return (ENOMEM);
492c19c7afeSEric Joyner 	}
493c19c7afeSEric Joyner 
494b1d5caf3SKevin Bowling 	for (i = 0, que = sc->rx_queues; i < nrxqsets; i++, que++) {
495c19c7afeSEric Joyner 		struct rx_ring *rxr = &que->rxr;
496c19c7afeSEric Joyner 
497c19c7afeSEric Joyner 		/* In case SR-IOV is enabled, align the index properly */
498b1d5caf3SKevin Bowling 		rxr->me = ixgbe_vf_que_index(sc->iov_mode, sc->pool,
499c19c7afeSEric Joyner 		    i);
500c19c7afeSEric Joyner 
501b1d5caf3SKevin Bowling 		rxr->sc = que->sc = sc;
502c19c7afeSEric Joyner 
503c19c7afeSEric Joyner 		/* get the virtual and physical address of the hw queues */
504c19c7afeSEric Joyner 		rxr->tail = IXGBE_RDT(rxr->me);
505c19c7afeSEric Joyner 		rxr->rx_base = (union ixgbe_adv_rx_desc *)vaddrs[i];
506c19c7afeSEric Joyner 		rxr->rx_paddr = paddrs[i];
507c19c7afeSEric Joyner 		rxr->bytes = 0;
508c19c7afeSEric Joyner 		rxr->que = que;
509c19c7afeSEric Joyner 	}
510c19c7afeSEric Joyner 
511c19c7afeSEric Joyner 	device_printf(iflib_get_dev(ctx), "allocated for %d rx queues\n",
512b1d5caf3SKevin Bowling 	    sc->num_rx_queues);
513c19c7afeSEric Joyner 
514c19c7afeSEric Joyner 	return (0);
515c19c7afeSEric Joyner } /* ixgbe_if_rx_queues_alloc */
516c19c7afeSEric Joyner 
517c19c7afeSEric Joyner /************************************************************************
518c19c7afeSEric Joyner  * ixgbe_if_queues_free
519c19c7afeSEric Joyner  ************************************************************************/
520c19c7afeSEric Joyner static void
521c19c7afeSEric Joyner ixgbe_if_queues_free(if_ctx_t ctx)
522c19c7afeSEric Joyner {
523b1d5caf3SKevin Bowling 	struct ixgbe_softc     *sc = iflib_get_softc(ctx);
524b1d5caf3SKevin Bowling 	struct ix_tx_queue *tx_que = sc->tx_queues;
525b1d5caf3SKevin Bowling 	struct ix_rx_queue *rx_que = sc->rx_queues;
526c19c7afeSEric Joyner 	int                i;
527c19c7afeSEric Joyner 
528c19c7afeSEric Joyner 	if (tx_que != NULL) {
529b1d5caf3SKevin Bowling 		for (i = 0; i < sc->num_tx_queues; i++, tx_que++) {
530c19c7afeSEric Joyner 			struct tx_ring *txr = &tx_que->txr;
531c19c7afeSEric Joyner 			if (txr->tx_rsq == NULL)
532c19c7afeSEric Joyner 				break;
533c19c7afeSEric Joyner 
534c19c7afeSEric Joyner 			free(txr->tx_rsq, M_IXGBE);
535c19c7afeSEric Joyner 			txr->tx_rsq = NULL;
536c19c7afeSEric Joyner 		}
537c19c7afeSEric Joyner 
538b1d5caf3SKevin Bowling 		free(sc->tx_queues, M_IXGBE);
539b1d5caf3SKevin Bowling 		sc->tx_queues = NULL;
540c19c7afeSEric Joyner 	}
541c19c7afeSEric Joyner 	if (rx_que != NULL) {
542b1d5caf3SKevin Bowling 		free(sc->rx_queues, M_IXGBE);
543b1d5caf3SKevin Bowling 		sc->rx_queues = NULL;
544c19c7afeSEric Joyner 	}
545c19c7afeSEric Joyner } /* ixgbe_if_queues_free */
546c19c7afeSEric Joyner 
5478eb6488eSEric Joyner /************************************************************************
5488eb6488eSEric Joyner  * ixgbe_initialize_rss_mapping
5498eb6488eSEric Joyner  ************************************************************************/
5508eb6488eSEric Joyner static void
551b1d5caf3SKevin Bowling ixgbe_initialize_rss_mapping(struct ixgbe_softc *sc)
552758cc3dcSJack F Vogel {
553b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
5548eb6488eSEric Joyner 	u32             reta = 0, mrqc, rss_key[10];
5558eb6488eSEric Joyner 	int             queue_id, table_size, index_mult;
5568eb6488eSEric Joyner 	int             i, j;
5578eb6488eSEric Joyner 	u32             rss_hash_config;
5586f37f232SEric Joyner 
559b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_RSS) {
5608eb6488eSEric Joyner 		/* Fetch the configured RSS key */
5618eb6488eSEric Joyner 		rss_getkey((uint8_t *)&rss_key);
562758cc3dcSJack F Vogel 	} else {
5638eb6488eSEric Joyner 		/* set up random bits */
5648eb6488eSEric Joyner 		arc4rand(&rss_key, sizeof(rss_key), 0);
565758cc3dcSJack F Vogel 	}
566758cc3dcSJack F Vogel 
5678eb6488eSEric Joyner 	/* Set multiplier for RETA setup and table size based on MAC */
5688eb6488eSEric Joyner 	index_mult = 0x1;
5698eb6488eSEric Joyner 	table_size = 128;
570b1d5caf3SKevin Bowling 	switch (sc->hw.mac.type) {
5718eb6488eSEric Joyner 	case ixgbe_mac_82598EB:
5728eb6488eSEric Joyner 		index_mult = 0x11;
573758cc3dcSJack F Vogel 		break;
5748eb6488eSEric Joyner 	case ixgbe_mac_X550:
5758eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
5768eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
5778eb6488eSEric Joyner 		table_size = 512;
5788eb6488eSEric Joyner 		break;
579758cc3dcSJack F Vogel 	default:
580758cc3dcSJack F Vogel 		break;
581758cc3dcSJack F Vogel 	}
582758cc3dcSJack F Vogel 
5838eb6488eSEric Joyner 	/* Set up the redirection table */
5848eb6488eSEric Joyner 	for (i = 0, j = 0; i < table_size; i++, j++) {
585b1d5caf3SKevin Bowling 		if (j == sc->num_rx_queues)
5868eb6488eSEric Joyner 			j = 0;
587758cc3dcSJack F Vogel 
588b1d5caf3SKevin Bowling 		if (sc->feat_en & IXGBE_FEATURE_RSS) {
589a9ca1c79SSean Bruno 			/*
5908eb6488eSEric Joyner 			 * Fetch the RSS bucket id for the given indirection
5918eb6488eSEric Joyner 			 * entry. Cap it at the number of configured buckets
592c19c7afeSEric Joyner 			 * (which is num_rx_queues.)
593a9ca1c79SSean Bruno 			 */
5948eb6488eSEric Joyner 			queue_id = rss_get_indirection_to_bucket(i);
595b1d5caf3SKevin Bowling 			queue_id = queue_id % sc->num_rx_queues;
596758cc3dcSJack F Vogel 		} else
5978eb6488eSEric Joyner 			queue_id = (j * index_mult);
5988eb6488eSEric Joyner 
5998eb6488eSEric Joyner 		/*
6008eb6488eSEric Joyner 		 * The low 8 bits are for hash value (n+0);
6018eb6488eSEric Joyner 		 * The next 8 bits are for hash value (n+1), etc.
6028eb6488eSEric Joyner 		 */
6038eb6488eSEric Joyner 		reta = reta >> 8;
6048eb6488eSEric Joyner 		reta = reta | (((uint32_t)queue_id) << 24);
6058eb6488eSEric Joyner 		if ((i & 3) == 3) {
6068eb6488eSEric Joyner 			if (i < 128)
6078eb6488eSEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
6088eb6488eSEric Joyner 			else
6098eb6488eSEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32),
6108eb6488eSEric Joyner 				    reta);
6118eb6488eSEric Joyner 			reta = 0;
6128eb6488eSEric Joyner 		}
613758cc3dcSJack F Vogel 	}
614758cc3dcSJack F Vogel 
6158eb6488eSEric Joyner 	/* Now fill our hash function seeds */
6168eb6488eSEric Joyner 	for (i = 0; i < 10; i++)
6178eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]);
618758cc3dcSJack F Vogel 
6198eb6488eSEric Joyner 	/* Perform hash on these packet types */
620b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_RSS)
6218eb6488eSEric Joyner 		rss_hash_config = rss_gethashconfig();
622758cc3dcSJack F Vogel 	else {
623758cc3dcSJack F Vogel 		/*
6248eb6488eSEric Joyner 		 * Disable UDP - IP fragments aren't currently being handled
6258eb6488eSEric Joyner 		 * and so we end up with a mix of 2-tuple and 4-tuple
6268eb6488eSEric Joyner 		 * traffic.
627758cc3dcSJack F Vogel 		 */
6288eb6488eSEric Joyner 		rss_hash_config = RSS_HASHTYPE_RSS_IPV4
6298eb6488eSEric Joyner 		                | RSS_HASHTYPE_RSS_TCP_IPV4
6308eb6488eSEric Joyner 		                | RSS_HASHTYPE_RSS_IPV6
6318eb6488eSEric Joyner 		                | RSS_HASHTYPE_RSS_TCP_IPV6
6328eb6488eSEric Joyner 		                | RSS_HASHTYPE_RSS_IPV6_EX
6338eb6488eSEric Joyner 		                | RSS_HASHTYPE_RSS_TCP_IPV6_EX;
634758cc3dcSJack F Vogel 	}
635758cc3dcSJack F Vogel 
6368eb6488eSEric Joyner 	mrqc = IXGBE_MRQC_RSSEN;
6378eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
6388eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4;
6398eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
6408eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP;
6418eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
6428eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6;
6438eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
6448eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
6458eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
6468eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX;
6478eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX)
6488eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP;
6498eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
6508eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP;
6518eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
6528eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
6538eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX)
6548eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
655b1d5caf3SKevin Bowling 	mrqc |= ixgbe_get_mrqc(sc->iov_mode);
6568eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
6578eb6488eSEric Joyner } /* ixgbe_initialize_rss_mapping */
658758cc3dcSJack F Vogel 
6598eb6488eSEric Joyner /************************************************************************
6608eb6488eSEric Joyner  * ixgbe_initialize_receive_units - Setup receive registers and features.
6618eb6488eSEric Joyner  ************************************************************************/
6628eb6488eSEric Joyner #define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1)
663758cc3dcSJack F Vogel 
664758cc3dcSJack F Vogel static void
665c19c7afeSEric Joyner ixgbe_initialize_receive_units(if_ctx_t ctx)
666758cc3dcSJack F Vogel {
667b1d5caf3SKevin Bowling 	struct ixgbe_softc     *sc = iflib_get_softc(ctx);
668b1d5caf3SKevin Bowling 	if_softc_ctx_t     scctx = sc->shared;
669b1d5caf3SKevin Bowling 	struct ixgbe_hw    *hw = &sc->hw;
670ff06a8dbSJustin Hibbits 	if_t               ifp = iflib_get_ifp(ctx);
671c19c7afeSEric Joyner 	struct ix_rx_queue *que;
6728eb6488eSEric Joyner 	int                i, j;
6738eb6488eSEric Joyner 	u32                bufsz, fctrl, srrctl, rxcsum;
6748eb6488eSEric Joyner 	u32                hlreg;
67548056c88SJack F Vogel 
67648056c88SJack F Vogel 	/*
6778eb6488eSEric Joyner 	 * Make sure receives are disabled while
6788eb6488eSEric Joyner 	 * setting up the descriptor ring
67948056c88SJack F Vogel 	 */
6808eb6488eSEric Joyner 	ixgbe_disable_rx(hw);
6818eb6488eSEric Joyner 
6828eb6488eSEric Joyner 	/* Enable broadcasts */
6838eb6488eSEric Joyner 	fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
6848eb6488eSEric Joyner 	fctrl |= IXGBE_FCTRL_BAM;
685b1d5caf3SKevin Bowling 	if (sc->hw.mac.type == ixgbe_mac_82598EB) {
6868eb6488eSEric Joyner 		fctrl |= IXGBE_FCTRL_DPF;
6878eb6488eSEric Joyner 		fctrl |= IXGBE_FCTRL_PMCF;
68848056c88SJack F Vogel 	}
6898eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
6908eb6488eSEric Joyner 
6918eb6488eSEric Joyner 	/* Set for Jumbo Frames? */
6928eb6488eSEric Joyner 	hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0);
693ff06a8dbSJustin Hibbits 	if (if_getmtu(ifp) > ETHERMTU)
6948eb6488eSEric Joyner 		hlreg |= IXGBE_HLREG0_JUMBOEN;
6958eb6488eSEric Joyner 	else
6968eb6488eSEric Joyner 		hlreg &= ~IXGBE_HLREG0_JUMBOEN;
6978eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg);
6988eb6488eSEric Joyner 
699b1d5caf3SKevin Bowling 	bufsz = (sc->rx_mbuf_sz + BSIZEPKT_ROUNDUP) >>
7008eb6488eSEric Joyner 	    IXGBE_SRRCTL_BSIZEPKT_SHIFT;
7018eb6488eSEric Joyner 
702c19c7afeSEric Joyner 	/* Setup the Base and Length of the Rx Descriptor Ring */
703b1d5caf3SKevin Bowling 	for (i = 0, que = sc->rx_queues; i < sc->num_rx_queues; i++, que++) {
704c19c7afeSEric Joyner 		struct rx_ring *rxr = &que->rxr;
705c19c7afeSEric Joyner 		u64            rdba = rxr->rx_paddr;
706c19c7afeSEric Joyner 
7078eb6488eSEric Joyner 		j = rxr->me;
7088eb6488eSEric Joyner 
7098eb6488eSEric Joyner 		/* Setup the Base and Length of the Rx Descriptor Ring */
7108eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j),
7118eb6488eSEric Joyner 		    (rdba & 0x00000000ffffffffULL));
7128eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32));
7138eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j),
714c19c7afeSEric Joyner 		     scctx->isc_nrxd[0] * sizeof(union ixgbe_adv_rx_desc));
7158eb6488eSEric Joyner 
7168eb6488eSEric Joyner 		/* Set up the SRRCTL register */
7178eb6488eSEric Joyner 		srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(j));
7188eb6488eSEric Joyner 		srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
7198eb6488eSEric Joyner 		srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
7208eb6488eSEric Joyner 		srrctl |= bufsz;
7218eb6488eSEric Joyner 		srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
72248056c88SJack F Vogel 
72348056c88SJack F Vogel 		/*
7248eb6488eSEric Joyner 		 * Set DROP_EN iff we have no flow control and >1 queue.
7258eb6488eSEric Joyner 		 * Note that srrctl was cleared shortly before during reset,
7268eb6488eSEric Joyner 		 * so we do not need to clear the bit, but do it just in case
7278eb6488eSEric Joyner 		 * this code is moved elsewhere.
72848056c88SJack F Vogel 		 */
729b1d5caf3SKevin Bowling 		if (sc->num_rx_queues > 1 &&
730b1d5caf3SKevin Bowling 		    sc->hw.fc.requested_mode == ixgbe_fc_none) {
7318eb6488eSEric Joyner 			srrctl |= IXGBE_SRRCTL_DROP_EN;
732758cc3dcSJack F Vogel 		} else {
7338eb6488eSEric Joyner 			srrctl &= ~IXGBE_SRRCTL_DROP_EN;
734758cc3dcSJack F Vogel 		}
735758cc3dcSJack F Vogel 
7368eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(j), srrctl);
737758cc3dcSJack F Vogel 
7388eb6488eSEric Joyner 		/* Setup the HW Rx Head and Tail Descriptor Pointers */
7398eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0);
7408eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0);
741758cc3dcSJack F Vogel 
7428eb6488eSEric Joyner 		/* Set the driver rx tail address */
7438eb6488eSEric Joyner 		rxr->tail =  IXGBE_RDT(rxr->me);
744a9ca1c79SSean Bruno 	}
745758cc3dcSJack F Vogel 
746b1d5caf3SKevin Bowling 	if (sc->hw.mac.type != ixgbe_mac_82598EB) {
7478eb6488eSEric Joyner 		u32 psrtype = IXGBE_PSRTYPE_TCPHDR
7488eb6488eSEric Joyner 		            | IXGBE_PSRTYPE_UDPHDR
7498eb6488eSEric Joyner 		            | IXGBE_PSRTYPE_IPV4HDR
7508eb6488eSEric Joyner 		            | IXGBE_PSRTYPE_IPV6HDR;
7518eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype);
7526f37f232SEric Joyner 	}
7536f37f232SEric Joyner 
7548eb6488eSEric Joyner 	rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
7558eb6488eSEric Joyner 
756b1d5caf3SKevin Bowling 	ixgbe_initialize_rss_mapping(sc);
7578eb6488eSEric Joyner 
758156424fcSPrzemyslaw Lewandowski 	if (sc->feat_en & IXGBE_FEATURE_RSS) {
7598eb6488eSEric Joyner 		/* RSS and RX IPP Checksum are mutually exclusive */
7608eb6488eSEric Joyner 		rxcsum |= IXGBE_RXCSUM_PCSD;
7616f37f232SEric Joyner 	}
7626f37f232SEric Joyner 
763ff06a8dbSJustin Hibbits 	if (if_getcapenable(ifp) & IFCAP_RXCSUM)
7648eb6488eSEric Joyner 		rxcsum |= IXGBE_RXCSUM_PCSD;
765758cc3dcSJack F Vogel 
7668eb6488eSEric Joyner 	/* This is useful for calculating UDP/IP fragment checksums */
7678eb6488eSEric Joyner 	if (!(rxcsum & IXGBE_RXCSUM_PCSD))
7688eb6488eSEric Joyner 		rxcsum |= IXGBE_RXCSUM_IPPCSE;
769758cc3dcSJack F Vogel 
7708eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
771758cc3dcSJack F Vogel 
7728eb6488eSEric Joyner } /* ixgbe_initialize_receive_units */
773758cc3dcSJack F Vogel 
7748eb6488eSEric Joyner /************************************************************************
7758eb6488eSEric Joyner  * ixgbe_initialize_transmit_units - Enable transmit units.
7768eb6488eSEric Joyner  ************************************************************************/
777758cc3dcSJack F Vogel static void
778c19c7afeSEric Joyner ixgbe_initialize_transmit_units(if_ctx_t ctx)
779758cc3dcSJack F Vogel {
780b1d5caf3SKevin Bowling 	struct ixgbe_softc     *sc = iflib_get_softc(ctx);
781b1d5caf3SKevin Bowling 	struct ixgbe_hw    *hw = &sc->hw;
782b1d5caf3SKevin Bowling 	if_softc_ctx_t     scctx = sc->shared;
783c19c7afeSEric Joyner 	struct ix_tx_queue *que;
784c19c7afeSEric Joyner 	int i;
785758cc3dcSJack F Vogel 
786758cc3dcSJack F Vogel 	/* Setup the Base and Length of the Tx Descriptor Ring */
787b1d5caf3SKevin Bowling 	for (i = 0, que = sc->tx_queues; i < sc->num_tx_queues;
788c19c7afeSEric Joyner 	    i++, que++) {
789c19c7afeSEric Joyner 		struct tx_ring	   *txr = &que->txr;
790c19c7afeSEric Joyner 		u64 tdba = txr->tx_paddr;
791758cc3dcSJack F Vogel 		u32 txctrl = 0;
79248056c88SJack F Vogel 		int j = txr->me;
793758cc3dcSJack F Vogel 
79448056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j),
795758cc3dcSJack F Vogel 		    (tdba & 0x00000000ffffffffULL));
79648056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32));
79748056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j),
798c19c7afeSEric Joyner 		    scctx->isc_ntxd[0] * sizeof(union ixgbe_adv_tx_desc));
799758cc3dcSJack F Vogel 
800758cc3dcSJack F Vogel 		/* Setup the HW Tx Head and Tail descriptor pointers */
80148056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0);
80248056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0);
803758cc3dcSJack F Vogel 
804758cc3dcSJack F Vogel 		/* Cache the tail address */
8052dc2d580SEric Joyner 		txr->tail = IXGBE_TDT(txr->me);
8062dc2d580SEric Joyner 
807088a0b27SEric Joyner 		txr->tx_rs_cidx = txr->tx_rs_pidx;
808088a0b27SEric Joyner 		txr->tx_cidx_processed = scctx->isc_ntxd[0] - 1;
809c19c7afeSEric Joyner 		for (int k = 0; k < scctx->isc_ntxd[0]; k++)
810c19c7afeSEric Joyner 			txr->tx_rsq[k] = QIDX_INVALID;
811758cc3dcSJack F Vogel 
812758cc3dcSJack F Vogel 		/* Disable Head Writeback */
813a9ca1c79SSean Bruno 		/*
814a9ca1c79SSean Bruno 		 * Note: for X550 series devices, these registers are actually
815a9ca1c79SSean Bruno 		 * prefixed with TPH_ isntead of DCA_, but the addresses and
816a9ca1c79SSean Bruno 		 * fields remain the same.
817a9ca1c79SSean Bruno 		 */
818758cc3dcSJack F Vogel 		switch (hw->mac.type) {
819758cc3dcSJack F Vogel 		case ixgbe_mac_82598EB:
82048056c88SJack F Vogel 			txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j));
821758cc3dcSJack F Vogel 			break;
822758cc3dcSJack F Vogel 		default:
82348056c88SJack F Vogel 			txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j));
824758cc3dcSJack F Vogel 			break;
825758cc3dcSJack F Vogel 		}
826758cc3dcSJack F Vogel 		txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN;
827758cc3dcSJack F Vogel 		switch (hw->mac.type) {
828758cc3dcSJack F Vogel 		case ixgbe_mac_82598EB:
82948056c88SJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl);
830758cc3dcSJack F Vogel 			break;
831758cc3dcSJack F Vogel 		default:
83248056c88SJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl);
833758cc3dcSJack F Vogel 			break;
834758cc3dcSJack F Vogel 		}
835758cc3dcSJack F Vogel 
836758cc3dcSJack F Vogel 	}
837758cc3dcSJack F Vogel 
838758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
839758cc3dcSJack F Vogel 		u32 dmatxctl, rttdcs;
8408eb6488eSEric Joyner 
841758cc3dcSJack F Vogel 		dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
842758cc3dcSJack F Vogel 		dmatxctl |= IXGBE_DMATXCTL_TE;
843758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl);
844758cc3dcSJack F Vogel 		/* Disable arbiter to set MTQC */
845758cc3dcSJack F Vogel 		rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
846758cc3dcSJack F Vogel 		rttdcs |= IXGBE_RTTDCS_ARBDIS;
847758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
8488eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_MTQC,
849b1d5caf3SKevin Bowling 		    ixgbe_get_mtqc(sc->iov_mode));
850758cc3dcSJack F Vogel 		rttdcs &= ~IXGBE_RTTDCS_ARBDIS;
851758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
852758cc3dcSJack F Vogel 	}
853758cc3dcSJack F Vogel 
8548eb6488eSEric Joyner } /* ixgbe_initialize_transmit_units */
855758cc3dcSJack F Vogel 
8568eb6488eSEric Joyner /************************************************************************
857c19c7afeSEric Joyner  * ixgbe_register
858c19c7afeSEric Joyner  ************************************************************************/
859c19c7afeSEric Joyner static void *
860c19c7afeSEric Joyner ixgbe_register(device_t dev)
861c19c7afeSEric Joyner {
862ffe3def9SMark Johnston 	return (&ixgbe_sctx_init);
863c19c7afeSEric Joyner } /* ixgbe_register */
864c19c7afeSEric Joyner 
865c19c7afeSEric Joyner /************************************************************************
866c19c7afeSEric Joyner  * ixgbe_if_attach_pre - Device initialization routine, part 1
867758cc3dcSJack F Vogel  *
8688eb6488eSEric Joyner  *   Called when the driver is being loaded.
869c19c7afeSEric Joyner  *   Identifies the type of hardware, initializes the hardware,
870c19c7afeSEric Joyner  *   and initializes iflib structures.
871758cc3dcSJack F Vogel  *
8728eb6488eSEric Joyner  *   return 0 on success, positive on failure
8738eb6488eSEric Joyner  ************************************************************************/
8748eb6488eSEric Joyner static int
875c19c7afeSEric Joyner ixgbe_if_attach_pre(if_ctx_t ctx)
876758cc3dcSJack F Vogel {
877b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc;
878c19c7afeSEric Joyner 	device_t        dev;
879c19c7afeSEric Joyner 	if_softc_ctx_t  scctx;
8808eb6488eSEric Joyner 	struct ixgbe_hw *hw;
8818eb6488eSEric Joyner 	int             error = 0;
8828eb6488eSEric Joyner 	u32             ctrl_ext;
8837234c309SJakub Chylkowski 	size_t i;
8848eb6488eSEric Joyner 
8858eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_attach: begin");
8868eb6488eSEric Joyner 
8878eb6488eSEric Joyner 	/* Allocate, clear, and link in our adapter structure */
888c19c7afeSEric Joyner 	dev = iflib_get_dev(ctx);
889b1d5caf3SKevin Bowling 	sc = iflib_get_softc(ctx);
890b1d5caf3SKevin Bowling 	sc->hw.back = sc;
891b1d5caf3SKevin Bowling 	sc->ctx = ctx;
892b1d5caf3SKevin Bowling 	sc->dev = dev;
893b1d5caf3SKevin Bowling 	scctx = sc->shared = iflib_get_softc_ctx(ctx);
894b1d5caf3SKevin Bowling 	sc->media = iflib_get_media(ctx);
895b1d5caf3SKevin Bowling 	hw = &sc->hw;
8968eb6488eSEric Joyner 
8978eb6488eSEric Joyner 	/* Determine hardware revision */
8988eb6488eSEric Joyner 	hw->vendor_id = pci_get_vendor(dev);
8998eb6488eSEric Joyner 	hw->device_id = pci_get_device(dev);
9008eb6488eSEric Joyner 	hw->revision_id = pci_get_revid(dev);
9018eb6488eSEric Joyner 	hw->subsystem_vendor_id = pci_get_subvendor(dev);
9028eb6488eSEric Joyner 	hw->subsystem_device_id = pci_get_subdevice(dev);
903758cc3dcSJack F Vogel 
9048eb6488eSEric Joyner 	/* Do base PCI setup - map BAR0 */
905c19c7afeSEric Joyner 	if (ixgbe_allocate_pci_resources(ctx)) {
9068eb6488eSEric Joyner 		device_printf(dev, "Allocation of PCI resources failed\n");
907c19c7afeSEric Joyner 		return (ENXIO);
9086f37f232SEric Joyner 	}
909758cc3dcSJack F Vogel 
9108eb6488eSEric Joyner 	/* let hardware know driver is loaded */
9118eb6488eSEric Joyner 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
9128eb6488eSEric Joyner 	ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
9138eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
914758cc3dcSJack F Vogel 
915758cc3dcSJack F Vogel 	/*
9168eb6488eSEric Joyner 	 * Initialize the shared code
917758cc3dcSJack F Vogel 	 */
918c19c7afeSEric Joyner 	if (ixgbe_init_shared_code(hw) != 0) {
9198eb6488eSEric Joyner 		device_printf(dev, "Unable to initialize the shared code\n");
9208eb6488eSEric Joyner 		error = ENXIO;
921c19c7afeSEric Joyner 		goto err_pci;
92230126537SJack F Vogel 	}
923758cc3dcSJack F Vogel 
9248b4a3fbdSKevin Bowling 	if (hw->mac.ops.fw_recovery_mode && hw->mac.ops.fw_recovery_mode(hw)) {
9258b4a3fbdSKevin Bowling 		device_printf(dev, "Firmware recovery mode detected. Limiting "
9268b4a3fbdSKevin Bowling 		    "functionality.\nRefer to the Intel(R) Ethernet Adapters "
9278b4a3fbdSKevin Bowling 		    "and Devices User Guide for details on firmware recovery "
9288b4a3fbdSKevin Bowling 		    "mode.");
9298b4a3fbdSKevin Bowling 		error = ENOSYS;
9308b4a3fbdSKevin Bowling 		goto err_pci;
9318b4a3fbdSKevin Bowling 	}
9328b4a3fbdSKevin Bowling 
9337234c309SJakub Chylkowski 	/* 82598 Does not support SR-IOV, initialize everything else */
9347234c309SJakub Chylkowski 	if (hw->mac.type >= ixgbe_mac_82599_vf) {
9357234c309SJakub Chylkowski 		for (i = 0; i < sc->num_vfs; i++)
9367234c309SJakub Chylkowski 			hw->mbx.ops[i].init_params(hw);
9377234c309SJakub Chylkowski 	}
938758cc3dcSJack F Vogel 
9398eb6488eSEric Joyner 	hw->allow_unsupported_sfp = allow_unsupported_sfp;
940758cc3dcSJack F Vogel 
941c19c7afeSEric Joyner 	if (hw->mac.type != ixgbe_mac_82598EB)
9428eb6488eSEric Joyner 		hw->phy.smart_speed = ixgbe_smart_speed;
9438eb6488eSEric Joyner 
944b1d5caf3SKevin Bowling 	ixgbe_init_device_features(sc);
9458eb6488eSEric Joyner 
9468eb6488eSEric Joyner 	/* Enable WoL (if supported) */
947b1d5caf3SKevin Bowling 	ixgbe_check_wol_support(sc);
9488eb6488eSEric Joyner 
9498eb6488eSEric Joyner 	/* Verify adapter fan is still functional (if applicable) */
950b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_FAN_FAIL) {
9518eb6488eSEric Joyner 		u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
952b1d5caf3SKevin Bowling 		ixgbe_check_fan_failure(sc, esdp, false);
9538eb6488eSEric Joyner 	}
9548eb6488eSEric Joyner 
9558eb6488eSEric Joyner 	/* Ensure SW/FW semaphore is free */
9568eb6488eSEric Joyner 	ixgbe_init_swfw_semaphore(hw);
9578eb6488eSEric Joyner 
9588eb6488eSEric Joyner 	/* Set an initial default flow control value */
9598eb6488eSEric Joyner 	hw->fc.requested_mode = ixgbe_flow_control;
9608eb6488eSEric Joyner 
96179b36ec9SKevin Bowling 	hw->phy.reset_if_overtemp = true;
9628eb6488eSEric Joyner 	error = ixgbe_reset_hw(hw);
96379b36ec9SKevin Bowling 	hw->phy.reset_if_overtemp = false;
9648eb6488eSEric Joyner 	if (error == IXGBE_ERR_SFP_NOT_PRESENT) {
965758cc3dcSJack F Vogel 		/*
9668eb6488eSEric Joyner 		 * No optics in this port, set up
9678eb6488eSEric Joyner 		 * so the timer routine will probe
9688eb6488eSEric Joyner 		 * for later insertion.
969758cc3dcSJack F Vogel 		 */
970b1d5caf3SKevin Bowling 		sc->sfp_probe = true;
971c19c7afeSEric Joyner 		error = 0;
9728eb6488eSEric Joyner 	} else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) {
9738eb6488eSEric Joyner 		device_printf(dev, "Unsupported SFP+ module detected!\n");
9748eb6488eSEric Joyner 		error = EIO;
975c19c7afeSEric Joyner 		goto err_pci;
9768eb6488eSEric Joyner 	} else if (error) {
9778eb6488eSEric Joyner 		device_printf(dev, "Hardware initialization failed\n");
9788eb6488eSEric Joyner 		error = EIO;
979c19c7afeSEric Joyner 		goto err_pci;
98097f9586eSSean Bruno 	}
98197f9586eSSean Bruno 
9828eb6488eSEric Joyner 	/* Make sure we have a good EEPROM before we read from it */
983b1d5caf3SKevin Bowling 	if (ixgbe_validate_eeprom_checksum(&sc->hw, NULL) < 0) {
9848eb6488eSEric Joyner 		device_printf(dev, "The EEPROM Checksum Is Not Valid\n");
9858eb6488eSEric Joyner 		error = EIO;
986c19c7afeSEric Joyner 		goto err_pci;
98797f9586eSSean Bruno 	}
98897f9586eSSean Bruno 
9898eb6488eSEric Joyner 	error = ixgbe_start_hw(hw);
9908eb6488eSEric Joyner 	switch (error) {
9918eb6488eSEric Joyner 	case IXGBE_ERR_EEPROM_VERSION:
9928eb6488eSEric Joyner 		device_printf(dev, "This device is a pre-production adapter/LOM.  Please be aware there may be issues associated with your hardware.\nIf you are experiencing problems please contact your Intel or hardware representative who provided you with this hardware.\n");
99397f9586eSSean Bruno 		break;
9948eb6488eSEric Joyner 	case IXGBE_ERR_SFP_NOT_SUPPORTED:
9958eb6488eSEric Joyner 		device_printf(dev, "Unsupported SFP+ Module\n");
9968eb6488eSEric Joyner 		error = EIO;
997c19c7afeSEric Joyner 		goto err_pci;
9988eb6488eSEric Joyner 	case IXGBE_ERR_SFP_NOT_PRESENT:
9998eb6488eSEric Joyner 		device_printf(dev, "No SFP+ Module found\n");
10008eb6488eSEric Joyner 		/* falls thru */
100197f9586eSSean Bruno 	default:
100297f9586eSSean Bruno 		break;
100397f9586eSSean Bruno 	}
100497f9586eSSean Bruno 
1005c19c7afeSEric Joyner 	/* Most of the iflib initialization... */
1006c19c7afeSEric Joyner 
1007c19c7afeSEric Joyner 	iflib_set_mac(ctx, hw->mac.addr);
1008b1d5caf3SKevin Bowling 	switch (sc->hw.mac.type) {
1009c19c7afeSEric Joyner 	case ixgbe_mac_X550:
1010c19c7afeSEric Joyner 	case ixgbe_mac_X550EM_x:
1011c19c7afeSEric Joyner 	case ixgbe_mac_X550EM_a:
1012c19c7afeSEric Joyner 		scctx->isc_rss_table_size = 512;
1013c19c7afeSEric Joyner 		scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 64;
1014c19c7afeSEric Joyner 		break;
1015c19c7afeSEric Joyner 	default:
1016c19c7afeSEric Joyner 		scctx->isc_rss_table_size = 128;
1017c19c7afeSEric Joyner 		scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 16;
1018c19c7afeSEric Joyner 	}
1019c19c7afeSEric Joyner 
1020c19c7afeSEric Joyner 	/* Allow legacy interrupts */
1021c19c7afeSEric Joyner 	ixgbe_txrx.ift_legacy_intr = ixgbe_intr;
1022c19c7afeSEric Joyner 
1023c19c7afeSEric Joyner 	scctx->isc_txqsizes[0] =
1024c19c7afeSEric Joyner 	    roundup2(scctx->isc_ntxd[0] * sizeof(union ixgbe_adv_tx_desc) +
1025c19c7afeSEric Joyner 	    sizeof(u32), DBA_ALIGN),
1026c19c7afeSEric Joyner 	scctx->isc_rxqsizes[0] =
1027c19c7afeSEric Joyner 	    roundup2(scctx->isc_nrxd[0] * sizeof(union ixgbe_adv_rx_desc),
1028c19c7afeSEric Joyner 	    DBA_ALIGN);
1029c19c7afeSEric Joyner 
1030c19c7afeSEric Joyner 	/* XXX */
1031c19c7afeSEric Joyner 	scctx->isc_tx_csum_flags = CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TSO |
1032c19c7afeSEric Joyner 	    CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_IP6_TSO;
1033b1d5caf3SKevin Bowling 	if (sc->hw.mac.type == ixgbe_mac_82598EB) {
1034c19c7afeSEric Joyner 		scctx->isc_tx_nsegments = IXGBE_82598_SCATTER;
1035c19c7afeSEric Joyner 	} else {
1036c19c7afeSEric Joyner 		scctx->isc_tx_csum_flags |= CSUM_SCTP |CSUM_IP6_SCTP;
1037c19c7afeSEric Joyner 		scctx->isc_tx_nsegments = IXGBE_82599_SCATTER;
1038c19c7afeSEric Joyner 	}
1039749597dcSEric Joyner 
1040749597dcSEric Joyner 	scctx->isc_msix_bar = pci_msix_table_bar(dev);
1041749597dcSEric Joyner 
1042c19c7afeSEric Joyner 	scctx->isc_tx_tso_segments_max = scctx->isc_tx_nsegments;
1043c19c7afeSEric Joyner 	scctx->isc_tx_tso_size_max = IXGBE_TSO_SIZE;
1044c19c7afeSEric Joyner 	scctx->isc_tx_tso_segsize_max = PAGE_SIZE;
1045c19c7afeSEric Joyner 
1046c19c7afeSEric Joyner 	scctx->isc_txrx = &ixgbe_txrx;
1047c19c7afeSEric Joyner 
10487f87c040SMarius Strobl 	scctx->isc_capabilities = scctx->isc_capenable = IXGBE_CAPS;
1049c19c7afeSEric Joyner 
1050c19c7afeSEric Joyner 	return (0);
1051c19c7afeSEric Joyner 
1052c19c7afeSEric Joyner err_pci:
1053b1d5caf3SKevin Bowling 	ctrl_ext = IXGBE_READ_REG(&sc->hw, IXGBE_CTRL_EXT);
1054c19c7afeSEric Joyner 	ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
1055b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(&sc->hw, IXGBE_CTRL_EXT, ctrl_ext);
1056c19c7afeSEric Joyner 	ixgbe_free_pci_resources(ctx);
1057c19c7afeSEric Joyner 
1058c19c7afeSEric Joyner 	return (error);
1059c19c7afeSEric Joyner } /* ixgbe_if_attach_pre */
1060c19c7afeSEric Joyner 
1061c19c7afeSEric Joyner  /*********************************************************************
1062c19c7afeSEric Joyner  * ixgbe_if_attach_post - Device initialization routine, part 2
1063c19c7afeSEric Joyner  *
1064c19c7afeSEric Joyner  *   Called during driver load, but after interrupts and
1065c19c7afeSEric Joyner  *   resources have been allocated and configured.
1066c19c7afeSEric Joyner  *   Sets up some data structures not relevant to iflib.
1067c19c7afeSEric Joyner  *
1068c19c7afeSEric Joyner  *   return 0 on success, positive on failure
1069c19c7afeSEric Joyner  *********************************************************************/
1070c19c7afeSEric Joyner static int
1071c19c7afeSEric Joyner ixgbe_if_attach_post(if_ctx_t ctx)
1072c19c7afeSEric Joyner {
1073c19c7afeSEric Joyner 	device_t dev;
1074b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc;
1075c19c7afeSEric Joyner 	struct ixgbe_hw *hw;
1076c19c7afeSEric Joyner 	int             error = 0;
1077c19c7afeSEric Joyner 
1078c19c7afeSEric Joyner 	dev = iflib_get_dev(ctx);
1079b1d5caf3SKevin Bowling 	sc = iflib_get_softc(ctx);
1080b1d5caf3SKevin Bowling 	hw = &sc->hw;
1081c19c7afeSEric Joyner 
1082c19c7afeSEric Joyner 
1083b1d5caf3SKevin Bowling 	if (sc->intr_type == IFLIB_INTR_LEGACY &&
1084b1d5caf3SKevin Bowling 		(sc->feat_cap & IXGBE_FEATURE_LEGACY_IRQ) == 0) {
1085c19c7afeSEric Joyner 		device_printf(dev, "Device does not support legacy interrupts");
1086c19c7afeSEric Joyner 		error = ENXIO;
1087c19c7afeSEric Joyner 		goto err;
1088c19c7afeSEric Joyner 	}
1089c19c7afeSEric Joyner 
1090c19c7afeSEric Joyner 	/* Allocate multicast array memory. */
1091b1d5caf3SKevin Bowling 	sc->mta = malloc(sizeof(*sc->mta) *
1092c19c7afeSEric Joyner 	                      MAX_NUM_MULTICAST_ADDRESSES, M_IXGBE, M_NOWAIT);
1093b1d5caf3SKevin Bowling 	if (sc->mta == NULL) {
1094c19c7afeSEric Joyner 		device_printf(dev, "Can not allocate multicast setup array\n");
1095c19c7afeSEric Joyner 		error = ENOMEM;
1096c19c7afeSEric Joyner 		goto err;
1097c19c7afeSEric Joyner 	}
1098c19c7afeSEric Joyner 
1099c19c7afeSEric Joyner 	/* hw.ix defaults init */
1100b1d5caf3SKevin Bowling 	ixgbe_set_advertise(sc, ixgbe_advertise_speed);
1101c19c7afeSEric Joyner 
11028eb6488eSEric Joyner 	/* Enable the optics for 82599 SFP+ fiber */
11038eb6488eSEric Joyner 	ixgbe_enable_tx_laser(hw);
1104758cc3dcSJack F Vogel 
11058eb6488eSEric Joyner 	/* Enable power to the phy. */
110679b36ec9SKevin Bowling 	ixgbe_set_phy_power(hw, true);
11078eb6488eSEric Joyner 
1108b1d5caf3SKevin Bowling 	ixgbe_initialize_iov(sc);
1109c19c7afeSEric Joyner 
1110c19c7afeSEric Joyner 	error = ixgbe_setup_interface(ctx);
1111c19c7afeSEric Joyner 	if (error) {
1112c19c7afeSEric Joyner 		device_printf(dev, "Interface setup failed: %d\n", error);
1113c19c7afeSEric Joyner 		goto err;
1114c19c7afeSEric Joyner 	}
1115c19c7afeSEric Joyner 
1116c19c7afeSEric Joyner 	ixgbe_if_update_admin_status(ctx);
1117c19c7afeSEric Joyner 
11188eb6488eSEric Joyner 	/* Initialize statistics */
1119b1d5caf3SKevin Bowling 	ixgbe_update_stats_counters(sc);
1120b1d5caf3SKevin Bowling 	ixgbe_add_hw_stats(sc);
11218eb6488eSEric Joyner 
11228eb6488eSEric Joyner 	/* Check PCIE slot type/speed/width */
1123b1d5caf3SKevin Bowling 	ixgbe_get_slot_info(sc);
1124758cc3dcSJack F Vogel 
1125758cc3dcSJack F Vogel 	/*
11268eb6488eSEric Joyner 	 * Do time init and sysctl init here, but
1127b1d5caf3SKevin Bowling 	 * only on the first port of a bypass sc.
1128758cc3dcSJack F Vogel 	 */
1129b1d5caf3SKevin Bowling 	ixgbe_bypass_init(sc);
1130758cc3dcSJack F Vogel 
11317660e4eaSKevin Bowling 	/* Display NVM and Option ROM versions */
11327660e4eaSKevin Bowling 	ixgbe_print_fw_version(ctx);
11337660e4eaSKevin Bowling 
11348eb6488eSEric Joyner 	/* Set an initial dmac value */
1135b1d5caf3SKevin Bowling 	sc->dmac = 0;
11368eb6488eSEric Joyner 	/* Set initial advertised speeds (if applicable) */
1137d381c807SPiotr Pietruszewski 	sc->advertise = ixgbe_get_default_advertise(sc);
1138758cc3dcSJack F Vogel 
1139b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_SRIOV)
11408eb6488eSEric Joyner 		ixgbe_define_iov_schemas(dev, &error);
1141758cc3dcSJack F Vogel 
11428eb6488eSEric Joyner 	/* Add sysctls */
1143c19c7afeSEric Joyner 	ixgbe_add_device_sysctls(ctx);
1144758cc3dcSJack F Vogel 
1145f72de14eSKevin Bowling 	/* Init recovery mode timer and state variable */
1146f72de14eSKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_RECOVERY_MODE) {
1147f72de14eSKevin Bowling 		sc->recovery_mode = 0;
1148f72de14eSKevin Bowling 
1149f72de14eSKevin Bowling 		/* Set up the timer callout */
1150f72de14eSKevin Bowling 		callout_init(&sc->fw_mode_timer, true);
1151f72de14eSKevin Bowling 
1152f72de14eSKevin Bowling 		/* Start the task */
1153a924b5eeSKevin Bowling 		callout_reset(&sc->fw_mode_timer, hz, ixgbe_fw_mode_timer, sc);
1154f72de14eSKevin Bowling 	}
1155f72de14eSKevin Bowling 
11568eb6488eSEric Joyner 	return (0);
1157c19c7afeSEric Joyner err:
11588eb6488eSEric Joyner 	return (error);
1159c19c7afeSEric Joyner } /* ixgbe_if_attach_post */
11608eb6488eSEric Joyner 
11618eb6488eSEric Joyner /************************************************************************
11628eb6488eSEric Joyner  * ixgbe_check_wol_support
11636f37f232SEric Joyner  *
11646f37f232SEric Joyner  *   Checks whether the adapter's ports are capable of
11656f37f232SEric Joyner  *   Wake On LAN by reading the adapter's NVM.
11666f37f232SEric Joyner  *
11676f37f232SEric Joyner  *   Sets each port's hw->wol_enabled value depending
11686f37f232SEric Joyner  *   on the value read here.
11698eb6488eSEric Joyner  ************************************************************************/
11706f37f232SEric Joyner static void
1171b1d5caf3SKevin Bowling ixgbe_check_wol_support(struct ixgbe_softc *sc)
11726f37f232SEric Joyner {
1173b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
11746f37f232SEric Joyner 	u16             dev_caps = 0;
11756f37f232SEric Joyner 
11766f37f232SEric Joyner 	/* Find out WoL support for port */
1177b1d5caf3SKevin Bowling 	sc->wol_support = hw->wol_enabled = 0;
11786f37f232SEric Joyner 	ixgbe_get_device_caps(hw, &dev_caps);
11796f37f232SEric Joyner 	if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
11806f37f232SEric Joyner 	    ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) &&
11816f37f232SEric Joyner 	     hw->bus.func == 0))
1182b1d5caf3SKevin Bowling 		sc->wol_support = hw->wol_enabled = 1;
11836f37f232SEric Joyner 
11846f37f232SEric Joyner 	/* Save initial wake up filter configuration */
1185b1d5caf3SKevin Bowling 	sc->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC);
11866f37f232SEric Joyner 
11876f37f232SEric Joyner 	return;
11888eb6488eSEric Joyner } /* ixgbe_check_wol_support */
11896f37f232SEric Joyner 
11908eb6488eSEric Joyner /************************************************************************
11918eb6488eSEric Joyner  * ixgbe_setup_interface
11928eb6488eSEric Joyner  *
11938eb6488eSEric Joyner  *   Setup networking device structure and register an interface.
11948eb6488eSEric Joyner  ************************************************************************/
11956f37f232SEric Joyner static int
1196c19c7afeSEric Joyner ixgbe_setup_interface(if_ctx_t ctx)
11976f37f232SEric Joyner {
1198ff06a8dbSJustin Hibbits 	if_t               ifp = iflib_get_ifp(ctx);
1199b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
12006f37f232SEric Joyner 
12018eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_setup_interface: begin");
12026f37f232SEric Joyner 
1203c19c7afeSEric Joyner 	if_setbaudrate(ifp, IF_Gbps(10));
12046f37f232SEric Joyner 
1205ff06a8dbSJustin Hibbits 	sc->max_frame_size = if_getmtu(ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN;
1206758cc3dcSJack F Vogel 
1207b1d5caf3SKevin Bowling 	sc->phy_layer = ixgbe_get_supported_physical_layer(&sc->hw);
12088eb6488eSEric Joyner 
1209c19c7afeSEric Joyner 	ixgbe_add_media_types(ctx);
1210c19c7afeSEric Joyner 
1211c19c7afeSEric Joyner 	/* Autoselect media by default */
1212b1d5caf3SKevin Bowling 	ifmedia_set(sc->media, IFM_ETHER | IFM_AUTO);
12138eb6488eSEric Joyner 
12148eb6488eSEric Joyner 	return (0);
12158eb6488eSEric Joyner } /* ixgbe_setup_interface */
1216758cc3dcSJack F Vogel 
12178eb6488eSEric Joyner /************************************************************************
1218c19c7afeSEric Joyner  * ixgbe_if_get_counter
12198eb6488eSEric Joyner  ************************************************************************/
1220758cc3dcSJack F Vogel static uint64_t
1221c19c7afeSEric Joyner ixgbe_if_get_counter(if_ctx_t ctx, ift_counter cnt)
1222758cc3dcSJack F Vogel {
1223b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
1224c19c7afeSEric Joyner 	if_t           ifp = iflib_get_ifp(ctx);
1225758cc3dcSJack F Vogel 
1226758cc3dcSJack F Vogel 	switch (cnt) {
1227758cc3dcSJack F Vogel 	case IFCOUNTER_IPACKETS:
1228b1d5caf3SKevin Bowling 		return (sc->ipackets);
1229758cc3dcSJack F Vogel 	case IFCOUNTER_OPACKETS:
1230b1d5caf3SKevin Bowling 		return (sc->opackets);
1231758cc3dcSJack F Vogel 	case IFCOUNTER_IBYTES:
1232b1d5caf3SKevin Bowling 		return (sc->ibytes);
1233758cc3dcSJack F Vogel 	case IFCOUNTER_OBYTES:
1234b1d5caf3SKevin Bowling 		return (sc->obytes);
1235758cc3dcSJack F Vogel 	case IFCOUNTER_IMCASTS:
1236b1d5caf3SKevin Bowling 		return (sc->imcasts);
1237758cc3dcSJack F Vogel 	case IFCOUNTER_OMCASTS:
1238b1d5caf3SKevin Bowling 		return (sc->omcasts);
1239758cc3dcSJack F Vogel 	case IFCOUNTER_COLLISIONS:
1240758cc3dcSJack F Vogel 		return (0);
1241758cc3dcSJack F Vogel 	case IFCOUNTER_IQDROPS:
1242b1d5caf3SKevin Bowling 		return (sc->iqdrops);
1243625d12c6SJohn Baldwin 	case IFCOUNTER_OQDROPS:
1244c19c7afeSEric Joyner 		return (0);
1245758cc3dcSJack F Vogel 	case IFCOUNTER_IERRORS:
1246b1d5caf3SKevin Bowling 		return (sc->ierrors);
1247758cc3dcSJack F Vogel 	default:
1248758cc3dcSJack F Vogel 		return (if_get_counter_default(ifp, cnt));
1249758cc3dcSJack F Vogel 	}
1250c19c7afeSEric Joyner } /* ixgbe_if_get_counter */
1251758cc3dcSJack F Vogel 
12528eb6488eSEric Joyner /************************************************************************
1253bca38080SAndrew Gallatin  * ixgbe_if_i2c_req
1254bca38080SAndrew Gallatin  ************************************************************************/
1255bca38080SAndrew Gallatin static int
1256bca38080SAndrew Gallatin ixgbe_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req)
1257bca38080SAndrew Gallatin {
1258b1d5caf3SKevin Bowling 	struct ixgbe_softc		*sc = iflib_get_softc(ctx);
1259b1d5caf3SKevin Bowling 	struct ixgbe_hw 	*hw = &sc->hw;
1260bca38080SAndrew Gallatin 	int 			i;
1261bca38080SAndrew Gallatin 
1262bca38080SAndrew Gallatin 
1263bca38080SAndrew Gallatin 	if (hw->phy.ops.read_i2c_byte == NULL)
1264bca38080SAndrew Gallatin 		return (ENXIO);
1265bca38080SAndrew Gallatin 	for (i = 0; i < req->len; i++)
1266bca38080SAndrew Gallatin 		hw->phy.ops.read_i2c_byte(hw, req->offset + i,
1267bca38080SAndrew Gallatin 		    req->dev_addr, &req->data[i]);
1268bca38080SAndrew Gallatin 	return (0);
1269bca38080SAndrew Gallatin } /* ixgbe_if_i2c_req */
1270bca38080SAndrew Gallatin 
1271cf150917SEric Joyner /* ixgbe_if_needs_restart - Tell iflib when the driver needs to be reinitialized
1272cf150917SEric Joyner  * @ctx: iflib context
1273cf150917SEric Joyner  * @event: event code to check
1274cf150917SEric Joyner  *
1275725e4008SKevin Bowling  * Defaults to returning false for unknown events.
1276cf150917SEric Joyner  *
1277cf150917SEric Joyner  * @returns true if iflib needs to reinit the interface
1278cf150917SEric Joyner  */
1279cf150917SEric Joyner static bool
1280cf150917SEric Joyner ixgbe_if_needs_restart(if_ctx_t ctx __unused, enum iflib_restart_event event)
1281cf150917SEric Joyner {
1282cf150917SEric Joyner 	switch (event) {
1283cf150917SEric Joyner 	case IFLIB_RESTART_VLAN_CONFIG:
1284cf150917SEric Joyner 	default:
1285725e4008SKevin Bowling 		return (false);
1286cf150917SEric Joyner 	}
1287cf150917SEric Joyner }
1288cf150917SEric Joyner 
1289bca38080SAndrew Gallatin /************************************************************************
12908eb6488eSEric Joyner  * ixgbe_add_media_types
12918eb6488eSEric Joyner  ************************************************************************/
12928eb6488eSEric Joyner static void
1293c19c7afeSEric Joyner ixgbe_add_media_types(if_ctx_t ctx)
12948eb6488eSEric Joyner {
1295b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = iflib_get_softc(ctx);
1296b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
1297c19c7afeSEric Joyner 	device_t        dev = iflib_get_dev(ctx);
12988eb6488eSEric Joyner 	u64             layer;
12998eb6488eSEric Joyner 
1300b1d5caf3SKevin Bowling 	layer = sc->phy_layer = ixgbe_get_supported_physical_layer(hw);
13018eb6488eSEric Joyner 
13028eb6488eSEric Joyner 	/* Media types with matching FreeBSD media defines */
13038eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T)
1304b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_T, 0, NULL);
13058eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T)
1306b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_T, 0, NULL);
13078eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX)
1308b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_100_TX, 0, NULL);
13098eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10BASE_T)
1310b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10_T, 0, NULL);
13118eb6488eSEric Joyner 
1312d381c807SPiotr Pietruszewski 	if (hw->mac.type == ixgbe_mac_X550) {
1313d381c807SPiotr Pietruszewski 		ifmedia_add(sc->media, IFM_ETHER | IFM_2500_T, 0, NULL);
1314d381c807SPiotr Pietruszewski 		ifmedia_add(sc->media, IFM_ETHER | IFM_5000_T, 0, NULL);
1315d381c807SPiotr Pietruszewski 	}
1316d381c807SPiotr Pietruszewski 
13178eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU ||
1318*48ddd1b9SKevin Bowling 	    layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) {
1319b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_TWINAX, 0,
13208eb6488eSEric Joyner 		    NULL);
1321*48ddd1b9SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_KX, 0, NULL);
1322*48ddd1b9SKevin Bowling 	}
13238eb6488eSEric Joyner 
13248eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) {
1325b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
13268eb6488eSEric Joyner 		if (hw->phy.multispeed_fiber)
1327b1d5caf3SKevin Bowling 			ifmedia_add(sc->media, IFM_ETHER | IFM_1000_LX, 0,
13288eb6488eSEric Joyner 			    NULL);
13298eb6488eSEric Joyner 	}
13308eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) {
1331b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
13328eb6488eSEric Joyner 		if (hw->phy.multispeed_fiber)
1333b1d5caf3SKevin Bowling 			ifmedia_add(sc->media, IFM_ETHER | IFM_1000_SX, 0,
13348eb6488eSEric Joyner 			    NULL);
13358eb6488eSEric Joyner 	} else if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX)
1336b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
13378eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4)
1338b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
13398eb6488eSEric Joyner 
13408eb6488eSEric Joyner #ifdef IFM_ETH_XTYPE
13418eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR)
1342b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_KR, 0, NULL);
13438eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4)
1344b1d5caf3SKevin Bowling 		ifmedia_add( sc->media, IFM_ETHER | IFM_10G_KX4, 0, NULL);
13458eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX)
1346b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_KX, 0, NULL);
13478eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX)
1348b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_2500_KX, 0, NULL);
13498eb6488eSEric Joyner #else
13508eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) {
13518eb6488eSEric Joyner 		device_printf(dev, "Media supported: 10GbaseKR\n");
13528eb6488eSEric Joyner 		device_printf(dev, "10GbaseKR mapped to 10GbaseSR\n");
1353b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
13548eb6488eSEric Joyner 	}
13558eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) {
13568eb6488eSEric Joyner 		device_printf(dev, "Media supported: 10GbaseKX4\n");
13578eb6488eSEric Joyner 		device_printf(dev, "10GbaseKX4 mapped to 10GbaseCX4\n");
1358b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
13598eb6488eSEric Joyner 	}
13608eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) {
13618eb6488eSEric Joyner 		device_printf(dev, "Media supported: 1000baseKX\n");
13628eb6488eSEric Joyner 		device_printf(dev, "1000baseKX mapped to 1000baseCX\n");
1363b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_CX, 0, NULL);
13648eb6488eSEric Joyner 	}
13658eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX) {
13668eb6488eSEric Joyner 		device_printf(dev, "Media supported: 2500baseKX\n");
13678eb6488eSEric Joyner 		device_printf(dev, "2500baseKX mapped to 2500baseSX\n");
1368b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_2500_SX, 0, NULL);
13698eb6488eSEric Joyner 	}
13708eb6488eSEric Joyner #endif
13718eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX)
13728eb6488eSEric Joyner 		device_printf(dev, "Media supported: 1000baseBX\n");
13738eb6488eSEric Joyner 
13748eb6488eSEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_82598AT) {
1375b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
13768eb6488eSEric Joyner 		    0, NULL);
1377b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_T, 0, NULL);
13788eb6488eSEric Joyner 	}
13798eb6488eSEric Joyner 
1380b1d5caf3SKevin Bowling 	ifmedia_add(sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
13818eb6488eSEric Joyner } /* ixgbe_add_media_types */
13828eb6488eSEric Joyner 
13838eb6488eSEric Joyner /************************************************************************
13848eb6488eSEric Joyner  * ixgbe_is_sfp
13858eb6488eSEric Joyner  ************************************************************************/
13868eb6488eSEric Joyner static inline bool
13878eb6488eSEric Joyner ixgbe_is_sfp(struct ixgbe_hw *hw)
13888eb6488eSEric Joyner {
13898eb6488eSEric Joyner 	switch (hw->mac.type) {
13908eb6488eSEric Joyner 	case ixgbe_mac_82598EB:
13918eb6488eSEric Joyner 		if (hw->phy.type == ixgbe_phy_nl)
139279b36ec9SKevin Bowling 			return (true);
139379b36ec9SKevin Bowling 		return (false);
13948eb6488eSEric Joyner 	case ixgbe_mac_82599EB:
13958eb6488eSEric Joyner 		switch (hw->mac.ops.get_media_type(hw)) {
13968eb6488eSEric Joyner 		case ixgbe_media_type_fiber:
13978eb6488eSEric Joyner 		case ixgbe_media_type_fiber_qsfp:
139879b36ec9SKevin Bowling 			return (true);
13998eb6488eSEric Joyner 		default:
140079b36ec9SKevin Bowling 			return (false);
14018eb6488eSEric Joyner 		}
14028eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
14038eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
14048eb6488eSEric Joyner 		if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber)
140579b36ec9SKevin Bowling 			return (true);
140679b36ec9SKevin Bowling 		return (false);
14078eb6488eSEric Joyner 	default:
140879b36ec9SKevin Bowling 		return (false);
14098eb6488eSEric Joyner 	}
14108eb6488eSEric Joyner } /* ixgbe_is_sfp */
14118eb6488eSEric Joyner 
14128eb6488eSEric Joyner /************************************************************************
14138eb6488eSEric Joyner  * ixgbe_config_link
14148eb6488eSEric Joyner  ************************************************************************/
14158eb6488eSEric Joyner static void
1416b2c1e8e6SEric Joyner ixgbe_config_link(if_ctx_t ctx)
14178eb6488eSEric Joyner {
1418b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = iflib_get_softc(ctx);
1419b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
14208eb6488eSEric Joyner 	u32             autoneg, err = 0;
14218eb6488eSEric Joyner 	bool            sfp, negotiate;
14228eb6488eSEric Joyner 
14238eb6488eSEric Joyner 	sfp = ixgbe_is_sfp(hw);
14248eb6488eSEric Joyner 
14258eb6488eSEric Joyner 	if (sfp) {
1426b1d5caf3SKevin Bowling 		sc->task_requests |= IXGBE_REQUEST_TASK_MOD;
1427b2c1e8e6SEric Joyner 		iflib_admin_intr_deferred(ctx);
14288eb6488eSEric Joyner 	} else {
14298eb6488eSEric Joyner 		if (hw->mac.ops.check_link)
1430b1d5caf3SKevin Bowling 			err = ixgbe_check_link(hw, &sc->link_speed,
1431b1d5caf3SKevin Bowling 			    &sc->link_up, false);
14328eb6488eSEric Joyner 		if (err)
1433c19c7afeSEric Joyner 			return;
14348eb6488eSEric Joyner 		autoneg = hw->phy.autoneg_advertised;
14358eb6488eSEric Joyner 		if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
14368eb6488eSEric Joyner 			err = hw->mac.ops.get_link_capabilities(hw, &autoneg,
14378eb6488eSEric Joyner 			    &negotiate);
14388eb6488eSEric Joyner 		if (err)
1439c19c7afeSEric Joyner 			return;
1440d381c807SPiotr Pietruszewski 
1441d381c807SPiotr Pietruszewski 		if (hw->mac.type == ixgbe_mac_X550 &&
1442d381c807SPiotr Pietruszewski 		    hw->phy.autoneg_advertised == 0) {
1443d381c807SPiotr Pietruszewski 			/*
1444d381c807SPiotr Pietruszewski 			 * 2.5G and 5G autonegotiation speeds on X550
1445d381c807SPiotr Pietruszewski 			 * are disabled by default due to reported
1446d381c807SPiotr Pietruszewski 			 * interoperability issues with some switches.
1447d381c807SPiotr Pietruszewski 			 *
1448d381c807SPiotr Pietruszewski 			 * The second condition checks if any operations
1449d381c807SPiotr Pietruszewski 			 * involving setting autonegotiation speeds have
1450d381c807SPiotr Pietruszewski 			 * been performed prior to this ixgbe_config_link()
1451d381c807SPiotr Pietruszewski 			 * call.
1452d381c807SPiotr Pietruszewski 			 *
1453d381c807SPiotr Pietruszewski 			 * If hw->phy.autoneg_advertised does not
1454d381c807SPiotr Pietruszewski 			 * equal 0, this means that the user might have
1455d381c807SPiotr Pietruszewski 			 * set autonegotiation speeds via the sysctl
1456d381c807SPiotr Pietruszewski 			 * before bringing the interface up. In this
1457d381c807SPiotr Pietruszewski 			 * case, we should not disable 2.5G and 5G
1458d381c807SPiotr Pietruszewski 			 * since that speeds might be selected by the
1459d381c807SPiotr Pietruszewski 			 * user.
1460d381c807SPiotr Pietruszewski 			 *
1461d381c807SPiotr Pietruszewski 			 * Otherwise (i.e. if hw->phy.autoneg_advertised
1462d381c807SPiotr Pietruszewski 			 * is set to 0), it is the first time we set
1463d381c807SPiotr Pietruszewski 			 * autonegotiation preferences and the default
1464d381c807SPiotr Pietruszewski 			 * set of speeds should exclude 2.5G and 5G.
1465d381c807SPiotr Pietruszewski 			 */
1466d381c807SPiotr Pietruszewski 			autoneg &= ~(IXGBE_LINK_SPEED_2_5GB_FULL |
1467d381c807SPiotr Pietruszewski 			    IXGBE_LINK_SPEED_5GB_FULL);
1468d381c807SPiotr Pietruszewski 		}
1469d381c807SPiotr Pietruszewski 
14708eb6488eSEric Joyner 		if (hw->mac.ops.setup_link)
14718eb6488eSEric Joyner 			err = hw->mac.ops.setup_link(hw, autoneg,
1472b1d5caf3SKevin Bowling 			    sc->link_up);
14738eb6488eSEric Joyner 	}
14748eb6488eSEric Joyner } /* ixgbe_config_link */
14758eb6488eSEric Joyner 
14768eb6488eSEric Joyner /************************************************************************
14778eb6488eSEric Joyner  * ixgbe_update_stats_counters - Update board statistics counters.
14788eb6488eSEric Joyner  ************************************************************************/
14798eb6488eSEric Joyner static void
1480b1d5caf3SKevin Bowling ixgbe_update_stats_counters(struct ixgbe_softc *sc)
14818eb6488eSEric Joyner {
1482b1d5caf3SKevin Bowling 	struct ixgbe_hw       *hw = &sc->hw;
1483b1d5caf3SKevin Bowling 	struct ixgbe_hw_stats *stats = &sc->stats.pf;
14848eb6488eSEric Joyner 	u32                   missed_rx = 0, bprc, lxon, lxoff, total;
1485e37d3dc1SEric Joyner 	u32                   lxoffrxc;
14868eb6488eSEric Joyner 	u64                   total_missed_rx = 0;
14878eb6488eSEric Joyner 
14888eb6488eSEric Joyner 	stats->crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
14898eb6488eSEric Joyner 	stats->illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC);
14908eb6488eSEric Joyner 	stats->errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC);
14918eb6488eSEric Joyner 	stats->mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC);
14928eb6488eSEric Joyner 	stats->mpc[0] += IXGBE_READ_REG(hw, IXGBE_MPC(0));
14938eb6488eSEric Joyner 
14948eb6488eSEric Joyner 	for (int i = 0; i < 16; i++) {
14958eb6488eSEric Joyner 		stats->qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
14968eb6488eSEric Joyner 		stats->qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
14978eb6488eSEric Joyner 		stats->qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
14988eb6488eSEric Joyner 	}
14998eb6488eSEric Joyner 	stats->mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC);
15008eb6488eSEric Joyner 	stats->mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC);
15018eb6488eSEric Joyner 	stats->rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
15028eb6488eSEric Joyner 
15038eb6488eSEric Joyner 	/* Hardware workaround, gprc counts missed packets */
15048eb6488eSEric Joyner 	stats->gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
15058eb6488eSEric Joyner 	stats->gprc -= missed_rx;
15068eb6488eSEric Joyner 
15078eb6488eSEric Joyner 	if (hw->mac.type != ixgbe_mac_82598EB) {
15088eb6488eSEric Joyner 		stats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) +
15098eb6488eSEric Joyner 		    ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32);
15108eb6488eSEric Joyner 		stats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) +
15118eb6488eSEric Joyner 		    ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32);
15128eb6488eSEric Joyner 		stats->tor += IXGBE_READ_REG(hw, IXGBE_TORL) +
15138eb6488eSEric Joyner 		    ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32);
15148eb6488eSEric Joyner 		stats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
1515e37d3dc1SEric Joyner 		lxoffrxc = IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
1516e37d3dc1SEric Joyner 		stats->lxoffrxc += lxoffrxc;
15178eb6488eSEric Joyner 	} else {
15188eb6488eSEric Joyner 		stats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
1519e37d3dc1SEric Joyner 		lxoffrxc = IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
1520e37d3dc1SEric Joyner 		stats->lxoffrxc += lxoffrxc;
15218eb6488eSEric Joyner 		/* 82598 only has a counter in the high register */
15228eb6488eSEric Joyner 		stats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
15238eb6488eSEric Joyner 		stats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
15248eb6488eSEric Joyner 		stats->tor += IXGBE_READ_REG(hw, IXGBE_TORH);
15258eb6488eSEric Joyner 	}
15268eb6488eSEric Joyner 
15278eb6488eSEric Joyner 	/*
1528e37d3dc1SEric Joyner 	 * For watchdog management we need to know if we have been paused
1529e37d3dc1SEric Joyner 	 * during the last interval, so capture that here.
1530e37d3dc1SEric Joyner 	*/
1531e37d3dc1SEric Joyner 	if (lxoffrxc)
1532b1d5caf3SKevin Bowling 		sc->shared->isc_pause_frames = 1;
1533e37d3dc1SEric Joyner 
1534e37d3dc1SEric Joyner 	/*
15358eb6488eSEric Joyner 	 * Workaround: mprc hardware is incorrectly counting
15368eb6488eSEric Joyner 	 * broadcasts, so for now we subtract those.
1537758cc3dcSJack F Vogel 	 */
15388eb6488eSEric Joyner 	bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
15398eb6488eSEric Joyner 	stats->bprc += bprc;
15408eb6488eSEric Joyner 	stats->mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
15418eb6488eSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB)
15428eb6488eSEric Joyner 		stats->mprc -= bprc;
15438eb6488eSEric Joyner 
15448eb6488eSEric Joyner 	stats->prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
15458eb6488eSEric Joyner 	stats->prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
15468eb6488eSEric Joyner 	stats->prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255);
15478eb6488eSEric Joyner 	stats->prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
15488eb6488eSEric Joyner 	stats->prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
15498eb6488eSEric Joyner 	stats->prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
15508eb6488eSEric Joyner 
15518eb6488eSEric Joyner 	lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC);
15528eb6488eSEric Joyner 	stats->lxontxc += lxon;
15538eb6488eSEric Joyner 	lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
15548eb6488eSEric Joyner 	stats->lxofftxc += lxoff;
15558eb6488eSEric Joyner 	total = lxon + lxoff;
15568eb6488eSEric Joyner 
15578eb6488eSEric Joyner 	stats->gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
15588eb6488eSEric Joyner 	stats->mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
15598eb6488eSEric Joyner 	stats->ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
15608eb6488eSEric Joyner 	stats->gptc -= total;
15618eb6488eSEric Joyner 	stats->mptc -= total;
15628eb6488eSEric Joyner 	stats->ptc64 -= total;
15638eb6488eSEric Joyner 	stats->gotc -= total * ETHER_MIN_LEN;
15648eb6488eSEric Joyner 
15658eb6488eSEric Joyner 	stats->ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
15668eb6488eSEric Joyner 	stats->rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
15678eb6488eSEric Joyner 	stats->roc += IXGBE_READ_REG(hw, IXGBE_ROC);
15688eb6488eSEric Joyner 	stats->rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
15698eb6488eSEric Joyner 	stats->mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC);
15708eb6488eSEric Joyner 	stats->mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC);
15718eb6488eSEric Joyner 	stats->mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC);
15728eb6488eSEric Joyner 	stats->tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
15738eb6488eSEric Joyner 	stats->tpt += IXGBE_READ_REG(hw, IXGBE_TPT);
15748eb6488eSEric Joyner 	stats->ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
15758eb6488eSEric Joyner 	stats->ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
15768eb6488eSEric Joyner 	stats->ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
15778eb6488eSEric Joyner 	stats->ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
15788eb6488eSEric Joyner 	stats->ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
15798eb6488eSEric Joyner 	stats->bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
15808eb6488eSEric Joyner 	stats->xec += IXGBE_READ_REG(hw, IXGBE_XEC);
15818eb6488eSEric Joyner 	stats->fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC);
15828eb6488eSEric Joyner 	stats->fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST);
15838eb6488eSEric Joyner 	/* Only read FCOE on 82599 */
15848eb6488eSEric Joyner 	if (hw->mac.type != ixgbe_mac_82598EB) {
15858eb6488eSEric Joyner 		stats->fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC);
15868eb6488eSEric Joyner 		stats->fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC);
15878eb6488eSEric Joyner 		stats->fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC);
15888eb6488eSEric Joyner 		stats->fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC);
15898eb6488eSEric Joyner 		stats->fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC);
15908eb6488eSEric Joyner 	}
15918eb6488eSEric Joyner 
15928eb6488eSEric Joyner 	/* Fill out the OS statistics structure */
1593b1d5caf3SKevin Bowling 	IXGBE_SET_IPACKETS(sc, stats->gprc);
1594b1d5caf3SKevin Bowling 	IXGBE_SET_OPACKETS(sc, stats->gptc);
1595b1d5caf3SKevin Bowling 	IXGBE_SET_IBYTES(sc, stats->gorc);
1596b1d5caf3SKevin Bowling 	IXGBE_SET_OBYTES(sc, stats->gotc);
1597b1d5caf3SKevin Bowling 	IXGBE_SET_IMCASTS(sc, stats->mprc);
1598b1d5caf3SKevin Bowling 	IXGBE_SET_OMCASTS(sc, stats->mptc);
1599b1d5caf3SKevin Bowling 	IXGBE_SET_COLLISIONS(sc, 0);
1600b1d5caf3SKevin Bowling 	IXGBE_SET_IQDROPS(sc, total_missed_rx);
1601afb1aa4eSPiotr Pietruszewski 
1602afb1aa4eSPiotr Pietruszewski 	/*
1603afb1aa4eSPiotr Pietruszewski 	 * Aggregate following types of errors as RX errors:
1604afb1aa4eSPiotr Pietruszewski 	 * - CRC error count,
1605afb1aa4eSPiotr Pietruszewski 	 * - illegal byte error count,
1606afb1aa4eSPiotr Pietruszewski 	 * - missed packets count,
1607afb1aa4eSPiotr Pietruszewski 	 * - length error count,
1608afb1aa4eSPiotr Pietruszewski 	 * - undersized packets count,
1609afb1aa4eSPiotr Pietruszewski 	 * - fragmented packets count,
1610afb1aa4eSPiotr Pietruszewski 	 * - oversized packets count,
1611afb1aa4eSPiotr Pietruszewski 	 * - jabber count.
1612afb1aa4eSPiotr Pietruszewski 	 */
16138526120aSAndrey V. Elsukov 	IXGBE_SET_IERRORS(sc, stats->crcerrs + stats->illerrc +
1614afb1aa4eSPiotr Pietruszewski 	    stats->mpc[0] + stats->rlec + stats->ruc + stats->rfc + stats->roc +
1615afb1aa4eSPiotr Pietruszewski 	    stats->rjc);
16168eb6488eSEric Joyner } /* ixgbe_update_stats_counters */
16178eb6488eSEric Joyner 
16188eb6488eSEric Joyner /************************************************************************
16198eb6488eSEric Joyner  * ixgbe_add_hw_stats
16208eb6488eSEric Joyner  *
16218eb6488eSEric Joyner  *   Add sysctl variables, one per statistic, to the system.
16228eb6488eSEric Joyner  ************************************************************************/
16238eb6488eSEric Joyner static void
1624b1d5caf3SKevin Bowling ixgbe_add_hw_stats(struct ixgbe_softc *sc)
16258eb6488eSEric Joyner {
1626b1d5caf3SKevin Bowling 	device_t               dev = iflib_get_dev(sc->ctx);
1627c19c7afeSEric Joyner 	struct ix_rx_queue     *rx_que;
1628c19c7afeSEric Joyner 	struct ix_tx_queue     *tx_que;
16298eb6488eSEric Joyner 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
16308eb6488eSEric Joyner 	struct sysctl_oid      *tree = device_get_sysctl_tree(dev);
16318eb6488eSEric Joyner 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
1632b1d5caf3SKevin Bowling 	struct ixgbe_hw_stats  *stats = &sc->stats.pf;
16338eb6488eSEric Joyner 	struct sysctl_oid      *stat_node, *queue_node;
16348eb6488eSEric Joyner 	struct sysctl_oid_list *stat_list, *queue_list;
1635c19c7afeSEric Joyner 	int                    i;
16368eb6488eSEric Joyner 
16378eb6488eSEric Joyner #define QUEUE_NAME_LEN 32
16388eb6488eSEric Joyner 	char                   namebuf[QUEUE_NAME_LEN];
16398eb6488eSEric Joyner 
16408eb6488eSEric Joyner 	/* Driver Statistics */
16418eb6488eSEric Joyner 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped",
1642b1d5caf3SKevin Bowling 	    CTLFLAG_RD, &sc->dropped_pkts, "Driver dropped packets");
16438eb6488eSEric Joyner 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
1644b1d5caf3SKevin Bowling 	    CTLFLAG_RD, &sc->watchdog_events, "Watchdog timeouts");
16458eb6488eSEric Joyner 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq",
1646b1d5caf3SKevin Bowling 	    CTLFLAG_RD, &sc->link_irq, "Link MSI-X IRQ Handled");
16478eb6488eSEric Joyner 
1648b1d5caf3SKevin Bowling 	for (i = 0, tx_que = sc->tx_queues; i < sc->num_tx_queues; i++, tx_que++) {
1649c19c7afeSEric Joyner 		struct tx_ring *txr = &tx_que->txr;
16508eb6488eSEric Joyner 		snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i);
16518eb6488eSEric Joyner 		queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
165220b91f0aSPawel Biernacki 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
16538eb6488eSEric Joyner 		queue_list = SYSCTL_CHILDREN(queue_node);
16548eb6488eSEric Joyner 
16558eb6488eSEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head",
1656f72de14eSKevin Bowling 		    CTLTYPE_UINT | CTLFLAG_RD, txr, 0,
16578eb6488eSEric Joyner 		    ixgbe_sysctl_tdh_handler, "IU", "Transmit Descriptor Head");
16588eb6488eSEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail",
1659f72de14eSKevin Bowling 		    CTLTYPE_UINT | CTLFLAG_RD, txr, 0,
16608eb6488eSEric Joyner 		    ixgbe_sysctl_tdt_handler, "IU", "Transmit Descriptor Tail");
16618eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
16628eb6488eSEric Joyner 		    CTLFLAG_RD, &txr->tso_tx, "TSO");
16638eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
16648eb6488eSEric Joyner 		    CTLFLAG_RD, &txr->total_packets,
16658eb6488eSEric Joyner 		    "Queue Packets Transmitted");
16668eb6488eSEric Joyner 	}
16678eb6488eSEric Joyner 
1668b1d5caf3SKevin Bowling 	for (i = 0, rx_que = sc->rx_queues; i < sc->num_rx_queues; i++, rx_que++) {
1669c19c7afeSEric Joyner 		struct rx_ring *rxr = &rx_que->rxr;
16708eb6488eSEric Joyner 		snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i);
16718eb6488eSEric Joyner 		queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
167220b91f0aSPawel Biernacki 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
16738eb6488eSEric Joyner 		queue_list = SYSCTL_CHILDREN(queue_node);
16748eb6488eSEric Joyner 
1675c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate",
1676f72de14eSKevin Bowling 		    CTLTYPE_UINT | CTLFLAG_RW,
1677b1d5caf3SKevin Bowling 		    &sc->rx_queues[i], 0,
1678c19c7afeSEric Joyner 		    ixgbe_sysctl_interrupt_rate_handler, "IU",
1679c19c7afeSEric Joyner 		    "Interrupt Rate");
1680c19c7afeSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
1681b1d5caf3SKevin Bowling 		    CTLFLAG_RD, &(sc->rx_queues[i].irqs),
1682c19c7afeSEric Joyner 		    "irqs on this queue");
16838eb6488eSEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head",
1684f72de14eSKevin Bowling 		    CTLTYPE_UINT | CTLFLAG_RD, rxr, 0,
16858eb6488eSEric Joyner 		    ixgbe_sysctl_rdh_handler, "IU", "Receive Descriptor Head");
16868eb6488eSEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail",
1687f72de14eSKevin Bowling 		    CTLTYPE_UINT | CTLFLAG_RD, rxr, 0,
16888eb6488eSEric Joyner 		    ixgbe_sysctl_rdt_handler, "IU", "Receive Descriptor Tail");
16898eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
16908eb6488eSEric Joyner 		    CTLFLAG_RD, &rxr->rx_packets, "Queue Packets Received");
16918eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
16928eb6488eSEric Joyner 		    CTLFLAG_RD, &rxr->rx_bytes, "Queue Bytes Received");
16938eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies",
16948eb6488eSEric Joyner 		    CTLFLAG_RD, &rxr->rx_copies, "Copied RX Frames");
16958eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_discarded",
16968eb6488eSEric Joyner 		    CTLFLAG_RD, &rxr->rx_discarded, "Discarded RX packets");
16978eb6488eSEric Joyner 	}
16988eb6488eSEric Joyner 
16998eb6488eSEric Joyner 	/* MAC stats get their own sub node */
17008eb6488eSEric Joyner 
17018eb6488eSEric Joyner 	stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats",
170220b91f0aSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "MAC Statistics");
17038eb6488eSEric Joyner 	stat_list = SYSCTL_CHILDREN(stat_node);
17048eb6488eSEric Joyner 
1705afb1aa4eSPiotr Pietruszewski 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_errs",
1706b1d5caf3SKevin Bowling 	    CTLFLAG_RD, &sc->ierrors, IXGBE_SYSCTL_DESC_RX_ERRS);
17078eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs",
17088eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->crcerrs, "CRC Errors");
17098eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs",
17108eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->illerrc, "Illegal Byte Errors");
17118eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs",
17128eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->errbc, "Byte Errors");
17138eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards",
17148eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mspdc, "MAC Short Packets Discarded");
17158eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults",
17168eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mlfc, "MAC Local Faults");
17178eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults",
17188eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mrfc, "MAC Remote Faults");
17198eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs",
17208eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->rlec, "Receive Length Errors");
17218eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_missed_packets",
17228eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mpc[0], "RX Missed Packet Count");
17238eb6488eSEric Joyner 
17248eb6488eSEric Joyner 	/* Flow Control stats */
17258eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd",
17268eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->lxontxc, "Link XON Transmitted");
17278eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd",
17288eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->lxonrxc, "Link XON Received");
17298eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd",
17308eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->lxofftxc, "Link XOFF Transmitted");
17318eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd",
17328eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->lxoffrxc, "Link XOFF Received");
17338eb6488eSEric Joyner 
17348eb6488eSEric Joyner 	/* Packet Reception Stats */
17358eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd",
17368eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->tor, "Total Octets Received");
17378eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd",
17388eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->gorc, "Good Octets Received");
17398eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd",
17408eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->tpr, "Total Packets Received");
17418eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd",
17428eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->gprc, "Good Packets Received");
17438eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd",
17448eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mprc, "Multicast Packets Received");
17458eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd",
17468eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->bprc, "Broadcast Packets Received");
17478eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64",
17488eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc64, "64 byte frames received ");
17498eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127",
17508eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc127, "65-127 byte frames received");
17518eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255",
17528eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc255, "128-255 byte frames received");
17538eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511",
17548eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc511, "256-511 byte frames received");
17558eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023",
17568eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc1023, "512-1023 byte frames received");
17578eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522",
17588eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc1522, "1023-1522 byte frames received");
17598eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized",
17608eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ruc, "Receive Undersized");
17618eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented",
17628eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->rfc, "Fragmented Packets Received ");
17638eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized",
17648eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->roc, "Oversized Packets Received");
17658eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd",
17668eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->rjc, "Received Jabber");
17678eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd",
17688eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mngprc, "Management Packets Received");
17698eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd",
17708eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mngptc, "Management Packets Dropped");
17718eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs",
17728eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->xec, "Checksum Errors");
17738eb6488eSEric Joyner 
17748eb6488eSEric Joyner 	/* Packet Transmission Stats */
17758eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd",
17768eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->gotc, "Good Octets Transmitted");
17778eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd",
17788eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->tpt, "Total Packets Transmitted");
17798eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd",
17808eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->gptc, "Good Packets Transmitted");
17818eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd",
17828eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->bptc, "Broadcast Packets Transmitted");
17838eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd",
17848eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mptc, "Multicast Packets Transmitted");
17858eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd",
17868eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mngptc, "Management Packets Transmitted");
17878eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64",
17888eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc64, "64 byte frames transmitted ");
17898eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127",
17908eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc127, "65-127 byte frames transmitted");
17918eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255",
17928eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc255, "128-255 byte frames transmitted");
17938eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511",
17948eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc511, "256-511 byte frames transmitted");
17958eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023",
17968eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc1023, "512-1023 byte frames transmitted");
17978eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522",
17988eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc1522, "1024-1522 byte frames transmitted");
17998eb6488eSEric Joyner } /* ixgbe_add_hw_stats */
18008eb6488eSEric Joyner 
18018eb6488eSEric Joyner /************************************************************************
18028eb6488eSEric Joyner  * ixgbe_sysctl_tdh_handler - Transmit Descriptor Head handler function
18038eb6488eSEric Joyner  *
18048eb6488eSEric Joyner  *   Retrieves the TDH value from the hardware
18058eb6488eSEric Joyner  ************************************************************************/
1806758cc3dcSJack F Vogel static int
1807758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS)
1808758cc3dcSJack F Vogel {
1809758cc3dcSJack F Vogel 	struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1);
18108eb6488eSEric Joyner 	int            error;
18118eb6488eSEric Joyner 	unsigned int   val;
1812758cc3dcSJack F Vogel 
18138eb6488eSEric Joyner 	if (!txr)
18148eb6488eSEric Joyner 		return (0);
18158eb6488eSEric Joyner 
1816f72de14eSKevin Bowling 
1817f72de14eSKevin Bowling 	if (atomic_load_acq_int(&txr->sc->recovery_mode))
1818f72de14eSKevin Bowling 		return (EPERM);
1819f72de14eSKevin Bowling 
1820b1d5caf3SKevin Bowling 	val = IXGBE_READ_REG(&txr->sc->hw, IXGBE_TDH(txr->me));
1821758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
1822758cc3dcSJack F Vogel 	if (error || !req->newptr)
1823758cc3dcSJack F Vogel 		return error;
1824758cc3dcSJack F Vogel 
18258eb6488eSEric Joyner 	return (0);
18268eb6488eSEric Joyner } /* ixgbe_sysctl_tdh_handler */
18278eb6488eSEric Joyner 
18288eb6488eSEric Joyner /************************************************************************
18298eb6488eSEric Joyner  * ixgbe_sysctl_tdt_handler - Transmit Descriptor Tail handler function
18308eb6488eSEric Joyner  *
1831758cc3dcSJack F Vogel  *   Retrieves the TDT value from the hardware
18328eb6488eSEric Joyner  ************************************************************************/
1833758cc3dcSJack F Vogel static int
1834758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS)
1835758cc3dcSJack F Vogel {
1836758cc3dcSJack F Vogel 	struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1);
18378eb6488eSEric Joyner 	int            error;
18388eb6488eSEric Joyner 	unsigned int   val;
1839758cc3dcSJack F Vogel 
18408eb6488eSEric Joyner 	if (!txr)
18418eb6488eSEric Joyner 		return (0);
18428eb6488eSEric Joyner 
1843f72de14eSKevin Bowling 	if (atomic_load_acq_int(&txr->sc->recovery_mode))
1844f72de14eSKevin Bowling 		return (EPERM);
1845f72de14eSKevin Bowling 
1846b1d5caf3SKevin Bowling 	val = IXGBE_READ_REG(&txr->sc->hw, IXGBE_TDT(txr->me));
1847758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
1848758cc3dcSJack F Vogel 	if (error || !req->newptr)
1849758cc3dcSJack F Vogel 		return error;
1850758cc3dcSJack F Vogel 
18518eb6488eSEric Joyner 	return (0);
18528eb6488eSEric Joyner } /* ixgbe_sysctl_tdt_handler */
18538eb6488eSEric Joyner 
18548eb6488eSEric Joyner /************************************************************************
18558eb6488eSEric Joyner  * ixgbe_sysctl_rdh_handler - Receive Descriptor Head handler function
18568eb6488eSEric Joyner  *
1857758cc3dcSJack F Vogel  *   Retrieves the RDH value from the hardware
18588eb6488eSEric Joyner  ************************************************************************/
1859758cc3dcSJack F Vogel static int
1860758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS)
1861758cc3dcSJack F Vogel {
1862758cc3dcSJack F Vogel 	struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1);
18638eb6488eSEric Joyner 	int            error;
18648eb6488eSEric Joyner 	unsigned int   val;
1865758cc3dcSJack F Vogel 
18668eb6488eSEric Joyner 	if (!rxr)
18678eb6488eSEric Joyner 		return (0);
18688eb6488eSEric Joyner 
1869f72de14eSKevin Bowling 	if (atomic_load_acq_int(&rxr->sc->recovery_mode))
1870f72de14eSKevin Bowling 		return (EPERM);
1871f72de14eSKevin Bowling 
1872b1d5caf3SKevin Bowling 	val = IXGBE_READ_REG(&rxr->sc->hw, IXGBE_RDH(rxr->me));
1873758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
1874758cc3dcSJack F Vogel 	if (error || !req->newptr)
1875758cc3dcSJack F Vogel 		return error;
1876758cc3dcSJack F Vogel 
18778eb6488eSEric Joyner 	return (0);
18788eb6488eSEric Joyner } /* ixgbe_sysctl_rdh_handler */
18798eb6488eSEric Joyner 
18808eb6488eSEric Joyner /************************************************************************
18818eb6488eSEric Joyner  * ixgbe_sysctl_rdt_handler - Receive Descriptor Tail handler function
18828eb6488eSEric Joyner  *
1883758cc3dcSJack F Vogel  *   Retrieves the RDT value from the hardware
18848eb6488eSEric Joyner  ************************************************************************/
1885758cc3dcSJack F Vogel static int
1886758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS)
1887758cc3dcSJack F Vogel {
1888758cc3dcSJack F Vogel 	struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1);
18898eb6488eSEric Joyner 	int            error;
18908eb6488eSEric Joyner 	unsigned int   val;
1891758cc3dcSJack F Vogel 
18928eb6488eSEric Joyner 	if (!rxr)
18938eb6488eSEric Joyner 		return (0);
18948eb6488eSEric Joyner 
1895f72de14eSKevin Bowling 	if (atomic_load_acq_int(&rxr->sc->recovery_mode))
1896f72de14eSKevin Bowling 		return (EPERM);
1897f72de14eSKevin Bowling 
1898b1d5caf3SKevin Bowling 	val = IXGBE_READ_REG(&rxr->sc->hw, IXGBE_RDT(rxr->me));
1899758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
1900758cc3dcSJack F Vogel 	if (error || !req->newptr)
1901758cc3dcSJack F Vogel 		return error;
19028eb6488eSEric Joyner 
19038eb6488eSEric Joyner 	return (0);
19048eb6488eSEric Joyner } /* ixgbe_sysctl_rdt_handler */
19058eb6488eSEric Joyner 
19068eb6488eSEric Joyner /************************************************************************
1907c19c7afeSEric Joyner  * ixgbe_if_vlan_register
19088eb6488eSEric Joyner  *
19098eb6488eSEric Joyner  *   Run via vlan config EVENT, it enables us to use the
19108eb6488eSEric Joyner  *   HW Filter table since we can get the vlan id. This
19118eb6488eSEric Joyner  *   just creates the entry in the soft version of the
19128eb6488eSEric Joyner  *   VFTA, init will repopulate the real table.
19138eb6488eSEric Joyner  ************************************************************************/
19148eb6488eSEric Joyner static void
1915c19c7afeSEric Joyner ixgbe_if_vlan_register(if_ctx_t ctx, u16 vtag)
19168eb6488eSEric Joyner {
1917b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
19188eb6488eSEric Joyner 	u16            index, bit;
19198eb6488eSEric Joyner 
19208eb6488eSEric Joyner 	index = (vtag >> 5) & 0x7F;
19218eb6488eSEric Joyner 	bit = vtag & 0x1F;
1922b1d5caf3SKevin Bowling 	sc->shadow_vfta[index] |= (1 << bit);
1923b1d5caf3SKevin Bowling 	++sc->num_vlans;
1924c19c7afeSEric Joyner 	ixgbe_setup_vlan_hw_support(ctx);
1925c19c7afeSEric Joyner } /* ixgbe_if_vlan_register */
19268eb6488eSEric Joyner 
19278eb6488eSEric Joyner /************************************************************************
1928c19c7afeSEric Joyner  * ixgbe_if_vlan_unregister
19298eb6488eSEric Joyner  *
19308eb6488eSEric Joyner  *   Run via vlan unconfig EVENT, remove our entry in the soft vfta.
19318eb6488eSEric Joyner  ************************************************************************/
19328eb6488eSEric Joyner static void
1933c19c7afeSEric Joyner ixgbe_if_vlan_unregister(if_ctx_t ctx, u16 vtag)
19348eb6488eSEric Joyner {
1935b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
19368eb6488eSEric Joyner 	u16            index, bit;
19378eb6488eSEric Joyner 
19388eb6488eSEric Joyner 	index = (vtag >> 5) & 0x7F;
19398eb6488eSEric Joyner 	bit = vtag & 0x1F;
1940b1d5caf3SKevin Bowling 	sc->shadow_vfta[index] &= ~(1 << bit);
1941b1d5caf3SKevin Bowling 	--sc->num_vlans;
19428eb6488eSEric Joyner 	/* Re-init to load the changes */
1943c19c7afeSEric Joyner 	ixgbe_setup_vlan_hw_support(ctx);
1944c19c7afeSEric Joyner } /* ixgbe_if_vlan_unregister */
19458eb6488eSEric Joyner 
19468eb6488eSEric Joyner /************************************************************************
19478eb6488eSEric Joyner  * ixgbe_setup_vlan_hw_support
19488eb6488eSEric Joyner  ************************************************************************/
19498eb6488eSEric Joyner static void
1950c19c7afeSEric Joyner ixgbe_setup_vlan_hw_support(if_ctx_t ctx)
19518eb6488eSEric Joyner {
1952ff06a8dbSJustin Hibbits 	if_t            ifp = iflib_get_ifp(ctx);
1953b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = iflib_get_softc(ctx);
1954b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
19558eb6488eSEric Joyner 	struct rx_ring  *rxr;
19568eb6488eSEric Joyner 	int             i;
19578eb6488eSEric Joyner 	u32             ctrl;
19588eb6488eSEric Joyner 
19598eb6488eSEric Joyner 
19608eb6488eSEric Joyner 	/*
19618eb6488eSEric Joyner 	 * We get here thru init_locked, meaning
19628eb6488eSEric Joyner 	 * a soft reset, this has already cleared
19638eb6488eSEric Joyner 	 * the VFTA and other state, so if there
19648eb6488eSEric Joyner 	 * have been no vlan's registered do nothing.
19658eb6488eSEric Joyner 	 */
1966ff06a8dbSJustin Hibbits 	if (sc->num_vlans == 0 || (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) == 0) {
1967e7abb897SKristof Provost 		/* Clear the vlan hw flag */
1968e7abb897SKristof Provost 		for (i = 0; i < sc->num_rx_queues; i++) {
1969e7abb897SKristof Provost 			rxr = &sc->rx_queues[i].rxr;
1970e7abb897SKristof Provost 			/* On 82599 the VLAN enable is per/queue in RXDCTL */
1971e7abb897SKristof Provost 			if (hw->mac.type != ixgbe_mac_82598EB) {
1972e7abb897SKristof Provost 				ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me));
1973e7abb897SKristof Provost 				ctrl &= ~IXGBE_RXDCTL_VME;
1974e7abb897SKristof Provost 				IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl);
1975e7abb897SKristof Provost 			}
1976e7abb897SKristof Provost 			rxr->vtag_strip = false;
1977e7abb897SKristof Provost 		}
1978e7abb897SKristof Provost 		ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
1979e7abb897SKristof Provost 		/* Enable the Filter Table if enabled */
1980e7abb897SKristof Provost 		ctrl |= IXGBE_VLNCTRL_CFIEN;
1981e7abb897SKristof Provost 		ctrl &= ~IXGBE_VLNCTRL_VFE;
1982e7abb897SKristof Provost 		if (hw->mac.type == ixgbe_mac_82598EB)
1983e7abb897SKristof Provost 			ctrl &= ~IXGBE_VLNCTRL_VME;
1984e7abb897SKristof Provost 		IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl);
19858eb6488eSEric Joyner 		return;
1986e7abb897SKristof Provost 	}
19878eb6488eSEric Joyner 
19888eb6488eSEric Joyner 	/* Setup the queues for vlans */
1989ff06a8dbSJustin Hibbits 	if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) {
1990b1d5caf3SKevin Bowling 		for (i = 0; i < sc->num_rx_queues; i++) {
1991b1d5caf3SKevin Bowling 			rxr = &sc->rx_queues[i].rxr;
19928eb6488eSEric Joyner 			/* On 82599 the VLAN enable is per/queue in RXDCTL */
19938eb6488eSEric Joyner 			if (hw->mac.type != ixgbe_mac_82598EB) {
19948eb6488eSEric Joyner 				ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me));
19958eb6488eSEric Joyner 				ctrl |= IXGBE_RXDCTL_VME;
19968eb6488eSEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl);
19978eb6488eSEric Joyner 			}
199879b36ec9SKevin Bowling 			rxr->vtag_strip = true;
1999758cc3dcSJack F Vogel 		}
20009c92bb71SSean Bruno 	}
2001758cc3dcSJack F Vogel 
2002ff06a8dbSJustin Hibbits 	if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0)
20038eb6488eSEric Joyner 		return;
20048eb6488eSEric Joyner 	/*
20058eb6488eSEric Joyner 	 * A soft reset zero's out the VFTA, so
20068eb6488eSEric Joyner 	 * we need to repopulate it now.
20078eb6488eSEric Joyner 	 */
20088eb6488eSEric Joyner 	for (i = 0; i < IXGBE_VFTA_SIZE; i++)
2009b1d5caf3SKevin Bowling 		if (sc->shadow_vfta[i] != 0)
20108eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_VFTA(i),
2011b1d5caf3SKevin Bowling 			    sc->shadow_vfta[i]);
20128eb6488eSEric Joyner 
20138eb6488eSEric Joyner 	ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
20148eb6488eSEric Joyner 	/* Enable the Filter Table if enabled */
2015ff06a8dbSJustin Hibbits 	if (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) {
20168eb6488eSEric Joyner 		ctrl &= ~IXGBE_VLNCTRL_CFIEN;
20178eb6488eSEric Joyner 		ctrl |= IXGBE_VLNCTRL_VFE;
20188eb6488eSEric Joyner 	}
20198eb6488eSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB)
20208eb6488eSEric Joyner 		ctrl |= IXGBE_VLNCTRL_VME;
20218eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl);
20228eb6488eSEric Joyner } /* ixgbe_setup_vlan_hw_support */
20238eb6488eSEric Joyner 
20248eb6488eSEric Joyner /************************************************************************
20258eb6488eSEric Joyner  * ixgbe_get_slot_info
20268eb6488eSEric Joyner  *
20278eb6488eSEric Joyner  *   Get the width and transaction speed of
20288eb6488eSEric Joyner  *   the slot this adapter is plugged into.
20298eb6488eSEric Joyner  ************************************************************************/
20308eb6488eSEric Joyner static void
2031b1d5caf3SKevin Bowling ixgbe_get_slot_info(struct ixgbe_softc *sc)
20328eb6488eSEric Joyner {
2033b1d5caf3SKevin Bowling 	device_t        dev = iflib_get_dev(sc->ctx);
2034b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
203579b36ec9SKevin Bowling 	int             bus_info_valid = true;
20368eb6488eSEric Joyner 	u32             offset;
20378eb6488eSEric Joyner 	u16             link;
20388eb6488eSEric Joyner 
20398eb6488eSEric Joyner 	/* Some devices are behind an internal bridge */
20408eb6488eSEric Joyner 	switch (hw->device_id) {
20418eb6488eSEric Joyner 	case IXGBE_DEV_ID_82599_SFP_SF_QP:
20428eb6488eSEric Joyner 	case IXGBE_DEV_ID_82599_QSFP_SF_QP:
20438eb6488eSEric Joyner 		goto get_parent_info;
20448eb6488eSEric Joyner 	default:
20458eb6488eSEric Joyner 		break;
20468eb6488eSEric Joyner 	}
20478eb6488eSEric Joyner 
20488eb6488eSEric Joyner 	ixgbe_get_bus_info(hw);
20498eb6488eSEric Joyner 
20508eb6488eSEric Joyner 	/*
20518eb6488eSEric Joyner 	 * Some devices don't use PCI-E, but there is no need
20528eb6488eSEric Joyner 	 * to display "Unknown" for bus speed and width.
20538eb6488eSEric Joyner 	 */
20548eb6488eSEric Joyner 	switch (hw->mac.type) {
20558eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
20568eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
20578eb6488eSEric Joyner 		return;
20588eb6488eSEric Joyner 	default:
20598eb6488eSEric Joyner 		goto display;
20608eb6488eSEric Joyner 	}
20618eb6488eSEric Joyner 
20628eb6488eSEric Joyner get_parent_info:
20638eb6488eSEric Joyner 	/*
20648eb6488eSEric Joyner 	 * For the Quad port adapter we need to parse back
20658eb6488eSEric Joyner 	 * up the PCI tree to find the speed of the expansion
20668eb6488eSEric Joyner 	 * slot into which this adapter is plugged. A bit more work.
20678eb6488eSEric Joyner 	 */
20688eb6488eSEric Joyner 	dev = device_get_parent(device_get_parent(dev));
20698eb6488eSEric Joyner #ifdef IXGBE_DEBUG
20708eb6488eSEric Joyner 	device_printf(dev, "parent pcib = %x,%x,%x\n", pci_get_bus(dev),
20718eb6488eSEric Joyner 	    pci_get_slot(dev), pci_get_function(dev));
20728eb6488eSEric Joyner #endif
20738eb6488eSEric Joyner 	dev = device_get_parent(device_get_parent(dev));
20748eb6488eSEric Joyner #ifdef IXGBE_DEBUG
20758eb6488eSEric Joyner 	device_printf(dev, "slot pcib = %x,%x,%x\n", pci_get_bus(dev),
20768eb6488eSEric Joyner 	    pci_get_slot(dev), pci_get_function(dev));
20778eb6488eSEric Joyner #endif
20788eb6488eSEric Joyner 	/* Now get the PCI Express Capabilities offset */
20798eb6488eSEric Joyner 	if (pci_find_cap(dev, PCIY_EXPRESS, &offset)) {
20808eb6488eSEric Joyner 		/*
20818eb6488eSEric Joyner 		 * Hmm...can't get PCI-Express capabilities.
20828eb6488eSEric Joyner 		 * Falling back to default method.
20838eb6488eSEric Joyner 		 */
208479b36ec9SKevin Bowling 		bus_info_valid = false;
20858eb6488eSEric Joyner 		ixgbe_get_bus_info(hw);
20868eb6488eSEric Joyner 		goto display;
20878eb6488eSEric Joyner 	}
20888eb6488eSEric Joyner 	/* ...and read the Link Status Register */
20898eb6488eSEric Joyner 	link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
20908eb6488eSEric Joyner 	ixgbe_set_pci_config_data_generic(hw, link);
20918eb6488eSEric Joyner 
20928eb6488eSEric Joyner display:
20938eb6488eSEric Joyner 	device_printf(dev, "PCI Express Bus: Speed %s %s\n",
20948eb6488eSEric Joyner 	    ((hw->bus.speed == ixgbe_bus_speed_8000)    ? "8.0GT/s"  :
20958eb6488eSEric Joyner 	     (hw->bus.speed == ixgbe_bus_speed_5000)    ? "5.0GT/s"  :
20968eb6488eSEric Joyner 	     (hw->bus.speed == ixgbe_bus_speed_2500)    ? "2.5GT/s"  :
20978eb6488eSEric Joyner 	     "Unknown"),
20988eb6488eSEric Joyner 	    ((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
20998eb6488eSEric Joyner 	     (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" :
21008eb6488eSEric Joyner 	     (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" :
21018eb6488eSEric Joyner 	     "Unknown"));
21028eb6488eSEric Joyner 
21038eb6488eSEric Joyner 	if (bus_info_valid) {
21048eb6488eSEric Joyner 		if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) &&
21058eb6488eSEric Joyner 		    ((hw->bus.width <= ixgbe_bus_width_pcie_x4) &&
21068eb6488eSEric Joyner 		    (hw->bus.speed == ixgbe_bus_speed_2500))) {
21078eb6488eSEric Joyner 			device_printf(dev, "PCI-Express bandwidth available for this card\n     is not sufficient for optimal performance.\n");
21088eb6488eSEric Joyner 			device_printf(dev, "For optimal performance a x8 PCIE, or x4 PCIE Gen2 slot is required.\n");
21098eb6488eSEric Joyner 		}
21108eb6488eSEric Joyner 		if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) &&
21118eb6488eSEric Joyner 		    ((hw->bus.width <= ixgbe_bus_width_pcie_x8) &&
21128eb6488eSEric Joyner 		    (hw->bus.speed < ixgbe_bus_speed_8000))) {
21138eb6488eSEric Joyner 			device_printf(dev, "PCI-Express bandwidth available for this card\n     is not sufficient for optimal performance.\n");
21148eb6488eSEric Joyner 			device_printf(dev, "For optimal performance a x8 PCIE Gen3 slot is required.\n");
21158eb6488eSEric Joyner 		}
21168eb6488eSEric Joyner 	} else
21178eb6488eSEric Joyner 		device_printf(dev, "Unable to determine slot speed/width. The speed/width reported are that of the internal switch.\n");
21188eb6488eSEric Joyner 
21198eb6488eSEric Joyner 	return;
21208eb6488eSEric Joyner } /* ixgbe_get_slot_info */
21218eb6488eSEric Joyner 
21228eb6488eSEric Joyner /************************************************************************
2123c19c7afeSEric Joyner  * ixgbe_if_msix_intr_assign
2124c19c7afeSEric Joyner  *
2125c19c7afeSEric Joyner  *   Setup MSI-X Interrupt resources and handlers
21268eb6488eSEric Joyner  ************************************************************************/
2127c19c7afeSEric Joyner static int
2128c19c7afeSEric Joyner ixgbe_if_msix_intr_assign(if_ctx_t ctx, int msix)
21298eb6488eSEric Joyner {
2130b1d5caf3SKevin Bowling 	struct ixgbe_softc     *sc = iflib_get_softc(ctx);
2131b1d5caf3SKevin Bowling 	struct ix_rx_queue *rx_que = sc->rx_queues;
2132c19c7afeSEric Joyner 	struct ix_tx_queue *tx_que;
2133c19c7afeSEric Joyner 	int                error, rid, vector = 0;
2134c19c7afeSEric Joyner 	char               buf[16];
21358eb6488eSEric Joyner 
2136c19c7afeSEric Joyner 	/* Admin Que is vector 0*/
2137c19c7afeSEric Joyner 	rid = vector + 1;
2138b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++, vector++, rx_que++) {
2139c19c7afeSEric Joyner 		rid = vector + 1;
2140c19c7afeSEric Joyner 
2141c19c7afeSEric Joyner 		snprintf(buf, sizeof(buf), "rxq%d", i);
2142c19c7afeSEric Joyner 		error = iflib_irq_alloc_generic(ctx, &rx_que->que_irq, rid,
214381be6552SMatt Macy 		    IFLIB_INTR_RXTX, ixgbe_msix_que, rx_que, rx_que->rxr.me, buf);
2144c19c7afeSEric Joyner 
2145c19c7afeSEric Joyner 		if (error) {
2146c19c7afeSEric Joyner 			device_printf(iflib_get_dev(ctx),
2147c19c7afeSEric Joyner 			    "Failed to allocate que int %d err: %d", i, error);
2148b1d5caf3SKevin Bowling 			sc->num_rx_queues = i + 1;
2149c19c7afeSEric Joyner 			goto fail;
21508eb6488eSEric Joyner 		}
21518eb6488eSEric Joyner 
2152c19c7afeSEric Joyner 		rx_que->msix = vector;
2153c19c7afeSEric Joyner 	}
2154b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_tx_queues; i++) {
2155c19c7afeSEric Joyner 		snprintf(buf, sizeof(buf), "txq%d", i);
2156b1d5caf3SKevin Bowling 		tx_que = &sc->tx_queues[i];
2157b1d5caf3SKevin Bowling 		tx_que->msix = i % sc->num_rx_queues;
2158c19c7afeSEric Joyner 		iflib_softirq_alloc_generic(ctx,
2159b1d5caf3SKevin Bowling 		    &sc->rx_queues[tx_que->msix].que_irq,
2160c19c7afeSEric Joyner 		    IFLIB_INTR_TX, tx_que, tx_que->txr.me, buf);
2161c19c7afeSEric Joyner 	}
2162c19c7afeSEric Joyner 	rid = vector + 1;
2163b1d5caf3SKevin Bowling 	error = iflib_irq_alloc_generic(ctx, &sc->irq, rid,
2164b1d5caf3SKevin Bowling 	    IFLIB_INTR_ADMIN, ixgbe_msix_link, sc, 0, "aq");
2165c19c7afeSEric Joyner 	if (error) {
2166c19c7afeSEric Joyner 		device_printf(iflib_get_dev(ctx),
2167c19c7afeSEric Joyner 		    "Failed to register admin handler");
2168c19c7afeSEric Joyner 		return (error);
2169c19c7afeSEric Joyner 	}
2170c19c7afeSEric Joyner 
2171b1d5caf3SKevin Bowling 	sc->vector = vector;
2172c19c7afeSEric Joyner 
2173c19c7afeSEric Joyner 	return (0);
2174c19c7afeSEric Joyner fail:
2175b1d5caf3SKevin Bowling 	iflib_irq_free(ctx, &sc->irq);
2176b1d5caf3SKevin Bowling 	rx_que = sc->rx_queues;
2177b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++, rx_que++)
2178c19c7afeSEric Joyner 		iflib_irq_free(ctx, &rx_que->que_irq);
2179c19c7afeSEric Joyner 
2180c19c7afeSEric Joyner 	return (error);
2181c19c7afeSEric Joyner } /* ixgbe_if_msix_intr_assign */
2182c19c7afeSEric Joyner 
218364881da4SSai Rajesh Tallamraju static inline void
2184b1d5caf3SKevin Bowling ixgbe_perform_aim(struct ixgbe_softc *sc, struct ix_rx_queue *que)
218564881da4SSai Rajesh Tallamraju {
218664881da4SSai Rajesh Tallamraju 	uint32_t newitr = 0;
218764881da4SSai Rajesh Tallamraju 	struct rx_ring *rxr = &que->rxr;
2188f72de14eSKevin Bowling 	/* FIXME struct tx_ring *txr = ... ->txr; */
218964881da4SSai Rajesh Tallamraju 
219064881da4SSai Rajesh Tallamraju 	/*
219164881da4SSai Rajesh Tallamraju 	 * Do Adaptive Interrupt Moderation:
219264881da4SSai Rajesh Tallamraju 	 *  - Write out last calculated setting
219364881da4SSai Rajesh Tallamraju 	 *  - Calculate based on average size over
219464881da4SSai Rajesh Tallamraju 	 *    the last interval.
219564881da4SSai Rajesh Tallamraju 	 */
219664881da4SSai Rajesh Tallamraju 	if (que->eitr_setting) {
2197b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(que->msix),
219864881da4SSai Rajesh Tallamraju 		    que->eitr_setting);
219964881da4SSai Rajesh Tallamraju 	}
220064881da4SSai Rajesh Tallamraju 
220164881da4SSai Rajesh Tallamraju 	que->eitr_setting = 0;
220264881da4SSai Rajesh Tallamraju 	/* Idle, do nothing */
220364881da4SSai Rajesh Tallamraju 	if (rxr->bytes == 0) {
2204f72de14eSKevin Bowling 		/* FIXME && txr->bytes == 0 */
220564881da4SSai Rajesh Tallamraju 		return;
220664881da4SSai Rajesh Tallamraju 	}
220764881da4SSai Rajesh Tallamraju 
2208f72de14eSKevin Bowling 	if ((rxr->bytes) && (rxr->packets))
2209f72de14eSKevin Bowling 		newitr = rxr->bytes / rxr->packets;
2210f72de14eSKevin Bowling 	/* FIXME for transmit accounting
2211f72de14eSKevin Bowling 	 * if ((txr->bytes) && (txr->packets))
2212f72de14eSKevin Bowling 	 * 	newitr = txr->bytes/txr->packets;
2213f72de14eSKevin Bowling 	 * if ((rxr->bytes) && (rxr->packets))
2214f72de14eSKevin Bowling 	 * 	newitr = max(newitr, (rxr->bytes / rxr->packets));
2215f72de14eSKevin Bowling 	 */
221664881da4SSai Rajesh Tallamraju 
221764881da4SSai Rajesh Tallamraju 	newitr += 24; /* account for hardware frame, crc */
221864881da4SSai Rajesh Tallamraju 	/* set an upper boundary */
221964881da4SSai Rajesh Tallamraju 	newitr = min(newitr, 3000);
222064881da4SSai Rajesh Tallamraju 
222164881da4SSai Rajesh Tallamraju 	/* Be nice to the mid range */
222264881da4SSai Rajesh Tallamraju 	if ((newitr > 300) && (newitr < 1200)) {
222364881da4SSai Rajesh Tallamraju 		newitr = (newitr / 3);
222464881da4SSai Rajesh Tallamraju 	} else {
222564881da4SSai Rajesh Tallamraju 		newitr = (newitr / 2);
222664881da4SSai Rajesh Tallamraju 	}
222764881da4SSai Rajesh Tallamraju 
2228b1d5caf3SKevin Bowling 	if (sc->hw.mac.type == ixgbe_mac_82598EB) {
222964881da4SSai Rajesh Tallamraju 		newitr |= newitr << 16;
223064881da4SSai Rajesh Tallamraju 	} else {
223164881da4SSai Rajesh Tallamraju 		newitr |= IXGBE_EITR_CNT_WDIS;
223264881da4SSai Rajesh Tallamraju 	}
223364881da4SSai Rajesh Tallamraju 
223464881da4SSai Rajesh Tallamraju 	/* save for next interrupt */
223564881da4SSai Rajesh Tallamraju 	que->eitr_setting = newitr;
223664881da4SSai Rajesh Tallamraju 
223764881da4SSai Rajesh Tallamraju 	/* Reset state */
2238f72de14eSKevin Bowling 	/* FIXME txr->bytes = 0; */
2239f72de14eSKevin Bowling 	/* FIXME txr->packets = 0; */
224064881da4SSai Rajesh Tallamraju 	rxr->bytes = 0;
224164881da4SSai Rajesh Tallamraju 	rxr->packets = 0;
224264881da4SSai Rajesh Tallamraju 
224364881da4SSai Rajesh Tallamraju 	return;
224464881da4SSai Rajesh Tallamraju }
224564881da4SSai Rajesh Tallamraju 
2246c19c7afeSEric Joyner /*********************************************************************
22478eb6488eSEric Joyner  * ixgbe_msix_que - MSI-X Queue Interrupt Service routine
2248c19c7afeSEric Joyner  **********************************************************************/
2249c19c7afeSEric Joyner static int
22508eb6488eSEric Joyner ixgbe_msix_que(void *arg)
22518eb6488eSEric Joyner {
2252c19c7afeSEric Joyner 	struct ix_rx_queue *que = arg;
2253b1d5caf3SKevin Bowling 	struct ixgbe_softc     *sc = que->sc;
2254ff06a8dbSJustin Hibbits 	if_t               ifp = iflib_get_ifp(que->sc->ctx);
22558eb6488eSEric Joyner 
22568eb6488eSEric Joyner 	/* Protect against spurious interrupts */
2257ff06a8dbSJustin Hibbits 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
22586c351041SEric Joyner 		return (FILTER_HANDLED);
22598eb6488eSEric Joyner 
2260b1d5caf3SKevin Bowling 	ixgbe_disable_queue(sc, que->msix);
22618eb6488eSEric Joyner 	++que->irqs;
22628eb6488eSEric Joyner 
226364881da4SSai Rajesh Tallamraju 	/* Check for AIM */
2264b1d5caf3SKevin Bowling 	if (sc->enable_aim) {
2265b1d5caf3SKevin Bowling 		ixgbe_perform_aim(sc, que);
226664881da4SSai Rajesh Tallamraju 	}
226764881da4SSai Rajesh Tallamraju 
2268c19c7afeSEric Joyner 	return (FILTER_SCHEDULE_THREAD);
22698eb6488eSEric Joyner } /* ixgbe_msix_que */
22708eb6488eSEric Joyner 
22718eb6488eSEric Joyner /************************************************************************
22728eb6488eSEric Joyner  * ixgbe_media_status - Media Ioctl callback
22738eb6488eSEric Joyner  *
22748eb6488eSEric Joyner  *   Called whenever the user queries the status of
22758eb6488eSEric Joyner  *   the interface using ifconfig.
22768eb6488eSEric Joyner  ************************************************************************/
22778eb6488eSEric Joyner static void
2278c19c7afeSEric Joyner ixgbe_if_media_status(if_ctx_t ctx, struct ifmediareq * ifmr)
22798eb6488eSEric Joyner {
2280b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = iflib_get_softc(ctx);
2281b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
22828eb6488eSEric Joyner 	int             layer;
22838eb6488eSEric Joyner 
2284c19c7afeSEric Joyner 	INIT_DEBUGOUT("ixgbe_if_media_status: begin");
2285c19c7afeSEric Joyner 
22868eb6488eSEric Joyner 	ifmr->ifm_status = IFM_AVALID;
22878eb6488eSEric Joyner 	ifmr->ifm_active = IFM_ETHER;
22888eb6488eSEric Joyner 
2289b1d5caf3SKevin Bowling 	if (!sc->link_active)
22908eb6488eSEric Joyner 		return;
22918eb6488eSEric Joyner 
22928eb6488eSEric Joyner 	ifmr->ifm_status |= IFM_ACTIVE;
2293b1d5caf3SKevin Bowling 	layer = sc->phy_layer;
22948eb6488eSEric Joyner 
22958eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T ||
22968eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_T ||
22978eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_100BASE_TX ||
22988eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_10BASE_T)
2299b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
23008eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
23018eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
23028eb6488eSEric Joyner 			break;
23038eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
23048eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_T | IFM_FDX;
23058eb6488eSEric Joyner 			break;
23068eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_100_FULL:
23078eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
23088eb6488eSEric Joyner 			break;
23098eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10_FULL:
23108eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10_T | IFM_FDX;
23118eb6488eSEric Joyner 			break;
23128eb6488eSEric Joyner 		}
2313d381c807SPiotr Pietruszewski 	if (hw->mac.type == ixgbe_mac_X550)
2314d381c807SPiotr Pietruszewski 		switch (sc->link_speed) {
2315d381c807SPiotr Pietruszewski 		case IXGBE_LINK_SPEED_5GB_FULL:
2316d381c807SPiotr Pietruszewski 			ifmr->ifm_active |= IFM_5000_T | IFM_FDX;
2317d381c807SPiotr Pietruszewski 			break;
2318d381c807SPiotr Pietruszewski 		case IXGBE_LINK_SPEED_2_5GB_FULL:
2319d381c807SPiotr Pietruszewski 			ifmr->ifm_active |= IFM_2500_T | IFM_FDX;
2320d381c807SPiotr Pietruszewski 			break;
2321d381c807SPiotr Pietruszewski 		}
23228eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU ||
23238eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA)
2324b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
23258eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
23268eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_TWINAX | IFM_FDX;
23278eb6488eSEric Joyner 			break;
2328*48ddd1b9SKevin Bowling 		case IXGBE_LINK_SPEED_1GB_FULL:
2329*48ddd1b9SKevin Bowling 			ifmr->ifm_active |= IFM_1000_KX | IFM_FDX;
2330*48ddd1b9SKevin Bowling 			break;
23318eb6488eSEric Joyner 		}
23328eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR)
2333b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
23348eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
23358eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_LR | IFM_FDX;
23368eb6488eSEric Joyner 			break;
23378eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
23388eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_LX | IFM_FDX;
23398eb6488eSEric Joyner 			break;
23408eb6488eSEric Joyner 		}
23418eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM)
2342b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
23438eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
23448eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_LRM | IFM_FDX;
23458eb6488eSEric Joyner 			break;
23468eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
23478eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_LX | IFM_FDX;
23488eb6488eSEric Joyner 			break;
23498eb6488eSEric Joyner 		}
23508eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR ||
23518eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX)
2352b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
23538eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
23548eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
23558eb6488eSEric Joyner 			break;
23568eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
23578eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_SX | IFM_FDX;
23588eb6488eSEric Joyner 			break;
23598eb6488eSEric Joyner 		}
23608eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4)
2361b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
23628eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
23638eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX;
23648eb6488eSEric Joyner 			break;
23658eb6488eSEric Joyner 		}
23668eb6488eSEric Joyner 	/*
23678eb6488eSEric Joyner 	 * XXX: These need to use the proper media types once
23688eb6488eSEric Joyner 	 * they're added.
23698eb6488eSEric Joyner 	 */
23708eb6488eSEric Joyner #ifndef IFM_ETH_XTYPE
23718eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR)
2372b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
23738eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
23748eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
23758eb6488eSEric Joyner 			break;
23768eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
23778eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_2500_SX | IFM_FDX;
23788eb6488eSEric Joyner 			break;
23798eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
23808eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_CX | IFM_FDX;
23818eb6488eSEric Joyner 			break;
23828eb6488eSEric Joyner 		}
23838eb6488eSEric Joyner 	else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 ||
23848eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX ||
23858eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX)
2386b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
23878eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
23888eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX;
23898eb6488eSEric Joyner 			break;
23908eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
23918eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_2500_SX | IFM_FDX;
23928eb6488eSEric Joyner 			break;
23938eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
23948eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_CX | IFM_FDX;
23958eb6488eSEric Joyner 			break;
23968eb6488eSEric Joyner 		}
23978eb6488eSEric Joyner #else
23988eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR)
2399b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
24008eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
24018eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_KR | IFM_FDX;
24028eb6488eSEric Joyner 			break;
24038eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
24048eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_2500_KX | IFM_FDX;
24058eb6488eSEric Joyner 			break;
24068eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
24078eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_KX | IFM_FDX;
24088eb6488eSEric Joyner 			break;
24098eb6488eSEric Joyner 		}
24108eb6488eSEric Joyner 	else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 ||
24118eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX ||
24128eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX)
2413b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
24148eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
24158eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_KX4 | IFM_FDX;
24168eb6488eSEric Joyner 			break;
24178eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
24188eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_2500_KX | IFM_FDX;
24198eb6488eSEric Joyner 			break;
24208eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
24218eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_KX | IFM_FDX;
24228eb6488eSEric Joyner 			break;
24238eb6488eSEric Joyner 		}
24248eb6488eSEric Joyner #endif
24258eb6488eSEric Joyner 
24268eb6488eSEric Joyner 	/* If nothing is recognized... */
24278eb6488eSEric Joyner 	if (IFM_SUBTYPE(ifmr->ifm_active) == 0)
24288eb6488eSEric Joyner 		ifmr->ifm_active |= IFM_UNKNOWN;
24298eb6488eSEric Joyner 
24308eb6488eSEric Joyner 	/* Display current flow control setting used on link */
24318eb6488eSEric Joyner 	if (hw->fc.current_mode == ixgbe_fc_rx_pause ||
24328eb6488eSEric Joyner 	    hw->fc.current_mode == ixgbe_fc_full)
24338eb6488eSEric Joyner 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
24348eb6488eSEric Joyner 	if (hw->fc.current_mode == ixgbe_fc_tx_pause ||
24358eb6488eSEric Joyner 	    hw->fc.current_mode == ixgbe_fc_full)
24368eb6488eSEric Joyner 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
24378eb6488eSEric Joyner } /* ixgbe_media_status */
24388eb6488eSEric Joyner 
24398eb6488eSEric Joyner /************************************************************************
24408eb6488eSEric Joyner  * ixgbe_media_change - Media Ioctl callback
24418eb6488eSEric Joyner  *
24428eb6488eSEric Joyner  *   Called when the user changes speed/duplex using
24438eb6488eSEric Joyner  *   media/mediopt option with ifconfig.
24448eb6488eSEric Joyner  ************************************************************************/
24458eb6488eSEric Joyner static int
2446c19c7afeSEric Joyner ixgbe_if_media_change(if_ctx_t ctx)
24478eb6488eSEric Joyner {
2448b1d5caf3SKevin Bowling 	struct ixgbe_softc   *sc = iflib_get_softc(ctx);
2449c19c7afeSEric Joyner 	struct ifmedia   *ifm = iflib_get_media(ctx);
2450b1d5caf3SKevin Bowling 	struct ixgbe_hw  *hw = &sc->hw;
24518eb6488eSEric Joyner 	ixgbe_link_speed speed = 0;
24528eb6488eSEric Joyner 
2453c19c7afeSEric Joyner 	INIT_DEBUGOUT("ixgbe_if_media_change: begin");
24548eb6488eSEric Joyner 
24558eb6488eSEric Joyner 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
24568eb6488eSEric Joyner 		return (EINVAL);
24578eb6488eSEric Joyner 
24588eb6488eSEric Joyner 	if (hw->phy.media_type == ixgbe_media_type_backplane)
2459c19c7afeSEric Joyner 		return (EPERM);
24608eb6488eSEric Joyner 
24618eb6488eSEric Joyner 	/*
24628eb6488eSEric Joyner 	 * We don't actually need to check against the supported
24638eb6488eSEric Joyner 	 * media types of the adapter; ifmedia will take care of
24648eb6488eSEric Joyner 	 * that for us.
24658eb6488eSEric Joyner 	 */
24668eb6488eSEric Joyner 	switch (IFM_SUBTYPE(ifm->ifm_media)) {
24678eb6488eSEric Joyner 	case IFM_AUTO:
24688eb6488eSEric Joyner 	case IFM_10G_T:
24698eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_100_FULL;
24708eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
24718eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_10GB_FULL;
24728eb6488eSEric Joyner 		break;
24738eb6488eSEric Joyner 	case IFM_10G_LRM:
24748eb6488eSEric Joyner 	case IFM_10G_LR:
24758eb6488eSEric Joyner #ifndef IFM_ETH_XTYPE
24768eb6488eSEric Joyner 	case IFM_10G_SR: /* KR, too */
24778eb6488eSEric Joyner 	case IFM_10G_CX4: /* KX4 */
24788eb6488eSEric Joyner #else
24798eb6488eSEric Joyner 	case IFM_10G_KR:
24808eb6488eSEric Joyner 	case IFM_10G_KX4:
24818eb6488eSEric Joyner #endif
24828eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
24838eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_10GB_FULL;
24848eb6488eSEric Joyner 		break;
24858eb6488eSEric Joyner #ifndef IFM_ETH_XTYPE
24868eb6488eSEric Joyner 	case IFM_1000_CX: /* KX */
24878eb6488eSEric Joyner #else
24888eb6488eSEric Joyner 	case IFM_1000_KX:
24898eb6488eSEric Joyner #endif
24908eb6488eSEric Joyner 	case IFM_1000_LX:
24918eb6488eSEric Joyner 	case IFM_1000_SX:
24928eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
24938eb6488eSEric Joyner 		break;
24948eb6488eSEric Joyner 	case IFM_1000_T:
24958eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_100_FULL;
24968eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
24978eb6488eSEric Joyner 		break;
24988eb6488eSEric Joyner 	case IFM_10G_TWINAX:
24998eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_10GB_FULL;
25008eb6488eSEric Joyner 		break;
2501d381c807SPiotr Pietruszewski 	case IFM_5000_T:
2502d381c807SPiotr Pietruszewski 		speed |= IXGBE_LINK_SPEED_5GB_FULL;
2503d381c807SPiotr Pietruszewski 		break;
2504d381c807SPiotr Pietruszewski 	case IFM_2500_T:
2505d381c807SPiotr Pietruszewski 		speed |= IXGBE_LINK_SPEED_2_5GB_FULL;
2506d381c807SPiotr Pietruszewski 		break;
25078eb6488eSEric Joyner 	case IFM_100_TX:
25088eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_100_FULL;
25098eb6488eSEric Joyner 		break;
25108eb6488eSEric Joyner 	case IFM_10_T:
25118eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_10_FULL;
25128eb6488eSEric Joyner 		break;
25138eb6488eSEric Joyner 	default:
25148eb6488eSEric Joyner 		goto invalid;
25158eb6488eSEric Joyner 	}
25168eb6488eSEric Joyner 
251779b36ec9SKevin Bowling 	hw->mac.autotry_restart = true;
251879b36ec9SKevin Bowling 	hw->mac.ops.setup_link(hw, speed, true);
2519b1d5caf3SKevin Bowling 	sc->advertise =
2520d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_10GB_FULL)  ? 0x4  : 0) |
2521d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_5GB_FULL)   ? 0x20 : 0) |
2522d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_2_5GB_FULL) ? 0x10 : 0) |
2523d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_1GB_FULL)   ? 0x2  : 0) |
2524d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_100_FULL)   ? 0x1  : 0) |
2525d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_10_FULL)    ? 0x8  : 0);
25268eb6488eSEric Joyner 
25278eb6488eSEric Joyner 	return (0);
25288eb6488eSEric Joyner 
25298eb6488eSEric Joyner invalid:
2530c19c7afeSEric Joyner 	device_printf(iflib_get_dev(ctx), "Invalid media type!\n");
25318eb6488eSEric Joyner 
25328eb6488eSEric Joyner 	return (EINVAL);
2533c19c7afeSEric Joyner } /* ixgbe_if_media_change */
25348eb6488eSEric Joyner 
25358eb6488eSEric Joyner /************************************************************************
25368eb6488eSEric Joyner  * ixgbe_set_promisc
25378eb6488eSEric Joyner  ************************************************************************/
2538c19c7afeSEric Joyner static int
2539c19c7afeSEric Joyner ixgbe_if_promisc_set(if_ctx_t ctx, int flags)
25408eb6488eSEric Joyner {
2541b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
2542ff06a8dbSJustin Hibbits 	if_t           ifp = iflib_get_ifp(ctx);
25438eb6488eSEric Joyner 	u32            rctl;
2544c19c7afeSEric Joyner 	int            mcnt = 0;
25458eb6488eSEric Joyner 
2546b1d5caf3SKevin Bowling 	rctl = IXGBE_READ_REG(&sc->hw, IXGBE_FCTRL);
25478eb6488eSEric Joyner 	rctl &= (~IXGBE_FCTRL_UPE);
2548ff06a8dbSJustin Hibbits 	if (if_getflags(ifp) & IFF_ALLMULTI)
25498eb6488eSEric Joyner 		mcnt = MAX_NUM_MULTICAST_ADDRESSES;
25508eb6488eSEric Joyner 	else {
2551ba76aa63SGleb Smirnoff 		mcnt = min(if_llmaddr_count(ifp), MAX_NUM_MULTICAST_ADDRESSES);
25528eb6488eSEric Joyner 	}
25538eb6488eSEric Joyner 	if (mcnt < MAX_NUM_MULTICAST_ADDRESSES)
25548eb6488eSEric Joyner 		rctl &= (~IXGBE_FCTRL_MPE);
2555b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, rctl);
25568eb6488eSEric Joyner 
2557ff06a8dbSJustin Hibbits 	if (if_getflags(ifp) & IFF_PROMISC) {
25588eb6488eSEric Joyner 		rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
2559b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, rctl);
2560ff06a8dbSJustin Hibbits 	} else if (if_getflags(ifp) & IFF_ALLMULTI) {
25618eb6488eSEric Joyner 		rctl |= IXGBE_FCTRL_MPE;
25628eb6488eSEric Joyner 		rctl &= ~IXGBE_FCTRL_UPE;
2563b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, rctl);
25648eb6488eSEric Joyner 	}
2565c19c7afeSEric Joyner 	return (0);
2566c19c7afeSEric Joyner } /* ixgbe_if_promisc_set */
25678eb6488eSEric Joyner 
25688eb6488eSEric Joyner /************************************************************************
25698eb6488eSEric Joyner  * ixgbe_msix_link - Link status change ISR (MSI/MSI-X)
25708eb6488eSEric Joyner  ************************************************************************/
2571c19c7afeSEric Joyner static int
25728eb6488eSEric Joyner ixgbe_msix_link(void *arg)
25738eb6488eSEric Joyner {
2574b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = arg;
2575b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
25768eb6488eSEric Joyner 	u32             eicr, eicr_mask;
25778eb6488eSEric Joyner 	s32             retval;
25788eb6488eSEric Joyner 
2579b1d5caf3SKevin Bowling 	++sc->link_irq;
25808eb6488eSEric Joyner 
25818eb6488eSEric Joyner 	/* Pause other interrupts */
25828eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_OTHER);
25838eb6488eSEric Joyner 
25848eb6488eSEric Joyner 	/* First get the cause */
25858eb6488eSEric Joyner 	eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
25868eb6488eSEric Joyner 	/* Be sure the queue bits are not cleared */
25878eb6488eSEric Joyner 	eicr &= ~IXGBE_EICR_RTX_QUEUE;
25888eb6488eSEric Joyner 	/* Clear interrupt with write */
25898eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
25908eb6488eSEric Joyner 
25918eb6488eSEric Joyner 	/* Link status change */
25928eb6488eSEric Joyner 	if (eicr & IXGBE_EICR_LSC) {
25938eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC);
2594b1d5caf3SKevin Bowling 		sc->task_requests |= IXGBE_REQUEST_TASK_LSC;
25958eb6488eSEric Joyner 	}
25968eb6488eSEric Joyner 
2597b1d5caf3SKevin Bowling 	if (sc->hw.mac.type != ixgbe_mac_82598EB) {
2598b1d5caf3SKevin Bowling 		if ((sc->feat_en & IXGBE_FEATURE_FDIR) &&
25998eb6488eSEric Joyner 		    (eicr & IXGBE_EICR_FLOW_DIR)) {
26008eb6488eSEric Joyner 			/* This is probably overkill :) */
2601b1d5caf3SKevin Bowling 			if (!atomic_cmpset_int(&sc->fdir_reinit, 0, 1))
2602c19c7afeSEric Joyner 				return (FILTER_HANDLED);
26038eb6488eSEric Joyner 			/* Disable the interrupt */
2604c19c7afeSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR);
2605b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_FDIR;
2606c19c7afeSEric Joyner 		} else
26078eb6488eSEric Joyner 			if (eicr & IXGBE_EICR_ECC) {
2608b1d5caf3SKevin Bowling 				device_printf(iflib_get_dev(sc->ctx),
26094f1d91e4SNeel Chauhan 				   "Received ECC Err, initiating reset\n");
26104f1d91e4SNeel Chauhan 				hw->mac.flags |= ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
26114f1d91e4SNeel Chauhan 				ixgbe_reset_hw(hw);
26128eb6488eSEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC);
26138eb6488eSEric Joyner 			}
26148eb6488eSEric Joyner 
26158eb6488eSEric Joyner 		/* Check for over temp condition */
2616b1d5caf3SKevin Bowling 		if (sc->feat_en & IXGBE_FEATURE_TEMP_SENSOR) {
2617b1d5caf3SKevin Bowling 			switch (sc->hw.mac.type) {
26188eb6488eSEric Joyner 			case ixgbe_mac_X550EM_a:
26198eb6488eSEric Joyner 				if (!(eicr & IXGBE_EICR_GPI_SDP0_X550EM_a))
26208eb6488eSEric Joyner 					break;
26218eb6488eSEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_EIMC,
26228eb6488eSEric Joyner 				    IXGBE_EICR_GPI_SDP0_X550EM_a);
26238eb6488eSEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_EICR,
26248eb6488eSEric Joyner 				    IXGBE_EICR_GPI_SDP0_X550EM_a);
26258eb6488eSEric Joyner 				retval = hw->phy.ops.check_overtemp(hw);
26268eb6488eSEric Joyner 				if (retval != IXGBE_ERR_OVERTEMP)
26278eb6488eSEric Joyner 					break;
2628b1d5caf3SKevin Bowling 				device_printf(iflib_get_dev(sc->ctx),
2629c19c7afeSEric Joyner 				    "\nCRITICAL: OVER TEMP!! PHY IS SHUT DOWN!!\n");
2630b1d5caf3SKevin Bowling 				device_printf(iflib_get_dev(sc->ctx),
2631c19c7afeSEric Joyner 				    "System shutdown required!\n");
26328eb6488eSEric Joyner 				break;
26338eb6488eSEric Joyner 			default:
26348eb6488eSEric Joyner 				if (!(eicr & IXGBE_EICR_TS))
26358eb6488eSEric Joyner 					break;
26368eb6488eSEric Joyner 				retval = hw->phy.ops.check_overtemp(hw);
26378eb6488eSEric Joyner 				if (retval != IXGBE_ERR_OVERTEMP)
26388eb6488eSEric Joyner 					break;
2639b1d5caf3SKevin Bowling 				device_printf(iflib_get_dev(sc->ctx),
2640c19c7afeSEric Joyner 				    "\nCRITICAL: OVER TEMP!! PHY IS SHUT DOWN!!\n");
2641b1d5caf3SKevin Bowling 				device_printf(iflib_get_dev(sc->ctx),
2642c19c7afeSEric Joyner 				    "System shutdown required!\n");
26438eb6488eSEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS);
26448eb6488eSEric Joyner 				break;
26458eb6488eSEric Joyner 			}
26468eb6488eSEric Joyner 		}
26478eb6488eSEric Joyner 
26488eb6488eSEric Joyner 		/* Check for VF message */
2649b1d5caf3SKevin Bowling 		if ((sc->feat_en & IXGBE_FEATURE_SRIOV) &&
26508eb6488eSEric Joyner 		    (eicr & IXGBE_EICR_MAILBOX))
2651b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_MBX;
26528eb6488eSEric Joyner 	}
26538eb6488eSEric Joyner 
26548eb6488eSEric Joyner 	if (ixgbe_is_sfp(hw)) {
26558eb6488eSEric Joyner 		/* Pluggable optics-related interrupt */
26568eb6488eSEric Joyner 		if (hw->mac.type >= ixgbe_mac_X540)
26578eb6488eSEric Joyner 			eicr_mask = IXGBE_EICR_GPI_SDP0_X540;
26588eb6488eSEric Joyner 		else
26598eb6488eSEric Joyner 			eicr_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw);
26608eb6488eSEric Joyner 
26618eb6488eSEric Joyner 		if (eicr & eicr_mask) {
26628eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask);
2663b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_MOD;
26648eb6488eSEric Joyner 		}
26658eb6488eSEric Joyner 
26668eb6488eSEric Joyner 		if ((hw->mac.type == ixgbe_mac_82599EB) &&
26678eb6488eSEric Joyner 		    (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) {
26688eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR,
26698eb6488eSEric Joyner 			    IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
2670b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_MSF;
26718eb6488eSEric Joyner 		}
26728eb6488eSEric Joyner 	}
26738eb6488eSEric Joyner 
26748eb6488eSEric Joyner 	/* Check for fan failure */
2675b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_FAN_FAIL) {
2676b1d5caf3SKevin Bowling 		ixgbe_check_fan_failure(sc, eicr, true);
26778eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
26788eb6488eSEric Joyner 	}
26798eb6488eSEric Joyner 
26808eb6488eSEric Joyner 	/* External PHY interrupt */
26818eb6488eSEric Joyner 	if ((hw->phy.type == ixgbe_phy_x550em_ext_t) &&
26828eb6488eSEric Joyner 	    (eicr & IXGBE_EICR_GPI_SDP0_X540)) {
26838eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540);
2684b1d5caf3SKevin Bowling 		sc->task_requests |= IXGBE_REQUEST_TASK_PHY;
26858eb6488eSEric Joyner 	}
26868eb6488eSEric Joyner 
2687b1d5caf3SKevin Bowling 	return (sc->task_requests != 0) ? FILTER_SCHEDULE_THREAD : FILTER_HANDLED;
26888eb6488eSEric Joyner } /* ixgbe_msix_link */
26898eb6488eSEric Joyner 
26908eb6488eSEric Joyner /************************************************************************
26918eb6488eSEric Joyner  * ixgbe_sysctl_interrupt_rate_handler
26928eb6488eSEric Joyner  ************************************************************************/
2693758cc3dcSJack F Vogel static int
2694758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
2695758cc3dcSJack F Vogel {
2696c19c7afeSEric Joyner 	struct ix_rx_queue *que = ((struct ix_rx_queue *)oidp->oid_arg1);
26978eb6488eSEric Joyner 	int                error;
2698758cc3dcSJack F Vogel 	unsigned int       reg, usec, rate;
2699758cc3dcSJack F Vogel 
2700f72de14eSKevin Bowling 	if (atomic_load_acq_int(&que->sc->recovery_mode))
2701f72de14eSKevin Bowling 		return (EPERM);
2702f72de14eSKevin Bowling 
2703b1d5caf3SKevin Bowling 	reg = IXGBE_READ_REG(&que->sc->hw, IXGBE_EITR(que->msix));
2704758cc3dcSJack F Vogel 	usec = ((reg & 0x0FF8) >> 3);
2705758cc3dcSJack F Vogel 	if (usec > 0)
2706758cc3dcSJack F Vogel 		rate = 500000 / usec;
2707758cc3dcSJack F Vogel 	else
2708758cc3dcSJack F Vogel 		rate = 0;
2709758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &rate, 0, req);
2710758cc3dcSJack F Vogel 	if (error || !req->newptr)
2711758cc3dcSJack F Vogel 		return error;
2712758cc3dcSJack F Vogel 	reg &= ~0xfff; /* default, no limitation */
2713758cc3dcSJack F Vogel 	ixgbe_max_interrupt_rate = 0;
2714758cc3dcSJack F Vogel 	if (rate > 0 && rate < 500000) {
2715758cc3dcSJack F Vogel 		if (rate < 1000)
2716758cc3dcSJack F Vogel 			rate = 1000;
2717758cc3dcSJack F Vogel 		ixgbe_max_interrupt_rate = rate;
2718758cc3dcSJack F Vogel 		reg |= ((4000000/rate) & 0xff8);
2719758cc3dcSJack F Vogel 	}
2720b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(&que->sc->hw, IXGBE_EITR(que->msix), reg);
2721758cc3dcSJack F Vogel 
27228eb6488eSEric Joyner 	return (0);
27238eb6488eSEric Joyner } /* ixgbe_sysctl_interrupt_rate_handler */
27248eb6488eSEric Joyner 
27258eb6488eSEric Joyner /************************************************************************
27268eb6488eSEric Joyner  * ixgbe_add_device_sysctls
27278eb6488eSEric Joyner  ************************************************************************/
27286f37f232SEric Joyner static void
2729c19c7afeSEric Joyner ixgbe_add_device_sysctls(if_ctx_t ctx)
27306f37f232SEric Joyner {
2731b1d5caf3SKevin Bowling 	struct ixgbe_softc         *sc = iflib_get_softc(ctx);
2732c19c7afeSEric Joyner 	device_t               dev = iflib_get_dev(ctx);
2733b1d5caf3SKevin Bowling 	struct ixgbe_hw        *hw = &sc->hw;
27346f37f232SEric Joyner 	struct sysctl_oid_list *child;
2735c19c7afeSEric Joyner 	struct sysctl_ctx_list *ctx_list;
27366f37f232SEric Joyner 
2737c19c7afeSEric Joyner 	ctx_list = device_get_sysctl_ctx(dev);
27386f37f232SEric Joyner 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
27396f37f232SEric Joyner 
27406f37f232SEric Joyner 	/* Sysctls for all devices */
2741c19c7afeSEric Joyner 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "fc",
2742f72de14eSKevin Bowling 	    CTLTYPE_INT | CTLFLAG_RW,
2743b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_sysctl_flowcntl, "I",
2744c19c7afeSEric Joyner 	    IXGBE_SYSCTL_DESC_SET_FC);
27456f37f232SEric Joyner 
2746c19c7afeSEric Joyner 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "advertise_speed",
2747f72de14eSKevin Bowling 	    CTLTYPE_INT | CTLFLAG_RW,
2748b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_sysctl_advertise, "I",
27498eb6488eSEric Joyner 	    IXGBE_SYSCTL_DESC_ADV_SPEED);
27506f37f232SEric Joyner 
2751b1d5caf3SKevin Bowling 	sc->enable_aim = ixgbe_enable_aim;
275264881da4SSai Rajesh Tallamraju 	SYSCTL_ADD_INT(ctx_list, child, OID_AUTO, "enable_aim", CTLFLAG_RW,
2753b1d5caf3SKevin Bowling 	    &sc->enable_aim, 0, "Interrupt Moderation");
275464881da4SSai Rajesh Tallamraju 
27557660e4eaSKevin Bowling 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "fw_version",
2756f72de14eSKevin Bowling 	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
27577660e4eaSKevin Bowling 	    ixgbe_sysctl_print_fw_version, "A", "Prints FW/NVM Versions");
27587660e4eaSKevin Bowling 
2759a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
2760a9ca1c79SSean Bruno 	/* testing sysctls (for all devices) */
2761c19c7afeSEric Joyner 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "power_state",
2762f72de14eSKevin Bowling 	    CTLTYPE_INT | CTLFLAG_RW,
2763b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_sysctl_power_state,
27648eb6488eSEric Joyner 	    "I", "PCI Power State");
2765a9ca1c79SSean Bruno 
2766c19c7afeSEric Joyner 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "print_rss_config",
2767f72de14eSKevin Bowling 	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
2768a9ca1c79SSean Bruno 	    ixgbe_sysctl_print_rss_config, "A", "Prints RSS Configuration");
2769a9ca1c79SSean Bruno #endif
2770a9ca1c79SSean Bruno 	/* for X550 series devices */
27716f37f232SEric Joyner 	if (hw->mac.type >= ixgbe_mac_X550)
2772c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "dmac",
2773f72de14eSKevin Bowling 		    CTLTYPE_U16 | CTLFLAG_RW,
2774b1d5caf3SKevin Bowling 		    sc, 0, ixgbe_sysctl_dmac,
27758eb6488eSEric Joyner 		    "I", "DMA Coalesce");
27766f37f232SEric Joyner 
2777a9ca1c79SSean Bruno 	/* for WoL-capable devices */
2778a9ca1c79SSean Bruno 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
2779c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "wol_enable",
2780f72de14eSKevin Bowling 		    CTLTYPE_INT | CTLFLAG_RW, sc, 0,
27818eb6488eSEric Joyner 		    ixgbe_sysctl_wol_enable, "I", "Enable/Disable Wake on LAN");
27826f37f232SEric Joyner 
2783c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "wufc",
2784f72de14eSKevin Bowling 		    CTLTYPE_U32 | CTLFLAG_RW,
2785b1d5caf3SKevin Bowling 		    sc, 0, ixgbe_sysctl_wufc,
27868eb6488eSEric Joyner 		    "I", "Enable/Disable Wake Up Filters");
27876f37f232SEric Joyner 	}
27886f37f232SEric Joyner 
2789a9ca1c79SSean Bruno 	/* for X552/X557-AT devices */
27906f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
27916f37f232SEric Joyner 		struct sysctl_oid *phy_node;
27926f37f232SEric Joyner 		struct sysctl_oid_list *phy_list;
27936f37f232SEric Joyner 
2794c19c7afeSEric Joyner 		phy_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, "phy",
279520b91f0aSPawel Biernacki 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "External PHY sysctls");
27966f37f232SEric Joyner 		phy_list = SYSCTL_CHILDREN(phy_node);
27976f37f232SEric Joyner 
2798c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, phy_list, OID_AUTO, "temp",
2799f72de14eSKevin Bowling 		    CTLTYPE_U16 | CTLFLAG_RD,
2800b1d5caf3SKevin Bowling 		    sc, 0, ixgbe_sysctl_phy_temp,
28018eb6488eSEric Joyner 		    "I", "Current External PHY Temperature (Celsius)");
28026f37f232SEric Joyner 
2803c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, phy_list, OID_AUTO,
280420b91f0aSPawel Biernacki 		    "overtemp_occurred",
2805f72de14eSKevin Bowling 		    CTLTYPE_U16 | CTLFLAG_RD, sc, 0,
28066f37f232SEric Joyner 		    ixgbe_sysctl_phy_overtemp_occurred, "I",
28076f37f232SEric Joyner 		    "External PHY High Temperature Event Occurred");
28086f37f232SEric Joyner 	}
28098eb6488eSEric Joyner 
2810b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_EEE) {
2811c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "eee_state",
2812f72de14eSKevin Bowling 		    CTLTYPE_INT | CTLFLAG_RW, sc, 0,
28138eb6488eSEric Joyner 		    ixgbe_sysctl_eee_state, "I", "EEE Power Save State");
28148eb6488eSEric Joyner 	}
28158eb6488eSEric Joyner } /* ixgbe_add_device_sysctls */
28168eb6488eSEric Joyner 
28178eb6488eSEric Joyner /************************************************************************
28188eb6488eSEric Joyner  * ixgbe_allocate_pci_resources
28198eb6488eSEric Joyner  ************************************************************************/
28208eb6488eSEric Joyner static int
2821c19c7afeSEric Joyner ixgbe_allocate_pci_resources(if_ctx_t ctx)
28228eb6488eSEric Joyner {
2823b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
2824c19c7afeSEric Joyner 	device_t        dev = iflib_get_dev(ctx);
28258eb6488eSEric Joyner 	int             rid;
28268eb6488eSEric Joyner 
28278eb6488eSEric Joyner 	rid = PCIR_BAR(0);
2828b1d5caf3SKevin Bowling 	sc->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
28298eb6488eSEric Joyner 	    RF_ACTIVE);
28308eb6488eSEric Joyner 
2831b1d5caf3SKevin Bowling 	if (!(sc->pci_mem)) {
28328eb6488eSEric Joyner 		device_printf(dev, "Unable to allocate bus resource: memory\n");
28338eb6488eSEric Joyner 		return (ENXIO);
28348eb6488eSEric Joyner 	}
28358eb6488eSEric Joyner 
28368eb6488eSEric Joyner 	/* Save bus_space values for READ/WRITE_REG macros */
2837b1d5caf3SKevin Bowling 	sc->osdep.mem_bus_space_tag = rman_get_bustag(sc->pci_mem);
2838b1d5caf3SKevin Bowling 	sc->osdep.mem_bus_space_handle =
2839b1d5caf3SKevin Bowling 	    rman_get_bushandle(sc->pci_mem);
28408eb6488eSEric Joyner 	/* Set hw values for shared code */
2841b1d5caf3SKevin Bowling 	sc->hw.hw_addr = (u8 *)&sc->osdep.mem_bus_space_handle;
28428eb6488eSEric Joyner 
28438eb6488eSEric Joyner 	return (0);
28448eb6488eSEric Joyner } /* ixgbe_allocate_pci_resources */
28458eb6488eSEric Joyner 
28468eb6488eSEric Joyner /************************************************************************
28478eb6488eSEric Joyner  * ixgbe_detach - Device removal routine
28488eb6488eSEric Joyner  *
28498eb6488eSEric Joyner  *   Called when the driver is being removed.
28508eb6488eSEric Joyner  *   Stops the adapter and deallocates all the resources
28518eb6488eSEric Joyner  *   that were allocated for driver operation.
28528eb6488eSEric Joyner  *
28538eb6488eSEric Joyner  *   return 0 on success, positive on failure
28548eb6488eSEric Joyner  ************************************************************************/
28558eb6488eSEric Joyner static int
2856c19c7afeSEric Joyner ixgbe_if_detach(if_ctx_t ctx)
28578eb6488eSEric Joyner {
2858b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
2859c19c7afeSEric Joyner 	device_t       dev = iflib_get_dev(ctx);
28608eb6488eSEric Joyner 	u32            ctrl_ext;
28618eb6488eSEric Joyner 
28628eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_detach: begin");
28638eb6488eSEric Joyner 
28648eb6488eSEric Joyner 	if (ixgbe_pci_iov_detach(dev) != 0) {
28658eb6488eSEric Joyner 		device_printf(dev, "SR-IOV in use; detach first.\n");
28668eb6488eSEric Joyner 		return (EBUSY);
28678eb6488eSEric Joyner 	}
28688eb6488eSEric Joyner 
2869c19c7afeSEric Joyner 	ixgbe_setup_low_power_mode(ctx);
28708eb6488eSEric Joyner 
28718eb6488eSEric Joyner 	/* let hardware know driver is unloading */
2872b1d5caf3SKevin Bowling 	ctrl_ext = IXGBE_READ_REG(&sc->hw, IXGBE_CTRL_EXT);
28738eb6488eSEric Joyner 	ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
2874b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(&sc->hw, IXGBE_CTRL_EXT, ctrl_ext);
28758eb6488eSEric Joyner 
2876f72de14eSKevin Bowling 	callout_drain(&sc->fw_mode_timer);
2877f72de14eSKevin Bowling 
2878c19c7afeSEric Joyner 	ixgbe_free_pci_resources(ctx);
2879b1d5caf3SKevin Bowling 	free(sc->mta, M_IXGBE);
28808eb6488eSEric Joyner 
28818eb6488eSEric Joyner 	return (0);
2882c19c7afeSEric Joyner } /* ixgbe_if_detach */
28838eb6488eSEric Joyner 
28848eb6488eSEric Joyner /************************************************************************
28858eb6488eSEric Joyner  * ixgbe_setup_low_power_mode - LPLU/WoL preparation
28868eb6488eSEric Joyner  *
28878eb6488eSEric Joyner  *   Prepare the adapter/port for LPLU and/or WoL
28888eb6488eSEric Joyner  ************************************************************************/
28898eb6488eSEric Joyner static int
2890c19c7afeSEric Joyner ixgbe_setup_low_power_mode(if_ctx_t ctx)
28918eb6488eSEric Joyner {
2892b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = iflib_get_softc(ctx);
2893b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
2894c19c7afeSEric Joyner 	device_t        dev = iflib_get_dev(ctx);
28958eb6488eSEric Joyner 	s32             error = 0;
28968eb6488eSEric Joyner 
2897c19c7afeSEric Joyner 	if (!hw->wol_enabled)
289879b36ec9SKevin Bowling 		ixgbe_set_phy_power(hw, false);
28998eb6488eSEric Joyner 
29008eb6488eSEric Joyner 	/* Limit power management flow to X550EM baseT */
29018eb6488eSEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
29028eb6488eSEric Joyner 	    hw->phy.ops.enter_lplu) {
29038eb6488eSEric Joyner 		/* Turn off support for APM wakeup. (Using ACPI instead) */
290473fa89e0SPiotr Pietruszewski 		IXGBE_WRITE_REG(hw, IXGBE_GRC_BY_MAC(hw),
290573fa89e0SPiotr Pietruszewski 		    IXGBE_READ_REG(hw, IXGBE_GRC_BY_MAC(hw)) & ~(u32)2);
29068eb6488eSEric Joyner 
29078eb6488eSEric Joyner 		/*
29088eb6488eSEric Joyner 		 * Clear Wake Up Status register to prevent any previous wakeup
29098eb6488eSEric Joyner 		 * events from waking us up immediately after we suspend.
29108eb6488eSEric Joyner 		 */
29118eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
29128eb6488eSEric Joyner 
29138eb6488eSEric Joyner 		/*
29148eb6488eSEric Joyner 		 * Program the Wakeup Filter Control register with user filter
29158eb6488eSEric Joyner 		 * settings
29168eb6488eSEric Joyner 		 */
2917b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(hw, IXGBE_WUFC, sc->wufc);
29188eb6488eSEric Joyner 
29198eb6488eSEric Joyner 		/* Enable wakeups and power management in Wakeup Control */
29208eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_WUC,
29218eb6488eSEric Joyner 		    IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN);
29228eb6488eSEric Joyner 
29238eb6488eSEric Joyner 		/* X550EM baseT adapters need a special LPLU flow */
292479b36ec9SKevin Bowling 		hw->phy.reset_disable = true;
2925c19c7afeSEric Joyner 		ixgbe_if_stop(ctx);
29268eb6488eSEric Joyner 		error = hw->phy.ops.enter_lplu(hw);
29278eb6488eSEric Joyner 		if (error)
29288eb6488eSEric Joyner 			device_printf(dev, "Error entering LPLU: %d\n", error);
292979b36ec9SKevin Bowling 		hw->phy.reset_disable = false;
29308eb6488eSEric Joyner 	} else {
29318eb6488eSEric Joyner 		/* Just stop for other adapters */
2932c19c7afeSEric Joyner 		ixgbe_if_stop(ctx);
29338eb6488eSEric Joyner 	}
29348eb6488eSEric Joyner 
29358eb6488eSEric Joyner 	return error;
29368eb6488eSEric Joyner } /* ixgbe_setup_low_power_mode */
29378eb6488eSEric Joyner 
29388eb6488eSEric Joyner /************************************************************************
29398eb6488eSEric Joyner  * ixgbe_shutdown - Shutdown entry point
29408eb6488eSEric Joyner  ************************************************************************/
29418eb6488eSEric Joyner static int
2942c19c7afeSEric Joyner ixgbe_if_shutdown(if_ctx_t ctx)
29438eb6488eSEric Joyner {
29448eb6488eSEric Joyner 	int error = 0;
29458eb6488eSEric Joyner 
29468eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_shutdown: begin");
29478eb6488eSEric Joyner 
2948c19c7afeSEric Joyner 	error = ixgbe_setup_low_power_mode(ctx);
29498eb6488eSEric Joyner 
29508eb6488eSEric Joyner 	return (error);
2951c19c7afeSEric Joyner } /* ixgbe_if_shutdown */
29528eb6488eSEric Joyner 
29538eb6488eSEric Joyner /************************************************************************
29548eb6488eSEric Joyner  * ixgbe_suspend
29558eb6488eSEric Joyner  *
29568eb6488eSEric Joyner  *   From D0 to D3
29578eb6488eSEric Joyner  ************************************************************************/
29588eb6488eSEric Joyner static int
2959c19c7afeSEric Joyner ixgbe_if_suspend(if_ctx_t ctx)
29608eb6488eSEric Joyner {
29618eb6488eSEric Joyner 	int error = 0;
29628eb6488eSEric Joyner 
29638eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_suspend: begin");
29648eb6488eSEric Joyner 
2965c19c7afeSEric Joyner 	error = ixgbe_setup_low_power_mode(ctx);
29668eb6488eSEric Joyner 
29678eb6488eSEric Joyner 	return (error);
2968c19c7afeSEric Joyner } /* ixgbe_if_suspend */
29698eb6488eSEric Joyner 
29708eb6488eSEric Joyner /************************************************************************
29718eb6488eSEric Joyner  * ixgbe_resume
29728eb6488eSEric Joyner  *
29738eb6488eSEric Joyner  *   From D3 to D0
29748eb6488eSEric Joyner  ************************************************************************/
29758eb6488eSEric Joyner static int
2976c19c7afeSEric Joyner ixgbe_if_resume(if_ctx_t ctx)
29778eb6488eSEric Joyner {
2978b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = iflib_get_softc(ctx);
2979c19c7afeSEric Joyner 	device_t        dev = iflib_get_dev(ctx);
2980ff06a8dbSJustin Hibbits 	if_t            ifp = iflib_get_ifp(ctx);
2981b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
29828eb6488eSEric Joyner 	u32             wus;
29838eb6488eSEric Joyner 
29848eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_resume: begin");
29858eb6488eSEric Joyner 
29868eb6488eSEric Joyner 	/* Read & clear WUS register */
29878eb6488eSEric Joyner 	wus = IXGBE_READ_REG(hw, IXGBE_WUS);
29888eb6488eSEric Joyner 	if (wus)
29898eb6488eSEric Joyner 		device_printf(dev, "Woken up by (WUS): %#010x\n",
29908eb6488eSEric Joyner 		    IXGBE_READ_REG(hw, IXGBE_WUS));
29918eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
29928eb6488eSEric Joyner 	/* And clear WUFC until next low-power transition */
29938eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0);
29948eb6488eSEric Joyner 
29958eb6488eSEric Joyner 	/*
29968eb6488eSEric Joyner 	 * Required after D3->D0 transition;
29978eb6488eSEric Joyner 	 * will re-advertise all previous advertised speeds
29988eb6488eSEric Joyner 	 */
2999ff06a8dbSJustin Hibbits 	if (if_getflags(ifp) & IFF_UP)
3000c19c7afeSEric Joyner 		ixgbe_if_init(ctx);
30018eb6488eSEric Joyner 
30028eb6488eSEric Joyner 	return (0);
3003c19c7afeSEric Joyner } /* ixgbe_if_resume */
30048eb6488eSEric Joyner 
30058eb6488eSEric Joyner /************************************************************************
3006c19c7afeSEric Joyner  * ixgbe_if_mtu_set - Ioctl mtu entry point
30078eb6488eSEric Joyner  *
3008c19c7afeSEric Joyner  *   Return 0 on success, EINVAL on failure
3009c19c7afeSEric Joyner  ************************************************************************/
3010c19c7afeSEric Joyner static int
3011c19c7afeSEric Joyner ixgbe_if_mtu_set(if_ctx_t ctx, uint32_t mtu)
3012c19c7afeSEric Joyner {
3013b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3014c19c7afeSEric Joyner 	int error = 0;
3015c19c7afeSEric Joyner 
3016c19c7afeSEric Joyner 	IOCTL_DEBUGOUT("ioctl: SIOCIFMTU (Set Interface MTU)");
3017c19c7afeSEric Joyner 
3018c19c7afeSEric Joyner 	if (mtu > IXGBE_MAX_MTU) {
3019c19c7afeSEric Joyner 		error = EINVAL;
3020c19c7afeSEric Joyner 	} else {
3021b1d5caf3SKevin Bowling 		sc->max_frame_size = mtu + IXGBE_MTU_HDR;
3022c19c7afeSEric Joyner 	}
3023c19c7afeSEric Joyner 
3024c19c7afeSEric Joyner 	return error;
3025c19c7afeSEric Joyner } /* ixgbe_if_mtu_set */
3026c19c7afeSEric Joyner 
3027c19c7afeSEric Joyner /************************************************************************
3028c19c7afeSEric Joyner  * ixgbe_if_crcstrip_set
30298eb6488eSEric Joyner  ************************************************************************/
30308eb6488eSEric Joyner static void
3031c19c7afeSEric Joyner ixgbe_if_crcstrip_set(if_ctx_t ctx, int onoff, int crcstrip)
30328eb6488eSEric Joyner {
3033b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3034c19c7afeSEric Joyner 	struct ixgbe_hw *hw = &sc->hw;
3035c19c7afeSEric Joyner 	/* crc stripping is set in two places:
3036c19c7afeSEric Joyner 	 * IXGBE_HLREG0 (modified on init_locked and hw reset)
3037c19c7afeSEric Joyner 	 * IXGBE_RDRXCTL (set by the original driver in
3038c19c7afeSEric Joyner 	 *	ixgbe_setup_hw_rsc() called in init_locked.
3039c19c7afeSEric Joyner 	 *	We disable the setting when netmap is compiled in).
3040c19c7afeSEric Joyner 	 * We update the values here, but also in ixgbe.c because
3041c19c7afeSEric Joyner 	 * init_locked sometimes is called outside our control.
3042c19c7afeSEric Joyner 	 */
3043c19c7afeSEric Joyner 	uint32_t hl, rxc;
30448eb6488eSEric Joyner 
3045c19c7afeSEric Joyner 	hl = IXGBE_READ_REG(hw, IXGBE_HLREG0);
3046c19c7afeSEric Joyner 	rxc = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
3047c19c7afeSEric Joyner #ifdef NETMAP
3048c19c7afeSEric Joyner 	if (netmap_verbose)
3049c19c7afeSEric Joyner 		D("%s read  HLREG 0x%x rxc 0x%x",
3050c19c7afeSEric Joyner 			onoff ? "enter" : "exit", hl, rxc);
30518eb6488eSEric Joyner #endif
3052c19c7afeSEric Joyner 	/* hw requirements ... */
3053c19c7afeSEric Joyner 	rxc &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
3054c19c7afeSEric Joyner 	rxc |= IXGBE_RDRXCTL_RSCACKC;
3055c19c7afeSEric Joyner 	if (onoff && !crcstrip) {
3056c19c7afeSEric Joyner 		/* keep the crc. Fast rx */
3057c19c7afeSEric Joyner 		hl &= ~IXGBE_HLREG0_RXCRCSTRP;
3058c19c7afeSEric Joyner 		rxc &= ~IXGBE_RDRXCTL_CRCSTRIP;
3059c19c7afeSEric Joyner 	} else {
3060c19c7afeSEric Joyner 		/* reset default mode */
3061c19c7afeSEric Joyner 		hl |= IXGBE_HLREG0_RXCRCSTRP;
3062c19c7afeSEric Joyner 		rxc |= IXGBE_RDRXCTL_CRCSTRIP;
3063c19c7afeSEric Joyner 	}
3064c19c7afeSEric Joyner #ifdef NETMAP
3065c19c7afeSEric Joyner 	if (netmap_verbose)
3066c19c7afeSEric Joyner 		D("%s write HLREG 0x%x rxc 0x%x",
3067c19c7afeSEric Joyner 			onoff ? "enter" : "exit", hl, rxc);
3068c19c7afeSEric Joyner #endif
3069c19c7afeSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hl);
3070c19c7afeSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rxc);
3071c19c7afeSEric Joyner } /* ixgbe_if_crcstrip_set */
30728eb6488eSEric Joyner 
3073c19c7afeSEric Joyner /*********************************************************************
3074c19c7afeSEric Joyner  * ixgbe_if_init - Init entry point
30758eb6488eSEric Joyner  *
30768eb6488eSEric Joyner  *   Used in two ways: It is used by the stack as an init
30778eb6488eSEric Joyner  *   entry point in network interface structure. It is also
30788eb6488eSEric Joyner  *   used by the driver as a hw/sw initialization routine to
30798eb6488eSEric Joyner  *   get to a consistent state.
30808eb6488eSEric Joyner  *
3081c19c7afeSEric Joyner  *   Return 0 on success, positive on failure
3082c19c7afeSEric Joyner  **********************************************************************/
30838eb6488eSEric Joyner void
3084c19c7afeSEric Joyner ixgbe_if_init(if_ctx_t ctx)
30858eb6488eSEric Joyner {
3086b1d5caf3SKevin Bowling 	struct ixgbe_softc     *sc = iflib_get_softc(ctx);
3087ff06a8dbSJustin Hibbits 	if_t               ifp = iflib_get_ifp(ctx);
3088c19c7afeSEric Joyner 	device_t           dev = iflib_get_dev(ctx);
3089b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3090c19c7afeSEric Joyner 	struct ix_rx_queue *rx_que;
3091c19c7afeSEric Joyner 	struct ix_tx_queue *tx_que;
30928eb6488eSEric Joyner 	u32             txdctl, mhadd;
30938eb6488eSEric Joyner 	u32             rxdctl, rxctrl;
30948eb6488eSEric Joyner 	u32             ctrl_ext;
30958eb6488eSEric Joyner 
3096c19c7afeSEric Joyner 	int             i, j, err;
30978eb6488eSEric Joyner 
3098c19c7afeSEric Joyner 	INIT_DEBUGOUT("ixgbe_if_init: begin");
30998eb6488eSEric Joyner 
31008eb6488eSEric Joyner 	/* Queue indices may change with IOV mode */
3101b1d5caf3SKevin Bowling 	ixgbe_align_all_queue_indices(sc);
31028eb6488eSEric Joyner 
31038eb6488eSEric Joyner 	/* reprogram the RAR[0] in case user changed it. */
3104b1d5caf3SKevin Bowling 	ixgbe_set_rar(hw, 0, hw->mac.addr, sc->pool, IXGBE_RAH_AV);
31058eb6488eSEric Joyner 
31068eb6488eSEric Joyner 	/* Get the latest mac address, User can use a LAA */
3107ff06a8dbSJustin Hibbits 	bcopy(if_getlladdr(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
3108b1d5caf3SKevin Bowling 	ixgbe_set_rar(hw, 0, hw->mac.addr, sc->pool, 1);
31098eb6488eSEric Joyner 	hw->addr_ctrl.rar_used_count = 1;
31108eb6488eSEric Joyner 
31118eb6488eSEric Joyner 	ixgbe_init_hw(hw);
3112c19c7afeSEric Joyner 
3113b1d5caf3SKevin Bowling 	ixgbe_initialize_iov(sc);
3114c19c7afeSEric Joyner 
3115c19c7afeSEric Joyner 	ixgbe_initialize_transmit_units(ctx);
31168eb6488eSEric Joyner 
31178eb6488eSEric Joyner 	/* Setup Multicast table */
3118c19c7afeSEric Joyner 	ixgbe_if_multi_set(ctx);
31198eb6488eSEric Joyner 
31208eb6488eSEric Joyner 	/* Determine the correct mbuf pool, based on frame size */
3121b1d5caf3SKevin Bowling 	sc->rx_mbuf_sz = iflib_get_rx_mbuf_sz(ctx);
31228eb6488eSEric Joyner 
31238eb6488eSEric Joyner 	/* Configure RX settings */
3124c19c7afeSEric Joyner 	ixgbe_initialize_receive_units(ctx);
31258eb6488eSEric Joyner 
3126b2c1e8e6SEric Joyner 	/*
3127b2c1e8e6SEric Joyner 	 * Initialize variable holding task enqueue requests
3128b2c1e8e6SEric Joyner 	 * from MSI-X interrupts
3129b2c1e8e6SEric Joyner 	 */
3130b1d5caf3SKevin Bowling 	sc->task_requests = 0;
3131b2c1e8e6SEric Joyner 
31328eb6488eSEric Joyner 	/* Enable SDP & MSI-X interrupts based on adapter */
3133b1d5caf3SKevin Bowling 	ixgbe_config_gpie(sc);
31348eb6488eSEric Joyner 
31358eb6488eSEric Joyner 	/* Set MTU size */
3136ff06a8dbSJustin Hibbits 	if (if_getmtu(ifp) > ETHERMTU) {
31378eb6488eSEric Joyner 		/* aka IXGBE_MAXFRS on 82599 and newer */
31388eb6488eSEric Joyner 		mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
31398eb6488eSEric Joyner 		mhadd &= ~IXGBE_MHADD_MFS_MASK;
3140b1d5caf3SKevin Bowling 		mhadd |= sc->max_frame_size << IXGBE_MHADD_MFS_SHIFT;
31418eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
31428eb6488eSEric Joyner 	}
31438eb6488eSEric Joyner 
31448eb6488eSEric Joyner 	/* Now enable all the queues */
3145b1d5caf3SKevin Bowling 	for (i = 0, tx_que = sc->tx_queues; i < sc->num_tx_queues; i++, tx_que++) {
3146c19c7afeSEric Joyner 		struct tx_ring *txr = &tx_que->txr;
3147c19c7afeSEric Joyner 
31488eb6488eSEric Joyner 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txr->me));
31498eb6488eSEric Joyner 		txdctl |= IXGBE_TXDCTL_ENABLE;
31508eb6488eSEric Joyner 		/* Set WTHRESH to 8, burst writeback */
31518eb6488eSEric Joyner 		txdctl |= (8 << 16);
31528eb6488eSEric Joyner 		/*
31538eb6488eSEric Joyner 		 * When the internal queue falls below PTHRESH (32),
31548eb6488eSEric Joyner 		 * start prefetching as long as there are at least
31558eb6488eSEric Joyner 		 * HTHRESH (1) buffers ready. The values are taken
31568eb6488eSEric Joyner 		 * from the Intel linux driver 3.8.21.
31578eb6488eSEric Joyner 		 * Prefetching enables tx line rate even with 1 queue.
31588eb6488eSEric Joyner 		 */
31598eb6488eSEric Joyner 		txdctl |= (32 << 0) | (1 << 8);
31608eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txr->me), txdctl);
31618eb6488eSEric Joyner 	}
31628eb6488eSEric Joyner 
3163b1d5caf3SKevin Bowling 	for (i = 0, rx_que = sc->rx_queues; i < sc->num_rx_queues; i++, rx_que++) {
3164c19c7afeSEric Joyner 		struct rx_ring *rxr = &rx_que->rxr;
3165c19c7afeSEric Joyner 
31668eb6488eSEric Joyner 		rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me));
31678eb6488eSEric Joyner 		if (hw->mac.type == ixgbe_mac_82598EB) {
31688eb6488eSEric Joyner 			/*
31698eb6488eSEric Joyner 			 * PTHRESH = 21
31708eb6488eSEric Joyner 			 * HTHRESH = 4
31718eb6488eSEric Joyner 			 * WTHRESH = 8
31728eb6488eSEric Joyner 			 */
31738eb6488eSEric Joyner 			rxdctl &= ~0x3FFFFF;
31748eb6488eSEric Joyner 			rxdctl |= 0x080420;
31758eb6488eSEric Joyner 		}
31768eb6488eSEric Joyner 		rxdctl |= IXGBE_RXDCTL_ENABLE;
31778eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), rxdctl);
3178c19c7afeSEric Joyner 		for (j = 0; j < 10; j++) {
31798eb6488eSEric Joyner 			if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)) &
31808eb6488eSEric Joyner 			    IXGBE_RXDCTL_ENABLE)
31818eb6488eSEric Joyner 				break;
31828eb6488eSEric Joyner 			else
31838eb6488eSEric Joyner 				msec_delay(1);
31848eb6488eSEric Joyner 		}
31858eb6488eSEric Joyner 		wmb();
31868eb6488eSEric Joyner 	}
31878eb6488eSEric Joyner 
31888eb6488eSEric Joyner 	/* Enable Receive engine */
31898eb6488eSEric Joyner 	rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
31908eb6488eSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB)
31918eb6488eSEric Joyner 		rxctrl |= IXGBE_RXCTRL_DMBYPS;
31928eb6488eSEric Joyner 	rxctrl |= IXGBE_RXCTRL_RXEN;
31938eb6488eSEric Joyner 	ixgbe_enable_rx_dma(hw, rxctrl);
31948eb6488eSEric Joyner 
3195c19c7afeSEric Joyner 	/* Set up MSI/MSI-X routing */
3196c19c7afeSEric Joyner 	if (ixgbe_enable_msix)  {
3197b1d5caf3SKevin Bowling 		ixgbe_configure_ivars(sc);
31988eb6488eSEric Joyner 		/* Set up auto-mask */
31998eb6488eSEric Joyner 		if (hw->mac.type == ixgbe_mac_82598EB)
32008eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
32018eb6488eSEric Joyner 		else {
32028eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF);
32038eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF);
32048eb6488eSEric Joyner 		}
32058eb6488eSEric Joyner 	} else {  /* Simple settings for Legacy/MSI */
3206b1d5caf3SKevin Bowling 		ixgbe_set_ivar(sc, 0, 0, 0);
3207b1d5caf3SKevin Bowling 		ixgbe_set_ivar(sc, 0, 0, 1);
32088eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
32098eb6488eSEric Joyner 	}
32108eb6488eSEric Joyner 
3211b1d5caf3SKevin Bowling 	ixgbe_init_fdir(sc);
32128eb6488eSEric Joyner 
32138eb6488eSEric Joyner 	/*
32148eb6488eSEric Joyner 	 * Check on any SFP devices that
32158eb6488eSEric Joyner 	 * need to be kick-started
32168eb6488eSEric Joyner 	 */
32178eb6488eSEric Joyner 	if (hw->phy.type == ixgbe_phy_none) {
32188eb6488eSEric Joyner 		err = hw->phy.ops.identify(hw);
32198eb6488eSEric Joyner 		if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
32208eb6488eSEric Joyner 			device_printf(dev,
32218eb6488eSEric Joyner 			    "Unsupported SFP+ module type was detected.\n");
32228eb6488eSEric Joyner 			return;
32238eb6488eSEric Joyner 		}
32248eb6488eSEric Joyner 	}
32258eb6488eSEric Joyner 
32268eb6488eSEric Joyner 	/* Set moderation on the Link interrupt */
3227b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(hw, IXGBE_EITR(sc->vector), IXGBE_LINK_ITR);
32288eb6488eSEric Joyner 
3229c19c7afeSEric Joyner 	/* Enable power to the phy. */
323079b36ec9SKevin Bowling 	ixgbe_set_phy_power(hw, true);
3231c19c7afeSEric Joyner 
32328eb6488eSEric Joyner 	/* Config/Enable Link */
3233b2c1e8e6SEric Joyner 	ixgbe_config_link(ctx);
32348eb6488eSEric Joyner 
32358eb6488eSEric Joyner 	/* Hardware Packet Buffer & Flow Control setup */
3236b1d5caf3SKevin Bowling 	ixgbe_config_delay_values(sc);
32378eb6488eSEric Joyner 
32388eb6488eSEric Joyner 	/* Initialize the FC settings */
32398eb6488eSEric Joyner 	ixgbe_start_hw(hw);
32408eb6488eSEric Joyner 
32418eb6488eSEric Joyner 	/* Set up VLAN support and filter */
3242c19c7afeSEric Joyner 	ixgbe_setup_vlan_hw_support(ctx);
32438eb6488eSEric Joyner 
32448eb6488eSEric Joyner 	/* Setup DMA Coalescing */
3245b1d5caf3SKevin Bowling 	ixgbe_config_dmac(sc);
32468eb6488eSEric Joyner 
32478eb6488eSEric Joyner 	/* And now turn on interrupts */
3248c19c7afeSEric Joyner 	ixgbe_if_enable_intr(ctx);
32498eb6488eSEric Joyner 
32508eb6488eSEric Joyner 	/* Enable the use of the MBX by the VF's */
3251b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_SRIOV) {
32528eb6488eSEric Joyner 		ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
32538eb6488eSEric Joyner 		ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
32548eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
32558eb6488eSEric Joyner 	}
32568eb6488eSEric Joyner 
32578eb6488eSEric Joyner } /* ixgbe_init_locked */
32588eb6488eSEric Joyner 
32598eb6488eSEric Joyner /************************************************************************
32608eb6488eSEric Joyner  * ixgbe_set_ivar
32618eb6488eSEric Joyner  *
32628eb6488eSEric Joyner  *   Setup the correct IVAR register for a particular MSI-X interrupt
32638eb6488eSEric Joyner  *     (yes this is all very magic and confusing :)
32648eb6488eSEric Joyner  *    - entry is the register array entry
32658eb6488eSEric Joyner  *    - vector is the MSI-X vector for this queue
32668eb6488eSEric Joyner  *    - type is RX/TX/MISC
32678eb6488eSEric Joyner  ************************************************************************/
32688eb6488eSEric Joyner static void
3269b1d5caf3SKevin Bowling ixgbe_set_ivar(struct ixgbe_softc *sc, u8 entry, u8 vector, s8 type)
32708eb6488eSEric Joyner {
3271b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
32728eb6488eSEric Joyner 	u32 ivar, index;
32738eb6488eSEric Joyner 
32748eb6488eSEric Joyner 	vector |= IXGBE_IVAR_ALLOC_VAL;
32758eb6488eSEric Joyner 
32768eb6488eSEric Joyner 	switch (hw->mac.type) {
32778eb6488eSEric Joyner 	case ixgbe_mac_82598EB:
32788eb6488eSEric Joyner 		if (type == -1)
32798eb6488eSEric Joyner 			entry = IXGBE_IVAR_OTHER_CAUSES_INDEX;
32808eb6488eSEric Joyner 		else
32818eb6488eSEric Joyner 			entry += (type * 64);
32828eb6488eSEric Joyner 		index = (entry >> 2) & 0x1F;
32838eb6488eSEric Joyner 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
32848eb6488eSEric Joyner 		ivar &= ~(0xFF << (8 * (entry & 0x3)));
32858eb6488eSEric Joyner 		ivar |= (vector << (8 * (entry & 0x3)));
3286b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_IVAR(index), ivar);
32878eb6488eSEric Joyner 		break;
32888eb6488eSEric Joyner 	case ixgbe_mac_82599EB:
32898eb6488eSEric Joyner 	case ixgbe_mac_X540:
32908eb6488eSEric Joyner 	case ixgbe_mac_X550:
32918eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
32928eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
32938eb6488eSEric Joyner 		if (type == -1) { /* MISC IVAR */
32948eb6488eSEric Joyner 			index = (entry & 1) * 8;
32958eb6488eSEric Joyner 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
32968eb6488eSEric Joyner 			ivar &= ~(0xFF << index);
32978eb6488eSEric Joyner 			ivar |= (vector << index);
32988eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
32998eb6488eSEric Joyner 		} else {          /* RX/TX IVARS */
33008eb6488eSEric Joyner 			index = (16 * (entry & 1)) + (8 * type);
33018eb6488eSEric Joyner 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1));
33028eb6488eSEric Joyner 			ivar &= ~(0xFF << index);
33038eb6488eSEric Joyner 			ivar |= (vector << index);
33048eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar);
33058eb6488eSEric Joyner 		}
33068eb6488eSEric Joyner 	default:
33078eb6488eSEric Joyner 		break;
33088eb6488eSEric Joyner 	}
33098eb6488eSEric Joyner } /* ixgbe_set_ivar */
33108eb6488eSEric Joyner 
33118eb6488eSEric Joyner /************************************************************************
33128eb6488eSEric Joyner  * ixgbe_configure_ivars
33138eb6488eSEric Joyner  ************************************************************************/
33148eb6488eSEric Joyner static void
3315b1d5caf3SKevin Bowling ixgbe_configure_ivars(struct ixgbe_softc *sc)
33168eb6488eSEric Joyner {
3317b1d5caf3SKevin Bowling 	struct ix_rx_queue *rx_que = sc->rx_queues;
3318b1d5caf3SKevin Bowling 	struct ix_tx_queue *tx_que = sc->tx_queues;
33198eb6488eSEric Joyner 	u32                newitr;
33208eb6488eSEric Joyner 
33218eb6488eSEric Joyner 	if (ixgbe_max_interrupt_rate > 0)
33228eb6488eSEric Joyner 		newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8;
33238eb6488eSEric Joyner 	else {
33248eb6488eSEric Joyner 		/*
33258eb6488eSEric Joyner 		 * Disable DMA coalescing if interrupt moderation is
33268eb6488eSEric Joyner 		 * disabled.
33278eb6488eSEric Joyner 		 */
3328b1d5caf3SKevin Bowling 		sc->dmac = 0;
33298eb6488eSEric Joyner 		newitr = 0;
33308eb6488eSEric Joyner 	}
33318eb6488eSEric Joyner 
3332b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++, rx_que++) {
3333c19c7afeSEric Joyner 		struct rx_ring *rxr = &rx_que->rxr;
33348eb6488eSEric Joyner 
3335c19c7afeSEric Joyner 		/* First the RX queue entry */
3336b1d5caf3SKevin Bowling 		ixgbe_set_ivar(sc, rxr->me, rx_que->msix, 0);
3337c19c7afeSEric Joyner 
3338c19c7afeSEric Joyner 		/* Set an Initial EITR value */
3339b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(rx_que->msix), newitr);
3340c19c7afeSEric Joyner 	}
3341b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_tx_queues; i++, tx_que++) {
3342c19c7afeSEric Joyner 		struct tx_ring *txr = &tx_que->txr;
3343c19c7afeSEric Joyner 
3344c19c7afeSEric Joyner 		/* ... and the TX */
3345b1d5caf3SKevin Bowling 		ixgbe_set_ivar(sc, txr->me, tx_que->msix, 1);
3346c19c7afeSEric Joyner 	}
33478eb6488eSEric Joyner 	/* For the Link interrupt */
3348b1d5caf3SKevin Bowling 	ixgbe_set_ivar(sc, 1, sc->vector, -1);
33498eb6488eSEric Joyner } /* ixgbe_configure_ivars */
33508eb6488eSEric Joyner 
33518eb6488eSEric Joyner /************************************************************************
33528eb6488eSEric Joyner  * ixgbe_config_gpie
33538eb6488eSEric Joyner  ************************************************************************/
33548eb6488eSEric Joyner static void
3355b1d5caf3SKevin Bowling ixgbe_config_gpie(struct ixgbe_softc *sc)
33568eb6488eSEric Joyner {
3357b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
33588eb6488eSEric Joyner 	u32             gpie;
33598eb6488eSEric Joyner 
33608eb6488eSEric Joyner 	gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
33618eb6488eSEric Joyner 
3362b1d5caf3SKevin Bowling 	if (sc->intr_type == IFLIB_INTR_MSIX) {
33638eb6488eSEric Joyner 		/* Enable Enhanced MSI-X mode */
33648eb6488eSEric Joyner 		gpie |= IXGBE_GPIE_MSIX_MODE
33658eb6488eSEric Joyner 		     |  IXGBE_GPIE_EIAME
33668eb6488eSEric Joyner 		     |  IXGBE_GPIE_PBA_SUPPORT
33678eb6488eSEric Joyner 		     |  IXGBE_GPIE_OCD;
33688eb6488eSEric Joyner 	}
33698eb6488eSEric Joyner 
33708eb6488eSEric Joyner 	/* Fan Failure Interrupt */
3371b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_FAN_FAIL)
33728eb6488eSEric Joyner 		gpie |= IXGBE_SDP1_GPIEN;
33738eb6488eSEric Joyner 
33748eb6488eSEric Joyner 	/* Thermal Sensor Interrupt */
3375b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_TEMP_SENSOR)
33768eb6488eSEric Joyner 		gpie |= IXGBE_SDP0_GPIEN_X540;
33778eb6488eSEric Joyner 
33788eb6488eSEric Joyner 	/* Link detection */
33798eb6488eSEric Joyner 	switch (hw->mac.type) {
33808eb6488eSEric Joyner 	case ixgbe_mac_82599EB:
33818eb6488eSEric Joyner 		gpie |= IXGBE_SDP1_GPIEN | IXGBE_SDP2_GPIEN;
33828eb6488eSEric Joyner 		break;
33838eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
33848eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
33858eb6488eSEric Joyner 		gpie |= IXGBE_SDP0_GPIEN_X540;
33868eb6488eSEric Joyner 		break;
33878eb6488eSEric Joyner 	default:
33888eb6488eSEric Joyner 		break;
33898eb6488eSEric Joyner 	}
33908eb6488eSEric Joyner 
33918eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
33928eb6488eSEric Joyner 
33938eb6488eSEric Joyner } /* ixgbe_config_gpie */
33948eb6488eSEric Joyner 
33958eb6488eSEric Joyner /************************************************************************
33968eb6488eSEric Joyner  * ixgbe_config_delay_values
33978eb6488eSEric Joyner  *
3398b1d5caf3SKevin Bowling  *   Requires sc->max_frame_size to be set.
33998eb6488eSEric Joyner  ************************************************************************/
34008eb6488eSEric Joyner static void
3401b1d5caf3SKevin Bowling ixgbe_config_delay_values(struct ixgbe_softc *sc)
34028eb6488eSEric Joyner {
3403b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
34048eb6488eSEric Joyner 	u32             rxpb, frame, size, tmp;
34058eb6488eSEric Joyner 
3406b1d5caf3SKevin Bowling 	frame = sc->max_frame_size;
34078eb6488eSEric Joyner 
34088eb6488eSEric Joyner 	/* Calculate High Water */
34098eb6488eSEric Joyner 	switch (hw->mac.type) {
34108eb6488eSEric Joyner 	case ixgbe_mac_X540:
34118eb6488eSEric Joyner 	case ixgbe_mac_X550:
34128eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
34138eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
34148eb6488eSEric Joyner 		tmp = IXGBE_DV_X540(frame, frame);
34158eb6488eSEric Joyner 		break;
34168eb6488eSEric Joyner 	default:
34178eb6488eSEric Joyner 		tmp = IXGBE_DV(frame, frame);
34188eb6488eSEric Joyner 		break;
34198eb6488eSEric Joyner 	}
34208eb6488eSEric Joyner 	size = IXGBE_BT2KB(tmp);
34218eb6488eSEric Joyner 	rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10;
34228eb6488eSEric Joyner 	hw->fc.high_water[0] = rxpb - size;
34238eb6488eSEric Joyner 
34248eb6488eSEric Joyner 	/* Now calculate Low Water */
34258eb6488eSEric Joyner 	switch (hw->mac.type) {
34268eb6488eSEric Joyner 	case ixgbe_mac_X540:
34278eb6488eSEric Joyner 	case ixgbe_mac_X550:
34288eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
34298eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
34308eb6488eSEric Joyner 		tmp = IXGBE_LOW_DV_X540(frame);
34318eb6488eSEric Joyner 		break;
34328eb6488eSEric Joyner 	default:
34338eb6488eSEric Joyner 		tmp = IXGBE_LOW_DV(frame);
34348eb6488eSEric Joyner 		break;
34358eb6488eSEric Joyner 	}
34368eb6488eSEric Joyner 	hw->fc.low_water[0] = IXGBE_BT2KB(tmp);
34378eb6488eSEric Joyner 
34388eb6488eSEric Joyner 	hw->fc.pause_time = IXGBE_FC_PAUSE;
343979b36ec9SKevin Bowling 	hw->fc.send_xon = true;
34408eb6488eSEric Joyner } /* ixgbe_config_delay_values */
34418eb6488eSEric Joyner 
34428eb6488eSEric Joyner /************************************************************************
34438eb6488eSEric Joyner  * ixgbe_set_multi - Multicast Update
34448eb6488eSEric Joyner  *
34458eb6488eSEric Joyner  *   Called whenever multicast address list is updated.
34468eb6488eSEric Joyner  ************************************************************************/
3447ba76aa63SGleb Smirnoff static u_int
344821afed4bSKevin Bowling ixgbe_mc_filter_apply(void *arg, struct sockaddr_dl *sdl, u_int idx)
34498eb6488eSEric Joyner {
3450b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = arg;
3451b1d5caf3SKevin Bowling 	struct ixgbe_mc_addr *mta = sc->mta;
3452c19c7afeSEric Joyner 
345321afed4bSKevin Bowling 	if (idx == MAX_NUM_MULTICAST_ADDRESSES)
3454c19c7afeSEric Joyner 		return (0);
345521afed4bSKevin Bowling 	bcopy(LLADDR(sdl), mta[idx].addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
3456b1d5caf3SKevin Bowling 	mta[idx].vmdq = sc->pool;
3457c19c7afeSEric Joyner 
3458c19c7afeSEric Joyner 	return (1);
3459c19c7afeSEric Joyner } /* ixgbe_mc_filter_apply */
3460c19c7afeSEric Joyner 
3461c19c7afeSEric Joyner static void
3462c19c7afeSEric Joyner ixgbe_if_multi_set(if_ctx_t ctx)
3463c19c7afeSEric Joyner {
3464b1d5caf3SKevin Bowling 	struct ixgbe_softc       *sc = iflib_get_softc(ctx);
34658eb6488eSEric Joyner 	struct ixgbe_mc_addr *mta;
3466ff06a8dbSJustin Hibbits 	if_t                  ifp = iflib_get_ifp(ctx);
34678eb6488eSEric Joyner 	u8                   *update_ptr;
34688eb6488eSEric Joyner 	u32                  fctrl;
3469ba76aa63SGleb Smirnoff 	u_int		     mcnt;
34708eb6488eSEric Joyner 
3471c19c7afeSEric Joyner 	IOCTL_DEBUGOUT("ixgbe_if_multi_set: begin");
34728eb6488eSEric Joyner 
3473b1d5caf3SKevin Bowling 	mta = sc->mta;
34748eb6488eSEric Joyner 	bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES);
34758eb6488eSEric Joyner 
3476b1d5caf3SKevin Bowling 	mcnt = if_foreach_llmaddr(iflib_get_ifp(ctx), ixgbe_mc_filter_apply, sc);
34778eb6488eSEric Joyner 
3478395cc55dSKevin Bowling 	if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) {
3479395cc55dSKevin Bowling 		update_ptr = (u8 *)mta;
3480395cc55dSKevin Bowling 		ixgbe_update_mc_addr_list(&sc->hw, update_ptr, mcnt,
3481395cc55dSKevin Bowling 		    ixgbe_mc_array_itr, true);
3482395cc55dSKevin Bowling 	}
3483395cc55dSKevin Bowling 
3484b1d5caf3SKevin Bowling 	fctrl = IXGBE_READ_REG(&sc->hw, IXGBE_FCTRL);
3485deecaa14SKevin Bowling 
3486ff06a8dbSJustin Hibbits 	if (if_getflags(ifp) & IFF_PROMISC)
34878eb6488eSEric Joyner 		fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
34888eb6488eSEric Joyner 	else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES ||
3489ff06a8dbSJustin Hibbits 	    if_getflags(ifp) & IFF_ALLMULTI) {
34908eb6488eSEric Joyner 		fctrl |= IXGBE_FCTRL_MPE;
34918eb6488eSEric Joyner 		fctrl &= ~IXGBE_FCTRL_UPE;
34928eb6488eSEric Joyner 	} else
34938eb6488eSEric Joyner 		fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
34948eb6488eSEric Joyner 
3495b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, fctrl);
3496c19c7afeSEric Joyner } /* ixgbe_if_multi_set */
34978eb6488eSEric Joyner 
34988eb6488eSEric Joyner /************************************************************************
34998eb6488eSEric Joyner  * ixgbe_mc_array_itr
35008eb6488eSEric Joyner  *
35018eb6488eSEric Joyner  *   An iterator function needed by the multicast shared code.
35028eb6488eSEric Joyner  *   It feeds the shared code routine the addresses in the
35038eb6488eSEric Joyner  *   array of ixgbe_set_multi() one by one.
35048eb6488eSEric Joyner  ************************************************************************/
35058eb6488eSEric Joyner static u8 *
35068eb6488eSEric Joyner ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq)
35078eb6488eSEric Joyner {
35088eb6488eSEric Joyner 	struct ixgbe_mc_addr *mta;
35098eb6488eSEric Joyner 
35108eb6488eSEric Joyner 	mta = (struct ixgbe_mc_addr *)*update_ptr;
35118eb6488eSEric Joyner 	*vmdq = mta->vmdq;
35128eb6488eSEric Joyner 
35138eb6488eSEric Joyner 	*update_ptr = (u8*)(mta + 1);
35148eb6488eSEric Joyner 
35158eb6488eSEric Joyner 	return (mta->addr);
35168eb6488eSEric Joyner } /* ixgbe_mc_array_itr */
35178eb6488eSEric Joyner 
35188eb6488eSEric Joyner /************************************************************************
35198eb6488eSEric Joyner  * ixgbe_local_timer - Timer routine
35208eb6488eSEric Joyner  *
35218eb6488eSEric Joyner  *   Checks for link status, updates statistics,
35228eb6488eSEric Joyner  *   and runs the watchdog check.
35238eb6488eSEric Joyner  ************************************************************************/
35248eb6488eSEric Joyner static void
3525c19c7afeSEric Joyner ixgbe_if_timer(if_ctx_t ctx, uint16_t qid)
35268eb6488eSEric Joyner {
3527b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
35288eb6488eSEric Joyner 
3529c19c7afeSEric Joyner 	if (qid != 0)
3530c19c7afeSEric Joyner 		return;
35318eb6488eSEric Joyner 
35328eb6488eSEric Joyner 	/* Check for pluggable optics */
3533b1d5caf3SKevin Bowling 	if (sc->sfp_probe)
3534c19c7afeSEric Joyner 		if (!ixgbe_sfp_probe(ctx))
3535c19c7afeSEric Joyner 			return; /* Nothing to do */
35368eb6488eSEric Joyner 
3537b1d5caf3SKevin Bowling 	ixgbe_check_link(&sc->hw, &sc->link_speed, &sc->link_up, 0);
35388eb6488eSEric Joyner 
3539c19c7afeSEric Joyner 	/* Fire off the adminq task */
3540c19c7afeSEric Joyner 	iflib_admin_intr_deferred(ctx);
35418eb6488eSEric Joyner 
3542c19c7afeSEric Joyner } /* ixgbe_if_timer */
35438eb6488eSEric Joyner 
35448eb6488eSEric Joyner /************************************************************************
3545f72de14eSKevin Bowling  * ixgbe_fw_mode_timer - FW mode timer routine
3546f72de14eSKevin Bowling  ************************************************************************/
3547f72de14eSKevin Bowling static void
3548f72de14eSKevin Bowling ixgbe_fw_mode_timer(void *arg)
3549f72de14eSKevin Bowling {
3550f72de14eSKevin Bowling 	struct ixgbe_softc *sc = arg;
3551f72de14eSKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3552f72de14eSKevin Bowling 
3553f72de14eSKevin Bowling 	if (ixgbe_fw_recovery_mode(hw)) {
3554f72de14eSKevin Bowling 		if (atomic_cmpset_acq_int(&sc->recovery_mode, 0, 1)) {
3555f72de14eSKevin Bowling 			/* Firmware error detected, entering recovery mode */
3556f72de14eSKevin Bowling 			device_printf(sc->dev, "Firmware recovery mode detected. Limiting"
3557f72de14eSKevin Bowling 			    " functionality. Refer to the Intel(R) Ethernet Adapters"
3558f72de14eSKevin Bowling 			    " and Devices User Guide for details on firmware recovery"
3559f72de14eSKevin Bowling 			    " mode.\n");
3560f72de14eSKevin Bowling 
3561f72de14eSKevin Bowling 			if (hw->adapter_stopped == FALSE)
3562f72de14eSKevin Bowling 				ixgbe_if_stop(sc->ctx);
3563f72de14eSKevin Bowling 		}
3564f72de14eSKevin Bowling 	} else
3565f72de14eSKevin Bowling 		atomic_cmpset_acq_int(&sc->recovery_mode, 1, 0);
3566f72de14eSKevin Bowling 
3567f72de14eSKevin Bowling 
3568f72de14eSKevin Bowling 	callout_reset(&sc->fw_mode_timer, hz,
3569f72de14eSKevin Bowling 	    ixgbe_fw_mode_timer, sc);
3570f72de14eSKevin Bowling } /* ixgbe_fw_mode_timer */
3571f72de14eSKevin Bowling 
3572f72de14eSKevin Bowling /************************************************************************
35738eb6488eSEric Joyner  * ixgbe_sfp_probe
35748eb6488eSEric Joyner  *
35758eb6488eSEric Joyner  *   Determine if a port had optics inserted.
35768eb6488eSEric Joyner  ************************************************************************/
35778eb6488eSEric Joyner static bool
3578c19c7afeSEric Joyner ixgbe_sfp_probe(if_ctx_t ctx)
35798eb6488eSEric Joyner {
3580b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = iflib_get_softc(ctx);
3581b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3582c19c7afeSEric Joyner 	device_t        dev = iflib_get_dev(ctx);
358379b36ec9SKevin Bowling 	bool            result = false;
35848eb6488eSEric Joyner 
35858eb6488eSEric Joyner 	if ((hw->phy.type == ixgbe_phy_nl) &&
35868eb6488eSEric Joyner 	    (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
35878eb6488eSEric Joyner 		s32 ret = hw->phy.ops.identify_sfp(hw);
35888eb6488eSEric Joyner 		if (ret)
35898eb6488eSEric Joyner 			goto out;
35908eb6488eSEric Joyner 		ret = hw->phy.ops.reset(hw);
3591b1d5caf3SKevin Bowling 		sc->sfp_probe = false;
35928eb6488eSEric Joyner 		if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
35938eb6488eSEric Joyner 			device_printf(dev, "Unsupported SFP+ module detected!");
35948eb6488eSEric Joyner 			device_printf(dev,
35958eb6488eSEric Joyner 			    "Reload driver with supported module.\n");
35968eb6488eSEric Joyner 			goto out;
35978eb6488eSEric Joyner 		} else
35988eb6488eSEric Joyner 			device_printf(dev, "SFP+ module detected!\n");
35998eb6488eSEric Joyner 		/* We now have supported optics */
360079b36ec9SKevin Bowling 		result = true;
36018eb6488eSEric Joyner 	}
36028eb6488eSEric Joyner out:
36038eb6488eSEric Joyner 
36048eb6488eSEric Joyner 	return (result);
36058eb6488eSEric Joyner } /* ixgbe_sfp_probe */
36068eb6488eSEric Joyner 
36078eb6488eSEric Joyner /************************************************************************
36088eb6488eSEric Joyner  * ixgbe_handle_mod - Tasklet for SFP module interrupts
36098eb6488eSEric Joyner  ************************************************************************/
36108eb6488eSEric Joyner static void
3611c19c7afeSEric Joyner ixgbe_handle_mod(void *context)
36128eb6488eSEric Joyner {
3613c19c7afeSEric Joyner 	if_ctx_t        ctx = context;
3614b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = iflib_get_softc(ctx);
3615b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3616c19c7afeSEric Joyner 	device_t        dev = iflib_get_dev(ctx);
36178eb6488eSEric Joyner 	u32             err, cage_full = 0;
36188eb6488eSEric Joyner 
3619b1d5caf3SKevin Bowling 	if (sc->hw.need_crosstalk_fix) {
36208eb6488eSEric Joyner 		switch (hw->mac.type) {
36218eb6488eSEric Joyner 		case ixgbe_mac_82599EB:
36228eb6488eSEric Joyner 			cage_full = IXGBE_READ_REG(hw, IXGBE_ESDP) &
36238eb6488eSEric Joyner 			    IXGBE_ESDP_SDP2;
36248eb6488eSEric Joyner 			break;
36258eb6488eSEric Joyner 		case ixgbe_mac_X550EM_x:
36268eb6488eSEric Joyner 		case ixgbe_mac_X550EM_a:
36278eb6488eSEric Joyner 			cage_full = IXGBE_READ_REG(hw, IXGBE_ESDP) &
36288eb6488eSEric Joyner 			    IXGBE_ESDP_SDP0;
36298eb6488eSEric Joyner 			break;
36308eb6488eSEric Joyner 		default:
36318eb6488eSEric Joyner 			break;
36328eb6488eSEric Joyner 		}
36338eb6488eSEric Joyner 
36348eb6488eSEric Joyner 		if (!cage_full)
3635c19c7afeSEric Joyner 			goto handle_mod_out;
36368eb6488eSEric Joyner 	}
36378eb6488eSEric Joyner 
36388eb6488eSEric Joyner 	err = hw->phy.ops.identify_sfp(hw);
36398eb6488eSEric Joyner 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
36408eb6488eSEric Joyner 		device_printf(dev,
36418eb6488eSEric Joyner 		    "Unsupported SFP+ module type was detected.\n");
3642c19c7afeSEric Joyner 		goto handle_mod_out;
36438eb6488eSEric Joyner 	}
36448eb6488eSEric Joyner 
3645c19c7afeSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB)
3646c19c7afeSEric Joyner 		err = hw->phy.ops.reset(hw);
3647c19c7afeSEric Joyner 	else
36488eb6488eSEric Joyner 		err = hw->mac.ops.setup_sfp(hw);
3649c19c7afeSEric Joyner 
36508eb6488eSEric Joyner 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
36518eb6488eSEric Joyner 		device_printf(dev,
36528eb6488eSEric Joyner 		    "Setup failure - unsupported SFP+ module type.\n");
3653c19c7afeSEric Joyner 		goto handle_mod_out;
36548eb6488eSEric Joyner 	}
3655b1d5caf3SKevin Bowling 	sc->task_requests |= IXGBE_REQUEST_TASK_MSF;
3656c19c7afeSEric Joyner 	return;
3657c19c7afeSEric Joyner 
3658c19c7afeSEric Joyner handle_mod_out:
3659b1d5caf3SKevin Bowling 	sc->task_requests &= ~(IXGBE_REQUEST_TASK_MSF);
36608eb6488eSEric Joyner } /* ixgbe_handle_mod */
36618eb6488eSEric Joyner 
36628eb6488eSEric Joyner 
36638eb6488eSEric Joyner /************************************************************************
36648eb6488eSEric Joyner  * ixgbe_handle_msf - Tasklet for MSF (multispeed fiber) interrupts
36658eb6488eSEric Joyner  ************************************************************************/
36668eb6488eSEric Joyner static void
3667c19c7afeSEric Joyner ixgbe_handle_msf(void *context)
36688eb6488eSEric Joyner {
3669c19c7afeSEric Joyner 	if_ctx_t        ctx = context;
3670b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = iflib_get_softc(ctx);
3671b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
36728eb6488eSEric Joyner 	u32             autoneg;
36738eb6488eSEric Joyner 	bool            negotiate;
36748eb6488eSEric Joyner 
36758eb6488eSEric Joyner 	/* get_supported_phy_layer will call hw->phy.ops.identify_sfp() */
3676b1d5caf3SKevin Bowling 	sc->phy_layer = ixgbe_get_supported_physical_layer(hw);
36778eb6488eSEric Joyner 
36788eb6488eSEric Joyner 	autoneg = hw->phy.autoneg_advertised;
36798eb6488eSEric Joyner 	if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
36808eb6488eSEric Joyner 		hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate);
36818eb6488eSEric Joyner 	if (hw->mac.ops.setup_link)
368279b36ec9SKevin Bowling 		hw->mac.ops.setup_link(hw, autoneg, true);
36838eb6488eSEric Joyner 
36848eb6488eSEric Joyner 	/* Adjust media types shown in ifconfig */
3685b1d5caf3SKevin Bowling 	ifmedia_removeall(sc->media);
3686b1d5caf3SKevin Bowling 	ixgbe_add_media_types(sc->ctx);
3687b1d5caf3SKevin Bowling 	ifmedia_set(sc->media, IFM_ETHER | IFM_AUTO);
36888eb6488eSEric Joyner } /* ixgbe_handle_msf */
36898eb6488eSEric Joyner 
36908eb6488eSEric Joyner /************************************************************************
36918eb6488eSEric Joyner  * ixgbe_handle_phy - Tasklet for external PHY interrupts
36928eb6488eSEric Joyner  ************************************************************************/
36938eb6488eSEric Joyner static void
3694c19c7afeSEric Joyner ixgbe_handle_phy(void *context)
36958eb6488eSEric Joyner {
3696c19c7afeSEric Joyner 	if_ctx_t        ctx = context;
3697b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = iflib_get_softc(ctx);
3698b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
36998eb6488eSEric Joyner 	int             error;
37008eb6488eSEric Joyner 
37018eb6488eSEric Joyner 	error = hw->phy.ops.handle_lasi(hw);
37028eb6488eSEric Joyner 	if (error == IXGBE_ERR_OVERTEMP)
3703b1d5caf3SKevin Bowling 		device_printf(sc->dev, "CRITICAL: EXTERNAL PHY OVER TEMP!!  PHY will downshift to lower power state!\n");
37048eb6488eSEric Joyner 	else if (error)
3705b1d5caf3SKevin Bowling 		device_printf(sc->dev,
37068eb6488eSEric Joyner 		    "Error handling LASI interrupt: %d\n", error);
37078eb6488eSEric Joyner } /* ixgbe_handle_phy */
37088eb6488eSEric Joyner 
37098eb6488eSEric Joyner /************************************************************************
3710c19c7afeSEric Joyner  * ixgbe_if_stop - Stop the hardware
37118eb6488eSEric Joyner  *
37128eb6488eSEric Joyner  *   Disables all traffic on the adapter by issuing a
37138eb6488eSEric Joyner  *   global reset on the MAC and deallocates TX/RX buffers.
37148eb6488eSEric Joyner  ************************************************************************/
37158eb6488eSEric Joyner static void
3716c19c7afeSEric Joyner ixgbe_if_stop(if_ctx_t ctx)
37178eb6488eSEric Joyner {
3718b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = iflib_get_softc(ctx);
3719b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
37208eb6488eSEric Joyner 
3721c19c7afeSEric Joyner 	INIT_DEBUGOUT("ixgbe_if_stop: begin\n");
37228eb6488eSEric Joyner 
37238eb6488eSEric Joyner 	ixgbe_reset_hw(hw);
372479b36ec9SKevin Bowling 	hw->adapter_stopped = false;
37258eb6488eSEric Joyner 	ixgbe_stop_adapter(hw);
37268eb6488eSEric Joyner 	if (hw->mac.type == ixgbe_mac_82599EB)
37278eb6488eSEric Joyner 		ixgbe_stop_mac_link_on_d3_82599(hw);
37288eb6488eSEric Joyner 	/* Turn off the laser - noop with no optics */
37298eb6488eSEric Joyner 	ixgbe_disable_tx_laser(hw);
37308eb6488eSEric Joyner 
37318eb6488eSEric Joyner 	/* Update the stack */
3732b1d5caf3SKevin Bowling 	sc->link_up = false;
3733c19c7afeSEric Joyner 	ixgbe_if_update_admin_status(ctx);
37348eb6488eSEric Joyner 
37358eb6488eSEric Joyner 	/* reprogram the RAR[0] in case user changed it. */
3736b1d5caf3SKevin Bowling 	ixgbe_set_rar(&sc->hw, 0, sc->hw.mac.addr, 0, IXGBE_RAH_AV);
37378eb6488eSEric Joyner 
37388eb6488eSEric Joyner 	return;
3739c19c7afeSEric Joyner } /* ixgbe_if_stop */
37408eb6488eSEric Joyner 
37418eb6488eSEric Joyner /************************************************************************
37428eb6488eSEric Joyner  * ixgbe_update_link_status - Update OS on link state
37438eb6488eSEric Joyner  *
37448eb6488eSEric Joyner  * Note: Only updates the OS on the cached link state.
37458eb6488eSEric Joyner  *       The real check of the hardware only happens with
37468eb6488eSEric Joyner  *       a link interrupt.
37478eb6488eSEric Joyner  ************************************************************************/
37488eb6488eSEric Joyner static void
3749c19c7afeSEric Joyner ixgbe_if_update_admin_status(if_ctx_t ctx)
37508eb6488eSEric Joyner {
3751b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3752c19c7afeSEric Joyner 	device_t       dev = iflib_get_dev(ctx);
37538eb6488eSEric Joyner 
3754b1d5caf3SKevin Bowling 	if (sc->link_up) {
3755b1d5caf3SKevin Bowling 		if (sc->link_active == false) {
37568eb6488eSEric Joyner 			if (bootverbose)
37578eb6488eSEric Joyner 				device_printf(dev, "Link is up %d Gbps %s \n",
3758b1d5caf3SKevin Bowling 				    ((sc->link_speed == 128) ? 10 : 1),
37598eb6488eSEric Joyner 				    "Full Duplex");
3760b1d5caf3SKevin Bowling 			sc->link_active = true;
37618eb6488eSEric Joyner 			/* Update any Flow Control changes */
3762b1d5caf3SKevin Bowling 			ixgbe_fc_enable(&sc->hw);
37638eb6488eSEric Joyner 			/* Update DMA coalescing config */
3764b1d5caf3SKevin Bowling 			ixgbe_config_dmac(sc);
3765a0302c92SPiotr Pietruszewski 			iflib_link_state_change(ctx, LINK_STATE_UP,
37665ddb1aa3SPiotr Kubaj 			    ixgbe_link_speed_to_baudrate(sc->link_speed));
3767c19c7afeSEric Joyner 
3768b1d5caf3SKevin Bowling 			if (sc->feat_en & IXGBE_FEATURE_SRIOV)
3769b1d5caf3SKevin Bowling 				ixgbe_ping_all_vfs(sc);
37708eb6488eSEric Joyner 		}
37718eb6488eSEric Joyner 	} else { /* Link down */
3772b1d5caf3SKevin Bowling 		if (sc->link_active == true) {
37738eb6488eSEric Joyner 			if (bootverbose)
37748eb6488eSEric Joyner 				device_printf(dev, "Link is Down\n");
3775c19c7afeSEric Joyner 			iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
3776b1d5caf3SKevin Bowling 			sc->link_active = false;
3777b1d5caf3SKevin Bowling 			if (sc->feat_en & IXGBE_FEATURE_SRIOV)
3778b1d5caf3SKevin Bowling 				ixgbe_ping_all_vfs(sc);
37798eb6488eSEric Joyner 		}
37808eb6488eSEric Joyner 	}
37818eb6488eSEric Joyner 
3782b2c1e8e6SEric Joyner 	/* Handle task requests from msix_link() */
3783b1d5caf3SKevin Bowling 	if (sc->task_requests & IXGBE_REQUEST_TASK_MOD)
3784b2c1e8e6SEric Joyner 		ixgbe_handle_mod(ctx);
3785b1d5caf3SKevin Bowling 	if (sc->task_requests & IXGBE_REQUEST_TASK_MSF)
3786b2c1e8e6SEric Joyner 		ixgbe_handle_msf(ctx);
3787b1d5caf3SKevin Bowling 	if (sc->task_requests & IXGBE_REQUEST_TASK_MBX)
3788b2c1e8e6SEric Joyner 		ixgbe_handle_mbx(ctx);
3789b1d5caf3SKevin Bowling 	if (sc->task_requests & IXGBE_REQUEST_TASK_FDIR)
3790b2c1e8e6SEric Joyner 		ixgbe_reinit_fdir(ctx);
3791b1d5caf3SKevin Bowling 	if (sc->task_requests & IXGBE_REQUEST_TASK_PHY)
3792b2c1e8e6SEric Joyner 		ixgbe_handle_phy(ctx);
3793b1d5caf3SKevin Bowling 	sc->task_requests = 0;
3794c19c7afeSEric Joyner 
3795b1d5caf3SKevin Bowling 	ixgbe_update_stats_counters(sc);
3796c19c7afeSEric Joyner } /* ixgbe_if_update_admin_status */
37978eb6488eSEric Joyner 
37988eb6488eSEric Joyner /************************************************************************
37998eb6488eSEric Joyner  * ixgbe_config_dmac - Configure DMA Coalescing
38008eb6488eSEric Joyner  ************************************************************************/
38018eb6488eSEric Joyner static void
3802b1d5caf3SKevin Bowling ixgbe_config_dmac(struct ixgbe_softc *sc)
38038eb6488eSEric Joyner {
3804b1d5caf3SKevin Bowling 	struct ixgbe_hw          *hw = &sc->hw;
38058eb6488eSEric Joyner 	struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config;
38068eb6488eSEric Joyner 
38078eb6488eSEric Joyner 	if (hw->mac.type < ixgbe_mac_X550 || !hw->mac.ops.dmac_config)
38088eb6488eSEric Joyner 		return;
38098eb6488eSEric Joyner 
3810b1d5caf3SKevin Bowling 	if (dcfg->watchdog_timer ^ sc->dmac ||
3811b1d5caf3SKevin Bowling 	    dcfg->link_speed ^ sc->link_speed) {
3812b1d5caf3SKevin Bowling 		dcfg->watchdog_timer = sc->dmac;
381379b36ec9SKevin Bowling 		dcfg->fcoe_en = false;
3814b1d5caf3SKevin Bowling 		dcfg->link_speed = sc->link_speed;
38158eb6488eSEric Joyner 		dcfg->num_tcs = 1;
38168eb6488eSEric Joyner 
38178eb6488eSEric Joyner 		INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n",
38188eb6488eSEric Joyner 		    dcfg->watchdog_timer, dcfg->link_speed);
38198eb6488eSEric Joyner 
38208eb6488eSEric Joyner 		hw->mac.ops.dmac_config(hw);
38218eb6488eSEric Joyner 	}
38228eb6488eSEric Joyner } /* ixgbe_config_dmac */
38238eb6488eSEric Joyner 
38248eb6488eSEric Joyner /************************************************************************
3825c19c7afeSEric Joyner  * ixgbe_if_enable_intr
38268eb6488eSEric Joyner  ************************************************************************/
3827c19c7afeSEric Joyner void
3828c19c7afeSEric Joyner ixgbe_if_enable_intr(if_ctx_t ctx)
38298eb6488eSEric Joyner {
3830b1d5caf3SKevin Bowling 	struct ixgbe_softc     *sc = iflib_get_softc(ctx);
3831b1d5caf3SKevin Bowling 	struct ixgbe_hw    *hw = &sc->hw;
3832b1d5caf3SKevin Bowling 	struct ix_rx_queue *que = sc->rx_queues;
38338eb6488eSEric Joyner 	u32                mask, fwsm;
38348eb6488eSEric Joyner 
38358eb6488eSEric Joyner 	mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
38368eb6488eSEric Joyner 
3837b1d5caf3SKevin Bowling 	switch (sc->hw.mac.type) {
38388eb6488eSEric Joyner 	case ixgbe_mac_82599EB:
38398eb6488eSEric Joyner 		mask |= IXGBE_EIMS_ECC;
3840b1d5caf3SKevin Bowling 		/* Temperature sensor on some scs */
38418eb6488eSEric Joyner 		mask |= IXGBE_EIMS_GPI_SDP0;
38428eb6488eSEric Joyner 		/* SFP+ (RX_LOS_N & MOD_ABS_N) */
38438eb6488eSEric Joyner 		mask |= IXGBE_EIMS_GPI_SDP1;
38448eb6488eSEric Joyner 		mask |= IXGBE_EIMS_GPI_SDP2;
38458eb6488eSEric Joyner 		break;
38468eb6488eSEric Joyner 	case ixgbe_mac_X540:
38478eb6488eSEric Joyner 		/* Detect if Thermal Sensor is enabled */
38488eb6488eSEric Joyner 		fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
38498eb6488eSEric Joyner 		if (fwsm & IXGBE_FWSM_TS_ENABLED)
38508eb6488eSEric Joyner 			mask |= IXGBE_EIMS_TS;
38518eb6488eSEric Joyner 		mask |= IXGBE_EIMS_ECC;
38528eb6488eSEric Joyner 		break;
38538eb6488eSEric Joyner 	case ixgbe_mac_X550:
38548eb6488eSEric Joyner 		/* MAC thermal sensor is automatically enabled */
38558eb6488eSEric Joyner 		mask |= IXGBE_EIMS_TS;
38568eb6488eSEric Joyner 		mask |= IXGBE_EIMS_ECC;
38578eb6488eSEric Joyner 		break;
38588eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
38598eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
38608eb6488eSEric Joyner 		/* Some devices use SDP0 for important information */
38618eb6488eSEric Joyner 		if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
38628eb6488eSEric Joyner 		    hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP ||
38638eb6488eSEric Joyner 		    hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N ||
38648eb6488eSEric Joyner 		    hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T)
38658eb6488eSEric Joyner 			mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw);
38668eb6488eSEric Joyner 		if (hw->phy.type == ixgbe_phy_x550em_ext_t)
38678eb6488eSEric Joyner 			mask |= IXGBE_EICR_GPI_SDP0_X540;
38688eb6488eSEric Joyner 		mask |= IXGBE_EIMS_ECC;
38698eb6488eSEric Joyner 		break;
38708eb6488eSEric Joyner 	default:
38718eb6488eSEric Joyner 		break;
38728eb6488eSEric Joyner 	}
38738eb6488eSEric Joyner 
38748eb6488eSEric Joyner 	/* Enable Fan Failure detection */
3875b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_FAN_FAIL)
38768eb6488eSEric Joyner 		mask |= IXGBE_EIMS_GPI_SDP1;
38778eb6488eSEric Joyner 	/* Enable SR-IOV */
3878b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_SRIOV)
38798eb6488eSEric Joyner 		mask |= IXGBE_EIMS_MAILBOX;
38808eb6488eSEric Joyner 	/* Enable Flow Director */
3881b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_FDIR)
38828eb6488eSEric Joyner 		mask |= IXGBE_EIMS_FLOW_DIR;
38838eb6488eSEric Joyner 
38848eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask);
38858eb6488eSEric Joyner 
38868eb6488eSEric Joyner 	/* With MSI-X we use auto clear */
3887b1d5caf3SKevin Bowling 	if (sc->intr_type == IFLIB_INTR_MSIX) {
38888eb6488eSEric Joyner 		mask = IXGBE_EIMS_ENABLE_MASK;
38898eb6488eSEric Joyner 		/* Don't autoclear Link */
38908eb6488eSEric Joyner 		mask &= ~IXGBE_EIMS_OTHER;
38918eb6488eSEric Joyner 		mask &= ~IXGBE_EIMS_LSC;
3892b1d5caf3SKevin Bowling 		if (sc->feat_cap & IXGBE_FEATURE_SRIOV)
38938eb6488eSEric Joyner 			mask &= ~IXGBE_EIMS_MAILBOX;
38948eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask);
38956f37f232SEric Joyner 	}
38966f37f232SEric Joyner 
3897758cc3dcSJack F Vogel 	/*
38988eb6488eSEric Joyner 	 * Now enable all queues, this is done separately to
38998eb6488eSEric Joyner 	 * allow for handling the extended (beyond 32) MSI-X
39008eb6488eSEric Joyner 	 * vectors that can be used by 82599
3901758cc3dcSJack F Vogel 	 */
3902b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++, que++)
3903b1d5caf3SKevin Bowling 		ixgbe_enable_queue(sc, que->msix);
39048eb6488eSEric Joyner 
39058eb6488eSEric Joyner 	IXGBE_WRITE_FLUSH(hw);
39068eb6488eSEric Joyner 
3907c19c7afeSEric Joyner } /* ixgbe_if_enable_intr */
39088eb6488eSEric Joyner 
39098eb6488eSEric Joyner /************************************************************************
39108eb6488eSEric Joyner  * ixgbe_disable_intr
39118eb6488eSEric Joyner  ************************************************************************/
3912758cc3dcSJack F Vogel static void
3913c19c7afeSEric Joyner ixgbe_if_disable_intr(if_ctx_t ctx)
3914758cc3dcSJack F Vogel {
3915b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3916c19c7afeSEric Joyner 
3917b1d5caf3SKevin Bowling 	if (sc->intr_type == IFLIB_INTR_MSIX)
3918b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EIAC, 0);
3919b1d5caf3SKevin Bowling 	if (sc->hw.mac.type == ixgbe_mac_82598EB) {
3920b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC, ~0);
39218eb6488eSEric Joyner 	} else {
3922b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC, 0xFFFF0000);
3923b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC_EX(0), ~0);
3924b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC_EX(1), ~0);
39258eb6488eSEric Joyner 	}
3926b1d5caf3SKevin Bowling 	IXGBE_WRITE_FLUSH(&sc->hw);
3927758cc3dcSJack F Vogel 
3928c19c7afeSEric Joyner } /* ixgbe_if_disable_intr */
39298eb6488eSEric Joyner 
39308eb6488eSEric Joyner /************************************************************************
3931b2c1e8e6SEric Joyner  * ixgbe_link_intr_enable
3932b2c1e8e6SEric Joyner  ************************************************************************/
3933b2c1e8e6SEric Joyner static void
3934b2c1e8e6SEric Joyner ixgbe_link_intr_enable(if_ctx_t ctx)
3935b2c1e8e6SEric Joyner {
3936b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &((struct ixgbe_softc *)iflib_get_softc(ctx))->hw;
3937b2c1e8e6SEric Joyner 
3938b2c1e8e6SEric Joyner 	/* Re-enable other interrupts */
3939b2c1e8e6SEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC);
3940b2c1e8e6SEric Joyner } /* ixgbe_link_intr_enable */
3941b2c1e8e6SEric Joyner 
3942b2c1e8e6SEric Joyner /************************************************************************
3943c19c7afeSEric Joyner  * ixgbe_if_rx_queue_intr_enable
3944c19c7afeSEric Joyner  ************************************************************************/
3945c19c7afeSEric Joyner static int
3946c19c7afeSEric Joyner ixgbe_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid)
3947c19c7afeSEric Joyner {
3948b1d5caf3SKevin Bowling 	struct ixgbe_softc     *sc = iflib_get_softc(ctx);
3949b1d5caf3SKevin Bowling 	struct ix_rx_queue *que = &sc->rx_queues[rxqid];
3950c19c7afeSEric Joyner 
3951b1d5caf3SKevin Bowling 	ixgbe_enable_queue(sc, que->msix);
3952c19c7afeSEric Joyner 
3953c19c7afeSEric Joyner 	return (0);
3954c19c7afeSEric Joyner } /* ixgbe_if_rx_queue_intr_enable */
3955c19c7afeSEric Joyner 
3956c19c7afeSEric Joyner /************************************************************************
3957c19c7afeSEric Joyner  * ixgbe_enable_queue
39588eb6488eSEric Joyner  ************************************************************************/
39598eb6488eSEric Joyner static void
3960b1d5caf3SKevin Bowling ixgbe_enable_queue(struct ixgbe_softc *sc, u32 vector)
39618eb6488eSEric Joyner {
3962b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
39632dc2d580SEric Joyner 	u64             queue = 1ULL << vector;
3964c19c7afeSEric Joyner 	u32             mask;
3965758cc3dcSJack F Vogel 
3966c19c7afeSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB) {
3967c19c7afeSEric Joyner 		mask = (IXGBE_EIMS_RTX_QUEUE & queue);
3968c19c7afeSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask);
3969c19c7afeSEric Joyner 	} else {
3970c19c7afeSEric Joyner 		mask = (queue & 0xFFFFFFFF);
3971c19c7afeSEric Joyner 		if (mask)
3972c19c7afeSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask);
3973c19c7afeSEric Joyner 		mask = (queue >> 32);
3974c19c7afeSEric Joyner 		if (mask)
3975c19c7afeSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask);
3976c19c7afeSEric Joyner 	}
3977c19c7afeSEric Joyner } /* ixgbe_enable_queue */
3978c19c7afeSEric Joyner 
3979c19c7afeSEric Joyner /************************************************************************
3980c19c7afeSEric Joyner  * ixgbe_disable_queue
3981c19c7afeSEric Joyner  ************************************************************************/
3982c19c7afeSEric Joyner static void
3983b1d5caf3SKevin Bowling ixgbe_disable_queue(struct ixgbe_softc *sc, u32 vector)
3984c19c7afeSEric Joyner {
3985b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
39862dc2d580SEric Joyner 	u64             queue = 1ULL << vector;
3987c19c7afeSEric Joyner 	u32             mask;
3988c19c7afeSEric Joyner 
3989c19c7afeSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB) {
3990c19c7afeSEric Joyner 		mask = (IXGBE_EIMS_RTX_QUEUE & queue);
3991c19c7afeSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask);
3992c19c7afeSEric Joyner 	} else {
3993c19c7afeSEric Joyner 		mask = (queue & 0xFFFFFFFF);
3994c19c7afeSEric Joyner 		if (mask)
3995c19c7afeSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask);
3996c19c7afeSEric Joyner 		mask = (queue >> 32);
3997c19c7afeSEric Joyner 		if (mask)
3998c19c7afeSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask);
3999c19c7afeSEric Joyner 	}
4000c19c7afeSEric Joyner } /* ixgbe_disable_queue */
4001c19c7afeSEric Joyner 
4002c19c7afeSEric Joyner /************************************************************************
4003c19c7afeSEric Joyner  * ixgbe_intr - Legacy Interrupt Service Routine
4004c19c7afeSEric Joyner  ************************************************************************/
4005c19c7afeSEric Joyner int
4006c19c7afeSEric Joyner ixgbe_intr(void *arg)
4007c19c7afeSEric Joyner {
4008b1d5caf3SKevin Bowling 	struct ixgbe_softc     *sc = arg;
4009b1d5caf3SKevin Bowling 	struct ix_rx_queue *que = sc->rx_queues;
4010b1d5caf3SKevin Bowling 	struct ixgbe_hw    *hw = &sc->hw;
4011b1d5caf3SKevin Bowling 	if_ctx_t           ctx = sc->ctx;
4012c19c7afeSEric Joyner 	u32                eicr, eicr_mask;
4013758cc3dcSJack F Vogel 
40148eb6488eSEric Joyner 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
4015758cc3dcSJack F Vogel 
40168eb6488eSEric Joyner 	++que->irqs;
40178eb6488eSEric Joyner 	if (eicr == 0) {
4018c19c7afeSEric Joyner 		ixgbe_if_enable_intr(ctx);
4019c19c7afeSEric Joyner 		return (FILTER_HANDLED);
4020758cc3dcSJack F Vogel 	}
4021758cc3dcSJack F Vogel 
40228eb6488eSEric Joyner 	/* Check for fan failure */
4023f72de14eSKevin Bowling 	if ((sc->feat_en & IXGBE_FEATURE_FAN_FAIL) &&
4024c19c7afeSEric Joyner 	    (eicr & IXGBE_EICR_GPI_SDP1)) {
4025b1d5caf3SKevin Bowling 		device_printf(sc->dev,
4026c19c7afeSEric Joyner 		    "\nCRITICAL: FAN FAILURE!! REPLACE IMMEDIATELY!!\n");
40278eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
4028758cc3dcSJack F Vogel 	}
4029758cc3dcSJack F Vogel 
40308eb6488eSEric Joyner 	/* Link status change */
4031c19c7afeSEric Joyner 	if (eicr & IXGBE_EICR_LSC) {
4032c19c7afeSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC);
4033c19c7afeSEric Joyner 		iflib_admin_intr_deferred(ctx);
4034c19c7afeSEric Joyner 	}
40358eb6488eSEric Joyner 
40368eb6488eSEric Joyner 	if (ixgbe_is_sfp(hw)) {
40378eb6488eSEric Joyner 		/* Pluggable optics-related interrupt */
40388eb6488eSEric Joyner 		if (hw->mac.type >= ixgbe_mac_X540)
40398eb6488eSEric Joyner 			eicr_mask = IXGBE_EICR_GPI_SDP0_X540;
40408eb6488eSEric Joyner 		else
40418eb6488eSEric Joyner 			eicr_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw);
40428eb6488eSEric Joyner 
40438eb6488eSEric Joyner 		if (eicr & eicr_mask) {
40448eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask);
4045b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_MOD;
40468eb6488eSEric Joyner 		}
40478eb6488eSEric Joyner 
40488eb6488eSEric Joyner 		if ((hw->mac.type == ixgbe_mac_82599EB) &&
40498eb6488eSEric Joyner 		    (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) {
40508eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR,
40518eb6488eSEric Joyner 			    IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
4052b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_MSF;
40538eb6488eSEric Joyner 		}
40548eb6488eSEric Joyner 	}
40558eb6488eSEric Joyner 
40568eb6488eSEric Joyner 	/* External PHY interrupt */
40578eb6488eSEric Joyner 	if ((hw->phy.type == ixgbe_phy_x550em_ext_t) &&
40588eb6488eSEric Joyner 	    (eicr & IXGBE_EICR_GPI_SDP0_X540))
4059b1d5caf3SKevin Bowling 		sc->task_requests |= IXGBE_REQUEST_TASK_PHY;
40608eb6488eSEric Joyner 
4061c19c7afeSEric Joyner 	return (FILTER_SCHEDULE_THREAD);
4062c19c7afeSEric Joyner } /* ixgbe_intr */
40638eb6488eSEric Joyner 
40648eb6488eSEric Joyner /************************************************************************
40658eb6488eSEric Joyner  * ixgbe_free_pci_resources
40668eb6488eSEric Joyner  ************************************************************************/
40678eb6488eSEric Joyner static void
4068c19c7afeSEric Joyner ixgbe_free_pci_resources(if_ctx_t ctx)
40698eb6488eSEric Joyner {
4070b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
4071b1d5caf3SKevin Bowling 	struct         ix_rx_queue *que = sc->rx_queues;
4072c19c7afeSEric Joyner 	device_t       dev = iflib_get_dev(ctx);
40738eb6488eSEric Joyner 
4074b97de13aSMarius Strobl 	/* Release all MSI-X queue resources */
4075b1d5caf3SKevin Bowling 	if (sc->intr_type == IFLIB_INTR_MSIX)
4076b1d5caf3SKevin Bowling 		iflib_irq_free(ctx, &sc->irq);
4077c19c7afeSEric Joyner 
4078c19c7afeSEric Joyner 	if (que != NULL) {
4079b1d5caf3SKevin Bowling 		for (int i = 0; i < sc->num_rx_queues; i++, que++) {
4080c19c7afeSEric Joyner 			iflib_irq_free(ctx, &que->que_irq);
4081c19c7afeSEric Joyner 		}
4082c19c7afeSEric Joyner 	}
40838eb6488eSEric Joyner 
4084b1d5caf3SKevin Bowling 	if (sc->pci_mem != NULL)
4085c19c7afeSEric Joyner 		bus_release_resource(dev, SYS_RES_MEMORY,
4086b1d5caf3SKevin Bowling 		    rman_get_rid(sc->pci_mem), sc->pci_mem);
40878eb6488eSEric Joyner } /* ixgbe_free_pci_resources */
40888eb6488eSEric Joyner 
40898eb6488eSEric Joyner /************************************************************************
40908eb6488eSEric Joyner  * ixgbe_sysctl_flowcntl
40918eb6488eSEric Joyner  *
40928eb6488eSEric Joyner  *   SYSCTL wrapper around setting Flow Control
40938eb6488eSEric Joyner  ************************************************************************/
4094758cc3dcSJack F Vogel static int
4095f2c4db54SSteven Hartland ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS)
4096758cc3dcSJack F Vogel {
4097b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc;
40988eb6488eSEric Joyner 	int            error, fc;
4099758cc3dcSJack F Vogel 
4100b1d5caf3SKevin Bowling 	sc = (struct ixgbe_softc *)arg1;
4101b1d5caf3SKevin Bowling 	fc = sc->hw.fc.current_mode;
4102f2c4db54SSteven Hartland 
4103f2c4db54SSteven Hartland 	error = sysctl_handle_int(oidp, &fc, 0, req);
4104758cc3dcSJack F Vogel 	if ((error) || (req->newptr == NULL))
4105758cc3dcSJack F Vogel 		return (error);
4106758cc3dcSJack F Vogel 
4107758cc3dcSJack F Vogel 	/* Don't bother if it's not changed */
4108b1d5caf3SKevin Bowling 	if (fc == sc->hw.fc.current_mode)
4109758cc3dcSJack F Vogel 		return (0);
4110758cc3dcSJack F Vogel 
4111b1d5caf3SKevin Bowling 	return ixgbe_set_flowcntl(sc, fc);
41128eb6488eSEric Joyner } /* ixgbe_sysctl_flowcntl */
4113f2c4db54SSteven Hartland 
41148eb6488eSEric Joyner /************************************************************************
41158eb6488eSEric Joyner  * ixgbe_set_flowcntl - Set flow control
41168eb6488eSEric Joyner  *
41178eb6488eSEric Joyner  *   Flow control values:
41188eb6488eSEric Joyner  *     0 - off
41198eb6488eSEric Joyner  *     1 - rx pause
41208eb6488eSEric Joyner  *     2 - tx pause
41218eb6488eSEric Joyner  *     3 - full
41228eb6488eSEric Joyner  ************************************************************************/
4123f2c4db54SSteven Hartland static int
4124b1d5caf3SKevin Bowling ixgbe_set_flowcntl(struct ixgbe_softc *sc, int fc)
4125f2c4db54SSteven Hartland {
4126f2c4db54SSteven Hartland 	switch (fc) {
4127758cc3dcSJack F Vogel 	case ixgbe_fc_rx_pause:
4128758cc3dcSJack F Vogel 	case ixgbe_fc_tx_pause:
4129758cc3dcSJack F Vogel 	case ixgbe_fc_full:
4130b1d5caf3SKevin Bowling 		sc->hw.fc.requested_mode = fc;
4131b1d5caf3SKevin Bowling 		if (sc->num_rx_queues > 1)
4132b1d5caf3SKevin Bowling 			ixgbe_disable_rx_drop(sc);
4133758cc3dcSJack F Vogel 		break;
4134758cc3dcSJack F Vogel 	case ixgbe_fc_none:
4135b1d5caf3SKevin Bowling 		sc->hw.fc.requested_mode = ixgbe_fc_none;
4136b1d5caf3SKevin Bowling 		if (sc->num_rx_queues > 1)
4137b1d5caf3SKevin Bowling 			ixgbe_enable_rx_drop(sc);
4138758cc3dcSJack F Vogel 		break;
4139758cc3dcSJack F Vogel 	default:
4140758cc3dcSJack F Vogel 		return (EINVAL);
4141758cc3dcSJack F Vogel 	}
41428eb6488eSEric Joyner 
4143758cc3dcSJack F Vogel 	/* Don't autoneg if forcing a value */
4144b1d5caf3SKevin Bowling 	sc->hw.fc.disable_fc_autoneg = true;
4145b1d5caf3SKevin Bowling 	ixgbe_fc_enable(&sc->hw);
41468eb6488eSEric Joyner 
4147f2c4db54SSteven Hartland 	return (0);
41488eb6488eSEric Joyner } /* ixgbe_set_flowcntl */
41498eb6488eSEric Joyner 
41508eb6488eSEric Joyner /************************************************************************
41518eb6488eSEric Joyner  * ixgbe_enable_rx_drop
41528eb6488eSEric Joyner  *
41538eb6488eSEric Joyner  *   Enable the hardware to drop packets when the buffer is
41548eb6488eSEric Joyner  *   full. This is useful with multiqueue, so that no single
41558eb6488eSEric Joyner  *   queue being full stalls the entire RX engine. We only
41568eb6488eSEric Joyner  *   enable this when Multiqueue is enabled AND Flow Control
41578eb6488eSEric Joyner  *   is disabled.
41588eb6488eSEric Joyner  ************************************************************************/
41598eb6488eSEric Joyner static void
4160b1d5caf3SKevin Bowling ixgbe_enable_rx_drop(struct ixgbe_softc *sc)
41618eb6488eSEric Joyner {
4162b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
41638eb6488eSEric Joyner 	struct rx_ring  *rxr;
41648eb6488eSEric Joyner 	u32             srrctl;
41658eb6488eSEric Joyner 
4166b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++) {
4167b1d5caf3SKevin Bowling 		rxr = &sc->rx_queues[i].rxr;
41688eb6488eSEric Joyner 		srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me));
41698eb6488eSEric Joyner 		srrctl |= IXGBE_SRRCTL_DROP_EN;
41708eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl);
4171758cc3dcSJack F Vogel 	}
4172758cc3dcSJack F Vogel 
41738eb6488eSEric Joyner 	/* enable drop for each vf */
4174b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_vfs; i++) {
41758eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_QDE,
41768eb6488eSEric Joyner 		                (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT) |
41778eb6488eSEric Joyner 		                IXGBE_QDE_ENABLE));
41788eb6488eSEric Joyner 	}
41798eb6488eSEric Joyner } /* ixgbe_enable_rx_drop */
41808eb6488eSEric Joyner 
41818eb6488eSEric Joyner /************************************************************************
41828eb6488eSEric Joyner  * ixgbe_disable_rx_drop
41838eb6488eSEric Joyner  ************************************************************************/
41848eb6488eSEric Joyner static void
4185b1d5caf3SKevin Bowling ixgbe_disable_rx_drop(struct ixgbe_softc *sc)
41868eb6488eSEric Joyner {
4187b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
41888eb6488eSEric Joyner 	struct rx_ring  *rxr;
41898eb6488eSEric Joyner 	u32             srrctl;
41908eb6488eSEric Joyner 
4191b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++) {
4192b1d5caf3SKevin Bowling 		rxr = &sc->rx_queues[i].rxr;
41938eb6488eSEric Joyner 		srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me));
41948eb6488eSEric Joyner 		srrctl &= ~IXGBE_SRRCTL_DROP_EN;
41958eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl);
41968eb6488eSEric Joyner 	}
41978eb6488eSEric Joyner 
41988eb6488eSEric Joyner 	/* disable drop for each vf */
4199b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_vfs; i++) {
42008eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_QDE,
42018eb6488eSEric Joyner 		    (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT)));
42028eb6488eSEric Joyner 	}
42038eb6488eSEric Joyner } /* ixgbe_disable_rx_drop */
42048eb6488eSEric Joyner 
42058eb6488eSEric Joyner /************************************************************************
42068eb6488eSEric Joyner  * ixgbe_sysctl_advertise
42078eb6488eSEric Joyner  *
42088eb6488eSEric Joyner  *   SYSCTL wrapper around setting advertised speed
42098eb6488eSEric Joyner  ************************************************************************/
4210758cc3dcSJack F Vogel static int
4211f2c4db54SSteven Hartland ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS)
4212758cc3dcSJack F Vogel {
4213b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc;
42148eb6488eSEric Joyner 	int            error, advertise;
4215758cc3dcSJack F Vogel 
4216b1d5caf3SKevin Bowling 	sc = (struct ixgbe_softc *)arg1;
4217f72de14eSKevin Bowling 	if (atomic_load_acq_int(&sc->recovery_mode))
4218f72de14eSKevin Bowling 		return (EPERM);
4219f72de14eSKevin Bowling 
4220b1d5caf3SKevin Bowling 	advertise = sc->advertise;
4221758cc3dcSJack F Vogel 
4222f2c4db54SSteven Hartland 	error = sysctl_handle_int(oidp, &advertise, 0, req);
4223758cc3dcSJack F Vogel 	if ((error) || (req->newptr == NULL))
4224758cc3dcSJack F Vogel 		return (error);
4225758cc3dcSJack F Vogel 
4226b1d5caf3SKevin Bowling 	return ixgbe_set_advertise(sc, advertise);
42278eb6488eSEric Joyner } /* ixgbe_sysctl_advertise */
4228f2c4db54SSteven Hartland 
42298eb6488eSEric Joyner /************************************************************************
42308eb6488eSEric Joyner  * ixgbe_set_advertise - Control advertised link speed
42318eb6488eSEric Joyner  *
42328eb6488eSEric Joyner  *   Flags:
42338eb6488eSEric Joyner  *     0x1  - advertise 100 Mb
42348eb6488eSEric Joyner  *     0x2  - advertise 1G
42358eb6488eSEric Joyner  *     0x4  - advertise 10G
42368eb6488eSEric Joyner  *     0x8  - advertise 10 Mb (yes, Mb)
4237d381c807SPiotr Pietruszewski  *     0x10 - advertise 2.5G (disabled by default)
4238d381c807SPiotr Pietruszewski  *     0x20 - advertise 5G (disabled by default)
4239d381c807SPiotr Pietruszewski  *
42408eb6488eSEric Joyner  ************************************************************************/
4241f2c4db54SSteven Hartland static int
4242b1d5caf3SKevin Bowling ixgbe_set_advertise(struct ixgbe_softc *sc, int advertise)
4243f2c4db54SSteven Hartland {
4244b1d5caf3SKevin Bowling 	device_t         dev = iflib_get_dev(sc->ctx);
4245f2c4db54SSteven Hartland 	struct ixgbe_hw  *hw;
42468eb6488eSEric Joyner 	ixgbe_link_speed speed = 0;
42478eb6488eSEric Joyner 	ixgbe_link_speed link_caps = 0;
42488eb6488eSEric Joyner 	s32              err = IXGBE_NOT_IMPLEMENTED;
424979b36ec9SKevin Bowling 	bool             negotiate = false;
4250f2c4db54SSteven Hartland 
4251d775d23aSSteven Hartland 	/* Checks to validate new value */
4252b1d5caf3SKevin Bowling 	if (sc->advertise == advertise) /* no change */
4253d775d23aSSteven Hartland 		return (0);
4254d775d23aSSteven Hartland 
4255b1d5caf3SKevin Bowling 	hw = &sc->hw;
4256f2c4db54SSteven Hartland 
4257a9ca1c79SSean Bruno 	/* No speed changes for backplane media */
4258a9ca1c79SSean Bruno 	if (hw->phy.media_type == ixgbe_media_type_backplane)
4259a9ca1c79SSean Bruno 		return (ENODEV);
4260a9ca1c79SSean Bruno 
4261758cc3dcSJack F Vogel 	if (!((hw->phy.media_type == ixgbe_media_type_copper) ||
4262758cc3dcSJack F Vogel 	      (hw->phy.multispeed_fiber))) {
42638eb6488eSEric Joyner 		device_printf(dev, "Advertised speed can only be set on copper or multispeed fiber media types.\n");
4264758cc3dcSJack F Vogel 		return (EINVAL);
4265758cc3dcSJack F Vogel 	}
4266758cc3dcSJack F Vogel 
4267d381c807SPiotr Pietruszewski 	if (advertise < 0x1 || advertise > 0x3F) {
4268d381c807SPiotr Pietruszewski 		device_printf(dev, "Invalid advertised speed; valid modes are 0x1 through 0x3F\n");
4269758cc3dcSJack F Vogel 		return (EINVAL);
4270758cc3dcSJack F Vogel 	}
4271758cc3dcSJack F Vogel 
42728eb6488eSEric Joyner 	if (hw->mac.ops.get_link_capabilities) {
42738eb6488eSEric Joyner 		err = hw->mac.ops.get_link_capabilities(hw, &link_caps,
42748eb6488eSEric Joyner 		    &negotiate);
42758eb6488eSEric Joyner 		if (err != IXGBE_SUCCESS) {
42768eb6488eSEric Joyner 			device_printf(dev, "Unable to determine supported advertise speeds\n");
42778eb6488eSEric Joyner 			return (ENODEV);
42788eb6488eSEric Joyner 		}
4279758cc3dcSJack F Vogel 	}
4280758cc3dcSJack F Vogel 
4281758cc3dcSJack F Vogel 	/* Set new value and report new advertised mode */
42828eb6488eSEric Joyner 	if (advertise & 0x1) {
42838eb6488eSEric Joyner 		if (!(link_caps & IXGBE_LINK_SPEED_100_FULL)) {
42848eb6488eSEric Joyner 			device_printf(dev, "Interface does not support 100Mb advertised speed\n");
42858eb6488eSEric Joyner 			return (EINVAL);
42868eb6488eSEric Joyner 		}
4287758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_100_FULL;
42888eb6488eSEric Joyner 	}
42898eb6488eSEric Joyner 	if (advertise & 0x2) {
42908eb6488eSEric Joyner 		if (!(link_caps & IXGBE_LINK_SPEED_1GB_FULL)) {
42918eb6488eSEric Joyner 			device_printf(dev, "Interface does not support 1Gb advertised speed\n");
42928eb6488eSEric Joyner 			return (EINVAL);
42938eb6488eSEric Joyner 		}
4294758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
42958eb6488eSEric Joyner 	}
42968eb6488eSEric Joyner 	if (advertise & 0x4) {
42978eb6488eSEric Joyner 		if (!(link_caps & IXGBE_LINK_SPEED_10GB_FULL)) {
42988eb6488eSEric Joyner 			device_printf(dev, "Interface does not support 10Gb advertised speed\n");
42998eb6488eSEric Joyner 			return (EINVAL);
43008eb6488eSEric Joyner 		}
4301758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_10GB_FULL;
43028eb6488eSEric Joyner 	}
43038eb6488eSEric Joyner 	if (advertise & 0x8) {
43048eb6488eSEric Joyner 		if (!(link_caps & IXGBE_LINK_SPEED_10_FULL)) {
43058eb6488eSEric Joyner 			device_printf(dev, "Interface does not support 10Mb advertised speed\n");
43068eb6488eSEric Joyner 			return (EINVAL);
43078eb6488eSEric Joyner 		}
43088eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_10_FULL;
43098eb6488eSEric Joyner 	}
4310d381c807SPiotr Pietruszewski 	if (advertise & 0x10) {
4311d381c807SPiotr Pietruszewski 		if (!(link_caps & IXGBE_LINK_SPEED_2_5GB_FULL)) {
4312d381c807SPiotr Pietruszewski 			device_printf(dev, "Interface does not support 2.5G advertised speed\n");
4313d381c807SPiotr Pietruszewski 			return (EINVAL);
4314d381c807SPiotr Pietruszewski 		}
4315d381c807SPiotr Pietruszewski 		speed |= IXGBE_LINK_SPEED_2_5GB_FULL;
4316d381c807SPiotr Pietruszewski 	}
4317d381c807SPiotr Pietruszewski 	if (advertise & 0x20) {
4318d381c807SPiotr Pietruszewski 		if (!(link_caps & IXGBE_LINK_SPEED_5GB_FULL)) {
4319d381c807SPiotr Pietruszewski 			device_printf(dev, "Interface does not support 5G advertised speed\n");
4320d381c807SPiotr Pietruszewski 			return (EINVAL);
4321d381c807SPiotr Pietruszewski 		}
4322d381c807SPiotr Pietruszewski 		speed |= IXGBE_LINK_SPEED_5GB_FULL;
4323d381c807SPiotr Pietruszewski 	}
4324758cc3dcSJack F Vogel 
432579b36ec9SKevin Bowling 	hw->mac.autotry_restart = true;
432679b36ec9SKevin Bowling 	hw->mac.ops.setup_link(hw, speed, true);
4327b1d5caf3SKevin Bowling 	sc->advertise = advertise;
4328758cc3dcSJack F Vogel 
4329f2c4db54SSteven Hartland 	return (0);
43308eb6488eSEric Joyner } /* ixgbe_set_advertise */
43318eb6488eSEric Joyner 
43328eb6488eSEric Joyner /************************************************************************
4333d381c807SPiotr Pietruszewski  * ixgbe_get_default_advertise - Get default advertised speed settings
43348eb6488eSEric Joyner  *
43358eb6488eSEric Joyner  *   Formatted for sysctl usage.
43368eb6488eSEric Joyner  *   Flags:
43378eb6488eSEric Joyner  *     0x1 - advertise 100 Mb
43388eb6488eSEric Joyner  *     0x2 - advertise 1G
43398eb6488eSEric Joyner  *     0x4 - advertise 10G
43408eb6488eSEric Joyner  *     0x8 - advertise 10 Mb (yes, Mb)
4341d381c807SPiotr Pietruszewski  *     0x10 - advertise 2.5G (disabled by default)
4342d381c807SPiotr Pietruszewski  *     0x20 - advertise 5G (disabled by default)
43438eb6488eSEric Joyner  ************************************************************************/
43448eb6488eSEric Joyner static int
4345d381c807SPiotr Pietruszewski ixgbe_get_default_advertise(struct ixgbe_softc *sc)
43468eb6488eSEric Joyner {
4347b1d5caf3SKevin Bowling 	struct ixgbe_hw  *hw = &sc->hw;
43488eb6488eSEric Joyner 	int              speed;
43498eb6488eSEric Joyner 	ixgbe_link_speed link_caps = 0;
43508eb6488eSEric Joyner 	s32              err;
435179b36ec9SKevin Bowling 	bool             negotiate = false;
4352758cc3dcSJack F Vogel 
4353758cc3dcSJack F Vogel 	/*
43548eb6488eSEric Joyner 	 * Advertised speed means nothing unless it's copper or
43558eb6488eSEric Joyner 	 * multi-speed fiber
4356758cc3dcSJack F Vogel 	 */
43578eb6488eSEric Joyner 	if (!(hw->phy.media_type == ixgbe_media_type_copper) &&
43588eb6488eSEric Joyner 	    !(hw->phy.multispeed_fiber))
4359758cc3dcSJack F Vogel 		return (0);
4360758cc3dcSJack F Vogel 
43618eb6488eSEric Joyner 	err = hw->mac.ops.get_link_capabilities(hw, &link_caps, &negotiate);
43628eb6488eSEric Joyner 	if (err != IXGBE_SUCCESS)
43638eb6488eSEric Joyner 		return (0);
43648eb6488eSEric Joyner 
4365d381c807SPiotr Pietruszewski 	if (hw->mac.type == ixgbe_mac_X550) {
4366d381c807SPiotr Pietruszewski 		/*
4367d381c807SPiotr Pietruszewski 		 * 2.5G and 5G autonegotiation speeds on X550
4368d381c807SPiotr Pietruszewski 		 * are disabled by default due to reported
4369d381c807SPiotr Pietruszewski 		 * interoperability issues with some switches.
4370d381c807SPiotr Pietruszewski 		 */
4371d381c807SPiotr Pietruszewski 		link_caps &= ~(IXGBE_LINK_SPEED_2_5GB_FULL |
4372d381c807SPiotr Pietruszewski 		    IXGBE_LINK_SPEED_5GB_FULL);
4373d381c807SPiotr Pietruszewski 	}
4374d381c807SPiotr Pietruszewski 
43758eb6488eSEric Joyner 	speed =
4376d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_10GB_FULL)  ? 0x4  : 0) |
4377d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_5GB_FULL)   ? 0x20 : 0) |
4378d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_2_5GB_FULL) ? 0x10 : 0) |
4379d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_1GB_FULL)   ? 0x2  : 0) |
4380d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_100_FULL)   ? 0x1  : 0) |
4381d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_10_FULL)    ? 0x8  : 0);
43828eb6488eSEric Joyner 
43838eb6488eSEric Joyner 	return speed;
4384d381c807SPiotr Pietruszewski } /* ixgbe_get_default_advertise */
43858eb6488eSEric Joyner 
43868eb6488eSEric Joyner /************************************************************************
43878eb6488eSEric Joyner  * ixgbe_sysctl_dmac - Manage DMA Coalescing
43888eb6488eSEric Joyner  *
43898eb6488eSEric Joyner  *   Control values:
43908eb6488eSEric Joyner  *     0/1 - off / on (use default value of 1000)
43918eb6488eSEric Joyner  *
43928eb6488eSEric Joyner  *     Legal timer values are:
43938eb6488eSEric Joyner  *     50,100,250,500,1000,2000,5000,10000
43948eb6488eSEric Joyner  *
43958eb6488eSEric Joyner  *     Turning off interrupt moderation will also turn this off.
43968eb6488eSEric Joyner  ************************************************************************/
43976f37f232SEric Joyner static int
43986f37f232SEric Joyner ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS)
43996f37f232SEric Joyner {
4400b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
4401ff06a8dbSJustin Hibbits 	if_t           ifp = iflib_get_ifp(sc->ctx);
44026f37f232SEric Joyner 	int            error;
4403c19c7afeSEric Joyner 	u16            newval;
44046f37f232SEric Joyner 
4405b1d5caf3SKevin Bowling 	newval = sc->dmac;
4406c19c7afeSEric Joyner 	error = sysctl_handle_16(oidp, &newval, 0, req);
44076f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
44086f37f232SEric Joyner 		return (error);
44096f37f232SEric Joyner 
4410a9ca1c79SSean Bruno 	switch (newval) {
44116f37f232SEric Joyner 	case 0:
44126f37f232SEric Joyner 		/* Disabled */
4413b1d5caf3SKevin Bowling 		sc->dmac = 0;
44146f37f232SEric Joyner 		break;
4415a9ca1c79SSean Bruno 	case 1:
4416a9ca1c79SSean Bruno 		/* Enable and use default */
4417b1d5caf3SKevin Bowling 		sc->dmac = 1000;
44186f37f232SEric Joyner 		break;
44196f37f232SEric Joyner 	case 50:
44206f37f232SEric Joyner 	case 100:
44216f37f232SEric Joyner 	case 250:
44226f37f232SEric Joyner 	case 500:
44236f37f232SEric Joyner 	case 1000:
44246f37f232SEric Joyner 	case 2000:
44256f37f232SEric Joyner 	case 5000:
44266f37f232SEric Joyner 	case 10000:
44276f37f232SEric Joyner 		/* Legal values - allow */
4428b1d5caf3SKevin Bowling 		sc->dmac = newval;
44296f37f232SEric Joyner 		break;
44306f37f232SEric Joyner 	default:
44316f37f232SEric Joyner 		/* Do nothing, illegal value */
44326f37f232SEric Joyner 		return (EINVAL);
44336f37f232SEric Joyner 	}
44346f37f232SEric Joyner 
44356f37f232SEric Joyner 	/* Re-initialize hardware if it's already running */
4436ff06a8dbSJustin Hibbits 	if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
4437ff06a8dbSJustin Hibbits 		if_init(ifp, ifp);
44386f37f232SEric Joyner 
44396f37f232SEric Joyner 	return (0);
44408eb6488eSEric Joyner } /* ixgbe_sysctl_dmac */
44416f37f232SEric Joyner 
4442a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
44438eb6488eSEric Joyner /************************************************************************
44448eb6488eSEric Joyner  * ixgbe_sysctl_power_state
44458eb6488eSEric Joyner  *
4446a9ca1c79SSean Bruno  *   Sysctl to test power states
4447a9ca1c79SSean Bruno  *   Values:
4448a9ca1c79SSean Bruno  *     0      - set device to D0
4449a9ca1c79SSean Bruno  *     3      - set device to D3
4450a9ca1c79SSean Bruno  *     (none) - get current device power state
44518eb6488eSEric Joyner  ************************************************************************/
4452a9ca1c79SSean Bruno static int
4453a9ca1c79SSean Bruno ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS)
4454a9ca1c79SSean Bruno {
4455b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
4456b1d5caf3SKevin Bowling 	device_t       dev = sc->dev;
4457a9ca1c79SSean Bruno 	int            curr_ps, new_ps, error = 0;
4458a9ca1c79SSean Bruno 
4459a9ca1c79SSean Bruno 	curr_ps = new_ps = pci_get_powerstate(dev);
4460a9ca1c79SSean Bruno 
4461a9ca1c79SSean Bruno 	error = sysctl_handle_int(oidp, &new_ps, 0, req);
4462a9ca1c79SSean Bruno 	if ((error) || (req->newptr == NULL))
4463a9ca1c79SSean Bruno 		return (error);
4464a9ca1c79SSean Bruno 
4465a9ca1c79SSean Bruno 	if (new_ps == curr_ps)
4466a9ca1c79SSean Bruno 		return (0);
4467a9ca1c79SSean Bruno 
4468a9ca1c79SSean Bruno 	if (new_ps == 3 && curr_ps == 0)
4469a9ca1c79SSean Bruno 		error = DEVICE_SUSPEND(dev);
4470a9ca1c79SSean Bruno 	else if (new_ps == 0 && curr_ps == 3)
4471a9ca1c79SSean Bruno 		error = DEVICE_RESUME(dev);
4472a9ca1c79SSean Bruno 	else
4473a9ca1c79SSean Bruno 		return (EINVAL);
4474a9ca1c79SSean Bruno 
4475a9ca1c79SSean Bruno 	device_printf(dev, "New state: %d\n", pci_get_powerstate(dev));
4476a9ca1c79SSean Bruno 
4477a9ca1c79SSean Bruno 	return (error);
44788eb6488eSEric Joyner } /* ixgbe_sysctl_power_state */
4479a9ca1c79SSean Bruno #endif
44808eb6488eSEric Joyner 
44818eb6488eSEric Joyner /************************************************************************
44828eb6488eSEric Joyner  * ixgbe_sysctl_wol_enable
44838eb6488eSEric Joyner  *
44848eb6488eSEric Joyner  *   Sysctl to enable/disable the WoL capability,
44858eb6488eSEric Joyner  *   if supported by the adapter.
44868eb6488eSEric Joyner  *
44876f37f232SEric Joyner  *   Values:
44886f37f232SEric Joyner  *     0 - disabled
44896f37f232SEric Joyner  *     1 - enabled
44908eb6488eSEric Joyner  ************************************************************************/
44916f37f232SEric Joyner static int
44926f37f232SEric Joyner ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS)
44936f37f232SEric Joyner {
4494b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = (struct ixgbe_softc *)arg1;
4495b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
44966f37f232SEric Joyner 	int             new_wol_enabled;
44976f37f232SEric Joyner 	int             error = 0;
44986f37f232SEric Joyner 
44996f37f232SEric Joyner 	new_wol_enabled = hw->wol_enabled;
45006f37f232SEric Joyner 	error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req);
45016f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
45026f37f232SEric Joyner 		return (error);
4503a9ca1c79SSean Bruno 	new_wol_enabled = !!(new_wol_enabled);
45046f37f232SEric Joyner 	if (new_wol_enabled == hw->wol_enabled)
45056f37f232SEric Joyner 		return (0);
45066f37f232SEric Joyner 
4507b1d5caf3SKevin Bowling 	if (new_wol_enabled > 0 && !sc->wol_support)
45086f37f232SEric Joyner 		return (ENODEV);
45096f37f232SEric Joyner 	else
4510a9ca1c79SSean Bruno 		hw->wol_enabled = new_wol_enabled;
45116f37f232SEric Joyner 
45126f37f232SEric Joyner 	return (0);
45138eb6488eSEric Joyner } /* ixgbe_sysctl_wol_enable */
45146f37f232SEric Joyner 
45158eb6488eSEric Joyner /************************************************************************
45168eb6488eSEric Joyner  * ixgbe_sysctl_wufc - Wake Up Filter Control
45178eb6488eSEric Joyner  *
45186f37f232SEric Joyner  *   Sysctl to enable/disable the types of packets that the
45196f37f232SEric Joyner  *   adapter will wake up on upon receipt.
45206f37f232SEric Joyner  *   Flags:
45216f37f232SEric Joyner  *     0x1  - Link Status Change
45226f37f232SEric Joyner  *     0x2  - Magic Packet
45236f37f232SEric Joyner  *     0x4  - Direct Exact
45246f37f232SEric Joyner  *     0x8  - Directed Multicast
45256f37f232SEric Joyner  *     0x10 - Broadcast
45266f37f232SEric Joyner  *     0x20 - ARP/IPv4 Request Packet
45276f37f232SEric Joyner  *     0x40 - Direct IPv4 Packet
45286f37f232SEric Joyner  *     0x80 - Direct IPv6 Packet
45296f37f232SEric Joyner  *
45308eb6488eSEric Joyner  *   Settings not listed above will cause the sysctl to return an error.
45318eb6488eSEric Joyner  ************************************************************************/
45326f37f232SEric Joyner static int
45336f37f232SEric Joyner ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS)
45346f37f232SEric Joyner {
4535b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
45366f37f232SEric Joyner 	int            error = 0;
45376f37f232SEric Joyner 	u32            new_wufc;
45386f37f232SEric Joyner 
4539b1d5caf3SKevin Bowling 	new_wufc = sc->wufc;
45406f37f232SEric Joyner 
4541c19c7afeSEric Joyner 	error = sysctl_handle_32(oidp, &new_wufc, 0, req);
45426f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
45436f37f232SEric Joyner 		return (error);
4544b1d5caf3SKevin Bowling 	if (new_wufc == sc->wufc)
45456f37f232SEric Joyner 		return (0);
45466f37f232SEric Joyner 
45476f37f232SEric Joyner 	if (new_wufc & 0xffffff00)
45486f37f232SEric Joyner 		return (EINVAL);
45498eb6488eSEric Joyner 
45506f37f232SEric Joyner 	new_wufc &= 0xff;
4551b1d5caf3SKevin Bowling 	new_wufc |= (0xffffff & sc->wufc);
4552b1d5caf3SKevin Bowling 	sc->wufc = new_wufc;
45536f37f232SEric Joyner 
45546f37f232SEric Joyner 	return (0);
45558eb6488eSEric Joyner } /* ixgbe_sysctl_wufc */
45566f37f232SEric Joyner 
4557a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
45588eb6488eSEric Joyner /************************************************************************
45598eb6488eSEric Joyner  * ixgbe_sysctl_print_rss_config
45608eb6488eSEric Joyner  ************************************************************************/
4561a9ca1c79SSean Bruno static int
4562a9ca1c79SSean Bruno ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS)
4563a9ca1c79SSean Bruno {
4564b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = (struct ixgbe_softc *)arg1;
4565b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
4566b1d5caf3SKevin Bowling 	device_t        dev = sc->dev;
4567a9ca1c79SSean Bruno 	struct sbuf     *buf;
45688eb6488eSEric Joyner 	int             error = 0, reta_size;
4569a9ca1c79SSean Bruno 	u32             reg;
4570a9ca1c79SSean Bruno 
4571f72de14eSKevin Bowling 	if (atomic_load_acq_int(&sc->recovery_mode))
4572f72de14eSKevin Bowling 		return (EPERM);
4573f72de14eSKevin Bowling 
4574a9ca1c79SSean Bruno 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4575a9ca1c79SSean Bruno 	if (!buf) {
4576a9ca1c79SSean Bruno 		device_printf(dev, "Could not allocate sbuf for output.\n");
4577a9ca1c79SSean Bruno 		return (ENOMEM);
4578a9ca1c79SSean Bruno 	}
4579a9ca1c79SSean Bruno 
4580a9ca1c79SSean Bruno 	// TODO: use sbufs to make a string to print out
4581a9ca1c79SSean Bruno 	/* Set multiplier for RETA setup and table size based on MAC */
4582b1d5caf3SKevin Bowling 	switch (sc->hw.mac.type) {
4583a9ca1c79SSean Bruno 	case ixgbe_mac_X550:
4584a9ca1c79SSean Bruno 	case ixgbe_mac_X550EM_x:
45858eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
4586a9ca1c79SSean Bruno 		reta_size = 128;
4587a9ca1c79SSean Bruno 		break;
4588a9ca1c79SSean Bruno 	default:
4589a9ca1c79SSean Bruno 		reta_size = 32;
4590a9ca1c79SSean Bruno 		break;
4591a9ca1c79SSean Bruno 	}
4592a9ca1c79SSean Bruno 
4593a9ca1c79SSean Bruno 	/* Print out the redirection table */
4594a9ca1c79SSean Bruno 	sbuf_cat(buf, "\n");
4595a9ca1c79SSean Bruno 	for (int i = 0; i < reta_size; i++) {
4596a9ca1c79SSean Bruno 		if (i < 32) {
4597a9ca1c79SSean Bruno 			reg = IXGBE_READ_REG(hw, IXGBE_RETA(i));
4598a9ca1c79SSean Bruno 			sbuf_printf(buf, "RETA(%2d): 0x%08x\n", i, reg);
4599a9ca1c79SSean Bruno 		} else {
4600a9ca1c79SSean Bruno 			reg = IXGBE_READ_REG(hw, IXGBE_ERETA(i - 32));
4601a9ca1c79SSean Bruno 			sbuf_printf(buf, "ERETA(%2d): 0x%08x\n", i - 32, reg);
4602a9ca1c79SSean Bruno 		}
4603a9ca1c79SSean Bruno 	}
4604a9ca1c79SSean Bruno 
4605a9ca1c79SSean Bruno 	// TODO: print more config
4606a9ca1c79SSean Bruno 
4607a9ca1c79SSean Bruno 	error = sbuf_finish(buf);
4608a9ca1c79SSean Bruno 	if (error)
4609a9ca1c79SSean Bruno 		device_printf(dev, "Error finishing sbuf: %d\n", error);
4610a9ca1c79SSean Bruno 
4611a9ca1c79SSean Bruno 	sbuf_delete(buf);
46128eb6488eSEric Joyner 
4613a9ca1c79SSean Bruno 	return (0);
46148eb6488eSEric Joyner } /* ixgbe_sysctl_print_rss_config */
4615a9ca1c79SSean Bruno #endif /* IXGBE_DEBUG */
4616a9ca1c79SSean Bruno 
46178eb6488eSEric Joyner /************************************************************************
46188eb6488eSEric Joyner  * ixgbe_sysctl_phy_temp - Retrieve temperature of PHY
46198eb6488eSEric Joyner  *
46208eb6488eSEric Joyner  *   For X552/X557-AT devices using an external PHY
46218eb6488eSEric Joyner  ************************************************************************/
46228eb6488eSEric Joyner static int
46238eb6488eSEric Joyner ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS)
46248eb6488eSEric Joyner {
4625b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = (struct ixgbe_softc *)arg1;
4626b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
46278eb6488eSEric Joyner 	u16             reg;
46288eb6488eSEric Joyner 
4629f72de14eSKevin Bowling 	if (atomic_load_acq_int(&sc->recovery_mode))
4630f72de14eSKevin Bowling 		return (EPERM);
4631f72de14eSKevin Bowling 
46328eb6488eSEric Joyner 	if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
4633b1d5caf3SKevin Bowling 		device_printf(iflib_get_dev(sc->ctx),
46348eb6488eSEric Joyner 		    "Device has no supported external thermal sensor.\n");
46358eb6488eSEric Joyner 		return (ENODEV);
46368eb6488eSEric Joyner 	}
46378eb6488eSEric Joyner 
46388eb6488eSEric Joyner 	if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP,
46398eb6488eSEric Joyner 	    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &reg)) {
4640b1d5caf3SKevin Bowling 		device_printf(iflib_get_dev(sc->ctx),
46418eb6488eSEric Joyner 		    "Error reading from PHY's current temperature register\n");
46428eb6488eSEric Joyner 		return (EAGAIN);
46438eb6488eSEric Joyner 	}
46448eb6488eSEric Joyner 
46458eb6488eSEric Joyner 	/* Shift temp for output */
46468eb6488eSEric Joyner 	reg = reg >> 8;
46478eb6488eSEric Joyner 
4648c19c7afeSEric Joyner 	return (sysctl_handle_16(oidp, NULL, reg, req));
46498eb6488eSEric Joyner } /* ixgbe_sysctl_phy_temp */
46508eb6488eSEric Joyner 
46518eb6488eSEric Joyner /************************************************************************
46528eb6488eSEric Joyner  * ixgbe_sysctl_phy_overtemp_occurred
46538eb6488eSEric Joyner  *
46548eb6488eSEric Joyner  *   Reports (directly from the PHY) whether the current PHY
46558eb6488eSEric Joyner  *   temperature is over the overtemp threshold.
46568eb6488eSEric Joyner  ************************************************************************/
46578eb6488eSEric Joyner static int
46588eb6488eSEric Joyner ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS)
46598eb6488eSEric Joyner {
4660b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = (struct ixgbe_softc *)arg1;
4661b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
46628eb6488eSEric Joyner 	u16             reg;
46638eb6488eSEric Joyner 
4664f72de14eSKevin Bowling 	if (atomic_load_acq_int(&sc->recovery_mode))
4665f72de14eSKevin Bowling 		return (EPERM);
4666f72de14eSKevin Bowling 
46678eb6488eSEric Joyner 	if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
4668b1d5caf3SKevin Bowling 		device_printf(iflib_get_dev(sc->ctx),
46698eb6488eSEric Joyner 		    "Device has no supported external thermal sensor.\n");
46708eb6488eSEric Joyner 		return (ENODEV);
46718eb6488eSEric Joyner 	}
46728eb6488eSEric Joyner 
46738eb6488eSEric Joyner 	if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS,
46748eb6488eSEric Joyner 	    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &reg)) {
4675b1d5caf3SKevin Bowling 		device_printf(iflib_get_dev(sc->ctx),
46768eb6488eSEric Joyner 		    "Error reading from PHY's temperature status register\n");
46778eb6488eSEric Joyner 		return (EAGAIN);
46788eb6488eSEric Joyner 	}
46798eb6488eSEric Joyner 
46808eb6488eSEric Joyner 	/* Get occurrence bit */
46818eb6488eSEric Joyner 	reg = !!(reg & 0x4000);
46828eb6488eSEric Joyner 
4683c19c7afeSEric Joyner 	return (sysctl_handle_16(oidp, 0, reg, req));
46848eb6488eSEric Joyner } /* ixgbe_sysctl_phy_overtemp_occurred */
46858eb6488eSEric Joyner 
46868eb6488eSEric Joyner /************************************************************************
46878eb6488eSEric Joyner  * ixgbe_sysctl_eee_state
46888eb6488eSEric Joyner  *
46898eb6488eSEric Joyner  *   Sysctl to set EEE power saving feature
46908eb6488eSEric Joyner  *   Values:
46918eb6488eSEric Joyner  *     0      - disable EEE
46928eb6488eSEric Joyner  *     1      - enable EEE
46938eb6488eSEric Joyner  *     (none) - get current device EEE state
46948eb6488eSEric Joyner  ************************************************************************/
46958eb6488eSEric Joyner static int
46968eb6488eSEric Joyner ixgbe_sysctl_eee_state(SYSCTL_HANDLER_ARGS)
46978eb6488eSEric Joyner {
4698b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
4699b1d5caf3SKevin Bowling 	device_t       dev = sc->dev;
4700ff06a8dbSJustin Hibbits 	if_t           ifp = iflib_get_ifp(sc->ctx);
47018eb6488eSEric Joyner 	int            curr_eee, new_eee, error = 0;
47028eb6488eSEric Joyner 	s32            retval;
47038eb6488eSEric Joyner 
4704f72de14eSKevin Bowling 	if (atomic_load_acq_int(&sc->recovery_mode))
4705f72de14eSKevin Bowling 		return (EPERM);
4706f72de14eSKevin Bowling 
4707b1d5caf3SKevin Bowling 	curr_eee = new_eee = !!(sc->feat_en & IXGBE_FEATURE_EEE);
47088eb6488eSEric Joyner 
47098eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &new_eee, 0, req);
47108eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
47118eb6488eSEric Joyner 		return (error);
47128eb6488eSEric Joyner 
47138eb6488eSEric Joyner 	/* Nothing to do */
47148eb6488eSEric Joyner 	if (new_eee == curr_eee)
47158eb6488eSEric Joyner 		return (0);
47168eb6488eSEric Joyner 
47178eb6488eSEric Joyner 	/* Not supported */
4718b1d5caf3SKevin Bowling 	if (!(sc->feat_cap & IXGBE_FEATURE_EEE))
47198eb6488eSEric Joyner 		return (EINVAL);
47208eb6488eSEric Joyner 
47218eb6488eSEric Joyner 	/* Bounds checking */
47228eb6488eSEric Joyner 	if ((new_eee < 0) || (new_eee > 1))
47238eb6488eSEric Joyner 		return (EINVAL);
47248eb6488eSEric Joyner 
4725b1d5caf3SKevin Bowling 	retval = ixgbe_setup_eee(&sc->hw, new_eee);
47268eb6488eSEric Joyner 	if (retval) {
47278eb6488eSEric Joyner 		device_printf(dev, "Error in EEE setup: 0x%08X\n", retval);
47288eb6488eSEric Joyner 		return (EINVAL);
47298eb6488eSEric Joyner 	}
47308eb6488eSEric Joyner 
47318eb6488eSEric Joyner 	/* Restart auto-neg */
4732ff06a8dbSJustin Hibbits 	if_init(ifp, ifp);
47338eb6488eSEric Joyner 
47348eb6488eSEric Joyner 	device_printf(dev, "New EEE state: %d\n", new_eee);
47358eb6488eSEric Joyner 
47368eb6488eSEric Joyner 	/* Cache new value */
47378eb6488eSEric Joyner 	if (new_eee)
4738b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_EEE;
47398eb6488eSEric Joyner 	else
4740b1d5caf3SKevin Bowling 		sc->feat_en &= ~IXGBE_FEATURE_EEE;
47418eb6488eSEric Joyner 
47428eb6488eSEric Joyner 	return (error);
47438eb6488eSEric Joyner } /* ixgbe_sysctl_eee_state */
47448eb6488eSEric Joyner 
47458eb6488eSEric Joyner /************************************************************************
47468eb6488eSEric Joyner  * ixgbe_init_device_features
47478eb6488eSEric Joyner  ************************************************************************/
47488eb6488eSEric Joyner static void
4749b1d5caf3SKevin Bowling ixgbe_init_device_features(struct ixgbe_softc *sc)
47508eb6488eSEric Joyner {
4751b1d5caf3SKevin Bowling 	sc->feat_cap = IXGBE_FEATURE_NETMAP
47528eb6488eSEric Joyner 	                  | IXGBE_FEATURE_RSS
47538eb6488eSEric Joyner 	                  | IXGBE_FEATURE_MSI
47548eb6488eSEric Joyner 	                  | IXGBE_FEATURE_MSIX
4755c19c7afeSEric Joyner 	                  | IXGBE_FEATURE_LEGACY_IRQ;
47568eb6488eSEric Joyner 
47578eb6488eSEric Joyner 	/* Set capabilities first... */
4758b1d5caf3SKevin Bowling 	switch (sc->hw.mac.type) {
47598eb6488eSEric Joyner 	case ixgbe_mac_82598EB:
4760b1d5caf3SKevin Bowling 		if (sc->hw.device_id == IXGBE_DEV_ID_82598AT)
4761b1d5caf3SKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_FAN_FAIL;
47628eb6488eSEric Joyner 		break;
47638eb6488eSEric Joyner 	case ixgbe_mac_X540:
4764b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_SRIOV;
4765b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_FDIR;
4766b1d5caf3SKevin Bowling 		if ((sc->hw.device_id == IXGBE_DEV_ID_X540_BYPASS) &&
4767b1d5caf3SKevin Bowling 		    (sc->hw.bus.func == 0))
4768b1d5caf3SKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_BYPASS;
47698eb6488eSEric Joyner 		break;
47708eb6488eSEric Joyner 	case ixgbe_mac_X550:
4771f72de14eSKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_RECOVERY_MODE;
4772b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_TEMP_SENSOR;
4773b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_SRIOV;
4774b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_FDIR;
47758eb6488eSEric Joyner 		break;
47768eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
4777f72de14eSKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_RECOVERY_MODE;
4778b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_SRIOV;
4779b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_FDIR;
4780f72de14eSKevin Bowling 		if (sc->hw.device_id == IXGBE_DEV_ID_X550EM_X_KR)
4781f72de14eSKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_EEE;
47828eb6488eSEric Joyner 		break;
47838eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
4784f72de14eSKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_RECOVERY_MODE;
4785b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_SRIOV;
4786b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_FDIR;
4787b1d5caf3SKevin Bowling 		sc->feat_cap &= ~IXGBE_FEATURE_LEGACY_IRQ;
4788b1d5caf3SKevin Bowling 		if ((sc->hw.device_id == IXGBE_DEV_ID_X550EM_A_1G_T) ||
4789b1d5caf3SKevin Bowling 		    (sc->hw.device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L)) {
4790b1d5caf3SKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_TEMP_SENSOR;
4791b1d5caf3SKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_EEE;
47928eb6488eSEric Joyner 		}
47938eb6488eSEric Joyner 		break;
47948eb6488eSEric Joyner 	case ixgbe_mac_82599EB:
4795b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_SRIOV;
4796b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_FDIR;
4797b1d5caf3SKevin Bowling 		if ((sc->hw.device_id == IXGBE_DEV_ID_82599_BYPASS) &&
4798b1d5caf3SKevin Bowling 		    (sc->hw.bus.func == 0))
4799b1d5caf3SKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_BYPASS;
4800b1d5caf3SKevin Bowling 		if (sc->hw.device_id == IXGBE_DEV_ID_82599_QSFP_SF_QP)
4801b1d5caf3SKevin Bowling 			sc->feat_cap &= ~IXGBE_FEATURE_LEGACY_IRQ;
48028eb6488eSEric Joyner 		break;
48038eb6488eSEric Joyner 	default:
48048eb6488eSEric Joyner 		break;
48058eb6488eSEric Joyner 	}
48068eb6488eSEric Joyner 
48078eb6488eSEric Joyner 	/* Enabled by default... */
48088eb6488eSEric Joyner 	/* Fan failure detection */
4809b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_FAN_FAIL)
4810b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_FAN_FAIL;
48118eb6488eSEric Joyner 	/* Netmap */
4812b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_NETMAP)
4813b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_NETMAP;
48148eb6488eSEric Joyner 	/* EEE */
4815b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_EEE)
4816b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_EEE;
48178eb6488eSEric Joyner 	/* Thermal Sensor */
4818b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_TEMP_SENSOR)
4819b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_TEMP_SENSOR;
4820f72de14eSKevin Bowling 	/* Recovery mode */
4821f72de14eSKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_RECOVERY_MODE)
4822f72de14eSKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_RECOVERY_MODE;
48238eb6488eSEric Joyner 
48248eb6488eSEric Joyner 	/* Enabled via global sysctl... */
48258eb6488eSEric Joyner 	/* Flow Director */
48268eb6488eSEric Joyner 	if (ixgbe_enable_fdir) {
4827b1d5caf3SKevin Bowling 		if (sc->feat_cap & IXGBE_FEATURE_FDIR)
4828b1d5caf3SKevin Bowling 			sc->feat_en |= IXGBE_FEATURE_FDIR;
48298eb6488eSEric Joyner 		else
4830b1d5caf3SKevin Bowling 			device_printf(sc->dev, "Device does not support Flow Director. Leaving disabled.");
48318eb6488eSEric Joyner 	}
48326f37f232SEric Joyner 	/*
48338eb6488eSEric Joyner 	 * Message Signal Interrupts - Extended (MSI-X)
48348eb6488eSEric Joyner 	 * Normal MSI is only enabled if MSI-X calls fail.
4835758cc3dcSJack F Vogel 	 */
48368eb6488eSEric Joyner 	if (!ixgbe_enable_msix)
4837b1d5caf3SKevin Bowling 		sc->feat_cap &= ~IXGBE_FEATURE_MSIX;
48388eb6488eSEric Joyner 	/* Receive-Side Scaling (RSS) */
4839b1d5caf3SKevin Bowling 	if ((sc->feat_cap & IXGBE_FEATURE_RSS) && ixgbe_enable_rss)
4840b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_RSS;
48418eb6488eSEric Joyner 
48428eb6488eSEric Joyner 	/* Disable features with unmet dependencies... */
48438eb6488eSEric Joyner 	/* No MSI-X */
4844b1d5caf3SKevin Bowling 	if (!(sc->feat_cap & IXGBE_FEATURE_MSIX)) {
4845b1d5caf3SKevin Bowling 		sc->feat_cap &= ~IXGBE_FEATURE_RSS;
4846b1d5caf3SKevin Bowling 		sc->feat_cap &= ~IXGBE_FEATURE_SRIOV;
4847b1d5caf3SKevin Bowling 		sc->feat_en &= ~IXGBE_FEATURE_RSS;
4848b1d5caf3SKevin Bowling 		sc->feat_en &= ~IXGBE_FEATURE_SRIOV;
48498eb6488eSEric Joyner 	}
48508eb6488eSEric Joyner } /* ixgbe_init_device_features */
48518eb6488eSEric Joyner 
48528eb6488eSEric Joyner /************************************************************************
48538eb6488eSEric Joyner  * ixgbe_check_fan_failure
48548eb6488eSEric Joyner  ************************************************************************/
48558eb6488eSEric Joyner static void
4856b1d5caf3SKevin Bowling ixgbe_check_fan_failure(struct ixgbe_softc *sc, u32 reg, bool in_interrupt)
48578eb6488eSEric Joyner {
48588eb6488eSEric Joyner 	u32 mask;
48598eb6488eSEric Joyner 
4860b1d5caf3SKevin Bowling 	mask = (in_interrupt) ? IXGBE_EICR_GPI_SDP1_BY_MAC(&sc->hw) :
48618eb6488eSEric Joyner 	    IXGBE_ESDP_SDP1;
48628eb6488eSEric Joyner 
48638eb6488eSEric Joyner 	if (reg & mask)
4864b1d5caf3SKevin Bowling 		device_printf(sc->dev, "\nCRITICAL: FAN FAILURE!! REPLACE IMMEDIATELY!!\n");
48658eb6488eSEric Joyner } /* ixgbe_check_fan_failure */
48667660e4eaSKevin Bowling 
48677660e4eaSKevin Bowling /************************************************************************
48687660e4eaSKevin Bowling  * ixgbe_sbuf_fw_version
48697660e4eaSKevin Bowling  ************************************************************************/
48707660e4eaSKevin Bowling static void
48717660e4eaSKevin Bowling ixgbe_sbuf_fw_version(struct ixgbe_hw *hw, struct sbuf *buf)
48727660e4eaSKevin Bowling {
48737660e4eaSKevin Bowling 	struct ixgbe_nvm_version nvm_ver = {0};
48745de5419bSKevin Bowling 	const char *space = "";
48757660e4eaSKevin Bowling 
4876f72de14eSKevin Bowling 	ixgbe_get_nvm_version(hw, &nvm_ver); /* NVM version */
48777660e4eaSKevin Bowling 	ixgbe_get_oem_prod_version(hw, &nvm_ver); /* OEM's NVM version */
48787660e4eaSKevin Bowling 	ixgbe_get_etk_id(hw, &nvm_ver); /* eTrack identifies a build in Intel's SCM */
4879f72de14eSKevin Bowling 	ixgbe_get_orom_version(hw, &nvm_ver); /* Option ROM */
4880f72de14eSKevin Bowling 
4881f72de14eSKevin Bowling 	/* FW version */
4882f72de14eSKevin Bowling 	if ((nvm_ver.phy_fw_maj == 0x0 &&
4883f72de14eSKevin Bowling 	    nvm_ver.phy_fw_min == 0x0 &&
4884f72de14eSKevin Bowling 	    nvm_ver.phy_fw_id == 0x0) ||
4885f72de14eSKevin Bowling 		(nvm_ver.phy_fw_maj == 0xF &&
4886f72de14eSKevin Bowling 	    nvm_ver.phy_fw_min == 0xFF &&
4887f72de14eSKevin Bowling 	    nvm_ver.phy_fw_id == 0xF)) {
4888f72de14eSKevin Bowling 		/* If major, minor and id numbers are set to 0,
4889f72de14eSKevin Bowling 		 * reading FW version is unsupported. If major number
4890f72de14eSKevin Bowling 		 * is set to 0xF, minor is set to 0xFF and id is set
4891f72de14eSKevin Bowling 		 * to 0xF, this means that number read is invalid. */
4892f72de14eSKevin Bowling 	} else
4893f72de14eSKevin Bowling 		sbuf_printf(buf, "fw %d.%d.%d ",
4894f72de14eSKevin Bowling 		    nvm_ver.phy_fw_maj, nvm_ver.phy_fw_min, nvm_ver.phy_fw_id);
4895f72de14eSKevin Bowling 
4896f72de14eSKevin Bowling 	/* NVM version */
4897f72de14eSKevin Bowling 	if ((nvm_ver.nvm_major == 0x0 &&
4898f72de14eSKevin Bowling 	    nvm_ver.nvm_minor == 0x0 &&
4899f72de14eSKevin Bowling 	    nvm_ver.nvm_id == 0x0) ||
4900f72de14eSKevin Bowling 		(nvm_ver.nvm_major == 0xF &&
4901f72de14eSKevin Bowling 	    nvm_ver.nvm_minor == 0xFF &&
4902f72de14eSKevin Bowling 	    nvm_ver.nvm_id == 0xF)) {
4903f72de14eSKevin Bowling 		/* If major, minor and id numbers are set to 0,
4904f72de14eSKevin Bowling 		 * reading NVM version is unsupported. If major number
4905f72de14eSKevin Bowling 		 * is set to 0xF, minor is set to 0xFF and id is set
4906f72de14eSKevin Bowling 		 * to 0xF, this means that number read is invalid. */
4907f72de14eSKevin Bowling 	} else
4908f72de14eSKevin Bowling 		sbuf_printf(buf, "nvm %x.%02x.%x ",
4909f72de14eSKevin Bowling 		    nvm_ver.nvm_major, nvm_ver.nvm_minor, nvm_ver.nvm_id);
49107660e4eaSKevin Bowling 
49115de5419bSKevin Bowling 	if (nvm_ver.oem_valid) {
49127660e4eaSKevin Bowling 		sbuf_printf(buf, "NVM OEM V%d.%d R%d", nvm_ver.oem_major,
49137660e4eaSKevin Bowling 		    nvm_ver.oem_minor, nvm_ver.oem_release);
49145de5419bSKevin Bowling 		space = " ";
49155de5419bSKevin Bowling 	}
49167660e4eaSKevin Bowling 
49175de5419bSKevin Bowling 	if (nvm_ver.or_valid) {
49185de5419bSKevin Bowling 		sbuf_printf(buf, "%sOption ROM V%d-b%d-p%d",
49195de5419bSKevin Bowling 		    space, nvm_ver.or_major, nvm_ver.or_build, nvm_ver.or_patch);
49205de5419bSKevin Bowling 		space = " ";
49215de5419bSKevin Bowling 	}
49227660e4eaSKevin Bowling 
49235de5419bSKevin Bowling 	if (nvm_ver.etk_id != ((NVM_VER_INVALID << NVM_ETK_SHIFT) |
4924f72de14eSKevin Bowling 	    NVM_VER_INVALID | 0xFFFFFFFF)) {
49255de5419bSKevin Bowling 		sbuf_printf(buf, "%seTrack 0x%08x", space, nvm_ver.etk_id);
49265de5419bSKevin Bowling 	}
49277660e4eaSKevin Bowling } /* ixgbe_sbuf_fw_version */
49287660e4eaSKevin Bowling 
49297660e4eaSKevin Bowling /************************************************************************
49307660e4eaSKevin Bowling  * ixgbe_print_fw_version
49317660e4eaSKevin Bowling  ************************************************************************/
49327660e4eaSKevin Bowling static void
49337660e4eaSKevin Bowling ixgbe_print_fw_version(if_ctx_t ctx)
49347660e4eaSKevin Bowling {
4935b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
4936b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
4937b1d5caf3SKevin Bowling 	device_t dev = sc->dev;
49387660e4eaSKevin Bowling 	struct sbuf *buf;
49397660e4eaSKevin Bowling 	int error = 0;
49407660e4eaSKevin Bowling 
49417660e4eaSKevin Bowling 	buf = sbuf_new_auto();
49427660e4eaSKevin Bowling 	if (!buf) {
49437660e4eaSKevin Bowling 		device_printf(dev, "Could not allocate sbuf for output.\n");
49447660e4eaSKevin Bowling 		return;
49457660e4eaSKevin Bowling 	}
49467660e4eaSKevin Bowling 
49477660e4eaSKevin Bowling 	ixgbe_sbuf_fw_version(hw, buf);
49487660e4eaSKevin Bowling 
49497660e4eaSKevin Bowling 	error = sbuf_finish(buf);
49507660e4eaSKevin Bowling 	if (error)
49517660e4eaSKevin Bowling 		device_printf(dev, "Error finishing sbuf: %d\n", error);
49527660e4eaSKevin Bowling 	else if (sbuf_len(buf))
49537660e4eaSKevin Bowling 		device_printf(dev, "%s\n", sbuf_data(buf));
49547660e4eaSKevin Bowling 
49557660e4eaSKevin Bowling 	sbuf_delete(buf);
49567660e4eaSKevin Bowling } /* ixgbe_print_fw_version */
49577660e4eaSKevin Bowling 
49587660e4eaSKevin Bowling /************************************************************************
49597660e4eaSKevin Bowling  * ixgbe_sysctl_print_fw_version
49607660e4eaSKevin Bowling  ************************************************************************/
49617660e4eaSKevin Bowling static int
49627660e4eaSKevin Bowling ixgbe_sysctl_print_fw_version(SYSCTL_HANDLER_ARGS)
49637660e4eaSKevin Bowling {
4964b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = (struct ixgbe_softc *)arg1;
4965b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
4966b1d5caf3SKevin Bowling 	device_t dev = sc->dev;
49677660e4eaSKevin Bowling 	struct sbuf *buf;
49687660e4eaSKevin Bowling 	int error = 0;
49697660e4eaSKevin Bowling 
49707660e4eaSKevin Bowling 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
49717660e4eaSKevin Bowling 	if (!buf) {
49727660e4eaSKevin Bowling 		device_printf(dev, "Could not allocate sbuf for output.\n");
49737660e4eaSKevin Bowling 		return (ENOMEM);
49747660e4eaSKevin Bowling 	}
49757660e4eaSKevin Bowling 
49767660e4eaSKevin Bowling 	ixgbe_sbuf_fw_version(hw, buf);
49777660e4eaSKevin Bowling 
49787660e4eaSKevin Bowling 	error = sbuf_finish(buf);
49797660e4eaSKevin Bowling 	if (error)
49807660e4eaSKevin Bowling 		device_printf(dev, "Error finishing sbuf: %d\n", error);
49817660e4eaSKevin Bowling 
49827660e4eaSKevin Bowling 	sbuf_delete(buf);
49837660e4eaSKevin Bowling 
49847660e4eaSKevin Bowling 	return (0);
49857660e4eaSKevin Bowling } /* ixgbe_sysctl_print_fw_version */
4986