Skip to contentSkip to conversation

nvme-pci: Remap CMB SQ entries on every controller reset

PATCH In review Scott Bauer 5 participants 5 messages Jul 12, 2018 – Jul 15, 2018

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 nvme-pci: Remap CMB SQ entries on every controller reset

Commit 815c6704bf9f1c59f3a6be380a4032b9c57b12f1 upstream.

The controller memory buffer is remapped into a kernel address on each reset, but the driver was setting the submission queue base address only on the very first queue creation. The remapped address is likely to change after a reset, so accessing the old address will hit a kernel bug.

This patch fixes that by setting the queue's CMB base address each time the queue is created.

Fixes f63572dff1421 ("nvme: unmap CMB and remove sysfs file in reset path")
Cc Jon Derrick <[email protected]>
---
 drivers/nvme/host/pci.c | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)
drivers/nvme/host/pci.c +16 -11
index 3d4724e38aa9..4cac4755abef 100644
@@ -1233,17 +1233,15 @@ static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues,
 static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq,
 				int qid, int depth)
 {
-	if (qid && dev->cmb && use_cmb_sqes && NVME_CMB_SQS(dev->cmbsz)) {
-		unsigned offset = (qid - 1) * roundup(SQ_SIZE(depth),
-						      dev->ctrl.page_size);
-		nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset;
-		nvmeq->sq_cmds_io = dev->cmb + offset;
-	} else {
-		nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth),
-					&nvmeq->sq_dma_addr, GFP_KERNEL);
-		if (!nvmeq->sq_cmds)
-			return -ENOMEM;
-	}
+
+	/* CMB SQEs will be mapped before creation */
+	if (qid && dev->cmb && use_cmb_sqes && NVME_CMB_SQS(dev->cmbsz))
+		return 0;
+
+	nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth),
+					    &nvmeq->sq_dma_addr, GFP_KERNEL);
+	if (!nvmeq->sq_cmds)
+		return -ENOMEM;
 
 	return 0;
 }
@@ -1320,6 +1318,13 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
 	struct nvme_dev *dev = nvmeq->dev;
 	int result;
 
+	if (qid && dev->cmb && use_cmb_sqes && NVME_CMB_SQS(dev->cmbsz)) {
+		unsigned offset = (qid - 1) * roundup(SQ_SIZE(nvmeq->q_depth),
+						      dev->ctrl.page_size);
+		nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset;
+		nvmeq->sq_cmds_io = dev->cmb + offset;
+	}
+
 	nvmeq->cq_vector = qid - 1;
 	result = adapter_alloc_cq(dev, qid, nvmeq);
 	if (result < 0)
Signature · 1 line
2.17.1
Reviewed-by on v1 1/1
#1 lore raw

Thank you, Scott

Quoted 84 lines · Scott Bauer

Commit 815c6704bf9f1c59f3a6be380a4032b9c57b12f1 upstream.

The controller memory buffer is remapped into a kernel address on each
reset, but the driver was setting the submission queue base address only on the very first queue creation. The remapped address is likely to
change after a reset, so accessing the old address will hit a kernel bug.

This patch fixes that by setting the queue's CMB base address each time
the queue is created.

Fixes f63572dff1421 ("nvme: unmap CMB and remove sysfs file in reset

path")

---
 drivers/nvme/host/pci.c | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)
