Merge tag 'for-5.4/block-2019-09-16' of git://git.kernel.dk/linux-block
[sfrench/cifs-2.6.git] / drivers / nvme / host / pci.c
index 52205f8d90b472755b995227fafe1883c5c597ad..6b4d7b064b38a6624d517306ca1f1d7a8cecf6fe 100644 (file)
@@ -2745,7 +2745,7 @@ static void nvme_async_probe(void *data, async_cookie_t cookie)
 {
        struct nvme_dev *dev = data;
 
-       nvme_reset_ctrl_sync(&dev->ctrl);
+       flush_work(&dev->ctrl.reset_work);
        flush_work(&dev->ctrl.scan_work);
        nvme_put_ctrl(&dev->ctrl);
 }
@@ -2811,6 +2811,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        dev_info(dev->ctrl.device, "pci function %s\n", dev_name(&pdev->dev));
 
+       nvme_reset_ctrl(&dev->ctrl);
        nvme_get_ctrl(&dev->ctrl);
        async_schedule(nvme_async_probe, dev);
 
@@ -2896,7 +2897,7 @@ static int nvme_resume(struct device *dev)
        struct nvme_dev *ndev = pci_get_drvdata(to_pci_dev(dev));
        struct nvme_ctrl *ctrl = &ndev->ctrl;
 
-       if (pm_resume_via_firmware() || !ctrl->npss ||
+       if (ndev->last_ps == U32_MAX ||
            nvme_set_power_state(ctrl, ndev->last_ps) != 0)
                nvme_reset_ctrl(ctrl);
        return 0;
@@ -2909,6 +2910,8 @@ static int nvme_suspend(struct device *dev)
        struct nvme_ctrl *ctrl = &ndev->ctrl;
        int ret = -EBUSY;
 
+       ndev->last_ps = U32_MAX;
+
        /*
         * The platform does not remove power for a kernel managed suspend so
         * use host managed nvme power settings for lowest idle power if
@@ -2916,8 +2919,15 @@ static int nvme_suspend(struct device *dev)
         * shutdown.  But if the firmware is involved after the suspend or the
         * device does not support any non-default power states, shut down the
         * device fully.
+        *
+        * If ASPM is not enabled for the device, shut down the device and allow
+        * the PCI bus layer to put it into D3 in order to take the PCIe link
+        * down, so as to allow the platform to achieve its minimum low-power
+        * state (which may not be possible if the link is up).
         */
-       if (pm_suspend_via_firmware() || !ctrl->npss) {
+       if (pm_suspend_via_firmware() || !ctrl->npss ||
+           !pcie_aspm_enabled(pdev) ||
+           (ndev->ctrl.quirks & NVME_QUIRK_SIMPLE_SUSPEND)) {
                nvme_dev_disable(ndev, true);
                return 0;
        }
@@ -2930,7 +2940,6 @@ static int nvme_suspend(struct device *dev)
            ctrl->state != NVME_CTRL_ADMIN_ONLY)
                goto unfreeze;
 
-       ndev->last_ps = 0;
        ret = nvme_get_power_state(ctrl, &ndev->last_ps);
        if (ret < 0)
                goto unfreeze;