[PATCH 2/2] platform: Facilitate the creation of pseudo-platform buses

Previous thread: FILE FOR CLAIM by Kelvin Moor on Tuesday, August 10, 2010 - 12:18 pm. (1 message)

Next thread: Re: remove inode_setattr by Stephen Rothwell on Tuesday, August 10, 2010 - 5:45 pm. (5 messages)
From: Patrick Pannuto
Date: Tuesday, August 10, 2010 - 4:49 pm

This has been split into two patches. The first, trivial patch,
has already been submitted and greg k-h has it queued up for
after the merge window; it is included here only for clarity.

The second patch contains everything interesting :)

[PATCHv2 1/2] platform: Use drv->driver.bus instead of assuming platform_bus_type
[PATCHv2 2/2] platform: Facilitate the creation of pseudo-platform buses
--

From: Patrick Pannuto
Date: Tuesday, August 10, 2010 - 4:49 pm

(lkml.org seems to have lost August 3rd...)
RFC: http://lkml.indiana.edu/hypermail//linux/kernel/1008.0/01342.html
 v1: http://lkml.indiana.edu/hypermail//linux/kernel/1008.0/01942.html

Based on the idea and code originally proposed by Kevin Hilman:
http://www.mail-archive.com/linux-omap@vger.kernel.org/msg31161.html

Changes from v1:

   * "Pseduo" buses are no longer init'd, they are [un]registered by:
       - pseudo_platform_bus_register(struct bus_type *)
       - pseudo_platform_bus_unregister(struct bus_type *)
   * These registrations [de]allocate a dev_pm_ops structure for the
     pseudo bus_type
   * Do not overwrite the parent if .bus is already set (that is, allow
     pseudo bus devices to be root devices)

   * Split into 2 patches:
       - 1/2: Already sent separately, but included here for clarity
       - 2/2: The real meat of the patch (this patch)

INTRO

As SOCs become more popular, the desire to quickly define a simple,
but functional, bus type with only a few unique properties becomes
desirable. As they become more complicated, the ability to nest these
simple busses and otherwise orchestrate them to match the actual
topology also becomes desirable.

EXAMPLE USAGE

