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