Commit 116af378201ef793424cd10508ccf18b06d8a021

Authored by Benjamin Herrenschmidt
Committed by Greg Kroah-Hartman
1 parent 0215ffb08c

Driver core: add notification of bus events

I finally did as you suggested and added the notifier to the struct
bus_type itself. There are still problems to be expected is something
attaches to a bus type where the code can hook in different struct
device sub-classes (which is imho a big bogosity but I won't even try to
argue that case now) but it will solve nicely a number of issues I've
had so far.

That also means that clients interested in registering for such
notifications have to do it before devices are added and after bus types
are registered. Fortunately, most bus types that matter for the various
usage scenarios I have in mind are registerd at postcore_initcall time,
which means I have a really nice spot at arch_initcall time to add my
notifiers.

There are 4 notifications provided. Device being added (before hooked to
the bus) and removed (failure of previous case or after being unhooked
from the bus), along with driver being bound to a device and about to be
unbound.

The usage I have for these are:

 - The 2 first ones are used to maintain a struct device_ext that is
hooked to struct device.firmware_data. This structure contains for now a
pointer to the Open Firmware node related to the device (if any), the
NUMA node ID (for quick access to it) and the DMA operations pointers &
iommu table instance for DMA to/from this device. For bus types I own
(like IBM VIO or EBUS), I just maintain that structure directly from the
bus code when creating the devices. But for bus types managed by generic
code like PCI or platform (actually, of_platform which is a variation of
platform linked to Open Firmware device-tree), I need this notifier.

 - The other two ones have a completely different usage scenario. I have
cases where multiple devices and their drivers depend on each other. For
example, the IBM EMAC network driver needs to attach to a MAL DMA engine
which is a separate device, and a PHY interface which is also a separate
device. They are all of_platform_device's (well, about to be with my
upcoming patches) but there is no say in what precise order the core
will "probe" them and instanciate the various modules. The solution I
found for that is to have the drivers for emac to use multithread_probe,
and wait for a driver to be bound to the target MAL and PHY control
devices (the device-tree contains reference to the MAL and PHY interface
nodes, which I can then match to of_platform_devices). Right now, I've
been polling, but with that notifier, I can more cleanly wait (with a
timeout of course).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

Showing 4 changed files with 61 additions and 0 deletions Side-by-side Diff

... ... @@ -724,6 +724,8 @@
724 724 {
725 725 int retval;
726 726  
  727 + BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);
  728 +
727 729 retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name);
728 730 if (retval)
729 731 goto out;
... ... @@ -781,6 +783,18 @@
781 783 kset_unregister(&bus->devices);
782 784 subsystem_unregister(&bus->subsys);
783 785 }
  786 +
  787 +int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)
  788 +{
  789 + return blocking_notifier_chain_register(&bus->bus_notifier, nb);
  790 +}
  791 +EXPORT_SYMBOL_GPL(bus_register_notifier);
  792 +
  793 +int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb)
  794 +{
  795 + return blocking_notifier_chain_unregister(&bus->bus_notifier, nb);
  796 +}
  797 +EXPORT_SYMBOL_GPL(bus_unregister_notifier);
