From: sashiko-bot@kernel.org
To: "Sumit Gupta" <sumitg@nvidia.com>, devicetree@vger.kernel.org
Cc: robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH 7/9] cpufreq: tegra194: derive frequency domain from device tree
Date: Wed, 04 Nov 2026 18:36:32 +0000 [thread overview]
Message-ID: <sashiko-outbox-197853@kernel.org> (raw)
In-Reply-To: <20261104181521.3003578-8-sumitg@nvidia.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] cpufreq: tegra194: unvalidated cluster LUT for multi-cluster policy
- [High] cpufreq: tegra194: unvalidated cpuid and clusterid in tegra194_get_speed()
--
commit 92b7184ee71717b6f0c29371b05878084c1e552d
Author: Sumit Gupta <sumitg@nvidia.com>
cpufreq: tegra194: derive frequency domain from device tree
This commit updates tegra194_cpufreq_init() to group CPUs into policies using
the device tree performance-domains property when present, allowing a single
policy to span multiple clusters and storing the domain index in clkid.
> diff --git a/drivers/cpufreq/tegra194-cpufreq.c b/drivers/cpufreq/tegra194-cpufreq.c
> index 047166463efef..1328aa0a1bd1a 100644
> --- a/drivers/cpufreq/tegra194-cpufreq.c
> +++ b/drivers/cpufreq/tegra194-cpufreq.c
[ ... ]
> @@ -528,21 +529,45 @@ static int tegra194_cpufreq_init(struct cpufreq_policy *policy)
> {
> struct tegra194_cpufreq_data *data = cpufreq_get_driver_data();
> int maxcpus_per_cluster = data->soc->maxcpus_per_cluster;
> - u32 clusterid = data->cpu_data[policy->cpu].clusterid;
> struct cpufreq_frequency_table *freq_table;
> struct cpufreq_frequency_table *bpmp_lut;
> - u32 start_cpu, cpu;
> + struct of_phandle_args args;
> + u32 start_cpu, cpu, clusterid;
> int ret;
>
> + /* Covers all possible CPUs, so offline siblings are grouped too. */
> + ret = of_perf_domain_get_sharing_cpumask(policy->cpu, "performance-domains",
> + "#performance-domain-cells",
> + policy->cpus, &args);
> + if (!ret) {
> + if (args.args_count != 1) {
> + pr_err("cpufreq: cpu%u: invalid #performance-domain-cells\n",
> + policy->cpu);
> + of_node_put(args.np);
> + return -EINVAL;
> + }
> +
> + for_each_cpu(cpu, policy->cpus)
> + data->cpu_data[cpu].clkid = args.args[0];
> +
> + of_node_put(args.np);
> + } else if (ret == -ENOENT) {
> + /* Legacy grouping for DTs without performance-domains. */
> + start_cpu = rounddown(policy->cpu, maxcpus_per_cluster);
> + for (cpu = start_cpu; cpu < (start_cpu + maxcpus_per_cluster); cpu++)
> + if (cpu_possible(cpu))
> + cpumask_set_cpu(cpu, policy->cpus);
> + } else {
> + pr_err("cpufreq: cpu%u: failed to get performance domain: %d\n",
> + policy->cpu, ret);
> + return ret;
> + }
> +
> + /* The BPMP LUT is indexed by the MPIDR cluster id, not clkid. */
> + clusterid = data->cpu_data[policy->cpu].clusterid;
> if (clusterid >= data->soc->num_clusters || !data->bpmp_luts[clusterid])
> return -EINVAL;
[Severity: High]
Since policy->cpus can now span multiple clusters, what happens when
tegra194_get_speed() is called for a CPU in another cluster of the same
policy (for example via cpufreq_get(), or after the initial policy->cpu goes
offline and cpufreq_offline() migrates policy->cpu to a sibling in a second
cluster without re-running tegra194_cpufreq_init())?
tegra194_cpufreq_init() only validates clusterid and
data->bpmp_luts[clusterid] for the initial policy->cpu, but
tegra194_get_speed() indexes data->bpmp_luts[] using the queried CPU's own
clusterid:
drivers/cpufreq/tegra194-cpufreq.c:tegra194_get_speed() {
...
u32 clusterid = data->cpu_data[cpu].clusterid;
...
cpufreq_for_each_valid_entry(pos, data->bpmp_luts[clusterid]) {
}
If tegra_cpufreq_bpmp_read_lut() returned -BPMP_EINVAL for that secondary
cluster (leaving data->bpmp_luts[clusterid] as NULL), or if that CPU's
clusterid is >= data->soc->num_clusters on an SoC where get_cpu_ndiv() does
not depend on freq_core_reg (such as Tegra194 or Tegra264), can
tegra194_get_speed() dereference a NULL pointer or read out of bounds in
data->bpmp_luts[]?
[Severity: High]
Can tegra194_get_speed() also trigger an out-of-bounds MMIO read in
tegra234_sample_counters() when cpuid or clusterid is out of bounds?
In tegra_cpufreq_cpu_online(), cpuid and clusterid from MPIDR are stored in
data->cpu_data[cpu] unconditionally, and if either is out of bounds, it logs
a warning, leaves freq_core_reg as NULL, and still returns 0:
drivers/cpufreq/tegra194-cpufreq.c:tegra_cpufreq_cpu_online() {
...
data->cpu_data[cpu].cpuid = cpuid;
data->cpu_data[cpu].clusterid = clusterid;
/* Derive per-core register address only when ccplex MMIO is mapped. */
if (data->regs) {
if (clusterid >= data->soc->num_clusters ||
cpuid >= data->soc->maxcpus_per_cluster) {
pr_warn_once("cpufreq: cpu%u: bad MPIDR (cluster %u, core %u)\n",
cpu, clusterid, cpuid);
}
tegra194_cpufreq_init() does not check cpuid >= data->soc->maxcpus_per_cluster
for policy->cpu, nor does it validate clusterid or cpuid for cross-cluster or
initially offline sibling CPUs in policy->cpus (which may later come online
via tegra194_cpufreq_online() without re-running tegra194_cpufreq_init()).
When tegra194_get_speed() runs on such a CPU, it calls
tegra194_calculate_speed() before get_cpu_ndiv() checks freq_core_reg:
drivers/cpufreq/tegra194-cpufreq.c:tegra194_get_speed() {
...
/* reconstruct actual cpu freq using counters */
rate = tegra194_calculate_speed(cpu);
/* get last written ndiv value */
ret = data->soc->ops->get_cpu_ndiv(cpu, data->cpu_data[cpu].cpuid, clusterid, &ndiv);
}
On Tegra234 and Tegra238, tegra194_calculate_speed()->tegra_read_counters()->
tegra234_sample_counters() computes actmon_reg directly from the unvalidated
clusterid and cpuid without checking freq_core_reg:
drivers/cpufreq/tegra194-cpufreq.c:tegra234_sample_counters() {
...
actmon_reg = CORE_ACTMON_CNTR_REG(data, data->cpu_data[c->cpu].clusterid,
data->cpu_data[c->cpu].cpuid);
val = readq(actmon_reg);
}
Could this read past the mapped MMIO region in data->regs?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261104181521.3003578-1-sumitg@nvidia.com?part=7
next prev parent reply other threads:[~2026-11-04 18:36 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-04 18:15 [PATCH 0/9] cpufreq: tegra194: add Tegra264 support Sumit Gupta
2026-11-04 18:15 ` [PATCH 1/9] cpufreq: tegra194: move MPIDR read to CPU hotplug callback Sumit Gupta
2026-11-04 18:29 ` sashiko-bot
2026-11-04 18:15 ` [PATCH 2/9] cpufreq: tegra194: remove duplicate counter sampling loops Sumit Gupta
2026-11-04 18:15 ` [PATCH 3/9] cpufreq: tegra194: add tegra_counter_delta helper Sumit Gupta
2026-11-04 18:15 ` [PATCH 4/9] cpufreq: tegra194: add per-SoC counter mask Sumit Gupta
2026-11-04 18:15 ` [PATCH 5/9] cpufreq: tegra194: split MMIO mapping from ACTMON offset Sumit Gupta
2026-11-04 18:15 ` [PATCH 6/9] dt-bindings: arm: nvidia: Document the Tegra264 CCPLEX cluster Sumit Gupta
2026-11-04 18:15 ` [PATCH 7/9] cpufreq: tegra194: derive frequency domain from device tree Sumit Gupta
2026-11-04 18:36 ` sashiko-bot [this message]
2026-11-04 18:15 ` [PATCH 8/9] cpufreq: tegra194: Add support for Tegra264 Sumit Gupta
2026-11-04 18:15 ` [PATCH 9/9] arm64: tegra: Add CCPLEX cluster node " Sumit Gupta
2026-11-04 18:41 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-197853@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=sumitg@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.