diff mbox series

[PATCH/RFC] mmc: tmio: Cancel delayed work before freeing host

Message ID b669f8e2aebcfe7a0937175058364daa5862d862.1698766265.git.geert+renesas@glider.be (mailing list archive)
State New, archived
Headers show
Series [PATCH/RFC] mmc: tmio: Cancel delayed work before freeing host | expand

Commit Message

Geert Uytterhoeven Oct. 31, 2023, 3:48 p.m. UTC
On RZ/Five SMARC EVK, where probing of SDHI fails due to missing pin
control:

    ------------[ cut here ]------------
    WARNING: CPU: 0 PID: 0 at kernel/time/timer.c:1739 __run_timers.part.0+0x1e8/0x22a
    Modules linked in:
    CPU: 0 PID: 0 Comm: swapper Not tainted 6.6.0-10953-ga37a67d260e6-dirty #86
    Hardware name: Renesas SMARC EVK based on r9a07g043f01 (DT)
    epc : __run_timers.part.0+0x1e8/0x22a
     ra : __run_timers.part.0+0x130/0x22a
    epc : ffffffff8007540c ra : ffffffff80075354 sp : ffffffc800003e60
     gp : ffffffff814f5f08 tp : ffffffff8140d5c0 t0 : 0000000000046600
     t1 : 0000000000000001 t2 : ffffffff81200c10 s0 : ffffffc800003f20
     s1 : ffffffd8023bc4a0 a0 : 00000000fffee790 a1 : 0000000000000200
     a2 : 0000000000000200 a3 : ffffffff81489640 a4 : ffffffc800003e60
     a5 : 0000000000000000 a6 : 0000000000000000 a7 : ffffffc800003e68
     s2 : 0000000000200000 s3 : 0000000000000122 s4 : 0000000000000000
     s5 : ffffffffffffffff s6 : ffffffff814896c0 s7 : ffffffff814f58a0
     s8 : ffffffff80f8bec8 s9 : 0000000000000000 s10: ffffffc800003e60
     s11: ffffffff81489640 t3 : ffffffff81489678 t4 : 0000000000000240
     t5 : ffffffd8024ac018 t6 : ffffffd8024ac038
    status: 0000000200000100 badaddr: 0000000000000000 cause: 0000000000000003
    [<ffffffff8007540c>] __run_timers.part.0+0x1e8/0x22a
    [<ffffffff80075472>] run_timer_softirq+0x24/0x4a
    [<ffffffff80804ec6>] __do_softirq+0xc6/0x212
    [<ffffffff80027434>] irq_exit_rcu+0x7c/0x9a
    [<ffffffff807fcd8a>] handle_riscv_irq+0x40/0x4e
    [<ffffffff807fd7f8>] do_irq+0x40/0x68
    ---[ end trace 0000000000000000 ]---

What happens?

    renesas_sdhi_probe()
    {
    	tmio_mmc_host_alloc()
	    mmc_alloc_host()
		INIT_DELAYED_WORK(&host->detect, mmc_rescan);

	devm_request_irq(tmio_mmc_irq);

	/*
	 * After this, the interrupt handler may be invoked at any time
	 *
	 *  tmio_mmc_irq()
	 *  {
	 *	__tmio_mmc_card_detect_irq()
	 *	    mmc_detect_change()
	 *		_mmc_detect_change()
	 *		    mmc_schedule_delayed_work(&host->detect, delay);
	 *  }
	 */

	tmio_mmc_host_probe()
	    tmio_mmc_init_ocr()
		    -EPROBE_DEFER

	tmio_mmc_host_free()
	    mmc_free_host()
    }

When expire_timers() runs later, it warns because the scheduled work was
freed, and now contains a NULL handler function pointer.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
Calling __mmc_stop_host() instead works too, but __mmc_stop_host() is an
internal core function, and is not exported to modules yet.

Perhaps this should be handled by mmc_free_host() instead?
---
 drivers/mmc/host/tmio_mmc_core.c | 1 +
 1 file changed, 1 insertion(+)

Comments

