Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cpufreq: mediatek-hw: Wait for CPU supplies before probing

Before proceeding with the probe and enabling frequency scaling for the
CPUs, make sure that all supplies feeding the CPUs have probed.

This fixes an issue observed on MT8195-Tomato where if the
mediatek-cpufreq-hw driver enabled the hardware (by writing to
REG_FREQ_ENABLE) before the SPMI controller driver (spmi-mtk-pmif),
behind which lies the big CPU supply, probed the platform would hang
shortly after with "rcu: INFO: rcu_preempt detected stalls on
CPUs/tasks" being printed in the log.

Fixes: 4855e26bcf4d ("cpufreq: mediatek-hw: Add support for CPUFREQ HW")
Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>

authored by

Nícolas F. R. A. Prado and committed by
Viresh Kumar
788715b5 f661017e

+18 -1
+18 -1
drivers/cpufreq/mediatek-cpufreq-hw.c
··· 13 13 #include <linux/of.h> 14 14 #include <linux/of_platform.h> 15 15 #include <linux/platform_device.h> 16 + #include <linux/regulator/consumer.h> 16 17 #include <linux/slab.h> 17 18 18 19 #define LUT_MAX_ENTRIES 32U ··· 301 300 static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev) 302 301 { 303 302 const void *data; 304 - int ret; 303 + int ret, cpu; 304 + struct device *cpu_dev; 305 + struct regulator *cpu_reg; 306 + 307 + /* Make sure that all CPU supplies are available before proceeding. */ 308 + for_each_possible_cpu(cpu) { 309 + cpu_dev = get_cpu_device(cpu); 310 + if (!cpu_dev) 311 + return dev_err_probe(&pdev->dev, -EPROBE_DEFER, 312 + "Failed to get cpu%d device\n", cpu); 313 + 314 + cpu_reg = devm_regulator_get_optional(cpu_dev, "cpu"); 315 + if (IS_ERR(cpu_reg)) 316 + return dev_err_probe(&pdev->dev, PTR_ERR(cpu_reg), 317 + "CPU%d regulator get failed\n", cpu); 318 + } 319 + 305 320 306 321 data = of_device_get_match_data(&pdev->dev); 307 322 if (!data)