162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Marvell OcteonTX CPT driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2019 Marvell International Ltd.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
762306a36Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as
862306a36Sopenharmony_ci * published by the Free Software Foundation.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/ctype.h>
1262306a36Sopenharmony_ci#include <linux/firmware.h>
1362306a36Sopenharmony_ci#include "otx_cpt_common.h"
1462306a36Sopenharmony_ci#include "otx_cptpf_ucode.h"
1562306a36Sopenharmony_ci#include "otx_cptpf.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define CSR_DELAY 30
1862306a36Sopenharmony_ci/* Tar archive defines */
1962306a36Sopenharmony_ci#define TAR_MAGIC		"ustar"
2062306a36Sopenharmony_ci#define TAR_MAGIC_LEN		6
2162306a36Sopenharmony_ci#define TAR_BLOCK_LEN		512
2262306a36Sopenharmony_ci#define REGTYPE			'0'
2362306a36Sopenharmony_ci#define AREGTYPE		'\0'
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* tar header as defined in POSIX 1003.1-1990. */
2662306a36Sopenharmony_cistruct tar_hdr_t {
2762306a36Sopenharmony_ci	char name[100];
2862306a36Sopenharmony_ci	char mode[8];
2962306a36Sopenharmony_ci	char uid[8];
3062306a36Sopenharmony_ci	char gid[8];
3162306a36Sopenharmony_ci	char size[12];
3262306a36Sopenharmony_ci	char mtime[12];
3362306a36Sopenharmony_ci	char chksum[8];
3462306a36Sopenharmony_ci	char typeflag;
3562306a36Sopenharmony_ci	char linkname[100];
3662306a36Sopenharmony_ci	char magic[6];
3762306a36Sopenharmony_ci	char version[2];
3862306a36Sopenharmony_ci	char uname[32];
3962306a36Sopenharmony_ci	char gname[32];
4062306a36Sopenharmony_ci	char devmajor[8];
4162306a36Sopenharmony_ci	char devminor[8];
4262306a36Sopenharmony_ci	char prefix[155];
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistruct tar_blk_t {
4662306a36Sopenharmony_ci	union {
4762306a36Sopenharmony_ci		struct tar_hdr_t hdr;
4862306a36Sopenharmony_ci		char block[TAR_BLOCK_LEN];
4962306a36Sopenharmony_ci	};
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistruct tar_arch_info_t {
5362306a36Sopenharmony_ci	struct list_head ucodes;
5462306a36Sopenharmony_ci	const struct firmware *fw;
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic struct otx_cpt_bitmap get_cores_bmap(struct device *dev,
5862306a36Sopenharmony_ci					   struct otx_cpt_eng_grp_info *eng_grp)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct otx_cpt_bitmap bmap = { {0} };
6162306a36Sopenharmony_ci	bool found = false;
6262306a36Sopenharmony_ci	int i;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (eng_grp->g->engs_num > OTX_CPT_MAX_ENGINES) {
6562306a36Sopenharmony_ci		dev_err(dev, "unsupported number of engines %d on octeontx\n",
6662306a36Sopenharmony_ci			eng_grp->g->engs_num);
6762306a36Sopenharmony_ci		return bmap;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {
7162306a36Sopenharmony_ci		if (eng_grp->engs[i].type) {
7262306a36Sopenharmony_ci			bitmap_or(bmap.bits, bmap.bits,
7362306a36Sopenharmony_ci				  eng_grp->engs[i].bmap,
7462306a36Sopenharmony_ci				  eng_grp->g->engs_num);
7562306a36Sopenharmony_ci			bmap.size = eng_grp->g->engs_num;
7662306a36Sopenharmony_ci			found = true;
7762306a36Sopenharmony_ci		}
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	if (!found)
8162306a36Sopenharmony_ci		dev_err(dev, "No engines reserved for engine group %d\n",
8262306a36Sopenharmony_ci			eng_grp->idx);
8362306a36Sopenharmony_ci	return bmap;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic int is_eng_type(int val, int eng_type)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	return val & (1 << eng_type);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic int dev_supports_eng_type(struct otx_cpt_eng_grps *eng_grps,
9262306a36Sopenharmony_ci				 int eng_type)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	return is_eng_type(eng_grps->eng_types_supported, eng_type);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void set_ucode_filename(struct otx_cpt_ucode *ucode,
9862306a36Sopenharmony_ci			       const char *filename)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	strscpy(ucode->filename, filename, OTX_CPT_UCODE_NAME_LENGTH);
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic char *get_eng_type_str(int eng_type)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	char *str = "unknown";
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	switch (eng_type) {
10862306a36Sopenharmony_ci	case OTX_CPT_SE_TYPES:
10962306a36Sopenharmony_ci		str = "SE";
11062306a36Sopenharmony_ci		break;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	case OTX_CPT_AE_TYPES:
11362306a36Sopenharmony_ci		str = "AE";
11462306a36Sopenharmony_ci		break;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci	return str;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic char *get_ucode_type_str(int ucode_type)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	char *str = "unknown";
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	switch (ucode_type) {
12462306a36Sopenharmony_ci	case (1 << OTX_CPT_SE_TYPES):
12562306a36Sopenharmony_ci		str = "SE";
12662306a36Sopenharmony_ci		break;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	case (1 << OTX_CPT_AE_TYPES):
12962306a36Sopenharmony_ci		str = "AE";
13062306a36Sopenharmony_ci		break;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci	return str;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic int get_ucode_type(struct otx_cpt_ucode_hdr *ucode_hdr, int *ucode_type)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	char tmp_ver_str[OTX_CPT_UCODE_VER_STR_SZ];
13862306a36Sopenharmony_ci	u32 i, val = 0;
13962306a36Sopenharmony_ci	u8 nn;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	strscpy(tmp_ver_str, ucode_hdr->ver_str, OTX_CPT_UCODE_VER_STR_SZ);
14262306a36Sopenharmony_ci	for (i = 0; i < strlen(tmp_ver_str); i++)
14362306a36Sopenharmony_ci		tmp_ver_str[i] = tolower(tmp_ver_str[i]);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	nn = ucode_hdr->ver_num.nn;
14662306a36Sopenharmony_ci	if (strnstr(tmp_ver_str, "se-", OTX_CPT_UCODE_VER_STR_SZ) &&
14762306a36Sopenharmony_ci	    (nn == OTX_CPT_SE_UC_TYPE1 || nn == OTX_CPT_SE_UC_TYPE2 ||
14862306a36Sopenharmony_ci	     nn == OTX_CPT_SE_UC_TYPE3))
14962306a36Sopenharmony_ci		val |= 1 << OTX_CPT_SE_TYPES;
15062306a36Sopenharmony_ci	if (strnstr(tmp_ver_str, "ae", OTX_CPT_UCODE_VER_STR_SZ) &&
15162306a36Sopenharmony_ci	    nn == OTX_CPT_AE_UC_TYPE)
15262306a36Sopenharmony_ci		val |= 1 << OTX_CPT_AE_TYPES;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	*ucode_type = val;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (!val)
15762306a36Sopenharmony_ci		return -EINVAL;
15862306a36Sopenharmony_ci	if (is_eng_type(val, OTX_CPT_AE_TYPES) &&
15962306a36Sopenharmony_ci	    is_eng_type(val, OTX_CPT_SE_TYPES))
16062306a36Sopenharmony_ci		return -EINVAL;
16162306a36Sopenharmony_ci	return 0;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic int is_mem_zero(const char *ptr, int size)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	int i;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
16962306a36Sopenharmony_ci		if (ptr[i])
17062306a36Sopenharmony_ci			return 0;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci	return 1;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic int cpt_set_ucode_base(struct otx_cpt_eng_grp_info *eng_grp, void *obj)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct otx_cpt_device *cpt = (struct otx_cpt_device *) obj;
17862306a36Sopenharmony_ci	dma_addr_t dma_addr;
17962306a36Sopenharmony_ci	struct otx_cpt_bitmap bmap;
18062306a36Sopenharmony_ci	int i;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	bmap = get_cores_bmap(&cpt->pdev->dev, eng_grp);
18362306a36Sopenharmony_ci	if (!bmap.size)
18462306a36Sopenharmony_ci		return -EINVAL;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (eng_grp->mirror.is_ena)
18762306a36Sopenharmony_ci		dma_addr =
18862306a36Sopenharmony_ci		       eng_grp->g->grp[eng_grp->mirror.idx].ucode[0].align_dma;
18962306a36Sopenharmony_ci	else
19062306a36Sopenharmony_ci		dma_addr = eng_grp->ucode[0].align_dma;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/*
19362306a36Sopenharmony_ci	 * Set UCODE_BASE only for the cores which are not used,
19462306a36Sopenharmony_ci	 * other cores should have already valid UCODE_BASE set
19562306a36Sopenharmony_ci	 */
19662306a36Sopenharmony_ci	for_each_set_bit(i, bmap.bits, bmap.size)
19762306a36Sopenharmony_ci		if (!eng_grp->g->eng_ref_cnt[i])
19862306a36Sopenharmony_ci			writeq((u64) dma_addr, cpt->reg_base +
19962306a36Sopenharmony_ci				OTX_CPT_PF_ENGX_UCODE_BASE(i));
20062306a36Sopenharmony_ci	return 0;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic int cpt_detach_and_disable_cores(struct otx_cpt_eng_grp_info *eng_grp,
20462306a36Sopenharmony_ci					void *obj)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct otx_cpt_device *cpt = (struct otx_cpt_device *) obj;
20762306a36Sopenharmony_ci	struct otx_cpt_bitmap bmap = { {0} };
20862306a36Sopenharmony_ci	int timeout = 10;
20962306a36Sopenharmony_ci	int i, busy;
21062306a36Sopenharmony_ci	u64 reg;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	bmap = get_cores_bmap(&cpt->pdev->dev, eng_grp);
21362306a36Sopenharmony_ci	if (!bmap.size)
21462306a36Sopenharmony_ci		return -EINVAL;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	/* Detach the cores from group */
21762306a36Sopenharmony_ci	reg = readq(cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx));
21862306a36Sopenharmony_ci	for_each_set_bit(i, bmap.bits, bmap.size) {
21962306a36Sopenharmony_ci		if (reg & (1ull << i)) {
22062306a36Sopenharmony_ci			eng_grp->g->eng_ref_cnt[i]--;
22162306a36Sopenharmony_ci			reg &= ~(1ull << i);
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci	writeq(reg, cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx));
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/* Wait for cores to become idle */
22762306a36Sopenharmony_ci	do {
22862306a36Sopenharmony_ci		busy = 0;
22962306a36Sopenharmony_ci		usleep_range(10000, 20000);
23062306a36Sopenharmony_ci		if (timeout-- < 0)
23162306a36Sopenharmony_ci			return -EBUSY;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		reg = readq(cpt->reg_base + OTX_CPT_PF_EXEC_BUSY);
23462306a36Sopenharmony_ci		for_each_set_bit(i, bmap.bits, bmap.size)
23562306a36Sopenharmony_ci			if (reg & (1ull << i)) {
23662306a36Sopenharmony_ci				busy = 1;
23762306a36Sopenharmony_ci				break;
23862306a36Sopenharmony_ci			}
23962306a36Sopenharmony_ci	} while (busy);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/* Disable the cores only if they are not used anymore */
24262306a36Sopenharmony_ci	reg = readq(cpt->reg_base + OTX_CPT_PF_EXE_CTL);
24362306a36Sopenharmony_ci	for_each_set_bit(i, bmap.bits, bmap.size)
24462306a36Sopenharmony_ci		if (!eng_grp->g->eng_ref_cnt[i])
24562306a36Sopenharmony_ci			reg &= ~(1ull << i);
24662306a36Sopenharmony_ci	writeq(reg, cpt->reg_base + OTX_CPT_PF_EXE_CTL);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return 0;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int cpt_attach_and_enable_cores(struct otx_cpt_eng_grp_info *eng_grp,
25262306a36Sopenharmony_ci				       void *obj)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	struct otx_cpt_device *cpt = (struct otx_cpt_device *) obj;
25562306a36Sopenharmony_ci	struct otx_cpt_bitmap bmap;
25662306a36Sopenharmony_ci	u64 reg;
25762306a36Sopenharmony_ci	int i;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	bmap = get_cores_bmap(&cpt->pdev->dev, eng_grp);
26062306a36Sopenharmony_ci	if (!bmap.size)
26162306a36Sopenharmony_ci		return -EINVAL;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* Attach the cores to the group */
26462306a36Sopenharmony_ci	reg = readq(cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx));
26562306a36Sopenharmony_ci	for_each_set_bit(i, bmap.bits, bmap.size) {
26662306a36Sopenharmony_ci		if (!(reg & (1ull << i))) {
26762306a36Sopenharmony_ci			eng_grp->g->eng_ref_cnt[i]++;
26862306a36Sopenharmony_ci			reg |= 1ull << i;
26962306a36Sopenharmony_ci		}
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci	writeq(reg, cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx));
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* Enable the cores */
27462306a36Sopenharmony_ci	reg = readq(cpt->reg_base + OTX_CPT_PF_EXE_CTL);
27562306a36Sopenharmony_ci	for_each_set_bit(i, bmap.bits, bmap.size)
27662306a36Sopenharmony_ci		reg |= 1ull << i;
27762306a36Sopenharmony_ci	writeq(reg, cpt->reg_base + OTX_CPT_PF_EXE_CTL);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return 0;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int process_tar_file(struct device *dev,
28362306a36Sopenharmony_ci			    struct tar_arch_info_t *tar_arch, char *filename,
28462306a36Sopenharmony_ci			    const u8 *data, u32 size)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct tar_ucode_info_t *tar_info;
28762306a36Sopenharmony_ci	struct otx_cpt_ucode_hdr *ucode_hdr;
28862306a36Sopenharmony_ci	int ucode_type, ucode_size;
28962306a36Sopenharmony_ci	unsigned int code_length;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/*
29262306a36Sopenharmony_ci	 * If size is less than microcode header size then don't report
29362306a36Sopenharmony_ci	 * an error because it might not be microcode file, just process
29462306a36Sopenharmony_ci	 * next file from archive
29562306a36Sopenharmony_ci	 */
29662306a36Sopenharmony_ci	if (size < sizeof(struct otx_cpt_ucode_hdr))
29762306a36Sopenharmony_ci		return 0;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	ucode_hdr = (struct otx_cpt_ucode_hdr *) data;
30062306a36Sopenharmony_ci	/*
30162306a36Sopenharmony_ci	 * If microcode version can't be found don't report an error
30262306a36Sopenharmony_ci	 * because it might not be microcode file, just process next file
30362306a36Sopenharmony_ci	 */
30462306a36Sopenharmony_ci	if (get_ucode_type(ucode_hdr, &ucode_type))
30562306a36Sopenharmony_ci		return 0;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	code_length = ntohl(ucode_hdr->code_length);
30862306a36Sopenharmony_ci	if (code_length >= INT_MAX / 2) {
30962306a36Sopenharmony_ci		dev_err(dev, "Invalid code_length %u\n", code_length);
31062306a36Sopenharmony_ci		return -EINVAL;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	ucode_size = code_length * 2;
31462306a36Sopenharmony_ci	if (!ucode_size || (size < round_up(ucode_size, 16) +
31562306a36Sopenharmony_ci	    sizeof(struct otx_cpt_ucode_hdr) + OTX_CPT_UCODE_SIGN_LEN)) {
31662306a36Sopenharmony_ci		dev_err(dev, "Ucode %s invalid size\n", filename);
31762306a36Sopenharmony_ci		return -EINVAL;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	tar_info = kzalloc(sizeof(struct tar_ucode_info_t), GFP_KERNEL);
32162306a36Sopenharmony_ci	if (!tar_info)
32262306a36Sopenharmony_ci		return -ENOMEM;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	tar_info->ucode_ptr = data;
32562306a36Sopenharmony_ci	set_ucode_filename(&tar_info->ucode, filename);
32662306a36Sopenharmony_ci	memcpy(tar_info->ucode.ver_str, ucode_hdr->ver_str,
32762306a36Sopenharmony_ci	       OTX_CPT_UCODE_VER_STR_SZ);
32862306a36Sopenharmony_ci	tar_info->ucode.ver_num = ucode_hdr->ver_num;
32962306a36Sopenharmony_ci	tar_info->ucode.type = ucode_type;
33062306a36Sopenharmony_ci	tar_info->ucode.size = ucode_size;
33162306a36Sopenharmony_ci	list_add_tail(&tar_info->list, &tar_arch->ucodes);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	return 0;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic void release_tar_archive(struct tar_arch_info_t *tar_arch)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct tar_ucode_info_t *curr, *temp;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (!tar_arch)
34162306a36Sopenharmony_ci		return;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	list_for_each_entry_safe(curr, temp, &tar_arch->ucodes, list) {
34462306a36Sopenharmony_ci		list_del(&curr->list);
34562306a36Sopenharmony_ci		kfree(curr);
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	release_firmware(tar_arch->fw);
34962306a36Sopenharmony_ci	kfree(tar_arch);
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic struct tar_ucode_info_t *get_uc_from_tar_archive(
35362306a36Sopenharmony_ci					struct tar_arch_info_t *tar_arch,
35462306a36Sopenharmony_ci					int ucode_type)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	struct tar_ucode_info_t *curr, *uc_found = NULL;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	list_for_each_entry(curr, &tar_arch->ucodes, list) {
35962306a36Sopenharmony_ci		if (!is_eng_type(curr->ucode.type, ucode_type))
36062306a36Sopenharmony_ci			continue;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci		if (!uc_found) {
36362306a36Sopenharmony_ci			uc_found = curr;
36462306a36Sopenharmony_ci			continue;
36562306a36Sopenharmony_ci		}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		switch (ucode_type) {
36862306a36Sopenharmony_ci		case OTX_CPT_AE_TYPES:
36962306a36Sopenharmony_ci			break;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		case OTX_CPT_SE_TYPES:
37262306a36Sopenharmony_ci			if (uc_found->ucode.ver_num.nn == OTX_CPT_SE_UC_TYPE2 ||
37362306a36Sopenharmony_ci			    (uc_found->ucode.ver_num.nn == OTX_CPT_SE_UC_TYPE3
37462306a36Sopenharmony_ci			     && curr->ucode.ver_num.nn == OTX_CPT_SE_UC_TYPE1))
37562306a36Sopenharmony_ci				uc_found = curr;
37662306a36Sopenharmony_ci			break;
37762306a36Sopenharmony_ci		}
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return uc_found;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic void print_tar_dbg_info(struct tar_arch_info_t *tar_arch,
38462306a36Sopenharmony_ci			       char *tar_filename)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct tar_ucode_info_t *curr;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	pr_debug("Tar archive filename %s\n", tar_filename);
38962306a36Sopenharmony_ci	pr_debug("Tar archive pointer %p, size %ld\n", tar_arch->fw->data,
39062306a36Sopenharmony_ci		 tar_arch->fw->size);
39162306a36Sopenharmony_ci	list_for_each_entry(curr, &tar_arch->ucodes, list) {
39262306a36Sopenharmony_ci		pr_debug("Ucode filename %s\n", curr->ucode.filename);
39362306a36Sopenharmony_ci		pr_debug("Ucode version string %s\n", curr->ucode.ver_str);
39462306a36Sopenharmony_ci		pr_debug("Ucode version %d.%d.%d.%d\n",
39562306a36Sopenharmony_ci			 curr->ucode.ver_num.nn, curr->ucode.ver_num.xx,
39662306a36Sopenharmony_ci			 curr->ucode.ver_num.yy, curr->ucode.ver_num.zz);
39762306a36Sopenharmony_ci		pr_debug("Ucode type (%d) %s\n", curr->ucode.type,
39862306a36Sopenharmony_ci			 get_ucode_type_str(curr->ucode.type));
39962306a36Sopenharmony_ci		pr_debug("Ucode size %d\n", curr->ucode.size);
40062306a36Sopenharmony_ci		pr_debug("Ucode ptr %p\n", curr->ucode_ptr);
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic struct tar_arch_info_t *load_tar_archive(struct device *dev,
40562306a36Sopenharmony_ci						char *tar_filename)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	struct tar_arch_info_t *tar_arch = NULL;
40862306a36Sopenharmony_ci	struct tar_blk_t *tar_blk;
40962306a36Sopenharmony_ci	unsigned int cur_size;
41062306a36Sopenharmony_ci	size_t tar_offs = 0;
41162306a36Sopenharmony_ci	size_t tar_size;
41262306a36Sopenharmony_ci	int ret;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	tar_arch = kzalloc(sizeof(struct tar_arch_info_t), GFP_KERNEL);
41562306a36Sopenharmony_ci	if (!tar_arch)
41662306a36Sopenharmony_ci		return NULL;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	INIT_LIST_HEAD(&tar_arch->ucodes);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Load tar archive */
42162306a36Sopenharmony_ci	ret = request_firmware(&tar_arch->fw, tar_filename, dev);
42262306a36Sopenharmony_ci	if (ret)
42362306a36Sopenharmony_ci		goto release_tar_arch;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	if (tar_arch->fw->size < TAR_BLOCK_LEN) {
42662306a36Sopenharmony_ci		dev_err(dev, "Invalid tar archive %s\n", tar_filename);
42762306a36Sopenharmony_ci		goto release_tar_arch;
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	tar_size = tar_arch->fw->size;
43162306a36Sopenharmony_ci	tar_blk = (struct tar_blk_t *) tar_arch->fw->data;
43262306a36Sopenharmony_ci	if (strncmp(tar_blk->hdr.magic, TAR_MAGIC, TAR_MAGIC_LEN - 1)) {
43362306a36Sopenharmony_ci		dev_err(dev, "Unsupported format of tar archive %s\n",
43462306a36Sopenharmony_ci			tar_filename);
43562306a36Sopenharmony_ci		goto release_tar_arch;
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	while (1) {
43962306a36Sopenharmony_ci		/* Read current file size */
44062306a36Sopenharmony_ci		ret = kstrtouint(tar_blk->hdr.size, 8, &cur_size);
44162306a36Sopenharmony_ci		if (ret)
44262306a36Sopenharmony_ci			goto release_tar_arch;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		if (tar_offs + cur_size > tar_size ||
44562306a36Sopenharmony_ci		    tar_offs + 2*TAR_BLOCK_LEN > tar_size) {
44662306a36Sopenharmony_ci			dev_err(dev, "Invalid tar archive %s\n", tar_filename);
44762306a36Sopenharmony_ci			goto release_tar_arch;
44862306a36Sopenharmony_ci		}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci		tar_offs += TAR_BLOCK_LEN;
45162306a36Sopenharmony_ci		if (tar_blk->hdr.typeflag == REGTYPE ||
45262306a36Sopenharmony_ci		    tar_blk->hdr.typeflag == AREGTYPE) {
45362306a36Sopenharmony_ci			ret = process_tar_file(dev, tar_arch,
45462306a36Sopenharmony_ci					       tar_blk->hdr.name,
45562306a36Sopenharmony_ci					       &tar_arch->fw->data[tar_offs],
45662306a36Sopenharmony_ci					       cur_size);
45762306a36Sopenharmony_ci			if (ret)
45862306a36Sopenharmony_ci				goto release_tar_arch;
45962306a36Sopenharmony_ci		}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		tar_offs += (cur_size/TAR_BLOCK_LEN) * TAR_BLOCK_LEN;
46262306a36Sopenharmony_ci		if (cur_size % TAR_BLOCK_LEN)
46362306a36Sopenharmony_ci			tar_offs += TAR_BLOCK_LEN;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci		/* Check for the end of the archive */
46662306a36Sopenharmony_ci		if (tar_offs + 2*TAR_BLOCK_LEN > tar_size) {
46762306a36Sopenharmony_ci			dev_err(dev, "Invalid tar archive %s\n", tar_filename);
46862306a36Sopenharmony_ci			goto release_tar_arch;
46962306a36Sopenharmony_ci		}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci		if (is_mem_zero(&tar_arch->fw->data[tar_offs],
47262306a36Sopenharmony_ci		    2*TAR_BLOCK_LEN))
47362306a36Sopenharmony_ci			break;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		/* Read next block from tar archive */
47662306a36Sopenharmony_ci		tar_blk = (struct tar_blk_t *) &tar_arch->fw->data[tar_offs];
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	print_tar_dbg_info(tar_arch, tar_filename);
48062306a36Sopenharmony_ci	return tar_arch;
48162306a36Sopenharmony_cirelease_tar_arch:
48262306a36Sopenharmony_ci	release_tar_archive(tar_arch);
48362306a36Sopenharmony_ci	return NULL;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic struct otx_cpt_engs_rsvd *find_engines_by_type(
48762306a36Sopenharmony_ci					struct otx_cpt_eng_grp_info *eng_grp,
48862306a36Sopenharmony_ci					int eng_type)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	int i;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {
49362306a36Sopenharmony_ci		if (!eng_grp->engs[i].type)
49462306a36Sopenharmony_ci			continue;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci		if (eng_grp->engs[i].type == eng_type)
49762306a36Sopenharmony_ci			return &eng_grp->engs[i];
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci	return NULL;
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ciint otx_cpt_uc_supports_eng_type(struct otx_cpt_ucode *ucode, int eng_type)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	return is_eng_type(ucode->type, eng_type);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(otx_cpt_uc_supports_eng_type);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ciint otx_cpt_eng_grp_has_eng_type(struct otx_cpt_eng_grp_info *eng_grp,
50962306a36Sopenharmony_ci				 int eng_type)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	struct otx_cpt_engs_rsvd *engs;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	engs = find_engines_by_type(eng_grp, eng_type);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	return (engs != NULL ? 1 : 0);
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(otx_cpt_eng_grp_has_eng_type);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic void print_ucode_info(struct otx_cpt_eng_grp_info *eng_grp,
52062306a36Sopenharmony_ci			     char *buf, int size)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	if (eng_grp->mirror.is_ena) {
52362306a36Sopenharmony_ci		scnprintf(buf, size, "%s (shared with engine_group%d)",
52462306a36Sopenharmony_ci			  eng_grp->g->grp[eng_grp->mirror.idx].ucode[0].ver_str,
52562306a36Sopenharmony_ci			  eng_grp->mirror.idx);
52662306a36Sopenharmony_ci	} else {
52762306a36Sopenharmony_ci		scnprintf(buf, size, "%s", eng_grp->ucode[0].ver_str);
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic void print_engs_info(struct otx_cpt_eng_grp_info *eng_grp,
53262306a36Sopenharmony_ci			    char *buf, int size, int idx)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	struct otx_cpt_engs_rsvd *mirrored_engs = NULL;
53562306a36Sopenharmony_ci	struct otx_cpt_engs_rsvd *engs;
53662306a36Sopenharmony_ci	int len, i;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	buf[0] = '\0';
53962306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {
54062306a36Sopenharmony_ci		engs = &eng_grp->engs[i];
54162306a36Sopenharmony_ci		if (!engs->type)
54262306a36Sopenharmony_ci			continue;
54362306a36Sopenharmony_ci		if (idx != -1 && idx != i)
54462306a36Sopenharmony_ci			continue;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		if (eng_grp->mirror.is_ena)
54762306a36Sopenharmony_ci			mirrored_engs = find_engines_by_type(
54862306a36Sopenharmony_ci					&eng_grp->g->grp[eng_grp->mirror.idx],
54962306a36Sopenharmony_ci					engs->type);
55062306a36Sopenharmony_ci		if (i > 0 && idx == -1) {
55162306a36Sopenharmony_ci			len = strlen(buf);
55262306a36Sopenharmony_ci			scnprintf(buf+len, size-len, ", ");
55362306a36Sopenharmony_ci		}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		len = strlen(buf);
55662306a36Sopenharmony_ci		scnprintf(buf+len, size-len, "%d %s ", mirrored_engs ?
55762306a36Sopenharmony_ci			  engs->count + mirrored_engs->count : engs->count,
55862306a36Sopenharmony_ci			  get_eng_type_str(engs->type));
55962306a36Sopenharmony_ci		if (mirrored_engs) {
56062306a36Sopenharmony_ci			len = strlen(buf);
56162306a36Sopenharmony_ci			scnprintf(buf+len, size-len,
56262306a36Sopenharmony_ci				  "(%d shared with engine_group%d) ",
56362306a36Sopenharmony_ci				  engs->count <= 0 ? engs->count +
56462306a36Sopenharmony_ci				  mirrored_engs->count : mirrored_engs->count,
56562306a36Sopenharmony_ci				  eng_grp->mirror.idx);
56662306a36Sopenharmony_ci		}
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic void print_ucode_dbg_info(struct otx_cpt_ucode *ucode)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	pr_debug("Ucode info\n");
57362306a36Sopenharmony_ci	pr_debug("Ucode version string %s\n", ucode->ver_str);
57462306a36Sopenharmony_ci	pr_debug("Ucode version %d.%d.%d.%d\n", ucode->ver_num.nn,
57562306a36Sopenharmony_ci		 ucode->ver_num.xx, ucode->ver_num.yy, ucode->ver_num.zz);
57662306a36Sopenharmony_ci	pr_debug("Ucode type %s\n", get_ucode_type_str(ucode->type));
57762306a36Sopenharmony_ci	pr_debug("Ucode size %d\n", ucode->size);
57862306a36Sopenharmony_ci	pr_debug("Ucode virt address %16.16llx\n", (u64)ucode->align_va);
57962306a36Sopenharmony_ci	pr_debug("Ucode phys address %16.16llx\n", ucode->align_dma);
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic void cpt_print_engines_mask(struct otx_cpt_eng_grp_info *eng_grp,
58362306a36Sopenharmony_ci				   struct device *dev, char *buf, int size)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct otx_cpt_bitmap bmap;
58662306a36Sopenharmony_ci	u32 mask[2];
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	bmap = get_cores_bmap(dev, eng_grp);
58962306a36Sopenharmony_ci	if (!bmap.size) {
59062306a36Sopenharmony_ci		scnprintf(buf, size, "unknown");
59162306a36Sopenharmony_ci		return;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci	bitmap_to_arr32(mask, bmap.bits, bmap.size);
59462306a36Sopenharmony_ci	scnprintf(buf, size, "%8.8x %8.8x", mask[1], mask[0]);
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic void print_dbg_info(struct device *dev,
59962306a36Sopenharmony_ci			   struct otx_cpt_eng_grps *eng_grps)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	char engs_info[2*OTX_CPT_UCODE_NAME_LENGTH];
60262306a36Sopenharmony_ci	struct otx_cpt_eng_grp_info *mirrored_grp;
60362306a36Sopenharmony_ci	char engs_mask[OTX_CPT_UCODE_NAME_LENGTH];
60462306a36Sopenharmony_ci	struct otx_cpt_eng_grp_info *grp;
60562306a36Sopenharmony_ci	struct otx_cpt_engs_rsvd *engs;
60662306a36Sopenharmony_ci	u32 mask[4];
60762306a36Sopenharmony_ci	int i, j;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	pr_debug("Engine groups global info\n");
61062306a36Sopenharmony_ci	pr_debug("max SE %d, max AE %d\n",
61162306a36Sopenharmony_ci		 eng_grps->avail.max_se_cnt, eng_grps->avail.max_ae_cnt);
61262306a36Sopenharmony_ci	pr_debug("free SE %d\n", eng_grps->avail.se_cnt);
61362306a36Sopenharmony_ci	pr_debug("free AE %d\n", eng_grps->avail.ae_cnt);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {
61662306a36Sopenharmony_ci		grp = &eng_grps->grp[i];
61762306a36Sopenharmony_ci		pr_debug("engine_group%d, state %s\n", i, grp->is_enabled ?
61862306a36Sopenharmony_ci			 "enabled" : "disabled");
61962306a36Sopenharmony_ci		if (grp->is_enabled) {
62062306a36Sopenharmony_ci			mirrored_grp = &eng_grps->grp[grp->mirror.idx];
62162306a36Sopenharmony_ci			pr_debug("Ucode0 filename %s, version %s\n",
62262306a36Sopenharmony_ci				 grp->mirror.is_ena ?
62362306a36Sopenharmony_ci				 mirrored_grp->ucode[0].filename :
62462306a36Sopenharmony_ci				 grp->ucode[0].filename,
62562306a36Sopenharmony_ci				 grp->mirror.is_ena ?
62662306a36Sopenharmony_ci				 mirrored_grp->ucode[0].ver_str :
62762306a36Sopenharmony_ci				 grp->ucode[0].ver_str);
62862306a36Sopenharmony_ci		}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci		for (j = 0; j < OTX_CPT_MAX_ETYPES_PER_GRP; j++) {
63162306a36Sopenharmony_ci			engs = &grp->engs[j];
63262306a36Sopenharmony_ci			if (engs->type) {
63362306a36Sopenharmony_ci				print_engs_info(grp, engs_info,
63462306a36Sopenharmony_ci						2*OTX_CPT_UCODE_NAME_LENGTH, j);
63562306a36Sopenharmony_ci				pr_debug("Slot%d: %s\n", j, engs_info);
63662306a36Sopenharmony_ci				bitmap_to_arr32(mask, engs->bmap,
63762306a36Sopenharmony_ci						eng_grps->engs_num);
63862306a36Sopenharmony_ci				pr_debug("Mask: %8.8x %8.8x %8.8x %8.8x\n",
63962306a36Sopenharmony_ci					 mask[3], mask[2], mask[1], mask[0]);
64062306a36Sopenharmony_ci			} else
64162306a36Sopenharmony_ci				pr_debug("Slot%d not used\n", j);
64262306a36Sopenharmony_ci		}
64362306a36Sopenharmony_ci		if (grp->is_enabled) {
64462306a36Sopenharmony_ci			cpt_print_engines_mask(grp, dev, engs_mask,
64562306a36Sopenharmony_ci					       OTX_CPT_UCODE_NAME_LENGTH);
64662306a36Sopenharmony_ci			pr_debug("Cmask: %s\n", engs_mask);
64762306a36Sopenharmony_ci		}
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic int update_engines_avail_count(struct device *dev,
65262306a36Sopenharmony_ci				      struct otx_cpt_engs_available *avail,
65362306a36Sopenharmony_ci				      struct otx_cpt_engs_rsvd *engs, int val)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	switch (engs->type) {
65662306a36Sopenharmony_ci	case OTX_CPT_SE_TYPES:
65762306a36Sopenharmony_ci		avail->se_cnt += val;
65862306a36Sopenharmony_ci		break;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	case OTX_CPT_AE_TYPES:
66162306a36Sopenharmony_ci		avail->ae_cnt += val;
66262306a36Sopenharmony_ci		break;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	default:
66562306a36Sopenharmony_ci		dev_err(dev, "Invalid engine type %d\n", engs->type);
66662306a36Sopenharmony_ci		return -EINVAL;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	return 0;
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic int update_engines_offset(struct device *dev,
67362306a36Sopenharmony_ci				 struct otx_cpt_engs_available *avail,
67462306a36Sopenharmony_ci				 struct otx_cpt_engs_rsvd *engs)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	switch (engs->type) {
67762306a36Sopenharmony_ci	case OTX_CPT_SE_TYPES:
67862306a36Sopenharmony_ci		engs->offset = 0;
67962306a36Sopenharmony_ci		break;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	case OTX_CPT_AE_TYPES:
68262306a36Sopenharmony_ci		engs->offset = avail->max_se_cnt;
68362306a36Sopenharmony_ci		break;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	default:
68662306a36Sopenharmony_ci		dev_err(dev, "Invalid engine type %d\n", engs->type);
68762306a36Sopenharmony_ci		return -EINVAL;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	return 0;
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cistatic int release_engines(struct device *dev, struct otx_cpt_eng_grp_info *grp)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	int i, ret = 0;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {
69862306a36Sopenharmony_ci		if (!grp->engs[i].type)
69962306a36Sopenharmony_ci			continue;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci		if (grp->engs[i].count > 0) {
70262306a36Sopenharmony_ci			ret = update_engines_avail_count(dev, &grp->g->avail,
70362306a36Sopenharmony_ci							 &grp->engs[i],
70462306a36Sopenharmony_ci							 grp->engs[i].count);
70562306a36Sopenharmony_ci			if (ret)
70662306a36Sopenharmony_ci				return ret;
70762306a36Sopenharmony_ci		}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		grp->engs[i].type = 0;
71062306a36Sopenharmony_ci		grp->engs[i].count = 0;
71162306a36Sopenharmony_ci		grp->engs[i].offset = 0;
71262306a36Sopenharmony_ci		grp->engs[i].ucode = NULL;
71362306a36Sopenharmony_ci		bitmap_zero(grp->engs[i].bmap, grp->g->engs_num);
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	return 0;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic int do_reserve_engines(struct device *dev,
72062306a36Sopenharmony_ci			      struct otx_cpt_eng_grp_info *grp,
72162306a36Sopenharmony_ci			      struct otx_cpt_engines *req_engs)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	struct otx_cpt_engs_rsvd *engs = NULL;
72462306a36Sopenharmony_ci	int i, ret;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {
72762306a36Sopenharmony_ci		if (!grp->engs[i].type) {
72862306a36Sopenharmony_ci			engs = &grp->engs[i];
72962306a36Sopenharmony_ci			break;
73062306a36Sopenharmony_ci		}
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	if (!engs)
73462306a36Sopenharmony_ci		return -ENOMEM;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	engs->type = req_engs->type;
73762306a36Sopenharmony_ci	engs->count = req_engs->count;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	ret = update_engines_offset(dev, &grp->g->avail, engs);
74062306a36Sopenharmony_ci	if (ret)
74162306a36Sopenharmony_ci		return ret;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	if (engs->count > 0) {
74462306a36Sopenharmony_ci		ret = update_engines_avail_count(dev, &grp->g->avail, engs,
74562306a36Sopenharmony_ci						 -engs->count);
74662306a36Sopenharmony_ci		if (ret)
74762306a36Sopenharmony_ci			return ret;
74862306a36Sopenharmony_ci	}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	return 0;
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic int check_engines_availability(struct device *dev,
75462306a36Sopenharmony_ci				      struct otx_cpt_eng_grp_info *grp,
75562306a36Sopenharmony_ci				      struct otx_cpt_engines *req_eng)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	int avail_cnt = 0;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	switch (req_eng->type) {
76062306a36Sopenharmony_ci	case OTX_CPT_SE_TYPES:
76162306a36Sopenharmony_ci		avail_cnt = grp->g->avail.se_cnt;
76262306a36Sopenharmony_ci		break;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	case OTX_CPT_AE_TYPES:
76562306a36Sopenharmony_ci		avail_cnt = grp->g->avail.ae_cnt;
76662306a36Sopenharmony_ci		break;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	default:
76962306a36Sopenharmony_ci		dev_err(dev, "Invalid engine type %d\n", req_eng->type);
77062306a36Sopenharmony_ci		return -EINVAL;
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	if (avail_cnt < req_eng->count) {
77462306a36Sopenharmony_ci		dev_err(dev,
77562306a36Sopenharmony_ci			"Error available %s engines %d < than requested %d\n",
77662306a36Sopenharmony_ci			get_eng_type_str(req_eng->type),
77762306a36Sopenharmony_ci			avail_cnt, req_eng->count);
77862306a36Sopenharmony_ci		return -EBUSY;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	return 0;
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_cistatic int reserve_engines(struct device *dev, struct otx_cpt_eng_grp_info *grp,
78562306a36Sopenharmony_ci			   struct otx_cpt_engines *req_engs, int req_cnt)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	int i, ret;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	/* Validate if a number of requested engines is available */
79062306a36Sopenharmony_ci	for (i = 0; i < req_cnt; i++) {
79162306a36Sopenharmony_ci		ret = check_engines_availability(dev, grp, &req_engs[i]);
79262306a36Sopenharmony_ci		if (ret)
79362306a36Sopenharmony_ci			return ret;
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	/* Reserve requested engines for this engine group */
79762306a36Sopenharmony_ci	for (i = 0; i < req_cnt; i++) {
79862306a36Sopenharmony_ci		ret = do_reserve_engines(dev, grp, &req_engs[i]);
79962306a36Sopenharmony_ci		if (ret)
80062306a36Sopenharmony_ci			return ret;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci	return 0;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic ssize_t eng_grp_info_show(struct device *dev,
80662306a36Sopenharmony_ci				 struct device_attribute *attr,
80762306a36Sopenharmony_ci				 char *buf)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	char ucode_info[2*OTX_CPT_UCODE_NAME_LENGTH];
81062306a36Sopenharmony_ci	char engs_info[2*OTX_CPT_UCODE_NAME_LENGTH];
81162306a36Sopenharmony_ci	char engs_mask[OTX_CPT_UCODE_NAME_LENGTH];
81262306a36Sopenharmony_ci	struct otx_cpt_eng_grp_info *eng_grp;
81362306a36Sopenharmony_ci	int ret;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	eng_grp = container_of(attr, struct otx_cpt_eng_grp_info, info_attr);
81662306a36Sopenharmony_ci	mutex_lock(&eng_grp->g->lock);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	print_engs_info(eng_grp, engs_info, 2*OTX_CPT_UCODE_NAME_LENGTH, -1);
81962306a36Sopenharmony_ci	print_ucode_info(eng_grp, ucode_info, 2*OTX_CPT_UCODE_NAME_LENGTH);
82062306a36Sopenharmony_ci	cpt_print_engines_mask(eng_grp, dev, engs_mask,
82162306a36Sopenharmony_ci			       OTX_CPT_UCODE_NAME_LENGTH);
82262306a36Sopenharmony_ci	ret = scnprintf(buf, PAGE_SIZE,
82362306a36Sopenharmony_ci			"Microcode : %s\nEngines: %s\nEngines mask: %s\n",
82462306a36Sopenharmony_ci			ucode_info, engs_info, engs_mask);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	mutex_unlock(&eng_grp->g->lock);
82762306a36Sopenharmony_ci	return ret;
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic int create_sysfs_eng_grps_info(struct device *dev,
83162306a36Sopenharmony_ci				      struct otx_cpt_eng_grp_info *eng_grp)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	eng_grp->info_attr.show = eng_grp_info_show;
83462306a36Sopenharmony_ci	eng_grp->info_attr.store = NULL;
83562306a36Sopenharmony_ci	eng_grp->info_attr.attr.name = eng_grp->sysfs_info_name;
83662306a36Sopenharmony_ci	eng_grp->info_attr.attr.mode = 0440;
83762306a36Sopenharmony_ci	sysfs_attr_init(&eng_grp->info_attr.attr);
83862306a36Sopenharmony_ci	return device_create_file(dev, &eng_grp->info_attr);
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic void ucode_unload(struct device *dev, struct otx_cpt_ucode *ucode)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	if (ucode->va) {
84462306a36Sopenharmony_ci		dma_free_coherent(dev, ucode->size + OTX_CPT_UCODE_ALIGNMENT,
84562306a36Sopenharmony_ci				  ucode->va, ucode->dma);
84662306a36Sopenharmony_ci		ucode->va = NULL;
84762306a36Sopenharmony_ci		ucode->align_va = NULL;
84862306a36Sopenharmony_ci		ucode->dma = 0;
84962306a36Sopenharmony_ci		ucode->align_dma = 0;
85062306a36Sopenharmony_ci		ucode->size = 0;
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	memset(&ucode->ver_str, 0, OTX_CPT_UCODE_VER_STR_SZ);
85462306a36Sopenharmony_ci	memset(&ucode->ver_num, 0, sizeof(struct otx_cpt_ucode_ver_num));
85562306a36Sopenharmony_ci	set_ucode_filename(ucode, "");
85662306a36Sopenharmony_ci	ucode->type = 0;
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_cistatic int copy_ucode_to_dma_mem(struct device *dev,
86062306a36Sopenharmony_ci				 struct otx_cpt_ucode *ucode,
86162306a36Sopenharmony_ci				 const u8 *ucode_data)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	u32 i;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/*  Allocate DMAable space */
86662306a36Sopenharmony_ci	ucode->va = dma_alloc_coherent(dev, ucode->size +
86762306a36Sopenharmony_ci				       OTX_CPT_UCODE_ALIGNMENT,
86862306a36Sopenharmony_ci				       &ucode->dma, GFP_KERNEL);
86962306a36Sopenharmony_ci	if (!ucode->va) {
87062306a36Sopenharmony_ci		dev_err(dev, "Unable to allocate space for microcode\n");
87162306a36Sopenharmony_ci		return -ENOMEM;
87262306a36Sopenharmony_ci	}
87362306a36Sopenharmony_ci	ucode->align_va = PTR_ALIGN(ucode->va, OTX_CPT_UCODE_ALIGNMENT);
87462306a36Sopenharmony_ci	ucode->align_dma = PTR_ALIGN(ucode->dma, OTX_CPT_UCODE_ALIGNMENT);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	memcpy((void *) ucode->align_va, (void *) ucode_data +
87762306a36Sopenharmony_ci	       sizeof(struct otx_cpt_ucode_hdr), ucode->size);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/* Byte swap 64-bit */
88062306a36Sopenharmony_ci	for (i = 0; i < (ucode->size / 8); i++)
88162306a36Sopenharmony_ci		((__be64 *)ucode->align_va)[i] =
88262306a36Sopenharmony_ci				cpu_to_be64(((u64 *)ucode->align_va)[i]);
88362306a36Sopenharmony_ci	/*  Ucode needs 16-bit swap */
88462306a36Sopenharmony_ci	for (i = 0; i < (ucode->size / 2); i++)
88562306a36Sopenharmony_ci		((__be16 *)ucode->align_va)[i] =
88662306a36Sopenharmony_ci				cpu_to_be16(((u16 *)ucode->align_va)[i]);
88762306a36Sopenharmony_ci	return 0;
88862306a36Sopenharmony_ci}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_cistatic int ucode_load(struct device *dev, struct otx_cpt_ucode *ucode,
89162306a36Sopenharmony_ci		      const char *ucode_filename)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	struct otx_cpt_ucode_hdr *ucode_hdr;
89462306a36Sopenharmony_ci	const struct firmware *fw;
89562306a36Sopenharmony_ci	unsigned int code_length;
89662306a36Sopenharmony_ci	int ret;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	set_ucode_filename(ucode, ucode_filename);
89962306a36Sopenharmony_ci	ret = request_firmware(&fw, ucode->filename, dev);
90062306a36Sopenharmony_ci	if (ret)
90162306a36Sopenharmony_ci		return ret;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	ucode_hdr = (struct otx_cpt_ucode_hdr *) fw->data;
90462306a36Sopenharmony_ci	memcpy(ucode->ver_str, ucode_hdr->ver_str, OTX_CPT_UCODE_VER_STR_SZ);
90562306a36Sopenharmony_ci	ucode->ver_num = ucode_hdr->ver_num;
90662306a36Sopenharmony_ci	code_length = ntohl(ucode_hdr->code_length);
90762306a36Sopenharmony_ci	if (code_length >= INT_MAX / 2) {
90862306a36Sopenharmony_ci		dev_err(dev, "Ucode invalid code_length %u\n", code_length);
90962306a36Sopenharmony_ci		ret = -EINVAL;
91062306a36Sopenharmony_ci		goto release_fw;
91162306a36Sopenharmony_ci	}
91262306a36Sopenharmony_ci	ucode->size = code_length * 2;
91362306a36Sopenharmony_ci	if (!ucode->size || (fw->size < round_up(ucode->size, 16)
91462306a36Sopenharmony_ci	    + sizeof(struct otx_cpt_ucode_hdr) + OTX_CPT_UCODE_SIGN_LEN)) {
91562306a36Sopenharmony_ci		dev_err(dev, "Ucode %s invalid size\n", ucode_filename);
91662306a36Sopenharmony_ci		ret = -EINVAL;
91762306a36Sopenharmony_ci		goto release_fw;
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	ret = get_ucode_type(ucode_hdr, &ucode->type);
92162306a36Sopenharmony_ci	if (ret) {
92262306a36Sopenharmony_ci		dev_err(dev, "Microcode %s unknown type 0x%x\n",
92362306a36Sopenharmony_ci			ucode->filename, ucode->type);
92462306a36Sopenharmony_ci		goto release_fw;
92562306a36Sopenharmony_ci	}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	ret = copy_ucode_to_dma_mem(dev, ucode, fw->data);
92862306a36Sopenharmony_ci	if (ret)
92962306a36Sopenharmony_ci		goto release_fw;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	print_ucode_dbg_info(ucode);
93262306a36Sopenharmony_cirelease_fw:
93362306a36Sopenharmony_ci	release_firmware(fw);
93462306a36Sopenharmony_ci	return ret;
93562306a36Sopenharmony_ci}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_cistatic int enable_eng_grp(struct otx_cpt_eng_grp_info *eng_grp,
93862306a36Sopenharmony_ci			  void *obj)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	int ret;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	ret = cpt_set_ucode_base(eng_grp, obj);
94362306a36Sopenharmony_ci	if (ret)
94462306a36Sopenharmony_ci		return ret;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	ret = cpt_attach_and_enable_cores(eng_grp, obj);
94762306a36Sopenharmony_ci	return ret;
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic int disable_eng_grp(struct device *dev,
95162306a36Sopenharmony_ci			   struct otx_cpt_eng_grp_info *eng_grp,
95262306a36Sopenharmony_ci			   void *obj)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	int i, ret;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	ret = cpt_detach_and_disable_cores(eng_grp, obj);
95762306a36Sopenharmony_ci	if (ret)
95862306a36Sopenharmony_ci		return ret;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	/* Unload ucode used by this engine group */
96162306a36Sopenharmony_ci	ucode_unload(dev, &eng_grp->ucode[0]);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {
96462306a36Sopenharmony_ci		if (!eng_grp->engs[i].type)
96562306a36Sopenharmony_ci			continue;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci		eng_grp->engs[i].ucode = &eng_grp->ucode[0];
96862306a36Sopenharmony_ci	}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	ret = cpt_set_ucode_base(eng_grp, obj);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	return ret;
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic void setup_eng_grp_mirroring(struct otx_cpt_eng_grp_info *dst_grp,
97662306a36Sopenharmony_ci				    struct otx_cpt_eng_grp_info *src_grp)
97762306a36Sopenharmony_ci{
97862306a36Sopenharmony_ci	/* Setup fields for engine group which is mirrored */
97962306a36Sopenharmony_ci	src_grp->mirror.is_ena = false;
98062306a36Sopenharmony_ci	src_grp->mirror.idx = 0;
98162306a36Sopenharmony_ci	src_grp->mirror.ref_count++;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	/* Setup fields for mirroring engine group */
98462306a36Sopenharmony_ci	dst_grp->mirror.is_ena = true;
98562306a36Sopenharmony_ci	dst_grp->mirror.idx = src_grp->idx;
98662306a36Sopenharmony_ci	dst_grp->mirror.ref_count = 0;
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic void remove_eng_grp_mirroring(struct otx_cpt_eng_grp_info *dst_grp)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	struct otx_cpt_eng_grp_info *src_grp;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	if (!dst_grp->mirror.is_ena)
99462306a36Sopenharmony_ci		return;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	src_grp = &dst_grp->g->grp[dst_grp->mirror.idx];
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	src_grp->mirror.ref_count--;
99962306a36Sopenharmony_ci	dst_grp->mirror.is_ena = false;
100062306a36Sopenharmony_ci	dst_grp->mirror.idx = 0;
100162306a36Sopenharmony_ci	dst_grp->mirror.ref_count = 0;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic void update_requested_engs(struct otx_cpt_eng_grp_info *mirrored_eng_grp,
100562306a36Sopenharmony_ci				  struct otx_cpt_engines *engs, int engs_cnt)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	struct otx_cpt_engs_rsvd *mirrored_engs;
100862306a36Sopenharmony_ci	int i;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	for (i = 0; i < engs_cnt; i++) {
101162306a36Sopenharmony_ci		mirrored_engs = find_engines_by_type(mirrored_eng_grp,
101262306a36Sopenharmony_ci						     engs[i].type);
101362306a36Sopenharmony_ci		if (!mirrored_engs)
101462306a36Sopenharmony_ci			continue;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci		/*
101762306a36Sopenharmony_ci		 * If mirrored group has this type of engines attached then
101862306a36Sopenharmony_ci		 * there are 3 scenarios possible:
101962306a36Sopenharmony_ci		 * 1) mirrored_engs.count == engs[i].count then all engines
102062306a36Sopenharmony_ci		 * from mirrored engine group will be shared with this engine
102162306a36Sopenharmony_ci		 * group
102262306a36Sopenharmony_ci		 * 2) mirrored_engs.count > engs[i].count then only a subset of
102362306a36Sopenharmony_ci		 * engines from mirrored engine group will be shared with this
102462306a36Sopenharmony_ci		 * engine group
102562306a36Sopenharmony_ci		 * 3) mirrored_engs.count < engs[i].count then all engines
102662306a36Sopenharmony_ci		 * from mirrored engine group will be shared with this group
102762306a36Sopenharmony_ci		 * and additional engines will be reserved for exclusively use
102862306a36Sopenharmony_ci		 * by this engine group
102962306a36Sopenharmony_ci		 */
103062306a36Sopenharmony_ci		engs[i].count -= mirrored_engs->count;
103162306a36Sopenharmony_ci	}
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_cistatic struct otx_cpt_eng_grp_info *find_mirrored_eng_grp(
103562306a36Sopenharmony_ci					struct otx_cpt_eng_grp_info *grp)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	struct otx_cpt_eng_grps *eng_grps = grp->g;
103862306a36Sopenharmony_ci	int i;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {
104162306a36Sopenharmony_ci		if (!eng_grps->grp[i].is_enabled)
104262306a36Sopenharmony_ci			continue;
104362306a36Sopenharmony_ci		if (eng_grps->grp[i].ucode[0].type)
104462306a36Sopenharmony_ci			continue;
104562306a36Sopenharmony_ci		if (grp->idx == i)
104662306a36Sopenharmony_ci			continue;
104762306a36Sopenharmony_ci		if (!strncasecmp(eng_grps->grp[i].ucode[0].ver_str,
104862306a36Sopenharmony_ci				 grp->ucode[0].ver_str,
104962306a36Sopenharmony_ci				 OTX_CPT_UCODE_VER_STR_SZ))
105062306a36Sopenharmony_ci			return &eng_grps->grp[i];
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	return NULL;
105462306a36Sopenharmony_ci}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_cistatic struct otx_cpt_eng_grp_info *find_unused_eng_grp(
105762306a36Sopenharmony_ci					struct otx_cpt_eng_grps *eng_grps)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	int i;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {
106262306a36Sopenharmony_ci		if (!eng_grps->grp[i].is_enabled)
106362306a36Sopenharmony_ci			return &eng_grps->grp[i];
106462306a36Sopenharmony_ci	}
106562306a36Sopenharmony_ci	return NULL;
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_cistatic int eng_grp_update_masks(struct device *dev,
106962306a36Sopenharmony_ci				struct otx_cpt_eng_grp_info *eng_grp)
107062306a36Sopenharmony_ci{
107162306a36Sopenharmony_ci	struct otx_cpt_engs_rsvd *engs, *mirrored_engs;
107262306a36Sopenharmony_ci	struct otx_cpt_bitmap tmp_bmap = { {0} };
107362306a36Sopenharmony_ci	int i, j, cnt, max_cnt;
107462306a36Sopenharmony_ci	int bit;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {
107762306a36Sopenharmony_ci		engs = &eng_grp->engs[i];
107862306a36Sopenharmony_ci		if (!engs->type)
107962306a36Sopenharmony_ci			continue;
108062306a36Sopenharmony_ci		if (engs->count <= 0)
108162306a36Sopenharmony_ci			continue;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci		switch (engs->type) {
108462306a36Sopenharmony_ci		case OTX_CPT_SE_TYPES:
108562306a36Sopenharmony_ci			max_cnt = eng_grp->g->avail.max_se_cnt;
108662306a36Sopenharmony_ci			break;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci		case OTX_CPT_AE_TYPES:
108962306a36Sopenharmony_ci			max_cnt = eng_grp->g->avail.max_ae_cnt;
109062306a36Sopenharmony_ci			break;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci		default:
109362306a36Sopenharmony_ci			dev_err(dev, "Invalid engine type %d\n", engs->type);
109462306a36Sopenharmony_ci			return -EINVAL;
109562306a36Sopenharmony_ci		}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci		cnt = engs->count;
109862306a36Sopenharmony_ci		WARN_ON(engs->offset + max_cnt > OTX_CPT_MAX_ENGINES);
109962306a36Sopenharmony_ci		bitmap_zero(tmp_bmap.bits, eng_grp->g->engs_num);
110062306a36Sopenharmony_ci		for (j = engs->offset; j < engs->offset + max_cnt; j++) {
110162306a36Sopenharmony_ci			if (!eng_grp->g->eng_ref_cnt[j]) {
110262306a36Sopenharmony_ci				bitmap_set(tmp_bmap.bits, j, 1);
110362306a36Sopenharmony_ci				cnt--;
110462306a36Sopenharmony_ci				if (!cnt)
110562306a36Sopenharmony_ci					break;
110662306a36Sopenharmony_ci			}
110762306a36Sopenharmony_ci		}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci		if (cnt)
111062306a36Sopenharmony_ci			return -ENOSPC;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci		bitmap_copy(engs->bmap, tmp_bmap.bits, eng_grp->g->engs_num);
111362306a36Sopenharmony_ci	}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	if (!eng_grp->mirror.is_ena)
111662306a36Sopenharmony_ci		return 0;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {
111962306a36Sopenharmony_ci		engs = &eng_grp->engs[i];
112062306a36Sopenharmony_ci		if (!engs->type)
112162306a36Sopenharmony_ci			continue;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci		mirrored_engs = find_engines_by_type(
112462306a36Sopenharmony_ci					&eng_grp->g->grp[eng_grp->mirror.idx],
112562306a36Sopenharmony_ci					engs->type);
112662306a36Sopenharmony_ci		WARN_ON(!mirrored_engs && engs->count <= 0);
112762306a36Sopenharmony_ci		if (!mirrored_engs)
112862306a36Sopenharmony_ci			continue;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci		bitmap_copy(tmp_bmap.bits, mirrored_engs->bmap,
113162306a36Sopenharmony_ci			    eng_grp->g->engs_num);
113262306a36Sopenharmony_ci		if (engs->count < 0) {
113362306a36Sopenharmony_ci			bit = find_first_bit(mirrored_engs->bmap,
113462306a36Sopenharmony_ci					     eng_grp->g->engs_num);
113562306a36Sopenharmony_ci			bitmap_clear(tmp_bmap.bits, bit, -engs->count);
113662306a36Sopenharmony_ci		}
113762306a36Sopenharmony_ci		bitmap_or(engs->bmap, engs->bmap, tmp_bmap.bits,
113862306a36Sopenharmony_ci			  eng_grp->g->engs_num);
113962306a36Sopenharmony_ci	}
114062306a36Sopenharmony_ci	return 0;
114162306a36Sopenharmony_ci}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_cistatic int delete_engine_group(struct device *dev,
114462306a36Sopenharmony_ci			       struct otx_cpt_eng_grp_info *eng_grp)
114562306a36Sopenharmony_ci{
114662306a36Sopenharmony_ci	int i, ret;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	if (!eng_grp->is_enabled)
114962306a36Sopenharmony_ci		return -EINVAL;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	if (eng_grp->mirror.ref_count) {
115262306a36Sopenharmony_ci		dev_err(dev, "Can't delete engine_group%d as it is used by engine_group(s):",
115362306a36Sopenharmony_ci			eng_grp->idx);
115462306a36Sopenharmony_ci		for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {
115562306a36Sopenharmony_ci			if (eng_grp->g->grp[i].mirror.is_ena &&
115662306a36Sopenharmony_ci			    eng_grp->g->grp[i].mirror.idx == eng_grp->idx)
115762306a36Sopenharmony_ci				pr_cont(" %d", i);
115862306a36Sopenharmony_ci		}
115962306a36Sopenharmony_ci		pr_cont("\n");
116062306a36Sopenharmony_ci		return -EINVAL;
116162306a36Sopenharmony_ci	}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	/* Removing engine group mirroring if enabled */
116462306a36Sopenharmony_ci	remove_eng_grp_mirroring(eng_grp);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	/* Disable engine group */
116762306a36Sopenharmony_ci	ret = disable_eng_grp(dev, eng_grp, eng_grp->g->obj);
116862306a36Sopenharmony_ci	if (ret)
116962306a36Sopenharmony_ci		return ret;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	/* Release all engines held by this engine group */
117262306a36Sopenharmony_ci	ret = release_engines(dev, eng_grp);
117362306a36Sopenharmony_ci	if (ret)
117462306a36Sopenharmony_ci		return ret;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	device_remove_file(dev, &eng_grp->info_attr);
117762306a36Sopenharmony_ci	eng_grp->is_enabled = false;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	return 0;
118062306a36Sopenharmony_ci}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_cistatic int validate_1_ucode_scenario(struct device *dev,
118362306a36Sopenharmony_ci				     struct otx_cpt_eng_grp_info *eng_grp,
118462306a36Sopenharmony_ci				     struct otx_cpt_engines *engs, int engs_cnt)
118562306a36Sopenharmony_ci{
118662306a36Sopenharmony_ci	int i;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	/* Verify that ucode loaded supports requested engine types */
118962306a36Sopenharmony_ci	for (i = 0; i < engs_cnt; i++) {
119062306a36Sopenharmony_ci		if (!otx_cpt_uc_supports_eng_type(&eng_grp->ucode[0],
119162306a36Sopenharmony_ci						  engs[i].type)) {
119262306a36Sopenharmony_ci			dev_err(dev,
119362306a36Sopenharmony_ci				"Microcode %s does not support %s engines\n",
119462306a36Sopenharmony_ci				eng_grp->ucode[0].filename,
119562306a36Sopenharmony_ci				get_eng_type_str(engs[i].type));
119662306a36Sopenharmony_ci			return -EINVAL;
119762306a36Sopenharmony_ci		}
119862306a36Sopenharmony_ci	}
119962306a36Sopenharmony_ci	return 0;
120062306a36Sopenharmony_ci}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistatic void update_ucode_ptrs(struct otx_cpt_eng_grp_info *eng_grp)
120362306a36Sopenharmony_ci{
120462306a36Sopenharmony_ci	struct otx_cpt_ucode *ucode;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	if (eng_grp->mirror.is_ena)
120762306a36Sopenharmony_ci		ucode = &eng_grp->g->grp[eng_grp->mirror.idx].ucode[0];
120862306a36Sopenharmony_ci	else
120962306a36Sopenharmony_ci		ucode = &eng_grp->ucode[0];
121062306a36Sopenharmony_ci	WARN_ON(!eng_grp->engs[0].type);
121162306a36Sopenharmony_ci	eng_grp->engs[0].ucode = ucode;
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_cistatic int create_engine_group(struct device *dev,
121562306a36Sopenharmony_ci			       struct otx_cpt_eng_grps *eng_grps,
121662306a36Sopenharmony_ci			       struct otx_cpt_engines *engs, int engs_cnt,
121762306a36Sopenharmony_ci			       void *ucode_data[], int ucodes_cnt,
121862306a36Sopenharmony_ci			       bool use_uc_from_tar_arch)
121962306a36Sopenharmony_ci{
122062306a36Sopenharmony_ci	struct otx_cpt_eng_grp_info *mirrored_eng_grp;
122162306a36Sopenharmony_ci	struct tar_ucode_info_t *tar_info;
122262306a36Sopenharmony_ci	struct otx_cpt_eng_grp_info *eng_grp;
122362306a36Sopenharmony_ci	int i, ret = 0;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	if (ucodes_cnt > OTX_CPT_MAX_ETYPES_PER_GRP)
122662306a36Sopenharmony_ci		return -EINVAL;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	/* Validate if requested engine types are supported by this device */
122962306a36Sopenharmony_ci	for (i = 0; i < engs_cnt; i++)
123062306a36Sopenharmony_ci		if (!dev_supports_eng_type(eng_grps, engs[i].type)) {
123162306a36Sopenharmony_ci			dev_err(dev, "Device does not support %s engines\n",
123262306a36Sopenharmony_ci				get_eng_type_str(engs[i].type));
123362306a36Sopenharmony_ci			return -EPERM;
123462306a36Sopenharmony_ci		}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	/* Find engine group which is not used */
123762306a36Sopenharmony_ci	eng_grp = find_unused_eng_grp(eng_grps);
123862306a36Sopenharmony_ci	if (!eng_grp) {
123962306a36Sopenharmony_ci		dev_err(dev, "Error all engine groups are being used\n");
124062306a36Sopenharmony_ci		return -ENOSPC;
124162306a36Sopenharmony_ci	}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	/* Load ucode */
124462306a36Sopenharmony_ci	for (i = 0; i < ucodes_cnt; i++) {
124562306a36Sopenharmony_ci		if (use_uc_from_tar_arch) {
124662306a36Sopenharmony_ci			tar_info = (struct tar_ucode_info_t *) ucode_data[i];
124762306a36Sopenharmony_ci			eng_grp->ucode[i] = tar_info->ucode;
124862306a36Sopenharmony_ci			ret = copy_ucode_to_dma_mem(dev, &eng_grp->ucode[i],
124962306a36Sopenharmony_ci						    tar_info->ucode_ptr);
125062306a36Sopenharmony_ci		} else
125162306a36Sopenharmony_ci			ret = ucode_load(dev, &eng_grp->ucode[i],
125262306a36Sopenharmony_ci					 (char *) ucode_data[i]);
125362306a36Sopenharmony_ci		if (ret)
125462306a36Sopenharmony_ci			goto err_ucode_unload;
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	/* Validate scenario where 1 ucode is used */
125862306a36Sopenharmony_ci	ret = validate_1_ucode_scenario(dev, eng_grp, engs, engs_cnt);
125962306a36Sopenharmony_ci	if (ret)
126062306a36Sopenharmony_ci		goto err_ucode_unload;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	/* Check if this group mirrors another existing engine group */
126362306a36Sopenharmony_ci	mirrored_eng_grp = find_mirrored_eng_grp(eng_grp);
126462306a36Sopenharmony_ci	if (mirrored_eng_grp) {
126562306a36Sopenharmony_ci		/* Setup mirroring */
126662306a36Sopenharmony_ci		setup_eng_grp_mirroring(eng_grp, mirrored_eng_grp);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci		/*
126962306a36Sopenharmony_ci		 * Update count of requested engines because some
127062306a36Sopenharmony_ci		 * of them might be shared with mirrored group
127162306a36Sopenharmony_ci		 */
127262306a36Sopenharmony_ci		update_requested_engs(mirrored_eng_grp, engs, engs_cnt);
127362306a36Sopenharmony_ci	}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	/* Reserve engines */
127662306a36Sopenharmony_ci	ret = reserve_engines(dev, eng_grp, engs, engs_cnt);
127762306a36Sopenharmony_ci	if (ret)
127862306a36Sopenharmony_ci		goto err_ucode_unload;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	/* Update ucode pointers used by engines */
128162306a36Sopenharmony_ci	update_ucode_ptrs(eng_grp);
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	/* Update engine masks used by this group */
128462306a36Sopenharmony_ci	ret = eng_grp_update_masks(dev, eng_grp);
128562306a36Sopenharmony_ci	if (ret)
128662306a36Sopenharmony_ci		goto err_release_engs;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	/* Create sysfs entry for engine group info */
128962306a36Sopenharmony_ci	ret = create_sysfs_eng_grps_info(dev, eng_grp);
129062306a36Sopenharmony_ci	if (ret)
129162306a36Sopenharmony_ci		goto err_release_engs;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	/* Enable engine group */
129462306a36Sopenharmony_ci	ret = enable_eng_grp(eng_grp, eng_grps->obj);
129562306a36Sopenharmony_ci	if (ret)
129662306a36Sopenharmony_ci		goto err_release_engs;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	/*
129962306a36Sopenharmony_ci	 * If this engine group mirrors another engine group
130062306a36Sopenharmony_ci	 * then we need to unload ucode as we will use ucode
130162306a36Sopenharmony_ci	 * from mirrored engine group
130262306a36Sopenharmony_ci	 */
130362306a36Sopenharmony_ci	if (eng_grp->mirror.is_ena)
130462306a36Sopenharmony_ci		ucode_unload(dev, &eng_grp->ucode[0]);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	eng_grp->is_enabled = true;
130762306a36Sopenharmony_ci	if (eng_grp->mirror.is_ena)
130862306a36Sopenharmony_ci		dev_info(dev,
130962306a36Sopenharmony_ci			 "Engine_group%d: reuse microcode %s from group %d\n",
131062306a36Sopenharmony_ci			 eng_grp->idx, mirrored_eng_grp->ucode[0].ver_str,
131162306a36Sopenharmony_ci			 mirrored_eng_grp->idx);
131262306a36Sopenharmony_ci	else
131362306a36Sopenharmony_ci		dev_info(dev, "Engine_group%d: microcode loaded %s\n",
131462306a36Sopenharmony_ci			 eng_grp->idx, eng_grp->ucode[0].ver_str);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	return 0;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_cierr_release_engs:
131962306a36Sopenharmony_ci	release_engines(dev, eng_grp);
132062306a36Sopenharmony_cierr_ucode_unload:
132162306a36Sopenharmony_ci	ucode_unload(dev, &eng_grp->ucode[0]);
132262306a36Sopenharmony_ci	return ret;
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_cistatic ssize_t ucode_load_store(struct device *dev,
132662306a36Sopenharmony_ci				struct device_attribute *attr,
132762306a36Sopenharmony_ci				const char *buf, size_t count)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	struct otx_cpt_engines engs[OTX_CPT_MAX_ETYPES_PER_GRP] = { {0} };
133062306a36Sopenharmony_ci	char *ucode_filename[OTX_CPT_MAX_ETYPES_PER_GRP];
133162306a36Sopenharmony_ci	char tmp_buf[OTX_CPT_UCODE_NAME_LENGTH] = { 0 };
133262306a36Sopenharmony_ci	char *start, *val, *err_msg, *tmp;
133362306a36Sopenharmony_ci	struct otx_cpt_eng_grps *eng_grps;
133462306a36Sopenharmony_ci	int grp_idx = 0, ret = -EINVAL;
133562306a36Sopenharmony_ci	bool has_se, has_ie, has_ae;
133662306a36Sopenharmony_ci	int del_grp_idx = -1;
133762306a36Sopenharmony_ci	int ucode_idx = 0;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	if (strlen(buf) > OTX_CPT_UCODE_NAME_LENGTH)
134062306a36Sopenharmony_ci		return -EINVAL;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	eng_grps = container_of(attr, struct otx_cpt_eng_grps, ucode_load_attr);
134362306a36Sopenharmony_ci	err_msg = "Invalid engine group format";
134462306a36Sopenharmony_ci	strscpy(tmp_buf, buf, OTX_CPT_UCODE_NAME_LENGTH);
134562306a36Sopenharmony_ci	start = tmp_buf;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	has_se = has_ie = has_ae = false;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	for (;;) {
135062306a36Sopenharmony_ci		val = strsep(&start, ";");
135162306a36Sopenharmony_ci		if (!val)
135262306a36Sopenharmony_ci			break;
135362306a36Sopenharmony_ci		val = strim(val);
135462306a36Sopenharmony_ci		if (!*val)
135562306a36Sopenharmony_ci			continue;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci		if (!strncasecmp(val, "engine_group", 12)) {
135862306a36Sopenharmony_ci			if (del_grp_idx != -1)
135962306a36Sopenharmony_ci				goto err_print;
136062306a36Sopenharmony_ci			tmp = strim(strsep(&val, ":"));
136162306a36Sopenharmony_ci			if (!val)
136262306a36Sopenharmony_ci				goto err_print;
136362306a36Sopenharmony_ci			if (strlen(tmp) != 13)
136462306a36Sopenharmony_ci				goto err_print;
136562306a36Sopenharmony_ci			if (kstrtoint((tmp + 12), 10, &del_grp_idx))
136662306a36Sopenharmony_ci				goto err_print;
136762306a36Sopenharmony_ci			val = strim(val);
136862306a36Sopenharmony_ci			if (strncasecmp(val, "null", 4))
136962306a36Sopenharmony_ci				goto err_print;
137062306a36Sopenharmony_ci			if (strlen(val) != 4)
137162306a36Sopenharmony_ci				goto err_print;
137262306a36Sopenharmony_ci		} else if (!strncasecmp(val, "se", 2) && strchr(val, ':')) {
137362306a36Sopenharmony_ci			if (has_se || ucode_idx)
137462306a36Sopenharmony_ci				goto err_print;
137562306a36Sopenharmony_ci			tmp = strim(strsep(&val, ":"));
137662306a36Sopenharmony_ci			if (!val)
137762306a36Sopenharmony_ci				goto err_print;
137862306a36Sopenharmony_ci			if (strlen(tmp) != 2)
137962306a36Sopenharmony_ci				goto err_print;
138062306a36Sopenharmony_ci			if (kstrtoint(strim(val), 10, &engs[grp_idx].count))
138162306a36Sopenharmony_ci				goto err_print;
138262306a36Sopenharmony_ci			engs[grp_idx++].type = OTX_CPT_SE_TYPES;
138362306a36Sopenharmony_ci			has_se = true;
138462306a36Sopenharmony_ci		} else if (!strncasecmp(val, "ae", 2) && strchr(val, ':')) {
138562306a36Sopenharmony_ci			if (has_ae || ucode_idx)
138662306a36Sopenharmony_ci				goto err_print;
138762306a36Sopenharmony_ci			tmp = strim(strsep(&val, ":"));
138862306a36Sopenharmony_ci			if (!val)
138962306a36Sopenharmony_ci				goto err_print;
139062306a36Sopenharmony_ci			if (strlen(tmp) != 2)
139162306a36Sopenharmony_ci				goto err_print;
139262306a36Sopenharmony_ci			if (kstrtoint(strim(val), 10, &engs[grp_idx].count))
139362306a36Sopenharmony_ci				goto err_print;
139462306a36Sopenharmony_ci			engs[grp_idx++].type = OTX_CPT_AE_TYPES;
139562306a36Sopenharmony_ci			has_ae = true;
139662306a36Sopenharmony_ci		} else {
139762306a36Sopenharmony_ci			if (ucode_idx > 1)
139862306a36Sopenharmony_ci				goto err_print;
139962306a36Sopenharmony_ci			if (!strlen(val))
140062306a36Sopenharmony_ci				goto err_print;
140162306a36Sopenharmony_ci			if (strnstr(val, " ", strlen(val)))
140262306a36Sopenharmony_ci				goto err_print;
140362306a36Sopenharmony_ci			ucode_filename[ucode_idx++] = val;
140462306a36Sopenharmony_ci		}
140562306a36Sopenharmony_ci	}
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	/* Validate input parameters */
140862306a36Sopenharmony_ci	if (del_grp_idx == -1) {
140962306a36Sopenharmony_ci		if (!(grp_idx && ucode_idx))
141062306a36Sopenharmony_ci			goto err_print;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci		if (ucode_idx > 1 && grp_idx < 2)
141362306a36Sopenharmony_ci			goto err_print;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci		if (grp_idx > OTX_CPT_MAX_ETYPES_PER_GRP) {
141662306a36Sopenharmony_ci			err_msg = "Error max 2 engine types can be attached";
141762306a36Sopenharmony_ci			goto err_print;
141862306a36Sopenharmony_ci		}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	} else {
142162306a36Sopenharmony_ci		if (del_grp_idx < 0 ||
142262306a36Sopenharmony_ci		    del_grp_idx >= OTX_CPT_MAX_ENGINE_GROUPS) {
142362306a36Sopenharmony_ci			dev_err(dev, "Invalid engine group index %d\n",
142462306a36Sopenharmony_ci				del_grp_idx);
142562306a36Sopenharmony_ci			ret = -EINVAL;
142662306a36Sopenharmony_ci			return ret;
142762306a36Sopenharmony_ci		}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci		if (!eng_grps->grp[del_grp_idx].is_enabled) {
143062306a36Sopenharmony_ci			dev_err(dev, "Error engine_group%d is not configured\n",
143162306a36Sopenharmony_ci				del_grp_idx);
143262306a36Sopenharmony_ci			ret = -EINVAL;
143362306a36Sopenharmony_ci			return ret;
143462306a36Sopenharmony_ci		}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci		if (grp_idx || ucode_idx)
143762306a36Sopenharmony_ci			goto err_print;
143862306a36Sopenharmony_ci	}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	mutex_lock(&eng_grps->lock);
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	if (eng_grps->is_rdonly) {
144362306a36Sopenharmony_ci		dev_err(dev, "Disable VFs before modifying engine groups\n");
144462306a36Sopenharmony_ci		ret = -EACCES;
144562306a36Sopenharmony_ci		goto err_unlock;
144662306a36Sopenharmony_ci	}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	if (del_grp_idx == -1)
144962306a36Sopenharmony_ci		/* create engine group */
145062306a36Sopenharmony_ci		ret = create_engine_group(dev, eng_grps, engs, grp_idx,
145162306a36Sopenharmony_ci					  (void **) ucode_filename,
145262306a36Sopenharmony_ci					  ucode_idx, false);
145362306a36Sopenharmony_ci	else
145462306a36Sopenharmony_ci		/* delete engine group */
145562306a36Sopenharmony_ci		ret = delete_engine_group(dev, &eng_grps->grp[del_grp_idx]);
145662306a36Sopenharmony_ci	if (ret)
145762306a36Sopenharmony_ci		goto err_unlock;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	print_dbg_info(dev, eng_grps);
146062306a36Sopenharmony_cierr_unlock:
146162306a36Sopenharmony_ci	mutex_unlock(&eng_grps->lock);
146262306a36Sopenharmony_ci	return ret ? ret : count;
146362306a36Sopenharmony_cierr_print:
146462306a36Sopenharmony_ci	dev_err(dev, "%s\n", err_msg);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	return ret;
146762306a36Sopenharmony_ci}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ciint otx_cpt_try_create_default_eng_grps(struct pci_dev *pdev,
147062306a36Sopenharmony_ci					struct otx_cpt_eng_grps *eng_grps,
147162306a36Sopenharmony_ci					int pf_type)
147262306a36Sopenharmony_ci{
147362306a36Sopenharmony_ci	struct tar_ucode_info_t *tar_info[OTX_CPT_MAX_ETYPES_PER_GRP] = {};
147462306a36Sopenharmony_ci	struct otx_cpt_engines engs[OTX_CPT_MAX_ETYPES_PER_GRP] = {};
147562306a36Sopenharmony_ci	struct tar_arch_info_t *tar_arch = NULL;
147662306a36Sopenharmony_ci	char *tar_filename;
147762306a36Sopenharmony_ci	int i, ret = 0;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	mutex_lock(&eng_grps->lock);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	/*
148262306a36Sopenharmony_ci	 * We don't create engine group for kernel crypto if attempt to create
148362306a36Sopenharmony_ci	 * it was already made (when user enabled VFs for the first time)
148462306a36Sopenharmony_ci	 */
148562306a36Sopenharmony_ci	if (eng_grps->is_first_try)
148662306a36Sopenharmony_ci		goto unlock_mutex;
148762306a36Sopenharmony_ci	eng_grps->is_first_try = true;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	/* We create group for kcrypto only if no groups are configured */
149062306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++)
149162306a36Sopenharmony_ci		if (eng_grps->grp[i].is_enabled)
149262306a36Sopenharmony_ci			goto unlock_mutex;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	switch (pf_type) {
149562306a36Sopenharmony_ci	case OTX_CPT_AE:
149662306a36Sopenharmony_ci	case OTX_CPT_SE:
149762306a36Sopenharmony_ci		tar_filename = OTX_CPT_UCODE_TAR_FILE_NAME;
149862306a36Sopenharmony_ci		break;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	default:
150162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unknown PF type %d\n", pf_type);
150262306a36Sopenharmony_ci		ret = -EINVAL;
150362306a36Sopenharmony_ci		goto unlock_mutex;
150462306a36Sopenharmony_ci	}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	tar_arch = load_tar_archive(&pdev->dev, tar_filename);
150762306a36Sopenharmony_ci	if (!tar_arch)
150862306a36Sopenharmony_ci		goto unlock_mutex;
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	/*
151162306a36Sopenharmony_ci	 * If device supports SE engines and there is SE microcode in tar
151262306a36Sopenharmony_ci	 * archive try to create engine group with SE engines for kernel
151362306a36Sopenharmony_ci	 * crypto functionality (symmetric crypto)
151462306a36Sopenharmony_ci	 */
151562306a36Sopenharmony_ci	tar_info[0] = get_uc_from_tar_archive(tar_arch, OTX_CPT_SE_TYPES);
151662306a36Sopenharmony_ci	if (tar_info[0] &&
151762306a36Sopenharmony_ci	    dev_supports_eng_type(eng_grps, OTX_CPT_SE_TYPES)) {
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci		engs[0].type = OTX_CPT_SE_TYPES;
152062306a36Sopenharmony_ci		engs[0].count = eng_grps->avail.max_se_cnt;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci		ret = create_engine_group(&pdev->dev, eng_grps, engs, 1,
152362306a36Sopenharmony_ci					  (void **) tar_info, 1, true);
152462306a36Sopenharmony_ci		if (ret)
152562306a36Sopenharmony_ci			goto release_tar_arch;
152662306a36Sopenharmony_ci	}
152762306a36Sopenharmony_ci	/*
152862306a36Sopenharmony_ci	 * If device supports AE engines and there is AE microcode in tar
152962306a36Sopenharmony_ci	 * archive try to create engine group with AE engines for asymmetric
153062306a36Sopenharmony_ci	 * crypto functionality.
153162306a36Sopenharmony_ci	 */
153262306a36Sopenharmony_ci	tar_info[0] = get_uc_from_tar_archive(tar_arch, OTX_CPT_AE_TYPES);
153362306a36Sopenharmony_ci	if (tar_info[0] &&
153462306a36Sopenharmony_ci	    dev_supports_eng_type(eng_grps, OTX_CPT_AE_TYPES)) {
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci		engs[0].type = OTX_CPT_AE_TYPES;
153762306a36Sopenharmony_ci		engs[0].count = eng_grps->avail.max_ae_cnt;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci		ret = create_engine_group(&pdev->dev, eng_grps, engs, 1,
154062306a36Sopenharmony_ci					  (void **) tar_info, 1, true);
154162306a36Sopenharmony_ci		if (ret)
154262306a36Sopenharmony_ci			goto release_tar_arch;
154362306a36Sopenharmony_ci	}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	print_dbg_info(&pdev->dev, eng_grps);
154662306a36Sopenharmony_cirelease_tar_arch:
154762306a36Sopenharmony_ci	release_tar_archive(tar_arch);
154862306a36Sopenharmony_ciunlock_mutex:
154962306a36Sopenharmony_ci	mutex_unlock(&eng_grps->lock);
155062306a36Sopenharmony_ci	return ret;
155162306a36Sopenharmony_ci}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_civoid otx_cpt_set_eng_grps_is_rdonly(struct otx_cpt_eng_grps *eng_grps,
155462306a36Sopenharmony_ci				    bool is_rdonly)
155562306a36Sopenharmony_ci{
155662306a36Sopenharmony_ci	mutex_lock(&eng_grps->lock);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	eng_grps->is_rdonly = is_rdonly;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	mutex_unlock(&eng_grps->lock);
156162306a36Sopenharmony_ci}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_civoid otx_cpt_disable_all_cores(struct otx_cpt_device *cpt)
156462306a36Sopenharmony_ci{
156562306a36Sopenharmony_ci	int grp, timeout = 100;
156662306a36Sopenharmony_ci	u64 reg;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	/* Disengage the cores from groups */
156962306a36Sopenharmony_ci	for (grp = 0; grp < OTX_CPT_MAX_ENGINE_GROUPS; grp++) {
157062306a36Sopenharmony_ci		writeq(0, cpt->reg_base + OTX_CPT_PF_GX_EN(grp));
157162306a36Sopenharmony_ci		udelay(CSR_DELAY);
157262306a36Sopenharmony_ci	}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	reg = readq(cpt->reg_base + OTX_CPT_PF_EXEC_BUSY);
157562306a36Sopenharmony_ci	while (reg) {
157662306a36Sopenharmony_ci		udelay(CSR_DELAY);
157762306a36Sopenharmony_ci		reg = readq(cpt->reg_base + OTX_CPT_PF_EXEC_BUSY);
157862306a36Sopenharmony_ci		if (timeout--) {
157962306a36Sopenharmony_ci			dev_warn(&cpt->pdev->dev, "Cores still busy\n");
158062306a36Sopenharmony_ci			break;
158162306a36Sopenharmony_ci		}
158262306a36Sopenharmony_ci	}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	/* Disable the cores */
158562306a36Sopenharmony_ci	writeq(0, cpt->reg_base + OTX_CPT_PF_EXE_CTL);
158662306a36Sopenharmony_ci}
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_civoid otx_cpt_cleanup_eng_grps(struct pci_dev *pdev,
158962306a36Sopenharmony_ci			      struct otx_cpt_eng_grps *eng_grps)
159062306a36Sopenharmony_ci{
159162306a36Sopenharmony_ci	struct otx_cpt_eng_grp_info *grp;
159262306a36Sopenharmony_ci	int i, j;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	mutex_lock(&eng_grps->lock);
159562306a36Sopenharmony_ci	if (eng_grps->is_ucode_load_created) {
159662306a36Sopenharmony_ci		device_remove_file(&pdev->dev,
159762306a36Sopenharmony_ci				   &eng_grps->ucode_load_attr);
159862306a36Sopenharmony_ci		eng_grps->is_ucode_load_created = false;
159962306a36Sopenharmony_ci	}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	/* First delete all mirroring engine groups */
160262306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++)
160362306a36Sopenharmony_ci		if (eng_grps->grp[i].mirror.is_ena)
160462306a36Sopenharmony_ci			delete_engine_group(&pdev->dev, &eng_grps->grp[i]);
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	/* Delete remaining engine groups */
160762306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++)
160862306a36Sopenharmony_ci		delete_engine_group(&pdev->dev, &eng_grps->grp[i]);
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	/* Release memory */
161162306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {
161262306a36Sopenharmony_ci		grp = &eng_grps->grp[i];
161362306a36Sopenharmony_ci		for (j = 0; j < OTX_CPT_MAX_ETYPES_PER_GRP; j++) {
161462306a36Sopenharmony_ci			kfree(grp->engs[j].bmap);
161562306a36Sopenharmony_ci			grp->engs[j].bmap = NULL;
161662306a36Sopenharmony_ci		}
161762306a36Sopenharmony_ci	}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	mutex_unlock(&eng_grps->lock);
162062306a36Sopenharmony_ci}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ciint otx_cpt_init_eng_grps(struct pci_dev *pdev,
162362306a36Sopenharmony_ci			  struct otx_cpt_eng_grps *eng_grps, int pf_type)
162462306a36Sopenharmony_ci{
162562306a36Sopenharmony_ci	struct otx_cpt_eng_grp_info *grp;
162662306a36Sopenharmony_ci	int i, j, ret = 0;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	mutex_init(&eng_grps->lock);
162962306a36Sopenharmony_ci	eng_grps->obj = pci_get_drvdata(pdev);
163062306a36Sopenharmony_ci	eng_grps->avail.se_cnt = eng_grps->avail.max_se_cnt;
163162306a36Sopenharmony_ci	eng_grps->avail.ae_cnt = eng_grps->avail.max_ae_cnt;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	eng_grps->engs_num = eng_grps->avail.max_se_cnt +
163462306a36Sopenharmony_ci			     eng_grps->avail.max_ae_cnt;
163562306a36Sopenharmony_ci	if (eng_grps->engs_num > OTX_CPT_MAX_ENGINES) {
163662306a36Sopenharmony_ci		dev_err(&pdev->dev,
163762306a36Sopenharmony_ci			"Number of engines %d > than max supported %d\n",
163862306a36Sopenharmony_ci			eng_grps->engs_num, OTX_CPT_MAX_ENGINES);
163962306a36Sopenharmony_ci		ret = -EINVAL;
164062306a36Sopenharmony_ci		goto err;
164162306a36Sopenharmony_ci	}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {
164462306a36Sopenharmony_ci		grp = &eng_grps->grp[i];
164562306a36Sopenharmony_ci		grp->g = eng_grps;
164662306a36Sopenharmony_ci		grp->idx = i;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci		snprintf(grp->sysfs_info_name, OTX_CPT_UCODE_NAME_LENGTH,
164962306a36Sopenharmony_ci			 "engine_group%d", i);
165062306a36Sopenharmony_ci		for (j = 0; j < OTX_CPT_MAX_ETYPES_PER_GRP; j++) {
165162306a36Sopenharmony_ci			grp->engs[j].bmap =
165262306a36Sopenharmony_ci				kcalloc(BITS_TO_LONGS(eng_grps->engs_num),
165362306a36Sopenharmony_ci					sizeof(long), GFP_KERNEL);
165462306a36Sopenharmony_ci			if (!grp->engs[j].bmap) {
165562306a36Sopenharmony_ci				ret = -ENOMEM;
165662306a36Sopenharmony_ci				goto err;
165762306a36Sopenharmony_ci			}
165862306a36Sopenharmony_ci		}
165962306a36Sopenharmony_ci	}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	switch (pf_type) {
166262306a36Sopenharmony_ci	case OTX_CPT_SE:
166362306a36Sopenharmony_ci		/* OcteonTX 83XX SE CPT PF has only SE engines attached */
166462306a36Sopenharmony_ci		eng_grps->eng_types_supported = 1 << OTX_CPT_SE_TYPES;
166562306a36Sopenharmony_ci		break;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	case OTX_CPT_AE:
166862306a36Sopenharmony_ci		/* OcteonTX 83XX AE CPT PF has only AE engines attached */
166962306a36Sopenharmony_ci		eng_grps->eng_types_supported = 1 << OTX_CPT_AE_TYPES;
167062306a36Sopenharmony_ci		break;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	default:
167362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unknown PF type %d\n", pf_type);
167462306a36Sopenharmony_ci		ret = -EINVAL;
167562306a36Sopenharmony_ci		goto err;
167662306a36Sopenharmony_ci	}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	eng_grps->ucode_load_attr.show = NULL;
167962306a36Sopenharmony_ci	eng_grps->ucode_load_attr.store = ucode_load_store;
168062306a36Sopenharmony_ci	eng_grps->ucode_load_attr.attr.name = "ucode_load";
168162306a36Sopenharmony_ci	eng_grps->ucode_load_attr.attr.mode = 0220;
168262306a36Sopenharmony_ci	sysfs_attr_init(&eng_grps->ucode_load_attr.attr);
168362306a36Sopenharmony_ci	ret = device_create_file(&pdev->dev,
168462306a36Sopenharmony_ci				 &eng_grps->ucode_load_attr);
168562306a36Sopenharmony_ci	if (ret)
168662306a36Sopenharmony_ci		goto err;
168762306a36Sopenharmony_ci	eng_grps->is_ucode_load_created = true;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	print_dbg_info(&pdev->dev, eng_grps);
169062306a36Sopenharmony_ci	return ret;
169162306a36Sopenharmony_cierr:
169262306a36Sopenharmony_ci	otx_cpt_cleanup_eng_grps(pdev, eng_grps);
169362306a36Sopenharmony_ci	return ret;
169462306a36Sopenharmony_ci}
1695