Devicetree
 help / color / mirror / Atom feed
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

  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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox