Skip to content

Commit a937feb

Browse files
wensKelsey Skunberg
authored and
Kelsey Skunberg
committed
regulator: vctrl: Avoid lockdep warning in enable/disable ops
BugLink: https://bugs.launchpad.net/bugs/1946024 [ Upstream commit 21e3980 ] vctrl_enable() and vctrl_disable() call regulator_enable() and regulator_disable(), respectively. However, vctrl_* are regulator ops and should not be calling the locked regulator APIs. Doing so results in a lockdep warning. Instead of exporting more internal regulator ops, model the ctrl supply as an actual supply to vctrl-regulator. At probe time this driver still needs to use the consumer API to fetch its constraints, but otherwise lets the regulator core handle the upstream supply for it. The enable/disable/is_enabled ops are not removed, but now only track state internally. This preserves the original behavior with the ops being available, but one could argue that the original behavior was already incorrect: the internal state would not match the upstream supply if that supply had another consumer that enabled the supply, while vctrl-regulator was not enabled. The lockdep warning is as follows: WARNING: possible circular locking dependency detected 5.14.0-rc6 #2 Not tainted ------------------------------------------------------ swapper/0/1 is trying to acquire lock: ffffffc011306d00 (regulator_list_mutex){+.+.}-{3:3}, at: regulator_lock_dependent (arch/arm64/include/asm/current.h:19 include/linux/ww_mutex.h:111 drivers/regulator/core.c:329) but task is already holding lock: ffffff8004a77160 (regulator_ww_class_mutex){+.+.}-{3:3}, at: regulator_lock_recursive (drivers/regulator/core.c:156 drivers/regulator/core.c:263) which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 (regulator_ww_class_mutex){+.+.}-{3:3}: __mutex_lock_common (include/asm-generic/atomic-instrumented.h:606 include/asm-generic/atomic-long.h:29 kernel/locking/mutex.c:103 kernel/locking/mutex.c:144 kernel/locking/mutex.c:963) ww_mutex_lock (kernel/locking/mutex.c:1199) regulator_lock_recursive (drivers/regulator/core.c:156 drivers/regulator/core.c:263) regulator_lock_dependent (drivers/regulator/core.c:343) regulator_enable (drivers/regulator/core.c:2808) set_machine_constraints (drivers/regulator/core.c:1536) regulator_register (drivers/regulator/core.c:5486) devm_regulator_register (drivers/regulator/devres.c:196) reg_fixed_voltage_probe (drivers/regulator/fixed.c:289) platform_probe (drivers/base/platform.c:1427) [...] -> #1 (regulator_ww_class_acquire){+.+.}-{0:0}: regulator_lock_dependent (include/linux/ww_mutex.h:129 drivers/regulator/core.c:329) regulator_enable (drivers/regulator/core.c:2808) set_machine_constraints (drivers/regulator/core.c:1536) regulator_register (drivers/regulator/core.c:5486) devm_regulator_register (drivers/regulator/devres.c:196) reg_fixed_voltage_probe (drivers/regulator/fixed.c:289) [...] -> #0 (regulator_list_mutex){+.+.}-{3:3}: __lock_acquire (kernel/locking/lockdep.c:3052 (discriminator 4) kernel/locking/lockdep.c:3174 (discriminator 4) kernel/locking/lockdep.c:3789 (discriminator 4) kernel/locking/lockdep.c:5015 (discriminator 4)) lock_acquire (arch/arm64/include/asm/percpu.h:39 kernel/locking/lockdep.c:438 kernel/locking/lockdep.c:5627) __mutex_lock_common (include/asm-generic/atomic-instrumented.h:606 include/asm-generic/atomic-long.h:29 kernel/locking/mutex.c:103 kernel/locking/mutex.c:144 kernel/locking/mutex.c:963) mutex_lock_nested (kernel/locking/mutex.c:1125) regulator_lock_dependent (arch/arm64/include/asm/current.h:19 include/linux/ww_mutex.h:111 drivers/regulator/core.c:329) regulator_enable (drivers/regulator/core.c:2808) vctrl_enable (drivers/regulator/vctrl-regulator.c:400) _regulator_do_enable (drivers/regulator/core.c:2617) _regulator_enable (drivers/regulator/core.c:2764) regulator_enable (drivers/regulator/core.c:308 drivers/regulator/core.c:2809) _set_opp (drivers/opp/core.c:819 drivers/opp/core.c:1072) dev_pm_opp_set_rate (drivers/opp/core.c:1164) set_target (drivers/cpufreq/cpufreq-dt.c:62) __cpufreq_driver_target (drivers/cpufreq/cpufreq.c:2216 drivers/cpufreq/cpufreq.c:2271) cpufreq_online (drivers/cpufreq/cpufreq.c:1488 (discriminator 2)) cpufreq_add_dev (drivers/cpufreq/cpufreq.c:1563) subsys_interface_register (drivers/base/bus.c:?) cpufreq_register_driver (drivers/cpufreq/cpufreq.c:2819) dt_cpufreq_probe (drivers/cpufreq/cpufreq-dt.c:344) [...] other info that might help us debug this: Chain exists of: regulator_list_mutex --> regulator_ww_class_acquire --> regulator_ww_class_mutex Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(regulator_ww_class_mutex); lock(regulator_ww_class_acquire); lock(regulator_ww_class_mutex); lock(regulator_list_mutex); *** DEADLOCK *** 6 locks held by swapper/0/1: #0: ffffff8002d32188 (&dev->mutex){....}-{3:3}, at: __device_driver_lock (drivers/base/dd.c:1030) #1: ffffffc0111a0520 (cpu_hotplug_lock){++++}-{0:0}, at: cpufreq_register_driver (drivers/cpufreq/cpufreq.c:2792 (discriminator 2)) #2: ffffff8002a8d918 (subsys mutex#9){+.+.}-{3:3}, at: subsys_interface_register (drivers/base/bus.c:1033) #3: ffffff800341bb90 (&policy->rwsem){+.+.}-{3:3}, at: cpufreq_online (include/linux/bitmap.h:285 include/linux/cpumask.h:405 drivers/cpufreq/cpufreq.c:1399) #4: ffffffc011f0b7b8 (regulator_ww_class_acquire){+.+.}-{0:0}, at: regulator_enable (drivers/regulator/core.c:2808) #5: ffffff8004a77160 (regulator_ww_class_mutex){+.+.}-{3:3}, at: regulator_lock_recursive (drivers/regulator/core.c:156 drivers/regulator/core.c:263) stack backtrace: CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.14.0-rc6 #2 7c8f8996d021ed0f65271e6aeebf7999de74a9fa Hardware name: Google Scarlet (DT) Call trace: dump_backtrace (arch/arm64/kernel/stacktrace.c:161) show_stack (arch/arm64/kernel/stacktrace.c:218) dump_stack_lvl (lib/dump_stack.c:106 (discriminator 2)) dump_stack (lib/dump_stack.c:113) print_circular_bug (kernel/locking/lockdep.c:?) check_noncircular (kernel/locking/lockdep.c:?) __lock_acquire (kernel/locking/lockdep.c:3052 (discriminator 4) kernel/locking/lockdep.c:3174 (discriminator 4) kernel/locking/lockdep.c:3789 (discriminator 4) kernel/locking/lockdep.c:5015 (discriminator 4)) lock_acquire (arch/arm64/include/asm/percpu.h:39 kernel/locking/lockdep.c:438 kernel/locking/lockdep.c:5627) __mutex_lock_common (include/asm-generic/atomic-instrumented.h:606 include/asm-generic/atomic-long.h:29 kernel/locking/mutex.c:103 kernel/locking/mutex.c:144 kernel/locking/mutex.c:963) mutex_lock_nested (kernel/locking/mutex.c:1125) regulator_lock_dependent (arch/arm64/include/asm/current.h:19 include/linux/ww_mutex.h:111 drivers/regulator/core.c:329) regulator_enable (drivers/regulator/core.c:2808) vctrl_enable (drivers/regulator/vctrl-regulator.c:400) _regulator_do_enable (drivers/regulator/core.c:2617) _regulator_enable (drivers/regulator/core.c:2764) regulator_enable (drivers/regulator/core.c:308 drivers/regulator/core.c:2809) _set_opp (drivers/opp/core.c:819 drivers/opp/core.c:1072) dev_pm_opp_set_rate (drivers/opp/core.c:1164) set_target (drivers/cpufreq/cpufreq-dt.c:62) __cpufreq_driver_target (drivers/cpufreq/cpufreq.c:2216 drivers/cpufreq/cpufreq.c:2271) cpufreq_online (drivers/cpufreq/cpufreq.c:1488 (discriminator 2)) cpufreq_add_dev (drivers/cpufreq/cpufreq.c:1563) subsys_interface_register (drivers/base/bus.c:?) cpufreq_register_driver (drivers/cpufreq/cpufreq.c:2819) dt_cpufreq_probe (drivers/cpufreq/cpufreq-dt.c:344) [...] Reported-by: Brian Norris <[email protected]> Fixes: f8702f9 ("regulator: core: Use ww_mutex for regulators locking") Fixes: e915331 ("regulator: vctrl-regulator: Avoid deadlock getting and setting the voltage") Signed-off-by: Chen-Yu Tsai <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Kamal Mostafa <[email protected]> Signed-off-by: Kelsey Skunberg <[email protected]>
1 parent 1e672e2 commit a937feb

