| From 452edfd767a5acd169f0f17e5d0513a9ed62a2d9 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 30 May 2025 15:38:08 +0200 |
| Subject: PM / devfreq: rockchip-dfi: double count on RK3588 |
| |
| From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com> |
| |
| [ Upstream commit f89c7fb83ae95578e355bed1a7aeea5f3ca5a067 ] |
| |
| On RK3588 with LPDDR4X memory, the cycle count as returned by |
| |
| perf stat -a -e rockchip_ddr/cycles/ sleep 1 |
| |
| consistently reads half as much as what the actual DDR frequency is at. |
| For a LPDDR4X module running at 2112MHz, I get more like 1056059916 |
| cycles per second, which is almost bang-on half what it should be. No, |
| I'm not mixing up megatransfers and megahertz. |
| |
| Consulting the downstream driver, this appears to be because the RK3588 |
| hardware specifically (and RK3528 as well, for future reference) needs a |
| multiplier of 2 to get to the correct frequency with everything but |
| LPDDR5. |
| |
| The RK3588's actual memory bandwidth measurements in MB/s are correct |
| however, as confirmed with stress-ng --stream. This makes me think the |
| access counters are not affected in the same way. This tracks with the |
| vendor kernel not multiplying the access counts either. |
| |
| Solve this by adding a new member to the dfi struct, which each SoC can |
| set to whatever they want, but defaults to 1 if left unset by the SoC |
| init functions. The event_get_count op can then use this multiplier if |
| the cycle count is requested. |
| |
| The cycle multiplier is not used in rockchip_dfi_get_event because the |
| vendor driver doesn't use it there either, and we don't do other actual |
| bandwidth unit conversion stuff in there anyway. |
| |
| Fixes: 481d97ba61e1 ("PM / devfreq: rockchip-dfi: add support for RK3588") |
| Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com> |
| Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> |
| Link: https://lore.kernel.org/lkml/20250530-rk3588-dfi-improvements-v1-1-6e077c243a95@collabora.com/ |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/devfreq/event/rockchip-dfi.c | 7 ++++++- |
| 1 file changed, 6 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c |
| index 0470d7c175f4f..54effb6351965 100644 |
| --- a/drivers/devfreq/event/rockchip-dfi.c |
| +++ b/drivers/devfreq/event/rockchip-dfi.c |
| @@ -116,6 +116,7 @@ struct rockchip_dfi { |
| int buswidth[DMC_MAX_CHANNELS]; |
| int ddrmon_stride; |
| bool ddrmon_ctrl_single; |
| + unsigned int count_multiplier; /* number of data clocks per count */ |
| }; |
| |
| static int rockchip_dfi_enable(struct rockchip_dfi *dfi) |
| @@ -435,7 +436,7 @@ static u64 rockchip_ddr_perf_event_get_count(struct perf_event *event) |
| |
| switch (event->attr.config) { |
| case PERF_EVENT_CYCLES: |
| - count = total.c[0].clock_cycles; |
| + count = total.c[0].clock_cycles * dfi->count_multiplier; |
| break; |
| case PERF_EVENT_READ_BYTES: |
| for (i = 0; i < dfi->max_channels; i++) |
| @@ -655,6 +656,9 @@ static int rockchip_ddr_perf_init(struct rockchip_dfi *dfi) |
| break; |
| } |
| |
| + if (!dfi->count_multiplier) |
| + dfi->count_multiplier = 1; |
| + |
| ret = perf_pmu_register(pmu, "rockchip_ddr", -1); |
| if (ret) |
| return ret; |
| @@ -751,6 +755,7 @@ static int rk3588_dfi_init(struct rockchip_dfi *dfi) |
| dfi->max_channels = 4; |
| |
| dfi->ddrmon_stride = 0x4000; |
| + dfi->count_multiplier = 2; |
| |
| return 0; |
| }; |
| -- |
| 2.51.0 |
| |