Commit 5ea5896e 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/IAL7SX



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

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: 523f34d8 ("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 6dfd6623
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1131,6 +1131,7 @@ struct hns_roce_scc_param {
	struct hns_roce_dev *hr_dev;
	u8 port_num;
	__le32 latest_param[HNS_ROCE_SCC_PARAM_SIZE];
	struct mutex scc_mutex; /* protect @param and @latest_param */
};

struct hns_roce_port {
+5 −0
Original line number Diff line number Diff line
@@ -7597,6 +7597,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);
	pdata = &hr_dev->port_data[port_num - 1];
	scc_param = &pdata->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);
@@ -7609,6 +7610,8 @@ static int hns_roce_v2_config_scc_param(struct hns_roce_dev *hr_dev,

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

	return 0;
}

@@ -7645,9 +7648,11 @@ static int hns_roce_v2_query_scc_param(struct hns_roce_dev *hr_dev,

	pdata = &hr_dev->port_data[port_num - 1];
	scc_param = &pdata->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
@@ -92,6 +92,7 @@ static int alloc_scc_param(struct hns_roce_dev *hr_dev,
		scc_param[i].algo_type = i;
		scc_param[i].hr_dev = hr_dev;
		scc_param[i].port_num = pdata->port_num;
		mutex_init(&scc_param[i].scc_mutex);
		INIT_DELAYED_WORK(&scc_param[i].scc_cfg_dwork,
				  scc_param_config_work);
	}
@@ -202,11 +203,13 @@ static ssize_t scc_attr_show(struct hns_roce_port *pdata,

	scc_param = &pdata->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));
}
@@ -236,8 +239,10 @@ static ssize_t scc_attr_store(struct hns_roce_port *pdata,

	attr_val = cpu_to_le32(val);
	scc_param = &pdata->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))
@@ -606,8 +611,10 @@ static void hns_roce_unregister_port_sysfs(struct hns_roce_dev *hr_dev,
	pdata = &hr_dev->port_data[port_num];
	sysfs_remove_groups(&pdata->kobj, hns_attr_port_groups);
	scc_param = pdata->scc_param;
	for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++)
	for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++) {
		cancel_delayed_work_sync(&scc_param[i].scc_cfg_dwork);
		mutex_destroy(&scc_param[i].scc_mutex);
	}
	kobject_put(&pdata->kobj);
}