Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2020-2021 Xilinx, Inc.
3 : : */
4 : :
5 : : #include <unistd.h>
6 : :
7 : : #include <rte_common.h>
8 : : #include <rte_errno.h>
9 : : #include <rte_vfio.h>
10 : : #include <rte_vhost.h>
11 : :
12 : : #include "efx.h"
13 : : #include "sfc_vdpa.h"
14 : : #include "sfc_vdpa_ops.h"
15 : :
16 : : #ifndef PAGE_SIZE
17 : : #define PAGE_SIZE (sysconf(_SC_PAGESIZE))
18 : : #endif
19 : :
20 : : int
21 : 0 : sfc_vdpa_dma_alloc(struct sfc_vdpa_adapter *sva, const char *name,
22 : : size_t len, efsys_mem_t *esmp)
23 : : {
24 : : uint64_t mcdi_iova;
25 : : size_t mcdi_buff_size;
26 : : char mz_name[RTE_MEMZONE_NAMESIZE];
27 : : const struct rte_memzone *mz = NULL;
28 : 0 : int numa_node = sva->pdev->device.numa_node;
29 : : int ret;
30 : :
31 : 0 : mcdi_buff_size = RTE_ALIGN_CEIL(len, PAGE_SIZE);
32 : : ret = snprintf(mz_name, RTE_MEMZONE_NAMESIZE, "%s_%s",
33 [ # # ]: 0 : sva->pdev->name, name);
34 [ # # ]: 0 : if (ret < 0 || ret >= RTE_MEMZONE_NAMESIZE) {
35 : 0 : sfc_vdpa_err(sva, "%s_%s too long to fit in mz_name",
36 : : sva->pdev->name, name);
37 : 0 : return -EINVAL;
38 : : }
39 : :
40 : 0 : sfc_vdpa_log_init(sva, "name=%s, len=%zu", mz_name, len);
41 : :
42 : 0 : mz = rte_memzone_reserve_aligned(mz_name, mcdi_buff_size,
43 : : numa_node,
44 : : RTE_MEMZONE_IOVA_CONTIG,
45 : 0 : PAGE_SIZE);
46 [ # # ]: 0 : if (mz == NULL) {
47 : 0 : sfc_vdpa_err(sva, "cannot reserve memory for %s: len=%#x: %s",
48 : : mz_name, (unsigned int)len,
49 : : rte_strerror(rte_errno));
50 : 0 : return -ENOMEM;
51 : : }
52 : :
53 : : /* IOVA address for MCDI would be re-calculated if mapping
54 : : * using default IOVA would fail.
55 : : * TODO: Earlier there was no way to get valid IOVA range.
56 : : * Recently a patch has been submitted to get the IOVA range
57 : : * using ioctl. VFIO_IOMMU_GET_INFO. This patch is available
58 : : * in the kernel version >= 5.4. Support to get the default
59 : : * IOVA address for MCDI buffer using available IOVA range
60 : : * would be added later. Meanwhile default IOVA for MCDI buffer
61 : : * is kept at high mem at 2TB. In case of overlap new available
62 : : * addresses would be searched and same would be used.
63 : : */
64 : : mcdi_iova = SFC_VDPA_DEFAULT_MCDI_IOVA;
65 : :
66 : : for (;;) {
67 : 0 : ret = rte_vfio_container_dma_map(sva->vfio_container_fd,
68 : 0 : (uint64_t)mz->addr, mcdi_iova,
69 : : mcdi_buff_size);
70 [ # # ]: 0 : if (ret == 0)
71 : : break;
72 : :
73 : 0 : mcdi_iova = mcdi_iova >> 1;
74 [ # # ]: 0 : if (mcdi_iova < mcdi_buff_size) {
75 : 0 : sfc_vdpa_err(sva,
76 : : "DMA mapping failed for MCDI : %s",
77 : : rte_strerror(rte_errno));
78 : 0 : rte_memzone_free(mz);
79 : 0 : return ret;
80 : : }
81 : : }
82 : :
83 : 0 : esmp->esm_addr = mcdi_iova;
84 : 0 : esmp->esm_base = mz->addr;
85 : 0 : sva->mcdi_buff_size = mcdi_buff_size;
86 : :
87 : 0 : sfc_vdpa_info(sva,
88 : : "DMA name=%s len=%zu => virt=%p iova=0x%" PRIx64,
89 : : name, len, esmp->esm_base, esmp->esm_addr);
90 : :
91 : 0 : return 0;
92 : : }
93 : :
94 : : void
95 : 0 : sfc_vdpa_dma_free(struct sfc_vdpa_adapter *sva, efsys_mem_t *esmp)
96 : : {
97 : : int ret;
98 : :
99 : 0 : sfc_vdpa_log_init(sva, "name=%s", esmp->esm_mz->name);
100 : :
101 : 0 : ret = rte_vfio_container_dma_unmap(sva->vfio_container_fd,
102 : 0 : (uint64_t)esmp->esm_base,
103 : : esmp->esm_addr, sva->mcdi_buff_size);
104 [ # # ]: 0 : if (ret < 0)
105 : 0 : sfc_vdpa_err(sva, "DMA unmap failed for MCDI : %s",
106 : : rte_strerror(rte_errno));
107 : :
108 : 0 : sfc_vdpa_info(sva,
109 : : "DMA free name=%s => virt=%p iova=0x%" PRIx64,
110 : : esmp->esm_mz->name, esmp->esm_base, esmp->esm_addr);
111 : :
112 : 0 : rte_free((void *)(esmp->esm_base));
113 : :
114 : 0 : sva->mcdi_buff_size = 0;
115 : : memset(esmp, 0, sizeof(*esmp));
116 : 0 : }
117 : :
118 : : int
119 : 0 : sfc_vdpa_dma_map(struct sfc_vdpa_ops_data *ops_data, bool do_map)
120 : : {
121 : : uint32_t i, j;
122 : : int rc;
123 : 0 : struct rte_vhost_memory *vhost_mem = NULL;
124 : : struct rte_vhost_mem_region *mem_reg = NULL;
125 : : int vfio_container_fd;
126 : : void *dev;
127 : :
128 : 0 : dev = ops_data->dev_handle;
129 : 0 : vfio_container_fd =
130 : : sfc_vdpa_adapter_by_dev_handle(dev)->vfio_container_fd;
131 : :
132 : 0 : rc = rte_vhost_get_mem_table(ops_data->vid, &vhost_mem);
133 [ # # ]: 0 : if (rc < 0) {
134 : 0 : sfc_vdpa_err(dev,
135 : : "failed to get VM memory layout");
136 : 0 : goto error;
137 : : }
138 : :
139 [ # # ]: 0 : for (i = 0; i < vhost_mem->nregions; i++) {
140 : : mem_reg = &vhost_mem->regions[i];
141 : :
142 [ # # ]: 0 : if (do_map) {
143 : 0 : rc = rte_vfio_container_dma_map(vfio_container_fd,
144 : : mem_reg->host_user_addr,
145 : : mem_reg->guest_phys_addr,
146 : : mem_reg->size);
147 [ # # ]: 0 : if (rc < 0) {
148 : 0 : sfc_vdpa_err(dev,
149 : : "DMA map failed : %s",
150 : : rte_strerror(rte_errno));
151 : 0 : goto failed_vfio_dma_map;
152 : : }
153 : : } else {
154 : 0 : rc = rte_vfio_container_dma_unmap(vfio_container_fd,
155 : : mem_reg->host_user_addr,
156 : : mem_reg->guest_phys_addr,
157 : : mem_reg->size);
158 [ # # ]: 0 : if (rc < 0) {
159 : 0 : sfc_vdpa_err(dev,
160 : : "DMA unmap failed : %s",
161 : : rte_strerror(rte_errno));
162 : 0 : goto error;
163 : : }
164 : : }
165 : : }
166 : :
167 : 0 : free(vhost_mem);
168 : :
169 : 0 : return 0;
170 : :
171 : : failed_vfio_dma_map:
172 [ # # ]: 0 : for (j = 0; j < i; j++) {
173 : 0 : mem_reg = &vhost_mem->regions[j];
174 : 0 : rte_vfio_container_dma_unmap(vfio_container_fd,
175 : : mem_reg->host_user_addr,
176 : : mem_reg->guest_phys_addr,
177 : : mem_reg->size);
178 : : }
179 : :
180 : 0 : error:
181 : 0 : free(vhost_mem);
182 : :
183 : 0 : return rc;
184 : : }
185 : :
186 : : static int
187 : : sfc_vdpa_mem_bar_init(struct sfc_vdpa_adapter *sva,
188 : : const efx_bar_region_t *mem_ebrp)
189 : : {
190 : 0 : struct rte_pci_device *pci_dev = sva->pdev;
191 : : efsys_bar_t *ebp = &sva->mem_bar;
192 : : struct rte_mem_resource *res =
193 : 0 : &pci_dev->mem_resource[mem_ebrp->ebr_index];
194 : :
195 : : SFC_BAR_LOCK_INIT(ebp, pci_dev->name);
196 : 0 : ebp->esb_rid = mem_ebrp->ebr_index;
197 : 0 : ebp->esb_dev = pci_dev;
198 : 0 : ebp->esb_base = res->addr;
199 : :
200 : : return 0;
201 : : }
202 : :
203 : : static void
204 : : sfc_vdpa_mem_bar_fini(struct sfc_vdpa_adapter *sva)
205 : : {
206 : 0 : efsys_bar_t *ebp = &sva->mem_bar;
207 : :
208 : : SFC_BAR_LOCK_DESTROY(ebp);
209 : : memset(ebp, 0, sizeof(*ebp));
210 : 0 : }
211 : :
212 : : static int
213 : 0 : sfc_vdpa_nic_probe(struct sfc_vdpa_adapter *sva)
214 : : {
215 : 0 : efx_nic_t *enp = sva->nic;
216 : : int rc;
217 : :
218 : 0 : rc = efx_nic_probe(enp, EFX_FW_VARIANT_DONT_CARE);
219 [ # # ]: 0 : if (rc != 0)
220 : 0 : sfc_vdpa_err(sva, "nic probe failed: %s", rte_strerror(rc));
221 : :
222 : 0 : return rc;
223 : : }
224 : :
225 : : static int
226 : 0 : sfc_vdpa_estimate_resource_limits(struct sfc_vdpa_adapter *sva)
227 : : {
228 : : efx_drv_limits_t limits;
229 : : int rc;
230 : : uint32_t evq_allocated;
231 : : uint32_t rxq_allocated;
232 : : uint32_t txq_allocated;
233 : : uint32_t max_queue_cnt;
234 : :
235 : : memset(&limits, 0, sizeof(limits));
236 : :
237 : : /* Request at least one Rx and Tx queue */
238 : 0 : limits.edl_min_rxq_count = 1;
239 : 0 : limits.edl_min_txq_count = 1;
240 : : /* Management event queue plus event queue for Tx/Rx queue */
241 : 0 : limits.edl_min_evq_count =
242 : : 1 + RTE_MAX(limits.edl_min_rxq_count, limits.edl_min_txq_count);
243 : :
244 : 0 : limits.edl_max_rxq_count = SFC_VDPA_MAX_QUEUE_PAIRS;
245 : 0 : limits.edl_max_txq_count = SFC_VDPA_MAX_QUEUE_PAIRS;
246 : 0 : limits.edl_max_evq_count = 1 + SFC_VDPA_MAX_QUEUE_PAIRS;
247 : :
248 : : SFC_VDPA_ASSERT(limits.edl_max_evq_count >= limits.edl_min_rxq_count);
249 : : SFC_VDPA_ASSERT(limits.edl_max_rxq_count >= limits.edl_min_rxq_count);
250 : : SFC_VDPA_ASSERT(limits.edl_max_txq_count >= limits.edl_min_rxq_count);
251 : :
252 : : /* Configure the minimum required resources needed for the
253 : : * driver to operate, and the maximum desired resources that the
254 : : * driver is capable of using.
255 : : */
256 : 0 : sfc_vdpa_log_init(sva, "set drv limit");
257 : 0 : efx_nic_set_drv_limits(sva->nic, &limits);
258 : :
259 : 0 : sfc_vdpa_log_init(sva, "init nic");
260 : 0 : rc = efx_nic_init(sva->nic);
261 [ # # ]: 0 : if (rc != 0) {
262 : 0 : sfc_vdpa_err(sva, "nic init failed: %s", rte_strerror(rc));
263 : 0 : goto fail_nic_init;
264 : : }
265 : :
266 : : /* Find resource dimensions assigned by firmware to this function */
267 : 0 : rc = efx_nic_get_vi_pool(sva->nic, &evq_allocated, &rxq_allocated,
268 : : &txq_allocated);
269 [ # # ]: 0 : if (rc != 0) {
270 : 0 : sfc_vdpa_err(sva, "vi pool get failed: %s", rte_strerror(rc));
271 : 0 : goto fail_get_vi_pool;
272 : : }
273 : :
274 : : /* It still may allocate more than maximum, ensure limit */
275 : 0 : evq_allocated = RTE_MIN(evq_allocated, limits.edl_max_evq_count);
276 : 0 : rxq_allocated = RTE_MIN(rxq_allocated, limits.edl_max_rxq_count);
277 : 0 : txq_allocated = RTE_MIN(txq_allocated, limits.edl_max_txq_count);
278 : :
279 : :
280 : 0 : max_queue_cnt = RTE_MIN(rxq_allocated, txq_allocated);
281 : : /* Subtract management EVQ not used for traffic */
282 : 0 : max_queue_cnt = RTE_MIN(evq_allocated - 1, max_queue_cnt);
283 : :
284 : : SFC_VDPA_ASSERT(max_queue_cnt > 0);
285 : :
286 : 0 : sva->max_queue_count = max_queue_cnt;
287 : 0 : sfc_vdpa_log_init(sva, "NIC init done with %u pair(s) of queues",
288 : : max_queue_cnt);
289 : :
290 : 0 : return 0;
291 : :
292 : : fail_get_vi_pool:
293 : 0 : efx_nic_fini(sva->nic);
294 : 0 : fail_nic_init:
295 : 0 : sfc_vdpa_log_init(sva, "failed: %s", rte_strerror(rc));
296 : 0 : return rc;
297 : : }
298 : :
299 : : int
300 : 0 : sfc_vdpa_hw_init(struct sfc_vdpa_adapter *sva)
301 : : {
302 : : efx_bar_region_t mem_ebr;
303 : : efx_nic_t *enp;
304 : : int rc;
305 : :
306 : 0 : sfc_vdpa_log_init(sva, "entry");
307 : :
308 : 0 : sfc_vdpa_log_init(sva, "get family");
309 : 0 : rc = sfc_efx_family(sva->pdev, &mem_ebr, &sva->family);
310 [ # # ]: 0 : if (rc != 0)
311 : 0 : goto fail_family;
312 : 0 : sfc_vdpa_log_init(sva,
313 : : "family is %u, membar is %d,"
314 : : "function control window offset is %#" PRIx64,
315 : : sva->family, mem_ebr.ebr_index, mem_ebr.ebr_offset);
316 : :
317 : 0 : sfc_vdpa_log_init(sva, "init mem bar");
318 : : rc = sfc_vdpa_mem_bar_init(sva, &mem_ebr);
319 : : if (rc != 0)
320 : : goto fail_mem_bar_init;
321 : :
322 : 0 : sfc_vdpa_log_init(sva, "create nic");
323 : : rte_spinlock_init(&sva->nic_lock);
324 : 0 : rc = efx_nic_create(sva->family, (efsys_identifier_t *)sva,
325 : 0 : &sva->mem_bar, mem_ebr.ebr_offset,
326 : 0 : &sva->nic_lock, &enp);
327 [ # # ]: 0 : if (rc != 0) {
328 : 0 : sfc_vdpa_err(sva, "nic create failed: %s", rte_strerror(rc));
329 : 0 : goto fail_nic_create;
330 : : }
331 : 0 : sva->nic = enp;
332 : :
333 : 0 : sfc_vdpa_log_init(sva, "init mcdi");
334 : 0 : rc = sfc_vdpa_mcdi_init(sva);
335 [ # # ]: 0 : if (rc != 0) {
336 : 0 : sfc_vdpa_err(sva, "mcdi init failed: %s", rte_strerror(rc));
337 : 0 : goto fail_mcdi_init;
338 : : }
339 : :
340 : 0 : sfc_vdpa_log_init(sva, "probe nic");
341 : 0 : rc = sfc_vdpa_nic_probe(sva);
342 [ # # ]: 0 : if (rc != 0)
343 : 0 : goto fail_nic_probe;
344 : :
345 : 0 : sfc_vdpa_log_init(sva, "reset nic");
346 : 0 : rc = efx_nic_reset(enp);
347 [ # # ]: 0 : if (rc != 0) {
348 : 0 : sfc_vdpa_err(sva, "nic reset failed: %s", rte_strerror(rc));
349 : 0 : goto fail_nic_reset;
350 : : }
351 : :
352 : 0 : sfc_vdpa_log_init(sva, "estimate resource limits");
353 : 0 : rc = sfc_vdpa_estimate_resource_limits(sva);
354 [ # # ]: 0 : if (rc != 0)
355 : 0 : goto fail_estimate_rsrc_limits;
356 : :
357 : 0 : sfc_vdpa_log_init(sva, "init virtio");
358 : 0 : rc = efx_virtio_init(enp);
359 [ # # ]: 0 : if (rc != 0) {
360 : 0 : sfc_vdpa_err(sva, "virtio init failed: %s", rte_strerror(rc));
361 : 0 : goto fail_virtio_init;
362 : : }
363 : :
364 : 0 : sfc_vdpa_log_init(sva, "init filter");
365 : 0 : rc = efx_filter_init(enp);
366 [ # # ]: 0 : if (rc != 0) {
367 : 0 : sfc_vdpa_err(sva, "filter init failed: %s", rte_strerror(rc));
368 : 0 : goto fail_filter_init;
369 : : }
370 : :
371 : 0 : sfc_vdpa_log_init(sva, "done");
372 : :
373 : 0 : return 0;
374 : :
375 : : fail_filter_init:
376 : 0 : efx_virtio_fini(enp);
377 : :
378 : 0 : fail_virtio_init:
379 : 0 : efx_nic_fini(enp);
380 : :
381 : 0 : fail_estimate_rsrc_limits:
382 : 0 : fail_nic_reset:
383 : 0 : efx_nic_unprobe(enp);
384 : :
385 : 0 : fail_nic_probe:
386 : 0 : sfc_vdpa_mcdi_fini(sva);
387 : :
388 : 0 : fail_mcdi_init:
389 : 0 : sfc_vdpa_log_init(sva, "destroy nic");
390 : 0 : sva->nic = NULL;
391 : 0 : efx_nic_destroy(enp);
392 : :
393 : 0 : fail_nic_create:
394 : : sfc_vdpa_mem_bar_fini(sva);
395 : :
396 : 0 : fail_mem_bar_init:
397 : 0 : fail_family:
398 : 0 : sfc_vdpa_log_init(sva, "failed: %s", rte_strerror(rc));
399 : 0 : return rc;
400 : : }
401 : :
402 : : void
403 : 0 : sfc_vdpa_hw_fini(struct sfc_vdpa_adapter *sva)
404 : : {
405 : 0 : efx_nic_t *enp = sva->nic;
406 : :
407 : 0 : sfc_vdpa_log_init(sva, "entry");
408 : :
409 : 0 : sfc_vdpa_log_init(sva, "virtio fini");
410 : 0 : efx_virtio_fini(enp);
411 : :
412 : 0 : sfc_vdpa_log_init(sva, "unprobe nic");
413 : 0 : efx_nic_unprobe(enp);
414 : :
415 : 0 : sfc_vdpa_log_init(sva, "mcdi fini");
416 : 0 : sfc_vdpa_mcdi_fini(sva);
417 : :
418 : 0 : sfc_vdpa_log_init(sva, "nic fini");
419 : 0 : efx_nic_fini(enp);
420 : :
421 : 0 : sfc_vdpa_log_init(sva, "destroy nic");
422 : 0 : sva->nic = NULL;
423 : 0 : efx_nic_destroy(enp);
424 : :
425 : : sfc_vdpa_mem_bar_fini(sva);
426 : 0 : }
|