]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * Copyright (c) 2016 QLogic Corporation. | |
3 | * All rights reserved. | |
4 | * www.qlogic.com | |
5 | * | |
6 | * See LICENSE.qede_pmd for copyright and licensing details. | |
7 | */ | |
8 | ||
9 | #ifndef __ECORE_CHAIN_H__ | |
10 | #define __ECORE_CHAIN_H__ | |
11 | ||
12 | #include <assert.h> /* @DPDK */ | |
13 | ||
14 | #include "common_hsi.h" | |
15 | #include "ecore_utils.h" | |
16 | ||
17 | enum ecore_chain_mode { | |
18 | /* Each Page contains a next pointer at its end */ | |
19 | ECORE_CHAIN_MODE_NEXT_PTR, | |
20 | ||
21 | /* Chain is a single page (next ptr) is unrequired */ | |
22 | ECORE_CHAIN_MODE_SINGLE, | |
23 | ||
24 | /* Page pointers are located in a side list */ | |
25 | ECORE_CHAIN_MODE_PBL, | |
26 | }; | |
27 | ||
28 | enum ecore_chain_use_mode { | |
29 | ECORE_CHAIN_USE_TO_PRODUCE, /* Chain starts empty */ | |
30 | ECORE_CHAIN_USE_TO_CONSUME, /* Chain starts full */ | |
31 | ECORE_CHAIN_USE_TO_CONSUME_PRODUCE, /* Chain starts empty */ | |
32 | }; | |
33 | ||
34 | enum ecore_chain_cnt_type { | |
35 | /* The chain's size/prod/cons are kept in 16-bit variables */ | |
36 | ECORE_CHAIN_CNT_TYPE_U16, | |
37 | ||
38 | /* The chain's size/prod/cons are kept in 32-bit variables */ | |
39 | ECORE_CHAIN_CNT_TYPE_U32, | |
40 | }; | |
41 | ||
42 | struct ecore_chain_next { | |
43 | struct regpair next_phys; | |
44 | void *next_virt; | |
45 | }; | |
46 | ||
47 | struct ecore_chain_pbl_u16 { | |
48 | u16 prod_page_idx; | |
49 | u16 cons_page_idx; | |
50 | }; | |
51 | ||
52 | struct ecore_chain_pbl_u32 { | |
53 | u32 prod_page_idx; | |
54 | u32 cons_page_idx; | |
55 | }; | |
56 | ||
57 | struct ecore_chain_pbl { | |
58 | /* Base address of a pre-allocated buffer for pbl */ | |
59 | dma_addr_t p_phys_table; | |
60 | void *p_virt_table; | |
61 | ||
62 | /* Table for keeping the virtual addresses of the chain pages, | |
63 | * respectively to the physical addresses in the pbl table. | |
64 | */ | |
65 | void **pp_virt_addr_tbl; | |
66 | ||
67 | /* Index to current used page by producer/consumer */ | |
68 | union { | |
69 | struct ecore_chain_pbl_u16 pbl16; | |
70 | struct ecore_chain_pbl_u32 pbl32; | |
71 | } u; | |
72 | }; | |
73 | ||
74 | struct ecore_chain_u16 { | |
75 | /* Cyclic index of next element to produce/consme */ | |
76 | u16 prod_idx; | |
77 | u16 cons_idx; | |
78 | }; | |
79 | ||
80 | struct ecore_chain_u32 { | |
81 | /* Cyclic index of next element to produce/consme */ | |
82 | u32 prod_idx; | |
83 | u32 cons_idx; | |
84 | }; | |
85 | ||
86 | struct ecore_chain { | |
87 | /* Address of first page of the chain */ | |
88 | void *p_virt_addr; | |
89 | dma_addr_t p_phys_addr; | |
90 | ||
91 | /* Point to next element to produce/consume */ | |
92 | void *p_prod_elem; | |
93 | void *p_cons_elem; | |
94 | ||
95 | enum ecore_chain_mode mode; | |
96 | enum ecore_chain_use_mode intended_use; | |
97 | ||
98 | enum ecore_chain_cnt_type cnt_type; | |
99 | union { | |
100 | struct ecore_chain_u16 chain16; | |
101 | struct ecore_chain_u32 chain32; | |
102 | } u; | |
103 | ||
104 | u32 page_cnt; | |
105 | ||
106 | /* Number of elements - capacity is for usable elements only, | |
107 | * while size will contain total number of elements [for entire chain]. | |
108 | */ | |
109 | u32 capacity; | |
110 | u32 size; | |
111 | ||
112 | /* Elements information for fast calculations */ | |
113 | u16 elem_per_page; | |
114 | u16 elem_per_page_mask; | |
115 | u16 elem_unusable; | |
116 | u16 usable_per_page; | |
117 | u16 elem_size; | |
118 | u16 next_page_mask; | |
119 | ||
120 | struct ecore_chain_pbl pbl; | |
121 | ||
122 | void *dp_ctx; | |
123 | }; | |
124 | ||
125 | #define ECORE_CHAIN_PBL_ENTRY_SIZE (8) | |
126 | #define ECORE_CHAIN_PAGE_SIZE (0x1000) | |
127 | #define ELEMS_PER_PAGE(elem_size) (ECORE_CHAIN_PAGE_SIZE / (elem_size)) | |
128 | ||
129 | #define UNUSABLE_ELEMS_PER_PAGE(elem_size, mode) \ | |
130 | ((mode == ECORE_CHAIN_MODE_NEXT_PTR) ? \ | |
131 | (1 + ((sizeof(struct ecore_chain_next) - 1) / \ | |
132 | (elem_size))) : 0) | |
133 | ||
134 | #define USABLE_ELEMS_PER_PAGE(elem_size, mode) \ | |
135 | ((u32)(ELEMS_PER_PAGE(elem_size) - \ | |
136 | UNUSABLE_ELEMS_PER_PAGE(elem_size, mode))) | |
137 | ||
138 | #define ECORE_CHAIN_PAGE_CNT(elem_cnt, elem_size, mode) \ | |
139 | DIV_ROUND_UP(elem_cnt, USABLE_ELEMS_PER_PAGE(elem_size, mode)) | |
140 | ||
141 | #define is_chain_u16(p) ((p)->cnt_type == ECORE_CHAIN_CNT_TYPE_U16) | |
142 | #define is_chain_u32(p) ((p)->cnt_type == ECORE_CHAIN_CNT_TYPE_U32) | |
143 | ||
144 | /* Accessors */ | |
145 | static OSAL_INLINE u16 ecore_chain_get_prod_idx(struct ecore_chain *p_chain) | |
146 | { | |
147 | OSAL_ASSERT(is_chain_u16(p_chain)); | |
148 | return p_chain->u.chain16.prod_idx; | |
149 | } | |
150 | ||
151 | static OSAL_INLINE u32 ecore_chain_get_prod_idx_u32(struct ecore_chain *p_chain) | |
152 | { | |
153 | OSAL_ASSERT(is_chain_u32(p_chain)); | |
154 | return p_chain->u.chain32.prod_idx; | |
155 | } | |
156 | ||
157 | static OSAL_INLINE u16 ecore_chain_get_cons_idx(struct ecore_chain *p_chain) | |
158 | { | |
159 | OSAL_ASSERT(is_chain_u16(p_chain)); | |
160 | return p_chain->u.chain16.cons_idx; | |
161 | } | |
162 | ||
163 | static OSAL_INLINE u32 ecore_chain_get_cons_idx_u32(struct ecore_chain *p_chain) | |
164 | { | |
165 | OSAL_ASSERT(is_chain_u32(p_chain)); | |
166 | return p_chain->u.chain32.cons_idx; | |
167 | } | |
168 | ||
169 | /* FIXME: | |
170 | * Should create OSALs for the below definitions. | |
171 | * For Linux, replace them with the existing U16_MAX and U32_MAX, and handle | |
172 | * kernel versions that lack them. | |
173 | */ | |
174 | #define ECORE_U16_MAX ((u16)~0U) | |
175 | #define ECORE_U32_MAX ((u32)~0U) | |
176 | ||
177 | static OSAL_INLINE u16 ecore_chain_get_elem_left(struct ecore_chain *p_chain) | |
178 | { | |
179 | u16 used; | |
180 | ||
181 | OSAL_ASSERT(is_chain_u16(p_chain)); | |
182 | ||
183 | used = (u16)(((u32)ECORE_U16_MAX + 1 + | |
184 | (u32)(p_chain->u.chain16.prod_idx)) - | |
185 | (u32)p_chain->u.chain16.cons_idx); | |
186 | if (p_chain->mode == ECORE_CHAIN_MODE_NEXT_PTR) | |
187 | used -= p_chain->u.chain16.prod_idx / p_chain->elem_per_page - | |
188 | p_chain->u.chain16.cons_idx / p_chain->elem_per_page; | |
189 | ||
190 | return (u16)(p_chain->capacity - used); | |
191 | } | |
192 | ||
193 | static OSAL_INLINE u32 | |
194 | ecore_chain_get_elem_left_u32(struct ecore_chain *p_chain) | |
195 | { | |
196 | u32 used; | |
197 | ||
198 | OSAL_ASSERT(is_chain_u32(p_chain)); | |
199 | ||
200 | used = (u32)(((u64)ECORE_U32_MAX + 1 + | |
201 | (u64)(p_chain->u.chain32.prod_idx)) - | |
202 | (u64)p_chain->u.chain32.cons_idx); | |
203 | if (p_chain->mode == ECORE_CHAIN_MODE_NEXT_PTR) | |
204 | used -= p_chain->u.chain32.prod_idx / p_chain->elem_per_page - | |
205 | p_chain->u.chain32.cons_idx / p_chain->elem_per_page; | |
206 | ||
207 | return p_chain->capacity - used; | |
208 | } | |
209 | ||
210 | static OSAL_INLINE u8 ecore_chain_is_full(struct ecore_chain *p_chain) | |
211 | { | |
212 | if (is_chain_u16(p_chain)) | |
213 | return (ecore_chain_get_elem_left(p_chain) == | |
214 | p_chain->capacity); | |
215 | else | |
216 | return (ecore_chain_get_elem_left_u32(p_chain) == | |
217 | p_chain->capacity); | |
218 | } | |
219 | ||
220 | static OSAL_INLINE u8 ecore_chain_is_empty(struct ecore_chain *p_chain) | |
221 | { | |
222 | if (is_chain_u16(p_chain)) | |
223 | return (ecore_chain_get_elem_left(p_chain) == 0); | |
224 | else | |
225 | return (ecore_chain_get_elem_left_u32(p_chain) == 0); | |
226 | } | |
227 | ||
228 | static OSAL_INLINE | |
229 | u16 ecore_chain_get_elem_per_page(struct ecore_chain *p_chain) | |
230 | { | |
231 | return p_chain->elem_per_page; | |
232 | } | |
233 | ||
234 | static OSAL_INLINE | |
235 | u16 ecore_chain_get_usable_per_page(struct ecore_chain *p_chain) | |
236 | { | |
237 | return p_chain->usable_per_page; | |
238 | } | |
239 | ||
240 | static OSAL_INLINE | |
241 | u16 ecore_chain_get_unusable_per_page(struct ecore_chain *p_chain) | |
242 | { | |
243 | return p_chain->elem_unusable; | |
244 | } | |
245 | ||
246 | static OSAL_INLINE u32 ecore_chain_get_size(struct ecore_chain *p_chain) | |
247 | { | |
248 | return p_chain->size; | |
249 | } | |
250 | ||
251 | static OSAL_INLINE u32 ecore_chain_get_page_cnt(struct ecore_chain *p_chain) | |
252 | { | |
253 | return p_chain->page_cnt; | |
254 | } | |
255 | ||
256 | static OSAL_INLINE | |
257 | dma_addr_t ecore_chain_get_pbl_phys(struct ecore_chain *p_chain) | |
258 | { | |
259 | return p_chain->pbl.p_phys_table; | |
260 | } | |
261 | ||
262 | /** | |
263 | * @brief ecore_chain_advance_page - | |
264 | * | |
265 | * Advance the next element accros pages for a linked chain | |
266 | * | |
267 | * @param p_chain | |
268 | * @param p_next_elem | |
269 | * @param idx_to_inc | |
270 | * @param page_to_inc | |
271 | */ | |
272 | static OSAL_INLINE void | |
273 | ecore_chain_advance_page(struct ecore_chain *p_chain, void **p_next_elem, | |
274 | void *idx_to_inc, void *page_to_inc) | |
275 | { | |
276 | struct ecore_chain_next *p_next = OSAL_NULL; | |
277 | u32 page_index = 0; | |
278 | ||
279 | switch (p_chain->mode) { | |
280 | case ECORE_CHAIN_MODE_NEXT_PTR: | |
281 | p_next = (struct ecore_chain_next *)(*p_next_elem); | |
282 | *p_next_elem = p_next->next_virt; | |
283 | if (is_chain_u16(p_chain)) | |
284 | *(u16 *)idx_to_inc += p_chain->elem_unusable; | |
285 | else | |
286 | *(u32 *)idx_to_inc += p_chain->elem_unusable; | |
287 | break; | |
288 | case ECORE_CHAIN_MODE_SINGLE: | |
289 | *p_next_elem = p_chain->p_virt_addr; | |
290 | break; | |
291 | case ECORE_CHAIN_MODE_PBL: | |
292 | if (is_chain_u16(p_chain)) { | |
293 | if (++(*(u16 *)page_to_inc) == p_chain->page_cnt) | |
294 | *(u16 *)page_to_inc = 0; | |
295 | page_index = *(u16 *)page_to_inc; | |
296 | } else { | |
297 | if (++(*(u32 *)page_to_inc) == p_chain->page_cnt) | |
298 | *(u32 *)page_to_inc = 0; | |
299 | page_index = *(u32 *)page_to_inc; | |
300 | } | |
301 | *p_next_elem = p_chain->pbl.pp_virt_addr_tbl[page_index]; | |
302 | } | |
303 | } | |
304 | ||
305 | #define is_unusable_idx(p, idx) \ | |
306 | (((p)->u.chain16.idx & (p)->elem_per_page_mask) == (p)->usable_per_page) | |
307 | ||
308 | #define is_unusable_idx_u32(p, idx) \ | |
309 | (((p)->u.chain32.idx & (p)->elem_per_page_mask) == (p)->usable_per_page) | |
310 | ||
311 | #define is_unusable_next_idx(p, idx) \ | |
312 | ((((p)->u.chain16.idx + 1) & \ | |
313 | (p)->elem_per_page_mask) == (p)->usable_per_page) | |
314 | ||
315 | #define is_unusable_next_idx_u32(p, idx) \ | |
316 | ((((p)->u.chain32.idx + 1) & \ | |
317 | (p)->elem_per_page_mask) == (p)->usable_per_page) | |
318 | ||
319 | #define test_and_skip(p, idx) \ | |
320 | do { \ | |
321 | if (is_chain_u16(p)) { \ | |
322 | if (is_unusable_idx(p, idx)) \ | |
323 | (p)->u.chain16.idx += \ | |
324 | (p)->elem_unusable; \ | |
325 | } else { \ | |
326 | if (is_unusable_idx_u32(p, idx)) \ | |
327 | (p)->u.chain32.idx += \ | |
328 | (p)->elem_unusable; \ | |
329 | } \ | |
330 | } while (0) | |
331 | ||
332 | /** | |
333 | * @brief ecore_chain_return_multi_produced - | |
334 | * | |
335 | * A chain in which the driver "Produces" elements should use this API | |
336 | * to indicate previous produced elements are now consumed. | |
337 | * | |
338 | * @param p_chain | |
339 | * @param num | |
340 | */ | |
341 | static OSAL_INLINE | |
342 | void ecore_chain_return_multi_produced(struct ecore_chain *p_chain, u32 num) | |
343 | { | |
344 | if (is_chain_u16(p_chain)) | |
345 | p_chain->u.chain16.cons_idx += (u16)num; | |
346 | else | |
347 | p_chain->u.chain32.cons_idx += num; | |
348 | test_and_skip(p_chain, cons_idx); | |
349 | } | |
350 | ||
351 | /** | |
352 | * @brief ecore_chain_return_produced - | |
353 | * | |
354 | * A chain in which the driver "Produces" elements should use this API | |
355 | * to indicate previous produced elements are now consumed. | |
356 | * | |
357 | * @param p_chain | |
358 | */ | |
359 | static OSAL_INLINE void ecore_chain_return_produced(struct ecore_chain *p_chain) | |
360 | { | |
361 | if (is_chain_u16(p_chain)) | |
362 | p_chain->u.chain16.cons_idx++; | |
363 | else | |
364 | p_chain->u.chain32.cons_idx++; | |
365 | test_and_skip(p_chain, cons_idx); | |
366 | } | |
367 | ||
368 | /** | |
369 | * @brief ecore_chain_produce - | |
370 | * | |
371 | * A chain in which the driver "Produces" elements should use this to get | |
372 | * a pointer to the next element which can be "Produced". It's driver | |
373 | * responsibility to validate that the chain has room for new element. | |
374 | * | |
375 | * @param p_chain | |
376 | * | |
377 | * @return void*, a pointer to next element | |
378 | */ | |
379 | static OSAL_INLINE void *ecore_chain_produce(struct ecore_chain *p_chain) | |
380 | { | |
381 | void *p_ret = OSAL_NULL, *p_prod_idx, *p_prod_page_idx; | |
382 | ||
383 | if (is_chain_u16(p_chain)) { | |
384 | if ((p_chain->u.chain16.prod_idx & | |
385 | p_chain->elem_per_page_mask) == p_chain->next_page_mask) { | |
386 | p_prod_idx = &p_chain->u.chain16.prod_idx; | |
387 | p_prod_page_idx = &p_chain->pbl.u.pbl16.prod_page_idx; | |
388 | ecore_chain_advance_page(p_chain, &p_chain->p_prod_elem, | |
389 | p_prod_idx, p_prod_page_idx); | |
390 | } | |
391 | p_chain->u.chain16.prod_idx++; | |
392 | } else { | |
393 | if ((p_chain->u.chain32.prod_idx & | |
394 | p_chain->elem_per_page_mask) == p_chain->next_page_mask) { | |
395 | p_prod_idx = &p_chain->u.chain32.prod_idx; | |
396 | p_prod_page_idx = &p_chain->pbl.u.pbl32.prod_page_idx; | |
397 | ecore_chain_advance_page(p_chain, &p_chain->p_prod_elem, | |
398 | p_prod_idx, p_prod_page_idx); | |
399 | } | |
400 | p_chain->u.chain32.prod_idx++; | |
401 | } | |
402 | ||
403 | p_ret = p_chain->p_prod_elem; | |
404 | p_chain->p_prod_elem = (void *)(((u8 *)p_chain->p_prod_elem) + | |
405 | p_chain->elem_size); | |
406 | ||
407 | return p_ret; | |
408 | } | |
409 | ||
410 | /** | |
411 | * @brief ecore_chain_get_capacity - | |
412 | * | |
413 | * Get the maximum number of BDs in chain | |
414 | * | |
415 | * @param p_chain | |
416 | * @param num | |
417 | * | |
418 | * @return number of unusable BDs | |
419 | */ | |
420 | static OSAL_INLINE u32 ecore_chain_get_capacity(struct ecore_chain *p_chain) | |
421 | { | |
422 | return p_chain->capacity; | |
423 | } | |
424 | ||
425 | /** | |
426 | * @brief ecore_chain_recycle_consumed - | |
427 | * | |
428 | * Returns an element which was previously consumed; | |
429 | * Increments producers so they could be written to FW. | |
430 | * | |
431 | * @param p_chain | |
432 | */ | |
433 | static OSAL_INLINE | |
434 | void ecore_chain_recycle_consumed(struct ecore_chain *p_chain) | |
435 | { | |
436 | test_and_skip(p_chain, prod_idx); | |
437 | if (is_chain_u16(p_chain)) | |
438 | p_chain->u.chain16.prod_idx++; | |
439 | else | |
440 | p_chain->u.chain32.prod_idx++; | |
441 | } | |
442 | ||
443 | /** | |
444 | * @brief ecore_chain_consume - | |
445 | * | |
446 | * A Chain in which the driver utilizes data written by a different source | |
447 | * (i.e., FW) should use this to access passed buffers. | |
448 | * | |
449 | * @param p_chain | |
450 | * | |
451 | * @return void*, a pointer to the next buffer written | |
452 | */ | |
453 | static OSAL_INLINE void *ecore_chain_consume(struct ecore_chain *p_chain) | |
454 | { | |
455 | void *p_ret = OSAL_NULL, *p_cons_idx, *p_cons_page_idx; | |
456 | ||
457 | if (is_chain_u16(p_chain)) { | |
458 | if ((p_chain->u.chain16.cons_idx & | |
459 | p_chain->elem_per_page_mask) == p_chain->next_page_mask) { | |
460 | p_cons_idx = &p_chain->u.chain16.cons_idx; | |
461 | p_cons_page_idx = &p_chain->pbl.u.pbl16.cons_page_idx; | |
462 | ecore_chain_advance_page(p_chain, &p_chain->p_cons_elem, | |
463 | p_cons_idx, p_cons_page_idx); | |
464 | } | |
465 | p_chain->u.chain16.cons_idx++; | |
466 | } else { | |
467 | if ((p_chain->u.chain32.cons_idx & | |
468 | p_chain->elem_per_page_mask) == p_chain->next_page_mask) { | |
469 | p_cons_idx = &p_chain->u.chain32.cons_idx; | |
470 | p_cons_page_idx = &p_chain->pbl.u.pbl32.cons_page_idx; | |
471 | ecore_chain_advance_page(p_chain, &p_chain->p_cons_elem, | |
472 | p_cons_idx, p_cons_page_idx); | |
473 | } | |
474 | p_chain->u.chain32.cons_idx++; | |
475 | } | |
476 | ||
477 | p_ret = p_chain->p_cons_elem; | |
478 | p_chain->p_cons_elem = (void *)(((u8 *)p_chain->p_cons_elem) + | |
479 | p_chain->elem_size); | |
480 | ||
481 | return p_ret; | |
482 | } | |
483 | ||
484 | /** | |
485 | * @brief ecore_chain_reset - | |
486 | * | |
487 | * Resets the chain to its start state | |
488 | * | |
489 | * @param p_chain pointer to a previously allocted chain | |
490 | */ | |
491 | static OSAL_INLINE void ecore_chain_reset(struct ecore_chain *p_chain) | |
492 | { | |
493 | u32 i; | |
494 | ||
495 | if (is_chain_u16(p_chain)) { | |
496 | p_chain->u.chain16.prod_idx = 0; | |
497 | p_chain->u.chain16.cons_idx = 0; | |
498 | } else { | |
499 | p_chain->u.chain32.prod_idx = 0; | |
500 | p_chain->u.chain32.cons_idx = 0; | |
501 | } | |
502 | p_chain->p_cons_elem = p_chain->p_virt_addr; | |
503 | p_chain->p_prod_elem = p_chain->p_virt_addr; | |
504 | ||
505 | if (p_chain->mode == ECORE_CHAIN_MODE_PBL) { | |
506 | /* Use (page_cnt - 1) as a reset value for the prod/cons page's | |
507 | * indices, to avoid unnecessary page advancing on the first | |
508 | * call to ecore_chain_produce/consume. Instead, the indices | |
509 | * will be advanced to page_cnt and then will be wrapped to 0. | |
510 | */ | |
511 | u32 reset_val = p_chain->page_cnt - 1; | |
512 | ||
513 | if (is_chain_u16(p_chain)) { | |
514 | p_chain->pbl.u.pbl16.prod_page_idx = (u16)reset_val; | |
515 | p_chain->pbl.u.pbl16.cons_page_idx = (u16)reset_val; | |
516 | } else { | |
517 | p_chain->pbl.u.pbl32.prod_page_idx = reset_val; | |
518 | p_chain->pbl.u.pbl32.cons_page_idx = reset_val; | |
519 | } | |
520 | } | |
521 | ||
522 | switch (p_chain->intended_use) { | |
523 | case ECORE_CHAIN_USE_TO_CONSUME_PRODUCE: | |
524 | case ECORE_CHAIN_USE_TO_PRODUCE: | |
525 | /* Do nothing */ | |
526 | break; | |
527 | ||
528 | case ECORE_CHAIN_USE_TO_CONSUME: | |
529 | /* produce empty elements */ | |
530 | for (i = 0; i < p_chain->capacity; i++) | |
531 | ecore_chain_recycle_consumed(p_chain); | |
532 | break; | |
533 | } | |
534 | } | |
535 | ||
536 | /** | |
537 | * @brief ecore_chain_init_params - | |
538 | * | |
539 | * Initalizes a basic chain struct | |
540 | * | |
541 | * @param p_chain | |
542 | * @param page_cnt number of pages in the allocated buffer | |
543 | * @param elem_size size of each element in the chain | |
544 | * @param intended_use | |
545 | * @param mode | |
546 | * @param cnt_type | |
547 | * @param dp_ctx | |
548 | */ | |
549 | static OSAL_INLINE void | |
550 | ecore_chain_init_params(struct ecore_chain *p_chain, u32 page_cnt, u8 elem_size, | |
551 | enum ecore_chain_use_mode intended_use, | |
552 | enum ecore_chain_mode mode, | |
553 | enum ecore_chain_cnt_type cnt_type, void *dp_ctx) | |
554 | { | |
555 | /* chain fixed parameters */ | |
556 | p_chain->p_virt_addr = OSAL_NULL; | |
557 | p_chain->p_phys_addr = 0; | |
558 | p_chain->elem_size = elem_size; | |
559 | p_chain->intended_use = intended_use; | |
560 | p_chain->mode = mode; | |
561 | p_chain->cnt_type = cnt_type; | |
562 | ||
563 | p_chain->elem_per_page = ELEMS_PER_PAGE(elem_size); | |
564 | p_chain->usable_per_page = USABLE_ELEMS_PER_PAGE(elem_size, mode); | |
565 | p_chain->elem_per_page_mask = p_chain->elem_per_page - 1; | |
566 | p_chain->elem_unusable = UNUSABLE_ELEMS_PER_PAGE(elem_size, mode); | |
567 | p_chain->next_page_mask = (p_chain->usable_per_page & | |
568 | p_chain->elem_per_page_mask); | |
569 | ||
570 | p_chain->page_cnt = page_cnt; | |
571 | p_chain->capacity = p_chain->usable_per_page * page_cnt; | |
572 | p_chain->size = p_chain->elem_per_page * page_cnt; | |
573 | ||
574 | p_chain->pbl.p_phys_table = 0; | |
575 | p_chain->pbl.p_virt_table = OSAL_NULL; | |
576 | p_chain->pbl.pp_virt_addr_tbl = OSAL_NULL; | |
577 | ||
578 | p_chain->dp_ctx = dp_ctx; | |
579 | } | |
580 | ||
581 | /** | |
582 | * @brief ecore_chain_init_mem - | |
583 | * | |
584 | * Initalizes a basic chain struct with its chain buffers | |
585 | * | |
586 | * @param p_chain | |
587 | * @param p_virt_addr virtual address of allocated buffer's beginning | |
588 | * @param p_phys_addr physical address of allocated buffer's beginning | |
589 | * | |
590 | */ | |
591 | static OSAL_INLINE void ecore_chain_init_mem(struct ecore_chain *p_chain, | |
592 | void *p_virt_addr, | |
593 | dma_addr_t p_phys_addr) | |
594 | { | |
595 | p_chain->p_virt_addr = p_virt_addr; | |
596 | p_chain->p_phys_addr = p_phys_addr; | |
597 | } | |
598 | ||
599 | /** | |
600 | * @brief ecore_chain_init_pbl_mem - | |
601 | * | |
602 | * Initalizes a basic chain struct with its pbl buffers | |
603 | * | |
604 | * @param p_chain | |
605 | * @param p_virt_pbl pointer to a pre allocated side table which will hold | |
606 | * virtual page addresses. | |
607 | * @param p_phys_pbl pointer to a pre-allocated side table which will hold | |
608 | * physical page addresses. | |
609 | * @param pp_virt_addr_tbl | |
610 | * pointer to a pre-allocated side table which will hold | |
611 | * the virtual addresses of the chain pages. | |
612 | * | |
613 | */ | |
614 | static OSAL_INLINE void ecore_chain_init_pbl_mem(struct ecore_chain *p_chain, | |
615 | void *p_virt_pbl, | |
616 | dma_addr_t p_phys_pbl, | |
617 | void **pp_virt_addr_tbl) | |
618 | { | |
619 | p_chain->pbl.p_phys_table = p_phys_pbl; | |
620 | p_chain->pbl.p_virt_table = p_virt_pbl; | |
621 | p_chain->pbl.pp_virt_addr_tbl = pp_virt_addr_tbl; | |
622 | } | |
623 | ||
624 | /** | |
625 | * @brief ecore_chain_init_next_ptr_elem - | |
626 | * | |
627 | * Initalizes a next pointer element | |
628 | * | |
629 | * @param p_chain | |
630 | * @param p_virt_curr virtual address of a chain page of which the next | |
631 | * pointer element is initialized | |
632 | * @param p_virt_next virtual address of the next chain page | |
633 | * @param p_phys_next physical address of the next chain page | |
634 | * | |
635 | */ | |
636 | static OSAL_INLINE void | |
637 | ecore_chain_init_next_ptr_elem(struct ecore_chain *p_chain, void *p_virt_curr, | |
638 | void *p_virt_next, dma_addr_t p_phys_next) | |
639 | { | |
640 | struct ecore_chain_next *p_next; | |
641 | u32 size; | |
642 | ||
643 | size = p_chain->elem_size * p_chain->usable_per_page; | |
644 | p_next = (struct ecore_chain_next *)((u8 *)p_virt_curr + size); | |
645 | ||
646 | DMA_REGPAIR_LE(p_next->next_phys, p_phys_next); | |
647 | ||
648 | p_next->next_virt = p_virt_next; | |
649 | } | |
650 | ||
651 | /** | |
652 | * @brief ecore_chain_get_last_elem - | |
653 | * | |
654 | * Returns a pointer to the last element of the chain | |
655 | * | |
656 | * @param p_chain | |
657 | * | |
658 | * @return void* | |
659 | */ | |
660 | static OSAL_INLINE void *ecore_chain_get_last_elem(struct ecore_chain *p_chain) | |
661 | { | |
662 | struct ecore_chain_next *p_next = OSAL_NULL; | |
663 | void *p_virt_addr = OSAL_NULL; | |
664 | u32 size, last_page_idx; | |
665 | ||
666 | if (!p_chain->p_virt_addr) | |
667 | goto out; | |
668 | ||
669 | switch (p_chain->mode) { | |
670 | case ECORE_CHAIN_MODE_NEXT_PTR: | |
671 | size = p_chain->elem_size * p_chain->usable_per_page; | |
672 | p_virt_addr = p_chain->p_virt_addr; | |
673 | p_next = (struct ecore_chain_next *)((u8 *)p_virt_addr + size); | |
674 | while (p_next->next_virt != p_chain->p_virt_addr) { | |
675 | p_virt_addr = p_next->next_virt; | |
676 | p_next = | |
677 | (struct ecore_chain_next *)((u8 *)p_virt_addr + | |
678 | size); | |
679 | } | |
680 | break; | |
681 | case ECORE_CHAIN_MODE_SINGLE: | |
682 | p_virt_addr = p_chain->p_virt_addr; | |
683 | break; | |
684 | case ECORE_CHAIN_MODE_PBL: | |
685 | last_page_idx = p_chain->page_cnt - 1; | |
686 | p_virt_addr = p_chain->pbl.pp_virt_addr_tbl[last_page_idx]; | |
687 | break; | |
688 | } | |
689 | /* p_virt_addr points at this stage to the last page of the chain */ | |
690 | size = p_chain->elem_size * (p_chain->usable_per_page - 1); | |
691 | p_virt_addr = ((u8 *)p_virt_addr + size); | |
692 | out: | |
693 | return p_virt_addr; | |
694 | } | |
695 | ||
696 | /** | |
697 | * @brief ecore_chain_set_prod - sets the prod to the given value | |
698 | * | |
699 | * @param prod_idx | |
700 | * @param p_prod_elem | |
701 | */ | |
702 | static OSAL_INLINE void ecore_chain_set_prod(struct ecore_chain *p_chain, | |
703 | u32 prod_idx, void *p_prod_elem) | |
704 | { | |
705 | if (is_chain_u16(p_chain)) | |
706 | p_chain->u.chain16.prod_idx = (u16)prod_idx; | |
707 | else | |
708 | p_chain->u.chain32.prod_idx = prod_idx; | |
709 | p_chain->p_prod_elem = p_prod_elem; | |
710 | } | |
711 | ||
712 | /** | |
713 | * @brief ecore_chain_pbl_zero_mem - set chain memory to 0 | |
714 | * | |
715 | * @param p_chain | |
716 | */ | |
717 | static OSAL_INLINE void ecore_chain_pbl_zero_mem(struct ecore_chain *p_chain) | |
718 | { | |
719 | u32 i, page_cnt; | |
720 | ||
721 | if (p_chain->mode != ECORE_CHAIN_MODE_PBL) | |
722 | return; | |
723 | ||
724 | page_cnt = ecore_chain_get_page_cnt(p_chain); | |
725 | ||
726 | for (i = 0; i < page_cnt; i++) | |
727 | OSAL_MEM_ZERO(p_chain->pbl.pp_virt_addr_tbl[i], | |
728 | ECORE_CHAIN_PAGE_SIZE); | |
729 | } | |
730 | ||
731 | int ecore_chain_print(struct ecore_chain *p_chain, char *buffer, | |
732 | u32 buffer_size, u32 *element_indx, u32 stop_indx, | |
733 | bool print_metadata, | |
734 | int (*func_ptr_print_element)(struct ecore_chain *p_chain, | |
735 | void *p_element, | |
736 | char *buffer), | |
737 | int (*func_ptr_print_metadata)(struct ecore_chain | |
738 | *p_chain, | |
739 | char *buffer)); | |
740 | ||
741 | #endif /* __ECORE_CHAIN_H__ */ |