aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-06-15 18:36:26 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-06-19 19:24:29 -0400
commit66345d5f79fcfa0214f5d98763643d4ee8e6965d (patch)
tree54e0765b867681dc85c6422a048e1c9a0ae25bd9
parentd9e455f53f6fb93c764de2399c3894bbdfd2caa7 (diff)
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 <rafael.j.wysocki@intel.com> Tested-by: Tony Luck <tony.luck@gmail.com> Acked-by: Toshi Kani <toshi.kani@hp.com>
-rw-r--r--arch/ia64/hp/common/sba_iommu.c24
1 files 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)
2042#endif 2042#endif
2043 2043
2044static int __init 2044static int __init
2045acpi_sba_ioc_add(struct acpi_device *device) 2045acpi_sba_ioc_add(struct acpi_device *device,
2046 const struct acpi_device_id *not_used)
2046{ 2047{
2047 struct ioc *ioc; 2048 struct ioc *ioc;
2048 acpi_status status; 2049 acpi_status status;
@@ -2090,14 +2091,18 @@ static const struct acpi_device_id hp_ioc_iommu_device_ids[] = {
2090 {"HWP0004", 0}, 2091 {"HWP0004", 0},
2091 {"", 0}, 2092 {"", 0},
2092}; 2093};
2093static struct acpi_driver acpi_sba_ioc_driver = { 2094static struct acpi_scan_handler acpi_sba_ioc_handler = {
2094 .name = "IOC IOMMU Driver", 2095 .ids = hp_ioc_iommu_device_ids,
2095 .ids = hp_ioc_iommu_device_ids, 2096 .attach = acpi_sba_ioc_add,
2096 .ops = {
2097 .add = acpi_sba_ioc_add,
2098 },
2099}; 2097};
2100 2098
2099static int __init acpi_sba_ioc_init_acpi(void)
2100{
2101 return acpi_scan_add_handler(&acpi_sba_ioc_handler);
2102}
2103/* This has to run before acpi_scan_init(). */
2104arch_initcall(acpi_sba_ioc_init_acpi);
2105
2101extern struct dma_map_ops swiotlb_dma_ops; 2106extern struct dma_map_ops swiotlb_dma_ops;
2102 2107
2103static int __init 2108static int __init
@@ -2122,7 +2127,10 @@ sba_init(void)
2122 } 2127 }
2123#endif 2128#endif
2124 2129
2125 acpi_bus_register_driver(&acpi_sba_ioc_driver); 2130 /*
2131 * ioc_list should be populated by the acpi_sba_ioc_handler's .attach()
2132 * routine, but that only happens if acpi_scan_init() has already run.
2133 */
2126 if (!ioc_list) { 2134 if (!ioc_list) {
2127#ifdef CONFIG_IA64_GENERIC 2135#ifdef CONFIG_IA64_GENERIC
2128 /* 2136 /*