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