linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Patrick Pannuto <ppannuto@codeaurora.org>
To: Patrick Pannuto <ppannuto@codeaurora.org>
Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	magnus.damm@gmail.com, grant.likely@secretlab.ca, gregkh@suse.de,
	Kevin Hilman <khilman@deeprootsystems.com>,
	Paul Mundt <lethal@linux-sh.org>,
	Magnus Damm <damm@opensource.se>,
	"Rafael J. Wysocki" <rjw@sisk.pl>,
	Eric Miao <eric.y.miao@gmail.com>, Dmitry Torokhov <dtor@mail.ru>,
	netdev@vger.kernel.org
Subject: Re: [PATCH 2/2] platform: Facilitate the creation of pseudo-platform buses
Date: Thu, 12 Aug 2010 18:13:09 -0700	[thread overview]
Message-ID: <4C649C25.5090808@codeaurora.org> (raw)
In-Reply-To: <1281484174-32174-3-git-send-email-ppannuto@codeaurora.org>

On 08/10/2010 04:49 PM, Patrick Pannuto wrote:
> (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 fail_bus2;
> 
> 		return error;
> 
> 		/* platform_device_unregister(&SOC_bus2); */
> fail_bus2:
> 		platform_device_unregister(&SOC_bus1);
> fail_bus1:
> 		pseudo_platform_bus_unregister(&SOC_bus_type);
> 
> 		return error;
> 	}
> 
> /drivers/my_driver.c:
> 	static struct platform_driver my_driver = {
> 		.driver = {
> 			.name	= "my-driver",
> 			.owner	= THIS_MODULE,
> 			.bus	= &SOC_bus_type,
> 		},
> 	};
> 
> /somewhere/my_device.c:
> 	static struct platform_device my_device = {
> 		.name		= "my-device",
> 		.id		= -1,
> 		.dev.bus	= &my_bus_type,
> 		.dev.parent	= &SOC_bus1.dev,
> 	};
> 
> This will build a device tree that mirrors the actual system:
> 
> /sys/bus
> |-- SOC-bus-type
> |   |-- devices
> |   |   |-- SOC_bus1 -> ../../../devices/SOC_bus1
> |   |   |-- SOC_bus2 -> ../../../devices/SOC_bus2
> |   |   |-- my-device -> ../../../devices/SOC_bus1/my-device
> |   |-- drivers
> |   |   |-- my-driver
> 
> /sys/devices
> |-- SOC_bus1
> |   |-- my-device
> |-- SOC_bus2
> 
> Driver can drive any device on the SOC, which is logical, without
> actually being registered on multiple /bus_types/, even though the
> devices may be on different /physical buses/ (which are actually
> just devices).
> 
> THOUGHTS:
> 
> 1.
> Notice that for a device / driver, only 3 lines were added to
> switch from the platform bus to the new SOC_bus. This is
> especially valuable if we consider supporting a legacy SOCs
> and new SOCs where the same driver is used, but may need to
> be on either the platform bus or the new SOC_bus. The above
> code then becomes:
> 
> 	(possibly in a header)
> 	#ifdef CONFIG_MY_BUS
> 	#define MY_BUS_TYPE     &SOC_bus_type
> 	#else
> 	#define MY_BUS_TYPE     NULL
> 	#endif
> 
> /drivers/my_driver.c
> 	static struct platform_driver my_driver = {
> 		.driver = {
> 			.name   = "my-driver",
> 			.owner  = THIS_MODULE,
> 			.bus    = MY_BUS_TYPE,
> 		},
> 	};
> 
> Which will allow the same driver to easily to used on either
> the platform bus or the newly defined bus type.
> 
> 2.
> Implementations wishing to make dynamic / run-time decisions on where
> devices are placed could easily create wrapper functions, that is
> 
> 	int SOC_device_register(struct platform_device *pdev)
> 	{
> 		if (pdev->archdata->flag)
> 			pdev->dev.parent = &SOC_bus1.dev;
> 		else
> 			pdev->dev.parent = &SOC_bus2.dev;
> 
> 		return platform_device_register(pdev);
> 	}
> 
> A similar solution also would allow for run-time determination of dev.bus,
> if that were necessary for your platform.
> 
> 3.
> I'm not convinced that dynamically allocating a new copy of dev_pm_ops is
> the best solution. I *AM*, however, convinced that removing const from
> 	struct bus_type {
> 		...
> 		const struct dev_pm_ops *pm;
> 		...
> 	};
> would be a mistake; it is far too easy to overwrite one of the function
> pointers on accident, and the const serves a very useful purpose here.
> 
> Cc: Kevin Hilman <khilman@deeprootsystems.com>
> Signed-off-by: Patrick Pannuto <ppannuto@codeaurora.org>
> ---
>  drivers/base/platform.c         |   92 +++++++++++++++++++++++++++++++++++++-
>  include/linux/platform_device.h |    3 +
>  2 files changed, 92 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index b69ccb4..933e0c1 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -238,8 +238,12 @@ int platform_device_add(struct platform_device *pdev)
>  	if (!pdev)
>  		return -EINVAL;
>  
> -	if (!pdev->dev.parent)
> -		pdev->dev.parent = &platform_bus;
> +	if (!pdev->dev.bus) {
> +		pdev->dev.bus = &platform_bus_type;
> +
> +		if (!pdev->dev.parent)
> +			pdev->dev.parent = &platform_bus;
> +	}
>  
>  	pdev->dev.bus = &platform_bus_type;

