diff options
Diffstat (limited to 'drivers/soc/fsl/qbman/bman.c')
-rw-r--r-- | drivers/soc/fsl/qbman/bman.c | 797 |
1 files changed, 797 insertions, 0 deletions
diff --git a/drivers/soc/fsl/qbman/bman.c b/drivers/soc/fsl/qbman/bman.c new file mode 100644 index 000000000000..ffa48fdbb1a9 --- /dev/null +++ b/drivers/soc/fsl/qbman/bman.c | |||
@@ -0,0 +1,797 @@ | |||
1 | /* Copyright 2008 - 2016 Freescale Semiconductor, Inc. | ||
2 | * | ||
3 | * Redistribution and use in source and binary forms, with or without | ||
4 | * modification, are permitted provided that the following conditions are met: | ||
5 | * * Redistributions of source code must retain the above copyright | ||
6 | * notice, this list of conditions and the following disclaimer. | ||
7 | * * Redistributions in binary form must reproduce the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer in the | ||
9 | * documentation and/or other materials provided with the distribution. | ||
10 | * * Neither the name of Freescale Semiconductor nor the | ||
11 | * names of its contributors may be used to endorse or promote products | ||
12 | * derived from this software without specific prior written permission. | ||
13 | * | ||
14 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
15 | * GNU General Public License ("GPL") as published by the Free Software | ||
16 | * Foundation, either version 2 of that License or (at your option) any | ||
17 | * later version. | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
20 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
22 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
23 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
26 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
29 | */ | ||
30 | |||
31 | #include "bman_priv.h" | ||
32 | |||
33 | #define IRQNAME "BMan portal %d" | ||
34 | #define MAX_IRQNAME 16 /* big enough for "BMan portal %d" */ | ||
35 | |||
36 | /* Portal register assists */ | ||
37 | |||
38 | /* Cache-inhibited register offsets */ | ||
39 | #define BM_REG_RCR_PI_CINH 0x0000 | ||
40 | #define BM_REG_RCR_CI_CINH 0x0004 | ||
41 | #define BM_REG_RCR_ITR 0x0008 | ||
42 | #define BM_REG_CFG 0x0100 | ||
43 | #define BM_REG_SCN(n) (0x0200 + ((n) << 2)) | ||
44 | #define BM_REG_ISR 0x0e00 | ||
45 | #define BM_REG_IER 0x0e04 | ||
46 | #define BM_REG_ISDR 0x0e08 | ||
47 | #define BM_REG_IIR 0x0e0c | ||
48 | |||
49 | /* Cache-enabled register offsets */ | ||
50 | #define BM_CL_CR 0x0000 | ||
51 | #define BM_CL_RR0 0x0100 | ||
52 | #define BM_CL_RR1 0x0140 | ||
53 | #define BM_CL_RCR 0x1000 | ||
54 | #define BM_CL_RCR_PI_CENA 0x3000 | ||
55 | #define BM_CL_RCR_CI_CENA 0x3100 | ||
56 | |||
57 | /* | ||
58 | * Portal modes. | ||
59 | * Enum types; | ||
60 | * pmode == production mode | ||
61 | * cmode == consumption mode, | ||
62 | * Enum values use 3 letter codes. First letter matches the portal mode, | ||
63 | * remaining two letters indicate; | ||
64 | * ci == cache-inhibited portal register | ||
65 | * ce == cache-enabled portal register | ||
66 | * vb == in-band valid-bit (cache-enabled) | ||
67 | */ | ||
68 | enum bm_rcr_pmode { /* matches BCSP_CFG::RPM */ | ||
69 | bm_rcr_pci = 0, /* PI index, cache-inhibited */ | ||
70 | bm_rcr_pce = 1, /* PI index, cache-enabled */ | ||
71 | bm_rcr_pvb = 2 /* valid-bit */ | ||
72 | }; | ||
73 | enum bm_rcr_cmode { /* s/w-only */ | ||
74 | bm_rcr_cci, /* CI index, cache-inhibited */ | ||
75 | bm_rcr_cce /* CI index, cache-enabled */ | ||
76 | }; | ||
77 | |||
78 | |||
79 | /* --- Portal structures --- */ | ||
80 | |||
81 | #define BM_RCR_SIZE 8 | ||
82 | |||
83 | /* Release Command */ | ||
84 | struct bm_rcr_entry { | ||
85 | union { | ||
86 | struct { | ||
87 | u8 _ncw_verb; /* writes to this are non-coherent */ | ||
88 | u8 bpid; /* used with BM_RCR_VERB_CMD_BPID_SINGLE */ | ||
89 | u8 __reserved1[62]; | ||
90 | }; | ||
91 | struct bm_buffer bufs[8]; | ||
92 | }; | ||
93 | }; | ||
94 | #define BM_RCR_VERB_VBIT 0x80 | ||
95 | #define BM_RCR_VERB_CMD_MASK 0x70 /* one of two values; */ | ||
96 | #define BM_RCR_VERB_CMD_BPID_SINGLE 0x20 | ||
97 | #define BM_RCR_VERB_CMD_BPID_MULTI 0x30 | ||
98 | #define BM_RCR_VERB_BUFCOUNT_MASK 0x0f /* values 1..8 */ | ||
99 | |||
100 | struct bm_rcr { | ||
101 | struct bm_rcr_entry *ring, *cursor; | ||
102 | u8 ci, available, ithresh, vbit; | ||
103 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
104 | u32 busy; | ||
105 | enum bm_rcr_pmode pmode; | ||
106 | enum bm_rcr_cmode cmode; | ||
107 | #endif | ||
108 | }; | ||
109 | |||
110 | /* MC (Management Command) command */ | ||
111 | struct bm_mc_command { | ||
112 | u8 _ncw_verb; /* writes to this are non-coherent */ | ||
113 | u8 bpid; /* used by acquire command */ | ||
114 | u8 __reserved[62]; | ||
115 | }; | ||
116 | #define BM_MCC_VERB_VBIT 0x80 | ||
117 | #define BM_MCC_VERB_CMD_MASK 0x70 /* where the verb contains; */ | ||
118 | #define BM_MCC_VERB_CMD_ACQUIRE 0x10 | ||
119 | #define BM_MCC_VERB_CMD_QUERY 0x40 | ||
120 | #define BM_MCC_VERB_ACQUIRE_BUFCOUNT 0x0f /* values 1..8 go here */ | ||
121 | |||
122 | /* MC result, Acquire and Query Response */ | ||
123 | union bm_mc_result { | ||
124 | struct { | ||
125 | u8 verb; | ||
126 | u8 bpid; | ||
127 | u8 __reserved[62]; | ||
128 | }; | ||
129 | struct bm_buffer bufs[8]; | ||
130 | }; | ||
131 | #define BM_MCR_VERB_VBIT 0x80 | ||
132 | #define BM_MCR_VERB_CMD_MASK BM_MCC_VERB_CMD_MASK | ||
133 | #define BM_MCR_VERB_CMD_ACQUIRE BM_MCC_VERB_CMD_ACQUIRE | ||
134 | #define BM_MCR_VERB_CMD_QUERY BM_MCC_VERB_CMD_QUERY | ||
135 | #define BM_MCR_VERB_CMD_ERR_INVALID 0x60 | ||
136 | #define BM_MCR_VERB_CMD_ERR_ECC 0x70 | ||
137 | #define BM_MCR_VERB_ACQUIRE_BUFCOUNT BM_MCC_VERB_ACQUIRE_BUFCOUNT /* 0..8 */ | ||
138 | #define BM_MCR_TIMEOUT 10000 /* us */ | ||
139 | |||
140 | struct bm_mc { | ||
141 | struct bm_mc_command *cr; | ||
142 | union bm_mc_result *rr; | ||
143 | u8 rridx, vbit; | ||
144 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
145 | enum { | ||
146 | /* Can only be _mc_start()ed */ | ||
147 | mc_idle, | ||
148 | /* Can only be _mc_commit()ed or _mc_abort()ed */ | ||
149 | mc_user, | ||
150 | /* Can only be _mc_retry()ed */ | ||
151 | mc_hw | ||
152 | } state; | ||
153 | #endif | ||
154 | }; | ||
155 | |||
156 | struct bm_addr { | ||
157 | void __iomem *ce; /* cache-enabled */ | ||
158 | void __iomem *ci; /* cache-inhibited */ | ||
159 | }; | ||
160 | |||
161 | struct bm_portal { | ||
162 | struct bm_addr addr; | ||
163 | struct bm_rcr rcr; | ||
164 | struct bm_mc mc; | ||
165 | } ____cacheline_aligned; | ||
166 | |||
167 | /* Cache-inhibited register access. */ | ||
168 | static inline u32 bm_in(struct bm_portal *p, u32 offset) | ||
169 | { | ||
170 | return __raw_readl(p->addr.ci + offset); | ||
171 | } | ||
172 | |||
173 | static inline void bm_out(struct bm_portal *p, u32 offset, u32 val) | ||
174 | { | ||
175 | __raw_writel(val, p->addr.ci + offset); | ||
176 | } | ||
177 | |||
178 | /* Cache Enabled Portal Access */ | ||
179 | static inline void bm_cl_invalidate(struct bm_portal *p, u32 offset) | ||
180 | { | ||
181 | dpaa_invalidate(p->addr.ce + offset); | ||
182 | } | ||
183 | |||
184 | static inline void bm_cl_touch_ro(struct bm_portal *p, u32 offset) | ||
185 | { | ||
186 | dpaa_touch_ro(p->addr.ce + offset); | ||
187 | } | ||
188 | |||
189 | static inline u32 bm_ce_in(struct bm_portal *p, u32 offset) | ||
190 | { | ||
191 | return __raw_readl(p->addr.ce + offset); | ||
192 | } | ||
193 | |||
194 | struct bman_portal { | ||
195 | struct bm_portal p; | ||
196 | /* interrupt sources processed by portal_isr(), configurable */ | ||
197 | unsigned long irq_sources; | ||
198 | /* probing time config params for cpu-affine portals */ | ||
199 | const struct bm_portal_config *config; | ||
200 | char irqname[MAX_IRQNAME]; | ||
201 | }; | ||
202 | |||
203 | static cpumask_t affine_mask; | ||
204 | static DEFINE_SPINLOCK(affine_mask_lock); | ||
205 | static DEFINE_PER_CPU(struct bman_portal, bman_affine_portal); | ||
206 | |||
207 | static inline struct bman_portal *get_affine_portal(void) | ||
208 | { | ||
209 | return &get_cpu_var(bman_affine_portal); | ||
210 | } | ||
211 | |||
212 | static inline void put_affine_portal(void) | ||
213 | { | ||
214 | put_cpu_var(bman_affine_portal); | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * This object type refers to a pool, it isn't *the* pool. There may be | ||
219 | * more than one such object per BMan buffer pool, eg. if different users of the | ||
220 | * pool are operating via different portals. | ||
221 | */ | ||
222 | struct bman_pool { | ||
223 | /* index of the buffer pool to encapsulate (0-63) */ | ||
224 | u32 bpid; | ||
225 | /* Used for hash-table admin when using depletion notifications. */ | ||
226 | struct bman_portal *portal; | ||
227 | struct bman_pool *next; | ||
228 | }; | ||
229 | |||
230 | static u32 poll_portal_slow(struct bman_portal *p, u32 is); | ||
231 | |||
232 | static irqreturn_t portal_isr(int irq, void *ptr) | ||
233 | { | ||
234 | struct bman_portal *p = ptr; | ||
235 | struct bm_portal *portal = &p->p; | ||
236 | u32 clear = p->irq_sources; | ||
237 | u32 is = bm_in(portal, BM_REG_ISR) & p->irq_sources; | ||
238 | |||
239 | if (unlikely(!is)) | ||
240 | return IRQ_NONE; | ||
241 | |||
242 | clear |= poll_portal_slow(p, is); | ||
243 | bm_out(portal, BM_REG_ISR, clear); | ||
244 | return IRQ_HANDLED; | ||
245 | } | ||
246 | |||
247 | /* --- RCR API --- */ | ||
248 | |||
249 | #define RCR_SHIFT ilog2(sizeof(struct bm_rcr_entry)) | ||
250 | #define RCR_CARRY (uintptr_t)(BM_RCR_SIZE << RCR_SHIFT) | ||
251 | |||
252 | /* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */ | ||
253 | static struct bm_rcr_entry *rcr_carryclear(struct bm_rcr_entry *p) | ||
254 | { | ||
255 | uintptr_t addr = (uintptr_t)p; | ||
256 | |||
257 | addr &= ~RCR_CARRY; | ||
258 | |||
259 | return (struct bm_rcr_entry *)addr; | ||
260 | } | ||
261 | |||
262 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
263 | /* Bit-wise logic to convert a ring pointer to a ring index */ | ||
264 | static int rcr_ptr2idx(struct bm_rcr_entry *e) | ||
265 | { | ||
266 | return ((uintptr_t)e >> RCR_SHIFT) & (BM_RCR_SIZE - 1); | ||
267 | } | ||
268 | #endif | ||
269 | |||
270 | /* Increment the 'cursor' ring pointer, taking 'vbit' into account */ | ||
271 | static inline void rcr_inc(struct bm_rcr *rcr) | ||
272 | { | ||
273 | /* increment to the next RCR pointer and handle overflow and 'vbit' */ | ||
274 | struct bm_rcr_entry *partial = rcr->cursor + 1; | ||
275 | |||
276 | rcr->cursor = rcr_carryclear(partial); | ||
277 | if (partial != rcr->cursor) | ||
278 | rcr->vbit ^= BM_RCR_VERB_VBIT; | ||
279 | } | ||
280 | |||
281 | static int bm_rcr_get_avail(struct bm_portal *portal) | ||
282 | { | ||
283 | struct bm_rcr *rcr = &portal->rcr; | ||
284 | |||
285 | return rcr->available; | ||
286 | } | ||
287 | |||
288 | static int bm_rcr_get_fill(struct bm_portal *portal) | ||
289 | { | ||
290 | struct bm_rcr *rcr = &portal->rcr; | ||
291 | |||
292 | return BM_RCR_SIZE - 1 - rcr->available; | ||
293 | } | ||
294 | |||
295 | static void bm_rcr_set_ithresh(struct bm_portal *portal, u8 ithresh) | ||
296 | { | ||
297 | struct bm_rcr *rcr = &portal->rcr; | ||
298 | |||
299 | rcr->ithresh = ithresh; | ||
300 | bm_out(portal, BM_REG_RCR_ITR, ithresh); | ||
301 | } | ||
302 | |||
303 | static void bm_rcr_cce_prefetch(struct bm_portal *portal) | ||
304 | { | ||
305 | __maybe_unused struct bm_rcr *rcr = &portal->rcr; | ||
306 | |||
307 | DPAA_ASSERT(rcr->cmode == bm_rcr_cce); | ||
308 | bm_cl_touch_ro(portal, BM_CL_RCR_CI_CENA); | ||
309 | } | ||
310 | |||
311 | static u8 bm_rcr_cce_update(struct bm_portal *portal) | ||
312 | { | ||
313 | struct bm_rcr *rcr = &portal->rcr; | ||
314 | u8 diff, old_ci = rcr->ci; | ||
315 | |||
316 | DPAA_ASSERT(rcr->cmode == bm_rcr_cce); | ||
317 | rcr->ci = bm_ce_in(portal, BM_CL_RCR_CI_CENA) & (BM_RCR_SIZE - 1); | ||
318 | bm_cl_invalidate(portal, BM_CL_RCR_CI_CENA); | ||
319 | diff = dpaa_cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci); | ||
320 | rcr->available += diff; | ||
321 | return diff; | ||
322 | } | ||
323 | |||
324 | static inline struct bm_rcr_entry *bm_rcr_start(struct bm_portal *portal) | ||
325 | { | ||
326 | struct bm_rcr *rcr = &portal->rcr; | ||
327 | |||
328 | DPAA_ASSERT(!rcr->busy); | ||
329 | if (!rcr->available) | ||
330 | return NULL; | ||
331 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
332 | rcr->busy = 1; | ||
333 | #endif | ||
334 | dpaa_zero(rcr->cursor); | ||
335 | return rcr->cursor; | ||
336 | } | ||
337 | |||
338 | static inline void bm_rcr_pvb_commit(struct bm_portal *portal, u8 myverb) | ||
339 | { | ||
340 | struct bm_rcr *rcr = &portal->rcr; | ||
341 | struct bm_rcr_entry *rcursor; | ||
342 | |||
343 | DPAA_ASSERT(rcr->busy); | ||
344 | DPAA_ASSERT(rcr->pmode == bm_rcr_pvb); | ||
345 | DPAA_ASSERT(rcr->available >= 1); | ||
346 | dma_wmb(); | ||
347 | rcursor = rcr->cursor; | ||
348 | rcursor->_ncw_verb = myverb | rcr->vbit; | ||
349 | dpaa_flush(rcursor); | ||
350 | rcr_inc(rcr); | ||
351 | rcr->available--; | ||
352 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
353 | rcr->busy = 0; | ||
354 | #endif | ||
355 | } | ||
356 | |||
357 | static int bm_rcr_init(struct bm_portal *portal, enum bm_rcr_pmode pmode, | ||
358 | enum bm_rcr_cmode cmode) | ||
359 | { | ||
360 | struct bm_rcr *rcr = &portal->rcr; | ||
361 | u32 cfg; | ||
362 | u8 pi; | ||
363 | |||
364 | rcr->ring = portal->addr.ce + BM_CL_RCR; | ||
365 | rcr->ci = bm_in(portal, BM_REG_RCR_CI_CINH) & (BM_RCR_SIZE - 1); | ||
366 | pi = bm_in(portal, BM_REG_RCR_PI_CINH) & (BM_RCR_SIZE - 1); | ||
367 | rcr->cursor = rcr->ring + pi; | ||
368 | rcr->vbit = (bm_in(portal, BM_REG_RCR_PI_CINH) & BM_RCR_SIZE) ? | ||
369 | BM_RCR_VERB_VBIT : 0; | ||
370 | rcr->available = BM_RCR_SIZE - 1 | ||
371 | - dpaa_cyc_diff(BM_RCR_SIZE, rcr->ci, pi); | ||
372 | rcr->ithresh = bm_in(portal, BM_REG_RCR_ITR); | ||
373 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
374 | rcr->busy = 0; | ||
375 | rcr->pmode = pmode; | ||
376 | rcr->cmode = cmode; | ||
377 | #endif | ||
378 | cfg = (bm_in(portal, BM_REG_CFG) & 0xffffffe0) | ||
379 | | (pmode & 0x3); /* BCSP_CFG::RPM */ | ||
380 | bm_out(portal, BM_REG_CFG, cfg); | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static void bm_rcr_finish(struct bm_portal *portal) | ||
385 | { | ||
386 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
387 | struct bm_rcr *rcr = &portal->rcr; | ||
388 | int i; | ||
389 | |||
390 | DPAA_ASSERT(!rcr->busy); | ||
391 | |||
392 | i = bm_in(portal, BM_REG_RCR_PI_CINH) & (BM_RCR_SIZE - 1); | ||
393 | if (i != rcr_ptr2idx(rcr->cursor)) | ||
394 | pr_crit("losing uncommited RCR entries\n"); | ||
395 | |||
396 | i = bm_in(portal, BM_REG_RCR_CI_CINH) & (BM_RCR_SIZE - 1); | ||
397 | if (i != rcr->ci) | ||
398 | pr_crit("missing existing RCR completions\n"); | ||
399 | if (rcr->ci != rcr_ptr2idx(rcr->cursor)) | ||
400 | pr_crit("RCR destroyed unquiesced\n"); | ||
401 | #endif | ||
402 | } | ||
403 | |||
404 | /* --- Management command API --- */ | ||
405 | static int bm_mc_init(struct bm_portal *portal) | ||
406 | { | ||
407 | struct bm_mc *mc = &portal->mc; | ||
408 | |||
409 | mc->cr = portal->addr.ce + BM_CL_CR; | ||
410 | mc->rr = portal->addr.ce + BM_CL_RR0; | ||
411 | mc->rridx = (__raw_readb(&mc->cr->_ncw_verb) & BM_MCC_VERB_VBIT) ? | ||
412 | 0 : 1; | ||
413 | mc->vbit = mc->rridx ? BM_MCC_VERB_VBIT : 0; | ||
414 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
415 | mc->state = mc_idle; | ||
416 | #endif | ||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | static void bm_mc_finish(struct bm_portal *portal) | ||
421 | { | ||
422 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
423 | struct bm_mc *mc = &portal->mc; | ||
424 | |||
425 | DPAA_ASSERT(mc->state == mc_idle); | ||
426 | if (mc->state != mc_idle) | ||
427 | pr_crit("Losing incomplete MC command\n"); | ||
428 | #endif | ||
429 | } | ||
430 | |||
431 | static inline struct bm_mc_command *bm_mc_start(struct bm_portal *portal) | ||
432 | { | ||
433 | struct bm_mc *mc = &portal->mc; | ||
434 | |||
435 | DPAA_ASSERT(mc->state == mc_idle); | ||
436 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
437 | mc->state = mc_user; | ||
438 | #endif | ||
439 | dpaa_zero(mc->cr); | ||
440 | return mc->cr; | ||
441 | } | ||
442 | |||
443 | static inline void bm_mc_commit(struct bm_portal *portal, u8 myverb) | ||
444 | { | ||
445 | struct bm_mc *mc = &portal->mc; | ||
446 | union bm_mc_result *rr = mc->rr + mc->rridx; | ||
447 | |||
448 | DPAA_ASSERT(mc->state == mc_user); | ||
449 | dma_wmb(); | ||
450 | mc->cr->_ncw_verb = myverb | mc->vbit; | ||
451 | dpaa_flush(mc->cr); | ||
452 | dpaa_invalidate_touch_ro(rr); | ||
453 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
454 | mc->state = mc_hw; | ||
455 | #endif | ||
456 | } | ||
457 | |||
458 | static inline union bm_mc_result *bm_mc_result(struct bm_portal *portal) | ||
459 | { | ||
460 | struct bm_mc *mc = &portal->mc; | ||
461 | union bm_mc_result *rr = mc->rr + mc->rridx; | ||
462 | |||
463 | DPAA_ASSERT(mc->state == mc_hw); | ||
464 | /* | ||
465 | * The inactive response register's verb byte always returns zero until | ||
466 | * its command is submitted and completed. This includes the valid-bit, | ||
467 | * in case you were wondering... | ||
468 | */ | ||
469 | if (!__raw_readb(&rr->verb)) { | ||
470 | dpaa_invalidate_touch_ro(rr); | ||
471 | return NULL; | ||
472 | } | ||
473 | mc->rridx ^= 1; | ||
474 | mc->vbit ^= BM_MCC_VERB_VBIT; | ||
475 | #ifdef CONFIG_FSL_DPAA_CHECKING | ||
476 | mc->state = mc_idle; | ||
477 | #endif | ||
478 | return rr; | ||
479 | } | ||
480 | |||
481 | static inline int bm_mc_result_timeout(struct bm_portal *portal, | ||
482 | union bm_mc_result **mcr) | ||
483 | { | ||
484 | int timeout = BM_MCR_TIMEOUT; | ||
485 | |||
486 | do { | ||
487 | *mcr = bm_mc_result(portal); | ||
488 | if (*mcr) | ||
489 | break; | ||
490 | udelay(1); | ||
491 | } while (--timeout); | ||
492 | |||
493 | return timeout; | ||
494 | } | ||
495 | |||
496 | /* Disable all BSCN interrupts for the portal */ | ||
497 | static void bm_isr_bscn_disable(struct bm_portal *portal) | ||
498 | { | ||
499 | bm_out(portal, BM_REG_SCN(0), 0); | ||
500 | bm_out(portal, BM_REG_SCN(1), 0); | ||
501 | } | ||
502 | |||
503 | static int bman_create_portal(struct bman_portal *portal, | ||
504 | const struct bm_portal_config *c) | ||
505 | { | ||
506 | struct bm_portal *p; | ||
507 | int ret; | ||
508 | |||
509 | p = &portal->p; | ||
510 | /* | ||
511 | * prep the low-level portal struct with the mapped addresses from the | ||
512 | * config, everything that follows depends on it and "config" is more | ||
513 | * for (de)reference... | ||
514 | */ | ||
515 | p->addr.ce = c->addr_virt[DPAA_PORTAL_CE]; | ||
516 | p->addr.ci = c->addr_virt[DPAA_PORTAL_CI]; | ||
517 | if (bm_rcr_init(p, bm_rcr_pvb, bm_rcr_cce)) { | ||
518 | dev_err(c->dev, "RCR initialisation failed\n"); | ||
519 | goto fail_rcr; | ||
520 | } | ||
521 | if (bm_mc_init(p)) { | ||
522 | dev_err(c->dev, "MC initialisation failed\n"); | ||
523 | goto fail_mc; | ||
524 | } | ||
525 | /* | ||
526 | * Default to all BPIDs disabled, we enable as required at | ||
527 | * run-time. | ||
528 | */ | ||
529 | bm_isr_bscn_disable(p); | ||
530 | |||
531 | /* Write-to-clear any stale interrupt status bits */ | ||
532 | bm_out(p, BM_REG_ISDR, 0xffffffff); | ||
533 | portal->irq_sources = 0; | ||
534 | bm_out(p, BM_REG_IER, 0); | ||
535 | bm_out(p, BM_REG_ISR, 0xffffffff); | ||
536 | snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu); | ||
537 | if (request_irq(c->irq, portal_isr, 0, portal->irqname, portal)) { | ||
538 | dev_err(c->dev, "request_irq() failed\n"); | ||
539 | goto fail_irq; | ||
540 | } | ||
541 | if (c->cpu != -1 && irq_can_set_affinity(c->irq) && | ||
542 | irq_set_affinity(c->irq, cpumask_of(c->cpu))) { | ||
543 | dev_err(c->dev, "irq_set_affinity() failed\n"); | ||
544 | goto fail_affinity; | ||
545 | } | ||
546 | |||
547 | /* Need RCR to be empty before continuing */ | ||
548 | ret = bm_rcr_get_fill(p); | ||
549 | if (ret) { | ||
550 | dev_err(c->dev, "RCR unclean\n"); | ||
551 | goto fail_rcr_empty; | ||
552 | } | ||
553 | /* Success */ | ||
554 | portal->config = c; | ||
555 | |||
556 | bm_out(p, BM_REG_ISDR, 0); | ||
557 | bm_out(p, BM_REG_IIR, 0); | ||
558 | |||
559 | return 0; | ||
560 | |||
561 | fail_rcr_empty: | ||
562 | fail_affinity: | ||
563 | free_irq(c->irq, portal); | ||
564 | fail_irq: | ||
565 | bm_mc_finish(p); | ||
566 | fail_mc: | ||
567 | bm_rcr_finish(p); | ||
568 | fail_rcr: | ||
569 | return -EIO; | ||
570 | } | ||
571 | |||
572 | struct bman_portal *bman_create_affine_portal(const struct bm_portal_config *c) | ||
573 | { | ||
574 | struct bman_portal *portal; | ||
575 | int err; | ||
576 | |||
577 | portal = &per_cpu(bman_affine_portal, c->cpu); | ||
578 | err = bman_create_portal(portal, c); | ||
579 | if (err) | ||
580 | return NULL; | ||
581 | |||
582 | spin_lock(&affine_mask_lock); | ||
583 | cpumask_set_cpu(c->cpu, &affine_mask); | ||
584 | spin_unlock(&affine_mask_lock); | ||
585 | |||
586 | return portal; | ||
587 | } | ||
588 | |||
589 | static u32 poll_portal_slow(struct bman_portal *p, u32 is) | ||
590 | { | ||
591 | u32 ret = is; | ||
592 | |||
593 | if (is & BM_PIRQ_RCRI) { | ||
594 | bm_rcr_cce_update(&p->p); | ||
595 | bm_rcr_set_ithresh(&p->p, 0); | ||
596 | bm_out(&p->p, BM_REG_ISR, BM_PIRQ_RCRI); | ||
597 | is &= ~BM_PIRQ_RCRI; | ||
598 | } | ||
599 | |||
600 | /* There should be no status register bits left undefined */ | ||
601 | DPAA_ASSERT(!is); | ||
602 | return ret; | ||
603 | } | ||
604 | |||
605 | int bman_p_irqsource_add(struct bman_portal *p, u32 bits) | ||
606 | { | ||
607 | unsigned long irqflags; | ||
608 | |||
609 | local_irq_save(irqflags); | ||
610 | set_bits(bits & BM_PIRQ_VISIBLE, &p->irq_sources); | ||
611 | bm_out(&p->p, BM_REG_IER, p->irq_sources); | ||
612 | local_irq_restore(irqflags); | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static int bm_shutdown_pool(u32 bpid) | ||
617 | { | ||
618 | struct bm_mc_command *bm_cmd; | ||
619 | union bm_mc_result *bm_res; | ||
620 | |||
621 | while (1) { | ||
622 | struct bman_portal *p = get_affine_portal(); | ||
623 | /* Acquire buffers until empty */ | ||
624 | bm_cmd = bm_mc_start(&p->p); | ||
625 | bm_cmd->bpid = bpid; | ||
626 | bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE | 1); | ||
627 | if (!bm_mc_result_timeout(&p->p, &bm_res)) { | ||
628 | put_affine_portal(); | ||
629 | pr_crit("BMan Acquire Command timedout\n"); | ||
630 | return -ETIMEDOUT; | ||
631 | } | ||
632 | if (!(bm_res->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT)) { | ||
633 | put_affine_portal(); | ||
634 | /* Pool is empty */ | ||
635 | return 0; | ||
636 | } | ||
637 | put_affine_portal(); | ||
638 | } | ||
639 | |||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | struct gen_pool *bm_bpalloc; | ||
644 | |||
645 | static int bm_alloc_bpid_range(u32 *result, u32 count) | ||
646 | { | ||
647 | unsigned long addr; | ||
648 | |||
649 | addr = gen_pool_alloc(bm_bpalloc, count); | ||
650 | if (!addr) | ||
651 | return -ENOMEM; | ||
652 | |||
653 | *result = addr & ~DPAA_GENALLOC_OFF; | ||
654 | |||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static int bm_release_bpid(u32 bpid) | ||
659 | { | ||
660 | int ret; | ||
661 | |||
662 | ret = bm_shutdown_pool(bpid); | ||
663 | if (ret) { | ||
664 | pr_debug("BPID %d leaked\n", bpid); | ||
665 | return ret; | ||
666 | } | ||
667 | |||
668 | gen_pool_free(bm_bpalloc, bpid | DPAA_GENALLOC_OFF, 1); | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | struct bman_pool *bman_new_pool(void) | ||
673 | { | ||
674 | struct bman_pool *pool = NULL; | ||
675 | u32 bpid; | ||
676 | |||
677 | if (bm_alloc_bpid_range(&bpid, 1)) | ||
678 | return NULL; | ||
679 | |||
680 | pool = kmalloc(sizeof(*pool), GFP_KERNEL); | ||
681 | if (!pool) | ||
682 | goto err; | ||
683 | |||
684 | pool->bpid = bpid; | ||
685 | |||
686 | return pool; | ||
687 | err: | ||
688 | bm_release_bpid(bpid); | ||
689 | kfree(pool); | ||
690 | return NULL; | ||
691 | } | ||
692 | EXPORT_SYMBOL(bman_new_pool); | ||
693 | |||
694 | void bman_free_pool(struct bman_pool *pool) | ||
695 | { | ||
696 | bm_release_bpid(pool->bpid); | ||
697 | |||
698 | kfree(pool); | ||
699 | } | ||
700 | EXPORT_SYMBOL(bman_free_pool); | ||
701 | |||
702 | int bman_get_bpid(const struct bman_pool *pool) | ||
703 | { | ||
704 | return pool->bpid; | ||
705 | } | ||
706 | EXPORT_SYMBOL(bman_get_bpid); | ||
707 | |||
708 | static void update_rcr_ci(struct bman_portal *p, int avail) | ||
709 | { | ||
710 | if (avail) | ||
711 | bm_rcr_cce_prefetch(&p->p); | ||
712 | else | ||
713 | bm_rcr_cce_update(&p->p); | ||
714 | } | ||
715 | |||
716 | int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num) | ||
717 | { | ||
718 | struct bman_portal *p; | ||
719 | struct bm_rcr_entry *r; | ||
720 | unsigned long irqflags; | ||
721 | int avail, timeout = 1000; /* 1ms */ | ||
722 | int i = num - 1; | ||
723 | |||
724 | DPAA_ASSERT(num > 0 && num <= 8); | ||
725 | |||
726 | do { | ||
727 | p = get_affine_portal(); | ||
728 | local_irq_save(irqflags); | ||
729 | avail = bm_rcr_get_avail(&p->p); | ||
730 | if (avail < 2) | ||
731 | update_rcr_ci(p, avail); | ||
732 | r = bm_rcr_start(&p->p); | ||
733 | local_irq_restore(irqflags); | ||
734 | put_affine_portal(); | ||
735 | if (likely(r)) | ||
736 | break; | ||
737 | |||
738 | udelay(1); | ||
739 | } while (--timeout); | ||
740 | |||
741 | if (unlikely(!timeout)) | ||
742 | return -ETIMEDOUT; | ||
743 | |||
744 | p = get_affine_portal(); | ||
745 | local_irq_save(irqflags); | ||
746 | /* | ||
747 | * we can copy all but the first entry, as this can trigger badness | ||
748 | * with the valid-bit | ||
749 | */ | ||
750 | bm_buffer_set64(r->bufs, bm_buffer_get64(bufs)); | ||
751 | bm_buffer_set_bpid(r->bufs, pool->bpid); | ||
752 | if (i) | ||
753 | memcpy(&r->bufs[1], &bufs[1], i * sizeof(bufs[0])); | ||
754 | |||
755 | bm_rcr_pvb_commit(&p->p, BM_RCR_VERB_CMD_BPID_SINGLE | | ||
756 | (num & BM_RCR_VERB_BUFCOUNT_MASK)); | ||
757 | |||
758 | local_irq_restore(irqflags); | ||
759 | put_affine_portal(); | ||
760 | return 0; | ||
761 | } | ||
762 | EXPORT_SYMBOL(bman_release); | ||
763 | |||
764 | int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num) | ||
765 | { | ||
766 | struct bman_portal *p = get_affine_portal(); | ||
767 | struct bm_mc_command *mcc; | ||
768 | union bm_mc_result *mcr; | ||
769 | int ret; | ||
770 | |||
771 | DPAA_ASSERT(num > 0 && num <= 8); | ||
772 | |||
773 | mcc = bm_mc_start(&p->p); | ||
774 | mcc->bpid = pool->bpid; | ||
775 | bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE | | ||
776 | (num & BM_MCC_VERB_ACQUIRE_BUFCOUNT)); | ||
777 | if (!bm_mc_result_timeout(&p->p, &mcr)) { | ||
778 | put_affine_portal(); | ||
779 | pr_crit("BMan Acquire Timeout\n"); | ||
780 | return -ETIMEDOUT; | ||
781 | } | ||
782 | ret = mcr->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT; | ||
783 | if (bufs) | ||
784 | memcpy(&bufs[0], &mcr->bufs[0], num * sizeof(bufs[0])); | ||
785 | |||
786 | put_affine_portal(); | ||
787 | if (ret != num) | ||
788 | ret = -ENOMEM; | ||
789 | return ret; | ||
790 | } | ||
791 | EXPORT_SYMBOL(bman_acquire); | ||
792 | |||
793 | const struct bm_portal_config * | ||
794 | bman_get_bm_portal_config(const struct bman_portal *portal) | ||
795 | { | ||
796 | return portal->config; | ||
797 | } | ||