Skip to contentSkip to conversation

pci: pcie-rcar-gen4: Limit Max_Read_Request_Size to 256 Bytes

PATCH New Marek Vasut 1 participant 1 message Nov 11

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 pci: pcie-rcar-gen4: Limit Max_Read_Request_Size to 256 Bytes

R-Car Gen4 PCIe controller has a hardware limitation of 256 Bytes Max_Payload_Size (MPS). PCIe specification indicates that the MPS must not exceed minimum MPS of any element along the packet path. Add a check to warn if MPS is ever set larger than 256.

R-Car Gen4 Reference Manual, chapter 104.4.8 Usage notes for MRRS (Max Read Request Size) states:

Please set "Max Read Request Size" to 128 bytes or 256 bytes. If "Max Read Request Size" is set to anything other than the above, the transferred data will not match the expected value.

This limitation also seems to apply to devices doing DMA reads, i.e. issuing MRd TLPs. This limitation can be triggered by using non-HMB NVMe SSD with Max_Read_Request_Size 512 Bytes, for example Crucial P5 Plus. Any write to the SSD (MRd TLP issued by the SSD controller) longer than 256 Bytes wraps around at the 256 Byte boundary, and the same data are written to the SSD starting at offset 0 and at 256 Bytes.

Limit Max_Read_Request_Size to at most 256 Bytes for each device connected to this PCIe controller to avoid this behavior.

The symptom is a read from the SSD which wraps around at 256 Byte boundary. The test for this symptom can be implemented by writing 512 Byte of random data into the SSD and reading the data back. If the read back data repeat after 256 Bytes, the device is affected.

Test:
"

    => pci enum

    => pci
    BusDevFun  VendorId   DeviceId   Device Class       Sub-Class
    _____________________________________________________________
    00.00.00   0x1912     0x0030     Bridge device           0x04
    02.00.00   0x1912     0x0030     Bridge device           0x04
    01.00.00   0xc0a9     0x5407     Mass storage controller 0x08
    03.00.00   0x1912     0x0014     Serial bus controller   0x03

    => nvme scan
    => nvme info
    Device 0: Vendor: 0xc0a9 Rev: P7CR403  Prod: 22323A68A6D7
                Type: Hard Disk
                Capacity: 476940.0 MB = 465.7 GB (976773168 x 512)

Before:

    # Display SSD PCIe capability DEVCTL Max_Read_Request_Size
    => pci display.w 01.00.00 0 0x38
    ...
    00000060: 0010 0002 8fe2 1000 2810 0000 f844 0045
                                  ^
                         EXPCAP DEVCTL MRRS 512B

    # Generate 256B + 256B of different data in DRAM and write them to the SSD
    => mw 0x54000000 0x1234abcd 0x40
    => mw 0x54000100 0xfedc5678 0x40
    => nvme write 0x54000000 0 2

    # Read data back and print the data
    => nvme read 0x58000000 0 2
    => md 0x58000000 0x4
    => md 0x58000100 0x4
    58000000: 1234abcd 1234abcd 1234abcd 1234abcd
    58000100: 1234abcd 1234abcd 1234abcd 1234abcd <--- faulty 256B wrap around

After:

    # Display SSD PCIe capability DEVCTL Max_Read_Request_Size
    => pci display.w 01.00.00 0 0x38
    ...
    00000060: 0010 0002 8fe2 1000 1810 0009 f844 0045
                                  ^
                         EXPCAP DEVCTL MRRS 256B

    # Generate 256B + 256B of different data in DRAM and write them to the SSD
    => mw 0x54000000 0x1234abcd 0x40
    => mw 0x54000100 0xfedc5678 0x40
    => nvme write 0x54000000 0 2

    # Read data back and print the data
    => nvme read 0x58000000 0 2
    => md 0x58000000 0x4
    => md 0x58000100 0x4
    58000000: 1234abcd 1234abcd 1234abcd 1234abcd
    58000100: fedc5678 fedc5678 fedc5678 fedc5678 <--- correct content

"

Ported from Linux commit f0a5c6bd797c ("PCI: rcar-gen4: Limit Max_Read_Request_Size to 256 Bytes")

---
Cc: Neil Armstrong <[email protected]>
Cc: Nobuhiro Iwamatsu <[email protected]>
Cc: Tom Rini <[email protected]>
Cc: [email protected]

---
 drivers/pci/pci-rcar-gen4.c | 111 ++++++++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)
drivers/pci/pci-rcar-gen4.c +111 -0
index b1d43b2e7aa..89a3772870a 100644
@@ -400,6 +400,112 @@ static int rcar_gen4_pcie_load_firmware(struct rcar_gen4_pcie *rcar)
 	return ret;
 }
 
