Daniel Wagner 664dfa
From: Klaus Jensen <k.jensen@samsung.com>
Daniel Wagner 664dfa
Date: Tue, 13 Dec 2022 09:58:07 +0100
Daniel Wagner 664dfa
Subject: nvme-pci: fix doorbell buffer value endianness
Daniel Wagner 664dfa
Patch-mainline: v6.2-rc2
Daniel Wagner 664dfa
Git-commit: b5f96cb719d8ba220b565ddd3ba4ac0d8bcfb130
Daniel Wagner 664dfa
References: git-fixes
Daniel Wagner 664dfa
Daniel Wagner 664dfa
When using shadow doorbells, the event index and the doorbell values are
Daniel Wagner 664dfa
written to host memory. Prior to this patch, the values written would
Daniel Wagner 664dfa
erroneously be written in host endianness. This causes trouble on
Daniel Wagner 664dfa
big-endian platforms. Fix this by adding missing endian conversions.
Daniel Wagner 664dfa
Daniel Wagner 664dfa
This issue was noticed by Guenter while testing various big-endian
Daniel Wagner 664dfa
platforms under QEMU[1]. A similar fix required for hw/nvme in QEMU is
Daniel Wagner 664dfa
up for review as well[2].
Daniel Wagner 664dfa
Daniel Wagner 664dfa
  [1]: https://lore.kernel.org/qemu-devel/20221209110022.GA3396194@roeck-us.net/
Daniel Wagner 664dfa
  [2]: https://lore.kernel.org/qemu-devel/20221212114409.34972-4-its@irrelevant.dk/
Daniel Wagner 664dfa
Daniel Wagner 664dfa
Fixes: f9f38e33389c ("nvme: improve performance for virtual NVMe devices")
Daniel Wagner 664dfa
Reported-by: Guenter Roeck <linux@roeck-us.net>
Daniel Wagner 664dfa
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Daniel Wagner 664dfa
Signed-off-by: Christoph Hellwig <hch@lst.de>
Daniel Wagner 664dfa
Acked-by: Daniel Wagner <dwagner@suse.de>
Daniel Wagner 664dfa
---
Daniel Wagner 664dfa
 drivers/nvme/host/pci.c |   25 +++++++++++++------------
Daniel Wagner 664dfa
 1 file changed, 13 insertions(+), 12 deletions(-)
Daniel Wagner 664dfa
Daniel Wagner 664dfa
--- a/drivers/nvme/host/pci.c
Daniel Wagner 664dfa
+++ b/drivers/nvme/host/pci.c
Daniel Wagner 664dfa
@@ -110,9 +110,9 @@ struct nvme_dev {
Daniel Wagner 664dfa
 	mempool_t *iod_mempool;
Daniel Wagner 664dfa
 
Daniel Wagner 664dfa
 	/* shadow doorbell buffer support: */
Daniel Wagner 664dfa
-	u32 *dbbuf_dbs;
Daniel Wagner 664dfa
+	__le32 *dbbuf_dbs;
Daniel Wagner 664dfa
 	dma_addr_t dbbuf_dbs_dma_addr;
Daniel Wagner 664dfa
-	u32 *dbbuf_eis;
Daniel Wagner 664dfa
+	__le32 *dbbuf_eis;
Daniel Wagner 664dfa
 	dma_addr_t dbbuf_eis_dma_addr;
Daniel Wagner 664dfa
 
Daniel Wagner 664dfa
 	/* host memory buffer support: */
Daniel Wagner 664dfa
@@ -172,10 +172,10 @@ struct nvme_queue {
Daniel Wagner 664dfa
 	u16 last_cq_head;
Daniel Wagner 664dfa
 	u16 qid;
Daniel Wagner 664dfa
 	u8 cq_phase;
Daniel Wagner 664dfa
-	u32 *dbbuf_sq_db;
Daniel Wagner 664dfa
-	u32 *dbbuf_cq_db;
Daniel Wagner 664dfa
-	u32 *dbbuf_sq_ei;
Daniel Wagner 664dfa
-	u32 *dbbuf_cq_ei;
Daniel Wagner 664dfa
+	__le32 *dbbuf_sq_db;
Daniel Wagner 664dfa
+	__le32 *dbbuf_cq_db;
Daniel Wagner 664dfa
+	__le32 *dbbuf_sq_ei;
Daniel Wagner 664dfa
+	__le32 *dbbuf_cq_ei;
Daniel Wagner 664dfa
 };
Daniel Wagner 664dfa
 
Daniel Wagner 664dfa
 /*
Daniel Wagner 664dfa
@@ -301,11 +301,11 @@ static inline int nvme_dbbuf_need_event(
Daniel Wagner 664dfa
 }
Daniel Wagner 664dfa
 
Daniel Wagner 664dfa
 /* Update dbbuf and return true if an MMIO is required */
Daniel Wagner 664dfa
-static bool nvme_dbbuf_update_and_check_event(u16 value, u32 *dbbuf_db,
Daniel Wagner 664dfa
-					      volatile u32 *dbbuf_ei)
Daniel Wagner 664dfa
+static bool nvme_dbbuf_update_and_check_event(u16 value, __le32 *dbbuf_db,
Daniel Wagner 664dfa
+					      volatile __le32 *dbbuf_ei)
Daniel Wagner 664dfa
 {
Daniel Wagner 664dfa
 	if (dbbuf_db) {
Daniel Wagner 664dfa
-		u16 old_value;
Daniel Wagner 664dfa
+		u16 old_value, event_idx;
Daniel Wagner 664dfa
 
Daniel Wagner 664dfa
 		/*
Daniel Wagner 664dfa
 		 * Ensure that the queue is written before updating
Daniel Wagner 664dfa
@@ -313,8 +313,8 @@ static bool nvme_dbbuf_update_and_check_
Daniel Wagner 664dfa
 		 */
Daniel Wagner 664dfa
 		wmb();
Daniel Wagner 664dfa
 
Daniel Wagner 664dfa
-		old_value = *dbbuf_db;
Daniel Wagner 664dfa
-		*dbbuf_db = value;
Daniel Wagner 664dfa
+		old_value = le32_to_cpu(*dbbuf_db);
Daniel Wagner 664dfa
+		*dbbuf_db = cpu_to_le32(value);
Daniel Wagner 664dfa
 
Daniel Wagner 664dfa
 		/*
Daniel Wagner 664dfa
 		 * Ensure that the doorbell is updated before reading the event
Daniel Wagner 664dfa
@@ -324,7 +324,8 @@ static bool nvme_dbbuf_update_and_check_
Daniel Wagner 664dfa
 		 */
Daniel Wagner 664dfa
 		mb();
Daniel Wagner 664dfa
 
Daniel Wagner 664dfa
-		if (!nvme_dbbuf_need_event(*dbbuf_ei, value, old_value))
Daniel Wagner 664dfa
+		event_idx = le32_to_cpu(*dbbuf_ei);
Daniel Wagner 664dfa
+		if (!nvme_dbbuf_need_event(event_idx, value, old_value))
Daniel Wagner 664dfa
 			return false;
Daniel Wagner 664dfa
 	}
Daniel Wagner 664dfa