Andy Green <[email protected]> writes:
>>> They have a single wakelock to cover delayed work in there, however
>>> there are multiple delayed works possible to be queued, eg delayed
>>> disable and delayed detect actions, and although they wrap scheduling
>>> the delayed work to also lock the wakelock, they don't wrap cancelling
>>> it, eg -->
>>
>> Yes, they unlock the wakelock when the delayed work is done, in the
>> handler.
>
> Right so cancelling the delayed work means the wakelock is left locked
> / asserted and we will never do the work to unlock it; the code for
> this case is broken.
Hum..
>>> So here when preparing for suspend we can cancel the delayed work we
>>> presumably arranged wakelock coverage for, without unlocking the
>>> wakelock.
>>
>> When the delayed work was canceled and handled immediately the wakelock
>> should have been unlocked.
>
> Not certain you meant this by "handled immediately" but to be clear
> cancel_delayed_work() deletes the timer that creates the delay, and
> stops the work ever from being executed. In that case the wakelock
> will be left locked with nothing coming to unlock him except any
> private wakelock timeout. And I am guessing private wakelock timeouts
> are there to hide a whole bunch of immortal wakelocks due to broken
> code that would otherwise kill suspend from ever happening.
The name cancel_delayed_work might be misleading but I learned that
although it deletes the timer, it still waits the work to be
finished. So in this case the wakelock is handled, no?
>> The problem is here:
>>
>> int mmc_pm_notify(struct notifier_block *notify_block,
>> unsigned long mode, void *unused)
>> {
>> ...
>> switch (mode) {
>> case PM_HIBERNATION_PREPARE:
>> case PM_SUSPEND_PREPARE:
>> ...
>> mmc_release_host(host);
>>
>> Which calls
>>
>> void mmc_release_host(struct mmc_host *host)
>> {
>> ...
>> mmc_host_lazy_disable(host);
>> ...
>> }
>>
>> Since omap_hsmmc has non-zero host->disable_delay by default, this will
>> schedule a new delayed_work thus acquire new wakelock.
>
> Okay, I see: thanks for sharing. I will look at the code.
>
>> I tried to fix this by ignore the host->disable_delay if
>> host->rescan_disable is non-zero, which means we are in suspend phase,
>> and it worked.
>
> I got the idea from looking at core.c it's full of bad corner cases
> and potential problems wrt wakelock. I just wanted to confirm it
> really does suck and it's not just me missing the point somewhere ^^
It does suck and it's not only you ;-)
--
Kanru
_______________________________________________
linaro-dev mailing list
[email protected]
http://lists.linaro.org/mailman/listinfo/linaro-dev