Re: platform/i2c busses: pm runtime and system sleep

Previous thread: [PATCH/RFC 0/2] jump label: simplify API by Jason Baron on Thursday, December 16, 2010 - 11:25 am. (21 messages)

Next thread: [PATCH 1/2] hpsa: do not consider firmware revision when looking for device changes. by Stephen M. Cameron on Thursday, December 16, 2010 - 12:00 pm. (1 message)
From: Rabin Vincent
Date: Thursday, December 16, 2010 - 11:26 am

Hello,

There seem to be some differences between the generic ops and the i2c
and platform busses' implementations of the interaction between runtime
PM and system sleep:

  (1) The platform bus does not implement the
      don't-call-pm->suspend()-if pm_runtime_suspended()-returns-true
      functionality implemented by the generic ops and i2c.

  (2) Both I2C and platform do not set the device as active when a
      pm->resume callback exists and it succeeds.

      This seems to have been done in i2c until recently, but has been
      removed by 753419f59e ("i2c: Fix for suspend/resume issue").  It
      seems to me that this removal is incorrect, and instead the real
      problem with the implementation was that it set the device as
      active even if no resume callback existed, whereas it should only
      do so when it exists and returns zero, like the generic ops.

Are these divergences from the generic ops to be considered as bugs?
Atleast (2) will cause devices which use UNIVERSAL_DEV_PM_OPS to have
incorrect runtime pm state after a resume from system sleep.

If so, before I send patches to fix them: can it be assumed that only
drivers using dev_pm_ops (and not the legacy ops of these busses) will
need the interactions between runtime PM and system sleep as done in the
generic ops?  This would mean that simple busses could simply use the
generic ops like below instead of duplicating their behaviour:

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 6b4cc56..46117e0 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -212,7 +212,7 @@ static int i2c_device_pm_resume(struct device *dev)
 	int ret;

 	if (pm)
-		ret = pm->resume ? pm->resume(dev) : 0;
+		ret = pm_generic_resume(dev);
 	else
 		ret = i2c_legacy_resume(dev);

 thanks,
 Rabin
--

From: Rafael J. Wysocki
Date: Thursday, December 16, 2010 - 5:09 pm

I think so.  I'm not sure about (1), because someone may already depend on

Yes, you can make this assumption safely.  The drivers that don't use

Thanks,
Rafael
--

From: Mark Brown
Date: Friday, December 17, 2010 - 5:54 am

This is platform lagging behind I2C in implementation - both originally 
did what platform does and then I2C was updated and platform wasn't.

It'd be really good if this could all be factored out into the PM core,
we're going to have to do the same thing for at least SPI as well and
possibly some other buses :/
--

From: Rafael J. Wysocki
Date: Friday, December 17, 2010 - 6:25 am

So how exactly the PM core is supposed to include those things?

There certainly are other buses that don't want to do them.

Thanks,
Rafael
--

From: Mark Brown
Date: Friday, December 17, 2010 - 6:34 am

By, for example, providing default implementations which the buses can
use if they choose to.
--

From: Rafael J. Wysocki
Date: Friday, December 17, 2010 - 6:49 am

OK, so we have generic_subsys_pm_ops.  Do we need anything beyond that?

Rafael
--

From: Mark Brown
Date: Friday, December 17, 2010 - 7:24 am

Hrm.  Possibly just some fiddling with those or alternative versions.
For example, looking at the I2C bus suspend it's this:

static int i2c_device_pm_suspend(struct device *dev)
{
	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;

	if (pm) {
		if (pm_runtime_suspended(dev))
			return 0;
		else
			return pm->suspend ? pm->suspend(dev) : 0;
	}

	return i2c_legacy_suspend(dev, PMSG_SUSPEND);
}

Ideally the if (pm) block could just be factored out into the pm core as
there's nothing I2C-specific about that at all.  Possibly even the whole
logic surrounding fall back to legacy, though that smells a bit.  The
generic suspend operation doesn't fit here:

int pm_generic_suspend(struct device *dev)
{
	return __pm_generic_call(dev, PM_EVENT_SUSPEND);
}
EXPORT_SYMBOL_GPL(pm_generic_suspend);
--

From: Rafael J. Wysocki
Date: Friday, December 17, 2010 - 4:01 pm

