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