Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec...
[linux-2.6-block.git] / drivers / thunderbolt / switch.c
index 52ff854f0d6c10898d060b78a0b8c13212f8c192..cd96994dc0947137672d4b82a3d017e1cd1c8520 100644 (file)
@@ -863,6 +863,30 @@ static ssize_t key_store(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR(key, 0600, key_show, key_store);
 
+static void nvm_authenticate_start(struct tb_switch *sw)
+{
+       struct pci_dev *root_port;
+
+       /*
+        * During host router NVM upgrade we should not allow root port to
+        * go into D3cold because some root ports cannot trigger PME
+        * itself. To be on the safe side keep the root port in D0 during
+        * the whole upgrade process.
+        */
+       root_port = pci_find_pcie_root_port(sw->tb->nhi->pdev);
+       if (root_port)
+               pm_runtime_get_noresume(&root_port->dev);
+}
+
+static void nvm_authenticate_complete(struct tb_switch *sw)
+{
+       struct pci_dev *root_port;
+
+       root_port = pci_find_pcie_root_port(sw->tb->nhi->pdev);
+       if (root_port)
+               pm_runtime_put(&root_port->dev);
+}
+
 static ssize_t nvm_authenticate_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
@@ -912,10 +936,18 @@ static ssize_t nvm_authenticate_store(struct device *dev,
 
                sw->nvm->authenticating = true;
 
-               if (!tb_route(sw))
+               if (!tb_route(sw)) {
+                       /*
+                        * Keep root port from suspending as long as the
+                        * NVM upgrade process is running.
+                        */
+                       nvm_authenticate_start(sw);
                        ret = nvm_authenticate_host(sw);
-               else
+                       if (ret)
+                               nvm_authenticate_complete(sw);
+               } else {
                        ret = nvm_authenticate_device(sw);
+               }
                pm_runtime_mark_last_busy(&sw->dev);
                pm_runtime_put_autosuspend(&sw->dev);
        }
@@ -1334,6 +1366,10 @@ static int tb_switch_add_dma_port(struct tb_switch *sw)
        if (ret <= 0)
                return ret;
 
+       /* Now we can allow root port to suspend again */
+       if (!tb_route(sw))
+               nvm_authenticate_complete(sw);
+
        if (status) {
                tb_sw_info(sw, "switch flash authentication failed\n");
                tb_switch_set_uuid(sw);