summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/thunderbolt/nhi.c12
-rw-r--r--drivers/thunderbolt/nhi.h3
2 files changed, 15 insertions, 0 deletions
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index c358c074f925..14311535661d 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -403,6 +403,8 @@ void ring_start(struct tb_ring *ring)
{
mutex_lock(&ring->nhi->lock);
mutex_lock(&ring->lock);
+ if (ring->nhi->going_away)
+ goto err;
if (ring->running) {
dev_WARN(&ring->nhi->pdev->dev, "ring already started\n");
goto err;
@@ -449,6 +451,8 @@ void ring_stop(struct tb_ring *ring)
mutex_lock(&ring->lock);
dev_info(&ring->nhi->pdev->dev, "stopping %s %d\n",
RING_TYPE(ring), ring->hop);
+ if (ring->nhi->going_away)
+ goto err;
if (!ring->running) {
dev_WARN(&ring->nhi->pdev->dev, "%s %d already stopped\n",
RING_TYPE(ring), ring->hop);
@@ -653,6 +657,14 @@ static int nhi_resume_noirq(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);
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);
}
diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h
index 446ff6dac91d..953864ae0ab3 100644
--- a/drivers/thunderbolt/nhi.h
+++ b/drivers/thunderbolt/nhi.h
@@ -20,6 +20,8 @@
* @tx_rings: All Tx 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
+ * @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
* MSI-X is used.
* @hop_count: Number of rings (end point hops) supported by NHI.
@@ -31,6 +33,7 @@ struct tb_nhi {
struct tb_ring **tx_rings;
struct tb_ring **rx_rings;
struct ida msix_ida;
+ bool going_away;
struct work_struct interrupt_work;
u32 hop_count;
};