1. Make ECMDQs to be evenly allocated based on the number of cores 2. Allow disabling ECMDQs at boot time
Zhen Lei (2): iommu/arm-smmu-v3: Make ECMDQs to be evenly allocated based on the number of cores iommu/arm-smmu-v3: Allow disabling ECMDQs at boot time
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 105 ++++---------------- 1 file changed, 17 insertions(+), 88 deletions(-)
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I7YUNJ
--------------------------------
The implementation of ECMDQ equalization based on the number of numa nodes and the number of cores in it is too complicated. Some special application scenarios, such as using maxcpus to limit the number of cores, may not be fully considered. Equalizing ECMDQ by number of cores can greatly simplify code and reduce quality risk.
Fixes: 3965519baff5 ("iommu/arm-smmu-v3: Add support for less than one ECMDQ per core") Signed-off-by: Zhen Lei thunder.leizhen@huawei.com --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 99 +++------------------ 1 file changed, 12 insertions(+), 87 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 1ee14a59a3d66c7..4419d6348f68511 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -4733,104 +4733,29 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool resume)
static int arm_smmu_ecmdq_layout(struct arm_smmu_device *smmu) { - int cpu, node, nr_remain, nr_nodes = 0; - int *nr_ecmdqs; - struct arm_smmu_ecmdq *ecmdq, **ecmdqs; + int cpu, host_cpu; + struct arm_smmu_ecmdq *ecmdq;
ecmdq = devm_alloc_percpu(smmu->dev, *ecmdq); if (!ecmdq) return -ENOMEM; smmu->ecmdq = ecmdq;
- if (num_possible_cpus() <= smmu->nr_ecmdq) { - for_each_possible_cpu(cpu) - *per_cpu_ptr(smmu->ecmdqs, cpu) = per_cpu_ptr(ecmdq, cpu); - - /* A core requires at most one ECMDQ */ + /* A core requires at most one ECMDQ */ + if (num_possible_cpus() < smmu->nr_ecmdq) smmu->nr_ecmdq = num_possible_cpus();
- return 0; - } - - for_each_node(node) - if (nr_cpus_node(node)) - nr_nodes++; - - if (nr_nodes >= smmu->nr_ecmdq) { - dev_err(smmu->dev, "%d ECMDQs is less than %d nodes\n", smmu->nr_ecmdq, nr_nodes); - return -ENOSPC; - } - - nr_ecmdqs = kcalloc(MAX_NUMNODES, sizeof(int), GFP_KERNEL); - if (!nr_ecmdqs) - return -ENOMEM; - - ecmdqs = kcalloc(smmu->nr_ecmdq, sizeof(*ecmdqs), GFP_KERNEL); - if (!ecmdqs) { - kfree(nr_ecmdqs); - return -ENOMEM; - } - - /* [1] Ensure that each node has at least one ECMDQ */ - nr_remain = smmu->nr_ecmdq - nr_nodes; - for_each_node(node) { - /* - * Calculate the number of ECMDQs to be allocated to this node. - * NR_ECMDQS_PER_CPU = nr_remain / num_possible_cpus(); - * When nr_cpus_node(node) is not zero, less than one ECMDQ - * may be left due to truncation rounding. - */ - nr_ecmdqs[node] = nr_cpus_node(node) * nr_remain / num_possible_cpus(); - } - - for_each_node(node) { - if (!nr_cpus_node(node)) - continue; - - nr_remain -= nr_ecmdqs[node]; - - /* An ECMDQ has been reserved for each node at above [1] */ - nr_ecmdqs[node]++; - } - - /* Divide the remaining ECMDQs */ - while (nr_remain) { - for_each_node(node) { - if (!nr_remain) - break; - - if (nr_ecmdqs[node] >= nr_cpus_node(node)) - continue; - - nr_ecmdqs[node]++; - nr_remain--; - } - } - - for_each_node(node) { - int i, round, shared; - - if (!nr_cpus_node(node)) - continue; - - shared = 0; - if (nr_ecmdqs[node] < nr_cpus_node(node)) - shared = 1; - - i = 0; - for_each_cpu(cpu, cpumask_of_node(node)) { - round = i % nr_ecmdqs[node]; - if (i++ < nr_ecmdqs[node]) - ecmdqs[round] = per_cpu_ptr(ecmdq, cpu); - else - ecmdqs[round]->cmdq.shared = shared; - *per_cpu_ptr(smmu->ecmdqs, cpu) = ecmdqs[round]; + for_each_possible_cpu(cpu) { + if (cpu < smmu->nr_ecmdq) { + *per_cpu_ptr(smmu->ecmdqs, cpu) = per_cpu_ptr(smmu->ecmdq, cpu); + } else { + host_cpu = cpu % smmu->nr_ecmdq; + ecmdq = per_cpu_ptr(smmu->ecmdq, host_cpu); + ecmdq->cmdq.shared = 1; + *per_cpu_ptr(smmu->ecmdqs, cpu) = ecmdq; } }
- kfree(nr_ecmdqs); - kfree(ecmdqs); - return 0; }
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I7YUNJ
--------------------------------
Add boot option arm_smmu_v3.disable_ecmdq to support disabling ECMDQ during startup. For example, add arm_smmu_v3.disable_ecmdq=1 in command line to disable ECMDQ and use normal CMDQ.
Signed-off-by: Zhen Lei thunder.leizhen@huawei.com --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 4419d6348f68511..d93ce123df49dc7 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -46,6 +46,10 @@ module_param(disable_msipolling, bool, 0444); MODULE_PARM_DESC(disable_msipolling, "Disable MSI-based polling for CMD_SYNC completion.");
+static bool disable_ecmdq; +module_param(disable_ecmdq, bool, 0444); +MODULE_PARM_DESC(disable_ecmdq, "Disable the use of ECMDQs"); + #ifdef CONFIG_SMMU_BYPASS_DEV struct smmu_bypass_device { unsigned short vendor; @@ -5129,7 +5133,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) dev_info(smmu->dev, "ias %lu-bit, oas %lu-bit (features 0x%08x)\n", smmu->ias, smmu->oas, smmu->features);
- if (smmu->features & ARM_SMMU_FEAT_ECMDQ) { + if (smmu->features & ARM_SMMU_FEAT_ECMDQ && !disable_ecmdq) { int err;
err = arm_smmu_ecmdq_probe(smmu);
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/2040 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/4...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/2040 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/4...