hulk inclusion category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/21064 -------------------------------- mpam_apply_config() sends the configuration to each RIS of a component through mpam_touch_msc(), which runs the write on a CPU that can reach the MSC. mpam_touch_msc() returns -ENXIO when none of the MSC's CPUs is online, and mpam_apply_config() discards the value and returns 0. The caller then treats a configuration that never reached the hardware as applied. resctrl_arch_update_domains() reports success to the schemata write, so userspace reads the new value back from the cached copy, while the MSC keeps the previous one. resctrl_arch_rmid_expand() records the binding of a request PARTID to an internal PARTID in reqpartid_map[] and returns, leaving the software map claiming a binding the hardware does not have. mpam_reprogram_msc() reprograms intPARTIDs when the CPUs come back, and those intPARTIDs use the mapping software recorded, so the two stay out of step until the map is rebuilt. ris->in_reset_state is cleared whether or not the write landed, so a RIS that is still in its reset state stops being reprogrammed on the next CPU online. Record the first failure from mpam_touch_msc() and return it. Clear ris->in_reset_state only for RISes whose write returned 0, and restore comp->cfg[partid] when any RIS failed, so the cached copy stops claiming a configuration the hardware rejected. resctrl_arch_rmid_expand() binds one request PARTID at a time through mpam_expand_one() and reverts the entry when the write fails; when the data half of a CDP pair fails after the code half was bound, revert the code half's map entry without re-running the sync, which would index comp->cfg[] by a request PARTID. Only writes that run while no CPU of an MSC is online fail in mpam_touch_msc(). mpam_resctrl_prepare_offline() refuses to offline a CPU while the file system is mounted and the L2 resource is visible, so the state is reached with the L2 resource hidden, or with an L3 or memory MSC whose CPUs are all offline. Fixes: be74872ad2e3 ("arm_mpam: Allow configuration to be applied and restored during cpu online") Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 35 ++++++++++++++-- drivers/platform/mpam/mpam_resctrl.c | 61 +++++++++++++++++++++++----- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index afccae608d03..c7ec1315d8ed 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -2803,7 +2803,8 @@ int mpam_apply_config(struct mpam_component *comp, u16 partid, { struct mpam_write_config_arg arg; struct mpam_msc_ris *ris; - int idx; + struct mpam_config old; + int err, idx; lockdep_assert_cpus_held(); @@ -2814,6 +2815,7 @@ int mpam_apply_config(struct mpam_component *comp, u16 partid, if (!memcmp(&comp->cfg[partid], cfg, sizeof(*cfg))) return 0; + old = comp->cfg[partid]; comp->cfg[partid] = *cfg; } @@ -2821,17 +2823,42 @@ int mpam_apply_config(struct mpam_component *comp, u16 partid, arg.partid = partid; arg.sync = sync; + err = 0; idx = srcu_read_lock(&mpam_srcu); list_for_each_entry_rcu(ris, &comp->ris, comp_list) { + int ret; + arg.ris = ris; mutex_lock(&ris->msc->lock); - mpam_touch_msc(ris->msc, __write_config, &arg); - ris->in_reset_state = false; + ret = mpam_touch_msc(ris->msc, __write_config, &arg); mutex_unlock(&ris->msc->lock); + + /* + * The MSC may not be reachable from any online CPU. Report + * that instead of pretending the configuration reached it, + * otherwise the caller and the software mapping disagree + * with the hardware. + */ + if (ret && !err) + err = ret; + + /* + * Only mark the RIS as configured once the write landed. + */ + if (!ret) + ris->in_reset_state = false; } srcu_read_unlock(&mpam_srcu, idx); - return 0; + /* + * The RISes are configured as a group. If any of them was not + * reachable, undo the software copy so that it does not claim a + * configuration the hardware does not have. + */ + if (err && !sync) + comp->cfg[partid] = old; + + return err; } static const struct of_device_id mpam_of_match[] = { diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index ad2848e322c6..0019305c4087 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -1484,24 +1484,63 @@ static int mpam_sync_config(u32 reqpartid) return 0; } -int resctrl_arch_rmid_expand(u32 closid) +/* + * Bind @reqpartid to @intpartid, then push the control group's existing + * configuration to it. The mapping has to be in place first: the sync + * path looks the intPARTID up through req2intpartid(). If the hardware + * write fails the mapping is rolled back, so the software mapping never + * claims a binding the hardware does not have. + */ +static int mpam_expand_one(u32 reqpartid, u32 intpartid) { u32 *map = reqpartid_map_writable(); - int i; + int err; + + map[reqpartid] = intpartid; + + err = mpam_sync_config(reqpartid); + if (err) + map[reqpartid] = reqpartid; + + return err; +} + +int resctrl_arch_rmid_expand(u32 closid) +{ + int i, err; for (i = resctrl_arch_get_num_closid(NULL); i < get_num_reqpartid(); i++) { - if (map[i] >= resctrl_arch_get_num_closid(NULL)) { + if (reqpartid_map_writable()[i] >= + resctrl_arch_get_num_closid(NULL)) { if (cdp_enabled) { - map[i] = resctrl_get_config_index(closid, CDP_DATA); - mpam_sync_config(i); - - map[i + 1] = resctrl_get_config_index(closid, CDP_CODE); - mpam_sync_config(i + 1); - + err = mpam_expand_one(i, + resctrl_get_config_index(closid, + CDP_DATA)); + if (err) + return err; + + err = mpam_expand_one(i + 1, + resctrl_get_config_index(closid, + CDP_CODE)); + if (err) { + /* + * Put the first half back. Its + * hardware write succeeded, but the + * pair is only usable together and + * re-running the sync here would + * index comp->cfg[i], which is out + * of range for a reqPARTID. + */ + reqpartid_map_writable()[i] = i; + return err; + } } else { - map[i] = resctrl_get_config_index(closid, CDP_NONE); - mpam_sync_config(i); + err = mpam_expand_one(i, + resctrl_get_config_index(closid, + CDP_NONE)); + if (err) + return err; } update_rmid_entries_for_reqpartid(i); -- 2.34.1