Andy Green <andy.gr...@linaro.org> 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
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev

Reply via email to