Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2231306/?format=api
{ "id": 2231306, "url": "http://patchwork.ozlabs.org/api/patches/2231306/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20260430145412.BC53E68AFE@verein.lst.de/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api", "name": "U-Boot", "link_name": "uboot", "list_id": "u-boot.lists.denx.de", "list_email": "u-boot@lists.denx.de", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260430145412.BC53E68AFE@verein.lst.de>", "list_archive_url": null, "date": "2026-04-30T14:54:12", "name": "nvme: Fix missing inbound DMA offset calculation", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "9fb183bb33390b48b274605c8f7d831de2535821", "submitter": { "id": 2722, "url": "http://patchwork.ozlabs.org/api/people/2722/?format=api", "name": "Torsten Duwe", "email": "duwe@lst.de" }, "delegate": { "id": 3651, "url": "http://patchwork.ozlabs.org/api/users/3651/?format=api", "username": "trini", "first_name": "Tom", "last_name": "Rini", "email": "trini@ti.com" }, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20260430145412.BC53E68AFE@verein.lst.de/mbox/", "series": [ { "id": 502322, "url": "http://patchwork.ozlabs.org/api/series/502322/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=502322", "date": "2026-04-30T14:54:12", "name": "nvme: Fix missing inbound DMA offset calculation", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/502322/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2231306/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2231306/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<u-boot-bounces@lists.denx.de>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org)", "phobos.denx.de;\n dmarc=fail (p=none dis=none) header.from=lst.de", "phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de", "phobos.denx.de;\n dmarc=fail (p=none dis=none) header.from=lst.de", "phobos.denx.de; spf=pass smtp.mailfrom=duwe@lst.de" ], "Received": [ "from phobos.denx.de (phobos.denx.de\n [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g5xyj6V6Pz1xqf\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 01 May 2026 00:54:21 +1000 (AEST)", "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id E820B80433;\n\tThu, 30 Apr 2026 16:54:17 +0200 (CEST)", "by phobos.denx.de (Postfix, from userid 109)\n id 68D388063E; Thu, 30 Apr 2026 16:54:16 +0200 (CEST)", "from verein.lst.de (verein.lst.de [213.95.11.211])\n (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id E883980086\n for <u-boot@lists.denx.de>; Thu, 30 Apr 2026 16:54:13 +0200 (CEST)", "by verein.lst.de (Postfix, from userid 2005)\n id BC53E68AFE; Thu, 30 Apr 2026 16:54:12 +0200 (CEST)" ], "X-Spam-Checker-Version": "SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de", "X-Spam-Level": "", "X-Spam-Status": "No, score=-1.9 required=5.0 tests=BAYES_00,\n RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham\n autolearn_force=no version=3.4.2", "To": "Bin Meng <bmeng.cn@gmail.com>,\n Andrew Goodbody <andrew.goodbody@linaro.org>,\n Tom Rini <trini@konsulko.com>", "Cc": "Peter Robinson <pbrobinson@gmail.com>,\n Matthias Brugger <mbrugger@suse.com>,\n Andrea della Porta <andrea.porta@suse.com>, u-boot@lists.denx.de", "Subject": "[PATCH] nvme: Fix missing inbound DMA offset calculation", "Message-Id": "<20260430145412.BC53E68AFE@verein.lst.de>", "Date": "Thu, 30 Apr 2026 16:54:12 +0200 (CEST)", "From": "duwe@lst.de (Torsten Duwe)", "X-BeenThere": "u-boot@lists.denx.de", "X-Mailman-Version": "2.1.39", "Precedence": "list", "List-Id": "U-Boot discussion <u-boot.lists.denx.de>", "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>", "List-Archive": "<https://lists.denx.de/pipermail/u-boot/>", "List-Post": "<mailto:u-boot@lists.denx.de>", "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>", "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=subscribe>", "Errors-To": "u-boot-bounces@lists.denx.de", "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>", "X-Virus-Scanned": "clamav-milter 0.103.8 at phobos.denx.de", "X-Virus-Status": "Clean" }, "content": "From: Torsten Duwe <duwe@suse.de>\n\nU-Boot currently does not account for PCIe bridges with a non-zero\ninbound access offset when talking NVMe, it only works on platforms\nwhere this offset happens to be zero.\n\nThis patch enhances the NVMe driver with the ability to also handle\nthese cases. The fix is required to boot e.g. the Raspberry Pi5 from\nNVMe.\n\nSigned-off-by: Torsten Duwe <duwe@suse.de>\n---\n\nKudos for the idea of case discrimination go to Andrea; this eases\nthings a lot.\n\nI do consider this a bug fix. The problem has popped up during RPi5\ndevelopment but really is a generic major defect IMHO. Please apply\nwherever appropriate.\n\n\tTorsten\n\n---\n drivers/nvme/nvme.c | 39 ++++++++++++++++++++++++++-------------\n 1 file changed, 26 insertions(+), 13 deletions(-)", "diff": "diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c\nindex 2b14437f69c..8056f52fb50 100644\n--- a/drivers/nvme/nvme.c\n+++ b/drivers/nvme/nvme.c\n@@ -12,6 +12,7 @@\n #include <log.h>\n #include <malloc.h>\n #include <memalign.h>\n+#include <phys2bus.h>\n #include <time.h>\n #include <dm/device-internal.h>\n #include <linux/compat.h>\n@@ -27,6 +28,18 @@\n #define IO_TIMEOUT\t\t30\n #define MAX_PRP_POOL\t\t512\n \n+/*\n+ * This macro detects the correct inbound DMA offset in both cases:\n+ * 1) the NVMe is mentioned in the device tree, along with its parent,\n+ *\tand no intermediate PCIe bus node in between.\n+ * 2) the NVMe was found dynamically by PCI enumeration which has created\n+ *\tan intermediate PCIe bus node. That node will be skipped and the offset\n+ *\tlooked up in the grandparent.\n+ */\n+#define DEV_ADDR(a)\t\t(dev_has_ofnode(dev->udev) ? \\\n+\t\t\t\t\tdev_phys_to_bus(dev->udev, (a)) : \\\n+\t\t\t\t\tdev_phys_to_bus(dev->udev->parent, (a)))\n+\n static int nvme_wait_csts(struct nvme_dev *dev, u32 mask, u32 val)\n {\n \tint timeout;\n@@ -91,12 +104,12 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,\n \ti = 0;\n \twhile (nprps) {\n \t\tif ((i == (prps_per_page - 1)) && nprps > 1) {\n-\t\t\t*(prp_pool + i) = cpu_to_le64((ulong)prp_pool +\n-\t\t\t\t\tpage_size);\n+\t\t\t*(prp_pool + i) = cpu_to_le64(DEV_ADDR((ulong)prp_pool +\n+\t\t\t\t\t\t\t\tpage_size));\n \t\t\ti = 0;\n \t\t\tprp_pool += page_size;\n \t\t}\n-\t\t*(prp_pool + i++) = cpu_to_le64(dma_addr);\n+\t\t*(prp_pool + i++) = cpu_to_le64(DEV_ADDR(dma_addr));\n \t\tdma_addr += page_size;\n \t\tnprps--;\n \t}\n@@ -393,8 +406,8 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)\n \tdev->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES;\n \n \twritel(aqa, &dev->bar->aqa);\n-\tnvme_writeq((ulong)nvmeq->sq_cmds, &dev->bar->asq);\n-\tnvme_writeq((ulong)nvmeq->cqes, &dev->bar->acq);\n+\tnvme_writeq(DEV_ADDR((ulong)nvmeq->sq_cmds), &dev->bar->asq);\n+\tnvme_writeq(DEV_ADDR((ulong)nvmeq->cqes), &dev->bar->acq);\n \n \tresult = nvme_enable_ctrl(dev);\n \tif (result)\n@@ -420,7 +433,7 @@ static int nvme_alloc_cq(struct nvme_dev *dev, u16 qid,\n \n \tmemset(&c, 0, sizeof(c));\n \tc.create_cq.opcode = nvme_admin_create_cq;\n-\tc.create_cq.prp1 = cpu_to_le64((ulong)nvmeq->cqes);\n+\tc.create_cq.prp1 = cpu_to_le64(DEV_ADDR((ulong)nvmeq->cqes));\n \tc.create_cq.cqid = cpu_to_le16(qid);\n \tc.create_cq.qsize = cpu_to_le16(nvmeq->q_depth - 1);\n \tc.create_cq.cq_flags = cpu_to_le16(flags);\n@@ -437,7 +450,7 @@ static int nvme_alloc_sq(struct nvme_dev *dev, u16 qid,\n \n \tmemset(&c, 0, sizeof(c));\n \tc.create_sq.opcode = nvme_admin_create_sq;\n-\tc.create_sq.prp1 = cpu_to_le64((ulong)nvmeq->sq_cmds);\n+\tc.create_sq.prp1 = cpu_to_le64(DEV_ADDR((ulong)nvmeq->sq_cmds));\n \tc.create_sq.sqid = cpu_to_le16(qid);\n \tc.create_sq.qsize = cpu_to_le16(nvmeq->q_depth - 1);\n \tc.create_sq.sq_flags = cpu_to_le16(flags);\n@@ -458,14 +471,14 @@ int nvme_identify(struct nvme_dev *dev, unsigned nsid,\n \tmemset(&c, 0, sizeof(c));\n \tc.identify.opcode = nvme_admin_identify;\n \tc.identify.nsid = cpu_to_le32(nsid);\n-\tc.identify.prp1 = cpu_to_le64(dma_addr);\n+\tc.identify.prp1 = cpu_to_le64(DEV_ADDR(dma_addr));\n \n \tlength -= (page_size - offset);\n \tif (length <= 0) {\n \t\tc.identify.prp2 = 0;\n \t} else {\n \t\tdma_addr += (page_size - offset);\n-\t\tc.identify.prp2 = cpu_to_le64(dma_addr);\n+\t\tc.identify.prp2 = cpu_to_le64(DEV_ADDR(dma_addr));\n \t}\n \n \tc.identify.cns = cpu_to_le32(cns);\n@@ -490,7 +503,7 @@ int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,\n \tmemset(&c, 0, sizeof(c));\n \tc.features.opcode = nvme_admin_get_features;\n \tc.features.nsid = cpu_to_le32(nsid);\n-\tc.features.prp1 = cpu_to_le64(dma_addr);\n+\tc.features.prp1 = cpu_to_le64(DEV_ADDR(dma_addr));\n \tc.features.fid = cpu_to_le32(fid);\n \n \tret = nvme_submit_admin_cmd(dev, &c, result);\n@@ -516,7 +529,7 @@ int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,\n \n \tmemset(&c, 0, sizeof(c));\n \tc.features.opcode = nvme_admin_set_features;\n-\tc.features.prp1 = cpu_to_le64(dma_addr);\n+\tc.features.prp1 = cpu_to_le64(DEV_ADDR(dma_addr));\n \tc.features.fid = cpu_to_le32(fid);\n \tc.features.dword11 = cpu_to_le32(dword11);\n \n@@ -785,8 +798,8 @@ static ulong nvme_blk_rw(struct udevice *udev, lbaint_t blknr,\n \t\tc.rw.slba = cpu_to_le64(slba);\n \t\tslba += lbas;\n \t\tc.rw.length = cpu_to_le16(lbas - 1);\n-\t\tc.rw.prp1 = cpu_to_le64(temp_buffer);\n-\t\tc.rw.prp2 = cpu_to_le64(prp2);\n+\t\tc.rw.prp1 = cpu_to_le64(DEV_ADDR(temp_buffer));\n+\t\tc.rw.prp2 = cpu_to_le64(DEV_ADDR(prp2));\n \t\tstatus = nvme_submit_sync_cmd(dev->queues[NVME_IO_Q],\n \t\t\t\t&c, NULL, IO_TIMEOUT);\n \t\tif (status)\n", "prefixes": [] }