Yijing Wang c2be6f93b3 PCI: pciehp: Use per-slot workqueues to avoid deadlock
When we have a hotplug-capable PCIe port with a second hotplug-capable
PCIe port below it, removing the device below the upstream port causes
a deadlock.

The deadlock happens because we use the pciehp_wq workqueue to run
pciehp_power_thread(), which uses pciehp_disable_slot() to remove devices
below the upstream port.  When we remove the downstream PCIe port, we call
pciehp_remove(), the pciehp driver's .remove() method.  That calls
flush_workqueue(pciehp_wq), which deadlocks because the
pciehp_power_thread() work item is still running.

This patch avoids the deadlock by creating a workqueue for every PCIe port
and removing the single shared workqueue.

Here's the call path that leads to the deadlock:

  pciehp_queue_pushbutton_work
    queue_work(pciehp_wq)                   # queue pciehp_power_thread
    ...

  pciehp_power_thread
    pciehp_disable_slot
      remove_board
	pciehp_unconfigure_device
	  pci_stop_and_remove_bus_device
	    ...
	      pciehp_remove                 # pciehp driver .remove method
		pciehp_release_ctrl
		  pcie_cleanup_slot
		    flush_workqueue(pciehp_wq)

This is fairly urgent because it can be caused by simply unplugging a
Thunderbolt adapter, as reported by Daniel below.

[bhelgaas: changelog]
Reference: http://lkml.kernel.org/r/CAMVG2ssiRgcTD1bej2tkUUfsWmpL5eNtPcNif9va2-Gzb2u8nQ@mail.gmail.com
Reported-and-tested-by: Daniel J Blueman <daniel@quora.org>
Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
CC: stable@vger.kernel.org
2013-01-12 13:56:33 -07:00
..
2012-12-15 12:37:18 -08:00
2012-12-19 12:47:41 -08:00
2012-12-19 12:47:41 -08:00
2012-12-12 12:05:15 -08:00
2012-12-07 23:13:36 +01:00
2012-12-17 17:15:13 -08:00
2012-12-20 10:07:25 -08:00
2012-12-11 14:08:47 -08:00
2012-12-18 15:19:06 +10:30
2012-12-20 07:21:54 -08:00
2012-12-12 11:45:16 -08:00
2012-12-17 17:15:14 -08:00
2012-12-11 13:13:55 -08:00
2012-12-19 08:19:07 -08:00
2012-12-11 13:13:55 -08:00
2012-12-12 12:05:15 -08:00
2012-12-16 17:39:14 -08:00