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