Don't issue uevents for legacy platform drivers
David Brownell
dbrownell at users.sourceforge.unroutablenet
Wed Dec 13 04:33:15 EST 2006
Commit: 23ec7ff48b3b2fd9ad5897d7389cc06b6d8e6b7e
Parent: e50b707bd42b0c4f395929830976443e5a4e21be
commit 23ec7ff48b3b2fd9ad5897d7389cc06b6d8e6b7e
Author: David Brownell <dbrownell at users.sourceforge.net>
AuthorDate: Wed Dec 13 04:12:40 2006 -0500
Commit: Andres Salomon <dilinger at debian.org>
CommitDate: Wed Dec 13 04:12:40 2006 -0500
Don't issue uevents for legacy platform drivers
We've had recent reports of some legacy "probe the hardware" style platform
drivers having nasty problems with hotplug support.
The core issue is that those drivers don't fully conform to the driver
model.
They assume a role that's the responsibility of infrastructure code: they
create their own device nodes. But hotplugging relies on drivers to have
split
those roles into different modules, hence the problems. If the driver
creates
nodes for devices that don't exist, the "modprobe $MODALIAS" step of
hotplugging
can become an endless loop *when driver load aborts* (it's safe otherwise).
This fix adds a per-device flag saying whether its driver can't be
hotplugged,
which is set by APIs used for "probe the hardware" style drivers. The flag
is used to bypass relevant hotplug logic (setting the $MODALIAS environment
variable) for those problematic drivers.
The minor glitch is that in a few cases those APIs are used by platform
code,
instead of by drivers. Examples include most places where a "pcspkr"
device is
created (although a recent un-merged patch fixed that for X86_PC), or the
way
platform devices are created for OpenFirmware nodes ... all those cases
seem
to kick in before userspace (and hotplug) is active though.
So the net of this patch is removing some nasty failures with legacy
drivers,
while retaining hotplug capability for those platform drivers which are
well
behaved (the majority).
---
drivers/base/platform.c | 20 ++++++++++++++++++++
include/linux/device.h | 1 +
2 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 940ce41..632be31 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -160,6 +160,11 @@ static void platform_device_release(stru
*
* 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. In
+ * the unusual case that the device isn't being dynamically allocated as
+ * of a legacy "probe the hardware" driver, infrastructure code should
+ * consider reversing this marking.
*/
struct platform_device *platform_device_alloc(const char *name, unsigned int id)
{
@@ -172,6 +177,7 @@ struct platform_device *platform_device_
pa->pdev.id = id;
device_initialize(&pa->pdev.dev);
pa->pdev.dev.release = platform_device_release;
+ pa->pdev.dev.is_driver_not_hotpluggable = 1;
}
return pa ? &pa->pdev : NULL;
@@ -349,6 +355,13 @@ EXPORT_SYMBOL_GPL(platform_device_unregi
* 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 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)
@@ -477,6 +490,13 @@ static int platform_uevent(struct device
{
struct platform_device *pdev = to_platform_device(dev);
+ /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in
+ * legacy probe-the-hardware drivers, which don't properly split
+ * out enumeration logic from drivers.
+ */
+ if (dev->is_driver_not_hotpluggable)
+ return 0;
+
envp[0] = buffer;
snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name);
return 0;
diff --git a/include/linux/device.h b/include/linux/device.h
index 662e6a1..494c14c 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -330,6 +330,7 @@ struct device {
struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
unsigned is_registered:1;
+ unsigned is_driver_not_hotpluggable:1;
struct device_attribute uevent_attr;
struct device_attribute *devt_attr;
More information about the Commits-kernel
mailing list