+static int rcar_gen4_pcie_post_probe(void *ctx, struct event *event)
+{
+	struct udevice *dev, *bus = event->data.dm.dev;
+	int pcie_off, ret;
+	u16 devctl;
+
+	if (!bus || !bus->driver)
+		return 0;
+
+	if (bus->driver->id != UCLASS_PCI && bus->driver->id != UCLASS_PCI_GENERIC)
+		return 0;
+
+	if (dev_has_ofnode(bus) && dev_read_bool(bus, "pci,no-autoconfig"))
+		return 0;
+
+	pcie_off = dm_pci_find_capability(bus, PCI_CAP_ID_EXP);
+	if (!pcie_off)
+		return 0;
+
+	dm_pci_read_config16(bus, pcie_off + PCI_EXP_DEVCTL, &devctl);
+	/*
+	 * R-Car Gen4 PCIe controller has a hardware limitation of 256 Bytes
+	 * Max_Payload_Size (MPS). PCIe specification indicates that the MPS
+	 * must not exceed minimum MPS of any element along the packet path.
+	 * The controller reports Max_Payload_Size_Supported (MPSS) 256 Bytes
+	 * for header type 0 and 128 Bytes for header type 1. The PCIe core
+	 * will not allow MPS to be set higher than MPSS; warn here in case
+	 * something went very wrong in the core.
+	 *
+	 * For details, refer to chapter "104.1.1 Features" in either of:
+	 * R-Car S4 R19UH0161EJ0140 Rev.1.40 Jul. 31, 2026 or
+	 * R-Car V4H R19UH0186EJ0140 Rev.1.40 Aug. 7, 2026 or
+	 * R-Car V4M R19UH0217EJ0110 Rev.1.10 Jun. 30, 2026.
+	 */
+	if ((devctl & PCI_EXP_DEVCTL_PAYLOAD) > PCI_EXP_DEVCTL_PAYLOAD_256B) {
+		/* Controller MPS should already be 256B or less. */
+		dev_err(bus, "MPS over limit, DEVCTL=0x%04x\n", devctl);
+		ret = dm_pci_clrset_config16(bus, pcie_off + PCI_EXP_DEVCTL,
+					     PCI_EXP_DEVCTL_PAYLOAD, PCI_EXP_DEVCTL_PAYLOAD_256B);
+		if (ret)
+			dev_err(bus, "MPS update failed, ret=%d\n", ret);
+	}
+
+	/*
+	 * R-Car Gen4 Reference Manual, chapter 104.4.8 Usage notes for
+	 * MRRS (Max Read Request Size) states:
+	 *
+	 *   Please set "Max Read Request Size" to 128 bytes or 256 bytes.
+	 *   If "Max Read Request Size" is set to anything other than the
+	 *   above, the transferred data will not match the expected value.
+	 *
+	 * This limitation also seems to apply to devices issuing MRd TLPs.
+	 * This limitation can be triggered by using non-HMB NVMe SSD with
+	 * Max_Read_Request_Size 512 Bytes, for example Crucial P5 Plus.
+	 * Any write into the SSD (MRd TLP issued by the SSD) longer than
+	 * 256 Bytes wraps around at 256 Byte boundary, and the same data
+	 * are written into the SSD starting at offset 0 and at 256 Bytes.
+	 *
+	 * Limit Max_Read_Request_Size to at most 256 Bytes for each
+	 * device connected to this PCIe controller to avoid this behavior.
+	 *
+	 * For details, refer to aforementioned chapter in either of:
+	 * R-Car S4 R19UH0161EJ0140 Rev.1.40 Jul. 31, 2026 or
+	 * R-Car V4H R19UH0186EJ0140 Rev.1.40 Aug. 7, 2026 or
+	 * R-Car V4M R19UH0217EJ0110 Rev.1.10 Jun. 30, 2026.
+	 */
+	if ((devctl & PCI_EXP_DEVCTL_READRQ) > PCI_EXP_DEVCTL_READRQ_256B) {
+		ret = dm_pci_clrset_config16(bus, pcie_off + PCI_EXP_DEVCTL,
+					     PCI_EXP_DEVCTL_READRQ, PCI_EXP_DEVCTL_READRQ_256B);
+		if (ret)
+			dev_err(bus, "MRRS update failed, ret=%d\n", ret);
+	}
+
+	/* Apply aforementioned limits to downstream devices too. */
+	for (device_find_first_child(bus, &dev); dev; device_find_next_child(&dev)) {
+		if (dev_has_ofnode(dev) && dev_read_bool(dev, "pci,no-autoconfig"))
+			continue;
+
+		pcie_off = dm_pci_find_capability(dev, PCI_CAP_ID_EXP);
+		if (!pcie_off)
+			continue;
+
+		dm_pci_read_config16(dev, pcie_off + PCI_EXP_DEVCTL, &devctl);
+
+		if ((devctl & PCI_EXP_DEVCTL_PAYLOAD) > PCI_EXP_DEVCTL_PAYLOAD_256B) {
+			/* MPS should already be 256B or less. */
+			dev_err(dev, "MPS over limit, DEVCTL=0x%04x\n", devctl);
+			ret = dm_pci_clrset_config16(bus, pcie_off + PCI_EXP_DEVCTL,
+						     PCI_EXP_DEVCTL_PAYLOAD,
+						     PCI_EXP_DEVCTL_PAYLOAD_256B);
+			if (ret)
+				dev_err(dev, "MPS update failed, ret=%d\n", ret);
+		}
+
+		if ((devctl & PCI_EXP_DEVCTL_READRQ) > PCI_EXP_DEVCTL_READRQ_256B) {
+			ret = dm_pci_clrset_config16(dev, pcie_off + PCI_EXP_DEVCTL,
+						     PCI_EXP_DEVCTL_READRQ,
+						     PCI_EXP_DEVCTL_READRQ_256B);
+			if (ret)
+				dev_err(dev, "MRRS update failed, ret=%d\n", ret);
+		}
+	}
+
+	return 0;
+}
+
 /**
  * rcar_gen4_pcie_probe() - Probe the PCIe bus for active link
  *
@@ -449,6 +555,11 @@ static int rcar_gen4_pcie_probe(struct udevice *dev)
 	if (IS_ERR(rcar->pe_rst))
 		return PTR_ERR(rcar->pe_rst);
 
+	ret = event_register("pcie post probe", EVT_DM_POST_PROBE,
+			     rcar_gen4_pcie_post_probe, dev);
+	if (ret)
+		return ret;
+
 	ret = rcar_gen4_pcie_host_init(dev);
 	if (ret)
 		return ret;
Signature · 1 line
2.53.0