1316485Sdavidcs/*
2337517Sdavidcs * Copyright (c) 2017-2018 Cavium, Inc.
3316485Sdavidcs * All rights reserved.
4316485Sdavidcs *
5316485Sdavidcs *  Redistribution and use in source and binary forms, with or without
6316485Sdavidcs *  modification, are permitted provided that the following conditions
7316485Sdavidcs *  are met:
8316485Sdavidcs *
9316485Sdavidcs *  1. Redistributions of source code must retain the above copyright
10316485Sdavidcs *     notice, this list of conditions and the following disclaimer.
11316485Sdavidcs *  2. Redistributions in binary form must reproduce the above copyright
12316485Sdavidcs *     notice, this list of conditions and the following disclaimer in the
13316485Sdavidcs *     documentation and/or other materials provided with the distribution.
14316485Sdavidcs *
15316485Sdavidcs *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16316485Sdavidcs *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17316485Sdavidcs *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18316485Sdavidcs *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19316485Sdavidcs *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20316485Sdavidcs *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21316485Sdavidcs *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22316485Sdavidcs *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23316485Sdavidcs *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24316485Sdavidcs *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25316485Sdavidcs *  POSSIBILITY OF SUCH DAMAGE.
26316485Sdavidcs *
27316485Sdavidcs * $FreeBSD: stable/11/sys/dev/qlnx/qlnxe/ecore_chain.h 337517 2018-08-09 01:17:35Z davidcs $
28316485Sdavidcs *
29316485Sdavidcs */
30316485Sdavidcs
31316485Sdavidcs#ifndef __ECORE_CHAIN_H__
32316485Sdavidcs#define __ECORE_CHAIN_H__
33316485Sdavidcs
34316485Sdavidcs#include "common_hsi.h"
35316485Sdavidcs#include "ecore_utils.h"
36316485Sdavidcs
37316485Sdavidcsenum ecore_chain_mode
38316485Sdavidcs{
39316485Sdavidcs	/* Each Page contains a next pointer at its end */
40316485Sdavidcs	ECORE_CHAIN_MODE_NEXT_PTR,
41316485Sdavidcs
42316485Sdavidcs	/* Chain is a single page (next ptr) is unrequired */
43316485Sdavidcs	ECORE_CHAIN_MODE_SINGLE,
44316485Sdavidcs
45316485Sdavidcs	/* Page pointers are located in a side list */
46316485Sdavidcs	ECORE_CHAIN_MODE_PBL,
47316485Sdavidcs};
48316485Sdavidcs
49316485Sdavidcsenum ecore_chain_use_mode
50316485Sdavidcs{
51316485Sdavidcs	ECORE_CHAIN_USE_TO_PRODUCE,		/* Chain starts empty */
52316485Sdavidcs	ECORE_CHAIN_USE_TO_CONSUME,		/* Chain starts full */
53316485Sdavidcs	ECORE_CHAIN_USE_TO_CONSUME_PRODUCE,	/* Chain starts empty */
54316485Sdavidcs};
55316485Sdavidcs
56316485Sdavidcsenum ecore_chain_cnt_type {
57316485Sdavidcs	/* The chain's size/prod/cons are kept in 16-bit variables */
58316485Sdavidcs	ECORE_CHAIN_CNT_TYPE_U16,
59316485Sdavidcs
60316485Sdavidcs	/* The chain's size/prod/cons are kept in 32-bit variables  */
61316485Sdavidcs	ECORE_CHAIN_CNT_TYPE_U32,
62316485Sdavidcs};
63316485Sdavidcs
64316485Sdavidcsstruct ecore_chain_next
65316485Sdavidcs{
66316485Sdavidcs	struct regpair	next_phys;
67316485Sdavidcs	void		*next_virt;
68316485Sdavidcs};
69316485Sdavidcs
70316485Sdavidcsstruct ecore_chain_pbl_u16 {
71316485Sdavidcs	u16	prod_page_idx;
72316485Sdavidcs	u16	cons_page_idx;
73316485Sdavidcs};
74316485Sdavidcs
75316485Sdavidcsstruct ecore_chain_pbl_u32 {
76316485Sdavidcs	u32	prod_page_idx;
77316485Sdavidcs	u32	cons_page_idx;
78316485Sdavidcs};
79316485Sdavidcs
80316485Sdavidcsstruct ecore_chain_ext_pbl
81316485Sdavidcs{
82316485Sdavidcs	dma_addr_t	p_pbl_phys;
83316485Sdavidcs	void		*p_pbl_virt;
84316485Sdavidcs};
85316485Sdavidcs
86316485Sdavidcsstruct ecore_chain_u16 {
87316485Sdavidcs	/* Cyclic index of next element to produce/consme */
88316485Sdavidcs	u16	prod_idx;
89316485Sdavidcs	u16	cons_idx;
90316485Sdavidcs};
91316485Sdavidcs
92316485Sdavidcsstruct ecore_chain_u32 {
93316485Sdavidcs	/* Cyclic index of next element to produce/consme */
94316485Sdavidcs	u32	prod_idx;
95316485Sdavidcs	u32	cons_idx;
96316485Sdavidcs};
97316485Sdavidcs
98316485Sdavidcsstruct ecore_chain
99316485Sdavidcs{
100316485Sdavidcs	/* fastpath portion of the chain - required for commands such
101316485Sdavidcs	 * as produce / consume.
102316485Sdavidcs	 */
103316485Sdavidcs	/* Point to next element to produce/consume */
104316485Sdavidcs	void				*p_prod_elem;
105316485Sdavidcs	void				*p_cons_elem;
106316485Sdavidcs
107316485Sdavidcs	/* Fastpath portions of the PBL [if exists] */
108316485Sdavidcs
109316485Sdavidcs	struct {
110316485Sdavidcs		/* Table for keeping the virtual addresses of the chain pages,
111316485Sdavidcs		 * respectively to the physical addresses in the pbl table.
112316485Sdavidcs		 */
113316485Sdavidcs		void		**pp_virt_addr_tbl;
114316485Sdavidcs
115316485Sdavidcs		union {
116316485Sdavidcs			struct ecore_chain_pbl_u16	pbl_u16;
117316485Sdavidcs			struct ecore_chain_pbl_u32	pbl_u32;
118316485Sdavidcs		} c;
119316485Sdavidcs	} pbl;
120316485Sdavidcs
121316485Sdavidcs	union {
122316485Sdavidcs		struct ecore_chain_u16	chain16;
123316485Sdavidcs		struct ecore_chain_u32	chain32;
124316485Sdavidcs	} u;
125316485Sdavidcs
126316485Sdavidcs	/* Capacity counts only usable elements */
127316485Sdavidcs	u32				capacity;
128316485Sdavidcs	u32				page_cnt;
129316485Sdavidcs
130316485Sdavidcs	/* A u8 would suffice for mode, but it would save as a lot of headaches
131316485Sdavidcs	 * on castings & defaults.
132316485Sdavidcs	 */
133316485Sdavidcs	enum ecore_chain_mode		mode;
134316485Sdavidcs
135316485Sdavidcs	/* Elements information for fast calculations */
136316485Sdavidcs	u16				elem_per_page;
137316485Sdavidcs	u16				elem_per_page_mask;
138316485Sdavidcs	u16				elem_size;
139316485Sdavidcs	u16				next_page_mask;
140316485Sdavidcs	u16				usable_per_page;
141316485Sdavidcs	u8				elem_unusable;
142316485Sdavidcs
143316485Sdavidcs	u8				cnt_type;
144316485Sdavidcs
145316485Sdavidcs	/* Slowpath of the chain - required for initialization and destruction,
146316485Sdavidcs	 * but isn't involved in regular functionality.
147316485Sdavidcs	 */
148316485Sdavidcs
149316485Sdavidcs	/* Base address of a pre-allocated buffer for pbl */
150316485Sdavidcs	struct {
151316485Sdavidcs		dma_addr_t		p_phys_table;
152316485Sdavidcs		void			*p_virt_table;
153316485Sdavidcs	} pbl_sp;
154316485Sdavidcs
155316485Sdavidcs	/* Address of first page of the chain  - the address is required
156316485Sdavidcs	 * for fastpath operation [consume/produce] but only for the the SINGLE
157316485Sdavidcs	 * flavour which isn't considered fastpath [== SPQ].
158316485Sdavidcs	 */
159316485Sdavidcs	void				*p_virt_addr;
160316485Sdavidcs	dma_addr_t			p_phys_addr;
161316485Sdavidcs
162316485Sdavidcs	/* Total number of elements [for entire chain] */
163316485Sdavidcs	u32				size;
164316485Sdavidcs
165316485Sdavidcs	u8				intended_use;
166316485Sdavidcs
167316485Sdavidcs	/* TBD - do we really need this? Couldn't find usage for it */
168316485Sdavidcs	bool				b_external_pbl;
169316485Sdavidcs
170316485Sdavidcs	void				*dp_ctx;
171316485Sdavidcs};
172316485Sdavidcs
173316485Sdavidcs#define ECORE_CHAIN_PBL_ENTRY_SIZE	(8)
174316485Sdavidcs#define ECORE_CHAIN_PAGE_SIZE		(0x1000)
175316485Sdavidcs#define ELEMS_PER_PAGE(elem_size)	(ECORE_CHAIN_PAGE_SIZE/(elem_size))
176316485Sdavidcs
177316485Sdavidcs#define UNUSABLE_ELEMS_PER_PAGE(elem_size, mode)		\
178316485Sdavidcs	  ((mode == ECORE_CHAIN_MODE_NEXT_PTR) ? 		\
179316485Sdavidcs	   (u8)(1 + ((sizeof(struct ecore_chain_next)-1) /	\
180316485Sdavidcs		     (elem_size))) : 0)
181316485Sdavidcs
182316485Sdavidcs#define USABLE_ELEMS_PER_PAGE(elem_size, mode)			\
183316485Sdavidcs	  ((u32) (ELEMS_PER_PAGE(elem_size) - 			\
184316485Sdavidcs	  	  UNUSABLE_ELEMS_PER_PAGE(elem_size, mode)))
185316485Sdavidcs
186316485Sdavidcs#define ECORE_CHAIN_PAGE_CNT(elem_cnt, elem_size, mode)		\
187316485Sdavidcs	DIV_ROUND_UP(elem_cnt, USABLE_ELEMS_PER_PAGE(elem_size, mode))
188316485Sdavidcs
189316485Sdavidcs#define is_chain_u16(p)	((p)->cnt_type == ECORE_CHAIN_CNT_TYPE_U16)
190316485Sdavidcs#define is_chain_u32(p)	((p)->cnt_type == ECORE_CHAIN_CNT_TYPE_U32)
191316485Sdavidcs
192316485Sdavidcs/* Accessors */
193316485Sdavidcsstatic OSAL_INLINE u16 ecore_chain_get_prod_idx(struct ecore_chain *p_chain)
194316485Sdavidcs{
195316485Sdavidcs	OSAL_ASSERT(is_chain_u16(p_chain));
196316485Sdavidcs	return p_chain->u.chain16.prod_idx;
197316485Sdavidcs}
198316485Sdavidcs
199337517Sdavidcs#ifndef LINUX_REMOVE
200316485Sdavidcsstatic OSAL_INLINE u32 ecore_chain_get_prod_idx_u32(struct ecore_chain *p_chain)
201316485Sdavidcs{
202316485Sdavidcs	OSAL_ASSERT(is_chain_u32(p_chain));
203316485Sdavidcs	return p_chain->u.chain32.prod_idx;
204316485Sdavidcs}
205337517Sdavidcs#endif
206316485Sdavidcs
207316485Sdavidcsstatic OSAL_INLINE u16 ecore_chain_get_cons_idx(struct ecore_chain *p_chain)
208316485Sdavidcs{
209316485Sdavidcs	OSAL_ASSERT(is_chain_u16(p_chain));
210316485Sdavidcs	return p_chain->u.chain16.cons_idx;
211316485Sdavidcs}
212316485Sdavidcs
213316485Sdavidcsstatic OSAL_INLINE u32 ecore_chain_get_cons_idx_u32(struct ecore_chain *p_chain)
214316485Sdavidcs{
215316485Sdavidcs	OSAL_ASSERT(is_chain_u32(p_chain));
216316485Sdavidcs	return p_chain->u.chain32.cons_idx;
217316485Sdavidcs}
218316485Sdavidcs
219320164Sdavidcs/* FIXME:
220320164Sdavidcs * Should create OSALs for the below definitions.
221320164Sdavidcs * For Linux, replace them with the existing U16_MAX and U32_MAX, and handle
222320164Sdavidcs * kernel versions that lack them.
223320164Sdavidcs */
224316485Sdavidcs#define ECORE_U16_MAX	((u16)~0U)
225316485Sdavidcs#define ECORE_U32_MAX	((u32)~0U)
226316485Sdavidcs
227316485Sdavidcsstatic OSAL_INLINE u16 ecore_chain_get_elem_left(struct ecore_chain *p_chain)
228316485Sdavidcs{
229316485Sdavidcs	u16 used;
230316485Sdavidcs
231316485Sdavidcs	OSAL_ASSERT(is_chain_u16(p_chain));
232316485Sdavidcs
233316485Sdavidcs	used = (u16)(((u32)ECORE_U16_MAX + 1 +
234316485Sdavidcs		      (u32)(p_chain->u.chain16.prod_idx)) -
235316485Sdavidcs		     (u32)p_chain->u.chain16.cons_idx);
236316485Sdavidcs	if (p_chain->mode == ECORE_CHAIN_MODE_NEXT_PTR)
237337517Sdavidcs		used -= (((u32)ECORE_U16_MAX + 1) / p_chain->elem_per_page +
238337517Sdavidcs			 p_chain->u.chain16.prod_idx / p_chain->elem_per_page -
239337517Sdavidcs			 p_chain->u.chain16.cons_idx / p_chain->elem_per_page) %
240337517Sdavidcs			p_chain->page_cnt;
241316485Sdavidcs
242316485Sdavidcs	return (u16)(p_chain->capacity - used);
243316485Sdavidcs}
244316485Sdavidcs
245316485Sdavidcsstatic OSAL_INLINE u32
246316485Sdavidcsecore_chain_get_elem_left_u32(struct ecore_chain *p_chain)
247316485Sdavidcs{
248316485Sdavidcs	u32 used;
249316485Sdavidcs
250316485Sdavidcs	OSAL_ASSERT(is_chain_u32(p_chain));
251316485Sdavidcs
252316485Sdavidcs	used = (u32)(((u64)ECORE_U32_MAX + 1 +
253316485Sdavidcs		      (u64)(p_chain->u.chain32.prod_idx)) -
254316485Sdavidcs		     (u64)p_chain->u.chain32.cons_idx);
255316485Sdavidcs	if (p_chain->mode == ECORE_CHAIN_MODE_NEXT_PTR)
256337517Sdavidcs		used -= (((u64)ECORE_U32_MAX + 1) / p_chain->elem_per_page +
257337517Sdavidcs			 p_chain->u.chain32.prod_idx / p_chain->elem_per_page -
258337517Sdavidcs			 p_chain->u.chain32.cons_idx / p_chain->elem_per_page) %
259337517Sdavidcs			p_chain->page_cnt;
260316485Sdavidcs
261316485Sdavidcs	return p_chain->capacity - used;
262316485Sdavidcs}
263316485Sdavidcs
264337517Sdavidcs#ifndef LINUX_REMOVE
265316485Sdavidcsstatic OSAL_INLINE u8 ecore_chain_is_full(struct ecore_chain *p_chain)
266316485Sdavidcs{
267316485Sdavidcs	if (is_chain_u16(p_chain))
268316485Sdavidcs		return (ecore_chain_get_elem_left(p_chain) ==
269316485Sdavidcs			p_chain->capacity);
270316485Sdavidcs	else
271316485Sdavidcs		return (ecore_chain_get_elem_left_u32(p_chain) ==
272316485Sdavidcs			p_chain->capacity);
273316485Sdavidcs}
274316485Sdavidcs
275316485Sdavidcsstatic OSAL_INLINE u8 ecore_chain_is_empty(struct ecore_chain *p_chain)
276316485Sdavidcs{
277316485Sdavidcs	if (is_chain_u16(p_chain))
278316485Sdavidcs		return (ecore_chain_get_elem_left(p_chain) == 0);
279316485Sdavidcs	else
280316485Sdavidcs		return (ecore_chain_get_elem_left_u32(p_chain) == 0);
281316485Sdavidcs}
282316485Sdavidcs
283316485Sdavidcsstatic OSAL_INLINE
284316485Sdavidcsu16 ecore_chain_get_elem_per_page(struct ecore_chain *p_chain)
285316485Sdavidcs{
286316485Sdavidcs	return p_chain->elem_per_page;
287316485Sdavidcs}
288337517Sdavidcs#endif
289316485Sdavidcs
290316485Sdavidcsstatic OSAL_INLINE
291316485Sdavidcsu16 ecore_chain_get_usable_per_page(struct ecore_chain *p_chain)
292316485Sdavidcs{
293316485Sdavidcs	return p_chain->usable_per_page;
294316485Sdavidcs}
295316485Sdavidcs
296316485Sdavidcsstatic OSAL_INLINE
297316485Sdavidcsu8 ecore_chain_get_unusable_per_page(struct ecore_chain *p_chain)
298316485Sdavidcs{
299316485Sdavidcs	return p_chain->elem_unusable;
300316485Sdavidcs}
301316485Sdavidcs
302337517Sdavidcs#ifndef LINUX_REMOVE
303316485Sdavidcsstatic OSAL_INLINE u32 ecore_chain_get_size(struct ecore_chain *p_chain)
304316485Sdavidcs{
305316485Sdavidcs	return p_chain->size;
306316485Sdavidcs}
307337517Sdavidcs#endif
308316485Sdavidcs
309316485Sdavidcsstatic OSAL_INLINE u32 ecore_chain_get_page_cnt(struct ecore_chain *p_chain)
310316485Sdavidcs{
311316485Sdavidcs	return p_chain->page_cnt;
312316485Sdavidcs}
313316485Sdavidcs
314316485Sdavidcsstatic OSAL_INLINE
315316485Sdavidcsdma_addr_t ecore_chain_get_pbl_phys(struct ecore_chain *p_chain)
316316485Sdavidcs{
317316485Sdavidcs	return p_chain->pbl_sp.p_phys_table;
318316485Sdavidcs}
319316485Sdavidcs
320316485Sdavidcs/**
321316485Sdavidcs * @brief ecore_chain_advance_page -
322316485Sdavidcs *
323316485Sdavidcs * Advance the next element accros pages for a linked chain
324316485Sdavidcs *
325316485Sdavidcs * @param p_chain
326316485Sdavidcs * @param p_next_elem
327316485Sdavidcs * @param idx_to_inc
328316485Sdavidcs * @param page_to_inc
329316485Sdavidcs */
330316485Sdavidcsstatic OSAL_INLINE void
331316485Sdavidcsecore_chain_advance_page(struct ecore_chain *p_chain, void **p_next_elem,
332316485Sdavidcs			 void *idx_to_inc, void *page_to_inc)
333316485Sdavidcs{
334316485Sdavidcs	struct ecore_chain_next *p_next = OSAL_NULL;
335316485Sdavidcs	u32 page_index = 0;
336316485Sdavidcs
337316485Sdavidcs	switch(p_chain->mode) {
338316485Sdavidcs	case ECORE_CHAIN_MODE_NEXT_PTR:
339316485Sdavidcs		p_next = (struct ecore_chain_next *)(*p_next_elem);
340316485Sdavidcs		*p_next_elem = p_next->next_virt;
341316485Sdavidcs		if (is_chain_u16(p_chain))
342316485Sdavidcs			*(u16 *)idx_to_inc += (u16)p_chain->elem_unusable;
343316485Sdavidcs		else
344316485Sdavidcs			*(u32 *)idx_to_inc += (u16)p_chain->elem_unusable;
345316485Sdavidcs		break;
346316485Sdavidcs	case ECORE_CHAIN_MODE_SINGLE:
347316485Sdavidcs		*p_next_elem = p_chain->p_virt_addr;
348316485Sdavidcs		break;
349316485Sdavidcs	case ECORE_CHAIN_MODE_PBL:
350316485Sdavidcs		if (is_chain_u16(p_chain)) {
351316485Sdavidcs			if (++(*(u16 *)page_to_inc) == p_chain->page_cnt)
352316485Sdavidcs				*(u16 *)page_to_inc = 0;
353316485Sdavidcs			page_index = *(u16 *)page_to_inc;
354316485Sdavidcs		} else {
355316485Sdavidcs			if (++(*(u32 *)page_to_inc) == p_chain->page_cnt)
356316485Sdavidcs				*(u32 *)page_to_inc = 0;
357316485Sdavidcs			page_index = *(u32 *)page_to_inc;
358316485Sdavidcs		}
359316485Sdavidcs		*p_next_elem = p_chain->pbl.pp_virt_addr_tbl[page_index];
360316485Sdavidcs	}
361316485Sdavidcs}
362316485Sdavidcs
363316485Sdavidcs#define is_unusable_idx(p, idx)			\
364316485Sdavidcs	(((p)->u.chain16.idx & (p)->elem_per_page_mask) == (p)->usable_per_page)
365316485Sdavidcs
366316485Sdavidcs#define is_unusable_idx_u32(p, idx)		\
367316485Sdavidcs	(((p)->u.chain32.idx & (p)->elem_per_page_mask) == (p)->usable_per_page)
368316485Sdavidcs
369316485Sdavidcs#define is_unusable_next_idx(p, idx)		\
370316485Sdavidcs	((((p)->u.chain16.idx + 1) & (p)->elem_per_page_mask) == (p)->usable_per_page)
371316485Sdavidcs
372316485Sdavidcs#define is_unusable_next_idx_u32(p, idx)	\
373316485Sdavidcs	((((p)->u.chain32.idx + 1) & (p)->elem_per_page_mask) == (p)->usable_per_page)
374316485Sdavidcs
375316485Sdavidcs#define test_and_skip(p, idx)							\
376316485Sdavidcs	do {									\
377316485Sdavidcs		if (is_chain_u16(p)) {						\
378316485Sdavidcs			if (is_unusable_idx(p, idx))				\
379316485Sdavidcs				(p)->u.chain16.idx += (p)->elem_unusable;	\
380316485Sdavidcs		} else {							\
381316485Sdavidcs			if (is_unusable_idx_u32(p, idx))			\
382316485Sdavidcs				(p)->u.chain32.idx += (p)->elem_unusable;	\
383316485Sdavidcs		}								\
384316485Sdavidcs	} while (0)
385316485Sdavidcs
386337517Sdavidcs#ifndef LINUX_REMOVE
387316485Sdavidcs/**
388316485Sdavidcs * @brief ecore_chain_return_multi_produced -
389316485Sdavidcs *
390316485Sdavidcs * A chain in which the driver "Produces" elements should use this API
391316485Sdavidcs * to indicate previous produced elements are now consumed.
392316485Sdavidcs *
393316485Sdavidcs * @param p_chain
394316485Sdavidcs * @param num
395316485Sdavidcs */
396316485Sdavidcsstatic OSAL_INLINE
397316485Sdavidcsvoid ecore_chain_return_multi_produced(struct ecore_chain *p_chain, u32 num)
398316485Sdavidcs{
399316485Sdavidcs	if (is_chain_u16(p_chain))
400316485Sdavidcs		p_chain->u.chain16.cons_idx += (u16)num;
401316485Sdavidcs	else
402316485Sdavidcs		p_chain->u.chain32.cons_idx += num;
403316485Sdavidcs	test_and_skip(p_chain, cons_idx);
404316485Sdavidcs}
405337517Sdavidcs#endif
406316485Sdavidcs
407316485Sdavidcs/**
408316485Sdavidcs * @brief ecore_chain_return_produced -
409316485Sdavidcs *
410316485Sdavidcs * A chain in which the driver "Produces" elements should use this API
411316485Sdavidcs * to indicate previous produced elements are now consumed.
412316485Sdavidcs *
413316485Sdavidcs * @param p_chain
414316485Sdavidcs */
415316485Sdavidcsstatic OSAL_INLINE void ecore_chain_return_produced(struct ecore_chain *p_chain)
416316485Sdavidcs{
417316485Sdavidcs	if (is_chain_u16(p_chain))
418316485Sdavidcs		p_chain->u.chain16.cons_idx++;
419316485Sdavidcs	else
420316485Sdavidcs		p_chain->u.chain32.cons_idx++;
421316485Sdavidcs	test_and_skip(p_chain, cons_idx);
422316485Sdavidcs}
423316485Sdavidcs
424316485Sdavidcs/**
425316485Sdavidcs * @brief ecore_chain_produce -
426316485Sdavidcs *
427316485Sdavidcs * A chain in which the driver "Produces" elements should use this to get
428316485Sdavidcs * a pointer to the next element which can be "Produced". It's driver
429316485Sdavidcs * responsibility to validate that the chain has room for new element.
430316485Sdavidcs *
431316485Sdavidcs * @param p_chain
432316485Sdavidcs *
433316485Sdavidcs * @return void*, a pointer to next element
434316485Sdavidcs */
435316485Sdavidcsstatic OSAL_INLINE void *ecore_chain_produce(struct ecore_chain *p_chain)
436316485Sdavidcs{
437316485Sdavidcs	void *p_ret = OSAL_NULL, *p_prod_idx, *p_prod_page_idx;
438316485Sdavidcs
439316485Sdavidcs	if (is_chain_u16(p_chain)) {
440316485Sdavidcs		if ((p_chain->u.chain16.prod_idx &
441316485Sdavidcs		     p_chain->elem_per_page_mask) ==
442316485Sdavidcs		    p_chain->next_page_mask) {
443316485Sdavidcs			p_prod_idx = &p_chain->u.chain16.prod_idx;
444316485Sdavidcs			p_prod_page_idx = &p_chain->pbl.c.pbl_u16.prod_page_idx;
445316485Sdavidcs			ecore_chain_advance_page(p_chain, &p_chain->p_prod_elem,
446316485Sdavidcs						 p_prod_idx, p_prod_page_idx);
447316485Sdavidcs		}
448316485Sdavidcs		p_chain->u.chain16.prod_idx++;
449316485Sdavidcs	} else {
450316485Sdavidcs		if ((p_chain->u.chain32.prod_idx &
451316485Sdavidcs		     p_chain->elem_per_page_mask) ==
452316485Sdavidcs		    p_chain->next_page_mask) {
453316485Sdavidcs			p_prod_idx = &p_chain->u.chain32.prod_idx;
454316485Sdavidcs			p_prod_page_idx = &p_chain->pbl.c.pbl_u32.prod_page_idx;
455316485Sdavidcs			ecore_chain_advance_page(p_chain, &p_chain->p_prod_elem,
456316485Sdavidcs						 p_prod_idx, p_prod_page_idx);
457316485Sdavidcs		}
458316485Sdavidcs		p_chain->u.chain32.prod_idx++;
459316485Sdavidcs	}
460316485Sdavidcs
461316485Sdavidcs	p_ret = p_chain->p_prod_elem;
462316485Sdavidcs	p_chain->p_prod_elem = (void*)(((u8*)p_chain->p_prod_elem) +
463316485Sdavidcs				       p_chain->elem_size);
464316485Sdavidcs
465316485Sdavidcs	return p_ret;
466316485Sdavidcs}
467316485Sdavidcs
468316485Sdavidcs/**
469316485Sdavidcs * @brief ecore_chain_get_capacity -
470316485Sdavidcs *
471316485Sdavidcs * Get the maximum number of BDs in chain
472316485Sdavidcs *
473316485Sdavidcs * @param p_chain
474316485Sdavidcs * @param num
475316485Sdavidcs *
476316485Sdavidcs * @return number of unusable BDs
477316485Sdavidcs */
478316485Sdavidcsstatic OSAL_INLINE u32 ecore_chain_get_capacity(struct ecore_chain *p_chain)
479316485Sdavidcs{
480316485Sdavidcs	return p_chain->capacity;
481316485Sdavidcs}
482316485Sdavidcs
483316485Sdavidcs/**
484316485Sdavidcs * @brief ecore_chain_recycle_consumed -
485316485Sdavidcs *
486316485Sdavidcs * Returns an element which was previously consumed;
487316485Sdavidcs * Increments producers so they could be written to FW.
488316485Sdavidcs *
489316485Sdavidcs * @param p_chain
490316485Sdavidcs */
491316485Sdavidcsstatic OSAL_INLINE
492316485Sdavidcsvoid ecore_chain_recycle_consumed(struct ecore_chain *p_chain)
493316485Sdavidcs{
494316485Sdavidcs	test_and_skip(p_chain, prod_idx);
495316485Sdavidcs	if (is_chain_u16(p_chain))
496316485Sdavidcs		p_chain->u.chain16.prod_idx++;
497316485Sdavidcs	else
498316485Sdavidcs		p_chain->u.chain32.prod_idx++;
499316485Sdavidcs}
500316485Sdavidcs
501316485Sdavidcs/**
502316485Sdavidcs * @brief ecore_chain_consume -
503316485Sdavidcs *
504316485Sdavidcs * A Chain in which the driver utilizes data written by a different source
505316485Sdavidcs * (i.e., FW) should use this to access passed buffers.
506316485Sdavidcs *
507316485Sdavidcs * @param p_chain
508316485Sdavidcs *
509316485Sdavidcs * @return void*, a pointer to the next buffer written
510316485Sdavidcs */
511316485Sdavidcsstatic OSAL_INLINE void *ecore_chain_consume(struct ecore_chain *p_chain)
512316485Sdavidcs{
513316485Sdavidcs	void *p_ret = OSAL_NULL, *p_cons_idx, *p_cons_page_idx;
514316485Sdavidcs
515316485Sdavidcs	if (is_chain_u16(p_chain)) {
516316485Sdavidcs		if ((p_chain->u.chain16.cons_idx &
517316485Sdavidcs		     p_chain->elem_per_page_mask) ==
518316485Sdavidcs		    p_chain->next_page_mask) {
519316485Sdavidcs			p_cons_idx = &p_chain->u.chain16.cons_idx;
520316485Sdavidcs			p_cons_page_idx = &p_chain->pbl.c.pbl_u16.cons_page_idx;
521316485Sdavidcs			ecore_chain_advance_page(p_chain, &p_chain->p_cons_elem,
522316485Sdavidcs						 p_cons_idx, p_cons_page_idx);
523316485Sdavidcs		}
524316485Sdavidcs		p_chain->u.chain16.cons_idx++;
525316485Sdavidcs	} else {
526316485Sdavidcs		if ((p_chain->u.chain32.cons_idx &
527316485Sdavidcs		     p_chain->elem_per_page_mask) ==
528316485Sdavidcs		    p_chain->next_page_mask) {
529316485Sdavidcs			p_cons_idx = &p_chain->u.chain32.cons_idx;
530316485Sdavidcs			p_cons_page_idx = &p_chain->pbl.c.pbl_u32.cons_page_idx;
531316485Sdavidcs			ecore_chain_advance_page(p_chain, &p_chain->p_cons_elem,
532316485Sdavidcs						 p_cons_idx, p_cons_page_idx);
533316485Sdavidcs		}
534316485Sdavidcs		p_chain->u.chain32.cons_idx++;
535316485Sdavidcs	}
536316485Sdavidcs
537316485Sdavidcs	p_ret = p_chain->p_cons_elem;
538316485Sdavidcs	p_chain->p_cons_elem = (void*)(((u8*)p_chain->p_cons_elem) +
539316485Sdavidcs				       p_chain->elem_size);
540316485Sdavidcs
541316485Sdavidcs	return p_ret;
542316485Sdavidcs}
543316485Sdavidcs
544316485Sdavidcs/**
545316485Sdavidcs * @brief ecore_chain_reset -
546316485Sdavidcs *
547316485Sdavidcs * Resets the chain to its start state
548316485Sdavidcs *
549316485Sdavidcs * @param p_chain pointer to a previously allocted chain
550316485Sdavidcs */
551316485Sdavidcsstatic OSAL_INLINE void ecore_chain_reset(struct ecore_chain *p_chain)
552316485Sdavidcs{
553316485Sdavidcs	u32 i;
554316485Sdavidcs
555316485Sdavidcs	if (is_chain_u16(p_chain)) {
556316485Sdavidcs		p_chain->u.chain16.prod_idx = 0;
557316485Sdavidcs		p_chain->u.chain16.cons_idx = 0;
558316485Sdavidcs	} else {
559316485Sdavidcs		p_chain->u.chain32.prod_idx = 0;
560316485Sdavidcs		p_chain->u.chain32.cons_idx = 0;
561316485Sdavidcs	}
562316485Sdavidcs	p_chain->p_cons_elem = p_chain->p_virt_addr;
563316485Sdavidcs	p_chain->p_prod_elem = p_chain->p_virt_addr;
564316485Sdavidcs
565316485Sdavidcs	if (p_chain->mode == ECORE_CHAIN_MODE_PBL) {
566337517Sdavidcs		/* Use "page_cnt-1" as a reset value for the prod/cons page's
567316485Sdavidcs		 * indices, to avoid unnecessary page advancing on the first
568316485Sdavidcs		 * call to ecore_chain_produce/consume. Instead, the indices
569316485Sdavidcs		 * will be advanced to page_cnt and then will be wrapped to 0.
570316485Sdavidcs		 */
571316485Sdavidcs		u32 reset_val = p_chain->page_cnt - 1;
572316485Sdavidcs
573316485Sdavidcs		if (is_chain_u16(p_chain)) {
574316485Sdavidcs			p_chain->pbl.c.pbl_u16.prod_page_idx = (u16)reset_val;
575316485Sdavidcs			p_chain->pbl.c.pbl_u16.cons_page_idx = (u16)reset_val;
576316485Sdavidcs		} else {
577316485Sdavidcs			p_chain->pbl.c.pbl_u32.prod_page_idx = reset_val;
578316485Sdavidcs			p_chain->pbl.c.pbl_u32.cons_page_idx = reset_val;
579316485Sdavidcs		}
580316485Sdavidcs	}
581316485Sdavidcs
582316485Sdavidcs	switch (p_chain->intended_use) {
583316485Sdavidcs	case ECORE_CHAIN_USE_TO_CONSUME:
584316485Sdavidcs		/* produce empty elements */
585316485Sdavidcs		for (i = 0; i < p_chain->capacity; i++)
586316485Sdavidcs			ecore_chain_recycle_consumed(p_chain);
587316485Sdavidcs		break;
588316485Sdavidcs
589316485Sdavidcs	case ECORE_CHAIN_USE_TO_CONSUME_PRODUCE:
590316485Sdavidcs	case ECORE_CHAIN_USE_TO_PRODUCE:
591316485Sdavidcs	default:
592316485Sdavidcs		/* Do nothing */
593316485Sdavidcs		break;
594316485Sdavidcs	}
595316485Sdavidcs}
596316485Sdavidcs
597316485Sdavidcs/**
598316485Sdavidcs * @brief ecore_chain_init_params -
599316485Sdavidcs *
600316485Sdavidcs * Initalizes a basic chain struct
601316485Sdavidcs *
602316485Sdavidcs * @param p_chain
603316485Sdavidcs * @param page_cnt	number of pages in the allocated buffer
604316485Sdavidcs * @param elem_size	size of each element in the chain
605316485Sdavidcs * @param intended_use
606316485Sdavidcs * @param mode
607316485Sdavidcs * @param cnt_type
608316485Sdavidcs * @param dp_ctx
609316485Sdavidcs */
610316485Sdavidcsstatic OSAL_INLINE void
611316485Sdavidcsecore_chain_init_params(struct ecore_chain *p_chain, u32 page_cnt, u8 elem_size,
612316485Sdavidcs			enum ecore_chain_use_mode intended_use,
613316485Sdavidcs			enum ecore_chain_mode mode,
614316485Sdavidcs			enum ecore_chain_cnt_type cnt_type, void *dp_ctx)
615316485Sdavidcs{
616316485Sdavidcs	/* chain fixed parameters */
617316485Sdavidcs	p_chain->p_virt_addr = OSAL_NULL;
618316485Sdavidcs	p_chain->p_phys_addr = 0;
619316485Sdavidcs	p_chain->elem_size = elem_size;
620316485Sdavidcs	p_chain->intended_use = (u8)intended_use;
621316485Sdavidcs	p_chain->mode = mode;
622316485Sdavidcs	p_chain->cnt_type = (u8)cnt_type;
623316485Sdavidcs
624316485Sdavidcs	p_chain->elem_per_page = ELEMS_PER_PAGE(elem_size);
625316485Sdavidcs	p_chain->usable_per_page = USABLE_ELEMS_PER_PAGE(elem_size, mode);
626316485Sdavidcs	p_chain->elem_per_page_mask = p_chain->elem_per_page - 1;
627316485Sdavidcs	p_chain->elem_unusable = UNUSABLE_ELEMS_PER_PAGE(elem_size, mode);
628316485Sdavidcs	p_chain->next_page_mask = (p_chain->usable_per_page &
629316485Sdavidcs				   p_chain->elem_per_page_mask);
630316485Sdavidcs
631316485Sdavidcs	p_chain->page_cnt = page_cnt;
632316485Sdavidcs	p_chain->capacity = p_chain->usable_per_page * page_cnt;
633316485Sdavidcs	p_chain->size = p_chain->elem_per_page * page_cnt;
634316485Sdavidcs	p_chain->b_external_pbl = false;
635316485Sdavidcs	p_chain->pbl_sp.p_phys_table = 0;
636316485Sdavidcs	p_chain->pbl_sp.p_virt_table = OSAL_NULL;
637316485Sdavidcs	p_chain->pbl.pp_virt_addr_tbl = OSAL_NULL;
638316485Sdavidcs
639316485Sdavidcs	p_chain->dp_ctx = dp_ctx;
640316485Sdavidcs}
641316485Sdavidcs
642316485Sdavidcs/**
643316485Sdavidcs * @brief ecore_chain_init_mem -
644316485Sdavidcs *
645316485Sdavidcs * Initalizes a basic chain struct with its chain buffers
646316485Sdavidcs *
647316485Sdavidcs * @param p_chain
648316485Sdavidcs * @param p_virt_addr	virtual address of allocated buffer's beginning
649316485Sdavidcs * @param p_phys_addr	physical address of allocated buffer's beginning
650316485Sdavidcs *
651316485Sdavidcs */
652316485Sdavidcsstatic OSAL_INLINE void ecore_chain_init_mem(struct ecore_chain *p_chain,
653316485Sdavidcs					     void *p_virt_addr,
654316485Sdavidcs					     dma_addr_t p_phys_addr)
655316485Sdavidcs{
656316485Sdavidcs	p_chain->p_virt_addr = p_virt_addr;
657316485Sdavidcs	p_chain->p_phys_addr = p_phys_addr;
658316485Sdavidcs}
659316485Sdavidcs
660316485Sdavidcs/**
661316485Sdavidcs * @brief ecore_chain_init_pbl_mem -
662316485Sdavidcs *
663316485Sdavidcs * Initalizes a basic chain struct with its pbl buffers
664316485Sdavidcs *
665316485Sdavidcs * @param p_chain
666316485Sdavidcs * @param p_virt_pbl	pointer to a pre allocated side table which will hold
667316485Sdavidcs *                      virtual page addresses.
668316485Sdavidcs * @param p_phys_pbl	pointer to a pre-allocated side table which will hold
669316485Sdavidcs *                      physical page addresses.
670316485Sdavidcs * @param pp_virt_addr_tbl
671316485Sdavidcs *                      pointer to a pre-allocated side table which will hold
672316485Sdavidcs *                      the virtual addresses of the chain pages.
673316485Sdavidcs *
674316485Sdavidcs */
675316485Sdavidcsstatic OSAL_INLINE void ecore_chain_init_pbl_mem(struct ecore_chain *p_chain,
676316485Sdavidcs						 void *p_virt_pbl,
677316485Sdavidcs						 dma_addr_t p_phys_pbl,
678316485Sdavidcs						 void **pp_virt_addr_tbl)
679316485Sdavidcs{
680316485Sdavidcs	p_chain->pbl_sp.p_phys_table = p_phys_pbl;
681316485Sdavidcs	p_chain->pbl_sp.p_virt_table = p_virt_pbl;
682316485Sdavidcs	p_chain->pbl.pp_virt_addr_tbl = pp_virt_addr_tbl;
683316485Sdavidcs}
684316485Sdavidcs
685316485Sdavidcs/**
686316485Sdavidcs * @brief ecore_chain_init_next_ptr_elem -
687316485Sdavidcs *
688316485Sdavidcs * Initalizes a next pointer element
689316485Sdavidcs *
690316485Sdavidcs * @param p_chain
691316485Sdavidcs * @param p_virt_curr	virtual address of a chain page of which the next
692316485Sdavidcs *                      pointer element is initialized
693316485Sdavidcs * @param p_virt_next	virtual address of the next chain page
694316485Sdavidcs * @param p_phys_next	physical address of the next chain page
695316485Sdavidcs *
696316485Sdavidcs */
697316485Sdavidcsstatic OSAL_INLINE void
698316485Sdavidcsecore_chain_init_next_ptr_elem(struct ecore_chain *p_chain, void *p_virt_curr,
699316485Sdavidcs			       void *p_virt_next, dma_addr_t p_phys_next)
700316485Sdavidcs{
701316485Sdavidcs	struct ecore_chain_next *p_next;
702316485Sdavidcs	u32 size;
703316485Sdavidcs
704316485Sdavidcs	size = p_chain->elem_size * p_chain->usable_per_page;
705316485Sdavidcs	p_next = (struct ecore_chain_next *)((u8 *)p_virt_curr + size);
706316485Sdavidcs
707316485Sdavidcs	DMA_REGPAIR_LE(p_next->next_phys, p_phys_next);
708316485Sdavidcs
709316485Sdavidcs	p_next->next_virt = p_virt_next;
710316485Sdavidcs}
711316485Sdavidcs
712316485Sdavidcs/**
713316485Sdavidcs * @brief ecore_chain_get_last_elem -
714316485Sdavidcs *
715316485Sdavidcs * Returns a pointer to the last element of the chain
716316485Sdavidcs *
717316485Sdavidcs * @param p_chain
718316485Sdavidcs *
719316485Sdavidcs * @return void*
720316485Sdavidcs */
721316485Sdavidcsstatic OSAL_INLINE void *ecore_chain_get_last_elem(struct ecore_chain *p_chain)
722316485Sdavidcs{
723316485Sdavidcs	struct ecore_chain_next *p_next = OSAL_NULL;
724316485Sdavidcs	void *p_virt_addr = OSAL_NULL;
725316485Sdavidcs	u32 size, last_page_idx;
726316485Sdavidcs
727316485Sdavidcs	if (!p_chain->p_virt_addr)
728316485Sdavidcs		goto out;
729316485Sdavidcs
730316485Sdavidcs	switch (p_chain->mode) {
731316485Sdavidcs	case ECORE_CHAIN_MODE_NEXT_PTR:
732316485Sdavidcs		size = p_chain->elem_size * p_chain->usable_per_page;
733316485Sdavidcs		p_virt_addr = p_chain->p_virt_addr;
734316485Sdavidcs		p_next = (struct ecore_chain_next *)((u8 *)p_virt_addr + size);
735316485Sdavidcs		while (p_next->next_virt != p_chain->p_virt_addr) {
736316485Sdavidcs			p_virt_addr = p_next->next_virt;
737316485Sdavidcs			p_next = (struct ecore_chain_next *)((u8 *)p_virt_addr +
738316485Sdavidcs							     size);
739316485Sdavidcs		}
740316485Sdavidcs		break;
741316485Sdavidcs	case ECORE_CHAIN_MODE_SINGLE:
742316485Sdavidcs		p_virt_addr = p_chain->p_virt_addr;
743316485Sdavidcs		break;
744316485Sdavidcs	case ECORE_CHAIN_MODE_PBL:
745316485Sdavidcs		last_page_idx = p_chain->page_cnt - 1;
746316485Sdavidcs		p_virt_addr = p_chain->pbl.pp_virt_addr_tbl[last_page_idx];
747316485Sdavidcs		break;
748316485Sdavidcs	}
749316485Sdavidcs	/* p_virt_addr points at this stage to the last page of the chain */
750316485Sdavidcs	size = p_chain->elem_size * (p_chain->usable_per_page - 1);
751316485Sdavidcs	p_virt_addr = (u8 *)p_virt_addr + size;
752316485Sdavidcsout:
753316485Sdavidcs	return p_virt_addr;
754316485Sdavidcs}
755316485Sdavidcs
756316485Sdavidcs/**
757316485Sdavidcs * @brief ecore_chain_set_prod - sets the prod to the given value
758316485Sdavidcs *
759316485Sdavidcs * @param prod_idx
760316485Sdavidcs * @param p_prod_elem
761316485Sdavidcs */
762316485Sdavidcsstatic OSAL_INLINE void ecore_chain_set_prod(struct ecore_chain *p_chain,
763316485Sdavidcs					     u32 prod_idx, void *p_prod_elem)
764316485Sdavidcs{
765337517Sdavidcs	if (p_chain->mode == ECORE_CHAIN_MODE_PBL) {
766337517Sdavidcs		/* Use "prod_idx-1" since ecore_chain_produce() advances the
767337517Sdavidcs		 * page index before the producer index when getting to
768337517Sdavidcs		 * "next_page_mask".
769337517Sdavidcs		 */
770337517Sdavidcs		u32 elem_idx =
771337517Sdavidcs			(prod_idx - 1 + p_chain->capacity) % p_chain->capacity;
772337517Sdavidcs		u32 page_idx = elem_idx / p_chain->elem_per_page;
773337517Sdavidcs
774337517Sdavidcs		if (is_chain_u16(p_chain))
775337517Sdavidcs			p_chain->pbl.c.pbl_u16.prod_page_idx = (u16)page_idx;
776337517Sdavidcs		else
777337517Sdavidcs			p_chain->pbl.c.pbl_u32.prod_page_idx = page_idx;
778337517Sdavidcs	}
779337517Sdavidcs
780316485Sdavidcs	if (is_chain_u16(p_chain))
781316485Sdavidcs		p_chain->u.chain16.prod_idx = (u16)prod_idx;
782316485Sdavidcs	else
783316485Sdavidcs		p_chain->u.chain32.prod_idx = prod_idx;
784316485Sdavidcs	p_chain->p_prod_elem = p_prod_elem;
785316485Sdavidcs}
786316485Sdavidcs
787316485Sdavidcs/**
788337517Sdavidcs * @brief ecore_chain_set_cons - sets the cons to the given value
789337517Sdavidcs *
790337517Sdavidcs * @param cons_idx
791337517Sdavidcs * @param p_cons_elem
792337517Sdavidcs */
793337517Sdavidcsstatic OSAL_INLINE void ecore_chain_set_cons(struct ecore_chain *p_chain,
794337517Sdavidcs					     u32 cons_idx, void *p_cons_elem)
795337517Sdavidcs{
796337517Sdavidcs	if (p_chain->mode == ECORE_CHAIN_MODE_PBL) {
797337517Sdavidcs		/* Use "cons_idx-1" since ecore_chain_consume() advances the
798337517Sdavidcs		 * page index before the consumer index when getting to
799337517Sdavidcs		 * "next_page_mask".
800337517Sdavidcs		 */
801337517Sdavidcs		u32 elem_idx =
802337517Sdavidcs			(cons_idx - 1 + p_chain->capacity) % p_chain->capacity;
803337517Sdavidcs		u32 page_idx = elem_idx / p_chain->elem_per_page;
804337517Sdavidcs
805337517Sdavidcs		if (is_chain_u16(p_chain))
806337517Sdavidcs			p_chain->pbl.c.pbl_u16.cons_page_idx = (u16)page_idx;
807337517Sdavidcs		else
808337517Sdavidcs			p_chain->pbl.c.pbl_u32.cons_page_idx = page_idx;
809337517Sdavidcs	}
810337517Sdavidcs
811337517Sdavidcs	if (is_chain_u16(p_chain))
812337517Sdavidcs		p_chain->u.chain16.cons_idx = (u16)cons_idx;
813337517Sdavidcs	else
814337517Sdavidcs		p_chain->u.chain32.cons_idx = cons_idx;
815337517Sdavidcs
816337517Sdavidcs	p_chain->p_cons_elem = p_cons_elem;
817337517Sdavidcs}
818337517Sdavidcs
819337517Sdavidcs/**
820316485Sdavidcs * @brief ecore_chain_pbl_zero_mem - set chain memory to 0
821316485Sdavidcs *
822316485Sdavidcs * @param p_chain
823316485Sdavidcs */
824316485Sdavidcsstatic OSAL_INLINE void ecore_chain_pbl_zero_mem(struct ecore_chain *p_chain)
825316485Sdavidcs{
826316485Sdavidcs	u32 i, page_cnt;
827316485Sdavidcs
828316485Sdavidcs	if (p_chain->mode != ECORE_CHAIN_MODE_PBL)
829316485Sdavidcs		return;
830316485Sdavidcs
831316485Sdavidcs	page_cnt = ecore_chain_get_page_cnt(p_chain);
832316485Sdavidcs
833316485Sdavidcs	for (i = 0; i < page_cnt; i++)
834316485Sdavidcs		OSAL_MEM_ZERO(p_chain->pbl.pp_virt_addr_tbl[i],
835316485Sdavidcs			      ECORE_CHAIN_PAGE_SIZE);
836316485Sdavidcs}
837316485Sdavidcs
838316485Sdavidcsint ecore_chain_print(struct ecore_chain *p_chain, char *buffer,
839316485Sdavidcs		      u32 buffer_size, u32 *element_indx, u32 stop_indx,
840316485Sdavidcs		      bool print_metadata,
841316485Sdavidcs		      int (*func_ptr_print_element)(struct ecore_chain *p_chain,
842316485Sdavidcs						    void *p_element,
843316485Sdavidcs						    char *buffer),
844316485Sdavidcs		      int (*func_ptr_print_metadata)(struct ecore_chain *p_chain,
845316485Sdavidcs						     char *buffer));
846316485Sdavidcs
847316485Sdavidcs#endif /* __ECORE_CHAIN_H__ */
848