File tree

1 file changed

+42
-30
lines changed

1 file changed

+42
-30
lines changed

drivers/regulator/vctrl-regulator.c

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ struct vctrl_voltage_table {
3737
struct vctrl_data {
3838
struct regulator_dev *rdev;
3939
struct regulator_desc desc;
40-
struct regulator *ctrl_reg;
4140
bool enabled;
4241
unsigned int min_slew_down_rate;
4342
unsigned int ovp_threshold;
@@ -82,7 +81,12 @@ static int vctrl_calc_output_voltage(struct vctrl_data *vctrl, int ctrl_uV)
8281
static int vctrl_get_voltage(struct regulator_dev *rdev)
8382
{
8483
struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
85-
int ctrl_uV = regulator_get_voltage_rdev(vctrl->ctrl_reg->rdev);
84+
int ctrl_uV;
85+
86+
if (!rdev->supply)
87+
return -EPROBE_DEFER;
88+
89+
ctrl_uV = regulator_get_voltage_rdev(rdev->supply->rdev);
8690

8791
return vctrl_calc_output_voltage(vctrl, ctrl_uV);
8892
}
@@ -92,14 +96,19 @@ static int vctrl_set_voltage(struct regulator_dev *rdev,
9296
unsigned int *selector)
9397
{
9498
struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
95-
struct regulator *ctrl_reg = vctrl->ctrl_reg;
96-
int orig_ctrl_uV = regulator_get_voltage_rdev(ctrl_reg->rdev);
97-
int uV = vctrl_calc_output_voltage(vctrl, orig_ctrl_uV);
99+
int orig_ctrl_uV;
100+
int uV;
98101
int ret;
99102

103+
if (!rdev->supply)
104+
return -EPROBE_DEFER;
105+
106+
orig_ctrl_uV = regulator_get_voltage_rdev(rdev->supply->rdev);
107+
uV = vctrl_calc_output_voltage(vctrl, orig_ctrl_uV);
108+
100109
if (req_min_uV >= uV || !vctrl->ovp_threshold)
101110
/* voltage rising or no OVP */
102-
return regulator_set_voltage_rdev(ctrl_reg->rdev,
111+
return regulator_set_voltage_rdev(rdev->supply->rdev,
103112
vctrl_calc_ctrl_voltage(vctrl, req_min_uV),
104113
vctrl_calc_ctrl_voltage(vctrl, req_max_uV),
105114
PM_SUSPEND_ON);
@@ -117,7 +126,7 @@ static int vctrl_set_voltage(struct regulator_dev *rdev,
117126
next_uV = max_t(int, req_min_uV, uV - max_drop_uV);
118127
next_ctrl_uV = vctrl_calc_ctrl_voltage(vctrl, next_uV);
119128

120-
ret = regulator_set_voltage_rdev(ctrl_reg->rdev,
129+
ret = regulator_set_voltage_rdev(rdev->supply->rdev,
121130
next_ctrl_uV,
122131
next_ctrl_uV,
123132
PM_SUSPEND_ON);
@@ -134,7 +143,7 @@ static int vctrl_set_voltage(struct regulator_dev *rdev,
134143

135144
err:
136145
/* Try to go back to original voltage */
137-
regulator_set_voltage_rdev(ctrl_reg->rdev, orig_ctrl_uV, orig_ctrl_uV,
146+
regulator_set_voltage_rdev(rdev->supply->rdev, orig_ctrl_uV, orig_ctrl_uV,
138147
PM_SUSPEND_ON);
139148

140149
return ret;
@@ -151,16 +160,18 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev,
151160
unsigned int selector)
152161
{
153162
struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
154-
struct regulator *ctrl_reg = vctrl->ctrl_reg;
155163
unsigned int orig_sel = vctrl->sel;
156164
int ret;
157165

166+
if (!rdev->supply)
167+
return -EPROBE_DEFER;
168+
158169
if (selector >= rdev->desc->n_voltages)
159170
return -EINVAL;
160171

161172
if (selector >= vctrl->sel || !vctrl->ovp_threshold) {
162173
/* voltage rising or no OVP */
163-
ret = regulator_set_voltage_rdev(ctrl_reg->rdev,
174+
ret = regulator_set_voltage_rdev(rdev->supply->rdev,
164175
vctrl->vtable[selector].ctrl,
165176
vctrl->vtable[selector].ctrl,
166177
PM_SUSPEND_ON);
@@ -179,7 +190,7 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev,
179190
else
180191
next_sel = vctrl->vtable[vctrl->sel].ovp_min_sel;
181192

182-
ret = regulator_set_voltage_rdev(ctrl_reg->rdev,
193+
ret = regulator_set_voltage_rdev(rdev->supply->rdev,
183194
vctrl->vtable[next_sel].ctrl,
184195
vctrl->vtable[next_sel].ctrl,
185196
PM_SUSPEND_ON);
@@ -202,7 +213,7 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev,
202213
err:
203214
if (vctrl->sel != orig_sel) {
204215
/* Try to go back to original voltage */
205-
if (!regulator_set_voltage_rdev(ctrl_reg->rdev,
216+
if (!regulator_set_voltage_rdev(rdev->supply->rdev,
206217
vctrl->vtable[orig_sel].ctrl,
207218
vctrl->vtable[orig_sel].ctrl,
208219
PM_SUSPEND_ON))
@@ -234,10 +245,6 @@ static int vctrl_parse_dt(struct platform_device *pdev,
234245
u32 pval;
235246
u32 vrange_ctrl[2];
236247

237-
vctrl->ctrl_reg = devm_regulator_get(&pdev->dev, "ctrl");
238-
if (IS_ERR(vctrl->ctrl_reg))
239-
return PTR_ERR(vctrl->ctrl_reg);
240-
241248
ret = of_property_read_u32(np, "ovp-threshold-percent", &pval);
242249
if (!ret) {
243250
vctrl->ovp_threshold = pval;
@@ -315,11 +322,11 @@ static int vctrl_cmp_ctrl_uV(const void *a, const void *b)
315322
return at->ctrl - bt->ctrl;
316323
}
317324

318-
static int vctrl_init_vtable(struct platform_device *pdev)
325+
static int vctrl_init_vtable(struct platform_device *pdev,
326+
struct regulator *ctrl_reg)
319327
{
320328
struct vctrl_data *vctrl = platform_get_drvdata(pdev);
321329
struct regulator_desc *rdesc = &vctrl->desc;
322-
struct regulator *ctrl_reg = vctrl->ctrl_reg;
323330
struct vctrl_voltage_range *vrange_ctrl = &vctrl->vrange.ctrl;
324331
int n_voltages;
325332
int ctrl_uV;
@@ -395,23 +402,19 @@ static int vctrl_init_vtable(struct platform_device *pdev)
395402
static int vctrl_enable(struct regulator_dev *rdev)
396403
{
397404
struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
398-
int ret = regulator_enable(vctrl->ctrl_reg);
399405

400-
if (!ret)
401-
vctrl->enabled = true;
406+
vctrl->enabled = true;
402407

403-
return ret;
408+
return 0;
404409
}
405410

406411
static int vctrl_disable(struct regulator_dev *rdev)
407412
{
408413
struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
409-
int ret = regulator_disable(vctrl->ctrl_reg);
410414

411-
if (!ret)
412-
vctrl->enabled = false;
415+
vctrl->enabled = false;
413416

414-
return ret;
417+
return 0;
415418
}
416419

417420
static int vctrl_is_enabled(struct regulator_dev *rdev)
@@ -447,6 +450,7 @@ static int vctrl_probe(struct platform_device *pdev)
447450
struct regulator_desc *rdesc;
448451
struct regulator_config cfg = { };
449452
struct vctrl_voltage_range *vrange_ctrl;
453+
struct regulator *ctrl_reg;
450454
int ctrl_uV;
451455
int ret;
452456

@@ -461,15 +465,20 @@ static int vctrl_probe(struct platform_device *pdev)
461465
if (ret)
462466
return ret;
463467

468+
ctrl_reg = devm_regulator_get(&pdev->dev, "ctrl");
469+
if (IS_ERR(ctrl_reg))
470+
return PTR_ERR(ctrl_reg);
471+
464472
vrange_ctrl = &vctrl->vrange.ctrl;
465473

466474
rdesc = &vctrl->desc;
467475
rdesc->name = "vctrl";
468476
rdesc->type = REGULATOR_VOLTAGE;
469477
rdesc->owner = THIS_MODULE;
478+
rdesc->supply_name = "ctrl";
470479

471-
if ((regulator_get_linear_step(vctrl->ctrl_reg) == 1) ||
472-
(regulator_count_voltages(vctrl->ctrl_reg) == -EINVAL)) {
480+
if ((regulator_get_linear_step(ctrl_reg) == 1) ||
481+
(regulator_count_voltages(ctrl_reg) == -EINVAL)) {
473482
rdesc->continuous_voltage_range = true;
474483
rdesc->ops = &vctrl_ops_cont;
475484
} else {
@@ -486,12 +495,12 @@ static int vctrl_probe(struct platform_device *pdev)
486495
cfg.init_data = init_data;
487496

488497
if (!rdesc->continuous_voltage_range) {
489-
ret = vctrl_init_vtable(pdev);
498+
ret = vctrl_init_vtable(pdev, ctrl_reg);
490499
if (ret)
491500
return ret;
492501

493502
/* Use locked consumer API when not in regulator framework */
494-
ctrl_uV = regulator_get_voltage(vctrl->ctrl_reg);
503+
ctrl_uV = regulator_get_voltage(ctrl_reg);
495504
if (ctrl_uV < 0) {
496505
dev_err(&pdev->dev, "failed to get control voltage\n");
497506
return ctrl_uV;
@@ -514,6 +523,9 @@ static int vctrl_probe(struct platform_device *pdev)
514523
}
515524
}
516525

526+
/* Drop ctrl-supply here in favor of regulator core managed supply */
527+
devm_regulator_put(ctrl_reg);
528+
517529
vctrl->rdev = devm_regulator_register(&pdev->dev, rdesc, &cfg);
518530
if (IS_ERR(vctrl->rdev)) {
519531
ret = PTR_ERR(vctrl->rdev);

0 commit comments

Comments
 (0)