Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2016-2018 Microsoft Corporation
3 : : * Copyright(c) 2013-2016 Brocade Communications Systems, Inc.
4 : : * All rights reserved.
5 : : */
6 : :
7 : : #include <stdint.h>
8 : : #include <string.h>
9 : : #include <stdio.h>
10 : : #include <errno.h>
11 : : #include <unistd.h>
12 : : #include <dirent.h>
13 : : #include <net/if.h>
14 : : #include <net/if_arp.h>
15 : : #include <netinet/in.h>
16 : : #include <sys/ioctl.h>
17 : :
18 : : #include <rte_ethdev.h>
19 : : #include <rte_memcpy.h>
20 : : #include <rte_string_fns.h>
21 : : #include <rte_memzone.h>
22 : : #include <rte_devargs.h>
23 : : #include <rte_malloc.h>
24 : : #include <rte_kvargs.h>
25 : : #include <rte_atomic.h>
26 : : #include <rte_branch_prediction.h>
27 : : #include <rte_ether.h>
28 : : #include <ethdev_driver.h>
29 : : #include <rte_cycles.h>
30 : : #include <rte_errno.h>
31 : : #include <rte_memory.h>
32 : : #include <rte_eal.h>
33 : : #include <dev_driver.h>
34 : : #include <bus_driver.h>
35 : : #include <bus_vmbus_driver.h>
36 : : #include <rte_alarm.h>
37 : :
38 : : #include "hn_logs.h"
39 : : #include "hn_var.h"
40 : : #include "hn_rndis.h"
41 : : #include "hn_nvs.h"
42 : : #include "ndis.h"
43 : :
44 : : #ifndef LIST_FOREACH_SAFE
45 : : #define LIST_FOREACH_SAFE(var, head, field, tvar) \
46 : : for ((var) = LIST_FIRST((head)); \
47 : : (var) && ((tvar) = LIST_NEXT((var), field), 1); \
48 : : (var) = (tvar))
49 : : #endif
50 : :
51 : : /* Spinlock for netvsc_shared_data */
52 : : static rte_spinlock_t netvsc_shared_data_lock = RTE_SPINLOCK_INITIALIZER;
53 : :
54 : : static struct netvsc_shared_data {
55 : : RTE_ATOMIC(uint32_t) secondary_cnt;
56 : : } *netvsc_shared_data;
57 : :
58 : : static const struct rte_memzone *netvsc_shared_mz;
59 : : #define MZ_NETVSC_SHARED_DATA "netvsc_shared_data"
60 : :
61 : : static struct netvsc_local_data {
62 : : bool init_done;
63 : : unsigned int primary_cnt;
64 : : unsigned int secondary_cnt;
65 : : } netvsc_local_data;
66 : :
67 : : #define NETVSC_MP_NAME "net_netvsc_mp"
68 : : #define NETVSC_MP_REQ_TIMEOUT_SEC 5
69 : :
70 : : struct netvsc_mp_param {
71 : : enum netvsc_mp_req_type type;
72 : : int vf_port;
73 : : int result;
74 : : };
75 : :
76 : : #define HN_TX_OFFLOAD_CAPS (RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | \
77 : : RTE_ETH_TX_OFFLOAD_TCP_CKSUM | \
78 : : RTE_ETH_TX_OFFLOAD_UDP_CKSUM | \
79 : : RTE_ETH_TX_OFFLOAD_TCP_TSO | \
80 : : RTE_ETH_TX_OFFLOAD_MULTI_SEGS | \
81 : : RTE_ETH_TX_OFFLOAD_VLAN_INSERT)
82 : :
83 : : #define HN_RX_OFFLOAD_CAPS (RTE_ETH_RX_OFFLOAD_CHECKSUM | \
84 : : RTE_ETH_RX_OFFLOAD_VLAN_STRIP | \
85 : : RTE_ETH_RX_OFFLOAD_RSS_HASH)
86 : :
87 : : #define NETVSC_ARG_LATENCY "latency"
88 : : #define NETVSC_ARG_RXBREAK "rx_copybreak"
89 : : #define NETVSC_ARG_TXBREAK "tx_copybreak"
90 : : #define NETVSC_ARG_RX_EXTMBUF_ENABLE "rx_extmbuf_enable"
91 : :
92 : : /* The max number of retry when hot adding a VF device */
93 : : #define NETVSC_MAX_HOTADD_RETRY 10
94 : :
95 : : struct hn_xstats_name_off {
96 : : char name[RTE_ETH_XSTATS_NAME_SIZE];
97 : : unsigned int offset;
98 : : };
99 : :
100 : : static const struct hn_xstats_name_off hn_stat_strings[] = {
101 : : { "good_packets", offsetof(struct hn_stats, packets) },
102 : : { "good_bytes", offsetof(struct hn_stats, bytes) },
103 : : { "errors", offsetof(struct hn_stats, errors) },
104 : : { "ring full", offsetof(struct hn_stats, ring_full) },
105 : : { "channel full", offsetof(struct hn_stats, channel_full) },
106 : : { "multicast_packets", offsetof(struct hn_stats, multicast) },
107 : : { "broadcast_packets", offsetof(struct hn_stats, broadcast) },
108 : : { "undersize_packets", offsetof(struct hn_stats, size_bins[0]) },
109 : : { "size_64_packets", offsetof(struct hn_stats, size_bins[1]) },
110 : : { "size_65_127_packets", offsetof(struct hn_stats, size_bins[2]) },
111 : : { "size_128_255_packets", offsetof(struct hn_stats, size_bins[3]) },
112 : : { "size_256_511_packets", offsetof(struct hn_stats, size_bins[4]) },
113 : : { "size_512_1023_packets", offsetof(struct hn_stats, size_bins[5]) },
114 : : { "size_1024_1518_packets", offsetof(struct hn_stats, size_bins[6]) },
115 : : { "size_1519_max_packets", offsetof(struct hn_stats, size_bins[7]) },
116 : : };
117 : :
118 : : /* The default RSS key.
119 : : * This value is the same as MLX5 so that flows will be
120 : : * received on same path for both VF and synthetic NIC.
121 : : */
122 : : static const uint8_t rss_default_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
123 : : 0x2c, 0xc6, 0x81, 0xd1, 0x5b, 0xdb, 0xf4, 0xf7,
124 : : 0xfc, 0xa2, 0x83, 0x19, 0xdb, 0x1a, 0x3e, 0x94,
125 : : 0x6b, 0x9e, 0x38, 0xd9, 0x2c, 0x9c, 0x03, 0xd1,
126 : : 0xad, 0x99, 0x44, 0xa7, 0xd9, 0x56, 0x3d, 0x59,
127 : : 0x06, 0x3c, 0x25, 0xf3, 0xfc, 0x1f, 0xdc, 0x2a,
128 : : };
129 : :
130 : : static rte_spinlock_t netvsc_lock = RTE_SPINLOCK_INITIALIZER;
131 : : struct da_cache {
132 : : LIST_ENTRY(da_cache) list;
133 : : char name[RTE_DEV_NAME_MAX_LEN];
134 : : char drv_str[];
135 : : };
136 : :
137 : : static LIST_HEAD(da_cache_list, da_cache) da_cache_list;
138 : : static unsigned int da_cache_usage;
139 : :
140 : : static struct rte_eth_dev *
141 : 0 : eth_dev_vmbus_allocate(struct rte_vmbus_device *dev, size_t private_data_size)
142 : : {
143 : : struct rte_eth_dev *eth_dev;
144 : : const char *name;
145 : :
146 [ # # ]: 0 : if (!dev)
147 : : return NULL;
148 : :
149 : 0 : name = dev->device.name;
150 : :
151 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
152 : 0 : eth_dev = rte_eth_dev_allocate(name);
153 [ # # ]: 0 : if (!eth_dev) {
154 : 0 : PMD_DRV_LOG(NOTICE, "can not allocate rte ethdev");
155 : 0 : return NULL;
156 : : }
157 : :
158 [ # # ]: 0 : if (private_data_size) {
159 : 0 : eth_dev->data->dev_private =
160 : 0 : rte_zmalloc_socket(name, private_data_size,
161 : : RTE_CACHE_LINE_SIZE, dev->device.numa_node);
162 [ # # ]: 0 : if (!eth_dev->data->dev_private) {
163 : 0 : PMD_DRV_LOG(NOTICE, "can not allocate driver data");
164 : 0 : rte_eth_dev_release_port(eth_dev);
165 : 0 : return NULL;
166 : : }
167 : : }
168 : : } else {
169 : 0 : eth_dev = rte_eth_dev_attach_secondary(name);
170 [ # # ]: 0 : if (!eth_dev) {
171 : 0 : PMD_DRV_LOG(NOTICE, "can not attach secondary");
172 : 0 : return NULL;
173 : : }
174 : : }
175 : :
176 : 0 : eth_dev->device = &dev->device;
177 : :
178 : : /* interrupt is simulated */
179 : 0 : rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_EXT);
180 : 0 : eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
181 : 0 : eth_dev->intr_handle = dev->intr_handle;
182 : :
183 : 0 : return eth_dev;
184 : : }
185 : :
186 : : static void
187 : : eth_dev_vmbus_release(struct rte_eth_dev *eth_dev)
188 : : {
189 : : /* free ether device */
190 : 0 : rte_eth_dev_release_port(eth_dev);
191 : :
192 : 0 : eth_dev->device = NULL;
193 : 0 : eth_dev->intr_handle = NULL;
194 : 0 : }
195 : :
196 : 0 : static int hn_set_parameter(const char *key, const char *value, void *opaque)
197 : : {
198 : : struct hn_data *hv = opaque;
199 : 0 : char *endp = NULL;
200 : : unsigned long v;
201 : :
202 : 0 : v = strtoul(value, &endp, 0);
203 [ # # # # ]: 0 : if (*value == '\0' || *endp != '\0') {
204 : 0 : PMD_DRV_LOG(ERR, "invalid parameter %s=%s", key, value);
205 : 0 : return -EINVAL;
206 : : }
207 : :
208 [ # # ]: 0 : if (!strcmp(key, NETVSC_ARG_LATENCY)) {
209 : : /* usec to nsec */
210 : 0 : hv->latency = v * 1000;
211 : 0 : PMD_DRV_LOG(DEBUG, "set latency %u usec", hv->latency);
212 [ # # ]: 0 : } else if (!strcmp(key, NETVSC_ARG_RXBREAK)) {
213 : 0 : hv->rx_copybreak = v;
214 : 0 : PMD_DRV_LOG(DEBUG, "rx copy break set to %u",
215 : : hv->rx_copybreak);
216 [ # # ]: 0 : } else if (!strcmp(key, NETVSC_ARG_TXBREAK)) {
217 : 0 : hv->tx_copybreak = v;
218 : 0 : PMD_DRV_LOG(DEBUG, "tx copy break set to %u",
219 : : hv->tx_copybreak);
220 [ # # ]: 0 : } else if (!strcmp(key, NETVSC_ARG_RX_EXTMBUF_ENABLE)) {
221 : 0 : hv->rx_extmbuf_enable = v;
222 : 0 : PMD_DRV_LOG(DEBUG, "rx extmbuf enable set to %u",
223 : : hv->rx_extmbuf_enable);
224 : : }
225 : :
226 : : return 0;
227 : : }
228 : :
229 : : /* Parse device arguments */
230 : 0 : static int hn_parse_args(const struct rte_eth_dev *dev)
231 : : {
232 : 0 : struct hn_data *hv = dev->data->dev_private;
233 : 0 : struct rte_devargs *devargs = dev->device->devargs;
234 : : static const char * const valid_keys[] = {
235 : : NETVSC_ARG_LATENCY,
236 : : NETVSC_ARG_RXBREAK,
237 : : NETVSC_ARG_TXBREAK,
238 : : NETVSC_ARG_RX_EXTMBUF_ENABLE,
239 : : NETVSC_ARG_NUMA_AWARE,
240 : : NULL
241 : : };
242 : : struct rte_kvargs *kvlist;
243 : : int ret;
244 : :
245 [ # # ]: 0 : if (!devargs)
246 : : return 0;
247 : :
248 : 0 : PMD_INIT_LOG(DEBUG, "device args %s %s",
249 : : devargs->name, devargs->args);
250 : :
251 : 0 : kvlist = rte_kvargs_parse(devargs->args, valid_keys);
252 [ # # ]: 0 : if (!kvlist) {
253 : 0 : PMD_DRV_LOG(ERR, "invalid parameters");
254 : 0 : return -EINVAL;
255 : : }
256 : :
257 : 0 : ret = rte_kvargs_process(kvlist, NULL, hn_set_parameter, hv);
258 : 0 : rte_kvargs_free(kvlist);
259 : :
260 : 0 : return ret;
261 : : }
262 : :
263 : : /* Update link status.
264 : : * Note: the DPDK definition of "wait_to_complete"
265 : : * means block this call until link is up.
266 : : * which is not worth supporting.
267 : : */
268 : : int
269 : 0 : hn_dev_link_update(struct rte_eth_dev *dev,
270 : : int wait_to_complete __rte_unused)
271 : : {
272 : 0 : struct hn_data *hv = dev->data->dev_private;
273 : : struct rte_eth_link link, old;
274 : : int error;
275 : :
276 : 0 : old = dev->data->dev_link;
277 : :
278 : 0 : error = hn_rndis_get_linkstatus(hv);
279 [ # # ]: 0 : if (error)
280 : : return error;
281 : :
282 : 0 : hn_rndis_get_linkspeed(hv);
283 : :
284 : 0 : link = (struct rte_eth_link) {
285 : : .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
286 : : .link_autoneg = RTE_ETH_LINK_SPEED_FIXED,
287 : 0 : .link_speed = hv->link_speed / 10000,
288 : : };
289 : :
290 [ # # ]: 0 : if (hv->link_status == NDIS_MEDIA_STATE_CONNECTED)
291 : 0 : link.link_status = RTE_ETH_LINK_UP;
292 : : else
293 : : link.link_status = RTE_ETH_LINK_DOWN;
294 : :
295 [ # # ]: 0 : if (old.link_status == link.link_status)
296 : : return 0;
297 : :
298 [ # # ]: 0 : PMD_INIT_LOG(DEBUG, "Port %d is %s", dev->data->port_id,
299 : : (link.link_status == RTE_ETH_LINK_UP) ? "up" : "down");
300 : :
301 : : return rte_eth_linkstatus_set(dev, &link);
302 : : }
303 : :
304 : 0 : static int hn_dev_info_get(struct rte_eth_dev *dev,
305 : : struct rte_eth_dev_info *dev_info)
306 : : {
307 : 0 : struct hn_data *hv = dev->data->dev_private;
308 : : int rc;
309 : :
310 : 0 : dev_info->speed_capa = RTE_ETH_LINK_SPEED_10G;
311 : 0 : dev_info->min_rx_bufsize = HN_MIN_RX_BUF_SIZE;
312 : 0 : dev_info->max_rx_pktlen = HN_MAX_XFER_LEN;
313 : 0 : dev_info->max_mac_addrs = 1;
314 : :
315 : 0 : dev_info->hash_key_size = NDIS_HASH_KEYSIZE_TOEPLITZ;
316 : 0 : dev_info->flow_type_rss_offloads = hv->rss_offloads;
317 : 0 : dev_info->reta_size = RTE_ETH_RSS_RETA_SIZE_128;
318 : :
319 : 0 : dev_info->max_rx_queues = hv->max_queues;
320 : 0 : dev_info->max_tx_queues = hv->max_queues;
321 : :
322 : 0 : dev_info->tx_desc_lim.nb_min = 1;
323 : 0 : dev_info->tx_desc_lim.nb_max = 4096;
324 : :
325 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
326 : : return 0;
327 : :
328 : : /* fills in rx and tx offload capability */
329 : 0 : rc = hn_rndis_get_offload(hv, dev_info);
330 [ # # ]: 0 : if (rc != 0)
331 : : return rc;
332 : :
333 : : /* merges the offload and queues of vf */
334 : 0 : return hn_vf_info_get(hv, dev_info);
335 : : }
336 : :
337 : 0 : static int hn_rss_reta_update(struct rte_eth_dev *dev,
338 : : struct rte_eth_rss_reta_entry64 *reta_conf,
339 : : uint16_t reta_size)
340 : : {
341 : 0 : struct hn_data *hv = dev->data->dev_private;
342 : : unsigned int i;
343 : : int err;
344 : :
345 : 0 : PMD_INIT_FUNC_TRACE();
346 : :
347 [ # # ]: 0 : if (reta_size != NDIS_HASH_INDCNT) {
348 : 0 : PMD_DRV_LOG(ERR, "Hash lookup table size does not match NDIS");
349 : 0 : return -EINVAL;
350 : : }
351 : :
352 [ # # ]: 0 : for (i = 0; i < NDIS_HASH_INDCNT; i++) {
353 : 0 : uint16_t idx = i / RTE_ETH_RETA_GROUP_SIZE;
354 : 0 : uint16_t shift = i % RTE_ETH_RETA_GROUP_SIZE;
355 : 0 : uint64_t mask = (uint64_t)1 << shift;
356 : :
357 [ # # ]: 0 : if (reta_conf[idx].mask & mask)
358 : 0 : hv->rss_ind[i] = reta_conf[idx].reta[shift];
359 : :
360 : : /*
361 : : * Ensure we don't allow config that directs traffic to an Rx
362 : : * queue that we aren't going to poll
363 : : */
364 [ # # ]: 0 : if (hv->rss_ind[i] >= dev->data->nb_rx_queues) {
365 : 0 : PMD_DRV_LOG(ERR, "RSS distributing traffic to invalid Rx queue");
366 : 0 : return -EINVAL;
367 : : }
368 : : }
369 : :
370 : 0 : err = hn_rndis_conf_rss(hv, NDIS_RSS_FLAG_DISABLE);
371 [ # # ]: 0 : if (err) {
372 : 0 : PMD_DRV_LOG(NOTICE,
373 : : "rss disable failed");
374 : 0 : return err;
375 : : }
376 : :
377 : 0 : err = hn_rndis_conf_rss(hv, 0);
378 [ # # ]: 0 : if (err) {
379 : 0 : PMD_DRV_LOG(NOTICE,
380 : : "reta reconfig failed");
381 : 0 : return err;
382 : : }
383 : :
384 : 0 : return hn_vf_reta_hash_update(dev, reta_conf, reta_size);
385 : : }
386 : :
387 : 0 : static int hn_rss_reta_query(struct rte_eth_dev *dev,
388 : : struct rte_eth_rss_reta_entry64 *reta_conf,
389 : : uint16_t reta_size)
390 : : {
391 : 0 : struct hn_data *hv = dev->data->dev_private;
392 : : unsigned int i;
393 : :
394 : 0 : PMD_INIT_FUNC_TRACE();
395 : :
396 [ # # ]: 0 : if (reta_size != NDIS_HASH_INDCNT) {
397 : 0 : PMD_DRV_LOG(ERR, "Hash lookup table size does not match NDIS");
398 : 0 : return -EINVAL;
399 : : }
400 : :
401 [ # # ]: 0 : for (i = 0; i < NDIS_HASH_INDCNT; i++) {
402 : 0 : uint16_t idx = i / RTE_ETH_RETA_GROUP_SIZE;
403 : 0 : uint16_t shift = i % RTE_ETH_RETA_GROUP_SIZE;
404 : 0 : uint64_t mask = (uint64_t)1 << shift;
405 : :
406 [ # # ]: 0 : if (reta_conf[idx].mask & mask)
407 : 0 : reta_conf[idx].reta[shift] = hv->rss_ind[i];
408 : : }
409 : : return 0;
410 : : }
411 : :
412 : 0 : static void hn_rss_hash_init(struct hn_data *hv,
413 : : const struct rte_eth_rss_conf *rss_conf)
414 : : {
415 : : /* Convert from DPDK RSS hash flags to NDIS hash flags */
416 : 0 : hv->rss_hash = NDIS_HASH_FUNCTION_TOEPLITZ;
417 : :
418 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_IPV4)
419 : 0 : hv->rss_hash |= NDIS_HASH_IPV4;
420 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_TCP)
421 : 0 : hv->rss_hash |= NDIS_HASH_TCP_IPV4;
422 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_IPV6)
423 : 0 : hv->rss_hash |= NDIS_HASH_IPV6;
424 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_IPV6_EX)
425 : 0 : hv->rss_hash |= NDIS_HASH_IPV6_EX;
426 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP)
427 : 0 : hv->rss_hash |= NDIS_HASH_TCP_IPV6;
428 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_IPV6_TCP_EX)
429 : 0 : hv->rss_hash |= NDIS_HASH_TCP_IPV6_EX;
430 : :
431 [ # # ]: 0 : memcpy(hv->rss_key, rss_conf->rss_key ? : rss_default_key,
432 : : NDIS_HASH_KEYSIZE_TOEPLITZ);
433 : 0 : }
434 : :
435 : 0 : static int hn_rss_hash_update(struct rte_eth_dev *dev,
436 : : struct rte_eth_rss_conf *rss_conf)
437 : : {
438 : 0 : struct hn_data *hv = dev->data->dev_private;
439 : : int err;
440 : :
441 : 0 : PMD_INIT_FUNC_TRACE();
442 : :
443 : 0 : err = hn_rndis_conf_rss(hv, NDIS_RSS_FLAG_DISABLE);
444 [ # # ]: 0 : if (err) {
445 : 0 : PMD_DRV_LOG(NOTICE,
446 : : "rss disable failed");
447 : 0 : return err;
448 : : }
449 : :
450 : 0 : hn_rss_hash_init(hv, rss_conf);
451 : :
452 [ # # ]: 0 : if (rss_conf->rss_hf != 0) {
453 : 0 : err = hn_rndis_conf_rss(hv, 0);
454 [ # # ]: 0 : if (err) {
455 : 0 : PMD_DRV_LOG(NOTICE,
456 : : "rss reconfig failed (RSS disabled)");
457 : 0 : return err;
458 : : }
459 : : }
460 : :
461 : 0 : return hn_vf_rss_hash_update(dev, rss_conf);
462 : : }
463 : :
464 : 0 : static int hn_rss_hash_conf_get(struct rte_eth_dev *dev,
465 : : struct rte_eth_rss_conf *rss_conf)
466 : : {
467 : 0 : struct hn_data *hv = dev->data->dev_private;
468 : :
469 : 0 : PMD_INIT_FUNC_TRACE();
470 : :
471 [ # # ]: 0 : if (hv->ndis_ver < NDIS_VERSION_6_20) {
472 : 0 : PMD_DRV_LOG(DEBUG, "RSS not supported on this host");
473 : 0 : return -EOPNOTSUPP;
474 : : }
475 : :
476 : 0 : rss_conf->rss_key_len = NDIS_HASH_KEYSIZE_TOEPLITZ;
477 [ # # ]: 0 : if (rss_conf->rss_key)
478 : 0 : memcpy(rss_conf->rss_key, hv->rss_key,
479 : : NDIS_HASH_KEYSIZE_TOEPLITZ);
480 : :
481 : 0 : rss_conf->rss_hf = 0;
482 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_IPV4)
483 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_IPV4;
484 : :
485 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_TCP_IPV4)
486 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_NONFRAG_IPV4_TCP;
487 : :
488 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_IPV6)
489 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_IPV6;
490 : :
491 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_IPV6_EX)
492 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_IPV6_EX;
493 : :
494 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_TCP_IPV6)
495 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_NONFRAG_IPV6_TCP;
496 : :
497 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_TCP_IPV6_EX)
498 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_IPV6_TCP_EX;
499 : :
500 : : return 0;
501 : : }
502 : :
503 : : static int
504 : 0 : hn_dev_promiscuous_enable(struct rte_eth_dev *dev)
505 : : {
506 : 0 : struct hn_data *hv = dev->data->dev_private;
507 : :
508 : 0 : hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_PROMISCUOUS);
509 : 0 : return hn_vf_promiscuous_enable(dev);
510 : : }
511 : :
512 : : static int
513 : 0 : hn_dev_promiscuous_disable(struct rte_eth_dev *dev)
514 : : {
515 : 0 : struct hn_data *hv = dev->data->dev_private;
516 : : uint32_t filter;
517 : :
518 : : filter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST;
519 [ # # ]: 0 : if (dev->data->all_multicast)
520 : : filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
521 : 0 : hn_rndis_set_rxfilter(hv, filter);
522 : 0 : return hn_vf_promiscuous_disable(dev);
523 : : }
524 : :
525 : : static int
526 : 0 : hn_dev_allmulticast_enable(struct rte_eth_dev *dev)
527 : : {
528 : 0 : struct hn_data *hv = dev->data->dev_private;
529 : :
530 : 0 : hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_DIRECTED |
531 : : NDIS_PACKET_TYPE_ALL_MULTICAST |
532 : : NDIS_PACKET_TYPE_BROADCAST);
533 : 0 : return hn_vf_allmulticast_enable(dev);
534 : : }
535 : :
536 : : static int
537 : 0 : hn_dev_allmulticast_disable(struct rte_eth_dev *dev)
538 : : {
539 : 0 : struct hn_data *hv = dev->data->dev_private;
540 : :
541 : 0 : hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_DIRECTED |
542 : : NDIS_PACKET_TYPE_BROADCAST);
543 : 0 : return hn_vf_allmulticast_disable(dev);
544 : : }
545 : :
546 : : static int
547 : 0 : hn_dev_mc_addr_list(struct rte_eth_dev *dev,
548 : : struct rte_ether_addr *mc_addr_set,
549 : : uint32_t nb_mc_addr)
550 : : {
551 : : /* No filtering on the synthetic path, but can do it on VF */
552 : 0 : return hn_vf_mc_addr_list(dev, mc_addr_set, nb_mc_addr);
553 : : }
554 : :
555 : : /* Setup shared rx/tx queue data */
556 : 0 : static int hn_subchan_configure(struct hn_data *hv,
557 : : uint32_t subchan)
558 : : {
559 : : struct vmbus_channel *primary = hn_primary_chan(hv);
560 : : int err;
561 : : unsigned int retry = 0;
562 : :
563 : 0 : PMD_DRV_LOG(DEBUG,
564 : : "open %u subchannels", subchan);
565 : :
566 : : /* Send create sub channels command */
567 : 0 : err = hn_nvs_alloc_subchans(hv, &subchan);
568 [ # # ]: 0 : if (err)
569 : : return err;
570 : :
571 [ # # ]: 0 : while (subchan > 0) {
572 : : struct vmbus_channel *new_sc;
573 : : uint16_t chn_index;
574 : :
575 : 0 : err = rte_vmbus_subchan_open(primary, &new_sc);
576 [ # # # # ]: 0 : if (err == -ENOENT && ++retry < 1000) {
577 : : /* This can happen if not ready yet */
578 : : rte_delay_ms(10);
579 : 0 : continue;
580 : : }
581 : :
582 [ # # ]: 0 : if (err) {
583 : 0 : PMD_DRV_LOG(ERR,
584 : : "open subchannel failed: %d", err);
585 : 0 : return err;
586 : : }
587 : :
588 : 0 : rte_vmbus_set_latency(hv->vmbus, new_sc, hv->latency);
589 : :
590 : : retry = 0;
591 : 0 : chn_index = rte_vmbus_sub_channel_index(new_sc);
592 [ # # # # ]: 0 : if (chn_index == 0 || chn_index > hv->max_queues) {
593 : 0 : PMD_DRV_LOG(ERR,
594 : : "Invalid subchannel offermsg channel %u",
595 : : chn_index);
596 : 0 : return -EIO;
597 : : }
598 : :
599 : 0 : PMD_DRV_LOG(DEBUG, "new sub channel %u", chn_index);
600 : 0 : hv->channels[chn_index] = new_sc;
601 : 0 : --subchan;
602 : : }
603 : :
604 : : return err;
605 : : }
606 : :
607 : 0 : static void netvsc_hotplug_retry(void *args)
608 : : {
609 : : int ret;
610 : : struct hv_hotadd_context *hot_ctx = args;
611 : 0 : struct hn_data *hv = hot_ctx->hv;
612 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[hv->port_id];
613 : 0 : struct rte_devargs *d = &hot_ctx->da;
614 : : char buf[256];
615 : :
616 : : DIR *di = NULL;
617 : : struct dirent *dir;
618 : : struct ifreq req;
619 : : struct rte_ether_addr eth_addr;
620 : : int s;
621 : :
622 : 0 : PMD_DRV_LOG(DEBUG, "%s: retry count %d",
623 : : __func__, hot_ctx->eal_hot_plug_retry);
624 : :
625 [ # # ]: 0 : if (hot_ctx->eal_hot_plug_retry++ > NETVSC_MAX_HOTADD_RETRY) {
626 : 0 : PMD_DRV_LOG(NOTICE, "Failed to parse PCI device retry=%d",
627 : : hot_ctx->eal_hot_plug_retry);
628 : 0 : goto free_hotadd_ctx;
629 : : }
630 : :
631 : 0 : snprintf(buf, sizeof(buf), "/sys/bus/pci/devices/%s/net", d->name);
632 : 0 : di = opendir(buf);
633 [ # # ]: 0 : if (!di) {
634 : 0 : PMD_DRV_LOG(DEBUG, "%s: can't open directory %s, "
635 : : "retrying in 1 second", __func__, buf);
636 : : /* The device is still being initialized, retry after 1 second */
637 : 0 : rte_eal_alarm_set(1000000, netvsc_hotplug_retry, hot_ctx);
638 : 0 : return;
639 : : }
640 : :
641 [ # # ]: 0 : while ((dir = readdir(di))) {
642 : : /* Skip . and .. directories */
643 [ # # # # ]: 0 : if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
644 : 0 : continue;
645 : :
646 : : /* trying to get mac address if this is a network device*/
647 : 0 : s = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
648 [ # # ]: 0 : if (s == -1) {
649 : 0 : PMD_DRV_LOG(ERR, "Failed to create socket errno %d",
650 : : errno);
651 : 0 : break;
652 : : }
653 : : strlcpy(req.ifr_name, dir->d_name, sizeof(req.ifr_name));
654 : 0 : ret = ioctl(s, SIOCGIFHWADDR, &req);
655 : 0 : close(s);
656 [ # # ]: 0 : if (ret == -1) {
657 : 0 : PMD_DRV_LOG(ERR,
658 : : "Failed to send SIOCGIFHWADDR for device %s",
659 : : dir->d_name);
660 : 0 : break;
661 : : }
662 [ # # ]: 0 : if (req.ifr_hwaddr.sa_family != ARPHRD_ETHER)
663 : 0 : continue;
664 : :
665 : : memcpy(eth_addr.addr_bytes, req.ifr_hwaddr.sa_data,
666 : : RTE_DIM(eth_addr.addr_bytes));
667 : :
668 [ # # ]: 0 : if (rte_is_same_ether_addr(ð_addr, dev->data->mac_addrs)) {
669 : : struct da_cache *cache;
670 : : char *drv_str = NULL;
671 : :
672 : : rte_spinlock_lock(&netvsc_lock);
673 : :
674 [ # # ]: 0 : LIST_FOREACH(cache, &da_cache_list, list) {
675 [ # # ]: 0 : if (strcmp(cache->name, d->name) == 0)
676 : : break;
677 : : }
678 : :
679 [ # # ]: 0 : if (cache)
680 : 0 : drv_str = strdup(cache->drv_str);
681 : :
682 : : rte_spinlock_unlock(&netvsc_lock);
683 : :
684 [ # # ]: 0 : PMD_DRV_LOG(NOTICE,
685 : : "Found matching MAC address, adding device %s network name %s args %s",
686 : : d->name, dir->d_name, drv_str ? drv_str : "");
687 : :
688 : : /* If this device has been hot removed from this
689 : : * parent device, restore its args.
690 : : */
691 : 0 : ret = rte_eal_hotplug_add(d->bus->name, d->name, drv_str ? drv_str : "");
692 [ # # ]: 0 : if (ret) {
693 : 0 : PMD_DRV_LOG(ERR,
694 : : "Failed to add PCI device %s",
695 : : d->name);
696 : : }
697 : :
698 : 0 : free(drv_str);
699 : :
700 : 0 : ret = hn_vf_add(dev, hv);
701 [ # # ]: 0 : if (ret)
702 : 0 : PMD_DRV_LOG(ERR, "Failed to add VF in hotplug retry: %d", ret);
703 : : break;
704 : : }
705 : : }
706 : :
707 : 0 : free_hotadd_ctx:
708 : : if (di)
709 : 0 : closedir(di);
710 : :
711 : 0 : rte_spinlock_lock(&hv->hotadd_lock);
712 [ # # ]: 0 : LIST_REMOVE(hot_ctx, list);
713 : : rte_spinlock_unlock(&hv->hotadd_lock);
714 : :
715 : 0 : rte_devargs_reset(d);
716 : 0 : free(hot_ctx);
717 : : }
718 : :
719 : : static void
720 : 0 : netvsc_hotadd_callback(const char *device_name, enum rte_dev_event_type type,
721 : : void *arg)
722 : : {
723 : : struct hn_data *hv = arg;
724 : : struct hv_hotadd_context *hot_ctx;
725 : : struct rte_devargs *d;
726 : : int ret;
727 : :
728 : 0 : PMD_DRV_LOG(INFO, "Device notification type=%d device_name=%s",
729 : : type, device_name);
730 : :
731 [ # # ]: 0 : switch (type) {
732 : 0 : case RTE_DEV_EVENT_ADD:
733 : : /* if we already has a VF, don't check on hot add */
734 [ # # ]: 0 : if (hv->vf_ctx.vf_state > vf_removed)
735 : : break;
736 : :
737 : 0 : hot_ctx = calloc(1, sizeof(*hot_ctx));
738 : :
739 [ # # ]: 0 : if (!hot_ctx) {
740 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate hotadd context");
741 : 0 : return;
742 : : }
743 : :
744 : 0 : hot_ctx->hv = hv;
745 : 0 : d = &hot_ctx->da;
746 : :
747 : 0 : ret = rte_devargs_parse(d, device_name);
748 [ # # ]: 0 : if (ret) {
749 : 0 : PMD_DRV_LOG(ERR,
750 : : "devargs parsing failed ret=%d", ret);
751 : 0 : goto free_ctx;
752 : : }
753 : :
754 [ # # ]: 0 : if (!strcmp(d->bus->name, "pci")) {
755 : : /* Start the process of figuring out if this
756 : : * PCI device is a VF device
757 : : */
758 : 0 : rte_spinlock_lock(&hv->hotadd_lock);
759 [ # # ]: 0 : LIST_INSERT_HEAD(&hv->hotadd_list, hot_ctx, list);
760 : : rte_spinlock_unlock(&hv->hotadd_lock);
761 : 0 : rte_eal_alarm_set(1000000, netvsc_hotplug_retry, hot_ctx);
762 : 0 : return;
763 : : }
764 : :
765 : : /* We will switch to VF on RDNIS configure message
766 : : * sent from VSP
767 : : */
768 : 0 : free_ctx:
769 : 0 : free(hot_ctx);
770 : 0 : break;
771 : :
772 : : default:
773 : : break;
774 : : }
775 : : }
776 : :
777 : : static void hn_detach(struct hn_data *hv);
778 : : static int hn_attach(struct hn_data *hv, unsigned int mtu);
779 : :
780 : 0 : static int hn_dev_configure(struct rte_eth_dev *dev)
781 : : {
782 : 0 : struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
783 : 0 : struct rte_eth_rss_conf *rss_conf = &dev_conf->rx_adv_conf.rss_conf;
784 : : const struct rte_eth_rxmode *rxmode = &dev_conf->rxmode;
785 : : const struct rte_eth_txmode *txmode = &dev_conf->txmode;
786 : 0 : struct hn_data *hv = dev->data->dev_private;
787 : : uint64_t unsupported;
788 : : int i, err, subchan;
789 : : uint32_t old_subchans = 0;
790 : : bool device_unmapped = false;
791 : :
792 : 0 : PMD_INIT_FUNC_TRACE();
793 : :
794 [ # # ]: 0 : if (dev_conf->rxmode.mq_mode & RTE_ETH_MQ_RX_RSS_FLAG)
795 : 0 : dev_conf->rxmode.offloads |= RTE_ETH_RX_OFFLOAD_RSS_HASH;
796 : :
797 : 0 : unsupported = txmode->offloads & ~HN_TX_OFFLOAD_CAPS;
798 [ # # ]: 0 : if (unsupported) {
799 : 0 : PMD_DRV_LOG(NOTICE,
800 : : "unsupported TX offload: %#" PRIx64,
801 : : unsupported);
802 : 0 : return -EINVAL;
803 : : }
804 : :
805 : 0 : unsupported = rxmode->offloads & ~HN_RX_OFFLOAD_CAPS;
806 [ # # ]: 0 : if (unsupported) {
807 : 0 : PMD_DRV_LOG(NOTICE,
808 : : "unsupported RX offload: %#" PRIx64,
809 : : rxmode->offloads);
810 : 0 : return -EINVAL;
811 : : }
812 : :
813 : 0 : hv->vlan_strip = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_STRIP);
814 : :
815 : : /* If queue count unchanged, skip subchannel teardown/reinit */
816 : 0 : if (RTE_MAX(dev->data->nb_rx_queues,
817 [ # # ]: 0 : dev->data->nb_tx_queues) == hv->num_queues)
818 : 0 : goto skip_reinit;
819 : :
820 : 0 : hv->num_queues = RTE_MAX(dev->data->nb_rx_queues,
821 : : dev->data->nb_tx_queues);
822 : :
823 : : /* Close all existing subchannels */
824 [ # # ]: 0 : for (i = 1; i < HN_MAX_CHANNELS; i++) {
825 [ # # ]: 0 : if (hv->channels[i] != NULL) {
826 : 0 : rte_vmbus_chan_close(hv->channels[i]);
827 : 0 : hv->channels[i] = NULL;
828 : 0 : old_subchans++;
829 : : }
830 : : }
831 : :
832 : : /*
833 : : * If subchannels existed, do a full NVS/RNDIS teardown
834 : : * and vmbus re-init to ensure a clean NVS session.
835 : : * Cannot re-send NVS subchannel request on the same
836 : : * session without invalidating the data path.
837 : : */
838 [ # # ]: 0 : if (old_subchans > 0) {
839 : 0 : PMD_DRV_LOG(NOTICE,
840 : : "reinit NVS (had %u subchannels)",
841 : : old_subchans);
842 : :
843 : 0 : hn_chim_uninit(dev);
844 : 0 : rte_free(hv->primary->rxbuf_info);
845 : 0 : hv->primary->rxbuf_info = NULL;
846 : : hn_detach(hv);
847 : :
848 : 0 : rte_vmbus_chan_close(hv->channels[0]);
849 : 0 : rte_free(hv->channels[0]);
850 : 0 : hv->channels[0] = NULL;
851 : :
852 : 0 : rte_vmbus_unmap_device(hv->vmbus);
853 : : device_unmapped = true;
854 : 0 : err = rte_vmbus_map_device(hv->vmbus);
855 [ # # ]: 0 : if (err) {
856 : 0 : PMD_DRV_LOG(ERR,
857 : : "Could not re-map vmbus device!");
858 : 0 : goto reinit_failed;
859 : : }
860 : : device_unmapped = false;
861 : :
862 : 0 : hv->rxbuf_res = hv->vmbus->resource[HV_RECV_BUF_MAP];
863 : 0 : hv->chim_res = hv->vmbus->resource[HV_SEND_BUF_MAP];
864 : :
865 : 0 : err = rte_vmbus_chan_open(hv->vmbus, &hv->channels[0]);
866 [ # # ]: 0 : if (err) {
867 : 0 : PMD_DRV_LOG(ERR,
868 : : "Could not re-open vmbus channel!");
869 : 0 : goto reinit_failed;
870 : : }
871 : :
872 : 0 : hv->primary->chan = hv->channels[0];
873 : :
874 : 0 : rte_vmbus_set_latency(hv->vmbus, hv->channels[0],
875 : : hv->latency);
876 : :
877 : 0 : err = hn_attach(hv, dev->data->mtu);
878 [ # # ]: 0 : if (err) {
879 : 0 : rte_vmbus_chan_close(hv->channels[0]);
880 : 0 : rte_free(hv->channels[0]);
881 : 0 : hv->channels[0] = NULL;
882 : 0 : PMD_DRV_LOG(ERR,
883 : : "NVS reinit failed: %d", err);
884 : 0 : goto reinit_failed;
885 : : }
886 : :
887 : 0 : err = hn_chim_init(dev);
888 [ # # ]: 0 : if (err) {
889 : : hn_detach(hv);
890 : 0 : rte_vmbus_chan_close(hv->channels[0]);
891 : 0 : rte_free(hv->channels[0]);
892 : 0 : hv->channels[0] = NULL;
893 : 0 : PMD_DRV_LOG(ERR,
894 : : "chim reinit failed: %d", err);
895 : 0 : goto reinit_failed;
896 : : }
897 : : }
898 : :
899 [ # # ]: 0 : for (i = 0; i < NDIS_HASH_INDCNT; i++)
900 : 0 : hv->rss_ind[i] = i % dev->data->nb_rx_queues;
901 : :
902 : 0 : hn_rss_hash_init(hv, rss_conf);
903 : :
904 : 0 : subchan = hv->num_queues - 1;
905 : :
906 : : /* Allocate fresh subchannels and configure RSS */
907 [ # # ]: 0 : if (subchan > 0) {
908 : 0 : err = hn_subchan_configure(hv, subchan);
909 [ # # ]: 0 : if (err) {
910 : 0 : PMD_DRV_LOG(NOTICE,
911 : : "subchannel configuration failed");
912 : 0 : goto subchan_cleanup;
913 : : }
914 : :
915 : 0 : err = hn_rndis_conf_rss(hv, NDIS_RSS_FLAG_DISABLE);
916 [ # # ]: 0 : if (err) {
917 : 0 : PMD_DRV_LOG(NOTICE,
918 : : "rss disable failed");
919 : 0 : goto subchan_cleanup;
920 : : }
921 : :
922 [ # # ]: 0 : if (rss_conf->rss_hf != 0) {
923 : 0 : err = hn_rndis_conf_rss(hv, 0);
924 [ # # ]: 0 : if (err) {
925 : 0 : PMD_DRV_LOG(NOTICE,
926 : : "initial RSS config failed");
927 : 0 : goto subchan_cleanup;
928 : : }
929 : : }
930 : : }
931 : :
932 : 0 : skip_reinit:
933 : : /* Apply offload config after reinit so it targets the final RNDIS session */
934 : 0 : err = hn_rndis_conf_offload(hv, txmode->offloads,
935 : 0 : rxmode->offloads);
936 [ # # ]: 0 : if (err) {
937 : 0 : PMD_DRV_LOG(NOTICE,
938 : : "offload configure failed");
939 : 0 : return err;
940 : : }
941 : :
942 : 0 : return hn_vf_configure_locked(dev, dev_conf);
943 : :
944 : 0 : subchan_cleanup:
945 [ # # ]: 0 : for (i = 1; i < HN_MAX_CHANNELS; i++) {
946 [ # # ]: 0 : if (hv->channels[i] != NULL) {
947 : 0 : rte_vmbus_chan_close(hv->channels[i]);
948 : 0 : hv->channels[i] = NULL;
949 : : }
950 : : }
951 : 0 : hv->num_queues = 1;
952 [ # # ]: 0 : for (i = 0; i < NDIS_HASH_INDCNT; i++)
953 : 0 : hv->rss_ind[i] = 0;
954 : :
955 : : /* Apply offload config so device is usable on primary queue */
956 : 0 : hn_rndis_conf_offload(hv, txmode->offloads, rxmode->offloads);
957 : 0 : return err;
958 : :
959 : 0 : reinit_failed:
960 : : /*
961 : : * Device is in a broken state after failed reinit.
962 : : * Try to re-establish minimal connectivity.
963 : : */
964 : 0 : PMD_DRV_LOG(ERR,
965 : : "reinit failed (err %d), attempting recovery", err);
966 [ # # ]: 0 : if (hv->channels[0] == NULL) {
967 [ # # ]: 0 : if (device_unmapped) {
968 [ # # ]: 0 : if (rte_vmbus_map_device(hv->vmbus)) {
969 : 0 : hv->num_queues = 0;
970 : 0 : PMD_DRV_LOG(ERR,
971 : : "recovery failed, could not re-map device");
972 : 0 : return err;
973 : : }
974 : 0 : hv->rxbuf_res = hv->vmbus->resource[HV_RECV_BUF_MAP];
975 : 0 : hv->chim_res = hv->vmbus->resource[HV_SEND_BUF_MAP];
976 : : }
977 [ # # ]: 0 : if (rte_vmbus_chan_open(hv->vmbus, &hv->channels[0]) == 0) {
978 [ # # ]: 0 : if (hn_attach(hv, dev->data->mtu) == 0) {
979 : 0 : hv->primary->chan = hv->channels[0];
980 [ # # ]: 0 : if (hn_chim_init(dev) != 0)
981 : 0 : PMD_DRV_LOG(WARNING,
982 : : "chim reinit failed during recovery");
983 : 0 : hv->num_queues = 1;
984 : 0 : PMD_DRV_LOG(NOTICE,
985 : : "recovery successful on primary channel");
986 : : } else {
987 : 0 : rte_vmbus_chan_close(hv->channels[0]);
988 : 0 : rte_free(hv->channels[0]);
989 : 0 : hv->channels[0] = NULL;
990 : 0 : hv->num_queues = 0;
991 : 0 : PMD_DRV_LOG(ERR,
992 : : "recovery failed, device unusable");
993 : : }
994 : : } else {
995 : 0 : hv->num_queues = 0;
996 : 0 : PMD_DRV_LOG(ERR,
997 : : "recovery failed, device unusable");
998 : : }
999 : : } else {
1000 : 0 : hv->num_queues = 1;
1001 : : }
1002 : : return err;
1003 : : }
1004 : :
1005 : 0 : static int hn_dev_stats_get(struct rte_eth_dev *dev,
1006 : : struct rte_eth_stats *stats,
1007 : : struct eth_queue_stats *qstats)
1008 : : {
1009 : : unsigned int i;
1010 : :
1011 : 0 : hn_vf_stats_get(dev, stats, qstats);
1012 : :
1013 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
1014 : 0 : const struct hn_tx_queue *txq = dev->data->tx_queues[i];
1015 : :
1016 [ # # ]: 0 : if (!txq)
1017 : 0 : continue;
1018 : :
1019 : 0 : stats->opackets += txq->stats.packets;
1020 : 0 : stats->obytes += txq->stats.bytes;
1021 : 0 : stats->oerrors += txq->stats.errors;
1022 : :
1023 [ # # ]: 0 : if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
1024 : 0 : qstats->q_opackets[i] += txq->stats.packets;
1025 : 0 : qstats->q_obytes[i] += txq->stats.bytes;
1026 : : }
1027 : : }
1028 : :
1029 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
1030 : 0 : const struct hn_rx_queue *rxq = dev->data->rx_queues[i];
1031 : :
1032 [ # # ]: 0 : if (!rxq)
1033 : 0 : continue;
1034 : :
1035 : 0 : stats->ipackets += rxq->stats.packets;
1036 : 0 : stats->ibytes += rxq->stats.bytes;
1037 : 0 : stats->ierrors += rxq->stats.errors;
1038 : 0 : stats->imissed += rxq->stats.ring_full;
1039 : :
1040 [ # # ]: 0 : if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
1041 : 0 : qstats->q_ipackets[i] += rxq->stats.packets;
1042 : 0 : qstats->q_ibytes[i] += rxq->stats.bytes;
1043 : : }
1044 : : }
1045 : :
1046 : 0 : stats->rx_nombuf += dev->data->rx_mbuf_alloc_failed;
1047 : 0 : return 0;
1048 : : }
1049 : :
1050 : : static int
1051 : 0 : hn_dev_stats_reset(struct rte_eth_dev *dev)
1052 : : {
1053 : : unsigned int i;
1054 : :
1055 : 0 : PMD_INIT_FUNC_TRACE();
1056 : :
1057 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
1058 : 0 : struct hn_tx_queue *txq = dev->data->tx_queues[i];
1059 : :
1060 [ # # ]: 0 : if (!txq)
1061 : 0 : continue;
1062 : 0 : memset(&txq->stats, 0, sizeof(struct hn_stats));
1063 : : }
1064 : :
1065 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
1066 : 0 : struct hn_rx_queue *rxq = dev->data->rx_queues[i];
1067 : :
1068 [ # # ]: 0 : if (!rxq)
1069 : 0 : continue;
1070 : :
1071 : 0 : memset(&rxq->stats, 0, sizeof(struct hn_stats));
1072 : : }
1073 : :
1074 : 0 : return 0;
1075 : : }
1076 : :
1077 : : static int
1078 : 0 : hn_dev_xstats_reset(struct rte_eth_dev *dev)
1079 : : {
1080 : : int ret;
1081 : :
1082 : 0 : ret = hn_dev_stats_reset(dev);
1083 [ # # ]: 0 : if (ret != 0)
1084 : : return 0;
1085 : :
1086 : 0 : return hn_vf_xstats_reset(dev);
1087 : : }
1088 : :
1089 : : static int
1090 : 0 : hn_dev_xstats_count(struct rte_eth_dev *dev)
1091 : : {
1092 : : int ret, count;
1093 : :
1094 : 0 : count = dev->data->nb_tx_queues * RTE_DIM(hn_stat_strings);
1095 : 0 : count += dev->data->nb_rx_queues * RTE_DIM(hn_stat_strings);
1096 : :
1097 : 0 : ret = hn_vf_xstats_get_names(dev, NULL, 0);
1098 [ # # ]: 0 : if (ret < 0)
1099 : : return ret;
1100 : :
1101 : 0 : return count + ret;
1102 : : }
1103 : :
1104 : : static int
1105 : 0 : hn_dev_xstats_get_names(struct rte_eth_dev *dev,
1106 : : struct rte_eth_xstat_name *xstats_names,
1107 : : unsigned int limit)
1108 : : {
1109 : : unsigned int i, t, count = 0;
1110 : : int ret;
1111 : :
1112 [ # # ]: 0 : if (!xstats_names)
1113 : 0 : return hn_dev_xstats_count(dev);
1114 : :
1115 : : /* Note: limit checked in rte_eth_xstats_names() */
1116 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
1117 : 0 : const struct hn_tx_queue *txq = dev->data->tx_queues[i];
1118 : :
1119 [ # # ]: 0 : if (!txq)
1120 : 0 : continue;
1121 : :
1122 [ # # ]: 0 : if (count >= limit)
1123 : : break;
1124 : :
1125 [ # # ]: 0 : for (t = 0; t < RTE_DIM(hn_stat_strings); t++)
1126 : 0 : snprintf(xstats_names[count++].name,
1127 : : RTE_ETH_XSTATS_NAME_SIZE,
1128 : 0 : "tx_q%u_%s", i, hn_stat_strings[t].name);
1129 : : }
1130 : :
1131 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
1132 : 0 : const struct hn_rx_queue *rxq = dev->data->rx_queues[i];
1133 : :
1134 [ # # ]: 0 : if (!rxq)
1135 : 0 : continue;
1136 : :
1137 [ # # ]: 0 : if (count >= limit)
1138 : : break;
1139 : :
1140 [ # # ]: 0 : for (t = 0; t < RTE_DIM(hn_stat_strings); t++)
1141 : 0 : snprintf(xstats_names[count++].name,
1142 : : RTE_ETH_XSTATS_NAME_SIZE,
1143 : : "rx_q%u_%s", i,
1144 : 0 : hn_stat_strings[t].name);
1145 : : }
1146 : :
1147 : 0 : ret = hn_vf_xstats_get_names(dev, xstats_names + count,
1148 : : limit - count);
1149 [ # # ]: 0 : if (ret < 0)
1150 : : return ret;
1151 : :
1152 : 0 : return count + ret;
1153 : : }
1154 : :
1155 : : static int
1156 : 0 : hn_dev_xstats_get(struct rte_eth_dev *dev,
1157 : : struct rte_eth_xstat *xstats,
1158 : : unsigned int n)
1159 : : {
1160 : : unsigned int i, t, count = 0;
1161 : 0 : const unsigned int nstats = hn_dev_xstats_count(dev);
1162 : : const char *stats;
1163 : : int ret;
1164 : :
1165 : 0 : PMD_INIT_FUNC_TRACE();
1166 : :
1167 [ # # ]: 0 : if (n < nstats)
1168 : : return nstats;
1169 : :
1170 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
1171 : 0 : const struct hn_tx_queue *txq = dev->data->tx_queues[i];
1172 : :
1173 [ # # ]: 0 : if (!txq)
1174 : 0 : continue;
1175 : :
1176 : 0 : stats = (const char *)&txq->stats;
1177 [ # # ]: 0 : for (t = 0; t < RTE_DIM(hn_stat_strings); t++, count++) {
1178 : 0 : xstats[count].id = count;
1179 : 0 : xstats[count].value = *(const uint64_t *)
1180 : 0 : (stats + hn_stat_strings[t].offset);
1181 : : }
1182 : : }
1183 : :
1184 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
1185 : 0 : const struct hn_rx_queue *rxq = dev->data->rx_queues[i];
1186 : :
1187 [ # # ]: 0 : if (!rxq)
1188 : 0 : continue;
1189 : :
1190 : 0 : stats = (const char *)&rxq->stats;
1191 [ # # ]: 0 : for (t = 0; t < RTE_DIM(hn_stat_strings); t++, count++) {
1192 : 0 : xstats[count].id = count;
1193 : 0 : xstats[count].value = *(const uint64_t *)
1194 : 0 : (stats + hn_stat_strings[t].offset);
1195 : : }
1196 : : }
1197 : :
1198 : 0 : ret = hn_vf_xstats_get(dev, xstats, count, n);
1199 [ # # ]: 0 : if (ret < 0)
1200 : : return ret;
1201 : :
1202 : 0 : return count + ret;
1203 : : }
1204 : :
1205 : : static int
1206 : 0 : hn_dev_start(struct rte_eth_dev *dev)
1207 : : {
1208 : 0 : struct hn_data *hv = dev->data->dev_private;
1209 : : int i, error;
1210 : :
1211 : 0 : PMD_INIT_FUNC_TRACE();
1212 : :
1213 : : /* Register to monitor hot plug events */
1214 : 0 : error = rte_dev_event_callback_register(NULL, netvsc_hotadd_callback,
1215 : : hv);
1216 [ # # ]: 0 : if (error) {
1217 : 0 : PMD_DRV_LOG(ERR, "failed to register device event callback");
1218 : 0 : return error;
1219 : : }
1220 : :
1221 : 0 : error = hn_rndis_set_rxfilter(hv,
1222 : : NDIS_PACKET_TYPE_BROADCAST |
1223 : : NDIS_PACKET_TYPE_ALL_MULTICAST |
1224 : : NDIS_PACKET_TYPE_DIRECTED);
1225 [ # # ]: 0 : if (error) {
1226 : 0 : rte_dev_event_callback_unregister(NULL,
1227 : : netvsc_hotadd_callback, hv);
1228 : 0 : return error;
1229 : : }
1230 : :
1231 : 0 : error = hn_vf_start(dev);
1232 [ # # ]: 0 : if (error) {
1233 : 0 : hn_rndis_set_rxfilter(hv, 0);
1234 : 0 : rte_dev_event_callback_unregister(NULL,
1235 : : netvsc_hotadd_callback, hv);
1236 : 0 : return error;
1237 : : }
1238 : :
1239 : : /* Initialize Link state */
1240 : 0 : hn_dev_link_update(dev, 0);
1241 : :
1242 [ # # ]: 0 : for (i = 0; i < hv->num_queues; i++) {
1243 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
1244 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
1245 : : }
1246 : :
1247 : : return error;
1248 : : }
1249 : :
1250 : : static int
1251 : 0 : hn_dev_stop(struct rte_eth_dev *dev)
1252 : : {
1253 : 0 : struct hn_data *hv = dev->data->dev_private;
1254 : : int i, ret;
1255 : : unsigned int retry;
1256 : :
1257 : 0 : PMD_INIT_FUNC_TRACE();
1258 : 0 : dev->data->dev_started = 0;
1259 : :
1260 : 0 : rte_dev_event_callback_unregister(NULL, netvsc_hotadd_callback, hv);
1261 : 0 : hn_rndis_set_rxfilter(hv, 0);
1262 : 0 : ret = hn_vf_stop(dev);
1263 : :
1264 : : /*
1265 : : * Drain pending TX completions to prevent stale completions
1266 : : * from corrupting queue state after port reconfiguration.
1267 : : */
1268 [ # # ]: 0 : for (retry = 0; retry < 100; retry++) {
1269 : : uint32_t pending = 0;
1270 : :
1271 [ # # ]: 0 : for (i = 0; i < hv->num_queues; i++) {
1272 : 0 : struct hn_tx_queue *txq = dev->data->tx_queues[i];
1273 : :
1274 [ # # ]: 0 : if (txq == NULL)
1275 : 0 : continue;
1276 : 0 : hn_process_events(hv, i, 0);
1277 : 0 : pending += rte_mempool_in_use_count(txq->txdesc_pool);
1278 : : }
1279 [ # # ]: 0 : if (pending == 0)
1280 : : break;
1281 : : rte_delay_ms(10);
1282 : : }
1283 [ # # ]: 0 : if (retry >= 100)
1284 : 0 : PMD_DRV_LOG(WARNING,
1285 : : "Failed to drain all TX completions");
1286 : :
1287 [ # # ]: 0 : for (i = 0; i < hv->num_queues; i++) {
1288 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
1289 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
1290 : : }
1291 : :
1292 : 0 : return ret;
1293 : : }
1294 : :
1295 : : static int
1296 : 0 : hn_dev_close(struct rte_eth_dev *dev)
1297 : : {
1298 : : int ret;
1299 : 0 : struct hn_data *hv = dev->data->dev_private;
1300 : : struct hv_hotadd_context *hot_ctx;
1301 : :
1302 : 0 : PMD_INIT_FUNC_TRACE();
1303 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1304 : : return 0;
1305 : :
1306 : 0 : rte_spinlock_lock(&hv->hotadd_lock);
1307 [ # # ]: 0 : while (!LIST_EMPTY(&hv->hotadd_list)) {
1308 : : hot_ctx = LIST_FIRST(&hv->hotadd_list);
1309 : 0 : rte_eal_alarm_cancel(netvsc_hotplug_retry, hot_ctx);
1310 [ # # ]: 0 : LIST_REMOVE(hot_ctx, list);
1311 : 0 : rte_devargs_reset(&hot_ctx->da);
1312 : 0 : free(hot_ctx);
1313 : : }
1314 : : rte_spinlock_unlock(&hv->hotadd_lock);
1315 : :
1316 : 0 : ret = hn_vf_close(dev);
1317 : 0 : hn_dev_free_queues(dev);
1318 : :
1319 : 0 : return ret;
1320 : : }
1321 : :
1322 : : /*
1323 : : * Setup connection between PMD and kernel.
1324 : : */
1325 : : static int
1326 : 0 : hn_attach(struct hn_data *hv, unsigned int mtu)
1327 : : {
1328 : : int error;
1329 : :
1330 : : /* Attach NVS */
1331 : 0 : error = hn_nvs_attach(hv, mtu);
1332 [ # # ]: 0 : if (error)
1333 : 0 : goto failed_nvs;
1334 : :
1335 : : /* Attach RNDIS */
1336 : 0 : error = hn_rndis_attach(hv);
1337 [ # # ]: 0 : if (error)
1338 : 0 : goto failed_rndis;
1339 : :
1340 : : /*
1341 : : * NOTE:
1342 : : * Under certain conditions on certain versions of Hyper-V,
1343 : : * the RNDIS rxfilter is _not_ zero on the hypervisor side
1344 : : * after the successful RNDIS initialization.
1345 : : */
1346 : 0 : hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_NONE);
1347 : 0 : return 0;
1348 : : failed_rndis:
1349 : 0 : hn_nvs_detach(hv);
1350 : : failed_nvs:
1351 : : return error;
1352 : : }
1353 : :
1354 : : static void
1355 : : hn_detach(struct hn_data *hv)
1356 : : {
1357 : 0 : hn_nvs_detach(hv);
1358 : 0 : hn_rndis_detach(hv);
1359 : : }
1360 : :
1361 : : /*
1362 : : * Connects EXISTING rx/tx queues to NEW vmbus channel(s), and
1363 : : * re-initializes NDIS and RNDIS, including re-sending initial
1364 : : * NDIS/RNDIS configuration. To be used after the underlying vmbus
1365 : : * has been un- and re-mapped, e.g. as must happen when the device
1366 : : * MTU is changed.
1367 : : */
1368 : : static int
1369 : 0 : hn_reinit(struct rte_eth_dev *dev, uint16_t mtu)
1370 : : {
1371 : 0 : struct hn_data *hv = dev->data->dev_private;
1372 : 0 : struct hn_rx_queue **rxqs = (struct hn_rx_queue **)dev->data->rx_queues;
1373 : 0 : struct hn_tx_queue **txqs = (struct hn_tx_queue **)dev->data->tx_queues;
1374 : : int i, ret = 0;
1375 : :
1376 : : /* Point primary queues at new primary channel */
1377 [ # # ]: 0 : if (rxqs[0]) {
1378 : 0 : rxqs[0]->chan = hv->channels[0];
1379 : 0 : txqs[0]->chan = hv->channels[0];
1380 : : }
1381 : :
1382 : 0 : ret = hn_attach(hv, mtu);
1383 [ # # ]: 0 : if (ret)
1384 : : return ret;
1385 : :
1386 : : /* Create vmbus subchannels, additional RNDIS configuration */
1387 : 0 : ret = hn_dev_configure(dev);
1388 [ # # ]: 0 : if (ret)
1389 : : return ret;
1390 : :
1391 : : /* Point any additional queues at new subchannels */
1392 [ # # ]: 0 : if (rxqs[0]) {
1393 [ # # ]: 0 : for (i = 1; i < dev->data->nb_rx_queues; i++)
1394 : 0 : rxqs[i]->chan = hv->channels[i];
1395 [ # # ]: 0 : for (i = 1; i < dev->data->nb_tx_queues; i++)
1396 : 0 : txqs[i]->chan = hv->channels[i];
1397 : : }
1398 : :
1399 : : return ret;
1400 : : }
1401 : :
1402 : : static int
1403 : 0 : hn_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
1404 : : {
1405 : 0 : struct hn_data *hv = dev->data->dev_private;
1406 : 0 : unsigned int orig_mtu = dev->data->mtu;
1407 : : uint32_t rndis_mtu;
1408 : : int ret = 0;
1409 : : int i;
1410 : :
1411 [ # # ]: 0 : if (dev->data->dev_started) {
1412 : 0 : PMD_DRV_LOG(ERR, "Device must be stopped before changing MTU");
1413 : 0 : return -EBUSY;
1414 : : }
1415 : :
1416 : : /* Change MTU of underlying VF dev first, if it exists */
1417 : 0 : ret = hn_vf_mtu_set(dev, mtu);
1418 [ # # ]: 0 : if (ret)
1419 : : return ret;
1420 : :
1421 : : /* Free chimney bitmap and rxbuf_info before NVS detach */
1422 : 0 : hn_chim_uninit(dev);
1423 : 0 : rte_free(hv->primary->rxbuf_info);
1424 : 0 : hv->primary->rxbuf_info = NULL;
1425 : :
1426 : : /* Release channel resources */
1427 : : hn_detach(hv);
1428 : :
1429 : : /* Close any secondary vmbus channels */
1430 [ # # ]: 0 : for (i = 1; i < hv->num_queues; i++) {
1431 : 0 : rte_vmbus_chan_close(hv->channels[i]);
1432 : 0 : hv->channels[i] = NULL;
1433 : : }
1434 : 0 : hv->num_queues = 1;
1435 : :
1436 : : /* Close primary vmbus channel */
1437 : 0 : rte_vmbus_chan_close(hv->channels[0]);
1438 : 0 : rte_free(hv->channels[0]);
1439 : :
1440 : : /* Unmap and re-map vmbus device */
1441 : 0 : rte_vmbus_unmap_device(hv->vmbus);
1442 : 0 : ret = rte_vmbus_map_device(hv->vmbus);
1443 [ # # ]: 0 : if (ret) {
1444 : : /* This is a catastrophic error - the device is unusable */
1445 : 0 : PMD_DRV_LOG(ERR, "Could not re-map vmbus device!");
1446 : 0 : return ret;
1447 : : }
1448 : :
1449 : : /* Update pointers to re-mapped UIO resources */
1450 : 0 : hv->rxbuf_res = hv->vmbus->resource[HV_RECV_BUF_MAP];
1451 : 0 : hv->chim_res = hv->vmbus->resource[HV_SEND_BUF_MAP];
1452 : :
1453 : : /* Re-open the primary vmbus channel */
1454 : 0 : ret = rte_vmbus_chan_open(hv->vmbus, &hv->channels[0]);
1455 [ # # ]: 0 : if (ret) {
1456 : : /* This is a catastrophic error - the device is unusable */
1457 : 0 : PMD_DRV_LOG(ERR, "Could not re-open vmbus channel!");
1458 : 0 : return ret;
1459 : : }
1460 : :
1461 : 0 : hv->primary->chan = hv->channels[0];
1462 : 0 : rte_vmbus_set_latency(hv->vmbus, hv->channels[0], hv->latency);
1463 : :
1464 : 0 : ret = hn_reinit(dev, mtu);
1465 [ # # ]: 0 : if (!ret) {
1466 : 0 : hn_chim_init(dev);
1467 : 0 : goto out;
1468 : : }
1469 : :
1470 : : /* In case of error, attempt to restore original MTU */
1471 : 0 : ret = hn_reinit(dev, orig_mtu);
1472 [ # # ]: 0 : if (ret)
1473 : 0 : PMD_DRV_LOG(ERR, "Restoring original MTU failed for netvsc");
1474 : : else
1475 : 0 : hn_chim_init(dev);
1476 : :
1477 : 0 : ret = hn_vf_mtu_set(dev, orig_mtu);
1478 [ # # ]: 0 : if (ret)
1479 : 0 : PMD_DRV_LOG(ERR, "Restoring original MTU failed for VF");
1480 : :
1481 : 0 : out:
1482 [ # # ]: 0 : if (hn_rndis_get_mtu(hv, &rndis_mtu)) {
1483 : 0 : PMD_DRV_LOG(ERR, "Could not get MTU via RNDIS");
1484 : : } else {
1485 : 0 : dev->data->mtu = (uint16_t)rndis_mtu;
1486 : 0 : PMD_DRV_LOG(DEBUG, "RNDIS MTU is %u", dev->data->mtu);
1487 : : }
1488 : :
1489 : : return ret;
1490 : : }
1491 : :
1492 : : static const struct eth_dev_ops hn_eth_dev_ops = {
1493 : : .dev_configure = hn_dev_configure,
1494 : : .dev_start = hn_dev_start,
1495 : : .dev_stop = hn_dev_stop,
1496 : : .dev_close = hn_dev_close,
1497 : : .dev_infos_get = hn_dev_info_get,
1498 : : .txq_info_get = hn_dev_tx_queue_info,
1499 : : .rxq_info_get = hn_dev_rx_queue_info,
1500 : : .dev_supported_ptypes_get = hn_vf_supported_ptypes,
1501 : : .promiscuous_enable = hn_dev_promiscuous_enable,
1502 : : .promiscuous_disable = hn_dev_promiscuous_disable,
1503 : : .allmulticast_enable = hn_dev_allmulticast_enable,
1504 : : .allmulticast_disable = hn_dev_allmulticast_disable,
1505 : : .set_mc_addr_list = hn_dev_mc_addr_list,
1506 : : .mtu_set = hn_dev_mtu_set,
1507 : : .reta_update = hn_rss_reta_update,
1508 : : .reta_query = hn_rss_reta_query,
1509 : : .rss_hash_update = hn_rss_hash_update,
1510 : : .rss_hash_conf_get = hn_rss_hash_conf_get,
1511 : : .tx_queue_setup = hn_dev_tx_queue_setup,
1512 : : .tx_queue_release = hn_dev_tx_queue_release,
1513 : : .tx_done_cleanup = hn_dev_tx_done_cleanup,
1514 : : .rx_queue_setup = hn_dev_rx_queue_setup,
1515 : : .rx_queue_release = hn_dev_rx_queue_release,
1516 : : .link_update = hn_dev_link_update,
1517 : : .stats_get = hn_dev_stats_get,
1518 : : .stats_reset = hn_dev_stats_reset,
1519 : : .xstats_get = hn_dev_xstats_get,
1520 : : .xstats_get_names = hn_dev_xstats_get_names,
1521 : : .xstats_reset = hn_dev_xstats_reset,
1522 : : };
1523 : :
1524 : : static int
1525 : 0 : eth_hn_dev_init(struct rte_eth_dev *eth_dev)
1526 : : {
1527 : 0 : struct hn_data *hv = eth_dev->data->dev_private;
1528 : 0 : struct rte_device *device = eth_dev->device;
1529 : : struct rte_vmbus_device *vmbus;
1530 : : uint32_t mtu;
1531 : : unsigned int rxr_cnt;
1532 : : int err, max_chan;
1533 : :
1534 : 0 : PMD_INIT_FUNC_TRACE();
1535 : :
1536 : : rte_spinlock_init(&hv->hotadd_lock);
1537 : 0 : LIST_INIT(&hv->hotadd_list);
1538 : :
1539 : 0 : vmbus = container_of(device, struct rte_vmbus_device, device);
1540 : 0 : eth_dev->dev_ops = &hn_eth_dev_ops;
1541 : 0 : eth_dev->rx_queue_count = hn_dev_rx_queue_count;
1542 : 0 : eth_dev->rx_descriptor_status = hn_dev_rx_queue_status;
1543 : 0 : eth_dev->tx_descriptor_status = hn_dev_tx_descriptor_status;
1544 : 0 : eth_dev->tx_pkt_burst = &hn_xmit_pkts;
1545 : 0 : eth_dev->rx_pkt_burst = &hn_recv_pkts;
1546 : :
1547 : : /*
1548 : : * for secondary processes, we don't initialize any further as primary
1549 : : * has already done this work.
1550 : : */
1551 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1552 : : return 0;
1553 : :
1554 : 0 : eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
1555 : :
1556 : : /* Since Hyper-V only supports one MAC address */
1557 : 0 : eth_dev->data->mac_addrs = rte_calloc("hv_mac", HN_MAX_MAC_ADDRS,
1558 : : sizeof(struct rte_ether_addr), 0);
1559 [ # # ]: 0 : if (eth_dev->data->mac_addrs == NULL) {
1560 : 0 : PMD_INIT_LOG(ERR,
1561 : : "Failed to allocate memory store MAC addresses");
1562 : 0 : return -ENOMEM;
1563 : : }
1564 : :
1565 : 0 : hv->vmbus = vmbus;
1566 : 0 : hv->rxbuf_res = vmbus->resource[HV_RECV_BUF_MAP];
1567 : 0 : hv->chim_res = vmbus->resource[HV_SEND_BUF_MAP];
1568 : 0 : hv->port_id = eth_dev->data->port_id;
1569 : 0 : hv->latency = HN_CHAN_LATENCY_NS;
1570 : 0 : hv->rx_copybreak = HN_RXCOPY_THRESHOLD;
1571 : 0 : hv->tx_copybreak = HN_TXCOPY_THRESHOLD;
1572 : 0 : hv->rx_extmbuf_enable = HN_RX_EXTMBUF_ENABLE;
1573 : 0 : hv->max_queues = 1;
1574 : :
1575 : : rte_rwlock_init(&hv->vf_lock);
1576 : 0 : hv->vf_ctx.vf_vsc_switched = false;
1577 : 0 : hv->vf_ctx.vf_vsp_reported = false;
1578 : 0 : hv->vf_ctx.vf_attached = false;
1579 : 0 : hv->vf_ctx.vf_state = vf_unknown;
1580 : :
1581 : 0 : err = hn_parse_args(eth_dev);
1582 [ # # ]: 0 : if (err)
1583 : : return err;
1584 : :
1585 : 0 : strlcpy(hv->owner.name, eth_dev->device->name,
1586 : : RTE_ETH_MAX_OWNER_NAME_LEN);
1587 : 0 : err = rte_eth_dev_owner_new(&hv->owner.id);
1588 [ # # ]: 0 : if (err) {
1589 : 0 : PMD_INIT_LOG(ERR, "Can not get owner id");
1590 : 0 : return err;
1591 : : }
1592 : :
1593 : : /* Initialize primary channel input for control operations */
1594 : 0 : err = rte_vmbus_chan_open(vmbus, &hv->channels[0]);
1595 [ # # ]: 0 : if (err)
1596 : : return err;
1597 : :
1598 : 0 : rte_vmbus_set_latency(hv->vmbus, hv->channels[0], hv->latency);
1599 : :
1600 : 0 : hv->primary = hn_rx_queue_alloc(hv, 0,
1601 : 0 : eth_dev->device->numa_node);
1602 : :
1603 [ # # ]: 0 : if (!hv->primary) {
1604 : : err = -ENOMEM;
1605 : 0 : goto failed;
1606 : : }
1607 : :
1608 : 0 : err = hn_attach(hv, RTE_ETHER_MTU);
1609 [ # # ]: 0 : if (err)
1610 : 0 : goto failed;
1611 : :
1612 : 0 : err = hn_chim_init(eth_dev);
1613 [ # # ]: 0 : if (err)
1614 : 0 : goto failed;
1615 : :
1616 : 0 : err = hn_rndis_get_mtu(hv, &mtu);
1617 [ # # ]: 0 : if (err)
1618 : 0 : goto failed;
1619 : 0 : eth_dev->data->mtu = (uint16_t)mtu;
1620 : 0 : PMD_INIT_LOG(DEBUG, "RNDIS MTU is %u", eth_dev->data->mtu);
1621 : :
1622 : 0 : err = hn_rndis_get_eaddr(hv, eth_dev->data->mac_addrs->addr_bytes);
1623 [ # # ]: 0 : if (err)
1624 : 0 : goto failed;
1625 : :
1626 : : /* Multi queue requires later versions of windows server */
1627 [ # # ]: 0 : if (hv->nvs_ver < NVS_VERSION_5)
1628 : : return 0;
1629 : :
1630 : 0 : max_chan = rte_vmbus_max_channels(vmbus);
1631 : 0 : PMD_INIT_LOG(DEBUG, "VMBus max channels %d", max_chan);
1632 [ # # ]: 0 : if (max_chan <= 0) {
1633 [ # # ]: 0 : err = max_chan ? max_chan : -ENODEV;
1634 : 0 : goto failed;
1635 : : }
1636 : :
1637 [ # # ]: 0 : if (hn_rndis_query_rsscaps(hv, &rxr_cnt) != 0)
1638 : 0 : rxr_cnt = 1;
1639 : :
1640 : 0 : hv->max_queues = RTE_MIN(rxr_cnt, (unsigned int)max_chan);
1641 : :
1642 : : /* If VF was reported but not added, do it now */
1643 : 0 : rte_rwlock_write_lock(&hv->vf_lock);
1644 [ # # # # ]: 0 : if (hv->vf_ctx.vf_vsp_reported && !hv->vf_ctx.vf_vsc_switched) {
1645 : 0 : PMD_INIT_LOG(DEBUG, "Adding VF device");
1646 : 0 : err = hn_vf_add_unlocked(eth_dev, hv);
1647 : : }
1648 : : rte_rwlock_write_unlock(&hv->vf_lock);
1649 : :
1650 : 0 : return 0;
1651 : :
1652 : 0 : failed:
1653 : 0 : PMD_INIT_LOG(NOTICE, "device init failed");
1654 : :
1655 : 0 : hn_chim_uninit(eth_dev);
1656 : : hn_detach(hv);
1657 : 0 : rte_free(hv->primary);
1658 : 0 : rte_vmbus_chan_close(hv->channels[0]);
1659 : 0 : return err;
1660 : : }
1661 : :
1662 : : static int
1663 : 0 : eth_hn_dev_uninit(struct rte_eth_dev *eth_dev)
1664 : : {
1665 : 0 : struct hn_data *hv = eth_dev->data->dev_private;
1666 : : int ret, ret_stop;
1667 : : int i;
1668 : :
1669 : 0 : PMD_INIT_FUNC_TRACE();
1670 : :
1671 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1672 : : return 0;
1673 : :
1674 : 0 : ret_stop = hn_dev_stop(eth_dev);
1675 : 0 : hn_dev_close(eth_dev);
1676 : :
1677 : : hn_detach(hv);
1678 : 0 : hn_chim_uninit(eth_dev);
1679 : :
1680 : : /* Close any subchannels before closing the primary channel */
1681 [ # # ]: 0 : for (i = 1; i < HN_MAX_CHANNELS; i++) {
1682 [ # # ]: 0 : if (hv->channels[i] != NULL) {
1683 : 0 : rte_vmbus_chan_close(hv->channels[i]);
1684 : 0 : hv->channels[i] = NULL;
1685 : : }
1686 : : }
1687 : :
1688 : 0 : rte_vmbus_chan_close(hv->channels[0]);
1689 : 0 : ret = rte_eth_dev_owner_delete(hv->owner.id);
1690 [ # # ]: 0 : if (ret != 0)
1691 : 0 : return ret;
1692 : :
1693 : : return ret_stop;
1694 : : }
1695 : :
1696 : 0 : static int populate_cache_list(void)
1697 : : {
1698 : : int ret = 0;
1699 : : struct rte_devargs *da;
1700 : :
1701 : : rte_spinlock_lock(&netvsc_lock);
1702 : 0 : da_cache_usage++;
1703 [ # # ]: 0 : if (da_cache_usage > 1) {
1704 : : ret = 0;
1705 : 0 : goto out;
1706 : : }
1707 : :
1708 : 0 : LIST_INIT(&da_cache_list);
1709 [ # # ]: 0 : RTE_EAL_DEVARGS_FOREACH("pci", da) {
1710 : : struct da_cache *cache;
1711 : :
1712 : 0 : cache = calloc(1, sizeof(*cache) + strlen(da->drv_str) + 1);
1713 [ # # ]: 0 : if (!cache) {
1714 : : ret = -ENOMEM;
1715 : 0 : goto out;
1716 : : }
1717 : :
1718 [ # # ]: 0 : strlcpy(cache->name, da->name, sizeof(cache->name));
1719 : 0 : strlcpy(cache->drv_str, da->drv_str, strlen(da->drv_str) + 1);
1720 [ # # ]: 0 : LIST_INSERT_HEAD(&da_cache_list, cache, list);
1721 : : }
1722 : 0 : out:
1723 : : rte_spinlock_unlock(&netvsc_lock);
1724 : 0 : return ret;
1725 : : }
1726 : :
1727 : 0 : static void remove_cache_list(void)
1728 : : {
1729 : : struct da_cache *cache, *tmp;
1730 : :
1731 : : rte_spinlock_lock(&netvsc_lock);
1732 : 0 : da_cache_usage--;
1733 [ # # ]: 0 : if (da_cache_usage)
1734 : 0 : goto out;
1735 : :
1736 [ # # ]: 0 : LIST_FOREACH_SAFE(cache, &da_cache_list, list, tmp) {
1737 [ # # ]: 0 : LIST_REMOVE(cache, list);
1738 : 0 : free(cache);
1739 : : }
1740 : 0 : out:
1741 : : rte_spinlock_unlock(&netvsc_lock);
1742 : 0 : }
1743 : :
1744 : : static int
1745 : 0 : netvsc_mp_primary_handle(const struct rte_mp_msg *mp_msg __rte_unused,
1746 : : const void *peer __rte_unused)
1747 : : {
1748 : : /* Stub function required for multi-process message handling registration */
1749 : 0 : return 0;
1750 : : }
1751 : :
1752 : : static void
1753 : : mp_init_msg(struct rte_mp_msg *msg, enum netvsc_mp_req_type type, int vf_port)
1754 : : {
1755 : : struct netvsc_mp_param *param;
1756 : :
1757 : : strlcpy(msg->name, NETVSC_MP_NAME, sizeof(msg->name));
1758 : 0 : msg->len_param = sizeof(*param);
1759 : :
1760 : : param = (struct netvsc_mp_param *)msg->param;
1761 : 0 : param->type = type;
1762 : 0 : param->vf_port = vf_port;
1763 : : }
1764 : :
1765 : 0 : static int netvsc_secondary_handle_device_remove(int vf_port)
1766 : : {
1767 [ # # ]: 0 : if (!rte_eth_dev_is_valid_port(vf_port)) {
1768 : : /* VF not probed in this secondary — nothing to release */
1769 : 0 : PMD_DRV_LOG(DEBUG, "VF port %u not present in secondary, skipping",
1770 : : vf_port);
1771 : 0 : return 0;
1772 : : }
1773 : :
1774 : 0 : PMD_DRV_LOG(DEBUG, "Secondary releasing VF port %d", vf_port);
1775 : 0 : return rte_eth_dev_release_port(&rte_eth_devices[vf_port]);
1776 : : }
1777 : :
1778 : : static int
1779 : 0 : netvsc_mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
1780 : : {
1781 : 0 : struct rte_mp_msg mp_res = { 0 };
1782 : : struct netvsc_mp_param *res = (struct netvsc_mp_param *)mp_res.param;
1783 : : const struct netvsc_mp_param *param =
1784 : : (const struct netvsc_mp_param *)mp_msg->param;
1785 : : int ret = 0;
1786 : :
1787 [ # # ]: 0 : mp_init_msg(&mp_res, param->type, param->vf_port);
1788 : :
1789 [ # # ]: 0 : switch (param->type) {
1790 : 0 : case NETVSC_MP_REQ_VF_REMOVE:
1791 : 0 : res->result = netvsc_secondary_handle_device_remove(param->vf_port);
1792 : 0 : ret = rte_mp_reply(&mp_res, peer);
1793 : 0 : break;
1794 : :
1795 : 0 : default:
1796 : 0 : PMD_DRV_LOG(ERR, "Unknown primary MP type %u", param->type);
1797 : : ret = -EINVAL;
1798 : : }
1799 : :
1800 : 0 : return ret;
1801 : : }
1802 : :
1803 : 0 : static int netvsc_mp_init_primary(void)
1804 : : {
1805 : : int ret;
1806 : 0 : ret = rte_mp_action_register(NETVSC_MP_NAME, netvsc_mp_primary_handle);
1807 [ # # # # ]: 0 : if (ret && rte_errno != ENOTSUP) {
1808 : 0 : PMD_DRV_LOG(ERR, "Failed to register primary handler %d %d",
1809 : : ret, rte_errno);
1810 : 0 : return -1;
1811 : : }
1812 : :
1813 : : return 0;
1814 : : }
1815 : :
1816 : : static void netvsc_mp_uninit_primary(void)
1817 : : {
1818 : 0 : rte_mp_action_unregister(NETVSC_MP_NAME);
1819 : : }
1820 : :
1821 : : static int netvsc_mp_init_secondary(void)
1822 : : {
1823 : 0 : return rte_mp_action_register(NETVSC_MP_NAME, netvsc_mp_secondary_handle);
1824 : : }
1825 : :
1826 : : static void netvsc_mp_uninit_secondary(void)
1827 : : {
1828 : 0 : rte_mp_action_unregister(NETVSC_MP_NAME);
1829 : 0 : }
1830 : :
1831 : 0 : int netvsc_mp_req_vf(struct hn_data *hv, enum netvsc_mp_req_type type,
1832 : : int vf_port)
1833 : : {
1834 : 0 : struct rte_mp_msg mp_req = { 0 };
1835 : : struct rte_mp_msg *mp_res;
1836 : 0 : struct rte_mp_reply mp_rep = { 0 };
1837 : : struct netvsc_mp_param *res;
1838 : 0 : struct timespec ts = {.tv_sec = NETVSC_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
1839 : : int i, ret;
1840 : :
1841 : : /* if secondary count is 0, return */
1842 [ # # ]: 0 : if (rte_atomic_load_explicit(&netvsc_shared_data->secondary_cnt,
1843 : : rte_memory_order_acquire) == 0)
1844 : : return 0;
1845 : :
1846 : : mp_init_msg(&mp_req, type, vf_port);
1847 : :
1848 : 0 : ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
1849 [ # # ]: 0 : if (ret) {
1850 [ # # ]: 0 : if (rte_errno != ENOTSUP)
1851 : 0 : PMD_DRV_LOG(ERR, "port %u failed to request VF remove",
1852 : : hv->port_id);
1853 : : else
1854 : : ret = 0;
1855 : 0 : goto exit;
1856 : : }
1857 : :
1858 [ # # ]: 0 : if (mp_rep.nb_sent != mp_rep.nb_received) {
1859 : 0 : PMD_DRV_LOG(ERR, "port %u not all secondaries responded type %d",
1860 : : hv->port_id, type);
1861 : : ret = -1;
1862 : 0 : goto exit;
1863 : : }
1864 [ # # ]: 0 : for (i = 0; i < mp_rep.nb_received; i++) {
1865 : 0 : mp_res = &mp_rep.msgs[i];
1866 : : res = (struct netvsc_mp_param *)mp_res->param;
1867 [ # # ]: 0 : if (res->result) {
1868 : 0 : PMD_DRV_LOG(ERR, "port %u request failed on secondary %d",
1869 : : hv->port_id, i);
1870 : : ret = -1;
1871 : 0 : goto exit;
1872 : : }
1873 : : }
1874 : :
1875 : 0 : exit:
1876 : 0 : free(mp_rep.msgs);
1877 : 0 : return ret;
1878 : : }
1879 : :
1880 : 0 : static int netvsc_init_once(void)
1881 : : {
1882 : : int ret = 0;
1883 : : const struct rte_memzone *secondary_mz;
1884 : :
1885 [ # # ]: 0 : if (netvsc_local_data.init_done)
1886 : : return 0;
1887 : :
1888 [ # # # ]: 0 : switch (rte_eal_process_type()) {
1889 : 0 : case RTE_PROC_PRIMARY:
1890 : 0 : netvsc_shared_mz = rte_memzone_reserve(MZ_NETVSC_SHARED_DATA,
1891 : : sizeof(*netvsc_shared_data), SOCKET_ID_ANY, 0);
1892 [ # # ]: 0 : if (!netvsc_shared_mz) {
1893 : 0 : PMD_DRV_LOG(ERR, "Cannot allocate netvsc shared data");
1894 : 0 : return -rte_errno;
1895 : : }
1896 : 0 : netvsc_shared_data = netvsc_shared_mz->addr;
1897 : 0 : rte_atomic_store_explicit(&netvsc_shared_data->secondary_cnt,
1898 : : 0, rte_memory_order_release);
1899 : :
1900 : 0 : ret = netvsc_mp_init_primary();
1901 [ # # ]: 0 : if (ret) {
1902 : 0 : rte_memzone_free(netvsc_shared_mz);
1903 : 0 : netvsc_shared_mz = NULL;
1904 : 0 : netvsc_shared_data = NULL;
1905 : 0 : break;
1906 : : }
1907 : :
1908 : 0 : PMD_DRV_LOG(DEBUG, "MP INIT PRIMARY");
1909 : 0 : netvsc_local_data.init_done = true;
1910 : 0 : break;
1911 : :
1912 : 0 : case RTE_PROC_SECONDARY:
1913 : 0 : secondary_mz = rte_memzone_lookup(MZ_NETVSC_SHARED_DATA);
1914 [ # # ]: 0 : if (!secondary_mz) {
1915 : 0 : PMD_DRV_LOG(ERR, "Cannot attach netvsc shared data");
1916 : 0 : return -rte_errno;
1917 : : }
1918 : 0 : netvsc_shared_data = secondary_mz->addr;
1919 : : ret = netvsc_mp_init_secondary();
1920 [ # # ]: 0 : if (ret) {
1921 : 0 : netvsc_shared_data = NULL;
1922 : 0 : break;
1923 : : }
1924 : :
1925 : 0 : PMD_DRV_LOG(DEBUG, "MP INIT SECONDARY");
1926 : 0 : netvsc_local_data.init_done = true;
1927 : 0 : break;
1928 : :
1929 : : default:
1930 : : /* Impossible */
1931 : : ret = -EPROTO;
1932 : : break;
1933 : : }
1934 : :
1935 : : return ret;
1936 : : }
1937 : :
1938 : 0 : static void netvsc_uninit_once(void)
1939 : : {
1940 [ # # ]: 0 : if (netvsc_local_data.primary_cnt ||
1941 [ # # ]: 0 : netvsc_local_data.secondary_cnt)
1942 : : return;
1943 : :
1944 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
1945 : : netvsc_mp_uninit_primary();
1946 : 0 : rte_memzone_free(netvsc_shared_mz);
1947 : 0 : netvsc_shared_mz = NULL;
1948 : 0 : netvsc_shared_data = NULL;
1949 : : } else {
1950 : : netvsc_mp_uninit_secondary();
1951 : : }
1952 : 0 : netvsc_local_data.init_done = false;
1953 : : }
1954 : :
1955 : 0 : static int eth_hn_probe(struct rte_vmbus_driver *drv __rte_unused,
1956 : : struct rte_vmbus_device *dev)
1957 : : {
1958 : : struct rte_eth_dev *eth_dev;
1959 : : struct hn_nvs_process_priv *process_priv;
1960 : : int ret = 0;
1961 : :
1962 : 0 : PMD_INIT_FUNC_TRACE();
1963 : :
1964 : 0 : ret = populate_cache_list();
1965 [ # # ]: 0 : if (ret)
1966 : : return ret;
1967 : :
1968 : : rte_spinlock_lock(&netvsc_shared_data_lock);
1969 : 0 : ret = netvsc_init_once();
1970 [ # # ]: 0 : if (!ret) {
1971 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
1972 : 0 : netvsc_local_data.primary_cnt++;
1973 : : } else {
1974 : 0 : rte_atomic_fetch_add_explicit(&netvsc_shared_data->secondary_cnt,
1975 : : 1, rte_memory_order_release);
1976 : 0 : netvsc_local_data.secondary_cnt++;
1977 : : }
1978 : : }
1979 : : rte_spinlock_unlock(&netvsc_shared_data_lock);
1980 [ # # ]: 0 : if (ret)
1981 : 0 : goto fail;
1982 : :
1983 : 0 : ret = rte_dev_event_monitor_start();
1984 [ # # ]: 0 : if (ret) {
1985 : 0 : PMD_DRV_LOG(ERR, "Failed to start device event monitoring");
1986 : 0 : goto init_once_failed;
1987 : : }
1988 : :
1989 : 0 : eth_dev = eth_dev_vmbus_allocate(dev, sizeof(struct hn_data));
1990 [ # # ]: 0 : if (!eth_dev) {
1991 : : ret = -ENOMEM;
1992 : 0 : goto vmbus_alloc_failed;
1993 : : }
1994 : :
1995 : 0 : process_priv = rte_zmalloc_socket("netvsc_proc_priv",
1996 : : sizeof(struct hn_nvs_process_priv),
1997 : : RTE_CACHE_LINE_SIZE,
1998 : : dev->device.numa_node);
1999 [ # # ]: 0 : if (!process_priv) {
2000 : : ret = -ENOMEM;
2001 : 0 : goto priv_alloc_failed;
2002 : : }
2003 : :
2004 : 0 : process_priv->vmbus_dev = dev;
2005 : 0 : eth_dev->process_private = process_priv;
2006 : :
2007 : 0 : ret = eth_hn_dev_init(eth_dev);
2008 [ # # ]: 0 : if (ret)
2009 : 0 : goto dev_init_failed;
2010 : :
2011 : 0 : rte_eth_dev_probing_finish(eth_dev);
2012 : :
2013 : 0 : return ret;
2014 : :
2015 : : dev_init_failed:
2016 : 0 : rte_free(process_priv);
2017 : :
2018 : 0 : priv_alloc_failed:
2019 : : eth_dev_vmbus_release(eth_dev);
2020 : :
2021 : 0 : vmbus_alloc_failed:
2022 : 0 : rte_dev_event_monitor_stop();
2023 : :
2024 : 0 : init_once_failed:
2025 : : rte_spinlock_lock(&netvsc_shared_data_lock);
2026 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
2027 : 0 : netvsc_local_data.primary_cnt--;
2028 : : } else {
2029 : 0 : rte_atomic_fetch_sub_explicit(&netvsc_shared_data->secondary_cnt,
2030 : : 1, rte_memory_order_release);
2031 : 0 : netvsc_local_data.secondary_cnt--;
2032 : : }
2033 : 0 : netvsc_uninit_once();
2034 : : rte_spinlock_unlock(&netvsc_shared_data_lock);
2035 : :
2036 : 0 : fail:
2037 : 0 : remove_cache_list();
2038 : 0 : return ret;
2039 : : }
2040 : :
2041 : 0 : static int eth_hn_remove(struct rte_vmbus_device *dev)
2042 : : {
2043 : : struct rte_eth_dev *eth_dev;
2044 : : struct hn_nvs_process_priv *process_priv;
2045 : : int ret;
2046 : :
2047 : 0 : PMD_INIT_FUNC_TRACE();
2048 : :
2049 : 0 : eth_dev = rte_eth_dev_allocated(dev->device.name);
2050 [ # # ]: 0 : if (!eth_dev) {
2051 : : ret = 0; /* port already released */
2052 : 0 : goto uninit;
2053 : : }
2054 : :
2055 : 0 : ret = eth_hn_dev_uninit(eth_dev);
2056 [ # # ]: 0 : if (ret)
2057 : 0 : goto uninit;
2058 : :
2059 : 0 : process_priv = eth_dev->process_private;
2060 : 0 : rte_free(process_priv);
2061 : :
2062 : : eth_dev_vmbus_release(eth_dev);
2063 : 0 : rte_dev_event_monitor_stop();
2064 : :
2065 : 0 : remove_cache_list();
2066 : :
2067 : 0 : uninit:
2068 : : rte_spinlock_lock(&netvsc_shared_data_lock);
2069 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
2070 : 0 : netvsc_local_data.primary_cnt--;
2071 : : } else {
2072 : 0 : rte_atomic_fetch_sub_explicit(&netvsc_shared_data->secondary_cnt,
2073 : : 1, rte_memory_order_release);
2074 : 0 : netvsc_local_data.secondary_cnt--;
2075 : : }
2076 : 0 : netvsc_uninit_once();
2077 : : rte_spinlock_unlock(&netvsc_shared_data_lock);
2078 : :
2079 : 0 : return ret;
2080 : : }
2081 : :
2082 : : /* Network device GUID */
2083 : : static const rte_uuid_t hn_net_ids[] = {
2084 : : /* f8615163-df3e-46c5-913f-f2d2f965ed0e */
2085 : : RTE_UUID_INIT(0xf8615163, 0xdf3e, 0x46c5, 0x913f, 0xf2d2f965ed0eULL),
2086 : : { 0 }
2087 : : };
2088 : :
2089 : : static struct rte_vmbus_driver rte_netvsc_pmd = {
2090 : : .id_table = hn_net_ids,
2091 : : .probe = eth_hn_probe,
2092 : : .remove = eth_hn_remove,
2093 : : };
2094 : :
2095 : 276 : RTE_PMD_REGISTER_VMBUS(net_netvsc, rte_netvsc_pmd);
2096 : : RTE_PMD_REGISTER_KMOD_DEP(net_netvsc, "* uio_hv_generic");
2097 [ - + ]: 276 : RTE_LOG_REGISTER_SUFFIX(hn_logtype_init, init, NOTICE);
2098 [ - + ]: 276 : RTE_LOG_REGISTER_SUFFIX(hn_logtype_driver, driver, NOTICE);
2099 : : RTE_PMD_REGISTER_PARAM_STRING(net_netvsc,
2100 : : NETVSC_ARG_LATENCY "=<uint32> "
2101 : : NETVSC_ARG_RXBREAK "=<uint32> "
2102 : : NETVSC_ARG_TXBREAK "=<uint32> "
2103 : : NETVSC_ARG_RX_EXTMBUF_ENABLE "=<0|1>");
|