1fe56b9e6SYuval Mintz /* QLogic qed NIC Driver 2*e8f1cb50SMintz, Yuval * Copyright (c) 2015-2017 QLogic Corporation 3fe56b9e6SYuval Mintz * 4*e8f1cb50SMintz, Yuval * This software is available to you under a choice of one of two 5*e8f1cb50SMintz, Yuval * licenses. You may choose to be licensed under the terms of the GNU 6*e8f1cb50SMintz, Yuval * General Public License (GPL) Version 2, available from the file 7*e8f1cb50SMintz, Yuval * COPYING in the main directory of this source tree, or the 8*e8f1cb50SMintz, Yuval * OpenIB.org BSD license below: 9*e8f1cb50SMintz, Yuval * 10*e8f1cb50SMintz, Yuval * Redistribution and use in source and binary forms, with or 11*e8f1cb50SMintz, Yuval * without modification, are permitted provided that the following 12*e8f1cb50SMintz, Yuval * conditions are met: 13*e8f1cb50SMintz, Yuval * 14*e8f1cb50SMintz, Yuval * - Redistributions of source code must retain the above 15*e8f1cb50SMintz, Yuval * copyright notice, this list of conditions and the following 16*e8f1cb50SMintz, Yuval * disclaimer. 17*e8f1cb50SMintz, Yuval * 18*e8f1cb50SMintz, Yuval * - Redistributions in binary form must reproduce the above 19*e8f1cb50SMintz, Yuval * copyright notice, this list of conditions and the following 20*e8f1cb50SMintz, Yuval * disclaimer in the documentation and /or other materials 21*e8f1cb50SMintz, Yuval * provided with the distribution. 22*e8f1cb50SMintz, Yuval * 23*e8f1cb50SMintz, Yuval * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24*e8f1cb50SMintz, Yuval * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25*e8f1cb50SMintz, Yuval * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26*e8f1cb50SMintz, Yuval * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27*e8f1cb50SMintz, Yuval * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28*e8f1cb50SMintz, Yuval * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29*e8f1cb50SMintz, Yuval * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30*e8f1cb50SMintz, Yuval * SOFTWARE. 31fe56b9e6SYuval Mintz */ 32fe56b9e6SYuval Mintz 33fe56b9e6SYuval Mintz #ifndef _QED_CHAIN_H 34fe56b9e6SYuval Mintz #define _QED_CHAIN_H 35fe56b9e6SYuval Mintz 36fe56b9e6SYuval Mintz #include <linux/types.h> 37fe56b9e6SYuval Mintz #include <asm/byteorder.h> 38fe56b9e6SYuval Mintz #include <linux/kernel.h> 39fe56b9e6SYuval Mintz #include <linux/list.h> 40fe56b9e6SYuval Mintz #include <linux/slab.h> 41fe56b9e6SYuval Mintz #include <linux/qed/common_hsi.h> 42fe56b9e6SYuval Mintz 43fe56b9e6SYuval Mintz enum qed_chain_mode { 44fe56b9e6SYuval Mintz /* Each Page contains a next pointer at its end */ 45fe56b9e6SYuval Mintz QED_CHAIN_MODE_NEXT_PTR, 46fe56b9e6SYuval Mintz 47fe56b9e6SYuval Mintz /* Chain is a single page (next ptr) is unrequired */ 48fe56b9e6SYuval Mintz QED_CHAIN_MODE_SINGLE, 49fe56b9e6SYuval Mintz 50fe56b9e6SYuval Mintz /* Page pointers are located in a side list */ 51fe56b9e6SYuval Mintz QED_CHAIN_MODE_PBL, 52fe56b9e6SYuval Mintz }; 53fe56b9e6SYuval Mintz 54fe56b9e6SYuval Mintz enum qed_chain_use_mode { 55fe56b9e6SYuval Mintz QED_CHAIN_USE_TO_PRODUCE, /* Chain starts empty */ 56fe56b9e6SYuval Mintz QED_CHAIN_USE_TO_CONSUME, /* Chain starts full */ 57fe56b9e6SYuval Mintz QED_CHAIN_USE_TO_CONSUME_PRODUCE, /* Chain starts empty */ 58fe56b9e6SYuval Mintz }; 59fe56b9e6SYuval Mintz 60a91eb52aSYuval Mintz enum qed_chain_cnt_type { 61a91eb52aSYuval Mintz /* The chain's size/prod/cons are kept in 16-bit variables */ 62a91eb52aSYuval Mintz QED_CHAIN_CNT_TYPE_U16, 63a91eb52aSYuval Mintz 64a91eb52aSYuval Mintz /* The chain's size/prod/cons are kept in 32-bit variables */ 65a91eb52aSYuval Mintz QED_CHAIN_CNT_TYPE_U32, 66a91eb52aSYuval Mintz }; 67a91eb52aSYuval Mintz 68fe56b9e6SYuval Mintz struct qed_chain_next { 69fe56b9e6SYuval Mintz struct regpair next_phys; 70fe56b9e6SYuval Mintz void *next_virt; 71fe56b9e6SYuval Mintz }; 72fe56b9e6SYuval Mintz 73a91eb52aSYuval Mintz struct qed_chain_pbl_u16 { 74fe56b9e6SYuval Mintz u16 prod_page_idx; 75fe56b9e6SYuval Mintz u16 cons_page_idx; 76fe56b9e6SYuval Mintz }; 77fe56b9e6SYuval Mintz 78a91eb52aSYuval Mintz struct qed_chain_pbl_u32 { 79a91eb52aSYuval Mintz u32 prod_page_idx; 80a91eb52aSYuval Mintz u32 cons_page_idx; 81a91eb52aSYuval Mintz }; 82a91eb52aSYuval Mintz 83a91eb52aSYuval Mintz struct qed_chain_u16 { 84a91eb52aSYuval Mintz /* Cyclic index of next element to produce/consme */ 85a91eb52aSYuval Mintz u16 prod_idx; 86a91eb52aSYuval Mintz u16 cons_idx; 87a91eb52aSYuval Mintz }; 88a91eb52aSYuval Mintz 89a91eb52aSYuval Mintz struct qed_chain_u32 { 90a91eb52aSYuval Mintz /* Cyclic index of next element to produce/consme */ 91a91eb52aSYuval Mintz u32 prod_idx; 92a91eb52aSYuval Mintz u32 cons_idx; 93a91eb52aSYuval Mintz }; 94a91eb52aSYuval Mintz 95fe56b9e6SYuval Mintz struct qed_chain { 966d937acfSMintz, Yuval /* fastpath portion of the chain - required for commands such 976d937acfSMintz, Yuval * as produce / consume. 986d937acfSMintz, Yuval */ 996d937acfSMintz, Yuval /* Point to next element to produce/consume */ 100fe56b9e6SYuval Mintz void *p_prod_elem; 101fe56b9e6SYuval Mintz void *p_cons_elem; 102a91eb52aSYuval Mintz 1036d937acfSMintz, Yuval /* Fastpath portions of the PBL [if exists] */ 1046d937acfSMintz, Yuval struct { 1056d937acfSMintz, Yuval /* Table for keeping the virtual addresses of the chain pages, 1066d937acfSMintz, Yuval * respectively to the physical addresses in the pbl table. 1076d937acfSMintz, Yuval */ 1086d937acfSMintz, Yuval void **pp_virt_addr_tbl; 1096d937acfSMintz, Yuval 1106d937acfSMintz, Yuval union { 1116d937acfSMintz, Yuval struct qed_chain_pbl_u16 u16; 1126d937acfSMintz, Yuval struct qed_chain_pbl_u32 u32; 1136d937acfSMintz, Yuval } c; 1146d937acfSMintz, Yuval } pbl; 115a91eb52aSYuval Mintz 116a91eb52aSYuval Mintz union { 117a91eb52aSYuval Mintz struct qed_chain_u16 chain16; 118a91eb52aSYuval Mintz struct qed_chain_u32 chain32; 119a91eb52aSYuval Mintz } u; 120a91eb52aSYuval Mintz 1216d937acfSMintz, Yuval /* Capacity counts only usable elements */ 1226d937acfSMintz, Yuval u32 capacity; 123a91eb52aSYuval Mintz u32 page_cnt; 124a91eb52aSYuval Mintz 1256d937acfSMintz, Yuval enum qed_chain_mode mode; 126a91eb52aSYuval Mintz 127a91eb52aSYuval Mintz /* Elements information for fast calculations */ 128fe56b9e6SYuval Mintz u16 elem_per_page; 129fe56b9e6SYuval Mintz u16 elem_per_page_mask; 130fe56b9e6SYuval Mintz u16 elem_size; 131fe56b9e6SYuval Mintz u16 next_page_mask; 1326d937acfSMintz, Yuval u16 usable_per_page; 1336d937acfSMintz, Yuval u8 elem_unusable; 1346d937acfSMintz, Yuval 1356d937acfSMintz, Yuval u8 cnt_type; 1366d937acfSMintz, Yuval 1376d937acfSMintz, Yuval /* Slowpath of the chain - required for initialization and destruction, 1386d937acfSMintz, Yuval * but isn't involved in regular functionality. 1396d937acfSMintz, Yuval */ 1406d937acfSMintz, Yuval 1416d937acfSMintz, Yuval /* Base address of a pre-allocated buffer for pbl */ 1426d937acfSMintz, Yuval struct { 1436d937acfSMintz, Yuval dma_addr_t p_phys_table; 1446d937acfSMintz, Yuval void *p_virt_table; 1456d937acfSMintz, Yuval } pbl_sp; 1466d937acfSMintz, Yuval 1476d937acfSMintz, Yuval /* Address of first page of the chain - the address is required 1486d937acfSMintz, Yuval * for fastpath operation [consume/produce] but only for the the SINGLE 1496d937acfSMintz, Yuval * flavour which isn't considered fastpath [== SPQ]. 1506d937acfSMintz, Yuval */ 1516d937acfSMintz, Yuval void *p_virt_addr; 1526d937acfSMintz, Yuval dma_addr_t p_phys_addr; 1536d937acfSMintz, Yuval 1546d937acfSMintz, Yuval /* Total number of elements [for entire chain] */ 1556d937acfSMintz, Yuval u32 size; 1566d937acfSMintz, Yuval 1576d937acfSMintz, Yuval u8 intended_use; 158fe56b9e6SYuval Mintz }; 159fe56b9e6SYuval Mintz 160fe56b9e6SYuval Mintz #define QED_CHAIN_PBL_ENTRY_SIZE (8) 161fe56b9e6SYuval Mintz #define QED_CHAIN_PAGE_SIZE (0x1000) 162fe56b9e6SYuval Mintz #define ELEMS_PER_PAGE(elem_size) (QED_CHAIN_PAGE_SIZE / (elem_size)) 163fe56b9e6SYuval Mintz 164fe56b9e6SYuval Mintz #define UNUSABLE_ELEMS_PER_PAGE(elem_size, mode) \ 1656d937acfSMintz, Yuval (((mode) == QED_CHAIN_MODE_NEXT_PTR) ? \ 1666d937acfSMintz, Yuval (u8)(1 + ((sizeof(struct qed_chain_next) - 1) / \ 167fe56b9e6SYuval Mintz (elem_size))) : 0) 168fe56b9e6SYuval Mintz 169fe56b9e6SYuval Mintz #define USABLE_ELEMS_PER_PAGE(elem_size, mode) \ 170fe56b9e6SYuval Mintz ((u32)(ELEMS_PER_PAGE(elem_size) - \ 171fe56b9e6SYuval Mintz UNUSABLE_ELEMS_PER_PAGE(elem_size, mode))) 172fe56b9e6SYuval Mintz 173fe56b9e6SYuval Mintz #define QED_CHAIN_PAGE_CNT(elem_cnt, elem_size, mode) \ 174fe56b9e6SYuval Mintz DIV_ROUND_UP(elem_cnt, USABLE_ELEMS_PER_PAGE(elem_size, mode)) 175fe56b9e6SYuval Mintz 176a91eb52aSYuval Mintz #define is_chain_u16(p) ((p)->cnt_type == QED_CHAIN_CNT_TYPE_U16) 177a91eb52aSYuval Mintz #define is_chain_u32(p) ((p)->cnt_type == QED_CHAIN_CNT_TYPE_U32) 178a91eb52aSYuval Mintz 179fe56b9e6SYuval Mintz /* Accessors */ 180fe56b9e6SYuval Mintz static inline u16 qed_chain_get_prod_idx(struct qed_chain *p_chain) 181fe56b9e6SYuval Mintz { 182a91eb52aSYuval Mintz return p_chain->u.chain16.prod_idx; 183fe56b9e6SYuval Mintz } 184fe56b9e6SYuval Mintz 185fe56b9e6SYuval Mintz static inline u16 qed_chain_get_cons_idx(struct qed_chain *p_chain) 186fe56b9e6SYuval Mintz { 187a91eb52aSYuval Mintz return p_chain->u.chain16.cons_idx; 188a91eb52aSYuval Mintz } 189a91eb52aSYuval Mintz 190a91eb52aSYuval Mintz static inline u32 qed_chain_get_cons_idx_u32(struct qed_chain *p_chain) 191a91eb52aSYuval Mintz { 192a91eb52aSYuval Mintz return p_chain->u.chain32.cons_idx; 193fe56b9e6SYuval Mintz } 194fe56b9e6SYuval Mintz 195fe56b9e6SYuval Mintz static inline u16 qed_chain_get_elem_left(struct qed_chain *p_chain) 196fe56b9e6SYuval Mintz { 197fe56b9e6SYuval Mintz u16 used; 198fe56b9e6SYuval Mintz 199a91eb52aSYuval Mintz used = (u16) (((u32)0x10000 + 200a91eb52aSYuval Mintz (u32)p_chain->u.chain16.prod_idx) - 201a91eb52aSYuval Mintz (u32)p_chain->u.chain16.cons_idx); 202fe56b9e6SYuval Mintz if (p_chain->mode == QED_CHAIN_MODE_NEXT_PTR) 203a91eb52aSYuval Mintz used -= p_chain->u.chain16.prod_idx / p_chain->elem_per_page - 204a91eb52aSYuval Mintz p_chain->u.chain16.cons_idx / p_chain->elem_per_page; 205a91eb52aSYuval Mintz 206a91eb52aSYuval Mintz return (u16)(p_chain->capacity - used); 207a91eb52aSYuval Mintz } 208a91eb52aSYuval Mintz 209a91eb52aSYuval Mintz static inline u32 qed_chain_get_elem_left_u32(struct qed_chain *p_chain) 210a91eb52aSYuval Mintz { 211a91eb52aSYuval Mintz u32 used; 212a91eb52aSYuval Mintz 213a91eb52aSYuval Mintz used = (u32) (((u64)0x100000000ULL + 214a91eb52aSYuval Mintz (u64)p_chain->u.chain32.prod_idx) - 215a91eb52aSYuval Mintz (u64)p_chain->u.chain32.cons_idx); 216a91eb52aSYuval Mintz if (p_chain->mode == QED_CHAIN_MODE_NEXT_PTR) 217a91eb52aSYuval Mintz used -= p_chain->u.chain32.prod_idx / p_chain->elem_per_page - 218a91eb52aSYuval Mintz p_chain->u.chain32.cons_idx / p_chain->elem_per_page; 219fe56b9e6SYuval Mintz 220fe56b9e6SYuval Mintz return p_chain->capacity - used; 221fe56b9e6SYuval Mintz } 222fe56b9e6SYuval Mintz 223a91eb52aSYuval Mintz static inline u16 qed_chain_get_usable_per_page(struct qed_chain *p_chain) 224fe56b9e6SYuval Mintz { 225fe56b9e6SYuval Mintz return p_chain->usable_per_page; 226fe56b9e6SYuval Mintz } 227fe56b9e6SYuval Mintz 2286d937acfSMintz, Yuval static inline u8 qed_chain_get_unusable_per_page(struct qed_chain *p_chain) 229fe56b9e6SYuval Mintz { 230fe56b9e6SYuval Mintz return p_chain->elem_unusable; 231fe56b9e6SYuval Mintz } 232fe56b9e6SYuval Mintz 233a91eb52aSYuval Mintz static inline u32 qed_chain_get_page_cnt(struct qed_chain *p_chain) 234fe56b9e6SYuval Mintz { 235a91eb52aSYuval Mintz return p_chain->page_cnt; 236fe56b9e6SYuval Mintz } 237fe56b9e6SYuval Mintz 238a91eb52aSYuval Mintz static inline dma_addr_t qed_chain_get_pbl_phys(struct qed_chain *p_chain) 239fe56b9e6SYuval Mintz { 2406d937acfSMintz, Yuval return p_chain->pbl_sp.p_phys_table; 241fe56b9e6SYuval Mintz } 242fe56b9e6SYuval Mintz 243fe56b9e6SYuval Mintz /** 244fe56b9e6SYuval Mintz * @brief qed_chain_advance_page - 245fe56b9e6SYuval Mintz * 246fe56b9e6SYuval Mintz * Advance the next element accros pages for a linked chain 247fe56b9e6SYuval Mintz * 248fe56b9e6SYuval Mintz * @param p_chain 249fe56b9e6SYuval Mintz * @param p_next_elem 250fe56b9e6SYuval Mintz * @param idx_to_inc 251fe56b9e6SYuval Mintz * @param page_to_inc 252fe56b9e6SYuval Mintz */ 253fe56b9e6SYuval Mintz static inline void 254fe56b9e6SYuval Mintz qed_chain_advance_page(struct qed_chain *p_chain, 255a91eb52aSYuval Mintz void **p_next_elem, void *idx_to_inc, void *page_to_inc) 256fe56b9e6SYuval Mintz { 257a91eb52aSYuval Mintz struct qed_chain_next *p_next = NULL; 258a91eb52aSYuval Mintz u32 page_index = 0; 2596d937acfSMintz, Yuval 260fe56b9e6SYuval Mintz switch (p_chain->mode) { 261fe56b9e6SYuval Mintz case QED_CHAIN_MODE_NEXT_PTR: 262a91eb52aSYuval Mintz p_next = *p_next_elem; 263fe56b9e6SYuval Mintz *p_next_elem = p_next->next_virt; 264a91eb52aSYuval Mintz if (is_chain_u16(p_chain)) 265a91eb52aSYuval Mintz *(u16 *)idx_to_inc += p_chain->elem_unusable; 266a91eb52aSYuval Mintz else 267a91eb52aSYuval Mintz *(u32 *)idx_to_inc += p_chain->elem_unusable; 268fe56b9e6SYuval Mintz break; 269fe56b9e6SYuval Mintz case QED_CHAIN_MODE_SINGLE: 270fe56b9e6SYuval Mintz *p_next_elem = p_chain->p_virt_addr; 271fe56b9e6SYuval Mintz break; 272fe56b9e6SYuval Mintz 273fe56b9e6SYuval Mintz case QED_CHAIN_MODE_PBL: 274a91eb52aSYuval Mintz if (is_chain_u16(p_chain)) { 275a91eb52aSYuval Mintz if (++(*(u16 *)page_to_inc) == p_chain->page_cnt) 276a91eb52aSYuval Mintz *(u16 *)page_to_inc = 0; 277a91eb52aSYuval Mintz page_index = *(u16 *)page_to_inc; 278a91eb52aSYuval Mintz } else { 279a91eb52aSYuval Mintz if (++(*(u32 *)page_to_inc) == p_chain->page_cnt) 280a91eb52aSYuval Mintz *(u32 *)page_to_inc = 0; 281a91eb52aSYuval Mintz page_index = *(u32 *)page_to_inc; 282fe56b9e6SYuval Mintz } 283a91eb52aSYuval Mintz *p_next_elem = p_chain->pbl.pp_virt_addr_tbl[page_index]; 284fe56b9e6SYuval Mintz } 285fe56b9e6SYuval Mintz } 286fe56b9e6SYuval Mintz 287fe56b9e6SYuval Mintz #define is_unusable_idx(p, idx) \ 288a91eb52aSYuval Mintz (((p)->u.chain16.idx & (p)->elem_per_page_mask) == (p)->usable_per_page) 289fe56b9e6SYuval Mintz 290a91eb52aSYuval Mintz #define is_unusable_idx_u32(p, idx) \ 291a91eb52aSYuval Mintz (((p)->u.chain32.idx & (p)->elem_per_page_mask) == (p)->usable_per_page) 292fe56b9e6SYuval Mintz #define is_unusable_next_idx(p, idx) \ 293a91eb52aSYuval Mintz ((((p)->u.chain16.idx + 1) & (p)->elem_per_page_mask) == \ 294a91eb52aSYuval Mintz (p)->usable_per_page) 295fe56b9e6SYuval Mintz 296a91eb52aSYuval Mintz #define is_unusable_next_idx_u32(p, idx) \ 297a91eb52aSYuval Mintz ((((p)->u.chain32.idx + 1) & (p)->elem_per_page_mask) == \ 298a91eb52aSYuval Mintz (p)->usable_per_page) 299a91eb52aSYuval Mintz 300a91eb52aSYuval Mintz #define test_and_skip(p, idx) \ 301fe56b9e6SYuval Mintz do { \ 302a91eb52aSYuval Mintz if (is_chain_u16(p)) { \ 303a91eb52aSYuval Mintz if (is_unusable_idx(p, idx)) \ 304a91eb52aSYuval Mintz (p)->u.chain16.idx += (p)->elem_unusable; \ 305a91eb52aSYuval Mintz } else { \ 306a91eb52aSYuval Mintz if (is_unusable_idx_u32(p, idx)) \ 307a91eb52aSYuval Mintz (p)->u.chain32.idx += (p)->elem_unusable; \ 308fe56b9e6SYuval Mintz } \ 309fe56b9e6SYuval Mintz } while (0) 310fe56b9e6SYuval Mintz 311fe56b9e6SYuval Mintz /** 312fe56b9e6SYuval Mintz * @brief qed_chain_return_produced - 313fe56b9e6SYuval Mintz * 314fe56b9e6SYuval Mintz * A chain in which the driver "Produces" elements should use this API 315fe56b9e6SYuval Mintz * to indicate previous produced elements are now consumed. 316fe56b9e6SYuval Mintz * 317fe56b9e6SYuval Mintz * @param p_chain 318fe56b9e6SYuval Mintz */ 319fe56b9e6SYuval Mintz static inline void qed_chain_return_produced(struct qed_chain *p_chain) 320fe56b9e6SYuval Mintz { 321a91eb52aSYuval Mintz if (is_chain_u16(p_chain)) 322a91eb52aSYuval Mintz p_chain->u.chain16.cons_idx++; 323a91eb52aSYuval Mintz else 324a91eb52aSYuval Mintz p_chain->u.chain32.cons_idx++; 325a91eb52aSYuval Mintz test_and_skip(p_chain, cons_idx); 326fe56b9e6SYuval Mintz } 327fe56b9e6SYuval Mintz 328fe56b9e6SYuval Mintz /** 329fe56b9e6SYuval Mintz * @brief qed_chain_produce - 330fe56b9e6SYuval Mintz * 331fe56b9e6SYuval Mintz * A chain in which the driver "Produces" elements should use this to get 332fe56b9e6SYuval Mintz * a pointer to the next element which can be "Produced". It's driver 333fe56b9e6SYuval Mintz * responsibility to validate that the chain has room for new element. 334fe56b9e6SYuval Mintz * 335fe56b9e6SYuval Mintz * @param p_chain 336fe56b9e6SYuval Mintz * 337fe56b9e6SYuval Mintz * @return void*, a pointer to next element 338fe56b9e6SYuval Mintz */ 339fe56b9e6SYuval Mintz static inline void *qed_chain_produce(struct qed_chain *p_chain) 340fe56b9e6SYuval Mintz { 341a91eb52aSYuval Mintz void *p_ret = NULL, *p_prod_idx, *p_prod_page_idx; 342fe56b9e6SYuval Mintz 343a91eb52aSYuval Mintz if (is_chain_u16(p_chain)) { 344a91eb52aSYuval Mintz if ((p_chain->u.chain16.prod_idx & 345a91eb52aSYuval Mintz p_chain->elem_per_page_mask) == p_chain->next_page_mask) { 346a91eb52aSYuval Mintz p_prod_idx = &p_chain->u.chain16.prod_idx; 3476d937acfSMintz, Yuval p_prod_page_idx = &p_chain->pbl.c.u16.prod_page_idx; 348fe56b9e6SYuval Mintz qed_chain_advance_page(p_chain, &p_chain->p_prod_elem, 349a91eb52aSYuval Mintz p_prod_idx, p_prod_page_idx); 350a91eb52aSYuval Mintz } 351a91eb52aSYuval Mintz p_chain->u.chain16.prod_idx++; 352a91eb52aSYuval Mintz } else { 353a91eb52aSYuval Mintz if ((p_chain->u.chain32.prod_idx & 354a91eb52aSYuval Mintz p_chain->elem_per_page_mask) == p_chain->next_page_mask) { 355a91eb52aSYuval Mintz p_prod_idx = &p_chain->u.chain32.prod_idx; 3566d937acfSMintz, Yuval p_prod_page_idx = &p_chain->pbl.c.u32.prod_page_idx; 357a91eb52aSYuval Mintz qed_chain_advance_page(p_chain, &p_chain->p_prod_elem, 358a91eb52aSYuval Mintz p_prod_idx, p_prod_page_idx); 359a91eb52aSYuval Mintz } 360a91eb52aSYuval Mintz p_chain->u.chain32.prod_idx++; 361fe56b9e6SYuval Mintz } 362fe56b9e6SYuval Mintz 363a91eb52aSYuval Mintz p_ret = p_chain->p_prod_elem; 364fe56b9e6SYuval Mintz p_chain->p_prod_elem = (void *)(((u8 *)p_chain->p_prod_elem) + 365fe56b9e6SYuval Mintz p_chain->elem_size); 366fe56b9e6SYuval Mintz 367a91eb52aSYuval Mintz return p_ret; 368fe56b9e6SYuval Mintz } 369fe56b9e6SYuval Mintz 370fe56b9e6SYuval Mintz /** 371fe56b9e6SYuval Mintz * @brief qed_chain_get_capacity - 372fe56b9e6SYuval Mintz * 373fe56b9e6SYuval Mintz * Get the maximum number of BDs in chain 374fe56b9e6SYuval Mintz * 375fe56b9e6SYuval Mintz * @param p_chain 376fe56b9e6SYuval Mintz * @param num 377fe56b9e6SYuval Mintz * 378a91eb52aSYuval Mintz * @return number of unusable BDs 379fe56b9e6SYuval Mintz */ 380a91eb52aSYuval Mintz static inline u32 qed_chain_get_capacity(struct qed_chain *p_chain) 381fe56b9e6SYuval Mintz { 382fe56b9e6SYuval Mintz return p_chain->capacity; 383fe56b9e6SYuval Mintz } 384fe56b9e6SYuval Mintz 385fe56b9e6SYuval Mintz /** 386fe56b9e6SYuval Mintz * @brief qed_chain_recycle_consumed - 387fe56b9e6SYuval Mintz * 388fe56b9e6SYuval Mintz * Returns an element which was previously consumed; 389fe56b9e6SYuval Mintz * Increments producers so they could be written to FW. 390fe56b9e6SYuval Mintz * 391fe56b9e6SYuval Mintz * @param p_chain 392fe56b9e6SYuval Mintz */ 393a91eb52aSYuval Mintz static inline void qed_chain_recycle_consumed(struct qed_chain *p_chain) 394fe56b9e6SYuval Mintz { 395a91eb52aSYuval Mintz test_and_skip(p_chain, prod_idx); 396a91eb52aSYuval Mintz if (is_chain_u16(p_chain)) 397a91eb52aSYuval Mintz p_chain->u.chain16.prod_idx++; 398a91eb52aSYuval Mintz else 399a91eb52aSYuval Mintz p_chain->u.chain32.prod_idx++; 400fe56b9e6SYuval Mintz } 401fe56b9e6SYuval Mintz 402fe56b9e6SYuval Mintz /** 403fe56b9e6SYuval Mintz * @brief qed_chain_consume - 404fe56b9e6SYuval Mintz * 405fe56b9e6SYuval Mintz * A Chain in which the driver utilizes data written by a different source 406fe56b9e6SYuval Mintz * (i.e., FW) should use this to access passed buffers. 407fe56b9e6SYuval Mintz * 408fe56b9e6SYuval Mintz * @param p_chain 409fe56b9e6SYuval Mintz * 410fe56b9e6SYuval Mintz * @return void*, a pointer to the next buffer written 411fe56b9e6SYuval Mintz */ 412fe56b9e6SYuval Mintz static inline void *qed_chain_consume(struct qed_chain *p_chain) 413fe56b9e6SYuval Mintz { 414a91eb52aSYuval Mintz void *p_ret = NULL, *p_cons_idx, *p_cons_page_idx; 415fe56b9e6SYuval Mintz 416a91eb52aSYuval Mintz if (is_chain_u16(p_chain)) { 417a91eb52aSYuval Mintz if ((p_chain->u.chain16.cons_idx & 418a91eb52aSYuval Mintz p_chain->elem_per_page_mask) == p_chain->next_page_mask) { 419a91eb52aSYuval Mintz p_cons_idx = &p_chain->u.chain16.cons_idx; 4206d937acfSMintz, Yuval p_cons_page_idx = &p_chain->pbl.c.u16.cons_page_idx; 421fe56b9e6SYuval Mintz qed_chain_advance_page(p_chain, &p_chain->p_cons_elem, 422a91eb52aSYuval Mintz p_cons_idx, p_cons_page_idx); 423a91eb52aSYuval Mintz } 424a91eb52aSYuval Mintz p_chain->u.chain16.cons_idx++; 425a91eb52aSYuval Mintz } else { 426a91eb52aSYuval Mintz if ((p_chain->u.chain32.cons_idx & 427a91eb52aSYuval Mintz p_chain->elem_per_page_mask) == p_chain->next_page_mask) { 428a91eb52aSYuval Mintz p_cons_idx = &p_chain->u.chain32.cons_idx; 4296d937acfSMintz, Yuval p_cons_page_idx = &p_chain->pbl.c.u32.cons_page_idx; 430a91eb52aSYuval Mintz qed_chain_advance_page(p_chain, &p_chain->p_cons_elem, 431a91eb52aSYuval Mintz p_cons_idx, p_cons_page_idx); 432a91eb52aSYuval Mintz } 433a91eb52aSYuval Mintz p_chain->u.chain32.cons_idx++; 434fe56b9e6SYuval Mintz } 435fe56b9e6SYuval Mintz 436a91eb52aSYuval Mintz p_ret = p_chain->p_cons_elem; 437fe56b9e6SYuval Mintz p_chain->p_cons_elem = (void *)(((u8 *)p_chain->p_cons_elem) + 438fe56b9e6SYuval Mintz p_chain->elem_size); 439fe56b9e6SYuval Mintz 440a91eb52aSYuval Mintz return p_ret; 441fe56b9e6SYuval Mintz } 442fe56b9e6SYuval Mintz 443fe56b9e6SYuval Mintz /** 444fe56b9e6SYuval Mintz * @brief qed_chain_reset - Resets the chain to its start state 445fe56b9e6SYuval Mintz * 446fe56b9e6SYuval Mintz * @param p_chain pointer to a previously allocted chain 447fe56b9e6SYuval Mintz */ 448fe56b9e6SYuval Mintz static inline void qed_chain_reset(struct qed_chain *p_chain) 449fe56b9e6SYuval Mintz { 450a91eb52aSYuval Mintz u32 i; 451fe56b9e6SYuval Mintz 452a91eb52aSYuval Mintz if (is_chain_u16(p_chain)) { 453a91eb52aSYuval Mintz p_chain->u.chain16.prod_idx = 0; 454a91eb52aSYuval Mintz p_chain->u.chain16.cons_idx = 0; 455a91eb52aSYuval Mintz } else { 456a91eb52aSYuval Mintz p_chain->u.chain32.prod_idx = 0; 457a91eb52aSYuval Mintz p_chain->u.chain32.cons_idx = 0; 458a91eb52aSYuval Mintz } 459fe56b9e6SYuval Mintz p_chain->p_cons_elem = p_chain->p_virt_addr; 460fe56b9e6SYuval Mintz p_chain->p_prod_elem = p_chain->p_virt_addr; 461fe56b9e6SYuval Mintz 462fe56b9e6SYuval Mintz if (p_chain->mode == QED_CHAIN_MODE_PBL) { 463a91eb52aSYuval Mintz /* Use (page_cnt - 1) as a reset value for the prod/cons page's 464a91eb52aSYuval Mintz * indices, to avoid unnecessary page advancing on the first 465a91eb52aSYuval Mintz * call to qed_chain_produce/consume. Instead, the indices 466a91eb52aSYuval Mintz * will be advanced to page_cnt and then will be wrapped to 0. 467a91eb52aSYuval Mintz */ 468a91eb52aSYuval Mintz u32 reset_val = p_chain->page_cnt - 1; 469a91eb52aSYuval Mintz 470a91eb52aSYuval Mintz if (is_chain_u16(p_chain)) { 4716d937acfSMintz, Yuval p_chain->pbl.c.u16.prod_page_idx = (u16)reset_val; 4726d937acfSMintz, Yuval p_chain->pbl.c.u16.cons_page_idx = (u16)reset_val; 473a91eb52aSYuval Mintz } else { 4746d937acfSMintz, Yuval p_chain->pbl.c.u32.prod_page_idx = reset_val; 4756d937acfSMintz, Yuval p_chain->pbl.c.u32.cons_page_idx = reset_val; 476a91eb52aSYuval Mintz } 477fe56b9e6SYuval Mintz } 478fe56b9e6SYuval Mintz 479fe56b9e6SYuval Mintz switch (p_chain->intended_use) { 480fe56b9e6SYuval Mintz case QED_CHAIN_USE_TO_CONSUME: 481fe56b9e6SYuval Mintz /* produce empty elements */ 482fe56b9e6SYuval Mintz for (i = 0; i < p_chain->capacity; i++) 483fe56b9e6SYuval Mintz qed_chain_recycle_consumed(p_chain); 484fe56b9e6SYuval Mintz break; 4856d937acfSMintz, Yuval 4866d937acfSMintz, Yuval case QED_CHAIN_USE_TO_CONSUME_PRODUCE: 4876d937acfSMintz, Yuval case QED_CHAIN_USE_TO_PRODUCE: 4886d937acfSMintz, Yuval default: 4896d937acfSMintz, Yuval /* Do nothing */ 4906d937acfSMintz, Yuval break; 491fe56b9e6SYuval Mintz } 492fe56b9e6SYuval Mintz } 493fe56b9e6SYuval Mintz 494fe56b9e6SYuval Mintz /** 495fe56b9e6SYuval Mintz * @brief qed_chain_init - Initalizes a basic chain struct 496fe56b9e6SYuval Mintz * 497fe56b9e6SYuval Mintz * @param p_chain 498fe56b9e6SYuval Mintz * @param p_virt_addr 499fe56b9e6SYuval Mintz * @param p_phys_addr physical address of allocated buffer's beginning 500fe56b9e6SYuval Mintz * @param page_cnt number of pages in the allocated buffer 501fe56b9e6SYuval Mintz * @param elem_size size of each element in the chain 502fe56b9e6SYuval Mintz * @param intended_use 503fe56b9e6SYuval Mintz * @param mode 504fe56b9e6SYuval Mintz */ 505a91eb52aSYuval Mintz static inline void qed_chain_init_params(struct qed_chain *p_chain, 506a91eb52aSYuval Mintz u32 page_cnt, 507fe56b9e6SYuval Mintz u8 elem_size, 508fe56b9e6SYuval Mintz enum qed_chain_use_mode intended_use, 509a91eb52aSYuval Mintz enum qed_chain_mode mode, 510a91eb52aSYuval Mintz enum qed_chain_cnt_type cnt_type) 511fe56b9e6SYuval Mintz { 512fe56b9e6SYuval Mintz /* chain fixed parameters */ 513a91eb52aSYuval Mintz p_chain->p_virt_addr = NULL; 514a91eb52aSYuval Mintz p_chain->p_phys_addr = 0; 515fe56b9e6SYuval Mintz p_chain->elem_size = elem_size; 5166d937acfSMintz, Yuval p_chain->intended_use = (u8)intended_use; 517a91eb52aSYuval Mintz p_chain->mode = mode; 5186d937acfSMintz, Yuval p_chain->cnt_type = (u8)cnt_type; 519a91eb52aSYuval Mintz 520fe56b9e6SYuval Mintz p_chain->elem_per_page = ELEMS_PER_PAGE(elem_size); 521a91eb52aSYuval Mintz p_chain->usable_per_page = USABLE_ELEMS_PER_PAGE(elem_size, mode); 522fe56b9e6SYuval Mintz p_chain->elem_per_page_mask = p_chain->elem_per_page - 1; 523fe56b9e6SYuval Mintz p_chain->elem_unusable = UNUSABLE_ELEMS_PER_PAGE(elem_size, mode); 524fe56b9e6SYuval Mintz p_chain->next_page_mask = (p_chain->usable_per_page & 525fe56b9e6SYuval Mintz p_chain->elem_per_page_mask); 526fe56b9e6SYuval Mintz 527a91eb52aSYuval Mintz p_chain->page_cnt = page_cnt; 528a91eb52aSYuval Mintz p_chain->capacity = p_chain->usable_per_page * page_cnt; 529a91eb52aSYuval Mintz p_chain->size = p_chain->elem_per_page * page_cnt; 530fe56b9e6SYuval Mintz 5316d937acfSMintz, Yuval p_chain->pbl_sp.p_phys_table = 0; 5326d937acfSMintz, Yuval p_chain->pbl_sp.p_virt_table = NULL; 533a91eb52aSYuval Mintz p_chain->pbl.pp_virt_addr_tbl = NULL; 534fe56b9e6SYuval Mintz } 535fe56b9e6SYuval Mintz 536fe56b9e6SYuval Mintz /** 537a91eb52aSYuval Mintz * @brief qed_chain_init_mem - 538a91eb52aSYuval Mintz * 539a91eb52aSYuval Mintz * Initalizes a basic chain struct with its chain buffers 540a91eb52aSYuval Mintz * 541fe56b9e6SYuval Mintz * @param p_chain 542fe56b9e6SYuval Mintz * @param p_virt_addr virtual address of allocated buffer's beginning 543fe56b9e6SYuval Mintz * @param p_phys_addr physical address of allocated buffer's beginning 544a91eb52aSYuval Mintz * 545fe56b9e6SYuval Mintz */ 546a91eb52aSYuval Mintz static inline void qed_chain_init_mem(struct qed_chain *p_chain, 547a91eb52aSYuval Mintz void *p_virt_addr, dma_addr_t p_phys_addr) 548fe56b9e6SYuval Mintz { 549a91eb52aSYuval Mintz p_chain->p_virt_addr = p_virt_addr; 550a91eb52aSYuval Mintz p_chain->p_phys_addr = p_phys_addr; 551fe56b9e6SYuval Mintz } 552fe56b9e6SYuval Mintz 553fe56b9e6SYuval Mintz /** 554a91eb52aSYuval Mintz * @brief qed_chain_init_pbl_mem - 555a91eb52aSYuval Mintz * 556a91eb52aSYuval Mintz * Initalizes a basic chain struct with its pbl buffers 557a91eb52aSYuval Mintz * 558a91eb52aSYuval Mintz * @param p_chain 559a91eb52aSYuval Mintz * @param p_virt_pbl pointer to a pre allocated side table which will hold 560a91eb52aSYuval Mintz * virtual page addresses. 561a91eb52aSYuval Mintz * @param p_phys_pbl pointer to a pre-allocated side table which will hold 562a91eb52aSYuval Mintz * physical page addresses. 563a91eb52aSYuval Mintz * @param pp_virt_addr_tbl 564a91eb52aSYuval Mintz * pointer to a pre-allocated side table which will hold 565a91eb52aSYuval Mintz * the virtual addresses of the chain pages. 566a91eb52aSYuval Mintz * 567a91eb52aSYuval Mintz */ 568a91eb52aSYuval Mintz static inline void qed_chain_init_pbl_mem(struct qed_chain *p_chain, 569a91eb52aSYuval Mintz void *p_virt_pbl, 570a91eb52aSYuval Mintz dma_addr_t p_phys_pbl, 571a91eb52aSYuval Mintz void **pp_virt_addr_tbl) 572a91eb52aSYuval Mintz { 5736d937acfSMintz, Yuval p_chain->pbl_sp.p_phys_table = p_phys_pbl; 5746d937acfSMintz, Yuval p_chain->pbl_sp.p_virt_table = p_virt_pbl; 575a91eb52aSYuval Mintz p_chain->pbl.pp_virt_addr_tbl = pp_virt_addr_tbl; 576a91eb52aSYuval Mintz } 577a91eb52aSYuval Mintz 578a91eb52aSYuval Mintz /** 579a91eb52aSYuval Mintz * @brief qed_chain_init_next_ptr_elem - 580a91eb52aSYuval Mintz * 581a91eb52aSYuval Mintz * Initalizes a next pointer element 582a91eb52aSYuval Mintz * 583a91eb52aSYuval Mintz * @param p_chain 584a91eb52aSYuval Mintz * @param p_virt_curr virtual address of a chain page of which the next 585a91eb52aSYuval Mintz * pointer element is initialized 586a91eb52aSYuval Mintz * @param p_virt_next virtual address of the next chain page 587a91eb52aSYuval Mintz * @param p_phys_next physical address of the next chain page 588a91eb52aSYuval Mintz * 589a91eb52aSYuval Mintz */ 590a91eb52aSYuval Mintz static inline void 591a91eb52aSYuval Mintz qed_chain_init_next_ptr_elem(struct qed_chain *p_chain, 592a91eb52aSYuval Mintz void *p_virt_curr, 593a91eb52aSYuval Mintz void *p_virt_next, dma_addr_t p_phys_next) 594a91eb52aSYuval Mintz { 595a91eb52aSYuval Mintz struct qed_chain_next *p_next; 596a91eb52aSYuval Mintz u32 size; 597a91eb52aSYuval Mintz 598a91eb52aSYuval Mintz size = p_chain->elem_size * p_chain->usable_per_page; 599a91eb52aSYuval Mintz p_next = (struct qed_chain_next *)((u8 *)p_virt_curr + size); 600a91eb52aSYuval Mintz 601a91eb52aSYuval Mintz DMA_REGPAIR_LE(p_next->next_phys, p_phys_next); 602a91eb52aSYuval Mintz 603a91eb52aSYuval Mintz p_next->next_virt = p_virt_next; 604a91eb52aSYuval Mintz } 605a91eb52aSYuval Mintz 606a91eb52aSYuval Mintz /** 607a91eb52aSYuval Mintz * @brief qed_chain_get_last_elem - 608a91eb52aSYuval Mintz * 609a91eb52aSYuval Mintz * Returns a pointer to the last element of the chain 610a91eb52aSYuval Mintz * 611a91eb52aSYuval Mintz * @param p_chain 612a91eb52aSYuval Mintz * 613a91eb52aSYuval Mintz * @return void* 614a91eb52aSYuval Mintz */ 615a91eb52aSYuval Mintz static inline void *qed_chain_get_last_elem(struct qed_chain *p_chain) 616a91eb52aSYuval Mintz { 617a91eb52aSYuval Mintz struct qed_chain_next *p_next = NULL; 618a91eb52aSYuval Mintz void *p_virt_addr = NULL; 619a91eb52aSYuval Mintz u32 size, last_page_idx; 620a91eb52aSYuval Mintz 621a91eb52aSYuval Mintz if (!p_chain->p_virt_addr) 622a91eb52aSYuval Mintz goto out; 623a91eb52aSYuval Mintz 624a91eb52aSYuval Mintz switch (p_chain->mode) { 625a91eb52aSYuval Mintz case QED_CHAIN_MODE_NEXT_PTR: 626a91eb52aSYuval Mintz size = p_chain->elem_size * p_chain->usable_per_page; 627a91eb52aSYuval Mintz p_virt_addr = p_chain->p_virt_addr; 628a91eb52aSYuval Mintz p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + size); 629a91eb52aSYuval Mintz while (p_next->next_virt != p_chain->p_virt_addr) { 630a91eb52aSYuval Mintz p_virt_addr = p_next->next_virt; 631a91eb52aSYuval Mintz p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + 632a91eb52aSYuval Mintz size); 633a91eb52aSYuval Mintz } 634a91eb52aSYuval Mintz break; 635a91eb52aSYuval Mintz case QED_CHAIN_MODE_SINGLE: 636a91eb52aSYuval Mintz p_virt_addr = p_chain->p_virt_addr; 637a91eb52aSYuval Mintz break; 638a91eb52aSYuval Mintz case QED_CHAIN_MODE_PBL: 639a91eb52aSYuval Mintz last_page_idx = p_chain->page_cnt - 1; 640a91eb52aSYuval Mintz p_virt_addr = p_chain->pbl.pp_virt_addr_tbl[last_page_idx]; 641a91eb52aSYuval Mintz break; 642a91eb52aSYuval Mintz } 643a91eb52aSYuval Mintz /* p_virt_addr points at this stage to the last page of the chain */ 644a91eb52aSYuval Mintz size = p_chain->elem_size * (p_chain->usable_per_page - 1); 645a91eb52aSYuval Mintz p_virt_addr = (u8 *)p_virt_addr + size; 646a91eb52aSYuval Mintz out: 647a91eb52aSYuval Mintz return p_virt_addr; 648a91eb52aSYuval Mintz } 649a91eb52aSYuval Mintz 650a91eb52aSYuval Mintz /** 651a91eb52aSYuval Mintz * @brief qed_chain_set_prod - sets the prod to the given value 652fe56b9e6SYuval Mintz * 653fe56b9e6SYuval Mintz * @param prod_idx 654fe56b9e6SYuval Mintz * @param p_prod_elem 655fe56b9e6SYuval Mintz */ 656fe56b9e6SYuval Mintz static inline void qed_chain_set_prod(struct qed_chain *p_chain, 657a91eb52aSYuval Mintz u32 prod_idx, void *p_prod_elem) 658fe56b9e6SYuval Mintz { 659a91eb52aSYuval Mintz if (is_chain_u16(p_chain)) 660a91eb52aSYuval Mintz p_chain->u.chain16.prod_idx = (u16) prod_idx; 661a91eb52aSYuval Mintz else 662a91eb52aSYuval Mintz p_chain->u.chain32.prod_idx = prod_idx; 663fe56b9e6SYuval Mintz p_chain->p_prod_elem = p_prod_elem; 664fe56b9e6SYuval Mintz } 665fe56b9e6SYuval Mintz 666fe56b9e6SYuval Mintz /** 667a91eb52aSYuval Mintz * @brief qed_chain_pbl_zero_mem - set chain memory to 0 668fe56b9e6SYuval Mintz * 669fe56b9e6SYuval Mintz * @param p_chain 670fe56b9e6SYuval Mintz */ 671a91eb52aSYuval Mintz static inline void qed_chain_pbl_zero_mem(struct qed_chain *p_chain) 672fe56b9e6SYuval Mintz { 673a91eb52aSYuval Mintz u32 i, page_cnt; 674fe56b9e6SYuval Mintz 675a91eb52aSYuval Mintz if (p_chain->mode != QED_CHAIN_MODE_PBL) 676a91eb52aSYuval Mintz return; 677fe56b9e6SYuval Mintz 678a91eb52aSYuval Mintz page_cnt = qed_chain_get_page_cnt(p_chain); 679fe56b9e6SYuval Mintz 680a91eb52aSYuval Mintz for (i = 0; i < page_cnt; i++) 681a91eb52aSYuval Mintz memset(p_chain->pbl.pp_virt_addr_tbl[i], 0, 682a91eb52aSYuval Mintz QED_CHAIN_PAGE_SIZE); 683fe56b9e6SYuval Mintz } 684fe56b9e6SYuval Mintz 685fe56b9e6SYuval Mintz #endif 686