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