aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2006-11-17 02:28:47 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-12-01 17:52:02 -0500
commitc67334fbdfbba533af767610cf3fde8a49710e62 (patch)
treec386f3aa4af94bb7d24ddb18b51f90bcb9a4d599
parentacf02d23b96efa92e7cff05987122ceeb37dd075 (diff)
Driver core: platform_driver_probe(), can save codespace
This defines a new platform_driver_probe() method allowing the driver's probe() method, and its support code+data, to safely live in __init sections for typical system configurations. Many system-on-chip processors could benefit from this API, to the tune of recovering hundreds to thousands of bytes per driver. That's memory which is currently wasted holding code which can never be called after system startup, yet can not be removed. It can't be removed because of the linkage requirement that pointers to init section code (like, ideally, probe support) must not live in other sections (like driver method tables) after those pointers would be invalid. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/base/platform.c48
-rw-r--r--include/linux/platform_device.h6
2 files changed, 54 insertions, 0 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 940ce41f1887..d1df4a087924 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -388,6 +388,11 @@ static int platform_drv_probe(struct device *_dev)
388 return drv->probe(dev); 388 return drv->probe(dev);
389} 389}
390 390
391static int platform_drv_probe_fail(struct device *_dev)
392{
393 return -ENXIO;
394}
395
391static int platform_drv_remove(struct device *_dev) 396static int platform_drv_remove(struct device *_dev)
392{ 397{
393 struct platform_driver *drv = to_platform_driver(_dev->driver); 398 struct platform_driver *drv = to_platform_driver(_dev->driver);
@@ -451,6 +456,49 @@ void platform_driver_unregister(struct platform_driver *drv)
451} 456}
452EXPORT_SYMBOL_GPL(platform_driver_unregister); 457EXPORT_SYMBOL_GPL(platform_driver_unregister);
453 458
459/**
460 * platform_driver_probe - register driver for non-hotpluggable device
461 * @drv: platform driver structure
462 * @probe: the driver probe routine, probably from an __init section
463 *
464 * Use this instead of platform_driver_register() when you know the device
465 * is not hotpluggable and has already been registered, and you want to
466 * remove its run-once probe() infrastructure from memory after the driver
467 * has bound to the device.
468 *
469 * One typical use for this would be with drivers for controllers integrated
470 * into system-on-chip processors, where the controller devices have been
471 * configured as part of board setup.
472 *
473 * Returns zero if the driver registered and bound to a device, else returns
474 * a negative error code and with the driver not registered.
475 */
476int platform_driver_probe(struct platform_driver *drv,
477 int (*probe)(struct platform_device *))
478{
479 int retval, code;
480
481 /* temporary section violation during probe() */
482 drv->probe = probe;
483 retval = code = platform_driver_register(drv);
484
485 /* Fixup that section violation, being paranoid about code scanning
486 * the list of drivers in order to probe new devices. Check to see
487 * if the probe was successful, and make sure any forced probes of
488 * new devices fail.
489 */
490 spin_lock(&platform_bus_type.klist_drivers.k_lock);
491 drv->probe = NULL;
492 if (code == 0 && list_empty(&drv->driver.klist_devices.k_list))
493 retval = -ENODEV;
494 drv->driver.probe = platform_drv_probe_fail;
495 spin_unlock(&platform_bus_type.klist_drivers.k_lock);
496
497 if (code != retval)
498 platform_driver_unregister(drv);
499 return retval;
500}
501EXPORT_SYMBOL_GPL(platform_driver_probe);
454 502
455/* modalias support enables more hands-off userspace setup: 503/* modalias support enables more hands-off userspace setup:
456 * (a) environment variable lets new-style hotplug events work once system is 504 * (a) environment variable lets new-style hotplug events work once system is
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 29cd6dee13db..20f47b81d3fa 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -58,6 +58,12 @@ struct platform_driver {
58extern int platform_driver_register(struct platform_driver *); 58extern int platform_driver_register(struct platform_driver *);
59extern void platform_driver_unregister(struct platform_driver *); 59extern void platform_driver_unregister(struct platform_driver *);
60 60
61/* non-hotpluggable platform devices may use this so that probe() and
62 * its support may live in __init sections, conserving runtime memory.
63 */
64extern int platform_driver_probe(struct platform_driver *driver,
65 int (*probe)(struct platform_device *));
66
61#define platform_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev) 67#define platform_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev)
62#define platform_set_drvdata(_dev,data) dev_set_drvdata(&(_dev)->dev, (data)) 68#define platform_set_drvdata(_dev,data) dev_set_drvdata(&(_dev)->dev, (data))
63 69