Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2021 Xilinx, Inc.
3 : : */
4 : :
5 : : #include <rte_mempool.h>
6 : : #include <rte_memzone.h>
7 : :
8 : : #include "efx.h"
9 : :
10 : : #include "sfc_log.h"
11 : : #include "sfc.h"
12 : : #include "sfc_nic_dma.h"
13 : :
14 : : static int
15 : : sfc_nic_dma_add_region(struct sfc_nic_dma_info *nic_dma_info,
16 : : rte_iova_t nic_base, rte_iova_t trgt_base,
17 : : size_t map_len)
18 : : {
19 : : struct sfc_nic_dma_region *region;
20 : :
21 [ # # ]: 0 : if (nic_dma_info->nb_regions >= RTE_DIM(nic_dma_info->regions))
22 : : return ENOMEM;
23 : :
24 : : region = &nic_dma_info->regions[nic_dma_info->nb_regions];
25 : 0 : region->nic_base = nic_base;
26 : 0 : region->trgt_base = trgt_base;
27 : 0 : region->trgt_end = trgt_base + map_len;
28 : :
29 : 0 : nic_dma_info->nb_regions++;
30 : : return 0;
31 : : }
32 : :
33 : : /*
34 : : * Register mapping for all IOVA mempools at the time of creation to
35 : : * have mapping for all mbufs.
36 : : */
37 : :
38 : : struct sfc_nic_dma_register_mempool_data {
39 : : struct sfc_adapter *sa;
40 : : int rc;
41 : : };
42 : :
43 : : static void
44 : 0 : sfc_nic_dma_register_mempool_chunk(struct rte_mempool *mp __rte_unused,
45 : : void *opaque,
46 : : struct rte_mempool_memhdr *memhdr,
47 : : unsigned mem_idx __rte_unused)
48 : : {
49 : : struct sfc_nic_dma_register_mempool_data *register_data = opaque;
50 [ # # ]: 0 : struct sfc_adapter *sa = register_data->sa;
51 : : struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
52 : : efsys_dma_addr_t nic_base;
53 : : efsys_dma_addr_t trgt_base;
54 : : size_t map_len;
55 : : int rc;
56 : :
57 [ # # ]: 0 : if (memhdr->iova == RTE_BAD_IOVA)
58 : 0 : return;
59 : :
60 : : /*
61 : : * Check if the memory chunk is mapped already. In that case, there's
62 : : * nothing left to do.
63 : : */
64 : 0 : nic_base = sfc_nic_dma_map(&sas->nic_dma_info, memhdr->iova,
65 : : memhdr->len);
66 [ # # ]: 0 : if (nic_base != RTE_BAD_IOVA)
67 : : return;
68 : :
69 : 0 : rc = efx_nic_dma_config_add(sa->nic, memhdr->iova, memhdr->len,
70 : : &nic_base, &trgt_base, &map_len);
71 [ # # ]: 0 : if (rc != 0) {
72 : 0 : sfc_err(sa,
73 : : "cannot handle memory buffer VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 ": %s",
74 : : memhdr->addr, (uint64_t)memhdr->iova, memhdr->len,
75 : : rte_strerror(rc));
76 : 0 : register_data->rc = rc;
77 : 0 : return;
78 : : }
79 : :
80 : 0 : sfc_info(sa,
81 : : "registered memory buffer VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 " -> NIC_BASE=%" PRIx64 " TRGT_BASE=%" PRIx64 " MAP_LEN=%" PRIx64,
82 : : memhdr->addr, (uint64_t)memhdr->iova, memhdr->len,
83 : : (uint64_t)nic_base, (uint64_t)trgt_base, (uint64_t)map_len);
84 : :
85 [ # # ]: 0 : rc = sfc_nic_dma_add_region(&sas->nic_dma_info, nic_base, trgt_base,
86 : : map_len);
87 : : if (rc != 0) {
88 : 0 : sfc_err(sa, "failed to add regioned NIC DMA mapping: %s",
89 : : rte_strerror(rc));
90 : 0 : register_data->rc = rc;
91 : : }
92 : : }
93 : :
94 : : static int
95 : 0 : sfc_nic_dma_register_mempool(struct sfc_adapter *sa, struct rte_mempool *mp)
96 : : {
97 : 0 : struct sfc_nic_dma_register_mempool_data register_data = {
98 : : .sa = sa,
99 : : };
100 : : uint32_t iters;
101 : : int result = 0;
102 : : int rc;
103 : :
104 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
105 : :
106 [ # # ]: 0 : if (mp->flags & RTE_MEMPOOL_F_NON_IO)
107 : : return 0;
108 : :
109 : 0 : iters = rte_mempool_mem_iter(mp, sfc_nic_dma_register_mempool_chunk,
110 : : ®ister_data);
111 [ # # ]: 0 : if (iters != mp->nb_mem_chunks) {
112 : 0 : sfc_err(sa,
113 : : "failed to iterate over memory chunks, some mbufs may be unusable");
114 : : result = EFAULT;
115 : : /*
116 : : * Return an error, but try to continue if error is
117 : : * async and cannot be handled properly.
118 : : */
119 : : }
120 : :
121 [ # # ]: 0 : if (register_data.rc != 0) {
122 : 0 : sfc_err(sa,
123 : : "failed to map some memory chunks (%s), some mbufs may be unusable",
124 : : rte_strerror(register_data.rc));
125 : 0 : result = register_data.rc;
126 : : /* Try to continue */
127 : : }
128 : :
129 : : /*
130 : : * There is no point to apply mapping changes triggered by mempool
131 : : * registration. Configuration will be propagated on start and
132 : : * mbufs mapping is required in started state only.
133 : : */
134 [ # # ]: 0 : if (sa->state == SFC_ETHDEV_STARTED) {
135 : : /*
136 : : * It's safe to reconfigure the DMA mapping even if no changes
137 : : * have been made during memory chunks iteration. In that case,
138 : : * this operation will not change anything either.
139 : : */
140 : 0 : rc = efx_nic_dma_reconfigure(sa->nic);
141 [ # # ]: 0 : if (rc != 0) {
142 : 0 : sfc_err(sa, "cannot reconfigure NIC DMA: %s",
143 : : rte_strerror(rc));
144 : : result = rc;
145 : : }
146 : : }
147 : :
148 : : return result;
149 : : }
150 : :
151 : : static void
152 : 0 : sfc_mempool_event_cb(enum rte_mempool_event event, struct rte_mempool *mp,
153 : : void *user_data)
154 : : {
155 : : struct sfc_adapter *sa = user_data;
156 : :
157 [ # # ]: 0 : if (event != RTE_MEMPOOL_EVENT_READY)
158 : : return;
159 : :
160 : 0 : sfc_adapter_lock(sa);
161 : :
162 : 0 : (void)sfc_nic_dma_register_mempool(sa, mp);
163 : :
164 : : sfc_adapter_unlock(sa);
165 : : }
166 : :
167 : : struct sfc_mempool_walk_data {
168 : : struct sfc_adapter *sa;
169 : : int rc;
170 : : };
171 : :
172 : : static void
173 : 0 : sfc_mempool_walk_cb(struct rte_mempool *mp, void *arg)
174 : : {
175 : : struct sfc_mempool_walk_data *walk_data = arg;
176 : : int rc;
177 : :
178 : 0 : rc = sfc_nic_dma_register_mempool(walk_data->sa, mp);
179 [ # # ]: 0 : if (rc != 0)
180 : 0 : walk_data->rc = rc;
181 : 0 : }
182 : :
183 : : static int
184 : 0 : sfc_nic_dma_attach_regioned(struct sfc_adapter *sa)
185 : : {
186 : : struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
187 : 0 : struct sfc_mempool_walk_data walk_data = {
188 : : .sa = sa,
189 : : };
190 : : int rc;
191 : :
192 : 0 : rc = rte_mempool_event_callback_register(sfc_mempool_event_cb, sa);
193 [ # # ]: 0 : if (rc != 0) {
194 : 0 : sfc_err(sa, "failed to register mempool event callback");
195 : : rc = EFAULT;
196 : 0 : goto fail_mempool_event_callback_register;
197 : : }
198 : :
199 : 0 : rte_mempool_walk(sfc_mempool_walk_cb, &walk_data);
200 [ # # ]: 0 : if (walk_data.rc != 0) {
201 : : rc = walk_data.rc;
202 : 0 : goto fail_mempool_walk;
203 : : }
204 : :
205 : : return 0;
206 : :
207 : : fail_mempool_walk:
208 : 0 : rte_mempool_event_callback_unregister(sfc_mempool_event_cb, sa);
209 : 0 : sas->nic_dma_info.nb_regions = 0;
210 : :
211 : : fail_mempool_event_callback_register:
212 : : return rc;
213 : : }
214 : :
215 : : static void
216 : : sfc_nic_dma_detach_regioned(struct sfc_adapter *sa)
217 : : {
218 : : struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
219 : :
220 : 0 : rte_mempool_event_callback_unregister(sfc_mempool_event_cb, sa);
221 : 0 : sas->nic_dma_info.nb_regions = 0;
222 : 0 : }
223 : :
224 : : int
225 : 0 : sfc_nic_dma_attach(struct sfc_adapter *sa)
226 : : {
227 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
228 : : int rc;
229 : :
230 : 0 : sfc_log_init(sa, "dma_mapping_type=%u", encp->enc_dma_mapping);
231 : :
232 [ # # # ]: 0 : switch (encp->enc_dma_mapping) {
233 : : case EFX_NIC_DMA_MAPPING_FLAT:
234 : : /* No mapping required */
235 : : rc = 0;
236 : : break;
237 : 0 : case EFX_NIC_DMA_MAPPING_REGIONED:
238 : 0 : rc = sfc_nic_dma_attach_regioned(sa);
239 : 0 : break;
240 : 0 : default:
241 : : rc = ENOTSUP;
242 : 0 : break;
243 : : }
244 : :
245 : 0 : sfc_log_init(sa, "done: %s", rte_strerror(rc));
246 : 0 : return rc;
247 : : }
248 : :
249 : : void
250 : 0 : sfc_nic_dma_detach(struct sfc_adapter *sa)
251 : : {
252 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
253 : :
254 : 0 : sfc_log_init(sa, "dma_mapping_type=%u", encp->enc_dma_mapping);
255 : :
256 [ # # ]: 0 : switch (encp->enc_dma_mapping) {
257 : : case EFX_NIC_DMA_MAPPING_FLAT:
258 : : /* Nothing to do here */
259 : : break;
260 : : case EFX_NIC_DMA_MAPPING_REGIONED:
261 : : sfc_nic_dma_detach_regioned(sa);
262 : : break;
263 : : default:
264 : : break;
265 : : }
266 : :
267 : 0 : sfc_log_init(sa, "done");
268 : 0 : }
269 : :
270 : : int
271 : 0 : sfc_nic_dma_mz_map(struct sfc_adapter *sa, const struct rte_memzone *mz,
272 : : efx_nic_dma_addr_type_t addr_type,
273 : : efsys_dma_addr_t *dma_addr)
274 : : {
275 : : efsys_dma_addr_t nic_base;
276 : : efsys_dma_addr_t trgt_base;
277 : : size_t map_len;
278 : : int rc;
279 : :
280 : : /*
281 : : * Check if the memzone can be mapped already without changing the DMA
282 : : * configuration.
283 : : * libefx is used instead of the driver cache since it can take the type
284 : : * of the buffer into account and make a better decision when it comes
285 : : * to buffers that are mapped by the FW itself.
286 : : */
287 : 0 : rc = efx_nic_dma_map(sa->nic, addr_type, mz->iova, mz->len, dma_addr);
288 [ # # ]: 0 : if (rc == 0)
289 : : return 0;
290 : :
291 [ # # ]: 0 : if (rc != ENOENT) {
292 : 0 : sfc_err(sa,
293 : : "failed to map memory buffer VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 ": %s",
294 : : mz->addr, (uint64_t)mz->iova, mz->len,
295 : : rte_strerror(rc));
296 : 0 : return rc;
297 : : }
298 : :
299 : 0 : rc = efx_nic_dma_config_add(sa->nic, mz->iova, mz->len,
300 : : &nic_base, &trgt_base, &map_len);
301 [ # # ]: 0 : if (rc != 0) {
302 : 0 : sfc_err(sa,
303 : : "cannot handle memory buffer VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 ": %s",
304 : : mz->addr, (uint64_t)mz->iova, mz->len,
305 : : rte_strerror(rc));
306 : 0 : return EFAULT;
307 : : }
308 : :
309 [ # # ]: 0 : rc = sfc_nic_dma_add_region(&sfc_sa2shared(sa)->nic_dma_info,
310 : : nic_base, trgt_base, map_len);
311 : : if (rc != 0) {
312 : 0 : sfc_err(sa,
313 : : "failed to add DMA region VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 ": %s",
314 : : mz->addr, (uint64_t)mz->iova, mz->len,
315 : : rte_strerror(rc));
316 : 0 : return rc;
317 : : }
318 : :
319 : 0 : rc = efx_nic_dma_reconfigure(sa->nic);
320 [ # # ]: 0 : if (rc != 0) {
321 : 0 : sfc_err(sa, "failed to reconfigure DMA");
322 : 0 : return rc;
323 : : }
324 : :
325 : 0 : rc = efx_nic_dma_map(sa->nic, addr_type, mz->iova, mz->len, dma_addr);
326 [ # # ]: 0 : if (rc != 0) {
327 : 0 : sfc_err(sa,
328 : : "failed to map memory buffer VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 ": %s",
329 : : mz->addr, (uint64_t)mz->iova, mz->len,
330 : : rte_strerror(rc));
331 : 0 : return rc;
332 : : }
333 : :
334 : : return 0;
335 : : }
|