xref: /freebsd/sys/dev/ixgbe/if_ix.c (revision d775d23ac56a7a14ce4ca2aae7539cb757722859)
1758cc3dcSJack F Vogel /******************************************************************************
2758cc3dcSJack F Vogel 
3758cc3dcSJack F Vogel   Copyright (c) 2001-2015, Intel Corporation
4758cc3dcSJack F Vogel   All rights reserved.
5758cc3dcSJack F Vogel 
6758cc3dcSJack F Vogel   Redistribution and use in source and binary forms, with or without
7758cc3dcSJack F Vogel   modification, are permitted provided that the following conditions are met:
8758cc3dcSJack F Vogel 
9758cc3dcSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
10758cc3dcSJack F Vogel       this list of conditions and the following disclaimer.
11758cc3dcSJack F Vogel 
12758cc3dcSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
13758cc3dcSJack F Vogel       notice, this list of conditions and the following disclaimer in the
14758cc3dcSJack F Vogel       documentation and/or other materials provided with the distribution.
15758cc3dcSJack F Vogel 
16758cc3dcSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
17758cc3dcSJack F Vogel       contributors may be used to endorse or promote products derived from
18758cc3dcSJack F Vogel       this software without specific prior written permission.
19758cc3dcSJack F Vogel 
20758cc3dcSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21758cc3dcSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22758cc3dcSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23758cc3dcSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24758cc3dcSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25758cc3dcSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26758cc3dcSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27758cc3dcSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28758cc3dcSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29758cc3dcSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30758cc3dcSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
31758cc3dcSJack F Vogel 
32758cc3dcSJack F Vogel ******************************************************************************/
33758cc3dcSJack F Vogel /*$FreeBSD$*/
34758cc3dcSJack F Vogel 
35758cc3dcSJack F Vogel 
36758cc3dcSJack F Vogel #ifndef IXGBE_STANDALONE_BUILD
37758cc3dcSJack F Vogel #include "opt_inet.h"
38758cc3dcSJack F Vogel #include "opt_inet6.h"
39758cc3dcSJack F Vogel #include "opt_rss.h"
40758cc3dcSJack F Vogel #endif
41758cc3dcSJack F Vogel 
42758cc3dcSJack F Vogel #include "ixgbe.h"
43758cc3dcSJack F Vogel 
44758cc3dcSJack F Vogel #ifdef	RSS
45a1edda90SAdrian Chadd #include <net/rss_config.h>
46758cc3dcSJack F Vogel #include <netinet/in_rss.h>
47758cc3dcSJack F Vogel #endif
48758cc3dcSJack F Vogel 
49758cc3dcSJack F Vogel /*********************************************************************
50758cc3dcSJack F Vogel  *  Driver version
51758cc3dcSJack F Vogel  *********************************************************************/
52a9ca1c79SSean Bruno char ixgbe_driver_version[] = "3.1.13-k";
53a9ca1c79SSean Bruno 
54758cc3dcSJack F Vogel 
55758cc3dcSJack F Vogel /*********************************************************************
56758cc3dcSJack F Vogel  *  PCI Device ID Table
57758cc3dcSJack F Vogel  *
58758cc3dcSJack F Vogel  *  Used by probe to select devices to load on
59758cc3dcSJack F Vogel  *  Last field stores an index into ixgbe_strings
60758cc3dcSJack F Vogel  *  Last entry must be all 0s
61758cc3dcSJack F Vogel  *
62758cc3dcSJack F Vogel  *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
63758cc3dcSJack F Vogel  *********************************************************************/
64758cc3dcSJack F Vogel 
65758cc3dcSJack F Vogel static ixgbe_vendor_info_t ixgbe_vendor_info_array[] =
66758cc3dcSJack F Vogel {
67758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT, 0, 0, 0},
68758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT, 0, 0, 0},
69758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4, 0, 0, 0},
70758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT, 0, 0, 0},
71758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT2, 0, 0, 0},
72758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598, 0, 0, 0},
73758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_DA_DUAL_PORT, 0, 0, 0},
74758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_CX4_DUAL_PORT, 0, 0, 0},
75758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_XF_LR, 0, 0, 0},
76758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM, 0, 0, 0},
77758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_SFP_LOM, 0, 0, 0},
78758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4, 0, 0, 0},
79758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4_MEZZ, 0, 0, 0},
80758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP, 0, 0, 0},
81758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_XAUI_LOM, 0, 0, 0},
82758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_CX4, 0, 0, 0},
83758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_T3_LOM, 0, 0, 0},
84758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_COMBO_BACKPLANE, 0, 0, 0},
85758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BACKPLANE_FCOE, 0, 0, 0},
86758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF2, 0, 0, 0},
87758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_FCOE, 0, 0, 0},
88758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599EN_SFP, 0, 0, 0},
89758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF_QP, 0, 0, 0},
90758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_QSFP_SF_QP, 0, 0, 0},
91758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T, 0, 0, 0},
92758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T1, 0, 0, 0},
93758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T, 0, 0, 0},
94a9ca1c79SSean Bruno 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550T1, 0, 0, 0},
95758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KR, 0, 0, 0},
96758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KX4, 0, 0, 0},
97758cc3dcSJack F Vogel 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_10G_T, 0, 0, 0},
98a9ca1c79SSean Bruno 	{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_SFP, 0, 0, 0},
99758cc3dcSJack F Vogel 	/* required last entry */
100758cc3dcSJack F Vogel 	{0, 0, 0, 0, 0}
101758cc3dcSJack F Vogel };
102758cc3dcSJack F Vogel 
103758cc3dcSJack F Vogel /*********************************************************************
104758cc3dcSJack F Vogel  *  Table of branding strings
105758cc3dcSJack F Vogel  *********************************************************************/
106758cc3dcSJack F Vogel 
107758cc3dcSJack F Vogel static char    *ixgbe_strings[] = {
108758cc3dcSJack F Vogel 	"Intel(R) PRO/10GbE PCI-Express Network Driver"
109758cc3dcSJack F Vogel };
110758cc3dcSJack F Vogel 
111758cc3dcSJack F Vogel /*********************************************************************
112758cc3dcSJack F Vogel  *  Function prototypes
113758cc3dcSJack F Vogel  *********************************************************************/
114758cc3dcSJack F Vogel static int      ixgbe_probe(device_t);
115758cc3dcSJack F Vogel static int      ixgbe_attach(device_t);
116758cc3dcSJack F Vogel static int      ixgbe_detach(device_t);
117758cc3dcSJack F Vogel static int      ixgbe_shutdown(device_t);
1186f37f232SEric Joyner static int	ixgbe_suspend(device_t);
1196f37f232SEric Joyner static int	ixgbe_resume(device_t);
120758cc3dcSJack F Vogel static int      ixgbe_ioctl(struct ifnet *, u_long, caddr_t);
121758cc3dcSJack F Vogel static void	ixgbe_init(void *);
122758cc3dcSJack F Vogel static void	ixgbe_init_locked(struct adapter *);
123758cc3dcSJack F Vogel static void     ixgbe_stop(void *);
124758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036
125758cc3dcSJack F Vogel static uint64_t	ixgbe_get_counter(struct ifnet *, ift_counter);
126758cc3dcSJack F Vogel #endif
127758cc3dcSJack F Vogel static void	ixgbe_add_media_types(struct adapter *);
128758cc3dcSJack F Vogel static void     ixgbe_media_status(struct ifnet *, struct ifmediareq *);
129758cc3dcSJack F Vogel static int      ixgbe_media_change(struct ifnet *);
130758cc3dcSJack F Vogel static void     ixgbe_identify_hardware(struct adapter *);
131758cc3dcSJack F Vogel static int      ixgbe_allocate_pci_resources(struct adapter *);
132a9ca1c79SSean Bruno static void	ixgbe_get_slot_info(struct adapter *);
133758cc3dcSJack F Vogel static int      ixgbe_allocate_msix(struct adapter *);
134758cc3dcSJack F Vogel static int      ixgbe_allocate_legacy(struct adapter *);
135758cc3dcSJack F Vogel static int	ixgbe_setup_msix(struct adapter *);
136758cc3dcSJack F Vogel static void	ixgbe_free_pci_resources(struct adapter *);
137758cc3dcSJack F Vogel static void	ixgbe_local_timer(void *);
138758cc3dcSJack F Vogel static int	ixgbe_setup_interface(device_t, struct adapter *);
13948056c88SJack F Vogel static void	ixgbe_config_gpie(struct adapter *);
1406f37f232SEric Joyner static void	ixgbe_config_dmac(struct adapter *);
1416f37f232SEric Joyner static void	ixgbe_config_delay_values(struct adapter *);
142758cc3dcSJack F Vogel static void	ixgbe_config_link(struct adapter *);
1436f37f232SEric Joyner static void	ixgbe_check_wol_support(struct adapter *);
1446f37f232SEric Joyner static int	ixgbe_setup_low_power_mode(struct adapter *);
145758cc3dcSJack F Vogel static void	ixgbe_rearm_queues(struct adapter *, u64);
146758cc3dcSJack F Vogel 
147758cc3dcSJack F Vogel static void     ixgbe_initialize_transmit_units(struct adapter *);
148758cc3dcSJack F Vogel static void     ixgbe_initialize_receive_units(struct adapter *);
149758cc3dcSJack F Vogel static void	ixgbe_enable_rx_drop(struct adapter *);
150758cc3dcSJack F Vogel static void	ixgbe_disable_rx_drop(struct adapter *);
151a9ca1c79SSean Bruno static void	ixgbe_initialize_rss_mapping(struct adapter *);
152758cc3dcSJack F Vogel 
153758cc3dcSJack F Vogel static void     ixgbe_enable_intr(struct adapter *);
154758cc3dcSJack F Vogel static void     ixgbe_disable_intr(struct adapter *);
155758cc3dcSJack F Vogel static void     ixgbe_update_stats_counters(struct adapter *);
156758cc3dcSJack F Vogel static void     ixgbe_set_promisc(struct adapter *);
157758cc3dcSJack F Vogel static void     ixgbe_set_multi(struct adapter *);
158758cc3dcSJack F Vogel static void     ixgbe_update_link_status(struct adapter *);
159758cc3dcSJack F Vogel static void	ixgbe_set_ivar(struct adapter *, u8, u8, s8);
160758cc3dcSJack F Vogel static void	ixgbe_configure_ivars(struct adapter *);
161758cc3dcSJack F Vogel static u8 *	ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *);
162758cc3dcSJack F Vogel 
163758cc3dcSJack F Vogel static void	ixgbe_setup_vlan_hw_support(struct adapter *);
164758cc3dcSJack F Vogel static void	ixgbe_register_vlan(void *, struct ifnet *, u16);
165758cc3dcSJack F Vogel static void	ixgbe_unregister_vlan(void *, struct ifnet *, u16);
166758cc3dcSJack F Vogel 
1676f37f232SEric Joyner static void	ixgbe_add_device_sysctls(struct adapter *);
1686f37f232SEric Joyner static void     ixgbe_add_hw_stats(struct adapter *);
169f2c4db54SSteven Hartland static int	ixgbe_set_flowcntl(struct adapter *, int);
170f2c4db54SSteven Hartland static int	ixgbe_set_advertise(struct adapter *, int);
1716f37f232SEric Joyner 
1726f37f232SEric Joyner /* Sysctl handlers */
173b0c041f8SSean Bruno static void	ixgbe_set_sysctl_value(struct adapter *, const char *,
174b0c041f8SSean Bruno 		     const char *, int *, int);
175f2c4db54SSteven Hartland static int	ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS);
176f2c4db54SSteven Hartland static int	ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS);
1776f37f232SEric Joyner static int	ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS);
1786f37f232SEric Joyner static int	ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS);
1796f37f232SEric Joyner static int	ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS);
1806f37f232SEric Joyner static int	ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS);
181a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
182a9ca1c79SSean Bruno static int	ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS);
183a9ca1c79SSean Bruno static int	ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS);
184a9ca1c79SSean Bruno #endif
1856f37f232SEric Joyner static int	ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS);
1866f37f232SEric Joyner static int	ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS);
1876f37f232SEric Joyner static int	ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS);
1886f37f232SEric Joyner static int	ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS);
1896f37f232SEric Joyner static int	ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS);
1906f37f232SEric Joyner static int	ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS);
191a9ca1c79SSean Bruno static int	ixgbe_sysctl_eee_tx_lpi_delay(SYSCTL_HANDLER_ARGS);
192758cc3dcSJack F Vogel 
193758cc3dcSJack F Vogel /* Support for pluggable optic modules */
194758cc3dcSJack F Vogel static bool	ixgbe_sfp_probe(struct adapter *);
195758cc3dcSJack F Vogel static void	ixgbe_setup_optics(struct adapter *);
196758cc3dcSJack F Vogel 
197758cc3dcSJack F Vogel /* Legacy (single vector interrupt handler */
198758cc3dcSJack F Vogel static void	ixgbe_legacy_irq(void *);
199758cc3dcSJack F Vogel 
200758cc3dcSJack F Vogel /* The MSI/X Interrupt handlers */
201758cc3dcSJack F Vogel static void	ixgbe_msix_que(void *);
202758cc3dcSJack F Vogel static void	ixgbe_msix_link(void *);
203758cc3dcSJack F Vogel 
204758cc3dcSJack F Vogel /* Deferred interrupt tasklets */
205758cc3dcSJack F Vogel static void	ixgbe_handle_que(void *, int);
206758cc3dcSJack F Vogel static void	ixgbe_handle_link(void *, int);
207758cc3dcSJack F Vogel static void	ixgbe_handle_msf(void *, int);
208758cc3dcSJack F Vogel static void	ixgbe_handle_mod(void *, int);
2096f37f232SEric Joyner static void	ixgbe_handle_phy(void *, int);
210758cc3dcSJack F Vogel 
211758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
212758cc3dcSJack F Vogel static void	ixgbe_reinit_fdir(void *, int);
213758cc3dcSJack F Vogel #endif
214758cc3dcSJack F Vogel 
21548056c88SJack F Vogel #ifdef PCI_IOV
21648056c88SJack F Vogel static void	ixgbe_ping_all_vfs(struct adapter *);
21748056c88SJack F Vogel static void	ixgbe_handle_mbx(void *, int);
21848056c88SJack F Vogel static int	ixgbe_init_iov(device_t, u16, const nvlist_t *);
21948056c88SJack F Vogel static void	ixgbe_uninit_iov(device_t);
22048056c88SJack F Vogel static int	ixgbe_add_vf(device_t, u16, const nvlist_t *);
22148056c88SJack F Vogel static void	ixgbe_initialize_iov(struct adapter *);
22248056c88SJack F Vogel static void	ixgbe_recalculate_max_frame(struct adapter *);
22348056c88SJack F Vogel static void	ixgbe_init_vf(struct adapter *, struct ixgbe_vf *);
22448056c88SJack F Vogel #endif /* PCI_IOV */
22548056c88SJack F Vogel 
22648056c88SJack F Vogel 
227758cc3dcSJack F Vogel /*********************************************************************
228758cc3dcSJack F Vogel  *  FreeBSD Device Interface Entry Points
229758cc3dcSJack F Vogel  *********************************************************************/
230758cc3dcSJack F Vogel 
231a1edda90SAdrian Chadd static device_method_t ix_methods[] = {
232758cc3dcSJack F Vogel 	/* Device interface */
233758cc3dcSJack F Vogel 	DEVMETHOD(device_probe, ixgbe_probe),
234758cc3dcSJack F Vogel 	DEVMETHOD(device_attach, ixgbe_attach),
235758cc3dcSJack F Vogel 	DEVMETHOD(device_detach, ixgbe_detach),
236758cc3dcSJack F Vogel 	DEVMETHOD(device_shutdown, ixgbe_shutdown),
2376f37f232SEric Joyner 	DEVMETHOD(device_suspend, ixgbe_suspend),
2386f37f232SEric Joyner 	DEVMETHOD(device_resume, ixgbe_resume),
23948056c88SJack F Vogel #ifdef PCI_IOV
2409e34aea2SJohn Baldwin 	DEVMETHOD(pci_iov_init, ixgbe_init_iov),
2419e34aea2SJohn Baldwin 	DEVMETHOD(pci_iov_uninit, ixgbe_uninit_iov),
2429e34aea2SJohn Baldwin 	DEVMETHOD(pci_iov_add_vf, ixgbe_add_vf),
24348056c88SJack F Vogel #endif /* PCI_IOV */
244758cc3dcSJack F Vogel 	DEVMETHOD_END
245758cc3dcSJack F Vogel };
246758cc3dcSJack F Vogel 
247a1edda90SAdrian Chadd static driver_t ix_driver = {
248a1edda90SAdrian Chadd 	"ix", ix_methods, sizeof(struct adapter),
249758cc3dcSJack F Vogel };
250758cc3dcSJack F Vogel 
251a1edda90SAdrian Chadd devclass_t ix_devclass;
252a1edda90SAdrian Chadd DRIVER_MODULE(ix, pci, ix_driver, ix_devclass, 0, 0);
253758cc3dcSJack F Vogel 
254a1edda90SAdrian Chadd MODULE_DEPEND(ix, pci, 1, 1, 1);
255a1edda90SAdrian Chadd MODULE_DEPEND(ix, ether, 1, 1, 1);
256847bf383SLuigi Rizzo #ifdef DEV_NETMAP
257847bf383SLuigi Rizzo MODULE_DEPEND(ix, netmap, 1, 1, 1);
258847bf383SLuigi Rizzo #endif /* DEV_NETMAP */
259758cc3dcSJack F Vogel 
260758cc3dcSJack F Vogel /*
261758cc3dcSJack F Vogel ** TUNEABLE PARAMETERS:
262758cc3dcSJack F Vogel */
263758cc3dcSJack F Vogel 
264758cc3dcSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0,
265758cc3dcSJack F Vogel 		   "IXGBE driver parameters");
266758cc3dcSJack F Vogel 
267758cc3dcSJack F Vogel /*
268758cc3dcSJack F Vogel ** AIM: Adaptive Interrupt Moderation
269758cc3dcSJack F Vogel ** which means that the interrupt rate
270758cc3dcSJack F Vogel ** is varied over time based on the
271758cc3dcSJack F Vogel ** traffic for that interrupt vector
272758cc3dcSJack F Vogel */
273758cc3dcSJack F Vogel static int ixgbe_enable_aim = TRUE;
274758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0,
275758cc3dcSJack F Vogel     "Enable adaptive interrupt moderation");
276758cc3dcSJack F Vogel 
277758cc3dcSJack F Vogel static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY);
278758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN,
279758cc3dcSJack F Vogel     &ixgbe_max_interrupt_rate, 0, "Maximum interrupts per second");
280758cc3dcSJack F Vogel 
281758cc3dcSJack F Vogel /* How many packets rxeof tries to clean at a time */
282758cc3dcSJack F Vogel static int ixgbe_rx_process_limit = 256;
283758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN,
284758cc3dcSJack F Vogel     &ixgbe_rx_process_limit, 0,
285758cc3dcSJack F Vogel     "Maximum number of received packets to process at a time,"
286758cc3dcSJack F Vogel     "-1 means unlimited");
287758cc3dcSJack F Vogel 
288758cc3dcSJack F Vogel /* How many packets txeof tries to clean at a time */
289758cc3dcSJack F Vogel static int ixgbe_tx_process_limit = 256;
290758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, tx_process_limit, CTLFLAG_RDTUN,
291758cc3dcSJack F Vogel     &ixgbe_tx_process_limit, 0,
292758cc3dcSJack F Vogel     "Maximum number of sent packets to process at a time,"
293758cc3dcSJack F Vogel     "-1 means unlimited");
294758cc3dcSJack F Vogel 
295f2c4db54SSteven Hartland /* Flow control setting, default to full */
296f2c4db54SSteven Hartland static int ixgbe_flow_control = ixgbe_fc_full;
297f2c4db54SSteven Hartland SYSCTL_INT(_hw_ix, OID_AUTO, flow_control, CTLFLAG_RDTUN,
298f2c4db54SSteven Hartland     &ixgbe_flow_control, 0, "Default flow control used for all adapters");
299f2c4db54SSteven Hartland 
300f2c4db54SSteven Hartland /* Advertise Speed, default to 0 (auto) */
301f2c4db54SSteven Hartland static int ixgbe_advertise_speed = 0;
302f2c4db54SSteven Hartland SYSCTL_INT(_hw_ix, OID_AUTO, advertise_speed, CTLFLAG_RDTUN,
303f2c4db54SSteven Hartland     &ixgbe_advertise_speed, 0, "Default advertised speed for all adapters");
304f2c4db54SSteven Hartland 
305758cc3dcSJack F Vogel /*
306758cc3dcSJack F Vogel ** Smart speed setting, default to on
307758cc3dcSJack F Vogel ** this only works as a compile option
308758cc3dcSJack F Vogel ** right now as its during attach, set
309758cc3dcSJack F Vogel ** this to 'ixgbe_smart_speed_off' to
310758cc3dcSJack F Vogel ** disable.
311758cc3dcSJack F Vogel */
312758cc3dcSJack F Vogel static int ixgbe_smart_speed = ixgbe_smart_speed_on;
313758cc3dcSJack F Vogel 
314758cc3dcSJack F Vogel /*
315758cc3dcSJack F Vogel  * MSIX should be the default for best performance,
316758cc3dcSJack F Vogel  * but this allows it to be forced off for testing.
317758cc3dcSJack F Vogel  */
318758cc3dcSJack F Vogel static int ixgbe_enable_msix = 1;
319758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixgbe_enable_msix, 0,
320758cc3dcSJack F Vogel     "Enable MSI-X interrupts");
321758cc3dcSJack F Vogel 
322758cc3dcSJack F Vogel /*
323758cc3dcSJack F Vogel  * Number of Queues, can be set to 0,
324758cc3dcSJack F Vogel  * it then autoconfigures based on the
325758cc3dcSJack F Vogel  * number of cpus with a max of 8. This
326758cc3dcSJack F Vogel  * can be overriden manually here.
327758cc3dcSJack F Vogel  */
328758cc3dcSJack F Vogel static int ixgbe_num_queues = 0;
329758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, num_queues, CTLFLAG_RDTUN, &ixgbe_num_queues, 0,
330758cc3dcSJack F Vogel     "Number of queues to configure, 0 indicates autoconfigure");
331758cc3dcSJack F Vogel 
332758cc3dcSJack F Vogel /*
333758cc3dcSJack F Vogel ** Number of TX descriptors per ring,
334758cc3dcSJack F Vogel ** setting higher than RX as this seems
335758cc3dcSJack F Vogel ** the better performing choice.
336758cc3dcSJack F Vogel */
337758cc3dcSJack F Vogel static int ixgbe_txd = PERFORM_TXD;
338758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, txd, CTLFLAG_RDTUN, &ixgbe_txd, 0,
339758cc3dcSJack F Vogel     "Number of transmit descriptors per queue");
340758cc3dcSJack F Vogel 
341758cc3dcSJack F Vogel /* Number of RX descriptors per ring */
342758cc3dcSJack F Vogel static int ixgbe_rxd = PERFORM_RXD;
343758cc3dcSJack F Vogel SYSCTL_INT(_hw_ix, OID_AUTO, rxd, CTLFLAG_RDTUN, &ixgbe_rxd, 0,
344758cc3dcSJack F Vogel     "Number of receive descriptors per queue");
345758cc3dcSJack F Vogel 
346758cc3dcSJack F Vogel /*
347758cc3dcSJack F Vogel ** Defining this on will allow the use
348758cc3dcSJack F Vogel ** of unsupported SFP+ modules, note that
349758cc3dcSJack F Vogel ** doing so you are on your own :)
350758cc3dcSJack F Vogel */
351758cc3dcSJack F Vogel static int allow_unsupported_sfp = FALSE;
352758cc3dcSJack F Vogel TUNABLE_INT("hw.ix.unsupported_sfp", &allow_unsupported_sfp);
353758cc3dcSJack F Vogel 
354758cc3dcSJack F Vogel /* Keep running tab on them for sanity check */
355758cc3dcSJack F Vogel static int ixgbe_total_ports;
356758cc3dcSJack F Vogel 
357758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
358758cc3dcSJack F Vogel /*
359758cc3dcSJack F Vogel ** Flow Director actually 'steals'
360758cc3dcSJack F Vogel ** part of the packet buffer as its
361758cc3dcSJack F Vogel ** filter pool, this variable controls
362758cc3dcSJack F Vogel ** how much it uses:
363758cc3dcSJack F Vogel **  0 = 64K, 1 = 128K, 2 = 256K
364758cc3dcSJack F Vogel */
365758cc3dcSJack F Vogel static int fdir_pballoc = 1;
366758cc3dcSJack F Vogel #endif
367758cc3dcSJack F Vogel 
368758cc3dcSJack F Vogel #ifdef DEV_NETMAP
369758cc3dcSJack F Vogel /*
370758cc3dcSJack F Vogel  * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
371758cc3dcSJack F Vogel  * be a reference on how to implement netmap support in a driver.
372758cc3dcSJack F Vogel  * Additional comments are in ixgbe_netmap.h .
373758cc3dcSJack F Vogel  *
374758cc3dcSJack F Vogel  * <dev/netmap/ixgbe_netmap.h> contains functions for netmap support
375758cc3dcSJack F Vogel  * that extend the standard driver.
376758cc3dcSJack F Vogel  */
377758cc3dcSJack F Vogel #include <dev/netmap/ixgbe_netmap.h>
378758cc3dcSJack F Vogel #endif /* DEV_NETMAP */
379758cc3dcSJack F Vogel 
38048056c88SJack F Vogel static MALLOC_DEFINE(M_IXGBE, "ix", "ix driver allocations");
38148056c88SJack F Vogel 
382758cc3dcSJack F Vogel /*********************************************************************
383758cc3dcSJack F Vogel  *  Device identification routine
384758cc3dcSJack F Vogel  *
385758cc3dcSJack F Vogel  *  ixgbe_probe determines if the driver should be loaded on
386758cc3dcSJack F Vogel  *  adapter based on PCI vendor/device id of the adapter.
387758cc3dcSJack F Vogel  *
388758cc3dcSJack F Vogel  *  return BUS_PROBE_DEFAULT on success, positive on failure
389758cc3dcSJack F Vogel  *********************************************************************/
390758cc3dcSJack F Vogel 
391758cc3dcSJack F Vogel static int
392758cc3dcSJack F Vogel ixgbe_probe(device_t dev)
393758cc3dcSJack F Vogel {
394758cc3dcSJack F Vogel 	ixgbe_vendor_info_t *ent;
395758cc3dcSJack F Vogel 
396758cc3dcSJack F Vogel 	u16	pci_vendor_id = 0;
397758cc3dcSJack F Vogel 	u16	pci_device_id = 0;
398758cc3dcSJack F Vogel 	u16	pci_subvendor_id = 0;
399758cc3dcSJack F Vogel 	u16	pci_subdevice_id = 0;
400758cc3dcSJack F Vogel 	char	adapter_name[256];
401758cc3dcSJack F Vogel 
402758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_probe: begin");
403758cc3dcSJack F Vogel 
404758cc3dcSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
405758cc3dcSJack F Vogel 	if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID)
406758cc3dcSJack F Vogel 		return (ENXIO);
407758cc3dcSJack F Vogel 
408758cc3dcSJack F Vogel 	pci_device_id = pci_get_device(dev);
409758cc3dcSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
410758cc3dcSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
411758cc3dcSJack F Vogel 
412758cc3dcSJack F Vogel 	ent = ixgbe_vendor_info_array;
413758cc3dcSJack F Vogel 	while (ent->vendor_id != 0) {
414758cc3dcSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
415758cc3dcSJack F Vogel 		    (pci_device_id == ent->device_id) &&
416758cc3dcSJack F Vogel 
417758cc3dcSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
418758cc3dcSJack F Vogel 		     (ent->subvendor_id == 0)) &&
419758cc3dcSJack F Vogel 
420758cc3dcSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
421758cc3dcSJack F Vogel 		     (ent->subdevice_id == 0))) {
422758cc3dcSJack F Vogel 			sprintf(adapter_name, "%s, Version - %s",
423758cc3dcSJack F Vogel 				ixgbe_strings[ent->index],
424758cc3dcSJack F Vogel 				ixgbe_driver_version);
425758cc3dcSJack F Vogel 			device_set_desc_copy(dev, adapter_name);
426758cc3dcSJack F Vogel 			++ixgbe_total_ports;
427758cc3dcSJack F Vogel 			return (BUS_PROBE_DEFAULT);
428758cc3dcSJack F Vogel 		}
429758cc3dcSJack F Vogel 		ent++;
430758cc3dcSJack F Vogel 	}
431758cc3dcSJack F Vogel 	return (ENXIO);
432758cc3dcSJack F Vogel }
433758cc3dcSJack F Vogel 
434758cc3dcSJack F Vogel /*********************************************************************
435758cc3dcSJack F Vogel  *  Device initialization routine
436758cc3dcSJack F Vogel  *
437758cc3dcSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
438758cc3dcSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
439758cc3dcSJack F Vogel  *  and initializes the hardware.
440758cc3dcSJack F Vogel  *
441758cc3dcSJack F Vogel  *  return 0 on success, positive on failure
442758cc3dcSJack F Vogel  *********************************************************************/
443758cc3dcSJack F Vogel 
444758cc3dcSJack F Vogel static int
445758cc3dcSJack F Vogel ixgbe_attach(device_t dev)
446758cc3dcSJack F Vogel {
447758cc3dcSJack F Vogel 	struct adapter *adapter;
448758cc3dcSJack F Vogel 	struct ixgbe_hw *hw;
449758cc3dcSJack F Vogel 	int             error = 0;
450758cc3dcSJack F Vogel 	u16		csum;
451758cc3dcSJack F Vogel 	u32		ctrl_ext;
452758cc3dcSJack F Vogel 
453758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_attach: begin");
454758cc3dcSJack F Vogel 
455758cc3dcSJack F Vogel 	/* Allocate, clear, and link in our adapter structure */
456758cc3dcSJack F Vogel 	adapter = device_get_softc(dev);
457a9ca1c79SSean Bruno 	adapter->dev = dev;
458758cc3dcSJack F Vogel 	hw = &adapter->hw;
459758cc3dcSJack F Vogel 
4608aa7fdbdSPatrick Kelsey #ifdef DEV_NETMAP
4618aa7fdbdSPatrick Kelsey 	adapter->init_locked = ixgbe_init_locked;
4628aa7fdbdSPatrick Kelsey 	adapter->stop_locked = ixgbe_stop;
4638aa7fdbdSPatrick Kelsey #endif
4648aa7fdbdSPatrick Kelsey 
465758cc3dcSJack F Vogel 	/* Core Lock Init*/
466758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev));
467758cc3dcSJack F Vogel 
468758cc3dcSJack F Vogel 	/* Set up the timer callout */
469758cc3dcSJack F Vogel 	callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0);
470758cc3dcSJack F Vogel 
471758cc3dcSJack F Vogel 	/* Determine hardware revision */
472758cc3dcSJack F Vogel 	ixgbe_identify_hardware(adapter);
473758cc3dcSJack F Vogel 
474758cc3dcSJack F Vogel 	/* Do base PCI setup - map BAR0 */
475758cc3dcSJack F Vogel 	if (ixgbe_allocate_pci_resources(adapter)) {
476758cc3dcSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
477758cc3dcSJack F Vogel 		error = ENXIO;
478758cc3dcSJack F Vogel 		goto err_out;
479758cc3dcSJack F Vogel 	}
480758cc3dcSJack F Vogel 
481b0c041f8SSean Bruno 	/* Sysctls for limiting the amount of work done in the taskqueues */
482b0c041f8SSean Bruno 	ixgbe_set_sysctl_value(adapter, "rx_processing_limit",
483b0c041f8SSean Bruno 	    "max number of rx packets to process",
484b0c041f8SSean Bruno 	    &adapter->rx_process_limit, ixgbe_rx_process_limit);
485b0c041f8SSean Bruno 
486b0c041f8SSean Bruno 	ixgbe_set_sysctl_value(adapter, "tx_processing_limit",
487b0c041f8SSean Bruno 	    "max number of tx packets to process",
488b0c041f8SSean Bruno 	&adapter->tx_process_limit, ixgbe_tx_process_limit);
489b0c041f8SSean Bruno 
490758cc3dcSJack F Vogel 	/* Do descriptor calc and sanity checks */
491758cc3dcSJack F Vogel 	if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 ||
492758cc3dcSJack F Vogel 	    ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) {
493758cc3dcSJack F Vogel 		device_printf(dev, "TXD config issue, using default!\n");
494758cc3dcSJack F Vogel 		adapter->num_tx_desc = DEFAULT_TXD;
495758cc3dcSJack F Vogel 	} else
496758cc3dcSJack F Vogel 		adapter->num_tx_desc = ixgbe_txd;
497758cc3dcSJack F Vogel 
498758cc3dcSJack F Vogel 	/*
499758cc3dcSJack F Vogel 	** With many RX rings it is easy to exceed the
500758cc3dcSJack F Vogel 	** system mbuf allocation. Tuning nmbclusters
501758cc3dcSJack F Vogel 	** can alleviate this.
502758cc3dcSJack F Vogel 	*/
503758cc3dcSJack F Vogel 	if (nmbclusters > 0) {
504758cc3dcSJack F Vogel 		int s;
505758cc3dcSJack F Vogel 		s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports;
506758cc3dcSJack F Vogel 		if (s > nmbclusters) {
507758cc3dcSJack F Vogel 			device_printf(dev, "RX Descriptors exceed "
508758cc3dcSJack F Vogel 			    "system mbuf max, using default instead!\n");
509758cc3dcSJack F Vogel 			ixgbe_rxd = DEFAULT_RXD;
510758cc3dcSJack F Vogel 		}
511758cc3dcSJack F Vogel 	}
512758cc3dcSJack F Vogel 
513758cc3dcSJack F Vogel 	if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 ||
514758cc3dcSJack F Vogel 	    ixgbe_rxd < MIN_RXD || ixgbe_rxd > MAX_RXD) {
515758cc3dcSJack F Vogel 		device_printf(dev, "RXD config issue, using default!\n");
516758cc3dcSJack F Vogel 		adapter->num_rx_desc = DEFAULT_RXD;
517758cc3dcSJack F Vogel 	} else
518758cc3dcSJack F Vogel 		adapter->num_rx_desc = ixgbe_rxd;
519758cc3dcSJack F Vogel 
520758cc3dcSJack F Vogel 	/* Allocate our TX/RX Queues */
521758cc3dcSJack F Vogel 	if (ixgbe_allocate_queues(adapter)) {
522758cc3dcSJack F Vogel 		error = ENOMEM;
523758cc3dcSJack F Vogel 		goto err_out;
524758cc3dcSJack F Vogel 	}
525758cc3dcSJack F Vogel 
526758cc3dcSJack F Vogel 	/* Allocate multicast array memory. */
52748056c88SJack F Vogel 	adapter->mta = malloc(sizeof(*adapter->mta) *
528758cc3dcSJack F Vogel 	    MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT);
529758cc3dcSJack F Vogel 	if (adapter->mta == NULL) {
530758cc3dcSJack F Vogel 		device_printf(dev, "Can not allocate multicast setup array\n");
531758cc3dcSJack F Vogel 		error = ENOMEM;
532758cc3dcSJack F Vogel 		goto err_late;
533758cc3dcSJack F Vogel 	}
534758cc3dcSJack F Vogel 
535758cc3dcSJack F Vogel 	/* Initialize the shared code */
536758cc3dcSJack F Vogel 	hw->allow_unsupported_sfp = allow_unsupported_sfp;
537758cc3dcSJack F Vogel 	error = ixgbe_init_shared_code(hw);
538758cc3dcSJack F Vogel 	if (error == IXGBE_ERR_SFP_NOT_PRESENT) {
539758cc3dcSJack F Vogel 		/*
540758cc3dcSJack F Vogel 		** No optics in this port, set up
541758cc3dcSJack F Vogel 		** so the timer routine will probe
542758cc3dcSJack F Vogel 		** for later insertion.
543758cc3dcSJack F Vogel 		*/
544758cc3dcSJack F Vogel 		adapter->sfp_probe = TRUE;
545758cc3dcSJack F Vogel 		error = 0;
546758cc3dcSJack F Vogel 	} else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) {
547758cc3dcSJack F Vogel 		device_printf(dev, "Unsupported SFP+ module detected!\n");
548758cc3dcSJack F Vogel 		error = EIO;
549758cc3dcSJack F Vogel 		goto err_late;
550758cc3dcSJack F Vogel 	} else if (error) {
551758cc3dcSJack F Vogel 		device_printf(dev, "Unable to initialize the shared code\n");
552758cc3dcSJack F Vogel 		error = EIO;
553758cc3dcSJack F Vogel 		goto err_late;
554758cc3dcSJack F Vogel 	}
555758cc3dcSJack F Vogel 
556758cc3dcSJack F Vogel 	/* Make sure we have a good EEPROM before we read from it */
557758cc3dcSJack F Vogel 	if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) {
558758cc3dcSJack F Vogel 		device_printf(dev, "The EEPROM Checksum Is Not Valid\n");
559758cc3dcSJack F Vogel 		error = EIO;
560758cc3dcSJack F Vogel 		goto err_late;
561758cc3dcSJack F Vogel 	}
562758cc3dcSJack F Vogel 
563758cc3dcSJack F Vogel 	error = ixgbe_init_hw(hw);
564758cc3dcSJack F Vogel 	switch (error) {
565758cc3dcSJack F Vogel 	case IXGBE_ERR_EEPROM_VERSION:
566758cc3dcSJack F Vogel 		device_printf(dev, "This device is a pre-production adapter/"
567758cc3dcSJack F Vogel 		    "LOM.  Please be aware there may be issues associated "
568758cc3dcSJack F Vogel 		    "with your hardware.\nIf you are experiencing problems "
569758cc3dcSJack F Vogel 		    "please contact your Intel or hardware representative "
570758cc3dcSJack F Vogel 		    "who provided you with this hardware.\n");
571758cc3dcSJack F Vogel 		break;
572758cc3dcSJack F Vogel 	case IXGBE_ERR_SFP_NOT_SUPPORTED:
573758cc3dcSJack F Vogel 		device_printf(dev, "Unsupported SFP+ Module\n");
574758cc3dcSJack F Vogel 		error = EIO;
575758cc3dcSJack F Vogel 		goto err_late;
576758cc3dcSJack F Vogel 	case IXGBE_ERR_SFP_NOT_PRESENT:
577758cc3dcSJack F Vogel 		device_printf(dev, "No SFP+ Module found\n");
578758cc3dcSJack F Vogel 		/* falls thru */
579758cc3dcSJack F Vogel 	default:
580758cc3dcSJack F Vogel 		break;
581758cc3dcSJack F Vogel 	}
582758cc3dcSJack F Vogel 
583f2c4db54SSteven Hartland 	/* hw.ix defaults init */
584f2c4db54SSteven Hartland 	ixgbe_set_advertise(adapter, ixgbe_advertise_speed);
585f2c4db54SSteven Hartland 	ixgbe_set_flowcntl(adapter, ixgbe_flow_control);
586f2c4db54SSteven Hartland 	adapter->enable_aim = ixgbe_enable_aim;
587f2c4db54SSteven Hartland 
588758cc3dcSJack F Vogel 	if ((adapter->msix > 1) && (ixgbe_enable_msix))
589758cc3dcSJack F Vogel 		error = ixgbe_allocate_msix(adapter);
590758cc3dcSJack F Vogel 	else
591758cc3dcSJack F Vogel 		error = ixgbe_allocate_legacy(adapter);
592758cc3dcSJack F Vogel 	if (error)
593758cc3dcSJack F Vogel 		goto err_late;
594758cc3dcSJack F Vogel 
5951ebf555bSSteven Hartland 	/* Enable the optics for 82599 SFP+ fiber */
5961ebf555bSSteven Hartland 	ixgbe_enable_tx_laser(hw);
5971ebf555bSSteven Hartland 
5981ebf555bSSteven Hartland 	/* Enable power to the phy. */
5991ebf555bSSteven Hartland 	ixgbe_set_phy_power(hw, TRUE);
6001ebf555bSSteven Hartland 
601758cc3dcSJack F Vogel 	/* Setup OS specific network interface */
602758cc3dcSJack F Vogel 	if (ixgbe_setup_interface(dev, adapter) != 0)
603758cc3dcSJack F Vogel 		goto err_late;
604758cc3dcSJack F Vogel 
605758cc3dcSJack F Vogel 	/* Initialize statistics */
606758cc3dcSJack F Vogel 	ixgbe_update_stats_counters(adapter);
607758cc3dcSJack F Vogel 
608758cc3dcSJack F Vogel 	/* Register for VLAN events */
609758cc3dcSJack F Vogel 	adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
610758cc3dcSJack F Vogel 	    ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST);
611758cc3dcSJack F Vogel 	adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
612758cc3dcSJack F Vogel 	    ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST);
613758cc3dcSJack F Vogel 
6146f37f232SEric Joyner         /* Check PCIE slot type/speed/width */
615a9ca1c79SSean Bruno 	ixgbe_get_slot_info(adapter);
616758cc3dcSJack F Vogel 
617a9ca1c79SSean Bruno 	/* Set an initial default flow control & dmac value */
618758cc3dcSJack F Vogel 	adapter->fc = ixgbe_fc_full;
619a9ca1c79SSean Bruno 	adapter->dmac = 0;
620a9ca1c79SSean Bruno 	adapter->eee_enabled = 0;
621758cc3dcSJack F Vogel 
62248056c88SJack F Vogel #ifdef PCI_IOV
62348056c88SJack F Vogel 	if ((hw->mac.type != ixgbe_mac_82598EB) && (adapter->msix > 1)) {
62448056c88SJack F Vogel 		nvlist_t *pf_schema, *vf_schema;
62548056c88SJack F Vogel 
62648056c88SJack F Vogel 		hw->mbx.ops.init_params(hw);
62748056c88SJack F Vogel 		pf_schema = pci_iov_schema_alloc_node();
62848056c88SJack F Vogel 		vf_schema = pci_iov_schema_alloc_node();
62948056c88SJack F Vogel 		pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
63048056c88SJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
63148056c88SJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, TRUE);
63248056c88SJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
63348056c88SJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
63448056c88SJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-promisc",
63548056c88SJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
63648056c88SJack F Vogel 		error = pci_iov_attach(dev, pf_schema, vf_schema);
63748056c88SJack F Vogel 		if (error != 0) {
63848056c88SJack F Vogel 			device_printf(dev,
63948056c88SJack F Vogel 			    "Error %d setting up SR-IOV\n", error);
64048056c88SJack F Vogel 		}
64148056c88SJack F Vogel 	}
64248056c88SJack F Vogel #endif /* PCI_IOV */
64348056c88SJack F Vogel 
6446f37f232SEric Joyner 	/* Check for certain supported features */
6456f37f232SEric Joyner 	ixgbe_check_wol_support(adapter);
6466f37f232SEric Joyner 
6476f37f232SEric Joyner 	/* Add sysctls */
6486f37f232SEric Joyner 	ixgbe_add_device_sysctls(adapter);
6496f37f232SEric Joyner 	ixgbe_add_hw_stats(adapter);
6506f37f232SEric Joyner 
651758cc3dcSJack F Vogel 	/* let hardware know driver is loaded */
652758cc3dcSJack F Vogel 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
653758cc3dcSJack F Vogel 	ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
654758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
655758cc3dcSJack F Vogel 
656758cc3dcSJack F Vogel #ifdef DEV_NETMAP
657758cc3dcSJack F Vogel 	ixgbe_netmap_attach(adapter);
658758cc3dcSJack F Vogel #endif /* DEV_NETMAP */
659758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_attach: end");
660758cc3dcSJack F Vogel 	return (0);
661758cc3dcSJack F Vogel 
662758cc3dcSJack F Vogel err_late:
663758cc3dcSJack F Vogel 	ixgbe_free_transmit_structures(adapter);
664758cc3dcSJack F Vogel 	ixgbe_free_receive_structures(adapter);
665758cc3dcSJack F Vogel err_out:
666758cc3dcSJack F Vogel 	if (adapter->ifp != NULL)
667758cc3dcSJack F Vogel 		if_free(adapter->ifp);
668758cc3dcSJack F Vogel 	ixgbe_free_pci_resources(adapter);
669758cc3dcSJack F Vogel 	free(adapter->mta, M_DEVBUF);
670758cc3dcSJack F Vogel 	return (error);
671758cc3dcSJack F Vogel }
672758cc3dcSJack F Vogel 
673758cc3dcSJack F Vogel /*********************************************************************
674758cc3dcSJack F Vogel  *  Device removal routine
675758cc3dcSJack F Vogel  *
676758cc3dcSJack F Vogel  *  The detach entry point is called when the driver is being removed.
677758cc3dcSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
678758cc3dcSJack F Vogel  *  that were allocated for driver operation.
679758cc3dcSJack F Vogel  *
680758cc3dcSJack F Vogel  *  return 0 on success, positive on failure
681758cc3dcSJack F Vogel  *********************************************************************/
682758cc3dcSJack F Vogel 
683758cc3dcSJack F Vogel static int
684758cc3dcSJack F Vogel ixgbe_detach(device_t dev)
685758cc3dcSJack F Vogel {
686758cc3dcSJack F Vogel 	struct adapter *adapter = device_get_softc(dev);
687758cc3dcSJack F Vogel 	struct ix_queue *que = adapter->queues;
688758cc3dcSJack F Vogel 	struct tx_ring *txr = adapter->tx_rings;
689758cc3dcSJack F Vogel 	u32	ctrl_ext;
690758cc3dcSJack F Vogel 
691758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_detach: begin");
692758cc3dcSJack F Vogel 
693758cc3dcSJack F Vogel 	/* Make sure VLANS are not using driver */
694758cc3dcSJack F Vogel 	if (adapter->ifp->if_vlantrunk != NULL) {
695758cc3dcSJack F Vogel 		device_printf(dev,"Vlan in use, detach first\n");
696758cc3dcSJack F Vogel 		return (EBUSY);
697758cc3dcSJack F Vogel 	}
698758cc3dcSJack F Vogel 
69948056c88SJack F Vogel #ifdef PCI_IOV
70048056c88SJack F Vogel 	if (pci_iov_detach(dev) != 0) {
70148056c88SJack F Vogel 		device_printf(dev, "SR-IOV in use; detach first.\n");
70248056c88SJack F Vogel 		return (EBUSY);
70348056c88SJack F Vogel 	}
70448056c88SJack F Vogel #endif /* PCI_IOV */
70548056c88SJack F Vogel 
706a9ca1c79SSean Bruno 	ether_ifdetach(adapter->ifp);
7076f37f232SEric Joyner 	/* Stop the adapter */
708758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
7096f37f232SEric Joyner 	ixgbe_setup_low_power_mode(adapter);
710758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
711758cc3dcSJack F Vogel 
712758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, que++, txr++) {
713758cc3dcSJack F Vogel 		if (que->tq) {
714758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
715758cc3dcSJack F Vogel 			taskqueue_drain(que->tq, &txr->txq_task);
716758cc3dcSJack F Vogel #endif
717758cc3dcSJack F Vogel 			taskqueue_drain(que->tq, &que->que_task);
718758cc3dcSJack F Vogel 			taskqueue_free(que->tq);
719758cc3dcSJack F Vogel 		}
720758cc3dcSJack F Vogel 	}
721758cc3dcSJack F Vogel 
722758cc3dcSJack F Vogel 	/* Drain the Link queue */
723758cc3dcSJack F Vogel 	if (adapter->tq) {
724758cc3dcSJack F Vogel 		taskqueue_drain(adapter->tq, &adapter->link_task);
725758cc3dcSJack F Vogel 		taskqueue_drain(adapter->tq, &adapter->mod_task);
726758cc3dcSJack F Vogel 		taskqueue_drain(adapter->tq, &adapter->msf_task);
72748056c88SJack F Vogel #ifdef PCI_IOV
72848056c88SJack F Vogel 		taskqueue_drain(adapter->tq, &adapter->mbx_task);
72948056c88SJack F Vogel #endif
7306f37f232SEric Joyner 		taskqueue_drain(adapter->tq, &adapter->phy_task);
731758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
732758cc3dcSJack F Vogel 		taskqueue_drain(adapter->tq, &adapter->fdir_task);
733758cc3dcSJack F Vogel #endif
734758cc3dcSJack F Vogel 		taskqueue_free(adapter->tq);
735758cc3dcSJack F Vogel 	}
736758cc3dcSJack F Vogel 
737758cc3dcSJack F Vogel 	/* let hardware know driver is unloading */
738758cc3dcSJack F Vogel 	ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
739758cc3dcSJack F Vogel 	ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
740758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext);
741758cc3dcSJack F Vogel 
742758cc3dcSJack F Vogel 	/* Unregister VLAN events */
743758cc3dcSJack F Vogel 	if (adapter->vlan_attach != NULL)
744758cc3dcSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach);
745758cc3dcSJack F Vogel 	if (adapter->vlan_detach != NULL)
746758cc3dcSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach);
747758cc3dcSJack F Vogel 
748758cc3dcSJack F Vogel 	callout_drain(&adapter->timer);
749758cc3dcSJack F Vogel #ifdef DEV_NETMAP
750758cc3dcSJack F Vogel 	netmap_detach(adapter->ifp);
751758cc3dcSJack F Vogel #endif /* DEV_NETMAP */
752758cc3dcSJack F Vogel 	ixgbe_free_pci_resources(adapter);
753758cc3dcSJack F Vogel 	bus_generic_detach(dev);
754758cc3dcSJack F Vogel 	if_free(adapter->ifp);
755758cc3dcSJack F Vogel 
756758cc3dcSJack F Vogel 	ixgbe_free_transmit_structures(adapter);
757758cc3dcSJack F Vogel 	ixgbe_free_receive_structures(adapter);
758758cc3dcSJack F Vogel 	free(adapter->mta, M_DEVBUF);
759758cc3dcSJack F Vogel 
760758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK_DESTROY(adapter);
761758cc3dcSJack F Vogel 	return (0);
762758cc3dcSJack F Vogel }
763758cc3dcSJack F Vogel 
764758cc3dcSJack F Vogel /*********************************************************************
765758cc3dcSJack F Vogel  *
766758cc3dcSJack F Vogel  *  Shutdown entry point
767758cc3dcSJack F Vogel  *
768758cc3dcSJack F Vogel  **********************************************************************/
769758cc3dcSJack F Vogel 
770758cc3dcSJack F Vogel static int
771758cc3dcSJack F Vogel ixgbe_shutdown(device_t dev)
772758cc3dcSJack F Vogel {
773758cc3dcSJack F Vogel 	struct adapter *adapter = device_get_softc(dev);
7746f37f232SEric Joyner 	int error = 0;
7756f37f232SEric Joyner 
7766f37f232SEric Joyner 	INIT_DEBUGOUT("ixgbe_shutdown: begin");
7776f37f232SEric Joyner 
778758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
7796f37f232SEric Joyner 	error = ixgbe_setup_low_power_mode(adapter);
780758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
7816f37f232SEric Joyner 
7826f37f232SEric Joyner 	return (error);
7836f37f232SEric Joyner }
7846f37f232SEric Joyner 
7856f37f232SEric Joyner /**
7866f37f232SEric Joyner  * Methods for going from:
7876f37f232SEric Joyner  * D0 -> D3: ixgbe_suspend
7886f37f232SEric Joyner  * D3 -> D0: ixgbe_resume
7896f37f232SEric Joyner  */
7906f37f232SEric Joyner static int
7916f37f232SEric Joyner ixgbe_suspend(device_t dev)
7926f37f232SEric Joyner {
7936f37f232SEric Joyner 	struct adapter *adapter = device_get_softc(dev);
7946f37f232SEric Joyner 	int error = 0;
7956f37f232SEric Joyner 
7966f37f232SEric Joyner 	INIT_DEBUGOUT("ixgbe_suspend: begin");
7976f37f232SEric Joyner 
7986f37f232SEric Joyner 	IXGBE_CORE_LOCK(adapter);
7996f37f232SEric Joyner 
8006f37f232SEric Joyner 	error = ixgbe_setup_low_power_mode(adapter);
8016f37f232SEric Joyner 
8026f37f232SEric Joyner 	IXGBE_CORE_UNLOCK(adapter);
8036f37f232SEric Joyner 
8046f37f232SEric Joyner 	return (error);
8056f37f232SEric Joyner }
8066f37f232SEric Joyner 
8076f37f232SEric Joyner static int
8086f37f232SEric Joyner ixgbe_resume(device_t dev)
8096f37f232SEric Joyner {
8106f37f232SEric Joyner 	struct adapter *adapter = device_get_softc(dev);
8116f37f232SEric Joyner 	struct ifnet *ifp = adapter->ifp;
8126f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
8136f37f232SEric Joyner 	u32 wus;
8146f37f232SEric Joyner 
8156f37f232SEric Joyner 	INIT_DEBUGOUT("ixgbe_resume: begin");
8166f37f232SEric Joyner 
8176f37f232SEric Joyner 	IXGBE_CORE_LOCK(adapter);
8186f37f232SEric Joyner 
8196f37f232SEric Joyner 	/* Read & clear WUS register */
8206f37f232SEric Joyner 	wus = IXGBE_READ_REG(hw, IXGBE_WUS);
8216f37f232SEric Joyner 	if (wus)
8226f37f232SEric Joyner 		device_printf(dev, "Woken up by (WUS): %#010x\n",
8236f37f232SEric Joyner 		    IXGBE_READ_REG(hw, IXGBE_WUS));
8246f37f232SEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
8256f37f232SEric Joyner 	/* And clear WUFC until next low-power transition */
8266f37f232SEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0);
8276f37f232SEric Joyner 
8286f37f232SEric Joyner 	/*
8296f37f232SEric Joyner 	 * Required after D3->D0 transition;
8306f37f232SEric Joyner 	 * will re-advertise all previous advertised speeds
8316f37f232SEric Joyner 	 */
8326f37f232SEric Joyner 	if (ifp->if_flags & IFF_UP)
8336f37f232SEric Joyner 		ixgbe_init_locked(adapter);
8346f37f232SEric Joyner 
8356f37f232SEric Joyner 	IXGBE_CORE_UNLOCK(adapter);
8366f37f232SEric Joyner 
837758cc3dcSJack F Vogel 	return (0);
838758cc3dcSJack F Vogel }
839758cc3dcSJack F Vogel 
840758cc3dcSJack F Vogel 
841758cc3dcSJack F Vogel /*********************************************************************
842758cc3dcSJack F Vogel  *  Ioctl entry point
843758cc3dcSJack F Vogel  *
844758cc3dcSJack F Vogel  *  ixgbe_ioctl is called when the user wants to configure the
845758cc3dcSJack F Vogel  *  interface.
846758cc3dcSJack F Vogel  *
847758cc3dcSJack F Vogel  *  return 0 on success, positive on failure
848758cc3dcSJack F Vogel  **********************************************************************/
849758cc3dcSJack F Vogel 
850758cc3dcSJack F Vogel static int
851758cc3dcSJack F Vogel ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
852758cc3dcSJack F Vogel {
853758cc3dcSJack F Vogel 	struct adapter	*adapter = ifp->if_softc;
854758cc3dcSJack F Vogel 	struct ifreq	*ifr = (struct ifreq *) data;
855758cc3dcSJack F Vogel #if defined(INET) || defined(INET6)
856758cc3dcSJack F Vogel 	struct ifaddr *ifa = (struct ifaddr *)data;
857758cc3dcSJack F Vogel #endif
858758cc3dcSJack F Vogel 	int             error = 0;
859e5cb6169SSean Bruno 	bool		avoid_reset = FALSE;
860758cc3dcSJack F Vogel 
861758cc3dcSJack F Vogel 	switch (command) {
862758cc3dcSJack F Vogel 
863758cc3dcSJack F Vogel         case SIOCSIFADDR:
864758cc3dcSJack F Vogel #ifdef INET
865758cc3dcSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET)
866758cc3dcSJack F Vogel 			avoid_reset = TRUE;
867758cc3dcSJack F Vogel #endif
868758cc3dcSJack F Vogel #ifdef INET6
869758cc3dcSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET6)
870758cc3dcSJack F Vogel 			avoid_reset = TRUE;
871758cc3dcSJack F Vogel #endif
872758cc3dcSJack F Vogel 		/*
873758cc3dcSJack F Vogel 		** Calling init results in link renegotiation,
874758cc3dcSJack F Vogel 		** so we avoid doing it when possible.
875758cc3dcSJack F Vogel 		*/
876758cc3dcSJack F Vogel 		if (avoid_reset) {
877758cc3dcSJack F Vogel 			ifp->if_flags |= IFF_UP;
878758cc3dcSJack F Vogel 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
879758cc3dcSJack F Vogel 				ixgbe_init(adapter);
880a9ca1c79SSean Bruno #ifdef INET
881758cc3dcSJack F Vogel 			if (!(ifp->if_flags & IFF_NOARP))
882758cc3dcSJack F Vogel 				arp_ifinit(ifp, ifa);
883e5cb6169SSean Bruno #endif
884758cc3dcSJack F Vogel 		} else
885758cc3dcSJack F Vogel 			error = ether_ioctl(ifp, command, data);
886758cc3dcSJack F Vogel 		break;
887758cc3dcSJack F Vogel 	case SIOCSIFMTU:
888758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
8896f37f232SEric Joyner 		if (ifr->ifr_mtu > IXGBE_MAX_MTU) {
890758cc3dcSJack F Vogel 			error = EINVAL;
891758cc3dcSJack F Vogel 		} else {
892758cc3dcSJack F Vogel 			IXGBE_CORE_LOCK(adapter);
893758cc3dcSJack F Vogel 			ifp->if_mtu = ifr->ifr_mtu;
894758cc3dcSJack F Vogel 			adapter->max_frame_size =
8956f37f232SEric Joyner 				ifp->if_mtu + IXGBE_MTU_HDR;
896758cc3dcSJack F Vogel 			ixgbe_init_locked(adapter);
89748056c88SJack F Vogel #ifdef PCI_IOV
89848056c88SJack F Vogel 			ixgbe_recalculate_max_frame(adapter);
89948056c88SJack F Vogel #endif
900758cc3dcSJack F Vogel 			IXGBE_CORE_UNLOCK(adapter);
901758cc3dcSJack F Vogel 		}
902758cc3dcSJack F Vogel 		break;
903758cc3dcSJack F Vogel 	case SIOCSIFFLAGS:
904758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
905758cc3dcSJack F Vogel 		IXGBE_CORE_LOCK(adapter);
906758cc3dcSJack F Vogel 		if (ifp->if_flags & IFF_UP) {
907758cc3dcSJack F Vogel 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
908758cc3dcSJack F Vogel 				if ((ifp->if_flags ^ adapter->if_flags) &
909758cc3dcSJack F Vogel 				    (IFF_PROMISC | IFF_ALLMULTI)) {
910758cc3dcSJack F Vogel 					ixgbe_set_promisc(adapter);
911758cc3dcSJack F Vogel                                 }
912758cc3dcSJack F Vogel 			} else
913758cc3dcSJack F Vogel 				ixgbe_init_locked(adapter);
914758cc3dcSJack F Vogel 		} else
915758cc3dcSJack F Vogel 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
916758cc3dcSJack F Vogel 				ixgbe_stop(adapter);
917758cc3dcSJack F Vogel 		adapter->if_flags = ifp->if_flags;
918758cc3dcSJack F Vogel 		IXGBE_CORE_UNLOCK(adapter);
919758cc3dcSJack F Vogel 		break;
920758cc3dcSJack F Vogel 	case SIOCADDMULTI:
921758cc3dcSJack F Vogel 	case SIOCDELMULTI:
922758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI");
923758cc3dcSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
924758cc3dcSJack F Vogel 			IXGBE_CORE_LOCK(adapter);
925758cc3dcSJack F Vogel 			ixgbe_disable_intr(adapter);
926758cc3dcSJack F Vogel 			ixgbe_set_multi(adapter);
927758cc3dcSJack F Vogel 			ixgbe_enable_intr(adapter);
928758cc3dcSJack F Vogel 			IXGBE_CORE_UNLOCK(adapter);
929758cc3dcSJack F Vogel 		}
930758cc3dcSJack F Vogel 		break;
931758cc3dcSJack F Vogel 	case SIOCSIFMEDIA:
932758cc3dcSJack F Vogel 	case SIOCGIFMEDIA:
933758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
934758cc3dcSJack F Vogel 		error = ifmedia_ioctl(ifp, ifr, &adapter->media, command);
935758cc3dcSJack F Vogel 		break;
936758cc3dcSJack F Vogel 	case SIOCSIFCAP:
937758cc3dcSJack F Vogel 	{
938758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
939a9ca1c79SSean Bruno 
940a9ca1c79SSean Bruno 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
941a9ca1c79SSean Bruno 		if (!mask)
942a9ca1c79SSean Bruno 			break;
943a9ca1c79SSean Bruno 
944a9ca1c79SSean Bruno 		/* HW cannot turn these on/off separately */
945a9ca1c79SSean Bruno 		if (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) {
946a9ca1c79SSean Bruno 			ifp->if_capenable ^= IFCAP_RXCSUM;
947a9ca1c79SSean Bruno 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
948a9ca1c79SSean Bruno 		}
949a9ca1c79SSean Bruno 		if (mask & IFCAP_TXCSUM)
950a9ca1c79SSean Bruno 			ifp->if_capenable ^= IFCAP_TXCSUM;
951a9ca1c79SSean Bruno 		if (mask & IFCAP_TXCSUM_IPV6)
952a9ca1c79SSean Bruno 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
953758cc3dcSJack F Vogel 		if (mask & IFCAP_TSO4)
954758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_TSO4;
955758cc3dcSJack F Vogel 		if (mask & IFCAP_TSO6)
956758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_TSO6;
957758cc3dcSJack F Vogel 		if (mask & IFCAP_LRO)
958758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_LRO;
959758cc3dcSJack F Vogel 		if (mask & IFCAP_VLAN_HWTAGGING)
960758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
961758cc3dcSJack F Vogel 		if (mask & IFCAP_VLAN_HWFILTER)
962758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
963758cc3dcSJack F Vogel 		if (mask & IFCAP_VLAN_HWTSO)
964758cc3dcSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
965a9ca1c79SSean Bruno 
966758cc3dcSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
967758cc3dcSJack F Vogel 			IXGBE_CORE_LOCK(adapter);
968758cc3dcSJack F Vogel 			ixgbe_init_locked(adapter);
969758cc3dcSJack F Vogel 			IXGBE_CORE_UNLOCK(adapter);
970758cc3dcSJack F Vogel 		}
971758cc3dcSJack F Vogel 		VLAN_CAPABILITIES(ifp);
972758cc3dcSJack F Vogel 		break;
973758cc3dcSJack F Vogel 	}
974758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036
975758cc3dcSJack F Vogel 	case SIOCGI2C:
976758cc3dcSJack F Vogel 	{
977758cc3dcSJack F Vogel 		struct ixgbe_hw *hw = &adapter->hw;
978758cc3dcSJack F Vogel 		struct ifi2creq i2c;
979758cc3dcSJack F Vogel 		int i;
980758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)");
981758cc3dcSJack F Vogel 		error = copyin(ifr->ifr_data, &i2c, sizeof(i2c));
982758cc3dcSJack F Vogel 		if (error != 0)
983758cc3dcSJack F Vogel 			break;
984758cc3dcSJack F Vogel 		if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) {
985758cc3dcSJack F Vogel 			error = EINVAL;
986758cc3dcSJack F Vogel 			break;
987758cc3dcSJack F Vogel 		}
988758cc3dcSJack F Vogel 		if (i2c.len > sizeof(i2c.data)) {
989758cc3dcSJack F Vogel 			error = EINVAL;
990758cc3dcSJack F Vogel 			break;
991758cc3dcSJack F Vogel 		}
992758cc3dcSJack F Vogel 
993758cc3dcSJack F Vogel 		for (i = 0; i < i2c.len; i++)
994758cc3dcSJack F Vogel 			hw->phy.ops.read_i2c_byte(hw, i2c.offset + i,
995758cc3dcSJack F Vogel 			    i2c.dev_addr, &i2c.data[i]);
996758cc3dcSJack F Vogel 		error = copyout(&i2c, ifr->ifr_data, sizeof(i2c));
997758cc3dcSJack F Vogel 		break;
998758cc3dcSJack F Vogel 	}
999758cc3dcSJack F Vogel #endif
1000758cc3dcSJack F Vogel 	default:
1001758cc3dcSJack F Vogel 		IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command);
1002758cc3dcSJack F Vogel 		error = ether_ioctl(ifp, command, data);
1003758cc3dcSJack F Vogel 		break;
1004758cc3dcSJack F Vogel 	}
1005758cc3dcSJack F Vogel 
1006758cc3dcSJack F Vogel 	return (error);
1007758cc3dcSJack F Vogel }
1008758cc3dcSJack F Vogel 
1009a9ca1c79SSean Bruno /*
1010a9ca1c79SSean Bruno  * Set the various hardware offload abilities.
1011a9ca1c79SSean Bruno  *
1012a9ca1c79SSean Bruno  * This takes the ifnet's if_capenable flags (e.g. set by the user using
1013a9ca1c79SSean Bruno  * ifconfig) and indicates to the OS via the ifnet's if_hwassist field what
1014a9ca1c79SSean Bruno  * mbuf offload flags the driver will understand.
1015a9ca1c79SSean Bruno  */
1016a9ca1c79SSean Bruno static void
1017a9ca1c79SSean Bruno ixgbe_set_if_hwassist(struct adapter *adapter)
1018a9ca1c79SSean Bruno {
1019a9ca1c79SSean Bruno 	struct ifnet *ifp = adapter->ifp;
10202602455cSMichael Tuexen 	struct ixgbe_hw *hw = &adapter->hw;
1021a9ca1c79SSean Bruno 
1022a9ca1c79SSean Bruno 	ifp->if_hwassist = 0;
1023a9ca1c79SSean Bruno #if __FreeBSD_version >= 1000000
1024a9ca1c79SSean Bruno 	if (ifp->if_capenable & IFCAP_TSO4)
1025a9ca1c79SSean Bruno 		ifp->if_hwassist |= CSUM_IP_TSO;
1026a9ca1c79SSean Bruno 	if (ifp->if_capenable & IFCAP_TSO6)
1027a9ca1c79SSean Bruno 		ifp->if_hwassist |= CSUM_IP6_TSO;
10282602455cSMichael Tuexen 	if (ifp->if_capenable & IFCAP_TXCSUM) {
10292602455cSMichael Tuexen 		ifp->if_hwassist |= (CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP);
10302602455cSMichael Tuexen 		if (hw->mac.type != ixgbe_mac_82598EB)
10312602455cSMichael Tuexen 			ifp->if_hwassist |= CSUM_IP_SCTP;
10322602455cSMichael Tuexen 	}
10332602455cSMichael Tuexen 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) {
10342602455cSMichael Tuexen 		ifp->if_hwassist |= (CSUM_IP6_UDP | CSUM_IP6_TCP);
10352602455cSMichael Tuexen 		if (hw->mac.type != ixgbe_mac_82598EB)
10362602455cSMichael Tuexen 			ifp->if_hwassist |= CSUM_IP6_SCTP;
10372602455cSMichael Tuexen 	}
1038a9ca1c79SSean Bruno #else
1039a9ca1c79SSean Bruno 	if (ifp->if_capenable & IFCAP_TSO)
1040a9ca1c79SSean Bruno 		ifp->if_hwassist |= CSUM_TSO;
1041a9ca1c79SSean Bruno 	if (ifp->if_capenable & IFCAP_TXCSUM) {
1042a9ca1c79SSean Bruno 		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
1043a9ca1c79SSean Bruno 		if (hw->mac.type != ixgbe_mac_82598EB)
1044a9ca1c79SSean Bruno 			ifp->if_hwassist |= CSUM_SCTP;
1045a9ca1c79SSean Bruno 	}
1046a9ca1c79SSean Bruno #endif
1047a9ca1c79SSean Bruno }
1048a9ca1c79SSean Bruno 
1049758cc3dcSJack F Vogel /*********************************************************************
1050758cc3dcSJack F Vogel  *  Init entry point
1051758cc3dcSJack F Vogel  *
1052758cc3dcSJack F Vogel  *  This routine is used in two ways. It is used by the stack as
1053758cc3dcSJack F Vogel  *  init entry point in network interface structure. It is also used
1054758cc3dcSJack F Vogel  *  by the driver as a hw/sw initialization routine to get to a
1055758cc3dcSJack F Vogel  *  consistent state.
1056758cc3dcSJack F Vogel  *
1057758cc3dcSJack F Vogel  *  return 0 on success, positive on failure
1058758cc3dcSJack F Vogel  **********************************************************************/
1059758cc3dcSJack F Vogel #define IXGBE_MHADD_MFS_SHIFT 16
1060758cc3dcSJack F Vogel 
1061758cc3dcSJack F Vogel static void
1062758cc3dcSJack F Vogel ixgbe_init_locked(struct adapter *adapter)
1063758cc3dcSJack F Vogel {
1064758cc3dcSJack F Vogel 	struct ifnet   *ifp = adapter->ifp;
1065758cc3dcSJack F Vogel 	device_t 	dev = adapter->dev;
1066758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
106748056c88SJack F Vogel 	struct tx_ring  *txr;
106848056c88SJack F Vogel 	struct rx_ring  *rxr;
106948056c88SJack F Vogel 	u32		txdctl, mhadd;
1070758cc3dcSJack F Vogel 	u32		rxdctl, rxctrl;
1071a9ca1c79SSean Bruno 	int err = 0;
107248056c88SJack F Vogel #ifdef PCI_IOV
107348056c88SJack F Vogel 	enum ixgbe_iov_mode mode;
107448056c88SJack F Vogel #endif
1075758cc3dcSJack F Vogel 
1076758cc3dcSJack F Vogel 	mtx_assert(&adapter->core_mtx, MA_OWNED);
1077758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_init_locked: begin");
107848056c88SJack F Vogel 
1079758cc3dcSJack F Vogel 	hw->adapter_stopped = FALSE;
1080758cc3dcSJack F Vogel 	ixgbe_stop_adapter(hw);
1081758cc3dcSJack F Vogel         callout_stop(&adapter->timer);
1082758cc3dcSJack F Vogel 
108348056c88SJack F Vogel #ifdef PCI_IOV
108448056c88SJack F Vogel 	mode = ixgbe_get_iov_mode(adapter);
108548056c88SJack F Vogel 	adapter->pool = ixgbe_max_vfs(mode);
108648056c88SJack F Vogel 	/* Queue indices may change with IOV mode */
108748056c88SJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++) {
108848056c88SJack F Vogel 		adapter->rx_rings[i].me = ixgbe_pf_que_index(mode, i);
108948056c88SJack F Vogel 		adapter->tx_rings[i].me = ixgbe_pf_que_index(mode, i);
109048056c88SJack F Vogel 	}
109148056c88SJack F Vogel #endif
1092758cc3dcSJack F Vogel         /* reprogram the RAR[0] in case user changed it. */
109348056c88SJack F Vogel 	ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, IXGBE_RAH_AV);
1094758cc3dcSJack F Vogel 
1095758cc3dcSJack F Vogel 	/* Get the latest mac address, User can use a LAA */
109648056c88SJack F Vogel 	bcopy(IF_LLADDR(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
109748056c88SJack F Vogel 	ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, 1);
1098758cc3dcSJack F Vogel 	hw->addr_ctrl.rar_used_count = 1;
1099758cc3dcSJack F Vogel 
1100a9ca1c79SSean Bruno 	/* Set hardware offload abilities from ifnet flags */
1101a9ca1c79SSean Bruno 	ixgbe_set_if_hwassist(adapter);
1102758cc3dcSJack F Vogel 
1103758cc3dcSJack F Vogel 	/* Prepare transmit descriptors and buffers */
1104758cc3dcSJack F Vogel 	if (ixgbe_setup_transmit_structures(adapter)) {
1105758cc3dcSJack F Vogel 		device_printf(dev, "Could not setup transmit structures\n");
1106758cc3dcSJack F Vogel 		ixgbe_stop(adapter);
1107758cc3dcSJack F Vogel 		return;
1108758cc3dcSJack F Vogel 	}
1109758cc3dcSJack F Vogel 
1110758cc3dcSJack F Vogel 	ixgbe_init_hw(hw);
111148056c88SJack F Vogel #ifdef PCI_IOV
111248056c88SJack F Vogel 	ixgbe_initialize_iov(adapter);
111348056c88SJack F Vogel #endif
1114758cc3dcSJack F Vogel 	ixgbe_initialize_transmit_units(adapter);
1115758cc3dcSJack F Vogel 
1116758cc3dcSJack F Vogel 	/* Setup Multicast table */
1117758cc3dcSJack F Vogel 	ixgbe_set_multi(adapter);
1118758cc3dcSJack F Vogel 
1119a9ca1c79SSean Bruno 	/* Determine the correct mbuf pool, based on frame size */
112048056c88SJack F Vogel 	if (adapter->max_frame_size <= MCLBYTES)
1121758cc3dcSJack F Vogel 		adapter->rx_mbuf_sz = MCLBYTES;
112230126537SJack F Vogel 	else
112348056c88SJack F Vogel 		adapter->rx_mbuf_sz = MJUMPAGESIZE;
1124758cc3dcSJack F Vogel 
1125758cc3dcSJack F Vogel 	/* Prepare receive descriptors and buffers */
1126758cc3dcSJack F Vogel 	if (ixgbe_setup_receive_structures(adapter)) {
1127758cc3dcSJack F Vogel 		device_printf(dev, "Could not setup receive structures\n");
1128758cc3dcSJack F Vogel 		ixgbe_stop(adapter);
1129758cc3dcSJack F Vogel 		return;
1130758cc3dcSJack F Vogel 	}
1131758cc3dcSJack F Vogel 
1132758cc3dcSJack F Vogel 	/* Configure RX settings */
1133758cc3dcSJack F Vogel 	ixgbe_initialize_receive_units(adapter);
1134758cc3dcSJack F Vogel 
113548056c88SJack F Vogel 	/* Enable SDP & MSIX interrupts based on adapter */
113648056c88SJack F Vogel 	ixgbe_config_gpie(adapter);
1137758cc3dcSJack F Vogel 
1138758cc3dcSJack F Vogel 	/* Set MTU size */
1139758cc3dcSJack F Vogel 	if (ifp->if_mtu > ETHERMTU) {
11406f37f232SEric Joyner 		/* aka IXGBE_MAXFRS on 82599 and newer */
1141758cc3dcSJack F Vogel 		mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
1142758cc3dcSJack F Vogel 		mhadd &= ~IXGBE_MHADD_MFS_MASK;
1143758cc3dcSJack F Vogel 		mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT;
1144758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
1145758cc3dcSJack F Vogel 	}
1146758cc3dcSJack F Vogel 
1147758cc3dcSJack F Vogel 	/* Now enable all the queues */
1148758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++) {
114948056c88SJack F Vogel 		txr = &adapter->tx_rings[i];
115048056c88SJack F Vogel 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txr->me));
1151758cc3dcSJack F Vogel 		txdctl |= IXGBE_TXDCTL_ENABLE;
1152758cc3dcSJack F Vogel 		/* Set WTHRESH to 8, burst writeback */
1153758cc3dcSJack F Vogel 		txdctl |= (8 << 16);
1154758cc3dcSJack F Vogel 		/*
1155758cc3dcSJack F Vogel 		 * When the internal queue falls below PTHRESH (32),
1156758cc3dcSJack F Vogel 		 * start prefetching as long as there are at least
1157758cc3dcSJack F Vogel 		 * HTHRESH (1) buffers ready. The values are taken
1158758cc3dcSJack F Vogel 		 * from the Intel linux driver 3.8.21.
1159758cc3dcSJack F Vogel 		 * Prefetching enables tx line rate even with 1 queue.
1160758cc3dcSJack F Vogel 		 */
1161758cc3dcSJack F Vogel 		txdctl |= (32 << 0) | (1 << 8);
116248056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txr->me), txdctl);
1163758cc3dcSJack F Vogel 	}
1164758cc3dcSJack F Vogel 
116548056c88SJack F Vogel 	for (int i = 0, j = 0; i < adapter->num_queues; i++) {
116648056c88SJack F Vogel 		rxr = &adapter->rx_rings[i];
116748056c88SJack F Vogel 		rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me));
1168758cc3dcSJack F Vogel 		if (hw->mac.type == ixgbe_mac_82598EB) {
1169758cc3dcSJack F Vogel 			/*
1170758cc3dcSJack F Vogel 			** PTHRESH = 21
1171758cc3dcSJack F Vogel 			** HTHRESH = 4
1172758cc3dcSJack F Vogel 			** WTHRESH = 8
1173758cc3dcSJack F Vogel 			*/
1174758cc3dcSJack F Vogel 			rxdctl &= ~0x3FFFFF;
1175758cc3dcSJack F Vogel 			rxdctl |= 0x080420;
1176758cc3dcSJack F Vogel 		}
1177758cc3dcSJack F Vogel 		rxdctl |= IXGBE_RXDCTL_ENABLE;
117848056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), rxdctl);
117948056c88SJack F Vogel 		for (; j < 10; j++) {
118048056c88SJack F Vogel 			if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)) &
1181758cc3dcSJack F Vogel 			    IXGBE_RXDCTL_ENABLE)
1182758cc3dcSJack F Vogel 				break;
1183758cc3dcSJack F Vogel 			else
1184758cc3dcSJack F Vogel 				msec_delay(1);
1185758cc3dcSJack F Vogel 		}
1186758cc3dcSJack F Vogel 		wmb();
1187758cc3dcSJack F Vogel #ifdef DEV_NETMAP
1188758cc3dcSJack F Vogel 		/*
1189758cc3dcSJack F Vogel 		 * In netmap mode, we must preserve the buffers made
1190758cc3dcSJack F Vogel 		 * available to userspace before the if_init()
1191758cc3dcSJack F Vogel 		 * (this is true by default on the TX side, because
1192758cc3dcSJack F Vogel 		 * init makes all buffers available to userspace).
1193758cc3dcSJack F Vogel 		 *
1194758cc3dcSJack F Vogel 		 * netmap_reset() and the device specific routines
1195758cc3dcSJack F Vogel 		 * (e.g. ixgbe_setup_receive_rings()) map these
1196758cc3dcSJack F Vogel 		 * buffers at the end of the NIC ring, so here we
1197758cc3dcSJack F Vogel 		 * must set the RDT (tail) register to make sure
1198758cc3dcSJack F Vogel 		 * they are not overwritten.
1199758cc3dcSJack F Vogel 		 *
1200758cc3dcSJack F Vogel 		 * In this driver the NIC ring starts at RDH = 0,
1201758cc3dcSJack F Vogel 		 * RDT points to the last slot available for reception (?),
1202758cc3dcSJack F Vogel 		 * so RDT = num_rx_desc - 1 means the whole ring is available.
1203758cc3dcSJack F Vogel 		 */
1204758cc3dcSJack F Vogel 		if (ifp->if_capenable & IFCAP_NETMAP) {
1205758cc3dcSJack F Vogel 			struct netmap_adapter *na = NA(adapter->ifp);
1206758cc3dcSJack F Vogel 			struct netmap_kring *kring = &na->rx_rings[i];
1207758cc3dcSJack F Vogel 			int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
1208758cc3dcSJack F Vogel 
120948056c88SJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), t);
1210758cc3dcSJack F Vogel 		} else
1211758cc3dcSJack F Vogel #endif /* DEV_NETMAP */
121248056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), adapter->num_rx_desc - 1);
1213758cc3dcSJack F Vogel 	}
1214758cc3dcSJack F Vogel 
1215758cc3dcSJack F Vogel 	/* Enable Receive engine */
1216758cc3dcSJack F Vogel 	rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
1217758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82598EB)
1218758cc3dcSJack F Vogel 		rxctrl |= IXGBE_RXCTRL_DMBYPS;
1219758cc3dcSJack F Vogel 	rxctrl |= IXGBE_RXCTRL_RXEN;
1220758cc3dcSJack F Vogel 	ixgbe_enable_rx_dma(hw, rxctrl);
1221758cc3dcSJack F Vogel 
1222758cc3dcSJack F Vogel 	callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter);
1223758cc3dcSJack F Vogel 
1224758cc3dcSJack F Vogel 	/* Set up MSI/X routing */
1225758cc3dcSJack F Vogel 	if (ixgbe_enable_msix)  {
1226758cc3dcSJack F Vogel 		ixgbe_configure_ivars(adapter);
1227758cc3dcSJack F Vogel 		/* Set up auto-mask */
1228758cc3dcSJack F Vogel 		if (hw->mac.type == ixgbe_mac_82598EB)
1229758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
1230758cc3dcSJack F Vogel 		else {
1231758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF);
1232758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF);
1233758cc3dcSJack F Vogel 		}
1234758cc3dcSJack F Vogel 	} else {  /* Simple settings for Legacy/MSI */
1235758cc3dcSJack F Vogel                 ixgbe_set_ivar(adapter, 0, 0, 0);
1236758cc3dcSJack F Vogel                 ixgbe_set_ivar(adapter, 0, 0, 1);
1237758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
1238758cc3dcSJack F Vogel 	}
1239758cc3dcSJack F Vogel 
1240758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
1241758cc3dcSJack F Vogel 	/* Init Flow director */
1242758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
1243758cc3dcSJack F Vogel 		u32 hdrm = 32 << fdir_pballoc;
1244758cc3dcSJack F Vogel 
1245758cc3dcSJack F Vogel 		hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL);
1246758cc3dcSJack F Vogel 		ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc);
1247758cc3dcSJack F Vogel 	}
1248758cc3dcSJack F Vogel #endif
1249758cc3dcSJack F Vogel 
1250758cc3dcSJack F Vogel 	/*
125148056c88SJack F Vogel 	 * Check on any SFP devices that
125248056c88SJack F Vogel 	 * need to be kick-started
1253758cc3dcSJack F Vogel 	 */
1254758cc3dcSJack F Vogel 	if (hw->phy.type == ixgbe_phy_none) {
1255a9ca1c79SSean Bruno 		err = hw->phy.ops.identify(hw);
1256758cc3dcSJack F Vogel 		if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
1257758cc3dcSJack F Vogel                 	device_printf(dev,
1258758cc3dcSJack F Vogel 			    "Unsupported SFP+ module type was detected.\n");
1259758cc3dcSJack F Vogel 			return;
1260758cc3dcSJack F Vogel         	}
1261758cc3dcSJack F Vogel 	}
1262758cc3dcSJack F Vogel 
1263758cc3dcSJack F Vogel 	/* Set moderation on the Link interrupt */
1264758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR);
1265758cc3dcSJack F Vogel 
12666f37f232SEric Joyner 	/* Configure Energy Efficient Ethernet for supported devices */
1267a9ca1c79SSean Bruno 	if (hw->mac.ops.setup_eee) {
1268a9ca1c79SSean Bruno 		err = hw->mac.ops.setup_eee(hw, adapter->eee_enabled);
1269a9ca1c79SSean Bruno 		if (err)
1270a9ca1c79SSean Bruno 			device_printf(dev, "Error setting up EEE: %d\n", err);
1271a9ca1c79SSean Bruno 	}
12726f37f232SEric Joyner 
12731ebf555bSSteven Hartland 	/* Enable power to the phy. */
12741ebf555bSSteven Hartland 	ixgbe_set_phy_power(hw, TRUE);
12751ebf555bSSteven Hartland 
1276758cc3dcSJack F Vogel 	/* Config/Enable Link */
1277758cc3dcSJack F Vogel 	ixgbe_config_link(adapter);
1278758cc3dcSJack F Vogel 
1279758cc3dcSJack F Vogel 	/* Hardware Packet Buffer & Flow Control setup */
12806f37f232SEric Joyner 	ixgbe_config_delay_values(adapter);
1281758cc3dcSJack F Vogel 
1282758cc3dcSJack F Vogel 	/* Initialize the FC settings */
1283758cc3dcSJack F Vogel 	ixgbe_start_hw(hw);
1284758cc3dcSJack F Vogel 
1285758cc3dcSJack F Vogel 	/* Set up VLAN support and filter */
1286758cc3dcSJack F Vogel 	ixgbe_setup_vlan_hw_support(adapter);
1287758cc3dcSJack F Vogel 
12886f37f232SEric Joyner 	/* Setup DMA Coalescing */
12896f37f232SEric Joyner 	ixgbe_config_dmac(adapter);
12906f37f232SEric Joyner 
1291758cc3dcSJack F Vogel 	/* And now turn on interrupts */
1292758cc3dcSJack F Vogel 	ixgbe_enable_intr(adapter);
1293758cc3dcSJack F Vogel 
129448056c88SJack F Vogel #ifdef PCI_IOV
129548056c88SJack F Vogel 	/* Enable the use of the MBX by the VF's */
129648056c88SJack F Vogel 	{
129748056c88SJack F Vogel 		u32 reg = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
129848056c88SJack F Vogel 		reg |= IXGBE_CTRL_EXT_PFRSTD;
129948056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, reg);
130048056c88SJack F Vogel 	}
130148056c88SJack F Vogel #endif
130248056c88SJack F Vogel 
1303758cc3dcSJack F Vogel 	/* Now inform the stack we're ready */
1304758cc3dcSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1305758cc3dcSJack F Vogel 
1306758cc3dcSJack F Vogel 	return;
1307758cc3dcSJack F Vogel }
1308758cc3dcSJack F Vogel 
1309758cc3dcSJack F Vogel static void
1310758cc3dcSJack F Vogel ixgbe_init(void *arg)
1311758cc3dcSJack F Vogel {
1312758cc3dcSJack F Vogel 	struct adapter *adapter = arg;
1313758cc3dcSJack F Vogel 
1314758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
1315758cc3dcSJack F Vogel 	ixgbe_init_locked(adapter);
1316758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
1317758cc3dcSJack F Vogel 	return;
1318758cc3dcSJack F Vogel }
1319758cc3dcSJack F Vogel 
13206f37f232SEric Joyner static void
132148056c88SJack F Vogel ixgbe_config_gpie(struct adapter *adapter)
132248056c88SJack F Vogel {
132348056c88SJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
132448056c88SJack F Vogel 	u32 gpie;
132548056c88SJack F Vogel 
132648056c88SJack F Vogel 	gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
132748056c88SJack F Vogel 
132848056c88SJack F Vogel 	/* Fan Failure Interrupt */
132948056c88SJack F Vogel 	if (hw->device_id == IXGBE_DEV_ID_82598AT)
133048056c88SJack F Vogel 		gpie |= IXGBE_SDP1_GPIEN;
133148056c88SJack F Vogel 
133248056c88SJack F Vogel 	/*
133348056c88SJack F Vogel 	 * Module detection (SDP2)
133448056c88SJack F Vogel 	 * Media ready (SDP1)
133548056c88SJack F Vogel 	 */
133648056c88SJack F Vogel 	if (hw->mac.type == ixgbe_mac_82599EB) {
133748056c88SJack F Vogel 		gpie |= IXGBE_SDP2_GPIEN;
133848056c88SJack F Vogel 		if (hw->device_id != IXGBE_DEV_ID_82599_QSFP_SF_QP)
133948056c88SJack F Vogel 			gpie |= IXGBE_SDP1_GPIEN;
134048056c88SJack F Vogel 	}
134148056c88SJack F Vogel 
134248056c88SJack F Vogel 	/*
134348056c88SJack F Vogel 	 * Thermal Failure Detection (X540)
1344a9ca1c79SSean Bruno 	 * Link Detection (X552 SFP+, X552/X557-AT)
134548056c88SJack F Vogel 	 */
134648056c88SJack F Vogel 	if (hw->mac.type == ixgbe_mac_X540 ||
134748056c88SJack F Vogel 	    hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
134848056c88SJack F Vogel 	    hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T)
134948056c88SJack F Vogel 		gpie |= IXGBE_SDP0_GPIEN_X540;
135048056c88SJack F Vogel 
135148056c88SJack F Vogel 	if (adapter->msix > 1) {
135248056c88SJack F Vogel 		/* Enable Enhanced MSIX mode */
135348056c88SJack F Vogel 		gpie |= IXGBE_GPIE_MSIX_MODE;
135448056c88SJack F Vogel 		gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT |
135548056c88SJack F Vogel 		    IXGBE_GPIE_OCD;
135648056c88SJack F Vogel 	}
135748056c88SJack F Vogel 
135848056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
135948056c88SJack F Vogel 	return;
136048056c88SJack F Vogel }
136148056c88SJack F Vogel 
136248056c88SJack F Vogel /*
136348056c88SJack F Vogel  * Requires adapter->max_frame_size to be set.
136448056c88SJack F Vogel  */
136548056c88SJack F Vogel static void
13666f37f232SEric Joyner ixgbe_config_delay_values(struct adapter *adapter)
13676f37f232SEric Joyner {
13686f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
13696f37f232SEric Joyner 	u32 rxpb, frame, size, tmp;
13706f37f232SEric Joyner 
13716f37f232SEric Joyner 	frame = adapter->max_frame_size;
13726f37f232SEric Joyner 
13736f37f232SEric Joyner 	/* Calculate High Water */
13746f37f232SEric Joyner 	switch (hw->mac.type) {
13756f37f232SEric Joyner 	case ixgbe_mac_X540:
13766f37f232SEric Joyner 	case ixgbe_mac_X550:
13776f37f232SEric Joyner 	case ixgbe_mac_X550EM_x:
13786f37f232SEric Joyner 		tmp = IXGBE_DV_X540(frame, frame);
13796f37f232SEric Joyner 		break;
13806f37f232SEric Joyner 	default:
13816f37f232SEric Joyner 		tmp = IXGBE_DV(frame, frame);
13826f37f232SEric Joyner 		break;
13836f37f232SEric Joyner 	}
13846f37f232SEric Joyner 	size = IXGBE_BT2KB(tmp);
13856f37f232SEric Joyner 	rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10;
13866f37f232SEric Joyner 	hw->fc.high_water[0] = rxpb - size;
13876f37f232SEric Joyner 
13886f37f232SEric Joyner 	/* Now calculate Low Water */
13896f37f232SEric Joyner 	switch (hw->mac.type) {
13906f37f232SEric Joyner 	case ixgbe_mac_X540:
13916f37f232SEric Joyner 	case ixgbe_mac_X550:
13926f37f232SEric Joyner 	case ixgbe_mac_X550EM_x:
13936f37f232SEric Joyner 		tmp = IXGBE_LOW_DV_X540(frame);
13946f37f232SEric Joyner 		break;
13956f37f232SEric Joyner 	default:
13966f37f232SEric Joyner 		tmp = IXGBE_LOW_DV(frame);
13976f37f232SEric Joyner 		break;
13986f37f232SEric Joyner 	}
13996f37f232SEric Joyner 	hw->fc.low_water[0] = IXGBE_BT2KB(tmp);
14006f37f232SEric Joyner 
14016f37f232SEric Joyner 	hw->fc.requested_mode = adapter->fc;
14026f37f232SEric Joyner 	hw->fc.pause_time = IXGBE_FC_PAUSE;
14036f37f232SEric Joyner 	hw->fc.send_xon = TRUE;
14046f37f232SEric Joyner }
1405758cc3dcSJack F Vogel 
1406758cc3dcSJack F Vogel /*
1407758cc3dcSJack F Vogel **
1408758cc3dcSJack F Vogel ** MSIX Interrupt Handlers and Tasklets
1409758cc3dcSJack F Vogel **
1410758cc3dcSJack F Vogel */
1411758cc3dcSJack F Vogel 
1412758cc3dcSJack F Vogel static inline void
1413758cc3dcSJack F Vogel ixgbe_enable_queue(struct adapter *adapter, u32 vector)
1414758cc3dcSJack F Vogel {
1415758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
1416758cc3dcSJack F Vogel 	u64	queue = (u64)(1 << vector);
1417758cc3dcSJack F Vogel 	u32	mask;
1418758cc3dcSJack F Vogel 
1419758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82598EB) {
1420758cc3dcSJack F Vogel                 mask = (IXGBE_EIMS_RTX_QUEUE & queue);
1421758cc3dcSJack F Vogel                 IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask);
1422758cc3dcSJack F Vogel 	} else {
1423758cc3dcSJack F Vogel                 mask = (queue & 0xFFFFFFFF);
1424758cc3dcSJack F Vogel                 if (mask)
1425758cc3dcSJack F Vogel                         IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask);
1426758cc3dcSJack F Vogel                 mask = (queue >> 32);
1427758cc3dcSJack F Vogel                 if (mask)
1428758cc3dcSJack F Vogel                         IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask);
1429758cc3dcSJack F Vogel 	}
1430758cc3dcSJack F Vogel }
1431758cc3dcSJack F Vogel 
1432758cc3dcSJack F Vogel static inline void
1433758cc3dcSJack F Vogel ixgbe_disable_queue(struct adapter *adapter, u32 vector)
1434758cc3dcSJack F Vogel {
1435758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
1436758cc3dcSJack F Vogel 	u64	queue = (u64)(1 << vector);
1437758cc3dcSJack F Vogel 	u32	mask;
1438758cc3dcSJack F Vogel 
1439758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82598EB) {
1440758cc3dcSJack F Vogel                 mask = (IXGBE_EIMS_RTX_QUEUE & queue);
1441758cc3dcSJack F Vogel                 IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask);
1442758cc3dcSJack F Vogel 	} else {
1443758cc3dcSJack F Vogel                 mask = (queue & 0xFFFFFFFF);
1444758cc3dcSJack F Vogel                 if (mask)
1445758cc3dcSJack F Vogel                         IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask);
1446758cc3dcSJack F Vogel                 mask = (queue >> 32);
1447758cc3dcSJack F Vogel                 if (mask)
1448758cc3dcSJack F Vogel                         IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask);
1449758cc3dcSJack F Vogel 	}
1450758cc3dcSJack F Vogel }
1451758cc3dcSJack F Vogel 
1452758cc3dcSJack F Vogel static void
1453758cc3dcSJack F Vogel ixgbe_handle_que(void *context, int pending)
1454758cc3dcSJack F Vogel {
1455758cc3dcSJack F Vogel 	struct ix_queue *que = context;
1456758cc3dcSJack F Vogel 	struct adapter  *adapter = que->adapter;
1457758cc3dcSJack F Vogel 	struct tx_ring  *txr = que->txr;
1458758cc3dcSJack F Vogel 	struct ifnet    *ifp = adapter->ifp;
1459758cc3dcSJack F Vogel 
1460758cc3dcSJack F Vogel 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
146148056c88SJack F Vogel 		ixgbe_rxeof(que);
1462758cc3dcSJack F Vogel 		IXGBE_TX_LOCK(txr);
1463758cc3dcSJack F Vogel 		ixgbe_txeof(txr);
1464758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
1465758cc3dcSJack F Vogel 		if (!drbr_empty(ifp, txr->br))
1466758cc3dcSJack F Vogel 			ixgbe_mq_start_locked(ifp, txr);
1467758cc3dcSJack F Vogel #else
1468758cc3dcSJack F Vogel 		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1469758cc3dcSJack F Vogel 			ixgbe_start_locked(txr, ifp);
1470758cc3dcSJack F Vogel #endif
1471758cc3dcSJack F Vogel 		IXGBE_TX_UNLOCK(txr);
1472758cc3dcSJack F Vogel 	}
1473758cc3dcSJack F Vogel 
1474758cc3dcSJack F Vogel 	/* Reenable this interrupt */
1475758cc3dcSJack F Vogel 	if (que->res != NULL)
1476758cc3dcSJack F Vogel 		ixgbe_enable_queue(adapter, que->msix);
1477758cc3dcSJack F Vogel 	else
1478758cc3dcSJack F Vogel 		ixgbe_enable_intr(adapter);
1479758cc3dcSJack F Vogel 	return;
1480758cc3dcSJack F Vogel }
1481758cc3dcSJack F Vogel 
1482758cc3dcSJack F Vogel 
1483758cc3dcSJack F Vogel /*********************************************************************
1484758cc3dcSJack F Vogel  *
1485758cc3dcSJack F Vogel  *  Legacy Interrupt Service routine
1486758cc3dcSJack F Vogel  *
1487758cc3dcSJack F Vogel  **********************************************************************/
1488758cc3dcSJack F Vogel 
1489758cc3dcSJack F Vogel static void
1490758cc3dcSJack F Vogel ixgbe_legacy_irq(void *arg)
1491758cc3dcSJack F Vogel {
1492758cc3dcSJack F Vogel 	struct ix_queue *que = arg;
1493758cc3dcSJack F Vogel 	struct adapter	*adapter = que->adapter;
1494758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
1495758cc3dcSJack F Vogel 	struct ifnet    *ifp = adapter->ifp;
1496758cc3dcSJack F Vogel 	struct 		tx_ring *txr = adapter->tx_rings;
1497758cc3dcSJack F Vogel 	bool		more;
1498758cc3dcSJack F Vogel 	u32       	reg_eicr;
1499758cc3dcSJack F Vogel 
1500758cc3dcSJack F Vogel 
1501758cc3dcSJack F Vogel 	reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
1502758cc3dcSJack F Vogel 
1503758cc3dcSJack F Vogel 	++que->irqs;
1504758cc3dcSJack F Vogel 	if (reg_eicr == 0) {
1505758cc3dcSJack F Vogel 		ixgbe_enable_intr(adapter);
1506758cc3dcSJack F Vogel 		return;
1507758cc3dcSJack F Vogel 	}
1508758cc3dcSJack F Vogel 
1509758cc3dcSJack F Vogel 	more = ixgbe_rxeof(que);
1510758cc3dcSJack F Vogel 
1511758cc3dcSJack F Vogel 	IXGBE_TX_LOCK(txr);
1512758cc3dcSJack F Vogel 	ixgbe_txeof(txr);
1513758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX
1514758cc3dcSJack F Vogel 	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1515758cc3dcSJack F Vogel 		ixgbe_start_locked(txr, ifp);
1516758cc3dcSJack F Vogel #else
1517758cc3dcSJack F Vogel 	if (!drbr_empty(ifp, txr->br))
1518758cc3dcSJack F Vogel 		ixgbe_mq_start_locked(ifp, txr);
1519758cc3dcSJack F Vogel #endif
1520758cc3dcSJack F Vogel 	IXGBE_TX_UNLOCK(txr);
1521758cc3dcSJack F Vogel 
1522758cc3dcSJack F Vogel 	/* Check for fan failure */
152348056c88SJack F Vogel 	if ((hw->device_id == IXGBE_DEV_ID_82598AT) &&
152448056c88SJack F Vogel 	    (reg_eicr & IXGBE_EICR_GPI_SDP1)) {
1525758cc3dcSJack F Vogel                 device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! "
1526758cc3dcSJack F Vogel 		    "REPLACE IMMEDIATELY!!\n");
1527758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
1528758cc3dcSJack F Vogel 	}
1529758cc3dcSJack F Vogel 
1530758cc3dcSJack F Vogel 	/* Link status change */
1531758cc3dcSJack F Vogel 	if (reg_eicr & IXGBE_EICR_LSC)
1532758cc3dcSJack F Vogel 		taskqueue_enqueue(adapter->tq, &adapter->link_task);
1533758cc3dcSJack F Vogel 
15346f37f232SEric Joyner 	/* External PHY interrupt */
15356f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
15366f37f232SEric Joyner 	    (reg_eicr & IXGBE_EICR_GPI_SDP0_X540))
15376f37f232SEric Joyner 		taskqueue_enqueue(adapter->tq, &adapter->phy_task);
15386f37f232SEric Joyner 
1539758cc3dcSJack F Vogel 	if (more)
1540758cc3dcSJack F Vogel 		taskqueue_enqueue(que->tq, &que->que_task);
1541758cc3dcSJack F Vogel 	else
1542758cc3dcSJack F Vogel 		ixgbe_enable_intr(adapter);
1543758cc3dcSJack F Vogel 	return;
1544758cc3dcSJack F Vogel }
1545758cc3dcSJack F Vogel 
1546758cc3dcSJack F Vogel 
1547758cc3dcSJack F Vogel /*********************************************************************
1548758cc3dcSJack F Vogel  *
1549758cc3dcSJack F Vogel  *  MSIX Queue Interrupt Service routine
1550758cc3dcSJack F Vogel  *
1551758cc3dcSJack F Vogel  **********************************************************************/
1552758cc3dcSJack F Vogel void
1553758cc3dcSJack F Vogel ixgbe_msix_que(void *arg)
1554758cc3dcSJack F Vogel {
1555758cc3dcSJack F Vogel 	struct ix_queue	*que = arg;
1556758cc3dcSJack F Vogel 	struct adapter  *adapter = que->adapter;
1557758cc3dcSJack F Vogel 	struct ifnet    *ifp = adapter->ifp;
1558758cc3dcSJack F Vogel 	struct tx_ring	*txr = que->txr;
1559758cc3dcSJack F Vogel 	struct rx_ring	*rxr = que->rxr;
1560758cc3dcSJack F Vogel 	bool		more;
1561758cc3dcSJack F Vogel 	u32		newitr = 0;
1562758cc3dcSJack F Vogel 
156348056c88SJack F Vogel 
1564758cc3dcSJack F Vogel 	/* Protect against spurious interrupts */
1565758cc3dcSJack F Vogel 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1566758cc3dcSJack F Vogel 		return;
1567758cc3dcSJack F Vogel 
1568758cc3dcSJack F Vogel 	ixgbe_disable_queue(adapter, que->msix);
1569758cc3dcSJack F Vogel 	++que->irqs;
1570758cc3dcSJack F Vogel 
1571758cc3dcSJack F Vogel 	more = ixgbe_rxeof(que);
1572758cc3dcSJack F Vogel 
1573758cc3dcSJack F Vogel 	IXGBE_TX_LOCK(txr);
1574758cc3dcSJack F Vogel 	ixgbe_txeof(txr);
1575758cc3dcSJack F Vogel #ifdef IXGBE_LEGACY_TX
1576758cc3dcSJack F Vogel 	if (!IFQ_DRV_IS_EMPTY(ifp->if_snd))
1577758cc3dcSJack F Vogel 		ixgbe_start_locked(txr, ifp);
1578758cc3dcSJack F Vogel #else
1579758cc3dcSJack F Vogel 	if (!drbr_empty(ifp, txr->br))
1580758cc3dcSJack F Vogel 		ixgbe_mq_start_locked(ifp, txr);
1581758cc3dcSJack F Vogel #endif
1582758cc3dcSJack F Vogel 	IXGBE_TX_UNLOCK(txr);
1583758cc3dcSJack F Vogel 
1584758cc3dcSJack F Vogel 	/* Do AIM now? */
1585758cc3dcSJack F Vogel 
1586f2c4db54SSteven Hartland 	if (adapter->enable_aim == FALSE)
1587758cc3dcSJack F Vogel 		goto no_calc;
1588758cc3dcSJack F Vogel 	/*
1589758cc3dcSJack F Vogel 	** Do Adaptive Interrupt Moderation:
1590758cc3dcSJack F Vogel         **  - Write out last calculated setting
1591758cc3dcSJack F Vogel 	**  - Calculate based on average size over
1592758cc3dcSJack F Vogel 	**    the last interval.
1593758cc3dcSJack F Vogel 	*/
1594758cc3dcSJack F Vogel         if (que->eitr_setting)
1595758cc3dcSJack F Vogel                 IXGBE_WRITE_REG(&adapter->hw,
1596758cc3dcSJack F Vogel                     IXGBE_EITR(que->msix), que->eitr_setting);
1597758cc3dcSJack F Vogel 
1598758cc3dcSJack F Vogel         que->eitr_setting = 0;
1599758cc3dcSJack F Vogel 
1600758cc3dcSJack F Vogel         /* Idle, do nothing */
1601758cc3dcSJack F Vogel         if ((txr->bytes == 0) && (rxr->bytes == 0))
1602758cc3dcSJack F Vogel                 goto no_calc;
1603758cc3dcSJack F Vogel 
1604758cc3dcSJack F Vogel 	if ((txr->bytes) && (txr->packets))
1605758cc3dcSJack F Vogel                	newitr = txr->bytes/txr->packets;
1606758cc3dcSJack F Vogel 	if ((rxr->bytes) && (rxr->packets))
1607758cc3dcSJack F Vogel 		newitr = max(newitr,
1608758cc3dcSJack F Vogel 		    (rxr->bytes / rxr->packets));
1609758cc3dcSJack F Vogel 	newitr += 24; /* account for hardware frame, crc */
1610758cc3dcSJack F Vogel 
1611758cc3dcSJack F Vogel 	/* set an upper boundary */
1612758cc3dcSJack F Vogel 	newitr = min(newitr, 3000);
1613758cc3dcSJack F Vogel 
1614758cc3dcSJack F Vogel 	/* Be nice to the mid range */
1615758cc3dcSJack F Vogel 	if ((newitr > 300) && (newitr < 1200))
1616758cc3dcSJack F Vogel 		newitr = (newitr / 3);
1617758cc3dcSJack F Vogel 	else
1618758cc3dcSJack F Vogel 		newitr = (newitr / 2);
1619758cc3dcSJack F Vogel 
1620758cc3dcSJack F Vogel         if (adapter->hw.mac.type == ixgbe_mac_82598EB)
1621758cc3dcSJack F Vogel                 newitr |= newitr << 16;
1622758cc3dcSJack F Vogel         else
1623758cc3dcSJack F Vogel                 newitr |= IXGBE_EITR_CNT_WDIS;
1624758cc3dcSJack F Vogel 
1625758cc3dcSJack F Vogel         /* save for next interrupt */
1626758cc3dcSJack F Vogel         que->eitr_setting = newitr;
1627758cc3dcSJack F Vogel 
1628758cc3dcSJack F Vogel         /* Reset state */
1629758cc3dcSJack F Vogel         txr->bytes = 0;
1630758cc3dcSJack F Vogel         txr->packets = 0;
1631758cc3dcSJack F Vogel         rxr->bytes = 0;
1632758cc3dcSJack F Vogel         rxr->packets = 0;
1633758cc3dcSJack F Vogel 
1634758cc3dcSJack F Vogel no_calc:
1635758cc3dcSJack F Vogel 	if (more)
1636758cc3dcSJack F Vogel 		taskqueue_enqueue(que->tq, &que->que_task);
1637758cc3dcSJack F Vogel 	else
1638758cc3dcSJack F Vogel 		ixgbe_enable_queue(adapter, que->msix);
1639758cc3dcSJack F Vogel 	return;
1640758cc3dcSJack F Vogel }
1641758cc3dcSJack F Vogel 
1642758cc3dcSJack F Vogel 
1643758cc3dcSJack F Vogel static void
1644758cc3dcSJack F Vogel ixgbe_msix_link(void *arg)
1645758cc3dcSJack F Vogel {
1646758cc3dcSJack F Vogel 	struct adapter	*adapter = arg;
1647758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
16486f37f232SEric Joyner 	u32		reg_eicr, mod_mask;
1649758cc3dcSJack F Vogel 
16506f37f232SEric Joyner 	++adapter->link_irq;
1651758cc3dcSJack F Vogel 
1652a9ca1c79SSean Bruno 	/* Pause other interrupts */
1653a9ca1c79SSean Bruno 	IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_OTHER);
1654a9ca1c79SSean Bruno 
1655758cc3dcSJack F Vogel 	/* First get the cause */
1656758cc3dcSJack F Vogel 	reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
1657758cc3dcSJack F Vogel 	/* Be sure the queue bits are not cleared */
1658758cc3dcSJack F Vogel 	reg_eicr &= ~IXGBE_EICR_RTX_QUEUE;
1659758cc3dcSJack F Vogel 	/* Clear interrupt with write */
1660758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr);
1661758cc3dcSJack F Vogel 
1662758cc3dcSJack F Vogel 	/* Link status change */
1663a9ca1c79SSean Bruno 	if (reg_eicr & IXGBE_EICR_LSC) {
1664a9ca1c79SSean Bruno 		IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC);
1665758cc3dcSJack F Vogel 		taskqueue_enqueue(adapter->tq, &adapter->link_task);
1666a9ca1c79SSean Bruno 	}
1667758cc3dcSJack F Vogel 
1668758cc3dcSJack F Vogel 	if (adapter->hw.mac.type != ixgbe_mac_82598EB) {
1669758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
1670758cc3dcSJack F Vogel 		if (reg_eicr & IXGBE_EICR_FLOW_DIR) {
1671758cc3dcSJack F Vogel 			/* This is probably overkill :) */
1672758cc3dcSJack F Vogel 			if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1))
1673758cc3dcSJack F Vogel 				return;
1674758cc3dcSJack F Vogel                 	/* Disable the interrupt */
1675758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR);
1676758cc3dcSJack F Vogel 			taskqueue_enqueue(adapter->tq, &adapter->fdir_task);
1677758cc3dcSJack F Vogel 		} else
1678758cc3dcSJack F Vogel #endif
1679758cc3dcSJack F Vogel 		if (reg_eicr & IXGBE_EICR_ECC) {
1680a9ca1c79SSean Bruno 			device_printf(adapter->dev, "CRITICAL: ECC ERROR!! "
1681758cc3dcSJack F Vogel 			    "Please Reboot!!\n");
1682758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC);
16836f37f232SEric Joyner 		}
16846f37f232SEric Joyner 
16856f37f232SEric Joyner 		/* Check for over temp condition */
16866f37f232SEric Joyner 		if (reg_eicr & IXGBE_EICR_TS) {
1687a9ca1c79SSean Bruno 			device_printf(adapter->dev, "CRITICAL: OVER TEMP!! "
16886f37f232SEric Joyner 			    "PHY IS SHUT DOWN!!\n");
16896f37f232SEric Joyner 			device_printf(adapter->dev, "System shutdown required!\n");
16906f37f232SEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS);
16916f37f232SEric Joyner 		}
169248056c88SJack F Vogel #ifdef PCI_IOV
169348056c88SJack F Vogel 		if (reg_eicr & IXGBE_EICR_MAILBOX)
169448056c88SJack F Vogel 			taskqueue_enqueue(adapter->tq, &adapter->mbx_task);
169548056c88SJack F Vogel #endif
16966f37f232SEric Joyner 	}
16976f37f232SEric Joyner 
16986f37f232SEric Joyner 	/* Pluggable optics-related interrupt */
16996f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP)
17006f37f232SEric Joyner 		mod_mask = IXGBE_EICR_GPI_SDP0_X540;
17016f37f232SEric Joyner 	else
17026f37f232SEric Joyner 		mod_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw);
1703758cc3dcSJack F Vogel 
1704758cc3dcSJack F Vogel 	if (ixgbe_is_sfp(hw)) {
17056f37f232SEric Joyner 		if (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) {
1706758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
1707758cc3dcSJack F Vogel 			taskqueue_enqueue(adapter->tq, &adapter->msf_task);
17086f37f232SEric Joyner 		} else if (reg_eicr & mod_mask) {
17096f37f232SEric Joyner 			IXGBE_WRITE_REG(hw, IXGBE_EICR, mod_mask);
1710758cc3dcSJack F Vogel 			taskqueue_enqueue(adapter->tq, &adapter->mod_task);
1711758cc3dcSJack F Vogel 		}
1712758cc3dcSJack F Vogel 	}
1713758cc3dcSJack F Vogel 
1714758cc3dcSJack F Vogel 	/* Check for fan failure */
1715758cc3dcSJack F Vogel 	if ((hw->device_id == IXGBE_DEV_ID_82598AT) &&
17166f37f232SEric Joyner 	    (reg_eicr & IXGBE_EICR_GPI_SDP1)) {
17176f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
1718758cc3dcSJack F Vogel                 device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! "
1719758cc3dcSJack F Vogel 		    "REPLACE IMMEDIATELY!!\n");
1720758cc3dcSJack F Vogel 	}
1721758cc3dcSJack F Vogel 
17226f37f232SEric Joyner 	/* External PHY interrupt */
17236f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
17246f37f232SEric Joyner 	    (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) {
17256f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540);
17266f37f232SEric Joyner 		taskqueue_enqueue(adapter->tq, &adapter->phy_task);
1727758cc3dcSJack F Vogel 	}
1728758cc3dcSJack F Vogel 
1729a9ca1c79SSean Bruno 	/* Re-enable other interrupts */
1730758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
1731758cc3dcSJack F Vogel 	return;
1732758cc3dcSJack F Vogel }
1733758cc3dcSJack F Vogel 
1734758cc3dcSJack F Vogel /*********************************************************************
1735758cc3dcSJack F Vogel  *
1736758cc3dcSJack F Vogel  *  Media Ioctl callback
1737758cc3dcSJack F Vogel  *
1738758cc3dcSJack F Vogel  *  This routine is called whenever the user queries the status of
1739758cc3dcSJack F Vogel  *  the interface using ifconfig.
1740758cc3dcSJack F Vogel  *
1741758cc3dcSJack F Vogel  **********************************************************************/
1742758cc3dcSJack F Vogel static void
1743758cc3dcSJack F Vogel ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
1744758cc3dcSJack F Vogel {
1745758cc3dcSJack F Vogel 	struct adapter *adapter = ifp->if_softc;
1746758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
1747758cc3dcSJack F Vogel 	int layer;
1748758cc3dcSJack F Vogel 
1749758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_media_status: begin");
1750758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
1751758cc3dcSJack F Vogel 	ixgbe_update_link_status(adapter);
1752758cc3dcSJack F Vogel 
1753758cc3dcSJack F Vogel 	ifmr->ifm_status = IFM_AVALID;
1754758cc3dcSJack F Vogel 	ifmr->ifm_active = IFM_ETHER;
1755758cc3dcSJack F Vogel 
1756758cc3dcSJack F Vogel 	if (!adapter->link_active) {
1757758cc3dcSJack F Vogel 		IXGBE_CORE_UNLOCK(adapter);
1758758cc3dcSJack F Vogel 		return;
1759758cc3dcSJack F Vogel 	}
1760758cc3dcSJack F Vogel 
1761758cc3dcSJack F Vogel 	ifmr->ifm_status |= IFM_ACTIVE;
176248056c88SJack F Vogel 	layer = adapter->phy_layer;
1763758cc3dcSJack F Vogel 
1764758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T ||
1765758cc3dcSJack F Vogel 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_T ||
1766758cc3dcSJack F Vogel 	    layer & IXGBE_PHYSICAL_LAYER_100BASE_TX)
1767758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1768758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1769758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
1770758cc3dcSJack F Vogel 			break;
1771758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
1772758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_1000_T | IFM_FDX;
1773758cc3dcSJack F Vogel 			break;
1774758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_100_FULL:
1775758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
1776758cc3dcSJack F Vogel 			break;
1777758cc3dcSJack F Vogel 		}
1778758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU ||
1779758cc3dcSJack F Vogel 	    layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA)
1780758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1781758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1782758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX | IFM_FDX;
1783758cc3dcSJack F Vogel 			break;
1784758cc3dcSJack F Vogel 		}
1785758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR)
1786758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1787758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1788758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LR | IFM_FDX;
1789758cc3dcSJack F Vogel 			break;
1790758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
1791758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX | IFM_FDX;
1792758cc3dcSJack F Vogel 			break;
1793758cc3dcSJack F Vogel 		}
1794758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM)
1795758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1796758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1797758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LRM | IFM_FDX;
1798758cc3dcSJack F Vogel 			break;
1799758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
1800758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX | IFM_FDX;
1801758cc3dcSJack F Vogel 			break;
1802758cc3dcSJack F Vogel 		}
1803758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR ||
1804758cc3dcSJack F Vogel 	    layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX)
1805758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1806758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1807758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
1808758cc3dcSJack F Vogel 			break;
1809758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
1810758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_1000_SX | IFM_FDX;
1811758cc3dcSJack F Vogel 			break;
1812758cc3dcSJack F Vogel 		}
1813758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4)
1814758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1815758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
1816758cc3dcSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX;
1817758cc3dcSJack F Vogel 			break;
1818758cc3dcSJack F Vogel 		}
1819758cc3dcSJack F Vogel 	/*
1820758cc3dcSJack F Vogel 	** XXX: These need to use the proper media types once
1821758cc3dcSJack F Vogel 	** they're added.
1822758cc3dcSJack F Vogel 	*/
1823a9ca1c79SSean Bruno #ifndef IFM_ETH_XTYPE
1824758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR)
1825758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1826758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
18276f37f232SEric Joyner 			ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
18286f37f232SEric Joyner 			break;
18296f37f232SEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
18306f37f232SEric Joyner 			ifmr->ifm_active |= IFM_2500_SX | IFM_FDX;
1831758cc3dcSJack F Vogel 			break;
1832758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
18336f37f232SEric Joyner 			ifmr->ifm_active |= IFM_1000_CX | IFM_FDX;
1834758cc3dcSJack F Vogel 			break;
1835758cc3dcSJack F Vogel 		}
18366f37f232SEric Joyner 	else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4
1837758cc3dcSJack F Vogel 	    || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX)
1838758cc3dcSJack F Vogel 		switch (adapter->link_speed) {
1839758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_10GB_FULL:
18406f37f232SEric Joyner 			ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX;
18416f37f232SEric Joyner 			break;
18426f37f232SEric Joyner 		case IXGBE_LINK_SPEED_2_5GB_FULL:
18436f37f232SEric Joyner 			ifmr->ifm_active |= IFM_2500_SX | IFM_FDX;
1844758cc3dcSJack F Vogel 			break;
1845758cc3dcSJack F Vogel 		case IXGBE_LINK_SPEED_1GB_FULL:
18466f37f232SEric Joyner 			ifmr->ifm_active |= IFM_1000_CX | IFM_FDX;
1847758cc3dcSJack F Vogel 			break;
1848758cc3dcSJack F Vogel 		}
1849a9ca1c79SSean Bruno #else
1850a9ca1c79SSean Bruno 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR)
1851a9ca1c79SSean Bruno 		switch (adapter->link_speed) {
1852a9ca1c79SSean Bruno 		case IXGBE_LINK_SPEED_10GB_FULL:
1853a9ca1c79SSean Bruno 			ifmr->ifm_active |= IFM_10G_KR | IFM_FDX;
1854a9ca1c79SSean Bruno 			break;
1855a9ca1c79SSean Bruno 		case IXGBE_LINK_SPEED_2_5GB_FULL:
1856a9ca1c79SSean Bruno 			ifmr->ifm_active |= IFM_2500_KX | IFM_FDX;
1857a9ca1c79SSean Bruno 			break;
1858a9ca1c79SSean Bruno 		case IXGBE_LINK_SPEED_1GB_FULL:
1859a9ca1c79SSean Bruno 			ifmr->ifm_active |= IFM_1000_KX | IFM_FDX;
1860a9ca1c79SSean Bruno 			break;
1861a9ca1c79SSean Bruno 		}
1862a9ca1c79SSean Bruno 	else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4
1863a9ca1c79SSean Bruno 	    || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX)
1864a9ca1c79SSean Bruno 		switch (adapter->link_speed) {
1865a9ca1c79SSean Bruno 		case IXGBE_LINK_SPEED_10GB_FULL:
1866a9ca1c79SSean Bruno 			ifmr->ifm_active |= IFM_10G_KX4 | IFM_FDX;
1867a9ca1c79SSean Bruno 			break;
1868a9ca1c79SSean Bruno 		case IXGBE_LINK_SPEED_2_5GB_FULL:
1869a9ca1c79SSean Bruno 			ifmr->ifm_active |= IFM_2500_KX | IFM_FDX;
1870a9ca1c79SSean Bruno 			break;
1871a9ca1c79SSean Bruno 		case IXGBE_LINK_SPEED_1GB_FULL:
1872a9ca1c79SSean Bruno 			ifmr->ifm_active |= IFM_1000_KX | IFM_FDX;
1873a9ca1c79SSean Bruno 			break;
1874a9ca1c79SSean Bruno 		}
1875a9ca1c79SSean Bruno #endif
1876758cc3dcSJack F Vogel 
1877758cc3dcSJack F Vogel 	/* If nothing is recognized... */
1878758cc3dcSJack F Vogel 	if (IFM_SUBTYPE(ifmr->ifm_active) == 0)
1879758cc3dcSJack F Vogel 		ifmr->ifm_active |= IFM_UNKNOWN;
1880758cc3dcSJack F Vogel 
1881758cc3dcSJack F Vogel #if __FreeBSD_version >= 900025
18826f37f232SEric Joyner 	/* Display current flow control setting used on link */
18836f37f232SEric Joyner 	if (hw->fc.current_mode == ixgbe_fc_rx_pause ||
18846f37f232SEric Joyner 	    hw->fc.current_mode == ixgbe_fc_full)
1885758cc3dcSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
18866f37f232SEric Joyner 	if (hw->fc.current_mode == ixgbe_fc_tx_pause ||
18876f37f232SEric Joyner 	    hw->fc.current_mode == ixgbe_fc_full)
1888758cc3dcSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
1889758cc3dcSJack F Vogel #endif
1890758cc3dcSJack F Vogel 
1891758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
1892758cc3dcSJack F Vogel 
1893758cc3dcSJack F Vogel 	return;
1894758cc3dcSJack F Vogel }
1895758cc3dcSJack F Vogel 
1896758cc3dcSJack F Vogel /*********************************************************************
1897758cc3dcSJack F Vogel  *
1898758cc3dcSJack F Vogel  *  Media Ioctl callback
1899758cc3dcSJack F Vogel  *
1900758cc3dcSJack F Vogel  *  This routine is called when the user changes speed/duplex using
1901758cc3dcSJack F Vogel  *  media/mediopt option with ifconfig.
1902758cc3dcSJack F Vogel  *
1903758cc3dcSJack F Vogel  **********************************************************************/
1904758cc3dcSJack F Vogel static int
1905758cc3dcSJack F Vogel ixgbe_media_change(struct ifnet * ifp)
1906758cc3dcSJack F Vogel {
1907758cc3dcSJack F Vogel 	struct adapter *adapter = ifp->if_softc;
1908758cc3dcSJack F Vogel 	struct ifmedia *ifm = &adapter->media;
1909758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
1910758cc3dcSJack F Vogel 	ixgbe_link_speed speed = 0;
1911758cc3dcSJack F Vogel 
1912758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_media_change: begin");
1913758cc3dcSJack F Vogel 
1914758cc3dcSJack F Vogel 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1915758cc3dcSJack F Vogel 		return (EINVAL);
1916758cc3dcSJack F Vogel 
19176f37f232SEric Joyner 	if (hw->phy.media_type == ixgbe_media_type_backplane)
1918a9ca1c79SSean Bruno 		return (ENODEV);
19196f37f232SEric Joyner 
1920758cc3dcSJack F Vogel 	/*
1921758cc3dcSJack F Vogel 	** We don't actually need to check against the supported
1922758cc3dcSJack F Vogel 	** media types of the adapter; ifmedia will take care of
1923758cc3dcSJack F Vogel 	** that for us.
1924758cc3dcSJack F Vogel 	*/
1925a9ca1c79SSean Bruno #ifndef IFM_ETH_XTYPE
1926758cc3dcSJack F Vogel 	switch (IFM_SUBTYPE(ifm->ifm_media)) {
1927758cc3dcSJack F Vogel 		case IFM_AUTO:
1928758cc3dcSJack F Vogel 		case IFM_10G_T:
1929758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_100_FULL;
1930758cc3dcSJack F Vogel 		case IFM_10G_LRM:
1931758cc3dcSJack F Vogel 		case IFM_10G_SR: /* KR, too */
1932758cc3dcSJack F Vogel 		case IFM_10G_LR:
19336f37f232SEric Joyner 		case IFM_10G_CX4: /* KX4 */
1934758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_1GB_FULL;
1935758cc3dcSJack F Vogel 		case IFM_10G_TWINAX:
1936758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_10GB_FULL;
1937758cc3dcSJack F Vogel 			break;
1938758cc3dcSJack F Vogel 		case IFM_1000_T:
1939758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_100_FULL;
1940758cc3dcSJack F Vogel 		case IFM_1000_LX:
1941758cc3dcSJack F Vogel 		case IFM_1000_SX:
19426f37f232SEric Joyner 		case IFM_1000_CX: /* KX */
1943758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_1GB_FULL;
1944758cc3dcSJack F Vogel 			break;
1945758cc3dcSJack F Vogel 		case IFM_100_TX:
1946758cc3dcSJack F Vogel 			speed |= IXGBE_LINK_SPEED_100_FULL;
1947758cc3dcSJack F Vogel 			break;
1948758cc3dcSJack F Vogel 		default:
1949758cc3dcSJack F Vogel 			goto invalid;
1950758cc3dcSJack F Vogel 	}
1951a9ca1c79SSean Bruno #else
1952a9ca1c79SSean Bruno 	switch (IFM_SUBTYPE(ifm->ifm_media)) {
1953a9ca1c79SSean Bruno 		case IFM_AUTO:
1954a9ca1c79SSean Bruno 		case IFM_10G_T:
1955a9ca1c79SSean Bruno 			speed |= IXGBE_LINK_SPEED_100_FULL;
1956a9ca1c79SSean Bruno 		case IFM_10G_LRM:
1957a9ca1c79SSean Bruno 		case IFM_10G_KR:
1958a9ca1c79SSean Bruno 		case IFM_10G_LR:
1959a9ca1c79SSean Bruno 		case IFM_10G_KX4:
1960a9ca1c79SSean Bruno 			speed |= IXGBE_LINK_SPEED_1GB_FULL;
1961a9ca1c79SSean Bruno 		case IFM_10G_TWINAX:
1962a9ca1c79SSean Bruno 			speed |= IXGBE_LINK_SPEED_10GB_FULL;
1963a9ca1c79SSean Bruno 			break;
1964a9ca1c79SSean Bruno 		case IFM_1000_T:
1965a9ca1c79SSean Bruno 			speed |= IXGBE_LINK_SPEED_100_FULL;
1966a9ca1c79SSean Bruno 		case IFM_1000_LX:
1967a9ca1c79SSean Bruno 		case IFM_1000_SX:
1968a9ca1c79SSean Bruno 		case IFM_1000_KX:
1969a9ca1c79SSean Bruno 			speed |= IXGBE_LINK_SPEED_1GB_FULL;
1970a9ca1c79SSean Bruno 			break;
1971a9ca1c79SSean Bruno 		case IFM_100_TX:
1972a9ca1c79SSean Bruno 			speed |= IXGBE_LINK_SPEED_100_FULL;
1973a9ca1c79SSean Bruno 			break;
1974a9ca1c79SSean Bruno 		default:
1975a9ca1c79SSean Bruno 			goto invalid;
1976a9ca1c79SSean Bruno 	}
1977a9ca1c79SSean Bruno #endif
1978758cc3dcSJack F Vogel 
1979758cc3dcSJack F Vogel 	hw->mac.autotry_restart = TRUE;
1980758cc3dcSJack F Vogel 	hw->mac.ops.setup_link(hw, speed, TRUE);
19811566d8d5SSteven Hartland 	if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
19821566d8d5SSteven Hartland 		adapter->advertise = 0;
19831566d8d5SSteven Hartland 	} else {
19841566d8d5SSteven Hartland 		if ((speed & IXGBE_LINK_SPEED_10GB_FULL) != 0)
19851566d8d5SSteven Hartland 			adapter->advertise |= 1 << 2;
19861566d8d5SSteven Hartland 		if ((speed & IXGBE_LINK_SPEED_1GB_FULL) != 0)
19871566d8d5SSteven Hartland 			adapter->advertise |= 1 << 1;
19881566d8d5SSteven Hartland 		if ((speed & IXGBE_LINK_SPEED_100_FULL) != 0)
19891566d8d5SSteven Hartland 			adapter->advertise |= 1 << 0;
19901566d8d5SSteven Hartland 	}
1991758cc3dcSJack F Vogel 
1992758cc3dcSJack F Vogel 	return (0);
1993758cc3dcSJack F Vogel 
1994758cc3dcSJack F Vogel invalid:
19956f37f232SEric Joyner 	device_printf(adapter->dev, "Invalid media type!\n");
1996758cc3dcSJack F Vogel 	return (EINVAL);
1997758cc3dcSJack F Vogel }
1998758cc3dcSJack F Vogel 
1999758cc3dcSJack F Vogel static void
2000758cc3dcSJack F Vogel ixgbe_set_promisc(struct adapter *adapter)
2001758cc3dcSJack F Vogel {
2002758cc3dcSJack F Vogel 	u_int32_t       reg_rctl;
2003758cc3dcSJack F Vogel 	struct ifnet   *ifp = adapter->ifp;
2004758cc3dcSJack F Vogel 	int		mcnt = 0;
2005758cc3dcSJack F Vogel 
2006758cc3dcSJack F Vogel 	reg_rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
2007758cc3dcSJack F Vogel 	reg_rctl &= (~IXGBE_FCTRL_UPE);
2008758cc3dcSJack F Vogel 	if (ifp->if_flags & IFF_ALLMULTI)
2009758cc3dcSJack F Vogel 		mcnt = MAX_NUM_MULTICAST_ADDRESSES;
2010758cc3dcSJack F Vogel 	else {
2011758cc3dcSJack F Vogel 		struct	ifmultiaddr *ifma;
2012758cc3dcSJack F Vogel #if __FreeBSD_version < 800000
2013758cc3dcSJack F Vogel 		IF_ADDR_LOCK(ifp);
2014758cc3dcSJack F Vogel #else
2015758cc3dcSJack F Vogel 		if_maddr_rlock(ifp);
2016758cc3dcSJack F Vogel #endif
2017758cc3dcSJack F Vogel 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2018758cc3dcSJack F Vogel 			if (ifma->ifma_addr->sa_family != AF_LINK)
2019758cc3dcSJack F Vogel 				continue;
2020758cc3dcSJack F Vogel 			if (mcnt == MAX_NUM_MULTICAST_ADDRESSES)
2021758cc3dcSJack F Vogel 				break;
2022758cc3dcSJack F Vogel 			mcnt++;
2023758cc3dcSJack F Vogel 		}
2024758cc3dcSJack F Vogel #if __FreeBSD_version < 800000
2025758cc3dcSJack F Vogel 		IF_ADDR_UNLOCK(ifp);
2026758cc3dcSJack F Vogel #else
2027758cc3dcSJack F Vogel 		if_maddr_runlock(ifp);
2028758cc3dcSJack F Vogel #endif
2029758cc3dcSJack F Vogel 	}
2030758cc3dcSJack F Vogel 	if (mcnt < MAX_NUM_MULTICAST_ADDRESSES)
2031758cc3dcSJack F Vogel 		reg_rctl &= (~IXGBE_FCTRL_MPE);
2032758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl);
2033758cc3dcSJack F Vogel 
2034758cc3dcSJack F Vogel 	if (ifp->if_flags & IFF_PROMISC) {
2035758cc3dcSJack F Vogel 		reg_rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
2036758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl);
2037758cc3dcSJack F Vogel 	} else if (ifp->if_flags & IFF_ALLMULTI) {
2038758cc3dcSJack F Vogel 		reg_rctl |= IXGBE_FCTRL_MPE;
2039758cc3dcSJack F Vogel 		reg_rctl &= ~IXGBE_FCTRL_UPE;
2040758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl);
2041758cc3dcSJack F Vogel 	}
2042758cc3dcSJack F Vogel 	return;
2043758cc3dcSJack F Vogel }
2044758cc3dcSJack F Vogel 
2045758cc3dcSJack F Vogel 
2046758cc3dcSJack F Vogel /*********************************************************************
2047758cc3dcSJack F Vogel  *  Multicast Update
2048758cc3dcSJack F Vogel  *
2049758cc3dcSJack F Vogel  *  This routine is called whenever multicast address list is updated.
2050758cc3dcSJack F Vogel  *
2051758cc3dcSJack F Vogel  **********************************************************************/
2052758cc3dcSJack F Vogel #define IXGBE_RAR_ENTRIES 16
2053758cc3dcSJack F Vogel 
2054758cc3dcSJack F Vogel static void
2055758cc3dcSJack F Vogel ixgbe_set_multi(struct adapter *adapter)
2056758cc3dcSJack F Vogel {
2057758cc3dcSJack F Vogel 	u32			fctrl;
2058758cc3dcSJack F Vogel 	u8			*update_ptr;
2059758cc3dcSJack F Vogel 	struct ifmultiaddr	*ifma;
206048056c88SJack F Vogel 	struct ixgbe_mc_addr	*mta;
2061758cc3dcSJack F Vogel 	int			mcnt = 0;
2062758cc3dcSJack F Vogel 	struct ifnet		*ifp = adapter->ifp;
2063758cc3dcSJack F Vogel 
2064758cc3dcSJack F Vogel 	IOCTL_DEBUGOUT("ixgbe_set_multi: begin");
2065758cc3dcSJack F Vogel 
2066758cc3dcSJack F Vogel 	mta = adapter->mta;
206748056c88SJack F Vogel 	bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES);
2068758cc3dcSJack F Vogel 
2069758cc3dcSJack F Vogel #if __FreeBSD_version < 800000
2070758cc3dcSJack F Vogel 	IF_ADDR_LOCK(ifp);
2071758cc3dcSJack F Vogel #else
2072758cc3dcSJack F Vogel 	if_maddr_rlock(ifp);
2073758cc3dcSJack F Vogel #endif
2074758cc3dcSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2075758cc3dcSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
2076758cc3dcSJack F Vogel 			continue;
2077758cc3dcSJack F Vogel 		if (mcnt == MAX_NUM_MULTICAST_ADDRESSES)
2078758cc3dcSJack F Vogel 			break;
2079758cc3dcSJack F Vogel 		bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr),
208048056c88SJack F Vogel 		    mta[mcnt].addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
208148056c88SJack F Vogel 		mta[mcnt].vmdq = adapter->pool;
2082758cc3dcSJack F Vogel 		mcnt++;
2083758cc3dcSJack F Vogel 	}
2084758cc3dcSJack F Vogel #if __FreeBSD_version < 800000
2085758cc3dcSJack F Vogel 	IF_ADDR_UNLOCK(ifp);
2086758cc3dcSJack F Vogel #else
2087758cc3dcSJack F Vogel 	if_maddr_runlock(ifp);
2088758cc3dcSJack F Vogel #endif
2089758cc3dcSJack F Vogel 
2090758cc3dcSJack F Vogel 	fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
2091758cc3dcSJack F Vogel 	fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
2092758cc3dcSJack F Vogel 	if (ifp->if_flags & IFF_PROMISC)
2093758cc3dcSJack F Vogel 		fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
2094758cc3dcSJack F Vogel 	else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES ||
2095758cc3dcSJack F Vogel 	    ifp->if_flags & IFF_ALLMULTI) {
2096758cc3dcSJack F Vogel 		fctrl |= IXGBE_FCTRL_MPE;
2097758cc3dcSJack F Vogel 		fctrl &= ~IXGBE_FCTRL_UPE;
2098758cc3dcSJack F Vogel 	} else
2099758cc3dcSJack F Vogel 		fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
2100758cc3dcSJack F Vogel 
2101758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl);
2102758cc3dcSJack F Vogel 
2103758cc3dcSJack F Vogel 	if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) {
210448056c88SJack F Vogel 		update_ptr = (u8 *)mta;
2105758cc3dcSJack F Vogel 		ixgbe_update_mc_addr_list(&adapter->hw,
2106758cc3dcSJack F Vogel 		    update_ptr, mcnt, ixgbe_mc_array_itr, TRUE);
2107758cc3dcSJack F Vogel 	}
2108758cc3dcSJack F Vogel 
2109758cc3dcSJack F Vogel 	return;
2110758cc3dcSJack F Vogel }
2111758cc3dcSJack F Vogel 
2112758cc3dcSJack F Vogel /*
2113758cc3dcSJack F Vogel  * This is an iterator function now needed by the multicast
2114758cc3dcSJack F Vogel  * shared code. It simply feeds the shared code routine the
2115758cc3dcSJack F Vogel  * addresses in the array of ixgbe_set_multi() one by one.
2116758cc3dcSJack F Vogel  */
2117758cc3dcSJack F Vogel static u8 *
2118758cc3dcSJack F Vogel ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq)
2119758cc3dcSJack F Vogel {
212048056c88SJack F Vogel 	struct ixgbe_mc_addr *mta;
2121758cc3dcSJack F Vogel 
212248056c88SJack F Vogel 	mta = (struct ixgbe_mc_addr *)*update_ptr;
212348056c88SJack F Vogel 	*vmdq = mta->vmdq;
212448056c88SJack F Vogel 
212548056c88SJack F Vogel 	*update_ptr = (u8*)(mta + 1);;
212648056c88SJack F Vogel 	return (mta->addr);
2127758cc3dcSJack F Vogel }
2128758cc3dcSJack F Vogel 
2129758cc3dcSJack F Vogel 
2130758cc3dcSJack F Vogel /*********************************************************************
2131758cc3dcSJack F Vogel  *  Timer routine
2132758cc3dcSJack F Vogel  *
2133758cc3dcSJack F Vogel  *  This routine checks for link status,updates statistics,
2134758cc3dcSJack F Vogel  *  and runs the watchdog check.
2135758cc3dcSJack F Vogel  *
2136758cc3dcSJack F Vogel  **********************************************************************/
2137758cc3dcSJack F Vogel 
2138758cc3dcSJack F Vogel static void
2139758cc3dcSJack F Vogel ixgbe_local_timer(void *arg)
2140758cc3dcSJack F Vogel {
2141758cc3dcSJack F Vogel 	struct adapter	*adapter = arg;
2142758cc3dcSJack F Vogel 	device_t	dev = adapter->dev;
2143758cc3dcSJack F Vogel 	struct ix_queue *que = adapter->queues;
2144758cc3dcSJack F Vogel 	u64		queues = 0;
2145758cc3dcSJack F Vogel 	int		hung = 0;
2146758cc3dcSJack F Vogel 
2147758cc3dcSJack F Vogel 	mtx_assert(&adapter->core_mtx, MA_OWNED);
2148758cc3dcSJack F Vogel 
2149758cc3dcSJack F Vogel 	/* Check for pluggable optics */
2150758cc3dcSJack F Vogel 	if (adapter->sfp_probe)
2151758cc3dcSJack F Vogel 		if (!ixgbe_sfp_probe(adapter))
2152758cc3dcSJack F Vogel 			goto out; /* Nothing to do */
2153758cc3dcSJack F Vogel 
2154758cc3dcSJack F Vogel 	ixgbe_update_link_status(adapter);
2155758cc3dcSJack F Vogel 	ixgbe_update_stats_counters(adapter);
2156758cc3dcSJack F Vogel 
2157758cc3dcSJack F Vogel 	/*
2158758cc3dcSJack F Vogel 	** Check the TX queues status
2159758cc3dcSJack F Vogel 	**	- mark hung queues so we don't schedule on them
2160758cc3dcSJack F Vogel 	**      - watchdog only if all queues show hung
2161758cc3dcSJack F Vogel 	*/
2162758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, que++) {
2163758cc3dcSJack F Vogel 		/* Keep track of queues with work for soft irq */
2164758cc3dcSJack F Vogel 		if (que->txr->busy)
2165758cc3dcSJack F Vogel 			queues |= ((u64)1 << que->me);
2166758cc3dcSJack F Vogel 		/*
2167758cc3dcSJack F Vogel 		** Each time txeof runs without cleaning, but there
2168758cc3dcSJack F Vogel 		** are uncleaned descriptors it increments busy. If
2169758cc3dcSJack F Vogel 		** we get to the MAX we declare it hung.
2170758cc3dcSJack F Vogel 		*/
2171758cc3dcSJack F Vogel 		if (que->busy == IXGBE_QUEUE_HUNG) {
2172758cc3dcSJack F Vogel 			++hung;
2173758cc3dcSJack F Vogel 			/* Mark the queue as inactive */
2174758cc3dcSJack F Vogel 			adapter->active_queues &= ~((u64)1 << que->me);
2175758cc3dcSJack F Vogel 			continue;
2176758cc3dcSJack F Vogel 		} else {
2177758cc3dcSJack F Vogel 			/* Check if we've come back from hung */
2178758cc3dcSJack F Vogel 			if ((adapter->active_queues & ((u64)1 << que->me)) == 0)
2179758cc3dcSJack F Vogel                                 adapter->active_queues |= ((u64)1 << que->me);
2180758cc3dcSJack F Vogel 		}
2181758cc3dcSJack F Vogel 		if (que->busy >= IXGBE_MAX_TX_BUSY) {
2182758cc3dcSJack F Vogel 			device_printf(dev,"Warning queue %d "
2183758cc3dcSJack F Vogel 			    "appears to be hung!\n", i);
2184758cc3dcSJack F Vogel 			que->txr->busy = IXGBE_QUEUE_HUNG;
2185758cc3dcSJack F Vogel 			++hung;
2186758cc3dcSJack F Vogel 		}
2187758cc3dcSJack F Vogel 
2188758cc3dcSJack F Vogel 	}
2189758cc3dcSJack F Vogel 
2190758cc3dcSJack F Vogel 	/* Only truly watchdog if all queues show hung */
2191758cc3dcSJack F Vogel 	if (hung == adapter->num_queues)
2192758cc3dcSJack F Vogel 		goto watchdog;
2193758cc3dcSJack F Vogel 	else if (queues != 0) { /* Force an IRQ on queues with work */
2194758cc3dcSJack F Vogel 		ixgbe_rearm_queues(adapter, queues);
2195758cc3dcSJack F Vogel 	}
2196758cc3dcSJack F Vogel 
2197758cc3dcSJack F Vogel out:
2198758cc3dcSJack F Vogel 	callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter);
2199758cc3dcSJack F Vogel 	return;
2200758cc3dcSJack F Vogel 
2201758cc3dcSJack F Vogel watchdog:
2202758cc3dcSJack F Vogel 	device_printf(adapter->dev, "Watchdog timeout -- resetting\n");
2203758cc3dcSJack F Vogel 	adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2204758cc3dcSJack F Vogel 	adapter->watchdog_events++;
2205758cc3dcSJack F Vogel 	ixgbe_init_locked(adapter);
2206758cc3dcSJack F Vogel }
2207758cc3dcSJack F Vogel 
220848056c88SJack F Vogel 
2209758cc3dcSJack F Vogel /*
2210758cc3dcSJack F Vogel ** Note: this routine updates the OS on the link state
2211758cc3dcSJack F Vogel **	the real check of the hardware only happens with
2212758cc3dcSJack F Vogel **	a link interrupt.
2213758cc3dcSJack F Vogel */
2214758cc3dcSJack F Vogel static void
2215758cc3dcSJack F Vogel ixgbe_update_link_status(struct adapter *adapter)
2216758cc3dcSJack F Vogel {
2217758cc3dcSJack F Vogel 	struct ifnet	*ifp = adapter->ifp;
2218758cc3dcSJack F Vogel 	device_t dev = adapter->dev;
2219758cc3dcSJack F Vogel 
2220758cc3dcSJack F Vogel 	if (adapter->link_up){
2221758cc3dcSJack F Vogel 		if (adapter->link_active == FALSE) {
2222758cc3dcSJack F Vogel 			if (bootverbose)
2223758cc3dcSJack F Vogel 				device_printf(dev,"Link is up %d Gbps %s \n",
2224758cc3dcSJack F Vogel 				    ((adapter->link_speed == 128)? 10:1),
2225758cc3dcSJack F Vogel 				    "Full Duplex");
2226758cc3dcSJack F Vogel 			adapter->link_active = TRUE;
2227758cc3dcSJack F Vogel 			/* Update any Flow Control changes */
2228758cc3dcSJack F Vogel 			ixgbe_fc_enable(&adapter->hw);
22296f37f232SEric Joyner 			/* Update DMA coalescing config */
22306f37f232SEric Joyner 			ixgbe_config_dmac(adapter);
2231758cc3dcSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_UP);
223248056c88SJack F Vogel #ifdef PCI_IOV
223348056c88SJack F Vogel 			ixgbe_ping_all_vfs(adapter);
223448056c88SJack F Vogel #endif
2235758cc3dcSJack F Vogel 		}
2236758cc3dcSJack F Vogel 	} else { /* Link down */
2237758cc3dcSJack F Vogel 		if (adapter->link_active == TRUE) {
2238758cc3dcSJack F Vogel 			if (bootverbose)
2239758cc3dcSJack F Vogel 				device_printf(dev,"Link is Down\n");
2240758cc3dcSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_DOWN);
2241758cc3dcSJack F Vogel 			adapter->link_active = FALSE;
224248056c88SJack F Vogel #ifdef PCI_IOV
224348056c88SJack F Vogel 			ixgbe_ping_all_vfs(adapter);
224448056c88SJack F Vogel #endif
2245758cc3dcSJack F Vogel 		}
2246758cc3dcSJack F Vogel 	}
2247758cc3dcSJack F Vogel 
2248758cc3dcSJack F Vogel 	return;
2249758cc3dcSJack F Vogel }
2250758cc3dcSJack F Vogel 
2251758cc3dcSJack F Vogel 
2252758cc3dcSJack F Vogel /*********************************************************************
2253758cc3dcSJack F Vogel  *
2254758cc3dcSJack F Vogel  *  This routine disables all traffic on the adapter by issuing a
2255758cc3dcSJack F Vogel  *  global reset on the MAC and deallocates TX/RX buffers.
2256758cc3dcSJack F Vogel  *
2257758cc3dcSJack F Vogel  **********************************************************************/
2258758cc3dcSJack F Vogel 
2259758cc3dcSJack F Vogel static void
2260758cc3dcSJack F Vogel ixgbe_stop(void *arg)
2261758cc3dcSJack F Vogel {
2262758cc3dcSJack F Vogel 	struct ifnet   *ifp;
2263758cc3dcSJack F Vogel 	struct adapter *adapter = arg;
2264758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
2265758cc3dcSJack F Vogel 	ifp = adapter->ifp;
2266758cc3dcSJack F Vogel 
2267758cc3dcSJack F Vogel 	mtx_assert(&adapter->core_mtx, MA_OWNED);
2268758cc3dcSJack F Vogel 
2269758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_stop: begin\n");
2270758cc3dcSJack F Vogel 	ixgbe_disable_intr(adapter);
2271758cc3dcSJack F Vogel 	callout_stop(&adapter->timer);
2272758cc3dcSJack F Vogel 
2273758cc3dcSJack F Vogel 	/* Let the stack know...*/
2274758cc3dcSJack F Vogel 	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2275758cc3dcSJack F Vogel 
2276758cc3dcSJack F Vogel 	ixgbe_reset_hw(hw);
2277758cc3dcSJack F Vogel 	hw->adapter_stopped = FALSE;
2278758cc3dcSJack F Vogel 	ixgbe_stop_adapter(hw);
2279758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82599EB)
2280758cc3dcSJack F Vogel 		ixgbe_stop_mac_link_on_d3_82599(hw);
2281758cc3dcSJack F Vogel 	/* Turn off the laser - noop with no optics */
2282758cc3dcSJack F Vogel 	ixgbe_disable_tx_laser(hw);
2283758cc3dcSJack F Vogel 
2284758cc3dcSJack F Vogel 	/* Update the stack */
2285758cc3dcSJack F Vogel 	adapter->link_up = FALSE;
2286758cc3dcSJack F Vogel        	ixgbe_update_link_status(adapter);
2287758cc3dcSJack F Vogel 
2288758cc3dcSJack F Vogel 	/* reprogram the RAR[0] in case user changed it. */
2289758cc3dcSJack F Vogel 	ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV);
2290758cc3dcSJack F Vogel 
2291758cc3dcSJack F Vogel 	return;
2292758cc3dcSJack F Vogel }
2293758cc3dcSJack F Vogel 
2294758cc3dcSJack F Vogel 
2295758cc3dcSJack F Vogel /*********************************************************************
2296758cc3dcSJack F Vogel  *
2297758cc3dcSJack F Vogel  *  Determine hardware revision.
2298758cc3dcSJack F Vogel  *
2299758cc3dcSJack F Vogel  **********************************************************************/
2300758cc3dcSJack F Vogel static void
2301758cc3dcSJack F Vogel ixgbe_identify_hardware(struct adapter *adapter)
2302758cc3dcSJack F Vogel {
2303758cc3dcSJack F Vogel 	device_t        dev = adapter->dev;
2304758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
2305758cc3dcSJack F Vogel 
2306758cc3dcSJack F Vogel 	/* Save off the information about this board */
2307758cc3dcSJack F Vogel 	hw->vendor_id = pci_get_vendor(dev);
2308758cc3dcSJack F Vogel 	hw->device_id = pci_get_device(dev);
2309758cc3dcSJack F Vogel 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
2310758cc3dcSJack F Vogel 	hw->subsystem_vendor_id =
2311758cc3dcSJack F Vogel 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
2312758cc3dcSJack F Vogel 	hw->subsystem_device_id =
2313758cc3dcSJack F Vogel 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
2314758cc3dcSJack F Vogel 
2315758cc3dcSJack F Vogel 	/*
2316758cc3dcSJack F Vogel 	** Make sure BUSMASTER is set
2317758cc3dcSJack F Vogel 	*/
2318758cc3dcSJack F Vogel 	pci_enable_busmaster(dev);
2319758cc3dcSJack F Vogel 
2320758cc3dcSJack F Vogel 	/* We need this here to set the num_segs below */
2321758cc3dcSJack F Vogel 	ixgbe_set_mac_type(hw);
2322758cc3dcSJack F Vogel 
23236f37f232SEric Joyner 	/* Pick up the 82599 settings */
2324758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
2325758cc3dcSJack F Vogel 		hw->phy.smart_speed = ixgbe_smart_speed;
2326758cc3dcSJack F Vogel 		adapter->num_segs = IXGBE_82599_SCATTER;
2327758cc3dcSJack F Vogel 	} else
2328758cc3dcSJack F Vogel 		adapter->num_segs = IXGBE_82598_SCATTER;
2329758cc3dcSJack F Vogel 
2330758cc3dcSJack F Vogel 	return;
2331758cc3dcSJack F Vogel }
2332758cc3dcSJack F Vogel 
2333758cc3dcSJack F Vogel /*********************************************************************
2334758cc3dcSJack F Vogel  *
2335758cc3dcSJack F Vogel  *  Determine optic type
2336758cc3dcSJack F Vogel  *
2337758cc3dcSJack F Vogel  **********************************************************************/
2338758cc3dcSJack F Vogel static void
2339758cc3dcSJack F Vogel ixgbe_setup_optics(struct adapter *adapter)
2340758cc3dcSJack F Vogel {
2341758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
2342758cc3dcSJack F Vogel 	int		layer;
2343758cc3dcSJack F Vogel 
234448056c88SJack F Vogel 	layer = adapter->phy_layer = ixgbe_get_supported_physical_layer(hw);
2345758cc3dcSJack F Vogel 
2346758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) {
2347758cc3dcSJack F Vogel 		adapter->optics = IFM_10G_T;
2348758cc3dcSJack F Vogel 		return;
2349758cc3dcSJack F Vogel 	}
2350758cc3dcSJack F Vogel 
2351758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) {
2352758cc3dcSJack F Vogel 		adapter->optics = IFM_1000_T;
2353758cc3dcSJack F Vogel 		return;
2354758cc3dcSJack F Vogel 	}
2355758cc3dcSJack F Vogel 
2356758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) {
2357758cc3dcSJack F Vogel 		adapter->optics = IFM_1000_SX;
2358758cc3dcSJack F Vogel 		return;
2359758cc3dcSJack F Vogel 	}
2360758cc3dcSJack F Vogel 
2361758cc3dcSJack F Vogel 	if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_LR |
2362758cc3dcSJack F Vogel 	    IXGBE_PHYSICAL_LAYER_10GBASE_LRM)) {
2363758cc3dcSJack F Vogel 		adapter->optics = IFM_10G_LR;
2364758cc3dcSJack F Vogel 		return;
2365758cc3dcSJack F Vogel 	}
2366758cc3dcSJack F Vogel 
2367758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) {
2368758cc3dcSJack F Vogel 		adapter->optics = IFM_10G_SR;
2369758cc3dcSJack F Vogel 		return;
2370758cc3dcSJack F Vogel 	}
2371758cc3dcSJack F Vogel 
2372758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU) {
2373758cc3dcSJack F Vogel 		adapter->optics = IFM_10G_TWINAX;
2374758cc3dcSJack F Vogel 		return;
2375758cc3dcSJack F Vogel 	}
2376758cc3dcSJack F Vogel 
2377758cc3dcSJack F Vogel 	if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 |
2378758cc3dcSJack F Vogel 	    IXGBE_PHYSICAL_LAYER_10GBASE_CX4)) {
2379758cc3dcSJack F Vogel 		adapter->optics = IFM_10G_CX4;
2380758cc3dcSJack F Vogel 		return;
2381758cc3dcSJack F Vogel 	}
2382758cc3dcSJack F Vogel 
2383758cc3dcSJack F Vogel 	/* If we get here just set the default */
2384758cc3dcSJack F Vogel 	adapter->optics = IFM_ETHER | IFM_AUTO;
2385758cc3dcSJack F Vogel 	return;
2386758cc3dcSJack F Vogel }
2387758cc3dcSJack F Vogel 
2388758cc3dcSJack F Vogel /*********************************************************************
2389758cc3dcSJack F Vogel  *
2390758cc3dcSJack F Vogel  *  Setup the Legacy or MSI Interrupt handler
2391758cc3dcSJack F Vogel  *
2392758cc3dcSJack F Vogel  **********************************************************************/
2393758cc3dcSJack F Vogel static int
2394758cc3dcSJack F Vogel ixgbe_allocate_legacy(struct adapter *adapter)
2395758cc3dcSJack F Vogel {
2396758cc3dcSJack F Vogel 	device_t	dev = adapter->dev;
2397758cc3dcSJack F Vogel 	struct		ix_queue *que = adapter->queues;
2398758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
2399758cc3dcSJack F Vogel 	struct tx_ring		*txr = adapter->tx_rings;
2400758cc3dcSJack F Vogel #endif
2401758cc3dcSJack F Vogel 	int		error, rid = 0;
2402758cc3dcSJack F Vogel 
2403758cc3dcSJack F Vogel 	/* MSI RID at 1 */
2404758cc3dcSJack F Vogel 	if (adapter->msix == 1)
2405758cc3dcSJack F Vogel 		rid = 1;
2406758cc3dcSJack F Vogel 
2407758cc3dcSJack F Vogel 	/* We allocate a single interrupt resource */
2408758cc3dcSJack F Vogel 	adapter->res = bus_alloc_resource_any(dev,
2409758cc3dcSJack F Vogel             SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
2410758cc3dcSJack F Vogel 	if (adapter->res == NULL) {
2411758cc3dcSJack F Vogel 		device_printf(dev, "Unable to allocate bus resource: "
2412758cc3dcSJack F Vogel 		    "interrupt\n");
2413758cc3dcSJack F Vogel 		return (ENXIO);
2414758cc3dcSJack F Vogel 	}
2415758cc3dcSJack F Vogel 
2416758cc3dcSJack F Vogel 	/*
2417758cc3dcSJack F Vogel 	 * Try allocating a fast interrupt and the associated deferred
2418758cc3dcSJack F Vogel 	 * processing contexts.
2419758cc3dcSJack F Vogel 	 */
2420758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
2421758cc3dcSJack F Vogel 	TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr);
2422758cc3dcSJack F Vogel #endif
2423758cc3dcSJack F Vogel 	TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que);
2424758cc3dcSJack F Vogel 	que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT,
2425758cc3dcSJack F Vogel             taskqueue_thread_enqueue, &que->tq);
2426758cc3dcSJack F Vogel 	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s ixq",
2427758cc3dcSJack F Vogel             device_get_nameunit(adapter->dev));
2428758cc3dcSJack F Vogel 
2429758cc3dcSJack F Vogel 	/* Tasklets for Link, SFP and Multispeed Fiber */
2430758cc3dcSJack F Vogel 	TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter);
2431758cc3dcSJack F Vogel 	TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter);
2432758cc3dcSJack F Vogel 	TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter);
24336f37f232SEric Joyner 	TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter);
2434758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
2435758cc3dcSJack F Vogel 	TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter);
2436758cc3dcSJack F Vogel #endif
2437758cc3dcSJack F Vogel 	adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT,
2438758cc3dcSJack F Vogel 	    taskqueue_thread_enqueue, &adapter->tq);
2439758cc3dcSJack F Vogel 	taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq",
2440758cc3dcSJack F Vogel 	    device_get_nameunit(adapter->dev));
2441758cc3dcSJack F Vogel 
2442758cc3dcSJack F Vogel 	if ((error = bus_setup_intr(dev, adapter->res,
2443758cc3dcSJack F Vogel             INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq,
2444758cc3dcSJack F Vogel             que, &adapter->tag)) != 0) {
2445758cc3dcSJack F Vogel 		device_printf(dev, "Failed to register fast interrupt "
2446758cc3dcSJack F Vogel 		    "handler: %d\n", error);
2447758cc3dcSJack F Vogel 		taskqueue_free(que->tq);
2448758cc3dcSJack F Vogel 		taskqueue_free(adapter->tq);
2449758cc3dcSJack F Vogel 		que->tq = NULL;
2450758cc3dcSJack F Vogel 		adapter->tq = NULL;
2451758cc3dcSJack F Vogel 		return (error);
2452758cc3dcSJack F Vogel 	}
2453758cc3dcSJack F Vogel 	/* For simplicity in the handlers */
2454758cc3dcSJack F Vogel 	adapter->active_queues = IXGBE_EIMS_ENABLE_MASK;
2455758cc3dcSJack F Vogel 
2456758cc3dcSJack F Vogel 	return (0);
2457758cc3dcSJack F Vogel }
2458758cc3dcSJack F Vogel 
2459758cc3dcSJack F Vogel 
2460758cc3dcSJack F Vogel /*********************************************************************
2461758cc3dcSJack F Vogel  *
2462758cc3dcSJack F Vogel  *  Setup MSIX Interrupt resources and handlers
2463758cc3dcSJack F Vogel  *
2464758cc3dcSJack F Vogel  **********************************************************************/
2465758cc3dcSJack F Vogel static int
2466758cc3dcSJack F Vogel ixgbe_allocate_msix(struct adapter *adapter)
2467758cc3dcSJack F Vogel {
2468758cc3dcSJack F Vogel 	device_t        dev = adapter->dev;
2469758cc3dcSJack F Vogel 	struct 		ix_queue *que = adapter->queues;
2470758cc3dcSJack F Vogel 	struct  	tx_ring *txr = adapter->tx_rings;
2471758cc3dcSJack F Vogel 	int 		error, rid, vector = 0;
2472758cc3dcSJack F Vogel 	int		cpu_id = 0;
2473a1edda90SAdrian Chadd #ifdef	RSS
2474a1edda90SAdrian Chadd 	cpuset_t	cpu_mask;
2475a1edda90SAdrian Chadd #endif
2476758cc3dcSJack F Vogel 
2477758cc3dcSJack F Vogel #ifdef	RSS
2478758cc3dcSJack F Vogel 	/*
2479758cc3dcSJack F Vogel 	 * If we're doing RSS, the number of queues needs to
2480758cc3dcSJack F Vogel 	 * match the number of RSS buckets that are configured.
2481758cc3dcSJack F Vogel 	 *
2482758cc3dcSJack F Vogel 	 * + If there's more queues than RSS buckets, we'll end
2483758cc3dcSJack F Vogel 	 *   up with queues that get no traffic.
2484758cc3dcSJack F Vogel 	 *
2485758cc3dcSJack F Vogel 	 * + If there's more RSS buckets than queues, we'll end
2486758cc3dcSJack F Vogel 	 *   up having multiple RSS buckets map to the same queue,
2487758cc3dcSJack F Vogel 	 *   so there'll be some contention.
2488758cc3dcSJack F Vogel 	 */
2489758cc3dcSJack F Vogel 	if (adapter->num_queues != rss_getnumbuckets()) {
2490758cc3dcSJack F Vogel 		device_printf(dev,
2491758cc3dcSJack F Vogel 		    "%s: number of queues (%d) != number of RSS buckets (%d)"
2492758cc3dcSJack F Vogel 		    "; performance will be impacted.\n",
2493758cc3dcSJack F Vogel 		    __func__,
2494758cc3dcSJack F Vogel 		    adapter->num_queues,
2495758cc3dcSJack F Vogel 		    rss_getnumbuckets());
2496758cc3dcSJack F Vogel 	}
2497758cc3dcSJack F Vogel #endif
2498758cc3dcSJack F Vogel 
2499758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) {
2500758cc3dcSJack F Vogel 		rid = vector + 1;
2501758cc3dcSJack F Vogel 		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
2502758cc3dcSJack F Vogel 		    RF_SHAREABLE | RF_ACTIVE);
2503758cc3dcSJack F Vogel 		if (que->res == NULL) {
2504758cc3dcSJack F Vogel 			device_printf(dev,"Unable to allocate"
2505758cc3dcSJack F Vogel 		    	    " bus resource: que interrupt [%d]\n", vector);
2506758cc3dcSJack F Vogel 			return (ENXIO);
2507758cc3dcSJack F Vogel 		}
2508758cc3dcSJack F Vogel 		/* Set the handler function */
2509758cc3dcSJack F Vogel 		error = bus_setup_intr(dev, que->res,
2510758cc3dcSJack F Vogel 		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
2511758cc3dcSJack F Vogel 		    ixgbe_msix_que, que, &que->tag);
2512758cc3dcSJack F Vogel 		if (error) {
2513758cc3dcSJack F Vogel 			que->res = NULL;
2514758cc3dcSJack F Vogel 			device_printf(dev, "Failed to register QUE handler");
2515758cc3dcSJack F Vogel 			return (error);
2516758cc3dcSJack F Vogel 		}
2517758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504
2518a9ca1c79SSean Bruno 		bus_describe_intr(dev, que->res, que->tag, "q%d", i);
2519758cc3dcSJack F Vogel #endif
2520758cc3dcSJack F Vogel 		que->msix = vector;
2521758cc3dcSJack F Vogel 		adapter->active_queues |= (u64)(1 << que->msix);
2522758cc3dcSJack F Vogel #ifdef	RSS
2523758cc3dcSJack F Vogel 		/*
2524758cc3dcSJack F Vogel 		 * The queue ID is used as the RSS layer bucket ID.
2525758cc3dcSJack F Vogel 		 * We look up the queue ID -> RSS CPU ID and select
2526758cc3dcSJack F Vogel 		 * that.
2527758cc3dcSJack F Vogel 		 */
2528758cc3dcSJack F Vogel 		cpu_id = rss_getcpu(i % rss_getnumbuckets());
2529758cc3dcSJack F Vogel #else
2530758cc3dcSJack F Vogel 		/*
2531758cc3dcSJack F Vogel 		 * Bind the msix vector, and thus the
2532758cc3dcSJack F Vogel 		 * rings to the corresponding cpu.
2533758cc3dcSJack F Vogel 		 *
2534758cc3dcSJack F Vogel 		 * This just happens to match the default RSS round-robin
2535758cc3dcSJack F Vogel 		 * bucket -> queue -> CPU allocation.
2536758cc3dcSJack F Vogel 		 */
2537758cc3dcSJack F Vogel 		if (adapter->num_queues > 1)
2538758cc3dcSJack F Vogel 			cpu_id = i;
2539758cc3dcSJack F Vogel #endif
2540758cc3dcSJack F Vogel 		if (adapter->num_queues > 1)
2541758cc3dcSJack F Vogel 			bus_bind_intr(dev, que->res, cpu_id);
254248056c88SJack F Vogel #ifdef IXGBE_DEBUG
2543758cc3dcSJack F Vogel #ifdef	RSS
2544758cc3dcSJack F Vogel 		device_printf(dev,
2545758cc3dcSJack F Vogel 		    "Bound RSS bucket %d to CPU %d\n",
2546758cc3dcSJack F Vogel 		    i, cpu_id);
2547758cc3dcSJack F Vogel #else
2548758cc3dcSJack F Vogel 		device_printf(dev,
2549758cc3dcSJack F Vogel 		    "Bound queue %d to cpu %d\n",
2550758cc3dcSJack F Vogel 		    i, cpu_id);
2551758cc3dcSJack F Vogel #endif
255248056c88SJack F Vogel #endif /* IXGBE_DEBUG */
255348056c88SJack F Vogel 
255448056c88SJack F Vogel 
2555758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
2556758cc3dcSJack F Vogel 		TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr);
2557758cc3dcSJack F Vogel #endif
2558758cc3dcSJack F Vogel 		TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que);
2559758cc3dcSJack F Vogel 		que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT,
2560758cc3dcSJack F Vogel 		    taskqueue_thread_enqueue, &que->tq);
2561758cc3dcSJack F Vogel #ifdef	RSS
2562a1edda90SAdrian Chadd 		CPU_SETOF(cpu_id, &cpu_mask);
2563a1edda90SAdrian Chadd 		taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET,
2564a1edda90SAdrian Chadd 		    &cpu_mask,
2565758cc3dcSJack F Vogel 		    "%s (bucket %d)",
2566758cc3dcSJack F Vogel 		    device_get_nameunit(adapter->dev),
2567758cc3dcSJack F Vogel 		    cpu_id);
2568758cc3dcSJack F Vogel #else
2569a9ca1c79SSean Bruno 		taskqueue_start_threads(&que->tq, 1, PI_NET, "%s:q%d",
2570a9ca1c79SSean Bruno 		    device_get_nameunit(adapter->dev), i);
2571758cc3dcSJack F Vogel #endif
2572758cc3dcSJack F Vogel 	}
2573758cc3dcSJack F Vogel 
2574758cc3dcSJack F Vogel 	/* and Link */
2575758cc3dcSJack F Vogel 	rid = vector + 1;
2576758cc3dcSJack F Vogel 	adapter->res = bus_alloc_resource_any(dev,
2577758cc3dcSJack F Vogel     	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
2578758cc3dcSJack F Vogel 	if (!adapter->res) {
2579758cc3dcSJack F Vogel 		device_printf(dev,"Unable to allocate"
2580758cc3dcSJack F Vogel     	    " bus resource: Link interrupt [%d]\n", rid);
2581758cc3dcSJack F Vogel 		return (ENXIO);
2582758cc3dcSJack F Vogel 	}
2583758cc3dcSJack F Vogel 	/* Set the link handler function */
2584758cc3dcSJack F Vogel 	error = bus_setup_intr(dev, adapter->res,
2585758cc3dcSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
2586758cc3dcSJack F Vogel 	    ixgbe_msix_link, adapter, &adapter->tag);
2587758cc3dcSJack F Vogel 	if (error) {
2588758cc3dcSJack F Vogel 		adapter->res = NULL;
2589758cc3dcSJack F Vogel 		device_printf(dev, "Failed to register LINK handler");
2590758cc3dcSJack F Vogel 		return (error);
2591758cc3dcSJack F Vogel 	}
2592758cc3dcSJack F Vogel #if __FreeBSD_version >= 800504
2593758cc3dcSJack F Vogel 	bus_describe_intr(dev, adapter->res, adapter->tag, "link");
2594758cc3dcSJack F Vogel #endif
2595758cc3dcSJack F Vogel 	adapter->vector = vector;
2596758cc3dcSJack F Vogel 	/* Tasklets for Link, SFP and Multispeed Fiber */
2597758cc3dcSJack F Vogel 	TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter);
2598758cc3dcSJack F Vogel 	TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter);
2599758cc3dcSJack F Vogel 	TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter);
260048056c88SJack F Vogel #ifdef PCI_IOV
260148056c88SJack F Vogel 	TASK_INIT(&adapter->mbx_task, 0, ixgbe_handle_mbx, adapter);
260248056c88SJack F Vogel #endif
26036f37f232SEric Joyner 	TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter);
2604758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
2605758cc3dcSJack F Vogel 	TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter);
2606758cc3dcSJack F Vogel #endif
2607758cc3dcSJack F Vogel 	adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT,
2608758cc3dcSJack F Vogel 	    taskqueue_thread_enqueue, &adapter->tq);
2609758cc3dcSJack F Vogel 	taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq",
2610758cc3dcSJack F Vogel 	    device_get_nameunit(adapter->dev));
2611758cc3dcSJack F Vogel 
2612758cc3dcSJack F Vogel 	return (0);
2613758cc3dcSJack F Vogel }
2614758cc3dcSJack F Vogel 
2615758cc3dcSJack F Vogel /*
2616758cc3dcSJack F Vogel  * Setup Either MSI/X or MSI
2617758cc3dcSJack F Vogel  */
2618758cc3dcSJack F Vogel static int
2619758cc3dcSJack F Vogel ixgbe_setup_msix(struct adapter *adapter)
2620758cc3dcSJack F Vogel {
2621758cc3dcSJack F Vogel 	device_t dev = adapter->dev;
2622758cc3dcSJack F Vogel 	int rid, want, queues, msgs;
2623758cc3dcSJack F Vogel 
2624758cc3dcSJack F Vogel 	/* Override by tuneable */
2625758cc3dcSJack F Vogel 	if (ixgbe_enable_msix == 0)
2626758cc3dcSJack F Vogel 		goto msi;
2627758cc3dcSJack F Vogel 
2628758cc3dcSJack F Vogel 	/* First try MSI/X */
2629758cc3dcSJack F Vogel 	msgs = pci_msix_count(dev);
2630758cc3dcSJack F Vogel 	if (msgs == 0)
2631758cc3dcSJack F Vogel 		goto msi;
2632758cc3dcSJack F Vogel 	rid = PCIR_BAR(MSIX_82598_BAR);
2633758cc3dcSJack F Vogel 	adapter->msix_mem = bus_alloc_resource_any(dev,
2634758cc3dcSJack F Vogel 	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
2635758cc3dcSJack F Vogel        	if (adapter->msix_mem == NULL) {
2636758cc3dcSJack F Vogel 		rid += 4;	/* 82599 maps in higher BAR */
2637758cc3dcSJack F Vogel 		adapter->msix_mem = bus_alloc_resource_any(dev,
2638758cc3dcSJack F Vogel 		    SYS_RES_MEMORY, &rid, RF_ACTIVE);
2639758cc3dcSJack F Vogel 	}
2640758cc3dcSJack F Vogel        	if (adapter->msix_mem == NULL) {
2641758cc3dcSJack F Vogel 		/* May not be enabled */
2642758cc3dcSJack F Vogel 		device_printf(adapter->dev,
2643758cc3dcSJack F Vogel 		    "Unable to map MSIX table \n");
2644758cc3dcSJack F Vogel 		goto msi;
2645758cc3dcSJack F Vogel 	}
2646758cc3dcSJack F Vogel 
2647758cc3dcSJack F Vogel 	/* Figure out a reasonable auto config value */
2648758cc3dcSJack F Vogel 	queues = (mp_ncpus > (msgs - 1)) ? (msgs - 1) : mp_ncpus;
2649758cc3dcSJack F Vogel 
2650758cc3dcSJack F Vogel #ifdef	RSS
2651758cc3dcSJack F Vogel 	/* If we're doing RSS, clamp at the number of RSS buckets */
2652758cc3dcSJack F Vogel 	if (queues > rss_getnumbuckets())
2653758cc3dcSJack F Vogel 		queues = rss_getnumbuckets();
2654758cc3dcSJack F Vogel #endif
2655758cc3dcSJack F Vogel 
2656758cc3dcSJack F Vogel 	if (ixgbe_num_queues != 0)
2657758cc3dcSJack F Vogel 		queues = ixgbe_num_queues;
2658a9ca1c79SSean Bruno 	/* Set max queues to 8 when autoconfiguring */
2659a9ca1c79SSean Bruno 	else if ((ixgbe_num_queues == 0) && (queues > 8))
2660a9ca1c79SSean Bruno 		queues = 8;
2661758cc3dcSJack F Vogel 
2662758cc3dcSJack F Vogel 	/* reflect correct sysctl value */
2663758cc3dcSJack F Vogel 	ixgbe_num_queues = queues;
2664758cc3dcSJack F Vogel 
2665758cc3dcSJack F Vogel 	/*
2666758cc3dcSJack F Vogel 	** Want one vector (RX/TX pair) per queue
2667758cc3dcSJack F Vogel 	** plus an additional for Link.
2668758cc3dcSJack F Vogel 	*/
2669758cc3dcSJack F Vogel 	want = queues + 1;
2670758cc3dcSJack F Vogel 	if (msgs >= want)
2671758cc3dcSJack F Vogel 		msgs = want;
2672758cc3dcSJack F Vogel 	else {
2673758cc3dcSJack F Vogel                	device_printf(adapter->dev,
2674758cc3dcSJack F Vogel 		    "MSIX Configuration Problem, "
2675758cc3dcSJack F Vogel 		    "%d vectors but %d queues wanted!\n",
2676758cc3dcSJack F Vogel 		    msgs, want);
2677758cc3dcSJack F Vogel 		goto msi;
2678758cc3dcSJack F Vogel 	}
2679758cc3dcSJack F Vogel 	if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) {
2680758cc3dcSJack F Vogel                	device_printf(adapter->dev,
2681758cc3dcSJack F Vogel 		    "Using MSIX interrupts with %d vectors\n", msgs);
2682758cc3dcSJack F Vogel 		adapter->num_queues = queues;
2683758cc3dcSJack F Vogel 		return (msgs);
2684758cc3dcSJack F Vogel 	}
2685758cc3dcSJack F Vogel 	/*
2686758cc3dcSJack F Vogel 	** If MSIX alloc failed or provided us with
2687758cc3dcSJack F Vogel 	** less than needed, free and fall through to MSI
2688758cc3dcSJack F Vogel 	*/
2689758cc3dcSJack F Vogel 	pci_release_msi(dev);
2690758cc3dcSJack F Vogel 
2691758cc3dcSJack F Vogel msi:
2692758cc3dcSJack F Vogel        	if (adapter->msix_mem != NULL) {
2693758cc3dcSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
2694758cc3dcSJack F Vogel 		    rid, adapter->msix_mem);
2695758cc3dcSJack F Vogel 		adapter->msix_mem = NULL;
2696758cc3dcSJack F Vogel 	}
2697758cc3dcSJack F Vogel 	msgs = 1;
2698758cc3dcSJack F Vogel 	if (pci_alloc_msi(dev, &msgs) == 0) {
2699758cc3dcSJack F Vogel 		device_printf(adapter->dev, "Using an MSI interrupt\n");
2700758cc3dcSJack F Vogel 		return (msgs);
2701758cc3dcSJack F Vogel 	}
2702758cc3dcSJack F Vogel 	device_printf(adapter->dev, "Using a Legacy interrupt\n");
2703758cc3dcSJack F Vogel 	return (0);
2704758cc3dcSJack F Vogel }
2705758cc3dcSJack F Vogel 
2706758cc3dcSJack F Vogel 
2707758cc3dcSJack F Vogel static int
2708758cc3dcSJack F Vogel ixgbe_allocate_pci_resources(struct adapter *adapter)
2709758cc3dcSJack F Vogel {
2710758cc3dcSJack F Vogel 	int             rid;
2711758cc3dcSJack F Vogel 	device_t        dev = adapter->dev;
2712758cc3dcSJack F Vogel 
2713758cc3dcSJack F Vogel 	rid = PCIR_BAR(0);
2714758cc3dcSJack F Vogel 	adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
2715758cc3dcSJack F Vogel 	    &rid, RF_ACTIVE);
2716758cc3dcSJack F Vogel 
2717758cc3dcSJack F Vogel 	if (!(adapter->pci_mem)) {
2718758cc3dcSJack F Vogel 		device_printf(dev, "Unable to allocate bus resource: memory\n");
2719758cc3dcSJack F Vogel 		return (ENXIO);
2720758cc3dcSJack F Vogel 	}
2721758cc3dcSJack F Vogel 
2722a9ca1c79SSean Bruno 	/* Save bus_space values for READ/WRITE_REG macros */
2723758cc3dcSJack F Vogel 	adapter->osdep.mem_bus_space_tag =
2724758cc3dcSJack F Vogel 		rman_get_bustag(adapter->pci_mem);
2725758cc3dcSJack F Vogel 	adapter->osdep.mem_bus_space_handle =
2726758cc3dcSJack F Vogel 		rman_get_bushandle(adapter->pci_mem);
2727a9ca1c79SSean Bruno 	/* Set hw values for shared code */
2728758cc3dcSJack F Vogel 	adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle;
2729a9ca1c79SSean Bruno 	adapter->hw.back = adapter;
2730758cc3dcSJack F Vogel 
2731a9ca1c79SSean Bruno 	/* Default to 1 queue if MSI-X setup fails */
2732758cc3dcSJack F Vogel 	adapter->num_queues = 1;
2733758cc3dcSJack F Vogel 
2734758cc3dcSJack F Vogel 	/*
2735a9ca1c79SSean Bruno 	** Now setup MSI or MSI-X, should
2736758cc3dcSJack F Vogel 	** return us the number of supported
2737758cc3dcSJack F Vogel 	** vectors. (Will be 1 for MSI)
2738758cc3dcSJack F Vogel 	*/
2739758cc3dcSJack F Vogel 	adapter->msix = ixgbe_setup_msix(adapter);
2740758cc3dcSJack F Vogel 	return (0);
2741758cc3dcSJack F Vogel }
2742758cc3dcSJack F Vogel 
2743758cc3dcSJack F Vogel static void
2744758cc3dcSJack F Vogel ixgbe_free_pci_resources(struct adapter * adapter)
2745758cc3dcSJack F Vogel {
2746758cc3dcSJack F Vogel 	struct 		ix_queue *que = adapter->queues;
2747758cc3dcSJack F Vogel 	device_t	dev = adapter->dev;
2748758cc3dcSJack F Vogel 	int		rid, memrid;
2749758cc3dcSJack F Vogel 
2750758cc3dcSJack F Vogel 	if (adapter->hw.mac.type == ixgbe_mac_82598EB)
2751758cc3dcSJack F Vogel 		memrid = PCIR_BAR(MSIX_82598_BAR);
2752758cc3dcSJack F Vogel 	else
2753758cc3dcSJack F Vogel 		memrid = PCIR_BAR(MSIX_82599_BAR);
2754758cc3dcSJack F Vogel 
2755758cc3dcSJack F Vogel 	/*
2756758cc3dcSJack F Vogel 	** There is a slight possibility of a failure mode
2757758cc3dcSJack F Vogel 	** in attach that will result in entering this function
2758758cc3dcSJack F Vogel 	** before interrupt resources have been initialized, and
2759758cc3dcSJack F Vogel 	** in that case we do not want to execute the loops below
2760758cc3dcSJack F Vogel 	** We can detect this reliably by the state of the adapter
2761758cc3dcSJack F Vogel 	** res pointer.
2762758cc3dcSJack F Vogel 	*/
2763758cc3dcSJack F Vogel 	if (adapter->res == NULL)
2764758cc3dcSJack F Vogel 		goto mem;
2765758cc3dcSJack F Vogel 
2766758cc3dcSJack F Vogel 	/*
2767758cc3dcSJack F Vogel 	**  Release all msix queue resources:
2768758cc3dcSJack F Vogel 	*/
2769758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, que++) {
2770758cc3dcSJack F Vogel 		rid = que->msix + 1;
2771758cc3dcSJack F Vogel 		if (que->tag != NULL) {
2772758cc3dcSJack F Vogel 			bus_teardown_intr(dev, que->res, que->tag);
2773758cc3dcSJack F Vogel 			que->tag = NULL;
2774758cc3dcSJack F Vogel 		}
2775758cc3dcSJack F Vogel 		if (que->res != NULL)
2776758cc3dcSJack F Vogel 			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
2777758cc3dcSJack F Vogel 	}
2778758cc3dcSJack F Vogel 
2779758cc3dcSJack F Vogel 
2780758cc3dcSJack F Vogel 	/* Clean the Legacy or Link interrupt last */
2781758cc3dcSJack F Vogel 	if (adapter->vector) /* we are doing MSIX */
2782758cc3dcSJack F Vogel 		rid = adapter->vector + 1;
2783758cc3dcSJack F Vogel 	else
2784758cc3dcSJack F Vogel 		(adapter->msix != 0) ? (rid = 1):(rid = 0);
2785758cc3dcSJack F Vogel 
2786758cc3dcSJack F Vogel 	if (adapter->tag != NULL) {
2787758cc3dcSJack F Vogel 		bus_teardown_intr(dev, adapter->res, adapter->tag);
2788758cc3dcSJack F Vogel 		adapter->tag = NULL;
2789758cc3dcSJack F Vogel 	}
2790758cc3dcSJack F Vogel 	if (adapter->res != NULL)
2791758cc3dcSJack F Vogel 		bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res);
2792758cc3dcSJack F Vogel 
2793758cc3dcSJack F Vogel mem:
2794758cc3dcSJack F Vogel 	if (adapter->msix)
2795758cc3dcSJack F Vogel 		pci_release_msi(dev);
2796758cc3dcSJack F Vogel 
2797758cc3dcSJack F Vogel 	if (adapter->msix_mem != NULL)
2798758cc3dcSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
2799758cc3dcSJack F Vogel 		    memrid, adapter->msix_mem);
2800758cc3dcSJack F Vogel 
2801758cc3dcSJack F Vogel 	if (adapter->pci_mem != NULL)
2802758cc3dcSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
2803758cc3dcSJack F Vogel 		    PCIR_BAR(0), adapter->pci_mem);
2804758cc3dcSJack F Vogel 
2805758cc3dcSJack F Vogel 	return;
2806758cc3dcSJack F Vogel }
2807758cc3dcSJack F Vogel 
2808758cc3dcSJack F Vogel /*********************************************************************
2809758cc3dcSJack F Vogel  *
2810758cc3dcSJack F Vogel  *  Setup networking device structure and register an interface.
2811758cc3dcSJack F Vogel  *
2812758cc3dcSJack F Vogel  **********************************************************************/
2813758cc3dcSJack F Vogel static int
2814758cc3dcSJack F Vogel ixgbe_setup_interface(device_t dev, struct adapter *adapter)
2815758cc3dcSJack F Vogel {
2816758cc3dcSJack F Vogel 	struct ifnet   *ifp;
2817758cc3dcSJack F Vogel 
2818758cc3dcSJack F Vogel 	INIT_DEBUGOUT("ixgbe_setup_interface: begin");
2819758cc3dcSJack F Vogel 
2820758cc3dcSJack F Vogel 	ifp = adapter->ifp = if_alloc(IFT_ETHER);
2821758cc3dcSJack F Vogel 	if (ifp == NULL) {
2822758cc3dcSJack F Vogel 		device_printf(dev, "can not allocate ifnet structure\n");
2823758cc3dcSJack F Vogel 		return (-1);
2824758cc3dcSJack F Vogel 	}
2825758cc3dcSJack F Vogel 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
2826758cc3dcSJack F Vogel 	ifp->if_baudrate = IF_Gbps(10);
2827758cc3dcSJack F Vogel 	ifp->if_init = ixgbe_init;
2828758cc3dcSJack F Vogel 	ifp->if_softc = adapter;
2829758cc3dcSJack F Vogel 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
2830758cc3dcSJack F Vogel 	ifp->if_ioctl = ixgbe_ioctl;
2831758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036
2832758cc3dcSJack F Vogel 	if_setgetcounterfn(ifp, ixgbe_get_counter);
2833758cc3dcSJack F Vogel #endif
28346f37f232SEric Joyner #if __FreeBSD_version >= 1100045
28356f37f232SEric Joyner 	/* TSO parameters */
28366f37f232SEric Joyner 	ifp->if_hw_tsomax = 65518;
28376f37f232SEric Joyner 	ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER;
28386f37f232SEric Joyner 	ifp->if_hw_tsomaxsegsize = 2048;
28396f37f232SEric Joyner #endif
2840758cc3dcSJack F Vogel #ifndef IXGBE_LEGACY_TX
2841758cc3dcSJack F Vogel 	ifp->if_transmit = ixgbe_mq_start;
2842758cc3dcSJack F Vogel 	ifp->if_qflush = ixgbe_qflush;
2843758cc3dcSJack F Vogel #else
2844758cc3dcSJack F Vogel 	ifp->if_start = ixgbe_start;
2845758cc3dcSJack F Vogel 	IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2);
2846758cc3dcSJack F Vogel 	ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2;
2847758cc3dcSJack F Vogel 	IFQ_SET_READY(&ifp->if_snd);
2848758cc3dcSJack F Vogel #endif
2849758cc3dcSJack F Vogel 
2850758cc3dcSJack F Vogel 	ether_ifattach(ifp, adapter->hw.mac.addr);
2851758cc3dcSJack F Vogel 
2852758cc3dcSJack F Vogel 	adapter->max_frame_size =
2853758cc3dcSJack F Vogel 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
2854758cc3dcSJack F Vogel 
2855758cc3dcSJack F Vogel 	/*
2856758cc3dcSJack F Vogel 	 * Tell the upper layer(s) we support long frames.
2857758cc3dcSJack F Vogel 	 */
2858758cc3dcSJack F Vogel 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
2859758cc3dcSJack F Vogel 
2860a9ca1c79SSean Bruno 	/* Set capability flags */
2861a9ca1c79SSean Bruno 	ifp->if_capabilities |= IFCAP_RXCSUM
2862a9ca1c79SSean Bruno 			     |  IFCAP_TXCSUM
2863a9ca1c79SSean Bruno 			     |  IFCAP_RXCSUM_IPV6
2864a9ca1c79SSean Bruno 			     |  IFCAP_TXCSUM_IPV6
2865a9ca1c79SSean Bruno 			     |  IFCAP_TSO4
2866a9ca1c79SSean Bruno 			     |  IFCAP_TSO6
2867a9ca1c79SSean Bruno 			     |  IFCAP_LRO
2868a9ca1c79SSean Bruno 			     |  IFCAP_VLAN_HWTAGGING
2869758cc3dcSJack F Vogel 			     |  IFCAP_VLAN_HWTSO
2870a9ca1c79SSean Bruno 			     |  IFCAP_VLAN_HWCSUM
2871a9ca1c79SSean Bruno 			     |  IFCAP_JUMBO_MTU
2872758cc3dcSJack F Vogel 			     |  IFCAP_VLAN_MTU
2873758cc3dcSJack F Vogel 			     |  IFCAP_HWSTATS;
2874a9ca1c79SSean Bruno 
2875a9ca1c79SSean Bruno 	/* Enable the above capabilities by default */
2876758cc3dcSJack F Vogel 	ifp->if_capenable = ifp->if_capabilities;
2877758cc3dcSJack F Vogel 
2878758cc3dcSJack F Vogel 	/*
2879758cc3dcSJack F Vogel 	** Don't turn this on by default, if vlans are
2880758cc3dcSJack F Vogel 	** created on another pseudo device (eg. lagg)
2881758cc3dcSJack F Vogel 	** then vlan events are not passed thru, breaking
2882758cc3dcSJack F Vogel 	** operation, but with HW FILTER off it works. If
2883758cc3dcSJack F Vogel 	** using vlans directly on the ixgbe driver you can
2884758cc3dcSJack F Vogel 	** enable this and get full hardware tag filtering.
2885758cc3dcSJack F Vogel 	*/
2886758cc3dcSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
2887758cc3dcSJack F Vogel 
2888758cc3dcSJack F Vogel 	/*
2889758cc3dcSJack F Vogel 	 * Specify the media types supported by this adapter and register
2890758cc3dcSJack F Vogel 	 * callbacks to update media and link information
2891758cc3dcSJack F Vogel 	 */
2892758cc3dcSJack F Vogel 	ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change,
2893758cc3dcSJack F Vogel 		    ixgbe_media_status);
2894758cc3dcSJack F Vogel 
2895a9ca1c79SSean Bruno 	adapter->phy_layer = ixgbe_get_supported_physical_layer(&adapter->hw);
2896758cc3dcSJack F Vogel 	ixgbe_add_media_types(adapter);
2897758cc3dcSJack F Vogel 
2898a9ca1c79SSean Bruno 	/* Set autoselect media by default */
2899758cc3dcSJack F Vogel 	ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
2900758cc3dcSJack F Vogel 
2901758cc3dcSJack F Vogel 	return (0);
2902758cc3dcSJack F Vogel }
2903758cc3dcSJack F Vogel 
2904758cc3dcSJack F Vogel static void
2905758cc3dcSJack F Vogel ixgbe_add_media_types(struct adapter *adapter)
2906758cc3dcSJack F Vogel {
2907758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
2908758cc3dcSJack F Vogel 	device_t dev = adapter->dev;
2909758cc3dcSJack F Vogel 	int layer;
2910758cc3dcSJack F Vogel 
2911a9ca1c79SSean Bruno 	layer = adapter->phy_layer;
2912758cc3dcSJack F Vogel 
2913758cc3dcSJack F Vogel 	/* Media types with matching FreeBSD media defines */
2914758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T)
2915758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2916758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T)
2917758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL);
2918758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX)
2919758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2920758cc3dcSJack F Vogel 
2921758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU ||
2922758cc3dcSJack F Vogel 	    layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA)
2923758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2924758cc3dcSJack F Vogel 
2925a9ca1c79SSean Bruno 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) {
2926758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2927a9ca1c79SSean Bruno 		if (hw->phy.multispeed_fiber)
2928a9ca1c79SSean Bruno 			ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, NULL);
2929a9ca1c79SSean Bruno 	}
2930a9ca1c79SSean Bruno 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) {
2931758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2932a9ca1c79SSean Bruno 		if (hw->phy.multispeed_fiber)
2933a9ca1c79SSean Bruno 			ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
2934a9ca1c79SSean Bruno 	} else if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX)
2935a9ca1c79SSean Bruno 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
2936758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4)
2937758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
2938758cc3dcSJack F Vogel 
2939a9ca1c79SSean Bruno #ifdef IFM_ETH_XTYPE
2940a9ca1c79SSean Bruno 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR)
2941a9ca1c79SSean Bruno 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KR, 0, NULL);
2942a9ca1c79SSean Bruno 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4)
2943a9ca1c79SSean Bruno 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KX4, 0, NULL);
2944a9ca1c79SSean Bruno 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX)
2945a9ca1c79SSean Bruno 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_KX, 0, NULL);
2946a9ca1c79SSean Bruno #else
2947758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) {
2948758cc3dcSJack F Vogel 		device_printf(dev, "Media supported: 10GbaseKR\n");
29496f37f232SEric Joyner 		device_printf(dev, "10GbaseKR mapped to 10GbaseSR\n");
29506f37f232SEric Joyner 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2951758cc3dcSJack F Vogel 	}
2952758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) {
2953758cc3dcSJack F Vogel 		device_printf(dev, "Media supported: 10GbaseKX4\n");
29546f37f232SEric Joyner 		device_printf(dev, "10GbaseKX4 mapped to 10GbaseCX4\n");
29556f37f232SEric Joyner 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
2956758cc3dcSJack F Vogel 	}
2957758cc3dcSJack F Vogel 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) {
2958758cc3dcSJack F Vogel 		device_printf(dev, "Media supported: 1000baseKX\n");
29596f37f232SEric Joyner 		device_printf(dev, "1000baseKX mapped to 1000baseCX\n");
29606f37f232SEric Joyner 		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_CX, 0, NULL);
2961758cc3dcSJack F Vogel 	}
2962a9ca1c79SSean Bruno #endif
2963a9ca1c79SSean Bruno 	if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX)
2964758cc3dcSJack F Vogel 		device_printf(dev, "Media supported: 1000baseBX\n");
2965758cc3dcSJack F Vogel 
2966758cc3dcSJack F Vogel 	if (hw->device_id == IXGBE_DEV_ID_82598AT) {
2967758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media,
2968758cc3dcSJack F Vogel 		    IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
2969758cc3dcSJack F Vogel 		ifmedia_add(&adapter->media,
2970758cc3dcSJack F Vogel 		    IFM_ETHER | IFM_1000_T, 0, NULL);
2971758cc3dcSJack F Vogel 	}
2972758cc3dcSJack F Vogel 
2973758cc3dcSJack F Vogel 	ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL);
2974758cc3dcSJack F Vogel }
2975758cc3dcSJack F Vogel 
2976758cc3dcSJack F Vogel static void
2977758cc3dcSJack F Vogel ixgbe_config_link(struct adapter *adapter)
2978758cc3dcSJack F Vogel {
2979758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
2980758cc3dcSJack F Vogel 	u32	autoneg, err = 0;
2981758cc3dcSJack F Vogel 	bool	sfp, negotiate;
2982758cc3dcSJack F Vogel 
2983758cc3dcSJack F Vogel 	sfp = ixgbe_is_sfp(hw);
2984758cc3dcSJack F Vogel 
2985758cc3dcSJack F Vogel 	if (sfp) {
2986758cc3dcSJack F Vogel 		taskqueue_enqueue(adapter->tq, &adapter->mod_task);
2987758cc3dcSJack F Vogel 	} else {
2988758cc3dcSJack F Vogel 		if (hw->mac.ops.check_link)
2989758cc3dcSJack F Vogel 			err = ixgbe_check_link(hw, &adapter->link_speed,
2990758cc3dcSJack F Vogel 			    &adapter->link_up, FALSE);
2991758cc3dcSJack F Vogel 		if (err)
2992758cc3dcSJack F Vogel 			goto out;
2993758cc3dcSJack F Vogel 		autoneg = hw->phy.autoneg_advertised;
2994758cc3dcSJack F Vogel 		if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
2995758cc3dcSJack F Vogel                 	err  = hw->mac.ops.get_link_capabilities(hw,
2996758cc3dcSJack F Vogel 			    &autoneg, &negotiate);
2997758cc3dcSJack F Vogel 		if (err)
2998758cc3dcSJack F Vogel 			goto out;
2999758cc3dcSJack F Vogel 		if (hw->mac.ops.setup_link)
3000758cc3dcSJack F Vogel                 	err = hw->mac.ops.setup_link(hw,
3001758cc3dcSJack F Vogel 			    autoneg, adapter->link_up);
3002758cc3dcSJack F Vogel 	}
3003758cc3dcSJack F Vogel out:
3004758cc3dcSJack F Vogel 	return;
3005758cc3dcSJack F Vogel }
3006758cc3dcSJack F Vogel 
3007758cc3dcSJack F Vogel 
3008758cc3dcSJack F Vogel /*********************************************************************
3009758cc3dcSJack F Vogel  *
3010758cc3dcSJack F Vogel  *  Enable transmit units.
3011758cc3dcSJack F Vogel  *
3012758cc3dcSJack F Vogel  **********************************************************************/
3013758cc3dcSJack F Vogel static void
3014758cc3dcSJack F Vogel ixgbe_initialize_transmit_units(struct adapter *adapter)
3015758cc3dcSJack F Vogel {
3016758cc3dcSJack F Vogel 	struct tx_ring	*txr = adapter->tx_rings;
3017758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
3018758cc3dcSJack F Vogel 
3019758cc3dcSJack F Vogel 	/* Setup the Base and Length of the Tx Descriptor Ring */
3020758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, txr++) {
3021758cc3dcSJack F Vogel 		u64	tdba = txr->txdma.dma_paddr;
3022758cc3dcSJack F Vogel 		u32	txctrl = 0;
302348056c88SJack F Vogel 		int	j = txr->me;
3024758cc3dcSJack F Vogel 
302548056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j),
3026758cc3dcSJack F Vogel 		       (tdba & 0x00000000ffffffffULL));
302748056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32));
302848056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j),
3029758cc3dcSJack F Vogel 		    adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc));
3030758cc3dcSJack F Vogel 
3031758cc3dcSJack F Vogel 		/* Setup the HW Tx Head and Tail descriptor pointers */
303248056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0);
303348056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0);
3034758cc3dcSJack F Vogel 
3035758cc3dcSJack F Vogel 		/* Cache the tail address */
303648056c88SJack F Vogel 		txr->tail = IXGBE_TDT(j);
3037758cc3dcSJack F Vogel 
3038758cc3dcSJack F Vogel 		/* Disable Head Writeback */
3039a9ca1c79SSean Bruno 		/*
3040a9ca1c79SSean Bruno 		 * Note: for X550 series devices, these registers are actually
3041a9ca1c79SSean Bruno 		 * prefixed with TPH_ isntead of DCA_, but the addresses and
3042a9ca1c79SSean Bruno 		 * fields remain the same.
3043a9ca1c79SSean Bruno 		 */
3044758cc3dcSJack F Vogel 		switch (hw->mac.type) {
3045758cc3dcSJack F Vogel 		case ixgbe_mac_82598EB:
304648056c88SJack F Vogel 			txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j));
3047758cc3dcSJack F Vogel 			break;
3048758cc3dcSJack F Vogel 		default:
304948056c88SJack F Vogel 			txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j));
3050758cc3dcSJack F Vogel 			break;
3051758cc3dcSJack F Vogel                 }
3052758cc3dcSJack F Vogel 		txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN;
3053758cc3dcSJack F Vogel 		switch (hw->mac.type) {
3054758cc3dcSJack F Vogel 		case ixgbe_mac_82598EB:
305548056c88SJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl);
3056758cc3dcSJack F Vogel 			break;
3057758cc3dcSJack F Vogel 		default:
305848056c88SJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl);
3059758cc3dcSJack F Vogel 			break;
3060758cc3dcSJack F Vogel 		}
3061758cc3dcSJack F Vogel 
3062758cc3dcSJack F Vogel 	}
3063758cc3dcSJack F Vogel 
3064758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
3065758cc3dcSJack F Vogel 		u32 dmatxctl, rttdcs;
306648056c88SJack F Vogel #ifdef PCI_IOV
306748056c88SJack F Vogel 		enum ixgbe_iov_mode mode = ixgbe_get_iov_mode(adapter);
306848056c88SJack F Vogel #endif
3069758cc3dcSJack F Vogel 		dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
3070758cc3dcSJack F Vogel 		dmatxctl |= IXGBE_DMATXCTL_TE;
3071758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl);
3072758cc3dcSJack F Vogel 		/* Disable arbiter to set MTQC */
3073758cc3dcSJack F Vogel 		rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
3074758cc3dcSJack F Vogel 		rttdcs |= IXGBE_RTTDCS_ARBDIS;
3075758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
307648056c88SJack F Vogel #ifdef PCI_IOV
307748056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_MTQC, ixgbe_get_mtqc(mode));
307848056c88SJack F Vogel #else
3079758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB);
308048056c88SJack F Vogel #endif
3081758cc3dcSJack F Vogel 		rttdcs &= ~IXGBE_RTTDCS_ARBDIS;
3082758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
3083758cc3dcSJack F Vogel 	}
3084758cc3dcSJack F Vogel 
3085758cc3dcSJack F Vogel 	return;
3086758cc3dcSJack F Vogel }
3087758cc3dcSJack F Vogel 
3088758cc3dcSJack F Vogel static void
3089a9ca1c79SSean Bruno ixgbe_initialize_rss_mapping(struct adapter *adapter)
3090758cc3dcSJack F Vogel {
3091758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
309248056c88SJack F Vogel 	u32 reta = 0, mrqc, rss_key[10];
309348056c88SJack F Vogel 	int queue_id, table_size, index_mult;
3094758cc3dcSJack F Vogel #ifdef	RSS
309548056c88SJack F Vogel 	u32 rss_hash_config;
3096758cc3dcSJack F Vogel #endif
309748056c88SJack F Vogel #ifdef PCI_IOV
309848056c88SJack F Vogel 	enum ixgbe_iov_mode mode;
309948056c88SJack F Vogel #endif
3100758cc3dcSJack F Vogel 
3101758cc3dcSJack F Vogel #ifdef	RSS
3102758cc3dcSJack F Vogel 	/* Fetch the configured RSS key */
3103758cc3dcSJack F Vogel 	rss_getkey((uint8_t *) &rss_key);
3104758cc3dcSJack F Vogel #else
3105758cc3dcSJack F Vogel 	/* set up random bits */
3106758cc3dcSJack F Vogel 	arc4rand(&rss_key, sizeof(rss_key), 0);
3107758cc3dcSJack F Vogel #endif
3108758cc3dcSJack F Vogel 
31096f37f232SEric Joyner 	/* Set multiplier for RETA setup and table size based on MAC */
31106f37f232SEric Joyner 	index_mult = 0x1;
31116f37f232SEric Joyner 	table_size = 128;
31126f37f232SEric Joyner 	switch (adapter->hw.mac.type) {
31136f37f232SEric Joyner 	case ixgbe_mac_82598EB:
31146f37f232SEric Joyner 		index_mult = 0x11;
31156f37f232SEric Joyner 		break;
31166f37f232SEric Joyner 	case ixgbe_mac_X550:
31176f37f232SEric Joyner 	case ixgbe_mac_X550EM_x:
31186f37f232SEric Joyner 		table_size = 512;
31196f37f232SEric Joyner 		break;
31206f37f232SEric Joyner 	default:
31216f37f232SEric Joyner 		break;
31226f37f232SEric Joyner 	}
31236f37f232SEric Joyner 
3124758cc3dcSJack F Vogel 	/* Set up the redirection table */
312548056c88SJack F Vogel 	for (int i = 0, j = 0; i < table_size; i++, j++) {
3126758cc3dcSJack F Vogel 		if (j == adapter->num_queues) j = 0;
3127758cc3dcSJack F Vogel #ifdef	RSS
3128758cc3dcSJack F Vogel 		/*
3129758cc3dcSJack F Vogel 		 * Fetch the RSS bucket id for the given indirection entry.
3130758cc3dcSJack F Vogel 		 * Cap it at the number of configured buckets (which is
3131758cc3dcSJack F Vogel 		 * num_queues.)
3132758cc3dcSJack F Vogel 		 */
3133758cc3dcSJack F Vogel 		queue_id = rss_get_indirection_to_bucket(i);
3134758cc3dcSJack F Vogel 		queue_id = queue_id % adapter->num_queues;
3135758cc3dcSJack F Vogel #else
31366f37f232SEric Joyner 		queue_id = (j * index_mult);
3137758cc3dcSJack F Vogel #endif
3138758cc3dcSJack F Vogel 		/*
3139758cc3dcSJack F Vogel 		 * The low 8 bits are for hash value (n+0);
3140758cc3dcSJack F Vogel 		 * The next 8 bits are for hash value (n+1), etc.
3141758cc3dcSJack F Vogel 		 */
3142758cc3dcSJack F Vogel 		reta = reta >> 8;
3143758cc3dcSJack F Vogel 		reta = reta | ( ((uint32_t) queue_id) << 24);
3144758cc3dcSJack F Vogel 		if ((i & 3) == 3) {
31456f37f232SEric Joyner 			if (i < 128)
3146758cc3dcSJack F Vogel 				IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
31476f37f232SEric Joyner 			else
31486f37f232SEric Joyner 				IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), reta);
3149758cc3dcSJack F Vogel 			reta = 0;
3150758cc3dcSJack F Vogel 		}
3151758cc3dcSJack F Vogel 	}
3152758cc3dcSJack F Vogel 
3153758cc3dcSJack F Vogel 	/* Now fill our hash function seeds */
3154758cc3dcSJack F Vogel 	for (int i = 0; i < 10; i++)
3155758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]);
3156758cc3dcSJack F Vogel 
3157758cc3dcSJack F Vogel 	/* Perform hash on these packet types */
3158758cc3dcSJack F Vogel #ifdef	RSS
3159758cc3dcSJack F Vogel 	mrqc = IXGBE_MRQC_RSSEN;
3160758cc3dcSJack F Vogel 	rss_hash_config = rss_gethashconfig();
3161758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
3162758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4;
3163758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
3164758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP;
3165758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
3166758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6;
3167758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
3168758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
3169758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
3170758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX;
3171758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX)
3172758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP;
3173758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
3174758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP;
3175758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX)
3176758cc3dcSJack F Vogel 		device_printf(adapter->dev,
3177758cc3dcSJack F Vogel 		    "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, "
3178758cc3dcSJack F Vogel 		    "but not supported\n", __func__);
3179758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
3180758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
3181758cc3dcSJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX)
3182758cc3dcSJack F Vogel 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
3183758cc3dcSJack F Vogel #else
3184758cc3dcSJack F Vogel 	/*
3185758cc3dcSJack F Vogel 	 * Disable UDP - IP fragments aren't currently being handled
3186758cc3dcSJack F Vogel 	 * and so we end up with a mix of 2-tuple and 4-tuple
3187758cc3dcSJack F Vogel 	 * traffic.
3188758cc3dcSJack F Vogel 	 */
3189758cc3dcSJack F Vogel 	mrqc = IXGBE_MRQC_RSSEN
3190758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV4
3191758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
3192758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP
3193758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV6_EX
3194758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV6
3195758cc3dcSJack F Vogel 	     | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
3196758cc3dcSJack F Vogel 	;
3197758cc3dcSJack F Vogel #endif /* RSS */
319848056c88SJack F Vogel #ifdef PCI_IOV
319948056c88SJack F Vogel 	mode = ixgbe_get_iov_mode(adapter);
320048056c88SJack F Vogel 	mrqc |= ixgbe_get_mrqc(mode);
320148056c88SJack F Vogel #endif
3202758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
3203758cc3dcSJack F Vogel }
3204758cc3dcSJack F Vogel 
3205758cc3dcSJack F Vogel 
3206758cc3dcSJack F Vogel /*********************************************************************
3207758cc3dcSJack F Vogel  *
3208758cc3dcSJack F Vogel  *  Setup receive registers and features.
3209758cc3dcSJack F Vogel  *
3210758cc3dcSJack F Vogel  **********************************************************************/
3211758cc3dcSJack F Vogel #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2
3212758cc3dcSJack F Vogel 
3213758cc3dcSJack F Vogel #define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1)
3214758cc3dcSJack F Vogel 
3215758cc3dcSJack F Vogel static void
3216758cc3dcSJack F Vogel ixgbe_initialize_receive_units(struct adapter *adapter)
3217758cc3dcSJack F Vogel {
3218758cc3dcSJack F Vogel 	struct	rx_ring	*rxr = adapter->rx_rings;
3219758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
3220758cc3dcSJack F Vogel 	struct ifnet   *ifp = adapter->ifp;
3221758cc3dcSJack F Vogel 	u32		bufsz, fctrl, srrctl, rxcsum;
3222758cc3dcSJack F Vogel 	u32		hlreg;
3223758cc3dcSJack F Vogel 
3224758cc3dcSJack F Vogel 	/*
3225758cc3dcSJack F Vogel 	 * Make sure receives are disabled while
3226758cc3dcSJack F Vogel 	 * setting up the descriptor ring
3227758cc3dcSJack F Vogel 	 */
3228758cc3dcSJack F Vogel 	ixgbe_disable_rx(hw);
3229758cc3dcSJack F Vogel 
3230758cc3dcSJack F Vogel 	/* Enable broadcasts */
3231758cc3dcSJack F Vogel 	fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
3232758cc3dcSJack F Vogel 	fctrl |= IXGBE_FCTRL_BAM;
32336f37f232SEric Joyner 	if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
3234758cc3dcSJack F Vogel 		fctrl |= IXGBE_FCTRL_DPF;
3235758cc3dcSJack F Vogel 		fctrl |= IXGBE_FCTRL_PMCF;
32366f37f232SEric Joyner 	}
3237758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
3238758cc3dcSJack F Vogel 
3239758cc3dcSJack F Vogel 	/* Set for Jumbo Frames? */
3240758cc3dcSJack F Vogel 	hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0);
3241758cc3dcSJack F Vogel 	if (ifp->if_mtu > ETHERMTU)
3242758cc3dcSJack F Vogel 		hlreg |= IXGBE_HLREG0_JUMBOEN;
3243758cc3dcSJack F Vogel 	else
3244758cc3dcSJack F Vogel 		hlreg &= ~IXGBE_HLREG0_JUMBOEN;
3245758cc3dcSJack F Vogel #ifdef DEV_NETMAP
3246758cc3dcSJack F Vogel 	/* crcstrip is conditional in netmap (in RDRXCTL too ?) */
3247758cc3dcSJack F Vogel 	if (ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip)
3248758cc3dcSJack F Vogel 		hlreg &= ~IXGBE_HLREG0_RXCRCSTRP;
3249758cc3dcSJack F Vogel 	else
3250758cc3dcSJack F Vogel 		hlreg |= IXGBE_HLREG0_RXCRCSTRP;
3251758cc3dcSJack F Vogel #endif /* DEV_NETMAP */
3252758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg);
3253758cc3dcSJack F Vogel 
3254758cc3dcSJack F Vogel 	bufsz = (adapter->rx_mbuf_sz +
3255758cc3dcSJack F Vogel 	    BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
3256758cc3dcSJack F Vogel 
3257758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, rxr++) {
3258758cc3dcSJack F Vogel 		u64 rdba = rxr->rxdma.dma_paddr;
325948056c88SJack F Vogel 		int j = rxr->me;
3260758cc3dcSJack F Vogel 
3261758cc3dcSJack F Vogel 		/* Setup the Base and Length of the Rx Descriptor Ring */
326248056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j),
3263758cc3dcSJack F Vogel 			       (rdba & 0x00000000ffffffffULL));
326448056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32));
326548056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j),
3266758cc3dcSJack F Vogel 		    adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc));
3267758cc3dcSJack F Vogel 
3268758cc3dcSJack F Vogel 		/* Set up the SRRCTL register */
326948056c88SJack F Vogel 		srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(j));
3270758cc3dcSJack F Vogel 		srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
3271758cc3dcSJack F Vogel 		srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
3272758cc3dcSJack F Vogel 		srrctl |= bufsz;
3273758cc3dcSJack F Vogel 		srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
3274758cc3dcSJack F Vogel 
3275758cc3dcSJack F Vogel 		/*
3276758cc3dcSJack F Vogel 		 * Set DROP_EN iff we have no flow control and >1 queue.
3277758cc3dcSJack F Vogel 		 * Note that srrctl was cleared shortly before during reset,
3278758cc3dcSJack F Vogel 		 * so we do not need to clear the bit, but do it just in case
3279758cc3dcSJack F Vogel 		 * this code is moved elsewhere.
3280758cc3dcSJack F Vogel 		 */
328130126537SJack F Vogel 		if (adapter->num_queues > 1 &&
328230126537SJack F Vogel 		    adapter->hw.fc.requested_mode == ixgbe_fc_none) {
3283758cc3dcSJack F Vogel 			srrctl |= IXGBE_SRRCTL_DROP_EN;
328430126537SJack F Vogel 		} else {
3285758cc3dcSJack F Vogel 			srrctl &= ~IXGBE_SRRCTL_DROP_EN;
328630126537SJack F Vogel 		}
3287758cc3dcSJack F Vogel 
328848056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(j), srrctl);
3289758cc3dcSJack F Vogel 
3290758cc3dcSJack F Vogel 		/* Setup the HW Rx Head and Tail Descriptor Pointers */
329148056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0);
329248056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0);
3293758cc3dcSJack F Vogel 
3294758cc3dcSJack F Vogel 		/* Set the driver rx tail address */
3295758cc3dcSJack F Vogel 		rxr->tail =  IXGBE_RDT(rxr->me);
3296758cc3dcSJack F Vogel 	}
3297758cc3dcSJack F Vogel 
3298758cc3dcSJack F Vogel 	if (adapter->hw.mac.type != ixgbe_mac_82598EB) {
3299758cc3dcSJack F Vogel 		u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
3300758cc3dcSJack F Vogel 			      IXGBE_PSRTYPE_UDPHDR |
3301758cc3dcSJack F Vogel 			      IXGBE_PSRTYPE_IPV4HDR |
3302758cc3dcSJack F Vogel 			      IXGBE_PSRTYPE_IPV6HDR;
3303758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype);
3304758cc3dcSJack F Vogel 	}
3305758cc3dcSJack F Vogel 
3306758cc3dcSJack F Vogel 	rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
3307758cc3dcSJack F Vogel 
3308a9ca1c79SSean Bruno 	ixgbe_initialize_rss_mapping(adapter);
3309758cc3dcSJack F Vogel 
3310758cc3dcSJack F Vogel 	if (adapter->num_queues > 1) {
3311758cc3dcSJack F Vogel 		/* RSS and RX IPP Checksum are mutually exclusive */
3312758cc3dcSJack F Vogel 		rxcsum |= IXGBE_RXCSUM_PCSD;
3313758cc3dcSJack F Vogel 	}
3314758cc3dcSJack F Vogel 
3315758cc3dcSJack F Vogel 	if (ifp->if_capenable & IFCAP_RXCSUM)
3316758cc3dcSJack F Vogel 		rxcsum |= IXGBE_RXCSUM_PCSD;
3317758cc3dcSJack F Vogel 
3318a9ca1c79SSean Bruno 	/* This is useful for calculating UDP/IP fragment checksums */
3319758cc3dcSJack F Vogel 	if (!(rxcsum & IXGBE_RXCSUM_PCSD))
3320758cc3dcSJack F Vogel 		rxcsum |= IXGBE_RXCSUM_IPPCSE;
3321758cc3dcSJack F Vogel 
3322758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
3323758cc3dcSJack F Vogel 
3324758cc3dcSJack F Vogel 	return;
3325758cc3dcSJack F Vogel }
3326758cc3dcSJack F Vogel 
3327758cc3dcSJack F Vogel 
3328758cc3dcSJack F Vogel /*
3329758cc3dcSJack F Vogel ** This routine is run via an vlan config EVENT,
3330758cc3dcSJack F Vogel ** it enables us to use the HW Filter table since
3331758cc3dcSJack F Vogel ** we can get the vlan id. This just creates the
3332758cc3dcSJack F Vogel ** entry in the soft version of the VFTA, init will
3333758cc3dcSJack F Vogel ** repopulate the real table.
3334758cc3dcSJack F Vogel */
3335758cc3dcSJack F Vogel static void
3336758cc3dcSJack F Vogel ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
3337758cc3dcSJack F Vogel {
3338758cc3dcSJack F Vogel 	struct adapter	*adapter = ifp->if_softc;
3339758cc3dcSJack F Vogel 	u16		index, bit;
3340758cc3dcSJack F Vogel 
3341758cc3dcSJack F Vogel 	if (ifp->if_softc !=  arg)   /* Not our event */
3342758cc3dcSJack F Vogel 		return;
3343758cc3dcSJack F Vogel 
3344758cc3dcSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
3345758cc3dcSJack F Vogel 		return;
3346758cc3dcSJack F Vogel 
3347758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
3348758cc3dcSJack F Vogel 	index = (vtag >> 5) & 0x7F;
3349758cc3dcSJack F Vogel 	bit = vtag & 0x1F;
3350758cc3dcSJack F Vogel 	adapter->shadow_vfta[index] |= (1 << bit);
3351758cc3dcSJack F Vogel 	++adapter->num_vlans;
3352758cc3dcSJack F Vogel 	ixgbe_setup_vlan_hw_support(adapter);
3353758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
3354758cc3dcSJack F Vogel }
3355758cc3dcSJack F Vogel 
3356758cc3dcSJack F Vogel /*
3357758cc3dcSJack F Vogel ** This routine is run via an vlan
3358758cc3dcSJack F Vogel ** unconfig EVENT, remove our entry
3359758cc3dcSJack F Vogel ** in the soft vfta.
3360758cc3dcSJack F Vogel */
3361758cc3dcSJack F Vogel static void
3362758cc3dcSJack F Vogel ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
3363758cc3dcSJack F Vogel {
3364758cc3dcSJack F Vogel 	struct adapter	*adapter = ifp->if_softc;
3365758cc3dcSJack F Vogel 	u16		index, bit;
3366758cc3dcSJack F Vogel 
3367758cc3dcSJack F Vogel 	if (ifp->if_softc !=  arg)
3368758cc3dcSJack F Vogel 		return;
3369758cc3dcSJack F Vogel 
3370758cc3dcSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
3371758cc3dcSJack F Vogel 		return;
3372758cc3dcSJack F Vogel 
3373758cc3dcSJack F Vogel 	IXGBE_CORE_LOCK(adapter);
3374758cc3dcSJack F Vogel 	index = (vtag >> 5) & 0x7F;
3375758cc3dcSJack F Vogel 	bit = vtag & 0x1F;
3376758cc3dcSJack F Vogel 	adapter->shadow_vfta[index] &= ~(1 << bit);
3377758cc3dcSJack F Vogel 	--adapter->num_vlans;
3378758cc3dcSJack F Vogel 	/* Re-init to load the changes */
3379758cc3dcSJack F Vogel 	ixgbe_setup_vlan_hw_support(adapter);
3380758cc3dcSJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
3381758cc3dcSJack F Vogel }
3382758cc3dcSJack F Vogel 
3383758cc3dcSJack F Vogel static void
3384758cc3dcSJack F Vogel ixgbe_setup_vlan_hw_support(struct adapter *adapter)
3385758cc3dcSJack F Vogel {
3386758cc3dcSJack F Vogel 	struct ifnet 	*ifp = adapter->ifp;
3387758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
3388758cc3dcSJack F Vogel 	struct rx_ring	*rxr;
3389758cc3dcSJack F Vogel 	u32		ctrl;
3390758cc3dcSJack F Vogel 
3391758cc3dcSJack F Vogel 
3392758cc3dcSJack F Vogel 	/*
3393758cc3dcSJack F Vogel 	** We get here thru init_locked, meaning
3394758cc3dcSJack F Vogel 	** a soft reset, this has already cleared
3395758cc3dcSJack F Vogel 	** the VFTA and other state, so if there
3396758cc3dcSJack F Vogel 	** have been no vlan's registered do nothing.
3397758cc3dcSJack F Vogel 	*/
3398758cc3dcSJack F Vogel 	if (adapter->num_vlans == 0)
3399758cc3dcSJack F Vogel 		return;
3400758cc3dcSJack F Vogel 
3401758cc3dcSJack F Vogel 	/* Setup the queues for vlans */
3402758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++) {
3403758cc3dcSJack F Vogel 		rxr = &adapter->rx_rings[i];
3404758cc3dcSJack F Vogel 		/* On 82599 the VLAN enable is per/queue in RXDCTL */
3405758cc3dcSJack F Vogel 		if (hw->mac.type != ixgbe_mac_82598EB) {
340648056c88SJack F Vogel 			ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me));
3407758cc3dcSJack F Vogel 			ctrl |= IXGBE_RXDCTL_VME;
340848056c88SJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl);
3409758cc3dcSJack F Vogel 		}
3410758cc3dcSJack F Vogel 		rxr->vtag_strip = TRUE;
3411758cc3dcSJack F Vogel 	}
3412758cc3dcSJack F Vogel 
3413758cc3dcSJack F Vogel 	if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0)
3414758cc3dcSJack F Vogel 		return;
3415758cc3dcSJack F Vogel 	/*
3416758cc3dcSJack F Vogel 	** A soft reset zero's out the VFTA, so
3417758cc3dcSJack F Vogel 	** we need to repopulate it now.
3418758cc3dcSJack F Vogel 	*/
3419758cc3dcSJack F Vogel 	for (int i = 0; i < IXGBE_VFTA_SIZE; i++)
3420758cc3dcSJack F Vogel 		if (adapter->shadow_vfta[i] != 0)
3421758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_VFTA(i),
3422758cc3dcSJack F Vogel 			    adapter->shadow_vfta[i]);
3423758cc3dcSJack F Vogel 
3424758cc3dcSJack F Vogel 	ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
3425758cc3dcSJack F Vogel 	/* Enable the Filter Table if enabled */
3426758cc3dcSJack F Vogel 	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) {
3427758cc3dcSJack F Vogel 		ctrl &= ~IXGBE_VLNCTRL_CFIEN;
3428758cc3dcSJack F Vogel 		ctrl |= IXGBE_VLNCTRL_VFE;
3429758cc3dcSJack F Vogel 	}
3430758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82598EB)
3431758cc3dcSJack F Vogel 		ctrl |= IXGBE_VLNCTRL_VME;
3432758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl);
3433758cc3dcSJack F Vogel }
3434758cc3dcSJack F Vogel 
3435758cc3dcSJack F Vogel static void
3436758cc3dcSJack F Vogel ixgbe_enable_intr(struct adapter *adapter)
3437758cc3dcSJack F Vogel {
3438758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
3439758cc3dcSJack F Vogel 	struct ix_queue	*que = adapter->queues;
3440758cc3dcSJack F Vogel 	u32		mask, fwsm;
3441758cc3dcSJack F Vogel 
3442758cc3dcSJack F Vogel 	mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
3443758cc3dcSJack F Vogel 	/* Enable Fan Failure detection */
3444758cc3dcSJack F Vogel 	if (hw->device_id == IXGBE_DEV_ID_82598AT)
34456f37f232SEric Joyner 		    mask |= IXGBE_EIMS_GPI_SDP1;
3446758cc3dcSJack F Vogel 
3447758cc3dcSJack F Vogel 	switch (adapter->hw.mac.type) {
3448758cc3dcSJack F Vogel 		case ixgbe_mac_82599EB:
3449758cc3dcSJack F Vogel 			mask |= IXGBE_EIMS_ECC;
3450758cc3dcSJack F Vogel 			/* Temperature sensor on some adapters */
34516f37f232SEric Joyner 			mask |= IXGBE_EIMS_GPI_SDP0;
3452758cc3dcSJack F Vogel 			/* SFP+ (RX_LOS_N & MOD_ABS_N) */
34536f37f232SEric Joyner 			mask |= IXGBE_EIMS_GPI_SDP1;
34546f37f232SEric Joyner 			mask |= IXGBE_EIMS_GPI_SDP2;
3455758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
3456758cc3dcSJack F Vogel 			mask |= IXGBE_EIMS_FLOW_DIR;
3457758cc3dcSJack F Vogel #endif
345848056c88SJack F Vogel #ifdef PCI_IOV
345948056c88SJack F Vogel 			mask |= IXGBE_EIMS_MAILBOX;
346048056c88SJack F Vogel #endif
3461758cc3dcSJack F Vogel 			break;
3462758cc3dcSJack F Vogel 		case ixgbe_mac_X540:
3463758cc3dcSJack F Vogel 			/* Detect if Thermal Sensor is enabled */
3464758cc3dcSJack F Vogel 			fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
3465758cc3dcSJack F Vogel 			if (fwsm & IXGBE_FWSM_TS_ENABLED)
3466758cc3dcSJack F Vogel 				mask |= IXGBE_EIMS_TS;
34676f37f232SEric Joyner 			mask |= IXGBE_EIMS_ECC;
34686f37f232SEric Joyner #ifdef IXGBE_FDIR
34696f37f232SEric Joyner 			mask |= IXGBE_EIMS_FLOW_DIR;
34706f37f232SEric Joyner #endif
34716f37f232SEric Joyner 			break;
34726f37f232SEric Joyner 		case ixgbe_mac_X550:
34736f37f232SEric Joyner 		case ixgbe_mac_X550EM_x:
34746f37f232SEric Joyner 			/* MAC thermal sensor is automatically enabled */
34756f37f232SEric Joyner 			mask |= IXGBE_EIMS_TS;
34766f37f232SEric Joyner 			/* Some devices use SDP0 for important information */
34776f37f232SEric Joyner 			if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
34786f37f232SEric Joyner 			    hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T)
3479758cc3dcSJack F Vogel 				mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw);
3480758cc3dcSJack F Vogel 			mask |= IXGBE_EIMS_ECC;
3481758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
3482758cc3dcSJack F Vogel 			mask |= IXGBE_EIMS_FLOW_DIR;
3483758cc3dcSJack F Vogel #endif
348448056c88SJack F Vogel #ifdef PCI_IOV
348548056c88SJack F Vogel 			mask |= IXGBE_EIMS_MAILBOX;
348648056c88SJack F Vogel #endif
3487758cc3dcSJack F Vogel 		/* falls through */
3488758cc3dcSJack F Vogel 		default:
3489758cc3dcSJack F Vogel 			break;
3490758cc3dcSJack F Vogel 	}
3491758cc3dcSJack F Vogel 
3492758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask);
3493758cc3dcSJack F Vogel 
34946f37f232SEric Joyner 	/* With MSI-X we use auto clear */
3495758cc3dcSJack F Vogel 	if (adapter->msix_mem) {
3496758cc3dcSJack F Vogel 		mask = IXGBE_EIMS_ENABLE_MASK;
3497758cc3dcSJack F Vogel 		/* Don't autoclear Link */
3498758cc3dcSJack F Vogel 		mask &= ~IXGBE_EIMS_OTHER;
3499758cc3dcSJack F Vogel 		mask &= ~IXGBE_EIMS_LSC;
350048056c88SJack F Vogel #ifdef PCI_IOV
350148056c88SJack F Vogel 		mask &= ~IXGBE_EIMS_MAILBOX;
350248056c88SJack F Vogel #endif
3503758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask);
3504758cc3dcSJack F Vogel 	}
3505758cc3dcSJack F Vogel 
3506758cc3dcSJack F Vogel 	/*
3507758cc3dcSJack F Vogel 	** Now enable all queues, this is done separately to
3508758cc3dcSJack F Vogel 	** allow for handling the extended (beyond 32) MSIX
3509758cc3dcSJack F Vogel 	** vectors that can be used by 82599
3510758cc3dcSJack F Vogel 	*/
3511758cc3dcSJack F Vogel         for (int i = 0; i < adapter->num_queues; i++, que++)
3512758cc3dcSJack F Vogel                 ixgbe_enable_queue(adapter, que->msix);
3513758cc3dcSJack F Vogel 
3514758cc3dcSJack F Vogel 	IXGBE_WRITE_FLUSH(hw);
3515758cc3dcSJack F Vogel 
3516758cc3dcSJack F Vogel 	return;
3517758cc3dcSJack F Vogel }
3518758cc3dcSJack F Vogel 
3519758cc3dcSJack F Vogel static void
3520758cc3dcSJack F Vogel ixgbe_disable_intr(struct adapter *adapter)
3521758cc3dcSJack F Vogel {
3522758cc3dcSJack F Vogel 	if (adapter->msix_mem)
3523758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, 0);
3524758cc3dcSJack F Vogel 	if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
3525758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
3526758cc3dcSJack F Vogel 	} else {
3527758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000);
3528758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0);
3529758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
3530758cc3dcSJack F Vogel 	}
3531758cc3dcSJack F Vogel 	IXGBE_WRITE_FLUSH(&adapter->hw);
3532758cc3dcSJack F Vogel 	return;
3533758cc3dcSJack F Vogel }
3534758cc3dcSJack F Vogel 
3535758cc3dcSJack F Vogel /*
3536758cc3dcSJack F Vogel ** Get the width and transaction speed of
3537758cc3dcSJack F Vogel ** the slot this adapter is plugged into.
3538758cc3dcSJack F Vogel */
3539758cc3dcSJack F Vogel static void
3540a9ca1c79SSean Bruno ixgbe_get_slot_info(struct adapter *adapter)
3541758cc3dcSJack F Vogel {
3542a9ca1c79SSean Bruno 	device_t		dev = adapter->dev;
3543a9ca1c79SSean Bruno 	struct ixgbe_hw		*hw = &adapter->hw;
3544758cc3dcSJack F Vogel 	struct ixgbe_mac_info	*mac = &hw->mac;
3545758cc3dcSJack F Vogel 	u16			link;
3546758cc3dcSJack F Vogel 	u32			offset;
3547758cc3dcSJack F Vogel 
3548758cc3dcSJack F Vogel 	/* For most devices simply call the shared code routine */
3549758cc3dcSJack F Vogel 	if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) {
3550758cc3dcSJack F Vogel 		ixgbe_get_bus_info(hw);
3551758cc3dcSJack F Vogel 		/* These devices don't use PCI-E */
35526f37f232SEric Joyner 		switch (hw->mac.type) {
35536f37f232SEric Joyner 		case ixgbe_mac_X550EM_x:
3554758cc3dcSJack F Vogel 			return;
35556f37f232SEric Joyner 		default:
3556758cc3dcSJack F Vogel 			goto display;
3557758cc3dcSJack F Vogel 		}
35586f37f232SEric Joyner 	}
3559758cc3dcSJack F Vogel 
3560758cc3dcSJack F Vogel 	/*
3561758cc3dcSJack F Vogel 	** For the Quad port adapter we need to parse back
3562758cc3dcSJack F Vogel 	** up the PCI tree to find the speed of the expansion
3563758cc3dcSJack F Vogel 	** slot into which this adapter is plugged. A bit more work.
3564758cc3dcSJack F Vogel 	*/
3565758cc3dcSJack F Vogel 	dev = device_get_parent(device_get_parent(dev));
3566758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG
3567758cc3dcSJack F Vogel 	device_printf(dev, "parent pcib = %x,%x,%x\n",
3568758cc3dcSJack F Vogel 	    pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev));
3569758cc3dcSJack F Vogel #endif
3570758cc3dcSJack F Vogel 	dev = device_get_parent(device_get_parent(dev));
3571758cc3dcSJack F Vogel #ifdef IXGBE_DEBUG
3572758cc3dcSJack F Vogel 	device_printf(dev, "slot pcib = %x,%x,%x\n",
3573758cc3dcSJack F Vogel 	    pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev));
3574758cc3dcSJack F Vogel #endif
3575758cc3dcSJack F Vogel 	/* Now get the PCI Express Capabilities offset */
3576758cc3dcSJack F Vogel 	pci_find_cap(dev, PCIY_EXPRESS, &offset);
3577758cc3dcSJack F Vogel 	/* ...and read the Link Status Register */
3578758cc3dcSJack F Vogel 	link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
3579758cc3dcSJack F Vogel 	switch (link & IXGBE_PCI_LINK_WIDTH) {
3580758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_WIDTH_1:
3581758cc3dcSJack F Vogel 		hw->bus.width = ixgbe_bus_width_pcie_x1;
3582758cc3dcSJack F Vogel 		break;
3583758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_WIDTH_2:
3584758cc3dcSJack F Vogel 		hw->bus.width = ixgbe_bus_width_pcie_x2;
3585758cc3dcSJack F Vogel 		break;
3586758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_WIDTH_4:
3587758cc3dcSJack F Vogel 		hw->bus.width = ixgbe_bus_width_pcie_x4;
3588758cc3dcSJack F Vogel 		break;
3589758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_WIDTH_8:
3590758cc3dcSJack F Vogel 		hw->bus.width = ixgbe_bus_width_pcie_x8;
3591758cc3dcSJack F Vogel 		break;
3592758cc3dcSJack F Vogel 	default:
3593758cc3dcSJack F Vogel 		hw->bus.width = ixgbe_bus_width_unknown;
3594758cc3dcSJack F Vogel 		break;
3595758cc3dcSJack F Vogel 	}
3596758cc3dcSJack F Vogel 
3597758cc3dcSJack F Vogel 	switch (link & IXGBE_PCI_LINK_SPEED) {
3598758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_SPEED_2500:
3599758cc3dcSJack F Vogel 		hw->bus.speed = ixgbe_bus_speed_2500;
3600758cc3dcSJack F Vogel 		break;
3601758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_SPEED_5000:
3602758cc3dcSJack F Vogel 		hw->bus.speed = ixgbe_bus_speed_5000;
3603758cc3dcSJack F Vogel 		break;
3604758cc3dcSJack F Vogel 	case IXGBE_PCI_LINK_SPEED_8000:
3605758cc3dcSJack F Vogel 		hw->bus.speed = ixgbe_bus_speed_8000;
3606758cc3dcSJack F Vogel 		break;
3607758cc3dcSJack F Vogel 	default:
3608758cc3dcSJack F Vogel 		hw->bus.speed = ixgbe_bus_speed_unknown;
3609758cc3dcSJack F Vogel 		break;
3610758cc3dcSJack F Vogel 	}
3611758cc3dcSJack F Vogel 
3612758cc3dcSJack F Vogel 	mac->ops.set_lan_id(hw);
3613758cc3dcSJack F Vogel 
3614758cc3dcSJack F Vogel display:
3615758cc3dcSJack F Vogel 	device_printf(dev,"PCI Express Bus: Speed %s %s\n",
3616758cc3dcSJack F Vogel 	    ((hw->bus.speed == ixgbe_bus_speed_8000) ? "8.0GT/s":
3617758cc3dcSJack F Vogel 	    (hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0GT/s":
3618758cc3dcSJack F Vogel 	    (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5GT/s":"Unknown"),
3619758cc3dcSJack F Vogel 	    (hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
3620758cc3dcSJack F Vogel 	    (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" :
3621758cc3dcSJack F Vogel 	    (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" :
3622758cc3dcSJack F Vogel 	    ("Unknown"));
3623758cc3dcSJack F Vogel 
3624758cc3dcSJack F Vogel 	if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) &&
3625758cc3dcSJack F Vogel 	    ((hw->bus.width <= ixgbe_bus_width_pcie_x4) &&
3626758cc3dcSJack F Vogel 	    (hw->bus.speed == ixgbe_bus_speed_2500))) {
3627758cc3dcSJack F Vogel 		device_printf(dev, "PCI-Express bandwidth available"
3628758cc3dcSJack F Vogel 		    " for this card\n     is not sufficient for"
3629758cc3dcSJack F Vogel 		    " optimal performance.\n");
3630758cc3dcSJack F Vogel 		device_printf(dev, "For optimal performance a x8 "
3631758cc3dcSJack F Vogel 		    "PCIE, or x4 PCIE Gen2 slot is required.\n");
3632758cc3dcSJack F Vogel         }
3633758cc3dcSJack F Vogel 	if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) &&
3634758cc3dcSJack F Vogel 	    ((hw->bus.width <= ixgbe_bus_width_pcie_x8) &&
3635758cc3dcSJack F Vogel 	    (hw->bus.speed < ixgbe_bus_speed_8000))) {
3636758cc3dcSJack F Vogel 		device_printf(dev, "PCI-Express bandwidth available"
3637758cc3dcSJack F Vogel 		    " for this card\n     is not sufficient for"
3638758cc3dcSJack F Vogel 		    " optimal performance.\n");
3639758cc3dcSJack F Vogel 		device_printf(dev, "For optimal performance a x8 "
3640758cc3dcSJack F Vogel 		    "PCIE Gen3 slot is required.\n");
3641758cc3dcSJack F Vogel         }
3642758cc3dcSJack F Vogel 
3643758cc3dcSJack F Vogel 	return;
3644758cc3dcSJack F Vogel }
3645758cc3dcSJack F Vogel 
3646758cc3dcSJack F Vogel 
3647758cc3dcSJack F Vogel /*
3648758cc3dcSJack F Vogel ** Setup the correct IVAR register for a particular MSIX interrupt
3649758cc3dcSJack F Vogel **   (yes this is all very magic and confusing :)
3650758cc3dcSJack F Vogel **  - entry is the register array entry
3651758cc3dcSJack F Vogel **  - vector is the MSIX vector for this queue
3652758cc3dcSJack F Vogel **  - type is RX/TX/MISC
3653758cc3dcSJack F Vogel */
3654758cc3dcSJack F Vogel static void
3655758cc3dcSJack F Vogel ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type)
3656758cc3dcSJack F Vogel {
3657758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
3658758cc3dcSJack F Vogel 	u32 ivar, index;
3659758cc3dcSJack F Vogel 
3660758cc3dcSJack F Vogel 	vector |= IXGBE_IVAR_ALLOC_VAL;
3661758cc3dcSJack F Vogel 
3662758cc3dcSJack F Vogel 	switch (hw->mac.type) {
3663758cc3dcSJack F Vogel 
3664758cc3dcSJack F Vogel 	case ixgbe_mac_82598EB:
3665758cc3dcSJack F Vogel 		if (type == -1)
3666758cc3dcSJack F Vogel 			entry = IXGBE_IVAR_OTHER_CAUSES_INDEX;
3667758cc3dcSJack F Vogel 		else
3668758cc3dcSJack F Vogel 			entry += (type * 64);
3669758cc3dcSJack F Vogel 		index = (entry >> 2) & 0x1F;
3670758cc3dcSJack F Vogel 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
3671758cc3dcSJack F Vogel 		ivar &= ~(0xFF << (8 * (entry & 0x3)));
3672758cc3dcSJack F Vogel 		ivar |= (vector << (8 * (entry & 0x3)));
3673758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar);
3674758cc3dcSJack F Vogel 		break;
3675758cc3dcSJack F Vogel 
3676758cc3dcSJack F Vogel 	case ixgbe_mac_82599EB:
3677758cc3dcSJack F Vogel 	case ixgbe_mac_X540:
3678758cc3dcSJack F Vogel 	case ixgbe_mac_X550:
3679758cc3dcSJack F Vogel 	case ixgbe_mac_X550EM_x:
3680758cc3dcSJack F Vogel 		if (type == -1) { /* MISC IVAR */
3681758cc3dcSJack F Vogel 			index = (entry & 1) * 8;
3682758cc3dcSJack F Vogel 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
3683758cc3dcSJack F Vogel 			ivar &= ~(0xFF << index);
3684758cc3dcSJack F Vogel 			ivar |= (vector << index);
3685758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
3686758cc3dcSJack F Vogel 		} else {	/* RX/TX IVARS */
3687758cc3dcSJack F Vogel 			index = (16 * (entry & 1)) + (8 * type);
3688758cc3dcSJack F Vogel 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1));
3689758cc3dcSJack F Vogel 			ivar &= ~(0xFF << index);
3690758cc3dcSJack F Vogel 			ivar |= (vector << index);
3691758cc3dcSJack F Vogel 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar);
3692758cc3dcSJack F Vogel 		}
3693758cc3dcSJack F Vogel 
3694758cc3dcSJack F Vogel 	default:
3695758cc3dcSJack F Vogel 		break;
3696758cc3dcSJack F Vogel 	}
3697758cc3dcSJack F Vogel }
3698758cc3dcSJack F Vogel 
3699758cc3dcSJack F Vogel static void
3700758cc3dcSJack F Vogel ixgbe_configure_ivars(struct adapter *adapter)
3701758cc3dcSJack F Vogel {
3702758cc3dcSJack F Vogel 	struct  ix_queue	*que = adapter->queues;
3703758cc3dcSJack F Vogel 	u32			newitr;
3704758cc3dcSJack F Vogel 
3705758cc3dcSJack F Vogel 	if (ixgbe_max_interrupt_rate > 0)
3706758cc3dcSJack F Vogel 		newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8;
37076f37f232SEric Joyner 	else {
37086f37f232SEric Joyner 		/*
37096f37f232SEric Joyner 		** Disable DMA coalescing if interrupt moderation is
37106f37f232SEric Joyner 		** disabled.
37116f37f232SEric Joyner 		*/
37126f37f232SEric Joyner 		adapter->dmac = 0;
3713758cc3dcSJack F Vogel 		newitr = 0;
37146f37f232SEric Joyner 	}
3715758cc3dcSJack F Vogel 
3716758cc3dcSJack F Vogel         for (int i = 0; i < adapter->num_queues; i++, que++) {
371748056c88SJack F Vogel 		struct rx_ring *rxr = &adapter->rx_rings[i];
371848056c88SJack F Vogel 		struct tx_ring *txr = &adapter->tx_rings[i];
3719758cc3dcSJack F Vogel 		/* First the RX queue entry */
372048056c88SJack F Vogel                 ixgbe_set_ivar(adapter, rxr->me, que->msix, 0);
3721758cc3dcSJack F Vogel 		/* ... and the TX */
372248056c88SJack F Vogel 		ixgbe_set_ivar(adapter, txr->me, que->msix, 1);
3723758cc3dcSJack F Vogel 		/* Set an Initial EITR value */
3724758cc3dcSJack F Vogel                 IXGBE_WRITE_REG(&adapter->hw,
3725758cc3dcSJack F Vogel                     IXGBE_EITR(que->msix), newitr);
3726758cc3dcSJack F Vogel 	}
3727758cc3dcSJack F Vogel 
3728758cc3dcSJack F Vogel 	/* For the Link interrupt */
3729758cc3dcSJack F Vogel         ixgbe_set_ivar(adapter, 1, adapter->vector, -1);
3730758cc3dcSJack F Vogel }
3731758cc3dcSJack F Vogel 
3732758cc3dcSJack F Vogel /*
3733758cc3dcSJack F Vogel ** ixgbe_sfp_probe - called in the local timer to
3734758cc3dcSJack F Vogel ** determine if a port had optics inserted.
3735758cc3dcSJack F Vogel */
373648056c88SJack F Vogel static bool
373748056c88SJack F Vogel ixgbe_sfp_probe(struct adapter *adapter)
3738758cc3dcSJack F Vogel {
3739758cc3dcSJack F Vogel 	struct ixgbe_hw	*hw = &adapter->hw;
3740758cc3dcSJack F Vogel 	device_t	dev = adapter->dev;
3741758cc3dcSJack F Vogel 	bool		result = FALSE;
3742758cc3dcSJack F Vogel 
3743758cc3dcSJack F Vogel 	if ((hw->phy.type == ixgbe_phy_nl) &&
3744758cc3dcSJack F Vogel 	    (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
3745758cc3dcSJack F Vogel 		s32 ret = hw->phy.ops.identify_sfp(hw);
3746758cc3dcSJack F Vogel 		if (ret)
3747758cc3dcSJack F Vogel                         goto out;
3748758cc3dcSJack F Vogel 		ret = hw->phy.ops.reset(hw);
3749758cc3dcSJack F Vogel 		if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
3750758cc3dcSJack F Vogel 			device_printf(dev, "Unsupported SFP+ module detected!");
3751a9ca1c79SSean Bruno 			device_printf(dev, "Reload driver with supported module.\n");
3752758cc3dcSJack F Vogel 			adapter->sfp_probe = FALSE;
3753758cc3dcSJack F Vogel                         goto out;
3754758cc3dcSJack F Vogel 		} else
3755758cc3dcSJack F Vogel 			device_printf(dev, "SFP+ module detected!\n");
3756758cc3dcSJack F Vogel 		/* We now have supported optics */
3757758cc3dcSJack F Vogel 		adapter->sfp_probe = FALSE;
3758758cc3dcSJack F Vogel 		/* Set the optics type so system reports correctly */
3759758cc3dcSJack F Vogel 		ixgbe_setup_optics(adapter);
3760758cc3dcSJack F Vogel 		result = TRUE;
3761758cc3dcSJack F Vogel 	}
3762758cc3dcSJack F Vogel out:
3763758cc3dcSJack F Vogel 	return (result);
3764758cc3dcSJack F Vogel }
3765758cc3dcSJack F Vogel 
3766758cc3dcSJack F Vogel /*
3767758cc3dcSJack F Vogel ** Tasklet handler for MSIX Link interrupts
3768758cc3dcSJack F Vogel **  - do outside interrupt since it might sleep
3769758cc3dcSJack F Vogel */
3770758cc3dcSJack F Vogel static void
3771758cc3dcSJack F Vogel ixgbe_handle_link(void *context, int pending)
3772758cc3dcSJack F Vogel {
3773758cc3dcSJack F Vogel 	struct adapter  *adapter = context;
3774a9ca1c79SSean Bruno 	struct ixgbe_hw *hw = &adapter->hw;
3775758cc3dcSJack F Vogel 
3776a9ca1c79SSean Bruno 	ixgbe_check_link(hw,
3777758cc3dcSJack F Vogel 	    &adapter->link_speed, &adapter->link_up, 0);
3778758cc3dcSJack F Vogel 	ixgbe_update_link_status(adapter);
3779a9ca1c79SSean Bruno 
3780a9ca1c79SSean Bruno 	/* Re-enable link interrupts */
3781a9ca1c79SSean Bruno 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_LSC);
3782758cc3dcSJack F Vogel }
3783758cc3dcSJack F Vogel 
3784758cc3dcSJack F Vogel /*
3785758cc3dcSJack F Vogel ** Tasklet for handling SFP module interrupts
3786758cc3dcSJack F Vogel */
3787758cc3dcSJack F Vogel static void
3788758cc3dcSJack F Vogel ixgbe_handle_mod(void *context, int pending)
3789758cc3dcSJack F Vogel {
3790758cc3dcSJack F Vogel 	struct adapter  *adapter = context;
3791758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
379297f9586eSSean Bruno 	enum ixgbe_phy_type orig_type = hw->phy.type;
3793758cc3dcSJack F Vogel 	device_t	dev = adapter->dev;
3794758cc3dcSJack F Vogel 	u32 err;
3795758cc3dcSJack F Vogel 
379697f9586eSSean Bruno 	IXGBE_CORE_LOCK(adapter);
379797f9586eSSean Bruno 
379897f9586eSSean Bruno 	/* Check to see if the PHY type changed */
379997f9586eSSean Bruno 	if (hw->phy.ops.identify) {
380097f9586eSSean Bruno 		hw->phy.type = ixgbe_phy_unknown;
380197f9586eSSean Bruno 		hw->phy.ops.identify(hw);
380297f9586eSSean Bruno 	}
380397f9586eSSean Bruno 
380497f9586eSSean Bruno 	if (hw->phy.type != orig_type) {
380597f9586eSSean Bruno 		device_printf(dev, "Detected phy_type %d\n", hw->phy.type);
380697f9586eSSean Bruno 
380797f9586eSSean Bruno 		if (hw->phy.type == ixgbe_phy_none) {
380897f9586eSSean Bruno 			hw->phy.sfp_type = ixgbe_sfp_type_unknown;
380997f9586eSSean Bruno 			goto out;
381097f9586eSSean Bruno 		}
381197f9586eSSean Bruno 
381297f9586eSSean Bruno 		/* Try to do the initialization that was skipped before */
381397f9586eSSean Bruno 		if (hw->phy.ops.init)
381497f9586eSSean Bruno 			hw->phy.ops.init(hw);
381597f9586eSSean Bruno 		if (hw->phy.ops.reset)
381697f9586eSSean Bruno 			hw->phy.ops.reset(hw);
381797f9586eSSean Bruno 	}
381897f9586eSSean Bruno 
3819758cc3dcSJack F Vogel 	err = hw->phy.ops.identify_sfp(hw);
3820758cc3dcSJack F Vogel 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
3821758cc3dcSJack F Vogel 		device_printf(dev,
3822758cc3dcSJack F Vogel 		    "Unsupported SFP+ module type was detected.\n");
382397f9586eSSean Bruno 		goto out;
3824758cc3dcSJack F Vogel 	}
382548056c88SJack F Vogel 
3826758cc3dcSJack F Vogel 	err = hw->mac.ops.setup_sfp(hw);
3827758cc3dcSJack F Vogel 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
3828758cc3dcSJack F Vogel 		device_printf(dev,
3829758cc3dcSJack F Vogel 		    "Setup failure - unsupported SFP+ module type.\n");
383097f9586eSSean Bruno 		goto out;
3831758cc3dcSJack F Vogel 	}
383297f9586eSSean Bruno 	if (hw->phy.multispeed_fiber)
3833758cc3dcSJack F Vogel 		taskqueue_enqueue(adapter->tq, &adapter->msf_task);
383497f9586eSSean Bruno out:
383597f9586eSSean Bruno 	/* Update media type */
383697f9586eSSean Bruno 	switch (hw->mac.ops.get_media_type(hw)) {
383797f9586eSSean Bruno 		case ixgbe_media_type_fiber:
383897f9586eSSean Bruno 			adapter->optics = IFM_10G_SR;
383997f9586eSSean Bruno 			break;
384097f9586eSSean Bruno 		case ixgbe_media_type_copper:
384197f9586eSSean Bruno 			adapter->optics = IFM_10G_TWINAX;
384297f9586eSSean Bruno 			break;
384397f9586eSSean Bruno 		case ixgbe_media_type_cx4:
384497f9586eSSean Bruno 			adapter->optics = IFM_10G_CX4;
384597f9586eSSean Bruno 			break;
384697f9586eSSean Bruno 		default:
384797f9586eSSean Bruno 			adapter->optics = 0;
384897f9586eSSean Bruno 			break;
384997f9586eSSean Bruno 	}
385097f9586eSSean Bruno 
385197f9586eSSean Bruno 	IXGBE_CORE_UNLOCK(adapter);
3852758cc3dcSJack F Vogel 	return;
3853758cc3dcSJack F Vogel }
3854758cc3dcSJack F Vogel 
3855758cc3dcSJack F Vogel 
3856758cc3dcSJack F Vogel /*
3857758cc3dcSJack F Vogel ** Tasklet for handling MSF (multispeed fiber) interrupts
3858758cc3dcSJack F Vogel */
3859758cc3dcSJack F Vogel static void
3860758cc3dcSJack F Vogel ixgbe_handle_msf(void *context, int pending)
3861758cc3dcSJack F Vogel {
3862758cc3dcSJack F Vogel 	struct adapter  *adapter = context;
3863758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
3864758cc3dcSJack F Vogel 	u32 autoneg;
3865758cc3dcSJack F Vogel 	bool negotiate;
3866758cc3dcSJack F Vogel 
386797f9586eSSean Bruno 	IXGBE_CORE_LOCK(adapter);
3868a9ca1c79SSean Bruno 	/* get_supported_phy_layer will call hw->phy.ops.identify_sfp() */
3869a9ca1c79SSean Bruno 	adapter->phy_layer = ixgbe_get_supported_physical_layer(hw);
3870758cc3dcSJack F Vogel 
3871758cc3dcSJack F Vogel 	autoneg = hw->phy.autoneg_advertised;
3872758cc3dcSJack F Vogel 	if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
3873758cc3dcSJack F Vogel 		hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate);
3874758cc3dcSJack F Vogel 	if (hw->mac.ops.setup_link)
3875758cc3dcSJack F Vogel 		hw->mac.ops.setup_link(hw, autoneg, TRUE);
3876758cc3dcSJack F Vogel 
3877a9ca1c79SSean Bruno 	/* Adjust media types shown in ifconfig */
3878758cc3dcSJack F Vogel 	ifmedia_removeall(&adapter->media);
3879758cc3dcSJack F Vogel 	ixgbe_add_media_types(adapter);
388097f9586eSSean Bruno 	IXGBE_CORE_UNLOCK(adapter);
3881758cc3dcSJack F Vogel 	return;
3882758cc3dcSJack F Vogel }
3883758cc3dcSJack F Vogel 
38846f37f232SEric Joyner /*
38856f37f232SEric Joyner ** Tasklet for handling interrupts from an external PHY
38866f37f232SEric Joyner */
38876f37f232SEric Joyner static void
38886f37f232SEric Joyner ixgbe_handle_phy(void *context, int pending)
38896f37f232SEric Joyner {
38906f37f232SEric Joyner 	struct adapter  *adapter = context;
38916f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
38926f37f232SEric Joyner 	int error;
38936f37f232SEric Joyner 
38946f37f232SEric Joyner 	error = hw->phy.ops.handle_lasi(hw);
38956f37f232SEric Joyner 	if (error == IXGBE_ERR_OVERTEMP)
38966f37f232SEric Joyner 		device_printf(adapter->dev,
38976f37f232SEric Joyner 		    "CRITICAL: EXTERNAL PHY OVER TEMP!! "
38986f37f232SEric Joyner 		    " PHY will downshift to lower power state!\n");
38996f37f232SEric Joyner 	else if (error)
39006f37f232SEric Joyner 		device_printf(adapter->dev,
39016f37f232SEric Joyner 		    "Error handling LASI interrupt: %d\n",
39026f37f232SEric Joyner 		    error);
39036f37f232SEric Joyner 	return;
39046f37f232SEric Joyner }
39056f37f232SEric Joyner 
3906758cc3dcSJack F Vogel #ifdef IXGBE_FDIR
3907758cc3dcSJack F Vogel /*
3908758cc3dcSJack F Vogel ** Tasklet for reinitializing the Flow Director filter table
3909758cc3dcSJack F Vogel */
3910758cc3dcSJack F Vogel static void
3911758cc3dcSJack F Vogel ixgbe_reinit_fdir(void *context, int pending)
3912758cc3dcSJack F Vogel {
3913758cc3dcSJack F Vogel 	struct adapter  *adapter = context;
3914758cc3dcSJack F Vogel 	struct ifnet   *ifp = adapter->ifp;
3915758cc3dcSJack F Vogel 
3916758cc3dcSJack F Vogel 	if (adapter->fdir_reinit != 1) /* Shouldn't happen */
3917758cc3dcSJack F Vogel 		return;
3918758cc3dcSJack F Vogel 	ixgbe_reinit_fdir_tables_82599(&adapter->hw);
3919758cc3dcSJack F Vogel 	adapter->fdir_reinit = 0;
3920758cc3dcSJack F Vogel 	/* re-enable flow director interrupts */
3921758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR);
3922758cc3dcSJack F Vogel 	/* Restart the interface */
3923758cc3dcSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
3924758cc3dcSJack F Vogel 	return;
3925758cc3dcSJack F Vogel }
3926758cc3dcSJack F Vogel #endif
3927758cc3dcSJack F Vogel 
39286f37f232SEric Joyner /*********************************************************************
39296f37f232SEric Joyner  *
39306f37f232SEric Joyner  *  Configure DMA Coalescing
39316f37f232SEric Joyner  *
39326f37f232SEric Joyner  **********************************************************************/
39336f37f232SEric Joyner static void
39346f37f232SEric Joyner ixgbe_config_dmac(struct adapter *adapter)
39356f37f232SEric Joyner {
39366f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
39376f37f232SEric Joyner 	struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config;
39386f37f232SEric Joyner 
39396f37f232SEric Joyner 	if (hw->mac.type < ixgbe_mac_X550 ||
39406f37f232SEric Joyner 	    !hw->mac.ops.dmac_config)
39416f37f232SEric Joyner 		return;
39426f37f232SEric Joyner 
39436f37f232SEric Joyner 	if (dcfg->watchdog_timer ^ adapter->dmac ||
39446f37f232SEric Joyner 	    dcfg->link_speed ^ adapter->link_speed) {
39456f37f232SEric Joyner 		dcfg->watchdog_timer = adapter->dmac;
39466f37f232SEric Joyner 		dcfg->fcoe_en = false;
39476f37f232SEric Joyner 		dcfg->link_speed = adapter->link_speed;
39486f37f232SEric Joyner 		dcfg->num_tcs = 1;
39496f37f232SEric Joyner 
39506f37f232SEric Joyner 		INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n",
39516f37f232SEric Joyner 		    dcfg->watchdog_timer, dcfg->link_speed);
39526f37f232SEric Joyner 
39536f37f232SEric Joyner 		hw->mac.ops.dmac_config(hw);
39546f37f232SEric Joyner 	}
39556f37f232SEric Joyner }
39566f37f232SEric Joyner 
39576f37f232SEric Joyner /*
39586f37f232SEric Joyner  * Checks whether the adapter's ports are capable of
39596f37f232SEric Joyner  * Wake On LAN by reading the adapter's NVM.
39606f37f232SEric Joyner  *
39616f37f232SEric Joyner  * Sets each port's hw->wol_enabled value depending
39626f37f232SEric Joyner  * on the value read here.
39636f37f232SEric Joyner  */
39646f37f232SEric Joyner static void
39656f37f232SEric Joyner ixgbe_check_wol_support(struct adapter *adapter)
39666f37f232SEric Joyner {
39676f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
39686f37f232SEric Joyner 	u16 dev_caps = 0;
39696f37f232SEric Joyner 
39706f37f232SEric Joyner 	/* Find out WoL support for port */
39716f37f232SEric Joyner 	adapter->wol_support = hw->wol_enabled = 0;
39726f37f232SEric Joyner 	ixgbe_get_device_caps(hw, &dev_caps);
39736f37f232SEric Joyner 	if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
39746f37f232SEric Joyner 	    ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) &&
39756f37f232SEric Joyner 	      hw->bus.func == 0))
39766f37f232SEric Joyner 		adapter->wol_support = hw->wol_enabled = 1;
39776f37f232SEric Joyner 
39786f37f232SEric Joyner 	/* Save initial wake up filter configuration */
39796f37f232SEric Joyner 	adapter->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC);
39806f37f232SEric Joyner 
39816f37f232SEric Joyner 	return;
39826f37f232SEric Joyner }
39836f37f232SEric Joyner 
39846f37f232SEric Joyner /*
39856f37f232SEric Joyner  * Prepare the adapter/port for LPLU and/or WoL
39866f37f232SEric Joyner  */
39876f37f232SEric Joyner static int
39886f37f232SEric Joyner ixgbe_setup_low_power_mode(struct adapter *adapter)
39896f37f232SEric Joyner {
39906f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
39916f37f232SEric Joyner 	device_t dev = adapter->dev;
39926f37f232SEric Joyner 	s32 error = 0;
39936f37f232SEric Joyner 
39946f37f232SEric Joyner 	mtx_assert(&adapter->core_mtx, MA_OWNED);
39956f37f232SEric Joyner 
39961ebf555bSSteven Hartland 	if (!hw->wol_enabled)
39971ebf555bSSteven Hartland 		ixgbe_set_phy_power(hw, FALSE);
39981ebf555bSSteven Hartland 
39996f37f232SEric Joyner 	/* Limit power management flow to X550EM baseT */
40006f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T
40016f37f232SEric Joyner 	    && hw->phy.ops.enter_lplu) {
40026f37f232SEric Joyner 		/* Turn off support for APM wakeup. (Using ACPI instead) */
40036f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_GRC,
40046f37f232SEric Joyner 		    IXGBE_READ_REG(hw, IXGBE_GRC) & ~(u32)2);
40056f37f232SEric Joyner 
40066f37f232SEric Joyner 		/*
40076f37f232SEric Joyner 		 * Clear Wake Up Status register to prevent any previous wakeup
40086f37f232SEric Joyner 		 * events from waking us up immediately after we suspend.
40096f37f232SEric Joyner 		 */
40106f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
40116f37f232SEric Joyner 
40126f37f232SEric Joyner 		/*
40136f37f232SEric Joyner 		 * Program the Wakeup Filter Control register with user filter
40146f37f232SEric Joyner 		 * settings
40156f37f232SEric Joyner 		 */
40166f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_WUFC, adapter->wufc);
40176f37f232SEric Joyner 
40186f37f232SEric Joyner 		/* Enable wakeups and power management in Wakeup Control */
40196f37f232SEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_WUC,
40206f37f232SEric Joyner 		    IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN);
40216f37f232SEric Joyner 
40226f37f232SEric Joyner 		/* X550EM baseT adapters need a special LPLU flow */
40236f37f232SEric Joyner 		hw->phy.reset_disable = true;
40246f37f232SEric Joyner 		ixgbe_stop(adapter);
40256f37f232SEric Joyner 		error = hw->phy.ops.enter_lplu(hw);
40266f37f232SEric Joyner 		if (error)
40276f37f232SEric Joyner 			device_printf(dev,
40286f37f232SEric Joyner 			    "Error entering LPLU: %d\n", error);
40296f37f232SEric Joyner 		hw->phy.reset_disable = false;
40306f37f232SEric Joyner 	} else {
40316f37f232SEric Joyner 		/* Just stop for other adapters */
40326f37f232SEric Joyner 		ixgbe_stop(adapter);
40336f37f232SEric Joyner 	}
40346f37f232SEric Joyner 
40356f37f232SEric Joyner 	return error;
40366f37f232SEric Joyner }
40376f37f232SEric Joyner 
4038758cc3dcSJack F Vogel /**********************************************************************
4039758cc3dcSJack F Vogel  *
4040758cc3dcSJack F Vogel  *  Update the board statistics counters.
4041758cc3dcSJack F Vogel  *
4042758cc3dcSJack F Vogel  **********************************************************************/
4043758cc3dcSJack F Vogel static void
4044758cc3dcSJack F Vogel ixgbe_update_stats_counters(struct adapter *adapter)
4045758cc3dcSJack F Vogel {
4046758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
4047758cc3dcSJack F Vogel 	u32 missed_rx = 0, bprc, lxon, lxoff, total;
4048758cc3dcSJack F Vogel 	u64 total_missed_rx = 0;
4049758cc3dcSJack F Vogel 
4050758cc3dcSJack F Vogel 	adapter->stats.pf.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
4051758cc3dcSJack F Vogel 	adapter->stats.pf.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC);
4052758cc3dcSJack F Vogel 	adapter->stats.pf.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC);
4053758cc3dcSJack F Vogel 	adapter->stats.pf.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC);
4054758cc3dcSJack F Vogel 
4055758cc3dcSJack F Vogel 	for (int i = 0; i < 16; i++) {
4056758cc3dcSJack F Vogel 		adapter->stats.pf.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
4057758cc3dcSJack F Vogel 		adapter->stats.pf.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
4058758cc3dcSJack F Vogel 		adapter->stats.pf.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
4059758cc3dcSJack F Vogel 	}
4060758cc3dcSJack F Vogel 	adapter->stats.pf.mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC);
4061758cc3dcSJack F Vogel 	adapter->stats.pf.mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC);
4062758cc3dcSJack F Vogel 	adapter->stats.pf.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
4063758cc3dcSJack F Vogel 
4064758cc3dcSJack F Vogel 	/* Hardware workaround, gprc counts missed packets */
4065758cc3dcSJack F Vogel 	adapter->stats.pf.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
4066758cc3dcSJack F Vogel 	adapter->stats.pf.gprc -= missed_rx;
4067758cc3dcSJack F Vogel 
4068758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
4069758cc3dcSJack F Vogel 		adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) +
4070758cc3dcSJack F Vogel 		    ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32);
4071758cc3dcSJack F Vogel 		adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) +
4072758cc3dcSJack F Vogel 		    ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32);
4073758cc3dcSJack F Vogel 		adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORL) +
4074758cc3dcSJack F Vogel 		    ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32);
4075758cc3dcSJack F Vogel 		adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
4076758cc3dcSJack F Vogel 		adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
4077758cc3dcSJack F Vogel 	} else {
4078758cc3dcSJack F Vogel 		adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
4079758cc3dcSJack F Vogel 		adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
4080758cc3dcSJack F Vogel 		/* 82598 only has a counter in the high register */
4081758cc3dcSJack F Vogel 		adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
4082758cc3dcSJack F Vogel 		adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
4083758cc3dcSJack F Vogel 		adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
4084758cc3dcSJack F Vogel 	}
4085758cc3dcSJack F Vogel 
4086758cc3dcSJack F Vogel 	/*
4087758cc3dcSJack F Vogel 	 * Workaround: mprc hardware is incorrectly counting
4088758cc3dcSJack F Vogel 	 * broadcasts, so for now we subtract those.
4089758cc3dcSJack F Vogel 	 */
4090758cc3dcSJack F Vogel 	bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
4091758cc3dcSJack F Vogel 	adapter->stats.pf.bprc += bprc;
4092758cc3dcSJack F Vogel 	adapter->stats.pf.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
4093758cc3dcSJack F Vogel 	if (hw->mac.type == ixgbe_mac_82598EB)
4094758cc3dcSJack F Vogel 		adapter->stats.pf.mprc -= bprc;
4095758cc3dcSJack F Vogel 
4096758cc3dcSJack F Vogel 	adapter->stats.pf.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
4097758cc3dcSJack F Vogel 	adapter->stats.pf.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
4098758cc3dcSJack F Vogel 	adapter->stats.pf.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255);
4099758cc3dcSJack F Vogel 	adapter->stats.pf.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
4100758cc3dcSJack F Vogel 	adapter->stats.pf.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
4101758cc3dcSJack F Vogel 	adapter->stats.pf.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
4102758cc3dcSJack F Vogel 
4103758cc3dcSJack F Vogel 	lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC);
4104758cc3dcSJack F Vogel 	adapter->stats.pf.lxontxc += lxon;
4105758cc3dcSJack F Vogel 	lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
4106758cc3dcSJack F Vogel 	adapter->stats.pf.lxofftxc += lxoff;
4107758cc3dcSJack F Vogel 	total = lxon + lxoff;
4108758cc3dcSJack F Vogel 
4109758cc3dcSJack F Vogel 	adapter->stats.pf.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
4110758cc3dcSJack F Vogel 	adapter->stats.pf.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
4111758cc3dcSJack F Vogel 	adapter->stats.pf.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
4112758cc3dcSJack F Vogel 	adapter->stats.pf.gptc -= total;
4113758cc3dcSJack F Vogel 	adapter->stats.pf.mptc -= total;
4114758cc3dcSJack F Vogel 	adapter->stats.pf.ptc64 -= total;
4115758cc3dcSJack F Vogel 	adapter->stats.pf.gotc -= total * ETHER_MIN_LEN;
4116758cc3dcSJack F Vogel 
4117758cc3dcSJack F Vogel 	adapter->stats.pf.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
4118758cc3dcSJack F Vogel 	adapter->stats.pf.rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
4119758cc3dcSJack F Vogel 	adapter->stats.pf.roc += IXGBE_READ_REG(hw, IXGBE_ROC);
4120758cc3dcSJack F Vogel 	adapter->stats.pf.rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
4121758cc3dcSJack F Vogel 	adapter->stats.pf.mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC);
4122758cc3dcSJack F Vogel 	adapter->stats.pf.mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC);
4123758cc3dcSJack F Vogel 	adapter->stats.pf.mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC);
4124758cc3dcSJack F Vogel 	adapter->stats.pf.tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
4125758cc3dcSJack F Vogel 	adapter->stats.pf.tpt += IXGBE_READ_REG(hw, IXGBE_TPT);
4126758cc3dcSJack F Vogel 	adapter->stats.pf.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
4127758cc3dcSJack F Vogel 	adapter->stats.pf.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
4128758cc3dcSJack F Vogel 	adapter->stats.pf.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
4129758cc3dcSJack F Vogel 	adapter->stats.pf.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
4130758cc3dcSJack F Vogel 	adapter->stats.pf.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
4131758cc3dcSJack F Vogel 	adapter->stats.pf.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
4132758cc3dcSJack F Vogel 	adapter->stats.pf.xec += IXGBE_READ_REG(hw, IXGBE_XEC);
4133758cc3dcSJack F Vogel 	adapter->stats.pf.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC);
4134758cc3dcSJack F Vogel 	adapter->stats.pf.fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST);
4135758cc3dcSJack F Vogel 	/* Only read FCOE on 82599 */
4136758cc3dcSJack F Vogel 	if (hw->mac.type != ixgbe_mac_82598EB) {
4137758cc3dcSJack F Vogel 		adapter->stats.pf.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC);
4138758cc3dcSJack F Vogel 		adapter->stats.pf.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC);
4139758cc3dcSJack F Vogel 		adapter->stats.pf.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC);
4140758cc3dcSJack F Vogel 		adapter->stats.pf.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC);
4141758cc3dcSJack F Vogel 		adapter->stats.pf.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC);
4142758cc3dcSJack F Vogel 	}
4143758cc3dcSJack F Vogel 
4144758cc3dcSJack F Vogel 	/* Fill out the OS statistics structure */
4145758cc3dcSJack F Vogel 	IXGBE_SET_IPACKETS(adapter, adapter->stats.pf.gprc);
4146758cc3dcSJack F Vogel 	IXGBE_SET_OPACKETS(adapter, adapter->stats.pf.gptc);
4147758cc3dcSJack F Vogel 	IXGBE_SET_IBYTES(adapter, adapter->stats.pf.gorc);
4148758cc3dcSJack F Vogel 	IXGBE_SET_OBYTES(adapter, adapter->stats.pf.gotc);
4149758cc3dcSJack F Vogel 	IXGBE_SET_IMCASTS(adapter, adapter->stats.pf.mprc);
4150758cc3dcSJack F Vogel 	IXGBE_SET_OMCASTS(adapter, adapter->stats.pf.mptc);
4151758cc3dcSJack F Vogel 	IXGBE_SET_COLLISIONS(adapter, 0);
4152758cc3dcSJack F Vogel 	IXGBE_SET_IQDROPS(adapter, total_missed_rx);
4153758cc3dcSJack F Vogel 	IXGBE_SET_IERRORS(adapter, adapter->stats.pf.crcerrs
4154758cc3dcSJack F Vogel 	    + adapter->stats.pf.rlec);
4155758cc3dcSJack F Vogel }
4156758cc3dcSJack F Vogel 
4157758cc3dcSJack F Vogel #if __FreeBSD_version >= 1100036
4158758cc3dcSJack F Vogel static uint64_t
4159758cc3dcSJack F Vogel ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt)
4160758cc3dcSJack F Vogel {
4161758cc3dcSJack F Vogel 	struct adapter *adapter;
4162625d12c6SJohn Baldwin 	struct tx_ring *txr;
4163625d12c6SJohn Baldwin 	uint64_t rv;
4164758cc3dcSJack F Vogel 
4165758cc3dcSJack F Vogel 	adapter = if_getsoftc(ifp);
4166758cc3dcSJack F Vogel 
4167758cc3dcSJack F Vogel 	switch (cnt) {
4168758cc3dcSJack F Vogel 	case IFCOUNTER_IPACKETS:
4169758cc3dcSJack F Vogel 		return (adapter->ipackets);
4170758cc3dcSJack F Vogel 	case IFCOUNTER_OPACKETS:
4171758cc3dcSJack F Vogel 		return (adapter->opackets);
4172758cc3dcSJack F Vogel 	case IFCOUNTER_IBYTES:
4173758cc3dcSJack F Vogel 		return (adapter->ibytes);
4174758cc3dcSJack F Vogel 	case IFCOUNTER_OBYTES:
4175758cc3dcSJack F Vogel 		return (adapter->obytes);
4176758cc3dcSJack F Vogel 	case IFCOUNTER_IMCASTS:
4177758cc3dcSJack F Vogel 		return (adapter->imcasts);
4178758cc3dcSJack F Vogel 	case IFCOUNTER_OMCASTS:
4179758cc3dcSJack F Vogel 		return (adapter->omcasts);
4180758cc3dcSJack F Vogel 	case IFCOUNTER_COLLISIONS:
4181758cc3dcSJack F Vogel 		return (0);
4182758cc3dcSJack F Vogel 	case IFCOUNTER_IQDROPS:
4183758cc3dcSJack F Vogel 		return (adapter->iqdrops);
4184625d12c6SJohn Baldwin 	case IFCOUNTER_OQDROPS:
4185625d12c6SJohn Baldwin 		rv = 0;
4186625d12c6SJohn Baldwin 		txr = adapter->tx_rings;
4187625d12c6SJohn Baldwin 		for (int i = 0; i < adapter->num_queues; i++, txr++)
4188625d12c6SJohn Baldwin 			rv += txr->br->br_drops;
4189625d12c6SJohn Baldwin 		return (rv);
4190758cc3dcSJack F Vogel 	case IFCOUNTER_IERRORS:
4191758cc3dcSJack F Vogel 		return (adapter->ierrors);
4192758cc3dcSJack F Vogel 	default:
4193758cc3dcSJack F Vogel 		return (if_get_counter_default(ifp, cnt));
4194758cc3dcSJack F Vogel 	}
4195758cc3dcSJack F Vogel }
4196758cc3dcSJack F Vogel #endif
4197758cc3dcSJack F Vogel 
4198758cc3dcSJack F Vogel /** ixgbe_sysctl_tdh_handler - Handler function
4199758cc3dcSJack F Vogel  *  Retrieves the TDH value from the hardware
4200758cc3dcSJack F Vogel  */
4201758cc3dcSJack F Vogel static int
4202758cc3dcSJack F Vogel ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS)
4203758cc3dcSJack F Vogel {
4204758cc3dcSJack F Vogel 	int error;
4205758cc3dcSJack F Vogel 
4206758cc3dcSJack F Vogel 	struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1);
4207758cc3dcSJack F Vogel 	if (!txr) return 0;
4208758cc3dcSJack F Vogel 
4209758cc3dcSJack F Vogel 	unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me));
4210758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
4211758cc3dcSJack F Vogel 	if (error || !req->newptr)
4212758cc3dcSJack F Vogel 		return error;
4213758cc3dcSJack F Vogel 	return 0;
4214758cc3dcSJack F Vogel }
4215758cc3dcSJack F Vogel 
4216758cc3dcSJack F Vogel /** ixgbe_sysctl_tdt_handler - Handler function
4217758cc3dcSJack F Vogel  *  Retrieves the TDT value from the hardware
4218758cc3dcSJack F Vogel  */
4219758cc3dcSJack F Vogel static int
4220758cc3dcSJack F Vogel ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS)
4221758cc3dcSJack F Vogel {
4222758cc3dcSJack F Vogel 	int error;
4223758cc3dcSJack F Vogel 
4224758cc3dcSJack F Vogel 	struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1);
4225758cc3dcSJack F Vogel 	if (!txr) return 0;
4226758cc3dcSJack F Vogel 
4227758cc3dcSJack F Vogel 	unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me));
4228758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
4229758cc3dcSJack F Vogel 	if (error || !req->newptr)
4230758cc3dcSJack F Vogel 		return error;
4231758cc3dcSJack F Vogel 	return 0;
4232758cc3dcSJack F Vogel }
4233758cc3dcSJack F Vogel 
4234758cc3dcSJack F Vogel /** ixgbe_sysctl_rdh_handler - Handler function
4235758cc3dcSJack F Vogel  *  Retrieves the RDH value from the hardware
4236758cc3dcSJack F Vogel  */
4237758cc3dcSJack F Vogel static int
4238758cc3dcSJack F Vogel ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS)
4239758cc3dcSJack F Vogel {
4240758cc3dcSJack F Vogel 	int error;
4241758cc3dcSJack F Vogel 
4242758cc3dcSJack F Vogel 	struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1);
4243758cc3dcSJack F Vogel 	if (!rxr) return 0;
4244758cc3dcSJack F Vogel 
4245758cc3dcSJack F Vogel 	unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me));
4246758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
4247758cc3dcSJack F Vogel 	if (error || !req->newptr)
4248758cc3dcSJack F Vogel 		return error;
4249758cc3dcSJack F Vogel 	return 0;
4250758cc3dcSJack F Vogel }
4251758cc3dcSJack F Vogel 
4252758cc3dcSJack F Vogel /** ixgbe_sysctl_rdt_handler - Handler function
4253758cc3dcSJack F Vogel  *  Retrieves the RDT value from the hardware
4254758cc3dcSJack F Vogel  */
4255758cc3dcSJack F Vogel static int
4256758cc3dcSJack F Vogel ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS)
4257758cc3dcSJack F Vogel {
4258758cc3dcSJack F Vogel 	int error;
4259758cc3dcSJack F Vogel 
4260758cc3dcSJack F Vogel 	struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1);
4261758cc3dcSJack F Vogel 	if (!rxr) return 0;
4262758cc3dcSJack F Vogel 
4263758cc3dcSJack F Vogel 	unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me));
4264758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &val, 0, req);
4265758cc3dcSJack F Vogel 	if (error || !req->newptr)
4266758cc3dcSJack F Vogel 		return error;
4267758cc3dcSJack F Vogel 	return 0;
4268758cc3dcSJack F Vogel }
4269758cc3dcSJack F Vogel 
4270758cc3dcSJack F Vogel static int
4271758cc3dcSJack F Vogel ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
4272758cc3dcSJack F Vogel {
4273758cc3dcSJack F Vogel 	int error;
4274758cc3dcSJack F Vogel 	struct ix_queue *que = ((struct ix_queue *)oidp->oid_arg1);
4275758cc3dcSJack F Vogel 	unsigned int reg, usec, rate;
4276758cc3dcSJack F Vogel 
4277758cc3dcSJack F Vogel 	reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix));
4278758cc3dcSJack F Vogel 	usec = ((reg & 0x0FF8) >> 3);
4279758cc3dcSJack F Vogel 	if (usec > 0)
4280758cc3dcSJack F Vogel 		rate = 500000 / usec;
4281758cc3dcSJack F Vogel 	else
4282758cc3dcSJack F Vogel 		rate = 0;
4283758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &rate, 0, req);
4284758cc3dcSJack F Vogel 	if (error || !req->newptr)
4285758cc3dcSJack F Vogel 		return error;
4286758cc3dcSJack F Vogel 	reg &= ~0xfff; /* default, no limitation */
4287758cc3dcSJack F Vogel 	ixgbe_max_interrupt_rate = 0;
4288758cc3dcSJack F Vogel 	if (rate > 0 && rate < 500000) {
4289758cc3dcSJack F Vogel 		if (rate < 1000)
4290758cc3dcSJack F Vogel 			rate = 1000;
4291758cc3dcSJack F Vogel 		ixgbe_max_interrupt_rate = rate;
4292758cc3dcSJack F Vogel 		reg |= ((4000000/rate) & 0xff8 );
4293758cc3dcSJack F Vogel 	}
4294758cc3dcSJack F Vogel 	IXGBE_WRITE_REG(&que->adapter->hw, IXGBE_EITR(que->msix), reg);
4295758cc3dcSJack F Vogel 	return 0;
4296758cc3dcSJack F Vogel }
4297758cc3dcSJack F Vogel 
42986f37f232SEric Joyner static void
42996f37f232SEric Joyner ixgbe_add_device_sysctls(struct adapter *adapter)
43006f37f232SEric Joyner {
43016f37f232SEric Joyner 	device_t dev = adapter->dev;
43026f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
43036f37f232SEric Joyner 	struct sysctl_oid_list *child;
43046f37f232SEric Joyner 	struct sysctl_ctx_list *ctx;
43056f37f232SEric Joyner 
43066f37f232SEric Joyner 	ctx = device_get_sysctl_ctx(dev);
43076f37f232SEric Joyner 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
43086f37f232SEric Joyner 
43096f37f232SEric Joyner 	/* Sysctls for all devices */
43106f37f232SEric Joyner 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fc",
43116f37f232SEric Joyner 			CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
4312f2c4db54SSteven Hartland 			ixgbe_sysctl_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC);
43136f37f232SEric Joyner 
43146f37f232SEric Joyner         SYSCTL_ADD_INT(ctx, child, OID_AUTO, "enable_aim",
43156f37f232SEric Joyner 			CTLFLAG_RW,
43166f37f232SEric Joyner 			&ixgbe_enable_aim, 1, "Interrupt Moderation");
43176f37f232SEric Joyner 
43186f37f232SEric Joyner 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "advertise_speed",
43196f37f232SEric Joyner 			CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
4320f2c4db54SSteven Hartland 			ixgbe_sysctl_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED);
43216f37f232SEric Joyner 
43226f37f232SEric Joyner 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "thermal_test",
43236f37f232SEric Joyner 			CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
43246f37f232SEric Joyner 			ixgbe_sysctl_thermal_test, "I", "Thermal Test");
43256f37f232SEric Joyner 
4326a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
4327a9ca1c79SSean Bruno 	/* testing sysctls (for all devices) */
4328a9ca1c79SSean Bruno 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "power_state",
4329a9ca1c79SSean Bruno 			CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
4330a9ca1c79SSean Bruno 			ixgbe_sysctl_power_state, "I", "PCI Power State");
4331a9ca1c79SSean Bruno 
4332a9ca1c79SSean Bruno 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config",
4333a9ca1c79SSean Bruno 			CTLTYPE_STRING | CTLFLAG_RD, adapter, 0,
4334a9ca1c79SSean Bruno 			ixgbe_sysctl_print_rss_config, "A", "Prints RSS Configuration");
4335a9ca1c79SSean Bruno #endif
4336a9ca1c79SSean Bruno 	/* for X550 series devices */
43376f37f232SEric Joyner 	if (hw->mac.type >= ixgbe_mac_X550)
43386f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac",
43396f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
43406f37f232SEric Joyner 				ixgbe_sysctl_dmac, "I", "DMA Coalesce");
43416f37f232SEric Joyner 
4342a9ca1c79SSean Bruno 	/* for X552 backplane devices */
4343a9ca1c79SSean Bruno 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) {
43446f37f232SEric Joyner 		struct sysctl_oid *eee_node;
43456f37f232SEric Joyner 		struct sysctl_oid_list *eee_list;
43466f37f232SEric Joyner 
43476f37f232SEric Joyner 		eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee",
43486f37f232SEric Joyner 					   CTLFLAG_RD, NULL,
43496f37f232SEric Joyner 					   "Energy Efficient Ethernet sysctls");
43506f37f232SEric Joyner 		eee_list = SYSCTL_CHILDREN(eee_node);
43516f37f232SEric Joyner 
43526f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "enable",
43536f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
43546f37f232SEric Joyner 				ixgbe_sysctl_eee_enable, "I",
43556f37f232SEric Joyner 				"Enable or Disable EEE");
43566f37f232SEric Joyner 
43576f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "negotiated",
43586f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
43596f37f232SEric Joyner 				ixgbe_sysctl_eee_negotiated, "I",
43606f37f232SEric Joyner 				"EEE negotiated on link");
43616f37f232SEric Joyner 
43626f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_status",
43636f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
43646f37f232SEric Joyner 				ixgbe_sysctl_eee_tx_lpi_status, "I",
43656f37f232SEric Joyner 				"Whether or not TX link is in LPI state");
43666f37f232SEric Joyner 
43676f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "rx_lpi_status",
43686f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
43696f37f232SEric Joyner 				ixgbe_sysctl_eee_rx_lpi_status, "I",
43706f37f232SEric Joyner 				"Whether or not RX link is in LPI state");
4371a9ca1c79SSean Bruno 
4372a9ca1c79SSean Bruno 		SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_delay",
4373a9ca1c79SSean Bruno 				CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
4374a9ca1c79SSean Bruno 				ixgbe_sysctl_eee_tx_lpi_delay, "I",
4375a9ca1c79SSean Bruno 				"TX LPI entry delay in microseconds");
43766f37f232SEric Joyner 	}
43776f37f232SEric Joyner 
4378a9ca1c79SSean Bruno 	/* for WoL-capable devices */
4379a9ca1c79SSean Bruno 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
43806f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wol_enable",
43816f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
43826f37f232SEric Joyner 				ixgbe_sysctl_wol_enable, "I",
43836f37f232SEric Joyner 				"Enable/Disable Wake on LAN");
43846f37f232SEric Joyner 
43856f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wufc",
43866f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
43876f37f232SEric Joyner 				ixgbe_sysctl_wufc, "I",
43886f37f232SEric Joyner 				"Enable/Disable Wake Up Filters");
43896f37f232SEric Joyner 	}
43906f37f232SEric Joyner 
4391a9ca1c79SSean Bruno 	/* for X552/X557-AT devices */
43926f37f232SEric Joyner 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
43936f37f232SEric Joyner 		struct sysctl_oid *phy_node;
43946f37f232SEric Joyner 		struct sysctl_oid_list *phy_list;
43956f37f232SEric Joyner 
43966f37f232SEric Joyner 		phy_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "phy",
43976f37f232SEric Joyner 					   CTLFLAG_RD, NULL,
43986f37f232SEric Joyner 					   "External PHY sysctls");
43996f37f232SEric Joyner 		phy_list = SYSCTL_CHILDREN(phy_node);
44006f37f232SEric Joyner 
44016f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "temp",
44026f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
44036f37f232SEric Joyner 				ixgbe_sysctl_phy_temp, "I",
44046f37f232SEric Joyner 				"Current External PHY Temperature (Celsius)");
44056f37f232SEric Joyner 
44066f37f232SEric Joyner 		SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "overtemp_occurred",
44076f37f232SEric Joyner 				CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
44086f37f232SEric Joyner 				ixgbe_sysctl_phy_overtemp_occurred, "I",
44096f37f232SEric Joyner 				"External PHY High Temperature Event Occurred");
44106f37f232SEric Joyner 	}
44116f37f232SEric Joyner }
44126f37f232SEric Joyner 
4413758cc3dcSJack F Vogel /*
4414758cc3dcSJack F Vogel  * Add sysctl variables, one per statistic, to the system.
4415758cc3dcSJack F Vogel  */
4416758cc3dcSJack F Vogel static void
4417758cc3dcSJack F Vogel ixgbe_add_hw_stats(struct adapter *adapter)
4418758cc3dcSJack F Vogel {
4419758cc3dcSJack F Vogel 	device_t dev = adapter->dev;
4420758cc3dcSJack F Vogel 
4421758cc3dcSJack F Vogel 	struct tx_ring *txr = adapter->tx_rings;
4422758cc3dcSJack F Vogel 	struct rx_ring *rxr = adapter->rx_rings;
4423758cc3dcSJack F Vogel 
4424758cc3dcSJack F Vogel 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
4425758cc3dcSJack F Vogel 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
4426758cc3dcSJack F Vogel 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
4427758cc3dcSJack F Vogel 	struct ixgbe_hw_stats *stats = &adapter->stats.pf;
4428758cc3dcSJack F Vogel 
4429758cc3dcSJack F Vogel 	struct sysctl_oid *stat_node, *queue_node;
4430758cc3dcSJack F Vogel 	struct sysctl_oid_list *stat_list, *queue_list;
4431758cc3dcSJack F Vogel 
4432758cc3dcSJack F Vogel #define QUEUE_NAME_LEN 32
4433758cc3dcSJack F Vogel 	char namebuf[QUEUE_NAME_LEN];
4434758cc3dcSJack F Vogel 
4435758cc3dcSJack F Vogel 	/* Driver Statistics */
4436758cc3dcSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped",
4437758cc3dcSJack F Vogel 			CTLFLAG_RD, &adapter->dropped_pkts,
4438758cc3dcSJack F Vogel 			"Driver dropped packets");
4439758cc3dcSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed",
4440758cc3dcSJack F Vogel 			CTLFLAG_RD, &adapter->mbuf_defrag_failed,
4441758cc3dcSJack F Vogel 			"m_defrag() failed");
4442758cc3dcSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
4443758cc3dcSJack F Vogel 			CTLFLAG_RD, &adapter->watchdog_events,
4444758cc3dcSJack F Vogel 			"Watchdog timeouts");
4445758cc3dcSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq",
44466f37f232SEric Joyner 			CTLFLAG_RD, &adapter->link_irq,
4447758cc3dcSJack F Vogel 			"Link MSIX IRQ Handled");
4448758cc3dcSJack F Vogel 
4449758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, txr++) {
4450758cc3dcSJack F Vogel 		snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i);
4451758cc3dcSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
4452758cc3dcSJack F Vogel 					    CTLFLAG_RD, NULL, "Queue Name");
4453758cc3dcSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
4454758cc3dcSJack F Vogel 
4455758cc3dcSJack F Vogel 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate",
4456758cc3dcSJack F Vogel 				CTLTYPE_UINT | CTLFLAG_RW, &adapter->queues[i],
4457758cc3dcSJack F Vogel 				sizeof(&adapter->queues[i]),
4458758cc3dcSJack F Vogel 				ixgbe_sysctl_interrupt_rate_handler, "IU",
4459758cc3dcSJack F Vogel 				"Interrupt Rate");
4460758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
4461758cc3dcSJack F Vogel 				CTLFLAG_RD, &(adapter->queues[i].irqs),
4462758cc3dcSJack F Vogel 				"irqs on this queue");
4463758cc3dcSJack F Vogel 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head",
4464758cc3dcSJack F Vogel 				CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr),
4465758cc3dcSJack F Vogel 				ixgbe_sysctl_tdh_handler, "IU",
4466758cc3dcSJack F Vogel 				"Transmit Descriptor Head");
4467758cc3dcSJack F Vogel 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail",
4468758cc3dcSJack F Vogel 				CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr),
4469758cc3dcSJack F Vogel 				ixgbe_sysctl_tdt_handler, "IU",
4470758cc3dcSJack F Vogel 				"Transmit Descriptor Tail");
4471758cc3dcSJack F Vogel 		SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx",
4472758cc3dcSJack F Vogel 				CTLFLAG_RD, &txr->tso_tx,
4473758cc3dcSJack F Vogel 				"TSO");
4474758cc3dcSJack F Vogel 		SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_tx_dma_setup",
4475758cc3dcSJack F Vogel 				CTLFLAG_RD, &txr->no_tx_dma_setup,
4476758cc3dcSJack F Vogel 				"Driver tx dma failure in xmit");
4477758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
4478758cc3dcSJack F Vogel 				CTLFLAG_RD, &txr->no_desc_avail,
4479758cc3dcSJack F Vogel 				"Queue No Descriptor Available");
4480758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
4481758cc3dcSJack F Vogel 				CTLFLAG_RD, &txr->total_packets,
4482758cc3dcSJack F Vogel 				"Queue Packets Transmitted");
4483625d12c6SJohn Baldwin 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops",
4484625d12c6SJohn Baldwin 				CTLFLAG_RD, &txr->br->br_drops,
4485625d12c6SJohn Baldwin 				"Packets dropped in buf_ring");
4486758cc3dcSJack F Vogel 	}
4487758cc3dcSJack F Vogel 
4488758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++, rxr++) {
4489758cc3dcSJack F Vogel 		snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i);
4490758cc3dcSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
4491758cc3dcSJack F Vogel 					    CTLFLAG_RD, NULL, "Queue Name");
4492758cc3dcSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
4493758cc3dcSJack F Vogel 
4494758cc3dcSJack F Vogel 		struct lro_ctrl *lro = &rxr->lro;
4495758cc3dcSJack F Vogel 
4496758cc3dcSJack F Vogel 		snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i);
4497758cc3dcSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
4498758cc3dcSJack F Vogel 					    CTLFLAG_RD, NULL, "Queue Name");
4499758cc3dcSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
4500758cc3dcSJack F Vogel 
4501758cc3dcSJack F Vogel 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head",
4502758cc3dcSJack F Vogel 				CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr),
4503758cc3dcSJack F Vogel 				ixgbe_sysctl_rdh_handler, "IU",
4504758cc3dcSJack F Vogel 				"Receive Descriptor Head");
4505758cc3dcSJack F Vogel 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail",
4506758cc3dcSJack F Vogel 				CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr),
4507758cc3dcSJack F Vogel 				ixgbe_sysctl_rdt_handler, "IU",
4508758cc3dcSJack F Vogel 				"Receive Descriptor Tail");
4509758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
4510758cc3dcSJack F Vogel 				CTLFLAG_RD, &rxr->rx_packets,
4511758cc3dcSJack F Vogel 				"Queue Packets Received");
4512758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
4513758cc3dcSJack F Vogel 				CTLFLAG_RD, &rxr->rx_bytes,
4514758cc3dcSJack F Vogel 				"Queue Bytes Received");
4515758cc3dcSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies",
4516758cc3dcSJack F Vogel 				CTLFLAG_RD, &rxr->rx_copies,
4517758cc3dcSJack F Vogel 				"Copied RX Frames");
4518e936121dSHans Petter Selasky 		SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_queued",
4519758cc3dcSJack F Vogel 				CTLFLAG_RD, &lro->lro_queued, 0,
4520758cc3dcSJack F Vogel 				"LRO Queued");
4521e936121dSHans Petter Selasky 		SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_flushed",
4522758cc3dcSJack F Vogel 				CTLFLAG_RD, &lro->lro_flushed, 0,
4523758cc3dcSJack F Vogel 				"LRO Flushed");
4524758cc3dcSJack F Vogel 	}
4525758cc3dcSJack F Vogel 
4526758cc3dcSJack F Vogel 	/* MAC stats get the own sub node */
4527758cc3dcSJack F Vogel 
4528758cc3dcSJack F Vogel 	stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats",
4529758cc3dcSJack F Vogel 				    CTLFLAG_RD, NULL, "MAC Statistics");
4530758cc3dcSJack F Vogel 	stat_list = SYSCTL_CHILDREN(stat_node);
4531758cc3dcSJack F Vogel 
4532758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs",
4533758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->crcerrs,
4534758cc3dcSJack F Vogel 			"CRC Errors");
4535758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs",
4536758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->illerrc,
4537758cc3dcSJack F Vogel 			"Illegal Byte Errors");
4538758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs",
4539758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->errbc,
4540758cc3dcSJack F Vogel 			"Byte Errors");
4541758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards",
4542758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mspdc,
4543758cc3dcSJack F Vogel 			"MAC Short Packets Discarded");
4544758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults",
4545758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mlfc,
4546758cc3dcSJack F Vogel 			"MAC Local Faults");
4547758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults",
4548758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mrfc,
4549758cc3dcSJack F Vogel 			"MAC Remote Faults");
4550758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs",
4551758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->rlec,
4552758cc3dcSJack F Vogel 			"Receive Length Errors");
4553758cc3dcSJack F Vogel 
4554758cc3dcSJack F Vogel 	/* Flow Control stats */
4555758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd",
4556758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->lxontxc,
4557758cc3dcSJack F Vogel 			"Link XON Transmitted");
4558758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd",
4559758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->lxonrxc,
4560758cc3dcSJack F Vogel 			"Link XON Received");
4561758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd",
4562758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->lxofftxc,
4563758cc3dcSJack F Vogel 			"Link XOFF Transmitted");
4564758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd",
4565758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->lxoffrxc,
4566758cc3dcSJack F Vogel 			"Link XOFF Received");
4567758cc3dcSJack F Vogel 
4568758cc3dcSJack F Vogel 	/* Packet Reception Stats */
4569758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd",
4570758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->tor,
4571758cc3dcSJack F Vogel 			"Total Octets Received");
4572758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd",
4573758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->gorc,
4574758cc3dcSJack F Vogel 			"Good Octets Received");
4575758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd",
4576758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->tpr,
4577758cc3dcSJack F Vogel 			"Total Packets Received");
4578758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd",
4579758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->gprc,
4580758cc3dcSJack F Vogel 			"Good Packets Received");
4581758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd",
4582758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mprc,
4583758cc3dcSJack F Vogel 			"Multicast Packets Received");
4584758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd",
4585758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->bprc,
4586758cc3dcSJack F Vogel 			"Broadcast Packets Received");
4587758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64",
4588758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc64,
4589758cc3dcSJack F Vogel 			"64 byte frames received ");
4590758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127",
4591758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc127,
4592758cc3dcSJack F Vogel 			"65-127 byte frames received");
4593758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255",
4594758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc255,
4595758cc3dcSJack F Vogel 			"128-255 byte frames received");
4596758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511",
4597758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc511,
4598758cc3dcSJack F Vogel 			"256-511 byte frames received");
4599758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023",
4600758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc1023,
4601758cc3dcSJack F Vogel 			"512-1023 byte frames received");
4602758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522",
4603758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->prc1522,
4604758cc3dcSJack F Vogel 			"1023-1522 byte frames received");
4605758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized",
4606758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ruc,
4607758cc3dcSJack F Vogel 			"Receive Undersized");
4608758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented",
4609758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->rfc,
4610758cc3dcSJack F Vogel 			"Fragmented Packets Received ");
4611758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized",
4612758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->roc,
4613758cc3dcSJack F Vogel 			"Oversized Packets Received");
4614758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd",
4615758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->rjc,
4616758cc3dcSJack F Vogel 			"Received Jabber");
4617758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd",
4618758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mngprc,
4619758cc3dcSJack F Vogel 			"Management Packets Received");
4620758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd",
4621758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mngptc,
4622758cc3dcSJack F Vogel 			"Management Packets Dropped");
4623758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs",
4624758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->xec,
4625758cc3dcSJack F Vogel 			"Checksum Errors");
4626758cc3dcSJack F Vogel 
4627758cc3dcSJack F Vogel 	/* Packet Transmission Stats */
4628758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd",
4629758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->gotc,
4630758cc3dcSJack F Vogel 			"Good Octets Transmitted");
4631758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd",
4632758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->tpt,
4633758cc3dcSJack F Vogel 			"Total Packets Transmitted");
4634758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd",
4635758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->gptc,
4636758cc3dcSJack F Vogel 			"Good Packets Transmitted");
4637758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd",
4638758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->bptc,
4639758cc3dcSJack F Vogel 			"Broadcast Packets Transmitted");
4640758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd",
4641758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mptc,
4642758cc3dcSJack F Vogel 			"Multicast Packets Transmitted");
4643758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd",
4644758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->mngptc,
4645758cc3dcSJack F Vogel 			"Management Packets Transmitted");
4646758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64",
4647758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc64,
4648758cc3dcSJack F Vogel 			"64 byte frames transmitted ");
4649758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127",
4650758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc127,
4651758cc3dcSJack F Vogel 			"65-127 byte frames transmitted");
4652758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255",
4653758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc255,
4654758cc3dcSJack F Vogel 			"128-255 byte frames transmitted");
4655758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511",
4656758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc511,
4657758cc3dcSJack F Vogel 			"256-511 byte frames transmitted");
4658758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023",
4659758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc1023,
4660758cc3dcSJack F Vogel 			"512-1023 byte frames transmitted");
4661758cc3dcSJack F Vogel 	SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522",
4662758cc3dcSJack F Vogel 			CTLFLAG_RD, &stats->ptc1522,
4663758cc3dcSJack F Vogel 			"1024-1522 byte frames transmitted");
4664758cc3dcSJack F Vogel }
4665758cc3dcSJack F Vogel 
4666b0c041f8SSean Bruno static void
4667b0c041f8SSean Bruno ixgbe_set_sysctl_value(struct adapter *adapter, const char *name,
4668b0c041f8SSean Bruno     const char *description, int *limit, int value)
4669b0c041f8SSean Bruno {
4670b0c041f8SSean Bruno 	*limit = value;
4671b0c041f8SSean Bruno 	SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev),
4672b0c041f8SSean Bruno 	    SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)),
4673b0c041f8SSean Bruno 	    OID_AUTO, name, CTLFLAG_RW, limit, value, description);
4674b0c041f8SSean Bruno }
4675b0c041f8SSean Bruno 
4676758cc3dcSJack F Vogel /*
4677758cc3dcSJack F Vogel ** Set flow control using sysctl:
4678758cc3dcSJack F Vogel ** Flow control values:
4679758cc3dcSJack F Vogel ** 	0 - off
4680758cc3dcSJack F Vogel **	1 - rx pause
4681758cc3dcSJack F Vogel **	2 - tx pause
4682758cc3dcSJack F Vogel **	3 - full
4683758cc3dcSJack F Vogel */
4684758cc3dcSJack F Vogel static int
4685f2c4db54SSteven Hartland ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS)
4686758cc3dcSJack F Vogel {
4687f2c4db54SSteven Hartland 	int error, fc;
4688f2c4db54SSteven Hartland 	struct adapter *adapter;
4689758cc3dcSJack F Vogel 
4690f2c4db54SSteven Hartland 	adapter = (struct adapter *) arg1;
4691f2c4db54SSteven Hartland 	fc = adapter->fc;
4692f2c4db54SSteven Hartland 
4693f2c4db54SSteven Hartland 	error = sysctl_handle_int(oidp, &fc, 0, req);
4694758cc3dcSJack F Vogel 	if ((error) || (req->newptr == NULL))
4695758cc3dcSJack F Vogel 		return (error);
4696758cc3dcSJack F Vogel 
4697758cc3dcSJack F Vogel 	/* Don't bother if it's not changed */
4698f2c4db54SSteven Hartland 	if (adapter->fc == fc)
4699758cc3dcSJack F Vogel 		return (0);
4700758cc3dcSJack F Vogel 
4701f2c4db54SSteven Hartland 	return ixgbe_set_flowcntl(adapter, fc);
4702f2c4db54SSteven Hartland }
4703f2c4db54SSteven Hartland 
4704f2c4db54SSteven Hartland 
4705f2c4db54SSteven Hartland static int
4706f2c4db54SSteven Hartland ixgbe_set_flowcntl(struct adapter *adapter, int fc)
4707f2c4db54SSteven Hartland {
4708f2c4db54SSteven Hartland 
4709f2c4db54SSteven Hartland 	switch (fc) {
4710758cc3dcSJack F Vogel 	case ixgbe_fc_rx_pause:
4711758cc3dcSJack F Vogel 	case ixgbe_fc_tx_pause:
4712758cc3dcSJack F Vogel 	case ixgbe_fc_full:
4713758cc3dcSJack F Vogel 		adapter->hw.fc.requested_mode = adapter->fc;
4714758cc3dcSJack F Vogel 		if (adapter->num_queues > 1)
4715758cc3dcSJack F Vogel 			ixgbe_disable_rx_drop(adapter);
4716758cc3dcSJack F Vogel 		break;
4717758cc3dcSJack F Vogel 	case ixgbe_fc_none:
4718758cc3dcSJack F Vogel 		adapter->hw.fc.requested_mode = ixgbe_fc_none;
4719758cc3dcSJack F Vogel 		if (adapter->num_queues > 1)
4720758cc3dcSJack F Vogel 			ixgbe_enable_rx_drop(adapter);
4721758cc3dcSJack F Vogel 		break;
4722758cc3dcSJack F Vogel 	default:
4723758cc3dcSJack F Vogel 		return (EINVAL);
4724758cc3dcSJack F Vogel 	}
4725f2c4db54SSteven Hartland 	adapter->fc = fc;
4726758cc3dcSJack F Vogel 	/* Don't autoneg if forcing a value */
4727758cc3dcSJack F Vogel 	adapter->hw.fc.disable_fc_autoneg = TRUE;
4728758cc3dcSJack F Vogel 	ixgbe_fc_enable(&adapter->hw);
4729f2c4db54SSteven Hartland 	return (0);
4730758cc3dcSJack F Vogel }
4731758cc3dcSJack F Vogel 
4732758cc3dcSJack F Vogel /*
4733758cc3dcSJack F Vogel ** Control advertised link speed:
4734758cc3dcSJack F Vogel **	Flags:
4735758cc3dcSJack F Vogel **	0x1 - advertise 100 Mb
4736758cc3dcSJack F Vogel **	0x2 - advertise 1G
4737758cc3dcSJack F Vogel **	0x4 - advertise 10G
4738758cc3dcSJack F Vogel */
4739758cc3dcSJack F Vogel static int
4740f2c4db54SSteven Hartland ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS)
4741758cc3dcSJack F Vogel {
4742f2c4db54SSteven Hartland 	int error, advertise;
4743758cc3dcSJack F Vogel 	struct adapter *adapter;
4744758cc3dcSJack F Vogel 
4745758cc3dcSJack F Vogel 	adapter = (struct adapter *) arg1;
4746f2c4db54SSteven Hartland 	advertise = adapter->advertise;
4747758cc3dcSJack F Vogel 
4748f2c4db54SSteven Hartland 	error = sysctl_handle_int(oidp, &advertise, 0, req);
4749758cc3dcSJack F Vogel 	if ((error) || (req->newptr == NULL))
4750758cc3dcSJack F Vogel 		return (error);
4751758cc3dcSJack F Vogel 
4752f2c4db54SSteven Hartland 	return ixgbe_set_advertise(adapter, advertise);
4753f2c4db54SSteven Hartland }
4754f2c4db54SSteven Hartland 
4755f2c4db54SSteven Hartland static int
4756f2c4db54SSteven Hartland ixgbe_set_advertise(struct adapter *adapter, int advertise)
4757f2c4db54SSteven Hartland {
4758f2c4db54SSteven Hartland 	device_t		dev;
4759f2c4db54SSteven Hartland 	struct ixgbe_hw		*hw;
4760f2c4db54SSteven Hartland 	ixgbe_link_speed	speed;
4761f2c4db54SSteven Hartland 
4762*d775d23aSSteven Hartland 	/* Checks to validate new value */
4763*d775d23aSSteven Hartland 	if (adapter->advertise == advertise) /* no change */
4764*d775d23aSSteven Hartland 		return (0);
4765*d775d23aSSteven Hartland 
4766f2c4db54SSteven Hartland 	hw = &adapter->hw;
4767f2c4db54SSteven Hartland 	dev = adapter->dev;
4768f2c4db54SSteven Hartland 
4769a9ca1c79SSean Bruno 	/* No speed changes for backplane media */
4770a9ca1c79SSean Bruno 	if (hw->phy.media_type == ixgbe_media_type_backplane)
4771a9ca1c79SSean Bruno 		return (ENODEV);
4772a9ca1c79SSean Bruno 
4773758cc3dcSJack F Vogel 	if (!((hw->phy.media_type == ixgbe_media_type_copper) ||
4774758cc3dcSJack F Vogel 	    (hw->phy.multispeed_fiber))) {
4775758cc3dcSJack F Vogel 		device_printf(dev,
4776758cc3dcSJack F Vogel 		    "Advertised speed can only be set on copper or "
4777758cc3dcSJack F Vogel 		    "multispeed fiber media types.\n");
4778758cc3dcSJack F Vogel 		return (EINVAL);
4779758cc3dcSJack F Vogel 	}
4780758cc3dcSJack F Vogel 
4781f2c4db54SSteven Hartland 	if (advertise < 0x1 || advertise > 0x7) {
4782758cc3dcSJack F Vogel 		device_printf(dev,
4783758cc3dcSJack F Vogel 		    "Invalid advertised speed; valid modes are 0x1 through 0x7\n");
4784758cc3dcSJack F Vogel 		return (EINVAL);
4785758cc3dcSJack F Vogel 	}
4786758cc3dcSJack F Vogel 
4787f2c4db54SSteven Hartland 	if ((advertise & 0x1)
4788758cc3dcSJack F Vogel 	    && (hw->mac.type != ixgbe_mac_X540)
4789758cc3dcSJack F Vogel 	    && (hw->mac.type != ixgbe_mac_X550)) {
4790758cc3dcSJack F Vogel 		device_printf(dev, "Set Advertise: 100Mb on X540/X550 only\n");
4791758cc3dcSJack F Vogel 		return (EINVAL);
4792758cc3dcSJack F Vogel 	}
4793758cc3dcSJack F Vogel 
4794758cc3dcSJack F Vogel 	/* Set new value and report new advertised mode */
4795f2c4db54SSteven Hartland 	speed = 0;
4796f2c4db54SSteven Hartland 	if (advertise & 0x1)
4797758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_100_FULL;
4798f2c4db54SSteven Hartland 	if (advertise & 0x2)
4799758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
4800f2c4db54SSteven Hartland 	if (advertise & 0x4)
4801758cc3dcSJack F Vogel 		speed |= IXGBE_LINK_SPEED_10GB_FULL;
4802f2c4db54SSteven Hartland 	adapter->advertise = advertise;
4803758cc3dcSJack F Vogel 
4804758cc3dcSJack F Vogel 	hw->mac.autotry_restart = TRUE;
4805758cc3dcSJack F Vogel 	hw->mac.ops.setup_link(hw, speed, TRUE);
4806758cc3dcSJack F Vogel 
4807f2c4db54SSteven Hartland 	return (0);
4808758cc3dcSJack F Vogel }
4809758cc3dcSJack F Vogel 
4810758cc3dcSJack F Vogel /*
4811a9ca1c79SSean Bruno  * The following two sysctls are for X552/X557-AT devices;
48126f37f232SEric Joyner  * they deal with the external PHY used in them.
4813758cc3dcSJack F Vogel  */
4814758cc3dcSJack F Vogel static int
48156f37f232SEric Joyner ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS)
4816758cc3dcSJack F Vogel {
4817758cc3dcSJack F Vogel 	struct adapter	*adapter = (struct adapter *) arg1;
4818758cc3dcSJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
48196f37f232SEric Joyner 	u16 reg;
4820758cc3dcSJack F Vogel 
48216f37f232SEric Joyner 	if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
48226f37f232SEric Joyner 		device_printf(adapter->dev,
48236f37f232SEric Joyner 		    "Device has no supported external thermal sensor.\n");
48246f37f232SEric Joyner 		return (ENODEV);
48256f37f232SEric Joyner 	}
4826758cc3dcSJack F Vogel 
48276f37f232SEric Joyner 	if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP,
48286f37f232SEric Joyner 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
48296f37f232SEric Joyner 				      &reg)) {
48306f37f232SEric Joyner 		device_printf(adapter->dev,
48316f37f232SEric Joyner 		    "Error reading from PHY's current temperature register\n");
48326f37f232SEric Joyner 		return (EAGAIN);
48336f37f232SEric Joyner 	}
48346f37f232SEric Joyner 
48356f37f232SEric Joyner 	/* Shift temp for output */
48366f37f232SEric Joyner 	reg = reg >> 8;
48376f37f232SEric Joyner 
48386f37f232SEric Joyner 	return (sysctl_handle_int(oidp, NULL, reg, req));
48396f37f232SEric Joyner }
48406f37f232SEric Joyner 
48416f37f232SEric Joyner /*
48426f37f232SEric Joyner  * Reports whether the current PHY temperature is over
48436f37f232SEric Joyner  * the overtemp threshold.
48446f37f232SEric Joyner  *  - This is reported directly from the PHY
48456f37f232SEric Joyner  */
48466f37f232SEric Joyner static int
48476f37f232SEric Joyner ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS)
48486f37f232SEric Joyner {
48496f37f232SEric Joyner 	struct adapter	*adapter = (struct adapter *) arg1;
48506f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
48516f37f232SEric Joyner 	u16 reg;
48526f37f232SEric Joyner 
48536f37f232SEric Joyner 	if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
48546f37f232SEric Joyner 		device_printf(adapter->dev,
48556f37f232SEric Joyner 		    "Device has no supported external thermal sensor.\n");
48566f37f232SEric Joyner 		return (ENODEV);
48576f37f232SEric Joyner 	}
48586f37f232SEric Joyner 
48596f37f232SEric Joyner 	if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS,
48606f37f232SEric Joyner 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
48616f37f232SEric Joyner 				      &reg)) {
48626f37f232SEric Joyner 		device_printf(adapter->dev,
48636f37f232SEric Joyner 		    "Error reading from PHY's temperature status register\n");
48646f37f232SEric Joyner 		return (EAGAIN);
48656f37f232SEric Joyner 	}
48666f37f232SEric Joyner 
48676f37f232SEric Joyner 	/* Get occurrence bit */
48686f37f232SEric Joyner 	reg = !!(reg & 0x4000);
48696f37f232SEric Joyner 	return (sysctl_handle_int(oidp, 0, reg, req));
48706f37f232SEric Joyner }
48716f37f232SEric Joyner 
48726f37f232SEric Joyner /*
48736f37f232SEric Joyner ** Thermal Shutdown Trigger (internal MAC)
48746f37f232SEric Joyner **   - Set this to 1 to cause an overtemp event to occur
48756f37f232SEric Joyner */
48766f37f232SEric Joyner static int
48776f37f232SEric Joyner ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS)
48786f37f232SEric Joyner {
48796f37f232SEric Joyner 	struct adapter	*adapter = (struct adapter *) arg1;
48806f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
48816f37f232SEric Joyner 	int error, fire = 0;
4882758cc3dcSJack F Vogel 
4883758cc3dcSJack F Vogel 	error = sysctl_handle_int(oidp, &fire, 0, req);
4884758cc3dcSJack F Vogel 	if ((error) || (req->newptr == NULL))
4885758cc3dcSJack F Vogel 		return (error);
4886758cc3dcSJack F Vogel 
4887758cc3dcSJack F Vogel 	if (fire) {
4888758cc3dcSJack F Vogel 		u32 reg = IXGBE_READ_REG(hw, IXGBE_EICS);
4889758cc3dcSJack F Vogel 		reg |= IXGBE_EICR_TS;
4890758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_EICS, reg);
4891758cc3dcSJack F Vogel 	}
4892758cc3dcSJack F Vogel 
4893758cc3dcSJack F Vogel 	return (0);
4894758cc3dcSJack F Vogel }
4895758cc3dcSJack F Vogel 
4896758cc3dcSJack F Vogel /*
48976f37f232SEric Joyner ** Manage DMA Coalescing.
48986f37f232SEric Joyner ** Control values:
48996f37f232SEric Joyner ** 	0/1 - off / on (use default value of 1000)
49006f37f232SEric Joyner **
49016f37f232SEric Joyner **	Legal timer values are:
49026f37f232SEric Joyner **	50,100,250,500,1000,2000,5000,10000
49036f37f232SEric Joyner **
49046f37f232SEric Joyner **	Turning off interrupt moderation will also turn this off.
49056f37f232SEric Joyner */
49066f37f232SEric Joyner static int
49076f37f232SEric Joyner ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS)
49086f37f232SEric Joyner {
49096f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
49106f37f232SEric Joyner 	struct ifnet *ifp = adapter->ifp;
49116f37f232SEric Joyner 	int		error;
4912a9ca1c79SSean Bruno 	u32		newval;
49136f37f232SEric Joyner 
4914a9ca1c79SSean Bruno 	newval = adapter->dmac;
4915a9ca1c79SSean Bruno 	error = sysctl_handle_int(oidp, &newval, 0, req);
49166f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
49176f37f232SEric Joyner 		return (error);
49186f37f232SEric Joyner 
4919a9ca1c79SSean Bruno 	switch (newval) {
49206f37f232SEric Joyner 	case 0:
49216f37f232SEric Joyner 		/* Disabled */
4922a9ca1c79SSean Bruno 		adapter->dmac = 0;
49236f37f232SEric Joyner 		break;
4924a9ca1c79SSean Bruno 	case 1:
4925a9ca1c79SSean Bruno 		/* Enable and use default */
49266f37f232SEric Joyner 		adapter->dmac = 1000;
49276f37f232SEric Joyner 		break;
49286f37f232SEric Joyner 	case 50:
49296f37f232SEric Joyner 	case 100:
49306f37f232SEric Joyner 	case 250:
49316f37f232SEric Joyner 	case 500:
49326f37f232SEric Joyner 	case 1000:
49336f37f232SEric Joyner 	case 2000:
49346f37f232SEric Joyner 	case 5000:
49356f37f232SEric Joyner 	case 10000:
49366f37f232SEric Joyner 		/* Legal values - allow */
4937a9ca1c79SSean Bruno 		adapter->dmac = newval;
49386f37f232SEric Joyner 		break;
49396f37f232SEric Joyner 	default:
49406f37f232SEric Joyner 		/* Do nothing, illegal value */
49416f37f232SEric Joyner 		return (EINVAL);
49426f37f232SEric Joyner 	}
49436f37f232SEric Joyner 
49446f37f232SEric Joyner 	/* Re-initialize hardware if it's already running */
49456f37f232SEric Joyner 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
49466f37f232SEric Joyner 		ixgbe_init(adapter);
49476f37f232SEric Joyner 
49486f37f232SEric Joyner 	return (0);
49496f37f232SEric Joyner }
49506f37f232SEric Joyner 
4951a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
4952a9ca1c79SSean Bruno /**
4953a9ca1c79SSean Bruno  * Sysctl to test power states
4954a9ca1c79SSean Bruno  * Values:
4955a9ca1c79SSean Bruno  *	0      - set device to D0
4956a9ca1c79SSean Bruno  *	3      - set device to D3
4957a9ca1c79SSean Bruno  *	(none) - get current device power state
4958a9ca1c79SSean Bruno  */
4959a9ca1c79SSean Bruno static int
4960a9ca1c79SSean Bruno ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS)
4961a9ca1c79SSean Bruno {
4962a9ca1c79SSean Bruno 	struct adapter *adapter = (struct adapter *) arg1;
4963a9ca1c79SSean Bruno 	device_t dev =  adapter->dev;
4964a9ca1c79SSean Bruno 	int curr_ps, new_ps, error = 0;
4965a9ca1c79SSean Bruno 
4966a9ca1c79SSean Bruno 	curr_ps = new_ps = pci_get_powerstate(dev);
4967a9ca1c79SSean Bruno 
4968a9ca1c79SSean Bruno 	error = sysctl_handle_int(oidp, &new_ps, 0, req);
4969a9ca1c79SSean Bruno 	if ((error) || (req->newptr == NULL))
4970a9ca1c79SSean Bruno 		return (error);
4971a9ca1c79SSean Bruno 
4972a9ca1c79SSean Bruno 	if (new_ps == curr_ps)
4973a9ca1c79SSean Bruno 		return (0);
4974a9ca1c79SSean Bruno 
4975a9ca1c79SSean Bruno 	if (new_ps == 3 && curr_ps == 0)
4976a9ca1c79SSean Bruno 		error = DEVICE_SUSPEND(dev);
4977a9ca1c79SSean Bruno 	else if (new_ps == 0 && curr_ps == 3)
4978a9ca1c79SSean Bruno 		error = DEVICE_RESUME(dev);
4979a9ca1c79SSean Bruno 	else
4980a9ca1c79SSean Bruno 		return (EINVAL);
4981a9ca1c79SSean Bruno 
4982a9ca1c79SSean Bruno 	device_printf(dev, "New state: %d\n", pci_get_powerstate(dev));
4983a9ca1c79SSean Bruno 
4984a9ca1c79SSean Bruno 	return (error);
4985a9ca1c79SSean Bruno }
4986a9ca1c79SSean Bruno #endif
49876f37f232SEric Joyner /*
49886f37f232SEric Joyner  * Sysctl to enable/disable the WoL capability, if supported by the adapter.
49896f37f232SEric Joyner  * Values:
49906f37f232SEric Joyner  *	0 - disabled
49916f37f232SEric Joyner  *	1 - enabled
49926f37f232SEric Joyner  */
49936f37f232SEric Joyner static int
49946f37f232SEric Joyner ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS)
49956f37f232SEric Joyner {
49966f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
49976f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
49986f37f232SEric Joyner 	int new_wol_enabled;
49996f37f232SEric Joyner 	int error = 0;
50006f37f232SEric Joyner 
50016f37f232SEric Joyner 	new_wol_enabled = hw->wol_enabled;
50026f37f232SEric Joyner 	error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req);
50036f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
50046f37f232SEric Joyner 		return (error);
5005a9ca1c79SSean Bruno 	new_wol_enabled = !!(new_wol_enabled);
50066f37f232SEric Joyner 	if (new_wol_enabled == hw->wol_enabled)
50076f37f232SEric Joyner 		return (0);
50086f37f232SEric Joyner 
50096f37f232SEric Joyner 	if (new_wol_enabled > 0 && !adapter->wol_support)
50106f37f232SEric Joyner 		return (ENODEV);
50116f37f232SEric Joyner 	else
5012a9ca1c79SSean Bruno 		hw->wol_enabled = new_wol_enabled;
50136f37f232SEric Joyner 
50146f37f232SEric Joyner 	return (0);
50156f37f232SEric Joyner }
50166f37f232SEric Joyner 
50176f37f232SEric Joyner /*
50186f37f232SEric Joyner  * Sysctl to enable/disable the Energy Efficient Ethernet capability,
50196f37f232SEric Joyner  * if supported by the adapter.
50206f37f232SEric Joyner  * Values:
50216f37f232SEric Joyner  *	0 - disabled
50226f37f232SEric Joyner  *	1 - enabled
50236f37f232SEric Joyner  */
50246f37f232SEric Joyner static int
50256f37f232SEric Joyner ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS)
50266f37f232SEric Joyner {
50276f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
502848056c88SJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
50296f37f232SEric Joyner 	struct ifnet *ifp = adapter->ifp;
50306f37f232SEric Joyner 	int new_eee_enabled, error = 0;
50316f37f232SEric Joyner 
50326f37f232SEric Joyner 	new_eee_enabled = adapter->eee_enabled;
50336f37f232SEric Joyner 	error = sysctl_handle_int(oidp, &new_eee_enabled, 0, req);
50346f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
50356f37f232SEric Joyner 		return (error);
5036a9ca1c79SSean Bruno 	new_eee_enabled = !!(new_eee_enabled);
50376f37f232SEric Joyner 	if (new_eee_enabled == adapter->eee_enabled)
50386f37f232SEric Joyner 		return (0);
50396f37f232SEric Joyner 
504048056c88SJack F Vogel 	if (new_eee_enabled > 0 && !hw->mac.ops.setup_eee)
50416f37f232SEric Joyner 		return (ENODEV);
50426f37f232SEric Joyner 	else
5043a9ca1c79SSean Bruno 		adapter->eee_enabled = new_eee_enabled;
50446f37f232SEric Joyner 
50456f37f232SEric Joyner 	/* Re-initialize hardware if it's already running */
50466f37f232SEric Joyner 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
50476f37f232SEric Joyner 		ixgbe_init(adapter);
50486f37f232SEric Joyner 
50496f37f232SEric Joyner 	return (0);
50506f37f232SEric Joyner }
50516f37f232SEric Joyner 
50526f37f232SEric Joyner /*
50536f37f232SEric Joyner  * Read-only sysctl indicating whether EEE support was negotiated
50546f37f232SEric Joyner  * on the link.
50556f37f232SEric Joyner  */
50566f37f232SEric Joyner static int
50576f37f232SEric Joyner ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS)
50586f37f232SEric Joyner {
50596f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
50606f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
50616f37f232SEric Joyner 	bool status;
50626f37f232SEric Joyner 
50636f37f232SEric Joyner 	status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & IXGBE_EEE_STAT_NEG);
50646f37f232SEric Joyner 
50656f37f232SEric Joyner 	return (sysctl_handle_int(oidp, 0, status, req));
50666f37f232SEric Joyner }
50676f37f232SEric Joyner 
50686f37f232SEric Joyner /*
50696f37f232SEric Joyner  * Read-only sysctl indicating whether RX Link is in LPI state.
50706f37f232SEric Joyner  */
50716f37f232SEric Joyner static int
50726f37f232SEric Joyner ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS)
50736f37f232SEric Joyner {
50746f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
50756f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
50766f37f232SEric Joyner 	bool status;
50776f37f232SEric Joyner 
50786f37f232SEric Joyner 	status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) &
50796f37f232SEric Joyner 	    IXGBE_EEE_RX_LPI_STATUS);
50806f37f232SEric Joyner 
50816f37f232SEric Joyner 	return (sysctl_handle_int(oidp, 0, status, req));
50826f37f232SEric Joyner }
50836f37f232SEric Joyner 
50846f37f232SEric Joyner /*
50856f37f232SEric Joyner  * Read-only sysctl indicating whether TX Link is in LPI state.
50866f37f232SEric Joyner  */
50876f37f232SEric Joyner static int
50886f37f232SEric Joyner ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS)
50896f37f232SEric Joyner {
50906f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
50916f37f232SEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
50926f37f232SEric Joyner 	bool status;
50936f37f232SEric Joyner 
50946f37f232SEric Joyner 	status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) &
50956f37f232SEric Joyner 	    IXGBE_EEE_TX_LPI_STATUS);
50966f37f232SEric Joyner 
50976f37f232SEric Joyner 	return (sysctl_handle_int(oidp, 0, status, req));
50986f37f232SEric Joyner }
50996f37f232SEric Joyner 
51006f37f232SEric Joyner /*
5101a9ca1c79SSean Bruno  * Read-only sysctl indicating TX Link LPI delay
5102a9ca1c79SSean Bruno  */
5103a9ca1c79SSean Bruno static int
5104a9ca1c79SSean Bruno ixgbe_sysctl_eee_tx_lpi_delay(SYSCTL_HANDLER_ARGS)
5105a9ca1c79SSean Bruno {
5106a9ca1c79SSean Bruno 	struct adapter *adapter = (struct adapter *) arg1;
5107a9ca1c79SSean Bruno 	struct ixgbe_hw *hw = &adapter->hw;
5108a9ca1c79SSean Bruno 	u32 reg;
5109a9ca1c79SSean Bruno 
5110a9ca1c79SSean Bruno 	reg = IXGBE_READ_REG(hw, IXGBE_EEE_SU);
5111a9ca1c79SSean Bruno 
5112a9ca1c79SSean Bruno 	return (sysctl_handle_int(oidp, 0, reg >> 26, req));
5113a9ca1c79SSean Bruno }
5114a9ca1c79SSean Bruno 
5115a9ca1c79SSean Bruno /*
51166f37f232SEric Joyner  * Sysctl to enable/disable the types of packets that the
51176f37f232SEric Joyner  * adapter will wake up on upon receipt.
51186f37f232SEric Joyner  * WUFC - Wake Up Filter Control
51196f37f232SEric Joyner  * Flags:
51206f37f232SEric Joyner  *	0x1  - Link Status Change
51216f37f232SEric Joyner  *	0x2  - Magic Packet
51226f37f232SEric Joyner  *	0x4  - Direct Exact
51236f37f232SEric Joyner  *	0x8  - Directed Multicast
51246f37f232SEric Joyner  *	0x10 - Broadcast
51256f37f232SEric Joyner  *	0x20 - ARP/IPv4 Request Packet
51266f37f232SEric Joyner  *	0x40 - Direct IPv4 Packet
51276f37f232SEric Joyner  *	0x80 - Direct IPv6 Packet
51286f37f232SEric Joyner  *
51296f37f232SEric Joyner  * Setting another flag will cause the sysctl to return an
51306f37f232SEric Joyner  * error.
51316f37f232SEric Joyner  */
51326f37f232SEric Joyner static int
51336f37f232SEric Joyner ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS)
51346f37f232SEric Joyner {
51356f37f232SEric Joyner 	struct adapter *adapter = (struct adapter *) arg1;
51366f37f232SEric Joyner 	int error = 0;
51376f37f232SEric Joyner 	u32 new_wufc;
51386f37f232SEric Joyner 
51396f37f232SEric Joyner 	new_wufc = adapter->wufc;
51406f37f232SEric Joyner 
51416f37f232SEric Joyner 	error = sysctl_handle_int(oidp, &new_wufc, 0, req);
51426f37f232SEric Joyner 	if ((error) || (req->newptr == NULL))
51436f37f232SEric Joyner 		return (error);
51446f37f232SEric Joyner 	if (new_wufc == adapter->wufc)
51456f37f232SEric Joyner 		return (0);
51466f37f232SEric Joyner 
51476f37f232SEric Joyner 	if (new_wufc & 0xffffff00)
51486f37f232SEric Joyner 		return (EINVAL);
51496f37f232SEric Joyner 	else {
51506f37f232SEric Joyner 		new_wufc &= 0xff;
51516f37f232SEric Joyner 		new_wufc |= (0xffffff & adapter->wufc);
51526f37f232SEric Joyner 		adapter->wufc = new_wufc;
51536f37f232SEric Joyner 	}
51546f37f232SEric Joyner 
51556f37f232SEric Joyner 	return (0);
51566f37f232SEric Joyner }
51576f37f232SEric Joyner 
5158a9ca1c79SSean Bruno #ifdef IXGBE_DEBUG
5159a9ca1c79SSean Bruno static int
5160a9ca1c79SSean Bruno ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS)
5161a9ca1c79SSean Bruno {
5162a9ca1c79SSean Bruno 	struct adapter *adapter = (struct adapter *)arg1;
5163a9ca1c79SSean Bruno 	struct ixgbe_hw *hw = &adapter->hw;
5164a9ca1c79SSean Bruno 	device_t dev = adapter->dev;
5165a9ca1c79SSean Bruno 	int error = 0, reta_size;
5166a9ca1c79SSean Bruno 	struct sbuf *buf;
5167a9ca1c79SSean Bruno 	u32 reg;
5168a9ca1c79SSean Bruno 
5169a9ca1c79SSean Bruno 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
5170a9ca1c79SSean Bruno 	if (!buf) {
5171a9ca1c79SSean Bruno 		device_printf(dev, "Could not allocate sbuf for output.\n");
5172a9ca1c79SSean Bruno 		return (ENOMEM);
5173a9ca1c79SSean Bruno 	}
5174a9ca1c79SSean Bruno 
5175a9ca1c79SSean Bruno 	// TODO: use sbufs to make a string to print out
5176a9ca1c79SSean Bruno 	/* Set multiplier for RETA setup and table size based on MAC */
5177a9ca1c79SSean Bruno 	switch (adapter->hw.mac.type) {
5178a9ca1c79SSean Bruno 	case ixgbe_mac_X550:
5179a9ca1c79SSean Bruno 	case ixgbe_mac_X550EM_x:
5180a9ca1c79SSean Bruno 		reta_size = 128;
5181a9ca1c79SSean Bruno 		break;
5182a9ca1c79SSean Bruno 	default:
5183a9ca1c79SSean Bruno 		reta_size = 32;
5184a9ca1c79SSean Bruno 		break;
5185a9ca1c79SSean Bruno 	}
5186a9ca1c79SSean Bruno 
5187a9ca1c79SSean Bruno 	/* Print out the redirection table */
5188a9ca1c79SSean Bruno 	sbuf_cat(buf, "\n");
5189a9ca1c79SSean Bruno 	for (int i = 0; i < reta_size; i++) {
5190a9ca1c79SSean Bruno 		if (i < 32) {
5191a9ca1c79SSean Bruno 			reg = IXGBE_READ_REG(hw, IXGBE_RETA(i));
5192a9ca1c79SSean Bruno 			sbuf_printf(buf, "RETA(%2d): 0x%08x\n", i, reg);
5193a9ca1c79SSean Bruno 		} else {
5194a9ca1c79SSean Bruno 			reg = IXGBE_READ_REG(hw, IXGBE_ERETA(i - 32));
5195a9ca1c79SSean Bruno 			sbuf_printf(buf, "ERETA(%2d): 0x%08x\n", i - 32, reg);
5196a9ca1c79SSean Bruno 		}
5197a9ca1c79SSean Bruno 	}
5198a9ca1c79SSean Bruno 
5199a9ca1c79SSean Bruno 	// TODO: print more config
5200a9ca1c79SSean Bruno 
5201a9ca1c79SSean Bruno 	error = sbuf_finish(buf);
5202a9ca1c79SSean Bruno 	if (error)
5203a9ca1c79SSean Bruno 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5204a9ca1c79SSean Bruno 
5205a9ca1c79SSean Bruno 	sbuf_delete(buf);
5206a9ca1c79SSean Bruno 	return (0);
5207a9ca1c79SSean Bruno }
5208a9ca1c79SSean Bruno #endif /* IXGBE_DEBUG */
5209a9ca1c79SSean Bruno 
52106f37f232SEric Joyner /*
5211758cc3dcSJack F Vogel ** Enable the hardware to drop packets when the buffer is
5212758cc3dcSJack F Vogel ** full. This is useful when multiqueue,so that no single
5213758cc3dcSJack F Vogel ** queue being full stalls the entire RX engine. We only
5214758cc3dcSJack F Vogel ** enable this when Multiqueue AND when Flow Control is
5215758cc3dcSJack F Vogel ** disabled.
5216758cc3dcSJack F Vogel */
5217758cc3dcSJack F Vogel static void
5218758cc3dcSJack F Vogel ixgbe_enable_rx_drop(struct adapter *adapter)
5219758cc3dcSJack F Vogel {
5220758cc3dcSJack F Vogel         struct ixgbe_hw *hw = &adapter->hw;
5221758cc3dcSJack F Vogel 
5222758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++) {
522348056c88SJack F Vogel 		struct rx_ring *rxr = &adapter->rx_rings[i];
522448056c88SJack F Vogel         	u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me));
5225758cc3dcSJack F Vogel         	srrctl |= IXGBE_SRRCTL_DROP_EN;
522648056c88SJack F Vogel         	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl);
5227758cc3dcSJack F Vogel 	}
522848056c88SJack F Vogel #ifdef PCI_IOV
522948056c88SJack F Vogel 	/* enable drop for each vf */
523048056c88SJack F Vogel 	for (int i = 0; i < adapter->num_vfs; i++) {
523148056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_QDE,
523248056c88SJack F Vogel 		    (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT) |
523348056c88SJack F Vogel 		    IXGBE_QDE_ENABLE));
523448056c88SJack F Vogel 	}
523548056c88SJack F Vogel #endif
5236758cc3dcSJack F Vogel }
5237758cc3dcSJack F Vogel 
5238758cc3dcSJack F Vogel static void
5239758cc3dcSJack F Vogel ixgbe_disable_rx_drop(struct adapter *adapter)
5240758cc3dcSJack F Vogel {
5241758cc3dcSJack F Vogel         struct ixgbe_hw *hw = &adapter->hw;
5242758cc3dcSJack F Vogel 
5243758cc3dcSJack F Vogel 	for (int i = 0; i < adapter->num_queues; i++) {
524448056c88SJack F Vogel 		struct rx_ring *rxr = &adapter->rx_rings[i];
524548056c88SJack F Vogel         	u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me));
5246758cc3dcSJack F Vogel         	srrctl &= ~IXGBE_SRRCTL_DROP_EN;
524748056c88SJack F Vogel         	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl);
5248758cc3dcSJack F Vogel 	}
524948056c88SJack F Vogel #ifdef PCI_IOV
525048056c88SJack F Vogel 	/* disable drop for each vf */
525148056c88SJack F Vogel 	for (int i = 0; i < adapter->num_vfs; i++) {
525248056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_QDE,
525348056c88SJack F Vogel 		    (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT)));
525448056c88SJack F Vogel 	}
525548056c88SJack F Vogel #endif
5256758cc3dcSJack F Vogel }
5257758cc3dcSJack F Vogel 
5258758cc3dcSJack F Vogel static void
5259758cc3dcSJack F Vogel ixgbe_rearm_queues(struct adapter *adapter, u64 queues)
5260758cc3dcSJack F Vogel {
5261758cc3dcSJack F Vogel 	u32 mask;
5262758cc3dcSJack F Vogel 
5263758cc3dcSJack F Vogel 	switch (adapter->hw.mac.type) {
5264758cc3dcSJack F Vogel 	case ixgbe_mac_82598EB:
5265758cc3dcSJack F Vogel 		mask = (IXGBE_EIMS_RTX_QUEUE & queues);
5266758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask);
5267758cc3dcSJack F Vogel 		break;
5268758cc3dcSJack F Vogel 	case ixgbe_mac_82599EB:
5269758cc3dcSJack F Vogel 	case ixgbe_mac_X540:
5270758cc3dcSJack F Vogel 	case ixgbe_mac_X550:
52716f37f232SEric Joyner 	case ixgbe_mac_X550EM_x:
5272758cc3dcSJack F Vogel 		mask = (queues & 0xFFFFFFFF);
5273758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask);
5274758cc3dcSJack F Vogel 		mask = (queues >> 32);
5275758cc3dcSJack F Vogel 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask);
5276758cc3dcSJack F Vogel 		break;
5277758cc3dcSJack F Vogel 	default:
5278758cc3dcSJack F Vogel 		break;
5279758cc3dcSJack F Vogel 	}
5280758cc3dcSJack F Vogel }
5281758cc3dcSJack F Vogel 
528248056c88SJack F Vogel #ifdef PCI_IOV
528348056c88SJack F Vogel 
528448056c88SJack F Vogel /*
528548056c88SJack F Vogel ** Support functions for SRIOV/VF management
528648056c88SJack F Vogel */
528748056c88SJack F Vogel 
528848056c88SJack F Vogel static void
528948056c88SJack F Vogel ixgbe_ping_all_vfs(struct adapter *adapter)
529048056c88SJack F Vogel {
529148056c88SJack F Vogel 	struct ixgbe_vf *vf;
529248056c88SJack F Vogel 
529348056c88SJack F Vogel 	for (int i = 0; i < adapter->num_vfs; i++) {
529448056c88SJack F Vogel 		vf = &adapter->vfs[i];
529548056c88SJack F Vogel 		if (vf->flags & IXGBE_VF_ACTIVE)
529648056c88SJack F Vogel 			ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG);
529748056c88SJack F Vogel 	}
529848056c88SJack F Vogel }
529948056c88SJack F Vogel 
530048056c88SJack F Vogel 
530148056c88SJack F Vogel static void
530248056c88SJack F Vogel ixgbe_vf_set_default_vlan(struct adapter *adapter, struct ixgbe_vf *vf,
530348056c88SJack F Vogel     uint16_t tag)
530448056c88SJack F Vogel {
530548056c88SJack F Vogel 	struct ixgbe_hw *hw;
530648056c88SJack F Vogel 	uint32_t vmolr, vmvir;
530748056c88SJack F Vogel 
530848056c88SJack F Vogel 	hw = &adapter->hw;
530948056c88SJack F Vogel 
531048056c88SJack F Vogel 	vf->vlan_tag = tag;
531148056c88SJack F Vogel 
531248056c88SJack F Vogel 	vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool));
531348056c88SJack F Vogel 
531448056c88SJack F Vogel 	/* Do not receive packets that pass inexact filters. */
531548056c88SJack F Vogel 	vmolr &= ~(IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_ROPE);
531648056c88SJack F Vogel 
531748056c88SJack F Vogel 	/* Disable Multicast Promicuous Mode. */
531848056c88SJack F Vogel 	vmolr &= ~IXGBE_VMOLR_MPE;
531948056c88SJack F Vogel 
532048056c88SJack F Vogel 	/* Accept broadcasts. */
532148056c88SJack F Vogel 	vmolr |= IXGBE_VMOLR_BAM;
532248056c88SJack F Vogel 
532348056c88SJack F Vogel 	if (tag == 0) {
532448056c88SJack F Vogel 		/* Accept non-vlan tagged traffic. */
532548056c88SJack F Vogel 		//vmolr |= IXGBE_VMOLR_AUPE;
532648056c88SJack F Vogel 
532748056c88SJack F Vogel 		/* Allow VM to tag outgoing traffic; no default tag. */
532848056c88SJack F Vogel 		vmvir = 0;
532948056c88SJack F Vogel 	} else {
533048056c88SJack F Vogel 		/* Require vlan-tagged traffic. */
533148056c88SJack F Vogel 		vmolr &= ~IXGBE_VMOLR_AUPE;
533248056c88SJack F Vogel 
533348056c88SJack F Vogel 		/* Tag all traffic with provided vlan tag. */
533448056c88SJack F Vogel 		vmvir = (tag | IXGBE_VMVIR_VLANA_DEFAULT);
533548056c88SJack F Vogel 	}
533648056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr);
533748056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir);
533848056c88SJack F Vogel }
533948056c88SJack F Vogel 
534048056c88SJack F Vogel 
534148056c88SJack F Vogel static boolean_t
534248056c88SJack F Vogel ixgbe_vf_frame_size_compatible(struct adapter *adapter, struct ixgbe_vf *vf)
534348056c88SJack F Vogel {
534448056c88SJack F Vogel 
534548056c88SJack F Vogel 	/*
534648056c88SJack F Vogel 	 * Frame size compatibility between PF and VF is only a problem on
534748056c88SJack F Vogel 	 * 82599-based cards.  X540 and later support any combination of jumbo
534848056c88SJack F Vogel 	 * frames on PFs and VFs.
534948056c88SJack F Vogel 	 */
535048056c88SJack F Vogel 	if (adapter->hw.mac.type != ixgbe_mac_82599EB)
535148056c88SJack F Vogel 		return (TRUE);
535248056c88SJack F Vogel 
535348056c88SJack F Vogel 	switch (vf->api_ver) {
535448056c88SJack F Vogel 	case IXGBE_API_VER_1_0:
535548056c88SJack F Vogel 	case IXGBE_API_VER_UNKNOWN:
535648056c88SJack F Vogel 		/*
535748056c88SJack F Vogel 		 * On legacy (1.0 and older) VF versions, we don't support jumbo
535848056c88SJack F Vogel 		 * frames on either the PF or the VF.
535948056c88SJack F Vogel 		 */
536048056c88SJack F Vogel 		if (adapter->max_frame_size > ETHER_MAX_LEN ||
536148056c88SJack F Vogel 		    vf->max_frame_size > ETHER_MAX_LEN)
536248056c88SJack F Vogel 		    return (FALSE);
536348056c88SJack F Vogel 
536448056c88SJack F Vogel 		return (TRUE);
536548056c88SJack F Vogel 
536648056c88SJack F Vogel 		break;
536748056c88SJack F Vogel 	case IXGBE_API_VER_1_1:
536848056c88SJack F Vogel 	default:
536948056c88SJack F Vogel 		/*
537048056c88SJack F Vogel 		 * 1.1 or later VF versions always work if they aren't using
537148056c88SJack F Vogel 		 * jumbo frames.
537248056c88SJack F Vogel 		 */
537348056c88SJack F Vogel 		if (vf->max_frame_size <= ETHER_MAX_LEN)
537448056c88SJack F Vogel 			return (TRUE);
537548056c88SJack F Vogel 
537648056c88SJack F Vogel 		/*
537748056c88SJack F Vogel 		 * Jumbo frames only work with VFs if the PF is also using jumbo
537848056c88SJack F Vogel 		 * frames.
537948056c88SJack F Vogel 		 */
538048056c88SJack F Vogel 		if (adapter->max_frame_size <= ETHER_MAX_LEN)
538148056c88SJack F Vogel 			return (TRUE);
538248056c88SJack F Vogel 
538348056c88SJack F Vogel 		return (FALSE);
538448056c88SJack F Vogel 
538548056c88SJack F Vogel 	}
538648056c88SJack F Vogel }
538748056c88SJack F Vogel 
538848056c88SJack F Vogel 
538948056c88SJack F Vogel static void
539048056c88SJack F Vogel ixgbe_process_vf_reset(struct adapter *adapter, struct ixgbe_vf *vf)
539148056c88SJack F Vogel {
539248056c88SJack F Vogel 	ixgbe_vf_set_default_vlan(adapter, vf, vf->default_vlan);
539348056c88SJack F Vogel 
539448056c88SJack F Vogel 	// XXX clear multicast addresses
539548056c88SJack F Vogel 
539648056c88SJack F Vogel 	ixgbe_clear_rar(&adapter->hw, vf->rar_index);
539748056c88SJack F Vogel 
539848056c88SJack F Vogel 	vf->api_ver = IXGBE_API_VER_UNKNOWN;
539948056c88SJack F Vogel }
540048056c88SJack F Vogel 
540148056c88SJack F Vogel 
540248056c88SJack F Vogel static void
540348056c88SJack F Vogel ixgbe_vf_enable_transmit(struct adapter *adapter, struct ixgbe_vf *vf)
540448056c88SJack F Vogel {
540548056c88SJack F Vogel 	struct ixgbe_hw *hw;
540648056c88SJack F Vogel 	uint32_t vf_index, vfte;
540748056c88SJack F Vogel 
540848056c88SJack F Vogel 	hw = &adapter->hw;
540948056c88SJack F Vogel 
541048056c88SJack F Vogel 	vf_index = IXGBE_VF_INDEX(vf->pool);
541148056c88SJack F Vogel 	vfte = IXGBE_READ_REG(hw, IXGBE_VFTE(vf_index));
541248056c88SJack F Vogel 	vfte |= IXGBE_VF_BIT(vf->pool);
541348056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_index), vfte);
541448056c88SJack F Vogel }
541548056c88SJack F Vogel 
541648056c88SJack F Vogel 
541748056c88SJack F Vogel static void
541848056c88SJack F Vogel ixgbe_vf_enable_receive(struct adapter *adapter, struct ixgbe_vf *vf)
541948056c88SJack F Vogel {
542048056c88SJack F Vogel 	struct ixgbe_hw *hw;
542148056c88SJack F Vogel 	uint32_t vf_index, vfre;
542248056c88SJack F Vogel 
542348056c88SJack F Vogel 	hw = &adapter->hw;
542448056c88SJack F Vogel 
542548056c88SJack F Vogel 	vf_index = IXGBE_VF_INDEX(vf->pool);
542648056c88SJack F Vogel 	vfre = IXGBE_READ_REG(hw, IXGBE_VFRE(vf_index));
542748056c88SJack F Vogel 	if (ixgbe_vf_frame_size_compatible(adapter, vf))
542848056c88SJack F Vogel 		vfre |= IXGBE_VF_BIT(vf->pool);
542948056c88SJack F Vogel 	else
543048056c88SJack F Vogel 		vfre &= ~IXGBE_VF_BIT(vf->pool);
543148056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_index), vfre);
543248056c88SJack F Vogel }
543348056c88SJack F Vogel 
543448056c88SJack F Vogel 
543548056c88SJack F Vogel static void
543648056c88SJack F Vogel ixgbe_vf_reset_msg(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg)
543748056c88SJack F Vogel {
543848056c88SJack F Vogel 	struct ixgbe_hw *hw;
543948056c88SJack F Vogel 	uint32_t ack;
544048056c88SJack F Vogel 	uint32_t resp[IXGBE_VF_PERMADDR_MSG_LEN];
544148056c88SJack F Vogel 
544248056c88SJack F Vogel 	hw = &adapter->hw;
544348056c88SJack F Vogel 
544448056c88SJack F Vogel 	ixgbe_process_vf_reset(adapter, vf);
544548056c88SJack F Vogel 
544648056c88SJack F Vogel 	if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) {
544748056c88SJack F Vogel 		ixgbe_set_rar(&adapter->hw, vf->rar_index,
544848056c88SJack F Vogel 		    vf->ether_addr, vf->pool, TRUE);
544948056c88SJack F Vogel 		ack = IXGBE_VT_MSGTYPE_ACK;
545048056c88SJack F Vogel 	} else
545148056c88SJack F Vogel 		ack = IXGBE_VT_MSGTYPE_NACK;
545248056c88SJack F Vogel 
545348056c88SJack F Vogel 	ixgbe_vf_enable_transmit(adapter, vf);
545448056c88SJack F Vogel 	ixgbe_vf_enable_receive(adapter, vf);
545548056c88SJack F Vogel 
545648056c88SJack F Vogel 	vf->flags |= IXGBE_VF_CTS;
545748056c88SJack F Vogel 
545848056c88SJack F Vogel 	resp[0] = IXGBE_VF_RESET | ack | IXGBE_VT_MSGTYPE_CTS;
545948056c88SJack F Vogel 	bcopy(vf->ether_addr, &resp[1], ETHER_ADDR_LEN);
546048056c88SJack F Vogel 	resp[3] = hw->mac.mc_filter_type;
546148056c88SJack F Vogel 	ixgbe_write_mbx(hw, resp, IXGBE_VF_PERMADDR_MSG_LEN, vf->pool);
546248056c88SJack F Vogel }
546348056c88SJack F Vogel 
546448056c88SJack F Vogel 
546548056c88SJack F Vogel static void
546648056c88SJack F Vogel ixgbe_vf_set_mac(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg)
546748056c88SJack F Vogel {
546848056c88SJack F Vogel 	uint8_t *mac;
546948056c88SJack F Vogel 
547048056c88SJack F Vogel 	mac = (uint8_t*)&msg[1];
547148056c88SJack F Vogel 
547248056c88SJack F Vogel 	/* Check that the VF has permission to change the MAC address. */
547348056c88SJack F Vogel 	if (!(vf->flags & IXGBE_VF_CAP_MAC) && ixgbe_vf_mac_changed(vf, mac)) {
547448056c88SJack F Vogel 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
547548056c88SJack F Vogel 		return;
547648056c88SJack F Vogel 	}
547748056c88SJack F Vogel 
547848056c88SJack F Vogel 	if (ixgbe_validate_mac_addr(mac) != 0) {
547948056c88SJack F Vogel 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
548048056c88SJack F Vogel 		return;
548148056c88SJack F Vogel 	}
548248056c88SJack F Vogel 
548348056c88SJack F Vogel 	bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN);
548448056c88SJack F Vogel 
548548056c88SJack F Vogel 	ixgbe_set_rar(&adapter->hw, vf->rar_index, vf->ether_addr,
548648056c88SJack F Vogel 	    vf->pool, TRUE);
548748056c88SJack F Vogel 
548848056c88SJack F Vogel 	ixgbe_send_vf_ack(adapter, vf, msg[0]);
548948056c88SJack F Vogel }
549048056c88SJack F Vogel 
549148056c88SJack F Vogel 
549248056c88SJack F Vogel /*
549348056c88SJack F Vogel ** VF multicast addresses are set by using the appropriate bit in
549448056c88SJack F Vogel ** 1 of 128 32 bit addresses (4096 possible).
549548056c88SJack F Vogel */
549648056c88SJack F Vogel static void
549748056c88SJack F Vogel ixgbe_vf_set_mc_addr(struct adapter *adapter, struct ixgbe_vf *vf, u32 *msg)
549848056c88SJack F Vogel {
549948056c88SJack F Vogel 	u16	*list = (u16*)&msg[1];
550048056c88SJack F Vogel 	int	entries;
550148056c88SJack F Vogel 	u32	vmolr, vec_bit, vec_reg, mta_reg;
550248056c88SJack F Vogel 
550348056c88SJack F Vogel 	entries = (msg[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT;
550448056c88SJack F Vogel 	entries = min(entries, IXGBE_MAX_VF_MC);
550548056c88SJack F Vogel 
550648056c88SJack F Vogel 	vmolr = IXGBE_READ_REG(&adapter->hw, IXGBE_VMOLR(vf->pool));
550748056c88SJack F Vogel 
550848056c88SJack F Vogel 	vf->num_mc_hashes = entries;
550948056c88SJack F Vogel 
551048056c88SJack F Vogel 	/* Set the appropriate MTA bit */
551148056c88SJack F Vogel 	for (int i = 0; i < entries; i++) {
551248056c88SJack F Vogel 		vf->mc_hash[i] = list[i];
551348056c88SJack F Vogel 		vec_reg = (vf->mc_hash[i] >> 5) & 0x7F;
551448056c88SJack F Vogel                 vec_bit = vf->mc_hash[i] & 0x1F;
551548056c88SJack F Vogel                 mta_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_MTA(vec_reg));
551648056c88SJack F Vogel                 mta_reg |= (1 << vec_bit);
551748056c88SJack F Vogel                 IXGBE_WRITE_REG(&adapter->hw, IXGBE_MTA(vec_reg), mta_reg);
551848056c88SJack F Vogel         }
551948056c88SJack F Vogel 
552048056c88SJack F Vogel 	vmolr |= IXGBE_VMOLR_ROMPE;
552148056c88SJack F Vogel 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_VMOLR(vf->pool), vmolr);
552248056c88SJack F Vogel 	ixgbe_send_vf_ack(adapter, vf, msg[0]);
552348056c88SJack F Vogel 	return;
552448056c88SJack F Vogel }
552548056c88SJack F Vogel 
552648056c88SJack F Vogel 
552748056c88SJack F Vogel static void
552848056c88SJack F Vogel ixgbe_vf_set_vlan(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg)
552948056c88SJack F Vogel {
553048056c88SJack F Vogel 	struct ixgbe_hw *hw;
553148056c88SJack F Vogel 	int enable;
553248056c88SJack F Vogel 	uint16_t tag;
553348056c88SJack F Vogel 
553448056c88SJack F Vogel 	hw = &adapter->hw;
553548056c88SJack F Vogel 	enable = IXGBE_VT_MSGINFO(msg[0]);
553648056c88SJack F Vogel 	tag = msg[1] & IXGBE_VLVF_VLANID_MASK;
553748056c88SJack F Vogel 
553848056c88SJack F Vogel 	if (!(vf->flags & IXGBE_VF_CAP_VLAN)) {
553948056c88SJack F Vogel 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
554048056c88SJack F Vogel 		return;
554148056c88SJack F Vogel 	}
554248056c88SJack F Vogel 
554348056c88SJack F Vogel 	/* It is illegal to enable vlan tag 0. */
554448056c88SJack F Vogel 	if (tag == 0 && enable != 0){
554548056c88SJack F Vogel 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
554648056c88SJack F Vogel 		return;
554748056c88SJack F Vogel 	}
554848056c88SJack F Vogel 
554948056c88SJack F Vogel 	ixgbe_set_vfta(hw, tag, vf->pool, enable);
555048056c88SJack F Vogel 	ixgbe_send_vf_ack(adapter, vf, msg[0]);
555148056c88SJack F Vogel }
555248056c88SJack F Vogel 
555348056c88SJack F Vogel 
555448056c88SJack F Vogel static void
555548056c88SJack F Vogel ixgbe_vf_set_lpe(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg)
555648056c88SJack F Vogel {
555748056c88SJack F Vogel 	struct ixgbe_hw *hw;
555848056c88SJack F Vogel 	uint32_t vf_max_size, pf_max_size, mhadd;
555948056c88SJack F Vogel 
556048056c88SJack F Vogel 	hw = &adapter->hw;
556148056c88SJack F Vogel 	vf_max_size = msg[1];
556248056c88SJack F Vogel 
556348056c88SJack F Vogel 	if (vf_max_size < ETHER_CRC_LEN) {
556448056c88SJack F Vogel 		/* We intentionally ACK invalid LPE requests. */
556548056c88SJack F Vogel 		ixgbe_send_vf_ack(adapter, vf, msg[0]);
556648056c88SJack F Vogel 		return;
556748056c88SJack F Vogel 	}
556848056c88SJack F Vogel 
556948056c88SJack F Vogel 	vf_max_size -= ETHER_CRC_LEN;
557048056c88SJack F Vogel 
557148056c88SJack F Vogel 	if (vf_max_size > IXGBE_MAX_FRAME_SIZE) {
557248056c88SJack F Vogel 		/* We intentionally ACK invalid LPE requests. */
557348056c88SJack F Vogel 		ixgbe_send_vf_ack(adapter, vf, msg[0]);
557448056c88SJack F Vogel 		return;
557548056c88SJack F Vogel 	}
557648056c88SJack F Vogel 
557748056c88SJack F Vogel 	vf->max_frame_size = vf_max_size;
557848056c88SJack F Vogel 	ixgbe_update_max_frame(adapter, vf->max_frame_size);
557948056c88SJack F Vogel 
558048056c88SJack F Vogel 	/*
558148056c88SJack F Vogel 	 * We might have to disable reception to this VF if the frame size is
558248056c88SJack F Vogel 	 * not compatible with the config on the PF.
558348056c88SJack F Vogel 	 */
558448056c88SJack F Vogel 	ixgbe_vf_enable_receive(adapter, vf);
558548056c88SJack F Vogel 
558648056c88SJack F Vogel 	mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
558748056c88SJack F Vogel 	pf_max_size = (mhadd & IXGBE_MHADD_MFS_MASK) >> IXGBE_MHADD_MFS_SHIFT;
558848056c88SJack F Vogel 
558948056c88SJack F Vogel 	if (pf_max_size < adapter->max_frame_size) {
559048056c88SJack F Vogel 		mhadd &= ~IXGBE_MHADD_MFS_MASK;
559148056c88SJack F Vogel 		mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT;
559248056c88SJack F Vogel 		IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
559348056c88SJack F Vogel 	}
559448056c88SJack F Vogel 
559548056c88SJack F Vogel 	ixgbe_send_vf_ack(adapter, vf, msg[0]);
559648056c88SJack F Vogel }
559748056c88SJack F Vogel 
559848056c88SJack F Vogel 
559948056c88SJack F Vogel static void
560048056c88SJack F Vogel ixgbe_vf_set_macvlan(struct adapter *adapter, struct ixgbe_vf *vf,
560148056c88SJack F Vogel     uint32_t *msg)
560248056c88SJack F Vogel {
560348056c88SJack F Vogel 	//XXX implement this
560448056c88SJack F Vogel 	ixgbe_send_vf_nack(adapter, vf, msg[0]);
560548056c88SJack F Vogel }
560648056c88SJack F Vogel 
560748056c88SJack F Vogel 
560848056c88SJack F Vogel static void
560948056c88SJack F Vogel ixgbe_vf_api_negotiate(struct adapter *adapter, struct ixgbe_vf *vf,
561048056c88SJack F Vogel     uint32_t *msg)
561148056c88SJack F Vogel {
561248056c88SJack F Vogel 
5613c8ed84dbSPatrick Kelsey 	switch (msg[1]) {
561448056c88SJack F Vogel 	case IXGBE_API_VER_1_0:
561548056c88SJack F Vogel 	case IXGBE_API_VER_1_1:
5616c8ed84dbSPatrick Kelsey 		vf->api_ver = msg[1];
561748056c88SJack F Vogel 		ixgbe_send_vf_ack(adapter, vf, msg[0]);
561848056c88SJack F Vogel 		break;
561948056c88SJack F Vogel 	default:
562048056c88SJack F Vogel 		vf->api_ver = IXGBE_API_VER_UNKNOWN;
562148056c88SJack F Vogel 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
562248056c88SJack F Vogel 		break;
562348056c88SJack F Vogel 	}
562448056c88SJack F Vogel }
562548056c88SJack F Vogel 
562648056c88SJack F Vogel 
562748056c88SJack F Vogel static void
562848056c88SJack F Vogel ixgbe_vf_get_queues(struct adapter *adapter, struct ixgbe_vf *vf,
562948056c88SJack F Vogel     uint32_t *msg)
563048056c88SJack F Vogel {
563148056c88SJack F Vogel 	struct ixgbe_hw *hw;
563248056c88SJack F Vogel 	uint32_t resp[IXGBE_VF_GET_QUEUES_RESP_LEN];
563348056c88SJack F Vogel 	int num_queues;
563448056c88SJack F Vogel 
563548056c88SJack F Vogel 	hw = &adapter->hw;
563648056c88SJack F Vogel 
563748056c88SJack F Vogel 	/* GET_QUEUES is not supported on pre-1.1 APIs. */
563848056c88SJack F Vogel 	switch (msg[0]) {
563948056c88SJack F Vogel 	case IXGBE_API_VER_1_0:
564048056c88SJack F Vogel 	case IXGBE_API_VER_UNKNOWN:
564148056c88SJack F Vogel 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
564248056c88SJack F Vogel 		return;
564348056c88SJack F Vogel 	}
564448056c88SJack F Vogel 
564548056c88SJack F Vogel 	resp[0] = IXGBE_VF_GET_QUEUES | IXGBE_VT_MSGTYPE_ACK |
564648056c88SJack F Vogel 	    IXGBE_VT_MSGTYPE_CTS;
564748056c88SJack F Vogel 
564848056c88SJack F Vogel 	num_queues = ixgbe_vf_queues(ixgbe_get_iov_mode(adapter));
564948056c88SJack F Vogel 	resp[IXGBE_VF_TX_QUEUES] = num_queues;
565048056c88SJack F Vogel 	resp[IXGBE_VF_RX_QUEUES] = num_queues;
565148056c88SJack F Vogel 	resp[IXGBE_VF_TRANS_VLAN] = (vf->default_vlan != 0);
565248056c88SJack F Vogel 	resp[IXGBE_VF_DEF_QUEUE] = 0;
565348056c88SJack F Vogel 
565448056c88SJack F Vogel 	ixgbe_write_mbx(hw, resp, IXGBE_VF_GET_QUEUES_RESP_LEN, vf->pool);
565548056c88SJack F Vogel }
565648056c88SJack F Vogel 
565748056c88SJack F Vogel 
565848056c88SJack F Vogel static void
565948056c88SJack F Vogel ixgbe_process_vf_msg(struct adapter *adapter, struct ixgbe_vf *vf)
566048056c88SJack F Vogel {
566148056c88SJack F Vogel 	struct ixgbe_hw *hw;
566248056c88SJack F Vogel 	uint32_t msg[IXGBE_VFMAILBOX_SIZE];
566348056c88SJack F Vogel 	int error;
566448056c88SJack F Vogel 
566548056c88SJack F Vogel 	hw = &adapter->hw;
566648056c88SJack F Vogel 
566748056c88SJack F Vogel 	error = ixgbe_read_mbx(hw, msg, IXGBE_VFMAILBOX_SIZE, vf->pool);
566848056c88SJack F Vogel 
566948056c88SJack F Vogel 	if (error != 0)
567048056c88SJack F Vogel 		return;
567148056c88SJack F Vogel 
567248056c88SJack F Vogel 	CTR3(KTR_MALLOC, "%s: received msg %x from %d",
567348056c88SJack F Vogel 	    adapter->ifp->if_xname, msg[0], vf->pool);
567448056c88SJack F Vogel 	if (msg[0] == IXGBE_VF_RESET) {
567548056c88SJack F Vogel 		ixgbe_vf_reset_msg(adapter, vf, msg);
567648056c88SJack F Vogel 		return;
567748056c88SJack F Vogel 	}
567848056c88SJack F Vogel 
567948056c88SJack F Vogel 	if (!(vf->flags & IXGBE_VF_CTS)) {
568048056c88SJack F Vogel 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
568148056c88SJack F Vogel 		return;
568248056c88SJack F Vogel 	}
568348056c88SJack F Vogel 
568448056c88SJack F Vogel 	switch (msg[0] & IXGBE_VT_MSG_MASK) {
568548056c88SJack F Vogel 	case IXGBE_VF_SET_MAC_ADDR:
568648056c88SJack F Vogel 		ixgbe_vf_set_mac(adapter, vf, msg);
568748056c88SJack F Vogel 		break;
568848056c88SJack F Vogel 	case IXGBE_VF_SET_MULTICAST:
568948056c88SJack F Vogel 		ixgbe_vf_set_mc_addr(adapter, vf, msg);
569048056c88SJack F Vogel 		break;
569148056c88SJack F Vogel 	case IXGBE_VF_SET_VLAN:
569248056c88SJack F Vogel 		ixgbe_vf_set_vlan(adapter, vf, msg);
569348056c88SJack F Vogel 		break;
569448056c88SJack F Vogel 	case IXGBE_VF_SET_LPE:
569548056c88SJack F Vogel 		ixgbe_vf_set_lpe(adapter, vf, msg);
569648056c88SJack F Vogel 		break;
569748056c88SJack F Vogel 	case IXGBE_VF_SET_MACVLAN:
569848056c88SJack F Vogel 		ixgbe_vf_set_macvlan(adapter, vf, msg);
569948056c88SJack F Vogel 		break;
570048056c88SJack F Vogel 	case IXGBE_VF_API_NEGOTIATE:
570148056c88SJack F Vogel 		ixgbe_vf_api_negotiate(adapter, vf, msg);
570248056c88SJack F Vogel 		break;
570348056c88SJack F Vogel 	case IXGBE_VF_GET_QUEUES:
570448056c88SJack F Vogel 		ixgbe_vf_get_queues(adapter, vf, msg);
570548056c88SJack F Vogel 		break;
570648056c88SJack F Vogel 	default:
570748056c88SJack F Vogel 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
570848056c88SJack F Vogel 	}
570948056c88SJack F Vogel }
571048056c88SJack F Vogel 
571148056c88SJack F Vogel 
571248056c88SJack F Vogel /*
571348056c88SJack F Vogel  * Tasklet for handling VF -> PF mailbox messages.
571448056c88SJack F Vogel  */
571548056c88SJack F Vogel static void
571648056c88SJack F Vogel ixgbe_handle_mbx(void *context, int pending)
571748056c88SJack F Vogel {
571848056c88SJack F Vogel 	struct adapter *adapter;
571948056c88SJack F Vogel 	struct ixgbe_hw *hw;
572048056c88SJack F Vogel 	struct ixgbe_vf *vf;
572148056c88SJack F Vogel 	int i;
572248056c88SJack F Vogel 
572348056c88SJack F Vogel 	adapter = context;
572448056c88SJack F Vogel 	hw = &adapter->hw;
572548056c88SJack F Vogel 
572648056c88SJack F Vogel 	IXGBE_CORE_LOCK(adapter);
572748056c88SJack F Vogel 	for (i = 0; i < adapter->num_vfs; i++) {
572848056c88SJack F Vogel 		vf = &adapter->vfs[i];
572948056c88SJack F Vogel 
573048056c88SJack F Vogel 		if (vf->flags & IXGBE_VF_ACTIVE) {
573148056c88SJack F Vogel 			if (ixgbe_check_for_rst(hw, vf->pool) == 0)
573248056c88SJack F Vogel 				ixgbe_process_vf_reset(adapter, vf);
573348056c88SJack F Vogel 
573448056c88SJack F Vogel 			if (ixgbe_check_for_msg(hw, vf->pool) == 0)
573548056c88SJack F Vogel 				ixgbe_process_vf_msg(adapter, vf);
573648056c88SJack F Vogel 
573748056c88SJack F Vogel 			if (ixgbe_check_for_ack(hw, vf->pool) == 0)
573848056c88SJack F Vogel 				ixgbe_process_vf_ack(adapter, vf);
573948056c88SJack F Vogel 		}
574048056c88SJack F Vogel 	}
574148056c88SJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
574248056c88SJack F Vogel }
574348056c88SJack F Vogel 
574448056c88SJack F Vogel 
574548056c88SJack F Vogel static int
574648056c88SJack F Vogel ixgbe_init_iov(device_t dev, u16 num_vfs, const nvlist_t *config)
574748056c88SJack F Vogel {
574848056c88SJack F Vogel 	struct adapter *adapter;
574948056c88SJack F Vogel 	enum ixgbe_iov_mode mode;
575048056c88SJack F Vogel 
575148056c88SJack F Vogel 	adapter = device_get_softc(dev);
575248056c88SJack F Vogel 	adapter->num_vfs = num_vfs;
575348056c88SJack F Vogel 	mode = ixgbe_get_iov_mode(adapter);
575448056c88SJack F Vogel 
575548056c88SJack F Vogel 	if (num_vfs > ixgbe_max_vfs(mode)) {
575648056c88SJack F Vogel 		adapter->num_vfs = 0;
575748056c88SJack F Vogel 		return (ENOSPC);
575848056c88SJack F Vogel 	}
575948056c88SJack F Vogel 
576048056c88SJack F Vogel 	IXGBE_CORE_LOCK(adapter);
576148056c88SJack F Vogel 
576248056c88SJack F Vogel 	adapter->vfs = malloc(sizeof(*adapter->vfs) * num_vfs, M_IXGBE,
576348056c88SJack F Vogel 	    M_NOWAIT | M_ZERO);
576448056c88SJack F Vogel 
576548056c88SJack F Vogel 	if (adapter->vfs == NULL) {
576648056c88SJack F Vogel 		adapter->num_vfs = 0;
576748056c88SJack F Vogel 		IXGBE_CORE_UNLOCK(adapter);
576848056c88SJack F Vogel 		return (ENOMEM);
576948056c88SJack F Vogel 	}
577048056c88SJack F Vogel 
577148056c88SJack F Vogel 	ixgbe_init_locked(adapter);
577248056c88SJack F Vogel 
577348056c88SJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
577448056c88SJack F Vogel 
577548056c88SJack F Vogel 	return (0);
577648056c88SJack F Vogel }
577748056c88SJack F Vogel 
577848056c88SJack F Vogel 
577948056c88SJack F Vogel static void
578048056c88SJack F Vogel ixgbe_uninit_iov(device_t dev)
578148056c88SJack F Vogel {
578248056c88SJack F Vogel 	struct ixgbe_hw *hw;
578348056c88SJack F Vogel 	struct adapter *adapter;
578448056c88SJack F Vogel 	uint32_t pf_reg, vf_reg;
578548056c88SJack F Vogel 
578648056c88SJack F Vogel 	adapter = device_get_softc(dev);
578748056c88SJack F Vogel 	hw = &adapter->hw;
578848056c88SJack F Vogel 
578948056c88SJack F Vogel 	IXGBE_CORE_LOCK(adapter);
579048056c88SJack F Vogel 
579148056c88SJack F Vogel 	/* Enable rx/tx for the PF and disable it for all VFs. */
579248056c88SJack F Vogel 	pf_reg = IXGBE_VF_INDEX(adapter->pool);
579348056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VFRE(pf_reg),
579448056c88SJack F Vogel 	    IXGBE_VF_BIT(adapter->pool));
579548056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VFTE(pf_reg),
579648056c88SJack F Vogel 	    IXGBE_VF_BIT(adapter->pool));
579748056c88SJack F Vogel 
579848056c88SJack F Vogel 	if (pf_reg == 0)
579948056c88SJack F Vogel 		vf_reg = 1;
580048056c88SJack F Vogel 	else
580148056c88SJack F Vogel 		vf_reg = 0;
580248056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 0);
580348056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 0);
580448056c88SJack F Vogel 
580548056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, 0);
580648056c88SJack F Vogel 
580748056c88SJack F Vogel 	free(adapter->vfs, M_IXGBE);
580848056c88SJack F Vogel 	adapter->vfs = NULL;
580948056c88SJack F Vogel 	adapter->num_vfs = 0;
581048056c88SJack F Vogel 
581148056c88SJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
581248056c88SJack F Vogel }
581348056c88SJack F Vogel 
581448056c88SJack F Vogel 
581548056c88SJack F Vogel static void
581648056c88SJack F Vogel ixgbe_initialize_iov(struct adapter *adapter)
581748056c88SJack F Vogel {
581848056c88SJack F Vogel 	struct ixgbe_hw *hw = &adapter->hw;
581948056c88SJack F Vogel 	uint32_t mrqc, mtqc, vt_ctl, vf_reg, gcr_ext, gpie;
582048056c88SJack F Vogel 	enum ixgbe_iov_mode mode;
582148056c88SJack F Vogel 	int i;
582248056c88SJack F Vogel 
582348056c88SJack F Vogel 	mode = ixgbe_get_iov_mode(adapter);
582448056c88SJack F Vogel 	if (mode == IXGBE_NO_VM)
582548056c88SJack F Vogel 		return;
582648056c88SJack F Vogel 
582748056c88SJack F Vogel 	IXGBE_CORE_LOCK_ASSERT(adapter);
582848056c88SJack F Vogel 
582948056c88SJack F Vogel 	mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC);
583048056c88SJack F Vogel 	mrqc &= ~IXGBE_MRQC_MRQE_MASK;
583148056c88SJack F Vogel 
583248056c88SJack F Vogel 	switch (mode) {
583348056c88SJack F Vogel 	case IXGBE_64_VM:
583448056c88SJack F Vogel 		mrqc |= IXGBE_MRQC_VMDQRSS64EN;
583548056c88SJack F Vogel 		break;
583648056c88SJack F Vogel 	case IXGBE_32_VM:
583748056c88SJack F Vogel 		mrqc |= IXGBE_MRQC_VMDQRSS32EN;
583848056c88SJack F Vogel 		break;
583948056c88SJack F Vogel 	default:
584048056c88SJack F Vogel 		panic("Unexpected SR-IOV mode %d", mode);
584148056c88SJack F Vogel 	}
584248056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
584348056c88SJack F Vogel 
584448056c88SJack F Vogel 	mtqc = IXGBE_MTQC_VT_ENA;
584548056c88SJack F Vogel 	switch (mode) {
584648056c88SJack F Vogel 	case IXGBE_64_VM:
584748056c88SJack F Vogel 		mtqc |= IXGBE_MTQC_64VF;
584848056c88SJack F Vogel 		break;
584948056c88SJack F Vogel 	case IXGBE_32_VM:
585048056c88SJack F Vogel 		mtqc |= IXGBE_MTQC_32VF;
585148056c88SJack F Vogel 		break;
585248056c88SJack F Vogel 	default:
585348056c88SJack F Vogel 		panic("Unexpected SR-IOV mode %d", mode);
585448056c88SJack F Vogel 	}
585548056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_MTQC, mtqc);
585648056c88SJack F Vogel 
585748056c88SJack F Vogel 
585848056c88SJack F Vogel 	gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
585948056c88SJack F Vogel 	gcr_ext |= IXGBE_GCR_EXT_MSIX_EN;
586048056c88SJack F Vogel 	gcr_ext &= ~IXGBE_GCR_EXT_VT_MODE_MASK;
586148056c88SJack F Vogel 	switch (mode) {
586248056c88SJack F Vogel 	case IXGBE_64_VM:
586348056c88SJack F Vogel 		gcr_ext |= IXGBE_GCR_EXT_VT_MODE_64;
586448056c88SJack F Vogel 		break;
586548056c88SJack F Vogel 	case IXGBE_32_VM:
586648056c88SJack F Vogel 		gcr_ext |= IXGBE_GCR_EXT_VT_MODE_32;
586748056c88SJack F Vogel 		break;
586848056c88SJack F Vogel 	default:
586948056c88SJack F Vogel 		panic("Unexpected SR-IOV mode %d", mode);
587048056c88SJack F Vogel 	}
587148056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext);
587248056c88SJack F Vogel 
587348056c88SJack F Vogel 
587448056c88SJack F Vogel 	gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
587548056c88SJack F Vogel 	gcr_ext &= ~IXGBE_GPIE_VTMODE_MASK;
587648056c88SJack F Vogel 	switch (mode) {
587748056c88SJack F Vogel 	case IXGBE_64_VM:
587848056c88SJack F Vogel 		gpie |= IXGBE_GPIE_VTMODE_64;
587948056c88SJack F Vogel 		break;
588048056c88SJack F Vogel 	case IXGBE_32_VM:
588148056c88SJack F Vogel 		gpie |= IXGBE_GPIE_VTMODE_32;
588248056c88SJack F Vogel 		break;
588348056c88SJack F Vogel 	default:
588448056c88SJack F Vogel 		panic("Unexpected SR-IOV mode %d", mode);
588548056c88SJack F Vogel 	}
588648056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
588748056c88SJack F Vogel 
588848056c88SJack F Vogel 	/* Enable rx/tx for the PF. */
588948056c88SJack F Vogel 	vf_reg = IXGBE_VF_INDEX(adapter->pool);
589048056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg),
589148056c88SJack F Vogel 	    IXGBE_VF_BIT(adapter->pool));
589248056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg),
589348056c88SJack F Vogel 	    IXGBE_VF_BIT(adapter->pool));
589448056c88SJack F Vogel 
589548056c88SJack F Vogel 	/* Allow VM-to-VM communication. */
589648056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
589748056c88SJack F Vogel 
589848056c88SJack F Vogel 	vt_ctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
589948056c88SJack F Vogel 	vt_ctl |= (adapter->pool << IXGBE_VT_CTL_POOL_SHIFT);
590048056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vt_ctl);
590148056c88SJack F Vogel 
590248056c88SJack F Vogel 	for (i = 0; i < adapter->num_vfs; i++)
590348056c88SJack F Vogel 		ixgbe_init_vf(adapter, &adapter->vfs[i]);
590448056c88SJack F Vogel }
590548056c88SJack F Vogel 
590648056c88SJack F Vogel 
590748056c88SJack F Vogel /*
590848056c88SJack F Vogel ** Check the max frame setting of all active VF's
590948056c88SJack F Vogel */
591048056c88SJack F Vogel static void
591148056c88SJack F Vogel ixgbe_recalculate_max_frame(struct adapter *adapter)
591248056c88SJack F Vogel {
591348056c88SJack F Vogel 	struct ixgbe_vf *vf;
591448056c88SJack F Vogel 
591548056c88SJack F Vogel 	IXGBE_CORE_LOCK_ASSERT(adapter);
591648056c88SJack F Vogel 
591748056c88SJack F Vogel 	for (int i = 0; i < adapter->num_vfs; i++) {
591848056c88SJack F Vogel 		vf = &adapter->vfs[i];
591948056c88SJack F Vogel 		if (vf->flags & IXGBE_VF_ACTIVE)
592048056c88SJack F Vogel 			ixgbe_update_max_frame(adapter, vf->max_frame_size);
592148056c88SJack F Vogel 	}
592248056c88SJack F Vogel }
592348056c88SJack F Vogel 
592448056c88SJack F Vogel 
592548056c88SJack F Vogel static void
592648056c88SJack F Vogel ixgbe_init_vf(struct adapter *adapter, struct ixgbe_vf *vf)
592748056c88SJack F Vogel {
592848056c88SJack F Vogel 	struct ixgbe_hw *hw;
592948056c88SJack F Vogel 	uint32_t vf_index, pfmbimr;
593048056c88SJack F Vogel 
593148056c88SJack F Vogel 	IXGBE_CORE_LOCK_ASSERT(adapter);
593248056c88SJack F Vogel 
593348056c88SJack F Vogel 	hw = &adapter->hw;
593448056c88SJack F Vogel 
593548056c88SJack F Vogel 	if (!(vf->flags & IXGBE_VF_ACTIVE))
593648056c88SJack F Vogel 		return;
593748056c88SJack F Vogel 
593848056c88SJack F Vogel 	vf_index = IXGBE_VF_INDEX(vf->pool);
593948056c88SJack F Vogel 	pfmbimr = IXGBE_READ_REG(hw, IXGBE_PFMBIMR(vf_index));
594048056c88SJack F Vogel 	pfmbimr |= IXGBE_VF_BIT(vf->pool);
594148056c88SJack F Vogel 	IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr);
594248056c88SJack F Vogel 
594348056c88SJack F Vogel 	ixgbe_vf_set_default_vlan(adapter, vf, vf->vlan_tag);
594448056c88SJack F Vogel 
594548056c88SJack F Vogel 	// XXX multicast addresses
594648056c88SJack F Vogel 
594748056c88SJack F Vogel 	if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) {
594848056c88SJack F Vogel 		ixgbe_set_rar(&adapter->hw, vf->rar_index,
594948056c88SJack F Vogel 		    vf->ether_addr, vf->pool, TRUE);
595048056c88SJack F Vogel 	}
595148056c88SJack F Vogel 
595248056c88SJack F Vogel 	ixgbe_vf_enable_transmit(adapter, vf);
595348056c88SJack F Vogel 	ixgbe_vf_enable_receive(adapter, vf);
595448056c88SJack F Vogel 
595548056c88SJack F Vogel 	ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG);
595648056c88SJack F Vogel }
595748056c88SJack F Vogel 
595848056c88SJack F Vogel static int
595948056c88SJack F Vogel ixgbe_add_vf(device_t dev, u16 vfnum, const nvlist_t *config)
596048056c88SJack F Vogel {
596148056c88SJack F Vogel 	struct adapter *adapter;
596248056c88SJack F Vogel 	struct ixgbe_vf *vf;
596348056c88SJack F Vogel 	const void *mac;
596448056c88SJack F Vogel 
596548056c88SJack F Vogel 	adapter = device_get_softc(dev);
596648056c88SJack F Vogel 
596748056c88SJack F Vogel 	KASSERT(vfnum < adapter->num_vfs, ("VF index %d is out of range %d",
596848056c88SJack F Vogel 	    vfnum, adapter->num_vfs));
596948056c88SJack F Vogel 
597048056c88SJack F Vogel 	IXGBE_CORE_LOCK(adapter);
597148056c88SJack F Vogel 	vf = &adapter->vfs[vfnum];
597248056c88SJack F Vogel 	vf->pool= vfnum;
597348056c88SJack F Vogel 
597448056c88SJack F Vogel 	/* RAR[0] is used by the PF so use vfnum + 1 for VF RAR. */
597548056c88SJack F Vogel 	vf->rar_index = vfnum + 1;
597648056c88SJack F Vogel 	vf->default_vlan = 0;
597748056c88SJack F Vogel 	vf->max_frame_size = ETHER_MAX_LEN;
597848056c88SJack F Vogel 	ixgbe_update_max_frame(adapter, vf->max_frame_size);
597948056c88SJack F Vogel 
598048056c88SJack F Vogel 	if (nvlist_exists_binary(config, "mac-addr")) {
598148056c88SJack F Vogel 		mac = nvlist_get_binary(config, "mac-addr", NULL);
598248056c88SJack F Vogel 		bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN);
598348056c88SJack F Vogel 		if (nvlist_get_bool(config, "allow-set-mac"))
598448056c88SJack F Vogel 			vf->flags |= IXGBE_VF_CAP_MAC;
598548056c88SJack F Vogel 	} else
598648056c88SJack F Vogel 		/*
598748056c88SJack F Vogel 		 * If the administrator has not specified a MAC address then
598848056c88SJack F Vogel 		 * we must allow the VF to choose one.
598948056c88SJack F Vogel 		 */
599048056c88SJack F Vogel 		vf->flags |= IXGBE_VF_CAP_MAC;
599148056c88SJack F Vogel 
599248056c88SJack F Vogel 	vf->flags = IXGBE_VF_ACTIVE;
599348056c88SJack F Vogel 
599448056c88SJack F Vogel 	ixgbe_init_vf(adapter, vf);
599548056c88SJack F Vogel 	IXGBE_CORE_UNLOCK(adapter);
599648056c88SJack F Vogel 
599748056c88SJack F Vogel 	return (0);
599848056c88SJack F Vogel }
599948056c88SJack F Vogel #endif /* PCI_IOV */
6000758cc3dcSJack F Vogel 
6001