From: Junxian Huang huangjunxian6@hisilicon.com
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: 523f34d81ea7 ("RDMA/hns: Support congestion control algorithm parameter configuration") Signed-off-by: Junxian Huang huangjunxian6@hisilicon.com Signed-off-by: Xinghai Cen cenxinghai@h-partners.com --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 5 +++++ drivers/infiniband/hw/hns/hns_roce_sysfs.c | 9 ++++++++- 3 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index ef5c72051a9a..92a9dfc04a80 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -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 { diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index a5f6e7685c2e..33af1fc89892 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -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; } diff --git a/drivers/infiniband/hw/hns/hns_roce_sysfs.c b/drivers/infiniband/hw/hns/hns_roce_sysfs.c index a43426717765..42d6e888cc90 100644 --- a/drivers/infiniband/hw/hns/hns_roce_sysfs.c +++ b/drivers/infiniband/hw/hns/hns_roce_sysfs.c @@ -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); }