int otx2_cpt_dl_custom_egrp_create()

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;
}