ARM64: DTS: Fix Firefly board audio driver
[firefly-linux-kernel-4.4.55.git] / drivers / nvme / host / pci.c
index 9e294ff4e652a2bb8daa9e3f4a94cc09e8bb8b88..4cbc1807edfc3175417051eea08fdc66a3a6697d 100644 (file)
@@ -1633,10 +1633,15 @@ static int nvme_wait_ready(struct nvme_dev *dev, u64 cap, bool enabled)
  */
 static int nvme_disable_ctrl(struct nvme_dev *dev, u64 cap)
 {
+       struct pci_dev *pdev = to_pci_dev(dev->dev);
+
        dev->ctrl_config &= ~NVME_CC_SHN_MASK;
        dev->ctrl_config &= ~NVME_CC_ENABLE;
        writel(dev->ctrl_config, &dev->bar->cc);
 
+       if (pdev->vendor == 0x1c58 && pdev->device == 0x0003)
+               msleep(NVME_QUIRK_DELAY_AMOUNT);
+
        return nvme_wait_ready(dev, cap, false);
 }
 
@@ -2217,8 +2222,8 @@ static int nvme_kthread(void *data)
                                                        csts & NVME_CSTS_CFS) {
                                if (!__nvme_reset(dev)) {
                                        dev_warn(dev->dev,
-                                               "Failed status: %x, reset controller\n",
-                                               readl(&dev->bar->csts));
+                                               "Failed status: 0x%x, reset controller\n",
+                                               csts);
                                }
                                continue;
                        }
@@ -2290,6 +2295,13 @@ static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)
        disk->queue = ns->queue;
        disk->driverfs_dev = dev->device;
        disk->flags = GENHD_FL_EXT_DEVT;
+#ifdef CONFIG_ARCH_ROCKCHIP
+       disk->is_rk_disk = true;
+#else
+       disk->is_rk_disk = false;
+#endif
+
+       disk->is_rk_disk = false;
        sprintf(disk->disk_name, "nvme%dn%d", dev->instance, nsid);
 
        /*
@@ -2540,8 +2552,17 @@ static void nvme_ns_remove(struct nvme_ns *ns)
 {
        bool kill = nvme_io_incapable(ns->dev) && !blk_queue_dying(ns->queue);
 
-       if (kill)
+       if (kill) {
                blk_set_queue_dying(ns->queue);
+
+               /*
+                * The controller was shutdown first if we got here through
+                * device removal. The shutdown may requeue outstanding
+                * requests. These need to be aborted immediately so
+                * del_gendisk doesn't block indefinitely for their completion.
+                */
+               blk_mq_abort_requeue_list(ns->queue);
+       }
        if (ns->disk->flags & GENHD_FL_UP)
                del_gendisk(ns->disk);
        if (kill || !blk_queue_dying(ns->queue)) {
@@ -2663,10 +2684,10 @@ static int nvme_dev_add(struct nvme_dev *dev)
        return 0;
 }
 
-static int nvme_dev_map(struct nvme_dev *dev)
+static int nvme_pci_enable(struct nvme_dev *dev)
 {
        u64 cap;
-       int bars, result = -ENOMEM;
+       int result = -ENOMEM;
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
        if (pci_enable_device_mem(pdev))
@@ -2674,24 +2695,14 @@ static int nvme_dev_map(struct nvme_dev *dev)
 
        dev->entry[0].vector = pdev->irq;
        pci_set_master(pdev);
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
-       if (!bars)
-               goto disable_pci;
-
-       if (pci_request_selected_regions(pdev, bars, "nvme"))
-               goto disable_pci;
 
        if (dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)) &&
            dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(32)))
                goto disable;
 
