#include <linux/pci-acpi.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/acpi.h>
 
 #include "../pci.h"
 #include "acpiphp.h"
        return AE_OK ;
 }
 
-/**
- * handle_hotplug_event_bridge - handle ACPI event on bridges
- * @handle: Notify()'ed acpi_handle
- * @type: Notify code
- * @context: pointer to acpiphp_bridge structure
- *
- * Handles ACPI event notification on {host,p2p} bridges.
- */
-static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context)
+struct acpiphp_hp_work {
+       struct work_struct work;
+       acpi_handle handle;
+       u32 type;
+       void *context;
+};
+
+static void alloc_acpiphp_hp_work(acpi_handle handle, u32 type,
+                                 void *context,
+                                 void (*func)(struct work_struct *work))
+{
+       struct acpiphp_hp_work *hp_work;
+       int ret;
+
+       hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
+       if (!hp_work)
+               return;
+
+       hp_work->handle = handle;
+       hp_work->type = type;
+       hp_work->context = context;
+
+       INIT_WORK(&hp_work->work, func);
+       ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
+       if (!ret)
+               kfree(hp_work);
+}
+
+static void _handle_hotplug_event_bridge(struct work_struct *work)
 {
        struct acpiphp_bridge *bridge;
        char objname[64];
                                      .pointer = objname };
        struct acpi_device *device;
        int num_sub_bridges = 0;
+       struct acpiphp_hp_work *hp_work;
+       acpi_handle handle;
+       u32 type;
+
+       hp_work = container_of(work, struct acpiphp_hp_work, work);
+       handle = hp_work->handle;
+       type = hp_work->type;
 
        if (acpi_bus_get_device(handle, &device)) {
                /* This bridge must have just been physically inserted */
                handle_bridge_insertion(handle, type);
-               return;
+               goto out;
        }
 
        bridge = acpiphp_handle_to_bridge(handle);
 
        if (!bridge && !num_sub_bridges) {
                err("cannot get bridge info\n");
-               return;
+               goto out;
        }
 
        acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
                warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
                break;
        }
+
+out:
+       kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
 }
 
 /**
- * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
+ * handle_hotplug_event_bridge - handle ACPI event on bridges
  * @handle: Notify()'ed acpi_handle
  * @type: Notify code
- * @context: pointer to acpiphp_func structure
+ * @context: pointer to acpiphp_bridge structure
  *
- * Handles ACPI event notification on slots.
+ * Handles ACPI event notification on {host,p2p} bridges.
  */
-static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context)
+static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
+                                       void *context)
+{
+       /*
+        * Currently the code adds all hotplug events to the kacpid_wq
+        * queue when it should add hotplug events to the kacpi_hotplug_wq.
+        * The proper way to fix this is to reorganize the code so that
+        * drivers (dock, etc.) do not call acpi_os_execute(), etc.
+        * For now just re-add this work to the kacpi_hotplug_wq so we
+        * don't deadlock on hotplug actions.
+        */
+       alloc_acpiphp_hp_work(handle, type, context,
+                             _handle_hotplug_event_bridge);
+}
+
+static void _handle_hotplug_event_func(struct work_struct *work)
 {
        struct acpiphp_func *func;
        char objname[64];
        struct acpi_buffer buffer = { .length = sizeof(objname),
                                      .pointer = objname };
+       struct acpiphp_hp_work *hp_work;
+       acpi_handle handle;
+       u32 type;
+       void *context;
+
+       hp_work = container_of(work, struct acpiphp_hp_work, work);
+       handle = hp_work->handle;
+       type = hp_work->type;
+       context = hp_work->context;
 
        acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
                warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
                break;
        }
+
+       kfree(hp_work); /* allocated in handle_hotplug_event_func */
 }
 
+/**
+ * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
+ * @handle: Notify()'ed acpi_handle
+ * @type: Notify code
+ * @context: pointer to acpiphp_func structure
+ *
+ * Handles ACPI event notification on slots.
+ */
+static void handle_hotplug_event_func(acpi_handle handle, u32 type,
+                                     void *context)
+{
+       /*
+        * Currently the code adds all hotplug events to the kacpid_wq
+        * queue when it should add hotplug events to the kacpi_hotplug_wq.
+        * The proper way to fix this is to reorganize the code so that
+        * drivers (dock, etc.) do not call acpi_os_execute(), etc.
+        * For now just re-add this work to the kacpi_hotplug_wq so we
+        * don't deadlock on hotplug actions.
+        */
+       alloc_acpiphp_hp_work(handle, type, context,
+                             _handle_hotplug_event_func);
+}
 
 static acpi_status
 find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)