Branch data Line data Source code
1 : : /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2 : : *
3 : : * Copyright 2008-2016 Freescale Semiconductor Inc.
4 : : * Copyright 2017, 2024 NXP
5 : : *
6 : : */
7 : : #include <rte_memcpy.h>
8 : : #include <rte_branch_prediction.h>
9 : : #include <eal_export.h>
10 : : #include <stdint.h>
11 : : #include <limits.h>
12 : :
13 : : #include "bman.h"
14 : :
15 : : /* Compilation constants */
16 : : #define RCR_THRESH 2 /* reread h/w CI when running out of space */
17 : : #define IRQNAME "BMan portal %d"
18 : : #define MAX_IRQNAME 16 /* big enough for "BMan portal %d" */
19 : :
20 : :
21 : : #define MAX_U16 UINT16_MAX
22 : : #define MAX_U32 UINT32_MAX
23 : : #ifndef BIT_SIZE
24 : : #define BIT_SIZE(t) (sizeof(t) * 8)
25 : : #endif
26 : : #define MAX_U48 \
27 : : ((((uint64_t)MAX_U16) << BIT_SIZE(uint32_t)) | MAX_U32)
28 : : #define HI16_OF_U48(x) \
29 : : (((x) >> BIT_SIZE(rte_be32_t)) & MAX_U16)
30 : : #define LO32_OF_U48(x) ((x) & MAX_U32)
31 : : #define U48_BY_HI16_LO32(hi, lo) \
32 : : (((hi) << BIT_SIZE(uint32_t)) | (lo))
33 : :
34 : : struct bman_portal {
35 : : struct bm_portal p;
36 : : /* 2-element array. pools[0] is mask, pools[1] is snapshot. */
37 : : struct bman_depletion *pools;
38 : : int thresh_set;
39 : : unsigned long irq_sources;
40 : : u32 slowpoll; /* only used when interrupts are off */
41 : : /* When the cpu-affine portal is activated, this is non-NULL */
42 : : const struct bm_portal_config *config;
43 : : char irqname[MAX_IRQNAME];
44 : : };
45 : :
46 : : static cpumask_t affine_mask;
47 : : static DEFINE_SPINLOCK(affine_mask_lock);
48 : : static RTE_DEFINE_PER_LCORE(struct bman_portal, bman_affine_portal);
49 : :
50 : : static inline struct bman_portal *get_affine_portal(void)
51 : : {
52 : : return &RTE_PER_LCORE(bman_affine_portal);
53 : : }
54 : :
55 : : /*
56 : : * This object type refers to a pool, it isn't *the* pool. There may be
57 : : * more than one such object per BMan buffer pool, eg. if different users of
58 : : * the pool are operating via different portals.
59 : : */
60 : : struct bman_pool {
61 : : struct bman_pool_params params;
62 : : /* Used for hash-table admin when using depletion notifications. */
63 : : struct bman_portal *portal;
64 : : struct bman_pool *next;
65 : : #ifdef RTE_LIBRTE_DPAA_HWDEBUG
66 : : atomic_t in_use;
67 : : #endif
68 : : };
69 : :
70 : : static inline
71 : 0 : struct bman_portal *bman_create_portal(struct bman_portal *portal,
72 : : const struct bm_portal_config *c)
73 : : {
74 : : struct bm_portal *p;
75 : : const struct bman_depletion *pools = &c->mask;
76 : : int ret;
77 : : u8 bpid = 0;
78 : :
79 : 0 : p = &portal->p;
80 : : /*
81 : : * prep the low-level portal struct with the mapped addresses from the
82 : : * config, everything that follows depends on it and "config" is more
83 : : * for (de)reference...
84 : : */
85 : 0 : p->addr.ce = c->addr_virt[DPAA_PORTAL_CE];
86 : 0 : p->addr.ci = c->addr_virt[DPAA_PORTAL_CI];
87 [ # # ]: 0 : if (bm_rcr_init(p, bm_rcr_pvb, bm_rcr_cce)) {
88 : 0 : pr_err("Bman RCR initialisation failed\n");
89 : 0 : return NULL;
90 : : }
91 : : if (bm_mc_init(p)) {
92 : : pr_err("Bman MC initialisation failed\n");
93 : : goto fail_mc;
94 : : }
95 : 0 : portal->pools = kmalloc(2 * sizeof(*pools), GFP_KERNEL);
96 [ # # ]: 0 : if (!portal->pools)
97 : 0 : goto fail_pools;
98 : 0 : portal->pools[0] = *pools;
99 : : bman_depletion_init(portal->pools + 1);
100 [ # # ]: 0 : while (bpid < bman_pool_max) {
101 : : /*
102 : : * Default to all BPIDs disabled, we enable as required at
103 : : * run-time.
104 : : */
105 : 0 : bm_isr_bscn_mask(p, bpid, 0);
106 : 0 : bpid++;
107 : : }
108 : 0 : portal->slowpoll = 0;
109 : : /* Write-to-clear any stale interrupt status bits */
110 : : bm_isr_disable_write(p, 0xffffffff);
111 : 0 : portal->irq_sources = 0;
112 : : bm_isr_enable_write(p, portal->irq_sources);
113 : : bm_isr_status_clear(p, 0xffffffff);
114 : 0 : snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu);
115 [ # # ]: 0 : if (request_irq(c->irq, NULL, 0, portal->irqname,
116 : : portal)) {
117 : 0 : pr_err("request_irq() failed\n");
118 : 0 : goto fail_irq;
119 : : }
120 : :
121 : : /* Need RCR to be empty before continuing */
122 : : ret = bm_rcr_get_fill(p);
123 [ # # ]: 0 : if (ret) {
124 : 0 : pr_err("Bman RCR unclean\n");
125 : 0 : goto fail_rcr_empty;
126 : : }
127 : : /* Success */
128 : 0 : portal->config = c;
129 : :
130 : : bm_isr_disable_write(p, 0);
131 : : bm_isr_uninhibit(p);
132 : 0 : return portal;
133 : : fail_rcr_empty:
134 : 0 : free_irq(c->irq, portal);
135 : 0 : fail_irq:
136 : 0 : kfree(portal->pools);
137 : 0 : fail_pools:
138 : : bm_mc_finish(p);
139 : : fail_mc:
140 : 0 : bm_rcr_finish(p);
141 : 0 : return NULL;
142 : : }
143 : :
144 : : struct bman_portal *
145 : 0 : bman_create_affine_portal(const struct bm_portal_config *c)
146 : : {
147 : : struct bman_portal *portal = get_affine_portal();
148 : :
149 : : /*This function is called from the context which is already affine to
150 : : *CPU or in other words this in non-migratable to other CPUs.
151 : : */
152 : 0 : portal = bman_create_portal(portal, c);
153 [ # # ]: 0 : if (portal) {
154 : : spin_lock(&affine_mask_lock);
155 [ # # ]: 0 : CPU_SET(c->cpu, &affine_mask);
156 : : spin_unlock(&affine_mask_lock);
157 : : }
158 : 0 : return portal;
159 : : }
160 : :
161 : : static inline
162 : 0 : void bman_destroy_portal(struct bman_portal *bm)
163 : : {
164 : : const struct bm_portal_config *pcfg;
165 : :
166 : 0 : pcfg = bm->config;
167 : 0 : bm_rcr_cce_update(&bm->p);
168 : : bm_rcr_cce_update(&bm->p);
169 : :
170 : 0 : free_irq(pcfg->irq, bm);
171 : :
172 : 0 : kfree(bm->pools);
173 : : bm_mc_finish(&bm->p);
174 : 0 : bm_rcr_finish(&bm->p);
175 : 0 : bm->config = NULL;
176 : 0 : }
177 : :
178 : : const struct
179 : 0 : bm_portal_config *bman_destroy_affine_portal(void)
180 : : {
181 : : struct bman_portal *bm = get_affine_portal();
182 : : const struct bm_portal_config *pcfg;
183 : :
184 : 0 : pcfg = bm->config;
185 : 0 : bman_destroy_portal(bm);
186 : : spin_lock(&affine_mask_lock);
187 [ # # ]: 0 : CPU_CLR(pcfg->cpu, &affine_mask);
188 : : spin_unlock(&affine_mask_lock);
189 : 0 : return pcfg;
190 : : }
191 : :
192 : : int
193 : 0 : bman_get_portal_index(void)
194 : : {
195 : : struct bman_portal *p = get_affine_portal();
196 : 0 : return p->config->index;
197 : : }
198 : :
199 : : static const u32 zero_thresholds[4] = {0, 0, 0, 0};
200 : :
201 : 0 : struct bman_pool *bman_new_pool(const struct bman_pool_params *params)
202 : : {
203 : : struct bman_pool *pool = NULL;
204 : : u32 bpid;
205 : :
206 [ # # ]: 0 : if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID) {
207 : : int ret = bman_alloc_bpid(&bpid);
208 : :
209 [ # # ]: 0 : if (ret)
210 : : return NULL;
211 : : } else {
212 [ # # ]: 0 : if (params->bpid >= bman_pool_max)
213 : : return NULL;
214 : 0 : bpid = params->bpid;
215 : : }
216 [ # # ]: 0 : if (params->flags & BMAN_POOL_FLAG_THRESH) {
217 : 0 : int ret = bm_pool_set(bpid, params->thresholds);
218 : :
219 [ # # ]: 0 : if (ret)
220 : 0 : goto err;
221 : : }
222 : :
223 : 0 : pool = kmalloc(sizeof(*pool), GFP_KERNEL);
224 [ # # ]: 0 : if (!pool)
225 : 0 : goto err;
226 : 0 : pool->params = *params;
227 : : #ifdef RTE_LIBRTE_DPAA_HWDEBUG
228 : : atomic_set(&pool->in_use, 1);
229 : : #endif
230 [ # # ]: 0 : if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
231 : 0 : pool->params.bpid = bpid;
232 : :
233 : : return pool;
234 : 0 : err:
235 [ # # ]: 0 : if (params->flags & BMAN_POOL_FLAG_THRESH)
236 : 0 : bm_pool_set(bpid, zero_thresholds);
237 : :
238 [ # # ]: 0 : if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
239 : 0 : bman_release_bpid(bpid);
240 : 0 : kfree(pool);
241 : :
242 : 0 : return NULL;
243 : : }
244 : :
245 : 0 : void bman_free_pool(struct bman_pool *pool)
246 : : {
247 [ # # ]: 0 : if (pool->params.flags & BMAN_POOL_FLAG_THRESH)
248 : 0 : bm_pool_set(pool->params.bpid, zero_thresholds);
249 [ # # ]: 0 : if (pool->params.flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
250 : 0 : bman_release_bpid(pool->params.bpid);
251 : 0 : kfree(pool);
252 : 0 : }
253 : :
254 : 0 : const struct bman_pool_params *bman_get_params(const struct bman_pool *pool)
255 : : {
256 : 0 : return &pool->params;
257 : : }
258 : :
259 : : static void update_rcr_ci(struct bman_portal *p, int avail)
260 : : {
261 [ # # # # ]: 0 : if (avail)
262 : : bm_rcr_cce_prefetch(&p->p);
263 : : else
264 : : bm_rcr_cce_update(&p->p);
265 : : }
266 : :
267 : : RTE_EXPORT_INTERNAL_SYMBOL(bman_release_fast)
268 : : int
269 : 0 : bman_release_fast(struct bman_pool *pool, const uint64_t *bufs,
270 : : uint8_t num)
271 : : {
272 : : struct bman_portal *p;
273 : : struct bm_rcr_entry *r;
274 : : uint8_t i, avail;
275 [ # # ]: 0 : uint64_t bpid = pool->params.bpid;
276 : : struct bm_hw_buf_desc bm_bufs[FSL_BM_BURST_MAX];
277 : :
278 : : #ifdef RTE_LIBRTE_DPAA_HWDEBUG
279 : : if (!num || (num > FSL_BM_BURST_MAX))
280 : : return -EINVAL;
281 : : if (pool->params.flags & BMAN_POOL_FLAG_NO_RELEASE)
282 : : return -EINVAL;
283 : : #endif
284 : :
285 : : p = get_affine_portal();
286 : : avail = bm_rcr_get_avail(&p->p);
287 [ # # ]: 0 : if (avail < 2)
288 : : update_rcr_ci(p, avail);
289 : : r = bm_rcr_start(&p->p);
290 [ # # ]: 0 : if (unlikely(!r))
291 : : return -EBUSY;
292 : :
293 : : /*
294 : : * we can copy all but the first entry, as this can trigger badness
295 : : * with the valid-bit
296 : : */
297 : 0 : bm_bufs[0].bpid = bpid;
298 [ # # ]: 0 : bm_bufs[0].hi_addr = cpu_to_be16(HI16_OF_U48(bufs[0]));
299 [ # # ]: 0 : bm_bufs[0].lo_addr = cpu_to_be32(LO32_OF_U48(bufs[0]));
300 [ # # ]: 0 : for (i = 1; i < num; i++) {
301 [ # # ]: 0 : bm_bufs[i].hi_addr = cpu_to_be16(HI16_OF_U48(bufs[i]));
302 [ # # ]: 0 : bm_bufs[i].lo_addr = cpu_to_be32(LO32_OF_U48(bufs[i]));
303 : : }
304 : :
305 : 0 : memcpy(r->bufs, bm_bufs, sizeof(struct bm_buffer) * num);
306 : :
307 : 0 : bm_rcr_pvb_commit(&p->p, BM_RCR_VERB_CMD_BPID_SINGLE |
308 : 0 : (num & BM_RCR_VERB_BUFCOUNT_MASK));
309 : :
310 : 0 : return 0;
311 : : }
312 : :
313 [ # # ]: 0 : int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num,
314 : : u32 flags __maybe_unused)
315 : : {
316 : : struct bman_portal *p;
317 : : struct bm_rcr_entry *r;
318 : : u32 i = num - 1;
319 : : u8 avail;
320 : :
321 : : #ifdef RTE_LIBRTE_DPAA_HWDEBUG
322 : : if (!num || (num > FSL_BM_BURST_MAX))
323 : : return -EINVAL;
324 : : if (pool->params.flags & BMAN_POOL_FLAG_NO_RELEASE)
325 : : return -EINVAL;
326 : : #endif
327 : :
328 : : p = get_affine_portal();
329 : : avail = bm_rcr_get_avail(&p->p);
330 [ # # ]: 0 : if (avail < 2)
331 : : update_rcr_ci(p, avail);
332 : : r = bm_rcr_start(&p->p);
333 [ # # ]: 0 : if (unlikely(!r))
334 : : return -EBUSY;
335 : :
336 : : /*
337 : : * we can copy all but the first entry, as this can trigger badness
338 : : * with the valid-bit
339 : : */
340 : 0 : r->bufs[0].opaque =
341 [ # # ]: 0 : cpu_to_be64(((u64)pool->params.bpid << 48) |
342 : : (bufs[0].opaque & MAX_U48));
343 [ # # ]: 0 : if (i) {
344 [ # # ]: 0 : for (i = 1; i < num; i++)
345 : 0 : r->bufs[i].opaque =
346 [ # # ]: 0 : cpu_to_be64(bufs[i].opaque & MAX_U48);
347 : : }
348 : :
349 : 0 : bm_rcr_pvb_commit(&p->p, BM_RCR_VERB_CMD_BPID_SINGLE |
350 : 0 : (num & BM_RCR_VERB_BUFCOUNT_MASK));
351 : :
352 : 0 : return 0;
353 : : }
354 : :
355 : : static inline uint64_t
356 : : __rte_unused bman_extract_addr(struct bm_buffer *buf)
357 : : {
358 : : buf->opaque = be64_to_cpu(buf->opaque);
359 : :
360 : : return buf->addr;
361 : : }
362 : :
363 : : static inline uint64_t
364 : 0 : bman_hw_extract_addr(struct bm_hw_buf_desc *buf)
365 : : {
366 : : uint64_t hi, lo;
367 : :
368 [ # # ]: 0 : hi = be16_to_cpu(buf->hi_addr);
369 [ # # ]: 0 : lo = be32_to_cpu(buf->lo_addr);
370 : 0 : return U48_BY_HI16_LO32(hi, lo);
371 : : }
372 : :
373 : : RTE_EXPORT_INTERNAL_SYMBOL(bman_acquire_fast)
374 : : int
375 : 0 : bman_acquire_fast(struct bman_pool *pool, uint64_t *bufs, uint8_t num)
376 : : {
377 : : struct bman_portal *p = get_affine_portal();
378 : : struct bm_mc_command *mcc;
379 : : struct bm_mc_result *mcr;
380 : : uint8_t i, rst;
381 : : struct bm_hw_buf_desc bm_bufs[FSL_BM_BURST_MAX];
382 : :
383 : : #ifdef RTE_LIBRTE_DPAA_HWDEBUG
384 : : if (!num || (num > FSL_BM_BURST_MAX))
385 : : return -EINVAL;
386 : : if (pool->params.flags & BMAN_POOL_FLAG_ONLY_RELEASE)
387 : : return -EINVAL;
388 : : #endif
389 : :
390 : : mcc = bm_mc_start(&p->p);
391 : 0 : mcc->acquire.bpid = pool->params.bpid;
392 : 0 : bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE |
393 : 0 : (num & BM_MCC_VERB_ACQUIRE_BUFCOUNT));
394 : : while (!(mcr = bm_mc_result(&p->p)))
395 : : ;
396 : 0 : rst = mcr->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT;
397 [ # # ]: 0 : if (unlikely(rst < 1 || rst > FSL_BM_BURST_MAX))
398 : : return -EINVAL;
399 : :
400 [ # # ]: 0 : rte_memcpy(bm_bufs, mcr->acquire.bufs,
401 : : sizeof(struct bm_buffer) * rst);
402 : :
403 [ # # ]: 0 : for (i = 0; i < rst; i++)
404 : 0 : bufs[i] = bman_hw_extract_addr(&bm_bufs[i]);
405 : :
406 : 0 : return rst;
407 : : }
408 : :
409 : 0 : int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num,
410 : : u32 flags __maybe_unused)
411 : : {
412 : : struct bman_portal *p = get_affine_portal();
413 : : struct bm_mc_command *mcc;
414 : : struct bm_mc_result *mcr;
415 : : uint8_t rst, i;
416 : :
417 : : #ifdef RTE_LIBRTE_DPAA_HWDEBUG
418 : : if (!num || (num > FSL_BM_BURST_MAX))
419 : : return -EINVAL;
420 : : if (pool->params.flags & BMAN_POOL_FLAG_ONLY_RELEASE)
421 : : return -EINVAL;
422 : : #endif
423 : :
424 : : mcc = bm_mc_start(&p->p);
425 : 0 : mcc->acquire.bpid = pool->params.bpid;
426 : 0 : bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE |
427 : 0 : (num & BM_MCC_VERB_ACQUIRE_BUFCOUNT));
428 : : while (!(mcr = bm_mc_result(&p->p)))
429 : 0 : cpu_relax();
430 : 0 : rst = mcr->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT;
431 [ # # ]: 0 : for (i = 0; i < rst; i++)
432 [ # # ]: 0 : bufs[i].opaque = be64_to_cpu(mcr->acquire.bufs[i].opaque);
433 : :
434 : 0 : return rst;
435 : : }
436 : :
437 : 0 : int bman_query_pools(struct bm_pool_state *state)
438 : : {
439 : : struct bman_portal *p = get_affine_portal();
440 : : struct bm_mc_result *mcr;
441 : :
442 : : bm_mc_start(&p->p);
443 : : bm_mc_commit(&p->p, BM_MCC_VERB_CMD_QUERY);
444 : : while (!(mcr = bm_mc_result(&p->p)))
445 : 0 : cpu_relax();
446 : : DPAA_ASSERT((mcr->verb & BM_MCR_VERB_CMD_MASK) ==
447 : : BM_MCR_VERB_CMD_QUERY);
448 : 0 : *state = mcr->query;
449 [ # # ]: 0 : state->as.state.state[0] = be32_to_cpu(state->as.state.state[0]);
450 [ # # ]: 0 : state->as.state.state[1] = be32_to_cpu(state->as.state.state[1]);
451 [ # # ]: 0 : state->ds.state.state[0] = be32_to_cpu(state->ds.state.state[0]);
452 [ # # ]: 0 : state->ds.state.state[1] = be32_to_cpu(state->ds.state.state[1]);
453 : 0 : return 0;
454 : : }
455 : :
456 : 0 : u32 bman_query_free_buffers(struct bman_pool *pool)
457 : : {
458 : 0 : return bm_pool_free_buffers(pool->params.bpid);
459 : : }
460 : :
461 : 0 : int bman_update_pool_thresholds(struct bman_pool *pool, const u32 *thresholds)
462 : : {
463 : : u32 bpid;
464 : :
465 : 0 : bpid = bman_get_params(pool)->bpid;
466 : :
467 : 0 : return bm_pool_set(bpid, thresholds);
468 : : }
469 : :
470 : 0 : int bman_shutdown_pool(u32 bpid)
471 : : {
472 : : struct bman_portal *p = get_affine_portal();
473 : 0 : return bm_shutdown_pool(&p->p, bpid);
474 : : }
|