13126df22SRasesh Mody /* SPDX-License-Identifier: BSD-3-Clause
29adde217SRasesh Mody * Copyright (c) 2016 - 2018 Cavium Inc.
3ec94dbc5SRasesh Mody * All rights reserved.
49adde217SRasesh Mody * www.cavium.com
5ec94dbc5SRasesh Mody */
6ec94dbc5SRasesh Mody
7ec94dbc5SRasesh Mody #ifndef __ECORE_CHAIN_H__
8ec94dbc5SRasesh Mody #define __ECORE_CHAIN_H__
9ec94dbc5SRasesh Mody
10ec94dbc5SRasesh Mody #include <assert.h> /* @DPDK */
11ec94dbc5SRasesh Mody
12ec94dbc5SRasesh Mody #include "common_hsi.h"
13ec94dbc5SRasesh Mody #include "ecore_utils.h"
14ec94dbc5SRasesh Mody
15ec94dbc5SRasesh Mody enum ecore_chain_mode {
16ec94dbc5SRasesh Mody /* Each Page contains a next pointer at its end */
17ec94dbc5SRasesh Mody ECORE_CHAIN_MODE_NEXT_PTR,
18ec94dbc5SRasesh Mody
19ec94dbc5SRasesh Mody /* Chain is a single page (next ptr) is unrequired */
20ec94dbc5SRasesh Mody ECORE_CHAIN_MODE_SINGLE,
21ec94dbc5SRasesh Mody
22ec94dbc5SRasesh Mody /* Page pointers are located in a side list */
23ec94dbc5SRasesh Mody ECORE_CHAIN_MODE_PBL,
24ec94dbc5SRasesh Mody };
25ec94dbc5SRasesh Mody
26ec94dbc5SRasesh Mody enum ecore_chain_use_mode {
27ec94dbc5SRasesh Mody ECORE_CHAIN_USE_TO_PRODUCE, /* Chain starts empty */
28ec94dbc5SRasesh Mody ECORE_CHAIN_USE_TO_CONSUME, /* Chain starts full */
29ec94dbc5SRasesh Mody ECORE_CHAIN_USE_TO_CONSUME_PRODUCE, /* Chain starts empty */
30ec94dbc5SRasesh Mody };
31ec94dbc5SRasesh Mody
32ec94dbc5SRasesh Mody enum ecore_chain_cnt_type {
33ec94dbc5SRasesh Mody /* The chain's size/prod/cons are kept in 16-bit variables */
34ec94dbc5SRasesh Mody ECORE_CHAIN_CNT_TYPE_U16,
35ec94dbc5SRasesh Mody
36ec94dbc5SRasesh Mody /* The chain's size/prod/cons are kept in 32-bit variables */
37ec94dbc5SRasesh Mody ECORE_CHAIN_CNT_TYPE_U32,
38ec94dbc5SRasesh Mody };
39ec94dbc5SRasesh Mody
40ec94dbc5SRasesh Mody struct ecore_chain_next {
41ec94dbc5SRasesh Mody struct regpair next_phys;
42ec94dbc5SRasesh Mody void *next_virt;
43ec94dbc5SRasesh Mody };
44ec94dbc5SRasesh Mody
45ec94dbc5SRasesh Mody struct ecore_chain_pbl_u16 {
46ec94dbc5SRasesh Mody u16 prod_page_idx;
47ec94dbc5SRasesh Mody u16 cons_page_idx;
48ec94dbc5SRasesh Mody };
49ec94dbc5SRasesh Mody
50ec94dbc5SRasesh Mody struct ecore_chain_pbl_u32 {
51ec94dbc5SRasesh Mody u32 prod_page_idx;
52ec94dbc5SRasesh Mody u32 cons_page_idx;
53ec94dbc5SRasesh Mody };
54ec94dbc5SRasesh Mody
55fe96c1e8SRasesh Mody struct ecore_chain_ext_pbl {
56fe96c1e8SRasesh Mody dma_addr_t p_pbl_phys;
57fe96c1e8SRasesh Mody void *p_pbl_virt;
58fe96c1e8SRasesh Mody };
59fe96c1e8SRasesh Mody
60ec94dbc5SRasesh Mody struct ecore_chain_u16 {
61ec94dbc5SRasesh Mody /* Cyclic index of next element to produce/consme */
62ec94dbc5SRasesh Mody u16 prod_idx;
63ec94dbc5SRasesh Mody u16 cons_idx;
64ec94dbc5SRasesh Mody };
65ec94dbc5SRasesh Mody
66ec94dbc5SRasesh Mody struct ecore_chain_u32 {
67ec94dbc5SRasesh Mody /* Cyclic index of next element to produce/consme */
68ec94dbc5SRasesh Mody u32 prod_idx;
69ec94dbc5SRasesh Mody u32 cons_idx;
70ec94dbc5SRasesh Mody };
71ec94dbc5SRasesh Mody
72ec94dbc5SRasesh Mody struct ecore_chain {
736a0f9f5cSRasesh Mody /* fastpath portion of the chain - required for commands such
746a0f9f5cSRasesh Mody * as produce / consume.
756a0f9f5cSRasesh Mody */
76ec94dbc5SRasesh Mody /* Point to next element to produce/consume */
77ec94dbc5SRasesh Mody void *p_prod_elem;
78ec94dbc5SRasesh Mody void *p_cons_elem;
79ec94dbc5SRasesh Mody
806a0f9f5cSRasesh Mody /* Fastpath portions of the PBL [if exists] */
81ec94dbc5SRasesh Mody
826a0f9f5cSRasesh Mody struct {
836a0f9f5cSRasesh Mody /* Table for keeping the virtual addresses of the chain pages,
846a0f9f5cSRasesh Mody * respectively to the physical addresses in the pbl table.
856a0f9f5cSRasesh Mody */
866a0f9f5cSRasesh Mody void **pp_virt_addr_tbl;
876a0f9f5cSRasesh Mody
886a0f9f5cSRasesh Mody union {
89*766d68acSRasesh Mody struct ecore_chain_pbl_u16 pbl_u16;
90*766d68acSRasesh Mody struct ecore_chain_pbl_u32 pbl_u32;
916a0f9f5cSRasesh Mody } c;
926a0f9f5cSRasesh Mody } pbl;
936a0f9f5cSRasesh Mody
94ec94dbc5SRasesh Mody union {
95ec94dbc5SRasesh Mody struct ecore_chain_u16 chain16;
96ec94dbc5SRasesh Mody struct ecore_chain_u32 chain32;
97ec94dbc5SRasesh Mody } u;
98ec94dbc5SRasesh Mody
996a0f9f5cSRasesh Mody /* Capacity counts only usable elements */
1006a0f9f5cSRasesh Mody u32 capacity;
101ec94dbc5SRasesh Mody u32 page_cnt;
102ec94dbc5SRasesh Mody
1036a0f9f5cSRasesh Mody /* A u8 would suffice for mode, but it would save as a lot of headaches
1046a0f9f5cSRasesh Mody * on castings & defaults.
105ec94dbc5SRasesh Mody */
1066a0f9f5cSRasesh Mody enum ecore_chain_mode mode;
107ec94dbc5SRasesh Mody
108ec94dbc5SRasesh Mody /* Elements information for fast calculations */
109ec94dbc5SRasesh Mody u16 elem_per_page;
110ec94dbc5SRasesh Mody u16 elem_per_page_mask;
111ec94dbc5SRasesh Mody u16 elem_size;
112ec94dbc5SRasesh Mody u16 next_page_mask;
1136a0f9f5cSRasesh Mody u16 usable_per_page;
1146a0f9f5cSRasesh Mody u8 elem_unusable;
115ec94dbc5SRasesh Mody
1166a0f9f5cSRasesh Mody u8 cnt_type;
1176a0f9f5cSRasesh Mody
1186a0f9f5cSRasesh Mody /* Slowpath of the chain - required for initialization and destruction,
1196a0f9f5cSRasesh Mody * but isn't involved in regular functionality.
1206a0f9f5cSRasesh Mody */
1216a0f9f5cSRasesh Mody
1226a0f9f5cSRasesh Mody /* Base address of a pre-allocated buffer for pbl */
1236a0f9f5cSRasesh Mody struct {
1246a0f9f5cSRasesh Mody dma_addr_t p_phys_table;
1256a0f9f5cSRasesh Mody void *p_virt_table;
1266a0f9f5cSRasesh Mody } pbl_sp;
1276a0f9f5cSRasesh Mody
1286a0f9f5cSRasesh Mody /* Address of first page of the chain - the address is required
1298f87ba70SThierry Herbelot * for fastpath operation [consume/produce] but only for the SINGLE
1306a0f9f5cSRasesh Mody * flavour which isn't considered fastpath [== SPQ].
1316a0f9f5cSRasesh Mody */
1326a0f9f5cSRasesh Mody void *p_virt_addr;
1336a0f9f5cSRasesh Mody dma_addr_t p_phys_addr;
1346a0f9f5cSRasesh Mody
1356a0f9f5cSRasesh Mody /* Total number of elements [for entire chain] */
1366a0f9f5cSRasesh Mody u32 size;
1376a0f9f5cSRasesh Mody
1386a0f9f5cSRasesh Mody u8 intended_use;
1396a0f9f5cSRasesh Mody
1406a0f9f5cSRasesh Mody /* TBD - do we really need this? Couldn't find usage for it */
1416a0f9f5cSRasesh Mody bool b_external_pbl;
14222d07d93SRasesh Mody
14322d07d93SRasesh Mody void *dp_ctx;
144ec94dbc5SRasesh Mody };
145ec94dbc5SRasesh Mody
146ec94dbc5SRasesh Mody #define ECORE_CHAIN_PBL_ENTRY_SIZE (8)
147ec94dbc5SRasesh Mody #define ECORE_CHAIN_PAGE_SIZE (0x1000)
148ec94dbc5SRasesh Mody #define ELEMS_PER_PAGE(elem_size) (ECORE_CHAIN_PAGE_SIZE / (elem_size))
149ec94dbc5SRasesh Mody
150ec94dbc5SRasesh Mody #define UNUSABLE_ELEMS_PER_PAGE(elem_size, mode) \
151ec94dbc5SRasesh Mody ((mode == ECORE_CHAIN_MODE_NEXT_PTR) ? \
1526a0f9f5cSRasesh Mody (u8)(1 + ((sizeof(struct ecore_chain_next) - 1) / \
153ec94dbc5SRasesh Mody (elem_size))) : 0)
154ec94dbc5SRasesh Mody
155ec94dbc5SRasesh Mody #define USABLE_ELEMS_PER_PAGE(elem_size, mode) \
156ec94dbc5SRasesh Mody ((u32)(ELEMS_PER_PAGE(elem_size) - \
157ec94dbc5SRasesh Mody UNUSABLE_ELEMS_PER_PAGE(elem_size, mode)))
158ec94dbc5SRasesh Mody
159ec94dbc5SRasesh Mody #define ECORE_CHAIN_PAGE_CNT(elem_cnt, elem_size, mode) \
160ec94dbc5SRasesh Mody DIV_ROUND_UP(elem_cnt, USABLE_ELEMS_PER_PAGE(elem_size, mode))
161ec94dbc5SRasesh Mody
162ec94dbc5SRasesh Mody #define is_chain_u16(p) ((p)->cnt_type == ECORE_CHAIN_CNT_TYPE_U16)
163ec94dbc5SRasesh Mody #define is_chain_u32(p) ((p)->cnt_type == ECORE_CHAIN_CNT_TYPE_U32)
164ec94dbc5SRasesh Mody
165ec94dbc5SRasesh Mody /* Accessors */
ecore_chain_get_prod_idx(struct ecore_chain * p_chain)166ec94dbc5SRasesh Mody static OSAL_INLINE u16 ecore_chain_get_prod_idx(struct ecore_chain *p_chain)
167ec94dbc5SRasesh Mody {
168ec94dbc5SRasesh Mody OSAL_ASSERT(is_chain_u16(p_chain));
169ec94dbc5SRasesh Mody return p_chain->u.chain16.prod_idx;
170ec94dbc5SRasesh Mody }
171ec94dbc5SRasesh Mody
ecore_chain_get_prod_idx_u32(struct ecore_chain * p_chain)172ec94dbc5SRasesh Mody static OSAL_INLINE u32 ecore_chain_get_prod_idx_u32(struct ecore_chain *p_chain)
173ec94dbc5SRasesh Mody {
174ec94dbc5SRasesh Mody OSAL_ASSERT(is_chain_u32(p_chain));
175ec94dbc5SRasesh Mody return p_chain->u.chain32.prod_idx;
176ec94dbc5SRasesh Mody }
177ec94dbc5SRasesh Mody
ecore_chain_get_cons_idx(struct ecore_chain * p_chain)178ec94dbc5SRasesh Mody static OSAL_INLINE u16 ecore_chain_get_cons_idx(struct ecore_chain *p_chain)
179ec94dbc5SRasesh Mody {
180ec94dbc5SRasesh Mody OSAL_ASSERT(is_chain_u16(p_chain));
181ec94dbc5SRasesh Mody return p_chain->u.chain16.cons_idx;
182ec94dbc5SRasesh Mody }
183ec94dbc5SRasesh Mody
ecore_chain_get_cons_idx_u32(struct ecore_chain * p_chain)184ec94dbc5SRasesh Mody static OSAL_INLINE u32 ecore_chain_get_cons_idx_u32(struct ecore_chain *p_chain)
185ec94dbc5SRasesh Mody {
186ec94dbc5SRasesh Mody OSAL_ASSERT(is_chain_u32(p_chain));
187ec94dbc5SRasesh Mody return p_chain->u.chain32.cons_idx;
188ec94dbc5SRasesh Mody }
189ec94dbc5SRasesh Mody
190ec94dbc5SRasesh Mody /* FIXME:
191ec94dbc5SRasesh Mody * Should create OSALs for the below definitions.
192ec94dbc5SRasesh Mody * For Linux, replace them with the existing U16_MAX and U32_MAX, and handle
193ec94dbc5SRasesh Mody * kernel versions that lack them.
194ec94dbc5SRasesh Mody */
195ec94dbc5SRasesh Mody #define ECORE_U16_MAX ((u16)~0U)
196ec94dbc5SRasesh Mody #define ECORE_U32_MAX ((u32)~0U)
197ec94dbc5SRasesh Mody
ecore_chain_get_elem_left(struct ecore_chain * p_chain)198ec94dbc5SRasesh Mody static OSAL_INLINE u16 ecore_chain_get_elem_left(struct ecore_chain *p_chain)
199ec94dbc5SRasesh Mody {
200ec94dbc5SRasesh Mody u16 used;
201ec94dbc5SRasesh Mody
202ec94dbc5SRasesh Mody OSAL_ASSERT(is_chain_u16(p_chain));
203ec94dbc5SRasesh Mody
204ec94dbc5SRasesh Mody used = (u16)(((u32)ECORE_U16_MAX + 1 +
205ec94dbc5SRasesh Mody (u32)(p_chain->u.chain16.prod_idx)) -
206ec94dbc5SRasesh Mody (u32)p_chain->u.chain16.cons_idx);
207ec94dbc5SRasesh Mody if (p_chain->mode == ECORE_CHAIN_MODE_NEXT_PTR)
208ec94dbc5SRasesh Mody used -= p_chain->u.chain16.prod_idx / p_chain->elem_per_page -
209ec94dbc5SRasesh Mody p_chain->u.chain16.cons_idx / p_chain->elem_per_page;
210ec94dbc5SRasesh Mody
211ec94dbc5SRasesh Mody return (u16)(p_chain->capacity - used);
212ec94dbc5SRasesh Mody }
213ec94dbc5SRasesh Mody
214ec94dbc5SRasesh Mody static OSAL_INLINE u32
ecore_chain_get_elem_left_u32(struct ecore_chain * p_chain)215ec94dbc5SRasesh Mody ecore_chain_get_elem_left_u32(struct ecore_chain *p_chain)
216ec94dbc5SRasesh Mody {
217ec94dbc5SRasesh Mody u32 used;
218ec94dbc5SRasesh Mody
219ec94dbc5SRasesh Mody OSAL_ASSERT(is_chain_u32(p_chain));
220ec94dbc5SRasesh Mody
221ec94dbc5SRasesh Mody used = (u32)(((u64)ECORE_U32_MAX + 1 +
222ec94dbc5SRasesh Mody (u64)(p_chain->u.chain32.prod_idx)) -
223ec94dbc5SRasesh Mody (u64)p_chain->u.chain32.cons_idx);
224ec94dbc5SRasesh Mody if (p_chain->mode == ECORE_CHAIN_MODE_NEXT_PTR)
225ec94dbc5SRasesh Mody used -= p_chain->u.chain32.prod_idx / p_chain->elem_per_page -
226ec94dbc5SRasesh Mody p_chain->u.chain32.cons_idx / p_chain->elem_per_page;
227ec94dbc5SRasesh Mody
228ec94dbc5SRasesh Mody return p_chain->capacity - used;
229ec94dbc5SRasesh Mody }
230ec94dbc5SRasesh Mody
ecore_chain_is_full(struct ecore_chain * p_chain)231ec94dbc5SRasesh Mody static OSAL_INLINE u8 ecore_chain_is_full(struct ecore_chain *p_chain)
232ec94dbc5SRasesh Mody {
233ec94dbc5SRasesh Mody if (is_chain_u16(p_chain))
234ec94dbc5SRasesh Mody return (ecore_chain_get_elem_left(p_chain) ==
235ec94dbc5SRasesh Mody p_chain->capacity);
236ec94dbc5SRasesh Mody else
237ec94dbc5SRasesh Mody return (ecore_chain_get_elem_left_u32(p_chain) ==
238ec94dbc5SRasesh Mody p_chain->capacity);
239ec94dbc5SRasesh Mody }
240ec94dbc5SRasesh Mody
ecore_chain_is_empty(struct ecore_chain * p_chain)241ec94dbc5SRasesh Mody static OSAL_INLINE u8 ecore_chain_is_empty(struct ecore_chain *p_chain)
242ec94dbc5SRasesh Mody {
243ec94dbc5SRasesh Mody if (is_chain_u16(p_chain))
244ec94dbc5SRasesh Mody return (ecore_chain_get_elem_left(p_chain) == 0);
245ec94dbc5SRasesh Mody else
246ec94dbc5SRasesh Mody return (ecore_chain_get_elem_left_u32(p_chain) == 0);
247ec94dbc5SRasesh Mody }
248ec94dbc5SRasesh Mody
249ec94dbc5SRasesh Mody static OSAL_INLINE
ecore_chain_get_elem_per_page(struct ecore_chain * p_chain)250ec94dbc5SRasesh Mody u16 ecore_chain_get_elem_per_page(struct ecore_chain *p_chain)
251ec94dbc5SRasesh Mody {
252ec94dbc5SRasesh Mody return p_chain->elem_per_page;
253ec94dbc5SRasesh Mody }
254ec94dbc5SRasesh Mody
255ec94dbc5SRasesh Mody static OSAL_INLINE
ecore_chain_get_usable_per_page(struct ecore_chain * p_chain)256ec94dbc5SRasesh Mody u16 ecore_chain_get_usable_per_page(struct ecore_chain *p_chain)
257ec94dbc5SRasesh Mody {
258ec94dbc5SRasesh Mody return p_chain->usable_per_page;
259ec94dbc5SRasesh Mody }
260ec94dbc5SRasesh Mody
261ec94dbc5SRasesh Mody static OSAL_INLINE
ecore_chain_get_unusable_per_page(struct ecore_chain * p_chain)2626a0f9f5cSRasesh Mody u8 ecore_chain_get_unusable_per_page(struct ecore_chain *p_chain)
263ec94dbc5SRasesh Mody {
264ec94dbc5SRasesh Mody return p_chain->elem_unusable;
265ec94dbc5SRasesh Mody }
266ec94dbc5SRasesh Mody
ecore_chain_get_size(struct ecore_chain * p_chain)267ec94dbc5SRasesh Mody static OSAL_INLINE u32 ecore_chain_get_size(struct ecore_chain *p_chain)
268ec94dbc5SRasesh Mody {
269ec94dbc5SRasesh Mody return p_chain->size;
270ec94dbc5SRasesh Mody }
271ec94dbc5SRasesh Mody
ecore_chain_get_page_cnt(struct ecore_chain * p_chain)272ec94dbc5SRasesh Mody static OSAL_INLINE u32 ecore_chain_get_page_cnt(struct ecore_chain *p_chain)
273ec94dbc5SRasesh Mody {
274ec94dbc5SRasesh Mody return p_chain->page_cnt;
275ec94dbc5SRasesh Mody }
276ec94dbc5SRasesh Mody
2775cdd769aSRasesh Mody static OSAL_INLINE
ecore_chain_get_pbl_phys(struct ecore_chain * p_chain)2785cdd769aSRasesh Mody dma_addr_t ecore_chain_get_pbl_phys(struct ecore_chain *p_chain)
2795cdd769aSRasesh Mody {
2806a0f9f5cSRasesh Mody return p_chain->pbl_sp.p_phys_table;
2815cdd769aSRasesh Mody }
2825cdd769aSRasesh Mody
283ec94dbc5SRasesh Mody /**
284ec94dbc5SRasesh Mody * @brief ecore_chain_advance_page -
285ec94dbc5SRasesh Mody *
286ec94dbc5SRasesh Mody * Advance the next element accros pages for a linked chain
287ec94dbc5SRasesh Mody *
288ec94dbc5SRasesh Mody * @param p_chain
289ec94dbc5SRasesh Mody * @param p_next_elem
290ec94dbc5SRasesh Mody * @param idx_to_inc
291ec94dbc5SRasesh Mody * @param page_to_inc
292ec94dbc5SRasesh Mody */
293ec94dbc5SRasesh Mody static OSAL_INLINE void
ecore_chain_advance_page(struct ecore_chain * p_chain,void ** p_next_elem,void * idx_to_inc,void * page_to_inc)294ec94dbc5SRasesh Mody ecore_chain_advance_page(struct ecore_chain *p_chain, void **p_next_elem,
295ec94dbc5SRasesh Mody void *idx_to_inc, void *page_to_inc)
296ec94dbc5SRasesh Mody {
297ec94dbc5SRasesh Mody struct ecore_chain_next *p_next = OSAL_NULL;
298ec94dbc5SRasesh Mody u32 page_index = 0;
299ec94dbc5SRasesh Mody
300ec94dbc5SRasesh Mody switch (p_chain->mode) {
301ec94dbc5SRasesh Mody case ECORE_CHAIN_MODE_NEXT_PTR:
302ec94dbc5SRasesh Mody p_next = (struct ecore_chain_next *)(*p_next_elem);
303ec94dbc5SRasesh Mody *p_next_elem = p_next->next_virt;
304ec94dbc5SRasesh Mody if (is_chain_u16(p_chain))
3056a0f9f5cSRasesh Mody *(u16 *)idx_to_inc += (u16)p_chain->elem_unusable;
306ec94dbc5SRasesh Mody else
3076a0f9f5cSRasesh Mody *(u32 *)idx_to_inc += (u16)p_chain->elem_unusable;
308ec94dbc5SRasesh Mody break;
309ec94dbc5SRasesh Mody case ECORE_CHAIN_MODE_SINGLE:
310ec94dbc5SRasesh Mody *p_next_elem = p_chain->p_virt_addr;
311ec94dbc5SRasesh Mody break;
312ec94dbc5SRasesh Mody case ECORE_CHAIN_MODE_PBL:
313ec94dbc5SRasesh Mody if (is_chain_u16(p_chain)) {
314ec94dbc5SRasesh Mody if (++(*(u16 *)page_to_inc) == p_chain->page_cnt)
315ec94dbc5SRasesh Mody *(u16 *)page_to_inc = 0;
316ec94dbc5SRasesh Mody page_index = *(u16 *)page_to_inc;
317ec94dbc5SRasesh Mody } else {
318ec94dbc5SRasesh Mody if (++(*(u32 *)page_to_inc) == p_chain->page_cnt)
319ec94dbc5SRasesh Mody *(u32 *)page_to_inc = 0;
320ec94dbc5SRasesh Mody page_index = *(u32 *)page_to_inc;
321ec94dbc5SRasesh Mody }
322ec94dbc5SRasesh Mody *p_next_elem = p_chain->pbl.pp_virt_addr_tbl[page_index];
323ec94dbc5SRasesh Mody }
324ec94dbc5SRasesh Mody }
325ec94dbc5SRasesh Mody
326ec94dbc5SRasesh Mody #define is_unusable_idx(p, idx) \
327ec94dbc5SRasesh Mody (((p)->u.chain16.idx & (p)->elem_per_page_mask) == (p)->usable_per_page)
328ec94dbc5SRasesh Mody
329ec94dbc5SRasesh Mody #define is_unusable_idx_u32(p, idx) \
330ec94dbc5SRasesh Mody (((p)->u.chain32.idx & (p)->elem_per_page_mask) == (p)->usable_per_page)
331ec94dbc5SRasesh Mody
332ec94dbc5SRasesh Mody #define is_unusable_next_idx(p, idx) \
3339455b556SRasesh Mody ((((p)->u.chain16.idx + 1) & \
3349455b556SRasesh Mody (p)->elem_per_page_mask) == (p)->usable_per_page)
335ec94dbc5SRasesh Mody
336ec94dbc5SRasesh Mody #define is_unusable_next_idx_u32(p, idx) \
3379455b556SRasesh Mody ((((p)->u.chain32.idx + 1) & \
3389455b556SRasesh Mody (p)->elem_per_page_mask) == (p)->usable_per_page)
339ec94dbc5SRasesh Mody
340ec94dbc5SRasesh Mody #define test_and_skip(p, idx) \
341ec94dbc5SRasesh Mody do { \
342ec94dbc5SRasesh Mody if (is_chain_u16(p)) { \
343ec94dbc5SRasesh Mody if (is_unusable_idx(p, idx)) \
3449455b556SRasesh Mody (p)->u.chain16.idx += \
3459455b556SRasesh Mody (p)->elem_unusable; \
346ec94dbc5SRasesh Mody } else { \
347ec94dbc5SRasesh Mody if (is_unusable_idx_u32(p, idx)) \
3489455b556SRasesh Mody (p)->u.chain32.idx += \
3499455b556SRasesh Mody (p)->elem_unusable; \
350ec94dbc5SRasesh Mody } \
351ec94dbc5SRasesh Mody } while (0)
352ec94dbc5SRasesh Mody
353ec94dbc5SRasesh Mody /**
354ec94dbc5SRasesh Mody * @brief ecore_chain_return_multi_produced -
355ec94dbc5SRasesh Mody *
356ec94dbc5SRasesh Mody * A chain in which the driver "Produces" elements should use this API
357ec94dbc5SRasesh Mody * to indicate previous produced elements are now consumed.
358ec94dbc5SRasesh Mody *
359ec94dbc5SRasesh Mody * @param p_chain
360ec94dbc5SRasesh Mody * @param num
361ec94dbc5SRasesh Mody */
362ec94dbc5SRasesh Mody static OSAL_INLINE
ecore_chain_return_multi_produced(struct ecore_chain * p_chain,u32 num)363ec94dbc5SRasesh Mody void ecore_chain_return_multi_produced(struct ecore_chain *p_chain, u32 num)
364ec94dbc5SRasesh Mody {
365ec94dbc5SRasesh Mody if (is_chain_u16(p_chain))
366ec94dbc5SRasesh Mody p_chain->u.chain16.cons_idx += (u16)num;
367ec94dbc5SRasesh Mody else
368ec94dbc5SRasesh Mody p_chain->u.chain32.cons_idx += num;
369ec94dbc5SRasesh Mody test_and_skip(p_chain, cons_idx);
370ec94dbc5SRasesh Mody }
371ec94dbc5SRasesh Mody
372ec94dbc5SRasesh Mody /**
373ec94dbc5SRasesh Mody * @brief ecore_chain_return_produced -
374ec94dbc5SRasesh Mody *
375ec94dbc5SRasesh Mody * A chain in which the driver "Produces" elements should use this API
376ec94dbc5SRasesh Mody * to indicate previous produced elements are now consumed.
377ec94dbc5SRasesh Mody *
378ec94dbc5SRasesh Mody * @param p_chain
379ec94dbc5SRasesh Mody */
ecore_chain_return_produced(struct ecore_chain * p_chain)380ec94dbc5SRasesh Mody static OSAL_INLINE void ecore_chain_return_produced(struct ecore_chain *p_chain)
381ec94dbc5SRasesh Mody {
382ec94dbc5SRasesh Mody if (is_chain_u16(p_chain))
383ec94dbc5SRasesh Mody p_chain->u.chain16.cons_idx++;
384ec94dbc5SRasesh Mody else
385ec94dbc5SRasesh Mody p_chain->u.chain32.cons_idx++;
386ec94dbc5SRasesh Mody test_and_skip(p_chain, cons_idx);
387ec94dbc5SRasesh Mody }
388ec94dbc5SRasesh Mody
389ec94dbc5SRasesh Mody /**
390ec94dbc5SRasesh Mody * @brief ecore_chain_produce -
391ec94dbc5SRasesh Mody *
392ec94dbc5SRasesh Mody * A chain in which the driver "Produces" elements should use this to get
393ec94dbc5SRasesh Mody * a pointer to the next element which can be "Produced". It's driver
394ec94dbc5SRasesh Mody * responsibility to validate that the chain has room for new element.
395ec94dbc5SRasesh Mody *
396ec94dbc5SRasesh Mody * @param p_chain
397ec94dbc5SRasesh Mody *
398ec94dbc5SRasesh Mody * @return void*, a pointer to next element
399ec94dbc5SRasesh Mody */
ecore_chain_produce(struct ecore_chain * p_chain)400ec94dbc5SRasesh Mody static OSAL_INLINE void *ecore_chain_produce(struct ecore_chain *p_chain)
401ec94dbc5SRasesh Mody {
402ec94dbc5SRasesh Mody void *p_ret = OSAL_NULL, *p_prod_idx, *p_prod_page_idx;
403ec94dbc5SRasesh Mody
404ec94dbc5SRasesh Mody if (is_chain_u16(p_chain)) {
405ec94dbc5SRasesh Mody if ((p_chain->u.chain16.prod_idx &
406ec94dbc5SRasesh Mody p_chain->elem_per_page_mask) == p_chain->next_page_mask) {
407ec94dbc5SRasesh Mody p_prod_idx = &p_chain->u.chain16.prod_idx;
408*766d68acSRasesh Mody p_prod_page_idx = &p_chain->pbl.c.pbl_u16.prod_page_idx;
409ec94dbc5SRasesh Mody ecore_chain_advance_page(p_chain, &p_chain->p_prod_elem,
410ec94dbc5SRasesh Mody p_prod_idx, p_prod_page_idx);
411ec94dbc5SRasesh Mody }
412ec94dbc5SRasesh Mody p_chain->u.chain16.prod_idx++;
413ec94dbc5SRasesh Mody } else {
414ec94dbc5SRasesh Mody if ((p_chain->u.chain32.prod_idx &
415ec94dbc5SRasesh Mody p_chain->elem_per_page_mask) == p_chain->next_page_mask) {
416ec94dbc5SRasesh Mody p_prod_idx = &p_chain->u.chain32.prod_idx;
417*766d68acSRasesh Mody p_prod_page_idx = &p_chain->pbl.c.pbl_u32.prod_page_idx;
418ec94dbc5SRasesh Mody ecore_chain_advance_page(p_chain, &p_chain->p_prod_elem,
419ec94dbc5SRasesh Mody p_prod_idx, p_prod_page_idx);
420ec94dbc5SRasesh Mody }
421ec94dbc5SRasesh Mody p_chain->u.chain32.prod_idx++;
422ec94dbc5SRasesh Mody }
423ec94dbc5SRasesh Mody
424ec94dbc5SRasesh Mody p_ret = p_chain->p_prod_elem;
425ec94dbc5SRasesh Mody p_chain->p_prod_elem = (void *)(((u8 *)p_chain->p_prod_elem) +
426ec94dbc5SRasesh Mody p_chain->elem_size);
427ec94dbc5SRasesh Mody
428ec94dbc5SRasesh Mody return p_ret;
429ec94dbc5SRasesh Mody }
430ec94dbc5SRasesh Mody
431ec94dbc5SRasesh Mody /**
432ec94dbc5SRasesh Mody * @brief ecore_chain_get_capacity -
433ec94dbc5SRasesh Mody *
434ec94dbc5SRasesh Mody * Get the maximum number of BDs in chain
435ec94dbc5SRasesh Mody *
436ec94dbc5SRasesh Mody * @param p_chain
437ec94dbc5SRasesh Mody * @param num
438ec94dbc5SRasesh Mody *
439ec94dbc5SRasesh Mody * @return number of unusable BDs
440ec94dbc5SRasesh Mody */
ecore_chain_get_capacity(struct ecore_chain * p_chain)441ec94dbc5SRasesh Mody static OSAL_INLINE u32 ecore_chain_get_capacity(struct ecore_chain *p_chain)
442ec94dbc5SRasesh Mody {
443ec94dbc5SRasesh Mody return p_chain->capacity;
444ec94dbc5SRasesh Mody }
445ec94dbc5SRasesh Mody
446ec94dbc5SRasesh Mody /**
447ec94dbc5SRasesh Mody * @brief ecore_chain_recycle_consumed -
448ec94dbc5SRasesh Mody *
449ec94dbc5SRasesh Mody * Returns an element which was previously consumed;
450ec94dbc5SRasesh Mody * Increments producers so they could be written to FW.
451ec94dbc5SRasesh Mody *
452ec94dbc5SRasesh Mody * @param p_chain
453ec94dbc5SRasesh Mody */
454ec94dbc5SRasesh Mody static OSAL_INLINE
ecore_chain_recycle_consumed(struct ecore_chain * p_chain)455ec94dbc5SRasesh Mody void ecore_chain_recycle_consumed(struct ecore_chain *p_chain)
456ec94dbc5SRasesh Mody {
457ec94dbc5SRasesh Mody test_and_skip(p_chain, prod_idx);
458ec94dbc5SRasesh Mody if (is_chain_u16(p_chain))
459ec94dbc5SRasesh Mody p_chain->u.chain16.prod_idx++;
460ec94dbc5SRasesh Mody else
461ec94dbc5SRasesh Mody p_chain->u.chain32.prod_idx++;
462ec94dbc5SRasesh Mody }
463ec94dbc5SRasesh Mody
464ec94dbc5SRasesh Mody /**
465ec94dbc5SRasesh Mody * @brief ecore_chain_consume -
466ec94dbc5SRasesh Mody *
467ec94dbc5SRasesh Mody * A Chain in which the driver utilizes data written by a different source
468ec94dbc5SRasesh Mody * (i.e., FW) should use this to access passed buffers.
469ec94dbc5SRasesh Mody *
470ec94dbc5SRasesh Mody * @param p_chain
471ec94dbc5SRasesh Mody *
472ec94dbc5SRasesh Mody * @return void*, a pointer to the next buffer written
473ec94dbc5SRasesh Mody */
ecore_chain_consume(struct ecore_chain * p_chain)474ec94dbc5SRasesh Mody static OSAL_INLINE void *ecore_chain_consume(struct ecore_chain *p_chain)
475ec94dbc5SRasesh Mody {
476ec94dbc5SRasesh Mody void *p_ret = OSAL_NULL, *p_cons_idx, *p_cons_page_idx;
477ec94dbc5SRasesh Mody
478ec94dbc5SRasesh Mody if (is_chain_u16(p_chain)) {
479ec94dbc5SRasesh Mody if ((p_chain->u.chain16.cons_idx &
480ec94dbc5SRasesh Mody p_chain->elem_per_page_mask) == p_chain->next_page_mask) {
481ec94dbc5SRasesh Mody p_cons_idx = &p_chain->u.chain16.cons_idx;
482*766d68acSRasesh Mody p_cons_page_idx = &p_chain->pbl.c.pbl_u16.cons_page_idx;
483ec94dbc5SRasesh Mody ecore_chain_advance_page(p_chain, &p_chain->p_cons_elem,
484ec94dbc5SRasesh Mody p_cons_idx, p_cons_page_idx);
485ec94dbc5SRasesh Mody }
486ec94dbc5SRasesh Mody p_chain->u.chain16.cons_idx++;
487ec94dbc5SRasesh Mody } else {
488ec94dbc5SRasesh Mody if ((p_chain->u.chain32.cons_idx &
489ec94dbc5SRasesh Mody p_chain->elem_per_page_mask) == p_chain->next_page_mask) {
490ec94dbc5SRasesh Mody p_cons_idx = &p_chain->u.chain32.cons_idx;
491*766d68acSRasesh Mody p_cons_page_idx = &p_chain->pbl.c.pbl_u32.cons_page_idx;
492ec94dbc5SRasesh Mody ecore_chain_advance_page(p_chain, &p_chain->p_cons_elem,
493ec94dbc5SRasesh Mody p_cons_idx, p_cons_page_idx);
494ec94dbc5SRasesh Mody }
495ec94dbc5SRasesh Mody p_chain->u.chain32.cons_idx++;
496ec94dbc5SRasesh Mody }
497ec94dbc5SRasesh Mody
498ec94dbc5SRasesh Mody p_ret = p_chain->p_cons_elem;
499ec94dbc5SRasesh Mody p_chain->p_cons_elem = (void *)(((u8 *)p_chain->p_cons_elem) +
500ec94dbc5SRasesh Mody p_chain->elem_size);
501ec94dbc5SRasesh Mody
502ec94dbc5SRasesh Mody return p_ret;
503ec94dbc5SRasesh Mody }
504ec94dbc5SRasesh Mody
505ec94dbc5SRasesh Mody /**
506ec94dbc5SRasesh Mody * @brief ecore_chain_reset -
507ec94dbc5SRasesh Mody *
508ec94dbc5SRasesh Mody * Resets the chain to its start state
509ec94dbc5SRasesh Mody *
510ec94dbc5SRasesh Mody * @param p_chain pointer to a previously allocted chain
511ec94dbc5SRasesh Mody */
ecore_chain_reset(struct ecore_chain * p_chain)512ec94dbc5SRasesh Mody static OSAL_INLINE void ecore_chain_reset(struct ecore_chain *p_chain)
513ec94dbc5SRasesh Mody {
514ec94dbc5SRasesh Mody u32 i;
515ec94dbc5SRasesh Mody
516ec94dbc5SRasesh Mody if (is_chain_u16(p_chain)) {
517ec94dbc5SRasesh Mody p_chain->u.chain16.prod_idx = 0;
518ec94dbc5SRasesh Mody p_chain->u.chain16.cons_idx = 0;
519ec94dbc5SRasesh Mody } else {
520ec94dbc5SRasesh Mody p_chain->u.chain32.prod_idx = 0;
521ec94dbc5SRasesh Mody p_chain->u.chain32.cons_idx = 0;
522ec94dbc5SRasesh Mody }
523ec94dbc5SRasesh Mody p_chain->p_cons_elem = p_chain->p_virt_addr;
524ec94dbc5SRasesh Mody p_chain->p_prod_elem = p_chain->p_virt_addr;
525ec94dbc5SRasesh Mody
526ec94dbc5SRasesh Mody if (p_chain->mode == ECORE_CHAIN_MODE_PBL) {
527fe7572b6SRasesh Mody /* Use "page_cnt-1" as a reset value for the prod/cons page's
528ec94dbc5SRasesh Mody * indices, to avoid unnecessary page advancing on the first
529ec94dbc5SRasesh Mody * call to ecore_chain_produce/consume. Instead, the indices
530ec94dbc5SRasesh Mody * will be advanced to page_cnt and then will be wrapped to 0.
531ec94dbc5SRasesh Mody */
532ec94dbc5SRasesh Mody u32 reset_val = p_chain->page_cnt - 1;
533ec94dbc5SRasesh Mody
534ec94dbc5SRasesh Mody if (is_chain_u16(p_chain)) {
535*766d68acSRasesh Mody p_chain->pbl.c.pbl_u16.prod_page_idx = (u16)reset_val;
536*766d68acSRasesh Mody p_chain->pbl.c.pbl_u16.cons_page_idx = (u16)reset_val;
537ec94dbc5SRasesh Mody } else {
538*766d68acSRasesh Mody p_chain->pbl.c.pbl_u32.prod_page_idx = reset_val;
539*766d68acSRasesh Mody p_chain->pbl.c.pbl_u32.cons_page_idx = reset_val;
540ec94dbc5SRasesh Mody }
541ec94dbc5SRasesh Mody }
542ec94dbc5SRasesh Mody
543ec94dbc5SRasesh Mody switch (p_chain->intended_use) {
544ec94dbc5SRasesh Mody case ECORE_CHAIN_USE_TO_CONSUME:
545ec94dbc5SRasesh Mody /* produce empty elements */
546ec94dbc5SRasesh Mody for (i = 0; i < p_chain->capacity; i++)
547ec94dbc5SRasesh Mody ecore_chain_recycle_consumed(p_chain);
548ec94dbc5SRasesh Mody break;
5496a0f9f5cSRasesh Mody
5506a0f9f5cSRasesh Mody case ECORE_CHAIN_USE_TO_CONSUME_PRODUCE:
5516a0f9f5cSRasesh Mody case ECORE_CHAIN_USE_TO_PRODUCE:
5526a0f9f5cSRasesh Mody default:
5536a0f9f5cSRasesh Mody /* Do nothing */
5546a0f9f5cSRasesh Mody break;
555ec94dbc5SRasesh Mody }
556ec94dbc5SRasesh Mody }
557ec94dbc5SRasesh Mody
558ec94dbc5SRasesh Mody /**
559ec94dbc5SRasesh Mody * @brief ecore_chain_init_params -
560ec94dbc5SRasesh Mody *
561ec94dbc5SRasesh Mody * Initalizes a basic chain struct
562ec94dbc5SRasesh Mody *
563ec94dbc5SRasesh Mody * @param p_chain
564ec94dbc5SRasesh Mody * @param page_cnt number of pages in the allocated buffer
565ec94dbc5SRasesh Mody * @param elem_size size of each element in the chain
566ec94dbc5SRasesh Mody * @param intended_use
567ec94dbc5SRasesh Mody * @param mode
568ec94dbc5SRasesh Mody * @param cnt_type
56922d07d93SRasesh Mody * @param dp_ctx
570ec94dbc5SRasesh Mody */
571ec94dbc5SRasesh Mody static OSAL_INLINE void
ecore_chain_init_params(struct ecore_chain * p_chain,u32 page_cnt,u8 elem_size,enum ecore_chain_use_mode intended_use,enum ecore_chain_mode mode,enum ecore_chain_cnt_type cnt_type,void * dp_ctx)572ec94dbc5SRasesh Mody ecore_chain_init_params(struct ecore_chain *p_chain, u32 page_cnt, u8 elem_size,
573ec94dbc5SRasesh Mody enum ecore_chain_use_mode intended_use,
574ec94dbc5SRasesh Mody enum ecore_chain_mode mode,
57522d07d93SRasesh Mody enum ecore_chain_cnt_type cnt_type, void *dp_ctx)
576ec94dbc5SRasesh Mody {
577ec94dbc5SRasesh Mody /* chain fixed parameters */
578ec94dbc5SRasesh Mody p_chain->p_virt_addr = OSAL_NULL;
579ec94dbc5SRasesh Mody p_chain->p_phys_addr = 0;
580ec94dbc5SRasesh Mody p_chain->elem_size = elem_size;
5816a0f9f5cSRasesh Mody p_chain->intended_use = (u8)intended_use;
582ec94dbc5SRasesh Mody p_chain->mode = mode;
5836a0f9f5cSRasesh Mody p_chain->cnt_type = (u8)cnt_type;
584ec94dbc5SRasesh Mody
585ec94dbc5SRasesh Mody p_chain->elem_per_page = ELEMS_PER_PAGE(elem_size);
586ec94dbc5SRasesh Mody p_chain->usable_per_page = USABLE_ELEMS_PER_PAGE(elem_size, mode);
587ec94dbc5SRasesh Mody p_chain->elem_per_page_mask = p_chain->elem_per_page - 1;
588ec94dbc5SRasesh Mody p_chain->elem_unusable = UNUSABLE_ELEMS_PER_PAGE(elem_size, mode);
589ec94dbc5SRasesh Mody p_chain->next_page_mask = (p_chain->usable_per_page &
590ec94dbc5SRasesh Mody p_chain->elem_per_page_mask);
591ec94dbc5SRasesh Mody
592ec94dbc5SRasesh Mody p_chain->page_cnt = page_cnt;
593ec94dbc5SRasesh Mody p_chain->capacity = p_chain->usable_per_page * page_cnt;
594ec94dbc5SRasesh Mody p_chain->size = p_chain->elem_per_page * page_cnt;
5956a0f9f5cSRasesh Mody p_chain->b_external_pbl = false;
5966a0f9f5cSRasesh Mody p_chain->pbl_sp.p_phys_table = 0;
5976a0f9f5cSRasesh Mody p_chain->pbl_sp.p_virt_table = OSAL_NULL;
598ec94dbc5SRasesh Mody p_chain->pbl.pp_virt_addr_tbl = OSAL_NULL;
59922d07d93SRasesh Mody
60022d07d93SRasesh Mody p_chain->dp_ctx = dp_ctx;
601ec94dbc5SRasesh Mody }
602ec94dbc5SRasesh Mody
603ec94dbc5SRasesh Mody /**
604ec94dbc5SRasesh Mody * @brief ecore_chain_init_mem -
605ec94dbc5SRasesh Mody *
606ec94dbc5SRasesh Mody * Initalizes a basic chain struct with its chain buffers
607ec94dbc5SRasesh Mody *
608ec94dbc5SRasesh Mody * @param p_chain
609ec94dbc5SRasesh Mody * @param p_virt_addr virtual address of allocated buffer's beginning
610ec94dbc5SRasesh Mody * @param p_phys_addr physical address of allocated buffer's beginning
611ec94dbc5SRasesh Mody *
612ec94dbc5SRasesh Mody */
ecore_chain_init_mem(struct ecore_chain * p_chain,void * p_virt_addr,dma_addr_t p_phys_addr)613ec94dbc5SRasesh Mody static OSAL_INLINE void ecore_chain_init_mem(struct ecore_chain *p_chain,
614ec94dbc5SRasesh Mody void *p_virt_addr,
615ec94dbc5SRasesh Mody dma_addr_t p_phys_addr)
616ec94dbc5SRasesh Mody {
617ec94dbc5SRasesh Mody p_chain->p_virt_addr = p_virt_addr;
618ec94dbc5SRasesh Mody p_chain->p_phys_addr = p_phys_addr;
619ec94dbc5SRasesh Mody }
620ec94dbc5SRasesh Mody
621ec94dbc5SRasesh Mody /**
622ec94dbc5SRasesh Mody * @brief ecore_chain_init_pbl_mem -
623ec94dbc5SRasesh Mody *
624ec94dbc5SRasesh Mody * Initalizes a basic chain struct with its pbl buffers
625ec94dbc5SRasesh Mody *
626ec94dbc5SRasesh Mody * @param p_chain
627ec94dbc5SRasesh Mody * @param p_virt_pbl pointer to a pre allocated side table which will hold
628ec94dbc5SRasesh Mody * virtual page addresses.
629ec94dbc5SRasesh Mody * @param p_phys_pbl pointer to a pre-allocated side table which will hold
630ec94dbc5SRasesh Mody * physical page addresses.
631ec94dbc5SRasesh Mody * @param pp_virt_addr_tbl
632ec94dbc5SRasesh Mody * pointer to a pre-allocated side table which will hold
633ec94dbc5SRasesh Mody * the virtual addresses of the chain pages.
634ec94dbc5SRasesh Mody *
635ec94dbc5SRasesh Mody */
ecore_chain_init_pbl_mem(struct ecore_chain * p_chain,void * p_virt_pbl,dma_addr_t p_phys_pbl,void ** pp_virt_addr_tbl)636ec94dbc5SRasesh Mody static OSAL_INLINE void ecore_chain_init_pbl_mem(struct ecore_chain *p_chain,
637ec94dbc5SRasesh Mody void *p_virt_pbl,
638ec94dbc5SRasesh Mody dma_addr_t p_phys_pbl,
639ec94dbc5SRasesh Mody void **pp_virt_addr_tbl)
640ec94dbc5SRasesh Mody {
6416a0f9f5cSRasesh Mody p_chain->pbl_sp.p_phys_table = p_phys_pbl;
6426a0f9f5cSRasesh Mody p_chain->pbl_sp.p_virt_table = p_virt_pbl;
643ec94dbc5SRasesh Mody p_chain->pbl.pp_virt_addr_tbl = pp_virt_addr_tbl;
644ec94dbc5SRasesh Mody }
645ec94dbc5SRasesh Mody
646ec94dbc5SRasesh Mody /**
647ec94dbc5SRasesh Mody * @brief ecore_chain_init_next_ptr_elem -
648ec94dbc5SRasesh Mody *
649ec94dbc5SRasesh Mody * Initalizes a next pointer element
650ec94dbc5SRasesh Mody *
651ec94dbc5SRasesh Mody * @param p_chain
652ec94dbc5SRasesh Mody * @param p_virt_curr virtual address of a chain page of which the next
653ec94dbc5SRasesh Mody * pointer element is initialized
654ec94dbc5SRasesh Mody * @param p_virt_next virtual address of the next chain page
655ec94dbc5SRasesh Mody * @param p_phys_next physical address of the next chain page
656ec94dbc5SRasesh Mody *
657ec94dbc5SRasesh Mody */
658ec94dbc5SRasesh Mody static OSAL_INLINE void
ecore_chain_init_next_ptr_elem(struct ecore_chain * p_chain,void * p_virt_curr,void * p_virt_next,dma_addr_t p_phys_next)659ec94dbc5SRasesh Mody ecore_chain_init_next_ptr_elem(struct ecore_chain *p_chain, void *p_virt_curr,
660ec94dbc5SRasesh Mody void *p_virt_next, dma_addr_t p_phys_next)
661ec94dbc5SRasesh Mody {
662ec94dbc5SRasesh Mody struct ecore_chain_next *p_next;
663ec94dbc5SRasesh Mody u32 size;
664ec94dbc5SRasesh Mody
665ec94dbc5SRasesh Mody size = p_chain->elem_size * p_chain->usable_per_page;
666ec94dbc5SRasesh Mody p_next = (struct ecore_chain_next *)((u8 *)p_virt_curr + size);
667ec94dbc5SRasesh Mody
668ec94dbc5SRasesh Mody DMA_REGPAIR_LE(p_next->next_phys, p_phys_next);
669ec94dbc5SRasesh Mody
670ec94dbc5SRasesh Mody p_next->next_virt = p_virt_next;
671ec94dbc5SRasesh Mody }
672ec94dbc5SRasesh Mody
673ec94dbc5SRasesh Mody /**
674ec94dbc5SRasesh Mody * @brief ecore_chain_get_last_elem -
675ec94dbc5SRasesh Mody *
676ec94dbc5SRasesh Mody * Returns a pointer to the last element of the chain
677ec94dbc5SRasesh Mody *
678ec94dbc5SRasesh Mody * @param p_chain
679ec94dbc5SRasesh Mody *
680ec94dbc5SRasesh Mody * @return void*
681ec94dbc5SRasesh Mody */
ecore_chain_get_last_elem(struct ecore_chain * p_chain)682ec94dbc5SRasesh Mody static OSAL_INLINE void *ecore_chain_get_last_elem(struct ecore_chain *p_chain)
683ec94dbc5SRasesh Mody {
684ec94dbc5SRasesh Mody struct ecore_chain_next *p_next = OSAL_NULL;
685ec94dbc5SRasesh Mody void *p_virt_addr = OSAL_NULL;
686ec94dbc5SRasesh Mody u32 size, last_page_idx;
687ec94dbc5SRasesh Mody
688ec94dbc5SRasesh Mody if (!p_chain->p_virt_addr)
689ec94dbc5SRasesh Mody goto out;
690ec94dbc5SRasesh Mody
691ec94dbc5SRasesh Mody switch (p_chain->mode) {
692ec94dbc5SRasesh Mody case ECORE_CHAIN_MODE_NEXT_PTR:
693ec94dbc5SRasesh Mody size = p_chain->elem_size * p_chain->usable_per_page;
694ec94dbc5SRasesh Mody p_virt_addr = p_chain->p_virt_addr;
695ec94dbc5SRasesh Mody p_next = (struct ecore_chain_next *)((u8 *)p_virt_addr + size);
696ec94dbc5SRasesh Mody while (p_next->next_virt != p_chain->p_virt_addr) {
697ec94dbc5SRasesh Mody p_virt_addr = p_next->next_virt;
698ec94dbc5SRasesh Mody p_next =
699ec94dbc5SRasesh Mody (struct ecore_chain_next *)((u8 *)p_virt_addr +
700ec94dbc5SRasesh Mody size);
701ec94dbc5SRasesh Mody }
702ec94dbc5SRasesh Mody break;
703ec94dbc5SRasesh Mody case ECORE_CHAIN_MODE_SINGLE:
704ec94dbc5SRasesh Mody p_virt_addr = p_chain->p_virt_addr;
705ec94dbc5SRasesh Mody break;
706ec94dbc5SRasesh Mody case ECORE_CHAIN_MODE_PBL:
707ec94dbc5SRasesh Mody last_page_idx = p_chain->page_cnt - 1;
708ec94dbc5SRasesh Mody p_virt_addr = p_chain->pbl.pp_virt_addr_tbl[last_page_idx];
709ec94dbc5SRasesh Mody break;
710ec94dbc5SRasesh Mody }
711ec94dbc5SRasesh Mody /* p_virt_addr points at this stage to the last page of the chain */
712ec94dbc5SRasesh Mody size = p_chain->elem_size * (p_chain->usable_per_page - 1);
713ec94dbc5SRasesh Mody p_virt_addr = ((u8 *)p_virt_addr + size);
714ec94dbc5SRasesh Mody out:
715ec94dbc5SRasesh Mody return p_virt_addr;
716ec94dbc5SRasesh Mody }
717ec94dbc5SRasesh Mody
718ec94dbc5SRasesh Mody /**
719ec94dbc5SRasesh Mody * @brief ecore_chain_set_prod - sets the prod to the given value
720ec94dbc5SRasesh Mody *
721ec94dbc5SRasesh Mody * @param prod_idx
722ec94dbc5SRasesh Mody * @param p_prod_elem
723ec94dbc5SRasesh Mody */
ecore_chain_set_prod(struct ecore_chain * p_chain,u32 prod_idx,void * p_prod_elem)724ec94dbc5SRasesh Mody static OSAL_INLINE void ecore_chain_set_prod(struct ecore_chain *p_chain,
725ec94dbc5SRasesh Mody u32 prod_idx, void *p_prod_elem)
726ec94dbc5SRasesh Mody {
727fe7572b6SRasesh Mody if (p_chain->mode == ECORE_CHAIN_MODE_PBL) {
728*766d68acSRasesh Mody u32 cur_prod, page_mask, page_cnt, page_diff;
729fe7572b6SRasesh Mody
730*766d68acSRasesh Mody cur_prod = is_chain_u16(p_chain) ? p_chain->u.chain16.prod_idx
731*766d68acSRasesh Mody : p_chain->u.chain32.prod_idx;
732*766d68acSRasesh Mody
733*766d68acSRasesh Mody /* Assume that number of elements in a page is power of 2 */
734*766d68acSRasesh Mody page_mask = ~p_chain->elem_per_page_mask;
735*766d68acSRasesh Mody
736*766d68acSRasesh Mody /* Use "cur_prod - 1" and "prod_idx - 1" since producer index
737*766d68acSRasesh Mody * reaches the first element of next page before the page index
738*766d68acSRasesh Mody * is incremented. See ecore_chain_produce().
739*766d68acSRasesh Mody * Index wrap around is not a problem because the difference
740*766d68acSRasesh Mody * between current and given producer indexes is always
741*766d68acSRasesh Mody * positive and lower than the chain's capacity.
742*766d68acSRasesh Mody */
743*766d68acSRasesh Mody page_diff = (((cur_prod - 1) & page_mask) -
744*766d68acSRasesh Mody ((prod_idx - 1) & page_mask)) /
745*766d68acSRasesh Mody p_chain->elem_per_page;
746*766d68acSRasesh Mody
747*766d68acSRasesh Mody page_cnt = ecore_chain_get_page_cnt(p_chain);
748fe7572b6SRasesh Mody if (is_chain_u16(p_chain))
749*766d68acSRasesh Mody p_chain->pbl.c.pbl_u16.prod_page_idx =
750*766d68acSRasesh Mody (p_chain->pbl.c.pbl_u16.prod_page_idx -
751*766d68acSRasesh Mody page_diff + page_cnt) % page_cnt;
752fe7572b6SRasesh Mody else
753*766d68acSRasesh Mody p_chain->pbl.c.pbl_u32.prod_page_idx =
754*766d68acSRasesh Mody (p_chain->pbl.c.pbl_u32.prod_page_idx -
755*766d68acSRasesh Mody page_diff + page_cnt) % page_cnt;
756fe7572b6SRasesh Mody }
757fe7572b6SRasesh Mody
758ec94dbc5SRasesh Mody if (is_chain_u16(p_chain))
759ec94dbc5SRasesh Mody p_chain->u.chain16.prod_idx = (u16)prod_idx;
760ec94dbc5SRasesh Mody else
761ec94dbc5SRasesh Mody p_chain->u.chain32.prod_idx = prod_idx;
762ec94dbc5SRasesh Mody p_chain->p_prod_elem = p_prod_elem;
763ec94dbc5SRasesh Mody }
764ec94dbc5SRasesh Mody
765ec94dbc5SRasesh Mody /**
766fe7572b6SRasesh Mody * @brief ecore_chain_set_cons - sets the cons to the given value
767fe7572b6SRasesh Mody *
768fe7572b6SRasesh Mody * @param cons_idx
769fe7572b6SRasesh Mody * @param p_cons_elem
770fe7572b6SRasesh Mody */
ecore_chain_set_cons(struct ecore_chain * p_chain,u32 cons_idx,void * p_cons_elem)771fe7572b6SRasesh Mody static OSAL_INLINE void ecore_chain_set_cons(struct ecore_chain *p_chain,
772fe7572b6SRasesh Mody u32 cons_idx, void *p_cons_elem)
773fe7572b6SRasesh Mody {
774fe7572b6SRasesh Mody if (p_chain->mode == ECORE_CHAIN_MODE_PBL) {
775*766d68acSRasesh Mody u32 cur_cons, page_mask, page_cnt, page_diff;
776fe7572b6SRasesh Mody
777*766d68acSRasesh Mody cur_cons = is_chain_u16(p_chain) ? p_chain->u.chain16.cons_idx
778*766d68acSRasesh Mody : p_chain->u.chain32.cons_idx;
779*766d68acSRasesh Mody
780*766d68acSRasesh Mody /* Assume that number of elements in a page is power of 2 */
781*766d68acSRasesh Mody page_mask = ~p_chain->elem_per_page_mask;
782*766d68acSRasesh Mody
783*766d68acSRasesh Mody /* Use "cur_cons - 1" and "cons_idx - 1" since consumer index
784*766d68acSRasesh Mody * reaches the first element of next page before the page index
785*766d68acSRasesh Mody * is incremented. See ecore_chain_consume().
786*766d68acSRasesh Mody * Index wrap around is not a problem because the difference
787*766d68acSRasesh Mody * between current and given consumer indexes is always
788*766d68acSRasesh Mody * positive and lower than the chain's capacity.
789*766d68acSRasesh Mody */
790*766d68acSRasesh Mody page_diff = (((cur_cons - 1) & page_mask) -
791*766d68acSRasesh Mody ((cons_idx - 1) & page_mask)) /
792*766d68acSRasesh Mody p_chain->elem_per_page;
793*766d68acSRasesh Mody
794*766d68acSRasesh Mody page_cnt = ecore_chain_get_page_cnt(p_chain);
795fe7572b6SRasesh Mody if (is_chain_u16(p_chain))
796*766d68acSRasesh Mody p_chain->pbl.c.pbl_u16.cons_page_idx =
797*766d68acSRasesh Mody (p_chain->pbl.c.pbl_u16.cons_page_idx -
798*766d68acSRasesh Mody page_diff + page_cnt) % page_cnt;
799fe7572b6SRasesh Mody else
800*766d68acSRasesh Mody p_chain->pbl.c.pbl_u32.cons_page_idx =
801*766d68acSRasesh Mody (p_chain->pbl.c.pbl_u32.cons_page_idx -
802*766d68acSRasesh Mody page_diff + page_cnt) % page_cnt;
803fe7572b6SRasesh Mody }
804fe7572b6SRasesh Mody
805fe7572b6SRasesh Mody if (is_chain_u16(p_chain))
806fe7572b6SRasesh Mody p_chain->u.chain16.cons_idx = (u16)cons_idx;
807fe7572b6SRasesh Mody else
808fe7572b6SRasesh Mody p_chain->u.chain32.cons_idx = cons_idx;
809fe7572b6SRasesh Mody
810fe7572b6SRasesh Mody p_chain->p_cons_elem = p_cons_elem;
811fe7572b6SRasesh Mody }
812fe7572b6SRasesh Mody
813fe7572b6SRasesh Mody /**
814ec94dbc5SRasesh Mody * @brief ecore_chain_pbl_zero_mem - set chain memory to 0
815ec94dbc5SRasesh Mody *
816ec94dbc5SRasesh Mody * @param p_chain
817ec94dbc5SRasesh Mody */
ecore_chain_pbl_zero_mem(struct ecore_chain * p_chain)818ec94dbc5SRasesh Mody static OSAL_INLINE void ecore_chain_pbl_zero_mem(struct ecore_chain *p_chain)
819ec94dbc5SRasesh Mody {
820ec94dbc5SRasesh Mody u32 i, page_cnt;
821ec94dbc5SRasesh Mody
822ec94dbc5SRasesh Mody if (p_chain->mode != ECORE_CHAIN_MODE_PBL)
823ec94dbc5SRasesh Mody return;
824ec94dbc5SRasesh Mody
825ec94dbc5SRasesh Mody page_cnt = ecore_chain_get_page_cnt(p_chain);
826ec94dbc5SRasesh Mody
827ec94dbc5SRasesh Mody for (i = 0; i < page_cnt; i++)
828ec94dbc5SRasesh Mody OSAL_MEM_ZERO(p_chain->pbl.pp_virt_addr_tbl[i],
829ec94dbc5SRasesh Mody ECORE_CHAIN_PAGE_SIZE);
830ec94dbc5SRasesh Mody }
831ec94dbc5SRasesh Mody
83222d07d93SRasesh Mody int ecore_chain_print(struct ecore_chain *p_chain, char *buffer,
83322d07d93SRasesh Mody u32 buffer_size, u32 *element_indx, u32 stop_indx,
83422d07d93SRasesh Mody bool print_metadata,
83522d07d93SRasesh Mody int (*func_ptr_print_element)(struct ecore_chain *p_chain,
83622d07d93SRasesh Mody void *p_element,
83722d07d93SRasesh Mody char *buffer),
83822d07d93SRasesh Mody int (*func_ptr_print_metadata)(struct ecore_chain
83922d07d93SRasesh Mody *p_chain,
84022d07d93SRasesh Mody char *buffer));
84122d07d93SRasesh Mody
842ec94dbc5SRasesh Mody #endif /* __ECORE_CHAIN_H__ */
843