Commit bdccf295 authored by Mika Westerberg's avatar Mika Westerberg Committed by Greg Kroah-Hartman

thunderbolt: Do not touch the hardware if the NHI is gone on resume

On PCs the NHI host controller is only present when there is a device
connected. When the last device is disconnected the host controller will
dissappear shortly (within 10s). Now if that happens when we are
suspended we should not try to touch the hardware anymore, so add a flag
for this and check it before we re-enable rings.
Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: default avatarYehezkel Bernat <yehezkel.bernat@intel.com>
Reviewed-by: default avatarMichael Jamet <michael.jamet@intel.com>
Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarAndreas Noever <andreas.noever@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3e136768
...@@ -403,6 +403,8 @@ void ring_start(struct tb_ring *ring) ...@@ -403,6 +403,8 @@ void ring_start(struct tb_ring *ring)
{ {
mutex_lock(&ring->nhi->lock); mutex_lock(&ring->nhi->lock);
mutex_lock(&ring->lock); mutex_lock(&ring->lock);
if (ring->nhi->going_away)
goto err;
if (ring->running) { if (ring->running) {
dev_WARN(&ring->nhi->pdev->dev, "ring already started\n"); dev_WARN(&ring->nhi->pdev->dev, "ring already started\n");
goto err; goto err;
...@@ -449,6 +451,8 @@ void ring_stop(struct tb_ring *ring) ...@@ -449,6 +451,8 @@ void ring_stop(struct tb_ring *ring)
mutex_lock(&ring->lock); mutex_lock(&ring->lock);
dev_info(&ring->nhi->pdev->dev, "stopping %s %d\n", dev_info(&ring->nhi->pdev->dev, "stopping %s %d\n",
RING_TYPE(ring), ring->hop); RING_TYPE(ring), ring->hop);
if (ring->nhi->going_away)
goto err;
if (!ring->running) { if (!ring->running) {
dev_WARN(&ring->nhi->pdev->dev, "%s %d already stopped\n", dev_WARN(&ring->nhi->pdev->dev, "%s %d already stopped\n",
RING_TYPE(ring), ring->hop); RING_TYPE(ring), ring->hop);
...@@ -653,6 +657,14 @@ static int nhi_resume_noirq(struct device *dev) ...@@ -653,6 +657,14 @@ static int nhi_resume_noirq(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct tb *tb = pci_get_drvdata(pdev); struct tb *tb = pci_get_drvdata(pdev);
/*
* Check that the device is still there. It may be that the user
* unplugged last device which causes the host controller to go
* away on PCs.
*/
if (!pci_device_is_present(pdev))
tb->nhi->going_away = true;
return tb_domain_resume_noirq(tb); return tb_domain_resume_noirq(tb);
} }
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
* @tx_rings: All Tx rings available on this host controller * @tx_rings: All Tx rings available on this host controller
* @rx_rings: All Rx rings available on this host controller * @rx_rings: All Rx rings available on this host controller
* @msix_ida: Used to allocate MSI-X vectors for rings * @msix_ida: Used to allocate MSI-X vectors for rings
* @going_away: The host controller device is about to disappear so when
* this flag is set, avoid touching the hardware anymore.
* @interrupt_work: Work scheduled to handle ring interrupt when no * @interrupt_work: Work scheduled to handle ring interrupt when no
* MSI-X is used. * MSI-X is used.
* @hop_count: Number of rings (end point hops) supported by NHI. * @hop_count: Number of rings (end point hops) supported by NHI.
...@@ -31,6 +33,7 @@ struct tb_nhi { ...@@ -31,6 +33,7 @@ struct tb_nhi {
struct tb_ring **tx_rings; struct tb_ring **tx_rings;
struct tb_ring **rx_rings; struct tb_ring **rx_rings;
struct ida msix_ida; struct ida msix_ida;
bool going_away;
struct work_struct interrupt_work; struct work_struct interrupt_work;
u32 hop_count; u32 hop_count;
}; };
......
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