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 : : #define HN_TX_OFFLOAD_CAPS (RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | \
52 : : RTE_ETH_TX_OFFLOAD_TCP_CKSUM | \
53 : : RTE_ETH_TX_OFFLOAD_UDP_CKSUM | \
54 : : RTE_ETH_TX_OFFLOAD_TCP_TSO | \
55 : : RTE_ETH_TX_OFFLOAD_MULTI_SEGS | \
56 : : RTE_ETH_TX_OFFLOAD_VLAN_INSERT)
57 : :
58 : : #define HN_RX_OFFLOAD_CAPS (RTE_ETH_RX_OFFLOAD_CHECKSUM | \
59 : : RTE_ETH_RX_OFFLOAD_VLAN_STRIP | \
60 : : RTE_ETH_RX_OFFLOAD_RSS_HASH)
61 : :
62 : : #define NETVSC_ARG_LATENCY "latency"
63 : : #define NETVSC_ARG_RXBREAK "rx_copybreak"
64 : : #define NETVSC_ARG_TXBREAK "tx_copybreak"
65 : : #define NETVSC_ARG_RX_EXTMBUF_ENABLE "rx_extmbuf_enable"
66 : :
67 : : /* The max number of retry when hot adding a VF device */
68 : : #define NETVSC_MAX_HOTADD_RETRY 10
69 : :
70 : : struct hn_xstats_name_off {
71 : : char name[RTE_ETH_XSTATS_NAME_SIZE];
72 : : unsigned int offset;
73 : : };
74 : :
75 : : static const struct hn_xstats_name_off hn_stat_strings[] = {
76 : : { "good_packets", offsetof(struct hn_stats, packets) },
77 : : { "good_bytes", offsetof(struct hn_stats, bytes) },
78 : : { "errors", offsetof(struct hn_stats, errors) },
79 : : { "ring full", offsetof(struct hn_stats, ring_full) },
80 : : { "channel full", offsetof(struct hn_stats, channel_full) },
81 : : { "multicast_packets", offsetof(struct hn_stats, multicast) },
82 : : { "broadcast_packets", offsetof(struct hn_stats, broadcast) },
83 : : { "undersize_packets", offsetof(struct hn_stats, size_bins[0]) },
84 : : { "size_64_packets", offsetof(struct hn_stats, size_bins[1]) },
85 : : { "size_65_127_packets", offsetof(struct hn_stats, size_bins[2]) },
86 : : { "size_128_255_packets", offsetof(struct hn_stats, size_bins[3]) },
87 : : { "size_256_511_packets", offsetof(struct hn_stats, size_bins[4]) },
88 : : { "size_512_1023_packets", offsetof(struct hn_stats, size_bins[5]) },
89 : : { "size_1024_1518_packets", offsetof(struct hn_stats, size_bins[6]) },
90 : : { "size_1519_max_packets", offsetof(struct hn_stats, size_bins[7]) },
91 : : };
92 : :
93 : : /* The default RSS key.
94 : : * This value is the same as MLX5 so that flows will be
95 : : * received on same path for both VF and synthetic NIC.
96 : : */
97 : : static const uint8_t rss_default_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
98 : : 0x2c, 0xc6, 0x81, 0xd1, 0x5b, 0xdb, 0xf4, 0xf7,
99 : : 0xfc, 0xa2, 0x83, 0x19, 0xdb, 0x1a, 0x3e, 0x94,
100 : : 0x6b, 0x9e, 0x38, 0xd9, 0x2c, 0x9c, 0x03, 0xd1,
101 : : 0xad, 0x99, 0x44, 0xa7, 0xd9, 0x56, 0x3d, 0x59,
102 : : 0x06, 0x3c, 0x25, 0xf3, 0xfc, 0x1f, 0xdc, 0x2a,
103 : : };
104 : :
105 : : static rte_spinlock_t netvsc_lock = RTE_SPINLOCK_INITIALIZER;
106 : : struct da_cache {
107 : : LIST_ENTRY(da_cache) list;
108 : : char name[RTE_DEV_NAME_MAX_LEN];
109 : : char drv_str[];
110 : : };
111 : :
112 : : static LIST_HEAD(da_cache_list, da_cache) da_cache_list;
113 : : static unsigned int da_cache_usage;
114 : :
115 : : static struct rte_eth_dev *
116 : 0 : eth_dev_vmbus_allocate(struct rte_vmbus_device *dev, size_t private_data_size)
117 : : {
118 : : struct rte_eth_dev *eth_dev;
119 : : const char *name;
120 : :
121 [ # # ]: 0 : if (!dev)
122 : : return NULL;
123 : :
124 : 0 : name = dev->device.name;
125 : :
126 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
127 : 0 : eth_dev = rte_eth_dev_allocate(name);
128 [ # # ]: 0 : if (!eth_dev) {
129 : 0 : PMD_DRV_LOG(NOTICE, "can not allocate rte ethdev");
130 : 0 : return NULL;
131 : : }
132 : :
133 [ # # ]: 0 : if (private_data_size) {
134 : 0 : eth_dev->data->dev_private =
135 : 0 : rte_zmalloc_socket(name, private_data_size,
136 : : RTE_CACHE_LINE_SIZE, dev->device.numa_node);
137 [ # # ]: 0 : if (!eth_dev->data->dev_private) {
138 : 0 : PMD_DRV_LOG(NOTICE, "can not allocate driver data");
139 : 0 : rte_eth_dev_release_port(eth_dev);
140 : 0 : return NULL;
141 : : }
142 : : }
143 : : } else {
144 : 0 : eth_dev = rte_eth_dev_attach_secondary(name);
145 [ # # ]: 0 : if (!eth_dev) {
146 : 0 : PMD_DRV_LOG(NOTICE, "can not attach secondary");
147 : 0 : return NULL;
148 : : }
149 : : }
150 : :
151 : 0 : eth_dev->device = &dev->device;
152 : :
153 : : /* interrupt is simulated */
154 : 0 : rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_EXT);
155 : 0 : eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
156 : 0 : eth_dev->intr_handle = dev->intr_handle;
157 : :
158 : 0 : return eth_dev;
159 : : }
160 : :
161 : : static void
162 : : eth_dev_vmbus_release(struct rte_eth_dev *eth_dev)
163 : : {
164 : : /* free ether device */
165 : 0 : rte_eth_dev_release_port(eth_dev);
166 : :
167 : 0 : eth_dev->device = NULL;
168 : 0 : eth_dev->intr_handle = NULL;
169 : 0 : }
170 : :
171 : 0 : static int hn_set_parameter(const char *key, const char *value, void *opaque)
172 : : {
173 : : struct hn_data *hv = opaque;
174 : 0 : char *endp = NULL;
175 : : unsigned long v;
176 : :
177 : 0 : v = strtoul(value, &endp, 0);
178 [ # # # # ]: 0 : if (*value == '\0' || *endp != '\0') {
179 : 0 : PMD_DRV_LOG(ERR, "invalid parameter %s=%s", key, value);
180 : 0 : return -EINVAL;
181 : : }
182 : :
183 [ # # ]: 0 : if (!strcmp(key, NETVSC_ARG_LATENCY)) {
184 : : /* usec to nsec */
185 : 0 : hv->latency = v * 1000;
186 : 0 : PMD_DRV_LOG(DEBUG, "set latency %u usec", hv->latency);
187 [ # # ]: 0 : } else if (!strcmp(key, NETVSC_ARG_RXBREAK)) {
188 : 0 : hv->rx_copybreak = v;
189 : 0 : PMD_DRV_LOG(DEBUG, "rx copy break set to %u",
190 : : hv->rx_copybreak);
191 [ # # ]: 0 : } else if (!strcmp(key, NETVSC_ARG_TXBREAK)) {
192 : 0 : hv->tx_copybreak = v;
193 : 0 : PMD_DRV_LOG(DEBUG, "tx copy break set to %u",
194 : : hv->tx_copybreak);
195 [ # # ]: 0 : } else if (!strcmp(key, NETVSC_ARG_RX_EXTMBUF_ENABLE)) {
196 : 0 : hv->rx_extmbuf_enable = v;
197 : 0 : PMD_DRV_LOG(DEBUG, "rx extmbuf enable set to %u",
198 : : hv->rx_extmbuf_enable);
199 : : }
200 : :
201 : : return 0;
202 : : }
203 : :
204 : : /* Parse device arguments */
205 : 0 : static int hn_parse_args(const struct rte_eth_dev *dev)
206 : : {
207 : 0 : struct hn_data *hv = dev->data->dev_private;
208 : 0 : struct rte_devargs *devargs = dev->device->devargs;
209 : : static const char * const valid_keys[] = {
210 : : NETVSC_ARG_LATENCY,
211 : : NETVSC_ARG_RXBREAK,
212 : : NETVSC_ARG_TXBREAK,
213 : : NETVSC_ARG_RX_EXTMBUF_ENABLE,
214 : : NETVSC_ARG_NUMA_AWARE,
215 : : NULL
216 : : };
217 : : struct rte_kvargs *kvlist;
218 : : int ret;
219 : :
220 [ # # ]: 0 : if (!devargs)
221 : : return 0;
222 : :
223 : 0 : PMD_INIT_LOG(DEBUG, "device args %s %s",
224 : : devargs->name, devargs->args);
225 : :
226 : 0 : kvlist = rte_kvargs_parse(devargs->args, valid_keys);
227 [ # # ]: 0 : if (!kvlist) {
228 : 0 : PMD_DRV_LOG(ERR, "invalid parameters");
229 : 0 : return -EINVAL;
230 : : }
231 : :
232 : 0 : ret = rte_kvargs_process(kvlist, NULL, hn_set_parameter, hv);
233 : 0 : rte_kvargs_free(kvlist);
234 : :
235 : 0 : return ret;
236 : : }
237 : :
238 : : /* Update link status.
239 : : * Note: the DPDK definition of "wait_to_complete"
240 : : * means block this call until link is up.
241 : : * which is not worth supporting.
242 : : */
243 : : int
244 : 0 : hn_dev_link_update(struct rte_eth_dev *dev,
245 : : int wait_to_complete __rte_unused)
246 : : {
247 : 0 : struct hn_data *hv = dev->data->dev_private;
248 : : struct rte_eth_link link, old;
249 : : int error;
250 : :
251 : 0 : old = dev->data->dev_link;
252 : :
253 : 0 : error = hn_rndis_get_linkstatus(hv);
254 [ # # ]: 0 : if (error)
255 : : return error;
256 : :
257 : 0 : hn_rndis_get_linkspeed(hv);
258 : :
259 : 0 : link = (struct rte_eth_link) {
260 : : .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
261 : : .link_autoneg = RTE_ETH_LINK_SPEED_FIXED,
262 : 0 : .link_speed = hv->link_speed / 10000,
263 : : };
264 : :
265 [ # # ]: 0 : if (hv->link_status == NDIS_MEDIA_STATE_CONNECTED)
266 : 0 : link.link_status = RTE_ETH_LINK_UP;
267 : : else
268 : : link.link_status = RTE_ETH_LINK_DOWN;
269 : :
270 [ # # ]: 0 : if (old.link_status == link.link_status)
271 : : return 0;
272 : :
273 [ # # ]: 0 : PMD_INIT_LOG(DEBUG, "Port %d is %s", dev->data->port_id,
274 : : (link.link_status == RTE_ETH_LINK_UP) ? "up" : "down");
275 : :
276 : : return rte_eth_linkstatus_set(dev, &link);
277 : : }
278 : :
279 : 0 : static int hn_dev_info_get(struct rte_eth_dev *dev,
280 : : struct rte_eth_dev_info *dev_info)
281 : : {
282 : 0 : struct hn_data *hv = dev->data->dev_private;
283 : : int rc;
284 : :
285 : 0 : dev_info->speed_capa = RTE_ETH_LINK_SPEED_10G;
286 : 0 : dev_info->min_rx_bufsize = HN_MIN_RX_BUF_SIZE;
287 : 0 : dev_info->max_rx_pktlen = HN_MAX_XFER_LEN;
288 : 0 : dev_info->max_mac_addrs = 1;
289 : :
290 : 0 : dev_info->hash_key_size = NDIS_HASH_KEYSIZE_TOEPLITZ;
291 : 0 : dev_info->flow_type_rss_offloads = hv->rss_offloads;
292 : 0 : dev_info->reta_size = RTE_ETH_RSS_RETA_SIZE_128;
293 : :
294 : 0 : dev_info->max_rx_queues = hv->max_queues;
295 : 0 : dev_info->max_tx_queues = hv->max_queues;
296 : :
297 : 0 : dev_info->tx_desc_lim.nb_min = 1;
298 : 0 : dev_info->tx_desc_lim.nb_max = 4096;
299 : :
300 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
301 : : return 0;
302 : :
303 : : /* fills in rx and tx offload capability */
304 : 0 : rc = hn_rndis_get_offload(hv, dev_info);
305 [ # # ]: 0 : if (rc != 0)
306 : : return rc;
307 : :
308 : : /* merges the offload and queues of vf */
309 : 0 : return hn_vf_info_get(hv, dev_info);
310 : : }
311 : :
312 : 0 : static int hn_rss_reta_update(struct rte_eth_dev *dev,
313 : : struct rte_eth_rss_reta_entry64 *reta_conf,
314 : : uint16_t reta_size)
315 : : {
316 : 0 : struct hn_data *hv = dev->data->dev_private;
317 : : unsigned int i;
318 : : int err;
319 : :
320 : 0 : PMD_INIT_FUNC_TRACE();
321 : :
322 [ # # ]: 0 : if (reta_size != NDIS_HASH_INDCNT) {
323 : 0 : PMD_DRV_LOG(ERR, "Hash lookup table size does not match NDIS");
324 : 0 : return -EINVAL;
325 : : }
326 : :
327 [ # # ]: 0 : for (i = 0; i < NDIS_HASH_INDCNT; i++) {
328 : 0 : uint16_t idx = i / RTE_ETH_RETA_GROUP_SIZE;
329 : 0 : uint16_t shift = i % RTE_ETH_RETA_GROUP_SIZE;
330 : 0 : uint64_t mask = (uint64_t)1 << shift;
331 : :
332 [ # # ]: 0 : if (reta_conf[idx].mask & mask)
333 : 0 : hv->rss_ind[i] = reta_conf[idx].reta[shift];
334 : :
335 : : /*
336 : : * Ensure we don't allow config that directs traffic to an Rx
337 : : * queue that we aren't going to poll
338 : : */
339 [ # # ]: 0 : if (hv->rss_ind[i] >= dev->data->nb_rx_queues) {
340 : 0 : PMD_DRV_LOG(ERR, "RSS distributing traffic to invalid Rx queue");
341 : 0 : return -EINVAL;
342 : : }
343 : : }
344 : :
345 : 0 : err = hn_rndis_conf_rss(hv, NDIS_RSS_FLAG_DISABLE);
346 [ # # ]: 0 : if (err) {
347 : 0 : PMD_DRV_LOG(NOTICE,
348 : : "rss disable failed");
349 : 0 : return err;
350 : : }
351 : :
352 : 0 : err = hn_rndis_conf_rss(hv, 0);
353 [ # # ]: 0 : if (err) {
354 : 0 : PMD_DRV_LOG(NOTICE,
355 : : "reta reconfig failed");
356 : 0 : return err;
357 : : }
358 : :
359 : 0 : return hn_vf_reta_hash_update(dev, reta_conf, reta_size);
360 : : }
361 : :
362 : 0 : static int hn_rss_reta_query(struct rte_eth_dev *dev,
363 : : struct rte_eth_rss_reta_entry64 *reta_conf,
364 : : uint16_t reta_size)
365 : : {
366 : 0 : struct hn_data *hv = dev->data->dev_private;
367 : : unsigned int i;
368 : :
369 : 0 : PMD_INIT_FUNC_TRACE();
370 : :
371 [ # # ]: 0 : if (reta_size != NDIS_HASH_INDCNT) {
372 : 0 : PMD_DRV_LOG(ERR, "Hash lookup table size does not match NDIS");
373 : 0 : return -EINVAL;
374 : : }
375 : :
376 [ # # ]: 0 : for (i = 0; i < NDIS_HASH_INDCNT; i++) {
377 : 0 : uint16_t idx = i / RTE_ETH_RETA_GROUP_SIZE;
378 : 0 : uint16_t shift = i % RTE_ETH_RETA_GROUP_SIZE;
379 : 0 : uint64_t mask = (uint64_t)1 << shift;
380 : :
381 [ # # ]: 0 : if (reta_conf[idx].mask & mask)
382 : 0 : reta_conf[idx].reta[shift] = hv->rss_ind[i];
383 : : }
384 : : return 0;
385 : : }
386 : :
387 : 0 : static void hn_rss_hash_init(struct hn_data *hv,
388 : : const struct rte_eth_rss_conf *rss_conf)
389 : : {
390 : : /* Convert from DPDK RSS hash flags to NDIS hash flags */
391 : 0 : hv->rss_hash = NDIS_HASH_FUNCTION_TOEPLITZ;
392 : :
393 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_IPV4)
394 : 0 : hv->rss_hash |= NDIS_HASH_IPV4;
395 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_TCP)
396 : 0 : hv->rss_hash |= NDIS_HASH_TCP_IPV4;
397 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_IPV6)
398 : 0 : hv->rss_hash |= NDIS_HASH_IPV6;
399 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_IPV6_EX)
400 : 0 : hv->rss_hash |= NDIS_HASH_IPV6_EX;
401 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP)
402 : 0 : hv->rss_hash |= NDIS_HASH_TCP_IPV6;
403 [ # # ]: 0 : if (rss_conf->rss_hf & RTE_ETH_RSS_IPV6_TCP_EX)
404 : 0 : hv->rss_hash |= NDIS_HASH_TCP_IPV6_EX;
405 : :
406 [ # # ]: 0 : memcpy(hv->rss_key, rss_conf->rss_key ? : rss_default_key,
407 : : NDIS_HASH_KEYSIZE_TOEPLITZ);
408 : 0 : }
409 : :
410 : 0 : static int hn_rss_hash_update(struct rte_eth_dev *dev,
411 : : struct rte_eth_rss_conf *rss_conf)
412 : : {
413 : 0 : struct hn_data *hv = dev->data->dev_private;
414 : : int err;
415 : :
416 : 0 : PMD_INIT_FUNC_TRACE();
417 : :
418 : 0 : err = hn_rndis_conf_rss(hv, NDIS_RSS_FLAG_DISABLE);
419 [ # # ]: 0 : if (err) {
420 : 0 : PMD_DRV_LOG(NOTICE,
421 : : "rss disable failed");
422 : 0 : return err;
423 : : }
424 : :
425 : 0 : hn_rss_hash_init(hv, rss_conf);
426 : :
427 [ # # ]: 0 : if (rss_conf->rss_hf != 0) {
428 : 0 : err = hn_rndis_conf_rss(hv, 0);
429 [ # # ]: 0 : if (err) {
430 : 0 : PMD_DRV_LOG(NOTICE,
431 : : "rss reconfig failed (RSS disabled)");
432 : 0 : return err;
433 : : }
434 : : }
435 : :
436 : 0 : return hn_vf_rss_hash_update(dev, rss_conf);
437 : : }
438 : :
439 : 0 : static int hn_rss_hash_conf_get(struct rte_eth_dev *dev,
440 : : struct rte_eth_rss_conf *rss_conf)
441 : : {
442 : 0 : struct hn_data *hv = dev->data->dev_private;
443 : :
444 : 0 : PMD_INIT_FUNC_TRACE();
445 : :
446 [ # # ]: 0 : if (hv->ndis_ver < NDIS_VERSION_6_20) {
447 : 0 : PMD_DRV_LOG(DEBUG, "RSS not supported on this host");
448 : 0 : return -EOPNOTSUPP;
449 : : }
450 : :
451 : 0 : rss_conf->rss_key_len = NDIS_HASH_KEYSIZE_TOEPLITZ;
452 [ # # ]: 0 : if (rss_conf->rss_key)
453 : 0 : memcpy(rss_conf->rss_key, hv->rss_key,
454 : : NDIS_HASH_KEYSIZE_TOEPLITZ);
455 : :
456 : 0 : rss_conf->rss_hf = 0;
457 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_IPV4)
458 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_IPV4;
459 : :
460 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_TCP_IPV4)
461 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_NONFRAG_IPV4_TCP;
462 : :
463 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_IPV6)
464 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_IPV6;
465 : :
466 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_IPV6_EX)
467 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_IPV6_EX;
468 : :
469 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_TCP_IPV6)
470 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_NONFRAG_IPV6_TCP;
471 : :
472 [ # # ]: 0 : if (hv->rss_hash & NDIS_HASH_TCP_IPV6_EX)
473 : 0 : rss_conf->rss_hf |= RTE_ETH_RSS_IPV6_TCP_EX;
474 : :
475 : : return 0;
476 : : }
477 : :
478 : : static int
479 : 0 : hn_dev_promiscuous_enable(struct rte_eth_dev *dev)
480 : : {
481 : 0 : struct hn_data *hv = dev->data->dev_private;
482 : :
483 : 0 : hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_PROMISCUOUS);
484 : 0 : return hn_vf_promiscuous_enable(dev);
485 : : }
486 : :
487 : : static int
488 : 0 : hn_dev_promiscuous_disable(struct rte_eth_dev *dev)
489 : : {
490 : 0 : struct hn_data *hv = dev->data->dev_private;
491 : : uint32_t filter;
492 : :
493 : : filter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST;
494 [ # # ]: 0 : if (dev->data->all_multicast)
495 : : filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
496 : 0 : hn_rndis_set_rxfilter(hv, filter);
497 : 0 : return hn_vf_promiscuous_disable(dev);
498 : : }
499 : :
500 : : static int
501 : 0 : hn_dev_allmulticast_enable(struct rte_eth_dev *dev)
502 : : {
503 : 0 : struct hn_data *hv = dev->data->dev_private;
504 : :
505 : 0 : hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_DIRECTED |
506 : : NDIS_PACKET_TYPE_ALL_MULTICAST |
507 : : NDIS_PACKET_TYPE_BROADCAST);
508 : 0 : return hn_vf_allmulticast_enable(dev);
509 : : }
510 : :
511 : : static int
512 : 0 : hn_dev_allmulticast_disable(struct rte_eth_dev *dev)
513 : : {
514 : 0 : struct hn_data *hv = dev->data->dev_private;
515 : :
516 : 0 : hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_DIRECTED |
517 : : NDIS_PACKET_TYPE_BROADCAST);
518 : 0 : return hn_vf_allmulticast_disable(dev);
519 : : }
520 : :
521 : : static int
522 : 0 : hn_dev_mc_addr_list(struct rte_eth_dev *dev,
523 : : struct rte_ether_addr *mc_addr_set,
524 : : uint32_t nb_mc_addr)
525 : : {
526 : : /* No filtering on the synthetic path, but can do it on VF */
527 : 0 : return hn_vf_mc_addr_list(dev, mc_addr_set, nb_mc_addr);
528 : : }
529 : :
530 : : /* Setup shared rx/tx queue data */
531 : 0 : static int hn_subchan_configure(struct hn_data *hv,
532 : : uint32_t subchan)
533 : : {
534 : : struct vmbus_channel *primary = hn_primary_chan(hv);
535 : : int err;
536 : : unsigned int retry = 0;
537 : :
538 : 0 : PMD_DRV_LOG(DEBUG,
539 : : "open %u subchannels", subchan);
540 : :
541 : : /* Send create sub channels command */
542 : 0 : err = hn_nvs_alloc_subchans(hv, &subchan);
543 [ # # ]: 0 : if (err)
544 : : return err;
545 : :
546 [ # # ]: 0 : while (subchan > 0) {
547 : : struct vmbus_channel *new_sc;
548 : : uint16_t chn_index;
549 : :
550 : 0 : err = rte_vmbus_subchan_open(primary, &new_sc);
551 [ # # # # ]: 0 : if (err == -ENOENT && ++retry < 1000) {
552 : : /* This can happen if not ready yet */
553 : : rte_delay_ms(10);
554 : 0 : continue;
555 : : }
556 : :
557 [ # # ]: 0 : if (err) {
558 : 0 : PMD_DRV_LOG(ERR,
559 : : "open subchannel failed: %d", err);
560 : 0 : return err;
561 : : }
562 : :
563 : 0 : rte_vmbus_set_latency(hv->vmbus, new_sc, hv->latency);
564 : :
565 : : retry = 0;
566 : 0 : chn_index = rte_vmbus_sub_channel_index(new_sc);
567 [ # # # # ]: 0 : if (chn_index == 0 || chn_index > hv->max_queues) {
568 : 0 : PMD_DRV_LOG(ERR,
569 : : "Invalid subchannel offermsg channel %u",
570 : : chn_index);
571 : 0 : return -EIO;
572 : : }
573 : :
574 : 0 : PMD_DRV_LOG(DEBUG, "new sub channel %u", chn_index);
575 : 0 : hv->channels[chn_index] = new_sc;
576 : 0 : --subchan;
577 : : }
578 : :
579 : : return err;
580 : : }
581 : :
582 : 0 : static void netvsc_hotplug_retry(void *args)
583 : : {
584 : : int ret;
585 : : struct hv_hotadd_context *hot_ctx = args;
586 : 0 : struct hn_data *hv = hot_ctx->hv;
587 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[hv->port_id];
588 : : struct rte_devargs *d = &hot_ctx->da;
589 : : char buf[256];
590 : :
591 : : DIR *di = NULL;
592 : : struct dirent *dir;
593 : : struct ifreq req;
594 : : struct rte_ether_addr eth_addr;
595 : : int s;
596 : :
597 : 0 : PMD_DRV_LOG(DEBUG, "%s: retry count %d",
598 : : __func__, hot_ctx->eal_hot_plug_retry);
599 : :
600 [ # # ]: 0 : if (hot_ctx->eal_hot_plug_retry++ > NETVSC_MAX_HOTADD_RETRY) {
601 : 0 : PMD_DRV_LOG(NOTICE, "Failed to parse PCI device retry=%d",
602 : : hot_ctx->eal_hot_plug_retry);
603 : 0 : goto free_hotadd_ctx;
604 : : }
605 : :
606 : 0 : snprintf(buf, sizeof(buf), "/sys/bus/pci/devices/%s/net", d->name);
607 : 0 : di = opendir(buf);
608 [ # # ]: 0 : if (!di) {
609 : 0 : PMD_DRV_LOG(DEBUG, "%s: can't open directory %s, "
610 : : "retrying in 1 second", __func__, buf);
611 : : /* The device is still being initialized, retry after 1 second */
612 : 0 : rte_eal_alarm_set(1000000, netvsc_hotplug_retry, hot_ctx);
613 : 0 : return;
614 : : }
615 : :
616 [ # # ]: 0 : while ((dir = readdir(di))) {
617 : : /* Skip . and .. directories */
618 [ # # # # ]: 0 : if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
619 : 0 : continue;
620 : :
621 : : /* trying to get mac address if this is a network device*/
622 : 0 : s = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
623 [ # # ]: 0 : if (s == -1) {
624 : 0 : PMD_DRV_LOG(ERR, "Failed to create socket errno %d",
625 : : errno);
626 : 0 : break;
627 : : }
628 : : strlcpy(req.ifr_name, dir->d_name, sizeof(req.ifr_name));
629 : 0 : ret = ioctl(s, SIOCGIFHWADDR, &req);
630 : 0 : close(s);
631 [ # # ]: 0 : if (ret == -1) {
632 : 0 : PMD_DRV_LOG(ERR,
633 : : "Failed to send SIOCGIFHWADDR for device %s",
634 : : dir->d_name);
635 : 0 : break;
636 : : }
637 [ # # ]: 0 : if (req.ifr_hwaddr.sa_family != ARPHRD_ETHER)
638 : 0 : continue;
639 : :
640 : : memcpy(eth_addr.addr_bytes, req.ifr_hwaddr.sa_data,
641 : : RTE_DIM(eth_addr.addr_bytes));
642 : :
643 [ # # ]: 0 : if (rte_is_same_ether_addr(ð_addr, dev->data->mac_addrs)) {
644 : : struct da_cache *cache;
645 : : char *drv_str = NULL;
646 : :
647 : : rte_spinlock_lock(&netvsc_lock);
648 : :
649 [ # # ]: 0 : LIST_FOREACH(cache, &da_cache_list, list) {
650 [ # # ]: 0 : if (strcmp(cache->name, d->name) == 0)
651 : : break;
652 : : }
653 : :
654 [ # # ]: 0 : if (cache)
655 : 0 : drv_str = strdup(cache->drv_str);
656 : :
657 : : rte_spinlock_unlock(&netvsc_lock);
658 : :
659 [ # # ]: 0 : PMD_DRV_LOG(NOTICE,
660 : : "Found matching MAC address, adding device %s network name %s args %s",
661 : : d->name, dir->d_name, drv_str ? drv_str : "");
662 : :
663 : : /* If this device has been hot removed from this
664 : : * parent device, restore its args.
665 : : */
666 : 0 : ret = rte_eal_hotplug_add(d->bus->name, d->name, drv_str ? drv_str : "");
667 [ # # ]: 0 : if (ret) {
668 : 0 : PMD_DRV_LOG(ERR,
669 : : "Failed to add PCI device %s",
670 : : d->name);
671 : : }
672 : :
673 : 0 : free(drv_str);
674 : :
675 : 0 : break;
676 : : }
677 : : }
678 : :
679 : 0 : free_hotadd_ctx:
680 : : if (di)
681 : 0 : closedir(di);
682 : :
683 : 0 : rte_spinlock_lock(&hv->hotadd_lock);
684 [ # # ]: 0 : LIST_REMOVE(hot_ctx, list);
685 : : rte_spinlock_unlock(&hv->hotadd_lock);
686 : :
687 : 0 : free(hot_ctx);
688 : : }
689 : :
690 : : static void
691 : 0 : netvsc_hotadd_callback(const char *device_name, enum rte_dev_event_type type,
692 : : void *arg)
693 : : {
694 : : struct hn_data *hv = arg;
695 : : struct hv_hotadd_context *hot_ctx;
696 : : struct rte_devargs *d;
697 : : int ret;
698 : :
699 : 0 : PMD_DRV_LOG(INFO, "Device notification type=%d device_name=%s",
700 : : type, device_name);
701 : :
702 [ # # ]: 0 : switch (type) {
703 : 0 : case RTE_DEV_EVENT_ADD:
704 : : /* if we already has a VF, don't check on hot add */
705 [ # # ]: 0 : if (hv->vf_ctx.vf_state > vf_removed)
706 : : break;
707 : :
708 : 0 : hot_ctx = calloc(1, sizeof(*hot_ctx));
709 : :
710 [ # # ]: 0 : if (!hot_ctx) {
711 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate hotadd context");
712 : 0 : return;
713 : : }
714 : :
715 : 0 : hot_ctx->hv = hv;
716 : 0 : d = &hot_ctx->da;
717 : :
718 : 0 : ret = rte_devargs_parse(d, device_name);
719 [ # # ]: 0 : if (ret) {
720 : 0 : PMD_DRV_LOG(ERR,
721 : : "devargs parsing failed ret=%d", ret);
722 : 0 : goto free_ctx;
723 : : }
724 : :
725 [ # # ]: 0 : if (!strcmp(d->bus->name, "pci")) {
726 : : /* Start the process of figuring out if this
727 : : * PCI device is a VF device
728 : : */
729 : 0 : rte_spinlock_lock(&hv->hotadd_lock);
730 [ # # ]: 0 : LIST_INSERT_HEAD(&hv->hotadd_list, hot_ctx, list);
731 : : rte_spinlock_unlock(&hv->hotadd_lock);
732 : 0 : rte_eal_alarm_set(1000000, netvsc_hotplug_retry, hot_ctx);
733 : 0 : return;
734 : : }
735 : :
736 : : /* We will switch to VF on RDNIS configure message
737 : : * sent from VSP
738 : : */
739 : 0 : free_ctx:
740 : 0 : free(hot_ctx);
741 : 0 : break;
742 : :
743 : : default:
744 : : break;
745 : : }
746 : : }
747 : :
748 : 0 : static int hn_dev_configure(struct rte_eth_dev *dev)
749 : : {
750 : 0 : struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
751 : 0 : struct rte_eth_rss_conf *rss_conf = &dev_conf->rx_adv_conf.rss_conf;
752 : : const struct rte_eth_rxmode *rxmode = &dev_conf->rxmode;
753 : : const struct rte_eth_txmode *txmode = &dev_conf->txmode;
754 : 0 : struct hn_data *hv = dev->data->dev_private;
755 : : uint64_t unsupported;
756 : : int i, err, subchan;
757 : :
758 : 0 : PMD_INIT_FUNC_TRACE();
759 : :
760 [ # # ]: 0 : if (dev_conf->rxmode.mq_mode & RTE_ETH_MQ_RX_RSS_FLAG)
761 : 0 : dev_conf->rxmode.offloads |= RTE_ETH_RX_OFFLOAD_RSS_HASH;
762 : :
763 : 0 : unsupported = txmode->offloads & ~HN_TX_OFFLOAD_CAPS;
764 [ # # ]: 0 : if (unsupported) {
765 : 0 : PMD_DRV_LOG(NOTICE,
766 : : "unsupported TX offload: %#" PRIx64,
767 : : unsupported);
768 : 0 : return -EINVAL;
769 : : }
770 : :
771 : 0 : unsupported = rxmode->offloads & ~HN_RX_OFFLOAD_CAPS;
772 [ # # ]: 0 : if (unsupported) {
773 : 0 : PMD_DRV_LOG(NOTICE,
774 : : "unsupported RX offload: %#" PRIx64,
775 : : rxmode->offloads);
776 : 0 : return -EINVAL;
777 : : }
778 : :
779 : 0 : hv->vlan_strip = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_STRIP);
780 : :
781 : 0 : err = hn_rndis_conf_offload(hv, txmode->offloads,
782 : : rxmode->offloads);
783 [ # # ]: 0 : if (err) {
784 : 0 : PMD_DRV_LOG(NOTICE,
785 : : "offload configure failed");
786 : 0 : return err;
787 : : }
788 : :
789 : 0 : hv->num_queues = RTE_MAX(dev->data->nb_rx_queues,
790 : : dev->data->nb_tx_queues);
791 : :
792 [ # # ]: 0 : for (i = 0; i < NDIS_HASH_INDCNT; i++)
793 : 0 : hv->rss_ind[i] = i % dev->data->nb_rx_queues;
794 : :
795 : 0 : hn_rss_hash_init(hv, rss_conf);
796 : :
797 : 0 : subchan = hv->num_queues - 1;
798 [ # # ]: 0 : if (subchan > 0) {
799 : 0 : err = hn_subchan_configure(hv, subchan);
800 [ # # ]: 0 : if (err) {
801 : 0 : PMD_DRV_LOG(NOTICE,
802 : : "subchannel configuration failed");
803 : 0 : return err;
804 : : }
805 : :
806 : 0 : err = hn_rndis_conf_rss(hv, NDIS_RSS_FLAG_DISABLE);
807 [ # # ]: 0 : if (err) {
808 : 0 : PMD_DRV_LOG(NOTICE,
809 : : "rss disable failed");
810 : 0 : return err;
811 : : }
812 : :
813 [ # # ]: 0 : if (rss_conf->rss_hf != 0) {
814 : 0 : err = hn_rndis_conf_rss(hv, 0);
815 [ # # ]: 0 : if (err) {
816 : 0 : PMD_DRV_LOG(NOTICE,
817 : : "initial RSS config failed");
818 : 0 : return err;
819 : : }
820 : : }
821 : : }
822 : :
823 : 0 : return hn_vf_configure_locked(dev, dev_conf);
824 : : }
825 : :
826 : 0 : static int hn_dev_stats_get(struct rte_eth_dev *dev,
827 : : struct rte_eth_stats *stats,
828 : : struct eth_queue_stats *qstats)
829 : : {
830 : : unsigned int i;
831 : :
832 : 0 : hn_vf_stats_get(dev, stats, qstats);
833 : :
834 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
835 : 0 : const struct hn_tx_queue *txq = dev->data->tx_queues[i];
836 : :
837 [ # # ]: 0 : if (!txq)
838 : 0 : continue;
839 : :
840 : 0 : stats->opackets += txq->stats.packets;
841 : 0 : stats->obytes += txq->stats.bytes;
842 : 0 : stats->oerrors += txq->stats.errors;
843 : :
844 [ # # ]: 0 : if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
845 : 0 : qstats->q_opackets[i] += txq->stats.packets;
846 : 0 : qstats->q_obytes[i] += txq->stats.bytes;
847 : : }
848 : : }
849 : :
850 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
851 : 0 : const struct hn_rx_queue *rxq = dev->data->rx_queues[i];
852 : :
853 [ # # ]: 0 : if (!rxq)
854 : 0 : continue;
855 : :
856 : 0 : stats->ipackets += rxq->stats.packets;
857 : 0 : stats->ibytes += rxq->stats.bytes;
858 : 0 : stats->ierrors += rxq->stats.errors;
859 : 0 : stats->imissed += rxq->stats.ring_full;
860 : :
861 [ # # ]: 0 : if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
862 : 0 : qstats->q_ipackets[i] += rxq->stats.packets;
863 : 0 : qstats->q_ibytes[i] += rxq->stats.bytes;
864 : : }
865 : : }
866 : :
867 : 0 : stats->rx_nombuf += dev->data->rx_mbuf_alloc_failed;
868 : 0 : return 0;
869 : : }
870 : :
871 : : static int
872 : 0 : hn_dev_stats_reset(struct rte_eth_dev *dev)
873 : : {
874 : : unsigned int i;
875 : :
876 : 0 : PMD_INIT_FUNC_TRACE();
877 : :
878 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
879 : 0 : struct hn_tx_queue *txq = dev->data->tx_queues[i];
880 : :
881 [ # # ]: 0 : if (!txq)
882 : 0 : continue;
883 : 0 : memset(&txq->stats, 0, sizeof(struct hn_stats));
884 : : }
885 : :
886 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
887 : 0 : struct hn_rx_queue *rxq = dev->data->rx_queues[i];
888 : :
889 [ # # ]: 0 : if (!rxq)
890 : 0 : continue;
891 : :
892 : 0 : memset(&rxq->stats, 0, sizeof(struct hn_stats));
893 : : }
894 : :
895 : 0 : return 0;
896 : : }
897 : :
898 : : static int
899 : 0 : hn_dev_xstats_reset(struct rte_eth_dev *dev)
900 : : {
901 : : int ret;
902 : :
903 : 0 : ret = hn_dev_stats_reset(dev);
904 [ # # ]: 0 : if (ret != 0)
905 : : return 0;
906 : :
907 : 0 : return hn_vf_xstats_reset(dev);
908 : : }
909 : :
910 : : static int
911 : 0 : hn_dev_xstats_count(struct rte_eth_dev *dev)
912 : : {
913 : : int ret, count;
914 : :
915 : 0 : count = dev->data->nb_tx_queues * RTE_DIM(hn_stat_strings);
916 : 0 : count += dev->data->nb_rx_queues * RTE_DIM(hn_stat_strings);
917 : :
918 : 0 : ret = hn_vf_xstats_get_names(dev, NULL, 0);
919 [ # # ]: 0 : if (ret < 0)
920 : : return ret;
921 : :
922 : 0 : return count + ret;
923 : : }
924 : :
925 : : static int
926 : 0 : hn_dev_xstats_get_names(struct rte_eth_dev *dev,
927 : : struct rte_eth_xstat_name *xstats_names,
928 : : unsigned int limit)
929 : : {
930 : : unsigned int i, t, count = 0;
931 : : int ret;
932 : :
933 [ # # ]: 0 : if (!xstats_names)
934 : 0 : return hn_dev_xstats_count(dev);
935 : :
936 : : /* Note: limit checked in rte_eth_xstats_names() */
937 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
938 : 0 : const struct hn_tx_queue *txq = dev->data->tx_queues[i];
939 : :
940 [ # # ]: 0 : if (!txq)
941 : 0 : continue;
942 : :
943 [ # # ]: 0 : if (count >= limit)
944 : : break;
945 : :
946 [ # # ]: 0 : for (t = 0; t < RTE_DIM(hn_stat_strings); t++)
947 : 0 : snprintf(xstats_names[count++].name,
948 : : RTE_ETH_XSTATS_NAME_SIZE,
949 : 0 : "tx_q%u_%s", i, hn_stat_strings[t].name);
950 : : }
951 : :
952 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
953 : 0 : const struct hn_rx_queue *rxq = dev->data->rx_queues[i];
954 : :
955 [ # # ]: 0 : if (!rxq)
956 : 0 : continue;
957 : :
958 [ # # ]: 0 : if (count >= limit)
959 : : break;
960 : :
961 [ # # ]: 0 : for (t = 0; t < RTE_DIM(hn_stat_strings); t++)
962 : 0 : snprintf(xstats_names[count++].name,
963 : : RTE_ETH_XSTATS_NAME_SIZE,
964 : : "rx_q%u_%s", i,
965 : 0 : hn_stat_strings[t].name);
966 : : }
967 : :
968 : 0 : ret = hn_vf_xstats_get_names(dev, xstats_names + count,
969 : : limit - count);
970 [ # # ]: 0 : if (ret < 0)
971 : : return ret;
972 : :
973 : 0 : return count + ret;
974 : : }
975 : :
976 : : static int
977 : 0 : hn_dev_xstats_get(struct rte_eth_dev *dev,
978 : : struct rte_eth_xstat *xstats,
979 : : unsigned int n)
980 : : {
981 : : unsigned int i, t, count = 0;
982 : 0 : const unsigned int nstats = hn_dev_xstats_count(dev);
983 : : const char *stats;
984 : : int ret;
985 : :
986 : 0 : PMD_INIT_FUNC_TRACE();
987 : :
988 [ # # ]: 0 : if (n < nstats)
989 : : return nstats;
990 : :
991 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
992 : 0 : const struct hn_tx_queue *txq = dev->data->tx_queues[i];
993 : :
994 [ # # ]: 0 : if (!txq)
995 : 0 : continue;
996 : :
997 : 0 : stats = (const char *)&txq->stats;
998 [ # # ]: 0 : for (t = 0; t < RTE_DIM(hn_stat_strings); t++, count++) {
999 : 0 : xstats[count].id = count;
1000 : 0 : xstats[count].value = *(const uint64_t *)
1001 : 0 : (stats + hn_stat_strings[t].offset);
1002 : : }
1003 : : }
1004 : :
1005 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
1006 : 0 : const struct hn_rx_queue *rxq = dev->data->rx_queues[i];
1007 : :
1008 [ # # ]: 0 : if (!rxq)
1009 : 0 : continue;
1010 : :
1011 : 0 : stats = (const char *)&rxq->stats;
1012 [ # # ]: 0 : for (t = 0; t < RTE_DIM(hn_stat_strings); t++, count++) {
1013 : 0 : xstats[count].id = count;
1014 : 0 : xstats[count].value = *(const uint64_t *)
1015 : 0 : (stats + hn_stat_strings[t].offset);
1016 : : }
1017 : : }
1018 : :
1019 : 0 : ret = hn_vf_xstats_get(dev, xstats, count, n);
1020 [ # # ]: 0 : if (ret < 0)
1021 : : return ret;
1022 : :
1023 : 0 : return count + ret;
1024 : : }
1025 : :
1026 : : static int
1027 : 0 : hn_dev_start(struct rte_eth_dev *dev)
1028 : : {
1029 : 0 : struct hn_data *hv = dev->data->dev_private;
1030 : : int i, error;
1031 : :
1032 : 0 : PMD_INIT_FUNC_TRACE();
1033 : :
1034 : : /* Register to monitor hot plug events */
1035 : 0 : error = rte_dev_event_callback_register(NULL, netvsc_hotadd_callback,
1036 : : hv);
1037 [ # # ]: 0 : if (error) {
1038 : 0 : PMD_DRV_LOG(ERR, "failed to register device event callback");
1039 : 0 : return error;
1040 : : }
1041 : :
1042 : 0 : error = hn_rndis_set_rxfilter(hv,
1043 : : NDIS_PACKET_TYPE_BROADCAST |
1044 : : NDIS_PACKET_TYPE_ALL_MULTICAST |
1045 : : NDIS_PACKET_TYPE_DIRECTED);
1046 [ # # ]: 0 : if (error)
1047 : : return error;
1048 : :
1049 : 0 : error = hn_vf_start(dev);
1050 [ # # ]: 0 : if (error)
1051 : 0 : hn_rndis_set_rxfilter(hv, 0);
1052 : :
1053 : : /* Initialize Link state */
1054 [ # # ]: 0 : if (error == 0)
1055 : 0 : hn_dev_link_update(dev, 0);
1056 : :
1057 [ # # ]: 0 : for (i = 0; i < hv->num_queues; i++) {
1058 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
1059 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
1060 : : }
1061 : :
1062 : : return error;
1063 : : }
1064 : :
1065 : : static int
1066 : 0 : hn_dev_stop(struct rte_eth_dev *dev)
1067 : : {
1068 : 0 : struct hn_data *hv = dev->data->dev_private;
1069 : : int i, ret;
1070 : :
1071 : 0 : PMD_INIT_FUNC_TRACE();
1072 : 0 : dev->data->dev_started = 0;
1073 : :
1074 : 0 : rte_dev_event_callback_unregister(NULL, netvsc_hotadd_callback, hv);
1075 : 0 : hn_rndis_set_rxfilter(hv, 0);
1076 : 0 : ret = hn_vf_stop(dev);
1077 : :
1078 [ # # ]: 0 : for (i = 0; i < hv->num_queues; i++) {
1079 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
1080 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
1081 : : }
1082 : :
1083 : 0 : return ret;
1084 : : }
1085 : :
1086 : : static int
1087 : 0 : hn_dev_close(struct rte_eth_dev *dev)
1088 : : {
1089 : : int ret;
1090 : 0 : struct hn_data *hv = dev->data->dev_private;
1091 : : struct hv_hotadd_context *hot_ctx;
1092 : :
1093 : 0 : PMD_INIT_FUNC_TRACE();
1094 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1095 : : return 0;
1096 : :
1097 : 0 : rte_spinlock_lock(&hv->hotadd_lock);
1098 [ # # ]: 0 : while (!LIST_EMPTY(&hv->hotadd_list)) {
1099 : : hot_ctx = LIST_FIRST(&hv->hotadd_list);
1100 : 0 : rte_eal_alarm_cancel(netvsc_hotplug_retry, hot_ctx);
1101 [ # # ]: 0 : LIST_REMOVE(hot_ctx, list);
1102 : 0 : free(hot_ctx);
1103 : : }
1104 : : rte_spinlock_unlock(&hv->hotadd_lock);
1105 : :
1106 : 0 : ret = hn_vf_close(dev);
1107 : 0 : hn_dev_free_queues(dev);
1108 : :
1109 : 0 : return ret;
1110 : : }
1111 : :
1112 : : /*
1113 : : * Setup connection between PMD and kernel.
1114 : : */
1115 : : static int
1116 : 0 : hn_attach(struct hn_data *hv, unsigned int mtu)
1117 : : {
1118 : : int error;
1119 : :
1120 : : /* Attach NVS */
1121 : 0 : error = hn_nvs_attach(hv, mtu);
1122 [ # # ]: 0 : if (error)
1123 : 0 : goto failed_nvs;
1124 : :
1125 : : /* Attach RNDIS */
1126 : 0 : error = hn_rndis_attach(hv);
1127 [ # # ]: 0 : if (error)
1128 : 0 : goto failed_rndis;
1129 : :
1130 : : /*
1131 : : * NOTE:
1132 : : * Under certain conditions on certain versions of Hyper-V,
1133 : : * the RNDIS rxfilter is _not_ zero on the hypervisor side
1134 : : * after the successful RNDIS initialization.
1135 : : */
1136 : 0 : hn_rndis_set_rxfilter(hv, NDIS_PACKET_TYPE_NONE);
1137 : 0 : return 0;
1138 : : failed_rndis:
1139 : 0 : hn_nvs_detach(hv);
1140 : : failed_nvs:
1141 : : return error;
1142 : : }
1143 : :
1144 : : static void
1145 : : hn_detach(struct hn_data *hv)
1146 : : {
1147 : 0 : hn_nvs_detach(hv);
1148 : 0 : hn_rndis_detach(hv);
1149 : : }
1150 : :
1151 : : /*
1152 : : * Connects EXISTING rx/tx queues to NEW vmbus channel(s), and
1153 : : * re-initializes NDIS and RNDIS, including re-sending initial
1154 : : * NDIS/RNDIS configuration. To be used after the underlying vmbus
1155 : : * has been un- and re-mapped, e.g. as must happen when the device
1156 : : * MTU is changed.
1157 : : */
1158 : : static int
1159 : 0 : hn_reinit(struct rte_eth_dev *dev, uint16_t mtu)
1160 : : {
1161 : 0 : struct hn_data *hv = dev->data->dev_private;
1162 : 0 : struct hn_rx_queue **rxqs = (struct hn_rx_queue **)dev->data->rx_queues;
1163 : 0 : struct hn_tx_queue **txqs = (struct hn_tx_queue **)dev->data->tx_queues;
1164 : : int i, ret = 0;
1165 : :
1166 : : /* Point primary queues at new primary channel */
1167 [ # # ]: 0 : if (rxqs[0]) {
1168 : 0 : rxqs[0]->chan = hv->channels[0];
1169 : 0 : txqs[0]->chan = hv->channels[0];
1170 : : }
1171 : :
1172 : 0 : ret = hn_attach(hv, mtu);
1173 [ # # ]: 0 : if (ret)
1174 : : return ret;
1175 : :
1176 : : /* Create vmbus subchannels, additional RNDIS configuration */
1177 : 0 : ret = hn_dev_configure(dev);
1178 [ # # ]: 0 : if (ret)
1179 : : return ret;
1180 : :
1181 : : /* Point any additional queues at new subchannels */
1182 [ # # ]: 0 : if (rxqs[0]) {
1183 [ # # ]: 0 : for (i = 1; i < dev->data->nb_rx_queues; i++)
1184 : 0 : rxqs[i]->chan = hv->channels[i];
1185 [ # # ]: 0 : for (i = 1; i < dev->data->nb_tx_queues; i++)
1186 : 0 : txqs[i]->chan = hv->channels[i];
1187 : : }
1188 : :
1189 : : return ret;
1190 : : }
1191 : :
1192 : : static int
1193 : 0 : hn_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
1194 : : {
1195 : 0 : struct hn_data *hv = dev->data->dev_private;
1196 : 0 : unsigned int orig_mtu = dev->data->mtu;
1197 : : uint32_t rndis_mtu;
1198 : : int ret = 0;
1199 : : int i;
1200 : :
1201 [ # # ]: 0 : if (dev->data->dev_started) {
1202 : 0 : PMD_DRV_LOG(ERR, "Device must be stopped before changing MTU");
1203 : 0 : return -EBUSY;
1204 : : }
1205 : :
1206 : : /* Change MTU of underlying VF dev first, if it exists */
1207 : 0 : ret = hn_vf_mtu_set(dev, mtu);
1208 [ # # ]: 0 : if (ret)
1209 : : return ret;
1210 : :
1211 : : /* Release channel resources */
1212 : : hn_detach(hv);
1213 : :
1214 : : /* Close any secondary vmbus channels */
1215 [ # # ]: 0 : for (i = 1; i < hv->num_queues; i++)
1216 : 0 : rte_vmbus_chan_close(hv->channels[i]);
1217 : :
1218 : : /* Close primary vmbus channel */
1219 : 0 : rte_free(hv->channels[0]);
1220 : :
1221 : : /* Unmap and re-map vmbus device */
1222 : 0 : rte_vmbus_unmap_device(hv->vmbus);
1223 : 0 : ret = rte_vmbus_map_device(hv->vmbus);
1224 [ # # ]: 0 : if (ret) {
1225 : : /* This is a catastrophic error - the device is unusable */
1226 : 0 : PMD_DRV_LOG(ERR, "Could not re-map vmbus device!");
1227 : 0 : return ret;
1228 : : }
1229 : :
1230 : : /* Update pointers to re-mapped UIO resources */
1231 : 0 : hv->rxbuf_res = hv->vmbus->resource[HV_RECV_BUF_MAP];
1232 : 0 : hv->chim_res = hv->vmbus->resource[HV_SEND_BUF_MAP];
1233 : :
1234 : : /* Re-open the primary vmbus channel */
1235 : 0 : ret = rte_vmbus_chan_open(hv->vmbus, &hv->channels[0]);
1236 [ # # ]: 0 : if (ret) {
1237 : : /* This is a catastrophic error - the device is unusable */
1238 : 0 : PMD_DRV_LOG(ERR, "Could not re-open vmbus channel!");
1239 : 0 : return ret;
1240 : : }
1241 : :
1242 : 0 : rte_vmbus_set_latency(hv->vmbus, hv->channels[0], hv->latency);
1243 : :
1244 : 0 : ret = hn_reinit(dev, mtu);
1245 [ # # ]: 0 : if (!ret)
1246 : 0 : goto out;
1247 : :
1248 : : /* In case of error, attempt to restore original MTU */
1249 : 0 : ret = hn_reinit(dev, orig_mtu);
1250 [ # # ]: 0 : if (ret)
1251 : 0 : PMD_DRV_LOG(ERR, "Restoring original MTU failed for netvsc");
1252 : :
1253 : 0 : ret = hn_vf_mtu_set(dev, orig_mtu);
1254 [ # # ]: 0 : if (ret)
1255 : 0 : PMD_DRV_LOG(ERR, "Restoring original MTU failed for VF");
1256 : :
1257 : 0 : out:
1258 [ # # ]: 0 : if (hn_rndis_get_mtu(hv, &rndis_mtu)) {
1259 : 0 : PMD_DRV_LOG(ERR, "Could not get MTU via RNDIS");
1260 : : } else {
1261 : 0 : dev->data->mtu = (uint16_t)rndis_mtu;
1262 : 0 : PMD_DRV_LOG(DEBUG, "RNDIS MTU is %u", dev->data->mtu);
1263 : : }
1264 : :
1265 : : return ret;
1266 : : }
1267 : :
1268 : : static const struct eth_dev_ops hn_eth_dev_ops = {
1269 : : .dev_configure = hn_dev_configure,
1270 : : .dev_start = hn_dev_start,
1271 : : .dev_stop = hn_dev_stop,
1272 : : .dev_close = hn_dev_close,
1273 : : .dev_infos_get = hn_dev_info_get,
1274 : : .txq_info_get = hn_dev_tx_queue_info,
1275 : : .rxq_info_get = hn_dev_rx_queue_info,
1276 : : .dev_supported_ptypes_get = hn_vf_supported_ptypes,
1277 : : .promiscuous_enable = hn_dev_promiscuous_enable,
1278 : : .promiscuous_disable = hn_dev_promiscuous_disable,
1279 : : .allmulticast_enable = hn_dev_allmulticast_enable,
1280 : : .allmulticast_disable = hn_dev_allmulticast_disable,
1281 : : .set_mc_addr_list = hn_dev_mc_addr_list,
1282 : : .mtu_set = hn_dev_mtu_set,
1283 : : .reta_update = hn_rss_reta_update,
1284 : : .reta_query = hn_rss_reta_query,
1285 : : .rss_hash_update = hn_rss_hash_update,
1286 : : .rss_hash_conf_get = hn_rss_hash_conf_get,
1287 : : .tx_queue_setup = hn_dev_tx_queue_setup,
1288 : : .tx_queue_release = hn_dev_tx_queue_release,
1289 : : .tx_done_cleanup = hn_dev_tx_done_cleanup,
1290 : : .rx_queue_setup = hn_dev_rx_queue_setup,
1291 : : .rx_queue_release = hn_dev_rx_queue_release,
1292 : : .link_update = hn_dev_link_update,
1293 : : .stats_get = hn_dev_stats_get,
1294 : : .stats_reset = hn_dev_stats_reset,
1295 : : .xstats_get = hn_dev_xstats_get,
1296 : : .xstats_get_names = hn_dev_xstats_get_names,
1297 : : .xstats_reset = hn_dev_xstats_reset,
1298 : : };
1299 : :
1300 : : static int
1301 : 0 : eth_hn_dev_init(struct rte_eth_dev *eth_dev)
1302 : : {
1303 : 0 : struct hn_data *hv = eth_dev->data->dev_private;
1304 : 0 : struct rte_device *device = eth_dev->device;
1305 : : struct rte_vmbus_device *vmbus;
1306 : : uint32_t mtu;
1307 : : unsigned int rxr_cnt;
1308 : : int err, max_chan;
1309 : :
1310 : 0 : PMD_INIT_FUNC_TRACE();
1311 : :
1312 : : rte_spinlock_init(&hv->hotadd_lock);
1313 : 0 : LIST_INIT(&hv->hotadd_list);
1314 : :
1315 : 0 : vmbus = container_of(device, struct rte_vmbus_device, device);
1316 : 0 : eth_dev->dev_ops = &hn_eth_dev_ops;
1317 : 0 : eth_dev->rx_queue_count = hn_dev_rx_queue_count;
1318 : 0 : eth_dev->rx_descriptor_status = hn_dev_rx_queue_status;
1319 : 0 : eth_dev->tx_descriptor_status = hn_dev_tx_descriptor_status;
1320 : 0 : eth_dev->tx_pkt_burst = &hn_xmit_pkts;
1321 : 0 : eth_dev->rx_pkt_burst = &hn_recv_pkts;
1322 : :
1323 : : /*
1324 : : * for secondary processes, we don't initialize any further as primary
1325 : : * has already done this work.
1326 : : */
1327 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1328 : : return 0;
1329 : :
1330 : 0 : eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
1331 : :
1332 : : /* Since Hyper-V only supports one MAC address */
1333 : 0 : eth_dev->data->mac_addrs = rte_calloc("hv_mac", HN_MAX_MAC_ADDRS,
1334 : : sizeof(struct rte_ether_addr), 0);
1335 [ # # ]: 0 : if (eth_dev->data->mac_addrs == NULL) {
1336 : 0 : PMD_INIT_LOG(ERR,
1337 : : "Failed to allocate memory store MAC addresses");
1338 : 0 : return -ENOMEM;
1339 : : }
1340 : :
1341 : 0 : hv->vmbus = vmbus;
1342 : 0 : hv->rxbuf_res = vmbus->resource[HV_RECV_BUF_MAP];
1343 : 0 : hv->chim_res = vmbus->resource[HV_SEND_BUF_MAP];
1344 : 0 : hv->port_id = eth_dev->data->port_id;
1345 : 0 : hv->latency = HN_CHAN_LATENCY_NS;
1346 : 0 : hv->rx_copybreak = HN_RXCOPY_THRESHOLD;
1347 : 0 : hv->tx_copybreak = HN_TXCOPY_THRESHOLD;
1348 : 0 : hv->rx_extmbuf_enable = HN_RX_EXTMBUF_ENABLE;
1349 : 0 : hv->max_queues = 1;
1350 : :
1351 : : rte_rwlock_init(&hv->vf_lock);
1352 : 0 : hv->vf_ctx.vf_vsc_switched = false;
1353 : 0 : hv->vf_ctx.vf_vsp_reported = false;
1354 : 0 : hv->vf_ctx.vf_attached = false;
1355 : 0 : hv->vf_ctx.vf_state = vf_unknown;
1356 : :
1357 : 0 : err = hn_parse_args(eth_dev);
1358 [ # # ]: 0 : if (err)
1359 : : return err;
1360 : :
1361 : 0 : strlcpy(hv->owner.name, eth_dev->device->name,
1362 : : RTE_ETH_MAX_OWNER_NAME_LEN);
1363 : 0 : err = rte_eth_dev_owner_new(&hv->owner.id);
1364 [ # # ]: 0 : if (err) {
1365 : 0 : PMD_INIT_LOG(ERR, "Can not get owner id");
1366 : 0 : return err;
1367 : : }
1368 : :
1369 : : /* Initialize primary channel input for control operations */
1370 : 0 : err = rte_vmbus_chan_open(vmbus, &hv->channels[0]);
1371 [ # # ]: 0 : if (err)
1372 : : return err;
1373 : :
1374 : 0 : rte_vmbus_set_latency(hv->vmbus, hv->channels[0], hv->latency);
1375 : :
1376 : 0 : hv->primary = hn_rx_queue_alloc(hv, 0,
1377 : 0 : eth_dev->device->numa_node);
1378 : :
1379 [ # # ]: 0 : if (!hv->primary)
1380 : : return -ENOMEM;
1381 : :
1382 : 0 : err = hn_attach(hv, RTE_ETHER_MTU);
1383 [ # # ]: 0 : if (err)
1384 : 0 : goto failed;
1385 : :
1386 : 0 : err = hn_chim_init(eth_dev);
1387 [ # # ]: 0 : if (err)
1388 : 0 : goto failed;
1389 : :
1390 : 0 : err = hn_rndis_get_mtu(hv, &mtu);
1391 [ # # ]: 0 : if (err)
1392 : 0 : goto failed;
1393 : 0 : eth_dev->data->mtu = (uint16_t)mtu;
1394 : 0 : PMD_INIT_LOG(DEBUG, "RNDIS MTU is %u", eth_dev->data->mtu);
1395 : :
1396 : 0 : err = hn_rndis_get_eaddr(hv, eth_dev->data->mac_addrs->addr_bytes);
1397 [ # # ]: 0 : if (err)
1398 : 0 : goto failed;
1399 : :
1400 : : /* Multi queue requires later versions of windows server */
1401 [ # # ]: 0 : if (hv->nvs_ver < NVS_VERSION_5)
1402 : : return 0;
1403 : :
1404 : 0 : max_chan = rte_vmbus_max_channels(vmbus);
1405 : 0 : PMD_INIT_LOG(DEBUG, "VMBus max channels %d", max_chan);
1406 [ # # ]: 0 : if (max_chan <= 0)
1407 : 0 : goto failed;
1408 : :
1409 [ # # ]: 0 : if (hn_rndis_query_rsscaps(hv, &rxr_cnt) != 0)
1410 : 0 : rxr_cnt = 1;
1411 : :
1412 : 0 : hv->max_queues = RTE_MIN(rxr_cnt, (unsigned int)max_chan);
1413 : :
1414 : : /* If VF was reported but not added, do it now */
1415 [ # # # # ]: 0 : if (hv->vf_ctx.vf_vsp_reported && !hv->vf_ctx.vf_vsc_switched) {
1416 : 0 : PMD_INIT_LOG(DEBUG, "Adding VF device");
1417 : :
1418 : 0 : err = hn_vf_add(eth_dev, hv);
1419 : : }
1420 : :
1421 : : return 0;
1422 : :
1423 : 0 : failed:
1424 : 0 : PMD_INIT_LOG(NOTICE, "device init failed");
1425 : :
1426 : 0 : hn_chim_uninit(eth_dev);
1427 : : hn_detach(hv);
1428 : 0 : return err;
1429 : : }
1430 : :
1431 : : static int
1432 : 0 : eth_hn_dev_uninit(struct rte_eth_dev *eth_dev)
1433 : : {
1434 : 0 : struct hn_data *hv = eth_dev->data->dev_private;
1435 : : int ret, ret_stop;
1436 : :
1437 : 0 : PMD_INIT_FUNC_TRACE();
1438 : :
1439 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1440 : : return 0;
1441 : :
1442 : 0 : ret_stop = hn_dev_stop(eth_dev);
1443 : 0 : hn_dev_close(eth_dev);
1444 : :
1445 : : hn_detach(hv);
1446 : 0 : hn_chim_uninit(eth_dev);
1447 : 0 : rte_vmbus_chan_close(hv->channels[0]);
1448 : 0 : rte_free(hv->primary);
1449 : 0 : ret = rte_eth_dev_owner_delete(hv->owner.id);
1450 [ # # ]: 0 : if (ret != 0)
1451 : 0 : return ret;
1452 : :
1453 : : return ret_stop;
1454 : : }
1455 : :
1456 : 0 : static int populate_cache_list(void)
1457 : : {
1458 : : int ret = 0;
1459 : : struct rte_devargs *da;
1460 : :
1461 : : rte_spinlock_lock(&netvsc_lock);
1462 : 0 : da_cache_usage++;
1463 [ # # ]: 0 : if (da_cache_usage > 1) {
1464 : : ret = 0;
1465 : 0 : goto out;
1466 : : }
1467 : :
1468 : 0 : LIST_INIT(&da_cache_list);
1469 [ # # ]: 0 : RTE_EAL_DEVARGS_FOREACH("pci", da) {
1470 : : struct da_cache *cache;
1471 : :
1472 : 0 : cache = calloc(1, sizeof(*cache) + strlen(da->drv_str) + 1);
1473 [ # # ]: 0 : if (!cache) {
1474 : : ret = -ENOMEM;
1475 : 0 : goto out;
1476 : : }
1477 : :
1478 [ # # ]: 0 : strlcpy(cache->name, da->name, sizeof(cache->name));
1479 : 0 : strlcpy(cache->drv_str, da->drv_str, strlen(da->drv_str) + 1);
1480 [ # # ]: 0 : LIST_INSERT_HEAD(&da_cache_list, cache, list);
1481 : : }
1482 : 0 : out:
1483 : : rte_spinlock_unlock(&netvsc_lock);
1484 : 0 : return ret;
1485 : : }
1486 : :
1487 : 0 : static void remove_cache_list(void)
1488 : : {
1489 : : struct da_cache *cache, *tmp;
1490 : :
1491 : : rte_spinlock_lock(&netvsc_lock);
1492 : 0 : da_cache_usage--;
1493 [ # # ]: 0 : if (da_cache_usage)
1494 : 0 : goto out;
1495 : :
1496 [ # # ]: 0 : LIST_FOREACH_SAFE(cache, &da_cache_list, list, tmp) {
1497 [ # # ]: 0 : LIST_REMOVE(cache, list);
1498 : 0 : free(cache);
1499 : : }
1500 : 0 : out:
1501 : : rte_spinlock_unlock(&netvsc_lock);
1502 : 0 : }
1503 : :
1504 : 0 : static int eth_hn_probe(struct rte_vmbus_driver *drv __rte_unused,
1505 : : struct rte_vmbus_device *dev)
1506 : : {
1507 : : struct rte_eth_dev *eth_dev;
1508 : : struct hn_nvs_process_priv *process_priv;
1509 : : int ret = 0;
1510 : :
1511 : 0 : PMD_INIT_FUNC_TRACE();
1512 : :
1513 : 0 : ret = populate_cache_list();
1514 [ # # ]: 0 : if (ret)
1515 : : return ret;
1516 : :
1517 : 0 : ret = rte_dev_event_monitor_start();
1518 [ # # ]: 0 : if (ret) {
1519 : 0 : PMD_DRV_LOG(ERR, "Failed to start device event monitoring");
1520 : 0 : goto fail;
1521 : : }
1522 : :
1523 : 0 : eth_dev = eth_dev_vmbus_allocate(dev, sizeof(struct hn_data));
1524 [ # # ]: 0 : if (!eth_dev) {
1525 : : ret = -ENOMEM;
1526 : 0 : goto vmbus_alloc_failed;
1527 : : }
1528 : :
1529 : 0 : process_priv = rte_zmalloc_socket("netvsc_proc_priv",
1530 : : sizeof(struct hn_nvs_process_priv),
1531 : : RTE_CACHE_LINE_SIZE,
1532 : : dev->device.numa_node);
1533 [ # # ]: 0 : if (!process_priv) {
1534 : : ret = -ENOMEM;
1535 : 0 : goto priv_alloc_failed;
1536 : : }
1537 : :
1538 : 0 : process_priv->vmbus_dev = dev;
1539 : 0 : eth_dev->process_private = process_priv;
1540 : :
1541 : 0 : ret = eth_hn_dev_init(eth_dev);
1542 [ # # ]: 0 : if (ret)
1543 : 0 : goto dev_init_failed;
1544 : :
1545 : 0 : rte_eth_dev_probing_finish(eth_dev);
1546 : 0 : return ret;
1547 : :
1548 : : dev_init_failed:
1549 : 0 : rte_free(process_priv);
1550 : :
1551 : 0 : priv_alloc_failed:
1552 : : eth_dev_vmbus_release(eth_dev);
1553 : :
1554 : 0 : vmbus_alloc_failed:
1555 : 0 : rte_dev_event_monitor_stop();
1556 : :
1557 : 0 : fail:
1558 : 0 : remove_cache_list();
1559 : 0 : return ret;
1560 : : }
1561 : :
1562 : 0 : static int eth_hn_remove(struct rte_vmbus_device *dev)
1563 : : {
1564 : : struct rte_eth_dev *eth_dev;
1565 : : struct hn_nvs_process_priv *process_priv;
1566 : : int ret;
1567 : :
1568 : 0 : PMD_INIT_FUNC_TRACE();
1569 : :
1570 : 0 : eth_dev = rte_eth_dev_allocated(dev->device.name);
1571 [ # # ]: 0 : if (!eth_dev)
1572 : : return 0; /* port already released */
1573 : :
1574 : 0 : ret = eth_hn_dev_uninit(eth_dev);
1575 [ # # ]: 0 : if (ret)
1576 : : return ret;
1577 : :
1578 : 0 : process_priv = eth_dev->process_private;
1579 : 0 : rte_free(process_priv);
1580 : :
1581 : : eth_dev_vmbus_release(eth_dev);
1582 : 0 : rte_dev_event_monitor_stop();
1583 : :
1584 : 0 : remove_cache_list();
1585 : :
1586 : 0 : return 0;
1587 : : }
1588 : :
1589 : : /* Network device GUID */
1590 : : static const rte_uuid_t hn_net_ids[] = {
1591 : : /* f8615163-df3e-46c5-913f-f2d2f965ed0e */
1592 : : RTE_UUID_INIT(0xf8615163, 0xdf3e, 0x46c5, 0x913f, 0xf2d2f965ed0eULL),
1593 : : { 0 }
1594 : : };
1595 : :
1596 : : static struct rte_vmbus_driver rte_netvsc_pmd = {
1597 : : .id_table = hn_net_ids,
1598 : : .probe = eth_hn_probe,
1599 : : .remove = eth_hn_remove,
1600 : : };
1601 : :
1602 : 254 : RTE_PMD_REGISTER_VMBUS(net_netvsc, rte_netvsc_pmd);
1603 : : RTE_PMD_REGISTER_KMOD_DEP(net_netvsc, "* uio_hv_generic");
1604 [ - + ]: 254 : RTE_LOG_REGISTER_SUFFIX(hn_logtype_init, init, NOTICE);
1605 [ - + ]: 254 : RTE_LOG_REGISTER_SUFFIX(hn_logtype_driver, driver, NOTICE);
1606 : : RTE_PMD_REGISTER_PARAM_STRING(net_netvsc,
1607 : : NETVSC_ARG_LATENCY "=<uint32> "
1608 : : NETVSC_ARG_RXBREAK "=<uint32> "
1609 : : NETVSC_ARG_TXBREAK "=<uint32> "
1610 : : NETVSC_ARG_RX_EXTMBUF_ENABLE "=<0|1>");
|