xref: /freebsd-src/sys/dev/ixgbe/if_ix.c (revision c58d34dd67a419866ee50f152044e49cecbae261)
1*c58d34ddSKevin Bowling /*****************************************************************************
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 
32*c58d34ddSKevin Bowling *****************************************************************************/
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 {
61*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT,
62*c58d34ddSKevin Bowling     "Intel(R) 82598EB AF (Dual Fiber)"),
63*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT,
64*c58d34ddSKevin Bowling     "Intel(R) 82598EB AF (Fiber)"),
65*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4,
66*c58d34ddSKevin Bowling     "Intel(R) 82598EB AT (CX4)"),
67*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT,
68*c58d34ddSKevin Bowling     "Intel(R) 82598EB AT"),
69*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT2,
70*c58d34ddSKevin Bowling     "Intel(R) 82598EB AT2"),
71fdbcd35aSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598, "Intel(R) 82598"),
72*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_DA_DUAL_PORT,
73*c58d34ddSKevin Bowling     "Intel(R) 82598EB AF DA (Dual Fiber)"),
74*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_CX4_DUAL_PORT,
75*c58d34ddSKevin Bowling     "Intel(R) 82598EB AT (Dual CX4)"),
76*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_XF_LR,
77*c58d34ddSKevin Bowling     "Intel(R) 82598EB AF (Dual Fiber LR)"),
78*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM,
79*c58d34ddSKevin Bowling     "Intel(R) 82598EB AF (Dual Fiber SR)"),
80*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_SFP_LOM,
81*c58d34ddSKevin Bowling     "Intel(R) 82598EB LOM"),
82*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4,
83*c58d34ddSKevin Bowling     "Intel(R) X520 82599 (KX4)"),
84*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4_MEZZ,
85*c58d34ddSKevin Bowling     "Intel(R) X520 82599 (KX4 Mezzanine)"),
86*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP,
87*c58d34ddSKevin Bowling     "Intel(R) X520 82599ES (SFI/SFP+)"),
88*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_XAUI_LOM,
89*c58d34ddSKevin Bowling     "Intel(R) X520 82599 (XAUI/BX4)"),
90*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_CX4,
91*c58d34ddSKevin Bowling     "Intel(R) X520 82599 (Dual CX4)"),
92*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_T3_LOM,
93*c58d34ddSKevin Bowling     "Intel(R) X520-T 82599 LOM"),
94*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_LS,
95*c58d34ddSKevin Bowling     "Intel(R) X520 82599 LS"),
96*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_COMBO_BACKPLANE,
97*c58d34ddSKevin Bowling     "Intel(R) X520 82599 (Combined Backplane)"),
98*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BACKPLANE_FCOE,
99*c58d34ddSKevin Bowling     "Intel(R) X520 82599 (Backplane w/FCoE)"),
100*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF2,
101*c58d34ddSKevin Bowling     "Intel(R) X520 82599 (Dual SFP+)"),
102*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_FCOE,
103*c58d34ddSKevin Bowling     "Intel(R) X520 82599 (Dual SFP+ w/FCoE)"),
104*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599EN_SFP,
105*c58d34ddSKevin Bowling     "Intel(R) X520-1 82599EN (SFP+)"),
106*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF_QP,
107*c58d34ddSKevin Bowling     "Intel(R) X520-4 82599 (Quad SFP+)"),
108*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_QSFP_SF_QP,
109*c58d34ddSKevin Bowling     "Intel(R) X520-Q1 82599 (QSFP+)"),
110*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T,
111*c58d34ddSKevin Bowling     "Intel(R) X540-AT2"),
112fdbcd35aSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T1,  "Intel(R) X540-T1"),
113fdbcd35aSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T,  "Intel(R) X550-T2"),
114fdbcd35aSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T1, "Intel(R) X550-T1"),
115*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KR,
116*c58d34ddSKevin Bowling     "Intel(R) X552 (KR Backplane)"),
117*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KX4,
118*c58d34ddSKevin Bowling     "Intel(R) X552 (KX4 Backplane)"),
119*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_10G_T,
120*c58d34ddSKevin Bowling     "Intel(R) X552/X557-AT (10GBASE-T)"),
121*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_1G_T,
122*c58d34ddSKevin Bowling     "Intel(R) X552 (1000BASE-T)"),
123*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_SFP,
124*c58d34ddSKevin Bowling     "Intel(R) X552 (SFP+)"),
125*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_KR,
126*c58d34ddSKevin Bowling     "Intel(R) X553 (KR Backplane)"),
127*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_KR_L,
128*c58d34ddSKevin Bowling     "Intel(R) X553 L (KR Backplane)"),
129*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SFP,
130*c58d34ddSKevin Bowling     "Intel(R) X553 (SFP+)"),
131*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SFP_N,
132*c58d34ddSKevin Bowling     "Intel(R) X553 N (SFP+)"),
133*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SGMII,
134*c58d34ddSKevin Bowling     "Intel(R) X553 (1GbE SGMII)"),
135*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SGMII_L,
136*c58d34ddSKevin Bowling     "Intel(R) X553 L (1GbE SGMII)"),
137*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_10G_T,
138*c58d34ddSKevin Bowling     "Intel(R) X553/X557-AT (10GBASE-T)"),
139*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_1G_T,
140*c58d34ddSKevin Bowling     "Intel(R) X553 (1GbE)"),
141*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_1G_T_L,
142*c58d34ddSKevin Bowling     "Intel(R) X553 L (1GbE)"),
143*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540_BYPASS,
144*c58d34ddSKevin Bowling     "Intel(R) X540-T2 (Bypass)"),
145*c58d34ddSKevin Bowling 	PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BYPASS,
146*c58d34ddSKevin Bowling     "Intel(R) X520 82599 (Bypass)"),
147758cc3dcSJack F Vogel 	/* required last entry */
148c19c7afeSEric Joyner 	PVID_END
149758cc3dcSJack F Vogel };
150758cc3dcSJack F Vogel 
151b1d5caf3SKevin Bowling static void *ixgbe_register(device_t);
152b1d5caf3SKevin Bowling static int  ixgbe_if_attach_pre(if_ctx_t);
153b1d5caf3SKevin Bowling static int  ixgbe_if_attach_post(if_ctx_t);
154b1d5caf3SKevin Bowling static int  ixgbe_if_detach(if_ctx_t);
155b1d5caf3SKevin Bowling static int  ixgbe_if_shutdown(if_ctx_t);
156b1d5caf3SKevin Bowling static int  ixgbe_if_suspend(if_ctx_t);
157b1d5caf3SKevin Bowling static int  ixgbe_if_resume(if_ctx_t);
158c19c7afeSEric Joyner 
159b1d5caf3SKevin Bowling static void ixgbe_if_stop(if_ctx_t);
160b1d5caf3SKevin Bowling void ixgbe_if_enable_intr(if_ctx_t);
161b1d5caf3SKevin Bowling static void ixgbe_if_disable_intr(if_ctx_t);
162b1d5caf3SKevin Bowling static void ixgbe_link_intr_enable(if_ctx_t);
163b1d5caf3SKevin Bowling static int  ixgbe_if_rx_queue_intr_enable(if_ctx_t, uint16_t);
164b1d5caf3SKevin Bowling static void ixgbe_if_media_status(if_ctx_t, struct ifmediareq *);
165b1d5caf3SKevin Bowling static int  ixgbe_if_media_change(if_ctx_t);
166c19c7afeSEric Joyner static int  ixgbe_if_msix_intr_assign(if_ctx_t, int);
167b1d5caf3SKevin Bowling static int  ixgbe_if_mtu_set(if_ctx_t, uint32_t);
168b1d5caf3SKevin Bowling static void ixgbe_if_crcstrip_set(if_ctx_t, int, int);
169b1d5caf3SKevin Bowling static void ixgbe_if_multi_set(if_ctx_t);
170b1d5caf3SKevin Bowling static int  ixgbe_if_promisc_set(if_ctx_t, int);
171*c58d34ddSKevin Bowling static int  ixgbe_if_tx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int,
172*c58d34ddSKevin Bowling     int);
173*c58d34ddSKevin Bowling static int  ixgbe_if_rx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int,
174*c58d34ddSKevin Bowling    int);
175b1d5caf3SKevin Bowling static void ixgbe_if_queues_free(if_ctx_t);
176b1d5caf3SKevin Bowling static void ixgbe_if_timer(if_ctx_t, uint16_t);
177b1d5caf3SKevin Bowling static void ixgbe_if_update_admin_status(if_ctx_t);
178b1d5caf3SKevin Bowling static void ixgbe_if_vlan_register(if_ctx_t, u16);
179b1d5caf3SKevin Bowling static void ixgbe_if_vlan_unregister(if_ctx_t, u16);
180b1d5caf3SKevin Bowling static int  ixgbe_if_i2c_req(if_ctx_t, struct ifi2creq *);
181b1d5caf3SKevin Bowling static bool ixgbe_if_needs_restart(if_ctx_t, enum iflib_restart_event);
182b1d5caf3SKevin Bowling int ixgbe_intr(void *);
183758cc3dcSJack F Vogel 
1848eb6488eSEric Joyner /************************************************************************
185758cc3dcSJack F Vogel  * Function prototypes
1868eb6488eSEric Joyner  ************************************************************************/
187c19c7afeSEric Joyner static uint64_t ixgbe_if_get_counter(if_ctx_t, ift_counter);
188758cc3dcSJack F Vogel 
189b1d5caf3SKevin Bowling static void ixgbe_enable_queue(struct ixgbe_softc *, u32);
190b1d5caf3SKevin Bowling static void ixgbe_disable_queue(struct ixgbe_softc *, u32);
191b1d5caf3SKevin Bowling static void ixgbe_add_device_sysctls(if_ctx_t);
192b1d5caf3SKevin Bowling static int  ixgbe_allocate_pci_resources(if_ctx_t);
193b1d5caf3SKevin Bowling static int  ixgbe_setup_low_power_mode(if_ctx_t);
194c19c7afeSEric Joyner 
195b1d5caf3SKevin Bowling static void ixgbe_config_dmac(struct ixgbe_softc *);
196b1d5caf3SKevin Bowling static void ixgbe_configure_ivars(struct ixgbe_softc *);
197b1d5caf3SKevin Bowling static void ixgbe_set_ivar(struct ixgbe_softc *, u8, u8, s8);
198c19c7afeSEric Joyner static u8   *ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *);
199b1d5caf3SKevin Bowling static bool ixgbe_sfp_probe(if_ctx_t);
200c19c7afeSEric Joyner 
201b1d5caf3SKevin Bowling static void ixgbe_free_pci_resources(if_ctx_t);
202c19c7afeSEric Joyner 
203b1d5caf3SKevin Bowling static int  ixgbe_msix_link(void *);
204b1d5caf3SKevin Bowling static int  ixgbe_msix_que(void *);
205b1d5caf3SKevin Bowling static void ixgbe_initialize_rss_mapping(struct ixgbe_softc *);
206b1d5caf3SKevin Bowling static void ixgbe_initialize_receive_units(if_ctx_t);
207b1d5caf3SKevin Bowling static void ixgbe_initialize_transmit_units(if_ctx_t);
208c19c7afeSEric Joyner 
209b1d5caf3SKevin Bowling static int  ixgbe_setup_interface(if_ctx_t);
210b1d5caf3SKevin Bowling static void ixgbe_init_device_features(struct ixgbe_softc *);
211b1d5caf3SKevin Bowling static void ixgbe_check_fan_failure(struct ixgbe_softc *, u32, bool);
2127660e4eaSKevin Bowling static void ixgbe_sbuf_fw_version(struct ixgbe_hw *, struct sbuf *);
213b1d5caf3SKevin Bowling static void ixgbe_print_fw_version(if_ctx_t);
214b1d5caf3SKevin Bowling static void ixgbe_add_media_types(if_ctx_t);
215b1d5caf3SKevin Bowling static void ixgbe_update_stats_counters(struct ixgbe_softc *);
216b1d5caf3SKevin Bowling static void ixgbe_config_link(if_ctx_t);
217b1d5caf3SKevin Bowling static void ixgbe_get_slot_info(struct ixgbe_softc *);
218f72de14eSKevin Bowling static void ixgbe_fw_mode_timer(void *);
219b1d5caf3SKevin Bowling static void ixgbe_check_wol_support(struct ixgbe_softc *);
220b1d5caf3SKevin Bowling static void ixgbe_enable_rx_drop(struct ixgbe_softc *);
221b1d5caf3SKevin Bowling static void ixgbe_disable_rx_drop(struct ixgbe_softc *);
222758cc3dcSJack F Vogel 
223b1d5caf3SKevin Bowling static void ixgbe_add_hw_stats(struct ixgbe_softc *);
224b1d5caf3SKevin Bowling static int  ixgbe_set_flowcntl(struct ixgbe_softc *, int);
225b1d5caf3SKevin Bowling static int  ixgbe_set_advertise(struct ixgbe_softc *, int);
226d381c807SPiotr Pietruszewski static int  ixgbe_get_default_advertise(struct ixgbe_softc *);
227b1d5caf3SKevin Bowling static void ixgbe_setup_vlan_hw_support(if_ctx_t);
228b1d5caf3SKevin Bowling static void ixgbe_config_gpie(struct ixgbe_softc *);
229b1d5caf3SKevin Bowling static void ixgbe_config_delay_values(struct ixgbe_softc *);
2306f37f232SEric Joyner 
2316f37f232SEric Joyner /* Sysctl handlers */
232f2c4db54SSteven Hartland static int  ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS);
233f2c4db54SSteven Hartland static int  ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS);
2348eb6488eSEric Joyner static int  ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS);
2356f37f232SEric Joyner static int  ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS);
2366f37f232SEric Joyner static int  ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS);
2376f37f232SEric Joyner static int  ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS);
2387660e4eaSKevin Bowling static int  ixgbe_sysctl_print_fw_version(SYSCTL_HANDLER_ARGS);
239a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
240a9ca1c79SSean Bruno static int  ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS);
241a9ca1c79SSean Bruno static int  ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS);
242a9ca1c79SSean Bruno #endif
2438eb6488eSEric Joyner static int  ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS);
2448eb6488eSEric Joyner static int  ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS);
2458eb6488eSEric Joyner static int  ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS);
2468eb6488eSEric Joyner static int  ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS);
2478eb6488eSEric Joyner static int  ixgbe_sysctl_eee_state(SYSCTL_HANDLER_ARGS);
2486f37f232SEric Joyner static int  ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS);
2496f37f232SEric Joyner static int  ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS);
250eea2e089SMichael Tuexen static int  ixgbe_sysctl_tso_tcp_flags_mask(SYSCTL_HANDLER_ARGS);
251758cc3dcSJack F Vogel 
252758cc3dcSJack F Vogel /* Deferred interrupt tasklets */
253c19c7afeSEric Joyner static void ixgbe_handle_msf(void *);
254c19c7afeSEric Joyner static void ixgbe_handle_mod(void *);
255c19c7afeSEric Joyner static void ixgbe_handle_phy(void *);
256758cc3dcSJack F Vogel 
2578eb6488eSEric Joyner /************************************************************************
258758cc3dcSJack F Vogel  *  FreeBSD Device Interface Entry Points
2598eb6488eSEric Joyner  ************************************************************************/
260a1edda90SAdrian Chadd static device_method_t ix_methods[] = {
261758cc3dcSJack F Vogel 	/* Device interface */
262c19c7afeSEric Joyner 	DEVMETHOD(device_register, ixgbe_register),
263c19c7afeSEric Joyner 	DEVMETHOD(device_probe, iflib_device_probe),
264c19c7afeSEric Joyner 	DEVMETHOD(device_attach, iflib_device_attach),
265c19c7afeSEric Joyner 	DEVMETHOD(device_detach, iflib_device_detach),
266c19c7afeSEric Joyner 	DEVMETHOD(device_shutdown, iflib_device_shutdown),
267c19c7afeSEric Joyner 	DEVMETHOD(device_suspend, iflib_device_suspend),
268c19c7afeSEric Joyner 	DEVMETHOD(device_resume, iflib_device_resume),
26948056c88SJack F Vogel #ifdef PCI_IOV
270c19c7afeSEric Joyner 	DEVMETHOD(pci_iov_init, iflib_device_iov_init),
271c19c7afeSEric Joyner 	DEVMETHOD(pci_iov_uninit, iflib_device_iov_uninit),
272c19c7afeSEric Joyner 	DEVMETHOD(pci_iov_add_vf, iflib_device_iov_add_vf),
27348056c88SJack F Vogel #endif /* PCI_IOV */
274758cc3dcSJack F Vogel 	DEVMETHOD_END
275758cc3dcSJack F Vogel };
276758cc3dcSJack F Vogel 
277a1edda90SAdrian Chadd static driver_t ix_driver = {
278b1d5caf3SKevin Bowling 	"ix", ix_methods, sizeof(struct ixgbe_softc),
279758cc3dcSJack F Vogel };
280758cc3dcSJack F Vogel 
281964c2b3aSJohn Baldwin DRIVER_MODULE(ix, pci, ix_driver, 0, 0);
282937b0f25SYuri Pankov IFLIB_PNP_INFO(pci, ix_driver, ixgbe_vendor_info_array);
283a1edda90SAdrian Chadd MODULE_DEPEND(ix, pci, 1, 1, 1);
284a1edda90SAdrian Chadd MODULE_DEPEND(ix, ether, 1, 1, 1);
285c19c7afeSEric Joyner MODULE_DEPEND(ix, iflib, 1, 1, 1);
286c19c7afeSEric Joyner 
287c19c7afeSEric Joyner static device_method_t ixgbe_if_methods[] = {
288c19c7afeSEric Joyner 	DEVMETHOD(ifdi_attach_pre, ixgbe_if_attach_pre),
289c19c7afeSEric Joyner 	DEVMETHOD(ifdi_attach_post, ixgbe_if_attach_post),
290c19c7afeSEric Joyner 	DEVMETHOD(ifdi_detach, ixgbe_if_detach),
291c19c7afeSEric Joyner 	DEVMETHOD(ifdi_shutdown, ixgbe_if_shutdown),
292c19c7afeSEric Joyner 	DEVMETHOD(ifdi_suspend, ixgbe_if_suspend),
293c19c7afeSEric Joyner 	DEVMETHOD(ifdi_resume, ixgbe_if_resume),
294c19c7afeSEric Joyner 	DEVMETHOD(ifdi_init, ixgbe_if_init),
295c19c7afeSEric Joyner 	DEVMETHOD(ifdi_stop, ixgbe_if_stop),
296c19c7afeSEric Joyner 	DEVMETHOD(ifdi_msix_intr_assign, ixgbe_if_msix_intr_assign),
297c19c7afeSEric Joyner 	DEVMETHOD(ifdi_intr_enable, ixgbe_if_enable_intr),
298c19c7afeSEric Joyner 	DEVMETHOD(ifdi_intr_disable, ixgbe_if_disable_intr),
299b2c1e8e6SEric Joyner 	DEVMETHOD(ifdi_link_intr_enable, ixgbe_link_intr_enable),
300c19c7afeSEric Joyner 	DEVMETHOD(ifdi_tx_queue_intr_enable, ixgbe_if_rx_queue_intr_enable),
301c19c7afeSEric Joyner 	DEVMETHOD(ifdi_rx_queue_intr_enable, ixgbe_if_rx_queue_intr_enable),
302c19c7afeSEric Joyner 	DEVMETHOD(ifdi_tx_queues_alloc, ixgbe_if_tx_queues_alloc),
303c19c7afeSEric Joyner 	DEVMETHOD(ifdi_rx_queues_alloc, ixgbe_if_rx_queues_alloc),
304c19c7afeSEric Joyner 	DEVMETHOD(ifdi_queues_free, ixgbe_if_queues_free),
305c19c7afeSEric Joyner 	DEVMETHOD(ifdi_update_admin_status, ixgbe_if_update_admin_status),
306c19c7afeSEric Joyner 	DEVMETHOD(ifdi_multi_set, ixgbe_if_multi_set),
307c19c7afeSEric Joyner 	DEVMETHOD(ifdi_mtu_set, ixgbe_if_mtu_set),
308c19c7afeSEric Joyner 	DEVMETHOD(ifdi_crcstrip_set, ixgbe_if_crcstrip_set),
309c19c7afeSEric Joyner 	DEVMETHOD(ifdi_media_status, ixgbe_if_media_status),
310c19c7afeSEric Joyner 	DEVMETHOD(ifdi_media_change, ixgbe_if_media_change),
311c19c7afeSEric Joyner 	DEVMETHOD(ifdi_promisc_set, ixgbe_if_promisc_set),
312c19c7afeSEric Joyner 	DEVMETHOD(ifdi_timer, ixgbe_if_timer),
313c19c7afeSEric Joyner 	DEVMETHOD(ifdi_vlan_register, ixgbe_if_vlan_register),
314c19c7afeSEric Joyner 	DEVMETHOD(ifdi_vlan_unregister, ixgbe_if_vlan_unregister),
315c19c7afeSEric Joyner 	DEVMETHOD(ifdi_get_counter, ixgbe_if_get_counter),
316bca38080SAndrew Gallatin 	DEVMETHOD(ifdi_i2c_req, ixgbe_if_i2c_req),
317cf150917SEric Joyner 	DEVMETHOD(ifdi_needs_restart, ixgbe_if_needs_restart),
318c19c7afeSEric Joyner #ifdef PCI_IOV
319c19c7afeSEric Joyner 	DEVMETHOD(ifdi_iov_init, ixgbe_if_iov_init),
320c19c7afeSEric Joyner 	DEVMETHOD(ifdi_iov_uninit, ixgbe_if_iov_uninit),
321c19c7afeSEric Joyner 	DEVMETHOD(ifdi_iov_vf_add, ixgbe_if_iov_vf_add),
322c19c7afeSEric Joyner #endif /* PCI_IOV */
323c19c7afeSEric Joyner 	DEVMETHOD_END
324c19c7afeSEric Joyner };
325758cc3dcSJack F Vogel 
326758cc3dcSJack F Vogel /*
3278eb6488eSEric Joyner  * TUNEABLE PARAMETERS:
328758cc3dcSJack F Vogel  */
329758cc3dcSJack F Vogel 
33020b91f0aSPawel Biernacki static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
33120b91f0aSPawel Biernacki     "IXGBE driver parameters");
332c19c7afeSEric Joyner static driver_t ixgbe_if_driver = {
333b1d5caf3SKevin Bowling   "ixgbe_if", ixgbe_if_methods, sizeof(struct ixgbe_softc)
334c19c7afeSEric Joyner };
335758cc3dcSJack F Vogel 
336758cc3dcSJack F Vogel static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY);
337758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN,
338758cc3dcSJack F Vogel     &ixgbe_max_interrupt_rate, 0, "Maximum interrupts per second");
339758cc3dcSJack F Vogel 
340f2c4db54SSteven Hartland /* Flow control setting, default to full */
341f2c4db54SSteven Hartland static int ixgbe_flow_control = ixgbe_fc_full;
342f2c4db54SSteven Hartland SYSCTL_INT(_hw_ix, OID_AUTO, flow_control, CTLFLAG_RDTUN,
343f2c4db54SSteven Hartland     &ixgbe_flow_control, 0, "Default flow control used for all adapters");
344f2c4db54SSteven Hartland 
345f2c4db54SSteven Hartland /* Advertise Speed, default to 0 (auto) */
346f2c4db54SSteven Hartland static int ixgbe_advertise_speed = 0;
347f2c4db54SSteven Hartland SYSCTL_INT(_hw_ix, OID_AUTO, advertise_speed, CTLFLAG_RDTUN,
348f2c4db54SSteven Hartland     &ixgbe_advertise_speed, 0, "Default advertised speed for all adapters");
349f2c4db54SSteven Hartland 
350758cc3dcSJack F Vogel /*
3518eb6488eSEric Joyner  * Smart speed setting, default to on
3528eb6488eSEric Joyner  * this only works as a compile option
3538eb6488eSEric Joyner  * right now as its during attach, set
3548eb6488eSEric Joyner  * this to 'ixgbe_smart_speed_off' to
3558eb6488eSEric Joyner  * disable.
356758cc3dcSJack F Vogel  */
357758cc3dcSJack F Vogel static int ixgbe_smart_speed = ixgbe_smart_speed_on;
358758cc3dcSJack F Vogel 
359758cc3dcSJack F Vogel /*
3608eb6488eSEric Joyner  * MSI-X should be the default for best performance,
361758cc3dcSJack F Vogel  * but this allows it to be forced off for testing.
362758cc3dcSJack F Vogel  */
363758cc3dcSJack F Vogel static int ixgbe_enable_msix = 1;
364*c58d34ddSKevin Bowling SYSCTL_INT(_hw_ix, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixgbe_enable_msix,
365*c58d34ddSKevin Bowling     0,
366758cc3dcSJack F Vogel     "Enable MSI-X interrupts");
367758cc3dcSJack F Vogel 
368758cc3dcSJack F Vogel /*
3698eb6488eSEric Joyner  * Defining this on will allow the use
3708eb6488eSEric Joyner  * of unsupported SFP+ modules, note that
3718eb6488eSEric Joyner  * doing so you are on your own :)
372758cc3dcSJack F Vogel  */
37379b36ec9SKevin Bowling static int allow_unsupported_sfp = false;
374fb6aa95dSSean Bruno SYSCTL_INT(_hw_ix, OID_AUTO, unsupported_sfp, CTLFLAG_RDTUN,
3758eb6488eSEric Joyner     &allow_unsupported_sfp, 0,
3768eb6488eSEric Joyner     "Allow unsupported SFP modules...use at your own risk");
3778eb6488eSEric Joyner 
3788eb6488eSEric Joyner /*
3798eb6488eSEric Joyner  * Not sure if Flow Director is fully baked,
3808eb6488eSEric Joyner  * so we'll default to turning it off.
3818eb6488eSEric Joyner  */
3828eb6488eSEric Joyner static int ixgbe_enable_fdir = 0;
383*c58d34ddSKevin Bowling SYSCTL_INT(_hw_ix, OID_AUTO, enable_fdir, CTLFLAG_RDTUN, &ixgbe_enable_fdir,
384*c58d34ddSKevin Bowling     0,
3858eb6488eSEric Joyner     "Enable Flow Director");
3868eb6488eSEric Joyner 
3878eb6488eSEric Joyner /* Receive-Side Scaling */
3888eb6488eSEric Joyner static int ixgbe_enable_rss = 1;
389*c58d34ddSKevin Bowling SYSCTL_INT(_hw_ix, OID_AUTO, enable_rss, CTLFLAG_RDTUN, &ixgbe_enable_rss,
390*c58d34ddSKevin Bowling     0,
3918eb6488eSEric Joyner     "Enable Receive-Side Scaling (RSS)");
392758cc3dcSJack F Vogel 
39364881da4SSai Rajesh Tallamraju /*
39464881da4SSai Rajesh Tallamraju  * AIM: Adaptive Interrupt Moderation
39564881da4SSai Rajesh Tallamraju  * which means that the interrupt rate
39664881da4SSai Rajesh Tallamraju  * is varied over time based on the
39764881da4SSai Rajesh Tallamraju  * traffic for that interrupt vector
39864881da4SSai Rajesh Tallamraju  */
39979b36ec9SKevin Bowling static int ixgbe_enable_aim = false;
400*c58d34ddSKevin Bowling SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim,
401*c58d34ddSKevin Bowling     0,
40264881da4SSai Rajesh Tallamraju     "Enable adaptive interrupt moderation");
40364881da4SSai Rajesh Tallamraju 
404c19c7afeSEric Joyner #if 0
405758cc3dcSJack F Vogel /* Keep running tab on them for sanity check */
406758cc3dcSJack F Vogel static int ixgbe_total_ports;
407c19c7afeSEric Joyner #endif
408758cc3dcSJack F Vogel 
4098eb6488eSEric Joyner MALLOC_DEFINE(M_IXGBE, "ix", "ix driver allocations");
410758cc3dcSJack F Vogel 
411c19c7afeSEric Joyner /*
412c19c7afeSEric Joyner  * For Flow Director: this is the number of TX packets we sample
413c19c7afeSEric Joyner  * for the filter pool, this means every 20th packet will be probed.
414c19c7afeSEric Joyner  *
415c19c7afeSEric Joyner  * This feature can be disabled by setting this to 0.
416c19c7afeSEric Joyner  */
417c19c7afeSEric Joyner static int atr_sample_rate = 20;
418c19c7afeSEric Joyner 
419c19c7afeSEric Joyner extern struct if_txrx ixgbe_txrx;
420c19c7afeSEric Joyner 
421c19c7afeSEric Joyner static struct if_shared_ctx ixgbe_sctx_init = {
422c19c7afeSEric Joyner 	.isc_magic = IFLIB_MAGIC,
423c19c7afeSEric Joyner 	.isc_q_align = PAGE_SIZE,/* max(DBA_ALIGN, PAGE_SIZE) */
4247f87c040SMarius Strobl 	.isc_tx_maxsize = IXGBE_TSO_SIZE + sizeof(struct ether_vlan_header),
425c19c7afeSEric Joyner 	.isc_tx_maxsegsize = PAGE_SIZE,
4267f87c040SMarius Strobl 	.isc_tso_maxsize = IXGBE_TSO_SIZE + sizeof(struct ether_vlan_header),
4277f87c040SMarius Strobl 	.isc_tso_maxsegsize = PAGE_SIZE,
428c19c7afeSEric Joyner 	.isc_rx_maxsize = PAGE_SIZE*4,
429c19c7afeSEric Joyner 	.isc_rx_nsegments = 1,
430c19c7afeSEric Joyner 	.isc_rx_maxsegsize = PAGE_SIZE*4,
431c19c7afeSEric Joyner 	.isc_nfl = 1,
432c19c7afeSEric Joyner 	.isc_ntxqs = 1,
433c19c7afeSEric Joyner 	.isc_nrxqs = 1,
434c19c7afeSEric Joyner 
435c19c7afeSEric Joyner 	.isc_admin_intrcnt = 1,
436c19c7afeSEric Joyner 	.isc_vendor_info = ixgbe_vendor_info_array,
437c19c7afeSEric Joyner 	.isc_driver_version = ixgbe_driver_version,
438c19c7afeSEric Joyner 	.isc_driver = &ixgbe_if_driver,
4397aad1f4eSEric Joyner 	.isc_flags = IFLIB_TSO_INIT_IP,
440c19c7afeSEric Joyner 
441c19c7afeSEric Joyner 	.isc_nrxd_min = {MIN_RXD},
442c19c7afeSEric Joyner 	.isc_ntxd_min = {MIN_TXD},
443c19c7afeSEric Joyner 	.isc_nrxd_max = {MAX_RXD},
444c19c7afeSEric Joyner 	.isc_ntxd_max = {MAX_TXD},
445c19c7afeSEric Joyner 	.isc_nrxd_default = {DEFAULT_RXD},
446c19c7afeSEric Joyner 	.isc_ntxd_default = {DEFAULT_TXD},
447c19c7afeSEric Joyner };
448c19c7afeSEric Joyner 
449c19c7afeSEric Joyner /************************************************************************
450c19c7afeSEric Joyner  * ixgbe_if_tx_queues_alloc
451c19c7afeSEric Joyner  ************************************************************************/
452c19c7afeSEric Joyner static int
453c19c7afeSEric Joyner ixgbe_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
454c19c7afeSEric Joyner     int ntxqs, int ntxqsets)
455c19c7afeSEric Joyner {
456b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
457b1d5caf3SKevin Bowling 	if_softc_ctx_t scctx = sc->shared;
458c19c7afeSEric Joyner 	struct ix_tx_queue *que;
459c19c7afeSEric Joyner 	int i, j, error;
460c19c7afeSEric Joyner 
461b1d5caf3SKevin Bowling 	MPASS(sc->num_tx_queues > 0);
462b1d5caf3SKevin Bowling 	MPASS(sc->num_tx_queues == ntxqsets);
463c19c7afeSEric Joyner 	MPASS(ntxqs == 1);
464c19c7afeSEric Joyner 
465c19c7afeSEric Joyner 	/* Allocate queue structure memory */
466b1d5caf3SKevin Bowling 	sc->tx_queues =
467*c58d34ddSKevin Bowling 	    (struct ix_tx_queue *)malloc(sizeof(struct ix_tx_queue) *
468*c58d34ddSKevin Bowling 	    ntxqsets, M_IXGBE, M_NOWAIT | M_ZERO);
469b1d5caf3SKevin Bowling 	if (!sc->tx_queues) {
470c19c7afeSEric Joyner 		device_printf(iflib_get_dev(ctx),
471c19c7afeSEric Joyner 		    "Unable to allocate TX ring memory\n");
472c19c7afeSEric Joyner 		return (ENOMEM);
473c19c7afeSEric Joyner 	}
474c19c7afeSEric Joyner 
475b1d5caf3SKevin Bowling 	for (i = 0, que = sc->tx_queues; i < ntxqsets; i++, que++) {
476c19c7afeSEric Joyner 		struct tx_ring *txr = &que->txr;
477c19c7afeSEric Joyner 
478c19c7afeSEric Joyner 		/* In case SR-IOV is enabled, align the index properly */
479*c58d34ddSKevin Bowling 		txr->me = ixgbe_vf_que_index(sc->iov_mode, sc->pool, i);
480c19c7afeSEric Joyner 
481b1d5caf3SKevin Bowling 		txr->sc = que->sc = sc;
482c19c7afeSEric Joyner 
483c19c7afeSEric Joyner 		/* Allocate report status array */
484*c58d34ddSKevin Bowling 		txr->tx_rsq = (qidx_t *)malloc(sizeof(qidx_t) *
485*c58d34ddSKevin Bowling 		    scctx->isc_ntxd[0], M_IXGBE, M_NOWAIT | M_ZERO);
486c19c7afeSEric Joyner 		if (txr->tx_rsq == NULL) {
487c19c7afeSEric Joyner 			error = ENOMEM;
488c19c7afeSEric Joyner 			goto fail;
489c19c7afeSEric Joyner 		}
490c19c7afeSEric Joyner 		for (j = 0; j < scctx->isc_ntxd[0]; j++)
491c19c7afeSEric Joyner 			txr->tx_rsq[j] = QIDX_INVALID;
492*c58d34ddSKevin Bowling 		/* get virtual and physical address of the hardware queues */
493c19c7afeSEric Joyner 		txr->tail = IXGBE_TDT(txr->me);
494c19c7afeSEric Joyner 		txr->tx_base = (union ixgbe_adv_tx_desc *)vaddrs[i];
495c19c7afeSEric Joyner 		txr->tx_paddr = paddrs[i];
496c19c7afeSEric Joyner 
497c19c7afeSEric Joyner 		txr->bytes = 0;
498c19c7afeSEric Joyner 		txr->total_packets = 0;
499c19c7afeSEric Joyner 
500c19c7afeSEric Joyner 		/* Set the rate at which we sample packets */
501b1d5caf3SKevin Bowling 		if (sc->feat_en & IXGBE_FEATURE_FDIR)
502c19c7afeSEric Joyner 			txr->atr_sample = atr_sample_rate;
503c19c7afeSEric Joyner 
504c19c7afeSEric Joyner 	}
505c19c7afeSEric Joyner 
506c19c7afeSEric Joyner 	device_printf(iflib_get_dev(ctx), "allocated for %d queues\n",
507b1d5caf3SKevin Bowling 	    sc->num_tx_queues);
508c19c7afeSEric Joyner 
509c19c7afeSEric Joyner 	return (0);
510c19c7afeSEric Joyner 
511c19c7afeSEric Joyner fail:
512c19c7afeSEric Joyner 	ixgbe_if_queues_free(ctx);
513c19c7afeSEric Joyner 
514c19c7afeSEric Joyner 	return (error);
515c19c7afeSEric Joyner } /* ixgbe_if_tx_queues_alloc */
516c19c7afeSEric Joyner 
517c19c7afeSEric Joyner /************************************************************************
518c19c7afeSEric Joyner  * ixgbe_if_rx_queues_alloc
519c19c7afeSEric Joyner  ************************************************************************/
520c19c7afeSEric Joyner static int
521c19c7afeSEric Joyner ixgbe_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
522c19c7afeSEric Joyner     int nrxqs, int nrxqsets)
523c19c7afeSEric Joyner {
524b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
525c19c7afeSEric Joyner 	struct ix_rx_queue *que;
526c19c7afeSEric Joyner 	int i;
527c19c7afeSEric Joyner 
528b1d5caf3SKevin Bowling 	MPASS(sc->num_rx_queues > 0);
529b1d5caf3SKevin Bowling 	MPASS(sc->num_rx_queues == nrxqsets);
530c19c7afeSEric Joyner 	MPASS(nrxqs == 1);
531c19c7afeSEric Joyner 
532c19c7afeSEric Joyner 	/* Allocate queue structure memory */
533b1d5caf3SKevin Bowling 	sc->rx_queues =
534c19c7afeSEric Joyner 	    (struct ix_rx_queue *)malloc(sizeof(struct ix_rx_queue)*nrxqsets,
535c19c7afeSEric Joyner 	    M_IXGBE, M_NOWAIT | M_ZERO);
536b1d5caf3SKevin Bowling 	if (!sc->rx_queues) {
537c19c7afeSEric Joyner 		device_printf(iflib_get_dev(ctx),
538c19c7afeSEric Joyner 		    "Unable to allocate TX ring memory\n");
539c19c7afeSEric Joyner 		return (ENOMEM);
540c19c7afeSEric Joyner 	}
541c19c7afeSEric Joyner 
542b1d5caf3SKevin Bowling 	for (i = 0, que = sc->rx_queues; i < nrxqsets; i++, que++) {
543c19c7afeSEric Joyner 		struct rx_ring *rxr = &que->rxr;
544c19c7afeSEric Joyner 
545c19c7afeSEric Joyner 		/* In case SR-IOV is enabled, align the index properly */
546*c58d34ddSKevin Bowling 		rxr->me = ixgbe_vf_que_index(sc->iov_mode, sc->pool, i);
547c19c7afeSEric Joyner 
548b1d5caf3SKevin Bowling 		rxr->sc = que->sc = sc;
549c19c7afeSEric Joyner 
550c19c7afeSEric Joyner 		/* get the virtual and physical address of the hw queues */
551c19c7afeSEric Joyner 		rxr->tail = IXGBE_RDT(rxr->me);
552c19c7afeSEric Joyner 		rxr->rx_base = (union ixgbe_adv_rx_desc *)vaddrs[i];
553c19c7afeSEric Joyner 		rxr->rx_paddr = paddrs[i];
554c19c7afeSEric Joyner 		rxr->bytes = 0;
555c19c7afeSEric Joyner 		rxr->que = que;
556c19c7afeSEric Joyner 	}
557c19c7afeSEric Joyner 
558c19c7afeSEric Joyner 	device_printf(iflib_get_dev(ctx), "allocated for %d rx queues\n",
559b1d5caf3SKevin Bowling 	    sc->num_rx_queues);
560c19c7afeSEric Joyner 
561c19c7afeSEric Joyner 	return (0);
562c19c7afeSEric Joyner } /* ixgbe_if_rx_queues_alloc */
563c19c7afeSEric Joyner 
564c19c7afeSEric Joyner /************************************************************************
565c19c7afeSEric Joyner  * ixgbe_if_queues_free
566c19c7afeSEric Joyner  ************************************************************************/
567c19c7afeSEric Joyner static void
568c19c7afeSEric Joyner ixgbe_if_queues_free(if_ctx_t ctx)
569c19c7afeSEric Joyner {
570b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
571b1d5caf3SKevin Bowling 	struct ix_tx_queue *tx_que = sc->tx_queues;
572b1d5caf3SKevin Bowling 	struct ix_rx_queue *rx_que = sc->rx_queues;
573c19c7afeSEric Joyner 	int i;
574c19c7afeSEric Joyner 
575c19c7afeSEric Joyner 	if (tx_que != NULL) {
576b1d5caf3SKevin Bowling 		for (i = 0; i < sc->num_tx_queues; i++, tx_que++) {
577c19c7afeSEric Joyner 			struct tx_ring *txr = &tx_que->txr;
578c19c7afeSEric Joyner 			if (txr->tx_rsq == NULL)
579c19c7afeSEric Joyner 				break;
580c19c7afeSEric Joyner 
581c19c7afeSEric Joyner 			free(txr->tx_rsq, M_IXGBE);
582c19c7afeSEric Joyner 			txr->tx_rsq = NULL;
583c19c7afeSEric Joyner 		}
584c19c7afeSEric Joyner 
585b1d5caf3SKevin Bowling 		free(sc->tx_queues, M_IXGBE);
586b1d5caf3SKevin Bowling 		sc->tx_queues = NULL;
587c19c7afeSEric Joyner 	}
588c19c7afeSEric Joyner 	if (rx_que != NULL) {
589b1d5caf3SKevin Bowling 		free(sc->rx_queues, M_IXGBE);
590b1d5caf3SKevin Bowling 		sc->rx_queues = NULL;
591c19c7afeSEric Joyner 	}
592c19c7afeSEric Joyner } /* ixgbe_if_queues_free */
593c19c7afeSEric Joyner 
5948eb6488eSEric Joyner /************************************************************************
5958eb6488eSEric Joyner  * ixgbe_initialize_rss_mapping
5968eb6488eSEric Joyner  ************************************************************************/
5978eb6488eSEric Joyner static void
598b1d5caf3SKevin Bowling ixgbe_initialize_rss_mapping(struct ixgbe_softc *sc)
599758cc3dcSJack F Vogel {
600b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
6018eb6488eSEric Joyner 	u32 reta = 0, mrqc, rss_key[10];
6028eb6488eSEric Joyner 	int queue_id, table_size, index_mult;
6038eb6488eSEric Joyner 	int i, j;
6048eb6488eSEric Joyner 	u32 rss_hash_config;
6056f37f232SEric Joyner 
606b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_RSS) {
6078eb6488eSEric Joyner 		/* Fetch the configured RSS key */
6088eb6488eSEric Joyner 		rss_getkey((uint8_t *)&rss_key);
609758cc3dcSJack F Vogel 	} else {
6108eb6488eSEric Joyner 		/* set up random bits */
6118eb6488eSEric Joyner 		arc4rand(&rss_key, sizeof(rss_key), 0);
612758cc3dcSJack F Vogel 	}
613758cc3dcSJack F Vogel 
6148eb6488eSEric Joyner 	/* Set multiplier for RETA setup and table size based on MAC */
6158eb6488eSEric Joyner 	index_mult = 0x1;
6168eb6488eSEric Joyner 	table_size = 128;
617b1d5caf3SKevin Bowling 	switch (sc->hw.mac.type) {
6188eb6488eSEric Joyner 	case ixgbe_mac_82598EB:
6198eb6488eSEric Joyner 		index_mult = 0x11;
620758cc3dcSJack F Vogel 		break;
6218eb6488eSEric Joyner 	case ixgbe_mac_X550:
6228eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
6238eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
6248eb6488eSEric Joyner 		table_size = 512;
6258eb6488eSEric Joyner 		break;
626758cc3dcSJack F Vogel 	default:
627758cc3dcSJack F Vogel 		break;
628758cc3dcSJack F Vogel 	}
629758cc3dcSJack F Vogel 
6308eb6488eSEric Joyner 	/* Set up the redirection table */
6318eb6488eSEric Joyner 	for (i = 0, j = 0; i < table_size; i++, j++) {
632b1d5caf3SKevin Bowling 		if (j == sc->num_rx_queues)
6338eb6488eSEric Joyner 			j = 0;
634758cc3dcSJack F Vogel 
635b1d5caf3SKevin Bowling 		if (sc->feat_en & IXGBE_FEATURE_RSS) {
636a9ca1c79SSean Bruno 			/*
6378eb6488eSEric Joyner 			 * Fetch the RSS bucket id for the given indirection
6388eb6488eSEric Joyner 			 * entry. Cap it at the number of configured buckets
639c19c7afeSEric Joyner 			 * (which is num_rx_queues.)
640a9ca1c79SSean Bruno 			 */
6418eb6488eSEric Joyner 			queue_id = rss_get_indirection_to_bucket(i);
642b1d5caf3SKevin Bowling 			queue_id = queue_id % sc->num_rx_queues;
643758cc3dcSJack F Vogel 		} else
6448eb6488eSEric Joyner 			queue_id = (j * index_mult);
6458eb6488eSEric Joyner 
6468eb6488eSEric Joyner 		/*
6478eb6488eSEric Joyner 		 * The low 8 bits are for hash value (n+0);
6488eb6488eSEric Joyner 		 * The next 8 bits are for hash value (n+1), etc.
6498eb6488eSEric Joyner 		 */
6508eb6488eSEric Joyner 		reta = reta >> 8;
6518eb6488eSEric Joyner 		reta = reta | (((uint32_t)queue_id) << 24);
6528eb6488eSEric Joyner 		if ((i & 3) == 3) {
6538eb6488eSEric Joyner 			if (i < 128)
6548eb6488eSEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
6558eb6488eSEric Joyner 			else
656*c58d34ddSKevin Bowling 				IXGBE_WRITE_REG(hw,
657*c58d34ddSKevin Bowling 				    IXGBE_ERETA((i >> 2) - 32), reta);
6588eb6488eSEric Joyner 			reta = 0;
6598eb6488eSEric Joyner 		}
660758cc3dcSJack F Vogel 	}
661758cc3dcSJack F Vogel 
6628eb6488eSEric Joyner 	/* Now fill our hash function seeds */
6638eb6488eSEric Joyner 	for (i = 0; i < 10; i++)
6648eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]);
665758cc3dcSJack F Vogel 
6668eb6488eSEric Joyner 	/* Perform hash on these packet types */
667b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_RSS)
6688eb6488eSEric Joyner 		rss_hash_config = rss_gethashconfig();
669758cc3dcSJack F Vogel 	else {
670758cc3dcSJack F Vogel 		/*
6718eb6488eSEric Joyner 		 * Disable UDP - IP fragments aren't currently being handled
6728eb6488eSEric Joyner 		 * and so we end up with a mix of 2-tuple and 4-tuple
6738eb6488eSEric Joyner 		 * traffic.
674758cc3dcSJack F Vogel 		 */
675*c58d34ddSKevin Bowling 		rss_hash_config = RSS_HASHTYPE_RSS_IPV4 |
676*c58d34ddSKevin Bowling 		    RSS_HASHTYPE_RSS_TCP_IPV4 |
677*c58d34ddSKevin Bowling 		    RSS_HASHTYPE_RSS_IPV6 |
678*c58d34ddSKevin Bowling 		    RSS_HASHTYPE_RSS_TCP_IPV6 |
679*c58d34ddSKevin Bowling 		    RSS_HASHTYPE_RSS_IPV6_EX |
680*c58d34ddSKevin Bowling 		    RSS_HASHTYPE_RSS_TCP_IPV6_EX;
681758cc3dcSJack F Vogel 	}
682758cc3dcSJack F Vogel 
6838eb6488eSEric Joyner 	mrqc = IXGBE_MRQC_RSSEN;
6848eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
6858eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4;
6868eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
6878eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP;
6888eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
6898eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6;
6908eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
6918eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
6928eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
6938eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX;
6948eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX)
6958eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP;
6968eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
6978eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP;
6988eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
6998eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
7008eb6488eSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX)
7018eb6488eSEric Joyner 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
702b1d5caf3SKevin Bowling 	mrqc |= ixgbe_get_mrqc(sc->iov_mode);
7038eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
7048eb6488eSEric Joyner } /* ixgbe_initialize_rss_mapping */
705758cc3dcSJack F Vogel 
7068eb6488eSEric Joyner /************************************************************************
7078eb6488eSEric Joyner  * ixgbe_initialize_receive_units - Setup receive registers and features.
7088eb6488eSEric Joyner  ************************************************************************/
7098eb6488eSEric Joyner #define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1)
710758cc3dcSJack F Vogel 
711758cc3dcSJack F Vogel static void
712c19c7afeSEric Joyner ixgbe_initialize_receive_units(if_ctx_t ctx)
713758cc3dcSJack F Vogel {
714b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
715b1d5caf3SKevin Bowling 	if_softc_ctx_t scctx = sc->shared;
716b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
717ff06a8dbSJustin Hibbits 	if_t ifp = iflib_get_ifp(ctx);
718c19c7afeSEric Joyner 	struct ix_rx_queue *que;
7198eb6488eSEric Joyner 	int i, j;
7208eb6488eSEric Joyner 	u32 bufsz, fctrl, srrctl, rxcsum;
7218eb6488eSEric Joyner 	u32 hlreg;
72248056c88SJack F Vogel 
72348056c88SJack F Vogel 	/*
7248eb6488eSEric Joyner 	 * Make sure receives are disabled while
7258eb6488eSEric Joyner 	 * setting up the descriptor ring
72648056c88SJack F Vogel 	 */
7278eb6488eSEric Joyner 	ixgbe_disable_rx(hw);
7288eb6488eSEric Joyner 
7298eb6488eSEric Joyner 	/* Enable broadcasts */
7308eb6488eSEric Joyner 	fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
7318eb6488eSEric Joyner 	fctrl |= IXGBE_FCTRL_BAM;
732b1d5caf3SKevin Bowling 	if (sc->hw.mac.type == ixgbe_mac_82598EB) {
7338eb6488eSEric Joyner 		fctrl |= IXGBE_FCTRL_DPF;
7348eb6488eSEric Joyner 		fctrl |= IXGBE_FCTRL_PMCF;
73548056c88SJack F Vogel 	}
7368eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
7378eb6488eSEric Joyner 
7388eb6488eSEric Joyner 	/* Set for Jumbo Frames? */
7398eb6488eSEric Joyner 	hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0);
740ff06a8dbSJustin Hibbits 	if (if_getmtu(ifp) > ETHERMTU)
7418eb6488eSEric Joyner 		hlreg |= IXGBE_HLREG0_JUMBOEN;
7428eb6488eSEric Joyner 	else
7438eb6488eSEric Joyner 		hlreg &= ~IXGBE_HLREG0_JUMBOEN;
7448eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg);
7458eb6488eSEric Joyner 
746b1d5caf3SKevin Bowling 	bufsz = (sc->rx_mbuf_sz + BSIZEPKT_ROUNDUP) >>
7478eb6488eSEric Joyner 	    IXGBE_SRRCTL_BSIZEPKT_SHIFT;
7488eb6488eSEric Joyner 
749c19c7afeSEric Joyner 	/* Setup the Base and Length of the Rx Descriptor Ring */
750b1d5caf3SKevin Bowling 	for (i = 0, que = sc->rx_queues; i < sc->num_rx_queues; i++, que++) {
751c19c7afeSEric Joyner 		struct rx_ring *rxr = &que->rxr;
752c19c7afeSEric Joyner 		u64 rdba = rxr->rx_paddr;
753c19c7afeSEric Joyner 
7548eb6488eSEric Joyner 		j = rxr->me;
7558eb6488eSEric Joyner 
7568eb6488eSEric Joyner 		/* Setup the Base and Length of the Rx Descriptor Ring */
7578eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j),
7588eb6488eSEric Joyner 		    (rdba & 0x00000000ffffffffULL));
7598eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32));
7608eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j),
761c19c7afeSEric Joyner 		     scctx->isc_nrxd[0] * sizeof(union ixgbe_adv_rx_desc));
7628eb6488eSEric Joyner 
7638eb6488eSEric Joyner 		/* Set up the SRRCTL register */
7648eb6488eSEric Joyner 		srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(j));
7658eb6488eSEric Joyner 		srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
7668eb6488eSEric Joyner 		srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
7678eb6488eSEric Joyner 		srrctl |= bufsz;
7688eb6488eSEric Joyner 		srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
76948056c88SJack F Vogel 
77048056c88SJack F Vogel 		/*
7718eb6488eSEric Joyner 		 * Set DROP_EN iff we have no flow control and >1 queue.
7728eb6488eSEric Joyner 		 * Note that srrctl was cleared shortly before during reset,
7738eb6488eSEric Joyner 		 * so we do not need to clear the bit, but do it just in case
7748eb6488eSEric Joyner 		 * this code is moved elsewhere.
77548056c88SJack F Vogel 		 */
776b1d5caf3SKevin Bowling 		if (sc->num_rx_queues > 1 &&
777b1d5caf3SKevin Bowling 		    sc->hw.fc.requested_mode == ixgbe_fc_none) {
7788eb6488eSEric Joyner 			srrctl |= IXGBE_SRRCTL_DROP_EN;
779758cc3dcSJack F Vogel 		} else {
7808eb6488eSEric Joyner 			srrctl &= ~IXGBE_SRRCTL_DROP_EN;
781758cc3dcSJack F Vogel 		}
782758cc3dcSJack F Vogel 
7838eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(j), srrctl);
784758cc3dcSJack F Vogel 
7858eb6488eSEric Joyner 		/* Setup the HW Rx Head and Tail Descriptor Pointers */
7868eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0);
7878eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0);
788758cc3dcSJack F Vogel 
7898eb6488eSEric Joyner 		/* Set the driver rx tail address */
7908eb6488eSEric Joyner 		rxr->tail =  IXGBE_RDT(rxr->me);
791a9ca1c79SSean Bruno 	}
792758cc3dcSJack F Vogel 
793b1d5caf3SKevin Bowling 	if (sc->hw.mac.type != ixgbe_mac_82598EB) {
794*c58d34ddSKevin Bowling 		u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
795*c58d34ddSKevin Bowling 		    IXGBE_PSRTYPE_UDPHDR |
796*c58d34ddSKevin Bowling 		    IXGBE_PSRTYPE_IPV4HDR |
797*c58d34ddSKevin Bowling 		    IXGBE_PSRTYPE_IPV6HDR;
7988eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype);
7996f37f232SEric Joyner 	}
8006f37f232SEric Joyner 
8018eb6488eSEric Joyner 	rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
8028eb6488eSEric Joyner 
803b1d5caf3SKevin Bowling 	ixgbe_initialize_rss_mapping(sc);
8048eb6488eSEric Joyner 
805156424fcSPrzemyslaw Lewandowski 	if (sc->feat_en & IXGBE_FEATURE_RSS) {
8068eb6488eSEric Joyner 		/* RSS and RX IPP Checksum are mutually exclusive */
8078eb6488eSEric Joyner 		rxcsum |= IXGBE_RXCSUM_PCSD;
8086f37f232SEric Joyner 	}
8096f37f232SEric Joyner 
810ff06a8dbSJustin Hibbits 	if (if_getcapenable(ifp) & IFCAP_RXCSUM)
8118eb6488eSEric Joyner 		rxcsum |= IXGBE_RXCSUM_PCSD;
812758cc3dcSJack F Vogel 
8138eb6488eSEric Joyner 	/* This is useful for calculating UDP/IP fragment checksums */
8148eb6488eSEric Joyner 	if (!(rxcsum & IXGBE_RXCSUM_PCSD))
8158eb6488eSEric Joyner 		rxcsum |= IXGBE_RXCSUM_IPPCSE;
816758cc3dcSJack F Vogel 
8178eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
818758cc3dcSJack F Vogel 
8198eb6488eSEric Joyner } /* ixgbe_initialize_receive_units */
820758cc3dcSJack F Vogel 
8218eb6488eSEric Joyner /************************************************************************
8228eb6488eSEric Joyner  * ixgbe_initialize_transmit_units - Enable transmit units.
8238eb6488eSEric Joyner  ************************************************************************/
824758cc3dcSJack F Vogel static void
825c19c7afeSEric Joyner ixgbe_initialize_transmit_units(if_ctx_t ctx)
826758cc3dcSJack F Vogel {
827b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
828b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
829b1d5caf3SKevin Bowling 	if_softc_ctx_t scctx = sc->shared;
830c19c7afeSEric Joyner 	struct ix_tx_queue *que;
831c19c7afeSEric Joyner 	int i;
832758cc3dcSJack F Vogel 
833758cc3dcSJack F Vogel 	/* Setup the Base and Length of the Tx Descriptor Ring */
834b1d5caf3SKevin Bowling 	for (i = 0, que = sc->tx_queues; i < sc->num_tx_queues;
835c19c7afeSEric Joyner 	    i++, que++) {
836c19c7afeSEric Joyner 		struct tx_ring	   *txr = &que->txr;
837c19c7afeSEric Joyner 		u64 tdba = txr->tx_paddr;
838758cc3dcSJack F Vogel 		u32 txctrl = 0;
83948056c88SJack F Vogel 		int j = txr->me;
840758cc3dcSJack F Vogel 
84148056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j),
842758cc3dcSJack F Vogel 		    (tdba & 0x00000000ffffffffULL));
84348056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32));
84448056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j),
845c19c7afeSEric Joyner 		    scctx->isc_ntxd[0] * sizeof(union ixgbe_adv_tx_desc));
846758cc3dcSJack F Vogel 
847758cc3dcSJack F Vogel 		/* Setup the HW Tx Head and Tail descriptor pointers */
84848056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0);
84948056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0);
850758cc3dcSJack F Vogel 
851758cc3dcSJack F Vogel 		/* Cache the tail address */
8522dc2d580SEric Joyner 		txr->tail = IXGBE_TDT(txr->me);
8532dc2d580SEric Joyner 
854088a0b27SEric Joyner 		txr->tx_rs_cidx = txr->tx_rs_pidx;
855088a0b27SEric Joyner 		txr->tx_cidx_processed = scctx->isc_ntxd[0] - 1;
856c19c7afeSEric Joyner 		for (int k = 0; k < scctx->isc_ntxd[0]; k++)
857c19c7afeSEric Joyner 			txr->tx_rsq[k] = QIDX_INVALID;
858758cc3dcSJack F Vogel 
859758cc3dcSJack F Vogel 		/* Disable Head Writeback */
860a9ca1c79SSean Bruno 		/*
861a9ca1c79SSean Bruno 		 * Note: for X550 series devices, these registers are actually
862a9ca1c79SSean Bruno 		 * prefixed with TPH_ isntead of DCA_, but the addresses and
863a9ca1c79SSean Bruno 		 * fields remain the same.
864a9ca1c79SSean Bruno 		 */
865758cc3dcSJack F Vogel 		switch (hw->mac.type) {
866758cc3dcSJack F Vogel 		case ixgbe_mac_82598EB:
86748056c88SJack F Vogel 			txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j));
868758cc3dcSJack F Vogel 			break;
869758cc3dcSJack F Vogel 		default:
870*c58d34ddSKevin Bowling 			txctrl =
871*c58d34ddSKevin Bowling 			    IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j));
872758cc3dcSJack F Vogel 			break;
873758cc3dcSJack F Vogel 		}
874758cc3dcSJack F Vogel 		txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN;
875758cc3dcSJack F Vogel 		switch (hw->mac.type) {
876758cc3dcSJack F Vogel 		case ixgbe_mac_82598EB:
87748056c88SJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl);
878758cc3dcSJack F Vogel 			break;
879758cc3dcSJack F Vogel 		default:
880*c58d34ddSKevin Bowling 			IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j),
881*c58d34ddSKevin Bowling 			    txctrl);
882758cc3dcSJack F Vogel 			break;
883758cc3dcSJack F Vogel 		}
884758cc3dcSJack F Vogel 
885758cc3dcSJack F Vogel 	}
886758cc3dcSJack F Vogel 
887758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
888758cc3dcSJack F Vogel 		u32 dmatxctl, rttdcs;
8898eb6488eSEric Joyner 
890758cc3dcSJack F Vogel 		dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
891758cc3dcSJack F Vogel 		dmatxctl |= IXGBE_DMATXCTL_TE;
892758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl);
893758cc3dcSJack F Vogel 		/* Disable arbiter to set MTQC */
894758cc3dcSJack F Vogel 		rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
895758cc3dcSJack F Vogel 		rttdcs |= IXGBE_RTTDCS_ARBDIS;
896758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
8978eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_MTQC,
898b1d5caf3SKevin Bowling 		    ixgbe_get_mtqc(sc->iov_mode));
899758cc3dcSJack F Vogel 		rttdcs &= ~IXGBE_RTTDCS_ARBDIS;
900758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
901758cc3dcSJack F Vogel 	}
902758cc3dcSJack F Vogel 
9038eb6488eSEric Joyner } /* ixgbe_initialize_transmit_units */
904758cc3dcSJack F Vogel 
9058eb6488eSEric Joyner /************************************************************************
906c19c7afeSEric Joyner  * ixgbe_register
907c19c7afeSEric Joyner  ************************************************************************/
908c19c7afeSEric Joyner static void *
909c19c7afeSEric Joyner ixgbe_register(device_t dev)
910c19c7afeSEric Joyner {
911ffe3def9SMark Johnston 	return (&ixgbe_sctx_init);
912c19c7afeSEric Joyner } /* ixgbe_register */
913c19c7afeSEric Joyner 
914c19c7afeSEric Joyner /************************************************************************
915c19c7afeSEric Joyner  * ixgbe_if_attach_pre - Device initialization routine, part 1
916758cc3dcSJack F Vogel  *
9178eb6488eSEric Joyner  *   Called when the driver is being loaded.
918c19c7afeSEric Joyner  *   Identifies the type of hardware, initializes the hardware,
919c19c7afeSEric Joyner  *   and initializes iflib structures.
920758cc3dcSJack F Vogel  *
9218eb6488eSEric Joyner  *   return 0 on success, positive on failure
9228eb6488eSEric Joyner  ************************************************************************/
9238eb6488eSEric Joyner static int
924c19c7afeSEric Joyner ixgbe_if_attach_pre(if_ctx_t ctx)
925758cc3dcSJack F Vogel {
926b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc;
927c19c7afeSEric Joyner 	device_t dev;
928c19c7afeSEric Joyner 	if_softc_ctx_t scctx;
9298eb6488eSEric Joyner 	struct ixgbe_hw *hw;
9308eb6488eSEric Joyner 	int error = 0;
9318eb6488eSEric Joyner 	u32 ctrl_ext;
9327234c309SJakub Chylkowski 	size_t i;
9338eb6488eSEric Joyner 
9348eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_attach: begin");
9358eb6488eSEric Joyner 
9368eb6488eSEric Joyner 	/* Allocate, clear, and link in our adapter structure */
937c19c7afeSEric Joyner 	dev = iflib_get_dev(ctx);
938b1d5caf3SKevin Bowling 	sc = iflib_get_softc(ctx);
939b1d5caf3SKevin Bowling 	sc->hw.back = sc;
940b1d5caf3SKevin Bowling 	sc->ctx = ctx;
941b1d5caf3SKevin Bowling 	sc->dev = dev;
942b1d5caf3SKevin Bowling 	scctx = sc->shared = iflib_get_softc_ctx(ctx);
943b1d5caf3SKevin Bowling 	sc->media = iflib_get_media(ctx);
944b1d5caf3SKevin Bowling 	hw = &sc->hw;
9458eb6488eSEric Joyner 
9468eb6488eSEric Joyner 	/* Determine hardware revision */
9478eb6488eSEric Joyner 	hw->vendor_id = pci_get_vendor(dev);
9488eb6488eSEric Joyner 	hw->device_id = pci_get_device(dev);
9498eb6488eSEric Joyner 	hw->revision_id = pci_get_revid(dev);
9508eb6488eSEric Joyner 	hw->subsystem_vendor_id = pci_get_subvendor(dev);
9518eb6488eSEric Joyner 	hw->subsystem_device_id = pci_get_subdevice(dev);
952758cc3dcSJack F Vogel 
9538eb6488eSEric Joyner 	/* Do base PCI setup - map BAR0 */
954c19c7afeSEric Joyner 	if (ixgbe_allocate_pci_resources(ctx)) {
9558eb6488eSEric Joyner 		device_printf(dev, "Allocation of PCI resources failed\n");
956c19c7afeSEric Joyner 		return (ENXIO);
9576f37f232SEric Joyner 	}
958758cc3dcSJack F Vogel 
9598eb6488eSEric Joyner 	/* let hardware know driver is loaded */
9608eb6488eSEric Joyner 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
9618eb6488eSEric Joyner 	ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
9628eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
963758cc3dcSJack F Vogel 
964758cc3dcSJack F Vogel 	/*
9658eb6488eSEric Joyner 	 * Initialize the shared code
966758cc3dcSJack F Vogel 	 */
967c19c7afeSEric Joyner 	if (ixgbe_init_shared_code(hw) != 0) {
9688eb6488eSEric Joyner 		device_printf(dev, "Unable to initialize the shared code\n");
9698eb6488eSEric Joyner 		error = ENXIO;
970c19c7afeSEric Joyner 		goto err_pci;
97130126537SJack F Vogel 	}
972758cc3dcSJack F Vogel 
973*c58d34ddSKevin Bowling 	if (hw->mac.ops.fw_recovery_mode &&
974*c58d34ddSKevin Bowling 	    hw->mac.ops.fw_recovery_mode(hw)) {
975*c58d34ddSKevin Bowling 		device_printf(dev,
976*c58d34ddSKevin Bowling 		    "Firmware recovery mode detected. Limiting "
9778b4a3fbdSKevin Bowling 		    "functionality.\nRefer to the Intel(R) Ethernet Adapters "
9788b4a3fbdSKevin Bowling 		    "and Devices User Guide for details on firmware recovery "
9798b4a3fbdSKevin Bowling 		    "mode.");
9808b4a3fbdSKevin Bowling 		error = ENOSYS;
9818b4a3fbdSKevin Bowling 		goto err_pci;
9828b4a3fbdSKevin Bowling 	}
9838b4a3fbdSKevin Bowling 
9847234c309SJakub Chylkowski 	/* 82598 Does not support SR-IOV, initialize everything else */
9857234c309SJakub Chylkowski 	if (hw->mac.type >= ixgbe_mac_82599_vf) {
9867234c309SJakub Chylkowski 		for (i = 0; i < sc->num_vfs; i++)
9877234c309SJakub Chylkowski 			hw->mbx.ops[i].init_params(hw);
9887234c309SJakub Chylkowski 	}
989758cc3dcSJack F Vogel 
9908eb6488eSEric Joyner 	hw->allow_unsupported_sfp = allow_unsupported_sfp;
991758cc3dcSJack F Vogel 
992c19c7afeSEric Joyner 	if (hw->mac.type != ixgbe_mac_82598EB)
9938eb6488eSEric Joyner 		hw->phy.smart_speed = ixgbe_smart_speed;
9948eb6488eSEric Joyner 
995b1d5caf3SKevin Bowling 	ixgbe_init_device_features(sc);
9968eb6488eSEric Joyner 
9978eb6488eSEric Joyner 	/* Enable WoL (if supported) */
998b1d5caf3SKevin Bowling 	ixgbe_check_wol_support(sc);
9998eb6488eSEric Joyner 
10008eb6488eSEric Joyner 	/* Verify adapter fan is still functional (if applicable) */
1001b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_FAN_FAIL) {
10028eb6488eSEric Joyner 		u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
1003b1d5caf3SKevin Bowling 		ixgbe_check_fan_failure(sc, esdp, false);
10048eb6488eSEric Joyner 	}
10058eb6488eSEric Joyner 
10068eb6488eSEric Joyner 	/* Ensure SW/FW semaphore is free */
10078eb6488eSEric Joyner 	ixgbe_init_swfw_semaphore(hw);
10088eb6488eSEric Joyner 
10098eb6488eSEric Joyner 	/* Set an initial default flow control value */
10108eb6488eSEric Joyner 	hw->fc.requested_mode = ixgbe_flow_control;
10118eb6488eSEric Joyner 
101279b36ec9SKevin Bowling 	hw->phy.reset_if_overtemp = true;
10138eb6488eSEric Joyner 	error = ixgbe_reset_hw(hw);
101479b36ec9SKevin Bowling 	hw->phy.reset_if_overtemp = false;
10158eb6488eSEric Joyner 	if (error == IXGBE_ERR_SFP_NOT_PRESENT) {
1016758cc3dcSJack F Vogel 		/*
10178eb6488eSEric Joyner 		 * No optics in this port, set up
10188eb6488eSEric Joyner 		 * so the timer routine will probe
10198eb6488eSEric Joyner 		 * for later insertion.
1020758cc3dcSJack F Vogel 		 */
1021b1d5caf3SKevin Bowling 		sc->sfp_probe = true;
1022c19c7afeSEric Joyner 		error = 0;
10238eb6488eSEric Joyner 	} else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) {
10248eb6488eSEric Joyner 		device_printf(dev, "Unsupported SFP+ module detected!\n");
10258eb6488eSEric Joyner 		error = EIO;
1026c19c7afeSEric Joyner 		goto err_pci;
10278eb6488eSEric Joyner 	} else if (error) {
10288eb6488eSEric Joyner 		device_printf(dev, "Hardware initialization failed\n");
10298eb6488eSEric Joyner 		error = EIO;
1030c19c7afeSEric Joyner 		goto err_pci;
103197f9586eSSean Bruno 	}
103297f9586eSSean Bruno 
10338eb6488eSEric Joyner 	/* Make sure we have a good EEPROM before we read from it */
1034b1d5caf3SKevin Bowling 	if (ixgbe_validate_eeprom_checksum(&sc->hw, NULL) < 0) {
10358eb6488eSEric Joyner 		device_printf(dev, "The EEPROM Checksum Is Not Valid\n");
10368eb6488eSEric Joyner 		error = EIO;
1037c19c7afeSEric Joyner 		goto err_pci;
103897f9586eSSean Bruno 	}
103997f9586eSSean Bruno 
10408eb6488eSEric Joyner 	error = ixgbe_start_hw(hw);
10418eb6488eSEric Joyner 	switch (error) {
10428eb6488eSEric Joyner 	case IXGBE_ERR_EEPROM_VERSION:
1043*c58d34ddSKevin Bowling 		device_printf(dev,
1044*c58d34ddSKevin Bowling 		    "This device is a pre-production adapter/LOM.  Please be"
1045*c58d34ddSKevin Bowling 		    " aware there may be issues associated with your"
1046*c58d34ddSKevin Bowling 		    " hardware.\nIf you are experiencing problems please"
1047*c58d34ddSKevin Bowling 		    " contact your Intel or hardware representative who"
1048*c58d34ddSKevin Bowling 		    " provided you with this hardware.\n");
104997f9586eSSean Bruno 		break;
10508eb6488eSEric Joyner 	case IXGBE_ERR_SFP_NOT_SUPPORTED:
10518eb6488eSEric Joyner 		device_printf(dev, "Unsupported SFP+ Module\n");
10528eb6488eSEric Joyner 		error = EIO;
1053c19c7afeSEric Joyner 		goto err_pci;
10548eb6488eSEric Joyner 	case IXGBE_ERR_SFP_NOT_PRESENT:
10558eb6488eSEric Joyner 		device_printf(dev, "No SFP+ Module found\n");
10568eb6488eSEric Joyner 		/* falls thru */
105797f9586eSSean Bruno 	default:
105897f9586eSSean Bruno 		break;
105997f9586eSSean Bruno 	}
106097f9586eSSean Bruno 
1061c19c7afeSEric Joyner 	/* Most of the iflib initialization... */
1062c19c7afeSEric Joyner 
1063c19c7afeSEric Joyner 	iflib_set_mac(ctx, hw->mac.addr);
1064b1d5caf3SKevin Bowling 	switch (sc->hw.mac.type) {
1065c19c7afeSEric Joyner 	case ixgbe_mac_X550:
1066c19c7afeSEric Joyner 	case ixgbe_mac_X550EM_x:
1067c19c7afeSEric Joyner 	case ixgbe_mac_X550EM_a:
1068c19c7afeSEric Joyner 		scctx->isc_rss_table_size = 512;
1069c19c7afeSEric Joyner 		scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 64;
1070c19c7afeSEric Joyner 		break;
1071c19c7afeSEric Joyner 	default:
1072c19c7afeSEric Joyner 		scctx->isc_rss_table_size = 128;
1073c19c7afeSEric Joyner 		scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 16;
1074c19c7afeSEric Joyner 	}
1075c19c7afeSEric Joyner 
1076c19c7afeSEric Joyner 	/* Allow legacy interrupts */
1077c19c7afeSEric Joyner 	ixgbe_txrx.ift_legacy_intr = ixgbe_intr;
1078c19c7afeSEric Joyner 
1079c19c7afeSEric Joyner 	scctx->isc_txqsizes[0] =
1080c19c7afeSEric Joyner 	    roundup2(scctx->isc_ntxd[0] * sizeof(union ixgbe_adv_tx_desc) +
1081c19c7afeSEric Joyner 	    sizeof(u32), DBA_ALIGN),
1082c19c7afeSEric Joyner 	scctx->isc_rxqsizes[0] =
1083c19c7afeSEric Joyner 	    roundup2(scctx->isc_nrxd[0] * sizeof(union ixgbe_adv_rx_desc),
1084c19c7afeSEric Joyner 	    DBA_ALIGN);
1085c19c7afeSEric Joyner 
1086c19c7afeSEric Joyner 	/* XXX */
1087c19c7afeSEric Joyner 	scctx->isc_tx_csum_flags = CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TSO |
1088c19c7afeSEric Joyner 	    CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_IP6_TSO;
1089b1d5caf3SKevin Bowling 	if (sc->hw.mac.type == ixgbe_mac_82598EB) {
1090c19c7afeSEric Joyner 		scctx->isc_tx_nsegments = IXGBE_82598_SCATTER;
1091c19c7afeSEric Joyner 	} else {
1092c19c7afeSEric Joyner 		scctx->isc_tx_csum_flags |= CSUM_SCTP |CSUM_IP6_SCTP;
1093c19c7afeSEric Joyner 		scctx->isc_tx_nsegments = IXGBE_82599_SCATTER;
1094c19c7afeSEric Joyner 	}
1095749597dcSEric Joyner 
1096749597dcSEric Joyner 	scctx->isc_msix_bar = pci_msix_table_bar(dev);
1097749597dcSEric Joyner 
1098c19c7afeSEric Joyner 	scctx->isc_tx_tso_segments_max = scctx->isc_tx_nsegments;
1099c19c7afeSEric Joyner 	scctx->isc_tx_tso_size_max = IXGBE_TSO_SIZE;
1100c19c7afeSEric Joyner 	scctx->isc_tx_tso_segsize_max = PAGE_SIZE;
1101c19c7afeSEric Joyner 
1102c19c7afeSEric Joyner 	scctx->isc_txrx = &ixgbe_txrx;
1103c19c7afeSEric Joyner 
11047f87c040SMarius Strobl 	scctx->isc_capabilities = scctx->isc_capenable = IXGBE_CAPS;
1105c19c7afeSEric Joyner 
1106c19c7afeSEric Joyner 	return (0);
1107c19c7afeSEric Joyner 
1108c19c7afeSEric Joyner err_pci:
1109b1d5caf3SKevin Bowling 	ctrl_ext = IXGBE_READ_REG(&sc->hw, IXGBE_CTRL_EXT);
1110c19c7afeSEric Joyner 	ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
1111b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(&sc->hw, IXGBE_CTRL_EXT, ctrl_ext);
1112c19c7afeSEric Joyner 	ixgbe_free_pci_resources(ctx);
1113c19c7afeSEric Joyner 
1114c19c7afeSEric Joyner 	return (error);
1115c19c7afeSEric Joyner } /* ixgbe_if_attach_pre */
1116c19c7afeSEric Joyner 
1117c19c7afeSEric Joyner  /*********************************************************************
1118c19c7afeSEric Joyner  * ixgbe_if_attach_post - Device initialization routine, part 2
1119c19c7afeSEric Joyner  *
1120c19c7afeSEric Joyner  *   Called during driver load, but after interrupts and
1121c19c7afeSEric Joyner  *   resources have been allocated and configured.
1122c19c7afeSEric Joyner  *   Sets up some data structures not relevant to iflib.
1123c19c7afeSEric Joyner  *
1124c19c7afeSEric Joyner  *   return 0 on success, positive on failure
1125c19c7afeSEric Joyner  *********************************************************************/
1126c19c7afeSEric Joyner static int
1127c19c7afeSEric Joyner ixgbe_if_attach_post(if_ctx_t ctx)
1128c19c7afeSEric Joyner {
1129c19c7afeSEric Joyner 	device_t dev;
1130b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc;
1131c19c7afeSEric Joyner 	struct ixgbe_hw *hw;
1132c19c7afeSEric Joyner 	int error = 0;
1133c19c7afeSEric Joyner 
1134c19c7afeSEric Joyner 	dev = iflib_get_dev(ctx);
1135b1d5caf3SKevin Bowling 	sc = iflib_get_softc(ctx);
1136b1d5caf3SKevin Bowling 	hw = &sc->hw;
1137c19c7afeSEric Joyner 
1138b1d5caf3SKevin Bowling 	if (sc->intr_type == IFLIB_INTR_LEGACY &&
1139b1d5caf3SKevin Bowling 		(sc->feat_cap & IXGBE_FEATURE_LEGACY_IRQ) == 0) {
1140c19c7afeSEric Joyner 		device_printf(dev, "Device does not support legacy interrupts");
1141c19c7afeSEric Joyner 		error = ENXIO;
1142c19c7afeSEric Joyner 		goto err;
1143c19c7afeSEric Joyner 	}
1144c19c7afeSEric Joyner 
1145c19c7afeSEric Joyner 	/* Allocate multicast array memory. */
1146*c58d34ddSKevin Bowling 	sc->mta = malloc(sizeof(*sc->mta) * MAX_NUM_MULTICAST_ADDRESSES,
1147*c58d34ddSKevin Bowling 	    M_IXGBE, M_NOWAIT);
1148b1d5caf3SKevin Bowling 	if (sc->mta == NULL) {
1149*c58d34ddSKevin Bowling 		device_printf(dev,
1150*c58d34ddSKevin Bowling 		    "Can not allocate multicast setup array\n");
1151c19c7afeSEric Joyner 		error = ENOMEM;
1152c19c7afeSEric Joyner 		goto err;
1153c19c7afeSEric Joyner 	}
1154c19c7afeSEric Joyner 
1155c19c7afeSEric Joyner 	/* hw.ix defaults init */
1156b1d5caf3SKevin Bowling 	ixgbe_set_advertise(sc, ixgbe_advertise_speed);
1157c19c7afeSEric Joyner 
11588eb6488eSEric Joyner 	/* Enable the optics for 82599 SFP+ fiber */
11598eb6488eSEric Joyner 	ixgbe_enable_tx_laser(hw);
1160758cc3dcSJack F Vogel 
11618eb6488eSEric Joyner 	/* Enable power to the phy. */
116279b36ec9SKevin Bowling 	ixgbe_set_phy_power(hw, true);
11638eb6488eSEric Joyner 
1164b1d5caf3SKevin Bowling 	ixgbe_initialize_iov(sc);
1165c19c7afeSEric Joyner 
1166c19c7afeSEric Joyner 	error = ixgbe_setup_interface(ctx);
1167c19c7afeSEric Joyner 	if (error) {
1168c19c7afeSEric Joyner 		device_printf(dev, "Interface setup failed: %d\n", error);
1169c19c7afeSEric Joyner 		goto err;
1170c19c7afeSEric Joyner 	}
1171c19c7afeSEric Joyner 
1172c19c7afeSEric Joyner 	ixgbe_if_update_admin_status(ctx);
1173c19c7afeSEric Joyner 
11748eb6488eSEric Joyner 	/* Initialize statistics */
1175b1d5caf3SKevin Bowling 	ixgbe_update_stats_counters(sc);
1176b1d5caf3SKevin Bowling 	ixgbe_add_hw_stats(sc);
11778eb6488eSEric Joyner 
11788eb6488eSEric Joyner 	/* Check PCIE slot type/speed/width */
1179b1d5caf3SKevin Bowling 	ixgbe_get_slot_info(sc);
1180758cc3dcSJack F Vogel 
1181758cc3dcSJack F Vogel 	/*
11828eb6488eSEric Joyner 	 * Do time init and sysctl init here, but
1183b1d5caf3SKevin Bowling 	 * only on the first port of a bypass sc.
1184758cc3dcSJack F Vogel 	 */
1185b1d5caf3SKevin Bowling 	ixgbe_bypass_init(sc);
1186758cc3dcSJack F Vogel 
11877660e4eaSKevin Bowling 	/* Display NVM and Option ROM versions */
11887660e4eaSKevin Bowling 	ixgbe_print_fw_version(ctx);
11897660e4eaSKevin Bowling 
11908eb6488eSEric Joyner 	/* Set an initial dmac value */
1191b1d5caf3SKevin Bowling 	sc->dmac = 0;
11928eb6488eSEric Joyner 	/* Set initial advertised speeds (if applicable) */
1193d381c807SPiotr Pietruszewski 	sc->advertise = ixgbe_get_default_advertise(sc);
1194758cc3dcSJack F Vogel 
1195b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_SRIOV)
11968eb6488eSEric Joyner 		ixgbe_define_iov_schemas(dev, &error);
1197758cc3dcSJack F Vogel 
11988eb6488eSEric Joyner 	/* Add sysctls */
1199c19c7afeSEric Joyner 	ixgbe_add_device_sysctls(ctx);
1200758cc3dcSJack F Vogel 
1201f72de14eSKevin Bowling 	/* Init recovery mode timer and state variable */
1202f72de14eSKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_RECOVERY_MODE) {
1203f72de14eSKevin Bowling 		sc->recovery_mode = 0;
1204f72de14eSKevin Bowling 
1205f72de14eSKevin Bowling 		/* Set up the timer callout */
1206f72de14eSKevin Bowling 		callout_init(&sc->fw_mode_timer, true);
1207f72de14eSKevin Bowling 
1208f72de14eSKevin Bowling 		/* Start the task */
1209a924b5eeSKevin Bowling 		callout_reset(&sc->fw_mode_timer, hz, ixgbe_fw_mode_timer, sc);
1210f72de14eSKevin Bowling 	}
1211f72de14eSKevin Bowling 
12128eb6488eSEric Joyner 	return (0);
1213c19c7afeSEric Joyner err:
12148eb6488eSEric Joyner 	return (error);
1215c19c7afeSEric Joyner } /* ixgbe_if_attach_post */
12168eb6488eSEric Joyner 
12178eb6488eSEric Joyner /************************************************************************
12188eb6488eSEric Joyner  * ixgbe_check_wol_support
12196f37f232SEric Joyner  *
12206f37f232SEric Joyner  *   Checks whether the adapter's ports are capable of
12216f37f232SEric Joyner  *   Wake On LAN by reading the adapter's NVM.
12226f37f232SEric Joyner  *
12236f37f232SEric Joyner  *   Sets each port's hw->wol_enabled value depending
12246f37f232SEric Joyner  *   on the value read here.
12258eb6488eSEric Joyner  ************************************************************************/
12266f37f232SEric Joyner static void
1227b1d5caf3SKevin Bowling ixgbe_check_wol_support(struct ixgbe_softc *sc)
12286f37f232SEric Joyner {
1229b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
12306f37f232SEric Joyner 	u16 dev_caps = 0;
12316f37f232SEric Joyner 
12326f37f232SEric Joyner 	/* Find out WoL support for port */
1233b1d5caf3SKevin Bowling 	sc->wol_support = hw->wol_enabled = 0;
12346f37f232SEric Joyner 	ixgbe_get_device_caps(hw, &dev_caps);
12356f37f232SEric Joyner 	if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
12366f37f232SEric Joyner 	    ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) &&
12376f37f232SEric Joyner 	     hw->bus.func == 0))
1238b1d5caf3SKevin Bowling 		sc->wol_support = hw->wol_enabled = 1;
12396f37f232SEric Joyner 
12406f37f232SEric Joyner 	/* Save initial wake up filter configuration */
1241b1d5caf3SKevin Bowling 	sc->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC);
12426f37f232SEric Joyner 
12436f37f232SEric Joyner 	return;
12448eb6488eSEric Joyner } /* ixgbe_check_wol_support */
12456f37f232SEric Joyner 
12468eb6488eSEric Joyner /************************************************************************
12478eb6488eSEric Joyner  * ixgbe_setup_interface
12488eb6488eSEric Joyner  *
12498eb6488eSEric Joyner  *   Setup networking device structure and register an interface.
12508eb6488eSEric Joyner  ************************************************************************/
12516f37f232SEric Joyner static int
1252c19c7afeSEric Joyner ixgbe_setup_interface(if_ctx_t ctx)
12536f37f232SEric Joyner {
1254ff06a8dbSJustin Hibbits 	if_t ifp = iflib_get_ifp(ctx);
1255b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
12566f37f232SEric Joyner 
12578eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_setup_interface: begin");
12586f37f232SEric Joyner 
1259c19c7afeSEric Joyner 	if_setbaudrate(ifp, IF_Gbps(10));
12606f37f232SEric Joyner 
1261ff06a8dbSJustin Hibbits 	sc->max_frame_size = if_getmtu(ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN;
1262758cc3dcSJack F Vogel 
1263b1d5caf3SKevin Bowling 	sc->phy_layer = ixgbe_get_supported_physical_layer(&sc->hw);
12648eb6488eSEric Joyner 
1265c19c7afeSEric Joyner 	ixgbe_add_media_types(ctx);
1266c19c7afeSEric Joyner 
1267c19c7afeSEric Joyner 	/* Autoselect media by default */
1268b1d5caf3SKevin Bowling 	ifmedia_set(sc->media, IFM_ETHER | IFM_AUTO);
12698eb6488eSEric Joyner 
12708eb6488eSEric Joyner 	return (0);
12718eb6488eSEric Joyner } /* ixgbe_setup_interface */
1272758cc3dcSJack F Vogel 
12738eb6488eSEric Joyner /************************************************************************
1274c19c7afeSEric Joyner  * ixgbe_if_get_counter
12758eb6488eSEric Joyner  ************************************************************************/
1276758cc3dcSJack F Vogel static uint64_t
1277c19c7afeSEric Joyner ixgbe_if_get_counter(if_ctx_t ctx, ift_counter cnt)
1278758cc3dcSJack F Vogel {
1279b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
1280c19c7afeSEric Joyner 	if_t ifp = iflib_get_ifp(ctx);
1281758cc3dcSJack F Vogel 
1282758cc3dcSJack F Vogel 	switch (cnt) {
1283758cc3dcSJack F Vogel 	case IFCOUNTER_IPACKETS:
1284b1d5caf3SKevin Bowling 		return (sc->ipackets);
1285758cc3dcSJack F Vogel 	case IFCOUNTER_OPACKETS:
1286b1d5caf3SKevin Bowling 		return (sc->opackets);
1287758cc3dcSJack F Vogel 	case IFCOUNTER_IBYTES:
1288b1d5caf3SKevin Bowling 		return (sc->ibytes);
1289758cc3dcSJack F Vogel 	case IFCOUNTER_OBYTES:
1290b1d5caf3SKevin Bowling 		return (sc->obytes);
1291758cc3dcSJack F Vogel 	case IFCOUNTER_IMCASTS:
1292b1d5caf3SKevin Bowling 		return (sc->imcasts);
1293758cc3dcSJack F Vogel 	case IFCOUNTER_OMCASTS:
1294b1d5caf3SKevin Bowling 		return (sc->omcasts);
1295758cc3dcSJack F Vogel 	case IFCOUNTER_COLLISIONS:
1296758cc3dcSJack F Vogel 		return (0);
1297758cc3dcSJack F Vogel 	case IFCOUNTER_IQDROPS:
1298b1d5caf3SKevin Bowling 		return (sc->iqdrops);
1299625d12c6SJohn Baldwin 	case IFCOUNTER_OQDROPS:
1300c19c7afeSEric Joyner 		return (0);
1301758cc3dcSJack F Vogel 	case IFCOUNTER_IERRORS:
1302b1d5caf3SKevin Bowling 		return (sc->ierrors);
1303758cc3dcSJack F Vogel 	default:
1304758cc3dcSJack F Vogel 		return (if_get_counter_default(ifp, cnt));
1305758cc3dcSJack F Vogel 	}
1306c19c7afeSEric Joyner } /* ixgbe_if_get_counter */
1307758cc3dcSJack F Vogel 
13088eb6488eSEric Joyner /************************************************************************
1309bca38080SAndrew Gallatin  * ixgbe_if_i2c_req
1310bca38080SAndrew Gallatin  ************************************************************************/
1311bca38080SAndrew Gallatin static int
1312bca38080SAndrew Gallatin ixgbe_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req)
1313bca38080SAndrew Gallatin {
1314b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
1315b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
1316bca38080SAndrew Gallatin 	int i;
1317bca38080SAndrew Gallatin 
1318bca38080SAndrew Gallatin 	if (hw->phy.ops.read_i2c_byte == NULL)
1319bca38080SAndrew Gallatin 		return (ENXIO);
1320bca38080SAndrew Gallatin 	for (i = 0; i < req->len; i++)
1321bca38080SAndrew Gallatin 		hw->phy.ops.read_i2c_byte(hw, req->offset + i,
1322bca38080SAndrew Gallatin 		    req->dev_addr, &req->data[i]);
1323bca38080SAndrew Gallatin 	return (0);
1324bca38080SAndrew Gallatin } /* ixgbe_if_i2c_req */
1325bca38080SAndrew Gallatin 
1326*c58d34ddSKevin Bowling /* ixgbe_if_needs_restart - Tell iflib when the driver needs to be
1327*c58d34ddSKevin Bowling  * reinitialized
1328cf150917SEric Joyner  * @ctx: iflib context
1329cf150917SEric Joyner  * @event: event code to check
1330cf150917SEric Joyner  *
1331725e4008SKevin Bowling  * Defaults to returning false for unknown events.
1332cf150917SEric Joyner  *
1333cf150917SEric Joyner  * @returns true if iflib needs to reinit the interface
1334cf150917SEric Joyner  */
1335cf150917SEric Joyner static bool
1336cf150917SEric Joyner ixgbe_if_needs_restart(if_ctx_t ctx __unused, enum iflib_restart_event event)
1337cf150917SEric Joyner {
1338cf150917SEric Joyner 	switch (event) {
1339cf150917SEric Joyner 	case IFLIB_RESTART_VLAN_CONFIG:
1340cf150917SEric Joyner 	default:
1341725e4008SKevin Bowling 		return (false);
1342cf150917SEric Joyner 	}
1343cf150917SEric Joyner }
1344cf150917SEric Joyner 
1345bca38080SAndrew Gallatin /************************************************************************
13468eb6488eSEric Joyner  * ixgbe_add_media_types
13478eb6488eSEric Joyner  ************************************************************************/
13488eb6488eSEric Joyner static void
1349c19c7afeSEric Joyner ixgbe_add_media_types(if_ctx_t ctx)
13508eb6488eSEric Joyner {
1351b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
1352b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
1353c19c7afeSEric Joyner 	device_t dev = iflib_get_dev(ctx);
13548eb6488eSEric Joyner 	u64 layer;
13558eb6488eSEric Joyner 
1356b1d5caf3SKevin Bowling 	layer = sc->phy_layer = ixgbe_get_supported_physical_layer(hw);
13578eb6488eSEric Joyner 
13588eb6488eSEric Joyner 	/* Media types with matching FreeBSD media defines */
13598eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T)
1360b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_T, 0, NULL);
13618eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T)
1362b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_T, 0, NULL);
13638eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX)
1364b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_100_TX, 0, NULL);
13658eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10BASE_T)
1366b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10_T, 0, NULL);
13678eb6488eSEric Joyner 
1368d381c807SPiotr Pietruszewski 	if (hw->mac.type == ixgbe_mac_X550) {
1369d381c807SPiotr Pietruszewski 		ifmedia_add(sc->media, IFM_ETHER | IFM_2500_T, 0, NULL);
1370d381c807SPiotr Pietruszewski 		ifmedia_add(sc->media, IFM_ETHER | IFM_5000_T, 0, NULL);
1371d381c807SPiotr Pietruszewski 	}
1372d381c807SPiotr Pietruszewski 
13738eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU ||
137448ddd1b9SKevin Bowling 	    layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) {
1375b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_TWINAX, 0,
13768eb6488eSEric Joyner 		    NULL);
137748ddd1b9SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_KX, 0, NULL);
137848ddd1b9SKevin Bowling 	}
13798eb6488eSEric Joyner 
13808eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) {
1381b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
13828eb6488eSEric Joyner 		if (hw->phy.multispeed_fiber)
1383b1d5caf3SKevin Bowling 			ifmedia_add(sc->media, IFM_ETHER | IFM_1000_LX, 0,
13848eb6488eSEric Joyner 			    NULL);
13858eb6488eSEric Joyner 	}
13868eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) {
1387b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
13888eb6488eSEric Joyner 		if (hw->phy.multispeed_fiber)
1389b1d5caf3SKevin Bowling 			ifmedia_add(sc->media, IFM_ETHER | IFM_1000_SX, 0,
13908eb6488eSEric Joyner 			    NULL);
13918eb6488eSEric Joyner 	} else if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX)
1392b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
13938eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4)
1394b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
13958eb6488eSEric Joyner 
13968eb6488eSEric Joyner #ifdef IFM_ETH_XTYPE
13978eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR)
1398b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_KR, 0, NULL);
13998eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4)
1400b1d5caf3SKevin Bowling 		ifmedia_add( sc->media, IFM_ETHER | IFM_10G_KX4, 0, NULL);
14018eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX)
1402b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_KX, 0, NULL);
14038eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX)
1404b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_2500_KX, 0, NULL);
14058eb6488eSEric Joyner #else
14068eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) {
14078eb6488eSEric Joyner 		device_printf(dev, "Media supported: 10GbaseKR\n");
14088eb6488eSEric Joyner 		device_printf(dev, "10GbaseKR mapped to 10GbaseSR\n");
1409b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
14108eb6488eSEric Joyner 	}
14118eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) {
14128eb6488eSEric Joyner 		device_printf(dev, "Media supported: 10GbaseKX4\n");
14138eb6488eSEric Joyner 		device_printf(dev, "10GbaseKX4 mapped to 10GbaseCX4\n");
1414b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
14158eb6488eSEric Joyner 	}
14168eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) {
14178eb6488eSEric Joyner 		device_printf(dev, "Media supported: 1000baseKX\n");
14188eb6488eSEric Joyner 		device_printf(dev, "1000baseKX mapped to 1000baseCX\n");
1419b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_CX, 0, NULL);
14208eb6488eSEric Joyner 	}
14218eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX) {
14228eb6488eSEric Joyner 		device_printf(dev, "Media supported: 2500baseKX\n");
14238eb6488eSEric Joyner 		device_printf(dev, "2500baseKX mapped to 2500baseSX\n");
1424b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_2500_SX, 0, NULL);
14258eb6488eSEric Joyner 	}
14268eb6488eSEric Joyner #endif
14278eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX)
14288eb6488eSEric Joyner 		device_printf(dev, "Media supported: 1000baseBX\n");
14298eb6488eSEric Joyner 
14308eb6488eSEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_82598AT) {
1431b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
14328eb6488eSEric Joyner 		    0, NULL);
1433b1d5caf3SKevin Bowling 		ifmedia_add(sc->media, IFM_ETHER | IFM_1000_T, 0, NULL);
14348eb6488eSEric Joyner 	}
14358eb6488eSEric Joyner 
1436b1d5caf3SKevin Bowling 	ifmedia_add(sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
14378eb6488eSEric Joyner } /* ixgbe_add_media_types */
14388eb6488eSEric Joyner 
14398eb6488eSEric Joyner /************************************************************************
14408eb6488eSEric Joyner  * ixgbe_is_sfp
14418eb6488eSEric Joyner  ************************************************************************/
14428eb6488eSEric Joyner static inline bool
14438eb6488eSEric Joyner ixgbe_is_sfp(struct ixgbe_hw *hw)
14448eb6488eSEric Joyner {
14458eb6488eSEric Joyner 	switch (hw->mac.type) {
14468eb6488eSEric Joyner 	case ixgbe_mac_82598EB:
14478eb6488eSEric Joyner 		if (hw->phy.type == ixgbe_phy_nl)
144879b36ec9SKevin Bowling 			return (true);
144979b36ec9SKevin Bowling 		return (false);
14508eb6488eSEric Joyner 	case ixgbe_mac_82599EB:
14518eb6488eSEric Joyner 		switch (hw->mac.ops.get_media_type(hw)) {
14528eb6488eSEric Joyner 		case ixgbe_media_type_fiber:
14538eb6488eSEric Joyner 		case ixgbe_media_type_fiber_qsfp:
145479b36ec9SKevin Bowling 			return (true);
14558eb6488eSEric Joyner 		default:
145679b36ec9SKevin Bowling 			return (false);
14578eb6488eSEric Joyner 		}
14588eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
14598eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
14608eb6488eSEric Joyner 		if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber)
146179b36ec9SKevin Bowling 			return (true);
146279b36ec9SKevin Bowling 		return (false);
14638eb6488eSEric Joyner 	default:
146479b36ec9SKevin Bowling 		return (false);
14658eb6488eSEric Joyner 	}
14668eb6488eSEric Joyner } /* ixgbe_is_sfp */
14678eb6488eSEric Joyner 
14688eb6488eSEric Joyner /************************************************************************
14698eb6488eSEric Joyner  * ixgbe_config_link
14708eb6488eSEric Joyner  ************************************************************************/
14718eb6488eSEric Joyner static void
1472b2c1e8e6SEric Joyner ixgbe_config_link(if_ctx_t ctx)
14738eb6488eSEric Joyner {
1474b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
1475b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
14768eb6488eSEric Joyner 	u32 autoneg, err = 0;
14778eb6488eSEric Joyner 	bool sfp, negotiate;
14788eb6488eSEric Joyner 
14798eb6488eSEric Joyner 	sfp = ixgbe_is_sfp(hw);
14808eb6488eSEric Joyner 
14818eb6488eSEric Joyner 	if (sfp) {
1482b1d5caf3SKevin Bowling 		sc->task_requests |= IXGBE_REQUEST_TASK_MOD;
1483b2c1e8e6SEric Joyner 		iflib_admin_intr_deferred(ctx);
14848eb6488eSEric Joyner 	} else {
14858eb6488eSEric Joyner 		if (hw->mac.ops.check_link)
1486b1d5caf3SKevin Bowling 			err = ixgbe_check_link(hw, &sc->link_speed,
1487b1d5caf3SKevin Bowling 			    &sc->link_up, false);
14888eb6488eSEric Joyner 		if (err)
1489c19c7afeSEric Joyner 			return;
14908eb6488eSEric Joyner 		autoneg = hw->phy.autoneg_advertised;
14918eb6488eSEric Joyner 		if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
14928eb6488eSEric Joyner 			err = hw->mac.ops.get_link_capabilities(hw, &autoneg,
14938eb6488eSEric Joyner 			    &negotiate);
14948eb6488eSEric Joyner 		if (err)
1495c19c7afeSEric Joyner 			return;
1496d381c807SPiotr Pietruszewski 
1497d381c807SPiotr Pietruszewski 		if (hw->mac.type == ixgbe_mac_X550 &&
1498d381c807SPiotr Pietruszewski 		    hw->phy.autoneg_advertised == 0) {
1499d381c807SPiotr Pietruszewski 			/*
1500d381c807SPiotr Pietruszewski 			 * 2.5G and 5G autonegotiation speeds on X550
1501d381c807SPiotr Pietruszewski 			 * are disabled by default due to reported
1502d381c807SPiotr Pietruszewski 			 * interoperability issues with some switches.
1503d381c807SPiotr Pietruszewski 			 *
1504d381c807SPiotr Pietruszewski 			 * The second condition checks if any operations
1505d381c807SPiotr Pietruszewski 			 * involving setting autonegotiation speeds have
1506d381c807SPiotr Pietruszewski 			 * been performed prior to this ixgbe_config_link()
1507d381c807SPiotr Pietruszewski 			 * call.
1508d381c807SPiotr Pietruszewski 			 *
1509d381c807SPiotr Pietruszewski 			 * If hw->phy.autoneg_advertised does not
1510d381c807SPiotr Pietruszewski 			 * equal 0, this means that the user might have
1511d381c807SPiotr Pietruszewski 			 * set autonegotiation speeds via the sysctl
1512d381c807SPiotr Pietruszewski 			 * before bringing the interface up. In this
1513d381c807SPiotr Pietruszewski 			 * case, we should not disable 2.5G and 5G
1514d381c807SPiotr Pietruszewski 			 * since that speeds might be selected by the
1515d381c807SPiotr Pietruszewski 			 * user.
1516d381c807SPiotr Pietruszewski 			 *
1517d381c807SPiotr Pietruszewski 			 * Otherwise (i.e. if hw->phy.autoneg_advertised
1518d381c807SPiotr Pietruszewski 			 * is set to 0), it is the first time we set
1519d381c807SPiotr Pietruszewski 			 * autonegotiation preferences and the default
1520d381c807SPiotr Pietruszewski 			 * set of speeds should exclude 2.5G and 5G.
1521d381c807SPiotr Pietruszewski 			 */
1522d381c807SPiotr Pietruszewski 			autoneg &= ~(IXGBE_LINK_SPEED_2_5GB_FULL |
1523d381c807SPiotr Pietruszewski 			    IXGBE_LINK_SPEED_5GB_FULL);
1524d381c807SPiotr Pietruszewski 		}
1525d381c807SPiotr Pietruszewski 
15268eb6488eSEric Joyner 		if (hw->mac.ops.setup_link)
15278eb6488eSEric Joyner 			err = hw->mac.ops.setup_link(hw, autoneg,
1528b1d5caf3SKevin Bowling 			    sc->link_up);
15298eb6488eSEric Joyner 	}
15308eb6488eSEric Joyner } /* ixgbe_config_link */
15318eb6488eSEric Joyner 
15328eb6488eSEric Joyner /************************************************************************
15338eb6488eSEric Joyner  * ixgbe_update_stats_counters - Update board statistics counters.
15348eb6488eSEric Joyner  ************************************************************************/
15358eb6488eSEric Joyner static void
1536b1d5caf3SKevin Bowling ixgbe_update_stats_counters(struct ixgbe_softc *sc)
15378eb6488eSEric Joyner {
1538b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
1539b1d5caf3SKevin Bowling 	struct ixgbe_hw_stats *stats = &sc->stats.pf;
15408eb6488eSEric Joyner 	u32 missed_rx = 0, bprc, lxon, lxoff, total;
1541e37d3dc1SEric Joyner 	u32 lxoffrxc;
15428eb6488eSEric Joyner 	u64 total_missed_rx = 0;
15438eb6488eSEric Joyner 
15448eb6488eSEric Joyner 	stats->crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
15458eb6488eSEric Joyner 	stats->illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC);
15468eb6488eSEric Joyner 	stats->errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC);
15478eb6488eSEric Joyner 	stats->mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC);
15488eb6488eSEric Joyner 	stats->mpc[0] += IXGBE_READ_REG(hw, IXGBE_MPC(0));
15498eb6488eSEric Joyner 
15508eb6488eSEric Joyner 	for (int i = 0; i < 16; i++) {
15518eb6488eSEric Joyner 		stats->qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
15528eb6488eSEric Joyner 		stats->qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
15538eb6488eSEric Joyner 		stats->qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
15548eb6488eSEric Joyner 	}
15558eb6488eSEric Joyner 	stats->mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC);
15568eb6488eSEric Joyner 	stats->mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC);
15578eb6488eSEric Joyner 	stats->rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
15588eb6488eSEric Joyner 
15598eb6488eSEric Joyner 	/* Hardware workaround, gprc counts missed packets */
15608eb6488eSEric Joyner 	stats->gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
15618eb6488eSEric Joyner 	stats->gprc -= missed_rx;
15628eb6488eSEric Joyner 
15638eb6488eSEric Joyner 	if (hw->mac.type != ixgbe_mac_82598EB) {
15648eb6488eSEric Joyner 		stats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) +
15658eb6488eSEric Joyner 		    ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32);
15668eb6488eSEric Joyner 		stats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) +
15678eb6488eSEric Joyner 		    ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32);
15688eb6488eSEric Joyner 		stats->tor += IXGBE_READ_REG(hw, IXGBE_TORL) +
15698eb6488eSEric Joyner 		    ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32);
15708eb6488eSEric Joyner 		stats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
1571e37d3dc1SEric Joyner 		lxoffrxc = IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
1572e37d3dc1SEric Joyner 		stats->lxoffrxc += lxoffrxc;
15738eb6488eSEric Joyner 	} else {
15748eb6488eSEric Joyner 		stats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
1575e37d3dc1SEric Joyner 		lxoffrxc = IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
1576e37d3dc1SEric Joyner 		stats->lxoffrxc += lxoffrxc;
15778eb6488eSEric Joyner 		/* 82598 only has a counter in the high register */
15788eb6488eSEric Joyner 		stats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
15798eb6488eSEric Joyner 		stats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
15808eb6488eSEric Joyner 		stats->tor += IXGBE_READ_REG(hw, IXGBE_TORH);
15818eb6488eSEric Joyner 	}
15828eb6488eSEric Joyner 
15838eb6488eSEric Joyner 	/*
1584e37d3dc1SEric Joyner 	 * For watchdog management we need to know if we have been paused
1585e37d3dc1SEric Joyner 	 * during the last interval, so capture that here.
1586e37d3dc1SEric Joyner 	*/
1587e37d3dc1SEric Joyner 	if (lxoffrxc)
1588b1d5caf3SKevin Bowling 		sc->shared->isc_pause_frames = 1;
1589e37d3dc1SEric Joyner 
1590e37d3dc1SEric Joyner 	/*
15918eb6488eSEric Joyner 	 * Workaround: mprc hardware is incorrectly counting
15928eb6488eSEric Joyner 	 * broadcasts, so for now we subtract those.
1593758cc3dcSJack F Vogel 	 */
15948eb6488eSEric Joyner 	bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
15958eb6488eSEric Joyner 	stats->bprc += bprc;
15968eb6488eSEric Joyner 	stats->mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
15978eb6488eSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB)
15988eb6488eSEric Joyner 		stats->mprc -= bprc;
15998eb6488eSEric Joyner 
16008eb6488eSEric Joyner 	stats->prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
16018eb6488eSEric Joyner 	stats->prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
16028eb6488eSEric Joyner 	stats->prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255);
16038eb6488eSEric Joyner 	stats->prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
16048eb6488eSEric Joyner 	stats->prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
16058eb6488eSEric Joyner 	stats->prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
16068eb6488eSEric Joyner 
16078eb6488eSEric Joyner 	lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC);
16088eb6488eSEric Joyner 	stats->lxontxc += lxon;
16098eb6488eSEric Joyner 	lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
16108eb6488eSEric Joyner 	stats->lxofftxc += lxoff;
16118eb6488eSEric Joyner 	total = lxon + lxoff;
16128eb6488eSEric Joyner 
16138eb6488eSEric Joyner 	stats->gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
16148eb6488eSEric Joyner 	stats->mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
16158eb6488eSEric Joyner 	stats->ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
16168eb6488eSEric Joyner 	stats->gptc -= total;
16178eb6488eSEric Joyner 	stats->mptc -= total;
16188eb6488eSEric Joyner 	stats->ptc64 -= total;
16198eb6488eSEric Joyner 	stats->gotc -= total * ETHER_MIN_LEN;
16208eb6488eSEric Joyner 
16218eb6488eSEric Joyner 	stats->ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
16228eb6488eSEric Joyner 	stats->rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
16238eb6488eSEric Joyner 	stats->roc += IXGBE_READ_REG(hw, IXGBE_ROC);
16248eb6488eSEric Joyner 	stats->rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
16258eb6488eSEric Joyner 	stats->mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC);
16268eb6488eSEric Joyner 	stats->mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC);
16278eb6488eSEric Joyner 	stats->mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC);
16288eb6488eSEric Joyner 	stats->tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
16298eb6488eSEric Joyner 	stats->tpt += IXGBE_READ_REG(hw, IXGBE_TPT);
16308eb6488eSEric Joyner 	stats->ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
16318eb6488eSEric Joyner 	stats->ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
16328eb6488eSEric Joyner 	stats->ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
16338eb6488eSEric Joyner 	stats->ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
16348eb6488eSEric Joyner 	stats->ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
16358eb6488eSEric Joyner 	stats->bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
16368eb6488eSEric Joyner 	stats->xec += IXGBE_READ_REG(hw, IXGBE_XEC);
16378eb6488eSEric Joyner 	stats->fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC);
16388eb6488eSEric Joyner 	stats->fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST);
16398eb6488eSEric Joyner 	/* Only read FCOE on 82599 */
16408eb6488eSEric Joyner 	if (hw->mac.type != ixgbe_mac_82598EB) {
16418eb6488eSEric Joyner 		stats->fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC);
16428eb6488eSEric Joyner 		stats->fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC);
16438eb6488eSEric Joyner 		stats->fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC);
16448eb6488eSEric Joyner 		stats->fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC);
16458eb6488eSEric Joyner 		stats->fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC);
16468eb6488eSEric Joyner 	}
16478eb6488eSEric Joyner 
16488eb6488eSEric Joyner 	/* Fill out the OS statistics structure */
1649b1d5caf3SKevin Bowling 	IXGBE_SET_IPACKETS(sc, stats->gprc);
1650b1d5caf3SKevin Bowling 	IXGBE_SET_OPACKETS(sc, stats->gptc);
1651b1d5caf3SKevin Bowling 	IXGBE_SET_IBYTES(sc, stats->gorc);
1652b1d5caf3SKevin Bowling 	IXGBE_SET_OBYTES(sc, stats->gotc);
1653b1d5caf3SKevin Bowling 	IXGBE_SET_IMCASTS(sc, stats->mprc);
1654b1d5caf3SKevin Bowling 	IXGBE_SET_OMCASTS(sc, stats->mptc);
1655b1d5caf3SKevin Bowling 	IXGBE_SET_COLLISIONS(sc, 0);
1656b1d5caf3SKevin Bowling 	IXGBE_SET_IQDROPS(sc, total_missed_rx);
1657afb1aa4eSPiotr Pietruszewski 
1658afb1aa4eSPiotr Pietruszewski 	/*
1659afb1aa4eSPiotr Pietruszewski 	 * Aggregate following types of errors as RX errors:
1660afb1aa4eSPiotr Pietruszewski 	 * - CRC error count,
1661afb1aa4eSPiotr Pietruszewski 	 * - illegal byte error count,
1662afb1aa4eSPiotr Pietruszewski 	 * - missed packets count,
1663afb1aa4eSPiotr Pietruszewski 	 * - length error count,
1664afb1aa4eSPiotr Pietruszewski 	 * - undersized packets count,
1665afb1aa4eSPiotr Pietruszewski 	 * - fragmented packets count,
1666afb1aa4eSPiotr Pietruszewski 	 * - oversized packets count,
1667afb1aa4eSPiotr Pietruszewski 	 * - jabber count.
1668afb1aa4eSPiotr Pietruszewski 	 */
16698526120aSAndrey V. Elsukov 	IXGBE_SET_IERRORS(sc, stats->crcerrs + stats->illerrc +
1670*c58d34ddSKevin Bowling 	    stats->mpc[0] + stats->rlec + stats->ruc + stats->rfc +
1671*c58d34ddSKevin Bowling 	    stats->roc + stats->rjc);
16728eb6488eSEric Joyner } /* ixgbe_update_stats_counters */
16738eb6488eSEric Joyner 
16748eb6488eSEric Joyner /************************************************************************
16758eb6488eSEric Joyner  * ixgbe_add_hw_stats
16768eb6488eSEric Joyner  *
16778eb6488eSEric Joyner  *   Add sysctl variables, one per statistic, to the system.
16788eb6488eSEric Joyner  ************************************************************************/
16798eb6488eSEric Joyner static void
1680b1d5caf3SKevin Bowling ixgbe_add_hw_stats(struct ixgbe_softc *sc)
16818eb6488eSEric Joyner {
1682b1d5caf3SKevin Bowling 	device_t dev = iflib_get_dev(sc->ctx);
1683c19c7afeSEric Joyner 	struct ix_rx_queue *rx_que;
1684c19c7afeSEric Joyner 	struct ix_tx_queue *tx_que;
16858eb6488eSEric Joyner 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
16868eb6488eSEric Joyner 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
16878eb6488eSEric Joyner 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
1688b1d5caf3SKevin Bowling 	struct ixgbe_hw_stats *stats = &sc->stats.pf;
16898eb6488eSEric Joyner 	struct sysctl_oid *stat_node, *queue_node;
16908eb6488eSEric Joyner 	struct sysctl_oid_list *stat_list, *queue_list;
1691c19c7afeSEric Joyner 	int i;
16928eb6488eSEric Joyner 
16938eb6488eSEric Joyner #define QUEUE_NAME_LEN 32
16948eb6488eSEric Joyner 	char namebuf[QUEUE_NAME_LEN];
16958eb6488eSEric Joyner 
16968eb6488eSEric Joyner 	/* Driver Statistics */
16978eb6488eSEric Joyner 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped",
1698b1d5caf3SKevin Bowling 	    CTLFLAG_RD, &sc->dropped_pkts, "Driver dropped packets");
16998eb6488eSEric Joyner 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
1700b1d5caf3SKevin Bowling 	    CTLFLAG_RD, &sc->watchdog_events, "Watchdog timeouts");
17018eb6488eSEric Joyner 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq",
1702b1d5caf3SKevin Bowling 	    CTLFLAG_RD, &sc->link_irq, "Link MSI-X IRQ Handled");
17038eb6488eSEric Joyner 
1704*c58d34ddSKevin Bowling 	for (i = 0, tx_que = sc->tx_queues; i < sc->num_tx_queues;
1705*c58d34ddSKevin Bowling 	    i++, tx_que++) {
1706c19c7afeSEric Joyner 		struct tx_ring *txr = &tx_que->txr;
17078eb6488eSEric Joyner 		snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i);
17088eb6488eSEric Joyner 		queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
170920b91f0aSPawel Biernacki 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
17108eb6488eSEric Joyner 		queue_list = SYSCTL_CHILDREN(queue_node);
17118eb6488eSEric Joyner 
17128eb6488eSEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head",
1713f72de14eSKevin Bowling 		    CTLTYPE_UINT | CTLFLAG_RD, txr, 0,
1714*c58d34ddSKevin Bowling 		    ixgbe_sysctl_tdh_handler, "IU",
1715*c58d34ddSKevin Bowling 		    "Transmit Descriptor Head");
17168eb6488eSEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail",
1717f72de14eSKevin Bowling 		    CTLTYPE_UINT | CTLFLAG_RD, txr, 0,
1718*c58d34ddSKevin Bowling 		    ixgbe_sysctl_tdt_handler, "IU",
1719*c58d34ddSKevin Bowling 		    "Transmit Descriptor Tail");
17208eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
17218eb6488eSEric Joyner 		    CTLFLAG_RD, &txr->tso_tx, "TSO");
17228eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
17238eb6488eSEric Joyner 		    CTLFLAG_RD, &txr->total_packets,
17248eb6488eSEric Joyner 		    "Queue Packets Transmitted");
17258eb6488eSEric Joyner 	}
17268eb6488eSEric Joyner 
1727*c58d34ddSKevin Bowling 	for (i = 0, rx_que = sc->rx_queues; i < sc->num_rx_queues;
1728*c58d34ddSKevin Bowling 	    i++, rx_que++) {
1729c19c7afeSEric Joyner 		struct rx_ring *rxr = &rx_que->rxr;
17308eb6488eSEric Joyner 		snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i);
17318eb6488eSEric Joyner 		queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
173220b91f0aSPawel Biernacki 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
17338eb6488eSEric Joyner 		queue_list = SYSCTL_CHILDREN(queue_node);
17348eb6488eSEric Joyner 
1735c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate",
1736f72de14eSKevin Bowling 		    CTLTYPE_UINT | CTLFLAG_RW,
1737b1d5caf3SKevin Bowling 		    &sc->rx_queues[i], 0,
1738c19c7afeSEric Joyner 		    ixgbe_sysctl_interrupt_rate_handler, "IU",
1739c19c7afeSEric Joyner 		    "Interrupt Rate");
1740c19c7afeSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
1741b1d5caf3SKevin Bowling 		    CTLFLAG_RD, &(sc->rx_queues[i].irqs),
1742c19c7afeSEric Joyner 		    "irqs on this queue");
17438eb6488eSEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head",
1744f72de14eSKevin Bowling 		    CTLTYPE_UINT | CTLFLAG_RD, rxr, 0,
1745*c58d34ddSKevin Bowling 		    ixgbe_sysctl_rdh_handler, "IU",
1746*c58d34ddSKevin Bowling 		    "Receive Descriptor Head");
17478eb6488eSEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail",
1748f72de14eSKevin Bowling 		    CTLTYPE_UINT | CTLFLAG_RD, rxr, 0,
1749*c58d34ddSKevin Bowling 		    ixgbe_sysctl_rdt_handler, "IU",
1750*c58d34ddSKevin Bowling 		    "Receive Descriptor Tail");
17518eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
17528eb6488eSEric Joyner 		    CTLFLAG_RD, &rxr->rx_packets, "Queue Packets Received");
17538eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
17548eb6488eSEric Joyner 		    CTLFLAG_RD, &rxr->rx_bytes, "Queue Bytes Received");
17558eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies",
17568eb6488eSEric Joyner 		    CTLFLAG_RD, &rxr->rx_copies, "Copied RX Frames");
17578eb6488eSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_discarded",
17588eb6488eSEric Joyner 		    CTLFLAG_RD, &rxr->rx_discarded, "Discarded RX packets");
17598eb6488eSEric Joyner 	}
17608eb6488eSEric Joyner 
17618eb6488eSEric Joyner 	/* MAC stats get their own sub node */
17628eb6488eSEric Joyner 	stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats",
176320b91f0aSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "MAC Statistics");
17648eb6488eSEric Joyner 	stat_list = SYSCTL_CHILDREN(stat_node);
17658eb6488eSEric Joyner 
1766afb1aa4eSPiotr Pietruszewski 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_errs",
1767b1d5caf3SKevin Bowling 	    CTLFLAG_RD, &sc->ierrors, IXGBE_SYSCTL_DESC_RX_ERRS);
17688eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs",
17698eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->crcerrs, "CRC Errors");
17708eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs",
17718eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->illerrc, "Illegal Byte Errors");
17728eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs",
17738eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->errbc, "Byte Errors");
17748eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards",
17758eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mspdc, "MAC Short Packets Discarded");
17768eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults",
17778eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mlfc, "MAC Local Faults");
17788eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults",
17798eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mrfc, "MAC Remote Faults");
17808eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs",
17818eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->rlec, "Receive Length Errors");
17828eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_missed_packets",
17838eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mpc[0], "RX Missed Packet Count");
17848eb6488eSEric Joyner 
17858eb6488eSEric Joyner 	/* Flow Control stats */
17868eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd",
17878eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->lxontxc, "Link XON Transmitted");
17888eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd",
17898eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->lxonrxc, "Link XON Received");
17908eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd",
17918eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->lxofftxc, "Link XOFF Transmitted");
17928eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd",
17938eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->lxoffrxc, "Link XOFF Received");
17948eb6488eSEric Joyner 
17958eb6488eSEric Joyner 	/* Packet Reception Stats */
17968eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd",
17978eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->tor, "Total Octets Received");
17988eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd",
17998eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->gorc, "Good Octets Received");
18008eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd",
18018eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->tpr, "Total Packets Received");
18028eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd",
18038eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->gprc, "Good Packets Received");
18048eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd",
18058eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mprc, "Multicast Packets Received");
18068eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd",
18078eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->bprc, "Broadcast Packets Received");
18088eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64",
18098eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc64, "64 byte frames received ");
18108eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127",
18118eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc127, "65-127 byte frames received");
18128eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255",
18138eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc255, "128-255 byte frames received");
18148eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511",
18158eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc511, "256-511 byte frames received");
18168eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023",
18178eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc1023, "512-1023 byte frames received");
18188eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522",
18198eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->prc1522, "1023-1522 byte frames received");
18208eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized",
18218eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ruc, "Receive Undersized");
18228eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented",
18238eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->rfc, "Fragmented Packets Received ");
18248eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized",
18258eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->roc, "Oversized Packets Received");
18268eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd",
18278eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->rjc, "Received Jabber");
18288eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd",
18298eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mngprc, "Management Packets Received");
18308eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd",
18318eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mngptc, "Management Packets Dropped");
18328eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs",
18338eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->xec, "Checksum Errors");
18348eb6488eSEric Joyner 
18358eb6488eSEric Joyner 	/* Packet Transmission Stats */
18368eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd",
18378eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->gotc, "Good Octets Transmitted");
18388eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd",
18398eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->tpt, "Total Packets Transmitted");
18408eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd",
18418eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->gptc, "Good Packets Transmitted");
18428eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd",
18438eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->bptc, "Broadcast Packets Transmitted");
18448eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd",
18458eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mptc, "Multicast Packets Transmitted");
18468eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd",
18478eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->mngptc, "Management Packets Transmitted");
18488eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64",
18498eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc64, "64 byte frames transmitted ");
18508eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127",
18518eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc127, "65-127 byte frames transmitted");
18528eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255",
18538eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc255, "128-255 byte frames transmitted");
18548eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511",
18558eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc511, "256-511 byte frames transmitted");
18568eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023",
18578eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc1023, "512-1023 byte frames transmitted");
18588eb6488eSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522",
18598eb6488eSEric Joyner 	    CTLFLAG_RD, &stats->ptc1522, "1024-1522 byte frames transmitted");
18608eb6488eSEric Joyner } /* ixgbe_add_hw_stats */
18618eb6488eSEric Joyner 
18628eb6488eSEric Joyner /************************************************************************
18638eb6488eSEric Joyner  * ixgbe_sysctl_tdh_handler - Transmit Descriptor Head handler function
18648eb6488eSEric Joyner  *
18658eb6488eSEric Joyner  *   Retrieves the TDH value from the hardware
18668eb6488eSEric Joyner  ************************************************************************/
1867758cc3dcSJack F Vogel static int
1868758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS)
1869758cc3dcSJack F Vogel {
1870758cc3dcSJack F Vogel 	struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1);
18718eb6488eSEric Joyner 	int error;
18728eb6488eSEric Joyner 	unsigned int val;
1873758cc3dcSJack F Vogel 
18748eb6488eSEric Joyner 	if (!txr)
18758eb6488eSEric Joyner 		return (0);
18768eb6488eSEric Joyner 
1877f72de14eSKevin Bowling 
1878f72de14eSKevin Bowling 	if (atomic_load_acq_int(&txr->sc->recovery_mode))
1879f72de14eSKevin Bowling 		return (EPERM);
1880f72de14eSKevin Bowling 
1881b1d5caf3SKevin Bowling 	val = IXGBE_READ_REG(&txr->sc->hw, IXGBE_TDH(txr->me));
1882758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
1883758cc3dcSJack F Vogel 	if (error || !req->newptr)
1884758cc3dcSJack F Vogel 		return error;
1885758cc3dcSJack F Vogel 
18868eb6488eSEric Joyner 	return (0);
18878eb6488eSEric Joyner } /* ixgbe_sysctl_tdh_handler */
18888eb6488eSEric Joyner 
18898eb6488eSEric Joyner /************************************************************************
18908eb6488eSEric Joyner  * ixgbe_sysctl_tdt_handler - Transmit Descriptor Tail handler function
18918eb6488eSEric Joyner  *
1892758cc3dcSJack F Vogel  *   Retrieves the TDT value from the hardware
18938eb6488eSEric Joyner  ************************************************************************/
1894758cc3dcSJack F Vogel static int
1895758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS)
1896758cc3dcSJack F Vogel {
1897758cc3dcSJack F Vogel 	struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1);
18988eb6488eSEric Joyner 	int error;
18998eb6488eSEric Joyner 	unsigned int val;
1900758cc3dcSJack F Vogel 
19018eb6488eSEric Joyner 	if (!txr)
19028eb6488eSEric Joyner 		return (0);
19038eb6488eSEric Joyner 
1904f72de14eSKevin Bowling 	if (atomic_load_acq_int(&txr->sc->recovery_mode))
1905f72de14eSKevin Bowling 		return (EPERM);
1906f72de14eSKevin Bowling 
1907b1d5caf3SKevin Bowling 	val = IXGBE_READ_REG(&txr->sc->hw, IXGBE_TDT(txr->me));
1908758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
1909758cc3dcSJack F Vogel 	if (error || !req->newptr)
1910758cc3dcSJack F Vogel 		return error;
1911758cc3dcSJack F Vogel 
19128eb6488eSEric Joyner 	return (0);
19138eb6488eSEric Joyner } /* ixgbe_sysctl_tdt_handler */
19148eb6488eSEric Joyner 
19158eb6488eSEric Joyner /************************************************************************
19168eb6488eSEric Joyner  * ixgbe_sysctl_rdh_handler - Receive Descriptor Head handler function
19178eb6488eSEric Joyner  *
1918758cc3dcSJack F Vogel  *   Retrieves the RDH value from the hardware
19198eb6488eSEric Joyner  ************************************************************************/
1920758cc3dcSJack F Vogel static int
1921758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS)
1922758cc3dcSJack F Vogel {
1923758cc3dcSJack F Vogel 	struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1);
19248eb6488eSEric Joyner 	int error;
19258eb6488eSEric Joyner 	unsigned int val;
1926758cc3dcSJack F Vogel 
19278eb6488eSEric Joyner 	if (!rxr)
19288eb6488eSEric Joyner 		return (0);
19298eb6488eSEric Joyner 
1930f72de14eSKevin Bowling 	if (atomic_load_acq_int(&rxr->sc->recovery_mode))
1931f72de14eSKevin Bowling 		return (EPERM);
1932f72de14eSKevin Bowling 
1933b1d5caf3SKevin Bowling 	val = IXGBE_READ_REG(&rxr->sc->hw, IXGBE_RDH(rxr->me));
1934758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
1935758cc3dcSJack F Vogel 	if (error || !req->newptr)
1936758cc3dcSJack F Vogel 		return error;
1937758cc3dcSJack F Vogel 
19388eb6488eSEric Joyner 	return (0);
19398eb6488eSEric Joyner } /* ixgbe_sysctl_rdh_handler */
19408eb6488eSEric Joyner 
19418eb6488eSEric Joyner /************************************************************************
19428eb6488eSEric Joyner  * ixgbe_sysctl_rdt_handler - Receive Descriptor Tail handler function
19438eb6488eSEric Joyner  *
1944758cc3dcSJack F Vogel  *   Retrieves the RDT value from the hardware
19458eb6488eSEric Joyner  ************************************************************************/
1946758cc3dcSJack F Vogel static int
1947758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS)
1948758cc3dcSJack F Vogel {
1949758cc3dcSJack F Vogel 	struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1);
19508eb6488eSEric Joyner 	int error;
19518eb6488eSEric Joyner 	unsigned int val;
1952758cc3dcSJack F Vogel 
19538eb6488eSEric Joyner 	if (!rxr)
19548eb6488eSEric Joyner 		return (0);
19558eb6488eSEric Joyner 
1956f72de14eSKevin Bowling 	if (atomic_load_acq_int(&rxr->sc->recovery_mode))
1957f72de14eSKevin Bowling 		return (EPERM);
1958f72de14eSKevin Bowling 
1959b1d5caf3SKevin Bowling 	val = IXGBE_READ_REG(&rxr->sc->hw, IXGBE_RDT(rxr->me));
1960758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
1961758cc3dcSJack F Vogel 	if (error || !req->newptr)
1962758cc3dcSJack F Vogel 		return error;
19638eb6488eSEric Joyner 
19648eb6488eSEric Joyner 	return (0);
19658eb6488eSEric Joyner } /* ixgbe_sysctl_rdt_handler */
19668eb6488eSEric Joyner 
19678eb6488eSEric Joyner /************************************************************************
1968c19c7afeSEric Joyner  * ixgbe_if_vlan_register
19698eb6488eSEric Joyner  *
19708eb6488eSEric Joyner  *   Run via vlan config EVENT, it enables us to use the
19718eb6488eSEric Joyner  *   HW Filter table since we can get the vlan id. This
19728eb6488eSEric Joyner  *   just creates the entry in the soft version of the
19738eb6488eSEric Joyner  *   VFTA, init will repopulate the real table.
19748eb6488eSEric Joyner  ************************************************************************/
19758eb6488eSEric Joyner static void
1976c19c7afeSEric Joyner ixgbe_if_vlan_register(if_ctx_t ctx, u16 vtag)
19778eb6488eSEric Joyner {
1978b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
19798eb6488eSEric Joyner 	u16 index, bit;
19808eb6488eSEric Joyner 
19818eb6488eSEric Joyner 	index = (vtag >> 5) & 0x7F;
19828eb6488eSEric Joyner 	bit = vtag & 0x1F;
1983b1d5caf3SKevin Bowling 	sc->shadow_vfta[index] |= (1 << bit);
1984b1d5caf3SKevin Bowling 	++sc->num_vlans;
1985c19c7afeSEric Joyner 	ixgbe_setup_vlan_hw_support(ctx);
1986c19c7afeSEric Joyner } /* ixgbe_if_vlan_register */
19878eb6488eSEric Joyner 
19888eb6488eSEric Joyner /************************************************************************
1989c19c7afeSEric Joyner  * ixgbe_if_vlan_unregister
19908eb6488eSEric Joyner  *
19918eb6488eSEric Joyner  *   Run via vlan unconfig EVENT, remove our entry in the soft vfta.
19928eb6488eSEric Joyner  ************************************************************************/
19938eb6488eSEric Joyner static void
1994c19c7afeSEric Joyner ixgbe_if_vlan_unregister(if_ctx_t ctx, u16 vtag)
19958eb6488eSEric Joyner {
1996b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
19978eb6488eSEric Joyner 	u16 index, bit;
19988eb6488eSEric Joyner 
19998eb6488eSEric Joyner 	index = (vtag >> 5) & 0x7F;
20008eb6488eSEric Joyner 	bit = vtag & 0x1F;
2001b1d5caf3SKevin Bowling 	sc->shadow_vfta[index] &= ~(1 << bit);
2002b1d5caf3SKevin Bowling 	--sc->num_vlans;
20038eb6488eSEric Joyner 	/* Re-init to load the changes */
2004c19c7afeSEric Joyner 	ixgbe_setup_vlan_hw_support(ctx);
2005c19c7afeSEric Joyner } /* ixgbe_if_vlan_unregister */
20068eb6488eSEric Joyner 
20078eb6488eSEric Joyner /************************************************************************
20088eb6488eSEric Joyner  * ixgbe_setup_vlan_hw_support
20098eb6488eSEric Joyner  ************************************************************************/
20108eb6488eSEric Joyner static void
2011c19c7afeSEric Joyner ixgbe_setup_vlan_hw_support(if_ctx_t ctx)
20128eb6488eSEric Joyner {
2013ff06a8dbSJustin Hibbits 	if_t ifp = iflib_get_ifp(ctx);
2014b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
2015b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
20168eb6488eSEric Joyner 	struct rx_ring *rxr;
20178eb6488eSEric Joyner 	int i;
20188eb6488eSEric Joyner 	u32 ctrl;
20198eb6488eSEric Joyner 
20208eb6488eSEric Joyner 
20218eb6488eSEric Joyner 	/*
20228eb6488eSEric Joyner 	 * We get here thru init_locked, meaning
20238eb6488eSEric Joyner 	 * a soft reset, this has already cleared
20248eb6488eSEric Joyner 	 * the VFTA and other state, so if there
20258eb6488eSEric Joyner 	 * have been no vlan's registered do nothing.
20268eb6488eSEric Joyner 	 */
2027*c58d34ddSKevin Bowling 	if (sc->num_vlans == 0 ||
2028*c58d34ddSKevin Bowling 	    (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) == 0) {
2029e7abb897SKristof Provost 		/* Clear the vlan hw flag */
2030e7abb897SKristof Provost 		for (i = 0; i < sc->num_rx_queues; i++) {
2031e7abb897SKristof Provost 			rxr = &sc->rx_queues[i].rxr;
2032e7abb897SKristof Provost 			/* On 82599 the VLAN enable is per/queue in RXDCTL */
2033e7abb897SKristof Provost 			if (hw->mac.type != ixgbe_mac_82598EB) {
2034*c58d34ddSKevin Bowling 				ctrl = IXGBE_READ_REG(hw,
2035*c58d34ddSKevin Bowling 				    IXGBE_RXDCTL(rxr->me));
2036e7abb897SKristof Provost 				ctrl &= ~IXGBE_RXDCTL_VME;
2037*c58d34ddSKevin Bowling 				IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me),
2038*c58d34ddSKevin Bowling 				    ctrl);
2039e7abb897SKristof Provost 			}
2040e7abb897SKristof Provost 			rxr->vtag_strip = false;
2041e7abb897SKristof Provost 		}
2042e7abb897SKristof Provost 		ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
2043e7abb897SKristof Provost 		/* Enable the Filter Table if enabled */
2044e7abb897SKristof Provost 		ctrl |= IXGBE_VLNCTRL_CFIEN;
2045e7abb897SKristof Provost 		ctrl &= ~IXGBE_VLNCTRL_VFE;
2046e7abb897SKristof Provost 		if (hw->mac.type == ixgbe_mac_82598EB)
2047e7abb897SKristof Provost 			ctrl &= ~IXGBE_VLNCTRL_VME;
2048e7abb897SKristof Provost 		IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl);
20498eb6488eSEric Joyner 		return;
2050e7abb897SKristof Provost 	}
20518eb6488eSEric Joyner 
20528eb6488eSEric Joyner 	/* Setup the queues for vlans */
2053ff06a8dbSJustin Hibbits 	if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) {
2054b1d5caf3SKevin Bowling 		for (i = 0; i < sc->num_rx_queues; i++) {
2055b1d5caf3SKevin Bowling 			rxr = &sc->rx_queues[i].rxr;
20568eb6488eSEric Joyner 			/* On 82599 the VLAN enable is per/queue in RXDCTL */
20578eb6488eSEric Joyner 			if (hw->mac.type != ixgbe_mac_82598EB) {
2058*c58d34ddSKevin Bowling 				ctrl = IXGBE_READ_REG(hw,
2059*c58d34ddSKevin Bowling 				    IXGBE_RXDCTL(rxr->me));
20608eb6488eSEric Joyner 				ctrl |= IXGBE_RXDCTL_VME;
2061*c58d34ddSKevin Bowling 				IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me),
2062*c58d34ddSKevin Bowling 				    ctrl);
20638eb6488eSEric Joyner 			}
206479b36ec9SKevin Bowling 			rxr->vtag_strip = true;
2065758cc3dcSJack F Vogel 		}
20669c92bb71SSean Bruno 	}
2067758cc3dcSJack F Vogel 
2068ff06a8dbSJustin Hibbits 	if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0)
20698eb6488eSEric Joyner 		return;
20708eb6488eSEric Joyner 	/*
20718eb6488eSEric Joyner 	 * A soft reset zero's out the VFTA, so
20728eb6488eSEric Joyner 	 * we need to repopulate it now.
20738eb6488eSEric Joyner 	 */
20748eb6488eSEric Joyner 	for (i = 0; i < IXGBE_VFTA_SIZE; i++)
2075b1d5caf3SKevin Bowling 		if (sc->shadow_vfta[i] != 0)
20768eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_VFTA(i),
2077b1d5caf3SKevin Bowling 			    sc->shadow_vfta[i]);
20788eb6488eSEric Joyner 
20798eb6488eSEric Joyner 	ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
20808eb6488eSEric Joyner 	/* Enable the Filter Table if enabled */
2081ff06a8dbSJustin Hibbits 	if (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) {
20828eb6488eSEric Joyner 		ctrl &= ~IXGBE_VLNCTRL_CFIEN;
20838eb6488eSEric Joyner 		ctrl |= IXGBE_VLNCTRL_VFE;
20848eb6488eSEric Joyner 	}
20858eb6488eSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB)
20868eb6488eSEric Joyner 		ctrl |= IXGBE_VLNCTRL_VME;
20878eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl);
20888eb6488eSEric Joyner } /* ixgbe_setup_vlan_hw_support */
20898eb6488eSEric Joyner 
20908eb6488eSEric Joyner /************************************************************************
20918eb6488eSEric Joyner  * ixgbe_get_slot_info
20928eb6488eSEric Joyner  *
20938eb6488eSEric Joyner  *   Get the width and transaction speed of
20948eb6488eSEric Joyner  *   the slot this adapter is plugged into.
20958eb6488eSEric Joyner  ************************************************************************/
20968eb6488eSEric Joyner static void
2097b1d5caf3SKevin Bowling ixgbe_get_slot_info(struct ixgbe_softc *sc)
20988eb6488eSEric Joyner {
2099b1d5caf3SKevin Bowling 	device_t dev = iflib_get_dev(sc->ctx);
2100b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
210179b36ec9SKevin Bowling 	int bus_info_valid = true;
21028eb6488eSEric Joyner 	u32 offset;
21038eb6488eSEric Joyner 	u16 link;
21048eb6488eSEric Joyner 
21058eb6488eSEric Joyner 	/* Some devices are behind an internal bridge */
21068eb6488eSEric Joyner 	switch (hw->device_id) {
21078eb6488eSEric Joyner 	case IXGBE_DEV_ID_82599_SFP_SF_QP:
21088eb6488eSEric Joyner 	case IXGBE_DEV_ID_82599_QSFP_SF_QP:
21098eb6488eSEric Joyner 		goto get_parent_info;
21108eb6488eSEric Joyner 	default:
21118eb6488eSEric Joyner 		break;
21128eb6488eSEric Joyner 	}
21138eb6488eSEric Joyner 
21148eb6488eSEric Joyner 	ixgbe_get_bus_info(hw);
21158eb6488eSEric Joyner 
21168eb6488eSEric Joyner 	/*
21178eb6488eSEric Joyner 	 * Some devices don't use PCI-E, but there is no need
21188eb6488eSEric Joyner 	 * to display "Unknown" for bus speed and width.
21198eb6488eSEric Joyner 	 */
21208eb6488eSEric Joyner 	switch (hw->mac.type) {
21218eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
21228eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
21238eb6488eSEric Joyner 		return;
21248eb6488eSEric Joyner 	default:
21258eb6488eSEric Joyner 		goto display;
21268eb6488eSEric Joyner 	}
21278eb6488eSEric Joyner 
21288eb6488eSEric Joyner get_parent_info:
21298eb6488eSEric Joyner 	/*
21308eb6488eSEric Joyner 	 * For the Quad port adapter we need to parse back
21318eb6488eSEric Joyner 	 * up the PCI tree to find the speed of the expansion
21328eb6488eSEric Joyner 	 * slot into which this adapter is plugged. A bit more work.
21338eb6488eSEric Joyner 	 */
21348eb6488eSEric Joyner 	dev = device_get_parent(device_get_parent(dev));
21358eb6488eSEric Joyner #ifdef IXGBE_DEBUG
21368eb6488eSEric Joyner 	device_printf(dev, "parent pcib = %x,%x,%x\n", pci_get_bus(dev),
21378eb6488eSEric Joyner 	    pci_get_slot(dev), pci_get_function(dev));
21388eb6488eSEric Joyner #endif
21398eb6488eSEric Joyner 	dev = device_get_parent(device_get_parent(dev));
21408eb6488eSEric Joyner #ifdef IXGBE_DEBUG
21418eb6488eSEric Joyner 	device_printf(dev, "slot pcib = %x,%x,%x\n", pci_get_bus(dev),
21428eb6488eSEric Joyner 	    pci_get_slot(dev), pci_get_function(dev));
21438eb6488eSEric Joyner #endif
21448eb6488eSEric Joyner 	/* Now get the PCI Express Capabilities offset */
21458eb6488eSEric Joyner 	if (pci_find_cap(dev, PCIY_EXPRESS, &offset)) {
21468eb6488eSEric Joyner 		/*
21478eb6488eSEric Joyner 		 * Hmm...can't get PCI-Express capabilities.
21488eb6488eSEric Joyner 		 * Falling back to default method.
21498eb6488eSEric Joyner 		 */
215079b36ec9SKevin Bowling 		bus_info_valid = false;
21518eb6488eSEric Joyner 		ixgbe_get_bus_info(hw);
21528eb6488eSEric Joyner 		goto display;
21538eb6488eSEric Joyner 	}
21548eb6488eSEric Joyner 	/* ...and read the Link Status Register */
21558eb6488eSEric Joyner 	link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
21568eb6488eSEric Joyner 	ixgbe_set_pci_config_data_generic(hw, link);
21578eb6488eSEric Joyner 
21588eb6488eSEric Joyner display:
21598eb6488eSEric Joyner 	device_printf(dev, "PCI Express Bus: Speed %s %s\n",
21608eb6488eSEric Joyner 	    ((hw->bus.speed == ixgbe_bus_speed_8000)    ? "8.0GT/s"  :
21618eb6488eSEric Joyner 	     (hw->bus.speed == ixgbe_bus_speed_5000)    ? "5.0GT/s"  :
21628eb6488eSEric Joyner 	     (hw->bus.speed == ixgbe_bus_speed_2500)    ? "2.5GT/s"  :
21638eb6488eSEric Joyner 	     "Unknown"),
21648eb6488eSEric Joyner 	    ((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
21658eb6488eSEric Joyner 	     (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" :
21668eb6488eSEric Joyner 	     (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" :
21678eb6488eSEric Joyner 	     "Unknown"));
21688eb6488eSEric Joyner 
21698eb6488eSEric Joyner 	if (bus_info_valid) {
21708eb6488eSEric Joyner 		if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) &&
21718eb6488eSEric Joyner 		    ((hw->bus.width <= ixgbe_bus_width_pcie_x4) &&
21728eb6488eSEric Joyner 		    (hw->bus.speed == ixgbe_bus_speed_2500))) {
2173*c58d34ddSKevin Bowling 			device_printf(dev,
2174*c58d34ddSKevin Bowling 			    "PCI-Express bandwidth available for this card"
2175*c58d34ddSKevin Bowling 			    " is not sufficient for optimal performance.\n");
2176*c58d34ddSKevin Bowling 			device_printf(dev,
2177*c58d34ddSKevin Bowling 			    "For optimal performance a x8 PCIE, or x4 PCIE"
2178*c58d34ddSKevin Bowling 			    " Gen2 slot is required.\n");
21798eb6488eSEric Joyner 		}
21808eb6488eSEric Joyner 		if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) &&
21818eb6488eSEric Joyner 		    ((hw->bus.width <= ixgbe_bus_width_pcie_x8) &&
21828eb6488eSEric Joyner 		    (hw->bus.speed < ixgbe_bus_speed_8000))) {
2183*c58d34ddSKevin Bowling 			device_printf(dev,
2184*c58d34ddSKevin Bowling 			    "PCI-Express bandwidth available for this card"
2185*c58d34ddSKevin Bowling 			    " is not sufficient for optimal performance.\n");
2186*c58d34ddSKevin Bowling 			device_printf(dev,
2187*c58d34ddSKevin Bowling 			    "For optimal performance a x8 PCIE Gen3 slot is"
2188*c58d34ddSKevin Bowling 			    " required.\n");
21898eb6488eSEric Joyner 		}
21908eb6488eSEric Joyner 	} else
2191*c58d34ddSKevin Bowling 		device_printf(dev,
2192*c58d34ddSKevin Bowling 		    "Unable to determine slot speed/width. The speed/width"
2193*c58d34ddSKevin Bowling 		    " reported are that of the internal switch.\n");
21948eb6488eSEric Joyner 
21958eb6488eSEric Joyner 	return;
21968eb6488eSEric Joyner } /* ixgbe_get_slot_info */
21978eb6488eSEric Joyner 
21988eb6488eSEric Joyner /************************************************************************
2199c19c7afeSEric Joyner  * ixgbe_if_msix_intr_assign
2200c19c7afeSEric Joyner  *
2201c19c7afeSEric Joyner  *   Setup MSI-X Interrupt resources and handlers
22028eb6488eSEric Joyner  ************************************************************************/
2203c19c7afeSEric Joyner static int
2204c19c7afeSEric Joyner ixgbe_if_msix_intr_assign(if_ctx_t ctx, int msix)
22058eb6488eSEric Joyner {
2206b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
2207b1d5caf3SKevin Bowling 	struct ix_rx_queue *rx_que = sc->rx_queues;
2208c19c7afeSEric Joyner 	struct ix_tx_queue *tx_que;
2209c19c7afeSEric Joyner 	int error, rid, vector = 0;
2210c19c7afeSEric Joyner 	char buf[16];
22118eb6488eSEric Joyner 
2212c19c7afeSEric Joyner 	/* Admin Que is vector 0*/
2213c19c7afeSEric Joyner 	rid = vector + 1;
2214b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++, vector++, rx_que++) {
2215c19c7afeSEric Joyner 		rid = vector + 1;
2216c19c7afeSEric Joyner 
2217c19c7afeSEric Joyner 		snprintf(buf, sizeof(buf), "rxq%d", i);
2218c19c7afeSEric Joyner 		error = iflib_irq_alloc_generic(ctx, &rx_que->que_irq, rid,
2219*c58d34ddSKevin Bowling 		    IFLIB_INTR_RXTX, ixgbe_msix_que, rx_que, rx_que->rxr.me,
2220*c58d34ddSKevin Bowling 		    buf);
2221c19c7afeSEric Joyner 
2222c19c7afeSEric Joyner 		if (error) {
2223c19c7afeSEric Joyner 			device_printf(iflib_get_dev(ctx),
2224*c58d34ddSKevin Bowling 			    "Failed to allocate que int %d err: %d",
2225*c58d34ddSKevin Bowling 			    i,error);
2226b1d5caf3SKevin Bowling 			sc->num_rx_queues = i + 1;
2227c19c7afeSEric Joyner 			goto fail;
22288eb6488eSEric Joyner 		}
22298eb6488eSEric Joyner 
2230c19c7afeSEric Joyner 		rx_que->msix = vector;
2231c19c7afeSEric Joyner 	}
2232b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_tx_queues; i++) {
2233c19c7afeSEric Joyner 		snprintf(buf, sizeof(buf), "txq%d", i);
2234b1d5caf3SKevin Bowling 		tx_que = &sc->tx_queues[i];
2235b1d5caf3SKevin Bowling 		tx_que->msix = i % sc->num_rx_queues;
2236c19c7afeSEric Joyner 		iflib_softirq_alloc_generic(ctx,
2237b1d5caf3SKevin Bowling 		    &sc->rx_queues[tx_que->msix].que_irq,
2238c19c7afeSEric Joyner 		    IFLIB_INTR_TX, tx_que, tx_que->txr.me, buf);
2239c19c7afeSEric Joyner 	}
2240c19c7afeSEric Joyner 	rid = vector + 1;
2241b1d5caf3SKevin Bowling 	error = iflib_irq_alloc_generic(ctx, &sc->irq, rid,
2242b1d5caf3SKevin Bowling 	    IFLIB_INTR_ADMIN, ixgbe_msix_link, sc, 0, "aq");
2243c19c7afeSEric Joyner 	if (error) {
2244c19c7afeSEric Joyner 		device_printf(iflib_get_dev(ctx),
2245c19c7afeSEric Joyner 		    "Failed to register admin handler");
2246c19c7afeSEric Joyner 		return (error);
2247c19c7afeSEric Joyner 	}
2248c19c7afeSEric Joyner 
2249b1d5caf3SKevin Bowling 	sc->vector = vector;
2250c19c7afeSEric Joyner 
2251c19c7afeSEric Joyner 	return (0);
2252c19c7afeSEric Joyner fail:
2253b1d5caf3SKevin Bowling 	iflib_irq_free(ctx, &sc->irq);
2254b1d5caf3SKevin Bowling 	rx_que = sc->rx_queues;
2255b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++, rx_que++)
2256c19c7afeSEric Joyner 		iflib_irq_free(ctx, &rx_que->que_irq);
2257c19c7afeSEric Joyner 
2258c19c7afeSEric Joyner 	return (error);
2259c19c7afeSEric Joyner } /* ixgbe_if_msix_intr_assign */
2260c19c7afeSEric Joyner 
226164881da4SSai Rajesh Tallamraju static inline void
2262b1d5caf3SKevin Bowling ixgbe_perform_aim(struct ixgbe_softc *sc, struct ix_rx_queue *que)
226364881da4SSai Rajesh Tallamraju {
226464881da4SSai Rajesh Tallamraju 	uint32_t newitr = 0;
226564881da4SSai Rajesh Tallamraju 	struct rx_ring *rxr = &que->rxr;
2266f72de14eSKevin Bowling 	/* FIXME struct tx_ring *txr = ... ->txr; */
226764881da4SSai Rajesh Tallamraju 
226864881da4SSai Rajesh Tallamraju 	/*
226964881da4SSai Rajesh Tallamraju 	 * Do Adaptive Interrupt Moderation:
227064881da4SSai Rajesh Tallamraju 	 *  - Write out last calculated setting
227164881da4SSai Rajesh Tallamraju 	 *  - Calculate based on average size over
227264881da4SSai Rajesh Tallamraju 	 *    the last interval.
227364881da4SSai Rajesh Tallamraju 	 */
227464881da4SSai Rajesh Tallamraju 	if (que->eitr_setting) {
2275b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(que->msix),
227664881da4SSai Rajesh Tallamraju 		    que->eitr_setting);
227764881da4SSai Rajesh Tallamraju 	}
227864881da4SSai Rajesh Tallamraju 
227964881da4SSai Rajesh Tallamraju 	que->eitr_setting = 0;
228064881da4SSai Rajesh Tallamraju 	/* Idle, do nothing */
228164881da4SSai Rajesh Tallamraju 	if (rxr->bytes == 0) {
2282f72de14eSKevin Bowling 		/* FIXME && txr->bytes == 0 */
228364881da4SSai Rajesh Tallamraju 		return;
228464881da4SSai Rajesh Tallamraju 	}
228564881da4SSai Rajesh Tallamraju 
2286f72de14eSKevin Bowling 	if ((rxr->bytes) && (rxr->packets))
2287f72de14eSKevin Bowling 		newitr = rxr->bytes / rxr->packets;
2288f72de14eSKevin Bowling 	/* FIXME for transmit accounting
2289f72de14eSKevin Bowling 	 * if ((txr->bytes) && (txr->packets))
2290f72de14eSKevin Bowling 	 * 	newitr = txr->bytes/txr->packets;
2291f72de14eSKevin Bowling 	 * if ((rxr->bytes) && (rxr->packets))
2292f72de14eSKevin Bowling 	 * 	newitr = max(newitr, (rxr->bytes / rxr->packets));
2293f72de14eSKevin Bowling 	 */
229464881da4SSai Rajesh Tallamraju 
229564881da4SSai Rajesh Tallamraju 	newitr += 24; /* account for hardware frame, crc */
229664881da4SSai Rajesh Tallamraju 	/* set an upper boundary */
229764881da4SSai Rajesh Tallamraju 	newitr = min(newitr, 3000);
229864881da4SSai Rajesh Tallamraju 
229964881da4SSai Rajesh Tallamraju 	/* Be nice to the mid range */
230064881da4SSai Rajesh Tallamraju 	if ((newitr > 300) && (newitr < 1200)) {
230164881da4SSai Rajesh Tallamraju 		newitr = (newitr / 3);
230264881da4SSai Rajesh Tallamraju 	} else {
230364881da4SSai Rajesh Tallamraju 		newitr = (newitr / 2);
230464881da4SSai Rajesh Tallamraju 	}
230564881da4SSai Rajesh Tallamraju 
2306b1d5caf3SKevin Bowling 	if (sc->hw.mac.type == ixgbe_mac_82598EB) {
230764881da4SSai Rajesh Tallamraju 		newitr |= newitr << 16;
230864881da4SSai Rajesh Tallamraju 	} else {
230964881da4SSai Rajesh Tallamraju 		newitr |= IXGBE_EITR_CNT_WDIS;
231064881da4SSai Rajesh Tallamraju 	}
231164881da4SSai Rajesh Tallamraju 
231264881da4SSai Rajesh Tallamraju 	/* save for next interrupt */
231364881da4SSai Rajesh Tallamraju 	que->eitr_setting = newitr;
231464881da4SSai Rajesh Tallamraju 
231564881da4SSai Rajesh Tallamraju 	/* Reset state */
2316f72de14eSKevin Bowling 	/* FIXME txr->bytes = 0; */
2317f72de14eSKevin Bowling 	/* FIXME txr->packets = 0; */
231864881da4SSai Rajesh Tallamraju 	rxr->bytes = 0;
231964881da4SSai Rajesh Tallamraju 	rxr->packets = 0;
232064881da4SSai Rajesh Tallamraju 
232164881da4SSai Rajesh Tallamraju 	return;
232264881da4SSai Rajesh Tallamraju }
232364881da4SSai Rajesh Tallamraju 
2324c19c7afeSEric Joyner /*********************************************************************
23258eb6488eSEric Joyner  * ixgbe_msix_que - MSI-X Queue Interrupt Service routine
2326c19c7afeSEric Joyner  **********************************************************************/
2327c19c7afeSEric Joyner static int
23288eb6488eSEric Joyner ixgbe_msix_que(void *arg)
23298eb6488eSEric Joyner {
2330c19c7afeSEric Joyner 	struct ix_rx_queue *que = arg;
2331b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = que->sc;
2332ff06a8dbSJustin Hibbits 	if_t ifp = iflib_get_ifp(que->sc->ctx);
23338eb6488eSEric Joyner 
23348eb6488eSEric Joyner 	/* Protect against spurious interrupts */
2335ff06a8dbSJustin Hibbits 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
23366c351041SEric Joyner 		return (FILTER_HANDLED);
23378eb6488eSEric Joyner 
2338b1d5caf3SKevin Bowling 	ixgbe_disable_queue(sc, que->msix);
23398eb6488eSEric Joyner 	++que->irqs;
23408eb6488eSEric Joyner 
234164881da4SSai Rajesh Tallamraju 	/* Check for AIM */
2342b1d5caf3SKevin Bowling 	if (sc->enable_aim) {
2343b1d5caf3SKevin Bowling 		ixgbe_perform_aim(sc, que);
234464881da4SSai Rajesh Tallamraju 	}
234564881da4SSai Rajesh Tallamraju 
2346c19c7afeSEric Joyner 	return (FILTER_SCHEDULE_THREAD);
23478eb6488eSEric Joyner } /* ixgbe_msix_que */
23488eb6488eSEric Joyner 
23498eb6488eSEric Joyner /************************************************************************
23508eb6488eSEric Joyner  * ixgbe_media_status - Media Ioctl callback
23518eb6488eSEric Joyner  *
23528eb6488eSEric Joyner  *   Called whenever the user queries the status of
23538eb6488eSEric Joyner  *   the interface using ifconfig.
23548eb6488eSEric Joyner  ************************************************************************/
23558eb6488eSEric Joyner static void
2356c19c7afeSEric Joyner ixgbe_if_media_status(if_ctx_t ctx, struct ifmediareq * ifmr)
23578eb6488eSEric Joyner {
2358b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
2359b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
23608eb6488eSEric Joyner 	int layer;
23618eb6488eSEric Joyner 
2362c19c7afeSEric Joyner 	INIT_DEBUGOUT("ixgbe_if_media_status: begin");
2363c19c7afeSEric Joyner 
23648eb6488eSEric Joyner 	ifmr->ifm_status = IFM_AVALID;
23658eb6488eSEric Joyner 	ifmr->ifm_active = IFM_ETHER;
23668eb6488eSEric Joyner 
2367b1d5caf3SKevin Bowling 	if (!sc->link_active)
23688eb6488eSEric Joyner 		return;
23698eb6488eSEric Joyner 
23708eb6488eSEric Joyner 	ifmr->ifm_status |= IFM_ACTIVE;
2371b1d5caf3SKevin Bowling 	layer = sc->phy_layer;
23728eb6488eSEric Joyner 
23738eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T ||
23748eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_T ||
23758eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_100BASE_TX ||
23768eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_10BASE_T)
2377b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
23788eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
23798eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
23808eb6488eSEric Joyner 			break;
23818eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
23828eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_T | IFM_FDX;
23838eb6488eSEric Joyner 			break;
23848eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_100_FULL:
23858eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
23868eb6488eSEric Joyner 			break;
23878eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10_FULL:
23888eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10_T | IFM_FDX;
23898eb6488eSEric Joyner 			break;
23908eb6488eSEric Joyner 		}
2391d381c807SPiotr Pietruszewski 	if (hw->mac.type == ixgbe_mac_X550)
2392d381c807SPiotr Pietruszewski 		switch (sc->link_speed) {
2393d381c807SPiotr Pietruszewski 		case IXGBE_LINK_SPEED_5GB_FULL:
2394d381c807SPiotr Pietruszewski 			ifmr->ifm_active |= IFM_5000_T | IFM_FDX;
2395d381c807SPiotr Pietruszewski 			break;
2396d381c807SPiotr Pietruszewski 		case IXGBE_LINK_SPEED_2_5GB_FULL:
2397d381c807SPiotr Pietruszewski 			ifmr->ifm_active |= IFM_2500_T | IFM_FDX;
2398d381c807SPiotr Pietruszewski 			break;
2399d381c807SPiotr Pietruszewski 		}
24008eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU ||
24018eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA)
2402b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
24038eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
24048eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_TWINAX | IFM_FDX;
24058eb6488eSEric Joyner 			break;
240648ddd1b9SKevin Bowling 		case IXGBE_LINK_SPEED_1GB_FULL:
240748ddd1b9SKevin Bowling 			ifmr->ifm_active |= IFM_1000_KX | IFM_FDX;
240848ddd1b9SKevin Bowling 			break;
24098eb6488eSEric Joyner 		}
24108eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR)
2411b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
24128eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
24138eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_LR | IFM_FDX;
24148eb6488eSEric Joyner 			break;
24158eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
24168eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_LX | IFM_FDX;
24178eb6488eSEric Joyner 			break;
24188eb6488eSEric Joyner 		}
24198eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM)
2420b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
24218eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
24228eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_LRM | IFM_FDX;
24238eb6488eSEric Joyner 			break;
24248eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
24258eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_LX | IFM_FDX;
24268eb6488eSEric Joyner 			break;
24278eb6488eSEric Joyner 		}
24288eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR ||
24298eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX)
2430b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
24318eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
24328eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
24338eb6488eSEric Joyner 			break;
24348eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
24358eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_SX | IFM_FDX;
24368eb6488eSEric Joyner 			break;
24378eb6488eSEric Joyner 		}
24388eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4)
2439b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
24408eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
24418eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX;
24428eb6488eSEric Joyner 			break;
24438eb6488eSEric Joyner 		}
24448eb6488eSEric Joyner 	/*
24458eb6488eSEric Joyner 	 * XXX: These need to use the proper media types once
24468eb6488eSEric Joyner 	 * they're added.
24478eb6488eSEric Joyner 	 */
24488eb6488eSEric Joyner #ifndef IFM_ETH_XTYPE
24498eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR)
2450b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
24518eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
24528eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
24538eb6488eSEric Joyner 			break;
24548eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
24558eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_2500_SX | IFM_FDX;
24568eb6488eSEric Joyner 			break;
24578eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
24588eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_CX | IFM_FDX;
24598eb6488eSEric Joyner 			break;
24608eb6488eSEric Joyner 		}
24618eb6488eSEric Joyner 	else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 ||
24628eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX ||
24638eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX)
2464b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
24658eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
24668eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX;
24678eb6488eSEric Joyner 			break;
24688eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
24698eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_2500_SX | IFM_FDX;
24708eb6488eSEric Joyner 			break;
24718eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
24728eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_CX | IFM_FDX;
24738eb6488eSEric Joyner 			break;
24748eb6488eSEric Joyner 		}
24758eb6488eSEric Joyner #else
24768eb6488eSEric Joyner 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR)
2477b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
24788eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
24798eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_KR | IFM_FDX;
24808eb6488eSEric Joyner 			break;
24818eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
24828eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_2500_KX | IFM_FDX;
24838eb6488eSEric Joyner 			break;
24848eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
24858eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_KX | IFM_FDX;
24868eb6488eSEric Joyner 			break;
24878eb6488eSEric Joyner 		}
24888eb6488eSEric Joyner 	else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 ||
24898eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX ||
24908eb6488eSEric Joyner 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX)
2491b1d5caf3SKevin Bowling 		switch (sc->link_speed) {
24928eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_10GB_FULL:
24938eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_10G_KX4 | IFM_FDX;
24948eb6488eSEric Joyner 			break;
24958eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
24968eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_2500_KX | IFM_FDX;
24978eb6488eSEric Joyner 			break;
24988eb6488eSEric Joyner 		case IXGBE_LINK_SPEED_1GB_FULL:
24998eb6488eSEric Joyner 			ifmr->ifm_active |= IFM_1000_KX | IFM_FDX;
25008eb6488eSEric Joyner 			break;
25018eb6488eSEric Joyner 		}
25028eb6488eSEric Joyner #endif
25038eb6488eSEric Joyner 
25048eb6488eSEric Joyner 	/* If nothing is recognized... */
25058eb6488eSEric Joyner 	if (IFM_SUBTYPE(ifmr->ifm_active) == 0)
25068eb6488eSEric Joyner 		ifmr->ifm_active |= IFM_UNKNOWN;
25078eb6488eSEric Joyner 
25088eb6488eSEric Joyner 	/* Display current flow control setting used on link */
25098eb6488eSEric Joyner 	if (hw->fc.current_mode == ixgbe_fc_rx_pause ||
25108eb6488eSEric Joyner 	    hw->fc.current_mode == ixgbe_fc_full)
25118eb6488eSEric Joyner 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
25128eb6488eSEric Joyner 	if (hw->fc.current_mode == ixgbe_fc_tx_pause ||
25138eb6488eSEric Joyner 	    hw->fc.current_mode == ixgbe_fc_full)
25148eb6488eSEric Joyner 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
25158eb6488eSEric Joyner } /* ixgbe_media_status */
25168eb6488eSEric Joyner 
25178eb6488eSEric Joyner /************************************************************************
25188eb6488eSEric Joyner  * ixgbe_media_change - Media Ioctl callback
25198eb6488eSEric Joyner  *
25208eb6488eSEric Joyner  *   Called when the user changes speed/duplex using
25218eb6488eSEric Joyner  *   media/mediopt option with ifconfig.
25228eb6488eSEric Joyner  ************************************************************************/
25238eb6488eSEric Joyner static int
2524c19c7afeSEric Joyner ixgbe_if_media_change(if_ctx_t ctx)
25258eb6488eSEric Joyner {
2526b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
2527c19c7afeSEric Joyner 	struct ifmedia *ifm = iflib_get_media(ctx);
2528b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
25298eb6488eSEric Joyner 	ixgbe_link_speed speed = 0;
25308eb6488eSEric Joyner 
2531c19c7afeSEric Joyner 	INIT_DEBUGOUT("ixgbe_if_media_change: begin");
25328eb6488eSEric Joyner 
25338eb6488eSEric Joyner 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
25348eb6488eSEric Joyner 		return (EINVAL);
25358eb6488eSEric Joyner 
25368eb6488eSEric Joyner 	if (hw->phy.media_type == ixgbe_media_type_backplane)
2537c19c7afeSEric Joyner 		return (EPERM);
25388eb6488eSEric Joyner 
25398eb6488eSEric Joyner 	/*
25408eb6488eSEric Joyner 	 * We don't actually need to check against the supported
25418eb6488eSEric Joyner 	 * media types of the adapter; ifmedia will take care of
25428eb6488eSEric Joyner 	 * that for us.
25438eb6488eSEric Joyner 	 */
25448eb6488eSEric Joyner 	switch (IFM_SUBTYPE(ifm->ifm_media)) {
25458eb6488eSEric Joyner 	case IFM_AUTO:
25468eb6488eSEric Joyner 	case IFM_10G_T:
25478eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_100_FULL;
25488eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
25498eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_10GB_FULL;
25508eb6488eSEric Joyner 		break;
25518eb6488eSEric Joyner 	case IFM_10G_LRM:
25528eb6488eSEric Joyner 	case IFM_10G_LR:
25538eb6488eSEric Joyner #ifndef IFM_ETH_XTYPE
25548eb6488eSEric Joyner 	case IFM_10G_SR: /* KR, too */
25558eb6488eSEric Joyner 	case IFM_10G_CX4: /* KX4 */
25568eb6488eSEric Joyner #else
25578eb6488eSEric Joyner 	case IFM_10G_KR:
25588eb6488eSEric Joyner 	case IFM_10G_KX4:
25598eb6488eSEric Joyner #endif
25608eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
25618eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_10GB_FULL;
25628eb6488eSEric Joyner 		break;
25638eb6488eSEric Joyner #ifndef IFM_ETH_XTYPE
25648eb6488eSEric Joyner 	case IFM_1000_CX: /* KX */
25658eb6488eSEric Joyner #else
25668eb6488eSEric Joyner 	case IFM_1000_KX:
25678eb6488eSEric Joyner #endif
25688eb6488eSEric Joyner 	case IFM_1000_LX:
25698eb6488eSEric Joyner 	case IFM_1000_SX:
25708eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
25718eb6488eSEric Joyner 		break;
25728eb6488eSEric Joyner 	case IFM_1000_T:
25738eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_100_FULL;
25748eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
25758eb6488eSEric Joyner 		break;
25768eb6488eSEric Joyner 	case IFM_10G_TWINAX:
25778eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_10GB_FULL;
25788eb6488eSEric Joyner 		break;
2579d381c807SPiotr Pietruszewski 	case IFM_5000_T:
2580d381c807SPiotr Pietruszewski 		speed |= IXGBE_LINK_SPEED_5GB_FULL;
2581d381c807SPiotr Pietruszewski 		break;
2582d381c807SPiotr Pietruszewski 	case IFM_2500_T:
2583d381c807SPiotr Pietruszewski 		speed |= IXGBE_LINK_SPEED_2_5GB_FULL;
2584d381c807SPiotr Pietruszewski 		break;
25858eb6488eSEric Joyner 	case IFM_100_TX:
25868eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_100_FULL;
25878eb6488eSEric Joyner 		break;
25888eb6488eSEric Joyner 	case IFM_10_T:
25898eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_10_FULL;
25908eb6488eSEric Joyner 		break;
25918eb6488eSEric Joyner 	default:
25928eb6488eSEric Joyner 		goto invalid;
25938eb6488eSEric Joyner 	}
25948eb6488eSEric Joyner 
259579b36ec9SKevin Bowling 	hw->mac.autotry_restart = true;
259679b36ec9SKevin Bowling 	hw->mac.ops.setup_link(hw, speed, true);
2597b1d5caf3SKevin Bowling 	sc->advertise =
2598d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_10GB_FULL)  ? 0x4  : 0) |
2599d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_5GB_FULL)   ? 0x20 : 0) |
2600d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_2_5GB_FULL) ? 0x10 : 0) |
2601d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_1GB_FULL)   ? 0x2  : 0) |
2602d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_100_FULL)   ? 0x1  : 0) |
2603d381c807SPiotr Pietruszewski 	    ((speed & IXGBE_LINK_SPEED_10_FULL)    ? 0x8  : 0);
26048eb6488eSEric Joyner 
26058eb6488eSEric Joyner 	return (0);
26068eb6488eSEric Joyner 
26078eb6488eSEric Joyner invalid:
2608c19c7afeSEric Joyner 	device_printf(iflib_get_dev(ctx), "Invalid media type!\n");
26098eb6488eSEric Joyner 
26108eb6488eSEric Joyner 	return (EINVAL);
2611c19c7afeSEric Joyner } /* ixgbe_if_media_change */
26128eb6488eSEric Joyner 
26138eb6488eSEric Joyner /************************************************************************
26148eb6488eSEric Joyner  * ixgbe_set_promisc
26158eb6488eSEric Joyner  ************************************************************************/
2616c19c7afeSEric Joyner static int
2617c19c7afeSEric Joyner ixgbe_if_promisc_set(if_ctx_t ctx, int flags)
26188eb6488eSEric Joyner {
2619b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
2620ff06a8dbSJustin Hibbits 	if_t ifp = iflib_get_ifp(ctx);
26218eb6488eSEric Joyner 	u32 rctl;
2622c19c7afeSEric Joyner 	int mcnt = 0;
26238eb6488eSEric Joyner 
2624b1d5caf3SKevin Bowling 	rctl = IXGBE_READ_REG(&sc->hw, IXGBE_FCTRL);
26258eb6488eSEric Joyner 	rctl &= (~IXGBE_FCTRL_UPE);
2626ff06a8dbSJustin Hibbits 	if (if_getflags(ifp) & IFF_ALLMULTI)
26278eb6488eSEric Joyner 		mcnt = MAX_NUM_MULTICAST_ADDRESSES;
26288eb6488eSEric Joyner 	else {
2629*c58d34ddSKevin Bowling 		mcnt = min(if_llmaddr_count(ifp),
2630*c58d34ddSKevin Bowling 		    MAX_NUM_MULTICAST_ADDRESSES);
26318eb6488eSEric Joyner 	}
26328eb6488eSEric Joyner 	if (mcnt < MAX_NUM_MULTICAST_ADDRESSES)
26338eb6488eSEric Joyner 		rctl &= (~IXGBE_FCTRL_MPE);
2634b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, rctl);
26358eb6488eSEric Joyner 
2636ff06a8dbSJustin Hibbits 	if (if_getflags(ifp) & IFF_PROMISC) {
26378eb6488eSEric Joyner 		rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
2638b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, rctl);
2639ff06a8dbSJustin Hibbits 	} else if (if_getflags(ifp) & IFF_ALLMULTI) {
26408eb6488eSEric Joyner 		rctl |= IXGBE_FCTRL_MPE;
26418eb6488eSEric Joyner 		rctl &= ~IXGBE_FCTRL_UPE;
2642b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, rctl);
26438eb6488eSEric Joyner 	}
2644c19c7afeSEric Joyner 	return (0);
2645c19c7afeSEric Joyner } /* ixgbe_if_promisc_set */
26468eb6488eSEric Joyner 
26478eb6488eSEric Joyner /************************************************************************
26488eb6488eSEric Joyner  * ixgbe_msix_link - Link status change ISR (MSI/MSI-X)
26498eb6488eSEric Joyner  ************************************************************************/
2650c19c7afeSEric Joyner static int
26518eb6488eSEric Joyner ixgbe_msix_link(void *arg)
26528eb6488eSEric Joyner {
2653b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = arg;
2654b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
26558eb6488eSEric Joyner 	u32 eicr, eicr_mask;
26568eb6488eSEric Joyner 	s32 retval;
26578eb6488eSEric Joyner 
2658b1d5caf3SKevin Bowling 	++sc->link_irq;
26598eb6488eSEric Joyner 
26608eb6488eSEric Joyner 	/* Pause other interrupts */
26618eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_OTHER);
26628eb6488eSEric Joyner 
26638eb6488eSEric Joyner 	/* First get the cause */
26648eb6488eSEric Joyner 	eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
26658eb6488eSEric Joyner 	/* Be sure the queue bits are not cleared */
26668eb6488eSEric Joyner 	eicr &= ~IXGBE_EICR_RTX_QUEUE;
26678eb6488eSEric Joyner 	/* Clear interrupt with write */
26688eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
26698eb6488eSEric Joyner 
26708eb6488eSEric Joyner 	/* Link status change */
26718eb6488eSEric Joyner 	if (eicr & IXGBE_EICR_LSC) {
26728eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC);
2673b1d5caf3SKevin Bowling 		sc->task_requests |= IXGBE_REQUEST_TASK_LSC;
26748eb6488eSEric Joyner 	}
26758eb6488eSEric Joyner 
2676b1d5caf3SKevin Bowling 	if (sc->hw.mac.type != ixgbe_mac_82598EB) {
2677b1d5caf3SKevin Bowling 		if ((sc->feat_en & IXGBE_FEATURE_FDIR) &&
26788eb6488eSEric Joyner 		    (eicr & IXGBE_EICR_FLOW_DIR)) {
26798eb6488eSEric Joyner 			/* This is probably overkill :) */
2680b1d5caf3SKevin Bowling 			if (!atomic_cmpset_int(&sc->fdir_reinit, 0, 1))
2681c19c7afeSEric Joyner 				return (FILTER_HANDLED);
26828eb6488eSEric Joyner 			/* Disable the interrupt */
2683c19c7afeSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR);
2684b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_FDIR;
2685c19c7afeSEric Joyner 		} else
26868eb6488eSEric Joyner 			if (eicr & IXGBE_EICR_ECC) {
2687b1d5caf3SKevin Bowling 				device_printf(iflib_get_dev(sc->ctx),
26884f1d91e4SNeel Chauhan 				    "Received ECC Err, initiating reset\n");
2689*c58d34ddSKevin Bowling 				hw->mac.flags |=
2690*c58d34ddSKevin Bowling 				    ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
26914f1d91e4SNeel Chauhan 				ixgbe_reset_hw(hw);
2692*c58d34ddSKevin Bowling 				IXGBE_WRITE_REG(hw, IXGBE_EICR,
2693*c58d34ddSKevin Bowling 				    IXGBE_EICR_ECC);
26948eb6488eSEric Joyner 			}
26958eb6488eSEric Joyner 
26968eb6488eSEric Joyner 		/* Check for over temp condition */
2697b1d5caf3SKevin Bowling 		if (sc->feat_en & IXGBE_FEATURE_TEMP_SENSOR) {
2698b1d5caf3SKevin Bowling 			switch (sc->hw.mac.type) {
26998eb6488eSEric Joyner 			case ixgbe_mac_X550EM_a:
27008eb6488eSEric Joyner 				if (!(eicr & IXGBE_EICR_GPI_SDP0_X550EM_a))
27018eb6488eSEric Joyner 					break;
27028eb6488eSEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_EIMC,
27038eb6488eSEric Joyner 				    IXGBE_EICR_GPI_SDP0_X550EM_a);
27048eb6488eSEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_EICR,
27058eb6488eSEric Joyner 				    IXGBE_EICR_GPI_SDP0_X550EM_a);
27068eb6488eSEric Joyner 				retval = hw->phy.ops.check_overtemp(hw);
27078eb6488eSEric Joyner 				if (retval != IXGBE_ERR_OVERTEMP)
27088eb6488eSEric Joyner 					break;
2709b1d5caf3SKevin Bowling 				device_printf(iflib_get_dev(sc->ctx),
2710*c58d34ddSKevin Bowling 				    "\nCRITICAL: OVER TEMP!!"
2711*c58d34ddSKevin Bowling 				    " PHY IS SHUT DOWN!!\n");
2712b1d5caf3SKevin Bowling 				device_printf(iflib_get_dev(sc->ctx),
2713c19c7afeSEric Joyner 				    "System shutdown required!\n");
27148eb6488eSEric Joyner 				break;
27158eb6488eSEric Joyner 			default:
27168eb6488eSEric Joyner 				if (!(eicr & IXGBE_EICR_TS))
27178eb6488eSEric Joyner 					break;
27188eb6488eSEric Joyner 				retval = hw->phy.ops.check_overtemp(hw);
27198eb6488eSEric Joyner 				if (retval != IXGBE_ERR_OVERTEMP)
27208eb6488eSEric Joyner 					break;
2721b1d5caf3SKevin Bowling 				device_printf(iflib_get_dev(sc->ctx),
2722*c58d34ddSKevin Bowling 				    "\nCRITICAL: OVER TEMP!!"
2723*c58d34ddSKevin Bowling 				    " PHY IS SHUT DOWN!!\n");
2724b1d5caf3SKevin Bowling 				device_printf(iflib_get_dev(sc->ctx),
2725c19c7afeSEric Joyner 				    "System shutdown required!\n");
2726*c58d34ddSKevin Bowling 				IXGBE_WRITE_REG(hw, IXGBE_EICR,
2727*c58d34ddSKevin Bowling 				    IXGBE_EICR_TS);
27288eb6488eSEric Joyner 				break;
27298eb6488eSEric Joyner 			}
27308eb6488eSEric Joyner 		}
27318eb6488eSEric Joyner 
27328eb6488eSEric Joyner 		/* Check for VF message */
2733b1d5caf3SKevin Bowling 		if ((sc->feat_en & IXGBE_FEATURE_SRIOV) &&
27348eb6488eSEric Joyner 		    (eicr & IXGBE_EICR_MAILBOX))
2735b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_MBX;
27368eb6488eSEric Joyner 	}
27378eb6488eSEric Joyner 
27388eb6488eSEric Joyner 	if (ixgbe_is_sfp(hw)) {
27398eb6488eSEric Joyner 		/* Pluggable optics-related interrupt */
27408eb6488eSEric Joyner 		if (hw->mac.type >= ixgbe_mac_X540)
27418eb6488eSEric Joyner 			eicr_mask = IXGBE_EICR_GPI_SDP0_X540;
27428eb6488eSEric Joyner 		else
27438eb6488eSEric Joyner 			eicr_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw);
27448eb6488eSEric Joyner 
27458eb6488eSEric Joyner 		if (eicr & eicr_mask) {
27468eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask);
2747b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_MOD;
27488eb6488eSEric Joyner 		}
27498eb6488eSEric Joyner 
27508eb6488eSEric Joyner 		if ((hw->mac.type == ixgbe_mac_82599EB) &&
27518eb6488eSEric Joyner 		    (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) {
27528eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR,
27538eb6488eSEric Joyner 			    IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
2754b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_MSF;
27558eb6488eSEric Joyner 		}
27568eb6488eSEric Joyner 	}
27578eb6488eSEric Joyner 
27588eb6488eSEric Joyner 	/* Check for fan failure */
2759b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_FAN_FAIL) {
2760b1d5caf3SKevin Bowling 		ixgbe_check_fan_failure(sc, eicr, true);
2761*c58d34ddSKevin Bowling 		IXGBE_WRITE_REG(hw, IXGBE_EICR,
2762*c58d34ddSKevin Bowling 		    IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
27638eb6488eSEric Joyner 	}
27648eb6488eSEric Joyner 
27658eb6488eSEric Joyner 	/* External PHY interrupt */
27668eb6488eSEric Joyner 	if ((hw->phy.type == ixgbe_phy_x550em_ext_t) &&
27678eb6488eSEric Joyner 	    (eicr & IXGBE_EICR_GPI_SDP0_X540)) {
27688eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540);
2769b1d5caf3SKevin Bowling 		sc->task_requests |= IXGBE_REQUEST_TASK_PHY;
27708eb6488eSEric Joyner 	}
27718eb6488eSEric Joyner 
2772*c58d34ddSKevin Bowling 	return (sc->task_requests != 0) ?
2773*c58d34ddSKevin Bowling 	    FILTER_SCHEDULE_THREAD : FILTER_HANDLED;
27748eb6488eSEric Joyner } /* ixgbe_msix_link */
27758eb6488eSEric Joyner 
27768eb6488eSEric Joyner /************************************************************************
27778eb6488eSEric Joyner  * ixgbe_sysctl_interrupt_rate_handler
27788eb6488eSEric Joyner  ************************************************************************/
2779758cc3dcSJack F Vogel static int
2780758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
2781758cc3dcSJack F Vogel {
2782c19c7afeSEric Joyner 	struct ix_rx_queue *que = ((struct ix_rx_queue *)oidp->oid_arg1);
27838eb6488eSEric Joyner 	int error;
2784758cc3dcSJack F Vogel 	unsigned int reg, usec, rate;
2785758cc3dcSJack F Vogel 
2786f72de14eSKevin Bowling 	if (atomic_load_acq_int(&que->sc->recovery_mode))
2787f72de14eSKevin Bowling 		return (EPERM);
2788f72de14eSKevin Bowling 
2789b1d5caf3SKevin Bowling 	reg = IXGBE_READ_REG(&que->sc->hw, IXGBE_EITR(que->msix));
2790758cc3dcSJack F Vogel 	usec = ((reg & 0x0FF8) >> 3);
2791758cc3dcSJack F Vogel 	if (usec > 0)
2792758cc3dcSJack F Vogel 		rate = 500000 / usec;
2793758cc3dcSJack F Vogel 	else
2794758cc3dcSJack F Vogel 		rate = 0;
2795758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &rate, 0, req);
2796758cc3dcSJack F Vogel 	if (error || !req->newptr)
2797758cc3dcSJack F Vogel 		return error;
2798758cc3dcSJack F Vogel 	reg &= ~0xfff; /* default, no limitation */
2799758cc3dcSJack F Vogel 	ixgbe_max_interrupt_rate = 0;
2800758cc3dcSJack F Vogel 	if (rate > 0 && rate < 500000) {
2801758cc3dcSJack F Vogel 		if (rate < 1000)
2802758cc3dcSJack F Vogel 			rate = 1000;
2803758cc3dcSJack F Vogel 		ixgbe_max_interrupt_rate = rate;
2804758cc3dcSJack F Vogel 		reg |= ((4000000/rate) & 0xff8);
2805758cc3dcSJack F Vogel 	}
2806b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(&que->sc->hw, IXGBE_EITR(que->msix), reg);
2807758cc3dcSJack F Vogel 
28088eb6488eSEric Joyner 	return (0);
28098eb6488eSEric Joyner } /* ixgbe_sysctl_interrupt_rate_handler */
28108eb6488eSEric Joyner 
28118eb6488eSEric Joyner /************************************************************************
28128eb6488eSEric Joyner  * ixgbe_add_device_sysctls
28138eb6488eSEric Joyner  ************************************************************************/
28146f37f232SEric Joyner static void
2815c19c7afeSEric Joyner ixgbe_add_device_sysctls(if_ctx_t ctx)
28166f37f232SEric Joyner {
2817b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
2818c19c7afeSEric Joyner 	device_t dev = iflib_get_dev(ctx);
2819b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
28206f37f232SEric Joyner 	struct sysctl_oid_list *child;
2821c19c7afeSEric Joyner 	struct sysctl_ctx_list *ctx_list;
28226f37f232SEric Joyner 
2823c19c7afeSEric Joyner 	ctx_list = device_get_sysctl_ctx(dev);
28246f37f232SEric Joyner 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
28256f37f232SEric Joyner 
28266f37f232SEric Joyner 	/* Sysctls for all devices */
2827c19c7afeSEric Joyner 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "fc",
2828f72de14eSKevin Bowling 	    CTLTYPE_INT | CTLFLAG_RW,
2829b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_sysctl_flowcntl, "I",
2830c19c7afeSEric Joyner 	    IXGBE_SYSCTL_DESC_SET_FC);
28316f37f232SEric Joyner 
2832c19c7afeSEric Joyner 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "advertise_speed",
2833f72de14eSKevin Bowling 	    CTLTYPE_INT | CTLFLAG_RW,
2834b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_sysctl_advertise, "I",
28358eb6488eSEric Joyner 	    IXGBE_SYSCTL_DESC_ADV_SPEED);
28366f37f232SEric Joyner 
2837b1d5caf3SKevin Bowling 	sc->enable_aim = ixgbe_enable_aim;
283864881da4SSai Rajesh Tallamraju 	SYSCTL_ADD_INT(ctx_list, child, OID_AUTO, "enable_aim", CTLFLAG_RW,
2839b1d5caf3SKevin Bowling 	    &sc->enable_aim, 0, "Interrupt Moderation");
284064881da4SSai Rajesh Tallamraju 
28417660e4eaSKevin Bowling 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "fw_version",
2842f72de14eSKevin Bowling 	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
28437660e4eaSKevin Bowling 	    ixgbe_sysctl_print_fw_version, "A", "Prints FW/NVM Versions");
28447660e4eaSKevin Bowling 
2845eea2e089SMichael Tuexen 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO,
2846eea2e089SMichael Tuexen 	    "tso_tcp_flags_mask_first_segment",
2847eea2e089SMichael Tuexen 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
2848eea2e089SMichael Tuexen 	    sc, 0, ixgbe_sysctl_tso_tcp_flags_mask, "IU",
2849eea2e089SMichael Tuexen 	    "TSO TCP flags mask for first segment");
2850eea2e089SMichael Tuexen 
2851eea2e089SMichael Tuexen 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO,
2852eea2e089SMichael Tuexen 	    "tso_tcp_flags_mask_middle_segment",
2853eea2e089SMichael Tuexen 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
2854eea2e089SMichael Tuexen 	    sc, 1, ixgbe_sysctl_tso_tcp_flags_mask, "IU",
2855eea2e089SMichael Tuexen 	    "TSO TCP flags mask for middle segment");
2856eea2e089SMichael Tuexen 
2857eea2e089SMichael Tuexen 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO,
2858eea2e089SMichael Tuexen 	    "tso_tcp_flags_mask_last_segment",
2859eea2e089SMichael Tuexen 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
2860eea2e089SMichael Tuexen 	    sc, 2, ixgbe_sysctl_tso_tcp_flags_mask, "IU",
2861eea2e089SMichael Tuexen 	    "TSO TCP flags mask for last segment");
2862eea2e089SMichael Tuexen 
2863a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
2864a9ca1c79SSean Bruno 	/* testing sysctls (for all devices) */
2865c19c7afeSEric Joyner 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "power_state",
2866f72de14eSKevin Bowling 	    CTLTYPE_INT | CTLFLAG_RW,
2867b1d5caf3SKevin Bowling 	    sc, 0, ixgbe_sysctl_power_state,
28688eb6488eSEric Joyner 	    "I", "PCI Power State");
2869a9ca1c79SSean Bruno 
2870c19c7afeSEric Joyner 	SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "print_rss_config",
2871f72de14eSKevin Bowling 	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
2872a9ca1c79SSean Bruno 	    ixgbe_sysctl_print_rss_config, "A", "Prints RSS Configuration");
2873a9ca1c79SSean Bruno #endif
2874a9ca1c79SSean Bruno 	/* for X550 series devices */
28756f37f232SEric Joyner 	if (hw->mac.type >= ixgbe_mac_X550)
2876c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "dmac",
2877f72de14eSKevin Bowling 		    CTLTYPE_U16 | CTLFLAG_RW,
2878b1d5caf3SKevin Bowling 		    sc, 0, ixgbe_sysctl_dmac,
28798eb6488eSEric Joyner 		    "I", "DMA Coalesce");
28806f37f232SEric Joyner 
2881a9ca1c79SSean Bruno 	/* for WoL-capable devices */
2882a9ca1c79SSean Bruno 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
2883c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "wol_enable",
2884f72de14eSKevin Bowling 		    CTLTYPE_INT | CTLFLAG_RW, sc, 0,
2885*c58d34ddSKevin Bowling 		    ixgbe_sysctl_wol_enable, "I",
2886*c58d34ddSKevin Bowling 		    "Enable/Disable Wake on LAN");
28876f37f232SEric Joyner 
2888c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "wufc",
2889f72de14eSKevin Bowling 		    CTLTYPE_U32 | CTLFLAG_RW,
2890b1d5caf3SKevin Bowling 		    sc, 0, ixgbe_sysctl_wufc,
28918eb6488eSEric Joyner 		    "I", "Enable/Disable Wake Up Filters");
28926f37f232SEric Joyner 	}
28936f37f232SEric Joyner 
2894a9ca1c79SSean Bruno 	/* for X552/X557-AT devices */
28956f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
28966f37f232SEric Joyner 		struct sysctl_oid *phy_node;
28976f37f232SEric Joyner 		struct sysctl_oid_list *phy_list;
28986f37f232SEric Joyner 
2899c19c7afeSEric Joyner 		phy_node = SYSCTL_ADD_NODE(ctx_list, child, OID_AUTO, "phy",
2900*c58d34ddSKevin Bowling 		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
2901*c58d34ddSKevin Bowling 		    "External PHY sysctls");
29026f37f232SEric Joyner 		phy_list = SYSCTL_CHILDREN(phy_node);
29036f37f232SEric Joyner 
2904c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, phy_list, OID_AUTO, "temp",
2905f72de14eSKevin Bowling 		    CTLTYPE_U16 | CTLFLAG_RD,
2906b1d5caf3SKevin Bowling 		    sc, 0, ixgbe_sysctl_phy_temp,
29078eb6488eSEric Joyner 		    "I", "Current External PHY Temperature (Celsius)");
29086f37f232SEric Joyner 
2909c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, phy_list, OID_AUTO,
291020b91f0aSPawel Biernacki 		    "overtemp_occurred",
2911f72de14eSKevin Bowling 		    CTLTYPE_U16 | CTLFLAG_RD, sc, 0,
29126f37f232SEric Joyner 		    ixgbe_sysctl_phy_overtemp_occurred, "I",
29136f37f232SEric Joyner 		    "External PHY High Temperature Event Occurred");
29146f37f232SEric Joyner 	}
29158eb6488eSEric Joyner 
2916b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_EEE) {
2917c19c7afeSEric Joyner 		SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "eee_state",
2918f72de14eSKevin Bowling 		    CTLTYPE_INT | CTLFLAG_RW, sc, 0,
29198eb6488eSEric Joyner 		    ixgbe_sysctl_eee_state, "I", "EEE Power Save State");
29208eb6488eSEric Joyner 	}
29218eb6488eSEric Joyner } /* ixgbe_add_device_sysctls */
29228eb6488eSEric Joyner 
29238eb6488eSEric Joyner /************************************************************************
29248eb6488eSEric Joyner  * ixgbe_allocate_pci_resources
29258eb6488eSEric Joyner  ************************************************************************/
29268eb6488eSEric Joyner static int
2927c19c7afeSEric Joyner ixgbe_allocate_pci_resources(if_ctx_t ctx)
29288eb6488eSEric Joyner {
2929b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
2930c19c7afeSEric Joyner 	device_t dev = iflib_get_dev(ctx);
29318eb6488eSEric Joyner 	int rid;
29328eb6488eSEric Joyner 
29338eb6488eSEric Joyner 	rid = PCIR_BAR(0);
2934b1d5caf3SKevin Bowling 	sc->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
29358eb6488eSEric Joyner 	    RF_ACTIVE);
29368eb6488eSEric Joyner 
2937b1d5caf3SKevin Bowling 	if (!(sc->pci_mem)) {
2938*c58d34ddSKevin Bowling 		device_printf(dev,
2939*c58d34ddSKevin Bowling 		    "Unable to allocate bus resource: memory\n");
29408eb6488eSEric Joyner 		return (ENXIO);
29418eb6488eSEric Joyner 	}
29428eb6488eSEric Joyner 
29438eb6488eSEric Joyner 	/* Save bus_space values for READ/WRITE_REG macros */
2944b1d5caf3SKevin Bowling 	sc->osdep.mem_bus_space_tag = rman_get_bustag(sc->pci_mem);
2945b1d5caf3SKevin Bowling 	sc->osdep.mem_bus_space_handle =
2946b1d5caf3SKevin Bowling 	    rman_get_bushandle(sc->pci_mem);
29478eb6488eSEric Joyner 	/* Set hw values for shared code */
2948b1d5caf3SKevin Bowling 	sc->hw.hw_addr = (u8 *)&sc->osdep.mem_bus_space_handle;
29498eb6488eSEric Joyner 
29508eb6488eSEric Joyner 	return (0);
29518eb6488eSEric Joyner } /* ixgbe_allocate_pci_resources */
29528eb6488eSEric Joyner 
29538eb6488eSEric Joyner /************************************************************************
29548eb6488eSEric Joyner  * ixgbe_detach - Device removal routine
29558eb6488eSEric Joyner  *
29568eb6488eSEric Joyner  *   Called when the driver is being removed.
29578eb6488eSEric Joyner  *   Stops the adapter and deallocates all the resources
29588eb6488eSEric Joyner  *   that were allocated for driver operation.
29598eb6488eSEric Joyner  *
29608eb6488eSEric Joyner  *   return 0 on success, positive on failure
29618eb6488eSEric Joyner  ************************************************************************/
29628eb6488eSEric Joyner static int
2963c19c7afeSEric Joyner ixgbe_if_detach(if_ctx_t ctx)
29648eb6488eSEric Joyner {
2965b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
2966c19c7afeSEric Joyner 	device_t dev = iflib_get_dev(ctx);
29678eb6488eSEric Joyner 	u32 ctrl_ext;
29688eb6488eSEric Joyner 
29698eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_detach: begin");
29708eb6488eSEric Joyner 
29718eb6488eSEric Joyner 	if (ixgbe_pci_iov_detach(dev) != 0) {
29728eb6488eSEric Joyner 		device_printf(dev, "SR-IOV in use; detach first.\n");
29738eb6488eSEric Joyner 		return (EBUSY);
29748eb6488eSEric Joyner 	}
29758eb6488eSEric Joyner 
2976c19c7afeSEric Joyner 	ixgbe_setup_low_power_mode(ctx);
29778eb6488eSEric Joyner 
29788eb6488eSEric Joyner 	/* let hardware know driver is unloading */
2979b1d5caf3SKevin Bowling 	ctrl_ext = IXGBE_READ_REG(&sc->hw, IXGBE_CTRL_EXT);
29808eb6488eSEric Joyner 	ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
2981b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(&sc->hw, IXGBE_CTRL_EXT, ctrl_ext);
29828eb6488eSEric Joyner 
2983f72de14eSKevin Bowling 	callout_drain(&sc->fw_mode_timer);
2984f72de14eSKevin Bowling 
2985c19c7afeSEric Joyner 	ixgbe_free_pci_resources(ctx);
2986b1d5caf3SKevin Bowling 	free(sc->mta, M_IXGBE);
29878eb6488eSEric Joyner 
29888eb6488eSEric Joyner 	return (0);
2989c19c7afeSEric Joyner } /* ixgbe_if_detach */
29908eb6488eSEric Joyner 
29918eb6488eSEric Joyner /************************************************************************
29928eb6488eSEric Joyner  * ixgbe_setup_low_power_mode - LPLU/WoL preparation
29938eb6488eSEric Joyner  *
29948eb6488eSEric Joyner  *   Prepare the adapter/port for LPLU and/or WoL
29958eb6488eSEric Joyner  ************************************************************************/
29968eb6488eSEric Joyner static int
2997c19c7afeSEric Joyner ixgbe_setup_low_power_mode(if_ctx_t ctx)
29988eb6488eSEric Joyner {
2999b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3000b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3001c19c7afeSEric Joyner 	device_t dev = iflib_get_dev(ctx);
30028eb6488eSEric Joyner 	s32 error = 0;
30038eb6488eSEric Joyner 
3004c19c7afeSEric Joyner 	if (!hw->wol_enabled)
300579b36ec9SKevin Bowling 		ixgbe_set_phy_power(hw, false);
30068eb6488eSEric Joyner 
30078eb6488eSEric Joyner 	/* Limit power management flow to X550EM baseT */
30088eb6488eSEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
30098eb6488eSEric Joyner 	    hw->phy.ops.enter_lplu) {
30108eb6488eSEric Joyner 		/* Turn off support for APM wakeup. (Using ACPI instead) */
301173fa89e0SPiotr Pietruszewski 		IXGBE_WRITE_REG(hw, IXGBE_GRC_BY_MAC(hw),
301273fa89e0SPiotr Pietruszewski 		    IXGBE_READ_REG(hw, IXGBE_GRC_BY_MAC(hw)) & ~(u32)2);
30138eb6488eSEric Joyner 
30148eb6488eSEric Joyner 		/*
3015*c58d34ddSKevin Bowling 		 * Clear Wake Up Status register to prevent any previous
3016*c58d34ddSKevin Bowling 		 * wakeup events from waking us up immediately after we
3017*c58d34ddSKevin Bowling 		 * suspend.
30188eb6488eSEric Joyner 		 */
30198eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
30208eb6488eSEric Joyner 
30218eb6488eSEric Joyner 		/*
30228eb6488eSEric Joyner 		 * Program the Wakeup Filter Control register with user filter
30238eb6488eSEric Joyner 		 * settings
30248eb6488eSEric Joyner 		 */
3025b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(hw, IXGBE_WUFC, sc->wufc);
30268eb6488eSEric Joyner 
30278eb6488eSEric Joyner 		/* Enable wakeups and power management in Wakeup Control */
30288eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_WUC,
30298eb6488eSEric Joyner 		    IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN);
30308eb6488eSEric Joyner 
30318eb6488eSEric Joyner 		/* X550EM baseT adapters need a special LPLU flow */
303279b36ec9SKevin Bowling 		hw->phy.reset_disable = true;
3033c19c7afeSEric Joyner 		ixgbe_if_stop(ctx);
30348eb6488eSEric Joyner 		error = hw->phy.ops.enter_lplu(hw);
30358eb6488eSEric Joyner 		if (error)
3036*c58d34ddSKevin Bowling 			device_printf(dev, "Error entering LPLU: %d\n",
3037*c58d34ddSKevin Bowling 			    error);
303879b36ec9SKevin Bowling 		hw->phy.reset_disable = false;
30398eb6488eSEric Joyner 	} else {
30408eb6488eSEric Joyner 		/* Just stop for other adapters */
3041c19c7afeSEric Joyner 		ixgbe_if_stop(ctx);
30428eb6488eSEric Joyner 	}
30438eb6488eSEric Joyner 
30448eb6488eSEric Joyner 	return error;
30458eb6488eSEric Joyner } /* ixgbe_setup_low_power_mode */
30468eb6488eSEric Joyner 
30478eb6488eSEric Joyner /************************************************************************
30488eb6488eSEric Joyner  * ixgbe_shutdown - Shutdown entry point
30498eb6488eSEric Joyner  ************************************************************************/
30508eb6488eSEric Joyner static int
3051c19c7afeSEric Joyner ixgbe_if_shutdown(if_ctx_t ctx)
30528eb6488eSEric Joyner {
30538eb6488eSEric Joyner 	int error = 0;
30548eb6488eSEric Joyner 
30558eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_shutdown: begin");
30568eb6488eSEric Joyner 
3057c19c7afeSEric Joyner 	error = ixgbe_setup_low_power_mode(ctx);
30588eb6488eSEric Joyner 
30598eb6488eSEric Joyner 	return (error);
3060c19c7afeSEric Joyner } /* ixgbe_if_shutdown */
30618eb6488eSEric Joyner 
30628eb6488eSEric Joyner /************************************************************************
30638eb6488eSEric Joyner  * ixgbe_suspend
30648eb6488eSEric Joyner  *
30658eb6488eSEric Joyner  *   From D0 to D3
30668eb6488eSEric Joyner  ************************************************************************/
30678eb6488eSEric Joyner static int
3068c19c7afeSEric Joyner ixgbe_if_suspend(if_ctx_t ctx)
30698eb6488eSEric Joyner {
30708eb6488eSEric Joyner 	int error = 0;
30718eb6488eSEric Joyner 
30728eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_suspend: begin");
30738eb6488eSEric Joyner 
3074c19c7afeSEric Joyner 	error = ixgbe_setup_low_power_mode(ctx);
30758eb6488eSEric Joyner 
30768eb6488eSEric Joyner 	return (error);
3077c19c7afeSEric Joyner } /* ixgbe_if_suspend */
30788eb6488eSEric Joyner 
30798eb6488eSEric Joyner /************************************************************************
30808eb6488eSEric Joyner  * ixgbe_resume
30818eb6488eSEric Joyner  *
30828eb6488eSEric Joyner  *   From D3 to D0
30838eb6488eSEric Joyner  ************************************************************************/
30848eb6488eSEric Joyner static int
3085c19c7afeSEric Joyner ixgbe_if_resume(if_ctx_t ctx)
30868eb6488eSEric Joyner {
3087b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3088c19c7afeSEric Joyner 	device_t dev = iflib_get_dev(ctx);
3089ff06a8dbSJustin Hibbits 	if_t ifp = iflib_get_ifp(ctx);
3090b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
30918eb6488eSEric Joyner 	u32 wus;
30928eb6488eSEric Joyner 
30938eb6488eSEric Joyner 	INIT_DEBUGOUT("ixgbe_resume: begin");
30948eb6488eSEric Joyner 
30958eb6488eSEric Joyner 	/* Read & clear WUS register */
30968eb6488eSEric Joyner 	wus = IXGBE_READ_REG(hw, IXGBE_WUS);
30978eb6488eSEric Joyner 	if (wus)
30988eb6488eSEric Joyner 		device_printf(dev, "Woken up by (WUS): %#010x\n",
30998eb6488eSEric Joyner 		    IXGBE_READ_REG(hw, IXGBE_WUS));
31008eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
31018eb6488eSEric Joyner 	/* And clear WUFC until next low-power transition */
31028eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0);
31038eb6488eSEric Joyner 
31048eb6488eSEric Joyner 	/*
31058eb6488eSEric Joyner 	 * Required after D3->D0 transition;
31068eb6488eSEric Joyner 	 * will re-advertise all previous advertised speeds
31078eb6488eSEric Joyner 	 */
3108ff06a8dbSJustin Hibbits 	if (if_getflags(ifp) & IFF_UP)
3109c19c7afeSEric Joyner 		ixgbe_if_init(ctx);
31108eb6488eSEric Joyner 
31118eb6488eSEric Joyner 	return (0);
3112c19c7afeSEric Joyner } /* ixgbe_if_resume */
31138eb6488eSEric Joyner 
31148eb6488eSEric Joyner /************************************************************************
3115c19c7afeSEric Joyner  * ixgbe_if_mtu_set - Ioctl mtu entry point
31168eb6488eSEric Joyner  *
3117c19c7afeSEric Joyner  *   Return 0 on success, EINVAL on failure
3118c19c7afeSEric Joyner  ************************************************************************/
3119c19c7afeSEric Joyner static int
3120c19c7afeSEric Joyner ixgbe_if_mtu_set(if_ctx_t ctx, uint32_t mtu)
3121c19c7afeSEric Joyner {
3122b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3123c19c7afeSEric Joyner 	int error = 0;
3124c19c7afeSEric Joyner 
3125c19c7afeSEric Joyner 	IOCTL_DEBUGOUT("ioctl: SIOCIFMTU (Set Interface MTU)");
3126c19c7afeSEric Joyner 
3127c19c7afeSEric Joyner 	if (mtu > IXGBE_MAX_MTU) {
3128c19c7afeSEric Joyner 		error = EINVAL;
3129c19c7afeSEric Joyner 	} else {
3130b1d5caf3SKevin Bowling 		sc->max_frame_size = mtu + IXGBE_MTU_HDR;
3131c19c7afeSEric Joyner 	}
3132c19c7afeSEric Joyner 
3133c19c7afeSEric Joyner 	return error;
3134c19c7afeSEric Joyner } /* ixgbe_if_mtu_set */
3135c19c7afeSEric Joyner 
3136c19c7afeSEric Joyner /************************************************************************
3137c19c7afeSEric Joyner  * ixgbe_if_crcstrip_set
31388eb6488eSEric Joyner  ************************************************************************/
31398eb6488eSEric Joyner static void
3140c19c7afeSEric Joyner ixgbe_if_crcstrip_set(if_ctx_t ctx, int onoff, int crcstrip)
31418eb6488eSEric Joyner {
3142b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3143c19c7afeSEric Joyner 	struct ixgbe_hw *hw = &sc->hw;
3144c19c7afeSEric Joyner 	/* crc stripping is set in two places:
3145c19c7afeSEric Joyner 	 * IXGBE_HLREG0 (modified on init_locked and hw reset)
3146c19c7afeSEric Joyner 	 * IXGBE_RDRXCTL (set by the original driver in
3147c19c7afeSEric Joyner 	 *	ixgbe_setup_hw_rsc() called in init_locked.
3148c19c7afeSEric Joyner 	 *	We disable the setting when netmap is compiled in).
3149c19c7afeSEric Joyner 	 * We update the values here, but also in ixgbe.c because
3150c19c7afeSEric Joyner 	 * init_locked sometimes is called outside our control.
3151c19c7afeSEric Joyner 	 */
3152c19c7afeSEric Joyner 	uint32_t hl, rxc;
31538eb6488eSEric Joyner 
3154c19c7afeSEric Joyner 	hl = IXGBE_READ_REG(hw, IXGBE_HLREG0);
3155c19c7afeSEric Joyner 	rxc = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
3156c19c7afeSEric Joyner #ifdef NETMAP
3157c19c7afeSEric Joyner 	if (netmap_verbose)
3158c19c7afeSEric Joyner 		D("%s read  HLREG 0x%x rxc 0x%x",
3159c19c7afeSEric Joyner 			onoff ? "enter" : "exit", hl, rxc);
31608eb6488eSEric Joyner #endif
3161c19c7afeSEric Joyner 	/* hw requirements ... */
3162c19c7afeSEric Joyner 	rxc &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
3163c19c7afeSEric Joyner 	rxc |= IXGBE_RDRXCTL_RSCACKC;
3164c19c7afeSEric Joyner 	if (onoff && !crcstrip) {
3165c19c7afeSEric Joyner 		/* keep the crc. Fast rx */
3166c19c7afeSEric Joyner 		hl &= ~IXGBE_HLREG0_RXCRCSTRP;
3167c19c7afeSEric Joyner 		rxc &= ~IXGBE_RDRXCTL_CRCSTRIP;
3168c19c7afeSEric Joyner 	} else {
3169c19c7afeSEric Joyner 		/* reset default mode */
3170c19c7afeSEric Joyner 		hl |= IXGBE_HLREG0_RXCRCSTRP;
3171c19c7afeSEric Joyner 		rxc |= IXGBE_RDRXCTL_CRCSTRIP;
3172c19c7afeSEric Joyner 	}
3173c19c7afeSEric Joyner #ifdef NETMAP
3174c19c7afeSEric Joyner 	if (netmap_verbose)
3175c19c7afeSEric Joyner 		D("%s write HLREG 0x%x rxc 0x%x",
3176c19c7afeSEric Joyner 			onoff ? "enter" : "exit", hl, rxc);
3177c19c7afeSEric Joyner #endif
3178c19c7afeSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hl);
3179c19c7afeSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rxc);
3180c19c7afeSEric Joyner } /* ixgbe_if_crcstrip_set */
31818eb6488eSEric Joyner 
3182c19c7afeSEric Joyner /*********************************************************************
3183c19c7afeSEric Joyner  * ixgbe_if_init - Init entry point
31848eb6488eSEric Joyner  *
31858eb6488eSEric Joyner  *   Used in two ways: It is used by the stack as an init
31868eb6488eSEric Joyner  *   entry point in network interface structure. It is also
31878eb6488eSEric Joyner  *   used by the driver as a hw/sw initialization routine to
31888eb6488eSEric Joyner  *   get to a consistent state.
31898eb6488eSEric Joyner  *
3190c19c7afeSEric Joyner  *   Return 0 on success, positive on failure
3191c19c7afeSEric Joyner  **********************************************************************/
31928eb6488eSEric Joyner void
3193c19c7afeSEric Joyner ixgbe_if_init(if_ctx_t ctx)
31948eb6488eSEric Joyner {
3195b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3196ff06a8dbSJustin Hibbits 	if_t ifp = iflib_get_ifp(ctx);
3197c19c7afeSEric Joyner 	device_t dev = iflib_get_dev(ctx);
3198b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3199c19c7afeSEric Joyner 	struct ix_rx_queue *rx_que;
3200c19c7afeSEric Joyner 	struct ix_tx_queue *tx_que;
32018eb6488eSEric Joyner 	u32 txdctl, mhadd;
32028eb6488eSEric Joyner 	u32 rxdctl, rxctrl;
32038eb6488eSEric Joyner 	u32 ctrl_ext;
32048eb6488eSEric Joyner 
3205c19c7afeSEric Joyner 	int i, j, err;
32068eb6488eSEric Joyner 
3207c19c7afeSEric Joyner 	INIT_DEBUGOUT("ixgbe_if_init: begin");
32088eb6488eSEric Joyner 
32098eb6488eSEric Joyner 	/* Queue indices may change with IOV mode */
3210b1d5caf3SKevin Bowling 	ixgbe_align_all_queue_indices(sc);
32118eb6488eSEric Joyner 
32128eb6488eSEric Joyner 	/* reprogram the RAR[0] in case user changed it. */
3213b1d5caf3SKevin Bowling 	ixgbe_set_rar(hw, 0, hw->mac.addr, sc->pool, IXGBE_RAH_AV);
32148eb6488eSEric Joyner 
32158eb6488eSEric Joyner 	/* Get the latest mac address, User can use a LAA */
3216ff06a8dbSJustin Hibbits 	bcopy(if_getlladdr(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
3217b1d5caf3SKevin Bowling 	ixgbe_set_rar(hw, 0, hw->mac.addr, sc->pool, 1);
32188eb6488eSEric Joyner 	hw->addr_ctrl.rar_used_count = 1;
32198eb6488eSEric Joyner 
32208eb6488eSEric Joyner 	ixgbe_init_hw(hw);
3221c19c7afeSEric Joyner 
3222b1d5caf3SKevin Bowling 	ixgbe_initialize_iov(sc);
3223c19c7afeSEric Joyner 
3224c19c7afeSEric Joyner 	ixgbe_initialize_transmit_units(ctx);
32258eb6488eSEric Joyner 
32268eb6488eSEric Joyner 	/* Setup Multicast table */
3227c19c7afeSEric Joyner 	ixgbe_if_multi_set(ctx);
32288eb6488eSEric Joyner 
32298eb6488eSEric Joyner 	/* Determine the correct mbuf pool, based on frame size */
3230b1d5caf3SKevin Bowling 	sc->rx_mbuf_sz = iflib_get_rx_mbuf_sz(ctx);
32318eb6488eSEric Joyner 
32328eb6488eSEric Joyner 	/* Configure RX settings */
3233c19c7afeSEric Joyner 	ixgbe_initialize_receive_units(ctx);
32348eb6488eSEric Joyner 
3235b2c1e8e6SEric Joyner 	/*
3236b2c1e8e6SEric Joyner 	 * Initialize variable holding task enqueue requests
3237b2c1e8e6SEric Joyner 	 * from MSI-X interrupts
3238b2c1e8e6SEric Joyner 	 */
3239b1d5caf3SKevin Bowling 	sc->task_requests = 0;
3240b2c1e8e6SEric Joyner 
32418eb6488eSEric Joyner 	/* Enable SDP & MSI-X interrupts based on adapter */
3242b1d5caf3SKevin Bowling 	ixgbe_config_gpie(sc);
32438eb6488eSEric Joyner 
32448eb6488eSEric Joyner 	/* Set MTU size */
3245ff06a8dbSJustin Hibbits 	if (if_getmtu(ifp) > ETHERMTU) {
32468eb6488eSEric Joyner 		/* aka IXGBE_MAXFRS on 82599 and newer */
32478eb6488eSEric Joyner 		mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
32488eb6488eSEric Joyner 		mhadd &= ~IXGBE_MHADD_MFS_MASK;
3249b1d5caf3SKevin Bowling 		mhadd |= sc->max_frame_size << IXGBE_MHADD_MFS_SHIFT;
32508eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
32518eb6488eSEric Joyner 	}
32528eb6488eSEric Joyner 
32538eb6488eSEric Joyner 	/* Now enable all the queues */
3254*c58d34ddSKevin Bowling 	for (i = 0, tx_que = sc->tx_queues; i < sc->num_tx_queues;
3255*c58d34ddSKevin Bowling 	    i++, tx_que++) {
3256c19c7afeSEric Joyner 		struct tx_ring *txr = &tx_que->txr;
3257c19c7afeSEric Joyner 
32588eb6488eSEric Joyner 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txr->me));
32598eb6488eSEric Joyner 		txdctl |= IXGBE_TXDCTL_ENABLE;
32608eb6488eSEric Joyner 		/* Set WTHRESH to 8, burst writeback */
32618eb6488eSEric Joyner 		txdctl |= (8 << 16);
32628eb6488eSEric Joyner 		/*
32638eb6488eSEric Joyner 		 * When the internal queue falls below PTHRESH (32),
32648eb6488eSEric Joyner 		 * start prefetching as long as there are at least
32658eb6488eSEric Joyner 		 * HTHRESH (1) buffers ready. The values are taken
32668eb6488eSEric Joyner 		 * from the Intel linux driver 3.8.21.
32678eb6488eSEric Joyner 		 * Prefetching enables tx line rate even with 1 queue.
32688eb6488eSEric Joyner 		 */
32698eb6488eSEric Joyner 		txdctl |= (32 << 0) | (1 << 8);
32708eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txr->me), txdctl);
32718eb6488eSEric Joyner 	}
32728eb6488eSEric Joyner 
3273*c58d34ddSKevin Bowling 	for (i = 0, rx_que = sc->rx_queues; i < sc->num_rx_queues;
3274*c58d34ddSKevin Bowling 	    i++, rx_que++) {
3275c19c7afeSEric Joyner 		struct rx_ring *rxr = &rx_que->rxr;
3276c19c7afeSEric Joyner 
32778eb6488eSEric Joyner 		rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me));
32788eb6488eSEric Joyner 		if (hw->mac.type == ixgbe_mac_82598EB) {
32798eb6488eSEric Joyner 			/*
32808eb6488eSEric Joyner 			 * PTHRESH = 21
32818eb6488eSEric Joyner 			 * HTHRESH = 4
32828eb6488eSEric Joyner 			 * WTHRESH = 8
32838eb6488eSEric Joyner 			 */
32848eb6488eSEric Joyner 			rxdctl &= ~0x3FFFFF;
32858eb6488eSEric Joyner 			rxdctl |= 0x080420;
32868eb6488eSEric Joyner 		}
32878eb6488eSEric Joyner 		rxdctl |= IXGBE_RXDCTL_ENABLE;
32888eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), rxdctl);
3289c19c7afeSEric Joyner 		for (j = 0; j < 10; j++) {
32908eb6488eSEric Joyner 			if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)) &
32918eb6488eSEric Joyner 			    IXGBE_RXDCTL_ENABLE)
32928eb6488eSEric Joyner 				break;
32938eb6488eSEric Joyner 			else
32948eb6488eSEric Joyner 				msec_delay(1);
32958eb6488eSEric Joyner 		}
32968eb6488eSEric Joyner 		wmb();
32978eb6488eSEric Joyner 	}
32988eb6488eSEric Joyner 
32998eb6488eSEric Joyner 	/* Enable Receive engine */
33008eb6488eSEric Joyner 	rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
33018eb6488eSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB)
33028eb6488eSEric Joyner 		rxctrl |= IXGBE_RXCTRL_DMBYPS;
33038eb6488eSEric Joyner 	rxctrl |= IXGBE_RXCTRL_RXEN;
33048eb6488eSEric Joyner 	ixgbe_enable_rx_dma(hw, rxctrl);
33058eb6488eSEric Joyner 
3306c19c7afeSEric Joyner 	/* Set up MSI/MSI-X routing */
3307c19c7afeSEric Joyner 	if (ixgbe_enable_msix)  {
3308b1d5caf3SKevin Bowling 		ixgbe_configure_ivars(sc);
33098eb6488eSEric Joyner 		/* Set up auto-mask */
33108eb6488eSEric Joyner 		if (hw->mac.type == ixgbe_mac_82598EB)
33118eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
33128eb6488eSEric Joyner 		else {
33138eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF);
33148eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF);
33158eb6488eSEric Joyner 		}
33168eb6488eSEric Joyner 	} else {  /* Simple settings for Legacy/MSI */
3317b1d5caf3SKevin Bowling 		ixgbe_set_ivar(sc, 0, 0, 0);
3318b1d5caf3SKevin Bowling 		ixgbe_set_ivar(sc, 0, 0, 1);
33198eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
33208eb6488eSEric Joyner 	}
33218eb6488eSEric Joyner 
3322b1d5caf3SKevin Bowling 	ixgbe_init_fdir(sc);
33238eb6488eSEric Joyner 
33248eb6488eSEric Joyner 	/*
33258eb6488eSEric Joyner 	 * Check on any SFP devices that
33268eb6488eSEric Joyner 	 * need to be kick-started
33278eb6488eSEric Joyner 	 */
33288eb6488eSEric Joyner 	if (hw->phy.type == ixgbe_phy_none) {
33298eb6488eSEric Joyner 		err = hw->phy.ops.identify(hw);
33308eb6488eSEric Joyner 		if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
33318eb6488eSEric Joyner 			device_printf(dev,
33328eb6488eSEric Joyner 			    "Unsupported SFP+ module type was detected.\n");
33338eb6488eSEric Joyner 			return;
33348eb6488eSEric Joyner 		}
33358eb6488eSEric Joyner 	}
33368eb6488eSEric Joyner 
33378eb6488eSEric Joyner 	/* Set moderation on the Link interrupt */
3338b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(hw, IXGBE_EITR(sc->vector), IXGBE_LINK_ITR);
33398eb6488eSEric Joyner 
3340c19c7afeSEric Joyner 	/* Enable power to the phy. */
334179b36ec9SKevin Bowling 	ixgbe_set_phy_power(hw, true);
3342c19c7afeSEric Joyner 
33438eb6488eSEric Joyner 	/* Config/Enable Link */
3344b2c1e8e6SEric Joyner 	ixgbe_config_link(ctx);
33458eb6488eSEric Joyner 
33468eb6488eSEric Joyner 	/* Hardware Packet Buffer & Flow Control setup */
3347b1d5caf3SKevin Bowling 	ixgbe_config_delay_values(sc);
33488eb6488eSEric Joyner 
33498eb6488eSEric Joyner 	/* Initialize the FC settings */
33508eb6488eSEric Joyner 	ixgbe_start_hw(hw);
33518eb6488eSEric Joyner 
33528eb6488eSEric Joyner 	/* Set up VLAN support and filter */
3353c19c7afeSEric Joyner 	ixgbe_setup_vlan_hw_support(ctx);
33548eb6488eSEric Joyner 
33558eb6488eSEric Joyner 	/* Setup DMA Coalescing */
3356b1d5caf3SKevin Bowling 	ixgbe_config_dmac(sc);
33578eb6488eSEric Joyner 
33588eb6488eSEric Joyner 	/* And now turn on interrupts */
3359c19c7afeSEric Joyner 	ixgbe_if_enable_intr(ctx);
33608eb6488eSEric Joyner 
33618eb6488eSEric Joyner 	/* Enable the use of the MBX by the VF's */
3362b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_SRIOV) {
33638eb6488eSEric Joyner 		ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
33648eb6488eSEric Joyner 		ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
33658eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
33668eb6488eSEric Joyner 	}
33678eb6488eSEric Joyner 
33688eb6488eSEric Joyner } /* ixgbe_init_locked */
33698eb6488eSEric Joyner 
33708eb6488eSEric Joyner /************************************************************************
33718eb6488eSEric Joyner  * ixgbe_set_ivar
33728eb6488eSEric Joyner  *
33738eb6488eSEric Joyner  *   Setup the correct IVAR register for a particular MSI-X interrupt
33748eb6488eSEric Joyner  *     (yes this is all very magic and confusing :)
33758eb6488eSEric Joyner  *    - entry is the register array entry
33768eb6488eSEric Joyner  *    - vector is the MSI-X vector for this queue
33778eb6488eSEric Joyner  *    - type is RX/TX/MISC
33788eb6488eSEric Joyner  ************************************************************************/
33798eb6488eSEric Joyner static void
3380b1d5caf3SKevin Bowling ixgbe_set_ivar(struct ixgbe_softc *sc, u8 entry, u8 vector, s8 type)
33818eb6488eSEric Joyner {
3382b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
33838eb6488eSEric Joyner 	u32 ivar, index;
33848eb6488eSEric Joyner 
33858eb6488eSEric Joyner 	vector |= IXGBE_IVAR_ALLOC_VAL;
33868eb6488eSEric Joyner 
33878eb6488eSEric Joyner 	switch (hw->mac.type) {
33888eb6488eSEric Joyner 	case ixgbe_mac_82598EB:
33898eb6488eSEric Joyner 		if (type == -1)
33908eb6488eSEric Joyner 			entry = IXGBE_IVAR_OTHER_CAUSES_INDEX;
33918eb6488eSEric Joyner 		else
33928eb6488eSEric Joyner 			entry += (type * 64);
33938eb6488eSEric Joyner 		index = (entry >> 2) & 0x1F;
33948eb6488eSEric Joyner 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
33958eb6488eSEric Joyner 		ivar &= ~(0xFF << (8 * (entry & 0x3)));
33968eb6488eSEric Joyner 		ivar |= (vector << (8 * (entry & 0x3)));
3397b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_IVAR(index), ivar);
33988eb6488eSEric Joyner 		break;
33998eb6488eSEric Joyner 	case ixgbe_mac_82599EB:
34008eb6488eSEric Joyner 	case ixgbe_mac_X540:
34018eb6488eSEric Joyner 	case ixgbe_mac_X550:
34028eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
34038eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
34048eb6488eSEric Joyner 		if (type == -1) { /* MISC IVAR */
34058eb6488eSEric Joyner 			index = (entry & 1) * 8;
34068eb6488eSEric Joyner 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
34078eb6488eSEric Joyner 			ivar &= ~(0xFF << index);
34088eb6488eSEric Joyner 			ivar |= (vector << index);
34098eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
34108eb6488eSEric Joyner 		} else {          /* RX/TX IVARS */
34118eb6488eSEric Joyner 			index = (16 * (entry & 1)) + (8 * type);
34128eb6488eSEric Joyner 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1));
34138eb6488eSEric Joyner 			ivar &= ~(0xFF << index);
34148eb6488eSEric Joyner 			ivar |= (vector << index);
34158eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar);
34168eb6488eSEric Joyner 		}
34178eb6488eSEric Joyner 	default:
34188eb6488eSEric Joyner 		break;
34198eb6488eSEric Joyner 	}
34208eb6488eSEric Joyner } /* ixgbe_set_ivar */
34218eb6488eSEric Joyner 
34228eb6488eSEric Joyner /************************************************************************
34238eb6488eSEric Joyner  * ixgbe_configure_ivars
34248eb6488eSEric Joyner  ************************************************************************/
34258eb6488eSEric Joyner static void
3426b1d5caf3SKevin Bowling ixgbe_configure_ivars(struct ixgbe_softc *sc)
34278eb6488eSEric Joyner {
3428b1d5caf3SKevin Bowling 	struct ix_rx_queue *rx_que = sc->rx_queues;
3429b1d5caf3SKevin Bowling 	struct ix_tx_queue *tx_que = sc->tx_queues;
34308eb6488eSEric Joyner 	u32 newitr;
34318eb6488eSEric Joyner 
34328eb6488eSEric Joyner 	if (ixgbe_max_interrupt_rate > 0)
34338eb6488eSEric Joyner 		newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8;
34348eb6488eSEric Joyner 	else {
34358eb6488eSEric Joyner 		/*
34368eb6488eSEric Joyner 		 * Disable DMA coalescing if interrupt moderation is
34378eb6488eSEric Joyner 		 * disabled.
34388eb6488eSEric Joyner 		 */
3439b1d5caf3SKevin Bowling 		sc->dmac = 0;
34408eb6488eSEric Joyner 		newitr = 0;
34418eb6488eSEric Joyner 	}
34428eb6488eSEric Joyner 
3443b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++, rx_que++) {
3444c19c7afeSEric Joyner 		struct rx_ring *rxr = &rx_que->rxr;
34458eb6488eSEric Joyner 
3446c19c7afeSEric Joyner 		/* First the RX queue entry */
3447b1d5caf3SKevin Bowling 		ixgbe_set_ivar(sc, rxr->me, rx_que->msix, 0);
3448c19c7afeSEric Joyner 
3449c19c7afeSEric Joyner 		/* Set an Initial EITR value */
3450b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(rx_que->msix), newitr);
3451c19c7afeSEric Joyner 	}
3452b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_tx_queues; i++, tx_que++) {
3453c19c7afeSEric Joyner 		struct tx_ring *txr = &tx_que->txr;
3454c19c7afeSEric Joyner 
3455c19c7afeSEric Joyner 		/* ... and the TX */
3456b1d5caf3SKevin Bowling 		ixgbe_set_ivar(sc, txr->me, tx_que->msix, 1);
3457c19c7afeSEric Joyner 	}
34588eb6488eSEric Joyner 	/* For the Link interrupt */
3459b1d5caf3SKevin Bowling 	ixgbe_set_ivar(sc, 1, sc->vector, -1);
34608eb6488eSEric Joyner } /* ixgbe_configure_ivars */
34618eb6488eSEric Joyner 
34628eb6488eSEric Joyner /************************************************************************
34638eb6488eSEric Joyner  * ixgbe_config_gpie
34648eb6488eSEric Joyner  ************************************************************************/
34658eb6488eSEric Joyner static void
3466b1d5caf3SKevin Bowling ixgbe_config_gpie(struct ixgbe_softc *sc)
34678eb6488eSEric Joyner {
3468b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
34698eb6488eSEric Joyner 	u32 gpie;
34708eb6488eSEric Joyner 
34718eb6488eSEric Joyner 	gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
34728eb6488eSEric Joyner 
3473b1d5caf3SKevin Bowling 	if (sc->intr_type == IFLIB_INTR_MSIX) {
34748eb6488eSEric Joyner 		/* Enable Enhanced MSI-X mode */
3475*c58d34ddSKevin Bowling 		gpie |= IXGBE_GPIE_MSIX_MODE |
3476*c58d34ddSKevin Bowling 		    IXGBE_GPIE_EIAME |
3477*c58d34ddSKevin Bowling 		    IXGBE_GPIE_PBA_SUPPORT |
3478*c58d34ddSKevin Bowling 		    IXGBE_GPIE_OCD;
34798eb6488eSEric Joyner 	}
34808eb6488eSEric Joyner 
34818eb6488eSEric Joyner 	/* Fan Failure Interrupt */
3482b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_FAN_FAIL)
34838eb6488eSEric Joyner 		gpie |= IXGBE_SDP1_GPIEN;
34848eb6488eSEric Joyner 
34858eb6488eSEric Joyner 	/* Thermal Sensor Interrupt */
3486b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_TEMP_SENSOR)
34878eb6488eSEric Joyner 		gpie |= IXGBE_SDP0_GPIEN_X540;
34888eb6488eSEric Joyner 
34898eb6488eSEric Joyner 	/* Link detection */
34908eb6488eSEric Joyner 	switch (hw->mac.type) {
34918eb6488eSEric Joyner 	case ixgbe_mac_82599EB:
34928eb6488eSEric Joyner 		gpie |= IXGBE_SDP1_GPIEN | IXGBE_SDP2_GPIEN;
34938eb6488eSEric Joyner 		break;
34948eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
34958eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
34968eb6488eSEric Joyner 		gpie |= IXGBE_SDP0_GPIEN_X540;
34978eb6488eSEric Joyner 		break;
34988eb6488eSEric Joyner 	default:
34998eb6488eSEric Joyner 		break;
35008eb6488eSEric Joyner 	}
35018eb6488eSEric Joyner 
35028eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
35038eb6488eSEric Joyner 
35048eb6488eSEric Joyner } /* ixgbe_config_gpie */
35058eb6488eSEric Joyner 
35068eb6488eSEric Joyner /************************************************************************
35078eb6488eSEric Joyner  * ixgbe_config_delay_values
35088eb6488eSEric Joyner  *
3509b1d5caf3SKevin Bowling  *   Requires sc->max_frame_size to be set.
35108eb6488eSEric Joyner  ************************************************************************/
35118eb6488eSEric Joyner static void
3512b1d5caf3SKevin Bowling ixgbe_config_delay_values(struct ixgbe_softc *sc)
35138eb6488eSEric Joyner {
3514b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
35158eb6488eSEric Joyner 	u32 rxpb, frame, size, tmp;
35168eb6488eSEric Joyner 
3517b1d5caf3SKevin Bowling 	frame = sc->max_frame_size;
35188eb6488eSEric Joyner 
35198eb6488eSEric Joyner 	/* Calculate High Water */
35208eb6488eSEric Joyner 	switch (hw->mac.type) {
35218eb6488eSEric Joyner 	case ixgbe_mac_X540:
35228eb6488eSEric Joyner 	case ixgbe_mac_X550:
35238eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
35248eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
35258eb6488eSEric Joyner 		tmp = IXGBE_DV_X540(frame, frame);
35268eb6488eSEric Joyner 		break;
35278eb6488eSEric Joyner 	default:
35288eb6488eSEric Joyner 		tmp = IXGBE_DV(frame, frame);
35298eb6488eSEric Joyner 		break;
35308eb6488eSEric Joyner 	}
35318eb6488eSEric Joyner 	size = IXGBE_BT2KB(tmp);
35328eb6488eSEric Joyner 	rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10;
35338eb6488eSEric Joyner 	hw->fc.high_water[0] = rxpb - size;
35348eb6488eSEric Joyner 
35358eb6488eSEric Joyner 	/* Now calculate Low Water */
35368eb6488eSEric Joyner 	switch (hw->mac.type) {
35378eb6488eSEric Joyner 	case ixgbe_mac_X540:
35388eb6488eSEric Joyner 	case ixgbe_mac_X550:
35398eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
35408eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
35418eb6488eSEric Joyner 		tmp = IXGBE_LOW_DV_X540(frame);
35428eb6488eSEric Joyner 		break;
35438eb6488eSEric Joyner 	default:
35448eb6488eSEric Joyner 		tmp = IXGBE_LOW_DV(frame);
35458eb6488eSEric Joyner 		break;
35468eb6488eSEric Joyner 	}
35478eb6488eSEric Joyner 	hw->fc.low_water[0] = IXGBE_BT2KB(tmp);
35488eb6488eSEric Joyner 
35498eb6488eSEric Joyner 	hw->fc.pause_time = IXGBE_FC_PAUSE;
355079b36ec9SKevin Bowling 	hw->fc.send_xon = true;
35518eb6488eSEric Joyner } /* ixgbe_config_delay_values */
35528eb6488eSEric Joyner 
35538eb6488eSEric Joyner /************************************************************************
35548eb6488eSEric Joyner  * ixgbe_set_multi - Multicast Update
35558eb6488eSEric Joyner  *
35568eb6488eSEric Joyner  *   Called whenever multicast address list is updated.
35578eb6488eSEric Joyner  ************************************************************************/
3558ba76aa63SGleb Smirnoff static u_int
355921afed4bSKevin Bowling ixgbe_mc_filter_apply(void *arg, struct sockaddr_dl *sdl, u_int idx)
35608eb6488eSEric Joyner {
3561b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = arg;
3562b1d5caf3SKevin Bowling 	struct ixgbe_mc_addr *mta = sc->mta;
3563c19c7afeSEric Joyner 
356421afed4bSKevin Bowling 	if (idx == MAX_NUM_MULTICAST_ADDRESSES)
3565c19c7afeSEric Joyner 		return (0);
356621afed4bSKevin Bowling 	bcopy(LLADDR(sdl), mta[idx].addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
3567b1d5caf3SKevin Bowling 	mta[idx].vmdq = sc->pool;
3568c19c7afeSEric Joyner 
3569c19c7afeSEric Joyner 	return (1);
3570c19c7afeSEric Joyner } /* ixgbe_mc_filter_apply */
3571c19c7afeSEric Joyner 
3572c19c7afeSEric Joyner static void
3573c19c7afeSEric Joyner ixgbe_if_multi_set(if_ctx_t ctx)
3574c19c7afeSEric Joyner {
3575b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
35768eb6488eSEric Joyner 	struct ixgbe_mc_addr *mta;
3577ff06a8dbSJustin Hibbits 	if_t ifp = iflib_get_ifp(ctx);
35788eb6488eSEric Joyner 	u8 *update_ptr;
35798eb6488eSEric Joyner 	u32 fctrl;
3580ba76aa63SGleb Smirnoff 	u_int mcnt;
35818eb6488eSEric Joyner 
3582c19c7afeSEric Joyner 	IOCTL_DEBUGOUT("ixgbe_if_multi_set: begin");
35838eb6488eSEric Joyner 
3584b1d5caf3SKevin Bowling 	mta = sc->mta;
35858eb6488eSEric Joyner 	bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES);
35868eb6488eSEric Joyner 
3587*c58d34ddSKevin Bowling 	mcnt = if_foreach_llmaddr(iflib_get_ifp(ctx), ixgbe_mc_filter_apply,
3588*c58d34ddSKevin Bowling 	    sc);
35898eb6488eSEric Joyner 
3590395cc55dSKevin Bowling 	if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) {
3591395cc55dSKevin Bowling 		update_ptr = (u8 *)mta;
3592395cc55dSKevin Bowling 		ixgbe_update_mc_addr_list(&sc->hw, update_ptr, mcnt,
3593395cc55dSKevin Bowling 		    ixgbe_mc_array_itr, true);
3594395cc55dSKevin Bowling 	}
3595395cc55dSKevin Bowling 
3596b1d5caf3SKevin Bowling 	fctrl = IXGBE_READ_REG(&sc->hw, IXGBE_FCTRL);
3597deecaa14SKevin Bowling 
3598ff06a8dbSJustin Hibbits 	if (if_getflags(ifp) & IFF_PROMISC)
35998eb6488eSEric Joyner 		fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
36008eb6488eSEric Joyner 	else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES ||
3601ff06a8dbSJustin Hibbits 	    if_getflags(ifp) & IFF_ALLMULTI) {
36028eb6488eSEric Joyner 		fctrl |= IXGBE_FCTRL_MPE;
36038eb6488eSEric Joyner 		fctrl &= ~IXGBE_FCTRL_UPE;
36048eb6488eSEric Joyner 	} else
36058eb6488eSEric Joyner 		fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
36068eb6488eSEric Joyner 
3607b1d5caf3SKevin Bowling 	IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, fctrl);
3608c19c7afeSEric Joyner } /* ixgbe_if_multi_set */
36098eb6488eSEric Joyner 
36108eb6488eSEric Joyner /************************************************************************
36118eb6488eSEric Joyner  * ixgbe_mc_array_itr
36128eb6488eSEric Joyner  *
36138eb6488eSEric Joyner  *   An iterator function needed by the multicast shared code.
36148eb6488eSEric Joyner  *   It feeds the shared code routine the addresses in the
36158eb6488eSEric Joyner  *   array of ixgbe_set_multi() one by one.
36168eb6488eSEric Joyner  ************************************************************************/
36178eb6488eSEric Joyner static u8 *
36188eb6488eSEric Joyner ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq)
36198eb6488eSEric Joyner {
36208eb6488eSEric Joyner 	struct ixgbe_mc_addr *mta;
36218eb6488eSEric Joyner 
36228eb6488eSEric Joyner 	mta = (struct ixgbe_mc_addr *)*update_ptr;
36238eb6488eSEric Joyner 	*vmdq = mta->vmdq;
36248eb6488eSEric Joyner 
36258eb6488eSEric Joyner 	*update_ptr = (u8*)(mta + 1);
36268eb6488eSEric Joyner 
36278eb6488eSEric Joyner 	return (mta->addr);
36288eb6488eSEric Joyner } /* ixgbe_mc_array_itr */
36298eb6488eSEric Joyner 
36308eb6488eSEric Joyner /************************************************************************
36318eb6488eSEric Joyner  * ixgbe_local_timer - Timer routine
36328eb6488eSEric Joyner  *
36338eb6488eSEric Joyner  *   Checks for link status, updates statistics,
36348eb6488eSEric Joyner  *   and runs the watchdog check.
36358eb6488eSEric Joyner  ************************************************************************/
36368eb6488eSEric Joyner static void
3637c19c7afeSEric Joyner ixgbe_if_timer(if_ctx_t ctx, uint16_t qid)
36388eb6488eSEric Joyner {
3639b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
36408eb6488eSEric Joyner 
3641c19c7afeSEric Joyner 	if (qid != 0)
3642c19c7afeSEric Joyner 		return;
36438eb6488eSEric Joyner 
36448eb6488eSEric Joyner 	/* Check for pluggable optics */
3645b1d5caf3SKevin Bowling 	if (sc->sfp_probe)
3646c19c7afeSEric Joyner 		if (!ixgbe_sfp_probe(ctx))
3647c19c7afeSEric Joyner 			return; /* Nothing to do */
36488eb6488eSEric Joyner 
3649b1d5caf3SKevin Bowling 	ixgbe_check_link(&sc->hw, &sc->link_speed, &sc->link_up, 0);
36508eb6488eSEric Joyner 
3651c19c7afeSEric Joyner 	/* Fire off the adminq task */
3652c19c7afeSEric Joyner 	iflib_admin_intr_deferred(ctx);
36538eb6488eSEric Joyner 
3654c19c7afeSEric Joyner } /* ixgbe_if_timer */
36558eb6488eSEric Joyner 
36568eb6488eSEric Joyner /************************************************************************
3657f72de14eSKevin Bowling  * ixgbe_fw_mode_timer - FW mode timer routine
3658f72de14eSKevin Bowling  ************************************************************************/
3659f72de14eSKevin Bowling static void
3660f72de14eSKevin Bowling ixgbe_fw_mode_timer(void *arg)
3661f72de14eSKevin Bowling {
3662f72de14eSKevin Bowling 	struct ixgbe_softc *sc = arg;
3663f72de14eSKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3664f72de14eSKevin Bowling 
3665f72de14eSKevin Bowling 	if (ixgbe_fw_recovery_mode(hw)) {
3666f72de14eSKevin Bowling 		if (atomic_cmpset_acq_int(&sc->recovery_mode, 0, 1)) {
3667f72de14eSKevin Bowling 			/* Firmware error detected, entering recovery mode */
3668*c58d34ddSKevin Bowling 			device_printf(sc->dev,
3669*c58d34ddSKevin Bowling 			    "Firmware recovery mode detected. Limiting"
3670*c58d34ddSKevin Bowling 			    " functionality. Refer to the Intel(R) Ethernet"
3671*c58d34ddSKevin Bowling 			    " Adapters and Devices User Guide for details on"
3672*c58d34ddSKevin Bowling 			    " firmware recovery mode.\n");
3673f72de14eSKevin Bowling 
3674f72de14eSKevin Bowling 			if (hw->adapter_stopped == FALSE)
3675f72de14eSKevin Bowling 				ixgbe_if_stop(sc->ctx);
3676f72de14eSKevin Bowling 		}
3677f72de14eSKevin Bowling 	} else
3678f72de14eSKevin Bowling 		atomic_cmpset_acq_int(&sc->recovery_mode, 1, 0);
3679f72de14eSKevin Bowling 
3680f72de14eSKevin Bowling 
3681f72de14eSKevin Bowling 	callout_reset(&sc->fw_mode_timer, hz,
3682f72de14eSKevin Bowling 	    ixgbe_fw_mode_timer, sc);
3683f72de14eSKevin Bowling } /* ixgbe_fw_mode_timer */
3684f72de14eSKevin Bowling 
3685f72de14eSKevin Bowling /************************************************************************
36868eb6488eSEric Joyner  * ixgbe_sfp_probe
36878eb6488eSEric Joyner  *
36888eb6488eSEric Joyner  *   Determine if a port had optics inserted.
36898eb6488eSEric Joyner  ************************************************************************/
36908eb6488eSEric Joyner static bool
3691c19c7afeSEric Joyner ixgbe_sfp_probe(if_ctx_t ctx)
36928eb6488eSEric Joyner {
3693b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3694b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3695c19c7afeSEric Joyner 	device_t dev = iflib_get_dev(ctx);
369679b36ec9SKevin Bowling 	bool result = false;
36978eb6488eSEric Joyner 
36988eb6488eSEric Joyner 	if ((hw->phy.type == ixgbe_phy_nl) &&
36998eb6488eSEric Joyner 	    (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
37008eb6488eSEric Joyner 		s32 ret = hw->phy.ops.identify_sfp(hw);
37018eb6488eSEric Joyner 		if (ret)
37028eb6488eSEric Joyner 			goto out;
37038eb6488eSEric Joyner 		ret = hw->phy.ops.reset(hw);
3704b1d5caf3SKevin Bowling 		sc->sfp_probe = false;
37058eb6488eSEric Joyner 		if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
3706*c58d34ddSKevin Bowling 			device_printf(dev,
3707*c58d34ddSKevin Bowling 			    "Unsupported SFP+ module detected!");
37088eb6488eSEric Joyner 			device_printf(dev,
37098eb6488eSEric Joyner 			    "Reload driver with supported module.\n");
37108eb6488eSEric Joyner 			goto out;
37118eb6488eSEric Joyner 		} else
37128eb6488eSEric Joyner 			device_printf(dev, "SFP+ module detected!\n");
37138eb6488eSEric Joyner 		/* We now have supported optics */
371479b36ec9SKevin Bowling 		result = true;
37158eb6488eSEric Joyner 	}
37168eb6488eSEric Joyner out:
37178eb6488eSEric Joyner 
37188eb6488eSEric Joyner 	return (result);
37198eb6488eSEric Joyner } /* ixgbe_sfp_probe */
37208eb6488eSEric Joyner 
37218eb6488eSEric Joyner /************************************************************************
37228eb6488eSEric Joyner  * ixgbe_handle_mod - Tasklet for SFP module interrupts
37238eb6488eSEric Joyner  ************************************************************************/
37248eb6488eSEric Joyner static void
3725c19c7afeSEric Joyner ixgbe_handle_mod(void *context)
37268eb6488eSEric Joyner {
3727c19c7afeSEric Joyner 	if_ctx_t ctx = context;
3728b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3729b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3730c19c7afeSEric Joyner 	device_t dev = iflib_get_dev(ctx);
37318eb6488eSEric Joyner 	u32 err, cage_full = 0;
37328eb6488eSEric Joyner 
3733b1d5caf3SKevin Bowling 	if (sc->hw.need_crosstalk_fix) {
37348eb6488eSEric Joyner 		switch (hw->mac.type) {
37358eb6488eSEric Joyner 		case ixgbe_mac_82599EB:
37368eb6488eSEric Joyner 			cage_full = IXGBE_READ_REG(hw, IXGBE_ESDP) &
37378eb6488eSEric Joyner 			    IXGBE_ESDP_SDP2;
37388eb6488eSEric Joyner 			break;
37398eb6488eSEric Joyner 		case ixgbe_mac_X550EM_x:
37408eb6488eSEric Joyner 		case ixgbe_mac_X550EM_a:
37418eb6488eSEric Joyner 			cage_full = IXGBE_READ_REG(hw, IXGBE_ESDP) &
37428eb6488eSEric Joyner 			    IXGBE_ESDP_SDP0;
37438eb6488eSEric Joyner 			break;
37448eb6488eSEric Joyner 		default:
37458eb6488eSEric Joyner 			break;
37468eb6488eSEric Joyner 		}
37478eb6488eSEric Joyner 
37488eb6488eSEric Joyner 		if (!cage_full)
3749c19c7afeSEric Joyner 			goto handle_mod_out;
37508eb6488eSEric Joyner 	}
37518eb6488eSEric Joyner 
37528eb6488eSEric Joyner 	err = hw->phy.ops.identify_sfp(hw);
37538eb6488eSEric Joyner 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
37548eb6488eSEric Joyner 		device_printf(dev,
37558eb6488eSEric Joyner 		    "Unsupported SFP+ module type was detected.\n");
3756c19c7afeSEric Joyner 		goto handle_mod_out;
37578eb6488eSEric Joyner 	}
37588eb6488eSEric Joyner 
3759c19c7afeSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB)
3760c19c7afeSEric Joyner 		err = hw->phy.ops.reset(hw);
3761c19c7afeSEric Joyner 	else
37628eb6488eSEric Joyner 		err = hw->mac.ops.setup_sfp(hw);
3763c19c7afeSEric Joyner 
37648eb6488eSEric Joyner 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
37658eb6488eSEric Joyner 		device_printf(dev,
37668eb6488eSEric Joyner 		    "Setup failure - unsupported SFP+ module type.\n");
3767c19c7afeSEric Joyner 		goto handle_mod_out;
37688eb6488eSEric Joyner 	}
3769b1d5caf3SKevin Bowling 	sc->task_requests |= IXGBE_REQUEST_TASK_MSF;
3770c19c7afeSEric Joyner 	return;
3771c19c7afeSEric Joyner 
3772c19c7afeSEric Joyner handle_mod_out:
3773b1d5caf3SKevin Bowling 	sc->task_requests &= ~(IXGBE_REQUEST_TASK_MSF);
37748eb6488eSEric Joyner } /* ixgbe_handle_mod */
37758eb6488eSEric Joyner 
37768eb6488eSEric Joyner 
37778eb6488eSEric Joyner /************************************************************************
37788eb6488eSEric Joyner  * ixgbe_handle_msf - Tasklet for MSF (multispeed fiber) interrupts
37798eb6488eSEric Joyner  ************************************************************************/
37808eb6488eSEric Joyner static void
3781c19c7afeSEric Joyner ixgbe_handle_msf(void *context)
37828eb6488eSEric Joyner {
3783c19c7afeSEric Joyner 	if_ctx_t ctx = context;
3784b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3785b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
37868eb6488eSEric Joyner 	u32 autoneg;
37878eb6488eSEric Joyner 	bool negotiate;
37888eb6488eSEric Joyner 
37898eb6488eSEric Joyner 	/* get_supported_phy_layer will call hw->phy.ops.identify_sfp() */
3790b1d5caf3SKevin Bowling 	sc->phy_layer = ixgbe_get_supported_physical_layer(hw);
37918eb6488eSEric Joyner 
37928eb6488eSEric Joyner 	autoneg = hw->phy.autoneg_advertised;
37938eb6488eSEric Joyner 	if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
37948eb6488eSEric Joyner 		hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate);
37958eb6488eSEric Joyner 	if (hw->mac.ops.setup_link)
379679b36ec9SKevin Bowling 		hw->mac.ops.setup_link(hw, autoneg, true);
37978eb6488eSEric Joyner 
37988eb6488eSEric Joyner 	/* Adjust media types shown in ifconfig */
3799b1d5caf3SKevin Bowling 	ifmedia_removeall(sc->media);
3800b1d5caf3SKevin Bowling 	ixgbe_add_media_types(sc->ctx);
3801b1d5caf3SKevin Bowling 	ifmedia_set(sc->media, IFM_ETHER | IFM_AUTO);
38028eb6488eSEric Joyner } /* ixgbe_handle_msf */
38038eb6488eSEric Joyner 
38048eb6488eSEric Joyner /************************************************************************
38058eb6488eSEric Joyner  * ixgbe_handle_phy - Tasklet for external PHY interrupts
38068eb6488eSEric Joyner  ************************************************************************/
38078eb6488eSEric Joyner static void
3808c19c7afeSEric Joyner ixgbe_handle_phy(void *context)
38098eb6488eSEric Joyner {
3810c19c7afeSEric Joyner 	if_ctx_t ctx = context;
3811b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3812b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
38138eb6488eSEric Joyner 	int error;
38148eb6488eSEric Joyner 
38158eb6488eSEric Joyner 	error = hw->phy.ops.handle_lasi(hw);
38168eb6488eSEric Joyner 	if (error == IXGBE_ERR_OVERTEMP)
3817*c58d34ddSKevin Bowling 		device_printf(sc->dev,
3818*c58d34ddSKevin Bowling 		    "CRITICAL: EXTERNAL PHY OVER TEMP!!"
3819*c58d34ddSKevin Bowling 		    "  PHY will downshift to lower power state!\n");
38208eb6488eSEric Joyner 	else if (error)
3821b1d5caf3SKevin Bowling 		device_printf(sc->dev,
38228eb6488eSEric Joyner 		    "Error handling LASI interrupt: %d\n", error);
38238eb6488eSEric Joyner } /* ixgbe_handle_phy */
38248eb6488eSEric Joyner 
38258eb6488eSEric Joyner /************************************************************************
3826c19c7afeSEric Joyner  * ixgbe_if_stop - Stop the hardware
38278eb6488eSEric Joyner  *
38288eb6488eSEric Joyner  *   Disables all traffic on the adapter by issuing a
38298eb6488eSEric Joyner  *   global reset on the MAC and deallocates TX/RX buffers.
38308eb6488eSEric Joyner  ************************************************************************/
38318eb6488eSEric Joyner static void
3832c19c7afeSEric Joyner ixgbe_if_stop(if_ctx_t ctx)
38338eb6488eSEric Joyner {
3834b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3835b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
38368eb6488eSEric Joyner 
3837c19c7afeSEric Joyner 	INIT_DEBUGOUT("ixgbe_if_stop: begin\n");
38388eb6488eSEric Joyner 
38398eb6488eSEric Joyner 	ixgbe_reset_hw(hw);
384079b36ec9SKevin Bowling 	hw->adapter_stopped = false;
38418eb6488eSEric Joyner 	ixgbe_stop_adapter(hw);
38428eb6488eSEric Joyner 	if (hw->mac.type == ixgbe_mac_82599EB)
38438eb6488eSEric Joyner 		ixgbe_stop_mac_link_on_d3_82599(hw);
38448eb6488eSEric Joyner 	/* Turn off the laser - noop with no optics */
38458eb6488eSEric Joyner 	ixgbe_disable_tx_laser(hw);
38468eb6488eSEric Joyner 
38478eb6488eSEric Joyner 	/* Update the stack */
3848b1d5caf3SKevin Bowling 	sc->link_up = false;
3849c19c7afeSEric Joyner 	ixgbe_if_update_admin_status(ctx);
38508eb6488eSEric Joyner 
38518eb6488eSEric Joyner 	/* reprogram the RAR[0] in case user changed it. */
3852b1d5caf3SKevin Bowling 	ixgbe_set_rar(&sc->hw, 0, sc->hw.mac.addr, 0, IXGBE_RAH_AV);
38538eb6488eSEric Joyner 
38548eb6488eSEric Joyner 	return;
3855c19c7afeSEric Joyner } /* ixgbe_if_stop */
38568eb6488eSEric Joyner 
38578eb6488eSEric Joyner /************************************************************************
38588eb6488eSEric Joyner  * ixgbe_update_link_status - Update OS on link state
38598eb6488eSEric Joyner  *
38608eb6488eSEric Joyner  * Note: Only updates the OS on the cached link state.
38618eb6488eSEric Joyner  *       The real check of the hardware only happens with
38628eb6488eSEric Joyner  *       a link interrupt.
38638eb6488eSEric Joyner  ************************************************************************/
38648eb6488eSEric Joyner static void
3865c19c7afeSEric Joyner ixgbe_if_update_admin_status(if_ctx_t ctx)
38668eb6488eSEric Joyner {
3867b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3868c19c7afeSEric Joyner 	device_t dev = iflib_get_dev(ctx);
38698eb6488eSEric Joyner 
3870b1d5caf3SKevin Bowling 	if (sc->link_up) {
3871b1d5caf3SKevin Bowling 		if (sc->link_active == false) {
38728eb6488eSEric Joyner 			if (bootverbose)
38738eb6488eSEric Joyner 				device_printf(dev, "Link is up %d Gbps %s \n",
3874b1d5caf3SKevin Bowling 				    ((sc->link_speed == 128) ? 10 : 1),
38758eb6488eSEric Joyner 				    "Full Duplex");
3876b1d5caf3SKevin Bowling 			sc->link_active = true;
38778eb6488eSEric Joyner 			/* Update any Flow Control changes */
3878b1d5caf3SKevin Bowling 			ixgbe_fc_enable(&sc->hw);
38798eb6488eSEric Joyner 			/* Update DMA coalescing config */
3880b1d5caf3SKevin Bowling 			ixgbe_config_dmac(sc);
3881a0302c92SPiotr Pietruszewski 			iflib_link_state_change(ctx, LINK_STATE_UP,
38825ddb1aa3SPiotr Kubaj 			    ixgbe_link_speed_to_baudrate(sc->link_speed));
3883c19c7afeSEric Joyner 
3884b1d5caf3SKevin Bowling 			if (sc->feat_en & IXGBE_FEATURE_SRIOV)
3885b1d5caf3SKevin Bowling 				ixgbe_ping_all_vfs(sc);
38868eb6488eSEric Joyner 		}
38878eb6488eSEric Joyner 	} else { /* Link down */
3888b1d5caf3SKevin Bowling 		if (sc->link_active == true) {
38898eb6488eSEric Joyner 			if (bootverbose)
38908eb6488eSEric Joyner 				device_printf(dev, "Link is Down\n");
3891c19c7afeSEric Joyner 			iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
3892b1d5caf3SKevin Bowling 			sc->link_active = false;
3893b1d5caf3SKevin Bowling 			if (sc->feat_en & IXGBE_FEATURE_SRIOV)
3894b1d5caf3SKevin Bowling 				ixgbe_ping_all_vfs(sc);
38958eb6488eSEric Joyner 		}
38968eb6488eSEric Joyner 	}
38978eb6488eSEric Joyner 
3898b2c1e8e6SEric Joyner 	/* Handle task requests from msix_link() */
3899b1d5caf3SKevin Bowling 	if (sc->task_requests & IXGBE_REQUEST_TASK_MOD)
3900b2c1e8e6SEric Joyner 		ixgbe_handle_mod(ctx);
3901b1d5caf3SKevin Bowling 	if (sc->task_requests & IXGBE_REQUEST_TASK_MSF)
3902b2c1e8e6SEric Joyner 		ixgbe_handle_msf(ctx);
3903b1d5caf3SKevin Bowling 	if (sc->task_requests & IXGBE_REQUEST_TASK_MBX)
3904b2c1e8e6SEric Joyner 		ixgbe_handle_mbx(ctx);
3905b1d5caf3SKevin Bowling 	if (sc->task_requests & IXGBE_REQUEST_TASK_FDIR)
3906b2c1e8e6SEric Joyner 		ixgbe_reinit_fdir(ctx);
3907b1d5caf3SKevin Bowling 	if (sc->task_requests & IXGBE_REQUEST_TASK_PHY)
3908b2c1e8e6SEric Joyner 		ixgbe_handle_phy(ctx);
3909b1d5caf3SKevin Bowling 	sc->task_requests = 0;
3910c19c7afeSEric Joyner 
3911b1d5caf3SKevin Bowling 	ixgbe_update_stats_counters(sc);
3912c19c7afeSEric Joyner } /* ixgbe_if_update_admin_status */
39138eb6488eSEric Joyner 
39148eb6488eSEric Joyner /************************************************************************
39158eb6488eSEric Joyner  * ixgbe_config_dmac - Configure DMA Coalescing
39168eb6488eSEric Joyner  ************************************************************************/
39178eb6488eSEric Joyner static void
3918b1d5caf3SKevin Bowling ixgbe_config_dmac(struct ixgbe_softc *sc)
39198eb6488eSEric Joyner {
3920b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
39218eb6488eSEric Joyner 	struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config;
39228eb6488eSEric Joyner 
39238eb6488eSEric Joyner 	if (hw->mac.type < ixgbe_mac_X550 || !hw->mac.ops.dmac_config)
39248eb6488eSEric Joyner 		return;
39258eb6488eSEric Joyner 
3926b1d5caf3SKevin Bowling 	if (dcfg->watchdog_timer ^ sc->dmac ||
3927b1d5caf3SKevin Bowling 	    dcfg->link_speed ^ sc->link_speed) {
3928b1d5caf3SKevin Bowling 		dcfg->watchdog_timer = sc->dmac;
392979b36ec9SKevin Bowling 		dcfg->fcoe_en = false;
3930b1d5caf3SKevin Bowling 		dcfg->link_speed = sc->link_speed;
39318eb6488eSEric Joyner 		dcfg->num_tcs = 1;
39328eb6488eSEric Joyner 
39338eb6488eSEric Joyner 		INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n",
39348eb6488eSEric Joyner 		    dcfg->watchdog_timer, dcfg->link_speed);
39358eb6488eSEric Joyner 
39368eb6488eSEric Joyner 		hw->mac.ops.dmac_config(hw);
39378eb6488eSEric Joyner 	}
39388eb6488eSEric Joyner } /* ixgbe_config_dmac */
39398eb6488eSEric Joyner 
39408eb6488eSEric Joyner /************************************************************************
3941c19c7afeSEric Joyner  * ixgbe_if_enable_intr
39428eb6488eSEric Joyner  ************************************************************************/
3943c19c7afeSEric Joyner void
3944c19c7afeSEric Joyner ixgbe_if_enable_intr(if_ctx_t ctx)
39458eb6488eSEric Joyner {
3946b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
3947b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
3948b1d5caf3SKevin Bowling 	struct ix_rx_queue *que = sc->rx_queues;
39498eb6488eSEric Joyner 	u32 mask, fwsm;
39508eb6488eSEric Joyner 
39518eb6488eSEric Joyner 	mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
39528eb6488eSEric Joyner 
3953b1d5caf3SKevin Bowling 	switch (sc->hw.mac.type) {
39548eb6488eSEric Joyner 	case ixgbe_mac_82599EB:
39558eb6488eSEric Joyner 		mask |= IXGBE_EIMS_ECC;
3956b1d5caf3SKevin Bowling 		/* Temperature sensor on some scs */
39578eb6488eSEric Joyner 		mask |= IXGBE_EIMS_GPI_SDP0;
39588eb6488eSEric Joyner 		/* SFP+ (RX_LOS_N & MOD_ABS_N) */
39598eb6488eSEric Joyner 		mask |= IXGBE_EIMS_GPI_SDP1;
39608eb6488eSEric Joyner 		mask |= IXGBE_EIMS_GPI_SDP2;
39618eb6488eSEric Joyner 		break;
39628eb6488eSEric Joyner 	case ixgbe_mac_X540:
39638eb6488eSEric Joyner 		/* Detect if Thermal Sensor is enabled */
39648eb6488eSEric Joyner 		fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
39658eb6488eSEric Joyner 		if (fwsm & IXGBE_FWSM_TS_ENABLED)
39668eb6488eSEric Joyner 			mask |= IXGBE_EIMS_TS;
39678eb6488eSEric Joyner 		mask |= IXGBE_EIMS_ECC;
39688eb6488eSEric Joyner 		break;
39698eb6488eSEric Joyner 	case ixgbe_mac_X550:
39708eb6488eSEric Joyner 		/* MAC thermal sensor is automatically enabled */
39718eb6488eSEric Joyner 		mask |= IXGBE_EIMS_TS;
39728eb6488eSEric Joyner 		mask |= IXGBE_EIMS_ECC;
39738eb6488eSEric Joyner 		break;
39748eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
39758eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
39768eb6488eSEric Joyner 		/* Some devices use SDP0 for important information */
39778eb6488eSEric Joyner 		if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
39788eb6488eSEric Joyner 		    hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP ||
39798eb6488eSEric Joyner 		    hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N ||
39808eb6488eSEric Joyner 		    hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T)
39818eb6488eSEric Joyner 			mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw);
39828eb6488eSEric Joyner 		if (hw->phy.type == ixgbe_phy_x550em_ext_t)
39838eb6488eSEric Joyner 			mask |= IXGBE_EICR_GPI_SDP0_X540;
39848eb6488eSEric Joyner 		mask |= IXGBE_EIMS_ECC;
39858eb6488eSEric Joyner 		break;
39868eb6488eSEric Joyner 	default:
39878eb6488eSEric Joyner 		break;
39888eb6488eSEric Joyner 	}
39898eb6488eSEric Joyner 
39908eb6488eSEric Joyner 	/* Enable Fan Failure detection */
3991b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_FAN_FAIL)
39928eb6488eSEric Joyner 		mask |= IXGBE_EIMS_GPI_SDP1;
39938eb6488eSEric Joyner 	/* Enable SR-IOV */
3994b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_SRIOV)
39958eb6488eSEric Joyner 		mask |= IXGBE_EIMS_MAILBOX;
39968eb6488eSEric Joyner 	/* Enable Flow Director */
3997b1d5caf3SKevin Bowling 	if (sc->feat_en & IXGBE_FEATURE_FDIR)
39988eb6488eSEric Joyner 		mask |= IXGBE_EIMS_FLOW_DIR;
39998eb6488eSEric Joyner 
40008eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask);
40018eb6488eSEric Joyner 
40028eb6488eSEric Joyner 	/* With MSI-X we use auto clear */
4003b1d5caf3SKevin Bowling 	if (sc->intr_type == IFLIB_INTR_MSIX) {
40048eb6488eSEric Joyner 		mask = IXGBE_EIMS_ENABLE_MASK;
40058eb6488eSEric Joyner 		/* Don't autoclear Link */
40068eb6488eSEric Joyner 		mask &= ~IXGBE_EIMS_OTHER;
40078eb6488eSEric Joyner 		mask &= ~IXGBE_EIMS_LSC;
4008b1d5caf3SKevin Bowling 		if (sc->feat_cap & IXGBE_FEATURE_SRIOV)
40098eb6488eSEric Joyner 			mask &= ~IXGBE_EIMS_MAILBOX;
40108eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask);
40116f37f232SEric Joyner 	}
40126f37f232SEric Joyner 
4013758cc3dcSJack F Vogel 	/*
40148eb6488eSEric Joyner 	 * Now enable all queues, this is done separately to
40158eb6488eSEric Joyner 	 * allow for handling the extended (beyond 32) MSI-X
40168eb6488eSEric Joyner 	 * vectors that can be used by 82599
4017758cc3dcSJack F Vogel 	 */
4018b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++, que++)
4019b1d5caf3SKevin Bowling 		ixgbe_enable_queue(sc, que->msix);
40208eb6488eSEric Joyner 
40218eb6488eSEric Joyner 	IXGBE_WRITE_FLUSH(hw);
40228eb6488eSEric Joyner 
4023c19c7afeSEric Joyner } /* ixgbe_if_enable_intr */
40248eb6488eSEric Joyner 
40258eb6488eSEric Joyner /************************************************************************
40268eb6488eSEric Joyner  * ixgbe_disable_intr
40278eb6488eSEric Joyner  ************************************************************************/
4028758cc3dcSJack F Vogel static void
4029c19c7afeSEric Joyner ixgbe_if_disable_intr(if_ctx_t ctx)
4030758cc3dcSJack F Vogel {
4031b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
4032c19c7afeSEric Joyner 
4033b1d5caf3SKevin Bowling 	if (sc->intr_type == IFLIB_INTR_MSIX)
4034b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EIAC, 0);
4035b1d5caf3SKevin Bowling 	if (sc->hw.mac.type == ixgbe_mac_82598EB) {
4036b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC, ~0);
40378eb6488eSEric Joyner 	} else {
4038b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC, 0xFFFF0000);
4039b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC_EX(0), ~0);
4040b1d5caf3SKevin Bowling 		IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC_EX(1), ~0);
40418eb6488eSEric Joyner 	}
4042b1d5caf3SKevin Bowling 	IXGBE_WRITE_FLUSH(&sc->hw);
4043758cc3dcSJack F Vogel 
4044c19c7afeSEric Joyner } /* ixgbe_if_disable_intr */
40458eb6488eSEric Joyner 
40468eb6488eSEric Joyner /************************************************************************
4047b2c1e8e6SEric Joyner  * ixgbe_link_intr_enable
4048b2c1e8e6SEric Joyner  ************************************************************************/
4049b2c1e8e6SEric Joyner static void
4050b2c1e8e6SEric Joyner ixgbe_link_intr_enable(if_ctx_t ctx)
4051b2c1e8e6SEric Joyner {
4052*c58d34ddSKevin Bowling 	struct ixgbe_hw *hw =
4053*c58d34ddSKevin Bowling 	    &((struct ixgbe_softc *)iflib_get_softc(ctx))->hw;
4054b2c1e8e6SEric Joyner 
4055b2c1e8e6SEric Joyner 	/* Re-enable other interrupts */
4056b2c1e8e6SEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC);
4057b2c1e8e6SEric Joyner } /* ixgbe_link_intr_enable */
4058b2c1e8e6SEric Joyner 
4059b2c1e8e6SEric Joyner /************************************************************************
4060c19c7afeSEric Joyner  * ixgbe_if_rx_queue_intr_enable
4061c19c7afeSEric Joyner  ************************************************************************/
4062c19c7afeSEric Joyner static int
4063c19c7afeSEric Joyner ixgbe_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid)
4064c19c7afeSEric Joyner {
4065b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
4066b1d5caf3SKevin Bowling 	struct ix_rx_queue *que = &sc->rx_queues[rxqid];
4067c19c7afeSEric Joyner 
4068b1d5caf3SKevin Bowling 	ixgbe_enable_queue(sc, que->msix);
4069c19c7afeSEric Joyner 
4070c19c7afeSEric Joyner 	return (0);
4071c19c7afeSEric Joyner } /* ixgbe_if_rx_queue_intr_enable */
4072c19c7afeSEric Joyner 
4073c19c7afeSEric Joyner /************************************************************************
4074c19c7afeSEric Joyner  * ixgbe_enable_queue
40758eb6488eSEric Joyner  ************************************************************************/
40768eb6488eSEric Joyner static void
4077b1d5caf3SKevin Bowling ixgbe_enable_queue(struct ixgbe_softc *sc, u32 vector)
40788eb6488eSEric Joyner {
4079b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
40802dc2d580SEric Joyner 	u64 queue = 1ULL << vector;
4081c19c7afeSEric Joyner 	u32 mask;
4082758cc3dcSJack F Vogel 
4083c19c7afeSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB) {
4084c19c7afeSEric Joyner 		mask = (IXGBE_EIMS_RTX_QUEUE & queue);
4085c19c7afeSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask);
4086c19c7afeSEric Joyner 	} else {
4087c19c7afeSEric Joyner 		mask = (queue & 0xFFFFFFFF);
4088c19c7afeSEric Joyner 		if (mask)
4089c19c7afeSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask);
4090c19c7afeSEric Joyner 		mask = (queue >> 32);
4091c19c7afeSEric Joyner 		if (mask)
4092c19c7afeSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask);
4093c19c7afeSEric Joyner 	}
4094c19c7afeSEric Joyner } /* ixgbe_enable_queue */
4095c19c7afeSEric Joyner 
4096c19c7afeSEric Joyner /************************************************************************
4097c19c7afeSEric Joyner  * ixgbe_disable_queue
4098c19c7afeSEric Joyner  ************************************************************************/
4099c19c7afeSEric Joyner static void
4100b1d5caf3SKevin Bowling ixgbe_disable_queue(struct ixgbe_softc *sc, u32 vector)
4101c19c7afeSEric Joyner {
4102b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
41032dc2d580SEric Joyner 	u64 queue = 1ULL << vector;
4104c19c7afeSEric Joyner 	u32 mask;
4105c19c7afeSEric Joyner 
4106c19c7afeSEric Joyner 	if (hw->mac.type == ixgbe_mac_82598EB) {
4107c19c7afeSEric Joyner 		mask = (IXGBE_EIMS_RTX_QUEUE & queue);
4108c19c7afeSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask);
4109c19c7afeSEric Joyner 	} else {
4110c19c7afeSEric Joyner 		mask = (queue & 0xFFFFFFFF);
4111c19c7afeSEric Joyner 		if (mask)
4112c19c7afeSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask);
4113c19c7afeSEric Joyner 		mask = (queue >> 32);
4114c19c7afeSEric Joyner 		if (mask)
4115c19c7afeSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask);
4116c19c7afeSEric Joyner 	}
4117c19c7afeSEric Joyner } /* ixgbe_disable_queue */
4118c19c7afeSEric Joyner 
4119c19c7afeSEric Joyner /************************************************************************
4120c19c7afeSEric Joyner  * ixgbe_intr - Legacy Interrupt Service Routine
4121c19c7afeSEric Joyner  ************************************************************************/
4122c19c7afeSEric Joyner int
4123c19c7afeSEric Joyner ixgbe_intr(void *arg)
4124c19c7afeSEric Joyner {
4125b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = arg;
4126b1d5caf3SKevin Bowling 	struct ix_rx_queue *que = sc->rx_queues;
4127b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
4128b1d5caf3SKevin Bowling 	if_ctx_t ctx = sc->ctx;
4129c19c7afeSEric Joyner 	u32 eicr, eicr_mask;
4130758cc3dcSJack F Vogel 
41318eb6488eSEric Joyner 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
4132758cc3dcSJack F Vogel 
41338eb6488eSEric Joyner 	++que->irqs;
41348eb6488eSEric Joyner 	if (eicr == 0) {
4135c19c7afeSEric Joyner 		ixgbe_if_enable_intr(ctx);
4136c19c7afeSEric Joyner 		return (FILTER_HANDLED);
4137758cc3dcSJack F Vogel 	}
4138758cc3dcSJack F Vogel 
41398eb6488eSEric Joyner 	/* Check for fan failure */
4140f72de14eSKevin Bowling 	if ((sc->feat_en & IXGBE_FEATURE_FAN_FAIL) &&
4141c19c7afeSEric Joyner 	    (eicr & IXGBE_EICR_GPI_SDP1)) {
4142b1d5caf3SKevin Bowling 		device_printf(sc->dev,
4143c19c7afeSEric Joyner 		    "\nCRITICAL: FAN FAILURE!! REPLACE IMMEDIATELY!!\n");
4144*c58d34ddSKevin Bowling 		IXGBE_WRITE_REG(hw, IXGBE_EIMS,
4145*c58d34ddSKevin Bowling 		    IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
4146758cc3dcSJack F Vogel 	}
4147758cc3dcSJack F Vogel 
41488eb6488eSEric Joyner 	/* Link status change */
4149c19c7afeSEric Joyner 	if (eicr & IXGBE_EICR_LSC) {
4150c19c7afeSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC);
4151c19c7afeSEric Joyner 		iflib_admin_intr_deferred(ctx);
4152c19c7afeSEric Joyner 	}
41538eb6488eSEric Joyner 
41548eb6488eSEric Joyner 	if (ixgbe_is_sfp(hw)) {
41558eb6488eSEric Joyner 		/* Pluggable optics-related interrupt */
41568eb6488eSEric Joyner 		if (hw->mac.type >= ixgbe_mac_X540)
41578eb6488eSEric Joyner 			eicr_mask = IXGBE_EICR_GPI_SDP0_X540;
41588eb6488eSEric Joyner 		else
41598eb6488eSEric Joyner 			eicr_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw);
41608eb6488eSEric Joyner 
41618eb6488eSEric Joyner 		if (eicr & eicr_mask) {
41628eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask);
4163b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_MOD;
41648eb6488eSEric Joyner 		}
41658eb6488eSEric Joyner 
41668eb6488eSEric Joyner 		if ((hw->mac.type == ixgbe_mac_82599EB) &&
41678eb6488eSEric Joyner 		    (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) {
41688eb6488eSEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR,
41698eb6488eSEric Joyner 			    IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
4170b1d5caf3SKevin Bowling 			sc->task_requests |= IXGBE_REQUEST_TASK_MSF;
41718eb6488eSEric Joyner 		}
41728eb6488eSEric Joyner 	}
41738eb6488eSEric Joyner 
41748eb6488eSEric Joyner 	/* External PHY interrupt */
41758eb6488eSEric Joyner 	if ((hw->phy.type == ixgbe_phy_x550em_ext_t) &&
41768eb6488eSEric Joyner 	    (eicr & IXGBE_EICR_GPI_SDP0_X540))
4177b1d5caf3SKevin Bowling 		sc->task_requests |= IXGBE_REQUEST_TASK_PHY;
41788eb6488eSEric Joyner 
4179c19c7afeSEric Joyner 	return (FILTER_SCHEDULE_THREAD);
4180c19c7afeSEric Joyner } /* ixgbe_intr */
41818eb6488eSEric Joyner 
41828eb6488eSEric Joyner /************************************************************************
41838eb6488eSEric Joyner  * ixgbe_free_pci_resources
41848eb6488eSEric Joyner  ************************************************************************/
41858eb6488eSEric Joyner static void
4186c19c7afeSEric Joyner ixgbe_free_pci_resources(if_ctx_t ctx)
41878eb6488eSEric Joyner {
4188b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
4189b1d5caf3SKevin Bowling 	struct ix_rx_queue *que = sc->rx_queues;
4190c19c7afeSEric Joyner 	device_t dev = iflib_get_dev(ctx);
41918eb6488eSEric Joyner 
4192b97de13aSMarius Strobl 	/* Release all MSI-X queue resources */
4193b1d5caf3SKevin Bowling 	if (sc->intr_type == IFLIB_INTR_MSIX)
4194b1d5caf3SKevin Bowling 		iflib_irq_free(ctx, &sc->irq);
4195c19c7afeSEric Joyner 
4196c19c7afeSEric Joyner 	if (que != NULL) {
4197b1d5caf3SKevin Bowling 		for (int i = 0; i < sc->num_rx_queues; i++, que++) {
4198c19c7afeSEric Joyner 			iflib_irq_free(ctx, &que->que_irq);
4199c19c7afeSEric Joyner 		}
4200c19c7afeSEric Joyner 	}
42018eb6488eSEric Joyner 
4202b1d5caf3SKevin Bowling 	if (sc->pci_mem != NULL)
4203c19c7afeSEric Joyner 		bus_release_resource(dev, SYS_RES_MEMORY,
4204b1d5caf3SKevin Bowling 		    rman_get_rid(sc->pci_mem), sc->pci_mem);
42058eb6488eSEric Joyner } /* ixgbe_free_pci_resources */
42068eb6488eSEric Joyner 
42078eb6488eSEric Joyner /************************************************************************
42088eb6488eSEric Joyner  * ixgbe_sysctl_flowcntl
42098eb6488eSEric Joyner  *
42108eb6488eSEric Joyner  *   SYSCTL wrapper around setting Flow Control
42118eb6488eSEric Joyner  ************************************************************************/
4212758cc3dcSJack F Vogel static int
4213f2c4db54SSteven Hartland ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS)
4214758cc3dcSJack F Vogel {
4215b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc;
42168eb6488eSEric Joyner 	int error, fc;
4217758cc3dcSJack F Vogel 
4218b1d5caf3SKevin Bowling 	sc = (struct ixgbe_softc *)arg1;
4219b1d5caf3SKevin Bowling 	fc = sc->hw.fc.current_mode;
4220f2c4db54SSteven Hartland 
4221f2c4db54SSteven Hartland 	error = sysctl_handle_int(oidp, &fc, 0, req);
4222758cc3dcSJack F Vogel 	if ((error) || (req->newptr == NULL))
4223758cc3dcSJack F Vogel 		return (error);
4224758cc3dcSJack F Vogel 
4225758cc3dcSJack F Vogel 	/* Don't bother if it's not changed */
4226b1d5caf3SKevin Bowling 	if (fc == sc->hw.fc.current_mode)
4227758cc3dcSJack F Vogel 		return (0);
4228758cc3dcSJack F Vogel 
4229b1d5caf3SKevin Bowling 	return ixgbe_set_flowcntl(sc, fc);
42308eb6488eSEric Joyner } /* ixgbe_sysctl_flowcntl */
4231f2c4db54SSteven Hartland 
42328eb6488eSEric Joyner /************************************************************************
42338eb6488eSEric Joyner  * ixgbe_set_flowcntl - Set flow control
42348eb6488eSEric Joyner  *
42358eb6488eSEric Joyner  *   Flow control values:
42368eb6488eSEric Joyner  *     0 - off
42378eb6488eSEric Joyner  *     1 - rx pause
42388eb6488eSEric Joyner  *     2 - tx pause
42398eb6488eSEric Joyner  *     3 - full
42408eb6488eSEric Joyner  ************************************************************************/
4241f2c4db54SSteven Hartland static int
4242b1d5caf3SKevin Bowling ixgbe_set_flowcntl(struct ixgbe_softc *sc, int fc)
4243f2c4db54SSteven Hartland {
4244f2c4db54SSteven Hartland 	switch (fc) {
4245758cc3dcSJack F Vogel 	case ixgbe_fc_rx_pause:
4246758cc3dcSJack F Vogel 	case ixgbe_fc_tx_pause:
4247758cc3dcSJack F Vogel 	case ixgbe_fc_full:
4248b1d5caf3SKevin Bowling 		sc->hw.fc.requested_mode = fc;
4249b1d5caf3SKevin Bowling 		if (sc->num_rx_queues > 1)
4250b1d5caf3SKevin Bowling 			ixgbe_disable_rx_drop(sc);
4251758cc3dcSJack F Vogel 		break;
4252758cc3dcSJack F Vogel 	case ixgbe_fc_none:
4253b1d5caf3SKevin Bowling 		sc->hw.fc.requested_mode = ixgbe_fc_none;
4254b1d5caf3SKevin Bowling 		if (sc->num_rx_queues > 1)
4255b1d5caf3SKevin Bowling 			ixgbe_enable_rx_drop(sc);
4256758cc3dcSJack F Vogel 		break;
4257758cc3dcSJack F Vogel 	default:
4258758cc3dcSJack F Vogel 		return (EINVAL);
4259758cc3dcSJack F Vogel 	}
42608eb6488eSEric Joyner 
4261758cc3dcSJack F Vogel 	/* Don't autoneg if forcing a value */
4262b1d5caf3SKevin Bowling 	sc->hw.fc.disable_fc_autoneg = true;
4263b1d5caf3SKevin Bowling 	ixgbe_fc_enable(&sc->hw);
42648eb6488eSEric Joyner 
4265f2c4db54SSteven Hartland 	return (0);
42668eb6488eSEric Joyner } /* ixgbe_set_flowcntl */
42678eb6488eSEric Joyner 
42688eb6488eSEric Joyner /************************************************************************
42698eb6488eSEric Joyner  * ixgbe_enable_rx_drop
42708eb6488eSEric Joyner  *
42718eb6488eSEric Joyner  *   Enable the hardware to drop packets when the buffer is
42728eb6488eSEric Joyner  *   full. This is useful with multiqueue, so that no single
42738eb6488eSEric Joyner  *   queue being full stalls the entire RX engine. We only
42748eb6488eSEric Joyner  *   enable this when Multiqueue is enabled AND Flow Control
42758eb6488eSEric Joyner  *   is disabled.
42768eb6488eSEric Joyner  ************************************************************************/
42778eb6488eSEric Joyner static void
4278b1d5caf3SKevin Bowling ixgbe_enable_rx_drop(struct ixgbe_softc *sc)
42798eb6488eSEric Joyner {
4280b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
42818eb6488eSEric Joyner 	struct rx_ring *rxr;
42828eb6488eSEric Joyner 	u32 srrctl;
42838eb6488eSEric Joyner 
4284b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++) {
4285b1d5caf3SKevin Bowling 		rxr = &sc->rx_queues[i].rxr;
42868eb6488eSEric Joyner 		srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me));
42878eb6488eSEric Joyner 		srrctl |= IXGBE_SRRCTL_DROP_EN;
42888eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl);
4289758cc3dcSJack F Vogel 	}
4290758cc3dcSJack F Vogel 
42918eb6488eSEric Joyner 	/* enable drop for each vf */
4292b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_vfs; i++) {
42938eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_QDE,
4294*c58d34ddSKevin Bowling 		    (IXGBE_QDE_WRITE |
4295*c58d34ddSKevin Bowling 		    (i << IXGBE_QDE_IDX_SHIFT) |
42968eb6488eSEric Joyner 		    IXGBE_QDE_ENABLE));
42978eb6488eSEric Joyner 	}
42988eb6488eSEric Joyner } /* ixgbe_enable_rx_drop */
42998eb6488eSEric Joyner 
43008eb6488eSEric Joyner /************************************************************************
43018eb6488eSEric Joyner  * ixgbe_disable_rx_drop
43028eb6488eSEric Joyner  ************************************************************************/
43038eb6488eSEric Joyner static void
4304b1d5caf3SKevin Bowling ixgbe_disable_rx_drop(struct ixgbe_softc *sc)
43058eb6488eSEric Joyner {
4306b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
43078eb6488eSEric Joyner 	struct rx_ring *rxr;
43088eb6488eSEric Joyner 	u32 srrctl;
43098eb6488eSEric Joyner 
4310b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_rx_queues; i++) {
4311b1d5caf3SKevin Bowling 		rxr = &sc->rx_queues[i].rxr;
43128eb6488eSEric Joyner 		srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me));
43138eb6488eSEric Joyner 		srrctl &= ~IXGBE_SRRCTL_DROP_EN;
43148eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl);
43158eb6488eSEric Joyner 	}
43168eb6488eSEric Joyner 
43178eb6488eSEric Joyner 	/* disable drop for each vf */
4318b1d5caf3SKevin Bowling 	for (int i = 0; i < sc->num_vfs; i++) {
43198eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_QDE,
43208eb6488eSEric Joyner 		    (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT)));
43218eb6488eSEric Joyner 	}
43228eb6488eSEric Joyner } /* ixgbe_disable_rx_drop */
43238eb6488eSEric Joyner 
43248eb6488eSEric Joyner /************************************************************************
43258eb6488eSEric Joyner  * ixgbe_sysctl_advertise
43268eb6488eSEric Joyner  *
43278eb6488eSEric Joyner  *   SYSCTL wrapper around setting advertised speed
43288eb6488eSEric Joyner  ************************************************************************/
4329758cc3dcSJack F Vogel static int
4330f2c4db54SSteven Hartland ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS)
4331758cc3dcSJack F Vogel {
4332b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc;
43338eb6488eSEric Joyner 	int error, advertise;
4334758cc3dcSJack F Vogel 
4335b1d5caf3SKevin Bowling 	sc = (struct ixgbe_softc *)arg1;
4336f72de14eSKevin Bowling 	if (atomic_load_acq_int(&sc->recovery_mode))
4337f72de14eSKevin Bowling 		return (EPERM);
4338f72de14eSKevin Bowling 
4339b1d5caf3SKevin Bowling 	advertise = sc->advertise;
4340758cc3dcSJack F Vogel 
4341f2c4db54SSteven Hartland 	error = sysctl_handle_int(oidp, &advertise, 0, req);
4342758cc3dcSJack F Vogel 	if ((error) || (req->newptr == NULL))
4343758cc3dcSJack F Vogel 		return (error);
4344758cc3dcSJack F Vogel 
4345b1d5caf3SKevin Bowling 	return ixgbe_set_advertise(sc, advertise);
43468eb6488eSEric Joyner } /* ixgbe_sysctl_advertise */
4347f2c4db54SSteven Hartland 
43488eb6488eSEric Joyner /************************************************************************
43498eb6488eSEric Joyner  * ixgbe_set_advertise - Control advertised link speed
43508eb6488eSEric Joyner  *
43518eb6488eSEric Joyner  *   Flags:
43528eb6488eSEric Joyner  *     0x1  - advertise 100 Mb
43538eb6488eSEric Joyner  *     0x2  - advertise 1G
43548eb6488eSEric Joyner  *     0x4  - advertise 10G
43558eb6488eSEric Joyner  *     0x8  - advertise 10 Mb (yes, Mb)
4356d381c807SPiotr Pietruszewski  *     0x10 - advertise 2.5G (disabled by default)
4357d381c807SPiotr Pietruszewski  *     0x20 - advertise 5G (disabled by default)
4358d381c807SPiotr Pietruszewski  *
43598eb6488eSEric Joyner  ************************************************************************/
4360f2c4db54SSteven Hartland static int
4361b1d5caf3SKevin Bowling ixgbe_set_advertise(struct ixgbe_softc *sc, int advertise)
4362f2c4db54SSteven Hartland {
4363b1d5caf3SKevin Bowling 	device_t dev = iflib_get_dev(sc->ctx);
4364f2c4db54SSteven Hartland 	struct ixgbe_hw *hw;
43658eb6488eSEric Joyner 	ixgbe_link_speed speed = 0;
43668eb6488eSEric Joyner 	ixgbe_link_speed link_caps = 0;
43678eb6488eSEric Joyner 	s32 err = IXGBE_NOT_IMPLEMENTED;
436879b36ec9SKevin Bowling 	bool negotiate = false;
4369f2c4db54SSteven Hartland 
4370d775d23aSSteven Hartland 	/* Checks to validate new value */
4371b1d5caf3SKevin Bowling 	if (sc->advertise == advertise) /* no change */
4372d775d23aSSteven Hartland 		return (0);
4373d775d23aSSteven Hartland 
4374b1d5caf3SKevin Bowling 	hw = &sc->hw;
4375f2c4db54SSteven Hartland 
4376a9ca1c79SSean Bruno 	/* No speed changes for backplane media */
4377a9ca1c79SSean Bruno 	if (hw->phy.media_type == ixgbe_media_type_backplane)
4378a9ca1c79SSean Bruno 		return (ENODEV);
4379a9ca1c79SSean Bruno 
4380758cc3dcSJack F Vogel 	if (!((hw->phy.media_type == ixgbe_media_type_copper) ||
4381758cc3dcSJack F Vogel 	      (hw->phy.multispeed_fiber))) {
4382*c58d34ddSKevin Bowling 		device_printf(dev,
4383*c58d34ddSKevin Bowling 		    "Advertised speed can only be set on copper or multispeed"
4384*c58d34ddSKevin Bowling 		    " fiber media types.\n");
4385758cc3dcSJack F Vogel 		return (EINVAL);
4386758cc3dcSJack F Vogel 	}
4387758cc3dcSJack F Vogel 
4388d381c807SPiotr Pietruszewski 	if (advertise < 0x1 || advertise > 0x3F) {
4389*c58d34ddSKevin Bowling 		device_printf(dev,
4390*c58d34ddSKevin Bowling 		    "Invalid advertised speed; valid modes are 0x1 through"
4391*c58d34ddSKevin Bowling 		    " 0x3F\n");
4392758cc3dcSJack F Vogel 		return (EINVAL);
4393758cc3dcSJack F Vogel 	}
4394758cc3dcSJack F Vogel 
43958eb6488eSEric Joyner 	if (hw->mac.ops.get_link_capabilities) {
43968eb6488eSEric Joyner 		err = hw->mac.ops.get_link_capabilities(hw, &link_caps,
43978eb6488eSEric Joyner 		    &negotiate);
43988eb6488eSEric Joyner 		if (err != IXGBE_SUCCESS) {
4399*c58d34ddSKevin Bowling 			device_printf(dev,
4400*c58d34ddSKevin Bowling 			    "Unable to determine supported advertise speeds"
4401*c58d34ddSKevin Bowling 			    "\n");
44028eb6488eSEric Joyner 			return (ENODEV);
44038eb6488eSEric Joyner 		}
4404758cc3dcSJack F Vogel 	}
4405758cc3dcSJack F Vogel 
4406758cc3dcSJack F Vogel 	/* Set new value and report new advertised mode */
44078eb6488eSEric Joyner 	if (advertise & 0x1) {
44088eb6488eSEric Joyner 		if (!(link_caps & IXGBE_LINK_SPEED_100_FULL)) {
4409*c58d34ddSKevin Bowling 			device_printf(dev,
4410*c58d34ddSKevin Bowling 			    "Interface does not support 100Mb advertised"
4411*c58d34ddSKevin Bowling 			    " speed\n");
44128eb6488eSEric Joyner 			return (EINVAL);
44138eb6488eSEric Joyner 		}
4414758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_100_FULL;
44158eb6488eSEric Joyner 	}
44168eb6488eSEric Joyner 	if (advertise & 0x2) {
44178eb6488eSEric Joyner 		if (!(link_caps & IXGBE_LINK_SPEED_1GB_FULL)) {
4418*c58d34ddSKevin Bowling 			device_printf(dev,
4419*c58d34ddSKevin Bowling 			    "Interface does not support 1Gb advertised speed"
4420*c58d34ddSKevin Bowling 			    "\n");
44218eb6488eSEric Joyner 			return (EINVAL);
44228eb6488eSEric Joyner 		}
4423758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
44248eb6488eSEric Joyner 	}
44258eb6488eSEric Joyner 	if (advertise & 0x4) {
44268eb6488eSEric Joyner 		if (!(link_caps & IXGBE_LINK_SPEED_10GB_FULL)) {
4427*c58d34ddSKevin Bowling 			device_printf(dev,
4428*c58d34ddSKevin Bowling 			    "Interface does not support 10Gb advertised speed"
4429*c58d34ddSKevin Bowling 			    "\n");
44308eb6488eSEric Joyner 			return (EINVAL);
44318eb6488eSEric Joyner 		}
4432758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_10GB_FULL;
44338eb6488eSEric Joyner 	}
44348eb6488eSEric Joyner 	if (advertise & 0x8) {
44358eb6488eSEric Joyner 		if (!(link_caps & IXGBE_LINK_SPEED_10_FULL)) {
4436*c58d34ddSKevin Bowling 			device_printf(dev,
4437*c58d34ddSKevin Bowling 			    "Interface does not support 10Mb advertised speed"
4438*c58d34ddSKevin Bowling 			    "\n");
44398eb6488eSEric Joyner 			return (EINVAL);
44408eb6488eSEric Joyner 		}
44418eb6488eSEric Joyner 		speed |= IXGBE_LINK_SPEED_10_FULL;
44428eb6488eSEric Joyner 	}
4443d381c807SPiotr Pietruszewski 	if (advertise & 0x10) {
4444d381c807SPiotr Pietruszewski 		if (!(link_caps & IXGBE_LINK_SPEED_2_5GB_FULL)) {
4445*c58d34ddSKevin Bowling 			device_printf(dev,
4446*c58d34ddSKevin Bowling 			    "Interface does not support 2.5G advertised speed"
4447*c58d34ddSKevin Bowling 			    "\n");
4448d381c807SPiotr Pietruszewski 			return (EINVAL);
4449d381c807SPiotr Pietruszewski 		}
4450d381c807SPiotr Pietruszewski 		speed |= IXGBE_LINK_SPEED_2_5GB_FULL;
4451d381c807SPiotr Pietruszewski 	}
4452d381c807SPiotr Pietruszewski 	if (advertise & 0x20) {
4453d381c807SPiotr Pietruszewski 		if (!(link_caps & IXGBE_LINK_SPEED_5GB_FULL)) {
4454*c58d34ddSKevin Bowling 			device_printf(dev,
4455*c58d34ddSKevin Bowling 			    "Interface does not support 5G advertised speed"
4456*c58d34ddSKevin Bowling 			    "\n");
4457d381c807SPiotr Pietruszewski 			return (EINVAL);
4458d381c807SPiotr Pietruszewski 		}
4459d381c807SPiotr Pietruszewski 		speed |= IXGBE_LINK_SPEED_5GB_FULL;
4460d381c807SPiotr Pietruszewski 	}
4461758cc3dcSJack F Vogel 
446279b36ec9SKevin Bowling 	hw->mac.autotry_restart = true;
446379b36ec9SKevin Bowling 	hw->mac.ops.setup_link(hw, speed, true);
4464b1d5caf3SKevin Bowling 	sc->advertise = advertise;
4465758cc3dcSJack F Vogel 
4466f2c4db54SSteven Hartland 	return (0);
44678eb6488eSEric Joyner } /* ixgbe_set_advertise */
44688eb6488eSEric Joyner 
44698eb6488eSEric Joyner /************************************************************************
4470d381c807SPiotr Pietruszewski  * ixgbe_get_default_advertise - Get default advertised speed settings
44718eb6488eSEric Joyner  *
44728eb6488eSEric Joyner  *   Formatted for sysctl usage.
44738eb6488eSEric Joyner  *   Flags:
44748eb6488eSEric Joyner  *     0x1 - advertise 100 Mb
44758eb6488eSEric Joyner  *     0x2 - advertise 1G
44768eb6488eSEric Joyner  *     0x4 - advertise 10G
44778eb6488eSEric Joyner  *     0x8 - advertise 10 Mb (yes, Mb)
4478d381c807SPiotr Pietruszewski  *     0x10 - advertise 2.5G (disabled by default)
4479d381c807SPiotr Pietruszewski  *     0x20 - advertise 5G (disabled by default)
44808eb6488eSEric Joyner  ************************************************************************/
44818eb6488eSEric Joyner static int
4482d381c807SPiotr Pietruszewski ixgbe_get_default_advertise(struct ixgbe_softc *sc)
44838eb6488eSEric Joyner {
4484b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
44858eb6488eSEric Joyner 	int speed;
44868eb6488eSEric Joyner 	ixgbe_link_speed link_caps = 0;
44878eb6488eSEric Joyner 	s32 err;
448879b36ec9SKevin Bowling 	bool negotiate = false;
4489758cc3dcSJack F Vogel 
4490758cc3dcSJack F Vogel 	/*
44918eb6488eSEric Joyner 	 * Advertised speed means nothing unless it's copper or
44928eb6488eSEric Joyner 	 * multi-speed fiber
4493758cc3dcSJack F Vogel 	 */
44948eb6488eSEric Joyner 	if (!(hw->phy.media_type == ixgbe_media_type_copper) &&
44958eb6488eSEric Joyner 	    !(hw->phy.multispeed_fiber))
4496758cc3dcSJack F Vogel 		return (0);
4497758cc3dcSJack F Vogel 
44988eb6488eSEric Joyner 	err = hw->mac.ops.get_link_capabilities(hw, &link_caps, &negotiate);
44998eb6488eSEric Joyner 	if (err != IXGBE_SUCCESS)
45008eb6488eSEric Joyner 		return (0);
45018eb6488eSEric Joyner 
4502d381c807SPiotr Pietruszewski 	if (hw->mac.type == ixgbe_mac_X550) {
4503d381c807SPiotr Pietruszewski 		/*
4504d381c807SPiotr Pietruszewski 		 * 2.5G and 5G autonegotiation speeds on X550
4505d381c807SPiotr Pietruszewski 		 * are disabled by default due to reported
4506d381c807SPiotr Pietruszewski 		 * interoperability issues with some switches.
4507d381c807SPiotr Pietruszewski 		 */
4508d381c807SPiotr Pietruszewski 		link_caps &= ~(IXGBE_LINK_SPEED_2_5GB_FULL |
4509d381c807SPiotr Pietruszewski 		    IXGBE_LINK_SPEED_5GB_FULL);
4510d381c807SPiotr Pietruszewski 	}
4511d381c807SPiotr Pietruszewski 
45128eb6488eSEric Joyner 	speed =
4513d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_10GB_FULL)  ? 0x4  : 0) |
4514d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_5GB_FULL)   ? 0x20 : 0) |
4515d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_2_5GB_FULL) ? 0x10 : 0) |
4516d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_1GB_FULL)   ? 0x2  : 0) |
4517d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_100_FULL)   ? 0x1  : 0) |
4518d381c807SPiotr Pietruszewski 	    ((link_caps & IXGBE_LINK_SPEED_10_FULL)    ? 0x8  : 0);
45198eb6488eSEric Joyner 
45208eb6488eSEric Joyner 	return speed;
4521d381c807SPiotr Pietruszewski } /* ixgbe_get_default_advertise */
45228eb6488eSEric Joyner 
45238eb6488eSEric Joyner /************************************************************************
45248eb6488eSEric Joyner  * ixgbe_sysctl_dmac - Manage DMA Coalescing
45258eb6488eSEric Joyner  *
45268eb6488eSEric Joyner  *   Control values:
45278eb6488eSEric Joyner  *     0/1 - off / on (use default value of 1000)
45288eb6488eSEric Joyner  *
45298eb6488eSEric Joyner  *     Legal timer values are:
45308eb6488eSEric Joyner  *     50,100,250,500,1000,2000,5000,10000
45318eb6488eSEric Joyner  *
45328eb6488eSEric Joyner  *     Turning off interrupt moderation will also turn this off.
45338eb6488eSEric Joyner  ************************************************************************/
45346f37f232SEric Joyner static int
45356f37f232SEric Joyner ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS)
45366f37f232SEric Joyner {
4537b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
4538ff06a8dbSJustin Hibbits 	if_t ifp = iflib_get_ifp(sc->ctx);
45396f37f232SEric Joyner 	int error;
4540c19c7afeSEric Joyner 	u16 newval;
45416f37f232SEric Joyner 
4542b1d5caf3SKevin Bowling 	newval = sc->dmac;
4543c19c7afeSEric Joyner 	error = sysctl_handle_16(oidp, &newval, 0, req);
45446f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
45456f37f232SEric Joyner 		return (error);
45466f37f232SEric Joyner 
4547a9ca1c79SSean Bruno 	switch (newval) {
45486f37f232SEric Joyner 	case 0:
45496f37f232SEric Joyner 		/* Disabled */
4550b1d5caf3SKevin Bowling 		sc->dmac = 0;
45516f37f232SEric Joyner 		break;
4552a9ca1c79SSean Bruno 	case 1:
4553a9ca1c79SSean Bruno 		/* Enable and use default */
4554b1d5caf3SKevin Bowling 		sc->dmac = 1000;
45556f37f232SEric Joyner 		break;
45566f37f232SEric Joyner 	case 50:
45576f37f232SEric Joyner 	case 100:
45586f37f232SEric Joyner 	case 250:
45596f37f232SEric Joyner 	case 500:
45606f37f232SEric Joyner 	case 1000:
45616f37f232SEric Joyner 	case 2000:
45626f37f232SEric Joyner 	case 5000:
45636f37f232SEric Joyner 	case 10000:
45646f37f232SEric Joyner 		/* Legal values - allow */
4565b1d5caf3SKevin Bowling 		sc->dmac = newval;
45666f37f232SEric Joyner 		break;
45676f37f232SEric Joyner 	default:
45686f37f232SEric Joyner 		/* Do nothing, illegal value */
45696f37f232SEric Joyner 		return (EINVAL);
45706f37f232SEric Joyner 	}
45716f37f232SEric Joyner 
45726f37f232SEric Joyner 	/* Re-initialize hardware if it's already running */
4573ff06a8dbSJustin Hibbits 	if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
4574ff06a8dbSJustin Hibbits 		if_init(ifp, ifp);
45756f37f232SEric Joyner 
45766f37f232SEric Joyner 	return (0);
45778eb6488eSEric Joyner } /* ixgbe_sysctl_dmac */
45786f37f232SEric Joyner 
4579a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
45808eb6488eSEric Joyner /************************************************************************
45818eb6488eSEric Joyner  * ixgbe_sysctl_power_state
45828eb6488eSEric Joyner  *
4583a9ca1c79SSean Bruno  *   Sysctl to test power states
4584a9ca1c79SSean Bruno  *   Values:
4585a9ca1c79SSean Bruno  *     0      - set device to D0
4586a9ca1c79SSean Bruno  *     3      - set device to D3
4587a9ca1c79SSean Bruno  *     (none) - get current device power state
45888eb6488eSEric Joyner  ************************************************************************/
4589a9ca1c79SSean Bruno static int
4590a9ca1c79SSean Bruno ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS)
4591a9ca1c79SSean Bruno {
4592b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
4593b1d5caf3SKevin Bowling 	device_t dev = sc->dev;
4594a9ca1c79SSean Bruno 	int curr_ps, new_ps, error = 0;
4595a9ca1c79SSean Bruno 
4596a9ca1c79SSean Bruno 	curr_ps = new_ps = pci_get_powerstate(dev);
4597a9ca1c79SSean Bruno 
4598a9ca1c79SSean Bruno 	error = sysctl_handle_int(oidp, &new_ps, 0, req);
4599a9ca1c79SSean Bruno 	if ((error) || (req->newptr == NULL))
4600a9ca1c79SSean Bruno 		return (error);
4601a9ca1c79SSean Bruno 
4602a9ca1c79SSean Bruno 	if (new_ps == curr_ps)
4603a9ca1c79SSean Bruno 		return (0);
4604a9ca1c79SSean Bruno 
4605a9ca1c79SSean Bruno 	if (new_ps == 3 && curr_ps == 0)
4606a9ca1c79SSean Bruno 		error = DEVICE_SUSPEND(dev);
4607a9ca1c79SSean Bruno 	else if (new_ps == 0 && curr_ps == 3)
4608a9ca1c79SSean Bruno 		error = DEVICE_RESUME(dev);
4609a9ca1c79SSean Bruno 	else
4610a9ca1c79SSean Bruno 		return (EINVAL);
4611a9ca1c79SSean Bruno 
4612a9ca1c79SSean Bruno 	device_printf(dev, "New state: %d\n", pci_get_powerstate(dev));
4613a9ca1c79SSean Bruno 
4614a9ca1c79SSean Bruno 	return (error);
46158eb6488eSEric Joyner } /* ixgbe_sysctl_power_state */
4616a9ca1c79SSean Bruno #endif
46178eb6488eSEric Joyner 
46188eb6488eSEric Joyner /************************************************************************
46198eb6488eSEric Joyner  * ixgbe_sysctl_wol_enable
46208eb6488eSEric Joyner  *
46218eb6488eSEric Joyner  *   Sysctl to enable/disable the WoL capability,
46228eb6488eSEric Joyner  *   if supported by the adapter.
46238eb6488eSEric Joyner  *
46246f37f232SEric Joyner  *   Values:
46256f37f232SEric Joyner  *     0 - disabled
46266f37f232SEric Joyner  *     1 - enabled
46278eb6488eSEric Joyner  ************************************************************************/
46286f37f232SEric Joyner static int
46296f37f232SEric Joyner ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS)
46306f37f232SEric Joyner {
4631b1d5caf3SKevin Bowling 	struct ixgbe_softc  *sc = (struct ixgbe_softc *)arg1;
4632b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
46336f37f232SEric Joyner 	int new_wol_enabled;
46346f37f232SEric Joyner 	int error = 0;
46356f37f232SEric Joyner 
46366f37f232SEric Joyner 	new_wol_enabled = hw->wol_enabled;
46376f37f232SEric Joyner 	error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req);
46386f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
46396f37f232SEric Joyner 		return (error);
4640a9ca1c79SSean Bruno 	new_wol_enabled = !!(new_wol_enabled);
46416f37f232SEric Joyner 	if (new_wol_enabled == hw->wol_enabled)
46426f37f232SEric Joyner 		return (0);
46436f37f232SEric Joyner 
4644b1d5caf3SKevin Bowling 	if (new_wol_enabled > 0 && !sc->wol_support)
46456f37f232SEric Joyner 		return (ENODEV);
46466f37f232SEric Joyner 	else
4647a9ca1c79SSean Bruno 		hw->wol_enabled = new_wol_enabled;
46486f37f232SEric Joyner 
46496f37f232SEric Joyner 	return (0);
46508eb6488eSEric Joyner } /* ixgbe_sysctl_wol_enable */
46516f37f232SEric Joyner 
46528eb6488eSEric Joyner /************************************************************************
46538eb6488eSEric Joyner  * ixgbe_sysctl_wufc - Wake Up Filter Control
46548eb6488eSEric Joyner  *
46556f37f232SEric Joyner  *   Sysctl to enable/disable the types of packets that the
46566f37f232SEric Joyner  *   adapter will wake up on upon receipt.
46576f37f232SEric Joyner  *   Flags:
46586f37f232SEric Joyner  *     0x1  - Link Status Change
46596f37f232SEric Joyner  *     0x2  - Magic Packet
46606f37f232SEric Joyner  *     0x4  - Direct Exact
46616f37f232SEric Joyner  *     0x8  - Directed Multicast
46626f37f232SEric Joyner  *     0x10 - Broadcast
46636f37f232SEric Joyner  *     0x20 - ARP/IPv4 Request Packet
46646f37f232SEric Joyner  *     0x40 - Direct IPv4 Packet
46656f37f232SEric Joyner  *     0x80 - Direct IPv6 Packet
46666f37f232SEric Joyner  *
46678eb6488eSEric Joyner  *   Settings not listed above will cause the sysctl to return an error.
46688eb6488eSEric Joyner  ************************************************************************/
46696f37f232SEric Joyner static int
46706f37f232SEric Joyner ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS)
46716f37f232SEric Joyner {
4672b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
46736f37f232SEric Joyner 	int error = 0;
46746f37f232SEric Joyner 	u32 new_wufc;
46756f37f232SEric Joyner 
4676b1d5caf3SKevin Bowling 	new_wufc = sc->wufc;
46776f37f232SEric Joyner 
4678c19c7afeSEric Joyner 	error = sysctl_handle_32(oidp, &new_wufc, 0, req);
46796f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
46806f37f232SEric Joyner 		return (error);
4681b1d5caf3SKevin Bowling 	if (new_wufc == sc->wufc)
46826f37f232SEric Joyner 		return (0);
46836f37f232SEric Joyner 
46846f37f232SEric Joyner 	if (new_wufc & 0xffffff00)
46856f37f232SEric Joyner 		return (EINVAL);
46868eb6488eSEric Joyner 
46876f37f232SEric Joyner 	new_wufc &= 0xff;
4688b1d5caf3SKevin Bowling 	new_wufc |= (0xffffff & sc->wufc);
4689b1d5caf3SKevin Bowling 	sc->wufc = new_wufc;
46906f37f232SEric Joyner 
46916f37f232SEric Joyner 	return (0);
46928eb6488eSEric Joyner } /* ixgbe_sysctl_wufc */
46936f37f232SEric Joyner 
4694a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
46958eb6488eSEric Joyner /************************************************************************
46968eb6488eSEric Joyner  * ixgbe_sysctl_print_rss_config
46978eb6488eSEric Joyner  ************************************************************************/
4698a9ca1c79SSean Bruno static int
4699a9ca1c79SSean Bruno ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS)
4700a9ca1c79SSean Bruno {
4701b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
4702b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
4703b1d5caf3SKevin Bowling 	device_t dev = sc->dev;
4704a9ca1c79SSean Bruno 	struct sbuf *buf;
47058eb6488eSEric Joyner 	int error = 0, reta_size;
4706a9ca1c79SSean Bruno 	u32 reg;
4707a9ca1c79SSean Bruno 
4708f72de14eSKevin Bowling 	if (atomic_load_acq_int(&sc->recovery_mode))
4709f72de14eSKevin Bowling 		return (EPERM);
4710f72de14eSKevin Bowling 
4711a9ca1c79SSean Bruno 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4712a9ca1c79SSean Bruno 	if (!buf) {
4713a9ca1c79SSean Bruno 		device_printf(dev, "Could not allocate sbuf for output.\n");
4714a9ca1c79SSean Bruno 		return (ENOMEM);
4715a9ca1c79SSean Bruno 	}
4716a9ca1c79SSean Bruno 
4717a9ca1c79SSean Bruno 	// TODO: use sbufs to make a string to print out
4718a9ca1c79SSean Bruno 	/* Set multiplier for RETA setup and table size based on MAC */
4719b1d5caf3SKevin Bowling 	switch (sc->hw.mac.type) {
4720a9ca1c79SSean Bruno 	case ixgbe_mac_X550:
4721a9ca1c79SSean Bruno 	case ixgbe_mac_X550EM_x:
47228eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
4723a9ca1c79SSean Bruno 		reta_size = 128;
4724a9ca1c79SSean Bruno 		break;
4725a9ca1c79SSean Bruno 	default:
4726a9ca1c79SSean Bruno 		reta_size = 32;
4727a9ca1c79SSean Bruno 		break;
4728a9ca1c79SSean Bruno 	}
4729a9ca1c79SSean Bruno 
4730a9ca1c79SSean Bruno 	/* Print out the redirection table */
4731a9ca1c79SSean Bruno 	sbuf_cat(buf, "\n");
4732a9ca1c79SSean Bruno 	for (int i = 0; i < reta_size; i++) {
4733a9ca1c79SSean Bruno 		if (i < 32) {
4734a9ca1c79SSean Bruno 			reg = IXGBE_READ_REG(hw, IXGBE_RETA(i));
4735a9ca1c79SSean Bruno 			sbuf_printf(buf, "RETA(%2d): 0x%08x\n", i, reg);
4736a9ca1c79SSean Bruno 		} else {
4737a9ca1c79SSean Bruno 			reg = IXGBE_READ_REG(hw, IXGBE_ERETA(i - 32));
4738a9ca1c79SSean Bruno 			sbuf_printf(buf, "ERETA(%2d): 0x%08x\n", i - 32, reg);
4739a9ca1c79SSean Bruno 		}
4740a9ca1c79SSean Bruno 	}
4741a9ca1c79SSean Bruno 
4742a9ca1c79SSean Bruno 	// TODO: print more config
4743a9ca1c79SSean Bruno 
4744a9ca1c79SSean Bruno 	error = sbuf_finish(buf);
4745a9ca1c79SSean Bruno 	if (error)
4746a9ca1c79SSean Bruno 		device_printf(dev, "Error finishing sbuf: %d\n", error);
4747a9ca1c79SSean Bruno 
4748a9ca1c79SSean Bruno 	sbuf_delete(buf);
47498eb6488eSEric Joyner 
4750a9ca1c79SSean Bruno 	return (0);
47518eb6488eSEric Joyner } /* ixgbe_sysctl_print_rss_config */
4752a9ca1c79SSean Bruno #endif /* IXGBE_DEBUG */
4753a9ca1c79SSean Bruno 
47548eb6488eSEric Joyner /************************************************************************
47558eb6488eSEric Joyner  * ixgbe_sysctl_phy_temp - Retrieve temperature of PHY
47568eb6488eSEric Joyner  *
47578eb6488eSEric Joyner  *   For X552/X557-AT devices using an external PHY
47588eb6488eSEric Joyner  ************************************************************************/
47598eb6488eSEric Joyner static int
47608eb6488eSEric Joyner ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS)
47618eb6488eSEric Joyner {
4762b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
4763b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
47648eb6488eSEric Joyner 	u16 reg;
47658eb6488eSEric Joyner 
4766f72de14eSKevin Bowling 	if (atomic_load_acq_int(&sc->recovery_mode))
4767f72de14eSKevin Bowling 		return (EPERM);
4768f72de14eSKevin Bowling 
47698eb6488eSEric Joyner 	if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
4770b1d5caf3SKevin Bowling 		device_printf(iflib_get_dev(sc->ctx),
47718eb6488eSEric Joyner 		    "Device has no supported external thermal sensor.\n");
47728eb6488eSEric Joyner 		return (ENODEV);
47738eb6488eSEric Joyner 	}
47748eb6488eSEric Joyner 
47758eb6488eSEric Joyner 	if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP,
47768eb6488eSEric Joyner 	    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &reg)) {
4777b1d5caf3SKevin Bowling 		device_printf(iflib_get_dev(sc->ctx),
4778*c58d34ddSKevin Bowling 		    "Error reading from PHY's current temperature register"
4779*c58d34ddSKevin Bowling 		    "\n");
47808eb6488eSEric Joyner 		return (EAGAIN);
47818eb6488eSEric Joyner 	}
47828eb6488eSEric Joyner 
47838eb6488eSEric Joyner 	/* Shift temp for output */
47848eb6488eSEric Joyner 	reg = reg >> 8;
47858eb6488eSEric Joyner 
4786c19c7afeSEric Joyner 	return (sysctl_handle_16(oidp, NULL, reg, req));
47878eb6488eSEric Joyner } /* ixgbe_sysctl_phy_temp */
47888eb6488eSEric Joyner 
47898eb6488eSEric Joyner /************************************************************************
47908eb6488eSEric Joyner  * ixgbe_sysctl_phy_overtemp_occurred
47918eb6488eSEric Joyner  *
47928eb6488eSEric Joyner  *   Reports (directly from the PHY) whether the current PHY
47938eb6488eSEric Joyner  *   temperature is over the overtemp threshold.
47948eb6488eSEric Joyner  ************************************************************************/
47958eb6488eSEric Joyner static int
47968eb6488eSEric Joyner ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS)
47978eb6488eSEric Joyner {
4798b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
4799b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
48008eb6488eSEric Joyner 	u16 reg;
48018eb6488eSEric Joyner 
4802f72de14eSKevin Bowling 	if (atomic_load_acq_int(&sc->recovery_mode))
4803f72de14eSKevin Bowling 		return (EPERM);
4804f72de14eSKevin Bowling 
48058eb6488eSEric Joyner 	if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
4806b1d5caf3SKevin Bowling 		device_printf(iflib_get_dev(sc->ctx),
48078eb6488eSEric Joyner 		    "Device has no supported external thermal sensor.\n");
48088eb6488eSEric Joyner 		return (ENODEV);
48098eb6488eSEric Joyner 	}
48108eb6488eSEric Joyner 
48118eb6488eSEric Joyner 	if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS,
48128eb6488eSEric Joyner 	    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &reg)) {
4813b1d5caf3SKevin Bowling 		device_printf(iflib_get_dev(sc->ctx),
48148eb6488eSEric Joyner 		    "Error reading from PHY's temperature status register\n");
48158eb6488eSEric Joyner 		return (EAGAIN);
48168eb6488eSEric Joyner 	}
48178eb6488eSEric Joyner 
48188eb6488eSEric Joyner 	/* Get occurrence bit */
48198eb6488eSEric Joyner 	reg = !!(reg & 0x4000);
48208eb6488eSEric Joyner 
4821c19c7afeSEric Joyner 	return (sysctl_handle_16(oidp, 0, reg, req));
48228eb6488eSEric Joyner } /* ixgbe_sysctl_phy_overtemp_occurred */
48238eb6488eSEric Joyner 
48248eb6488eSEric Joyner /************************************************************************
48258eb6488eSEric Joyner  * ixgbe_sysctl_eee_state
48268eb6488eSEric Joyner  *
48278eb6488eSEric Joyner  *   Sysctl to set EEE power saving feature
48288eb6488eSEric Joyner  *   Values:
48298eb6488eSEric Joyner  *     0      - disable EEE
48308eb6488eSEric Joyner  *     1      - enable EEE
48318eb6488eSEric Joyner  *     (none) - get current device EEE state
48328eb6488eSEric Joyner  ************************************************************************/
48338eb6488eSEric Joyner static int
48348eb6488eSEric Joyner ixgbe_sysctl_eee_state(SYSCTL_HANDLER_ARGS)
48358eb6488eSEric Joyner {
4836b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
4837b1d5caf3SKevin Bowling 	device_t dev = sc->dev;
4838ff06a8dbSJustin Hibbits 	if_t ifp = iflib_get_ifp(sc->ctx);
48398eb6488eSEric Joyner 	int curr_eee, new_eee, error = 0;
48408eb6488eSEric Joyner 	s32 retval;
48418eb6488eSEric Joyner 
4842f72de14eSKevin Bowling 	if (atomic_load_acq_int(&sc->recovery_mode))
4843f72de14eSKevin Bowling 		return (EPERM);
4844f72de14eSKevin Bowling 
4845b1d5caf3SKevin Bowling 	curr_eee = new_eee = !!(sc->feat_en & IXGBE_FEATURE_EEE);
48468eb6488eSEric Joyner 
48478eb6488eSEric Joyner 	error = sysctl_handle_int(oidp, &new_eee, 0, req);
48488eb6488eSEric Joyner 	if ((error) || (req->newptr == NULL))
48498eb6488eSEric Joyner 		return (error);
48508eb6488eSEric Joyner 
48518eb6488eSEric Joyner 	/* Nothing to do */
48528eb6488eSEric Joyner 	if (new_eee == curr_eee)
48538eb6488eSEric Joyner 		return (0);
48548eb6488eSEric Joyner 
48558eb6488eSEric Joyner 	/* Not supported */
4856b1d5caf3SKevin Bowling 	if (!(sc->feat_cap & IXGBE_FEATURE_EEE))
48578eb6488eSEric Joyner 		return (EINVAL);
48588eb6488eSEric Joyner 
48598eb6488eSEric Joyner 	/* Bounds checking */
48608eb6488eSEric Joyner 	if ((new_eee < 0) || (new_eee > 1))
48618eb6488eSEric Joyner 		return (EINVAL);
48628eb6488eSEric Joyner 
4863b1d5caf3SKevin Bowling 	retval = ixgbe_setup_eee(&sc->hw, new_eee);
48648eb6488eSEric Joyner 	if (retval) {
48658eb6488eSEric Joyner 		device_printf(dev, "Error in EEE setup: 0x%08X\n", retval);
48668eb6488eSEric Joyner 		return (EINVAL);
48678eb6488eSEric Joyner 	}
48688eb6488eSEric Joyner 
48698eb6488eSEric Joyner 	/* Restart auto-neg */
4870ff06a8dbSJustin Hibbits 	if_init(ifp, ifp);
48718eb6488eSEric Joyner 
48728eb6488eSEric Joyner 	device_printf(dev, "New EEE state: %d\n", new_eee);
48738eb6488eSEric Joyner 
48748eb6488eSEric Joyner 	/* Cache new value */
48758eb6488eSEric Joyner 	if (new_eee)
4876b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_EEE;
48778eb6488eSEric Joyner 	else
4878b1d5caf3SKevin Bowling 		sc->feat_en &= ~IXGBE_FEATURE_EEE;
48798eb6488eSEric Joyner 
48808eb6488eSEric Joyner 	return (error);
48818eb6488eSEric Joyner } /* ixgbe_sysctl_eee_state */
48828eb6488eSEric Joyner 
4883eea2e089SMichael Tuexen static int
4884eea2e089SMichael Tuexen ixgbe_sysctl_tso_tcp_flags_mask(SYSCTL_HANDLER_ARGS)
4885eea2e089SMichael Tuexen {
4886eea2e089SMichael Tuexen 	struct ixgbe_softc *sc;
4887eea2e089SMichael Tuexen 	u32 reg, val, shift;
4888eea2e089SMichael Tuexen 	int error, mask;
4889eea2e089SMichael Tuexen 
4890eea2e089SMichael Tuexen 	sc = oidp->oid_arg1;
4891eea2e089SMichael Tuexen 	switch (oidp->oid_arg2) {
4892eea2e089SMichael Tuexen 	case 0:
4893eea2e089SMichael Tuexen 		reg = IXGBE_DTXTCPFLGL;
4894eea2e089SMichael Tuexen 		shift = 0;
4895eea2e089SMichael Tuexen 		break;
4896eea2e089SMichael Tuexen 	case 1:
4897eea2e089SMichael Tuexen 		reg = IXGBE_DTXTCPFLGL;
4898eea2e089SMichael Tuexen 		shift = 16;
4899eea2e089SMichael Tuexen 		break;
4900eea2e089SMichael Tuexen 	case 2:
4901eea2e089SMichael Tuexen 		reg = IXGBE_DTXTCPFLGH;
4902eea2e089SMichael Tuexen 		shift = 0;
4903eea2e089SMichael Tuexen 		break;
4904eea2e089SMichael Tuexen 	default:
4905eea2e089SMichael Tuexen 		return (EINVAL);
4906eea2e089SMichael Tuexen 		break;
4907eea2e089SMichael Tuexen 	}
4908eea2e089SMichael Tuexen 	val = IXGBE_READ_REG(&sc->hw, reg);
4909eea2e089SMichael Tuexen 	mask = (val >> shift) & 0xfff;
4910eea2e089SMichael Tuexen 	error = sysctl_handle_int(oidp, &mask, 0, req);
4911eea2e089SMichael Tuexen 	if (error != 0 || req->newptr == NULL)
4912eea2e089SMichael Tuexen 		return (error);
4913eea2e089SMichael Tuexen 	if (mask < 0 || mask > 0xfff)
4914eea2e089SMichael Tuexen 		return (EINVAL);
4915eea2e089SMichael Tuexen 	val = (val & ~(0xfff << shift)) | (mask << shift);
4916eea2e089SMichael Tuexen 	IXGBE_WRITE_REG(&sc->hw, reg, val);
4917eea2e089SMichael Tuexen 	return (0);
4918eea2e089SMichael Tuexen }
4919eea2e089SMichael Tuexen 
49208eb6488eSEric Joyner /************************************************************************
49218eb6488eSEric Joyner  * ixgbe_init_device_features
49228eb6488eSEric Joyner  ************************************************************************/
49238eb6488eSEric Joyner static void
4924b1d5caf3SKevin Bowling ixgbe_init_device_features(struct ixgbe_softc *sc)
49258eb6488eSEric Joyner {
4926*c58d34ddSKevin Bowling 	sc->feat_cap = IXGBE_FEATURE_NETMAP |
4927*c58d34ddSKevin Bowling 	    IXGBE_FEATURE_RSS |
4928*c58d34ddSKevin Bowling 	    IXGBE_FEATURE_MSI |
4929*c58d34ddSKevin Bowling 	    IXGBE_FEATURE_MSIX |
4930*c58d34ddSKevin Bowling 	    IXGBE_FEATURE_LEGACY_IRQ;
49318eb6488eSEric Joyner 
49328eb6488eSEric Joyner 	/* Set capabilities first... */
4933b1d5caf3SKevin Bowling 	switch (sc->hw.mac.type) {
49348eb6488eSEric Joyner 	case ixgbe_mac_82598EB:
4935b1d5caf3SKevin Bowling 		if (sc->hw.device_id == IXGBE_DEV_ID_82598AT)
4936b1d5caf3SKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_FAN_FAIL;
49378eb6488eSEric Joyner 		break;
49388eb6488eSEric Joyner 	case ixgbe_mac_X540:
4939b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_SRIOV;
4940b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_FDIR;
4941b1d5caf3SKevin Bowling 		if ((sc->hw.device_id == IXGBE_DEV_ID_X540_BYPASS) &&
4942b1d5caf3SKevin Bowling 		    (sc->hw.bus.func == 0))
4943b1d5caf3SKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_BYPASS;
49448eb6488eSEric Joyner 		break;
49458eb6488eSEric Joyner 	case ixgbe_mac_X550:
4946f72de14eSKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_RECOVERY_MODE;
4947b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_TEMP_SENSOR;
4948b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_SRIOV;
4949b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_FDIR;
49508eb6488eSEric Joyner 		break;
49518eb6488eSEric Joyner 	case ixgbe_mac_X550EM_x:
4952f72de14eSKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_RECOVERY_MODE;
4953b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_SRIOV;
4954b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_FDIR;
4955f72de14eSKevin Bowling 		if (sc->hw.device_id == IXGBE_DEV_ID_X550EM_X_KR)
4956f72de14eSKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_EEE;
49578eb6488eSEric Joyner 		break;
49588eb6488eSEric Joyner 	case ixgbe_mac_X550EM_a:
4959f72de14eSKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_RECOVERY_MODE;
4960b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_SRIOV;
4961b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_FDIR;
4962b1d5caf3SKevin Bowling 		sc->feat_cap &= ~IXGBE_FEATURE_LEGACY_IRQ;
4963b1d5caf3SKevin Bowling 		if ((sc->hw.device_id == IXGBE_DEV_ID_X550EM_A_1G_T) ||
4964b1d5caf3SKevin Bowling 		    (sc->hw.device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L)) {
4965b1d5caf3SKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_TEMP_SENSOR;
4966b1d5caf3SKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_EEE;
49678eb6488eSEric Joyner 		}
49688eb6488eSEric Joyner 		break;
49698eb6488eSEric Joyner 	case ixgbe_mac_82599EB:
4970b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_SRIOV;
4971b1d5caf3SKevin Bowling 		sc->feat_cap |= IXGBE_FEATURE_FDIR;
4972b1d5caf3SKevin Bowling 		if ((sc->hw.device_id == IXGBE_DEV_ID_82599_BYPASS) &&
4973b1d5caf3SKevin Bowling 		    (sc->hw.bus.func == 0))
4974b1d5caf3SKevin Bowling 			sc->feat_cap |= IXGBE_FEATURE_BYPASS;
4975b1d5caf3SKevin Bowling 		if (sc->hw.device_id == IXGBE_DEV_ID_82599_QSFP_SF_QP)
4976b1d5caf3SKevin Bowling 			sc->feat_cap &= ~IXGBE_FEATURE_LEGACY_IRQ;
49778eb6488eSEric Joyner 		break;
49788eb6488eSEric Joyner 	default:
49798eb6488eSEric Joyner 		break;
49808eb6488eSEric Joyner 	}
49818eb6488eSEric Joyner 
49828eb6488eSEric Joyner 	/* Enabled by default... */
49838eb6488eSEric Joyner 	/* Fan failure detection */
4984b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_FAN_FAIL)
4985b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_FAN_FAIL;
49868eb6488eSEric Joyner 	/* Netmap */
4987b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_NETMAP)
4988b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_NETMAP;
49898eb6488eSEric Joyner 	/* EEE */
4990b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_EEE)
4991b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_EEE;
49928eb6488eSEric Joyner 	/* Thermal Sensor */
4993b1d5caf3SKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_TEMP_SENSOR)
4994b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_TEMP_SENSOR;
4995f72de14eSKevin Bowling 	/* Recovery mode */
4996f72de14eSKevin Bowling 	if (sc->feat_cap & IXGBE_FEATURE_RECOVERY_MODE)
4997f72de14eSKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_RECOVERY_MODE;
49988eb6488eSEric Joyner 
49998eb6488eSEric Joyner 	/* Enabled via global sysctl... */
50008eb6488eSEric Joyner 	/* Flow Director */
50018eb6488eSEric Joyner 	if (ixgbe_enable_fdir) {
5002b1d5caf3SKevin Bowling 		if (sc->feat_cap & IXGBE_FEATURE_FDIR)
5003b1d5caf3SKevin Bowling 			sc->feat_en |= IXGBE_FEATURE_FDIR;
50048eb6488eSEric Joyner 		else
5005*c58d34ddSKevin Bowling 			device_printf(sc->dev,
5006*c58d34ddSKevin Bowling 			    "Device does not support Flow Director."
5007*c58d34ddSKevin Bowling 			    " Leaving disabled.");
50088eb6488eSEric Joyner 	}
50096f37f232SEric Joyner 	/*
50108eb6488eSEric Joyner 	 * Message Signal Interrupts - Extended (MSI-X)
50118eb6488eSEric Joyner 	 * Normal MSI is only enabled if MSI-X calls fail.
5012758cc3dcSJack F Vogel 	 */
50138eb6488eSEric Joyner 	if (!ixgbe_enable_msix)
5014b1d5caf3SKevin Bowling 		sc->feat_cap &= ~IXGBE_FEATURE_MSIX;
50158eb6488eSEric Joyner 	/* Receive-Side Scaling (RSS) */
5016b1d5caf3SKevin Bowling 	if ((sc->feat_cap & IXGBE_FEATURE_RSS) && ixgbe_enable_rss)
5017b1d5caf3SKevin Bowling 		sc->feat_en |= IXGBE_FEATURE_RSS;
50188eb6488eSEric Joyner 
50198eb6488eSEric Joyner 	/* Disable features with unmet dependencies... */
50208eb6488eSEric Joyner 	/* No MSI-X */
5021b1d5caf3SKevin Bowling 	if (!(sc->feat_cap & IXGBE_FEATURE_MSIX)) {
5022b1d5caf3SKevin Bowling 		sc->feat_cap &= ~IXGBE_FEATURE_RSS;
5023b1d5caf3SKevin Bowling 		sc->feat_cap &= ~IXGBE_FEATURE_SRIOV;
5024b1d5caf3SKevin Bowling 		sc->feat_en &= ~IXGBE_FEATURE_RSS;
5025b1d5caf3SKevin Bowling 		sc->feat_en &= ~IXGBE_FEATURE_SRIOV;
50268eb6488eSEric Joyner 	}
50278eb6488eSEric Joyner } /* ixgbe_init_device_features */
50288eb6488eSEric Joyner 
50298eb6488eSEric Joyner /************************************************************************
50308eb6488eSEric Joyner  * ixgbe_check_fan_failure
50318eb6488eSEric Joyner  ************************************************************************/
50328eb6488eSEric Joyner static void
5033b1d5caf3SKevin Bowling ixgbe_check_fan_failure(struct ixgbe_softc *sc, u32 reg, bool in_interrupt)
50348eb6488eSEric Joyner {
50358eb6488eSEric Joyner 	u32 mask;
50368eb6488eSEric Joyner 
5037b1d5caf3SKevin Bowling 	mask = (in_interrupt) ? IXGBE_EICR_GPI_SDP1_BY_MAC(&sc->hw) :
50388eb6488eSEric Joyner 	    IXGBE_ESDP_SDP1;
50398eb6488eSEric Joyner 
50408eb6488eSEric Joyner 	if (reg & mask)
5041*c58d34ddSKevin Bowling 		device_printf(sc->dev,
5042*c58d34ddSKevin Bowling 		    "\nCRITICAL: FAN FAILURE!! REPLACE IMMEDIATELY!!\n");
50438eb6488eSEric Joyner } /* ixgbe_check_fan_failure */
50447660e4eaSKevin Bowling 
50457660e4eaSKevin Bowling /************************************************************************
50467660e4eaSKevin Bowling  * ixgbe_sbuf_fw_version
50477660e4eaSKevin Bowling  ************************************************************************/
50487660e4eaSKevin Bowling static void
50497660e4eaSKevin Bowling ixgbe_sbuf_fw_version(struct ixgbe_hw *hw, struct sbuf *buf)
50507660e4eaSKevin Bowling {
50517660e4eaSKevin Bowling 	struct ixgbe_nvm_version nvm_ver = {0};
50525de5419bSKevin Bowling 	const char *space = "";
50537660e4eaSKevin Bowling 
5054f72de14eSKevin Bowling 	ixgbe_get_nvm_version(hw, &nvm_ver); /* NVM version */
50557660e4eaSKevin Bowling 	ixgbe_get_oem_prod_version(hw, &nvm_ver); /* OEM's NVM version */
5056*c58d34ddSKevin Bowling 	ixgbe_get_etk_id(hw, &nvm_ver); /* eTrack a build ID in Intel's SCM */
5057f72de14eSKevin Bowling 	ixgbe_get_orom_version(hw, &nvm_ver); /* Option ROM */
5058f72de14eSKevin Bowling 
5059f72de14eSKevin Bowling 	/* FW version */
5060f72de14eSKevin Bowling 	if ((nvm_ver.phy_fw_maj == 0x0 &&
5061f72de14eSKevin Bowling 	    nvm_ver.phy_fw_min == 0x0 &&
5062f72de14eSKevin Bowling 	    nvm_ver.phy_fw_id == 0x0) ||
5063f72de14eSKevin Bowling 		(nvm_ver.phy_fw_maj == 0xF &&
5064f72de14eSKevin Bowling 	    nvm_ver.phy_fw_min == 0xFF &&
5065f72de14eSKevin Bowling 	    nvm_ver.phy_fw_id == 0xF)) {
5066f72de14eSKevin Bowling 		/* If major, minor and id numbers are set to 0,
5067f72de14eSKevin Bowling 		 * reading FW version is unsupported. If major number
5068f72de14eSKevin Bowling 		 * is set to 0xF, minor is set to 0xFF and id is set
5069f72de14eSKevin Bowling 		 * to 0xF, this means that number read is invalid. */
5070f72de14eSKevin Bowling 	} else
5071f72de14eSKevin Bowling 		sbuf_printf(buf, "fw %d.%d.%d ",
5072*c58d34ddSKevin Bowling 		    nvm_ver.phy_fw_maj, nvm_ver.phy_fw_min,
5073*c58d34ddSKevin Bowling 		    nvm_ver.phy_fw_id);
5074f72de14eSKevin Bowling 
5075f72de14eSKevin Bowling 	/* NVM version */
5076f72de14eSKevin Bowling 	if ((nvm_ver.nvm_major == 0x0 &&
5077f72de14eSKevin Bowling 	    nvm_ver.nvm_minor == 0x0 &&
5078f72de14eSKevin Bowling 	    nvm_ver.nvm_id == 0x0) ||
5079f72de14eSKevin Bowling 		(nvm_ver.nvm_major == 0xF &&
5080f72de14eSKevin Bowling 	    nvm_ver.nvm_minor == 0xFF &&
5081f72de14eSKevin Bowling 	    nvm_ver.nvm_id == 0xF)) {
5082f72de14eSKevin Bowling 		/* If major, minor and id numbers are set to 0,
5083f72de14eSKevin Bowling 		 * reading NVM version is unsupported. If major number
5084f72de14eSKevin Bowling 		 * is set to 0xF, minor is set to 0xFF and id is set
5085f72de14eSKevin Bowling 		 * to 0xF, this means that number read is invalid. */
5086f72de14eSKevin Bowling 	} else
5087f72de14eSKevin Bowling 		sbuf_printf(buf, "nvm %x.%02x.%x ",
5088f72de14eSKevin Bowling 		    nvm_ver.nvm_major, nvm_ver.nvm_minor, nvm_ver.nvm_id);
50897660e4eaSKevin Bowling 
50905de5419bSKevin Bowling 	if (nvm_ver.oem_valid) {
50917660e4eaSKevin Bowling 		sbuf_printf(buf, "NVM OEM V%d.%d R%d", nvm_ver.oem_major,
50927660e4eaSKevin Bowling 		    nvm_ver.oem_minor, nvm_ver.oem_release);
50935de5419bSKevin Bowling 		space = " ";
50945de5419bSKevin Bowling 	}
50957660e4eaSKevin Bowling 
50965de5419bSKevin Bowling 	if (nvm_ver.or_valid) {
50975de5419bSKevin Bowling 		sbuf_printf(buf, "%sOption ROM V%d-b%d-p%d",
5098*c58d34ddSKevin Bowling 		    space, nvm_ver.or_major, nvm_ver.or_build,
5099*c58d34ddSKevin Bowling 		    nvm_ver.or_patch);
51005de5419bSKevin Bowling 		space = " ";
51015de5419bSKevin Bowling 	}
51027660e4eaSKevin Bowling 
51035de5419bSKevin Bowling 	if (nvm_ver.etk_id != ((NVM_VER_INVALID << NVM_ETK_SHIFT) |
5104f72de14eSKevin Bowling 	    NVM_VER_INVALID | 0xFFFFFFFF)) {
51055de5419bSKevin Bowling 		sbuf_printf(buf, "%seTrack 0x%08x", space, nvm_ver.etk_id);
51065de5419bSKevin Bowling 	}
51077660e4eaSKevin Bowling } /* ixgbe_sbuf_fw_version */
51087660e4eaSKevin Bowling 
51097660e4eaSKevin Bowling /************************************************************************
51107660e4eaSKevin Bowling  * ixgbe_print_fw_version
51117660e4eaSKevin Bowling  ************************************************************************/
51127660e4eaSKevin Bowling static void
51137660e4eaSKevin Bowling ixgbe_print_fw_version(if_ctx_t ctx)
51147660e4eaSKevin Bowling {
5115b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
5116b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
5117b1d5caf3SKevin Bowling 	device_t dev = sc->dev;
51187660e4eaSKevin Bowling 	struct sbuf *buf;
51197660e4eaSKevin Bowling 	int error = 0;
51207660e4eaSKevin Bowling 
51217660e4eaSKevin Bowling 	buf = sbuf_new_auto();
51227660e4eaSKevin Bowling 	if (!buf) {
51237660e4eaSKevin Bowling 		device_printf(dev, "Could not allocate sbuf for output.\n");
51247660e4eaSKevin Bowling 		return;
51257660e4eaSKevin Bowling 	}
51267660e4eaSKevin Bowling 
51277660e4eaSKevin Bowling 	ixgbe_sbuf_fw_version(hw, buf);
51287660e4eaSKevin Bowling 
51297660e4eaSKevin Bowling 	error = sbuf_finish(buf);
51307660e4eaSKevin Bowling 	if (error)
51317660e4eaSKevin Bowling 		device_printf(dev, "Error finishing sbuf: %d\n", error);
51327660e4eaSKevin Bowling 	else if (sbuf_len(buf))
51337660e4eaSKevin Bowling 		device_printf(dev, "%s\n", sbuf_data(buf));
51347660e4eaSKevin Bowling 
51357660e4eaSKevin Bowling 	sbuf_delete(buf);
51367660e4eaSKevin Bowling } /* ixgbe_print_fw_version */
51377660e4eaSKevin Bowling 
51387660e4eaSKevin Bowling /************************************************************************
51397660e4eaSKevin Bowling  * ixgbe_sysctl_print_fw_version
51407660e4eaSKevin Bowling  ************************************************************************/
51417660e4eaSKevin Bowling static int
51427660e4eaSKevin Bowling ixgbe_sysctl_print_fw_version(SYSCTL_HANDLER_ARGS)
51437660e4eaSKevin Bowling {
5144b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
5145b1d5caf3SKevin Bowling 	struct ixgbe_hw *hw = &sc->hw;
5146b1d5caf3SKevin Bowling 	device_t dev = sc->dev;
51477660e4eaSKevin Bowling 	struct sbuf *buf;
51487660e4eaSKevin Bowling 	int error = 0;
51497660e4eaSKevin Bowling 
51507660e4eaSKevin Bowling 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
51517660e4eaSKevin Bowling 	if (!buf) {
51527660e4eaSKevin Bowling 		device_printf(dev, "Could not allocate sbuf for output.\n");
51537660e4eaSKevin Bowling 		return (ENOMEM);
51547660e4eaSKevin Bowling 	}
51557660e4eaSKevin Bowling 
51567660e4eaSKevin Bowling 	ixgbe_sbuf_fw_version(hw, buf);
51577660e4eaSKevin Bowling 
51587660e4eaSKevin Bowling 	error = sbuf_finish(buf);
51597660e4eaSKevin Bowling 	if (error)
51607660e4eaSKevin Bowling 		device_printf(dev, "Error finishing sbuf: %d\n", error);
51617660e4eaSKevin Bowling 
51627660e4eaSKevin Bowling 	sbuf_delete(buf);
51637660e4eaSKevin Bowling 
51647660e4eaSKevin Bowling 	return (0);
51657660e4eaSKevin Bowling } /* ixgbe_sysctl_print_fw_version */
5166