hulk inclusion category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/21064 -------------------------------- A bandwidth counter that is enabled when its MSC loses its last online CPU is read and cleared by mpam_save_mbwu_state(), and the value is added to mbwu_state->correction. mpam_reprogram_msc() restores the monitor later and __ris_msmon_read() adds correction to the value the hardware reports, which is how the traffic counted before the reset is kept. The two sides disagree about units. __ris_msmon_read() masks the value field and, on a monitor without the long counter, shifts it left by mbwu_scale. mpam_save_mbwu_state() adds the register as read: on the long counter that includes NRDY in bit 63 and the bits above the counter width, and on the short counter it includes NRDY in bit 31 and leaves the value unscaled. A monitor with mbwu_scale of 1 and a short counter therefore adds a correction twice the value the hardware reported. A monitor whose register had NRDY set at the time of the save adds 2^31 as if it were traffic. Mask the value the same way __ris_msmon_read() does, and apply mbwu_scale on the short counter path where the read path applies it. The long counter path selects the field by the counter width feature, matching the read path. Both paths shift by MBWUMON_IDR.SCALE without consulting the SCLEN bit that gen_msmon_ctl_flt_vals() programs from the same feature. The two stay consistent because the driver sets SCLEN exactly when mbwu_scale is non-zero, so the shift mirrors what the hardware did; keep that invariant in mind if the SCLEN condition ever changes. Only monitors that are enabled across a CPU offline reach the save path, and the difference in units needs either a non-zero mbwu_scale or a counter whose NRDY bit is set at the time of the save. Fixes: ee7098fbc7b0 ("arm_mpam: Add MBWU counter scaling support") Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index fc9ba63afe82..afccae608d03 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -1615,9 +1615,25 @@ static int mpam_save_mbwu_state(void *arg) if (mpam_ris_has_mbwu_long_counter(ris)) { val = mpam_msc_read_mbwu_l(msc); mpam_msc_zero_mbwu_l(msc); + /* + * The value field is not scaled for long counters, + * see __ris_msmon_read(). + */ + if (mpam_has_feature(mpam_feat_msmon_mbwu_63counter, + &ris->props)) + val = FIELD_GET(MSMON___LWD_VALUE, val); + else + val = FIELD_GET(MSMON___L_VALUE, val); } else { val = mpam_read_monsel_reg(msc, MBWU); mpam_write_monsel_reg(msc, MBWU, 0); + /* + * Strip NRDY and apply the same scale as the read + * path, so that correction is in the same unit as + * the value it is added to later. + */ + val = FIELD_GET(MSMON___VALUE, val); + val <<= ris->props.mbwu_scale; } cfg->mon = i; -- 2.34.1