xref: /f-stack/dpdk/drivers/net/netvsc/hn_ethdev.c (revision 2d9fd380)
1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606  * Copyright(c) 2016-2018 Microsoft Corporation
3d30ea906Sjfb8856606  * Copyright(c) 2013-2016 Brocade Communications Systems, Inc.
4d30ea906Sjfb8856606  * All rights reserved.
5d30ea906Sjfb8856606  */
6d30ea906Sjfb8856606 
7d30ea906Sjfb8856606 #include <stdint.h>
8d30ea906Sjfb8856606 #include <string.h>
9d30ea906Sjfb8856606 #include <stdio.h>
10d30ea906Sjfb8856606 #include <errno.h>
11d30ea906Sjfb8856606 #include <unistd.h>
12d30ea906Sjfb8856606 
13d30ea906Sjfb8856606 #include <rte_ethdev.h>
14d30ea906Sjfb8856606 #include <rte_memcpy.h>
15d30ea906Sjfb8856606 #include <rte_string_fns.h>
16d30ea906Sjfb8856606 #include <rte_memzone.h>
17d30ea906Sjfb8856606 #include <rte_devargs.h>
18d30ea906Sjfb8856606 #include <rte_malloc.h>
19d30ea906Sjfb8856606 #include <rte_kvargs.h>
20d30ea906Sjfb8856606 #include <rte_atomic.h>
21d30ea906Sjfb8856606 #include <rte_branch_prediction.h>
22d30ea906Sjfb8856606 #include <rte_ether.h>
23d30ea906Sjfb8856606 #include <rte_ethdev_driver.h>
24d30ea906Sjfb8856606 #include <rte_cycles.h>
25d30ea906Sjfb8856606 #include <rte_errno.h>
26d30ea906Sjfb8856606 #include <rte_memory.h>
27d30ea906Sjfb8856606 #include <rte_eal.h>
28d30ea906Sjfb8856606 #include <rte_dev.h>
29d30ea906Sjfb8856606 #include <rte_bus_vmbus.h>
30d30ea906Sjfb8856606 
31d30ea906Sjfb8856606 #include "hn_logs.h"
32d30ea906Sjfb8856606 #include "hn_var.h"
33d30ea906Sjfb8856606 #include "hn_rndis.h"
34d30ea906Sjfb8856606 #include "hn_nvs.h"
35d30ea906Sjfb8856606 #include "ndis.h"
36d30ea906Sjfb8856606 
37d30ea906Sjfb8856606 #define HN_TX_OFFLOAD_CAPS (DEV_TX_OFFLOAD_IPV4_CKSUM | \
38d30ea906Sjfb8856606 			    DEV_TX_OFFLOAD_TCP_CKSUM  | \
39d30ea906Sjfb8856606 			    DEV_TX_OFFLOAD_UDP_CKSUM  | \
40d30ea906Sjfb8856606 			    DEV_TX_OFFLOAD_TCP_TSO    | \
41d30ea906Sjfb8856606 			    DEV_TX_OFFLOAD_MULTI_SEGS | \
42d30ea906Sjfb8856606 			    DEV_TX_OFFLOAD_VLAN_INSERT)
43d30ea906Sjfb8856606 
44d30ea906Sjfb8856606 #define HN_RX_OFFLOAD_CAPS (DEV_RX_OFFLOAD_CHECKSUM | \
454418919fSjohnjiang 			    DEV_RX_OFFLOAD_VLAN_STRIP | \
464418919fSjohnjiang 			    DEV_RX_OFFLOAD_RSS_HASH)
47d30ea906Sjfb8856606 
48*2d9fd380Sjfb8856606 #define NETVSC_ARG_LATENCY "latency"
49*2d9fd380Sjfb8856606 #define NETVSC_ARG_RXBREAK "rx_copybreak"
50*2d9fd380Sjfb8856606 #define NETVSC_ARG_TXBREAK "tx_copybreak"
51*2d9fd380Sjfb8856606 #define NETVSC_ARG_RX_EXTMBUF_ENABLE "rx_extmbuf_enable"
52d30ea906Sjfb8856606 
53d30ea906Sjfb8856606 struct hn_xstats_name_off {
54d30ea906Sjfb8856606 	char name[RTE_ETH_XSTATS_NAME_SIZE];
55d30ea906Sjfb8856606 	unsigned int offset;
56d30ea906Sjfb8856606 };
57d30ea906Sjfb8856606 
58d30ea906Sjfb8856606 static const struct hn_xstats_name_off hn_stat_strings[] = {
59d30ea906Sjfb8856606 	{ "good_packets",           offsetof(struct hn_stats, packets) },
60d30ea906Sjfb8856606 	{ "good_bytes",             offsetof(struct hn_stats, bytes) },
61d30ea906Sjfb8856606 	{ "errors",                 offsetof(struct hn_stats, errors) },
62d30ea906Sjfb8856606 	{ "ring full",              offsetof(struct hn_stats, ring_full) },
63*2d9fd380Sjfb8856606 	{ "channel full",           offsetof(struct hn_stats, channel_full) },
64d30ea906Sjfb8856606 	{ "multicast_packets",      offsetof(struct hn_stats, multicast) },
65d30ea906Sjfb8856606 	{ "broadcast_packets",      offsetof(struct hn_stats, broadcast) },
66d30ea906Sjfb8856606 	{ "undersize_packets",      offsetof(struct hn_stats, size_bins[0]) },
67d30ea906Sjfb8856606 	{ "size_64_packets",        offsetof(struct hn_stats, size_bins[1]) },
68d30ea906Sjfb8856606 	{ "size_65_127_packets",    offsetof(struct hn_stats, size_bins[2]) },
69d30ea906Sjfb8856606 	{ "size_128_255_packets",   offsetof(struct hn_stats, size_bins[3]) },
70d30ea906Sjfb8856606 	{ "size_256_511_packets",   offsetof(struct hn_stats, size_bins[4]) },
71d30ea906Sjfb8856606 	{ "size_512_1023_packets",  offsetof(struct hn_stats, size_bins[5]) },
72d30ea906Sjfb8856606 	{ "size_1024_1518_packets", offsetof(struct hn_stats, size_bins[6]) },
73d30ea906Sjfb8856606 	{ "size_1519_max_packets",  offsetof(struct hn_stats, size_bins[7]) },
74d30ea906Sjfb8856606 };
75d30ea906Sjfb8856606 
764418919fSjohnjiang /* The default RSS key.
774418919fSjohnjiang  * This value is the same as MLX5 so that flows will be
780c6bd470Sfengbojiang  * received on same path for both VF and synthetic NIC.
794418919fSjohnjiang  */
804418919fSjohnjiang static const uint8_t rss_default_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
814418919fSjohnjiang 	0x2c, 0xc6, 0x81, 0xd1,	0x5b, 0xdb, 0xf4, 0xf7,
824418919fSjohnjiang 	0xfc, 0xa2, 0x83, 0x19,	0xdb, 0x1a, 0x3e, 0x94,
834418919fSjohnjiang 	0x6b, 0x9e, 0x38, 0xd9,	0x2c, 0x9c, 0x03, 0xd1,
844418919fSjohnjiang 	0xad, 0x99, 0x44, 0xa7,	0xd9, 0x56, 0x3d, 0x59,
854418919fSjohnjiang 	0x06, 0x3c, 0x25, 0xf3,	0xfc, 0x1f, 0xdc, 0x2a,
864418919fSjohnjiang };
874418919fSjohnjiang 
88d30ea906Sjfb8856606 static struct rte_eth_dev *
eth_dev_vmbus_allocate(struct rte_vmbus_device * dev,size_t private_data_size)89d30ea906Sjfb8856606 eth_dev_vmbus_allocate(struct rte_vmbus_device *dev, size_t private_data_size)
90d30ea906Sjfb8856606 {
91d30ea906Sjfb8856606 	struct rte_eth_dev *eth_dev;
92d30ea906Sjfb8856606 	const char *name;
93d30ea906Sjfb8856606 
94d30ea906Sjfb8856606 	if (!dev)
95d30ea906Sjfb8856606 		return NULL;
96d30ea906Sjfb8856606 
97d30ea906Sjfb8856606 	name = dev->device.name;
98d30ea906Sjfb8856606 
99d30ea906Sjfb8856606 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
100d30ea906Sjfb8856606 		eth_dev = rte_eth_dev_allocate(name);
101d30ea906Sjfb8856606 		if (!eth_dev) {
102d30ea906Sjfb8856606 			PMD_DRV_LOG(NOTICE, "can not allocate rte ethdev");
103d30ea906Sjfb8856606 			return NULL;
104d30ea906Sjfb8856606 		}
105d30ea906Sjfb8856606 
106d30ea906Sjfb8856606 		if (private_data_size) {
107d30ea906Sjfb8856606 			eth_dev->data->dev_private =
108d30ea906Sjfb8856606 				rte_zmalloc_socket(name, private_data_size,
109d30ea906Sjfb8856606 						     RTE_CACHE_LINE_SIZE, dev->device.numa_node);
110d30ea906Sjfb8856606 			if (!eth_dev->data->dev_private) {
111d30ea906Sjfb8856606 				PMD_DRV_LOG(NOTICE, "can not allocate driver data");
112d30ea906Sjfb8856606 				rte_eth_dev_release_port(eth_dev);
113d30ea906Sjfb8856606 				return NULL;
114d30ea906Sjfb8856606 			}
115d30ea906Sjfb8856606 		}
116d30ea906Sjfb8856606 	} else {
117d30ea906Sjfb8856606 		eth_dev = rte_eth_dev_attach_secondary(name);
118d30ea906Sjfb8856606 		if (!eth_dev) {
119d30ea906Sjfb8856606 			PMD_DRV_LOG(NOTICE, "can not attach secondary");
120d30ea906Sjfb8856606 			return NULL;
121d30ea906Sjfb8856606 		}
122d30ea906Sjfb8856606 	}
123d30ea906Sjfb8856606 
124d30ea906Sjfb8856606 	eth_dev->device = &dev->device;
125d30ea906Sjfb8856606 
126d30ea906Sjfb8856606 	/* interrupt is simulated */
127d30ea906Sjfb8856606 	dev->intr_handle.type = RTE_INTR_HANDLE_EXT;
128d30ea906Sjfb8856606 	eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
129d30ea906Sjfb8856606 	eth_dev->intr_handle = &dev->intr_handle;
130d30ea906Sjfb8856606 
131d30ea906Sjfb8856606 	return eth_dev;
132d30ea906Sjfb8856606 }
133d30ea906Sjfb8856606 
134d30ea906Sjfb8856606 static void
eth_dev_vmbus_release(struct rte_eth_dev * eth_dev)135d30ea906Sjfb8856606 eth_dev_vmbus_release(struct rte_eth_dev *eth_dev)
136d30ea906Sjfb8856606 {
137d30ea906Sjfb8856606 	/* free ether device */
138d30ea906Sjfb8856606 	rte_eth_dev_release_port(eth_dev);
139d30ea906Sjfb8856606 
140d30ea906Sjfb8856606 	eth_dev->device = NULL;
141d30ea906Sjfb8856606 	eth_dev->intr_handle = NULL;
142d30ea906Sjfb8856606 }
143d30ea906Sjfb8856606 
hn_set_parameter(const char * key,const char * value,void * opaque)144*2d9fd380Sjfb8856606 static int hn_set_parameter(const char *key, const char *value, void *opaque)
145d30ea906Sjfb8856606 {
146d30ea906Sjfb8856606 	struct hn_data *hv = opaque;
147d30ea906Sjfb8856606 	char *endp = NULL;
148*2d9fd380Sjfb8856606 	unsigned long v;
149d30ea906Sjfb8856606 
150*2d9fd380Sjfb8856606 	v = strtoul(value, &endp, 0);
151d30ea906Sjfb8856606 	if (*value == '\0' || *endp != '\0') {
152d30ea906Sjfb8856606 		PMD_DRV_LOG(ERR, "invalid parameter %s=%s", key, value);
153d30ea906Sjfb8856606 		return -EINVAL;
154d30ea906Sjfb8856606 	}
155d30ea906Sjfb8856606 
156*2d9fd380Sjfb8856606 	if (!strcmp(key, NETVSC_ARG_LATENCY)) {
157*2d9fd380Sjfb8856606 		/* usec to nsec */
158*2d9fd380Sjfb8856606 		hv->latency = v * 1000;
159*2d9fd380Sjfb8856606 		PMD_DRV_LOG(DEBUG, "set latency %u usec", hv->latency);
160*2d9fd380Sjfb8856606 	} else if (!strcmp(key, NETVSC_ARG_RXBREAK)) {
161*2d9fd380Sjfb8856606 		hv->rx_copybreak = v;
162*2d9fd380Sjfb8856606 		PMD_DRV_LOG(DEBUG, "rx copy break set to %u",
163*2d9fd380Sjfb8856606 			    hv->rx_copybreak);
164*2d9fd380Sjfb8856606 	} else if (!strcmp(key, NETVSC_ARG_TXBREAK)) {
165*2d9fd380Sjfb8856606 		hv->tx_copybreak = v;
166*2d9fd380Sjfb8856606 		PMD_DRV_LOG(DEBUG, "tx copy break set to %u",
167*2d9fd380Sjfb8856606 			    hv->tx_copybreak);
168*2d9fd380Sjfb8856606 	} else if (!strcmp(key, NETVSC_ARG_RX_EXTMBUF_ENABLE)) {
169*2d9fd380Sjfb8856606 		hv->rx_extmbuf_enable = v;
170*2d9fd380Sjfb8856606 		PMD_DRV_LOG(DEBUG, "rx extmbuf enable set to %u",
171*2d9fd380Sjfb8856606 			    hv->rx_extmbuf_enable);
172*2d9fd380Sjfb8856606 	}
173d30ea906Sjfb8856606 
174d30ea906Sjfb8856606 	return 0;
175d30ea906Sjfb8856606 }
176d30ea906Sjfb8856606 
177d30ea906Sjfb8856606 /* Parse device arguments */
hn_parse_args(const struct rte_eth_dev * dev)178d30ea906Sjfb8856606 static int hn_parse_args(const struct rte_eth_dev *dev)
179d30ea906Sjfb8856606 {
180d30ea906Sjfb8856606 	struct hn_data *hv = dev->data->dev_private;
181d30ea906Sjfb8856606 	struct rte_devargs *devargs = dev->device->devargs;
182d30ea906Sjfb8856606 	static const char * const valid_keys[] = {
183*2d9fd380Sjfb8856606 		NETVSC_ARG_LATENCY,
184*2d9fd380Sjfb8856606 		NETVSC_ARG_RXBREAK,
185*2d9fd380Sjfb8856606 		NETVSC_ARG_TXBREAK,
186*2d9fd380Sjfb8856606 		NETVSC_ARG_RX_EXTMBUF_ENABLE,
187d30ea906Sjfb8856606 		NULL
188d30ea906Sjfb8856606 	};
189d30ea906Sjfb8856606 	struct rte_kvargs *kvlist;
190d30ea906Sjfb8856606 	int ret;
191d30ea906Sjfb8856606 
192d30ea906Sjfb8856606 	if (!devargs)
193d30ea906Sjfb8856606 		return 0;
194d30ea906Sjfb8856606 
195d30ea906Sjfb8856606 	PMD_INIT_LOG(DEBUG, "device args %s %s",
196d30ea906Sjfb8856606 		     devargs->name, devargs->args);
197d30ea906Sjfb8856606 
198d30ea906Sjfb8856606 	kvlist = rte_kvargs_parse(devargs->args, valid_keys);
199d30ea906Sjfb8856606 	if (!kvlist) {
200*2d9fd380Sjfb8856606 		PMD_DRV_LOG(ERR, "invalid parameters");
201d30ea906Sjfb8856606 		return -EINVAL;
202d30ea906Sjfb8856606 	}
203d30ea906Sjfb8856606 
204*2d9fd380Sjfb8856606 	ret = rte_kvargs_process(kvlist, NULL, hn_set_parameter, hv);
205d30ea906Sjfb8856606 	rte_kvargs_free(kvlist);
206*2d9fd380Sjfb8856606 
207d30ea906Sjfb8856606 	return ret;
208d30ea906Sjfb8856606 }
209d30ea906Sjfb8856606 
210d30ea906Sjfb8856606 /* Update link status.
211d30ea906Sjfb8856606  * Note: the DPDK definition of "wait_to_complete"
212d30ea906Sjfb8856606  *   means block this call until link is up.
213d30ea906Sjfb8856606  *   which is not worth supporting.
214d30ea906Sjfb8856606  */
215d30ea906Sjfb8856606 int
hn_dev_link_update(struct rte_eth_dev * dev,int wait_to_complete __rte_unused)216d30ea906Sjfb8856606 hn_dev_link_update(struct rte_eth_dev *dev,
2170c6bd470Sfengbojiang 		   int wait_to_complete __rte_unused)
218d30ea906Sjfb8856606 {
219d30ea906Sjfb8856606 	struct hn_data *hv = dev->data->dev_private;
220d30ea906Sjfb8856606 	struct rte_eth_link link, old;
221d30ea906Sjfb8856606 	int error;
222d30ea906Sjfb8856606 
223d30ea906Sjfb8856606 	old = dev->data->dev_link;
224d30ea906Sjfb8856606 
225d30ea906Sjfb8856606 	error = hn_rndis_get_linkstatus(hv);
226d30ea906Sjfb8856606 	if (error)
227d30ea906Sjfb8856606 		return error;
228d30ea906Sjfb8856606 
229d30ea906Sjfb8856606 	hn_rndis_get_linkspeed(hv);
230d30ea906Sjfb8856606 
231d30ea906Sjfb8856606 	link = (struct rte_eth_link) {
232d30ea906Sjfb8856606 		.link_duplex = ETH_LINK_FULL_DUPLEX,
233d30ea906Sjfb8856606 		.link_autoneg = ETH_LINK_SPEED_FIXED,
234d30ea906Sjfb8856606 		.link_speed = hv->link_speed / 10000,
235d30ea906Sjfb8856606 	};
236d30ea906Sjfb8856606 
237d30ea906Sjfb8856606 	if (hv->link_status == NDIS_MEDIA_STATE_CONNECTED)
238d30ea906Sjfb8856606 		link.link_status = ETH_LINK_UP;
239d30ea906Sjfb8856606 	else
240d30ea906Sjfb8856606 		link.link_status = ETH_LINK_DOWN;
241d30ea906Sjfb8856606 
242d30ea906Sjfb8856606 	if (old.link_status == link.link_status)
243d30ea906Sjfb8856606 		return 0;
244d30ea906Sjfb8856606 
245d30ea906Sjfb8856606 	PMD_INIT_LOG(DEBUG, "Port %d is %s", dev->data->port_id,
246d30ea906Sjfb8856606 		     (link.link_status == ETH_LINK_UP) ? "up" : "down");
247d30ea906Sjfb8856606 
248d30ea906Sjfb8856606 	return rte_eth_linkstatus_set(dev, &link);
249d30ea906Sjfb8856606 }
250d30ea906Sjfb8856606 
hn_dev_info_get(struct rte_eth_dev * dev,struct rte_eth_dev_info * dev_info)2514418919fSjohnjiang static int hn_dev_info_get(struct rte_eth_dev *dev,
252d30ea906Sjfb8856606 			   struct rte_eth_dev_info *dev_info)
253d30ea906Sjfb8856606 {
254d30ea906Sjfb8856606 	struct hn_data *hv = dev->data->dev_private;
2554418919fSjohnjiang 	int rc;
256d30ea906Sjfb8856606 
257d30ea906Sjfb8856606 	dev_info->speed_capa = ETH_LINK_SPEED_10G;
258d30ea906Sjfb8856606 	dev_info->min_rx_bufsize = HN_MIN_RX_BUF_SIZE;
259d30ea906Sjfb8856606 	dev_info->max_rx_pktlen  = HN_MAX_XFER_LEN;
260d30ea906Sjfb8856606 	dev_info->max_mac_addrs  = 1;
261d30ea906Sjfb8856606 
262d30ea906Sjfb8856606 	dev_info->hash_key_size = NDIS_HASH_KEYSIZE_TOEPLITZ;
2634b05018fSfengbojiang 	dev_info->flow_type_rss_offloads = hv->rss_offloads;
2644b05018fSfengbojiang 	dev_info->reta_size = ETH_RSS_RETA_SIZE_128;
265d30ea906Sjfb8856606 
266d30ea906Sjfb8856606 	dev_info->max_rx_queues = hv->max_queues;
267d30ea906Sjfb8856606 	dev_info->max_tx_queues = hv->max_queues;
268d30ea906Sjfb8856606 
2690c6bd470Sfengbojiang 	dev_info->tx_desc_lim.nb_min = 1;
2700c6bd470Sfengbojiang 	dev_info->tx_desc_lim.nb_max = 4096;
2710c6bd470Sfengbojiang 
2724418919fSjohnjiang 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
2734418919fSjohnjiang 		return 0;
2744418919fSjohnjiang 
2754418919fSjohnjiang 	/* fills in rx and tx offload capability */
2764418919fSjohnjiang 	rc = hn_rndis_get_offload(hv, dev_info);
2774418919fSjohnjiang 	if (rc != 0)
2784418919fSjohnjiang 		return rc;
2794418919fSjohnjiang 
2804418919fSjohnjiang 	/* merges the offload and queues of vf */
2814418919fSjohnjiang 	return hn_vf_info_get(hv, dev_info);
282d30ea906Sjfb8856606 }
283d30ea906Sjfb8856606 
hn_rss_reta_update(struct rte_eth_dev * dev,struct rte_eth_rss_reta_entry64 * reta_conf,uint16_t reta_size)2844418919fSjohnjiang static int hn_rss_reta_update(struct rte_eth_dev *dev,
2854418919fSjohnjiang 			      struct rte_eth_rss_reta_entry64 *reta_conf,
2864418919fSjohnjiang 			      uint16_t reta_size)
2874418919fSjohnjiang {
2884418919fSjohnjiang 	struct hn_data *hv = dev->data->dev_private;
2894418919fSjohnjiang 	unsigned int i;
2904418919fSjohnjiang 	int err;
2914418919fSjohnjiang 
2924418919fSjohnjiang 	PMD_INIT_FUNC_TRACE();
2934418919fSjohnjiang 
2944418919fSjohnjiang 	if (reta_size != NDIS_HASH_INDCNT) {
2954418919fSjohnjiang 		PMD_DRV_LOG(ERR, "Hash lookup table size does not match NDIS");
2964418919fSjohnjiang 		return -EINVAL;
2974418919fSjohnjiang 	}
2984418919fSjohnjiang 
2994418919fSjohnjiang 	for (i = 0; i < NDIS_HASH_INDCNT; i++) {
3004418919fSjohnjiang 		uint16_t idx = i / RTE_RETA_GROUP_SIZE;
3014418919fSjohnjiang 		uint16_t shift = i % RTE_RETA_GROUP_SIZE;
3024418919fSjohnjiang 		uint64_t mask = (uint64_t)1 << shift;
3034418919fSjohnjiang 
3044418919fSjohnjiang 		if (reta_conf[idx].mask & mask)
3054418919fSjohnjiang 			hv->rss_ind[i] = reta_conf[idx].reta[shift];
3064418919fSjohnjiang 	}
3074418919fSjohnjiang 
3084418919fSjohnjiang 	err = hn_rndis_conf_rss(hv, NDIS_RSS_FLAG_DISABLE);
3094418919fSjohnjiang 	if (err) {
3104418919fSjohnjiang 		PMD_DRV_LOG(NOTICE,
3114418919fSjohnjiang 			"rss disable failed");
3124418919fSjohnjiang 		return err;
3134418919fSjohnjiang 	}
3144418919fSjohnjiang 
3154418919fSjohnjiang 	err = hn_rndis_conf_rss(hv, 0);
3164418919fSjohnjiang 	if (err) {
3174418919fSjohnjiang 		PMD_DRV_LOG(NOTICE,
3184418919fSjohnjiang 			    "reta reconfig failed");
3194418919fSjohnjiang 		return err;
3204418919fSjohnjiang 	}
3214418919fSjohnjiang 
3224418919fSjohnjiang 	return hn_vf_reta_hash_update(dev, reta_conf, reta_size);
3234418919fSjohnjiang }
3244418919fSjohnjiang 
hn_rss_reta_query(struct rte_eth_dev * dev,struct rte_eth_rss_reta_entry64 * reta_conf,uint16_t reta_size)3254418919fSjohnjiang static int hn_rss_reta_query(struct rte_eth_dev *dev,
3264418919fSjohnjiang 			     struct rte_eth_rss_reta_entry64 *reta_conf,
3274418919fSjohnjiang 			     uint16_t reta_size)
3284418919fSjohnjiang {
3294418919fSjohnjiang 	struct hn_data *hv = dev->data->dev_private;
3304418919fSjohnjiang 	unsigned int i;
3314418919fSjohnjiang 
3324418919fSjohnjiang 	PMD_INIT_FUNC_TRACE();
3334418919fSjohnjiang 
3344418919fSjohnjiang 	if (reta_size != NDIS_HASH_INDCNT) {
3354418919fSjohnjiang 		PMD_DRV_LOG(ERR, "Hash lookup table size does not match NDIS");
3364418919fSjohnjiang 		return -EINVAL;
3374418919fSjohnjiang 	}
3384418919fSjohnjiang 
3394418919fSjohnjiang 	for (i = 0; i < NDIS_HASH_INDCNT; i++) {
3404418919fSjohnjiang 		uint16_t idx = i / RTE_RETA_GROUP_SIZE;
3414418919fSjohnjiang 		uint16_t shift = i % RTE_RETA_GROUP_SIZE;
3424418919fSjohnjiang 		uint64_t mask = (uint64_t)1 << shift;
3434418919fSjohnjiang 
3444418919fSjohnjiang 		if (reta_conf[idx].mask & mask)
3454418919fSjohnjiang 			reta_conf[idx].reta[shift] = hv->rss_ind[i];
3464418919fSjohnjiang 	}
3474418919fSjohnjiang 	return 0;
3484418919fSjohnjiang }
3494418919fSjohnjiang 
hn_rss_hash_init(struct hn_data * hv,const struct rte_eth_rss_conf * rss_conf)3504418919fSjohnjiang static void hn_rss_hash_init(struct hn_data *hv,
3514418919fSjohnjiang 			     const struct rte_eth_rss_conf *rss_conf)
3524418919fSjohnjiang {
3534418919fSjohnjiang 	/* Convert from DPDK RSS hash flags to NDIS hash flags */
3544418919fSjohnjiang 	hv->rss_hash = NDIS_HASH_FUNCTION_TOEPLITZ;
3554418919fSjohnjiang 
3564418919fSjohnjiang 	if (rss_conf->rss_hf & ETH_RSS_IPV4)
3574418919fSjohnjiang 		hv->rss_hash |= NDIS_HASH_IPV4;
3584418919fSjohnjiang 	if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_TCP)
3594418919fSjohnjiang 		hv->rss_hash |= NDIS_HASH_TCP_IPV4;
3604418919fSjohnjiang 	if (rss_conf->rss_hf & ETH_RSS_IPV6)
3614418919fSjohnjiang 		hv->rss_hash |=  NDIS_HASH_IPV6;
3624418919fSjohnjiang 	if (rss_conf->rss_hf & ETH_RSS_IPV6_EX)
3634418919fSjohnjiang 		hv->rss_hash |=  NDIS_HASH_IPV6_EX;
3644418919fSjohnjiang 	if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV6_TCP)
3654418919fSjohnjiang 		hv->rss_hash |= NDIS_HASH_TCP_IPV6;
3664418919fSjohnjiang 	if (rss_conf->rss_hf & ETH_RSS_IPV6_TCP_EX)
3674418919fSjohnjiang 		hv->rss_hash |= NDIS_HASH_TCP_IPV6_EX;
3684418919fSjohnjiang 
3694418919fSjohnjiang 	memcpy(hv->rss_key, rss_conf->rss_key ? : rss_default_key,
3704418919fSjohnjiang 	       NDIS_HASH_KEYSIZE_TOEPLITZ);
3714418919fSjohnjiang }
3724418919fSjohnjiang 
hn_rss_hash_update(struct rte_eth_dev * dev,struct rte_eth_rss_conf * rss_conf)3734418919fSjohnjiang static int hn_rss_hash_update(struct rte_eth_dev *dev,
3744418919fSjohnjiang 			      struct rte_eth_rss_conf *rss_conf)
3754418919fSjohnjiang {
3764418919fSjohnjiang 	struct hn_data *hv = dev->data->dev_private;
3774418919fSjohnjiang 	int err;
3784418919fSjohnjiang 
3794418919fSjohnjiang 	PMD_INIT_FUNC_TRACE();
3804418919fSjohnjiang 
3814418919fSjohnjiang 	err = hn_rndis_conf_rss(hv, NDIS_RSS_FLAG_DISABLE);
3824418919fSjohnjiang 	if (err) {
3834418919fSjohnjiang 		PMD_DRV_LOG(NOTICE,
3844418919fSjohnjiang 			    "rss disable failed");
3854418919fSjohnjiang 		return err;
3864418919fSjohnjiang 	}
3874418919fSjohnjiang 
3884418919fSjohnjiang 	hn_rss_hash_init(hv, rss_conf);
3894418919fSjohnjiang 
3900c6bd470Sfengbojiang 	if (rss_conf->rss_hf != 0) {
3914418919fSjohnjiang 		err = hn_rndis_conf_rss(hv, 0);
3924418919fSjohnjiang 		if (err) {
3934418919fSjohnjiang 			PMD_DRV_LOG(NOTICE,
3944418919fSjohnjiang 				    "rss reconfig failed (RSS disabled)");
3954418919fSjohnjiang 			return err;
3964418919fSjohnjiang 		}
3970c6bd470Sfengbojiang 	}
3984418919fSjohnjiang 
3994418919fSjohnjiang 	return hn_vf_rss_hash_update(dev, rss_conf);
4004418919fSjohnjiang }
4014418919fSjohnjiang 
hn_rss_hash_conf_get(struct rte_eth_dev * dev,struct rte_eth_rss_conf * rss_conf)4024418919fSjohnjiang static int hn_rss_hash_conf_get(struct rte_eth_dev *dev,
4034418919fSjohnjiang 				struct rte_eth_rss_conf *rss_conf)
4044418919fSjohnjiang {
4054418919fSjohnjiang 	struct hn_data *hv = dev->data->dev_private;
4064418919fSjohnjiang 
4074418919fSjohnjiang 	PMD_INIT_FUNC_TRACE();
4084418919fSjohnjiang 
4094418919fSjohnjiang 	if (hv->ndis_ver < NDIS_VERSION_6_20) {
4104418919fSjohnjiang 		PMD_DRV_LOG(DEBUG, "RSS not supported on this host");
4114418919fSjohnjiang 		return -EOPNOTSUPP;
4124418919fSjohnjiang 	}
4134418919fSjohnjiang 
4144418919fSjohnjiang 	rss_conf->rss_key_len = NDIS_HASH_KEYSIZE_TOEPLITZ;
4154418919fSjohnjiang 	if (rss_conf->rss_key)
4164418919fSjohnjiang 		memcpy(rss_conf->rss_key, hv->rss_key,
4174418919fSjohnjiang 		       NDIS_HASH_KEYSIZE_TOEPLITZ);
4184418919fSjohnjiang 
4194418919fSjohnjiang 	rss_conf->rss_hf = 0;
4204418919fSjohnjiang 	if (hv->rss_hash & NDIS_HASH_IPV4)
4214418919fSjohnjiang 		rss_conf->rss_hf |= ETH_RSS_IPV4;
4224418919fSjohnjiang 
4234418919fSjohnjiang 	if (hv->rss_hash & NDIS_HASH_TCP_IPV4)
4244418919fSjohnjiang 		rss_conf->rss_hf |= ETH_RSS_NONFRAG_IPV4_TCP;
4254418919fSjohnjiang 
4264418919fSjohnjiang 	if (hv->rss_hash & NDIS_HASH_IPV6)
4274418919fSjohnjiang 		rss_conf->rss_hf |= ETH_RSS_IPV6;
4284418919fSjohnjiang 
4294418919fSjohnjiang 	if (hv->rss_hash & NDIS_HASH_IPV6_EX)
4304418919fSjohnjiang 		rss_conf->rss_hf |= ETH_RSS_IPV6_EX;
4314418919fSjohnjiang 
4324418919fSjohnjiang 	if (hv->rss_hash & NDIS_HASH_TCP_IPV6)
4334418919fSjohnjiang 		rss_conf->rss_hf |= ETH_RSS_NONFRAG_IPV6_TCP;
4344418919fSjohnjiang 
4354418919fSjohnjiang 	if (hv->rss_hash & NDIS_HASH_TCP_IPV6_EX)
4364418919fSjohnjiang 		rss_conf->rss_hf |= ETH_RSS_IPV6_TCP_EX;
4374418919fSjohnjiang 
4384418919fSjohnjiang 	return 0;
4394418919fSjohnjiang }
4404418919fSjohnjiang 
4414418919fSjohnjiang static int
hn_dev_promiscuous_enable(struct rte_eth_dev * dev)442d30ea906Sjfb8856606 hn_dev_promiscuous_enable(struct rte_eth_dev *dev)
443d30ea906Sjfb8856606 {
444d30ea906Sjfb8856606 	struct hn_data *hv = dev->data->dev_private;
445d30ea906Sjfb8856606 
446d30ea906Sjfb8856606 	hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_PROMISCUOUS);
4474418919fSjohnjiang 	return hn_vf_promiscuous_enable(dev);
448d30ea906Sjfb8856606 }
449d30ea906Sjfb8856606 
4504418919fSjohnjiang static int
hn_dev_promiscuous_disable(struct rte_eth_dev * dev)451d30ea906Sjfb8856606 hn_dev_promiscuous_disable(struct rte_eth_dev *dev)
452d30ea906Sjfb8856606 {
453d30ea906Sjfb8856606 	struct hn_data *hv = dev->data->dev_private;
454d30ea906Sjfb8856606 	uint32_t filter;
455d30ea906Sjfb8856606 
456d30ea906Sjfb8856606 	filter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST;
457d30ea906Sjfb8856606 	if (dev->data->all_multicast)
458d30ea906Sjfb8856606 		filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
459d30ea906Sjfb8856606 	hn_rndis_set_rxfilter(hv, filter);
4604418919fSjohnjiang 	return hn_vf_promiscuous_disable(dev);
461d30ea906Sjfb8856606 }
462d30ea906Sjfb8856606 
4634418919fSjohnjiang static int
hn_dev_allmulticast_enable(struct rte_eth_dev * dev)464d30ea906Sjfb8856606 hn_dev_allmulticast_enable(struct rte_eth_dev *dev)
465d30ea906Sjfb8856606 {
466d30ea906Sjfb8856606 	struct hn_data *hv = dev->data->dev_private;
467d30ea906Sjfb8856606 
468d30ea906Sjfb8856606 	hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_DIRECTED |
469d30ea906Sjfb8856606 			      NDIS_PACKET_TYPE_ALL_MULTICAST |
470d30ea906Sjfb8856606 			NDIS_PACKET_TYPE_BROADCAST);
4714418919fSjohnjiang 	return hn_vf_allmulticast_enable(dev);
472d30ea906Sjfb8856606 }
473d30ea906Sjfb8856606 
4744418919fSjohnjiang static int
hn_dev_allmulticast_disable(struct rte_eth_dev * dev)475d30ea906Sjfb8856606 hn_dev_allmulticast_disable(struct rte_eth_dev *dev)
476d30ea906Sjfb8856606 {
477d30ea906Sjfb8856606 	struct hn_data *hv = dev->data->dev_private;
478d30ea906Sjfb8856606 
479d30ea906Sjfb8856606 	hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_DIRECTED |
480d30ea906Sjfb8856606 			     NDIS_PACKET_TYPE_BROADCAST);
4814418919fSjohnjiang 	return hn_vf_allmulticast_disable(dev);
482d30ea906Sjfb8856606 }
483d30ea906Sjfb8856606 
484d30ea906Sjfb8856606 static int
hn_dev_mc_addr_list(struct rte_eth_dev * dev,struct rte_ether_addr * mc_addr_set,uint32_t nb_mc_addr)485d30ea906Sjfb8856606 hn_dev_mc_addr_list(struct rte_eth_dev *dev,
4864418919fSjohnjiang 		     struct rte_ether_addr *mc_addr_set,
487d30ea906Sjfb8856606 		     uint32_t nb_mc_addr)
488d30ea906Sjfb8856606 {
489d30ea906Sjfb8856606 	/* No filtering on the synthetic path, but can do it on VF */
490d30ea906Sjfb8856606 	return hn_vf_mc_addr_list(dev, mc_addr_set, nb_mc_addr);
491d30ea906Sjfb8856606 }
492d30ea906Sjfb8856606 
493d30ea906Sjfb8856606 /* Setup shared rx/tx queue data */
hn_subchan_configure(struct hn_data * hv,uint32_t subchan)494d30ea906Sjfb8856606 static int hn_subchan_configure(struct hn_data *hv,
495d30ea906Sjfb8856606 				uint32_t subchan)
496d30ea906Sjfb8856606 {
497d30ea906Sjfb8856606 	struct vmbus_channel *primary = hn_primary_chan(hv);
498d30ea906Sjfb8856606 	int err;
499d30ea906Sjfb8856606 	unsigned int retry = 0;
500d30ea906Sjfb8856606 
501d30ea906Sjfb8856606 	PMD_DRV_LOG(DEBUG,
502d30ea906Sjfb8856606 		    "open %u subchannels", subchan);
503d30ea906Sjfb8856606 
504d30ea906Sjfb8856606 	/* Send create sub channels command */
505d30ea906Sjfb8856606 	err = hn_nvs_alloc_subchans(hv, &subchan);
506d30ea906Sjfb8856606 	if (err)
507d30ea906Sjfb8856606 		return  err;
508d30ea906Sjfb8856606 
509d30ea906Sjfb8856606 	while (subchan > 0) {
510d30ea906Sjfb8856606 		struct vmbus_channel *new_sc;
511d30ea906Sjfb8856606 		uint16_t chn_index;
512d30ea906Sjfb8856606 
513d30ea906Sjfb8856606 		err = rte_vmbus_subchan_open(primary, &new_sc);
514d30ea906Sjfb8856606 		if (err == -ENOENT && ++retry < 1000) {
515d30ea906Sjfb8856606 			/* This can happen if not ready yet */
516d30ea906Sjfb8856606 			rte_delay_ms(10);
517d30ea906Sjfb8856606 			continue;
518d30ea906Sjfb8856606 		}
519d30ea906Sjfb8856606 
520d30ea906Sjfb8856606 		if (err) {
521d30ea906Sjfb8856606 			PMD_DRV_LOG(ERR,
522d30ea906Sjfb8856606 				    "open subchannel failed: %d", err);
523d30ea906Sjfb8856606 			return err;
524d30ea906Sjfb8856606 		}
525d30ea906Sjfb8856606 
526d30ea906Sjfb8856606 		rte_vmbus_set_latency(hv->vmbus, new_sc, hv->latency);
527d30ea906Sjfb8856606 
528d30ea906Sjfb8856606 		retry = 0;
529d30ea906Sjfb8856606 		chn_index = rte_vmbus_sub_channel_index(new_sc);
530d30ea906Sjfb8856606 		if (chn_index == 0 || chn_index > hv->max_queues) {
531d30ea906Sjfb8856606 			PMD_DRV_LOG(ERR,
532d30ea906Sjfb8856606 				    "Invalid subchannel offermsg channel %u",
533d30ea906Sjfb8856606 				    chn_index);
534d30ea906Sjfb8856606 			return -EIO;
535d30ea906Sjfb8856606 		}
536d30ea906Sjfb8856606 
537d30ea906Sjfb8856606 		PMD_DRV_LOG(DEBUG, "new sub channel %u", chn_index);
538d30ea906Sjfb8856606 		hv->channels[chn_index] = new_sc;
539d30ea906Sjfb8856606 		--subchan;
540d30ea906Sjfb8856606 	}
541d30ea906Sjfb8856606 
542d30ea906Sjfb8856606 	return err;
543d30ea906Sjfb8856606 }
544d30ea906Sjfb8856606 
hn_dev_configure(struct rte_eth_dev * dev)545d30ea906Sjfb8856606 static int hn_dev_configure(struct rte_eth_dev *dev)
546d30ea906Sjfb8856606 {
5474418919fSjohnjiang 	struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
5484418919fSjohnjiang 	struct rte_eth_rss_conf *rss_conf = &dev_conf->rx_adv_conf.rss_conf;
549d30ea906Sjfb8856606 	const struct rte_eth_rxmode *rxmode = &dev_conf->rxmode;
550d30ea906Sjfb8856606 	const struct rte_eth_txmode *txmode = &dev_conf->txmode;
551d30ea906Sjfb8856606 	struct hn_data *hv = dev->data->dev_private;
552d30ea906Sjfb8856606 	uint64_t unsupported;
5534418919fSjohnjiang 	int i, err, subchan;
554d30ea906Sjfb8856606 
555d30ea906Sjfb8856606 	PMD_INIT_FUNC_TRACE();
556d30ea906Sjfb8856606 
5574418919fSjohnjiang 	if (dev_conf->rxmode.mq_mode & ETH_MQ_RX_RSS_FLAG)
5584418919fSjohnjiang 		dev_conf->rxmode.offloads |= DEV_RX_OFFLOAD_RSS_HASH;
5594418919fSjohnjiang 
560d30ea906Sjfb8856606 	unsupported = txmode->offloads & ~HN_TX_OFFLOAD_CAPS;
561d30ea906Sjfb8856606 	if (unsupported) {
562d30ea906Sjfb8856606 		PMD_DRV_LOG(NOTICE,
563d30ea906Sjfb8856606 			    "unsupported TX offload: %#" PRIx64,
564d30ea906Sjfb8856606 			    unsupported);
565d30ea906Sjfb8856606 		return -EINVAL;
566d30ea906Sjfb8856606 	}
567d30ea906Sjfb8856606 
568d30ea906Sjfb8856606 	unsupported = rxmode->offloads & ~HN_RX_OFFLOAD_CAPS;
569d30ea906Sjfb8856606 	if (unsupported) {
570d30ea906Sjfb8856606 		PMD_DRV_LOG(NOTICE,
571d30ea906Sjfb8856606 			    "unsupported RX offload: %#" PRIx64,
572d30ea906Sjfb8856606 			    rxmode->offloads);
573d30ea906Sjfb8856606 		return -EINVAL;
574d30ea906Sjfb8856606 	}
575d30ea906Sjfb8856606 
5764418919fSjohnjiang 	hv->vlan_strip = !!(rxmode->offloads & DEV_RX_OFFLOAD_VLAN_STRIP);
5774418919fSjohnjiang 
578d30ea906Sjfb8856606 	err = hn_rndis_conf_offload(hv, txmode->offloads,
579d30ea906Sjfb8856606 				    rxmode->offloads);
580d30ea906Sjfb8856606 	if (err) {
581d30ea906Sjfb8856606 		PMD_DRV_LOG(NOTICE,
582d30ea906Sjfb8856606 			    "offload configure failed");
583d30ea906Sjfb8856606 		return err;
584d30ea906Sjfb8856606 	}
585d30ea906Sjfb8856606 
586d30ea906Sjfb8856606 	hv->num_queues = RTE_MAX(dev->data->nb_rx_queues,
587d30ea906Sjfb8856606 				 dev->data->nb_tx_queues);
5884418919fSjohnjiang 
5894418919fSjohnjiang 	for (i = 0; i < NDIS_HASH_INDCNT; i++)
5900c6bd470Sfengbojiang 		hv->rss_ind[i] = i % dev->data->nb_rx_queues;
5914418919fSjohnjiang 
5924418919fSjohnjiang 	hn_rss_hash_init(hv, rss_conf);
5934418919fSjohnjiang 
594d30ea906Sjfb8856606 	subchan = hv->num_queues - 1;
595d30ea906Sjfb8856606 	if (subchan > 0) {
596d30ea906Sjfb8856606 		err = hn_subchan_configure(hv, subchan);
597d30ea906Sjfb8856606 		if (err) {
598d30ea906Sjfb8856606 			PMD_DRV_LOG(NOTICE,
599d30ea906Sjfb8856606 				    "subchannel configuration failed");
600d30ea906Sjfb8856606 			return err;
601d30ea906Sjfb8856606 		}
602d30ea906Sjfb8856606 
6034418919fSjohnjiang 		err = hn_rndis_conf_rss(hv, NDIS_RSS_FLAG_DISABLE);
604d30ea906Sjfb8856606 		if (err) {
605d30ea906Sjfb8856606 			PMD_DRV_LOG(NOTICE,
6064418919fSjohnjiang 				"rss disable failed");
6074418919fSjohnjiang 			return err;
6084418919fSjohnjiang 		}
6094418919fSjohnjiang 
6100c6bd470Sfengbojiang 		if (rss_conf->rss_hf != 0) {
6114418919fSjohnjiang 			err = hn_rndis_conf_rss(hv, 0);
6124418919fSjohnjiang 			if (err) {
6134418919fSjohnjiang 				PMD_DRV_LOG(NOTICE,
6144418919fSjohnjiang 					    "initial RSS config failed");
615d30ea906Sjfb8856606 				return err;
616d30ea906Sjfb8856606 			}
617d30ea906Sjfb8856606 		}
6180c6bd470Sfengbojiang 	}
619d30ea906Sjfb8856606 
620d30ea906Sjfb8856606 	return hn_vf_configure(dev, dev_conf);
621d30ea906Sjfb8856606 }
622d30ea906Sjfb8856606 
hn_dev_stats_get(struct rte_eth_dev * dev,struct rte_eth_stats * stats)623d30ea906Sjfb8856606 static int hn_dev_stats_get(struct rte_eth_dev *dev,
624d30ea906Sjfb8856606 			    struct rte_eth_stats *stats)
625d30ea906Sjfb8856606 {
626d30ea906Sjfb8856606 	unsigned int i;
627d30ea906Sjfb8856606 
628d30ea906Sjfb8856606 	hn_vf_stats_get(dev, stats);
629d30ea906Sjfb8856606 
630d30ea906Sjfb8856606 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
631d30ea906Sjfb8856606 		const struct hn_tx_queue *txq = dev->data->tx_queues[i];
632d30ea906Sjfb8856606 
633d30ea906Sjfb8856606 		if (!txq)
634d30ea906Sjfb8856606 			continue;
635d30ea906Sjfb8856606 
636d30ea906Sjfb8856606 		stats->opackets += txq->stats.packets;
637d30ea906Sjfb8856606 		stats->obytes += txq->stats.bytes;
638d30ea906Sjfb8856606 		stats->oerrors += txq->stats.errors;
639d30ea906Sjfb8856606 
640d30ea906Sjfb8856606 		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
641d30ea906Sjfb8856606 			stats->q_opackets[i] = txq->stats.packets;
642d30ea906Sjfb8856606 			stats->q_obytes[i] = txq->stats.bytes;
643d30ea906Sjfb8856606 		}
644d30ea906Sjfb8856606 	}
645d30ea906Sjfb8856606 
646d30ea906Sjfb8856606 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
647d30ea906Sjfb8856606 		const struct hn_rx_queue *rxq = dev->data->rx_queues[i];
648d30ea906Sjfb8856606 
649d30ea906Sjfb8856606 		if (!rxq)
650d30ea906Sjfb8856606 			continue;
651d30ea906Sjfb8856606 
652d30ea906Sjfb8856606 		stats->ipackets += rxq->stats.packets;
653d30ea906Sjfb8856606 		stats->ibytes += rxq->stats.bytes;
654d30ea906Sjfb8856606 		stats->ierrors += rxq->stats.errors;
655d30ea906Sjfb8856606 		stats->imissed += rxq->stats.ring_full;
656d30ea906Sjfb8856606 
657d30ea906Sjfb8856606 		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
658d30ea906Sjfb8856606 			stats->q_ipackets[i] = rxq->stats.packets;
659d30ea906Sjfb8856606 			stats->q_ibytes[i] = rxq->stats.bytes;
660d30ea906Sjfb8856606 		}
661d30ea906Sjfb8856606 	}
662d30ea906Sjfb8856606 
663d30ea906Sjfb8856606 	stats->rx_nombuf = dev->data->rx_mbuf_alloc_failed;
664d30ea906Sjfb8856606 	return 0;
665d30ea906Sjfb8856606 }
666d30ea906Sjfb8856606 
6674418919fSjohnjiang static int
hn_dev_stats_reset(struct rte_eth_dev * dev)668d30ea906Sjfb8856606 hn_dev_stats_reset(struct rte_eth_dev *dev)
669d30ea906Sjfb8856606 {
670d30ea906Sjfb8856606 	unsigned int i;
671d30ea906Sjfb8856606 
672d30ea906Sjfb8856606 	PMD_INIT_FUNC_TRACE();
673d30ea906Sjfb8856606 
674d30ea906Sjfb8856606 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
675d30ea906Sjfb8856606 		struct hn_tx_queue *txq = dev->data->tx_queues[i];
676d30ea906Sjfb8856606 
677d30ea906Sjfb8856606 		if (!txq)
678d30ea906Sjfb8856606 			continue;
679d30ea906Sjfb8856606 		memset(&txq->stats, 0, sizeof(struct hn_stats));
680d30ea906Sjfb8856606 	}
681d30ea906Sjfb8856606 
682d30ea906Sjfb8856606 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
683d30ea906Sjfb8856606 		struct hn_rx_queue *rxq = dev->data->rx_queues[i];
684d30ea906Sjfb8856606 
685d30ea906Sjfb8856606 		if (!rxq)
686d30ea906Sjfb8856606 			continue;
687d30ea906Sjfb8856606 
688d30ea906Sjfb8856606 		memset(&rxq->stats, 0, sizeof(struct hn_stats));
689d30ea906Sjfb8856606 	}
6904418919fSjohnjiang 
6914418919fSjohnjiang 	return 0;
692d30ea906Sjfb8856606 }
693d30ea906Sjfb8856606 
6944418919fSjohnjiang static int
hn_dev_xstats_reset(struct rte_eth_dev * dev)695d30ea906Sjfb8856606 hn_dev_xstats_reset(struct rte_eth_dev *dev)
696d30ea906Sjfb8856606 {
6974418919fSjohnjiang 	int ret;
6984418919fSjohnjiang 
6994418919fSjohnjiang 	ret = hn_dev_stats_reset(dev);
7004418919fSjohnjiang 	if (ret != 0)
7014418919fSjohnjiang 		return 0;
7024418919fSjohnjiang 
7034418919fSjohnjiang 	return hn_vf_xstats_reset(dev);
704d30ea906Sjfb8856606 }
705d30ea906Sjfb8856606 
706d30ea906Sjfb8856606 static int
hn_dev_xstats_count(struct rte_eth_dev * dev)707d30ea906Sjfb8856606 hn_dev_xstats_count(struct rte_eth_dev *dev)
708d30ea906Sjfb8856606 {
709d30ea906Sjfb8856606 	int ret, count;
710d30ea906Sjfb8856606 
711d30ea906Sjfb8856606 	count = dev->data->nb_tx_queues * RTE_DIM(hn_stat_strings);
712d30ea906Sjfb8856606 	count += dev->data->nb_rx_queues * RTE_DIM(hn_stat_strings);
713d30ea906Sjfb8856606 
714d30ea906Sjfb8856606 	ret = hn_vf_xstats_get_names(dev, NULL, 0);
715d30ea906Sjfb8856606 	if (ret < 0)
716d30ea906Sjfb8856606 		return ret;
717d30ea906Sjfb8856606 
718d30ea906Sjfb8856606 	return count + ret;
719d30ea906Sjfb8856606 }
720d30ea906Sjfb8856606 
721d30ea906Sjfb8856606 static int
hn_dev_xstats_get_names(struct rte_eth_dev * dev,struct rte_eth_xstat_name * xstats_names,unsigned int limit)722d30ea906Sjfb8856606 hn_dev_xstats_get_names(struct rte_eth_dev *dev,
723d30ea906Sjfb8856606 			struct rte_eth_xstat_name *xstats_names,
724d30ea906Sjfb8856606 			unsigned int limit)
725d30ea906Sjfb8856606 {
726d30ea906Sjfb8856606 	unsigned int i, t, count = 0;
727d30ea906Sjfb8856606 	int ret;
728d30ea906Sjfb8856606 
729d30ea906Sjfb8856606 	if (!xstats_names)
730d30ea906Sjfb8856606 		return hn_dev_xstats_count(dev);
731d30ea906Sjfb8856606 
732d30ea906Sjfb8856606 	/* Note: limit checked in rte_eth_xstats_names() */
733d30ea906Sjfb8856606 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
734d30ea906Sjfb8856606 		const struct hn_tx_queue *txq = dev->data->tx_queues[i];
735d30ea906Sjfb8856606 
736d30ea906Sjfb8856606 		if (!txq)
737d30ea906Sjfb8856606 			continue;
738d30ea906Sjfb8856606 
739d30ea906Sjfb8856606 		if (count >= limit)
740d30ea906Sjfb8856606 			break;
741d30ea906Sjfb8856606 
742d30ea906Sjfb8856606 		for (t = 0; t < RTE_DIM(hn_stat_strings); t++)
743d30ea906Sjfb8856606 			snprintf(xstats_names[count++].name,
744d30ea906Sjfb8856606 				 RTE_ETH_XSTATS_NAME_SIZE,
745d30ea906Sjfb8856606 				 "tx_q%u_%s", i, hn_stat_strings[t].name);
746d30ea906Sjfb8856606 	}
747d30ea906Sjfb8856606 
748d30ea906Sjfb8856606 	for (i = 0; i < dev->data->nb_rx_queues; i++)  {
749d30ea906Sjfb8856606 		const struct hn_rx_queue *rxq = dev->data->rx_queues[i];
750d30ea906Sjfb8856606 
751d30ea906Sjfb8856606 		if (!rxq)
752d30ea906Sjfb8856606 			continue;
753d30ea906Sjfb8856606 
754d30ea906Sjfb8856606 		if (count >= limit)
755d30ea906Sjfb8856606 			break;
756d30ea906Sjfb8856606 
757d30ea906Sjfb8856606 		for (t = 0; t < RTE_DIM(hn_stat_strings); t++)
758d30ea906Sjfb8856606 			snprintf(xstats_names[count++].name,
759d30ea906Sjfb8856606 				 RTE_ETH_XSTATS_NAME_SIZE,
760d30ea906Sjfb8856606 				 "rx_q%u_%s", i,
761d30ea906Sjfb8856606 				 hn_stat_strings[t].name);
762d30ea906Sjfb8856606 	}
763d30ea906Sjfb8856606 
764d30ea906Sjfb8856606 	ret = hn_vf_xstats_get_names(dev, xstats_names + count,
765d30ea906Sjfb8856606 				     limit - count);
766d30ea906Sjfb8856606 	if (ret < 0)
767d30ea906Sjfb8856606 		return ret;
768d30ea906Sjfb8856606 
769d30ea906Sjfb8856606 	return count + ret;
770d30ea906Sjfb8856606 }
771d30ea906Sjfb8856606 
772d30ea906Sjfb8856606 static int
hn_dev_xstats_get(struct rte_eth_dev * dev,struct rte_eth_xstat * xstats,unsigned int n)773d30ea906Sjfb8856606 hn_dev_xstats_get(struct rte_eth_dev *dev,
774d30ea906Sjfb8856606 		  struct rte_eth_xstat *xstats,
775d30ea906Sjfb8856606 		  unsigned int n)
776d30ea906Sjfb8856606 {
777d30ea906Sjfb8856606 	unsigned int i, t, count = 0;
778d30ea906Sjfb8856606 	const unsigned int nstats = hn_dev_xstats_count(dev);
779d30ea906Sjfb8856606 	const char *stats;
780d30ea906Sjfb8856606 	int ret;
781d30ea906Sjfb8856606 
782d30ea906Sjfb8856606 	PMD_INIT_FUNC_TRACE();
783d30ea906Sjfb8856606 
784d30ea906Sjfb8856606 	if (n < nstats)
785d30ea906Sjfb8856606 		return nstats;
786d30ea906Sjfb8856606 
787d30ea906Sjfb8856606 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
788d30ea906Sjfb8856606 		const struct hn_tx_queue *txq = dev->data->tx_queues[i];
789d30ea906Sjfb8856606 
790d30ea906Sjfb8856606 		if (!txq)
791d30ea906Sjfb8856606 			continue;
792d30ea906Sjfb8856606 
793d30ea906Sjfb8856606 		stats = (const char *)&txq->stats;
7944b05018fSfengbojiang 		for (t = 0; t < RTE_DIM(hn_stat_strings); t++, count++) {
7954b05018fSfengbojiang 			xstats[count].id = count;
7964b05018fSfengbojiang 			xstats[count].value = *(const uint64_t *)
797d30ea906Sjfb8856606 				(stats + hn_stat_strings[t].offset);
798d30ea906Sjfb8856606 		}
7994b05018fSfengbojiang 	}
800d30ea906Sjfb8856606 
801d30ea906Sjfb8856606 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
802d30ea906Sjfb8856606 		const struct hn_rx_queue *rxq = dev->data->rx_queues[i];
803d30ea906Sjfb8856606 
804d30ea906Sjfb8856606 		if (!rxq)
805d30ea906Sjfb8856606 			continue;
806d30ea906Sjfb8856606 
807d30ea906Sjfb8856606 		stats = (const char *)&rxq->stats;
8084b05018fSfengbojiang 		for (t = 0; t < RTE_DIM(hn_stat_strings); t++, count++) {
8094b05018fSfengbojiang 			xstats[count].id = count;
8104b05018fSfengbojiang 			xstats[count].value = *(const uint64_t *)
811d30ea906Sjfb8856606 				(stats + hn_stat_strings[t].offset);
812d30ea906Sjfb8856606 		}
8134b05018fSfengbojiang 	}
814d30ea906Sjfb8856606 
8154b05018fSfengbojiang 	ret = hn_vf_xstats_get(dev, xstats, count, n);
816d30ea906Sjfb8856606 	if (ret < 0)
817d30ea906Sjfb8856606 		return ret;
818d30ea906Sjfb8856606 
819d30ea906Sjfb8856606 	return count + ret;
820d30ea906Sjfb8856606 }
821d30ea906Sjfb8856606 
822d30ea906Sjfb8856606 static int
hn_dev_start(struct rte_eth_dev * dev)823d30ea906Sjfb8856606 hn_dev_start(struct rte_eth_dev *dev)
824d30ea906Sjfb8856606 {
825d30ea906Sjfb8856606 	struct hn_data *hv = dev->data->dev_private;
826d30ea906Sjfb8856606 	int error;
827d30ea906Sjfb8856606 
828d30ea906Sjfb8856606 	PMD_INIT_FUNC_TRACE();
829d30ea906Sjfb8856606 
830d30ea906Sjfb8856606 	error = hn_rndis_set_rxfilter(hv,
831d30ea906Sjfb8856606 				      NDIS_PACKET_TYPE_BROADCAST |
832d30ea906Sjfb8856606 				      NDIS_PACKET_TYPE_ALL_MULTICAST |
833d30ea906Sjfb8856606 				      NDIS_PACKET_TYPE_DIRECTED);
834d30ea906Sjfb8856606 	if (error)
835d30ea906Sjfb8856606 		return error;
836d30ea906Sjfb8856606 
837d30ea906Sjfb8856606 	error = hn_vf_start(dev);
838d30ea906Sjfb8856606 	if (error)
839d30ea906Sjfb8856606 		hn_rndis_set_rxfilter(hv, 0);
840d30ea906Sjfb8856606 
8414418919fSjohnjiang 	/* Initialize Link state */
8424418919fSjohnjiang 	if (error == 0)
8434418919fSjohnjiang 		hn_dev_link_update(dev, 0);
8444418919fSjohnjiang 
845d30ea906Sjfb8856606 	return error;
846d30ea906Sjfb8856606 }
847d30ea906Sjfb8856606 
848*2d9fd380Sjfb8856606 static int
hn_dev_stop(struct rte_eth_dev * dev)849d30ea906Sjfb8856606 hn_dev_stop(struct rte_eth_dev *dev)
850d30ea906Sjfb8856606 {
851d30ea906Sjfb8856606 	struct hn_data *hv = dev->data->dev_private;
852d30ea906Sjfb8856606 
853d30ea906Sjfb8856606 	PMD_INIT_FUNC_TRACE();
854*2d9fd380Sjfb8856606 	dev->data->dev_started = 0;
855d30ea906Sjfb8856606 
856d30ea906Sjfb8856606 	hn_rndis_set_rxfilter(hv, 0);
857*2d9fd380Sjfb8856606 	return hn_vf_stop(dev);
858d30ea906Sjfb8856606 }
859d30ea906Sjfb8856606 
860*2d9fd380Sjfb8856606 static int
hn_dev_close(struct rte_eth_dev * dev)8614418919fSjohnjiang hn_dev_close(struct rte_eth_dev *dev)
862d30ea906Sjfb8856606 {
863*2d9fd380Sjfb8856606 	int ret;
864d30ea906Sjfb8856606 
865*2d9fd380Sjfb8856606 	PMD_INIT_FUNC_TRACE();
866*2d9fd380Sjfb8856606 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
867*2d9fd380Sjfb8856606 		return 0;
868*2d9fd380Sjfb8856606 
869*2d9fd380Sjfb8856606 	ret = hn_vf_close(dev);
8704418919fSjohnjiang 	hn_dev_free_queues(dev);
871*2d9fd380Sjfb8856606 
872*2d9fd380Sjfb8856606 	return ret;
873d30ea906Sjfb8856606 }
874d30ea906Sjfb8856606 
875d30ea906Sjfb8856606 static const struct eth_dev_ops hn_eth_dev_ops = {
876d30ea906Sjfb8856606 	.dev_configure		= hn_dev_configure,
877d30ea906Sjfb8856606 	.dev_start		= hn_dev_start,
878d30ea906Sjfb8856606 	.dev_stop		= hn_dev_stop,
879d30ea906Sjfb8856606 	.dev_close		= hn_dev_close,
880d30ea906Sjfb8856606 	.dev_infos_get		= hn_dev_info_get,
881*2d9fd380Sjfb8856606 	.txq_info_get		= hn_dev_tx_queue_info,
882*2d9fd380Sjfb8856606 	.rxq_info_get		= hn_dev_rx_queue_info,
883d30ea906Sjfb8856606 	.dev_supported_ptypes_get = hn_vf_supported_ptypes,
884d30ea906Sjfb8856606 	.promiscuous_enable     = hn_dev_promiscuous_enable,
885d30ea906Sjfb8856606 	.promiscuous_disable    = hn_dev_promiscuous_disable,
886d30ea906Sjfb8856606 	.allmulticast_enable    = hn_dev_allmulticast_enable,
887d30ea906Sjfb8856606 	.allmulticast_disable   = hn_dev_allmulticast_disable,
888d30ea906Sjfb8856606 	.set_mc_addr_list	= hn_dev_mc_addr_list,
8894418919fSjohnjiang 	.reta_update		= hn_rss_reta_update,
8904418919fSjohnjiang 	.reta_query             = hn_rss_reta_query,
8914418919fSjohnjiang 	.rss_hash_update	= hn_rss_hash_update,
8924418919fSjohnjiang 	.rss_hash_conf_get      = hn_rss_hash_conf_get,
893d30ea906Sjfb8856606 	.tx_queue_setup		= hn_dev_tx_queue_setup,
894d30ea906Sjfb8856606 	.tx_queue_release	= hn_dev_tx_queue_release,
895d30ea906Sjfb8856606 	.tx_done_cleanup        = hn_dev_tx_done_cleanup,
896d30ea906Sjfb8856606 	.rx_queue_setup		= hn_dev_rx_queue_setup,
897d30ea906Sjfb8856606 	.rx_queue_release	= hn_dev_rx_queue_release,
898d30ea906Sjfb8856606 	.link_update		= hn_dev_link_update,
899d30ea906Sjfb8856606 	.stats_get		= hn_dev_stats_get,
900d30ea906Sjfb8856606 	.stats_reset            = hn_dev_stats_reset,
901d30ea906Sjfb8856606 	.xstats_get		= hn_dev_xstats_get,
902d30ea906Sjfb8856606 	.xstats_get_names	= hn_dev_xstats_get_names,
903d30ea906Sjfb8856606 	.xstats_reset		= hn_dev_xstats_reset,
904d30ea906Sjfb8856606 };
905d30ea906Sjfb8856606 
906d30ea906Sjfb8856606 /*
907d30ea906Sjfb8856606  * Setup connection between PMD and kernel.
908d30ea906Sjfb8856606  */
909d30ea906Sjfb8856606 static int
hn_attach(struct hn_data * hv,unsigned int mtu)910d30ea906Sjfb8856606 hn_attach(struct hn_data *hv, unsigned int mtu)
911d30ea906Sjfb8856606 {
912d30ea906Sjfb8856606 	int error;
913d30ea906Sjfb8856606 
914d30ea906Sjfb8856606 	/* Attach NVS */
915d30ea906Sjfb8856606 	error = hn_nvs_attach(hv, mtu);
916d30ea906Sjfb8856606 	if (error)
917d30ea906Sjfb8856606 		goto failed_nvs;
918d30ea906Sjfb8856606 
919d30ea906Sjfb8856606 	/* Attach RNDIS */
920d30ea906Sjfb8856606 	error = hn_rndis_attach(hv);
921d30ea906Sjfb8856606 	if (error)
922d30ea906Sjfb8856606 		goto failed_rndis;
923d30ea906Sjfb8856606 
924d30ea906Sjfb8856606 	/*
925d30ea906Sjfb8856606 	 * NOTE:
926d30ea906Sjfb8856606 	 * Under certain conditions on certain versions of Hyper-V,
927d30ea906Sjfb8856606 	 * the RNDIS rxfilter is _not_ zero on the hypervisor side
928d30ea906Sjfb8856606 	 * after the successful RNDIS initialization.
929d30ea906Sjfb8856606 	 */
930d30ea906Sjfb8856606 	hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_NONE);
931d30ea906Sjfb8856606 	return 0;
932d30ea906Sjfb8856606 failed_rndis:
933d30ea906Sjfb8856606 	hn_nvs_detach(hv);
934d30ea906Sjfb8856606 failed_nvs:
935d30ea906Sjfb8856606 	return error;
936d30ea906Sjfb8856606 }
937d30ea906Sjfb8856606 
938d30ea906Sjfb8856606 static void
hn_detach(struct hn_data * hv)939d30ea906Sjfb8856606 hn_detach(struct hn_data *hv)
940d30ea906Sjfb8856606 {
941d30ea906Sjfb8856606 	hn_nvs_detach(hv);
942d30ea906Sjfb8856606 	hn_rndis_detach(hv);
943d30ea906Sjfb8856606 }
944d30ea906Sjfb8856606 
945d30ea906Sjfb8856606 static int
eth_hn_dev_init(struct rte_eth_dev * eth_dev)946d30ea906Sjfb8856606 eth_hn_dev_init(struct rte_eth_dev *eth_dev)
947d30ea906Sjfb8856606 {
948d30ea906Sjfb8856606 	struct hn_data *hv = eth_dev->data->dev_private;
949d30ea906Sjfb8856606 	struct rte_device *device = eth_dev->device;
950d30ea906Sjfb8856606 	struct rte_vmbus_device *vmbus;
951d30ea906Sjfb8856606 	unsigned int rxr_cnt;
952d30ea906Sjfb8856606 	int err, max_chan;
953d30ea906Sjfb8856606 
954d30ea906Sjfb8856606 	PMD_INIT_FUNC_TRACE();
955d30ea906Sjfb8856606 
956d30ea906Sjfb8856606 	vmbus = container_of(device, struct rte_vmbus_device, device);
957d30ea906Sjfb8856606 	eth_dev->dev_ops = &hn_eth_dev_ops;
958*2d9fd380Sjfb8856606 	eth_dev->rx_queue_count = hn_dev_rx_queue_count;
959*2d9fd380Sjfb8856606 	eth_dev->rx_descriptor_status = hn_dev_rx_queue_status;
960*2d9fd380Sjfb8856606 	eth_dev->tx_descriptor_status = hn_dev_tx_descriptor_status;
961d30ea906Sjfb8856606 	eth_dev->tx_pkt_burst = &hn_xmit_pkts;
962d30ea906Sjfb8856606 	eth_dev->rx_pkt_burst = &hn_recv_pkts;
963d30ea906Sjfb8856606 
964d30ea906Sjfb8856606 	/*
965d30ea906Sjfb8856606 	 * for secondary processes, we don't initialize any further as primary
966d30ea906Sjfb8856606 	 * has already done this work.
967d30ea906Sjfb8856606 	 */
968d30ea906Sjfb8856606 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
969d30ea906Sjfb8856606 		return 0;
970d30ea906Sjfb8856606 
971*2d9fd380Sjfb8856606 	eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
972*2d9fd380Sjfb8856606 
9730c6bd470Sfengbojiang 	/* Since Hyper-V only supports one MAC address */
9740c6bd470Sfengbojiang 	eth_dev->data->mac_addrs = rte_calloc("hv_mac", HN_MAX_MAC_ADDRS,
9750c6bd470Sfengbojiang 					      sizeof(struct rte_ether_addr), 0);
9760c6bd470Sfengbojiang 	if (eth_dev->data->mac_addrs == NULL) {
9770c6bd470Sfengbojiang 		PMD_INIT_LOG(ERR,
9780c6bd470Sfengbojiang 			     "Failed to allocate memory store MAC addresses");
9790c6bd470Sfengbojiang 		return -ENOMEM;
9800c6bd470Sfengbojiang 	}
9810c6bd470Sfengbojiang 
982d30ea906Sjfb8856606 	hv->vmbus = vmbus;
983d30ea906Sjfb8856606 	hv->rxbuf_res = &vmbus->resource[HV_RECV_BUF_MAP];
984d30ea906Sjfb8856606 	hv->chim_res  = &vmbus->resource[HV_SEND_BUF_MAP];
985d30ea906Sjfb8856606 	hv->port_id = eth_dev->data->port_id;
986d30ea906Sjfb8856606 	hv->latency = HN_CHAN_LATENCY_NS;
987*2d9fd380Sjfb8856606 	hv->rx_copybreak = HN_RXCOPY_THRESHOLD;
988*2d9fd380Sjfb8856606 	hv->tx_copybreak = HN_TXCOPY_THRESHOLD;
989*2d9fd380Sjfb8856606 	hv->rx_extmbuf_enable = HN_RX_EXTMBUF_ENABLE;
9901646932aSjfb8856606 	hv->max_queues = 1;
991*2d9fd380Sjfb8856606 
9920c6bd470Sfengbojiang 	rte_rwlock_init(&hv->vf_lock);
9931646932aSjfb8856606 	hv->vf_port = HN_INVALID_PORT;
994d30ea906Sjfb8856606 
995d30ea906Sjfb8856606 	err = hn_parse_args(eth_dev);
996d30ea906Sjfb8856606 	if (err)
997d30ea906Sjfb8856606 		return err;
998d30ea906Sjfb8856606 
999d30ea906Sjfb8856606 	strlcpy(hv->owner.name, eth_dev->device->name,
1000d30ea906Sjfb8856606 		RTE_ETH_MAX_OWNER_NAME_LEN);
1001d30ea906Sjfb8856606 	err = rte_eth_dev_owner_new(&hv->owner.id);
1002d30ea906Sjfb8856606 	if (err) {
1003d30ea906Sjfb8856606 		PMD_INIT_LOG(ERR, "Can not get owner id");
1004d30ea906Sjfb8856606 		return err;
1005d30ea906Sjfb8856606 	}
1006d30ea906Sjfb8856606 
1007d30ea906Sjfb8856606 	/* Initialize primary channel input for control operations */
1008d30ea906Sjfb8856606 	err = rte_vmbus_chan_open(vmbus, &hv->channels[0]);
1009d30ea906Sjfb8856606 	if (err)
1010d30ea906Sjfb8856606 		return err;
1011d30ea906Sjfb8856606 
1012d30ea906Sjfb8856606 	rte_vmbus_set_latency(hv->vmbus, hv->channels[0], hv->latency);
1013d30ea906Sjfb8856606 
1014d30ea906Sjfb8856606 	hv->primary = hn_rx_queue_alloc(hv, 0,
1015d30ea906Sjfb8856606 					eth_dev->device->numa_node);
1016d30ea906Sjfb8856606 
1017d30ea906Sjfb8856606 	if (!hv->primary)
1018d30ea906Sjfb8856606 		return -ENOMEM;
1019d30ea906Sjfb8856606 
10204418919fSjohnjiang 	err = hn_attach(hv, RTE_ETHER_MTU);
1021d30ea906Sjfb8856606 	if  (err)
1022d30ea906Sjfb8856606 		goto failed;
1023d30ea906Sjfb8856606 
10240c6bd470Sfengbojiang 	err = hn_chim_init(eth_dev);
1025d30ea906Sjfb8856606 	if (err)
1026d30ea906Sjfb8856606 		goto failed;
1027d30ea906Sjfb8856606 
10280c6bd470Sfengbojiang 	err = hn_rndis_get_eaddr(hv, eth_dev->data->mac_addrs->addr_bytes);
1029d30ea906Sjfb8856606 	if (err)
1030d30ea906Sjfb8856606 		goto failed;
1031d30ea906Sjfb8856606 
10321646932aSjfb8856606 	/* Multi queue requires later versions of windows server */
10331646932aSjfb8856606 	if (hv->nvs_ver < NVS_VERSION_5)
10341646932aSjfb8856606 		return 0;
10351646932aSjfb8856606 
1036d30ea906Sjfb8856606 	max_chan = rte_vmbus_max_channels(vmbus);
1037d30ea906Sjfb8856606 	PMD_INIT_LOG(DEBUG, "VMBus max channels %d", max_chan);
1038d30ea906Sjfb8856606 	if (max_chan <= 0)
1039d30ea906Sjfb8856606 		goto failed;
1040d30ea906Sjfb8856606 
1041d30ea906Sjfb8856606 	if (hn_rndis_query_rsscaps(hv, &rxr_cnt) != 0)
1042d30ea906Sjfb8856606 		rxr_cnt = 1;
1043d30ea906Sjfb8856606 
1044d30ea906Sjfb8856606 	hv->max_queues = RTE_MIN(rxr_cnt, (unsigned int)max_chan);
1045d30ea906Sjfb8856606 
1046d30ea906Sjfb8856606 	/* If VF was reported but not added, do it now */
10471646932aSjfb8856606 	if (hv->vf_present && !hn_vf_attached(hv)) {
1048d30ea906Sjfb8856606 		PMD_INIT_LOG(DEBUG, "Adding VF device");
1049d30ea906Sjfb8856606 
1050d30ea906Sjfb8856606 		err = hn_vf_add(eth_dev, hv);
1051d30ea906Sjfb8856606 		if (err)
10521646932aSjfb8856606 			hv->vf_present = 0;
1053d30ea906Sjfb8856606 	}
1054d30ea906Sjfb8856606 
1055d30ea906Sjfb8856606 	return 0;
1056d30ea906Sjfb8856606 
1057d30ea906Sjfb8856606 failed:
1058d30ea906Sjfb8856606 	PMD_INIT_LOG(NOTICE, "device init failed");
1059d30ea906Sjfb8856606 
10600c6bd470Sfengbojiang 	hn_chim_uninit(eth_dev);
1061d30ea906Sjfb8856606 	hn_detach(hv);
1062d30ea906Sjfb8856606 	return err;
1063d30ea906Sjfb8856606 }
1064d30ea906Sjfb8856606 
1065d30ea906Sjfb8856606 static int
eth_hn_dev_uninit(struct rte_eth_dev * eth_dev)1066d30ea906Sjfb8856606 eth_hn_dev_uninit(struct rte_eth_dev *eth_dev)
1067d30ea906Sjfb8856606 {
1068d30ea906Sjfb8856606 	struct hn_data *hv = eth_dev->data->dev_private;
1069*2d9fd380Sjfb8856606 	int ret, ret_stop;
1070d30ea906Sjfb8856606 
1071d30ea906Sjfb8856606 	PMD_INIT_FUNC_TRACE();
1072d30ea906Sjfb8856606 
1073d30ea906Sjfb8856606 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1074d30ea906Sjfb8856606 		return 0;
1075d30ea906Sjfb8856606 
1076*2d9fd380Sjfb8856606 	ret_stop = hn_dev_stop(eth_dev);
1077d30ea906Sjfb8856606 	hn_dev_close(eth_dev);
1078d30ea906Sjfb8856606 
1079d30ea906Sjfb8856606 	hn_detach(hv);
10800c6bd470Sfengbojiang 	hn_chim_uninit(eth_dev);
1081d30ea906Sjfb8856606 	rte_vmbus_chan_close(hv->primary->chan);
1082d30ea906Sjfb8856606 	rte_free(hv->primary);
10834418919fSjohnjiang 	ret = rte_eth_dev_owner_delete(hv->owner.id);
10844418919fSjohnjiang 	if (ret != 0)
10854418919fSjohnjiang 		return ret;
1086d30ea906Sjfb8856606 
1087*2d9fd380Sjfb8856606 	return ret_stop;
1088d30ea906Sjfb8856606 }
1089d30ea906Sjfb8856606 
eth_hn_probe(struct rte_vmbus_driver * drv __rte_unused,struct rte_vmbus_device * dev)1090d30ea906Sjfb8856606 static int eth_hn_probe(struct rte_vmbus_driver *drv __rte_unused,
1091d30ea906Sjfb8856606 			struct rte_vmbus_device *dev)
1092d30ea906Sjfb8856606 {
1093d30ea906Sjfb8856606 	struct rte_eth_dev *eth_dev;
1094d30ea906Sjfb8856606 	int ret;
1095d30ea906Sjfb8856606 
1096d30ea906Sjfb8856606 	PMD_INIT_FUNC_TRACE();
1097d30ea906Sjfb8856606 
1098d30ea906Sjfb8856606 	eth_dev = eth_dev_vmbus_allocate(dev, sizeof(struct hn_data));
1099d30ea906Sjfb8856606 	if (!eth_dev)
1100d30ea906Sjfb8856606 		return -ENOMEM;
1101d30ea906Sjfb8856606 
1102d30ea906Sjfb8856606 	ret = eth_hn_dev_init(eth_dev);
1103d30ea906Sjfb8856606 	if (ret)
1104d30ea906Sjfb8856606 		eth_dev_vmbus_release(eth_dev);
1105d30ea906Sjfb8856606 	else
1106d30ea906Sjfb8856606 		rte_eth_dev_probing_finish(eth_dev);
1107d30ea906Sjfb8856606 
1108d30ea906Sjfb8856606 	return ret;
1109d30ea906Sjfb8856606 }
1110d30ea906Sjfb8856606 
eth_hn_remove(struct rte_vmbus_device * dev)1111d30ea906Sjfb8856606 static int eth_hn_remove(struct rte_vmbus_device *dev)
1112d30ea906Sjfb8856606 {
1113d30ea906Sjfb8856606 	struct rte_eth_dev *eth_dev;
1114d30ea906Sjfb8856606 	int ret;
1115d30ea906Sjfb8856606 
1116d30ea906Sjfb8856606 	PMD_INIT_FUNC_TRACE();
1117d30ea906Sjfb8856606 
1118d30ea906Sjfb8856606 	eth_dev = rte_eth_dev_allocated(dev->device.name);
1119d30ea906Sjfb8856606 	if (!eth_dev)
1120*2d9fd380Sjfb8856606 		return 0; /* port already released */
1121d30ea906Sjfb8856606 
1122d30ea906Sjfb8856606 	ret = eth_hn_dev_uninit(eth_dev);
1123d30ea906Sjfb8856606 	if (ret)
1124d30ea906Sjfb8856606 		return ret;
1125d30ea906Sjfb8856606 
1126d30ea906Sjfb8856606 	eth_dev_vmbus_release(eth_dev);
1127d30ea906Sjfb8856606 	return 0;
1128d30ea906Sjfb8856606 }
1129d30ea906Sjfb8856606 
1130d30ea906Sjfb8856606 /* Network device GUID */
1131d30ea906Sjfb8856606 static const rte_uuid_t hn_net_ids[] = {
1132d30ea906Sjfb8856606 	/*  f8615163-df3e-46c5-913f-f2d2f965ed0e */
1133d30ea906Sjfb8856606 	RTE_UUID_INIT(0xf8615163, 0xdf3e, 0x46c5, 0x913f, 0xf2d2f965ed0eULL),
1134d30ea906Sjfb8856606 	{ 0 }
1135d30ea906Sjfb8856606 };
1136d30ea906Sjfb8856606 
1137d30ea906Sjfb8856606 static struct rte_vmbus_driver rte_netvsc_pmd = {
1138d30ea906Sjfb8856606 	.id_table = hn_net_ids,
1139d30ea906Sjfb8856606 	.probe = eth_hn_probe,
1140d30ea906Sjfb8856606 	.remove = eth_hn_remove,
1141d30ea906Sjfb8856606 };
1142d30ea906Sjfb8856606 
1143d30ea906Sjfb8856606 RTE_PMD_REGISTER_VMBUS(net_netvsc, rte_netvsc_pmd);
1144d30ea906Sjfb8856606 RTE_PMD_REGISTER_KMOD_DEP(net_netvsc, "* uio_hv_generic");
1145*2d9fd380Sjfb8856606 RTE_LOG_REGISTER(hn_logtype_init, pmd.net.netvsc.init, NOTICE);
1146*2d9fd380Sjfb8856606 RTE_LOG_REGISTER(hn_logtype_driver, pmd.net.netvsc.driver, NOTICE);
1147*2d9fd380Sjfb8856606 RTE_PMD_REGISTER_PARAM_STRING(net_netvsc,
1148*2d9fd380Sjfb8856606 			      NETVSC_ARG_LATENCY "=<uint32> "
1149*2d9fd380Sjfb8856606 			      NETVSC_ARG_RXBREAK "=<uint32> "
1150*2d9fd380Sjfb8856606 			      NETVSC_ARG_TXBREAK "=<uint32> "
1151*2d9fd380Sjfb8856606 			      NETVSC_ARG_RX_EXTMBUF_ENABLE "=<0|1>");
1152