diff options
author | Prarit Bhargava <prarit@redhat.com> | 2011-09-28 19:40:53 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2011-10-14 12:05:31 -0400 |
commit | 6af8bef14d6fc9e4e52c83fd646412e9dedadd26 (patch) | |
tree | a1ddb0962fe8d5704cff9f3627322eb2fe0fa479 /drivers/acpi | |
parent | 379021d5c0899fcf9410cae4ca7a59a5a94ca769 (diff) |
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: Prarit Bhargava <prarit@redhat.com>
Cc: mjg@redhat.com
Cc: bhelgaas@google.com
Cc: linux-acpi@vger.kernel.org
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/osl.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index fa32f584229f..f31c5c5f1b7e 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -80,7 +80,8 @@ static acpi_osd_handler acpi_irq_handler; | |||
80 | static void *acpi_irq_context; | 80 | static void *acpi_irq_context; |
81 | static struct workqueue_struct *kacpid_wq; | 81 | static struct workqueue_struct *kacpid_wq; |
82 | static struct workqueue_struct *kacpi_notify_wq; | 82 | static struct workqueue_struct *kacpi_notify_wq; |
83 | static struct workqueue_struct *kacpi_hotplug_wq; | 83 | struct workqueue_struct *kacpi_hotplug_wq; |
84 | EXPORT_SYMBOL(kacpi_hotplug_wq); | ||
84 | 85 | ||
85 | struct acpi_res_list { | 86 | struct acpi_res_list { |
86 | resource_size_t start; | 87 | resource_size_t start; |