Commit 6af8bef1 authored by Prarit Bhargava's avatar Prarit Bhargava Committed by Jesse Barnes

PCI hotplug: acpiphp: Prevent deadlock on PCI-to-PCI bridge remove

I originally submitted a patch to workaround this by pushing all Ejection
Requests and Device Checks onto the kacpi_hotplug queue.

http://marc.info/?l=linux-acpi&m=131678270930105&w=2

The patch is still insufficient in that Bus Checks also need to be added.

Rather than add all events, including non-PCI-hotplug events, to the
hotplug queue, mjg suggested that a better approach would be to modify
the acpiphp driver so only acpiphp events would be added to the
kacpi_hotplug queue.

It's a longer patch, but at least we maintain the benefit of having separate
queues in ACPI.  This, of course, is still only a workaround the problem.
As Bjorn and mjg pointed out, we have to refactor a lot of this code to do
the right thing but at this point it is a better to have this code working.

The acpi core places all events on the kacpi_notify queue.  When the acpiphp
driver is loaded and a PCI card with a PCI-to-PCI bridge is removed the
following call sequence occurs:

cleanup_p2p_bridge()
	    -> cleanup_bridge()
		    -> acpi_remove_notify_handler()
			    -> acpi_os_wait_events_complete()
				    -> flush_workqueue(kacpi_notify_wq)

which is the queue we are currently executing on and the process will hang.

Move all hotplug acpiphp events onto the kacpi_hotplug workqueue.  In
handle_hotplug_event_bridge() and handle_hotplug_event_func() we can simply
push the rest of the work onto the kacpi_hotplug queue and then avoid the
deadlock.
Signed-off-by: default avatarPrarit Bhargava <prarit@redhat.com>
Cc: mjg@redhat.com
Cc: bhelgaas@google.com
Cc: linux-acpi@vger.kernel.org
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 379021d5
...@@ -80,7 +80,8 @@ static acpi_osd_handler acpi_irq_handler; ...@@ -80,7 +80,8 @@ static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context; static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq; static struct workqueue_struct *kacpid_wq;
static struct workqueue_struct *kacpi_notify_wq; static struct workqueue_struct *kacpi_notify_wq;
static struct workqueue_struct *kacpi_hotplug_wq; struct workqueue_struct *kacpi_hotplug_wq;
EXPORT_SYMBOL(kacpi_hotplug_wq);
struct acpi_res_list { struct acpi_res_list {
resource_size_t start; resource_size_t start;
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include <linux/pci-acpi.h> #include <linux/pci-acpi.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/acpi.h>
#include "../pci.h" #include "../pci.h"
#include "acpiphp.h" #include "acpiphp.h"
...@@ -1149,15 +1150,35 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -1149,15 +1150,35 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK ; return AE_OK ;
} }
/** struct acpiphp_hp_work {
* handle_hotplug_event_bridge - handle ACPI event on bridges struct work_struct work;
* @handle: Notify()'ed acpi_handle acpi_handle handle;
* @type: Notify code u32 type;
* @context: pointer to acpiphp_bridge structure void *context;
* };
* Handles ACPI event notification on {host,p2p} bridges.
*/ static void alloc_acpiphp_hp_work(acpi_handle handle, u32 type,
static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context) 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; struct acpiphp_bridge *bridge;
char objname[64]; char objname[64];
...@@ -1165,11 +1186,18 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont ...@@ -1165,11 +1186,18 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
.pointer = objname }; .pointer = objname };
struct acpi_device *device; struct acpi_device *device;
int num_sub_bridges = 0; 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)) { if (acpi_bus_get_device(handle, &device)) {
/* This bridge must have just been physically inserted */ /* This bridge must have just been physically inserted */
handle_bridge_insertion(handle, type); handle_bridge_insertion(handle, type);
return; goto out;
} }
bridge = acpiphp_handle_to_bridge(handle); bridge = acpiphp_handle_to_bridge(handle);
...@@ -1180,7 +1208,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont ...@@ -1180,7 +1208,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
if (!bridge && !num_sub_bridges) { if (!bridge && !num_sub_bridges) {
err("cannot get bridge info\n"); err("cannot get bridge info\n");
return; goto out;
} }
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
...@@ -1241,22 +1269,49 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont ...@@ -1241,22 +1269,49 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
break; 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 * @handle: Notify()'ed acpi_handle
* @type: Notify code * @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; struct acpiphp_func *func;
char objname[64]; char objname[64];
struct acpi_buffer buffer = { .length = sizeof(objname), struct acpi_buffer buffer = { .length = sizeof(objname),
.pointer = 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); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
...@@ -1291,8 +1346,32 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex ...@@ -1291,8 +1346,32 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex
warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
break; 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 static acpi_status
find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
......
...@@ -189,6 +189,8 @@ void acpi_os_fixed_event_count(u32 fixed_event_number); ...@@ -189,6 +189,8 @@ void acpi_os_fixed_event_count(u32 fixed_event_number);
/* /*
* Threads and Scheduling * Threads and Scheduling
*/ */
extern struct workqueue_struct *kacpi_hotplug_wq;
acpi_thread_id acpi_os_get_thread_id(void); acpi_thread_id acpi_os_get_thread_id(void);
acpi_status acpi_status
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment