]>
Commit | Line | Data |
---|---|---|
335f7cc0 SL |
1 | From c4efc8ce27a8db0b812c94d063c482251fd3d605 Mon Sep 17 00:00:00 2001 |
2 | From: Sasha Levin <sashal@kernel.org> | |
3 | Date: Tue, 27 Feb 2024 20:52:31 +0800 | |
4 | Subject: drivers/perf: hisi: Enable HiSilicon Erratum 162700402 quirk for | |
5 | HIP09 | |
6 | ||
7 | From: Junhao He <hejunhao3@huawei.com> | |
8 | ||
9 | [ Upstream commit e10b6976f6b9afdf3564f88c851e42d139bb19c0 ] | |
10 | ||
11 | HiSilicon UC PMU v2 suffers the erratum 162700402 that the PMU counter | |
12 | cannot be set due to the lack of clock under power saving mode. This will | |
13 | lead to error or inaccurate counts. The clock can be enabled by the PMU | |
14 | global enabling control. | |
15 | ||
16 | This patch tries to fix this by set the UC PMU enable before set event | |
17 | period to turn on the clock, and then restore the UC PMU configuration. | |
18 | The counter register can hold its value without a clock. | |
19 | ||
20 | Signed-off-by: Junhao He <hejunhao3@huawei.com> | |
21 | Reviewed-by: Yicong Yang <yangyicong@hisilicon.com> | |
22 | Link: https://lore.kernel.org/r/20240227125231.53127-1-hejunhao3@huawei.com | |
23 | Signed-off-by: Will Deacon <will@kernel.org> | |
24 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
25 | --- | |
26 | drivers/perf/hisilicon/hisi_uncore_uc_pmu.c | 42 ++++++++++++++++++++- | |
27 | 1 file changed, 41 insertions(+), 1 deletion(-) | |
28 | ||
29 | diff --git a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c | |
30 | index 636fb79647c8c..481dcc9e8fbf8 100644 | |
31 | --- a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c | |
32 | +++ b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c | |
33 | @@ -287,12 +287,52 @@ static u64 hisi_uc_pmu_read_counter(struct hisi_pmu *uc_pmu, | |
34 | return readq(uc_pmu->base + HISI_UC_CNTR_REGn(hwc->idx)); | |
35 | } | |
36 | ||
37 | -static void hisi_uc_pmu_write_counter(struct hisi_pmu *uc_pmu, | |
38 | +static bool hisi_uc_pmu_get_glb_en_state(struct hisi_pmu *uc_pmu) | |
39 | +{ | |
40 | + u32 val; | |
41 | + | |
42 | + val = readl(uc_pmu->base + HISI_UC_EVENT_CTRL_REG); | |
43 | + return !!FIELD_GET(HISI_UC_EVENT_GLB_EN, val); | |
44 | +} | |
45 | + | |
46 | +static void hisi_uc_pmu_write_counter_normal(struct hisi_pmu *uc_pmu, | |
47 | struct hw_perf_event *hwc, u64 val) | |
48 | { | |
49 | writeq(val, uc_pmu->base + HISI_UC_CNTR_REGn(hwc->idx)); | |
50 | } | |
51 | ||
52 | +static void hisi_uc_pmu_write_counter_quirk_v2(struct hisi_pmu *uc_pmu, | |
53 | + struct hw_perf_event *hwc, u64 val) | |
54 | +{ | |
55 | + hisi_uc_pmu_start_counters(uc_pmu); | |
56 | + hisi_uc_pmu_write_counter_normal(uc_pmu, hwc, val); | |
57 | + hisi_uc_pmu_stop_counters(uc_pmu); | |
58 | +} | |
59 | + | |
60 | +static void hisi_uc_pmu_write_counter(struct hisi_pmu *uc_pmu, | |
61 | + struct hw_perf_event *hwc, u64 val) | |
62 | +{ | |
63 | + bool enable = hisi_uc_pmu_get_glb_en_state(uc_pmu); | |
64 | + bool erratum = uc_pmu->identifier == HISI_PMU_V2; | |
65 | + | |
66 | + /* | |
67 | + * HiSilicon UC PMU v2 suffers the erratum 162700402 that the | |
68 | + * PMU counter cannot be set due to the lack of clock under power | |
69 | + * saving mode. This will lead to error or inaccurate counts. | |
70 | + * The clock can be enabled by the PMU global enabling control. | |
71 | + * The irq handler and pmu_start() will call the function to set | |
72 | + * period. If the function under irq context, the PMU has been | |
73 | + * enabled therefore we set counter directly. Other situations | |
74 | + * the PMU is disabled, we need to enable it to turn on the | |
75 | + * counter clock to set period, and then restore PMU enable | |
76 | + * status, the counter can hold its value without a clock. | |
77 | + */ | |
78 | + if (enable || !erratum) | |
79 | + hisi_uc_pmu_write_counter_normal(uc_pmu, hwc, val); | |
80 | + else | |
81 | + hisi_uc_pmu_write_counter_quirk_v2(uc_pmu, hwc, val); | |
82 | +} | |
83 | + | |
84 | static void hisi_uc_pmu_enable_counter_int(struct hisi_pmu *uc_pmu, | |
85 | struct hw_perf_event *hwc) | |
86 | { | |
87 | -- | |
88 | 2.43.0 | |
89 |