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