Forum Discussion
Bug! Quartus Pro 20.1.1, Cyclone V, utilizing PCIe example from 16.1.
- 5 years ago
I got it working.
The last hurdle was the MSI interface. I'm not sure why it wasn't working, but restarting the design from scratch with my recently acquired knowledge got everything working.
I've attached my qsys file and socfpga.dtsi. Hopefully it will help others get a jump on things so they don't have to learn everything the hard way as I did.
This design is not optimized for speed, nor is it optimized for space.
NVMe read speed is around 80 MB/s.
NVMe write speed is around 50 MB/s.
Faster drives will do a little better, but even the over a gig per second on PC 4 lane part I have doesn't do much better than 110 MB/s read. Bandwidth is limited by the ARM memory interface and the fact that bursting logic at 125MHz causes timing violations. A burst length of one on the Txs interface has got to slow things down.
Performance is quoted with the 5.11 kernel, the 5.4 kernel is not quite as fast. Still fast enough for an embedded system though.
Don't forget to enable the fpga, pcie and msi modules in your top level board dts file.
And don't forget to reserve the first 64K of DRAM as stated above. If you don't you will get read errors.
There are probably better configurations, and eventually I'll probably try to optimize for size since my logic will need to get bigger on the next project. But for now. It finally works.
Good luck to you all.
It's almost completely working. There is one problem left. First let me summarize something that people may not know.
With Cyclone V pcie controller, there is no way to specify dma-ranges with the 5.4 kernel. It does nothing. However, on kernel 5.11 dma-ranges can be set and if you set it, the pci device driver will crash.
There is a problem with read errors from pcie devices. I fixed this by adding this to the top of my board device tree dts file:
(Long comment above it, code after)
// Reserve the first 64KB cause the pcie driver doesn't know better? // Assumption: the pcie driver overwrites the vector table. // If this is not present, the nvme has read errors. // The kernel complains about the reservation, but does it: // "ERROR: reserving fdt memory region failed (addr=0 size=10000)" // You can see it reserved the memory in iomem: // root@cyclone5:~# cat /proc/iomem // 00010000-001fffff : System RAM // 00200000-3fffffff : System RAM // 00d00000-00daf47f : Kernel data // ff700000-ff701fff : ff700000.ethernet ethernet@ff700000 // ff702000-ff703fff : ff702000.ethernet ethernet@ff702000 // ff704000-ff704fff : ff704000.dwmmc0 dwmmc0@ff704000 // ff705000-ff705fff : ff705000.spi spi@ff705000 // ff706000-ff706fff : ff706000.fpgamgr fpgamgr@ff706000 // ff709000-ff709fff : ff709000.gpio gpio@ff709000 // ffa00000-ffa00fff : ff705000.spi spi@ff705000 // ffb90000-ffb90003 : ff706000.fpgamgr fpgamgr@ff706000 // ffc02000-ffc0201f : serial // ffc03000-ffc0301f : serial // ffc04000-ffc04fff : ffc04000.i2c i2c@ffc04000 // ffc05000-ffc05fff : ffc05000.i2c i2c@ffc05000 // ffd02000-ffd02fff : ffd02000.watchdog watchdog@ffd02000 // ffd05000-ffd05fff : rstmgr // ffd08140-ffd08143 : ffd08140.l2-ecc // ffe01000-ffe01fff : pdma@ffe01000 // ffff0000-ffffffff : ffff0000.sram reserved-memory { #address-cells = <1>; #size-cells = <1>; ranges; pcidma1@0 { reg = <0x00000000 0x00010000>; no-map; }; };
Note: The 5.4 kernel reserves exactly 64K for the vector table and stops the read errors. The 5.11 kernel reserves 2 MegaBytes and also stops the read errors. I do not understand this issue, but this is the work around.
I believe this only applies to Cyclone V which has an ARMv5 whose vector table is not movable. I suspect the kernel is not protecting the vector table from PCIe writes, unless the dts specifically reserves the memory. But this is just a guess. A kernel guru needs to be consulted to be sure.
I have a very simplified design that works well, almost. There are interrupt issues which I haven't been able to get past. I have the help of a linux driver expert and he suspects the hardware is misbehaving.
The failure:
When doing extensive writes to the NVMe, the following messages are generated and if the timeout is set to 30 seconds, each of them represents a 30 second delay.
root@cyclone5:~# ./test_nvme.sh [ 75.836736] nvme nvme0: I/O 904 QID 1 timeout, completion polled [ 75.981635] EXT4-fs (nvme0n1p1): mounted filesystem with ordered data mode. Opts: (null). Quota mode: disabled. Starting Trace... [ 82.826885] nvme nvme0: I/O 896 QID 1 timeout, completion polled [ 85.116846] nvme nvme0: I/O 928 QID 1 timeout, completion polled [ 86.156823] nvme nvme0: I/O 998 QID 1 timeout, completion polled [ 87.196816] nvme nvme0: I/O 928 QID 1 timeout, completion polled [ 88.236805] nvme nvme0: I/O 929 QID 1 timeout, completion polled [ 89.276824] nvme nvme0: I/O 928 QID 1 timeout, completion polled root@cyclone5:~# grep timeout nvme_ nvme_full_2021_03_23_debug.log nvme_full_2021_03_25_debug.log nvme_full_2021_03_26_debug.log nvme_trace_2021_0323.log nvme_full_2021_03_24_debug.log nvme_full_2021_03_25b_debug.log nvme_trace.log root@cyclone5:~# grep timeout nvme_full_2021_03_26_debug.log kworker/0:2H-76 [000] .... 27.676716: nvme_timeout: qid: 1, tag: 98, completed: 4 kworker/0:2H-76 [000] .... 75.836728: nvme_timeout: qid: 1, tag: 904, completed: 1 kworker/1:1H-50 [001] .... 82.826875: nvme_timeout: qid: 1, tag: 896, completed: 65 kworker/0:2H-76 [000] .... 85.116834: nvme_timeout: qid: 1, tag: 928, completed: 65 kworker/0:2H-76 [000] .... 86.156812: nvme_timeout: qid: 1, tag: 998, completed: -961 kworker/0:2H-76 [000] .... 87.196806: nvme_timeout: qid: 1, tag: 928, completed: 64 kworker/0:2H-76 [000] .... 88.236793: nvme_timeout: qid: 1, tag: 929, completed: 65 kworker/0:2H-76 [000] .... 89.276815: nvme_timeout: qid: 1, tag: 928, completed: 57
The trace is generated by patches applied to drivers within the kernel.
Some NVMe's have less issue with this than others.
I have noticed that the MSI and MSI-X interrupts are not being used and I suspect this is related to the issue.
This is lspci -v for my laptops nvme controller:
02:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller SM981/PM981/PM983 (prog-if 02 [NVM Express]) Subsystem: Samsung Electronics Co Ltd NVMe SSD Controller SM981/PM981/PM983 Flags: bus master, fast devsel, latency 0, IRQ 31, NUMA node 0 Memory at d1800000 (64-bit, non-prefetchable) [size=16K] Capabilities: [40] Power Management version 3 Capabilities: [50] MSI: Enable- Count=1/32 Maskable- 64bit+ Capabilities: [70] Express Endpoint, MSI 00 Capabilities: [b0] MSI-X: Enable+ Count=33 Masked- Capabilities: [100] Advanced Error Reporting Capabilities: [148] Device Serial Number 00-00-00-00-00-00-00-00 Capabilities: [158] Power Budgeting <?> Capabilities: [168] Secondary PCI Express Capabilities: [188] Latency Tolerance Reporting Capabilities: [190] L1 PM Substates Kernel driver in use: nvme
Notice MSI-X Enable has a '+' sign after it. Here is the output of lspci -v for the Cyclone V
00:00.0 PCI bridge: Altera Corporation Device e000 (rev 01) (prog-if 00 [Normal decode]) Flags: bus master, fast devsel, latency 0 Bus: primary=00, secondary=01, subordinate=01, sec-latency=0 I/O behind bridge: 00000000-00000fff [size=4K] Memory behind bridge: 00000000-000fffff [size=1M] Prefetchable memory behind bridge: 00000000-000fffff [size=1M] Capabilities: [50] MSI: Enable- Count=1/4 Maskable- 64bit+ Capabilities: [68] MSI-X: Enable- Count=513 Masked- Capabilities: [78] Power Management version 3 Capabilities: [80] Express Root Port (Slot-), MSI 00 Capabilities: [100] Virtual Channel Capabilities: [200] Vendor Specific Information: ID=1172 Rev=0 Len=044 <?> lspci: Unable to load libkmod resources: error -12 01:00.0 Non-Volatile memory controller: Sandisk Corp WD Black 2018/PC SN520 NVMe SSD (rev 01) (prog-if 02 [NVM Express]) Subsystem: Sandisk Corp WD Black 2018/PC SN520 NVMe SSD Flags: bus master, fast devsel, latency 0, IRQ 57 [virtual] Memory at c0000000 (64-bit, non-prefetchable) [size=16K] Capabilities: [80] Power Management version 3 Capabilities: [90] MSI: Enable- Count=1/32 Maskable- 64bit+ Capabilities: [b0] MSI-X: Enable- Count=17 Masked- Capabilities: [c0] Express Endpoint, MSI 00 Capabilities: [100] Advanced Error Reporting Capabilities: [150] Device Serial Number 00-00-00-00-00-00-00-00 Capabilities: [1b8] Latency Tolerance Reporting Capabilities: [300] Secondary PCI Express <?> Capabilities: [900] L1 PM Substates Kernel driver in use: nvme
Notice that MSI Enable and MSI-X Enable have '-' minus signs after them.
I thought that maybe I have to enable the msi driver in the kernel, but I think the pcie-altera-msi driver is not used for the Avalon-MM PCIe controller because it is designed for the stand alone MSI to GIC module.
How do I get MSI / MSI-X to enable with the pcie-altera driver?
Thanks for your support.
Brian
I got it working.
The last hurdle was the MSI interface. I'm not sure why it wasn't working, but restarting the design from scratch with my recently acquired knowledge got everything working.
I've attached my qsys file and socfpga.dtsi. Hopefully it will help others get a jump on things so they don't have to learn everything the hard way as I did.
This design is not optimized for speed, nor is it optimized for space.
NVMe read speed is around 80 MB/s.
NVMe write speed is around 50 MB/s.
Faster drives will do a little better, but even the over a gig per second on PC 4 lane part I have doesn't do much better than 110 MB/s read. Bandwidth is limited by the ARM memory interface and the fact that bursting logic at 125MHz causes timing violations. A burst length of one on the Txs interface has got to slow things down.
Performance is quoted with the 5.11 kernel, the 5.4 kernel is not quite as fast. Still fast enough for an embedded system though.
Don't forget to enable the fpga, pcie and msi modules in your top level board dts file.
And don't forget to reserve the first 64K of DRAM as stated above. If you don't you will get read errors.
There are probably better configurations, and eventually I'll probably try to optimize for size since my logic will need to get bigger on the next project. But for now. It finally works.
Good luck to you all.