{
        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;
        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);
        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);
 }
 
 
  * @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.
        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;
 };