Hi -
Yesterday I studied suspend status on 3.0 kernel for Panda, for mem
suspend it's working pretty well in Ubuntu case, desktop is coming back
up woken by USB keyboard action, WLAN is workable after reassociation.
However in Android case, the same tree merged with common-android-3.0 to
get Androidization is blowing chunks in suspend / resume, entering a
loop where it aborts suspend and then tries to suspend again all the time.
Increasing the debug level in wakelock code shows at least two guys that
can make trouble, locks "mmc_delayed_work" and "alarm_rtc".
"mmc_delayed_work" casues wakelock stuff to return -EAGAIN, and
"alarm_rtc" seems to timeout as a wakelock, but leave the alarm device
in a state where it will abort suspend on -EBUSY.
I took a look in drivers/mmc/core/core.c to see what the wakelock
support patches had done there and was a bit surprised.
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 -->
void mmc_stop_host(struct mmc_host *host)
{
...
if (host->caps & MMC_CAP_DISABLE)
cancel_delayed_work(&host->disable);
cancel_delayed_work_sync(&host->detect);
mmc_flush_scheduled_work();
Nor do wakelocks seem to maintain counters, they're either locked or
unlocked.
So the following code looks highly suspicious:
static int mmc_schedule_delayed_work(struct delayed_work *work,
unsigned long delay)
{
wake_lock(&mmc_delayed_work_wake_lock);
return queue_delayed_work(workqueue, work, delay);
}
static int mmc_host_do_disable(struct mmc_host *host, int lazy)
{
....
(conditionally)
mmc_schedule_delayed_work(&host->disable, delay);
...
}
void mmc_host_deeper_disable(struct work_struct *work)
{
...
mmc_host_do_disable(host, 1);
...
wake_unlock(&mmc_delayed_work_wake_lock);
}
Ie mmc_host_deeper_disable() can provoke delayed work which it proceeds
to unlock wakelock coverage for.
To the point of the symptoms:
int mmc_pm_notify(struct notifier_block *notify_block,
unsigned long mode, void *unused)
{
...
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
...
cancel_delayed_work_sync(&host->detect);
So here when preparing for suspend we can cancel the delayed work we
presumably arranged wakelock coverage for, without unlocking the wakelock.
Am I missing the point or is some work needed to improve wakelock
application for mmc stuff in common-android-3.0?
-Andy
--
Andy Green | TI Landing Team Leader
Linaro.org │ Open source software for ARM SoCs | Follow Linaro
http://facebook.com/pages/Linaro/155974581091106 -
http://twitter.com/#!/linaroorg - http://linaro.org/linaro-blog
_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev