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