xref: /freebsd/sys/dev/ixl/ixl_pf_main.c (revision 38663adb61440bd659fb457909782b71ba8806fa)
14294f337SSean Bruno /******************************************************************************
24294f337SSean Bruno 
3f4cc2d17SEric Joyner   Copyright (c) 2013-2018, Intel Corporation
44294f337SSean Bruno   All rights reserved.
54294f337SSean Bruno 
64294f337SSean Bruno   Redistribution and use in source and binary forms, with or without
74294f337SSean Bruno   modification, are permitted provided that the following conditions are met:
84294f337SSean Bruno 
94294f337SSean Bruno    1. Redistributions of source code must retain the above copyright notice,
104294f337SSean Bruno       this list of conditions and the following disclaimer.
114294f337SSean Bruno 
124294f337SSean Bruno    2. Redistributions in binary form must reproduce the above copyright
134294f337SSean Bruno       notice, this list of conditions and the following disclaimer in the
144294f337SSean Bruno       documentation and/or other materials provided with the distribution.
154294f337SSean Bruno 
164294f337SSean Bruno    3. Neither the name of the Intel Corporation nor the names of its
174294f337SSean Bruno       contributors may be used to endorse or promote products derived from
184294f337SSean Bruno       this software without specific prior written permission.
194294f337SSean Bruno 
204294f337SSean Bruno   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
214294f337SSean Bruno   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224294f337SSean Bruno   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234294f337SSean Bruno   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
244294f337SSean Bruno   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
254294f337SSean Bruno   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
264294f337SSean Bruno   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
274294f337SSean Bruno   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
284294f337SSean Bruno   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
294294f337SSean Bruno   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
304294f337SSean Bruno   POSSIBILITY OF SUCH DAMAGE.
314294f337SSean Bruno 
324294f337SSean Bruno ******************************************************************************/
334294f337SSean Bruno 
344294f337SSean Bruno 
354294f337SSean Bruno #include "ixl_pf.h"
364294f337SSean Bruno 
374294f337SSean Bruno #ifdef PCI_IOV
384294f337SSean Bruno #include "ixl_pf_iov.h"
394294f337SSean Bruno #endif
404294f337SSean Bruno 
41cb6b8299SEric Joyner #ifdef IXL_IW
42cb6b8299SEric Joyner #include "ixl_iw.h"
43cb6b8299SEric Joyner #include "ixl_iw_int.h"
44cb6b8299SEric Joyner #endif
45cb6b8299SEric Joyner 
46cb6b8299SEric Joyner static u8	ixl_convert_sysctl_aq_link_speed(u8, bool);
47ceebc2f3SEric Joyner static void	ixl_sbuf_print_bytes(struct sbuf *, u8 *, int, int, bool);
48b4a7ce06SEric Joyner static const char * ixl_link_speed_string(enum i40e_aq_link_speed);
49b4a7ce06SEric Joyner static u_int	ixl_add_maddr(void *, struct sockaddr_dl *, u_int);
50b4a7ce06SEric Joyner static u_int	ixl_match_maddr(void *, struct sockaddr_dl *, u_int);
51b4a7ce06SEric Joyner static char *	ixl_switch_element_string(struct sbuf *, u8, u16);
52b4a7ce06SEric Joyner static enum ixl_fw_mode ixl_get_fw_mode(struct ixl_pf *);
534294f337SSean Bruno 
544294f337SSean Bruno /* Sysctls */
55ceebc2f3SEric Joyner static int	ixl_sysctl_set_advertise(SYSCTL_HANDLER_ARGS);
56ceebc2f3SEric Joyner static int	ixl_sysctl_supported_speeds(SYSCTL_HANDLER_ARGS);
57ceebc2f3SEric Joyner static int	ixl_sysctl_current_speed(SYSCTL_HANDLER_ARGS);
584294f337SSean Bruno static int	ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS);
594294f337SSean Bruno static int	ixl_sysctl_unallocated_queues(SYSCTL_HANDLER_ARGS);
604294f337SSean Bruno static int	ixl_sysctl_pf_tx_itr(SYSCTL_HANDLER_ARGS);
614294f337SSean Bruno static int	ixl_sysctl_pf_rx_itr(SYSCTL_HANDLER_ARGS);
624294f337SSean Bruno 
632984a8ddSEric Joyner static int	ixl_sysctl_eee_enable(SYSCTL_HANDLER_ARGS);
6421802a12SKrzysztof Galazka static int	ixl_sysctl_set_link_active(SYSCTL_HANDLER_ARGS);
652984a8ddSEric Joyner 
664294f337SSean Bruno /* Debug Sysctls */
674294f337SSean Bruno static int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
684294f337SSean Bruno static int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
69a146207dSPiotr Kubaj static int	ixl_sysctl_phy_statistics(SYSCTL_HANDLER_ARGS);
704294f337SSean Bruno static int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
714294f337SSean Bruno static int	ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS);
724294f337SSean Bruno static int	ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS);
73fa6662b3SLutz Donnerhacke static int	ixl_sysctl_switch_vlans(SYSCTL_HANDLER_ARGS);
744294f337SSean Bruno static int	ixl_sysctl_hkey(SYSCTL_HANDLER_ARGS);
75cb6b8299SEric Joyner static int	ixl_sysctl_hena(SYSCTL_HANDLER_ARGS);
764294f337SSean Bruno static int	ixl_sysctl_hlut(SYSCTL_HANDLER_ARGS);
77cb6b8299SEric Joyner static int	ixl_sysctl_fw_link_management(SYSCTL_HANDLER_ARGS);
78cb6b8299SEric Joyner static int	ixl_sysctl_read_i2c_byte(SYSCTL_HANDLER_ARGS);
79cb6b8299SEric Joyner static int	ixl_sysctl_write_i2c_byte(SYSCTL_HANDLER_ARGS);
80cb6b8299SEric Joyner static int	ixl_sysctl_fec_fc_ability(SYSCTL_HANDLER_ARGS);
81cb6b8299SEric Joyner static int	ixl_sysctl_fec_rs_ability(SYSCTL_HANDLER_ARGS);
82cb6b8299SEric Joyner static int	ixl_sysctl_fec_fc_request(SYSCTL_HANDLER_ARGS);
83cb6b8299SEric Joyner static int	ixl_sysctl_fec_rs_request(SYSCTL_HANDLER_ARGS);
84cb6b8299SEric Joyner static int	ixl_sysctl_fec_auto_enable(SYSCTL_HANDLER_ARGS);
85ceebc2f3SEric Joyner static int	ixl_sysctl_dump_debug_data(SYSCTL_HANDLER_ARGS);
86ceebc2f3SEric Joyner static int	ixl_sysctl_fw_lldp(SYSCTL_HANDLER_ARGS);
87b4a7ce06SEric Joyner static int	ixl_sysctl_read_i2c_diag_data(SYSCTL_HANDLER_ARGS);
88b4a7ce06SEric Joyner 
89b4a7ce06SEric Joyner /* Debug Sysctls */
901031d839SEric Joyner static int	ixl_sysctl_do_pf_reset(SYSCTL_HANDLER_ARGS);
911031d839SEric Joyner static int	ixl_sysctl_do_core_reset(SYSCTL_HANDLER_ARGS);
921031d839SEric Joyner static int	ixl_sysctl_do_global_reset(SYSCTL_HANDLER_ARGS);
931031d839SEric Joyner static int	ixl_sysctl_queue_interrupt_table(SYSCTL_HANDLER_ARGS);
944fecb701SKrzysztof Galazka static int	ixl_sysctl_debug_queue_int_ctln(SYSCTL_HANDLER_ARGS);
95cb6b8299SEric Joyner #ifdef IXL_DEBUG
96cb6b8299SEric Joyner static int	ixl_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS);
97cb6b8299SEric Joyner static int	ixl_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS);
98cb6b8299SEric Joyner #endif
99cb6b8299SEric Joyner 
100cb6b8299SEric Joyner #ifdef IXL_IW
101cb6b8299SEric Joyner extern int ixl_enable_iwarp;
102ceebc2f3SEric Joyner extern int ixl_limit_iwarp_msix;
103cb6b8299SEric Joyner #endif
1044294f337SSean Bruno 
105b4a7ce06SEric Joyner static const char * const ixl_fc_string[6] = {
10633c66d8aSRyan Libby 	"None",
10733c66d8aSRyan Libby 	"Rx",
10833c66d8aSRyan Libby 	"Tx",
10933c66d8aSRyan Libby 	"Full",
11033c66d8aSRyan Libby 	"Priority",
11133c66d8aSRyan Libby 	"Default"
11233c66d8aSRyan Libby };
11333c66d8aSRyan Libby 
114ceebc2f3SEric Joyner static char *ixl_fec_string[3] = {
115ceebc2f3SEric Joyner        "CL108 RS-FEC",
116ceebc2f3SEric Joyner        "CL74 FC-FEC/BASE-R",
117ceebc2f3SEric Joyner        "None"
118ceebc2f3SEric Joyner };
119ceebc2f3SEric Joyner 
120b8f51b8cSPiotr Kubaj /* Functions for setting and checking driver state. Note the functions take
121b8f51b8cSPiotr Kubaj  * bit positions, not bitmasks. The atomic_set_32 and atomic_clear_32
122b8f51b8cSPiotr Kubaj  * operations require bitmasks. This can easily lead to programming error, so
123b8f51b8cSPiotr Kubaj  * we provide wrapper functions to avoid this.
124b8f51b8cSPiotr Kubaj  */
125b8f51b8cSPiotr Kubaj 
126b8f51b8cSPiotr Kubaj /**
127b8f51b8cSPiotr Kubaj  * ixl_set_state - Set the specified state
128b8f51b8cSPiotr Kubaj  * @s: the state bitmap
129b8f51b8cSPiotr Kubaj  * @bit: the state to set
130b8f51b8cSPiotr Kubaj  *
131b8f51b8cSPiotr Kubaj  * Atomically update the state bitmap with the specified bit set.
132b8f51b8cSPiotr Kubaj  */
133b8f51b8cSPiotr Kubaj inline void
ixl_set_state(volatile u32 * s,enum ixl_state bit)134b8f51b8cSPiotr Kubaj ixl_set_state(volatile u32 *s, enum ixl_state bit)
135b8f51b8cSPiotr Kubaj {
136b8f51b8cSPiotr Kubaj 	/* atomic_set_32 expects a bitmask */
137b8f51b8cSPiotr Kubaj 	atomic_set_32(s, BIT(bit));
138b8f51b8cSPiotr Kubaj }
139b8f51b8cSPiotr Kubaj 
140b8f51b8cSPiotr Kubaj /**
141b8f51b8cSPiotr Kubaj  * ixl_clear_state - Clear the specified state
142b8f51b8cSPiotr Kubaj  * @s: the state bitmap
143b8f51b8cSPiotr Kubaj  * @bit: the state to clear
144b8f51b8cSPiotr Kubaj  *
145b8f51b8cSPiotr Kubaj  * Atomically update the state bitmap with the specified bit cleared.
146b8f51b8cSPiotr Kubaj  */
147b8f51b8cSPiotr Kubaj inline void
ixl_clear_state(volatile u32 * s,enum ixl_state bit)148b8f51b8cSPiotr Kubaj ixl_clear_state(volatile u32 *s, enum ixl_state bit)
149b8f51b8cSPiotr Kubaj {
150b8f51b8cSPiotr Kubaj 	/* atomic_clear_32 expects a bitmask */
151b8f51b8cSPiotr Kubaj 	atomic_clear_32(s, BIT(bit));
152b8f51b8cSPiotr Kubaj }
153b8f51b8cSPiotr Kubaj 
154b8f51b8cSPiotr Kubaj /**
155b8f51b8cSPiotr Kubaj  * ixl_test_state - Test the specified state
156b8f51b8cSPiotr Kubaj  * @s: the state bitmap
157b8f51b8cSPiotr Kubaj  * @bit: the bit to test
158b8f51b8cSPiotr Kubaj  *
159b8f51b8cSPiotr Kubaj  * Return true if the state is set, false otherwise. Use this only if the flow
160b8f51b8cSPiotr Kubaj  * does not need to update the state. If you must update the state as well,
161b8f51b8cSPiotr Kubaj  * prefer ixl_testandset_state.
162b8f51b8cSPiotr Kubaj  */
163b8f51b8cSPiotr Kubaj inline bool
ixl_test_state(volatile u32 * s,enum ixl_state bit)164b8f51b8cSPiotr Kubaj ixl_test_state(volatile u32 *s, enum ixl_state bit)
165b8f51b8cSPiotr Kubaj {
166b8f51b8cSPiotr Kubaj 	return !!(*s & BIT(bit));
167b8f51b8cSPiotr Kubaj }
168b8f51b8cSPiotr Kubaj 
169b8f51b8cSPiotr Kubaj /**
170b8f51b8cSPiotr Kubaj  * ixl_testandset_state - Test and set the specified state
171b8f51b8cSPiotr Kubaj  * @s: the state bitmap
172b8f51b8cSPiotr Kubaj  * @bit: the bit to test
173b8f51b8cSPiotr Kubaj  *
174b8f51b8cSPiotr Kubaj  * Atomically update the state bitmap, setting the specified bit. Returns the
175b8f51b8cSPiotr Kubaj  * previous value of the bit.
176b8f51b8cSPiotr Kubaj  */
177b8f51b8cSPiotr Kubaj inline u32
ixl_testandset_state(volatile u32 * s,enum ixl_state bit)178b8f51b8cSPiotr Kubaj ixl_testandset_state(volatile u32 *s, enum ixl_state bit)
179b8f51b8cSPiotr Kubaj {
180b8f51b8cSPiotr Kubaj 	/* atomic_testandset_32 expects a bit position, as opposed to bitmask
181b8f51b8cSPiotr Kubaj 	expected by other atomic functions */
182b8f51b8cSPiotr Kubaj 	return atomic_testandset_32(s, bit);
183b8f51b8cSPiotr Kubaj }
184b8f51b8cSPiotr Kubaj 
18533c66d8aSRyan Libby MALLOC_DEFINE(M_IXL, "ixl", "ixl driver allocations");
18633c66d8aSRyan Libby 
1874294f337SSean Bruno /*
1884294f337SSean Bruno ** Put the FW, API, NVM, EEtrackID, and OEM version information into a string
1894294f337SSean Bruno */
1904294f337SSean Bruno void
ixl_nvm_version_str(struct i40e_hw * hw,struct sbuf * buf)1914294f337SSean Bruno ixl_nvm_version_str(struct i40e_hw *hw, struct sbuf *buf)
1924294f337SSean Bruno {
1934294f337SSean Bruno 	u8 oem_ver = (u8)(hw->nvm.oem_ver >> 24);
1944294f337SSean Bruno 	u16 oem_build = (u16)((hw->nvm.oem_ver >> 16) & 0xFFFF);
1954294f337SSean Bruno 	u8 oem_patch = (u8)(hw->nvm.oem_ver & 0xFF);
1964294f337SSean Bruno 
1974294f337SSean Bruno 	sbuf_printf(buf,
1984294f337SSean Bruno 	    "fw %d.%d.%05d api %d.%d nvm %x.%02x etid %08x oem %d.%d.%d",
1994294f337SSean Bruno 	    hw->aq.fw_maj_ver, hw->aq.fw_min_ver, hw->aq.fw_build,
2004294f337SSean Bruno 	    hw->aq.api_maj_ver, hw->aq.api_min_ver,
2014294f337SSean Bruno 	    (hw->nvm.version & IXL_NVM_VERSION_HI_MASK) >>
2024294f337SSean Bruno 	    IXL_NVM_VERSION_HI_SHIFT,
2034294f337SSean Bruno 	    (hw->nvm.version & IXL_NVM_VERSION_LO_MASK) >>
2044294f337SSean Bruno 	    IXL_NVM_VERSION_LO_SHIFT,
2054294f337SSean Bruno 	    hw->nvm.eetrack,
2064294f337SSean Bruno 	    oem_ver, oem_build, oem_patch);
2074294f337SSean Bruno }
2084294f337SSean Bruno 
2094294f337SSean Bruno void
ixl_print_nvm_version(struct ixl_pf * pf)2104294f337SSean Bruno ixl_print_nvm_version(struct ixl_pf *pf)
2114294f337SSean Bruno {
2124294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
2134294f337SSean Bruno 	device_t dev = pf->dev;
2144294f337SSean Bruno 	struct sbuf *sbuf;
2154294f337SSean Bruno 
2164294f337SSean Bruno 	sbuf = sbuf_new_auto();
2174294f337SSean Bruno 	ixl_nvm_version_str(hw, sbuf);
2184294f337SSean Bruno 	sbuf_finish(sbuf);
2194294f337SSean Bruno 	device_printf(dev, "%s\n", sbuf_data(sbuf));
2204294f337SSean Bruno 	sbuf_delete(sbuf);
2214294f337SSean Bruno }
2224294f337SSean Bruno 
223b4a7ce06SEric Joyner /**
224b4a7ce06SEric Joyner  * ixl_get_fw_mode - Check the state of FW
225b4a7ce06SEric Joyner  * @hw: device hardware structure
226b4a7ce06SEric Joyner  *
227b4a7ce06SEric Joyner  * Identify state of FW. It might be in a recovery mode
228b4a7ce06SEric Joyner  * which limits functionality and requires special handling
229b4a7ce06SEric Joyner  * from the driver.
230b4a7ce06SEric Joyner  *
231b4a7ce06SEric Joyner  * @returns FW mode (normal, recovery, unexpected EMP reset)
232b4a7ce06SEric Joyner  */
233b4a7ce06SEric Joyner static enum ixl_fw_mode
ixl_get_fw_mode(struct ixl_pf * pf)234b4a7ce06SEric Joyner ixl_get_fw_mode(struct ixl_pf *pf)
2354294f337SSean Bruno {
2364294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
237b4a7ce06SEric Joyner 	enum ixl_fw_mode fw_mode = IXL_FW_MODE_NORMAL;
238b4a7ce06SEric Joyner 	u32 fwsts;
2394294f337SSean Bruno 
240b4a7ce06SEric Joyner #ifdef IXL_DEBUG
241b4a7ce06SEric Joyner 	if (pf->recovery_mode)
242b4a7ce06SEric Joyner 		return IXL_FW_MODE_RECOVERY;
243b4a7ce06SEric Joyner #endif
244b4a7ce06SEric Joyner 	fwsts = rd32(hw, I40E_GL_FWSTS) & I40E_GL_FWSTS_FWS1B_MASK;
2454294f337SSean Bruno 
246b4a7ce06SEric Joyner 	/* Is set and has one of expected values */
247b4a7ce06SEric Joyner 	if ((fwsts >= I40E_XL710_GL_FWSTS_FWS1B_REC_MOD_CORER_MASK &&
248b4a7ce06SEric Joyner 	    fwsts <= I40E_XL710_GL_FWSTS_FWS1B_REC_MOD_NVM_MASK) ||
249b4a7ce06SEric Joyner 	    fwsts == I40E_X722_GL_FWSTS_FWS1B_REC_MOD_GLOBR_MASK ||
250b4a7ce06SEric Joyner 	    fwsts == I40E_X722_GL_FWSTS_FWS1B_REC_MOD_CORER_MASK)
251b4a7ce06SEric Joyner 		fw_mode = IXL_FW_MODE_RECOVERY;
252b4a7ce06SEric Joyner 	else {
253b4a7ce06SEric Joyner 		if (fwsts > I40E_GL_FWSTS_FWS1B_EMPR_0 &&
254b4a7ce06SEric Joyner 		    fwsts <= I40E_GL_FWSTS_FWS1B_EMPR_10)
255b4a7ce06SEric Joyner 			fw_mode = IXL_FW_MODE_UEMPR;
2564294f337SSean Bruno 	}
257b4a7ce06SEric Joyner 	return (fw_mode);
2584294f337SSean Bruno }
2594294f337SSean Bruno 
260b4a7ce06SEric Joyner /**
261b4a7ce06SEric Joyner  * ixl_pf_reset - Reset the PF
262b4a7ce06SEric Joyner  * @pf: PF structure
263b4a7ce06SEric Joyner  *
264b4a7ce06SEric Joyner  * Ensure that FW is in the right state and do the reset
265b4a7ce06SEric Joyner  * if needed.
266b4a7ce06SEric Joyner  *
267b4a7ce06SEric Joyner  * @returns zero on success, or an error code on failure.
268b4a7ce06SEric Joyner  */
269b4a7ce06SEric Joyner int
ixl_pf_reset(struct ixl_pf * pf)270b4a7ce06SEric Joyner ixl_pf_reset(struct ixl_pf *pf)
2714294f337SSean Bruno {
2724294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
273b4a7ce06SEric Joyner 	enum i40e_status_code status;
274b4a7ce06SEric Joyner 	enum ixl_fw_mode fw_mode;
2754294f337SSean Bruno 
276b4a7ce06SEric Joyner 	fw_mode = ixl_get_fw_mode(pf);
277b4a7ce06SEric Joyner 	ixl_dbg_info(pf, "%s: before PF reset FW mode: 0x%08x\n", __func__, fw_mode);
278b4a7ce06SEric Joyner 	if (fw_mode == IXL_FW_MODE_RECOVERY) {
279b8f51b8cSPiotr Kubaj 		ixl_set_state(&pf->state, IXL_STATE_RECOVERY_MODE);
280b4a7ce06SEric Joyner 		/* Don't try to reset device if it's in recovery mode */
281b4a7ce06SEric Joyner 		return (0);
2824294f337SSean Bruno 	}
2834294f337SSean Bruno 
284b4a7ce06SEric Joyner 	status = i40e_pf_reset(hw);
285b4a7ce06SEric Joyner 	if (status == I40E_SUCCESS)
286b4a7ce06SEric Joyner 		return (0);
287b4a7ce06SEric Joyner 
288b4a7ce06SEric Joyner 	/* Check FW mode again in case it has changed while
289b4a7ce06SEric Joyner 	 * waiting for reset to complete */
290b4a7ce06SEric Joyner 	fw_mode = ixl_get_fw_mode(pf);
291b4a7ce06SEric Joyner 	ixl_dbg_info(pf, "%s: after PF reset FW mode: 0x%08x\n", __func__, fw_mode);
292b4a7ce06SEric Joyner 	if (fw_mode == IXL_FW_MODE_RECOVERY) {
293b8f51b8cSPiotr Kubaj 		ixl_set_state(&pf->state, IXL_STATE_RECOVERY_MODE);
294b4a7ce06SEric Joyner 		return (0);
295b4a7ce06SEric Joyner 	}
296b4a7ce06SEric Joyner 
297b4a7ce06SEric Joyner 	if (fw_mode == IXL_FW_MODE_UEMPR)
298b4a7ce06SEric Joyner 		device_printf(pf->dev,
299b4a7ce06SEric Joyner 		    "Entering recovery mode due to repeated FW resets. This may take several minutes. Refer to the Intel(R) Ethernet Adapters and Devices User Guide.\n");
300b4a7ce06SEric Joyner 	else
301b4a7ce06SEric Joyner 		device_printf(pf->dev, "PF reset failure %s\n",
302b4a7ce06SEric Joyner 		    i40e_stat_str(hw, status));
303b4a7ce06SEric Joyner 	return (EIO);
304b4a7ce06SEric Joyner }
305b4a7ce06SEric Joyner 
306b4a7ce06SEric Joyner /**
307b4a7ce06SEric Joyner  * ixl_setup_hmc - Setup LAN Host Memory Cache
308b4a7ce06SEric Joyner  * @pf: PF structure
309b4a7ce06SEric Joyner  *
310b4a7ce06SEric Joyner  * Init and configure LAN Host Memory Cache
311b4a7ce06SEric Joyner  *
312b4a7ce06SEric Joyner  * @returns 0 on success, EIO on error
313b4a7ce06SEric Joyner  */
314b4a7ce06SEric Joyner int
ixl_setup_hmc(struct ixl_pf * pf)315b4a7ce06SEric Joyner ixl_setup_hmc(struct ixl_pf *pf)
316b4a7ce06SEric Joyner {
317b4a7ce06SEric Joyner 	struct i40e_hw *hw = &pf->hw;
318b4a7ce06SEric Joyner 	enum i40e_status_code status;
319b4a7ce06SEric Joyner 
320b4a7ce06SEric Joyner 	status = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
321b4a7ce06SEric Joyner 	    hw->func_caps.num_rx_qp, 0, 0);
322b4a7ce06SEric Joyner 	if (status) {
323b4a7ce06SEric Joyner 		device_printf(pf->dev, "init_lan_hmc failed: %s\n",
324b4a7ce06SEric Joyner 		    i40e_stat_str(hw, status));
325b4a7ce06SEric Joyner 		return (EIO);
326b4a7ce06SEric Joyner 	}
327b4a7ce06SEric Joyner 
328b4a7ce06SEric Joyner 	status = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
329b4a7ce06SEric Joyner 	if (status) {
330b4a7ce06SEric Joyner 		device_printf(pf->dev, "configure_lan_hmc failed: %s\n",
331b4a7ce06SEric Joyner 		    i40e_stat_str(hw, status));
332b4a7ce06SEric Joyner 		return (EIO);
333b4a7ce06SEric Joyner 	}
334b4a7ce06SEric Joyner 
335b4a7ce06SEric Joyner 	return (0);
336b4a7ce06SEric Joyner }
337b4a7ce06SEric Joyner 
338b4a7ce06SEric Joyner /**
339b4a7ce06SEric Joyner  * ixl_shutdown_hmc - Shutdown LAN Host Memory Cache
340b4a7ce06SEric Joyner  * @pf: PF structure
341b4a7ce06SEric Joyner  *
342b4a7ce06SEric Joyner  * Shutdown Host Memory Cache if configured.
343b4a7ce06SEric Joyner  *
344b4a7ce06SEric Joyner  */
345b4a7ce06SEric Joyner void
ixl_shutdown_hmc(struct ixl_pf * pf)346b4a7ce06SEric Joyner ixl_shutdown_hmc(struct ixl_pf *pf)
347b4a7ce06SEric Joyner {
348b4a7ce06SEric Joyner 	struct i40e_hw *hw = &pf->hw;
349b4a7ce06SEric Joyner 	enum i40e_status_code status;
350b4a7ce06SEric Joyner 
351b4a7ce06SEric Joyner 	/* HMC not configured, no need to shutdown */
352b4a7ce06SEric Joyner 	if (hw->hmc.hmc_obj == NULL)
353b4a7ce06SEric Joyner 		return;
354b4a7ce06SEric Joyner 
355b4a7ce06SEric Joyner 	status = i40e_shutdown_lan_hmc(hw);
356b4a7ce06SEric Joyner 	if (status)
357b4a7ce06SEric Joyner 		device_printf(pf->dev,
358b4a7ce06SEric Joyner 		    "Shutdown LAN HMC failed with code %s\n",
359b4a7ce06SEric Joyner 		    i40e_stat_str(hw, status));
360b4a7ce06SEric Joyner }
3614294f337SSean Bruno /*
3624294f337SSean Bruno  * Write PF ITR values to queue ITR registers.
3634294f337SSean Bruno  */
3644294f337SSean Bruno void
ixl_configure_itr(struct ixl_pf * pf)3654294f337SSean Bruno ixl_configure_itr(struct ixl_pf *pf)
3664294f337SSean Bruno {
3674294f337SSean Bruno 	ixl_configure_tx_itr(pf);
3684294f337SSean Bruno 	ixl_configure_rx_itr(pf);
3694294f337SSean Bruno }
3704294f337SSean Bruno 
3714294f337SSean Bruno /*********************************************************************
3724294f337SSean Bruno  *
3734294f337SSean Bruno  *  Get the hardware capabilities
3744294f337SSean Bruno  *
3754294f337SSean Bruno  **********************************************************************/
3764294f337SSean Bruno 
3774294f337SSean Bruno int
ixl_get_hw_capabilities(struct ixl_pf * pf)3784294f337SSean Bruno ixl_get_hw_capabilities(struct ixl_pf *pf)
3794294f337SSean Bruno {
3804294f337SSean Bruno 	struct i40e_aqc_list_capabilities_element_resp *buf;
3814294f337SSean Bruno 	struct i40e_hw	*hw = &pf->hw;
3824294f337SSean Bruno 	device_t 	dev = pf->dev;
3831031d839SEric Joyner 	enum i40e_status_code status;
3841031d839SEric Joyner 	int len, i2c_intfc_num;
3854294f337SSean Bruno 	bool again = TRUE;
3861031d839SEric Joyner 	u16 needed;
3874294f337SSean Bruno 
388b4a7ce06SEric Joyner 	if (IXL_PF_IN_RECOVERY_MODE(pf)) {
389b4a7ce06SEric Joyner 		hw->func_caps.iwarp = 0;
390b4a7ce06SEric Joyner 		return (0);
391b4a7ce06SEric Joyner 	}
392b4a7ce06SEric Joyner 
3934294f337SSean Bruno 	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
3944294f337SSean Bruno retry:
3954294f337SSean Bruno 	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
3967d4dceecSKrzysztof Galazka 	    malloc(len, M_IXL, M_NOWAIT | M_ZERO))) {
3974294f337SSean Bruno 		device_printf(dev, "Unable to allocate cap memory\n");
3984294f337SSean Bruno                 return (ENOMEM);
3994294f337SSean Bruno 	}
4004294f337SSean Bruno 
4014294f337SSean Bruno 	/* This populates the hw struct */
4021031d839SEric Joyner         status = i40e_aq_discover_capabilities(hw, buf, len,
4034294f337SSean Bruno 	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
4047d4dceecSKrzysztof Galazka 	free(buf, M_IXL);
4054294f337SSean Bruno 	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
4064294f337SSean Bruno 	    (again == TRUE)) {
4074294f337SSean Bruno 		/* retry once with a larger buffer */
4084294f337SSean Bruno 		again = FALSE;
4094294f337SSean Bruno 		len = needed;
4104294f337SSean Bruno 		goto retry;
4111031d839SEric Joyner 	} else if (status != I40E_SUCCESS) {
4121031d839SEric Joyner 		device_printf(dev, "capability discovery failed; status %s, error %s\n",
4131031d839SEric Joyner 		    i40e_stat_str(hw, status), i40e_aq_str(hw, hw->aq.asq_last_status));
4144294f337SSean Bruno 		return (ENODEV);
4154294f337SSean Bruno 	}
4164294f337SSean Bruno 
4171031d839SEric Joyner 	/*
4181031d839SEric Joyner 	 * Some devices have both MDIO and I2C; since this isn't reported
4191031d839SEric Joyner 	 * by the FW, check registers to see if an I2C interface exists.
4201031d839SEric Joyner 	 */
4211031d839SEric Joyner 	i2c_intfc_num = ixl_find_i2c_interface(pf);
4221031d839SEric Joyner 	if (i2c_intfc_num != -1)
423ceebc2f3SEric Joyner 		pf->has_i2c = true;
424ceebc2f3SEric Joyner 
4251031d839SEric Joyner 	/* Determine functions to use for driver I2C accesses */
4261031d839SEric Joyner 	switch (pf->i2c_access_method) {
427b4a7ce06SEric Joyner 	case IXL_I2C_ACCESS_METHOD_BEST_AVAILABLE: {
428b4a7ce06SEric Joyner 		if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
4291031d839SEric Joyner 			pf->read_i2c_byte = ixl_read_i2c_byte_aq;
4301031d839SEric Joyner 			pf->write_i2c_byte = ixl_write_i2c_byte_aq;
4311031d839SEric Joyner 		} else {
4321031d839SEric Joyner 			pf->read_i2c_byte = ixl_read_i2c_byte_reg;
4331031d839SEric Joyner 			pf->write_i2c_byte = ixl_write_i2c_byte_reg;
4341031d839SEric Joyner 		}
4351031d839SEric Joyner 		break;
4361031d839SEric Joyner 	}
437b4a7ce06SEric Joyner 	case IXL_I2C_ACCESS_METHOD_AQ:
4381031d839SEric Joyner 		pf->read_i2c_byte = ixl_read_i2c_byte_aq;
4391031d839SEric Joyner 		pf->write_i2c_byte = ixl_write_i2c_byte_aq;
4401031d839SEric Joyner 		break;
441b4a7ce06SEric Joyner 	case IXL_I2C_ACCESS_METHOD_REGISTER_I2CCMD:
4421031d839SEric Joyner 		pf->read_i2c_byte = ixl_read_i2c_byte_reg;
4431031d839SEric Joyner 		pf->write_i2c_byte = ixl_write_i2c_byte_reg;
4441031d839SEric Joyner 		break;
445b4a7ce06SEric Joyner 	case IXL_I2C_ACCESS_METHOD_BIT_BANG_I2CPARAMS:
4461031d839SEric Joyner 		pf->read_i2c_byte = ixl_read_i2c_byte_bb;
4471031d839SEric Joyner 		pf->write_i2c_byte = ixl_write_i2c_byte_bb;
4481031d839SEric Joyner 		break;
4491031d839SEric Joyner 	default:
4501031d839SEric Joyner 		/* Should not happen */
4511031d839SEric Joyner 		device_printf(dev, "Error setting I2C access functions\n");
4521031d839SEric Joyner 		break;
4531031d839SEric Joyner 	}
4541031d839SEric Joyner 
45521802a12SKrzysztof Galazka 	/* Keep link active by default */
456b8f51b8cSPiotr Kubaj 	ixl_set_state(&pf->state, IXL_STATE_LINK_ACTIVE_ON_DOWN);
45721802a12SKrzysztof Galazka 
4584294f337SSean Bruno 	/* Print a subset of the capability information. */
459b97de13aSMarius Strobl 	device_printf(dev,
460b97de13aSMarius Strobl 	    "PF-ID[%d]: VFs %d, MSI-X %d, VF MSI-X %d, QPs %d, %s\n",
4614294f337SSean Bruno 	    hw->pf_id, hw->func_caps.num_vfs, hw->func_caps.num_msix_vectors,
4624294f337SSean Bruno 	    hw->func_caps.num_msix_vectors_vf, hw->func_caps.num_tx_qp,
4634294f337SSean Bruno 	    (hw->func_caps.mdio_port_mode == 2) ? "I2C" :
464ceebc2f3SEric Joyner 	    (hw->func_caps.mdio_port_mode == 1 && pf->has_i2c) ? "MDIO & I2C" :
4654294f337SSean Bruno 	    (hw->func_caps.mdio_port_mode == 1) ? "MDIO dedicated" :
4664294f337SSean Bruno 	    "MDIO shared");
4674294f337SSean Bruno 
4681031d839SEric Joyner 	return (0);
4694294f337SSean Bruno }
4704294f337SSean Bruno 
4714294f337SSean Bruno /* For the set_advertise sysctl */
4724294f337SSean Bruno void
ixl_set_initial_advertised_speeds(struct ixl_pf * pf)473ceebc2f3SEric Joyner ixl_set_initial_advertised_speeds(struct ixl_pf *pf)
4744294f337SSean Bruno {
4754294f337SSean Bruno 	device_t dev = pf->dev;
476ceebc2f3SEric Joyner 	int err;
4774294f337SSean Bruno 
478ceebc2f3SEric Joyner 	/* Make sure to initialize the device to the complete list of
479ceebc2f3SEric Joyner 	 * supported speeds on driver load, to ensure unloading and
480ceebc2f3SEric Joyner 	 * reloading the driver will restore this value.
481ceebc2f3SEric Joyner 	 */
482ceebc2f3SEric Joyner 	err = ixl_set_advertised_speeds(pf, pf->supported_speeds, true);
483ceebc2f3SEric Joyner 	if (err) {
4844294f337SSean Bruno 		/* Non-fatal error */
485ceebc2f3SEric Joyner 		device_printf(dev, "%s: ixl_set_advertised_speeds() error %d\n",
486ceebc2f3SEric Joyner 			      __func__, err);
4874294f337SSean Bruno 		return;
4884294f337SSean Bruno 	}
4894294f337SSean Bruno 
490cb6b8299SEric Joyner 	pf->advertised_speed =
491ceebc2f3SEric Joyner 	    ixl_convert_sysctl_aq_link_speed(pf->supported_speeds, false);
4924294f337SSean Bruno }
4934294f337SSean Bruno 
4944294f337SSean Bruno int
ixl_teardown_hw_structs(struct ixl_pf * pf)4954294f337SSean Bruno ixl_teardown_hw_structs(struct ixl_pf *pf)
4964294f337SSean Bruno {
4974294f337SSean Bruno 	enum i40e_status_code status = 0;
4984294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
4994294f337SSean Bruno 	device_t dev = pf->dev;
5004294f337SSean Bruno 
5014294f337SSean Bruno 	/* Shutdown LAN HMC */
5024294f337SSean Bruno 	if (hw->hmc.hmc_obj) {
5034294f337SSean Bruno 		status = i40e_shutdown_lan_hmc(hw);
5044294f337SSean Bruno 		if (status) {
5054294f337SSean Bruno 			device_printf(dev,
5061031d839SEric Joyner 			    "init: LAN HMC shutdown failure; status %s\n",
5071031d839SEric Joyner 			    i40e_stat_str(hw, status));
5084294f337SSean Bruno 			goto err_out;
5094294f337SSean Bruno 		}
5104294f337SSean Bruno 	}
5114294f337SSean Bruno 
5124294f337SSean Bruno 	/* Shutdown admin queue */
513ceebc2f3SEric Joyner 	ixl_disable_intr0(hw);
5144294f337SSean Bruno 	status = i40e_shutdown_adminq(hw);
5154294f337SSean Bruno 	if (status)
5164294f337SSean Bruno 		device_printf(dev,
5171031d839SEric Joyner 		    "init: Admin Queue shutdown failure; status %s\n",
5181031d839SEric Joyner 		    i40e_stat_str(hw, status));
5194294f337SSean Bruno 
52077c1fcecSEric Joyner 	ixl_pf_qmgr_release(&pf->qmgr, &pf->qtag);
5214294f337SSean Bruno err_out:
5224294f337SSean Bruno 	return (status);
5234294f337SSean Bruno }
5244294f337SSean Bruno 
5257d4dceecSKrzysztof Galazka /*
5267d4dceecSKrzysztof Galazka ** Creates new filter with given MAC address and VLAN ID
5277d4dceecSKrzysztof Galazka */
5287d4dceecSKrzysztof Galazka static struct ixl_mac_filter *
ixl_new_filter(struct ixl_ftl_head * headp,const u8 * macaddr,s16 vlan)5297d4dceecSKrzysztof Galazka ixl_new_filter(struct ixl_ftl_head *headp, const u8 *macaddr, s16 vlan)
5307d4dceecSKrzysztof Galazka {
5317d4dceecSKrzysztof Galazka 	struct ixl_mac_filter  *f;
5327d4dceecSKrzysztof Galazka 
5337d4dceecSKrzysztof Galazka 	/* create a new empty filter */
5347d4dceecSKrzysztof Galazka 	f = malloc(sizeof(struct ixl_mac_filter),
5357d4dceecSKrzysztof Galazka 	    M_IXL, M_NOWAIT | M_ZERO);
5367d4dceecSKrzysztof Galazka 	if (f) {
5377d4dceecSKrzysztof Galazka 		LIST_INSERT_HEAD(headp, f, ftle);
5387d4dceecSKrzysztof Galazka 		bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
5397d4dceecSKrzysztof Galazka 		f->vlan = vlan;
5407d4dceecSKrzysztof Galazka 	}
5417d4dceecSKrzysztof Galazka 
5427d4dceecSKrzysztof Galazka 	return (f);
5437d4dceecSKrzysztof Galazka }
5447d4dceecSKrzysztof Galazka 
5457d4dceecSKrzysztof Galazka /**
5467d4dceecSKrzysztof Galazka  * ixl_free_filters - Free all filters in given list
5477d4dceecSKrzysztof Galazka  * headp - pointer to list head
5487d4dceecSKrzysztof Galazka  *
5497d4dceecSKrzysztof Galazka  * Frees memory used by each entry in the list.
5507d4dceecSKrzysztof Galazka  * Does not remove filters from HW.
5517d4dceecSKrzysztof Galazka  */
5527d4dceecSKrzysztof Galazka void
ixl_free_filters(struct ixl_ftl_head * headp)5537d4dceecSKrzysztof Galazka ixl_free_filters(struct ixl_ftl_head *headp)
5547d4dceecSKrzysztof Galazka {
5557d4dceecSKrzysztof Galazka 	struct ixl_mac_filter *f, *nf;
5567d4dceecSKrzysztof Galazka 
5577d4dceecSKrzysztof Galazka 	f = LIST_FIRST(headp);
5587d4dceecSKrzysztof Galazka 	while (f != NULL) {
5597d4dceecSKrzysztof Galazka 		nf = LIST_NEXT(f, ftle);
5607d4dceecSKrzysztof Galazka 		free(f, M_IXL);
5617d4dceecSKrzysztof Galazka 		f = nf;
5627d4dceecSKrzysztof Galazka 	}
5637d4dceecSKrzysztof Galazka 
5647d4dceecSKrzysztof Galazka 	LIST_INIT(headp);
5657d4dceecSKrzysztof Galazka }
5667d4dceecSKrzysztof Galazka 
567ba76aa63SGleb Smirnoff static u_int
ixl_add_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)568ba76aa63SGleb Smirnoff ixl_add_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
569ba76aa63SGleb Smirnoff {
5707d4dceecSKrzysztof Galazka 	struct ixl_add_maddr_arg *ama = arg;
5717d4dceecSKrzysztof Galazka 	struct ixl_vsi *vsi = ama->vsi;
5727d4dceecSKrzysztof Galazka 	const u8 *macaddr = (u8*)LLADDR(sdl);
5737d4dceecSKrzysztof Galazka 	struct ixl_mac_filter *f;
574ba76aa63SGleb Smirnoff 
5757d4dceecSKrzysztof Galazka 	/* Does one already exist */
5767d4dceecSKrzysztof Galazka 	f = ixl_find_filter(&vsi->ftl, macaddr, IXL_VLAN_ANY);
5777d4dceecSKrzysztof Galazka 	if (f != NULL)
5787d4dceecSKrzysztof Galazka 		return (0);
5797d4dceecSKrzysztof Galazka 
5807d4dceecSKrzysztof Galazka 	f = ixl_new_filter(&ama->to_add, macaddr, IXL_VLAN_ANY);
5817d4dceecSKrzysztof Galazka 	if (f == NULL) {
5827d4dceecSKrzysztof Galazka 		device_printf(vsi->dev, "WARNING: no filter available!!\n");
5837d4dceecSKrzysztof Galazka 		return (0);
5847d4dceecSKrzysztof Galazka 	}
5857d4dceecSKrzysztof Galazka 	f->flags |= IXL_FILTER_MC;
586ba76aa63SGleb Smirnoff 
587ba76aa63SGleb Smirnoff 	return (1);
588ba76aa63SGleb Smirnoff }
589ba76aa63SGleb Smirnoff 
5904294f337SSean Bruno /*********************************************************************
5914294f337SSean Bruno  * 	Filter Routines
5924294f337SSean Bruno  *
5934294f337SSean Bruno  *	Routines for multicast and vlan filter management.
5944294f337SSean Bruno  *
5954294f337SSean Bruno  *********************************************************************/
5964294f337SSean Bruno void
ixl_add_multi(struct ixl_vsi * vsi)5974294f337SSean Bruno ixl_add_multi(struct ixl_vsi *vsi)
5984294f337SSean Bruno {
599402810d3SJustin Hibbits 	if_t			ifp = vsi->ifp;
6004294f337SSean Bruno 	struct i40e_hw		*hw = vsi->hw;
6017d4dceecSKrzysztof Galazka 	int			mcnt = 0;
6027d4dceecSKrzysztof Galazka 	struct ixl_add_maddr_arg cb_arg;
6034294f337SSean Bruno 
6044294f337SSean Bruno 	IOCTL_DEBUGOUT("ixl_add_multi: begin");
6054294f337SSean Bruno 
606ba76aa63SGleb Smirnoff 	mcnt = if_llmaddr_count(ifp);
6074294f337SSean Bruno 	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
608*38663adbSFranco Fichtner 		i40e_aq_set_vsi_multicast_promiscuous(hw,
609*38663adbSFranco Fichtner 		    vsi->seid, TRUE, NULL);
610*38663adbSFranco Fichtner 		/* delete all existing MC filters */
6117d4dceecSKrzysztof Galazka 		ixl_del_multi(vsi, true);
6124294f337SSean Bruno 		return;
6134294f337SSean Bruno 	}
6144294f337SSean Bruno 
6157d4dceecSKrzysztof Galazka 	cb_arg.vsi = vsi;
6167d4dceecSKrzysztof Galazka 	LIST_INIT(&cb_arg.to_add);
6177d4dceecSKrzysztof Galazka 
6187d4dceecSKrzysztof Galazka 	mcnt = if_foreach_llmaddr(ifp, ixl_add_maddr, &cb_arg);
6197d4dceecSKrzysztof Galazka 	if (mcnt > 0)
6207d4dceecSKrzysztof Galazka 		ixl_add_hw_filters(vsi, &cb_arg.to_add, mcnt);
6214294f337SSean Bruno 
6224294f337SSean Bruno 	IOCTL_DEBUGOUT("ixl_add_multi: end");
6234294f337SSean Bruno }
6244294f337SSean Bruno 
625ba76aa63SGleb Smirnoff static u_int
ixl_match_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)626ba76aa63SGleb Smirnoff ixl_match_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
627ba76aa63SGleb Smirnoff {
628ba76aa63SGleb Smirnoff 	struct ixl_mac_filter *f = arg;
629ba76aa63SGleb Smirnoff 
6307d4dceecSKrzysztof Galazka 	if (ixl_ether_is_equal(f->macaddr, (u8 *)LLADDR(sdl)))
631ba76aa63SGleb Smirnoff 		return (1);
632ba76aa63SGleb Smirnoff 	else
633ba76aa63SGleb Smirnoff 		return (0);
634ba76aa63SGleb Smirnoff }
635ba76aa63SGleb Smirnoff 
6367d4dceecSKrzysztof Galazka void
ixl_del_multi(struct ixl_vsi * vsi,bool all)6377d4dceecSKrzysztof Galazka ixl_del_multi(struct ixl_vsi *vsi, bool all)
6384294f337SSean Bruno {
639*38663adbSFranco Fichtner 	struct ixl_ftl_head	to_del;
640402810d3SJustin Hibbits 	if_t			ifp = vsi->ifp;
6417d4dceecSKrzysztof Galazka 	struct ixl_mac_filter	*f, *fn;
642*38663adbSFranco Fichtner 	int			mcnt = 0;
6434294f337SSean Bruno 
6444294f337SSean Bruno 	IOCTL_DEBUGOUT("ixl_del_multi: begin");
6454294f337SSean Bruno 
6467d4dceecSKrzysztof Galazka 	LIST_INIT(&to_del);
647b4a7ce06SEric Joyner 	/* Search for removed multicast addresses */
6487d4dceecSKrzysztof Galazka 	LIST_FOREACH_SAFE(f, &vsi->ftl, ftle, fn) {
649*38663adbSFranco Fichtner 		if ((f->flags & IXL_FILTER_MC) == 0 ||
650*38663adbSFranco Fichtner 		    (!all && (if_foreach_llmaddr(ifp, ixl_match_maddr, f) == 0)))
6517d4dceecSKrzysztof Galazka 			continue;
6527d4dceecSKrzysztof Galazka 
6537d4dceecSKrzysztof Galazka 		LIST_REMOVE(f, ftle);
6547d4dceecSKrzysztof Galazka 		LIST_INSERT_HEAD(&to_del, f, ftle);
655*38663adbSFranco Fichtner 		mcnt++;
6564294f337SSean Bruno 	}
6574294f337SSean Bruno 
658*38663adbSFranco Fichtner 	if (mcnt > 0)
659*38663adbSFranco Fichtner 		ixl_del_hw_filters(vsi, &to_del, mcnt);
6604294f337SSean Bruno }
6614294f337SSean Bruno 
662cb6b8299SEric Joyner void
ixl_link_up_msg(struct ixl_pf * pf)663cb6b8299SEric Joyner ixl_link_up_msg(struct ixl_pf *pf)
664cb6b8299SEric Joyner {
665cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
666402810d3SJustin Hibbits 	if_t ifp = pf->vsi.ifp;
667ceebc2f3SEric Joyner 	char *req_fec_string, *neg_fec_string;
668ceebc2f3SEric Joyner 	u8 fec_abilities;
669cb6b8299SEric Joyner 
670ceebc2f3SEric Joyner 	fec_abilities = hw->phy.link_info.req_fec_info;
671ceebc2f3SEric Joyner 	/* If both RS and KR are requested, only show RS */
672ceebc2f3SEric Joyner 	if (fec_abilities & I40E_AQ_REQUEST_FEC_RS)
673ceebc2f3SEric Joyner 		req_fec_string = ixl_fec_string[0];
674ceebc2f3SEric Joyner 	else if (fec_abilities & I40E_AQ_REQUEST_FEC_KR)
675ceebc2f3SEric Joyner 		req_fec_string = ixl_fec_string[1];
676ceebc2f3SEric Joyner 	else
677ceebc2f3SEric Joyner 		req_fec_string = ixl_fec_string[2];
678ceebc2f3SEric Joyner 
679ceebc2f3SEric Joyner 	if (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_RS_ENA)
680ceebc2f3SEric Joyner 		neg_fec_string = ixl_fec_string[0];
681ceebc2f3SEric Joyner 	else if (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_KR_ENA)
682ceebc2f3SEric Joyner 		neg_fec_string = ixl_fec_string[1];
683ceebc2f3SEric Joyner 	else
684ceebc2f3SEric Joyner 		neg_fec_string = ixl_fec_string[2];
685ceebc2f3SEric Joyner 
686ceebc2f3SEric Joyner 	log(LOG_NOTICE, "%s: Link is up, %s Full Duplex, Requested FEC: %s, Negotiated FEC: %s, Autoneg: %s, Flow Control: %s\n",
687402810d3SJustin Hibbits 	    if_name(ifp),
688b4a7ce06SEric Joyner 	    ixl_link_speed_string(hw->phy.link_info.link_speed),
689ceebc2f3SEric Joyner 	    req_fec_string, neg_fec_string,
690cb6b8299SEric Joyner 	    (hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED) ? "True" : "False",
691cb6b8299SEric Joyner 	    (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX &&
692cb6b8299SEric Joyner 	        hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) ?
693cb6b8299SEric Joyner 		ixl_fc_string[3] : (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) ?
694cb6b8299SEric Joyner 		ixl_fc_string[2] : (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) ?
695cb6b8299SEric Joyner 		ixl_fc_string[1] : ixl_fc_string[0]);
696cb6b8299SEric Joyner }
697cb6b8299SEric Joyner 
6984294f337SSean Bruno /*
6994294f337SSean Bruno  * Configure admin queue/misc interrupt cause registers in hardware.
7004294f337SSean Bruno  */
7014294f337SSean Bruno void
ixl_configure_intr0_msix(struct ixl_pf * pf)7024294f337SSean Bruno ixl_configure_intr0_msix(struct ixl_pf *pf)
7034294f337SSean Bruno {
7044294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
7054294f337SSean Bruno 	u32 reg;
7064294f337SSean Bruno 
7074294f337SSean Bruno 	/* First set up the adminq - vector 0 */
7084294f337SSean Bruno 	wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
7094294f337SSean Bruno 	rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
7104294f337SSean Bruno 
7114294f337SSean Bruno 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
7124294f337SSean Bruno 	    I40E_PFINT_ICR0_ENA_GRST_MASK |
7134294f337SSean Bruno 	    I40E_PFINT_ICR0_ENA_HMC_ERR_MASK |
7144294f337SSean Bruno 	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
7154294f337SSean Bruno 	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
7164294f337SSean Bruno 	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
717ceebc2f3SEric Joyner 	    I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK |
7184294f337SSean Bruno 	    I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK;
7194294f337SSean Bruno 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
7204294f337SSean Bruno 
7214294f337SSean Bruno 	/*
7224294f337SSean Bruno 	 * 0x7FF is the end of the queue list.
7234294f337SSean Bruno 	 * This means we won't use MSI-X vector 0 for a queue interrupt
724b97de13aSMarius Strobl 	 * in MSI-X mode.
7254294f337SSean Bruno 	 */
7264294f337SSean Bruno 	wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
7274294f337SSean Bruno 	/* Value is in 2 usec units, so 0x3E is 62*2 = 124 usecs. */
7284294f337SSean Bruno 	wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x3E);
7294294f337SSean Bruno 
7304294f337SSean Bruno 	wr32(hw, I40E_PFINT_DYN_CTL0,
7314294f337SSean Bruno 	    I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK |
7324294f337SSean Bruno 	    I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
7334294f337SSean Bruno 
7344294f337SSean Bruno 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
7354294f337SSean Bruno }
7364294f337SSean Bruno 
7374294f337SSean Bruno void
ixl_add_ifmedia(struct ifmedia * media,u64 phy_types)738b4a7ce06SEric Joyner ixl_add_ifmedia(struct ifmedia *media, u64 phy_types)
7394294f337SSean Bruno {
7404294f337SSean Bruno 	/* Display supported media types */
741cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_100BASE_TX))
742b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_100_TX, 0, NULL);
7434294f337SSean Bruno 
744cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_T))
745b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_1000_T, 0, NULL);
746cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_SX))
747b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_1000_SX, 0, NULL);
748cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_LX))
749b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_1000_LX, 0, NULL);
7504294f337SSean Bruno 
7512984a8ddSEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_2_5GBASE_T))
7522984a8ddSEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_2500_T, 0, NULL);
7532984a8ddSEric Joyner 
7542984a8ddSEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_5GBASE_T))
7552984a8ddSEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_5000_T, 0, NULL);
7562984a8ddSEric Joyner 
757cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_XAUI) ||
758cb6b8299SEric Joyner 	    phy_types & (I40E_CAP_PHY_TYPE_XFI) ||
759cb6b8299SEric Joyner 	    phy_types & (I40E_CAP_PHY_TYPE_10GBASE_SFPP_CU))
760b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
7614294f337SSean Bruno 
762cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_SR))
763b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_10G_SR, 0, NULL);
764cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_LR))
765b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_10G_LR, 0, NULL);
766cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_T))
767b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_10G_T, 0, NULL);
7684294f337SSean Bruno 
769cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_CR4) ||
770cb6b8299SEric Joyner 	    phy_types & (I40E_CAP_PHY_TYPE_40GBASE_CR4_CU) ||
771cb6b8299SEric Joyner 	    phy_types & (I40E_CAP_PHY_TYPE_40GBASE_AOC) ||
772cb6b8299SEric Joyner 	    phy_types & (I40E_CAP_PHY_TYPE_XLAUI) ||
773cb6b8299SEric Joyner 	    phy_types & (I40E_CAP_PHY_TYPE_40GBASE_KR4))
774b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
775cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_SR4))
776b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
777cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_LR4))
778b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
7794294f337SSean Bruno 
780cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_KX))
781b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_1000_KX, 0, NULL);
7824294f337SSean Bruno 
783cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_CR1_CU)
784cb6b8299SEric Joyner 	    || phy_types & (I40E_CAP_PHY_TYPE_10GBASE_CR1))
785b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_10G_CR1, 0, NULL);
786cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_AOC))
787b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_10G_AOC, 0, NULL);
788cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_SFI))
789b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_10G_SFI, 0, NULL);
790cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_KX4))
791b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_10G_KX4, 0, NULL);
792cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_KR))
793b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_10G_KR, 0, NULL);
7944294f337SSean Bruno 
795cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_20GBASE_KR2))
796b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_20G_KR2, 0, NULL);
7974294f337SSean Bruno 
798cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_KR4))
799b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_40G_KR4, 0, NULL);
800cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_XLPPI))
801b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL);
802cb6b8299SEric Joyner 
803cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_KR))
804b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_25G_KR, 0, NULL);
805cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_CR))
806b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_25G_CR, 0, NULL);
807cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_SR))
808b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_25G_SR, 0, NULL);
809cb6b8299SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_LR))
810b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_25G_LR, 0, NULL);
811ceebc2f3SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_AOC))
812b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_25G_AOC, 0, NULL);
813ceebc2f3SEric Joyner 	if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_ACC))
814b4a7ce06SEric Joyner 		ifmedia_add(media, IFM_ETHER | IFM_25G_ACC, 0, NULL);
8154294f337SSean Bruno }
8164294f337SSean Bruno 
8174294f337SSean Bruno /*********************************************************************
8184294f337SSean Bruno  *
8194294f337SSean Bruno  *  Get Firmware Switch configuration
8204294f337SSean Bruno  *	- this will need to be more robust when more complex
8214294f337SSean Bruno  *	  switch configurations are enabled.
8224294f337SSean Bruno  *
8234294f337SSean Bruno  **********************************************************************/
8244294f337SSean Bruno int
ixl_switch_config(struct ixl_pf * pf)8254294f337SSean Bruno ixl_switch_config(struct ixl_pf *pf)
8264294f337SSean Bruno {
8274294f337SSean Bruno 	struct i40e_hw	*hw = &pf->hw;
8284294f337SSean Bruno 	struct ixl_vsi	*vsi = &pf->vsi;
8291031d839SEric Joyner 	device_t 	dev = iflib_get_dev(vsi->ctx);
8304294f337SSean Bruno 	struct i40e_aqc_get_switch_config_resp *sw_config;
8314294f337SSean Bruno 	u8	aq_buf[I40E_AQ_LARGE_BUF];
8324294f337SSean Bruno 	int	ret;
8334294f337SSean Bruno 	u16	next = 0;
8344294f337SSean Bruno 
8354294f337SSean Bruno 	memset(&aq_buf, 0, sizeof(aq_buf));
8364294f337SSean Bruno 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
8374294f337SSean Bruno 	ret = i40e_aq_get_switch_config(hw, sw_config,
8384294f337SSean Bruno 	    sizeof(aq_buf), &next, NULL);
8394294f337SSean Bruno 	if (ret) {
8404294f337SSean Bruno 		device_printf(dev, "aq_get_switch_config() failed, error %d,"
8414294f337SSean Bruno 		    " aq_error %d\n", ret, pf->hw.aq.asq_last_status);
8424294f337SSean Bruno 		return (ret);
8434294f337SSean Bruno 	}
8444294f337SSean Bruno 	if (pf->dbg_mask & IXL_DBG_SWITCH_INFO) {
8454294f337SSean Bruno 		device_printf(dev,
8464294f337SSean Bruno 		    "Switch config: header reported: %d in structure, %d total\n",
847c65f571cSLeandro Lupori 		    LE16_TO_CPU(sw_config->header.num_reported),
848c65f571cSLeandro Lupori 		    LE16_TO_CPU(sw_config->header.num_total));
849c65f571cSLeandro Lupori 		for (int i = 0;
850c65f571cSLeandro Lupori 		    i < LE16_TO_CPU(sw_config->header.num_reported); i++) {
8514294f337SSean Bruno 			device_printf(dev,
852cb6b8299SEric Joyner 			    "-> %d: type=%d seid=%d uplink=%d downlink=%d\n", i,
8534294f337SSean Bruno 			    sw_config->element[i].element_type,
854c65f571cSLeandro Lupori 			    LE16_TO_CPU(sw_config->element[i].seid),
855c65f571cSLeandro Lupori 			    LE16_TO_CPU(sw_config->element[i].uplink_seid),
856c65f571cSLeandro Lupori 			    LE16_TO_CPU(sw_config->element[i].downlink_seid));
8574294f337SSean Bruno 		}
8584294f337SSean Bruno 	}
8594294f337SSean Bruno 	/* Simplified due to a single VSI */
860c65f571cSLeandro Lupori 	vsi->uplink_seid = LE16_TO_CPU(sw_config->element[0].uplink_seid);
861c65f571cSLeandro Lupori 	vsi->downlink_seid = LE16_TO_CPU(sw_config->element[0].downlink_seid);
862c65f571cSLeandro Lupori 	vsi->seid = LE16_TO_CPU(sw_config->element[0].seid);
8634294f337SSean Bruno 	return (ret);
8644294f337SSean Bruno }
8654294f337SSean Bruno 
8664294f337SSean Bruno void
ixl_vsi_add_sysctls(struct ixl_vsi * vsi,const char * sysctl_name,bool queues_sysctls)867b4a7ce06SEric Joyner ixl_vsi_add_sysctls(struct ixl_vsi * vsi, const char * sysctl_name, bool queues_sysctls)
8684294f337SSean Bruno {
869b4a7ce06SEric Joyner 	struct sysctl_oid *tree;
870b4a7ce06SEric Joyner 	struct sysctl_oid_list *child;
871b4a7ce06SEric Joyner 	struct sysctl_oid_list *vsi_list;
8724294f337SSean Bruno 
873b4a7ce06SEric Joyner 	tree = device_get_sysctl_tree(vsi->dev);
874b4a7ce06SEric Joyner 	child = SYSCTL_CHILDREN(tree);
875b4a7ce06SEric Joyner 	vsi->vsi_node = SYSCTL_ADD_NODE(&vsi->sysctl_ctx, child, OID_AUTO, sysctl_name,
876b4a7ce06SEric Joyner 			CTLFLAG_RD, NULL, "VSI Number");
8774294f337SSean Bruno 
878b4a7ce06SEric Joyner 	vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
879b4a7ce06SEric Joyner 	ixl_add_sysctls_eth_stats(&vsi->sysctl_ctx, vsi_list, &vsi->eth_stats);
8804294f337SSean Bruno 
8819f99061eSKrzysztof Galazka 	/* Copy of netstat RX errors counter for validation purposes */
8829f99061eSKrzysztof Galazka 	SYSCTL_ADD_UQUAD(&vsi->sysctl_ctx, vsi_list, OID_AUTO, "rx_errors",
8839f99061eSKrzysztof Galazka 			CTLFLAG_RD, &vsi->ierrors,
8849f99061eSKrzysztof Galazka 			"RX packet errors");
8859f99061eSKrzysztof Galazka 
886b4a7ce06SEric Joyner 	if (queues_sysctls)
887b4a7ce06SEric Joyner 		ixl_vsi_add_queues_stats(vsi, &vsi->sysctl_ctx);
8884294f337SSean Bruno }
8894294f337SSean Bruno 
8904294f337SSean Bruno /*
8914294f337SSean Bruno  * Used to set the Tx ITR value for all of the PF LAN VSI's queues.
8924294f337SSean Bruno  * Writes to the ITR registers immediately.
8934294f337SSean Bruno  */
8944294f337SSean Bruno static int
ixl_sysctl_pf_tx_itr(SYSCTL_HANDLER_ARGS)8954294f337SSean Bruno ixl_sysctl_pf_tx_itr(SYSCTL_HANDLER_ARGS)
8964294f337SSean Bruno {
8974294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
8984294f337SSean Bruno 	device_t dev = pf->dev;
8994294f337SSean Bruno 	int error = 0;
9004294f337SSean Bruno 	int requested_tx_itr;
9014294f337SSean Bruno 
9024294f337SSean Bruno 	requested_tx_itr = pf->tx_itr;
9034294f337SSean Bruno 	error = sysctl_handle_int(oidp, &requested_tx_itr, 0, req);
9044294f337SSean Bruno 	if ((error) || (req->newptr == NULL))
9054294f337SSean Bruno 		return (error);
9064294f337SSean Bruno 	if (pf->dynamic_tx_itr) {
9074294f337SSean Bruno 		device_printf(dev,
9084294f337SSean Bruno 		    "Cannot set TX itr value while dynamic TX itr is enabled\n");
9094294f337SSean Bruno 		    return (EINVAL);
9104294f337SSean Bruno 	}
9114294f337SSean Bruno 	if (requested_tx_itr < 0 || requested_tx_itr > IXL_MAX_ITR) {
9124294f337SSean Bruno 		device_printf(dev,
9134294f337SSean Bruno 		    "Invalid TX itr value; value must be between 0 and %d\n",
9144294f337SSean Bruno 		        IXL_MAX_ITR);
9154294f337SSean Bruno 		return (EINVAL);
9164294f337SSean Bruno 	}
9174294f337SSean Bruno 
9184294f337SSean Bruno 	pf->tx_itr = requested_tx_itr;
9194294f337SSean Bruno 	ixl_configure_tx_itr(pf);
9204294f337SSean Bruno 
9214294f337SSean Bruno 	return (error);
9224294f337SSean Bruno }
9234294f337SSean Bruno 
9244294f337SSean Bruno /*
9254294f337SSean Bruno  * Used to set the Rx ITR value for all of the PF LAN VSI's queues.
9264294f337SSean Bruno  * Writes to the ITR registers immediately.
9274294f337SSean Bruno  */
9284294f337SSean Bruno static int
ixl_sysctl_pf_rx_itr(SYSCTL_HANDLER_ARGS)9294294f337SSean Bruno ixl_sysctl_pf_rx_itr(SYSCTL_HANDLER_ARGS)
9304294f337SSean Bruno {
9314294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
9324294f337SSean Bruno 	device_t dev = pf->dev;
9334294f337SSean Bruno 	int error = 0;
9344294f337SSean Bruno 	int requested_rx_itr;
9354294f337SSean Bruno 
9364294f337SSean Bruno 	requested_rx_itr = pf->rx_itr;
9374294f337SSean Bruno 	error = sysctl_handle_int(oidp, &requested_rx_itr, 0, req);
9384294f337SSean Bruno 	if ((error) || (req->newptr == NULL))
9394294f337SSean Bruno 		return (error);
9404294f337SSean Bruno 	if (pf->dynamic_rx_itr) {
9414294f337SSean Bruno 		device_printf(dev,
9424294f337SSean Bruno 		    "Cannot set RX itr value while dynamic RX itr is enabled\n");
9434294f337SSean Bruno 		    return (EINVAL);
9444294f337SSean Bruno 	}
9454294f337SSean Bruno 	if (requested_rx_itr < 0 || requested_rx_itr > IXL_MAX_ITR) {
9464294f337SSean Bruno 		device_printf(dev,
9474294f337SSean Bruno 		    "Invalid RX itr value; value must be between 0 and %d\n",
9484294f337SSean Bruno 		        IXL_MAX_ITR);
9494294f337SSean Bruno 		return (EINVAL);
9504294f337SSean Bruno 	}
9514294f337SSean Bruno 
9524294f337SSean Bruno 	pf->rx_itr = requested_rx_itr;
9534294f337SSean Bruno 	ixl_configure_rx_itr(pf);
9544294f337SSean Bruno 
9554294f337SSean Bruno 	return (error);
9564294f337SSean Bruno }
9574294f337SSean Bruno 
9584294f337SSean Bruno void
ixl_add_sysctls_mac_stats(struct sysctl_ctx_list * ctx,struct sysctl_oid_list * child,struct i40e_hw_port_stats * stats)9594294f337SSean Bruno ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx,
9604294f337SSean Bruno 	struct sysctl_oid_list *child,
9614294f337SSean Bruno 	struct i40e_hw_port_stats *stats)
9624294f337SSean Bruno {
96320b91f0aSPawel Biernacki 	struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
96420b91f0aSPawel Biernacki 	    "mac", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Mac Statistics");
9654294f337SSean Bruno 	struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node);
9664294f337SSean Bruno 
9674294f337SSean Bruno 	struct i40e_eth_stats *eth_stats = &stats->eth;
9684294f337SSean Bruno 	ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats);
9694294f337SSean Bruno 
9704294f337SSean Bruno 	struct ixl_sysctl_info ctls[] =
9714294f337SSean Bruno 	{
9724294f337SSean Bruno 		{&stats->crc_errors, "crc_errors", "CRC Errors"},
9734294f337SSean Bruno 		{&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"},
9744294f337SSean Bruno 		{&stats->mac_local_faults, "local_faults", "MAC Local Faults"},
9754294f337SSean Bruno 		{&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"},
9764294f337SSean Bruno 		{&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"},
9774294f337SSean Bruno 		/* Packet Reception Stats */
9784294f337SSean Bruno 		{&stats->rx_size_64, "rx_frames_64", "64 byte frames received"},
9794294f337SSean Bruno 		{&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"},
9804294f337SSean Bruno 		{&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"},
9814294f337SSean Bruno 		{&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"},
9824294f337SSean Bruno 		{&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"},
9834294f337SSean Bruno 		{&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"},
9844294f337SSean Bruno 		{&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"},
9854294f337SSean Bruno 		{&stats->rx_undersize, "rx_undersize", "Undersized packets received"},
9864294f337SSean Bruno 		{&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"},
9874294f337SSean Bruno 		{&stats->rx_oversize, "rx_oversized", "Oversized packets received"},
9884294f337SSean Bruno 		{&stats->rx_jabber, "rx_jabber", "Received Jabber"},
9894294f337SSean Bruno 		{&stats->checksum_error, "checksum_errors", "Checksum Errors"},
9904294f337SSean Bruno 		/* Packet Transmission Stats */
9914294f337SSean Bruno 		{&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"},
9924294f337SSean Bruno 		{&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"},
9934294f337SSean Bruno 		{&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"},
9944294f337SSean Bruno 		{&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"},
9954294f337SSean Bruno 		{&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"},
9964294f337SSean Bruno 		{&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"},
9974294f337SSean Bruno 		{&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"},
9984294f337SSean Bruno 		/* Flow control */
9994294f337SSean Bruno 		{&stats->link_xon_tx, "xon_txd", "Link XON transmitted"},
10004294f337SSean Bruno 		{&stats->link_xon_rx, "xon_recvd", "Link XON received"},
10014294f337SSean Bruno 		{&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"},
10024294f337SSean Bruno 		{&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"},
10034294f337SSean Bruno 		/* End */
10044294f337SSean Bruno 		{0,0,0}
10054294f337SSean Bruno 	};
10064294f337SSean Bruno 
10074294f337SSean Bruno 	struct ixl_sysctl_info *entry = ctls;
10084294f337SSean Bruno 	while (entry->stat != 0)
10094294f337SSean Bruno 	{
10104294f337SSean Bruno 		SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name,
10114294f337SSean Bruno 				CTLFLAG_RD, entry->stat,
10124294f337SSean Bruno 				entry->description);
10134294f337SSean Bruno 		entry++;
10144294f337SSean Bruno 	}
10154294f337SSean Bruno }
10164294f337SSean Bruno 
10174294f337SSean Bruno void
ixl_set_rss_key(struct ixl_pf * pf)10184294f337SSean Bruno ixl_set_rss_key(struct ixl_pf *pf)
10194294f337SSean Bruno {
10204294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
10214294f337SSean Bruno 	struct ixl_vsi *vsi = &pf->vsi;
10224294f337SSean Bruno 	device_t	dev = pf->dev;
10234294f337SSean Bruno 	u32 rss_seed[IXL_RSS_KEY_SIZE_REG];
1024ceebc2f3SEric Joyner 	enum i40e_status_code status;
10254294f337SSean Bruno 
10264294f337SSean Bruno #ifdef RSS
10274294f337SSean Bruno         /* Fetch the configured RSS key */
10284294f337SSean Bruno         rss_getkey((uint8_t *) &rss_seed);
1029ceebc2f3SEric Joyner #else
1030ceebc2f3SEric Joyner 	ixl_get_default_rss_key(rss_seed);
10314294f337SSean Bruno #endif
10324294f337SSean Bruno 	/* Fill out hash function seed */
10334294f337SSean Bruno 	if (hw->mac.type == I40E_MAC_X722) {
10344294f337SSean Bruno 		struct i40e_aqc_get_set_rss_key_data key_data;
1035ceebc2f3SEric Joyner 		bcopy(rss_seed, &key_data, 52);
10364294f337SSean Bruno 		status = i40e_aq_set_rss_key(hw, vsi->vsi_num, &key_data);
10374294f337SSean Bruno 		if (status)
1038ceebc2f3SEric Joyner 			device_printf(dev,
1039ceebc2f3SEric Joyner 			    "i40e_aq_set_rss_key status %s, error %s\n",
1040ceebc2f3SEric Joyner 			    i40e_stat_str(hw, status),
1041ceebc2f3SEric Joyner 			    i40e_aq_str(hw, hw->aq.asq_last_status));
10424294f337SSean Bruno 	} else {
10434294f337SSean Bruno 		for (int i = 0; i < IXL_RSS_KEY_SIZE_REG; i++)
10444294f337SSean Bruno 			i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), rss_seed[i]);
10454294f337SSean Bruno 	}
10464294f337SSean Bruno }
10474294f337SSean Bruno 
10484294f337SSean Bruno /*
10494294f337SSean Bruno  * Configure enabled PCTYPES for RSS.
10504294f337SSean Bruno  */
10514294f337SSean Bruno void
ixl_set_rss_pctypes(struct ixl_pf * pf)10524294f337SSean Bruno ixl_set_rss_pctypes(struct ixl_pf *pf)
10534294f337SSean Bruno {
10544294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
10554294f337SSean Bruno 	u64		set_hena = 0, hena;
10564294f337SSean Bruno 
10574294f337SSean Bruno #ifdef RSS
10584294f337SSean Bruno 	u32		rss_hash_config;
10594294f337SSean Bruno 
10604294f337SSean Bruno 	rss_hash_config = rss_gethashconfig();
10614294f337SSean Bruno 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
10624294f337SSean Bruno                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
10634294f337SSean Bruno 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
10644294f337SSean Bruno                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
10654294f337SSean Bruno 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
10664294f337SSean Bruno                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP);
10674294f337SSean Bruno 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
10684294f337SSean Bruno                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
10694294f337SSean Bruno 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
10704294f337SSean Bruno 		set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
10714294f337SSean Bruno 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
10724294f337SSean Bruno                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
10734294f337SSean Bruno         if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
10744294f337SSean Bruno                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP);
10754294f337SSean Bruno #else
1076cb6b8299SEric Joyner 	if (hw->mac.type == I40E_MAC_X722)
1077cb6b8299SEric Joyner 		set_hena = IXL_DEFAULT_RSS_HENA_X722;
1078cb6b8299SEric Joyner 	else
1079cb6b8299SEric Joyner 		set_hena = IXL_DEFAULT_RSS_HENA_XL710;
10804294f337SSean Bruno #endif
10814294f337SSean Bruno 	hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) |
10824294f337SSean Bruno 	    ((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32);
10834294f337SSean Bruno 	hena |= set_hena;
10844294f337SSean Bruno 	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena);
10854294f337SSean Bruno 	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
10864294f337SSean Bruno 
10874294f337SSean Bruno }
10884294f337SSean Bruno 
10894294f337SSean Bruno /*
10904294f337SSean Bruno ** Setup the PF's RSS parameters.
10914294f337SSean Bruno */
10924294f337SSean Bruno void
ixl_config_rss(struct ixl_pf * pf)10934294f337SSean Bruno ixl_config_rss(struct ixl_pf *pf)
10944294f337SSean Bruno {
10954294f337SSean Bruno 	ixl_set_rss_key(pf);
10964294f337SSean Bruno 	ixl_set_rss_pctypes(pf);
10974294f337SSean Bruno 	ixl_set_rss_hlut(pf);
10984294f337SSean Bruno }
10994294f337SSean Bruno 
11004294f337SSean Bruno /*
11011031d839SEric Joyner  * In some firmware versions there is default MAC/VLAN filter
11021031d839SEric Joyner  * configured which interferes with filters managed by driver.
11031031d839SEric Joyner  * Make sure it's removed.
11041031d839SEric Joyner  */
110577c1fcecSEric Joyner void
ixl_del_default_hw_filters(struct ixl_vsi * vsi)11061031d839SEric Joyner ixl_del_default_hw_filters(struct ixl_vsi *vsi)
11071031d839SEric Joyner {
11081031d839SEric Joyner 	struct i40e_aqc_remove_macvlan_element_data e;
11091031d839SEric Joyner 
11101031d839SEric Joyner 	bzero(&e, sizeof(e));
11111031d839SEric Joyner 	bcopy(vsi->hw->mac.perm_addr, e.mac_addr, ETHER_ADDR_LEN);
11121031d839SEric Joyner 	e.vlan_tag = 0;
11131031d839SEric Joyner 	e.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
11141031d839SEric Joyner 	i40e_aq_remove_macvlan(vsi->hw, vsi->seid, &e, 1, NULL);
11151031d839SEric Joyner 
11161031d839SEric Joyner 	bzero(&e, sizeof(e));
11171031d839SEric Joyner 	bcopy(vsi->hw->mac.perm_addr, e.mac_addr, ETHER_ADDR_LEN);
11181031d839SEric Joyner 	e.vlan_tag = 0;
11191031d839SEric Joyner 	e.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH |
11201031d839SEric Joyner 		I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
11211031d839SEric Joyner 	i40e_aq_remove_macvlan(vsi->hw, vsi->seid, &e, 1, NULL);
11224294f337SSean Bruno }
11234294f337SSean Bruno 
11244294f337SSean Bruno /*
11254294f337SSean Bruno ** Initialize filter list and add filters that the hardware
11264294f337SSean Bruno ** needs to know about.
11274294f337SSean Bruno **
1128b4a7ce06SEric Joyner ** Requires VSI's seid to be set before calling.
11294294f337SSean Bruno */
11304294f337SSean Bruno void
ixl_init_filters(struct ixl_vsi * vsi)11314294f337SSean Bruno ixl_init_filters(struct ixl_vsi *vsi)
11324294f337SSean Bruno {
11334294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
11344294f337SSean Bruno 
1135b4a7ce06SEric Joyner 	ixl_dbg_filter(pf, "%s: start\n", __func__);
1136b4a7ce06SEric Joyner 
11371031d839SEric Joyner 	/* Initialize mac filter list for VSI */
11387d4dceecSKrzysztof Galazka 	LIST_INIT(&vsi->ftl);
1139b4a7ce06SEric Joyner 	vsi->num_hw_filters = 0;
11404294f337SSean Bruno 
11411031d839SEric Joyner 	/* Receive broadcast Ethernet frames */
11421031d839SEric Joyner 	i40e_aq_set_vsi_broadcast(&pf->hw, vsi->seid, TRUE, NULL);
11431031d839SEric Joyner 
1144b4a7ce06SEric Joyner 	if (IXL_VSI_IS_VF(vsi))
1145b4a7ce06SEric Joyner 		return;
1146b4a7ce06SEric Joyner 
11471031d839SEric Joyner 	ixl_del_default_hw_filters(vsi);
11481031d839SEric Joyner 
11491031d839SEric Joyner 	ixl_add_filter(vsi, vsi->hw->mac.addr, IXL_VLAN_ANY);
1150b4a7ce06SEric Joyner 
11514294f337SSean Bruno 	/*
11524294f337SSean Bruno 	 * Prevent Tx flow control frames from being sent out by
11534294f337SSean Bruno 	 * non-firmware transmitters.
11544294f337SSean Bruno 	 * This affects every VSI in the PF.
11554294f337SSean Bruno 	 */
1156b4a7ce06SEric Joyner #ifndef IXL_DEBUG_FC
1157b4a7ce06SEric Joyner 	i40e_add_filter_to_drop_tx_flow_control_frames(vsi->hw, vsi->seid);
1158b4a7ce06SEric Joyner #else
11594294f337SSean Bruno 	if (pf->enable_tx_fc_filter)
11604294f337SSean Bruno 		i40e_add_filter_to_drop_tx_flow_control_frames(vsi->hw, vsi->seid);
1161b4a7ce06SEric Joyner #endif
11624294f337SSean Bruno }
11634294f337SSean Bruno 
11644294f337SSean Bruno void
ixl_reconfigure_filters(struct ixl_vsi * vsi)11654294f337SSean Bruno ixl_reconfigure_filters(struct ixl_vsi *vsi)
11664294f337SSean Bruno {
11677d4dceecSKrzysztof Galazka 	struct i40e_hw *hw = vsi->hw;
11687d4dceecSKrzysztof Galazka 	struct ixl_ftl_head tmp;
11697d4dceecSKrzysztof Galazka 	int cnt;
11707d4dceecSKrzysztof Galazka 
11717d4dceecSKrzysztof Galazka 	/*
11727d4dceecSKrzysztof Galazka 	 * The ixl_add_hw_filters function adds filters configured
11737d4dceecSKrzysztof Galazka 	 * in HW to a list in VSI. Move all filters to a temporary
11747d4dceecSKrzysztof Galazka 	 * list to avoid corrupting it by concatenating to itself.
11757d4dceecSKrzysztof Galazka 	 */
11767d4dceecSKrzysztof Galazka 	LIST_INIT(&tmp);
11777d4dceecSKrzysztof Galazka 	LIST_CONCAT(&tmp, &vsi->ftl, ixl_mac_filter, ftle);
11787d4dceecSKrzysztof Galazka 	cnt = vsi->num_hw_filters;
11797d4dceecSKrzysztof Galazka 	vsi->num_hw_filters = 0;
11807d4dceecSKrzysztof Galazka 
11817d4dceecSKrzysztof Galazka 	ixl_add_hw_filters(vsi, &tmp, cnt);
11827d4dceecSKrzysztof Galazka 
1183e706512aSYan Ka Chiu 	/*
1184e706512aSYan Ka Chiu 	 * When the vsi is allocated for the VFs, both vsi->hw and vsi->ifp
1185e706512aSYan Ka Chiu 	 * will be NULL. Furthermore, the ftl of such vsi already contains
1186e706512aSYan Ka Chiu 	 * IXL_VLAN_ANY filter so we can skip that as well.
1187e706512aSYan Ka Chiu 	 */
1188e706512aSYan Ka Chiu 	if (hw == NULL)
1189e706512aSYan Ka Chiu 		return;
1190e706512aSYan Ka Chiu 
11917d4dceecSKrzysztof Galazka 	/* Filter could be removed if MAC address was changed */
11927d4dceecSKrzysztof Galazka 	ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
11937d4dceecSKrzysztof Galazka 
11947d4dceecSKrzysztof Galazka 	if ((if_getcapenable(vsi->ifp) & IFCAP_VLAN_HWFILTER) == 0)
11957d4dceecSKrzysztof Galazka 		return;
11967d4dceecSKrzysztof Galazka 	/*
11977d4dceecSKrzysztof Galazka 	 * VLAN HW filtering is enabled, make sure that filters
11987d4dceecSKrzysztof Galazka 	 * for all registered VLAN tags are configured
11997d4dceecSKrzysztof Galazka 	 */
12007d4dceecSKrzysztof Galazka 	ixl_add_vlan_filters(vsi, hw->mac.addr);
12014294f337SSean Bruno }
12024294f337SSean Bruno 
12034294f337SSean Bruno /*
120477c1fcecSEric Joyner  * This routine adds a MAC/VLAN filter to the software filter
120577c1fcecSEric Joyner  * list, then adds that new filter to the HW if it doesn't already
120677c1fcecSEric Joyner  * exist in the SW filter list.
12074294f337SSean Bruno  */
12084294f337SSean Bruno void
ixl_add_filter(struct ixl_vsi * vsi,const u8 * macaddr,s16 vlan)120933c66d8aSRyan Libby ixl_add_filter(struct ixl_vsi *vsi, const u8 *macaddr, s16 vlan)
12104294f337SSean Bruno {
12114294f337SSean Bruno 	struct ixl_mac_filter	*f, *tmp;
12124294f337SSean Bruno 	struct ixl_pf		*pf;
12134294f337SSean Bruno 	device_t		dev;
12147d4dceecSKrzysztof Galazka 	struct ixl_ftl_head	to_add;
12157d4dceecSKrzysztof Galazka 	int			to_add_cnt;
12164294f337SSean Bruno 
12174294f337SSean Bruno 	pf = vsi->back;
12184294f337SSean Bruno 	dev = pf->dev;
12197d4dceecSKrzysztof Galazka 	to_add_cnt = 1;
12204294f337SSean Bruno 
1221b4a7ce06SEric Joyner 	ixl_dbg_filter(pf, "ixl_add_filter: " MAC_FORMAT ", vlan %4d\n",
1222b4a7ce06SEric Joyner 	    MAC_FORMAT_ARGS(macaddr), vlan);
1223b4a7ce06SEric Joyner 
12244294f337SSean Bruno 	/* Does one already exist */
12257d4dceecSKrzysztof Galazka 	f = ixl_find_filter(&vsi->ftl, macaddr, vlan);
12264294f337SSean Bruno 	if (f != NULL)
12274294f337SSean Bruno 		return;
12284294f337SSean Bruno 
12297d4dceecSKrzysztof Galazka 	LIST_INIT(&to_add);
12307d4dceecSKrzysztof Galazka 	f = ixl_new_filter(&to_add, macaddr, vlan);
12314294f337SSean Bruno 	if (f == NULL) {
12324294f337SSean Bruno 		device_printf(dev, "WARNING: no filter available!!\n");
12334294f337SSean Bruno 		return;
12344294f337SSean Bruno 	}
12354294f337SSean Bruno 	if (f->vlan != IXL_VLAN_ANY)
12364294f337SSean Bruno 		f->flags |= IXL_FILTER_VLAN;
12374294f337SSean Bruno 	else
12384294f337SSean Bruno 		vsi->num_macs++;
12394294f337SSean Bruno 
12407d4dceecSKrzysztof Galazka 	/*
12417d4dceecSKrzysztof Galazka 	** Is this the first vlan being registered, if so we
12427d4dceecSKrzysztof Galazka 	** need to remove the ANY filter that indicates we are
12437d4dceecSKrzysztof Galazka 	** not in a vlan, and replace that with a 0 filter.
12447d4dceecSKrzysztof Galazka 	*/
12457d4dceecSKrzysztof Galazka 	if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) {
12467d4dceecSKrzysztof Galazka 		tmp = ixl_find_filter(&vsi->ftl, macaddr, IXL_VLAN_ANY);
12477d4dceecSKrzysztof Galazka 		if (tmp != NULL) {
12487d4dceecSKrzysztof Galazka 			struct ixl_ftl_head to_del;
12497d4dceecSKrzysztof Galazka 
12507d4dceecSKrzysztof Galazka 			/* Prepare new filter first to avoid removing
12517d4dceecSKrzysztof Galazka 			 * VLAN_ANY filter if allocation fails */
12527d4dceecSKrzysztof Galazka 			f = ixl_new_filter(&to_add, macaddr, 0);
12537d4dceecSKrzysztof Galazka 			if (f == NULL) {
12547d4dceecSKrzysztof Galazka 				device_printf(dev, "WARNING: no filter available!!\n");
12557d4dceecSKrzysztof Galazka 				free(LIST_FIRST(&to_add), M_IXL);
12567d4dceecSKrzysztof Galazka 				return;
12577d4dceecSKrzysztof Galazka 			}
12587d4dceecSKrzysztof Galazka 			to_add_cnt++;
12597d4dceecSKrzysztof Galazka 
12607d4dceecSKrzysztof Galazka 			LIST_REMOVE(tmp, ftle);
12617d4dceecSKrzysztof Galazka 			LIST_INIT(&to_del);
12627d4dceecSKrzysztof Galazka 			LIST_INSERT_HEAD(&to_del, tmp, ftle);
12637d4dceecSKrzysztof Galazka 			ixl_del_hw_filters(vsi, &to_del, 1);
12647d4dceecSKrzysztof Galazka 		}
12657d4dceecSKrzysztof Galazka 	}
12667d4dceecSKrzysztof Galazka 
12677d4dceecSKrzysztof Galazka 	ixl_add_hw_filters(vsi, &to_add, to_add_cnt);
12687d4dceecSKrzysztof Galazka }
12697d4dceecSKrzysztof Galazka 
12707d4dceecSKrzysztof Galazka /**
12717d4dceecSKrzysztof Galazka  * ixl_add_vlan_filters - Add MAC/VLAN filters for all registered VLANs
12727d4dceecSKrzysztof Galazka  * @vsi: pointer to VSI
12737d4dceecSKrzysztof Galazka  * @macaddr: MAC address
12747d4dceecSKrzysztof Galazka  *
12757d4dceecSKrzysztof Galazka  * Adds MAC/VLAN filter for each VLAN configured on the interface
12767d4dceecSKrzysztof Galazka  * if there is enough HW filters. Otherwise adds a single filter
12777d4dceecSKrzysztof Galazka  * for all tagged and untagged frames to allow all configured VLANs
12787d4dceecSKrzysztof Galazka  * to recieve traffic.
12797d4dceecSKrzysztof Galazka  */
12807d4dceecSKrzysztof Galazka void
ixl_add_vlan_filters(struct ixl_vsi * vsi,const u8 * macaddr)12817d4dceecSKrzysztof Galazka ixl_add_vlan_filters(struct ixl_vsi *vsi, const u8 *macaddr)
12827d4dceecSKrzysztof Galazka {
12837d4dceecSKrzysztof Galazka 	struct ixl_ftl_head to_add;
12847d4dceecSKrzysztof Galazka 	struct ixl_mac_filter *f;
12857d4dceecSKrzysztof Galazka 	int to_add_cnt = 0;
12867d4dceecSKrzysztof Galazka 	int i, vlan = 0;
12877d4dceecSKrzysztof Galazka 
12887d4dceecSKrzysztof Galazka 	if (vsi->num_vlans == 0 || vsi->num_vlans > IXL_MAX_VLAN_FILTERS) {
12897d4dceecSKrzysztof Galazka 		ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
12907d4dceecSKrzysztof Galazka 		return;
12917d4dceecSKrzysztof Galazka 	}
12927d4dceecSKrzysztof Galazka 	LIST_INIT(&to_add);
12937d4dceecSKrzysztof Galazka 
12947d4dceecSKrzysztof Galazka 	/* Add filter for untagged frames if it does not exist yet */
12957d4dceecSKrzysztof Galazka 	f = ixl_find_filter(&vsi->ftl, macaddr, 0);
12967d4dceecSKrzysztof Galazka 	if (f == NULL) {
12977d4dceecSKrzysztof Galazka 		f = ixl_new_filter(&to_add, macaddr, 0);
12987d4dceecSKrzysztof Galazka 		if (f == NULL) {
12997d4dceecSKrzysztof Galazka 			device_printf(vsi->dev, "WARNING: no filter available!!\n");
13007d4dceecSKrzysztof Galazka 			return;
13017d4dceecSKrzysztof Galazka 		}
13027d4dceecSKrzysztof Galazka 		to_add_cnt++;
13037d4dceecSKrzysztof Galazka 	}
13047d4dceecSKrzysztof Galazka 
13057d4dceecSKrzysztof Galazka 	for (i = 1; i < EVL_VLID_MASK; i = vlan + 1) {
13067d4dceecSKrzysztof Galazka 		bit_ffs_at(vsi->vlans_map, i, IXL_VLANS_MAP_LEN, &vlan);
13077d4dceecSKrzysztof Galazka 		if (vlan == -1)
13087d4dceecSKrzysztof Galazka 			break;
13097d4dceecSKrzysztof Galazka 
13107d4dceecSKrzysztof Galazka 		/* Does one already exist */
13117d4dceecSKrzysztof Galazka 		f = ixl_find_filter(&vsi->ftl, macaddr, vlan);
13127d4dceecSKrzysztof Galazka 		if (f != NULL)
13137d4dceecSKrzysztof Galazka 			continue;
13147d4dceecSKrzysztof Galazka 
13157d4dceecSKrzysztof Galazka 		f = ixl_new_filter(&to_add, macaddr, vlan);
13167d4dceecSKrzysztof Galazka 		if (f == NULL) {
13177d4dceecSKrzysztof Galazka 			device_printf(vsi->dev, "WARNING: no filter available!!\n");
13187d4dceecSKrzysztof Galazka 			ixl_free_filters(&to_add);
13197d4dceecSKrzysztof Galazka 			return;
13207d4dceecSKrzysztof Galazka 		}
13217d4dceecSKrzysztof Galazka 		to_add_cnt++;
13227d4dceecSKrzysztof Galazka 	}
13237d4dceecSKrzysztof Galazka 
13247d4dceecSKrzysztof Galazka 	ixl_add_hw_filters(vsi, &to_add, to_add_cnt);
13254294f337SSean Bruno }
13264294f337SSean Bruno 
13274294f337SSean Bruno void
ixl_del_filter(struct ixl_vsi * vsi,const u8 * macaddr,s16 vlan)132833c66d8aSRyan Libby ixl_del_filter(struct ixl_vsi *vsi, const u8 *macaddr, s16 vlan)
13294294f337SSean Bruno {
13307d4dceecSKrzysztof Galazka 	struct ixl_mac_filter *f, *tmp;
13317d4dceecSKrzysztof Galazka 	struct ixl_ftl_head ftl_head;
13327d4dceecSKrzysztof Galazka 	int to_del_cnt = 1;
13334294f337SSean Bruno 
1334b4a7ce06SEric Joyner 	ixl_dbg_filter((struct ixl_pf *)vsi->back,
1335b4a7ce06SEric Joyner 	    "ixl_del_filter: " MAC_FORMAT ", vlan %4d\n",
1336b4a7ce06SEric Joyner 	    MAC_FORMAT_ARGS(macaddr), vlan);
1337b4a7ce06SEric Joyner 
13387d4dceecSKrzysztof Galazka 	f = ixl_find_filter(&vsi->ftl, macaddr, vlan);
13394294f337SSean Bruno 	if (f == NULL)
13404294f337SSean Bruno 		return;
13414294f337SSean Bruno 
13427d4dceecSKrzysztof Galazka 	LIST_REMOVE(f, ftle);
13437d4dceecSKrzysztof Galazka 	LIST_INIT(&ftl_head);
13447d4dceecSKrzysztof Galazka 	LIST_INSERT_HEAD(&ftl_head, f, ftle);
13451031d839SEric Joyner 	if (f->vlan == IXL_VLAN_ANY && (f->flags & IXL_FILTER_VLAN) != 0)
13464294f337SSean Bruno 		vsi->num_macs--;
13474294f337SSean Bruno 
13487d4dceecSKrzysztof Galazka 	/* If this is not the last vlan just remove the filter */
13497d4dceecSKrzysztof Galazka 	if (vlan == IXL_VLAN_ANY || vsi->num_vlans > 0) {
13507d4dceecSKrzysztof Galazka 		ixl_del_hw_filters(vsi, &ftl_head, to_del_cnt);
13517d4dceecSKrzysztof Galazka 		return;
13527d4dceecSKrzysztof Galazka 	}
13537d4dceecSKrzysztof Galazka 
13547d4dceecSKrzysztof Galazka 	/* It's the last vlan, we need to switch back to a non-vlan filter */
13557d4dceecSKrzysztof Galazka 	tmp = ixl_find_filter(&vsi->ftl, macaddr, 0);
13567d4dceecSKrzysztof Galazka 	if (tmp != NULL) {
13577d4dceecSKrzysztof Galazka 		LIST_REMOVE(tmp, ftle);
13587d4dceecSKrzysztof Galazka 		LIST_INSERT_AFTER(f, tmp, ftle);
13597d4dceecSKrzysztof Galazka 		to_del_cnt++;
13607d4dceecSKrzysztof Galazka 	}
13617d4dceecSKrzysztof Galazka 	ixl_del_hw_filters(vsi, &ftl_head, to_del_cnt);
13627d4dceecSKrzysztof Galazka 
13634294f337SSean Bruno 	ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
13644294f337SSean Bruno }
13657d4dceecSKrzysztof Galazka 
13667d4dceecSKrzysztof Galazka /**
13677d4dceecSKrzysztof Galazka  * ixl_del_all_vlan_filters - Delete all VLAN filters with given MAC
13687d4dceecSKrzysztof Galazka  * @vsi: VSI which filters need to be removed
13697d4dceecSKrzysztof Galazka  * @macaddr: MAC address
13707d4dceecSKrzysztof Galazka  *
13717d4dceecSKrzysztof Galazka  * Remove all MAC/VLAN filters with a given MAC address. For multicast
13727d4dceecSKrzysztof Galazka  * addresses there is always single filter for all VLANs used (IXL_VLAN_ANY)
13737d4dceecSKrzysztof Galazka  * so skip them to speed up processing. Those filters should be removed
13747d4dceecSKrzysztof Galazka  * using ixl_del_filter function.
13757d4dceecSKrzysztof Galazka  */
13767d4dceecSKrzysztof Galazka void
ixl_del_all_vlan_filters(struct ixl_vsi * vsi,const u8 * macaddr)13777d4dceecSKrzysztof Galazka ixl_del_all_vlan_filters(struct ixl_vsi *vsi, const u8 *macaddr)
13787d4dceecSKrzysztof Galazka {
13797d4dceecSKrzysztof Galazka 	struct ixl_mac_filter *f, *tmp;
13807d4dceecSKrzysztof Galazka 	struct ixl_ftl_head to_del;
13817d4dceecSKrzysztof Galazka 	int to_del_cnt = 0;
13827d4dceecSKrzysztof Galazka 
13837d4dceecSKrzysztof Galazka 	LIST_INIT(&to_del);
13847d4dceecSKrzysztof Galazka 
13857d4dceecSKrzysztof Galazka 	LIST_FOREACH_SAFE(f, &vsi->ftl, ftle, tmp) {
13867d4dceecSKrzysztof Galazka 		if ((f->flags & IXL_FILTER_MC) != 0 ||
13877d4dceecSKrzysztof Galazka 		    !ixl_ether_is_equal(f->macaddr, macaddr))
13887d4dceecSKrzysztof Galazka 			continue;
13897d4dceecSKrzysztof Galazka 
13907d4dceecSKrzysztof Galazka 		LIST_REMOVE(f, ftle);
13917d4dceecSKrzysztof Galazka 		LIST_INSERT_HEAD(&to_del, f, ftle);
13927d4dceecSKrzysztof Galazka 		to_del_cnt++;
13937d4dceecSKrzysztof Galazka 	}
13947d4dceecSKrzysztof Galazka 
13957d4dceecSKrzysztof Galazka 	ixl_dbg_filter((struct ixl_pf *)vsi->back,
13967d4dceecSKrzysztof Galazka 	    "%s: " MAC_FORMAT ", to_del_cnt: %d\n",
13977d4dceecSKrzysztof Galazka 	    __func__, MAC_FORMAT_ARGS(macaddr), to_del_cnt);
13987d4dceecSKrzysztof Galazka 	if (to_del_cnt > 0)
13997d4dceecSKrzysztof Galazka 		ixl_del_hw_filters(vsi, &to_del, to_del_cnt);
14004294f337SSean Bruno }
14014294f337SSean Bruno 
14024294f337SSean Bruno /*
14034294f337SSean Bruno ** Find the filter with both matching mac addr and vlan id
14044294f337SSean Bruno */
14054294f337SSean Bruno struct ixl_mac_filter *
ixl_find_filter(struct ixl_ftl_head * headp,const u8 * macaddr,s16 vlan)14067d4dceecSKrzysztof Galazka ixl_find_filter(struct ixl_ftl_head *headp, const u8 *macaddr, s16 vlan)
14074294f337SSean Bruno {
14084294f337SSean Bruno 	struct ixl_mac_filter	*f;
14094294f337SSean Bruno 
14107d4dceecSKrzysztof Galazka 	LIST_FOREACH(f, headp, ftle) {
14117d4dceecSKrzysztof Galazka 		if (ixl_ether_is_equal(f->macaddr, macaddr) &&
14127d4dceecSKrzysztof Galazka 		    (f->vlan == vlan)) {
14131031d839SEric Joyner 			return (f);
14144294f337SSean Bruno 		}
14154294f337SSean Bruno 	}
14164294f337SSean Bruno 
14171031d839SEric Joyner 	return (NULL);
14184294f337SSean Bruno }
14194294f337SSean Bruno 
14204294f337SSean Bruno /*
14214294f337SSean Bruno ** This routine takes additions to the vsi filter
14224294f337SSean Bruno ** table and creates an Admin Queue call to create
14234294f337SSean Bruno ** the filters in the hardware.
14244294f337SSean Bruno */
14254294f337SSean Bruno void
ixl_add_hw_filters(struct ixl_vsi * vsi,struct ixl_ftl_head * to_add,int cnt)14267d4dceecSKrzysztof Galazka ixl_add_hw_filters(struct ixl_vsi *vsi, struct ixl_ftl_head *to_add, int cnt)
14274294f337SSean Bruno {
14284294f337SSean Bruno 	struct i40e_aqc_add_macvlan_element_data *a, *b;
14297d4dceecSKrzysztof Galazka 	struct ixl_mac_filter	*f, *fn;
14304294f337SSean Bruno 	struct ixl_pf		*pf;
14314294f337SSean Bruno 	struct i40e_hw		*hw;
14324294f337SSean Bruno 	device_t		dev;
14331031d839SEric Joyner 	enum i40e_status_code	status;
14341031d839SEric Joyner 	int			j = 0;
14351031d839SEric Joyner 
14364294f337SSean Bruno 	pf = vsi->back;
143777c1fcecSEric Joyner 	dev = vsi->dev;
14384294f337SSean Bruno 	hw = &pf->hw;
14394294f337SSean Bruno 
14407d4dceecSKrzysztof Galazka 	ixl_dbg_filter(pf, "ixl_add_hw_filters: cnt: %d\n", cnt);
1441b4a7ce06SEric Joyner 
144277c1fcecSEric Joyner 	if (cnt < 1) {
144377c1fcecSEric Joyner 		ixl_dbg_info(pf, "ixl_add_hw_filters: cnt == 0\n");
144477c1fcecSEric Joyner 		return;
144577c1fcecSEric Joyner 	}
144677c1fcecSEric Joyner 
1447ac2fffa4SPedro F. Giffuni 	a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
14487d4dceecSKrzysztof Galazka 	    M_IXL, M_NOWAIT | M_ZERO);
14494294f337SSean Bruno 	if (a == NULL) {
14504294f337SSean Bruno 		device_printf(dev, "add_hw_filters failed to get memory\n");
14514294f337SSean Bruno 		return;
14524294f337SSean Bruno 	}
14534294f337SSean Bruno 
14547d4dceecSKrzysztof Galazka 	LIST_FOREACH(f, to_add, ftle) {
14554294f337SSean Bruno 		b = &a[j]; // a pox on fvl long names :)
14564294f337SSean Bruno 		bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN);
14574294f337SSean Bruno 		if (f->vlan == IXL_VLAN_ANY) {
14584294f337SSean Bruno 			b->vlan_tag = 0;
14597d4dceecSKrzysztof Galazka 			b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
14604294f337SSean Bruno 		} else {
14617d4dceecSKrzysztof Galazka 			b->vlan_tag = f->vlan;
14624294f337SSean Bruno 			b->flags = 0;
14634294f337SSean Bruno 		}
14647d4dceecSKrzysztof Galazka 		b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
14651d02c6b1SKrzysztof Galazka 		/* Some FW versions do not set match method
14661d02c6b1SKrzysztof Galazka 		 * when adding filters fails. Initialize it with
14671d02c6b1SKrzysztof Galazka 		 * expected error value to allow detection which
14681d02c6b1SKrzysztof Galazka 		 * filters were not added */
14691d02c6b1SKrzysztof Galazka 		b->match_method = I40E_AQC_MM_ERR_NO_RES;
147077c1fcecSEric Joyner 		ixl_dbg_filter(pf, "ADD: " MAC_FORMAT "\n",
147177c1fcecSEric Joyner 		    MAC_FORMAT_ARGS(f->macaddr));
14727d4dceecSKrzysztof Galazka 
14737d4dceecSKrzysztof Galazka 		if (++j == cnt)
14744294f337SSean Bruno 			break;
14754294f337SSean Bruno 	}
14767d4dceecSKrzysztof Galazka 	if (j != cnt) {
14777d4dceecSKrzysztof Galazka 		/* Something went wrong */
14787d4dceecSKrzysztof Galazka 		device_printf(dev,
14797d4dceecSKrzysztof Galazka 		    "%s ERROR: list of filters to short expected: %d, found: %d\n",
14807d4dceecSKrzysztof Galazka 		    __func__, cnt, j);
14817d4dceecSKrzysztof Galazka 		ixl_free_filters(to_add);
14827d4dceecSKrzysztof Galazka 		goto out_free;
14834294f337SSean Bruno 	}
14847d4dceecSKrzysztof Galazka 
14857d4dceecSKrzysztof Galazka 	status = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL);
14867d4dceecSKrzysztof Galazka 	if (status == I40E_SUCCESS) {
14877d4dceecSKrzysztof Galazka 		LIST_CONCAT(&vsi->ftl, to_add, ixl_mac_filter, ftle);
14887d4dceecSKrzysztof Galazka 		vsi->num_hw_filters += j;
14897d4dceecSKrzysztof Galazka 		goto out_free;
14907d4dceecSKrzysztof Galazka 	}
14917d4dceecSKrzysztof Galazka 
14927d4dceecSKrzysztof Galazka 	device_printf(dev,
14937d4dceecSKrzysztof Galazka 	    "i40e_aq_add_macvlan status %s, error %s\n",
14947d4dceecSKrzysztof Galazka 	    i40e_stat_str(hw, status),
14957d4dceecSKrzysztof Galazka 	    i40e_aq_str(hw, hw->aq.asq_last_status));
14967d4dceecSKrzysztof Galazka 	j = 0;
14977d4dceecSKrzysztof Galazka 
14987d4dceecSKrzysztof Galazka 	/* Verify which filters were actually configured in HW
14997d4dceecSKrzysztof Galazka 	 * and add them to the list */
15007d4dceecSKrzysztof Galazka 	LIST_FOREACH_SAFE(f, to_add, ftle, fn) {
15017d4dceecSKrzysztof Galazka 		LIST_REMOVE(f, ftle);
15027d4dceecSKrzysztof Galazka 		if (a[j].match_method == I40E_AQC_MM_ERR_NO_RES) {
15037d4dceecSKrzysztof Galazka 			ixl_dbg_filter(pf,
15047d4dceecSKrzysztof Galazka 			    "%s filter " MAC_FORMAT " VTAG: %d not added\n",
15057d4dceecSKrzysztof Galazka 			    __func__,
15067d4dceecSKrzysztof Galazka 			    MAC_FORMAT_ARGS(f->macaddr),
15077d4dceecSKrzysztof Galazka 			    f->vlan);
15087d4dceecSKrzysztof Galazka 			free(f, M_IXL);
15097d4dceecSKrzysztof Galazka 		} else {
15107d4dceecSKrzysztof Galazka 			LIST_INSERT_HEAD(&vsi->ftl, f, ftle);
15117d4dceecSKrzysztof Galazka 			vsi->num_hw_filters++;
15127d4dceecSKrzysztof Galazka 		}
15137d4dceecSKrzysztof Galazka 		j++;
15147d4dceecSKrzysztof Galazka 	}
15157d4dceecSKrzysztof Galazka 
15167d4dceecSKrzysztof Galazka out_free:
15177d4dceecSKrzysztof Galazka 	free(a, M_IXL);
15184294f337SSean Bruno }
15194294f337SSean Bruno 
15204294f337SSean Bruno /*
15214294f337SSean Bruno ** This routine takes removals in the vsi filter
15224294f337SSean Bruno ** table and creates an Admin Queue call to delete
15234294f337SSean Bruno ** the filters in the hardware.
15244294f337SSean Bruno */
15254294f337SSean Bruno void
ixl_del_hw_filters(struct ixl_vsi * vsi,struct ixl_ftl_head * to_del,int cnt)15267d4dceecSKrzysztof Galazka ixl_del_hw_filters(struct ixl_vsi *vsi, struct ixl_ftl_head *to_del, int cnt)
15274294f337SSean Bruno {
15284294f337SSean Bruno 	struct i40e_aqc_remove_macvlan_element_data *d, *e;
15294294f337SSean Bruno 	struct ixl_pf		*pf;
15304294f337SSean Bruno 	struct i40e_hw		*hw;
15314294f337SSean Bruno 	device_t		dev;
15324294f337SSean Bruno 	struct ixl_mac_filter	*f, *f_temp;
15331031d839SEric Joyner 	enum i40e_status_code	status;
15341031d839SEric Joyner 	int			j = 0;
15354294f337SSean Bruno 
15364294f337SSean Bruno 	pf = vsi->back;
15374294f337SSean Bruno 	hw = &pf->hw;
153877c1fcecSEric Joyner 	dev = vsi->dev;
15394294f337SSean Bruno 
1540b4a7ce06SEric Joyner 	ixl_dbg_filter(pf, "%s: start, cnt: %d\n", __func__, cnt);
1541b4a7ce06SEric Joyner 
1542ac2fffa4SPedro F. Giffuni 	d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
15437d4dceecSKrzysztof Galazka 	    M_IXL, M_NOWAIT | M_ZERO);
15444294f337SSean Bruno 	if (d == NULL) {
15451031d839SEric Joyner 		device_printf(dev, "%s: failed to get memory\n", __func__);
15464294f337SSean Bruno 		return;
15474294f337SSean Bruno 	}
15484294f337SSean Bruno 
15497d4dceecSKrzysztof Galazka 	LIST_FOREACH_SAFE(f, to_del, ftle, f_temp) {
15504294f337SSean Bruno 		e = &d[j]; // a pox on fvl long names :)
15514294f337SSean Bruno 		bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN);
15524294f337SSean Bruno 		e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
1553ceebc2f3SEric Joyner 		if (f->vlan == IXL_VLAN_ANY) {
1554ceebc2f3SEric Joyner 			e->vlan_tag = 0;
1555ceebc2f3SEric Joyner 			e->flags |= I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
1556ceebc2f3SEric Joyner 		} else {
1557ceebc2f3SEric Joyner 			e->vlan_tag = f->vlan;
1558ceebc2f3SEric Joyner 		}
155977c1fcecSEric Joyner 
156077c1fcecSEric Joyner 		ixl_dbg_filter(pf, "DEL: " MAC_FORMAT "\n",
156177c1fcecSEric Joyner 		    MAC_FORMAT_ARGS(f->macaddr));
156277c1fcecSEric Joyner 
15637d4dceecSKrzysztof Galazka 		/* delete entry from the list */
15647d4dceecSKrzysztof Galazka 		LIST_REMOVE(f, ftle);
15657d4dceecSKrzysztof Galazka 		free(f, M_IXL);
15667d4dceecSKrzysztof Galazka 		if (++j == cnt)
15674294f337SSean Bruno 			break;
15684294f337SSean Bruno 	}
15697d4dceecSKrzysztof Galazka 	if (j != cnt || !LIST_EMPTY(to_del)) {
15707d4dceecSKrzysztof Galazka 		/* Something went wrong */
15717d4dceecSKrzysztof Galazka 		device_printf(dev,
15727d4dceecSKrzysztof Galazka 		    "%s ERROR: wrong size of list of filters, expected: %d, found: %d\n",
15737d4dceecSKrzysztof Galazka 		    __func__, cnt, j);
15747d4dceecSKrzysztof Galazka 		ixl_free_filters(to_del);
15757d4dceecSKrzysztof Galazka 		goto out_free;
15767d4dceecSKrzysztof Galazka 	}
15771031d839SEric Joyner 	status = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL);
15781031d839SEric Joyner 	if (status) {
15794294f337SSean Bruno 		device_printf(dev,
15807d4dceecSKrzysztof Galazka 		    "%s: i40e_aq_remove_macvlan status %s, error %s\n",
15817d4dceecSKrzysztof Galazka 		    __func__, i40e_stat_str(hw, status),
15827d4dceecSKrzysztof Galazka 		    i40e_aq_str(hw, hw->aq.asq_last_status));
15837d4dceecSKrzysztof Galazka 		for (int i = 0; i < j; i++) {
15847d4dceecSKrzysztof Galazka 			if (d[i].error_code == 0)
15857d4dceecSKrzysztof Galazka 				continue;
15867d4dceecSKrzysztof Galazka 			device_printf(dev,
15877d4dceecSKrzysztof Galazka 			    "%s Filter does not exist " MAC_FORMAT " VTAG: %d\n",
15887d4dceecSKrzysztof Galazka 			    __func__, MAC_FORMAT_ARGS(d[i].mac_addr),
15897d4dceecSKrzysztof Galazka 			    d[i].vlan_tag);
15904294f337SSean Bruno 		}
15917d4dceecSKrzysztof Galazka 	}
15927d4dceecSKrzysztof Galazka 
15937d4dceecSKrzysztof Galazka 	vsi->num_hw_filters -= j;
15947d4dceecSKrzysztof Galazka 
15957d4dceecSKrzysztof Galazka out_free:
15967d4dceecSKrzysztof Galazka 	free(d, M_IXL);
1597b4a7ce06SEric Joyner 
1598b4a7ce06SEric Joyner 	ixl_dbg_filter(pf, "%s: end\n", __func__);
15994294f337SSean Bruno }
16004294f337SSean Bruno 
16014294f337SSean Bruno int
ixl_enable_tx_ring(struct ixl_pf * pf,struct ixl_pf_qtag * qtag,u16 vsi_qidx)16024294f337SSean Bruno ixl_enable_tx_ring(struct ixl_pf *pf, struct ixl_pf_qtag *qtag, u16 vsi_qidx)
16034294f337SSean Bruno {
16044294f337SSean Bruno 	struct i40e_hw	*hw = &pf->hw;
16054294f337SSean Bruno 	int		error = 0;
16064294f337SSean Bruno 	u32		reg;
16074294f337SSean Bruno 	u16		pf_qidx;
16084294f337SSean Bruno 
16094294f337SSean Bruno 	pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
16104294f337SSean Bruno 
16114294f337SSean Bruno 	ixl_dbg(pf, IXL_DBG_EN_DIS,
16124294f337SSean Bruno 	    "Enabling PF TX ring %4d / VSI TX ring %4d...\n",
16134294f337SSean Bruno 	    pf_qidx, vsi_qidx);
16144294f337SSean Bruno 
16154294f337SSean Bruno 	i40e_pre_tx_queue_cfg(hw, pf_qidx, TRUE);
16164294f337SSean Bruno 
16174294f337SSean Bruno 	reg = rd32(hw, I40E_QTX_ENA(pf_qidx));
16184294f337SSean Bruno 	reg |= I40E_QTX_ENA_QENA_REQ_MASK |
16194294f337SSean Bruno 	    I40E_QTX_ENA_QENA_STAT_MASK;
16204294f337SSean Bruno 	wr32(hw, I40E_QTX_ENA(pf_qidx), reg);
16214294f337SSean Bruno 	/* Verify the enable took */
16224294f337SSean Bruno 	for (int j = 0; j < 10; j++) {
16234294f337SSean Bruno 		reg = rd32(hw, I40E_QTX_ENA(pf_qidx));
16244294f337SSean Bruno 		if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
16254294f337SSean Bruno 			break;
1626ceebc2f3SEric Joyner 		i40e_usec_delay(10);
16274294f337SSean Bruno 	}
16284294f337SSean Bruno 	if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) {
16294294f337SSean Bruno 		device_printf(pf->dev, "TX queue %d still disabled!\n",
16304294f337SSean Bruno 		    pf_qidx);
16314294f337SSean Bruno 		error = ETIMEDOUT;
16324294f337SSean Bruno 	}
16334294f337SSean Bruno 
16344294f337SSean Bruno 	return (error);
16354294f337SSean Bruno }
16364294f337SSean Bruno 
16374294f337SSean Bruno int
ixl_enable_rx_ring(struct ixl_pf * pf,struct ixl_pf_qtag * qtag,u16 vsi_qidx)16384294f337SSean Bruno ixl_enable_rx_ring(struct ixl_pf *pf, struct ixl_pf_qtag *qtag, u16 vsi_qidx)
16394294f337SSean Bruno {
16404294f337SSean Bruno 	struct i40e_hw	*hw = &pf->hw;
16414294f337SSean Bruno 	int		error = 0;
16424294f337SSean Bruno 	u32		reg;
16434294f337SSean Bruno 	u16		pf_qidx;
16444294f337SSean Bruno 
16454294f337SSean Bruno 	pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
16464294f337SSean Bruno 
16474294f337SSean Bruno 	ixl_dbg(pf, IXL_DBG_EN_DIS,
16484294f337SSean Bruno 	    "Enabling PF RX ring %4d / VSI RX ring %4d...\n",
16494294f337SSean Bruno 	    pf_qidx, vsi_qidx);
16504294f337SSean Bruno 
16514294f337SSean Bruno 	reg = rd32(hw, I40E_QRX_ENA(pf_qidx));
16524294f337SSean Bruno 	reg |= I40E_QRX_ENA_QENA_REQ_MASK |
16534294f337SSean Bruno 	    I40E_QRX_ENA_QENA_STAT_MASK;
16544294f337SSean Bruno 	wr32(hw, I40E_QRX_ENA(pf_qidx), reg);
16554294f337SSean Bruno 	/* Verify the enable took */
16564294f337SSean Bruno 	for (int j = 0; j < 10; j++) {
16574294f337SSean Bruno 		reg = rd32(hw, I40E_QRX_ENA(pf_qidx));
16584294f337SSean Bruno 		if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
16594294f337SSean Bruno 			break;
1660ceebc2f3SEric Joyner 		i40e_usec_delay(10);
16614294f337SSean Bruno 	}
16624294f337SSean Bruno 	if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) {
16634294f337SSean Bruno 		device_printf(pf->dev, "RX queue %d still disabled!\n",
16644294f337SSean Bruno 		    pf_qidx);
16654294f337SSean Bruno 		error = ETIMEDOUT;
16664294f337SSean Bruno 	}
16674294f337SSean Bruno 
16684294f337SSean Bruno 	return (error);
16694294f337SSean Bruno }
16704294f337SSean Bruno 
16714294f337SSean Bruno int
ixl_enable_ring(struct ixl_pf * pf,struct ixl_pf_qtag * qtag,u16 vsi_qidx)16724294f337SSean Bruno ixl_enable_ring(struct ixl_pf *pf, struct ixl_pf_qtag *qtag, u16 vsi_qidx)
16734294f337SSean Bruno {
16744294f337SSean Bruno 	int error = 0;
16754294f337SSean Bruno 
16764294f337SSean Bruno 	error = ixl_enable_tx_ring(pf, qtag, vsi_qidx);
16774294f337SSean Bruno 	/* Called function already prints error message */
16784294f337SSean Bruno 	if (error)
16794294f337SSean Bruno 		return (error);
16804294f337SSean Bruno 	error = ixl_enable_rx_ring(pf, qtag, vsi_qidx);
16814294f337SSean Bruno 	return (error);
16824294f337SSean Bruno }
16834294f337SSean Bruno 
1684ceebc2f3SEric Joyner /*
1685ceebc2f3SEric Joyner  * Returns error on first ring that is detected hung.
1686ceebc2f3SEric Joyner  */
16874294f337SSean Bruno int
ixl_disable_tx_ring(struct ixl_pf * pf,struct ixl_pf_qtag * qtag,u16 vsi_qidx)16884294f337SSean Bruno ixl_disable_tx_ring(struct ixl_pf *pf, struct ixl_pf_qtag *qtag, u16 vsi_qidx)
16894294f337SSean Bruno {
16904294f337SSean Bruno 	struct i40e_hw	*hw = &pf->hw;
16914294f337SSean Bruno 	int		error = 0;
16924294f337SSean Bruno 	u32		reg;
16934294f337SSean Bruno 	u16		pf_qidx;
16944294f337SSean Bruno 
16954294f337SSean Bruno 	pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
16964294f337SSean Bruno 
1697b4a7ce06SEric Joyner 	ixl_dbg(pf, IXL_DBG_EN_DIS,
1698b4a7ce06SEric Joyner 	    "Disabling PF TX ring %4d / VSI TX ring %4d...\n",
1699b4a7ce06SEric Joyner 	    pf_qidx, vsi_qidx);
1700b4a7ce06SEric Joyner 
17014294f337SSean Bruno 	i40e_pre_tx_queue_cfg(hw, pf_qidx, FALSE);
17024294f337SSean Bruno 	i40e_usec_delay(500);
17034294f337SSean Bruno 
17044294f337SSean Bruno 	reg = rd32(hw, I40E_QTX_ENA(pf_qidx));
17054294f337SSean Bruno 	reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
17064294f337SSean Bruno 	wr32(hw, I40E_QTX_ENA(pf_qidx), reg);
17074294f337SSean Bruno 	/* Verify the disable took */
17084294f337SSean Bruno 	for (int j = 0; j < 10; j++) {
17094294f337SSean Bruno 		reg = rd32(hw, I40E_QTX_ENA(pf_qidx));
17104294f337SSean Bruno 		if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
17114294f337SSean Bruno 			break;
17124294f337SSean Bruno 		i40e_msec_delay(10);
17134294f337SSean Bruno 	}
17144294f337SSean Bruno 	if (reg & I40E_QTX_ENA_QENA_STAT_MASK) {
17154294f337SSean Bruno 		device_printf(pf->dev, "TX queue %d still enabled!\n",
17164294f337SSean Bruno 		    pf_qidx);
17174294f337SSean Bruno 		error = ETIMEDOUT;
17184294f337SSean Bruno 	}
17194294f337SSean Bruno 
17204294f337SSean Bruno 	return (error);
17214294f337SSean Bruno }
17224294f337SSean Bruno 
1723ceebc2f3SEric Joyner /*
1724ceebc2f3SEric Joyner  * Returns error on first ring that is detected hung.
1725ceebc2f3SEric Joyner  */
17264294f337SSean Bruno int
ixl_disable_rx_ring(struct ixl_pf * pf,struct ixl_pf_qtag * qtag,u16 vsi_qidx)17274294f337SSean Bruno ixl_disable_rx_ring(struct ixl_pf *pf, struct ixl_pf_qtag *qtag, u16 vsi_qidx)
17284294f337SSean Bruno {
17294294f337SSean Bruno 	struct i40e_hw	*hw = &pf->hw;
17304294f337SSean Bruno 	int		error = 0;
17314294f337SSean Bruno 	u32		reg;
17324294f337SSean Bruno 	u16		pf_qidx;
17334294f337SSean Bruno 
17344294f337SSean Bruno 	pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
17354294f337SSean Bruno 
1736b4a7ce06SEric Joyner 	ixl_dbg(pf, IXL_DBG_EN_DIS,
1737b4a7ce06SEric Joyner 	    "Disabling PF RX ring %4d / VSI RX ring %4d...\n",
1738b4a7ce06SEric Joyner 	    pf_qidx, vsi_qidx);
1739b4a7ce06SEric Joyner 
17404294f337SSean Bruno 	reg = rd32(hw, I40E_QRX_ENA(pf_qidx));
17414294f337SSean Bruno 	reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
17424294f337SSean Bruno 	wr32(hw, I40E_QRX_ENA(pf_qidx), reg);
17434294f337SSean Bruno 	/* Verify the disable took */
17444294f337SSean Bruno 	for (int j = 0; j < 10; j++) {
17454294f337SSean Bruno 		reg = rd32(hw, I40E_QRX_ENA(pf_qidx));
17464294f337SSean Bruno 		if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
17474294f337SSean Bruno 			break;
17484294f337SSean Bruno 		i40e_msec_delay(10);
17494294f337SSean Bruno 	}
17504294f337SSean Bruno 	if (reg & I40E_QRX_ENA_QENA_STAT_MASK) {
17514294f337SSean Bruno 		device_printf(pf->dev, "RX queue %d still enabled!\n",
17524294f337SSean Bruno 		    pf_qidx);
17534294f337SSean Bruno 		error = ETIMEDOUT;
17544294f337SSean Bruno 	}
17554294f337SSean Bruno 
17564294f337SSean Bruno 	return (error);
17574294f337SSean Bruno }
17584294f337SSean Bruno 
17594294f337SSean Bruno int
ixl_disable_ring(struct ixl_pf * pf,struct ixl_pf_qtag * qtag,u16 vsi_qidx)17604294f337SSean Bruno ixl_disable_ring(struct ixl_pf *pf, struct ixl_pf_qtag *qtag, u16 vsi_qidx)
17614294f337SSean Bruno {
17624294f337SSean Bruno 	int error = 0;
17634294f337SSean Bruno 
17644294f337SSean Bruno 	error = ixl_disable_tx_ring(pf, qtag, vsi_qidx);
17654294f337SSean Bruno 	/* Called function already prints error message */
17664294f337SSean Bruno 	if (error)
17674294f337SSean Bruno 		return (error);
17684294f337SSean Bruno 	error = ixl_disable_rx_ring(pf, qtag, vsi_qidx);
17694294f337SSean Bruno 	return (error);
17704294f337SSean Bruno }
17714294f337SSean Bruno 
177277c1fcecSEric Joyner static void
ixl_handle_tx_mdd_event(struct ixl_pf * pf)177377c1fcecSEric Joyner ixl_handle_tx_mdd_event(struct ixl_pf *pf)
177477c1fcecSEric Joyner {
177577c1fcecSEric Joyner 	struct i40e_hw *hw = &pf->hw;
177677c1fcecSEric Joyner 	device_t dev = pf->dev;
177777c1fcecSEric Joyner 	struct ixl_vf *vf;
177877c1fcecSEric Joyner 	bool mdd_detected = false;
177977c1fcecSEric Joyner 	bool pf_mdd_detected = false;
178077c1fcecSEric Joyner 	bool vf_mdd_detected = false;
178177c1fcecSEric Joyner 	u16 vf_num, queue;
178277c1fcecSEric Joyner 	u8 pf_num, event;
178377c1fcecSEric Joyner 	u8 pf_mdet_num, vp_mdet_num;
178477c1fcecSEric Joyner 	u32 reg;
178577c1fcecSEric Joyner 
178677c1fcecSEric Joyner 	/* find what triggered the MDD event */
178777c1fcecSEric Joyner 	reg = rd32(hw, I40E_GL_MDET_TX);
178877c1fcecSEric Joyner 	if (reg & I40E_GL_MDET_TX_VALID_MASK) {
178977c1fcecSEric Joyner 		pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
179077c1fcecSEric Joyner 		    I40E_GL_MDET_TX_PF_NUM_SHIFT;
179177c1fcecSEric Joyner 		vf_num = (reg & I40E_GL_MDET_TX_VF_NUM_MASK) >>
179277c1fcecSEric Joyner 		    I40E_GL_MDET_TX_VF_NUM_SHIFT;
179377c1fcecSEric Joyner 		event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
179477c1fcecSEric Joyner 		    I40E_GL_MDET_TX_EVENT_SHIFT;
179577c1fcecSEric Joyner 		queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
179677c1fcecSEric Joyner 		    I40E_GL_MDET_TX_QUEUE_SHIFT;
179777c1fcecSEric Joyner 		wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
179877c1fcecSEric Joyner 		mdd_detected = true;
179977c1fcecSEric Joyner 	}
180077c1fcecSEric Joyner 
180177c1fcecSEric Joyner 	if (!mdd_detected)
180277c1fcecSEric Joyner 		return;
180377c1fcecSEric Joyner 
180477c1fcecSEric Joyner 	reg = rd32(hw, I40E_PF_MDET_TX);
180577c1fcecSEric Joyner 	if (reg & I40E_PF_MDET_TX_VALID_MASK) {
180677c1fcecSEric Joyner 		wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
180777c1fcecSEric Joyner 		pf_mdet_num = hw->pf_id;
180877c1fcecSEric Joyner 		pf_mdd_detected = true;
180977c1fcecSEric Joyner 	}
181077c1fcecSEric Joyner 
181177c1fcecSEric Joyner 	/* Check if MDD was caused by a VF */
181277c1fcecSEric Joyner 	for (int i = 0; i < pf->num_vfs; i++) {
181377c1fcecSEric Joyner 		vf = &(pf->vfs[i]);
181477c1fcecSEric Joyner 		reg = rd32(hw, I40E_VP_MDET_TX(i));
181577c1fcecSEric Joyner 		if (reg & I40E_VP_MDET_TX_VALID_MASK) {
181677c1fcecSEric Joyner 			wr32(hw, I40E_VP_MDET_TX(i), 0xFFFF);
181777c1fcecSEric Joyner 			vp_mdet_num = i;
181877c1fcecSEric Joyner 			vf->num_mdd_events++;
181977c1fcecSEric Joyner 			vf_mdd_detected = true;
182077c1fcecSEric Joyner 		}
182177c1fcecSEric Joyner 	}
182277c1fcecSEric Joyner 
182377c1fcecSEric Joyner 	/* Print out an error message */
182477c1fcecSEric Joyner 	if (vf_mdd_detected && pf_mdd_detected)
182577c1fcecSEric Joyner 		device_printf(dev,
182677c1fcecSEric Joyner 		    "Malicious Driver Detection event %d"
182777c1fcecSEric Joyner 		    " on TX queue %d, pf number %d (PF-%d), vf number %d (VF-%d)\n",
182877c1fcecSEric Joyner 		    event, queue, pf_num, pf_mdet_num, vf_num, vp_mdet_num);
182977c1fcecSEric Joyner 	else if (vf_mdd_detected && !pf_mdd_detected)
183077c1fcecSEric Joyner 		device_printf(dev,
183177c1fcecSEric Joyner 		    "Malicious Driver Detection event %d"
183277c1fcecSEric Joyner 		    " on TX queue %d, pf number %d, vf number %d (VF-%d)\n",
183377c1fcecSEric Joyner 		    event, queue, pf_num, vf_num, vp_mdet_num);
183477c1fcecSEric Joyner 	else if (!vf_mdd_detected && pf_mdd_detected)
183577c1fcecSEric Joyner 		device_printf(dev,
183677c1fcecSEric Joyner 		    "Malicious Driver Detection event %d"
183777c1fcecSEric Joyner 		    " on TX queue %d, pf number %d (PF-%d)\n",
183877c1fcecSEric Joyner 		    event, queue, pf_num, pf_mdet_num);
183977c1fcecSEric Joyner 	/* Theoretically shouldn't happen */
184077c1fcecSEric Joyner 	else
184177c1fcecSEric Joyner 		device_printf(dev,
184277c1fcecSEric Joyner 		    "TX Malicious Driver Detection event (unknown)\n");
184377c1fcecSEric Joyner }
184477c1fcecSEric Joyner 
184577c1fcecSEric Joyner static void
ixl_handle_rx_mdd_event(struct ixl_pf * pf)184677c1fcecSEric Joyner ixl_handle_rx_mdd_event(struct ixl_pf *pf)
184777c1fcecSEric Joyner {
184877c1fcecSEric Joyner 	struct i40e_hw *hw = &pf->hw;
184977c1fcecSEric Joyner 	device_t dev = pf->dev;
185077c1fcecSEric Joyner 	struct ixl_vf *vf;
185177c1fcecSEric Joyner 	bool mdd_detected = false;
185277c1fcecSEric Joyner 	bool pf_mdd_detected = false;
185377c1fcecSEric Joyner 	bool vf_mdd_detected = false;
185477c1fcecSEric Joyner 	u16 queue;
185577c1fcecSEric Joyner 	u8 pf_num, event;
185677c1fcecSEric Joyner 	u8 pf_mdet_num, vp_mdet_num;
185777c1fcecSEric Joyner 	u32 reg;
185877c1fcecSEric Joyner 
185977c1fcecSEric Joyner 	/*
186077c1fcecSEric Joyner 	 * GL_MDET_RX doesn't contain VF number information, unlike
186177c1fcecSEric Joyner 	 * GL_MDET_TX.
186277c1fcecSEric Joyner 	 */
186377c1fcecSEric Joyner 	reg = rd32(hw, I40E_GL_MDET_RX);
186477c1fcecSEric Joyner 	if (reg & I40E_GL_MDET_RX_VALID_MASK) {
186577c1fcecSEric Joyner 		pf_num = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
186677c1fcecSEric Joyner 		    I40E_GL_MDET_RX_FUNCTION_SHIFT;
186777c1fcecSEric Joyner 		event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
186877c1fcecSEric Joyner 		    I40E_GL_MDET_RX_EVENT_SHIFT;
186977c1fcecSEric Joyner 		queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
187077c1fcecSEric Joyner 		    I40E_GL_MDET_RX_QUEUE_SHIFT;
187177c1fcecSEric Joyner 		wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
187277c1fcecSEric Joyner 		mdd_detected = true;
187377c1fcecSEric Joyner 	}
187477c1fcecSEric Joyner 
187577c1fcecSEric Joyner 	if (!mdd_detected)
187677c1fcecSEric Joyner 		return;
187777c1fcecSEric Joyner 
187877c1fcecSEric Joyner 	reg = rd32(hw, I40E_PF_MDET_RX);
187977c1fcecSEric Joyner 	if (reg & I40E_PF_MDET_RX_VALID_MASK) {
188077c1fcecSEric Joyner 		wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
188177c1fcecSEric Joyner 		pf_mdet_num = hw->pf_id;
188277c1fcecSEric Joyner 		pf_mdd_detected = true;
188377c1fcecSEric Joyner 	}
188477c1fcecSEric Joyner 
188577c1fcecSEric Joyner 	/* Check if MDD was caused by a VF */
188677c1fcecSEric Joyner 	for (int i = 0; i < pf->num_vfs; i++) {
188777c1fcecSEric Joyner 		vf = &(pf->vfs[i]);
188877c1fcecSEric Joyner 		reg = rd32(hw, I40E_VP_MDET_RX(i));
188977c1fcecSEric Joyner 		if (reg & I40E_VP_MDET_RX_VALID_MASK) {
189077c1fcecSEric Joyner 			wr32(hw, I40E_VP_MDET_RX(i), 0xFFFF);
189177c1fcecSEric Joyner 			vp_mdet_num = i;
189277c1fcecSEric Joyner 			vf->num_mdd_events++;
189377c1fcecSEric Joyner 			vf_mdd_detected = true;
189477c1fcecSEric Joyner 		}
189577c1fcecSEric Joyner 	}
189677c1fcecSEric Joyner 
189777c1fcecSEric Joyner 	/* Print out an error message */
189877c1fcecSEric Joyner 	if (vf_mdd_detected && pf_mdd_detected)
189977c1fcecSEric Joyner 		device_printf(dev,
190077c1fcecSEric Joyner 		    "Malicious Driver Detection event %d"
190177c1fcecSEric Joyner 		    " on RX queue %d, pf number %d (PF-%d), (VF-%d)\n",
190277c1fcecSEric Joyner 		    event, queue, pf_num, pf_mdet_num, vp_mdet_num);
190377c1fcecSEric Joyner 	else if (vf_mdd_detected && !pf_mdd_detected)
190477c1fcecSEric Joyner 		device_printf(dev,
190577c1fcecSEric Joyner 		    "Malicious Driver Detection event %d"
190677c1fcecSEric Joyner 		    " on RX queue %d, pf number %d, (VF-%d)\n",
190777c1fcecSEric Joyner 		    event, queue, pf_num, vp_mdet_num);
190877c1fcecSEric Joyner 	else if (!vf_mdd_detected && pf_mdd_detected)
190977c1fcecSEric Joyner 		device_printf(dev,
191077c1fcecSEric Joyner 		    "Malicious Driver Detection event %d"
191177c1fcecSEric Joyner 		    " on RX queue %d, pf number %d (PF-%d)\n",
191277c1fcecSEric Joyner 		    event, queue, pf_num, pf_mdet_num);
191377c1fcecSEric Joyner 	/* Theoretically shouldn't happen */
191477c1fcecSEric Joyner 	else
191577c1fcecSEric Joyner 		device_printf(dev,
191677c1fcecSEric Joyner 		    "RX Malicious Driver Detection event (unknown)\n");
191777c1fcecSEric Joyner }
191877c1fcecSEric Joyner 
19194294f337SSean Bruno /**
19204294f337SSean Bruno  * ixl_handle_mdd_event
19214294f337SSean Bruno  *
19224294f337SSean Bruno  * Called from interrupt handler to identify possibly malicious vfs
19234294f337SSean Bruno  * (But also detects events from the PF, as well)
19244294f337SSean Bruno  **/
19254294f337SSean Bruno void
ixl_handle_mdd_event(struct ixl_pf * pf)19264294f337SSean Bruno ixl_handle_mdd_event(struct ixl_pf *pf)
19274294f337SSean Bruno {
19284294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
19294294f337SSean Bruno 	u32 reg;
19304294f337SSean Bruno 
193177c1fcecSEric Joyner 	/*
193277c1fcecSEric Joyner 	 * Handle both TX/RX because it's possible they could
193377c1fcecSEric Joyner 	 * both trigger in the same interrupt.
193477c1fcecSEric Joyner 	 */
193577c1fcecSEric Joyner 	ixl_handle_tx_mdd_event(pf);
193677c1fcecSEric Joyner 	ixl_handle_rx_mdd_event(pf);
19374294f337SSean Bruno 
1938b8f51b8cSPiotr Kubaj 	ixl_clear_state(&pf->state, IXL_STATE_MDD_PENDING);
19391031d839SEric Joyner 
19404294f337SSean Bruno 	/* re-enable mdd interrupt cause */
19414294f337SSean Bruno 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
19424294f337SSean Bruno 	reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
19434294f337SSean Bruno 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
19444294f337SSean Bruno 	ixl_flush(hw);
19454294f337SSean Bruno }
19464294f337SSean Bruno 
19474294f337SSean Bruno void
ixl_enable_intr0(struct i40e_hw * hw)1948cb6b8299SEric Joyner ixl_enable_intr0(struct i40e_hw *hw)
19494294f337SSean Bruno {
19504294f337SSean Bruno 	u32		reg;
19514294f337SSean Bruno 
1952cb6b8299SEric Joyner 	/* Use IXL_ITR_NONE so ITR isn't updated here */
19534294f337SSean Bruno 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
19544294f337SSean Bruno 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
19554294f337SSean Bruno 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
19564294f337SSean Bruno 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
19574294f337SSean Bruno }
19584294f337SSean Bruno 
19594294f337SSean Bruno void
ixl_disable_intr0(struct i40e_hw * hw)1960cb6b8299SEric Joyner ixl_disable_intr0(struct i40e_hw *hw)
19614294f337SSean Bruno {
19624294f337SSean Bruno 	u32		reg;
19634294f337SSean Bruno 
19644294f337SSean Bruno 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
19654294f337SSean Bruno 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
19664294f337SSean Bruno 	ixl_flush(hw);
19674294f337SSean Bruno }
19684294f337SSean Bruno 
19694294f337SSean Bruno void
ixl_enable_queue(struct i40e_hw * hw,int id)19704294f337SSean Bruno ixl_enable_queue(struct i40e_hw *hw, int id)
19714294f337SSean Bruno {
19724294f337SSean Bruno 	u32		reg;
19734294f337SSean Bruno 
19744294f337SSean Bruno 	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
19754294f337SSean Bruno 	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
19764294f337SSean Bruno 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
19774294f337SSean Bruno 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
19784294f337SSean Bruno }
19794294f337SSean Bruno 
19804294f337SSean Bruno void
ixl_disable_queue(struct i40e_hw * hw,int id)19814294f337SSean Bruno ixl_disable_queue(struct i40e_hw *hw, int id)
19824294f337SSean Bruno {
19834294f337SSean Bruno 	u32		reg;
19844294f337SSean Bruno 
19854294f337SSean Bruno 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
19864294f337SSean Bruno 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
19874294f337SSean Bruno }
19884294f337SSean Bruno 
19894294f337SSean Bruno void
ixl_handle_empr_reset(struct ixl_pf * pf)1990b4a7ce06SEric Joyner ixl_handle_empr_reset(struct ixl_pf *pf)
1991b4a7ce06SEric Joyner {
1992b4a7ce06SEric Joyner 	struct ixl_vsi	*vsi = &pf->vsi;
1993402810d3SJustin Hibbits 	bool is_up = !!(if_getdrvflags(vsi->ifp) & IFF_DRV_RUNNING);
1994b4a7ce06SEric Joyner 
1995b4a7ce06SEric Joyner 	ixl_prepare_for_reset(pf, is_up);
1996b4a7ce06SEric Joyner 	/*
1997b4a7ce06SEric Joyner 	 * i40e_pf_reset checks the type of reset and acts
1998b4a7ce06SEric Joyner 	 * accordingly. If EMP or Core reset was performed
1999b4a7ce06SEric Joyner 	 * doing PF reset is not necessary and it sometimes
2000b4a7ce06SEric Joyner 	 * fails.
2001b4a7ce06SEric Joyner 	 */
2002b4a7ce06SEric Joyner 	ixl_pf_reset(pf);
2003b4a7ce06SEric Joyner 
2004b4a7ce06SEric Joyner 	if (!IXL_PF_IN_RECOVERY_MODE(pf) &&
2005b4a7ce06SEric Joyner 	    ixl_get_fw_mode(pf) == IXL_FW_MODE_RECOVERY) {
2006b8f51b8cSPiotr Kubaj 		ixl_set_state(&pf->state, IXL_STATE_RECOVERY_MODE);
2007b4a7ce06SEric Joyner 		device_printf(pf->dev,
2008b4a7ce06SEric Joyner 		    "Firmware recovery mode detected. Limiting functionality. Refer to Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n");
2009b4a7ce06SEric Joyner 		pf->link_up = FALSE;
2010b4a7ce06SEric Joyner 		ixl_update_link_status(pf);
2011b4a7ce06SEric Joyner 	}
2012b4a7ce06SEric Joyner 
2013b4a7ce06SEric Joyner 	ixl_rebuild_hw_structs_after_reset(pf, is_up);
2014b4a7ce06SEric Joyner 
2015b8f51b8cSPiotr Kubaj 	ixl_clear_state(&pf->state, IXL_STATE_RESETTING);
2016b4a7ce06SEric Joyner }
2017b4a7ce06SEric Joyner 
2018b4a7ce06SEric Joyner void
ixl_update_stats_counters(struct ixl_pf * pf)20194294f337SSean Bruno ixl_update_stats_counters(struct ixl_pf *pf)
20204294f337SSean Bruno {
20214294f337SSean Bruno 	struct i40e_hw	*hw = &pf->hw;
20224294f337SSean Bruno 	struct ixl_vsi	*vsi = &pf->vsi;
20234294f337SSean Bruno 	struct ixl_vf	*vf;
2024f17e0a71SEric Joyner 	u64 prev_link_xoff_rx = pf->stats.link_xoff_rx;
20254294f337SSean Bruno 
20264294f337SSean Bruno 	struct i40e_hw_port_stats *nsd = &pf->stats;
20274294f337SSean Bruno 	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
20284294f337SSean Bruno 
20294294f337SSean Bruno 	/* Update hw stats */
20304294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
20314294f337SSean Bruno 			   pf->stat_offsets_loaded,
20324294f337SSean Bruno 			   &osd->crc_errors, &nsd->crc_errors);
20334294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
20344294f337SSean Bruno 			   pf->stat_offsets_loaded,
20354294f337SSean Bruno 			   &osd->illegal_bytes, &nsd->illegal_bytes);
2036fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_GORCL(hw->port),
20374294f337SSean Bruno 			   pf->stat_offsets_loaded,
20384294f337SSean Bruno 			   &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
2039fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_GOTCL(hw->port),
20404294f337SSean Bruno 			   pf->stat_offsets_loaded,
20414294f337SSean Bruno 			   &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
20424294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
20434294f337SSean Bruno 			   pf->stat_offsets_loaded,
20444294f337SSean Bruno 			   &osd->eth.rx_discards,
20454294f337SSean Bruno 			   &nsd->eth.rx_discards);
2046fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_UPRCL(hw->port),
20474294f337SSean Bruno 			   pf->stat_offsets_loaded,
20484294f337SSean Bruno 			   &osd->eth.rx_unicast,
20494294f337SSean Bruno 			   &nsd->eth.rx_unicast);
2050fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_UPTCL(hw->port),
20514294f337SSean Bruno 			   pf->stat_offsets_loaded,
20524294f337SSean Bruno 			   &osd->eth.tx_unicast,
20534294f337SSean Bruno 			   &nsd->eth.tx_unicast);
2054fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_MPRCL(hw->port),
20554294f337SSean Bruno 			   pf->stat_offsets_loaded,
20564294f337SSean Bruno 			   &osd->eth.rx_multicast,
20574294f337SSean Bruno 			   &nsd->eth.rx_multicast);
2058fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_MPTCL(hw->port),
20594294f337SSean Bruno 			   pf->stat_offsets_loaded,
20604294f337SSean Bruno 			   &osd->eth.tx_multicast,
20614294f337SSean Bruno 			   &nsd->eth.tx_multicast);
2062fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_BPRCL(hw->port),
20634294f337SSean Bruno 			   pf->stat_offsets_loaded,
20644294f337SSean Bruno 			   &osd->eth.rx_broadcast,
20654294f337SSean Bruno 			   &nsd->eth.rx_broadcast);
2066fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_BPTCL(hw->port),
20674294f337SSean Bruno 			   pf->stat_offsets_loaded,
20684294f337SSean Bruno 			   &osd->eth.tx_broadcast,
20694294f337SSean Bruno 			   &nsd->eth.tx_broadcast);
20704294f337SSean Bruno 
20714294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
20724294f337SSean Bruno 			   pf->stat_offsets_loaded,
20734294f337SSean Bruno 			   &osd->tx_dropped_link_down,
20744294f337SSean Bruno 			   &nsd->tx_dropped_link_down);
20754294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
20764294f337SSean Bruno 			   pf->stat_offsets_loaded,
20774294f337SSean Bruno 			   &osd->mac_local_faults,
20784294f337SSean Bruno 			   &nsd->mac_local_faults);
20794294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
20804294f337SSean Bruno 			   pf->stat_offsets_loaded,
20814294f337SSean Bruno 			   &osd->mac_remote_faults,
20824294f337SSean Bruno 			   &nsd->mac_remote_faults);
20834294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
20844294f337SSean Bruno 			   pf->stat_offsets_loaded,
20854294f337SSean Bruno 			   &osd->rx_length_errors,
20864294f337SSean Bruno 			   &nsd->rx_length_errors);
20874294f337SSean Bruno 
20884294f337SSean Bruno 	/* Flow control (LFC) stats */
20894294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
20904294f337SSean Bruno 			   pf->stat_offsets_loaded,
20914294f337SSean Bruno 			   &osd->link_xon_rx, &nsd->link_xon_rx);
20924294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
20934294f337SSean Bruno 			   pf->stat_offsets_loaded,
20944294f337SSean Bruno 			   &osd->link_xon_tx, &nsd->link_xon_tx);
20954294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
20964294f337SSean Bruno 			   pf->stat_offsets_loaded,
20974294f337SSean Bruno 			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
20984294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
20994294f337SSean Bruno 			   pf->stat_offsets_loaded,
21004294f337SSean Bruno 			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
21014294f337SSean Bruno 
2102f17e0a71SEric Joyner 	/*
2103f17e0a71SEric Joyner 	 * For watchdog management we need to know if we have been paused
2104f17e0a71SEric Joyner 	 * during the last interval, so capture that here.
2105f17e0a71SEric Joyner 	 */
2106f17e0a71SEric Joyner 	if (pf->stats.link_xoff_rx != prev_link_xoff_rx)
2107087ea410SEric Joyner 		vsi->shared->isc_pause_frames = 1;
2108f17e0a71SEric Joyner 
21094294f337SSean Bruno 	/* Packet size stats rx */
2110fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PRC64L(hw->port),
21114294f337SSean Bruno 			   pf->stat_offsets_loaded,
21124294f337SSean Bruno 			   &osd->rx_size_64, &nsd->rx_size_64);
2113fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PRC127L(hw->port),
21144294f337SSean Bruno 			   pf->stat_offsets_loaded,
21154294f337SSean Bruno 			   &osd->rx_size_127, &nsd->rx_size_127);
2116fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PRC255L(hw->port),
21174294f337SSean Bruno 			   pf->stat_offsets_loaded,
21184294f337SSean Bruno 			   &osd->rx_size_255, &nsd->rx_size_255);
2119fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PRC511L(hw->port),
21204294f337SSean Bruno 			   pf->stat_offsets_loaded,
21214294f337SSean Bruno 			   &osd->rx_size_511, &nsd->rx_size_511);
2122fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PRC1023L(hw->port),
21234294f337SSean Bruno 			   pf->stat_offsets_loaded,
21244294f337SSean Bruno 			   &osd->rx_size_1023, &nsd->rx_size_1023);
2125fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PRC1522L(hw->port),
21264294f337SSean Bruno 			   pf->stat_offsets_loaded,
21274294f337SSean Bruno 			   &osd->rx_size_1522, &nsd->rx_size_1522);
2128fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PRC9522L(hw->port),
21294294f337SSean Bruno 			   pf->stat_offsets_loaded,
21304294f337SSean Bruno 			   &osd->rx_size_big, &nsd->rx_size_big);
21314294f337SSean Bruno 
21324294f337SSean Bruno 	/* Packet size stats tx */
2133fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PTC64L(hw->port),
21344294f337SSean Bruno 			   pf->stat_offsets_loaded,
21354294f337SSean Bruno 			   &osd->tx_size_64, &nsd->tx_size_64);
2136fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PTC127L(hw->port),
21374294f337SSean Bruno 			   pf->stat_offsets_loaded,
21384294f337SSean Bruno 			   &osd->tx_size_127, &nsd->tx_size_127);
2139fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PTC255L(hw->port),
21404294f337SSean Bruno 			   pf->stat_offsets_loaded,
21414294f337SSean Bruno 			   &osd->tx_size_255, &nsd->tx_size_255);
2142fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PTC511L(hw->port),
21434294f337SSean Bruno 			   pf->stat_offsets_loaded,
21444294f337SSean Bruno 			   &osd->tx_size_511, &nsd->tx_size_511);
2145fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PTC1023L(hw->port),
21464294f337SSean Bruno 			   pf->stat_offsets_loaded,
21474294f337SSean Bruno 			   &osd->tx_size_1023, &nsd->tx_size_1023);
2148fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PTC1522L(hw->port),
21494294f337SSean Bruno 			   pf->stat_offsets_loaded,
21504294f337SSean Bruno 			   &osd->tx_size_1522, &nsd->tx_size_1522);
2151fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLPRT_PTC9522L(hw->port),
21524294f337SSean Bruno 			   pf->stat_offsets_loaded,
21534294f337SSean Bruno 			   &osd->tx_size_big, &nsd->tx_size_big);
21544294f337SSean Bruno 
21554294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
21564294f337SSean Bruno 			   pf->stat_offsets_loaded,
21574294f337SSean Bruno 			   &osd->rx_undersize, &nsd->rx_undersize);
21584294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
21594294f337SSean Bruno 			   pf->stat_offsets_loaded,
21604294f337SSean Bruno 			   &osd->rx_fragments, &nsd->rx_fragments);
2161fef4249fSEric Joyner 
2162fef4249fSEric Joyner 	u64 rx_roc;
21634294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
21644294f337SSean Bruno 			   pf->stat_offsets_loaded,
2165fef4249fSEric Joyner 			   &osd->rx_oversize, &rx_roc);
2166fef4249fSEric Joyner 
2167fef4249fSEric Joyner 	/*
2168fef4249fSEric Joyner 	 * Read from RXERR1 register to get the count for the packets
2169fef4249fSEric Joyner 	 * larger than RX MAX and include that in total rx_oversize count.
2170fef4249fSEric Joyner 	 *
2171fef4249fSEric Joyner 	 * Also need to add BIT(7) to hw->port value while indexing
2172fef4249fSEric Joyner 	 * I40E_GL_RXERR1 register as indexes 0..127 are for VFs when
2173fef4249fSEric Joyner 	 * SR-IOV is enabled. Indexes 128..143 are for PFs.
2174fef4249fSEric Joyner 	 */
2175fef4249fSEric Joyner 	u64 rx_err1;
2176fef4249fSEric Joyner 	ixl_stat_update64(hw,
2177fef4249fSEric Joyner 			   I40E_GL_RXERR1L(hw->pf_id + BIT(7)),
2178fef4249fSEric Joyner 			   pf->stat_offsets_loaded,
2179fef4249fSEric Joyner 			   &osd->rx_err1,
2180fef4249fSEric Joyner 			   &rx_err1);
2181fef4249fSEric Joyner 
2182fef4249fSEric Joyner 	nsd->rx_oversize = rx_roc + rx_err1;
2183fef4249fSEric Joyner 
21844294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
21854294f337SSean Bruno 			   pf->stat_offsets_loaded,
21864294f337SSean Bruno 			   &osd->rx_jabber, &nsd->rx_jabber);
21872984a8ddSEric Joyner 	/* EEE */
21882984a8ddSEric Joyner 	i40e_get_phy_lpi_status(hw, nsd);
21892984a8ddSEric Joyner 
21902984a8ddSEric Joyner 	i40e_lpi_stat_update(hw, pf->stat_offsets_loaded,
21912984a8ddSEric Joyner 			  &osd->tx_lpi_count, &nsd->tx_lpi_count,
21922984a8ddSEric Joyner 			  &osd->rx_lpi_count, &nsd->rx_lpi_count);
21932984a8ddSEric Joyner 
21944294f337SSean Bruno 	pf->stat_offsets_loaded = true;
21954294f337SSean Bruno 	/* End hw stats */
21964294f337SSean Bruno 
21974294f337SSean Bruno 	/* Update vsi stats */
21984294f337SSean Bruno 	ixl_update_vsi_stats(vsi);
21994294f337SSean Bruno 
22004294f337SSean Bruno 	for (int i = 0; i < pf->num_vfs; i++) {
22014294f337SSean Bruno 		vf = &pf->vfs[i];
22024294f337SSean Bruno 		if (vf->vf_flags & VF_FLAG_ENABLED)
22034294f337SSean Bruno 			ixl_update_eth_stats(&pf->vfs[i].vsi);
22044294f337SSean Bruno 	}
22054294f337SSean Bruno }
22064294f337SSean Bruno 
22074294f337SSean Bruno /**
22084294f337SSean Bruno  * Update VSI-specific ethernet statistics counters.
22094294f337SSean Bruno  **/
22104294f337SSean Bruno void
ixl_update_eth_stats(struct ixl_vsi * vsi)22114294f337SSean Bruno ixl_update_eth_stats(struct ixl_vsi *vsi)
22124294f337SSean Bruno {
22134294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
22144294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
22154294f337SSean Bruno 	struct i40e_eth_stats *es;
22164294f337SSean Bruno 	struct i40e_eth_stats *oes;
22174294f337SSean Bruno 	u16 stat_idx = vsi->info.stat_counter_idx;
22184294f337SSean Bruno 
22194294f337SSean Bruno 	es = &vsi->eth_stats;
22204294f337SSean Bruno 	oes = &vsi->eth_stats_offsets;
22214294f337SSean Bruno 
22224294f337SSean Bruno 	/* Gather up the stats that the hw collects */
22234294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
22244294f337SSean Bruno 			   vsi->stat_offsets_loaded,
22254294f337SSean Bruno 			   &oes->tx_errors, &es->tx_errors);
22264294f337SSean Bruno 	ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
22274294f337SSean Bruno 			   vsi->stat_offsets_loaded,
22284294f337SSean Bruno 			   &oes->rx_discards, &es->rx_discards);
22294294f337SSean Bruno 
2230fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLV_GORCL(stat_idx),
22314294f337SSean Bruno 			   vsi->stat_offsets_loaded,
22324294f337SSean Bruno 			   &oes->rx_bytes, &es->rx_bytes);
2233fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLV_UPRCL(stat_idx),
22344294f337SSean Bruno 			   vsi->stat_offsets_loaded,
22354294f337SSean Bruno 			   &oes->rx_unicast, &es->rx_unicast);
2236fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLV_MPRCL(stat_idx),
22374294f337SSean Bruno 			   vsi->stat_offsets_loaded,
22384294f337SSean Bruno 			   &oes->rx_multicast, &es->rx_multicast);
2239fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLV_BPRCL(stat_idx),
22404294f337SSean Bruno 			   vsi->stat_offsets_loaded,
22414294f337SSean Bruno 			   &oes->rx_broadcast, &es->rx_broadcast);
22424294f337SSean Bruno 
2243fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLV_GOTCL(stat_idx),
22444294f337SSean Bruno 			   vsi->stat_offsets_loaded,
22454294f337SSean Bruno 			   &oes->tx_bytes, &es->tx_bytes);
2246fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLV_UPTCL(stat_idx),
22474294f337SSean Bruno 			   vsi->stat_offsets_loaded,
22484294f337SSean Bruno 			   &oes->tx_unicast, &es->tx_unicast);
2249fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLV_MPTCL(stat_idx),
22504294f337SSean Bruno 			   vsi->stat_offsets_loaded,
22514294f337SSean Bruno 			   &oes->tx_multicast, &es->tx_multicast);
2252fef4249fSEric Joyner 	ixl_stat_update48(hw, I40E_GLV_BPTCL(stat_idx),
22534294f337SSean Bruno 			   vsi->stat_offsets_loaded,
22544294f337SSean Bruno 			   &oes->tx_broadcast, &es->tx_broadcast);
22554294f337SSean Bruno 	vsi->stat_offsets_loaded = true;
22564294f337SSean Bruno }
22574294f337SSean Bruno 
22584294f337SSean Bruno void
ixl_update_vsi_stats(struct ixl_vsi * vsi)22594294f337SSean Bruno ixl_update_vsi_stats(struct ixl_vsi *vsi)
22604294f337SSean Bruno {
22614294f337SSean Bruno 	struct ixl_pf		*pf;
22624294f337SSean Bruno 	struct i40e_eth_stats	*es;
22639f99061eSKrzysztof Galazka 	u64			tx_discards, csum_errs;
22644294f337SSean Bruno 
22654294f337SSean Bruno 	struct i40e_hw_port_stats *nsd;
22664294f337SSean Bruno 
22674294f337SSean Bruno 	pf = vsi->back;
22684294f337SSean Bruno 	es = &vsi->eth_stats;
22694294f337SSean Bruno 	nsd = &pf->stats;
22704294f337SSean Bruno 
22714294f337SSean Bruno 	ixl_update_eth_stats(vsi);
22724294f337SSean Bruno 
22734294f337SSean Bruno 	tx_discards = es->tx_discards + nsd->tx_dropped_link_down;
22744294f337SSean Bruno 
22759f99061eSKrzysztof Galazka 	csum_errs = 0;
22769f99061eSKrzysztof Galazka 	for (int i = 0; i < vsi->num_rx_queues; i++)
22779f99061eSKrzysztof Galazka 		csum_errs += vsi->rx_queues[i].rxr.csum_errs;
22789f99061eSKrzysztof Galazka 	nsd->checksum_error = csum_errs;
22799f99061eSKrzysztof Galazka 
22804294f337SSean Bruno 	/* Update ifnet stats */
22814294f337SSean Bruno 	IXL_SET_IPACKETS(vsi, es->rx_unicast +
22824294f337SSean Bruno 	                   es->rx_multicast +
22834294f337SSean Bruno 			   es->rx_broadcast);
22844294f337SSean Bruno 	IXL_SET_OPACKETS(vsi, es->tx_unicast +
22854294f337SSean Bruno 	                   es->tx_multicast +
22864294f337SSean Bruno 			   es->tx_broadcast);
22874294f337SSean Bruno 	IXL_SET_IBYTES(vsi, es->rx_bytes);
22884294f337SSean Bruno 	IXL_SET_OBYTES(vsi, es->tx_bytes);
22894294f337SSean Bruno 	IXL_SET_IMCASTS(vsi, es->rx_multicast);
22904294f337SSean Bruno 	IXL_SET_OMCASTS(vsi, es->tx_multicast);
22914294f337SSean Bruno 
22924294f337SSean Bruno 	IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes +
22939f99061eSKrzysztof Galazka 	    nsd->checksum_error + nsd->rx_length_errors +
22949f99061eSKrzysztof Galazka 	    nsd->rx_undersize + nsd->rx_fragments + nsd->rx_oversize +
22954294f337SSean Bruno 	    nsd->rx_jabber);
22964294f337SSean Bruno 	IXL_SET_OERRORS(vsi, es->tx_errors);
22974294f337SSean Bruno 	IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards);
22984294f337SSean Bruno 	IXL_SET_OQDROPS(vsi, tx_discards);
22994294f337SSean Bruno 	IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol);
23004294f337SSean Bruno 	IXL_SET_COLLISIONS(vsi, 0);
23014294f337SSean Bruno }
23024294f337SSean Bruno 
23034294f337SSean Bruno /**
23044294f337SSean Bruno  * Reset all of the stats for the given pf
23054294f337SSean Bruno  **/
23064294f337SSean Bruno void
ixl_pf_reset_stats(struct ixl_pf * pf)23074294f337SSean Bruno ixl_pf_reset_stats(struct ixl_pf *pf)
23084294f337SSean Bruno {
23094294f337SSean Bruno 	bzero(&pf->stats, sizeof(struct i40e_hw_port_stats));
23104294f337SSean Bruno 	bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats));
23114294f337SSean Bruno 	pf->stat_offsets_loaded = false;
23124294f337SSean Bruno }
23134294f337SSean Bruno 
23144294f337SSean Bruno /**
23154294f337SSean Bruno  * Resets all stats of the given vsi
23164294f337SSean Bruno  **/
23174294f337SSean Bruno void
ixl_vsi_reset_stats(struct ixl_vsi * vsi)23184294f337SSean Bruno ixl_vsi_reset_stats(struct ixl_vsi *vsi)
23194294f337SSean Bruno {
23204294f337SSean Bruno 	bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats));
23214294f337SSean Bruno 	bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats));
23224294f337SSean Bruno 	vsi->stat_offsets_loaded = false;
23234294f337SSean Bruno }
23244294f337SSean Bruno 
23254294f337SSean Bruno /**
2326fef4249fSEric Joyner  * Helper function for reading and updating 48/64 bit stats from the hw
23274294f337SSean Bruno  *
23284294f337SSean Bruno  * Since the device stats are not reset at PFReset, they likely will not
23294294f337SSean Bruno  * be zeroed when the driver starts.  We'll save the first values read
23304294f337SSean Bruno  * and use them as offsets to be subtracted from the raw values in order
23314294f337SSean Bruno  * to report stats that count from zero.
23324294f337SSean Bruno  **/
2333fef4249fSEric Joyner static void
_ixl_stat_update_helper(struct i40e_hw * hw,u32 reg,bool offset_loaded,u64 mask,u64 * offset,u64 * stat)2334fef4249fSEric Joyner _ixl_stat_update_helper(struct i40e_hw *hw, u32 reg,
2335fef4249fSEric Joyner 	bool offset_loaded, u64 mask, u64 *offset, u64 *stat)
23364294f337SSean Bruno {
2337fef4249fSEric Joyner 	u64 new_data = rd64(hw, reg);
23384294f337SSean Bruno 
23394294f337SSean Bruno 	if (!offset_loaded)
23404294f337SSean Bruno 		*offset = new_data;
23414294f337SSean Bruno 	if (new_data >= *offset)
23424294f337SSean Bruno 		*stat = new_data - *offset;
23434294f337SSean Bruno 	else
2344fef4249fSEric Joyner 		*stat = (new_data + mask) - *offset + 1;
2345fef4249fSEric Joyner 	*stat &= mask;
2346fef4249fSEric Joyner }
2347fef4249fSEric Joyner 
2348fef4249fSEric Joyner /**
2349fef4249fSEric Joyner  * Read and update a 48 bit stat from the hw
2350fef4249fSEric Joyner  **/
2351fef4249fSEric Joyner void
ixl_stat_update48(struct i40e_hw * hw,u32 reg,bool offset_loaded,u64 * offset,u64 * stat)2352fef4249fSEric Joyner ixl_stat_update48(struct i40e_hw *hw, u32 reg,
2353fef4249fSEric Joyner 	bool offset_loaded, u64 *offset, u64 *stat)
2354fef4249fSEric Joyner {
2355fef4249fSEric Joyner 	_ixl_stat_update_helper(hw,
2356fef4249fSEric Joyner 		reg,
2357fef4249fSEric Joyner 		offset_loaded,
2358fef4249fSEric Joyner 		0xFFFFFFFFFFFFULL,
2359fef4249fSEric Joyner 		offset,
2360fef4249fSEric Joyner 		stat);
2361fef4249fSEric Joyner }
2362fef4249fSEric Joyner 
2363fef4249fSEric Joyner /**
2364fef4249fSEric Joyner  * ixl_stat_update64 - read and update a 64 bit stat from the chip.
2365fef4249fSEric Joyner  **/
2366fef4249fSEric Joyner void
ixl_stat_update64(struct i40e_hw * hw,u32 reg,bool offset_loaded,u64 * offset,u64 * stat)2367fef4249fSEric Joyner ixl_stat_update64(struct i40e_hw *hw, u32 reg,
2368fef4249fSEric Joyner 			       bool offset_loaded, u64 *offset, u64 *stat)
2369fef4249fSEric Joyner {
2370fef4249fSEric Joyner 	_ixl_stat_update_helper(hw,
2371fef4249fSEric Joyner 		reg,
2372fef4249fSEric Joyner 		offset_loaded,
2373fef4249fSEric Joyner 		0xFFFFFFFFFFFFFFFFULL,
2374fef4249fSEric Joyner 		offset,
2375fef4249fSEric Joyner 		stat);
23764294f337SSean Bruno }
23774294f337SSean Bruno 
23784294f337SSean Bruno /**
23794294f337SSean Bruno  * Read and update a 32 bit stat from the hw
23804294f337SSean Bruno  **/
23814294f337SSean Bruno void
ixl_stat_update32(struct i40e_hw * hw,u32 reg,bool offset_loaded,u64 * offset,u64 * stat)23824294f337SSean Bruno ixl_stat_update32(struct i40e_hw *hw, u32 reg,
23834294f337SSean Bruno 	bool offset_loaded, u64 *offset, u64 *stat)
23844294f337SSean Bruno {
23854294f337SSean Bruno 	u32 new_data;
23864294f337SSean Bruno 
23874294f337SSean Bruno 	new_data = rd32(hw, reg);
23884294f337SSean Bruno 	if (!offset_loaded)
23894294f337SSean Bruno 		*offset = new_data;
23904294f337SSean Bruno 	if (new_data >= *offset)
23914294f337SSean Bruno 		*stat = (u32)(new_data - *offset);
23924294f337SSean Bruno 	else
23934294f337SSean Bruno 		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
23944294f337SSean Bruno }
23954294f337SSean Bruno 
2396b4a7ce06SEric Joyner /**
2397b4a7ce06SEric Joyner  * Add subset of device sysctls safe to use in recovery mode
2398b4a7ce06SEric Joyner  */
2399b4a7ce06SEric Joyner void
ixl_add_sysctls_recovery_mode(struct ixl_pf * pf)2400b4a7ce06SEric Joyner ixl_add_sysctls_recovery_mode(struct ixl_pf *pf)
2401b4a7ce06SEric Joyner {
2402b4a7ce06SEric Joyner 	device_t dev = pf->dev;
2403b4a7ce06SEric Joyner 
2404b4a7ce06SEric Joyner 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
2405b4a7ce06SEric Joyner 	struct sysctl_oid_list *ctx_list =
2406b4a7ce06SEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
2407b4a7ce06SEric Joyner 
2408b4a7ce06SEric Joyner 	struct sysctl_oid *debug_node;
2409b4a7ce06SEric Joyner 	struct sysctl_oid_list *debug_list;
2410b4a7ce06SEric Joyner 
2411b4a7ce06SEric Joyner 	SYSCTL_ADD_PROC(ctx, ctx_list,
2412b4a7ce06SEric Joyner 	    OID_AUTO, "fw_version",
2413b4a7ce06SEric Joyner 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, pf, 0,
2414b4a7ce06SEric Joyner 	    ixl_sysctl_show_fw, "A", "Firmware version");
2415b4a7ce06SEric Joyner 
2416b4a7ce06SEric Joyner 	/* Add sysctls meant to print debug information, but don't list them
2417b4a7ce06SEric Joyner 	 * in "sysctl -a" output. */
2418b4a7ce06SEric Joyner 	debug_node = SYSCTL_ADD_NODE(ctx, ctx_list,
2419b4a7ce06SEric Joyner 	    OID_AUTO, "debug", CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE, NULL,
2420b4a7ce06SEric Joyner 	    "Debug Sysctls");
2421b4a7ce06SEric Joyner 	debug_list = SYSCTL_CHILDREN(debug_node);
2422b4a7ce06SEric Joyner 
2423b4a7ce06SEric Joyner 	SYSCTL_ADD_UINT(ctx, debug_list,
2424b4a7ce06SEric Joyner 	    OID_AUTO, "shared_debug_mask", CTLFLAG_RW,
2425b4a7ce06SEric Joyner 	    &pf->hw.debug_mask, 0, "Shared code debug message level");
2426b4a7ce06SEric Joyner 
2427b4a7ce06SEric Joyner 	SYSCTL_ADD_UINT(ctx, debug_list,
2428b4a7ce06SEric Joyner 	    OID_AUTO, "core_debug_mask", CTLFLAG_RW,
2429b4a7ce06SEric Joyner 	    &pf->dbg_mask, 0, "Non-shared code debug message level");
2430b4a7ce06SEric Joyner 
2431b4a7ce06SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
2432b4a7ce06SEric Joyner 	    OID_AUTO, "dump_debug_data",
2433b4a7ce06SEric Joyner 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
2434b4a7ce06SEric Joyner 	    pf, 0, ixl_sysctl_dump_debug_data, "A", "Dump Debug Data from FW");
2435b4a7ce06SEric Joyner 
2436b4a7ce06SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
2437b4a7ce06SEric Joyner 	    OID_AUTO, "do_pf_reset",
2438b4a7ce06SEric Joyner 	    CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT,
2439b4a7ce06SEric Joyner 	    pf, 0, ixl_sysctl_do_pf_reset, "I", "Tell HW to initiate a PF reset");
2440b4a7ce06SEric Joyner 
2441b4a7ce06SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
2442b4a7ce06SEric Joyner 	    OID_AUTO, "do_core_reset",
2443b4a7ce06SEric Joyner 	    CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT,
2444b4a7ce06SEric Joyner 	    pf, 0, ixl_sysctl_do_core_reset, "I", "Tell HW to initiate a CORE reset");
2445b4a7ce06SEric Joyner 
2446b4a7ce06SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
2447b4a7ce06SEric Joyner 	    OID_AUTO, "do_global_reset",
2448b4a7ce06SEric Joyner 	    CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT,
2449b4a7ce06SEric Joyner 	    pf, 0, ixl_sysctl_do_global_reset, "I", "Tell HW to initiate a GLOBAL reset");
2450b4a7ce06SEric Joyner 
2451b4a7ce06SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
2452b4a7ce06SEric Joyner 	    OID_AUTO, "queue_interrupt_table",
2453b4a7ce06SEric Joyner 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
2454b4a7ce06SEric Joyner 	    pf, 0, ixl_sysctl_queue_interrupt_table, "A", "View MSI-X indices for TX/RX queues");
24554fecb701SKrzysztof Galazka 
24564fecb701SKrzysztof Galazka 	SYSCTL_ADD_PROC(ctx, debug_list,
24574fecb701SKrzysztof Galazka 	    OID_AUTO, "queue_int_ctln",
24584fecb701SKrzysztof Galazka 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
24594fecb701SKrzysztof Galazka 	    pf, 0, ixl_sysctl_debug_queue_int_ctln, "A",
24604fecb701SKrzysztof Galazka 	    "View MSI-X control registers for RX queues");
2461b4a7ce06SEric Joyner }
2462b4a7ce06SEric Joyner 
24634294f337SSean Bruno void
ixl_add_device_sysctls(struct ixl_pf * pf)24644294f337SSean Bruno ixl_add_device_sysctls(struct ixl_pf *pf)
24654294f337SSean Bruno {
24664294f337SSean Bruno 	device_t dev = pf->dev;
2467cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
24684294f337SSean Bruno 
24694294f337SSean Bruno 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
24704294f337SSean Bruno 	struct sysctl_oid_list *ctx_list =
24714294f337SSean Bruno 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
24724294f337SSean Bruno 
24734294f337SSean Bruno 	struct sysctl_oid *debug_node;
24744294f337SSean Bruno 	struct sysctl_oid_list *debug_list;
24754294f337SSean Bruno 
2476cb6b8299SEric Joyner 	struct sysctl_oid *fec_node;
2477cb6b8299SEric Joyner 	struct sysctl_oid_list *fec_list;
24782984a8ddSEric Joyner 	struct sysctl_oid *eee_node;
24792984a8ddSEric Joyner 	struct sysctl_oid_list *eee_list;
2480cb6b8299SEric Joyner 
24814294f337SSean Bruno 	/* Set up sysctls */
24824294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, ctx_list,
248320b91f0aSPawel Biernacki 	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
2484ceebc2f3SEric Joyner 	    pf, 0, ixl_sysctl_set_flowcntl, "I", IXL_SYSCTL_HELP_FC);
24854294f337SSean Bruno 
24864294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, ctx_list,
248720b91f0aSPawel Biernacki 	    OID_AUTO, "advertise_speed",
248820b91f0aSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, pf, 0,
248920b91f0aSPawel Biernacki 	    ixl_sysctl_set_advertise, "I", IXL_SYSCTL_HELP_SET_ADVERTISE);
2490ceebc2f3SEric Joyner 
2491ceebc2f3SEric Joyner 	SYSCTL_ADD_PROC(ctx, ctx_list,
249220b91f0aSPawel Biernacki 	    OID_AUTO, "supported_speeds",
249320b91f0aSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, pf, 0,
249420b91f0aSPawel Biernacki 	    ixl_sysctl_supported_speeds, "I", IXL_SYSCTL_HELP_SUPPORTED_SPEED);
24954294f337SSean Bruno 
24964294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, ctx_list,
249720b91f0aSPawel Biernacki 	    OID_AUTO, "current_speed",
249820b91f0aSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, pf, 0,
249920b91f0aSPawel Biernacki 	    ixl_sysctl_current_speed, "A", "Current Port Speed");
25004294f337SSean Bruno 
25014294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, ctx_list,
250220b91f0aSPawel Biernacki 	    OID_AUTO, "fw_version",
250320b91f0aSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, pf, 0,
250420b91f0aSPawel Biernacki 	    ixl_sysctl_show_fw, "A", "Firmware version");
25054294f337SSean Bruno 
25064294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, ctx_list,
250720b91f0aSPawel Biernacki 	    OID_AUTO, "unallocated_queues",
250820b91f0aSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, pf, 0,
250920b91f0aSPawel Biernacki 	    ixl_sysctl_unallocated_queues, "I",
25104294f337SSean Bruno 	    "Queues not allocated to a PF or VF");
25114294f337SSean Bruno 
25124294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, ctx_list,
251320b91f0aSPawel Biernacki 	    OID_AUTO, "tx_itr",
251420b91f0aSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, pf, 0,
251520b91f0aSPawel Biernacki 	    ixl_sysctl_pf_tx_itr, "I",
25164294f337SSean Bruno 	    "Immediately set TX ITR value for all queues");
25174294f337SSean Bruno 
25184294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, ctx_list,
251920b91f0aSPawel Biernacki 	    OID_AUTO, "rx_itr",
252020b91f0aSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, pf, 0,
252120b91f0aSPawel Biernacki 	    ixl_sysctl_pf_rx_itr, "I",
25224294f337SSean Bruno 	    "Immediately set RX ITR value for all queues");
25234294f337SSean Bruno 
25244294f337SSean Bruno 	SYSCTL_ADD_INT(ctx, ctx_list,
25254294f337SSean Bruno 	    OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW,
25264294f337SSean Bruno 	    &pf->dynamic_rx_itr, 0, "Enable dynamic RX ITR");
25274294f337SSean Bruno 
25284294f337SSean Bruno 	SYSCTL_ADD_INT(ctx, ctx_list,
25294294f337SSean Bruno 	    OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW,
25304294f337SSean Bruno 	    &pf->dynamic_tx_itr, 0, "Enable dynamic TX ITR");
25314294f337SSean Bruno 
2532cb6b8299SEric Joyner 	/* Add FEC sysctls for 25G adapters */
2533ceebc2f3SEric Joyner 	if (i40e_is_25G_device(hw->device_id)) {
2534cb6b8299SEric Joyner 		fec_node = SYSCTL_ADD_NODE(ctx, ctx_list,
253520b91f0aSPawel Biernacki 		    OID_AUTO, "fec", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
253620b91f0aSPawel Biernacki 		    "FEC Sysctls");
2537cb6b8299SEric Joyner 		fec_list = SYSCTL_CHILDREN(fec_node);
2538cb6b8299SEric Joyner 
2539cb6b8299SEric Joyner 		SYSCTL_ADD_PROC(ctx, fec_list,
254020b91f0aSPawel Biernacki 		    OID_AUTO, "fc_ability",
254120b91f0aSPawel Biernacki 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, pf, 0,
254220b91f0aSPawel Biernacki 		    ixl_sysctl_fec_fc_ability, "I", "FC FEC ability enabled");
2543cb6b8299SEric Joyner 
2544cb6b8299SEric Joyner 		SYSCTL_ADD_PROC(ctx, fec_list,
254520b91f0aSPawel Biernacki 		    OID_AUTO, "rs_ability",
254620b91f0aSPawel Biernacki 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, pf, 0,
254720b91f0aSPawel Biernacki 		    ixl_sysctl_fec_rs_ability, "I", "RS FEC ability enabled");
2548cb6b8299SEric Joyner 
2549cb6b8299SEric Joyner 		SYSCTL_ADD_PROC(ctx, fec_list,
255020b91f0aSPawel Biernacki 		    OID_AUTO, "fc_requested",
255120b91f0aSPawel Biernacki 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, pf, 0,
255220b91f0aSPawel Biernacki 		    ixl_sysctl_fec_fc_request, "I",
255320b91f0aSPawel Biernacki 		    "FC FEC mode requested on link");
2554cb6b8299SEric Joyner 
2555cb6b8299SEric Joyner 		SYSCTL_ADD_PROC(ctx, fec_list,
255620b91f0aSPawel Biernacki 		    OID_AUTO, "rs_requested",
255720b91f0aSPawel Biernacki 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, pf, 0,
255820b91f0aSPawel Biernacki 		    ixl_sysctl_fec_rs_request, "I",
255920b91f0aSPawel Biernacki 		    "RS FEC mode requested on link");
2560cb6b8299SEric Joyner 
2561cb6b8299SEric Joyner 		SYSCTL_ADD_PROC(ctx, fec_list,
256220b91f0aSPawel Biernacki 		    OID_AUTO, "auto_fec_enabled",
256320b91f0aSPawel Biernacki 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, pf, 0,
256420b91f0aSPawel Biernacki 		    ixl_sysctl_fec_auto_enable, "I",
256520b91f0aSPawel Biernacki 		    "Let FW decide FEC ability/request modes");
2566cb6b8299SEric Joyner 	}
2567cb6b8299SEric Joyner 
2568ceebc2f3SEric Joyner 	SYSCTL_ADD_PROC(ctx, ctx_list,
256920b91f0aSPawel Biernacki 	    OID_AUTO, "fw_lldp", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
2570ceebc2f3SEric Joyner 	    pf, 0, ixl_sysctl_fw_lldp, "I", IXL_SYSCTL_HELP_FW_LLDP);
2571ceebc2f3SEric Joyner 
25722984a8ddSEric Joyner 	eee_node = SYSCTL_ADD_NODE(ctx, ctx_list,
25732984a8ddSEric Joyner 	    OID_AUTO, "eee", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
25742984a8ddSEric Joyner 	    "Energy Efficient Ethernet (EEE) Sysctls");
25752984a8ddSEric Joyner 	eee_list = SYSCTL_CHILDREN(eee_node);
25762984a8ddSEric Joyner 
25772984a8ddSEric Joyner 	SYSCTL_ADD_PROC(ctx, eee_list,
25782984a8ddSEric Joyner 	    OID_AUTO, "enable", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
25792984a8ddSEric Joyner 	    pf, 0, ixl_sysctl_eee_enable, "I",
25802984a8ddSEric Joyner 	    "Enable Energy Efficient Ethernet (EEE)");
25812984a8ddSEric Joyner 
25822984a8ddSEric Joyner 	SYSCTL_ADD_UINT(ctx, eee_list, OID_AUTO, "tx_lpi_status",
25832984a8ddSEric Joyner 	    CTLFLAG_RD | CTLFLAG_MPSAFE, &pf->stats.tx_lpi_status, 0,
25842984a8ddSEric Joyner 	    "TX LPI status");
25852984a8ddSEric Joyner 
25862984a8ddSEric Joyner 	SYSCTL_ADD_UINT(ctx, eee_list, OID_AUTO, "rx_lpi_status",
25872984a8ddSEric Joyner 	    CTLFLAG_RD | CTLFLAG_MPSAFE, &pf->stats.rx_lpi_status, 0,
25882984a8ddSEric Joyner 	    "RX LPI status");
25892984a8ddSEric Joyner 
25902984a8ddSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, eee_list, OID_AUTO, "tx_lpi_count",
25912984a8ddSEric Joyner 	    CTLFLAG_RD | CTLFLAG_MPSAFE, &pf->stats.tx_lpi_count,
25922984a8ddSEric Joyner 	    "TX LPI count");
25932984a8ddSEric Joyner 
25942984a8ddSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, eee_list, OID_AUTO, "rx_lpi_count",
25952984a8ddSEric Joyner 	    CTLFLAG_RD | CTLFLAG_MPSAFE, &pf->stats.rx_lpi_count,
25962984a8ddSEric Joyner 	    "RX LPI count");
25972984a8ddSEric Joyner 
259821802a12SKrzysztof Galazka 	SYSCTL_ADD_PROC(ctx, ctx_list, OID_AUTO,
259921802a12SKrzysztof Galazka 	    "link_active_on_if_down",
260021802a12SKrzysztof Galazka 	    CTLTYPE_INT | CTLFLAG_RWTUN,
260121802a12SKrzysztof Galazka 	    pf, 0, ixl_sysctl_set_link_active, "I",
260221802a12SKrzysztof Galazka 	    IXL_SYSCTL_HELP_SET_LINK_ACTIVE);
260321802a12SKrzysztof Galazka 
26044294f337SSean Bruno 	/* Add sysctls meant to print debug information, but don't list them
26054294f337SSean Bruno 	 * in "sysctl -a" output. */
26064294f337SSean Bruno 	debug_node = SYSCTL_ADD_NODE(ctx, ctx_list,
260720b91f0aSPawel Biernacki 	    OID_AUTO, "debug", CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE, NULL,
260820b91f0aSPawel Biernacki 	    "Debug Sysctls");
26094294f337SSean Bruno 	debug_list = SYSCTL_CHILDREN(debug_node);
26104294f337SSean Bruno 
26114294f337SSean Bruno 	SYSCTL_ADD_UINT(ctx, debug_list,
26124294f337SSean Bruno 	    OID_AUTO, "shared_debug_mask", CTLFLAG_RW,
26134294f337SSean Bruno 	    &pf->hw.debug_mask, 0, "Shared code debug message level");
26144294f337SSean Bruno 
26154294f337SSean Bruno 	SYSCTL_ADD_UINT(ctx, debug_list,
26164294f337SSean Bruno 	    OID_AUTO, "core_debug_mask", CTLFLAG_RW,
26171031d839SEric Joyner 	    &pf->dbg_mask, 0, "Non-shared code debug message level");
26184294f337SSean Bruno 
26194294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, debug_list,
262020b91f0aSPawel Biernacki 	    OID_AUTO, "link_status",
262120b91f0aSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
26224294f337SSean Bruno 	    pf, 0, ixl_sysctl_link_status, "A", IXL_SYSCTL_HELP_LINK_STATUS);
26234294f337SSean Bruno 
26244294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, debug_list,
262521802a12SKrzysztof Galazka 	    OID_AUTO, "phy_abilities_init",
262621802a12SKrzysztof Galazka 	    CTLTYPE_STRING | CTLFLAG_RD,
262721802a12SKrzysztof Galazka 	    pf, 1, ixl_sysctl_phy_abilities, "A", "Initial PHY Abilities");
262821802a12SKrzysztof Galazka 
262921802a12SKrzysztof Galazka 	SYSCTL_ADD_PROC(ctx, debug_list,
263020b91f0aSPawel Biernacki 	    OID_AUTO, "phy_abilities",
263120b91f0aSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
26324294f337SSean Bruno 	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
26334294f337SSean Bruno 
26344294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, debug_list,
263520b91f0aSPawel Biernacki 	    OID_AUTO, "filter_list",
263620b91f0aSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
26374294f337SSean Bruno 	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
26384294f337SSean Bruno 
26394294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, debug_list,
264020b91f0aSPawel Biernacki 	    OID_AUTO, "hw_res_alloc",
264120b91f0aSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
26424294f337SSean Bruno 	    pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
26434294f337SSean Bruno 
26444294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, debug_list,
264520b91f0aSPawel Biernacki 	    OID_AUTO, "switch_config",
264620b91f0aSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
26474294f337SSean Bruno 	    pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
26484294f337SSean Bruno 
26494294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, debug_list,
2650fa6662b3SLutz Donnerhacke 	    OID_AUTO, "switch_vlans",
2651fa6662b3SLutz Donnerhacke 	    CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT,
2652fa6662b3SLutz Donnerhacke 	    pf, 0, ixl_sysctl_switch_vlans, "I", "HW Switch VLAN Configuration");
2653fa6662b3SLutz Donnerhacke 
2654fa6662b3SLutz Donnerhacke 	SYSCTL_ADD_PROC(ctx, debug_list,
265520b91f0aSPawel Biernacki 	    OID_AUTO, "rss_key",
265620b91f0aSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
26574294f337SSean Bruno 	    pf, 0, ixl_sysctl_hkey, "A", "View RSS key");
26584294f337SSean Bruno 
26594294f337SSean Bruno 	SYSCTL_ADD_PROC(ctx, debug_list,
266020b91f0aSPawel Biernacki 	    OID_AUTO, "rss_lut",
266120b91f0aSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
26624294f337SSean Bruno 	    pf, 0, ixl_sysctl_hlut, "A", "View RSS lookup table");
2663cb6b8299SEric Joyner 
2664cb6b8299SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
266520b91f0aSPawel Biernacki 	    OID_AUTO, "rss_hena",
266620b91f0aSPawel Biernacki 	    CTLTYPE_ULONG | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
2667cb6b8299SEric Joyner 	    pf, 0, ixl_sysctl_hena, "LU", "View enabled packet types for RSS");
2668cb6b8299SEric Joyner 
2669cb6b8299SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
267020b91f0aSPawel Biernacki 	    OID_AUTO, "disable_fw_link_management",
267120b91f0aSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT,
2672cb6b8299SEric Joyner 	    pf, 0, ixl_sysctl_fw_link_management, "I", "Disable FW Link Management");
2673cb6b8299SEric Joyner 
2674ceebc2f3SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
267520b91f0aSPawel Biernacki 	    OID_AUTO, "dump_debug_data",
267620b91f0aSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
2677ceebc2f3SEric Joyner 	    pf, 0, ixl_sysctl_dump_debug_data, "A", "Dump Debug Data from FW");
2678ceebc2f3SEric Joyner 
26791031d839SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
268020b91f0aSPawel Biernacki 	    OID_AUTO, "do_pf_reset",
268120b91f0aSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT,
26821031d839SEric Joyner 	    pf, 0, ixl_sysctl_do_pf_reset, "I", "Tell HW to initiate a PF reset");
26831031d839SEric Joyner 
26841031d839SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
268520b91f0aSPawel Biernacki 	    OID_AUTO, "do_core_reset",
268620b91f0aSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT,
26871031d839SEric Joyner 	    pf, 0, ixl_sysctl_do_core_reset, "I", "Tell HW to initiate a CORE reset");
26881031d839SEric Joyner 
26891031d839SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
269020b91f0aSPawel Biernacki 	    OID_AUTO, "do_global_reset",
269120b91f0aSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT,
26921031d839SEric Joyner 	    pf, 0, ixl_sysctl_do_global_reset, "I", "Tell HW to initiate a GLOBAL reset");
26931031d839SEric Joyner 
26941031d839SEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
269520b91f0aSPawel Biernacki 	    OID_AUTO, "queue_interrupt_table",
269620b91f0aSPawel Biernacki 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
26971031d839SEric Joyner 	    pf, 0, ixl_sysctl_queue_interrupt_table, "A", "View MSI-X indices for TX/RX queues");
26981031d839SEric Joyner 
2699a146207dSPiotr Kubaj 	SYSCTL_ADD_PROC(ctx, debug_list,
2700a146207dSPiotr Kubaj 	    OID_AUTO, "phy_statistics", CTLTYPE_STRING | CTLFLAG_RD,
2701a146207dSPiotr Kubaj 	    pf, 0, ixl_sysctl_phy_statistics, "A", "PHY Statistics");
2702a146207dSPiotr Kubaj 
2703cb6b8299SEric Joyner 	if (pf->has_i2c) {
2704cb6b8299SEric Joyner 		SYSCTL_ADD_PROC(ctx, debug_list,
270520b91f0aSPawel Biernacki 		    OID_AUTO, "read_i2c_byte",
270620b91f0aSPawel Biernacki 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
27071031d839SEric Joyner 		    pf, 0, ixl_sysctl_read_i2c_byte, "I", IXL_SYSCTL_HELP_READ_I2C);
2708cb6b8299SEric Joyner 
2709cb6b8299SEric Joyner 		SYSCTL_ADD_PROC(ctx, debug_list,
271020b91f0aSPawel Biernacki 		    OID_AUTO, "write_i2c_byte",
271120b91f0aSPawel Biernacki 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
27121031d839SEric Joyner 		    pf, 0, ixl_sysctl_write_i2c_byte, "I", IXL_SYSCTL_HELP_WRITE_I2C);
27131031d839SEric Joyner 
27141031d839SEric Joyner 		SYSCTL_ADD_PROC(ctx, debug_list,
271520b91f0aSPawel Biernacki 		    OID_AUTO, "read_i2c_diag_data",
271620b91f0aSPawel Biernacki 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
27171031d839SEric Joyner 		    pf, 0, ixl_sysctl_read_i2c_diag_data, "A", "Dump selected diagnostic data from FW");
2718cb6b8299SEric Joyner 	}
27194294f337SSean Bruno }
27204294f337SSean Bruno 
27214294f337SSean Bruno /*
27224294f337SSean Bruno  * Primarily for finding out how many queues can be assigned to VFs,
27234294f337SSean Bruno  * at runtime.
27244294f337SSean Bruno  */
27254294f337SSean Bruno static int
ixl_sysctl_unallocated_queues(SYSCTL_HANDLER_ARGS)27264294f337SSean Bruno ixl_sysctl_unallocated_queues(SYSCTL_HANDLER_ARGS)
27274294f337SSean Bruno {
27284294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
27294294f337SSean Bruno 	int queues;
27304294f337SSean Bruno 
27314294f337SSean Bruno 	queues = (int)ixl_pf_qmgr_get_num_free(&pf->qmgr);
27324294f337SSean Bruno 
27334294f337SSean Bruno 	return sysctl_handle_int(oidp, NULL, queues, req);
27344294f337SSean Bruno }
27354294f337SSean Bruno 
2736b4a7ce06SEric Joyner static const char *
ixl_link_speed_string(enum i40e_aq_link_speed link_speed)2737b4a7ce06SEric Joyner ixl_link_speed_string(enum i40e_aq_link_speed link_speed)
27384294f337SSean Bruno {
2739b4a7ce06SEric Joyner 	const char * link_speed_str[] = {
27404294f337SSean Bruno 		"Unknown",
2741cb6b8299SEric Joyner 		"100 Mbps",
2742cb6b8299SEric Joyner 		"1 Gbps",
2743cb6b8299SEric Joyner 		"10 Gbps",
2744cb6b8299SEric Joyner 		"40 Gbps",
2745cb6b8299SEric Joyner 		"20 Gbps",
2746cb6b8299SEric Joyner 		"25 Gbps",
27472984a8ddSEric Joyner 		"2.5 Gbps",
27482984a8ddSEric Joyner 		"5 Gbps"
27494294f337SSean Bruno 	};
2750b4a7ce06SEric Joyner 	int index;
27514294f337SSean Bruno 
2752cb6b8299SEric Joyner 	switch (link_speed) {
27534294f337SSean Bruno 	case I40E_LINK_SPEED_100MB:
27544294f337SSean Bruno 		index = 1;
27554294f337SSean Bruno 		break;
27564294f337SSean Bruno 	case I40E_LINK_SPEED_1GB:
27574294f337SSean Bruno 		index = 2;
27584294f337SSean Bruno 		break;
27594294f337SSean Bruno 	case I40E_LINK_SPEED_10GB:
27604294f337SSean Bruno 		index = 3;
27614294f337SSean Bruno 		break;
27624294f337SSean Bruno 	case I40E_LINK_SPEED_40GB:
27634294f337SSean Bruno 		index = 4;
27644294f337SSean Bruno 		break;
27654294f337SSean Bruno 	case I40E_LINK_SPEED_20GB:
27664294f337SSean Bruno 		index = 5;
27674294f337SSean Bruno 		break;
2768cb6b8299SEric Joyner 	case I40E_LINK_SPEED_25GB:
2769cb6b8299SEric Joyner 		index = 6;
2770cb6b8299SEric Joyner 		break;
27712984a8ddSEric Joyner 	case I40E_LINK_SPEED_2_5GB:
27722984a8ddSEric Joyner 		index = 7;
27732984a8ddSEric Joyner 		break;
27742984a8ddSEric Joyner 	case I40E_LINK_SPEED_5GB:
27752984a8ddSEric Joyner 		index = 8;
27762984a8ddSEric Joyner 		break;
27774294f337SSean Bruno 	case I40E_LINK_SPEED_UNKNOWN:
27784294f337SSean Bruno 	default:
27794294f337SSean Bruno 		index = 0;
27804294f337SSean Bruno 		break;
27814294f337SSean Bruno 	}
27824294f337SSean Bruno 
2783b4a7ce06SEric Joyner 	return (link_speed_str[index]);
2784cb6b8299SEric Joyner }
2785cb6b8299SEric Joyner 
2786cb6b8299SEric Joyner int
ixl_sysctl_current_speed(SYSCTL_HANDLER_ARGS)2787ceebc2f3SEric Joyner ixl_sysctl_current_speed(SYSCTL_HANDLER_ARGS)
2788cb6b8299SEric Joyner {
2789cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
2790cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
2791cb6b8299SEric Joyner 	int error = 0;
2792cb6b8299SEric Joyner 
2793cb6b8299SEric Joyner 	ixl_update_link_status(pf);
2794cb6b8299SEric Joyner 
2795cb6b8299SEric Joyner 	error = sysctl_handle_string(oidp,
2796b4a7ce06SEric Joyner 	    __DECONST(void *,
2797b4a7ce06SEric Joyner 		ixl_link_speed_string(hw->phy.link_info.link_speed)),
2798cb6b8299SEric Joyner 	    8, req);
2799b4a7ce06SEric Joyner 
28004294f337SSean Bruno 	return (error);
28014294f337SSean Bruno }
28024294f337SSean Bruno 
2803ceebc2f3SEric Joyner /*
2804ceebc2f3SEric Joyner  * Converts 8-bit speeds value to and from sysctl flags and
2805ceebc2f3SEric Joyner  * Admin Queue flags.
2806ceebc2f3SEric Joyner  */
2807cb6b8299SEric Joyner static u8
ixl_convert_sysctl_aq_link_speed(u8 speeds,bool to_aq)2808cb6b8299SEric Joyner ixl_convert_sysctl_aq_link_speed(u8 speeds, bool to_aq)
2809cb6b8299SEric Joyner {
28102984a8ddSEric Joyner #define SPEED_MAP_SIZE 8
2811b4a7ce06SEric Joyner 	static u16 speedmap[SPEED_MAP_SIZE] = {
2812cb6b8299SEric Joyner 		(I40E_LINK_SPEED_100MB | (0x1 << 8)),
2813cb6b8299SEric Joyner 		(I40E_LINK_SPEED_1GB   | (0x2 << 8)),
2814cb6b8299SEric Joyner 		(I40E_LINK_SPEED_10GB  | (0x4 << 8)),
2815cb6b8299SEric Joyner 		(I40E_LINK_SPEED_20GB  | (0x8 << 8)),
2816cb6b8299SEric Joyner 		(I40E_LINK_SPEED_25GB  | (0x10 << 8)),
28172984a8ddSEric Joyner 		(I40E_LINK_SPEED_40GB  | (0x20 << 8)),
28182984a8ddSEric Joyner 		(I40E_LINK_SPEED_2_5GB | (0x40 << 8)),
28192984a8ddSEric Joyner 		(I40E_LINK_SPEED_5GB   | (0x80 << 8)),
2820cb6b8299SEric Joyner 	};
2821cb6b8299SEric Joyner 	u8 retval = 0;
2822cb6b8299SEric Joyner 
2823b4a7ce06SEric Joyner 	for (int i = 0; i < SPEED_MAP_SIZE; i++) {
2824cb6b8299SEric Joyner 		if (to_aq)
2825cb6b8299SEric Joyner 			retval |= (speeds & (speedmap[i] >> 8)) ? (speedmap[i] & 0xff) : 0;
2826cb6b8299SEric Joyner 		else
2827cb6b8299SEric Joyner 			retval |= (speeds & speedmap[i]) ? (speedmap[i] >> 8) : 0;
2828cb6b8299SEric Joyner 	}
2829cb6b8299SEric Joyner 
2830cb6b8299SEric Joyner 	return (retval);
2831cb6b8299SEric Joyner }
2832cb6b8299SEric Joyner 
28334294f337SSean Bruno int
ixl_set_advertised_speeds(struct ixl_pf * pf,int speeds,bool from_aq)2834ceebc2f3SEric Joyner ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds, bool from_aq)
28354294f337SSean Bruno {
28364294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
28374294f337SSean Bruno 	device_t dev = pf->dev;
28384294f337SSean Bruno 	struct i40e_aq_get_phy_abilities_resp abilities;
28394294f337SSean Bruno 	struct i40e_aq_set_phy_config config;
28404294f337SSean Bruno 	enum i40e_status_code aq_error = 0;
28414294f337SSean Bruno 
28424294f337SSean Bruno 	/* Get current capability information */
28434294f337SSean Bruno 	aq_error = i40e_aq_get_phy_capabilities(hw,
28444294f337SSean Bruno 	    FALSE, FALSE, &abilities, NULL);
28454294f337SSean Bruno 	if (aq_error) {
28464294f337SSean Bruno 		device_printf(dev,
28474294f337SSean Bruno 		    "%s: Error getting phy capabilities %d,"
28484294f337SSean Bruno 		    " aq error: %d\n", __func__, aq_error,
28494294f337SSean Bruno 		    hw->aq.asq_last_status);
28504294f337SSean Bruno 		return (EIO);
28514294f337SSean Bruno 	}
28524294f337SSean Bruno 
28534294f337SSean Bruno 	/* Prepare new config */
28544294f337SSean Bruno 	bzero(&config, sizeof(config));
2855ceebc2f3SEric Joyner 	if (from_aq)
2856ceebc2f3SEric Joyner 		config.link_speed = speeds;
2857ceebc2f3SEric Joyner 	else
2858cb6b8299SEric Joyner 		config.link_speed = ixl_convert_sysctl_aq_link_speed(speeds, true);
28594294f337SSean Bruno 	config.phy_type = abilities.phy_type;
2860cb6b8299SEric Joyner 	config.phy_type_ext = abilities.phy_type_ext;
28614294f337SSean Bruno 	config.abilities = abilities.abilities
28624294f337SSean Bruno 	    | I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
28634294f337SSean Bruno 	config.eee_capability = abilities.eee_capability;
28644294f337SSean Bruno 	config.eeer = abilities.eeer_val;
28654294f337SSean Bruno 	config.low_power_ctrl = abilities.d3_lpan;
2866b4a7ce06SEric Joyner 	config.fec_config = abilities.fec_cfg_curr_mod_ext_info
2867b4a7ce06SEric Joyner 	    & I40E_AQ_PHY_FEC_CONFIG_MASK;
28684294f337SSean Bruno 
28694294f337SSean Bruno 	/* Do aq command & restart link */
28704294f337SSean Bruno 	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
28714294f337SSean Bruno 	if (aq_error) {
28724294f337SSean Bruno 		device_printf(dev,
28734294f337SSean Bruno 		    "%s: Error setting new phy config %d,"
28744294f337SSean Bruno 		    " aq error: %d\n", __func__, aq_error,
28754294f337SSean Bruno 		    hw->aq.asq_last_status);
2876cb6b8299SEric Joyner 		return (EIO);
28774294f337SSean Bruno 	}
28784294f337SSean Bruno 
28794294f337SSean Bruno 	return (0);
28804294f337SSean Bruno }
28814294f337SSean Bruno 
28824294f337SSean Bruno /*
2883b4a7ce06SEric Joyner ** Supported link speeds
2884ceebc2f3SEric Joyner **	Flags:
2885ceebc2f3SEric Joyner **	 0x1 - 100 Mb
2886ceebc2f3SEric Joyner **	 0x2 - 1G
2887ceebc2f3SEric Joyner **	 0x4 - 10G
2888ceebc2f3SEric Joyner **	 0x8 - 20G
2889ceebc2f3SEric Joyner **	0x10 - 25G
2890ceebc2f3SEric Joyner **	0x20 - 40G
28912984a8ddSEric Joyner **	0x40 - 2.5G
28922984a8ddSEric Joyner **	0x80 - 5G
2893ceebc2f3SEric Joyner */
2894ceebc2f3SEric Joyner static int
ixl_sysctl_supported_speeds(SYSCTL_HANDLER_ARGS)2895ceebc2f3SEric Joyner ixl_sysctl_supported_speeds(SYSCTL_HANDLER_ARGS)
2896ceebc2f3SEric Joyner {
2897ceebc2f3SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
2898ceebc2f3SEric Joyner 	int supported = ixl_convert_sysctl_aq_link_speed(pf->supported_speeds, false);
2899ceebc2f3SEric Joyner 
2900ceebc2f3SEric Joyner 	return sysctl_handle_int(oidp, NULL, supported, req);
2901ceebc2f3SEric Joyner }
2902ceebc2f3SEric Joyner 
2903ceebc2f3SEric Joyner /*
29044294f337SSean Bruno ** Control link advertise speed:
29054294f337SSean Bruno **	Flags:
29064294f337SSean Bruno **	 0x1 - advertise 100 Mb
29074294f337SSean Bruno **	 0x2 - advertise 1G
29084294f337SSean Bruno **	 0x4 - advertise 10G
29094294f337SSean Bruno **	 0x8 - advertise 20G
2910cb6b8299SEric Joyner **	0x10 - advertise 25G
2911cb6b8299SEric Joyner **	0x20 - advertise 40G
29122984a8ddSEric Joyner **	0x40 - advertise 2.5G
29132984a8ddSEric Joyner **	0x80 - advertise 5G
29144294f337SSean Bruno **
29154294f337SSean Bruno **	Set to 0 to disable link
29164294f337SSean Bruno */
29174294f337SSean Bruno int
ixl_sysctl_set_advertise(SYSCTL_HANDLER_ARGS)2918ceebc2f3SEric Joyner ixl_sysctl_set_advertise(SYSCTL_HANDLER_ARGS)
29194294f337SSean Bruno {
29204294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
29214294f337SSean Bruno 	device_t dev = pf->dev;
2922cb6b8299SEric Joyner 	u8 converted_speeds;
29234294f337SSean Bruno 	int requested_ls = 0;
29244294f337SSean Bruno 	int error = 0;
29254294f337SSean Bruno 
29264294f337SSean Bruno 	/* Read in new mode */
29274294f337SSean Bruno 	requested_ls = pf->advertised_speed;
29284294f337SSean Bruno 	error = sysctl_handle_int(oidp, &requested_ls, 0, req);
29294294f337SSean Bruno 	if ((error) || (req->newptr == NULL))
29304294f337SSean Bruno 		return (error);
2931b4a7ce06SEric Joyner 	if (IXL_PF_IN_RECOVERY_MODE(pf)) {
2932b4a7ce06SEric Joyner 		device_printf(dev, "Interface is currently in FW recovery mode. "
2933b4a7ce06SEric Joyner 				"Setting advertise speed not supported\n");
2934b4a7ce06SEric Joyner 		return (EINVAL);
2935b4a7ce06SEric Joyner 	}
2936ceebc2f3SEric Joyner 
2937ceebc2f3SEric Joyner 	/* Error out if bits outside of possible flag range are set */
29382984a8ddSEric Joyner 	if ((requested_ls & ~((u8)0xFF)) != 0) {
2939ceebc2f3SEric Joyner 		device_printf(dev, "Input advertised speed out of range; "
2940ceebc2f3SEric Joyner 		    "valid flags are: 0x%02x\n",
2941ceebc2f3SEric Joyner 		    ixl_convert_sysctl_aq_link_speed(pf->supported_speeds, false));
29424294f337SSean Bruno 		return (EINVAL);
29434294f337SSean Bruno 	}
29444294f337SSean Bruno 
2945ceebc2f3SEric Joyner 	/* Check if adapter supports input value */
2946cb6b8299SEric Joyner 	converted_speeds = ixl_convert_sysctl_aq_link_speed((u8)requested_ls, true);
2947cb6b8299SEric Joyner 	if ((converted_speeds | pf->supported_speeds) != pf->supported_speeds) {
2948cb6b8299SEric Joyner 		device_printf(dev, "Invalid advertised speed; "
2949cb6b8299SEric Joyner 		    "valid flags are: 0x%02x\n",
2950cb6b8299SEric Joyner 		    ixl_convert_sysctl_aq_link_speed(pf->supported_speeds, false));
2951cb6b8299SEric Joyner 		return (EINVAL);
2952cb6b8299SEric Joyner 	}
29534294f337SSean Bruno 
2954ceebc2f3SEric Joyner 	error = ixl_set_advertised_speeds(pf, requested_ls, false);
29554294f337SSean Bruno 	if (error)
29564294f337SSean Bruno 		return (error);
29574294f337SSean Bruno 
29584294f337SSean Bruno 	pf->advertised_speed = requested_ls;
29594294f337SSean Bruno 	ixl_update_link_status(pf);
29604294f337SSean Bruno 	return (0);
29614294f337SSean Bruno }
29624294f337SSean Bruno 
29634294f337SSean Bruno /*
2964b4a7ce06SEric Joyner  * Input: bitmap of enum i40e_aq_link_speed
2965b4a7ce06SEric Joyner  */
2966b4a7ce06SEric Joyner u64
ixl_max_aq_speed_to_value(u8 link_speeds)2967b4a7ce06SEric Joyner ixl_max_aq_speed_to_value(u8 link_speeds)
2968b4a7ce06SEric Joyner {
2969b4a7ce06SEric Joyner 	if (link_speeds & I40E_LINK_SPEED_40GB)
2970b4a7ce06SEric Joyner 		return IF_Gbps(40);
2971b4a7ce06SEric Joyner 	if (link_speeds & I40E_LINK_SPEED_25GB)
2972b4a7ce06SEric Joyner 		return IF_Gbps(25);
2973b4a7ce06SEric Joyner 	if (link_speeds & I40E_LINK_SPEED_20GB)
2974b4a7ce06SEric Joyner 		return IF_Gbps(20);
2975b4a7ce06SEric Joyner 	if (link_speeds & I40E_LINK_SPEED_10GB)
2976b4a7ce06SEric Joyner 		return IF_Gbps(10);
29772984a8ddSEric Joyner 	if (link_speeds & I40E_LINK_SPEED_5GB)
29782984a8ddSEric Joyner 		return IF_Gbps(5);
29792984a8ddSEric Joyner 	if (link_speeds & I40E_LINK_SPEED_2_5GB)
29802984a8ddSEric Joyner 		return IF_Mbps(2500);
2981b4a7ce06SEric Joyner 	if (link_speeds & I40E_LINK_SPEED_1GB)
2982b4a7ce06SEric Joyner 		return IF_Gbps(1);
2983b4a7ce06SEric Joyner 	if (link_speeds & I40E_LINK_SPEED_100MB)
2984b4a7ce06SEric Joyner 		return IF_Mbps(100);
2985b4a7ce06SEric Joyner 	else
2986b4a7ce06SEric Joyner 		/* Minimum supported link speed */
2987b4a7ce06SEric Joyner 		return IF_Mbps(100);
2988b4a7ce06SEric Joyner }
2989b4a7ce06SEric Joyner 
2990b4a7ce06SEric Joyner /*
29914294f337SSean Bruno ** Get the width and transaction speed of
29924294f337SSean Bruno ** the bus this adapter is plugged into.
29934294f337SSean Bruno */
29944294f337SSean Bruno void
ixl_get_bus_info(struct ixl_pf * pf)2995cb6b8299SEric Joyner ixl_get_bus_info(struct ixl_pf *pf)
29964294f337SSean Bruno {
2997cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
2998cb6b8299SEric Joyner 	device_t dev = pf->dev;
29994294f337SSean Bruno         u16 link;
3000cb6b8299SEric Joyner         u32 offset, num_ports;
3001cb6b8299SEric Joyner 	u64 max_speed;
30024294f337SSean Bruno 
30034294f337SSean Bruno 	/* Some devices don't use PCIE */
30044294f337SSean Bruno 	if (hw->mac.type == I40E_MAC_X722)
30054294f337SSean Bruno 		return;
30064294f337SSean Bruno 
30074294f337SSean Bruno         /* Read PCI Express Capabilities Link Status Register */
30084294f337SSean Bruno         pci_find_cap(dev, PCIY_EXPRESS, &offset);
30094294f337SSean Bruno         link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
30104294f337SSean Bruno 
30114294f337SSean Bruno 	/* Fill out hw struct with PCIE info */
30124294f337SSean Bruno 	i40e_set_pci_config_data(hw, link);
30134294f337SSean Bruno 
30144294f337SSean Bruno 	/* Use info to print out bandwidth messages */
30154294f337SSean Bruno         device_printf(dev,"PCI Express Bus: Speed %s %s\n",
30164294f337SSean Bruno             ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s":
30174294f337SSean Bruno             (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s":
30184294f337SSean Bruno             (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"),
30194294f337SSean Bruno             (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" :
30204294f337SSean Bruno             (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" :
3021cb6b8299SEric Joyner             (hw->bus.width == i40e_bus_width_pcie_x2) ? "Width x2" :
30224294f337SSean Bruno             (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" :
30234294f337SSean Bruno             ("Unknown"));
30244294f337SSean Bruno 
3025cb6b8299SEric Joyner 	/*
3026cb6b8299SEric Joyner 	 * If adapter is in slot with maximum supported speed,
3027cb6b8299SEric Joyner 	 * no warning message needs to be printed out.
3028cb6b8299SEric Joyner 	 */
3029cb6b8299SEric Joyner 	if (hw->bus.speed >= i40e_bus_speed_8000
3030cb6b8299SEric Joyner 	    && hw->bus.width >= i40e_bus_width_pcie_x8)
3031cb6b8299SEric Joyner 		return;
3032cb6b8299SEric Joyner 
3033cb6b8299SEric Joyner 	num_ports = bitcount32(hw->func_caps.valid_functions);
3034cb6b8299SEric Joyner 	max_speed = ixl_max_aq_speed_to_value(pf->supported_speeds) / 1000000;
3035cb6b8299SEric Joyner 
3036cb6b8299SEric Joyner 	if ((num_ports * max_speed) > hw->bus.speed * hw->bus.width) {
30374294f337SSean Bruno                 device_printf(dev, "PCI-Express bandwidth available"
30384294f337SSean Bruno                     " for this device may be insufficient for"
30394294f337SSean Bruno                     " optimal performance.\n");
3040cb6b8299SEric Joyner                 device_printf(dev, "Please move the device to a different"
3041cb6b8299SEric Joyner 		    " PCI-e link with more lanes and/or higher"
3042cb6b8299SEric Joyner 		    " transfer rate.\n");
30434294f337SSean Bruno         }
30444294f337SSean Bruno }
30454294f337SSean Bruno 
30464294f337SSean Bruno static int
ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)30474294f337SSean Bruno ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)
30484294f337SSean Bruno {
30494294f337SSean Bruno 	struct ixl_pf	*pf = (struct ixl_pf *)arg1;
30504294f337SSean Bruno 	struct i40e_hw	*hw = &pf->hw;
30514294f337SSean Bruno 	struct sbuf	*sbuf;
30524294f337SSean Bruno 
30534294f337SSean Bruno 	sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
30544294f337SSean Bruno 	ixl_nvm_version_str(hw, sbuf);
30554294f337SSean Bruno 	sbuf_finish(sbuf);
30564294f337SSean Bruno 	sbuf_delete(sbuf);
30574294f337SSean Bruno 
3058ceebc2f3SEric Joyner 	return (0);
30594294f337SSean Bruno }
30604294f337SSean Bruno 
30614294f337SSean Bruno void
ixl_print_nvm_cmd(device_t dev,struct i40e_nvm_access * nvma)30624294f337SSean Bruno ixl_print_nvm_cmd(device_t dev, struct i40e_nvm_access *nvma)
30634294f337SSean Bruno {
3064b4a7ce06SEric Joyner 	u8 nvma_ptr = nvma->config & 0xFF;
3065b4a7ce06SEric Joyner 	u8 nvma_flags = (nvma->config & 0xF00) >> 8;
3066b4a7ce06SEric Joyner 	const char * cmd_str;
30674294f337SSean Bruno 
30684294f337SSean Bruno 	switch (nvma->command) {
3069b4a7ce06SEric Joyner 	case I40E_NVM_READ:
3070b4a7ce06SEric Joyner 		if (nvma_ptr == 0xF && nvma_flags == 0xF &&
3071b4a7ce06SEric Joyner 		    nvma->offset == 0 && nvma->data_size == 1) {
3072b4a7ce06SEric Joyner 			device_printf(dev, "NVMUPD: Get Driver Status Command\n");
3073b4a7ce06SEric Joyner 			return;
3074b4a7ce06SEric Joyner 		}
3075b4a7ce06SEric Joyner 		cmd_str = "READ ";
30764294f337SSean Bruno 		break;
3077b4a7ce06SEric Joyner 	case I40E_NVM_WRITE:
3078b4a7ce06SEric Joyner 		cmd_str = "WRITE";
30794294f337SSean Bruno 		break;
30804294f337SSean Bruno 	default:
3081b4a7ce06SEric Joyner 		device_printf(dev, "NVMUPD: unknown command: 0x%08x\n", nvma->command);
3082b4a7ce06SEric Joyner 		return;
30834294f337SSean Bruno 	}
3084b4a7ce06SEric Joyner 	device_printf(dev,
3085b4a7ce06SEric Joyner 	    "NVMUPD: cmd: %s ptr: 0x%02x flags: 0x%01x offset: 0x%08x data_s: 0x%08x\n",
3086b4a7ce06SEric Joyner 	    cmd_str, nvma_ptr, nvma_flags, nvma->offset, nvma->data_size);
30874294f337SSean Bruno }
30884294f337SSean Bruno 
30894294f337SSean Bruno int
ixl_handle_nvmupd_cmd(struct ixl_pf * pf,struct ifdrv * ifd)30904294f337SSean Bruno ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd)
30914294f337SSean Bruno {
30924294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
30934294f337SSean Bruno 	struct i40e_nvm_access *nvma;
30944294f337SSean Bruno 	device_t dev = pf->dev;
30954294f337SSean Bruno 	enum i40e_status_code status = 0;
30962de16a73SEric Joyner 	size_t nvma_size, ifd_len, exp_len;
30972de16a73SEric Joyner 	int err, perrno;
30984294f337SSean Bruno 
30994294f337SSean Bruno 	DEBUGFUNC("ixl_handle_nvmupd_cmd");
31004294f337SSean Bruno 
31014294f337SSean Bruno 	/* Sanity checks */
31022de16a73SEric Joyner 	nvma_size = sizeof(struct i40e_nvm_access);
31032de16a73SEric Joyner 	ifd_len = ifd->ifd_len;
31042de16a73SEric Joyner 
31052de16a73SEric Joyner 	if (ifd_len < nvma_size ||
31064294f337SSean Bruno 	    ifd->ifd_data == NULL) {
31074294f337SSean Bruno 		device_printf(dev, "%s: incorrect ifdrv length or data pointer\n",
31084294f337SSean Bruno 		    __func__);
3109ceebc2f3SEric Joyner 		device_printf(dev, "%s: ifdrv length: %zu, sizeof(struct i40e_nvm_access): %zu\n",
31102de16a73SEric Joyner 		    __func__, ifd_len, nvma_size);
31114294f337SSean Bruno 		device_printf(dev, "%s: data pointer: %p\n", __func__,
31124294f337SSean Bruno 		    ifd->ifd_data);
31134294f337SSean Bruno 		return (EINVAL);
31144294f337SSean Bruno 	}
31154294f337SSean Bruno 
3116b4a7ce06SEric Joyner 	nvma = malloc(ifd_len, M_IXL, M_WAITOK);
31172de16a73SEric Joyner 	err = copyin(ifd->ifd_data, nvma, ifd_len);
31182de16a73SEric Joyner 	if (err) {
31192de16a73SEric Joyner 		device_printf(dev, "%s: Cannot get request from user space\n",
31202de16a73SEric Joyner 		    __func__);
3121b4a7ce06SEric Joyner 		free(nvma, M_IXL);
31222de16a73SEric Joyner 		return (err);
31232de16a73SEric Joyner 	}
31244294f337SSean Bruno 
31254294f337SSean Bruno 	if (pf->dbg_mask & IXL_DBG_NVMUPD)
31264294f337SSean Bruno 		ixl_print_nvm_cmd(dev, nvma);
31274294f337SSean Bruno 
31287d4dceecSKrzysztof Galazka 	if (IXL_PF_IS_RESETTING(pf)) {
31294294f337SSean Bruno 		int count = 0;
31304294f337SSean Bruno 		while (count++ < 100) {
31314294f337SSean Bruno 			i40e_msec_delay(100);
31327d4dceecSKrzysztof Galazka 			if (!(IXL_PF_IS_RESETTING(pf)))
31334294f337SSean Bruno 				break;
31344294f337SSean Bruno 		}
31354294f337SSean Bruno 	}
31364294f337SSean Bruno 
31377d4dceecSKrzysztof Galazka 	if (IXL_PF_IS_RESETTING(pf)) {
3138b4a7ce06SEric Joyner 		device_printf(dev,
3139b4a7ce06SEric Joyner 		    "%s: timeout waiting for EMP reset to finish\n",
3140b4a7ce06SEric Joyner 		    __func__);
3141b4a7ce06SEric Joyner 		free(nvma, M_IXL);
31422de16a73SEric Joyner 		return (-EBUSY);
31432de16a73SEric Joyner 	}
31442de16a73SEric Joyner 
31452de16a73SEric Joyner 	if (nvma->data_size < 1 || nvma->data_size > 4096) {
3146b4a7ce06SEric Joyner 		device_printf(dev,
3147b4a7ce06SEric Joyner 		    "%s: invalid request, data size not in supported range\n",
31482de16a73SEric Joyner 		    __func__);
3149b4a7ce06SEric Joyner 		free(nvma, M_IXL);
31502de16a73SEric Joyner 		return (EINVAL);
31512de16a73SEric Joyner 	}
31522de16a73SEric Joyner 
31532de16a73SEric Joyner 	/*
31542de16a73SEric Joyner 	 * Older versions of the NVM update tool don't set ifd_len to the size
31552de16a73SEric Joyner 	 * of the entire buffer passed to the ioctl. Check the data_size field
31562de16a73SEric Joyner 	 * in the contained i40e_nvm_access struct and ensure everything is
31572de16a73SEric Joyner 	 * copied in from userspace.
31582de16a73SEric Joyner 	 */
31592de16a73SEric Joyner 	exp_len = nvma_size + nvma->data_size - 1; /* One byte is kept in struct */
31602de16a73SEric Joyner 
31612de16a73SEric Joyner 	if (ifd_len < exp_len) {
31622de16a73SEric Joyner 		ifd_len = exp_len;
3163b4a7ce06SEric Joyner 		nvma = realloc(nvma, ifd_len, M_IXL, M_WAITOK);
31642de16a73SEric Joyner 		err = copyin(ifd->ifd_data, nvma, ifd_len);
31652de16a73SEric Joyner 		if (err) {
31662de16a73SEric Joyner 			device_printf(dev, "%s: Cannot get request from user space\n",
31672de16a73SEric Joyner 					__func__);
3168b4a7ce06SEric Joyner 			free(nvma, M_IXL);
31692de16a73SEric Joyner 			return (err);
31702de16a73SEric Joyner 		}
31712de16a73SEric Joyner 	}
31722de16a73SEric Joyner 
31731031d839SEric Joyner 	// TODO: Might need a different lock here
31741031d839SEric Joyner 	// IXL_PF_LOCK(pf);
31754294f337SSean Bruno 	status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno);
31761031d839SEric Joyner 	// IXL_PF_UNLOCK(pf);
31772de16a73SEric Joyner 
31782de16a73SEric Joyner 	err = copyout(nvma, ifd->ifd_data, ifd_len);
3179b4a7ce06SEric Joyner 	free(nvma, M_IXL);
31802de16a73SEric Joyner 	if (err) {
31812de16a73SEric Joyner 		device_printf(dev, "%s: Cannot return data to user space\n",
31822de16a73SEric Joyner 				__func__);
31832de16a73SEric Joyner 		return (err);
31844294f337SSean Bruno 	}
31854294f337SSean Bruno 
3186ceebc2f3SEric Joyner 	/* Let the nvmupdate report errors, show them only when debug is enabled */
3187ceebc2f3SEric Joyner 	if (status != 0 && (pf->dbg_mask & IXL_DBG_NVMUPD) != 0)
3188cb6b8299SEric Joyner 		device_printf(dev, "i40e_nvmupd_command status %s, perrno %d\n",
3189cb6b8299SEric Joyner 		    i40e_stat_str(hw, status), perrno);
31904294f337SSean Bruno 
31914294f337SSean Bruno 	/*
31924294f337SSean Bruno 	 * -EPERM is actually ERESTART, which the kernel interprets as it needing
31934294f337SSean Bruno 	 * to run this ioctl again. So use -EACCES for -EPERM instead.
31944294f337SSean Bruno 	 */
31954294f337SSean Bruno 	if (perrno == -EPERM)
31964294f337SSean Bruno 		return (-EACCES);
31974294f337SSean Bruno 	else
31984294f337SSean Bruno 		return (perrno);
31994294f337SSean Bruno }
32004294f337SSean Bruno 
3201cb6b8299SEric Joyner int
ixl_find_i2c_interface(struct ixl_pf * pf)3202cb6b8299SEric Joyner ixl_find_i2c_interface(struct ixl_pf *pf)
3203cb6b8299SEric Joyner {
3204cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
3205cb6b8299SEric Joyner 	bool i2c_en, port_matched;
3206cb6b8299SEric Joyner 	u32 reg;
3207cb6b8299SEric Joyner 
3208cb6b8299SEric Joyner 	for (int i = 0; i < 4; i++) {
3209cb6b8299SEric Joyner 		reg = rd32(hw, I40E_GLGEN_MDIO_I2C_SEL(i));
3210cb6b8299SEric Joyner 		i2c_en = (reg & I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_MASK);
3211cb6b8299SEric Joyner 		port_matched = ((reg & I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_MASK)
3212cb6b8299SEric Joyner 		    >> I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT)
3213cb6b8299SEric Joyner 		    & BIT(hw->port);
3214cb6b8299SEric Joyner 		if (i2c_en && port_matched)
3215cb6b8299SEric Joyner 			return (i);
3216cb6b8299SEric Joyner 	}
3217cb6b8299SEric Joyner 
3218cb6b8299SEric Joyner 	return (-1);
3219cb6b8299SEric Joyner }
3220cb6b8299SEric Joyner 
322121802a12SKrzysztof Galazka void
ixl_set_link(struct ixl_pf * pf,bool enable)322221802a12SKrzysztof Galazka ixl_set_link(struct ixl_pf *pf, bool enable)
322321802a12SKrzysztof Galazka {
322421802a12SKrzysztof Galazka 	struct i40e_hw *hw = &pf->hw;
322521802a12SKrzysztof Galazka 	device_t dev = pf->dev;
322621802a12SKrzysztof Galazka 	struct i40e_aq_get_phy_abilities_resp abilities;
322721802a12SKrzysztof Galazka 	struct i40e_aq_set_phy_config config;
322821802a12SKrzysztof Galazka 	enum i40e_status_code aq_error = 0;
322921802a12SKrzysztof Galazka 	u32 phy_type, phy_type_ext;
323021802a12SKrzysztof Galazka 
323121802a12SKrzysztof Galazka 	/* Get initial capability information */
323221802a12SKrzysztof Galazka 	aq_error = i40e_aq_get_phy_capabilities(hw,
323321802a12SKrzysztof Galazka 	    FALSE, TRUE, &abilities, NULL);
323421802a12SKrzysztof Galazka 	if (aq_error) {
323521802a12SKrzysztof Galazka 		device_printf(dev,
323621802a12SKrzysztof Galazka 		    "%s: Error getting phy capabilities %d,"
323721802a12SKrzysztof Galazka 		    " aq error: %d\n", __func__, aq_error,
323821802a12SKrzysztof Galazka 		    hw->aq.asq_last_status);
323921802a12SKrzysztof Galazka 		return;
324021802a12SKrzysztof Galazka 	}
324121802a12SKrzysztof Galazka 
324221802a12SKrzysztof Galazka 	phy_type = abilities.phy_type;
324321802a12SKrzysztof Galazka 	phy_type_ext = abilities.phy_type_ext;
324421802a12SKrzysztof Galazka 
324521802a12SKrzysztof Galazka 	/* Get current capability information */
324621802a12SKrzysztof Galazka 	aq_error = i40e_aq_get_phy_capabilities(hw,
324721802a12SKrzysztof Galazka 	    FALSE, FALSE, &abilities, NULL);
324821802a12SKrzysztof Galazka 	if (aq_error) {
324921802a12SKrzysztof Galazka 		device_printf(dev,
325021802a12SKrzysztof Galazka 		    "%s: Error getting phy capabilities %d,"
325121802a12SKrzysztof Galazka 		    " aq error: %d\n", __func__, aq_error,
325221802a12SKrzysztof Galazka 		    hw->aq.asq_last_status);
325321802a12SKrzysztof Galazka 		return;
325421802a12SKrzysztof Galazka 	}
325521802a12SKrzysztof Galazka 
325621802a12SKrzysztof Galazka 	/* Prepare new config */
325721802a12SKrzysztof Galazka 	memset(&config, 0, sizeof(config));
325821802a12SKrzysztof Galazka 	config.link_speed = abilities.link_speed;
325921802a12SKrzysztof Galazka 	config.abilities = abilities.abilities;
326021802a12SKrzysztof Galazka 	config.eee_capability = abilities.eee_capability;
326121802a12SKrzysztof Galazka 	config.eeer = abilities.eeer_val;
326221802a12SKrzysztof Galazka 	config.low_power_ctrl = abilities.d3_lpan;
326321802a12SKrzysztof Galazka 	config.fec_config = abilities.fec_cfg_curr_mod_ext_info
326421802a12SKrzysztof Galazka 	    & I40E_AQ_PHY_FEC_CONFIG_MASK;
326521802a12SKrzysztof Galazka 	config.phy_type = 0;
326621802a12SKrzysztof Galazka 	config.phy_type_ext = 0;
326721802a12SKrzysztof Galazka 
326821802a12SKrzysztof Galazka 	config.abilities &= ~(I40E_AQ_PHY_FLAG_PAUSE_TX |
326921802a12SKrzysztof Galazka 			I40E_AQ_PHY_FLAG_PAUSE_RX);
327021802a12SKrzysztof Galazka 
327121802a12SKrzysztof Galazka 	switch (pf->fc) {
327221802a12SKrzysztof Galazka 	case I40E_FC_FULL:
327321802a12SKrzysztof Galazka 		config.abilities |= I40E_AQ_PHY_FLAG_PAUSE_TX |
327421802a12SKrzysztof Galazka 			I40E_AQ_PHY_FLAG_PAUSE_RX;
327521802a12SKrzysztof Galazka 		break;
327621802a12SKrzysztof Galazka 	case I40E_FC_RX_PAUSE:
327721802a12SKrzysztof Galazka 		config.abilities |= I40E_AQ_PHY_FLAG_PAUSE_RX;
327821802a12SKrzysztof Galazka 		break;
327921802a12SKrzysztof Galazka 	case I40E_FC_TX_PAUSE:
328021802a12SKrzysztof Galazka 		config.abilities |= I40E_AQ_PHY_FLAG_PAUSE_TX;
328121802a12SKrzysztof Galazka 		break;
328221802a12SKrzysztof Galazka 	default:
328321802a12SKrzysztof Galazka 		break;
328421802a12SKrzysztof Galazka 	}
328520a52706SKrzysztof Galazka 
328620a52706SKrzysztof Galazka 	if (enable) {
328720a52706SKrzysztof Galazka 		config.phy_type = phy_type;
328820a52706SKrzysztof Galazka 		config.phy_type_ext = phy_type_ext;
328920a52706SKrzysztof Galazka 
329021802a12SKrzysztof Galazka 	}
329121802a12SKrzysztof Galazka 
329221802a12SKrzysztof Galazka 	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
329321802a12SKrzysztof Galazka 	if (aq_error) {
329421802a12SKrzysztof Galazka 		device_printf(dev,
329521802a12SKrzysztof Galazka 		    "%s: Error setting new phy config %d,"
329621802a12SKrzysztof Galazka 		    " aq error: %d\n", __func__, aq_error,
329721802a12SKrzysztof Galazka 		    hw->aq.asq_last_status);
329821802a12SKrzysztof Galazka 		return;
329921802a12SKrzysztof Galazka 	}
330021802a12SKrzysztof Galazka 
330121802a12SKrzysztof Galazka 	aq_error = i40e_aq_set_link_restart_an(hw, enable, NULL);
330221802a12SKrzysztof Galazka 	if (aq_error) {
330321802a12SKrzysztof Galazka 		device_printf(dev,
330421802a12SKrzysztof Galazka 		    "%s: Error set link config %d,"
330521802a12SKrzysztof Galazka 		    " aq error: %d\n", __func__, aq_error,
330621802a12SKrzysztof Galazka 		    hw->aq.asq_last_status);
330721802a12SKrzysztof Galazka 		return;
330821802a12SKrzysztof Galazka 	}
330921802a12SKrzysztof Galazka }
331021802a12SKrzysztof Galazka 
33114294f337SSean Bruno static char *
ixl_phy_type_string(u32 bit_pos,bool ext)3312cb6b8299SEric Joyner ixl_phy_type_string(u32 bit_pos, bool ext)
33134294f337SSean Bruno {
33144294f337SSean Bruno 	static char * phy_types_str[32] = {
33154294f337SSean Bruno 		"SGMII",
33164294f337SSean Bruno 		"1000BASE-KX",
33174294f337SSean Bruno 		"10GBASE-KX4",
33184294f337SSean Bruno 		"10GBASE-KR",
33194294f337SSean Bruno 		"40GBASE-KR4",
33204294f337SSean Bruno 		"XAUI",
33214294f337SSean Bruno 		"XFI",
33224294f337SSean Bruno 		"SFI",
33234294f337SSean Bruno 		"XLAUI",
33244294f337SSean Bruno 		"XLPPI",
33254294f337SSean Bruno 		"40GBASE-CR4",
33264294f337SSean Bruno 		"10GBASE-CR1",
3327ceebc2f3SEric Joyner 		"SFP+ Active DA",
3328ceebc2f3SEric Joyner 		"QSFP+ Active DA",
33294294f337SSean Bruno 		"Reserved (14)",
33304294f337SSean Bruno 		"Reserved (15)",
33314294f337SSean Bruno 		"Reserved (16)",
33324294f337SSean Bruno 		"100BASE-TX",
33334294f337SSean Bruno 		"1000BASE-T",
33344294f337SSean Bruno 		"10GBASE-T",
33354294f337SSean Bruno 		"10GBASE-SR",
33364294f337SSean Bruno 		"10GBASE-LR",
33374294f337SSean Bruno 		"10GBASE-SFP+Cu",
33384294f337SSean Bruno 		"10GBASE-CR1",
33394294f337SSean Bruno 		"40GBASE-CR4",
33404294f337SSean Bruno 		"40GBASE-SR4",
33414294f337SSean Bruno 		"40GBASE-LR4",
33424294f337SSean Bruno 		"1000BASE-SX",
33434294f337SSean Bruno 		"1000BASE-LX",
33444294f337SSean Bruno 		"1000BASE-T Optical",
33454294f337SSean Bruno 		"20GBASE-KR2",
33464294f337SSean Bruno 		"Reserved (31)"
33474294f337SSean Bruno 	};
3348ceebc2f3SEric Joyner 	static char * ext_phy_types_str[8] = {
3349cb6b8299SEric Joyner 		"25GBASE-KR",
3350cb6b8299SEric Joyner 		"25GBASE-CR",
3351cb6b8299SEric Joyner 		"25GBASE-SR",
3352ceebc2f3SEric Joyner 		"25GBASE-LR",
3353ceebc2f3SEric Joyner 		"25GBASE-AOC",
3354ceebc2f3SEric Joyner 		"25GBASE-ACC",
33552984a8ddSEric Joyner 		"2.5GBASE-T",
33562984a8ddSEric Joyner 		"5GBASE-T"
3357cb6b8299SEric Joyner 	};
33584294f337SSean Bruno 
3359ceebc2f3SEric Joyner 	if (ext && bit_pos > 7) return "Invalid_Ext";
33604294f337SSean Bruno 	if (bit_pos > 31) return "Invalid";
3361cb6b8299SEric Joyner 
3362cb6b8299SEric Joyner 	return (ext) ? ext_phy_types_str[bit_pos] : phy_types_str[bit_pos];
33634294f337SSean Bruno }
33644294f337SSean Bruno 
33651031d839SEric Joyner /* TODO: ERJ: I don't this is necessary anymore. */
3366cb6b8299SEric Joyner int
ixl_aq_get_link_status(struct ixl_pf * pf,struct i40e_aqc_get_link_status * link_status)3367cb6b8299SEric Joyner ixl_aq_get_link_status(struct ixl_pf *pf, struct i40e_aqc_get_link_status *link_status)
3368cb6b8299SEric Joyner {
3369cb6b8299SEric Joyner 	device_t dev = pf->dev;
3370cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
3371cb6b8299SEric Joyner 	struct i40e_aq_desc desc;
3372cb6b8299SEric Joyner 	enum i40e_status_code status;
3373cb6b8299SEric Joyner 
3374cb6b8299SEric Joyner 	struct i40e_aqc_get_link_status *aq_link_status =
3375cb6b8299SEric Joyner 		(struct i40e_aqc_get_link_status *)&desc.params.raw;
3376cb6b8299SEric Joyner 
3377cb6b8299SEric Joyner 	i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_get_link_status);
3378cb6b8299SEric Joyner 	link_status->command_flags = CPU_TO_LE16(I40E_AQ_LSE_ENABLE);
3379cb6b8299SEric Joyner 	status = i40e_asq_send_command(hw, &desc, NULL, 0, NULL);
3380cb6b8299SEric Joyner 	if (status) {
3381cb6b8299SEric Joyner 		device_printf(dev,
3382cb6b8299SEric Joyner 		    "%s: i40e_aqc_opc_get_link_status status %s, aq error %s\n",
3383cb6b8299SEric Joyner 		    __func__, i40e_stat_str(hw, status),
3384cb6b8299SEric Joyner 		    i40e_aq_str(hw, hw->aq.asq_last_status));
3385cb6b8299SEric Joyner 		return (EIO);
3386cb6b8299SEric Joyner 	}
3387cb6b8299SEric Joyner 
3388cb6b8299SEric Joyner 	bcopy(aq_link_status, link_status, sizeof(struct i40e_aqc_get_link_status));
3389cb6b8299SEric Joyner 	return (0);
3390cb6b8299SEric Joyner }
3391cb6b8299SEric Joyner 
3392cb6b8299SEric Joyner static char *
ixl_phy_type_string_ls(u8 val)3393cb6b8299SEric Joyner ixl_phy_type_string_ls(u8 val)
3394cb6b8299SEric Joyner {
3395cb6b8299SEric Joyner 	if (val >= 0x1F)
3396cb6b8299SEric Joyner 		return ixl_phy_type_string(val - 0x1F, true);
3397cb6b8299SEric Joyner 	else
3398cb6b8299SEric Joyner 		return ixl_phy_type_string(val, false);
3399cb6b8299SEric Joyner }
34004294f337SSean Bruno 
34014294f337SSean Bruno static int
ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)34024294f337SSean Bruno ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
34034294f337SSean Bruno {
34044294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
34054294f337SSean Bruno 	device_t dev = pf->dev;
34064294f337SSean Bruno 	struct sbuf *buf;
34074294f337SSean Bruno 	int error = 0;
34084294f337SSean Bruno 
34094294f337SSean Bruno 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
34104294f337SSean Bruno 	if (!buf) {
34114294f337SSean Bruno 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
34124294f337SSean Bruno 		return (ENOMEM);
34134294f337SSean Bruno 	}
34144294f337SSean Bruno 
3415cb6b8299SEric Joyner 	struct i40e_aqc_get_link_status link_status;
3416cb6b8299SEric Joyner 	error = ixl_aq_get_link_status(pf, &link_status);
3417cb6b8299SEric Joyner 	if (error) {
34184294f337SSean Bruno 		sbuf_delete(buf);
3419cb6b8299SEric Joyner 		return (error);
34204294f337SSean Bruno 	}
34214294f337SSean Bruno 
34224294f337SSean Bruno 	sbuf_printf(buf, "\n"
34234294f337SSean Bruno 	    "PHY Type : 0x%02x<%s>\n"
34244294f337SSean Bruno 	    "Speed    : 0x%02x\n"
34254294f337SSean Bruno 	    "Link info: 0x%02x\n"
34264294f337SSean Bruno 	    "AN info  : 0x%02x\n"
34274294f337SSean Bruno 	    "Ext info : 0x%02x\n"
3428cb6b8299SEric Joyner 	    "Loopback : 0x%02x\n"
34294294f337SSean Bruno 	    "Max Frame: %d\n"
3430cb6b8299SEric Joyner 	    "Config   : 0x%02x\n"
3431cb6b8299SEric Joyner 	    "Power    : 0x%02x",
3432cb6b8299SEric Joyner 	    link_status.phy_type,
3433cb6b8299SEric Joyner 	    ixl_phy_type_string_ls(link_status.phy_type),
34344294f337SSean Bruno 	    link_status.link_speed,
3435cb6b8299SEric Joyner 	    link_status.link_info,
3436cb6b8299SEric Joyner 	    link_status.an_info,
3437cb6b8299SEric Joyner 	    link_status.ext_info,
3438cb6b8299SEric Joyner 	    link_status.loopback,
3439cb6b8299SEric Joyner 	    link_status.max_frame_size,
3440cb6b8299SEric Joyner 	    link_status.config,
3441cb6b8299SEric Joyner 	    link_status.power_desc);
34424294f337SSean Bruno 
34434294f337SSean Bruno 	error = sbuf_finish(buf);
34444294f337SSean Bruno 	if (error)
34454294f337SSean Bruno 		device_printf(dev, "Error finishing sbuf: %d\n", error);
34464294f337SSean Bruno 
34474294f337SSean Bruno 	sbuf_delete(buf);
34484294f337SSean Bruno 	return (error);
34494294f337SSean Bruno }
34504294f337SSean Bruno 
34514294f337SSean Bruno static int
ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)34524294f337SSean Bruno ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)
34534294f337SSean Bruno {
34544294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
34554294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
34564294f337SSean Bruno 	device_t dev = pf->dev;
34574294f337SSean Bruno 	enum i40e_status_code status;
34584294f337SSean Bruno 	struct i40e_aq_get_phy_abilities_resp abilities;
34594294f337SSean Bruno 	struct sbuf *buf;
34604294f337SSean Bruno 	int error = 0;
34614294f337SSean Bruno 
34624294f337SSean Bruno 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
34634294f337SSean Bruno 	if (!buf) {
34644294f337SSean Bruno 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
34654294f337SSean Bruno 		return (ENOMEM);
34664294f337SSean Bruno 	}
34674294f337SSean Bruno 
34684294f337SSean Bruno 	status = i40e_aq_get_phy_capabilities(hw,
346921802a12SKrzysztof Galazka 	    FALSE, arg2 != 0, &abilities, NULL);
34704294f337SSean Bruno 	if (status) {
34714294f337SSean Bruno 		device_printf(dev,
34724294f337SSean Bruno 		    "%s: i40e_aq_get_phy_capabilities() status %s, aq error %s\n",
34734294f337SSean Bruno 		    __func__, i40e_stat_str(hw, status),
34744294f337SSean Bruno 		    i40e_aq_str(hw, hw->aq.asq_last_status));
34754294f337SSean Bruno 		sbuf_delete(buf);
34764294f337SSean Bruno 		return (EIO);
34774294f337SSean Bruno 	}
34784294f337SSean Bruno 
34794294f337SSean Bruno 	sbuf_printf(buf, "\n"
34804294f337SSean Bruno 	    "PHY Type : %08x",
34814294f337SSean Bruno 	    abilities.phy_type);
34824294f337SSean Bruno 
34834294f337SSean Bruno 	if (abilities.phy_type != 0) {
34844294f337SSean Bruno 		sbuf_printf(buf, "<");
34854294f337SSean Bruno 		for (int i = 0; i < 32; i++)
34864294f337SSean Bruno 			if ((1 << i) & abilities.phy_type)
3487cb6b8299SEric Joyner 				sbuf_printf(buf, "%s,", ixl_phy_type_string(i, false));
3488b4a7ce06SEric Joyner 		sbuf_printf(buf, ">");
34894294f337SSean Bruno 	}
34904294f337SSean Bruno 
3491b4a7ce06SEric Joyner 	sbuf_printf(buf, "\nPHY Ext  : %02x",
3492cb6b8299SEric Joyner 	    abilities.phy_type_ext);
3493cb6b8299SEric Joyner 
3494cb6b8299SEric Joyner 	if (abilities.phy_type_ext != 0) {
3495cb6b8299SEric Joyner 		sbuf_printf(buf, "<");
3496cb6b8299SEric Joyner 		for (int i = 0; i < 4; i++)
3497cb6b8299SEric Joyner 			if ((1 << i) & abilities.phy_type_ext)
3498b4a7ce06SEric Joyner 				sbuf_printf(buf, "%s,",
3499b4a7ce06SEric Joyner 				    ixl_phy_type_string(i, true));
3500cb6b8299SEric Joyner 		sbuf_printf(buf, ">");
3501cb6b8299SEric Joyner 	}
3502cb6b8299SEric Joyner 
3503b4a7ce06SEric Joyner 	sbuf_printf(buf, "\nSpeed    : %02x", abilities.link_speed);
3504b4a7ce06SEric Joyner 	if (abilities.link_speed != 0) {
3505b4a7ce06SEric Joyner 		u8 link_speed;
3506b4a7ce06SEric Joyner 		sbuf_printf(buf, " <");
3507b4a7ce06SEric Joyner 		for (int i = 0; i < 8; i++) {
3508b4a7ce06SEric Joyner 			link_speed = (1 << i) & abilities.link_speed;
3509b4a7ce06SEric Joyner 			if (link_speed)
3510b4a7ce06SEric Joyner 				sbuf_printf(buf, "%s, ",
3511b4a7ce06SEric Joyner 				    ixl_link_speed_string(link_speed));
3512b4a7ce06SEric Joyner 		}
3513b4a7ce06SEric Joyner 		sbuf_printf(buf, ">");
3514b4a7ce06SEric Joyner 	}
3515b4a7ce06SEric Joyner 
3516b4a7ce06SEric Joyner 	sbuf_printf(buf, "\n"
35174294f337SSean Bruno 	    "Abilities: %02x\n"
35184294f337SSean Bruno 	    "EEE cap  : %04x\n"
35194294f337SSean Bruno 	    "EEER reg : %08x\n"
35204294f337SSean Bruno 	    "D3 Lpan  : %02x\n"
35214294f337SSean Bruno 	    "ID       : %02x %02x %02x %02x\n"
3522cb6b8299SEric Joyner 	    "ModType  : %02x %02x %02x\n"
3523cb6b8299SEric Joyner 	    "ModType E: %01x\n"
3524cb6b8299SEric Joyner 	    "FEC Cfg  : %02x\n"
3525cb6b8299SEric Joyner 	    "Ext CC   : %02x",
35264294f337SSean Bruno 	    abilities.abilities, abilities.eee_capability,
35274294f337SSean Bruno 	    abilities.eeer_val, abilities.d3_lpan,
35284294f337SSean Bruno 	    abilities.phy_id[0], abilities.phy_id[1],
35294294f337SSean Bruno 	    abilities.phy_id[2], abilities.phy_id[3],
35304294f337SSean Bruno 	    abilities.module_type[0], abilities.module_type[1],
3531ceebc2f3SEric Joyner 	    abilities.module_type[2], (abilities.fec_cfg_curr_mod_ext_info & 0xe0) >> 5,
3532ceebc2f3SEric Joyner 	    abilities.fec_cfg_curr_mod_ext_info & 0x1F,
3533cb6b8299SEric Joyner 	    abilities.ext_comp_code);
35344294f337SSean Bruno 
35354294f337SSean Bruno 	error = sbuf_finish(buf);
35364294f337SSean Bruno 	if (error)
35374294f337SSean Bruno 		device_printf(dev, "Error finishing sbuf: %d\n", error);
35384294f337SSean Bruno 
35394294f337SSean Bruno 	sbuf_delete(buf);
35404294f337SSean Bruno 	return (error);
35414294f337SSean Bruno }
35424294f337SSean Bruno 
35434294f337SSean Bruno static int
ixl_sysctl_phy_statistics(SYSCTL_HANDLER_ARGS)3544a146207dSPiotr Kubaj ixl_sysctl_phy_statistics(SYSCTL_HANDLER_ARGS)
3545a146207dSPiotr Kubaj {
3546a146207dSPiotr Kubaj 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
3547a146207dSPiotr Kubaj 	struct i40e_hw *hw = &pf->hw;
3548a146207dSPiotr Kubaj 	device_t dev = pf->dev;
3549a146207dSPiotr Kubaj 	struct sbuf *buf;
3550a146207dSPiotr Kubaj 	int error = 0;
3551a146207dSPiotr Kubaj 
3552a146207dSPiotr Kubaj 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
3553a146207dSPiotr Kubaj 	if (buf == NULL) {
3554a146207dSPiotr Kubaj 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
3555a146207dSPiotr Kubaj 		return (ENOMEM);
3556a146207dSPiotr Kubaj 	}
3557a146207dSPiotr Kubaj 
3558a146207dSPiotr Kubaj 	if (hw->mac.type == I40E_MAC_X722) {
3559a146207dSPiotr Kubaj 		sbuf_printf(buf, "\n"
3560a146207dSPiotr Kubaj 		    "PCS Link Control Register:                          unavailable\n"
3561a146207dSPiotr Kubaj 		    "PCS Link Status 1:                                  unavailable\n"
3562a146207dSPiotr Kubaj 		    "PCS Link Status 2:                                  unavailable\n"
3563a146207dSPiotr Kubaj 		    "XGMII FIFO Status:                                  unavailable\n"
3564a146207dSPiotr Kubaj 		    "Auto-Negotiation (AN) Status:                       unavailable\n"
3565a146207dSPiotr Kubaj 		    "KR PCS Status:                                      unavailable\n"
3566a146207dSPiotr Kubaj 		    "KR FEC Status 1 – FEC Correctable Blocks Counter:   unavailable\n"
3567a146207dSPiotr Kubaj 		    "KR FEC Status 2 – FEC Uncorrectable Blocks Counter: unavailable"
3568a146207dSPiotr Kubaj 		);
3569a146207dSPiotr Kubaj 	} else {
3570a146207dSPiotr Kubaj 		sbuf_printf(buf, "\n"
3571a146207dSPiotr Kubaj 		    "PCS Link Control Register:                          %#010X\n"
3572a146207dSPiotr Kubaj 		    "PCS Link Status 1:                                  %#010X\n"
3573a146207dSPiotr Kubaj 		    "PCS Link Status 2:                                  %#010X\n"
3574a146207dSPiotr Kubaj 		    "XGMII FIFO Status:                                  %#010X\n"
3575a146207dSPiotr Kubaj 		    "Auto-Negotiation (AN) Status:                       %#010X\n"
3576a146207dSPiotr Kubaj 		    "KR PCS Status:                                      %#010X\n"
3577a146207dSPiotr Kubaj 		    "KR FEC Status 1 – FEC Correctable Blocks Counter:   %#010X\n"
3578a146207dSPiotr Kubaj 		    "KR FEC Status 2 – FEC Uncorrectable Blocks Counter: %#010X",
3579a146207dSPiotr Kubaj 		    rd32(hw, I40E_PRTMAC_PCS_LINK_CTRL),
3580a146207dSPiotr Kubaj 		    rd32(hw, I40E_PRTMAC_PCS_LINK_STATUS1(0)),
3581a146207dSPiotr Kubaj 		    rd32(hw, I40E_PRTMAC_PCS_LINK_STATUS2),
3582a146207dSPiotr Kubaj 		    rd32(hw, I40E_PRTMAC_PCS_XGMII_FIFO_STATUS),
3583a146207dSPiotr Kubaj 		    rd32(hw, I40E_PRTMAC_PCS_AN_LP_STATUS),
3584a146207dSPiotr Kubaj 		    rd32(hw, I40E_PRTMAC_PCS_KR_STATUS),
3585a146207dSPiotr Kubaj 		    rd32(hw, I40E_PRTMAC_PCS_FEC_KR_STATUS1),
3586a146207dSPiotr Kubaj 		    rd32(hw, I40E_PRTMAC_PCS_FEC_KR_STATUS2)
3587a146207dSPiotr Kubaj 		);
3588a146207dSPiotr Kubaj 	}
3589a146207dSPiotr Kubaj 
3590a146207dSPiotr Kubaj 	error = sbuf_finish(buf);
3591a146207dSPiotr Kubaj 	if (error)
3592a146207dSPiotr Kubaj 		device_printf(dev, "Error finishing sbuf: %d\n", error);
3593a146207dSPiotr Kubaj 
3594a146207dSPiotr Kubaj 	sbuf_delete(buf);
3595a146207dSPiotr Kubaj 	return (error);
3596a146207dSPiotr Kubaj }
3597a146207dSPiotr Kubaj 
3598a146207dSPiotr Kubaj static int
ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)35994294f337SSean Bruno ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
36004294f337SSean Bruno {
36014294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
36024294f337SSean Bruno 	struct ixl_vsi *vsi = &pf->vsi;
36034294f337SSean Bruno 	struct ixl_mac_filter *f;
360477c1fcecSEric Joyner 	device_t dev = pf->dev;
360577c1fcecSEric Joyner 	int error = 0, ftl_len = 0, ftl_counter = 0;
36064294f337SSean Bruno 
360777c1fcecSEric Joyner 	struct sbuf *buf;
36084294f337SSean Bruno 
360977c1fcecSEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
361077c1fcecSEric Joyner 	if (!buf) {
3611b4a7ce06SEric Joyner 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
361277c1fcecSEric Joyner 		return (ENOMEM);
361377c1fcecSEric Joyner 	}
361477c1fcecSEric Joyner 
361577c1fcecSEric Joyner 	sbuf_printf(buf, "\n");
361677c1fcecSEric Joyner 
361777c1fcecSEric Joyner 	/* Print MAC filters */
361877c1fcecSEric Joyner 	sbuf_printf(buf, "PF Filters:\n");
36197d4dceecSKrzysztof Galazka 	LIST_FOREACH(f, &vsi->ftl, ftle)
36204294f337SSean Bruno 		ftl_len++;
36214294f337SSean Bruno 
362277c1fcecSEric Joyner 	if (ftl_len < 1)
362377c1fcecSEric Joyner 		sbuf_printf(buf, "(none)\n");
362477c1fcecSEric Joyner 	else {
36257d4dceecSKrzysztof Galazka 		LIST_FOREACH(f, &vsi->ftl, ftle) {
362677c1fcecSEric Joyner 			sbuf_printf(buf,
36274294f337SSean Bruno 			    MAC_FORMAT ", vlan %4d, flags %#06x",
36284294f337SSean Bruno 			    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
36294294f337SSean Bruno 			/* don't print '\n' for last entry */
363077c1fcecSEric Joyner 			if (++ftl_counter != ftl_len)
363177c1fcecSEric Joyner 				sbuf_printf(buf, "\n");
36324294f337SSean Bruno 		}
36334294f337SSean Bruno 	}
36344294f337SSean Bruno 
363577c1fcecSEric Joyner #ifdef PCI_IOV
363677c1fcecSEric Joyner 	/* TODO: Give each VF its own filter list sysctl */
363777c1fcecSEric Joyner 	struct ixl_vf *vf;
363877c1fcecSEric Joyner 	if (pf->num_vfs > 0) {
363977c1fcecSEric Joyner 		sbuf_printf(buf, "\n\n");
364077c1fcecSEric Joyner 		for (int i = 0; i < pf->num_vfs; i++) {
364177c1fcecSEric Joyner 			vf = &pf->vfs[i];
364277c1fcecSEric Joyner 			if (!(vf->vf_flags & VF_FLAG_ENABLED))
364377c1fcecSEric Joyner 				continue;
364477c1fcecSEric Joyner 
364577c1fcecSEric Joyner 			vsi = &vf->vsi;
364677c1fcecSEric Joyner 			ftl_len = 0, ftl_counter = 0;
364777c1fcecSEric Joyner 			sbuf_printf(buf, "VF-%d Filters:\n", vf->vf_num);
36487d4dceecSKrzysztof Galazka 			LIST_FOREACH(f, &vsi->ftl, ftle)
364977c1fcecSEric Joyner 				ftl_len++;
365077c1fcecSEric Joyner 
365177c1fcecSEric Joyner 			if (ftl_len < 1)
365277c1fcecSEric Joyner 				sbuf_printf(buf, "(none)\n");
365377c1fcecSEric Joyner 			else {
36547d4dceecSKrzysztof Galazka 				LIST_FOREACH(f, &vsi->ftl, ftle) {
365577c1fcecSEric Joyner 					sbuf_printf(buf,
365677c1fcecSEric Joyner 					    MAC_FORMAT ", vlan %4d, flags %#06x\n",
365777c1fcecSEric Joyner 					    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
365877c1fcecSEric Joyner 				}
365977c1fcecSEric Joyner 			}
366077c1fcecSEric Joyner 		}
366177c1fcecSEric Joyner 	}
366277c1fcecSEric Joyner #endif
366377c1fcecSEric Joyner 
366477c1fcecSEric Joyner 	error = sbuf_finish(buf);
36654294f337SSean Bruno 	if (error)
366677c1fcecSEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
366777c1fcecSEric Joyner 	sbuf_delete(buf);
366877c1fcecSEric Joyner 
366977c1fcecSEric Joyner 	return (error);
36704294f337SSean Bruno }
36714294f337SSean Bruno 
36724294f337SSean Bruno #define IXL_SW_RES_SIZE 0x14
36734294f337SSean Bruno int
ixl_res_alloc_cmp(const void * a,const void * b)36744294f337SSean Bruno ixl_res_alloc_cmp(const void *a, const void *b)
36754294f337SSean Bruno {
36764294f337SSean Bruno 	const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two;
36774294f337SSean Bruno 	one = (const struct i40e_aqc_switch_resource_alloc_element_resp *)a;
36784294f337SSean Bruno 	two = (const struct i40e_aqc_switch_resource_alloc_element_resp *)b;
36794294f337SSean Bruno 
36804294f337SSean Bruno 	return ((int)one->resource_type - (int)two->resource_type);
36814294f337SSean Bruno }
36824294f337SSean Bruno 
36834294f337SSean Bruno /*
36844294f337SSean Bruno  * Longest string length: 25
36854294f337SSean Bruno  */
3686b4a7ce06SEric Joyner const char *
ixl_switch_res_type_string(u8 type)36874294f337SSean Bruno ixl_switch_res_type_string(u8 type)
36884294f337SSean Bruno {
3689b4a7ce06SEric Joyner 	static const char * ixl_switch_res_type_strings[IXL_SW_RES_SIZE] = {
36904294f337SSean Bruno 		"VEB",
36914294f337SSean Bruno 		"VSI",
36924294f337SSean Bruno 		"Perfect Match MAC address",
36934294f337SSean Bruno 		"S-tag",
36944294f337SSean Bruno 		"(Reserved)",
36954294f337SSean Bruno 		"Multicast hash entry",
36964294f337SSean Bruno 		"Unicast hash entry",
36974294f337SSean Bruno 		"VLAN",
36984294f337SSean Bruno 		"VSI List entry",
36994294f337SSean Bruno 		"(Reserved)",
37004294f337SSean Bruno 		"VLAN Statistic Pool",
37014294f337SSean Bruno 		"Mirror Rule",
37024294f337SSean Bruno 		"Queue Set",
37034294f337SSean Bruno 		"Inner VLAN Forward filter",
37044294f337SSean Bruno 		"(Reserved)",
37054294f337SSean Bruno 		"Inner MAC",
37064294f337SSean Bruno 		"IP",
37074294f337SSean Bruno 		"GRE/VN1 Key",
37084294f337SSean Bruno 		"VN2 Key",
37094294f337SSean Bruno 		"Tunneling Port"
37104294f337SSean Bruno 	};
37114294f337SSean Bruno 
3712b4a7ce06SEric Joyner 	if (type < IXL_SW_RES_SIZE)
37134294f337SSean Bruno 		return ixl_switch_res_type_strings[type];
37144294f337SSean Bruno 	else
37154294f337SSean Bruno 		return "(Reserved)";
37164294f337SSean Bruno }
37174294f337SSean Bruno 
37184294f337SSean Bruno static int
ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)37194294f337SSean Bruno ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)
37204294f337SSean Bruno {
37214294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
37224294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
37234294f337SSean Bruno 	device_t dev = pf->dev;
37244294f337SSean Bruno 	struct sbuf *buf;
37254294f337SSean Bruno 	enum i40e_status_code status;
37264294f337SSean Bruno 	int error = 0;
37274294f337SSean Bruno 
37284294f337SSean Bruno 	u8 num_entries;
37294294f337SSean Bruno 	struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE];
37304294f337SSean Bruno 
37314294f337SSean Bruno 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
37324294f337SSean Bruno 	if (!buf) {
37334294f337SSean Bruno 		device_printf(dev, "Could not allocate sbuf for output.\n");
37344294f337SSean Bruno 		return (ENOMEM);
37354294f337SSean Bruno 	}
37364294f337SSean Bruno 
37374294f337SSean Bruno 	bzero(resp, sizeof(resp));
37384294f337SSean Bruno 	status = i40e_aq_get_switch_resource_alloc(hw, &num_entries,
37394294f337SSean Bruno 				resp,
37404294f337SSean Bruno 				IXL_SW_RES_SIZE,
37414294f337SSean Bruno 				NULL);
37424294f337SSean Bruno 	if (status) {
37434294f337SSean Bruno 		device_printf(dev,
37444294f337SSean Bruno 		    "%s: get_switch_resource_alloc() error %s, aq error %s\n",
37454294f337SSean Bruno 		    __func__, i40e_stat_str(hw, status),
37464294f337SSean Bruno 		    i40e_aq_str(hw, hw->aq.asq_last_status));
37474294f337SSean Bruno 		sbuf_delete(buf);
37484294f337SSean Bruno 		return (error);
37494294f337SSean Bruno 	}
37504294f337SSean Bruno 
37514294f337SSean Bruno 	/* Sort entries by type for display */
37524294f337SSean Bruno 	qsort(resp, num_entries,
37534294f337SSean Bruno 	    sizeof(struct i40e_aqc_switch_resource_alloc_element_resp),
37544294f337SSean Bruno 	    &ixl_res_alloc_cmp);
37554294f337SSean Bruno 
37564294f337SSean Bruno 	sbuf_cat(buf, "\n");
37574294f337SSean Bruno 	sbuf_printf(buf, "# of entries: %d\n", num_entries);
37584294f337SSean Bruno 	sbuf_printf(buf,
37594294f337SSean Bruno 	    "                     Type | Guaranteed | Total | Used   | Un-allocated\n"
37604294f337SSean Bruno 	    "                          | (this)     | (all) | (this) | (all)       \n");
37614294f337SSean Bruno 	for (int i = 0; i < num_entries; i++) {
37624294f337SSean Bruno 		sbuf_printf(buf,
37634294f337SSean Bruno 		    "%25s | %10d   %5d   %6d   %12d",
37644294f337SSean Bruno 		    ixl_switch_res_type_string(resp[i].resource_type),
37654294f337SSean Bruno 		    resp[i].guaranteed,
37664294f337SSean Bruno 		    resp[i].total,
37674294f337SSean Bruno 		    resp[i].used,
37684294f337SSean Bruno 		    resp[i].total_unalloced);
37694294f337SSean Bruno 		if (i < num_entries - 1)
37704294f337SSean Bruno 			sbuf_cat(buf, "\n");
37714294f337SSean Bruno 	}
37724294f337SSean Bruno 
37734294f337SSean Bruno 	error = sbuf_finish(buf);
37744294f337SSean Bruno 	if (error)
37754294f337SSean Bruno 		device_printf(dev, "Error finishing sbuf: %d\n", error);
37764294f337SSean Bruno 
37774294f337SSean Bruno 	sbuf_delete(buf);
37784294f337SSean Bruno 	return (error);
37794294f337SSean Bruno }
37804294f337SSean Bruno 
3781b4a7ce06SEric Joyner enum ixl_sw_seid_offset {
3782b4a7ce06SEric Joyner 	IXL_SW_SEID_EMP = 1,
3783b4a7ce06SEric Joyner 	IXL_SW_SEID_MAC_START = 2,
3784b4a7ce06SEric Joyner 	IXL_SW_SEID_MAC_END = 5,
3785b4a7ce06SEric Joyner 	IXL_SW_SEID_PF_START = 16,
3786b4a7ce06SEric Joyner 	IXL_SW_SEID_PF_END = 31,
3787b4a7ce06SEric Joyner 	IXL_SW_SEID_VF_START = 32,
3788b4a7ce06SEric Joyner 	IXL_SW_SEID_VF_END = 159,
3789b4a7ce06SEric Joyner };
3790b4a7ce06SEric Joyner 
37914294f337SSean Bruno /*
3792b4a7ce06SEric Joyner  * Caller must init and delete sbuf; this function will clear and
3793b4a7ce06SEric Joyner  * finish it for caller.
3794b4a7ce06SEric Joyner  *
3795b4a7ce06SEric Joyner  * Note: The SEID argument only applies for elements defined by FW at
3796b4a7ce06SEric Joyner  * power-on; these include the EMP, Ports, PFs and VFs.
37974294f337SSean Bruno  */
3798b4a7ce06SEric Joyner static char *
ixl_switch_element_string(struct sbuf * s,u8 element_type,u16 seid)3799b4a7ce06SEric Joyner ixl_switch_element_string(struct sbuf *s, u8 element_type, u16 seid)
38004294f337SSean Bruno {
38014294f337SSean Bruno 	sbuf_clear(s);
38024294f337SSean Bruno 
3803b4a7ce06SEric Joyner 	/* If SEID is in certain ranges, then we can infer the
3804b4a7ce06SEric Joyner 	 * mapping of SEID to switch element.
3805b4a7ce06SEric Joyner 	 */
3806b4a7ce06SEric Joyner 	if (seid == IXL_SW_SEID_EMP) {
38074294f337SSean Bruno 		sbuf_cat(s, "EMP");
3808b4a7ce06SEric Joyner 		goto out;
3809b4a7ce06SEric Joyner 	} else if (seid >= IXL_SW_SEID_MAC_START &&
3810b4a7ce06SEric Joyner 	    seid <= IXL_SW_SEID_MAC_END) {
3811b4a7ce06SEric Joyner 		sbuf_printf(s, "MAC  %2d",
3812b4a7ce06SEric Joyner 		    seid - IXL_SW_SEID_MAC_START);
3813b4a7ce06SEric Joyner 		goto out;
3814b4a7ce06SEric Joyner 	} else if (seid >= IXL_SW_SEID_PF_START &&
3815b4a7ce06SEric Joyner 	    seid <= IXL_SW_SEID_PF_END) {
3816b4a7ce06SEric Joyner 		sbuf_printf(s, "PF  %3d",
3817b4a7ce06SEric Joyner 		    seid - IXL_SW_SEID_PF_START);
3818b4a7ce06SEric Joyner 		goto out;
3819b4a7ce06SEric Joyner 	} else if (seid >= IXL_SW_SEID_VF_START &&
3820b4a7ce06SEric Joyner 	    seid <= IXL_SW_SEID_VF_END) {
3821b4a7ce06SEric Joyner 		sbuf_printf(s, "VF  %3d",
3822b4a7ce06SEric Joyner 		    seid - IXL_SW_SEID_VF_START);
3823b4a7ce06SEric Joyner 		goto out;
3824b4a7ce06SEric Joyner 	}
3825b4a7ce06SEric Joyner 
3826b4a7ce06SEric Joyner 	switch (element_type) {
38274294f337SSean Bruno 	case I40E_AQ_SW_ELEM_TYPE_BMC:
38284294f337SSean Bruno 		sbuf_cat(s, "BMC");
38294294f337SSean Bruno 		break;
38304294f337SSean Bruno 	case I40E_AQ_SW_ELEM_TYPE_PV:
38314294f337SSean Bruno 		sbuf_cat(s, "PV");
38324294f337SSean Bruno 		break;
38334294f337SSean Bruno 	case I40E_AQ_SW_ELEM_TYPE_VEB:
38344294f337SSean Bruno 		sbuf_cat(s, "VEB");
38354294f337SSean Bruno 		break;
38364294f337SSean Bruno 	case I40E_AQ_SW_ELEM_TYPE_PA:
38374294f337SSean Bruno 		sbuf_cat(s, "PA");
38384294f337SSean Bruno 		break;
38394294f337SSean Bruno 	case I40E_AQ_SW_ELEM_TYPE_VSI:
3840b4a7ce06SEric Joyner 		sbuf_printf(s, "VSI");
38414294f337SSean Bruno 		break;
38424294f337SSean Bruno 	default:
38434294f337SSean Bruno 		sbuf_cat(s, "?");
38444294f337SSean Bruno 		break;
38454294f337SSean Bruno 	}
38464294f337SSean Bruno 
3847b4a7ce06SEric Joyner out:
38484294f337SSean Bruno 	sbuf_finish(s);
38494294f337SSean Bruno 	return sbuf_data(s);
38504294f337SSean Bruno }
38514294f337SSean Bruno 
38524294f337SSean Bruno static int
ixl_sw_cfg_elem_seid_cmp(const void * a,const void * b)3853b4a7ce06SEric Joyner ixl_sw_cfg_elem_seid_cmp(const void *a, const void *b)
3854b4a7ce06SEric Joyner {
3855b4a7ce06SEric Joyner 	const struct i40e_aqc_switch_config_element_resp *one, *two;
3856b4a7ce06SEric Joyner 	one = (const struct i40e_aqc_switch_config_element_resp *)a;
3857b4a7ce06SEric Joyner 	two = (const struct i40e_aqc_switch_config_element_resp *)b;
3858b4a7ce06SEric Joyner 
3859b4a7ce06SEric Joyner 	return ((int)one->seid - (int)two->seid);
3860b4a7ce06SEric Joyner }
3861b4a7ce06SEric Joyner 
3862b4a7ce06SEric Joyner static int
ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS)38634294f337SSean Bruno ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS)
38644294f337SSean Bruno {
38654294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
38664294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
38674294f337SSean Bruno 	device_t dev = pf->dev;
38684294f337SSean Bruno 	struct sbuf *buf;
38694294f337SSean Bruno 	struct sbuf *nmbuf;
38704294f337SSean Bruno 	enum i40e_status_code status;
38714294f337SSean Bruno 	int error = 0;
38724294f337SSean Bruno 	u16 next = 0;
38734294f337SSean Bruno 	u8 aq_buf[I40E_AQ_LARGE_BUF];
38744294f337SSean Bruno 
3875b4a7ce06SEric Joyner 	struct i40e_aqc_switch_config_element_resp *elem;
38764294f337SSean Bruno 	struct i40e_aqc_get_switch_config_resp *sw_config;
38774294f337SSean Bruno 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
38784294f337SSean Bruno 
38794294f337SSean Bruno 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
38804294f337SSean Bruno 	if (!buf) {
38814294f337SSean Bruno 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
38824294f337SSean Bruno 		return (ENOMEM);
38834294f337SSean Bruno 	}
38844294f337SSean Bruno 
38854294f337SSean Bruno 	status = i40e_aq_get_switch_config(hw, sw_config,
38864294f337SSean Bruno 	    sizeof(aq_buf), &next, NULL);
38874294f337SSean Bruno 	if (status) {
38884294f337SSean Bruno 		device_printf(dev,
38894294f337SSean Bruno 		    "%s: aq_get_switch_config() error %s, aq error %s\n",
38904294f337SSean Bruno 		    __func__, i40e_stat_str(hw, status),
38914294f337SSean Bruno 		    i40e_aq_str(hw, hw->aq.asq_last_status));
38924294f337SSean Bruno 		sbuf_delete(buf);
38934294f337SSean Bruno 		return error;
38944294f337SSean Bruno 	}
38954294f337SSean Bruno 	if (next)
38964294f337SSean Bruno 		device_printf(dev, "%s: TODO: get more config with SEID %d\n",
38974294f337SSean Bruno 		    __func__, next);
38984294f337SSean Bruno 
38994294f337SSean Bruno 	nmbuf = sbuf_new_auto();
39004294f337SSean Bruno 	if (!nmbuf) {
39014294f337SSean Bruno 		device_printf(dev, "Could not allocate sbuf for name output.\n");
39024294f337SSean Bruno 		sbuf_delete(buf);
39034294f337SSean Bruno 		return (ENOMEM);
39044294f337SSean Bruno 	}
39054294f337SSean Bruno 
3906b4a7ce06SEric Joyner 	/* Sort entries by SEID for display */
3907b4a7ce06SEric Joyner 	qsort(sw_config->element, sw_config->header.num_reported,
3908b4a7ce06SEric Joyner 	    sizeof(struct i40e_aqc_switch_config_element_resp),
3909b4a7ce06SEric Joyner 	    &ixl_sw_cfg_elem_seid_cmp);
3910b4a7ce06SEric Joyner 
39114294f337SSean Bruno 	sbuf_cat(buf, "\n");
39124294f337SSean Bruno 	/* Assuming <= 255 elements in switch */
39134294f337SSean Bruno 	sbuf_printf(buf, "# of reported elements: %d\n", sw_config->header.num_reported);
39144294f337SSean Bruno 	sbuf_printf(buf, "total # of elements: %d\n", sw_config->header.num_total);
39154294f337SSean Bruno 	/* Exclude:
3916b4a7ce06SEric Joyner 	 * Revision -- all elements are revision 1 for now
39174294f337SSean Bruno 	 */
39184294f337SSean Bruno 	sbuf_printf(buf,
3919b4a7ce06SEric Joyner 	    "SEID (  Name  ) |  Up  (  Name  ) | Down (  Name  ) | Conn Type\n"
39204294f337SSean Bruno 	    "                |                 |                 | (uplink)\n");
39214294f337SSean Bruno 	for (int i = 0; i < sw_config->header.num_reported; i++) {
3922b4a7ce06SEric Joyner 		elem = &sw_config->element[i];
3923b4a7ce06SEric Joyner 
39244294f337SSean Bruno 		// "%4d (%8s) | %8s   %8s   %#8x",
3925b4a7ce06SEric Joyner 		sbuf_printf(buf, "%4d", elem->seid);
39264294f337SSean Bruno 		sbuf_cat(buf, " ");
39274294f337SSean Bruno 		sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf,
3928b4a7ce06SEric Joyner 		    elem->element_type, elem->seid));
39294294f337SSean Bruno 		sbuf_cat(buf, " | ");
3930b4a7ce06SEric Joyner 		sbuf_printf(buf, "%4d", elem->uplink_seid);
39314294f337SSean Bruno 		sbuf_cat(buf, " ");
3932b4a7ce06SEric Joyner 		sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf,
3933b4a7ce06SEric Joyner 		    0, elem->uplink_seid));
3934b4a7ce06SEric Joyner 		sbuf_cat(buf, " | ");
3935b4a7ce06SEric Joyner 		sbuf_printf(buf, "%4d", elem->downlink_seid);
39364294f337SSean Bruno 		sbuf_cat(buf, " ");
3937b4a7ce06SEric Joyner 		sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf,
3938b4a7ce06SEric Joyner 		    0, elem->downlink_seid));
3939b4a7ce06SEric Joyner 		sbuf_cat(buf, " | ");
3940b4a7ce06SEric Joyner 		sbuf_printf(buf, "%8d", elem->connection_type);
39414294f337SSean Bruno 		if (i < sw_config->header.num_reported - 1)
39424294f337SSean Bruno 			sbuf_cat(buf, "\n");
39434294f337SSean Bruno 	}
39444294f337SSean Bruno 	sbuf_delete(nmbuf);
39454294f337SSean Bruno 
39464294f337SSean Bruno 	error = sbuf_finish(buf);
39474294f337SSean Bruno 	if (error)
39484294f337SSean Bruno 		device_printf(dev, "Error finishing sbuf: %d\n", error);
39494294f337SSean Bruno 
39504294f337SSean Bruno 	sbuf_delete(buf);
39514294f337SSean Bruno 
39524294f337SSean Bruno 	return (error);
39534294f337SSean Bruno }
39544294f337SSean Bruno 
39554294f337SSean Bruno static int
ixl_sysctl_switch_vlans(SYSCTL_HANDLER_ARGS)3956fa6662b3SLutz Donnerhacke ixl_sysctl_switch_vlans(SYSCTL_HANDLER_ARGS)
3957fa6662b3SLutz Donnerhacke {
3958fa6662b3SLutz Donnerhacke 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
3959fa6662b3SLutz Donnerhacke 	struct i40e_hw *hw = &pf->hw;
3960fa6662b3SLutz Donnerhacke 	device_t dev = pf->dev;
3961fa6662b3SLutz Donnerhacke 	int requested_vlan = -1;
3962fa6662b3SLutz Donnerhacke 	enum i40e_status_code status = 0;
3963fa6662b3SLutz Donnerhacke 	int error = 0;
3964fa6662b3SLutz Donnerhacke 
3965fa6662b3SLutz Donnerhacke 	error = sysctl_handle_int(oidp, &requested_vlan, 0, req);
3966fa6662b3SLutz Donnerhacke 	if ((error) || (req->newptr == NULL))
3967fa6662b3SLutz Donnerhacke 	    return (error);
3968fa6662b3SLutz Donnerhacke 
3969fa6662b3SLutz Donnerhacke 	if ((hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) == 0) {
3970fa6662b3SLutz Donnerhacke 		device_printf(dev, "Flags disallow setting of vlans\n");
3971fa6662b3SLutz Donnerhacke 		return (ENODEV);
3972fa6662b3SLutz Donnerhacke 	}
3973fa6662b3SLutz Donnerhacke 
3974fa6662b3SLutz Donnerhacke 	hw->switch_tag = requested_vlan;
3975fa6662b3SLutz Donnerhacke 	device_printf(dev,
3976fa6662b3SLutz Donnerhacke 	    "Setting switch config to switch_tag=%04x, first_tag=%04x, second_tag=%04x\n",
3977fa6662b3SLutz Donnerhacke 	    hw->switch_tag, hw->first_tag, hw->second_tag);
3978fa6662b3SLutz Donnerhacke 	status = i40e_aq_set_switch_config(hw, 0, 0, 0, NULL);
3979fa6662b3SLutz Donnerhacke 	if (status) {
3980fa6662b3SLutz Donnerhacke 		device_printf(dev,
3981fa6662b3SLutz Donnerhacke 		    "%s: aq_set_switch_config() error %s, aq error %s\n",
3982fa6662b3SLutz Donnerhacke 		    __func__, i40e_stat_str(hw, status),
3983fa6662b3SLutz Donnerhacke 		    i40e_aq_str(hw, hw->aq.asq_last_status));
3984fa6662b3SLutz Donnerhacke 		return (status);
3985fa6662b3SLutz Donnerhacke 	}
3986fa6662b3SLutz Donnerhacke 	return (0);
3987fa6662b3SLutz Donnerhacke }
3988fa6662b3SLutz Donnerhacke 
3989fa6662b3SLutz Donnerhacke static int
ixl_sysctl_hkey(SYSCTL_HANDLER_ARGS)39904294f337SSean Bruno ixl_sysctl_hkey(SYSCTL_HANDLER_ARGS)
39914294f337SSean Bruno {
39924294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
39934294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
39944294f337SSean Bruno 	device_t dev = pf->dev;
39954294f337SSean Bruno 	struct sbuf *buf;
39964294f337SSean Bruno 	int error = 0;
39974294f337SSean Bruno 	enum i40e_status_code status;
39984294f337SSean Bruno 	u32 reg;
39994294f337SSean Bruno 
40004294f337SSean Bruno 	struct i40e_aqc_get_set_rss_key_data key_data;
40014294f337SSean Bruno 
40024294f337SSean Bruno 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
40034294f337SSean Bruno 	if (!buf) {
40044294f337SSean Bruno 		device_printf(dev, "Could not allocate sbuf for output.\n");
40054294f337SSean Bruno 		return (ENOMEM);
40064294f337SSean Bruno 	}
40074294f337SSean Bruno 
4008b4a7ce06SEric Joyner 	bzero(&key_data, sizeof(key_data));
4009ceebc2f3SEric Joyner 
40104294f337SSean Bruno 	sbuf_cat(buf, "\n");
40114294f337SSean Bruno 	if (hw->mac.type == I40E_MAC_X722) {
40124294f337SSean Bruno 		status = i40e_aq_get_rss_key(hw, pf->vsi.vsi_num, &key_data);
40134294f337SSean Bruno 		if (status)
40144294f337SSean Bruno 			device_printf(dev, "i40e_aq_get_rss_key status %s, error %s\n",
40154294f337SSean Bruno 			    i40e_stat_str(hw, status), i40e_aq_str(hw, hw->aq.asq_last_status));
40164294f337SSean Bruno 	} else {
40174294f337SSean Bruno 		for (int i = 0; i < IXL_RSS_KEY_SIZE_REG; i++) {
40184294f337SSean Bruno 			reg = i40e_read_rx_ctl(hw, I40E_PFQF_HKEY(i));
4019ceebc2f3SEric Joyner 			bcopy(&reg, ((caddr_t)&key_data) + (i << 2), 4);
40204294f337SSean Bruno 		}
40214294f337SSean Bruno 	}
40224294f337SSean Bruno 
4023ceebc2f3SEric Joyner 	ixl_sbuf_print_bytes(buf, (u8 *)&key_data, sizeof(key_data), 0, true);
4024ceebc2f3SEric Joyner 
40254294f337SSean Bruno 	error = sbuf_finish(buf);
40264294f337SSean Bruno 	if (error)
40274294f337SSean Bruno 		device_printf(dev, "Error finishing sbuf: %d\n", error);
40284294f337SSean Bruno 	sbuf_delete(buf);
40294294f337SSean Bruno 
40304294f337SSean Bruno 	return (error);
40314294f337SSean Bruno }
40324294f337SSean Bruno 
4033ceebc2f3SEric Joyner static void
ixl_sbuf_print_bytes(struct sbuf * sb,u8 * buf,int length,int label_offset,bool text)4034ceebc2f3SEric Joyner ixl_sbuf_print_bytes(struct sbuf *sb, u8 *buf, int length, int label_offset, bool text)
4035ceebc2f3SEric Joyner {
4036ceebc2f3SEric Joyner 	int i, j, k, width;
4037ceebc2f3SEric Joyner 	char c;
4038ceebc2f3SEric Joyner 
4039ceebc2f3SEric Joyner 	if (length < 1 || buf == NULL) return;
4040ceebc2f3SEric Joyner 
4041ceebc2f3SEric Joyner 	int byte_stride = 16;
4042ceebc2f3SEric Joyner 	int lines = length / byte_stride;
4043ceebc2f3SEric Joyner 	int rem = length % byte_stride;
4044ceebc2f3SEric Joyner 	if (rem > 0)
4045ceebc2f3SEric Joyner 		lines++;
4046ceebc2f3SEric Joyner 
4047ceebc2f3SEric Joyner 	for (i = 0; i < lines; i++) {
4048ceebc2f3SEric Joyner 		width = (rem > 0 && i == lines - 1)
4049ceebc2f3SEric Joyner 		    ? rem : byte_stride;
4050ceebc2f3SEric Joyner 
4051ceebc2f3SEric Joyner 		sbuf_printf(sb, "%4d | ", label_offset + i * byte_stride);
4052ceebc2f3SEric Joyner 
4053ceebc2f3SEric Joyner 		for (j = 0; j < width; j++)
4054ceebc2f3SEric Joyner 			sbuf_printf(sb, "%02x ", buf[i * byte_stride + j]);
4055ceebc2f3SEric Joyner 
4056ceebc2f3SEric Joyner 		if (width < byte_stride) {
4057ceebc2f3SEric Joyner 			for (k = 0; k < (byte_stride - width); k++)
4058ceebc2f3SEric Joyner 				sbuf_printf(sb, "   ");
4059ceebc2f3SEric Joyner 		}
4060ceebc2f3SEric Joyner 
4061ceebc2f3SEric Joyner 		if (!text) {
4062ceebc2f3SEric Joyner 			sbuf_printf(sb, "\n");
4063ceebc2f3SEric Joyner 			continue;
4064ceebc2f3SEric Joyner 		}
4065ceebc2f3SEric Joyner 
4066ceebc2f3SEric Joyner 		for (j = 0; j < width; j++) {
4067ceebc2f3SEric Joyner 			c = (char)buf[i * byte_stride + j];
4068ceebc2f3SEric Joyner 			if (c < 32 || c > 126)
4069ceebc2f3SEric Joyner 				sbuf_printf(sb, ".");
4070ceebc2f3SEric Joyner 			else
4071ceebc2f3SEric Joyner 				sbuf_printf(sb, "%c", c);
4072ceebc2f3SEric Joyner 
4073ceebc2f3SEric Joyner 			if (j == width - 1)
4074ceebc2f3SEric Joyner 				sbuf_printf(sb, "\n");
4075ceebc2f3SEric Joyner 		}
4076ceebc2f3SEric Joyner 	}
4077ceebc2f3SEric Joyner }
4078ceebc2f3SEric Joyner 
40794294f337SSean Bruno static int
ixl_sysctl_hlut(SYSCTL_HANDLER_ARGS)40804294f337SSean Bruno ixl_sysctl_hlut(SYSCTL_HANDLER_ARGS)
40814294f337SSean Bruno {
40824294f337SSean Bruno 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
40834294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
40844294f337SSean Bruno 	device_t dev = pf->dev;
40854294f337SSean Bruno 	struct sbuf *buf;
40864294f337SSean Bruno 	int error = 0;
40874294f337SSean Bruno 	enum i40e_status_code status;
40884294f337SSean Bruno 	u8 hlut[512];
40894294f337SSean Bruno 	u32 reg;
40904294f337SSean Bruno 
40914294f337SSean Bruno 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
40924294f337SSean Bruno 	if (!buf) {
40934294f337SSean Bruno 		device_printf(dev, "Could not allocate sbuf for output.\n");
40944294f337SSean Bruno 		return (ENOMEM);
40954294f337SSean Bruno 	}
40964294f337SSean Bruno 
4097ceebc2f3SEric Joyner 	bzero(hlut, sizeof(hlut));
40984294f337SSean Bruno 	sbuf_cat(buf, "\n");
40994294f337SSean Bruno 	if (hw->mac.type == I40E_MAC_X722) {
41004294f337SSean Bruno 		status = i40e_aq_get_rss_lut(hw, pf->vsi.vsi_num, TRUE, hlut, sizeof(hlut));
41014294f337SSean Bruno 		if (status)
41024294f337SSean Bruno 			device_printf(dev, "i40e_aq_get_rss_lut status %s, error %s\n",
41034294f337SSean Bruno 			    i40e_stat_str(hw, status), i40e_aq_str(hw, hw->aq.asq_last_status));
41044294f337SSean Bruno 	} else {
41054294f337SSean Bruno 		for (int i = 0; i < hw->func_caps.rss_table_size >> 2; i++) {
41064294f337SSean Bruno 			reg = rd32(hw, I40E_PFQF_HLUT(i));
4107ceebc2f3SEric Joyner 			bcopy(&reg, &hlut[i << 2], 4);
41084294f337SSean Bruno 		}
41094294f337SSean Bruno 	}
4110ceebc2f3SEric Joyner 	ixl_sbuf_print_bytes(buf, hlut, 512, 0, false);
41114294f337SSean Bruno 
41124294f337SSean Bruno 	error = sbuf_finish(buf);
41134294f337SSean Bruno 	if (error)
41144294f337SSean Bruno 		device_printf(dev, "Error finishing sbuf: %d\n", error);
41154294f337SSean Bruno 	sbuf_delete(buf);
41164294f337SSean Bruno 
41174294f337SSean Bruno 	return (error);
41184294f337SSean Bruno }
41194294f337SSean Bruno 
4120cb6b8299SEric Joyner static int
ixl_sysctl_hena(SYSCTL_HANDLER_ARGS)4121cb6b8299SEric Joyner ixl_sysctl_hena(SYSCTL_HANDLER_ARGS)
4122cb6b8299SEric Joyner {
4123cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4124cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
4125cb6b8299SEric Joyner 	u64 hena;
4126cb6b8299SEric Joyner 
4127cb6b8299SEric Joyner 	hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) |
4128cb6b8299SEric Joyner 	    ((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32);
4129cb6b8299SEric Joyner 
4130cb6b8299SEric Joyner 	return sysctl_handle_long(oidp, NULL, hena, req);
4131cb6b8299SEric Joyner }
4132cb6b8299SEric Joyner 
4133cb6b8299SEric Joyner /*
4134cb6b8299SEric Joyner  * Sysctl to disable firmware's link management
4135cb6b8299SEric Joyner  *
4136cb6b8299SEric Joyner  * 1 - Disable link management on this port
4137cb6b8299SEric Joyner  * 0 - Re-enable link management
4138cb6b8299SEric Joyner  *
4139cb6b8299SEric Joyner  * On normal NVMs, firmware manages link by default.
4140cb6b8299SEric Joyner  */
4141cb6b8299SEric Joyner static int
ixl_sysctl_fw_link_management(SYSCTL_HANDLER_ARGS)4142cb6b8299SEric Joyner ixl_sysctl_fw_link_management(SYSCTL_HANDLER_ARGS)
4143cb6b8299SEric Joyner {
4144cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4145cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
4146cb6b8299SEric Joyner 	device_t dev = pf->dev;
4147cb6b8299SEric Joyner 	int requested_mode = -1;
4148cb6b8299SEric Joyner 	enum i40e_status_code status = 0;
4149cb6b8299SEric Joyner 	int error = 0;
4150cb6b8299SEric Joyner 
4151cb6b8299SEric Joyner 	/* Read in new mode */
4152cb6b8299SEric Joyner 	error = sysctl_handle_int(oidp, &requested_mode, 0, req);
4153cb6b8299SEric Joyner 	if ((error) || (req->newptr == NULL))
4154cb6b8299SEric Joyner 		return (error);
4155cb6b8299SEric Joyner 	/* Check for sane value */
4156cb6b8299SEric Joyner 	if (requested_mode < 0 || requested_mode > 1) {
4157cb6b8299SEric Joyner 		device_printf(dev, "Valid modes are 0 or 1\n");
4158cb6b8299SEric Joyner 		return (EINVAL);
4159cb6b8299SEric Joyner 	}
4160cb6b8299SEric Joyner 
4161cb6b8299SEric Joyner 	/* Set new mode */
4162cb6b8299SEric Joyner 	status = i40e_aq_set_phy_debug(hw, !!(requested_mode) << 4, NULL);
4163cb6b8299SEric Joyner 	if (status) {
4164cb6b8299SEric Joyner 		device_printf(dev,
4165cb6b8299SEric Joyner 		    "%s: Error setting new phy debug mode %s,"
4166cb6b8299SEric Joyner 		    " aq error: %s\n", __func__, i40e_stat_str(hw, status),
4167cb6b8299SEric Joyner 		    i40e_aq_str(hw, hw->aq.asq_last_status));
4168cb6b8299SEric Joyner 		return (EIO);
4169cb6b8299SEric Joyner 	}
4170cb6b8299SEric Joyner 
4171cb6b8299SEric Joyner 	return (0);
4172cb6b8299SEric Joyner }
4173cb6b8299SEric Joyner 
4174cb6b8299SEric Joyner /*
4175b4a7ce06SEric Joyner  * Read some diagnostic data from a (Q)SFP+ module
4176b4a7ce06SEric Joyner  *
4177b4a7ce06SEric Joyner  *             SFP A2   QSFP Lower Page
4178b4a7ce06SEric Joyner  * Temperature 96-97	22-23
4179b4a7ce06SEric Joyner  * Vcc         98-99    26-27
4180b4a7ce06SEric Joyner  * TX power    102-103  34-35..40-41
4181b4a7ce06SEric Joyner  * RX power    104-105  50-51..56-57
41821031d839SEric Joyner  */
41831031d839SEric Joyner static int
ixl_sysctl_read_i2c_diag_data(SYSCTL_HANDLER_ARGS)41841031d839SEric Joyner ixl_sysctl_read_i2c_diag_data(SYSCTL_HANDLER_ARGS)
41851031d839SEric Joyner {
41861031d839SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
41871031d839SEric Joyner 	device_t dev = pf->dev;
41881031d839SEric Joyner 	struct sbuf *sbuf;
41891031d839SEric Joyner 	int error = 0;
41901031d839SEric Joyner 	u8 output;
41911031d839SEric Joyner 
4192b4a7ce06SEric Joyner 	if (req->oldptr == NULL) {
4193b4a7ce06SEric Joyner 		error = SYSCTL_OUT(req, 0, 128);
4194b4a7ce06SEric Joyner 		return (0);
4195b4a7ce06SEric Joyner 	}
4196b4a7ce06SEric Joyner 
41971031d839SEric Joyner 	error = pf->read_i2c_byte(pf, 0, 0xA0, &output);
41981031d839SEric Joyner 	if (error) {
41991031d839SEric Joyner 		device_printf(dev, "Error reading from i2c\n");
42001031d839SEric Joyner 		return (error);
42011031d839SEric Joyner 	}
42021031d839SEric Joyner 
4203b4a7ce06SEric Joyner 	/* 0x3 for SFP; 0xD/0x11 for QSFP+/QSFP28 */
4204b4a7ce06SEric Joyner 	if (output == 0x3) {
4205b4a7ce06SEric Joyner 		/*
4206b4a7ce06SEric Joyner 		 * Check for:
4207b4a7ce06SEric Joyner 		 * - Internally calibrated data
4208b4a7ce06SEric Joyner 		 * - Diagnostic monitoring is implemented
4209b4a7ce06SEric Joyner 		 */
42101031d839SEric Joyner 		pf->read_i2c_byte(pf, 92, 0xA0, &output);
42111031d839SEric Joyner 		if (!(output & 0x60)) {
42121031d839SEric Joyner 			device_printf(dev, "Module doesn't support diagnostics: %02X\n", output);
4213b4a7ce06SEric Joyner 			return (0);
42141031d839SEric Joyner 		}
42151031d839SEric Joyner 
42161031d839SEric Joyner 		sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
42171031d839SEric Joyner 
42181031d839SEric Joyner 		for (u8 offset = 96; offset < 100; offset++) {
42191031d839SEric Joyner 			pf->read_i2c_byte(pf, offset, 0xA2, &output);
42201031d839SEric Joyner 			sbuf_printf(sbuf, "%02X ", output);
42211031d839SEric Joyner 		}
42221031d839SEric Joyner 		for (u8 offset = 102; offset < 106; offset++) {
42231031d839SEric Joyner 			pf->read_i2c_byte(pf, offset, 0xA2, &output);
42241031d839SEric Joyner 			sbuf_printf(sbuf, "%02X ", output);
42251031d839SEric Joyner 		}
4226b4a7ce06SEric Joyner 	} else if (output == 0xD || output == 0x11) {
4227b4a7ce06SEric Joyner 		/*
4228b4a7ce06SEric Joyner 		 * QSFP+ modules are always internally calibrated, and must indicate
4229b4a7ce06SEric Joyner 		 * what types of diagnostic monitoring are implemented
4230b4a7ce06SEric Joyner 		 */
4231b4a7ce06SEric Joyner 		sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4232b4a7ce06SEric Joyner 
4233b4a7ce06SEric Joyner 		for (u8 offset = 22; offset < 24; offset++) {
4234b4a7ce06SEric Joyner 			pf->read_i2c_byte(pf, offset, 0xA0, &output);
4235b4a7ce06SEric Joyner 			sbuf_printf(sbuf, "%02X ", output);
4236b4a7ce06SEric Joyner 		}
4237b4a7ce06SEric Joyner 		for (u8 offset = 26; offset < 28; offset++) {
4238b4a7ce06SEric Joyner 			pf->read_i2c_byte(pf, offset, 0xA0, &output);
4239b4a7ce06SEric Joyner 			sbuf_printf(sbuf, "%02X ", output);
4240b4a7ce06SEric Joyner 		}
4241b4a7ce06SEric Joyner 		/* Read the data from the first lane */
4242b4a7ce06SEric Joyner 		for (u8 offset = 34; offset < 36; offset++) {
4243b4a7ce06SEric Joyner 			pf->read_i2c_byte(pf, offset, 0xA0, &output);
4244b4a7ce06SEric Joyner 			sbuf_printf(sbuf, "%02X ", output);
4245b4a7ce06SEric Joyner 		}
4246b4a7ce06SEric Joyner 		for (u8 offset = 50; offset < 52; offset++) {
4247b4a7ce06SEric Joyner 			pf->read_i2c_byte(pf, offset, 0xA0, &output);
4248b4a7ce06SEric Joyner 			sbuf_printf(sbuf, "%02X ", output);
4249b4a7ce06SEric Joyner 		}
4250b4a7ce06SEric Joyner 	} else {
4251b4a7ce06SEric Joyner 		device_printf(dev, "Module is not SFP/SFP+/SFP28/QSFP+ (%02X)\n", output);
4252b4a7ce06SEric Joyner 		return (0);
4253b4a7ce06SEric Joyner 	}
42541031d839SEric Joyner 
42551031d839SEric Joyner 	sbuf_finish(sbuf);
42561031d839SEric Joyner 	sbuf_delete(sbuf);
42571031d839SEric Joyner 
42581031d839SEric Joyner 	return (0);
42591031d839SEric Joyner }
42601031d839SEric Joyner 
42611031d839SEric Joyner /*
4262cb6b8299SEric Joyner  * Sysctl to read a byte from I2C bus.
4263cb6b8299SEric Joyner  *
4264cb6b8299SEric Joyner  * Input: 32-bit value:
4265cb6b8299SEric Joyner  * 	bits 0-7:   device address (0xA0 or 0xA2)
4266cb6b8299SEric Joyner  * 	bits 8-15:  offset (0-255)
4267cb6b8299SEric Joyner  *	bits 16-31: unused
4268cb6b8299SEric Joyner  * Output: 8-bit value read
4269cb6b8299SEric Joyner  */
4270cb6b8299SEric Joyner static int
ixl_sysctl_read_i2c_byte(SYSCTL_HANDLER_ARGS)4271cb6b8299SEric Joyner ixl_sysctl_read_i2c_byte(SYSCTL_HANDLER_ARGS)
4272cb6b8299SEric Joyner {
4273cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4274cb6b8299SEric Joyner 	device_t dev = pf->dev;
4275cb6b8299SEric Joyner 	int input = -1, error = 0;
4276cb6b8299SEric Joyner 	u8 dev_addr, offset, output;
4277cb6b8299SEric Joyner 
4278cb6b8299SEric Joyner 	/* Read in I2C read parameters */
4279cb6b8299SEric Joyner 	error = sysctl_handle_int(oidp, &input, 0, req);
4280cb6b8299SEric Joyner 	if ((error) || (req->newptr == NULL))
4281cb6b8299SEric Joyner 		return (error);
4282cb6b8299SEric Joyner 	/* Validate device address */
4283cb6b8299SEric Joyner 	dev_addr = input & 0xFF;
4284cb6b8299SEric Joyner 	if (dev_addr != 0xA0 && dev_addr != 0xA2) {
4285cb6b8299SEric Joyner 		return (EINVAL);
4286cb6b8299SEric Joyner 	}
4287cb6b8299SEric Joyner 	offset = (input >> 8) & 0xFF;
4288cb6b8299SEric Joyner 
42891031d839SEric Joyner 	error = pf->read_i2c_byte(pf, offset, dev_addr, &output);
4290cb6b8299SEric Joyner 	if (error)
4291cb6b8299SEric Joyner 		return (error);
4292cb6b8299SEric Joyner 
4293cb6b8299SEric Joyner 	device_printf(dev, "%02X\n", output);
4294cb6b8299SEric Joyner 	return (0);
4295cb6b8299SEric Joyner }
4296cb6b8299SEric Joyner 
4297cb6b8299SEric Joyner /*
4298cb6b8299SEric Joyner  * Sysctl to write a byte to the I2C bus.
4299cb6b8299SEric Joyner  *
4300cb6b8299SEric Joyner  * Input: 32-bit value:
4301cb6b8299SEric Joyner  * 	bits 0-7:   device address (0xA0 or 0xA2)
4302cb6b8299SEric Joyner  * 	bits 8-15:  offset (0-255)
4303cb6b8299SEric Joyner  *	bits 16-23: value to write
4304cb6b8299SEric Joyner  *	bits 24-31: unused
4305cb6b8299SEric Joyner  * Output: 8-bit value written
4306cb6b8299SEric Joyner  */
4307cb6b8299SEric Joyner static int
ixl_sysctl_write_i2c_byte(SYSCTL_HANDLER_ARGS)4308cb6b8299SEric Joyner ixl_sysctl_write_i2c_byte(SYSCTL_HANDLER_ARGS)
4309cb6b8299SEric Joyner {
4310cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4311cb6b8299SEric Joyner 	device_t dev = pf->dev;
4312cb6b8299SEric Joyner 	int input = -1, error = 0;
4313cb6b8299SEric Joyner 	u8 dev_addr, offset, value;
4314cb6b8299SEric Joyner 
4315cb6b8299SEric Joyner 	/* Read in I2C write parameters */
4316cb6b8299SEric Joyner 	error = sysctl_handle_int(oidp, &input, 0, req);
4317cb6b8299SEric Joyner 	if ((error) || (req->newptr == NULL))
4318cb6b8299SEric Joyner 		return (error);
4319cb6b8299SEric Joyner 	/* Validate device address */
4320cb6b8299SEric Joyner 	dev_addr = input & 0xFF;
4321cb6b8299SEric Joyner 	if (dev_addr != 0xA0 && dev_addr != 0xA2) {
4322cb6b8299SEric Joyner 		return (EINVAL);
4323cb6b8299SEric Joyner 	}
4324cb6b8299SEric Joyner 	offset = (input >> 8) & 0xFF;
4325cb6b8299SEric Joyner 	value = (input >> 16) & 0xFF;
4326cb6b8299SEric Joyner 
43271031d839SEric Joyner 	error = pf->write_i2c_byte(pf, offset, dev_addr, value);
4328cb6b8299SEric Joyner 	if (error)
4329cb6b8299SEric Joyner 		return (error);
4330cb6b8299SEric Joyner 
4331cb6b8299SEric Joyner 	device_printf(dev, "%02X written\n", value);
4332cb6b8299SEric Joyner 	return (0);
4333cb6b8299SEric Joyner }
4334cb6b8299SEric Joyner 
4335cb6b8299SEric Joyner static int
ixl_get_fec_config(struct ixl_pf * pf,struct i40e_aq_get_phy_abilities_resp * abilities,u8 bit_pos,int * is_set)4336cb6b8299SEric Joyner ixl_get_fec_config(struct ixl_pf *pf, struct i40e_aq_get_phy_abilities_resp *abilities,
4337cb6b8299SEric Joyner     u8 bit_pos, int *is_set)
4338cb6b8299SEric Joyner {
4339cb6b8299SEric Joyner 	device_t dev = pf->dev;
4340cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
4341cb6b8299SEric Joyner 	enum i40e_status_code status;
4342cb6b8299SEric Joyner 
4343b4a7ce06SEric Joyner 	if (IXL_PF_IN_RECOVERY_MODE(pf))
4344b4a7ce06SEric Joyner 		return (EIO);
4345b4a7ce06SEric Joyner 
4346cb6b8299SEric Joyner 	status = i40e_aq_get_phy_capabilities(hw,
4347cb6b8299SEric Joyner 	    FALSE, FALSE, abilities, NULL);
4348cb6b8299SEric Joyner 	if (status) {
4349cb6b8299SEric Joyner 		device_printf(dev,
4350cb6b8299SEric Joyner 		    "%s: i40e_aq_get_phy_capabilities() status %s, aq error %s\n",
4351cb6b8299SEric Joyner 		    __func__, i40e_stat_str(hw, status),
4352cb6b8299SEric Joyner 		    i40e_aq_str(hw, hw->aq.asq_last_status));
4353cb6b8299SEric Joyner 		return (EIO);
4354cb6b8299SEric Joyner 	}
4355cb6b8299SEric Joyner 
4356ceebc2f3SEric Joyner 	*is_set = !!(abilities->fec_cfg_curr_mod_ext_info & bit_pos);
4357cb6b8299SEric Joyner 	return (0);
4358cb6b8299SEric Joyner }
4359cb6b8299SEric Joyner 
4360cb6b8299SEric Joyner static int
ixl_set_fec_config(struct ixl_pf * pf,struct i40e_aq_get_phy_abilities_resp * abilities,u8 bit_pos,int set)4361cb6b8299SEric Joyner ixl_set_fec_config(struct ixl_pf *pf, struct i40e_aq_get_phy_abilities_resp *abilities,
4362cb6b8299SEric Joyner     u8 bit_pos, int set)
4363cb6b8299SEric Joyner {
4364cb6b8299SEric Joyner 	device_t dev = pf->dev;
4365cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
4366cb6b8299SEric Joyner 	struct i40e_aq_set_phy_config config;
4367cb6b8299SEric Joyner 	enum i40e_status_code status;
4368cb6b8299SEric Joyner 
4369cb6b8299SEric Joyner 	/* Set new PHY config */
4370cb6b8299SEric Joyner 	memset(&config, 0, sizeof(config));
4371ceebc2f3SEric Joyner 	config.fec_config = abilities->fec_cfg_curr_mod_ext_info & ~(bit_pos);
4372cb6b8299SEric Joyner 	if (set)
4373cb6b8299SEric Joyner 		config.fec_config |= bit_pos;
4374ceebc2f3SEric Joyner 	if (config.fec_config != abilities->fec_cfg_curr_mod_ext_info) {
4375cb6b8299SEric Joyner 		config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
4376cb6b8299SEric Joyner 		config.phy_type = abilities->phy_type;
4377cb6b8299SEric Joyner 		config.phy_type_ext = abilities->phy_type_ext;
4378cb6b8299SEric Joyner 		config.link_speed = abilities->link_speed;
4379cb6b8299SEric Joyner 		config.eee_capability = abilities->eee_capability;
4380cb6b8299SEric Joyner 		config.eeer = abilities->eeer_val;
4381cb6b8299SEric Joyner 		config.low_power_ctrl = abilities->d3_lpan;
4382cb6b8299SEric Joyner 		status = i40e_aq_set_phy_config(hw, &config, NULL);
4383cb6b8299SEric Joyner 
4384cb6b8299SEric Joyner 		if (status) {
4385cb6b8299SEric Joyner 			device_printf(dev,
4386cb6b8299SEric Joyner 			    "%s: i40e_aq_set_phy_config() status %s, aq error %s\n",
4387cb6b8299SEric Joyner 			    __func__, i40e_stat_str(hw, status),
4388cb6b8299SEric Joyner 			    i40e_aq_str(hw, hw->aq.asq_last_status));
4389cb6b8299SEric Joyner 			return (EIO);
4390cb6b8299SEric Joyner 		}
4391cb6b8299SEric Joyner 	}
4392cb6b8299SEric Joyner 
4393cb6b8299SEric Joyner 	return (0);
4394cb6b8299SEric Joyner }
4395cb6b8299SEric Joyner 
4396cb6b8299SEric Joyner static int
ixl_sysctl_fec_fc_ability(SYSCTL_HANDLER_ARGS)4397cb6b8299SEric Joyner ixl_sysctl_fec_fc_ability(SYSCTL_HANDLER_ARGS)
4398cb6b8299SEric Joyner {
4399cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4400cb6b8299SEric Joyner 	int mode, error = 0;
4401cb6b8299SEric Joyner 
4402cb6b8299SEric Joyner 	struct i40e_aq_get_phy_abilities_resp abilities;
4403ceebc2f3SEric Joyner 	error = ixl_get_fec_config(pf, &abilities, I40E_AQ_ENABLE_FEC_KR, &mode);
4404cb6b8299SEric Joyner 	if (error)
4405cb6b8299SEric Joyner 		return (error);
4406cb6b8299SEric Joyner 	/* Read in new mode */
4407cb6b8299SEric Joyner 	error = sysctl_handle_int(oidp, &mode, 0, req);
4408cb6b8299SEric Joyner 	if ((error) || (req->newptr == NULL))
4409cb6b8299SEric Joyner 		return (error);
4410cb6b8299SEric Joyner 
4411cb6b8299SEric Joyner 	return ixl_set_fec_config(pf, &abilities, I40E_AQ_SET_FEC_ABILITY_KR, !!(mode));
4412cb6b8299SEric Joyner }
4413cb6b8299SEric Joyner 
4414cb6b8299SEric Joyner static int
ixl_sysctl_fec_rs_ability(SYSCTL_HANDLER_ARGS)4415cb6b8299SEric Joyner ixl_sysctl_fec_rs_ability(SYSCTL_HANDLER_ARGS)
4416cb6b8299SEric Joyner {
4417cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4418cb6b8299SEric Joyner 	int mode, error = 0;
4419cb6b8299SEric Joyner 
4420cb6b8299SEric Joyner 	struct i40e_aq_get_phy_abilities_resp abilities;
4421ceebc2f3SEric Joyner 	error = ixl_get_fec_config(pf, &abilities, I40E_AQ_ENABLE_FEC_RS, &mode);
4422cb6b8299SEric Joyner 	if (error)
4423cb6b8299SEric Joyner 		return (error);
4424cb6b8299SEric Joyner 	/* Read in new mode */
4425cb6b8299SEric Joyner 	error = sysctl_handle_int(oidp, &mode, 0, req);
4426cb6b8299SEric Joyner 	if ((error) || (req->newptr == NULL))
4427cb6b8299SEric Joyner 		return (error);
4428cb6b8299SEric Joyner 
4429cb6b8299SEric Joyner 	return ixl_set_fec_config(pf, &abilities, I40E_AQ_SET_FEC_ABILITY_RS, !!(mode));
4430cb6b8299SEric Joyner }
4431cb6b8299SEric Joyner 
4432cb6b8299SEric Joyner static int
ixl_sysctl_fec_fc_request(SYSCTL_HANDLER_ARGS)4433cb6b8299SEric Joyner ixl_sysctl_fec_fc_request(SYSCTL_HANDLER_ARGS)
4434cb6b8299SEric Joyner {
4435cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4436cb6b8299SEric Joyner 	int mode, error = 0;
4437cb6b8299SEric Joyner 
4438cb6b8299SEric Joyner 	struct i40e_aq_get_phy_abilities_resp abilities;
4439ceebc2f3SEric Joyner 	error = ixl_get_fec_config(pf, &abilities, I40E_AQ_REQUEST_FEC_KR, &mode);
4440cb6b8299SEric Joyner 	if (error)
4441cb6b8299SEric Joyner 		return (error);
4442cb6b8299SEric Joyner 	/* Read in new mode */
4443cb6b8299SEric Joyner 	error = sysctl_handle_int(oidp, &mode, 0, req);
4444cb6b8299SEric Joyner 	if ((error) || (req->newptr == NULL))
4445cb6b8299SEric Joyner 		return (error);
4446cb6b8299SEric Joyner 
4447cb6b8299SEric Joyner 	return ixl_set_fec_config(pf, &abilities, I40E_AQ_SET_FEC_REQUEST_KR, !!(mode));
4448cb6b8299SEric Joyner }
4449cb6b8299SEric Joyner 
4450cb6b8299SEric Joyner static int
ixl_sysctl_fec_rs_request(SYSCTL_HANDLER_ARGS)4451cb6b8299SEric Joyner ixl_sysctl_fec_rs_request(SYSCTL_HANDLER_ARGS)
4452cb6b8299SEric Joyner {
4453cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4454cb6b8299SEric Joyner 	int mode, error = 0;
4455cb6b8299SEric Joyner 
4456cb6b8299SEric Joyner 	struct i40e_aq_get_phy_abilities_resp abilities;
4457ceebc2f3SEric Joyner 	error = ixl_get_fec_config(pf, &abilities, I40E_AQ_REQUEST_FEC_RS, &mode);
4458cb6b8299SEric Joyner 	if (error)
4459cb6b8299SEric Joyner 		return (error);
4460cb6b8299SEric Joyner 	/* Read in new mode */
4461cb6b8299SEric Joyner 	error = sysctl_handle_int(oidp, &mode, 0, req);
4462cb6b8299SEric Joyner 	if ((error) || (req->newptr == NULL))
4463cb6b8299SEric Joyner 		return (error);
4464cb6b8299SEric Joyner 
4465cb6b8299SEric Joyner 	return ixl_set_fec_config(pf, &abilities, I40E_AQ_SET_FEC_REQUEST_RS, !!(mode));
4466cb6b8299SEric Joyner }
4467cb6b8299SEric Joyner 
4468cb6b8299SEric Joyner static int
ixl_sysctl_fec_auto_enable(SYSCTL_HANDLER_ARGS)4469cb6b8299SEric Joyner ixl_sysctl_fec_auto_enable(SYSCTL_HANDLER_ARGS)
4470cb6b8299SEric Joyner {
4471cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4472cb6b8299SEric Joyner 	int mode, error = 0;
4473cb6b8299SEric Joyner 
4474cb6b8299SEric Joyner 	struct i40e_aq_get_phy_abilities_resp abilities;
4475ceebc2f3SEric Joyner 	error = ixl_get_fec_config(pf, &abilities, I40E_AQ_ENABLE_FEC_AUTO, &mode);
4476cb6b8299SEric Joyner 	if (error)
4477cb6b8299SEric Joyner 		return (error);
4478cb6b8299SEric Joyner 	/* Read in new mode */
4479cb6b8299SEric Joyner 	error = sysctl_handle_int(oidp, &mode, 0, req);
4480cb6b8299SEric Joyner 	if ((error) || (req->newptr == NULL))
4481cb6b8299SEric Joyner 		return (error);
4482cb6b8299SEric Joyner 
4483cb6b8299SEric Joyner 	return ixl_set_fec_config(pf, &abilities, I40E_AQ_SET_FEC_AUTO, !!(mode));
4484cb6b8299SEric Joyner }
4485cb6b8299SEric Joyner 
4486ceebc2f3SEric Joyner static int
ixl_sysctl_dump_debug_data(SYSCTL_HANDLER_ARGS)4487ceebc2f3SEric Joyner ixl_sysctl_dump_debug_data(SYSCTL_HANDLER_ARGS)
4488ceebc2f3SEric Joyner {
4489ceebc2f3SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4490ceebc2f3SEric Joyner 	struct i40e_hw *hw = &pf->hw;
4491ceebc2f3SEric Joyner 	device_t dev = pf->dev;
4492ceebc2f3SEric Joyner 	struct sbuf *buf;
4493ceebc2f3SEric Joyner 	int error = 0;
4494ceebc2f3SEric Joyner 	enum i40e_status_code status;
4495ceebc2f3SEric Joyner 
4496ceebc2f3SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4497ceebc2f3SEric Joyner 	if (!buf) {
4498ceebc2f3SEric Joyner 		device_printf(dev, "Could not allocate sbuf for output.\n");
4499ceebc2f3SEric Joyner 		return (ENOMEM);
4500ceebc2f3SEric Joyner 	}
4501ceebc2f3SEric Joyner 
4502ceebc2f3SEric Joyner 	u8 *final_buff;
4503ceebc2f3SEric Joyner 	/* This amount is only necessary if reading the entire cluster into memory */
4504ceebc2f3SEric Joyner #define IXL_FINAL_BUFF_SIZE	(1280 * 1024)
45057d4dceecSKrzysztof Galazka 	final_buff = malloc(IXL_FINAL_BUFF_SIZE, M_IXL, M_NOWAIT);
4506ceebc2f3SEric Joyner 	if (final_buff == NULL) {
4507ceebc2f3SEric Joyner 		device_printf(dev, "Could not allocate memory for output.\n");
4508ceebc2f3SEric Joyner 		goto out;
4509ceebc2f3SEric Joyner 	}
4510ceebc2f3SEric Joyner 	int final_buff_len = 0;
4511ceebc2f3SEric Joyner 
4512ceebc2f3SEric Joyner 	u8 cluster_id = 1;
4513ceebc2f3SEric Joyner 	bool more = true;
4514ceebc2f3SEric Joyner 
4515ceebc2f3SEric Joyner 	u8 dump_buf[4096];
4516ceebc2f3SEric Joyner 	u16 curr_buff_size = 4096;
4517ceebc2f3SEric Joyner 	u8 curr_next_table = 0;
4518ceebc2f3SEric Joyner 	u32 curr_next_index = 0;
4519ceebc2f3SEric Joyner 
4520ceebc2f3SEric Joyner 	u16 ret_buff_size;
4521ceebc2f3SEric Joyner 	u8 ret_next_table;
4522ceebc2f3SEric Joyner 	u32 ret_next_index;
4523ceebc2f3SEric Joyner 
4524ceebc2f3SEric Joyner 	sbuf_cat(buf, "\n");
4525ceebc2f3SEric Joyner 
4526ceebc2f3SEric Joyner 	while (more) {
4527ceebc2f3SEric Joyner 		status = i40e_aq_debug_dump(hw, cluster_id, curr_next_table, curr_next_index, curr_buff_size,
4528ceebc2f3SEric Joyner 		    dump_buf, &ret_buff_size, &ret_next_table, &ret_next_index, NULL);
4529ceebc2f3SEric Joyner 		if (status) {
4530ceebc2f3SEric Joyner 			device_printf(dev, "i40e_aq_debug_dump status %s, error %s\n",
4531ceebc2f3SEric Joyner 			    i40e_stat_str(hw, status), i40e_aq_str(hw, hw->aq.asq_last_status));
4532ceebc2f3SEric Joyner 			goto free_out;
4533ceebc2f3SEric Joyner 		}
4534ceebc2f3SEric Joyner 
4535ceebc2f3SEric Joyner 		/* copy info out of temp buffer */
4536ceebc2f3SEric Joyner 		bcopy(dump_buf, (caddr_t)final_buff + final_buff_len, ret_buff_size);
4537ceebc2f3SEric Joyner 		final_buff_len += ret_buff_size;
4538ceebc2f3SEric Joyner 
4539ceebc2f3SEric Joyner 		if (ret_next_table != curr_next_table) {
4540ceebc2f3SEric Joyner 			/* We're done with the current table; we can dump out read data. */
4541ceebc2f3SEric Joyner 			sbuf_printf(buf, "%d:", curr_next_table);
4542ceebc2f3SEric Joyner 			int bytes_printed = 0;
4543ceebc2f3SEric Joyner 			while (bytes_printed <= final_buff_len) {
4544ceebc2f3SEric Joyner 				sbuf_printf(buf, "%16D", ((caddr_t)final_buff + bytes_printed), "");
4545ceebc2f3SEric Joyner 				bytes_printed += 16;
4546ceebc2f3SEric Joyner 			}
4547ceebc2f3SEric Joyner 				sbuf_cat(buf, "\n");
4548ceebc2f3SEric Joyner 
4549ceebc2f3SEric Joyner 			/* The entire cluster has been read; we're finished */
4550ceebc2f3SEric Joyner 			if (ret_next_table == 0xFF)
4551ceebc2f3SEric Joyner 				break;
4552ceebc2f3SEric Joyner 
4553ceebc2f3SEric Joyner 			/* Otherwise clear the output buffer and continue reading */
4554ceebc2f3SEric Joyner 			bzero(final_buff, IXL_FINAL_BUFF_SIZE);
4555ceebc2f3SEric Joyner 			final_buff_len = 0;
4556ceebc2f3SEric Joyner 		}
4557ceebc2f3SEric Joyner 
4558ceebc2f3SEric Joyner 		if (ret_next_index == 0xFFFFFFFF)
4559ceebc2f3SEric Joyner 			ret_next_index = 0;
4560ceebc2f3SEric Joyner 
4561ceebc2f3SEric Joyner 		bzero(dump_buf, sizeof(dump_buf));
4562ceebc2f3SEric Joyner 		curr_next_table = ret_next_table;
4563ceebc2f3SEric Joyner 		curr_next_index = ret_next_index;
4564ceebc2f3SEric Joyner 	}
4565ceebc2f3SEric Joyner 
4566ceebc2f3SEric Joyner free_out:
45677d4dceecSKrzysztof Galazka 	free(final_buff, M_IXL);
4568ceebc2f3SEric Joyner out:
4569ceebc2f3SEric Joyner 	error = sbuf_finish(buf);
4570ceebc2f3SEric Joyner 	if (error)
4571ceebc2f3SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
4572ceebc2f3SEric Joyner 	sbuf_delete(buf);
4573ceebc2f3SEric Joyner 
4574ceebc2f3SEric Joyner 	return (error);
4575ceebc2f3SEric Joyner }
4576ceebc2f3SEric Joyner 
4577ceebc2f3SEric Joyner static int
ixl_start_fw_lldp(struct ixl_pf * pf)4578b4a7ce06SEric Joyner ixl_start_fw_lldp(struct ixl_pf *pf)
4579b4a7ce06SEric Joyner {
4580b4a7ce06SEric Joyner 	struct i40e_hw *hw = &pf->hw;
4581b4a7ce06SEric Joyner 	enum i40e_status_code status;
4582b4a7ce06SEric Joyner 
4583b4a7ce06SEric Joyner 	status = i40e_aq_start_lldp(hw, false, NULL);
4584b4a7ce06SEric Joyner 	if (status != I40E_SUCCESS) {
4585b4a7ce06SEric Joyner 		switch (hw->aq.asq_last_status) {
4586b4a7ce06SEric Joyner 		case I40E_AQ_RC_EEXIST:
4587b4a7ce06SEric Joyner 			device_printf(pf->dev,
4588b4a7ce06SEric Joyner 			    "FW LLDP agent is already running\n");
4589b4a7ce06SEric Joyner 			break;
4590b4a7ce06SEric Joyner 		case I40E_AQ_RC_EPERM:
4591b4a7ce06SEric Joyner 			device_printf(pf->dev,
4592b4a7ce06SEric Joyner 			    "Device configuration forbids SW from starting "
4593b4a7ce06SEric Joyner 			    "the LLDP agent. Set the \"LLDP Agent\" UEFI HII "
4594b4a7ce06SEric Joyner 			    "attribute to \"Enabled\" to use this sysctl\n");
4595b4a7ce06SEric Joyner 			return (EINVAL);
4596b4a7ce06SEric Joyner 		default:
4597b4a7ce06SEric Joyner 			device_printf(pf->dev,
4598b4a7ce06SEric Joyner 			    "Starting FW LLDP agent failed: error: %s, %s\n",
4599b4a7ce06SEric Joyner 			    i40e_stat_str(hw, status),
4600b4a7ce06SEric Joyner 			    i40e_aq_str(hw, hw->aq.asq_last_status));
4601b4a7ce06SEric Joyner 			return (EINVAL);
4602b4a7ce06SEric Joyner 		}
4603b4a7ce06SEric Joyner 	}
4604b4a7ce06SEric Joyner 
4605b8f51b8cSPiotr Kubaj 	ixl_clear_state(&pf->state, IXL_STATE_FW_LLDP_DISABLED);
4606b4a7ce06SEric Joyner 	return (0);
4607b4a7ce06SEric Joyner }
4608b4a7ce06SEric Joyner 
4609b4a7ce06SEric Joyner static int
ixl_stop_fw_lldp(struct ixl_pf * pf)4610b4a7ce06SEric Joyner ixl_stop_fw_lldp(struct ixl_pf *pf)
4611b4a7ce06SEric Joyner {
4612b4a7ce06SEric Joyner 	struct i40e_hw *hw = &pf->hw;
4613b4a7ce06SEric Joyner 	device_t dev = pf->dev;
4614b4a7ce06SEric Joyner 	enum i40e_status_code status;
4615b4a7ce06SEric Joyner 
4616b4a7ce06SEric Joyner 	if (hw->func_caps.npar_enable != 0) {
4617b4a7ce06SEric Joyner 		device_printf(dev,
4618b4a7ce06SEric Joyner 		    "Disabling FW LLDP agent is not supported on this device\n");
4619b4a7ce06SEric Joyner 		return (EINVAL);
4620b4a7ce06SEric Joyner 	}
4621b4a7ce06SEric Joyner 
4622b4a7ce06SEric Joyner 	if ((hw->flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE) == 0) {
4623b4a7ce06SEric Joyner 		device_printf(dev,
4624b4a7ce06SEric Joyner 		    "Disabling FW LLDP agent is not supported in this FW version. Please update FW to enable this feature.\n");
4625b4a7ce06SEric Joyner 		return (EINVAL);
4626b4a7ce06SEric Joyner 	}
4627b4a7ce06SEric Joyner 
4628b4a7ce06SEric Joyner 	status = i40e_aq_stop_lldp(hw, true, false, NULL);
4629b4a7ce06SEric Joyner 	if (status != I40E_SUCCESS) {
4630b4a7ce06SEric Joyner 		if (hw->aq.asq_last_status != I40E_AQ_RC_EPERM) {
4631b4a7ce06SEric Joyner 			device_printf(dev,
4632b4a7ce06SEric Joyner 			    "Disabling FW LLDP agent failed: error: %s, %s\n",
4633b4a7ce06SEric Joyner 			    i40e_stat_str(hw, status),
4634b4a7ce06SEric Joyner 			    i40e_aq_str(hw, hw->aq.asq_last_status));
4635b4a7ce06SEric Joyner 			return (EINVAL);
4636b4a7ce06SEric Joyner 		}
4637b4a7ce06SEric Joyner 
4638b4a7ce06SEric Joyner 		device_printf(dev, "FW LLDP agent is already stopped\n");
4639b4a7ce06SEric Joyner 	}
4640b4a7ce06SEric Joyner 
4641b4a7ce06SEric Joyner 	i40e_aq_set_dcb_parameters(hw, true, NULL);
4642b8f51b8cSPiotr Kubaj 	ixl_set_state(&pf->state, IXL_STATE_FW_LLDP_DISABLED);
4643b4a7ce06SEric Joyner 	return (0);
4644b4a7ce06SEric Joyner }
4645b4a7ce06SEric Joyner 
4646b4a7ce06SEric Joyner static int
ixl_sysctl_fw_lldp(SYSCTL_HANDLER_ARGS)4647ceebc2f3SEric Joyner ixl_sysctl_fw_lldp(SYSCTL_HANDLER_ARGS)
4648ceebc2f3SEric Joyner {
4649ceebc2f3SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4650b4a7ce06SEric Joyner 	int state, new_state, error = 0;
4651b4a7ce06SEric Joyner 
4652b8f51b8cSPiotr Kubaj 	state = new_state = !ixl_test_state(&pf->state, IXL_STATE_FW_LLDP_DISABLED);
4653ceebc2f3SEric Joyner 
4654ceebc2f3SEric Joyner 	/* Read in new mode */
4655ceebc2f3SEric Joyner 	error = sysctl_handle_int(oidp, &new_state, 0, req);
4656ceebc2f3SEric Joyner 	if ((error) || (req->newptr == NULL))
4657ceebc2f3SEric Joyner 		return (error);
4658ceebc2f3SEric Joyner 
4659ceebc2f3SEric Joyner 	/* Already in requested state */
4660ceebc2f3SEric Joyner 	if (new_state == state)
4661ceebc2f3SEric Joyner 		return (error);
4662ceebc2f3SEric Joyner 
4663b4a7ce06SEric Joyner 	if (new_state == 0)
4664b4a7ce06SEric Joyner 		return ixl_stop_fw_lldp(pf);
4665ceebc2f3SEric Joyner 
4666b4a7ce06SEric Joyner 	return ixl_start_fw_lldp(pf);
4667ceebc2f3SEric Joyner }
4668ceebc2f3SEric Joyner 
46692984a8ddSEric Joyner static int
ixl_sysctl_eee_enable(SYSCTL_HANDLER_ARGS)46702984a8ddSEric Joyner ixl_sysctl_eee_enable(SYSCTL_HANDLER_ARGS)
46712984a8ddSEric Joyner {
46722984a8ddSEric Joyner 	struct ixl_pf         *pf = (struct ixl_pf *)arg1;
46732984a8ddSEric Joyner 	int                   state, new_state;
46742984a8ddSEric Joyner 	int                   sysctl_handle_status = 0;
46752984a8ddSEric Joyner 	enum i40e_status_code cmd_status;
46762984a8ddSEric Joyner 
46772984a8ddSEric Joyner 	/* Init states' values */
4678b8f51b8cSPiotr Kubaj 	state = new_state = ixl_test_state(&pf->state, IXL_STATE_EEE_ENABLED);
46792984a8ddSEric Joyner 
46802984a8ddSEric Joyner 	/* Get requested mode */
46812984a8ddSEric Joyner 	sysctl_handle_status = sysctl_handle_int(oidp, &new_state, 0, req);
46822984a8ddSEric Joyner 	if ((sysctl_handle_status) || (req->newptr == NULL))
46832984a8ddSEric Joyner 		return (sysctl_handle_status);
46842984a8ddSEric Joyner 
46852984a8ddSEric Joyner 	/* Check if state has changed */
46862984a8ddSEric Joyner 	if (new_state == state)
46872984a8ddSEric Joyner 		return (0);
46882984a8ddSEric Joyner 
46892984a8ddSEric Joyner 	/* Set new state */
46902984a8ddSEric Joyner 	cmd_status = i40e_enable_eee(&pf->hw, (bool)(!!new_state));
46912984a8ddSEric Joyner 
46922984a8ddSEric Joyner 	/* Save new state or report error */
46932984a8ddSEric Joyner 	if (!cmd_status) {
46942984a8ddSEric Joyner 		if (new_state == 0)
4695b8f51b8cSPiotr Kubaj 			ixl_clear_state(&pf->state, IXL_STATE_EEE_ENABLED);
46962984a8ddSEric Joyner 		else
4697b8f51b8cSPiotr Kubaj 			ixl_set_state(&pf->state, IXL_STATE_EEE_ENABLED);
46982984a8ddSEric Joyner 	} else if (cmd_status == I40E_ERR_CONFIG)
46992984a8ddSEric Joyner 		return (EPERM);
47002984a8ddSEric Joyner 	else
47012984a8ddSEric Joyner 		return (EIO);
47022984a8ddSEric Joyner 
47032984a8ddSEric Joyner 	return (0);
47042984a8ddSEric Joyner }
47052984a8ddSEric Joyner 
470621802a12SKrzysztof Galazka static int
ixl_sysctl_set_link_active(SYSCTL_HANDLER_ARGS)470721802a12SKrzysztof Galazka ixl_sysctl_set_link_active(SYSCTL_HANDLER_ARGS)
470821802a12SKrzysztof Galazka {
470921802a12SKrzysztof Galazka 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
471021802a12SKrzysztof Galazka 	int error, state;
471121802a12SKrzysztof Galazka 
4712b8f51b8cSPiotr Kubaj 	state = ixl_test_state(&pf->state, IXL_STATE_LINK_ACTIVE_ON_DOWN);
471321802a12SKrzysztof Galazka 
471421802a12SKrzysztof Galazka 	error = sysctl_handle_int(oidp, &state, 0, req);
471521802a12SKrzysztof Galazka 	if ((error) || (req->newptr == NULL))
471621802a12SKrzysztof Galazka 		return (error);
471721802a12SKrzysztof Galazka 
471821802a12SKrzysztof Galazka 	if (state == 0)
4719b8f51b8cSPiotr Kubaj 		ixl_clear_state(&pf->state, IXL_STATE_LINK_ACTIVE_ON_DOWN);
472021802a12SKrzysztof Galazka 	else
4721b8f51b8cSPiotr Kubaj 		ixl_set_state(&pf->state, IXL_STATE_LINK_ACTIVE_ON_DOWN);
472221802a12SKrzysztof Galazka 
472321802a12SKrzysztof Galazka 	return (0);
472421802a12SKrzysztof Galazka }
472521802a12SKrzysztof Galazka 
472621802a12SKrzysztof Galazka 
4727ceebc2f3SEric Joyner int
ixl_attach_get_link_status(struct ixl_pf * pf)4728ceebc2f3SEric Joyner ixl_attach_get_link_status(struct ixl_pf *pf)
4729ceebc2f3SEric Joyner {
4730ceebc2f3SEric Joyner 	struct i40e_hw *hw = &pf->hw;
4731ceebc2f3SEric Joyner 	device_t dev = pf->dev;
4732ba2f531fSKrzysztof Galazka 	enum i40e_status_code status;
4733ceebc2f3SEric Joyner 
4734ceebc2f3SEric Joyner 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
4735ceebc2f3SEric Joyner 	    (hw->aq.fw_maj_ver < 4)) {
4736ceebc2f3SEric Joyner 		i40e_msec_delay(75);
4737ba2f531fSKrzysztof Galazka 		status = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
4738ba2f531fSKrzysztof Galazka 		if (status != I40E_SUCCESS) {
4739ba2f531fSKrzysztof Galazka 			device_printf(dev,
4740ba2f531fSKrzysztof Galazka 			    "%s link restart failed status: %s, aq_err=%s\n",
4741ba2f531fSKrzysztof Galazka 			    __func__, i40e_stat_str(hw, status),
4742ba2f531fSKrzysztof Galazka 			    i40e_aq_str(hw, hw->aq.asq_last_status));
4743ba2f531fSKrzysztof Galazka 			return (EINVAL);
4744ceebc2f3SEric Joyner 		}
4745ceebc2f3SEric Joyner 	}
4746ceebc2f3SEric Joyner 
4747ceebc2f3SEric Joyner 	/* Determine link state */
4748ceebc2f3SEric Joyner 	hw->phy.get_link_info = TRUE;
4749ba2f531fSKrzysztof Galazka 	status = i40e_get_link_status(hw, &pf->link_up);
4750ba2f531fSKrzysztof Galazka 	if (status != I40E_SUCCESS) {
4751ba2f531fSKrzysztof Galazka 		device_printf(dev,
4752ba2f531fSKrzysztof Galazka 		    "%s get link status, status: %s aq_err=%s\n",
4753ba2f531fSKrzysztof Galazka 		    __func__, i40e_stat_str(hw, status),
4754ba2f531fSKrzysztof Galazka 		    i40e_aq_str(hw, hw->aq.asq_last_status));
4755ba2f531fSKrzysztof Galazka 		/*
4756ba2f531fSKrzysztof Galazka 		 * Most probably FW has not finished configuring PHY.
4757ba2f531fSKrzysztof Galazka 		 * Retry periodically in a timer callback.
4758ba2f531fSKrzysztof Galazka 		 */
4759ba2f531fSKrzysztof Galazka 		ixl_set_state(&pf->state, IXL_STATE_LINK_POLLING);
4760ba2f531fSKrzysztof Galazka 		pf->link_poll_start = getsbinuptime();
4761ba2f531fSKrzysztof Galazka 		return (EAGAIN);
4762ba2f531fSKrzysztof Galazka 	}
4763ba2f531fSKrzysztof Galazka  	ixl_dbg_link(pf, "%s link_up: %d\n", __func__, pf->link_up);
476420a52706SKrzysztof Galazka 
476520a52706SKrzysztof Galazka 	/* Flow Control mode not set by user, read current FW settings */
476620a52706SKrzysztof Galazka 	if (pf->fc == -1)
476720a52706SKrzysztof Galazka 		pf->fc = hw->fc.current_mode;
476820a52706SKrzysztof Galazka 
4769ceebc2f3SEric Joyner 	return (0);
4770ceebc2f3SEric Joyner }
47711031d839SEric Joyner 
47721031d839SEric Joyner static int
ixl_sysctl_do_pf_reset(SYSCTL_HANDLER_ARGS)47731031d839SEric Joyner ixl_sysctl_do_pf_reset(SYSCTL_HANDLER_ARGS)
47741031d839SEric Joyner {
47751031d839SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
47761031d839SEric Joyner 	int requested = 0, error = 0;
47771031d839SEric Joyner 
47781031d839SEric Joyner 	/* Read in new mode */
47791031d839SEric Joyner 	error = sysctl_handle_int(oidp, &requested, 0, req);
47801031d839SEric Joyner 	if ((error) || (req->newptr == NULL))
47811031d839SEric Joyner 		return (error);
47821031d839SEric Joyner 
47831031d839SEric Joyner 	/* Initiate the PF reset later in the admin task */
4784b8f51b8cSPiotr Kubaj 	ixl_set_state(&pf->state, IXL_STATE_PF_RESET_REQ);
47851031d839SEric Joyner 
47861031d839SEric Joyner 	return (error);
47871031d839SEric Joyner }
47881031d839SEric Joyner 
47891031d839SEric Joyner static int
ixl_sysctl_do_core_reset(SYSCTL_HANDLER_ARGS)47901031d839SEric Joyner ixl_sysctl_do_core_reset(SYSCTL_HANDLER_ARGS)
47911031d839SEric Joyner {
47921031d839SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
47931031d839SEric Joyner 	struct i40e_hw *hw = &pf->hw;
47941031d839SEric Joyner 	int requested = 0, error = 0;
47951031d839SEric Joyner 
47961031d839SEric Joyner 	/* Read in new mode */
47971031d839SEric Joyner 	error = sysctl_handle_int(oidp, &requested, 0, req);
47981031d839SEric Joyner 	if ((error) || (req->newptr == NULL))
47991031d839SEric Joyner 		return (error);
48001031d839SEric Joyner 
48011031d839SEric Joyner 	wr32(hw, I40E_GLGEN_RTRIG, I40E_GLGEN_RTRIG_CORER_MASK);
48021031d839SEric Joyner 
48031031d839SEric Joyner 	return (error);
48041031d839SEric Joyner }
48051031d839SEric Joyner 
48061031d839SEric Joyner static int
ixl_sysctl_do_global_reset(SYSCTL_HANDLER_ARGS)48071031d839SEric Joyner ixl_sysctl_do_global_reset(SYSCTL_HANDLER_ARGS)
48081031d839SEric Joyner {
48091031d839SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
48101031d839SEric Joyner 	struct i40e_hw *hw = &pf->hw;
48111031d839SEric Joyner 	int requested = 0, error = 0;
48121031d839SEric Joyner 
48131031d839SEric Joyner 	/* Read in new mode */
48141031d839SEric Joyner 	error = sysctl_handle_int(oidp, &requested, 0, req);
48151031d839SEric Joyner 	if ((error) || (req->newptr == NULL))
48161031d839SEric Joyner 		return (error);
48171031d839SEric Joyner 
48181031d839SEric Joyner 	wr32(hw, I40E_GLGEN_RTRIG, I40E_GLGEN_RTRIG_GLOBR_MASK);
48191031d839SEric Joyner 
48201031d839SEric Joyner 	return (error);
48211031d839SEric Joyner }
48221031d839SEric Joyner 
48231031d839SEric Joyner /*
48241031d839SEric Joyner  * Print out mapping of TX queue indexes and Rx queue indexes
48251031d839SEric Joyner  * to MSI-X vectors.
48261031d839SEric Joyner  */
48271031d839SEric Joyner static int
ixl_sysctl_queue_interrupt_table(SYSCTL_HANDLER_ARGS)48281031d839SEric Joyner ixl_sysctl_queue_interrupt_table(SYSCTL_HANDLER_ARGS)
48291031d839SEric Joyner {
48301031d839SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
48311031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
48324fecb701SKrzysztof Galazka 	struct i40e_hw *hw = vsi->hw;
48331031d839SEric Joyner 	device_t dev = pf->dev;
48341031d839SEric Joyner 	struct sbuf *buf;
48351031d839SEric Joyner 	int error = 0;
48361031d839SEric Joyner 
48371031d839SEric Joyner 	struct ixl_rx_queue *rx_que = vsi->rx_queues;
48381031d839SEric Joyner 	struct ixl_tx_queue *tx_que = vsi->tx_queues;
48391031d839SEric Joyner 
48401031d839SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
48411031d839SEric Joyner 	if (!buf) {
48421031d839SEric Joyner 		device_printf(dev, "Could not allocate sbuf for output.\n");
48431031d839SEric Joyner 		return (ENOMEM);
48441031d839SEric Joyner 	}
48451031d839SEric Joyner 
48461031d839SEric Joyner 	sbuf_cat(buf, "\n");
48471031d839SEric Joyner 	for (int i = 0; i < vsi->num_rx_queues; i++) {
48481031d839SEric Joyner 		rx_que = &vsi->rx_queues[i];
48494fecb701SKrzysztof Galazka 		sbuf_printf(buf,
48504fecb701SKrzysztof Galazka 		    "(rxq %3d): %d LNKLSTN: %08x QINT_RQCTL: %08x\n",
48514fecb701SKrzysztof Galazka 		    i, rx_que->msix,
48524fecb701SKrzysztof Galazka 		    rd32(hw, I40E_PFINT_LNKLSTN(rx_que->msix - 1)),
48534fecb701SKrzysztof Galazka 		    rd32(hw, I40E_QINT_RQCTL(rx_que->msix - 1)));
48541031d839SEric Joyner 	}
48551031d839SEric Joyner 	for (int i = 0; i < vsi->num_tx_queues; i++) {
48561031d839SEric Joyner 		tx_que = &vsi->tx_queues[i];
48574fecb701SKrzysztof Galazka 		sbuf_printf(buf, "(txq %3d): %d QINT_TQCTL: %08x\n",
48584fecb701SKrzysztof Galazka 		    i, tx_que->msix,
48594fecb701SKrzysztof Galazka 		    rd32(hw, I40E_QINT_TQCTL(tx_que->msix - 1)));
48604fecb701SKrzysztof Galazka 	}
48614fecb701SKrzysztof Galazka 
48624fecb701SKrzysztof Galazka 	error = sbuf_finish(buf);
48634fecb701SKrzysztof Galazka 	if (error)
48644fecb701SKrzysztof Galazka 		device_printf(dev, "Error finishing sbuf: %d\n", error);
48654fecb701SKrzysztof Galazka 	sbuf_delete(buf);
48664fecb701SKrzysztof Galazka 
48674fecb701SKrzysztof Galazka 	return (error);
48684fecb701SKrzysztof Galazka }
48694fecb701SKrzysztof Galazka 
48704fecb701SKrzysztof Galazka static int
ixl_sysctl_debug_queue_int_ctln(SYSCTL_HANDLER_ARGS)48714fecb701SKrzysztof Galazka ixl_sysctl_debug_queue_int_ctln(SYSCTL_HANDLER_ARGS)
48724fecb701SKrzysztof Galazka {
48734fecb701SKrzysztof Galazka 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
48744fecb701SKrzysztof Galazka 	struct ixl_vsi *vsi = &pf->vsi;
48754fecb701SKrzysztof Galazka 	struct i40e_hw *hw = vsi->hw;
48764fecb701SKrzysztof Galazka 	device_t dev = pf->dev;
48774fecb701SKrzysztof Galazka 	struct sbuf *buf;
48784fecb701SKrzysztof Galazka 	int error = 0;
48794fecb701SKrzysztof Galazka 
48804fecb701SKrzysztof Galazka 	struct ixl_rx_queue *rx_que = vsi->rx_queues;
48814fecb701SKrzysztof Galazka 
48824fecb701SKrzysztof Galazka 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
48834fecb701SKrzysztof Galazka 	if (!buf) {
48844fecb701SKrzysztof Galazka 		device_printf(dev, "Could not allocate sbuf for output.\n");
48854fecb701SKrzysztof Galazka 		return (ENOMEM);
48864fecb701SKrzysztof Galazka 	}
48874fecb701SKrzysztof Galazka 
48884fecb701SKrzysztof Galazka 	sbuf_cat(buf, "\n");
48894fecb701SKrzysztof Galazka 	for (int i = 0; i < vsi->num_rx_queues; i++) {
48904fecb701SKrzysztof Galazka 		rx_que = &vsi->rx_queues[i];
48914fecb701SKrzysztof Galazka 		sbuf_printf(buf,
48924fecb701SKrzysztof Galazka 		    "(rxq %3d): %d PFINT_DYN_CTLN: %08x\n",
48934fecb701SKrzysztof Galazka 		    i, rx_que->msix,
48944fecb701SKrzysztof Galazka 		    rd32(hw, I40E_PFINT_DYN_CTLN(rx_que->msix - 1)));
48951031d839SEric Joyner 	}
48961031d839SEric Joyner 
48971031d839SEric Joyner 	error = sbuf_finish(buf);
48981031d839SEric Joyner 	if (error)
48991031d839SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
49001031d839SEric Joyner 	sbuf_delete(buf);
49011031d839SEric Joyner 
49021031d839SEric Joyner 	return (error);
49031031d839SEric Joyner }
4904