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