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 <stdint.h>
6 : : #include <sched.h>
7 : : #include <fcntl.h>
8 : : #include <sys/eventfd.h>
9 : :
10 : : #include <rte_malloc.h>
11 : : #include <rte_memory.h>
12 : : #include <rte_errno.h>
13 : : #include <rte_lcore.h>
14 : : #include <rte_atomic.h>
15 : : #include <rte_common.h>
16 : : #include <rte_io.h>
17 : : #include <rte_alarm.h>
18 : :
19 : : #include <mlx5_common.h>
20 : : #include <mlx5_common_os.h>
21 : : #include <mlx5_common_devx.h>
22 : : #include <mlx5_glue.h>
23 : :
24 : : #include "mlx5_vdpa_utils.h"
25 : : #include "mlx5_vdpa.h"
26 : :
27 : :
28 : : #define MLX5_VDPA_ERROR_TIME_SEC 3u
29 : :
30 : : void
31 : 0 : mlx5_vdpa_event_qp_global_release(struct mlx5_vdpa_priv *priv)
32 : : {
33 : 0 : mlx5_devx_uar_release(&priv->uar);
34 : : #ifdef HAVE_IBV_DEVX_EVENT
35 [ # # ]: 0 : if (priv->eventc) {
36 : : mlx5_os_devx_destroy_event_channel(priv->eventc);
37 : 0 : priv->eventc = NULL;
38 : : }
39 : : #endif
40 : 0 : }
41 : :
42 : : /* Prepare all the global resources for all the event objects.*/
43 : : int
44 : 0 : mlx5_vdpa_event_qp_global_prepare(struct mlx5_vdpa_priv *priv)
45 : : {
46 : 0 : priv->eventc = mlx5_os_devx_create_event_channel(priv->cdev->ctx,
47 : : MLX5DV_DEVX_CREATE_EVENT_CHANNEL_FLAGS_OMIT_EV_DATA);
48 [ # # ]: 0 : if (!priv->eventc) {
49 : 0 : rte_errno = errno;
50 : 0 : DRV_LOG(ERR, "Failed to create event channel %d.",
51 : : rte_errno);
52 : 0 : goto error;
53 : : }
54 [ # # ]: 0 : if (mlx5_devx_uar_prepare(priv->cdev, &priv->uar) != 0) {
55 : 0 : DRV_LOG(ERR, "Failed to allocate UAR.");
56 : 0 : goto error;
57 : : }
58 : : return 0;
59 : 0 : error:
60 : 0 : mlx5_vdpa_event_qp_global_release(priv);
61 : 0 : return -1;
62 : : }
63 : :
64 : : static void
65 : 0 : mlx5_vdpa_cq_destroy(struct mlx5_vdpa_cq *cq)
66 : : {
67 : 0 : mlx5_devx_cq_destroy(&cq->cq_obj);
68 : : memset(cq, 0, sizeof(*cq));
69 : 0 : }
70 : :
71 : : static inline void __rte_unused
72 : 0 : mlx5_vdpa_cq_arm(struct mlx5_vdpa_priv *priv, struct mlx5_vdpa_cq *cq)
73 : : {
74 : 0 : uint32_t arm_sn = cq->arm_sn << MLX5_CQ_SQN_OFFSET;
75 : 0 : uint32_t cq_ci = cq->cq_ci & MLX5_CI_MASK;
76 : 0 : uint32_t doorbell_hi = arm_sn | MLX5_CQ_DBR_CMD_ALL | cq_ci;
77 : 0 : uint64_t doorbell = ((uint64_t)doorbell_hi << 32) | cq->cq_obj.cq->id;
78 [ # # ]: 0 : uint64_t db_be = rte_cpu_to_be_64(doorbell);
79 : :
80 : : mlx5_doorbell_ring(&priv->uar.cq_db, db_be, doorbell_hi,
81 : 0 : &cq->cq_obj.db_rec[MLX5_CQ_ARM_DB], 0);
82 : 0 : cq->arm_sn++;
83 : 0 : cq->armed = 1;
84 : 0 : }
85 : :
86 : : static int
87 : 0 : mlx5_vdpa_cq_create(struct mlx5_vdpa_priv *priv, uint16_t log_desc_n,
88 : : int callfd, struct mlx5_vdpa_virtq *virtq)
89 : : {
90 : 0 : struct mlx5_devx_cq_attr attr = {
91 : : .use_first_only = 1,
92 [ # # ]: 0 : .uar_page_id = mlx5_os_get_devx_uar_page_id(priv->uar.obj),
93 : : };
94 : 0 : struct mlx5_vdpa_cq *cq = &virtq->eqp.cq;
95 : 0 : uint16_t event_nums[1] = {0};
96 : : int ret;
97 : :
98 : 0 : ret = mlx5_devx_cq_create(priv->cdev->ctx, &cq->cq_obj, log_desc_n,
99 : : &attr, SOCKET_ID_ANY);
100 [ # # ]: 0 : if (ret)
101 : 0 : goto error;
102 : 0 : cq->cq_ci = 0;
103 : 0 : cq->log_desc_n = log_desc_n;
104 : : rte_spinlock_init(&cq->sl);
105 : : /* Subscribe CQ event to the event channel controlled by the driver. */
106 : 0 : ret = mlx5_glue->devx_subscribe_devx_event(priv->eventc,
107 : 0 : cq->cq_obj.cq->obj,
108 : : sizeof(event_nums),
109 : : event_nums,
110 : : (uint64_t)(uintptr_t)virtq);
111 [ # # ]: 0 : if (ret) {
112 : 0 : DRV_LOG(ERR, "Failed to subscribe CQE event.");
113 : 0 : rte_errno = errno;
114 : 0 : goto error;
115 : : }
116 : 0 : cq->callfd = callfd;
117 : : /* Init CQ to ones to be in HW owner in the start. */
118 : 0 : cq->cq_obj.cqes[0].op_own = MLX5_CQE_OWNER_MASK;
119 : 0 : cq->cq_obj.cqes[0].wqe_counter = rte_cpu_to_be_16(UINT16_MAX);
120 : : /* First arming. */
121 : 0 : mlx5_vdpa_cq_arm(priv, cq);
122 : 0 : return 0;
123 : 0 : error:
124 : 0 : mlx5_vdpa_cq_destroy(cq);
125 : 0 : return -1;
126 : : }
127 : :
128 : : static inline uint32_t
129 : 0 : mlx5_vdpa_cq_poll(struct mlx5_vdpa_cq *cq)
130 : : {
131 : : struct mlx5_vdpa_event_qp *eqp =
132 : : container_of(cq, struct mlx5_vdpa_event_qp, cq);
133 : 0 : const unsigned int cq_size = 1 << cq->log_desc_n;
134 : : union {
135 : : struct {
136 : : uint16_t wqe_counter;
137 : : uint8_t rsvd5;
138 : : uint8_t op_own;
139 : : };
140 : : uint32_t word;
141 : : } last_word;
142 : 0 : uint16_t next_wqe_counter = eqp->qp_pi;
143 : : uint16_t cur_wqe_counter;
144 : : uint16_t comp;
145 : :
146 : 0 : last_word.word = rte_read32(&cq->cq_obj.cqes[0].wqe_counter);
147 [ # # ]: 0 : cur_wqe_counter = rte_be_to_cpu_16(last_word.wqe_counter);
148 : 0 : comp = cur_wqe_counter + (uint16_t)1 - next_wqe_counter;
149 [ # # ]: 0 : if (comp) {
150 : 0 : cq->cq_ci += comp;
151 : : MLX5_ASSERT(MLX5_CQE_OPCODE(last_word.op_own) !=
152 : : MLX5_CQE_INVALID);
153 [ # # ]: 0 : if (unlikely(!(MLX5_CQE_OPCODE(last_word.op_own) ==
154 : : MLX5_CQE_RESP_ERR ||
155 : : MLX5_CQE_OPCODE(last_word.op_own) ==
156 : : MLX5_CQE_REQ_ERR)))
157 : 0 : cq->errors++;
158 : 0 : rte_io_wmb();
159 : : /* Ring CQ doorbell record. */
160 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
161 : 0 : eqp->qp_pi += comp;
162 : 0 : rte_io_wmb();
163 : : /* Ring SW QP doorbell record. */
164 [ # # ]: 0 : eqp->sw_qp.db_rec[0] = rte_cpu_to_be_32(eqp->qp_pi + cq_size);
165 : : }
166 : 0 : return comp;
167 : : }
168 : :
169 : : static void
170 : 0 : mlx5_vdpa_arm_all_cqs(struct mlx5_vdpa_priv *priv)
171 : : {
172 : : struct mlx5_vdpa_virtq *virtq;
173 : : struct mlx5_vdpa_cq *cq;
174 : : int i;
175 : :
176 [ # # ]: 0 : for (i = 0; i < priv->nr_virtqs; i++) {
177 : : virtq = &priv->virtqs[i];
178 : 0 : pthread_mutex_lock(&virtq->virtq_lock);
179 : 0 : cq = &priv->virtqs[i].eqp.cq;
180 [ # # # # ]: 0 : if (cq->cq_obj.cq && !cq->armed)
181 : 0 : mlx5_vdpa_cq_arm(priv, cq);
182 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
183 : : }
184 : 0 : }
185 : :
186 : : static void
187 : 0 : mlx5_vdpa_timer_sleep(struct mlx5_vdpa_priv *priv, uint32_t max)
188 : : {
189 [ # # ]: 0 : if (priv->event_mode == MLX5_VDPA_EVENT_MODE_DYNAMIC_TIMER) {
190 [ # # # ]: 0 : switch (max) {
191 : 0 : case 0:
192 : 0 : priv->timer_delay_us += priv->event_us;
193 : 0 : break;
194 : : case 1:
195 : : break;
196 : 0 : default:
197 : 0 : priv->timer_delay_us /= max;
198 : 0 : break;
199 : : }
200 : : }
201 [ # # ]: 0 : if (priv->timer_delay_us)
202 : 0 : usleep(priv->timer_delay_us);
203 : : else
204 : : /* Give-up CPU to improve polling threads scheduling. */
205 : 0 : sched_yield();
206 : 0 : }
207 : :
208 : : /* Notify virtio device for specific virtq new traffic. */
209 : : static uint32_t
210 : 0 : mlx5_vdpa_queue_complete(struct mlx5_vdpa_cq *cq)
211 : : {
212 : : uint32_t comp = 0;
213 : :
214 [ # # ]: 0 : if (cq->cq_obj.cq) {
215 : 0 : comp = mlx5_vdpa_cq_poll(cq);
216 [ # # ]: 0 : if (comp) {
217 [ # # ]: 0 : if (cq->callfd != -1)
218 : 0 : eventfd_write(cq->callfd, (eventfd_t)1);
219 : 0 : cq->armed = 0;
220 : : }
221 : : }
222 : 0 : return comp;
223 : : }
224 : :
225 : : /* Notify virtio device for any virtq new traffic. */
226 : : static uint32_t
227 : 0 : mlx5_vdpa_queues_complete(struct mlx5_vdpa_priv *priv)
228 : : {
229 : : struct mlx5_vdpa_virtq *virtq;
230 : : struct mlx5_vdpa_cq *cq;
231 : : uint32_t max = 0;
232 : : uint32_t comp;
233 : : int i;
234 : :
235 [ # # ]: 0 : for (i = 0; i < priv->nr_virtqs; i++) {
236 : : virtq = &priv->virtqs[i];
237 : 0 : pthread_mutex_lock(&virtq->virtq_lock);
238 : 0 : cq = &virtq->eqp.cq;
239 : 0 : comp = mlx5_vdpa_queue_complete(cq);
240 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
241 : : if (comp > max)
242 : : max = comp;
243 : : }
244 : 0 : return max;
245 : : }
246 : :
247 : : void
248 : 0 : mlx5_vdpa_drain_cq(struct mlx5_vdpa_priv *priv)
249 : : {
250 : : unsigned int i;
251 : :
252 [ # # ]: 0 : for (i = 0; i < priv->caps.max_num_virtio_queues; i++) {
253 : 0 : struct mlx5_vdpa_cq *cq = &priv->virtqs[i].eqp.cq;
254 : :
255 : 0 : mlx5_vdpa_queue_complete(cq);
256 [ # # ]: 0 : if (cq->cq_obj.cq) {
257 : 0 : cq->cq_obj.cqes[0].wqe_counter =
258 : : rte_cpu_to_be_16(UINT16_MAX);
259 : 0 : priv->virtqs[i].eqp.qp_pi = 0;
260 [ # # ]: 0 : if (!cq->armed)
261 : 0 : mlx5_vdpa_cq_arm(priv, cq);
262 : : }
263 : : }
264 : 0 : }
265 : :
266 : : /* Wait on all CQs channel for completion event. */
267 : : static struct mlx5_vdpa_virtq *
268 : 0 : mlx5_vdpa_event_wait(struct mlx5_vdpa_priv *priv __rte_unused)
269 : : {
270 : : #ifdef HAVE_IBV_DEVX_EVENT
271 : : union {
272 : : struct mlx5dv_devx_async_event_hdr event_resp;
273 : : uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128];
274 : : } out;
275 : 0 : int ret = mlx5_glue->devx_get_event(priv->eventc, &out.event_resp,
276 : : sizeof(out.buf));
277 : :
278 [ # # ]: 0 : if (ret >= 0)
279 : 0 : return (struct mlx5_vdpa_virtq *)
280 : 0 : (uintptr_t)out.event_resp.cookie;
281 : 0 : DRV_LOG(INFO, "Got error in devx_get_event, ret = %d, errno = %d.",
282 : : ret, errno);
283 : : #endif
284 : 0 : return NULL;
285 : : }
286 : :
287 : : static uint32_t
288 : 0 : mlx5_vdpa_event_handle(void *arg)
289 : : {
290 : : struct mlx5_vdpa_priv *priv = arg;
291 : : struct mlx5_vdpa_virtq *virtq;
292 : : uint32_t max;
293 : :
294 [ # # # ]: 0 : switch (priv->event_mode) {
295 : 0 : case MLX5_VDPA_EVENT_MODE_DYNAMIC_TIMER:
296 : : case MLX5_VDPA_EVENT_MODE_FIXED_TIMER:
297 : 0 : priv->timer_delay_us = priv->event_us;
298 : : while (1) {
299 : 0 : max = mlx5_vdpa_queues_complete(priv);
300 [ # # ]: 0 : if (max == 0 && priv->no_traffic_counter++ >=
301 [ # # ]: 0 : priv->no_traffic_max) {
302 : 0 : DRV_LOG(DEBUG, "Device %s traffic was stopped.",
303 : : priv->vdev->device->name);
304 : 0 : mlx5_vdpa_arm_all_cqs(priv);
305 : : do {
306 : 0 : virtq = mlx5_vdpa_event_wait(priv);
307 [ # # ]: 0 : if (virtq == NULL)
308 : : break;
309 : 0 : pthread_mutex_lock(
310 : : &virtq->virtq_lock);
311 [ # # ]: 0 : if (mlx5_vdpa_queue_complete(
312 : : &virtq->eqp.cq) > 0) {
313 : 0 : pthread_mutex_unlock(
314 : : &virtq->virtq_lock);
315 : 0 : break;
316 : : }
317 : 0 : pthread_mutex_unlock(
318 : : &virtq->virtq_lock);
319 : : } while (1);
320 : 0 : priv->timer_delay_us = priv->event_us;
321 : 0 : priv->no_traffic_counter = 0;
322 [ # # ]: 0 : } else if (max != 0) {
323 : 0 : priv->no_traffic_counter = 0;
324 : : }
325 : 0 : mlx5_vdpa_timer_sleep(priv, max);
326 : : }
327 : : return 0;
328 : 0 : case MLX5_VDPA_EVENT_MODE_ONLY_INTERRUPT:
329 : : do {
330 : 0 : virtq = mlx5_vdpa_event_wait(priv);
331 [ # # ]: 0 : if (virtq != NULL) {
332 : 0 : pthread_mutex_lock(&virtq->virtq_lock);
333 [ # # ]: 0 : if (mlx5_vdpa_queue_complete(
334 : : &virtq->eqp.cq) > 0)
335 : 0 : mlx5_vdpa_cq_arm(priv, &virtq->eqp.cq);
336 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
337 : : }
338 : : } while (1);
339 : : return 0;
340 : 0 : default:
341 : : return 0;
342 : : }
343 : : }
344 : :
345 : : static void
346 : 0 : mlx5_vdpa_err_interrupt_handler(void *cb_arg __rte_unused)
347 : : {
348 : : #ifdef HAVE_IBV_DEVX_EVENT
349 : : struct mlx5_vdpa_priv *priv = cb_arg;
350 : : union {
351 : : struct mlx5dv_devx_async_event_hdr event_resp;
352 : : uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128];
353 : : } out;
354 : : uint32_t vq_index, i, version;
355 : : struct mlx5_vdpa_virtq *virtq;
356 : : uint64_t sec;
357 : :
358 : 0 : while (mlx5_glue->devx_get_event(priv->err_chnl, &out.event_resp,
359 [ # # ]: 0 : sizeof(out.buf)) >=
360 : : (ssize_t)sizeof(out.event_resp.cookie)) {
361 : 0 : vq_index = out.event_resp.cookie & UINT32_MAX;
362 : 0 : version = out.event_resp.cookie >> 32;
363 [ # # ]: 0 : if (vq_index >= priv->nr_virtqs) {
364 : 0 : DRV_LOG(ERR, "Invalid device %s error event virtq %d.",
365 : : priv->vdev->device->name, vq_index);
366 : 0 : continue;
367 : : }
368 : : virtq = &priv->virtqs[vq_index];
369 : 0 : pthread_mutex_lock(&virtq->virtq_lock);
370 [ # # # # ]: 0 : if (!virtq->enable || virtq->version != version)
371 : 0 : goto unlock;
372 [ # # ]: 0 : if (rte_rdtsc() / rte_get_tsc_hz() < MLX5_VDPA_ERROR_TIME_SEC)
373 : 0 : goto unlock;
374 : 0 : virtq->stopped = 1;
375 : : /* Query error info. */
376 [ # # ]: 0 : if (mlx5_vdpa_virtq_query(priv, vq_index))
377 : 0 : goto log;
378 : : /* Disable vq. */
379 [ # # ]: 0 : if (mlx5_vdpa_virtq_enable(priv, vq_index, 0)) {
380 : 0 : DRV_LOG(ERR, "Failed to disable virtq %d.", vq_index);
381 : 0 : goto log;
382 : : }
383 : : /* Retry if error happens less than N times in 3 seconds. */
384 : 0 : sec = (rte_rdtsc() - virtq->err_time[0]) / rte_get_tsc_hz();
385 [ # # ]: 0 : if (sec > MLX5_VDPA_ERROR_TIME_SEC) {
386 : : /* Retry. */
387 [ # # ]: 0 : if (mlx5_vdpa_virtq_enable(priv, vq_index, 1))
388 : 0 : DRV_LOG(ERR, "Failed to enable virtq %d.",
389 : : vq_index);
390 : : else
391 : 0 : DRV_LOG(WARNING, "Recover virtq %d: %u.",
392 : : vq_index, ++virtq->n_retry);
393 : : } else {
394 : : /* Retry timeout, give up. */
395 : 0 : DRV_LOG(ERR, "Device %s virtq %d failed to recover.",
396 : : priv->vdev->device->name, vq_index);
397 : : }
398 : : log:
399 : : /* Shift in current time to error time log end. */
400 [ # # ]: 0 : for (i = 1; i < RTE_DIM(virtq->err_time); i++)
401 : 0 : virtq->err_time[i - 1] = virtq->err_time[i];
402 : 0 : virtq->err_time[RTE_DIM(virtq->err_time) - 1] = rte_rdtsc();
403 : 0 : unlock:
404 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
405 : : }
406 : : #endif
407 : 0 : }
408 : :
409 : : int
410 : 0 : mlx5_vdpa_err_event_setup(struct mlx5_vdpa_priv *priv)
411 : : {
412 : : int ret;
413 : : int flags;
414 : :
415 : : /* Setup device event channel. */
416 : 0 : priv->err_chnl = mlx5_glue->devx_create_event_channel(priv->cdev->ctx,
417 : : 0);
418 [ # # ]: 0 : if (!priv->err_chnl) {
419 : 0 : rte_errno = errno;
420 : 0 : DRV_LOG(ERR, "Failed to create device event channel %d.",
421 : : rte_errno);
422 : 0 : goto error;
423 : : }
424 : 0 : flags = fcntl(priv->err_chnl->fd, F_GETFL);
425 : 0 : ret = fcntl(priv->err_chnl->fd, F_SETFL, flags | O_NONBLOCK);
426 [ # # ]: 0 : if (ret) {
427 : 0 : rte_errno = errno;
428 : 0 : DRV_LOG(ERR, "Failed to change device event channel FD.");
429 : 0 : goto error;
430 : : }
431 : 0 : priv->err_intr_handle =
432 : 0 : rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
433 [ # # ]: 0 : if (priv->err_intr_handle == NULL) {
434 : 0 : DRV_LOG(ERR, "Fail to allocate intr_handle");
435 : 0 : goto error;
436 : : }
437 [ # # ]: 0 : if (rte_intr_fd_set(priv->err_intr_handle, priv->err_chnl->fd))
438 : 0 : goto error;
439 : :
440 [ # # ]: 0 : if (rte_intr_type_set(priv->err_intr_handle, RTE_INTR_HANDLE_EXT))
441 : 0 : goto error;
442 : :
443 : 0 : ret = rte_intr_callback_register(priv->err_intr_handle,
444 : : mlx5_vdpa_err_interrupt_handler,
445 : : priv);
446 [ # # ]: 0 : if (ret != 0) {
447 : 0 : rte_intr_fd_set(priv->err_intr_handle, 0);
448 : 0 : DRV_LOG(ERR, "Failed to register error interrupt for device %d.",
449 : : priv->vid);
450 : 0 : rte_errno = -ret;
451 : 0 : goto error;
452 : : } else {
453 : 0 : DRV_LOG(DEBUG, "Registered error interrupt for device%d.",
454 : : priv->vid);
455 : : }
456 : 0 : return 0;
457 : 0 : error:
458 : 0 : mlx5_vdpa_err_event_unset(priv);
459 : 0 : return -1;
460 : : }
461 : :
462 : : void
463 : 0 : mlx5_vdpa_err_event_unset(struct mlx5_vdpa_priv *priv)
464 : : {
465 : : int retries = MLX5_VDPA_INTR_RETRIES;
466 : : int ret = -EAGAIN;
467 : :
468 [ # # ]: 0 : if (!rte_intr_fd_get(priv->err_intr_handle))
469 : : return;
470 [ # # # # ]: 0 : while (retries-- && ret == -EAGAIN) {
471 : 0 : ret = rte_intr_callback_unregister(priv->err_intr_handle,
472 : : mlx5_vdpa_err_interrupt_handler,
473 : : priv);
474 [ # # ]: 0 : if (ret == -EAGAIN) {
475 : 0 : DRV_LOG(DEBUG, "Try again to unregister fd %d "
476 : : "of error interrupt, retries = %d.",
477 : : rte_intr_fd_get(priv->err_intr_handle),
478 : : retries);
479 : : rte_pause();
480 : : }
481 : : }
482 [ # # ]: 0 : if (priv->err_chnl) {
483 : : #ifdef HAVE_IBV_DEVX_EVENT
484 : : union {
485 : : struct mlx5dv_devx_async_event_hdr event_resp;
486 : : uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) +
487 : : 128];
488 : : } out;
489 : :
490 : : /* Clean all pending events. */
491 : 0 : while (mlx5_glue->devx_get_event(priv->err_chnl,
492 [ # # ]: 0 : &out.event_resp, sizeof(out.buf)) >=
493 : : (ssize_t)sizeof(out.event_resp.cookie))
494 : : ;
495 : : #endif
496 : 0 : mlx5_glue->devx_destroy_event_channel(priv->err_chnl);
497 : 0 : priv->err_chnl = NULL;
498 : : }
499 : 0 : rte_intr_instance_free(priv->err_intr_handle);
500 : : }
501 : :
502 : : int
503 : 0 : mlx5_vdpa_cqe_event_setup(struct mlx5_vdpa_priv *priv)
504 : : {
505 : : int ret;
506 : : rte_thread_attr_t attr;
507 : : char name[RTE_THREAD_INTERNAL_NAME_SIZE];
508 : :
509 [ # # ]: 0 : if (!priv->eventc)
510 : : /* All virtqs are in poll mode. */
511 : : return 0;
512 : 0 : ret = rte_thread_attr_init(&attr);
513 [ # # ]: 0 : if (ret != 0) {
514 : 0 : DRV_LOG(ERR, "Failed to initialize thread attributes");
515 : 0 : goto out;
516 : : }
517 [ # # ]: 0 : if (priv->event_core != -1)
518 [ # # ]: 0 : CPU_SET(priv->event_core, &attr.cpuset);
519 : : else
520 : 0 : attr.cpuset = rte_lcore_cpuset(rte_get_main_lcore());
521 : 0 : ret = rte_thread_create(&priv->timer_tid,
522 : : &attr, mlx5_vdpa_event_handle, priv);
523 [ # # ]: 0 : if (ret != 0) {
524 : 0 : DRV_LOG(ERR, "Failed to create timer thread.");
525 : 0 : goto out;
526 : : }
527 : 0 : snprintf(name, sizeof(name), "vmlx5-%d", priv->vid);
528 : 0 : rte_thread_set_prefixed_name(priv->timer_tid, name);
529 : 0 : out:
530 [ # # ]: 0 : if (ret != 0)
531 : 0 : return -1;
532 : : return 0;
533 : : }
534 : :
535 : : void
536 : 0 : mlx5_vdpa_cqe_event_unset(struct mlx5_vdpa_priv *priv)
537 : : {
538 : : struct mlx5_vdpa_virtq *virtq;
539 : : int i;
540 : :
541 [ # # ]: 0 : if (priv->timer_tid.opaque_id != 0) {
542 : 0 : pthread_cancel((pthread_t)priv->timer_tid.opaque_id);
543 : 0 : rte_thread_join(priv->timer_tid, NULL);
544 : : /* The mutex may stay locked after event thread cancel, initiate it. */
545 [ # # ]: 0 : for (i = 0; i < priv->nr_virtqs; i++) {
546 : : virtq = &priv->virtqs[i];
547 : 0 : pthread_mutex_init(&virtq->virtq_lock, NULL);
548 : : }
549 : : }
550 : 0 : priv->timer_tid.opaque_id = 0;
551 : 0 : }
552 : :
553 : : void
554 : 0 : mlx5_vdpa_event_qp_destroy(struct mlx5_vdpa_event_qp *eqp)
555 : : {
556 : 0 : mlx5_devx_qp_destroy(&eqp->sw_qp);
557 [ # # ]: 0 : if (eqp->fw_qp)
558 : 0 : claim_zero(mlx5_devx_cmd_destroy(eqp->fw_qp));
559 : 0 : mlx5_vdpa_cq_destroy(&eqp->cq);
560 : : memset(eqp, 0, sizeof(*eqp));
561 : 0 : }
562 : :
563 : : static int
564 : 0 : mlx5_vdpa_qps2rts(struct mlx5_vdpa_event_qp *eqp)
565 : : {
566 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_RST2INIT_QP,
567 : 0 : eqp->sw_qp.qp->id)) {
568 : 0 : DRV_LOG(ERR, "Failed to modify FW QP to INIT state(%u).",
569 : : rte_errno);
570 : 0 : return -1;
571 : : }
572 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp,
573 : 0 : MLX5_CMD_OP_RST2INIT_QP, eqp->fw_qp->id)) {
574 : 0 : DRV_LOG(ERR, "Failed to modify SW QP to INIT state(%u).",
575 : : rte_errno);
576 : 0 : return -1;
577 : : }
578 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_INIT2RTR_QP,
579 : 0 : eqp->sw_qp.qp->id)) {
580 : 0 : DRV_LOG(ERR, "Failed to modify FW QP to RTR state(%u).",
581 : : rte_errno);
582 : 0 : return -1;
583 : : }
584 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp,
585 : 0 : MLX5_CMD_OP_INIT2RTR_QP, eqp->fw_qp->id)) {
586 : 0 : DRV_LOG(ERR, "Failed to modify SW QP to RTR state(%u).",
587 : : rte_errno);
588 : 0 : return -1;
589 : : }
590 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_RTR2RTS_QP,
591 : 0 : eqp->sw_qp.qp->id)) {
592 : 0 : DRV_LOG(ERR, "Failed to modify FW QP to RTS state(%u).",
593 : : rte_errno);
594 : 0 : return -1;
595 : : }
596 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp, MLX5_CMD_OP_RTR2RTS_QP,
597 : 0 : eqp->fw_qp->id)) {
598 : 0 : DRV_LOG(ERR, "Failed to modify SW QP to RTS state(%u).",
599 : : rte_errno);
600 : 0 : return -1;
601 : : }
602 : : return 0;
603 : : }
604 : :
605 : : int
606 : 0 : mlx5_vdpa_qps2rst2rts(struct mlx5_vdpa_event_qp *eqp)
607 : : {
608 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_QP_2RST,
609 : 0 : eqp->sw_qp.qp->id)) {
610 : 0 : DRV_LOG(ERR, "Failed to modify FW QP to RST state(%u).",
611 : : rte_errno);
612 : 0 : return -1;
613 : : }
614 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp,
615 : 0 : MLX5_CMD_OP_QP_2RST, eqp->fw_qp->id)) {
616 : 0 : DRV_LOG(ERR, "Failed to modify SW QP to RST state(%u).",
617 : : rte_errno);
618 : 0 : return -1;
619 : : }
620 : 0 : return mlx5_vdpa_qps2rts(eqp);
621 : : }
622 : :
623 : : int
624 : 0 : mlx5_vdpa_event_qp_prepare(struct mlx5_vdpa_priv *priv, uint16_t desc_n,
625 : : int callfd, struct mlx5_vdpa_virtq *virtq, bool reset)
626 : : {
627 : 0 : struct mlx5_vdpa_event_qp *eqp = &virtq->eqp;
628 : 0 : struct mlx5_devx_qp_attr attr = {0};
629 [ # # ]: 0 : uint16_t log_desc_n = rte_log2_u32(desc_n);
630 : : uint32_t ret;
631 : :
632 [ # # # # ]: 0 : if (eqp->cq.cq_obj.cq != NULL && log_desc_n == eqp->cq.log_desc_n) {
633 : : /* Reuse existing resources. */
634 : 0 : eqp->cq.callfd = callfd;
635 : : /* FW will set event qp to error state in q destroy. */
636 [ # # # # ]: 0 : if (reset && !mlx5_vdpa_qps2rst2rts(eqp))
637 : 0 : rte_write32(rte_cpu_to_be_32(RTE_BIT32(log_desc_n)),
638 [ # # ]: 0 : &eqp->sw_qp.db_rec[0]);
639 : 0 : return 0;
640 : : }
641 [ # # ]: 0 : if (eqp->fw_qp)
642 : 0 : mlx5_vdpa_event_qp_destroy(eqp);
643 [ # # ]: 0 : if (mlx5_vdpa_cq_create(priv, log_desc_n, callfd, virtq) ||
644 [ # # ]: 0 : !eqp->cq.cq_obj.cq)
645 : : return -1;
646 : 0 : attr.pd = priv->cdev->pdn;
647 : 0 : attr.ts_format =
648 : 0 : mlx5_ts_format_conv(priv->cdev->config.hca_attr.qp_ts_format);
649 : 0 : eqp->fw_qp = mlx5_devx_cmd_create_qp(priv->cdev->ctx, &attr);
650 [ # # ]: 0 : if (!eqp->fw_qp) {
651 : 0 : DRV_LOG(ERR, "Failed to create FW QP(%u).", rte_errno);
652 : 0 : goto error;
653 : : }
654 [ # # ]: 0 : attr.uar_index = mlx5_os_get_devx_uar_page_id(priv->uar.obj);
655 : 0 : attr.cqn = eqp->cq.cq_obj.cq->id;
656 : 0 : attr.num_of_receive_wqes = RTE_BIT32(log_desc_n);
657 : 0 : attr.log_rq_stride = rte_log2_u32(MLX5_WSEG_SIZE);
658 : 0 : attr.num_of_send_wqbbs = 0; /* No need SQ. */
659 : 0 : attr.ts_format =
660 : 0 : mlx5_ts_format_conv(priv->cdev->config.hca_attr.qp_ts_format);
661 : 0 : ret = mlx5_devx_qp_create(priv->cdev->ctx, &(eqp->sw_qp),
662 : 0 : attr.num_of_receive_wqes * MLX5_WSEG_SIZE,
663 : : &attr, SOCKET_ID_ANY);
664 [ # # ]: 0 : if (ret) {
665 : 0 : DRV_LOG(ERR, "Failed to create SW QP(%u).", rte_errno);
666 : 0 : goto error;
667 : : }
668 [ # # ]: 0 : if (mlx5_vdpa_qps2rts(eqp))
669 : 0 : goto error;
670 : 0 : eqp->qp_pi = 0;
671 : : /* First ringing. */
672 [ # # ]: 0 : if (eqp->sw_qp.db_rec)
673 [ # # ]: 0 : rte_write32(rte_cpu_to_be_32(RTE_BIT32(log_desc_n)),
674 : : &eqp->sw_qp.db_rec[0]);
675 : : return 0;
676 : 0 : error:
677 : 0 : mlx5_vdpa_event_qp_destroy(eqp);
678 : 0 : return -1;
679 : : }
680 : :
|