Skip to content

Commit ebefac5

Browse files
BobBeckettkeithbusch
authored andcommitted
nvme-pci: 512 byte aligned dma pool segment quirk
We initially introduced a quick fix limiting the queue depth to 1 as experimentation showed that it fixed data corruption on 64GB steamdecks. Further experimentation revealed corruption only happens when the last PRP data element aligns to the end of the page boundary. The device appears to treat this as a PRP chain to a new list instead of the data element that it actually is. This implementation is in violation of the spec. Encountering this errata with the Linux driver requires the host request a 128k transfer and coincidently be handed the last small pool dma buffer within a page. The QD1 quirk effectly works around this because the last data PRP always was at a 248 byte offset from the page start, so it never appeared at the end of the page, but comes at the expense of throttling IO and wasting the remainder of the PRP page beyond 256 bytes. Also to note, the MDTS on these devices is small enough that the "large" prp pool can hold enough PRP elements to never reach the end, so that pool is not a problem either. Introduce a new quirk to ensure the small pool is always aligned such that the last PRP element can't appear a the end of the page. This comes at the expense of wasting 256 bytes per small pool page allocated. Link: https://lore.kernel.org/linux-nvme/20241113043151.GA20077@lst.de/T/#u Fixes: 83bdfcb ("nvme-pci: qdepth 1 quirk") Cc: Paweł Anikiel <panikiel@google.com> Signed-off-by: Robert Beckett <bob.beckett@collabora.com> Signed-off-by: Keith Busch <kbusch@kernel.org>
1 parent 790eb09 commit ebefac5

File tree

2 files changed

+12
-2
lines changed

2 files changed

+12
-2
lines changed

drivers/nvme/host/nvme.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ enum nvme_quirks {
173173
* MSI (but not MSI-X) interrupts are broken and never fire.
174174
*/
175175
NVME_QUIRK_BROKEN_MSI = (1 << 21),
176+
177+
/*
178+
* Align dma pool segment size to 512 bytes
179+
*/
180+
NVME_QUIRK_DMAPOOL_ALIGN_512 = (1 << 22),
176181
};
177182

178183
/*

drivers/nvme/host/pci.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2834,15 +2834,20 @@ static int nvme_disable_prepare_reset(struct nvme_dev *dev, bool shutdown)
28342834

28352835
static int nvme_setup_prp_pools(struct nvme_dev *dev)
28362836
{
2837+
size_t small_align = 256;
2838+
28372839
dev->prp_page_pool = dma_pool_create("prp list page", dev->dev,
28382840
NVME_CTRL_PAGE_SIZE,
28392841
NVME_CTRL_PAGE_SIZE, 0);
28402842
if (!dev->prp_page_pool)
28412843
return -ENOMEM;
28422844

2845+
if (dev->ctrl.quirks & NVME_QUIRK_DMAPOOL_ALIGN_512)
2846+
small_align = 512;
2847+
28432848
/* Optimisation for I/Os between 4k and 128k */
28442849
dev->prp_small_pool = dma_pool_create("prp list 256", dev->dev,
2845-
256, 256, 0);
2850+
256, small_align, 0);
28462851
if (!dev->prp_small_pool) {
28472852
dma_pool_destroy(dev->prp_page_pool);
28482853
return -ENOMEM;
@@ -3607,7 +3612,7 @@ static const struct pci_device_id nvme_id_table[] = {
36073612
{ PCI_VDEVICE(REDHAT, 0x0010), /* Qemu emulated controller */
36083613
.driver_data = NVME_QUIRK_BOGUS_NID, },
36093614
{ PCI_DEVICE(0x1217, 0x8760), /* O2 Micro 64GB Steam Deck */
3610-
.driver_data = NVME_QUIRK_QDEPTH_ONE },
3615+
.driver_data = NVME_QUIRK_DMAPOOL_ALIGN_512, },
36113616
{ PCI_DEVICE(0x126f, 0x2262), /* Silicon Motion generic */
36123617
.driver_data = NVME_QUIRK_NO_DEEPEST_PS |
36133618
NVME_QUIRK_BOGUS_NID, },

0 commit comments

Comments
 (0)