xref: /freebsd-src/sys/dev/iavf/iavf_lib.c (revision e53a21abdf2953714e44e3c54b4bb78557cb096c)
1ca853deeSEric Joyner /* SPDX-License-Identifier: BSD-3-Clause */
2*e53a21abSEric Joyner /*  Copyright (c) 2024, Intel Corporation
3ca853deeSEric Joyner  *  All rights reserved.
4ca853deeSEric Joyner  *
5ca853deeSEric Joyner  *  Redistribution and use in source and binary forms, with or without
6ca853deeSEric Joyner  *  modification, are permitted provided that the following conditions are met:
7ca853deeSEric Joyner  *
8ca853deeSEric Joyner  *   1. Redistributions of source code must retain the above copyright notice,
9ca853deeSEric Joyner  *      this list of conditions and the following disclaimer.
10ca853deeSEric Joyner  *
11ca853deeSEric Joyner  *   2. Redistributions in binary form must reproduce the above copyright
12ca853deeSEric Joyner  *      notice, this list of conditions and the following disclaimer in the
13ca853deeSEric Joyner  *      documentation and/or other materials provided with the distribution.
14ca853deeSEric Joyner  *
15ca853deeSEric Joyner  *   3. Neither the name of the Intel Corporation nor the names of its
16ca853deeSEric Joyner  *      contributors may be used to endorse or promote products derived from
17ca853deeSEric Joyner  *      this software without specific prior written permission.
18ca853deeSEric Joyner  *
19ca853deeSEric Joyner  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20ca853deeSEric Joyner  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21ca853deeSEric Joyner  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22ca853deeSEric Joyner  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23ca853deeSEric Joyner  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ca853deeSEric Joyner  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ca853deeSEric Joyner  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ca853deeSEric Joyner  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ca853deeSEric Joyner  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ca853deeSEric Joyner  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ca853deeSEric Joyner  *  POSSIBILITY OF SUCH DAMAGE.
30ca853deeSEric Joyner  */
31ca853deeSEric Joyner 
32ca853deeSEric Joyner /**
33ca853deeSEric Joyner  * @file iavf_lib.c
34ca853deeSEric Joyner  * @brief library code common to both legacy and iflib
35ca853deeSEric Joyner  *
36ca853deeSEric Joyner  * Contains functions common to the iflib and legacy drivers. Includes
37ca853deeSEric Joyner  * hardware initialization and control functions, as well as sysctl handlers
38ca853deeSEric Joyner  * for the sysctls which are shared between the legacy and iflib drivers.
39ca853deeSEric Joyner  */
40ca853deeSEric Joyner #include "iavf_iflib.h"
41ca853deeSEric Joyner #include "iavf_vc_common.h"
42ca853deeSEric Joyner 
43ca853deeSEric Joyner static void iavf_init_hw(struct iavf_hw *hw, device_t dev);
44ca853deeSEric Joyner static u_int iavf_mc_filter_apply(void *arg, struct sockaddr_dl *sdl, u_int cnt);
45ca853deeSEric Joyner 
46ca853deeSEric Joyner /**
47ca853deeSEric Joyner  * iavf_msec_pause - Pause for at least the specified number of milliseconds
48ca853deeSEric Joyner  * @msecs: number of milliseconds to pause for
49ca853deeSEric Joyner  *
50ca853deeSEric Joyner  * Pause execution of the current thread for a specified number of
51ca853deeSEric Joyner  * milliseconds. Used to enforce minimum delay times when waiting for various
52ca853deeSEric Joyner  * hardware events.
53ca853deeSEric Joyner  */
54ca853deeSEric Joyner void
55ca853deeSEric Joyner iavf_msec_pause(int msecs)
56ca853deeSEric Joyner {
57ca853deeSEric Joyner 	pause("iavf_msec_pause", MSEC_2_TICKS(msecs));
58ca853deeSEric Joyner }
59ca853deeSEric Joyner 
60ca853deeSEric Joyner /**
61ca853deeSEric Joyner  * iavf_get_default_rss_key - Get the default RSS key for this driver
62ca853deeSEric Joyner  * @key: output parameter to store the key in
63ca853deeSEric Joyner  *
64ca853deeSEric Joyner  * Copies the driver's default RSS key into the provided key variable.
65ca853deeSEric Joyner  *
66ca853deeSEric Joyner  * @pre assumes that key is not NULL and has at least IAVF_RSS_KEY_SIZE
67ca853deeSEric Joyner  * storage space.
68ca853deeSEric Joyner  */
69ca853deeSEric Joyner void
70ca853deeSEric Joyner iavf_get_default_rss_key(u32 *key)
71ca853deeSEric Joyner {
72ca853deeSEric Joyner 	MPASS(key != NULL);
73ca853deeSEric Joyner 
74ca853deeSEric Joyner 	u32 rss_seed[IAVF_RSS_KEY_SIZE_REG] = {0x41b01687,
75ca853deeSEric Joyner 	    0x183cfd8c, 0xce880440, 0x580cbc3c,
76ca853deeSEric Joyner 	    0x35897377, 0x328b25e1, 0x4fa98922,
77ca853deeSEric Joyner 	    0xb7d90c14, 0xd5bad70d, 0xcd15a2c1,
78ca853deeSEric Joyner 	    0x0, 0x0, 0x0};
79ca853deeSEric Joyner 
80ca853deeSEric Joyner 	bcopy(rss_seed, key, IAVF_RSS_KEY_SIZE);
81ca853deeSEric Joyner }
82ca853deeSEric Joyner 
83ca853deeSEric Joyner /**
84ca853deeSEric Joyner  * iavf_allocate_pci_resources_common - Allocate PCI resources
85ca853deeSEric Joyner  * @sc: the private device softc pointer
86ca853deeSEric Joyner  *
87ca853deeSEric Joyner  * @pre sc->dev is set
88ca853deeSEric Joyner  *
89ca853deeSEric Joyner  * Allocates the common PCI resources used by the driver.
90ca853deeSEric Joyner  *
91ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
92ca853deeSEric Joyner  */
93ca853deeSEric Joyner int
94ca853deeSEric Joyner iavf_allocate_pci_resources_common(struct iavf_sc *sc)
95ca853deeSEric Joyner {
96ca853deeSEric Joyner 	struct iavf_hw *hw = &sc->hw;
97ca853deeSEric Joyner 	device_t dev = sc->dev;
98ca853deeSEric Joyner 	int rid;
99ca853deeSEric Joyner 
100ca853deeSEric Joyner 	/* Map PCI BAR0 */
101ca853deeSEric Joyner 	rid = PCIR_BAR(0);
102ca853deeSEric Joyner 	sc->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
103ca853deeSEric Joyner 	    &rid, RF_ACTIVE);
104ca853deeSEric Joyner 
105ca853deeSEric Joyner 	if (!(sc->pci_mem)) {
106ca853deeSEric Joyner 		device_printf(dev, "Unable to allocate bus resource: PCI memory\n");
107ca853deeSEric Joyner 		return (ENXIO);
108ca853deeSEric Joyner 	}
109ca853deeSEric Joyner 
110ca853deeSEric Joyner 	iavf_init_hw(hw, dev);
111ca853deeSEric Joyner 
112ca853deeSEric Joyner 	/* Save off register access information */
113ca853deeSEric Joyner 	sc->osdep.mem_bus_space_tag =
114ca853deeSEric Joyner 		rman_get_bustag(sc->pci_mem);
115ca853deeSEric Joyner 	sc->osdep.mem_bus_space_handle =
116ca853deeSEric Joyner 		rman_get_bushandle(sc->pci_mem);
117ca853deeSEric Joyner 	sc->osdep.mem_bus_space_size = rman_get_size(sc->pci_mem);
118ca853deeSEric Joyner 	sc->osdep.flush_reg = IAVF_VFGEN_RSTAT;
119ca853deeSEric Joyner 	sc->osdep.dev = dev;
120ca853deeSEric Joyner 
121ca853deeSEric Joyner 	sc->hw.hw_addr = (u8 *)&sc->osdep.mem_bus_space_handle;
122ca853deeSEric Joyner 	sc->hw.back = &sc->osdep;
123ca853deeSEric Joyner 
124ca853deeSEric Joyner 	return (0);
125ca853deeSEric Joyner }
126ca853deeSEric Joyner 
127ca853deeSEric Joyner /**
128ca853deeSEric Joyner  * iavf_init_hw - Initialize the device HW
129ca853deeSEric Joyner  * @hw: device hardware structure
130ca853deeSEric Joyner  * @dev: the stack device_t pointer
131ca853deeSEric Joyner  *
132ca853deeSEric Joyner  * Attach helper function. Gathers information about the (virtual) hardware
133ca853deeSEric Joyner  * for use elsewhere in the driver.
134ca853deeSEric Joyner  */
135ca853deeSEric Joyner static void
136ca853deeSEric Joyner iavf_init_hw(struct iavf_hw *hw, device_t dev)
137ca853deeSEric Joyner {
138ca853deeSEric Joyner 	/* Save off the information about this board */
139ca853deeSEric Joyner 	hw->vendor_id = pci_get_vendor(dev);
140ca853deeSEric Joyner 	hw->device_id = pci_get_device(dev);
141ca853deeSEric Joyner 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
142ca853deeSEric Joyner 	hw->subsystem_vendor_id =
143ca853deeSEric Joyner 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
144ca853deeSEric Joyner 	hw->subsystem_device_id =
145ca853deeSEric Joyner 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
146ca853deeSEric Joyner 
147ca853deeSEric Joyner 	hw->bus.device = pci_get_slot(dev);
148ca853deeSEric Joyner 	hw->bus.func = pci_get_function(dev);
149ca853deeSEric Joyner }
150ca853deeSEric Joyner 
151ca853deeSEric Joyner /**
152ca853deeSEric Joyner  * iavf_sysctl_current_speed - Sysctl to display the current device speed
153ca853deeSEric Joyner  * @oidp: syctl oid pointer
154ca853deeSEric Joyner  * @arg1: pointer to the device softc typecasted to void *
155ca853deeSEric Joyner  * @arg2: unused sysctl argument
156ca853deeSEric Joyner  * @req: sysctl request structure
157ca853deeSEric Joyner  *
158ca853deeSEric Joyner  * Reads the current speed reported from the physical device into a string for
159ca853deeSEric Joyner  * display by the current_speed sysctl.
160ca853deeSEric Joyner  *
161ca853deeSEric Joyner  * @returns zero or an error code on failure.
162ca853deeSEric Joyner  */
163ca853deeSEric Joyner int
164ca853deeSEric Joyner iavf_sysctl_current_speed(SYSCTL_HANDLER_ARGS)
165ca853deeSEric Joyner {
166ca853deeSEric Joyner 	struct iavf_sc *sc = (struct iavf_sc *)arg1;
167ca853deeSEric Joyner 	int error = 0;
168ca853deeSEric Joyner 
169ca853deeSEric Joyner 	UNREFERENCED_PARAMETER(arg2);
170ca853deeSEric Joyner 
171ca853deeSEric Joyner 	if (iavf_driver_is_detaching(sc))
172ca853deeSEric Joyner 		return (ESHUTDOWN);
173ca853deeSEric Joyner 
174ca853deeSEric Joyner 	if (IAVF_CAP_ADV_LINK_SPEED(sc))
175ca853deeSEric Joyner 		error = sysctl_handle_string(oidp,
176ca853deeSEric Joyner 		  __DECONST(char *, iavf_ext_speed_to_str(iavf_adv_speed_to_ext_speed(sc->link_speed_adv))),
177ca853deeSEric Joyner 		  8, req);
178ca853deeSEric Joyner 	else
179ca853deeSEric Joyner 		error = sysctl_handle_string(oidp,
180ca853deeSEric Joyner 		  __DECONST(char *, iavf_vc_speed_to_string(sc->link_speed)),
181ca853deeSEric Joyner 		  8, req);
182ca853deeSEric Joyner 
183ca853deeSEric Joyner 	return (error);
184ca853deeSEric Joyner }
185ca853deeSEric Joyner 
186ca853deeSEric Joyner /**
187ca853deeSEric Joyner  * iavf_reset_complete - Wait for a device reset to complete
188ca853deeSEric Joyner  * @hw: pointer to the hardware structure
189ca853deeSEric Joyner  *
190ca853deeSEric Joyner  * Reads the reset registers and waits until they indicate that a device reset
191ca853deeSEric Joyner  * is complete.
192ca853deeSEric Joyner  *
193ca853deeSEric Joyner  * @pre this function may call pause() and must not be called from a context
194ca853deeSEric Joyner  * that cannot sleep.
195ca853deeSEric Joyner  *
196ca853deeSEric Joyner  * @returns zero on success, or EBUSY if it times out waiting for reset.
197ca853deeSEric Joyner  */
198ca853deeSEric Joyner int
199ca853deeSEric Joyner iavf_reset_complete(struct iavf_hw *hw)
200ca853deeSEric Joyner {
201ca853deeSEric Joyner 	u32 reg;
202ca853deeSEric Joyner 
203ca853deeSEric Joyner 	/* Wait up to ~10 seconds */
204ca853deeSEric Joyner 	for (int i = 0; i < 100; i++) {
205ca853deeSEric Joyner 		reg = rd32(hw, IAVF_VFGEN_RSTAT) &
206ca853deeSEric Joyner 		    IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
207ca853deeSEric Joyner 
208ca853deeSEric Joyner                 if ((reg == VIRTCHNL_VFR_VFACTIVE) ||
209ca853deeSEric Joyner 		    (reg == VIRTCHNL_VFR_COMPLETED))
210ca853deeSEric Joyner 			return (0);
211ca853deeSEric Joyner 		iavf_msec_pause(100);
212ca853deeSEric Joyner 	}
213ca853deeSEric Joyner 
214ca853deeSEric Joyner 	return (EBUSY);
215ca853deeSEric Joyner }
216ca853deeSEric Joyner 
217ca853deeSEric Joyner /**
218ca853deeSEric Joyner  * iavf_setup_vc - Setup virtchnl communication
219ca853deeSEric Joyner  * @sc: device private softc
220ca853deeSEric Joyner  *
221ca853deeSEric Joyner  * iavf_attach() helper function. Initializes the admin queue and attempts to
222ca853deeSEric Joyner  * establish contact with the PF by retrying the initial "API version" message
223ca853deeSEric Joyner  * several times or until the PF responds.
224ca853deeSEric Joyner  *
225ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
226ca853deeSEric Joyner  */
227ca853deeSEric Joyner int
228ca853deeSEric Joyner iavf_setup_vc(struct iavf_sc *sc)
229ca853deeSEric Joyner {
230ca853deeSEric Joyner 	struct iavf_hw *hw = &sc->hw;
231ca853deeSEric Joyner 	device_t dev = sc->dev;
232ca853deeSEric Joyner 	int error = 0, ret_error = 0, asq_retries = 0;
233ca853deeSEric Joyner 	bool send_api_ver_retried = 0;
234ca853deeSEric Joyner 
235ca853deeSEric Joyner 	/* Need to set these AQ parameters before initializing AQ */
236ca853deeSEric Joyner 	hw->aq.num_arq_entries = IAVF_AQ_LEN;
237ca853deeSEric Joyner 	hw->aq.num_asq_entries = IAVF_AQ_LEN;
238ca853deeSEric Joyner 	hw->aq.arq_buf_size = IAVF_AQ_BUF_SZ;
239ca853deeSEric Joyner 	hw->aq.asq_buf_size = IAVF_AQ_BUF_SZ;
240ca853deeSEric Joyner 
241ca853deeSEric Joyner 	for (int i = 0; i < IAVF_AQ_MAX_ERR; i++) {
242ca853deeSEric Joyner 		/* Initialize admin queue */
243ca853deeSEric Joyner 		error = iavf_init_adminq(hw);
244ca853deeSEric Joyner 		if (error) {
245ca853deeSEric Joyner 			device_printf(dev, "%s: init_adminq failed: %d\n",
246ca853deeSEric Joyner 			    __func__, error);
247ca853deeSEric Joyner 			ret_error = 1;
248ca853deeSEric Joyner 			continue;
249ca853deeSEric Joyner 		}
250ca853deeSEric Joyner 
251ca853deeSEric Joyner 		iavf_dbg_init(sc, "Initialized Admin Queue; starting"
252ca853deeSEric Joyner 		    " send_api_ver attempt %d", i+1);
253ca853deeSEric Joyner 
254ca853deeSEric Joyner retry_send:
255ca853deeSEric Joyner 		/* Send VF's API version */
256ca853deeSEric Joyner 		error = iavf_send_api_ver(sc);
257ca853deeSEric Joyner 		if (error) {
258ca853deeSEric Joyner 			iavf_shutdown_adminq(hw);
259ca853deeSEric Joyner 			ret_error = 2;
260ca853deeSEric Joyner 			device_printf(dev, "%s: unable to send api"
261ca853deeSEric Joyner 			    " version to PF on attempt %d, error %d\n",
262ca853deeSEric Joyner 			    __func__, i+1, error);
263ca853deeSEric Joyner 		}
264ca853deeSEric Joyner 
265ca853deeSEric Joyner 		asq_retries = 0;
266ca853deeSEric Joyner 		while (!iavf_asq_done(hw)) {
267ca853deeSEric Joyner 			if (++asq_retries > IAVF_AQ_MAX_ERR) {
268ca853deeSEric Joyner 				iavf_shutdown_adminq(hw);
269ca853deeSEric Joyner 				device_printf(dev, "Admin Queue timeout "
270ca853deeSEric Joyner 				    "(waiting for send_api_ver), %d more tries...\n",
271ca853deeSEric Joyner 				    IAVF_AQ_MAX_ERR - (i + 1));
272ca853deeSEric Joyner 				ret_error = 3;
273ca853deeSEric Joyner 				break;
274ca853deeSEric Joyner 			}
275ca853deeSEric Joyner 			iavf_msec_pause(10);
276ca853deeSEric Joyner 		}
277ca853deeSEric Joyner 		if (asq_retries > IAVF_AQ_MAX_ERR)
278ca853deeSEric Joyner 			continue;
279ca853deeSEric Joyner 
280ca853deeSEric Joyner 		iavf_dbg_init(sc, "Sent API version message to PF");
281ca853deeSEric Joyner 
282ca853deeSEric Joyner 		/* Verify that the VF accepts the PF's API version */
283ca853deeSEric Joyner 		error = iavf_verify_api_ver(sc);
284ca853deeSEric Joyner 		if (error == ETIMEDOUT) {
285ca853deeSEric Joyner 			if (!send_api_ver_retried) {
286ca853deeSEric Joyner 				/* Resend message, one more time */
287ca853deeSEric Joyner 				send_api_ver_retried = true;
288ca853deeSEric Joyner 				device_printf(dev,
289ca853deeSEric Joyner 				    "%s: Timeout while verifying API version on first"
290ca853deeSEric Joyner 				    " try!\n", __func__);
291ca853deeSEric Joyner 				goto retry_send;
292ca853deeSEric Joyner 			} else {
293ca853deeSEric Joyner 				device_printf(dev,
294ca853deeSEric Joyner 				    "%s: Timeout while verifying API version on second"
295ca853deeSEric Joyner 				    " try!\n", __func__);
296ca853deeSEric Joyner 				ret_error = 4;
297ca853deeSEric Joyner 				break;
298ca853deeSEric Joyner 			}
299ca853deeSEric Joyner 		}
300ca853deeSEric Joyner 		if (error) {
301ca853deeSEric Joyner 			device_printf(dev,
302ca853deeSEric Joyner 			    "%s: Unable to verify API version,"
303ca853deeSEric Joyner 			    " error %d\n", __func__, error);
304ca853deeSEric Joyner 			ret_error = 5;
305ca853deeSEric Joyner 		}
306ca853deeSEric Joyner 		break;
307ca853deeSEric Joyner 	}
308ca853deeSEric Joyner 
309ca853deeSEric Joyner 	if (ret_error >= 4)
310ca853deeSEric Joyner 		iavf_shutdown_adminq(hw);
311ca853deeSEric Joyner 	return (ret_error);
312ca853deeSEric Joyner }
313ca853deeSEric Joyner 
314ca853deeSEric Joyner /**
315ca853deeSEric Joyner  * iavf_reset - Requests a VF reset from the PF.
316ca853deeSEric Joyner  * @sc: device private softc
317ca853deeSEric Joyner  *
318ca853deeSEric Joyner  * @pre Requires the VF's Admin Queue to be initialized.
319ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
320ca853deeSEric Joyner  */
321ca853deeSEric Joyner int
322ca853deeSEric Joyner iavf_reset(struct iavf_sc *sc)
323ca853deeSEric Joyner {
324ca853deeSEric Joyner 	struct iavf_hw	*hw = &sc->hw;
325ca853deeSEric Joyner 	device_t	dev = sc->dev;
326ca853deeSEric Joyner 	int		error = 0;
327ca853deeSEric Joyner 
328ca853deeSEric Joyner 	/* Ask the PF to reset us if we are initiating */
329ca853deeSEric Joyner 	if (!iavf_test_state(&sc->state, IAVF_STATE_RESET_PENDING))
330ca853deeSEric Joyner 		iavf_request_reset(sc);
331ca853deeSEric Joyner 
332ca853deeSEric Joyner 	iavf_msec_pause(100);
333ca853deeSEric Joyner 	error = iavf_reset_complete(hw);
334ca853deeSEric Joyner 	if (error) {
335ca853deeSEric Joyner 		device_printf(dev, "%s: VF reset failed\n",
336ca853deeSEric Joyner 		    __func__);
337ca853deeSEric Joyner 		return (error);
338ca853deeSEric Joyner 	}
339ca853deeSEric Joyner 	pci_enable_busmaster(dev);
340ca853deeSEric Joyner 
341ca853deeSEric Joyner 	error = iavf_shutdown_adminq(hw);
342ca853deeSEric Joyner 	if (error) {
343ca853deeSEric Joyner 		device_printf(dev, "%s: shutdown_adminq failed: %d\n",
344ca853deeSEric Joyner 		    __func__, error);
345ca853deeSEric Joyner 		return (error);
346ca853deeSEric Joyner 	}
347ca853deeSEric Joyner 
348ca853deeSEric Joyner 	error = iavf_init_adminq(hw);
349ca853deeSEric Joyner 	if (error) {
350ca853deeSEric Joyner 		device_printf(dev, "%s: init_adminq failed: %d\n",
351ca853deeSEric Joyner 		    __func__, error);
352ca853deeSEric Joyner 		return (error);
353ca853deeSEric Joyner 	}
354ca853deeSEric Joyner 
355ca853deeSEric Joyner 	/* IFLIB: This is called only in the iflib driver */
356ca853deeSEric Joyner 	iavf_enable_adminq_irq(hw);
357ca853deeSEric Joyner 	return (0);
358ca853deeSEric Joyner }
359ca853deeSEric Joyner 
360ca853deeSEric Joyner /**
361ca853deeSEric Joyner  * iavf_enable_admin_irq - Enable the administrative interrupt
362ca853deeSEric Joyner  * @hw: pointer to the hardware structure
363ca853deeSEric Joyner  *
364ca853deeSEric Joyner  * Writes to registers to enable the administrative interrupt cause, in order
365ca853deeSEric Joyner  * to handle non-queue related interrupt events.
366ca853deeSEric Joyner  */
367ca853deeSEric Joyner void
368ca853deeSEric Joyner iavf_enable_adminq_irq(struct iavf_hw *hw)
369ca853deeSEric Joyner {
370ca853deeSEric Joyner 	wr32(hw, IAVF_VFINT_DYN_CTL01,
371ca853deeSEric Joyner 	    IAVF_VFINT_DYN_CTL01_INTENA_MASK |
372ca853deeSEric Joyner 	    IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
373ca853deeSEric Joyner 	    IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
374ca853deeSEric Joyner 	wr32(hw, IAVF_VFINT_ICR0_ENA1, IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
375ca853deeSEric Joyner 	/* flush */
376ca853deeSEric Joyner 	rd32(hw, IAVF_VFGEN_RSTAT);
377ca853deeSEric Joyner }
378ca853deeSEric Joyner 
379ca853deeSEric Joyner /**
380ca853deeSEric Joyner  * iavf_disable_admin_irq - Disable the administrative interrupt cause
381ca853deeSEric Joyner  * @hw: pointer to the hardware structure
382ca853deeSEric Joyner  *
383ca853deeSEric Joyner  * Writes to registers to disable the administrative interrupt cause.
384ca853deeSEric Joyner  */
385ca853deeSEric Joyner void
386ca853deeSEric Joyner iavf_disable_adminq_irq(struct iavf_hw *hw)
387ca853deeSEric Joyner {
388ca853deeSEric Joyner 	wr32(hw, IAVF_VFINT_DYN_CTL01, 0);
389ca853deeSEric Joyner 	wr32(hw, IAVF_VFINT_ICR0_ENA1, 0);
390ca853deeSEric Joyner 	iavf_flush(hw);
391ca853deeSEric Joyner }
392ca853deeSEric Joyner 
393ca853deeSEric Joyner /**
394ca853deeSEric Joyner  * iavf_vf_config - Configure this VF over the virtchnl
395ca853deeSEric Joyner  * @sc: device private softc
396ca853deeSEric Joyner  *
397ca853deeSEric Joyner  * iavf_attach() helper function. Asks the PF for this VF's configuration, and
398ca853deeSEric Joyner  * saves the information if it receives it.
399ca853deeSEric Joyner  *
400ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
401ca853deeSEric Joyner  */
402ca853deeSEric Joyner int
403ca853deeSEric Joyner iavf_vf_config(struct iavf_sc *sc)
404ca853deeSEric Joyner {
405ca853deeSEric Joyner 	struct iavf_hw *hw = &sc->hw;
406ca853deeSEric Joyner 	device_t dev = sc->dev;
407ca853deeSEric Joyner 	int bufsz, error = 0, ret_error = 0;
408ca853deeSEric Joyner 	int asq_retries, retried = 0;
409ca853deeSEric Joyner 
410ca853deeSEric Joyner retry_config:
411ca853deeSEric Joyner 	error = iavf_send_vf_config_msg(sc);
412ca853deeSEric Joyner 	if (error) {
413ca853deeSEric Joyner 		device_printf(dev,
414ca853deeSEric Joyner 		    "%s: Unable to send VF config request, attempt %d,"
415ca853deeSEric Joyner 		    " error %d\n", __func__, retried + 1, error);
416ca853deeSEric Joyner 		ret_error = 2;
417ca853deeSEric Joyner 	}
418ca853deeSEric Joyner 
419ca853deeSEric Joyner 	asq_retries = 0;
420ca853deeSEric Joyner 	while (!iavf_asq_done(hw)) {
421ca853deeSEric Joyner 		if (++asq_retries > IAVF_AQ_MAX_ERR) {
422ca853deeSEric Joyner 			device_printf(dev, "%s: Admin Queue timeout "
423ca853deeSEric Joyner 			    "(waiting for send_vf_config_msg), attempt %d\n",
424ca853deeSEric Joyner 			    __func__, retried + 1);
425ca853deeSEric Joyner 			ret_error = 3;
426ca853deeSEric Joyner 			goto fail;
427ca853deeSEric Joyner 		}
428ca853deeSEric Joyner 		iavf_msec_pause(10);
429ca853deeSEric Joyner 	}
430ca853deeSEric Joyner 
431ca853deeSEric Joyner 	iavf_dbg_init(sc, "Sent VF config message to PF, attempt %d\n",
432ca853deeSEric Joyner 	    retried + 1);
433ca853deeSEric Joyner 
434ca853deeSEric Joyner 	if (!sc->vf_res) {
435ca853deeSEric Joyner 		bufsz = sizeof(struct virtchnl_vf_resource) +
436ca853deeSEric Joyner 		    (IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource));
437ca853deeSEric Joyner 		sc->vf_res = (struct virtchnl_vf_resource *)malloc(bufsz, M_IAVF, M_NOWAIT);
438ca853deeSEric Joyner 		if (!sc->vf_res) {
439ca853deeSEric Joyner 			device_printf(dev,
440ca853deeSEric Joyner 			    "%s: Unable to allocate memory for VF configuration"
441ca853deeSEric Joyner 			    " message from PF on attempt %d\n", __func__, retried + 1);
442ca853deeSEric Joyner 			ret_error = 1;
443ca853deeSEric Joyner 			goto fail;
444ca853deeSEric Joyner 		}
445ca853deeSEric Joyner 	}
446ca853deeSEric Joyner 
447ca853deeSEric Joyner 	/* Check for VF config response */
448ca853deeSEric Joyner 	error = iavf_get_vf_config(sc);
449ca853deeSEric Joyner 	if (error == ETIMEDOUT) {
450ca853deeSEric Joyner 		/* The 1st time we timeout, send the configuration message again */
451ca853deeSEric Joyner 		if (!retried) {
452ca853deeSEric Joyner 			retried++;
453ca853deeSEric Joyner 			goto retry_config;
454ca853deeSEric Joyner 		}
455ca853deeSEric Joyner 		device_printf(dev,
456ca853deeSEric Joyner 		    "%s: iavf_get_vf_config() timed out waiting for a response\n",
457ca853deeSEric Joyner 		    __func__);
458ca853deeSEric Joyner 	}
459ca853deeSEric Joyner 	if (error) {
460ca853deeSEric Joyner 		device_printf(dev,
461ca853deeSEric Joyner 		    "%s: Unable to get VF configuration from PF after %d tries!\n",
462ca853deeSEric Joyner 		    __func__, retried + 1);
463ca853deeSEric Joyner 		ret_error = 4;
464ca853deeSEric Joyner 	}
465ca853deeSEric Joyner 	goto done;
466ca853deeSEric Joyner 
467ca853deeSEric Joyner fail:
468ca853deeSEric Joyner 	free(sc->vf_res, M_IAVF);
469ca853deeSEric Joyner done:
470ca853deeSEric Joyner 	return (ret_error);
471ca853deeSEric Joyner }
472ca853deeSEric Joyner 
473ca853deeSEric Joyner /**
474ca853deeSEric Joyner  * iavf_print_device_info - Print some device parameters at attach
475ca853deeSEric Joyner  * @sc: device private softc
476ca853deeSEric Joyner  *
477ca853deeSEric Joyner  * Log a message about this virtual device's capabilities at attach time.
478ca853deeSEric Joyner  */
479ca853deeSEric Joyner void
480ca853deeSEric Joyner iavf_print_device_info(struct iavf_sc *sc)
481ca853deeSEric Joyner {
482ca853deeSEric Joyner 	device_t dev = sc->dev;
483ca853deeSEric Joyner 
484ca853deeSEric Joyner 	device_printf(dev,
485ca853deeSEric Joyner 	    "VSIs %d, QPs %d, MSI-X %d, RSS sizes: key %d lut %d\n",
486ca853deeSEric Joyner 	    sc->vf_res->num_vsis,
487ca853deeSEric Joyner 	    sc->vf_res->num_queue_pairs,
488ca853deeSEric Joyner 	    sc->vf_res->max_vectors,
489ca853deeSEric Joyner 	    sc->vf_res->rss_key_size,
490ca853deeSEric Joyner 	    sc->vf_res->rss_lut_size);
491ca853deeSEric Joyner 	iavf_dbg_info(sc, "Capabilities=%b\n",
492ca853deeSEric Joyner 	    sc->vf_res->vf_cap_flags, IAVF_PRINTF_VF_OFFLOAD_FLAGS);
493ca853deeSEric Joyner }
494ca853deeSEric Joyner 
495ca853deeSEric Joyner /**
496ca853deeSEric Joyner  * iavf_get_vsi_res_from_vf_res - Get VSI parameters and info for this VF
497ca853deeSEric Joyner  * @sc: device private softc
498ca853deeSEric Joyner  *
499ca853deeSEric Joyner  * Get the VSI parameters and information from the general VF resource info
500ca853deeSEric Joyner  * received by the physical device.
501ca853deeSEric Joyner  *
502ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
503ca853deeSEric Joyner  */
504ca853deeSEric Joyner int
505ca853deeSEric Joyner iavf_get_vsi_res_from_vf_res(struct iavf_sc *sc)
506ca853deeSEric Joyner {
507ca853deeSEric Joyner 	struct iavf_vsi *vsi = &sc->vsi;
508ca853deeSEric Joyner 	device_t dev = sc->dev;
509ca853deeSEric Joyner 
510ca853deeSEric Joyner 	sc->vsi_res = NULL;
511ca853deeSEric Joyner 
512ca853deeSEric Joyner 	for (int i = 0; i < sc->vf_res->num_vsis; i++) {
513ca853deeSEric Joyner 		/* XXX: We only use the first VSI we find */
51467be1e19SDimitry Andric 		if (sc->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
515ca853deeSEric Joyner 			sc->vsi_res = &sc->vf_res->vsi_res[i];
516ca853deeSEric Joyner 	}
517ca853deeSEric Joyner 	if (!sc->vsi_res) {
518ca853deeSEric Joyner 		device_printf(dev, "%s: no LAN VSI found\n", __func__);
519ca853deeSEric Joyner 		return (EIO);
520ca853deeSEric Joyner 	}
521ca853deeSEric Joyner 
522ca853deeSEric Joyner 	vsi->id = sc->vsi_res->vsi_id;
523ca853deeSEric Joyner 	return (0);
524ca853deeSEric Joyner }
525ca853deeSEric Joyner 
526ca853deeSEric Joyner /**
527ca853deeSEric Joyner  * iavf_set_mac_addresses - Set the MAC address for this interface
528ca853deeSEric Joyner  * @sc: device private softc
529ca853deeSEric Joyner  *
530ca853deeSEric Joyner  * Set the permanent MAC address field in the HW structure. If a MAC address
531ca853deeSEric Joyner  * has not yet been set for this device by the physical function, generate one
532ca853deeSEric Joyner  * randomly.
533ca853deeSEric Joyner  */
534ca853deeSEric Joyner void
535ca853deeSEric Joyner iavf_set_mac_addresses(struct iavf_sc *sc)
536ca853deeSEric Joyner {
537ca853deeSEric Joyner 	struct iavf_hw *hw = &sc->hw;
538ca853deeSEric Joyner 	device_t dev = sc->dev;
539ca853deeSEric Joyner 	u8 addr[ETHER_ADDR_LEN];
540ca853deeSEric Joyner 
541ca853deeSEric Joyner 	/* If no mac address was assigned just make a random one */
542ca853deeSEric Joyner 	if (ETHER_IS_ZERO(hw->mac.addr)) {
543ca853deeSEric Joyner 		arc4rand(&addr, sizeof(addr), 0);
544ca853deeSEric Joyner 		addr[0] &= 0xFE;
545ca853deeSEric Joyner 		addr[0] |= 0x02;
546ca853deeSEric Joyner 		memcpy(hw->mac.addr, addr, sizeof(addr));
547ca853deeSEric Joyner 		device_printf(dev, "Generated random MAC address\n");
548ca853deeSEric Joyner 	}
549ca853deeSEric Joyner 	memcpy(hw->mac.perm_addr, hw->mac.addr, ETHER_ADDR_LEN);
550ca853deeSEric Joyner }
551ca853deeSEric Joyner 
552ca853deeSEric Joyner /**
553ca853deeSEric Joyner  * iavf_init_filters - Initialize filter structures
554ca853deeSEric Joyner  * @sc: device private softc
555ca853deeSEric Joyner  *
556ca853deeSEric Joyner  * Initialize the MAC and VLAN filter list heads.
557ca853deeSEric Joyner  *
558ca853deeSEric Joyner  * @remark this is intended to be called only once during the device attach
559ca853deeSEric Joyner  * process.
560ca853deeSEric Joyner  *
561ca853deeSEric Joyner  * @pre Because it uses M_WAITOK, this function should only be called in
562ca853deeSEric Joyner  * a context that is safe to sleep.
563ca853deeSEric Joyner  */
564ca853deeSEric Joyner void
565ca853deeSEric Joyner iavf_init_filters(struct iavf_sc *sc)
566ca853deeSEric Joyner {
567ca853deeSEric Joyner 	sc->mac_filters = (struct mac_list *)malloc(sizeof(struct iavf_mac_filter),
568ca853deeSEric Joyner 	    M_IAVF, M_WAITOK | M_ZERO);
569ca853deeSEric Joyner 	SLIST_INIT(sc->mac_filters);
570ca853deeSEric Joyner 	sc->vlan_filters = (struct vlan_list *)malloc(sizeof(struct iavf_vlan_filter),
571ca853deeSEric Joyner 	    M_IAVF, M_WAITOK | M_ZERO);
572ca853deeSEric Joyner 	SLIST_INIT(sc->vlan_filters);
573ca853deeSEric Joyner }
574ca853deeSEric Joyner 
575ca853deeSEric Joyner /**
576ca853deeSEric Joyner  * iavf_free_filters - Release filter lists
577ca853deeSEric Joyner  * @sc: device private softc
578ca853deeSEric Joyner  *
579ca853deeSEric Joyner  * Free the MAC and VLAN filter lists.
580ca853deeSEric Joyner  *
581ca853deeSEric Joyner  * @remark this is intended to be called only once during the device detach
582ca853deeSEric Joyner  * process.
583ca853deeSEric Joyner  */
584ca853deeSEric Joyner void
585ca853deeSEric Joyner iavf_free_filters(struct iavf_sc *sc)
586ca853deeSEric Joyner {
587ca853deeSEric Joyner 	struct iavf_mac_filter *f;
588ca853deeSEric Joyner 	struct iavf_vlan_filter *v;
589ca853deeSEric Joyner 
590ca853deeSEric Joyner 	while (!SLIST_EMPTY(sc->mac_filters)) {
591ca853deeSEric Joyner 		f = SLIST_FIRST(sc->mac_filters);
592ca853deeSEric Joyner 		SLIST_REMOVE_HEAD(sc->mac_filters, next);
593ca853deeSEric Joyner 		free(f, M_IAVF);
594ca853deeSEric Joyner 	}
595ca853deeSEric Joyner 	free(sc->mac_filters, M_IAVF);
596ca853deeSEric Joyner 	while (!SLIST_EMPTY(sc->vlan_filters)) {
597ca853deeSEric Joyner 		v = SLIST_FIRST(sc->vlan_filters);
598ca853deeSEric Joyner 		SLIST_REMOVE_HEAD(sc->vlan_filters, next);
599ca853deeSEric Joyner 		free(v, M_IAVF);
600ca853deeSEric Joyner 	}
601ca853deeSEric Joyner 	free(sc->vlan_filters, M_IAVF);
602ca853deeSEric Joyner }
603ca853deeSEric Joyner 
604ca853deeSEric Joyner /**
605ca853deeSEric Joyner  * iavf_add_device_sysctls_common - Initialize common device sysctls
606ca853deeSEric Joyner  * @sc: device private softc
607ca853deeSEric Joyner  *
608ca853deeSEric Joyner  * Setup sysctls common to both the iflib and legacy drivers.
609ca853deeSEric Joyner  */
610ca853deeSEric Joyner void
611ca853deeSEric Joyner iavf_add_device_sysctls_common(struct iavf_sc *sc)
612ca853deeSEric Joyner {
613ca853deeSEric Joyner 	device_t dev = sc->dev;
614ca853deeSEric Joyner 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
615ca853deeSEric Joyner 	struct sysctl_oid_list *ctx_list =
616ca853deeSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
617ca853deeSEric Joyner 
618ca853deeSEric Joyner 	SYSCTL_ADD_PROC(ctx, ctx_list,
619ca853deeSEric Joyner 	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
620ca853deeSEric Joyner 	    sc, 0, iavf_sysctl_current_speed, "A", "Current Port Speed");
621ca853deeSEric Joyner 
622ca853deeSEric Joyner 	SYSCTL_ADD_PROC(ctx, ctx_list,
623ca853deeSEric Joyner 	    OID_AUTO, "tx_itr", CTLTYPE_INT | CTLFLAG_RW,
624ca853deeSEric Joyner 	    sc, 0, iavf_sysctl_tx_itr, "I",
625ca853deeSEric Joyner 	    "Immediately set TX ITR value for all queues");
626ca853deeSEric Joyner 
627ca853deeSEric Joyner 	SYSCTL_ADD_PROC(ctx, ctx_list,
628ca853deeSEric Joyner 	    OID_AUTO, "rx_itr", CTLTYPE_INT | CTLFLAG_RW,
629ca853deeSEric Joyner 	    sc, 0, iavf_sysctl_rx_itr, "I",
630ca853deeSEric Joyner 	    "Immediately set RX ITR value for all queues");
631ca853deeSEric Joyner 
632ca853deeSEric Joyner 	SYSCTL_ADD_UQUAD(ctx, ctx_list,
633ca853deeSEric Joyner 	    OID_AUTO, "admin_irq", CTLFLAG_RD,
634ca853deeSEric Joyner 	    &sc->admin_irq, "Admin Queue IRQ Handled");
635ca853deeSEric Joyner }
636ca853deeSEric Joyner 
637ca853deeSEric Joyner /**
638ca853deeSEric Joyner  * iavf_add_debug_sysctls_common - Initialize common debug sysctls
639ca853deeSEric Joyner  * @sc: device private softc
640ca853deeSEric Joyner  * @debug_list: pionter to debug sysctl node
641ca853deeSEric Joyner  *
642ca853deeSEric Joyner  * Setup sysctls used for debugging the device driver into the debug sysctl
643ca853deeSEric Joyner  * node.
644ca853deeSEric Joyner  */
645ca853deeSEric Joyner void
646ca853deeSEric Joyner iavf_add_debug_sysctls_common(struct iavf_sc *sc, struct sysctl_oid_list *debug_list)
647ca853deeSEric Joyner {
648ca853deeSEric Joyner 	device_t dev = sc->dev;
649ca853deeSEric Joyner 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
650ca853deeSEric Joyner 
651ca853deeSEric Joyner 	SYSCTL_ADD_UINT(ctx, debug_list,
652ca853deeSEric Joyner 	    OID_AUTO, "shared_debug_mask", CTLFLAG_RW,
653ca853deeSEric Joyner 	    &sc->hw.debug_mask, 0, "Shared code debug message level");
654ca853deeSEric Joyner 
655ca853deeSEric Joyner 	SYSCTL_ADD_UINT(ctx, debug_list,
656ca853deeSEric Joyner 	    OID_AUTO, "core_debug_mask", CTLFLAG_RW,
657ca853deeSEric Joyner 	    (unsigned int *)&sc->dbg_mask, 0, "Non-shared code debug message level");
658ca853deeSEric Joyner 
659ca853deeSEric Joyner 	SYSCTL_ADD_PROC(ctx, debug_list,
660ca853deeSEric Joyner 	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
661ca853deeSEric Joyner 	    sc, 0, iavf_sysctl_sw_filter_list, "A", "SW Filter List");
662ca853deeSEric Joyner }
663ca853deeSEric Joyner 
664ca853deeSEric Joyner /**
665ca853deeSEric Joyner  * iavf_sysctl_tx_itr - Sysctl to set the Tx ITR value
666ca853deeSEric Joyner  * @oidp: sysctl oid pointer
667ca853deeSEric Joyner  * @arg1: pointer to the device softc
668ca853deeSEric Joyner  * @arg2: unused sysctl argument
669ca853deeSEric Joyner  * @req: sysctl req pointer
670ca853deeSEric Joyner  *
671ca853deeSEric Joyner  * On read, returns the Tx ITR value for all of the VF queues. On write,
672ca853deeSEric Joyner  * update the Tx ITR registers with the new Tx ITR value.
673ca853deeSEric Joyner  *
674ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
675ca853deeSEric Joyner  */
676ca853deeSEric Joyner int
677ca853deeSEric Joyner iavf_sysctl_tx_itr(SYSCTL_HANDLER_ARGS)
678ca853deeSEric Joyner {
679ca853deeSEric Joyner 	struct iavf_sc *sc = (struct iavf_sc *)arg1;
680ca853deeSEric Joyner 	device_t dev = sc->dev;
681ca853deeSEric Joyner 	int requested_tx_itr;
682ca853deeSEric Joyner 	int error = 0;
683ca853deeSEric Joyner 
684ca853deeSEric Joyner 	UNREFERENCED_PARAMETER(arg2);
685ca853deeSEric Joyner 
686ca853deeSEric Joyner 	if (iavf_driver_is_detaching(sc))
687ca853deeSEric Joyner 		return (ESHUTDOWN);
688ca853deeSEric Joyner 
689ca853deeSEric Joyner 	requested_tx_itr = sc->tx_itr;
690ca853deeSEric Joyner 	error = sysctl_handle_int(oidp, &requested_tx_itr, 0, req);
691ca853deeSEric Joyner 	if ((error) || (req->newptr == NULL))
692ca853deeSEric Joyner 		return (error);
693ca853deeSEric Joyner 	if (requested_tx_itr < 0 || requested_tx_itr > IAVF_MAX_ITR) {
694ca853deeSEric Joyner 		device_printf(dev,
695ca853deeSEric Joyner 		    "Invalid TX itr value; value must be between 0 and %d\n",
696ca853deeSEric Joyner 		        IAVF_MAX_ITR);
697ca853deeSEric Joyner 		return (EINVAL);
698ca853deeSEric Joyner 	}
699ca853deeSEric Joyner 
700ca853deeSEric Joyner 	sc->tx_itr = requested_tx_itr;
701ca853deeSEric Joyner 	iavf_configure_tx_itr(sc);
702ca853deeSEric Joyner 
703ca853deeSEric Joyner 	return (error);
704ca853deeSEric Joyner }
705ca853deeSEric Joyner 
706ca853deeSEric Joyner /**
707ca853deeSEric Joyner  * iavf_sysctl_rx_itr - Sysctl to set the Rx ITR value
708ca853deeSEric Joyner  * @oidp: sysctl oid pointer
709ca853deeSEric Joyner  * @arg1: pointer to the device softc
710ca853deeSEric Joyner  * @arg2: unused sysctl argument
711ca853deeSEric Joyner  * @req: sysctl req pointer
712ca853deeSEric Joyner  *
713ca853deeSEric Joyner  * On read, returns the Rx ITR value for all of the VF queues. On write,
714ca853deeSEric Joyner  * update the ITR registers with the new Rx ITR value.
715ca853deeSEric Joyner  *
716ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
717ca853deeSEric Joyner  */
718ca853deeSEric Joyner int
719ca853deeSEric Joyner iavf_sysctl_rx_itr(SYSCTL_HANDLER_ARGS)
720ca853deeSEric Joyner {
721ca853deeSEric Joyner 	struct iavf_sc *sc = (struct iavf_sc *)arg1;
722ca853deeSEric Joyner 	device_t dev = sc->dev;
723ca853deeSEric Joyner 	int requested_rx_itr;
724ca853deeSEric Joyner 	int error = 0;
725ca853deeSEric Joyner 
726ca853deeSEric Joyner 	UNREFERENCED_PARAMETER(arg2);
727ca853deeSEric Joyner 
728ca853deeSEric Joyner 	if (iavf_driver_is_detaching(sc))
729ca853deeSEric Joyner 		return (ESHUTDOWN);
730ca853deeSEric Joyner 
731ca853deeSEric Joyner 	requested_rx_itr = sc->rx_itr;
732ca853deeSEric Joyner 	error = sysctl_handle_int(oidp, &requested_rx_itr, 0, req);
733ca853deeSEric Joyner 	if ((error) || (req->newptr == NULL))
734ca853deeSEric Joyner 		return (error);
735ca853deeSEric Joyner 	if (requested_rx_itr < 0 || requested_rx_itr > IAVF_MAX_ITR) {
736ca853deeSEric Joyner 		device_printf(dev,
737ca853deeSEric Joyner 		    "Invalid RX itr value; value must be between 0 and %d\n",
738ca853deeSEric Joyner 		        IAVF_MAX_ITR);
739ca853deeSEric Joyner 		return (EINVAL);
740ca853deeSEric Joyner 	}
741ca853deeSEric Joyner 
742ca853deeSEric Joyner 	sc->rx_itr = requested_rx_itr;
743ca853deeSEric Joyner 	iavf_configure_rx_itr(sc);
744ca853deeSEric Joyner 
745ca853deeSEric Joyner 	return (error);
746ca853deeSEric Joyner }
747ca853deeSEric Joyner 
748ca853deeSEric Joyner /**
749ca853deeSEric Joyner  * iavf_configure_tx_itr - Configure the Tx ITR
750ca853deeSEric Joyner  * @sc: device private softc
751ca853deeSEric Joyner  *
752ca853deeSEric Joyner  * Updates the ITR registers with a new Tx ITR setting.
753ca853deeSEric Joyner  */
754ca853deeSEric Joyner void
755ca853deeSEric Joyner iavf_configure_tx_itr(struct iavf_sc *sc)
756ca853deeSEric Joyner {
757ca853deeSEric Joyner 	struct iavf_hw		*hw = &sc->hw;
758ca853deeSEric Joyner 	struct iavf_vsi		*vsi = &sc->vsi;
759ca853deeSEric Joyner 	struct iavf_tx_queue	*que = vsi->tx_queues;
760ca853deeSEric Joyner 
761ca853deeSEric Joyner 	vsi->tx_itr_setting = sc->tx_itr;
762ca853deeSEric Joyner 
763ca853deeSEric Joyner 	for (int i = 0; i < IAVF_NTXQS(vsi); i++, que++) {
764ca853deeSEric Joyner 		struct tx_ring	*txr = &que->txr;
765ca853deeSEric Joyner 
766ca853deeSEric Joyner 		wr32(hw, IAVF_VFINT_ITRN1(IAVF_TX_ITR, i),
767ca853deeSEric Joyner 		    vsi->tx_itr_setting);
768ca853deeSEric Joyner 		txr->itr = vsi->tx_itr_setting;
769ca853deeSEric Joyner 		txr->latency = IAVF_AVE_LATENCY;
770ca853deeSEric Joyner 	}
771ca853deeSEric Joyner }
772ca853deeSEric Joyner 
773ca853deeSEric Joyner /**
774ca853deeSEric Joyner  * iavf_configure_rx_itr - Configure the Rx ITR
775ca853deeSEric Joyner  * @sc: device private softc
776ca853deeSEric Joyner  *
777ca853deeSEric Joyner  * Updates the ITR registers with a new Rx ITR setting.
778ca853deeSEric Joyner  */
779ca853deeSEric Joyner void
780ca853deeSEric Joyner iavf_configure_rx_itr(struct iavf_sc *sc)
781ca853deeSEric Joyner {
782ca853deeSEric Joyner 	struct iavf_hw		*hw = &sc->hw;
783ca853deeSEric Joyner 	struct iavf_vsi		*vsi = &sc->vsi;
784ca853deeSEric Joyner 	struct iavf_rx_queue	*que = vsi->rx_queues;
785ca853deeSEric Joyner 
786ca853deeSEric Joyner 	vsi->rx_itr_setting = sc->rx_itr;
787ca853deeSEric Joyner 
788ca853deeSEric Joyner 	for (int i = 0; i < IAVF_NRXQS(vsi); i++, que++) {
789ca853deeSEric Joyner 		struct rx_ring	*rxr = &que->rxr;
790ca853deeSEric Joyner 
791ca853deeSEric Joyner 		wr32(hw, IAVF_VFINT_ITRN1(IAVF_RX_ITR, i),
792ca853deeSEric Joyner 		    vsi->rx_itr_setting);
793ca853deeSEric Joyner 		rxr->itr = vsi->rx_itr_setting;
794ca853deeSEric Joyner 		rxr->latency = IAVF_AVE_LATENCY;
795ca853deeSEric Joyner 	}
796ca853deeSEric Joyner }
797ca853deeSEric Joyner 
798ca853deeSEric Joyner /**
799ca853deeSEric Joyner  * iavf_create_debug_sysctl_tree - Create a debug sysctl node
800ca853deeSEric Joyner  * @sc: device private softc
801ca853deeSEric Joyner  *
802ca853deeSEric Joyner  * Create a sysctl node meant to hold sysctls used to print debug information.
803ca853deeSEric Joyner  * Mark it as CTLFLAG_SKIP so that these sysctls do not show up in the
804ca853deeSEric Joyner  * "sysctl -a" output.
805ca853deeSEric Joyner  *
806ca853deeSEric Joyner  * @returns a pointer to the created sysctl node.
807ca853deeSEric Joyner  */
808ca853deeSEric Joyner struct sysctl_oid_list *
809ca853deeSEric Joyner iavf_create_debug_sysctl_tree(struct iavf_sc *sc)
810ca853deeSEric Joyner {
811ca853deeSEric Joyner 	device_t dev = sc->dev;
812ca853deeSEric Joyner 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
813ca853deeSEric Joyner 	struct sysctl_oid_list *ctx_list =
814ca853deeSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
815ca853deeSEric Joyner 	struct sysctl_oid *debug_node;
816ca853deeSEric Joyner 
817ca853deeSEric Joyner 	debug_node = SYSCTL_ADD_NODE(ctx, ctx_list,
818ca853deeSEric Joyner 	    OID_AUTO, "debug", CTLFLAG_RD | CTLFLAG_SKIP, NULL, "Debug Sysctls");
819ca853deeSEric Joyner 
820ca853deeSEric Joyner 	return (SYSCTL_CHILDREN(debug_node));
821ca853deeSEric Joyner }
822ca853deeSEric Joyner 
823ca853deeSEric Joyner /**
824ca853deeSEric Joyner  * iavf_add_vsi_sysctls - Add sysctls for a given VSI
825ca853deeSEric Joyner  * @dev: device pointer
826ca853deeSEric Joyner  * @vsi: pointer to the VSI
827ca853deeSEric Joyner  * @ctx: sysctl context to add to
828ca853deeSEric Joyner  * @sysctl_name: name of the sysctl node (containing the VSI number)
829ca853deeSEric Joyner  *
830ca853deeSEric Joyner  * Adds a new sysctl node for holding specific sysctls for the given VSI.
831ca853deeSEric Joyner  */
832ca853deeSEric Joyner void
833ca853deeSEric Joyner iavf_add_vsi_sysctls(device_t dev, struct iavf_vsi *vsi,
834ca853deeSEric Joyner     struct sysctl_ctx_list *ctx, const char *sysctl_name)
835ca853deeSEric Joyner {
836ca853deeSEric Joyner 	struct sysctl_oid *tree;
837ca853deeSEric Joyner 	struct sysctl_oid_list *child;
838ca853deeSEric Joyner 	struct sysctl_oid_list *vsi_list;
839ca853deeSEric Joyner 
840ca853deeSEric Joyner 	tree = device_get_sysctl_tree(dev);
841ca853deeSEric Joyner 	child = SYSCTL_CHILDREN(tree);
842ca853deeSEric Joyner 	vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name,
843ca853deeSEric Joyner 				   CTLFLAG_RD, NULL, "VSI Number");
844ca853deeSEric Joyner 	vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
845ca853deeSEric Joyner 
846ca853deeSEric Joyner 	iavf_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats);
847ca853deeSEric Joyner }
848ca853deeSEric Joyner 
849ca853deeSEric Joyner /**
850ca853deeSEric Joyner  * iavf_sysctl_sw_filter_list - Dump software filters
851ca853deeSEric Joyner  * @oidp: sysctl oid pointer
852ca853deeSEric Joyner  * @arg1: pointer to the device softc
853ca853deeSEric Joyner  * @arg2: unused sysctl argument
854ca853deeSEric Joyner  * @req: sysctl req pointer
855ca853deeSEric Joyner  *
856ca853deeSEric Joyner  * On read, generates a string which lists the MAC and VLAN filters added to
857ca853deeSEric Joyner  * this virtual device. Useful for debugging to see whether or not the
858ca853deeSEric Joyner  * expected filters have been configured by software.
859ca853deeSEric Joyner  *
860ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
861ca853deeSEric Joyner  */
862ca853deeSEric Joyner int
863ca853deeSEric Joyner iavf_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
864ca853deeSEric Joyner {
865ca853deeSEric Joyner 	struct iavf_sc *sc = (struct iavf_sc *)arg1;
866ca853deeSEric Joyner 	struct iavf_mac_filter *f;
867ca853deeSEric Joyner 	struct iavf_vlan_filter *v;
868ca853deeSEric Joyner 	device_t dev = sc->dev;
869ca853deeSEric Joyner 	int ftl_len, ftl_counter = 0, error = 0;
870ca853deeSEric Joyner 	struct sbuf *buf;
871ca853deeSEric Joyner 
872ca853deeSEric Joyner 	UNREFERENCED_2PARAMETER(arg2, oidp);
873ca853deeSEric Joyner 
874ca853deeSEric Joyner 	if (iavf_driver_is_detaching(sc))
875ca853deeSEric Joyner 		return (ESHUTDOWN);
876ca853deeSEric Joyner 
877ca853deeSEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
878ca853deeSEric Joyner 	if (!buf) {
879ca853deeSEric Joyner 		device_printf(dev, "Could not allocate sbuf for output.\n");
880ca853deeSEric Joyner 		return (ENOMEM);
881ca853deeSEric Joyner 	}
882ca853deeSEric Joyner 
883ca853deeSEric Joyner 	sbuf_printf(buf, "\n");
884ca853deeSEric Joyner 
885ca853deeSEric Joyner 	/* Print MAC filters */
886ca853deeSEric Joyner 	sbuf_printf(buf, "MAC Filters:\n");
887ca853deeSEric Joyner 	ftl_len = 0;
888ca853deeSEric Joyner 	SLIST_FOREACH(f, sc->mac_filters, next)
889ca853deeSEric Joyner 		ftl_len++;
890ca853deeSEric Joyner 	if (ftl_len < 1)
891ca853deeSEric Joyner 		sbuf_printf(buf, "(none)\n");
892ca853deeSEric Joyner 	else {
893ca853deeSEric Joyner 		SLIST_FOREACH(f, sc->mac_filters, next) {
894ca853deeSEric Joyner 			sbuf_printf(buf,
895ca853deeSEric Joyner 			    MAC_FORMAT ", flags %#06x\n",
896ca853deeSEric Joyner 			    MAC_FORMAT_ARGS(f->macaddr), f->flags);
897ca853deeSEric Joyner 		}
898ca853deeSEric Joyner 	}
899ca853deeSEric Joyner 
900ca853deeSEric Joyner 	/* Print VLAN filters */
901ca853deeSEric Joyner 	sbuf_printf(buf, "VLAN Filters:\n");
902ca853deeSEric Joyner 	ftl_len = 0;
903ca853deeSEric Joyner 	SLIST_FOREACH(v, sc->vlan_filters, next)
904ca853deeSEric Joyner 		ftl_len++;
905ca853deeSEric Joyner 	if (ftl_len < 1)
906ca853deeSEric Joyner 		sbuf_printf(buf, "(none)");
907ca853deeSEric Joyner 	else {
908ca853deeSEric Joyner 		SLIST_FOREACH(v, sc->vlan_filters, next) {
909ca853deeSEric Joyner 			sbuf_printf(buf,
910ca853deeSEric Joyner 			    "%d, flags %#06x",
911ca853deeSEric Joyner 			    v->vlan, v->flags);
912ca853deeSEric Joyner 			/* don't print '\n' for last entry */
913ca853deeSEric Joyner 			if (++ftl_counter != ftl_len)
914ca853deeSEric Joyner 				sbuf_printf(buf, "\n");
915ca853deeSEric Joyner 		}
916ca853deeSEric Joyner 	}
917ca853deeSEric Joyner 
918ca853deeSEric Joyner 	error = sbuf_finish(buf);
919ca853deeSEric Joyner 	if (error)
920ca853deeSEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
921ca853deeSEric Joyner 
922ca853deeSEric Joyner 	sbuf_delete(buf);
923ca853deeSEric Joyner 	return (error);
924ca853deeSEric Joyner }
925ca853deeSEric Joyner 
926ca853deeSEric Joyner /**
927ca853deeSEric Joyner  * iavf_media_status_common - Get media status for this device
928ca853deeSEric Joyner  * @sc: device softc pointer
929ca853deeSEric Joyner  * @ifmr: ifmedia request structure
930ca853deeSEric Joyner  *
931ca853deeSEric Joyner  * Report the media status for this device into the given ifmr structure.
932ca853deeSEric Joyner  */
933ca853deeSEric Joyner void
934ca853deeSEric Joyner iavf_media_status_common(struct iavf_sc *sc, struct ifmediareq *ifmr)
935ca853deeSEric Joyner {
936ca853deeSEric Joyner 	enum iavf_ext_link_speed ext_speed;
937ca853deeSEric Joyner 
938ca853deeSEric Joyner 	iavf_update_link_status(sc);
939ca853deeSEric Joyner 
940ca853deeSEric Joyner 	ifmr->ifm_status = IFM_AVALID;
941ca853deeSEric Joyner 	ifmr->ifm_active = IFM_ETHER;
942ca853deeSEric Joyner 
943ca853deeSEric Joyner 	if (!sc->link_up)
944ca853deeSEric Joyner 		return;
945ca853deeSEric Joyner 
946ca853deeSEric Joyner 	ifmr->ifm_status |= IFM_ACTIVE;
947ca853deeSEric Joyner 	/* Hardware is always full-duplex */
948ca853deeSEric Joyner 	ifmr->ifm_active |= IFM_FDX;
949ca853deeSEric Joyner 
950ca853deeSEric Joyner 	/* Based on the link speed reported by the PF over the AdminQ, choose a
951ca853deeSEric Joyner 	 * PHY type to report. This isn't 100% correct since we don't really
952ca853deeSEric Joyner 	 * know the underlying PHY type of the PF, but at least we can report
953ca853deeSEric Joyner 	 * a valid link speed...
954ca853deeSEric Joyner 	 */
955ca853deeSEric Joyner 	if (IAVF_CAP_ADV_LINK_SPEED(sc))
956ca853deeSEric Joyner 		ext_speed = iavf_adv_speed_to_ext_speed(sc->link_speed_adv);
957ca853deeSEric Joyner 	else
958ca853deeSEric Joyner 		ext_speed = iavf_vc_speed_to_ext_speed(sc->link_speed);
959ca853deeSEric Joyner 
960ca853deeSEric Joyner 	ifmr->ifm_active |= iavf_ext_speed_to_ifmedia(ext_speed);
961ca853deeSEric Joyner }
962ca853deeSEric Joyner 
963ca853deeSEric Joyner /**
964ca853deeSEric Joyner  * iavf_media_change_common - Change the media type for this device
965ca853deeSEric Joyner  * @ifp: ifnet structure
966ca853deeSEric Joyner  *
967ca853deeSEric Joyner  * @returns ENODEV because changing the media and speed is not supported.
968ca853deeSEric Joyner  */
969ca853deeSEric Joyner int
970d8096b2dSJustin Hibbits iavf_media_change_common(if_t ifp)
971ca853deeSEric Joyner {
972ca853deeSEric Joyner 	if_printf(ifp, "Changing speed is not supported\n");
973ca853deeSEric Joyner 
974ca853deeSEric Joyner 	return (ENODEV);
975ca853deeSEric Joyner }
976ca853deeSEric Joyner 
977ca853deeSEric Joyner /**
978ca853deeSEric Joyner  * iavf_set_initial_baudrate - Set the initial device baudrate
979ca853deeSEric Joyner  * @ifp: ifnet structure
980ca853deeSEric Joyner  *
981ca853deeSEric Joyner  * Set the baudrate for this ifnet structure to the expected initial value of
982ca853deeSEric Joyner  * 40Gbps. This maybe updated to a lower baudrate after the physical function
983ca853deeSEric Joyner  * reports speed to us over the virtchnl interface.
984ca853deeSEric Joyner  */
985ca853deeSEric Joyner void
986d8096b2dSJustin Hibbits iavf_set_initial_baudrate(if_t ifp)
987ca853deeSEric Joyner {
988ca853deeSEric Joyner 	if_setbaudrate(ifp, IF_Gbps(40));
989ca853deeSEric Joyner }
990ca853deeSEric Joyner 
991ca853deeSEric Joyner /**
992ca853deeSEric Joyner  * iavf_add_sysctls_eth_stats - Add ethernet statistics sysctls
993ca853deeSEric Joyner  * @ctx: the sysctl ctx to add to
994ca853deeSEric Joyner  * @child: the node to add the sysctls to
995ca853deeSEric Joyner  * @eth_stats: ethernet stats structure
996ca853deeSEric Joyner  *
997ca853deeSEric Joyner  * Creates sysctls that report the values of the provided ethernet stats
998ca853deeSEric Joyner  * structure.
999ca853deeSEric Joyner  */
1000ca853deeSEric Joyner void
1001ca853deeSEric Joyner iavf_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
1002ca853deeSEric Joyner 	struct sysctl_oid_list *child,
1003ca853deeSEric Joyner 	struct iavf_eth_stats *eth_stats)
1004ca853deeSEric Joyner {
1005ca853deeSEric Joyner 	struct iavf_sysctl_info ctls[] =
1006ca853deeSEric Joyner 	{
1007ca853deeSEric Joyner 		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
1008ca853deeSEric Joyner 		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
1009ca853deeSEric Joyner 			"Unicast Packets Received"},
1010ca853deeSEric Joyner 		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
1011ca853deeSEric Joyner 			"Multicast Packets Received"},
1012ca853deeSEric Joyner 		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
1013ca853deeSEric Joyner 			"Broadcast Packets Received"},
1014ca853deeSEric Joyner 		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
1015ca853deeSEric Joyner 		{&eth_stats->rx_unknown_protocol, "rx_unknown_proto",
1016ca853deeSEric Joyner 			"RX unknown protocol packets"},
1017ca853deeSEric Joyner 		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
1018ca853deeSEric Joyner 		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
1019ca853deeSEric Joyner 		{&eth_stats->tx_multicast, "mcast_pkts_txd",
1020ca853deeSEric Joyner 			"Multicast Packets Transmitted"},
1021ca853deeSEric Joyner 		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
1022ca853deeSEric Joyner 			"Broadcast Packets Transmitted"},
1023ca853deeSEric Joyner 		{&eth_stats->tx_errors, "tx_errors", "TX packet errors"},
1024ca853deeSEric Joyner 		// end
1025ca853deeSEric Joyner 		{0,0,0}
1026ca853deeSEric Joyner 	};
1027ca853deeSEric Joyner 
1028ca853deeSEric Joyner 	struct iavf_sysctl_info *entry = ctls;
1029ca853deeSEric Joyner 
1030ca853deeSEric Joyner 	while (entry->stat != 0)
1031ca853deeSEric Joyner 	{
1032ca853deeSEric Joyner 		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
1033ca853deeSEric Joyner 				CTLFLAG_RD, entry->stat,
1034ca853deeSEric Joyner 				entry->description);
1035ca853deeSEric Joyner 		entry++;
1036ca853deeSEric Joyner 	}
1037ca853deeSEric Joyner }
1038ca853deeSEric Joyner 
1039ca853deeSEric Joyner /**
1040ca853deeSEric Joyner  * iavf_max_vc_speed_to_value - Convert link speed to IF speed value
1041ca853deeSEric Joyner  * @link_speeds: bitmap of supported link speeds
1042ca853deeSEric Joyner  *
1043ca853deeSEric Joyner  * @returns the link speed value for the highest speed reported in the
1044ca853deeSEric Joyner  * link_speeds bitmap.
1045ca853deeSEric Joyner  */
1046ca853deeSEric Joyner u64
1047ca853deeSEric Joyner iavf_max_vc_speed_to_value(u8 link_speeds)
1048ca853deeSEric Joyner {
1049ca853deeSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_40GB)
1050ca853deeSEric Joyner 		return IF_Gbps(40);
1051ca853deeSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_25GB)
1052ca853deeSEric Joyner 		return IF_Gbps(25);
1053ca853deeSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_20GB)
1054ca853deeSEric Joyner 		return IF_Gbps(20);
1055ca853deeSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_10GB)
1056ca853deeSEric Joyner 		return IF_Gbps(10);
1057ca853deeSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_1GB)
1058ca853deeSEric Joyner 		return IF_Gbps(1);
1059ca853deeSEric Joyner 	if (link_speeds & VIRTCHNL_LINK_SPEED_100MB)
1060ca853deeSEric Joyner 		return IF_Mbps(100);
1061ca853deeSEric Joyner 	else
1062ca853deeSEric Joyner 		/* Minimum supported link speed */
1063ca853deeSEric Joyner 		return IF_Mbps(100);
1064ca853deeSEric Joyner }
1065ca853deeSEric Joyner 
1066ca853deeSEric Joyner /**
1067ca853deeSEric Joyner  * iavf_config_rss_reg - Configure RSS using registers
1068ca853deeSEric Joyner  * @sc: device private softc
1069ca853deeSEric Joyner  *
1070ca853deeSEric Joyner  * Configures RSS for this function using the device registers. Called if the
1071ca853deeSEric Joyner  * PF does not support configuring RSS over the virtchnl interface.
1072ca853deeSEric Joyner  */
1073ca853deeSEric Joyner void
1074ca853deeSEric Joyner iavf_config_rss_reg(struct iavf_sc *sc)
1075ca853deeSEric Joyner {
1076ca853deeSEric Joyner 	struct iavf_hw	*hw = &sc->hw;
1077ca853deeSEric Joyner 	struct iavf_vsi	*vsi = &sc->vsi;
1078ca853deeSEric Joyner 	u32		lut = 0;
1079ca853deeSEric Joyner 	u64		set_hena = 0, hena;
1080ca853deeSEric Joyner 	int		i, j, que_id;
1081ca853deeSEric Joyner 	u32		rss_seed[IAVF_RSS_KEY_SIZE_REG];
1082ca853deeSEric Joyner #ifdef RSS
1083ca853deeSEric Joyner 	u32		rss_hash_config;
1084ca853deeSEric Joyner #endif
1085ca853deeSEric Joyner 
1086ca853deeSEric Joyner 	/* Don't set up RSS if using a single queue */
1087ca853deeSEric Joyner 	if (IAVF_NRXQS(vsi) == 1) {
1088ca853deeSEric Joyner 		wr32(hw, IAVF_VFQF_HENA(0), 0);
1089ca853deeSEric Joyner 		wr32(hw, IAVF_VFQF_HENA(1), 0);
1090ca853deeSEric Joyner 		iavf_flush(hw);
1091ca853deeSEric Joyner 		return;
1092ca853deeSEric Joyner 	}
1093ca853deeSEric Joyner 
1094ca853deeSEric Joyner #ifdef RSS
1095ca853deeSEric Joyner 	/* Fetch the configured RSS key */
1096ca853deeSEric Joyner 	rss_getkey((uint8_t *) &rss_seed);
1097ca853deeSEric Joyner #else
1098ca853deeSEric Joyner 	iavf_get_default_rss_key(rss_seed);
1099ca853deeSEric Joyner #endif
1100ca853deeSEric Joyner 
1101ca853deeSEric Joyner 	/* Fill out hash function seed */
1102ca853deeSEric Joyner 	for (i = 0; i < IAVF_RSS_KEY_SIZE_REG; i++)
1103ca853deeSEric Joyner                 wr32(hw, IAVF_VFQF_HKEY(i), rss_seed[i]);
1104ca853deeSEric Joyner 
1105ca853deeSEric Joyner 	/* Enable PCTYPES for RSS: */
1106ca853deeSEric Joyner #ifdef RSS
1107ca853deeSEric Joyner 	rss_hash_config = rss_gethashconfig();
1108ca853deeSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
1109ca853deeSEric Joyner                 set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV4_OTHER);
1110ca853deeSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
1111ca853deeSEric Joyner                 set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV4_TCP);
1112ca853deeSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
1113ca853deeSEric Joyner                 set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV4_UDP);
1114ca853deeSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
1115ca853deeSEric Joyner                 set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV6_OTHER);
1116ca853deeSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
1117ca853deeSEric Joyner 		set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_FRAG_IPV6);
1118ca853deeSEric Joyner 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
1119ca853deeSEric Joyner                 set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV6_TCP);
1120ca853deeSEric Joyner         if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
1121ca853deeSEric Joyner                 set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV6_UDP);
1122ca853deeSEric Joyner #else
1123ca853deeSEric Joyner 	set_hena = IAVF_DEFAULT_RSS_HENA_XL710;
1124ca853deeSEric Joyner #endif
1125ca853deeSEric Joyner 	hena = (u64)rd32(hw, IAVF_VFQF_HENA(0)) |
1126ca853deeSEric Joyner 	    ((u64)rd32(hw, IAVF_VFQF_HENA(1)) << 32);
1127ca853deeSEric Joyner 	hena |= set_hena;
1128ca853deeSEric Joyner 	wr32(hw, IAVF_VFQF_HENA(0), (u32)hena);
1129ca853deeSEric Joyner 	wr32(hw, IAVF_VFQF_HENA(1), (u32)(hena >> 32));
1130ca853deeSEric Joyner 
1131ca853deeSEric Joyner 	/* Populate the LUT with max no. of queues in round robin fashion */
1132ca853deeSEric Joyner 	for (i = 0, j = 0; i < IAVF_RSS_VSI_LUT_SIZE; i++, j++) {
1133ca853deeSEric Joyner                 if (j == IAVF_NRXQS(vsi))
1134ca853deeSEric Joyner                         j = 0;
1135ca853deeSEric Joyner #ifdef RSS
1136ca853deeSEric Joyner 		/*
1137ca853deeSEric Joyner 		 * Fetch the RSS bucket id for the given indirection entry.
1138ca853deeSEric Joyner 		 * Cap it at the number of configured buckets (which is
1139ca853deeSEric Joyner 		 * num_rx_queues.)
1140ca853deeSEric Joyner 		 */
1141ca853deeSEric Joyner 		que_id = rss_get_indirection_to_bucket(i);
1142ca853deeSEric Joyner 		que_id = que_id % IAVF_NRXQS(vsi);
1143ca853deeSEric Joyner #else
1144ca853deeSEric Joyner 		que_id = j;
1145ca853deeSEric Joyner #endif
1146ca853deeSEric Joyner                 /* lut = 4-byte sliding window of 4 lut entries */
1147ca853deeSEric Joyner                 lut = (lut << 8) | (que_id & IAVF_RSS_VF_LUT_ENTRY_MASK);
1148ca853deeSEric Joyner                 /* On i = 3, we have 4 entries in lut; write to the register */
1149ca853deeSEric Joyner                 if ((i & 3) == 3) {
1150ca853deeSEric Joyner                         wr32(hw, IAVF_VFQF_HLUT(i >> 2), lut);
1151ca853deeSEric Joyner 			iavf_dbg_rss(sc, "%s: HLUT(%2d): %#010x", __func__,
1152ca853deeSEric Joyner 			    i, lut);
1153ca853deeSEric Joyner 		}
1154ca853deeSEric Joyner         }
1155ca853deeSEric Joyner 	iavf_flush(hw);
1156ca853deeSEric Joyner }
1157ca853deeSEric Joyner 
1158ca853deeSEric Joyner /**
1159ca853deeSEric Joyner  * iavf_config_rss_pf - Configure RSS using PF virtchnl messages
1160ca853deeSEric Joyner  * @sc: device private softc
1161ca853deeSEric Joyner  *
1162ca853deeSEric Joyner  * Configure RSS by sending virtchnl messages to the PF.
1163ca853deeSEric Joyner  */
1164ca853deeSEric Joyner void
1165ca853deeSEric Joyner iavf_config_rss_pf(struct iavf_sc *sc)
1166ca853deeSEric Joyner {
1167ca853deeSEric Joyner 	iavf_send_vc_msg(sc, IAVF_FLAG_AQ_CONFIG_RSS_KEY);
1168ca853deeSEric Joyner 
1169ca853deeSEric Joyner 	iavf_send_vc_msg(sc, IAVF_FLAG_AQ_SET_RSS_HENA);
1170ca853deeSEric Joyner 
1171ca853deeSEric Joyner 	iavf_send_vc_msg(sc, IAVF_FLAG_AQ_CONFIG_RSS_LUT);
1172ca853deeSEric Joyner }
1173ca853deeSEric Joyner 
1174ca853deeSEric Joyner /**
1175ca853deeSEric Joyner  * iavf_config_rss - setup RSS
1176ca853deeSEric Joyner  * @sc: device private softc
1177ca853deeSEric Joyner  *
1178ca853deeSEric Joyner  * Configures RSS using the method determined by capability flags in the VF
1179ca853deeSEric Joyner  * resources structure sent from the PF over the virtchnl interface.
1180ca853deeSEric Joyner  *
1181ca853deeSEric Joyner  * @remark RSS keys and table are cleared on VF reset.
1182ca853deeSEric Joyner  */
1183ca853deeSEric Joyner void
1184ca853deeSEric Joyner iavf_config_rss(struct iavf_sc *sc)
1185ca853deeSEric Joyner {
1186ca853deeSEric Joyner 	if (sc->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_REG) {
1187ca853deeSEric Joyner 		iavf_dbg_info(sc, "Setting up RSS using VF registers...\n");
1188ca853deeSEric Joyner 		iavf_config_rss_reg(sc);
1189ca853deeSEric Joyner 	} else if (sc->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
1190ca853deeSEric Joyner 		iavf_dbg_info(sc, "Setting up RSS using messages to PF...\n");
1191ca853deeSEric Joyner 		iavf_config_rss_pf(sc);
1192ca853deeSEric Joyner 	} else
1193ca853deeSEric Joyner 		device_printf(sc->dev, "VF does not support RSS capability sent by PF.\n");
1194ca853deeSEric Joyner }
1195ca853deeSEric Joyner 
1196ca853deeSEric Joyner /**
1197ca853deeSEric Joyner  * iavf_config_promisc - setup promiscuous mode
1198ca853deeSEric Joyner  * @sc: device private softc
1199ca853deeSEric Joyner  * @flags: promiscuous flags to configure
1200ca853deeSEric Joyner  *
1201ca853deeSEric Joyner  * Request that promiscuous modes be enabled from the PF
1202ca853deeSEric Joyner  *
1203ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
1204ca853deeSEric Joyner  */
1205ca853deeSEric Joyner int
1206ca853deeSEric Joyner iavf_config_promisc(struct iavf_sc *sc, int flags)
1207ca853deeSEric Joyner {
1208d8096b2dSJustin Hibbits 	if_t ifp = sc->vsi.ifp;
1209ca853deeSEric Joyner 
1210ca853deeSEric Joyner 	sc->promisc_flags = 0;
1211ca853deeSEric Joyner 
1212ca853deeSEric Joyner 	if (flags & IFF_ALLMULTI ||
1213ca853deeSEric Joyner 		if_llmaddr_count(ifp) == MAX_MULTICAST_ADDR)
1214ca853deeSEric Joyner 		sc->promisc_flags |= FLAG_VF_MULTICAST_PROMISC;
1215ca853deeSEric Joyner 	if (flags & IFF_PROMISC)
1216ca853deeSEric Joyner 		sc->promisc_flags |= FLAG_VF_UNICAST_PROMISC;
1217ca853deeSEric Joyner 
1218ca853deeSEric Joyner 	iavf_send_vc_msg(sc, IAVF_FLAG_AQ_CONFIGURE_PROMISC);
1219ca853deeSEric Joyner 
1220ca853deeSEric Joyner 	return (0);
1221ca853deeSEric Joyner }
1222ca853deeSEric Joyner 
1223ca853deeSEric Joyner /**
1224ca853deeSEric Joyner  * iavf_mc_filter_apply - Program a MAC filter for this VF
1225ca853deeSEric Joyner  * @arg: pointer to the device softc
1226ca853deeSEric Joyner  * @sdl: MAC multicast address
1227ca853deeSEric Joyner  * @cnt: unused parameter
1228ca853deeSEric Joyner  *
1229ca853deeSEric Joyner  * Program a MAC address multicast filter for this device. Intended
1230ca853deeSEric Joyner  * to be used with the map-like function if_foreach_llmaddr().
1231ca853deeSEric Joyner  *
1232ca853deeSEric Joyner  * @returns 1 on success, or 0 on failure
1233ca853deeSEric Joyner  */
1234ca853deeSEric Joyner static u_int
1235ca853deeSEric Joyner iavf_mc_filter_apply(void *arg, struct sockaddr_dl *sdl, u_int cnt __unused)
1236ca853deeSEric Joyner {
1237ca853deeSEric Joyner 	struct iavf_sc *sc = (struct iavf_sc *)arg;
1238ca853deeSEric Joyner 	int error;
1239ca853deeSEric Joyner 
1240ca853deeSEric Joyner 	error = iavf_add_mac_filter(sc, (u8*)LLADDR(sdl), IAVF_FILTER_MC);
1241ca853deeSEric Joyner 
1242ca853deeSEric Joyner 	return (!error);
1243ca853deeSEric Joyner }
1244ca853deeSEric Joyner 
1245ca853deeSEric Joyner /**
1246ca853deeSEric Joyner  * iavf_init_multi - Initialize multicast address filters
1247ca853deeSEric Joyner  * @sc: device private softc
1248ca853deeSEric Joyner  *
1249ca853deeSEric Joyner  * Called during initialization to reset multicast address filters to a known
1250ca853deeSEric Joyner  * fresh state by deleting all currently active filters.
1251ca853deeSEric Joyner  */
1252ca853deeSEric Joyner void
1253ca853deeSEric Joyner iavf_init_multi(struct iavf_sc *sc)
1254ca853deeSEric Joyner {
1255ca853deeSEric Joyner 	struct iavf_mac_filter *f;
1256ca853deeSEric Joyner 	int mcnt = 0;
1257ca853deeSEric Joyner 
1258ca853deeSEric Joyner 	/* First clear any multicast filters */
1259ca853deeSEric Joyner 	SLIST_FOREACH(f, sc->mac_filters, next) {
1260ca853deeSEric Joyner 		if ((f->flags & IAVF_FILTER_USED)
1261ca853deeSEric Joyner 		    && (f->flags & IAVF_FILTER_MC)) {
1262ca853deeSEric Joyner 			f->flags |= IAVF_FILTER_DEL;
1263ca853deeSEric Joyner 			mcnt++;
1264ca853deeSEric Joyner 		}
1265ca853deeSEric Joyner 	}
1266ca853deeSEric Joyner 	if (mcnt > 0)
1267ca853deeSEric Joyner 		iavf_send_vc_msg(sc, IAVF_FLAG_AQ_DEL_MAC_FILTER);
1268ca853deeSEric Joyner }
1269ca853deeSEric Joyner 
1270ca853deeSEric Joyner /**
1271ca853deeSEric Joyner  * iavf_multi_set - Set multicast filters
1272ca853deeSEric Joyner  * @sc: device private softc
1273ca853deeSEric Joyner  *
1274ca853deeSEric Joyner  * Set multicast MAC filters for this device. If there are too many filters,
1275ca853deeSEric Joyner  * this will request the device to go into multicast promiscuous mode instead.
1276ca853deeSEric Joyner  */
1277ca853deeSEric Joyner void
1278ca853deeSEric Joyner iavf_multi_set(struct iavf_sc *sc)
1279ca853deeSEric Joyner {
1280ca853deeSEric Joyner 	if_t ifp = sc->vsi.ifp;
1281ca853deeSEric Joyner 	int mcnt = 0;
1282ca853deeSEric Joyner 
1283ca853deeSEric Joyner 	IOCTL_DEBUGOUT("iavf_multi_set: begin");
1284ca853deeSEric Joyner 
1285ca853deeSEric Joyner 	mcnt = if_llmaddr_count(ifp);
1286ca853deeSEric Joyner 	if (__predict_false(mcnt == MAX_MULTICAST_ADDR)) {
1287ca853deeSEric Joyner 		/* Delete MC filters and enable mulitcast promisc instead */
1288ca853deeSEric Joyner 		iavf_init_multi(sc);
1289ca853deeSEric Joyner 		sc->promisc_flags |= FLAG_VF_MULTICAST_PROMISC;
1290ca853deeSEric Joyner 		iavf_send_vc_msg(sc, IAVF_FLAG_AQ_CONFIGURE_PROMISC);
1291ca853deeSEric Joyner 		return;
1292ca853deeSEric Joyner 	}
1293ca853deeSEric Joyner 
1294ca853deeSEric Joyner 	/* If there aren't too many filters, delete existing MC filters */
1295ca853deeSEric Joyner 	iavf_init_multi(sc);
1296ca853deeSEric Joyner 
1297ca853deeSEric Joyner 	/* And (re-)install filters for all mcast addresses */
1298ca853deeSEric Joyner 	mcnt = if_foreach_llmaddr(ifp, iavf_mc_filter_apply, sc);
1299ca853deeSEric Joyner 
1300ca853deeSEric Joyner 	if (mcnt > 0)
1301ca853deeSEric Joyner 		iavf_send_vc_msg(sc, IAVF_FLAG_AQ_ADD_MAC_FILTER);
1302ca853deeSEric Joyner }
1303ca853deeSEric Joyner 
1304ca853deeSEric Joyner /**
1305ca853deeSEric Joyner  * iavf_add_mac_filter - Add a MAC filter to the sc MAC list
1306ca853deeSEric Joyner  * @sc: device private softc
1307ca853deeSEric Joyner  * @macaddr: MAC address to add
1308ca853deeSEric Joyner  * @flags: filter flags
1309ca853deeSEric Joyner  *
1310ca853deeSEric Joyner  * Add a new MAC filter to the softc MAC filter list. These will later be sent
1311ca853deeSEric Joyner  * to the physical function (and ultimately hardware) via the virtchnl
1312ca853deeSEric Joyner  * interface.
1313ca853deeSEric Joyner  *
1314ca853deeSEric Joyner  * @returns zero on success, EEXIST if the filter already exists, and ENOMEM
1315ca853deeSEric Joyner  * if we ran out of memory allocating the filter structure.
1316ca853deeSEric Joyner  */
1317ca853deeSEric Joyner int
1318ca853deeSEric Joyner iavf_add_mac_filter(struct iavf_sc *sc, u8 *macaddr, u16 flags)
1319ca853deeSEric Joyner {
1320ca853deeSEric Joyner 	struct iavf_mac_filter	*f;
1321ca853deeSEric Joyner 
1322ca853deeSEric Joyner 	/* Does one already exist? */
1323ca853deeSEric Joyner 	f = iavf_find_mac_filter(sc, macaddr);
1324ca853deeSEric Joyner 	if (f != NULL) {
1325ca853deeSEric Joyner 		iavf_dbg_filter(sc, "exists: " MAC_FORMAT "\n",
1326ca853deeSEric Joyner 		    MAC_FORMAT_ARGS(macaddr));
1327ca853deeSEric Joyner 		return (EEXIST);
1328ca853deeSEric Joyner 	}
1329ca853deeSEric Joyner 
1330ca853deeSEric Joyner 	/* If not, get a new empty filter */
1331ca853deeSEric Joyner 	f = iavf_get_mac_filter(sc);
1332ca853deeSEric Joyner 	if (f == NULL) {
1333ca853deeSEric Joyner 		device_printf(sc->dev, "%s: no filters available!!\n",
1334ca853deeSEric Joyner 		    __func__);
1335ca853deeSEric Joyner 		return (ENOMEM);
1336ca853deeSEric Joyner 	}
1337ca853deeSEric Joyner 
1338ca853deeSEric Joyner 	iavf_dbg_filter(sc, "marked: " MAC_FORMAT "\n",
1339ca853deeSEric Joyner 	    MAC_FORMAT_ARGS(macaddr));
1340ca853deeSEric Joyner 
1341ca853deeSEric Joyner 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
1342ca853deeSEric Joyner 	f->flags |= (IAVF_FILTER_ADD | IAVF_FILTER_USED);
1343ca853deeSEric Joyner 	f->flags |= flags;
1344ca853deeSEric Joyner 	return (0);
1345ca853deeSEric Joyner }
1346ca853deeSEric Joyner 
1347ca853deeSEric Joyner /**
1348ca853deeSEric Joyner  * iavf_find_mac_filter - Find a MAC filter with the given address
1349ca853deeSEric Joyner  * @sc: device private softc
1350ca853deeSEric Joyner  * @macaddr: the MAC address to find
1351ca853deeSEric Joyner  *
1352ca853deeSEric Joyner  * Finds the filter structure in the MAC filter list with the corresponding
1353ca853deeSEric Joyner  * MAC address.
1354ca853deeSEric Joyner  *
1355ca853deeSEric Joyner  * @returns a pointer to the filter structure, or NULL if no such filter
1356ca853deeSEric Joyner  * exists in the list yet.
1357ca853deeSEric Joyner  */
1358ca853deeSEric Joyner struct iavf_mac_filter *
1359ca853deeSEric Joyner iavf_find_mac_filter(struct iavf_sc *sc, u8 *macaddr)
1360ca853deeSEric Joyner {
1361ca853deeSEric Joyner 	struct iavf_mac_filter	*f;
1362ca853deeSEric Joyner 	bool match = FALSE;
1363ca853deeSEric Joyner 
1364ca853deeSEric Joyner 	SLIST_FOREACH(f, sc->mac_filters, next) {
1365ca853deeSEric Joyner 		if (cmp_etheraddr(f->macaddr, macaddr)) {
1366ca853deeSEric Joyner 			match = TRUE;
1367ca853deeSEric Joyner 			break;
1368ca853deeSEric Joyner 		}
1369ca853deeSEric Joyner 	}
1370ca853deeSEric Joyner 
1371ca853deeSEric Joyner 	if (!match)
1372ca853deeSEric Joyner 		f = NULL;
1373ca853deeSEric Joyner 	return (f);
1374ca853deeSEric Joyner }
1375ca853deeSEric Joyner 
1376ca853deeSEric Joyner /**
1377ca853deeSEric Joyner  * iavf_get_mac_filter - Get a new MAC address filter
1378ca853deeSEric Joyner  * @sc: device private softc
1379ca853deeSEric Joyner  *
1380ca853deeSEric Joyner  * Allocates a new filter structure and inserts it into the MAC filter list.
1381ca853deeSEric Joyner  *
1382ca853deeSEric Joyner  * @post the caller must fill in the structure details after calling this
1383ca853deeSEric Joyner  * function, but does not need to insert it into the linked list.
1384ca853deeSEric Joyner  *
1385ca853deeSEric Joyner  * @returns a pointer to the new filter structure, or NULL of we failed to
1386ca853deeSEric Joyner  * allocate it.
1387ca853deeSEric Joyner  */
1388ca853deeSEric Joyner struct iavf_mac_filter *
1389ca853deeSEric Joyner iavf_get_mac_filter(struct iavf_sc *sc)
1390ca853deeSEric Joyner {
1391ca853deeSEric Joyner 	struct iavf_mac_filter *f;
1392ca853deeSEric Joyner 
1393ca853deeSEric Joyner 	f = (struct iavf_mac_filter *)malloc(sizeof(struct iavf_mac_filter),
1394ca853deeSEric Joyner 	    M_IAVF, M_NOWAIT | M_ZERO);
1395ca853deeSEric Joyner 	if (f)
1396ca853deeSEric Joyner 		SLIST_INSERT_HEAD(sc->mac_filters, f, next);
1397ca853deeSEric Joyner 
1398ca853deeSEric Joyner 	return (f);
1399ca853deeSEric Joyner }
1400ca853deeSEric Joyner 
1401ca853deeSEric Joyner /**
1402ca853deeSEric Joyner  * iavf_baudrate_from_link_speed - Convert link speed to baudrate
1403ca853deeSEric Joyner  * @sc: device private softc
1404ca853deeSEric Joyner  *
1405ca853deeSEric Joyner  * @post The link_speed_adv field is in Mbps, so it is multipled by
1406ca853deeSEric Joyner  * 1,000,000 before it's returned.
1407ca853deeSEric Joyner  *
1408ca853deeSEric Joyner  * @returns the adapter link speed in bits/sec
1409ca853deeSEric Joyner  */
1410ca853deeSEric Joyner u64
1411ca853deeSEric Joyner iavf_baudrate_from_link_speed(struct iavf_sc *sc)
1412ca853deeSEric Joyner {
1413ca853deeSEric Joyner 	if (sc->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_ADV_LINK_SPEED)
1414ca853deeSEric Joyner 		return (sc->link_speed_adv * IAVF_ADV_LINK_SPEED_SCALE);
1415ca853deeSEric Joyner 	else
1416ca853deeSEric Joyner 		return iavf_max_vc_speed_to_value(sc->link_speed);
1417ca853deeSEric Joyner }
1418ca853deeSEric Joyner 
1419ca853deeSEric Joyner /**
1420ca853deeSEric Joyner  * iavf_add_vlan_filter - Add a VLAN filter to the softc VLAN list
1421ca853deeSEric Joyner  * @sc: device private softc
1422ca853deeSEric Joyner  * @vtag: the VLAN id to filter
1423ca853deeSEric Joyner  *
1424ca853deeSEric Joyner  * Allocate a new VLAN filter structure and insert it into the VLAN list.
1425ca853deeSEric Joyner  */
1426ca853deeSEric Joyner void
1427ca853deeSEric Joyner iavf_add_vlan_filter(struct iavf_sc *sc, u16 vtag)
1428ca853deeSEric Joyner {
1429ca853deeSEric Joyner 	struct iavf_vlan_filter	*v;
1430ca853deeSEric Joyner 
1431ca853deeSEric Joyner 	v = (struct iavf_vlan_filter *)malloc(sizeof(struct iavf_vlan_filter),
1432ca853deeSEric Joyner 	    M_IAVF, M_WAITOK | M_ZERO);
1433ca853deeSEric Joyner 	SLIST_INSERT_HEAD(sc->vlan_filters, v, next);
1434ca853deeSEric Joyner 	v->vlan = vtag;
1435ca853deeSEric Joyner 	v->flags = IAVF_FILTER_ADD;
1436ca853deeSEric Joyner }
1437ca853deeSEric Joyner 
1438ca853deeSEric Joyner /**
1439ca853deeSEric Joyner  * iavf_mark_del_vlan_filter - Mark a given VLAN id for deletion
1440ca853deeSEric Joyner  * @sc: device private softc
1441ca853deeSEric Joyner  * @vtag: the VLAN id to delete
1442ca853deeSEric Joyner  *
1443ca853deeSEric Joyner  * Marks all VLAN filters matching the given vtag for deletion.
1444ca853deeSEric Joyner  *
1445ca853deeSEric Joyner  * @returns the number of filters marked for deletion.
1446ca853deeSEric Joyner  *
1447ca853deeSEric Joyner  * @remark the filters are not removed immediately, but will be removed from
1448ca853deeSEric Joyner  * the list by another function that synchronizes over the virtchnl interface.
1449ca853deeSEric Joyner  */
1450ca853deeSEric Joyner int
1451ca853deeSEric Joyner iavf_mark_del_vlan_filter(struct iavf_sc *sc, u16 vtag)
1452ca853deeSEric Joyner {
1453ca853deeSEric Joyner 	struct iavf_vlan_filter	*v;
1454ca853deeSEric Joyner 	int i = 0;
1455ca853deeSEric Joyner 
1456ca853deeSEric Joyner 	SLIST_FOREACH(v, sc->vlan_filters, next) {
1457ca853deeSEric Joyner 		if (v->vlan == vtag) {
1458ca853deeSEric Joyner 			v->flags = IAVF_FILTER_DEL;
1459ca853deeSEric Joyner 			++i;
1460ca853deeSEric Joyner 		}
1461ca853deeSEric Joyner 	}
1462ca853deeSEric Joyner 
1463ca853deeSEric Joyner 	return (i);
1464ca853deeSEric Joyner }
1465ca853deeSEric Joyner 
1466ca853deeSEric Joyner /**
1467ca853deeSEric Joyner  * iavf_update_msix_devinfo - Fix MSIX values for pci_msix_count()
1468ca853deeSEric Joyner  * @dev: pointer to kernel device
1469ca853deeSEric Joyner  *
1470ca853deeSEric Joyner  * Fix cached MSI-X control register information. This is a workaround
1471ca853deeSEric Joyner  * for an issue where VFs spawned in non-passthrough mode on FreeBSD
1472ca853deeSEric Joyner  * will have their PCI information cached before the PF driver
1473ca853deeSEric Joyner  * finishes updating their PCI information.
1474ca853deeSEric Joyner  *
1475ca853deeSEric Joyner  * @pre Must be called before pci_msix_count()
1476ca853deeSEric Joyner  */
1477ca853deeSEric Joyner void
1478ca853deeSEric Joyner iavf_update_msix_devinfo(device_t dev)
1479ca853deeSEric Joyner {
1480ca853deeSEric Joyner 	struct pci_devinfo *dinfo;
1481ca853deeSEric Joyner 	u32 msix_ctrl;
1482*e53a21abSEric Joyner 	u8 msix_location;
1483ca853deeSEric Joyner 
1484ca853deeSEric Joyner 	dinfo = (struct pci_devinfo *)device_get_ivars(dev);
1485*e53a21abSEric Joyner 	msix_location = dinfo->cfg.msix.msix_location;
1486*e53a21abSEric Joyner 	msix_ctrl = pci_read_config(dev, msix_location + PCIR_MSIX_CTRL, 2);
1487ca853deeSEric Joyner 	dinfo->cfg.msix.msix_ctrl = msix_ctrl;
1488ca853deeSEric Joyner 	dinfo->cfg.msix.msix_msgnum = (msix_ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1;
1489ca853deeSEric Joyner }
1490ca853deeSEric Joyner 
1491ca853deeSEric Joyner /**
1492ca853deeSEric Joyner  * iavf_disable_queues_with_retries - Send PF multiple DISABLE_QUEUES messages
1493ca853deeSEric Joyner  * @sc: device softc
1494ca853deeSEric Joyner  *
1495ca853deeSEric Joyner  * Send a virtual channel message to the PF to DISABLE_QUEUES, but resend it up
1496ca853deeSEric Joyner  * to IAVF_MAX_DIS_Q_RETRY times if the response says that it wasn't
1497ca853deeSEric Joyner  * successful. This is intended to workaround a bug that can appear on the PF.
1498ca853deeSEric Joyner  */
1499ca853deeSEric Joyner void
1500ca853deeSEric Joyner iavf_disable_queues_with_retries(struct iavf_sc *sc)
1501ca853deeSEric Joyner {
1502ca853deeSEric Joyner 	bool in_detach = iavf_driver_is_detaching(sc);
1503ca853deeSEric Joyner 	int max_attempts = IAVF_MAX_DIS_Q_RETRY;
1504ca853deeSEric Joyner 	int msg_count = 0;
1505ca853deeSEric Joyner 
1506ca853deeSEric Joyner 	/* While the driver is detaching, it doesn't care if the queue
1507ca853deeSEric Joyner 	 * disable finishes successfully or not. Just send one message
1508ca853deeSEric Joyner 	 * to just notify the PF driver.
1509ca853deeSEric Joyner 	 */
1510ca853deeSEric Joyner 	if (in_detach)
1511ca853deeSEric Joyner 		max_attempts = 1;
1512ca853deeSEric Joyner 
1513ca853deeSEric Joyner 	while ((msg_count < max_attempts) &&
1514ca853deeSEric Joyner 	    atomic_load_acq_32(&sc->queues_enabled)) {
1515ca853deeSEric Joyner 		msg_count++;
1516ca853deeSEric Joyner 		iavf_send_vc_msg_sleep(sc, IAVF_FLAG_AQ_DISABLE_QUEUES);
1517ca853deeSEric Joyner 	}
1518ca853deeSEric Joyner 
1519ca853deeSEric Joyner 	/* Possibly print messages about retry attempts and issues */
1520ca853deeSEric Joyner 	if (msg_count > 1)
1521ca853deeSEric Joyner 		iavf_dbg_vc(sc, "DISABLE_QUEUES messages sent: %d\n",
1522ca853deeSEric Joyner 		    msg_count);
1523ca853deeSEric Joyner 
1524ca853deeSEric Joyner 	if (!in_detach && msg_count >= max_attempts)
1525ca853deeSEric Joyner 		device_printf(sc->dev, "%s: DISABLE_QUEUES may have failed\n",
1526ca853deeSEric Joyner 		    __func__);
1527ca853deeSEric Joyner }
1528