^^^ small bug here, this line should be deleted; any other comments though?

>  
> @@ -482,7 +486,8 @@ static void platform_drv_shutdown(struct device *_dev)
>   */
>  int platform_driver_register(struct platform_driver *drv)
>  {
> -	drv->driver.bus = &platform_bus_type;
> +	if (!drv->driver.bus)
> +		drv->driver.bus = &platform_bus_type;
>  	if (drv->probe)
>  		drv->driver.probe = platform_drv_probe;
>  	if (drv->remove)
> @@ -1017,6 +1022,87 @@ struct bus_type platform_bus_type = {
>  };
>  EXPORT_SYMBOL_GPL(platform_bus_type);
>  
> +/** pseudo_platform_bus_register - register an "almost platform bus"
> + * @bus: partially complete bus type to register
> + *
> + * This init will fill in any ommitted fields in @bus, however, it
> + * also allocates memory and replaces the pm field in @bus, since
> + * pm is const, but some of its pointers may need this one-time
> + * initialziation overwrite.
> + *
> + * @bus's registered this way should be released with
> + * pseudo_platform_bus_unregister
> + */
> +int pseudo_platform_bus_register(struct bus_type *bus)
> +{
> +	int error;
> +	struct dev_pm_ops* heap_pm;
> +	heap_pm = kmalloc(sizeof (*heap_pm), GFP_KERNEL);
> +
> +	if (!heap_pm)
> +		return -ENOMEM;
> +
> +	if (!bus->dev_attrs)
> +		bus->dev_attrs = platform_bus_type.dev_attrs;
> +	if (!bus->match)
> +		bus->match = platform_bus_type.match;
> +	if (!bus->uevent)
> +		bus->uevent = platform_bus_type.uevent;
> +	if (!bus->pm)
> +		memcpy(heap_pm, &platform_bus_type.pm, sizeof(*heap_pm));
> +	else {
> +		heap_pm->prepare = (bus->pm->prepare) ?
> +			bus->pm->prepare : platform_pm_prepare;
> +		heap_pm->complete = (bus->pm->complete) ?
> +			bus->pm->complete : platform_pm_complete;
> +		heap_pm->suspend = (bus->pm->suspend) ?
> +			bus->pm->suspend : platform_pm_suspend;
> +		heap_pm->resume = (bus->pm->resume) ?
> +			bus->pm->resume : platform_pm_resume;
> +		heap_pm->freeze = (bus->pm->freeze) ?
> +			bus->pm->freeze : platform_pm_freeze;
> +		heap_pm->thaw = (bus->pm->thaw) ?
> +			bus->pm->thaw : platform_pm_thaw;
> +		heap_pm->poweroff = (bus->pm->poweroff) ?
> +			bus->pm->poweroff : platform_pm_poweroff;
> +		heap_pm->restore = (bus->pm->restore) ?
> +			bus->pm->restore : platform_pm_restore;
> +		heap_pm->suspend_noirq = (bus->pm->suspend_noirq) ?
> +			bus->pm->suspend_noirq : platform_pm_suspend_noirq;
> +		heap_pm->resume_noirq = (bus->pm->resume_noirq) ?
> +			bus->pm->resume_noirq : platform_pm_resume_noirq;
> +		heap_pm->freeze_noirq = (bus->pm->freeze_noirq) ?
> +			bus->pm->freeze_noirq : platform_pm_freeze_noirq;
> +		heap_pm->thaw_noirq = (bus->pm->thaw_noirq) ?
> +			bus->pm->thaw_noirq : platform_pm_thaw_noirq;
> +		heap_pm->poweroff_noirq = (bus->pm->poweroff_noirq) ?
> +			bus->pm->poweroff_noirq : platform_pm_poweroff_noirq;
> +		heap_pm->restore_noirq = (bus->pm->restore_noirq) ?
> +			bus->pm->restore_noirq : platform_pm_restore_noirq;
> +		heap_pm->runtime_suspend = (bus->pm->runtime_suspend) ?
> +			bus->pm->runtime_suspend : platform_pm_runtime_suspend;
> +		heap_pm->runtime_resume = (bus->pm->runtime_resume) ?
> +			bus->pm->runtime_resume : platform_pm_runtime_resume;
> +		heap_pm->runtime_idle = (bus->pm->runtime_idle) ?
> +			bus->pm->runtime_idle : platform_pm_runtime_idle;
> +	}
> +	bus->pm = heap_pm;
> +
> +	error = bus_register(bus);
> +	if (error)
> +		kfree(bus->pm);
> +
> +	return error;
> +}
> +EXPORT_SYMBOL_GPL(pseudo_platform_bus_register);
> +
> +void pseudo_platform_bus_unregister(struct bus_type *bus)
> +{
> +	bus_unregister(bus);
> +	kfree(bus->pm);
> +}
> +EXPORT_SYMBOL_GPL(pseudo_platform_bus_unregister);
> +
>  int __init platform_bus_init(void)
>  {
>  	int error;
> diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
> index 5417944..5ec827c 100644
> --- a/include/linux/platform_device.h
> +++ b/include/linux/platform_device.h
> @@ -79,6 +79,9 @@ extern int platform_driver_probe(struct platform_driver *driver,
>  #define platform_get_drvdata(_dev)	dev_get_drvdata(&(_dev)->dev)
>  #define platform_set_drvdata(_dev,data)	dev_set_drvdata(&(_dev)->dev, (data))
>  
> +extern int pseudo_platform_bus_register(struct bus_type *);
> +extern void pseudo_platform_bus_unregister(struct bus_type *);
> +
>  extern struct platform_device *platform_create_bundle(struct platform_driver *driver,
>  					int (*probe)(struct platform_device *),
>  					struct resource *res, unsigned int n_res,


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

  reply	other threads:[~2010-08-13  1:13 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-08-10 23:49 [PATCHv2 0/2] platform: Facilitate the creation of pseudo-platform buses Patrick Pannuto
2010-08-10 23:49 ` [PATCH 1/2] platform: Use drv->driver.bus instead of assuming platform_bus_type Patrick Pannuto
2010-08-10 23:49 ` [PATCH 2/2] platform: Facilitate the creation of pseudo-platform buses Patrick Pannuto
2010-08-13  1:13   ` Patrick Pannuto [this message]
2010-08-14 21:04     ` Greg KH
2010-08-13 22:05   ` Grant Likely
2010-08-16 18:47     ` Patrick Pannuto
2010-08-16 20:25       ` Grant Likely
2010-08-16 23:58       ` Michał Mirosław
2010-08-16  1:38   ` Moffett, Kyle D
2010-08-16  6:43     ` Grant Likely
2010-08-19 19:20       ` Kevin Hilman
2010-08-19 22:22         ` Grant Likely
2010-08-20 18:51           ` Kevin Hilman
2010-08-20 20:08             ` Grant Likely
2010-08-21  0:10               ` Kevin Hilman
2010-08-21  7:10                 ` Grant Likely
2010-08-23 14:53                   ` Kevin Hilman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4C649C25.5090808@codeaurora.org \
    --to=ppannuto@codeaurora.org \
    --cc=damm@opensource.se \
    --cc=dtor@mail.ru \
    --cc=eric.y.miao@gmail.com \
    --cc=grant.likely@secretlab.ca \
    --cc=gregkh@suse.de \
    --cc=khilman@deeprootsystems.com \
    --cc=lethal@linux-sh.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=magnus.damm@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=rjw@sisk.pl \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).