Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2019 Mellanox Technologies, Ltd
3 : : */
4 : : #include <unistd.h>
5 : : #include <net/if.h>
6 : : #include <sys/socket.h>
7 : : #include <sys/ioctl.h>
8 : : #include <sys/mman.h>
9 : : #include <fcntl.h>
10 : : #include <netinet/in.h>
11 : :
12 : : #include <rte_malloc.h>
13 : : #include <rte_log.h>
14 : : #include <rte_errno.h>
15 : : #include <rte_string_fns.h>
16 : : #include <bus_pci_driver.h>
17 : : #include <rte_eal_paging.h>
18 : :
19 : : #include <mlx5_glue.h>
20 : : #include <mlx5_common.h>
21 : : #include <mlx5_common_defs.h>
22 : : #include <mlx5_devx_cmds.h>
23 : : #include <mlx5_prm.h>
24 : : #include <mlx5_nl.h>
25 : :
26 : : #include "mlx5_vdpa_utils.h"
27 : : #include "mlx5_vdpa.h"
28 : :
29 : : #define MLX5_VDPA_DRIVER_NAME vdpa_mlx5
30 : :
31 : : #define MLX5_VDPA_DEFAULT_FEATURES ((1ULL << VHOST_USER_F_PROTOCOL_FEATURES) | \
32 : : (1ULL << VIRTIO_F_ANY_LAYOUT) | \
33 : : (1ULL << VIRTIO_NET_F_MQ) | \
34 : : (1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE) | \
35 : : (1ULL << VIRTIO_F_ORDER_PLATFORM) | \
36 : : (1ULL << VHOST_F_LOG_ALL) | \
37 : : (1ULL << VIRTIO_NET_F_MTU))
38 : :
39 : : #define MLX5_VDPA_PROTOCOL_FEATURES \
40 : : ((1ULL << VHOST_USER_PROTOCOL_F_BACKEND_REQ) | \
41 : : (1ULL << VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD) | \
42 : : (1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER) | \
43 : : (1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD) | \
44 : : (1ULL << VHOST_USER_PROTOCOL_F_MQ) | \
45 : : (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU) | \
46 : : (1ULL << VHOST_USER_PROTOCOL_F_STATUS))
47 : :
48 : : #define MLX5_VDPA_DEFAULT_NO_TRAFFIC_MAX 16LLU
49 : :
50 : : TAILQ_HEAD(mlx5_vdpa_privs, mlx5_vdpa_priv) priv_list =
51 : : TAILQ_HEAD_INITIALIZER(priv_list);
52 : : static pthread_mutex_t priv_list_lock = PTHREAD_MUTEX_INITIALIZER;
53 : :
54 : : struct mlx5_vdpa_conf_thread_mng conf_thread_mng;
55 : :
56 : : static void mlx5_vdpa_dev_release(struct mlx5_vdpa_priv *priv);
57 : :
58 : : static struct mlx5_vdpa_priv *
59 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(struct rte_vdpa_device *vdev)
60 : : {
61 : : struct mlx5_vdpa_priv *priv;
62 : : int found = 0;
63 : :
64 : 0 : pthread_mutex_lock(&priv_list_lock);
65 [ # # ]: 0 : TAILQ_FOREACH(priv, &priv_list, next) {
66 [ # # ]: 0 : if (vdev == priv->vdev) {
67 : : found = 1;
68 : : break;
69 : : }
70 : : }
71 : 0 : pthread_mutex_unlock(&priv_list_lock);
72 [ # # ]: 0 : if (!found) {
73 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
74 : 0 : rte_errno = EINVAL;
75 : 0 : return NULL;
76 : : }
77 : : return priv;
78 : : }
79 : :
80 : : static int
81 : 0 : mlx5_vdpa_get_queue_num(struct rte_vdpa_device *vdev, uint32_t *queue_num)
82 : : {
83 : : struct mlx5_vdpa_priv *priv =
84 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(vdev);
85 : :
86 [ # # ]: 0 : if (priv == NULL) {
87 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
88 : 0 : return -1;
89 : : }
90 : 0 : *queue_num = priv->caps.max_num_virtio_queues / 2;
91 : 0 : return 0;
92 : : }
93 : :
94 : : static int
95 : 0 : mlx5_vdpa_get_vdpa_features(struct rte_vdpa_device *vdev, uint64_t *features)
96 : : {
97 : : struct mlx5_vdpa_priv *priv =
98 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(vdev);
99 : :
100 [ # # ]: 0 : if (priv == NULL) {
101 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
102 : 0 : return -1;
103 : : }
104 : 0 : *features = MLX5_VDPA_DEFAULT_FEATURES;
105 [ # # ]: 0 : if (priv->caps.virtio_queue_type & (1 << MLX5_VIRTQ_TYPE_PACKED))
106 : 0 : *features |= (1ULL << VIRTIO_F_RING_PACKED);
107 [ # # ]: 0 : if (priv->caps.tso_ipv4)
108 : 0 : *features |= (1ULL << VIRTIO_NET_F_HOST_TSO4);
109 [ # # ]: 0 : if (priv->caps.tso_ipv6)
110 : 0 : *features |= (1ULL << VIRTIO_NET_F_HOST_TSO6);
111 [ # # ]: 0 : if (priv->caps.tx_csum)
112 : 0 : *features |= (1ULL << VIRTIO_NET_F_CSUM);
113 [ # # ]: 0 : if (priv->caps.rx_csum)
114 : 0 : *features |= (1ULL << VIRTIO_NET_F_GUEST_CSUM);
115 [ # # ]: 0 : if (priv->caps.virtio_version_1_0)
116 : 0 : *features |= (1ULL << VIRTIO_F_VERSION_1);
117 : : return 0;
118 : : }
119 : :
120 : : static int
121 : 0 : mlx5_vdpa_get_protocol_features(struct rte_vdpa_device *vdev,
122 : : uint64_t *features)
123 : : {
124 : : struct mlx5_vdpa_priv *priv =
125 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(vdev);
126 : :
127 [ # # ]: 0 : if (priv == NULL) {
128 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
129 : 0 : return -1;
130 : : }
131 : 0 : *features = MLX5_VDPA_PROTOCOL_FEATURES;
132 : 0 : return 0;
133 : : }
134 : :
135 : : static int
136 : 0 : mlx5_vdpa_set_vring_state(int vid, int vring, int state)
137 : : {
138 : 0 : struct rte_vdpa_device *vdev = rte_vhost_get_vdpa_device(vid);
139 : : struct mlx5_vdpa_priv *priv =
140 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(vdev);
141 : : struct mlx5_vdpa_virtq *virtq;
142 : : int ret;
143 : :
144 [ # # ]: 0 : if (priv == NULL) {
145 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
146 : 0 : return -EINVAL;
147 : : }
148 [ # # ]: 0 : if (vring >= (int)priv->caps.max_num_virtio_queues) {
149 : 0 : DRV_LOG(ERR, "Too big vring id: %d.", vring);
150 : 0 : return -E2BIG;
151 : : }
152 : : virtq = &priv->virtqs[vring];
153 : 0 : pthread_mutex_lock(&virtq->virtq_lock);
154 : 0 : ret = mlx5_vdpa_virtq_enable(priv, vring, state);
155 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
156 : 0 : return ret;
157 : : }
158 : :
159 : : static int
160 : 0 : mlx5_vdpa_features_set(int vid)
161 : : {
162 : 0 : struct rte_vdpa_device *vdev = rte_vhost_get_vdpa_device(vid);
163 : : struct mlx5_vdpa_priv *priv =
164 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(vdev);
165 : : uint64_t log_base, log_size;
166 : : uint64_t features;
167 : : int ret;
168 : :
169 [ # # ]: 0 : if (priv == NULL) {
170 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
171 : 0 : return -EINVAL;
172 : : }
173 : 0 : ret = rte_vhost_get_negotiated_features(vid, &features);
174 [ # # ]: 0 : if (ret) {
175 : 0 : DRV_LOG(ERR, "Failed to get negotiated features.");
176 : 0 : return ret;
177 : : }
178 [ # # ]: 0 : if (RTE_VHOST_NEED_LOG(features)) {
179 : 0 : ret = rte_vhost_get_log_base(vid, &log_base, &log_size);
180 [ # # ]: 0 : if (ret) {
181 : 0 : DRV_LOG(ERR, "Failed to get log base.");
182 : 0 : return ret;
183 : : }
184 : 0 : ret = mlx5_vdpa_dirty_bitmap_set(priv, log_base, log_size);
185 [ # # ]: 0 : if (ret) {
186 : 0 : DRV_LOG(ERR, "Failed to set dirty bitmap.");
187 : 0 : return ret;
188 : : }
189 : 0 : DRV_LOG(INFO, "mlx5 vdpa: enabling dirty logging...");
190 : 0 : ret = mlx5_vdpa_logging_enable(priv, 1);
191 [ # # ]: 0 : if (ret) {
192 : 0 : DRV_LOG(ERR, "Failed t enable dirty logging.");
193 : 0 : return ret;
194 : : }
195 : : }
196 : : return 0;
197 : : }
198 : :
199 : : static int
200 : 0 : mlx5_vdpa_mtu_set(struct mlx5_vdpa_priv *priv)
201 : : {
202 : : struct ifreq request;
203 : 0 : uint16_t vhost_mtu = 0;
204 : : uint16_t kern_mtu = 0;
205 : 0 : int ret = rte_vhost_get_mtu(priv->vid, &vhost_mtu);
206 : : int sock;
207 : : int retries = MLX5_VDPA_MAX_RETRIES;
208 : :
209 [ # # ]: 0 : if (ret) {
210 : 0 : DRV_LOG(DEBUG, "Cannot get vhost MTU - %d.", ret);
211 : 0 : return ret;
212 : : }
213 [ # # ]: 0 : if (!vhost_mtu) {
214 : 0 : DRV_LOG(DEBUG, "Vhost MTU is 0.");
215 : 0 : return ret;
216 : : }
217 : 0 : ret = mlx5_get_ifname_sysfs
218 [ # # ]: 0 : (mlx5_os_get_ctx_device_name(priv->cdev->ctx),
219 : : request.ifr_name);
220 [ # # ]: 0 : if (ret) {
221 : 0 : DRV_LOG(DEBUG, "Cannot get kernel IF name - %d.", ret);
222 : 0 : return ret;
223 : : }
224 : 0 : sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
225 [ # # ]: 0 : if (sock == -1) {
226 : 0 : DRV_LOG(DEBUG, "Cannot open IF socket.");
227 : 0 : return sock;
228 : : }
229 [ # # ]: 0 : while (retries--) {
230 : 0 : ret = ioctl(sock, SIOCGIFMTU, &request);
231 [ # # ]: 0 : if (ret == -1)
232 : : break;
233 : 0 : kern_mtu = request.ifr_mtu;
234 : 0 : DRV_LOG(DEBUG, "MTU: current %d requested %d.", (int)kern_mtu,
235 : : (int)vhost_mtu);
236 [ # # ]: 0 : if (kern_mtu == vhost_mtu)
237 : : break;
238 : 0 : request.ifr_mtu = vhost_mtu;
239 : 0 : ret = ioctl(sock, SIOCSIFMTU, &request);
240 [ # # ]: 0 : if (ret == -1)
241 : : break;
242 : 0 : request.ifr_mtu = 0;
243 : 0 : usleep(MLX5_VDPA_USEC);
244 : : }
245 : 0 : close(sock);
246 [ # # ]: 0 : return kern_mtu == vhost_mtu ? 0 : -1;
247 : : }
248 : :
249 : : void
250 : 0 : mlx5_vdpa_dev_cache_clean(struct mlx5_vdpa_priv *priv)
251 : : {
252 : : /* Clean pre-created resource in dev removal only. */
253 [ # # ]: 0 : if (!priv->queues)
254 : 0 : mlx5_vdpa_virtqs_cleanup(priv);
255 : 0 : mlx5_vdpa_mem_dereg(priv);
256 : 0 : }
257 : :
258 : : static bool
259 : 0 : mlx5_vdpa_wait_dev_close_tasks_done(struct mlx5_vdpa_priv *priv)
260 : : {
261 : : uint32_t timeout = 0;
262 : :
263 : : /* Check and wait all close tasks done. */
264 : 0 : while (rte_atomic_load_explicit(&priv->dev_close_progress,
265 [ # # # # ]: 0 : rte_memory_order_relaxed) != 0 && timeout < 1000) {
266 : 0 : rte_delay_us_sleep(10000);
267 : 0 : timeout++;
268 : : }
269 [ # # ]: 0 : if (priv->dev_close_progress) {
270 : 0 : DRV_LOG(ERR,
271 : : "Failed to wait close device tasks done vid %d.",
272 : : priv->vid);
273 : 0 : return true;
274 : : }
275 : : return false;
276 : : }
277 : :
278 : : static int
279 : 0 : _internal_mlx5_vdpa_dev_close(struct mlx5_vdpa_priv *priv,
280 : : bool release_resource)
281 : : {
282 : : int ret = 0;
283 : 0 : int vid = priv->vid;
284 : :
285 : 0 : mlx5_vdpa_virtq_unreg_intr_handle_all(priv);
286 : 0 : mlx5_vdpa_cqe_event_unset(priv);
287 [ # # ]: 0 : if (priv->state == MLX5_VDPA_STATE_CONFIGURED) {
288 : 0 : ret |= mlx5_vdpa_lm_log(priv);
289 : 0 : priv->state = MLX5_VDPA_STATE_IN_PROGRESS;
290 : : }
291 [ # # # # ]: 0 : if (priv->use_c_thread && !release_resource) {
292 : 0 : if (priv->last_c_thrd_idx >=
293 [ # # ]: 0 : (conf_thread_mng.max_thrds - 1))
294 : 0 : priv->last_c_thrd_idx = 0;
295 : : else
296 : 0 : priv->last_c_thrd_idx++;
297 : 0 : rte_atomic_store_explicit(&priv->dev_close_progress,
298 : : 1, rte_memory_order_relaxed);
299 [ # # ]: 0 : if (mlx5_vdpa_task_add(priv,
300 : 0 : priv->last_c_thrd_idx,
301 : : MLX5_VDPA_TASK_DEV_CLOSE_NOWAIT,
302 : : NULL, NULL, NULL, 1)) {
303 : 0 : DRV_LOG(ERR,
304 : : "Fail to add dev close task. ");
305 : 0 : goto single_thrd;
306 : : }
307 : 0 : priv->state = MLX5_VDPA_STATE_PROBED;
308 : 0 : DRV_LOG(INFO, "vDPA device %d was closed.", vid);
309 : 0 : return ret;
310 : : }
311 : 0 : single_thrd:
312 : 0 : pthread_mutex_lock(&priv->steer_update_lock);
313 : 0 : mlx5_vdpa_steer_unset(priv);
314 : 0 : pthread_mutex_unlock(&priv->steer_update_lock);
315 : 0 : mlx5_vdpa_virtqs_release(priv, release_resource);
316 : 0 : mlx5_vdpa_drain_cq(priv);
317 [ # # ]: 0 : if (priv->lm_mr.addr)
318 : 0 : mlx5_os_wrapped_mkey_destroy(&priv->lm_mr);
319 [ # # ]: 0 : if (!priv->connected)
320 : 0 : mlx5_vdpa_dev_cache_clean(priv);
321 : 0 : priv->vid = 0;
322 : 0 : rte_atomic_store_explicit(&priv->dev_close_progress, 0,
323 : : rte_memory_order_relaxed);
324 : 0 : priv->state = MLX5_VDPA_STATE_PROBED;
325 : 0 : DRV_LOG(INFO, "vDPA device %d was closed.", vid);
326 : 0 : return ret;
327 : : }
328 : :
329 : : static int
330 : 0 : mlx5_vdpa_dev_close(int vid)
331 : : {
332 : 0 : struct rte_vdpa_device *vdev = rte_vhost_get_vdpa_device(vid);
333 : : struct mlx5_vdpa_priv *priv;
334 : :
335 [ # # ]: 0 : if (!vdev) {
336 : 0 : DRV_LOG(ERR, "Invalid vDPA device.");
337 : 0 : return -1;
338 : : }
339 : 0 : priv = mlx5_vdpa_find_priv_resource_by_vdev(vdev);
340 [ # # ]: 0 : if (priv == NULL) {
341 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
342 : 0 : return -1;
343 : : }
344 : 0 : return _internal_mlx5_vdpa_dev_close(priv, false);
345 : : }
346 : :
347 : : static int
348 : 0 : mlx5_vdpa_dev_config(int vid)
349 : : {
350 : 0 : struct rte_vdpa_device *vdev = rte_vhost_get_vdpa_device(vid);
351 : : struct mlx5_vdpa_priv *priv =
352 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(vdev);
353 : :
354 [ # # ]: 0 : if (priv == NULL) {
355 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
356 : 0 : return -EINVAL;
357 : : }
358 [ # # # # ]: 0 : if (priv->state == MLX5_VDPA_STATE_CONFIGURED &&
359 : 0 : mlx5_vdpa_dev_close(vid)) {
360 : 0 : DRV_LOG(ERR, "Failed to reconfigure vid %d.", vid);
361 : 0 : return -1;
362 : : }
363 [ # # ]: 0 : if (mlx5_vdpa_wait_dev_close_tasks_done(priv))
364 : : return -1;
365 : 0 : priv->vid = vid;
366 : 0 : priv->connected = true;
367 [ # # ]: 0 : if (mlx5_vdpa_mtu_set(priv))
368 : 0 : DRV_LOG(WARNING, "MTU cannot be set on device %s.",
369 : : vdev->device->name);
370 [ # # # # ]: 0 : if (mlx5_vdpa_mem_register(priv) ||
371 [ # # # # ]: 0 : mlx5_vdpa_virtqs_prepare(priv) || mlx5_vdpa_steer_setup(priv) ||
372 : 0 : mlx5_vdpa_cqe_event_setup(priv)) {
373 : 0 : mlx5_vdpa_dev_close(vid);
374 : 0 : return -1;
375 : : }
376 : 0 : priv->state = MLX5_VDPA_STATE_CONFIGURED;
377 : 0 : DRV_LOG(INFO, "vDPA device %d was configured.", vid);
378 : 0 : return 0;
379 : : }
380 : :
381 : : static int
382 : 0 : mlx5_vdpa_get_device_fd(int vid)
383 : : {
384 : 0 : struct rte_vdpa_device *vdev = rte_vhost_get_vdpa_device(vid);
385 : : struct mlx5_vdpa_priv *priv =
386 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(vdev);
387 : :
388 [ # # ]: 0 : if (priv == NULL) {
389 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
390 : 0 : return -EINVAL;
391 : : }
392 : 0 : return ((struct ibv_context *)priv->cdev->ctx)->cmd_fd;
393 : : }
394 : :
395 : : static int
396 : 0 : mlx5_vdpa_get_notify_area(int vid, int qid, uint64_t *offset, uint64_t *size)
397 : : {
398 : 0 : struct rte_vdpa_device *vdev = rte_vhost_get_vdpa_device(vid);
399 : : struct mlx5_vdpa_priv *priv =
400 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(vdev);
401 : :
402 : : RTE_SET_USED(qid);
403 [ # # ]: 0 : if (priv == NULL) {
404 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
405 : 0 : return -EINVAL;
406 : : }
407 [ # # ]: 0 : if (!priv->var) {
408 : 0 : DRV_LOG(ERR, "VAR was not created for device %s, is the device"
409 : : " configured?.", vdev->device->name);
410 : 0 : return -EINVAL;
411 : : }
412 : 0 : *offset = priv->var->mmap_off;
413 : 0 : *size = priv->var->length;
414 : 0 : return 0;
415 : : }
416 : :
417 : : static int
418 : 0 : mlx5_vdpa_get_stats_names(struct rte_vdpa_device *vdev,
419 : : struct rte_vdpa_stat_name *stats_names,
420 : : unsigned int size)
421 : : {
422 : : static const char *mlx5_vdpa_stats_names[MLX5_VDPA_STATS_MAX] = {
423 : : "received_descriptors",
424 : : "completed_descriptors",
425 : : "bad descriptor errors",
426 : : "exceed max chain",
427 : : "invalid buffer",
428 : : "completion errors",
429 : : };
430 : : struct mlx5_vdpa_priv *priv =
431 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(vdev);
432 : : unsigned int i;
433 : :
434 [ # # ]: 0 : if (priv == NULL) {
435 : 0 : DRV_LOG(ERR, "Invalid device: %s.", vdev->device->name);
436 : 0 : return -ENODEV;
437 : : }
438 [ # # ]: 0 : if (!stats_names)
439 : : return MLX5_VDPA_STATS_MAX;
440 : 0 : size = RTE_MIN(size, (unsigned int)MLX5_VDPA_STATS_MAX);
441 [ # # ]: 0 : for (i = 0; i < size; ++i)
442 : 0 : strlcpy(stats_names[i].name, mlx5_vdpa_stats_names[i],
443 : : RTE_VDPA_STATS_NAME_SIZE);
444 : 0 : return size;
445 : : }
446 : :
447 : : static int
448 : 0 : mlx5_vdpa_get_stats(struct rte_vdpa_device *vdev, int qid,
449 : : struct rte_vdpa_stat *stats, unsigned int n)
450 : : {
451 : : struct mlx5_vdpa_priv *priv =
452 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(vdev);
453 : :
454 [ # # ]: 0 : if (priv == NULL) {
455 : 0 : DRV_LOG(ERR, "Invalid device: %s.", vdev->device->name);
456 : 0 : return -ENODEV;
457 : : }
458 [ # # ]: 0 : if (qid >= (int)priv->caps.max_num_virtio_queues) {
459 : 0 : DRV_LOG(ERR, "Too big vring id: %d for device %s.", qid,
460 : : vdev->device->name);
461 : 0 : return -E2BIG;
462 : : }
463 [ # # ]: 0 : if (!priv->caps.queue_counters_valid) {
464 : 0 : DRV_LOG(ERR, "Virtq statistics is not supported for device %s.",
465 : : vdev->device->name);
466 : 0 : return -ENOTSUP;
467 : : }
468 : 0 : return mlx5_vdpa_virtq_stats_get(priv, qid, stats, n);
469 : : }
470 : :
471 : : static int
472 : 0 : mlx5_vdpa_reset_stats(struct rte_vdpa_device *vdev, int qid)
473 : : {
474 : : struct mlx5_vdpa_priv *priv =
475 : 0 : mlx5_vdpa_find_priv_resource_by_vdev(vdev);
476 : :
477 [ # # ]: 0 : if (priv == NULL) {
478 : 0 : DRV_LOG(ERR, "Invalid device: %s.", vdev->device->name);
479 : 0 : return -ENODEV;
480 : : }
481 [ # # ]: 0 : if (qid >= (int)priv->caps.max_num_virtio_queues) {
482 : 0 : DRV_LOG(ERR, "Too big vring id: %d for device %s.", qid,
483 : : vdev->device->name);
484 : 0 : return -E2BIG;
485 : : }
486 [ # # ]: 0 : if (!priv->caps.queue_counters_valid) {
487 : 0 : DRV_LOG(ERR, "Virtq statistics is not supported for device %s.",
488 : : vdev->device->name);
489 : 0 : return -ENOTSUP;
490 : : }
491 : 0 : return mlx5_vdpa_virtq_stats_reset(priv, qid);
492 : : }
493 : :
494 : : static int
495 : 0 : mlx5_vdpa_dev_cleanup(int vid)
496 : : {
497 : 0 : struct rte_vdpa_device *vdev = rte_vhost_get_vdpa_device(vid);
498 : : struct mlx5_vdpa_priv *priv;
499 : :
500 [ # # ]: 0 : if (vdev == NULL)
501 : : return -1;
502 : 0 : priv = mlx5_vdpa_find_priv_resource_by_vdev(vdev);
503 [ # # ]: 0 : if (priv == NULL) {
504 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
505 : 0 : return -1;
506 : : }
507 [ # # ]: 0 : if (priv->state == MLX5_VDPA_STATE_PROBED) {
508 [ # # ]: 0 : if (priv->use_c_thread)
509 : 0 : mlx5_vdpa_wait_dev_close_tasks_done(priv);
510 : 0 : mlx5_vdpa_dev_cache_clean(priv);
511 : : }
512 : 0 : priv->connected = false;
513 : 0 : return 0;
514 : : }
515 : :
516 : : static struct rte_vdpa_dev_ops mlx5_vdpa_ops = {
517 : : .get_queue_num = mlx5_vdpa_get_queue_num,
518 : : .get_features = mlx5_vdpa_get_vdpa_features,
519 : : .get_protocol_features = mlx5_vdpa_get_protocol_features,
520 : : .dev_conf = mlx5_vdpa_dev_config,
521 : : .dev_close = mlx5_vdpa_dev_close,
522 : : .dev_cleanup = mlx5_vdpa_dev_cleanup,
523 : : .set_vring_state = mlx5_vdpa_set_vring_state,
524 : : .set_features = mlx5_vdpa_features_set,
525 : : .migration_done = NULL,
526 : : .get_vfio_group_fd = NULL,
527 : : .get_vfio_device_fd = mlx5_vdpa_get_device_fd,
528 : : .get_notify_area = mlx5_vdpa_get_notify_area,
529 : : .get_stats_names = mlx5_vdpa_get_stats_names,
530 : : .get_stats = mlx5_vdpa_get_stats,
531 : : .reset_stats = mlx5_vdpa_reset_stats,
532 : : };
533 : :
534 : : static int
535 : 0 : mlx5_vdpa_args_check_handler(const char *key, const char *val, void *opaque)
536 : : {
537 : : struct mlx5_vdpa_priv *priv = opaque;
538 : : unsigned long tmp;
539 : 0 : int n_cores = sysconf(_SC_NPROCESSORS_ONLN);
540 : :
541 : 0 : errno = 0;
542 : 0 : tmp = strtoul(val, NULL, 0);
543 [ # # ]: 0 : if (errno) {
544 : 0 : DRV_LOG(WARNING, "%s: \"%s\" is an invalid integer.", key, val);
545 : 0 : return -errno;
546 : : }
547 [ # # ]: 0 : if (strcmp(key, "event_mode") == 0) {
548 [ # # ]: 0 : if (tmp <= MLX5_VDPA_EVENT_MODE_ONLY_INTERRUPT)
549 : 0 : priv->event_mode = (int)tmp;
550 : : else
551 : 0 : DRV_LOG(WARNING, "Invalid event_mode %s.", val);
552 [ # # ]: 0 : } else if (strcmp(key, "event_us") == 0) {
553 : 0 : priv->event_us = (uint32_t)tmp;
554 [ # # ]: 0 : } else if (strcmp(key, "no_traffic_time") == 0) {
555 : 0 : priv->no_traffic_max = (uint32_t)tmp;
556 [ # # ]: 0 : } else if (strcmp(key, "event_core") == 0) {
557 [ # # ]: 0 : if (tmp >= (unsigned long)n_cores)
558 : 0 : DRV_LOG(WARNING, "Invalid event_core %s.", val);
559 : : else
560 : 0 : priv->event_core = tmp;
561 [ # # ]: 0 : } else if (strcmp(key, "max_conf_threads") == 0) {
562 [ # # ]: 0 : if (tmp) {
563 : 0 : priv->use_c_thread = true;
564 [ # # ]: 0 : if (!conf_thread_mng.initializer_priv) {
565 : 0 : conf_thread_mng.initializer_priv = priv;
566 [ # # ]: 0 : if (tmp > MLX5_VDPA_MAX_C_THRD) {
567 : 0 : DRV_LOG(WARNING,
568 : : "Invalid max_conf_threads %s "
569 : : "and set max_conf_threads to %d",
570 : : val, MLX5_VDPA_MAX_C_THRD);
571 : : tmp = MLX5_VDPA_MAX_C_THRD;
572 : : }
573 : 0 : conf_thread_mng.max_thrds = tmp;
574 [ # # ]: 0 : } else if (tmp != conf_thread_mng.max_thrds) {
575 : 0 : DRV_LOG(WARNING,
576 : : "max_conf_threads is PMD argument and not per device, "
577 : : "only the first device configuration set it, current value is %d "
578 : : "and will not be changed to %d.",
579 : : conf_thread_mng.max_thrds, (int)tmp);
580 : : }
581 : : } else {
582 : 0 : priv->use_c_thread = false;
583 : : }
584 [ # # ]: 0 : } else if (strcmp(key, "hw_latency_mode") == 0) {
585 : 0 : priv->hw_latency_mode = (uint32_t)tmp;
586 [ # # ]: 0 : } else if (strcmp(key, "hw_max_latency_us") == 0) {
587 : 0 : priv->hw_max_latency_us = (uint32_t)tmp;
588 [ # # ]: 0 : } else if (strcmp(key, "hw_max_pending_comp") == 0) {
589 : 0 : priv->hw_max_pending_comp = (uint32_t)tmp;
590 [ # # ]: 0 : } else if (strcmp(key, "queue_size") == 0) {
591 : 0 : priv->queue_size = (uint16_t)tmp;
592 [ # # ]: 0 : } else if (strcmp(key, "queues") == 0) {
593 : 0 : priv->queues = (uint16_t)tmp;
594 : : } else {
595 : 0 : DRV_LOG(WARNING, "Invalid key %s.", key);
596 : : }
597 : : return 0;
598 : : }
599 : :
600 : : static void
601 : 0 : mlx5_vdpa_config_get(struct mlx5_kvargs_ctrl *mkvlist,
602 : : struct mlx5_vdpa_priv *priv)
603 : : {
604 : 0 : const char **params = (const char *[]){
605 : : "event_core",
606 : : "event_mode",
607 : : "event_us",
608 : : "hw_latency_mode",
609 : : "hw_max_latency_us",
610 : : "hw_max_pending_comp",
611 : : "no_traffic_time",
612 : : "queue_size",
613 : : "queues",
614 : : "max_conf_threads",
615 : : NULL,
616 : : };
617 : :
618 : 0 : priv->event_mode = MLX5_VDPA_EVENT_MODE_FIXED_TIMER;
619 : 0 : priv->event_us = 0;
620 : 0 : priv->event_core = -1;
621 : 0 : priv->no_traffic_max = MLX5_VDPA_DEFAULT_NO_TRAFFIC_MAX;
622 [ # # ]: 0 : if (mkvlist == NULL)
623 : 0 : return;
624 : 0 : mlx5_kvargs_process(mkvlist, params, mlx5_vdpa_args_check_handler,
625 : : priv);
626 [ # # ]: 0 : if (!priv->event_us &&
627 [ # # ]: 0 : priv->event_mode == MLX5_VDPA_EVENT_MODE_DYNAMIC_TIMER)
628 : 0 : priv->event_us = MLX5_VDPA_DEFAULT_TIMER_STEP_US;
629 [ # # # # : 0 : if ((priv->queue_size && !priv->queues) ||
# # ]
630 [ # # ]: 0 : (!priv->queue_size && priv->queues)) {
631 : 0 : priv->queue_size = 0;
632 : 0 : priv->queues = 0;
633 : 0 : DRV_LOG(WARNING, "Please provide both queue_size and queues.");
634 : : }
635 : 0 : DRV_LOG(DEBUG, "event mode is %d.", priv->event_mode);
636 : 0 : DRV_LOG(DEBUG, "event_us is %u us.", priv->event_us);
637 : 0 : DRV_LOG(DEBUG, "no traffic max is %u.", priv->no_traffic_max);
638 : 0 : DRV_LOG(DEBUG, "queues is %u, queue_size is %u.", priv->queues,
639 : : priv->queue_size);
640 : : }
641 : :
642 : : void
643 : 0 : mlx5_vdpa_prepare_virtq_destroy(struct mlx5_vdpa_priv *priv)
644 : : {
645 : : uint32_t max_queues, index;
646 : : struct mlx5_vdpa_virtq *virtq;
647 : :
648 [ # # # # ]: 0 : if (!priv->queues || !priv->queue_size)
649 : : return;
650 : 0 : max_queues = ((priv->queues * 2) < priv->caps.max_num_virtio_queues) ?
651 : : (priv->queues * 2) : (priv->caps.max_num_virtio_queues);
652 [ # # ]: 0 : if (mlx5_vdpa_is_modify_virtq_supported(priv))
653 : 0 : mlx5_vdpa_steer_unset(priv);
654 [ # # ]: 0 : for (index = 0; index < max_queues; ++index) {
655 : 0 : virtq = &priv->virtqs[index];
656 [ # # ]: 0 : if (virtq->virtq) {
657 : 0 : pthread_mutex_lock(&virtq->virtq_lock);
658 : 0 : mlx5_vdpa_virtq_unset(virtq);
659 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
660 : : }
661 : : }
662 : : }
663 : :
664 : : static int
665 : 0 : mlx5_vdpa_virtq_resource_prepare(struct mlx5_vdpa_priv *priv)
666 : : {
667 : 0 : RTE_ATOMIC(uint32_t) remaining_cnt = 0;
668 : 0 : RTE_ATOMIC(uint32_t) err_cnt = 0;
669 : : uint32_t task_num = 0;
670 : : uint32_t max_queues, index, thrd_idx, data[1];
671 : : struct mlx5_vdpa_virtq *virtq;
672 : :
673 [ # # ]: 0 : for (index = 0; index < priv->caps.max_num_virtio_queues;
674 : 0 : index++) {
675 : : virtq = &priv->virtqs[index];
676 : 0 : pthread_mutex_init(&virtq->virtq_lock, NULL);
677 : : }
678 [ # # # # ]: 0 : if (!priv->queues || !priv->queue_size)
679 : : return 0;
680 : 0 : max_queues = (priv->queues < priv->caps.max_num_virtio_queues) ?
681 [ # # ]: 0 : (priv->queues * 2) : (priv->caps.max_num_virtio_queues);
682 [ # # ]: 0 : if (priv->use_c_thread) {
683 : 0 : uint32_t main_task_idx[max_queues];
684 : :
685 [ # # ]: 0 : for (index = 0; index < max_queues; ++index) {
686 : 0 : thrd_idx = index % (conf_thread_mng.max_thrds + 1);
687 [ # # ]: 0 : if (!thrd_idx) {
688 : 0 : main_task_idx[task_num] = index;
689 : 0 : task_num++;
690 : 0 : continue;
691 : : }
692 : 0 : thrd_idx = priv->last_c_thrd_idx + 1;
693 [ # # ]: 0 : if (thrd_idx >= conf_thread_mng.max_thrds)
694 : : thrd_idx = 0;
695 : 0 : priv->last_c_thrd_idx = thrd_idx;
696 : 0 : data[0] = index;
697 [ # # ]: 0 : if (mlx5_vdpa_task_add(priv, thrd_idx,
698 : : MLX5_VDPA_TASK_PREPARE_VIRTQ,
699 : : &remaining_cnt, &err_cnt,
700 : : (void **)&data, 1)) {
701 : 0 : DRV_LOG(ERR, "Fail to add "
702 : : "task prepare virtq (%d).", index);
703 : 0 : main_task_idx[task_num] = index;
704 : 0 : task_num++;
705 : : }
706 : : }
707 [ # # ]: 0 : for (index = 0; index < task_num; ++index)
708 [ # # ]: 0 : if (mlx5_vdpa_virtq_single_resource_prepare(priv,
709 : 0 : main_task_idx[index]))
710 : 0 : goto error;
711 [ # # ]: 0 : if (mlx5_vdpa_c_thread_wait_bulk_tasks_done(&remaining_cnt,
712 : : &err_cnt, 2000)) {
713 : 0 : DRV_LOG(ERR,
714 : : "Failed to wait virt-queue prepare tasks ready.");
715 : 0 : goto error;
716 : : }
717 : : } else {
718 [ # # ]: 0 : for (index = 0; index < max_queues; ++index)
719 [ # # ]: 0 : if (mlx5_vdpa_virtq_single_resource_prepare(priv,
720 : : index))
721 : 0 : goto error;
722 : : }
723 [ # # ]: 0 : if (mlx5_vdpa_is_modify_virtq_supported(priv))
724 [ # # ]: 0 : if (mlx5_vdpa_steer_update(priv, true))
725 : 0 : goto error;
726 : : return 0;
727 : 0 : error:
728 : 0 : mlx5_vdpa_prepare_virtq_destroy(priv);
729 : 0 : return -1;
730 : : }
731 : :
732 : : static int
733 : 0 : mlx5_vdpa_create_dev_resources(struct mlx5_vdpa_priv *priv)
734 : : {
735 : 0 : struct mlx5_devx_tis_attr tis_attr = {0};
736 : 0 : struct ibv_context *ctx = priv->cdev->ctx;
737 : : uint32_t i;
738 : : int retry;
739 : :
740 [ # # ]: 0 : for (retry = 0; retry < 7; retry++) {
741 : 0 : priv->var = mlx5_glue->dv_alloc_var(ctx, 0);
742 [ # # ]: 0 : if (priv->var != NULL)
743 : : break;
744 : 0 : DRV_LOG(WARNING, "Failed to allocate VAR, retry %d.", retry);
745 : : /* Wait Qemu release VAR during vdpa restart, 0.1 sec based. */
746 : 0 : usleep(100000U << retry);
747 : : }
748 [ # # ]: 0 : if (!priv->var) {
749 : 0 : DRV_LOG(ERR, "Failed to allocate VAR %u.", errno);
750 : 0 : rte_errno = ENOMEM;
751 : 0 : return -rte_errno;
752 : : }
753 : : /* Always map the entire page. */
754 : 0 : priv->virtq_db_addr = mmap(NULL, priv->var->length, PROT_READ |
755 : : PROT_WRITE, MAP_SHARED, ctx->cmd_fd,
756 : : priv->var->mmap_off);
757 [ # # ]: 0 : if (priv->virtq_db_addr == MAP_FAILED) {
758 : 0 : DRV_LOG(ERR, "Failed to map doorbell page %u.", errno);
759 : 0 : priv->virtq_db_addr = NULL;
760 : 0 : rte_errno = errno;
761 : 0 : return -rte_errno;
762 : : }
763 : : /* Add within page offset for 64K page system. */
764 : 0 : priv->virtq_db_addr = (char *)priv->virtq_db_addr +
765 : 0 : ((rte_mem_page_size() - 1) & priv->caps.doorbell_bar_offset);
766 : 0 : DRV_LOG(DEBUG, "VAR address of doorbell mapping is %p.",
767 : : priv->virtq_db_addr);
768 : 0 : priv->td = mlx5_devx_cmd_create_td(ctx);
769 [ # # ]: 0 : if (!priv->td) {
770 : 0 : DRV_LOG(ERR, "Failed to create transport domain.");
771 : 0 : rte_errno = errno;
772 : 0 : return -rte_errno;
773 : : }
774 : 0 : tis_attr.transport_domain = priv->td->id;
775 [ # # ]: 0 : for (i = 0; i < priv->num_lag_ports; i++) {
776 : : /* 0 is auto affinity, non-zero value to propose port. */
777 : 0 : tis_attr.lag_tx_port_affinity = i + 1;
778 : 0 : priv->tiss[i] = mlx5_devx_cmd_create_tis(ctx, &tis_attr);
779 [ # # ]: 0 : if (!priv->tiss[i]) {
780 : 0 : DRV_LOG(ERR, "Failed to create TIS %u.", i);
781 : 0 : return -rte_errno;
782 : : }
783 : : }
784 : 0 : priv->null_mr = mlx5_glue->alloc_null_mr(priv->cdev->pd);
785 [ # # ]: 0 : if (!priv->null_mr) {
786 : 0 : DRV_LOG(ERR, "Failed to allocate null MR.");
787 : 0 : rte_errno = errno;
788 : 0 : return -rte_errno;
789 : : }
790 : 0 : DRV_LOG(DEBUG, "Dump fill Mkey = %u.", priv->null_mr->lkey);
791 : : #ifdef HAVE_MLX5DV_DR
792 : 0 : priv->steer.domain = mlx5_glue->dr_create_domain(ctx,
793 : : MLX5DV_DR_DOMAIN_TYPE_NIC_RX);
794 [ # # ]: 0 : if (!priv->steer.domain) {
795 : 0 : DRV_LOG(ERR, "Failed to create Rx domain.");
796 : 0 : rte_errno = errno;
797 : 0 : return -rte_errno;
798 : : }
799 : : #endif
800 : 0 : priv->steer.tbl = mlx5_glue->dr_create_flow_tbl(priv->steer.domain, 0);
801 [ # # ]: 0 : if (!priv->steer.tbl) {
802 : 0 : DRV_LOG(ERR, "Failed to create table 0 with Rx domain.");
803 : 0 : rte_errno = errno;
804 : 0 : return -rte_errno;
805 : : }
806 [ # # ]: 0 : if (mlx5_vdpa_err_event_setup(priv) != 0)
807 : 0 : return -rte_errno;
808 [ # # ]: 0 : if (mlx5_vdpa_event_qp_global_prepare(priv))
809 : 0 : return -rte_errno;
810 [ # # ]: 0 : if (mlx5_vdpa_virtq_resource_prepare(priv))
811 : 0 : return -rte_errno;
812 : : return 0;
813 : : }
814 : :
815 : : static int
816 : 0 : mlx5_vdpa_dev_probe(struct mlx5_common_device *cdev,
817 : : struct mlx5_kvargs_ctrl *mkvlist)
818 : : {
819 : : struct mlx5_vdpa_priv *priv = NULL;
820 : : struct mlx5_hca_attr *attr = &cdev->config.hca_attr;
821 : :
822 [ # # # # ]: 0 : if (!attr->vdpa.valid || !attr->vdpa.max_num_virtio_queues) {
823 : 0 : DRV_LOG(ERR, "Not enough capabilities to support vdpa, maybe "
824 : : "old FW/OFED version?");
825 : 0 : rte_errno = ENOTSUP;
826 : 0 : return -rte_errno;
827 : : }
828 [ # # ]: 0 : if (!attr->vdpa.queue_counters_valid)
829 : 0 : DRV_LOG(DEBUG, "No capability to support virtq statistics.");
830 : 0 : priv = rte_zmalloc("mlx5 vDPA device private", sizeof(*priv) +
831 : 0 : sizeof(struct mlx5_vdpa_virtq) *
832 : 0 : attr->vdpa.max_num_virtio_queues,
833 : : RTE_CACHE_LINE_SIZE);
834 [ # # ]: 0 : if (!priv) {
835 : 0 : DRV_LOG(ERR, "Failed to allocate private memory.");
836 : 0 : rte_errno = ENOMEM;
837 : 0 : return -rte_errno;
838 : : }
839 : 0 : priv->caps = attr->vdpa;
840 : 0 : priv->log_max_rqt_size = attr->log_max_rqt_size;
841 : 0 : priv->num_lag_ports = attr->num_lag_ports;
842 [ # # ]: 0 : if (attr->num_lag_ports == 0)
843 : 0 : priv->num_lag_ports = 1;
844 : : rte_spinlock_init(&priv->db_lock);
845 : 0 : pthread_mutex_init(&priv->steer_update_lock, NULL);
846 : 0 : priv->cdev = cdev;
847 : 0 : mlx5_vdpa_config_get(mkvlist, priv);
848 [ # # ]: 0 : if (priv->use_c_thread) {
849 [ # # ]: 0 : if (conf_thread_mng.initializer_priv == priv)
850 [ # # ]: 0 : if (mlx5_vdpa_mult_threads_create())
851 : 0 : goto error;
852 : 0 : rte_atomic_fetch_add_explicit(&conf_thread_mng.refcnt, 1,
853 : : rte_memory_order_relaxed);
854 : : }
855 [ # # ]: 0 : if (mlx5_vdpa_create_dev_resources(priv))
856 : 0 : goto error;
857 : 0 : priv->vdev = rte_vdpa_register_device(cdev->dev, &mlx5_vdpa_ops);
858 [ # # ]: 0 : if (priv->vdev == NULL) {
859 : 0 : DRV_LOG(ERR, "Failed to register vDPA device.");
860 [ # # ]: 0 : rte_errno = rte_errno ? rte_errno : EINVAL;
861 : 0 : goto error;
862 : : }
863 : 0 : pthread_mutex_lock(&priv_list_lock);
864 : 0 : TAILQ_INSERT_TAIL(&priv_list, priv, next);
865 : 0 : pthread_mutex_unlock(&priv_list_lock);
866 : 0 : return 0;
867 : 0 : error:
868 [ # # ]: 0 : if (conf_thread_mng.initializer_priv == priv)
869 : 0 : mlx5_vdpa_mult_threads_destroy(false);
870 : : if (priv)
871 : 0 : mlx5_vdpa_dev_release(priv);
872 : 0 : return -rte_errno;
873 : : }
874 : :
875 : : static int
876 : 0 : mlx5_vdpa_dev_remove(struct mlx5_common_device *cdev)
877 : : {
878 : : struct mlx5_vdpa_priv *priv = NULL;
879 : : int found = 0;
880 : :
881 : 0 : pthread_mutex_lock(&priv_list_lock);
882 [ # # ]: 0 : TAILQ_FOREACH(priv, &priv_list, next) {
883 [ # # ]: 0 : if (priv->vdev->device == cdev->dev) {
884 : : found = 1;
885 : : break;
886 : : }
887 : : }
888 [ # # ]: 0 : if (found)
889 [ # # ]: 0 : TAILQ_REMOVE(&priv_list, priv, next);
890 : 0 : pthread_mutex_unlock(&priv_list_lock);
891 [ # # ]: 0 : if (found)
892 : 0 : mlx5_vdpa_dev_release(priv);
893 : 0 : return 0;
894 : : }
895 : :
896 : : static void
897 : 0 : mlx5_vdpa_release_dev_resources(struct mlx5_vdpa_priv *priv)
898 : : {
899 : : uint32_t i;
900 : :
901 [ # # ]: 0 : if (priv->queues)
902 : 0 : mlx5_vdpa_virtqs_cleanup(priv);
903 : 0 : mlx5_vdpa_dev_cache_clean(priv);
904 [ # # ]: 0 : for (i = 0; i < priv->caps.max_num_virtio_queues; i++) {
905 [ # # ]: 0 : if (!priv->virtqs[i].counters)
906 : 0 : continue;
907 : 0 : claim_zero(mlx5_devx_cmd_destroy(priv->virtqs[i].counters));
908 : : }
909 : 0 : mlx5_vdpa_event_qp_global_release(priv);
910 : 0 : mlx5_vdpa_err_event_unset(priv);
911 [ # # ]: 0 : if (priv->steer.tbl)
912 : 0 : claim_zero(mlx5_glue->dr_destroy_flow_tbl(priv->steer.tbl));
913 [ # # ]: 0 : if (priv->steer.domain)
914 : 0 : claim_zero(mlx5_glue->dr_destroy_domain(priv->steer.domain));
915 [ # # ]: 0 : if (priv->null_mr)
916 : 0 : claim_zero(mlx5_glue->dereg_mr(priv->null_mr));
917 [ # # ]: 0 : for (i = 0; i < priv->num_lag_ports; i++) {
918 [ # # ]: 0 : if (priv->tiss[i])
919 : 0 : claim_zero(mlx5_devx_cmd_destroy(priv->tiss[i]));
920 : : }
921 [ # # ]: 0 : if (priv->td)
922 : 0 : claim_zero(mlx5_devx_cmd_destroy(priv->td));
923 [ # # ]: 0 : if (priv->virtq_db_addr)
924 : : /* Mask out the within page offset for munmap. */
925 : 0 : claim_zero(munmap((void *)((uintptr_t)priv->virtq_db_addr &
926 : : ~(rte_mem_page_size() - 1)), priv->var->length));
927 [ # # ]: 0 : if (priv->var)
928 : 0 : mlx5_glue->dv_free_var(priv->var);
929 : 0 : }
930 : :
931 : : static void
932 : 0 : mlx5_vdpa_dev_release(struct mlx5_vdpa_priv *priv)
933 : : {
934 [ # # ]: 0 : if (priv->state == MLX5_VDPA_STATE_CONFIGURED)
935 : 0 : _internal_mlx5_vdpa_dev_close(priv, true);
936 [ # # ]: 0 : if (priv->use_c_thread)
937 : 0 : mlx5_vdpa_wait_dev_close_tasks_done(priv);
938 : 0 : mlx5_vdpa_release_dev_resources(priv);
939 [ # # ]: 0 : if (priv->vdev)
940 : 0 : rte_vdpa_unregister_device(priv->vdev);
941 [ # # ]: 0 : if (priv->use_c_thread)
942 [ # # ]: 0 : if (rte_atomic_fetch_sub_explicit(&conf_thread_mng.refcnt,
943 : : 1, rte_memory_order_relaxed) == 1)
944 : 0 : mlx5_vdpa_mult_threads_destroy(true);
945 : 0 : rte_free(priv);
946 : 0 : }
947 : :
948 : : static const struct rte_pci_id mlx5_vdpa_pci_id_map[] = {
949 : : {
950 : : RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
951 : : PCI_DEVICE_ID_MELLANOX_CONNECTX6)
952 : : },
953 : : {
954 : : RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
955 : : PCI_DEVICE_ID_MELLANOX_CONNECTX6VF)
956 : : },
957 : : {
958 : : RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
959 : : PCI_DEVICE_ID_MELLANOX_CONNECTX6DX)
960 : : },
961 : : {
962 : : RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
963 : : PCI_DEVICE_ID_MELLANOX_CONNECTXVF)
964 : : },
965 : : {
966 : : RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
967 : : PCI_DEVICE_ID_MELLANOX_BLUEFIELD2)
968 : : },
969 : : {
970 : : RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
971 : : PCI_DEVICE_ID_MELLANOX_CONNECTX6LX)
972 : : },
973 : : {
974 : : RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
975 : : PCI_DEVICE_ID_MELLANOX_CONNECTX7)
976 : : },
977 : : {
978 : : RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
979 : : PCI_DEVICE_ID_MELLANOX_BLUEFIELD3)
980 : : },
981 : : {
982 : : .vendor_id = 0
983 : : }
984 : : };
985 : :
986 : : static struct mlx5_class_driver mlx5_vdpa_driver = {
987 : : .drv_class = MLX5_CLASS_VDPA,
988 : : .name = RTE_STR(MLX5_VDPA_DRIVER_NAME),
989 : : .id_table = mlx5_vdpa_pci_id_map,
990 : : .probe = mlx5_vdpa_dev_probe,
991 : : .remove = mlx5_vdpa_dev_remove,
992 : : };
993 : :
994 [ - + ]: 252 : RTE_LOG_REGISTER_DEFAULT(mlx5_vdpa_logtype, NOTICE)
995 : :
996 : : /**
997 : : * Driver initialization routine.
998 : : */
999 : 252 : RTE_INIT(rte_mlx5_vdpa_init)
1000 : : {
1001 : 252 : mlx5_common_init();
1002 [ + - ]: 252 : if (mlx5_glue)
1003 : 252 : mlx5_class_driver_register(&mlx5_vdpa_driver);
1004 : 252 : }
1005 : :
1006 : : RTE_PMD_EXPORT_NAME(MLX5_VDPA_DRIVER_NAME, __COUNTER__);
1007 : : RTE_PMD_REGISTER_PCI_TABLE(MLX5_VDPA_DRIVER_NAME, mlx5_vdpa_pci_id_map);
1008 : : RTE_PMD_REGISTER_KMOD_DEP(MLX5_VDPA_DRIVER_NAME, "* ib_uverbs & mlx5_core & mlx5_ib");
|