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