From d9e455f53f6fb93c764de2399c3894bbdfd2caa7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 10 Jun 2013 13:00:50 +0200 Subject: ACPI / scan: Simplify ACPI driver probing There is no particular reason why acpi_bus_driver_init() needs to be a separate function and its location with respect to its only caller, acpi_device_probe(), makes the code a bit difficult to follow. Besides, it doesn't really make sense to check if 'device' is not NULL in acpi_bus_driver_init(), because we've already dereferenced dev->driver in acpi_device_probe() at that point and, moreover, 'device' cannot be NULL then, because acpi_device_probe() is called via really_probe() (which also sets dev->driver for that matter). For these reasons, drop acpi_bus_driver_init() altogether and move the remaining code from it directly into acpi_device_probe(). Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 81 ++++++++++++++++++----------------------------------- 1 file changed, 27 insertions(+), 54 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b14ac46948c9..4eeea2262454 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -816,32 +816,40 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device) acpi_device_notify); } -static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *); -static int acpi_device_probe(struct device * dev) +static int acpi_device_probe(struct device *dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); int ret; - ret = acpi_bus_driver_init(acpi_dev, acpi_drv); - if (!ret) { - if (acpi_drv->ops.notify) { - ret = acpi_device_install_notify_handler(acpi_dev); - if (ret) { - if (acpi_drv->ops.remove) - acpi_drv->ops.remove(acpi_dev); - acpi_dev->driver = NULL; - acpi_dev->driver_data = NULL; - return ret; - } - } + if (!acpi_drv->ops.add) + return -ENOSYS; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Found driver [%s] for device [%s]\n", - acpi_drv->name, acpi_dev->pnp.bus_id)); - get_device(dev); + ret = acpi_drv->ops.add(acpi_dev); + if (ret) + return ret; + + acpi_dev->driver = acpi_drv; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Driver [%s] successfully bound to device [%s]\n", + acpi_drv->name, acpi_dev->pnp.bus_id)); + + if (acpi_drv->ops.notify) { + ret = acpi_device_install_notify_handler(acpi_dev); + if (ret) { + if (acpi_drv->ops.remove) + acpi_drv->ops.remove(acpi_dev); + + acpi_dev->driver = NULL; + acpi_dev->driver_data = NULL; + return ret; + } } - return ret; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", + acpi_drv->name, acpi_dev->pnp.bus_id)); + get_device(dev); + return 0; } static int acpi_device_remove(struct device * dev) @@ -997,41 +1005,6 @@ static void acpi_device_unregister(struct acpi_device *device) /* -------------------------------------------------------------------------- Driver Management -------------------------------------------------------------------------- */ -/** - * acpi_bus_driver_init - add a device to a driver - * @device: the device to add and initialize - * @driver: driver for the device - * - * Used to initialize a device via its device driver. Called whenever a - * driver is bound to a device. Invokes the driver's add() ops. - */ -static int -acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) -{ - int result = 0; - - if (!device || !driver) - return -EINVAL; - - if (!driver->ops.add) - return -ENOSYS; - - result = driver->ops.add(device); - if (result) - return result; - - device->driver = driver; - - /* - * TBD - Configuration Management: Assign resources to device based - * upon possible configuration and currently allocated resources. - */ - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Driver successfully bound to device\n")); - return 0; -} - /** * acpi_bus_register_driver - register a driver with the ACPI bus * @driver: driver being registered -- cgit v1.2.3-59-g8ed1b From 66345d5f79fcfa0214f5d98763643d4ee8e6965d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 16 Jun 2013 00:36:26 +0200 Subject: ACPI / ia64 / sba_iommu: Use ACPI scan handler for device discovery The IA64 System Bus Adapter (SBA) I/O MMU driver uses an ACPI driver object to look for device objects it needs in the ACPI namespace, but that leads to an ordering issue between that driver and the container scan handler on ia64 HP rx2600. Namely, on that machine the SBA I/O MMU device object in the ACPI namespace has a _HID returning its own specific device ID and a _CID returning a generic container device ID. According to Toshi Kani, the idea is that if a _HID is not mached by an I/O MMU driver, the _CID should be matched by a generic container driver, so those device IDs should be used mutually exclusively. That is not what happens, however, because the container driver uses an ACPI scan handler which is matched against the device object in question before registering the SBA I/O MMU driver object. As a result, that scan handler claims the device object first. The driver binds to the same device object later, however, and they both happily use it simultaneously going forward (fortunately, that doesn't cause any real breakage to happen). To avoid that ordering issue, make the SBA I/O MMU code use an ACPI scan handler instead of an ACPI driver, so that it can claim the SBA I/O MMU device object before the container driver (thanks to an improved algorithm of matching ACPI device IDs used for ACPI scan handlers, which matches device _HIDs against the registered scan handlers before _CIDs). This also reduces the kernel's memory footprint slightly by avoiding to register a driver object that's not used after system initialization, so having it registered (and present in sysfs) throughout the system's life time isn't particularly useful. Signed-off-by: Rafael J. Wysocki Tested-by: Tony Luck Acked-by: Toshi Kani --- arch/ia64/hp/common/sba_iommu.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index bcda5b2d121a..d43daf192b21 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -2042,7 +2042,8 @@ sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle) #endif static int __init -acpi_sba_ioc_add(struct acpi_device *device) +acpi_sba_ioc_add(struct acpi_device *device, + const struct acpi_device_id *not_used) { struct ioc *ioc; acpi_status status; @@ -2090,14 +2091,18 @@ static const struct acpi_device_id hp_ioc_iommu_device_ids[] = { {"HWP0004", 0}, {"", 0}, }; -static struct acpi_driver acpi_sba_ioc_driver = { - .name = "IOC IOMMU Driver", - .ids = hp_ioc_iommu_device_ids, - .ops = { - .add = acpi_sba_ioc_add, - }, +static struct acpi_scan_handler acpi_sba_ioc_handler = { + .ids = hp_ioc_iommu_device_ids, + .attach = acpi_sba_ioc_add, }; +static int __init acpi_sba_ioc_init_acpi(void) +{ + return acpi_scan_add_handler(&acpi_sba_ioc_handler); +} +/* This has to run before acpi_scan_init(). */ +arch_initcall(acpi_sba_ioc_init_acpi); + extern struct dma_map_ops swiotlb_dma_ops; static int __init @@ -2122,7 +2127,10 @@ sba_init(void) } #endif - acpi_bus_register_driver(&acpi_sba_ioc_driver); + /* + * ioc_list should be populated by the acpi_sba_ioc_handler's .attach() + * routine, but that only happens if acpi_scan_init() has already run. + */ if (!ioc_list) { #ifdef CONFIG_IA64_GENERIC /* -- cgit v1.2.3-59-g8ed1b From 24071f472d813fccacc1ef7356b1f41422a1b968 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 16 Jun 2013 00:36:41 +0200 Subject: ACPI / scan: Do not bind ACPI drivers to objects with scan handlers ACPI drivers must not be bound to device objects having scan handlers attatched to them, so make acpi_device_probe() fail with -EINVAL if the device object being probed has an ACPI scan handler. After this change the analogous check introduced into the ACPI video driver by commit 8c9b7a7 (ACPI / video: Do not bind to device objects with a scan handler) is not necessary any more and may be dropped, so drop it. Signed-off-by: Rafael J. Wysocki Tested-by: Tony Luck Acked-by: Toshi Kani --- drivers/acpi/scan.c | 3 +++ drivers/acpi/video.c | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 4eeea2262454..54529424a0a5 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -822,6 +822,9 @@ static int acpi_device_probe(struct device *dev) struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); int ret; + if (acpi_dev->handler) + return -EINVAL; + if (!acpi_drv->ops.add) return -ENOSYS; diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 440eadf2d32c..5d7075d25700 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1722,9 +1722,6 @@ static int acpi_video_bus_add(struct acpi_device *device) int error; acpi_status status; - if (device->handler) - return -EINVAL; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, device->parent->handle, 1, acpi_video_bus_match, NULL, -- cgit v1.2.3-59-g8ed1b