Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2022 NVIDIA Corporation & Affiliates
3 : : */
4 : : #include <string.h>
5 : : #include <unistd.h>
6 : : #include <sys/eventfd.h>
7 : :
8 : : #include <rte_malloc.h>
9 : : #include <rte_errno.h>
10 : : #include <rte_io.h>
11 : : #include <rte_alarm.h>
12 : : #include <rte_tailq.h>
13 : : #include <rte_ring_elem.h>
14 : : #include <rte_ring_peek.h>
15 : :
16 : : #include <mlx5_common.h>
17 : :
18 : : #include "mlx5_vdpa_utils.h"
19 : : #include "mlx5_vdpa.h"
20 : :
21 : : static inline uint32_t
22 [ # # # ]: 0 : mlx5_vdpa_c_thrd_ring_dequeue_bulk(struct rte_ring *r,
23 : : void **obj, uint32_t n, uint32_t *avail)
24 : : {
25 : : uint32_t m;
26 : :
27 : : m = rte_ring_dequeue_bulk_elem_start(r, obj,
28 : : sizeof(struct mlx5_vdpa_task), n, avail);
29 [ # # ]: 0 : n = (m == n) ? n : 0;
30 : : rte_ring_dequeue_elem_finish(r, n);
31 : 0 : return n;
32 : : }
33 : :
34 : : static inline uint32_t
35 [ # # # ]: 0 : mlx5_vdpa_c_thrd_ring_enqueue_bulk(struct rte_ring *r,
36 : : void * const *obj, uint32_t n, uint32_t *free)
37 : : {
38 : : uint32_t m;
39 : :
40 : : m = rte_ring_enqueue_bulk_elem_start(r, n, free);
41 [ # # ]: 0 : n = (m == n) ? n : 0;
42 : : rte_ring_enqueue_elem_finish(r, obj,
43 : : sizeof(struct mlx5_vdpa_task), n);
44 : 0 : return n;
45 : : }
46 : :
47 : : bool
48 : 0 : mlx5_vdpa_task_add(struct mlx5_vdpa_priv *priv,
49 : : uint32_t thrd_idx,
50 : : enum mlx5_vdpa_task_type task_type,
51 : : RTE_ATOMIC(uint32_t) *remaining_cnt, RTE_ATOMIC(uint32_t) *err_cnt,
52 : : void **task_data, uint32_t num)
53 : : {
54 : 0 : struct rte_ring *rng = conf_thread_mng.cthrd[thrd_idx].rng;
55 : : struct mlx5_vdpa_task task[MLX5_VDPA_TASKS_PER_DEV];
56 : : uint32_t *data = (uint32_t *)task_data;
57 : : uint32_t i;
58 : :
59 : : MLX5_ASSERT(num <= MLX5_VDPA_TASKS_PER_DEV);
60 [ # # ]: 0 : for (i = 0 ; i < num; i++) {
61 : 0 : task[i].priv = priv;
62 : : /* To be added later. */
63 : 0 : task[i].type = task_type;
64 : 0 : task[i].remaining_cnt = remaining_cnt;
65 : 0 : task[i].err_cnt = err_cnt;
66 [ # # ]: 0 : if (data)
67 : 0 : task[i].idx = data[i];
68 : : }
69 [ # # ]: 0 : if (!mlx5_vdpa_c_thrd_ring_enqueue_bulk(rng, (void **)&task, num, NULL))
70 : : return -1;
71 [ # # ]: 0 : for (i = 0 ; i < num; i++)
72 [ # # ]: 0 : if (task[i].remaining_cnt)
73 : 0 : rte_atomic_fetch_add_explicit(task[i].remaining_cnt, 1,
74 : : rte_memory_order_relaxed);
75 : : /* wake up conf thread. */
76 : 0 : pthread_mutex_lock(&conf_thread_mng.cthrd_lock);
77 : 0 : pthread_cond_signal(&conf_thread_mng.cthrd[thrd_idx].c_cond);
78 : 0 : pthread_mutex_unlock(&conf_thread_mng.cthrd_lock);
79 : 0 : return 0;
80 : : }
81 : :
82 : : bool
83 : 0 : mlx5_vdpa_c_thread_wait_bulk_tasks_done(RTE_ATOMIC(uint32_t) *remaining_cnt,
84 : : RTE_ATOMIC(uint32_t) *err_cnt, uint32_t sleep_time)
85 : : {
86 : : /* Check and wait all tasks done. */
87 : 0 : while (rte_atomic_load_explicit(remaining_cnt,
88 [ # # ]: 0 : rte_memory_order_relaxed) != 0) {
89 : 0 : rte_delay_us_sleep(sleep_time);
90 : : }
91 [ # # ]: 0 : if (rte_atomic_load_explicit(err_cnt,
92 : : rte_memory_order_relaxed)) {
93 : 0 : DRV_LOG(ERR, "Tasks done with error.");
94 : 0 : return true;
95 : : }
96 : : return false;
97 : : }
98 : :
99 : : static uint32_t
100 : 0 : mlx5_vdpa_c_thread_handle(void *arg)
101 : : {
102 : : struct mlx5_vdpa_conf_thread_mng *multhrd = arg;
103 : : struct mlx5_vdpa_virtq *virtq;
104 : : struct mlx5_vdpa_priv *priv;
105 : : struct mlx5_vdpa_task task;
106 : : struct rte_ring *rng;
107 : : uint64_t features;
108 : : uint32_t thrd_idx;
109 : : uint32_t task_num;
110 : : int ret;
111 : :
112 [ # # ]: 0 : for (thrd_idx = 0; thrd_idx < multhrd->max_thrds;
113 : 0 : thrd_idx++)
114 [ # # ]: 0 : if (rte_thread_equal(multhrd->cthrd[thrd_idx].tid, rte_thread_self()))
115 : : break;
116 [ # # ]: 0 : if (thrd_idx >= multhrd->max_thrds)
117 : : return 1;
118 : 0 : rng = multhrd->cthrd[thrd_idx].rng;
119 : : while (1) {
120 : 0 : task_num = mlx5_vdpa_c_thrd_ring_dequeue_bulk(rng,
121 : : (void **)&task, 1, NULL);
122 [ # # ]: 0 : if (!task_num) {
123 : : /* No task and condition wait. */
124 : 0 : pthread_mutex_lock(&multhrd->cthrd_lock);
125 : 0 : pthread_cond_wait(
126 : : &multhrd->cthrd[thrd_idx].c_cond,
127 : : &multhrd->cthrd_lock);
128 : 0 : pthread_mutex_unlock(&multhrd->cthrd_lock);
129 : 0 : continue;
130 : : }
131 : 0 : priv = task.priv;
132 [ # # ]: 0 : if (priv == NULL)
133 : 0 : continue;
134 [ # # # # : 0 : switch (task.type) {
# # ]
135 : 0 : case MLX5_VDPA_TASK_REG_MR:
136 : 0 : ret = mlx5_vdpa_register_mr(priv, task.idx);
137 [ # # ]: 0 : if (ret) {
138 : 0 : DRV_LOG(ERR,
139 : : "Failed to register mr %d.", task.idx);
140 : 0 : rte_atomic_fetch_add_explicit(task.err_cnt, 1,
141 : : rte_memory_order_relaxed);
142 : : }
143 : : break;
144 : 0 : case MLX5_VDPA_TASK_SETUP_VIRTQ:
145 : 0 : virtq = &priv->virtqs[task.idx];
146 : 0 : pthread_mutex_lock(&virtq->virtq_lock);
147 : 0 : ret = mlx5_vdpa_virtq_setup(priv,
148 : : task.idx, false);
149 [ # # ]: 0 : if (ret) {
150 : 0 : DRV_LOG(ERR,
151 : : "Failed to setup virtq %d.", task.idx);
152 : 0 : rte_atomic_fetch_add_explicit(
153 : : task.err_cnt, 1, rte_memory_order_relaxed);
154 : : }
155 : 0 : virtq->enable = 1;
156 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
157 : 0 : break;
158 : 0 : case MLX5_VDPA_TASK_STOP_VIRTQ:
159 : 0 : virtq = &priv->virtqs[task.idx];
160 : 0 : pthread_mutex_lock(&virtq->virtq_lock);
161 : 0 : ret = mlx5_vdpa_virtq_stop(priv,
162 : : task.idx);
163 [ # # ]: 0 : if (ret) {
164 : 0 : DRV_LOG(ERR,
165 : : "Failed to stop virtq %d.",
166 : : task.idx);
167 : 0 : rte_atomic_fetch_add_explicit(
168 : : task.err_cnt, 1,
169 : : rte_memory_order_relaxed);
170 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
171 : 0 : break;
172 : : }
173 : 0 : ret = rte_vhost_get_negotiated_features(
174 : : priv->vid, &features);
175 [ # # ]: 0 : if (ret) {
176 : 0 : DRV_LOG(ERR,
177 : : "Failed to get negotiated features virtq %d.",
178 : : task.idx);
179 : 0 : rte_atomic_fetch_add_explicit(
180 : : task.err_cnt, 1,
181 : : rte_memory_order_relaxed);
182 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
183 : 0 : break;
184 : : }
185 [ # # ]: 0 : if (RTE_VHOST_NEED_LOG(features))
186 : 0 : rte_vhost_log_used_vring(
187 : : priv->vid, task.idx, 0,
188 : 0 : MLX5_VDPA_USED_RING_LEN(virtq->vq_size));
189 : 0 : pthread_mutex_unlock(&virtq->virtq_lock);
190 : 0 : break;
191 : 0 : case MLX5_VDPA_TASK_DEV_CLOSE_NOWAIT:
192 : 0 : pthread_mutex_lock(&priv->steer_update_lock);
193 : 0 : mlx5_vdpa_steer_unset(priv);
194 : 0 : pthread_mutex_unlock(&priv->steer_update_lock);
195 : 0 : mlx5_vdpa_virtqs_release(priv, false);
196 : 0 : mlx5_vdpa_drain_cq(priv);
197 [ # # ]: 0 : if (priv->lm_mr.addr)
198 : 0 : mlx5_os_wrapped_mkey_destroy(
199 : : &priv->lm_mr);
200 [ # # ]: 0 : if (!priv->connected)
201 : 0 : mlx5_vdpa_dev_cache_clean(priv);
202 : 0 : priv->vid = 0;
203 : 0 : rte_atomic_store_explicit(
204 : : &priv->dev_close_progress, 0,
205 : : rte_memory_order_relaxed);
206 : 0 : break;
207 : 0 : case MLX5_VDPA_TASK_PREPARE_VIRTQ:
208 : 0 : ret = mlx5_vdpa_virtq_single_resource_prepare(
209 : 0 : priv, task.idx);
210 [ # # ]: 0 : if (ret) {
211 : 0 : DRV_LOG(ERR,
212 : : "Failed to prepare virtq %d.",
213 : : task.idx);
214 : 0 : rte_atomic_fetch_add_explicit(
215 : : task.err_cnt, 1,
216 : : rte_memory_order_relaxed);
217 : : }
218 : : break;
219 : 0 : default:
220 : 0 : DRV_LOG(ERR, "Invalid vdpa task type %d.",
221 : : task.type);
222 : 0 : break;
223 : : }
224 [ # # ]: 0 : if (task.remaining_cnt)
225 : 0 : rte_atomic_fetch_sub_explicit(task.remaining_cnt,
226 : : 1, rte_memory_order_relaxed);
227 : : }
228 : : return 0;
229 : : }
230 : :
231 : : static void
232 : 0 : mlx5_vdpa_c_thread_destroy(uint32_t thrd_idx, bool need_unlock)
233 : : {
234 : : pthread_t *tid = (pthread_t *)&conf_thread_mng.cthrd[thrd_idx].tid.opaque_id;
235 [ # # ]: 0 : if (*tid != 0) {
236 : 0 : pthread_cancel(*tid);
237 : 0 : rte_thread_join(conf_thread_mng.cthrd[thrd_idx].tid, NULL);
238 : 0 : *tid = 0;
239 [ # # ]: 0 : if (need_unlock)
240 : 0 : pthread_mutex_init(&conf_thread_mng.cthrd_lock, NULL);
241 : : }
242 [ # # ]: 0 : if (conf_thread_mng.cthrd[thrd_idx].rng) {
243 : 0 : rte_ring_free(conf_thread_mng.cthrd[thrd_idx].rng);
244 : 0 : conf_thread_mng.cthrd[thrd_idx].rng = NULL;
245 : : }
246 : 0 : }
247 : :
248 : : static int
249 : 0 : mlx5_vdpa_c_thread_create(void)
250 : : {
251 : : uint32_t thrd_idx;
252 : : uint32_t ring_num;
253 : : char name[RTE_RING_NAMESIZE];
254 : : int ret;
255 : :
256 : 0 : pthread_mutex_lock(&conf_thread_mng.cthrd_lock);
257 : 0 : ring_num = MLX5_VDPA_MAX_TASKS_PER_THRD / conf_thread_mng.max_thrds;
258 [ # # ]: 0 : if (!ring_num) {
259 : 0 : DRV_LOG(ERR, "Invalid ring number for thread.");
260 : 0 : goto c_thread_err;
261 : : }
262 [ # # ]: 0 : for (thrd_idx = 0; thrd_idx < conf_thread_mng.max_thrds;
263 : 0 : thrd_idx++) {
264 : : snprintf(name, sizeof(name), "vDPA-mthread-ring-%d",
265 : : thrd_idx);
266 : 0 : conf_thread_mng.cthrd[thrd_idx].rng = rte_ring_create_elem(name,
267 : : sizeof(struct mlx5_vdpa_task), ring_num,
268 : 0 : rte_socket_id(),
269 : : RING_F_MP_HTS_ENQ | RING_F_MC_HTS_DEQ |
270 : : RING_F_EXACT_SZ);
271 [ # # ]: 0 : if (!conf_thread_mng.cthrd[thrd_idx].rng) {
272 : 0 : DRV_LOG(ERR,
273 : : "Failed to create vdpa multi-threads %d ring.",
274 : : thrd_idx);
275 : 0 : goto c_thread_err;
276 : : }
277 : : snprintf(name, RTE_THREAD_INTERNAL_NAME_SIZE, "vmlx5-c%d", thrd_idx);
278 : 0 : ret = rte_thread_create_internal_control(&conf_thread_mng.cthrd[thrd_idx].tid,
279 : : name,
280 : : mlx5_vdpa_c_thread_handle, &conf_thread_mng);
281 [ # # ]: 0 : if (ret) {
282 : 0 : DRV_LOG(ERR, "Failed to create vdpa multi-threads %d.",
283 : : thrd_idx);
284 : 0 : goto c_thread_err;
285 : : }
286 : 0 : pthread_cond_init(&conf_thread_mng.cthrd[thrd_idx].c_cond,
287 : : NULL);
288 : : }
289 : 0 : pthread_mutex_unlock(&conf_thread_mng.cthrd_lock);
290 : 0 : return 0;
291 : : c_thread_err:
292 [ # # ]: 0 : for (thrd_idx = 0; thrd_idx < conf_thread_mng.max_thrds;
293 : 0 : thrd_idx++)
294 : 0 : mlx5_vdpa_c_thread_destroy(thrd_idx, false);
295 : 0 : pthread_mutex_unlock(&conf_thread_mng.cthrd_lock);
296 : 0 : return -1;
297 : : }
298 : :
299 : : int
300 : 0 : mlx5_vdpa_mult_threads_create(void)
301 : : {
302 : 0 : pthread_mutex_init(&conf_thread_mng.cthrd_lock, NULL);
303 [ # # ]: 0 : if (mlx5_vdpa_c_thread_create()) {
304 : 0 : DRV_LOG(ERR, "Cannot create vDPA configuration threads.");
305 : 0 : mlx5_vdpa_mult_threads_destroy(false);
306 : 0 : return -1;
307 : : }
308 : : return 0;
309 : : }
310 : :
311 : : void
312 : 0 : mlx5_vdpa_mult_threads_destroy(bool need_unlock)
313 : : {
314 : : uint32_t thrd_idx;
315 : :
316 [ # # ]: 0 : if (!conf_thread_mng.initializer_priv)
317 : : return;
318 [ # # ]: 0 : for (thrd_idx = 0; thrd_idx < conf_thread_mng.max_thrds;
319 : 0 : thrd_idx++)
320 : 0 : mlx5_vdpa_c_thread_destroy(thrd_idx, need_unlock);
321 : 0 : pthread_mutex_destroy(&conf_thread_mng.cthrd_lock);
322 : : memset(&conf_thread_mng, 0, sizeof(struct mlx5_vdpa_conf_thread_mng));
323 : : }
|