@@ -27,7 +27,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/pci.h>
@@ -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,47 +83,46 @@ 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);
- n++;
- }
+ if (driver->add)
+ list_for_each_entry(root, &acpi_pci_roots, node) {
+ driver->add(root);
+ 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);
+ if (driver->remove)
+ list_for_each_entry(root, &acpi_pci_roots, node)
+ driver->remove(root);
+ 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)
{
struct acpi_pci_root *root;
-
+ struct acpi_handle *handle = NULL;
+
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;
+ }
+ return handle;
+}
EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
/**
@@ -459,7 +460,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
printk(KERN_ERR PREFIX "can't evaluate _SEG\n");
result = -ENODEV;
- goto end;
+ goto out_free;
}
/* Check _CRS first, then _BBN. If no _BBN, default to zero. */
@@ -484,7 +485,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
else {
printk(KERN_ERR PREFIX "can't evaluate _BBN\n");
result = -ENODEV;
- goto end;
+ goto out_free;
}
}
@@ -508,7 +509,7 @@ 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);
printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n",
@@ -528,7 +529,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;
}
/*
@@ -538,7 +539,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
@@ -621,11 +622,14 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true);
+ mutex_unlock(&acpi_pci_root_lock);
+
return 0;
-end:
- if (!list_empty(&root->node))
- list_del(&root->node);
+out_del_root:
+ list_del(&root->node);
+ mutex_unlock(&acpi_pci_root_lock);
+out_free:
kfree(root);
return result;
}
@@ -635,11 +639,14 @@ 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(root);
pci_bus_add_devices(root->bus);
+ mutex_unlock(&acpi_pci_root_lock);
+
return 0;
}
@@ -650,6 +657,8 @@ 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);
+
/* that root bus could be removed already */
if (!pci_find_bus(root->segment, root->secondary.start)) {
dev_printk(KERN_DEBUG, &device->dev,
@@ -677,6 +686,7 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type)
out:
list_del(&root->node);
+ mutex_unlock(&acpi_pci_root_lock);
kfree(root);
return 0;