Skip to content

Commit f17cf8f

Browse files
birkelundgregkh
authored andcommitted
nvme-pci: fix doorbell buffer value endianness
[ Upstream commit b5f96cb ] When using shadow doorbells, the event index and the doorbell values are written to host memory. Prior to this patch, the values written would erroneously be written in host endianness. This causes trouble on big-endian platforms. Fix this by adding missing endian conversions. This issue was noticed by Guenter while testing various big-endian platforms under QEMU[1]. A similar fix required for hw/nvme in QEMU is up for review as well[2]. [1]: https://lore.kernel.org/qemu-devel/20221209110022.GA3396194@roeck-us.net/ [2]: https://lore.kernel.org/qemu-devel/20221212114409.34972-4-its@irrelevant.dk/ Fixes: f9f38e3 ("nvme: improve performance for virtual NVMe devices") Reported-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Klaus Jensen <k.jensen@samsung.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent ead99ec commit f17cf8f

File tree

1 file changed

+13
-12
lines changed

1 file changed

+13
-12
lines changed

drivers/nvme/host/pci.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,9 @@ struct nvme_dev {
142142
mempool_t *iod_mempool;
143143

144144
/* shadow doorbell buffer support: */
145-
u32 *dbbuf_dbs;
145+
__le32 *dbbuf_dbs;
146146
dma_addr_t dbbuf_dbs_dma_addr;
147-
u32 *dbbuf_eis;
147+
__le32 *dbbuf_eis;
148148
dma_addr_t dbbuf_eis_dma_addr;
149149

150150
/* host memory buffer support: */
@@ -208,10 +208,10 @@ struct nvme_queue {
208208
#define NVMEQ_SQ_CMB 1
209209
#define NVMEQ_DELETE_ERROR 2
210210
#define NVMEQ_POLLED 3
211-
u32 *dbbuf_sq_db;
212-
u32 *dbbuf_cq_db;
213-
u32 *dbbuf_sq_ei;
214-
u32 *dbbuf_cq_ei;
211+
__le32 *dbbuf_sq_db;
212+
__le32 *dbbuf_cq_db;
213+
__le32 *dbbuf_sq_ei;
214+
__le32 *dbbuf_cq_ei;
215215
struct completion delete_done;
216216
};
217217

@@ -332,20 +332,20 @@ static inline int nvme_dbbuf_need_event(u16 event_idx, u16 new_idx, u16 old)
332332
}
333333

334334
/* Update dbbuf and return true if an MMIO is required */
335-
static bool nvme_dbbuf_update_and_check_event(u16 value, u32 *dbbuf_db,
336-
volatile u32 *dbbuf_ei)
335+
static bool nvme_dbbuf_update_and_check_event(u16 value, __le32 *dbbuf_db,
336+
volatile __le32 *dbbuf_ei)
337337
{
338338
if (dbbuf_db) {
339-
u16 old_value;
339+
u16 old_value, event_idx;
340340

341341
/*
342342
* Ensure that the queue is written before updating
343343
* the doorbell in memory
344344
*/
345345
wmb();
346346

347-
old_value = *dbbuf_db;
348-
*dbbuf_db = value;
347+
old_value = le32_to_cpu(*dbbuf_db);
348+
*dbbuf_db = cpu_to_le32(value);
349349

350350
/*
351351
* Ensure that the doorbell is updated before reading the event
@@ -355,7 +355,8 @@ static bool nvme_dbbuf_update_and_check_event(u16 value, u32 *dbbuf_db,
355355
*/
356356
mb();
357357

358-
if (!nvme_dbbuf_need_event(*dbbuf_ei, value, old_value))
358+
event_idx = le32_to_cpu(*dbbuf_ei);
359+
if (!nvme_dbbuf_need_event(event_idx, value, old_value))
359360
return false;
360361
}
361362

0 commit comments

Comments
 (0)