Cc: Rafael J. Wysocki <rjw@...>, Alan Stern <stern@...>, Nigel Cunningham <nigel@...>, Pavel Machek <pavel@...>, Matthew Garrett <mjg59@...>, <linux-kernel@...>, <linux-pm@...>
On Jul 08, 2007, at 20:33:37, Benjamin Herrenschmidt wrote:
I agree completely. It's a bit trickier if you want to do work in
uninterruptable contexts:
driver_suspend_callback(...)
{
dev_suspend_lock(dev);
put_hardware_to_sleep(dev);
}
driver_resume_callback(...)
{
wake_hardware_up(dev);
dev_suspend_unlock(dev);
}
Then for sleep-capable contexts:
dev_suspend_lock(dev);
dev_suspend_unlock(dev);
And for no-sleep contexts like interrupts etc:
if (!dev_suspend_trylock(dev))
return postpone_work_for_later(dev, ...);
do_stuff_with(dev);
dev_suspend_unlock(dev);
You could do this with a straight mutex except for the
dev_suspend_trylock/unlock bit in uninterruptable contexts, but I
seem to recall somebody saying that could be made to work if there
was a real need for it. Alternatively you could just drive the
"Generic Mutex" guys up the wall by inventing your own pseudo-mutex
with a spinlock, a boolean value, and a waitqueue.
Then when you put your driver to sleep, things trying to do IO will
automatically "freeze" themselves exactly until the device is woken
again.
Assuming the driver model and subsystem get the ordering right for
which devices to suspend/resume, then it's impossible to deadlock or
cause hardware confusion. And even further, if you manage to make
the automagic mutex-debugging code work with the noninterruptable
trylock it will yell at you when the driver model does nasty deadlock-
y things.
On the other hand, if the driver model *doesn't* get the ordering
right then it's fundamentally impossible to reliably suspend and resume.
Cheers,
Kyle Moffett
-