aboutsummaryrefslogtreecommitdiff
path: root/drivers/pci/hotplug/shpchp.h
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2013-01-11 12:21:15 -0700
committerBjorn Helgaas <bhelgaas@google.com>2013-01-14 10:23:22 -0700
commitf652e7d2916fe2fcf9e7d709aa5b7476b431e2dd (patch)
tree3de39a91ba274a307e11face7f5bbb8a3f7244b5 /drivers/pci/hotplug/shpchp.h
parentd347e75847c1fb299c97736638f45e6ea39702d4 (diff)
PCI: shpchp: Use per-slot workqueues to avoid deadlock
When we have an SHPC-capable bridge with a second SHPC-capable bridge below it, pushing the upstream bridge's attention button causes a deadlock. The deadlock happens because we use the shpchp_wq workqueue to run shpchp_pushbutton_thread(), which uses shpchp_disable_slot() to remove devices below the upstream bridge. When we remove the downstream bridge, we call shpc_remove(), the shpchp driver's .remove() method. That calls flush_workqueue(shpchp_wq), which deadlocks because the shpchp_pushbutton_thread() work item is still running. This patch avoids the deadlock by creating a workqueue for every slot and removing the single shared workqueue. Here's the call path that leads to the deadlock: shpchp_queue_pushbutton_work queue_work(shpchp_wq) # shpchp_pushbutton_thread ... shpchp_pushbutton_thread shpchp_disable_slot remove_board shpchp_unconfigure_device pci_stop_and_remove_bus_device ... shpc_remove # shpchp driver .remove method hpc_release_ctlr cleanup_slots flush_workqueue(shpchp_wq) This change is based on code inspection, since we don't have hardware with this topology. Based-on-patch-by: Yijing Wang <wangyijing@huawei.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> CC: stable@vger.kernel.org
Diffstat (limited to 'drivers/pci/hotplug/shpchp.h')
-rw-r--r--drivers/pci/hotplug/shpchp.h2
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 1b69d955a31..b849f995075 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -46,7 +46,6 @@
extern bool shpchp_poll_mode;
extern int shpchp_poll_time;
extern bool shpchp_debug;
-extern struct workqueue_struct *shpchp_wq;
#define dbg(format, arg...) \
do { \
@@ -90,6 +89,7 @@ struct slot {
struct list_head slot_list;
struct delayed_work work; /* work for button event */
struct mutex lock;
+ struct workqueue_struct *wq;
u8 hp_slot;
};