-       dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
-       if (!dev->bar)
-               goto disable;
-
        if (readl(&dev->bar->csts) == -1) {
                result = -ENODEV;
-               goto unmap;
+               goto disable;
        }
 
        /*
@@ -2701,7 +2712,7 @@ static int nvme_dev_map(struct nvme_dev *dev)
        if (!pdev->irq) {
                result = pci_enable_msix(pdev, dev->entry, 1);
                if (result < 0)
-                       goto unmap;
+                       goto disable;
        }
 
        cap = lo_hi_readq(&dev->bar->cap);
@@ -2725,17 +2736,20 @@ static int nvme_dev_map(struct nvme_dev *dev)
 
        return 0;
 
- unmap:
-       iounmap(dev->bar);
-       dev->bar = NULL;
  disable:
-       pci_release_regions(pdev);
- disable_pci:
        pci_disable_device(pdev);
+
        return result;
 }
 
 static void nvme_dev_unmap(struct nvme_dev *dev)
+{
+       if (dev->bar)
+               iounmap(dev->bar);
+       pci_release_regions(to_pci_dev(dev->dev));
+}
+
+static void nvme_pci_disable(struct nvme_dev *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
@@ -2744,12 +2758,6 @@ static void nvme_dev_unmap(struct nvme_dev *dev)
        else if (pdev->msix_enabled)
                pci_disable_msix(pdev);
 
-       if (dev->bar) {
-               iounmap(dev->bar);
-               dev->bar = NULL;
-               pci_release_regions(pdev);
-       }
-
        if (pci_is_enabled(pdev))
                pci_disable_device(pdev);
 }
@@ -2953,7 +2961,7 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
 
        nvme_dev_list_remove(dev);
 
-       if (dev->bar) {
+       if (pci_is_enabled(to_pci_dev(dev->dev))) {
                nvme_freeze_queues(dev);
                csts = readl(&dev->bar->csts);
        }
@@ -2967,7 +2975,7 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
                nvme_shutdown_ctrl(dev);
                nvme_disable_queue(dev, 0);
        }
-       nvme_dev_unmap(dev);
+       nvme_pci_disable(dev);
 
        for (i = dev->queue_count - 1; i >= 0; i--)
                nvme_clear_queue(dev->queues[i]);
@@ -2977,6 +2985,15 @@ static void nvme_dev_remove(struct nvme_dev *dev)
 {
        struct nvme_ns *ns, *next;
 
+       if (nvme_io_incapable(dev)) {
+               /*
+                * If the device is not capable of IO (surprise hot-removal,
+                * for example), we need to quiesce prior to deleting the
+                * namespaces. This will end outstanding requests and prevent
+                * attempts to sync dirty data.
+                */
+               nvme_dev_shutdown(dev);
+       }
        list_for_each_entry_safe(ns, next, &dev->namespaces, list)
                nvme_ns_remove(ns);
 }
@@ -3118,7 +3135,7 @@ static void nvme_probe_work(struct work_struct *work)
        bool start_thread = false;
        int result;
 
-       result = nvme_dev_map(dev);
+       result = nvme_pci_enable(dev);
        if (result)
                goto out;
 
@@ -3274,6 +3291,27 @@ static ssize_t nvme_sysfs_reset(struct device *dev,
 }
 static DEVICE_ATTR(reset_controller, S_IWUSR, NULL, nvme_sysfs_reset);
 
+static int nvme_dev_map(struct nvme_dev *dev)
+{
+       int bars;
+       struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+       bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       if (!bars)
+               return -ENODEV;
+       if (pci_request_selected_regions(pdev, bars, "nvme"))
+               return -ENODEV;
+
+       dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
+       if (!dev->bar)
+               goto release;
+
+       return 0;
+release:
+       pci_release_regions(pdev);
+       return -ENODEV;
+}
+
 static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int node, result = -ENOMEM;
@@ -3299,6 +3337,11 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        INIT_WORK(&dev->reset_work, nvme_reset_work);
        dev->dev = get_device(&pdev->dev);
        pci_set_drvdata(pdev, dev);
+
+       result = nvme_dev_map(dev);
+       if (result)
+               goto free;
+
        result = nvme_set_instance(dev);
        if (result)
                goto put_pci;
@@ -3337,6 +3380,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        nvme_release_instance(dev);
  put_pci:
        put_device(dev->dev);
+       nvme_dev_unmap(dev);
  free:
        kfree(dev->queues);
        kfree(dev->entry);
@@ -3380,6 +3424,7 @@ static void nvme_remove(struct pci_dev *pdev)
        nvme_free_queues(dev, 0);
        nvme_release_cmb(dev);
        nvme_release_prp_pools(dev);
+       nvme_dev_unmap(dev);
        kref_put(&dev->kref, nvme_free_dev);
 }