in marvell/octeontx2/otx2_cptpf_ucode.c [1518:1668]
int otx2_cpt_dl_custom_egrp_create(struct otx2_cptpf_dev *cptpf,
struct devlink_param_gset_ctx *ctx)
{
struct otx2_cpt_engines engs[OTX2_CPT_MAX_ETYPES_PER_GRP] = { { 0 } };
struct otx2_cpt_uc_info_t *uc_info[OTX2_CPT_MAX_ETYPES_PER_GRP] = {};
struct otx2_cpt_eng_grps *eng_grps = &cptpf->eng_grps;
char *ucode_filename[OTX2_CPT_MAX_ETYPES_PER_GRP];
char tmp_buf[OTX2_CPT_NAME_LENGTH] = { 0 };
struct device *dev = &cptpf->pdev->dev;
char *start, *val, *err_msg, *tmp;
int grp_idx = 0, ret = -EINVAL;
bool has_se, has_ie, has_ae;
struct fw_info_t fw_info;
int ucode_idx = 0;
if (!eng_grps->is_grps_created) {
dev_err(dev, "Not allowed before creating the default groups\n");
return -EINVAL;
}
err_msg = "Invalid engine group format";
strscpy(tmp_buf, ctx->val.vstr, strlen(ctx->val.vstr) + 1);
start = tmp_buf;
has_se = has_ie = has_ae = false;
for (;;) {
val = strsep(&start, ";");
if (!val)
break;
val = strim(val);
if (!*val)
continue;
if (!strncasecmp(val, "se", 2) && strchr(val, ':')) {
if (has_se || ucode_idx)
goto err_print;
tmp = strim(strsep(&val, ":"));
if (!val)
goto err_print;
if (strlen(tmp) != 2)
goto err_print;
if (kstrtoint(strim(val), 10, &engs[grp_idx].count))
goto err_print;
engs[grp_idx++].type = OTX2_CPT_SE_TYPES;
has_se = true;
} else if (!strncasecmp(val, "ae", 2) && strchr(val, ':')) {
if (has_ae || ucode_idx)
goto err_print;
tmp = strim(strsep(&val, ":"));
if (!val)
goto err_print;
if (strlen(tmp) != 2)
goto err_print;
if (kstrtoint(strim(val), 10, &engs[grp_idx].count))
goto err_print;
engs[grp_idx++].type = OTX2_CPT_AE_TYPES;
has_ae = true;
} else if (!strncasecmp(val, "ie", 2) && strchr(val, ':')) {
if (has_ie || ucode_idx)
goto err_print;
tmp = strim(strsep(&val, ":"));
if (!val)
goto err_print;
if (strlen(tmp) != 2)
goto err_print;
if (kstrtoint(strim(val), 10, &engs[grp_idx].count))
goto err_print;
engs[grp_idx++].type = OTX2_CPT_IE_TYPES;
has_ie = true;
} else {
if (ucode_idx > 1)
goto err_print;
if (!strlen(val))
goto err_print;
if (strnstr(val, " ", strlen(val)))
goto err_print;
ucode_filename[ucode_idx++] = val;
}
}
/* Validate input parameters */
if (!(grp_idx && ucode_idx))
goto err_print;
if (ucode_idx > 1 && grp_idx < 2)
goto err_print;
if (grp_idx > OTX2_CPT_MAX_ETYPES_PER_GRP) {
err_msg = "Error max 2 engine types can be attached";
goto err_print;
}
if (grp_idx > 1) {
if ((engs[0].type + engs[1].type) !=
(OTX2_CPT_SE_TYPES + OTX2_CPT_IE_TYPES)) {
err_msg = "Only combination of SE+IE engines is allowed";
goto err_print;
}
/* Keep SE engines at zero index */
if (engs[1].type == OTX2_CPT_SE_TYPES)
swap(engs[0], engs[1]);
}
mutex_lock(&eng_grps->lock);
if (cptpf->enabled_vfs) {
dev_err(dev, "Disable VFs before modifying engine groups\n");
ret = -EACCES;
goto err_unlock;
}
INIT_LIST_HEAD(&fw_info.ucodes);
ret = load_fw(dev, &fw_info, ucode_filename[0]);
if (ret) {
dev_err(dev, "Unable to load firmware %s\n", ucode_filename[0]);
goto err_unlock;
}
if (ucode_idx > 1) {
ret = load_fw(dev, &fw_info, ucode_filename[1]);
if (ret) {
dev_err(dev, "Unable to load firmware %s\n",
ucode_filename[1]);
goto release_fw;
}
}
uc_info[0] = get_ucode(&fw_info, engs[0].type);
if (uc_info[0] == NULL) {
dev_err(dev, "Unable to find firmware for %s\n",
get_eng_type_str(engs[0].type));
ret = -EINVAL;
goto release_fw;
}
if (ucode_idx > 1) {
uc_info[1] = get_ucode(&fw_info, engs[1].type);
if (uc_info[1] == NULL) {
dev_err(dev, "Unable to find firmware for %s\n",
get_eng_type_str(engs[1].type));
ret = -EINVAL;
goto release_fw;
}
}
ret = create_engine_group(dev, eng_grps, engs, grp_idx,
(void **)uc_info, 1);
release_fw:
cpt_ucode_release_fw(&fw_info);
err_unlock:
mutex_unlock(&eng_grps->lock);
return ret;
err_print:
dev_err(dev, "%s\n", err_msg);
return ret;
}