18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Marvell OcteonTX CPT driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2019 Marvell International Ltd. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 88c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/ctype.h> 128c2ecf20Sopenharmony_ci#include <linux/firmware.h> 138c2ecf20Sopenharmony_ci#include "otx_cpt_common.h" 148c2ecf20Sopenharmony_ci#include "otx_cptpf_ucode.h" 158c2ecf20Sopenharmony_ci#include "otx_cptpf.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define CSR_DELAY 30 188c2ecf20Sopenharmony_ci/* Tar archive defines */ 198c2ecf20Sopenharmony_ci#define TAR_MAGIC "ustar" 208c2ecf20Sopenharmony_ci#define TAR_MAGIC_LEN 6 218c2ecf20Sopenharmony_ci#define TAR_BLOCK_LEN 512 228c2ecf20Sopenharmony_ci#define REGTYPE '0' 238c2ecf20Sopenharmony_ci#define AREGTYPE '\0' 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* tar header as defined in POSIX 1003.1-1990. */ 268c2ecf20Sopenharmony_cistruct tar_hdr_t { 278c2ecf20Sopenharmony_ci char name[100]; 288c2ecf20Sopenharmony_ci char mode[8]; 298c2ecf20Sopenharmony_ci char uid[8]; 308c2ecf20Sopenharmony_ci char gid[8]; 318c2ecf20Sopenharmony_ci char size[12]; 328c2ecf20Sopenharmony_ci char mtime[12]; 338c2ecf20Sopenharmony_ci char chksum[8]; 348c2ecf20Sopenharmony_ci char typeflag; 358c2ecf20Sopenharmony_ci char linkname[100]; 368c2ecf20Sopenharmony_ci char magic[6]; 378c2ecf20Sopenharmony_ci char version[2]; 388c2ecf20Sopenharmony_ci char uname[32]; 398c2ecf20Sopenharmony_ci char gname[32]; 408c2ecf20Sopenharmony_ci char devmajor[8]; 418c2ecf20Sopenharmony_ci char devminor[8]; 428c2ecf20Sopenharmony_ci char prefix[155]; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct tar_blk_t { 468c2ecf20Sopenharmony_ci union { 478c2ecf20Sopenharmony_ci struct tar_hdr_t hdr; 488c2ecf20Sopenharmony_ci char block[TAR_BLOCK_LEN]; 498c2ecf20Sopenharmony_ci }; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct tar_arch_info_t { 538c2ecf20Sopenharmony_ci struct list_head ucodes; 548c2ecf20Sopenharmony_ci const struct firmware *fw; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic struct otx_cpt_bitmap get_cores_bmap(struct device *dev, 588c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *eng_grp) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct otx_cpt_bitmap bmap = { {0} }; 618c2ecf20Sopenharmony_ci bool found = false; 628c2ecf20Sopenharmony_ci int i; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (eng_grp->g->engs_num > OTX_CPT_MAX_ENGINES) { 658c2ecf20Sopenharmony_ci dev_err(dev, "unsupported number of engines %d on octeontx\n", 668c2ecf20Sopenharmony_ci eng_grp->g->engs_num); 678c2ecf20Sopenharmony_ci return bmap; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) { 718c2ecf20Sopenharmony_ci if (eng_grp->engs[i].type) { 728c2ecf20Sopenharmony_ci bitmap_or(bmap.bits, bmap.bits, 738c2ecf20Sopenharmony_ci eng_grp->engs[i].bmap, 748c2ecf20Sopenharmony_ci eng_grp->g->engs_num); 758c2ecf20Sopenharmony_ci bmap.size = eng_grp->g->engs_num; 768c2ecf20Sopenharmony_ci found = true; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (!found) 818c2ecf20Sopenharmony_ci dev_err(dev, "No engines reserved for engine group %d\n", 828c2ecf20Sopenharmony_ci eng_grp->idx); 838c2ecf20Sopenharmony_ci return bmap; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int is_eng_type(int val, int eng_type) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci return val & (1 << eng_type); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int dev_supports_eng_type(struct otx_cpt_eng_grps *eng_grps, 928c2ecf20Sopenharmony_ci int eng_type) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci return is_eng_type(eng_grps->eng_types_supported, eng_type); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic void set_ucode_filename(struct otx_cpt_ucode *ucode, 988c2ecf20Sopenharmony_ci const char *filename) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci strlcpy(ucode->filename, filename, OTX_CPT_UCODE_NAME_LENGTH); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic char *get_eng_type_str(int eng_type) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci char *str = "unknown"; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci switch (eng_type) { 1088c2ecf20Sopenharmony_ci case OTX_CPT_SE_TYPES: 1098c2ecf20Sopenharmony_ci str = "SE"; 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci case OTX_CPT_AE_TYPES: 1138c2ecf20Sopenharmony_ci str = "AE"; 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci return str; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic char *get_ucode_type_str(int ucode_type) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci char *str = "unknown"; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci switch (ucode_type) { 1248c2ecf20Sopenharmony_ci case (1 << OTX_CPT_SE_TYPES): 1258c2ecf20Sopenharmony_ci str = "SE"; 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci case (1 << OTX_CPT_AE_TYPES): 1298c2ecf20Sopenharmony_ci str = "AE"; 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci return str; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int get_ucode_type(struct otx_cpt_ucode_hdr *ucode_hdr, int *ucode_type) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci char tmp_ver_str[OTX_CPT_UCODE_VER_STR_SZ]; 1388c2ecf20Sopenharmony_ci u32 i, val = 0; 1398c2ecf20Sopenharmony_ci u8 nn; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci strlcpy(tmp_ver_str, ucode_hdr->ver_str, OTX_CPT_UCODE_VER_STR_SZ); 1428c2ecf20Sopenharmony_ci for (i = 0; i < strlen(tmp_ver_str); i++) 1438c2ecf20Sopenharmony_ci tmp_ver_str[i] = tolower(tmp_ver_str[i]); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci nn = ucode_hdr->ver_num.nn; 1468c2ecf20Sopenharmony_ci if (strnstr(tmp_ver_str, "se-", OTX_CPT_UCODE_VER_STR_SZ) && 1478c2ecf20Sopenharmony_ci (nn == OTX_CPT_SE_UC_TYPE1 || nn == OTX_CPT_SE_UC_TYPE2 || 1488c2ecf20Sopenharmony_ci nn == OTX_CPT_SE_UC_TYPE3)) 1498c2ecf20Sopenharmony_ci val |= 1 << OTX_CPT_SE_TYPES; 1508c2ecf20Sopenharmony_ci if (strnstr(tmp_ver_str, "ae", OTX_CPT_UCODE_VER_STR_SZ) && 1518c2ecf20Sopenharmony_ci nn == OTX_CPT_AE_UC_TYPE) 1528c2ecf20Sopenharmony_ci val |= 1 << OTX_CPT_AE_TYPES; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci *ucode_type = val; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (!val) 1578c2ecf20Sopenharmony_ci return -EINVAL; 1588c2ecf20Sopenharmony_ci if (is_eng_type(val, OTX_CPT_AE_TYPES) && 1598c2ecf20Sopenharmony_ci is_eng_type(val, OTX_CPT_SE_TYPES)) 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int is_mem_zero(const char *ptr, int size) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci int i; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 1698c2ecf20Sopenharmony_ci if (ptr[i]) 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci return 1; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int cpt_set_ucode_base(struct otx_cpt_eng_grp_info *eng_grp, void *obj) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct otx_cpt_device *cpt = (struct otx_cpt_device *) obj; 1788c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 1798c2ecf20Sopenharmony_ci struct otx_cpt_bitmap bmap; 1808c2ecf20Sopenharmony_ci int i; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci bmap = get_cores_bmap(&cpt->pdev->dev, eng_grp); 1838c2ecf20Sopenharmony_ci if (!bmap.size) 1848c2ecf20Sopenharmony_ci return -EINVAL; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (eng_grp->mirror.is_ena) 1878c2ecf20Sopenharmony_ci dma_addr = 1888c2ecf20Sopenharmony_ci eng_grp->g->grp[eng_grp->mirror.idx].ucode[0].align_dma; 1898c2ecf20Sopenharmony_ci else 1908c2ecf20Sopenharmony_ci dma_addr = eng_grp->ucode[0].align_dma; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* 1938c2ecf20Sopenharmony_ci * Set UCODE_BASE only for the cores which are not used, 1948c2ecf20Sopenharmony_ci * other cores should have already valid UCODE_BASE set 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ci for_each_set_bit(i, bmap.bits, bmap.size) 1978c2ecf20Sopenharmony_ci if (!eng_grp->g->eng_ref_cnt[i]) 1988c2ecf20Sopenharmony_ci writeq((u64) dma_addr, cpt->reg_base + 1998c2ecf20Sopenharmony_ci OTX_CPT_PF_ENGX_UCODE_BASE(i)); 2008c2ecf20Sopenharmony_ci return 0; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int cpt_detach_and_disable_cores(struct otx_cpt_eng_grp_info *eng_grp, 2048c2ecf20Sopenharmony_ci void *obj) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct otx_cpt_device *cpt = (struct otx_cpt_device *) obj; 2078c2ecf20Sopenharmony_ci struct otx_cpt_bitmap bmap = { {0} }; 2088c2ecf20Sopenharmony_ci int timeout = 10; 2098c2ecf20Sopenharmony_ci int i, busy; 2108c2ecf20Sopenharmony_ci u64 reg; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci bmap = get_cores_bmap(&cpt->pdev->dev, eng_grp); 2138c2ecf20Sopenharmony_ci if (!bmap.size) 2148c2ecf20Sopenharmony_ci return -EINVAL; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* Detach the cores from group */ 2178c2ecf20Sopenharmony_ci reg = readq(cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx)); 2188c2ecf20Sopenharmony_ci for_each_set_bit(i, bmap.bits, bmap.size) { 2198c2ecf20Sopenharmony_ci if (reg & (1ull << i)) { 2208c2ecf20Sopenharmony_ci eng_grp->g->eng_ref_cnt[i]--; 2218c2ecf20Sopenharmony_ci reg &= ~(1ull << i); 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci writeq(reg, cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx)); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Wait for cores to become idle */ 2278c2ecf20Sopenharmony_ci do { 2288c2ecf20Sopenharmony_ci busy = 0; 2298c2ecf20Sopenharmony_ci usleep_range(10000, 20000); 2308c2ecf20Sopenharmony_ci if (timeout-- < 0) 2318c2ecf20Sopenharmony_ci return -EBUSY; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci reg = readq(cpt->reg_base + OTX_CPT_PF_EXEC_BUSY); 2348c2ecf20Sopenharmony_ci for_each_set_bit(i, bmap.bits, bmap.size) 2358c2ecf20Sopenharmony_ci if (reg & (1ull << i)) { 2368c2ecf20Sopenharmony_ci busy = 1; 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci } while (busy); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* Disable the cores only if they are not used anymore */ 2428c2ecf20Sopenharmony_ci reg = readq(cpt->reg_base + OTX_CPT_PF_EXE_CTL); 2438c2ecf20Sopenharmony_ci for_each_set_bit(i, bmap.bits, bmap.size) 2448c2ecf20Sopenharmony_ci if (!eng_grp->g->eng_ref_cnt[i]) 2458c2ecf20Sopenharmony_ci reg &= ~(1ull << i); 2468c2ecf20Sopenharmony_ci writeq(reg, cpt->reg_base + OTX_CPT_PF_EXE_CTL); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int cpt_attach_and_enable_cores(struct otx_cpt_eng_grp_info *eng_grp, 2528c2ecf20Sopenharmony_ci void *obj) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct otx_cpt_device *cpt = (struct otx_cpt_device *) obj; 2558c2ecf20Sopenharmony_ci struct otx_cpt_bitmap bmap; 2568c2ecf20Sopenharmony_ci u64 reg; 2578c2ecf20Sopenharmony_ci int i; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci bmap = get_cores_bmap(&cpt->pdev->dev, eng_grp); 2608c2ecf20Sopenharmony_ci if (!bmap.size) 2618c2ecf20Sopenharmony_ci return -EINVAL; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Attach the cores to the group */ 2648c2ecf20Sopenharmony_ci reg = readq(cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx)); 2658c2ecf20Sopenharmony_ci for_each_set_bit(i, bmap.bits, bmap.size) { 2668c2ecf20Sopenharmony_ci if (!(reg & (1ull << i))) { 2678c2ecf20Sopenharmony_ci eng_grp->g->eng_ref_cnt[i]++; 2688c2ecf20Sopenharmony_ci reg |= 1ull << i; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci writeq(reg, cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx)); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* Enable the cores */ 2748c2ecf20Sopenharmony_ci reg = readq(cpt->reg_base + OTX_CPT_PF_EXE_CTL); 2758c2ecf20Sopenharmony_ci for_each_set_bit(i, bmap.bits, bmap.size) 2768c2ecf20Sopenharmony_ci reg |= 1ull << i; 2778c2ecf20Sopenharmony_ci writeq(reg, cpt->reg_base + OTX_CPT_PF_EXE_CTL); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int process_tar_file(struct device *dev, 2838c2ecf20Sopenharmony_ci struct tar_arch_info_t *tar_arch, char *filename, 2848c2ecf20Sopenharmony_ci const u8 *data, u32 size) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct tar_ucode_info_t *tar_info; 2878c2ecf20Sopenharmony_ci struct otx_cpt_ucode_hdr *ucode_hdr; 2888c2ecf20Sopenharmony_ci int ucode_type, ucode_size; 2898c2ecf20Sopenharmony_ci unsigned int code_length; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* 2928c2ecf20Sopenharmony_ci * If size is less than microcode header size then don't report 2938c2ecf20Sopenharmony_ci * an error because it might not be microcode file, just process 2948c2ecf20Sopenharmony_ci * next file from archive 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci if (size < sizeof(struct otx_cpt_ucode_hdr)) 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ucode_hdr = (struct otx_cpt_ucode_hdr *) data; 3008c2ecf20Sopenharmony_ci /* 3018c2ecf20Sopenharmony_ci * If microcode version can't be found don't report an error 3028c2ecf20Sopenharmony_ci * because it might not be microcode file, just process next file 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci if (get_ucode_type(ucode_hdr, &ucode_type)) 3058c2ecf20Sopenharmony_ci return 0; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci code_length = ntohl(ucode_hdr->code_length); 3088c2ecf20Sopenharmony_ci if (code_length >= INT_MAX / 2) { 3098c2ecf20Sopenharmony_ci dev_err(dev, "Invalid code_length %u\n", code_length); 3108c2ecf20Sopenharmony_ci return -EINVAL; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci ucode_size = code_length * 2; 3148c2ecf20Sopenharmony_ci if (!ucode_size || (size < round_up(ucode_size, 16) + 3158c2ecf20Sopenharmony_ci sizeof(struct otx_cpt_ucode_hdr) + OTX_CPT_UCODE_SIGN_LEN)) { 3168c2ecf20Sopenharmony_ci dev_err(dev, "Ucode %s invalid size\n", filename); 3178c2ecf20Sopenharmony_ci return -EINVAL; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci tar_info = kzalloc(sizeof(struct tar_ucode_info_t), GFP_KERNEL); 3218c2ecf20Sopenharmony_ci if (!tar_info) 3228c2ecf20Sopenharmony_ci return -ENOMEM; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci tar_info->ucode_ptr = data; 3258c2ecf20Sopenharmony_ci set_ucode_filename(&tar_info->ucode, filename); 3268c2ecf20Sopenharmony_ci memcpy(tar_info->ucode.ver_str, ucode_hdr->ver_str, 3278c2ecf20Sopenharmony_ci OTX_CPT_UCODE_VER_STR_SZ); 3288c2ecf20Sopenharmony_ci tar_info->ucode.ver_num = ucode_hdr->ver_num; 3298c2ecf20Sopenharmony_ci tar_info->ucode.type = ucode_type; 3308c2ecf20Sopenharmony_ci tar_info->ucode.size = ucode_size; 3318c2ecf20Sopenharmony_ci list_add_tail(&tar_info->list, &tar_arch->ucodes); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic void release_tar_archive(struct tar_arch_info_t *tar_arch) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct tar_ucode_info_t *curr, *temp; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (!tar_arch) 3418c2ecf20Sopenharmony_ci return; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci list_for_each_entry_safe(curr, temp, &tar_arch->ucodes, list) { 3448c2ecf20Sopenharmony_ci list_del(&curr->list); 3458c2ecf20Sopenharmony_ci kfree(curr); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (tar_arch->fw) 3498c2ecf20Sopenharmony_ci release_firmware(tar_arch->fw); 3508c2ecf20Sopenharmony_ci kfree(tar_arch); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic struct tar_ucode_info_t *get_uc_from_tar_archive( 3548c2ecf20Sopenharmony_ci struct tar_arch_info_t *tar_arch, 3558c2ecf20Sopenharmony_ci int ucode_type) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct tar_ucode_info_t *curr, *uc_found = NULL; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci list_for_each_entry(curr, &tar_arch->ucodes, list) { 3608c2ecf20Sopenharmony_ci if (!is_eng_type(curr->ucode.type, ucode_type)) 3618c2ecf20Sopenharmony_ci continue; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (!uc_found) { 3648c2ecf20Sopenharmony_ci uc_found = curr; 3658c2ecf20Sopenharmony_ci continue; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci switch (ucode_type) { 3698c2ecf20Sopenharmony_ci case OTX_CPT_AE_TYPES: 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci case OTX_CPT_SE_TYPES: 3738c2ecf20Sopenharmony_ci if (uc_found->ucode.ver_num.nn == OTX_CPT_SE_UC_TYPE2 || 3748c2ecf20Sopenharmony_ci (uc_found->ucode.ver_num.nn == OTX_CPT_SE_UC_TYPE3 3758c2ecf20Sopenharmony_ci && curr->ucode.ver_num.nn == OTX_CPT_SE_UC_TYPE1)) 3768c2ecf20Sopenharmony_ci uc_found = curr; 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return uc_found; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic void print_tar_dbg_info(struct tar_arch_info_t *tar_arch, 3858c2ecf20Sopenharmony_ci char *tar_filename) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct tar_ucode_info_t *curr; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci pr_debug("Tar archive filename %s\n", tar_filename); 3908c2ecf20Sopenharmony_ci pr_debug("Tar archive pointer %p, size %ld\n", tar_arch->fw->data, 3918c2ecf20Sopenharmony_ci tar_arch->fw->size); 3928c2ecf20Sopenharmony_ci list_for_each_entry(curr, &tar_arch->ucodes, list) { 3938c2ecf20Sopenharmony_ci pr_debug("Ucode filename %s\n", curr->ucode.filename); 3948c2ecf20Sopenharmony_ci pr_debug("Ucode version string %s\n", curr->ucode.ver_str); 3958c2ecf20Sopenharmony_ci pr_debug("Ucode version %d.%d.%d.%d\n", 3968c2ecf20Sopenharmony_ci curr->ucode.ver_num.nn, curr->ucode.ver_num.xx, 3978c2ecf20Sopenharmony_ci curr->ucode.ver_num.yy, curr->ucode.ver_num.zz); 3988c2ecf20Sopenharmony_ci pr_debug("Ucode type (%d) %s\n", curr->ucode.type, 3998c2ecf20Sopenharmony_ci get_ucode_type_str(curr->ucode.type)); 4008c2ecf20Sopenharmony_ci pr_debug("Ucode size %d\n", curr->ucode.size); 4018c2ecf20Sopenharmony_ci pr_debug("Ucode ptr %p\n", curr->ucode_ptr); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic struct tar_arch_info_t *load_tar_archive(struct device *dev, 4068c2ecf20Sopenharmony_ci char *tar_filename) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct tar_arch_info_t *tar_arch = NULL; 4098c2ecf20Sopenharmony_ci struct tar_blk_t *tar_blk; 4108c2ecf20Sopenharmony_ci unsigned int cur_size; 4118c2ecf20Sopenharmony_ci size_t tar_offs = 0; 4128c2ecf20Sopenharmony_ci size_t tar_size; 4138c2ecf20Sopenharmony_ci int ret; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci tar_arch = kzalloc(sizeof(struct tar_arch_info_t), GFP_KERNEL); 4168c2ecf20Sopenharmony_ci if (!tar_arch) 4178c2ecf20Sopenharmony_ci return NULL; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tar_arch->ucodes); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* Load tar archive */ 4228c2ecf20Sopenharmony_ci ret = request_firmware(&tar_arch->fw, tar_filename, dev); 4238c2ecf20Sopenharmony_ci if (ret) 4248c2ecf20Sopenharmony_ci goto release_tar_arch; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (tar_arch->fw->size < TAR_BLOCK_LEN) { 4278c2ecf20Sopenharmony_ci dev_err(dev, "Invalid tar archive %s\n", tar_filename); 4288c2ecf20Sopenharmony_ci goto release_tar_arch; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci tar_size = tar_arch->fw->size; 4328c2ecf20Sopenharmony_ci tar_blk = (struct tar_blk_t *) tar_arch->fw->data; 4338c2ecf20Sopenharmony_ci if (strncmp(tar_blk->hdr.magic, TAR_MAGIC, TAR_MAGIC_LEN - 1)) { 4348c2ecf20Sopenharmony_ci dev_err(dev, "Unsupported format of tar archive %s\n", 4358c2ecf20Sopenharmony_ci tar_filename); 4368c2ecf20Sopenharmony_ci goto release_tar_arch; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci while (1) { 4408c2ecf20Sopenharmony_ci /* Read current file size */ 4418c2ecf20Sopenharmony_ci ret = kstrtouint(tar_blk->hdr.size, 8, &cur_size); 4428c2ecf20Sopenharmony_ci if (ret) 4438c2ecf20Sopenharmony_ci goto release_tar_arch; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (tar_offs + cur_size > tar_size || 4468c2ecf20Sopenharmony_ci tar_offs + 2*TAR_BLOCK_LEN > tar_size) { 4478c2ecf20Sopenharmony_ci dev_err(dev, "Invalid tar archive %s\n", tar_filename); 4488c2ecf20Sopenharmony_ci goto release_tar_arch; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci tar_offs += TAR_BLOCK_LEN; 4528c2ecf20Sopenharmony_ci if (tar_blk->hdr.typeflag == REGTYPE || 4538c2ecf20Sopenharmony_ci tar_blk->hdr.typeflag == AREGTYPE) { 4548c2ecf20Sopenharmony_ci ret = process_tar_file(dev, tar_arch, 4558c2ecf20Sopenharmony_ci tar_blk->hdr.name, 4568c2ecf20Sopenharmony_ci &tar_arch->fw->data[tar_offs], 4578c2ecf20Sopenharmony_ci cur_size); 4588c2ecf20Sopenharmony_ci if (ret) 4598c2ecf20Sopenharmony_ci goto release_tar_arch; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci tar_offs += (cur_size/TAR_BLOCK_LEN) * TAR_BLOCK_LEN; 4638c2ecf20Sopenharmony_ci if (cur_size % TAR_BLOCK_LEN) 4648c2ecf20Sopenharmony_ci tar_offs += TAR_BLOCK_LEN; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* Check for the end of the archive */ 4678c2ecf20Sopenharmony_ci if (tar_offs + 2*TAR_BLOCK_LEN > tar_size) { 4688c2ecf20Sopenharmony_ci dev_err(dev, "Invalid tar archive %s\n", tar_filename); 4698c2ecf20Sopenharmony_ci goto release_tar_arch; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (is_mem_zero(&tar_arch->fw->data[tar_offs], 4738c2ecf20Sopenharmony_ci 2*TAR_BLOCK_LEN)) 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Read next block from tar archive */ 4778c2ecf20Sopenharmony_ci tar_blk = (struct tar_blk_t *) &tar_arch->fw->data[tar_offs]; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci print_tar_dbg_info(tar_arch, tar_filename); 4818c2ecf20Sopenharmony_ci return tar_arch; 4828c2ecf20Sopenharmony_cirelease_tar_arch: 4838c2ecf20Sopenharmony_ci release_tar_archive(tar_arch); 4848c2ecf20Sopenharmony_ci return NULL; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic struct otx_cpt_engs_rsvd *find_engines_by_type( 4888c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *eng_grp, 4898c2ecf20Sopenharmony_ci int eng_type) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci int i; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) { 4948c2ecf20Sopenharmony_ci if (!eng_grp->engs[i].type) 4958c2ecf20Sopenharmony_ci continue; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (eng_grp->engs[i].type == eng_type) 4988c2ecf20Sopenharmony_ci return &eng_grp->engs[i]; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci return NULL; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ciint otx_cpt_uc_supports_eng_type(struct otx_cpt_ucode *ucode, int eng_type) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci return is_eng_type(ucode->type, eng_type); 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(otx_cpt_uc_supports_eng_type); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ciint otx_cpt_eng_grp_has_eng_type(struct otx_cpt_eng_grp_info *eng_grp, 5108c2ecf20Sopenharmony_ci int eng_type) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct otx_cpt_engs_rsvd *engs; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci engs = find_engines_by_type(eng_grp, eng_type); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return (engs != NULL ? 1 : 0); 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(otx_cpt_eng_grp_has_eng_type); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic void print_ucode_info(struct otx_cpt_eng_grp_info *eng_grp, 5218c2ecf20Sopenharmony_ci char *buf, int size) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci if (eng_grp->mirror.is_ena) { 5248c2ecf20Sopenharmony_ci scnprintf(buf, size, "%s (shared with engine_group%d)", 5258c2ecf20Sopenharmony_ci eng_grp->g->grp[eng_grp->mirror.idx].ucode[0].ver_str, 5268c2ecf20Sopenharmony_ci eng_grp->mirror.idx); 5278c2ecf20Sopenharmony_ci } else { 5288c2ecf20Sopenharmony_ci scnprintf(buf, size, "%s", eng_grp->ucode[0].ver_str); 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic void print_engs_info(struct otx_cpt_eng_grp_info *eng_grp, 5338c2ecf20Sopenharmony_ci char *buf, int size, int idx) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci struct otx_cpt_engs_rsvd *mirrored_engs = NULL; 5368c2ecf20Sopenharmony_ci struct otx_cpt_engs_rsvd *engs; 5378c2ecf20Sopenharmony_ci int len, i; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci buf[0] = '\0'; 5408c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) { 5418c2ecf20Sopenharmony_ci engs = &eng_grp->engs[i]; 5428c2ecf20Sopenharmony_ci if (!engs->type) 5438c2ecf20Sopenharmony_ci continue; 5448c2ecf20Sopenharmony_ci if (idx != -1 && idx != i) 5458c2ecf20Sopenharmony_ci continue; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (eng_grp->mirror.is_ena) 5488c2ecf20Sopenharmony_ci mirrored_engs = find_engines_by_type( 5498c2ecf20Sopenharmony_ci &eng_grp->g->grp[eng_grp->mirror.idx], 5508c2ecf20Sopenharmony_ci engs->type); 5518c2ecf20Sopenharmony_ci if (i > 0 && idx == -1) { 5528c2ecf20Sopenharmony_ci len = strlen(buf); 5538c2ecf20Sopenharmony_ci scnprintf(buf+len, size-len, ", "); 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci len = strlen(buf); 5578c2ecf20Sopenharmony_ci scnprintf(buf+len, size-len, "%d %s ", mirrored_engs ? 5588c2ecf20Sopenharmony_ci engs->count + mirrored_engs->count : engs->count, 5598c2ecf20Sopenharmony_ci get_eng_type_str(engs->type)); 5608c2ecf20Sopenharmony_ci if (mirrored_engs) { 5618c2ecf20Sopenharmony_ci len = strlen(buf); 5628c2ecf20Sopenharmony_ci scnprintf(buf+len, size-len, 5638c2ecf20Sopenharmony_ci "(%d shared with engine_group%d) ", 5648c2ecf20Sopenharmony_ci engs->count <= 0 ? engs->count + 5658c2ecf20Sopenharmony_ci mirrored_engs->count : mirrored_engs->count, 5668c2ecf20Sopenharmony_ci eng_grp->mirror.idx); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic void print_ucode_dbg_info(struct otx_cpt_ucode *ucode) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci pr_debug("Ucode info\n"); 5748c2ecf20Sopenharmony_ci pr_debug("Ucode version string %s\n", ucode->ver_str); 5758c2ecf20Sopenharmony_ci pr_debug("Ucode version %d.%d.%d.%d\n", ucode->ver_num.nn, 5768c2ecf20Sopenharmony_ci ucode->ver_num.xx, ucode->ver_num.yy, ucode->ver_num.zz); 5778c2ecf20Sopenharmony_ci pr_debug("Ucode type %s\n", get_ucode_type_str(ucode->type)); 5788c2ecf20Sopenharmony_ci pr_debug("Ucode size %d\n", ucode->size); 5798c2ecf20Sopenharmony_ci pr_debug("Ucode virt address %16.16llx\n", (u64)ucode->align_va); 5808c2ecf20Sopenharmony_ci pr_debug("Ucode phys address %16.16llx\n", ucode->align_dma); 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic void cpt_print_engines_mask(struct otx_cpt_eng_grp_info *eng_grp, 5848c2ecf20Sopenharmony_ci struct device *dev, char *buf, int size) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct otx_cpt_bitmap bmap; 5878c2ecf20Sopenharmony_ci u32 mask[2]; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci bmap = get_cores_bmap(dev, eng_grp); 5908c2ecf20Sopenharmony_ci if (!bmap.size) { 5918c2ecf20Sopenharmony_ci scnprintf(buf, size, "unknown"); 5928c2ecf20Sopenharmony_ci return; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci bitmap_to_arr32(mask, bmap.bits, bmap.size); 5958c2ecf20Sopenharmony_ci scnprintf(buf, size, "%8.8x %8.8x", mask[1], mask[0]); 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic void print_dbg_info(struct device *dev, 6008c2ecf20Sopenharmony_ci struct otx_cpt_eng_grps *eng_grps) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci char engs_info[2*OTX_CPT_UCODE_NAME_LENGTH]; 6038c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *mirrored_grp; 6048c2ecf20Sopenharmony_ci char engs_mask[OTX_CPT_UCODE_NAME_LENGTH]; 6058c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *grp; 6068c2ecf20Sopenharmony_ci struct otx_cpt_engs_rsvd *engs; 6078c2ecf20Sopenharmony_ci u32 mask[4]; 6088c2ecf20Sopenharmony_ci int i, j; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci pr_debug("Engine groups global info\n"); 6118c2ecf20Sopenharmony_ci pr_debug("max SE %d, max AE %d\n", 6128c2ecf20Sopenharmony_ci eng_grps->avail.max_se_cnt, eng_grps->avail.max_ae_cnt); 6138c2ecf20Sopenharmony_ci pr_debug("free SE %d\n", eng_grps->avail.se_cnt); 6148c2ecf20Sopenharmony_ci pr_debug("free AE %d\n", eng_grps->avail.ae_cnt); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) { 6178c2ecf20Sopenharmony_ci grp = &eng_grps->grp[i]; 6188c2ecf20Sopenharmony_ci pr_debug("engine_group%d, state %s\n", i, grp->is_enabled ? 6198c2ecf20Sopenharmony_ci "enabled" : "disabled"); 6208c2ecf20Sopenharmony_ci if (grp->is_enabled) { 6218c2ecf20Sopenharmony_ci mirrored_grp = &eng_grps->grp[grp->mirror.idx]; 6228c2ecf20Sopenharmony_ci pr_debug("Ucode0 filename %s, version %s\n", 6238c2ecf20Sopenharmony_ci grp->mirror.is_ena ? 6248c2ecf20Sopenharmony_ci mirrored_grp->ucode[0].filename : 6258c2ecf20Sopenharmony_ci grp->ucode[0].filename, 6268c2ecf20Sopenharmony_ci grp->mirror.is_ena ? 6278c2ecf20Sopenharmony_ci mirrored_grp->ucode[0].ver_str : 6288c2ecf20Sopenharmony_ci grp->ucode[0].ver_str); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci for (j = 0; j < OTX_CPT_MAX_ETYPES_PER_GRP; j++) { 6328c2ecf20Sopenharmony_ci engs = &grp->engs[j]; 6338c2ecf20Sopenharmony_ci if (engs->type) { 6348c2ecf20Sopenharmony_ci print_engs_info(grp, engs_info, 6358c2ecf20Sopenharmony_ci 2*OTX_CPT_UCODE_NAME_LENGTH, j); 6368c2ecf20Sopenharmony_ci pr_debug("Slot%d: %s\n", j, engs_info); 6378c2ecf20Sopenharmony_ci bitmap_to_arr32(mask, engs->bmap, 6388c2ecf20Sopenharmony_ci eng_grps->engs_num); 6398c2ecf20Sopenharmony_ci pr_debug("Mask: %8.8x %8.8x %8.8x %8.8x\n", 6408c2ecf20Sopenharmony_ci mask[3], mask[2], mask[1], mask[0]); 6418c2ecf20Sopenharmony_ci } else 6428c2ecf20Sopenharmony_ci pr_debug("Slot%d not used\n", j); 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci if (grp->is_enabled) { 6458c2ecf20Sopenharmony_ci cpt_print_engines_mask(grp, dev, engs_mask, 6468c2ecf20Sopenharmony_ci OTX_CPT_UCODE_NAME_LENGTH); 6478c2ecf20Sopenharmony_ci pr_debug("Cmask: %s\n", engs_mask); 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic int update_engines_avail_count(struct device *dev, 6538c2ecf20Sopenharmony_ci struct otx_cpt_engs_available *avail, 6548c2ecf20Sopenharmony_ci struct otx_cpt_engs_rsvd *engs, int val) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci switch (engs->type) { 6578c2ecf20Sopenharmony_ci case OTX_CPT_SE_TYPES: 6588c2ecf20Sopenharmony_ci avail->se_cnt += val; 6598c2ecf20Sopenharmony_ci break; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci case OTX_CPT_AE_TYPES: 6628c2ecf20Sopenharmony_ci avail->ae_cnt += val; 6638c2ecf20Sopenharmony_ci break; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci default: 6668c2ecf20Sopenharmony_ci dev_err(dev, "Invalid engine type %d\n", engs->type); 6678c2ecf20Sopenharmony_ci return -EINVAL; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci return 0; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic int update_engines_offset(struct device *dev, 6748c2ecf20Sopenharmony_ci struct otx_cpt_engs_available *avail, 6758c2ecf20Sopenharmony_ci struct otx_cpt_engs_rsvd *engs) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci switch (engs->type) { 6788c2ecf20Sopenharmony_ci case OTX_CPT_SE_TYPES: 6798c2ecf20Sopenharmony_ci engs->offset = 0; 6808c2ecf20Sopenharmony_ci break; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci case OTX_CPT_AE_TYPES: 6838c2ecf20Sopenharmony_ci engs->offset = avail->max_se_cnt; 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci default: 6878c2ecf20Sopenharmony_ci dev_err(dev, "Invalid engine type %d\n", engs->type); 6888c2ecf20Sopenharmony_ci return -EINVAL; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci return 0; 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic int release_engines(struct device *dev, struct otx_cpt_eng_grp_info *grp) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci int i, ret = 0; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) { 6998c2ecf20Sopenharmony_ci if (!grp->engs[i].type) 7008c2ecf20Sopenharmony_ci continue; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (grp->engs[i].count > 0) { 7038c2ecf20Sopenharmony_ci ret = update_engines_avail_count(dev, &grp->g->avail, 7048c2ecf20Sopenharmony_ci &grp->engs[i], 7058c2ecf20Sopenharmony_ci grp->engs[i].count); 7068c2ecf20Sopenharmony_ci if (ret) 7078c2ecf20Sopenharmony_ci return ret; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci grp->engs[i].type = 0; 7118c2ecf20Sopenharmony_ci grp->engs[i].count = 0; 7128c2ecf20Sopenharmony_ci grp->engs[i].offset = 0; 7138c2ecf20Sopenharmony_ci grp->engs[i].ucode = NULL; 7148c2ecf20Sopenharmony_ci bitmap_zero(grp->engs[i].bmap, grp->g->engs_num); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci return 0; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic int do_reserve_engines(struct device *dev, 7218c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *grp, 7228c2ecf20Sopenharmony_ci struct otx_cpt_engines *req_engs) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct otx_cpt_engs_rsvd *engs = NULL; 7258c2ecf20Sopenharmony_ci int i, ret; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) { 7288c2ecf20Sopenharmony_ci if (!grp->engs[i].type) { 7298c2ecf20Sopenharmony_ci engs = &grp->engs[i]; 7308c2ecf20Sopenharmony_ci break; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (!engs) 7358c2ecf20Sopenharmony_ci return -ENOMEM; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci engs->type = req_engs->type; 7388c2ecf20Sopenharmony_ci engs->count = req_engs->count; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci ret = update_engines_offset(dev, &grp->g->avail, engs); 7418c2ecf20Sopenharmony_ci if (ret) 7428c2ecf20Sopenharmony_ci return ret; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (engs->count > 0) { 7458c2ecf20Sopenharmony_ci ret = update_engines_avail_count(dev, &grp->g->avail, engs, 7468c2ecf20Sopenharmony_ci -engs->count); 7478c2ecf20Sopenharmony_ci if (ret) 7488c2ecf20Sopenharmony_ci return ret; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return 0; 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic int check_engines_availability(struct device *dev, 7558c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *grp, 7568c2ecf20Sopenharmony_ci struct otx_cpt_engines *req_eng) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci int avail_cnt = 0; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci switch (req_eng->type) { 7618c2ecf20Sopenharmony_ci case OTX_CPT_SE_TYPES: 7628c2ecf20Sopenharmony_ci avail_cnt = grp->g->avail.se_cnt; 7638c2ecf20Sopenharmony_ci break; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci case OTX_CPT_AE_TYPES: 7668c2ecf20Sopenharmony_ci avail_cnt = grp->g->avail.ae_cnt; 7678c2ecf20Sopenharmony_ci break; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci default: 7708c2ecf20Sopenharmony_ci dev_err(dev, "Invalid engine type %d\n", req_eng->type); 7718c2ecf20Sopenharmony_ci return -EINVAL; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (avail_cnt < req_eng->count) { 7758c2ecf20Sopenharmony_ci dev_err(dev, 7768c2ecf20Sopenharmony_ci "Error available %s engines %d < than requested %d\n", 7778c2ecf20Sopenharmony_ci get_eng_type_str(req_eng->type), 7788c2ecf20Sopenharmony_ci avail_cnt, req_eng->count); 7798c2ecf20Sopenharmony_ci return -EBUSY; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic int reserve_engines(struct device *dev, struct otx_cpt_eng_grp_info *grp, 7868c2ecf20Sopenharmony_ci struct otx_cpt_engines *req_engs, int req_cnt) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci int i, ret; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci /* Validate if a number of requested engines is available */ 7918c2ecf20Sopenharmony_ci for (i = 0; i < req_cnt; i++) { 7928c2ecf20Sopenharmony_ci ret = check_engines_availability(dev, grp, &req_engs[i]); 7938c2ecf20Sopenharmony_ci if (ret) 7948c2ecf20Sopenharmony_ci return ret; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci /* Reserve requested engines for this engine group */ 7988c2ecf20Sopenharmony_ci for (i = 0; i < req_cnt; i++) { 7998c2ecf20Sopenharmony_ci ret = do_reserve_engines(dev, grp, &req_engs[i]); 8008c2ecf20Sopenharmony_ci if (ret) 8018c2ecf20Sopenharmony_ci return ret; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci return 0; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic ssize_t eng_grp_info_show(struct device *dev, 8078c2ecf20Sopenharmony_ci struct device_attribute *attr, 8088c2ecf20Sopenharmony_ci char *buf) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci char ucode_info[2*OTX_CPT_UCODE_NAME_LENGTH]; 8118c2ecf20Sopenharmony_ci char engs_info[2*OTX_CPT_UCODE_NAME_LENGTH]; 8128c2ecf20Sopenharmony_ci char engs_mask[OTX_CPT_UCODE_NAME_LENGTH]; 8138c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *eng_grp; 8148c2ecf20Sopenharmony_ci int ret; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci eng_grp = container_of(attr, struct otx_cpt_eng_grp_info, info_attr); 8178c2ecf20Sopenharmony_ci mutex_lock(&eng_grp->g->lock); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci print_engs_info(eng_grp, engs_info, 2*OTX_CPT_UCODE_NAME_LENGTH, -1); 8208c2ecf20Sopenharmony_ci print_ucode_info(eng_grp, ucode_info, 2*OTX_CPT_UCODE_NAME_LENGTH); 8218c2ecf20Sopenharmony_ci cpt_print_engines_mask(eng_grp, dev, engs_mask, 8228c2ecf20Sopenharmony_ci OTX_CPT_UCODE_NAME_LENGTH); 8238c2ecf20Sopenharmony_ci ret = scnprintf(buf, PAGE_SIZE, 8248c2ecf20Sopenharmony_ci "Microcode : %s\nEngines: %s\nEngines mask: %s\n", 8258c2ecf20Sopenharmony_ci ucode_info, engs_info, engs_mask); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci mutex_unlock(&eng_grp->g->lock); 8288c2ecf20Sopenharmony_ci return ret; 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic int create_sysfs_eng_grps_info(struct device *dev, 8328c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *eng_grp) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci eng_grp->info_attr.show = eng_grp_info_show; 8358c2ecf20Sopenharmony_ci eng_grp->info_attr.store = NULL; 8368c2ecf20Sopenharmony_ci eng_grp->info_attr.attr.name = eng_grp->sysfs_info_name; 8378c2ecf20Sopenharmony_ci eng_grp->info_attr.attr.mode = 0440; 8388c2ecf20Sopenharmony_ci sysfs_attr_init(&eng_grp->info_attr.attr); 8398c2ecf20Sopenharmony_ci return device_create_file(dev, &eng_grp->info_attr); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic void ucode_unload(struct device *dev, struct otx_cpt_ucode *ucode) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci if (ucode->va) { 8458c2ecf20Sopenharmony_ci dma_free_coherent(dev, ucode->size + OTX_CPT_UCODE_ALIGNMENT, 8468c2ecf20Sopenharmony_ci ucode->va, ucode->dma); 8478c2ecf20Sopenharmony_ci ucode->va = NULL; 8488c2ecf20Sopenharmony_ci ucode->align_va = NULL; 8498c2ecf20Sopenharmony_ci ucode->dma = 0; 8508c2ecf20Sopenharmony_ci ucode->align_dma = 0; 8518c2ecf20Sopenharmony_ci ucode->size = 0; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci memset(&ucode->ver_str, 0, OTX_CPT_UCODE_VER_STR_SZ); 8558c2ecf20Sopenharmony_ci memset(&ucode->ver_num, 0, sizeof(struct otx_cpt_ucode_ver_num)); 8568c2ecf20Sopenharmony_ci set_ucode_filename(ucode, ""); 8578c2ecf20Sopenharmony_ci ucode->type = 0; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic int copy_ucode_to_dma_mem(struct device *dev, 8618c2ecf20Sopenharmony_ci struct otx_cpt_ucode *ucode, 8628c2ecf20Sopenharmony_ci const u8 *ucode_data) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci u32 i; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* Allocate DMAable space */ 8678c2ecf20Sopenharmony_ci ucode->va = dma_alloc_coherent(dev, ucode->size + 8688c2ecf20Sopenharmony_ci OTX_CPT_UCODE_ALIGNMENT, 8698c2ecf20Sopenharmony_ci &ucode->dma, GFP_KERNEL); 8708c2ecf20Sopenharmony_ci if (!ucode->va) { 8718c2ecf20Sopenharmony_ci dev_err(dev, "Unable to allocate space for microcode\n"); 8728c2ecf20Sopenharmony_ci return -ENOMEM; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci ucode->align_va = PTR_ALIGN(ucode->va, OTX_CPT_UCODE_ALIGNMENT); 8758c2ecf20Sopenharmony_ci ucode->align_dma = PTR_ALIGN(ucode->dma, OTX_CPT_UCODE_ALIGNMENT); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci memcpy((void *) ucode->align_va, (void *) ucode_data + 8788c2ecf20Sopenharmony_ci sizeof(struct otx_cpt_ucode_hdr), ucode->size); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci /* Byte swap 64-bit */ 8818c2ecf20Sopenharmony_ci for (i = 0; i < (ucode->size / 8); i++) 8828c2ecf20Sopenharmony_ci ((__be64 *)ucode->align_va)[i] = 8838c2ecf20Sopenharmony_ci cpu_to_be64(((u64 *)ucode->align_va)[i]); 8848c2ecf20Sopenharmony_ci /* Ucode needs 16-bit swap */ 8858c2ecf20Sopenharmony_ci for (i = 0; i < (ucode->size / 2); i++) 8868c2ecf20Sopenharmony_ci ((__be16 *)ucode->align_va)[i] = 8878c2ecf20Sopenharmony_ci cpu_to_be16(((u16 *)ucode->align_va)[i]); 8888c2ecf20Sopenharmony_ci return 0; 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic int ucode_load(struct device *dev, struct otx_cpt_ucode *ucode, 8928c2ecf20Sopenharmony_ci const char *ucode_filename) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci struct otx_cpt_ucode_hdr *ucode_hdr; 8958c2ecf20Sopenharmony_ci const struct firmware *fw; 8968c2ecf20Sopenharmony_ci unsigned int code_length; 8978c2ecf20Sopenharmony_ci int ret; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci set_ucode_filename(ucode, ucode_filename); 9008c2ecf20Sopenharmony_ci ret = request_firmware(&fw, ucode->filename, dev); 9018c2ecf20Sopenharmony_ci if (ret) 9028c2ecf20Sopenharmony_ci return ret; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci ucode_hdr = (struct otx_cpt_ucode_hdr *) fw->data; 9058c2ecf20Sopenharmony_ci memcpy(ucode->ver_str, ucode_hdr->ver_str, OTX_CPT_UCODE_VER_STR_SZ); 9068c2ecf20Sopenharmony_ci ucode->ver_num = ucode_hdr->ver_num; 9078c2ecf20Sopenharmony_ci code_length = ntohl(ucode_hdr->code_length); 9088c2ecf20Sopenharmony_ci if (code_length >= INT_MAX / 2) { 9098c2ecf20Sopenharmony_ci dev_err(dev, "Ucode invalid code_length %u\n", code_length); 9108c2ecf20Sopenharmony_ci ret = -EINVAL; 9118c2ecf20Sopenharmony_ci goto release_fw; 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci ucode->size = code_length * 2; 9148c2ecf20Sopenharmony_ci if (!ucode->size || (fw->size < round_up(ucode->size, 16) 9158c2ecf20Sopenharmony_ci + sizeof(struct otx_cpt_ucode_hdr) + OTX_CPT_UCODE_SIGN_LEN)) { 9168c2ecf20Sopenharmony_ci dev_err(dev, "Ucode %s invalid size\n", ucode_filename); 9178c2ecf20Sopenharmony_ci ret = -EINVAL; 9188c2ecf20Sopenharmony_ci goto release_fw; 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci ret = get_ucode_type(ucode_hdr, &ucode->type); 9228c2ecf20Sopenharmony_ci if (ret) { 9238c2ecf20Sopenharmony_ci dev_err(dev, "Microcode %s unknown type 0x%x\n", 9248c2ecf20Sopenharmony_ci ucode->filename, ucode->type); 9258c2ecf20Sopenharmony_ci goto release_fw; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci ret = copy_ucode_to_dma_mem(dev, ucode, fw->data); 9298c2ecf20Sopenharmony_ci if (ret) 9308c2ecf20Sopenharmony_ci goto release_fw; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci print_ucode_dbg_info(ucode); 9338c2ecf20Sopenharmony_cirelease_fw: 9348c2ecf20Sopenharmony_ci release_firmware(fw); 9358c2ecf20Sopenharmony_ci return ret; 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic int enable_eng_grp(struct otx_cpt_eng_grp_info *eng_grp, 9398c2ecf20Sopenharmony_ci void *obj) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci int ret; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci ret = cpt_set_ucode_base(eng_grp, obj); 9448c2ecf20Sopenharmony_ci if (ret) 9458c2ecf20Sopenharmony_ci return ret; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci ret = cpt_attach_and_enable_cores(eng_grp, obj); 9488c2ecf20Sopenharmony_ci return ret; 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic int disable_eng_grp(struct device *dev, 9528c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *eng_grp, 9538c2ecf20Sopenharmony_ci void *obj) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci int i, ret; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci ret = cpt_detach_and_disable_cores(eng_grp, obj); 9588c2ecf20Sopenharmony_ci if (ret) 9598c2ecf20Sopenharmony_ci return ret; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* Unload ucode used by this engine group */ 9628c2ecf20Sopenharmony_ci ucode_unload(dev, &eng_grp->ucode[0]); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) { 9658c2ecf20Sopenharmony_ci if (!eng_grp->engs[i].type) 9668c2ecf20Sopenharmony_ci continue; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci eng_grp->engs[i].ucode = &eng_grp->ucode[0]; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci ret = cpt_set_ucode_base(eng_grp, obj); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci return ret; 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic void setup_eng_grp_mirroring(struct otx_cpt_eng_grp_info *dst_grp, 9778c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *src_grp) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci /* Setup fields for engine group which is mirrored */ 9808c2ecf20Sopenharmony_ci src_grp->mirror.is_ena = false; 9818c2ecf20Sopenharmony_ci src_grp->mirror.idx = 0; 9828c2ecf20Sopenharmony_ci src_grp->mirror.ref_count++; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci /* Setup fields for mirroring engine group */ 9858c2ecf20Sopenharmony_ci dst_grp->mirror.is_ena = true; 9868c2ecf20Sopenharmony_ci dst_grp->mirror.idx = src_grp->idx; 9878c2ecf20Sopenharmony_ci dst_grp->mirror.ref_count = 0; 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_cistatic void remove_eng_grp_mirroring(struct otx_cpt_eng_grp_info *dst_grp) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *src_grp; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (!dst_grp->mirror.is_ena) 9958c2ecf20Sopenharmony_ci return; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci src_grp = &dst_grp->g->grp[dst_grp->mirror.idx]; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci src_grp->mirror.ref_count--; 10008c2ecf20Sopenharmony_ci dst_grp->mirror.is_ena = false; 10018c2ecf20Sopenharmony_ci dst_grp->mirror.idx = 0; 10028c2ecf20Sopenharmony_ci dst_grp->mirror.ref_count = 0; 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic void update_requested_engs(struct otx_cpt_eng_grp_info *mirrored_eng_grp, 10068c2ecf20Sopenharmony_ci struct otx_cpt_engines *engs, int engs_cnt) 10078c2ecf20Sopenharmony_ci{ 10088c2ecf20Sopenharmony_ci struct otx_cpt_engs_rsvd *mirrored_engs; 10098c2ecf20Sopenharmony_ci int i; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci for (i = 0; i < engs_cnt; i++) { 10128c2ecf20Sopenharmony_ci mirrored_engs = find_engines_by_type(mirrored_eng_grp, 10138c2ecf20Sopenharmony_ci engs[i].type); 10148c2ecf20Sopenharmony_ci if (!mirrored_engs) 10158c2ecf20Sopenharmony_ci continue; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci /* 10188c2ecf20Sopenharmony_ci * If mirrored group has this type of engines attached then 10198c2ecf20Sopenharmony_ci * there are 3 scenarios possible: 10208c2ecf20Sopenharmony_ci * 1) mirrored_engs.count == engs[i].count then all engines 10218c2ecf20Sopenharmony_ci * from mirrored engine group will be shared with this engine 10228c2ecf20Sopenharmony_ci * group 10238c2ecf20Sopenharmony_ci * 2) mirrored_engs.count > engs[i].count then only a subset of 10248c2ecf20Sopenharmony_ci * engines from mirrored engine group will be shared with this 10258c2ecf20Sopenharmony_ci * engine group 10268c2ecf20Sopenharmony_ci * 3) mirrored_engs.count < engs[i].count then all engines 10278c2ecf20Sopenharmony_ci * from mirrored engine group will be shared with this group 10288c2ecf20Sopenharmony_ci * and additional engines will be reserved for exclusively use 10298c2ecf20Sopenharmony_ci * by this engine group 10308c2ecf20Sopenharmony_ci */ 10318c2ecf20Sopenharmony_ci engs[i].count -= mirrored_engs->count; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic struct otx_cpt_eng_grp_info *find_mirrored_eng_grp( 10368c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *grp) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci struct otx_cpt_eng_grps *eng_grps = grp->g; 10398c2ecf20Sopenharmony_ci int i; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) { 10428c2ecf20Sopenharmony_ci if (!eng_grps->grp[i].is_enabled) 10438c2ecf20Sopenharmony_ci continue; 10448c2ecf20Sopenharmony_ci if (eng_grps->grp[i].ucode[0].type) 10458c2ecf20Sopenharmony_ci continue; 10468c2ecf20Sopenharmony_ci if (grp->idx == i) 10478c2ecf20Sopenharmony_ci continue; 10488c2ecf20Sopenharmony_ci if (!strncasecmp(eng_grps->grp[i].ucode[0].ver_str, 10498c2ecf20Sopenharmony_ci grp->ucode[0].ver_str, 10508c2ecf20Sopenharmony_ci OTX_CPT_UCODE_VER_STR_SZ)) 10518c2ecf20Sopenharmony_ci return &eng_grps->grp[i]; 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return NULL; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic struct otx_cpt_eng_grp_info *find_unused_eng_grp( 10588c2ecf20Sopenharmony_ci struct otx_cpt_eng_grps *eng_grps) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci int i; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) { 10638c2ecf20Sopenharmony_ci if (!eng_grps->grp[i].is_enabled) 10648c2ecf20Sopenharmony_ci return &eng_grps->grp[i]; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci return NULL; 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cistatic int eng_grp_update_masks(struct device *dev, 10708c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *eng_grp) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci struct otx_cpt_engs_rsvd *engs, *mirrored_engs; 10738c2ecf20Sopenharmony_ci struct otx_cpt_bitmap tmp_bmap = { {0} }; 10748c2ecf20Sopenharmony_ci int i, j, cnt, max_cnt; 10758c2ecf20Sopenharmony_ci int bit; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) { 10788c2ecf20Sopenharmony_ci engs = &eng_grp->engs[i]; 10798c2ecf20Sopenharmony_ci if (!engs->type) 10808c2ecf20Sopenharmony_ci continue; 10818c2ecf20Sopenharmony_ci if (engs->count <= 0) 10828c2ecf20Sopenharmony_ci continue; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci switch (engs->type) { 10858c2ecf20Sopenharmony_ci case OTX_CPT_SE_TYPES: 10868c2ecf20Sopenharmony_ci max_cnt = eng_grp->g->avail.max_se_cnt; 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci case OTX_CPT_AE_TYPES: 10908c2ecf20Sopenharmony_ci max_cnt = eng_grp->g->avail.max_ae_cnt; 10918c2ecf20Sopenharmony_ci break; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci default: 10948c2ecf20Sopenharmony_ci dev_err(dev, "Invalid engine type %d\n", engs->type); 10958c2ecf20Sopenharmony_ci return -EINVAL; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci cnt = engs->count; 10998c2ecf20Sopenharmony_ci WARN_ON(engs->offset + max_cnt > OTX_CPT_MAX_ENGINES); 11008c2ecf20Sopenharmony_ci bitmap_zero(tmp_bmap.bits, eng_grp->g->engs_num); 11018c2ecf20Sopenharmony_ci for (j = engs->offset; j < engs->offset + max_cnt; j++) { 11028c2ecf20Sopenharmony_ci if (!eng_grp->g->eng_ref_cnt[j]) { 11038c2ecf20Sopenharmony_ci bitmap_set(tmp_bmap.bits, j, 1); 11048c2ecf20Sopenharmony_ci cnt--; 11058c2ecf20Sopenharmony_ci if (!cnt) 11068c2ecf20Sopenharmony_ci break; 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (cnt) 11118c2ecf20Sopenharmony_ci return -ENOSPC; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci bitmap_copy(engs->bmap, tmp_bmap.bits, eng_grp->g->engs_num); 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (!eng_grp->mirror.is_ena) 11178c2ecf20Sopenharmony_ci return 0; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) { 11208c2ecf20Sopenharmony_ci engs = &eng_grp->engs[i]; 11218c2ecf20Sopenharmony_ci if (!engs->type) 11228c2ecf20Sopenharmony_ci continue; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci mirrored_engs = find_engines_by_type( 11258c2ecf20Sopenharmony_ci &eng_grp->g->grp[eng_grp->mirror.idx], 11268c2ecf20Sopenharmony_ci engs->type); 11278c2ecf20Sopenharmony_ci WARN_ON(!mirrored_engs && engs->count <= 0); 11288c2ecf20Sopenharmony_ci if (!mirrored_engs) 11298c2ecf20Sopenharmony_ci continue; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci bitmap_copy(tmp_bmap.bits, mirrored_engs->bmap, 11328c2ecf20Sopenharmony_ci eng_grp->g->engs_num); 11338c2ecf20Sopenharmony_ci if (engs->count < 0) { 11348c2ecf20Sopenharmony_ci bit = find_first_bit(mirrored_engs->bmap, 11358c2ecf20Sopenharmony_ci eng_grp->g->engs_num); 11368c2ecf20Sopenharmony_ci bitmap_clear(tmp_bmap.bits, bit, -engs->count); 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci bitmap_or(engs->bmap, engs->bmap, tmp_bmap.bits, 11398c2ecf20Sopenharmony_ci eng_grp->g->engs_num); 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci return 0; 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic int delete_engine_group(struct device *dev, 11458c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *eng_grp) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci int i, ret; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci if (!eng_grp->is_enabled) 11508c2ecf20Sopenharmony_ci return -EINVAL; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci if (eng_grp->mirror.ref_count) { 11538c2ecf20Sopenharmony_ci dev_err(dev, "Can't delete engine_group%d as it is used by engine_group(s):", 11548c2ecf20Sopenharmony_ci eng_grp->idx); 11558c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) { 11568c2ecf20Sopenharmony_ci if (eng_grp->g->grp[i].mirror.is_ena && 11578c2ecf20Sopenharmony_ci eng_grp->g->grp[i].mirror.idx == eng_grp->idx) 11588c2ecf20Sopenharmony_ci pr_cont(" %d", i); 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci pr_cont("\n"); 11618c2ecf20Sopenharmony_ci return -EINVAL; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci /* Removing engine group mirroring if enabled */ 11658c2ecf20Sopenharmony_ci remove_eng_grp_mirroring(eng_grp); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci /* Disable engine group */ 11688c2ecf20Sopenharmony_ci ret = disable_eng_grp(dev, eng_grp, eng_grp->g->obj); 11698c2ecf20Sopenharmony_ci if (ret) 11708c2ecf20Sopenharmony_ci return ret; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* Release all engines held by this engine group */ 11738c2ecf20Sopenharmony_ci ret = release_engines(dev, eng_grp); 11748c2ecf20Sopenharmony_ci if (ret) 11758c2ecf20Sopenharmony_ci return ret; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci device_remove_file(dev, &eng_grp->info_attr); 11788c2ecf20Sopenharmony_ci eng_grp->is_enabled = false; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci return 0; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_cistatic int validate_1_ucode_scenario(struct device *dev, 11848c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *eng_grp, 11858c2ecf20Sopenharmony_ci struct otx_cpt_engines *engs, int engs_cnt) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci int i; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci /* Verify that ucode loaded supports requested engine types */ 11908c2ecf20Sopenharmony_ci for (i = 0; i < engs_cnt; i++) { 11918c2ecf20Sopenharmony_ci if (!otx_cpt_uc_supports_eng_type(&eng_grp->ucode[0], 11928c2ecf20Sopenharmony_ci engs[i].type)) { 11938c2ecf20Sopenharmony_ci dev_err(dev, 11948c2ecf20Sopenharmony_ci "Microcode %s does not support %s engines\n", 11958c2ecf20Sopenharmony_ci eng_grp->ucode[0].filename, 11968c2ecf20Sopenharmony_ci get_eng_type_str(engs[i].type)); 11978c2ecf20Sopenharmony_ci return -EINVAL; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci return 0; 12018c2ecf20Sopenharmony_ci} 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_cistatic void update_ucode_ptrs(struct otx_cpt_eng_grp_info *eng_grp) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci struct otx_cpt_ucode *ucode; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (eng_grp->mirror.is_ena) 12088c2ecf20Sopenharmony_ci ucode = &eng_grp->g->grp[eng_grp->mirror.idx].ucode[0]; 12098c2ecf20Sopenharmony_ci else 12108c2ecf20Sopenharmony_ci ucode = &eng_grp->ucode[0]; 12118c2ecf20Sopenharmony_ci WARN_ON(!eng_grp->engs[0].type); 12128c2ecf20Sopenharmony_ci eng_grp->engs[0].ucode = ucode; 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic int create_engine_group(struct device *dev, 12168c2ecf20Sopenharmony_ci struct otx_cpt_eng_grps *eng_grps, 12178c2ecf20Sopenharmony_ci struct otx_cpt_engines *engs, int engs_cnt, 12188c2ecf20Sopenharmony_ci void *ucode_data[], int ucodes_cnt, 12198c2ecf20Sopenharmony_ci bool use_uc_from_tar_arch) 12208c2ecf20Sopenharmony_ci{ 12218c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *mirrored_eng_grp; 12228c2ecf20Sopenharmony_ci struct tar_ucode_info_t *tar_info; 12238c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *eng_grp; 12248c2ecf20Sopenharmony_ci int i, ret = 0; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (ucodes_cnt > OTX_CPT_MAX_ETYPES_PER_GRP) 12278c2ecf20Sopenharmony_ci return -EINVAL; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci /* Validate if requested engine types are supported by this device */ 12308c2ecf20Sopenharmony_ci for (i = 0; i < engs_cnt; i++) 12318c2ecf20Sopenharmony_ci if (!dev_supports_eng_type(eng_grps, engs[i].type)) { 12328c2ecf20Sopenharmony_ci dev_err(dev, "Device does not support %s engines\n", 12338c2ecf20Sopenharmony_ci get_eng_type_str(engs[i].type)); 12348c2ecf20Sopenharmony_ci return -EPERM; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci /* Find engine group which is not used */ 12388c2ecf20Sopenharmony_ci eng_grp = find_unused_eng_grp(eng_grps); 12398c2ecf20Sopenharmony_ci if (!eng_grp) { 12408c2ecf20Sopenharmony_ci dev_err(dev, "Error all engine groups are being used\n"); 12418c2ecf20Sopenharmony_ci return -ENOSPC; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci /* Load ucode */ 12458c2ecf20Sopenharmony_ci for (i = 0; i < ucodes_cnt; i++) { 12468c2ecf20Sopenharmony_ci if (use_uc_from_tar_arch) { 12478c2ecf20Sopenharmony_ci tar_info = (struct tar_ucode_info_t *) ucode_data[i]; 12488c2ecf20Sopenharmony_ci eng_grp->ucode[i] = tar_info->ucode; 12498c2ecf20Sopenharmony_ci ret = copy_ucode_to_dma_mem(dev, &eng_grp->ucode[i], 12508c2ecf20Sopenharmony_ci tar_info->ucode_ptr); 12518c2ecf20Sopenharmony_ci } else 12528c2ecf20Sopenharmony_ci ret = ucode_load(dev, &eng_grp->ucode[i], 12538c2ecf20Sopenharmony_ci (char *) ucode_data[i]); 12548c2ecf20Sopenharmony_ci if (ret) 12558c2ecf20Sopenharmony_ci goto err_ucode_unload; 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci /* Validate scenario where 1 ucode is used */ 12598c2ecf20Sopenharmony_ci ret = validate_1_ucode_scenario(dev, eng_grp, engs, engs_cnt); 12608c2ecf20Sopenharmony_ci if (ret) 12618c2ecf20Sopenharmony_ci goto err_ucode_unload; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci /* Check if this group mirrors another existing engine group */ 12648c2ecf20Sopenharmony_ci mirrored_eng_grp = find_mirrored_eng_grp(eng_grp); 12658c2ecf20Sopenharmony_ci if (mirrored_eng_grp) { 12668c2ecf20Sopenharmony_ci /* Setup mirroring */ 12678c2ecf20Sopenharmony_ci setup_eng_grp_mirroring(eng_grp, mirrored_eng_grp); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci /* 12708c2ecf20Sopenharmony_ci * Update count of requested engines because some 12718c2ecf20Sopenharmony_ci * of them might be shared with mirrored group 12728c2ecf20Sopenharmony_ci */ 12738c2ecf20Sopenharmony_ci update_requested_engs(mirrored_eng_grp, engs, engs_cnt); 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci /* Reserve engines */ 12778c2ecf20Sopenharmony_ci ret = reserve_engines(dev, eng_grp, engs, engs_cnt); 12788c2ecf20Sopenharmony_ci if (ret) 12798c2ecf20Sopenharmony_ci goto err_ucode_unload; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* Update ucode pointers used by engines */ 12828c2ecf20Sopenharmony_ci update_ucode_ptrs(eng_grp); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci /* Update engine masks used by this group */ 12858c2ecf20Sopenharmony_ci ret = eng_grp_update_masks(dev, eng_grp); 12868c2ecf20Sopenharmony_ci if (ret) 12878c2ecf20Sopenharmony_ci goto err_release_engs; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci /* Create sysfs entry for engine group info */ 12908c2ecf20Sopenharmony_ci ret = create_sysfs_eng_grps_info(dev, eng_grp); 12918c2ecf20Sopenharmony_ci if (ret) 12928c2ecf20Sopenharmony_ci goto err_release_engs; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* Enable engine group */ 12958c2ecf20Sopenharmony_ci ret = enable_eng_grp(eng_grp, eng_grps->obj); 12968c2ecf20Sopenharmony_ci if (ret) 12978c2ecf20Sopenharmony_ci goto err_release_engs; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci /* 13008c2ecf20Sopenharmony_ci * If this engine group mirrors another engine group 13018c2ecf20Sopenharmony_ci * then we need to unload ucode as we will use ucode 13028c2ecf20Sopenharmony_ci * from mirrored engine group 13038c2ecf20Sopenharmony_ci */ 13048c2ecf20Sopenharmony_ci if (eng_grp->mirror.is_ena) 13058c2ecf20Sopenharmony_ci ucode_unload(dev, &eng_grp->ucode[0]); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci eng_grp->is_enabled = true; 13088c2ecf20Sopenharmony_ci if (eng_grp->mirror.is_ena) 13098c2ecf20Sopenharmony_ci dev_info(dev, 13108c2ecf20Sopenharmony_ci "Engine_group%d: reuse microcode %s from group %d\n", 13118c2ecf20Sopenharmony_ci eng_grp->idx, mirrored_eng_grp->ucode[0].ver_str, 13128c2ecf20Sopenharmony_ci mirrored_eng_grp->idx); 13138c2ecf20Sopenharmony_ci else 13148c2ecf20Sopenharmony_ci dev_info(dev, "Engine_group%d: microcode loaded %s\n", 13158c2ecf20Sopenharmony_ci eng_grp->idx, eng_grp->ucode[0].ver_str); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci return 0; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cierr_release_engs: 13208c2ecf20Sopenharmony_ci release_engines(dev, eng_grp); 13218c2ecf20Sopenharmony_cierr_ucode_unload: 13228c2ecf20Sopenharmony_ci ucode_unload(dev, &eng_grp->ucode[0]); 13238c2ecf20Sopenharmony_ci return ret; 13248c2ecf20Sopenharmony_ci} 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_cistatic ssize_t ucode_load_store(struct device *dev, 13278c2ecf20Sopenharmony_ci struct device_attribute *attr, 13288c2ecf20Sopenharmony_ci const char *buf, size_t count) 13298c2ecf20Sopenharmony_ci{ 13308c2ecf20Sopenharmony_ci struct otx_cpt_engines engs[OTX_CPT_MAX_ETYPES_PER_GRP] = { {0} }; 13318c2ecf20Sopenharmony_ci char *ucode_filename[OTX_CPT_MAX_ETYPES_PER_GRP]; 13328c2ecf20Sopenharmony_ci char tmp_buf[OTX_CPT_UCODE_NAME_LENGTH] = { 0 }; 13338c2ecf20Sopenharmony_ci char *start, *val, *err_msg, *tmp; 13348c2ecf20Sopenharmony_ci struct otx_cpt_eng_grps *eng_grps; 13358c2ecf20Sopenharmony_ci int grp_idx = 0, ret = -EINVAL; 13368c2ecf20Sopenharmony_ci bool has_se, has_ie, has_ae; 13378c2ecf20Sopenharmony_ci int del_grp_idx = -1; 13388c2ecf20Sopenharmony_ci int ucode_idx = 0; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (strlen(buf) > OTX_CPT_UCODE_NAME_LENGTH) 13418c2ecf20Sopenharmony_ci return -EINVAL; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci eng_grps = container_of(attr, struct otx_cpt_eng_grps, ucode_load_attr); 13448c2ecf20Sopenharmony_ci err_msg = "Invalid engine group format"; 13458c2ecf20Sopenharmony_ci strlcpy(tmp_buf, buf, OTX_CPT_UCODE_NAME_LENGTH); 13468c2ecf20Sopenharmony_ci start = tmp_buf; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci has_se = has_ie = has_ae = false; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci for (;;) { 13518c2ecf20Sopenharmony_ci val = strsep(&start, ";"); 13528c2ecf20Sopenharmony_ci if (!val) 13538c2ecf20Sopenharmony_ci break; 13548c2ecf20Sopenharmony_ci val = strim(val); 13558c2ecf20Sopenharmony_ci if (!*val) 13568c2ecf20Sopenharmony_ci continue; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci if (!strncasecmp(val, "engine_group", 12)) { 13598c2ecf20Sopenharmony_ci if (del_grp_idx != -1) 13608c2ecf20Sopenharmony_ci goto err_print; 13618c2ecf20Sopenharmony_ci tmp = strim(strsep(&val, ":")); 13628c2ecf20Sopenharmony_ci if (!val) 13638c2ecf20Sopenharmony_ci goto err_print; 13648c2ecf20Sopenharmony_ci if (strlen(tmp) != 13) 13658c2ecf20Sopenharmony_ci goto err_print; 13668c2ecf20Sopenharmony_ci if (kstrtoint((tmp + 12), 10, &del_grp_idx)) 13678c2ecf20Sopenharmony_ci goto err_print; 13688c2ecf20Sopenharmony_ci val = strim(val); 13698c2ecf20Sopenharmony_ci if (strncasecmp(val, "null", 4)) 13708c2ecf20Sopenharmony_ci goto err_print; 13718c2ecf20Sopenharmony_ci if (strlen(val) != 4) 13728c2ecf20Sopenharmony_ci goto err_print; 13738c2ecf20Sopenharmony_ci } else if (!strncasecmp(val, "se", 2) && strchr(val, ':')) { 13748c2ecf20Sopenharmony_ci if (has_se || ucode_idx) 13758c2ecf20Sopenharmony_ci goto err_print; 13768c2ecf20Sopenharmony_ci tmp = strim(strsep(&val, ":")); 13778c2ecf20Sopenharmony_ci if (!val) 13788c2ecf20Sopenharmony_ci goto err_print; 13798c2ecf20Sopenharmony_ci if (strlen(tmp) != 2) 13808c2ecf20Sopenharmony_ci goto err_print; 13818c2ecf20Sopenharmony_ci if (kstrtoint(strim(val), 10, &engs[grp_idx].count)) 13828c2ecf20Sopenharmony_ci goto err_print; 13838c2ecf20Sopenharmony_ci engs[grp_idx++].type = OTX_CPT_SE_TYPES; 13848c2ecf20Sopenharmony_ci has_se = true; 13858c2ecf20Sopenharmony_ci } else if (!strncasecmp(val, "ae", 2) && strchr(val, ':')) { 13868c2ecf20Sopenharmony_ci if (has_ae || ucode_idx) 13878c2ecf20Sopenharmony_ci goto err_print; 13888c2ecf20Sopenharmony_ci tmp = strim(strsep(&val, ":")); 13898c2ecf20Sopenharmony_ci if (!val) 13908c2ecf20Sopenharmony_ci goto err_print; 13918c2ecf20Sopenharmony_ci if (strlen(tmp) != 2) 13928c2ecf20Sopenharmony_ci goto err_print; 13938c2ecf20Sopenharmony_ci if (kstrtoint(strim(val), 10, &engs[grp_idx].count)) 13948c2ecf20Sopenharmony_ci goto err_print; 13958c2ecf20Sopenharmony_ci engs[grp_idx++].type = OTX_CPT_AE_TYPES; 13968c2ecf20Sopenharmony_ci has_ae = true; 13978c2ecf20Sopenharmony_ci } else { 13988c2ecf20Sopenharmony_ci if (ucode_idx > 1) 13998c2ecf20Sopenharmony_ci goto err_print; 14008c2ecf20Sopenharmony_ci if (!strlen(val)) 14018c2ecf20Sopenharmony_ci goto err_print; 14028c2ecf20Sopenharmony_ci if (strnstr(val, " ", strlen(val))) 14038c2ecf20Sopenharmony_ci goto err_print; 14048c2ecf20Sopenharmony_ci ucode_filename[ucode_idx++] = val; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci /* Validate input parameters */ 14098c2ecf20Sopenharmony_ci if (del_grp_idx == -1) { 14108c2ecf20Sopenharmony_ci if (!(grp_idx && ucode_idx)) 14118c2ecf20Sopenharmony_ci goto err_print; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (ucode_idx > 1 && grp_idx < 2) 14148c2ecf20Sopenharmony_ci goto err_print; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (grp_idx > OTX_CPT_MAX_ETYPES_PER_GRP) { 14178c2ecf20Sopenharmony_ci err_msg = "Error max 2 engine types can be attached"; 14188c2ecf20Sopenharmony_ci goto err_print; 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci } else { 14228c2ecf20Sopenharmony_ci if (del_grp_idx < 0 || 14238c2ecf20Sopenharmony_ci del_grp_idx >= OTX_CPT_MAX_ENGINE_GROUPS) { 14248c2ecf20Sopenharmony_ci dev_err(dev, "Invalid engine group index %d\n", 14258c2ecf20Sopenharmony_ci del_grp_idx); 14268c2ecf20Sopenharmony_ci ret = -EINVAL; 14278c2ecf20Sopenharmony_ci return ret; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci if (!eng_grps->grp[del_grp_idx].is_enabled) { 14318c2ecf20Sopenharmony_ci dev_err(dev, "Error engine_group%d is not configured\n", 14328c2ecf20Sopenharmony_ci del_grp_idx); 14338c2ecf20Sopenharmony_ci ret = -EINVAL; 14348c2ecf20Sopenharmony_ci return ret; 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci if (grp_idx || ucode_idx) 14388c2ecf20Sopenharmony_ci goto err_print; 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci mutex_lock(&eng_grps->lock); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (eng_grps->is_rdonly) { 14448c2ecf20Sopenharmony_ci dev_err(dev, "Disable VFs before modifying engine groups\n"); 14458c2ecf20Sopenharmony_ci ret = -EACCES; 14468c2ecf20Sopenharmony_ci goto err_unlock; 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci if (del_grp_idx == -1) 14508c2ecf20Sopenharmony_ci /* create engine group */ 14518c2ecf20Sopenharmony_ci ret = create_engine_group(dev, eng_grps, engs, grp_idx, 14528c2ecf20Sopenharmony_ci (void **) ucode_filename, 14538c2ecf20Sopenharmony_ci ucode_idx, false); 14548c2ecf20Sopenharmony_ci else 14558c2ecf20Sopenharmony_ci /* delete engine group */ 14568c2ecf20Sopenharmony_ci ret = delete_engine_group(dev, &eng_grps->grp[del_grp_idx]); 14578c2ecf20Sopenharmony_ci if (ret) 14588c2ecf20Sopenharmony_ci goto err_unlock; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci print_dbg_info(dev, eng_grps); 14618c2ecf20Sopenharmony_cierr_unlock: 14628c2ecf20Sopenharmony_ci mutex_unlock(&eng_grps->lock); 14638c2ecf20Sopenharmony_ci return ret ? ret : count; 14648c2ecf20Sopenharmony_cierr_print: 14658c2ecf20Sopenharmony_ci dev_err(dev, "%s\n", err_msg); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci return ret; 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ciint otx_cpt_try_create_default_eng_grps(struct pci_dev *pdev, 14718c2ecf20Sopenharmony_ci struct otx_cpt_eng_grps *eng_grps, 14728c2ecf20Sopenharmony_ci int pf_type) 14738c2ecf20Sopenharmony_ci{ 14748c2ecf20Sopenharmony_ci struct tar_ucode_info_t *tar_info[OTX_CPT_MAX_ETYPES_PER_GRP] = {}; 14758c2ecf20Sopenharmony_ci struct otx_cpt_engines engs[OTX_CPT_MAX_ETYPES_PER_GRP] = {}; 14768c2ecf20Sopenharmony_ci struct tar_arch_info_t *tar_arch = NULL; 14778c2ecf20Sopenharmony_ci char *tar_filename; 14788c2ecf20Sopenharmony_ci int i, ret = 0; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci mutex_lock(&eng_grps->lock); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci /* 14838c2ecf20Sopenharmony_ci * We don't create engine group for kernel crypto if attempt to create 14848c2ecf20Sopenharmony_ci * it was already made (when user enabled VFs for the first time) 14858c2ecf20Sopenharmony_ci */ 14868c2ecf20Sopenharmony_ci if (eng_grps->is_first_try) 14878c2ecf20Sopenharmony_ci goto unlock_mutex; 14888c2ecf20Sopenharmony_ci eng_grps->is_first_try = true; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci /* We create group for kcrypto only if no groups are configured */ 14918c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) 14928c2ecf20Sopenharmony_ci if (eng_grps->grp[i].is_enabled) 14938c2ecf20Sopenharmony_ci goto unlock_mutex; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci switch (pf_type) { 14968c2ecf20Sopenharmony_ci case OTX_CPT_AE: 14978c2ecf20Sopenharmony_ci case OTX_CPT_SE: 14988c2ecf20Sopenharmony_ci tar_filename = OTX_CPT_UCODE_TAR_FILE_NAME; 14998c2ecf20Sopenharmony_ci break; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci default: 15028c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unknown PF type %d\n", pf_type); 15038c2ecf20Sopenharmony_ci ret = -EINVAL; 15048c2ecf20Sopenharmony_ci goto unlock_mutex; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci tar_arch = load_tar_archive(&pdev->dev, tar_filename); 15088c2ecf20Sopenharmony_ci if (!tar_arch) 15098c2ecf20Sopenharmony_ci goto unlock_mutex; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci /* 15128c2ecf20Sopenharmony_ci * If device supports SE engines and there is SE microcode in tar 15138c2ecf20Sopenharmony_ci * archive try to create engine group with SE engines for kernel 15148c2ecf20Sopenharmony_ci * crypto functionality (symmetric crypto) 15158c2ecf20Sopenharmony_ci */ 15168c2ecf20Sopenharmony_ci tar_info[0] = get_uc_from_tar_archive(tar_arch, OTX_CPT_SE_TYPES); 15178c2ecf20Sopenharmony_ci if (tar_info[0] && 15188c2ecf20Sopenharmony_ci dev_supports_eng_type(eng_grps, OTX_CPT_SE_TYPES)) { 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci engs[0].type = OTX_CPT_SE_TYPES; 15218c2ecf20Sopenharmony_ci engs[0].count = eng_grps->avail.max_se_cnt; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci ret = create_engine_group(&pdev->dev, eng_grps, engs, 1, 15248c2ecf20Sopenharmony_ci (void **) tar_info, 1, true); 15258c2ecf20Sopenharmony_ci if (ret) 15268c2ecf20Sopenharmony_ci goto release_tar_arch; 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci /* 15298c2ecf20Sopenharmony_ci * If device supports AE engines and there is AE microcode in tar 15308c2ecf20Sopenharmony_ci * archive try to create engine group with AE engines for asymmetric 15318c2ecf20Sopenharmony_ci * crypto functionality. 15328c2ecf20Sopenharmony_ci */ 15338c2ecf20Sopenharmony_ci tar_info[0] = get_uc_from_tar_archive(tar_arch, OTX_CPT_AE_TYPES); 15348c2ecf20Sopenharmony_ci if (tar_info[0] && 15358c2ecf20Sopenharmony_ci dev_supports_eng_type(eng_grps, OTX_CPT_AE_TYPES)) { 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci engs[0].type = OTX_CPT_AE_TYPES; 15388c2ecf20Sopenharmony_ci engs[0].count = eng_grps->avail.max_ae_cnt; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci ret = create_engine_group(&pdev->dev, eng_grps, engs, 1, 15418c2ecf20Sopenharmony_ci (void **) tar_info, 1, true); 15428c2ecf20Sopenharmony_ci if (ret) 15438c2ecf20Sopenharmony_ci goto release_tar_arch; 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci print_dbg_info(&pdev->dev, eng_grps); 15478c2ecf20Sopenharmony_cirelease_tar_arch: 15488c2ecf20Sopenharmony_ci release_tar_archive(tar_arch); 15498c2ecf20Sopenharmony_ciunlock_mutex: 15508c2ecf20Sopenharmony_ci mutex_unlock(&eng_grps->lock); 15518c2ecf20Sopenharmony_ci return ret; 15528c2ecf20Sopenharmony_ci} 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_civoid otx_cpt_set_eng_grps_is_rdonly(struct otx_cpt_eng_grps *eng_grps, 15558c2ecf20Sopenharmony_ci bool is_rdonly) 15568c2ecf20Sopenharmony_ci{ 15578c2ecf20Sopenharmony_ci mutex_lock(&eng_grps->lock); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci eng_grps->is_rdonly = is_rdonly; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci mutex_unlock(&eng_grps->lock); 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_civoid otx_cpt_disable_all_cores(struct otx_cpt_device *cpt) 15658c2ecf20Sopenharmony_ci{ 15668c2ecf20Sopenharmony_ci int grp, timeout = 100; 15678c2ecf20Sopenharmony_ci u64 reg; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci /* Disengage the cores from groups */ 15708c2ecf20Sopenharmony_ci for (grp = 0; grp < OTX_CPT_MAX_ENGINE_GROUPS; grp++) { 15718c2ecf20Sopenharmony_ci writeq(0, cpt->reg_base + OTX_CPT_PF_GX_EN(grp)); 15728c2ecf20Sopenharmony_ci udelay(CSR_DELAY); 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci reg = readq(cpt->reg_base + OTX_CPT_PF_EXEC_BUSY); 15768c2ecf20Sopenharmony_ci while (reg) { 15778c2ecf20Sopenharmony_ci udelay(CSR_DELAY); 15788c2ecf20Sopenharmony_ci reg = readq(cpt->reg_base + OTX_CPT_PF_EXEC_BUSY); 15798c2ecf20Sopenharmony_ci if (timeout--) { 15808c2ecf20Sopenharmony_ci dev_warn(&cpt->pdev->dev, "Cores still busy\n"); 15818c2ecf20Sopenharmony_ci break; 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci /* Disable the cores */ 15868c2ecf20Sopenharmony_ci writeq(0, cpt->reg_base + OTX_CPT_PF_EXE_CTL); 15878c2ecf20Sopenharmony_ci} 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_civoid otx_cpt_cleanup_eng_grps(struct pci_dev *pdev, 15908c2ecf20Sopenharmony_ci struct otx_cpt_eng_grps *eng_grps) 15918c2ecf20Sopenharmony_ci{ 15928c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *grp; 15938c2ecf20Sopenharmony_ci int i, j; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci mutex_lock(&eng_grps->lock); 15968c2ecf20Sopenharmony_ci if (eng_grps->is_ucode_load_created) { 15978c2ecf20Sopenharmony_ci device_remove_file(&pdev->dev, 15988c2ecf20Sopenharmony_ci &eng_grps->ucode_load_attr); 15998c2ecf20Sopenharmony_ci eng_grps->is_ucode_load_created = false; 16008c2ecf20Sopenharmony_ci } 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci /* First delete all mirroring engine groups */ 16038c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) 16048c2ecf20Sopenharmony_ci if (eng_grps->grp[i].mirror.is_ena) 16058c2ecf20Sopenharmony_ci delete_engine_group(&pdev->dev, &eng_grps->grp[i]); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci /* Delete remaining engine groups */ 16088c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) 16098c2ecf20Sopenharmony_ci delete_engine_group(&pdev->dev, &eng_grps->grp[i]); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci /* Release memory */ 16128c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) { 16138c2ecf20Sopenharmony_ci grp = &eng_grps->grp[i]; 16148c2ecf20Sopenharmony_ci for (j = 0; j < OTX_CPT_MAX_ETYPES_PER_GRP; j++) { 16158c2ecf20Sopenharmony_ci kfree(grp->engs[j].bmap); 16168c2ecf20Sopenharmony_ci grp->engs[j].bmap = NULL; 16178c2ecf20Sopenharmony_ci } 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci mutex_unlock(&eng_grps->lock); 16218c2ecf20Sopenharmony_ci} 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ciint otx_cpt_init_eng_grps(struct pci_dev *pdev, 16248c2ecf20Sopenharmony_ci struct otx_cpt_eng_grps *eng_grps, int pf_type) 16258c2ecf20Sopenharmony_ci{ 16268c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *grp; 16278c2ecf20Sopenharmony_ci int i, j, ret = 0; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci mutex_init(&eng_grps->lock); 16308c2ecf20Sopenharmony_ci eng_grps->obj = pci_get_drvdata(pdev); 16318c2ecf20Sopenharmony_ci eng_grps->avail.se_cnt = eng_grps->avail.max_se_cnt; 16328c2ecf20Sopenharmony_ci eng_grps->avail.ae_cnt = eng_grps->avail.max_ae_cnt; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci eng_grps->engs_num = eng_grps->avail.max_se_cnt + 16358c2ecf20Sopenharmony_ci eng_grps->avail.max_ae_cnt; 16368c2ecf20Sopenharmony_ci if (eng_grps->engs_num > OTX_CPT_MAX_ENGINES) { 16378c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 16388c2ecf20Sopenharmony_ci "Number of engines %d > than max supported %d\n", 16398c2ecf20Sopenharmony_ci eng_grps->engs_num, OTX_CPT_MAX_ENGINES); 16408c2ecf20Sopenharmony_ci ret = -EINVAL; 16418c2ecf20Sopenharmony_ci goto err; 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) { 16458c2ecf20Sopenharmony_ci grp = &eng_grps->grp[i]; 16468c2ecf20Sopenharmony_ci grp->g = eng_grps; 16478c2ecf20Sopenharmony_ci grp->idx = i; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci snprintf(grp->sysfs_info_name, OTX_CPT_UCODE_NAME_LENGTH, 16508c2ecf20Sopenharmony_ci "engine_group%d", i); 16518c2ecf20Sopenharmony_ci for (j = 0; j < OTX_CPT_MAX_ETYPES_PER_GRP; j++) { 16528c2ecf20Sopenharmony_ci grp->engs[j].bmap = 16538c2ecf20Sopenharmony_ci kcalloc(BITS_TO_LONGS(eng_grps->engs_num), 16548c2ecf20Sopenharmony_ci sizeof(long), GFP_KERNEL); 16558c2ecf20Sopenharmony_ci if (!grp->engs[j].bmap) { 16568c2ecf20Sopenharmony_ci ret = -ENOMEM; 16578c2ecf20Sopenharmony_ci goto err; 16588c2ecf20Sopenharmony_ci } 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci switch (pf_type) { 16638c2ecf20Sopenharmony_ci case OTX_CPT_SE: 16648c2ecf20Sopenharmony_ci /* OcteonTX 83XX SE CPT PF has only SE engines attached */ 16658c2ecf20Sopenharmony_ci eng_grps->eng_types_supported = 1 << OTX_CPT_SE_TYPES; 16668c2ecf20Sopenharmony_ci break; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci case OTX_CPT_AE: 16698c2ecf20Sopenharmony_ci /* OcteonTX 83XX AE CPT PF has only AE engines attached */ 16708c2ecf20Sopenharmony_ci eng_grps->eng_types_supported = 1 << OTX_CPT_AE_TYPES; 16718c2ecf20Sopenharmony_ci break; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci default: 16748c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unknown PF type %d\n", pf_type); 16758c2ecf20Sopenharmony_ci ret = -EINVAL; 16768c2ecf20Sopenharmony_ci goto err; 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci eng_grps->ucode_load_attr.show = NULL; 16808c2ecf20Sopenharmony_ci eng_grps->ucode_load_attr.store = ucode_load_store; 16818c2ecf20Sopenharmony_ci eng_grps->ucode_load_attr.attr.name = "ucode_load"; 16828c2ecf20Sopenharmony_ci eng_grps->ucode_load_attr.attr.mode = 0220; 16838c2ecf20Sopenharmony_ci sysfs_attr_init(&eng_grps->ucode_load_attr.attr); 16848c2ecf20Sopenharmony_ci ret = device_create_file(&pdev->dev, 16858c2ecf20Sopenharmony_ci &eng_grps->ucode_load_attr); 16868c2ecf20Sopenharmony_ci if (ret) 16878c2ecf20Sopenharmony_ci goto err; 16888c2ecf20Sopenharmony_ci eng_grps->is_ucode_load_created = true; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci print_dbg_info(&pdev->dev, eng_grps); 16918c2ecf20Sopenharmony_ci return ret; 16928c2ecf20Sopenharmony_cierr: 16938c2ecf20Sopenharmony_ci otx_cpt_cleanup_eng_grps(pdev, eng_grps); 16948c2ecf20Sopenharmony_ci return ret; 16958c2ecf20Sopenharmony_ci} 1696