nvme-pci: allow use of cmb on v1.4 controllers
authorKlaus Jensen <k.jensen@samsung.com>
Fri, 15 Jan 2021 06:30:46 +0000 (07:30 +0100)
committerChristoph Hellwig <hch@lst.de>
Mon, 18 Jan 2021 17:58:18 +0000 (18:58 +0100)
Since NVMe v1.4 the Controller Memory Buffer must be explicitly enabled
by the host.

Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
[hch: avoid a local variable and add a comment]
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/nvme/host/pci.c
include/linux/nvme.h

index 50d9a20568a28df74abd85584259b246dbe67eac..25456d02eddb8cf4af4cda4026ae146be877af9d 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/t10-pi.h>
 #include <linux/types.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
 #include <linux/sed-opal.h>
 #include <linux/pci-p2pdma.h>
 
@@ -1795,6 +1796,9 @@ static void nvme_map_cmb(struct nvme_dev *dev)
        if (dev->cmb_size)
                return;
 
+       if (NVME_CAP_CMBS(dev->ctrl.cap))
+               writel(NVME_CMBMSC_CRE, dev->bar + NVME_REG_CMBMSC);
+
        dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
        if (!dev->cmbsz)
                return;
@@ -1808,6 +1812,16 @@ static void nvme_map_cmb(struct nvme_dev *dev)
        if (offset > bar_size)
                return;
 
+       /*
+        * Tell the controller about the host side address mapping the CMB,
+        * and enable CMB decoding for the NVMe 1.4+ scheme:
+        */
+       if (NVME_CAP_CMBS(dev->ctrl.cap)) {
+               hi_lo_writeq(NVME_CMBMSC_CRE | NVME_CMBMSC_CMSE |
+                            (pci_bus_address(pdev, bar) + offset),
+                            dev->bar + NVME_REG_CMBMSC);
+       }
+
        /*
         * Controllers may support a CMB size larger than their BAR,
         * for example, due to being behind a bridge. Reduce the CMB to
index d925359976873ad4215ddd6f63ed4551d7bd4d91..bfed36e342ccb262dc3625a9d89867725d4be11d 100644 (file)
@@ -116,6 +116,9 @@ enum {
        NVME_REG_BPMBL  = 0x0048,       /* Boot Partition Memory Buffer
                                         * Location
                                         */
+       NVME_REG_CMBMSC = 0x0050,       /* Controller Memory Buffer Memory
+                                        * Space Control
+                                        */
        NVME_REG_PMRCAP = 0x0e00,       /* Persistent Memory Capabilities */
        NVME_REG_PMRCTL = 0x0e04,       /* Persistent Memory Region Control */
        NVME_REG_PMRSTS = 0x0e08,       /* Persistent Memory Region Status */
@@ -135,6 +138,7 @@ enum {
 #define NVME_CAP_CSS(cap)      (((cap) >> 37) & 0xff)
 #define NVME_CAP_MPSMIN(cap)   (((cap) >> 48) & 0xf)
 #define NVME_CAP_MPSMAX(cap)   (((cap) >> 52) & 0xf)
+#define NVME_CAP_CMBS(cap)     (((cap) >> 57) & 0x1)
 
 #define NVME_CMB_BIR(cmbloc)   ((cmbloc) & 0x7)
 #define NVME_CMB_OFST(cmbloc)  (((cmbloc) >> 12) & 0xfffff)
@@ -192,6 +196,8 @@ enum {
        NVME_CSTS_SHST_OCCUR    = 1 << 2,
        NVME_CSTS_SHST_CMPLT    = 2 << 2,
        NVME_CSTS_SHST_MASK     = 3 << 2,
+       NVME_CMBMSC_CRE         = 1 << 0,
+       NVME_CMBMSC_CMSE        = 1 << 1,
 };
 
 struct nvme_id_power_state {