xref: /openbsd-src/sys/dev/pci/if_iavf.c (revision 51248bbd565d4bc7e4685749d06ef754afcd1c21)
1*51248bbdSyasuoka /*	$OpenBSD: if_iavf.c,v 1.18 2024/11/27 02:40:53 yasuoka Exp $	*/
24ccba60fSjmatthew 
34ccba60fSjmatthew /*
44ccba60fSjmatthew  * Copyright (c) 2013-2015, Intel Corporation
54ccba60fSjmatthew  * All rights reserved.
64ccba60fSjmatthew 
74ccba60fSjmatthew  * Redistribution and use in source and binary forms, with or without
84ccba60fSjmatthew  * modification, are permitted provided that the following conditions are met:
94ccba60fSjmatthew  *
104ccba60fSjmatthew  *  1. Redistributions of source code must retain the above copyright notice,
114ccba60fSjmatthew  *     this list of conditions and the following disclaimer.
124ccba60fSjmatthew  *
134ccba60fSjmatthew  *  2. Redistributions in binary form must reproduce the above copyright
144ccba60fSjmatthew  *     notice, this list of conditions and the following disclaimer in the
154ccba60fSjmatthew  *     documentation and/or other materials provided with the distribution.
164ccba60fSjmatthew  *
174ccba60fSjmatthew  *  3. Neither the name of the Intel Corporation nor the names of its
184ccba60fSjmatthew  *     contributors may be used to endorse or promote products derived from
194ccba60fSjmatthew  *     this software without specific prior written permission.
204ccba60fSjmatthew  *
214ccba60fSjmatthew  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
224ccba60fSjmatthew  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
234ccba60fSjmatthew  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
244ccba60fSjmatthew  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
254ccba60fSjmatthew  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
264ccba60fSjmatthew  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
274ccba60fSjmatthew  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
284ccba60fSjmatthew  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
294ccba60fSjmatthew  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
304ccba60fSjmatthew  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
314ccba60fSjmatthew  * POSSIBILITY OF SUCH DAMAGE.
324ccba60fSjmatthew  */
334ccba60fSjmatthew 
344ccba60fSjmatthew /*
354ccba60fSjmatthew  * Copyright (c) 2016,2017 David Gwynne <dlg@openbsd.org>
364ccba60fSjmatthew  * Copyright (c) 2019 Jonathan Matthew <jmatthew@openbsd.org>
374ccba60fSjmatthew  *
384ccba60fSjmatthew  * Permission to use, copy, modify, and distribute this software for any
394ccba60fSjmatthew  * purpose with or without fee is hereby granted, provided that the above
404ccba60fSjmatthew  * copyright notice and this permission notice appear in all copies.
414ccba60fSjmatthew  *
424ccba60fSjmatthew  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
434ccba60fSjmatthew  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
444ccba60fSjmatthew  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
454ccba60fSjmatthew  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
464ccba60fSjmatthew  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
474ccba60fSjmatthew  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
484ccba60fSjmatthew  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
494ccba60fSjmatthew  */
504ccba60fSjmatthew 
514ccba60fSjmatthew #include "bpfilter.h"
52*51248bbdSyasuoka #include "vlan.h"
534ccba60fSjmatthew 
544ccba60fSjmatthew #include <sys/param.h>
554ccba60fSjmatthew #include <sys/systm.h>
564ccba60fSjmatthew #include <sys/proc.h>
574ccba60fSjmatthew #include <sys/sockio.h>
584ccba60fSjmatthew #include <sys/mbuf.h>
594ccba60fSjmatthew #include <sys/socket.h>
604ccba60fSjmatthew #include <sys/device.h>
614ccba60fSjmatthew #include <sys/pool.h>
624ccba60fSjmatthew #include <sys/queue.h>
634ccba60fSjmatthew #include <sys/timeout.h>
644ccba60fSjmatthew #include <sys/task.h>
654ccba60fSjmatthew #include <sys/syslog.h>
664ccba60fSjmatthew 
674ccba60fSjmatthew #include <machine/bus.h>
684ccba60fSjmatthew #include <machine/intr.h>
694ccba60fSjmatthew 
704ccba60fSjmatthew #include <net/if.h>
714ccba60fSjmatthew #include <net/if_media.h>
724ccba60fSjmatthew 
734ccba60fSjmatthew #if NBPFILTER > 0
744ccba60fSjmatthew #include <net/bpf.h>
754ccba60fSjmatthew #endif
764ccba60fSjmatthew 
774ccba60fSjmatthew #include <netinet/in.h>
784ccba60fSjmatthew #include <netinet/if_ether.h>
79*51248bbdSyasuoka #include <netinet/udp.h>
804ccba60fSjmatthew 
814ccba60fSjmatthew #include <dev/pci/pcireg.h>
824ccba60fSjmatthew #include <dev/pci/pcivar.h>
834ccba60fSjmatthew #include <dev/pci/pcidevs.h>
844ccba60fSjmatthew 
854ccba60fSjmatthew #define I40E_MASK(mask, shift)		((mask) << (shift))
864ccba60fSjmatthew #define I40E_AQ_LARGE_BUF		512
874ccba60fSjmatthew 
882fa30b92Sjmatthew #define IAVF_REG_VFR			0xdeadbeef
892fa30b92Sjmatthew 
904ccba60fSjmatthew #define IAVF_VFR_INPROGRESS		0
914ccba60fSjmatthew #define IAVF_VFR_COMPLETED		1
924ccba60fSjmatthew #define IAVF_VFR_VFACTIVE		2
934ccba60fSjmatthew 
944ccba60fSjmatthew #include <dev/pci/if_ixlreg.h>
954ccba60fSjmatthew 
964ccba60fSjmatthew struct iavf_aq_desc {
974ccba60fSjmatthew 	uint16_t	iaq_flags;
984ccba60fSjmatthew #define	IAVF_AQ_DD		(1U << 0)
994ccba60fSjmatthew #define	IAVF_AQ_CMP		(1U << 1)
1004ccba60fSjmatthew #define IAVF_AQ_ERR		(1U << 2)
1014ccba60fSjmatthew #define IAVF_AQ_VFE		(1U << 3)
1024ccba60fSjmatthew #define IAVF_AQ_LB		(1U << 9)
1034ccba60fSjmatthew #define IAVF_AQ_RD		(1U << 10)
1044ccba60fSjmatthew #define IAVF_AQ_VFC		(1U << 11)
1054ccba60fSjmatthew #define IAVF_AQ_BUF		(1U << 12)
1064ccba60fSjmatthew #define IAVF_AQ_SI		(1U << 13)
1074ccba60fSjmatthew #define IAVF_AQ_EI		(1U << 14)
1084ccba60fSjmatthew #define IAVF_AQ_FE		(1U << 15)
1094ccba60fSjmatthew 
1104ccba60fSjmatthew #define IAVF_AQ_FLAGS_FMT	"\020" "\020FE" "\017EI" "\016SI" "\015BUF" \
1114ccba60fSjmatthew 				    "\014VFC" "\013DB" "\012LB" "\004VFE" \
1124ccba60fSjmatthew 				    "\003ERR" "\002CMP" "\001DD"
1134ccba60fSjmatthew 
1144ccba60fSjmatthew 	uint16_t	iaq_opcode;
1154ccba60fSjmatthew 
1164ccba60fSjmatthew 	uint16_t	iaq_datalen;
1174ccba60fSjmatthew 	uint16_t	iaq_retval;
1184ccba60fSjmatthew 
1194ccba60fSjmatthew 	uint32_t	iaq_vc_opcode;
1204ccba60fSjmatthew 	uint32_t	iaq_vc_retval;
1214ccba60fSjmatthew 
1224ccba60fSjmatthew 	uint32_t	iaq_param[4];
1234ccba60fSjmatthew /*	iaq_vfid	iaq_param[0] */
1244ccba60fSjmatthew /*	iaq_data_hi	iaq_param[2] */
1254ccba60fSjmatthew /*	iaq_data_lo	iaq_param[3] */
1264ccba60fSjmatthew } __packed __aligned(8);
1274ccba60fSjmatthew 
1284ccba60fSjmatthew /* aq commands */
1294ccba60fSjmatthew #define IAVF_AQ_OP_SEND_TO_PF		0x0801
1304ccba60fSjmatthew #define IAVF_AQ_OP_MSG_FROM_PF		0x0802
1314ccba60fSjmatthew #define IAVF_AQ_OP_SHUTDOWN		0x0803
1324ccba60fSjmatthew 
1334ccba60fSjmatthew /* virt channel messages */
1344ccba60fSjmatthew #define IAVF_VC_OP_VERSION		1
1354ccba60fSjmatthew #define IAVF_VC_OP_RESET_VF		2
1364ccba60fSjmatthew #define IAVF_VC_OP_GET_VF_RESOURCES	3
1374ccba60fSjmatthew #define IAVF_VC_OP_CONFIG_TX_QUEUE	4
1384ccba60fSjmatthew #define IAVF_VC_OP_CONFIG_RX_QUEUE	5
1394ccba60fSjmatthew #define IAVF_VC_OP_CONFIG_VSI_QUEUES	6
1404ccba60fSjmatthew #define IAVF_VC_OP_CONFIG_IRQ_MAP	7
1414ccba60fSjmatthew #define IAVF_VC_OP_ENABLE_QUEUES	8
1424ccba60fSjmatthew #define IAVF_VC_OP_DISABLE_QUEUES	9
1434ccba60fSjmatthew #define IAVF_VC_OP_ADD_ETH_ADDR		10
1444ccba60fSjmatthew #define IAVF_VC_OP_DEL_ETH_ADDR		11
1454ccba60fSjmatthew #define IAVF_VC_OP_ADD_VLAN		12
1464ccba60fSjmatthew #define IAVF_VC_OP_DEL_VLAN		13
1474ccba60fSjmatthew #define IAVF_VC_OP_CONFIG_PROMISC	14
1484ccba60fSjmatthew #define IAVF_VC_OP_GET_STATS		15
1494ccba60fSjmatthew #define IAVF_VC_OP_EVENT		17
1504ccba60fSjmatthew #define IAVF_VC_OP_GET_RSS_HENA_CAPS	25
1514ccba60fSjmatthew #define IAVF_VC_OP_SET_RSS_HENA		26
1524ccba60fSjmatthew 
1534ccba60fSjmatthew /* virt channel response codes */
1544ccba60fSjmatthew #define IAVF_VC_RC_SUCCESS		0
1554ccba60fSjmatthew #define IAVF_VC_RC_ERR_PARAM		-5
1564ccba60fSjmatthew #define IAVF_VC_RC_ERR_OPCODE		-38
1574ccba60fSjmatthew #define IAVF_VC_RC_ERR_CQP_COMPL	-39
1584ccba60fSjmatthew #define IAVF_VC_RC_ERR_VF_ID		-40
1594ccba60fSjmatthew #define IAVF_VC_RC_ERR_NOT_SUP		-64
1604ccba60fSjmatthew 
1614ccba60fSjmatthew /* virt channel events */
1624ccba60fSjmatthew #define IAVF_VC_EVENT_LINK_CHANGE	1
1634ccba60fSjmatthew #define IAVF_VC_EVENT_RESET_IMPENDING	2
1644ccba60fSjmatthew #define IAVF_VC_EVENT_PF_DRIVER_CLOSE	3
1654ccba60fSjmatthew 
1664ccba60fSjmatthew /* virt channel offloads */
1674ccba60fSjmatthew #define IAVF_VC_OFFLOAD_L2		0x00000001
1684ccba60fSjmatthew #define IAVF_VC_OFFLOAD_IWARP		0x00000002
1694ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RSVD		0x00000004
1704ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RSS_AQ		0x00000008
1714ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RSS_REG		0x00000010
1724ccba60fSjmatthew #define IAVF_VC_OFFLOAD_WB_ON_ITR	0x00000020
1734ccba60fSjmatthew #define IAVF_VC_OFFLOAD_VLAN		0x00010000
1744ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RX_POLLING	0x00020000
1754ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RSS_PCTYPE_V2	0x00040000
1764ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RSS_PF		0x00080000
1774ccba60fSjmatthew #define IAVF_VC_OFFLOAD_ENCAP		0x00100000
1784ccba60fSjmatthew #define IAVF_VC_OFFLOAD_ENCAP_CSUM	0x00200000
1794ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RX_ENCAP_CSUM	0x00400000
1804ccba60fSjmatthew 
1814ccba60fSjmatthew /* link speeds */
1824ccba60fSjmatthew #define IAVF_VC_LINK_SPEED_100MB	0x1
1834ccba60fSjmatthew #define IAVC_VC_LINK_SPEED_1000MB	0x2
1844ccba60fSjmatthew #define IAVC_VC_LINK_SPEED_10GB		0x3
1854ccba60fSjmatthew #define IAVC_VC_LINK_SPEED_40GB		0x4
1864ccba60fSjmatthew #define IAVC_VC_LINK_SPEED_20GB		0x5
1874ccba60fSjmatthew #define IAVC_VC_LINK_SPEED_25GB		0x6
1884ccba60fSjmatthew 
189baed872eSjmatthew struct iavf_link_speed {
190baed872eSjmatthew 	uint64_t	baudrate;
191baed872eSjmatthew 	uint64_t	media;
192baed872eSjmatthew };
193baed872eSjmatthew 
194baed872eSjmatthew static const struct iavf_link_speed iavf_link_speeds[] = {
195baed872eSjmatthew 	{ 0, 0 },
196baed872eSjmatthew 	{ IF_Mbps(100), IFM_100_TX },
197baed872eSjmatthew 	{ IF_Mbps(1000), IFM_1000_T },
198baed872eSjmatthew 	{ IF_Gbps(10), IFM_10G_T },
199baed872eSjmatthew 	{ IF_Gbps(40), IFM_40G_CR4 },
200baed872eSjmatthew 	{ IF_Gbps(20), IFM_20G_KR2 },
201baed872eSjmatthew 	{ IF_Gbps(25), IFM_25G_CR }
202baed872eSjmatthew };
203baed872eSjmatthew 
2044ccba60fSjmatthew 
2054ccba60fSjmatthew struct iavf_vc_version_info {
2064ccba60fSjmatthew 	uint32_t	major;
2074ccba60fSjmatthew 	uint32_t	minor;
2084ccba60fSjmatthew } __packed;
2094ccba60fSjmatthew 
2104ccba60fSjmatthew struct iavf_vc_txq_info {
2114ccba60fSjmatthew 	uint16_t	vsi_id;
2124ccba60fSjmatthew 	uint16_t	queue_id;
2134ccba60fSjmatthew 	uint16_t	ring_len;
2144ccba60fSjmatthew 	uint16_t	headwb_ena;		/* deprecated */
2154ccba60fSjmatthew 	uint64_t	dma_ring_addr;
2164ccba60fSjmatthew 	uint64_t	dma_headwb_addr;	/* deprecated */
2174ccba60fSjmatthew } __packed;
2184ccba60fSjmatthew 
2194ccba60fSjmatthew struct iavf_vc_rxq_info {
2204ccba60fSjmatthew 	uint16_t	vsi_id;
2214ccba60fSjmatthew 	uint16_t	queue_id;
2224ccba60fSjmatthew 	uint32_t	ring_len;
2234ccba60fSjmatthew 	uint16_t	hdr_size;
2244ccba60fSjmatthew 	uint16_t	splithdr_ena;
2254ccba60fSjmatthew 	uint32_t	databuf_size;
2264ccba60fSjmatthew 	uint32_t	max_pkt_size;
2274ccba60fSjmatthew 	uint32_t	pad1;
2284ccba60fSjmatthew 	uint64_t	dma_ring_addr;
2294ccba60fSjmatthew 	uint32_t	rx_split_pos;
2304ccba60fSjmatthew 	uint32_t	pad2;
2314ccba60fSjmatthew } __packed;
2324ccba60fSjmatthew 
2334ccba60fSjmatthew struct iavf_vc_queue_pair_info {
2344ccba60fSjmatthew 	struct iavf_vc_txq_info	txq;
2354ccba60fSjmatthew 	struct iavf_vc_rxq_info	rxq;
2364ccba60fSjmatthew } __packed;
2374ccba60fSjmatthew 
2384ccba60fSjmatthew struct iavf_vc_queue_config_info {
2394ccba60fSjmatthew 	uint16_t	vsi_id;
2404ccba60fSjmatthew 	uint16_t	num_queue_pairs;
2414ccba60fSjmatthew 	uint32_t	pad;
2424ccba60fSjmatthew 	struct iavf_vc_queue_pair_info qpair[1];
2434ccba60fSjmatthew } __packed;
2444ccba60fSjmatthew 
2454ccba60fSjmatthew struct iavf_vc_vector_map {
2464ccba60fSjmatthew 	uint16_t	vsi_id;
2474ccba60fSjmatthew 	uint16_t	vector_id;
2484ccba60fSjmatthew 	uint16_t	rxq_map;
2494ccba60fSjmatthew 	uint16_t	txq_map;
2504ccba60fSjmatthew 	uint16_t	rxitr_idx;
2514ccba60fSjmatthew 	uint16_t	txitr_idx;
2524ccba60fSjmatthew } __packed;
2534ccba60fSjmatthew 
2544ccba60fSjmatthew struct iavf_vc_irq_map_info {
2554ccba60fSjmatthew 	uint16_t	num_vectors;
2564ccba60fSjmatthew 	struct iavf_vc_vector_map vecmap[1];
2574ccba60fSjmatthew } __packed;
2584ccba60fSjmatthew 
2594ccba60fSjmatthew struct iavf_vc_queue_select {
2604ccba60fSjmatthew 	uint16_t	vsi_id;
2614ccba60fSjmatthew 	uint16_t	pad;
2624ccba60fSjmatthew 	uint32_t	rx_queues;
2634ccba60fSjmatthew 	uint32_t	tx_queues;
2644ccba60fSjmatthew } __packed;
2654ccba60fSjmatthew 
2664ccba60fSjmatthew struct iavf_vc_vsi_resource {
2674ccba60fSjmatthew 	uint16_t	vsi_id;
2684ccba60fSjmatthew 	uint16_t	num_queue_pairs;
2694ccba60fSjmatthew 	uint32_t	vsi_type;
2704ccba60fSjmatthew 	uint16_t	qset_handle;
2714ccba60fSjmatthew 	uint8_t		default_mac[ETHER_ADDR_LEN];
2724ccba60fSjmatthew } __packed;
2734ccba60fSjmatthew 
2744ccba60fSjmatthew struct iavf_vc_vf_resource {
2754ccba60fSjmatthew 	uint16_t	num_vsis;
2764ccba60fSjmatthew 	uint16_t	num_qp;
2774ccba60fSjmatthew 	uint16_t	max_vectors;
2784ccba60fSjmatthew 	uint16_t	max_mtu;
2794ccba60fSjmatthew 	uint32_t	offload_flags;
2804ccba60fSjmatthew 	uint32_t	rss_key_size;
2814ccba60fSjmatthew 	uint32_t	rss_lut_size;
2824ccba60fSjmatthew 	struct iavf_vc_vsi_resource vsi_res[1];
2834ccba60fSjmatthew } __packed;
2844ccba60fSjmatthew 
2854ccba60fSjmatthew struct iavf_vc_eth_addr {
2864ccba60fSjmatthew 	uint8_t		addr[ETHER_ADDR_LEN];
2874ccba60fSjmatthew 	uint8_t		pad[2];
2884ccba60fSjmatthew } __packed;
2894ccba60fSjmatthew 
2904ccba60fSjmatthew struct iavf_vc_eth_addr_list {
2914ccba60fSjmatthew 	uint16_t	vsi_id;
2924ccba60fSjmatthew 	uint16_t	num_elements;
2934ccba60fSjmatthew 	struct iavf_vc_eth_addr list[1];
2944ccba60fSjmatthew } __packed;
2954ccba60fSjmatthew 
2964ccba60fSjmatthew struct iavf_vc_vlan_list {
2974ccba60fSjmatthew 	uint16_t	vsi_id;
2984ccba60fSjmatthew 	uint16_t	num_elements;
2994ccba60fSjmatthew 	uint16_t	vlan_id[1];
3004ccba60fSjmatthew } __packed;
3014ccba60fSjmatthew 
3024ccba60fSjmatthew struct iavf_vc_promisc_info {
3034ccba60fSjmatthew 	uint16_t	vsi_id;
3044ccba60fSjmatthew 	uint16_t	flags;
3054ccba60fSjmatthew #define IAVF_FLAG_VF_UNICAST_PROMISC	0x0001
3064ccba60fSjmatthew #define IAVF_FLAG_VF_MULTICAST_PROMISC	0x0002
3074ccba60fSjmatthew } __packed;
3084ccba60fSjmatthew 
3094ccba60fSjmatthew struct iavf_vc_pf_event {
3104ccba60fSjmatthew 	uint32_t	event;
3114ccba60fSjmatthew 	uint32_t	link_speed;
3124ccba60fSjmatthew 	uint8_t		link_status;
3134ccba60fSjmatthew 	uint8_t		pad[3];
3144ccba60fSjmatthew 	uint32_t	severity;
3154ccba60fSjmatthew } __packed;
3164ccba60fSjmatthew 
3174ccba60fSjmatthew /* aq response codes */
3184ccba60fSjmatthew #define IAVF_AQ_RC_OK			0  /* success */
3194ccba60fSjmatthew #define IAVF_AQ_RC_EPERM		1  /* Operation not permitted */
3204ccba60fSjmatthew #define IAVF_AQ_RC_ENOENT		2  /* No such element */
3214ccba60fSjmatthew #define IAVF_AQ_RC_ESRCH		3  /* Bad opcode */
3224ccba60fSjmatthew #define IAVF_AQ_RC_EINTR		4  /* operation interrupted */
3234ccba60fSjmatthew #define IAVF_AQ_RC_EIO			5  /* I/O error */
3244ccba60fSjmatthew #define IAVF_AQ_RC_ENXIO		6  /* No such resource */
3254ccba60fSjmatthew #define IAVF_AQ_RC_E2BIG		7  /* Arg too long */
3264ccba60fSjmatthew #define IAVF_AQ_RC_EAGAIN		8  /* Try again */
3274ccba60fSjmatthew #define IAVF_AQ_RC_ENOMEM		9  /* Out of memory */
3284ccba60fSjmatthew #define IAVF_AQ_RC_EACCES		10 /* Permission denied */
3294ccba60fSjmatthew #define IAVF_AQ_RC_EFAULT		11 /* Bad address */
3304ccba60fSjmatthew #define IAVF_AQ_RC_EBUSY		12 /* Device or resource busy */
3314ccba60fSjmatthew #define IAVF_AQ_RC_EEXIST		13 /* object already exists */
3324ccba60fSjmatthew #define IAVF_AQ_RC_EINVAL		14 /* invalid argument */
3334ccba60fSjmatthew #define IAVF_AQ_RC_ENOTTY		15 /* not a typewriter */
3344ccba60fSjmatthew #define IAVF_AQ_RC_ENOSPC		16 /* No space or alloc failure */
3354ccba60fSjmatthew #define IAVF_AQ_RC_ENOSYS		17 /* function not implemented */
3364ccba60fSjmatthew #define IAVF_AQ_RC_ERANGE		18 /* parameter out of range */
3374ccba60fSjmatthew #define IAVF_AQ_RC_EFLUSHED		19 /* cmd flushed due to prev error */
3384ccba60fSjmatthew #define IAVF_AQ_RC_BAD_ADDR		20 /* contains a bad pointer */
3394ccba60fSjmatthew #define IAVF_AQ_RC_EMODE		21 /* not allowed in current mode */
3404ccba60fSjmatthew #define IAVF_AQ_RC_EFBIG		22 /* file too large */
3414ccba60fSjmatthew 
3424ccba60fSjmatthew struct iavf_tx_desc {
3434ccba60fSjmatthew 	uint64_t		addr;
3444ccba60fSjmatthew 	uint64_t		cmd;
3454ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_SHIFT		0
3464ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_MASK		(0xfULL << IAVF_TX_DESC_DTYPE_SHIFT)
3474ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_DATA		(0x0ULL << IAVF_TX_DESC_DTYPE_SHIFT)
3484ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_NOP		(0x1ULL << IAVF_TX_DESC_DTYPE_SHIFT)
3494ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_CONTEXT	(0x1ULL << IAVF_TX_DESC_DTYPE_SHIFT)
3504ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_FCOE_CTX	(0x2ULL << IAVF_TX_DESC_DTYPE_SHIFT)
3514ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_FD		(0x8ULL << IAVF_TX_DESC_DTYPE_SHIFT)
3524ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_DDP_CTX	(0x9ULL << IAVF_TX_DESC_DTYPE_SHIFT)
3534ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_FLEX_DATA	(0xbULL << IAVF_TX_DESC_DTYPE_SHIFT)
3544ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_FLEX_CTX_1	(0xcULL << IAVF_TX_DESC_DTYPE_SHIFT)
3554ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_FLEX_CTX_2	(0xdULL << IAVF_TX_DESC_DTYPE_SHIFT)
3564ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_DONE		(0xfULL << IAVF_TX_DESC_DTYPE_SHIFT)
3574ccba60fSjmatthew 
3584ccba60fSjmatthew #define IAVF_TX_DESC_CMD_SHIFT		4
3594ccba60fSjmatthew #define IAVF_TX_DESC_CMD_MASK		(0x3ffULL << IAVF_TX_DESC_CMD_SHIFT)
3604ccba60fSjmatthew #define IAVF_TX_DESC_CMD_EOP		(0x001 << IAVF_TX_DESC_CMD_SHIFT)
3614ccba60fSjmatthew #define IAVF_TX_DESC_CMD_RS		(0x002 << IAVF_TX_DESC_CMD_SHIFT)
3624ccba60fSjmatthew #define IAVF_TX_DESC_CMD_ICRC		(0x004 << IAVF_TX_DESC_CMD_SHIFT)
3634ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IL2TAG1	(0x008 << IAVF_TX_DESC_CMD_SHIFT)
3644ccba60fSjmatthew #define IAVF_TX_DESC_CMD_DUMMY		(0x010 << IAVF_TX_DESC_CMD_SHIFT)
3654ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IIPT_MASK	(0x060 << IAVF_TX_DESC_CMD_SHIFT)
3664ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IIPT_NONIP	(0x000 << IAVF_TX_DESC_CMD_SHIFT)
3674ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IIPT_IPV6	(0x020 << IAVF_TX_DESC_CMD_SHIFT)
3684ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IIPT_IPV4	(0x040 << IAVF_TX_DESC_CMD_SHIFT)
3694ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IIPT_IPV4_CSUM	(0x060 << IAVF_TX_DESC_CMD_SHIFT)
3704ccba60fSjmatthew #define IAVF_TX_DESC_CMD_FCOET		(0x080 << IAVF_TX_DESC_CMD_SHIFT)
3714ccba60fSjmatthew #define IAVF_TX_DESC_CMD_L4T_EOFT_MASK	(0x300 << IAVF_TX_DESC_CMD_SHIFT)
3724ccba60fSjmatthew #define IAVF_TX_DESC_CMD_L4T_EOFT_UNK	(0x000 << IAVF_TX_DESC_CMD_SHIFT)
3734ccba60fSjmatthew #define IAVF_TX_DESC_CMD_L4T_EOFT_TCP	(0x100 << IAVF_TX_DESC_CMD_SHIFT)
3744ccba60fSjmatthew #define IAVF_TX_DESC_CMD_L4T_EOFT_SCTP	(0x200 << IAVF_TX_DESC_CMD_SHIFT)
3754ccba60fSjmatthew #define IAVF_TX_DESC_CMD_L4T_EOFT_UDP	(0x300 << IAVF_TX_DESC_CMD_SHIFT)
3764ccba60fSjmatthew 
3774ccba60fSjmatthew #define IAVF_TX_DESC_MACLEN_SHIFT	16
3784ccba60fSjmatthew #define IAVF_TX_DESC_MACLEN_MASK	(0x7fULL << IAVF_TX_DESC_MACLEN_SHIFT)
3794ccba60fSjmatthew #define IAVF_TX_DESC_IPLEN_SHIFT	23
3804ccba60fSjmatthew #define IAVF_TX_DESC_IPLEN_MASK		(0x7fULL << IAVF_TX_DESC_IPLEN_SHIFT)
3814ccba60fSjmatthew #define IAVF_TX_DESC_L4LEN_SHIFT	30
3824ccba60fSjmatthew #define IAVF_TX_DESC_L4LEN_MASK		(0xfULL << IAVF_TX_DESC_L4LEN_SHIFT)
3834ccba60fSjmatthew #define IAVF_TX_DESC_FCLEN_SHIFT	30
3844ccba60fSjmatthew #define IAVF_TX_DESC_FCLEN_MASK		(0xfULL << IAVF_TX_DESC_FCLEN_SHIFT)
3854ccba60fSjmatthew 
3864ccba60fSjmatthew #define IAVF_TX_DESC_BSIZE_SHIFT	34
3874ccba60fSjmatthew #define IAVF_TX_DESC_BSIZE_MAX		0x3fffULL
3884ccba60fSjmatthew #define IAVF_TX_DESC_BSIZE_MASK		\
3894ccba60fSjmatthew 	(IAVF_TX_DESC_BSIZE_MAX << IAVF_TX_DESC_BSIZE_SHIFT)
3903e0b52e8Sjmatthew 
3913e0b52e8Sjmatthew #define IAVF_TX_DESC_L2TAG1_SHIFT	48
3923e0b52e8Sjmatthew #define IAVF_TX_DESC_L2TAG1_MASK	(0xffff << IAVF_TX_DESC_L2TAG1_SHIFT)
3934ccba60fSjmatthew } __packed __aligned(16);
3944ccba60fSjmatthew 
3954ccba60fSjmatthew struct iavf_rx_rd_desc_16 {
3964ccba60fSjmatthew 	uint64_t		paddr; /* packet addr */
3974ccba60fSjmatthew 	uint64_t		haddr; /* header addr */
3984ccba60fSjmatthew } __packed __aligned(16);
3994ccba60fSjmatthew 
4004ccba60fSjmatthew struct iavf_rx_rd_desc_32 {
4014ccba60fSjmatthew 	uint64_t		paddr; /* packet addr */
4024ccba60fSjmatthew 	uint64_t		haddr; /* header addr */
4034ccba60fSjmatthew 	uint64_t		_reserved1;
4044ccba60fSjmatthew 	uint64_t		_reserved2;
4054ccba60fSjmatthew } __packed __aligned(16);
4064ccba60fSjmatthew 
4074ccba60fSjmatthew struct iavf_rx_wb_desc_16 {
4084ccba60fSjmatthew 	uint64_t		qword0;
4093e0b52e8Sjmatthew #define IAVF_RX_DESC_L2TAG1_SHIFT	16
4103e0b52e8Sjmatthew #define IAVF_RX_DESC_L2TAG1_MASK	(0xffff << IAVF_RX_DESC_L2TAG1_SHIFT)
4114ccba60fSjmatthew 	uint64_t		qword1;
4124ccba60fSjmatthew #define IAVF_RX_DESC_DD			(1 << 0)
4134ccba60fSjmatthew #define IAVF_RX_DESC_EOP		(1 << 1)
4144ccba60fSjmatthew #define IAVF_RX_DESC_L2TAG1P		(1 << 2)
4154ccba60fSjmatthew #define IAVF_RX_DESC_L3L4P		(1 << 3)
4164ccba60fSjmatthew #define IAVF_RX_DESC_CRCP		(1 << 4)
4174ccba60fSjmatthew #define IAVF_RX_DESC_TSYNINDX_SHIFT	5	/* TSYNINDX */
4184ccba60fSjmatthew #define IAVF_RX_DESC_TSYNINDX_MASK	(7 << IAVF_RX_DESC_TSYNINDX_SHIFT)
4194ccba60fSjmatthew #define IAVF_RX_DESC_UMB_SHIFT		9
4204ccba60fSjmatthew #define IAVF_RX_DESC_UMB_MASK		(0x3 << IAVF_RX_DESC_UMB_SHIFT)
4214ccba60fSjmatthew #define IAVF_RX_DESC_UMB_UCAST		(0x0 << IAVF_RX_DESC_UMB_SHIFT)
4224ccba60fSjmatthew #define IAVF_RX_DESC_UMB_MCAST		(0x1 << IAVF_RX_DESC_UMB_SHIFT)
4234ccba60fSjmatthew #define IAVF_RX_DESC_UMB_BCAST		(0x2 << IAVF_RX_DESC_UMB_SHIFT)
4244ccba60fSjmatthew #define IAVF_RX_DESC_UMB_MIRROR		(0x3 << IAVF_RX_DESC_UMB_SHIFT)
4254ccba60fSjmatthew #define IAVF_RX_DESC_FLM		(1 << 11)
4264ccba60fSjmatthew #define IAVF_RX_DESC_FLTSTAT_SHIFT 	12
4274ccba60fSjmatthew #define IAVF_RX_DESC_FLTSTAT_MASK 	(0x3 << IAVF_RX_DESC_FLTSTAT_SHIFT)
4284ccba60fSjmatthew #define IAVF_RX_DESC_FLTSTAT_NODATA 	(0x0 << IAVF_RX_DESC_FLTSTAT_SHIFT)
4294ccba60fSjmatthew #define IAVF_RX_DESC_FLTSTAT_FDFILTID 	(0x1 << IAVF_RX_DESC_FLTSTAT_SHIFT)
4304ccba60fSjmatthew #define IAVF_RX_DESC_FLTSTAT_RSS 	(0x3 << IAVF_RX_DESC_FLTSTAT_SHIFT)
4314ccba60fSjmatthew #define IAVF_RX_DESC_LPBK		(1 << 14)
4324ccba60fSjmatthew #define IAVF_RX_DESC_IPV6EXTADD		(1 << 15)
4334ccba60fSjmatthew #define IAVF_RX_DESC_INT_UDP_0		(1 << 18)
4344ccba60fSjmatthew 
4354ccba60fSjmatthew #define IAVF_RX_DESC_RXE		(1 << 19)
4364ccba60fSjmatthew #define IAVF_RX_DESC_HBO		(1 << 21)
4374ccba60fSjmatthew #define IAVF_RX_DESC_IPE		(1 << 22)
4384ccba60fSjmatthew #define IAVF_RX_DESC_L4E		(1 << 23)
4394ccba60fSjmatthew #define IAVF_RX_DESC_EIPE		(1 << 24)
4404ccba60fSjmatthew #define IAVF_RX_DESC_OVERSIZE		(1 << 25)
4414ccba60fSjmatthew 
4424ccba60fSjmatthew #define IAVF_RX_DESC_PTYPE_SHIFT	30
4434ccba60fSjmatthew #define IAVF_RX_DESC_PTYPE_MASK		(0xffULL << IAVF_RX_DESC_PTYPE_SHIFT)
4444ccba60fSjmatthew 
4454ccba60fSjmatthew #define IAVF_RX_DESC_PLEN_SHIFT		38
4464ccba60fSjmatthew #define IAVF_RX_DESC_PLEN_MASK		(0x3fffULL << IAVF_RX_DESC_PLEN_SHIFT)
4474ccba60fSjmatthew #define IAVF_RX_DESC_HLEN_SHIFT		42
4484ccba60fSjmatthew #define IAVF_RX_DESC_HLEN_MASK		(0x7ffULL << IAVF_RX_DESC_HLEN_SHIFT)
4494ccba60fSjmatthew } __packed __aligned(16);
4504ccba60fSjmatthew 
4514ccba60fSjmatthew struct iavf_rx_wb_desc_32 {
4524ccba60fSjmatthew 	uint64_t		qword0;
4534ccba60fSjmatthew 	uint64_t		qword1;
4544ccba60fSjmatthew 	uint64_t		qword2;
4554ccba60fSjmatthew 	uint64_t		qword3;
4564ccba60fSjmatthew } __packed __aligned(16);
4574ccba60fSjmatthew 
4584ccba60fSjmatthew 
4594ccba60fSjmatthew #define IAVF_VF_MAJOR			1
4604ccba60fSjmatthew #define IAVF_VF_MINOR			1
4614ccba60fSjmatthew 
4624ccba60fSjmatthew #define IAVF_TX_PKT_DESCS		8
4634ccba60fSjmatthew #define IAVF_TX_QUEUE_ALIGN		128
4644ccba60fSjmatthew #define IAVF_RX_QUEUE_ALIGN		128
4654ccba60fSjmatthew 
4664ccba60fSjmatthew #define IAVF_HARDMTU			9712 /* 9726 - ETHER_HDR_LEN */
4674ccba60fSjmatthew 
4684ccba60fSjmatthew #define IAVF_PCIREG			PCI_MAPREG_START
4694ccba60fSjmatthew 
4704ccba60fSjmatthew #define IAVF_ITR0			0x0
4714ccba60fSjmatthew #define IAVF_ITR1			0x1
4724ccba60fSjmatthew #define IAVF_ITR2			0x2
4734ccba60fSjmatthew #define IAVF_NOITR			0x3
4744ccba60fSjmatthew 
4754ccba60fSjmatthew #define IAVF_AQ_NUM			256
4764ccba60fSjmatthew #define IAVF_AQ_MASK			(IAVF_AQ_NUM - 1)
4774ccba60fSjmatthew #define IAVF_AQ_ALIGN			64 /* lol */
4784ccba60fSjmatthew #define IAVF_AQ_BUFLEN			4096
4794ccba60fSjmatthew 
4804ccba60fSjmatthew struct iavf_aq_regs {
4814ccba60fSjmatthew 	bus_size_t		atq_tail;
4824ccba60fSjmatthew 	bus_size_t		atq_head;
4834ccba60fSjmatthew 	bus_size_t		atq_len;
4844ccba60fSjmatthew 	bus_size_t		atq_bal;
4854ccba60fSjmatthew 	bus_size_t		atq_bah;
4864ccba60fSjmatthew 
4874ccba60fSjmatthew 	bus_size_t		arq_tail;
4884ccba60fSjmatthew 	bus_size_t		arq_head;
4894ccba60fSjmatthew 	bus_size_t		arq_len;
4904ccba60fSjmatthew 	bus_size_t		arq_bal;
4914ccba60fSjmatthew 	bus_size_t		arq_bah;
4924ccba60fSjmatthew 
4934ccba60fSjmatthew 	uint32_t		atq_len_enable;
4944ccba60fSjmatthew 	uint32_t		atq_tail_mask;
4954ccba60fSjmatthew 	uint32_t		atq_head_mask;
4964ccba60fSjmatthew 
4974ccba60fSjmatthew 	uint32_t		arq_len_enable;
4984ccba60fSjmatthew 	uint32_t		arq_tail_mask;
4994ccba60fSjmatthew 	uint32_t		arq_head_mask;
5004ccba60fSjmatthew };
5014ccba60fSjmatthew 
5024ccba60fSjmatthew struct iavf_aq_buf {
5034ccba60fSjmatthew 	SIMPLEQ_ENTRY(iavf_aq_buf)
5044ccba60fSjmatthew 				 aqb_entry;
5054ccba60fSjmatthew 	void			*aqb_data;
5064ccba60fSjmatthew 	bus_dmamap_t		 aqb_map;
5074ccba60fSjmatthew };
5084ccba60fSjmatthew SIMPLEQ_HEAD(iavf_aq_bufs, iavf_aq_buf);
5094ccba60fSjmatthew 
5104ccba60fSjmatthew struct iavf_dmamem {
5114ccba60fSjmatthew 	bus_dmamap_t		ixm_map;
5124ccba60fSjmatthew 	bus_dma_segment_t	ixm_seg;
5134ccba60fSjmatthew 	int			ixm_nsegs;
5144ccba60fSjmatthew 	size_t			ixm_size;
5154ccba60fSjmatthew 	caddr_t			ixm_kva;
5164ccba60fSjmatthew };
5174ccba60fSjmatthew #define IAVF_DMA_MAP(_ixm)	((_ixm)->ixm_map)
5184ccba60fSjmatthew #define IAVF_DMA_DVA(_ixm)	((_ixm)->ixm_map->dm_segs[0].ds_addr)
5194ccba60fSjmatthew #define IAVF_DMA_KVA(_ixm)	((void *)(_ixm)->ixm_kva)
5204ccba60fSjmatthew #define IAVF_DMA_LEN(_ixm)	((_ixm)->ixm_size)
5214ccba60fSjmatthew 
5224ccba60fSjmatthew struct iavf_tx_map {
5234ccba60fSjmatthew 	struct mbuf		*txm_m;
5244ccba60fSjmatthew 	bus_dmamap_t		 txm_map;
5254ccba60fSjmatthew 	unsigned int		 txm_eop;
5264ccba60fSjmatthew };
5274ccba60fSjmatthew 
5284ccba60fSjmatthew struct iavf_tx_ring {
5294ccba60fSjmatthew 	unsigned int		 txr_prod;
5304ccba60fSjmatthew 	unsigned int		 txr_cons;
5314ccba60fSjmatthew 
5324ccba60fSjmatthew 	struct iavf_tx_map	*txr_maps;
5334ccba60fSjmatthew 	struct iavf_dmamem	 txr_mem;
5344ccba60fSjmatthew 
5354ccba60fSjmatthew 	bus_size_t		 txr_tail;
5364ccba60fSjmatthew 	unsigned int		 txr_qid;
5374ccba60fSjmatthew };
5384ccba60fSjmatthew 
5394ccba60fSjmatthew struct iavf_rx_map {
5404ccba60fSjmatthew 	struct mbuf		*rxm_m;
5414ccba60fSjmatthew 	bus_dmamap_t		 rxm_map;
5424ccba60fSjmatthew };
5434ccba60fSjmatthew 
5444ccba60fSjmatthew struct iavf_rx_ring {
5454ccba60fSjmatthew 	struct iavf_softc	*rxr_sc;
5464ccba60fSjmatthew 
5474ccba60fSjmatthew 	struct if_rxring	 rxr_acct;
5484ccba60fSjmatthew 	struct timeout		 rxr_refill;
5494ccba60fSjmatthew 
5504ccba60fSjmatthew 	unsigned int		 rxr_prod;
5514ccba60fSjmatthew 	unsigned int		 rxr_cons;
5524ccba60fSjmatthew 
5534ccba60fSjmatthew 	struct iavf_rx_map	*rxr_maps;
5544ccba60fSjmatthew 	struct iavf_dmamem	 rxr_mem;
5554ccba60fSjmatthew 
5564ccba60fSjmatthew 	struct mbuf		*rxr_m_head;
5574ccba60fSjmatthew 	struct mbuf		**rxr_m_tail;
5584ccba60fSjmatthew 
5594ccba60fSjmatthew 	bus_size_t		 rxr_tail;
5604ccba60fSjmatthew 	unsigned int		 rxr_qid;
5614ccba60fSjmatthew };
5624ccba60fSjmatthew 
5634ccba60fSjmatthew struct iavf_softc {
5644ccba60fSjmatthew 	struct device		 sc_dev;
5654ccba60fSjmatthew 	struct arpcom		 sc_ac;
5664ccba60fSjmatthew 	struct ifmedia		 sc_media;
5674ccba60fSjmatthew 	uint64_t		 sc_media_status;
5684ccba60fSjmatthew 	uint64_t		 sc_media_active;
5694ccba60fSjmatthew 
5704ccba60fSjmatthew 	pci_chipset_tag_t	 sc_pc;
5714ccba60fSjmatthew 	pci_intr_handle_t	 sc_ih;
5724ccba60fSjmatthew 	void			*sc_ihc;
5734ccba60fSjmatthew 	pcitag_t		 sc_tag;
5744ccba60fSjmatthew 
5754ccba60fSjmatthew 	bus_dma_tag_t		 sc_dmat;
5764ccba60fSjmatthew 	bus_space_tag_t		 sc_memt;
5774ccba60fSjmatthew 	bus_space_handle_t	 sc_memh;
5784ccba60fSjmatthew 	bus_size_t		 sc_mems;
5794ccba60fSjmatthew 
5804ccba60fSjmatthew 	uint32_t		 sc_major_ver;
5814ccba60fSjmatthew 	uint32_t		 sc_minor_ver;
5824ccba60fSjmatthew 
5834ccba60fSjmatthew 	int			 sc_got_vf_resources;
5844ccba60fSjmatthew 	int			 sc_got_irq_map;
5854ccba60fSjmatthew 	uint32_t		 sc_vf_id;
5864ccba60fSjmatthew 	uint16_t		 sc_vsi_id;
5874ccba60fSjmatthew 	uint16_t		 sc_qset_handle;
5884ccba60fSjmatthew 	unsigned int		 sc_base_queue;
5894ccba60fSjmatthew 
5904ccba60fSjmatthew 	struct cond		 sc_admin_cond;
5914ccba60fSjmatthew 	int			 sc_admin_result;
5924ccba60fSjmatthew 	struct timeout		 sc_admin_timeout;
5934ccba60fSjmatthew 
5944ccba60fSjmatthew 	struct iavf_dmamem	 sc_scratch;
5954ccba60fSjmatthew 
5964ccba60fSjmatthew 	const struct iavf_aq_regs *
5974ccba60fSjmatthew 				 sc_aq_regs;
5984ccba60fSjmatthew 
5994ccba60fSjmatthew 	struct mutex		 sc_atq_mtx;
6004ccba60fSjmatthew 	struct iavf_dmamem	 sc_atq;
6014ccba60fSjmatthew 	unsigned int		 sc_atq_prod;
6024ccba60fSjmatthew 	unsigned int		 sc_atq_cons;
6034ccba60fSjmatthew 
6044ccba60fSjmatthew 	struct iavf_dmamem	 sc_arq;
6054ccba60fSjmatthew 	struct iavf_aq_bufs	 sc_arq_idle;
6064ccba60fSjmatthew 	struct iavf_aq_bufs	 sc_arq_live;
6074ccba60fSjmatthew 	struct if_rxring	 sc_arq_ring;
6084ccba60fSjmatthew 	unsigned int		 sc_arq_prod;
6094ccba60fSjmatthew 	unsigned int		 sc_arq_cons;
6104ccba60fSjmatthew 
6112fa30b92Sjmatthew 	struct task		 sc_reset_task;
6122fa30b92Sjmatthew 	int			 sc_resetting;
6134ccba60fSjmatthew 
6144ccba60fSjmatthew 	unsigned int		 sc_tx_ring_ndescs;
6154ccba60fSjmatthew 	unsigned int		 sc_rx_ring_ndescs;
6164ccba60fSjmatthew 	unsigned int		 sc_nqueues;	/* 1 << sc_nqueues */
6174ccba60fSjmatthew 
6184ccba60fSjmatthew 	struct rwlock		 sc_cfg_lock;
6194ccba60fSjmatthew 	unsigned int		 sc_dead;
6204ccba60fSjmatthew 
6214ccba60fSjmatthew 	uint8_t			 sc_enaddr[ETHER_ADDR_LEN];
6224ccba60fSjmatthew };
6234ccba60fSjmatthew #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
6244ccba60fSjmatthew 
6254ccba60fSjmatthew #define delaymsec(_ms)	delay(1000 * (_ms))
6264ccba60fSjmatthew 
6274ccba60fSjmatthew static int	iavf_dmamem_alloc(struct iavf_softc *, struct iavf_dmamem *,
6284ccba60fSjmatthew 		    bus_size_t, u_int);
6294ccba60fSjmatthew static void	iavf_dmamem_free(struct iavf_softc *, struct iavf_dmamem *);
6304ccba60fSjmatthew 
631e13657b7Sjmatthew static int	iavf_arq_fill(struct iavf_softc *, int);
6324ccba60fSjmatthew static void	iavf_arq_unfill(struct iavf_softc *);
6334ccba60fSjmatthew static void	iavf_arq_timeout(void *);
6344ccba60fSjmatthew static int	iavf_arq_wait(struct iavf_softc *, int);
6354ccba60fSjmatthew 
6364ccba60fSjmatthew static int	iavf_atq_post(struct iavf_softc *, struct iavf_aq_desc *);
6374ccba60fSjmatthew static void	iavf_atq_done(struct iavf_softc *);
6384ccba60fSjmatthew 
6392fa30b92Sjmatthew static void	iavf_init_admin_queue(struct iavf_softc *);
6402fa30b92Sjmatthew 
6414ccba60fSjmatthew static int	iavf_get_version(struct iavf_softc *);
6424ccba60fSjmatthew static int	iavf_get_vf_resources(struct iavf_softc *);
6434ccba60fSjmatthew static int	iavf_config_irq_map(struct iavf_softc *);
6444ccba60fSjmatthew 
6454ccba60fSjmatthew static int	iavf_add_del_addr(struct iavf_softc *, uint8_t *, int);
646e13657b7Sjmatthew static int	iavf_process_arq(struct iavf_softc *, int);
6474ccba60fSjmatthew 
6484ccba60fSjmatthew static int	iavf_match(struct device *, void *, void *);
6494ccba60fSjmatthew static void	iavf_attach(struct device *, struct device *, void *);
6504ccba60fSjmatthew 
6514ccba60fSjmatthew static int	iavf_media_change(struct ifnet *);
6524ccba60fSjmatthew static void	iavf_media_status(struct ifnet *, struct ifmediareq *);
6534ccba60fSjmatthew static void	iavf_watchdog(struct ifnet *);
6544ccba60fSjmatthew static int	iavf_ioctl(struct ifnet *, u_long, caddr_t);
6554ccba60fSjmatthew static void	iavf_start(struct ifqueue *);
6564ccba60fSjmatthew static int	iavf_intr(void *);
6574ccba60fSjmatthew static int	iavf_up(struct iavf_softc *);
6584ccba60fSjmatthew static int	iavf_down(struct iavf_softc *);
6594ccba60fSjmatthew static int	iavf_iff(struct iavf_softc *);
6602fa30b92Sjmatthew static void	iavf_reset(void *);
6614ccba60fSjmatthew 
6624ccba60fSjmatthew static struct iavf_tx_ring *
6634ccba60fSjmatthew 		iavf_txr_alloc(struct iavf_softc *, unsigned int);
6644ccba60fSjmatthew static void	iavf_txr_clean(struct iavf_softc *, struct iavf_tx_ring *);
6654ccba60fSjmatthew static void	iavf_txr_free(struct iavf_softc *, struct iavf_tx_ring *);
6664ccba60fSjmatthew static int	iavf_txeof(struct iavf_softc *, struct ifqueue *);
6674ccba60fSjmatthew 
6684ccba60fSjmatthew static struct iavf_rx_ring *
6694ccba60fSjmatthew 		iavf_rxr_alloc(struct iavf_softc *, unsigned int);
6704ccba60fSjmatthew static void	iavf_rxr_clean(struct iavf_softc *, struct iavf_rx_ring *);
6714ccba60fSjmatthew static void	iavf_rxr_free(struct iavf_softc *, struct iavf_rx_ring *);
6724ccba60fSjmatthew static int	iavf_rxeof(struct iavf_softc *, struct ifiqueue *);
6734ccba60fSjmatthew static void	iavf_rxfill(struct iavf_softc *, struct iavf_rx_ring *);
6744ccba60fSjmatthew static void	iavf_rxrefill(void *);
6754ccba60fSjmatthew static int	iavf_rxrinfo(struct iavf_softc *, struct if_rxrinfo *);
6764ccba60fSjmatthew 
6774ccba60fSjmatthew struct cfdriver iavf_cd = {
6784ccba60fSjmatthew 	NULL,
6794ccba60fSjmatthew 	"iavf",
6804ccba60fSjmatthew 	DV_IFNET,
6814ccba60fSjmatthew };
6824ccba60fSjmatthew 
6838d2c75e4Smpi const struct cfattach iavf_ca = {
6844ccba60fSjmatthew 	sizeof(struct iavf_softc),
6854ccba60fSjmatthew 	iavf_match,
6864ccba60fSjmatthew 	iavf_attach,
6874ccba60fSjmatthew };
6884ccba60fSjmatthew 
6894ccba60fSjmatthew static const struct iavf_aq_regs iavf_aq_regs = {
6904ccba60fSjmatthew 	.atq_tail	= I40E_VF_ATQT1,
6914ccba60fSjmatthew 	.atq_tail_mask	= I40E_VF_ATQT1_ATQT_MASK,
6924ccba60fSjmatthew 	.atq_head	= I40E_VF_ATQH1,
6934ccba60fSjmatthew 	.atq_head_mask	= I40E_VF_ARQH1_ARQH_MASK,
6944ccba60fSjmatthew 	.atq_len	= I40E_VF_ATQLEN1,
6954ccba60fSjmatthew 	.atq_bal	= I40E_VF_ATQBAL1,
6964ccba60fSjmatthew 	.atq_bah	= I40E_VF_ATQBAH1,
6974ccba60fSjmatthew 	.atq_len_enable	= I40E_VF_ATQLEN1_ATQENABLE_MASK,
6984ccba60fSjmatthew 
6994ccba60fSjmatthew 	.arq_tail	= I40E_VF_ARQT1,
7004ccba60fSjmatthew 	.arq_tail_mask	= I40E_VF_ARQT1_ARQT_MASK,
7014ccba60fSjmatthew 	.arq_head	= I40E_VF_ARQH1,
7024ccba60fSjmatthew 	.arq_head_mask	= I40E_VF_ARQH1_ARQH_MASK,
7034ccba60fSjmatthew 	.arq_len	= I40E_VF_ARQLEN1,
7044ccba60fSjmatthew 	.arq_bal	= I40E_VF_ARQBAL1,
7054ccba60fSjmatthew 	.arq_bah	= I40E_VF_ARQBAH1,
7064ccba60fSjmatthew 	.arq_len_enable	= I40E_VF_ARQLEN1_ARQENABLE_MASK,
7074ccba60fSjmatthew };
7084ccba60fSjmatthew 
7094ccba60fSjmatthew #define iavf_rd(_s, _r) \
7104ccba60fSjmatthew 	bus_space_read_4((_s)->sc_memt, (_s)->sc_memh, (_r))
7114ccba60fSjmatthew #define iavf_wr(_s, _r, _v) \
7124ccba60fSjmatthew 	bus_space_write_4((_s)->sc_memt, (_s)->sc_memh, (_r), (_v))
7134ccba60fSjmatthew #define iavf_barrier(_s, _r, _l, _o) \
7144ccba60fSjmatthew 	bus_space_barrier((_s)->sc_memt, (_s)->sc_memh, (_r), (_l), (_o))
7154ccba60fSjmatthew #define iavf_intr_enable(_s) \
7164ccba60fSjmatthew 	iavf_wr((_s), I40E_VFINT_DYN_CTL01, I40E_VFINT_DYN_CTL0_INTENA_MASK | \
7174ccba60fSjmatthew 	    I40E_VFINT_DYN_CTL0_CLEARPBA_MASK | \
7184ccba60fSjmatthew 	    (IAVF_NOITR << I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT)); \
7194ccba60fSjmatthew 	iavf_wr((_s), I40E_VFINT_ICR0_ENA1, I40E_VFINT_ICR0_ENA1_ADMINQ_MASK)
7204ccba60fSjmatthew 
7214ccba60fSjmatthew #define iavf_nqueues(_sc)	(1 << (_sc)->sc_nqueues)
7221f28ec92Sjmatthew #define iavf_allqueues(_sc)	((1 << ((_sc)->sc_nqueues+1)) - 1)
7234ccba60fSjmatthew 
7244ccba60fSjmatthew #ifdef __LP64__
7254ccba60fSjmatthew #define iavf_dmamem_hi(_ixm)	(uint32_t)(IAVF_DMA_DVA(_ixm) >> 32)
7264ccba60fSjmatthew #else
7274ccba60fSjmatthew #define iavf_dmamem_hi(_ixm)	0
7284ccba60fSjmatthew #endif
7294ccba60fSjmatthew 
7304ccba60fSjmatthew #define iavf_dmamem_lo(_ixm) 	(uint32_t)IAVF_DMA_DVA(_ixm)
7314ccba60fSjmatthew 
7324ccba60fSjmatthew static inline void
7334ccba60fSjmatthew iavf_aq_dva(struct iavf_aq_desc *iaq, bus_addr_t addr)
7344ccba60fSjmatthew {
7354ccba60fSjmatthew #ifdef __LP64__
7364ccba60fSjmatthew 	htolem32(&iaq->iaq_param[2], addr >> 32);
7374ccba60fSjmatthew #else
7384ccba60fSjmatthew 	iaq->iaq_param[2] = htole32(0);
7394ccba60fSjmatthew #endif
7404ccba60fSjmatthew 	htolem32(&iaq->iaq_param[3], addr);
7414ccba60fSjmatthew }
7424ccba60fSjmatthew 
7434ccba60fSjmatthew #if _BYTE_ORDER == _BIG_ENDIAN
7444ccba60fSjmatthew #define HTOLE16(_x)	(uint16_t)(((_x) & 0xff) << 8 | ((_x) & 0xff00) >> 8)
7454ccba60fSjmatthew #else
7464ccba60fSjmatthew #define HTOLE16(_x)	(_x)
7474ccba60fSjmatthew #endif
7484ccba60fSjmatthew 
7494ccba60fSjmatthew static const struct pci_matchid iavf_devices[] = {
7504ccba60fSjmatthew 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_XL710_VF },
7514ccba60fSjmatthew 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_XL710_VF_HV },
7524ccba60fSjmatthew 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_X722_VF },
7534ccba60fSjmatthew 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_ADAPTIVE_VF },
7544ccba60fSjmatthew };
7554ccba60fSjmatthew 
7564ccba60fSjmatthew static int
7574ccba60fSjmatthew iavf_match(struct device *parent, void *match, void *aux)
7584ccba60fSjmatthew {
7594ccba60fSjmatthew 	return (pci_matchbyid(aux, iavf_devices, nitems(iavf_devices)));
7604ccba60fSjmatthew }
7614ccba60fSjmatthew 
7624ccba60fSjmatthew void
7634ccba60fSjmatthew iavf_attach(struct device *parent, struct device *self, void *aux)
7644ccba60fSjmatthew {
7654ccba60fSjmatthew 	struct iavf_softc *sc = (struct iavf_softc *)self;
7664ccba60fSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
7674ccba60fSjmatthew 	struct pci_attach_args *pa = aux;
7684ccba60fSjmatthew 	pcireg_t memtype;
7694ccba60fSjmatthew 	int tries;
7704ccba60fSjmatthew 
7714ccba60fSjmatthew 	rw_init(&sc->sc_cfg_lock, "iavfcfg");
7724ccba60fSjmatthew 
7734ccba60fSjmatthew 	sc->sc_pc = pa->pa_pc;
7744ccba60fSjmatthew 	sc->sc_tag = pa->pa_tag;
7754ccba60fSjmatthew 	sc->sc_dmat = pa->pa_dmat;
7764ccba60fSjmatthew 	sc->sc_aq_regs = &iavf_aq_regs;
7774ccba60fSjmatthew 
7784ccba60fSjmatthew 	sc->sc_nqueues = 0; /* 1 << 0 is 1 queue */
7794ccba60fSjmatthew 	sc->sc_tx_ring_ndescs = 1024;
7804ccba60fSjmatthew 	sc->sc_rx_ring_ndescs = 1024;
7814ccba60fSjmatthew 
7824ccba60fSjmatthew 	memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, IAVF_PCIREG);
7834ccba60fSjmatthew 	if (pci_mapreg_map(pa, IAVF_PCIREG, memtype, 0,
7844ccba60fSjmatthew 	    &sc->sc_memt, &sc->sc_memh, NULL, &sc->sc_mems, 0)) {
7854ccba60fSjmatthew 		printf(": unable to map registers\n");
7864ccba60fSjmatthew 		return;
7874ccba60fSjmatthew 	}
7884ccba60fSjmatthew 
7894ccba60fSjmatthew 	for (tries = 0; tries < 100; tries++) {
7904ccba60fSjmatthew 		uint32_t reg;
7914ccba60fSjmatthew 		reg = iavf_rd(sc, I40E_VFGEN_RSTAT) &
7924ccba60fSjmatthew 		    I40E_VFGEN_RSTAT_VFR_STATE_MASK;
7934ccba60fSjmatthew 		if (reg == IAVF_VFR_VFACTIVE ||
7944ccba60fSjmatthew 		    reg == IAVF_VFR_COMPLETED)
7954ccba60fSjmatthew 			break;
7964ccba60fSjmatthew 
7974ccba60fSjmatthew 		delay(10000);
7984ccba60fSjmatthew 	}
7994ccba60fSjmatthew 	if (tries == 100) {
8004ccba60fSjmatthew 		printf(": VF reset timed out\n");
8014ccba60fSjmatthew 		return;
8024ccba60fSjmatthew 	}
8032fa30b92Sjmatthew 	task_set(&sc->sc_reset_task, iavf_reset, sc);
8044ccba60fSjmatthew 
8054ccba60fSjmatthew 	mtx_init(&sc->sc_atq_mtx, IPL_NET);
8064ccba60fSjmatthew 
8074ccba60fSjmatthew 	if (iavf_dmamem_alloc(sc, &sc->sc_atq,
8084ccba60fSjmatthew 	    sizeof(struct iavf_aq_desc) * IAVF_AQ_NUM, IAVF_AQ_ALIGN) != 0) {
8094ccba60fSjmatthew 		printf("\n" "%s: unable to allocate atq\n", DEVNAME(sc));
8104ccba60fSjmatthew 		goto unmap;
8114ccba60fSjmatthew 	}
8124ccba60fSjmatthew 
8134ccba60fSjmatthew 	SIMPLEQ_INIT(&sc->sc_arq_idle);
8144ccba60fSjmatthew 	SIMPLEQ_INIT(&sc->sc_arq_live);
8154ccba60fSjmatthew 	if_rxr_init(&sc->sc_arq_ring, 2, IAVF_AQ_NUM - 1);
8164ccba60fSjmatthew 	sc->sc_arq_cons = 0;
8174ccba60fSjmatthew 	sc->sc_arq_prod = 0;
8184ccba60fSjmatthew 
8194ccba60fSjmatthew 	if (iavf_dmamem_alloc(sc, &sc->sc_arq,
8204ccba60fSjmatthew 	    sizeof(struct iavf_aq_desc) * IAVF_AQ_NUM, IAVF_AQ_ALIGN) != 0) {
8214ccba60fSjmatthew 		printf("\n" "%s: unable to allocate arq\n", DEVNAME(sc));
8224ccba60fSjmatthew 		goto free_atq;
8234ccba60fSjmatthew 	}
8244ccba60fSjmatthew 
825e13657b7Sjmatthew 	if (!iavf_arq_fill(sc, 0)) {
8264ccba60fSjmatthew 		printf("\n" "%s: unable to fill arq descriptors\n",
8274ccba60fSjmatthew 		    DEVNAME(sc));
8284ccba60fSjmatthew 		goto free_arq;
8294ccba60fSjmatthew 	}
8304ccba60fSjmatthew 	timeout_set(&sc->sc_admin_timeout, iavf_arq_timeout, sc);
8314ccba60fSjmatthew 
8324ccba60fSjmatthew 	if (iavf_dmamem_alloc(sc, &sc->sc_scratch, PAGE_SIZE, IAVF_AQ_ALIGN) != 0) {
8334ccba60fSjmatthew 		printf("\n" "%s: unable to allocate scratch\n", DEVNAME(sc));
8344ccba60fSjmatthew 		goto shutdown;
8354ccba60fSjmatthew 	}
8364ccba60fSjmatthew 
8374ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq),
8384ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&sc->sc_atq),
8394ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
8404ccba60fSjmatthew 
8414ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_arq),
8424ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&sc->sc_arq),
8434ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
8444ccba60fSjmatthew 
8452fa30b92Sjmatthew 	iavf_init_admin_queue(sc);
8464ccba60fSjmatthew 
8474ccba60fSjmatthew 	if (iavf_get_version(sc) != 0) {
8484ccba60fSjmatthew 		printf(", unable to get VF interface version\n");
8494ccba60fSjmatthew 		goto free_scratch;
8504ccba60fSjmatthew 	}
8514ccba60fSjmatthew 
8524ccba60fSjmatthew 	if (iavf_get_vf_resources(sc) != 0) {
853e13657b7Sjmatthew 		printf(", timed out waiting for VF resources\n");
8544ccba60fSjmatthew 		goto free_scratch;
8554ccba60fSjmatthew 	}
8564ccba60fSjmatthew 
8574ccba60fSjmatthew 	if (iavf_config_irq_map(sc) != 0) {
858e13657b7Sjmatthew 		printf(", timeout waiting for IRQ map response");
8594ccba60fSjmatthew 		goto free_scratch;
8604ccba60fSjmatthew 	}
8614ccba60fSjmatthew 
8624ccba60fSjmatthew 	/* msix only? */
8634ccba60fSjmatthew 	if (pci_intr_map_msix(pa, 0, &sc->sc_ih) != 0) {
8644ccba60fSjmatthew 		printf(", unable to map interrupt\n");
8654ccba60fSjmatthew 		goto free_scratch;
8664ccba60fSjmatthew 	}
8674ccba60fSjmatthew 
8684ccba60fSjmatthew 	/* generate an address if the pf didn't give us one */
8694ccba60fSjmatthew 	memcpy(sc->sc_enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
8704ccba60fSjmatthew 	if (memcmp(sc->sc_ac.ac_enaddr, etheranyaddr, ETHER_ADDR_LEN) == 0)
8714ccba60fSjmatthew 		ether_fakeaddr(ifp);
8724ccba60fSjmatthew 
8734ccba60fSjmatthew 	printf(", %s, address %s\n", pci_intr_string(sc->sc_pc, sc->sc_ih),
8744ccba60fSjmatthew 	    ether_sprintf(sc->sc_ac.ac_enaddr));
8754ccba60fSjmatthew 
8764ccba60fSjmatthew 	sc->sc_ihc = pci_intr_establish(sc->sc_pc, sc->sc_ih,
8774ccba60fSjmatthew 	    IPL_NET | IPL_MPSAFE, iavf_intr, sc, DEVNAME(sc));
8784ccba60fSjmatthew 	if (sc->sc_ihc == NULL) {
8794ccba60fSjmatthew 		printf("%s: unable to establish interrupt handler\n",
8804ccba60fSjmatthew 		    DEVNAME(sc));
8814ccba60fSjmatthew 		goto free_scratch;
8824ccba60fSjmatthew 	}
8834ccba60fSjmatthew 
8844ccba60fSjmatthew 	ifp->if_softc = sc;
8854ccba60fSjmatthew 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
8864ccba60fSjmatthew 	ifp->if_xflags = IFXF_MPSAFE;
8874ccba60fSjmatthew 	ifp->if_ioctl = iavf_ioctl;
8884ccba60fSjmatthew 	ifp->if_qstart = iavf_start;
8894ccba60fSjmatthew 	ifp->if_watchdog = iavf_watchdog;
8904ccba60fSjmatthew 	if (ifp->if_hardmtu == 0)
8914ccba60fSjmatthew 		ifp->if_hardmtu = IAVF_HARDMTU;
8924ccba60fSjmatthew 	strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
893cf96265bSbluhm 	ifq_init_maxlen(&ifp->if_snd, sc->sc_tx_ring_ndescs);
8944ccba60fSjmatthew 
895*51248bbdSyasuoka 	ifp->if_capabilities = IFCAP_VLAN_MTU;
896*51248bbdSyasuoka #if NVLAN > 0
897*51248bbdSyasuoka 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
8984ccba60fSjmatthew #endif
899*51248bbdSyasuoka 	ifp->if_capabilities |= IFCAP_CSUM_IPv4 |
900*51248bbdSyasuoka 	    IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4 |
901*51248bbdSyasuoka 	    IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6;
9024ccba60fSjmatthew 
9034ccba60fSjmatthew 	ifmedia_init(&sc->sc_media, 0, iavf_media_change, iavf_media_status);
9044ccba60fSjmatthew 
9054ccba60fSjmatthew 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
9064ccba60fSjmatthew 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
9074ccba60fSjmatthew 
9084ccba60fSjmatthew 	if_attach(ifp);
9094ccba60fSjmatthew 	ether_ifattach(ifp);
9104ccba60fSjmatthew 
9114ccba60fSjmatthew 	if_attach_queues(ifp, iavf_nqueues(sc));
9124ccba60fSjmatthew 	if_attach_iqueues(ifp, iavf_nqueues(sc));
9134ccba60fSjmatthew 
9144ccba60fSjmatthew 	iavf_intr_enable(sc);
9154ccba60fSjmatthew 
9164ccba60fSjmatthew 	return;
9174ccba60fSjmatthew free_scratch:
9184ccba60fSjmatthew 	iavf_dmamem_free(sc, &sc->sc_scratch);
9194ccba60fSjmatthew shutdown:
9204ccba60fSjmatthew 	iavf_wr(sc, sc->sc_aq_regs->atq_head, 0);
9214ccba60fSjmatthew 	iavf_wr(sc, sc->sc_aq_regs->arq_head, 0);
9224ccba60fSjmatthew 	iavf_wr(sc, sc->sc_aq_regs->atq_tail, 0);
9234ccba60fSjmatthew 	iavf_wr(sc, sc->sc_aq_regs->arq_tail, 0);
9244ccba60fSjmatthew 
9254ccba60fSjmatthew 	iavf_wr(sc, sc->sc_aq_regs->atq_bal, 0);
9264ccba60fSjmatthew 	iavf_wr(sc, sc->sc_aq_regs->atq_bah, 0);
9274ccba60fSjmatthew 	iavf_wr(sc, sc->sc_aq_regs->atq_len, 0);
9284ccba60fSjmatthew 
9294ccba60fSjmatthew 	iavf_wr(sc, sc->sc_aq_regs->arq_bal, 0);
9304ccba60fSjmatthew 	iavf_wr(sc, sc->sc_aq_regs->arq_bah, 0);
9314ccba60fSjmatthew 	iavf_wr(sc, sc->sc_aq_regs->arq_len, 0);
9324ccba60fSjmatthew 
9334ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_arq),
9344ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&sc->sc_arq),
9354ccba60fSjmatthew 	    BUS_DMASYNC_POSTREAD);
9364ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq),
9374ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&sc->sc_atq),
9384ccba60fSjmatthew 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
9394ccba60fSjmatthew 
9404ccba60fSjmatthew 	iavf_arq_unfill(sc);
9414ccba60fSjmatthew free_arq:
9424ccba60fSjmatthew 	iavf_dmamem_free(sc, &sc->sc_arq);
9434ccba60fSjmatthew free_atq:
9444ccba60fSjmatthew 	iavf_dmamem_free(sc, &sc->sc_atq);
9454ccba60fSjmatthew unmap:
9464ccba60fSjmatthew 	bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems);
9474ccba60fSjmatthew 	sc->sc_mems = 0;
9484ccba60fSjmatthew }
9494ccba60fSjmatthew 
9504ccba60fSjmatthew static int
9514ccba60fSjmatthew iavf_media_change(struct ifnet *ifp)
9524ccba60fSjmatthew {
9534ccba60fSjmatthew 	return (EOPNOTSUPP);
9544ccba60fSjmatthew }
9554ccba60fSjmatthew 
9564ccba60fSjmatthew static void
9574ccba60fSjmatthew iavf_media_status(struct ifnet *ifp, struct ifmediareq *ifm)
9584ccba60fSjmatthew {
9594ccba60fSjmatthew 	struct iavf_softc *sc = ifp->if_softc;
9604ccba60fSjmatthew 
96104e5e978Sjmatthew 	KERNEL_ASSERT_LOCKED();
9624ccba60fSjmatthew 
9634ccba60fSjmatthew 	ifm->ifm_status = sc->sc_media_status;
9644ccba60fSjmatthew 	ifm->ifm_active = sc->sc_media_active;
9654ccba60fSjmatthew }
9664ccba60fSjmatthew 
9674ccba60fSjmatthew static void
9684ccba60fSjmatthew iavf_watchdog(struct ifnet *ifp)
9694ccba60fSjmatthew {
9704ccba60fSjmatthew 
9714ccba60fSjmatthew }
9724ccba60fSjmatthew 
9734ccba60fSjmatthew int
9744ccba60fSjmatthew iavf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
9754ccba60fSjmatthew {
9764ccba60fSjmatthew 	struct iavf_softc *sc = (struct iavf_softc *)ifp->if_softc;
9774ccba60fSjmatthew 	struct ifreq *ifr = (struct ifreq *)data;
9784ccba60fSjmatthew 	uint8_t addrhi[ETHER_ADDR_LEN], addrlo[ETHER_ADDR_LEN];
9794ccba60fSjmatthew 	int /*aqerror,*/ error = 0;
9804ccba60fSjmatthew 
9814ccba60fSjmatthew 	switch (cmd) {
9824ccba60fSjmatthew 	case SIOCSIFADDR:
9834ccba60fSjmatthew 		ifp->if_flags |= IFF_UP;
9844ccba60fSjmatthew 		/* FALLTHROUGH */
9854ccba60fSjmatthew 
9864ccba60fSjmatthew 	case SIOCSIFFLAGS:
9874ccba60fSjmatthew 		if (ISSET(ifp->if_flags, IFF_UP)) {
9884ccba60fSjmatthew 			if (ISSET(ifp->if_flags, IFF_RUNNING))
9894ccba60fSjmatthew 				error = ENETRESET;
9904ccba60fSjmatthew 			else
9914ccba60fSjmatthew 				error = iavf_up(sc);
9924ccba60fSjmatthew 		} else {
9934ccba60fSjmatthew 			if (ISSET(ifp->if_flags, IFF_RUNNING))
9944ccba60fSjmatthew 				error = iavf_down(sc);
9954ccba60fSjmatthew 		}
9964ccba60fSjmatthew 		break;
9974ccba60fSjmatthew 
9984ccba60fSjmatthew 	case SIOCGIFMEDIA:
9994ccba60fSjmatthew 	case SIOCSIFMEDIA:
10004ccba60fSjmatthew 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
10014ccba60fSjmatthew 		break;
10024ccba60fSjmatthew 
10034ccba60fSjmatthew 	case SIOCGIFRXR:
10044ccba60fSjmatthew 		error = iavf_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data);
10054ccba60fSjmatthew 		break;
10064ccba60fSjmatthew 
10074ccba60fSjmatthew 	case SIOCADDMULTI:
10084ccba60fSjmatthew 		if (ether_addmulti(ifr, &sc->sc_ac) == ENETRESET) {
10094ccba60fSjmatthew 			error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
10104ccba60fSjmatthew 			if (error != 0)
10114ccba60fSjmatthew 				return (error);
10124ccba60fSjmatthew 
10134ccba60fSjmatthew 			iavf_add_del_addr(sc, addrlo, 1);
10144ccba60fSjmatthew 			/* check result i guess? */
10154ccba60fSjmatthew 
10164ccba60fSjmatthew 			if (sc->sc_ac.ac_multirangecnt > 0) {
10174ccba60fSjmatthew 				SET(ifp->if_flags, IFF_ALLMULTI);
10184ccba60fSjmatthew 				error = ENETRESET;
10194ccba60fSjmatthew 			}
10204ccba60fSjmatthew 		}
10214ccba60fSjmatthew 		break;
10224ccba60fSjmatthew 
10234ccba60fSjmatthew 	case SIOCDELMULTI:
10244ccba60fSjmatthew 		if (ether_delmulti(ifr, &sc->sc_ac) == ENETRESET) {
10254ccba60fSjmatthew 			error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
10264ccba60fSjmatthew 			if (error != 0)
10274ccba60fSjmatthew 				return (error);
10284ccba60fSjmatthew 
10294ccba60fSjmatthew 			iavf_add_del_addr(sc, addrlo, 0);
10304ccba60fSjmatthew 
10314ccba60fSjmatthew 			if (ISSET(ifp->if_flags, IFF_ALLMULTI) &&
10324ccba60fSjmatthew 			    sc->sc_ac.ac_multirangecnt == 0) {
10334ccba60fSjmatthew 				CLR(ifp->if_flags, IFF_ALLMULTI);
10344ccba60fSjmatthew 				error = ENETRESET;
10354ccba60fSjmatthew 			}
10364ccba60fSjmatthew 		}
10374ccba60fSjmatthew 		break;
10384ccba60fSjmatthew 
10394ccba60fSjmatthew 	default:
10404ccba60fSjmatthew 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
10414ccba60fSjmatthew 		break;
10424ccba60fSjmatthew 	}
10434ccba60fSjmatthew 
10444ccba60fSjmatthew 	if (error == ENETRESET)
10454ccba60fSjmatthew 		error = iavf_iff(sc);
10464ccba60fSjmatthew 
10474ccba60fSjmatthew 	return (error);
10484ccba60fSjmatthew }
10494ccba60fSjmatthew 
10504ccba60fSjmatthew static int
10514ccba60fSjmatthew iavf_config_vsi_queues(struct iavf_softc *sc)
10524ccba60fSjmatthew {
10534ccba60fSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
10544ccba60fSjmatthew 	struct iavf_aq_desc iaq;
10554ccba60fSjmatthew 	struct iavf_vc_queue_config_info *config;
10564ccba60fSjmatthew 	struct iavf_vc_txq_info *txq;
10574ccba60fSjmatthew 	struct iavf_vc_rxq_info *rxq;
10584ccba60fSjmatthew 	struct iavf_rx_ring *rxr;
10594ccba60fSjmatthew 	struct iavf_tx_ring *txr;
10604ccba60fSjmatthew 	int rv, i;
10614ccba60fSjmatthew 
10624ccba60fSjmatthew 	memset(&iaq, 0, sizeof(iaq));
10634ccba60fSjmatthew 	iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD);
10644ccba60fSjmatthew 	iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF);
10654ccba60fSjmatthew 	iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_CONFIG_VSI_QUEUES);
10664ccba60fSjmatthew 	iaq.iaq_datalen = htole16(sizeof(*config) +
10674ccba60fSjmatthew 	    iavf_nqueues(sc) * sizeof(struct iavf_vc_queue_pair_info));
10684ccba60fSjmatthew 	iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch));
10694ccba60fSjmatthew 
10704ccba60fSjmatthew 	config = IAVF_DMA_KVA(&sc->sc_scratch);
10714ccba60fSjmatthew 	config->vsi_id = htole16(sc->sc_vsi_id);
10724ccba60fSjmatthew 	config->num_queue_pairs = htole16(iavf_nqueues(sc));
10734ccba60fSjmatthew 
10744ccba60fSjmatthew 	for (i = 0; i < iavf_nqueues(sc); i++) {
10754ccba60fSjmatthew 		rxr = ifp->if_iqs[i]->ifiq_softc;
10764ccba60fSjmatthew 		txr = ifp->if_ifqs[i]->ifq_softc;
10774ccba60fSjmatthew 
10784ccba60fSjmatthew 		txq = &config->qpair[i].txq;
10794ccba60fSjmatthew 		txq->vsi_id = htole16(sc->sc_vsi_id);
10804ccba60fSjmatthew 		txq->queue_id = htole16(i);
10814ccba60fSjmatthew 		txq->ring_len = sc->sc_tx_ring_ndescs;
10824ccba60fSjmatthew 		txq->headwb_ena = 0;
10834ccba60fSjmatthew 		htolem64(&txq->dma_ring_addr, IAVF_DMA_DVA(&txr->txr_mem));
10844ccba60fSjmatthew 		txq->dma_headwb_addr = 0;
10854ccba60fSjmatthew 
10864ccba60fSjmatthew 		rxq = &config->qpair[i].rxq;
10874ccba60fSjmatthew 		rxq->vsi_id = htole16(sc->sc_vsi_id);
10884ccba60fSjmatthew 		rxq->queue_id = htole16(i);
10894ccba60fSjmatthew 		rxq->ring_len = sc->sc_rx_ring_ndescs;
10904ccba60fSjmatthew 		rxq->splithdr_ena = 0;
10914ccba60fSjmatthew 		rxq->databuf_size = htole32(MCLBYTES);
10924ccba60fSjmatthew 		rxq->max_pkt_size = htole32(IAVF_HARDMTU);
10934ccba60fSjmatthew 		htolem64(&rxq->dma_ring_addr, IAVF_DMA_DVA(&rxr->rxr_mem));
10944ccba60fSjmatthew 		rxq->rx_split_pos = 0;
10954ccba60fSjmatthew 	}
10964ccba60fSjmatthew 
10974ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0,
10984ccba60fSjmatthew 	    IAVF_DMA_LEN(&sc->sc_scratch),
10994ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD);
11004ccba60fSjmatthew 
11014ccba60fSjmatthew 	iavf_atq_post(sc, &iaq);
11024ccba60fSjmatthew 	rv = iavf_arq_wait(sc, 250);
11034ccba60fSjmatthew 	if (rv != IAVF_VC_RC_SUCCESS) {
11044ccba60fSjmatthew 		printf("%s: CONFIG_VSI_QUEUES failed: %d\n", DEVNAME(sc), rv);
11054ccba60fSjmatthew 		return (1);
11064ccba60fSjmatthew 	}
11074ccba60fSjmatthew 
11084ccba60fSjmatthew 	return (0);
11094ccba60fSjmatthew }
11104ccba60fSjmatthew 
11114ccba60fSjmatthew static int
11124ccba60fSjmatthew iavf_config_hena(struct iavf_softc *sc)
11134ccba60fSjmatthew {
11144ccba60fSjmatthew 	struct iavf_aq_desc iaq;
11154ccba60fSjmatthew 	uint64_t *caps;
11164ccba60fSjmatthew 	int rv;
11174ccba60fSjmatthew 
11184ccba60fSjmatthew 	memset(&iaq, 0, sizeof(iaq));
11194ccba60fSjmatthew 	iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD);
11204ccba60fSjmatthew 	iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF);
11214ccba60fSjmatthew 	iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_SET_RSS_HENA);
112226c48d9fSjmatthew 	iaq.iaq_datalen = htole16(sizeof(*caps));
11234ccba60fSjmatthew 	iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch));
11244ccba60fSjmatthew 
11254ccba60fSjmatthew 	caps = IAVF_DMA_KVA(&sc->sc_scratch);
11264ccba60fSjmatthew 	*caps = 0;
11274ccba60fSjmatthew 
11284ccba60fSjmatthew 	iavf_atq_post(sc, &iaq);
11294ccba60fSjmatthew 	rv = iavf_arq_wait(sc, 250);
11304ccba60fSjmatthew 	if (rv != IAVF_VC_RC_SUCCESS) {
11314ccba60fSjmatthew 		printf("%s: SET_RSS_HENA failed: %d\n", DEVNAME(sc), rv);
11324ccba60fSjmatthew 		return (1);
11334ccba60fSjmatthew 	}
11344ccba60fSjmatthew 
11354ccba60fSjmatthew 	caps = IAVF_DMA_KVA(&sc->sc_scratch);
11364ccba60fSjmatthew 
11374ccba60fSjmatthew 	return (0);
11384ccba60fSjmatthew }
11394ccba60fSjmatthew 
11404ccba60fSjmatthew static int
11411f28ec92Sjmatthew iavf_queue_select(struct iavf_softc *sc, int opcode)
11424ccba60fSjmatthew {
11434ccba60fSjmatthew 	struct iavf_aq_desc iaq;
11444ccba60fSjmatthew 	struct iavf_vc_queue_select *qsel;
11454ccba60fSjmatthew 	int rv;
11464ccba60fSjmatthew 
11474ccba60fSjmatthew 	memset(&iaq, 0, sizeof(iaq));
11484ccba60fSjmatthew 	iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD);
11494ccba60fSjmatthew 	iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF);
11501f28ec92Sjmatthew 	iaq.iaq_vc_opcode = htole32(opcode);
11514ccba60fSjmatthew 	iaq.iaq_datalen = htole16(sizeof(*qsel));
11524ccba60fSjmatthew 	iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch));
11534ccba60fSjmatthew 
11544ccba60fSjmatthew 	qsel = IAVF_DMA_KVA(&sc->sc_scratch);
11554ccba60fSjmatthew 	qsel->vsi_id = htole16(sc->sc_vsi_id);
11561f28ec92Sjmatthew 	qsel->rx_queues = htole32(iavf_allqueues(sc));
11571f28ec92Sjmatthew 	qsel->tx_queues = htole32(iavf_allqueues(sc));
11584ccba60fSjmatthew 
11594ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0,
11604ccba60fSjmatthew 	    IAVF_DMA_LEN(&sc->sc_scratch),
11614ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD);
11624ccba60fSjmatthew 
11634ccba60fSjmatthew 	iavf_atq_post(sc, &iaq);
11644ccba60fSjmatthew 	rv = iavf_arq_wait(sc, 250);
11654ccba60fSjmatthew 	if (rv != IAVF_VC_RC_SUCCESS) {
11661f28ec92Sjmatthew 		printf("%s: queue op %d failed: %d\n", DEVNAME(sc), opcode, rv);
11674ccba60fSjmatthew 		return (1);
11684ccba60fSjmatthew 	}
11694ccba60fSjmatthew 
11704ccba60fSjmatthew 	return (0);
11714ccba60fSjmatthew }
11724ccba60fSjmatthew 
11734ccba60fSjmatthew static int
11744ccba60fSjmatthew iavf_up(struct iavf_softc *sc)
11754ccba60fSjmatthew {
11764ccba60fSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
11774ccba60fSjmatthew 	struct iavf_rx_ring *rxr;
11784ccba60fSjmatthew 	struct iavf_tx_ring *txr;
11794ccba60fSjmatthew 	unsigned int nqueues, i;
11804ccba60fSjmatthew 	int rv = ENOMEM;
11814ccba60fSjmatthew 
11824ccba60fSjmatthew 	nqueues = iavf_nqueues(sc);
11834ccba60fSjmatthew 	KASSERT(nqueues == 1); /* XXX */
11844ccba60fSjmatthew 
11854ccba60fSjmatthew 	rw_enter_write(&sc->sc_cfg_lock);
11864ccba60fSjmatthew 	if (sc->sc_dead) {
11874ccba60fSjmatthew 		rw_exit_write(&sc->sc_cfg_lock);
11884ccba60fSjmatthew 		return (ENXIO);
11894ccba60fSjmatthew 	}
11904ccba60fSjmatthew 
11914ccba60fSjmatthew 	for (i = 0; i < nqueues; i++) {
11924ccba60fSjmatthew 		rxr = iavf_rxr_alloc(sc, i);
11934ccba60fSjmatthew 		if (rxr == NULL)
11944ccba60fSjmatthew 			goto free;
11954ccba60fSjmatthew 
11964ccba60fSjmatthew 		txr = iavf_txr_alloc(sc, i);
11974ccba60fSjmatthew 		if (txr == NULL) {
11984ccba60fSjmatthew 			iavf_rxr_free(sc, rxr);
11994ccba60fSjmatthew 			goto free;
12004ccba60fSjmatthew 		}
12014ccba60fSjmatthew 
12024ccba60fSjmatthew 		ifp->if_iqs[i]->ifiq_softc = rxr;
12034ccba60fSjmatthew 		ifp->if_ifqs[i]->ifq_softc = txr;
12044ccba60fSjmatthew 
12054ccba60fSjmatthew 		iavf_rxfill(sc, rxr);
12064ccba60fSjmatthew 	}
12074ccba60fSjmatthew 
12084ccba60fSjmatthew 	if (iavf_config_vsi_queues(sc) != 0)
12094ccba60fSjmatthew 		goto down;
12104ccba60fSjmatthew 
12114ccba60fSjmatthew 	if (iavf_config_hena(sc) != 0)
12124ccba60fSjmatthew 		goto down;
12134ccba60fSjmatthew 
12141f28ec92Sjmatthew 	if (iavf_queue_select(sc, IAVF_VC_OP_ENABLE_QUEUES) != 0)
12154ccba60fSjmatthew 		goto down;
12164ccba60fSjmatthew 
12174ccba60fSjmatthew 	SET(ifp->if_flags, IFF_RUNNING);
12184ccba60fSjmatthew 
12194ccba60fSjmatthew 	iavf_wr(sc, I40E_VFINT_ITR01(0), 0x7a);
12204ccba60fSjmatthew 	iavf_wr(sc, I40E_VFINT_ITR01(1), 0x7a);
12214ccba60fSjmatthew 	iavf_wr(sc, I40E_VFINT_ITR01(2), 0);
12224ccba60fSjmatthew 
12234ccba60fSjmatthew 	rw_exit_write(&sc->sc_cfg_lock);
12244ccba60fSjmatthew 
12254ccba60fSjmatthew 	return (ENETRESET);
12264ccba60fSjmatthew 
12274ccba60fSjmatthew free:
12284ccba60fSjmatthew 	for (i = 0; i < nqueues; i++) {
12294ccba60fSjmatthew 		rxr = ifp->if_iqs[i]->ifiq_softc;
12304ccba60fSjmatthew 		txr = ifp->if_ifqs[i]->ifq_softc;
12314ccba60fSjmatthew 
12324ccba60fSjmatthew 		if (rxr == NULL) {
12334ccba60fSjmatthew 			/*
12344ccba60fSjmatthew 			 * tx and rx get set at the same time, so if one
12354ccba60fSjmatthew 			 * is NULL, the other is too.
12364ccba60fSjmatthew 			 */
12374ccba60fSjmatthew 			continue;
12384ccba60fSjmatthew 		}
12394ccba60fSjmatthew 
12404ccba60fSjmatthew 		iavf_txr_free(sc, txr);
12414ccba60fSjmatthew 		iavf_rxr_free(sc, rxr);
12424ccba60fSjmatthew 	}
12434ccba60fSjmatthew 	rw_exit_write(&sc->sc_cfg_lock);
12444ccba60fSjmatthew 	return (rv);
12454ccba60fSjmatthew down:
12464ccba60fSjmatthew 	rw_exit_write(&sc->sc_cfg_lock);
12474ccba60fSjmatthew 	iavf_down(sc);
12484ccba60fSjmatthew 	return (ETIMEDOUT);
12494ccba60fSjmatthew }
12504ccba60fSjmatthew 
12514ccba60fSjmatthew static int
12524ccba60fSjmatthew iavf_config_promisc_mode(struct iavf_softc *sc, int unicast, int multicast)
12534ccba60fSjmatthew {
12544ccba60fSjmatthew 	struct iavf_aq_desc iaq;
12554ccba60fSjmatthew 	struct iavf_vc_promisc_info *promisc;
12564ccba60fSjmatthew 	int rv, flags;
12574ccba60fSjmatthew 
12584ccba60fSjmatthew 	memset(&iaq, 0, sizeof(iaq));
12594ccba60fSjmatthew 	iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD);
12604ccba60fSjmatthew 	iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF);
12614ccba60fSjmatthew 	iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_CONFIG_PROMISC);
12624ccba60fSjmatthew 	iaq.iaq_datalen = htole16(sizeof(*promisc));
12634ccba60fSjmatthew 	iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch));
12644ccba60fSjmatthew 
12654ccba60fSjmatthew 	flags = 0;
12664ccba60fSjmatthew 	if (unicast)
12674ccba60fSjmatthew 		flags |= IAVF_FLAG_VF_UNICAST_PROMISC;
12684ccba60fSjmatthew 	if (multicast)
12694ccba60fSjmatthew 		flags |= IAVF_FLAG_VF_MULTICAST_PROMISC;
12704ccba60fSjmatthew 
12714ccba60fSjmatthew 	promisc = IAVF_DMA_KVA(&sc->sc_scratch);
12724ccba60fSjmatthew 	promisc->vsi_id = htole16(sc->sc_vsi_id);
12734ccba60fSjmatthew 	promisc->flags = htole16(flags);
12744ccba60fSjmatthew 
12754ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0,
12764ccba60fSjmatthew 	    IAVF_DMA_LEN(&sc->sc_scratch),
12774ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD);
12784ccba60fSjmatthew 
12794ccba60fSjmatthew 	iavf_atq_post(sc, &iaq);
12804ccba60fSjmatthew 	rv = iavf_arq_wait(sc, 250);
12814ccba60fSjmatthew 	if (rv != IAVF_VC_RC_SUCCESS) {
12824ccba60fSjmatthew 		printf("%s: CONFIG_PROMISC_MODE failed: %d\n", DEVNAME(sc), rv);
12834ccba60fSjmatthew 		return (1);
12844ccba60fSjmatthew 	}
12854ccba60fSjmatthew 
12864ccba60fSjmatthew 	return (0);
12874ccba60fSjmatthew }
12884ccba60fSjmatthew 
12894ccba60fSjmatthew static int
12904ccba60fSjmatthew iavf_add_del_addr(struct iavf_softc *sc, uint8_t *addr, int add)
12914ccba60fSjmatthew {
12924ccba60fSjmatthew 	struct iavf_aq_desc iaq;
12934ccba60fSjmatthew 	struct iavf_vc_eth_addr_list *addrs;
12944ccba60fSjmatthew 	struct iavf_vc_eth_addr *vcaddr;
12954ccba60fSjmatthew 	int rv;
12964ccba60fSjmatthew 
12974ccba60fSjmatthew 	memset(&iaq, 0, sizeof(iaq));
12984ccba60fSjmatthew 	iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD);
12994ccba60fSjmatthew 	iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF);
13004ccba60fSjmatthew 	if (add)
13014ccba60fSjmatthew 		iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_ADD_ETH_ADDR);
13024ccba60fSjmatthew 	else
13034ccba60fSjmatthew 		iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_DEL_ETH_ADDR);
13044ccba60fSjmatthew 	iaq.iaq_datalen = htole16(sizeof(*addrs) + sizeof(*vcaddr));
13054ccba60fSjmatthew 	iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch));
13064ccba60fSjmatthew 
13074ccba60fSjmatthew 	addrs = IAVF_DMA_KVA(&sc->sc_scratch);
13084ccba60fSjmatthew 	addrs->vsi_id = htole16(sc->sc_vsi_id);
13094ccba60fSjmatthew 	addrs->num_elements = htole16(1);
13104ccba60fSjmatthew 
13114ccba60fSjmatthew 	vcaddr = addrs->list;
13124ccba60fSjmatthew 	memcpy(vcaddr->addr, addr, ETHER_ADDR_LEN);
13134ccba60fSjmatthew 
13144ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0,
13154ccba60fSjmatthew 	    IAVF_DMA_LEN(&sc->sc_scratch),
13164ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD);
13174ccba60fSjmatthew 
13184ccba60fSjmatthew 	iavf_atq_post(sc, &iaq);
13194ccba60fSjmatthew 	rv = iavf_arq_wait(sc, 250);
13204ccba60fSjmatthew 	if (rv != IAVF_VC_RC_SUCCESS) {
13214ccba60fSjmatthew 		printf("%s: ADD/DEL_ETH_ADDR failed: %d\n", DEVNAME(sc), rv);
13224ccba60fSjmatthew 		return (1);
13234ccba60fSjmatthew 	}
13244ccba60fSjmatthew 
13254ccba60fSjmatthew 	return (0);
13264ccba60fSjmatthew }
13274ccba60fSjmatthew 
13284ccba60fSjmatthew static int
13294ccba60fSjmatthew iavf_iff(struct iavf_softc *sc)
13304ccba60fSjmatthew {
13314ccba60fSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
1332ec60c50dSjmatthew 	int unicast, multicast;
13334ccba60fSjmatthew 
13344ccba60fSjmatthew 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
13354ccba60fSjmatthew 		return (0);
13364ccba60fSjmatthew 
13374ccba60fSjmatthew 	rw_enter_write(&sc->sc_cfg_lock);
13384ccba60fSjmatthew 
1339ec60c50dSjmatthew 	unicast = 0;
1340ec60c50dSjmatthew 	multicast = 0;
1341ec60c50dSjmatthew 	if (ISSET(ifp->if_flags, IFF_PROMISC)) {
1342ec60c50dSjmatthew 		unicast = 1;
1343ec60c50dSjmatthew 		multicast = 1;
1344ec60c50dSjmatthew 	} else if (ISSET(ifp->if_flags, IFF_ALLMULTI)) {
1345ec60c50dSjmatthew 		multicast = 1;
1346ec60c50dSjmatthew 	}
1347ec60c50dSjmatthew 	iavf_config_promisc_mode(sc, unicast, multicast);
13484ccba60fSjmatthew 
13494ccba60fSjmatthew 	if (memcmp(sc->sc_enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN) != 0) {
13504ccba60fSjmatthew 		if (memcmp(sc->sc_enaddr, etheranyaddr, ETHER_ADDR_LEN) != 0)
13514ccba60fSjmatthew 			iavf_add_del_addr(sc, sc->sc_enaddr, 0);
13524ccba60fSjmatthew 		memcpy(sc->sc_enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
13534ccba60fSjmatthew 		iavf_add_del_addr(sc, sc->sc_enaddr, 1);
13544ccba60fSjmatthew 	}
13554ccba60fSjmatthew 
13564ccba60fSjmatthew 	rw_exit_write(&sc->sc_cfg_lock);
13574ccba60fSjmatthew 	return (0);
13584ccba60fSjmatthew }
13594ccba60fSjmatthew 
13604ccba60fSjmatthew static int
13614ccba60fSjmatthew iavf_down(struct iavf_softc *sc)
13624ccba60fSjmatthew {
13634ccba60fSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
13644ccba60fSjmatthew 	struct iavf_rx_ring *rxr;
13654ccba60fSjmatthew 	struct iavf_tx_ring *txr;
13664ccba60fSjmatthew 	unsigned int nqueues, i;
13671f28ec92Sjmatthew 	uint32_t reg;
13684ccba60fSjmatthew 	int error = 0;
13694ccba60fSjmatthew 
13704ccba60fSjmatthew 	nqueues = iavf_nqueues(sc);
13714ccba60fSjmatthew 
13724ccba60fSjmatthew 	rw_enter_write(&sc->sc_cfg_lock);
13734ccba60fSjmatthew 
13744ccba60fSjmatthew 	CLR(ifp->if_flags, IFF_RUNNING);
13754ccba60fSjmatthew 
13764ccba60fSjmatthew 	NET_UNLOCK();
13774ccba60fSjmatthew 
13782fa30b92Sjmatthew 	if (sc->sc_resetting == 0) {
13794ccba60fSjmatthew 		/* disable queues */
13801f28ec92Sjmatthew 		if (iavf_queue_select(sc, IAVF_VC_OP_DISABLE_QUEUES) != 0)
13811f28ec92Sjmatthew 			goto die;
13822fa30b92Sjmatthew 	}
13834ccba60fSjmatthew 
13841f28ec92Sjmatthew 	/* mask interrupts */
13851f28ec92Sjmatthew 	reg = iavf_rd(sc, I40E_VFINT_DYN_CTL01);
13861f28ec92Sjmatthew 	reg |= I40E_VFINT_DYN_CTL0_INTENA_MSK_MASK |
13871f28ec92Sjmatthew 	    (IAVF_NOITR << I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT);
13881f28ec92Sjmatthew 	iavf_wr(sc, I40E_VFINT_DYN_CTL01, reg);
13891f28ec92Sjmatthew 
13901f28ec92Sjmatthew 	/* make sure no hw generated work is still in flight */
13914ccba60fSjmatthew 	intr_barrier(sc->sc_ihc);
13924ccba60fSjmatthew 	for (i = 0; i < nqueues; i++) {
13934ccba60fSjmatthew 		rxr = ifp->if_iqs[i]->ifiq_softc;
13944ccba60fSjmatthew 		txr = ifp->if_ifqs[i]->ifq_softc;
13954ccba60fSjmatthew 
13964ccba60fSjmatthew 		ifq_barrier(ifp->if_ifqs[i]);
13974ccba60fSjmatthew 
13984ccba60fSjmatthew 		timeout_del_barrier(&rxr->rxr_refill);
13994ccba60fSjmatthew 	}
14004ccba60fSjmatthew 
14014ccba60fSjmatthew 	for (i = 0; i < nqueues; i++) {
14024ccba60fSjmatthew 		rxr = ifp->if_iqs[i]->ifiq_softc;
14034ccba60fSjmatthew 		txr = ifp->if_ifqs[i]->ifq_softc;
14044ccba60fSjmatthew 
14054ccba60fSjmatthew 		iavf_txr_clean(sc, txr);
14064ccba60fSjmatthew 		iavf_rxr_clean(sc, rxr);
14074ccba60fSjmatthew 
14084ccba60fSjmatthew 		iavf_txr_free(sc, txr);
14094ccba60fSjmatthew 		iavf_rxr_free(sc, rxr);
14104ccba60fSjmatthew 
14114ccba60fSjmatthew 		ifp->if_iqs[i]->ifiq_softc = NULL;
14124ccba60fSjmatthew 		ifp->if_ifqs[i]->ifq_softc =  NULL;
14134ccba60fSjmatthew 	}
14144ccba60fSjmatthew 
14151f28ec92Sjmatthew 	/* unmask */
14161f28ec92Sjmatthew 	reg = iavf_rd(sc, I40E_VFINT_DYN_CTL01);
14171f28ec92Sjmatthew 	reg |= (IAVF_NOITR << I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT);
14181f28ec92Sjmatthew 	iavf_wr(sc, I40E_VFINT_DYN_CTL01, reg);
14191f28ec92Sjmatthew 
14204ccba60fSjmatthew out:
14214ccba60fSjmatthew 	rw_exit_write(&sc->sc_cfg_lock);
14224ccba60fSjmatthew 	NET_LOCK();
14234ccba60fSjmatthew 	return (error);
14241f28ec92Sjmatthew die:
14254ccba60fSjmatthew 	sc->sc_dead = 1;
14264ccba60fSjmatthew 	log(LOG_CRIT, "%s: failed to shut down rings", DEVNAME(sc));
14274ccba60fSjmatthew 	error = ETIMEDOUT;
14284ccba60fSjmatthew 	goto out;
14294ccba60fSjmatthew }
14304ccba60fSjmatthew 
14312fa30b92Sjmatthew static void
14322fa30b92Sjmatthew iavf_reset(void *xsc)
14332fa30b92Sjmatthew {
14342fa30b92Sjmatthew 	struct iavf_softc *sc = xsc;
14352fa30b92Sjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
14362fa30b92Sjmatthew 	int tries, up, link_state;
14372fa30b92Sjmatthew 
14382fa30b92Sjmatthew 	NET_LOCK();
14392fa30b92Sjmatthew 
14402fa30b92Sjmatthew 	/* treat the reset as a loss of link */
14412fa30b92Sjmatthew 	link_state = ifp->if_link_state;
14422fa30b92Sjmatthew 	if (ifp->if_link_state != LINK_STATE_DOWN) {
14432fa30b92Sjmatthew 		ifp->if_link_state = LINK_STATE_DOWN;
14442fa30b92Sjmatthew 		if_link_state_change(ifp);
14452fa30b92Sjmatthew 	}
14462fa30b92Sjmatthew 
14472fa30b92Sjmatthew 	up = 0;
14482fa30b92Sjmatthew 	if (ISSET(ifp->if_flags, IFF_RUNNING)) {
14492fa30b92Sjmatthew 		iavf_down(sc);
14502fa30b92Sjmatthew 		up = 1;
14512fa30b92Sjmatthew 	}
14522fa30b92Sjmatthew 
14532fa30b92Sjmatthew 	rw_enter_write(&sc->sc_cfg_lock);
14542fa30b92Sjmatthew 
14552fa30b92Sjmatthew 	sc->sc_major_ver = UINT_MAX;
14562fa30b92Sjmatthew 	sc->sc_minor_ver = UINT_MAX;
14572fa30b92Sjmatthew 	sc->sc_got_vf_resources = 0;
14582fa30b92Sjmatthew 	sc->sc_got_irq_map = 0;
14592fa30b92Sjmatthew 
14602fa30b92Sjmatthew 	for (tries = 0; tries < 100; tries++) {
14612fa30b92Sjmatthew 		uint32_t reg;
14622fa30b92Sjmatthew 		reg = iavf_rd(sc, I40E_VFGEN_RSTAT) &
14632fa30b92Sjmatthew 		    I40E_VFGEN_RSTAT_VFR_STATE_MASK;
14642fa30b92Sjmatthew 		if (reg == IAVF_VFR_VFACTIVE ||
14652fa30b92Sjmatthew 		    reg == IAVF_VFR_COMPLETED)
14662fa30b92Sjmatthew 			break;
14672fa30b92Sjmatthew 
14682fa30b92Sjmatthew 		delay(10000);
14692fa30b92Sjmatthew 	}
14702fa30b92Sjmatthew 	if (tries == 100) {
14712fa30b92Sjmatthew 		printf("%s: VF reset timed out\n", DEVNAME(sc));
14722fa30b92Sjmatthew 		goto failed;
14732fa30b92Sjmatthew 	}
14742fa30b92Sjmatthew 
14752fa30b92Sjmatthew 	iavf_arq_unfill(sc);
14762fa30b92Sjmatthew 	sc->sc_arq_cons = 0;
14772fa30b92Sjmatthew 	sc->sc_arq_prod = 0;
14782fa30b92Sjmatthew 	if (!iavf_arq_fill(sc, 0)) {
14792fa30b92Sjmatthew 		printf("\n" "%s: unable to fill arq descriptors\n",
14802fa30b92Sjmatthew 		    DEVNAME(sc));
14812fa30b92Sjmatthew 		goto failed;
14822fa30b92Sjmatthew 	}
14832fa30b92Sjmatthew 
14842fa30b92Sjmatthew 	iavf_init_admin_queue(sc);
14852fa30b92Sjmatthew 
14862fa30b92Sjmatthew 	if (iavf_get_version(sc) != 0) {
14872fa30b92Sjmatthew 		printf("%s: unable to get VF interface version\n",
14882fa30b92Sjmatthew 		    DEVNAME(sc));
14892fa30b92Sjmatthew 		goto failed;
14902fa30b92Sjmatthew 	}
14912fa30b92Sjmatthew 
14922fa30b92Sjmatthew 	if (iavf_get_vf_resources(sc) != 0) {
14932fa30b92Sjmatthew 		printf("%s: timed out waiting for VF resources\n",
14942fa30b92Sjmatthew 		    DEVNAME(sc));
14952fa30b92Sjmatthew 		goto failed;
14962fa30b92Sjmatthew 	}
14972fa30b92Sjmatthew 
14982fa30b92Sjmatthew 	if (iavf_config_irq_map(sc) != 0) {
14992fa30b92Sjmatthew 		printf("%s: timed out configuring IRQ map\n", DEVNAME(sc));
15002fa30b92Sjmatthew 		goto failed;
15012fa30b92Sjmatthew 	}
15022fa30b92Sjmatthew 
15032fa30b92Sjmatthew 	/* do we need to re-add mac addresses here? */
15042fa30b92Sjmatthew 
15052fa30b92Sjmatthew 	sc->sc_resetting = 0;
15062fa30b92Sjmatthew 	iavf_intr_enable(sc);
15072fa30b92Sjmatthew 	rw_exit_write(&sc->sc_cfg_lock);
15082fa30b92Sjmatthew 
15092fa30b92Sjmatthew 	/* the PF-assigned MAC address might have changed */
15102fa30b92Sjmatthew 	if ((memcmp(sc->sc_ac.ac_enaddr, etheranyaddr, ETHER_ADDR_LEN) != 0) &&
15112fa30b92Sjmatthew 	    (memcmp(sc->sc_ac.ac_enaddr, sc->sc_enaddr, ETHER_ADDR_LEN) != 0)) {
15122fa30b92Sjmatthew 		memcpy(sc->sc_enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
15132fa30b92Sjmatthew 		if_setlladdr(ifp, sc->sc_ac.ac_enaddr);
15142fa30b92Sjmatthew 		ifnewlladdr(ifp);
15152fa30b92Sjmatthew 	}
15162fa30b92Sjmatthew 
15172fa30b92Sjmatthew 	/* restore link state */
15182fa30b92Sjmatthew 	if (link_state != LINK_STATE_DOWN) {
15192fa30b92Sjmatthew 		ifp->if_link_state = link_state;
15202fa30b92Sjmatthew 		if_link_state_change(ifp);
15212fa30b92Sjmatthew 	}
15222fa30b92Sjmatthew 
15232fa30b92Sjmatthew 	if (up) {
15242fa30b92Sjmatthew 		int i;
15252fa30b92Sjmatthew 
15262fa30b92Sjmatthew 		iavf_up(sc);
15272fa30b92Sjmatthew 
15282fa30b92Sjmatthew 		for (i = 0; i < iavf_nqueues(sc); i++) {
15292fa30b92Sjmatthew 			if (ifq_is_oactive(ifp->if_ifqs[i]))
15302fa30b92Sjmatthew 				ifq_restart(ifp->if_ifqs[i]);
15312fa30b92Sjmatthew 		}
15322fa30b92Sjmatthew 	}
15332fa30b92Sjmatthew 
15342fa30b92Sjmatthew 	NET_UNLOCK();
15352fa30b92Sjmatthew 	return;
15362fa30b92Sjmatthew failed:
15372fa30b92Sjmatthew 	sc->sc_dead = 1;
15382fa30b92Sjmatthew 	sc->sc_resetting = 0;
15392fa30b92Sjmatthew 	rw_exit_write(&sc->sc_cfg_lock);
15402fa30b92Sjmatthew 	NET_UNLOCK();
15412fa30b92Sjmatthew }
15422fa30b92Sjmatthew 
15434ccba60fSjmatthew static struct iavf_tx_ring *
15444ccba60fSjmatthew iavf_txr_alloc(struct iavf_softc *sc, unsigned int qid)
15454ccba60fSjmatthew {
15464ccba60fSjmatthew 	struct iavf_tx_ring *txr;
15474ccba60fSjmatthew 	struct iavf_tx_map *maps, *txm;
15484ccba60fSjmatthew 	unsigned int i;
15494ccba60fSjmatthew 
15504ccba60fSjmatthew 	txr = malloc(sizeof(*txr), M_DEVBUF, M_WAITOK|M_CANFAIL);
15514ccba60fSjmatthew 	if (txr == NULL)
15524ccba60fSjmatthew 		return (NULL);
15534ccba60fSjmatthew 
15544ccba60fSjmatthew 	maps = mallocarray(sizeof(*maps),
15554ccba60fSjmatthew 	    sc->sc_tx_ring_ndescs, M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
15564ccba60fSjmatthew 	if (maps == NULL)
15574ccba60fSjmatthew 		goto free;
15584ccba60fSjmatthew 
15594ccba60fSjmatthew 	if (iavf_dmamem_alloc(sc, &txr->txr_mem,
15604ccba60fSjmatthew 	    sizeof(struct iavf_tx_desc) * sc->sc_tx_ring_ndescs,
15614ccba60fSjmatthew 	    IAVF_TX_QUEUE_ALIGN) != 0)
15624ccba60fSjmatthew 		goto freemap;
15634ccba60fSjmatthew 
15644ccba60fSjmatthew 	for (i = 0; i < sc->sc_tx_ring_ndescs; i++) {
15654ccba60fSjmatthew 		txm = &maps[i];
15664ccba60fSjmatthew 
15674ccba60fSjmatthew 		if (bus_dmamap_create(sc->sc_dmat,
15684ccba60fSjmatthew 		    IAVF_HARDMTU, IAVF_TX_PKT_DESCS, IAVF_HARDMTU, 0,
15694ccba60fSjmatthew 		    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
15704ccba60fSjmatthew 		    &txm->txm_map) != 0)
15714ccba60fSjmatthew 			goto uncreate;
15724ccba60fSjmatthew 
15734ccba60fSjmatthew 		txm->txm_eop = -1;
15744ccba60fSjmatthew 		txm->txm_m = NULL;
15754ccba60fSjmatthew 	}
15764ccba60fSjmatthew 
15774ccba60fSjmatthew 	txr->txr_cons = txr->txr_prod = 0;
15784ccba60fSjmatthew 	txr->txr_maps = maps;
15794ccba60fSjmatthew 
15804ccba60fSjmatthew 	txr->txr_tail = I40E_QTX_TAIL1(qid);
15814ccba60fSjmatthew 	txr->txr_qid = qid;
15824ccba60fSjmatthew 
15834ccba60fSjmatthew 	return (txr);
15844ccba60fSjmatthew 
15854ccba60fSjmatthew uncreate:
15864ccba60fSjmatthew 	for (i = 0; i < sc->sc_tx_ring_ndescs; i++) {
15874ccba60fSjmatthew 		txm = &maps[i];
15884ccba60fSjmatthew 
15894ccba60fSjmatthew 		if (txm->txm_map == NULL)
15904ccba60fSjmatthew 			continue;
15914ccba60fSjmatthew 
15924ccba60fSjmatthew 		bus_dmamap_destroy(sc->sc_dmat, txm->txm_map);
15934ccba60fSjmatthew 	}
15944ccba60fSjmatthew 
15954ccba60fSjmatthew 	iavf_dmamem_free(sc, &txr->txr_mem);
15964ccba60fSjmatthew freemap:
15974ccba60fSjmatthew 	free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_tx_ring_ndescs);
15984ccba60fSjmatthew free:
15994ccba60fSjmatthew 	free(txr, M_DEVBUF, sizeof(*txr));
16004ccba60fSjmatthew 	return (NULL);
16014ccba60fSjmatthew }
16024ccba60fSjmatthew 
16034ccba60fSjmatthew static void
16044ccba60fSjmatthew iavf_txr_clean(struct iavf_softc *sc, struct iavf_tx_ring *txr)
16054ccba60fSjmatthew {
16064ccba60fSjmatthew 	struct iavf_tx_map *maps, *txm;
16074ccba60fSjmatthew 	bus_dmamap_t map;
16084ccba60fSjmatthew 	unsigned int i;
16094ccba60fSjmatthew 
16104ccba60fSjmatthew 	maps = txr->txr_maps;
16114ccba60fSjmatthew 	for (i = 0; i < sc->sc_tx_ring_ndescs; i++) {
16124ccba60fSjmatthew 		txm = &maps[i];
16134ccba60fSjmatthew 
16144ccba60fSjmatthew 		if (txm->txm_m == NULL)
16154ccba60fSjmatthew 			continue;
16164ccba60fSjmatthew 
16174ccba60fSjmatthew 		map = txm->txm_map;
16184ccba60fSjmatthew 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
16194ccba60fSjmatthew 		    BUS_DMASYNC_POSTWRITE);
16204ccba60fSjmatthew 		bus_dmamap_unload(sc->sc_dmat, map);
16214ccba60fSjmatthew 
16224ccba60fSjmatthew 		m_freem(txm->txm_m);
16234ccba60fSjmatthew 		txm->txm_m = NULL;
16244ccba60fSjmatthew 	}
16254ccba60fSjmatthew }
16264ccba60fSjmatthew 
16274ccba60fSjmatthew static void
16284ccba60fSjmatthew iavf_txr_free(struct iavf_softc *sc, struct iavf_tx_ring *txr)
16294ccba60fSjmatthew {
16304ccba60fSjmatthew 	struct iavf_tx_map *maps, *txm;
16314ccba60fSjmatthew 	unsigned int i;
16324ccba60fSjmatthew 
16334ccba60fSjmatthew 	maps = txr->txr_maps;
16344ccba60fSjmatthew 	for (i = 0; i < sc->sc_tx_ring_ndescs; i++) {
16354ccba60fSjmatthew 		txm = &maps[i];
16364ccba60fSjmatthew 
16374ccba60fSjmatthew 		bus_dmamap_destroy(sc->sc_dmat, txm->txm_map);
16384ccba60fSjmatthew 	}
16394ccba60fSjmatthew 
16404ccba60fSjmatthew 	iavf_dmamem_free(sc, &txr->txr_mem);
16414ccba60fSjmatthew 	free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_tx_ring_ndescs);
16424ccba60fSjmatthew 	free(txr, M_DEVBUF, sizeof(*txr));
16434ccba60fSjmatthew }
16444ccba60fSjmatthew 
16454ccba60fSjmatthew static inline int
16464ccba60fSjmatthew iavf_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m)
16474ccba60fSjmatthew {
16484ccba60fSjmatthew 	int error;
16494ccba60fSjmatthew 
16504ccba60fSjmatthew 	error = bus_dmamap_load_mbuf(dmat, map, m,
16514ccba60fSjmatthew 	    BUS_DMA_STREAMING | BUS_DMA_NOWAIT);
16524ccba60fSjmatthew 	if (error != EFBIG)
16534ccba60fSjmatthew 		return (error);
16544ccba60fSjmatthew 
16554ccba60fSjmatthew 	error = m_defrag(m, M_DONTWAIT);
16564ccba60fSjmatthew 	if (error != 0)
16574ccba60fSjmatthew 		return (error);
16584ccba60fSjmatthew 
16594ccba60fSjmatthew 	return (bus_dmamap_load_mbuf(dmat, map, m,
16604ccba60fSjmatthew 	    BUS_DMA_STREAMING | BUS_DMA_NOWAIT));
16614ccba60fSjmatthew }
16624ccba60fSjmatthew 
1663*51248bbdSyasuoka static uint64_t
1664*51248bbdSyasuoka iavf_tx_offload(struct mbuf *m)
1665*51248bbdSyasuoka {
1666*51248bbdSyasuoka 	struct ether_extracted ext;
1667*51248bbdSyasuoka 	uint64_t hlen;
1668*51248bbdSyasuoka 	uint64_t offload = 0;
1669*51248bbdSyasuoka 
1670*51248bbdSyasuoka #if NVLAN > 0
1671*51248bbdSyasuoka 	if (ISSET(m->m_flags, M_VLANTAG)) {
1672*51248bbdSyasuoka 		uint64_t vtag = m->m_pkthdr.ether_vtag;
1673*51248bbdSyasuoka 		offload |= IAVF_TX_DESC_CMD_IL2TAG1;
1674*51248bbdSyasuoka 		offload |= vtag << IAVF_TX_DESC_L2TAG1_SHIFT;
1675*51248bbdSyasuoka 	}
1676*51248bbdSyasuoka #endif
1677*51248bbdSyasuoka 
1678*51248bbdSyasuoka 	if (!ISSET(m->m_pkthdr.csum_flags,
1679*51248bbdSyasuoka 	    M_IPV4_CSUM_OUT|M_TCP_CSUM_OUT|M_UDP_CSUM_OUT))
1680*51248bbdSyasuoka 		return (offload);
1681*51248bbdSyasuoka 
1682*51248bbdSyasuoka 	ether_extract_headers(m, &ext);
1683*51248bbdSyasuoka 
1684*51248bbdSyasuoka 	if (ext.ip4) {
1685*51248bbdSyasuoka 		offload |= ISSET(m->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT) ?
1686*51248bbdSyasuoka 		    IAVF_TX_DESC_CMD_IIPT_IPV4_CSUM :
1687*51248bbdSyasuoka 		    IAVF_TX_DESC_CMD_IIPT_IPV4;
1688*51248bbdSyasuoka #ifdef INET6
1689*51248bbdSyasuoka 	} else if (ext.ip6) {
1690*51248bbdSyasuoka 		offload |= IAVF_TX_DESC_CMD_IIPT_IPV6;
1691*51248bbdSyasuoka #endif
1692*51248bbdSyasuoka 	} else {
1693*51248bbdSyasuoka 		panic("CSUM_OUT set for non-IP packet");
1694*51248bbdSyasuoka 		/* NOTREACHED */
1695*51248bbdSyasuoka 	}
1696*51248bbdSyasuoka 	hlen = ext.iphlen;
1697*51248bbdSyasuoka 
1698*51248bbdSyasuoka 	offload |= (ETHER_HDR_LEN >> 1) << IAVF_TX_DESC_MACLEN_SHIFT;
1699*51248bbdSyasuoka 	offload |= (hlen >> 2) << IAVF_TX_DESC_IPLEN_SHIFT;
1700*51248bbdSyasuoka 
1701*51248bbdSyasuoka 	if (ext.tcp && ISSET(m->m_pkthdr.csum_flags, M_TCP_CSUM_OUT)) {
1702*51248bbdSyasuoka 		offload |= IAVF_TX_DESC_CMD_L4T_EOFT_TCP;
1703*51248bbdSyasuoka 		offload |= (uint64_t)(ext.tcphlen >> 2)
1704*51248bbdSyasuoka 		    << IAVF_TX_DESC_L4LEN_SHIFT;
1705*51248bbdSyasuoka 	} else if (ext.udp && ISSET(m->m_pkthdr.csum_flags, M_UDP_CSUM_OUT)) {
1706*51248bbdSyasuoka 		offload |= IAVF_TX_DESC_CMD_L4T_EOFT_UDP;
1707*51248bbdSyasuoka 		offload |= (uint64_t)(sizeof(*ext.udp) >> 2)
1708*51248bbdSyasuoka 		    << IAVF_TX_DESC_L4LEN_SHIFT;
1709*51248bbdSyasuoka 	}
1710*51248bbdSyasuoka 
1711*51248bbdSyasuoka 	return offload;
1712*51248bbdSyasuoka }
1713*51248bbdSyasuoka 
17144ccba60fSjmatthew static void
17154ccba60fSjmatthew iavf_start(struct ifqueue *ifq)
17164ccba60fSjmatthew {
17174ccba60fSjmatthew 	struct ifnet *ifp = ifq->ifq_if;
17184ccba60fSjmatthew 	struct iavf_softc *sc = ifp->if_softc;
17194ccba60fSjmatthew 	struct iavf_tx_ring *txr = ifq->ifq_softc;
17204ccba60fSjmatthew 	struct iavf_tx_desc *ring, *txd;
17214ccba60fSjmatthew 	struct iavf_tx_map *txm;
17224ccba60fSjmatthew 	bus_dmamap_t map;
17234ccba60fSjmatthew 	struct mbuf *m;
17244ccba60fSjmatthew 	uint64_t cmd;
1725*51248bbdSyasuoka 	uint64_t offload;
17264ccba60fSjmatthew 	unsigned int prod, free, last, i;
17274ccba60fSjmatthew 	unsigned int mask;
17284ccba60fSjmatthew 	int post = 0;
17294ccba60fSjmatthew #if NBPFILTER > 0
17304ccba60fSjmatthew 	caddr_t if_bpf;
17314ccba60fSjmatthew #endif
17324ccba60fSjmatthew 
17334ccba60fSjmatthew 	if (!LINK_STATE_IS_UP(ifp->if_link_state)) {
17344ccba60fSjmatthew 		ifq_purge(ifq);
17354ccba60fSjmatthew 		return;
17364ccba60fSjmatthew 	}
17374ccba60fSjmatthew 
17384ccba60fSjmatthew 	prod = txr->txr_prod;
17394ccba60fSjmatthew 	free = txr->txr_cons;
17404ccba60fSjmatthew 	if (free <= prod)
17414ccba60fSjmatthew 		free += sc->sc_tx_ring_ndescs;
17424ccba60fSjmatthew 	free -= prod;
17434ccba60fSjmatthew 
17444ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&txr->txr_mem),
17454ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_POSTWRITE);
17464ccba60fSjmatthew 
17474ccba60fSjmatthew 	ring = IAVF_DMA_KVA(&txr->txr_mem);
17484ccba60fSjmatthew 	mask = sc->sc_tx_ring_ndescs - 1;
17494ccba60fSjmatthew 
17504ccba60fSjmatthew 	for (;;) {
17514ccba60fSjmatthew 		if (free <= IAVF_TX_PKT_DESCS) {
17524ccba60fSjmatthew 			ifq_set_oactive(ifq);
17534ccba60fSjmatthew 			break;
17544ccba60fSjmatthew 		}
17554ccba60fSjmatthew 
17564ccba60fSjmatthew 		m = ifq_dequeue(ifq);
17574ccba60fSjmatthew 		if (m == NULL)
17584ccba60fSjmatthew 			break;
17594ccba60fSjmatthew 
1760*51248bbdSyasuoka 		offload = iavf_tx_offload(m);
1761*51248bbdSyasuoka 
17624ccba60fSjmatthew 		txm = &txr->txr_maps[prod];
17634ccba60fSjmatthew 		map = txm->txm_map;
17644ccba60fSjmatthew 
17654ccba60fSjmatthew 		if (iavf_load_mbuf(sc->sc_dmat, map, m) != 0) {
17664ccba60fSjmatthew 			ifq->ifq_errors++;
17674ccba60fSjmatthew 			m_freem(m);
17684ccba60fSjmatthew 			continue;
17694ccba60fSjmatthew 		}
17704ccba60fSjmatthew 
17714ccba60fSjmatthew 		bus_dmamap_sync(sc->sc_dmat, map, 0,
17724ccba60fSjmatthew 		    map->dm_mapsize, BUS_DMASYNC_PREWRITE);
17734ccba60fSjmatthew 
17744ccba60fSjmatthew 		for (i = 0; i < map->dm_nsegs; i++) {
17754ccba60fSjmatthew 			txd = &ring[prod];
17764ccba60fSjmatthew 
17774ccba60fSjmatthew 			cmd = (uint64_t)map->dm_segs[i].ds_len <<
17784ccba60fSjmatthew 			    IAVF_TX_DESC_BSIZE_SHIFT;
1779*51248bbdSyasuoka 			cmd |= IAVF_TX_DESC_DTYPE_DATA | IAVF_TX_DESC_CMD_ICRC;
1780*51248bbdSyasuoka 			cmd |= offload;
17814ccba60fSjmatthew 
17824ccba60fSjmatthew 			htolem64(&txd->addr, map->dm_segs[i].ds_addr);
17834ccba60fSjmatthew 			htolem64(&txd->cmd, cmd);
17844ccba60fSjmatthew 
17854ccba60fSjmatthew 			last = prod;
17864ccba60fSjmatthew 
17874ccba60fSjmatthew 			prod++;
17884ccba60fSjmatthew 			prod &= mask;
17894ccba60fSjmatthew 		}
17904ccba60fSjmatthew 		cmd |= IAVF_TX_DESC_CMD_EOP | IAVF_TX_DESC_CMD_RS;
17914ccba60fSjmatthew 		htolem64(&txd->cmd, cmd);
17924ccba60fSjmatthew 
17934ccba60fSjmatthew 		txm->txm_m = m;
17944ccba60fSjmatthew 		txm->txm_eop = last;
17954ccba60fSjmatthew 
17964ccba60fSjmatthew #if NBPFILTER > 0
17974ccba60fSjmatthew 		if_bpf = ifp->if_bpf;
17984ccba60fSjmatthew 		if (if_bpf)
17994ccba60fSjmatthew 			bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT);
18004ccba60fSjmatthew #endif
18014ccba60fSjmatthew 
18024ccba60fSjmatthew 		free -= i;
18034ccba60fSjmatthew 		post = 1;
18044ccba60fSjmatthew 	}
18054ccba60fSjmatthew 
18064ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&txr->txr_mem),
18074ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_PREWRITE);
18084ccba60fSjmatthew 
18094ccba60fSjmatthew 	if (post) {
18104ccba60fSjmatthew 		txr->txr_prod = prod;
18114ccba60fSjmatthew 		iavf_wr(sc, txr->txr_tail, prod);
18124ccba60fSjmatthew 	}
18134ccba60fSjmatthew }
18144ccba60fSjmatthew 
18154ccba60fSjmatthew static int
18164ccba60fSjmatthew iavf_txeof(struct iavf_softc *sc, struct ifqueue *ifq)
18174ccba60fSjmatthew {
18184ccba60fSjmatthew 	struct iavf_tx_ring *txr = ifq->ifq_softc;
18194ccba60fSjmatthew 	struct iavf_tx_desc *ring, *txd;
18204ccba60fSjmatthew 	struct iavf_tx_map *txm;
18214ccba60fSjmatthew 	bus_dmamap_t map;
18224ccba60fSjmatthew 	unsigned int cons, prod, last;
18234ccba60fSjmatthew 	unsigned int mask;
18244ccba60fSjmatthew 	uint64_t dtype;
18254ccba60fSjmatthew 	int done = 0;
18264ccba60fSjmatthew 
18274ccba60fSjmatthew 	prod = txr->txr_prod;
18284ccba60fSjmatthew 	cons = txr->txr_cons;
18294ccba60fSjmatthew 
18304ccba60fSjmatthew 	if (cons == prod)
18314ccba60fSjmatthew 		return (0);
18324ccba60fSjmatthew 
18334ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&txr->txr_mem),
18344ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_POSTREAD);
18354ccba60fSjmatthew 
18364ccba60fSjmatthew 	ring = IAVF_DMA_KVA(&txr->txr_mem);
18374ccba60fSjmatthew 	mask = sc->sc_tx_ring_ndescs - 1;
18384ccba60fSjmatthew 
18394ccba60fSjmatthew 	do {
18404ccba60fSjmatthew 		txm = &txr->txr_maps[cons];
18414ccba60fSjmatthew 		last = txm->txm_eop;
18424ccba60fSjmatthew 		txd = &ring[last];
18434ccba60fSjmatthew 
18444ccba60fSjmatthew 		dtype = txd->cmd & htole64(IAVF_TX_DESC_DTYPE_MASK);
18454ccba60fSjmatthew 		if (dtype != htole64(IAVF_TX_DESC_DTYPE_DONE))
18464ccba60fSjmatthew 			break;
18474ccba60fSjmatthew 
18484ccba60fSjmatthew 		map = txm->txm_map;
18494ccba60fSjmatthew 
18504ccba60fSjmatthew 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
18514ccba60fSjmatthew 		    BUS_DMASYNC_POSTWRITE);
18524ccba60fSjmatthew 		bus_dmamap_unload(sc->sc_dmat, map);
18534ccba60fSjmatthew 		m_freem(txm->txm_m);
18544ccba60fSjmatthew 
18554ccba60fSjmatthew 		txm->txm_m = NULL;
18564ccba60fSjmatthew 		txm->txm_eop = -1;
18574ccba60fSjmatthew 
18584ccba60fSjmatthew 		cons = last + 1;
18594ccba60fSjmatthew 		cons &= mask;
18604ccba60fSjmatthew 
18614ccba60fSjmatthew 		done = 1;
18624ccba60fSjmatthew 	} while (cons != prod);
18634ccba60fSjmatthew 
18644ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&txr->txr_mem),
18654ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_PREREAD);
18664ccba60fSjmatthew 
18674ccba60fSjmatthew 	txr->txr_cons = cons;
18684ccba60fSjmatthew 
18694ccba60fSjmatthew 	//ixl_enable(sc, txr->txr_msix);
18704ccba60fSjmatthew 
18714ccba60fSjmatthew 	if (ifq_is_oactive(ifq))
18724ccba60fSjmatthew 		ifq_restart(ifq);
18734ccba60fSjmatthew 
18744ccba60fSjmatthew 	return (done);
18754ccba60fSjmatthew }
18764ccba60fSjmatthew 
18774ccba60fSjmatthew static struct iavf_rx_ring *
18784ccba60fSjmatthew iavf_rxr_alloc(struct iavf_softc *sc, unsigned int qid)
18794ccba60fSjmatthew {
18804ccba60fSjmatthew 	struct iavf_rx_ring *rxr;
18814ccba60fSjmatthew 	struct iavf_rx_map *maps, *rxm;
18824ccba60fSjmatthew 	unsigned int i;
18834ccba60fSjmatthew 
18844ccba60fSjmatthew 	rxr = malloc(sizeof(*rxr), M_DEVBUF, M_WAITOK|M_CANFAIL);
18854ccba60fSjmatthew 	if (rxr == NULL)
18864ccba60fSjmatthew 		return (NULL);
18874ccba60fSjmatthew 
18884ccba60fSjmatthew 	maps = mallocarray(sizeof(*maps),
18894ccba60fSjmatthew 	    sc->sc_rx_ring_ndescs, M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
18904ccba60fSjmatthew 	if (maps == NULL)
18914ccba60fSjmatthew 		goto free;
18924ccba60fSjmatthew 
18934ccba60fSjmatthew 	if (iavf_dmamem_alloc(sc, &rxr->rxr_mem,
18944ccba60fSjmatthew 	    sizeof(struct iavf_rx_rd_desc_32) * sc->sc_rx_ring_ndescs,
18954ccba60fSjmatthew 	    IAVF_RX_QUEUE_ALIGN) != 0)
18964ccba60fSjmatthew 		goto freemap;
18974ccba60fSjmatthew 
18984ccba60fSjmatthew 	for (i = 0; i < sc->sc_rx_ring_ndescs; i++) {
18994ccba60fSjmatthew 		rxm = &maps[i];
19004ccba60fSjmatthew 
19014ccba60fSjmatthew 		if (bus_dmamap_create(sc->sc_dmat,
19024ccba60fSjmatthew 		    IAVF_HARDMTU, 1, IAVF_HARDMTU, 0,
19034ccba60fSjmatthew 		    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
19044ccba60fSjmatthew 		    &rxm->rxm_map) != 0)
19054ccba60fSjmatthew 			goto uncreate;
19064ccba60fSjmatthew 
19074ccba60fSjmatthew 		rxm->rxm_m = NULL;
19084ccba60fSjmatthew 	}
19094ccba60fSjmatthew 
19104ccba60fSjmatthew 	rxr->rxr_sc = sc;
19114ccba60fSjmatthew 	if_rxr_init(&rxr->rxr_acct, 17, sc->sc_rx_ring_ndescs - 1);
19124ccba60fSjmatthew 	timeout_set(&rxr->rxr_refill, iavf_rxrefill, rxr);
19134ccba60fSjmatthew 	rxr->rxr_cons = rxr->rxr_prod = 0;
19144ccba60fSjmatthew 	rxr->rxr_m_head = NULL;
19154ccba60fSjmatthew 	rxr->rxr_m_tail = &rxr->rxr_m_head;
19164ccba60fSjmatthew 	rxr->rxr_maps = maps;
19174ccba60fSjmatthew 
19184ccba60fSjmatthew 	rxr->rxr_tail = I40E_QRX_TAIL1(qid);
19194ccba60fSjmatthew 	rxr->rxr_qid = qid;
19204ccba60fSjmatthew 
19214ccba60fSjmatthew 	return (rxr);
19224ccba60fSjmatthew 
19234ccba60fSjmatthew uncreate:
19244ccba60fSjmatthew 	for (i = 0; i < sc->sc_rx_ring_ndescs; i++) {
19254ccba60fSjmatthew 		rxm = &maps[i];
19264ccba60fSjmatthew 
19274ccba60fSjmatthew 		if (rxm->rxm_map == NULL)
19284ccba60fSjmatthew 			continue;
19294ccba60fSjmatthew 
19304ccba60fSjmatthew 		bus_dmamap_destroy(sc->sc_dmat, rxm->rxm_map);
19314ccba60fSjmatthew 	}
19324ccba60fSjmatthew 
19334ccba60fSjmatthew 	iavf_dmamem_free(sc, &rxr->rxr_mem);
19344ccba60fSjmatthew freemap:
19354ccba60fSjmatthew 	free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_rx_ring_ndescs);
19364ccba60fSjmatthew free:
19374ccba60fSjmatthew 	free(rxr, M_DEVBUF, sizeof(*rxr));
19384ccba60fSjmatthew 	return (NULL);
19394ccba60fSjmatthew }
19404ccba60fSjmatthew 
19414ccba60fSjmatthew static void
19424ccba60fSjmatthew iavf_rxr_clean(struct iavf_softc *sc, struct iavf_rx_ring *rxr)
19434ccba60fSjmatthew {
19444ccba60fSjmatthew 	struct iavf_rx_map *maps, *rxm;
19454ccba60fSjmatthew 	bus_dmamap_t map;
19464ccba60fSjmatthew 	unsigned int i;
19474ccba60fSjmatthew 
19484ccba60fSjmatthew 	timeout_del_barrier(&rxr->rxr_refill);
19494ccba60fSjmatthew 
19504ccba60fSjmatthew 	maps = rxr->rxr_maps;
19514ccba60fSjmatthew 	for (i = 0; i < sc->sc_rx_ring_ndescs; i++) {
19524ccba60fSjmatthew 		rxm = &maps[i];
19534ccba60fSjmatthew 
19544ccba60fSjmatthew 		if (rxm->rxm_m == NULL)
19554ccba60fSjmatthew 			continue;
19564ccba60fSjmatthew 
19574ccba60fSjmatthew 		map = rxm->rxm_map;
19584ccba60fSjmatthew 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
19594ccba60fSjmatthew 		    BUS_DMASYNC_POSTWRITE);
19604ccba60fSjmatthew 		bus_dmamap_unload(sc->sc_dmat, map);
19614ccba60fSjmatthew 
19624ccba60fSjmatthew 		m_freem(rxm->rxm_m);
19634ccba60fSjmatthew 		rxm->rxm_m = NULL;
19644ccba60fSjmatthew 	}
19654ccba60fSjmatthew 
19664ccba60fSjmatthew 	m_freem(rxr->rxr_m_head);
19674ccba60fSjmatthew 	rxr->rxr_m_head = NULL;
19684ccba60fSjmatthew 	rxr->rxr_m_tail = &rxr->rxr_m_head;
19694ccba60fSjmatthew 
19704ccba60fSjmatthew 	rxr->rxr_prod = rxr->rxr_cons = 0;
19714ccba60fSjmatthew }
19724ccba60fSjmatthew 
19734ccba60fSjmatthew static void
19744ccba60fSjmatthew iavf_rxr_free(struct iavf_softc *sc, struct iavf_rx_ring *rxr)
19754ccba60fSjmatthew {
19764ccba60fSjmatthew 	struct iavf_rx_map *maps, *rxm;
19774ccba60fSjmatthew 	unsigned int i;
19784ccba60fSjmatthew 
19794ccba60fSjmatthew 	maps = rxr->rxr_maps;
19804ccba60fSjmatthew 	for (i = 0; i < sc->sc_rx_ring_ndescs; i++) {
19814ccba60fSjmatthew 		rxm = &maps[i];
19824ccba60fSjmatthew 
19834ccba60fSjmatthew 		bus_dmamap_destroy(sc->sc_dmat, rxm->rxm_map);
19844ccba60fSjmatthew 	}
19854ccba60fSjmatthew 
19864ccba60fSjmatthew 	iavf_dmamem_free(sc, &rxr->rxr_mem);
19874ccba60fSjmatthew 	free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_rx_ring_ndescs);
19884ccba60fSjmatthew 	free(rxr, M_DEVBUF, sizeof(*rxr));
19894ccba60fSjmatthew }
19904ccba60fSjmatthew 
1991*51248bbdSyasuoka static void
1992*51248bbdSyasuoka iavf_rx_checksum(struct mbuf *m, uint64_t word)
1993*51248bbdSyasuoka {
1994*51248bbdSyasuoka 	if (!ISSET(word, IAVF_RX_DESC_L3L4P))
1995*51248bbdSyasuoka 		return;
1996*51248bbdSyasuoka 
1997*51248bbdSyasuoka 	if (ISSET(word, IAVF_RX_DESC_IPE))
1998*51248bbdSyasuoka 		return;
1999*51248bbdSyasuoka 
2000*51248bbdSyasuoka 	m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
2001*51248bbdSyasuoka 
2002*51248bbdSyasuoka 	if (ISSET(word, IAVF_RX_DESC_L4E))
2003*51248bbdSyasuoka 		return;
2004*51248bbdSyasuoka 
2005*51248bbdSyasuoka 	m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
2006*51248bbdSyasuoka }
2007*51248bbdSyasuoka 
2008*51248bbdSyasuoka 
20094ccba60fSjmatthew static int
20104ccba60fSjmatthew iavf_rxeof(struct iavf_softc *sc, struct ifiqueue *ifiq)
20114ccba60fSjmatthew {
20124ccba60fSjmatthew 	struct iavf_rx_ring *rxr = ifiq->ifiq_softc;
20134ccba60fSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
20144ccba60fSjmatthew 	struct iavf_rx_wb_desc_32 *ring, *rxd;
20154ccba60fSjmatthew 	struct iavf_rx_map *rxm;
20164ccba60fSjmatthew 	bus_dmamap_t map;
20174ccba60fSjmatthew 	unsigned int cons, prod;
20184ccba60fSjmatthew 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
20194ccba60fSjmatthew 	struct mbuf *m;
20204ccba60fSjmatthew 	uint64_t word;
20213e0b52e8Sjmatthew 	uint16_t vlan;
20224ccba60fSjmatthew 	unsigned int len;
20234ccba60fSjmatthew 	unsigned int mask;
20244ccba60fSjmatthew 	int done = 0;
20254ccba60fSjmatthew 
20264ccba60fSjmatthew 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
20274ccba60fSjmatthew 		return (0);
20284ccba60fSjmatthew 
20294ccba60fSjmatthew 	prod = rxr->rxr_prod;
20304ccba60fSjmatthew 	cons = rxr->rxr_cons;
20314ccba60fSjmatthew 
20324ccba60fSjmatthew 	if (cons == prod)
20334ccba60fSjmatthew 		return (0);
20344ccba60fSjmatthew 
20354ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&rxr->rxr_mem),
20364ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&rxr->rxr_mem),
20374ccba60fSjmatthew 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
20384ccba60fSjmatthew 
20394ccba60fSjmatthew 	ring = IAVF_DMA_KVA(&rxr->rxr_mem);
20404ccba60fSjmatthew 	mask = sc->sc_rx_ring_ndescs - 1;
20414ccba60fSjmatthew 
20424ccba60fSjmatthew 	do {
20434ccba60fSjmatthew 		rxd = &ring[cons];
20444ccba60fSjmatthew 
20454ccba60fSjmatthew 		word = lemtoh64(&rxd->qword1);
20464ccba60fSjmatthew 		if (!ISSET(word, IAVF_RX_DESC_DD))
20474ccba60fSjmatthew 			break;
20484ccba60fSjmatthew 
20494ccba60fSjmatthew 		if_rxr_put(&rxr->rxr_acct, 1);
20504ccba60fSjmatthew 
20514ccba60fSjmatthew 		rxm = &rxr->rxr_maps[cons];
20524ccba60fSjmatthew 
20534ccba60fSjmatthew 		map = rxm->rxm_map;
20544ccba60fSjmatthew 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
20554ccba60fSjmatthew 		    BUS_DMASYNC_POSTREAD);
20564ccba60fSjmatthew 		bus_dmamap_unload(sc->sc_dmat, map);
20574ccba60fSjmatthew 
20584ccba60fSjmatthew 		m = rxm->rxm_m;
20594ccba60fSjmatthew 		rxm->rxm_m = NULL;
20604ccba60fSjmatthew 
20614ccba60fSjmatthew 		len = (word & IAVF_RX_DESC_PLEN_MASK) >> IAVF_RX_DESC_PLEN_SHIFT;
20624ccba60fSjmatthew 		m->m_len = len;
20634ccba60fSjmatthew 		m->m_pkthdr.len = 0;
20644ccba60fSjmatthew 
20654ccba60fSjmatthew 		m->m_next = NULL;
20664ccba60fSjmatthew 		*rxr->rxr_m_tail = m;
20674ccba60fSjmatthew 		rxr->rxr_m_tail = &m->m_next;
20684ccba60fSjmatthew 
20694ccba60fSjmatthew 		m = rxr->rxr_m_head;
20704ccba60fSjmatthew 		m->m_pkthdr.len += len;
20714ccba60fSjmatthew 
20724ccba60fSjmatthew 		if (ISSET(word, IAVF_RX_DESC_EOP)) {
2073*51248bbdSyasuoka #if NVLAN > 0
20743e0b52e8Sjmatthew 			if (ISSET(word, IAVF_RX_DESC_L2TAG1P)) {
20753e0b52e8Sjmatthew 				vlan = (lemtoh64(&rxd->qword0) &
20763e0b52e8Sjmatthew 				    IAVF_RX_DESC_L2TAG1_MASK)
20773e0b52e8Sjmatthew 				    >> IAVF_RX_DESC_L2TAG1_SHIFT;
20783e0b52e8Sjmatthew 				m->m_pkthdr.ether_vtag = vlan;
20793e0b52e8Sjmatthew 				m->m_flags |= M_VLANTAG;
20803e0b52e8Sjmatthew 			}
2081*51248bbdSyasuoka #endif
20824ccba60fSjmatthew 			if (!ISSET(word,
20834ccba60fSjmatthew 			    IAVF_RX_DESC_RXE | IAVF_RX_DESC_OVERSIZE)) {
2084*51248bbdSyasuoka 				iavf_rx_checksum(m, word);
20854ccba60fSjmatthew 				ml_enqueue(&ml, m);
20864ccba60fSjmatthew 			} else {
20874ccba60fSjmatthew 				ifp->if_ierrors++; /* XXX */
20884ccba60fSjmatthew 				m_freem(m);
20894ccba60fSjmatthew 			}
20904ccba60fSjmatthew 
20914ccba60fSjmatthew 			rxr->rxr_m_head = NULL;
20924ccba60fSjmatthew 			rxr->rxr_m_tail = &rxr->rxr_m_head;
20934ccba60fSjmatthew 		}
20944ccba60fSjmatthew 
20954ccba60fSjmatthew 		cons++;
20964ccba60fSjmatthew 		cons &= mask;
20974ccba60fSjmatthew 
20984ccba60fSjmatthew 		done = 1;
20994ccba60fSjmatthew 	} while (cons != prod);
21004ccba60fSjmatthew 
21014ccba60fSjmatthew 	if (done) {
21024ccba60fSjmatthew 		rxr->rxr_cons = cons;
21034ccba60fSjmatthew 		if (ifiq_input(ifiq, &ml))
21044ccba60fSjmatthew 			if_rxr_livelocked(&rxr->rxr_acct);
21054ccba60fSjmatthew 		iavf_rxfill(sc, rxr);
21064ccba60fSjmatthew 	}
21074ccba60fSjmatthew 
21084ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&rxr->rxr_mem),
21094ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&rxr->rxr_mem),
21104ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
21114ccba60fSjmatthew 
21124ccba60fSjmatthew 	return (done);
21134ccba60fSjmatthew }
21144ccba60fSjmatthew 
21154ccba60fSjmatthew static void
21164ccba60fSjmatthew iavf_rxfill(struct iavf_softc *sc, struct iavf_rx_ring *rxr)
21174ccba60fSjmatthew {
21184ccba60fSjmatthew 	struct iavf_rx_rd_desc_32 *ring, *rxd;
21194ccba60fSjmatthew 	struct iavf_rx_map *rxm;
21204ccba60fSjmatthew 	bus_dmamap_t map;
21214ccba60fSjmatthew 	struct mbuf *m;
21224ccba60fSjmatthew 	unsigned int prod;
21234ccba60fSjmatthew 	unsigned int slots;
21244ccba60fSjmatthew 	unsigned int mask;
21254ccba60fSjmatthew 	int post = 0;
21264ccba60fSjmatthew 
21274ccba60fSjmatthew 	slots = if_rxr_get(&rxr->rxr_acct, sc->sc_rx_ring_ndescs);
21284ccba60fSjmatthew 	if (slots == 0)
21294ccba60fSjmatthew 		return;
21304ccba60fSjmatthew 
21314ccba60fSjmatthew 	prod = rxr->rxr_prod;
21324ccba60fSjmatthew 
21334ccba60fSjmatthew 	ring = IAVF_DMA_KVA(&rxr->rxr_mem);
21344ccba60fSjmatthew 	mask = sc->sc_rx_ring_ndescs - 1;
21354ccba60fSjmatthew 
21364ccba60fSjmatthew 	do {
21374ccba60fSjmatthew 		rxm = &rxr->rxr_maps[prod];
21384ccba60fSjmatthew 
2139471f2571Sjan 		m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES + ETHER_ALIGN);
21404ccba60fSjmatthew 		if (m == NULL)
21414ccba60fSjmatthew 			break;
21424ccba60fSjmatthew 		m->m_data += (m->m_ext.ext_size - (MCLBYTES + ETHER_ALIGN));
21434ccba60fSjmatthew 		m->m_len = m->m_pkthdr.len = MCLBYTES + ETHER_ALIGN;
21444ccba60fSjmatthew 
21454ccba60fSjmatthew 		map = rxm->rxm_map;
21464ccba60fSjmatthew 
21474ccba60fSjmatthew 		if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
21484ccba60fSjmatthew 		    BUS_DMA_NOWAIT) != 0) {
21494ccba60fSjmatthew 			m_freem(m);
21504ccba60fSjmatthew 			break;
21514ccba60fSjmatthew 		}
21524ccba60fSjmatthew 
21534ccba60fSjmatthew 		rxm->rxm_m = m;
21544ccba60fSjmatthew 
21554ccba60fSjmatthew 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
21564ccba60fSjmatthew 		    BUS_DMASYNC_PREREAD);
21574ccba60fSjmatthew 
21584ccba60fSjmatthew 		rxd = &ring[prod];
21594ccba60fSjmatthew 
21604ccba60fSjmatthew 		htolem64(&rxd->paddr, map->dm_segs[0].ds_addr);
21614ccba60fSjmatthew 		rxd->haddr = htole64(0);
21624ccba60fSjmatthew 
21634ccba60fSjmatthew 		prod++;
21644ccba60fSjmatthew 		prod &= mask;
21654ccba60fSjmatthew 
21664ccba60fSjmatthew 		post = 1;
21674ccba60fSjmatthew 	} while (--slots);
21684ccba60fSjmatthew 
21694ccba60fSjmatthew 	if_rxr_put(&rxr->rxr_acct, slots);
21704ccba60fSjmatthew 
21714ccba60fSjmatthew 	if (if_rxr_inuse(&rxr->rxr_acct) == 0)
21724ccba60fSjmatthew 		timeout_add(&rxr->rxr_refill, 1);
21734ccba60fSjmatthew 	else if (post) {
21744ccba60fSjmatthew 		rxr->rxr_prod = prod;
21754ccba60fSjmatthew 		iavf_wr(sc, rxr->rxr_tail, prod);
21764ccba60fSjmatthew 	}
21774ccba60fSjmatthew }
21784ccba60fSjmatthew 
21794ccba60fSjmatthew void
21804ccba60fSjmatthew iavf_rxrefill(void *arg)
21814ccba60fSjmatthew {
21824ccba60fSjmatthew 	struct iavf_rx_ring *rxr = arg;
21834ccba60fSjmatthew 	struct iavf_softc *sc = rxr->rxr_sc;
21844ccba60fSjmatthew 
21854ccba60fSjmatthew 	iavf_rxfill(sc, rxr);
21864ccba60fSjmatthew }
21874ccba60fSjmatthew 
21884ccba60fSjmatthew static int
21894ccba60fSjmatthew iavf_rxrinfo(struct iavf_softc *sc, struct if_rxrinfo *ifri)
21904ccba60fSjmatthew {
21914ccba60fSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
21924ccba60fSjmatthew 	struct if_rxring_info *ifr;
21934ccba60fSjmatthew 	struct iavf_rx_ring *ring;
21944ccba60fSjmatthew 	int i, rv;
21954ccba60fSjmatthew 
21964ccba60fSjmatthew 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
21974ccba60fSjmatthew 		return (ENOTTY);
21984ccba60fSjmatthew 
21994ccba60fSjmatthew 	ifr = mallocarray(sizeof(*ifr), iavf_nqueues(sc), M_TEMP,
22004ccba60fSjmatthew 	    M_WAITOK|M_CANFAIL|M_ZERO);
22014ccba60fSjmatthew 	if (ifr == NULL)
22024ccba60fSjmatthew 		return (ENOMEM);
22034ccba60fSjmatthew 
22044ccba60fSjmatthew 	for (i = 0; i < iavf_nqueues(sc); i++) {
22054ccba60fSjmatthew 		ring = ifp->if_iqs[i]->ifiq_softc;
22064ccba60fSjmatthew 		ifr[i].ifr_size = MCLBYTES;
22074ccba60fSjmatthew 		ifr[i].ifr_info = ring->rxr_acct;
22084ccba60fSjmatthew 	}
22094ccba60fSjmatthew 
22104ccba60fSjmatthew 	rv = if_rxr_info_ioctl(ifri, iavf_nqueues(sc), ifr);
22114ccba60fSjmatthew 	free(ifr, M_TEMP, iavf_nqueues(sc) * sizeof(*ifr));
22124ccba60fSjmatthew 
22134ccba60fSjmatthew 	return (rv);
22144ccba60fSjmatthew }
22154ccba60fSjmatthew 
22164ccba60fSjmatthew static int
22174ccba60fSjmatthew iavf_intr(void *xsc)
22184ccba60fSjmatthew {
22194ccba60fSjmatthew 	struct iavf_softc *sc = xsc;
22204ccba60fSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
22214ccba60fSjmatthew 	uint32_t icr, ena;
22224ccba60fSjmatthew 	int i, rv = 0;
22234ccba60fSjmatthew 
22244ccba60fSjmatthew 	ena = iavf_rd(sc, I40E_VFINT_ICR0_ENA1);
22254ccba60fSjmatthew 	iavf_intr_enable(sc);
22264ccba60fSjmatthew 	icr = iavf_rd(sc, I40E_VFINT_ICR01);
22274ccba60fSjmatthew 
22282fa30b92Sjmatthew 	if (icr == IAVF_REG_VFR) {
22292fa30b92Sjmatthew 		printf("%s: VF reset in progress\n", DEVNAME(sc));
22302fa30b92Sjmatthew 		sc->sc_resetting = 1;
22312fa30b92Sjmatthew 		task_add(systq, &sc->sc_reset_task);
22322fa30b92Sjmatthew 		return (1);
22332fa30b92Sjmatthew 	}
22342fa30b92Sjmatthew 
22354ccba60fSjmatthew 	if (ISSET(icr, I40E_VFINT_ICR01_ADMINQ_MASK)) {
22364ccba60fSjmatthew 		iavf_atq_done(sc);
2237e13657b7Sjmatthew 		iavf_process_arq(sc, 0);
22384ccba60fSjmatthew 		rv = 1;
22394ccba60fSjmatthew 	}
22404ccba60fSjmatthew 
22414ccba60fSjmatthew 	if (ISSET(icr, I40E_VFINT_ICR01_QUEUE_0_MASK)) {
22424ccba60fSjmatthew 		for (i = 0; i < iavf_nqueues(sc); i++) {
22434ccba60fSjmatthew 			rv |= iavf_rxeof(sc, ifp->if_iqs[i]);
22444ccba60fSjmatthew 			rv |= iavf_txeof(sc, ifp->if_ifqs[i]);
22454ccba60fSjmatthew 		}
22464ccba60fSjmatthew 	}
22474ccba60fSjmatthew 
22484ccba60fSjmatthew 	return (rv);
22494ccba60fSjmatthew }
22504ccba60fSjmatthew 
22514ccba60fSjmatthew static void
22524ccba60fSjmatthew iavf_process_vf_resources(struct iavf_softc *sc, struct iavf_aq_desc *desc,
22534ccba60fSjmatthew     struct iavf_aq_buf *buf)
22544ccba60fSjmatthew {
22554ccba60fSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
22564ccba60fSjmatthew 	struct iavf_vc_vf_resource *vf_res;
22574ccba60fSjmatthew 	struct iavf_vc_vsi_resource *vsi_res;
22584ccba60fSjmatthew 	int mtu;
22594ccba60fSjmatthew 
22604ccba60fSjmatthew 	sc->sc_got_vf_resources = 1;
22614ccba60fSjmatthew 
22624ccba60fSjmatthew 	vf_res = buf->aqb_data;
22634ccba60fSjmatthew 	if (letoh16(vf_res->num_vsis) == 0) {
22644ccba60fSjmatthew 		printf(", no VSI available\n");
22654ccba60fSjmatthew 		/* set vsi number to something */
22664ccba60fSjmatthew 		return;
22674ccba60fSjmatthew 	}
22684ccba60fSjmatthew 
22694ccba60fSjmatthew 	mtu = letoh16(vf_res->max_mtu);
22704ccba60fSjmatthew 	if (mtu != 0)
22714ccba60fSjmatthew 		ifp->if_hardmtu = MIN(IAVF_HARDMTU, mtu);
22724ccba60fSjmatthew 
22734ccba60fSjmatthew 	/* limit vectors to what we got here? */
22744ccba60fSjmatthew 
22754ccba60fSjmatthew 	/* just take the first vsi */
22764ccba60fSjmatthew 	vsi_res = &vf_res->vsi_res[0];
22774ccba60fSjmatthew 	sc->sc_vsi_id = letoh16(vsi_res->vsi_id);
22784ccba60fSjmatthew 	sc->sc_qset_handle = letoh16(vsi_res->qset_handle);
22794ccba60fSjmatthew 	/* limit number of queues to what we got here */
22804ccba60fSjmatthew 	/* is vsi type interesting? */
22814ccba60fSjmatthew 
22824ccba60fSjmatthew 	sc->sc_vf_id = letoh32(desc->iaq_param[0]);
22834ccba60fSjmatthew 
22844ccba60fSjmatthew 	memcpy(sc->sc_ac.ac_enaddr, vsi_res->default_mac, ETHER_ADDR_LEN);
22852fa30b92Sjmatthew 
22862fa30b92Sjmatthew 	if (sc->sc_resetting == 0)
22874ccba60fSjmatthew 		printf(", VF %d VSI %d", sc->sc_vf_id, sc->sc_vsi_id);
22884ccba60fSjmatthew }
22894ccba60fSjmatthew 
2290baed872eSjmatthew static const struct iavf_link_speed *
2291baed872eSjmatthew iavf_find_link_speed(struct iavf_softc *sc, uint32_t link_speed)
2292baed872eSjmatthew {
2293baed872eSjmatthew 	int i;
2294baed872eSjmatthew 	for (i = 0; i < nitems(iavf_link_speeds); i++) {
2295baed872eSjmatthew 		if (link_speed & (1 << i))
2296baed872eSjmatthew 			return (&iavf_link_speeds[i]);
2297baed872eSjmatthew 	}
2298baed872eSjmatthew 
2299baed872eSjmatthew 	return (NULL);
2300baed872eSjmatthew }
2301baed872eSjmatthew 
23024ccba60fSjmatthew static void
23034ccba60fSjmatthew iavf_process_vc_event(struct iavf_softc *sc, struct iavf_aq_desc *desc,
23044ccba60fSjmatthew     struct iavf_aq_buf *buf)
23054ccba60fSjmatthew {
23064ccba60fSjmatthew 	struct iavf_vc_pf_event *event;
2307baed872eSjmatthew 	struct ifnet *ifp = &sc->sc_ac.ac_if;
2308baed872eSjmatthew 	const struct iavf_link_speed *speed;
2309baed872eSjmatthew 	int link;
23104ccba60fSjmatthew 
23114ccba60fSjmatthew 	event = buf->aqb_data;
23124ccba60fSjmatthew 	switch (event->event) {
23134ccba60fSjmatthew 	case IAVF_VC_EVENT_LINK_CHANGE:
2314baed872eSjmatthew 		sc->sc_media_status = IFM_AVALID;
2315baed872eSjmatthew 		sc->sc_media_active = IFM_ETHER;
2316baed872eSjmatthew 		link = LINK_STATE_DOWN;
2317baed872eSjmatthew 		if (event->link_status) {
2318baed872eSjmatthew 			link = LINK_STATE_UP;
2319baed872eSjmatthew 			sc->sc_media_status |= IFM_ACTIVE;
2320baed872eSjmatthew 
2321baed872eSjmatthew 			ifp->if_baudrate = 0;
2322baed872eSjmatthew 			speed = iavf_find_link_speed(sc, event->link_speed);
2323baed872eSjmatthew 			if (speed != NULL) {
2324baed872eSjmatthew 				sc->sc_media_active |= speed->media;
2325baed872eSjmatthew 				ifp->if_baudrate = speed->baudrate;
2326baed872eSjmatthew 			}
2327baed872eSjmatthew 		}
2328baed872eSjmatthew 
2329baed872eSjmatthew 		if (ifp->if_link_state != link) {
2330baed872eSjmatthew 			ifp->if_link_state = link;
2331baed872eSjmatthew 			if_link_state_change(ifp);
2332baed872eSjmatthew 		}
23334ccba60fSjmatthew 		break;
23344ccba60fSjmatthew 
23354ccba60fSjmatthew 	default:
23364ccba60fSjmatthew 		break;
23374ccba60fSjmatthew 	}
23384ccba60fSjmatthew }
23394ccba60fSjmatthew 
23404ccba60fSjmatthew static void
23414ccba60fSjmatthew iavf_process_irq_map(struct iavf_softc *sc, struct iavf_aq_desc *desc)
23424ccba60fSjmatthew {
23434ccba60fSjmatthew 	if (letoh32(desc->iaq_vc_retval) != IAVF_VC_RC_SUCCESS) {
23444ccba60fSjmatthew 		printf("config irq map failed: %d\n", letoh32(desc->iaq_vc_retval));
23454ccba60fSjmatthew 	}
23464ccba60fSjmatthew 	sc->sc_got_irq_map = 1;
23474ccba60fSjmatthew }
23484ccba60fSjmatthew 
23492fa30b92Sjmatthew static void
23502fa30b92Sjmatthew iavf_init_admin_queue(struct iavf_softc *sc)
23512fa30b92Sjmatthew {
23522fa30b92Sjmatthew 	iavf_wr(sc, sc->sc_aq_regs->atq_head, 0);
23532fa30b92Sjmatthew 	iavf_wr(sc, sc->sc_aq_regs->arq_head, 0);
23542fa30b92Sjmatthew 	iavf_wr(sc, sc->sc_aq_regs->atq_tail, 0);
23552fa30b92Sjmatthew 
23562fa30b92Sjmatthew 	iavf_barrier(sc, 0, sc->sc_mems, BUS_SPACE_BARRIER_WRITE);
23572fa30b92Sjmatthew 
23582fa30b92Sjmatthew 	iavf_wr(sc, sc->sc_aq_regs->atq_bal,
23592fa30b92Sjmatthew 	    iavf_dmamem_lo(&sc->sc_atq));
23602fa30b92Sjmatthew 	iavf_wr(sc, sc->sc_aq_regs->atq_bah,
23612fa30b92Sjmatthew 	    iavf_dmamem_hi(&sc->sc_atq));
23622fa30b92Sjmatthew 	iavf_wr(sc, sc->sc_aq_regs->atq_len,
23632fa30b92Sjmatthew 	    sc->sc_aq_regs->atq_len_enable | IAVF_AQ_NUM);
23642fa30b92Sjmatthew 
23652fa30b92Sjmatthew 	iavf_wr(sc, sc->sc_aq_regs->arq_bal,
23662fa30b92Sjmatthew 	    iavf_dmamem_lo(&sc->sc_arq));
23672fa30b92Sjmatthew 	iavf_wr(sc, sc->sc_aq_regs->arq_bah,
23682fa30b92Sjmatthew 	    iavf_dmamem_hi(&sc->sc_arq));
23692fa30b92Sjmatthew 	iavf_wr(sc, sc->sc_aq_regs->arq_len,
23702fa30b92Sjmatthew 	    sc->sc_aq_regs->arq_len_enable | IAVF_AQ_NUM);
23712fa30b92Sjmatthew 
23722fa30b92Sjmatthew 	iavf_wr(sc, sc->sc_aq_regs->arq_tail, sc->sc_arq_prod);
23732fa30b92Sjmatthew }
23742fa30b92Sjmatthew 
23754ccba60fSjmatthew static int
2376e13657b7Sjmatthew iavf_process_arq(struct iavf_softc *sc, int fill)
23774ccba60fSjmatthew {
23784ccba60fSjmatthew 	struct iavf_aq_desc *arq, *iaq;
23794ccba60fSjmatthew 	struct iavf_aq_buf *aqb;
23804ccba60fSjmatthew 	struct iavf_vc_version_info *ver;
23814ccba60fSjmatthew 	unsigned int cons = sc->sc_arq_cons;
23824ccba60fSjmatthew 	unsigned int prod;
23834ccba60fSjmatthew 	int done = 0;
23844ccba60fSjmatthew 
23854ccba60fSjmatthew 	prod = iavf_rd(sc, sc->sc_aq_regs->arq_head) &
23864ccba60fSjmatthew 	    sc->sc_aq_regs->arq_head_mask;
23874ccba60fSjmatthew 
23884ccba60fSjmatthew 	if (cons == prod)
23894ccba60fSjmatthew 		return (0);
23904ccba60fSjmatthew 
23914ccba60fSjmatthew 	arq = IAVF_DMA_KVA(&sc->sc_arq);
23924ccba60fSjmatthew 
23934ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_arq),
23944ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&sc->sc_arq),
23954ccba60fSjmatthew 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
23964ccba60fSjmatthew 
23974ccba60fSjmatthew 	do {
23984ccba60fSjmatthew 		iaq = &arq[cons];
23994ccba60fSjmatthew 
24004ccba60fSjmatthew 		aqb = SIMPLEQ_FIRST(&sc->sc_arq_live);
24014ccba60fSjmatthew 		SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_live, aqb_entry);
24024ccba60fSjmatthew 		bus_dmamap_sync(sc->sc_dmat, aqb->aqb_map, 0, IAVF_AQ_BUFLEN,
24034ccba60fSjmatthew 		    BUS_DMASYNC_POSTREAD);
24044ccba60fSjmatthew 
24054ccba60fSjmatthew 		switch (letoh32(iaq->iaq_vc_opcode)) {
24064ccba60fSjmatthew 		case IAVF_VC_OP_VERSION:
24074ccba60fSjmatthew 			ver = aqb->aqb_data;
24084ccba60fSjmatthew 			sc->sc_major_ver = letoh32(ver->major);
24094ccba60fSjmatthew 			sc->sc_minor_ver = letoh32(ver->minor);
24104ccba60fSjmatthew 			break;
24114ccba60fSjmatthew 
24124ccba60fSjmatthew 		case IAVF_VC_OP_GET_VF_RESOURCES:
24134ccba60fSjmatthew 			iavf_process_vf_resources(sc, iaq, aqb);
24144ccba60fSjmatthew 			break;
24154ccba60fSjmatthew 
24164ccba60fSjmatthew 		case IAVF_VC_OP_EVENT:
24174ccba60fSjmatthew 			iavf_process_vc_event(sc, iaq, aqb);
24184ccba60fSjmatthew 			break;
24194ccba60fSjmatthew 
24204ccba60fSjmatthew 		case IAVF_VC_OP_CONFIG_IRQ_MAP:
24214ccba60fSjmatthew 			iavf_process_irq_map(sc, iaq);
24224ccba60fSjmatthew 			break;
24234ccba60fSjmatthew 
24244ccba60fSjmatthew 		case IAVF_VC_OP_CONFIG_TX_QUEUE:
24254ccba60fSjmatthew 		case IAVF_VC_OP_CONFIG_RX_QUEUE:
24264ccba60fSjmatthew 		case IAVF_VC_OP_CONFIG_VSI_QUEUES:
24274ccba60fSjmatthew 		case IAVF_VC_OP_ENABLE_QUEUES:
24284ccba60fSjmatthew 		case IAVF_VC_OP_DISABLE_QUEUES:
24294ccba60fSjmatthew 		case IAVF_VC_OP_GET_RSS_HENA_CAPS:
24304ccba60fSjmatthew 		case IAVF_VC_OP_SET_RSS_HENA:
24314ccba60fSjmatthew 		case IAVF_VC_OP_ADD_ETH_ADDR:
24324ccba60fSjmatthew 		case IAVF_VC_OP_DEL_ETH_ADDR:
24334ccba60fSjmatthew 		case IAVF_VC_OP_CONFIG_PROMISC:
24344ccba60fSjmatthew 			sc->sc_admin_result = letoh32(iaq->iaq_vc_retval);
24354ccba60fSjmatthew 			cond_signal(&sc->sc_admin_cond);
24364ccba60fSjmatthew 			break;
24374ccba60fSjmatthew 		}
24384ccba60fSjmatthew 
24394ccba60fSjmatthew 		memset(iaq, 0, sizeof(*iaq));
24404ccba60fSjmatthew 		SIMPLEQ_INSERT_TAIL(&sc->sc_arq_idle, aqb, aqb_entry);
24414ccba60fSjmatthew 		if_rxr_put(&sc->sc_arq_ring, 1);
24424ccba60fSjmatthew 
24434ccba60fSjmatthew 		cons++;
24444ccba60fSjmatthew 		cons &= IAVF_AQ_MASK;
24454ccba60fSjmatthew 
24464ccba60fSjmatthew 		done = 1;
24474ccba60fSjmatthew 	} while (cons != prod);
24484ccba60fSjmatthew 
2449e13657b7Sjmatthew 	if (fill)
2450e13657b7Sjmatthew 		iavf_arq_fill(sc, 1);
24514ccba60fSjmatthew 
24524ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_arq),
24534ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&sc->sc_arq),
24544ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
24554ccba60fSjmatthew 
24564ccba60fSjmatthew 	sc->sc_arq_cons = cons;
24574ccba60fSjmatthew 	return (done);
24584ccba60fSjmatthew }
24594ccba60fSjmatthew 
24604ccba60fSjmatthew static void
24614ccba60fSjmatthew iavf_atq_done(struct iavf_softc *sc)
24624ccba60fSjmatthew {
24634ccba60fSjmatthew 	struct iavf_aq_desc *atq, *slot;
24644ccba60fSjmatthew 	unsigned int cons;
24654ccba60fSjmatthew 	unsigned int prod;
24664ccba60fSjmatthew 
2467bd6a7abaSjmatthew 	mtx_enter(&sc->sc_atq_mtx);
2468bd6a7abaSjmatthew 
24694ccba60fSjmatthew 	prod = sc->sc_atq_prod;
24704ccba60fSjmatthew 	cons = sc->sc_atq_cons;
24714ccba60fSjmatthew 
2472bd6a7abaSjmatthew 	if (prod == cons) {
2473bd6a7abaSjmatthew 		mtx_leave(&sc->sc_atq_mtx);
24744ccba60fSjmatthew 		return;
2475bd6a7abaSjmatthew 	}
24764ccba60fSjmatthew 
24774ccba60fSjmatthew 	atq = IAVF_DMA_KVA(&sc->sc_atq);
24784ccba60fSjmatthew 
24794ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq),
24804ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&sc->sc_atq),
24814ccba60fSjmatthew 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
24824ccba60fSjmatthew 
24834ccba60fSjmatthew 	do {
24844ccba60fSjmatthew 		slot = &atq[cons];
24854ccba60fSjmatthew 		if (!ISSET(slot->iaq_flags, htole16(IAVF_AQ_DD)))
24864ccba60fSjmatthew 			break;
24874ccba60fSjmatthew 
24884ccba60fSjmatthew 		memset(slot, 0, sizeof(*slot));
24894ccba60fSjmatthew 
24904ccba60fSjmatthew 		cons++;
24914ccba60fSjmatthew 		cons &= IAVF_AQ_MASK;
24924ccba60fSjmatthew 	} while (cons != prod);
24934ccba60fSjmatthew 
24944ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq),
24954ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&sc->sc_atq),
24964ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
24974ccba60fSjmatthew 
24984ccba60fSjmatthew 	sc->sc_atq_cons = cons;
2499bd6a7abaSjmatthew 
2500bd6a7abaSjmatthew 	mtx_leave(&sc->sc_atq_mtx);
25014ccba60fSjmatthew }
25024ccba60fSjmatthew 
25034ccba60fSjmatthew static int
25044ccba60fSjmatthew iavf_atq_post(struct iavf_softc *sc, struct iavf_aq_desc *iaq)
25054ccba60fSjmatthew {
25064ccba60fSjmatthew 	struct iavf_aq_desc *atq, *slot;
25074ccba60fSjmatthew 	unsigned int prod;
25084ccba60fSjmatthew 
2509bd6a7abaSjmatthew 	mtx_enter(&sc->sc_atq_mtx);
2510bd6a7abaSjmatthew 
25114ccba60fSjmatthew 	atq = IAVF_DMA_KVA(&sc->sc_atq);
25124ccba60fSjmatthew 	prod = sc->sc_atq_prod;
25134ccba60fSjmatthew 	slot = atq + prod;
25144ccba60fSjmatthew 
25154ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq),
25164ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&sc->sc_atq), BUS_DMASYNC_POSTWRITE);
25174ccba60fSjmatthew 
25184ccba60fSjmatthew 	*slot = *iaq;
25194ccba60fSjmatthew 	slot->iaq_flags |= htole16(IAVF_AQ_SI);
25204ccba60fSjmatthew 
25214ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq),
25224ccba60fSjmatthew 	    0, IAVF_DMA_LEN(&sc->sc_atq), BUS_DMASYNC_PREWRITE);
25234ccba60fSjmatthew 
25244ccba60fSjmatthew 	prod++;
25254ccba60fSjmatthew 	prod &= IAVF_AQ_MASK;
25264ccba60fSjmatthew 	sc->sc_atq_prod = prod;
25274ccba60fSjmatthew 	iavf_wr(sc, sc->sc_aq_regs->atq_tail, prod);
2528bd6a7abaSjmatthew 
2529bd6a7abaSjmatthew 	mtx_leave(&sc->sc_atq_mtx);
2530bd6a7abaSjmatthew 
25314ccba60fSjmatthew 	return (prod);
25324ccba60fSjmatthew }
25334ccba60fSjmatthew 
25344ccba60fSjmatthew static int
25354ccba60fSjmatthew iavf_get_version(struct iavf_softc *sc)
25364ccba60fSjmatthew {
25374ccba60fSjmatthew 	struct iavf_aq_desc iaq;
25384ccba60fSjmatthew 	struct iavf_vc_version_info *ver;
25394ccba60fSjmatthew 	int tries;
25404ccba60fSjmatthew 
25414ccba60fSjmatthew 	memset(&iaq, 0, sizeof(iaq));
25424ccba60fSjmatthew 	iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD);
25434ccba60fSjmatthew 	iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF);
25444ccba60fSjmatthew 	iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_VERSION);
25454ccba60fSjmatthew 	iaq.iaq_datalen = htole16(sizeof(struct iavf_vc_version_info));
25464ccba60fSjmatthew 	iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch));
25474ccba60fSjmatthew 
25484ccba60fSjmatthew 	ver = IAVF_DMA_KVA(&sc->sc_scratch);
25494ccba60fSjmatthew 	ver->major = htole32(IAVF_VF_MAJOR);
25504ccba60fSjmatthew 	ver->minor = htole32(IAVF_VF_MINOR);
25514ccba60fSjmatthew 	sc->sc_major_ver = UINT_MAX;
25524ccba60fSjmatthew 	sc->sc_minor_ver = UINT_MAX;
25534ccba60fSjmatthew 
25544ccba60fSjmatthew 	membar_sync();
25554ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0, IAVF_DMA_LEN(&sc->sc_scratch),
25564ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD);
25574ccba60fSjmatthew 
25584ccba60fSjmatthew 	iavf_atq_post(sc, &iaq);
25594ccba60fSjmatthew 
25604ccba60fSjmatthew 	for (tries = 0; tries < 100; tries++) {
2561e13657b7Sjmatthew 		iavf_process_arq(sc, 1);
25624ccba60fSjmatthew 		if (sc->sc_major_ver != -1)
25634ccba60fSjmatthew 			break;
25644ccba60fSjmatthew 
25654ccba60fSjmatthew 		delaymsec(1);
25664ccba60fSjmatthew 	}
25674ccba60fSjmatthew 	if (tries == 100) {
25684ccba60fSjmatthew 		printf(", timeout waiting for VF version");
25694ccba60fSjmatthew 		return (1);
25704ccba60fSjmatthew 	}
25714ccba60fSjmatthew 
25724ccba60fSjmatthew 	if (sc->sc_major_ver != IAVF_VF_MAJOR) {
25734ccba60fSjmatthew 		printf(", unsupported VF version %d", sc->sc_major_ver);
25744ccba60fSjmatthew 		return (1);
25754ccba60fSjmatthew 	}
25764ccba60fSjmatthew 
25772fa30b92Sjmatthew 	if (sc->sc_resetting == 0) {
25782fa30b92Sjmatthew 		printf(", VF version %d.%d%s", sc->sc_major_ver,
25792fa30b92Sjmatthew 		    sc->sc_minor_ver,
25804ccba60fSjmatthew 		    (sc->sc_minor_ver > IAVF_VF_MINOR) ? " (minor mismatch)" : "");
25812fa30b92Sjmatthew 	}
25824ccba60fSjmatthew 
25834ccba60fSjmatthew 	return (0);
25844ccba60fSjmatthew }
25854ccba60fSjmatthew 
25864ccba60fSjmatthew static int
25874ccba60fSjmatthew iavf_get_vf_resources(struct iavf_softc *sc)
25884ccba60fSjmatthew {
25894ccba60fSjmatthew 	struct iavf_aq_desc iaq;
25904ccba60fSjmatthew 	uint32_t *cap;
25914ccba60fSjmatthew 	int tries;
25924ccba60fSjmatthew 
25934ccba60fSjmatthew 	memset(&iaq, 0, sizeof(iaq));
25944ccba60fSjmatthew 	iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD);
25954ccba60fSjmatthew 	iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF);
25964ccba60fSjmatthew 	iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_GET_VF_RESOURCES);
25974ccba60fSjmatthew 	iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch));
25984ccba60fSjmatthew 
25994ccba60fSjmatthew 	if (sc->sc_minor_ver > 0) {
26004ccba60fSjmatthew 		iaq.iaq_datalen = htole16(sizeof(uint32_t));
26014ccba60fSjmatthew 		cap = IAVF_DMA_KVA(&sc->sc_scratch);
26024ccba60fSjmatthew 		*cap = htole32(IAVF_VC_OFFLOAD_L2 | IAVF_VC_OFFLOAD_VLAN |
26034ccba60fSjmatthew 		    IAVF_VC_OFFLOAD_RSS_PF);
26044ccba60fSjmatthew 	}
26054ccba60fSjmatthew 
26064ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0, IAVF_DMA_LEN(&sc->sc_scratch),
26074ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD);
26084ccba60fSjmatthew 
26094ccba60fSjmatthew 	sc->sc_got_vf_resources = 0;
26104ccba60fSjmatthew 	iavf_atq_post(sc, &iaq);
26114ccba60fSjmatthew 
26124ccba60fSjmatthew 	for (tries = 0; tries < 100; tries++) {
2613e13657b7Sjmatthew 		iavf_process_arq(sc, 1);
26144ccba60fSjmatthew 		if (sc->sc_got_vf_resources != 0)
2615e13657b7Sjmatthew 			return (0);
26164ccba60fSjmatthew 
26174ccba60fSjmatthew 		delaymsec(1);
26184ccba60fSjmatthew 	}
26194ccba60fSjmatthew 
2620e13657b7Sjmatthew 	return (1);
26214ccba60fSjmatthew }
26224ccba60fSjmatthew 
26234ccba60fSjmatthew static int
26244ccba60fSjmatthew iavf_config_irq_map(struct iavf_softc *sc)
26254ccba60fSjmatthew {
26264ccba60fSjmatthew 	struct iavf_aq_desc iaq;
26274ccba60fSjmatthew 	struct iavf_vc_vector_map *vec;
26284ccba60fSjmatthew 	struct iavf_vc_irq_map_info *map;
26294ccba60fSjmatthew 	int tries;
26304ccba60fSjmatthew 
26314ccba60fSjmatthew 	memset(&iaq, 0, sizeof(iaq));
26324ccba60fSjmatthew 	iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD);
26334ccba60fSjmatthew 	iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF);
26344ccba60fSjmatthew 	iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_CONFIG_IRQ_MAP);
26354ccba60fSjmatthew 	iaq.iaq_datalen = htole16(sizeof(*map) + sizeof(*vec));
26364ccba60fSjmatthew 	iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch));
26374ccba60fSjmatthew 
26384ccba60fSjmatthew 	map = IAVF_DMA_KVA(&sc->sc_scratch);
26392c4469d1Sjmatthew 	map->num_vectors = htole16(1);
26404ccba60fSjmatthew 
26414ccba60fSjmatthew 	vec = map->vecmap;
26422c4469d1Sjmatthew 	vec[0].vsi_id = htole16(sc->sc_vsi_id);
26434ccba60fSjmatthew 	vec[0].vector_id = 0;
26442c4469d1Sjmatthew 	vec[0].rxq_map = htole16(iavf_allqueues(sc));
26452c4469d1Sjmatthew 	vec[0].txq_map = htole16(iavf_allqueues(sc));
26462c4469d1Sjmatthew 	vec[0].rxitr_idx = htole16(IAVF_NOITR);
26472c4469d1Sjmatthew 	vec[0].txitr_idx = htole16(IAVF_NOITR);
26484ccba60fSjmatthew 
26494ccba60fSjmatthew 	bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0, IAVF_DMA_LEN(&sc->sc_scratch),
26504ccba60fSjmatthew 	    BUS_DMASYNC_PREREAD);
26514ccba60fSjmatthew 
26524ccba60fSjmatthew 	sc->sc_got_irq_map = 0;
26534ccba60fSjmatthew 	iavf_atq_post(sc, &iaq);
26544ccba60fSjmatthew 
26554ccba60fSjmatthew 	for (tries = 0; tries < 100; tries++) {
2656e13657b7Sjmatthew 		iavf_process_arq(sc, 1);
26574ccba60fSjmatthew 		if (sc->sc_got_irq_map != 0)
2658e13657b7Sjmatthew 			return (0);
26594ccba60fSjmatthew 
26604ccba60fSjmatthew 		delaymsec(1);
26614ccba60fSjmatthew 	}
26624ccba60fSjmatthew 
2663e13657b7Sjmatthew 	return (1);
26644ccba60fSjmatthew }
26654ccba60fSjmatthew 
26664ccba60fSjmatthew static struct iavf_aq_buf *
26674ccba60fSjmatthew iavf_aqb_alloc(struct iavf_softc *sc)
26684ccba60fSjmatthew {
26694ccba60fSjmatthew 	struct iavf_aq_buf *aqb;
26704ccba60fSjmatthew 
26714ccba60fSjmatthew 	aqb = malloc(sizeof(*aqb), M_DEVBUF, M_WAITOK);
26724ccba60fSjmatthew 	if (aqb == NULL)
26734ccba60fSjmatthew 		return (NULL);
26744ccba60fSjmatthew 
26754ccba60fSjmatthew 	aqb->aqb_data = dma_alloc(IAVF_AQ_BUFLEN, PR_WAITOK);
26764ccba60fSjmatthew 	if (aqb->aqb_data == NULL)
26774ccba60fSjmatthew 		goto free;
26784ccba60fSjmatthew 
26794ccba60fSjmatthew 	if (bus_dmamap_create(sc->sc_dmat, IAVF_AQ_BUFLEN, 1,
26804ccba60fSjmatthew 	    IAVF_AQ_BUFLEN, 0,
26814ccba60fSjmatthew 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
26824ccba60fSjmatthew 	    &aqb->aqb_map) != 0)
26834ccba60fSjmatthew 		goto dma_free;
26844ccba60fSjmatthew 
26854ccba60fSjmatthew 	if (bus_dmamap_load(sc->sc_dmat, aqb->aqb_map, aqb->aqb_data,
26864ccba60fSjmatthew 	    IAVF_AQ_BUFLEN, NULL, BUS_DMA_WAITOK) != 0)
26874ccba60fSjmatthew 		goto destroy;
26884ccba60fSjmatthew 
26894ccba60fSjmatthew 	return (aqb);
26904ccba60fSjmatthew 
26914ccba60fSjmatthew destroy:
26924ccba60fSjmatthew 	bus_dmamap_destroy(sc->sc_dmat, aqb->aqb_map);
26934ccba60fSjmatthew dma_free:
26944ccba60fSjmatthew 	dma_free(aqb->aqb_data, IAVF_AQ_BUFLEN);
26954ccba60fSjmatthew free:
26964ccba60fSjmatthew 	free(aqb, M_DEVBUF, sizeof(*aqb));
26974ccba60fSjmatthew 
26984ccba60fSjmatthew 	return (NULL);
26994ccba60fSjmatthew }
27004ccba60fSjmatthew 
27014ccba60fSjmatthew static void
27024ccba60fSjmatthew iavf_aqb_free(struct iavf_softc *sc, struct iavf_aq_buf *aqb)
27034ccba60fSjmatthew {
27044ccba60fSjmatthew 	bus_dmamap_unload(sc->sc_dmat, aqb->aqb_map);
27054ccba60fSjmatthew 	bus_dmamap_destroy(sc->sc_dmat, aqb->aqb_map);
27064ccba60fSjmatthew 	dma_free(aqb->aqb_data, IAVF_AQ_BUFLEN);
27074ccba60fSjmatthew 	free(aqb, M_DEVBUF, sizeof(*aqb));
27084ccba60fSjmatthew }
27094ccba60fSjmatthew 
27104ccba60fSjmatthew static int
2711e13657b7Sjmatthew iavf_arq_fill(struct iavf_softc *sc, int post)
27124ccba60fSjmatthew {
27134ccba60fSjmatthew 	struct iavf_aq_buf *aqb;
27144ccba60fSjmatthew 	struct iavf_aq_desc *arq, *iaq;
27154ccba60fSjmatthew 	unsigned int prod = sc->sc_arq_prod;
27164ccba60fSjmatthew 	unsigned int n;
2717e13657b7Sjmatthew 	int filled = 0;
27184ccba60fSjmatthew 
27194ccba60fSjmatthew 	n = if_rxr_get(&sc->sc_arq_ring, IAVF_AQ_NUM);
27204ccba60fSjmatthew 	arq = IAVF_DMA_KVA(&sc->sc_arq);
27214ccba60fSjmatthew 
27224ccba60fSjmatthew 	while (n > 0) {
27234ccba60fSjmatthew 		aqb = SIMPLEQ_FIRST(&sc->sc_arq_idle);
27244ccba60fSjmatthew 		if (aqb != NULL)
27254ccba60fSjmatthew 			SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_idle, aqb_entry);
27264ccba60fSjmatthew 		else if ((aqb = iavf_aqb_alloc(sc)) == NULL)
27274ccba60fSjmatthew 			break;
27284ccba60fSjmatthew 
27294ccba60fSjmatthew 		memset(aqb->aqb_data, 0, IAVF_AQ_BUFLEN);
27304ccba60fSjmatthew 
27314ccba60fSjmatthew 		bus_dmamap_sync(sc->sc_dmat, aqb->aqb_map, 0, IAVF_AQ_BUFLEN,
27324ccba60fSjmatthew 		    BUS_DMASYNC_PREREAD);
27334ccba60fSjmatthew 
27344ccba60fSjmatthew 		iaq = &arq[prod];
27354ccba60fSjmatthew 		iaq->iaq_flags = htole16(IAVF_AQ_BUF |
27364ccba60fSjmatthew 		    (IAVF_AQ_BUFLEN > I40E_AQ_LARGE_BUF ? IAVF_AQ_LB : 0));
27374ccba60fSjmatthew 		iaq->iaq_opcode = 0;
27384ccba60fSjmatthew 		iaq->iaq_datalen = htole16(IAVF_AQ_BUFLEN);
27394ccba60fSjmatthew 		iaq->iaq_retval = 0;
27404ccba60fSjmatthew 		iaq->iaq_vc_opcode = 0;
27414ccba60fSjmatthew 		iaq->iaq_vc_retval = 0;
27424ccba60fSjmatthew 		iaq->iaq_param[0] = 0;
27434ccba60fSjmatthew 		iaq->iaq_param[1] = 0;
27444ccba60fSjmatthew 		iavf_aq_dva(iaq, aqb->aqb_map->dm_segs[0].ds_addr);
27454ccba60fSjmatthew 
27464ccba60fSjmatthew 		SIMPLEQ_INSERT_TAIL(&sc->sc_arq_live, aqb, aqb_entry);
27474ccba60fSjmatthew 
27484ccba60fSjmatthew 		prod++;
27494ccba60fSjmatthew 		prod &= IAVF_AQ_MASK;
27504ccba60fSjmatthew 
2751e13657b7Sjmatthew 		filled = 1;
27524ccba60fSjmatthew 
27534ccba60fSjmatthew 		n--;
27544ccba60fSjmatthew 	}
27554ccba60fSjmatthew 
27564ccba60fSjmatthew 	if_rxr_put(&sc->sc_arq_ring, n);
27574ccba60fSjmatthew 	sc->sc_arq_prod = prod;
27584ccba60fSjmatthew 
2759e13657b7Sjmatthew 	if (filled && post)
2760e13657b7Sjmatthew 		iavf_wr(sc, sc->sc_aq_regs->arq_tail, sc->sc_arq_prod);
2761e13657b7Sjmatthew 
2762e13657b7Sjmatthew 	return (filled);
27634ccba60fSjmatthew }
27644ccba60fSjmatthew 
27654ccba60fSjmatthew static void
27664ccba60fSjmatthew iavf_arq_unfill(struct iavf_softc *sc)
27674ccba60fSjmatthew {
27684ccba60fSjmatthew 	struct iavf_aq_buf *aqb;
27694ccba60fSjmatthew 
27704ccba60fSjmatthew 	while ((aqb = SIMPLEQ_FIRST(&sc->sc_arq_live)) != NULL) {
27714ccba60fSjmatthew 		SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_live, aqb_entry);
27724ccba60fSjmatthew 
27734ccba60fSjmatthew 		bus_dmamap_sync(sc->sc_dmat, aqb->aqb_map, 0, IAVF_AQ_BUFLEN,
27744ccba60fSjmatthew 		    BUS_DMASYNC_POSTREAD);
27754ccba60fSjmatthew 		iavf_aqb_free(sc, aqb);
2776e13657b7Sjmatthew 		if_rxr_put(&sc->sc_arq_ring, 1);
27774ccba60fSjmatthew 	}
27784ccba60fSjmatthew }
27794ccba60fSjmatthew 
27804ccba60fSjmatthew static void
27814ccba60fSjmatthew iavf_arq_timeout(void *xsc)
27824ccba60fSjmatthew {
27834ccba60fSjmatthew 	struct iavf_softc *sc = xsc;
27844ccba60fSjmatthew 
27854ccba60fSjmatthew 	sc->sc_admin_result = -1;
27864ccba60fSjmatthew 	cond_signal(&sc->sc_admin_cond);
27874ccba60fSjmatthew }
27884ccba60fSjmatthew 
27894ccba60fSjmatthew static int
27904ccba60fSjmatthew iavf_arq_wait(struct iavf_softc *sc, int msec)
27914ccba60fSjmatthew {
27924ccba60fSjmatthew 	cond_init(&sc->sc_admin_cond);
27934ccba60fSjmatthew 
27944ccba60fSjmatthew 	timeout_add_msec(&sc->sc_admin_timeout, msec);
27954ccba60fSjmatthew 
27964ccba60fSjmatthew 	cond_wait(&sc->sc_admin_cond, "iavfarq");
27971f28ec92Sjmatthew 	timeout_del(&sc->sc_admin_timeout);
27981f28ec92Sjmatthew 
2799e13657b7Sjmatthew 	iavf_arq_fill(sc, 1);
28004ccba60fSjmatthew 	return sc->sc_admin_result;
28014ccba60fSjmatthew }
28024ccba60fSjmatthew 
28034ccba60fSjmatthew static int
28044ccba60fSjmatthew iavf_dmamem_alloc(struct iavf_softc *sc, struct iavf_dmamem *ixm,
28054ccba60fSjmatthew     bus_size_t size, u_int align)
28064ccba60fSjmatthew {
28074ccba60fSjmatthew 	ixm->ixm_size = size;
28084ccba60fSjmatthew 
28094ccba60fSjmatthew 	if (bus_dmamap_create(sc->sc_dmat, ixm->ixm_size, 1,
28104ccba60fSjmatthew 	    ixm->ixm_size, 0,
28114ccba60fSjmatthew 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
28124ccba60fSjmatthew 	    &ixm->ixm_map) != 0)
28134ccba60fSjmatthew 		return (1);
28144ccba60fSjmatthew 	if (bus_dmamem_alloc(sc->sc_dmat, ixm->ixm_size,
28154ccba60fSjmatthew 	    align, 0, &ixm->ixm_seg, 1, &ixm->ixm_nsegs,
28164ccba60fSjmatthew 	    BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
28174ccba60fSjmatthew 		goto destroy;
28184ccba60fSjmatthew 	if (bus_dmamem_map(sc->sc_dmat, &ixm->ixm_seg, ixm->ixm_nsegs,
28194ccba60fSjmatthew 	    ixm->ixm_size, &ixm->ixm_kva, BUS_DMA_WAITOK) != 0)
28204ccba60fSjmatthew 		goto free;
28214ccba60fSjmatthew 	if (bus_dmamap_load(sc->sc_dmat, ixm->ixm_map, ixm->ixm_kva,
28224ccba60fSjmatthew 	    ixm->ixm_size, NULL, BUS_DMA_WAITOK) != 0)
28234ccba60fSjmatthew 		goto unmap;
28244ccba60fSjmatthew 
28254ccba60fSjmatthew 	return (0);
28264ccba60fSjmatthew unmap:
28274ccba60fSjmatthew 	bus_dmamem_unmap(sc->sc_dmat, ixm->ixm_kva, ixm->ixm_size);
28284ccba60fSjmatthew free:
28294ccba60fSjmatthew 	bus_dmamem_free(sc->sc_dmat, &ixm->ixm_seg, 1);
28304ccba60fSjmatthew destroy:
28314ccba60fSjmatthew 	bus_dmamap_destroy(sc->sc_dmat, ixm->ixm_map);
28324ccba60fSjmatthew 	return (1);
28334ccba60fSjmatthew }
28344ccba60fSjmatthew 
28354ccba60fSjmatthew static void
28364ccba60fSjmatthew iavf_dmamem_free(struct iavf_softc *sc, struct iavf_dmamem *ixm)
28374ccba60fSjmatthew {
28384ccba60fSjmatthew 	bus_dmamap_unload(sc->sc_dmat, ixm->ixm_map);
28394ccba60fSjmatthew 	bus_dmamem_unmap(sc->sc_dmat, ixm->ixm_kva, ixm->ixm_size);
28404ccba60fSjmatthew 	bus_dmamem_free(sc->sc_dmat, &ixm->ixm_seg, 1);
28414ccba60fSjmatthew 	bus_dmamap_destroy(sc->sc_dmat, ixm->ixm_map);
28424ccba60fSjmatthew }
2843