===================================================================
@@ -61,6 +61,12 @@ struct acpi_os_dpc {
int wait;
};
+struct acpi_os_barrier_work {
+ struct completion run;
+ struct completion exit;
+ struct work_struct work;
+};
+
#ifdef CONFIG_ACPI_CUSTOM_DSDT
#include CONFIG_ACPI_CUSTOM_DSDT_FILE
#endif
@@ -700,28 +706,15 @@ static void acpi_os_execute_deferred(str
{
struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
- if (dpc->wait)
- acpi_os_wait_events_complete(NULL);
+ if (dpc->wait) {
+ flush_workqueue(kacpid_wq);
+ flush_workqueue(kacpi_notify_wq);
+ }
dpc->function(dpc->context);
kfree(dpc);
}
-/*******************************************************************************
- *
- * FUNCTION: acpi_os_execute
- *
- * PARAMETERS: Type - Type of the callback
- * Function - Function to be executed
- * Context - Function parameters
- *
- * RETURN: Status
- *
- * DESCRIPTION: Depending on type, either queues function for deferred execution or
- * immediately executes function on a separate thread.
- *
- ******************************************************************************/
-
static acpi_status __acpi_os_execute(acpi_execute_type type,
acpi_osd_exec_callback function, void *context, int hp)
{
@@ -770,6 +763,20 @@ static acpi_status __acpi_os_execute(acp
return status;
}
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_os_execute
+ *
+ * PARAMETERS: Type - Type of the callback
+ * Function - Function to be executed
+ * Context - Function parameters
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Depending on type, either queues function for deferred execution or
+ * immediately executes function on a separate thread.
+ *
+ ******************************************************************************/
acpi_status acpi_os_execute(acpi_execute_type type,
acpi_osd_exec_callback function, void *context)
{
@@ -783,13 +790,77 @@ acpi_status acpi_os_hotplug_execute(acpi
return __acpi_os_execute(0, function, context, 1);
}
-void acpi_os_wait_events_complete(void *context)
+static void acpi_os_barrier_fn(struct work_struct *work)
{
- flush_workqueue(kacpid_wq);
- flush_workqueue(kacpi_notify_wq);
+ struct acpi_os_barrier_work *barrier;
+
+ barrier = container_of(work, struct acpi_os_barrier_work, work);
+ complete(&barrier->run);
+ wait_for_completion(&barrier->exit);
+ kfree(barrier);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_os_add_events_barrier
+ *
+ * PARAMETERS: type - Type of events to add the barrier for
+ *
+ * RETURN: Context to be passed to acpi_os_remove_events_barrier() or NULL
+ * on failure.
+ *
+ * DESCRIPTION: Ensure that all of the events of given type either have been
+ * handled before we continue running or will not be handled until
+ * acpi_os_remove_events_barrier() is run.
+ *
+ ******************************************************************************/
+void *acpi_os_add_events_barrier(acpi_execute_type type)
+{
+ struct acpi_os_barrier_work *barrier;
+ struct workqueue_struct *queue;
+ int ret;
+
+ barrier = kmalloc(sizeof(*barrier), GFP_KERNEL);
+ if (!barrier)
+ return NULL;
+
+ init_completion(&barrier->run);
+ init_completion(&barrier->exit);
+ INIT_WORK(&barrier->work, acpi_os_barrier_fn);
+ queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
+ ret = queue_work(queue, &barrier->work);
+ if (!ret) {
+ printk(KERN_ERR PREFIX "queue_work() failed!\n");
+ kfree(barrier);
+ return NULL;
+ }
+
+ wait_for_completion(&barrier->run);
+
+ return barrier;
}
+EXPORT_SYMBOL(acpi_os_add_events_barrier);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_os_remove_events_barrier
+ *
+ * PARAMETERS: context - Information needed to remove the barrier
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Using the context information remove an events barrier added by
+ * acpi_os_add_events_barrier().
+ *
+ ******************************************************************************/
+void acpi_os_remove_events_barrier(void *context)
+{
+ struct acpi_os_barrier_work *barrier = context;
-EXPORT_SYMBOL(acpi_os_wait_events_complete);
+ if (barrier)
+ complete(&barrier->exit);
+}
+EXPORT_SYMBOL(acpi_os_remove_events_barrier);
/*
* Allocate the memory for a spinlock and initialize it.
===================================================================
@@ -194,7 +194,8 @@ acpi_os_execute(acpi_execute_type type,
acpi_status
acpi_os_hotplug_execute(acpi_osd_exec_callback function, void *context);
-void acpi_os_wait_events_complete(void *context);
+void *acpi_os_add_events_barrier(acpi_execute_type type);
+void acpi_os_remove_events_barrier(void *context);
void acpi_os_sleep(acpi_integer milliseconds);
===================================================================
@@ -497,6 +497,7 @@ acpi_remove_notify_handler(acpi_handle d
union acpi_operand_object *notify_obj;
union acpi_operand_object *obj_desc;
struct acpi_namespace_node *node;
+ void *events_barrier;
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
@@ -511,11 +512,16 @@ acpi_remove_notify_handler(acpi_handle d
/* Make sure all deferred tasks are completed */
- acpi_os_wait_events_complete(NULL);
+
+ events_barrier = acpi_os_add_events_barrier(OSL_NOTIFY_HANDLER);
+ if (!events_barrier) {
+ status = AE_ERROR;
+ goto exit;
+ }
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
- goto exit;
+ goto release_events;
}
/* Convert and validate the device handle */
@@ -653,6 +659,8 @@ acpi_remove_notify_handler(acpi_handle d
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ release_events:
+ acpi_os_remove_events_barrier(events_barrier);
exit:
if (ACPI_FAILURE(status))
ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler"));
@@ -774,6 +782,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_
{
struct acpi_gpe_event_info *gpe_event_info;
struct acpi_handler_info *handler;
+ void *events_barrier;
acpi_status status;
acpi_cpu_flags flags;
@@ -785,9 +794,16 @@ acpi_remove_gpe_handler(acpi_handle gpe_
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
+ /* Make sure all deferred tasks are completed */
+
+ events_barrier = acpi_os_add_events_barrier(OSL_GPE_HANDLER);
+ if (!events_barrier) {
+ return_ACPI_STATUS(AE_ERROR);
+ }
+
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto release_events;
}
/* Ensure that we have a valid GPE number */
@@ -813,15 +829,6 @@ acpi_remove_gpe_handler(acpi_handle gpe_
goto unlock_and_exit;
}
- /* Make sure all deferred tasks are completed */
-
- (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
- acpi_os_wait_events_complete(NULL);
- status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
/* Remove the handler */
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
@@ -842,6 +849,8 @@ acpi_remove_gpe_handler(acpi_handle gpe_
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ release_events:
+ acpi_os_remove_events_barrier(events_barrier);
return_ACPI_STATUS(status);
}