hulk inclusion category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/21064 -------------------------------- mpam_msc_hw_probe() derives two limits from an MSC's RISes: partid_max, the request PARTID limit, and intpartid_max, the number of distinct configurations. mpam_ris_hw_probe() runs once per RIS and folds the RIS's own limit into both. Folding into intpartid_max is an assignment, not a clamp. A RIS with PARTID narrowing sets intpartid_max to the MSC's INTPARTID_MAX; a RIS without narrowing sets it to msc->partid_max, which at that point is the minimum over every RIS seen so far. The second form overwrites whatever an earlier RIS established. PARTID narrowing is global to an MSC, so all RISes of one MSC agree on it, but the limits they report are not necessarily the same: MPAMF_IDR.PARTID_MAX is permitted to vary between the instances of MPAMF_IDR, each reporting the space of its own resource instance. With RIS0 reporting a smaller PARTID space than RIS1, RIS1 writes back its larger value over the minimum RIS0 established, and the minimum is lost. mpam_msc_hw_probe() takes the system-wide minimum after the loop, but msc->intpartid_max already holds the overwritten value by then, and the system-wide minimum inherits it. resctrl_arch_get_num_closid() reports intpartid_max + 1, so the driver advertises more control groups than the RIS with the smaller space can hold. Configuring one of those groups programs that RIS with an intPARTID above its maximum, which the architecture describes as CONSTRAINED UNPREDICTABLE behaviour for the request that carries it. Start intpartid_max at the MSC-wide limit before the loop and take min() of it in both branches. The non-narrowing branch now reads the RIS's own PARTID limit from ris->idr instead of msc->partid_max: by the time mpam_ris_hw_probe() runs, msc->partid_max already includes this RIS and states the common limit of the RISes processed so far, which understates the RIS's own space and depends on probe order. Every RIS reports a PARTID_MAX value, and the field is per instance, so an MSC whose RISes report different values is affected regardless of whether it implements PARTID narrowing. QEMU gives every RIS of an MSC the same IDR, so the disagreement cannot be built in emulation. Fixes: 26b0eaa72060 ("arm_mpam: Add intPARTID and reqPARTID support for narrow PARTID feature") Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index e78352e2dcb2..e934fdb91414 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -785,9 +785,17 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) u16 partid_max = FIELD_GET(MPAMF_PARTID_NRW_IDR_INTPARTID_MAX, nrwidr); mpam_set_feature(mpam_feat_partid_nrw, props); - msc->intpartid_max = min(msc->partid_max, partid_max); + msc->intpartid_max = min(msc->intpartid_max, partid_max); } else { - msc->intpartid_max = msc->partid_max; + /* + * Without narrowing every request PARTID needs its own + * configuration, so the intPARTID space is the RIS's own + * PARTID space. Take the minimum over all RIS instead of + * overwriting: a previous RIS may have had a smaller limit. + */ + msc->intpartid_max = min(msc->intpartid_max, + FIELD_GET(MPAMF_IDR_PARTID_MAX, + ris->idr)); } } @@ -824,6 +832,7 @@ static int mpam_msc_hw_probe(struct mpam_msc *msc) /* Use these values so partid/pmg always starts with a valid value */ msc->partid_max = FIELD_GET(MPAMF_IDR_PARTID_MAX, idr); + msc->intpartid_max = msc->partid_max; msc->pmg_max = mpam_pmg_max_workaround(idr); for (ris_idx = 0; ris_idx <= msc->ris_max; ris_idx++) { -- 2.34.1