Skip to content

Commit 2787710

Browse files
Daniel ThompsonJiri Kosina
authored andcommitted
HID: i2c-hid: goodix: Fix a lockdep splat
I'm was on the receiving end of a lockdep splat from this driver and after scratching my head I couldn't be entirely sure it was a false positive given we would also have to think about whether the regulator locking is safe (since the notifier is called whilst holding regulator locks which are also needed for regulator_is_enabled() ). Regardless of whether it is a real bug or not, the mutex isn't needed. We can use reference counting tricks instead to avoid races with the notifier calls. The observed splat follows: ------------------------------------------------------ kworker/u16:3/127 is trying to acquire lock: ffff00008021fb20 (&ihid_goodix->regulator_mutex){+.+.}-{4:4}, at: ihid_goodix_vdd_notify+0x30/0x94 but task is already holding lock: ffff0000835c60c0 (&(&rdev->notifier)->rwsem){++++}-{4:4}, at: blocking_notifier_call_chain+0x30/0x70 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&(&rdev->notifier)->rwsem){++++}-{4:4}: down_write+0x68/0x8c blocking_notifier_chain_register+0x54/0x70 regulator_register_notifier+0x1c/0x24 devm_regulator_register_notifier+0x58/0x98 i2c_hid_of_goodix_probe+0xdc/0x158 i2c_device_probe+0x25d/0x270 really_probe+0x174/0x2cc __driver_probe_device+0xc0/0xd8 driver_probe_device+0x50/0xe4 __device_attach_driver+0xa8/0xc0 bus_for_each_drv+0x9c/0xc0 __device_attach_async_helper+0x6c/0xbc async_run_entry_fn+0x38/0x100 process_one_work+0x294/0x438 worker_thread+0x180/0x258 kthread+0x120/0x130 ret_from_fork+0x10/0x20 -> #0 (&ihid_goodix->regulator_mutex){+.+.}-{4:4}: __lock_acquire+0xd24/0xfe8 lock_acquire+0x288/0x2f4 __mutex_lock+0xa0/0x338 mutex_lock_nested+0x3c/0x5c ihid_goodix_vdd_notify+0x30/0x94 notifier_call_chain+0x6c/0x8c blocking_notifier_call_chain+0x48/0x70 _notifier_call_chain.isra.0+0x18/0x20 _regulator_enable+0xc0/0x178 regulator_enable+0x40/0x7c goodix_i2c_hid_power_up+0x18/0x20 i2c_hid_core_power_up.isra.0+0x1c/0x2c i2c_hid_core_probe+0xd8/0x3d4 i2c_hid_of_goodix_probe+0x14c/0x158 i2c_device_probe+0x25c/0x270 really_probe+0x174/0x2cc __driver_probe_device+0xc0/0xd8 driver_probe_device+0x50/0xe4 __device_attach_driver+0xa8/0xc0 bus_for_each_drv+0x9c/0xc0 __device_attach_async_helper+0x6c/0xbc async_run_entry_fn+0x38/0x100 process_one_work+0x294/0x438 worker_thread+0x180/0x258 kthread+0x120/0x130 ret_from_fork+0x10/0x20 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&(&rdev->notifier)->rwsem); lock(&ihid_goodix->regulator_mutex); lock(&(&rdev->notifier)->rwsem); lock(&ihid_goodix->regulator_mutex); *** DEADLOCK *** Signed-off-by: Daniel Thompson <[email protected]> Fixes: 18eeef4 ("HID: i2c-hid: goodix: Tie the reset line to true state of the regulator") Reviewed-by: Douglas Anderson <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 817b8b9 commit 2787710

File tree

1 file changed

+12
-16
lines changed

1 file changed

+12
-16
lines changed

drivers/hid/i2c-hid/i2c-hid-of-goodix.c

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ struct i2c_hid_of_goodix {
2727

2828
struct regulator *vdd;
2929
struct notifier_block nb;
30-
struct mutex regulator_mutex;
3130
struct gpio_desc *reset_gpio;
3231
const struct goodix_i2c_hid_timing_data *timings;
3332
};
@@ -67,8 +66,6 @@ static int ihid_goodix_vdd_notify(struct notifier_block *nb,
6766
container_of(nb, struct i2c_hid_of_goodix, nb);
6867
int ret = NOTIFY_OK;
6968

70-
mutex_lock(&ihid_goodix->regulator_mutex);
71-
7269
switch (event) {
7370
case REGULATOR_EVENT_PRE_DISABLE:
7471
gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
@@ -87,8 +84,6 @@ static int ihid_goodix_vdd_notify(struct notifier_block *nb,
8784
break;
8885
}
8986

90-
mutex_unlock(&ihid_goodix->regulator_mutex);
91-
9287
return ret;
9388
}
9489

@@ -102,8 +97,6 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client,
10297
if (!ihid_goodix)
10398
return -ENOMEM;
10499

105-
mutex_init(&ihid_goodix->regulator_mutex);
106-
107100
ihid_goodix->ops.power_up = goodix_i2c_hid_power_up;
108101
ihid_goodix->ops.power_down = goodix_i2c_hid_power_down;
109102

@@ -130,25 +123,28 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client,
130123
* long. Holding the controller in reset apparently draws extra
131124
* power.
132125
*/
133-
mutex_lock(&ihid_goodix->regulator_mutex);
134126
ihid_goodix->nb.notifier_call = ihid_goodix_vdd_notify;
135127
ret = devm_regulator_register_notifier(ihid_goodix->vdd, &ihid_goodix->nb);
136-
if (ret) {
137-
mutex_unlock(&ihid_goodix->regulator_mutex);
128+
if (ret)
138129
return dev_err_probe(&client->dev, ret,
139130
"regulator notifier request failed\n");
140-
}
141131

142132
/*
143133
* If someone else is holding the regulator on (or the regulator is
144134
* an always-on one) we might never be told to deassert reset. Do it
145-
* now. Here we'll assume that someone else might have _just
146-
* barely_ turned the regulator on so we'll do the full
147-
* "post_power_delay" just in case.
135+
* now... and temporarily bump the regulator reference count just to
136+
* make sure it is impossible for this to race with our own notifier!
137+
* We also assume that someone else might have _just barely_ turned
138+
* the regulator on so we'll do the full "post_power_delay" just in
139+
* case.
148140
*/
149-
if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd))
141+
if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd)) {
142+
ret = regulator_enable(ihid_goodix->vdd);
143+
if (ret)
144+
return ret;
150145
goodix_i2c_hid_deassert_reset(ihid_goodix, true);
151-
mutex_unlock(&ihid_goodix->regulator_mutex);
146+
regulator_disable(ihid_goodix->vdd);
147+
}
152148

153149
return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001, 0);
154150
}

0 commit comments

Comments
 (0)