drm: bridge: adv7511: unregister cec i2c device after cec adapter
authorAlvin Šipraga <alsi@bang-olufsen.dk>
Sun, 12 Jun 2022 14:48:54 +0000 (16:48 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 26 Oct 2022 10:34:50 +0000 (12:34 +0200)
[ Upstream commit 40cdb02cb9f965732eb543d47f15bef8d10f0f5f ]

cec_unregister_adapter() assumes that the underlying adapter ops are
callable. For example, if the CEC adapter currently has a valid physical
address, then the unregistration procedure will invalidate the physical
address by setting it to f.f.f.f. Whence the following kernel oops
observed after removing the adv7511 module:

    Unable to handle kernel execution of user memory at virtual address 0000000000000000
    Internal error: Oops: 86000004 [#1] PREEMPT_RT SMP
    Call trace:
     0x0
     adv7511_cec_adap_log_addr+0x1ac/0x1c8 [adv7511]
     cec_adap_unconfigure+0x44/0x90 [cec]
     __cec_s_phys_addr.part.0+0x68/0x230 [cec]
     __cec_s_phys_addr+0x40/0x50 [cec]
     cec_unregister_adapter+0xb4/0x118 [cec]
     adv7511_remove+0x60/0x90 [adv7511]
     i2c_device_remove+0x34/0xe0
     device_release_driver_internal+0x114/0x1f0
     driver_detach+0x54/0xe0
     bus_remove_driver+0x60/0xd8
     driver_unregister+0x34/0x60
     i2c_del_driver+0x2c/0x68
     adv7511_exit+0x1c/0x67c [adv7511]
     __arm64_sys_delete_module+0x154/0x288
     invoke_syscall+0x48/0x100
     el0_svc_common.constprop.0+0x48/0xe8
     do_el0_svc+0x28/0x88
     el0_svc+0x1c/0x50
     el0t_64_sync_handler+0xa8/0xb0
     el0t_64_sync+0x15c/0x160
    Code: bad PC value
    ---[ end trace 0000000000000000 ]---

Protect against this scenario by unregistering i2c_cec after
unregistering the CEC adapter. Duly disable the CEC clock afterwards
too.

Fixes: 3b1b975003e4 ("drm: adv7511/33: add HDMI CEC support")
Signed-off-by: Alvin Šipraga <alsi@bang-olufsen.dk>
Reviewed-by: Robert Foss <robert.foss@linaro.org>
Signed-off-by: Robert Foss <robert.foss@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20220612144854.2223873-3-alvin@pqrs.dk
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c

index 7e3f6633f255dd666f50606fa59320b5dfe37ff7..3dc551d223d664624630869372ad73923c4e9257 100644 (file)
@@ -1326,8 +1326,6 @@ static int adv7511_remove(struct i2c_client *i2c)
 
        if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
                adv7533_detach_dsi(adv7511);
-       i2c_unregister_device(adv7511->i2c_cec);
-       clk_disable_unprepare(adv7511->cec_clk);
 
        adv7511_uninit_regulators(adv7511);
 
@@ -1336,6 +1334,8 @@ static int adv7511_remove(struct i2c_client *i2c)
        adv7511_audio_exit(adv7511);
 
        cec_unregister_adapter(adv7511->cec_adap);
+       i2c_unregister_device(adv7511->i2c_cec);
+       clk_disable_unprepare(adv7511->cec_clk);
 
        i2c_unregister_device(adv7511->i2c_packet);
        i2c_unregister_device(adv7511->i2c_edid);