xref: /dpdk/drivers/net/qede/base/ecore_chain.h (revision 766d68ac2d116f5a08de0b8667939408ce362c44)
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