Ulf Hansson Nov. 2, 2023, 11:45 a.m. UTC | #1
On Tue, 31 Oct 2023 at 16:48, Geert Uytterhoeven
<geert+renesas@glider.be> wrote:
>
> On RZ/Five SMARC EVK, where probing of SDHI fails due to missing pin
> control:
>
>     ------------[ cut here ]------------
>     WARNING: CPU: 0 PID: 0 at kernel/time/timer.c:1739 __run_timers.part.0+0x1e8/0x22a
>     Modules linked in:
>     CPU: 0 PID: 0 Comm: swapper Not tainted 6.6.0-10953-ga37a67d260e6-dirty #86
>     Hardware name: Renesas SMARC EVK based on r9a07g043f01 (DT)
>     epc : __run_timers.part.0+0x1e8/0x22a
>      ra : __run_timers.part.0+0x130/0x22a
>     epc : ffffffff8007540c ra : ffffffff80075354 sp : ffffffc800003e60
>      gp : ffffffff814f5f08 tp : ffffffff8140d5c0 t0 : 0000000000046600
>      t1 : 0000000000000001 t2 : ffffffff81200c10 s0 : ffffffc800003f20
>      s1 : ffffffd8023bc4a0 a0 : 00000000fffee790 a1 : 0000000000000200
>      a2 : 0000000000000200 a3 : ffffffff81489640 a4 : ffffffc800003e60
>      a5 : 0000000000000000 a6 : 0000000000000000 a7 : ffffffc800003e68
>      s2 : 0000000000200000 s3 : 0000000000000122 s4 : 0000000000000000
>      s5 : ffffffffffffffff s6 : ffffffff814896c0 s7 : ffffffff814f58a0
>      s8 : ffffffff80f8bec8 s9 : 0000000000000000 s10: ffffffc800003e60
>      s11: ffffffff81489640 t3 : ffffffff81489678 t4 : 0000000000000240
>      t5 : ffffffd8024ac018 t6 : ffffffd8024ac038
>     status: 0000000200000100 badaddr: 0000000000000000 cause: 0000000000000003
>     [<ffffffff8007540c>] __run_timers.part.0+0x1e8/0x22a
>     [<ffffffff80075472>] run_timer_softirq+0x24/0x4a
>     [<ffffffff80804ec6>] __do_softirq+0xc6/0x212
>     [<ffffffff80027434>] irq_exit_rcu+0x7c/0x9a
>     [<ffffffff807fcd8a>] handle_riscv_irq+0x40/0x4e
>     [<ffffffff807fd7f8>] do_irq+0x40/0x68
>     ---[ end trace 0000000000000000 ]---
>
> What happens?
>
>     renesas_sdhi_probe()
>     {
>         tmio_mmc_host_alloc()
>             mmc_alloc_host()
>                 INIT_DELAYED_WORK(&host->detect, mmc_rescan);
>
>         devm_request_irq(tmio_mmc_irq);
>
>         /*
>          * After this, the interrupt handler may be invoked at any time
>          *
>          *  tmio_mmc_irq()
>          *  {
>          *      __tmio_mmc_card_detect_irq()
>          *          mmc_detect_change()
>          *              _mmc_detect_change()
>          *                  mmc_schedule_delayed_work(&host->detect, delay);
>          *  }
>          */
>
>         tmio_mmc_host_probe()
>             tmio_mmc_init_ocr()
>                     -EPROBE_DEFER
>
>         tmio_mmc_host_free()
>             mmc_free_host()
>     }
>
> When expire_timers() runs later, it warns because the scheduled work was
> freed, and now contains a NULL handler function pointer.
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
> Calling __mmc_stop_host() instead works too, but __mmc_stop_host() is an
> internal core function, and is not exported to modules yet.
>
> Perhaps this should be handled by mmc_free_host() instead?

That sounds reasonable to me. Or actually not "instead of"
__mmc_stop_host(), but rather from mmc_free_host() too.

mmc_stop_host() also needs to make sure that mmc_rescan() isn't
currently being executed, so that when setting the
"host->rescan_disable = 1;" it really takes effect.

Do you want to send a patch?

> ---
>  drivers/mmc/host/tmio_mmc_core.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
> index be7f18fd4836ab29..1e56e78a020d94b9 100644
> --- a/drivers/mmc/host/tmio_mmc_core.c
> +++ b/drivers/mmc/host/tmio_mmc_core.c
> @@ -1132,6 +1132,7 @@ EXPORT_SYMBOL_GPL(tmio_mmc_host_alloc);
>
>  void tmio_mmc_host_free(struct tmio_mmc_host *host)
>  {
> +       cancel_delayed_work_sync(&host->mmc->detect);
>         mmc_free_host(host->mmc);
>  }
>  EXPORT_SYMBOL_GPL(tmio_mmc_host_free);

Kind regards
Uffe
diff mbox series

Patch

diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index be7f18fd4836ab29..1e56e78a020d94b9 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -1132,6 +1132,7 @@  EXPORT_SYMBOL_GPL(tmio_mmc_host_alloc);
 
 void tmio_mmc_host_free(struct tmio_mmc_host *host)
 {
+	cancel_delayed_work_sync(&host->mmc->detect);
 	mmc_free_host(host->mmc);
 }
 EXPORT_SYMBOL_GPL(tmio_mmc_host_free);