171 lines
6.6 KiB
Diff
171 lines
6.6 KiB
Diff
From 081bfa93450c8b4aa3f483eb14ec7a1bae34f9d4 Mon Sep 17 00:00:00 2001
|
|
From: Yicong Yang <yangyicong@hisilicon.com>
|
|
Date: Mon, 14 Aug 2023 20:40:12 +0800
|
|
Subject: [PATCH 54/55] perf/smmuv3: Enable HiSilicon Erratum 162001900 quirk
|
|
for HIP08/09
|
|
|
|
mainline inclusion
|
|
from mainline-v6.6-rc1
|
|
commit 0242737dc4eb9f6e9a5ea594b3f93efa0b12f28d
|
|
category: bugfix
|
|
bugzilla: https://gitee.com/openeuler/kernel/issues/I8AU2M
|
|
|
|
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0242737dc4eb9f6e9a5ea594b3f93efa0b12f28d
|
|
|
|
---------------------------------------------------------------------
|
|
|
|
Some HiSilicon SMMU PMCG suffers the erratum 162001900 that the PMU
|
|
disable control sometimes fail to disable the counters. This will lead
|
|
to error or inaccurate data since before we enable the counters the
|
|
counter's still counting for the event used in last perf session.
|
|
|
|
This patch tries to fix this by hardening the global disable process.
|
|
Before disable the PMU, writing an invalid event type (0xffff) to
|
|
focibly stop the counters. Correspondingly restore each events on
|
|
pmu::pmu_enable().
|
|
|
|
Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
|
|
Link: https://lore.kernel.org/r/20230814124012.58013-1-yangyicong@huawei.com
|
|
Signed-off-by: Will Deacon <will@kernel.org>
|
|
Signed-off-by: hongrongxuan <hongrongxuan@huawei.com>
|
|
|
|
Conflicts:
|
|
Documentation/arch/arm64/silicon-errata.rst
|
|
---
|
|
Documentation/arm64/silicon-errata.txt | 3 ++
|
|
drivers/acpi/arm64/iort.c | 5 ++-
|
|
drivers/perf/arm_smmuv3_pmu.c | 46 +++++++++++++++++++++++++-
|
|
include/linux/acpi_iort.h | 1 +
|
|
4 files changed, 53 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
|
|
index e733d13d7b98..c5aad5509a5a 100644
|
|
--- a/Documentation/arm64/silicon-errata.txt
|
|
+++ b/Documentation/arm64/silicon-errata.txt
|
|
@@ -80,6 +80,9 @@ stable kernels.
|
|
| Hisilicon | TSV{110,200} | #1980005 | HISILICON_ERRATUM_1980005 |
|
|
| Hisilicon | Hip09 | #162100801 | HISILICON_ERRATUM_161600801 |
|
|
| Hisilicon | Hip08 SMMU PMCG | #162001800 | N/A |
|
|
+| Hisilicon | Hip08 SMMU PMCG | #162001900 | N/A
|
|
+|
|
|
+| | Hip09 SMMU PMCG | |
|
|
| | | | |
|
|
| Qualcomm Tech. | Kryo/Falkor v1 | E1003 | QCOM_FALKOR_ERRATUM_1003 |
|
|
| Qualcomm Tech. | Falkor v1 | E1009 | QCOM_FALKOR_ERRATUM_1009 |
|
|
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
|
|
index abc62558e818..7cfbf52055f8 100644
|
|
--- a/drivers/acpi/arm64/iort.c
|
|
+++ b/drivers/acpi/arm64/iort.c
|
|
@@ -1479,7 +1479,10 @@ static void __init arm_smmu_v3_pmcg_init_resources(struct resource *res,
|
|
static struct acpi_platform_list pmcg_plat_info[] __initdata = {
|
|
/* HiSilicon Hip08 Platform */
|
|
{"HISI ", "HIP08 ", 0, ACPI_SIG_IORT, greater_than_or_equal,
|
|
- "Erratum #162001800", IORT_SMMU_V3_PMCG_HISI_HIP08},
|
|
+ "Erratum #162001800, Erratum #162001900", IORT_SMMU_V3_PMCG_HISI_HIP08},
|
|
+ /* HiSilicon Hip09 Platform */
|
|
+ {"HISI ", "HIP09 ", 0, ACPI_SIG_IORT, greater_than_or_equal,
|
|
+ "Erratum #162001900", IORT_SMMU_V3_PMCG_HISI_HIP09},
|
|
{ }
|
|
};
|
|
|
|
diff --git a/drivers/perf/arm_smmuv3_pmu.c b/drivers/perf/arm_smmuv3_pmu.c
|
|
index 3df836fd2f70..56e6f6773675 100644
|
|
--- a/drivers/perf/arm_smmuv3_pmu.c
|
|
+++ b/drivers/perf/arm_smmuv3_pmu.c
|
|
@@ -95,6 +95,7 @@
|
|
#define SMMU_PMCG_PA_SHIFT 12
|
|
|
|
#define SMMU_PMCG_EVCNTR_RDONLY BIT(0)
|
|
+#define SMMU_PMCG_HARDEN_DISABLE BIT(1)
|
|
|
|
static int cpuhp_state_num;
|
|
|
|
@@ -138,6 +139,20 @@ static inline void smmu_pmu_enable(struct pmu *pmu)
|
|
writel(SMMU_PMCG_CR_ENABLE, smmu_pmu->reg_base + SMMU_PMCG_CR);
|
|
}
|
|
|
|
+static int smmu_pmu_apply_event_filter(struct smmu_pmu *smmu_pmu,
|
|
+ struct perf_event *event, int idx);
|
|
+
|
|
+static inline void smmu_pmu_enable_quirk_hip08_09(struct pmu *pmu)
|
|
+{
|
|
+ struct smmu_pmu *smmu_pmu = to_smmu_pmu(pmu);
|
|
+ unsigned int idx;
|
|
+
|
|
+ for_each_set_bit(idx, smmu_pmu->used_counters, smmu_pmu->num_counters)
|
|
+ smmu_pmu_apply_event_filter(smmu_pmu, smmu_pmu->events[idx], idx);
|
|
+
|
|
+ smmu_pmu_enable(pmu);
|
|
+}
|
|
+
|
|
static inline void smmu_pmu_disable(struct pmu *pmu)
|
|
{
|
|
struct smmu_pmu *smmu_pmu = to_smmu_pmu(pmu);
|
|
@@ -146,6 +161,22 @@ static inline void smmu_pmu_disable(struct pmu *pmu)
|
|
writel(0, smmu_pmu->reg_base + SMMU_PMCG_IRQ_CTRL);
|
|
}
|
|
|
|
+static inline void smmu_pmu_disable_quirk_hip08_09(struct pmu *pmu)
|
|
+{
|
|
+ struct smmu_pmu *smmu_pmu = to_smmu_pmu(pmu);
|
|
+ unsigned int idx;
|
|
+
|
|
+ /*
|
|
+ * The global disable of PMU sometimes fail to stop the counting.
|
|
+ * Harden this by writing an invalid event type to each used counter
|
|
+ * to forcibly stop counting.
|
|
+ */
|
|
+ for_each_set_bit(idx, smmu_pmu->used_counters, smmu_pmu->num_counters)
|
|
+ writel(0xffff, smmu_pmu->reg_base + SMMU_PMCG_EVTYPER(idx));
|
|
+
|
|
+ smmu_pmu_disable(pmu);
|
|
+}
|
|
+
|
|
static inline void smmu_pmu_counter_set_value(struct smmu_pmu *smmu_pmu,
|
|
u32 idx, u64 value)
|
|
{
|
|
@@ -727,7 +758,10 @@ static void smmu_pmu_get_acpi_options(struct smmu_pmu *smmu_pmu)
|
|
switch (model) {
|
|
case IORT_SMMU_V3_PMCG_HISI_HIP08:
|
|
/* HiSilicon Erratum 162001800 */
|
|
- smmu_pmu->options |= SMMU_PMCG_EVCNTR_RDONLY;
|
|
+ smmu_pmu->options |= SMMU_PMCG_EVCNTR_RDONLY | SMMU_PMCG_HARDEN_DISABLE;
|
|
+ break;
|
|
+ case IORT_SMMU_V3_PMCG_HISI_HIP09:
|
|
+ smmu_pmu->options |= SMMU_PMCG_HARDEN_DISABLE;
|
|
break;
|
|
}
|
|
|
|
@@ -815,6 +849,16 @@ static int smmu_pmu_probe(struct platform_device *pdev)
|
|
|
|
smmu_pmu_get_acpi_options(smmu_pmu);
|
|
|
|
+ /*
|
|
+ * For platforms suffer this quirk, the PMU disable sometimes fails to
|
|
+ * stop the counters. This will leads to inaccurate or error counting.
|
|
+ * Forcibly disable the counters with these quirk handler.
|
|
+ */
|
|
+ if (smmu_pmu->options & SMMU_PMCG_HARDEN_DISABLE) {
|
|
+ smmu_pmu->pmu.pmu_enable = smmu_pmu_enable_quirk_hip08_09;
|
|
+ smmu_pmu->pmu.pmu_disable = smmu_pmu_disable_quirk_hip08_09;
|
|
+ }
|
|
+
|
|
/* Pick one CPU to be the preferred one to use */
|
|
smmu_pmu->on_cpu = raw_smp_processor_id();
|
|
WARN_ON(irq_set_affinity(smmu_pmu->irq, cpumask_of(smmu_pmu->on_cpu)));
|
|
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
|
|
index bdb69125854e..b1c1c84a422e 100644
|
|
--- a/include/linux/acpi_iort.h
|
|
+++ b/include/linux/acpi_iort.h
|
|
@@ -32,6 +32,7 @@
|
|
*/
|
|
#define IORT_SMMU_V3_PMCG_GENERIC 0x00000000 /* Generic SMMUv3 PMCG */
|
|
#define IORT_SMMU_V3_PMCG_HISI_HIP08 0x00000001 /* HiSilicon HIP08 PMCG */
|
|
+#define IORT_SMMU_V3_PMCG_HISI_HIP09 0x00000002 /* HiSilicon HIP09 PMCG */
|
|
|
|
int iort_register_domain_token(int trans_id, phys_addr_t base,
|
|
struct fwnode_handle *fw_node);
|
|
--
|
|
2.27.0
|
|
|