1a08c9b2cSAlexander Lobakin // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2a08c9b2cSAlexander Lobakin /* Copyright (c) 2020 Marvell International Ltd. */
3a08c9b2cSAlexander Lobakin
4a08c9b2cSAlexander Lobakin #include <linux/dma-mapping.h>
5a08c9b2cSAlexander Lobakin #include <linux/qed/qed_chain.h>
6a08c9b2cSAlexander Lobakin #include <linux/vmalloc.h>
7a08c9b2cSAlexander Lobakin
8a08c9b2cSAlexander Lobakin #include "qed_dev_api.h"
9a08c9b2cSAlexander Lobakin
qed_chain_init(struct qed_chain * chain,const struct qed_chain_init_params * params,u32 page_cnt)10b6db3f71SAlexander Lobakin static void qed_chain_init(struct qed_chain *chain,
11b6db3f71SAlexander Lobakin const struct qed_chain_init_params *params,
12b6db3f71SAlexander Lobakin u32 page_cnt)
135e776d80SAlexander Lobakin {
145e776d80SAlexander Lobakin memset(chain, 0, sizeof(*chain));
155e776d80SAlexander Lobakin
16b6db3f71SAlexander Lobakin chain->elem_size = params->elem_size;
17b6db3f71SAlexander Lobakin chain->intended_use = params->intended_use;
18b6db3f71SAlexander Lobakin chain->mode = params->mode;
19b6db3f71SAlexander Lobakin chain->cnt_type = params->cnt_type;
205e776d80SAlexander Lobakin
2115506586SAlexander Lobakin chain->elem_per_page = ELEMS_PER_PAGE(params->elem_size,
2215506586SAlexander Lobakin params->page_size);
23b6db3f71SAlexander Lobakin chain->usable_per_page = USABLE_ELEMS_PER_PAGE(params->elem_size,
2415506586SAlexander Lobakin params->page_size,
25b6db3f71SAlexander Lobakin params->mode);
26b6db3f71SAlexander Lobakin chain->elem_unusable = UNUSABLE_ELEMS_PER_PAGE(params->elem_size,
27b6db3f71SAlexander Lobakin params->mode);
285e776d80SAlexander Lobakin
295e776d80SAlexander Lobakin chain->elem_per_page_mask = chain->elem_per_page - 1;
305e776d80SAlexander Lobakin chain->next_page_mask = chain->usable_per_page &
315e776d80SAlexander Lobakin chain->elem_per_page_mask;
325e776d80SAlexander Lobakin
3315506586SAlexander Lobakin chain->page_size = params->page_size;
345e776d80SAlexander Lobakin chain->page_cnt = page_cnt;
355e776d80SAlexander Lobakin chain->capacity = chain->usable_per_page * page_cnt;
365e776d80SAlexander Lobakin chain->size = chain->elem_per_page * page_cnt;
37c3a321b0SAlexander Lobakin
38b6db3f71SAlexander Lobakin if (params->ext_pbl_virt) {
39b6db3f71SAlexander Lobakin chain->pbl_sp.table_virt = params->ext_pbl_virt;
40b6db3f71SAlexander Lobakin chain->pbl_sp.table_phys = params->ext_pbl_phys;
41c3a321b0SAlexander Lobakin
42c3a321b0SAlexander Lobakin chain->b_external_pbl = true;
43c3a321b0SAlexander Lobakin }
445e776d80SAlexander Lobakin }
455e776d80SAlexander Lobakin
qed_chain_init_next_ptr_elem(const struct qed_chain * chain,void * virt_curr,void * virt_next,dma_addr_t phys_next)465e776d80SAlexander Lobakin static void qed_chain_init_next_ptr_elem(const struct qed_chain *chain,
475e776d80SAlexander Lobakin void *virt_curr, void *virt_next,
485e776d80SAlexander Lobakin dma_addr_t phys_next)
495e776d80SAlexander Lobakin {
505e776d80SAlexander Lobakin struct qed_chain_next *next;
515e776d80SAlexander Lobakin u32 size;
525e776d80SAlexander Lobakin
535e776d80SAlexander Lobakin size = chain->elem_size * chain->usable_per_page;
545e776d80SAlexander Lobakin next = virt_curr + size;
555e776d80SAlexander Lobakin
565e776d80SAlexander Lobakin DMA_REGPAIR_LE(next->next_phys, phys_next);
575e776d80SAlexander Lobakin next->next_virt = virt_next;
585e776d80SAlexander Lobakin }
595e776d80SAlexander Lobakin
qed_chain_init_mem(struct qed_chain * chain,void * virt_addr,dma_addr_t phys_addr)605e776d80SAlexander Lobakin static void qed_chain_init_mem(struct qed_chain *chain, void *virt_addr,
615e776d80SAlexander Lobakin dma_addr_t phys_addr)
625e776d80SAlexander Lobakin {
635e776d80SAlexander Lobakin chain->p_virt_addr = virt_addr;
645e776d80SAlexander Lobakin chain->p_phys_addr = phys_addr;
655e776d80SAlexander Lobakin }
665e776d80SAlexander Lobakin
qed_chain_free_next_ptr(struct qed_dev * cdev,struct qed_chain * chain)67a08c9b2cSAlexander Lobakin static void qed_chain_free_next_ptr(struct qed_dev *cdev,
68a08c9b2cSAlexander Lobakin struct qed_chain *chain)
69a08c9b2cSAlexander Lobakin {
70a08c9b2cSAlexander Lobakin struct device *dev = &cdev->pdev->dev;
71a08c9b2cSAlexander Lobakin struct qed_chain_next *next;
72a08c9b2cSAlexander Lobakin dma_addr_t phys, phys_next;
73a08c9b2cSAlexander Lobakin void *virt, *virt_next;
74a08c9b2cSAlexander Lobakin u32 size, i;
75a08c9b2cSAlexander Lobakin
76a08c9b2cSAlexander Lobakin size = chain->elem_size * chain->usable_per_page;
77a08c9b2cSAlexander Lobakin virt = chain->p_virt_addr;
78a08c9b2cSAlexander Lobakin phys = chain->p_phys_addr;
79a08c9b2cSAlexander Lobakin
80a08c9b2cSAlexander Lobakin for (i = 0; i < chain->page_cnt; i++) {
81a08c9b2cSAlexander Lobakin if (!virt)
82a08c9b2cSAlexander Lobakin break;
83a08c9b2cSAlexander Lobakin
84a08c9b2cSAlexander Lobakin next = virt + size;
85a08c9b2cSAlexander Lobakin virt_next = next->next_virt;
86a08c9b2cSAlexander Lobakin phys_next = HILO_DMA_REGPAIR(next->next_phys);
87a08c9b2cSAlexander Lobakin
8815506586SAlexander Lobakin dma_free_coherent(dev, chain->page_size, virt, phys);
89a08c9b2cSAlexander Lobakin
90a08c9b2cSAlexander Lobakin virt = virt_next;
91a08c9b2cSAlexander Lobakin phys = phys_next;
92a08c9b2cSAlexander Lobakin }
93a08c9b2cSAlexander Lobakin }
94a08c9b2cSAlexander Lobakin
qed_chain_free_single(struct qed_dev * cdev,struct qed_chain * chain)95a08c9b2cSAlexander Lobakin static void qed_chain_free_single(struct qed_dev *cdev,
96a08c9b2cSAlexander Lobakin struct qed_chain *chain)
97a08c9b2cSAlexander Lobakin {
98a08c9b2cSAlexander Lobakin if (!chain->p_virt_addr)
99a08c9b2cSAlexander Lobakin return;
100a08c9b2cSAlexander Lobakin
10115506586SAlexander Lobakin dma_free_coherent(&cdev->pdev->dev, chain->page_size,
102a08c9b2cSAlexander Lobakin chain->p_virt_addr, chain->p_phys_addr);
103a08c9b2cSAlexander Lobakin }
104a08c9b2cSAlexander Lobakin
qed_chain_free_pbl(struct qed_dev * cdev,struct qed_chain * chain)105a08c9b2cSAlexander Lobakin static void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *chain)
106a08c9b2cSAlexander Lobakin {
107a08c9b2cSAlexander Lobakin struct device *dev = &cdev->pdev->dev;
108a08c9b2cSAlexander Lobakin struct addr_tbl_entry *entry;
1099b6ee3cfSAlexander Lobakin u32 i;
110a08c9b2cSAlexander Lobakin
111a08c9b2cSAlexander Lobakin if (!chain->pbl.pp_addr_tbl)
112a08c9b2cSAlexander Lobakin return;
113a08c9b2cSAlexander Lobakin
114a08c9b2cSAlexander Lobakin for (i = 0; i < chain->page_cnt; i++) {
115a08c9b2cSAlexander Lobakin entry = chain->pbl.pp_addr_tbl + i;
116a08c9b2cSAlexander Lobakin if (!entry->virt_addr)
117a08c9b2cSAlexander Lobakin break;
118a08c9b2cSAlexander Lobakin
11915506586SAlexander Lobakin dma_free_coherent(dev, chain->page_size, entry->virt_addr,
120a08c9b2cSAlexander Lobakin entry->dma_map);
121a08c9b2cSAlexander Lobakin }
122a08c9b2cSAlexander Lobakin
123a08c9b2cSAlexander Lobakin if (!chain->b_external_pbl)
1249b6ee3cfSAlexander Lobakin dma_free_coherent(dev, chain->pbl_sp.table_size,
1259b6ee3cfSAlexander Lobakin chain->pbl_sp.table_virt,
1269b6ee3cfSAlexander Lobakin chain->pbl_sp.table_phys);
127a08c9b2cSAlexander Lobakin
128a08c9b2cSAlexander Lobakin vfree(chain->pbl.pp_addr_tbl);
129a08c9b2cSAlexander Lobakin chain->pbl.pp_addr_tbl = NULL;
130a08c9b2cSAlexander Lobakin }
131a08c9b2cSAlexander Lobakin
132a08c9b2cSAlexander Lobakin /**
133a08c9b2cSAlexander Lobakin * qed_chain_free() - Free chain DMA memory.
134a08c9b2cSAlexander Lobakin *
135a08c9b2cSAlexander Lobakin * @cdev: Main device structure.
136a08c9b2cSAlexander Lobakin * @chain: Chain to free.
137a08c9b2cSAlexander Lobakin */
qed_chain_free(struct qed_dev * cdev,struct qed_chain * chain)138a08c9b2cSAlexander Lobakin void qed_chain_free(struct qed_dev *cdev, struct qed_chain *chain)
139a08c9b2cSAlexander Lobakin {
140a08c9b2cSAlexander Lobakin switch (chain->mode) {
141a08c9b2cSAlexander Lobakin case QED_CHAIN_MODE_NEXT_PTR:
142a08c9b2cSAlexander Lobakin qed_chain_free_next_ptr(cdev, chain);
143a08c9b2cSAlexander Lobakin break;
144a08c9b2cSAlexander Lobakin case QED_CHAIN_MODE_SINGLE:
145a08c9b2cSAlexander Lobakin qed_chain_free_single(cdev, chain);
146a08c9b2cSAlexander Lobakin break;
147a08c9b2cSAlexander Lobakin case QED_CHAIN_MODE_PBL:
148a08c9b2cSAlexander Lobakin qed_chain_free_pbl(cdev, chain);
149a08c9b2cSAlexander Lobakin break;
150a08c9b2cSAlexander Lobakin default:
15196ca4c50SAlexander Lobakin return;
152a08c9b2cSAlexander Lobakin }
15396ca4c50SAlexander Lobakin
15496ca4c50SAlexander Lobakin qed_chain_init_mem(chain, NULL, 0);
155a08c9b2cSAlexander Lobakin }
156a08c9b2cSAlexander Lobakin
157a08c9b2cSAlexander Lobakin static int
qed_chain_alloc_sanity_check(struct qed_dev * cdev,const struct qed_chain_init_params * params,u32 page_cnt)158a08c9b2cSAlexander Lobakin qed_chain_alloc_sanity_check(struct qed_dev *cdev,
159b6db3f71SAlexander Lobakin const struct qed_chain_init_params *params,
160b6db3f71SAlexander Lobakin u32 page_cnt)
161a08c9b2cSAlexander Lobakin {
162b6db3f71SAlexander Lobakin u64 chain_size;
163b6db3f71SAlexander Lobakin
16415506586SAlexander Lobakin chain_size = ELEMS_PER_PAGE(params->elem_size, params->page_size);
165b6db3f71SAlexander Lobakin chain_size *= page_cnt;
166b6db3f71SAlexander Lobakin
167b6db3f71SAlexander Lobakin if (!chain_size)
168b6db3f71SAlexander Lobakin return -EINVAL;
169a08c9b2cSAlexander Lobakin
170a08c9b2cSAlexander Lobakin /* The actual chain size can be larger than the maximal possible value
171a08c9b2cSAlexander Lobakin * after rounding up the requested elements number to pages, and after
172a08c9b2cSAlexander Lobakin * taking into account the unusuable elements (next-ptr elements).
173a08c9b2cSAlexander Lobakin * The size of a "u16" chain can be (U16_MAX + 1) since the chain
174a08c9b2cSAlexander Lobakin * size/capacity fields are of u32 type.
175a08c9b2cSAlexander Lobakin */
176b6db3f71SAlexander Lobakin switch (params->cnt_type) {
177a08c9b2cSAlexander Lobakin case QED_CHAIN_CNT_TYPE_U16:
178a08c9b2cSAlexander Lobakin if (chain_size > U16_MAX + 1)
179a08c9b2cSAlexander Lobakin break;
180a08c9b2cSAlexander Lobakin
181a08c9b2cSAlexander Lobakin return 0;
182a08c9b2cSAlexander Lobakin case QED_CHAIN_CNT_TYPE_U32:
183a08c9b2cSAlexander Lobakin if (chain_size > U32_MAX)
184a08c9b2cSAlexander Lobakin break;
185a08c9b2cSAlexander Lobakin
186a08c9b2cSAlexander Lobakin return 0;
187a08c9b2cSAlexander Lobakin default:
188a08c9b2cSAlexander Lobakin return -EINVAL;
189a08c9b2cSAlexander Lobakin }
190a08c9b2cSAlexander Lobakin
191a08c9b2cSAlexander Lobakin DP_NOTICE(cdev,
192a08c9b2cSAlexander Lobakin "The actual chain size (0x%llx) is larger than the maximal possible value\n",
193a08c9b2cSAlexander Lobakin chain_size);
194a08c9b2cSAlexander Lobakin
195a08c9b2cSAlexander Lobakin return -EINVAL;
196a08c9b2cSAlexander Lobakin }
197a08c9b2cSAlexander Lobakin
qed_chain_alloc_next_ptr(struct qed_dev * cdev,struct qed_chain * chain)198a08c9b2cSAlexander Lobakin static int qed_chain_alloc_next_ptr(struct qed_dev *cdev,
199a08c9b2cSAlexander Lobakin struct qed_chain *chain)
200a08c9b2cSAlexander Lobakin {
201a08c9b2cSAlexander Lobakin struct device *dev = &cdev->pdev->dev;
202a08c9b2cSAlexander Lobakin void *virt, *virt_prev = NULL;
203a08c9b2cSAlexander Lobakin dma_addr_t phys;
204a08c9b2cSAlexander Lobakin u32 i;
205a08c9b2cSAlexander Lobakin
206a08c9b2cSAlexander Lobakin for (i = 0; i < chain->page_cnt; i++) {
20715506586SAlexander Lobakin virt = dma_alloc_coherent(dev, chain->page_size, &phys,
208a08c9b2cSAlexander Lobakin GFP_KERNEL);
209a08c9b2cSAlexander Lobakin if (!virt)
210a08c9b2cSAlexander Lobakin return -ENOMEM;
211a08c9b2cSAlexander Lobakin
212a08c9b2cSAlexander Lobakin if (i == 0) {
213a08c9b2cSAlexander Lobakin qed_chain_init_mem(chain, virt, phys);
214a08c9b2cSAlexander Lobakin qed_chain_reset(chain);
215a08c9b2cSAlexander Lobakin } else {
216a08c9b2cSAlexander Lobakin qed_chain_init_next_ptr_elem(chain, virt_prev, virt,
217a08c9b2cSAlexander Lobakin phys);
218a08c9b2cSAlexander Lobakin }
219a08c9b2cSAlexander Lobakin
220a08c9b2cSAlexander Lobakin virt_prev = virt;
221a08c9b2cSAlexander Lobakin }
222a08c9b2cSAlexander Lobakin
223a08c9b2cSAlexander Lobakin /* Last page's next element should point to the beginning of the
224a08c9b2cSAlexander Lobakin * chain.
225a08c9b2cSAlexander Lobakin */
226a08c9b2cSAlexander Lobakin qed_chain_init_next_ptr_elem(chain, virt_prev, chain->p_virt_addr,
227a08c9b2cSAlexander Lobakin chain->p_phys_addr);
228a08c9b2cSAlexander Lobakin
229a08c9b2cSAlexander Lobakin return 0;
230a08c9b2cSAlexander Lobakin }
231a08c9b2cSAlexander Lobakin
qed_chain_alloc_single(struct qed_dev * cdev,struct qed_chain * chain)232a08c9b2cSAlexander Lobakin static int qed_chain_alloc_single(struct qed_dev *cdev,
233a08c9b2cSAlexander Lobakin struct qed_chain *chain)
234a08c9b2cSAlexander Lobakin {
235a08c9b2cSAlexander Lobakin dma_addr_t phys;
236a08c9b2cSAlexander Lobakin void *virt;
237a08c9b2cSAlexander Lobakin
23815506586SAlexander Lobakin virt = dma_alloc_coherent(&cdev->pdev->dev, chain->page_size,
239a08c9b2cSAlexander Lobakin &phys, GFP_KERNEL);
240a08c9b2cSAlexander Lobakin if (!virt)
241a08c9b2cSAlexander Lobakin return -ENOMEM;
242a08c9b2cSAlexander Lobakin
243a08c9b2cSAlexander Lobakin qed_chain_init_mem(chain, virt, phys);
244a08c9b2cSAlexander Lobakin qed_chain_reset(chain);
245a08c9b2cSAlexander Lobakin
246a08c9b2cSAlexander Lobakin return 0;
247a08c9b2cSAlexander Lobakin }
248a08c9b2cSAlexander Lobakin
qed_chain_alloc_pbl(struct qed_dev * cdev,struct qed_chain * chain)249c3a321b0SAlexander Lobakin static int qed_chain_alloc_pbl(struct qed_dev *cdev, struct qed_chain *chain)
250a08c9b2cSAlexander Lobakin {
251a08c9b2cSAlexander Lobakin struct device *dev = &cdev->pdev->dev;
252a08c9b2cSAlexander Lobakin struct addr_tbl_entry *addr_tbl;
253a08c9b2cSAlexander Lobakin dma_addr_t phys, pbl_phys;
2549b6ee3cfSAlexander Lobakin __le64 *pbl_virt;
255a08c9b2cSAlexander Lobakin u32 page_cnt, i;
256a08c9b2cSAlexander Lobakin size_t size;
257a08c9b2cSAlexander Lobakin void *virt;
258a08c9b2cSAlexander Lobakin
259a08c9b2cSAlexander Lobakin page_cnt = chain->page_cnt;
260a08c9b2cSAlexander Lobakin
261a08c9b2cSAlexander Lobakin size = array_size(page_cnt, sizeof(*addr_tbl));
262a08c9b2cSAlexander Lobakin if (unlikely(size == SIZE_MAX))
263a08c9b2cSAlexander Lobakin return -EOVERFLOW;
264a08c9b2cSAlexander Lobakin
265a08c9b2cSAlexander Lobakin addr_tbl = vzalloc(size);
266a08c9b2cSAlexander Lobakin if (!addr_tbl)
267a08c9b2cSAlexander Lobakin return -ENOMEM;
268a08c9b2cSAlexander Lobakin
269a08c9b2cSAlexander Lobakin chain->pbl.pp_addr_tbl = addr_tbl;
270a08c9b2cSAlexander Lobakin
2711775da47SAlexander Lobakin if (chain->b_external_pbl) {
2721775da47SAlexander Lobakin pbl_virt = chain->pbl_sp.table_virt;
273c3a321b0SAlexander Lobakin goto alloc_pages;
2741775da47SAlexander Lobakin }
275a08c9b2cSAlexander Lobakin
2769b6ee3cfSAlexander Lobakin size = array_size(page_cnt, sizeof(*pbl_virt));
277a08c9b2cSAlexander Lobakin if (unlikely(size == SIZE_MAX))
278a08c9b2cSAlexander Lobakin return -EOVERFLOW;
279a08c9b2cSAlexander Lobakin
280c3a321b0SAlexander Lobakin pbl_virt = dma_alloc_coherent(dev, size, &pbl_phys, GFP_KERNEL);
281a08c9b2cSAlexander Lobakin if (!pbl_virt)
282a08c9b2cSAlexander Lobakin return -ENOMEM;
283a08c9b2cSAlexander Lobakin
2849b6ee3cfSAlexander Lobakin chain->pbl_sp.table_virt = pbl_virt;
2859b6ee3cfSAlexander Lobakin chain->pbl_sp.table_phys = pbl_phys;
2869b6ee3cfSAlexander Lobakin chain->pbl_sp.table_size = size;
287a08c9b2cSAlexander Lobakin
288c3a321b0SAlexander Lobakin alloc_pages:
289a08c9b2cSAlexander Lobakin for (i = 0; i < page_cnt; i++) {
29015506586SAlexander Lobakin virt = dma_alloc_coherent(dev, chain->page_size, &phys,
291a08c9b2cSAlexander Lobakin GFP_KERNEL);
292a08c9b2cSAlexander Lobakin if (!virt)
293a08c9b2cSAlexander Lobakin return -ENOMEM;
294a08c9b2cSAlexander Lobakin
295a08c9b2cSAlexander Lobakin if (i == 0) {
296a08c9b2cSAlexander Lobakin qed_chain_init_mem(chain, virt, phys);
297a08c9b2cSAlexander Lobakin qed_chain_reset(chain);
298a08c9b2cSAlexander Lobakin }
299a08c9b2cSAlexander Lobakin
300a08c9b2cSAlexander Lobakin /* Fill the PBL table with the physical address of the page */
3019b6ee3cfSAlexander Lobakin pbl_virt[i] = cpu_to_le64(phys);
302a08c9b2cSAlexander Lobakin
303a08c9b2cSAlexander Lobakin /* Keep the virtual address of the page */
304a08c9b2cSAlexander Lobakin addr_tbl[i].virt_addr = virt;
305a08c9b2cSAlexander Lobakin addr_tbl[i].dma_map = phys;
306a08c9b2cSAlexander Lobakin }
307a08c9b2cSAlexander Lobakin
308a08c9b2cSAlexander Lobakin return 0;
309a08c9b2cSAlexander Lobakin }
310a08c9b2cSAlexander Lobakin
311b6db3f71SAlexander Lobakin /**
312b6db3f71SAlexander Lobakin * qed_chain_alloc() - Allocate and initialize a chain.
313b6db3f71SAlexander Lobakin *
314b6db3f71SAlexander Lobakin * @cdev: Main device structure.
315b6db3f71SAlexander Lobakin * @chain: Chain to be processed.
316b6db3f71SAlexander Lobakin * @params: Chain initialization parameters.
317b6db3f71SAlexander Lobakin *
318b6db3f71SAlexander Lobakin * Return: 0 on success, negative errno otherwise.
319b6db3f71SAlexander Lobakin */
qed_chain_alloc(struct qed_dev * cdev,struct qed_chain * chain,struct qed_chain_init_params * params)320b6db3f71SAlexander Lobakin int qed_chain_alloc(struct qed_dev *cdev, struct qed_chain *chain,
321b6db3f71SAlexander Lobakin struct qed_chain_init_params *params)
322a08c9b2cSAlexander Lobakin {
323a08c9b2cSAlexander Lobakin u32 page_cnt;
324a08c9b2cSAlexander Lobakin int rc;
325a08c9b2cSAlexander Lobakin
32615506586SAlexander Lobakin if (!params->page_size)
32715506586SAlexander Lobakin params->page_size = QED_CHAIN_PAGE_SIZE;
32815506586SAlexander Lobakin
329b6db3f71SAlexander Lobakin if (params->mode == QED_CHAIN_MODE_SINGLE)
330a08c9b2cSAlexander Lobakin page_cnt = 1;
331a08c9b2cSAlexander Lobakin else
332b6db3f71SAlexander Lobakin page_cnt = QED_CHAIN_PAGE_CNT(params->num_elems,
333b6db3f71SAlexander Lobakin params->elem_size,
33415506586SAlexander Lobakin params->page_size,
335b6db3f71SAlexander Lobakin params->mode);
336a08c9b2cSAlexander Lobakin
337b6db3f71SAlexander Lobakin rc = qed_chain_alloc_sanity_check(cdev, params, page_cnt);
338a08c9b2cSAlexander Lobakin if (rc) {
339a08c9b2cSAlexander Lobakin DP_NOTICE(cdev,
340a08c9b2cSAlexander Lobakin "Cannot allocate a chain with the given arguments:\n");
341a08c9b2cSAlexander Lobakin DP_NOTICE(cdev,
34215506586SAlexander Lobakin "[use_mode %d, mode %d, cnt_type %d, num_elems %d, elem_size %zu, page_size %u]\n",
343b6db3f71SAlexander Lobakin params->intended_use, params->mode, params->cnt_type,
34415506586SAlexander Lobakin params->num_elems, params->elem_size,
34515506586SAlexander Lobakin params->page_size);
346a08c9b2cSAlexander Lobakin return rc;
347a08c9b2cSAlexander Lobakin }
348a08c9b2cSAlexander Lobakin
349b6db3f71SAlexander Lobakin qed_chain_init(chain, params, page_cnt);
350a08c9b2cSAlexander Lobakin
351b6db3f71SAlexander Lobakin switch (params->mode) {
352a08c9b2cSAlexander Lobakin case QED_CHAIN_MODE_NEXT_PTR:
353a08c9b2cSAlexander Lobakin rc = qed_chain_alloc_next_ptr(cdev, chain);
354a08c9b2cSAlexander Lobakin break;
355a08c9b2cSAlexander Lobakin case QED_CHAIN_MODE_SINGLE:
356a08c9b2cSAlexander Lobakin rc = qed_chain_alloc_single(cdev, chain);
357a08c9b2cSAlexander Lobakin break;
358a08c9b2cSAlexander Lobakin case QED_CHAIN_MODE_PBL:
359c3a321b0SAlexander Lobakin rc = qed_chain_alloc_pbl(cdev, chain);
360a08c9b2cSAlexander Lobakin break;
361a08c9b2cSAlexander Lobakin default:
362a08c9b2cSAlexander Lobakin return -EINVAL;
363a08c9b2cSAlexander Lobakin }
364a08c9b2cSAlexander Lobakin
365a08c9b2cSAlexander Lobakin if (!rc)
366a08c9b2cSAlexander Lobakin return 0;
367a08c9b2cSAlexander Lobakin
368a08c9b2cSAlexander Lobakin qed_chain_free(cdev, chain);
369a08c9b2cSAlexander Lobakin
370a08c9b2cSAlexander Lobakin return rc;
371a08c9b2cSAlexander Lobakin }
372