784 798  
785 799 int __init buses_init(void)
786 800 {
... ... @@ -17,6 +17,7 @@
17 17 #include <linux/slab.h>
18 18 #include <linux/string.h>
19 19 #include <linux/kdev_t.h>
  20 +#include <linux/notifier.h>
20 21  
21 22 #include <asm/semaphore.h>
22 23  
... ... @@ -428,6 +429,11 @@
428 429 if (platform_notify)
429 430 platform_notify(dev);
430 431  
  432 + /* notify clients of device entry (new way) */
  433 + if (dev->bus)
  434 + blocking_notifier_call_chain(&dev->bus->bus_notifier,
  435 + BUS_NOTIFY_ADD_DEVICE, dev);
  436 +
431 437 dev->uevent_attr.attr.name = "uevent";
432 438 dev->uevent_attr.attr.mode = S_IWUSR;
433 439 if (dev->driver)
... ... @@ -504,6 +510,9 @@
504 510 BusError:
505 511 device_pm_remove(dev);
506 512 PMError:
  513 + if (dev->bus)
  514 + blocking_notifier_call_chain(&dev->bus->bus_notifier,
  515 + BUS_NOTIFY_DEL_DEVICE, dev);
507 516 device_remove_groups(dev);
508 517 GroupError:
509 518 device_remove_attrs(dev);
... ... @@ -622,6 +631,9 @@
622 631 */
623 632 if (platform_notify_remove)
624 633 platform_notify_remove(dev);
  634 + if (dev->bus)
  635 + blocking_notifier_call_chain(&dev->bus->bus_notifier,
  636 + BUS_NOTIFY_DEL_DEVICE, dev);
625 637 bus_remove_device(dev);
626 638 device_pm_remove(dev);
627 639 kobject_uevent(&dev->kobj, KOBJ_REMOVE);
... ... @@ -52,6 +52,11 @@
52 52  
53 53 pr_debug("bound device '%s' to driver '%s'\n",
54 54 dev->bus_id, dev->driver->name);
  55 +
  56 + if (dev->bus)
  57 + blocking_notifier_call_chain(&dev->bus->bus_notifier,
  58 + BUS_NOTIFY_BOUND_DRIVER, dev);
  59 +
55 60 klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
56 61 ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj,
57 62 kobject_name(&dev->kobj));
... ... @@ -287,6 +292,11 @@
287 292 sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
288 293 sysfs_remove_link(&dev->kobj, "driver");
289 294 klist_remove(&dev->knode_driver);
  295 +
  296 + if (dev->bus)
  297 + blocking_notifier_call_chain(&dev->bus->bus_notifier,
  298 + BUS_NOTIFY_UNBIND_DRIVER,
  299 + dev);
290 300  
291 301 if (dev->bus && dev->bus->remove)
292 302 dev->bus->remove(dev);
include/linux/device.h
... ... @@ -42,6 +42,8 @@
42 42 struct klist klist_devices;
43 43 struct klist klist_drivers;
44 44  
  45 + struct blocking_notifier_head bus_notifier;
  46 +
45 47 struct bus_attribute * bus_attrs;
46 48 struct device_attribute * dev_attrs;
47 49 struct driver_attribute * drv_attrs;
... ... @@ -74,6 +76,29 @@
74 76 int __must_check bus_for_each_drv(struct bus_type *bus,
75 77 struct device_driver *start, void *data,
76 78 int (*fn)(struct device_driver *, void *));
  79 +
  80 +/*
  81 + * Bus notifiers: Get notified of addition/removal of devices
  82 + * and binding/unbinding of drivers to devices.
  83 + * In the long run, it should be a replacement for the platform
  84 + * notify hooks.
  85 + */
  86 +struct notifier_block;
  87 +
  88 +extern int bus_register_notifier(struct bus_type *bus,
  89 + struct notifier_block *nb);
  90 +extern int bus_unregister_notifier(struct bus_type *bus,
  91 + struct notifier_block *nb);
  92 +
  93 +/* All 4 notifers below get called with the target struct device *
  94 + * as an argument. Note that those functions are likely to be called
  95 + * with the device semaphore held in the core, so be careful.
  96 + */
  97 +#define BUS_NOTIFY_ADD_DEVICE 0x00000001 /* device added */
  98 +#define BUS_NOTIFY_DEL_DEVICE 0x00000002 /* device removed */
  99 +#define BUS_NOTIFY_BOUND_DRIVER 0x00000003 /* driver bound to device */
  100 +#define BUS_NOTIFY_UNBIND_DRIVER 0x00000004 /* driver about to be
  101 + unbound */
77 102  
78 103 /* driverfs interface for exporting bus attributes */
79 104