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 : : static void
248 : 0 : mlx5_vdpa_drain_cq_one(struct mlx5_vdpa_priv *priv,
249 : : struct mlx5_vdpa_virtq *virtq)
250 : : {
251 : 0 : struct mlx5_vdpa_cq *cq = &virtq->eqp.cq;
252 : :
253 : 0 : mlx5_vdpa_queue_complete(cq);
254 [ # # ]: 0 : if (cq->cq_obj.cq) {
255 : 0 : cq->cq_obj.cqes[0].wqe_counter = rte_cpu_to_be_16(UINT16_MAX);
256 : 0 : virtq->eqp.qp_pi = 0;
257 [ # # ]: 0 : if (!cq->armed)
258 : 0 : mlx5_vdpa_cq_arm(priv, cq);
259 : : }
260 : 0 : }
261 : :
262 : : void
263 : 0 : mlx5_vdpa_drain_cq(struct mlx5_vdpa_priv *priv)
264 : : {
265 : : struct mlx5_vdpa_virtq *virtq;
266 : : unsigned int i;
267 : :
268 [ # # ]: 0 : for (i = 0; i < priv->caps.max_num_virtio_queues; i++) {
269 : 0 : virtq = &priv->virtqs[i];
270 : 0 : mlx5_vdpa_drain_cq_one(priv, virtq);
271 : : }
272 : 0 : }
273 : :
274 : : /* Wait on all CQs channel for completion event. */
275 : : static struct mlx5_vdpa_virtq *
276 : 0 : mlx5_vdpa_event_wait(struct mlx5_vdpa_priv *priv __rte_unused)
277 : : {
278 : : #ifdef HAVE_IBV_DEVX_EVENT
279 : : union {
280 : : struct mlx5dv_devx_async_event_hdr event_resp;
281 : : uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128];
282 : : } out;
283 : 0 : int ret = mlx5_glue->devx_get_event(priv->eventc, &out.event_resp,
284 : : sizeof(out.buf));
285 : :
286 [ # # ]: 0 : if (ret >= 0)
287 : 0 : return (struct mlx5_vdpa_virtq *)
288 : 0 : (uintptr_t)out.event_resp.cookie;
289 : 0 : DRV_LOG(INFO, "Got error in devx_get_event, ret = %d, errno = %d.",
290 : : ret, errno);
291 : : #endif
292 : 0 : return NULL;
293 : : }
294 : :
295 : : static uint32_t
296 : 0 : mlx5_vdpa_event_handle(void *arg)
297 : : {
298 : : struct mlx5_vdpa_priv *priv = arg;
299 : : struct mlx5_vdpa_virtq *virtq;
300 : : uint32_t max;
301 : :
302 [ # # # ]: 0 : switch (priv->event_mode) {
303 : 0 : case MLX5_VDPA_EVENT_MODE_DYNAMIC_TIMER:
304 : : case MLX5_VDPA_EVENT_MODE_FIXED_TIMER:
305 : 0 : priv->timer_delay_us = priv->event_us;
306 : : while (1) {
307 : 0 : max = mlx5_vdpa_queues_complete(priv);
308 [ # # ]: 0 : if (max == 0 && priv->no_traffic_counter++ >=
309 [ # # ]: 0 : priv->no_traffic_max) {
310 : 0 : DRV_LOG(DEBUG, "Device %s traffic was stopped.",
311 : : priv->vdev->device->name);
312 : 0 : mlx5_vdpa_arm_all_cqs(priv);
313 : : do {
314 : 0 : virtq = mlx5_vdpa_event_wait(priv);
315 [ # # ]: 0 : if (virtq == NULL)
316 : : break;
317 : 0 : pthread_mutex_lock(
318 : : &virtq->virtq_lock);
319 [ # # ]: 0 : if (mlx5_vdpa_queue_complete(
320 : : &virtq->eqp.cq) > 0) {
321 : 0 : pthread_mutex_unlock(
322 : : &virtq->virtq_lock);
323 : 0 : break;
324 : : }
325 : 0 : pthread_mutex_unlock(
326 : : &virtq->virtq_lock);
327 : : } while (1);
328 : 0 : priv->timer_delay_us = priv->event_us;
329 : 0 : priv->no_traffic_counter = 0;
330 [ # # ]: 0 : } else if (max != 0) {
331 : 0 : priv->no_traffic_counter = 0;
332 : : }
333 : 0 : mlx5_vdpa_timer_sleep(priv, max);
334 : : }
335 : : return 0;
336 : 0 : case MLX5_VDPA_EVENT_MODE_ONLY_INTERRUPT:
337 : : do {
338 : 0 : virtq = mlx5_vdpa_event_wait(priv);
339 [ # # ]: 0 : if (virtq != NULL) {
340 : 0 : pthread_mutex_lock(&virtq->virtq_lock);
341 [ # # ]: 0 : if (mlx5_vdpa_queue_complete(
342 : : &virtq->eqp.cq) > 0)
343 : 0 : mlx5_vdpa_cq_arm(priv, &virtq->eqp.cq);
344 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
345 : : }
346 : : } while (1);
347 : : return 0;
348 : 0 : default:
349 : : return 0;
350 : : }
351 : : }
352 : :
353 : : static void
354 : 0 : mlx5_vdpa_err_interrupt_handler(void *cb_arg __rte_unused)
355 : : {
356 : : #ifdef HAVE_IBV_DEVX_EVENT
357 : : struct mlx5_vdpa_priv *priv = cb_arg;
358 : : union {
359 : : struct mlx5dv_devx_async_event_hdr event_resp;
360 : : uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128];
361 : : } out;
362 : : uint32_t vq_index, i, version;
363 : : struct mlx5_vdpa_virtq *virtq;
364 : : uint64_t sec;
365 : :
366 : 0 : while (mlx5_glue->devx_get_event(priv->err_chnl, &out.event_resp,
367 [ # # ]: 0 : sizeof(out.buf)) >=
368 : : (ssize_t)sizeof(out.event_resp.cookie)) {
369 : 0 : vq_index = out.event_resp.cookie & UINT32_MAX;
370 : 0 : version = out.event_resp.cookie >> 32;
371 [ # # ]: 0 : if (vq_index >= priv->nr_virtqs) {
372 : 0 : DRV_LOG(ERR, "Invalid device %s error event virtq %d.",
373 : : priv->vdev->device->name, vq_index);
374 : 0 : continue;
375 : : }
376 : : virtq = &priv->virtqs[vq_index];
377 : 0 : pthread_mutex_lock(&virtq->virtq_lock);
378 [ # # # # ]: 0 : if (!virtq->enable || virtq->version != version)
379 : 0 : goto unlock;
380 [ # # ]: 0 : if (rte_rdtsc() / rte_get_tsc_hz() < MLX5_VDPA_ERROR_TIME_SEC)
381 : 0 : goto unlock;
382 : 0 : virtq->stopped = 1;
383 : : /* Query error info. */
384 [ # # ]: 0 : if (mlx5_vdpa_virtq_query(priv, vq_index))
385 : 0 : goto log;
386 : : /* Disable vq. */
387 [ # # ]: 0 : if (mlx5_vdpa_virtq_enable(priv, vq_index, 0)) {
388 : 0 : DRV_LOG(ERR, "Failed to disable virtq %d.", vq_index);
389 : 0 : goto log;
390 : : }
391 : : /* Retry if error happens less than N times in 3 seconds. */
392 : 0 : sec = (rte_rdtsc() - virtq->err_time[0]) / rte_get_tsc_hz();
393 [ # # ]: 0 : if (sec > MLX5_VDPA_ERROR_TIME_SEC) {
394 : : /* Retry. */
395 [ # # ]: 0 : if (mlx5_vdpa_virtq_enable(priv, vq_index, 1))
396 : 0 : DRV_LOG(ERR, "Failed to enable virtq %d.",
397 : : vq_index);
398 : : else
399 : 0 : DRV_LOG(WARNING, "Recover virtq %d: %u.",
400 : : vq_index, ++virtq->n_retry);
401 : : } else {
402 : : /* Retry timeout, give up. */
403 : 0 : DRV_LOG(ERR, "Device %s virtq %d failed to recover.",
404 : : priv->vdev->device->name, vq_index);
405 : : }
406 : : log:
407 : : /* Shift in current time to error time log end. */
408 [ # # ]: 0 : for (i = 1; i < RTE_DIM(virtq->err_time); i++)
409 : 0 : virtq->err_time[i - 1] = virtq->err_time[i];
410 : 0 : virtq->err_time[RTE_DIM(virtq->err_time) - 1] = rte_rdtsc();
411 : 0 : unlock:
412 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
413 : : }
414 : : #endif
415 : 0 : }
416 : :
417 : : int
418 : 0 : mlx5_vdpa_err_event_setup(struct mlx5_vdpa_priv *priv)
419 : : {
420 : : int ret;
421 : : int flags;
422 : :
423 : : /* Setup device event channel. */
424 : 0 : priv->err_chnl = mlx5_glue->devx_create_event_channel(priv->cdev->ctx,
425 : : 0);
426 [ # # ]: 0 : if (!priv->err_chnl) {
427 : 0 : rte_errno = errno;
428 : 0 : DRV_LOG(ERR, "Failed to create device event channel %d.",
429 : : rte_errno);
430 : 0 : goto error;
431 : : }
432 : 0 : flags = fcntl(priv->err_chnl->fd, F_GETFL);
433 : 0 : ret = fcntl(priv->err_chnl->fd, F_SETFL, flags | O_NONBLOCK);
434 [ # # ]: 0 : if (ret) {
435 : 0 : rte_errno = errno;
436 : 0 : DRV_LOG(ERR, "Failed to change device event channel FD.");
437 : 0 : goto error;
438 : : }
439 : 0 : priv->err_intr_handle =
440 : 0 : rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
441 [ # # ]: 0 : if (priv->err_intr_handle == NULL) {
442 : 0 : DRV_LOG(ERR, "Fail to allocate intr_handle");
443 : 0 : goto error;
444 : : }
445 [ # # ]: 0 : if (rte_intr_fd_set(priv->err_intr_handle, priv->err_chnl->fd))
446 : 0 : goto error;
447 : :
448 [ # # ]: 0 : if (rte_intr_type_set(priv->err_intr_handle, RTE_INTR_HANDLE_EXT))
449 : 0 : goto error;
450 : :
451 : 0 : ret = rte_intr_callback_register(priv->err_intr_handle,
452 : : mlx5_vdpa_err_interrupt_handler,
453 : : priv);
454 [ # # ]: 0 : if (ret != 0) {
455 : 0 : rte_intr_fd_set(priv->err_intr_handle, 0);
456 : 0 : DRV_LOG(ERR, "Failed to register error interrupt for device %d.",
457 : : priv->vid);
458 : 0 : rte_errno = -ret;
459 : 0 : goto error;
460 : : } else {
461 : 0 : DRV_LOG(DEBUG, "Registered error interrupt for device%d.",
462 : : priv->vid);
463 : : }
464 : 0 : return 0;
465 : 0 : error:
466 : 0 : mlx5_vdpa_err_event_unset(priv);
467 : 0 : return -1;
468 : : }
469 : :
470 : : void
471 : 0 : mlx5_vdpa_err_event_unset(struct mlx5_vdpa_priv *priv)
472 : : {
473 : : int retries = MLX5_VDPA_INTR_RETRIES;
474 : : int ret = -EAGAIN;
475 : :
476 [ # # ]: 0 : if (!rte_intr_fd_get(priv->err_intr_handle))
477 : : return;
478 [ # # # # ]: 0 : while (retries-- && ret == -EAGAIN) {
479 : 0 : ret = rte_intr_callback_unregister(priv->err_intr_handle,
480 : : mlx5_vdpa_err_interrupt_handler,
481 : : priv);
482 [ # # ]: 0 : if (ret == -EAGAIN) {
483 : 0 : DRV_LOG(DEBUG, "Try again to unregister fd %d "
484 : : "of error interrupt, retries = %d.",
485 : : rte_intr_fd_get(priv->err_intr_handle),
486 : : retries);
487 : : rte_pause();
488 : : }
489 : : }
490 [ # # ]: 0 : if (priv->err_chnl) {
491 : : #ifdef HAVE_IBV_DEVX_EVENT
492 : : union {
493 : : struct mlx5dv_devx_async_event_hdr event_resp;
494 : : uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) +
495 : : 128];
496 : : } out;
497 : :
498 : : /* Clean all pending events. */
499 : 0 : while (mlx5_glue->devx_get_event(priv->err_chnl,
500 [ # # ]: 0 : &out.event_resp, sizeof(out.buf)) >=
501 : : (ssize_t)sizeof(out.event_resp.cookie))
502 : : ;
503 : : #endif
504 : 0 : mlx5_glue->devx_destroy_event_channel(priv->err_chnl);
505 : 0 : priv->err_chnl = NULL;
506 : : }
507 : 0 : rte_intr_instance_free(priv->err_intr_handle);
508 : : }
509 : :
510 : : int
511 : 0 : mlx5_vdpa_cqe_event_setup(struct mlx5_vdpa_priv *priv)
512 : : {
513 : : int ret;
514 : : rte_thread_attr_t attr;
515 : : char name[RTE_THREAD_INTERNAL_NAME_SIZE];
516 : :
517 [ # # ]: 0 : if (!priv->eventc)
518 : : /* All virtqs are in poll mode. */
519 : : return 0;
520 : 0 : ret = rte_thread_attr_init(&attr);
521 [ # # ]: 0 : if (ret != 0) {
522 : 0 : DRV_LOG(ERR, "Failed to initialize thread attributes");
523 : 0 : goto out;
524 : : }
525 [ # # ]: 0 : if (priv->event_core != -1)
526 [ # # ]: 0 : CPU_SET(priv->event_core, &attr.cpuset);
527 : : else
528 : 0 : attr.cpuset = rte_lcore_cpuset(rte_get_main_lcore());
529 : 0 : ret = rte_thread_create(&priv->timer_tid,
530 : : &attr, mlx5_vdpa_event_handle, priv);
531 [ # # ]: 0 : if (ret != 0) {
532 : 0 : DRV_LOG(ERR, "Failed to create timer thread.");
533 : 0 : goto out;
534 : : }
535 : 0 : snprintf(name, sizeof(name), "vmlx5-%d", priv->vid);
536 : 0 : rte_thread_set_prefixed_name(priv->timer_tid, name);
537 : 0 : out:
538 [ # # ]: 0 : if (ret != 0)
539 : 0 : return -1;
540 : : return 0;
541 : : }
542 : :
543 : : void
544 : 0 : mlx5_vdpa_cqe_event_unset(struct mlx5_vdpa_priv *priv)
545 : : {
546 : : struct mlx5_vdpa_virtq *virtq;
547 : : int i;
548 : :
549 [ # # ]: 0 : if (priv->timer_tid.opaque_id != 0) {
550 : 0 : pthread_cancel((pthread_t)priv->timer_tid.opaque_id);
551 : 0 : rte_thread_join(priv->timer_tid, NULL);
552 : : /* The mutex may stay locked after event thread cancel, initiate it. */
553 [ # # ]: 0 : for (i = 0; i < priv->nr_virtqs; i++) {
554 : : virtq = &priv->virtqs[i];
555 : 0 : pthread_mutex_init(&virtq->virtq_lock, NULL);
556 : : }
557 : : }
558 : 0 : priv->timer_tid.opaque_id = 0;
559 : 0 : }
560 : :
561 : : void
562 : 0 : mlx5_vdpa_event_qp_destroy(struct mlx5_vdpa_event_qp *eqp)
563 : : {
564 : 0 : mlx5_devx_qp_destroy(&eqp->sw_qp);
565 [ # # ]: 0 : if (eqp->fw_qp)
566 : 0 : claim_zero(mlx5_devx_cmd_destroy(eqp->fw_qp));
567 : 0 : mlx5_vdpa_cq_destroy(&eqp->cq);
568 : : memset(eqp, 0, sizeof(*eqp));
569 : 0 : }
570 : :
571 : : static int
572 : 0 : mlx5_vdpa_qps2rts(struct mlx5_vdpa_event_qp *eqp)
573 : : {
574 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_RST2INIT_QP,
575 : 0 : eqp->sw_qp.qp->id)) {
576 : 0 : DRV_LOG(ERR, "Failed to modify FW QP to INIT state(%u).",
577 : : rte_errno);
578 : 0 : return -1;
579 : : }
580 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp,
581 : 0 : MLX5_CMD_OP_RST2INIT_QP, eqp->fw_qp->id)) {
582 : 0 : DRV_LOG(ERR, "Failed to modify SW QP to INIT state(%u).",
583 : : rte_errno);
584 : 0 : return -1;
585 : : }
586 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_INIT2RTR_QP,
587 : 0 : eqp->sw_qp.qp->id)) {
588 : 0 : DRV_LOG(ERR, "Failed to modify FW QP to RTR state(%u).",
589 : : rte_errno);
590 : 0 : return -1;
591 : : }
592 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp,
593 : 0 : MLX5_CMD_OP_INIT2RTR_QP, eqp->fw_qp->id)) {
594 : 0 : DRV_LOG(ERR, "Failed to modify SW QP to RTR state(%u).",
595 : : rte_errno);
596 : 0 : return -1;
597 : : }
598 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_RTR2RTS_QP,
599 : 0 : eqp->sw_qp.qp->id)) {
600 : 0 : DRV_LOG(ERR, "Failed to modify FW QP to RTS state(%u).",
601 : : rte_errno);
602 : 0 : return -1;
603 : : }
604 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp, MLX5_CMD_OP_RTR2RTS_QP,
605 : 0 : eqp->fw_qp->id)) {
606 : 0 : DRV_LOG(ERR, "Failed to modify SW QP to RTS state(%u).",
607 : : rte_errno);
608 : 0 : return -1;
609 : : }
610 : : return 0;
611 : : }
612 : :
613 : : int
614 : 0 : mlx5_vdpa_qps2rst2rts(struct mlx5_vdpa_event_qp *eqp)
615 : : {
616 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_QP_2RST,
617 : 0 : eqp->sw_qp.qp->id)) {
618 : 0 : DRV_LOG(ERR, "Failed to modify FW QP to RST state(%u).",
619 : : rte_errno);
620 : 0 : return -1;
621 : : }
622 [ # # ]: 0 : if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp,
623 : 0 : MLX5_CMD_OP_QP_2RST, eqp->fw_qp->id)) {
624 : 0 : DRV_LOG(ERR, "Failed to modify SW QP to RST state(%u).",
625 : : rte_errno);
626 : 0 : return -1;
627 : : }
628 : 0 : return mlx5_vdpa_qps2rts(eqp);
629 : : }
630 : :
631 : : int
632 : 0 : mlx5_vdpa_event_qp_prepare(struct mlx5_vdpa_priv *priv, uint16_t desc_n,
633 : : int callfd, struct mlx5_vdpa_virtq *virtq, bool reset)
634 : : {
635 : 0 : struct mlx5_vdpa_event_qp *eqp = &virtq->eqp;
636 : 0 : struct mlx5_devx_qp_attr attr = {0};
637 [ # # ]: 0 : uint16_t log_desc_n = rte_log2_u32(desc_n);
638 : : uint32_t ret;
639 : :
640 [ # # # # ]: 0 : if (eqp->cq.cq_obj.cq != NULL && log_desc_n == eqp->cq.log_desc_n) {
641 : : /* Reuse existing resources. */
642 : 0 : eqp->cq.callfd = callfd;
643 : 0 : mlx5_vdpa_drain_cq_one(priv, virtq);
644 : : /* FW will set event qp to error state in q destroy. */
645 [ # # # # ]: 0 : if (reset && !mlx5_vdpa_qps2rst2rts(eqp))
646 : 0 : rte_write32(rte_cpu_to_be_32(RTE_BIT32(log_desc_n)),
647 [ # # ]: 0 : &eqp->sw_qp.db_rec[0]);
648 : 0 : return 0;
649 : : }
650 [ # # ]: 0 : if (eqp->fw_qp)
651 : 0 : mlx5_vdpa_event_qp_destroy(eqp);
652 [ # # ]: 0 : if (mlx5_vdpa_cq_create(priv, log_desc_n, callfd, virtq) ||
653 [ # # ]: 0 : !eqp->cq.cq_obj.cq)
654 : : return -1;
655 : 0 : attr.pd = priv->cdev->pdn;
656 : 0 : attr.ts_format =
657 : 0 : mlx5_ts_format_conv(priv->cdev->config.hca_attr.qp_ts_format);
658 : 0 : eqp->fw_qp = mlx5_devx_cmd_create_qp(priv->cdev->ctx, &attr);
659 [ # # ]: 0 : if (!eqp->fw_qp) {
660 : 0 : DRV_LOG(ERR, "Failed to create FW QP(%u).", rte_errno);
661 : 0 : goto error;
662 : : }
663 [ # # ]: 0 : attr.uar_index = mlx5_os_get_devx_uar_page_id(priv->uar.obj);
664 : 0 : attr.cqn = eqp->cq.cq_obj.cq->id;
665 : 0 : attr.num_of_receive_wqes = RTE_BIT32(log_desc_n);
666 : 0 : attr.log_rq_stride = rte_log2_u32(MLX5_WSEG_SIZE);
667 : 0 : attr.num_of_send_wqbbs = 0; /* No need SQ. */
668 : 0 : attr.ts_format =
669 : 0 : mlx5_ts_format_conv(priv->cdev->config.hca_attr.qp_ts_format);
670 : 0 : ret = mlx5_devx_qp_create(priv->cdev->ctx, &(eqp->sw_qp),
671 : 0 : attr.num_of_receive_wqes * MLX5_WSEG_SIZE,
672 : : &attr, SOCKET_ID_ANY);
673 [ # # ]: 0 : if (ret) {
674 : 0 : DRV_LOG(ERR, "Failed to create SW QP(%u).", rte_errno);
675 : 0 : goto error;
676 : : }
677 [ # # ]: 0 : if (mlx5_vdpa_qps2rts(eqp))
678 : 0 : goto error;
679 : 0 : eqp->qp_pi = 0;
680 : : /* First ringing. */
681 [ # # ]: 0 : if (eqp->sw_qp.db_rec)
682 [ # # ]: 0 : rte_write32(rte_cpu_to_be_32(RTE_BIT32(log_desc_n)),
683 : : &eqp->sw_qp.db_rec[0]);
684 : : return 0;
685 : 0 : error:
686 : 0 : mlx5_vdpa_event_qp_destroy(eqp);
687 : 0 : return -1;
688 : : }
689 : :
|