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