Commit:     49a4ec188f9a96c9a5567956718213d38a456a19
Parent:     eb81d93046e7de51d47b8f1303d80e6f51ac9e33
Author:     David Brownell <[EMAIL PROTECTED]>
AuthorDate: Tue May 8 00:29:39 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Tue May 8 11:15:10 2007 -0700

    fix hotplug for legacy platform drivers
    We've had various reports of some legacy "probe the hardware" style
    platform drivers having nasty problems with hotplug support.
    The core issue is that those legacy drivers don't fully conform to the
    driver model.  They assume a role that should be the responsibility of
    infrastructure code: creating device nodes.
    The "modprobe" step in hotplugging relies on drivers to have split those
    roles into different modules.  The lack of this split causes the problems.
    When a driver creates nodes for devices that don't exist (sending a hotplug
    event), then exits (aborting one modprobe) before the "modprobe $MODALIAS"
    step completes (by failing, since it's in the middle of a modprobe), the
    result can be an endless loop of modprobe invocations ...  badness.
    This fix uses the newish per-device flag controlling issuance of "add"
    events.  (A previous version of this patch used a per-device "driver can
    hotplug" flag, which only scrubbed $MODALIAS from the environment rather
    than suppressing the entire hotplug event.) It also shrinks that flag to
    one bit, saving a word in "struct device".
    So the net of this patch is removing some nasty failures with legacy
    drivers, while retaining hotplug capability for the majority of platform
    Signed-off-by: David Brownell <[EMAIL PROTECTED]>
    Cc: Andres Salomon <[EMAIL PROTECTED]>
    Cc: Dominik Brodowski <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
 drivers/base/platform.c           |   18 ++++++++++++++++++
 drivers/pcmcia/pxa2xx_mainstone.c |    1 +
 drivers/pcmcia/pxa2xx_sharpsl.c   |    1 +
 include/linux/device.h            |    4 ++--
 4 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 17b5ece..eb84d9d 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -160,6 +160,11 @@ static void platform_device_release(struct device *dev)
  *     Create a platform device object which can have other objects attached
  *     to it, and which will have attached objects freed when it is released.
+ *
+ *     This device will be marked as not supporting hotpluggable drivers; no
+ *     device add/remove uevents will be generated.  In the unusual case that
+ *     the device isn't being dynamically allocated as a legacy "probe the
+ *     hardware" driver, infrastructure code should reverse this marking.
 struct platform_device *platform_device_alloc(const char *name, unsigned int 
@@ -172,6 +177,12 @@ struct platform_device *platform_device_alloc(const char 
*name, unsigned int id)
                pa-> = id;
                pa-> = platform_device_release;
+               /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble 
+                * legacy probe-the-hardware drivers, which don't properly split
+                * out device enumeration logic from drivers.
+                */
+               pa-> = 1;
        return pa ? &pa->pdev : NULL;
@@ -351,6 +362,13 @@ EXPORT_SYMBOL_GPL(platform_device_unregister);
  *     memory allocated for the device allows drivers using such devices
  *     to be unloaded iwithout waiting for the last reference to the device
  *     to be dropped.
+ *
+ *     This interface is primarily intended for use with legacy drivers
+ *     which probe hardware directly.  Because such drivers create sysfs
+ *     device nodes themselves, rather than letting system infrastructure
+ *     handle such device enumeration tasks, they don't fully conform to
+ *     the Linux driver model.  In particular, when such drivers are built
+ *     as modules, they can't be "hotplugged".
 struct platform_device *platform_device_register_simple(char *name, unsigned 
int id,
                                                        struct resource *res, 
unsigned int num)
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c 
index fda0694..383107b 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -175,6 +175,7 @@ static int __init mst_pcmcia_init(void)
        if (!mst_pcmcia_device)
                return -ENOMEM;
+       mst_pcmcia_device->dev.uevent_suppress = 0;
        mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops;
        ret = platform_device_add(mst_pcmcia_device);
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index b7b9e14..a2daa3f 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -261,6 +261,7 @@ static int __init sharpsl_pcmcia_init(void)
        if (!sharpsl_pcmcia_device)
                return -ENOMEM;
+       sharpsl_pcmcia_device->dev.uevent_suppress = 0;
        sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
        sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
diff --git a/include/linux/device.h b/include/linux/device.h
index 6579068..2e1a298 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -412,12 +412,13 @@ struct device {
        struct klist_node       knode_parent;           /* node in sibling list 
        struct klist_node       knode_driver;
        struct klist_node       knode_bus;
-       struct device   * parent;
+       struct device           *parent;
        struct kobject kobj;
        char    bus_id[BUS_ID_SIZE];    /* position on parent bus */
        struct device_type      *type;
        unsigned                is_registered:1;
+       unsigned                uevent_suppress:1;
        struct device_attribute uevent_attr;
        struct device_attribute *devt_attr;
@@ -458,7 +459,6 @@ struct device {
        struct class            *class;
        dev_t                   devt;           /* dev_t, creates the sysfs 
"dev" */
        struct attribute_group  **groups;       /* optional groups */
-       int                     uevent_suppress;
        void    (*release)(struct device * dev);
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at

Reply via email to