drivers/nvme/host/pci.c +0 -8
index 3d4724e38aa9..4cac4755abef 100644
@@ -1233,17 +1233,15 @@ static int nvme_cmb_qdepth(struct nvme_dev
 *dev, int nr_io_queues,
 static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct
 nvme_queue *nvmeq,
 				int qid, int depth)
 {
-	if (qid && dev->cmb && use_cmb_sqes && NVME_CMB_SQS(dev-
 >cmbsz)) {
-		unsigned offset = (qid - 1) *
 roundup(SQ_SIZE(depth),
-						      dev-
 >ctrl.page_size);
-		nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset;
-		nvmeq->sq_cmds_io = dev->cmb + offset;
-	} else {
-		nvmeq->sq_cmds = dma_alloc_coherent(dev->dev,
 SQ_SIZE(depth),
-					&nvmeq->sq_dma_addr,

GFP_KERNEL);

drivers/nvme/host/pci.c +3 -3
-		if (!nvmeq->sq_cmds)
-			return -ENOMEM;
-	}
+
+	/* CMB SQEs will be mapped before creation */
+	if (qid && dev->cmb && use_cmb_sqes && NVME_CMB_SQS(dev-
Quoted 1 line

cmbsz))

drivers/nvme/host/pci.c +3 -0
+		return 0;
+
+	nvmeq->sq_cmds = dma_alloc_coherent(dev->dev,

SQ_SIZE(depth),

drivers/nvme/host/pci.c +1 -0
+					    &nvmeq->sq_dma_addr,

GFP_KERNEL);

drivers/nvme/host/pci.c +5 -0
+	if (!nvmeq->sq_cmds)
+		return -ENOMEM;
 
 	return 0;
 }
@@ -1320,6 +1318,13 @@ static int nvme_create_queue(struct nvme_queue
 *nvmeq, int qid)
 	struct nvme_dev *dev = nvmeq->dev;
 	int result;
 
+	if (qid && dev->cmb && use_cmb_sqes && NVME_CMB_SQS(dev-
 >cmbsz)) {
+		unsigned offset = (qid - 1) * roundup(SQ_SIZE(nvmeq-
 >q_depth),
+						      dev-
Quoted 1 line

ctrl.page_size);

drivers/nvme/host/pci.c +4 -0
+		nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset;
+		nvmeq->sq_cmds_io = dev->cmb + offset;
+	}
+
 	nvmeq->cq_vector = qid - 1;
 	result = adapter_alloc_cq(dev, qid, nvmeq);
 	if (result < 0)
maintainer
#2 lore raw
In reply to Scott Bauer
Quoted 17 lines · Scott Bauer

Commit 815c6704bf9f1c59f3a6be380a4032b9c57b12f1 upstream.

The controller memory buffer is remapped into a kernel address on each reset, but the driver was setting the submission queue base address only on the very first queue creation. The remapped address is likely to change after a reset, so accessing the old address will hit a kernel bug.

This patch fixes that by setting the queue's CMB base address each time the queue is created.

Fixes f63572dff1421 ("nvme: unmap CMB and remove sysfs file in reset path")
Cc Jon Derrick <[email protected]>
Quoted 3 lines
---
 drivers/nvme/host/pci.c | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)

"backport" to where? What kernel tree(s) do you want this applied to?

I need a hint please...

thanks,

greg k-h

#3 lore raw
Quoted 22 lines · Greg KH
Quoted 17 lines · Scott Bauer

Commit 815c6704bf9f1c59f3a6be380a4032b9c57b12f1 upstream.

The controller memory buffer is remapped into a kernel address on each reset, but the driver was setting the submission queue base address only on the very first queue creation. The remapped address is likely to change after a reset, so accessing the old address will hit a kernel bug.

This patch fixes that by setting the queue's CMB base address each time the queue is created.

Fixes f63572dff1421 ("nvme: unmap CMB and remove sysfs file in reset path")
Cc Jon Derrick <[email protected]>
Quoted 3 lines
---
 drivers/nvme/host/pci.c | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)
Quoted 3 lines

"backport" to where? What kernel tree(s) do you want this applied to?

I need a hint please...

Sorry about that. 4.9 and 4.14 are the applicable targets.

#4 lore raw
In reply to Scott Bauer
Quoted 17 lines · Scott Bauer

Commit 815c6704bf9f1c59f3a6be380a4032b9c57b12f1 upstream.

The controller memory buffer is remapped into a kernel address on each reset, but the driver was setting the submission queue base address only on the very first queue creation. The remapped address is likely to change after a reset, so accessing the old address will hit a kernel bug.

This patch fixes that by setting the queue's CMB base address each time the queue is created.

Fixes f63572dff1421 ("nvme: unmap CMB and remove sysfs file in reset path")
Cc Jon Derrick <[email protected]>
Quoted 3 lines
---
 drivers/nvme/host/pci.c | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)

Now queued up, thanks.

greg k-h