| From c4efc8ce27a8db0b812c94d063c482251fd3d605 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 27 Feb 2024 20:52:31 +0800 |
| Subject: drivers/perf: hisi: Enable HiSilicon Erratum 162700402 quirk for |
| HIP09 |
| |
| From: Junhao He <hejunhao3@huawei.com> |
| |
| [ Upstream commit e10b6976f6b9afdf3564f88c851e42d139bb19c0 ] |
| |
| HiSilicon UC PMU v2 suffers the erratum 162700402 that the PMU counter |
| cannot be set due to the lack of clock under power saving mode. This will |
| lead to error or inaccurate counts. The clock can be enabled by the PMU |
| global enabling control. |
| |
| This patch tries to fix this by set the UC PMU enable before set event |
| period to turn on the clock, and then restore the UC PMU configuration. |
| The counter register can hold its value without a clock. |
| |
| Signed-off-by: Junhao He <hejunhao3@huawei.com> |
| Reviewed-by: Yicong Yang <yangyicong@hisilicon.com> |
| Link: https://lore.kernel.org/r/20240227125231.53127-1-hejunhao3@huawei.com |
| Signed-off-by: Will Deacon <will@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/perf/hisilicon/hisi_uncore_uc_pmu.c | 42 ++++++++++++++++++++- |
| 1 file changed, 41 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c |
| index 636fb79647c8c..481dcc9e8fbf8 100644 |
| --- a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c |
| +++ b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c |
| @@ -287,12 +287,52 @@ static u64 hisi_uc_pmu_read_counter(struct hisi_pmu *uc_pmu, |
| return readq(uc_pmu->base + HISI_UC_CNTR_REGn(hwc->idx)); |
| } |
| |
| -static void hisi_uc_pmu_write_counter(struct hisi_pmu *uc_pmu, |
| +static bool hisi_uc_pmu_get_glb_en_state(struct hisi_pmu *uc_pmu) |
| +{ |
| + u32 val; |
| + |
| + val = readl(uc_pmu->base + HISI_UC_EVENT_CTRL_REG); |
| + return !!FIELD_GET(HISI_UC_EVENT_GLB_EN, val); |
| +} |
| + |
| +static void hisi_uc_pmu_write_counter_normal(struct hisi_pmu *uc_pmu, |
| struct hw_perf_event *hwc, u64 val) |
| { |
| writeq(val, uc_pmu->base + HISI_UC_CNTR_REGn(hwc->idx)); |
| } |
| |
| +static void hisi_uc_pmu_write_counter_quirk_v2(struct hisi_pmu *uc_pmu, |
| + struct hw_perf_event *hwc, u64 val) |
| +{ |
| + hisi_uc_pmu_start_counters(uc_pmu); |
| + hisi_uc_pmu_write_counter_normal(uc_pmu, hwc, val); |
| + hisi_uc_pmu_stop_counters(uc_pmu); |
| +} |
| + |
| +static void hisi_uc_pmu_write_counter(struct hisi_pmu *uc_pmu, |
| + struct hw_perf_event *hwc, u64 val) |
| +{ |
| + bool enable = hisi_uc_pmu_get_glb_en_state(uc_pmu); |
| + bool erratum = uc_pmu->identifier == HISI_PMU_V2; |
| + |
| + /* |
| + * HiSilicon UC PMU v2 suffers the erratum 162700402 that the |
| + * PMU counter cannot be set due to the lack of clock under power |
| + * saving mode. This will lead to error or inaccurate counts. |
| + * The clock can be enabled by the PMU global enabling control. |
| + * The irq handler and pmu_start() will call the function to set |
| + * period. If the function under irq context, the PMU has been |
| + * enabled therefore we set counter directly. Other situations |
| + * the PMU is disabled, we need to enable it to turn on the |
| + * counter clock to set period, and then restore PMU enable |
| + * status, the counter can hold its value without a clock. |
| + */ |
| + if (enable || !erratum) |
| + hisi_uc_pmu_write_counter_normal(uc_pmu, hwc, val); |
| + else |
| + hisi_uc_pmu_write_counter_quirk_v2(uc_pmu, hwc, val); |
| +} |
| + |
| static void hisi_uc_pmu_enable_counter_int(struct hisi_pmu *uc_pmu, |
| struct hw_perf_event *hwc) |
| { |
| -- |
| 2.43.0 |
| |