xref: /freebsd/sys/dev/ixgbe/if_ix.c (revision 6f37f2324dfbc0e537ddc97f39ca4f70f77226c9)
1758cc3dcSJack F Vogel /******************************************************************************
2758cc3dcSJack F Vogel 
3758cc3dcSJack F Vogel   Copyright (c) 2001-2015, Intel Corporation
4758cc3dcSJack F Vogel   All rights reserved.
5758cc3dcSJack F Vogel 
6758cc3dcSJack F Vogel   Redistribution and use in source and binary forms, with or without
7758cc3dcSJack F Vogel   modification, are permitted provided that the following conditions are met:
8758cc3dcSJack F Vogel 
9758cc3dcSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
10758cc3dcSJack F Vogel       this list of conditions and the following disclaimer.
11758cc3dcSJack F Vogel 
12758cc3dcSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
13758cc3dcSJack F Vogel       notice, this list of conditions and the following disclaimer in the
14758cc3dcSJack F Vogel       documentation and/or other materials provided with the distribution.
15758cc3dcSJack F Vogel 
16758cc3dcSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
17758cc3dcSJack F Vogel       contributors may be used to endorse or promote products derived from
18758cc3dcSJack F Vogel       this software without specific prior written permission.
19758cc3dcSJack F Vogel 
20758cc3dcSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21758cc3dcSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22758cc3dcSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23758cc3dcSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24758cc3dcSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25758cc3dcSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26758cc3dcSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27758cc3dcSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28758cc3dcSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29758cc3dcSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30758cc3dcSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
31758cc3dcSJack F Vogel 
32758cc3dcSJack F Vogel ******************************************************************************/
33758cc3dcSJack F Vogel /*$FreeBSD$*/
34758cc3dcSJack F Vogel 
35758cc3dcSJack F Vogel 
36758cc3dcSJack F Vogel #ifndef IXGBE_STANDALONE_BUILD
37758cc3dcSJack F Vogel #include "opt_inet.h"
38758cc3dcSJack F Vogel #include "opt_inet6.h"
39758cc3dcSJack F Vogel #include "opt_rss.h"
40758cc3dcSJack F Vogel #endif
41758cc3dcSJack F Vogel 
42758cc3dcSJack F Vogel #include "ixgbe.h"
43758cc3dcSJack F Vogel 
44758cc3dcSJack F Vogel #ifdef	RSS
45a1edda90SAdrian Chadd #include <net/rss_config.h>
46758cc3dcSJack F Vogel #include <netinet/in_rss.h>
47758cc3dcSJack F Vogel #endif
48758cc3dcSJack F Vogel 
49758cc3dcSJack F Vogel /*********************************************************************
50758cc3dcSJack F Vogel  *  Set this to one to display debug statistics
51758cc3dcSJack F Vogel  *********************************************************************/
52758cc3dcSJack F Vogel int             ixgbe_display_debug_stats = 0;
53758cc3dcSJack F Vogel 
54758cc3dcSJack F Vogel /*********************************************************************
55758cc3dcSJack F Vogel  *  Driver version
56758cc3dcSJack F Vogel  *********************************************************************/
57*6f37f232SEric Joyner char ixgbe_driver_version[] = "2.8.3";
58758cc3dcSJack F Vogel 
59758cc3dcSJack F Vogel /*********************************************************************
60758cc3dcSJack F Vogel  *  PCI Device ID Table
61758cc3dcSJack F Vogel  *
62758cc3dcSJack F Vogel  *  Used by probe to select devices to load on
63758cc3dcSJack F Vogel  *  Last field stores an index into ixgbe_strings
64758cc3dcSJack F Vogel  *  Last entry must be all 0s
65758cc3dcSJack F Vogel  *
66758cc3dcSJack F Vogel  *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
67758cc3dcSJack F Vogel  *********************************************************************/
68758cc3dcSJack F Vogel 
69758cc3dcSJack F Vogel static ixgbe_vendor_info_t ixgbe_vendor_info_array[] =
70758cc3dcSJack F Vogel {
71758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT, 0, 0, 0},
72758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT, 0, 0, 0},
73758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4, 0, 0, 0},
74758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT, 0, 0, 0},
75758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT2, 0, 0, 0},
76758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598, 0, 0, 0},
77758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_DA_DUAL_PORT, 0, 0, 0},
78758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_CX4_DUAL_PORT, 0, 0, 0},
79758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_XF_LR, 0, 0, 0},
80758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM, 0, 0, 0},
81758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_SFP_LOM, 0, 0, 0},
82758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4, 0, 0, 0},
83758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4_MEZZ, 0, 0, 0},
84758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP, 0, 0, 0},
85758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_XAUI_LOM, 0, 0, 0},
86758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_CX4, 0, 0, 0},
87758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_T3_LOM, 0, 0, 0},
88758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_COMBO_BACKPLANE, 0, 0, 0},
89758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BACKPLANE_FCOE, 0, 0, 0},
90758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF2, 0, 0, 0},
91758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_FCOE, 0, 0, 0},
92758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599EN_SFP, 0, 0, 0},
93758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF_QP, 0, 0, 0},
94758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_QSFP_SF_QP, 0, 0, 0},
95758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T, 0, 0, 0},
96758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T1, 0, 0, 0},
97758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T, 0, 0, 0},
98758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KR, 0, 0, 0},
99758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KX4, 0, 0, 0},
100758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_10G_T, 0, 0, 0},
101758cc3dcSJack F Vogel 	/* required last entry */
102758cc3dcSJack F Vogel 	{0, 0, 0, 0, 0}
103758cc3dcSJack F Vogel };
104758cc3dcSJack F Vogel 
105758cc3dcSJack F Vogel /*********************************************************************
106758cc3dcSJack F Vogel  *  Table of branding strings
107758cc3dcSJack F Vogel  *********************************************************************/
108758cc3dcSJack F Vogel 
109758cc3dcSJack F Vogel static char    *ixgbe_strings[] = {
110758cc3dcSJack F Vogel 	"Intel(R) PRO/10GbE PCI-Express Network Driver"
111758cc3dcSJack F Vogel };
112758cc3dcSJack F Vogel 
113758cc3dcSJack F Vogel /*********************************************************************
114758cc3dcSJack F Vogel  *  Function prototypes
115758cc3dcSJack F Vogel  *********************************************************************/
116758cc3dcSJack F Vogel static int      ixgbe_probe(device_t);
117758cc3dcSJack F Vogel static int      ixgbe_attach(device_t);
118758cc3dcSJack F Vogel static int      ixgbe_detach(device_t);
119758cc3dcSJack F Vogel static int      ixgbe_shutdown(device_t);
120*6f37f232SEric Joyner static int	ixgbe_suspend(device_t);
121*6f37f232SEric Joyner static int	ixgbe_resume(device_t);
122758cc3dcSJack F Vogel static int      ixgbe_ioctl(struct ifnet *, u_long, caddr_t);
123758cc3dcSJack F Vogel static void	ixgbe_init(void *);
124758cc3dcSJack F Vogel static void	ixgbe_init_locked(struct adapter *);
125758cc3dcSJack F Vogel static void     ixgbe_stop(void *);
126758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036
127758cc3dcSJack F Vogel static uint64_t	ixgbe_get_counter(struct ifnet *, ift_counter);
128758cc3dcSJack F Vogel #endif
129758cc3dcSJack F Vogel static void	ixgbe_add_media_types(struct adapter *);
130758cc3dcSJack F Vogel static void     ixgbe_media_status(struct ifnet *, struct ifmediareq *);
131758cc3dcSJack F Vogel static int      ixgbe_media_change(struct ifnet *);
132758cc3dcSJack F Vogel static void     ixgbe_identify_hardware(struct adapter *);
133758cc3dcSJack F Vogel static int      ixgbe_allocate_pci_resources(struct adapter *);
134758cc3dcSJack F Vogel static void	ixgbe_get_slot_info(struct ixgbe_hw *);
135758cc3dcSJack F Vogel static int      ixgbe_allocate_msix(struct adapter *);
136758cc3dcSJack F Vogel static int      ixgbe_allocate_legacy(struct adapter *);
137758cc3dcSJack F Vogel static int	ixgbe_setup_msix(struct adapter *);
138758cc3dcSJack F Vogel static void	ixgbe_free_pci_resources(struct adapter *);
139758cc3dcSJack F Vogel static void	ixgbe_local_timer(void *);
140758cc3dcSJack F Vogel static int	ixgbe_setup_interface(device_t, struct adapter *);
141*6f37f232SEric Joyner static void	ixgbe_config_dmac(struct adapter *);
142*6f37f232SEric Joyner static void	ixgbe_config_delay_values(struct adapter *);
143758cc3dcSJack F Vogel static void	ixgbe_config_link(struct adapter *);
144*6f37f232SEric Joyner static void	ixgbe_check_eee_support(struct adapter *);
145*6f37f232SEric Joyner static void	ixgbe_check_wol_support(struct adapter *);
146*6f37f232SEric Joyner static int	ixgbe_setup_low_power_mode(struct adapter *);
147758cc3dcSJack F Vogel static void	ixgbe_rearm_queues(struct adapter *, u64);
148758cc3dcSJack F Vogel 
149758cc3dcSJack F Vogel static void     ixgbe_initialize_transmit_units(struct adapter *);
150758cc3dcSJack F Vogel static void     ixgbe_initialize_receive_units(struct adapter *);
151758cc3dcSJack F Vogel static void	ixgbe_enable_rx_drop(struct adapter *);
152758cc3dcSJack F Vogel static void	ixgbe_disable_rx_drop(struct adapter *);
153758cc3dcSJack F Vogel 
154758cc3dcSJack F Vogel static void     ixgbe_enable_intr(struct adapter *);
155758cc3dcSJack F Vogel static void     ixgbe_disable_intr(struct adapter *);
156758cc3dcSJack F Vogel static void     ixgbe_update_stats_counters(struct adapter *);
157758cc3dcSJack F Vogel static void     ixgbe_set_promisc(struct adapter *);
158758cc3dcSJack F Vogel static void     ixgbe_set_multi(struct adapter *);
159758cc3dcSJack F Vogel static void     ixgbe_update_link_status(struct adapter *);
160758cc3dcSJack F Vogel static void	ixgbe_set_ivar(struct adapter *, u8, u8, s8);
161758cc3dcSJack F Vogel static void	ixgbe_configure_ivars(struct adapter *);
162758cc3dcSJack F Vogel static u8 *	ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *);
163758cc3dcSJack F Vogel 
164758cc3dcSJack F Vogel static void	ixgbe_setup_vlan_hw_support(struct adapter *);
165758cc3dcSJack F Vogel static void	ixgbe_register_vlan(void *, struct ifnet *, u16);
166758cc3dcSJack F Vogel static void	ixgbe_unregister_vlan(void *, struct ifnet *, u16);
167758cc3dcSJack F Vogel 
168*6f37f232SEric Joyner static void	ixgbe_add_device_sysctls(struct adapter *);
169*6f37f232SEric Joyner static void     ixgbe_add_hw_stats(struct adapter *);
170*6f37f232SEric Joyner 
171*6f37f232SEric Joyner /* Sysctl handlers */
172*6f37f232SEric Joyner static int	ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS);
173*6f37f232SEric Joyner static int	ixgbe_set_advertise(SYSCTL_HANDLER_ARGS);
174*6f37f232SEric Joyner static int	ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS);
175*6f37f232SEric Joyner static int	ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS);
176*6f37f232SEric Joyner static int	ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS);
177*6f37f232SEric Joyner static int	ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS);
178*6f37f232SEric Joyner static int	ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS);
179*6f37f232SEric Joyner static int	ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS);
180*6f37f232SEric Joyner static int	ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS);
181*6f37f232SEric Joyner static int	ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS);
182*6f37f232SEric Joyner static int	ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS);
183*6f37f232SEric Joyner static int	ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS);
184758cc3dcSJack F Vogel 
185758cc3dcSJack F Vogel /* Support for pluggable optic modules */
186758cc3dcSJack F Vogel static bool	ixgbe_sfp_probe(struct adapter *);
187758cc3dcSJack F Vogel static void	ixgbe_setup_optics(struct adapter *);
188758cc3dcSJack F Vogel 
189758cc3dcSJack F Vogel /* Legacy (single vector interrupt handler */
190758cc3dcSJack F Vogel static void	ixgbe_legacy_irq(void *);
191758cc3dcSJack F Vogel 
192758cc3dcSJack F Vogel /* The MSI/X Interrupt handlers */
193758cc3dcSJack F Vogel static void	ixgbe_msix_que(void *);
194758cc3dcSJack F Vogel static void	ixgbe_msix_link(void *);
195758cc3dcSJack F Vogel 
196758cc3dcSJack F Vogel /* Deferred interrupt tasklets */
197758cc3dcSJack F Vogel static void	ixgbe_handle_que(void *, int);
198758cc3dcSJack F Vogel static void	ixgbe_handle_link(void *, int);
199758cc3dcSJack F Vogel static void	ixgbe_handle_msf(void *, int);
200758cc3dcSJack F Vogel static void	ixgbe_handle_mod(void *, int);
201*6f37f232SEric Joyner static void	ixgbe_handle_phy(void *, int);
202758cc3dcSJack F Vogel 
203758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
204758cc3dcSJack F Vogel static void	ixgbe_reinit_fdir(void *, int);
205758cc3dcSJack F Vogel #endif
206758cc3dcSJack F Vogel 
207758cc3dcSJack F Vogel 
208758cc3dcSJack F Vogel /* Missing shared code prototype */
209758cc3dcSJack F Vogel extern void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw);
210758cc3dcSJack F Vogel 
211758cc3dcSJack F Vogel /*********************************************************************
212758cc3dcSJack F Vogel  *  FreeBSD Device Interface Entry Points
213758cc3dcSJack F Vogel  *********************************************************************/
214758cc3dcSJack F Vogel 
215a1edda90SAdrian Chadd static device_method_t ix_methods[] = {
216758cc3dcSJack F Vogel 	/* Device interface */
217758cc3dcSJack F Vogel 	DEVMETHOD(device_probe, ixgbe_probe),
218758cc3dcSJack F Vogel 	DEVMETHOD(device_attach, ixgbe_attach),
219758cc3dcSJack F Vogel 	DEVMETHOD(device_detach, ixgbe_detach),
220758cc3dcSJack F Vogel 	DEVMETHOD(device_shutdown, ixgbe_shutdown),
221*6f37f232SEric Joyner 	DEVMETHOD(device_suspend, ixgbe_suspend),
222*6f37f232SEric Joyner 	DEVMETHOD(device_resume, ixgbe_resume),
223758cc3dcSJack F Vogel 	DEVMETHOD_END
224758cc3dcSJack F Vogel };
225758cc3dcSJack F Vogel 
226a1edda90SAdrian Chadd static driver_t ix_driver = {
227a1edda90SAdrian Chadd 	"ix", ix_methods, sizeof(struct adapter),
228758cc3dcSJack F Vogel };
229758cc3dcSJack F Vogel 
230a1edda90SAdrian Chadd devclass_t ix_devclass;
231a1edda90SAdrian Chadd DRIVER_MODULE(ix, pci, ix_driver, ix_devclass, 0, 0);
232758cc3dcSJack F Vogel 
233a1edda90SAdrian Chadd MODULE_DEPEND(ix, pci, 1, 1, 1);
234a1edda90SAdrian Chadd MODULE_DEPEND(ix, ether, 1, 1, 1);
235758cc3dcSJack F Vogel 
236758cc3dcSJack F Vogel /*
237758cc3dcSJack F Vogel ** TUNEABLE PARAMETERS:
238758cc3dcSJack F Vogel */
239758cc3dcSJack F Vogel 
240758cc3dcSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0,
241758cc3dcSJack F Vogel 		   "IXGBE driver parameters");
242758cc3dcSJack F Vogel 
243758cc3dcSJack F Vogel /*
244758cc3dcSJack F Vogel ** AIM: Adaptive Interrupt Moderation
245758cc3dcSJack F Vogel ** which means that the interrupt rate
246758cc3dcSJack F Vogel ** is varied over time based on the
247758cc3dcSJack F Vogel ** traffic for that interrupt vector
248758cc3dcSJack F Vogel */
249758cc3dcSJack F Vogel static int ixgbe_enable_aim = TRUE;
250758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0,
251758cc3dcSJack F Vogel     "Enable adaptive interrupt moderation");
252758cc3dcSJack F Vogel 
253758cc3dcSJack F Vogel static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY);
254758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN,
255758cc3dcSJack F Vogel     &ixgbe_max_interrupt_rate, 0, "Maximum interrupts per second");
256758cc3dcSJack F Vogel 
257758cc3dcSJack F Vogel /* How many packets rxeof tries to clean at a time */
258758cc3dcSJack F Vogel static int ixgbe_rx_process_limit = 256;
259758cc3dcSJack F Vogel TUNABLE_INT("hw.ixgbe.rx_process_limit", &ixgbe_rx_process_limit);
260758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN,
261758cc3dcSJack F Vogel     &ixgbe_rx_process_limit, 0,
262758cc3dcSJack F Vogel     "Maximum number of received packets to process at a time,"
263758cc3dcSJack F Vogel     "-1 means unlimited");
264758cc3dcSJack F Vogel 
265758cc3dcSJack F Vogel /* How many packets txeof tries to clean at a time */
266758cc3dcSJack F Vogel static int ixgbe_tx_process_limit = 256;
267758cc3dcSJack F Vogel TUNABLE_INT("hw.ixgbe.tx_process_limit", &ixgbe_tx_process_limit);
268758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, tx_process_limit, CTLFLAG_RDTUN,
269758cc3dcSJack F Vogel     &ixgbe_tx_process_limit, 0,
270758cc3dcSJack F Vogel     "Maximum number of sent packets to process at a time,"
271758cc3dcSJack F Vogel     "-1 means unlimited");
272758cc3dcSJack F Vogel 
273758cc3dcSJack F Vogel /*
274758cc3dcSJack F Vogel ** Smart speed setting, default to on
275758cc3dcSJack F Vogel ** this only works as a compile option
276758cc3dcSJack F Vogel ** right now as its during attach, set
277758cc3dcSJack F Vogel ** this to 'ixgbe_smart_speed_off' to
278758cc3dcSJack F Vogel ** disable.
279758cc3dcSJack F Vogel */
280758cc3dcSJack F Vogel static int ixgbe_smart_speed = ixgbe_smart_speed_on;
281758cc3dcSJack F Vogel 
282758cc3dcSJack F Vogel /*
283758cc3dcSJack F Vogel  * MSIX should be the default for best performance,
284758cc3dcSJack F Vogel  * but this allows it to be forced off for testing.
285758cc3dcSJack F Vogel  */
286758cc3dcSJack F Vogel static int ixgbe_enable_msix = 1;
287758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixgbe_enable_msix, 0,
288758cc3dcSJack F Vogel     "Enable MSI-X interrupts");
289758cc3dcSJack F Vogel 
290758cc3dcSJack F Vogel /*
291758cc3dcSJack F Vogel  * Number of Queues, can be set to 0,
292758cc3dcSJack F Vogel  * it then autoconfigures based on the
293758cc3dcSJack F Vogel  * number of cpus with a max of 8. This
294758cc3dcSJack F Vogel  * can be overriden manually here.
295758cc3dcSJack F Vogel  */
296758cc3dcSJack F Vogel static int ixgbe_num_queues = 0;
297758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, num_queues, CTLFLAG_RDTUN, &ixgbe_num_queues, 0,
298758cc3dcSJack F Vogel     "Number of queues to configure, 0 indicates autoconfigure");
299758cc3dcSJack F Vogel 
300758cc3dcSJack F Vogel /*
301758cc3dcSJack F Vogel ** Number of TX descriptors per ring,
302758cc3dcSJack F Vogel ** setting higher than RX as this seems
303758cc3dcSJack F Vogel ** the better performing choice.
304758cc3dcSJack F Vogel */
305758cc3dcSJack F Vogel static int ixgbe_txd = PERFORM_TXD;
306758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, txd, CTLFLAG_RDTUN, &ixgbe_txd, 0,
307758cc3dcSJack F Vogel     "Number of transmit descriptors per queue");
308758cc3dcSJack F Vogel 
309758cc3dcSJack F Vogel /* Number of RX descriptors per ring */
310758cc3dcSJack F Vogel static int ixgbe_rxd = PERFORM_RXD;
311758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rxd, CTLFLAG_RDTUN, &ixgbe_rxd, 0,
312758cc3dcSJack F Vogel     "Number of receive descriptors per queue");
313758cc3dcSJack F Vogel 
314758cc3dcSJack F Vogel /*
315758cc3dcSJack F Vogel ** Defining this on will allow the use
316758cc3dcSJack F Vogel ** of unsupported SFP+ modules, note that
317758cc3dcSJack F Vogel ** doing so you are on your own :)
318758cc3dcSJack F Vogel */
319758cc3dcSJack F Vogel static int allow_unsupported_sfp = FALSE;
320758cc3dcSJack F Vogel TUNABLE_INT("hw.ix.unsupported_sfp", &allow_unsupported_sfp);
321758cc3dcSJack F Vogel 
322758cc3dcSJack F Vogel /* Keep running tab on them for sanity check */
323758cc3dcSJack F Vogel static int ixgbe_total_ports;
324758cc3dcSJack F Vogel 
325758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
326758cc3dcSJack F Vogel /*
327758cc3dcSJack F Vogel ** Flow Director actually 'steals'
328758cc3dcSJack F Vogel ** part of the packet buffer as its
329758cc3dcSJack F Vogel ** filter pool, this variable controls
330758cc3dcSJack F Vogel ** how much it uses:
331758cc3dcSJack F Vogel **  0 = 64K, 1 = 128K, 2 = 256K
332758cc3dcSJack F Vogel */
333758cc3dcSJack F Vogel static int fdir_pballoc = 1;
334758cc3dcSJack F Vogel #endif
335758cc3dcSJack F Vogel 
336758cc3dcSJack F Vogel #ifdef DEV_NETMAP
337758cc3dcSJack F Vogel /*
338758cc3dcSJack F Vogel  * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
339758cc3dcSJack F Vogel  * be a reference on how to implement netmap support in a driver.
340758cc3dcSJack F Vogel  * Additional comments are in ixgbe_netmap.h .
341758cc3dcSJack F Vogel  *
342758cc3dcSJack F Vogel  * <dev/netmap/ixgbe_netmap.h> contains functions for netmap support
343758cc3dcSJack F Vogel  * that extend the standard driver.
344758cc3dcSJack F Vogel  */
345758cc3dcSJack F Vogel #include <dev/netmap/ixgbe_netmap.h>
346758cc3dcSJack F Vogel #endif /* DEV_NETMAP */
347758cc3dcSJack F Vogel 
348758cc3dcSJack F Vogel /*********************************************************************
349758cc3dcSJack F Vogel  *  Device identification routine
350758cc3dcSJack F Vogel  *
351758cc3dcSJack F Vogel  *  ixgbe_probe determines if the driver should be loaded on
352758cc3dcSJack F Vogel  *  adapter based on PCI vendor/device id of the adapter.
353758cc3dcSJack F Vogel  *
354758cc3dcSJack F Vogel  *  return BUS_PROBE_DEFAULT on success, positive on failure
355758cc3dcSJack F Vogel  *********************************************************************/
356758cc3dcSJack F Vogel 
357758cc3dcSJack F Vogel static int
358758cc3dcSJack F Vogel ixgbe_probe(device_t dev)
359758cc3dcSJack F Vogel {
360758cc3dcSJack F Vogel 	ixgbe_vendor_info_t *ent;
361758cc3dcSJack F Vogel 
362758cc3dcSJack F Vogel 	u16	pci_vendor_id = 0;
363758cc3dcSJack F Vogel 	u16	pci_device_id = 0;
364758cc3dcSJack F Vogel 	u16	pci_subvendor_id = 0;
365758cc3dcSJack F Vogel 	u16	pci_subdevice_id = 0;
366758cc3dcSJack F Vogel 	char	adapter_name[256];
367758cc3dcSJack F Vogel 
368758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_probe: begin");
369758cc3dcSJack F Vogel 
370758cc3dcSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
371758cc3dcSJack F Vogel 	if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID)
372758cc3dcSJack F Vogel 		return (ENXIO);
373758cc3dcSJack F Vogel 
374758cc3dcSJack F Vogel 	pci_device_id = pci_get_device(dev);
375758cc3dcSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
376758cc3dcSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
377758cc3dcSJack F Vogel 
378758cc3dcSJack F Vogel 	ent = ixgbe_vendor_info_array;
379758cc3dcSJack F Vogel 	while (ent->vendor_id != 0) {
380758cc3dcSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
381758cc3dcSJack F Vogel 		    (pci_device_id == ent->device_id) &&
382758cc3dcSJack F Vogel 
383758cc3dcSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
384758cc3dcSJack F Vogel 		     (ent->subvendor_id == 0)) &&
385758cc3dcSJack F Vogel 
386758cc3dcSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
387758cc3dcSJack F Vogel 		     (ent->subdevice_id == 0))) {
388758cc3dcSJack F Vogel 			sprintf(adapter_name, "%s, Version - %s",
389758cc3dcSJack F Vogel 				ixgbe_strings[ent->index],
390758cc3dcSJack F Vogel 				ixgbe_driver_version);
391758cc3dcSJack F Vogel 			device_set_desc_copy(dev, adapter_name);
392758cc3dcSJack F Vogel 			++ixgbe_total_ports;
393758cc3dcSJack F Vogel 			return (BUS_PROBE_DEFAULT);
394758cc3dcSJack F Vogel 		}
395758cc3dcSJack F Vogel 		ent++;
396758cc3dcSJack F Vogel 	}
397758cc3dcSJack F Vogel 	return (ENXIO);
398758cc3dcSJack F Vogel }
399758cc3dcSJack F Vogel 
400758cc3dcSJack F Vogel /*********************************************************************
401758cc3dcSJack F Vogel  *  Device initialization routine
402758cc3dcSJack F Vogel  *
403758cc3dcSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
404758cc3dcSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
405758cc3dcSJack F Vogel  *  and initializes the hardware.
406758cc3dcSJack F Vogel  *
407758cc3dcSJack F Vogel  *  return 0 on success, positive on failure
408758cc3dcSJack F Vogel  *********************************************************************/
409758cc3dcSJack F Vogel 
410758cc3dcSJack F Vogel static int
411758cc3dcSJack F Vogel ixgbe_attach(device_t dev)
412758cc3dcSJack F Vogel {
413758cc3dcSJack F Vogel 	struct adapter *adapter;
414758cc3dcSJack F Vogel 	struct ixgbe_hw *hw;
415758cc3dcSJack F Vogel 	int             error = 0;
416758cc3dcSJack F Vogel 	u16		csum;
417758cc3dcSJack F Vogel 	u32		ctrl_ext;
418758cc3dcSJack F Vogel 
419758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_attach: begin");
420758cc3dcSJack F Vogel 
421758cc3dcSJack F Vogel 	/* Allocate, clear, and link in our adapter structure */
422758cc3dcSJack F Vogel 	adapter = device_get_softc(dev);
423758cc3dcSJack F Vogel 	adapter->dev = adapter->osdep.dev = dev;
424758cc3dcSJack F Vogel 	hw = &adapter->hw;
425758cc3dcSJack F Vogel 
426758cc3dcSJack F Vogel 	/* Core Lock Init*/
427758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev));
428758cc3dcSJack F Vogel 
429758cc3dcSJack F Vogel 	/* Set up the timer callout */
430758cc3dcSJack F Vogel 	callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0);
431758cc3dcSJack F Vogel 
432758cc3dcSJack F Vogel 	/* Determine hardware revision */
433758cc3dcSJack F Vogel 	ixgbe_identify_hardware(adapter);
434758cc3dcSJack F Vogel 
435758cc3dcSJack F Vogel 	/* Do base PCI setup - map BAR0 */
436758cc3dcSJack F Vogel 	if (ixgbe_allocate_pci_resources(adapter)) {
437758cc3dcSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
438758cc3dcSJack F Vogel 		error = ENXIO;
439758cc3dcSJack F Vogel 		goto err_out;
440758cc3dcSJack F Vogel 	}
441758cc3dcSJack F Vogel 
442758cc3dcSJack F Vogel 	/* Do descriptor calc and sanity checks */
443758cc3dcSJack F Vogel 	if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 ||
444758cc3dcSJack F Vogel 	    ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) {
445758cc3dcSJack F Vogel 		device_printf(dev, "TXD config issue, using default!\n");
446758cc3dcSJack F Vogel 		adapter->num_tx_desc = DEFAULT_TXD;
447758cc3dcSJack F Vogel 	} else
448758cc3dcSJack F Vogel 		adapter->num_tx_desc = ixgbe_txd;
449758cc3dcSJack F Vogel 
450758cc3dcSJack F Vogel 	/*
451758cc3dcSJack F Vogel 	** With many RX rings it is easy to exceed the
452758cc3dcSJack F Vogel 	** system mbuf allocation. Tuning nmbclusters
453758cc3dcSJack F Vogel 	** can alleviate this.
454758cc3dcSJack F Vogel 	*/
455758cc3dcSJack F Vogel 	if (nmbclusters > 0) {
456758cc3dcSJack F Vogel 		int s;
457758cc3dcSJack F Vogel 		s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports;
458758cc3dcSJack F Vogel 		if (s > nmbclusters) {
459758cc3dcSJack F Vogel 			device_printf(dev, "RX Descriptors exceed "
460758cc3dcSJack F Vogel 			    "system mbuf max, using default instead!\n");
461758cc3dcSJack F Vogel 			ixgbe_rxd = DEFAULT_RXD;
462758cc3dcSJack F Vogel 		}
463758cc3dcSJack F Vogel 	}
464758cc3dcSJack F Vogel 
465758cc3dcSJack F Vogel 	if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 ||
466758cc3dcSJack F Vogel 	    ixgbe_rxd < MIN_RXD || ixgbe_rxd > MAX_RXD) {
467758cc3dcSJack F Vogel 		device_printf(dev, "RXD config issue, using default!\n");
468758cc3dcSJack F Vogel 		adapter->num_rx_desc = DEFAULT_RXD;
469758cc3dcSJack F Vogel 	} else
470758cc3dcSJack F Vogel 		adapter->num_rx_desc = ixgbe_rxd;
471758cc3dcSJack F Vogel 
472758cc3dcSJack F Vogel 	/* Allocate our TX/RX Queues */
473758cc3dcSJack F Vogel 	if (ixgbe_allocate_queues(adapter)) {
474758cc3dcSJack F Vogel 		error = ENOMEM;
475758cc3dcSJack F Vogel 		goto err_out;
476758cc3dcSJack F Vogel 	}
477758cc3dcSJack F Vogel 
478758cc3dcSJack F Vogel 	/* Allocate multicast array memory. */
479758cc3dcSJack F Vogel 	adapter->mta = malloc(sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS *
480758cc3dcSJack F Vogel 	    MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT);
481758cc3dcSJack F Vogel 	if (adapter->mta == NULL) {
482758cc3dcSJack F Vogel 		device_printf(dev, "Can not allocate multicast setup array\n");
483758cc3dcSJack F Vogel 		error = ENOMEM;
484758cc3dcSJack F Vogel 		goto err_late;
485758cc3dcSJack F Vogel 	}
486758cc3dcSJack F Vogel 
487758cc3dcSJack F Vogel 	/* Initialize the shared code */
488758cc3dcSJack F Vogel 	hw->allow_unsupported_sfp = allow_unsupported_sfp;
489758cc3dcSJack F Vogel 	error = ixgbe_init_shared_code(hw);
490758cc3dcSJack F Vogel 	if (error == IXGBE_ERR_SFP_NOT_PRESENT) {
491758cc3dcSJack F Vogel 		/*
492758cc3dcSJack F Vogel 		** No optics in this port, set up
493758cc3dcSJack F Vogel 		** so the timer routine will probe
494758cc3dcSJack F Vogel 		** for later insertion.
495758cc3dcSJack F Vogel 		*/
496758cc3dcSJack F Vogel 		adapter->sfp_probe = TRUE;
497758cc3dcSJack F Vogel 		error = 0;
498758cc3dcSJack F Vogel 	} else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) {
499758cc3dcSJack F Vogel 		device_printf(dev,"Unsupported SFP+ module detected!\n");
500758cc3dcSJack F Vogel 		error = EIO;
501758cc3dcSJack F Vogel 		goto err_late;
502758cc3dcSJack F Vogel 	} else if (error) {
503758cc3dcSJack F Vogel 		device_printf(dev,"Unable to initialize the shared code\n");
504758cc3dcSJack F Vogel 		error = EIO;
505758cc3dcSJack F Vogel 		goto err_late;
506758cc3dcSJack F Vogel 	}
507758cc3dcSJack F Vogel 
508758cc3dcSJack F Vogel 	/* Make sure we have a good EEPROM before we read from it */
509758cc3dcSJack F Vogel 	if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) {
510758cc3dcSJack F Vogel 		device_printf(dev,"The EEPROM Checksum Is Not Valid\n");
511758cc3dcSJack F Vogel 		error = EIO;
512758cc3dcSJack F Vogel 		goto err_late;
513758cc3dcSJack F Vogel 	}
514758cc3dcSJack F Vogel 
515758cc3dcSJack F Vogel 	error = ixgbe_init_hw(hw);
516758cc3dcSJack F Vogel 	switch (error) {
517758cc3dcSJack F Vogel 	case IXGBE_ERR_EEPROM_VERSION:
518758cc3dcSJack F Vogel 		device_printf(dev, "This device is a pre-production adapter/"
519758cc3dcSJack F Vogel 		    "LOM.  Please be aware there may be issues associated "
520758cc3dcSJack F Vogel 		    "with your hardware.\n If you are experiencing problems "
521758cc3dcSJack F Vogel 		    "please contact your Intel or hardware representative "
522758cc3dcSJack F Vogel 		    "who provided you with this hardware.\n");
523758cc3dcSJack F Vogel 		break;
524758cc3dcSJack F Vogel 	case IXGBE_ERR_SFP_NOT_SUPPORTED:
525758cc3dcSJack F Vogel 		device_printf(dev,"Unsupported SFP+ Module\n");
526758cc3dcSJack F Vogel 		error = EIO;
527758cc3dcSJack F Vogel 		goto err_late;
528758cc3dcSJack F Vogel 	case IXGBE_ERR_SFP_NOT_PRESENT:
529758cc3dcSJack F Vogel 		device_printf(dev,"No SFP+ Module found\n");
530758cc3dcSJack F Vogel 		/* falls thru */
531758cc3dcSJack F Vogel 	default:
532758cc3dcSJack F Vogel 		break;
533758cc3dcSJack F Vogel 	}
534758cc3dcSJack F Vogel 
535758cc3dcSJack F Vogel 	/* Detect and set physical type */
536758cc3dcSJack F Vogel 	ixgbe_setup_optics(adapter);
537758cc3dcSJack F Vogel 
538758cc3dcSJack F Vogel 	if ((adapter->msix > 1) && (ixgbe_enable_msix))
539758cc3dcSJack F Vogel 		error = ixgbe_allocate_msix(adapter);
540758cc3dcSJack F Vogel 	else
541758cc3dcSJack F Vogel 		error = ixgbe_allocate_legacy(adapter);
542758cc3dcSJack F Vogel 	if (error)
543758cc3dcSJack F Vogel 		goto err_late;
544758cc3dcSJack F Vogel 
545758cc3dcSJack F Vogel 	/* Setup OS specific network interface */
546758cc3dcSJack F Vogel 	if (ixgbe_setup_interface(dev, adapter) != 0)
547758cc3dcSJack F Vogel 		goto err_late;
548758cc3dcSJack F Vogel 
549758cc3dcSJack F Vogel 	/* Initialize statistics */
550758cc3dcSJack F Vogel 	ixgbe_update_stats_counters(adapter);
551758cc3dcSJack F Vogel 
552758cc3dcSJack F Vogel 	/* Register for VLAN events */
553758cc3dcSJack F Vogel 	adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
554758cc3dcSJack F Vogel 	    ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST);
555758cc3dcSJack F Vogel 	adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
556758cc3dcSJack F Vogel 	    ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST);
557758cc3dcSJack F Vogel 
558*6f37f232SEric Joyner         /* Check PCIE slot type/speed/width */
559758cc3dcSJack F Vogel 	ixgbe_get_slot_info(hw);
560758cc3dcSJack F Vogel 
561758cc3dcSJack F Vogel 
562758cc3dcSJack F Vogel 	/* Set an initial default flow control value */
563758cc3dcSJack F Vogel 	adapter->fc = ixgbe_fc_full;
564758cc3dcSJack F Vogel 
565*6f37f232SEric Joyner 	/* Check for certain supported features */
566*6f37f232SEric Joyner 	ixgbe_check_wol_support(adapter);
567*6f37f232SEric Joyner 	ixgbe_check_eee_support(adapter);
568*6f37f232SEric Joyner 
569*6f37f232SEric Joyner 	/* Add sysctls */
570*6f37f232SEric Joyner 	ixgbe_add_device_sysctls(adapter);
571*6f37f232SEric Joyner 	ixgbe_add_hw_stats(adapter);
572*6f37f232SEric Joyner 
573758cc3dcSJack F Vogel 	/* let hardware know driver is loaded */
574758cc3dcSJack F Vogel 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
575758cc3dcSJack F Vogel 	ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
576758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
577758cc3dcSJack F Vogel 
578758cc3dcSJack F Vogel #ifdef DEV_NETMAP
579758cc3dcSJack F Vogel 	ixgbe_netmap_attach(adapter);
580758cc3dcSJack F Vogel #endif /* DEV_NETMAP */
581758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_attach: end");
582758cc3dcSJack F Vogel 	return (0);
583758cc3dcSJack F Vogel 
584758cc3dcSJack F Vogel err_late:
585758cc3dcSJack F Vogel 	ixgbe_free_transmit_structures(adapter);
586758cc3dcSJack F Vogel 	ixgbe_free_receive_structures(adapter);
587758cc3dcSJack F Vogel err_out:
588758cc3dcSJack F Vogel 	if (adapter->ifp != NULL)
589758cc3dcSJack F Vogel 		if_free(adapter->ifp);
590758cc3dcSJack F Vogel 	ixgbe_free_pci_resources(adapter);
591758cc3dcSJack F Vogel 	free(adapter->mta, M_DEVBUF);
592758cc3dcSJack F Vogel 	return (error);
593758cc3dcSJack F Vogel }
594758cc3dcSJack F Vogel 
595758cc3dcSJack F Vogel /*********************************************************************
596758cc3dcSJack F Vogel  *  Device removal routine
597758cc3dcSJack F Vogel  *
598758cc3dcSJack F Vogel  *  The detach entry point is called when the driver is being removed.
599758cc3dcSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
600758cc3dcSJack F Vogel  *  that were allocated for driver operation.
601758cc3dcSJack F Vogel  *
602758cc3dcSJack F Vogel  *  return 0 on success, positive on failure
603758cc3dcSJack F Vogel  *********************************************************************/
604758cc3dcSJack F Vogel 
605758cc3dcSJack F Vogel static int
606758cc3dcSJack F Vogel ixgbe_detach(device_t dev)
607758cc3dcSJack F Vogel {
608758cc3dcSJack F Vogel 	struct adapter *adapter = device_get_softc(dev);
609758cc3dcSJack F Vogel 	struct ix_queue *que = adapter->queues;
610758cc3dcSJack F Vogel 	struct tx_ring *txr = adapter->tx_rings;
611758cc3dcSJack F Vogel 	u32	ctrl_ext;
612758cc3dcSJack F Vogel 
613758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_detach: begin");
614758cc3dcSJack F Vogel 
615758cc3dcSJack F Vogel 	/* Make sure VLANS are not using driver */
616758cc3dcSJack F Vogel 	if (adapter->ifp->if_vlantrunk != NULL) {
617758cc3dcSJack F Vogel 		device_printf(dev,"Vlan in use, detach first\n");
618758cc3dcSJack F Vogel 		return (EBUSY);
619758cc3dcSJack F Vogel 	}
620758cc3dcSJack F Vogel 
621*6f37f232SEric Joyner 	/* Stop the adapter */
622758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
623*6f37f232SEric Joyner 	ixgbe_setup_low_power_mode(adapter);
624758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
625758cc3dcSJack F Vogel 
626758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, que++, txr++) {
627758cc3dcSJack F Vogel 		if (que->tq) {
628758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
629758cc3dcSJack F Vogel 			taskqueue_drain(que->tq, &txr->txq_task);
630758cc3dcSJack F Vogel #endif
631758cc3dcSJack F Vogel 			taskqueue_drain(que->tq, &que->que_task);
632758cc3dcSJack F Vogel 			taskqueue_free(que->tq);
633758cc3dcSJack F Vogel 		}
634758cc3dcSJack F Vogel 	}
635758cc3dcSJack F Vogel 
636758cc3dcSJack F Vogel 	/* Drain the Link queue */
637758cc3dcSJack F Vogel 	if (adapter->tq) {
638758cc3dcSJack F Vogel 		taskqueue_drain(adapter->tq, &adapter->link_task);
639758cc3dcSJack F Vogel 		taskqueue_drain(adapter->tq, &adapter->mod_task);
640758cc3dcSJack F Vogel 		taskqueue_drain(adapter->tq, &adapter->msf_task);
641*6f37f232SEric Joyner 		taskqueue_drain(adapter->tq, &adapter->phy_task);
642758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
643758cc3dcSJack F Vogel 		taskqueue_drain(adapter->tq, &adapter->fdir_task);
644758cc3dcSJack F Vogel #endif
645758cc3dcSJack F Vogel 		taskqueue_free(adapter->tq);
646758cc3dcSJack F Vogel 	}
647758cc3dcSJack F Vogel 
648758cc3dcSJack F Vogel 	/* let hardware know driver is unloading */
649758cc3dcSJack F Vogel 	ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
650758cc3dcSJack F Vogel 	ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
651758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext);
652758cc3dcSJack F Vogel 
653758cc3dcSJack F Vogel 	/* Unregister VLAN events */
654758cc3dcSJack F Vogel 	if (adapter->vlan_attach != NULL)
655758cc3dcSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach);
656758cc3dcSJack F Vogel 	if (adapter->vlan_detach != NULL)
657758cc3dcSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach);
658758cc3dcSJack F Vogel 
659758cc3dcSJack F Vogel 	ether_ifdetach(adapter->ifp);
660758cc3dcSJack F Vogel 	callout_drain(&adapter->timer);
661758cc3dcSJack F Vogel #ifdef DEV_NETMAP
662758cc3dcSJack F Vogel 	netmap_detach(adapter->ifp);
663758cc3dcSJack F Vogel #endif /* DEV_NETMAP */
664758cc3dcSJack F Vogel 	ixgbe_free_pci_resources(adapter);
665758cc3dcSJack F Vogel 	bus_generic_detach(dev);
666758cc3dcSJack F Vogel 	if_free(adapter->ifp);
667758cc3dcSJack F Vogel 
668758cc3dcSJack F Vogel 	ixgbe_free_transmit_structures(adapter);
669758cc3dcSJack F Vogel 	ixgbe_free_receive_structures(adapter);
670758cc3dcSJack F Vogel 	free(adapter->mta, M_DEVBUF);
671758cc3dcSJack F Vogel 
672758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK_DESTROY(adapter);
673758cc3dcSJack F Vogel 	return (0);
674758cc3dcSJack F Vogel }
675758cc3dcSJack F Vogel 
676758cc3dcSJack F Vogel /*********************************************************************
677758cc3dcSJack F Vogel  *
678758cc3dcSJack F Vogel  *  Shutdown entry point
679758cc3dcSJack F Vogel  *
680758cc3dcSJack F Vogel  **********************************************************************/
681758cc3dcSJack F Vogel 
682758cc3dcSJack F Vogel static int
683758cc3dcSJack F Vogel ixgbe_shutdown(device_t dev)
684758cc3dcSJack F Vogel {
685758cc3dcSJack F Vogel 	struct adapter *adapter = device_get_softc(dev);
686*6f37f232SEric Joyner 	int error = 0;
687*6f37f232SEric Joyner 
688*6f37f232SEric Joyner 	INIT_DEBUGOUT("ixgbe_shutdown: begin");
689*6f37f232SEric Joyner 
690758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
691*6f37f232SEric Joyner 	error = ixgbe_setup_low_power_mode(adapter);
692758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
693*6f37f232SEric Joyner 
694*6f37f232SEric Joyner 	return (error);
695*6f37f232SEric Joyner }
696*6f37f232SEric Joyner 
697*6f37f232SEric Joyner /**
698*6f37f232SEric Joyner  * Methods for going from:
699*6f37f232SEric Joyner  * D0 -> D3: ixgbe_suspend
700*6f37f232SEric Joyner  * D3 -> D0: ixgbe_resume
701*6f37f232SEric Joyner  */
702*6f37f232SEric Joyner static int
703*6f37f232SEric Joyner ixgbe_suspend(device_t dev)
704*6f37f232SEric Joyner {
705*6f37f232SEric Joyner 	struct adapter *adapter = device_get_softc(dev);
706*6f37f232SEric Joyner 	int error = 0;
707*6f37f232SEric Joyner 
708*6f37f232SEric Joyner 	INIT_DEBUGOUT("ixgbe_suspend: begin");
709*6f37f232SEric Joyner 
710*6f37f232SEric Joyner 	IXGBE_CORE_LOCK(adapter);
711*6f37f232SEric Joyner 
712*6f37f232SEric Joyner 	error = ixgbe_setup_low_power_mode(adapter);
713*6f37f232SEric Joyner 
714*6f37f232SEric Joyner 	/* Save state and power down */
715*6f37f232SEric Joyner 	pci_save_state(dev);
716*6f37f232SEric Joyner 	pci_set_powerstate(dev, PCI_POWERSTATE_D3);
717*6f37f232SEric Joyner 
718*6f37f232SEric Joyner 	IXGBE_CORE_UNLOCK(adapter);
719*6f37f232SEric Joyner 
720*6f37f232SEric Joyner 	return (error);
721*6f37f232SEric Joyner }
722*6f37f232SEric Joyner 
723*6f37f232SEric Joyner static int
724*6f37f232SEric Joyner ixgbe_resume(device_t dev)
725*6f37f232SEric Joyner {
726*6f37f232SEric Joyner 	struct adapter *adapter = device_get_softc(dev);
727*6f37f232SEric Joyner 	struct ifnet *ifp = adapter->ifp;
728*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
729*6f37f232SEric Joyner 	u32 wus;
730*6f37f232SEric Joyner 
731*6f37f232SEric Joyner 	INIT_DEBUGOUT("ixgbe_resume: begin");
732*6f37f232SEric Joyner 
733*6f37f232SEric Joyner 	IXGBE_CORE_LOCK(adapter);
734*6f37f232SEric Joyner 
735*6f37f232SEric Joyner 	pci_set_powerstate(dev, PCI_POWERSTATE_D0);
736*6f37f232SEric Joyner 	pci_restore_state(dev);
737*6f37f232SEric Joyner 
738*6f37f232SEric Joyner 	/* Read & clear WUS register */
739*6f37f232SEric Joyner 	wus = IXGBE_READ_REG(hw, IXGBE_WUS);
740*6f37f232SEric Joyner 	if (wus)
741*6f37f232SEric Joyner 		device_printf(dev, "Woken up by (WUS): %#010x\n",
742*6f37f232SEric Joyner 		    IXGBE_READ_REG(hw, IXGBE_WUS));
743*6f37f232SEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
744*6f37f232SEric Joyner 	/* And clear WUFC until next low-power transition */
745*6f37f232SEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0);
746*6f37f232SEric Joyner 
747*6f37f232SEric Joyner 	/*
748*6f37f232SEric Joyner 	 * Required after D3->D0 transition;
749*6f37f232SEric Joyner 	 * will re-advertise all previous advertised speeds
750*6f37f232SEric Joyner 	 */
751*6f37f232SEric Joyner 	if (ifp->if_flags & IFF_UP)
752*6f37f232SEric Joyner 		ixgbe_init_locked(adapter);
753*6f37f232SEric Joyner 
754*6f37f232SEric Joyner 	IXGBE_CORE_UNLOCK(adapter);
755*6f37f232SEric Joyner 
756*6f37f232SEric Joyner 	INIT_DEBUGOUT("ixgbe_resume: end");
757758cc3dcSJack F Vogel 	return (0);
758758cc3dcSJack F Vogel }
759758cc3dcSJack F Vogel 
760758cc3dcSJack F Vogel 
761758cc3dcSJack F Vogel /*********************************************************************
762758cc3dcSJack F Vogel  *  Ioctl entry point
763758cc3dcSJack F Vogel  *
764758cc3dcSJack F Vogel  *  ixgbe_ioctl is called when the user wants to configure the
765758cc3dcSJack F Vogel  *  interface.
766758cc3dcSJack F Vogel  *
767758cc3dcSJack F Vogel  *  return 0 on success, positive on failure
768758cc3dcSJack F Vogel  **********************************************************************/
769758cc3dcSJack F Vogel 
770758cc3dcSJack F Vogel static int
771758cc3dcSJack F Vogel ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
772758cc3dcSJack F Vogel {
773758cc3dcSJack F Vogel 	struct adapter	*adapter = ifp->if_softc;
774758cc3dcSJack F Vogel 	struct ifreq	*ifr = (struct ifreq *) data;
775758cc3dcSJack F Vogel #if defined(INET) || defined(INET6)
776758cc3dcSJack F Vogel 	struct ifaddr *ifa = (struct ifaddr *)data;
777758cc3dcSJack F Vogel 	bool		avoid_reset = FALSE;
778758cc3dcSJack F Vogel #endif
779758cc3dcSJack F Vogel 	int             error = 0;
780758cc3dcSJack F Vogel 
781758cc3dcSJack F Vogel 	switch (command) {
782758cc3dcSJack F Vogel 
783758cc3dcSJack F Vogel         case SIOCSIFADDR:
784758cc3dcSJack F Vogel #ifdef INET
785758cc3dcSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET)
786758cc3dcSJack F Vogel 			avoid_reset = TRUE;
787758cc3dcSJack F Vogel #endif
788758cc3dcSJack F Vogel #ifdef INET6
789758cc3dcSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET6)
790758cc3dcSJack F Vogel 			avoid_reset = TRUE;
791758cc3dcSJack F Vogel #endif
792758cc3dcSJack F Vogel #if defined(INET) || defined(INET6)
793758cc3dcSJack F Vogel 		/*
794758cc3dcSJack F Vogel 		** Calling init results in link renegotiation,
795758cc3dcSJack F Vogel 		** so we avoid doing it when possible.
796758cc3dcSJack F Vogel 		*/
797758cc3dcSJack F Vogel 		if (avoid_reset) {
798758cc3dcSJack F Vogel 			ifp->if_flags |= IFF_UP;
799758cc3dcSJack F Vogel 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
800758cc3dcSJack F Vogel 				ixgbe_init(adapter);
801758cc3dcSJack F Vogel 			if (!(ifp->if_flags & IFF_NOARP))
802758cc3dcSJack F Vogel 				arp_ifinit(ifp, ifa);
803758cc3dcSJack F Vogel 		} else
804758cc3dcSJack F Vogel 			error = ether_ioctl(ifp, command, data);
805758cc3dcSJack F Vogel #endif
806758cc3dcSJack F Vogel 		break;
807758cc3dcSJack F Vogel 	case SIOCSIFMTU:
808758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
809*6f37f232SEric Joyner 		if (ifr->ifr_mtu > IXGBE_MAX_MTU) {
810758cc3dcSJack F Vogel 			error = EINVAL;
811758cc3dcSJack F Vogel 		} else {
812758cc3dcSJack F Vogel 			IXGBE_CORE_LOCK(adapter);
813758cc3dcSJack F Vogel 			ifp->if_mtu = ifr->ifr_mtu;
814758cc3dcSJack F Vogel 			adapter->max_frame_size =
815*6f37f232SEric Joyner 				ifp->if_mtu + IXGBE_MTU_HDR;
816758cc3dcSJack F Vogel 			ixgbe_init_locked(adapter);
817758cc3dcSJack F Vogel 			IXGBE_CORE_UNLOCK(adapter);
818758cc3dcSJack F Vogel 		}
819758cc3dcSJack F Vogel 		break;
820758cc3dcSJack F Vogel 	case SIOCSIFFLAGS:
821758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
822758cc3dcSJack F Vogel 		IXGBE_CORE_LOCK(adapter);
823758cc3dcSJack F Vogel 		if (ifp->if_flags & IFF_UP) {
824758cc3dcSJack F Vogel 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
825758cc3dcSJack F Vogel 				if ((ifp->if_flags ^ adapter->if_flags) &
826758cc3dcSJack F Vogel 				    (IFF_PROMISC | IFF_ALLMULTI)) {
827758cc3dcSJack F Vogel 					ixgbe_set_promisc(adapter);
828758cc3dcSJack F Vogel                                 }
829758cc3dcSJack F Vogel 			} else
830758cc3dcSJack F Vogel 				ixgbe_init_locked(adapter);
831758cc3dcSJack F Vogel 		} else
832758cc3dcSJack F Vogel 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
833758cc3dcSJack F Vogel 				ixgbe_stop(adapter);
834758cc3dcSJack F Vogel 		adapter->if_flags = ifp->if_flags;
835758cc3dcSJack F Vogel 		IXGBE_CORE_UNLOCK(adapter);
836758cc3dcSJack F Vogel 		break;
837758cc3dcSJack F Vogel 	case SIOCADDMULTI:
838758cc3dcSJack F Vogel 	case SIOCDELMULTI:
839758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI");
840758cc3dcSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
841758cc3dcSJack F Vogel 			IXGBE_CORE_LOCK(adapter);
842758cc3dcSJack F Vogel 			ixgbe_disable_intr(adapter);
843758cc3dcSJack F Vogel 			ixgbe_set_multi(adapter);
844758cc3dcSJack F Vogel 			ixgbe_enable_intr(adapter);
845758cc3dcSJack F Vogel 			IXGBE_CORE_UNLOCK(adapter);
846758cc3dcSJack F Vogel 		}
847758cc3dcSJack F Vogel 		break;
848758cc3dcSJack F Vogel 	case SIOCSIFMEDIA:
849758cc3dcSJack F Vogel 	case SIOCGIFMEDIA:
850758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
851758cc3dcSJack F Vogel 		error = ifmedia_ioctl(ifp, ifr, &adapter->media, command);
852758cc3dcSJack F Vogel 		break;
853758cc3dcSJack F Vogel 	case SIOCSIFCAP:
854758cc3dcSJack F Vogel 	{
855758cc3dcSJack F Vogel 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
856758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
857758cc3dcSJack F Vogel 		if (mask & IFCAP_HWCSUM)
858758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_HWCSUM;
859758cc3dcSJack F Vogel 		if (mask & IFCAP_TSO4)
860758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_TSO4;
861758cc3dcSJack F Vogel 		if (mask & IFCAP_TSO6)
862758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_TSO6;
863758cc3dcSJack F Vogel 		if (mask & IFCAP_LRO)
864758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_LRO;
865758cc3dcSJack F Vogel 		if (mask & IFCAP_VLAN_HWTAGGING)
866758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
867758cc3dcSJack F Vogel 		if (mask & IFCAP_VLAN_HWFILTER)
868758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
869758cc3dcSJack F Vogel 		if (mask & IFCAP_VLAN_HWTSO)
870758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
871758cc3dcSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
872758cc3dcSJack F Vogel 			IXGBE_CORE_LOCK(adapter);
873758cc3dcSJack F Vogel 			ixgbe_init_locked(adapter);
874758cc3dcSJack F Vogel 			IXGBE_CORE_UNLOCK(adapter);
875758cc3dcSJack F Vogel 		}
876758cc3dcSJack F Vogel 		VLAN_CAPABILITIES(ifp);
877758cc3dcSJack F Vogel 		break;
878758cc3dcSJack F Vogel 	}
879758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036
880758cc3dcSJack F Vogel 	case SIOCGI2C:
881758cc3dcSJack F Vogel 	{
882758cc3dcSJack F Vogel 		struct ixgbe_hw *hw = &adapter->hw;
883758cc3dcSJack F Vogel 		struct ifi2creq i2c;
884758cc3dcSJack F Vogel 		int i;
885758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)");
886758cc3dcSJack F Vogel 		error = copyin(ifr->ifr_data, &i2c, sizeof(i2c));
887758cc3dcSJack F Vogel 		if (error != 0)
888758cc3dcSJack F Vogel 			break;
889758cc3dcSJack F Vogel 		if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) {
890758cc3dcSJack F Vogel 			error = EINVAL;
891758cc3dcSJack F Vogel 			break;
892758cc3dcSJack F Vogel 		}
893758cc3dcSJack F Vogel 		if (i2c.len > sizeof(i2c.data)) {
894758cc3dcSJack F Vogel 			error = EINVAL;
895758cc3dcSJack F Vogel 			break;
896758cc3dcSJack F Vogel 		}
897758cc3dcSJack F Vogel 
898758cc3dcSJack F Vogel 		for (i = 0; i < i2c.len; i++)
899758cc3dcSJack F Vogel 			hw->phy.ops.read_i2c_byte(hw, i2c.offset + i,
900758cc3dcSJack F Vogel 			    i2c.dev_addr, &i2c.data[i]);
901758cc3dcSJack F Vogel 		error = copyout(&i2c, ifr->ifr_data, sizeof(i2c));
902758cc3dcSJack F Vogel 		break;
903758cc3dcSJack F Vogel 	}
904758cc3dcSJack F Vogel #endif
905758cc3dcSJack F Vogel 	default:
906758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command);
907758cc3dcSJack F Vogel 		error = ether_ioctl(ifp, command, data);
908758cc3dcSJack F Vogel 		break;
909758cc3dcSJack F Vogel 	}
910758cc3dcSJack F Vogel 
911758cc3dcSJack F Vogel 	return (error);
912758cc3dcSJack F Vogel }
913758cc3dcSJack F Vogel 
914758cc3dcSJack F Vogel /*********************************************************************
915758cc3dcSJack F Vogel  *  Init entry point
916758cc3dcSJack F Vogel  *
917758cc3dcSJack F Vogel  *  This routine is used in two ways. It is used by the stack as
918758cc3dcSJack F Vogel  *  init entry point in network interface structure. It is also used
919758cc3dcSJack F Vogel  *  by the driver as a hw/sw initialization routine to get to a
920758cc3dcSJack F Vogel  *  consistent state.
921758cc3dcSJack F Vogel  *
922758cc3dcSJack F Vogel  *  return 0 on success, positive on failure
923758cc3dcSJack F Vogel  **********************************************************************/
924758cc3dcSJack F Vogel #define IXGBE_MHADD_MFS_SHIFT 16
925758cc3dcSJack F Vogel 
926758cc3dcSJack F Vogel static void
927758cc3dcSJack F Vogel ixgbe_init_locked(struct adapter *adapter)
928758cc3dcSJack F Vogel {
929758cc3dcSJack F Vogel 	struct ifnet   *ifp = adapter->ifp;
930758cc3dcSJack F Vogel 	device_t 	dev = adapter->dev;
931758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
932758cc3dcSJack F Vogel 	u32		k, txdctl, mhadd, gpie;
933758cc3dcSJack F Vogel 	u32		rxdctl, rxctrl;
934758cc3dcSJack F Vogel 
935758cc3dcSJack F Vogel 	mtx_assert(&adapter->core_mtx, MA_OWNED);
936758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_init_locked: begin");
937758cc3dcSJack F Vogel 	hw->adapter_stopped = FALSE;
938758cc3dcSJack F Vogel 	ixgbe_stop_adapter(hw);
939758cc3dcSJack F Vogel         callout_stop(&adapter->timer);
940758cc3dcSJack F Vogel 
941758cc3dcSJack F Vogel         /* reprogram the RAR[0] in case user changed it. */
942758cc3dcSJack F Vogel         ixgbe_set_rar(hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV);
943758cc3dcSJack F Vogel 
944758cc3dcSJack F Vogel 	/* Get the latest mac address, User can use a LAA */
945758cc3dcSJack F Vogel 	bcopy(IF_LLADDR(adapter->ifp), hw->mac.addr,
946758cc3dcSJack F Vogel 	      IXGBE_ETH_LENGTH_OF_ADDRESS);
947758cc3dcSJack F Vogel 	ixgbe_set_rar(hw, 0, hw->mac.addr, 0, 1);
948758cc3dcSJack F Vogel 	hw->addr_ctrl.rar_used_count = 1;
949758cc3dcSJack F Vogel 
950758cc3dcSJack F Vogel 	/* Set the various hardware offload abilities */
951758cc3dcSJack F Vogel 	ifp->if_hwassist = 0;
952758cc3dcSJack F Vogel 	if (ifp->if_capenable & IFCAP_TSO)
953758cc3dcSJack F Vogel 		ifp->if_hwassist |= CSUM_TSO;
954758cc3dcSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM) {
955758cc3dcSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
956758cc3dcSJack F Vogel #if __FreeBSD_version >= 800000
957758cc3dcSJack F Vogel 		if (hw->mac.type != ixgbe_mac_82598EB)
958758cc3dcSJack F Vogel 			ifp->if_hwassist |= CSUM_SCTP;
959758cc3dcSJack F Vogel #endif
960758cc3dcSJack F Vogel 	}
961758cc3dcSJack F Vogel 
962758cc3dcSJack F Vogel 	/* Prepare transmit descriptors and buffers */
963758cc3dcSJack F Vogel 	if (ixgbe_setup_transmit_structures(adapter)) {
964758cc3dcSJack F Vogel 		device_printf(dev, "Could not setup transmit structures\n");
965758cc3dcSJack F Vogel 		ixgbe_stop(adapter);
966758cc3dcSJack F Vogel 		return;
967758cc3dcSJack F Vogel 	}
968758cc3dcSJack F Vogel 
969758cc3dcSJack F Vogel 	ixgbe_init_hw(hw);
970758cc3dcSJack F Vogel 	ixgbe_initialize_transmit_units(adapter);
971758cc3dcSJack F Vogel 
972758cc3dcSJack F Vogel 	/* Setup Multicast table */
973758cc3dcSJack F Vogel 	ixgbe_set_multi(adapter);
974758cc3dcSJack F Vogel 
975758cc3dcSJack F Vogel 	/*
976758cc3dcSJack F Vogel 	** Determine the correct mbuf pool
977758cc3dcSJack F Vogel 	** for doing jumbo frames
978758cc3dcSJack F Vogel 	*/
979758cc3dcSJack F Vogel 	if (adapter->max_frame_size <= 2048)
980758cc3dcSJack F Vogel 		adapter->rx_mbuf_sz = MCLBYTES;
981758cc3dcSJack F Vogel 	else if (adapter->max_frame_size <= 4096)
982758cc3dcSJack F Vogel 		adapter->rx_mbuf_sz = MJUMPAGESIZE;
983758cc3dcSJack F Vogel 	else if (adapter->max_frame_size <= 9216)
984758cc3dcSJack F Vogel 		adapter->rx_mbuf_sz = MJUM9BYTES;
985758cc3dcSJack F Vogel 	else
986758cc3dcSJack F Vogel 		adapter->rx_mbuf_sz = MJUM16BYTES;
987758cc3dcSJack F Vogel 
988758cc3dcSJack F Vogel 	/* Prepare receive descriptors and buffers */
989758cc3dcSJack F Vogel 	if (ixgbe_setup_receive_structures(adapter)) {
990758cc3dcSJack F Vogel 		device_printf(dev, "Could not setup receive structures\n");
991758cc3dcSJack F Vogel 		ixgbe_stop(adapter);
992758cc3dcSJack F Vogel 		return;
993758cc3dcSJack F Vogel 	}
994758cc3dcSJack F Vogel 
995758cc3dcSJack F Vogel 	/* Configure RX settings */
996758cc3dcSJack F Vogel 	ixgbe_initialize_receive_units(adapter);
997758cc3dcSJack F Vogel 
998758cc3dcSJack F Vogel 	gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE);
999758cc3dcSJack F Vogel 
1000758cc3dcSJack F Vogel 	/* Enable Fan Failure Interrupt */
1001758cc3dcSJack F Vogel 	gpie |= IXGBE_SDP1_GPIEN_BY_MAC(hw);
1002758cc3dcSJack F Vogel 
1003758cc3dcSJack F Vogel 	/* Add for Module detection */
1004758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82599EB)
1005*6f37f232SEric Joyner 		gpie |= IXGBE_SDP2_GPIEN;
1006758cc3dcSJack F Vogel 
1007*6f37f232SEric Joyner 	/*
1008*6f37f232SEric Joyner 	 * Thermal Failure Detection (X540)
1009*6f37f232SEric Joyner 	 * Link Detection (X552)
1010*6f37f232SEric Joyner 	 */
1011*6f37f232SEric Joyner 	if (hw->mac.type == ixgbe_mac_X540 ||
1012*6f37f232SEric Joyner 	    hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
1013*6f37f232SEric Joyner 	    hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T)
1014*6f37f232SEric Joyner 		gpie |= IXGBE_SDP0_GPIEN_X540;
1015758cc3dcSJack F Vogel 
1016758cc3dcSJack F Vogel 	if (adapter->msix > 1) {
1017758cc3dcSJack F Vogel 		/* Enable Enhanced MSIX mode */
1018758cc3dcSJack F Vogel 		gpie |= IXGBE_GPIE_MSIX_MODE;
1019758cc3dcSJack F Vogel 		gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT |
1020758cc3dcSJack F Vogel 		    IXGBE_GPIE_OCD;
1021758cc3dcSJack F Vogel 	}
1022758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
1023758cc3dcSJack F Vogel 
1024758cc3dcSJack F Vogel 	/* Set MTU size */
1025758cc3dcSJack F Vogel 	if (ifp->if_mtu > ETHERMTU) {
1026*6f37f232SEric Joyner 		/* aka IXGBE_MAXFRS on 82599 and newer */
1027758cc3dcSJack F Vogel 		mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
1028758cc3dcSJack F Vogel 		mhadd &= ~IXGBE_MHADD_MFS_MASK;
1029758cc3dcSJack F Vogel 		mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT;
1030758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
1031758cc3dcSJack F Vogel 	}
1032758cc3dcSJack F Vogel 
1033758cc3dcSJack F Vogel 	/* Now enable all the queues */
1034758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++) {
1035758cc3dcSJack F Vogel 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
1036758cc3dcSJack F Vogel 		txdctl |= IXGBE_TXDCTL_ENABLE;
1037758cc3dcSJack F Vogel 		/* Set WTHRESH to 8, burst writeback */
1038758cc3dcSJack F Vogel 		txdctl |= (8 << 16);
1039758cc3dcSJack F Vogel 		/*
1040758cc3dcSJack F Vogel 		 * When the internal queue falls below PTHRESH (32),
1041758cc3dcSJack F Vogel 		 * start prefetching as long as there are at least
1042758cc3dcSJack F Vogel 		 * HTHRESH (1) buffers ready. The values are taken
1043758cc3dcSJack F Vogel 		 * from the Intel linux driver 3.8.21.
1044758cc3dcSJack F Vogel 		 * Prefetching enables tx line rate even with 1 queue.
1045758cc3dcSJack F Vogel 		 */
1046758cc3dcSJack F Vogel 		txdctl |= (32 << 0) | (1 << 8);
1047758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), txdctl);
1048758cc3dcSJack F Vogel 	}
1049758cc3dcSJack F Vogel 
1050758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++) {
1051758cc3dcSJack F Vogel 		rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
1052758cc3dcSJack F Vogel 		if (hw->mac.type == ixgbe_mac_82598EB) {
1053758cc3dcSJack F Vogel 			/*
1054758cc3dcSJack F Vogel 			** PTHRESH = 21
1055758cc3dcSJack F Vogel 			** HTHRESH = 4
1056758cc3dcSJack F Vogel 			** WTHRESH = 8
1057758cc3dcSJack F Vogel 			*/
1058758cc3dcSJack F Vogel 			rxdctl &= ~0x3FFFFF;
1059758cc3dcSJack F Vogel 			rxdctl |= 0x080420;
1060758cc3dcSJack F Vogel 		}
1061758cc3dcSJack F Vogel 		rxdctl |= IXGBE_RXDCTL_ENABLE;
1062758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), rxdctl);
1063758cc3dcSJack F Vogel 		for (k = 0; k < 10; k++) {
1064758cc3dcSJack F Vogel 			if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)) &
1065758cc3dcSJack F Vogel 			    IXGBE_RXDCTL_ENABLE)
1066758cc3dcSJack F Vogel 				break;
1067758cc3dcSJack F Vogel 			else
1068758cc3dcSJack F Vogel 				msec_delay(1);
1069758cc3dcSJack F Vogel 		}
1070758cc3dcSJack F Vogel 		wmb();
1071758cc3dcSJack F Vogel #ifdef DEV_NETMAP
1072758cc3dcSJack F Vogel 		/*
1073758cc3dcSJack F Vogel 		 * In netmap mode, we must preserve the buffers made
1074758cc3dcSJack F Vogel 		 * available to userspace before the if_init()
1075758cc3dcSJack F Vogel 		 * (this is true by default on the TX side, because
1076758cc3dcSJack F Vogel 		 * init makes all buffers available to userspace).
1077758cc3dcSJack F Vogel 		 *
1078758cc3dcSJack F Vogel 		 * netmap_reset() and the device specific routines
1079758cc3dcSJack F Vogel 		 * (e.g. ixgbe_setup_receive_rings()) map these
1080758cc3dcSJack F Vogel 		 * buffers at the end of the NIC ring, so here we
1081758cc3dcSJack F Vogel 		 * must set the RDT (tail) register to make sure
1082758cc3dcSJack F Vogel 		 * they are not overwritten.
1083758cc3dcSJack F Vogel 		 *
1084758cc3dcSJack F Vogel 		 * In this driver the NIC ring starts at RDH = 0,
1085758cc3dcSJack F Vogel 		 * RDT points to the last slot available for reception (?),
1086758cc3dcSJack F Vogel 		 * so RDT = num_rx_desc - 1 means the whole ring is available.
1087758cc3dcSJack F Vogel 		 */
1088758cc3dcSJack F Vogel 		if (ifp->if_capenable & IFCAP_NETMAP) {
1089758cc3dcSJack F Vogel 			struct netmap_adapter *na = NA(adapter->ifp);
1090758cc3dcSJack F Vogel 			struct netmap_kring *kring = &na->rx_rings[i];
1091758cc3dcSJack F Vogel 			int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
1092758cc3dcSJack F Vogel 
1093758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_RDT(i), t);
1094758cc3dcSJack F Vogel 		} else
1095758cc3dcSJack F Vogel #endif /* DEV_NETMAP */
1096758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDT(i), adapter->num_rx_desc - 1);
1097758cc3dcSJack F Vogel 	}
1098758cc3dcSJack F Vogel 
1099758cc3dcSJack F Vogel 	/* Enable Receive engine */
1100758cc3dcSJack F Vogel 	rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
1101758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82598EB)
1102758cc3dcSJack F Vogel 		rxctrl |= IXGBE_RXCTRL_DMBYPS;
1103758cc3dcSJack F Vogel 	rxctrl |= IXGBE_RXCTRL_RXEN;
1104758cc3dcSJack F Vogel 	ixgbe_enable_rx_dma(hw, rxctrl);
1105758cc3dcSJack F Vogel 
1106758cc3dcSJack F Vogel 	callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter);
1107758cc3dcSJack F Vogel 
1108758cc3dcSJack F Vogel 	/* Set up MSI/X routing */
1109758cc3dcSJack F Vogel 	if (ixgbe_enable_msix)  {
1110758cc3dcSJack F Vogel 		ixgbe_configure_ivars(adapter);
1111758cc3dcSJack F Vogel 		/* Set up auto-mask */
1112758cc3dcSJack F Vogel 		if (hw->mac.type == ixgbe_mac_82598EB)
1113758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
1114758cc3dcSJack F Vogel 		else {
1115758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF);
1116758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF);
1117758cc3dcSJack F Vogel 		}
1118758cc3dcSJack F Vogel 	} else {  /* Simple settings for Legacy/MSI */
1119758cc3dcSJack F Vogel                 ixgbe_set_ivar(adapter, 0, 0, 0);
1120758cc3dcSJack F Vogel                 ixgbe_set_ivar(adapter, 0, 0, 1);
1121758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
1122758cc3dcSJack F Vogel 	}
1123758cc3dcSJack F Vogel 
1124758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
1125758cc3dcSJack F Vogel 	/* Init Flow director */
1126758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
1127758cc3dcSJack F Vogel 		u32 hdrm = 32 << fdir_pballoc;
1128758cc3dcSJack F Vogel 
1129758cc3dcSJack F Vogel 		hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL);
1130758cc3dcSJack F Vogel 		ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc);
1131758cc3dcSJack F Vogel 	}
1132758cc3dcSJack F Vogel #endif
1133758cc3dcSJack F Vogel 
1134758cc3dcSJack F Vogel 	/*
1135758cc3dcSJack F Vogel 	** Check on any SFP devices that
1136758cc3dcSJack F Vogel 	** need to be kick-started
1137758cc3dcSJack F Vogel 	*/
1138758cc3dcSJack F Vogel 	if (hw->phy.type == ixgbe_phy_none) {
1139758cc3dcSJack F Vogel 		int err = hw->phy.ops.identify(hw);
1140758cc3dcSJack F Vogel 		if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
1141758cc3dcSJack F Vogel                 	device_printf(dev,
1142758cc3dcSJack F Vogel 			    "Unsupported SFP+ module type was detected.\n");
1143758cc3dcSJack F Vogel 			return;
1144758cc3dcSJack F Vogel         	}
1145758cc3dcSJack F Vogel 	}
1146758cc3dcSJack F Vogel 
1147758cc3dcSJack F Vogel 	/* Set moderation on the Link interrupt */
1148758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR);
1149758cc3dcSJack F Vogel 
1150*6f37f232SEric Joyner 	/* Configure Energy Efficient Ethernet for supported devices */
1151*6f37f232SEric Joyner 	if (adapter->eee_support)
1152*6f37f232SEric Joyner 		ixgbe_setup_eee(hw, adapter->eee_enabled);
1153*6f37f232SEric Joyner 
1154758cc3dcSJack F Vogel 	/* Config/Enable Link */
1155758cc3dcSJack F Vogel 	ixgbe_config_link(adapter);
1156758cc3dcSJack F Vogel 
1157758cc3dcSJack F Vogel 	/* Hardware Packet Buffer & Flow Control setup */
1158*6f37f232SEric Joyner 	ixgbe_config_delay_values(adapter);
1159758cc3dcSJack F Vogel 
1160758cc3dcSJack F Vogel 	/* Initialize the FC settings */
1161758cc3dcSJack F Vogel 	ixgbe_start_hw(hw);
1162758cc3dcSJack F Vogel 
1163758cc3dcSJack F Vogel 	/* Set up VLAN support and filter */
1164758cc3dcSJack F Vogel 	ixgbe_setup_vlan_hw_support(adapter);
1165758cc3dcSJack F Vogel 
1166*6f37f232SEric Joyner 	/* Setup DMA Coalescing */
1167*6f37f232SEric Joyner 	ixgbe_config_dmac(adapter);
1168*6f37f232SEric Joyner 
1169758cc3dcSJack F Vogel 	/* And now turn on interrupts */
1170758cc3dcSJack F Vogel 	ixgbe_enable_intr(adapter);
1171758cc3dcSJack F Vogel 
1172758cc3dcSJack F Vogel 	/* Now inform the stack we're ready */
1173758cc3dcSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1174758cc3dcSJack F Vogel 
1175758cc3dcSJack F Vogel 	return;
1176758cc3dcSJack F Vogel }
1177758cc3dcSJack F Vogel 
1178758cc3dcSJack F Vogel static void
1179758cc3dcSJack F Vogel ixgbe_init(void *arg)
1180758cc3dcSJack F Vogel {
1181758cc3dcSJack F Vogel 	struct adapter *adapter = arg;
1182758cc3dcSJack F Vogel 
1183758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
1184758cc3dcSJack F Vogel 	ixgbe_init_locked(adapter);
1185758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
1186758cc3dcSJack F Vogel 	return;
1187758cc3dcSJack F Vogel }
1188758cc3dcSJack F Vogel 
1189*6f37f232SEric Joyner static void
1190*6f37f232SEric Joyner ixgbe_config_delay_values(struct adapter *adapter)
1191*6f37f232SEric Joyner {
1192*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
1193*6f37f232SEric Joyner 	u32 rxpb, frame, size, tmp;
1194*6f37f232SEric Joyner 
1195*6f37f232SEric Joyner 	frame = adapter->max_frame_size;
1196*6f37f232SEric Joyner 
1197*6f37f232SEric Joyner 	/* Calculate High Water */
1198*6f37f232SEric Joyner 	switch (hw->mac.type) {
1199*6f37f232SEric Joyner 	case ixgbe_mac_X540:
1200*6f37f232SEric Joyner 	case ixgbe_mac_X550:
1201*6f37f232SEric Joyner 	case ixgbe_mac_X550EM_x:
1202*6f37f232SEric Joyner 		tmp = IXGBE_DV_X540(frame, frame);
1203*6f37f232SEric Joyner 		break;
1204*6f37f232SEric Joyner 	default:
1205*6f37f232SEric Joyner 		tmp = IXGBE_DV(frame, frame);
1206*6f37f232SEric Joyner 		break;
1207*6f37f232SEric Joyner 	}
1208*6f37f232SEric Joyner 	size = IXGBE_BT2KB(tmp);
1209*6f37f232SEric Joyner 	rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10;
1210*6f37f232SEric Joyner 	hw->fc.high_water[0] = rxpb - size;
1211*6f37f232SEric Joyner 
1212*6f37f232SEric Joyner 	/* Now calculate Low Water */
1213*6f37f232SEric Joyner 	switch (hw->mac.type) {
1214*6f37f232SEric Joyner 	case ixgbe_mac_X540:
1215*6f37f232SEric Joyner 	case ixgbe_mac_X550:
1216*6f37f232SEric Joyner 	case ixgbe_mac_X550EM_x:
1217*6f37f232SEric Joyner 		tmp = IXGBE_LOW_DV_X540(frame);
1218*6f37f232SEric Joyner 		break;
1219*6f37f232SEric Joyner 	default:
1220*6f37f232SEric Joyner 		tmp = IXGBE_LOW_DV(frame);
1221*6f37f232SEric Joyner 		break;
1222*6f37f232SEric Joyner 	}
1223*6f37f232SEric Joyner 	hw->fc.low_water[0] = IXGBE_BT2KB(tmp);
1224*6f37f232SEric Joyner 
1225*6f37f232SEric Joyner 	hw->fc.requested_mode = adapter->fc;
1226*6f37f232SEric Joyner 	hw->fc.pause_time = IXGBE_FC_PAUSE;
1227*6f37f232SEric Joyner 	hw->fc.send_xon = TRUE;
1228*6f37f232SEric Joyner }
1229758cc3dcSJack F Vogel 
1230758cc3dcSJack F Vogel /*
1231758cc3dcSJack F Vogel **
1232758cc3dcSJack F Vogel ** MSIX Interrupt Handlers and Tasklets
1233758cc3dcSJack F Vogel **
1234758cc3dcSJack F Vogel */
1235758cc3dcSJack F Vogel 
1236758cc3dcSJack F Vogel static inline void
1237758cc3dcSJack F Vogel ixgbe_enable_queue(struct adapter *adapter, u32 vector)
1238758cc3dcSJack F Vogel {
1239758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
1240758cc3dcSJack F Vogel 	u64	queue = (u64)(1 << vector);
1241758cc3dcSJack F Vogel 	u32	mask;
1242758cc3dcSJack F Vogel 
1243758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82598EB) {
1244758cc3dcSJack F Vogel                 mask = (IXGBE_EIMS_RTX_QUEUE & queue);
1245758cc3dcSJack F Vogel                 IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask);
1246758cc3dcSJack F Vogel 	} else {
1247758cc3dcSJack F Vogel                 mask = (queue & 0xFFFFFFFF);
1248758cc3dcSJack F Vogel                 if (mask)
1249758cc3dcSJack F Vogel                         IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask);
1250758cc3dcSJack F Vogel                 mask = (queue >> 32);
1251758cc3dcSJack F Vogel                 if (mask)
1252758cc3dcSJack F Vogel                         IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask);
1253758cc3dcSJack F Vogel 	}
1254758cc3dcSJack F Vogel }
1255758cc3dcSJack F Vogel 
1256758cc3dcSJack F Vogel static inline void
1257758cc3dcSJack F Vogel ixgbe_disable_queue(struct adapter *adapter, u32 vector)
1258758cc3dcSJack F Vogel {
1259758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
1260758cc3dcSJack F Vogel 	u64	queue = (u64)(1 << vector);
1261758cc3dcSJack F Vogel 	u32	mask;
1262758cc3dcSJack F Vogel 
1263758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82598EB) {
1264758cc3dcSJack F Vogel                 mask = (IXGBE_EIMS_RTX_QUEUE & queue);
1265758cc3dcSJack F Vogel                 IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask);
1266758cc3dcSJack F Vogel 	} else {
1267758cc3dcSJack F Vogel                 mask = (queue & 0xFFFFFFFF);
1268758cc3dcSJack F Vogel                 if (mask)
1269758cc3dcSJack F Vogel                         IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask);
1270758cc3dcSJack F Vogel                 mask = (queue >> 32);
1271758cc3dcSJack F Vogel                 if (mask)
1272758cc3dcSJack F Vogel                         IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask);
1273758cc3dcSJack F Vogel 	}
1274758cc3dcSJack F Vogel }
1275758cc3dcSJack F Vogel 
1276758cc3dcSJack F Vogel static void
1277758cc3dcSJack F Vogel ixgbe_handle_que(void *context, int pending)
1278758cc3dcSJack F Vogel {
1279758cc3dcSJack F Vogel 	struct ix_queue *que = context;
1280758cc3dcSJack F Vogel 	struct adapter  *adapter = que->adapter;
1281758cc3dcSJack F Vogel 	struct tx_ring  *txr = que->txr;
1282758cc3dcSJack F Vogel 	struct ifnet    *ifp = adapter->ifp;
1283*6f37f232SEric Joyner 	bool		more;
1284758cc3dcSJack F Vogel 
1285758cc3dcSJack F Vogel 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1286*6f37f232SEric Joyner 		more = ixgbe_rxeof(que);
1287758cc3dcSJack F Vogel 		IXGBE_TX_LOCK(txr);
1288758cc3dcSJack F Vogel 		ixgbe_txeof(txr);
1289758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
1290758cc3dcSJack F Vogel 		if (!drbr_empty(ifp, txr->br))
1291758cc3dcSJack F Vogel 			ixgbe_mq_start_locked(ifp, txr);
1292758cc3dcSJack F Vogel #else
1293758cc3dcSJack F Vogel 		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1294758cc3dcSJack F Vogel 			ixgbe_start_locked(txr, ifp);
1295758cc3dcSJack F Vogel #endif
1296758cc3dcSJack F Vogel 		IXGBE_TX_UNLOCK(txr);
1297758cc3dcSJack F Vogel 	}
1298758cc3dcSJack F Vogel 
1299758cc3dcSJack F Vogel 	/* Reenable this interrupt */
1300758cc3dcSJack F Vogel 	if (que->res != NULL)
1301758cc3dcSJack F Vogel 		ixgbe_enable_queue(adapter, que->msix);
1302758cc3dcSJack F Vogel 	else
1303758cc3dcSJack F Vogel 		ixgbe_enable_intr(adapter);
1304758cc3dcSJack F Vogel 	return;
1305758cc3dcSJack F Vogel }
1306758cc3dcSJack F Vogel 
1307758cc3dcSJack F Vogel 
1308758cc3dcSJack F Vogel /*********************************************************************
1309758cc3dcSJack F Vogel  *
1310758cc3dcSJack F Vogel  *  Legacy Interrupt Service routine
1311758cc3dcSJack F Vogel  *
1312758cc3dcSJack F Vogel  **********************************************************************/
1313758cc3dcSJack F Vogel 
1314758cc3dcSJack F Vogel static void
1315758cc3dcSJack F Vogel ixgbe_legacy_irq(void *arg)
1316758cc3dcSJack F Vogel {
1317758cc3dcSJack F Vogel 	struct ix_queue *que = arg;
1318758cc3dcSJack F Vogel 	struct adapter	*adapter = que->adapter;
1319758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
1320758cc3dcSJack F Vogel 	struct ifnet    *ifp = adapter->ifp;
1321758cc3dcSJack F Vogel 	struct 		tx_ring *txr = adapter->tx_rings;
1322758cc3dcSJack F Vogel 	bool		more;
1323758cc3dcSJack F Vogel 	u32       	reg_eicr;
1324758cc3dcSJack F Vogel 
1325758cc3dcSJack F Vogel 
1326758cc3dcSJack F Vogel 	reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
1327758cc3dcSJack F Vogel 
1328758cc3dcSJack F Vogel 	++que->irqs;
1329758cc3dcSJack F Vogel 	if (reg_eicr == 0) {
1330758cc3dcSJack F Vogel 		ixgbe_enable_intr(adapter);
1331758cc3dcSJack F Vogel 		return;
1332758cc3dcSJack F Vogel 	}
1333758cc3dcSJack F Vogel 
1334758cc3dcSJack F Vogel 	more = ixgbe_rxeof(que);
1335758cc3dcSJack F Vogel 
1336758cc3dcSJack F Vogel 	IXGBE_TX_LOCK(txr);
1337758cc3dcSJack F Vogel 	ixgbe_txeof(txr);
1338758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX
1339758cc3dcSJack F Vogel 	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1340758cc3dcSJack F Vogel 		ixgbe_start_locked(txr, ifp);
1341758cc3dcSJack F Vogel #else
1342758cc3dcSJack F Vogel 	if (!drbr_empty(ifp, txr->br))
1343758cc3dcSJack F Vogel 		ixgbe_mq_start_locked(ifp, txr);
1344758cc3dcSJack F Vogel #endif
1345758cc3dcSJack F Vogel 	IXGBE_TX_UNLOCK(txr);
1346758cc3dcSJack F Vogel 
1347758cc3dcSJack F Vogel 	/* Check for fan failure */
1348758cc3dcSJack F Vogel 	if ((hw->phy.media_type == ixgbe_media_type_copper) &&
1349758cc3dcSJack F Vogel 	    (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) {
1350758cc3dcSJack F Vogel                 device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! "
1351758cc3dcSJack F Vogel 		    "REPLACE IMMEDIATELY!!\n");
1352758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
1353758cc3dcSJack F Vogel 	}
1354758cc3dcSJack F Vogel 
1355758cc3dcSJack F Vogel 	/* Link status change */
1356758cc3dcSJack F Vogel 	if (reg_eicr & IXGBE_EICR_LSC)
1357758cc3dcSJack F Vogel 		taskqueue_enqueue(adapter->tq, &adapter->link_task);
1358758cc3dcSJack F Vogel 
1359*6f37f232SEric Joyner 	/* External PHY interrupt */
1360*6f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
1361*6f37f232SEric Joyner 	    (reg_eicr & IXGBE_EICR_GPI_SDP0_X540))
1362*6f37f232SEric Joyner 		taskqueue_enqueue(adapter->tq, &adapter->phy_task);
1363*6f37f232SEric Joyner 
1364758cc3dcSJack F Vogel 	if (more)
1365758cc3dcSJack F Vogel 		taskqueue_enqueue(que->tq, &que->que_task);
1366758cc3dcSJack F Vogel 	else
1367758cc3dcSJack F Vogel 		ixgbe_enable_intr(adapter);
1368758cc3dcSJack F Vogel 	return;
1369758cc3dcSJack F Vogel }
1370758cc3dcSJack F Vogel 
1371758cc3dcSJack F Vogel 
1372758cc3dcSJack F Vogel /*********************************************************************
1373758cc3dcSJack F Vogel  *
1374758cc3dcSJack F Vogel  *  MSIX Queue Interrupt Service routine
1375758cc3dcSJack F Vogel  *
1376758cc3dcSJack F Vogel  **********************************************************************/
1377758cc3dcSJack F Vogel void
1378758cc3dcSJack F Vogel ixgbe_msix_que(void *arg)
1379758cc3dcSJack F Vogel {
1380758cc3dcSJack F Vogel 	struct ix_queue	*que = arg;
1381758cc3dcSJack F Vogel 	struct adapter  *adapter = que->adapter;
1382758cc3dcSJack F Vogel 	struct ifnet    *ifp = adapter->ifp;
1383758cc3dcSJack F Vogel 	struct tx_ring	*txr = que->txr;
1384758cc3dcSJack F Vogel 	struct rx_ring	*rxr = que->rxr;
1385758cc3dcSJack F Vogel 	bool		more;
1386758cc3dcSJack F Vogel 	u32		newitr = 0;
1387758cc3dcSJack F Vogel 
1388758cc3dcSJack F Vogel 	/* Protect against spurious interrupts */
1389758cc3dcSJack F Vogel 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1390758cc3dcSJack F Vogel 		return;
1391758cc3dcSJack F Vogel 
1392758cc3dcSJack F Vogel 	ixgbe_disable_queue(adapter, que->msix);
1393758cc3dcSJack F Vogel 	++que->irqs;
1394758cc3dcSJack F Vogel 
1395758cc3dcSJack F Vogel 	more = ixgbe_rxeof(que);
1396758cc3dcSJack F Vogel 
1397758cc3dcSJack F Vogel 	IXGBE_TX_LOCK(txr);
1398758cc3dcSJack F Vogel 	ixgbe_txeof(txr);
1399758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX
1400758cc3dcSJack F Vogel 	if (!IFQ_DRV_IS_EMPTY(ifp->if_snd))
1401758cc3dcSJack F Vogel 		ixgbe_start_locked(txr, ifp);
1402758cc3dcSJack F Vogel #else
1403758cc3dcSJack F Vogel 	if (!drbr_empty(ifp, txr->br))
1404758cc3dcSJack F Vogel 		ixgbe_mq_start_locked(ifp, txr);
1405758cc3dcSJack F Vogel #endif
1406758cc3dcSJack F Vogel 	IXGBE_TX_UNLOCK(txr);
1407758cc3dcSJack F Vogel 
1408758cc3dcSJack F Vogel 	/* Do AIM now? */
1409758cc3dcSJack F Vogel 
1410758cc3dcSJack F Vogel 	if (ixgbe_enable_aim == FALSE)
1411758cc3dcSJack F Vogel 		goto no_calc;
1412758cc3dcSJack F Vogel 	/*
1413758cc3dcSJack F Vogel 	** Do Adaptive Interrupt Moderation:
1414758cc3dcSJack F Vogel         **  - Write out last calculated setting
1415758cc3dcSJack F Vogel 	**  - Calculate based on average size over
1416758cc3dcSJack F Vogel 	**    the last interval.
1417758cc3dcSJack F Vogel 	*/
1418758cc3dcSJack F Vogel         if (que->eitr_setting)
1419758cc3dcSJack F Vogel                 IXGBE_WRITE_REG(&adapter->hw,
1420758cc3dcSJack F Vogel                     IXGBE_EITR(que->msix), que->eitr_setting);
1421758cc3dcSJack F Vogel 
1422758cc3dcSJack F Vogel         que->eitr_setting = 0;
1423758cc3dcSJack F Vogel 
1424758cc3dcSJack F Vogel         /* Idle, do nothing */
1425758cc3dcSJack F Vogel         if ((txr->bytes == 0) && (rxr->bytes == 0))
1426758cc3dcSJack F Vogel                 goto no_calc;
1427758cc3dcSJack F Vogel 
1428758cc3dcSJack F Vogel 	if ((txr->bytes) && (txr->packets))
1429758cc3dcSJack F Vogel                	newitr = txr->bytes/txr->packets;
1430758cc3dcSJack F Vogel 	if ((rxr->bytes) && (rxr->packets))
1431758cc3dcSJack F Vogel 		newitr = max(newitr,
1432758cc3dcSJack F Vogel 		    (rxr->bytes / rxr->packets));
1433758cc3dcSJack F Vogel 	newitr += 24; /* account for hardware frame, crc */
1434758cc3dcSJack F Vogel 
1435758cc3dcSJack F Vogel 	/* set an upper boundary */
1436758cc3dcSJack F Vogel 	newitr = min(newitr, 3000);
1437758cc3dcSJack F Vogel 
1438758cc3dcSJack F Vogel 	/* Be nice to the mid range */
1439758cc3dcSJack F Vogel 	if ((newitr > 300) && (newitr < 1200))
1440758cc3dcSJack F Vogel 		newitr = (newitr / 3);
1441758cc3dcSJack F Vogel 	else
1442758cc3dcSJack F Vogel 		newitr = (newitr / 2);
1443758cc3dcSJack F Vogel 
1444758cc3dcSJack F Vogel         if (adapter->hw.mac.type == ixgbe_mac_82598EB)
1445758cc3dcSJack F Vogel                 newitr |= newitr << 16;
1446758cc3dcSJack F Vogel         else
1447758cc3dcSJack F Vogel                 newitr |= IXGBE_EITR_CNT_WDIS;
1448758cc3dcSJack F Vogel 
1449758cc3dcSJack F Vogel         /* save for next interrupt */
1450758cc3dcSJack F Vogel         que->eitr_setting = newitr;
1451758cc3dcSJack F Vogel 
1452758cc3dcSJack F Vogel         /* Reset state */
1453758cc3dcSJack F Vogel         txr->bytes = 0;
1454758cc3dcSJack F Vogel         txr->packets = 0;
1455758cc3dcSJack F Vogel         rxr->bytes = 0;
1456758cc3dcSJack F Vogel         rxr->packets = 0;
1457758cc3dcSJack F Vogel 
1458758cc3dcSJack F Vogel no_calc:
1459758cc3dcSJack F Vogel 	if (more)
1460758cc3dcSJack F Vogel 		taskqueue_enqueue(que->tq, &que->que_task);
1461758cc3dcSJack F Vogel 	else
1462758cc3dcSJack F Vogel 		ixgbe_enable_queue(adapter, que->msix);
1463758cc3dcSJack F Vogel 	return;
1464758cc3dcSJack F Vogel }
1465758cc3dcSJack F Vogel 
1466758cc3dcSJack F Vogel 
1467758cc3dcSJack F Vogel static void
1468758cc3dcSJack F Vogel ixgbe_msix_link(void *arg)
1469758cc3dcSJack F Vogel {
1470758cc3dcSJack F Vogel 	struct adapter	*adapter = arg;
1471758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
1472*6f37f232SEric Joyner 	u32		reg_eicr, mod_mask;
1473758cc3dcSJack F Vogel 
1474*6f37f232SEric Joyner 	++adapter->link_irq;
1475758cc3dcSJack F Vogel 
1476758cc3dcSJack F Vogel 	/* First get the cause */
1477758cc3dcSJack F Vogel 	reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
1478758cc3dcSJack F Vogel 	/* Be sure the queue bits are not cleared */
1479758cc3dcSJack F Vogel 	reg_eicr &= ~IXGBE_EICR_RTX_QUEUE;
1480758cc3dcSJack F Vogel 	/* Clear interrupt with write */
1481758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr);
1482758cc3dcSJack F Vogel 
1483758cc3dcSJack F Vogel 	/* Link status change */
1484758cc3dcSJack F Vogel 	if (reg_eicr & IXGBE_EICR_LSC)
1485758cc3dcSJack F Vogel 		taskqueue_enqueue(adapter->tq, &adapter->link_task);
1486758cc3dcSJack F Vogel 
1487758cc3dcSJack F Vogel 	if (adapter->hw.mac.type != ixgbe_mac_82598EB) {
1488758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
1489758cc3dcSJack F Vogel 		if (reg_eicr & IXGBE_EICR_FLOW_DIR) {
1490758cc3dcSJack F Vogel 			/* This is probably overkill :) */
1491758cc3dcSJack F Vogel 			if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1))
1492758cc3dcSJack F Vogel 				return;
1493758cc3dcSJack F Vogel                 	/* Disable the interrupt */
1494758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR);
1495758cc3dcSJack F Vogel 			taskqueue_enqueue(adapter->tq, &adapter->fdir_task);
1496758cc3dcSJack F Vogel 		} else
1497758cc3dcSJack F Vogel #endif
1498758cc3dcSJack F Vogel 		if (reg_eicr & IXGBE_EICR_ECC) {
1499758cc3dcSJack F Vogel                 	device_printf(adapter->dev, "\nCRITICAL: ECC ERROR!! "
1500758cc3dcSJack F Vogel 			    "Please Reboot!!\n");
1501758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC);
1502*6f37f232SEric Joyner 		}
1503*6f37f232SEric Joyner 
1504*6f37f232SEric Joyner 		/* Check for over temp condition */
1505*6f37f232SEric Joyner 		if (reg_eicr & IXGBE_EICR_TS) {
1506*6f37f232SEric Joyner 			device_printf(adapter->dev, "\nCRITICAL: OVER TEMP!! "
1507*6f37f232SEric Joyner 			    "PHY IS SHUT DOWN!!\n");
1508*6f37f232SEric Joyner 			device_printf(adapter->dev, "System shutdown required!\n");
1509*6f37f232SEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS);
1510*6f37f232SEric Joyner 		}
1511*6f37f232SEric Joyner 	}
1512*6f37f232SEric Joyner 
1513*6f37f232SEric Joyner 	/* Pluggable optics-related interrupt */
1514*6f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP)
1515*6f37f232SEric Joyner 		mod_mask = IXGBE_EICR_GPI_SDP0_X540;
1516*6f37f232SEric Joyner 	else
1517*6f37f232SEric Joyner 		mod_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw);
1518758cc3dcSJack F Vogel 
1519758cc3dcSJack F Vogel 	if (ixgbe_is_sfp(hw)) {
1520*6f37f232SEric Joyner 		if (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) {
1521758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
1522758cc3dcSJack F Vogel 			taskqueue_enqueue(adapter->tq, &adapter->msf_task);
1523*6f37f232SEric Joyner 		} else if (reg_eicr & mod_mask) {
1524*6f37f232SEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR, mod_mask);
1525758cc3dcSJack F Vogel 			taskqueue_enqueue(adapter->tq, &adapter->mod_task);
1526758cc3dcSJack F Vogel 		}
1527758cc3dcSJack F Vogel 	}
1528758cc3dcSJack F Vogel 
1529758cc3dcSJack F Vogel 	/* Check for fan failure */
1530758cc3dcSJack F Vogel 	if ((hw->device_id == IXGBE_DEV_ID_82598AT) &&
1531*6f37f232SEric Joyner 	    (reg_eicr & IXGBE_EICR_GPI_SDP1)) {
1532*6f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
1533758cc3dcSJack F Vogel                 device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! "
1534758cc3dcSJack F Vogel 		    "REPLACE IMMEDIATELY!!\n");
1535758cc3dcSJack F Vogel 	}
1536758cc3dcSJack F Vogel 
1537*6f37f232SEric Joyner 	/* External PHY interrupt */
1538*6f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
1539*6f37f232SEric Joyner 	    (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) {
1540*6f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540);
1541*6f37f232SEric Joyner 		taskqueue_enqueue(adapter->tq, &adapter->phy_task);
1542758cc3dcSJack F Vogel 	}
1543758cc3dcSJack F Vogel 
1544758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
1545758cc3dcSJack F Vogel 	return;
1546758cc3dcSJack F Vogel }
1547758cc3dcSJack F Vogel 
1548758cc3dcSJack F Vogel /*********************************************************************
1549758cc3dcSJack F Vogel  *
1550758cc3dcSJack F Vogel  *  Media Ioctl callback
1551758cc3dcSJack F Vogel  *
1552758cc3dcSJack F Vogel  *  This routine is called whenever the user queries the status of
1553758cc3dcSJack F Vogel  *  the interface using ifconfig.
1554758cc3dcSJack F Vogel  *
1555758cc3dcSJack F Vogel  **********************************************************************/
1556758cc3dcSJack F Vogel static void
1557758cc3dcSJack F Vogel ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
1558758cc3dcSJack F Vogel {
1559758cc3dcSJack F Vogel 	struct adapter *adapter = ifp->if_softc;
1560758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
1561758cc3dcSJack F Vogel 	int layer;
1562758cc3dcSJack F Vogel 
1563758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_media_status: begin");
1564758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
1565758cc3dcSJack F Vogel 	ixgbe_update_link_status(adapter);
1566758cc3dcSJack F Vogel 
1567758cc3dcSJack F Vogel 	ifmr->ifm_status = IFM_AVALID;
1568758cc3dcSJack F Vogel 	ifmr->ifm_active = IFM_ETHER;
1569758cc3dcSJack F Vogel 
1570758cc3dcSJack F Vogel 	if (!adapter->link_active) {
1571758cc3dcSJack F Vogel 		IXGBE_CORE_UNLOCK(adapter);
1572758cc3dcSJack F Vogel 		return;
1573758cc3dcSJack F Vogel 	}
1574758cc3dcSJack F Vogel 
1575758cc3dcSJack F Vogel 	ifmr->ifm_status |= IFM_ACTIVE;
1576758cc3dcSJack F Vogel 	layer = ixgbe_get_supported_physical_layer(hw);
1577758cc3dcSJack F Vogel 
1578758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T ||
1579758cc3dcSJack F Vogel 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_T ||
1580758cc3dcSJack F Vogel 	    layer & IXGBE_PHYSICAL_LAYER_100BASE_TX)
1581758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1582758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1583758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
1584758cc3dcSJack F Vogel 			break;
1585758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
1586758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_1000_T | IFM_FDX;
1587758cc3dcSJack F Vogel 			break;
1588758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_100_FULL:
1589758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
1590758cc3dcSJack F Vogel 			break;
1591758cc3dcSJack F Vogel 		}
1592758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU ||
1593758cc3dcSJack F Vogel 	    layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA)
1594758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1595758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1596758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX | IFM_FDX;
1597758cc3dcSJack F Vogel 			break;
1598758cc3dcSJack F Vogel 		}
1599758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR)
1600758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1601758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1602758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LR | IFM_FDX;
1603758cc3dcSJack F Vogel 			break;
1604758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
1605758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX | IFM_FDX;
1606758cc3dcSJack F Vogel 			break;
1607758cc3dcSJack F Vogel 		}
1608758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM)
1609758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1610758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1611758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LRM | IFM_FDX;
1612758cc3dcSJack F Vogel 			break;
1613758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
1614758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX | IFM_FDX;
1615758cc3dcSJack F Vogel 			break;
1616758cc3dcSJack F Vogel 		}
1617758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR ||
1618758cc3dcSJack F Vogel 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX)
1619758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1620758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1621758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
1622758cc3dcSJack F Vogel 			break;
1623758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
1624758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_1000_SX | IFM_FDX;
1625758cc3dcSJack F Vogel 			break;
1626758cc3dcSJack F Vogel 		}
1627758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4)
1628758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1629758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1630758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX;
1631758cc3dcSJack F Vogel 			break;
1632758cc3dcSJack F Vogel 		}
1633758cc3dcSJack F Vogel 	/*
1634758cc3dcSJack F Vogel 	** XXX: These need to use the proper media types once
1635758cc3dcSJack F Vogel 	** they're added.
1636758cc3dcSJack F Vogel 	*/
1637758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR)
1638758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1639758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1640*6f37f232SEric Joyner 			ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
1641*6f37f232SEric Joyner 			break;
1642*6f37f232SEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
1643*6f37f232SEric Joyner 			ifmr->ifm_active |= IFM_2500_SX | IFM_FDX;
1644758cc3dcSJack F Vogel 			break;
1645758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
1646*6f37f232SEric Joyner 			ifmr->ifm_active |= IFM_1000_CX | IFM_FDX;
1647758cc3dcSJack F Vogel 			break;
1648758cc3dcSJack F Vogel 		}
1649*6f37f232SEric Joyner 	else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4
1650758cc3dcSJack F Vogel 	    || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX)
1651758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1652758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1653*6f37f232SEric Joyner 			ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX;
1654*6f37f232SEric Joyner 			break;
1655*6f37f232SEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
1656*6f37f232SEric Joyner 			ifmr->ifm_active |= IFM_2500_SX | IFM_FDX;
1657758cc3dcSJack F Vogel 			break;
1658758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
1659*6f37f232SEric Joyner 			ifmr->ifm_active |= IFM_1000_CX | IFM_FDX;
1660758cc3dcSJack F Vogel 			break;
1661758cc3dcSJack F Vogel 		}
1662758cc3dcSJack F Vogel 
1663758cc3dcSJack F Vogel 	/* If nothing is recognized... */
1664758cc3dcSJack F Vogel 	if (IFM_SUBTYPE(ifmr->ifm_active) == 0)
1665758cc3dcSJack F Vogel 		ifmr->ifm_active |= IFM_UNKNOWN;
1666758cc3dcSJack F Vogel 
1667758cc3dcSJack F Vogel #if __FreeBSD_version >= 900025
1668*6f37f232SEric Joyner 	/* Display current flow control setting used on link */
1669*6f37f232SEric Joyner 	if (hw->fc.current_mode == ixgbe_fc_rx_pause ||
1670*6f37f232SEric Joyner 	    hw->fc.current_mode == ixgbe_fc_full)
1671758cc3dcSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
1672*6f37f232SEric Joyner 	if (hw->fc.current_mode == ixgbe_fc_tx_pause ||
1673*6f37f232SEric Joyner 	    hw->fc.current_mode == ixgbe_fc_full)
1674758cc3dcSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
1675758cc3dcSJack F Vogel #endif
1676758cc3dcSJack F Vogel 
1677758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
1678758cc3dcSJack F Vogel 
1679758cc3dcSJack F Vogel 	return;
1680758cc3dcSJack F Vogel }
1681758cc3dcSJack F Vogel 
1682758cc3dcSJack F Vogel /*********************************************************************
1683758cc3dcSJack F Vogel  *
1684758cc3dcSJack F Vogel  *  Media Ioctl callback
1685758cc3dcSJack F Vogel  *
1686758cc3dcSJack F Vogel  *  This routine is called when the user changes speed/duplex using
1687758cc3dcSJack F Vogel  *  media/mediopt option with ifconfig.
1688758cc3dcSJack F Vogel  *
1689758cc3dcSJack F Vogel  **********************************************************************/
1690758cc3dcSJack F Vogel static int
1691758cc3dcSJack F Vogel ixgbe_media_change(struct ifnet * ifp)
1692758cc3dcSJack F Vogel {
1693758cc3dcSJack F Vogel 	struct adapter *adapter = ifp->if_softc;
1694758cc3dcSJack F Vogel 	struct ifmedia *ifm = &adapter->media;
1695758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
1696758cc3dcSJack F Vogel 	ixgbe_link_speed speed = 0;
1697758cc3dcSJack F Vogel 
1698758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_media_change: begin");
1699758cc3dcSJack F Vogel 
1700758cc3dcSJack F Vogel 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1701758cc3dcSJack F Vogel 		return (EINVAL);
1702758cc3dcSJack F Vogel 
1703*6f37f232SEric Joyner 	if (hw->phy.media_type == ixgbe_media_type_backplane)
1704*6f37f232SEric Joyner 		return (EPERM);
1705*6f37f232SEric Joyner 
1706758cc3dcSJack F Vogel 	/*
1707758cc3dcSJack F Vogel 	** We don't actually need to check against the supported
1708758cc3dcSJack F Vogel 	** media types of the adapter; ifmedia will take care of
1709758cc3dcSJack F Vogel 	** that for us.
1710758cc3dcSJack F Vogel 	*/
1711758cc3dcSJack F Vogel 	switch (IFM_SUBTYPE(ifm->ifm_media)) {
1712758cc3dcSJack F Vogel 		case IFM_AUTO:
1713758cc3dcSJack F Vogel 		case IFM_10G_T:
1714758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_100_FULL;
1715758cc3dcSJack F Vogel 		case IFM_10G_LRM:
1716758cc3dcSJack F Vogel 		case IFM_10G_SR: /* KR, too */
1717758cc3dcSJack F Vogel 		case IFM_10G_LR:
1718*6f37f232SEric Joyner 		case IFM_10G_CX4: /* KX4 */
1719758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_1GB_FULL;
1720758cc3dcSJack F Vogel 		case IFM_10G_TWINAX:
1721758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_10GB_FULL;
1722758cc3dcSJack F Vogel 			break;
1723758cc3dcSJack F Vogel 		case IFM_1000_T:
1724758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_100_FULL;
1725758cc3dcSJack F Vogel 		case IFM_1000_LX:
1726758cc3dcSJack F Vogel 		case IFM_1000_SX:
1727*6f37f232SEric Joyner 		case IFM_1000_CX: /* KX */
1728758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_1GB_FULL;
1729758cc3dcSJack F Vogel 			break;
1730758cc3dcSJack F Vogel 		case IFM_100_TX:
1731758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_100_FULL;
1732758cc3dcSJack F Vogel 			break;
1733758cc3dcSJack F Vogel 		default:
1734758cc3dcSJack F Vogel 			goto invalid;
1735758cc3dcSJack F Vogel 	}
1736758cc3dcSJack F Vogel 
1737758cc3dcSJack F Vogel 	hw->mac.autotry_restart = TRUE;
1738758cc3dcSJack F Vogel 	hw->mac.ops.setup_link(hw, speed, TRUE);
1739758cc3dcSJack F Vogel 	adapter->advertise =
1740758cc3dcSJack F Vogel 		((speed & IXGBE_LINK_SPEED_10GB_FULL) << 2) |
1741758cc3dcSJack F Vogel 		((speed & IXGBE_LINK_SPEED_1GB_FULL) << 1) |
1742758cc3dcSJack F Vogel 		((speed & IXGBE_LINK_SPEED_100_FULL) << 0);
1743758cc3dcSJack F Vogel 
1744758cc3dcSJack F Vogel 	return (0);
1745758cc3dcSJack F Vogel 
1746758cc3dcSJack F Vogel invalid:
1747*6f37f232SEric Joyner 	device_printf(adapter->dev, "Invalid media type!\n");
1748758cc3dcSJack F Vogel 	return (EINVAL);
1749758cc3dcSJack F Vogel }
1750758cc3dcSJack F Vogel 
1751758cc3dcSJack F Vogel static void
1752758cc3dcSJack F Vogel ixgbe_set_promisc(struct adapter *adapter)
1753758cc3dcSJack F Vogel {
1754758cc3dcSJack F Vogel 	u_int32_t       reg_rctl;
1755758cc3dcSJack F Vogel 	struct ifnet   *ifp = adapter->ifp;
1756758cc3dcSJack F Vogel 	int		mcnt = 0;
1757758cc3dcSJack F Vogel 
1758758cc3dcSJack F Vogel 	reg_rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
1759758cc3dcSJack F Vogel 	reg_rctl &= (~IXGBE_FCTRL_UPE);
1760758cc3dcSJack F Vogel 	if (ifp->if_flags & IFF_ALLMULTI)
1761758cc3dcSJack F Vogel 		mcnt = MAX_NUM_MULTICAST_ADDRESSES;
1762758cc3dcSJack F Vogel 	else {
1763758cc3dcSJack F Vogel 		struct	ifmultiaddr *ifma;
1764758cc3dcSJack F Vogel #if __FreeBSD_version < 800000
1765758cc3dcSJack F Vogel 		IF_ADDR_LOCK(ifp);
1766758cc3dcSJack F Vogel #else
1767758cc3dcSJack F Vogel 		if_maddr_rlock(ifp);
1768758cc3dcSJack F Vogel #endif
1769758cc3dcSJack F Vogel 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1770758cc3dcSJack F Vogel 			if (ifma->ifma_addr->sa_family != AF_LINK)
1771758cc3dcSJack F Vogel 				continue;
1772758cc3dcSJack F Vogel 			if (mcnt == MAX_NUM_MULTICAST_ADDRESSES)
1773758cc3dcSJack F Vogel 				break;
1774758cc3dcSJack F Vogel 			mcnt++;
1775758cc3dcSJack F Vogel 		}
1776758cc3dcSJack F Vogel #if __FreeBSD_version < 800000
1777758cc3dcSJack F Vogel 		IF_ADDR_UNLOCK(ifp);
1778758cc3dcSJack F Vogel #else
1779758cc3dcSJack F Vogel 		if_maddr_runlock(ifp);
1780758cc3dcSJack F Vogel #endif
1781758cc3dcSJack F Vogel 	}
1782758cc3dcSJack F Vogel 	if (mcnt < MAX_NUM_MULTICAST_ADDRESSES)
1783758cc3dcSJack F Vogel 		reg_rctl &= (~IXGBE_FCTRL_MPE);
1784758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl);
1785758cc3dcSJack F Vogel 
1786758cc3dcSJack F Vogel 	if (ifp->if_flags & IFF_PROMISC) {
1787758cc3dcSJack F Vogel 		reg_rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
1788758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl);
1789758cc3dcSJack F Vogel 	} else if (ifp->if_flags & IFF_ALLMULTI) {
1790758cc3dcSJack F Vogel 		reg_rctl |= IXGBE_FCTRL_MPE;
1791758cc3dcSJack F Vogel 		reg_rctl &= ~IXGBE_FCTRL_UPE;
1792758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl);
1793758cc3dcSJack F Vogel 	}
1794758cc3dcSJack F Vogel 	return;
1795758cc3dcSJack F Vogel }
1796758cc3dcSJack F Vogel 
1797758cc3dcSJack F Vogel 
1798758cc3dcSJack F Vogel /*********************************************************************
1799758cc3dcSJack F Vogel  *  Multicast Update
1800758cc3dcSJack F Vogel  *
1801758cc3dcSJack F Vogel  *  This routine is called whenever multicast address list is updated.
1802758cc3dcSJack F Vogel  *
1803758cc3dcSJack F Vogel  **********************************************************************/
1804758cc3dcSJack F Vogel #define IXGBE_RAR_ENTRIES 16
1805758cc3dcSJack F Vogel 
1806758cc3dcSJack F Vogel static void
1807758cc3dcSJack F Vogel ixgbe_set_multi(struct adapter *adapter)
1808758cc3dcSJack F Vogel {
1809758cc3dcSJack F Vogel 	u32	fctrl;
1810758cc3dcSJack F Vogel 	u8	*mta;
1811758cc3dcSJack F Vogel 	u8	*update_ptr;
1812758cc3dcSJack F Vogel 	struct	ifmultiaddr *ifma;
1813758cc3dcSJack F Vogel 	int	mcnt = 0;
1814758cc3dcSJack F Vogel 	struct ifnet   *ifp = adapter->ifp;
1815758cc3dcSJack F Vogel 
1816758cc3dcSJack F Vogel 	IOCTL_DEBUGOUT("ixgbe_set_multi: begin");
1817758cc3dcSJack F Vogel 
1818758cc3dcSJack F Vogel 	mta = adapter->mta;
1819758cc3dcSJack F Vogel 	bzero(mta, sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS *
1820758cc3dcSJack F Vogel 	    MAX_NUM_MULTICAST_ADDRESSES);
1821758cc3dcSJack F Vogel 
1822758cc3dcSJack F Vogel #if __FreeBSD_version < 800000
1823758cc3dcSJack F Vogel 	IF_ADDR_LOCK(ifp);
1824758cc3dcSJack F Vogel #else
1825758cc3dcSJack F Vogel 	if_maddr_rlock(ifp);
1826758cc3dcSJack F Vogel #endif
1827758cc3dcSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1828758cc3dcSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
1829758cc3dcSJack F Vogel 			continue;
1830758cc3dcSJack F Vogel 		if (mcnt == MAX_NUM_MULTICAST_ADDRESSES)
1831758cc3dcSJack F Vogel 			break;
1832758cc3dcSJack F Vogel 		bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr),
1833758cc3dcSJack F Vogel 		    &mta[mcnt * IXGBE_ETH_LENGTH_OF_ADDRESS],
1834758cc3dcSJack F Vogel 		    IXGBE_ETH_LENGTH_OF_ADDRESS);
1835758cc3dcSJack F Vogel 		mcnt++;
1836758cc3dcSJack F Vogel 	}
1837758cc3dcSJack F Vogel #if __FreeBSD_version < 800000
1838758cc3dcSJack F Vogel 	IF_ADDR_UNLOCK(ifp);
1839758cc3dcSJack F Vogel #else
1840758cc3dcSJack F Vogel 	if_maddr_runlock(ifp);
1841758cc3dcSJack F Vogel #endif
1842758cc3dcSJack F Vogel 
1843758cc3dcSJack F Vogel 	fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
1844758cc3dcSJack F Vogel 	fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
1845758cc3dcSJack F Vogel 	if (ifp->if_flags & IFF_PROMISC)
1846758cc3dcSJack F Vogel 		fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
1847758cc3dcSJack F Vogel 	else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES ||
1848758cc3dcSJack F Vogel 	    ifp->if_flags & IFF_ALLMULTI) {
1849758cc3dcSJack F Vogel 		fctrl |= IXGBE_FCTRL_MPE;
1850758cc3dcSJack F Vogel 		fctrl &= ~IXGBE_FCTRL_UPE;
1851758cc3dcSJack F Vogel 	} else
1852758cc3dcSJack F Vogel 		fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
1853758cc3dcSJack F Vogel 
1854758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl);
1855758cc3dcSJack F Vogel 
1856758cc3dcSJack F Vogel 	if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) {
1857758cc3dcSJack F Vogel 		update_ptr = mta;
1858758cc3dcSJack F Vogel 		ixgbe_update_mc_addr_list(&adapter->hw,
1859758cc3dcSJack F Vogel 		    update_ptr, mcnt, ixgbe_mc_array_itr, TRUE);
1860758cc3dcSJack F Vogel 	}
1861758cc3dcSJack F Vogel 
1862758cc3dcSJack F Vogel 	return;
1863758cc3dcSJack F Vogel }
1864758cc3dcSJack F Vogel 
1865758cc3dcSJack F Vogel /*
1866758cc3dcSJack F Vogel  * This is an iterator function now needed by the multicast
1867758cc3dcSJack F Vogel  * shared code. It simply feeds the shared code routine the
1868758cc3dcSJack F Vogel  * addresses in the array of ixgbe_set_multi() one by one.
1869758cc3dcSJack F Vogel  */
1870758cc3dcSJack F Vogel static u8 *
1871758cc3dcSJack F Vogel ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq)
1872758cc3dcSJack F Vogel {
1873758cc3dcSJack F Vogel 	u8 *addr = *update_ptr;
1874758cc3dcSJack F Vogel 	u8 *newptr;
1875758cc3dcSJack F Vogel 	*vmdq = 0;
1876758cc3dcSJack F Vogel 
1877758cc3dcSJack F Vogel 	newptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS;
1878758cc3dcSJack F Vogel 	*update_ptr = newptr;
1879758cc3dcSJack F Vogel 	return addr;
1880758cc3dcSJack F Vogel }
1881758cc3dcSJack F Vogel 
1882758cc3dcSJack F Vogel 
1883758cc3dcSJack F Vogel /*********************************************************************
1884758cc3dcSJack F Vogel  *  Timer routine
1885758cc3dcSJack F Vogel  *
1886758cc3dcSJack F Vogel  *  This routine checks for link status,updates statistics,
1887758cc3dcSJack F Vogel  *  and runs the watchdog check.
1888758cc3dcSJack F Vogel  *
1889758cc3dcSJack F Vogel  **********************************************************************/
1890758cc3dcSJack F Vogel 
1891758cc3dcSJack F Vogel static void
1892758cc3dcSJack F Vogel ixgbe_local_timer(void *arg)
1893758cc3dcSJack F Vogel {
1894758cc3dcSJack F Vogel 	struct adapter	*adapter = arg;
1895758cc3dcSJack F Vogel 	device_t	dev = adapter->dev;
1896758cc3dcSJack F Vogel 	struct ix_queue *que = adapter->queues;
1897758cc3dcSJack F Vogel 	u64		queues = 0;
1898758cc3dcSJack F Vogel 	int		hung = 0;
1899758cc3dcSJack F Vogel 
1900758cc3dcSJack F Vogel 	mtx_assert(&adapter->core_mtx, MA_OWNED);
1901758cc3dcSJack F Vogel 
1902758cc3dcSJack F Vogel 	/* Check for pluggable optics */
1903758cc3dcSJack F Vogel 	if (adapter->sfp_probe)
1904758cc3dcSJack F Vogel 		if (!ixgbe_sfp_probe(adapter))
1905758cc3dcSJack F Vogel 			goto out; /* Nothing to do */
1906758cc3dcSJack F Vogel 
1907758cc3dcSJack F Vogel 	ixgbe_update_link_status(adapter);
1908758cc3dcSJack F Vogel 	ixgbe_update_stats_counters(adapter);
1909758cc3dcSJack F Vogel 
1910758cc3dcSJack F Vogel 	/*
1911758cc3dcSJack F Vogel 	** Check the TX queues status
1912758cc3dcSJack F Vogel 	**	- mark hung queues so we don't schedule on them
1913758cc3dcSJack F Vogel 	**      - watchdog only if all queues show hung
1914758cc3dcSJack F Vogel 	*/
1915758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, que++) {
1916758cc3dcSJack F Vogel 		/* Keep track of queues with work for soft irq */
1917758cc3dcSJack F Vogel 		if (que->txr->busy)
1918758cc3dcSJack F Vogel 			queues |= ((u64)1 << que->me);
1919758cc3dcSJack F Vogel 		/*
1920758cc3dcSJack F Vogel 		** Each time txeof runs without cleaning, but there
1921758cc3dcSJack F Vogel 		** are uncleaned descriptors it increments busy. If
1922758cc3dcSJack F Vogel 		** we get to the MAX we declare it hung.
1923758cc3dcSJack F Vogel 		*/
1924758cc3dcSJack F Vogel 		if (que->busy == IXGBE_QUEUE_HUNG) {
1925758cc3dcSJack F Vogel 			++hung;
1926758cc3dcSJack F Vogel 			/* Mark the queue as inactive */
1927758cc3dcSJack F Vogel 			adapter->active_queues &= ~((u64)1 << que->me);
1928758cc3dcSJack F Vogel 			continue;
1929758cc3dcSJack F Vogel 		} else {
1930758cc3dcSJack F Vogel 			/* Check if we've come back from hung */
1931758cc3dcSJack F Vogel 			if ((adapter->active_queues & ((u64)1 << que->me)) == 0)
1932758cc3dcSJack F Vogel                                 adapter->active_queues |= ((u64)1 << que->me);
1933758cc3dcSJack F Vogel 		}
1934758cc3dcSJack F Vogel 		if (que->busy >= IXGBE_MAX_TX_BUSY) {
1935758cc3dcSJack F Vogel 			device_printf(dev,"Warning queue %d "
1936758cc3dcSJack F Vogel 			    "appears to be hung!\n", i);
1937758cc3dcSJack F Vogel 			que->txr->busy = IXGBE_QUEUE_HUNG;
1938758cc3dcSJack F Vogel 			++hung;
1939758cc3dcSJack F Vogel 		}
1940758cc3dcSJack F Vogel 
1941758cc3dcSJack F Vogel 	}
1942758cc3dcSJack F Vogel 
1943758cc3dcSJack F Vogel 	/* Only truly watchdog if all queues show hung */
1944758cc3dcSJack F Vogel 	if (hung == adapter->num_queues)
1945758cc3dcSJack F Vogel 		goto watchdog;
1946758cc3dcSJack F Vogel 	else if (queues != 0) { /* Force an IRQ on queues with work */
1947758cc3dcSJack F Vogel 		ixgbe_rearm_queues(adapter, queues);
1948758cc3dcSJack F Vogel 	}
1949758cc3dcSJack F Vogel 
1950758cc3dcSJack F Vogel out:
1951758cc3dcSJack F Vogel 	callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter);
1952758cc3dcSJack F Vogel 	return;
1953758cc3dcSJack F Vogel 
1954758cc3dcSJack F Vogel watchdog:
1955758cc3dcSJack F Vogel 	device_printf(adapter->dev, "Watchdog timeout -- resetting\n");
1956758cc3dcSJack F Vogel 	adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1957758cc3dcSJack F Vogel 	adapter->watchdog_events++;
1958758cc3dcSJack F Vogel 	ixgbe_init_locked(adapter);
1959758cc3dcSJack F Vogel }
1960758cc3dcSJack F Vogel 
1961758cc3dcSJack F Vogel /*
1962758cc3dcSJack F Vogel ** Note: this routine updates the OS on the link state
1963758cc3dcSJack F Vogel **	the real check of the hardware only happens with
1964758cc3dcSJack F Vogel **	a link interrupt.
1965758cc3dcSJack F Vogel */
1966758cc3dcSJack F Vogel static void
1967758cc3dcSJack F Vogel ixgbe_update_link_status(struct adapter *adapter)
1968758cc3dcSJack F Vogel {
1969758cc3dcSJack F Vogel 	struct ifnet	*ifp = adapter->ifp;
1970758cc3dcSJack F Vogel 	device_t dev = adapter->dev;
1971758cc3dcSJack F Vogel 
1972758cc3dcSJack F Vogel 	if (adapter->link_up){
1973758cc3dcSJack F Vogel 		if (adapter->link_active == FALSE) {
1974758cc3dcSJack F Vogel 			if (bootverbose)
1975758cc3dcSJack F Vogel 				device_printf(dev,"Link is up %d Gbps %s \n",
1976758cc3dcSJack F Vogel 				    ((adapter->link_speed == 128)? 10:1),
1977758cc3dcSJack F Vogel 				    "Full Duplex");
1978758cc3dcSJack F Vogel 			adapter->link_active = TRUE;
1979758cc3dcSJack F Vogel 			/* Update any Flow Control changes */
1980758cc3dcSJack F Vogel 			ixgbe_fc_enable(&adapter->hw);
1981*6f37f232SEric Joyner 			/* Update DMA coalescing config */
1982*6f37f232SEric Joyner 			ixgbe_config_dmac(adapter);
1983758cc3dcSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_UP);
1984758cc3dcSJack F Vogel 		}
1985758cc3dcSJack F Vogel 	} else { /* Link down */
1986758cc3dcSJack F Vogel 		if (adapter->link_active == TRUE) {
1987758cc3dcSJack F Vogel 			if (bootverbose)
1988758cc3dcSJack F Vogel 				device_printf(dev,"Link is Down\n");
1989758cc3dcSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_DOWN);
1990758cc3dcSJack F Vogel 			adapter->link_active = FALSE;
1991758cc3dcSJack F Vogel 		}
1992758cc3dcSJack F Vogel 	}
1993758cc3dcSJack F Vogel 
1994758cc3dcSJack F Vogel 	return;
1995758cc3dcSJack F Vogel }
1996758cc3dcSJack F Vogel 
1997758cc3dcSJack F Vogel 
1998758cc3dcSJack F Vogel /*********************************************************************
1999758cc3dcSJack F Vogel  *
2000758cc3dcSJack F Vogel  *  This routine disables all traffic on the adapter by issuing a
2001758cc3dcSJack F Vogel  *  global reset on the MAC and deallocates TX/RX buffers.
2002758cc3dcSJack F Vogel  *
2003758cc3dcSJack F Vogel  **********************************************************************/
2004758cc3dcSJack F Vogel 
2005758cc3dcSJack F Vogel static void
2006758cc3dcSJack F Vogel ixgbe_stop(void *arg)
2007758cc3dcSJack F Vogel {
2008758cc3dcSJack F Vogel 	struct ifnet   *ifp;
2009758cc3dcSJack F Vogel 	struct adapter *adapter = arg;
2010758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
2011758cc3dcSJack F Vogel 	ifp = adapter->ifp;
2012758cc3dcSJack F Vogel 
2013758cc3dcSJack F Vogel 	mtx_assert(&adapter->core_mtx, MA_OWNED);
2014758cc3dcSJack F Vogel 
2015758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_stop: begin\n");
2016758cc3dcSJack F Vogel 	ixgbe_disable_intr(adapter);
2017758cc3dcSJack F Vogel 	callout_stop(&adapter->timer);
2018758cc3dcSJack F Vogel 
2019758cc3dcSJack F Vogel 	/* Let the stack know...*/
2020758cc3dcSJack F Vogel 	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2021758cc3dcSJack F Vogel 
2022758cc3dcSJack F Vogel 	ixgbe_reset_hw(hw);
2023758cc3dcSJack F Vogel 	hw->adapter_stopped = FALSE;
2024758cc3dcSJack F Vogel 	ixgbe_stop_adapter(hw);
2025758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82599EB)
2026758cc3dcSJack F Vogel 		ixgbe_stop_mac_link_on_d3_82599(hw);
2027758cc3dcSJack F Vogel 	/* Turn off the laser - noop with no optics */
2028758cc3dcSJack F Vogel 	ixgbe_disable_tx_laser(hw);
2029758cc3dcSJack F Vogel 
2030758cc3dcSJack F Vogel 	/* Update the stack */
2031758cc3dcSJack F Vogel 	adapter->link_up = FALSE;
2032758cc3dcSJack F Vogel        	ixgbe_update_link_status(adapter);
2033758cc3dcSJack F Vogel 
2034758cc3dcSJack F Vogel 	/* reprogram the RAR[0] in case user changed it. */
2035758cc3dcSJack F Vogel 	ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV);
2036758cc3dcSJack F Vogel 
2037758cc3dcSJack F Vogel 	return;
2038758cc3dcSJack F Vogel }
2039758cc3dcSJack F Vogel 
2040758cc3dcSJack F Vogel 
2041758cc3dcSJack F Vogel /*********************************************************************
2042758cc3dcSJack F Vogel  *
2043758cc3dcSJack F Vogel  *  Determine hardware revision.
2044758cc3dcSJack F Vogel  *
2045758cc3dcSJack F Vogel  **********************************************************************/
2046758cc3dcSJack F Vogel static void
2047758cc3dcSJack F Vogel ixgbe_identify_hardware(struct adapter *adapter)
2048758cc3dcSJack F Vogel {
2049758cc3dcSJack F Vogel 	device_t        dev = adapter->dev;
2050758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
2051758cc3dcSJack F Vogel 
2052758cc3dcSJack F Vogel 	/* Save off the information about this board */
2053758cc3dcSJack F Vogel 	hw->vendor_id = pci_get_vendor(dev);
2054758cc3dcSJack F Vogel 	hw->device_id = pci_get_device(dev);
2055758cc3dcSJack F Vogel 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
2056758cc3dcSJack F Vogel 	hw->subsystem_vendor_id =
2057758cc3dcSJack F Vogel 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
2058758cc3dcSJack F Vogel 	hw->subsystem_device_id =
2059758cc3dcSJack F Vogel 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
2060758cc3dcSJack F Vogel 
2061758cc3dcSJack F Vogel 	/*
2062758cc3dcSJack F Vogel 	** Make sure BUSMASTER is set
2063758cc3dcSJack F Vogel 	*/
2064758cc3dcSJack F Vogel 	pci_enable_busmaster(dev);
2065758cc3dcSJack F Vogel 
2066758cc3dcSJack F Vogel 	/* We need this here to set the num_segs below */
2067758cc3dcSJack F Vogel 	ixgbe_set_mac_type(hw);
2068758cc3dcSJack F Vogel 
2069*6f37f232SEric Joyner 	/* Pick up the 82599 settings */
2070758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
2071758cc3dcSJack F Vogel 		hw->phy.smart_speed = ixgbe_smart_speed;
2072758cc3dcSJack F Vogel 		adapter->num_segs = IXGBE_82599_SCATTER;
2073758cc3dcSJack F Vogel 	} else
2074758cc3dcSJack F Vogel 		adapter->num_segs = IXGBE_82598_SCATTER;
2075758cc3dcSJack F Vogel 
2076758cc3dcSJack F Vogel 	return;
2077758cc3dcSJack F Vogel }
2078758cc3dcSJack F Vogel 
2079758cc3dcSJack F Vogel /*********************************************************************
2080758cc3dcSJack F Vogel  *
2081758cc3dcSJack F Vogel  *  Determine optic type
2082758cc3dcSJack F Vogel  *
2083758cc3dcSJack F Vogel  **********************************************************************/
2084758cc3dcSJack F Vogel static void
2085758cc3dcSJack F Vogel ixgbe_setup_optics(struct adapter *adapter)
2086758cc3dcSJack F Vogel {
2087758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
2088758cc3dcSJack F Vogel 	int		layer;
2089758cc3dcSJack F Vogel 
2090758cc3dcSJack F Vogel 	layer = ixgbe_get_supported_physical_layer(hw);
2091758cc3dcSJack F Vogel 
2092758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) {
2093758cc3dcSJack F Vogel 		adapter->optics = IFM_10G_T;
2094758cc3dcSJack F Vogel 		return;
2095758cc3dcSJack F Vogel 	}
2096758cc3dcSJack F Vogel 
2097758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) {
2098758cc3dcSJack F Vogel 		adapter->optics = IFM_1000_T;
2099758cc3dcSJack F Vogel 		return;
2100758cc3dcSJack F Vogel 	}
2101758cc3dcSJack F Vogel 
2102758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) {
2103758cc3dcSJack F Vogel 		adapter->optics = IFM_1000_SX;
2104758cc3dcSJack F Vogel 		return;
2105758cc3dcSJack F Vogel 	}
2106758cc3dcSJack F Vogel 
2107758cc3dcSJack F Vogel 	if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_LR |
2108758cc3dcSJack F Vogel 	    IXGBE_PHYSICAL_LAYER_10GBASE_LRM)) {
2109758cc3dcSJack F Vogel 		adapter->optics = IFM_10G_LR;
2110758cc3dcSJack F Vogel 		return;
2111758cc3dcSJack F Vogel 	}
2112758cc3dcSJack F Vogel 
2113758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) {
2114758cc3dcSJack F Vogel 		adapter->optics = IFM_10G_SR;
2115758cc3dcSJack F Vogel 		return;
2116758cc3dcSJack F Vogel 	}
2117758cc3dcSJack F Vogel 
2118758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU) {
2119758cc3dcSJack F Vogel 		adapter->optics = IFM_10G_TWINAX;
2120758cc3dcSJack F Vogel 		return;
2121758cc3dcSJack F Vogel 	}
2122758cc3dcSJack F Vogel 
2123758cc3dcSJack F Vogel 	if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 |
2124758cc3dcSJack F Vogel 	    IXGBE_PHYSICAL_LAYER_10GBASE_CX4)) {
2125758cc3dcSJack F Vogel 		adapter->optics = IFM_10G_CX4;
2126758cc3dcSJack F Vogel 		return;
2127758cc3dcSJack F Vogel 	}
2128758cc3dcSJack F Vogel 
2129758cc3dcSJack F Vogel 	/* If we get here just set the default */
2130758cc3dcSJack F Vogel 	adapter->optics = IFM_ETHER | IFM_AUTO;
2131758cc3dcSJack F Vogel 	return;
2132758cc3dcSJack F Vogel }
2133758cc3dcSJack F Vogel 
2134758cc3dcSJack F Vogel /*********************************************************************
2135758cc3dcSJack F Vogel  *
2136758cc3dcSJack F Vogel  *  Setup the Legacy or MSI Interrupt handler
2137758cc3dcSJack F Vogel  *
2138758cc3dcSJack F Vogel  **********************************************************************/
2139758cc3dcSJack F Vogel static int
2140758cc3dcSJack F Vogel ixgbe_allocate_legacy(struct adapter *adapter)
2141758cc3dcSJack F Vogel {
2142758cc3dcSJack F Vogel 	device_t	dev = adapter->dev;
2143758cc3dcSJack F Vogel 	struct		ix_queue *que = adapter->queues;
2144758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
2145758cc3dcSJack F Vogel 	struct tx_ring		*txr = adapter->tx_rings;
2146758cc3dcSJack F Vogel #endif
2147758cc3dcSJack F Vogel 	int		error, rid = 0;
2148758cc3dcSJack F Vogel 
2149758cc3dcSJack F Vogel 	/* MSI RID at 1 */
2150758cc3dcSJack F Vogel 	if (adapter->msix == 1)
2151758cc3dcSJack F Vogel 		rid = 1;
2152758cc3dcSJack F Vogel 
2153758cc3dcSJack F Vogel 	/* We allocate a single interrupt resource */
2154758cc3dcSJack F Vogel 	adapter->res = bus_alloc_resource_any(dev,
2155758cc3dcSJack F Vogel             SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
2156758cc3dcSJack F Vogel 	if (adapter->res == NULL) {
2157758cc3dcSJack F Vogel 		device_printf(dev, "Unable to allocate bus resource: "
2158758cc3dcSJack F Vogel 		    "interrupt\n");
2159758cc3dcSJack F Vogel 		return (ENXIO);
2160758cc3dcSJack F Vogel 	}
2161758cc3dcSJack F Vogel 
2162758cc3dcSJack F Vogel 	/*
2163758cc3dcSJack F Vogel 	 * Try allocating a fast interrupt and the associated deferred
2164758cc3dcSJack F Vogel 	 * processing contexts.
2165758cc3dcSJack F Vogel 	 */
2166758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
2167758cc3dcSJack F Vogel 	TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr);
2168758cc3dcSJack F Vogel #endif
2169758cc3dcSJack F Vogel 	TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que);
2170758cc3dcSJack F Vogel 	que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT,
2171758cc3dcSJack F Vogel             taskqueue_thread_enqueue, &que->tq);
2172758cc3dcSJack F Vogel 	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s ixq",
2173758cc3dcSJack F Vogel             device_get_nameunit(adapter->dev));
2174758cc3dcSJack F Vogel 
2175758cc3dcSJack F Vogel 	/* Tasklets for Link, SFP and Multispeed Fiber */
2176758cc3dcSJack F Vogel 	TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter);
2177758cc3dcSJack F Vogel 	TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter);
2178758cc3dcSJack F Vogel 	TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter);
2179*6f37f232SEric Joyner 	TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter);
2180758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
2181758cc3dcSJack F Vogel 	TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter);
2182758cc3dcSJack F Vogel #endif
2183758cc3dcSJack F Vogel 	adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT,
2184758cc3dcSJack F Vogel 	    taskqueue_thread_enqueue, &adapter->tq);
2185758cc3dcSJack F Vogel 	taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq",
2186758cc3dcSJack F Vogel 	    device_get_nameunit(adapter->dev));
2187758cc3dcSJack F Vogel 
2188758cc3dcSJack F Vogel 	if ((error = bus_setup_intr(dev, adapter->res,
2189758cc3dcSJack F Vogel             INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq,
2190758cc3dcSJack F Vogel             que, &adapter->tag)) != 0) {
2191758cc3dcSJack F Vogel 		device_printf(dev, "Failed to register fast interrupt "
2192758cc3dcSJack F Vogel 		    "handler: %d\n", error);
2193758cc3dcSJack F Vogel 		taskqueue_free(que->tq);
2194758cc3dcSJack F Vogel 		taskqueue_free(adapter->tq);
2195758cc3dcSJack F Vogel 		que->tq = NULL;
2196758cc3dcSJack F Vogel 		adapter->tq = NULL;
2197758cc3dcSJack F Vogel 		return (error);
2198758cc3dcSJack F Vogel 	}
2199758cc3dcSJack F Vogel 	/* For simplicity in the handlers */
2200758cc3dcSJack F Vogel 	adapter->active_queues = IXGBE_EIMS_ENABLE_MASK;
2201758cc3dcSJack F Vogel 
2202758cc3dcSJack F Vogel 	return (0);
2203758cc3dcSJack F Vogel }
2204758cc3dcSJack F Vogel 
2205758cc3dcSJack F Vogel 
2206758cc3dcSJack F Vogel /*********************************************************************
2207758cc3dcSJack F Vogel  *
2208758cc3dcSJack F Vogel  *  Setup MSIX Interrupt resources and handlers
2209758cc3dcSJack F Vogel  *
2210758cc3dcSJack F Vogel  **********************************************************************/
2211758cc3dcSJack F Vogel static int
2212758cc3dcSJack F Vogel ixgbe_allocate_msix(struct adapter *adapter)
2213758cc3dcSJack F Vogel {
2214758cc3dcSJack F Vogel 	device_t        dev = adapter->dev;
2215758cc3dcSJack F Vogel 	struct 		ix_queue *que = adapter->queues;
2216758cc3dcSJack F Vogel 	struct  	tx_ring *txr = adapter->tx_rings;
2217758cc3dcSJack F Vogel 	int 		error, rid, vector = 0;
2218758cc3dcSJack F Vogel 	int		cpu_id = 0;
2219a1edda90SAdrian Chadd #ifdef	RSS
2220a1edda90SAdrian Chadd 	cpuset_t	cpu_mask;
2221a1edda90SAdrian Chadd #endif
2222758cc3dcSJack F Vogel 
2223758cc3dcSJack F Vogel #ifdef	RSS
2224758cc3dcSJack F Vogel 	/*
2225758cc3dcSJack F Vogel 	 * If we're doing RSS, the number of queues needs to
2226758cc3dcSJack F Vogel 	 * match the number of RSS buckets that are configured.
2227758cc3dcSJack F Vogel 	 *
2228758cc3dcSJack F Vogel 	 * + If there's more queues than RSS buckets, we'll end
2229758cc3dcSJack F Vogel 	 *   up with queues that get no traffic.
2230758cc3dcSJack F Vogel 	 *
2231758cc3dcSJack F Vogel 	 * + If there's more RSS buckets than queues, we'll end
2232758cc3dcSJack F Vogel 	 *   up having multiple RSS buckets map to the same queue,
2233758cc3dcSJack F Vogel 	 *   so there'll be some contention.
2234758cc3dcSJack F Vogel 	 */
2235758cc3dcSJack F Vogel 	if (adapter->num_queues != rss_getnumbuckets()) {
2236758cc3dcSJack F Vogel 		device_printf(dev,
2237758cc3dcSJack F Vogel 		    "%s: number of queues (%d) != number of RSS buckets (%d)"
2238758cc3dcSJack F Vogel 		    "; performance will be impacted.\n",
2239758cc3dcSJack F Vogel 		    __func__,
2240758cc3dcSJack F Vogel 		    adapter->num_queues,
2241758cc3dcSJack F Vogel 		    rss_getnumbuckets());
2242758cc3dcSJack F Vogel 	}
2243758cc3dcSJack F Vogel #endif
2244758cc3dcSJack F Vogel 
2245758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) {
2246758cc3dcSJack F Vogel 		rid = vector + 1;
2247758cc3dcSJack F Vogel 		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
2248758cc3dcSJack F Vogel 		    RF_SHAREABLE | RF_ACTIVE);
2249758cc3dcSJack F Vogel 		if (que->res == NULL) {
2250758cc3dcSJack F Vogel 			device_printf(dev,"Unable to allocate"
2251758cc3dcSJack F Vogel 		    	    " bus resource: que interrupt [%d]\n", vector);
2252758cc3dcSJack F Vogel 			return (ENXIO);
2253758cc3dcSJack F Vogel 		}
2254758cc3dcSJack F Vogel 		/* Set the handler function */
2255758cc3dcSJack F Vogel 		error = bus_setup_intr(dev, que->res,
2256758cc3dcSJack F Vogel 		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
2257758cc3dcSJack F Vogel 		    ixgbe_msix_que, que, &que->tag);
2258758cc3dcSJack F Vogel 		if (error) {
2259758cc3dcSJack F Vogel 			que->res = NULL;
2260758cc3dcSJack F Vogel 			device_printf(dev, "Failed to register QUE handler");
2261758cc3dcSJack F Vogel 			return (error);
2262758cc3dcSJack F Vogel 		}
2263758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504
2264758cc3dcSJack F Vogel 		bus_describe_intr(dev, que->res, que->tag, "que %d", i);
2265758cc3dcSJack F Vogel #endif
2266758cc3dcSJack F Vogel 		que->msix = vector;
2267758cc3dcSJack F Vogel 		adapter->active_queues |= (u64)(1 << que->msix);
2268758cc3dcSJack F Vogel #ifdef	RSS
2269758cc3dcSJack F Vogel 		/*
2270758cc3dcSJack F Vogel 		 * The queue ID is used as the RSS layer bucket ID.
2271758cc3dcSJack F Vogel 		 * We look up the queue ID -> RSS CPU ID and select
2272758cc3dcSJack F Vogel 		 * that.
2273758cc3dcSJack F Vogel 		 */
2274758cc3dcSJack F Vogel 		cpu_id = rss_getcpu(i % rss_getnumbuckets());
2275758cc3dcSJack F Vogel #else
2276758cc3dcSJack F Vogel 		/*
2277758cc3dcSJack F Vogel 		 * Bind the msix vector, and thus the
2278758cc3dcSJack F Vogel 		 * rings to the corresponding cpu.
2279758cc3dcSJack F Vogel 		 *
2280758cc3dcSJack F Vogel 		 * This just happens to match the default RSS round-robin
2281758cc3dcSJack F Vogel 		 * bucket -> queue -> CPU allocation.
2282758cc3dcSJack F Vogel 		 */
2283758cc3dcSJack F Vogel 		if (adapter->num_queues > 1)
2284758cc3dcSJack F Vogel 			cpu_id = i;
2285758cc3dcSJack F Vogel #endif
2286758cc3dcSJack F Vogel 		if (adapter->num_queues > 1)
2287758cc3dcSJack F Vogel 			bus_bind_intr(dev, que->res, cpu_id);
2288758cc3dcSJack F Vogel 
2289758cc3dcSJack F Vogel #ifdef	RSS
2290758cc3dcSJack F Vogel 		device_printf(dev,
2291758cc3dcSJack F Vogel 		    "Bound RSS bucket %d to CPU %d\n",
2292758cc3dcSJack F Vogel 		    i, cpu_id);
2293758cc3dcSJack F Vogel #else
2294*6f37f232SEric Joyner 		if (bootverbose)
2295758cc3dcSJack F Vogel 			device_printf(dev,
2296758cc3dcSJack F Vogel 			    "Bound queue %d to cpu %d\n",
2297758cc3dcSJack F Vogel 			    i, cpu_id);
2298758cc3dcSJack F Vogel #endif
2299758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
2300758cc3dcSJack F Vogel 		TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr);
2301758cc3dcSJack F Vogel #endif
2302758cc3dcSJack F Vogel 		TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que);
2303758cc3dcSJack F Vogel 		que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT,
2304758cc3dcSJack F Vogel 		    taskqueue_thread_enqueue, &que->tq);
2305758cc3dcSJack F Vogel #ifdef	RSS
2306a1edda90SAdrian Chadd 		CPU_SETOF(cpu_id, &cpu_mask);
2307a1edda90SAdrian Chadd 		taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET,
2308a1edda90SAdrian Chadd 		    &cpu_mask,
2309758cc3dcSJack F Vogel 		    "%s (bucket %d)",
2310758cc3dcSJack F Vogel 		    device_get_nameunit(adapter->dev),
2311758cc3dcSJack F Vogel 		    cpu_id);
2312758cc3dcSJack F Vogel #else
2313758cc3dcSJack F Vogel 		taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
2314758cc3dcSJack F Vogel 		    device_get_nameunit(adapter->dev));
2315758cc3dcSJack F Vogel #endif
2316758cc3dcSJack F Vogel 	}
2317758cc3dcSJack F Vogel 
2318758cc3dcSJack F Vogel 	/* and Link */
2319758cc3dcSJack F Vogel 	rid = vector + 1;
2320758cc3dcSJack F Vogel 	adapter->res = bus_alloc_resource_any(dev,
2321758cc3dcSJack F Vogel     	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
2322758cc3dcSJack F Vogel 	if (!adapter->res) {
2323758cc3dcSJack F Vogel 		device_printf(dev,"Unable to allocate"
2324758cc3dcSJack F Vogel     	    " bus resource: Link interrupt [%d]\n", rid);
2325758cc3dcSJack F Vogel 		return (ENXIO);
2326758cc3dcSJack F Vogel 	}
2327758cc3dcSJack F Vogel 	/* Set the link handler function */
2328758cc3dcSJack F Vogel 	error = bus_setup_intr(dev, adapter->res,
2329758cc3dcSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
2330758cc3dcSJack F Vogel 	    ixgbe_msix_link, adapter, &adapter->tag);
2331758cc3dcSJack F Vogel 	if (error) {
2332758cc3dcSJack F Vogel 		adapter->res = NULL;
2333758cc3dcSJack F Vogel 		device_printf(dev, "Failed to register LINK handler");
2334758cc3dcSJack F Vogel 		return (error);
2335758cc3dcSJack F Vogel 	}
2336758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504
2337758cc3dcSJack F Vogel 	bus_describe_intr(dev, adapter->res, adapter->tag, "link");
2338758cc3dcSJack F Vogel #endif
2339758cc3dcSJack F Vogel 	adapter->vector = vector;
2340758cc3dcSJack F Vogel 	/* Tasklets for Link, SFP and Multispeed Fiber */
2341758cc3dcSJack F Vogel 	TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter);
2342758cc3dcSJack F Vogel 	TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter);
2343758cc3dcSJack F Vogel 	TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter);
2344*6f37f232SEric Joyner 	TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter);
2345758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
2346758cc3dcSJack F Vogel 	TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter);
2347758cc3dcSJack F Vogel #endif
2348758cc3dcSJack F Vogel 	adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT,
2349758cc3dcSJack F Vogel 	    taskqueue_thread_enqueue, &adapter->tq);
2350758cc3dcSJack F Vogel 	taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq",
2351758cc3dcSJack F Vogel 	    device_get_nameunit(adapter->dev));
2352758cc3dcSJack F Vogel 
2353758cc3dcSJack F Vogel 	return (0);
2354758cc3dcSJack F Vogel }
2355758cc3dcSJack F Vogel 
2356758cc3dcSJack F Vogel /*
2357758cc3dcSJack F Vogel  * Setup Either MSI/X or MSI
2358758cc3dcSJack F Vogel  */
2359758cc3dcSJack F Vogel static int
2360758cc3dcSJack F Vogel ixgbe_setup_msix(struct adapter *adapter)
2361758cc3dcSJack F Vogel {
2362758cc3dcSJack F Vogel 	device_t dev = adapter->dev;
2363758cc3dcSJack F Vogel 	int rid, want, queues, msgs;
2364758cc3dcSJack F Vogel 
2365758cc3dcSJack F Vogel 	/* Override by tuneable */
2366758cc3dcSJack F Vogel 	if (ixgbe_enable_msix == 0)
2367758cc3dcSJack F Vogel 		goto msi;
2368758cc3dcSJack F Vogel 
2369758cc3dcSJack F Vogel 	/* First try MSI/X */
2370758cc3dcSJack F Vogel 	msgs = pci_msix_count(dev);
2371758cc3dcSJack F Vogel 	if (msgs == 0)
2372758cc3dcSJack F Vogel 		goto msi;
2373758cc3dcSJack F Vogel 	rid = PCIR_BAR(MSIX_82598_BAR);
2374758cc3dcSJack F Vogel 	adapter->msix_mem = bus_alloc_resource_any(dev,
2375758cc3dcSJack F Vogel 	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
2376758cc3dcSJack F Vogel        	if (adapter->msix_mem == NULL) {
2377758cc3dcSJack F Vogel 		rid += 4;	/* 82599 maps in higher BAR */
2378758cc3dcSJack F Vogel 		adapter->msix_mem = bus_alloc_resource_any(dev,
2379758cc3dcSJack F Vogel 		    SYS_RES_MEMORY, &rid, RF_ACTIVE);
2380758cc3dcSJack F Vogel 	}
2381758cc3dcSJack F Vogel        	if (adapter->msix_mem == NULL) {
2382758cc3dcSJack F Vogel 		/* May not be enabled */
2383758cc3dcSJack F Vogel 		device_printf(adapter->dev,
2384758cc3dcSJack F Vogel 		    "Unable to map MSIX table \n");
2385758cc3dcSJack F Vogel 		goto msi;
2386758cc3dcSJack F Vogel 	}
2387758cc3dcSJack F Vogel 
2388758cc3dcSJack F Vogel 	/* Figure out a reasonable auto config value */
2389758cc3dcSJack F Vogel 	queues = (mp_ncpus > (msgs-1)) ? (msgs-1) : mp_ncpus;
2390758cc3dcSJack F Vogel 
2391758cc3dcSJack F Vogel #ifdef	RSS
2392758cc3dcSJack F Vogel 	/* If we're doing RSS, clamp at the number of RSS buckets */
2393758cc3dcSJack F Vogel 	if (queues > rss_getnumbuckets())
2394758cc3dcSJack F Vogel 		queues = rss_getnumbuckets();
2395758cc3dcSJack F Vogel #endif
2396758cc3dcSJack F Vogel 
2397758cc3dcSJack F Vogel 	if (ixgbe_num_queues != 0)
2398758cc3dcSJack F Vogel 		queues = ixgbe_num_queues;
2399758cc3dcSJack F Vogel 
2400758cc3dcSJack F Vogel 	/* reflect correct sysctl value */
2401758cc3dcSJack F Vogel 	ixgbe_num_queues = queues;
2402758cc3dcSJack F Vogel 
2403758cc3dcSJack F Vogel 	/*
2404758cc3dcSJack F Vogel 	** Want one vector (RX/TX pair) per queue
2405758cc3dcSJack F Vogel 	** plus an additional for Link.
2406758cc3dcSJack F Vogel 	*/
2407758cc3dcSJack F Vogel 	want = queues + 1;
2408758cc3dcSJack F Vogel 	if (msgs >= want)
2409758cc3dcSJack F Vogel 		msgs = want;
2410758cc3dcSJack F Vogel 	else {
2411758cc3dcSJack F Vogel                	device_printf(adapter->dev,
2412758cc3dcSJack F Vogel 		    "MSIX Configuration Problem, "
2413758cc3dcSJack F Vogel 		    "%d vectors but %d queues wanted!\n",
2414758cc3dcSJack F Vogel 		    msgs, want);
2415758cc3dcSJack F Vogel 		goto msi;
2416758cc3dcSJack F Vogel 	}
2417758cc3dcSJack F Vogel 	if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) {
2418758cc3dcSJack F Vogel                	device_printf(adapter->dev,
2419758cc3dcSJack F Vogel 		    "Using MSIX interrupts with %d vectors\n", msgs);
2420758cc3dcSJack F Vogel 		adapter->num_queues = queues;
2421758cc3dcSJack F Vogel 		return (msgs);
2422758cc3dcSJack F Vogel 	}
2423758cc3dcSJack F Vogel 	/*
2424758cc3dcSJack F Vogel 	** If MSIX alloc failed or provided us with
2425758cc3dcSJack F Vogel 	** less than needed, free and fall through to MSI
2426758cc3dcSJack F Vogel 	*/
2427758cc3dcSJack F Vogel 	pci_release_msi(dev);
2428758cc3dcSJack F Vogel 
2429758cc3dcSJack F Vogel msi:
2430758cc3dcSJack F Vogel        	if (adapter->msix_mem != NULL) {
2431758cc3dcSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
2432758cc3dcSJack F Vogel 		    rid, adapter->msix_mem);
2433758cc3dcSJack F Vogel 		adapter->msix_mem = NULL;
2434758cc3dcSJack F Vogel 	}
2435758cc3dcSJack F Vogel        	msgs = 1;
2436758cc3dcSJack F Vogel        	if (pci_alloc_msi(dev, &msgs) == 0) {
2437758cc3dcSJack F Vogel                	device_printf(adapter->dev,"Using an MSI interrupt\n");
2438758cc3dcSJack F Vogel 		return (msgs);
2439758cc3dcSJack F Vogel 	}
2440758cc3dcSJack F Vogel 	device_printf(adapter->dev,"Using a Legacy interrupt\n");
2441758cc3dcSJack F Vogel 	return (0);
2442758cc3dcSJack F Vogel }
2443758cc3dcSJack F Vogel 
2444758cc3dcSJack F Vogel 
2445758cc3dcSJack F Vogel static int
2446758cc3dcSJack F Vogel ixgbe_allocate_pci_resources(struct adapter *adapter)
2447758cc3dcSJack F Vogel {
2448758cc3dcSJack F Vogel 	int             rid;
2449758cc3dcSJack F Vogel 	device_t        dev = adapter->dev;
2450758cc3dcSJack F Vogel 
2451758cc3dcSJack F Vogel 	rid = PCIR_BAR(0);
2452758cc3dcSJack F Vogel 	adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
2453758cc3dcSJack F Vogel 	    &rid, RF_ACTIVE);
2454758cc3dcSJack F Vogel 
2455758cc3dcSJack F Vogel 	if (!(adapter->pci_mem)) {
2456758cc3dcSJack F Vogel 		device_printf(dev,"Unable to allocate bus resource: memory\n");
2457758cc3dcSJack F Vogel 		return (ENXIO);
2458758cc3dcSJack F Vogel 	}
2459758cc3dcSJack F Vogel 
2460758cc3dcSJack F Vogel 	adapter->osdep.mem_bus_space_tag =
2461758cc3dcSJack F Vogel 		rman_get_bustag(adapter->pci_mem);
2462758cc3dcSJack F Vogel 	adapter->osdep.mem_bus_space_handle =
2463758cc3dcSJack F Vogel 		rman_get_bushandle(adapter->pci_mem);
2464758cc3dcSJack F Vogel 	adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle;
2465758cc3dcSJack F Vogel 
2466758cc3dcSJack F Vogel 	/* Legacy defaults */
2467758cc3dcSJack F Vogel 	adapter->num_queues = 1;
2468758cc3dcSJack F Vogel 	adapter->hw.back = &adapter->osdep;
2469758cc3dcSJack F Vogel 
2470758cc3dcSJack F Vogel 	/*
2471758cc3dcSJack F Vogel 	** Now setup MSI or MSI/X, should
2472758cc3dcSJack F Vogel 	** return us the number of supported
2473758cc3dcSJack F Vogel 	** vectors. (Will be 1 for MSI)
2474758cc3dcSJack F Vogel 	*/
2475758cc3dcSJack F Vogel 	adapter->msix = ixgbe_setup_msix(adapter);
2476758cc3dcSJack F Vogel 	return (0);
2477758cc3dcSJack F Vogel }
2478758cc3dcSJack F Vogel 
2479758cc3dcSJack F Vogel static void
2480758cc3dcSJack F Vogel ixgbe_free_pci_resources(struct adapter * adapter)
2481758cc3dcSJack F Vogel {
2482758cc3dcSJack F Vogel 	struct 		ix_queue *que = adapter->queues;
2483758cc3dcSJack F Vogel 	device_t	dev = adapter->dev;
2484758cc3dcSJack F Vogel 	int		rid, memrid;
2485758cc3dcSJack F Vogel 
2486758cc3dcSJack F Vogel 	if (adapter->hw.mac.type == ixgbe_mac_82598EB)
2487758cc3dcSJack F Vogel 		memrid = PCIR_BAR(MSIX_82598_BAR);
2488758cc3dcSJack F Vogel 	else
2489758cc3dcSJack F Vogel 		memrid = PCIR_BAR(MSIX_82599_BAR);
2490758cc3dcSJack F Vogel 
2491758cc3dcSJack F Vogel 	/*
2492758cc3dcSJack F Vogel 	** There is a slight possibility of a failure mode
2493758cc3dcSJack F Vogel 	** in attach that will result in entering this function
2494758cc3dcSJack F Vogel 	** before interrupt resources have been initialized, and
2495758cc3dcSJack F Vogel 	** in that case we do not want to execute the loops below
2496758cc3dcSJack F Vogel 	** We can detect this reliably by the state of the adapter
2497758cc3dcSJack F Vogel 	** res pointer.
2498758cc3dcSJack F Vogel 	*/
2499758cc3dcSJack F Vogel 	if (adapter->res == NULL)
2500758cc3dcSJack F Vogel 		goto mem;
2501758cc3dcSJack F Vogel 
2502758cc3dcSJack F Vogel 	/*
2503758cc3dcSJack F Vogel 	**  Release all msix queue resources:
2504758cc3dcSJack F Vogel 	*/
2505758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, que++) {
2506758cc3dcSJack F Vogel 		rid = que->msix + 1;
2507758cc3dcSJack F Vogel 		if (que->tag != NULL) {
2508758cc3dcSJack F Vogel 			bus_teardown_intr(dev, que->res, que->tag);
2509758cc3dcSJack F Vogel 			que->tag = NULL;
2510758cc3dcSJack F Vogel 		}
2511758cc3dcSJack F Vogel 		if (que->res != NULL)
2512758cc3dcSJack F Vogel 			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
2513758cc3dcSJack F Vogel 	}
2514758cc3dcSJack F Vogel 
2515758cc3dcSJack F Vogel 
2516758cc3dcSJack F Vogel 	/* Clean the Legacy or Link interrupt last */
2517758cc3dcSJack F Vogel 	if (adapter->vector) /* we are doing MSIX */
2518758cc3dcSJack F Vogel 		rid = adapter->vector + 1;
2519758cc3dcSJack F Vogel 	else
2520758cc3dcSJack F Vogel 		(adapter->msix != 0) ? (rid = 1):(rid = 0);
2521758cc3dcSJack F Vogel 
2522758cc3dcSJack F Vogel 	if (adapter->tag != NULL) {
2523758cc3dcSJack F Vogel 		bus_teardown_intr(dev, adapter->res, adapter->tag);
2524758cc3dcSJack F Vogel 		adapter->tag = NULL;
2525758cc3dcSJack F Vogel 	}
2526758cc3dcSJack F Vogel 	if (adapter->res != NULL)
2527758cc3dcSJack F Vogel 		bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res);
2528758cc3dcSJack F Vogel 
2529758cc3dcSJack F Vogel mem:
2530758cc3dcSJack F Vogel 	if (adapter->msix)
2531758cc3dcSJack F Vogel 		pci_release_msi(dev);
2532758cc3dcSJack F Vogel 
2533758cc3dcSJack F Vogel 	if (adapter->msix_mem != NULL)
2534758cc3dcSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
2535758cc3dcSJack F Vogel 		    memrid, adapter->msix_mem);
2536758cc3dcSJack F Vogel 
2537758cc3dcSJack F Vogel 	if (adapter->pci_mem != NULL)
2538758cc3dcSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
2539758cc3dcSJack F Vogel 		    PCIR_BAR(0), adapter->pci_mem);
2540758cc3dcSJack F Vogel 
2541758cc3dcSJack F Vogel 	return;
2542758cc3dcSJack F Vogel }
2543758cc3dcSJack F Vogel 
2544758cc3dcSJack F Vogel /*********************************************************************
2545758cc3dcSJack F Vogel  *
2546758cc3dcSJack F Vogel  *  Setup networking device structure and register an interface.
2547758cc3dcSJack F Vogel  *
2548758cc3dcSJack F Vogel  **********************************************************************/
2549758cc3dcSJack F Vogel static int
2550758cc3dcSJack F Vogel ixgbe_setup_interface(device_t dev, struct adapter *adapter)
2551758cc3dcSJack F Vogel {
2552758cc3dcSJack F Vogel 	struct ifnet   *ifp;
2553758cc3dcSJack F Vogel 
2554758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_setup_interface: begin");
2555758cc3dcSJack F Vogel 
2556758cc3dcSJack F Vogel 	ifp = adapter->ifp = if_alloc(IFT_ETHER);
2557758cc3dcSJack F Vogel 	if (ifp == NULL) {
2558758cc3dcSJack F Vogel 		device_printf(dev, "can not allocate ifnet structure\n");
2559758cc3dcSJack F Vogel 		return (-1);
2560758cc3dcSJack F Vogel 	}
2561758cc3dcSJack F Vogel 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
2562758cc3dcSJack F Vogel 	ifp->if_baudrate = IF_Gbps(10);
2563758cc3dcSJack F Vogel 	ifp->if_init = ixgbe_init;
2564758cc3dcSJack F Vogel 	ifp->if_softc = adapter;
2565758cc3dcSJack F Vogel 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
2566758cc3dcSJack F Vogel 	ifp->if_ioctl = ixgbe_ioctl;
2567758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036
2568758cc3dcSJack F Vogel 	if_setgetcounterfn(ifp, ixgbe_get_counter);
2569758cc3dcSJack F Vogel #endif
2570*6f37f232SEric Joyner #if __FreeBSD_version >= 1100045
2571*6f37f232SEric Joyner 	/* TSO parameters */
2572*6f37f232SEric Joyner 	ifp->if_hw_tsomax = 65518;
2573*6f37f232SEric Joyner 	ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER;
2574*6f37f232SEric Joyner 	ifp->if_hw_tsomaxsegsize = 2048;
2575*6f37f232SEric Joyner #endif
2576758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
2577758cc3dcSJack F Vogel 	ifp->if_transmit = ixgbe_mq_start;
2578758cc3dcSJack F Vogel 	ifp->if_qflush = ixgbe_qflush;
2579758cc3dcSJack F Vogel #else
2580758cc3dcSJack F Vogel 	ifp->if_start = ixgbe_start;
2581758cc3dcSJack F Vogel 	IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2);
2582758cc3dcSJack F Vogel 	ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2;
2583758cc3dcSJack F Vogel 	IFQ_SET_READY(&ifp->if_snd);
2584758cc3dcSJack F Vogel #endif
2585758cc3dcSJack F Vogel 
2586758cc3dcSJack F Vogel 	ether_ifattach(ifp, adapter->hw.mac.addr);
2587758cc3dcSJack F Vogel 
2588758cc3dcSJack F Vogel 	adapter->max_frame_size =
2589758cc3dcSJack F Vogel 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
2590758cc3dcSJack F Vogel 
2591758cc3dcSJack F Vogel 	/*
2592758cc3dcSJack F Vogel 	 * Tell the upper layer(s) we support long frames.
2593758cc3dcSJack F Vogel 	 */
2594758cc3dcSJack F Vogel 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
2595758cc3dcSJack F Vogel 
2596758cc3dcSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO | IFCAP_VLAN_HWCSUM;
2597758cc3dcSJack F Vogel 	ifp->if_capabilities |= IFCAP_JUMBO_MTU;
2598758cc3dcSJack F Vogel 	ifp->if_capabilities |= IFCAP_LRO;
2599758cc3dcSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
2600758cc3dcSJack F Vogel 			     |  IFCAP_VLAN_HWTSO
2601758cc3dcSJack F Vogel 			     |  IFCAP_VLAN_MTU
2602758cc3dcSJack F Vogel 			     |  IFCAP_HWSTATS;
2603758cc3dcSJack F Vogel 	ifp->if_capenable = ifp->if_capabilities;
2604758cc3dcSJack F Vogel 
2605758cc3dcSJack F Vogel 	/*
2606758cc3dcSJack F Vogel 	** Don't turn this on by default, if vlans are
2607758cc3dcSJack F Vogel 	** created on another pseudo device (eg. lagg)
2608758cc3dcSJack F Vogel 	** then vlan events are not passed thru, breaking
2609758cc3dcSJack F Vogel 	** operation, but with HW FILTER off it works. If
2610758cc3dcSJack F Vogel 	** using vlans directly on the ixgbe driver you can
2611758cc3dcSJack F Vogel 	** enable this and get full hardware tag filtering.
2612758cc3dcSJack F Vogel 	*/
2613758cc3dcSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
2614758cc3dcSJack F Vogel 
2615758cc3dcSJack F Vogel 	/*
2616758cc3dcSJack F Vogel 	 * Specify the media types supported by this adapter and register
2617758cc3dcSJack F Vogel 	 * callbacks to update media and link information
2618758cc3dcSJack F Vogel 	 */
2619758cc3dcSJack F Vogel 	ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change,
2620758cc3dcSJack F Vogel 		    ixgbe_media_status);
2621758cc3dcSJack F Vogel 
2622758cc3dcSJack F Vogel 	ixgbe_add_media_types(adapter);
2623758cc3dcSJack F Vogel 
2624758cc3dcSJack F Vogel 	/* Autoselect media by default */
2625758cc3dcSJack F Vogel 	ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
2626758cc3dcSJack F Vogel 
2627758cc3dcSJack F Vogel 	return (0);
2628758cc3dcSJack F Vogel }
2629758cc3dcSJack F Vogel 
2630758cc3dcSJack F Vogel static void
2631758cc3dcSJack F Vogel ixgbe_add_media_types(struct adapter *adapter)
2632758cc3dcSJack F Vogel {
2633758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
2634758cc3dcSJack F Vogel 	device_t dev = adapter->dev;
2635758cc3dcSJack F Vogel 	int layer;
2636758cc3dcSJack F Vogel 
2637758cc3dcSJack F Vogel 	layer = ixgbe_get_supported_physical_layer(hw);
2638758cc3dcSJack F Vogel 
2639758cc3dcSJack F Vogel 	/* Media types with matching FreeBSD media defines */
2640758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T)
2641758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2642758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T)
2643758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL);
2644758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX)
2645758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2646758cc3dcSJack F Vogel 
2647758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU ||
2648758cc3dcSJack F Vogel 	    layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA)
2649758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2650758cc3dcSJack F Vogel 
2651758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR)
2652758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2653758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR)
2654758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2655758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4)
2656758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
2657758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX)
2658758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
2659758cc3dcSJack F Vogel 
2660758cc3dcSJack F Vogel 	/*
2661758cc3dcSJack F Vogel 	** Other (no matching FreeBSD media type):
2662758cc3dcSJack F Vogel 	** To workaround this, we'll assign these completely
2663758cc3dcSJack F Vogel 	** inappropriate media types.
2664758cc3dcSJack F Vogel 	*/
2665758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) {
2666758cc3dcSJack F Vogel 		device_printf(dev, "Media supported: 10GbaseKR\n");
2667*6f37f232SEric Joyner 		device_printf(dev, "10GbaseKR mapped to 10GbaseSR\n");
2668*6f37f232SEric Joyner 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2669758cc3dcSJack F Vogel 	}
2670758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) {
2671758cc3dcSJack F Vogel 		device_printf(dev, "Media supported: 10GbaseKX4\n");
2672*6f37f232SEric Joyner 		device_printf(dev, "10GbaseKX4 mapped to 10GbaseCX4\n");
2673*6f37f232SEric Joyner 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
2674758cc3dcSJack F Vogel 	}
2675758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) {
2676758cc3dcSJack F Vogel 		device_printf(dev, "Media supported: 1000baseKX\n");
2677*6f37f232SEric Joyner 		device_printf(dev, "1000baseKX mapped to 1000baseCX\n");
2678*6f37f232SEric Joyner 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_CX, 0, NULL);
2679758cc3dcSJack F Vogel 	}
2680758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX) {
2681758cc3dcSJack F Vogel 		/* Someday, someone will care about you... */
2682758cc3dcSJack F Vogel 		device_printf(dev, "Media supported: 1000baseBX\n");
2683758cc3dcSJack F Vogel 	}
2684758cc3dcSJack F Vogel 
2685758cc3dcSJack F Vogel 	if (hw->device_id == IXGBE_DEV_ID_82598AT) {
2686758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media,
2687758cc3dcSJack F Vogel 		    IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
2688758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media,
2689758cc3dcSJack F Vogel 		    IFM_ETHER | IFM_1000_T, 0, NULL);
2690758cc3dcSJack F Vogel 	}
2691758cc3dcSJack F Vogel 
2692758cc3dcSJack F Vogel 	ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL);
2693758cc3dcSJack F Vogel }
2694758cc3dcSJack F Vogel 
2695758cc3dcSJack F Vogel static void
2696758cc3dcSJack F Vogel ixgbe_config_link(struct adapter *adapter)
2697758cc3dcSJack F Vogel {
2698758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
2699758cc3dcSJack F Vogel 	u32	autoneg, err = 0;
2700758cc3dcSJack F Vogel 	bool	sfp, negotiate;
2701758cc3dcSJack F Vogel 
2702758cc3dcSJack F Vogel 	sfp = ixgbe_is_sfp(hw);
2703758cc3dcSJack F Vogel 
2704758cc3dcSJack F Vogel 	if (sfp) {
2705758cc3dcSJack F Vogel 		if (hw->phy.multispeed_fiber) {
2706758cc3dcSJack F Vogel 			hw->mac.ops.setup_sfp(hw);
2707758cc3dcSJack F Vogel 			ixgbe_enable_tx_laser(hw);
2708758cc3dcSJack F Vogel 			taskqueue_enqueue(adapter->tq, &adapter->msf_task);
2709758cc3dcSJack F Vogel 		} else
2710758cc3dcSJack F Vogel 			taskqueue_enqueue(adapter->tq, &adapter->mod_task);
2711758cc3dcSJack F Vogel 	} else {
2712758cc3dcSJack F Vogel 		if (hw->mac.ops.check_link)
2713758cc3dcSJack F Vogel 			err = ixgbe_check_link(hw, &adapter->link_speed,
2714758cc3dcSJack F Vogel 			    &adapter->link_up, FALSE);
2715758cc3dcSJack F Vogel 		if (err)
2716758cc3dcSJack F Vogel 			goto out;
2717758cc3dcSJack F Vogel 		autoneg = hw->phy.autoneg_advertised;
2718758cc3dcSJack F Vogel 		if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
2719758cc3dcSJack F Vogel                 	err  = hw->mac.ops.get_link_capabilities(hw,
2720758cc3dcSJack F Vogel 			    &autoneg, &negotiate);
2721758cc3dcSJack F Vogel 		if (err)
2722758cc3dcSJack F Vogel 			goto out;
2723758cc3dcSJack F Vogel 		if (hw->mac.ops.setup_link)
2724758cc3dcSJack F Vogel                 	err = hw->mac.ops.setup_link(hw,
2725758cc3dcSJack F Vogel 			    autoneg, adapter->link_up);
2726758cc3dcSJack F Vogel 	}
2727758cc3dcSJack F Vogel out:
2728758cc3dcSJack F Vogel 	return;
2729758cc3dcSJack F Vogel }
2730758cc3dcSJack F Vogel 
2731758cc3dcSJack F Vogel 
2732758cc3dcSJack F Vogel /*********************************************************************
2733758cc3dcSJack F Vogel  *
2734758cc3dcSJack F Vogel  *  Enable transmit units.
2735758cc3dcSJack F Vogel  *
2736758cc3dcSJack F Vogel  **********************************************************************/
2737758cc3dcSJack F Vogel static void
2738758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(struct adapter *adapter)
2739758cc3dcSJack F Vogel {
2740758cc3dcSJack F Vogel 	struct tx_ring	*txr = adapter->tx_rings;
2741758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
2742758cc3dcSJack F Vogel 
2743758cc3dcSJack F Vogel 	/* Setup the Base and Length of the Tx Descriptor Ring */
2744758cc3dcSJack F Vogel 
2745758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, txr++) {
2746758cc3dcSJack F Vogel 		u64	tdba = txr->txdma.dma_paddr;
2747758cc3dcSJack F Vogel 		u32	txctrl = 0;
2748758cc3dcSJack F Vogel 
2749758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i),
2750758cc3dcSJack F Vogel 		       (tdba & 0x00000000ffffffffULL));
2751758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (tdba >> 32));
2752758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i),
2753758cc3dcSJack F Vogel 		    adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc));
2754758cc3dcSJack F Vogel 
2755758cc3dcSJack F Vogel 		/* Setup the HW Tx Head and Tail descriptor pointers */
2756758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0);
2757758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0);
2758758cc3dcSJack F Vogel 
2759758cc3dcSJack F Vogel 		/* Cache the tail address */
2760758cc3dcSJack F Vogel 		txr->tail = IXGBE_TDT(txr->me);
2761758cc3dcSJack F Vogel 
2762758cc3dcSJack F Vogel 		/* Set the processing limit */
2763758cc3dcSJack F Vogel 		txr->process_limit = ixgbe_tx_process_limit;
2764758cc3dcSJack F Vogel 
2765758cc3dcSJack F Vogel 		/* Disable Head Writeback */
2766758cc3dcSJack F Vogel 		switch (hw->mac.type) {
2767758cc3dcSJack F Vogel 		case ixgbe_mac_82598EB:
2768758cc3dcSJack F Vogel 			txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i));
2769758cc3dcSJack F Vogel 			break;
2770758cc3dcSJack F Vogel 		case ixgbe_mac_82599EB:
2771758cc3dcSJack F Vogel 		case ixgbe_mac_X540:
2772758cc3dcSJack F Vogel 		default:
2773758cc3dcSJack F Vogel 			txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i));
2774758cc3dcSJack F Vogel 			break;
2775758cc3dcSJack F Vogel                 }
2776758cc3dcSJack F Vogel 		txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN;
2777758cc3dcSJack F Vogel 		switch (hw->mac.type) {
2778758cc3dcSJack F Vogel 		case ixgbe_mac_82598EB:
2779758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl);
2780758cc3dcSJack F Vogel 			break;
2781758cc3dcSJack F Vogel 		case ixgbe_mac_82599EB:
2782758cc3dcSJack F Vogel 		case ixgbe_mac_X540:
2783758cc3dcSJack F Vogel 		default:
2784758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(i), txctrl);
2785758cc3dcSJack F Vogel 			break;
2786758cc3dcSJack F Vogel 		}
2787758cc3dcSJack F Vogel 
2788758cc3dcSJack F Vogel 	}
2789758cc3dcSJack F Vogel 
2790758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
2791758cc3dcSJack F Vogel 		u32 dmatxctl, rttdcs;
2792758cc3dcSJack F Vogel 		dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
2793758cc3dcSJack F Vogel 		dmatxctl |= IXGBE_DMATXCTL_TE;
2794758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl);
2795758cc3dcSJack F Vogel 		/* Disable arbiter to set MTQC */
2796758cc3dcSJack F Vogel 		rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
2797758cc3dcSJack F Vogel 		rttdcs |= IXGBE_RTTDCS_ARBDIS;
2798758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
2799758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB);
2800758cc3dcSJack F Vogel 		rttdcs &= ~IXGBE_RTTDCS_ARBDIS;
2801758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
2802758cc3dcSJack F Vogel 	}
2803758cc3dcSJack F Vogel 
2804758cc3dcSJack F Vogel 	return;
2805758cc3dcSJack F Vogel }
2806758cc3dcSJack F Vogel 
2807758cc3dcSJack F Vogel static void
2808758cc3dcSJack F Vogel ixgbe_initialise_rss_mapping(struct adapter *adapter)
2809758cc3dcSJack F Vogel {
2810758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
2811758cc3dcSJack F Vogel 	uint32_t reta;
2812*6f37f232SEric Joyner 	int i, j, queue_id, table_size;
2813*6f37f232SEric Joyner 	int index_mult;
2814758cc3dcSJack F Vogel 	uint32_t rss_key[10];
2815758cc3dcSJack F Vogel 	uint32_t mrqc;
2816758cc3dcSJack F Vogel #ifdef	RSS
2817758cc3dcSJack F Vogel 	uint32_t rss_hash_config;
2818758cc3dcSJack F Vogel #endif
2819758cc3dcSJack F Vogel 
2820758cc3dcSJack F Vogel 	/* Setup RSS */
2821758cc3dcSJack F Vogel 	reta = 0;
2822758cc3dcSJack F Vogel 
2823758cc3dcSJack F Vogel #ifdef	RSS
2824758cc3dcSJack F Vogel 	/* Fetch the configured RSS key */
2825758cc3dcSJack F Vogel 	rss_getkey((uint8_t *) &rss_key);
2826758cc3dcSJack F Vogel #else
2827758cc3dcSJack F Vogel 	/* set up random bits */
2828758cc3dcSJack F Vogel 	arc4rand(&rss_key, sizeof(rss_key), 0);
2829758cc3dcSJack F Vogel #endif
2830758cc3dcSJack F Vogel 
2831*6f37f232SEric Joyner 	/* Set multiplier for RETA setup and table size based on MAC */
2832*6f37f232SEric Joyner 	index_mult = 0x1;
2833*6f37f232SEric Joyner 	table_size = 128;
2834*6f37f232SEric Joyner 	switch (adapter->hw.mac.type) {
2835*6f37f232SEric Joyner 	case ixgbe_mac_82598EB:
2836*6f37f232SEric Joyner 		index_mult = 0x11;
2837*6f37f232SEric Joyner 		break;
2838*6f37f232SEric Joyner 	case ixgbe_mac_X550:
2839*6f37f232SEric Joyner 	case ixgbe_mac_X550EM_x:
2840*6f37f232SEric Joyner 		table_size = 512;
2841*6f37f232SEric Joyner 		break;
2842*6f37f232SEric Joyner 	default:
2843*6f37f232SEric Joyner 		break;
2844*6f37f232SEric Joyner 	}
2845*6f37f232SEric Joyner 
2846758cc3dcSJack F Vogel 	/* Set up the redirection table */
2847*6f37f232SEric Joyner 	for (i = 0, j = 0; i < table_size; i++, j++) {
2848758cc3dcSJack F Vogel 		if (j == adapter->num_queues) j = 0;
2849758cc3dcSJack F Vogel #ifdef	RSS
2850758cc3dcSJack F Vogel 		/*
2851758cc3dcSJack F Vogel 		 * Fetch the RSS bucket id for the given indirection entry.
2852758cc3dcSJack F Vogel 		 * Cap it at the number of configured buckets (which is
2853758cc3dcSJack F Vogel 		 * num_queues.)
2854758cc3dcSJack F Vogel 		 */
2855758cc3dcSJack F Vogel 		queue_id = rss_get_indirection_to_bucket(i);
2856758cc3dcSJack F Vogel 		queue_id = queue_id % adapter->num_queues;
2857758cc3dcSJack F Vogel #else
2858*6f37f232SEric Joyner 		queue_id = (j * index_mult);
2859758cc3dcSJack F Vogel #endif
2860758cc3dcSJack F Vogel 		/*
2861758cc3dcSJack F Vogel 		 * The low 8 bits are for hash value (n+0);
2862758cc3dcSJack F Vogel 		 * The next 8 bits are for hash value (n+1), etc.
2863758cc3dcSJack F Vogel 		 */
2864758cc3dcSJack F Vogel 		reta = reta >> 8;
2865758cc3dcSJack F Vogel 		reta = reta | ( ((uint32_t) queue_id) << 24);
2866758cc3dcSJack F Vogel 		if ((i & 3) == 3) {
2867*6f37f232SEric Joyner 			if (i < 128)
2868758cc3dcSJack F Vogel 				IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
2869*6f37f232SEric Joyner 			else
2870*6f37f232SEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), reta);
2871758cc3dcSJack F Vogel 			reta = 0;
2872758cc3dcSJack F Vogel 		}
2873758cc3dcSJack F Vogel 	}
2874758cc3dcSJack F Vogel 
2875758cc3dcSJack F Vogel 	/* Now fill our hash function seeds */
2876758cc3dcSJack F Vogel 	for (int i = 0; i < 10; i++)
2877758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]);
2878758cc3dcSJack F Vogel 
2879758cc3dcSJack F Vogel 	/* Perform hash on these packet types */
2880758cc3dcSJack F Vogel #ifdef	RSS
2881758cc3dcSJack F Vogel 	mrqc = IXGBE_MRQC_RSSEN;
2882758cc3dcSJack F Vogel 	rss_hash_config = rss_gethashconfig();
2883758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
2884758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4;
2885758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
2886758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP;
2887758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
2888758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6;
2889758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
2890758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
2891758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
2892758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX;
2893758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX)
2894758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP;
2895758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
2896758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP;
2897758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX)
2898758cc3dcSJack F Vogel 		device_printf(adapter->dev,
2899758cc3dcSJack F Vogel 		    "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, "
2900758cc3dcSJack F Vogel 		    "but not supported\n", __func__);
2901758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
2902758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
2903758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX)
2904758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
2905758cc3dcSJack F Vogel #else
2906758cc3dcSJack F Vogel 	/*
2907758cc3dcSJack F Vogel 	 * Disable UDP - IP fragments aren't currently being handled
2908758cc3dcSJack F Vogel 	 * and so we end up with a mix of 2-tuple and 4-tuple
2909758cc3dcSJack F Vogel 	 * traffic.
2910758cc3dcSJack F Vogel 	 */
2911758cc3dcSJack F Vogel 	mrqc = IXGBE_MRQC_RSSEN
2912758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV4
2913758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
2914758cc3dcSJack F Vogel #if 0
2915758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
2916758cc3dcSJack F Vogel #endif
2917758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP
2918758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV6_EX
2919758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV6
2920758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
2921758cc3dcSJack F Vogel #if 0
2922758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV6_UDP
2923758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP
2924758cc3dcSJack F Vogel #endif
2925758cc3dcSJack F Vogel 	;
2926758cc3dcSJack F Vogel #endif /* RSS */
2927758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
2928758cc3dcSJack F Vogel }
2929758cc3dcSJack F Vogel 
2930758cc3dcSJack F Vogel 
2931758cc3dcSJack F Vogel /*********************************************************************
2932758cc3dcSJack F Vogel  *
2933758cc3dcSJack F Vogel  *  Setup receive registers and features.
2934758cc3dcSJack F Vogel  *
2935758cc3dcSJack F Vogel  **********************************************************************/
2936758cc3dcSJack F Vogel #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2
2937758cc3dcSJack F Vogel 
2938758cc3dcSJack F Vogel #define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1)
2939758cc3dcSJack F Vogel 
2940758cc3dcSJack F Vogel static void
2941758cc3dcSJack F Vogel ixgbe_initialize_receive_units(struct adapter *adapter)
2942758cc3dcSJack F Vogel {
2943758cc3dcSJack F Vogel 	struct	rx_ring	*rxr = adapter->rx_rings;
2944758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
2945758cc3dcSJack F Vogel 	struct ifnet   *ifp = adapter->ifp;
2946758cc3dcSJack F Vogel 	u32		bufsz, fctrl, srrctl, rxcsum;
2947758cc3dcSJack F Vogel 	u32		hlreg;
2948758cc3dcSJack F Vogel 
2949758cc3dcSJack F Vogel 
2950758cc3dcSJack F Vogel 	/*
2951758cc3dcSJack F Vogel 	 * Make sure receives are disabled while
2952758cc3dcSJack F Vogel 	 * setting up the descriptor ring
2953758cc3dcSJack F Vogel 	 */
2954758cc3dcSJack F Vogel 	ixgbe_disable_rx(hw);
2955758cc3dcSJack F Vogel 
2956758cc3dcSJack F Vogel 	/* Enable broadcasts */
2957758cc3dcSJack F Vogel 	fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
2958758cc3dcSJack F Vogel 	fctrl |= IXGBE_FCTRL_BAM;
2959*6f37f232SEric Joyner 	if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
2960758cc3dcSJack F Vogel 		fctrl |= IXGBE_FCTRL_DPF;
2961758cc3dcSJack F Vogel 		fctrl |= IXGBE_FCTRL_PMCF;
2962*6f37f232SEric Joyner 	}
2963758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
2964758cc3dcSJack F Vogel 
2965758cc3dcSJack F Vogel 	/* Set for Jumbo Frames? */
2966758cc3dcSJack F Vogel 	hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0);
2967758cc3dcSJack F Vogel 	if (ifp->if_mtu > ETHERMTU)
2968758cc3dcSJack F Vogel 		hlreg |= IXGBE_HLREG0_JUMBOEN;
2969758cc3dcSJack F Vogel 	else
2970758cc3dcSJack F Vogel 		hlreg &= ~IXGBE_HLREG0_JUMBOEN;
2971758cc3dcSJack F Vogel #ifdef DEV_NETMAP
2972758cc3dcSJack F Vogel 	/* crcstrip is conditional in netmap (in RDRXCTL too ?) */
2973758cc3dcSJack F Vogel 	if (ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip)
2974758cc3dcSJack F Vogel 		hlreg &= ~IXGBE_HLREG0_RXCRCSTRP;
2975758cc3dcSJack F Vogel 	else
2976758cc3dcSJack F Vogel 		hlreg |= IXGBE_HLREG0_RXCRCSTRP;
2977758cc3dcSJack F Vogel #endif /* DEV_NETMAP */
2978758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg);
2979758cc3dcSJack F Vogel 
2980758cc3dcSJack F Vogel 	bufsz = (adapter->rx_mbuf_sz +
2981758cc3dcSJack F Vogel 	    BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
2982758cc3dcSJack F Vogel 
2983758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, rxr++) {
2984758cc3dcSJack F Vogel 		u64 rdba = rxr->rxdma.dma_paddr;
2985758cc3dcSJack F Vogel 
2986758cc3dcSJack F Vogel 		/* Setup the Base and Length of the Rx Descriptor Ring */
2987758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i),
2988758cc3dcSJack F Vogel 			       (rdba & 0x00000000ffffffffULL));
2989758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32));
2990758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i),
2991758cc3dcSJack F Vogel 		    adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc));
2992758cc3dcSJack F Vogel 
2993758cc3dcSJack F Vogel 		/* Set up the SRRCTL register */
2994758cc3dcSJack F Vogel 		srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i));
2995758cc3dcSJack F Vogel 		srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
2996758cc3dcSJack F Vogel 		srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
2997758cc3dcSJack F Vogel 		srrctl |= bufsz;
2998758cc3dcSJack F Vogel 		srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
2999758cc3dcSJack F Vogel 
3000758cc3dcSJack F Vogel 		/*
3001758cc3dcSJack F Vogel 		 * Set DROP_EN iff we have no flow control and >1 queue.
3002758cc3dcSJack F Vogel 		 * Note that srrctl was cleared shortly before during reset,
3003758cc3dcSJack F Vogel 		 * so we do not need to clear the bit, but do it just in case
3004758cc3dcSJack F Vogel 		 * this code is moved elsewhere.
3005758cc3dcSJack F Vogel 		 */
3006758cc3dcSJack F Vogel 		if (adapter->num_queues > 1 &&
3007758cc3dcSJack F Vogel 		    adapter->hw.fc.requested_mode == ixgbe_fc_none) {
3008758cc3dcSJack F Vogel 			srrctl |= IXGBE_SRRCTL_DROP_EN;
3009758cc3dcSJack F Vogel 		} else {
3010758cc3dcSJack F Vogel 			srrctl &= ~IXGBE_SRRCTL_DROP_EN;
3011758cc3dcSJack F Vogel 		}
3012758cc3dcSJack F Vogel 
3013758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl);
3014758cc3dcSJack F Vogel 
3015758cc3dcSJack F Vogel 		/* Setup the HW Rx Head and Tail Descriptor Pointers */
3016758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0);
3017758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0);
3018758cc3dcSJack F Vogel 
3019758cc3dcSJack F Vogel 		/* Set the processing limit */
3020758cc3dcSJack F Vogel 		rxr->process_limit = ixgbe_rx_process_limit;
3021758cc3dcSJack F Vogel 
3022758cc3dcSJack F Vogel 		/* Set the driver rx tail address */
3023758cc3dcSJack F Vogel 		rxr->tail =  IXGBE_RDT(rxr->me);
3024758cc3dcSJack F Vogel 	}
3025758cc3dcSJack F Vogel 
3026758cc3dcSJack F Vogel 	if (adapter->hw.mac.type != ixgbe_mac_82598EB) {
3027758cc3dcSJack F Vogel 		u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
3028758cc3dcSJack F Vogel 			      IXGBE_PSRTYPE_UDPHDR |
3029758cc3dcSJack F Vogel 			      IXGBE_PSRTYPE_IPV4HDR |
3030758cc3dcSJack F Vogel 			      IXGBE_PSRTYPE_IPV6HDR;
3031758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype);
3032758cc3dcSJack F Vogel 	}
3033758cc3dcSJack F Vogel 
3034758cc3dcSJack F Vogel 	rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
3035758cc3dcSJack F Vogel 
3036758cc3dcSJack F Vogel 	ixgbe_initialise_rss_mapping(adapter);
3037758cc3dcSJack F Vogel 
3038758cc3dcSJack F Vogel 	if (adapter->num_queues > 1) {
3039758cc3dcSJack F Vogel 		/* RSS and RX IPP Checksum are mutually exclusive */
3040758cc3dcSJack F Vogel 		rxcsum |= IXGBE_RXCSUM_PCSD;
3041758cc3dcSJack F Vogel 	}
3042758cc3dcSJack F Vogel 
3043758cc3dcSJack F Vogel 	if (ifp->if_capenable & IFCAP_RXCSUM)
3044758cc3dcSJack F Vogel 		rxcsum |= IXGBE_RXCSUM_PCSD;
3045758cc3dcSJack F Vogel 
3046758cc3dcSJack F Vogel 	if (!(rxcsum & IXGBE_RXCSUM_PCSD))
3047758cc3dcSJack F Vogel 		rxcsum |= IXGBE_RXCSUM_IPPCSE;
3048758cc3dcSJack F Vogel 
3049758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
3050758cc3dcSJack F Vogel 
3051758cc3dcSJack F Vogel 	return;
3052758cc3dcSJack F Vogel }
3053758cc3dcSJack F Vogel 
3054758cc3dcSJack F Vogel 
3055758cc3dcSJack F Vogel /*
3056758cc3dcSJack F Vogel ** This routine is run via an vlan config EVENT,
3057758cc3dcSJack F Vogel ** it enables us to use the HW Filter table since
3058758cc3dcSJack F Vogel ** we can get the vlan id. This just creates the
3059758cc3dcSJack F Vogel ** entry in the soft version of the VFTA, init will
3060758cc3dcSJack F Vogel ** repopulate the real table.
3061758cc3dcSJack F Vogel */
3062758cc3dcSJack F Vogel static void
3063758cc3dcSJack F Vogel ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
3064758cc3dcSJack F Vogel {
3065758cc3dcSJack F Vogel 	struct adapter	*adapter = ifp->if_softc;
3066758cc3dcSJack F Vogel 	u16		index, bit;
3067758cc3dcSJack F Vogel 
3068758cc3dcSJack F Vogel 	if (ifp->if_softc !=  arg)   /* Not our event */
3069758cc3dcSJack F Vogel 		return;
3070758cc3dcSJack F Vogel 
3071758cc3dcSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
3072758cc3dcSJack F Vogel 		return;
3073758cc3dcSJack F Vogel 
3074758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
3075758cc3dcSJack F Vogel 	index = (vtag >> 5) & 0x7F;
3076758cc3dcSJack F Vogel 	bit = vtag & 0x1F;
3077758cc3dcSJack F Vogel 	adapter->shadow_vfta[index] |= (1 << bit);
3078758cc3dcSJack F Vogel 	++adapter->num_vlans;
3079758cc3dcSJack F Vogel 	ixgbe_setup_vlan_hw_support(adapter);
3080758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
3081758cc3dcSJack F Vogel }
3082758cc3dcSJack F Vogel 
3083758cc3dcSJack F Vogel /*
3084758cc3dcSJack F Vogel ** This routine is run via an vlan
3085758cc3dcSJack F Vogel ** unconfig EVENT, remove our entry
3086758cc3dcSJack F Vogel ** in the soft vfta.
3087758cc3dcSJack F Vogel */
3088758cc3dcSJack F Vogel static void
3089758cc3dcSJack F Vogel ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
3090758cc3dcSJack F Vogel {
3091758cc3dcSJack F Vogel 	struct adapter	*adapter = ifp->if_softc;
3092758cc3dcSJack F Vogel 	u16		index, bit;
3093758cc3dcSJack F Vogel 
3094758cc3dcSJack F Vogel 	if (ifp->if_softc !=  arg)
3095758cc3dcSJack F Vogel 		return;
3096758cc3dcSJack F Vogel 
3097758cc3dcSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
3098758cc3dcSJack F Vogel 		return;
3099758cc3dcSJack F Vogel 
3100758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
3101758cc3dcSJack F Vogel 	index = (vtag >> 5) & 0x7F;
3102758cc3dcSJack F Vogel 	bit = vtag & 0x1F;
3103758cc3dcSJack F Vogel 	adapter->shadow_vfta[index] &= ~(1 << bit);
3104758cc3dcSJack F Vogel 	--adapter->num_vlans;
3105758cc3dcSJack F Vogel 	/* Re-init to load the changes */
3106758cc3dcSJack F Vogel 	ixgbe_setup_vlan_hw_support(adapter);
3107758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
3108758cc3dcSJack F Vogel }
3109758cc3dcSJack F Vogel 
3110758cc3dcSJack F Vogel static void
3111758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(struct adapter *adapter)
3112758cc3dcSJack F Vogel {
3113758cc3dcSJack F Vogel 	struct ifnet 	*ifp = adapter->ifp;
3114758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
3115758cc3dcSJack F Vogel 	struct rx_ring	*rxr;
3116758cc3dcSJack F Vogel 	u32		ctrl;
3117758cc3dcSJack F Vogel 
3118758cc3dcSJack F Vogel 
3119758cc3dcSJack F Vogel 	/*
3120758cc3dcSJack F Vogel 	** We get here thru init_locked, meaning
3121758cc3dcSJack F Vogel 	** a soft reset, this has already cleared
3122758cc3dcSJack F Vogel 	** the VFTA and other state, so if there
3123758cc3dcSJack F Vogel 	** have been no vlan's registered do nothing.
3124758cc3dcSJack F Vogel 	*/
3125758cc3dcSJack F Vogel 	if (adapter->num_vlans == 0)
3126758cc3dcSJack F Vogel 		return;
3127758cc3dcSJack F Vogel 
3128758cc3dcSJack F Vogel 	/* Setup the queues for vlans */
3129758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++) {
3130758cc3dcSJack F Vogel 		rxr = &adapter->rx_rings[i];
3131758cc3dcSJack F Vogel 		/* On 82599 the VLAN enable is per/queue in RXDCTL */
3132758cc3dcSJack F Vogel 		if (hw->mac.type != ixgbe_mac_82598EB) {
3133758cc3dcSJack F Vogel 			ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
3134758cc3dcSJack F Vogel 			ctrl |= IXGBE_RXDCTL_VME;
3135758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), ctrl);
3136758cc3dcSJack F Vogel 		}
3137758cc3dcSJack F Vogel 		rxr->vtag_strip = TRUE;
3138758cc3dcSJack F Vogel 	}
3139758cc3dcSJack F Vogel 
3140758cc3dcSJack F Vogel 	if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0)
3141758cc3dcSJack F Vogel 		return;
3142758cc3dcSJack F Vogel 	/*
3143758cc3dcSJack F Vogel 	** A soft reset zero's out the VFTA, so
3144758cc3dcSJack F Vogel 	** we need to repopulate it now.
3145758cc3dcSJack F Vogel 	*/
3146758cc3dcSJack F Vogel 	for (int i = 0; i < IXGBE_VFTA_SIZE; i++)
3147758cc3dcSJack F Vogel 		if (adapter->shadow_vfta[i] != 0)
3148758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_VFTA(i),
3149758cc3dcSJack F Vogel 			    adapter->shadow_vfta[i]);
3150758cc3dcSJack F Vogel 
3151758cc3dcSJack F Vogel 	ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
3152758cc3dcSJack F Vogel 	/* Enable the Filter Table if enabled */
3153758cc3dcSJack F Vogel 	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) {
3154758cc3dcSJack F Vogel 		ctrl &= ~IXGBE_VLNCTRL_CFIEN;
3155758cc3dcSJack F Vogel 		ctrl |= IXGBE_VLNCTRL_VFE;
3156758cc3dcSJack F Vogel 	}
3157758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82598EB)
3158758cc3dcSJack F Vogel 		ctrl |= IXGBE_VLNCTRL_VME;
3159758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl);
3160758cc3dcSJack F Vogel }
3161758cc3dcSJack F Vogel 
3162758cc3dcSJack F Vogel static void
3163758cc3dcSJack F Vogel ixgbe_enable_intr(struct adapter *adapter)
3164758cc3dcSJack F Vogel {
3165758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
3166758cc3dcSJack F Vogel 	struct ix_queue	*que = adapter->queues;
3167758cc3dcSJack F Vogel 	u32		mask, fwsm;
3168758cc3dcSJack F Vogel 
3169758cc3dcSJack F Vogel 	mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
3170758cc3dcSJack F Vogel 	/* Enable Fan Failure detection */
3171758cc3dcSJack F Vogel 	if (hw->device_id == IXGBE_DEV_ID_82598AT)
3172*6f37f232SEric Joyner 		    mask |= IXGBE_EIMS_GPI_SDP1;
3173758cc3dcSJack F Vogel 
3174758cc3dcSJack F Vogel 	switch (adapter->hw.mac.type) {
3175758cc3dcSJack F Vogel 		case ixgbe_mac_82599EB:
3176758cc3dcSJack F Vogel 			mask |= IXGBE_EIMS_ECC;
3177758cc3dcSJack F Vogel 			/* Temperature sensor on some adapters */
3178*6f37f232SEric Joyner 			mask |= IXGBE_EIMS_GPI_SDP0;
3179758cc3dcSJack F Vogel 			/* SFP+ (RX_LOS_N & MOD_ABS_N) */
3180*6f37f232SEric Joyner 			mask |= IXGBE_EIMS_GPI_SDP1;
3181*6f37f232SEric Joyner 			mask |= IXGBE_EIMS_GPI_SDP2;
3182758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
3183758cc3dcSJack F Vogel 			mask |= IXGBE_EIMS_FLOW_DIR;
3184758cc3dcSJack F Vogel #endif
3185758cc3dcSJack F Vogel 			break;
3186758cc3dcSJack F Vogel 		case ixgbe_mac_X540:
3187758cc3dcSJack F Vogel 			/* Detect if Thermal Sensor is enabled */
3188758cc3dcSJack F Vogel 			fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
3189758cc3dcSJack F Vogel 			if (fwsm & IXGBE_FWSM_TS_ENABLED)
3190758cc3dcSJack F Vogel 				mask |= IXGBE_EIMS_TS;
3191*6f37f232SEric Joyner 			mask |= IXGBE_EIMS_ECC;
3192*6f37f232SEric Joyner #ifdef IXGBE_FDIR
3193*6f37f232SEric Joyner 			mask |= IXGBE_EIMS_FLOW_DIR;
3194*6f37f232SEric Joyner #endif
3195*6f37f232SEric Joyner 			break;
3196*6f37f232SEric Joyner 		case ixgbe_mac_X550:
3197*6f37f232SEric Joyner 		case ixgbe_mac_X550EM_x:
3198*6f37f232SEric Joyner 			/* MAC thermal sensor is automatically enabled */
3199*6f37f232SEric Joyner 			mask |= IXGBE_EIMS_TS;
3200*6f37f232SEric Joyner 			/* Some devices use SDP0 for important information */
3201*6f37f232SEric Joyner 			if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
3202*6f37f232SEric Joyner 			    hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T)
3203758cc3dcSJack F Vogel 				mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw);
3204758cc3dcSJack F Vogel 			mask |= IXGBE_EIMS_ECC;
3205758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
3206758cc3dcSJack F Vogel 			mask |= IXGBE_EIMS_FLOW_DIR;
3207758cc3dcSJack F Vogel #endif
3208758cc3dcSJack F Vogel 		/* falls through */
3209758cc3dcSJack F Vogel 		default:
3210758cc3dcSJack F Vogel 			break;
3211758cc3dcSJack F Vogel 	}
3212758cc3dcSJack F Vogel 
3213758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask);
3214758cc3dcSJack F Vogel 
3215*6f37f232SEric Joyner 	/* With MSI-X we use auto clear */
3216758cc3dcSJack F Vogel 	if (adapter->msix_mem) {
3217758cc3dcSJack F Vogel 		mask = IXGBE_EIMS_ENABLE_MASK;
3218758cc3dcSJack F Vogel 		/* Don't autoclear Link */
3219758cc3dcSJack F Vogel 		mask &= ~IXGBE_EIMS_OTHER;
3220758cc3dcSJack F Vogel 		mask &= ~IXGBE_EIMS_LSC;
3221758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask);
3222758cc3dcSJack F Vogel 	}
3223758cc3dcSJack F Vogel 
3224758cc3dcSJack F Vogel 	/*
3225758cc3dcSJack F Vogel 	** Now enable all queues, this is done separately to
3226758cc3dcSJack F Vogel 	** allow for handling the extended (beyond 32) MSIX
3227758cc3dcSJack F Vogel 	** vectors that can be used by 82599
3228758cc3dcSJack F Vogel 	*/
3229758cc3dcSJack F Vogel         for (int i = 0; i < adapter->num_queues; i++, que++)
3230758cc3dcSJack F Vogel                 ixgbe_enable_queue(adapter, que->msix);
3231758cc3dcSJack F Vogel 
3232758cc3dcSJack F Vogel 	IXGBE_WRITE_FLUSH(hw);
3233758cc3dcSJack F Vogel 
3234758cc3dcSJack F Vogel 	return;
3235758cc3dcSJack F Vogel }
3236758cc3dcSJack F Vogel 
3237758cc3dcSJack F Vogel static void
3238758cc3dcSJack F Vogel ixgbe_disable_intr(struct adapter *adapter)
3239758cc3dcSJack F Vogel {
3240758cc3dcSJack F Vogel 	if (adapter->msix_mem)
3241758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, 0);
3242758cc3dcSJack F Vogel 	if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
3243758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
3244758cc3dcSJack F Vogel 	} else {
3245758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000);
3246758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0);
3247758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
3248758cc3dcSJack F Vogel 	}
3249758cc3dcSJack F Vogel 	IXGBE_WRITE_FLUSH(&adapter->hw);
3250758cc3dcSJack F Vogel 	return;
3251758cc3dcSJack F Vogel }
3252758cc3dcSJack F Vogel 
3253758cc3dcSJack F Vogel /*
3254758cc3dcSJack F Vogel ** Get the width and transaction speed of
3255758cc3dcSJack F Vogel ** the slot this adapter is plugged into.
3256758cc3dcSJack F Vogel */
3257758cc3dcSJack F Vogel static void
3258758cc3dcSJack F Vogel ixgbe_get_slot_info(struct ixgbe_hw *hw)
3259758cc3dcSJack F Vogel {
3260758cc3dcSJack F Vogel 	device_t		dev = ((struct ixgbe_osdep *)hw->back)->dev;
3261758cc3dcSJack F Vogel 	struct ixgbe_mac_info	*mac = &hw->mac;
3262758cc3dcSJack F Vogel 	u16			link;
3263758cc3dcSJack F Vogel 	u32			offset;
3264758cc3dcSJack F Vogel 
3265758cc3dcSJack F Vogel 	/* For most devices simply call the shared code routine */
3266758cc3dcSJack F Vogel 	if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) {
3267758cc3dcSJack F Vogel 		ixgbe_get_bus_info(hw);
3268758cc3dcSJack F Vogel 		/* These devices don't use PCI-E */
3269*6f37f232SEric Joyner 		switch (hw->mac.type) {
3270*6f37f232SEric Joyner 		case ixgbe_mac_X550EM_x:
3271758cc3dcSJack F Vogel 			return;
3272*6f37f232SEric Joyner 		default:
3273758cc3dcSJack F Vogel 			goto display;
3274758cc3dcSJack F Vogel 		}
3275*6f37f232SEric Joyner 	}
3276758cc3dcSJack F Vogel 
3277758cc3dcSJack F Vogel 	/*
3278758cc3dcSJack F Vogel 	** For the Quad port adapter we need to parse back
3279758cc3dcSJack F Vogel 	** up the PCI tree to find the speed of the expansion
3280758cc3dcSJack F Vogel 	** slot into which this adapter is plugged. A bit more work.
3281758cc3dcSJack F Vogel 	*/
3282758cc3dcSJack F Vogel 	dev = device_get_parent(device_get_parent(dev));
3283758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG
3284758cc3dcSJack F Vogel 	device_printf(dev, "parent pcib = %x,%x,%x\n",
3285758cc3dcSJack F Vogel 	    pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev));
3286758cc3dcSJack F Vogel #endif
3287758cc3dcSJack F Vogel 	dev = device_get_parent(device_get_parent(dev));
3288758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG
3289758cc3dcSJack F Vogel 	device_printf(dev, "slot pcib = %x,%x,%x\n",
3290758cc3dcSJack F Vogel 	    pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev));
3291758cc3dcSJack F Vogel #endif
3292758cc3dcSJack F Vogel 	/* Now get the PCI Express Capabilities offset */
3293758cc3dcSJack F Vogel 	pci_find_cap(dev, PCIY_EXPRESS, &offset);
3294758cc3dcSJack F Vogel 	/* ...and read the Link Status Register */
3295758cc3dcSJack F Vogel 	link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
3296758cc3dcSJack F Vogel 	switch (link & IXGBE_PCI_LINK_WIDTH) {
3297758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_WIDTH_1:
3298758cc3dcSJack F Vogel 		hw->bus.width = ixgbe_bus_width_pcie_x1;
3299758cc3dcSJack F Vogel 		break;
3300758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_WIDTH_2:
3301758cc3dcSJack F Vogel 		hw->bus.width = ixgbe_bus_width_pcie_x2;
3302758cc3dcSJack F Vogel 		break;
3303758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_WIDTH_4:
3304758cc3dcSJack F Vogel 		hw->bus.width = ixgbe_bus_width_pcie_x4;
3305758cc3dcSJack F Vogel 		break;
3306758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_WIDTH_8:
3307758cc3dcSJack F Vogel 		hw->bus.width = ixgbe_bus_width_pcie_x8;
3308758cc3dcSJack F Vogel 		break;
3309758cc3dcSJack F Vogel 	default:
3310758cc3dcSJack F Vogel 		hw->bus.width = ixgbe_bus_width_unknown;
3311758cc3dcSJack F Vogel 		break;
3312758cc3dcSJack F Vogel 	}
3313758cc3dcSJack F Vogel 
3314758cc3dcSJack F Vogel 	switch (link & IXGBE_PCI_LINK_SPEED) {
3315758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_SPEED_2500:
3316758cc3dcSJack F Vogel 		hw->bus.speed = ixgbe_bus_speed_2500;
3317758cc3dcSJack F Vogel 		break;
3318758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_SPEED_5000:
3319758cc3dcSJack F Vogel 		hw->bus.speed = ixgbe_bus_speed_5000;
3320758cc3dcSJack F Vogel 		break;
3321758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_SPEED_8000:
3322758cc3dcSJack F Vogel 		hw->bus.speed = ixgbe_bus_speed_8000;
3323758cc3dcSJack F Vogel 		break;
3324758cc3dcSJack F Vogel 	default:
3325758cc3dcSJack F Vogel 		hw->bus.speed = ixgbe_bus_speed_unknown;
3326758cc3dcSJack F Vogel 		break;
3327758cc3dcSJack F Vogel 	}
3328758cc3dcSJack F Vogel 
3329758cc3dcSJack F Vogel 	mac->ops.set_lan_id(hw);
3330758cc3dcSJack F Vogel 
3331758cc3dcSJack F Vogel display:
3332758cc3dcSJack F Vogel 	device_printf(dev,"PCI Express Bus: Speed %s %s\n",
3333758cc3dcSJack F Vogel 	    ((hw->bus.speed == ixgbe_bus_speed_8000) ? "8.0GT/s":
3334758cc3dcSJack F Vogel 	    (hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0GT/s":
3335758cc3dcSJack F Vogel 	    (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5GT/s":"Unknown"),
3336758cc3dcSJack F Vogel 	    (hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
3337758cc3dcSJack F Vogel 	    (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" :
3338758cc3dcSJack F Vogel 	    (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" :
3339758cc3dcSJack F Vogel 	    ("Unknown"));
3340758cc3dcSJack F Vogel 
3341758cc3dcSJack F Vogel 	if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) &&
3342758cc3dcSJack F Vogel 	    ((hw->bus.width <= ixgbe_bus_width_pcie_x4) &&
3343758cc3dcSJack F Vogel 	    (hw->bus.speed == ixgbe_bus_speed_2500))) {
3344758cc3dcSJack F Vogel 		device_printf(dev, "PCI-Express bandwidth available"
3345758cc3dcSJack F Vogel 		    " for this card\n     is not sufficient for"
3346758cc3dcSJack F Vogel 		    " optimal performance.\n");
3347758cc3dcSJack F Vogel 		device_printf(dev, "For optimal performance a x8 "
3348758cc3dcSJack F Vogel 		    "PCIE, or x4 PCIE Gen2 slot is required.\n");
3349758cc3dcSJack F Vogel         }
3350758cc3dcSJack F Vogel 	if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) &&
3351758cc3dcSJack F Vogel 	    ((hw->bus.width <= ixgbe_bus_width_pcie_x8) &&
3352758cc3dcSJack F Vogel 	    (hw->bus.speed < ixgbe_bus_speed_8000))) {
3353758cc3dcSJack F Vogel 		device_printf(dev, "PCI-Express bandwidth available"
3354758cc3dcSJack F Vogel 		    " for this card\n     is not sufficient for"
3355758cc3dcSJack F Vogel 		    " optimal performance.\n");
3356758cc3dcSJack F Vogel 		device_printf(dev, "For optimal performance a x8 "
3357758cc3dcSJack F Vogel 		    "PCIE Gen3 slot is required.\n");
3358758cc3dcSJack F Vogel         }
3359758cc3dcSJack F Vogel 
3360758cc3dcSJack F Vogel 	return;
3361758cc3dcSJack F Vogel }
3362758cc3dcSJack F Vogel 
3363758cc3dcSJack F Vogel 
3364758cc3dcSJack F Vogel /*
3365758cc3dcSJack F Vogel ** Setup the correct IVAR register for a particular MSIX interrupt
3366758cc3dcSJack F Vogel **   (yes this is all very magic and confusing :)
3367758cc3dcSJack F Vogel **  - entry is the register array entry
3368758cc3dcSJack F Vogel **  - vector is the MSIX vector for this queue
3369758cc3dcSJack F Vogel **  - type is RX/TX/MISC
3370758cc3dcSJack F Vogel */
3371758cc3dcSJack F Vogel static void
3372758cc3dcSJack F Vogel ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type)
3373758cc3dcSJack F Vogel {
3374758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
3375758cc3dcSJack F Vogel 	u32 ivar, index;
3376758cc3dcSJack F Vogel 
3377758cc3dcSJack F Vogel 	vector |= IXGBE_IVAR_ALLOC_VAL;
3378758cc3dcSJack F Vogel 
3379758cc3dcSJack F Vogel 	switch (hw->mac.type) {
3380758cc3dcSJack F Vogel 
3381758cc3dcSJack F Vogel 	case ixgbe_mac_82598EB:
3382758cc3dcSJack F Vogel 		if (type == -1)
3383758cc3dcSJack F Vogel 			entry = IXGBE_IVAR_OTHER_CAUSES_INDEX;
3384758cc3dcSJack F Vogel 		else
3385758cc3dcSJack F Vogel 			entry += (type * 64);
3386758cc3dcSJack F Vogel 		index = (entry >> 2) & 0x1F;
3387758cc3dcSJack F Vogel 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
3388758cc3dcSJack F Vogel 		ivar &= ~(0xFF << (8 * (entry & 0x3)));
3389758cc3dcSJack F Vogel 		ivar |= (vector << (8 * (entry & 0x3)));
3390758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar);
3391758cc3dcSJack F Vogel 		break;
3392758cc3dcSJack F Vogel 
3393758cc3dcSJack F Vogel 	case ixgbe_mac_82599EB:
3394758cc3dcSJack F Vogel 	case ixgbe_mac_X540:
3395758cc3dcSJack F Vogel 	case ixgbe_mac_X550:
3396758cc3dcSJack F Vogel 	case ixgbe_mac_X550EM_x:
3397758cc3dcSJack F Vogel 		if (type == -1) { /* MISC IVAR */
3398758cc3dcSJack F Vogel 			index = (entry & 1) * 8;
3399758cc3dcSJack F Vogel 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
3400758cc3dcSJack F Vogel 			ivar &= ~(0xFF << index);
3401758cc3dcSJack F Vogel 			ivar |= (vector << index);
3402758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
3403758cc3dcSJack F Vogel 		} else {	/* RX/TX IVARS */
3404758cc3dcSJack F Vogel 			index = (16 * (entry & 1)) + (8 * type);
3405758cc3dcSJack F Vogel 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1));
3406758cc3dcSJack F Vogel 			ivar &= ~(0xFF << index);
3407758cc3dcSJack F Vogel 			ivar |= (vector << index);
3408758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar);
3409758cc3dcSJack F Vogel 		}
3410758cc3dcSJack F Vogel 
3411758cc3dcSJack F Vogel 	default:
3412758cc3dcSJack F Vogel 		break;
3413758cc3dcSJack F Vogel 	}
3414758cc3dcSJack F Vogel }
3415758cc3dcSJack F Vogel 
3416758cc3dcSJack F Vogel static void
3417758cc3dcSJack F Vogel ixgbe_configure_ivars(struct adapter *adapter)
3418758cc3dcSJack F Vogel {
3419758cc3dcSJack F Vogel 	struct  ix_queue *que = adapter->queues;
3420758cc3dcSJack F Vogel 	u32 newitr;
3421758cc3dcSJack F Vogel 
3422758cc3dcSJack F Vogel 	if (ixgbe_max_interrupt_rate > 0)
3423758cc3dcSJack F Vogel 		newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8;
3424*6f37f232SEric Joyner 	else {
3425*6f37f232SEric Joyner 		/*
3426*6f37f232SEric Joyner 		** Disable DMA coalescing if interrupt moderation is
3427*6f37f232SEric Joyner 		** disabled.
3428*6f37f232SEric Joyner 		*/
3429*6f37f232SEric Joyner 		adapter->dmac = 0;
3430758cc3dcSJack F Vogel 		newitr = 0;
3431*6f37f232SEric Joyner 	}
3432758cc3dcSJack F Vogel 
3433758cc3dcSJack F Vogel         for (int i = 0; i < adapter->num_queues; i++, que++) {
3434758cc3dcSJack F Vogel 		/* First the RX queue entry */
3435758cc3dcSJack F Vogel                 ixgbe_set_ivar(adapter, i, que->msix, 0);
3436758cc3dcSJack F Vogel 		/* ... and the TX */
3437758cc3dcSJack F Vogel 		ixgbe_set_ivar(adapter, i, que->msix, 1);
3438758cc3dcSJack F Vogel 		/* Set an Initial EITR value */
3439758cc3dcSJack F Vogel                 IXGBE_WRITE_REG(&adapter->hw,
3440758cc3dcSJack F Vogel                     IXGBE_EITR(que->msix), newitr);
3441758cc3dcSJack F Vogel 	}
3442758cc3dcSJack F Vogel 
3443758cc3dcSJack F Vogel 	/* For the Link interrupt */
3444758cc3dcSJack F Vogel         ixgbe_set_ivar(adapter, 1, adapter->vector, -1);
3445758cc3dcSJack F Vogel }
3446758cc3dcSJack F Vogel 
3447758cc3dcSJack F Vogel /*
3448758cc3dcSJack F Vogel ** ixgbe_sfp_probe - called in the local timer to
3449758cc3dcSJack F Vogel ** determine if a port had optics inserted.
3450758cc3dcSJack F Vogel */
3451758cc3dcSJack F Vogel static bool ixgbe_sfp_probe(struct adapter *adapter)
3452758cc3dcSJack F Vogel {
3453758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
3454758cc3dcSJack F Vogel 	device_t	dev = adapter->dev;
3455758cc3dcSJack F Vogel 	bool		result = FALSE;
3456758cc3dcSJack F Vogel 
3457758cc3dcSJack F Vogel 	if ((hw->phy.type == ixgbe_phy_nl) &&
3458758cc3dcSJack F Vogel 	    (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
3459758cc3dcSJack F Vogel 		s32 ret = hw->phy.ops.identify_sfp(hw);
3460758cc3dcSJack F Vogel 		if (ret)
3461758cc3dcSJack F Vogel                         goto out;
3462758cc3dcSJack F Vogel 		ret = hw->phy.ops.reset(hw);
3463758cc3dcSJack F Vogel 		if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
3464758cc3dcSJack F Vogel 			device_printf(dev,"Unsupported SFP+ module detected!");
3465758cc3dcSJack F Vogel 			printf(" Reload driver with supported module.\n");
3466758cc3dcSJack F Vogel 			adapter->sfp_probe = FALSE;
3467758cc3dcSJack F Vogel                         goto out;
3468758cc3dcSJack F Vogel 		} else
3469758cc3dcSJack F Vogel 			device_printf(dev,"SFP+ module detected!\n");
3470758cc3dcSJack F Vogel 		/* We now have supported optics */
3471758cc3dcSJack F Vogel 		adapter->sfp_probe = FALSE;
3472758cc3dcSJack F Vogel 		/* Set the optics type so system reports correctly */
3473758cc3dcSJack F Vogel 		ixgbe_setup_optics(adapter);
3474758cc3dcSJack F Vogel 		result = TRUE;
3475758cc3dcSJack F Vogel 	}
3476758cc3dcSJack F Vogel out:
3477758cc3dcSJack F Vogel 	return (result);
3478758cc3dcSJack F Vogel }
3479758cc3dcSJack F Vogel 
3480758cc3dcSJack F Vogel /*
3481758cc3dcSJack F Vogel ** Tasklet handler for MSIX Link interrupts
3482758cc3dcSJack F Vogel **  - do outside interrupt since it might sleep
3483758cc3dcSJack F Vogel */
3484758cc3dcSJack F Vogel static void
3485758cc3dcSJack F Vogel ixgbe_handle_link(void *context, int pending)
3486758cc3dcSJack F Vogel {
3487758cc3dcSJack F Vogel 	struct adapter  *adapter = context;
3488758cc3dcSJack F Vogel 
3489758cc3dcSJack F Vogel 	ixgbe_check_link(&adapter->hw,
3490758cc3dcSJack F Vogel 	    &adapter->link_speed, &adapter->link_up, 0);
3491758cc3dcSJack F Vogel 	ixgbe_update_link_status(adapter);
3492758cc3dcSJack F Vogel }
3493758cc3dcSJack F Vogel 
3494758cc3dcSJack F Vogel /*
3495758cc3dcSJack F Vogel ** Tasklet for handling SFP module interrupts
3496758cc3dcSJack F Vogel */
3497758cc3dcSJack F Vogel static void
3498758cc3dcSJack F Vogel ixgbe_handle_mod(void *context, int pending)
3499758cc3dcSJack F Vogel {
3500758cc3dcSJack F Vogel 	struct adapter  *adapter = context;
3501758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
3502758cc3dcSJack F Vogel 	device_t	dev = adapter->dev;
3503758cc3dcSJack F Vogel 	u32 err;
3504758cc3dcSJack F Vogel 
3505758cc3dcSJack F Vogel 	err = hw->phy.ops.identify_sfp(hw);
3506758cc3dcSJack F Vogel 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
3507758cc3dcSJack F Vogel 		device_printf(dev,
3508758cc3dcSJack F Vogel 		    "Unsupported SFP+ module type was detected.\n");
3509758cc3dcSJack F Vogel 		return;
3510758cc3dcSJack F Vogel 	}
3511758cc3dcSJack F Vogel 	err = hw->mac.ops.setup_sfp(hw);
3512758cc3dcSJack F Vogel 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
3513758cc3dcSJack F Vogel 		device_printf(dev,
3514758cc3dcSJack F Vogel 		    "Setup failure - unsupported SFP+ module type.\n");
3515758cc3dcSJack F Vogel 		return;
3516758cc3dcSJack F Vogel 	}
3517758cc3dcSJack F Vogel 	taskqueue_enqueue(adapter->tq, &adapter->msf_task);
3518758cc3dcSJack F Vogel 	return;
3519758cc3dcSJack F Vogel }
3520758cc3dcSJack F Vogel 
3521758cc3dcSJack F Vogel 
3522758cc3dcSJack F Vogel /*
3523758cc3dcSJack F Vogel ** Tasklet for handling MSF (multispeed fiber) interrupts
3524758cc3dcSJack F Vogel */
3525758cc3dcSJack F Vogel static void
3526758cc3dcSJack F Vogel ixgbe_handle_msf(void *context, int pending)
3527758cc3dcSJack F Vogel {
3528758cc3dcSJack F Vogel 	struct adapter  *adapter = context;
3529758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
3530758cc3dcSJack F Vogel 	u32 autoneg;
3531758cc3dcSJack F Vogel 	bool negotiate;
3532758cc3dcSJack F Vogel 	int err;
3533758cc3dcSJack F Vogel 
3534758cc3dcSJack F Vogel 	err = hw->phy.ops.identify_sfp(hw);
3535758cc3dcSJack F Vogel 	if (!err) {
3536758cc3dcSJack F Vogel 		ixgbe_setup_optics(adapter);
3537758cc3dcSJack F Vogel 		INIT_DEBUGOUT1("ixgbe_sfp_probe: flags: %X\n", adapter->optics);
3538758cc3dcSJack F Vogel 	}
3539758cc3dcSJack F Vogel 
3540758cc3dcSJack F Vogel 	autoneg = hw->phy.autoneg_advertised;
3541758cc3dcSJack F Vogel 	if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
3542758cc3dcSJack F Vogel 		hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate);
3543758cc3dcSJack F Vogel 	if (hw->mac.ops.setup_link)
3544758cc3dcSJack F Vogel 		hw->mac.ops.setup_link(hw, autoneg, TRUE);
3545758cc3dcSJack F Vogel 
3546758cc3dcSJack F Vogel 	ifmedia_removeall(&adapter->media);
3547758cc3dcSJack F Vogel 	ixgbe_add_media_types(adapter);
3548758cc3dcSJack F Vogel 	return;
3549758cc3dcSJack F Vogel }
3550758cc3dcSJack F Vogel 
3551*6f37f232SEric Joyner /*
3552*6f37f232SEric Joyner ** Tasklet for handling interrupts from an external PHY
3553*6f37f232SEric Joyner */
3554*6f37f232SEric Joyner static void
3555*6f37f232SEric Joyner ixgbe_handle_phy(void *context, int pending)
3556*6f37f232SEric Joyner {
3557*6f37f232SEric Joyner 	struct adapter  *adapter = context;
3558*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
3559*6f37f232SEric Joyner 	int error;
3560*6f37f232SEric Joyner 
3561*6f37f232SEric Joyner 	error = hw->phy.ops.handle_lasi(hw);
3562*6f37f232SEric Joyner 	if (error == IXGBE_ERR_OVERTEMP)
3563*6f37f232SEric Joyner 		device_printf(adapter->dev,
3564*6f37f232SEric Joyner 		    "CRITICAL: EXTERNAL PHY OVER TEMP!! "
3565*6f37f232SEric Joyner 		    " PHY will downshift to lower power state!\n");
3566*6f37f232SEric Joyner 	else if (error)
3567*6f37f232SEric Joyner 		device_printf(adapter->dev,
3568*6f37f232SEric Joyner 		    "Error handling LASI interrupt: %d\n",
3569*6f37f232SEric Joyner 		    error);
3570*6f37f232SEric Joyner 	return;
3571*6f37f232SEric Joyner }
3572*6f37f232SEric Joyner 
3573758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
3574758cc3dcSJack F Vogel /*
3575758cc3dcSJack F Vogel ** Tasklet for reinitializing the Flow Director filter table
3576758cc3dcSJack F Vogel */
3577758cc3dcSJack F Vogel static void
3578758cc3dcSJack F Vogel ixgbe_reinit_fdir(void *context, int pending)
3579758cc3dcSJack F Vogel {
3580758cc3dcSJack F Vogel 	struct adapter  *adapter = context;
3581758cc3dcSJack F Vogel 	struct ifnet   *ifp = adapter->ifp;
3582758cc3dcSJack F Vogel 
3583758cc3dcSJack F Vogel 	if (adapter->fdir_reinit != 1) /* Shouldn't happen */
3584758cc3dcSJack F Vogel 		return;
3585758cc3dcSJack F Vogel 	ixgbe_reinit_fdir_tables_82599(&adapter->hw);
3586758cc3dcSJack F Vogel 	adapter->fdir_reinit = 0;
3587758cc3dcSJack F Vogel 	/* re-enable flow director interrupts */
3588758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR);
3589758cc3dcSJack F Vogel 	/* Restart the interface */
3590758cc3dcSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
3591758cc3dcSJack F Vogel 	return;
3592758cc3dcSJack F Vogel }
3593758cc3dcSJack F Vogel #endif
3594758cc3dcSJack F Vogel 
3595*6f37f232SEric Joyner /*********************************************************************
3596*6f37f232SEric Joyner  *
3597*6f37f232SEric Joyner  *  Configure DMA Coalescing
3598*6f37f232SEric Joyner  *
3599*6f37f232SEric Joyner  **********************************************************************/
3600*6f37f232SEric Joyner static void
3601*6f37f232SEric Joyner ixgbe_config_dmac(struct adapter *adapter)
3602*6f37f232SEric Joyner {
3603*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
3604*6f37f232SEric Joyner 	struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config;
3605*6f37f232SEric Joyner 
3606*6f37f232SEric Joyner 	if (hw->mac.type < ixgbe_mac_X550 ||
3607*6f37f232SEric Joyner 	    !hw->mac.ops.dmac_config)
3608*6f37f232SEric Joyner 		return;
3609*6f37f232SEric Joyner 
3610*6f37f232SEric Joyner 	if (dcfg->watchdog_timer ^ adapter->dmac ||
3611*6f37f232SEric Joyner 	    dcfg->link_speed ^ adapter->link_speed) {
3612*6f37f232SEric Joyner 		dcfg->watchdog_timer = adapter->dmac;
3613*6f37f232SEric Joyner 		dcfg->fcoe_en = false;
3614*6f37f232SEric Joyner 		dcfg->link_speed = adapter->link_speed;
3615*6f37f232SEric Joyner 		dcfg->num_tcs = 1;
3616*6f37f232SEric Joyner 
3617*6f37f232SEric Joyner 		INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n",
3618*6f37f232SEric Joyner 		    dcfg->watchdog_timer, dcfg->link_speed);
3619*6f37f232SEric Joyner 
3620*6f37f232SEric Joyner 		hw->mac.ops.dmac_config(hw);
3621*6f37f232SEric Joyner 	}
3622*6f37f232SEric Joyner }
3623*6f37f232SEric Joyner 
3624*6f37f232SEric Joyner /*
3625*6f37f232SEric Joyner  * Checks whether the adapter supports Energy Efficient Ethernet
3626*6f37f232SEric Joyner  * or not, based on device ID.
3627*6f37f232SEric Joyner  */
3628*6f37f232SEric Joyner static void
3629*6f37f232SEric Joyner ixgbe_check_eee_support(struct adapter *adapter)
3630*6f37f232SEric Joyner {
3631*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
3632*6f37f232SEric Joyner 
3633*6f37f232SEric Joyner 	adapter->eee_support = adapter->eee_enabled =
3634*6f37f232SEric Joyner 	    (hw->device_id == IXGBE_DEV_ID_X550T ||
3635*6f37f232SEric Joyner 	        hw->device_id == IXGBE_DEV_ID_X550EM_X_KR);
3636*6f37f232SEric Joyner }
3637*6f37f232SEric Joyner 
3638*6f37f232SEric Joyner /*
3639*6f37f232SEric Joyner  * Checks whether the adapter's ports are capable of
3640*6f37f232SEric Joyner  * Wake On LAN by reading the adapter's NVM.
3641*6f37f232SEric Joyner  *
3642*6f37f232SEric Joyner  * Sets each port's hw->wol_enabled value depending
3643*6f37f232SEric Joyner  * on the value read here.
3644*6f37f232SEric Joyner  */
3645*6f37f232SEric Joyner static void
3646*6f37f232SEric Joyner ixgbe_check_wol_support(struct adapter *adapter)
3647*6f37f232SEric Joyner {
3648*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
3649*6f37f232SEric Joyner 	u16 dev_caps = 0;
3650*6f37f232SEric Joyner 
3651*6f37f232SEric Joyner 	/* Find out WoL support for port */
3652*6f37f232SEric Joyner 	adapter->wol_support = hw->wol_enabled = 0;
3653*6f37f232SEric Joyner 	ixgbe_get_device_caps(hw, &dev_caps);
3654*6f37f232SEric Joyner 	if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
3655*6f37f232SEric Joyner 	    ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) &&
3656*6f37f232SEric Joyner 	        hw->bus.func == 0))
3657*6f37f232SEric Joyner 	    adapter->wol_support = hw->wol_enabled = 1;
3658*6f37f232SEric Joyner 
3659*6f37f232SEric Joyner 	/* Save initial wake up filter configuration */
3660*6f37f232SEric Joyner 	adapter->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC);
3661*6f37f232SEric Joyner 
3662*6f37f232SEric Joyner 	return;
3663*6f37f232SEric Joyner }
3664*6f37f232SEric Joyner 
3665*6f37f232SEric Joyner /*
3666*6f37f232SEric Joyner  * Prepare the adapter/port for LPLU and/or WoL
3667*6f37f232SEric Joyner  */
3668*6f37f232SEric Joyner static int
3669*6f37f232SEric Joyner ixgbe_setup_low_power_mode(struct adapter *adapter)
3670*6f37f232SEric Joyner {
3671*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
3672*6f37f232SEric Joyner 	device_t dev = adapter->dev;
3673*6f37f232SEric Joyner 	s32 error = 0;
3674*6f37f232SEric Joyner 
3675*6f37f232SEric Joyner 	mtx_assert(&adapter->core_mtx, MA_OWNED);
3676*6f37f232SEric Joyner 
3677*6f37f232SEric Joyner 	/* Limit power management flow to X550EM baseT */
3678*6f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T
3679*6f37f232SEric Joyner 	    && hw->phy.ops.enter_lplu) {
3680*6f37f232SEric Joyner 		/* Turn off support for APM wakeup. (Using ACPI instead) */
3681*6f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_GRC,
3682*6f37f232SEric Joyner 		    IXGBE_READ_REG(hw, IXGBE_GRC) & ~(u32)2);
3683*6f37f232SEric Joyner 
3684*6f37f232SEric Joyner 		/*
3685*6f37f232SEric Joyner 		 * Clear Wake Up Status register to prevent any previous wakeup
3686*6f37f232SEric Joyner 		 * events from waking us up immediately after we suspend.
3687*6f37f232SEric Joyner 		 */
3688*6f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
3689*6f37f232SEric Joyner 
3690*6f37f232SEric Joyner 		/*
3691*6f37f232SEric Joyner 		 * Program the Wakeup Filter Control register with user filter
3692*6f37f232SEric Joyner 		 * settings
3693*6f37f232SEric Joyner 		 */
3694*6f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_WUFC, adapter->wufc);
3695*6f37f232SEric Joyner 
3696*6f37f232SEric Joyner 		/* Enable wakeups and power management in Wakeup Control */
3697*6f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_WUC,
3698*6f37f232SEric Joyner 		    IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN);
3699*6f37f232SEric Joyner 
3700*6f37f232SEric Joyner 		/* X550EM baseT adapters need a special LPLU flow */
3701*6f37f232SEric Joyner 		hw->phy.reset_disable = true;
3702*6f37f232SEric Joyner 		ixgbe_stop(adapter);
3703*6f37f232SEric Joyner 		error = hw->phy.ops.enter_lplu(hw);
3704*6f37f232SEric Joyner 		if (error)
3705*6f37f232SEric Joyner 			device_printf(dev,
3706*6f37f232SEric Joyner 			    "Error entering LPLU: %d\n", error);
3707*6f37f232SEric Joyner 		hw->phy.reset_disable = false;
3708*6f37f232SEric Joyner 	} else {
3709*6f37f232SEric Joyner 		/* Just stop for other adapters */
3710*6f37f232SEric Joyner 		ixgbe_stop(adapter);
3711*6f37f232SEric Joyner 	}
3712*6f37f232SEric Joyner 
3713*6f37f232SEric Joyner 	return error;
3714*6f37f232SEric Joyner }
3715*6f37f232SEric Joyner 
3716758cc3dcSJack F Vogel /**********************************************************************
3717758cc3dcSJack F Vogel  *
3718758cc3dcSJack F Vogel  *  Update the board statistics counters.
3719758cc3dcSJack F Vogel  *
3720758cc3dcSJack F Vogel  **********************************************************************/
3721758cc3dcSJack F Vogel static void
3722758cc3dcSJack F Vogel ixgbe_update_stats_counters(struct adapter *adapter)
3723758cc3dcSJack F Vogel {
3724758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
3725758cc3dcSJack F Vogel 	u32 missed_rx = 0, bprc, lxon, lxoff, total;
3726758cc3dcSJack F Vogel 	u64 total_missed_rx = 0;
3727758cc3dcSJack F Vogel 
3728758cc3dcSJack F Vogel 	adapter->stats.pf.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
3729758cc3dcSJack F Vogel 	adapter->stats.pf.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC);
3730758cc3dcSJack F Vogel 	adapter->stats.pf.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC);
3731758cc3dcSJack F Vogel 	adapter->stats.pf.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC);
3732758cc3dcSJack F Vogel 
3733758cc3dcSJack F Vogel 	for (int i = 0; i < 16; i++) {
3734758cc3dcSJack F Vogel 		adapter->stats.pf.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
3735758cc3dcSJack F Vogel 		adapter->stats.pf.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
3736758cc3dcSJack F Vogel 		adapter->stats.pf.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
3737758cc3dcSJack F Vogel 	}
3738758cc3dcSJack F Vogel 	adapter->stats.pf.mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC);
3739758cc3dcSJack F Vogel 	adapter->stats.pf.mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC);
3740758cc3dcSJack F Vogel 	adapter->stats.pf.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
3741758cc3dcSJack F Vogel 
3742758cc3dcSJack F Vogel 	/* Hardware workaround, gprc counts missed packets */
3743758cc3dcSJack F Vogel 	adapter->stats.pf.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
3744758cc3dcSJack F Vogel 	adapter->stats.pf.gprc -= missed_rx;
3745758cc3dcSJack F Vogel 
3746758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
3747758cc3dcSJack F Vogel 		adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) +
3748758cc3dcSJack F Vogel 		    ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32);
3749758cc3dcSJack F Vogel 		adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) +
3750758cc3dcSJack F Vogel 		    ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32);
3751758cc3dcSJack F Vogel 		adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORL) +
3752758cc3dcSJack F Vogel 		    ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32);
3753758cc3dcSJack F Vogel 		adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
3754758cc3dcSJack F Vogel 		adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
3755758cc3dcSJack F Vogel 	} else {
3756758cc3dcSJack F Vogel 		adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
3757758cc3dcSJack F Vogel 		adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
3758758cc3dcSJack F Vogel 		/* 82598 only has a counter in the high register */
3759758cc3dcSJack F Vogel 		adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
3760758cc3dcSJack F Vogel 		adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
3761758cc3dcSJack F Vogel 		adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
3762758cc3dcSJack F Vogel 	}
3763758cc3dcSJack F Vogel 
3764758cc3dcSJack F Vogel 	/*
3765758cc3dcSJack F Vogel 	 * Workaround: mprc hardware is incorrectly counting
3766758cc3dcSJack F Vogel 	 * broadcasts, so for now we subtract those.
3767758cc3dcSJack F Vogel 	 */
3768758cc3dcSJack F Vogel 	bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
3769758cc3dcSJack F Vogel 	adapter->stats.pf.bprc += bprc;
3770758cc3dcSJack F Vogel 	adapter->stats.pf.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
3771758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82598EB)
3772758cc3dcSJack F Vogel 		adapter->stats.pf.mprc -= bprc;
3773758cc3dcSJack F Vogel 
3774758cc3dcSJack F Vogel 	adapter->stats.pf.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
3775758cc3dcSJack F Vogel 	adapter->stats.pf.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
3776758cc3dcSJack F Vogel 	adapter->stats.pf.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255);
3777758cc3dcSJack F Vogel 	adapter->stats.pf.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
3778758cc3dcSJack F Vogel 	adapter->stats.pf.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
3779758cc3dcSJack F Vogel 	adapter->stats.pf.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
3780758cc3dcSJack F Vogel 
3781758cc3dcSJack F Vogel 	lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC);
3782758cc3dcSJack F Vogel 	adapter->stats.pf.lxontxc += lxon;
3783758cc3dcSJack F Vogel 	lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
3784758cc3dcSJack F Vogel 	adapter->stats.pf.lxofftxc += lxoff;
3785758cc3dcSJack F Vogel 	total = lxon + lxoff;
3786758cc3dcSJack F Vogel 
3787758cc3dcSJack F Vogel 	adapter->stats.pf.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
3788758cc3dcSJack F Vogel 	adapter->stats.pf.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
3789758cc3dcSJack F Vogel 	adapter->stats.pf.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
3790758cc3dcSJack F Vogel 	adapter->stats.pf.gptc -= total;
3791758cc3dcSJack F Vogel 	adapter->stats.pf.mptc -= total;
3792758cc3dcSJack F Vogel 	adapter->stats.pf.ptc64 -= total;
3793758cc3dcSJack F Vogel 	adapter->stats.pf.gotc -= total * ETHER_MIN_LEN;
3794758cc3dcSJack F Vogel 
3795758cc3dcSJack F Vogel 	adapter->stats.pf.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
3796758cc3dcSJack F Vogel 	adapter->stats.pf.rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
3797758cc3dcSJack F Vogel 	adapter->stats.pf.roc += IXGBE_READ_REG(hw, IXGBE_ROC);
3798758cc3dcSJack F Vogel 	adapter->stats.pf.rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
3799758cc3dcSJack F Vogel 	adapter->stats.pf.mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC);
3800758cc3dcSJack F Vogel 	adapter->stats.pf.mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC);
3801758cc3dcSJack F Vogel 	adapter->stats.pf.mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC);
3802758cc3dcSJack F Vogel 	adapter->stats.pf.tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
3803758cc3dcSJack F Vogel 	adapter->stats.pf.tpt += IXGBE_READ_REG(hw, IXGBE_TPT);
3804758cc3dcSJack F Vogel 	adapter->stats.pf.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
3805758cc3dcSJack F Vogel 	adapter->stats.pf.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
3806758cc3dcSJack F Vogel 	adapter->stats.pf.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
3807758cc3dcSJack F Vogel 	adapter->stats.pf.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
3808758cc3dcSJack F Vogel 	adapter->stats.pf.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
3809758cc3dcSJack F Vogel 	adapter->stats.pf.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
3810758cc3dcSJack F Vogel 	adapter->stats.pf.xec += IXGBE_READ_REG(hw, IXGBE_XEC);
3811758cc3dcSJack F Vogel 	adapter->stats.pf.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC);
3812758cc3dcSJack F Vogel 	adapter->stats.pf.fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST);
3813758cc3dcSJack F Vogel 	/* Only read FCOE on 82599 */
3814758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
3815758cc3dcSJack F Vogel 		adapter->stats.pf.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC);
3816758cc3dcSJack F Vogel 		adapter->stats.pf.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC);
3817758cc3dcSJack F Vogel 		adapter->stats.pf.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC);
3818758cc3dcSJack F Vogel 		adapter->stats.pf.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC);
3819758cc3dcSJack F Vogel 		adapter->stats.pf.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC);
3820758cc3dcSJack F Vogel 	}
3821758cc3dcSJack F Vogel 
3822758cc3dcSJack F Vogel 	/* Fill out the OS statistics structure */
3823758cc3dcSJack F Vogel 	IXGBE_SET_IPACKETS(adapter, adapter->stats.pf.gprc);
3824758cc3dcSJack F Vogel 	IXGBE_SET_OPACKETS(adapter, adapter->stats.pf.gptc);
3825758cc3dcSJack F Vogel 	IXGBE_SET_IBYTES(adapter, adapter->stats.pf.gorc);
3826758cc3dcSJack F Vogel 	IXGBE_SET_OBYTES(adapter, adapter->stats.pf.gotc);
3827758cc3dcSJack F Vogel 	IXGBE_SET_IMCASTS(adapter, adapter->stats.pf.mprc);
3828758cc3dcSJack F Vogel 	IXGBE_SET_OMCASTS(adapter, adapter->stats.pf.mptc);
3829758cc3dcSJack F Vogel 	IXGBE_SET_COLLISIONS(adapter, 0);
3830758cc3dcSJack F Vogel 	IXGBE_SET_IQDROPS(adapter, total_missed_rx);
3831758cc3dcSJack F Vogel 	IXGBE_SET_IERRORS(adapter, adapter->stats.pf.crcerrs
3832758cc3dcSJack F Vogel 	    + adapter->stats.pf.rlec);
3833758cc3dcSJack F Vogel }
3834758cc3dcSJack F Vogel 
3835758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036
3836758cc3dcSJack F Vogel static uint64_t
3837758cc3dcSJack F Vogel ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt)
3838758cc3dcSJack F Vogel {
3839758cc3dcSJack F Vogel 	struct adapter *adapter;
3840625d12c6SJohn Baldwin 	struct tx_ring *txr;
3841625d12c6SJohn Baldwin 	uint64_t rv;
3842758cc3dcSJack F Vogel 
3843758cc3dcSJack F Vogel 	adapter = if_getsoftc(ifp);
3844758cc3dcSJack F Vogel 
3845758cc3dcSJack F Vogel 	switch (cnt) {
3846758cc3dcSJack F Vogel 	case IFCOUNTER_IPACKETS:
3847758cc3dcSJack F Vogel 		return (adapter->ipackets);
3848758cc3dcSJack F Vogel 	case IFCOUNTER_OPACKETS:
3849758cc3dcSJack F Vogel 		return (adapter->opackets);
3850758cc3dcSJack F Vogel 	case IFCOUNTER_IBYTES:
3851758cc3dcSJack F Vogel 		return (adapter->ibytes);
3852758cc3dcSJack F Vogel 	case IFCOUNTER_OBYTES:
3853758cc3dcSJack F Vogel 		return (adapter->obytes);
3854758cc3dcSJack F Vogel 	case IFCOUNTER_IMCASTS:
3855758cc3dcSJack F Vogel 		return (adapter->imcasts);
3856758cc3dcSJack F Vogel 	case IFCOUNTER_OMCASTS:
3857758cc3dcSJack F Vogel 		return (adapter->omcasts);
3858758cc3dcSJack F Vogel 	case IFCOUNTER_COLLISIONS:
3859758cc3dcSJack F Vogel 		return (0);
3860758cc3dcSJack F Vogel 	case IFCOUNTER_IQDROPS:
3861758cc3dcSJack F Vogel 		return (adapter->iqdrops);
3862625d12c6SJohn Baldwin 	case IFCOUNTER_OQDROPS:
3863625d12c6SJohn Baldwin 		rv = 0;
3864625d12c6SJohn Baldwin 		txr = adapter->tx_rings;
3865625d12c6SJohn Baldwin 		for (int i = 0; i < adapter->num_queues; i++, txr++)
3866625d12c6SJohn Baldwin 			rv += txr->br->br_drops;
3867625d12c6SJohn Baldwin 		return (rv);
3868758cc3dcSJack F Vogel 	case IFCOUNTER_IERRORS:
3869758cc3dcSJack F Vogel 		return (adapter->ierrors);
3870758cc3dcSJack F Vogel 	default:
3871758cc3dcSJack F Vogel 		return (if_get_counter_default(ifp, cnt));
3872758cc3dcSJack F Vogel 	}
3873758cc3dcSJack F Vogel }
3874758cc3dcSJack F Vogel #endif
3875758cc3dcSJack F Vogel 
3876758cc3dcSJack F Vogel /** ixgbe_sysctl_tdh_handler - Handler function
3877758cc3dcSJack F Vogel  *  Retrieves the TDH value from the hardware
3878758cc3dcSJack F Vogel  */
3879758cc3dcSJack F Vogel static int
3880758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS)
3881758cc3dcSJack F Vogel {
3882758cc3dcSJack F Vogel 	int error;
3883758cc3dcSJack F Vogel 
3884758cc3dcSJack F Vogel 	struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1);
3885758cc3dcSJack F Vogel 	if (!txr) return 0;
3886758cc3dcSJack F Vogel 
3887758cc3dcSJack F Vogel 	unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me));
3888758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
3889758cc3dcSJack F Vogel 	if (error || !req->newptr)
3890758cc3dcSJack F Vogel 		return error;
3891758cc3dcSJack F Vogel 	return 0;
3892758cc3dcSJack F Vogel }
3893758cc3dcSJack F Vogel 
3894758cc3dcSJack F Vogel /** ixgbe_sysctl_tdt_handler - Handler function
3895758cc3dcSJack F Vogel  *  Retrieves the TDT value from the hardware
3896758cc3dcSJack F Vogel  */
3897758cc3dcSJack F Vogel static int
3898758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS)
3899758cc3dcSJack F Vogel {
3900758cc3dcSJack F Vogel 	int error;
3901758cc3dcSJack F Vogel 
3902758cc3dcSJack F Vogel 	struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1);
3903758cc3dcSJack F Vogel 	if (!txr) return 0;
3904758cc3dcSJack F Vogel 
3905758cc3dcSJack F Vogel 	unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me));
3906758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
3907758cc3dcSJack F Vogel 	if (error || !req->newptr)
3908758cc3dcSJack F Vogel 		return error;
3909758cc3dcSJack F Vogel 	return 0;
3910758cc3dcSJack F Vogel }
3911758cc3dcSJack F Vogel 
3912758cc3dcSJack F Vogel /** ixgbe_sysctl_rdh_handler - Handler function
3913758cc3dcSJack F Vogel  *  Retrieves the RDH value from the hardware
3914758cc3dcSJack F Vogel  */
3915758cc3dcSJack F Vogel static int
3916758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS)
3917758cc3dcSJack F Vogel {
3918758cc3dcSJack F Vogel 	int error;
3919758cc3dcSJack F Vogel 
3920758cc3dcSJack F Vogel 	struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1);
3921758cc3dcSJack F Vogel 	if (!rxr) return 0;
3922758cc3dcSJack F Vogel 
3923758cc3dcSJack F Vogel 	unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me));
3924758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
3925758cc3dcSJack F Vogel 	if (error || !req->newptr)
3926758cc3dcSJack F Vogel 		return error;
3927758cc3dcSJack F Vogel 	return 0;
3928758cc3dcSJack F Vogel }
3929758cc3dcSJack F Vogel 
3930758cc3dcSJack F Vogel /** ixgbe_sysctl_rdt_handler - Handler function
3931758cc3dcSJack F Vogel  *  Retrieves the RDT value from the hardware
3932758cc3dcSJack F Vogel  */
3933758cc3dcSJack F Vogel static int
3934758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS)
3935758cc3dcSJack F Vogel {
3936758cc3dcSJack F Vogel 	int error;
3937758cc3dcSJack F Vogel 
3938758cc3dcSJack F Vogel 	struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1);
3939758cc3dcSJack F Vogel 	if (!rxr) return 0;
3940758cc3dcSJack F Vogel 
3941758cc3dcSJack F Vogel 	unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me));
3942758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
3943758cc3dcSJack F Vogel 	if (error || !req->newptr)
3944758cc3dcSJack F Vogel 		return error;
3945758cc3dcSJack F Vogel 	return 0;
3946758cc3dcSJack F Vogel }
3947758cc3dcSJack F Vogel 
3948758cc3dcSJack F Vogel static int
3949758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
3950758cc3dcSJack F Vogel {
3951758cc3dcSJack F Vogel 	int error;
3952758cc3dcSJack F Vogel 	struct ix_queue *que = ((struct ix_queue *)oidp->oid_arg1);
3953758cc3dcSJack F Vogel 	unsigned int reg, usec, rate;
3954758cc3dcSJack F Vogel 
3955758cc3dcSJack F Vogel 	reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix));
3956758cc3dcSJack F Vogel 	usec = ((reg & 0x0FF8) >> 3);
3957758cc3dcSJack F Vogel 	if (usec > 0)
3958758cc3dcSJack F Vogel 		rate = 500000 / usec;
3959758cc3dcSJack F Vogel 	else
3960758cc3dcSJack F Vogel 		rate = 0;
3961758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &rate, 0, req);
3962758cc3dcSJack F Vogel 	if (error || !req->newptr)
3963758cc3dcSJack F Vogel 		return error;
3964758cc3dcSJack F Vogel 	reg &= ~0xfff; /* default, no limitation */
3965758cc3dcSJack F Vogel 	ixgbe_max_interrupt_rate = 0;
3966758cc3dcSJack F Vogel 	if (rate > 0 && rate < 500000) {
3967758cc3dcSJack F Vogel 		if (rate < 1000)
3968758cc3dcSJack F Vogel 			rate = 1000;
3969758cc3dcSJack F Vogel 		ixgbe_max_interrupt_rate = rate;
3970758cc3dcSJack F Vogel 		reg |= ((4000000/rate) & 0xff8 );
3971758cc3dcSJack F Vogel 	}
3972758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&que->adapter->hw, IXGBE_EITR(que->msix), reg);
3973758cc3dcSJack F Vogel 	return 0;
3974758cc3dcSJack F Vogel }
3975758cc3dcSJack F Vogel 
3976*6f37f232SEric Joyner static void
3977*6f37f232SEric Joyner ixgbe_add_device_sysctls(struct adapter *adapter)
3978*6f37f232SEric Joyner {
3979*6f37f232SEric Joyner 	device_t dev = adapter->dev;
3980*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
3981*6f37f232SEric Joyner 	struct sysctl_oid_list *child;
3982*6f37f232SEric Joyner 	struct sysctl_ctx_list *ctx;
3983*6f37f232SEric Joyner 
3984*6f37f232SEric Joyner 	ctx = device_get_sysctl_ctx(dev);
3985*6f37f232SEric Joyner 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
3986*6f37f232SEric Joyner 
3987*6f37f232SEric Joyner 	/* Sysctls for all devices */
3988*6f37f232SEric Joyner 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fc",
3989*6f37f232SEric Joyner 			CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
3990*6f37f232SEric Joyner 			ixgbe_set_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC);
3991*6f37f232SEric Joyner 
3992*6f37f232SEric Joyner         SYSCTL_ADD_INT(ctx, child, OID_AUTO, "enable_aim",
3993*6f37f232SEric Joyner 			CTLFLAG_RW,
3994*6f37f232SEric Joyner 			&ixgbe_enable_aim, 1, "Interrupt Moderation");
3995*6f37f232SEric Joyner 
3996*6f37f232SEric Joyner 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "advertise_speed",
3997*6f37f232SEric Joyner 			CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
3998*6f37f232SEric Joyner 			ixgbe_set_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED);
3999*6f37f232SEric Joyner 
4000*6f37f232SEric Joyner 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "thermal_test",
4001*6f37f232SEric Joyner 			CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
4002*6f37f232SEric Joyner 			ixgbe_sysctl_thermal_test, "I", "Thermal Test");
4003*6f37f232SEric Joyner 
4004*6f37f232SEric Joyner 	/* for X550 devices */
4005*6f37f232SEric Joyner 	if (hw->mac.type >= ixgbe_mac_X550)
4006*6f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac",
4007*6f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
4008*6f37f232SEric Joyner 				ixgbe_sysctl_dmac, "I", "DMA Coalesce");
4009*6f37f232SEric Joyner 
4010*6f37f232SEric Joyner 	/* for X550T and X550EM backplane devices */
4011*6f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550T ||
4012*6f37f232SEric Joyner 	    hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) {
4013*6f37f232SEric Joyner 		struct sysctl_oid *eee_node;
4014*6f37f232SEric Joyner 		struct sysctl_oid_list *eee_list;
4015*6f37f232SEric Joyner 
4016*6f37f232SEric Joyner 		eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee",
4017*6f37f232SEric Joyner 					   CTLFLAG_RD, NULL,
4018*6f37f232SEric Joyner 					   "Energy Efficient Ethernet sysctls");
4019*6f37f232SEric Joyner 		eee_list = SYSCTL_CHILDREN(eee_node);
4020*6f37f232SEric Joyner 
4021*6f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "enable",
4022*6f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
4023*6f37f232SEric Joyner 				ixgbe_sysctl_eee_enable, "I",
4024*6f37f232SEric Joyner 				"Enable or Disable EEE");
4025*6f37f232SEric Joyner 
4026*6f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "negotiated",
4027*6f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
4028*6f37f232SEric Joyner 				ixgbe_sysctl_eee_negotiated, "I",
4029*6f37f232SEric Joyner 				"EEE negotiated on link");
4030*6f37f232SEric Joyner 
4031*6f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_status",
4032*6f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
4033*6f37f232SEric Joyner 				ixgbe_sysctl_eee_tx_lpi_status, "I",
4034*6f37f232SEric Joyner 				"Whether or not TX link is in LPI state");
4035*6f37f232SEric Joyner 
4036*6f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "rx_lpi_status",
4037*6f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
4038*6f37f232SEric Joyner 				ixgbe_sysctl_eee_rx_lpi_status, "I",
4039*6f37f232SEric Joyner 				"Whether or not RX link is in LPI state");
4040*6f37f232SEric Joyner 	}
4041*6f37f232SEric Joyner 
4042*6f37f232SEric Joyner 	/* for certain 10GBaseT devices */
4043*6f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550T ||
4044*6f37f232SEric Joyner 	    hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
4045*6f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wol_enable",
4046*6f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
4047*6f37f232SEric Joyner 				ixgbe_sysctl_wol_enable, "I",
4048*6f37f232SEric Joyner 				"Enable/Disable Wake on LAN");
4049*6f37f232SEric Joyner 
4050*6f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wufc",
4051*6f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
4052*6f37f232SEric Joyner 				ixgbe_sysctl_wufc, "I",
4053*6f37f232SEric Joyner 				"Enable/Disable Wake Up Filters");
4054*6f37f232SEric Joyner 	}
4055*6f37f232SEric Joyner 
4056*6f37f232SEric Joyner 	/* for X550EM 10GBaseT devices */
4057*6f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
4058*6f37f232SEric Joyner 		struct sysctl_oid *phy_node;
4059*6f37f232SEric Joyner 		struct sysctl_oid_list *phy_list;
4060*6f37f232SEric Joyner 
4061*6f37f232SEric Joyner 		phy_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "phy",
4062*6f37f232SEric Joyner 					   CTLFLAG_RD, NULL,
4063*6f37f232SEric Joyner 					   "External PHY sysctls");
4064*6f37f232SEric Joyner 		phy_list = SYSCTL_CHILDREN(phy_node);
4065*6f37f232SEric Joyner 
4066*6f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "temp",
4067*6f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
4068*6f37f232SEric Joyner 				ixgbe_sysctl_phy_temp, "I",
4069*6f37f232SEric Joyner 				"Current External PHY Temperature (Celsius)");
4070*6f37f232SEric Joyner 
4071*6f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "overtemp_occurred",
4072*6f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
4073*6f37f232SEric Joyner 				ixgbe_sysctl_phy_overtemp_occurred, "I",
4074*6f37f232SEric Joyner 				"External PHY High Temperature Event Occurred");
4075*6f37f232SEric Joyner 	}
4076*6f37f232SEric Joyner }
4077*6f37f232SEric Joyner 
4078758cc3dcSJack F Vogel /*
4079758cc3dcSJack F Vogel  * Add sysctl variables, one per statistic, to the system.
4080758cc3dcSJack F Vogel  */
4081758cc3dcSJack F Vogel static void
4082758cc3dcSJack F Vogel ixgbe_add_hw_stats(struct adapter *adapter)
4083758cc3dcSJack F Vogel {
4084758cc3dcSJack F Vogel 	device_t dev = adapter->dev;
4085758cc3dcSJack F Vogel 
4086758cc3dcSJack F Vogel 	struct tx_ring *txr = adapter->tx_rings;
4087758cc3dcSJack F Vogel 	struct rx_ring *rxr = adapter->rx_rings;
4088758cc3dcSJack F Vogel 
4089758cc3dcSJack F Vogel 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
4090758cc3dcSJack F Vogel 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
4091758cc3dcSJack F Vogel 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
4092758cc3dcSJack F Vogel 	struct ixgbe_hw_stats *stats = &adapter->stats.pf;
4093758cc3dcSJack F Vogel 
4094758cc3dcSJack F Vogel 	struct sysctl_oid *stat_node, *queue_node;
4095758cc3dcSJack F Vogel 	struct sysctl_oid_list *stat_list, *queue_list;
4096758cc3dcSJack F Vogel 
4097758cc3dcSJack F Vogel #define QUEUE_NAME_LEN 32
4098758cc3dcSJack F Vogel 	char namebuf[QUEUE_NAME_LEN];
4099758cc3dcSJack F Vogel 
4100758cc3dcSJack F Vogel 	/* Driver Statistics */
4101758cc3dcSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped",
4102758cc3dcSJack F Vogel 			CTLFLAG_RD, &adapter->dropped_pkts,
4103758cc3dcSJack F Vogel 			"Driver dropped packets");
4104758cc3dcSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed",
4105758cc3dcSJack F Vogel 			CTLFLAG_RD, &adapter->mbuf_defrag_failed,
4106758cc3dcSJack F Vogel 			"m_defrag() failed");
4107758cc3dcSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
4108758cc3dcSJack F Vogel 			CTLFLAG_RD, &adapter->watchdog_events,
4109758cc3dcSJack F Vogel 			"Watchdog timeouts");
4110758cc3dcSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq",
4111*6f37f232SEric Joyner 			CTLFLAG_RD, &adapter->link_irq,
4112758cc3dcSJack F Vogel 			"Link MSIX IRQ Handled");
4113758cc3dcSJack F Vogel 
4114758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, txr++) {
4115758cc3dcSJack F Vogel 		snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i);
4116758cc3dcSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
4117758cc3dcSJack F Vogel 					    CTLFLAG_RD, NULL, "Queue Name");
4118758cc3dcSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
4119758cc3dcSJack F Vogel 
4120758cc3dcSJack F Vogel 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate",
4121758cc3dcSJack F Vogel 				CTLTYPE_UINT | CTLFLAG_RW, &adapter->queues[i],
4122758cc3dcSJack F Vogel 				sizeof(&adapter->queues[i]),
4123758cc3dcSJack F Vogel 				ixgbe_sysctl_interrupt_rate_handler, "IU",
4124758cc3dcSJack F Vogel 				"Interrupt Rate");
4125758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
4126758cc3dcSJack F Vogel 				CTLFLAG_RD, &(adapter->queues[i].irqs),
4127758cc3dcSJack F Vogel 				"irqs on this queue");
4128758cc3dcSJack F Vogel 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head",
4129758cc3dcSJack F Vogel 				CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr),
4130758cc3dcSJack F Vogel 				ixgbe_sysctl_tdh_handler, "IU",
4131758cc3dcSJack F Vogel 				"Transmit Descriptor Head");
4132758cc3dcSJack F Vogel 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail",
4133758cc3dcSJack F Vogel 				CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr),
4134758cc3dcSJack F Vogel 				ixgbe_sysctl_tdt_handler, "IU",
4135758cc3dcSJack F Vogel 				"Transmit Descriptor Tail");
4136758cc3dcSJack F Vogel 		SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx",
4137758cc3dcSJack F Vogel 				CTLFLAG_RD, &txr->tso_tx,
4138758cc3dcSJack F Vogel 				"TSO");
4139758cc3dcSJack F Vogel 		SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_tx_dma_setup",
4140758cc3dcSJack F Vogel 				CTLFLAG_RD, &txr->no_tx_dma_setup,
4141758cc3dcSJack F Vogel 				"Driver tx dma failure in xmit");
4142758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
4143758cc3dcSJack F Vogel 				CTLFLAG_RD, &txr->no_desc_avail,
4144758cc3dcSJack F Vogel 				"Queue No Descriptor Available");
4145758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
4146758cc3dcSJack F Vogel 				CTLFLAG_RD, &txr->total_packets,
4147758cc3dcSJack F Vogel 				"Queue Packets Transmitted");
4148625d12c6SJohn Baldwin 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops",
4149625d12c6SJohn Baldwin 				CTLFLAG_RD, &txr->br->br_drops,
4150625d12c6SJohn Baldwin 				"Packets dropped in buf_ring");
4151758cc3dcSJack F Vogel 	}
4152758cc3dcSJack F Vogel 
4153758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, rxr++) {
4154758cc3dcSJack F Vogel 		snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i);
4155758cc3dcSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
4156758cc3dcSJack F Vogel 					    CTLFLAG_RD, NULL, "Queue Name");
4157758cc3dcSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
4158758cc3dcSJack F Vogel 
4159758cc3dcSJack F Vogel 		struct lro_ctrl *lro = &rxr->lro;
4160758cc3dcSJack F Vogel 
4161758cc3dcSJack F Vogel 		snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i);
4162758cc3dcSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
4163758cc3dcSJack F Vogel 					    CTLFLAG_RD, NULL, "Queue Name");
4164758cc3dcSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
4165758cc3dcSJack F Vogel 
4166758cc3dcSJack F Vogel 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head",
4167758cc3dcSJack F Vogel 				CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr),
4168758cc3dcSJack F Vogel 				ixgbe_sysctl_rdh_handler, "IU",
4169758cc3dcSJack F Vogel 				"Receive Descriptor Head");
4170758cc3dcSJack F Vogel 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail",
4171758cc3dcSJack F Vogel 				CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr),
4172758cc3dcSJack F Vogel 				ixgbe_sysctl_rdt_handler, "IU",
4173758cc3dcSJack F Vogel 				"Receive Descriptor Tail");
4174758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
4175758cc3dcSJack F Vogel 				CTLFLAG_RD, &rxr->rx_packets,
4176758cc3dcSJack F Vogel 				"Queue Packets Received");
4177758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
4178758cc3dcSJack F Vogel 				CTLFLAG_RD, &rxr->rx_bytes,
4179758cc3dcSJack F Vogel 				"Queue Bytes Received");
4180758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies",
4181758cc3dcSJack F Vogel 				CTLFLAG_RD, &rxr->rx_copies,
4182758cc3dcSJack F Vogel 				"Copied RX Frames");
4183758cc3dcSJack F Vogel 		SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_queued",
4184758cc3dcSJack F Vogel 				CTLFLAG_RD, &lro->lro_queued, 0,
4185758cc3dcSJack F Vogel 				"LRO Queued");
4186758cc3dcSJack F Vogel 		SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_flushed",
4187758cc3dcSJack F Vogel 				CTLFLAG_RD, &lro->lro_flushed, 0,
4188758cc3dcSJack F Vogel 				"LRO Flushed");
4189758cc3dcSJack F Vogel 	}
4190758cc3dcSJack F Vogel 
4191758cc3dcSJack F Vogel 	/* MAC stats get the own sub node */
4192758cc3dcSJack F Vogel 
4193758cc3dcSJack F Vogel 	stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats",
4194758cc3dcSJack F Vogel 				    CTLFLAG_RD, NULL, "MAC Statistics");
4195758cc3dcSJack F Vogel 	stat_list = SYSCTL_CHILDREN(stat_node);
4196758cc3dcSJack F Vogel 
4197758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs",
4198758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->crcerrs,
4199758cc3dcSJack F Vogel 			"CRC Errors");
4200758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs",
4201758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->illerrc,
4202758cc3dcSJack F Vogel 			"Illegal Byte Errors");
4203758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs",
4204758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->errbc,
4205758cc3dcSJack F Vogel 			"Byte Errors");
4206758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards",
4207758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mspdc,
4208758cc3dcSJack F Vogel 			"MAC Short Packets Discarded");
4209758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults",
4210758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mlfc,
4211758cc3dcSJack F Vogel 			"MAC Local Faults");
4212758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults",
4213758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mrfc,
4214758cc3dcSJack F Vogel 			"MAC Remote Faults");
4215758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs",
4216758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->rlec,
4217758cc3dcSJack F Vogel 			"Receive Length Errors");
4218758cc3dcSJack F Vogel 
4219758cc3dcSJack F Vogel 	/* Flow Control stats */
4220758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd",
4221758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->lxontxc,
4222758cc3dcSJack F Vogel 			"Link XON Transmitted");
4223758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd",
4224758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->lxonrxc,
4225758cc3dcSJack F Vogel 			"Link XON Received");
4226758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd",
4227758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->lxofftxc,
4228758cc3dcSJack F Vogel 			"Link XOFF Transmitted");
4229758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd",
4230758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->lxoffrxc,
4231758cc3dcSJack F Vogel 			"Link XOFF Received");
4232758cc3dcSJack F Vogel 
4233758cc3dcSJack F Vogel 	/* Packet Reception Stats */
4234758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd",
4235758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->tor,
4236758cc3dcSJack F Vogel 			"Total Octets Received");
4237758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd",
4238758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->gorc,
4239758cc3dcSJack F Vogel 			"Good Octets Received");
4240758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd",
4241758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->tpr,
4242758cc3dcSJack F Vogel 			"Total Packets Received");
4243758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd",
4244758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->gprc,
4245758cc3dcSJack F Vogel 			"Good Packets Received");
4246758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd",
4247758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mprc,
4248758cc3dcSJack F Vogel 			"Multicast Packets Received");
4249758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd",
4250758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->bprc,
4251758cc3dcSJack F Vogel 			"Broadcast Packets Received");
4252758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64",
4253758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc64,
4254758cc3dcSJack F Vogel 			"64 byte frames received ");
4255758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127",
4256758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc127,
4257758cc3dcSJack F Vogel 			"65-127 byte frames received");
4258758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255",
4259758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc255,
4260758cc3dcSJack F Vogel 			"128-255 byte frames received");
4261758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511",
4262758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc511,
4263758cc3dcSJack F Vogel 			"256-511 byte frames received");
4264758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023",
4265758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc1023,
4266758cc3dcSJack F Vogel 			"512-1023 byte frames received");
4267758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522",
4268758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc1522,
4269758cc3dcSJack F Vogel 			"1023-1522 byte frames received");
4270758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized",
4271758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ruc,
4272758cc3dcSJack F Vogel 			"Receive Undersized");
4273758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented",
4274758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->rfc,
4275758cc3dcSJack F Vogel 			"Fragmented Packets Received ");
4276758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized",
4277758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->roc,
4278758cc3dcSJack F Vogel 			"Oversized Packets Received");
4279758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd",
4280758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->rjc,
4281758cc3dcSJack F Vogel 			"Received Jabber");
4282758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd",
4283758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mngprc,
4284758cc3dcSJack F Vogel 			"Management Packets Received");
4285758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd",
4286758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mngptc,
4287758cc3dcSJack F Vogel 			"Management Packets Dropped");
4288758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs",
4289758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->xec,
4290758cc3dcSJack F Vogel 			"Checksum Errors");
4291758cc3dcSJack F Vogel 
4292758cc3dcSJack F Vogel 	/* Packet Transmission Stats */
4293758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd",
4294758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->gotc,
4295758cc3dcSJack F Vogel 			"Good Octets Transmitted");
4296758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd",
4297758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->tpt,
4298758cc3dcSJack F Vogel 			"Total Packets Transmitted");
4299758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd",
4300758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->gptc,
4301758cc3dcSJack F Vogel 			"Good Packets Transmitted");
4302758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd",
4303758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->bptc,
4304758cc3dcSJack F Vogel 			"Broadcast Packets Transmitted");
4305758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd",
4306758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mptc,
4307758cc3dcSJack F Vogel 			"Multicast Packets Transmitted");
4308758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd",
4309758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mngptc,
4310758cc3dcSJack F Vogel 			"Management Packets Transmitted");
4311758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64",
4312758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc64,
4313758cc3dcSJack F Vogel 			"64 byte frames transmitted ");
4314758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127",
4315758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc127,
4316758cc3dcSJack F Vogel 			"65-127 byte frames transmitted");
4317758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255",
4318758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc255,
4319758cc3dcSJack F Vogel 			"128-255 byte frames transmitted");
4320758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511",
4321758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc511,
4322758cc3dcSJack F Vogel 			"256-511 byte frames transmitted");
4323758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023",
4324758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc1023,
4325758cc3dcSJack F Vogel 			"512-1023 byte frames transmitted");
4326758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522",
4327758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc1522,
4328758cc3dcSJack F Vogel 			"1024-1522 byte frames transmitted");
4329758cc3dcSJack F Vogel }
4330758cc3dcSJack F Vogel 
4331758cc3dcSJack F Vogel /*
4332758cc3dcSJack F Vogel ** Set flow control using sysctl:
4333758cc3dcSJack F Vogel ** Flow control values:
4334758cc3dcSJack F Vogel ** 	0 - off
4335758cc3dcSJack F Vogel **	1 - rx pause
4336758cc3dcSJack F Vogel **	2 - tx pause
4337758cc3dcSJack F Vogel **	3 - full
4338758cc3dcSJack F Vogel */
4339758cc3dcSJack F Vogel static int
4340758cc3dcSJack F Vogel ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS)
4341758cc3dcSJack F Vogel {
4342758cc3dcSJack F Vogel 	int error, last;
4343758cc3dcSJack F Vogel 	struct adapter *adapter = (struct adapter *) arg1;
4344758cc3dcSJack F Vogel 
4345758cc3dcSJack F Vogel 	last = adapter->fc;
4346758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &adapter->fc, 0, req);
4347758cc3dcSJack F Vogel 	if ((error) || (req->newptr == NULL))
4348758cc3dcSJack F Vogel 		return (error);
4349758cc3dcSJack F Vogel 
4350758cc3dcSJack F Vogel 	/* Don't bother if it's not changed */
4351758cc3dcSJack F Vogel 	if (adapter->fc == last)
4352758cc3dcSJack F Vogel 		return (0);
4353758cc3dcSJack F Vogel 
4354758cc3dcSJack F Vogel 	switch (adapter->fc) {
4355758cc3dcSJack F Vogel 		case ixgbe_fc_rx_pause:
4356758cc3dcSJack F Vogel 		case ixgbe_fc_tx_pause:
4357758cc3dcSJack F Vogel 		case ixgbe_fc_full:
4358758cc3dcSJack F Vogel 			adapter->hw.fc.requested_mode = adapter->fc;
4359758cc3dcSJack F Vogel 			if (adapter->num_queues > 1)
4360758cc3dcSJack F Vogel 				ixgbe_disable_rx_drop(adapter);
4361758cc3dcSJack F Vogel 			break;
4362758cc3dcSJack F Vogel 		case ixgbe_fc_none:
4363758cc3dcSJack F Vogel 			adapter->hw.fc.requested_mode = ixgbe_fc_none;
4364758cc3dcSJack F Vogel 			if (adapter->num_queues > 1)
4365758cc3dcSJack F Vogel 				ixgbe_enable_rx_drop(adapter);
4366758cc3dcSJack F Vogel 			break;
4367758cc3dcSJack F Vogel 		default:
4368758cc3dcSJack F Vogel 			adapter->fc = last;
4369758cc3dcSJack F Vogel 			return (EINVAL);
4370758cc3dcSJack F Vogel 	}
4371758cc3dcSJack F Vogel 	/* Don't autoneg if forcing a value */
4372758cc3dcSJack F Vogel 	adapter->hw.fc.disable_fc_autoneg = TRUE;
4373758cc3dcSJack F Vogel 	ixgbe_fc_enable(&adapter->hw);
4374758cc3dcSJack F Vogel 	return error;
4375758cc3dcSJack F Vogel }
4376758cc3dcSJack F Vogel 
4377758cc3dcSJack F Vogel /*
4378758cc3dcSJack F Vogel ** Control advertised link speed:
4379758cc3dcSJack F Vogel **	Flags:
4380758cc3dcSJack F Vogel **	0x1 - advertise 100 Mb
4381758cc3dcSJack F Vogel **	0x2 - advertise 1G
4382758cc3dcSJack F Vogel **	0x4 - advertise 10G
4383758cc3dcSJack F Vogel */
4384758cc3dcSJack F Vogel static int
4385758cc3dcSJack F Vogel ixgbe_set_advertise(SYSCTL_HANDLER_ARGS)
4386758cc3dcSJack F Vogel {
4387758cc3dcSJack F Vogel 	int			error = 0, requested;
4388758cc3dcSJack F Vogel 	struct adapter		*adapter;
4389758cc3dcSJack F Vogel 	device_t		dev;
4390758cc3dcSJack F Vogel 	struct ixgbe_hw		*hw;
4391758cc3dcSJack F Vogel 	ixgbe_link_speed	speed = 0;
4392758cc3dcSJack F Vogel 
4393758cc3dcSJack F Vogel 	adapter = (struct adapter *) arg1;
4394758cc3dcSJack F Vogel 	dev = adapter->dev;
4395758cc3dcSJack F Vogel 	hw = &adapter->hw;
4396758cc3dcSJack F Vogel 
4397758cc3dcSJack F Vogel 	requested = adapter->advertise;
4398758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &requested, 0, req);
4399758cc3dcSJack F Vogel 	if ((error) || (req->newptr == NULL))
4400758cc3dcSJack F Vogel 		return (error);
4401758cc3dcSJack F Vogel 
4402758cc3dcSJack F Vogel 	/* Checks to validate new value */
4403758cc3dcSJack F Vogel 	if (adapter->advertise == requested) /* no change */
4404758cc3dcSJack F Vogel 		return (0);
4405758cc3dcSJack F Vogel 
4406758cc3dcSJack F Vogel 	if (!((hw->phy.media_type == ixgbe_media_type_copper) ||
4407758cc3dcSJack F Vogel 	    (hw->phy.multispeed_fiber))) {
4408758cc3dcSJack F Vogel 		device_printf(dev,
4409758cc3dcSJack F Vogel 		    "Advertised speed can only be set on copper or "
4410758cc3dcSJack F Vogel 		    "multispeed fiber media types.\n");
4411758cc3dcSJack F Vogel 		return (EINVAL);
4412758cc3dcSJack F Vogel 	}
4413758cc3dcSJack F Vogel 
4414758cc3dcSJack F Vogel 	if (requested < 0x1 || requested > 0x7) {
4415758cc3dcSJack F Vogel 		device_printf(dev,
4416758cc3dcSJack F Vogel 		    "Invalid advertised speed; valid modes are 0x1 through 0x7\n");
4417758cc3dcSJack F Vogel 		return (EINVAL);
4418758cc3dcSJack F Vogel 	}
4419758cc3dcSJack F Vogel 
4420758cc3dcSJack F Vogel 	if ((requested & 0x1)
4421758cc3dcSJack F Vogel 	    && (hw->mac.type != ixgbe_mac_X540)
4422758cc3dcSJack F Vogel 	    && (hw->mac.type != ixgbe_mac_X550)) {
4423758cc3dcSJack F Vogel 		device_printf(dev, "Set Advertise: 100Mb on X540/X550 only\n");
4424758cc3dcSJack F Vogel 		return (EINVAL);
4425758cc3dcSJack F Vogel 	}
4426758cc3dcSJack F Vogel 
4427758cc3dcSJack F Vogel 	/* Set new value and report new advertised mode */
4428758cc3dcSJack F Vogel 	if (requested & 0x1)
4429758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_100_FULL;
4430758cc3dcSJack F Vogel 	if (requested & 0x2)
4431758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
4432758cc3dcSJack F Vogel 	if (requested & 0x4)
4433758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_10GB_FULL;
4434758cc3dcSJack F Vogel 
4435758cc3dcSJack F Vogel 	hw->mac.autotry_restart = TRUE;
4436758cc3dcSJack F Vogel 	hw->mac.ops.setup_link(hw, speed, TRUE);
4437758cc3dcSJack F Vogel 	adapter->advertise = requested;
4438758cc3dcSJack F Vogel 
4439758cc3dcSJack F Vogel 	return (error);
4440758cc3dcSJack F Vogel }
4441758cc3dcSJack F Vogel 
4442758cc3dcSJack F Vogel /*
4443*6f37f232SEric Joyner  * The following two sysctls are for X550 BaseT devices;
4444*6f37f232SEric Joyner  * they deal with the external PHY used in them.
4445758cc3dcSJack F Vogel  */
4446758cc3dcSJack F Vogel static int
4447*6f37f232SEric Joyner ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS)
4448758cc3dcSJack F Vogel {
4449758cc3dcSJack F Vogel 	struct adapter	*adapter = (struct adapter *) arg1;
4450758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
4451*6f37f232SEric Joyner 	u16 reg;
4452758cc3dcSJack F Vogel 
4453*6f37f232SEric Joyner 	if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
4454*6f37f232SEric Joyner 		device_printf(adapter->dev,
4455*6f37f232SEric Joyner 		    "Device has no supported external thermal sensor.\n");
4456*6f37f232SEric Joyner 		return (ENODEV);
4457*6f37f232SEric Joyner 	}
4458758cc3dcSJack F Vogel 
4459*6f37f232SEric Joyner 	if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP,
4460*6f37f232SEric Joyner 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
4461*6f37f232SEric Joyner 				      &reg)) {
4462*6f37f232SEric Joyner 		device_printf(adapter->dev,
4463*6f37f232SEric Joyner 		    "Error reading from PHY's current temperature register\n");
4464*6f37f232SEric Joyner 		return (EAGAIN);
4465*6f37f232SEric Joyner 	}
4466*6f37f232SEric Joyner 
4467*6f37f232SEric Joyner 	/* Shift temp for output */
4468*6f37f232SEric Joyner 	reg = reg >> 8;
4469*6f37f232SEric Joyner 
4470*6f37f232SEric Joyner 	return (sysctl_handle_int(oidp, NULL, reg, req));
4471*6f37f232SEric Joyner }
4472*6f37f232SEric Joyner 
4473*6f37f232SEric Joyner /*
4474*6f37f232SEric Joyner  * Reports whether the current PHY temperature is over
4475*6f37f232SEric Joyner  * the overtemp threshold.
4476*6f37f232SEric Joyner  *  - This is reported directly from the PHY
4477*6f37f232SEric Joyner  */
4478*6f37f232SEric Joyner static int
4479*6f37f232SEric Joyner ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS)
4480*6f37f232SEric Joyner {
4481*6f37f232SEric Joyner 	struct adapter	*adapter = (struct adapter *) arg1;
4482*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
4483*6f37f232SEric Joyner 	u16 reg;
4484*6f37f232SEric Joyner 
4485*6f37f232SEric Joyner 	if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
4486*6f37f232SEric Joyner 		device_printf(adapter->dev,
4487*6f37f232SEric Joyner 		    "Device has no supported external thermal sensor.\n");
4488*6f37f232SEric Joyner 		return (ENODEV);
4489*6f37f232SEric Joyner 	}
4490*6f37f232SEric Joyner 
4491*6f37f232SEric Joyner 	if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS,
4492*6f37f232SEric Joyner 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
4493*6f37f232SEric Joyner 				      &reg)) {
4494*6f37f232SEric Joyner 		device_printf(adapter->dev,
4495*6f37f232SEric Joyner 		    "Error reading from PHY's temperature status register\n");
4496*6f37f232SEric Joyner 		return (EAGAIN);
4497*6f37f232SEric Joyner 	}
4498*6f37f232SEric Joyner 
4499*6f37f232SEric Joyner 	/* Get occurrence bit */
4500*6f37f232SEric Joyner 	reg = !!(reg & 0x4000);
4501*6f37f232SEric Joyner 	return (sysctl_handle_int(oidp, 0, reg, req));
4502*6f37f232SEric Joyner }
4503*6f37f232SEric Joyner 
4504*6f37f232SEric Joyner /*
4505*6f37f232SEric Joyner ** Thermal Shutdown Trigger (internal MAC)
4506*6f37f232SEric Joyner **   - Set this to 1 to cause an overtemp event to occur
4507*6f37f232SEric Joyner */
4508*6f37f232SEric Joyner static int
4509*6f37f232SEric Joyner ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS)
4510*6f37f232SEric Joyner {
4511*6f37f232SEric Joyner 	struct adapter	*adapter = (struct adapter *) arg1;
4512*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
4513*6f37f232SEric Joyner 	int error, fire = 0;
4514758cc3dcSJack F Vogel 
4515758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &fire, 0, req);
4516758cc3dcSJack F Vogel 	if ((error) || (req->newptr == NULL))
4517758cc3dcSJack F Vogel 		return (error);
4518758cc3dcSJack F Vogel 
4519758cc3dcSJack F Vogel 	if (fire) {
4520758cc3dcSJack F Vogel 		u32 reg = IXGBE_READ_REG(hw, IXGBE_EICS);
4521758cc3dcSJack F Vogel 		reg |= IXGBE_EICR_TS;
4522758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_EICS, reg);
4523758cc3dcSJack F Vogel 	}
4524758cc3dcSJack F Vogel 
4525758cc3dcSJack F Vogel 	return (0);
4526758cc3dcSJack F Vogel }
4527758cc3dcSJack F Vogel 
4528758cc3dcSJack F Vogel /*
4529*6f37f232SEric Joyner ** Manage DMA Coalescing.
4530*6f37f232SEric Joyner ** Control values:
4531*6f37f232SEric Joyner ** 	0/1 - off / on (use default value of 1000)
4532*6f37f232SEric Joyner **
4533*6f37f232SEric Joyner **	Legal timer values are:
4534*6f37f232SEric Joyner **	50,100,250,500,1000,2000,5000,10000
4535*6f37f232SEric Joyner **
4536*6f37f232SEric Joyner **	Turning off interrupt moderation will also turn this off.
4537*6f37f232SEric Joyner */
4538*6f37f232SEric Joyner static int
4539*6f37f232SEric Joyner ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS)
4540*6f37f232SEric Joyner {
4541*6f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
4542*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
4543*6f37f232SEric Joyner 	struct ifnet *ifp = adapter->ifp;
4544*6f37f232SEric Joyner 	int		error;
4545*6f37f232SEric Joyner 	u16		oldval;
4546*6f37f232SEric Joyner 
4547*6f37f232SEric Joyner 	oldval = adapter->dmac;
4548*6f37f232SEric Joyner 	error = sysctl_handle_int(oidp, &adapter->dmac, 0, req);
4549*6f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
4550*6f37f232SEric Joyner 		return (error);
4551*6f37f232SEric Joyner 
4552*6f37f232SEric Joyner 	switch (hw->mac.type) {
4553*6f37f232SEric Joyner 	case ixgbe_mac_X550:
4554*6f37f232SEric Joyner 	case ixgbe_mac_X550EM_x:
4555*6f37f232SEric Joyner 		break;
4556*6f37f232SEric Joyner 	default:
4557*6f37f232SEric Joyner 		device_printf(adapter->dev,
4558*6f37f232SEric Joyner 		    "DMA Coalescing is only supported on X550 devices\n");
4559*6f37f232SEric Joyner 		return (ENODEV);
4560*6f37f232SEric Joyner 	}
4561*6f37f232SEric Joyner 
4562*6f37f232SEric Joyner 	switch (adapter->dmac) {
4563*6f37f232SEric Joyner 	case 0:
4564*6f37f232SEric Joyner 		/* Disabled */
4565*6f37f232SEric Joyner 		break;
4566*6f37f232SEric Joyner 	case 1: /* Enable and use default */
4567*6f37f232SEric Joyner 		adapter->dmac = 1000;
4568*6f37f232SEric Joyner 		break;
4569*6f37f232SEric Joyner 	case 50:
4570*6f37f232SEric Joyner 	case 100:
4571*6f37f232SEric Joyner 	case 250:
4572*6f37f232SEric Joyner 	case 500:
4573*6f37f232SEric Joyner 	case 1000:
4574*6f37f232SEric Joyner 	case 2000:
4575*6f37f232SEric Joyner 	case 5000:
4576*6f37f232SEric Joyner 	case 10000:
4577*6f37f232SEric Joyner 		/* Legal values - allow */
4578*6f37f232SEric Joyner 		break;
4579*6f37f232SEric Joyner 	default:
4580*6f37f232SEric Joyner 		/* Do nothing, illegal value */
4581*6f37f232SEric Joyner 		adapter->dmac = oldval;
4582*6f37f232SEric Joyner 		return (EINVAL);
4583*6f37f232SEric Joyner 	}
4584*6f37f232SEric Joyner 
4585*6f37f232SEric Joyner 	/* Re-initialize hardware if it's already running */
4586*6f37f232SEric Joyner 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
4587*6f37f232SEric Joyner 		ixgbe_init(adapter);
4588*6f37f232SEric Joyner 
4589*6f37f232SEric Joyner 	return (0);
4590*6f37f232SEric Joyner }
4591*6f37f232SEric Joyner 
4592*6f37f232SEric Joyner /*
4593*6f37f232SEric Joyner  * Sysctl to enable/disable the WoL capability, if supported by the adapter.
4594*6f37f232SEric Joyner  * Values:
4595*6f37f232SEric Joyner  *	0 - disabled
4596*6f37f232SEric Joyner  *	1 - enabled
4597*6f37f232SEric Joyner  */
4598*6f37f232SEric Joyner static int
4599*6f37f232SEric Joyner ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS)
4600*6f37f232SEric Joyner {
4601*6f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
4602*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
4603*6f37f232SEric Joyner 	int new_wol_enabled;
4604*6f37f232SEric Joyner 	int error = 0;
4605*6f37f232SEric Joyner 
4606*6f37f232SEric Joyner 	new_wol_enabled = hw->wol_enabled;
4607*6f37f232SEric Joyner 	error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req);
4608*6f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
4609*6f37f232SEric Joyner 		return (error);
4610*6f37f232SEric Joyner 	if (new_wol_enabled == hw->wol_enabled)
4611*6f37f232SEric Joyner 		return (0);
4612*6f37f232SEric Joyner 
4613*6f37f232SEric Joyner 	if (new_wol_enabled > 0 && !adapter->wol_support)
4614*6f37f232SEric Joyner 		return (ENODEV);
4615*6f37f232SEric Joyner 	else
4616*6f37f232SEric Joyner 		hw->wol_enabled = !!(new_wol_enabled);
4617*6f37f232SEric Joyner 
4618*6f37f232SEric Joyner 	return (0);
4619*6f37f232SEric Joyner }
4620*6f37f232SEric Joyner 
4621*6f37f232SEric Joyner /*
4622*6f37f232SEric Joyner  * Sysctl to enable/disable the Energy Efficient Ethernet capability,
4623*6f37f232SEric Joyner  * if supported by the adapter.
4624*6f37f232SEric Joyner  * Values:
4625*6f37f232SEric Joyner  *	0 - disabled
4626*6f37f232SEric Joyner  *	1 - enabled
4627*6f37f232SEric Joyner  */
4628*6f37f232SEric Joyner static int
4629*6f37f232SEric Joyner ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS)
4630*6f37f232SEric Joyner {
4631*6f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
4632*6f37f232SEric Joyner 	struct ifnet *ifp = adapter->ifp;
4633*6f37f232SEric Joyner 	int new_eee_enabled, error = 0;
4634*6f37f232SEric Joyner 
4635*6f37f232SEric Joyner 	new_eee_enabled = adapter->eee_enabled;
4636*6f37f232SEric Joyner 	error = sysctl_handle_int(oidp, &new_eee_enabled, 0, req);
4637*6f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
4638*6f37f232SEric Joyner 		return (error);
4639*6f37f232SEric Joyner 	if (new_eee_enabled == adapter->eee_enabled)
4640*6f37f232SEric Joyner 		return (0);
4641*6f37f232SEric Joyner 
4642*6f37f232SEric Joyner 	if (new_eee_enabled > 0 && !adapter->eee_support)
4643*6f37f232SEric Joyner 		return (ENODEV);
4644*6f37f232SEric Joyner 	else
4645*6f37f232SEric Joyner 		adapter->eee_enabled = !!(new_eee_enabled);
4646*6f37f232SEric Joyner 
4647*6f37f232SEric Joyner 	/* Re-initialize hardware if it's already running */
4648*6f37f232SEric Joyner 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
4649*6f37f232SEric Joyner 		ixgbe_init(adapter);
4650*6f37f232SEric Joyner 
4651*6f37f232SEric Joyner 	return (0);
4652*6f37f232SEric Joyner }
4653*6f37f232SEric Joyner 
4654*6f37f232SEric Joyner /*
4655*6f37f232SEric Joyner  * Read-only sysctl indicating whether EEE support was negotiated
4656*6f37f232SEric Joyner  * on the link.
4657*6f37f232SEric Joyner  */
4658*6f37f232SEric Joyner static int
4659*6f37f232SEric Joyner ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS)
4660*6f37f232SEric Joyner {
4661*6f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
4662*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
4663*6f37f232SEric Joyner 	bool status;
4664*6f37f232SEric Joyner 
4665*6f37f232SEric Joyner 	status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & IXGBE_EEE_STAT_NEG);
4666*6f37f232SEric Joyner 
4667*6f37f232SEric Joyner 	return (sysctl_handle_int(oidp, 0, status, req));
4668*6f37f232SEric Joyner }
4669*6f37f232SEric Joyner 
4670*6f37f232SEric Joyner /*
4671*6f37f232SEric Joyner  * Read-only sysctl indicating whether RX Link is in LPI state.
4672*6f37f232SEric Joyner  */
4673*6f37f232SEric Joyner static int
4674*6f37f232SEric Joyner ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS)
4675*6f37f232SEric Joyner {
4676*6f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
4677*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
4678*6f37f232SEric Joyner 	bool status;
4679*6f37f232SEric Joyner 
4680*6f37f232SEric Joyner 	status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) &
4681*6f37f232SEric Joyner 	    IXGBE_EEE_RX_LPI_STATUS);
4682*6f37f232SEric Joyner 
4683*6f37f232SEric Joyner 	return (sysctl_handle_int(oidp, 0, status, req));
4684*6f37f232SEric Joyner }
4685*6f37f232SEric Joyner 
4686*6f37f232SEric Joyner /*
4687*6f37f232SEric Joyner  * Read-only sysctl indicating whether TX Link is in LPI state.
4688*6f37f232SEric Joyner  */
4689*6f37f232SEric Joyner static int
4690*6f37f232SEric Joyner ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS)
4691*6f37f232SEric Joyner {
4692*6f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
4693*6f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
4694*6f37f232SEric Joyner 	bool status;
4695*6f37f232SEric Joyner 
4696*6f37f232SEric Joyner 	status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) &
4697*6f37f232SEric Joyner 	    IXGBE_EEE_TX_LPI_STATUS);
4698*6f37f232SEric Joyner 
4699*6f37f232SEric Joyner 	return (sysctl_handle_int(oidp, 0, status, req));
4700*6f37f232SEric Joyner }
4701*6f37f232SEric Joyner 
4702*6f37f232SEric Joyner /*
4703*6f37f232SEric Joyner  * Sysctl to enable/disable the types of packets that the
4704*6f37f232SEric Joyner  * adapter will wake up on upon receipt.
4705*6f37f232SEric Joyner  * WUFC - Wake Up Filter Control
4706*6f37f232SEric Joyner  * Flags:
4707*6f37f232SEric Joyner  *	0x1  - Link Status Change
4708*6f37f232SEric Joyner  *	0x2  - Magic Packet
4709*6f37f232SEric Joyner  *	0x4  - Direct Exact
4710*6f37f232SEric Joyner  *	0x8  - Directed Multicast
4711*6f37f232SEric Joyner  *	0x10 - Broadcast
4712*6f37f232SEric Joyner  *	0x20 - ARP/IPv4 Request Packet
4713*6f37f232SEric Joyner  *	0x40 - Direct IPv4 Packet
4714*6f37f232SEric Joyner  *	0x80 - Direct IPv6 Packet
4715*6f37f232SEric Joyner  *
4716*6f37f232SEric Joyner  * Setting another flag will cause the sysctl to return an
4717*6f37f232SEric Joyner  * error.
4718*6f37f232SEric Joyner  */
4719*6f37f232SEric Joyner static int
4720*6f37f232SEric Joyner ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS)
4721*6f37f232SEric Joyner {
4722*6f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
4723*6f37f232SEric Joyner 	int error = 0;
4724*6f37f232SEric Joyner 	u32 new_wufc;
4725*6f37f232SEric Joyner 
4726*6f37f232SEric Joyner 	new_wufc = adapter->wufc;
4727*6f37f232SEric Joyner 
4728*6f37f232SEric Joyner 	error = sysctl_handle_int(oidp, &new_wufc, 0, req);
4729*6f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
4730*6f37f232SEric Joyner 		return (error);
4731*6f37f232SEric Joyner 	if (new_wufc == adapter->wufc)
4732*6f37f232SEric Joyner 		return (0);
4733*6f37f232SEric Joyner 
4734*6f37f232SEric Joyner 	if (new_wufc & 0xffffff00)
4735*6f37f232SEric Joyner 		return (EINVAL);
4736*6f37f232SEric Joyner 	else {
4737*6f37f232SEric Joyner 		new_wufc &= 0xff;
4738*6f37f232SEric Joyner 		new_wufc |= (0xffffff & adapter->wufc);
4739*6f37f232SEric Joyner 		adapter->wufc = new_wufc;
4740*6f37f232SEric Joyner 	}
4741*6f37f232SEric Joyner 
4742*6f37f232SEric Joyner 	return (0);
4743*6f37f232SEric Joyner }
4744*6f37f232SEric Joyner 
4745*6f37f232SEric Joyner /*
4746758cc3dcSJack F Vogel ** Enable the hardware to drop packets when the buffer is
4747758cc3dcSJack F Vogel ** full. This is useful when multiqueue,so that no single
4748758cc3dcSJack F Vogel ** queue being full stalls the entire RX engine. We only
4749758cc3dcSJack F Vogel ** enable this when Multiqueue AND when Flow Control is
4750758cc3dcSJack F Vogel ** disabled.
4751758cc3dcSJack F Vogel */
4752758cc3dcSJack F Vogel static void
4753758cc3dcSJack F Vogel ixgbe_enable_rx_drop(struct adapter *adapter)
4754758cc3dcSJack F Vogel {
4755758cc3dcSJack F Vogel         struct ixgbe_hw *hw = &adapter->hw;
4756758cc3dcSJack F Vogel 
4757758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++) {
4758758cc3dcSJack F Vogel         	u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i));
4759758cc3dcSJack F Vogel         	srrctl |= IXGBE_SRRCTL_DROP_EN;
4760758cc3dcSJack F Vogel         	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl);
4761758cc3dcSJack F Vogel 	}
4762758cc3dcSJack F Vogel }
4763758cc3dcSJack F Vogel 
4764758cc3dcSJack F Vogel static void
4765758cc3dcSJack F Vogel ixgbe_disable_rx_drop(struct adapter *adapter)
4766758cc3dcSJack F Vogel {
4767758cc3dcSJack F Vogel         struct ixgbe_hw *hw = &adapter->hw;
4768758cc3dcSJack F Vogel 
4769758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++) {
4770758cc3dcSJack F Vogel         	u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i));
4771758cc3dcSJack F Vogel         	srrctl &= ~IXGBE_SRRCTL_DROP_EN;
4772758cc3dcSJack F Vogel         	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl);
4773758cc3dcSJack F Vogel 	}
4774758cc3dcSJack F Vogel }
4775758cc3dcSJack F Vogel 
4776758cc3dcSJack F Vogel static void
4777758cc3dcSJack F Vogel ixgbe_rearm_queues(struct adapter *adapter, u64 queues)
4778758cc3dcSJack F Vogel {
4779758cc3dcSJack F Vogel 	u32 mask;
4780758cc3dcSJack F Vogel 
4781758cc3dcSJack F Vogel 	switch (adapter->hw.mac.type) {
4782758cc3dcSJack F Vogel 	case ixgbe_mac_82598EB:
4783758cc3dcSJack F Vogel 		mask = (IXGBE_EIMS_RTX_QUEUE & queues);
4784758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask);
4785758cc3dcSJack F Vogel 		break;
4786758cc3dcSJack F Vogel 	case ixgbe_mac_82599EB:
4787758cc3dcSJack F Vogel 	case ixgbe_mac_X540:
4788758cc3dcSJack F Vogel 	case ixgbe_mac_X550:
4789*6f37f232SEric Joyner 	case ixgbe_mac_X550EM_x:
4790758cc3dcSJack F Vogel 		mask = (queues & 0xFFFFFFFF);
4791758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask);
4792758cc3dcSJack F Vogel 		mask = (queues >> 32);
4793758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask);
4794758cc3dcSJack F Vogel 		break;
4795758cc3dcSJack F Vogel 	default:
4796758cc3dcSJack F Vogel 		break;
4797758cc3dcSJack F Vogel 	}
4798758cc3dcSJack F Vogel }
4799758cc3dcSJack F Vogel 
4800758cc3dcSJack F Vogel 
4801