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') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index ec54014c321c..68d679e21248 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.2.3 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') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 68d679e21248..4bec13d9c2bf 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.2.3 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') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 4bec13d9c2bf..d710585e4a7f 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.2.3 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 ++++---- drivers/acpi/pci_slot.c | 11 ++++++----- drivers/pci/hotplug/acpiphp_glue.c | 12 +++++++----- include/linux/acpi.h | 4 ++-- 4 files changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index d710585e4a7f..2868a9ff6d07 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); diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index e50e31a518af..8051ffa7609d 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -67,8 +67,8 @@ struct acpi_pci_slot { struct list_head list; /* node in the list of slots */ }; -static int acpi_pci_slot_add(acpi_handle handle); -static void acpi_pci_slot_remove(acpi_handle handle); +static int acpi_pci_slot_add(struct acpi_pci_root *root); +static void acpi_pci_slot_remove(struct acpi_pci_root *root); static LIST_HEAD(slot_list); static DEFINE_MUTEX(slot_list_lock); @@ -295,11 +295,11 @@ walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function) * @handle: points to an acpi_pci_root */ static int -acpi_pci_slot_add(acpi_handle handle) +acpi_pci_slot_add(struct acpi_pci_root *root) { acpi_status status; - status = walk_root_bridge(handle, register_slot); + status = walk_root_bridge(root->device->handle, register_slot); if (ACPI_FAILURE(status)) err("%s: register_slot failure - %d\n", __func__, status); @@ -311,10 +311,11 @@ acpi_pci_slot_add(acpi_handle handle) * @handle: points to an acpi_pci_root */ static void -acpi_pci_slot_remove(acpi_handle handle) +acpi_pci_slot_remove(struct acpi_pci_root *root) { struct acpi_pci_slot *slot, *tmp; struct pci_bus *pbus; + acpi_handle handle = root->device->handle; mutex_lock(&slot_list_lock); list_for_each_entry_safe(slot, tmp, &slot_list, list) { diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 7be4ca5e1f4c..466233b481b1 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -382,10 +382,10 @@ static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) /* allocate and initialize host bridge data structure */ -static void add_host_bridge(acpi_handle *handle) +static void add_host_bridge(struct acpi_pci_root *root) { struct acpiphp_bridge *bridge; - struct acpi_pci_root *root = acpi_pci_find_root(handle); + acpi_handle handle = root->device->handle; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); if (bridge == NULL) @@ -468,11 +468,12 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) /* find hot-pluggable slots, and then find P2P bridge */ -static int add_bridge(acpi_handle handle) +static int add_bridge(struct acpi_pci_root *root) { acpi_status status; unsigned long long tmp; acpi_handle dummy_handle; + acpi_handle handle = root->device->handle; /* if the bridge doesn't have _STA, we assume it is always there */ status = acpi_get_handle(handle, "_STA", &dummy_handle); @@ -490,7 +491,7 @@ static int add_bridge(acpi_handle handle) /* check if this bridge has ejectable slots */ if (detect_ejectable_slots(handle) > 0) { dbg("found PCI host-bus bridge with hot-pluggable slots\n"); - add_host_bridge(handle); + add_host_bridge(root); } /* search P2P bridges under this host bridge */ @@ -588,9 +589,10 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; } -static void remove_bridge(acpi_handle handle) +static void remove_bridge(struct acpi_pci_root *root) { struct acpiphp_bridge *bridge; + acpi_handle handle = root->device->handle; /* cleanup p2p bridges under this host bridge in a depth-first manner */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index a54cf8e512ad..6906e6fb82ea 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -139,8 +139,8 @@ void acpi_pci_irq_disable (struct pci_dev *dev); struct acpi_pci_driver { struct list_head node; - int (*add)(acpi_handle handle); - void (*remove)(acpi_handle handle); + int (*add)(struct acpi_pci_root *root); + void (*remove)(struct acpi_pci_root *root); }; int acpi_pci_register_driver(struct acpi_pci_driver *driver); -- cgit v1.2.3 From 0f2bdfedcb8f1aaf54a0ab4934f33b3710692a19 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Sep 2012 16:03:58 +0900 Subject: PCI/ACPI: Use acpi_pci_root info rather than looking it up again This patch changes the function signature of walk_root_bridge(). We can omit _STA, _SEG, and _BBN evaluation by passing not acpi_handle but acpi_pci_root. Now that acpi_pci_slot_add() which is the only caller of walk_root_bridge() gets acpi_pci_root structure, changing signature of walk_root_bridge() is reasonable. [bhelgaas: changelog] Signed-off-by: Taku Izumi Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_slot.c | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 8051ffa7609d..d22585f21aeb 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -233,45 +233,20 @@ out: /* * walk_root_bridge - generic root bridge walker - * @handle: points to an acpi_pci_root + * @root: poiner of an acpi_pci_root * @user_function: user callback for slot objects * * Call user_function for all objects underneath this root bridge. * Walk p2p bridges underneath us and call user_function on those too. */ static int -walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function) +walk_root_bridge(struct acpi_pci_root *root, acpi_walk_callback user_function) { - int seg, bus; - unsigned long long tmp; acpi_status status; - acpi_handle dummy_handle; - struct pci_bus *pci_bus; + acpi_handle handle = root->device->handle; + struct pci_bus *pci_bus = root->bus; struct callback_args context; - /* If the bridge doesn't have _STA, we assume it is always there */ - status = acpi_get_handle(handle, "_STA", &dummy_handle); - if (ACPI_SUCCESS(status)) { - status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); - if (ACPI_FAILURE(status)) { - info("%s: _STA evaluation failure\n", __func__); - return 0; - } - if ((tmp & ACPI_STA_DEVICE_FUNCTIONING) == 0) - /* don't register this object */ - return 0; - } - - status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp); - seg = ACPI_SUCCESS(status) ? tmp : 0; - - status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp); - bus = ACPI_SUCCESS(status) ? tmp : 0; - - pci_bus = pci_find_bus(seg, bus); - if (!pci_bus) - return 0; - context.pci_bus = pci_bus; context.user_function = user_function; context.root_handle = handle; @@ -299,7 +274,7 @@ acpi_pci_slot_add(struct acpi_pci_root *root) { acpi_status status; - status = walk_root_bridge(root->device->handle, register_slot); + status = walk_root_bridge(root, register_slot); if (ACPI_FAILURE(status)) err("%s: register_slot failure - %d\n", __func__, status); -- cgit v1.2.3 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') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 2868a9ff6d07..e1bdcc700cbb 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.2.3 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') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index e1bdcc700cbb..13f9b5ba3354 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.2.3