[PATCH RFC 14/15] arm_mpam: Support MSC accessibility derivation from RIS nodes
Yin Li <[email protected]>
| Newsgroups | dev.linux.lists.driver-core,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <20260811-mpam-resctrl-dt-knp-support-v1-14-ea6397bead59@oss.qualcomm.com> |
The DT accessibility derivation only handled MSCs whose parent node is a cache or memory device. When the MSC is placed under a generic container (e.g. directly under /soc), the parent gives no affinity hint and there is no fallback. Add a per-RIS fallback path for when the parent node is not a recognised cache or memory device. For each available RIS child node, affinity is resolved in two steps: first from an explicit 'cpus' phandle-array on the RIS node, then from the 'arm,mpam-device' phandle. The final accessibility mask is the union of all RIS masks; if any RIS fails to resolve, the mask is cleared and the MSC fails to probe rather than come up with a partial affinity. Factor the DT-specific logic into mpam_dt_update_msc_accessibility() so that update_msc_accessibility() dispatches cleanly between ACPI and DT paths. Co-developed-by: Huang Yiwei <[email protected]> Signed-off-by: Huang Yiwei <[email protected]> Signed-off-by: Yin Li <[email protected]> --- drivers/resctrl/mpam_devices.c | 146 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 131 insertions(+), 15 deletions(-) diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c index d8856864e89a..d0462239deeb 100644 --- a/drivers/resctrl/mpam_devices.c +++ b/drivers/resctrl/mpam_devices.c @@ -2156,6 +2156,136 @@ static int mpam_msc_setup_error_irq(struct mpam_msc *msc) return 0; } +/* + * Resolve a RIS to its CPU affinity from its 'cpus' phandle-array. + * Returns -ENODEV when 'cpus' is absent (the caller may use another source), + * -EINVAL when any phandle is invalid, or 0 on full success. + */ +static int get_cpumask_from_ris_cpus(struct device_node *ris_np, + cpumask_t *affinity) +{ + int i, cpu_phandle_count; + + cpu_phandle_count = of_count_phandle_with_args(ris_np, "cpus", NULL); + if (cpu_phandle_count <= 0) + return -ENODEV; + + for (i = 0; i < cpu_phandle_count; i++) { + struct device_node *phandle_np __free(device_node) = + of_parse_phandle(ris_np, "cpus", i); + int cpu, matched = -1; + + if (phandle_np) { + for_each_possible_cpu(cpu) { + struct device_node *cpu_node __free(device_node) = + of_get_cpu_node(cpu, NULL); + + if (phandle_np == cpu_node) { + matched = cpu; + break; + } + } + } + + if (matched < 0) { + pr_warn("MPAM: RIS %pOF cpus[%d] (%pOF) is not a possible CPU\n", + ris_np, i, phandle_np); + return -EINVAL; + } + + cpumask_set_cpu(matched, affinity); + } + + return 0; +} + +/* + * Resolve a RIS to its CPU affinity from its 'arm,mpam-device' phandle. + * Returns -EINVAL when 'arm,mpam-device' is absent or the phandle is invalid. + * 0 on full success. + */ +static int get_cpumask_from_ris_phandle(struct device_node *ris, + cpumask_t *affinity) +{ + struct device_node *mpam_device __free(device_node) = + of_parse_phandle(ris, "arm,mpam-device", 0); + + if (!mpam_device) { + pr_warn("MPAM: RIS %pOF has neither 'cpus' nor 'arm,mpam-device'\n", + ris); + return -EINVAL; + } + + if (of_device_is_compatible(mpam_device, "cache")) + return get_cpumask_from_cache(mpam_device, affinity); + + if (of_device_is_compatible(mpam_device, "memory")) { + cpumask_or(affinity, affinity, cpu_possible_mask); + return 0; + } + + return -EINVAL; +} + +static int get_cpumask_from_ris(struct device_node *ris, cpumask_t *affinity) +{ + int err; + + err = get_cpumask_from_ris_cpus(ris, affinity); + if (err != -ENODEV) + return err; + + return get_cpumask_from_ris_phandle(ris, affinity); +} + +/* + * Returns -ENODEV when the parent is just a container (not a recognised device), + * so the caller falls back to the per-RIS description. + */ +static int get_cpumask_from_parent(struct mpam_msc *msc, cpumask_t *affinity) +{ + struct device_node *parent __free(device_node) = + of_get_parent(msc->pdev->dev.of_node); + + if (parent == of_root) { + cpumask_copy(affinity, cpu_possible_mask); + return 0; + } + + if (of_device_is_compatible(parent, "cache")) + return get_cpumask_from_cache(parent, affinity); + + if (of_device_is_compatible(parent, "memory")) { + cpumask_copy(affinity, cpu_possible_mask); + return 0; + } + + return -ENODEV; +} + +/* + * An MSC's CPU affinity is described either by its parent node or, when the + * parent is just a container, per-RIS inside the MSC. In the per-RIS case the + * accessibility is the union of the RIS affinities: every RIS must resolve, so + * a single failure clears the mask and stops and the MSC fails to probe rather + * than come up with a partial affinity. + */ +static void mpam_dt_update_msc_accessibility(struct mpam_msc *msc) +{ + cpumask_t *affinity = &msc->accessibility; + + cpumask_clear(affinity); + + if (get_cpumask_from_parent(msc, affinity) == -ENODEV) { + for_each_available_child_of_node_scoped(msc->pdev->dev.of_node, ris) { + if (get_cpumask_from_ris(ris, affinity)) { + cpumask_clear(affinity); + break; + } + } + } +} + /* * An MSC can control traffic from a set of CPUs, but may only be accessible * from a (hopefully wider) set of CPUs. The common reason for this is power @@ -2165,8 +2295,6 @@ static int mpam_msc_setup_error_irq(struct mpam_msc *msc) */ static void update_msc_accessibility(struct mpam_msc *msc) { - struct device *dev = &msc->pdev->dev; - struct device_node *parent; u32 affinity_id; int err; @@ -2182,19 +2310,7 @@ static void update_msc_accessibility(struct mpam_msc *msc) return; } - /* Where an MSC can be accessed from depends on the path to of_node. */ - parent = of_get_parent(msc->pdev->dev.of_node); - if (parent == of_root) { - cpumask_copy(&msc->accessibility, cpu_possible_mask); - } else { - if (of_device_is_compatible(parent, "cache")) - get_cpumask_from_cache(parent, &msc->accessibility); - else if (of_device_is_compatible(parent, "memory")) - cpumask_copy(&msc->accessibility, cpu_possible_mask); - else - dev_err_once(dev, "Cannot determine accessibility of MSC.\n"); - } - of_node_put(parent); + mpam_dt_update_msc_accessibility(msc); } /* -- 2.34.1