From 6af8bef14d6fc9e4e52c83fd646412e9dedadd26 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Wed, 28 Sep 2011 19:40:53 -0400 Subject: 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 Cc: mjg@redhat.com Cc: bhelgaas@google.com Cc: linux-acpi@vger.kernel.org Signed-off-by: Jesse Barnes --- drivers/acpi/osl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index fa32f58..f31c5c5 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -80,7 +80,8 @@ static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_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 { resource_size_t start; -- cgit v1.1