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