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
next prev parent reply other threads:[~2010-08-13 1:13 UTC|newest]
Thread overview: 22+ 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 19:20 ` Kevin Hilman
2010-08-19 22:22 ` Grant Likely
2010-08-20 18:51 ` Kevin Hilman
2010-08-20 18:51 ` Kevin Hilman
2010-08-20 20:08 ` Grant Likely
2010-08-21 0:10 ` Kevin Hilman
2010-08-21 0:10 ` Kevin Hilman
2010-08-21 7:10 ` Grant Likely
2010-08-23 14:53 ` Kevin Hilman
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.