Commit c67334fbdfbba533af767610cf3fde8a49710e62

Authored by David Brownell
Committed by Greg Kroah-Hartman
1 parent acf02d23b9

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>

Showing 2 changed files with 54 additions and 0 deletions Side-by-side Diff

drivers/base/platform.c
... ... @@ -388,6 +388,11 @@
388 388 return drv->probe(dev);
389 389 }
390 390  
  391 +static int platform_drv_probe_fail(struct device *_dev)
  392 +{
  393 + return -ENXIO;
  394 +}
  395 +
391 396 static int platform_drv_remove(struct device *_dev)
392 397 {
393 398 struct platform_driver *drv = to_platform_driver(_dev->driver);
... ... @@ -451,6 +456,49 @@
451 456 }
452 457 EXPORT_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 + */
  476 +int 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 +}
  501 +EXPORT_SYMBOL_GPL(platform_driver_probe);
454 502  
455 503 /* modalias support enables more hands-off userspace setup:
456 504 * (a) environment variable lets new-style hotplug events work once system is
include/linux/platform_device.h
... ... @@ -58,6 +58,12 @@
58 58 extern int platform_driver_register(struct platform_driver *);
59 59 extern 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 + */
  64 +extern int platform_driver_probe(struct platform_driver *driver,
  65 + int (*probe)(struct platform_device *));
  66 +
61 67 #define platform_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev)
62 68 #define platform_set_drvdata(_dev,data) dev_set_drvdata(&(_dev)->dev, (data))
63 69