18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* Copyright (c) 2020 Marvell International Ltd. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 58c2ecf20Sopenharmony_ci#include <linux/qed/qed_chain.h> 68c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "qed_dev_api.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistatic void qed_chain_init(struct qed_chain *chain, 118c2ecf20Sopenharmony_ci const struct qed_chain_init_params *params, 128c2ecf20Sopenharmony_ci u32 page_cnt) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci memset(chain, 0, sizeof(*chain)); 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci chain->elem_size = params->elem_size; 178c2ecf20Sopenharmony_ci chain->intended_use = params->intended_use; 188c2ecf20Sopenharmony_ci chain->mode = params->mode; 198c2ecf20Sopenharmony_ci chain->cnt_type = params->cnt_type; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci chain->elem_per_page = ELEMS_PER_PAGE(params->elem_size, 228c2ecf20Sopenharmony_ci params->page_size); 238c2ecf20Sopenharmony_ci chain->usable_per_page = USABLE_ELEMS_PER_PAGE(params->elem_size, 248c2ecf20Sopenharmony_ci params->page_size, 258c2ecf20Sopenharmony_ci params->mode); 268c2ecf20Sopenharmony_ci chain->elem_unusable = UNUSABLE_ELEMS_PER_PAGE(params->elem_size, 278c2ecf20Sopenharmony_ci params->mode); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci chain->elem_per_page_mask = chain->elem_per_page - 1; 308c2ecf20Sopenharmony_ci chain->next_page_mask = chain->usable_per_page & 318c2ecf20Sopenharmony_ci chain->elem_per_page_mask; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci chain->page_size = params->page_size; 348c2ecf20Sopenharmony_ci chain->page_cnt = page_cnt; 358c2ecf20Sopenharmony_ci chain->capacity = chain->usable_per_page * page_cnt; 368c2ecf20Sopenharmony_ci chain->size = chain->elem_per_page * page_cnt; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (params->ext_pbl_virt) { 398c2ecf20Sopenharmony_ci chain->pbl_sp.table_virt = params->ext_pbl_virt; 408c2ecf20Sopenharmony_ci chain->pbl_sp.table_phys = params->ext_pbl_phys; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci chain->b_external_pbl = true; 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void qed_chain_init_next_ptr_elem(const struct qed_chain *chain, 478c2ecf20Sopenharmony_ci void *virt_curr, void *virt_next, 488c2ecf20Sopenharmony_ci dma_addr_t phys_next) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct qed_chain_next *next; 518c2ecf20Sopenharmony_ci u32 size; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci size = chain->elem_size * chain->usable_per_page; 548c2ecf20Sopenharmony_ci next = virt_curr + size; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci DMA_REGPAIR_LE(next->next_phys, phys_next); 578c2ecf20Sopenharmony_ci next->next_virt = virt_next; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void qed_chain_init_mem(struct qed_chain *chain, void *virt_addr, 618c2ecf20Sopenharmony_ci dma_addr_t phys_addr) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci chain->p_virt_addr = virt_addr; 648c2ecf20Sopenharmony_ci chain->p_phys_addr = phys_addr; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void qed_chain_free_next_ptr(struct qed_dev *cdev, 688c2ecf20Sopenharmony_ci struct qed_chain *chain) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct device *dev = &cdev->pdev->dev; 718c2ecf20Sopenharmony_ci struct qed_chain_next *next; 728c2ecf20Sopenharmony_ci dma_addr_t phys, phys_next; 738c2ecf20Sopenharmony_ci void *virt, *virt_next; 748c2ecf20Sopenharmony_ci u32 size, i; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci size = chain->elem_size * chain->usable_per_page; 778c2ecf20Sopenharmony_ci virt = chain->p_virt_addr; 788c2ecf20Sopenharmony_ci phys = chain->p_phys_addr; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci for (i = 0; i < chain->page_cnt; i++) { 818c2ecf20Sopenharmony_ci if (!virt) 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci next = virt + size; 858c2ecf20Sopenharmony_ci virt_next = next->next_virt; 868c2ecf20Sopenharmony_ci phys_next = HILO_DMA_REGPAIR(next->next_phys); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci dma_free_coherent(dev, chain->page_size, virt, phys); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci virt = virt_next; 918c2ecf20Sopenharmony_ci phys = phys_next; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void qed_chain_free_single(struct qed_dev *cdev, 968c2ecf20Sopenharmony_ci struct qed_chain *chain) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci if (!chain->p_virt_addr) 998c2ecf20Sopenharmony_ci return; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci dma_free_coherent(&cdev->pdev->dev, chain->page_size, 1028c2ecf20Sopenharmony_ci chain->p_virt_addr, chain->p_phys_addr); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *chain) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct device *dev = &cdev->pdev->dev; 1088c2ecf20Sopenharmony_ci struct addr_tbl_entry *entry; 1098c2ecf20Sopenharmony_ci u32 i; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (!chain->pbl.pp_addr_tbl) 1128c2ecf20Sopenharmony_ci return; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci for (i = 0; i < chain->page_cnt; i++) { 1158c2ecf20Sopenharmony_ci entry = chain->pbl.pp_addr_tbl + i; 1168c2ecf20Sopenharmony_ci if (!entry->virt_addr) 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci dma_free_coherent(dev, chain->page_size, entry->virt_addr, 1208c2ecf20Sopenharmony_ci entry->dma_map); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (!chain->b_external_pbl) 1248c2ecf20Sopenharmony_ci dma_free_coherent(dev, chain->pbl_sp.table_size, 1258c2ecf20Sopenharmony_ci chain->pbl_sp.table_virt, 1268c2ecf20Sopenharmony_ci chain->pbl_sp.table_phys); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci vfree(chain->pbl.pp_addr_tbl); 1298c2ecf20Sopenharmony_ci chain->pbl.pp_addr_tbl = NULL; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/** 1338c2ecf20Sopenharmony_ci * qed_chain_free() - Free chain DMA memory. 1348c2ecf20Sopenharmony_ci * 1358c2ecf20Sopenharmony_ci * @cdev: Main device structure. 1368c2ecf20Sopenharmony_ci * @chain: Chain to free. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_civoid qed_chain_free(struct qed_dev *cdev, struct qed_chain *chain) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci switch (chain->mode) { 1418c2ecf20Sopenharmony_ci case QED_CHAIN_MODE_NEXT_PTR: 1428c2ecf20Sopenharmony_ci qed_chain_free_next_ptr(cdev, chain); 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci case QED_CHAIN_MODE_SINGLE: 1458c2ecf20Sopenharmony_ci qed_chain_free_single(cdev, chain); 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci case QED_CHAIN_MODE_PBL: 1488c2ecf20Sopenharmony_ci qed_chain_free_pbl(cdev, chain); 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci default: 1518c2ecf20Sopenharmony_ci return; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci qed_chain_init_mem(chain, NULL, 0); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int 1588c2ecf20Sopenharmony_ciqed_chain_alloc_sanity_check(struct qed_dev *cdev, 1598c2ecf20Sopenharmony_ci const struct qed_chain_init_params *params, 1608c2ecf20Sopenharmony_ci u32 page_cnt) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci u64 chain_size; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci chain_size = ELEMS_PER_PAGE(params->elem_size, params->page_size); 1658c2ecf20Sopenharmony_ci chain_size *= page_cnt; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (!chain_size) 1688c2ecf20Sopenharmony_ci return -EINVAL; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* The actual chain size can be larger than the maximal possible value 1718c2ecf20Sopenharmony_ci * after rounding up the requested elements number to pages, and after 1728c2ecf20Sopenharmony_ci * taking into account the unusuable elements (next-ptr elements). 1738c2ecf20Sopenharmony_ci * The size of a "u16" chain can be (U16_MAX + 1) since the chain 1748c2ecf20Sopenharmony_ci * size/capacity fields are of u32 type. 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_ci switch (params->cnt_type) { 1778c2ecf20Sopenharmony_ci case QED_CHAIN_CNT_TYPE_U16: 1788c2ecf20Sopenharmony_ci if (chain_size > U16_MAX + 1) 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci case QED_CHAIN_CNT_TYPE_U32: 1838c2ecf20Sopenharmony_ci if (chain_size > U32_MAX) 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci default: 1888c2ecf20Sopenharmony_ci return -EINVAL; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 1928c2ecf20Sopenharmony_ci "The actual chain size (0x%llx) is larger than the maximal possible value\n", 1938c2ecf20Sopenharmony_ci chain_size); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return -EINVAL; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic int qed_chain_alloc_next_ptr(struct qed_dev *cdev, 1998c2ecf20Sopenharmony_ci struct qed_chain *chain) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct device *dev = &cdev->pdev->dev; 2028c2ecf20Sopenharmony_ci void *virt, *virt_prev = NULL; 2038c2ecf20Sopenharmony_ci dma_addr_t phys; 2048c2ecf20Sopenharmony_ci u32 i; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci for (i = 0; i < chain->page_cnt; i++) { 2078c2ecf20Sopenharmony_ci virt = dma_alloc_coherent(dev, chain->page_size, &phys, 2088c2ecf20Sopenharmony_ci GFP_KERNEL); 2098c2ecf20Sopenharmony_ci if (!virt) 2108c2ecf20Sopenharmony_ci return -ENOMEM; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (i == 0) { 2138c2ecf20Sopenharmony_ci qed_chain_init_mem(chain, virt, phys); 2148c2ecf20Sopenharmony_ci qed_chain_reset(chain); 2158c2ecf20Sopenharmony_ci } else { 2168c2ecf20Sopenharmony_ci qed_chain_init_next_ptr_elem(chain, virt_prev, virt, 2178c2ecf20Sopenharmony_ci phys); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci virt_prev = virt; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* Last page's next element should point to the beginning of the 2248c2ecf20Sopenharmony_ci * chain. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci qed_chain_init_next_ptr_elem(chain, virt_prev, chain->p_virt_addr, 2278c2ecf20Sopenharmony_ci chain->p_phys_addr); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int qed_chain_alloc_single(struct qed_dev *cdev, 2338c2ecf20Sopenharmony_ci struct qed_chain *chain) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci dma_addr_t phys; 2368c2ecf20Sopenharmony_ci void *virt; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci virt = dma_alloc_coherent(&cdev->pdev->dev, chain->page_size, 2398c2ecf20Sopenharmony_ci &phys, GFP_KERNEL); 2408c2ecf20Sopenharmony_ci if (!virt) 2418c2ecf20Sopenharmony_ci return -ENOMEM; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci qed_chain_init_mem(chain, virt, phys); 2448c2ecf20Sopenharmony_ci qed_chain_reset(chain); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int qed_chain_alloc_pbl(struct qed_dev *cdev, struct qed_chain *chain) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct device *dev = &cdev->pdev->dev; 2528c2ecf20Sopenharmony_ci struct addr_tbl_entry *addr_tbl; 2538c2ecf20Sopenharmony_ci dma_addr_t phys, pbl_phys; 2548c2ecf20Sopenharmony_ci __le64 *pbl_virt; 2558c2ecf20Sopenharmony_ci u32 page_cnt, i; 2568c2ecf20Sopenharmony_ci size_t size; 2578c2ecf20Sopenharmony_ci void *virt; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci page_cnt = chain->page_cnt; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci size = array_size(page_cnt, sizeof(*addr_tbl)); 2628c2ecf20Sopenharmony_ci if (unlikely(size == SIZE_MAX)) 2638c2ecf20Sopenharmony_ci return -EOVERFLOW; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci addr_tbl = vzalloc(size); 2668c2ecf20Sopenharmony_ci if (!addr_tbl) 2678c2ecf20Sopenharmony_ci return -ENOMEM; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci chain->pbl.pp_addr_tbl = addr_tbl; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (chain->b_external_pbl) { 2728c2ecf20Sopenharmony_ci pbl_virt = chain->pbl_sp.table_virt; 2738c2ecf20Sopenharmony_ci goto alloc_pages; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci size = array_size(page_cnt, sizeof(*pbl_virt)); 2778c2ecf20Sopenharmony_ci if (unlikely(size == SIZE_MAX)) 2788c2ecf20Sopenharmony_ci return -EOVERFLOW; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci pbl_virt = dma_alloc_coherent(dev, size, &pbl_phys, GFP_KERNEL); 2818c2ecf20Sopenharmony_ci if (!pbl_virt) 2828c2ecf20Sopenharmony_ci return -ENOMEM; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci chain->pbl_sp.table_virt = pbl_virt; 2858c2ecf20Sopenharmony_ci chain->pbl_sp.table_phys = pbl_phys; 2868c2ecf20Sopenharmony_ci chain->pbl_sp.table_size = size; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cialloc_pages: 2898c2ecf20Sopenharmony_ci for (i = 0; i < page_cnt; i++) { 2908c2ecf20Sopenharmony_ci virt = dma_alloc_coherent(dev, chain->page_size, &phys, 2918c2ecf20Sopenharmony_ci GFP_KERNEL); 2928c2ecf20Sopenharmony_ci if (!virt) 2938c2ecf20Sopenharmony_ci return -ENOMEM; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (i == 0) { 2968c2ecf20Sopenharmony_ci qed_chain_init_mem(chain, virt, phys); 2978c2ecf20Sopenharmony_ci qed_chain_reset(chain); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Fill the PBL table with the physical address of the page */ 3018c2ecf20Sopenharmony_ci pbl_virt[i] = cpu_to_le64(phys); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Keep the virtual address of the page */ 3048c2ecf20Sopenharmony_ci addr_tbl[i].virt_addr = virt; 3058c2ecf20Sopenharmony_ci addr_tbl[i].dma_map = phys; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return 0; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/** 3128c2ecf20Sopenharmony_ci * qed_chain_alloc() - Allocate and initialize a chain. 3138c2ecf20Sopenharmony_ci * 3148c2ecf20Sopenharmony_ci * @cdev: Main device structure. 3158c2ecf20Sopenharmony_ci * @chain: Chain to be processed. 3168c2ecf20Sopenharmony_ci * @params: Chain initialization parameters. 3178c2ecf20Sopenharmony_ci * 3188c2ecf20Sopenharmony_ci * Return: 0 on success, negative errno otherwise. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_ciint qed_chain_alloc(struct qed_dev *cdev, struct qed_chain *chain, 3218c2ecf20Sopenharmony_ci struct qed_chain_init_params *params) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci u32 page_cnt; 3248c2ecf20Sopenharmony_ci int rc; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (!params->page_size) 3278c2ecf20Sopenharmony_ci params->page_size = QED_CHAIN_PAGE_SIZE; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (params->mode == QED_CHAIN_MODE_SINGLE) 3308c2ecf20Sopenharmony_ci page_cnt = 1; 3318c2ecf20Sopenharmony_ci else 3328c2ecf20Sopenharmony_ci page_cnt = QED_CHAIN_PAGE_CNT(params->num_elems, 3338c2ecf20Sopenharmony_ci params->elem_size, 3348c2ecf20Sopenharmony_ci params->page_size, 3358c2ecf20Sopenharmony_ci params->mode); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci rc = qed_chain_alloc_sanity_check(cdev, params, page_cnt); 3388c2ecf20Sopenharmony_ci if (rc) { 3398c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 3408c2ecf20Sopenharmony_ci "Cannot allocate a chain with the given arguments:\n"); 3418c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 3428c2ecf20Sopenharmony_ci "[use_mode %d, mode %d, cnt_type %d, num_elems %d, elem_size %zu, page_size %u]\n", 3438c2ecf20Sopenharmony_ci params->intended_use, params->mode, params->cnt_type, 3448c2ecf20Sopenharmony_ci params->num_elems, params->elem_size, 3458c2ecf20Sopenharmony_ci params->page_size); 3468c2ecf20Sopenharmony_ci return rc; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci qed_chain_init(chain, params, page_cnt); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci switch (params->mode) { 3528c2ecf20Sopenharmony_ci case QED_CHAIN_MODE_NEXT_PTR: 3538c2ecf20Sopenharmony_ci rc = qed_chain_alloc_next_ptr(cdev, chain); 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci case QED_CHAIN_MODE_SINGLE: 3568c2ecf20Sopenharmony_ci rc = qed_chain_alloc_single(cdev, chain); 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci case QED_CHAIN_MODE_PBL: 3598c2ecf20Sopenharmony_ci rc = qed_chain_alloc_pbl(cdev, chain); 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci default: 3628c2ecf20Sopenharmony_ci return -EINVAL; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (!rc) 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci qed_chain_free(cdev, chain); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return rc; 3718c2ecf20Sopenharmony_ci} 372