From: Dmitry Baryshkov dmitry.baryshkov@linaro.org
stable inclusion from stable-v6.6.2 commit b70dc563b7ee3ab7088edf0898ef025b04303536 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8IW7G
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
[ Upstream commit 15fe53be46eaf4f6339cd433972ecc90513e3076 ]
If DSI host attachment fails, the LT9611UXC driver will remove the bridge without ensuring that there is no outstanding HPD work being done. In rare cases this can result in the warnings regarding the mutex being incorrect. Fix this by forcebly freing IRQ and flushing the work.
DEBUG_LOCKS_WARN_ON(lock->magic != lock) WARNING: CPU: 0 PID: 10 at kernel/locking/mutex.c:582 __mutex_lock+0x468/0x77c Modules linked in: CPU: 0 PID: 10 Comm: kworker/0:1 Tainted: G U 6.6.0-rc5-next-20231011-gd81f81c2b682-dirty #1206 Hardware name: Qualcomm Technologies, Inc. Robotics RB5 (DT) Workqueue: events lt9611uxc_hpd_work pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : __mutex_lock+0x468/0x77c lr : __mutex_lock+0x468/0x77c sp : ffff8000800a3c70 x29: ffff8000800a3c70 x28: 0000000000000000 x27: ffffd595fe333000 x26: ffff7c2f0002c005 x25: ffffd595ff1b3000 x24: ffffd595fccda5a0 x23: 0000000000000000 x22: 0000000000000002 x21: ffff7c2f056d91c8 x20: 0000000000000000 x19: ffff7c2f056d91c8 x18: fffffffffffe8db0 x17: 000000040044ffff x16: 005000f2b5503510 x15: 0000000000000000 x14: 000000000006efb8 x13: 0000000000000000 x12: 0000000000000037 x11: 0000000000000001 x10: 0000000000001470 x9 : ffff8000800a3ae0 x8 : ffff7c2f0027f8d0 x7 : ffff7c2f0027e400 x6 : ffffd595fc702b54 x5 : 0000000000000000 x4 : ffff8000800a0000 x3 : 0000000000000000 x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff7c2f0027e400 Call trace: __mutex_lock+0x468/0x77c mutex_lock_nested+0x24/0x30 drm_bridge_hpd_notify+0x2c/0x5c lt9611uxc_hpd_work+0x6c/0x80 process_one_work+0x1ec/0x51c worker_thread+0x1ec/0x3e4 kthread+0x120/0x124 ret_from_fork+0x10/0x20 irq event stamp: 15799 hardirqs last enabled at (15799): [<ffffd595fc702ba4>] finish_task_switch.isra.0+0xa8/0x278 hardirqs last disabled at (15798): [<ffffd595fd5a1580>] __schedule+0x7b8/0xbd8 softirqs last enabled at (15794): [<ffffd595fc690698>] __do_softirq+0x498/0x4e0 softirqs last disabled at (15771): [<ffffd595fc69615c>] ____do_softirq+0x10/0x1c
Fixes: bc6fa8676ebb ("drm/bridge/lontium-lt9611uxc: move HPD notification out of IRQ handler") Signed-off-by: Dmitry Baryshkov dmitry.baryshkov@linaro.org Reviewed-by: Robert Foss rfoss@kernel.org Signed-off-by: Robert Foss rfoss@kernel.org Link: https://patchwork.freedesktop.org/patch/msgid/20231011220002.382422-1-dmitry... Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 22c84d29c2bc..6f33bb0dd32a 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -929,9 +929,9 @@ static int lt9611uxc_probe(struct i2c_client *client) init_waitqueue_head(<9611uxc->wq); INIT_WORK(<9611uxc->work, lt9611uxc_hpd_work);
- ret = devm_request_threaded_irq(dev, client->irq, NULL, - lt9611uxc_irq_thread_handler, - IRQF_ONESHOT, "lt9611uxc", lt9611uxc); + ret = request_threaded_irq(client->irq, NULL, + lt9611uxc_irq_thread_handler, + IRQF_ONESHOT, "lt9611uxc", lt9611uxc); if (ret) { dev_err(dev, "failed to request irq\n"); goto err_disable_regulators; @@ -967,6 +967,8 @@ static int lt9611uxc_probe(struct i2c_client *client) return lt9611uxc_audio_init(dev, lt9611uxc);
err_remove_bridge: + free_irq(client->irq, lt9611uxc); + cancel_work_sync(<9611uxc->work); drm_bridge_remove(<9611uxc->bridge);
err_disable_regulators: @@ -983,7 +985,7 @@ static void lt9611uxc_remove(struct i2c_client *client) { struct lt9611uxc *lt9611uxc = i2c_get_clientdata(client);
- disable_irq(client->irq); + free_irq(client->irq, lt9611uxc); cancel_work_sync(<9611uxc->work); lt9611uxc_audio_exit(lt9611uxc); drm_bridge_remove(<9611uxc->bridge);