/arch/ARCH/MY_ARCH/my_bus.c:

	#include <linux/device.h>
	#include <linux/platform_device.h>

	struct bus_type SOC_bus_type = {
		.name = "SOC-bus-type",
	};
	EXPORT_SYMBOL_GPL(SOC_bus_type);

	struct platform_device SOC_bus1 = {
		.name	 = "SOC-bus1",
		.id		= -1,
		.dev.bus = &SOC_bus_type;
	};
	EXPORT_SYMBOL_GPL(SOC_bus1);

	struct platform_device SOC_bus2 = {
		.name	 = "SOC-bus2",
		.id		= -2,
		.dev.bus = &SOC_bus_type;
	};
	EXPORT_SYMBOL_GPL(SOC_bus2);

	static int __init SOC_bus_init(void)
	{
		int error;

		error = pseudo_platform_bus_register(&SOC_bus_type);
		if (error)
			return error;

		error = platform_device_register(&SOC_bus1);
		if (error)
			goto fail_bus1;

		error = platform_device_register(&SOC_bus2);
		if (error)
			goto ...
From: Patrick Pannuto
Date: Thursday, August 12, 2010 - 6:13 pm

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
--

From: Greg KH
Date: Saturday, August 14, 2010 - 2:04 pm

Sorry, been busy with the -rc1 merge stuff, I'll have more time to look
at it next week.

Well, after you address Grant's issues first :)

thanks,

greg k-h
--

From: Grant Likely
Date: Friday, August 13, 2010 - 3:05 pm

On Tue, Aug 10, 2010 at 5:49 PM, Patrick Pannuto

Hi Patrick,

Before acking this as something that should be merged, I'd like to see
some real device drivers converted to use this interface so I can

For safety, I think you'd want to have a separate add function for
each new platform bus type, and change the name of this function to
explicitly pass the bus type:

int __platform_device_add(struct platform_device *pdev)
{
	if (!pdev->dev.bus)
		return -EINVAL;
	[... existing code ...]
}

int platform_device_add(struct platform_device *pdev)
{
       if (!pdev->dev.parent)
               pdev->dev.parent = &platform_bus;
       pdev->dev.bus = &platform_bus_type;
       __platform_device_add(pdev);
}

And then for each bus type (in this example, I'll call it
foo_bus_type, and assume foo_device wraps platform_device):

int foo_device_add(struct foo_device *foo)
{
	foo->pdev.dev.bus = &foo_bus_type;
	__platform_device_add(&foo->pdev);
}

That will allow the new bus_type code to keep foo_bus_type as an
unexported static and will provide a bit more type safety.  For
example, it avoids accidentally registering a plain (unwrapped)

Ditto here; better to have a separate foo_driver_register() for each

Kerneldoc style error.  Should be:

+/**

Nit: heap_pm is an odd name.  Typically Linux local vars are named
according to what they are, not where the memory is allocated from.

Ick, this is a nasty list of conditional statements.  :-)  Instead it
could have an unconditional initialize function which sets it up just
like the platform bus without registering.  Then allow the
foo_bus_type initialization code override the ones it cares about, and



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
--

From: Patrick Pannuto
Date: Monday, August 16, 2010 - 11:47 am

Yes, this makes sense.  Originally, I was trying to avoid this due
to a misguided notion of backwards compatibility - namely that
devices could register themselves conditionally via

	.bus = HAVE_FOO_BUS,

and always call the same platform_[device|driver]_register, but
thinking about this more, such a compile (or run)-time decision can
just as easily be made in the foo_[device|driver]_register. The
impact on legacy code is the same either way, but your suggested
interface is much better.




No, this won't work. (Unless, every pseudo_bus_type author did this same
kludge to work around const - better to do once IMHO)

struct bus_type {
	...
	const struct dev_pm_ops *pm;
	...
};

That const is there to *prevent* device/driver writers from overriding
pm ops on accident, and to that end, it has value. What we would really
like here is 'const after registered' semantics, where the bus author
can fill in half the structure, and the platform code can fill in the
rest. However, allowing subclasses to modify private data elements isn't
possible in C :)

I believe the 'const' here provides valuable safety. My original attempt
at doing this removed the const, and I overwrote one of the pointers in
platform_dev_pm_ops on my first try at implementing it!

This was the best solution I could come up with while preserving the const
nature of the pm_ops and introducing minimal complexity / potential to


-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
--

From: Grant Likely
Date: Monday, August 16, 2010 - 1:25 pm

On Mon, Aug 16, 2010 at 12:47 PM, Patrick Pannuto

Actually, I also made a kerneldoc style error here because the braces
are missing.  This should be:

+/**
+ * pseudo_platform_bus_register() - register an "almost platform bus"

See Documentation/kernel-doc-nano-HOWTO.txt for details.

I'm also not fond of the "pseudo" name.  It isn't really a pseudo bus,
but rather a different bus type that happens to inherit most of the
platform_bus infrastructure.  It may be better just to expose the
platform_bus helper functions without any reference to pseudo, and let
the users be responsible for any naming differentiation.  This is
particularly true if the custom bus becomes responsible for
registering itself and only the initialization functions are exposed.


Okay then, here is a better approach:  Don't do any allocation in this
function.  Just initialize the bus_type exactly the way it is
initialized for the platform bus and assign the default dev_pm_ops.
If the custom bus needs to override them, then it should be
responsible to kmemdup the default dev_pm_ops structure and modify the

Yes, overriding the const is a bad idea and you'd be wrong to override it.  :-)

Cheers,
g.
--

From: Michał Mirosław
Date: Monday, August 16, 2010 - 4:58 pm

Actually you can do:

const struct dev_pm_ops test = {
    DEFAULT_PLATFORM_PM_OPS,
    .prepare = my_func,
    ...
};

where:

#define DEFAULT_PLATFORM_PM_OPS \
    .prepare = platform_pm_prepare, \
    .complete = platform_pm_complete, \
    ...

In case of repeated field assignments, gcc uses the last value (as per
http://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html).

Best Regards,
Michał Mirosław
--

From: Moffett, Kyle D
Date: Sunday, August 15, 2010 - 6:38 pm

Hmm...

To me this seems like a really painful implementation of what the OpenFirmware-esque "Flattened Device Tree" does on many embedded systems.

For example, to build an equivalent device tree using an OpenFirmware FDT file, I'd just use this:

/dts-v1/;
/ {
	#address-cells = <1>;
	#size-cells = <1>;
	[...snip...]

	soc-bus-1@fc000000 {
		/* of_platform driver matches against this: */
		compatible = "my-company-name,soc-bus-type";

		/* Define base address and size of the bus */
		reg = <0xfc000000 0x01000000>;
		#address-cells = <1>;
		#size-cells = <1>;

		/* 
		 * Define logical memory mapping relative to the bus addr:
		 * First field is the relative base address for children,
		 * second field is the address in the parent's memory map,
		 * third field is the size of the range.
		 */
		ranges = <0x0 0xfc000000 0x01000000>;

		/* Now for sub-devices */
		my-device@0x10000 {
			compatible = "my-company-name,my-driver";
			reg = <0x10000 0x100>; /* Address and size */
		};
	};

	soc-bus-2@fd000000 {
		/* of_platform driver matches against this: */
		compatible = "my-company-name,soc-bus-type";

		/* Define base address and size of the bus */
		reg = <0xfd000000 0x01000000>;
		#address-cells = <1>;
		#size-cells = <1>;

		/* 
		 * Define logical memory mapping relative to the bus addr:
		 * First field is the relative base address for children,
		 * second field is the address in the parent's memory map,
		 * third field is the size of the range.
		 */
		ranges = <0x0 0xfd000000 0x01000000>;
	};
};

