Commit 3d57d0f4 authored by Junxian Huang's avatar Junxian Huang Committed by Chengchang Tang
Browse files

RDMA/hns: Fix concurrency between sysfs store and FW configuration of scc params

driver inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IB30V8



----------------------------------------------------------------------

The FW configuration of scc param is delayed with a workqueue. This may
lead to scc params being modified by sysfs store callback while they're
being configured to FW. Use a mutex to solve this.

Fixes: 41da9cd8 ("RDMA/hns: Support congestion control algorithm parameter configuration")
Signed-off-by: default avatarJunxian Huang <huangjunxian6@hisilicon.com>
Signed-off-by: default avatarXinghai Cen <cenxinghai@h-partners.com>
parent 5a71b75e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1082,6 +1082,7 @@ struct hns_roce_scc_param {
	struct delayed_work scc_cfg_dwork;
	struct hns_roce_dev *hr_dev;
	__le32 latest_param[HNS_ROCE_SCC_PARAM_SIZE];
	struct mutex scc_mutex; /* protect @param and @lastest_param */
};

struct hns_roce_dev {
+6 −0
Original line number Diff line number Diff line
@@ -7258,6 +7258,7 @@ static int hns_roce_v2_config_scc_param(struct hns_roce_dev *hr_dev,

	hns_roce_cmq_setup_basic_desc(&desc, scc_opcode[algo], false);
	scc_param = &hr_dev->scc_param[algo];
	mutex_lock(&scc_param->scc_mutex);
	memcpy(&desc.data, scc_param, sizeof(scc_param->param));

	ret = hns_roce_cmq_send(hr_dev, &desc, 1);
@@ -7265,11 +7266,14 @@ static int hns_roce_v2_config_scc_param(struct hns_roce_dev *hr_dev,
		ibdev_err_ratelimited(&hr_dev->ib_dev,
			"failed to configure scc param, opcode: 0x%x, ret = %d.\n",
			le16_to_cpu(desc.opcode), ret);
		mutex_unlock(&scc_param->scc_mutex);
		return ret;
	}

	memcpy(scc_param->latest_param, &desc.data,
	       sizeof(scc_param->latest_param));
	mutex_unlock(&scc_param->scc_mutex);

	return 0;
}

@@ -7298,9 +7302,11 @@ static int hns_roce_v2_query_scc_param(struct hns_roce_dev *hr_dev,
	}

	scc_param = &hr_dev->scc_param[algo];
	mutex_lock(&scc_param->scc_mutex);
	memcpy(scc_param->param, &desc.data, sizeof(scc_param->param));
	memcpy(scc_param->latest_param, &desc.data,
	       sizeof(scc_param->latest_param));
	mutex_unlock(&scc_param->scc_mutex);

	return 0;
}
+8 −1
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ int hns_roce_alloc_scc_param(struct hns_roce_dev *hr_dev)
	for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++) {
		scc_param[i].algo_type = i;
		scc_param[i].hr_dev = hr_dev;
		mutex_init(&scc_param[i].scc_mutex);
		INIT_DELAYED_WORK(&scc_param[i].scc_cfg_dwork,
				  scc_param_config_work);
	}
@@ -63,8 +64,10 @@ void hns_roce_dealloc_scc_param(struct hns_roce_dev *hr_dev)
	if (!hr_dev->scc_param)
		return;

	for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++)
	for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++) {
		cancel_delayed_work_sync(&hr_dev->scc_param[i].scc_cfg_dwork);
		mutex_destroy(&hr_dev->scc_param[i].scc_mutex);
	}

	kvfree(hr_dev->scc_param);
	hr_dev->scc_param = NULL;
@@ -110,11 +113,13 @@ static ssize_t scc_attr_show(struct ib_device *ibdev, u32 port_num,

	scc_param = &hr_dev->scc_param[scc_attr->algo_type];

	mutex_lock(&scc_param->scc_mutex);
	if (scc_attr->offset == offsetof(typeof(*scc_param), lifespan))
		val = scc_param->lifespan;
	else
		memcpy(&val, (void *)scc_param->latest_param + scc_attr->offset,
		       scc_attr->size);
	mutex_unlock(&scc_param->scc_mutex);

	return sysfs_emit(buf, "%u\n", le32_to_cpu(val));
}
@@ -145,8 +150,10 @@ static ssize_t scc_attr_store(struct ib_device *ibdev, u32 port_num,

	attr_val = cpu_to_le32(val);
	scc_param = &hr_dev->scc_param[scc_attr->algo_type];
	mutex_lock(&scc_param->scc_mutex);
	memcpy((void *)scc_param + scc_attr->offset, &attr_val,
	       scc_attr->size);
	mutex_unlock(&scc_param->scc_mutex);

	/* lifespan is only used for driver */
	if (scc_attr->offset >= offsetof(typeof(*scc_param), lifespan))