[RFC/NOT FOR MERGING 1/5] arm: omap: fix up _od_suspend_noirq and _od_resume_noirq

Felipe Balbi balbi at ti.com
Thu Oct 18 13:50:27 EDT 2012


Hi,

On Thu, Oct 18, 2012 at 10:42:37AM -0700, Kevin Hilman wrote:
> Felipe Balbi <balbi at ti.com> writes:
> 
> > Hi,
> >
> > On Thu, Oct 18, 2012 at 09:34:15AM -0700, Kevin Hilman wrote:
> >> Felipe Balbi <balbi at ti.com> writes:
> >> 
> >> > current implementation doesn't take care about
> >> > drivers which don't provide *_noirq methods 
> >> 
> >> The generic ops handle this.  See below.
> >> 
> >> > and we could fall into a situation where we would suspend/resume
> >> > devices even though they haven't asked for it.
> >> 
> >> The following explanation doesn't explain this, so I dont' follow
> >> the "even though they haven't asked for it" part.
> >> 
> >> > One such case happened with the I2C driver which
> >> > was getting suspended during suspend_noirq() just
> >> > to be resume right after by any other device doing
> >> > an I2C transfer on its suspend method.
> >> 
> >> In order to be I2C to be runtime resumed after its noirq method has been
> >> called, that means the other device is doing an I2C xfer in its noirq
> >> method.  That is a bug.
> >> 
> >> > Signed-off-by: Felipe Balbi <balbi at ti.com>
> >> > ---
> >> >  arch/arm/plat-omap/omap_device.c | 8 ++++++++
> >> >  1 file changed, 8 insertions(+)
> >> >
> >> > diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
> >> > index 7a7d1f2..935f416 100644
> >> > --- a/arch/arm/plat-omap/omap_device.c
> >> > +++ b/arch/arm/plat-omap/omap_device.c
> >> > @@ -804,8 +804,12 @@ static int _od_suspend_noirq(struct device *dev)
> >> >  {
> >> >  	struct platform_device *pdev = to_platform_device(dev);
> >> >  	struct omap_device *od = to_omap_device(pdev);
> >> > +	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
> >> >  	int ret;
> >> >  
> >> > +	if (!pm || !pm->suspend_noirq)
> >> > +		return 0;
> >> > +
> >> 
> >> you just re implemented pm_generic_suspend_noirq() (c.f. drivers/base/power/generic_ops.c)
> >> 
> >> >  	/* Don't attempt late suspend on a driver that is not bound */
> >> >  	if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER)
> >> >  		return 0;
> >> > @@ -827,6 +831,10 @@ static int _od_resume_noirq(struct device *dev)
> >> >  {
> >> >  	struct platform_device *pdev = to_platform_device(dev);
> >> >  	struct omap_device *od = to_omap_device(pdev);
> >> > +	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
> >> > +
> >> > +	if (!pm || !pm->resume_noirq)
> >> > +		return 0;
> >> 
> >> and this is basically pm_generic_resume_noirq()
> >
> > not true, there is a slight different. Note that you only call
> > pm_generic_resume_noirq() after calling pm_runtime_resume()ing the
> > device:
> 
> >> static int _od_resume_noirq(struct device *dev)
> >> {
> >> 	struct platform_device *pdev = to_platform_device(dev);
> >> 	struct omap_device *od = to_omap_device(pdev);
> >> 
> >> 	if ((od->flags & OMAP_DEVICE_SUSPENDED) &&
> >> 	    !pm_runtime_status_suspended(dev)) {
> >> 		od->flags &= ~OMAP_DEVICE_SUSPENDED;
> >> 		if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND))
> >> 			omap_device_enable(pdev);
> >> 		pm_generic_runtime_resume(dev);
> >
> > right here. IMHO this is a bug, if the define doesn't implement
> > resume_noirq, it's telling you that it has nothing to do at that time,
> 
> This is where the misunderstanding is.  I suggest you have a look
> at commit c03f007a8bf0e092caeb6856a5c8a850df10b974 where this feature
> was added, but I'll try to summarize:
> 
> The goal is simply this:
> 
> If, by the time .suspend_noirq has run, the driver is not already
> runtime suspended, then forcefully runtime suspend it.
> 
> That's it.

Yes, I got the intention, but to me it looks wrong.

> Again, this is required because system suspend disables runtime PM
> transitions at a certain point, if the device is used after that point,
> there is *no other way* for the driver to properly manage the idle
> transition (or, if there is, please explain it to me.)

Can you please let me know of any situation where e.g. I2C/SPI would be
needed after all its children are suspended ?

> > so you shouldn't forcefully resume the device.
> 
> Note it's only forcefully resumed *if* it was forcefully suspended by
> suspend_noirq.

likewise, you shouldn't forcefully runtime suspend a device. The device
driver needs to be required to provide suspend/resume functions if it
cares.

> > If the device dies, then it means that it needs to implement
> > resume_noirq. What you have here, is a "workaround" for badly written
> > device drivers IMHO. 
> 
> That's one way of looking at it.  The other way of looking at it is that
> by handling this at the PM domain level, the drivers can be much simpler,
> and thus less likely to get wrong.

You're still bypassing what the PM framework wants us to do, no ? What
if Rafael decides to drastically change the way system and runtime PM is
done and it ends up breaking what we have on OMAP ? If we stick to the
standard, the it's less likely to brea.

> But even then, with your proposed changes, I don't think the device will
> be properly idled (including the omap_device_idle) in these important cases:
> 
> 1) I2C is used by some other device *after* its ->suspend method has
>    been called.

how can that happen ? I2C's ->suspend method will only be called after
all its children are suspended.

> 2) I2C runtime PM is disabled from userspace
>    (echo off > /sys/devices/.../power/control)

that should not make a difference if you omap_device_idle() is written
as it should. Maybe what you need is a refactor to provide
omap_device_idle() and omap_device_runtime_idle(), the latter taking
care of the case where runtime pm can be disabled from userspace while
the former idling whenever it's called.

> but I'll take this up in the I2C driver patch itself.

sure :-)

> > Note also, that you could runtime resume devices which don't implement
> > resume_noirq().
> 
> Again, this is by design.

a very weird design IMHO. Either that or I'm really missing something
here.

> It doesn't matter if the driver has noirq methods.  If it is not yet
> runtime suspended, it is forceably runtime suspended.   The generic

if it's not yet runtime suspended, you need to call the driver's
->suspend_* method (depending on the suspend phase you are right now),
but "reusing" the runtime_suspend method sounds to me like another
"special OMAP requirement".

> noirq calls are just there in case the driver has noirq callbacks.

I get that, but why would you suspend a device which doesn't want to be
suspended in suspend_noirq(), but using its runtime_suspend method ?

If I2C dies on a suspend/resume transition, it's a bug in the I2C
driver, no ?

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121018/687f60a5/attachment.sig>


More information about the linux-arm-kernel mailing list