If you don't need to actually do anything special at the bus level, you can just:
	static struct of_device_id soc_bus_ids[] = {
		{ .compatible = "soc-bus-type", },
		{},
	};
	of_platform_bus_probe(NULL, &soc_bus_ids, NULL);

Any of_platform driver that matches something on one of those busses is automatically probed.  Alternatively, if you need special bus behavior:
	static struct of_device_id soc_bus_ids[] = {
		{ .compatible = ...
From: Grant Likely
Date: Sunday, August 15, 2010 - 11:43 pm

Patrick and Kevin have been trying to solve a different problem.  The
FDT is really good at describing the topology and interconnections of
the system, but it doesn't solve the problem of how the different bus
behaviour is implemented in the kernel.  They need a method of
registering devices that have subtly different behaviour from the
plain-vanilla platform bus.  Whether or not the device data originates
from the FDT is irrelevant, and the problem remains the same.

I'm not convinced (yet) that this is the right approach, and I'd like
to see a few sample drivers converted to the new approach.  Creating
new bus_types that "inherit" from the platform_bus is actually not a
bad idea, and it is an elegant way to change the behaviour (for
example, how power management is implemented) for devices connected in
a different way.

A problem with the approach that Kevin pointed out is that drivers
that need to work on both the platform_bus_type and the new
soc_bus_type must explicitly register themselves on both bus types.
There is no mechanism to allow drivers from one bus type to also be
made available to another bus type. Certainly it would be possible to
invent a mechanism, but the more I think about it, them more I think
it will be a bad idea.  The runtime-PM use-case that kicked this
discussion off makes the assumption that a driver will behave
identically when attached to either the platform_bus_type or the
soc_bus_type.  However, I think that in the general case that
assumption will prove to be false.  I strongly suspect that the new
bus type will turn out to be not as similar to the platform_bus_type
as originally assumed and that there will still be bus-type-specific
impact on device drivers (but I digress; this paragraph is more
directed to Patrick and Kevin, and doesn't address your comments).


Be careful!  This is actually a confusing example.  Linux already has
a concept of a bus_type, and it is not the same as what is shown in
this example.  Part of the problem is ...
From: Kevin Hilman
Date: Thursday, August 19, 2010 - 12:20 pm

And potentially more than 2 if a driver exists for a hardware block on
different SoCs.  Magnus raised this issue for drivers used across SH and
ARM/SH-Mobile, and the same issue exists between TI OMAP and TI DaVinci

What makes you suspect that?  Maybe Patrick has other use-cases in mind,
but from a PM perspective, I have not seen any impact.

One of the primary goals of this (at least for me and it seems Magnus also)
is to keep drivers ignorant of their bus type, and any bus-type-specific
code should be done in the bus_type implementation.

Both for SH and OMAP, we've been using the (admiteddly broken)
weak-symbol-override approach to getting a custom bus-type based on the
platform_bus.  We've been using that in OMAP for a while now and have
not seen any need to for the drivers to know if they are on the vanilla
platform_bus or the customized one.

I'm very curious to hear what type of impact you expect to the drivers.

Kevin
--

From: Grant Likely
Date: Thursday, August 19, 2010 - 3:22 pm

On Thu, Aug 19, 2010 at 1:20 PM, Kevin Hilman

Call it a gut reaction if you like, but here's my line of thinking.
In your use case, sure, there is zero impact on drivers, but will that
continue to be the case for other bus architectures as they use this
interface?  Or, in other words, will this solution end up being short
sighted and we'll be having this discussion all over again in a year?

The big concern for me is the idea of partial divergence from the
platform_bus_type (specifically having different bus_type, but same
pool of drivers).  For starts, how is it represented in the device
model?  Where do the device drivers live in /sys/bus/*/drivers?  What
happens when one bus type is unregistered but has drivers used by
another bus type?  Does it scale to the (granted, currently
speculative) use-case where the device driver does need knowledge
about which bus_type it is registered against?  I'm also concerned
about the complexity required to implement driver sharing and ensuring
that correct locking and consistency is maintained between bus_types.

Note: I consider partial divergence to be different from
platform_bus_type inheritance which Patrick has been implementing.  I
don't have a technical issue with inheritance (drivers aren't shared),
I'm just not convinced it is the best solution yet.  :-)

My other thought is this:  If from both the device perspective and the
driver perspective the interface is exactly the same as the
platform_bus_type, then platform_bus_type really is the correct
interface.  That says to me that putting the runtime PM behaviour into
a new bus_type is abstracting at the wrong level, and a different
method should be used to modify PM behaviour, either based on device
model topology (ie, the parent implement's the child's runtime PM
behaviour), or maybe a "struct dev_pm_ops *bus_pm" in the struct
device.

However, the number of device drivers affected is still very small,
and I don't have concerns if each driver registers itself on multiple
bus ...
From: Kevin Hilman
Date: Friday, August 20, 2010 - 11:51 am

Grant Likely <grant.likely@secretlab.ca> writes:


Heh, now I feel like we're going around in circles.  Remember, I never
wanted to create add a new bus_type.  Someone else [ahem] suggested

Yes, I'm working on the devres approach to that now, as is Magnus for

IMHO, simply overriding the few dev_pm_ops methods was the cleanest and
simplest.

Since we seem to be in agreement now that the a new bus may not the
right abstraction for this (since we want it to be completely
transparent to the drivers), I'll go back to the original design.  No new
bus types, keep the platform_bus as is, but simply override the few
dev_pm_ops methods I care about.  This is what is done on SH,
SH-Mobile[1] and my original version for OMAP that started this
conversation.

Yes, the weak-symbol method of overriding is not scalable, but that's a
separate issue from whether or not to create a new bus.  I have a
proposed fix for the weak which I'll post shortly.

Kevin

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2010-August/022411.html



--

From: Grant Likely
Date: Friday, August 20, 2010 - 1:08 pm

On Fri, Aug 20, 2010 at 12:51 PM, Kevin Hilman

Hey!  I didn't suggest it either!  I believe that was Greg at ELC.  I

Okay.

One constraint remains though:  If you can override the dev_pm_ops on
a per-device or per-device-parent basis, then you've got my support.
If the override (even when fixed to work at runtime) applies to every
device on the platform_bus_type, then I'll nack it.  My concern here
is that the SoC or platform support code doesn't get to "own" the
platform_bus_type.  Other drivers/code can register their own set of
platform_devices, which may also need to perform their own dev_pm_ops
override.  If the override is global to the platform_bus_type, then
the model will not scale.

Cheers,
g.
--

From: Grant Likely
Date: Saturday, August 21, 2010 - 12:10 am

On Fri, Aug 20, 2010 at 6:10 PM, Kevin Hilman

Nope!  Not a new requirement; this is the issue that this entire
thread has been about.  Hijacking the entire platform_bus_type
behaviour for a particular bus is the wrong thing to do because there



Oops, I didn't phrase that very well.  What I meant was that SoC or
platform support code must not be allowed to "own" or hijack the
platform_bus_type for it's own purposes.  What I wrote sounds like I

Alright, I can agree to that.  I do agree that the runtime override is
far and away better than the weak symbol approach.  However, there
needs to be some very clear rules in place for users of the override,
namely that users must understand that they are stewards of the
platform_bus_type, and must take care to preserve the default
behaviour for "uninteresting" devices.

Also, the expectation should be that it is a temporary measure until a
better abstraction is implemented.  It might be that a separate
bus_type is the way to go (if the multiple driver registration problem
can be solved) or it might be a way to differentiate pm_ops either
per-device or per-parent.  I'm not sure, but I'm starting on an OMAP
project soon, so I may very well end up working on this.

Cheers,
g.
--

From: Kevin Hilman
Date: Monday, August 23, 2010 - 7:53 am

Completely agree here.

Any overrides of the dev_pm_ops functions that do not also call the
pm_generic_* functions (or their equivalents) should be suspect.


Yes, I'll be glad to work on this too, but first I need to get through
reviewing the backlog of all the OMAP drivers we're converting to
runtime PM.

Kevin
--

From: Patrick Pannuto
Date: Tuesday, August 10, 2010 - 4:49 pm

In theory (although not *yet* in practice), a driver being passed
to platform_driver_probe might have driver.bus set to something
other than platform_bus_type. Locking drv->driver.bus is always
correct.

Signed-off-by: Patrick Pannuto <ppannuto@codeaurora.org>
---
 drivers/base/platform.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 4d99c8b..b69ccb4 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -539,12 +539,12 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,
 	 * if the probe was successful, and make sure any forced probes of
 	 * new devices fail.
 	 */
-	spin_lock(&platform_bus_type.p->klist_drivers.k_lock);
+	spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);
 	drv->probe = NULL;
 	if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
 		retval = -ENODEV;
 	drv->driver.probe = platform_drv_probe_fail;
-	spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);
+	spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);
 
 	if (code != retval)
 		platform_driver_unregister(drv);
-- 
1.7.2

--

Previous thread: FILE FOR CLAIM by Kelvin Moor on Tuesday, August 10, 2010 - 12:18 pm. (1 message)

Next thread: Re: remove inode_setattr by Stephen Rothwell on Tuesday, August 10, 2010 - 5:45 pm. (5 messages)