Path: blob/master/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c
26285 views
// SPDX-License-Identifier: GPL-2.01/* Marvell OcteonTX CPT driver2*3* Copyright (C) 2019 Marvell International Ltd.4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License version 2 as7* published by the Free Software Foundation.8*/910#include <linux/ctype.h>11#include <linux/firmware.h>12#include <linux/string_choices.h>13#include "otx_cpt_common.h"14#include "otx_cptpf_ucode.h"15#include "otx_cptpf.h"1617#define CSR_DELAY 3018/* Tar archive defines */19#define TAR_MAGIC "ustar"20#define TAR_MAGIC_LEN 621#define TAR_BLOCK_LEN 51222#define REGTYPE '0'23#define AREGTYPE '\0'2425/* tar header as defined in POSIX 1003.1-1990. */26struct tar_hdr_t {27char name[100];28char mode[8];29char uid[8];30char gid[8];31char size[12];32char mtime[12];33char chksum[8];34char typeflag;35char linkname[100];36char magic[6];37char version[2];38char uname[32];39char gname[32];40char devmajor[8];41char devminor[8];42char prefix[155];43};4445struct tar_blk_t {46union {47struct tar_hdr_t hdr;48char block[TAR_BLOCK_LEN];49};50};5152struct tar_arch_info_t {53struct list_head ucodes;54const struct firmware *fw;55};5657static struct otx_cpt_bitmap get_cores_bmap(struct device *dev,58struct otx_cpt_eng_grp_info *eng_grp)59{60struct otx_cpt_bitmap bmap = { {0} };61bool found = false;62int i;6364if (eng_grp->g->engs_num > OTX_CPT_MAX_ENGINES) {65dev_err(dev, "unsupported number of engines %d on octeontx\n",66eng_grp->g->engs_num);67return bmap;68}6970for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {71if (eng_grp->engs[i].type) {72bitmap_or(bmap.bits, bmap.bits,73eng_grp->engs[i].bmap,74eng_grp->g->engs_num);75bmap.size = eng_grp->g->engs_num;76found = true;77}78}7980if (!found)81dev_err(dev, "No engines reserved for engine group %d\n",82eng_grp->idx);83return bmap;84}8586static int is_eng_type(int val, int eng_type)87{88return val & (1 << eng_type);89}9091static int dev_supports_eng_type(struct otx_cpt_eng_grps *eng_grps,92int eng_type)93{94return is_eng_type(eng_grps->eng_types_supported, eng_type);95}9697static void set_ucode_filename(struct otx_cpt_ucode *ucode,98const char *filename)99{100strscpy(ucode->filename, filename, OTX_CPT_UCODE_NAME_LENGTH);101}102103static char *get_eng_type_str(int eng_type)104{105char *str = "unknown";106107switch (eng_type) {108case OTX_CPT_SE_TYPES:109str = "SE";110break;111112case OTX_CPT_AE_TYPES:113str = "AE";114break;115}116return str;117}118119static char *get_ucode_type_str(int ucode_type)120{121char *str = "unknown";122123switch (ucode_type) {124case (1 << OTX_CPT_SE_TYPES):125str = "SE";126break;127128case (1 << OTX_CPT_AE_TYPES):129str = "AE";130break;131}132return str;133}134135static int get_ucode_type(struct otx_cpt_ucode_hdr *ucode_hdr, int *ucode_type)136{137char tmp_ver_str[OTX_CPT_UCODE_VER_STR_SZ];138u32 i, val = 0;139u8 nn;140141strscpy(tmp_ver_str, ucode_hdr->ver_str, OTX_CPT_UCODE_VER_STR_SZ);142for (i = 0; i < strlen(tmp_ver_str); i++)143tmp_ver_str[i] = tolower(tmp_ver_str[i]);144145nn = ucode_hdr->ver_num.nn;146if (strnstr(tmp_ver_str, "se-", OTX_CPT_UCODE_VER_STR_SZ) &&147(nn == OTX_CPT_SE_UC_TYPE1 || nn == OTX_CPT_SE_UC_TYPE2 ||148nn == OTX_CPT_SE_UC_TYPE3))149val |= 1 << OTX_CPT_SE_TYPES;150if (strnstr(tmp_ver_str, "ae", OTX_CPT_UCODE_VER_STR_SZ) &&151nn == OTX_CPT_AE_UC_TYPE)152val |= 1 << OTX_CPT_AE_TYPES;153154*ucode_type = val;155156if (!val)157return -EINVAL;158if (is_eng_type(val, OTX_CPT_AE_TYPES) &&159is_eng_type(val, OTX_CPT_SE_TYPES))160return -EINVAL;161return 0;162}163164static int is_mem_zero(const char *ptr, int size)165{166int i;167168for (i = 0; i < size; i++) {169if (ptr[i])170return 0;171}172return 1;173}174175static int cpt_set_ucode_base(struct otx_cpt_eng_grp_info *eng_grp, void *obj)176{177struct otx_cpt_device *cpt = (struct otx_cpt_device *) obj;178dma_addr_t dma_addr;179struct otx_cpt_bitmap bmap;180int i;181182bmap = get_cores_bmap(&cpt->pdev->dev, eng_grp);183if (!bmap.size)184return -EINVAL;185186if (eng_grp->mirror.is_ena)187dma_addr =188eng_grp->g->grp[eng_grp->mirror.idx].ucode[0].align_dma;189else190dma_addr = eng_grp->ucode[0].align_dma;191192/*193* Set UCODE_BASE only for the cores which are not used,194* other cores should have already valid UCODE_BASE set195*/196for_each_set_bit(i, bmap.bits, bmap.size)197if (!eng_grp->g->eng_ref_cnt[i])198writeq((u64) dma_addr, cpt->reg_base +199OTX_CPT_PF_ENGX_UCODE_BASE(i));200return 0;201}202203static int cpt_detach_and_disable_cores(struct otx_cpt_eng_grp_info *eng_grp,204void *obj)205{206struct otx_cpt_device *cpt = (struct otx_cpt_device *) obj;207struct otx_cpt_bitmap bmap = { {0} };208int timeout = 10;209int i, busy;210u64 reg;211212bmap = get_cores_bmap(&cpt->pdev->dev, eng_grp);213if (!bmap.size)214return -EINVAL;215216/* Detach the cores from group */217reg = readq(cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx));218for_each_set_bit(i, bmap.bits, bmap.size) {219if (reg & (1ull << i)) {220eng_grp->g->eng_ref_cnt[i]--;221reg &= ~(1ull << i);222}223}224writeq(reg, cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx));225226/* Wait for cores to become idle */227do {228busy = 0;229usleep_range(10000, 20000);230if (timeout-- < 0)231return -EBUSY;232233reg = readq(cpt->reg_base + OTX_CPT_PF_EXEC_BUSY);234for_each_set_bit(i, bmap.bits, bmap.size)235if (reg & (1ull << i)) {236busy = 1;237break;238}239} while (busy);240241/* Disable the cores only if they are not used anymore */242reg = readq(cpt->reg_base + OTX_CPT_PF_EXE_CTL);243for_each_set_bit(i, bmap.bits, bmap.size)244if (!eng_grp->g->eng_ref_cnt[i])245reg &= ~(1ull << i);246writeq(reg, cpt->reg_base + OTX_CPT_PF_EXE_CTL);247248return 0;249}250251static int cpt_attach_and_enable_cores(struct otx_cpt_eng_grp_info *eng_grp,252void *obj)253{254struct otx_cpt_device *cpt = (struct otx_cpt_device *) obj;255struct otx_cpt_bitmap bmap;256u64 reg;257int i;258259bmap = get_cores_bmap(&cpt->pdev->dev, eng_grp);260if (!bmap.size)261return -EINVAL;262263/* Attach the cores to the group */264reg = readq(cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx));265for_each_set_bit(i, bmap.bits, bmap.size) {266if (!(reg & (1ull << i))) {267eng_grp->g->eng_ref_cnt[i]++;268reg |= 1ull << i;269}270}271writeq(reg, cpt->reg_base + OTX_CPT_PF_GX_EN(eng_grp->idx));272273/* Enable the cores */274reg = readq(cpt->reg_base + OTX_CPT_PF_EXE_CTL);275for_each_set_bit(i, bmap.bits, bmap.size)276reg |= 1ull << i;277writeq(reg, cpt->reg_base + OTX_CPT_PF_EXE_CTL);278279return 0;280}281282static int process_tar_file(struct device *dev,283struct tar_arch_info_t *tar_arch, char *filename,284const u8 *data, u32 size)285{286struct tar_ucode_info_t *tar_info;287struct otx_cpt_ucode_hdr *ucode_hdr;288int ucode_type, ucode_size;289unsigned int code_length;290291/*292* If size is less than microcode header size then don't report293* an error because it might not be microcode file, just process294* next file from archive295*/296if (size < sizeof(struct otx_cpt_ucode_hdr))297return 0;298299ucode_hdr = (struct otx_cpt_ucode_hdr *) data;300/*301* If microcode version can't be found don't report an error302* because it might not be microcode file, just process next file303*/304if (get_ucode_type(ucode_hdr, &ucode_type))305return 0;306307code_length = ntohl(ucode_hdr->code_length);308if (code_length >= INT_MAX / 2) {309dev_err(dev, "Invalid code_length %u\n", code_length);310return -EINVAL;311}312313ucode_size = code_length * 2;314if (!ucode_size || (size < round_up(ucode_size, 16) +315sizeof(struct otx_cpt_ucode_hdr) + OTX_CPT_UCODE_SIGN_LEN)) {316dev_err(dev, "Ucode %s invalid size\n", filename);317return -EINVAL;318}319320tar_info = kzalloc(sizeof(struct tar_ucode_info_t), GFP_KERNEL);321if (!tar_info)322return -ENOMEM;323324tar_info->ucode_ptr = data;325set_ucode_filename(&tar_info->ucode, filename);326memcpy(tar_info->ucode.ver_str, ucode_hdr->ver_str,327OTX_CPT_UCODE_VER_STR_SZ);328tar_info->ucode.ver_num = ucode_hdr->ver_num;329tar_info->ucode.type = ucode_type;330tar_info->ucode.size = ucode_size;331list_add_tail(&tar_info->list, &tar_arch->ucodes);332333return 0;334}335336static void release_tar_archive(struct tar_arch_info_t *tar_arch)337{338struct tar_ucode_info_t *curr, *temp;339340if (!tar_arch)341return;342343list_for_each_entry_safe(curr, temp, &tar_arch->ucodes, list) {344list_del(&curr->list);345kfree(curr);346}347348release_firmware(tar_arch->fw);349kfree(tar_arch);350}351352static struct tar_ucode_info_t *get_uc_from_tar_archive(353struct tar_arch_info_t *tar_arch,354int ucode_type)355{356struct tar_ucode_info_t *curr, *uc_found = NULL;357358list_for_each_entry(curr, &tar_arch->ucodes, list) {359if (!is_eng_type(curr->ucode.type, ucode_type))360continue;361362if (!uc_found) {363uc_found = curr;364continue;365}366367switch (ucode_type) {368case OTX_CPT_AE_TYPES:369break;370371case OTX_CPT_SE_TYPES:372if (uc_found->ucode.ver_num.nn == OTX_CPT_SE_UC_TYPE2 ||373(uc_found->ucode.ver_num.nn == OTX_CPT_SE_UC_TYPE3374&& curr->ucode.ver_num.nn == OTX_CPT_SE_UC_TYPE1))375uc_found = curr;376break;377}378}379380return uc_found;381}382383static void print_tar_dbg_info(struct tar_arch_info_t *tar_arch,384char *tar_filename)385{386struct tar_ucode_info_t *curr;387388pr_debug("Tar archive filename %s\n", tar_filename);389pr_debug("Tar archive pointer %p, size %ld\n", tar_arch->fw->data,390tar_arch->fw->size);391list_for_each_entry(curr, &tar_arch->ucodes, list) {392pr_debug("Ucode filename %s\n", curr->ucode.filename);393pr_debug("Ucode version string %s\n", curr->ucode.ver_str);394pr_debug("Ucode version %d.%d.%d.%d\n",395curr->ucode.ver_num.nn, curr->ucode.ver_num.xx,396curr->ucode.ver_num.yy, curr->ucode.ver_num.zz);397pr_debug("Ucode type (%d) %s\n", curr->ucode.type,398get_ucode_type_str(curr->ucode.type));399pr_debug("Ucode size %d\n", curr->ucode.size);400pr_debug("Ucode ptr %p\n", curr->ucode_ptr);401}402}403404static struct tar_arch_info_t *load_tar_archive(struct device *dev,405char *tar_filename)406{407struct tar_arch_info_t *tar_arch = NULL;408struct tar_blk_t *tar_blk;409unsigned int cur_size;410size_t tar_offs = 0;411size_t tar_size;412int ret;413414tar_arch = kzalloc(sizeof(struct tar_arch_info_t), GFP_KERNEL);415if (!tar_arch)416return NULL;417418INIT_LIST_HEAD(&tar_arch->ucodes);419420/* Load tar archive */421ret = request_firmware(&tar_arch->fw, tar_filename, dev);422if (ret)423goto release_tar_arch;424425if (tar_arch->fw->size < TAR_BLOCK_LEN) {426dev_err(dev, "Invalid tar archive %s\n", tar_filename);427goto release_tar_arch;428}429430tar_size = tar_arch->fw->size;431tar_blk = (struct tar_blk_t *) tar_arch->fw->data;432if (strncmp(tar_blk->hdr.magic, TAR_MAGIC, TAR_MAGIC_LEN - 1)) {433dev_err(dev, "Unsupported format of tar archive %s\n",434tar_filename);435goto release_tar_arch;436}437438while (1) {439/* Read current file size */440ret = kstrtouint(tar_blk->hdr.size, 8, &cur_size);441if (ret)442goto release_tar_arch;443444if (tar_offs + cur_size > tar_size ||445tar_offs + 2*TAR_BLOCK_LEN > tar_size) {446dev_err(dev, "Invalid tar archive %s\n", tar_filename);447goto release_tar_arch;448}449450tar_offs += TAR_BLOCK_LEN;451if (tar_blk->hdr.typeflag == REGTYPE ||452tar_blk->hdr.typeflag == AREGTYPE) {453ret = process_tar_file(dev, tar_arch,454tar_blk->hdr.name,455&tar_arch->fw->data[tar_offs],456cur_size);457if (ret)458goto release_tar_arch;459}460461tar_offs += (cur_size/TAR_BLOCK_LEN) * TAR_BLOCK_LEN;462if (cur_size % TAR_BLOCK_LEN)463tar_offs += TAR_BLOCK_LEN;464465/* Check for the end of the archive */466if (tar_offs + 2*TAR_BLOCK_LEN > tar_size) {467dev_err(dev, "Invalid tar archive %s\n", tar_filename);468goto release_tar_arch;469}470471if (is_mem_zero(&tar_arch->fw->data[tar_offs],4722*TAR_BLOCK_LEN))473break;474475/* Read next block from tar archive */476tar_blk = (struct tar_blk_t *) &tar_arch->fw->data[tar_offs];477}478479print_tar_dbg_info(tar_arch, tar_filename);480return tar_arch;481release_tar_arch:482release_tar_archive(tar_arch);483return NULL;484}485486static struct otx_cpt_engs_rsvd *find_engines_by_type(487struct otx_cpt_eng_grp_info *eng_grp,488int eng_type)489{490int i;491492for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {493if (!eng_grp->engs[i].type)494continue;495496if (eng_grp->engs[i].type == eng_type)497return &eng_grp->engs[i];498}499return NULL;500}501502int otx_cpt_uc_supports_eng_type(struct otx_cpt_ucode *ucode, int eng_type)503{504return is_eng_type(ucode->type, eng_type);505}506EXPORT_SYMBOL_GPL(otx_cpt_uc_supports_eng_type);507508static void print_ucode_info(struct otx_cpt_eng_grp_info *eng_grp,509char *buf, int size)510{511if (eng_grp->mirror.is_ena) {512scnprintf(buf, size, "%s (shared with engine_group%d)",513eng_grp->g->grp[eng_grp->mirror.idx].ucode[0].ver_str,514eng_grp->mirror.idx);515} else {516scnprintf(buf, size, "%s", eng_grp->ucode[0].ver_str);517}518}519520static void print_engs_info(struct otx_cpt_eng_grp_info *eng_grp,521char *buf, int size, int idx)522{523struct otx_cpt_engs_rsvd *mirrored_engs = NULL;524struct otx_cpt_engs_rsvd *engs;525int len, i;526527buf[0] = '\0';528for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {529engs = &eng_grp->engs[i];530if (!engs->type)531continue;532if (idx != -1 && idx != i)533continue;534535if (eng_grp->mirror.is_ena)536mirrored_engs = find_engines_by_type(537&eng_grp->g->grp[eng_grp->mirror.idx],538engs->type);539if (i > 0 && idx == -1) {540len = strlen(buf);541scnprintf(buf+len, size-len, ", ");542}543544len = strlen(buf);545scnprintf(buf+len, size-len, "%d %s ", mirrored_engs ?546engs->count + mirrored_engs->count : engs->count,547get_eng_type_str(engs->type));548if (mirrored_engs) {549len = strlen(buf);550scnprintf(buf+len, size-len,551"(%d shared with engine_group%d) ",552engs->count <= 0 ? engs->count +553mirrored_engs->count : mirrored_engs->count,554eng_grp->mirror.idx);555}556}557}558559static void print_ucode_dbg_info(struct otx_cpt_ucode *ucode)560{561pr_debug("Ucode info\n");562pr_debug("Ucode version string %s\n", ucode->ver_str);563pr_debug("Ucode version %d.%d.%d.%d\n", ucode->ver_num.nn,564ucode->ver_num.xx, ucode->ver_num.yy, ucode->ver_num.zz);565pr_debug("Ucode type %s\n", get_ucode_type_str(ucode->type));566pr_debug("Ucode size %d\n", ucode->size);567pr_debug("Ucode virt address %16.16llx\n", (u64)ucode->align_va);568pr_debug("Ucode phys address %16.16llx\n", ucode->align_dma);569}570571static void cpt_print_engines_mask(struct otx_cpt_eng_grp_info *eng_grp,572struct device *dev, char *buf, int size)573{574struct otx_cpt_bitmap bmap;575u32 mask[2];576577bmap = get_cores_bmap(dev, eng_grp);578if (!bmap.size) {579scnprintf(buf, size, "unknown");580return;581}582bitmap_to_arr32(mask, bmap.bits, bmap.size);583scnprintf(buf, size, "%8.8x %8.8x", mask[1], mask[0]);584}585586587static void print_dbg_info(struct device *dev,588struct otx_cpt_eng_grps *eng_grps)589{590char engs_info[2*OTX_CPT_UCODE_NAME_LENGTH];591struct otx_cpt_eng_grp_info *mirrored_grp;592char engs_mask[OTX_CPT_UCODE_NAME_LENGTH];593struct otx_cpt_eng_grp_info *grp;594struct otx_cpt_engs_rsvd *engs;595u32 mask[4];596int i, j;597598pr_debug("Engine groups global info\n");599pr_debug("max SE %d, max AE %d\n",600eng_grps->avail.max_se_cnt, eng_grps->avail.max_ae_cnt);601pr_debug("free SE %d\n", eng_grps->avail.se_cnt);602pr_debug("free AE %d\n", eng_grps->avail.ae_cnt);603604for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {605grp = &eng_grps->grp[i];606pr_debug("engine_group%d, state %s\n", i,607str_enabled_disabled(grp->is_enabled));608if (grp->is_enabled) {609mirrored_grp = &eng_grps->grp[grp->mirror.idx];610pr_debug("Ucode0 filename %s, version %s\n",611grp->mirror.is_ena ?612mirrored_grp->ucode[0].filename :613grp->ucode[0].filename,614grp->mirror.is_ena ?615mirrored_grp->ucode[0].ver_str :616grp->ucode[0].ver_str);617}618619for (j = 0; j < OTX_CPT_MAX_ETYPES_PER_GRP; j++) {620engs = &grp->engs[j];621if (engs->type) {622print_engs_info(grp, engs_info,6232*OTX_CPT_UCODE_NAME_LENGTH, j);624pr_debug("Slot%d: %s\n", j, engs_info);625bitmap_to_arr32(mask, engs->bmap,626eng_grps->engs_num);627pr_debug("Mask: %8.8x %8.8x %8.8x %8.8x\n",628mask[3], mask[2], mask[1], mask[0]);629} else630pr_debug("Slot%d not used\n", j);631}632if (grp->is_enabled) {633cpt_print_engines_mask(grp, dev, engs_mask,634OTX_CPT_UCODE_NAME_LENGTH);635pr_debug("Cmask: %s\n", engs_mask);636}637}638}639640static int update_engines_avail_count(struct device *dev,641struct otx_cpt_engs_available *avail,642struct otx_cpt_engs_rsvd *engs, int val)643{644switch (engs->type) {645case OTX_CPT_SE_TYPES:646avail->se_cnt += val;647break;648649case OTX_CPT_AE_TYPES:650avail->ae_cnt += val;651break;652653default:654dev_err(dev, "Invalid engine type %d\n", engs->type);655return -EINVAL;656}657658return 0;659}660661static int update_engines_offset(struct device *dev,662struct otx_cpt_engs_available *avail,663struct otx_cpt_engs_rsvd *engs)664{665switch (engs->type) {666case OTX_CPT_SE_TYPES:667engs->offset = 0;668break;669670case OTX_CPT_AE_TYPES:671engs->offset = avail->max_se_cnt;672break;673674default:675dev_err(dev, "Invalid engine type %d\n", engs->type);676return -EINVAL;677}678679return 0;680}681682static int release_engines(struct device *dev, struct otx_cpt_eng_grp_info *grp)683{684int i, ret = 0;685686for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {687if (!grp->engs[i].type)688continue;689690if (grp->engs[i].count > 0) {691ret = update_engines_avail_count(dev, &grp->g->avail,692&grp->engs[i],693grp->engs[i].count);694if (ret)695return ret;696}697698grp->engs[i].type = 0;699grp->engs[i].count = 0;700grp->engs[i].offset = 0;701grp->engs[i].ucode = NULL;702bitmap_zero(grp->engs[i].bmap, grp->g->engs_num);703}704705return 0;706}707708static int do_reserve_engines(struct device *dev,709struct otx_cpt_eng_grp_info *grp,710struct otx_cpt_engines *req_engs)711{712struct otx_cpt_engs_rsvd *engs = NULL;713int i, ret;714715for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {716if (!grp->engs[i].type) {717engs = &grp->engs[i];718break;719}720}721722if (!engs)723return -ENOMEM;724725engs->type = req_engs->type;726engs->count = req_engs->count;727728ret = update_engines_offset(dev, &grp->g->avail, engs);729if (ret)730return ret;731732if (engs->count > 0) {733ret = update_engines_avail_count(dev, &grp->g->avail, engs,734-engs->count);735if (ret)736return ret;737}738739return 0;740}741742static int check_engines_availability(struct device *dev,743struct otx_cpt_eng_grp_info *grp,744struct otx_cpt_engines *req_eng)745{746int avail_cnt = 0;747748switch (req_eng->type) {749case OTX_CPT_SE_TYPES:750avail_cnt = grp->g->avail.se_cnt;751break;752753case OTX_CPT_AE_TYPES:754avail_cnt = grp->g->avail.ae_cnt;755break;756757default:758dev_err(dev, "Invalid engine type %d\n", req_eng->type);759return -EINVAL;760}761762if (avail_cnt < req_eng->count) {763dev_err(dev,764"Error available %s engines %d < than requested %d\n",765get_eng_type_str(req_eng->type),766avail_cnt, req_eng->count);767return -EBUSY;768}769770return 0;771}772773static int reserve_engines(struct device *dev, struct otx_cpt_eng_grp_info *grp,774struct otx_cpt_engines *req_engs, int req_cnt)775{776int i, ret;777778/* Validate if a number of requested engines is available */779for (i = 0; i < req_cnt; i++) {780ret = check_engines_availability(dev, grp, &req_engs[i]);781if (ret)782return ret;783}784785/* Reserve requested engines for this engine group */786for (i = 0; i < req_cnt; i++) {787ret = do_reserve_engines(dev, grp, &req_engs[i]);788if (ret)789return ret;790}791return 0;792}793794static ssize_t eng_grp_info_show(struct device *dev,795struct device_attribute *attr,796char *buf)797{798char ucode_info[2*OTX_CPT_UCODE_NAME_LENGTH];799char engs_info[2*OTX_CPT_UCODE_NAME_LENGTH];800char engs_mask[OTX_CPT_UCODE_NAME_LENGTH];801struct otx_cpt_eng_grp_info *eng_grp;802int ret;803804eng_grp = container_of(attr, struct otx_cpt_eng_grp_info, info_attr);805mutex_lock(&eng_grp->g->lock);806807print_engs_info(eng_grp, engs_info, 2*OTX_CPT_UCODE_NAME_LENGTH, -1);808print_ucode_info(eng_grp, ucode_info, 2*OTX_CPT_UCODE_NAME_LENGTH);809cpt_print_engines_mask(eng_grp, dev, engs_mask,810OTX_CPT_UCODE_NAME_LENGTH);811ret = scnprintf(buf, PAGE_SIZE,812"Microcode : %s\nEngines: %s\nEngines mask: %s\n",813ucode_info, engs_info, engs_mask);814815mutex_unlock(&eng_grp->g->lock);816return ret;817}818819static int create_sysfs_eng_grps_info(struct device *dev,820struct otx_cpt_eng_grp_info *eng_grp)821{822eng_grp->info_attr.show = eng_grp_info_show;823eng_grp->info_attr.store = NULL;824eng_grp->info_attr.attr.name = eng_grp->sysfs_info_name;825eng_grp->info_attr.attr.mode = 0440;826sysfs_attr_init(&eng_grp->info_attr.attr);827return device_create_file(dev, &eng_grp->info_attr);828}829830static void ucode_unload(struct device *dev, struct otx_cpt_ucode *ucode)831{832if (ucode->va) {833dma_free_coherent(dev, ucode->size + OTX_CPT_UCODE_ALIGNMENT,834ucode->va, ucode->dma);835ucode->va = NULL;836ucode->align_va = NULL;837ucode->dma = 0;838ucode->align_dma = 0;839ucode->size = 0;840}841842memset(&ucode->ver_str, 0, OTX_CPT_UCODE_VER_STR_SZ);843memset(&ucode->ver_num, 0, sizeof(struct otx_cpt_ucode_ver_num));844set_ucode_filename(ucode, "");845ucode->type = 0;846}847848static int copy_ucode_to_dma_mem(struct device *dev,849struct otx_cpt_ucode *ucode,850const u8 *ucode_data)851{852u32 i;853854/* Allocate DMAable space */855ucode->va = dma_alloc_coherent(dev, ucode->size +856OTX_CPT_UCODE_ALIGNMENT,857&ucode->dma, GFP_KERNEL);858if (!ucode->va) {859dev_err(dev, "Unable to allocate space for microcode\n");860return -ENOMEM;861}862ucode->align_va = PTR_ALIGN(ucode->va, OTX_CPT_UCODE_ALIGNMENT);863ucode->align_dma = PTR_ALIGN(ucode->dma, OTX_CPT_UCODE_ALIGNMENT);864865memcpy((void *) ucode->align_va, (void *) ucode_data +866sizeof(struct otx_cpt_ucode_hdr), ucode->size);867868/* Byte swap 64-bit */869for (i = 0; i < (ucode->size / 8); i++)870((__be64 *)ucode->align_va)[i] =871cpu_to_be64(((u64 *)ucode->align_va)[i]);872/* Ucode needs 16-bit swap */873for (i = 0; i < (ucode->size / 2); i++)874((__be16 *)ucode->align_va)[i] =875cpu_to_be16(((u16 *)ucode->align_va)[i]);876return 0;877}878879static int ucode_load(struct device *dev, struct otx_cpt_ucode *ucode,880const char *ucode_filename)881{882struct otx_cpt_ucode_hdr *ucode_hdr;883const struct firmware *fw;884unsigned int code_length;885int ret;886887set_ucode_filename(ucode, ucode_filename);888ret = request_firmware(&fw, ucode->filename, dev);889if (ret)890return ret;891892ucode_hdr = (struct otx_cpt_ucode_hdr *) fw->data;893memcpy(ucode->ver_str, ucode_hdr->ver_str, OTX_CPT_UCODE_VER_STR_SZ);894ucode->ver_num = ucode_hdr->ver_num;895code_length = ntohl(ucode_hdr->code_length);896if (code_length >= INT_MAX / 2) {897dev_err(dev, "Ucode invalid code_length %u\n", code_length);898ret = -EINVAL;899goto release_fw;900}901ucode->size = code_length * 2;902if (!ucode->size || (fw->size < round_up(ucode->size, 16)903+ sizeof(struct otx_cpt_ucode_hdr) + OTX_CPT_UCODE_SIGN_LEN)) {904dev_err(dev, "Ucode %s invalid size\n", ucode_filename);905ret = -EINVAL;906goto release_fw;907}908909ret = get_ucode_type(ucode_hdr, &ucode->type);910if (ret) {911dev_err(dev, "Microcode %s unknown type 0x%x\n",912ucode->filename, ucode->type);913goto release_fw;914}915916ret = copy_ucode_to_dma_mem(dev, ucode, fw->data);917if (ret)918goto release_fw;919920print_ucode_dbg_info(ucode);921release_fw:922release_firmware(fw);923return ret;924}925926static int enable_eng_grp(struct otx_cpt_eng_grp_info *eng_grp,927void *obj)928{929int ret;930931ret = cpt_set_ucode_base(eng_grp, obj);932if (ret)933return ret;934935ret = cpt_attach_and_enable_cores(eng_grp, obj);936return ret;937}938939static int disable_eng_grp(struct device *dev,940struct otx_cpt_eng_grp_info *eng_grp,941void *obj)942{943int i, ret;944945ret = cpt_detach_and_disable_cores(eng_grp, obj);946if (ret)947return ret;948949/* Unload ucode used by this engine group */950ucode_unload(dev, &eng_grp->ucode[0]);951952for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {953if (!eng_grp->engs[i].type)954continue;955956eng_grp->engs[i].ucode = &eng_grp->ucode[0];957}958959ret = cpt_set_ucode_base(eng_grp, obj);960961return ret;962}963964static void setup_eng_grp_mirroring(struct otx_cpt_eng_grp_info *dst_grp,965struct otx_cpt_eng_grp_info *src_grp)966{967/* Setup fields for engine group which is mirrored */968src_grp->mirror.is_ena = false;969src_grp->mirror.idx = 0;970src_grp->mirror.ref_count++;971972/* Setup fields for mirroring engine group */973dst_grp->mirror.is_ena = true;974dst_grp->mirror.idx = src_grp->idx;975dst_grp->mirror.ref_count = 0;976}977978static void remove_eng_grp_mirroring(struct otx_cpt_eng_grp_info *dst_grp)979{980struct otx_cpt_eng_grp_info *src_grp;981982if (!dst_grp->mirror.is_ena)983return;984985src_grp = &dst_grp->g->grp[dst_grp->mirror.idx];986987src_grp->mirror.ref_count--;988dst_grp->mirror.is_ena = false;989dst_grp->mirror.idx = 0;990dst_grp->mirror.ref_count = 0;991}992993static void update_requested_engs(struct otx_cpt_eng_grp_info *mirrored_eng_grp,994struct otx_cpt_engines *engs, int engs_cnt)995{996struct otx_cpt_engs_rsvd *mirrored_engs;997int i;998999for (i = 0; i < engs_cnt; i++) {1000mirrored_engs = find_engines_by_type(mirrored_eng_grp,1001engs[i].type);1002if (!mirrored_engs)1003continue;10041005/*1006* If mirrored group has this type of engines attached then1007* there are 3 scenarios possible:1008* 1) mirrored_engs.count == engs[i].count then all engines1009* from mirrored engine group will be shared with this engine1010* group1011* 2) mirrored_engs.count > engs[i].count then only a subset of1012* engines from mirrored engine group will be shared with this1013* engine group1014* 3) mirrored_engs.count < engs[i].count then all engines1015* from mirrored engine group will be shared with this group1016* and additional engines will be reserved for exclusively use1017* by this engine group1018*/1019engs[i].count -= mirrored_engs->count;1020}1021}10221023static struct otx_cpt_eng_grp_info *find_mirrored_eng_grp(1024struct otx_cpt_eng_grp_info *grp)1025{1026struct otx_cpt_eng_grps *eng_grps = grp->g;1027int i;10281029for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {1030if (!eng_grps->grp[i].is_enabled)1031continue;1032if (eng_grps->grp[i].ucode[0].type)1033continue;1034if (grp->idx == i)1035continue;1036if (!strncasecmp(eng_grps->grp[i].ucode[0].ver_str,1037grp->ucode[0].ver_str,1038OTX_CPT_UCODE_VER_STR_SZ))1039return &eng_grps->grp[i];1040}10411042return NULL;1043}10441045static struct otx_cpt_eng_grp_info *find_unused_eng_grp(1046struct otx_cpt_eng_grps *eng_grps)1047{1048int i;10491050for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {1051if (!eng_grps->grp[i].is_enabled)1052return &eng_grps->grp[i];1053}1054return NULL;1055}10561057static int eng_grp_update_masks(struct device *dev,1058struct otx_cpt_eng_grp_info *eng_grp)1059{1060struct otx_cpt_engs_rsvd *engs, *mirrored_engs;1061struct otx_cpt_bitmap tmp_bmap = { {0} };1062int i, j, cnt, max_cnt;1063int bit;10641065for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {1066engs = &eng_grp->engs[i];1067if (!engs->type)1068continue;1069if (engs->count <= 0)1070continue;10711072switch (engs->type) {1073case OTX_CPT_SE_TYPES:1074max_cnt = eng_grp->g->avail.max_se_cnt;1075break;10761077case OTX_CPT_AE_TYPES:1078max_cnt = eng_grp->g->avail.max_ae_cnt;1079break;10801081default:1082dev_err(dev, "Invalid engine type %d\n", engs->type);1083return -EINVAL;1084}10851086cnt = engs->count;1087WARN_ON(engs->offset + max_cnt > OTX_CPT_MAX_ENGINES);1088bitmap_zero(tmp_bmap.bits, eng_grp->g->engs_num);1089for (j = engs->offset; j < engs->offset + max_cnt; j++) {1090if (!eng_grp->g->eng_ref_cnt[j]) {1091bitmap_set(tmp_bmap.bits, j, 1);1092cnt--;1093if (!cnt)1094break;1095}1096}10971098if (cnt)1099return -ENOSPC;11001101bitmap_copy(engs->bmap, tmp_bmap.bits, eng_grp->g->engs_num);1102}11031104if (!eng_grp->mirror.is_ena)1105return 0;11061107for (i = 0; i < OTX_CPT_MAX_ETYPES_PER_GRP; i++) {1108engs = &eng_grp->engs[i];1109if (!engs->type)1110continue;11111112mirrored_engs = find_engines_by_type(1113&eng_grp->g->grp[eng_grp->mirror.idx],1114engs->type);1115WARN_ON(!mirrored_engs && engs->count <= 0);1116if (!mirrored_engs)1117continue;11181119bitmap_copy(tmp_bmap.bits, mirrored_engs->bmap,1120eng_grp->g->engs_num);1121if (engs->count < 0) {1122bit = find_first_bit(mirrored_engs->bmap,1123eng_grp->g->engs_num);1124bitmap_clear(tmp_bmap.bits, bit, -engs->count);1125}1126bitmap_or(engs->bmap, engs->bmap, tmp_bmap.bits,1127eng_grp->g->engs_num);1128}1129return 0;1130}11311132static int delete_engine_group(struct device *dev,1133struct otx_cpt_eng_grp_info *eng_grp)1134{1135int i, ret;11361137if (!eng_grp->is_enabled)1138return -EINVAL;11391140if (eng_grp->mirror.ref_count) {1141dev_err(dev, "Can't delete engine_group%d as it is used by engine_group(s):",1142eng_grp->idx);1143for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {1144if (eng_grp->g->grp[i].mirror.is_ena &&1145eng_grp->g->grp[i].mirror.idx == eng_grp->idx)1146pr_cont(" %d", i);1147}1148pr_cont("\n");1149return -EINVAL;1150}11511152/* Removing engine group mirroring if enabled */1153remove_eng_grp_mirroring(eng_grp);11541155/* Disable engine group */1156ret = disable_eng_grp(dev, eng_grp, eng_grp->g->obj);1157if (ret)1158return ret;11591160/* Release all engines held by this engine group */1161ret = release_engines(dev, eng_grp);1162if (ret)1163return ret;11641165device_remove_file(dev, &eng_grp->info_attr);1166eng_grp->is_enabled = false;11671168return 0;1169}11701171static int validate_1_ucode_scenario(struct device *dev,1172struct otx_cpt_eng_grp_info *eng_grp,1173struct otx_cpt_engines *engs, int engs_cnt)1174{1175int i;11761177/* Verify that ucode loaded supports requested engine types */1178for (i = 0; i < engs_cnt; i++) {1179if (!otx_cpt_uc_supports_eng_type(&eng_grp->ucode[0],1180engs[i].type)) {1181dev_err(dev,1182"Microcode %s does not support %s engines\n",1183eng_grp->ucode[0].filename,1184get_eng_type_str(engs[i].type));1185return -EINVAL;1186}1187}1188return 0;1189}11901191static void update_ucode_ptrs(struct otx_cpt_eng_grp_info *eng_grp)1192{1193struct otx_cpt_ucode *ucode;11941195if (eng_grp->mirror.is_ena)1196ucode = &eng_grp->g->grp[eng_grp->mirror.idx].ucode[0];1197else1198ucode = &eng_grp->ucode[0];1199WARN_ON(!eng_grp->engs[0].type);1200eng_grp->engs[0].ucode = ucode;1201}12021203static int create_engine_group(struct device *dev,1204struct otx_cpt_eng_grps *eng_grps,1205struct otx_cpt_engines *engs, int engs_cnt,1206void *ucode_data[], int ucodes_cnt,1207bool use_uc_from_tar_arch)1208{1209struct otx_cpt_eng_grp_info *mirrored_eng_grp;1210struct tar_ucode_info_t *tar_info;1211struct otx_cpt_eng_grp_info *eng_grp;1212int i, ret = 0;12131214if (ucodes_cnt > OTX_CPT_MAX_ETYPES_PER_GRP)1215return -EINVAL;12161217/* Validate if requested engine types are supported by this device */1218for (i = 0; i < engs_cnt; i++)1219if (!dev_supports_eng_type(eng_grps, engs[i].type)) {1220dev_err(dev, "Device does not support %s engines\n",1221get_eng_type_str(engs[i].type));1222return -EPERM;1223}12241225/* Find engine group which is not used */1226eng_grp = find_unused_eng_grp(eng_grps);1227if (!eng_grp) {1228dev_err(dev, "Error all engine groups are being used\n");1229return -ENOSPC;1230}12311232/* Load ucode */1233for (i = 0; i < ucodes_cnt; i++) {1234if (use_uc_from_tar_arch) {1235tar_info = (struct tar_ucode_info_t *) ucode_data[i];1236eng_grp->ucode[i] = tar_info->ucode;1237ret = copy_ucode_to_dma_mem(dev, &eng_grp->ucode[i],1238tar_info->ucode_ptr);1239} else1240ret = ucode_load(dev, &eng_grp->ucode[i],1241(char *) ucode_data[i]);1242if (ret)1243goto err_ucode_unload;1244}12451246/* Validate scenario where 1 ucode is used */1247ret = validate_1_ucode_scenario(dev, eng_grp, engs, engs_cnt);1248if (ret)1249goto err_ucode_unload;12501251/* Check if this group mirrors another existing engine group */1252mirrored_eng_grp = find_mirrored_eng_grp(eng_grp);1253if (mirrored_eng_grp) {1254/* Setup mirroring */1255setup_eng_grp_mirroring(eng_grp, mirrored_eng_grp);12561257/*1258* Update count of requested engines because some1259* of them might be shared with mirrored group1260*/1261update_requested_engs(mirrored_eng_grp, engs, engs_cnt);1262}12631264/* Reserve engines */1265ret = reserve_engines(dev, eng_grp, engs, engs_cnt);1266if (ret)1267goto err_ucode_unload;12681269/* Update ucode pointers used by engines */1270update_ucode_ptrs(eng_grp);12711272/* Update engine masks used by this group */1273ret = eng_grp_update_masks(dev, eng_grp);1274if (ret)1275goto err_release_engs;12761277/* Create sysfs entry for engine group info */1278ret = create_sysfs_eng_grps_info(dev, eng_grp);1279if (ret)1280goto err_release_engs;12811282/* Enable engine group */1283ret = enable_eng_grp(eng_grp, eng_grps->obj);1284if (ret)1285goto err_release_engs;12861287/*1288* If this engine group mirrors another engine group1289* then we need to unload ucode as we will use ucode1290* from mirrored engine group1291*/1292if (eng_grp->mirror.is_ena)1293ucode_unload(dev, &eng_grp->ucode[0]);12941295eng_grp->is_enabled = true;1296if (eng_grp->mirror.is_ena)1297dev_info(dev,1298"Engine_group%d: reuse microcode %s from group %d\n",1299eng_grp->idx, mirrored_eng_grp->ucode[0].ver_str,1300mirrored_eng_grp->idx);1301else1302dev_info(dev, "Engine_group%d: microcode loaded %s\n",1303eng_grp->idx, eng_grp->ucode[0].ver_str);13041305return 0;13061307err_release_engs:1308release_engines(dev, eng_grp);1309err_ucode_unload:1310ucode_unload(dev, &eng_grp->ucode[0]);1311return ret;1312}13131314static ssize_t ucode_load_store(struct device *dev,1315struct device_attribute *attr,1316const char *buf, size_t count)1317{1318struct otx_cpt_engines engs[OTX_CPT_MAX_ETYPES_PER_GRP] = { {0} };1319char *ucode_filename[OTX_CPT_MAX_ETYPES_PER_GRP];1320char tmp_buf[OTX_CPT_UCODE_NAME_LENGTH] = { 0 };1321char *start, *val, *err_msg, *tmp;1322struct otx_cpt_eng_grps *eng_grps;1323int grp_idx = 0, ret = -EINVAL;1324bool has_se, has_ie, has_ae;1325int del_grp_idx = -1;1326int ucode_idx = 0;13271328if (strlen(buf) > OTX_CPT_UCODE_NAME_LENGTH)1329return -EINVAL;13301331eng_grps = container_of(attr, struct otx_cpt_eng_grps, ucode_load_attr);1332err_msg = "Invalid engine group format";1333strscpy(tmp_buf, buf, OTX_CPT_UCODE_NAME_LENGTH);1334start = tmp_buf;13351336has_se = has_ie = has_ae = false;13371338for (;;) {1339val = strsep(&start, ";");1340if (!val)1341break;1342val = strim(val);1343if (!*val)1344continue;13451346if (!strncasecmp(val, "engine_group", 12)) {1347if (del_grp_idx != -1)1348goto err_print;1349tmp = strim(strsep(&val, ":"));1350if (!val)1351goto err_print;1352if (strlen(tmp) != 13)1353goto err_print;1354if (kstrtoint((tmp + 12), 10, &del_grp_idx))1355goto err_print;1356val = strim(val);1357if (strncasecmp(val, "null", 4))1358goto err_print;1359if (strlen(val) != 4)1360goto err_print;1361} else if (!strncasecmp(val, "se", 2) && strchr(val, ':')) {1362if (has_se || ucode_idx)1363goto err_print;1364tmp = strim(strsep(&val, ":"));1365if (!val)1366goto err_print;1367if (strlen(tmp) != 2)1368goto err_print;1369if (kstrtoint(strim(val), 10, &engs[grp_idx].count))1370goto err_print;1371engs[grp_idx++].type = OTX_CPT_SE_TYPES;1372has_se = true;1373} else if (!strncasecmp(val, "ae", 2) && strchr(val, ':')) {1374if (has_ae || ucode_idx)1375goto err_print;1376tmp = strim(strsep(&val, ":"));1377if (!val)1378goto err_print;1379if (strlen(tmp) != 2)1380goto err_print;1381if (kstrtoint(strim(val), 10, &engs[grp_idx].count))1382goto err_print;1383engs[grp_idx++].type = OTX_CPT_AE_TYPES;1384has_ae = true;1385} else {1386if (ucode_idx > 1)1387goto err_print;1388if (!strlen(val))1389goto err_print;1390if (strnstr(val, " ", strlen(val)))1391goto err_print;1392ucode_filename[ucode_idx++] = val;1393}1394}13951396/* Validate input parameters */1397if (del_grp_idx == -1) {1398if (!(grp_idx && ucode_idx))1399goto err_print;14001401if (ucode_idx > 1 && grp_idx < 2)1402goto err_print;14031404if (grp_idx > OTX_CPT_MAX_ETYPES_PER_GRP) {1405err_msg = "Error max 2 engine types can be attached";1406goto err_print;1407}14081409} else {1410if (del_grp_idx < 0 ||1411del_grp_idx >= OTX_CPT_MAX_ENGINE_GROUPS) {1412dev_err(dev, "Invalid engine group index %d\n",1413del_grp_idx);1414ret = -EINVAL;1415return ret;1416}14171418if (!eng_grps->grp[del_grp_idx].is_enabled) {1419dev_err(dev, "Error engine_group%d is not configured\n",1420del_grp_idx);1421ret = -EINVAL;1422return ret;1423}14241425if (grp_idx || ucode_idx)1426goto err_print;1427}14281429mutex_lock(&eng_grps->lock);14301431if (eng_grps->is_rdonly) {1432dev_err(dev, "Disable VFs before modifying engine groups\n");1433ret = -EACCES;1434goto err_unlock;1435}14361437if (del_grp_idx == -1)1438/* create engine group */1439ret = create_engine_group(dev, eng_grps, engs, grp_idx,1440(void **) ucode_filename,1441ucode_idx, false);1442else1443/* delete engine group */1444ret = delete_engine_group(dev, &eng_grps->grp[del_grp_idx]);1445if (ret)1446goto err_unlock;14471448print_dbg_info(dev, eng_grps);1449err_unlock:1450mutex_unlock(&eng_grps->lock);1451return ret ? ret : count;1452err_print:1453dev_err(dev, "%s\n", err_msg);14541455return ret;1456}14571458int otx_cpt_try_create_default_eng_grps(struct pci_dev *pdev,1459struct otx_cpt_eng_grps *eng_grps,1460int pf_type)1461{1462struct tar_ucode_info_t *tar_info[OTX_CPT_MAX_ETYPES_PER_GRP] = {};1463struct otx_cpt_engines engs[OTX_CPT_MAX_ETYPES_PER_GRP] = {};1464struct tar_arch_info_t *tar_arch = NULL;1465char *tar_filename;1466int i, ret = 0;14671468mutex_lock(&eng_grps->lock);14691470/*1471* We don't create engine group for kernel crypto if attempt to create1472* it was already made (when user enabled VFs for the first time)1473*/1474if (eng_grps->is_first_try)1475goto unlock_mutex;1476eng_grps->is_first_try = true;14771478/* We create group for kcrypto only if no groups are configured */1479for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++)1480if (eng_grps->grp[i].is_enabled)1481goto unlock_mutex;14821483switch (pf_type) {1484case OTX_CPT_AE:1485case OTX_CPT_SE:1486tar_filename = OTX_CPT_UCODE_TAR_FILE_NAME;1487break;14881489default:1490dev_err(&pdev->dev, "Unknown PF type %d\n", pf_type);1491ret = -EINVAL;1492goto unlock_mutex;1493}14941495tar_arch = load_tar_archive(&pdev->dev, tar_filename);1496if (!tar_arch)1497goto unlock_mutex;14981499/*1500* If device supports SE engines and there is SE microcode in tar1501* archive try to create engine group with SE engines for kernel1502* crypto functionality (symmetric crypto)1503*/1504tar_info[0] = get_uc_from_tar_archive(tar_arch, OTX_CPT_SE_TYPES);1505if (tar_info[0] &&1506dev_supports_eng_type(eng_grps, OTX_CPT_SE_TYPES)) {15071508engs[0].type = OTX_CPT_SE_TYPES;1509engs[0].count = eng_grps->avail.max_se_cnt;15101511ret = create_engine_group(&pdev->dev, eng_grps, engs, 1,1512(void **) tar_info, 1, true);1513if (ret)1514goto release_tar_arch;1515}1516/*1517* If device supports AE engines and there is AE microcode in tar1518* archive try to create engine group with AE engines for asymmetric1519* crypto functionality.1520*/1521tar_info[0] = get_uc_from_tar_archive(tar_arch, OTX_CPT_AE_TYPES);1522if (tar_info[0] &&1523dev_supports_eng_type(eng_grps, OTX_CPT_AE_TYPES)) {15241525engs[0].type = OTX_CPT_AE_TYPES;1526engs[0].count = eng_grps->avail.max_ae_cnt;15271528ret = create_engine_group(&pdev->dev, eng_grps, engs, 1,1529(void **) tar_info, 1, true);1530if (ret)1531goto release_tar_arch;1532}15331534print_dbg_info(&pdev->dev, eng_grps);1535release_tar_arch:1536release_tar_archive(tar_arch);1537unlock_mutex:1538mutex_unlock(&eng_grps->lock);1539return ret;1540}15411542void otx_cpt_set_eng_grps_is_rdonly(struct otx_cpt_eng_grps *eng_grps,1543bool is_rdonly)1544{1545mutex_lock(&eng_grps->lock);15461547eng_grps->is_rdonly = is_rdonly;15481549mutex_unlock(&eng_grps->lock);1550}15511552void otx_cpt_disable_all_cores(struct otx_cpt_device *cpt)1553{1554int grp, timeout = 100;1555u64 reg;15561557/* Disengage the cores from groups */1558for (grp = 0; grp < OTX_CPT_MAX_ENGINE_GROUPS; grp++) {1559writeq(0, cpt->reg_base + OTX_CPT_PF_GX_EN(grp));1560udelay(CSR_DELAY);1561}15621563reg = readq(cpt->reg_base + OTX_CPT_PF_EXEC_BUSY);1564while (reg) {1565udelay(CSR_DELAY);1566reg = readq(cpt->reg_base + OTX_CPT_PF_EXEC_BUSY);1567if (timeout--) {1568dev_warn(&cpt->pdev->dev, "Cores still busy\n");1569break;1570}1571}15721573/* Disable the cores */1574writeq(0, cpt->reg_base + OTX_CPT_PF_EXE_CTL);1575}15761577void otx_cpt_cleanup_eng_grps(struct pci_dev *pdev,1578struct otx_cpt_eng_grps *eng_grps)1579{1580struct otx_cpt_eng_grp_info *grp;1581int i, j;15821583mutex_lock(&eng_grps->lock);1584if (eng_grps->is_ucode_load_created) {1585device_remove_file(&pdev->dev,1586&eng_grps->ucode_load_attr);1587eng_grps->is_ucode_load_created = false;1588}15891590/* First delete all mirroring engine groups */1591for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++)1592if (eng_grps->grp[i].mirror.is_ena)1593delete_engine_group(&pdev->dev, &eng_grps->grp[i]);15941595/* Delete remaining engine groups */1596for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++)1597delete_engine_group(&pdev->dev, &eng_grps->grp[i]);15981599/* Release memory */1600for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {1601grp = &eng_grps->grp[i];1602for (j = 0; j < OTX_CPT_MAX_ETYPES_PER_GRP; j++) {1603kfree(grp->engs[j].bmap);1604grp->engs[j].bmap = NULL;1605}1606}16071608mutex_unlock(&eng_grps->lock);1609}16101611int otx_cpt_init_eng_grps(struct pci_dev *pdev,1612struct otx_cpt_eng_grps *eng_grps, int pf_type)1613{1614struct otx_cpt_eng_grp_info *grp;1615int i, j, ret = 0;16161617mutex_init(&eng_grps->lock);1618eng_grps->obj = pci_get_drvdata(pdev);1619eng_grps->avail.se_cnt = eng_grps->avail.max_se_cnt;1620eng_grps->avail.ae_cnt = eng_grps->avail.max_ae_cnt;16211622eng_grps->engs_num = eng_grps->avail.max_se_cnt +1623eng_grps->avail.max_ae_cnt;1624if (eng_grps->engs_num > OTX_CPT_MAX_ENGINES) {1625dev_err(&pdev->dev,1626"Number of engines %d > than max supported %d\n",1627eng_grps->engs_num, OTX_CPT_MAX_ENGINES);1628ret = -EINVAL;1629goto err;1630}16311632for (i = 0; i < OTX_CPT_MAX_ENGINE_GROUPS; i++) {1633grp = &eng_grps->grp[i];1634grp->g = eng_grps;1635grp->idx = i;16361637snprintf(grp->sysfs_info_name, OTX_CPT_UCODE_NAME_LENGTH,1638"engine_group%d", i);1639for (j = 0; j < OTX_CPT_MAX_ETYPES_PER_GRP; j++) {1640grp->engs[j].bmap =1641kcalloc(BITS_TO_LONGS(eng_grps->engs_num),1642sizeof(long), GFP_KERNEL);1643if (!grp->engs[j].bmap) {1644ret = -ENOMEM;1645goto err;1646}1647}1648}16491650switch (pf_type) {1651case OTX_CPT_SE:1652/* OcteonTX 83XX SE CPT PF has only SE engines attached */1653eng_grps->eng_types_supported = 1 << OTX_CPT_SE_TYPES;1654break;16551656case OTX_CPT_AE:1657/* OcteonTX 83XX AE CPT PF has only AE engines attached */1658eng_grps->eng_types_supported = 1 << OTX_CPT_AE_TYPES;1659break;16601661default:1662dev_err(&pdev->dev, "Unknown PF type %d\n", pf_type);1663ret = -EINVAL;1664goto err;1665}16661667eng_grps->ucode_load_attr.show = NULL;1668eng_grps->ucode_load_attr.store = ucode_load_store;1669eng_grps->ucode_load_attr.attr.name = "ucode_load";1670eng_grps->ucode_load_attr.attr.mode = 0220;1671sysfs_attr_init(&eng_grps->ucode_load_attr.attr);1672ret = device_create_file(&pdev->dev,1673&eng_grps->ucode_load_attr);1674if (ret)1675goto err;1676eng_grps->is_ucode_load_created = true;16771678print_dbg_info(&pdev->dev, eng_grps);1679return ret;1680err:1681otx_cpt_cleanup_eng_grps(pdev, eng_grps);1682return ret;1683}168416851686