* [PATCH v0] Fix NVMe for non-zero bus offsets
@ 2026-03-02 12:59 Torsten Duwe
2026-03-02 15:42 ` [hack] help U-Boot find the correct PCIe inbound offset for NVMe on Raspberry Pi 5 Torsten Duwe
0 siblings, 1 reply; 6+ messages in thread
From: Torsten Duwe @ 2026-03-02 12:59 UTC (permalink / raw)
To: Bin Meng, Andrew Goodbody
Cc: Peter Robinson, Matthias Brugger, Andrea della Porta, Tom Rini,
u-boot
Hi all,
working on the RPi5 I found that the U-Boot NVMe code is lacking a significant
feature. The NVMe protocol heavily relies on device access into main memory,
in the medieval times of computing this was called "bus master DMA". The NVMe
device must generate memory addresses and read or write contents there. The
current U-Boot code does in no way account for PCIe bridges in the path that
add an offset to such "inbound accesses". Consequently, U-Boot can only boot
from NVMe on platforms where this address offset is zero.
(These are surprisingly many!)
This proposed patch uses the already existent dev_phys_to_bus(), which can
dig up the correct offset from associated DT nodes and subtract it. I have
no strong opinion on the macro naming, and whether it should silently pull
in the "dev" from the outer scope or have it better passed explicitly.
Signed-off-by: Torsten Duwe <duwe@lst.de>
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index 2b14437f69c..98b9cec47d6 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -12,6 +12,7 @@
#include <log.h>
#include <malloc.h>
#include <memalign.h>
+#include <phys2bus.h>
#include <time.h>
#include <dm/device-internal.h>
#include <linux/compat.h>
@@ -27,6 +28,8 @@
#define IO_TIMEOUT 30
#define MAX_PRP_POOL 512
+#define BUS_ADDR(a) dev_phys_to_bus(dev->udev, (a))
+
static int nvme_wait_csts(struct nvme_dev *dev, u32 mask, u32 val)
{
int timeout;
@@ -91,12 +100,12 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
i = 0;
while (nprps) {
if ((i == (prps_per_page - 1)) && nprps > 1) {
- *(prp_pool + i) = cpu_to_le64((ulong)prp_pool +
- page_size);
+ *(prp_pool + i) = cpu_to_le64(BUS_ADDR((ulong)prp_pool +
+ page_size));
i = 0;
prp_pool += page_size;
}
- *(prp_pool + i++) = cpu_to_le64(dma_addr);
+ *(prp_pool + i++) = cpu_to_le64(BUS_ADDR(dma_addr));
dma_addr += page_size;
nprps--;
}
@@ -393,8 +406,8 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
dev->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES;
writel(aqa, &dev->bar->aqa);
- nvme_writeq((ulong)nvmeq->sq_cmds, &dev->bar->asq);
- nvme_writeq((ulong)nvmeq->cqes, &dev->bar->acq);
+ nvme_writeq(BUS_ADDR((ulong)nvmeq->sq_cmds), &dev->bar->asq);
+ nvme_writeq(BUS_ADDR((ulong)nvmeq->cqes), &dev->bar->acq);
result = nvme_enable_ctrl(dev);
if (result)
@@ -420,7 +436,7 @@ static int nvme_alloc_cq(struct nvme_dev *dev, u16 qid,
memset(&c, 0, sizeof(c));
c.create_cq.opcode = nvme_admin_create_cq;
- c.create_cq.prp1 = cpu_to_le64((ulong)nvmeq->cqes);
+ c.create_cq.prp1 = cpu_to_le64(BUS_ADDR((ulong)nvmeq->cqes));
c.create_cq.cqid = cpu_to_le16(qid);
c.create_cq.qsize = cpu_to_le16(nvmeq->q_depth - 1);
c.create_cq.cq_flags = cpu_to_le16(flags);
@@ -437,7 +453,7 @@ static int nvme_alloc_sq(struct nvme_dev *dev, u16 qid,
memset(&c, 0, sizeof(c));
c.create_sq.opcode = nvme_admin_create_sq;
- c.create_sq.prp1 = cpu_to_le64((ulong)nvmeq->sq_cmds);
+ c.create_sq.prp1 = cpu_to_le64(BUS_ADDR((ulong)nvmeq->sq_cmds));
c.create_sq.sqid = cpu_to_le16(qid);
c.create_sq.qsize = cpu_to_le16(nvmeq->q_depth - 1);
c.create_sq.sq_flags = cpu_to_le16(flags);
@@ -458,14 +474,14 @@ int nvme_identify(struct nvme_dev *dev, unsigned nsid,
memset(&c, 0, sizeof(c));
c.identify.opcode = nvme_admin_identify;
c.identify.nsid = cpu_to_le32(nsid);
- c.identify.prp1 = cpu_to_le64(dma_addr);
+ c.identify.prp1 = cpu_to_le64(BUS_ADDR(dma_addr));
length -= (page_size - offset);
if (length <= 0) {
c.identify.prp2 = 0;
} else {
dma_addr += (page_size - offset);
- c.identify.prp2 = cpu_to_le64(dma_addr);
+ c.identify.prp2 = cpu_to_le64(BUS_ADDR(dma_addr));
}
c.identify.cns = cpu_to_le32(cns);
@@ -490,7 +506,7 @@ int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
memset(&c, 0, sizeof(c));
c.features.opcode = nvme_admin_get_features;
c.features.nsid = cpu_to_le32(nsid);
- c.features.prp1 = cpu_to_le64(dma_addr);
+ c.features.prp1 = cpu_to_le64(BUS_ADDR(dma_addr));
c.features.fid = cpu_to_le32(fid);
ret = nvme_submit_admin_cmd(dev, &c, result);
@@ -516,7 +532,7 @@ int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
memset(&c, 0, sizeof(c));
c.features.opcode = nvme_admin_set_features;
- c.features.prp1 = cpu_to_le64(dma_addr);
+ c.features.prp1 = cpu_to_le64(BUS_ADDR(dma_addr));
c.features.fid = cpu_to_le32(fid);
c.features.dword11 = cpu_to_le32(dword11);
@@ -785,8 +805,8 @@ static ulong nvme_blk_rw(struct udevice *udev, lbaint_t blknr,
c.rw.slba = cpu_to_le64(slba);
slba += lbas;
c.rw.length = cpu_to_le16(lbas - 1);
- c.rw.prp1 = cpu_to_le64(temp_buffer);
- c.rw.prp2 = cpu_to_le64(prp2);
+ c.rw.prp1 = cpu_to_le64(BUS_ADDR(temp_buffer));
+ c.rw.prp2 = cpu_to_le64(BUS_ADDR(prp2));
status = nvme_submit_sync_cmd(dev->queues[NVME_IO_Q],
&c, NULL, IO_TIMEOUT);
if (status)
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [hack] help U-Boot find the correct PCIe inbound offset for NVMe on Raspberry Pi 5
2026-03-02 12:59 [PATCH v0] Fix NVMe for non-zero bus offsets Torsten Duwe
@ 2026-03-02 15:42 ` Torsten Duwe
2026-03-04 19:43 ` Pedro Falcato
0 siblings, 1 reply; 6+ messages in thread
From: Torsten Duwe @ 2026-03-02 15:42 UTC (permalink / raw)
To: Bin Meng, Andrew Goodbody
Cc: Peter Robinson, Matthias Brugger, Andrea della Porta, Tom Rini,
u-boot
On Mon, 2 Mar 2026 13:59:40 +0100
Torsten Duwe <duwe@lst.de> wrote:
> This proposed patch uses the already existent dev_phys_to_bus(),
> which can dig up the correct offset from associated DT nodes and
> subtract it.
Just to make it clear, that patch is a necessary but not a sufficient
condition to boot the RPi5 from NVMe. The PCIe bus node above
the NVMe is generated dynamically has no DT node with dma-ranges and so
dev_phys_to_bus() still returns zero. In order to test NVMe on the
RPi5 you can either:
hard code the 64GiB value when building your private U-Boot binary:
-#define BUS_ADDR(a) dev_phys_to_bus(dev->udev, (a))
+#define BUS_ADDR(a) ((a)+0x1000000000LL)
OR use this tricky DT change Andrea has prepared:
--- a/dts/upstream/src/arm64/broadcom/bcm2712.dtsi
+++ b/dts/upstream/src/arm64/broadcom/bcm2712.dtsi
@@ -571,6 +571,15 @@
<0x03000000 0xff 0xfffff000 0x10 0x00131000 0x00 0x00001000>;
status = "disabled";
+
+ pci@0,0 {
+ reg = <0x00 0x00 0x00 0x00 0x00>;
+ device_type = "pci";
+ #address-cells = <0x03>;
+ #size-cells = <0x02>;
+ ranges;
+ dma-ranges;
+ };
};
pcie2: pcie@1000120000 {
This pci@0,0 node needs to be below the pcie@1000110000 RC node so it
can "bridge" dev_phys_to_bus() to the RC node when it climbs up the
device tree and so helps it find the correct value.
AFAICS the proper fix should be to add some dma-ranges property when
dynamic PCI devices are created during enumeration/scan or make
dev_phys_to_bus() skip those nodes for the lookup.
Torsten
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [hack] help U-Boot find the correct PCIe inbound offset for NVMe on Raspberry Pi 5
2026-03-02 15:42 ` [hack] help U-Boot find the correct PCIe inbound offset for NVMe on Raspberry Pi 5 Torsten Duwe
@ 2026-03-04 19:43 ` Pedro Falcato
2026-03-04 20:24 ` Peter Robinson
2026-03-05 9:01 ` Matthias Brugger
0 siblings, 2 replies; 6+ messages in thread
From: Pedro Falcato @ 2026-03-04 19:43 UTC (permalink / raw)
To: Torsten Duwe
Cc: Bin Meng, Andrew Goodbody, Peter Robinson, Matthias Brugger,
Andrea della Porta, Tom Rini, u-boot
Hi Torsten,
On Mon, Mar 02, 2026 at 04:42:56PM +0100, Torsten Duwe wrote:
> On Mon, 2 Mar 2026 13:59:40 +0100
> Torsten Duwe <duwe@lst.de> wrote:
>
> > This proposed patch uses the already existent dev_phys_to_bus(),
> > which can dig up the correct offset from associated DT nodes and
> > subtract it.
>
> Just to make it clear, that patch is a necessary but not a sufficient
> condition to boot the RPi5 from NVMe. The PCIe bus node above
> the NVMe is generated dynamically has no DT node with dma-ranges and so
> dev_phys_to_bus() still returns zero. In order to test NVMe on the
> RPi5 you can either:
>
Say I wanted to test NVMe booting on the pi5 (which I actually do).
I would need:
1) this patch
2) one of the two BUS_ADDR() related diffs
3) the fixes posted in https://lore.kernel.org/u-boot/20251105163553.15F2A227AAC@verein.lst.de/
4) anything else?
Thanks,
Pedro
> hard code the 64GiB value when building your private U-Boot binary:
>
> -#define BUS_ADDR(a) dev_phys_to_bus(dev->udev, (a))
> +#define BUS_ADDR(a) ((a)+0x1000000000LL)
>
> OR use this tricky DT change Andrea has prepared:
>
> --- a/dts/upstream/src/arm64/broadcom/bcm2712.dtsi
> +++ b/dts/upstream/src/arm64/broadcom/bcm2712.dtsi
> @@ -571,6 +571,15 @@
> <0x03000000 0xff 0xfffff000 0x10 0x00131000 0x00 0x00001000>;
> status = "disabled";
> +
> + pci@0,0 {
> + reg = <0x00 0x00 0x00 0x00 0x00>;
> + device_type = "pci";
> + #address-cells = <0x03>;
> + #size-cells = <0x02>;
> + ranges;
> + dma-ranges;
> + };
> };
>
> pcie2: pcie@1000120000 {
>
> This pci@0,0 node needs to be below the pcie@1000110000 RC node so it
> can "bridge" dev_phys_to_bus() to the RC node when it climbs up the
> device tree and so helps it find the correct value.
>
> AFAICS the proper fix should be to add some dma-ranges property when
> dynamic PCI devices are created during enumeration/scan or make
> dev_phys_to_bus() skip those nodes for the lookup.
>
> Torsten
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [hack] help U-Boot find the correct PCIe inbound offset for NVMe on Raspberry Pi 5
2026-03-04 19:43 ` Pedro Falcato
@ 2026-03-04 20:24 ` Peter Robinson
2026-03-04 22:25 ` Torsten Duwe
2026-03-05 9:01 ` Matthias Brugger
1 sibling, 1 reply; 6+ messages in thread
From: Peter Robinson @ 2026-03-04 20:24 UTC (permalink / raw)
To: Pedro Falcato
Cc: Torsten Duwe, Bin Meng, Andrew Goodbody, Matthias Brugger,
Andrea della Porta, Tom Rini, u-boot
On Wed, 4 Mar 2026 at 19:43, Pedro Falcato <pfalcato@suse.de> wrote:
>
> Hi Torsten,
>
> On Mon, Mar 02, 2026 at 04:42:56PM +0100, Torsten Duwe wrote:
> > On Mon, 2 Mar 2026 13:59:40 +0100
> > Torsten Duwe <duwe@lst.de> wrote:
> >
> > > This proposed patch uses the already existent dev_phys_to_bus(),
> > > which can dig up the correct offset from associated DT nodes and
> > > subtract it.
> >
> > Just to make it clear, that patch is a necessary but not a sufficient
> > condition to boot the RPi5 from NVMe. The PCIe bus node above
> > the NVMe is generated dynamically has no DT node with dma-ranges and so
> > dev_phys_to_bus() still returns zero. In order to test NVMe on the
> > RPi5 you can either:
> >
>
> Say I wanted to test NVMe booting on the pi5 (which I actually do).
> I would need:
> 1) this patch
> 2) one of the two BUS_ADDR() related diffs
> 3) the fixes posted in https://lore.kernel.org/u-boot/20251105163553.15F2A227AAC@verein.lst.de/
I believe that series has been replaced with:
https://lore.kernel.org/u-boot/20260227152046.42DE068B05@verein.lst.de/T/#t
> 4) anything else?
Enable NVME support in the defconfig
> Thanks,
> Pedro
>
> > hard code the 64GiB value when building your private U-Boot binary:
> >
> > -#define BUS_ADDR(a) dev_phys_to_bus(dev->udev, (a))
> > +#define BUS_ADDR(a) ((a)+0x1000000000LL)
> >
> > OR use this tricky DT change Andrea has prepared:
> >
> > --- a/dts/upstream/src/arm64/broadcom/bcm2712.dtsi
> > +++ b/dts/upstream/src/arm64/broadcom/bcm2712.dtsi
> > @@ -571,6 +571,15 @@
> > <0x03000000 0xff 0xfffff000 0x10 0x00131000 0x00 0x00001000>;
> > status = "disabled";
> > +
> > + pci@0,0 {
> > + reg = <0x00 0x00 0x00 0x00 0x00>;
> > + device_type = "pci";
> > + #address-cells = <0x03>;
> > + #size-cells = <0x02>;
> > + ranges;
> > + dma-ranges;
> > + };
> > };
> >
> > pcie2: pcie@1000120000 {
> >
> > This pci@0,0 node needs to be below the pcie@1000110000 RC node so it
> > can "bridge" dev_phys_to_bus() to the RC node when it climbs up the
> > device tree and so helps it find the correct value.
> >
> > AFAICS the proper fix should be to add some dma-ranges property when
> > dynamic PCI devices are created during enumeration/scan or make
> > dev_phys_to_bus() skip those nodes for the lookup.
> >
> > Torsten
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [hack] help U-Boot find the correct PCIe inbound offset for NVMe on Raspberry Pi 5
2026-03-04 20:24 ` Peter Robinson
@ 2026-03-04 22:25 ` Torsten Duwe
0 siblings, 0 replies; 6+ messages in thread
From: Torsten Duwe @ 2026-03-04 22:25 UTC (permalink / raw)
To: Peter Robinson
Cc: Pedro Falcato, Bin Meng, Andrew Goodbody, Matthias Brugger,
Andrea della Porta, Tom Rini, u-boot
On Wed, 4 Mar 2026 20:24:35 +0000
Peter Robinson <pbrobinson@gmail.com> wrote:
> On Wed, 4 Mar 2026 at 19:43, Pedro Falcato <pfalcato@suse.de> wrote:
> >
> > Hi Torsten,
> >
> > On Mon, Mar 02, 2026 at 04:42:56PM +0100, Torsten Duwe wrote:
> > > On Mon, 2 Mar 2026 13:59:40 +0100
> > > Torsten Duwe <duwe@lst.de> wrote:
> > >
> > > > This proposed patch uses the already existent dev_phys_to_bus(),
> > > > which can dig up the correct offset from associated DT nodes and
> > > > subtract it.
> > >
> > > Just to make it clear, that patch is a necessary but not a sufficient
> > > condition to boot the RPi5 from NVMe. The PCIe bus node above
> > > the NVMe is generated dynamically has no DT node with dma-ranges and so
> > > dev_phys_to_bus() still returns zero. In order to test NVMe on the
> > > RPi5 you can either:
> > >
> >
> > Say I wanted to test NVMe booting on the pi5 (which I actually do).
> > I would need:
> > 1) this patch
> > 2) one of the two BUS_ADDR() related diffs
> > 3) the fixes posted in https://lore.kernel.org/u-boot/20251105163553.15F2A227AAC@verein.lst.de/
>
> I believe that series has been replaced with:
> https://lore.kernel.org/u-boot/20260227152046.42DE068B05@verein.lst.de/T/#t
Yes. Or on patchwork: https://patchwork.ozlabs.org/project/uboot/list/?series=493779
> > 4) anything else?
>
> Enable NVME support in the defconfig
NVME commands and NVME_PCI. CONFIG_NVME_PCI requires CONFIG_NVME.
Torsten
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [hack] help U-Boot find the correct PCIe inbound offset for NVMe on Raspberry Pi 5
2026-03-04 19:43 ` Pedro Falcato
2026-03-04 20:24 ` Peter Robinson
@ 2026-03-05 9:01 ` Matthias Brugger
1 sibling, 0 replies; 6+ messages in thread
From: Matthias Brugger @ 2026-03-05 9:01 UTC (permalink / raw)
To: Pedro Falcato, Torsten Duwe
Cc: Bin Meng, Andrew Goodbody, Peter Robinson, Andrea della Porta,
Tom Rini, u-boot
On 04/03/2026 20:43, Pedro Falcato wrote:
> Hi Torsten,
>
> On Mon, Mar 02, 2026 at 04:42:56PM +0100, Torsten Duwe wrote:
>> On Mon, 2 Mar 2026 13:59:40 +0100
>> Torsten Duwe <duwe@lst.de> wrote:
>>
>>> This proposed patch uses the already existent dev_phys_to_bus(),
>>> which can dig up the correct offset from associated DT nodes and
>>> subtract it.
>>
>> Just to make it clear, that patch is a necessary but not a sufficient
>> condition to boot the RPi5 from NVMe. The PCIe bus node above
>> the NVMe is generated dynamically has no DT node with dma-ranges and so
>> dev_phys_to_bus() still returns zero. In order to test NVMe on the
>> RPi5 you can either:
>>
>
> Say I wanted to test NVMe booting on the pi5 (which I actually do).
> I would need:
> 1) this patch
> 2) one of the two BUS_ADDR() related diffs
> 3) the fixes posted in https://lore.kernel.org/u-boot/20251105163553.15F2A227AAC@verein.lst.de/
> 4) anything else?
>
Just as a heads-up. If you interested to test this on openSUSE, you can install
uboot-rpiarm64 and raspberrypi-firmware-dt package from this open build service
project:
https://build.opensuse.org/project/show/home:mbrugger:branches:RPi5
That has both series on top of v2026.01 (plus other openSUSE stuff) and the DT
patch.
Regards,
Matthias
> Thanks,
> Pedro
>
>> hard code the 64GiB value when building your private U-Boot binary:
>>
>> -#define BUS_ADDR(a) dev_phys_to_bus(dev->udev, (a))
>> +#define BUS_ADDR(a) ((a)+0x1000000000LL)
>>
>> OR use this tricky DT change Andrea has prepared:
>>
>> --- a/dts/upstream/src/arm64/broadcom/bcm2712.dtsi
>> +++ b/dts/upstream/src/arm64/broadcom/bcm2712.dtsi
>> @@ -571,6 +571,15 @@
>> <0x03000000 0xff 0xfffff000 0x10 0x00131000 0x00 0x00001000>;
>> status = "disabled";
>> +
>> + pci@0,0 {
>> + reg = <0x00 0x00 0x00 0x00 0x00>;
>> + device_type = "pci";
>> + #address-cells = <0x03>;
>> + #size-cells = <0x02>;
>> + ranges;
>> + dma-ranges;
>> + };
>> };
>>
>> pcie2: pcie@1000120000 {
>>
>> This pci@0,0 node needs to be below the pcie@1000110000 RC node so it
>> can "bridge" dev_phys_to_bus() to the RC node when it climbs up the
>> device tree and so helps it find the correct value.
>>
>> AFAICS the proper fix should be to add some dma-ranges property when
>> dynamic PCI devices are created during enumeration/scan or make
>> dev_phys_to_bus() skip those nodes for the lookup.
>>
>> Torsten
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-03-05 9:01 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-02 12:59 [PATCH v0] Fix NVMe for non-zero bus offsets Torsten Duwe
2026-03-02 15:42 ` [hack] help U-Boot find the correct PCIe inbound offset for NVMe on Raspberry Pi 5 Torsten Duwe
2026-03-04 19:43 ` Pedro Falcato
2026-03-04 20:24 ` Peter Robinson
2026-03-04 22:25 ` Torsten Duwe
2026-03-05 9:01 ` Matthias Brugger
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.