From 8ee5bdf3e9c99808bf271aa5cc41d689e6d9d3eb Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 18 Sep 2012 15:19:49 +0900 Subject: PCI/ACPI: Use normal list for struct acpi_pci_driver Use normal list for struct acpi_pci_driver to simplify code. Signed-off-by: Jiang Liu Signed-off-by: Yinghai Lu Signed-off-by: Taku Izumi Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index ec54014c..68d679e 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -72,8 +72,8 @@ static struct acpi_driver acpi_pci_root_driver = { }; static LIST_HEAD(acpi_pci_roots); +static LIST_HEAD(acpi_pci_drivers); -static struct acpi_pci_driver *sub_driver; static DEFINE_MUTEX(osc_lock); int acpi_pci_register_driver(struct acpi_pci_driver *driver) @@ -81,10 +81,7 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver) int n = 0; struct acpi_pci_root *root; - struct acpi_pci_driver **pptr = &sub_driver; - while (*pptr) - pptr = &(*pptr)->next; - *pptr = driver; + list_add_tail(&driver->node, &acpi_pci_drivers); if (!driver->add) return 0; @@ -103,14 +100,7 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) { struct acpi_pci_root *root; - struct acpi_pci_driver **pptr = &sub_driver; - while (*pptr) { - if (*pptr == driver) - break; - pptr = &(*pptr)->next; - } - BUG_ON(!*pptr); - *pptr = (*pptr)->next; + list_del(&driver->node); if (!driver->remove) return; -- cgit v1.1 From c8e9afb124f61e0c9901801f4c95ae4208bd4536 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 18 Sep 2012 15:20:34 +0900 Subject: PCI/ACPI: Notify acpi_pci_drivers when hot-plugging PCI root bridges When hot-plugging PCI root bridge, acpi_pci_drivers' add()/remove() methods should be invoked to notify registered drivers. Signed-off-by: Jiang Liu Signed-off-by: Yinghai Lu Signed-off-by: Taku Izumi Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 68d679e..4bec13d 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -626,14 +626,25 @@ end: static int acpi_pci_root_start(struct acpi_device *device) { struct acpi_pci_root *root = acpi_driver_data(device); + struct acpi_pci_driver *driver; + + list_for_each_entry(driver, &acpi_pci_drivers, node) + if (driver->add) + driver->add(device->handle); pci_bus_add_devices(root->bus); + return 0; } static int acpi_pci_root_remove(struct acpi_device *device, int type) { struct acpi_pci_root *root = acpi_driver_data(device); + struct acpi_pci_driver *driver; + + list_for_each_entry(driver, &acpi_pci_drivers, node) + if (driver->remove) + driver->remove(root->device->handle); device_set_run_wake(root->bus->bridge, false); pci_acpi_remove_bus_pm_notifier(device); -- cgit v1.1 From d0020f65220c237f300355873125df5efe2c2740 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Tue, 18 Sep 2012 15:21:31 +0900 Subject: PCI/ACPI: Protect acpi_pci_drivers list with mutex Use mutex to protect global acpi_pci_drivers list against PCI host bridge hotplug operations. Signed-off-by: Jiang Liu Signed-off-by: Yinghai Lu Signed-off-by: Taku Izumi Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 4bec13d..d710585 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -71,6 +71,8 @@ static struct acpi_driver acpi_pci_root_driver = { }, }; +/* Lock to protect both acpi_pci_roots and acpi_pci_drivers lists */ +static DEFINE_MUTEX(acpi_pci_root_lock); static LIST_HEAD(acpi_pci_roots); static LIST_HEAD(acpi_pci_drivers); @@ -81,34 +83,30 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver) int n = 0; struct acpi_pci_root *root; + mutex_lock(&acpi_pci_root_lock); list_add_tail(&driver->node, &acpi_pci_drivers); - - if (!driver->add) - return 0; - - list_for_each_entry(root, &acpi_pci_roots, node) { - driver->add(root->device->handle); - n++; - } + if (driver->add) + list_for_each_entry(root, &acpi_pci_roots, node) { + driver->add(root->device->handle); + n++; + } + mutex_unlock(&acpi_pci_root_lock); return n; } - EXPORT_SYMBOL(acpi_pci_register_driver); void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) { struct acpi_pci_root *root; + mutex_lock(&acpi_pci_root_lock); list_del(&driver->node); - - if (!driver->remove) - return; - - list_for_each_entry(root, &acpi_pci_roots, node) - driver->remove(root->device->handle); + if (driver->remove) + list_for_each_entry(root, &acpi_pci_roots, node) + driver->remove(root->device->handle); + mutex_unlock(&acpi_pci_root_lock); } - EXPORT_SYMBOL(acpi_pci_unregister_driver); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) @@ -628,9 +626,11 @@ static int acpi_pci_root_start(struct acpi_device *device) struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_driver *driver; + mutex_lock(&acpi_pci_root_lock); list_for_each_entry(driver, &acpi_pci_drivers, node) if (driver->add) driver->add(device->handle); + mutex_unlock(&acpi_pci_root_lock); pci_bus_add_devices(root->bus); @@ -642,9 +642,11 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_driver *driver; + mutex_lock(&acpi_pci_root_lock); list_for_each_entry(driver, &acpi_pci_drivers, node) if (driver->remove) driver->remove(root->device->handle); + mutex_unlock(&acpi_pci_root_lock); device_set_run_wake(root->bus->bridge, false); pci_acpi_remove_bus_pm_notifier(device); -- cgit v1.1 From 55bfe3c0c561783655a8ff2f6f3f19ac1362b132 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Tue, 18 Sep 2012 15:22:35 +0900 Subject: PCI/ACPI: Pass acpi_pci_root to acpi_pci_drivers' add/remove interface This patch changes .add/.remove interfaces of acpi_pci_driver. In the current implementation acpi_handle is passed as a parameter of .add/.remove interface. However, the acpi_pci_root structure contains more useful information than just the acpi_handle. This enables us to avoid some useless lookups in each acpi_pci_driver. Note: This changes interfaces used by acpi_pci_register_driver(), an exported symbol. This patch updates all the in-kernel users, but any out-of-kernel acpi_pci_register_driver() users will need updates. [bhelgaas: changelog] Signed-off-by: Taku Izumi Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index d710585..2868a9f 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -87,7 +87,7 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver) list_add_tail(&driver->node, &acpi_pci_drivers); if (driver->add) list_for_each_entry(root, &acpi_pci_roots, node) { - driver->add(root->device->handle); + driver->add(root); n++; } mutex_unlock(&acpi_pci_root_lock); @@ -104,7 +104,7 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) list_del(&driver->node); if (driver->remove) list_for_each_entry(root, &acpi_pci_roots, node) - driver->remove(root->device->handle); + driver->remove(root); mutex_unlock(&acpi_pci_root_lock); } EXPORT_SYMBOL(acpi_pci_unregister_driver); @@ -629,7 +629,7 @@ static int acpi_pci_root_start(struct acpi_device *device) mutex_lock(&acpi_pci_root_lock); list_for_each_entry(driver, &acpi_pci_drivers, node) if (driver->add) - driver->add(device->handle); + driver->add(root); mutex_unlock(&acpi_pci_root_lock); pci_bus_add_devices(root->bus); @@ -645,7 +645,7 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) mutex_lock(&acpi_pci_root_lock); list_for_each_entry(driver, &acpi_pci_drivers, node) if (driver->remove) - driver->remove(root->device->handle); + driver->remove(root); mutex_unlock(&acpi_pci_root_lock); device_set_run_wake(root->bus->bridge, false); -- cgit v1.1 From 6507e6ebebd2d5f7e17c6f2e32524270edd2a922 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Tue, 18 Sep 2012 15:24:40 +0900 Subject: PCI/ACPI: Protect acpi_pci_roots list with mutex Use mutex to protect acpi_pci_roots list against PCI host bridge hotplug operations. [bhelgaas: s/struct acpi_handle *handle/acpi_handle handle/] Signed-off-by: Taku Izumi Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 2868a9f..e1bdcc7 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -112,12 +112,17 @@ EXPORT_SYMBOL(acpi_pci_unregister_driver); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) { struct acpi_pci_root *root; + acpi_handle handle = NULL; + mutex_lock(&acpi_pci_root_lock); list_for_each_entry(root, &acpi_pci_roots, node) if ((root->segment == (u16) seg) && - (root->secondary.start == (u16) bus)) - return root->device->handle; - return NULL; + (root->secondary.start == (u16) bus)) { + handle = root->device->handle; + break; + } + mutex_unlock(&acpi_pci_root_lock); + return handle; } EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); @@ -506,8 +511,9 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) * TBD: Need PCI interface for enumeration/configuration of roots. */ - /* TBD: Locking */ + mutex_lock(&acpi_pci_root_lock); list_add_tail(&root->node, &acpi_pci_roots); + mutex_unlock(&acpi_pci_root_lock); printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n", acpi_device_name(device), acpi_device_bid(device), @@ -526,7 +532,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) "Bus %04x:%02x not present in PCI namespace\n", root->segment, (unsigned int)root->secondary.start); result = -ENODEV; - goto end; + goto out_del_root; } /* @@ -536,7 +542,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) */ result = acpi_pci_bind_root(device); if (result) - goto end; + goto out_del_root; /* * PCI Routing Table @@ -614,9 +620,11 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) return 0; +out_del_root: + mutex_lock(&acpi_pci_root_lock); + list_del(&root->node); + mutex_unlock(&acpi_pci_root_lock); end: - if (!list_empty(&root->node)) - list_del(&root->node); kfree(root); return result; } @@ -646,11 +654,12 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) list_for_each_entry(driver, &acpi_pci_drivers, node) if (driver->remove) driver->remove(root); - mutex_unlock(&acpi_pci_root_lock); device_set_run_wake(root->bus->bridge, false); pci_acpi_remove_bus_pm_notifier(device); + list_del(&root->node); + mutex_unlock(&acpi_pci_root_lock); kfree(root); return 0; } -- cgit v1.1 From cd4faf9c34b27cbb6bcc70a4f1d1759f2e6fa7fd Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Tue, 18 Sep 2012 15:23:23 +0900 Subject: PCI/ACPI: Use acpi_driver_data() rather than searching acpi_pci_roots This patch changes the implementation of acpi_pci_find_root(). We can access acpi_pci_root without scanning acpi_pci_roots list. If hostbridge hotplug is supported, acpi_pci_roots list will be protected by mutex. We should not access acpi_pci_roots list if preventable to lessen deadlock risk. Signed-off-by: Taku Izumi Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index e1bdcc7..13f9b5b 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -270,12 +270,15 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags) struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) { struct acpi_pci_root *root; + struct acpi_device *device; - list_for_each_entry(root, &acpi_pci_roots, node) { - if (root->device->handle == handle) - return root; - } - return NULL; + if (acpi_bus_get_device(handle, &device) || + acpi_match_device_ids(device, root_device_ids)) + return NULL; + + root = acpi_driver_data(device); + + return root; } EXPORT_SYMBOL_GPL(acpi_pci_find_root); -- cgit v1.1