xref: /freebsd/sys/dev/iavf/iavf_vc_common.c (revision 0834f13da9e3b2912368f9ee3467997cd76911a4)
1ca853deeSEric Joyner /* SPDX-License-Identifier: BSD-3-Clause */
2ca853deeSEric Joyner /*  Copyright (c) 2021, 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_vc_common.c
34ca853deeSEric Joyner  * @brief Common virtchnl interface functions
35ca853deeSEric Joyner  *
36ca853deeSEric Joyner  * Contains functions implementing the virtchnl interface for connecting to
37ca853deeSEric Joyner  * the PF driver. This file contains the functions which are common between
38ca853deeSEric Joyner  * the legacy and iflib driver implementations.
39ca853deeSEric Joyner  */
40ca853deeSEric Joyner #include "iavf_vc_common.h"
41ca853deeSEric Joyner 
42ca853deeSEric Joyner /* Static function decls */
43ca853deeSEric Joyner static void iavf_handle_link_event(struct iavf_sc *sc,
44ca853deeSEric Joyner     struct virtchnl_pf_event *vpe);
45ca853deeSEric Joyner 
46ca853deeSEric Joyner /**
47ca853deeSEric Joyner  * iavf_send_pf_msg - Send virtchnl message to PF device
48ca853deeSEric Joyner  * @sc: device softc
49ca853deeSEric Joyner  * @op: the op to send
50ca853deeSEric Joyner  * @msg: message contents
51ca853deeSEric Joyner  * @len: length of the message
52ca853deeSEric Joyner  *
53ca853deeSEric Joyner  * Send a message to the PF device over the virtchnl connection. Print
54ca853deeSEric Joyner  * a status code if the message reports an error.
55ca853deeSEric Joyner  *
56ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
57ca853deeSEric Joyner  */
58ca853deeSEric Joyner int
iavf_send_pf_msg(struct iavf_sc * sc,enum virtchnl_ops op,u8 * msg,u16 len)59ca853deeSEric Joyner iavf_send_pf_msg(struct iavf_sc *sc,
60ca853deeSEric Joyner 	enum virtchnl_ops op, u8 *msg, u16 len)
61ca853deeSEric Joyner {
62ca853deeSEric Joyner 	struct iavf_hw *hw = &sc->hw;
63ca853deeSEric Joyner 	device_t dev = sc->dev;
64ca853deeSEric Joyner 	enum iavf_status status;
65ca853deeSEric Joyner 	int val_err;
66ca853deeSEric Joyner 
67ca853deeSEric Joyner 	/* Validating message before sending it to the PF */
68ca853deeSEric Joyner 	val_err = virtchnl_vc_validate_vf_msg(&sc->version, op, msg, len);
69ca853deeSEric Joyner 	if (val_err)
70ca853deeSEric Joyner 		device_printf(dev, "Error validating msg to PF for op %d,"
71ca853deeSEric Joyner 		    " msglen %d: error %d\n", op, len, val_err);
72ca853deeSEric Joyner 
73ca853deeSEric Joyner 	if (!iavf_check_asq_alive(hw)) {
74ca853deeSEric Joyner 		if (op != VIRTCHNL_OP_GET_STATS)
75ca853deeSEric Joyner 			device_printf(dev, "Unable to send opcode %s to PF, "
76ca853deeSEric Joyner 			    "ASQ is not alive\n", iavf_vc_opcode_str(op));
77ca853deeSEric Joyner 		return (0);
78ca853deeSEric Joyner 	}
79ca853deeSEric Joyner 
80ca853deeSEric Joyner 	if (op != VIRTCHNL_OP_GET_STATS)
81ca853deeSEric Joyner 		iavf_dbg_vc(sc,
82ca853deeSEric Joyner 		    "Sending msg (op=%s[%d]) to PF\n",
83ca853deeSEric Joyner 		    iavf_vc_opcode_str(op), op);
84ca853deeSEric Joyner 
85ca853deeSEric Joyner 	status = iavf_aq_send_msg_to_pf(hw, op, IAVF_SUCCESS, msg, len, NULL);
86ca853deeSEric Joyner 	if (status && op != VIRTCHNL_OP_GET_STATS)
87ca853deeSEric Joyner 		device_printf(dev, "Unable to send opcode %s to PF, "
88ca853deeSEric Joyner 		    "status %s, aq error %s\n",
89ca853deeSEric Joyner 		    iavf_vc_opcode_str(op),
90ca853deeSEric Joyner 		    iavf_stat_str(hw, status),
91ca853deeSEric Joyner 		    iavf_aq_str(hw, hw->aq.asq_last_status));
92ca853deeSEric Joyner 
93ca853deeSEric Joyner 	return (status);
94ca853deeSEric Joyner }
95ca853deeSEric Joyner 
96ca853deeSEric Joyner /**
97ca853deeSEric Joyner  * iavf_send_api_ver - Send the API version we support to the PF
98ca853deeSEric Joyner  * @sc: device softc
99ca853deeSEric Joyner  *
100ca853deeSEric Joyner  * Send API version admin queue message to the PF. The reply is not checked
101ca853deeSEric Joyner  * in this function.
102ca853deeSEric Joyner  *
103ca853deeSEric Joyner  * @returns 0 if the message was successfully sent, or one of the
104ca853deeSEric Joyner  * IAVF_ADMIN_QUEUE_ERROR_ statuses if not.
105ca853deeSEric Joyner  */
106ca853deeSEric Joyner int
iavf_send_api_ver(struct iavf_sc * sc)107ca853deeSEric Joyner iavf_send_api_ver(struct iavf_sc *sc)
108ca853deeSEric Joyner {
109ca853deeSEric Joyner 	struct virtchnl_version_info vvi;
110ca853deeSEric Joyner 
111ca853deeSEric Joyner 	vvi.major = VIRTCHNL_VERSION_MAJOR;
112ca853deeSEric Joyner 	vvi.minor = VIRTCHNL_VERSION_MINOR;
113ca853deeSEric Joyner 
114ca853deeSEric Joyner 	return iavf_send_pf_msg(sc, VIRTCHNL_OP_VERSION,
115ca853deeSEric Joyner 	    (u8 *)&vvi, sizeof(vvi));
116ca853deeSEric Joyner }
117ca853deeSEric Joyner 
118ca853deeSEric Joyner /**
119ca853deeSEric Joyner  * iavf_verify_api_ver - Verify the PF supports our API version
120ca853deeSEric Joyner  * @sc: device softc
121ca853deeSEric Joyner  *
122ca853deeSEric Joyner  * Compare API versions with the PF. Must be called after admin queue is
123ca853deeSEric Joyner  * initialized.
124ca853deeSEric Joyner  *
125ca853deeSEric Joyner  * @returns 0 if API versions match, EIO if they do not, or
126ca853deeSEric Joyner  * IAVF_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty.
127ca853deeSEric Joyner  */
128ca853deeSEric Joyner int
iavf_verify_api_ver(struct iavf_sc * sc)129ca853deeSEric Joyner iavf_verify_api_ver(struct iavf_sc *sc)
130ca853deeSEric Joyner {
131ca853deeSEric Joyner 	struct virtchnl_version_info *pf_vvi;
132ca853deeSEric Joyner 	struct iavf_hw *hw = &sc->hw;
133ca853deeSEric Joyner 	struct iavf_arq_event_info event;
134ca853deeSEric Joyner 	enum iavf_status status;
135ca853deeSEric Joyner 	device_t dev = sc->dev;
136ca853deeSEric Joyner 	int error = 0;
137ca853deeSEric Joyner 	int retries = 0;
138ca853deeSEric Joyner 
139ca853deeSEric Joyner 	event.buf_len = IAVF_AQ_BUF_SZ;
140ca853deeSEric Joyner 	event.msg_buf = (u8 *)malloc(event.buf_len, M_IAVF, M_WAITOK);
141ca853deeSEric Joyner 
142ca853deeSEric Joyner 	for (;;) {
143ca853deeSEric Joyner 		if (++retries > IAVF_AQ_MAX_ERR)
144ca853deeSEric Joyner 			goto out_alloc;
145ca853deeSEric Joyner 
146ca853deeSEric Joyner 		/* Initial delay here is necessary */
147ca853deeSEric Joyner 		iavf_msec_pause(100);
148ca853deeSEric Joyner 		status = iavf_clean_arq_element(hw, &event, NULL);
149ca853deeSEric Joyner 		if (status == IAVF_ERR_ADMIN_QUEUE_NO_WORK)
150ca853deeSEric Joyner 			continue;
151ca853deeSEric Joyner 		else if (status) {
152ca853deeSEric Joyner 			error = EIO;
153ca853deeSEric Joyner 			goto out_alloc;
154ca853deeSEric Joyner 		}
155ca853deeSEric Joyner 
156ca853deeSEric Joyner 		if ((enum virtchnl_ops)le32toh(event.desc.cookie_high) !=
157ca853deeSEric Joyner 		    VIRTCHNL_OP_VERSION) {
158ca853deeSEric Joyner 			iavf_dbg_vc(sc, "%s: Received unexpected op response: %d\n",
159ca853deeSEric Joyner 			    __func__, le32toh(event.desc.cookie_high));
160ca853deeSEric Joyner 			/* Don't stop looking for expected response */
161ca853deeSEric Joyner 			continue;
162ca853deeSEric Joyner 		}
163ca853deeSEric Joyner 
164ca853deeSEric Joyner 		status = (enum iavf_status)le32toh(event.desc.cookie_low);
165ca853deeSEric Joyner 		if (status) {
166ca853deeSEric Joyner 			error = EIO;
167ca853deeSEric Joyner 			goto out_alloc;
168ca853deeSEric Joyner 		} else
169ca853deeSEric Joyner 			break;
170ca853deeSEric Joyner 	}
171ca853deeSEric Joyner 
172ca853deeSEric Joyner 	pf_vvi = (struct virtchnl_version_info *)event.msg_buf;
173ca853deeSEric Joyner 	if ((pf_vvi->major > VIRTCHNL_VERSION_MAJOR) ||
174ca853deeSEric Joyner 	    ((pf_vvi->major == VIRTCHNL_VERSION_MAJOR) &&
175ca853deeSEric Joyner 	    (pf_vvi->minor > VIRTCHNL_VERSION_MINOR))) {
176ca853deeSEric Joyner 		device_printf(dev, "Critical PF/VF API version mismatch!\n");
177ca853deeSEric Joyner 		error = EIO;
178ca853deeSEric Joyner 	} else {
179ca853deeSEric Joyner 		sc->version.major = pf_vvi->major;
180ca853deeSEric Joyner 		sc->version.minor = pf_vvi->minor;
181ca853deeSEric Joyner 	}
182ca853deeSEric Joyner 
183ca853deeSEric Joyner 	/* Log PF/VF api versions */
184ca853deeSEric Joyner 	device_printf(dev, "PF API %d.%d / VF API %d.%d\n",
185ca853deeSEric Joyner 	    pf_vvi->major, pf_vvi->minor,
186ca853deeSEric Joyner 	    VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
187ca853deeSEric Joyner 
188ca853deeSEric Joyner out_alloc:
189ca853deeSEric Joyner 	free(event.msg_buf, M_IAVF);
190ca853deeSEric Joyner 	return (error);
191ca853deeSEric Joyner }
192ca853deeSEric Joyner 
193ca853deeSEric Joyner /**
194ca853deeSEric Joyner  * iavf_send_vf_config_msg - Send VF configuration request
195ca853deeSEric Joyner  * @sc: device softc
196ca853deeSEric Joyner  *
197ca853deeSEric Joyner  * Send VF configuration request admin queue message to the PF. The reply
198ca853deeSEric Joyner  * is not checked in this function.
199ca853deeSEric Joyner  *
200ca853deeSEric Joyner  * @returns 0 if the message was successfully sent, or one of the
201ca853deeSEric Joyner  * IAVF_ADMIN_QUEUE_ERROR_ statuses if not.
202ca853deeSEric Joyner  */
203ca853deeSEric Joyner int
iavf_send_vf_config_msg(struct iavf_sc * sc)204ca853deeSEric Joyner iavf_send_vf_config_msg(struct iavf_sc *sc)
205ca853deeSEric Joyner {
206ca853deeSEric Joyner 	u32 caps;
207ca853deeSEric Joyner 
208ca853deeSEric Joyner 	/* Support the base mode functionality, as well as advanced
209ca853deeSEric Joyner 	 * speed reporting capability.
210ca853deeSEric Joyner 	 */
211ca853deeSEric Joyner 	caps = VF_BASE_MODE_OFFLOADS |
212ca853deeSEric Joyner 	    VIRTCHNL_VF_CAP_ADV_LINK_SPEED;
213ca853deeSEric Joyner 
214ca853deeSEric Joyner 	iavf_dbg_info(sc, "Sending offload flags: 0x%b\n",
215ca853deeSEric Joyner 	    caps, IAVF_PRINTF_VF_OFFLOAD_FLAGS);
216ca853deeSEric Joyner 
217ca853deeSEric Joyner 	if (sc->version.minor == VIRTCHNL_VERSION_MINOR_NO_VF_CAPS)
218ca853deeSEric Joyner 		return iavf_send_pf_msg(sc, VIRTCHNL_OP_GET_VF_RESOURCES,
219ca853deeSEric Joyner 				  NULL, 0);
220ca853deeSEric Joyner 	else
221ca853deeSEric Joyner 		return iavf_send_pf_msg(sc, VIRTCHNL_OP_GET_VF_RESOURCES,
222ca853deeSEric Joyner 				  (u8 *)&caps, sizeof(caps));
223ca853deeSEric Joyner }
224ca853deeSEric Joyner 
225ca853deeSEric Joyner /**
226ca853deeSEric Joyner  * iavf_get_vf_config - Get the VF configuration from the PF
227ca853deeSEric Joyner  * @sc: device softc
228ca853deeSEric Joyner  *
229ca853deeSEric Joyner  * Get VF configuration from PF and populate hw structure. Must be called after
230ca853deeSEric Joyner  * admin queue is initialized. Busy waits until response is received from PF,
231ca853deeSEric Joyner  * with maximum timeout. Response from PF is returned in the buffer for further
232ca853deeSEric Joyner  * processing by the caller.
233ca853deeSEric Joyner  *
234ca853deeSEric Joyner  * @returns zero on success, or an error code on failure
235ca853deeSEric Joyner  */
236ca853deeSEric Joyner int
iavf_get_vf_config(struct iavf_sc * sc)237ca853deeSEric Joyner iavf_get_vf_config(struct iavf_sc *sc)
238ca853deeSEric Joyner {
239ca853deeSEric Joyner 	struct iavf_hw	*hw = &sc->hw;
240ca853deeSEric Joyner 	device_t	dev = sc->dev;
241ca853deeSEric Joyner 	enum iavf_status status = IAVF_SUCCESS;
242ca853deeSEric Joyner 	struct iavf_arq_event_info event;
243ca853deeSEric Joyner 	u16 len;
244ca853deeSEric Joyner 	u32 retries = 0;
245ca853deeSEric Joyner 	int error = 0;
246ca853deeSEric Joyner 
247ca853deeSEric Joyner 	/* Note this assumes a single VSI */
248ca853deeSEric Joyner 	len = sizeof(struct virtchnl_vf_resource) +
249ca853deeSEric Joyner 	    sizeof(struct virtchnl_vsi_resource);
250ca853deeSEric Joyner 	event.buf_len = len;
251ca853deeSEric Joyner 	event.msg_buf = (u8 *)malloc(event.buf_len, M_IAVF, M_WAITOK);
252ca853deeSEric Joyner 
253ca853deeSEric Joyner 	for (;;) {
254ca853deeSEric Joyner 		status = iavf_clean_arq_element(hw, &event, NULL);
255ca853deeSEric Joyner 		if (status == IAVF_ERR_ADMIN_QUEUE_NO_WORK) {
256ca853deeSEric Joyner 			if (++retries <= IAVF_AQ_MAX_ERR)
257ca853deeSEric Joyner 				iavf_msec_pause(10);
258ca853deeSEric Joyner 		} else if ((enum virtchnl_ops)le32toh(event.desc.cookie_high) !=
259ca853deeSEric Joyner 		    VIRTCHNL_OP_GET_VF_RESOURCES) {
260ca853deeSEric Joyner 			iavf_dbg_vc(sc, "%s: Received a response from PF,"
261ca853deeSEric Joyner 			    " opcode %d, error %d",
262ca853deeSEric Joyner 			    __func__,
263ca853deeSEric Joyner 			    le32toh(event.desc.cookie_high),
264ca853deeSEric Joyner 			    le32toh(event.desc.cookie_low));
265ca853deeSEric Joyner 			retries++;
266ca853deeSEric Joyner 			continue;
267ca853deeSEric Joyner 		} else {
268ca853deeSEric Joyner 			status = (enum iavf_status)le32toh(event.desc.cookie_low);
269ca853deeSEric Joyner 			if (status) {
270ca853deeSEric Joyner 				device_printf(dev, "%s: Error returned from PF,"
271ca853deeSEric Joyner 				    " opcode %d, error %d\n", __func__,
272ca853deeSEric Joyner 				    le32toh(event.desc.cookie_high),
273ca853deeSEric Joyner 				    le32toh(event.desc.cookie_low));
274ca853deeSEric Joyner 				error = EIO;
275ca853deeSEric Joyner 				goto out_alloc;
276ca853deeSEric Joyner 			}
277ca853deeSEric Joyner 			/* We retrieved the config message, with no errors */
278ca853deeSEric Joyner 			break;
279ca853deeSEric Joyner 		}
280ca853deeSEric Joyner 
281ca853deeSEric Joyner 		if (retries > IAVF_AQ_MAX_ERR) {
282ca853deeSEric Joyner 			iavf_dbg_vc(sc,
283ca853deeSEric Joyner 			    "%s: Did not receive response after %d tries.",
284ca853deeSEric Joyner 			    __func__, retries);
285ca853deeSEric Joyner 			error = ETIMEDOUT;
286ca853deeSEric Joyner 			goto out_alloc;
287ca853deeSEric Joyner 		}
288ca853deeSEric Joyner 	}
289ca853deeSEric Joyner 
290ca853deeSEric Joyner 	memcpy(sc->vf_res, event.msg_buf, min(event.msg_len, len));
291ca853deeSEric Joyner 	iavf_vf_parse_hw_config(hw, sc->vf_res);
292ca853deeSEric Joyner 
293ca853deeSEric Joyner out_alloc:
294ca853deeSEric Joyner 	free(event.msg_buf, M_IAVF);
295ca853deeSEric Joyner 	return (error);
296ca853deeSEric Joyner }
297ca853deeSEric Joyner 
298ca853deeSEric Joyner /**
299ca853deeSEric Joyner  * iavf_enable_queues - Enable queues
300ca853deeSEric Joyner  * @sc: device softc
301ca853deeSEric Joyner  *
302ca853deeSEric Joyner  * Request that the PF enable all of our queues.
303ca853deeSEric Joyner  *
304ca853deeSEric Joyner  * @remark the reply from the PF is not checked by this function.
305ca853deeSEric Joyner  *
306ca853deeSEric Joyner  * @returns zero
307ca853deeSEric Joyner  */
308ca853deeSEric Joyner int
iavf_enable_queues(struct iavf_sc * sc)309ca853deeSEric Joyner iavf_enable_queues(struct iavf_sc *sc)
310ca853deeSEric Joyner {
311ca853deeSEric Joyner 	struct virtchnl_queue_select vqs;
312ca853deeSEric Joyner 	struct iavf_vsi *vsi = &sc->vsi;
313ca853deeSEric Joyner 
314ca853deeSEric Joyner 	vqs.vsi_id = sc->vsi_res->vsi_id;
315ca853deeSEric Joyner 	vqs.tx_queues = (1 << IAVF_NTXQS(vsi)) - 1;
316ca853deeSEric Joyner 	vqs.rx_queues = vqs.tx_queues;
317ca853deeSEric Joyner 	iavf_send_pf_msg(sc, VIRTCHNL_OP_ENABLE_QUEUES,
318ca853deeSEric Joyner 			   (u8 *)&vqs, sizeof(vqs));
319ca853deeSEric Joyner 	return (0);
320ca853deeSEric Joyner }
321ca853deeSEric Joyner 
322ca853deeSEric Joyner /**
323ca853deeSEric Joyner  * iavf_disable_queues - Disable queues
324ca853deeSEric Joyner  * @sc: device softc
325ca853deeSEric Joyner  *
326ca853deeSEric Joyner  * Request that the PF disable all of our queues.
327ca853deeSEric Joyner  *
328ca853deeSEric Joyner  * @remark the reply from the PF is not checked by this function.
329ca853deeSEric Joyner  *
330ca853deeSEric Joyner  * @returns zero
331ca853deeSEric Joyner  */
332ca853deeSEric Joyner int
iavf_disable_queues(struct iavf_sc * sc)333ca853deeSEric Joyner iavf_disable_queues(struct iavf_sc *sc)
334ca853deeSEric Joyner {
335ca853deeSEric Joyner 	struct virtchnl_queue_select vqs;
336ca853deeSEric Joyner 	struct iavf_vsi *vsi = &sc->vsi;
337ca853deeSEric Joyner 
338ca853deeSEric Joyner 	vqs.vsi_id = sc->vsi_res->vsi_id;
339ca853deeSEric Joyner 	vqs.tx_queues = (1 << IAVF_NTXQS(vsi)) - 1;
340ca853deeSEric Joyner 	vqs.rx_queues = vqs.tx_queues;
341ca853deeSEric Joyner 	iavf_send_pf_msg(sc, VIRTCHNL_OP_DISABLE_QUEUES,
342ca853deeSEric Joyner 			   (u8 *)&vqs, sizeof(vqs));
343ca853deeSEric Joyner 	return (0);
344ca853deeSEric Joyner }
345ca853deeSEric Joyner 
346ca853deeSEric Joyner /**
347ca853deeSEric Joyner  * iavf_add_vlans - Add VLAN filters
348ca853deeSEric Joyner  * @sc: device softc
349ca853deeSEric Joyner  *
350ca853deeSEric Joyner  * Scan the Filter List looking for vlans that need
351ca853deeSEric Joyner  * to be added, then create the data to hand to the AQ
352ca853deeSEric Joyner  * for handling.
353ca853deeSEric Joyner  *
354ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
355ca853deeSEric Joyner  */
356ca853deeSEric Joyner int
iavf_add_vlans(struct iavf_sc * sc)357ca853deeSEric Joyner iavf_add_vlans(struct iavf_sc *sc)
358ca853deeSEric Joyner {
359ca853deeSEric Joyner 	struct virtchnl_vlan_filter_list *v;
360ca853deeSEric Joyner 	struct iavf_vlan_filter *f, *ftmp;
361ca853deeSEric Joyner 	device_t dev = sc->dev;
362ca853deeSEric Joyner 	int i = 0, cnt = 0;
363ca853deeSEric Joyner 	u32 len;
364ca853deeSEric Joyner 
365ca853deeSEric Joyner 	/* Get count of VLAN filters to add */
366ca853deeSEric Joyner 	SLIST_FOREACH(f, sc->vlan_filters, next) {
367ca853deeSEric Joyner 		if (f->flags & IAVF_FILTER_ADD)
368ca853deeSEric Joyner 			cnt++;
369ca853deeSEric Joyner 	}
370ca853deeSEric Joyner 
371ca853deeSEric Joyner 	if (!cnt) /* no work... */
372ca853deeSEric Joyner 		return (ENOENT);
373ca853deeSEric Joyner 
374ca853deeSEric Joyner 	len = sizeof(struct virtchnl_vlan_filter_list) +
375ca853deeSEric Joyner 	      (cnt * sizeof(u16));
376ca853deeSEric Joyner 
377ca853deeSEric Joyner 	if (len > IAVF_AQ_BUF_SZ) {
378ca853deeSEric Joyner 		device_printf(dev, "%s: Exceeded Max AQ Buf size\n",
379ca853deeSEric Joyner 			__func__);
380ca853deeSEric Joyner 		return (EFBIG);
381ca853deeSEric Joyner 	}
382ca853deeSEric Joyner 
383ca853deeSEric Joyner 	v = (struct virtchnl_vlan_filter_list *)malloc(len, M_IAVF, M_NOWAIT | M_ZERO);
384ca853deeSEric Joyner 	if (!v) {
385ca853deeSEric Joyner 		device_printf(dev, "%s: unable to allocate memory\n",
386ca853deeSEric Joyner 			__func__);
387ca853deeSEric Joyner 		return (ENOMEM);
388ca853deeSEric Joyner 	}
389ca853deeSEric Joyner 
390ca853deeSEric Joyner 	v->vsi_id = sc->vsi_res->vsi_id;
391ca853deeSEric Joyner 	v->num_elements = cnt;
392ca853deeSEric Joyner 
393ca853deeSEric Joyner 	/* Scan the filter array */
394ca853deeSEric Joyner 	SLIST_FOREACH_SAFE(f, sc->vlan_filters, next, ftmp) {
395ca853deeSEric Joyner                 if (f->flags & IAVF_FILTER_ADD) {
396ca853deeSEric Joyner                         bcopy(&f->vlan, &v->vlan_id[i], sizeof(u16));
397ca853deeSEric Joyner 			f->flags = IAVF_FILTER_USED;
398ca853deeSEric Joyner                         i++;
399ca853deeSEric Joyner                 }
400ca853deeSEric Joyner                 if (i == cnt)
401ca853deeSEric Joyner                         break;
402ca853deeSEric Joyner 	}
403ca853deeSEric Joyner 
404ca853deeSEric Joyner 	iavf_send_pf_msg(sc, VIRTCHNL_OP_ADD_VLAN, (u8 *)v, len);
405ca853deeSEric Joyner 	free(v, M_IAVF);
406ca853deeSEric Joyner 	/* add stats? */
407ca853deeSEric Joyner 	return (0);
408ca853deeSEric Joyner }
409ca853deeSEric Joyner 
410ca853deeSEric Joyner /**
411ca853deeSEric Joyner  * iavf_del_vlans - Delete VLAN filters
412ca853deeSEric Joyner  * @sc: device softc
413ca853deeSEric Joyner  *
414ca853deeSEric Joyner  * Scan the Filter Table looking for vlans that need
415ca853deeSEric Joyner  * to be removed, then create the data to hand to the AQ
416ca853deeSEric Joyner  * for handling.
417ca853deeSEric Joyner  *
418ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
419ca853deeSEric Joyner  */
420ca853deeSEric Joyner int
iavf_del_vlans(struct iavf_sc * sc)421ca853deeSEric Joyner iavf_del_vlans(struct iavf_sc *sc)
422ca853deeSEric Joyner {
423ca853deeSEric Joyner 	struct virtchnl_vlan_filter_list *v;
424ca853deeSEric Joyner 	struct iavf_vlan_filter *f, *ftmp;
425ca853deeSEric Joyner 	device_t dev = sc->dev;
426ca853deeSEric Joyner 	int i = 0, cnt = 0;
427ca853deeSEric Joyner 	u32 len;
428ca853deeSEric Joyner 
429ca853deeSEric Joyner 	/* Get count of VLAN filters to delete */
430ca853deeSEric Joyner 	SLIST_FOREACH(f, sc->vlan_filters, next) {
431ca853deeSEric Joyner 		if (f->flags & IAVF_FILTER_DEL)
432ca853deeSEric Joyner 			cnt++;
433ca853deeSEric Joyner 	}
434ca853deeSEric Joyner 
435ca853deeSEric Joyner 	if (!cnt) /* no work... */
436ca853deeSEric Joyner 		return (ENOENT);
437ca853deeSEric Joyner 
438ca853deeSEric Joyner 	len = sizeof(struct virtchnl_vlan_filter_list) +
439ca853deeSEric Joyner 	      (cnt * sizeof(u16));
440ca853deeSEric Joyner 
441ca853deeSEric Joyner 	if (len > IAVF_AQ_BUF_SZ) {
442ca853deeSEric Joyner 		device_printf(dev, "%s: Exceeded Max AQ Buf size\n",
443ca853deeSEric Joyner 			__func__);
444ca853deeSEric Joyner 		return (EFBIG);
445ca853deeSEric Joyner 	}
446ca853deeSEric Joyner 
447ca853deeSEric Joyner 	v = (struct virtchnl_vlan_filter_list *)
448ca853deeSEric Joyner 	    malloc(len, M_IAVF, M_NOWAIT | M_ZERO);
449ca853deeSEric Joyner 	if (!v) {
450ca853deeSEric Joyner 		device_printf(dev, "%s: unable to allocate memory\n",
451ca853deeSEric Joyner 			__func__);
452ca853deeSEric Joyner 		return (ENOMEM);
453ca853deeSEric Joyner 	}
454ca853deeSEric Joyner 
455ca853deeSEric Joyner 	v->vsi_id = sc->vsi_res->vsi_id;
456ca853deeSEric Joyner 	v->num_elements = cnt;
457ca853deeSEric Joyner 
458ca853deeSEric Joyner 	/* Scan the filter array */
459ca853deeSEric Joyner 	SLIST_FOREACH_SAFE(f, sc->vlan_filters, next, ftmp) {
460ca853deeSEric Joyner                 if (f->flags & IAVF_FILTER_DEL) {
461ca853deeSEric Joyner                         bcopy(&f->vlan, &v->vlan_id[i], sizeof(u16));
462ca853deeSEric Joyner                         i++;
463ca853deeSEric Joyner                         SLIST_REMOVE(sc->vlan_filters, f, iavf_vlan_filter, next);
464ca853deeSEric Joyner                         free(f, M_IAVF);
465ca853deeSEric Joyner                 }
466ca853deeSEric Joyner                 if (i == cnt)
467ca853deeSEric Joyner                         break;
468ca853deeSEric Joyner 	}
469ca853deeSEric Joyner 
470ca853deeSEric Joyner 	iavf_send_pf_msg(sc, VIRTCHNL_OP_DEL_VLAN, (u8 *)v, len);
471ca853deeSEric Joyner 	free(v, M_IAVF);
472ca853deeSEric Joyner 	/* add stats? */
473ca853deeSEric Joyner 	return (0);
474ca853deeSEric Joyner }
475ca853deeSEric Joyner 
476ca853deeSEric Joyner /**
477ca853deeSEric Joyner  * iavf_add_ether_filters - Add MAC filters
478ca853deeSEric Joyner  * @sc: device softc
479ca853deeSEric Joyner  *
480ca853deeSEric Joyner  * This routine takes additions to the vsi filter
481ca853deeSEric Joyner  * table and creates an Admin Queue call to create
482ca853deeSEric Joyner  * the filters in the hardware.
483ca853deeSEric Joyner  *
484ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
485ca853deeSEric Joyner  */
486ca853deeSEric Joyner int
iavf_add_ether_filters(struct iavf_sc * sc)487ca853deeSEric Joyner iavf_add_ether_filters(struct iavf_sc *sc)
488ca853deeSEric Joyner {
489ca853deeSEric Joyner 	struct virtchnl_ether_addr_list *a;
490ca853deeSEric Joyner 	struct iavf_mac_filter *f;
491ca853deeSEric Joyner 	device_t dev = sc->dev;
492ca853deeSEric Joyner 	int len, j = 0, cnt = 0;
493ca853deeSEric Joyner 	int error;
494ca853deeSEric Joyner 
495ca853deeSEric Joyner 	/* Get count of MAC addresses to add */
496ca853deeSEric Joyner 	SLIST_FOREACH(f, sc->mac_filters, next) {
497ca853deeSEric Joyner 		if (f->flags & IAVF_FILTER_ADD)
498ca853deeSEric Joyner 			cnt++;
499ca853deeSEric Joyner 	}
500ca853deeSEric Joyner 	if (cnt == 0) { /* Should not happen... */
501ca853deeSEric Joyner 		iavf_dbg_vc(sc, "%s: cnt == 0, exiting...\n", __func__);
502ca853deeSEric Joyner 		return (ENOENT);
503ca853deeSEric Joyner 	}
504ca853deeSEric Joyner 
505ca853deeSEric Joyner 	len = sizeof(struct virtchnl_ether_addr_list) +
506ca853deeSEric Joyner 	    (cnt * sizeof(struct virtchnl_ether_addr));
507ca853deeSEric Joyner 
508ca853deeSEric Joyner 	a = (struct virtchnl_ether_addr_list *)
509ca853deeSEric Joyner 	    malloc(len, M_IAVF, M_NOWAIT | M_ZERO);
510ca853deeSEric Joyner 	if (a == NULL) {
511ca853deeSEric Joyner 		device_printf(dev, "%s: Failed to get memory for "
512ca853deeSEric Joyner 		    "virtchnl_ether_addr_list\n", __func__);
513ca853deeSEric Joyner 		return (ENOMEM);
514ca853deeSEric Joyner 	}
515ca853deeSEric Joyner 	a->vsi_id = sc->vsi.id;
516ca853deeSEric Joyner 	a->num_elements = cnt;
517ca853deeSEric Joyner 
518ca853deeSEric Joyner 	/* Scan the filter array */
519ca853deeSEric Joyner 	SLIST_FOREACH(f, sc->mac_filters, next) {
520ca853deeSEric Joyner 		if (f->flags & IAVF_FILTER_ADD) {
521ca853deeSEric Joyner 			bcopy(f->macaddr, a->list[j].addr, ETHER_ADDR_LEN);
522ca853deeSEric Joyner 			f->flags &= ~IAVF_FILTER_ADD;
523ca853deeSEric Joyner 			j++;
524ca853deeSEric Joyner 
525ca853deeSEric Joyner 			iavf_dbg_vc(sc, "%s: ADD: " MAC_FORMAT "\n",
526ca853deeSEric Joyner 			    __func__, MAC_FORMAT_ARGS(f->macaddr));
527ca853deeSEric Joyner 		}
528ca853deeSEric Joyner 		if (j == cnt)
529ca853deeSEric Joyner 			break;
530ca853deeSEric Joyner 	}
531ca853deeSEric Joyner 	iavf_dbg_vc(sc, "%s: len %d, j %d, cnt %d\n", __func__,
532ca853deeSEric Joyner 	    len, j, cnt);
533ca853deeSEric Joyner 
534ca853deeSEric Joyner 	error = iavf_send_pf_msg(sc,
535ca853deeSEric Joyner 	    VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)a, len);
536ca853deeSEric Joyner 	/* add stats? */
537ca853deeSEric Joyner 	free(a, M_IAVF);
538ca853deeSEric Joyner 	return (error);
539ca853deeSEric Joyner }
540ca853deeSEric Joyner 
541ca853deeSEric Joyner /**
542ca853deeSEric Joyner  * iavf_del_ether_filters - Delete MAC filters
543ca853deeSEric Joyner  * @sc: device softc
544ca853deeSEric Joyner  *
545ca853deeSEric Joyner  * This routine takes filters flagged for deletion in the
546ca853deeSEric Joyner  * sc MAC filter list and creates an Admin Queue call
547ca853deeSEric Joyner  * to delete those filters in the hardware.
548ca853deeSEric Joyner  *
549ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
550ca853deeSEric Joyner */
551ca853deeSEric Joyner int
iavf_del_ether_filters(struct iavf_sc * sc)552ca853deeSEric Joyner iavf_del_ether_filters(struct iavf_sc *sc)
553ca853deeSEric Joyner {
554ca853deeSEric Joyner 	struct virtchnl_ether_addr_list *d;
555ca853deeSEric Joyner 	struct iavf_mac_filter *f, *f_temp;
556ca853deeSEric Joyner 	device_t dev = sc->dev;
557ca853deeSEric Joyner 	int len, j = 0, cnt = 0;
558ca853deeSEric Joyner 
559ca853deeSEric Joyner 	/* Get count of MAC addresses to delete */
560ca853deeSEric Joyner 	SLIST_FOREACH(f, sc->mac_filters, next) {
561ca853deeSEric Joyner 		if (f->flags & IAVF_FILTER_DEL)
562ca853deeSEric Joyner 			cnt++;
563ca853deeSEric Joyner 	}
564ca853deeSEric Joyner 	if (cnt == 0) {
565ca853deeSEric Joyner 		iavf_dbg_vc(sc, "%s: cnt == 0, exiting...\n", __func__);
566ca853deeSEric Joyner 		return (ENOENT);
567ca853deeSEric Joyner 	}
568ca853deeSEric Joyner 
569ca853deeSEric Joyner 	len = sizeof(struct virtchnl_ether_addr_list) +
570ca853deeSEric Joyner 	    (cnt * sizeof(struct virtchnl_ether_addr));
571ca853deeSEric Joyner 
572ca853deeSEric Joyner 	d = (struct virtchnl_ether_addr_list *)
573ca853deeSEric Joyner 	    malloc(len, M_IAVF, M_NOWAIT | M_ZERO);
574ca853deeSEric Joyner 	if (d == NULL) {
575ca853deeSEric Joyner 		device_printf(dev, "%s: Failed to get memory for "
576ca853deeSEric Joyner 		    "virtchnl_ether_addr_list\n", __func__);
577ca853deeSEric Joyner 		return (ENOMEM);
578ca853deeSEric Joyner 	}
579ca853deeSEric Joyner 	d->vsi_id = sc->vsi.id;
580ca853deeSEric Joyner 	d->num_elements = cnt;
581ca853deeSEric Joyner 
582ca853deeSEric Joyner 	/* Scan the filter array */
583ca853deeSEric Joyner 	SLIST_FOREACH_SAFE(f, sc->mac_filters, next, f_temp) {
584ca853deeSEric Joyner 		if (f->flags & IAVF_FILTER_DEL) {
585ca853deeSEric Joyner 			bcopy(f->macaddr, d->list[j].addr, ETHER_ADDR_LEN);
586ca853deeSEric Joyner 			iavf_dbg_vc(sc, "DEL: " MAC_FORMAT "\n",
587ca853deeSEric Joyner 			    MAC_FORMAT_ARGS(f->macaddr));
588ca853deeSEric Joyner 			j++;
589ca853deeSEric Joyner 			SLIST_REMOVE(sc->mac_filters, f, iavf_mac_filter, next);
590ca853deeSEric Joyner 			free(f, M_IAVF);
591ca853deeSEric Joyner 		}
592ca853deeSEric Joyner 		if (j == cnt)
593ca853deeSEric Joyner 			break;
594ca853deeSEric Joyner 	}
595ca853deeSEric Joyner 	iavf_send_pf_msg(sc,
596ca853deeSEric Joyner 	    VIRTCHNL_OP_DEL_ETH_ADDR, (u8 *)d, len);
597ca853deeSEric Joyner 	/* add stats? */
598ca853deeSEric Joyner 	free(d, M_IAVF);
599ca853deeSEric Joyner 	return (0);
600ca853deeSEric Joyner }
601ca853deeSEric Joyner 
602ca853deeSEric Joyner /**
603ca853deeSEric Joyner  * iavf_request_reset - Request a device reset
604ca853deeSEric Joyner  * @sc: device softc
605ca853deeSEric Joyner  *
606ca853deeSEric Joyner  * Request that the PF reset this VF. No response is expected.
607ca853deeSEric Joyner  *
608ca853deeSEric Joyner  * @returns zero
609ca853deeSEric Joyner  */
610ca853deeSEric Joyner int
iavf_request_reset(struct iavf_sc * sc)611ca853deeSEric Joyner iavf_request_reset(struct iavf_sc *sc)
612ca853deeSEric Joyner {
613ca853deeSEric Joyner 	/*
614ca853deeSEric Joyner 	** Set the reset status to "in progress" before
615ca853deeSEric Joyner 	** the request, this avoids any possibility of
616ca853deeSEric Joyner 	** a mistaken early detection of completion.
617ca853deeSEric Joyner 	*/
618ca853deeSEric Joyner 	wr32(&sc->hw, IAVF_VFGEN_RSTAT, VIRTCHNL_VFR_INPROGRESS);
619ca853deeSEric Joyner 	iavf_send_pf_msg(sc, VIRTCHNL_OP_RESET_VF, NULL, 0);
620ca853deeSEric Joyner 	return (0);
621ca853deeSEric Joyner }
622ca853deeSEric Joyner 
623ca853deeSEric Joyner /**
624ca853deeSEric Joyner  * iavf_request_stats - Request VF stats
625ca853deeSEric Joyner  * @sc: device softc
626ca853deeSEric Joyner  *
627ca853deeSEric Joyner  * Request the statistics for this VF's VSI from PF.
628ca853deeSEric Joyner  *
629ca853deeSEric Joyner  * @remark prints an error message on failure to obtain stats, but does not
630ca853deeSEric Joyner  * return with an error code.
631ca853deeSEric Joyner  *
632ca853deeSEric Joyner  * @returns zero
633ca853deeSEric Joyner  */
634ca853deeSEric Joyner int
iavf_request_stats(struct iavf_sc * sc)635ca853deeSEric Joyner iavf_request_stats(struct iavf_sc *sc)
636ca853deeSEric Joyner {
637ca853deeSEric Joyner 	struct virtchnl_queue_select vqs;
638ca853deeSEric Joyner 	int error = 0;
639ca853deeSEric Joyner 
640ca853deeSEric Joyner 	vqs.vsi_id = sc->vsi_res->vsi_id;
641ca853deeSEric Joyner 	/* Low priority, we don't need to error check */
642ca853deeSEric Joyner 	error = iavf_send_pf_msg(sc, VIRTCHNL_OP_GET_STATS,
643ca853deeSEric Joyner 	    (u8 *)&vqs, sizeof(vqs));
644ca853deeSEric Joyner 	if (error)
645ca853deeSEric Joyner 		device_printf(sc->dev, "Error sending stats request to PF: %d\n", error);
646ca853deeSEric Joyner 
647ca853deeSEric Joyner 	return (0);
648ca853deeSEric Joyner }
649ca853deeSEric Joyner 
650ca853deeSEric Joyner /**
651ca853deeSEric Joyner  * iavf_update_stats_counters - Update driver statistics
652ca853deeSEric Joyner  * @sc: device softc
653ca853deeSEric Joyner  * @es: ethernet stats storage
654ca853deeSEric Joyner  *
655ca853deeSEric Joyner  * Updates driver's stats counters with VSI stats returned from PF.
656ca853deeSEric Joyner  */
657ca853deeSEric Joyner void
iavf_update_stats_counters(struct iavf_sc * sc,struct iavf_eth_stats * es)658ca853deeSEric Joyner iavf_update_stats_counters(struct iavf_sc *sc, struct iavf_eth_stats *es)
659ca853deeSEric Joyner {
660ca853deeSEric Joyner 	struct iavf_vsi *vsi = &sc->vsi;
661ca853deeSEric Joyner 
662ca853deeSEric Joyner 	/* Update ifnet stats */
663*0834f13dSPiotr Kubaj 	vsi->ipackets = es->rx_unicast + es->rx_multicast + es->rx_broadcast;
664*0834f13dSPiotr Kubaj 	vsi->opackets = es->tx_unicast + es->tx_multicast + es->tx_broadcast;
665*0834f13dSPiotr Kubaj 	vsi->ibytes = es->rx_bytes;
666*0834f13dSPiotr Kubaj 	vsi->obytes = es->tx_bytes;
667*0834f13dSPiotr Kubaj 	vsi->imcasts = es->rx_multicast;
668*0834f13dSPiotr Kubaj 	vsi->omcasts = es->tx_multicast;
669ca853deeSEric Joyner 
670*0834f13dSPiotr Kubaj 	vsi->oerrors = es->tx_errors;
671*0834f13dSPiotr Kubaj 	vsi->iqdrops = es->rx_discards;
672*0834f13dSPiotr Kubaj 	vsi->oqdrops = es->tx_discards;
673*0834f13dSPiotr Kubaj 	vsi->noproto = es->rx_unknown_protocol;
674ca853deeSEric Joyner 
675ca853deeSEric Joyner 	vsi->eth_stats = *es;
676ca853deeSEric Joyner }
677ca853deeSEric Joyner 
678ca853deeSEric Joyner /**
679ca853deeSEric Joyner  * iavf_config_rss_key - Configure RSS key over virtchnl
680ca853deeSEric Joyner  * @sc: device softc
681ca853deeSEric Joyner  *
682ca853deeSEric Joyner  * Send a message to the PF to configure the RSS key using the virtchnl
683ca853deeSEric Joyner  * interface.
684ca853deeSEric Joyner  *
685ca853deeSEric Joyner  * @remark this does not check the reply from the PF.
686ca853deeSEric Joyner  *
687ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
688ca853deeSEric Joyner  */
689ca853deeSEric Joyner int
iavf_config_rss_key(struct iavf_sc * sc)690ca853deeSEric Joyner iavf_config_rss_key(struct iavf_sc *sc)
691ca853deeSEric Joyner {
692ca853deeSEric Joyner 	struct virtchnl_rss_key *rss_key_msg;
693ca853deeSEric Joyner 	int msg_len, key_length;
694ca853deeSEric Joyner 	u8		rss_seed[IAVF_RSS_KEY_SIZE];
695ca853deeSEric Joyner 
696ca853deeSEric Joyner #ifdef RSS
697ca853deeSEric Joyner 	/* Fetch the configured RSS key */
698ca853deeSEric Joyner 	rss_getkey((uint8_t *) &rss_seed);
699ca853deeSEric Joyner #else
700ca853deeSEric Joyner 	iavf_get_default_rss_key((u32 *)rss_seed);
701ca853deeSEric Joyner #endif
702ca853deeSEric Joyner 
703ca853deeSEric Joyner 	/* Send the fetched key */
704ca853deeSEric Joyner 	key_length = IAVF_RSS_KEY_SIZE;
705ca853deeSEric Joyner 	msg_len = sizeof(struct virtchnl_rss_key) + (sizeof(u8) * key_length) - 1;
706ca853deeSEric Joyner 	rss_key_msg = (struct virtchnl_rss_key *)
707ca853deeSEric Joyner 	    malloc(msg_len, M_IAVF, M_NOWAIT | M_ZERO);
708ca853deeSEric Joyner 	if (rss_key_msg == NULL) {
709ca853deeSEric Joyner 		device_printf(sc->dev, "Unable to allocate msg memory for RSS key msg.\n");
710ca853deeSEric Joyner 		return (ENOMEM);
711ca853deeSEric Joyner 	}
712ca853deeSEric Joyner 
713ca853deeSEric Joyner 	rss_key_msg->vsi_id = sc->vsi_res->vsi_id;
714ca853deeSEric Joyner 	rss_key_msg->key_len = key_length;
715ca853deeSEric Joyner 	bcopy(rss_seed, &rss_key_msg->key[0], key_length);
716ca853deeSEric Joyner 
717ca853deeSEric Joyner 	iavf_dbg_vc(sc, "%s: vsi_id %d, key_len %d\n", __func__,
718ca853deeSEric Joyner 	    rss_key_msg->vsi_id, rss_key_msg->key_len);
719ca853deeSEric Joyner 
720ca853deeSEric Joyner 	iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_RSS_KEY,
721ca853deeSEric Joyner 			  (u8 *)rss_key_msg, msg_len);
722ca853deeSEric Joyner 
723ca853deeSEric Joyner 	free(rss_key_msg, M_IAVF);
724ca853deeSEric Joyner 	return (0);
725ca853deeSEric Joyner }
726ca853deeSEric Joyner 
727ca853deeSEric Joyner /**
728ca853deeSEric Joyner  * iavf_set_rss_hena - Configure the RSS HENA
729ca853deeSEric Joyner  * @sc: device softc
730ca853deeSEric Joyner  *
731ca853deeSEric Joyner  * Configure the RSS HENA values by sending a virtchnl message to the PF
732ca853deeSEric Joyner  *
733ca853deeSEric Joyner  * @remark the reply from the PF is not checked by this function.
734ca853deeSEric Joyner  *
735ca853deeSEric Joyner  * @returns zero
736ca853deeSEric Joyner  */
737ca853deeSEric Joyner int
iavf_set_rss_hena(struct iavf_sc * sc)738ca853deeSEric Joyner iavf_set_rss_hena(struct iavf_sc *sc)
739ca853deeSEric Joyner {
740ca853deeSEric Joyner 	struct virtchnl_rss_hena hena;
741ca853deeSEric Joyner 	struct iavf_hw *hw = &sc->hw;
742ca853deeSEric Joyner 
743ca853deeSEric Joyner 	if (hw->mac.type == IAVF_MAC_VF)
744ca853deeSEric Joyner 		hena.hena = IAVF_DEFAULT_RSS_HENA_AVF;
745ca853deeSEric Joyner 	else if (hw->mac.type == IAVF_MAC_X722_VF)
746ca853deeSEric Joyner 		hena.hena = IAVF_DEFAULT_RSS_HENA_X722;
747ca853deeSEric Joyner 	else
748ca853deeSEric Joyner 		hena.hena = IAVF_DEFAULT_RSS_HENA_BASE;
749ca853deeSEric Joyner 
750ca853deeSEric Joyner 	iavf_send_pf_msg(sc, VIRTCHNL_OP_SET_RSS_HENA,
751ca853deeSEric Joyner 	    (u8 *)&hena, sizeof(hena));
752ca853deeSEric Joyner 	return (0);
753ca853deeSEric Joyner }
754ca853deeSEric Joyner 
755ca853deeSEric Joyner /**
756ca853deeSEric Joyner  * iavf_config_rss_lut - Configure RSS lookup table
757ca853deeSEric Joyner  * @sc: device softc
758ca853deeSEric Joyner  *
759ca853deeSEric Joyner  * Configure the RSS lookup table by sending a virtchnl message to the PF.
760ca853deeSEric Joyner  *
761ca853deeSEric Joyner  * @remark the reply from the PF is not checked in this function.
762ca853deeSEric Joyner  *
763ca853deeSEric Joyner  * @returns zero on success, or an error code on failure.
764ca853deeSEric Joyner  */
765ca853deeSEric Joyner int
iavf_config_rss_lut(struct iavf_sc * sc)766ca853deeSEric Joyner iavf_config_rss_lut(struct iavf_sc *sc)
767ca853deeSEric Joyner {
768ca853deeSEric Joyner 	struct virtchnl_rss_lut *rss_lut_msg;
769ca853deeSEric Joyner 	int msg_len;
770ca853deeSEric Joyner 	u16 lut_length;
771ca853deeSEric Joyner 	u32 lut;
772ca853deeSEric Joyner 	int i, que_id;
773ca853deeSEric Joyner 
774ca853deeSEric Joyner 	lut_length = IAVF_RSS_VSI_LUT_SIZE;
775ca853deeSEric Joyner 	msg_len = sizeof(struct virtchnl_rss_lut) + (lut_length * sizeof(u8)) - 1;
776ca853deeSEric Joyner 	rss_lut_msg = (struct virtchnl_rss_lut *)
777ca853deeSEric Joyner 	    malloc(msg_len, M_IAVF, M_NOWAIT | M_ZERO);
778ca853deeSEric Joyner 	if (rss_lut_msg == NULL) {
779ca853deeSEric Joyner 		device_printf(sc->dev, "Unable to allocate msg memory for RSS lut msg.\n");
780ca853deeSEric Joyner 		return (ENOMEM);
781ca853deeSEric Joyner 	}
782ca853deeSEric Joyner 
783ca853deeSEric Joyner 	rss_lut_msg->vsi_id = sc->vsi_res->vsi_id;
784ca853deeSEric Joyner 	/* Each LUT entry is a max of 1 byte, so this is easy */
785ca853deeSEric Joyner 	rss_lut_msg->lut_entries = lut_length;
786ca853deeSEric Joyner 
787ca853deeSEric Joyner 	/* Populate the LUT with max no. of queues in round robin fashion */
788ca853deeSEric Joyner 	for (i = 0; i < lut_length; i++) {
789ca853deeSEric Joyner #ifdef RSS
790ca853deeSEric Joyner 		/*
791ca853deeSEric Joyner 		 * Fetch the RSS bucket id for the given indirection entry.
792ca853deeSEric Joyner 		 * Cap it at the number of configured buckets (which is
793ca853deeSEric Joyner 		 * num_queues.)
794ca853deeSEric Joyner 		 */
795ca853deeSEric Joyner 		que_id = rss_get_indirection_to_bucket(i);
796ca853deeSEric Joyner 		que_id = que_id % sc->vsi.num_rx_queues;
797ca853deeSEric Joyner #else
798ca853deeSEric Joyner 		que_id = i % sc->vsi.num_rx_queues;
799ca853deeSEric Joyner #endif
800ca853deeSEric Joyner 		lut = que_id & IAVF_RSS_VSI_LUT_ENTRY_MASK;
801ca853deeSEric Joyner 		rss_lut_msg->lut[i] = lut;
802ca853deeSEric Joyner 	}
803ca853deeSEric Joyner 
804ca853deeSEric Joyner 	iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_RSS_LUT,
805ca853deeSEric Joyner 			  (u8 *)rss_lut_msg, msg_len);
806ca853deeSEric Joyner 
807ca853deeSEric Joyner 	free(rss_lut_msg, M_IAVF);
808ca853deeSEric Joyner 	return (0);
809ca853deeSEric Joyner }
810ca853deeSEric Joyner 
811ca853deeSEric Joyner /**
812ca853deeSEric Joyner  * iavf_config_promisc_mode - Configure promiscuous mode
813ca853deeSEric Joyner  * @sc: device softc
814ca853deeSEric Joyner  *
815ca853deeSEric Joyner  * Configure the device into promiscuous mode by sending a virtchnl message to
816ca853deeSEric Joyner  * the PF.
817ca853deeSEric Joyner  *
818ca853deeSEric Joyner  * @remark the reply from the PF is not checked in this function.
819ca853deeSEric Joyner  *
820ca853deeSEric Joyner  * @returns zero
821ca853deeSEric Joyner  */
822ca853deeSEric Joyner int
iavf_config_promisc_mode(struct iavf_sc * sc)823ca853deeSEric Joyner iavf_config_promisc_mode(struct iavf_sc *sc)
824ca853deeSEric Joyner {
825ca853deeSEric Joyner 	struct virtchnl_promisc_info pinfo;
826ca853deeSEric Joyner 
827ca853deeSEric Joyner 	pinfo.vsi_id = sc->vsi_res->vsi_id;
828ca853deeSEric Joyner 	pinfo.flags = sc->promisc_flags;
829ca853deeSEric Joyner 
830ca853deeSEric Joyner 	iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
831ca853deeSEric Joyner 	    (u8 *)&pinfo, sizeof(pinfo));
832ca853deeSEric Joyner 	return (0);
833ca853deeSEric Joyner }
834ca853deeSEric Joyner 
835ca853deeSEric Joyner /**
836ca853deeSEric Joyner  * iavf_vc_send_cmd - Convert request into virtchnl calls
837ca853deeSEric Joyner  * @sc: device softc
838ca853deeSEric Joyner  * @request: the requested command to run
839ca853deeSEric Joyner  *
840ca853deeSEric Joyner  * Send the proper virtchnl call based on the request value.
841ca853deeSEric Joyner  *
842ca853deeSEric Joyner  * @returns zero on success, or an error code on failure. Note that unknown
843ca853deeSEric Joyner  * requests will return zero.
844ca853deeSEric Joyner  */
845ca853deeSEric Joyner int
iavf_vc_send_cmd(struct iavf_sc * sc,uint32_t request)846ca853deeSEric Joyner iavf_vc_send_cmd(struct iavf_sc *sc, uint32_t request)
847ca853deeSEric Joyner {
848ca853deeSEric Joyner 	switch (request) {
849ca853deeSEric Joyner 	case IAVF_FLAG_AQ_MAP_VECTORS:
850ca853deeSEric Joyner 		return iavf_map_queues(sc);
851ca853deeSEric Joyner 
852ca853deeSEric Joyner 	case IAVF_FLAG_AQ_ADD_MAC_FILTER:
853ca853deeSEric Joyner 		return iavf_add_ether_filters(sc);
854ca853deeSEric Joyner 
855ca853deeSEric Joyner 	case IAVF_FLAG_AQ_ADD_VLAN_FILTER:
856ca853deeSEric Joyner 		return iavf_add_vlans(sc);
857ca853deeSEric Joyner 
858ca853deeSEric Joyner 	case IAVF_FLAG_AQ_DEL_MAC_FILTER:
859ca853deeSEric Joyner 		return iavf_del_ether_filters(sc);
860ca853deeSEric Joyner 
861ca853deeSEric Joyner 	case IAVF_FLAG_AQ_DEL_VLAN_FILTER:
862ca853deeSEric Joyner 		return iavf_del_vlans(sc);
863ca853deeSEric Joyner 
864ca853deeSEric Joyner 	case IAVF_FLAG_AQ_CONFIGURE_QUEUES:
865ca853deeSEric Joyner 		return iavf_configure_queues(sc);
866ca853deeSEric Joyner 
867ca853deeSEric Joyner 	case IAVF_FLAG_AQ_DISABLE_QUEUES:
868ca853deeSEric Joyner 		return iavf_disable_queues(sc);
869ca853deeSEric Joyner 
870ca853deeSEric Joyner 	case IAVF_FLAG_AQ_ENABLE_QUEUES:
871ca853deeSEric Joyner 		return iavf_enable_queues(sc);
872ca853deeSEric Joyner 
873ca853deeSEric Joyner 	case IAVF_FLAG_AQ_CONFIG_RSS_KEY:
874ca853deeSEric Joyner 		return iavf_config_rss_key(sc);
875ca853deeSEric Joyner 
876ca853deeSEric Joyner 	case IAVF_FLAG_AQ_SET_RSS_HENA:
877ca853deeSEric Joyner 		return iavf_set_rss_hena(sc);
878ca853deeSEric Joyner 
879ca853deeSEric Joyner 	case IAVF_FLAG_AQ_CONFIG_RSS_LUT:
880ca853deeSEric Joyner 		return iavf_config_rss_lut(sc);
881ca853deeSEric Joyner 
882ca853deeSEric Joyner 	case IAVF_FLAG_AQ_CONFIGURE_PROMISC:
883ca853deeSEric Joyner 		return iavf_config_promisc_mode(sc);
884ca853deeSEric Joyner 	}
885ca853deeSEric Joyner 
886ca853deeSEric Joyner 	return (0);
887ca853deeSEric Joyner }
888ca853deeSEric Joyner 
889ca853deeSEric Joyner /**
890ca853deeSEric Joyner  * iavf_vc_get_op_chan - Get op channel for a request
891ca853deeSEric Joyner  * @sc: device softc
892ca853deeSEric Joyner  * @request: the request type
893ca853deeSEric Joyner  *
894ca853deeSEric Joyner  * @returns the op channel for the given request, or NULL if no channel is
895ca853deeSEric Joyner  * used.
896ca853deeSEric Joyner  */
897ca853deeSEric Joyner void *
iavf_vc_get_op_chan(struct iavf_sc * sc,uint32_t request)898ca853deeSEric Joyner iavf_vc_get_op_chan(struct iavf_sc *sc, uint32_t request)
899ca853deeSEric Joyner {
900ca853deeSEric Joyner 	switch (request) {
901ca853deeSEric Joyner 	case IAVF_FLAG_AQ_ENABLE_QUEUES:
902ca853deeSEric Joyner 		return (&sc->enable_queues_chan);
903ca853deeSEric Joyner 	case IAVF_FLAG_AQ_DISABLE_QUEUES:
904ca853deeSEric Joyner 		return (&sc->disable_queues_chan);
905ca853deeSEric Joyner 	default:
906ca853deeSEric Joyner 		return (NULL);
907ca853deeSEric Joyner 	}
908ca853deeSEric Joyner }
909ca853deeSEric Joyner 
910ca853deeSEric Joyner /**
911ca853deeSEric Joyner  * iavf_vc_stat_str - convert virtchnl status err code to a string
912ca853deeSEric Joyner  * @hw: pointer to the HW structure
913ca853deeSEric Joyner  * @stat_err: the status error code to convert
914ca853deeSEric Joyner  *
915ca853deeSEric Joyner  * @returns the human readable string representing the specified error code.
916ca853deeSEric Joyner  **/
917ca853deeSEric Joyner const char *
iavf_vc_stat_str(struct iavf_hw * hw,enum virtchnl_status_code stat_err)918ca853deeSEric Joyner iavf_vc_stat_str(struct iavf_hw *hw, enum virtchnl_status_code stat_err)
919ca853deeSEric Joyner {
920ca853deeSEric Joyner 	switch (stat_err) {
921ca853deeSEric Joyner 	case VIRTCHNL_STATUS_SUCCESS:
922ca853deeSEric Joyner 		return "OK";
923ca853deeSEric Joyner 	case VIRTCHNL_ERR_PARAM:
924ca853deeSEric Joyner 		return "VIRTCHNL_ERR_PARAM";
925ca853deeSEric Joyner 	case VIRTCHNL_STATUS_ERR_NO_MEMORY:
926ca853deeSEric Joyner 		return "VIRTCHNL_STATUS_ERR_NO_MEMORY";
927ca853deeSEric Joyner 	case VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH:
928ca853deeSEric Joyner 		return "VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH";
929ca853deeSEric Joyner 	case VIRTCHNL_STATUS_ERR_CQP_COMPL_ERROR:
930ca853deeSEric Joyner 		return "VIRTCHNL_STATUS_ERR_CQP_COMPL_ERROR";
931ca853deeSEric Joyner 	case VIRTCHNL_STATUS_ERR_INVALID_VF_ID:
932ca853deeSEric Joyner 		return "VIRTCHNL_STATUS_ERR_INVALID_VF_ID";
933ca853deeSEric Joyner 	case VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR:
934ca853deeSEric Joyner 		return "VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR";
935ca853deeSEric Joyner 	case VIRTCHNL_STATUS_NOT_SUPPORTED:
936ca853deeSEric Joyner 		return "VIRTCHNL_STATUS_NOT_SUPPORTED";
937ca853deeSEric Joyner 	}
938ca853deeSEric Joyner 
939ca853deeSEric Joyner 	snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err);
940ca853deeSEric Joyner 	return hw->err_str;
941ca853deeSEric Joyner }
942ca853deeSEric Joyner 
943ca853deeSEric Joyner /**
944ca853deeSEric Joyner  * iavf_adv_speed_to_ext_speed - Convert numeric speed to iavf speed enum
945ca853deeSEric Joyner  * @adv_link_speed: link speed in Mb/s
946ca853deeSEric Joyner  *
947ca853deeSEric Joyner  * Converts the link speed from the "advanced" link speed virtchnl op into the
948ca853deeSEric Joyner  * closest approximation of the internal iavf link speed, rounded down.
949ca853deeSEric Joyner  *
950ca853deeSEric Joyner  * @returns the link speed as an iavf_ext_link_speed enum value
951ca853deeSEric Joyner  */
952ca853deeSEric Joyner enum iavf_ext_link_speed
iavf_adv_speed_to_ext_speed(u32 adv_link_speed)953ca853deeSEric Joyner iavf_adv_speed_to_ext_speed(u32 adv_link_speed)
954ca853deeSEric Joyner {
955ca853deeSEric Joyner 	if (adv_link_speed >= 100000)
956ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_100GB;
957ca853deeSEric Joyner 	if (adv_link_speed >= 50000)
958ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_50GB;
959ca853deeSEric Joyner 	if (adv_link_speed >= 40000)
960ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_40GB;
961ca853deeSEric Joyner 	if (adv_link_speed >= 25000)
962ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_25GB;
963ca853deeSEric Joyner 	if (adv_link_speed >= 20000)
964ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_20GB;
965ca853deeSEric Joyner 	if (adv_link_speed >= 10000)
966ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_10GB;
967ca853deeSEric Joyner 	if (adv_link_speed >= 5000)
968ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_5GB;
969ca853deeSEric Joyner 	if (adv_link_speed >= 2500)
970ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_2500MB;
971ca853deeSEric Joyner 	if (adv_link_speed >= 1000)
972ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_1000MB;
973ca853deeSEric Joyner 	if (adv_link_speed >= 100)
974ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_100MB;
975ca853deeSEric Joyner 	if (adv_link_speed >= 10)
976ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_10MB;
977ca853deeSEric Joyner 
978ca853deeSEric Joyner 	return IAVF_EXT_LINK_SPEED_UNKNOWN;
979ca853deeSEric Joyner }
980ca853deeSEric Joyner 
981ca853deeSEric Joyner /**
982ca853deeSEric Joyner  * iavf_ext_speed_to_ifmedia - Convert internal iavf speed to ifmedia value
983ca853deeSEric Joyner  * @link_speed: the link speed
984ca853deeSEric Joyner  *
985ca853deeSEric Joyner  * @remark this is sort of a hack, because we don't actually know what media
986ca853deeSEric Joyner  * type the VF is running on. In an ideal world we might just report the media
987ca853deeSEric Joyner  * type as "virtual" and have another mechanism for reporting the link
988ca853deeSEric Joyner  * speed.
989ca853deeSEric Joyner  *
990ca853deeSEric Joyner  * @returns a suitable ifmedia type for the given link speed.
991ca853deeSEric Joyner  */
992ca853deeSEric Joyner u32
iavf_ext_speed_to_ifmedia(enum iavf_ext_link_speed link_speed)993ca853deeSEric Joyner iavf_ext_speed_to_ifmedia(enum iavf_ext_link_speed link_speed)
994ca853deeSEric Joyner {
995ca853deeSEric Joyner 	switch (link_speed) {
996ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_100GB:
997ca853deeSEric Joyner 		return IFM_100G_SR4;
998ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_50GB:
999ca853deeSEric Joyner 		return IFM_50G_SR2;
1000ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_40GB:
1001ca853deeSEric Joyner 		return IFM_40G_SR4;
1002ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_25GB:
1003ca853deeSEric Joyner 		return IFM_25G_SR;
1004ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_20GB:
1005ca853deeSEric Joyner 		return IFM_20G_KR2;
1006ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_10GB:
1007ca853deeSEric Joyner 		return IFM_10G_SR;
1008ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_5GB:
1009ca853deeSEric Joyner 		return IFM_5000_T;
1010ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_2500MB:
1011ca853deeSEric Joyner 		return IFM_2500_T;
1012ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_1000MB:
1013ca853deeSEric Joyner 		return IFM_1000_T;
1014ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_100MB:
1015ca853deeSEric Joyner 		return IFM_100_TX;
1016ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_10MB:
1017ca853deeSEric Joyner 		return IFM_10_T;
1018ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_UNKNOWN:
1019ca853deeSEric Joyner 	default:
1020ca853deeSEric Joyner 		return IFM_UNKNOWN;
1021ca853deeSEric Joyner 	}
1022ca853deeSEric Joyner }
1023ca853deeSEric Joyner 
1024ca853deeSEric Joyner /**
1025ca853deeSEric Joyner  * iavf_vc_speed_to_ext_speed - Convert virtchnl speed enum to native iavf
1026ca853deeSEric Joyner  * driver speed representation.
1027ca853deeSEric Joyner  * @link_speed: link speed enum value
1028ca853deeSEric Joyner  *
1029ca853deeSEric Joyner  * @returns the link speed in the native iavf format.
1030ca853deeSEric Joyner  */
1031ca853deeSEric Joyner enum iavf_ext_link_speed
iavf_vc_speed_to_ext_speed(enum virtchnl_link_speed link_speed)1032ca853deeSEric Joyner iavf_vc_speed_to_ext_speed(enum virtchnl_link_speed link_speed)
1033ca853deeSEric Joyner {
1034ca853deeSEric Joyner 	switch (link_speed) {
1035ca853deeSEric Joyner 	case VIRTCHNL_LINK_SPEED_40GB:
1036ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_40GB;
1037ca853deeSEric Joyner 	case VIRTCHNL_LINK_SPEED_25GB:
1038ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_25GB;
1039ca853deeSEric Joyner 	case VIRTCHNL_LINK_SPEED_20GB:
1040ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_20GB;
1041ca853deeSEric Joyner 	case VIRTCHNL_LINK_SPEED_10GB:
1042ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_10GB;
1043ca853deeSEric Joyner 	case VIRTCHNL_LINK_SPEED_1GB:
1044ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_1000MB;
1045ca853deeSEric Joyner 	case VIRTCHNL_LINK_SPEED_100MB:
1046ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_100MB;
1047ca853deeSEric Joyner 	case VIRTCHNL_LINK_SPEED_UNKNOWN:
1048ca853deeSEric Joyner 	default:
1049ca853deeSEric Joyner 		return IAVF_EXT_LINK_SPEED_UNKNOWN;
1050ca853deeSEric Joyner 	}
1051ca853deeSEric Joyner }
1052ca853deeSEric Joyner 
1053ca853deeSEric Joyner /**
1054ca853deeSEric Joyner  * iavf_vc_speed_to_string - Convert virtchnl speed to a string
1055ca853deeSEric Joyner  * @link_speed: the speed to convert
1056ca853deeSEric Joyner  *
1057ca853deeSEric Joyner  * @returns string representing the link speed as reported by the virtchnl
1058ca853deeSEric Joyner  * interface.
1059ca853deeSEric Joyner  */
1060ca853deeSEric Joyner const char *
iavf_vc_speed_to_string(enum virtchnl_link_speed link_speed)1061ca853deeSEric Joyner iavf_vc_speed_to_string(enum virtchnl_link_speed link_speed)
1062ca853deeSEric Joyner {
1063ca853deeSEric Joyner 	return iavf_ext_speed_to_str(iavf_vc_speed_to_ext_speed(link_speed));
1064ca853deeSEric Joyner }
1065ca853deeSEric Joyner 
1066ca853deeSEric Joyner /**
1067ca853deeSEric Joyner  * iavf_ext_speed_to_str - Convert iavf speed enum to string representation
1068ca853deeSEric Joyner  * @link_speed: link speed enum value
1069ca853deeSEric Joyner  *
1070ca853deeSEric Joyner  * XXX: This is an iavf-modified copy of ice_aq_speed_to_str()
1071ca853deeSEric Joyner  *
1072ca853deeSEric Joyner  * @returns the string representation of the given link speed.
1073ca853deeSEric Joyner  */
1074ca853deeSEric Joyner const char *
iavf_ext_speed_to_str(enum iavf_ext_link_speed link_speed)1075ca853deeSEric Joyner iavf_ext_speed_to_str(enum iavf_ext_link_speed link_speed)
1076ca853deeSEric Joyner {
1077ca853deeSEric Joyner 	switch (link_speed) {
1078ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_100GB:
1079ca853deeSEric Joyner 		return "100 Gbps";
1080ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_50GB:
1081ca853deeSEric Joyner 		return "50 Gbps";
1082ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_40GB:
1083ca853deeSEric Joyner 		return "40 Gbps";
1084ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_25GB:
1085ca853deeSEric Joyner 		return "25 Gbps";
1086ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_20GB:
1087ca853deeSEric Joyner 		return "20 Gbps";
1088ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_10GB:
1089ca853deeSEric Joyner 		return "10 Gbps";
1090ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_5GB:
1091ca853deeSEric Joyner 		return "5 Gbps";
1092ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_2500MB:
1093ca853deeSEric Joyner 		return "2.5 Gbps";
1094ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_1000MB:
1095ca853deeSEric Joyner 		return "1 Gbps";
1096ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_100MB:
1097ca853deeSEric Joyner 		return "100 Mbps";
1098ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_10MB:
1099ca853deeSEric Joyner 		return "10 Mbps";
1100ca853deeSEric Joyner 	case IAVF_EXT_LINK_SPEED_UNKNOWN:
1101ca853deeSEric Joyner 	default:
1102ca853deeSEric Joyner 		return "Unknown";
1103ca853deeSEric Joyner 	}
1104ca853deeSEric Joyner }
1105ca853deeSEric Joyner 
1106ca853deeSEric Joyner /**
1107ca853deeSEric Joyner  * iavf_vc_opcode_str - Convert virtchnl opcode to string
1108ca853deeSEric Joyner  * @op: the virtchnl op code
1109ca853deeSEric Joyner  *
1110ca853deeSEric Joyner  * @returns the string representation of the given virtchnl op code
1111ca853deeSEric Joyner  */
1112ca853deeSEric Joyner const char *
iavf_vc_opcode_str(uint16_t op)1113ca853deeSEric Joyner iavf_vc_opcode_str(uint16_t op)
1114ca853deeSEric Joyner {
1115ca853deeSEric Joyner 	switch (op) {
1116ca853deeSEric Joyner 	case VIRTCHNL_OP_VERSION:
1117ca853deeSEric Joyner 		return ("VERSION");
1118ca853deeSEric Joyner 	case VIRTCHNL_OP_RESET_VF:
1119ca853deeSEric Joyner 		return ("RESET_VF");
1120ca853deeSEric Joyner 	case VIRTCHNL_OP_GET_VF_RESOURCES:
1121ca853deeSEric Joyner 		return ("GET_VF_RESOURCES");
1122ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_TX_QUEUE:
1123ca853deeSEric Joyner 		return ("CONFIG_TX_QUEUE");
1124ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_RX_QUEUE:
1125ca853deeSEric Joyner 		return ("CONFIG_RX_QUEUE");
1126ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
1127ca853deeSEric Joyner 		return ("CONFIG_VSI_QUEUES");
1128ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_IRQ_MAP:
1129ca853deeSEric Joyner 		return ("CONFIG_IRQ_MAP");
1130ca853deeSEric Joyner 	case VIRTCHNL_OP_ENABLE_QUEUES:
1131ca853deeSEric Joyner 		return ("ENABLE_QUEUES");
1132ca853deeSEric Joyner 	case VIRTCHNL_OP_DISABLE_QUEUES:
1133ca853deeSEric Joyner 		return ("DISABLE_QUEUES");
1134ca853deeSEric Joyner 	case VIRTCHNL_OP_ADD_ETH_ADDR:
1135ca853deeSEric Joyner 		return ("ADD_ETH_ADDR");
1136ca853deeSEric Joyner 	case VIRTCHNL_OP_DEL_ETH_ADDR:
1137ca853deeSEric Joyner 		return ("DEL_ETH_ADDR");
1138ca853deeSEric Joyner 	case VIRTCHNL_OP_ADD_VLAN:
1139ca853deeSEric Joyner 		return ("ADD_VLAN");
1140ca853deeSEric Joyner 	case VIRTCHNL_OP_DEL_VLAN:
1141ca853deeSEric Joyner 		return ("DEL_VLAN");
1142ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
1143ca853deeSEric Joyner 		return ("CONFIG_PROMISCUOUS_MODE");
1144ca853deeSEric Joyner 	case VIRTCHNL_OP_GET_STATS:
1145ca853deeSEric Joyner 		return ("GET_STATS");
1146ca853deeSEric Joyner 	case VIRTCHNL_OP_RSVD:
1147ca853deeSEric Joyner 		return ("RSVD");
1148ca853deeSEric Joyner 	case VIRTCHNL_OP_EVENT:
1149ca853deeSEric Joyner 		return ("EVENT");
1150ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_RSS_KEY:
1151ca853deeSEric Joyner 		return ("CONFIG_RSS_KEY");
1152ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_RSS_LUT:
1153ca853deeSEric Joyner 		return ("CONFIG_RSS_LUT");
1154ca853deeSEric Joyner 	case VIRTCHNL_OP_GET_RSS_HENA_CAPS:
1155ca853deeSEric Joyner 		return ("GET_RSS_HENA_CAPS");
1156ca853deeSEric Joyner 	case VIRTCHNL_OP_SET_RSS_HENA:
1157ca853deeSEric Joyner 		return ("SET_RSS_HENA");
1158ca853deeSEric Joyner 	default:
1159ca853deeSEric Joyner 		return ("UNKNOWN");
1160ca853deeSEric Joyner 	}
1161ca853deeSEric Joyner }
1162ca853deeSEric Joyner 
1163ca853deeSEric Joyner /**
1164ca853deeSEric Joyner  * iavf_vc_completion - Handle PF reply messages
1165ca853deeSEric Joyner  * @sc: device softc
1166ca853deeSEric Joyner  * @v_opcode: virtchnl op code
1167ca853deeSEric Joyner  * @v_retval: virtchnl return value
1168ca853deeSEric Joyner  * @msg: the message to send
1169ca853deeSEric Joyner  * @msglen: length of the msg buffer
1170ca853deeSEric Joyner  *
1171ca853deeSEric Joyner  * Asynchronous completion function for admin queue messages. Rather than busy
1172ca853deeSEric Joyner  * wait, we fire off our requests and assume that no errors will be returned.
1173ca853deeSEric Joyner  * This function handles the reply messages.
1174ca853deeSEric Joyner  */
1175ca853deeSEric Joyner void
iavf_vc_completion(struct iavf_sc * sc,enum virtchnl_ops v_opcode,enum virtchnl_status_code v_retval,u8 * msg,u16 msglen __unused)1176ca853deeSEric Joyner iavf_vc_completion(struct iavf_sc *sc,
1177ca853deeSEric Joyner     enum virtchnl_ops v_opcode,
1178ca853deeSEric Joyner     enum virtchnl_status_code v_retval, u8 *msg, u16 msglen __unused)
1179ca853deeSEric Joyner {
1180ca853deeSEric Joyner 	device_t	dev = sc->dev;
1181ca853deeSEric Joyner 
1182ca853deeSEric Joyner 	if (v_opcode != VIRTCHNL_OP_GET_STATS)
1183ca853deeSEric Joyner 		iavf_dbg_vc(sc, "%s: opcode %s\n", __func__,
1184ca853deeSEric Joyner 		    iavf_vc_opcode_str(v_opcode));
1185ca853deeSEric Joyner 
1186ca853deeSEric Joyner 	if (v_opcode == VIRTCHNL_OP_EVENT) {
1187ca853deeSEric Joyner 		struct virtchnl_pf_event *vpe =
1188ca853deeSEric Joyner 			(struct virtchnl_pf_event *)msg;
1189ca853deeSEric Joyner 
1190ca853deeSEric Joyner 		switch (vpe->event) {
1191ca853deeSEric Joyner 		case VIRTCHNL_EVENT_LINK_CHANGE:
1192ca853deeSEric Joyner 			iavf_handle_link_event(sc, vpe);
1193ca853deeSEric Joyner 			break;
1194ca853deeSEric Joyner 		case VIRTCHNL_EVENT_RESET_IMPENDING:
1195ca853deeSEric Joyner 			device_printf(dev, "PF initiated reset!\n");
1196ca853deeSEric Joyner 			iavf_set_state(&sc->state, IAVF_STATE_RESET_PENDING);
1197ca853deeSEric Joyner 			break;
1198ca853deeSEric Joyner 		default:
1199ca853deeSEric Joyner 			iavf_dbg_vc(sc, "Unknown event %d from AQ\n",
1200ca853deeSEric Joyner 				vpe->event);
1201ca853deeSEric Joyner 			break;
1202ca853deeSEric Joyner 		}
1203ca853deeSEric Joyner 
1204ca853deeSEric Joyner 		return;
1205ca853deeSEric Joyner 	}
1206ca853deeSEric Joyner 
1207ca853deeSEric Joyner 	/* Catch-all error response */
1208ca853deeSEric Joyner 	if (v_retval) {
1209ca853deeSEric Joyner 		bool print_error = true;
1210ca853deeSEric Joyner 
1211ca853deeSEric Joyner 		switch (v_opcode) {
1212ca853deeSEric Joyner 		case VIRTCHNL_OP_ADD_ETH_ADDR:
1213ca853deeSEric Joyner 			device_printf(dev, "WARNING: Error adding VF mac filter!\n");
1214ca853deeSEric Joyner 			device_printf(dev, "WARNING: Device may not receive traffic!\n");
1215ca853deeSEric Joyner 			break;
1216ca853deeSEric Joyner 		case VIRTCHNL_OP_ENABLE_QUEUES:
1217ca853deeSEric Joyner 			sc->enable_queues_chan = 1;
1218ca853deeSEric Joyner 			wakeup_one(&sc->enable_queues_chan);
1219ca853deeSEric Joyner 			break;
1220ca853deeSEric Joyner 		case VIRTCHNL_OP_DISABLE_QUEUES:
1221ca853deeSEric Joyner 			sc->disable_queues_chan = 1;
1222ca853deeSEric Joyner 			wakeup_one(&sc->disable_queues_chan);
1223ca853deeSEric Joyner 			/* This may fail, but it does not necessarily mean that
1224ca853deeSEric Joyner 			 * something is critically wrong.
1225ca853deeSEric Joyner 			 */
1226ca853deeSEric Joyner 			if (!(sc->dbg_mask & IAVF_DBG_VC))
1227ca853deeSEric Joyner 				print_error = false;
1228ca853deeSEric Joyner 			break;
1229ca853deeSEric Joyner 		default:
1230ca853deeSEric Joyner 			break;
1231ca853deeSEric Joyner 		}
1232ca853deeSEric Joyner 
1233ca853deeSEric Joyner 		if (print_error)
1234ca853deeSEric Joyner 			device_printf(dev,
1235ca853deeSEric Joyner 			    "%s: AQ returned error %s to our request %s!\n",
1236ca853deeSEric Joyner 			    __func__, iavf_vc_stat_str(&sc->hw, v_retval),
1237ca853deeSEric Joyner 			    iavf_vc_opcode_str(v_opcode));
1238ca853deeSEric Joyner 		return;
1239ca853deeSEric Joyner 	}
1240ca853deeSEric Joyner 
1241ca853deeSEric Joyner 	switch (v_opcode) {
1242ca853deeSEric Joyner 	case VIRTCHNL_OP_GET_STATS:
1243ca853deeSEric Joyner 		iavf_update_stats_counters(sc, (struct iavf_eth_stats *)msg);
1244ca853deeSEric Joyner 		break;
1245ca853deeSEric Joyner 	case VIRTCHNL_OP_ADD_ETH_ADDR:
1246ca853deeSEric Joyner 		break;
1247ca853deeSEric Joyner 	case VIRTCHNL_OP_DEL_ETH_ADDR:
1248ca853deeSEric Joyner 		break;
1249ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
1250ca853deeSEric Joyner 		break;
1251ca853deeSEric Joyner 	case VIRTCHNL_OP_ADD_VLAN:
1252ca853deeSEric Joyner 		break;
1253ca853deeSEric Joyner 	case VIRTCHNL_OP_DEL_VLAN:
1254ca853deeSEric Joyner 		break;
1255ca853deeSEric Joyner 	case VIRTCHNL_OP_ENABLE_QUEUES:
1256ca853deeSEric Joyner 		atomic_store_rel_32(&sc->queues_enabled, 1);
1257ca853deeSEric Joyner 		sc->enable_queues_chan = 1;
1258ca853deeSEric Joyner 		wakeup_one(&sc->enable_queues_chan);
1259ca853deeSEric Joyner 		break;
1260ca853deeSEric Joyner 	case VIRTCHNL_OP_DISABLE_QUEUES:
1261ca853deeSEric Joyner 		atomic_store_rel_32(&sc->queues_enabled, 0);
1262ca853deeSEric Joyner 		sc->disable_queues_chan = 1;
1263ca853deeSEric Joyner 		wakeup_one(&sc->disable_queues_chan);
1264ca853deeSEric Joyner 		break;
1265ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
1266ca853deeSEric Joyner 		break;
1267ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_IRQ_MAP:
1268ca853deeSEric Joyner 		break;
1269ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_RSS_KEY:
1270ca853deeSEric Joyner 		break;
1271ca853deeSEric Joyner 	case VIRTCHNL_OP_SET_RSS_HENA:
1272ca853deeSEric Joyner 		break;
1273ca853deeSEric Joyner 	case VIRTCHNL_OP_CONFIG_RSS_LUT:
1274ca853deeSEric Joyner 		break;
1275ca853deeSEric Joyner 	default:
1276ca853deeSEric Joyner 		iavf_dbg_vc(sc,
1277ca853deeSEric Joyner 		    "Received unexpected message %s from PF.\n",
1278ca853deeSEric Joyner 		    iavf_vc_opcode_str(v_opcode));
1279ca853deeSEric Joyner 		break;
1280ca853deeSEric Joyner 	}
1281ca853deeSEric Joyner }
1282ca853deeSEric Joyner 
1283ca853deeSEric Joyner /**
1284ca853deeSEric Joyner  * iavf_handle_link_event - Handle Link event virtchml message
1285ca853deeSEric Joyner  * @sc: device softc
1286ca853deeSEric Joyner  * @vpe: virtchnl PF link event structure
1287ca853deeSEric Joyner  *
1288ca853deeSEric Joyner  * Process a virtchnl PF link event and update the driver and stack status of
1289ca853deeSEric Joyner  * the link event.
1290ca853deeSEric Joyner  */
1291ca853deeSEric Joyner static void
iavf_handle_link_event(struct iavf_sc * sc,struct virtchnl_pf_event * vpe)1292ca853deeSEric Joyner iavf_handle_link_event(struct iavf_sc *sc, struct virtchnl_pf_event *vpe)
1293ca853deeSEric Joyner {
1294ca853deeSEric Joyner 	MPASS(vpe->event == VIRTCHNL_EVENT_LINK_CHANGE);
1295ca853deeSEric Joyner 
1296ca853deeSEric Joyner 	if (sc->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_ADV_LINK_SPEED)
1297ca853deeSEric Joyner 	{
1298ca853deeSEric Joyner 		iavf_dbg_vc(sc, "Link change (adv): status %d, speed %u\n",
1299ca853deeSEric Joyner 		    vpe->event_data.link_event_adv.link_status,
1300ca853deeSEric Joyner 		    vpe->event_data.link_event_adv.link_speed);
1301ca853deeSEric Joyner 		sc->link_up =
1302ca853deeSEric Joyner 			vpe->event_data.link_event_adv.link_status;
1303ca853deeSEric Joyner 		sc->link_speed_adv =
1304ca853deeSEric Joyner 			vpe->event_data.link_event_adv.link_speed;
1305ca853deeSEric Joyner 
1306ca853deeSEric Joyner 	} else {
1307ca853deeSEric Joyner 		iavf_dbg_vc(sc, "Link change: status %d, speed %x\n",
1308ca853deeSEric Joyner 		    vpe->event_data.link_event.link_status,
1309ca853deeSEric Joyner 		    vpe->event_data.link_event.link_speed);
1310ca853deeSEric Joyner 		sc->link_up =
1311ca853deeSEric Joyner 			vpe->event_data.link_event.link_status;
1312ca853deeSEric Joyner 		sc->link_speed =
1313ca853deeSEric Joyner 			vpe->event_data.link_event.link_speed;
1314ca853deeSEric Joyner 	}
1315ca853deeSEric Joyner 
1316ca853deeSEric Joyner 	iavf_update_link_status(sc);
1317ca853deeSEric Joyner }
1318