hulk inclusion category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/21064 -------------------------------- mpam_thread_switch() loads the task's MPAM1_EL1 value for the CPU whenever the task carries a resctrl label, and the CPU default otherwise. It decides "carries a label" by calling req2intpartid() on the task's request PARTID and treating a zero internal PARTID as "no label". Under Narrow-PARTID a request PARTID at or above the intPARTID count maps onto a small intPARTID, zero included, so a task in a monitor group of the root control group reports internal PARTID 0 for a request PARTID that is not zero. mpam_thread_switch() then programs the task's MPAM1_EL1 with the CPU default, so the task's memory accesses carry the default PARTID and the monitor group's counter does not advance for them. The group exists to account for that task's traffic and accounts for none of it. Test the request side instead. PARTID_I stays out of the test: CDP makes mpam_set_task_partid_pmg() write partid_d + 1 there, so a task moved back to the root control group holds (0, 1, _, _) and has to follow the CPU default, which is the behaviour introduced by commit ec5074d9367a ("arm64/mpam: Fix incorrect CPU-to-partid binding under CDP mode"). PMG_D has to be part of the test: RMID encodes as (reqPARTID << shift) | PMG, so a monitor group of control group 0 holds a non-zero PMG while PARTID_D stays 0. mpam_get_regval_partid() has no other caller, so remove it. Only systems with the Narrow-PARTID feature are affected. Where the request PARTID is the internal PARTID, req2intpartid() returns its argument and the defect cannot arise. QEMU increments an enabled bandwidth monitor at a fixed rate whatever PARTID runs, so the accounting is not observable in emulation. Fixes: cb30664e92e8 ("arm_mpam: Refactor rmid to reqPARTID/PMG mapping") Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> --- arch/arm64/include/asm/mpam.h | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h index 4d0a66013e3f..f98b22198d95 100644 --- a/arch/arm64/include/asm/mpam.h +++ b/arch/arm64/include/asm/mpam.h @@ -131,11 +131,35 @@ static inline u64 mpam_get_regval(struct task_struct *tsk) u32 req2intpartid(u32 reqpartid); -static inline u32 mpam_get_regval_partid(u64 regval) +/* + * Does the task carry a resctrl label of its own? Only the request side + * matters: PARTID_D identifies the control group and PMG_D the monitor + * group within it. + * + * The instruction-side fields are not useful here. Under CDP + * mpam_set_task_partid_pmg() writes partid_i as partid_d + 1 but leaves + * pmg_i equal to pmg_d, so PARTID_I is derived rather than independent, + * and PMG_I only repeats PMG_D. + * + * Looking at PARTID_I, or at req2intpartid() of PARTID_D, gets it wrong in + * both directions: + * + * - Under CDP a task moved back to the root control group is given + * (0, 1, _, _). It must follow the CPU's default label, see + * ec5074d9367a. A raw "any field non-zero" test would keep the stale + * label instead. + * + * - With Narrow-PARTID a task in a root monitor group can carry + * reqPARTID above the intPARTID count, which maps back to intPARTID 0. + * It must keep its own label so the monitor group sees the traffic. + * + * PMG_D has to be part of the test: RMID encodes as + * (reqPARTID << shift) | PMG, so a monitor group of control group 0 with a + * non-zero PMG still has PARTID_D == 0. + */ +static inline bool mpam_regval_has_tag(u64 regval) { - u32 reqpartid = (regval & MPAM_SYSREG_PARTID_D) >> 16; - - return req2intpartid(reqpartid); + return regval & (MPAM_SYSREG_PARTID_D | MPAM_SYSREG_PMG_D); } static inline void mpam_thread_switch(struct task_struct *tsk) @@ -148,7 +172,7 @@ static inline void mpam_thread_switch(struct task_struct *tsk) !static_branch_likely(&mpam_enabled)) return; - if (!regval || !mpam_get_regval_partid(regval)) + if (!mpam_regval_has_tag(regval)) regval = READ_ONCE(per_cpu(arm64_mpam_default, cpu)); oldregval = READ_ONCE(per_cpu(arm64_mpam_current, cpu)); -- 2.34.1