Well, looking at __pm_generic_call(), I think it does.

It appears to do exactly what the pm block above does, so it should be possible
to have something like this:

static int i2c_device_pm_suspend(struct device *dev)
{
	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
	return pm ? pm_generic_suspend(dev) : i2c_legacy_suspend(dev, PMSG_SUSPEND);
}

if I'm not missing anything.

Thanks,
Rafael
--

From: Mark Brown
Date: Friday, December 17, 2010 - 6:04 pm

SPI and platform (the first two buses I looked at) both seem to have
legacy suspend operations too?  Clearly the bus would need to provide an
op to invoke the legacy call but the logic which prioritises the pm_ops


Yes, I think that should work - thanks.  A similar thing would work for
the default platform bus implementation, too, and bring it into line
with I2C here.  I'll have a play.  Similarly for SPI.
--

From: Rafael J. Wysocki
Date: Saturday, December 18, 2010 - 5:54 am

Well, the problem with that is the driver would need to tell the generic call
what the legacy routine is and there's no, er, generic way to do that.

In the i2c case, for example, there is struct i2c_driver that contains the
->suspend() and ->resume() pointers, so the bus type driver _knows_ how to
get there, but the PM core doesn't have this information.

Thanks,
Rafael
--

From: Mark Brown
Date: Saturday, December 18, 2010 - 6:20 am

Sure, but this could be readily accomplished by providing bus
legacy_suspend() and legacy_resume() operations that the generic code
could use to do the actual call.  This would save them all implmeneting
essentially the same decision making code for all the various different 
PM operations - the only bit that differs between buses is going to be
the actual process for calling the legacy API.

Like I say, I'm not sure if it's actually worth it.
--

From: Rafael J. Wysocki
Date: Saturday, December 18, 2010 - 7:59 am

First, there already are ->suspend() and ->resume() callbacks in
struct bus_type which are regarded as "legacy".  The PM core uses those as
appropriate in drivers/base/power/main.c .

Second, the situation at hand is that the bus type implements dev_pm_ops,
but the driver doesn't.  Now, pm_generic_suspend() is called with a struct
device pointer, so it would have to go back to dev->bus, find the
->legacy_suspend() callback (as opposed to ->suspend(), which also is legacy,

Well, I don't really think so.

Thanks,
Rafael
--

From: Mark Brown
Date: Monday, December 20, 2010 - 8:00 am

Well, the trouble is that the whole situation is already pretty
confusing for what should be very simple buses, each one needs to write
a bunch of not really bus specific code in order to get basic behaviour
which allows the drivers to make use of runtime PM, requiring more
thought and care per bus than I'd expect given that they've nothing
really to contribute.  This leads to the sort of random variations
between buses that Rabin is reporting, and means that updates keep
having to get done in multiple different places.

The overall effect is that from the point of view of trying to use
runtime PM in drivers which work with these simple buses everything
feels like it's much harder work than it should be.  Moving all the
decision making out of the buses and into the PM core seems like a win
here.
--

From: Rafael J. Wysocki
Date: Monday, December 20, 2010 - 2:13 pm

Well, the _solution_ is to get rid of the legacy stuff from those buses in the
first place.  Then, they'll just need to use the generic ops without any
trouble.

What you're proposing is a workaround that people will use as an excuse for
not doing the right thing forever.

Thanks,
Rafael
--

From: Mark Brown
Date: Tuesday, December 21, 2010 - 4:51 pm

I hadn't actually realised that there was any urgency about removing the
old APIs - I'd not really seen much work in that direction.  If the
intention is to actively push people over to dev_pm_ops that does make a
bit more sense.
--

From: Rafael J. Wysocki
Date: Tuesday, December 21, 2010 - 5:35 pm

There's no urgency strictly speaking, but there's a preference. :-)

I think it probably is the time to actually start pushing people into that,
because the legacy stuff has been causing too much pain recently.

Thanks,
Rafael
--

Previous thread: [PATCH/RFC 0/2] jump label: simplify API by Jason Baron on Thursday, December 16, 2010 - 11:25 am. (21 messages)

Next thread: [PATCH 1/2] hpsa: do not consider firmware revision when looking for device changes. by Stephen M. Cameron on Thursday, December 16, 2010 - 12:00 pm. (1 message)