summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/acpi_memhotplug.c56
-rw-r--r--drivers/acpi/container.c12
-rw-r--r--drivers/acpi/dock.c19
-rw-r--r--drivers/acpi/processor_driver.c24
-rw-r--r--drivers/acpi/scan.c69
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c6
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c5
-rw-r--r--include/acpi/acpi_bus.h3
8 files changed, 139 insertions, 55 deletions
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 94c823b2513..034d3e72aa9 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -153,14 +153,16 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
return 0;
}
-static int
-acpi_memory_get_device(acpi_handle handle,
- struct acpi_memory_device **mem_device)
+static int acpi_memory_get_device(acpi_handle handle,
+ struct acpi_memory_device **mem_device)
{
struct acpi_device *device = NULL;
- int result;
+ int result = 0;
- if (!acpi_bus_get_device(handle, &device) && device)
+ acpi_scan_lock_acquire();
+
+ acpi_bus_get_device(handle, &device);
+ if (device)
goto end;
/*
@@ -169,23 +171,28 @@ acpi_memory_get_device(acpi_handle handle,
*/
result = acpi_bus_scan(handle);
if (result) {
- acpi_handle_warn(handle, "Cannot add acpi bus\n");
- return -EINVAL;
+ acpi_handle_warn(handle, "ACPI namespace scan failed\n");
+ result = -EINVAL;
+ goto out;
}
result = acpi_bus_get_device(handle, &device);
if (result) {
acpi_handle_warn(handle, "Missing device object\n");
- return -EINVAL;
+ result = -EINVAL;
+ goto out;
}
- end:
+ end:
*mem_device = acpi_driver_data(device);
if (!(*mem_device)) {
dev_err(&device->dev, "driver data not found\n");
- return -ENODEV;
+ result = -ENODEV;
+ goto out;
}
- return 0;
+ out:
+ acpi_scan_lock_release();
+ return result;
}
static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
@@ -305,6 +312,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
struct acpi_device *device;
struct acpi_eject_event *ej_event = NULL;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+ acpi_status status;
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
@@ -327,29 +335,40 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"\nReceived EJECT REQUEST notification for device\n"));
+ status = AE_ERROR;
+ acpi_scan_lock_acquire();
+
if (acpi_bus_get_device(handle, &device)) {
acpi_handle_err(handle, "Device doesn't exist\n");
- break;
+ goto unlock;
}
mem_device = acpi_driver_data(device);
if (!mem_device) {
acpi_handle_err(handle, "Driver Data is NULL\n");
- break;
+ goto unlock;
}
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
if (!ej_event) {
pr_err(PREFIX "No memory, dropping EJECT\n");
- break;
+ goto unlock;
}
+ get_device(&device->dev);
ej_event->device = device;
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
- acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
- (void *)ej_event);
+ /* The eject is carried out asynchronously. */
+ status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
+ ej_event);
+ if (ACPI_FAILURE(status)) {
+ put_device(&device->dev);
+ kfree(ej_event);
+ }
- /* eject is performed asynchronously */
- return;
+ unlock:
+ acpi_scan_lock_release();
+ if (ACPI_SUCCESS(status))
+ return;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
@@ -360,7 +379,6 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
- return;
}
static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 4cc2937cc02..5523ba7d764 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -88,6 +88,8 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
acpi_status status;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+ acpi_scan_lock_acquire();
+
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* Fall through */
@@ -103,7 +105,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
/* device exist and this is a remove request */
device->flags.eject_pending = 1;
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
- return;
+ goto out;
}
break;
}
@@ -130,18 +132,20 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
if (!acpi_bus_get_device(handle, &device) && device) {
device->flags.eject_pending = 1;
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
- return;
+ goto out;
}
break;
default:
/* non-hotplug event; possibly handled by other handler */
- return;
+ goto out;
}
/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
- return;
+
+ out:
+ acpi_scan_lock_release();
}
static bool is_container(acpi_handle handle)
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 68d720af71e..4fdea381ef2 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -744,7 +744,9 @@ static void acpi_dock_deferred_cb(void *context)
{
struct dock_data *data = context;
+ acpi_scan_lock_acquire();
dock_notify(data->handle, data->event, data->ds);
+ acpi_scan_lock_release();
kfree(data);
}
@@ -757,20 +759,31 @@ static int acpi_dock_notifier_call(struct notifier_block *this,
if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
&& event != ACPI_NOTIFY_EJECT_REQUEST)
return 0;
+
+ acpi_scan_lock_acquire();
+
list_for_each_entry(dock_station, &dock_stations, sibling) {
if (dock_station->handle == handle) {
struct dock_data *dd;
+ acpi_status status;
dd = kmalloc(sizeof(*dd), GFP_KERNEL);
if (!dd)
- return 0;
+ break;
+
dd->handle = handle;
dd->event = event;
dd->ds = dock_station;
- acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
- return 0 ;
+ status = acpi_os_hotplug_execute(acpi_dock_deferred_cb,
+ dd);
+ if (ACPI_FAILURE(status))
+ kfree(dd);
+
+ break;
}
}
+
+ acpi_scan_lock_release();
return 0;
}
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index c5d2fd85dbe..cbf1f122666 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -683,8 +683,11 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
struct acpi_device *device = NULL;
struct acpi_eject_event *ej_event = NULL;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+ acpi_status status;
int result;
+ acpi_scan_lock_acquire();
+
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
@@ -733,25 +736,32 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
break;
}
+ get_device(&device->dev);
ej_event->device = device;
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
- acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
- (void *)ej_event);
-
- /* eject is performed asynchronously */
- return;
+ /* The eject is carried out asynchronously. */
+ status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
+ ej_event);
+ if (ACPI_FAILURE(status)) {
+ put_device(&device->dev);
+ kfree(ej_event);
+ break;
+ }
+ goto out;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
/* non-hotplug event; possibly handled by other handler */
- return;
+ goto out;
}
/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
- return;
+
+ out:
+ acpi_scan_lock_release();
}
static acpi_status is_processor_device(acpi_handle handle)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index c7676ee8eca..d16a94ef0ba 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -42,6 +42,18 @@ struct acpi_device_bus_id{
struct list_head node;
};
+void acpi_scan_lock_acquire(void)
+{
+ mutex_lock(&acpi_scan_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_scan_lock_acquire);
+
+void acpi_scan_lock_release(void)
+{
+ mutex_unlock(&acpi_scan_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_scan_lock_release);
+
int acpi_scan_add_handler(struct acpi_scan_handler *handler)
{
if (!handler || !handler->attach)
@@ -95,8 +107,6 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
}
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
-static void __acpi_bus_trim(struct acpi_device *start);
-
/**
* acpi_bus_hot_remove_device: hot-remove a device and its children
* @context: struct acpi_eject_event pointer (freed in this func)
@@ -107,7 +117,7 @@ static void __acpi_bus_trim(struct acpi_device *start);
*/
void acpi_bus_hot_remove_device(void *context)
{
- struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context;
+ struct acpi_eject_event *ej_event = context;
struct acpi_device *device = ej_event->device;
acpi_handle handle = device->handle;
acpi_handle temp;
@@ -118,11 +128,19 @@ void acpi_bus_hot_remove_device(void *context)
mutex_lock(&acpi_scan_lock);
+ /* If there is no handle, the device node has been unregistered. */
+ if (!device->handle) {
+ dev_dbg(&device->dev, "ACPI handle missing\n");
+ put_device(&device->dev);
+ goto out;
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Hot-removing device %s...\n", dev_name(&device->dev)));
- __acpi_bus_trim(device);
- /* Device node has been released. */
+ acpi_bus_trim(device);
+ /* Device node has been unregistered. */
+ put_device(&device->dev);
device = NULL;
if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
@@ -151,6 +169,7 @@ void acpi_bus_hot_remove_device(void *context)
ost_code, NULL);
}
+ out:
mutex_unlock(&acpi_scan_lock);
kfree(context);
return;
@@ -212,6 +231,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
goto err;
}
+ get_device(&acpi_device->dev);
ej_event->device = acpi_device;
if (acpi_device->flags.eject_pending) {
/* event originated from ACPI eject notification */
@@ -224,7 +244,11 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
}
- acpi_os_hotplug_execute(acpi_bus_hot_remove_device, (void *)ej_event);
+ status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
+ if (ACPI_FAILURE(status)) {
+ put_device(&acpi_device->dev);
+ kfree(ej_event);
+ }
err:
return ret;
}
@@ -779,6 +803,7 @@ static void acpi_device_unregister(struct acpi_device *device)
* no more references.
*/
acpi_device_set_power(device, ACPI_STATE_D3_COLD);
+ device->handle = NULL;
put_device(&device->dev);
}
@@ -1623,14 +1648,14 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
* there has been a real error. There just have been no suitable ACPI objects
* in the table trunk from which the kernel could create a device and add an
* appropriate driver.
+ *
+ * Must be called under acpi_scan_lock.
*/
int acpi_bus_scan(acpi_handle handle)
{
void *device = NULL;
int error = 0;
- mutex_lock(&acpi_scan_lock);
-
if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device)))
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
acpi_bus_check_add, NULL, NULL, &device);
@@ -1641,7 +1666,6 @@ int acpi_bus_scan(acpi_handle handle)
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
acpi_bus_device_attach, NULL, NULL, NULL);
- mutex_unlock(&acpi_scan_lock);
return error;
}
EXPORT_SYMBOL(acpi_bus_scan);
@@ -1678,7 +1702,13 @@ static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
return AE_OK;
}
-static void __acpi_bus_trim(struct acpi_device *start)
+/**
+ * acpi_bus_trim - Remove ACPI device node and all of its descendants
+ * @start: Root of the ACPI device nodes subtree to remove.
+ *
+ * Must be called under acpi_scan_lock.
+ */
+void acpi_bus_trim(struct acpi_device *start)
{
/*
* Execute acpi_bus_device_detach() as a post-order callback to detach
@@ -1695,13 +1725,6 @@ static void __acpi_bus_trim(struct acpi_device *start)
acpi_bus_remove, NULL, NULL);
acpi_bus_remove(start->handle, 0, NULL, NULL);
}
-
-void acpi_bus_trim(struct acpi_device *start)
-{
- mutex_lock(&acpi_scan_lock);
- __acpi_bus_trim(start);
- mutex_unlock(&acpi_scan_lock);
-}
EXPORT_SYMBOL_GPL(acpi_bus_trim);
static int acpi_bus_scan_fixed(void)
@@ -1758,23 +1781,27 @@ int __init acpi_scan_init(void)
acpi_csrt_init();
acpi_container_init();
+ mutex_lock(&acpi_scan_lock);
/*
* Enumerate devices in the ACPI namespace.
*/
result = acpi_bus_scan(ACPI_ROOT_OBJECT);
if (result)
- return result;
+ goto out;
result = acpi_bus_get_device(ACPI_ROOT_OBJECT, &acpi_root);
if (result)
- return result;
+ goto out;
result = acpi_bus_scan_fixed();
if (result) {
acpi_device_unregister(acpi_root);
- return result;
+ goto out;
}
acpi_update_all_gpes();
- return 0;
+
+ out:
+ mutex_unlock(&acpi_scan_lock);
+ return result;
}
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index d1a6f4a25da..a951c22921d 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -1218,6 +1218,8 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
handle = hp_work->handle;
type = hp_work->type;
+ acpi_scan_lock_acquire();
+
if (acpi_bus_get_device(handle, &device)) {
/* This bridge must have just been physically inserted */
handle_bridge_insertion(handle, type);
@@ -1295,6 +1297,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
}
out:
+ acpi_scan_lock_release();
kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
}
@@ -1341,6 +1344,8 @@ static void _handle_hotplug_event_func(struct work_struct *work)
func = (struct acpiphp_func *)context;
+ acpi_scan_lock_acquire();
+
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* bus re-enumerate */
@@ -1371,6 +1376,7 @@ static void _handle_hotplug_event_func(struct work_struct *work)
break;
}
+ acpi_scan_lock_release();
kfree(hp_work); /* allocated in handle_hotplug_event_func */
}
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index ae606b3e991..574421bc2fa 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -425,6 +425,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
pdevice = NULL;
}
+ acpi_scan_lock_acquire();
/*
* Walk the rootbus node's immediate children looking for
* the slot's device node(s). There can be more than
@@ -458,6 +459,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
}
}
}
+ acpi_scan_lock_release();
}
/* Call the driver for the new device */
@@ -508,6 +510,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
/* Get the rootbus node pointer */
phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+ acpi_scan_lock_acquire();
/*
* Walk the rootbus node's immediate children looking for
* the slot's device node(s). There can be more than
@@ -538,7 +541,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
acpi_bus_trim(device);
}
}
-
+ acpi_scan_lock_release();
}
/* Free the SN resources assigned to the Linux device.*/
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 41850cb2173..227ba7dc293 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -395,6 +395,9 @@ int acpi_bus_receive_event(struct acpi_bus_event *event);
static inline int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
{ return 0; }
#endif
+
+void acpi_scan_lock_acquire(void);
+void acpi_scan_lock_release(void);
int acpi_scan_add_handler(struct acpi_scan_handler *handler);
int acpi_bus_register_driver(struct acpi_driver *driver);
void acpi_bus_unregister_driver(struct acpi_driver *driver);