Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2020-2021 Xilinx, Inc.
3 : : */
4 : :
5 : : #include <uapi/linux/vfio.h>
6 : :
7 : : #include <pthread.h>
8 : : #include <unistd.h>
9 : : #include <sys/ioctl.h>
10 : :
11 : : #include <rte_errno.h>
12 : : #include <rte_malloc.h>
13 : : #include <rte_vdpa.h>
14 : : #include <rte_vhost.h>
15 : :
16 : : #include <vdpa_driver.h>
17 : :
18 : : #include "efx.h"
19 : : #include "sfc_vdpa_ops.h"
20 : : #include "sfc_vdpa.h"
21 : :
22 : : /* These protocol features are needed to enable notifier ctrl */
23 : : #define SFC_VDPA_PROTOCOL_FEATURES \
24 : : ((1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK) | \
25 : : (1ULL << VHOST_USER_PROTOCOL_F_BACKEND_REQ) | \
26 : : (1ULL << VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD) | \
27 : : (1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER) | \
28 : : (1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD) | \
29 : : (1ULL << VHOST_USER_PROTOCOL_F_MQ))
30 : :
31 : : /*
32 : : * Set of features which are enabled by default.
33 : : * Protocol feature bit is needed to enable notification notifier ctrl.
34 : : */
35 : : #define SFC_VDPA_DEFAULT_FEATURES \
36 : : ((1ULL << VHOST_USER_F_PROTOCOL_FEATURES) | \
37 : : (1ULL << VIRTIO_NET_F_MQ))
38 : :
39 : : #define SFC_VDPA_MSIX_IRQ_SET_BUF_LEN \
40 : : (sizeof(struct vfio_irq_set) + \
41 : : sizeof(int) * (SFC_VDPA_MAX_QUEUE_PAIRS * 2 + 1))
42 : :
43 : : /* It will be used for target VF when calling function is not PF */
44 : : #define SFC_VDPA_VF_NULL 0xFFFF
45 : :
46 : : static int
47 : 0 : sfc_vdpa_get_device_features(struct sfc_vdpa_ops_data *ops_data)
48 : : {
49 : : int rc;
50 : : uint64_t dev_features;
51 : : efx_nic_t *nic;
52 : :
53 : 0 : nic = sfc_vdpa_adapter_by_dev_handle(ops_data->dev_handle)->nic;
54 : :
55 : 0 : rc = efx_virtio_get_features(nic, EFX_VIRTIO_DEVICE_TYPE_NET,
56 : : &dev_features);
57 [ # # ]: 0 : if (rc != 0) {
58 : 0 : sfc_vdpa_err(ops_data->dev_handle,
59 : : "could not read device feature: %s",
60 : : rte_strerror(rc));
61 : 0 : return rc;
62 : : }
63 : :
64 : 0 : ops_data->dev_features = dev_features;
65 : :
66 : 0 : sfc_vdpa_info(ops_data->dev_handle,
67 : : "device supported virtio features : 0x%" PRIx64,
68 : : ops_data->dev_features);
69 : :
70 : 0 : return 0;
71 : : }
72 : :
73 : : static uint64_t
74 : 0 : hva_to_gpa(int vid, uint64_t hva)
75 : : {
76 : 0 : struct rte_vhost_memory *vhost_mem = NULL;
77 : : struct rte_vhost_mem_region *mem_reg = NULL;
78 : : uint32_t i;
79 : : uint64_t gpa = 0;
80 : :
81 [ # # ]: 0 : if (rte_vhost_get_mem_table(vid, &vhost_mem) < 0)
82 : 0 : goto error;
83 : :
84 [ # # ]: 0 : for (i = 0; i < vhost_mem->nregions; i++) {
85 : : mem_reg = &vhost_mem->regions[i];
86 : :
87 [ # # ]: 0 : if (hva >= mem_reg->host_user_addr &&
88 [ # # ]: 0 : hva < mem_reg->host_user_addr + mem_reg->size) {
89 : 0 : gpa = (hva - mem_reg->host_user_addr) +
90 : 0 : mem_reg->guest_phys_addr;
91 : 0 : break;
92 : : }
93 : : }
94 : :
95 : 0 : error:
96 : 0 : free(vhost_mem);
97 : 0 : return gpa;
98 : : }
99 : :
100 : : static int
101 : 0 : sfc_vdpa_enable_vfio_intr(struct sfc_vdpa_ops_data *ops_data)
102 : : {
103 : : int rc;
104 : : int *irq_fd_ptr;
105 : : int vfio_dev_fd;
106 : : uint32_t i, num_vring;
107 : : struct rte_vhost_vring vring;
108 : : struct vfio_irq_set *irq_set;
109 : : struct rte_pci_device *pci_dev;
110 : : char irq_set_buf[SFC_VDPA_MSIX_IRQ_SET_BUF_LEN];
111 : : void *dev;
112 : :
113 : 0 : num_vring = rte_vhost_get_vring_num(ops_data->vid);
114 : 0 : dev = ops_data->dev_handle;
115 : 0 : vfio_dev_fd = sfc_vdpa_adapter_by_dev_handle(dev)->vfio_dev_fd;
116 : 0 : pci_dev = sfc_vdpa_adapter_by_dev_handle(dev)->pdev;
117 : :
118 : : irq_set = (struct vfio_irq_set *)irq_set_buf;
119 : 0 : irq_set->argsz = sizeof(irq_set_buf);
120 : 0 : irq_set->count = num_vring + 1;
121 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
122 : : VFIO_IRQ_SET_ACTION_TRIGGER;
123 : 0 : irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
124 : 0 : irq_set->start = 0;
125 : : irq_fd_ptr = (int *)&irq_set->data;
126 : 0 : irq_fd_ptr[RTE_INTR_VEC_ZERO_OFFSET] =
127 : 0 : rte_intr_fd_get(pci_dev->intr_handle);
128 : :
129 [ # # ]: 0 : for (i = 0; i < num_vring; i++) {
130 : 0 : rc = rte_vhost_get_vhost_vring(ops_data->vid, i, &vring);
131 [ # # ]: 0 : if (rc)
132 : : return -1;
133 : :
134 : 0 : irq_fd_ptr[RTE_INTR_VEC_RXTX_OFFSET + i] = vring.callfd;
135 : : }
136 : :
137 : 0 : rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
138 [ # # ]: 0 : if (rc) {
139 : 0 : sfc_vdpa_err(ops_data->dev_handle,
140 : : "error enabling MSI-X interrupts: %s",
141 : : strerror(errno));
142 : 0 : return -1;
143 : : }
144 : :
145 : : return 0;
146 : : }
147 : :
148 : : static int
149 : 0 : sfc_vdpa_disable_vfio_intr(struct sfc_vdpa_ops_data *ops_data)
150 : : {
151 : : int rc;
152 : : int vfio_dev_fd;
153 : : struct vfio_irq_set irq_set;
154 : : void *dev;
155 : :
156 : 0 : dev = ops_data->dev_handle;
157 : 0 : vfio_dev_fd = sfc_vdpa_adapter_by_dev_handle(dev)->vfio_dev_fd;
158 : :
159 : 0 : irq_set.argsz = sizeof(irq_set);
160 : 0 : irq_set.count = 0;
161 : 0 : irq_set.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
162 : 0 : irq_set.index = VFIO_PCI_MSIX_IRQ_INDEX;
163 : 0 : irq_set.start = 0;
164 : :
165 : 0 : rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, &irq_set);
166 [ # # ]: 0 : if (rc) {
167 : 0 : sfc_vdpa_err(ops_data->dev_handle,
168 : : "error disabling MSI-X interrupts: %s",
169 : : strerror(errno));
170 : 0 : return -1;
171 : : }
172 : :
173 : : return 0;
174 : : }
175 : :
176 : : static int
177 : 0 : sfc_vdpa_get_vring_info(struct sfc_vdpa_ops_data *ops_data,
178 : : int vq_num, struct sfc_vdpa_vring_info *vring)
179 : : {
180 : : int rc;
181 : : uint64_t gpa;
182 : : struct rte_vhost_vring vq;
183 : :
184 : 0 : rc = rte_vhost_get_vhost_vring(ops_data->vid, vq_num, &vq);
185 [ # # ]: 0 : if (rc < 0) {
186 : 0 : sfc_vdpa_err(ops_data->dev_handle,
187 : : "get vhost vring failed: %s", rte_strerror(rc));
188 : 0 : return rc;
189 : : }
190 : :
191 : 0 : gpa = hva_to_gpa(ops_data->vid, (uint64_t)(uintptr_t)vq.desc);
192 [ # # ]: 0 : if (gpa == 0) {
193 : 0 : sfc_vdpa_err(ops_data->dev_handle,
194 : : "fail to get GPA for descriptor ring.");
195 : 0 : return -1;
196 : : }
197 : 0 : vring->desc = gpa;
198 : :
199 : 0 : gpa = hva_to_gpa(ops_data->vid, (uint64_t)(uintptr_t)vq.avail);
200 [ # # ]: 0 : if (gpa == 0) {
201 : 0 : sfc_vdpa_err(ops_data->dev_handle,
202 : : "fail to get GPA for available ring.");
203 : 0 : return -1;
204 : : }
205 : 0 : vring->avail = gpa;
206 : :
207 : 0 : gpa = hva_to_gpa(ops_data->vid, (uint64_t)(uintptr_t)vq.used);
208 [ # # ]: 0 : if (gpa == 0) {
209 : 0 : sfc_vdpa_err(ops_data->dev_handle,
210 : : "fail to get GPA for used ring.");
211 : 0 : return -1;
212 : : }
213 : 0 : vring->used = gpa;
214 : :
215 : 0 : vring->size = vq.size;
216 : :
217 : 0 : rc = rte_vhost_get_vring_base(ops_data->vid, vq_num,
218 : : &vring->last_avail_idx,
219 : : &vring->last_used_idx);
220 : :
221 : 0 : return rc;
222 : : }
223 : :
224 : : static int
225 : 0 : sfc_vdpa_virtq_start(struct sfc_vdpa_ops_data *ops_data, int vq_num)
226 : : {
227 : : int rc;
228 : : uint32_t doorbell;
229 : : efx_virtio_vq_t *vq;
230 : : struct sfc_vdpa_vring_info vring;
231 : : efx_virtio_vq_cfg_t vq_cfg;
232 : : efx_virtio_vq_dyncfg_t vq_dyncfg;
233 : :
234 : 0 : vq = ops_data->vq_cxt[vq_num].vq;
235 [ # # ]: 0 : if (vq == NULL)
236 : : return -1;
237 : :
238 : 0 : rc = sfc_vdpa_get_vring_info(ops_data, vq_num, &vring);
239 [ # # ]: 0 : if (rc < 0) {
240 : 0 : sfc_vdpa_err(ops_data->dev_handle,
241 : : "get vring info failed: %s", rte_strerror(rc));
242 : 0 : goto fail_vring_info;
243 : : }
244 : :
245 : 0 : vq_cfg.evvc_target_vf = SFC_VDPA_VF_NULL;
246 : :
247 : : /* even virtqueue for RX and odd for TX */
248 [ # # ]: 0 : if (vq_num % 2) {
249 : 0 : vq_cfg.evvc_type = EFX_VIRTIO_VQ_TYPE_NET_TXQ;
250 : 0 : sfc_vdpa_info(ops_data->dev_handle,
251 : : "configure virtqueue # %d (TXQ)", vq_num);
252 : : } else {
253 : 0 : vq_cfg.evvc_type = EFX_VIRTIO_VQ_TYPE_NET_RXQ;
254 : 0 : sfc_vdpa_info(ops_data->dev_handle,
255 : : "configure virtqueue # %d (RXQ)", vq_num);
256 : : }
257 : :
258 : 0 : vq_cfg.evvc_vq_num = vq_num;
259 : 0 : vq_cfg.evvc_desc_tbl_addr = vring.desc;
260 : 0 : vq_cfg.evvc_avail_ring_addr = vring.avail;
261 : 0 : vq_cfg.evvc_used_ring_addr = vring.used;
262 : 0 : vq_cfg.evvc_vq_size = vring.size;
263 : :
264 : 0 : vq_dyncfg.evvd_vq_used_idx = vring.last_used_idx;
265 : 0 : vq_dyncfg.evvd_vq_avail_idx = vring.last_avail_idx;
266 : :
267 : : /* MSI-X vector is function-relative */
268 : 0 : vq_cfg.evvc_msix_vector = RTE_INTR_VEC_RXTX_OFFSET + vq_num;
269 [ # # ]: 0 : if (ops_data->vdpa_context == SFC_VDPA_AS_VF)
270 : 0 : vq_cfg.evvc_pas_id = 0;
271 : 0 : vq_cfg.evcc_features = ops_data->dev_features &
272 : 0 : ops_data->req_features;
273 : :
274 : : /* Start virtqueue */
275 : 0 : rc = efx_virtio_qstart(vq, &vq_cfg, &vq_dyncfg);
276 [ # # ]: 0 : if (rc != 0) {
277 : 0 : sfc_vdpa_err(ops_data->dev_handle,
278 : : "virtqueue start failed: %s",
279 : : rte_strerror(rc));
280 : 0 : goto fail_virtio_qstart;
281 : : }
282 : :
283 : 0 : sfc_vdpa_info(ops_data->dev_handle,
284 : : "virtqueue started successfully for vq_num %d", vq_num);
285 : :
286 : 0 : rc = efx_virtio_get_doorbell_offset(vq, &doorbell);
287 [ # # ]: 0 : if (rc != 0) {
288 : 0 : sfc_vdpa_err(ops_data->dev_handle,
289 : : "failed to get doorbell offset: %s",
290 : : rte_strerror(rc));
291 : 0 : goto fail_doorbell;
292 : : }
293 : :
294 : : /*
295 : : * Cache the bar_offset here for each VQ here, it will come
296 : : * in handy when sfc_vdpa_get_notify_area() is invoked.
297 : : */
298 : 0 : ops_data->vq_cxt[vq_num].doorbell = (void *)(uintptr_t)doorbell;
299 : 0 : ops_data->vq_cxt[vq_num].enable = B_TRUE;
300 : :
301 : 0 : return rc;
302 : :
303 : : fail_doorbell:
304 : 0 : fail_virtio_qstart:
305 : 0 : efx_virtio_qdestroy(vq);
306 : : fail_vring_info:
307 : : return rc;
308 : : }
309 : :
310 : : static int
311 : 0 : sfc_vdpa_virtq_stop(struct sfc_vdpa_ops_data *ops_data, int vq_num)
312 : : {
313 : : int rc;
314 : : efx_virtio_vq_dyncfg_t vq_idx;
315 : : efx_virtio_vq_t *vq;
316 : :
317 [ # # ]: 0 : if (ops_data->vq_cxt[vq_num].enable != B_TRUE)
318 : : return -1;
319 : :
320 : 0 : vq = ops_data->vq_cxt[vq_num].vq;
321 [ # # ]: 0 : if (vq == NULL)
322 : : return -1;
323 : :
324 : : /* stop the vq */
325 : 0 : rc = efx_virtio_qstop(vq, &vq_idx);
326 [ # # ]: 0 : if (rc == 0) {
327 : 0 : ops_data->vq_cxt[vq_num].cidx = vq_idx.evvd_vq_used_idx;
328 : 0 : ops_data->vq_cxt[vq_num].pidx = vq_idx.evvd_vq_avail_idx;
329 : : }
330 : 0 : ops_data->vq_cxt[vq_num].enable = B_FALSE;
331 : :
332 : 0 : return rc;
333 : : }
334 : :
335 : : static int
336 : 0 : sfc_vdpa_configure(struct sfc_vdpa_ops_data *ops_data)
337 : : {
338 : : int rc, i;
339 : : int nr_vring;
340 : : int max_vring_cnt;
341 : : efx_virtio_vq_t *vq;
342 : : efx_nic_t *nic;
343 : : void *dev;
344 : :
345 : 0 : dev = ops_data->dev_handle;
346 : 0 : nic = sfc_vdpa_adapter_by_dev_handle(dev)->nic;
347 : :
348 [ # # ]: 0 : SFC_EFX_ASSERT(ops_data->state == SFC_VDPA_STATE_INITIALIZED);
349 : :
350 : 0 : ops_data->state = SFC_VDPA_STATE_CONFIGURING;
351 : :
352 : 0 : nr_vring = rte_vhost_get_vring_num(ops_data->vid);
353 : 0 : max_vring_cnt =
354 : 0 : (sfc_vdpa_adapter_by_dev_handle(dev)->max_queue_count * 2);
355 : :
356 : : /* number of vring should not be more than supported max vq count */
357 [ # # ]: 0 : if (nr_vring > max_vring_cnt) {
358 : 0 : sfc_vdpa_err(dev,
359 : : "nr_vring (%d) is > max vring count (%d)",
360 : : nr_vring, max_vring_cnt);
361 : 0 : goto fail_vring_num;
362 : : }
363 : :
364 : 0 : rc = sfc_vdpa_dma_map(ops_data, true);
365 [ # # ]: 0 : if (rc) {
366 : 0 : sfc_vdpa_err(dev,
367 : : "DMA map failed: %s", rte_strerror(rc));
368 : 0 : goto fail_dma_map;
369 : : }
370 : :
371 [ # # ]: 0 : for (i = 0; i < nr_vring; i++) {
372 : 0 : rc = efx_virtio_qcreate(nic, &vq);
373 [ # # # # ]: 0 : if ((rc != 0) || (vq == NULL)) {
374 : 0 : sfc_vdpa_err(dev,
375 : : "virtqueue create failed: %s",
376 : : rte_strerror(rc));
377 : 0 : goto fail_vq_create;
378 : : }
379 : :
380 : : /* store created virtqueue context */
381 : 0 : ops_data->vq_cxt[i].vq = vq;
382 : : }
383 : :
384 : 0 : ops_data->vq_count = i;
385 : :
386 : 0 : ops_data->state = SFC_VDPA_STATE_CONFIGURED;
387 : :
388 : 0 : return 0;
389 : :
390 : : fail_vq_create:
391 : 0 : sfc_vdpa_dma_map(ops_data, false);
392 : :
393 : 0 : fail_dma_map:
394 : 0 : fail_vring_num:
395 : 0 : ops_data->state = SFC_VDPA_STATE_INITIALIZED;
396 : :
397 : 0 : return -1;
398 : : }
399 : :
400 : : static void
401 : 0 : sfc_vdpa_close(struct sfc_vdpa_ops_data *ops_data)
402 : : {
403 : : int i;
404 : :
405 [ # # ]: 0 : if (ops_data->state != SFC_VDPA_STATE_CONFIGURED)
406 : : return;
407 : :
408 : 0 : ops_data->state = SFC_VDPA_STATE_CLOSING;
409 : :
410 [ # # ]: 0 : for (i = 0; i < ops_data->vq_count; i++) {
411 [ # # ]: 0 : if (ops_data->vq_cxt[i].vq == NULL)
412 : 0 : continue;
413 : :
414 : 0 : efx_virtio_qdestroy(ops_data->vq_cxt[i].vq);
415 : : }
416 : :
417 : 0 : sfc_vdpa_dma_map(ops_data, false);
418 : :
419 : 0 : ops_data->state = SFC_VDPA_STATE_INITIALIZED;
420 : : }
421 : :
422 : : static void
423 : 0 : sfc_vdpa_stop(struct sfc_vdpa_ops_data *ops_data)
424 : : {
425 : : int i;
426 : : int rc;
427 : :
428 [ # # ]: 0 : if (ops_data->state != SFC_VDPA_STATE_STARTED)
429 : : return;
430 : :
431 : 0 : ops_data->state = SFC_VDPA_STATE_STOPPING;
432 : :
433 [ # # ]: 0 : for (i = 0; i < ops_data->vq_count; i++) {
434 : 0 : rc = sfc_vdpa_virtq_stop(ops_data, i);
435 : : if (rc != 0)
436 : : continue;
437 : : }
438 : :
439 : 0 : sfc_vdpa_disable_vfio_intr(ops_data);
440 : :
441 : 0 : sfc_vdpa_filter_remove(ops_data);
442 : :
443 : 0 : ops_data->state = SFC_VDPA_STATE_CONFIGURED;
444 : : }
445 : :
446 : : static int
447 : 0 : sfc_vdpa_start(struct sfc_vdpa_ops_data *ops_data)
448 : : {
449 : : int i, j;
450 : : int rc;
451 : :
452 [ # # ]: 0 : SFC_EFX_ASSERT(ops_data->state == SFC_VDPA_STATE_CONFIGURED);
453 : :
454 : 0 : sfc_vdpa_log_init(ops_data->dev_handle, "entry");
455 : :
456 : 0 : ops_data->state = SFC_VDPA_STATE_STARTING;
457 : :
458 : 0 : sfc_vdpa_log_init(ops_data->dev_handle, "enable interrupts");
459 : 0 : rc = sfc_vdpa_enable_vfio_intr(ops_data);
460 [ # # ]: 0 : if (rc < 0) {
461 : 0 : sfc_vdpa_err(ops_data->dev_handle,
462 : : "vfio intr allocation failed: %s",
463 : : rte_strerror(rc));
464 : 0 : goto fail_enable_vfio_intr;
465 : : }
466 : :
467 : 0 : rte_vhost_get_negotiated_features(ops_data->vid,
468 : : &ops_data->req_features);
469 : :
470 : 0 : sfc_vdpa_info(ops_data->dev_handle,
471 : : "negotiated feature : 0x%" PRIx64,
472 : : ops_data->req_features);
473 : :
474 [ # # ]: 0 : for (i = 0; i < ops_data->vq_count; i++) {
475 : 0 : sfc_vdpa_log_init(ops_data->dev_handle,
476 : : "starting vq# %d", i);
477 : 0 : rc = sfc_vdpa_virtq_start(ops_data, i);
478 [ # # ]: 0 : if (rc != 0)
479 : 0 : goto fail_vq_start;
480 : : }
481 : :
482 : 0 : ops_data->vq_count = i;
483 : :
484 : 0 : sfc_vdpa_log_init(ops_data->dev_handle,
485 : : "configure MAC filters");
486 : 0 : rc = sfc_vdpa_filter_config(ops_data);
487 [ # # ]: 0 : if (rc != 0) {
488 : 0 : sfc_vdpa_err(ops_data->dev_handle,
489 : : "MAC filter config failed: %s",
490 : : rte_strerror(rc));
491 : 0 : goto fail_filter_cfg;
492 : : }
493 : :
494 : 0 : ops_data->state = SFC_VDPA_STATE_STARTED;
495 : :
496 : 0 : sfc_vdpa_log_init(ops_data->dev_handle, "done");
497 : :
498 : 0 : return 0;
499 : :
500 : : fail_filter_cfg:
501 : : /* remove already created filters */
502 : 0 : sfc_vdpa_filter_remove(ops_data);
503 : 0 : fail_vq_start:
504 : : /* stop already started virtqueues */
505 [ # # ]: 0 : for (j = 0; j < i; j++)
506 : 0 : sfc_vdpa_virtq_stop(ops_data, j);
507 : 0 : sfc_vdpa_disable_vfio_intr(ops_data);
508 : :
509 : 0 : fail_enable_vfio_intr:
510 : 0 : ops_data->state = SFC_VDPA_STATE_CONFIGURED;
511 : :
512 : 0 : return rc;
513 : : }
514 : :
515 : : static int
516 : 0 : sfc_vdpa_get_queue_num(struct rte_vdpa_device *vdpa_dev, uint32_t *queue_num)
517 : : {
518 : : struct sfc_vdpa_ops_data *ops_data;
519 : : void *dev;
520 : :
521 : 0 : ops_data = sfc_vdpa_get_data_by_dev(vdpa_dev);
522 [ # # ]: 0 : if (ops_data == NULL)
523 : : return -1;
524 : :
525 : 0 : dev = ops_data->dev_handle;
526 : 0 : *queue_num = sfc_vdpa_adapter_by_dev_handle(dev)->max_queue_count;
527 : :
528 : 0 : sfc_vdpa_info(dev, "vDPA ops get_queue_num :: supported queue num : %u",
529 : : *queue_num);
530 : :
531 : 0 : return 0;
532 : : }
533 : :
534 : : static int
535 : 0 : sfc_vdpa_get_features(struct rte_vdpa_device *vdpa_dev, uint64_t *features)
536 : : {
537 : : struct sfc_vdpa_ops_data *ops_data;
538 : :
539 : 0 : ops_data = sfc_vdpa_get_data_by_dev(vdpa_dev);
540 [ # # ]: 0 : if (ops_data == NULL)
541 : : return -1;
542 : :
543 : 0 : *features = ops_data->drv_features;
544 : :
545 : 0 : sfc_vdpa_info(ops_data->dev_handle,
546 : : "vDPA ops get_feature :: features : 0x%" PRIx64,
547 : : *features);
548 : :
549 : 0 : return 0;
550 : : }
551 : :
552 : : static int
553 : 0 : sfc_vdpa_get_protocol_features(struct rte_vdpa_device *vdpa_dev,
554 : : uint64_t *features)
555 : : {
556 : : struct sfc_vdpa_ops_data *ops_data;
557 : :
558 : 0 : ops_data = sfc_vdpa_get_data_by_dev(vdpa_dev);
559 [ # # ]: 0 : if (ops_data == NULL)
560 : : return -1;
561 : :
562 : 0 : *features = SFC_VDPA_PROTOCOL_FEATURES;
563 : :
564 : 0 : sfc_vdpa_info(ops_data->dev_handle,
565 : : "vDPA ops get_protocol_feature :: features : 0x%" PRIx64,
566 : : *features);
567 : :
568 : 0 : return 0;
569 : : }
570 : :
571 : : static uint32_t
572 : 0 : sfc_vdpa_notify_ctrl(void *arg)
573 : : {
574 : : struct sfc_vdpa_ops_data *ops_data;
575 : : int vid;
576 : :
577 : : ops_data = arg;
578 [ # # ]: 0 : if (ops_data == NULL)
579 : : return 0;
580 : :
581 : 0 : sfc_vdpa_adapter_lock(sfc_vdpa_adapter_by_dev_handle(ops_data->dev_handle));
582 : :
583 : 0 : vid = ops_data->vid;
584 : :
585 [ # # ]: 0 : if (rte_vhost_host_notifier_ctrl(vid, RTE_VHOST_QUEUE_ALL, true) != 0)
586 : 0 : sfc_vdpa_info(ops_data->dev_handle,
587 : : "vDPA (%s): Notifier could not get configured",
588 : : ops_data->vdpa_dev->device->name);
589 : :
590 : 0 : sfc_vdpa_adapter_unlock(sfc_vdpa_adapter_by_dev_handle(ops_data->dev_handle));
591 : :
592 : 0 : return 0;
593 : : }
594 : :
595 : : static int
596 : 0 : sfc_vdpa_setup_notify_ctrl(struct sfc_vdpa_ops_data *ops_data)
597 : : {
598 : : int ret;
599 : :
600 : 0 : ops_data->is_notify_thread_started = false;
601 : :
602 : : /*
603 : : * Use rte_vhost_host_notifier_ctrl in a thread to avoid
604 : : * dead lock scenario when multiple VFs are used in single vdpa
605 : : * application and multiple VFs are passed to a single VM.
606 : : */
607 : 0 : ret = rte_thread_create_internal_control(&ops_data->notify_tid,
608 : : "sfc-vdpa", sfc_vdpa_notify_ctrl, ops_data);
609 [ # # ]: 0 : if (ret != 0) {
610 : 0 : sfc_vdpa_err(ops_data->dev_handle,
611 : : "failed to create notify_ctrl thread: %s",
612 : : rte_strerror(ret));
613 : 0 : return -1;
614 : : }
615 : 0 : ops_data->is_notify_thread_started = true;
616 : :
617 : 0 : return 0;
618 : : }
619 : :
620 : : static int
621 : 0 : sfc_vdpa_dev_config(int vid)
622 : : {
623 : : struct rte_vdpa_device *vdpa_dev;
624 : : int rc;
625 : : struct sfc_vdpa_ops_data *ops_data;
626 : :
627 : 0 : vdpa_dev = rte_vhost_get_vdpa_device(vid);
628 : :
629 : 0 : ops_data = sfc_vdpa_get_data_by_dev(vdpa_dev);
630 [ # # ]: 0 : if (ops_data == NULL) {
631 : 0 : SFC_VDPA_GENERIC_LOG(ERR,
632 : : "invalid vDPA device : %p, vid : %d",
633 : : vdpa_dev, vid);
634 : 0 : return -1;
635 : : }
636 : :
637 : 0 : sfc_vdpa_log_init(ops_data->dev_handle, "entry");
638 : :
639 : 0 : ops_data->vid = vid;
640 : :
641 : 0 : sfc_vdpa_adapter_lock(sfc_vdpa_adapter_by_dev_handle(ops_data->dev_handle));
642 : :
643 : 0 : sfc_vdpa_log_init(ops_data->dev_handle, "configuring");
644 : 0 : rc = sfc_vdpa_configure(ops_data);
645 [ # # ]: 0 : if (rc != 0)
646 : 0 : goto fail_vdpa_config;
647 : :
648 : 0 : sfc_vdpa_log_init(ops_data->dev_handle, "starting");
649 : 0 : rc = sfc_vdpa_start(ops_data);
650 [ # # ]: 0 : if (rc != 0)
651 : 0 : goto fail_vdpa_start;
652 : :
653 : 0 : rc = sfc_vdpa_setup_notify_ctrl(ops_data);
654 [ # # ]: 0 : if (rc != 0)
655 : 0 : goto fail_vdpa_notify;
656 : :
657 : 0 : sfc_vdpa_adapter_unlock(sfc_vdpa_adapter_by_dev_handle(ops_data->dev_handle));
658 : :
659 : 0 : sfc_vdpa_log_init(ops_data->dev_handle, "done");
660 : :
661 : 0 : return 0;
662 : :
663 : : fail_vdpa_notify:
664 : 0 : sfc_vdpa_stop(ops_data);
665 : :
666 : 0 : fail_vdpa_start:
667 : 0 : sfc_vdpa_close(ops_data);
668 : :
669 : 0 : fail_vdpa_config:
670 : 0 : sfc_vdpa_adapter_unlock(sfc_vdpa_adapter_by_dev_handle(ops_data->dev_handle));
671 : :
672 : 0 : return -1;
673 : : }
674 : :
675 : : static int
676 : 0 : sfc_vdpa_dev_close(int vid)
677 : : {
678 : : int ret;
679 : : struct rte_vdpa_device *vdpa_dev;
680 : : struct sfc_vdpa_ops_data *ops_data;
681 : :
682 : 0 : vdpa_dev = rte_vhost_get_vdpa_device(vid);
683 : :
684 : 0 : ops_data = sfc_vdpa_get_data_by_dev(vdpa_dev);
685 [ # # ]: 0 : if (ops_data == NULL) {
686 : 0 : SFC_VDPA_GENERIC_LOG(ERR,
687 : : "invalid vDPA device : %p, vid : %d",
688 : : vdpa_dev, vid);
689 : 0 : return -1;
690 : : }
691 : :
692 : 0 : sfc_vdpa_adapter_lock(sfc_vdpa_adapter_by_dev_handle(ops_data->dev_handle));
693 [ # # ]: 0 : if (ops_data->is_notify_thread_started == true) {
694 : 0 : ret = pthread_cancel((pthread_t)ops_data->notify_tid.opaque_id);
695 [ # # ]: 0 : if (ret != 0) {
696 : 0 : sfc_vdpa_err(ops_data->dev_handle,
697 : : "failed to cancel notify_ctrl thread: %s",
698 : : rte_strerror(ret));
699 : : }
700 : :
701 : 0 : ret = rte_thread_join(ops_data->notify_tid, NULL);
702 [ # # ]: 0 : if (ret != 0) {
703 : 0 : sfc_vdpa_err(ops_data->dev_handle,
704 : : "failed to join terminated notify_ctrl thread: %s",
705 : : rte_strerror(ret));
706 : : }
707 : : }
708 : 0 : ops_data->is_notify_thread_started = false;
709 : :
710 : 0 : sfc_vdpa_stop(ops_data);
711 : 0 : sfc_vdpa_close(ops_data);
712 : :
713 : 0 : sfc_vdpa_adapter_unlock(sfc_vdpa_adapter_by_dev_handle(ops_data->dev_handle));
714 : :
715 : 0 : return 0;
716 : : }
717 : :
718 : : static int
719 : 0 : sfc_vdpa_set_vring_state(int vid, int vring, int state)
720 : : {
721 : : struct sfc_vdpa_ops_data *ops_data;
722 : : struct rte_vdpa_device *vdpa_dev;
723 : : efx_rc_t rc;
724 : : int vring_max;
725 : : void *dev;
726 : :
727 : 0 : vdpa_dev = rte_vhost_get_vdpa_device(vid);
728 : :
729 : 0 : ops_data = sfc_vdpa_get_data_by_dev(vdpa_dev);
730 [ # # ]: 0 : if (ops_data == NULL)
731 : : return -1;
732 : :
733 : 0 : dev = ops_data->dev_handle;
734 : :
735 : 0 : sfc_vdpa_info(dev,
736 : : "vDPA ops set_vring_state: vid: %d, vring: %d, state:%d",
737 : : vid, vring, state);
738 : :
739 : 0 : vring_max = (sfc_vdpa_adapter_by_dev_handle(dev)->max_queue_count * 2);
740 : :
741 [ # # ]: 0 : if (vring < 0 || vring > vring_max) {
742 : 0 : sfc_vdpa_err(dev, "received invalid vring id : %d to set state",
743 : : vring);
744 : 0 : return -1;
745 : : }
746 : :
747 : : /*
748 : : * Skip if device is not yet started. virtqueues state can be
749 : : * changed once it is created and other configurations are done.
750 : : */
751 [ # # ]: 0 : if (ops_data->state != SFC_VDPA_STATE_STARTED)
752 : : return 0;
753 : :
754 [ # # ]: 0 : if (ops_data->vq_cxt[vring].enable == state)
755 : : return 0;
756 : :
757 [ # # ]: 0 : if (state == 0) {
758 : 0 : rc = sfc_vdpa_virtq_stop(ops_data, vring);
759 [ # # ]: 0 : if (rc != 0) {
760 : 0 : sfc_vdpa_err(dev, "virtqueue stop failed: %s",
761 : : rte_strerror(rc));
762 : : }
763 : : } else {
764 : 0 : rc = sfc_vdpa_virtq_start(ops_data, vring);
765 [ # # ]: 0 : if (rc != 0) {
766 : 0 : sfc_vdpa_err(dev, "virtqueue start failed: %s",
767 : : rte_strerror(rc));
768 : : }
769 : : }
770 : :
771 : : return rc;
772 : : }
773 : :
774 : : static int
775 : 0 : sfc_vdpa_set_features(int vid)
776 : : {
777 : : RTE_SET_USED(vid);
778 : :
779 : 0 : return -1;
780 : : }
781 : :
782 : : static int
783 : 0 : sfc_vdpa_get_vfio_device_fd(int vid)
784 : : {
785 : : struct rte_vdpa_device *vdpa_dev;
786 : : struct sfc_vdpa_ops_data *ops_data;
787 : : int vfio_dev_fd;
788 : : void *dev;
789 : :
790 : 0 : vdpa_dev = rte_vhost_get_vdpa_device(vid);
791 : :
792 : 0 : ops_data = sfc_vdpa_get_data_by_dev(vdpa_dev);
793 [ # # ]: 0 : if (ops_data == NULL)
794 : : return -1;
795 : :
796 : 0 : dev = ops_data->dev_handle;
797 : 0 : vfio_dev_fd = sfc_vdpa_adapter_by_dev_handle(dev)->vfio_dev_fd;
798 : :
799 : 0 : sfc_vdpa_info(dev, "vDPA ops get_vfio_device_fd :: vfio fd : %d",
800 : : vfio_dev_fd);
801 : :
802 : 0 : return vfio_dev_fd;
803 : : }
804 : :
805 : : static int
806 : 0 : sfc_vdpa_get_notify_area(int vid, int qid, uint64_t *offset, uint64_t *size)
807 : : {
808 : : int ret;
809 : : efx_nic_t *nic;
810 : : int vfio_dev_fd;
811 : : volatile void *doorbell;
812 : : struct rte_pci_device *pci_dev;
813 : : struct rte_vdpa_device *vdpa_dev;
814 : : struct sfc_vdpa_ops_data *ops_data;
815 : 0 : struct vfio_region_info reg = { .argsz = sizeof(reg) };
816 : : const efx_nic_cfg_t *encp;
817 : : int max_vring_cnt;
818 : : int64_t len;
819 : : void *dev;
820 : :
821 : 0 : vdpa_dev = rte_vhost_get_vdpa_device(vid);
822 : :
823 : 0 : ops_data = sfc_vdpa_get_data_by_dev(vdpa_dev);
824 [ # # ]: 0 : if (ops_data == NULL)
825 : : return -1;
826 : :
827 : 0 : dev = ops_data->dev_handle;
828 : :
829 : 0 : vfio_dev_fd = sfc_vdpa_adapter_by_dev_handle(dev)->vfio_dev_fd;
830 : 0 : max_vring_cnt =
831 : 0 : (sfc_vdpa_adapter_by_dev_handle(dev)->max_queue_count * 2);
832 : :
833 : 0 : nic = sfc_vdpa_adapter_by_dev_handle(ops_data->dev_handle)->nic;
834 : 0 : encp = efx_nic_cfg_get(nic);
835 : :
836 [ # # ]: 0 : if (qid >= max_vring_cnt) {
837 : 0 : sfc_vdpa_err(dev, "invalid qid : %d", qid);
838 : 0 : return -1;
839 : : }
840 : :
841 : 0 : reg.index = sfc_vdpa_adapter_by_dev_handle(dev)->mem_bar.esb_rid;
842 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, ®);
843 [ # # ]: 0 : if (ret != 0) {
844 : 0 : sfc_vdpa_err(dev, "could not get device region info: %s",
845 : : strerror(errno));
846 : 0 : return ret;
847 : : }
848 : :
849 : : /* Use bar_offset that was cached during sfc_vdpa_virtq_start() */
850 : 0 : *offset = reg.offset + (uint64_t)ops_data->vq_cxt[qid].doorbell;
851 : :
852 : 0 : len = (1U << encp->enc_vi_window_shift) / 2;
853 [ # # ]: 0 : if (len >= sysconf(_SC_PAGESIZE)) {
854 : 0 : *size = sysconf(_SC_PAGESIZE);
855 : : } else {
856 : 0 : sfc_vdpa_err(dev, "invalid VI window size : 0x%" PRIx64, len);
857 : 0 : return -1;
858 : : }
859 : :
860 : 0 : sfc_vdpa_info(dev, "vDPA ops get_notify_area :: offset : 0x%" PRIx64,
861 : : *offset);
862 : :
863 : 0 : pci_dev = sfc_vdpa_adapter_by_dev_handle(dev)->pdev;
864 : 0 : doorbell = (uint8_t *)pci_dev->mem_resource[reg.index].addr + *offset;
865 : :
866 : : /*
867 : : * virtio-net driver in VM sends queue notifications before
868 : : * vDPA has a chance to setup the queues and notification area,
869 : : * and hence the HW misses these doorbell notifications.
870 : : * Since, it is safe to send duplicate doorbell, send another
871 : : * doorbell from vDPA driver as workaround for this timing issue.
872 : : */
873 : 0 : rte_write16(qid, doorbell);
874 : :
875 : 0 : return 0;
876 : : }
877 : :
878 : : static struct rte_vdpa_dev_ops sfc_vdpa_ops = {
879 : : .get_queue_num = sfc_vdpa_get_queue_num,
880 : : .get_features = sfc_vdpa_get_features,
881 : : .get_protocol_features = sfc_vdpa_get_protocol_features,
882 : : .dev_conf = sfc_vdpa_dev_config,
883 : : .dev_close = sfc_vdpa_dev_close,
884 : : .set_vring_state = sfc_vdpa_set_vring_state,
885 : : .set_features = sfc_vdpa_set_features,
886 : : .get_vfio_device_fd = sfc_vdpa_get_vfio_device_fd,
887 : : .get_notify_area = sfc_vdpa_get_notify_area,
888 : : };
889 : :
890 : : struct sfc_vdpa_ops_data *
891 : 0 : sfc_vdpa_device_init(void *dev_handle, enum sfc_vdpa_context context)
892 : : {
893 : : struct sfc_vdpa_ops_data *ops_data;
894 : : struct rte_pci_device *pci_dev;
895 : : int rc;
896 : :
897 : : /* Create vDPA ops context */
898 : 0 : ops_data = rte_zmalloc("vdpa", sizeof(struct sfc_vdpa_ops_data), 0);
899 [ # # ]: 0 : if (ops_data == NULL)
900 : : return NULL;
901 : :
902 : 0 : ops_data->vdpa_context = context;
903 : 0 : ops_data->dev_handle = dev_handle;
904 : :
905 : 0 : pci_dev = sfc_vdpa_adapter_by_dev_handle(dev_handle)->pdev;
906 : :
907 : : /* Register vDPA Device */
908 : 0 : sfc_vdpa_log_init(dev_handle, "register vDPA device");
909 : 0 : ops_data->vdpa_dev =
910 : 0 : rte_vdpa_register_device(&pci_dev->device, &sfc_vdpa_ops);
911 [ # # ]: 0 : if (ops_data->vdpa_dev == NULL) {
912 : 0 : sfc_vdpa_err(dev_handle, "vDPA device registration failed");
913 : 0 : goto fail_register_device;
914 : : }
915 : :
916 : : /* Read supported device features */
917 : 0 : sfc_vdpa_log_init(dev_handle, "get device feature");
918 : 0 : rc = sfc_vdpa_get_device_features(ops_data);
919 [ # # ]: 0 : if (rc != 0)
920 : 0 : goto fail_get_dev_feature;
921 : :
922 : : /* Driver features are superset of device supported feature
923 : : * and any additional features supported by the driver.
924 : : */
925 : 0 : ops_data->drv_features =
926 : 0 : ops_data->dev_features | SFC_VDPA_DEFAULT_FEATURES;
927 : :
928 : 0 : ops_data->state = SFC_VDPA_STATE_INITIALIZED;
929 : :
930 : 0 : return ops_data;
931 : :
932 : : fail_get_dev_feature:
933 : 0 : rte_vdpa_unregister_device(ops_data->vdpa_dev);
934 : :
935 : 0 : fail_register_device:
936 : 0 : rte_free(ops_data);
937 : 0 : return NULL;
938 : : }
939 : :
940 : : void
941 : 0 : sfc_vdpa_device_fini(struct sfc_vdpa_ops_data *ops_data)
942 : : {
943 : 0 : rte_vdpa_unregister_device(ops_data->vdpa_dev);
944 : :
945 : 0 : rte_free(ops_data);
946 : 0 : }
|