Re: [PATCH] PCI: rcar-gen4: Limit Max_Read_Request_Size and Max_Payload_Size to 256 Bytes
From: Manivannan Sadhasivam
Date: Mon May 11 2026 - 10:36:56 EST
On Sun, Apr 26, 2026 at 01:38:28AM +0200, Marek Vasut wrote:
> R-Car Gen4 PCIe controller has a hardware limitation of 256 Bytes
> maximum payload size. The PCIe DMA generates requests of size up
> to minimum(Max_Read_Request_Size, Max_Payload_Size). Force limit
> both Max_Read_Request_Size and Max_Payload_Size to 256 Bytes and
> propagate this limit to all downstream devices.
>
> This limitation can be triggered for example by using an NVMe SSD
> which does not use host memory buffer, Samsung 980 PRO is such an
> SSD. Affected SSD reports 'hmpre' field as 0:
> "
> $ nvme id-ctrl /dev/nvme0 | grep hmpre
> hmpre : 0
> "
>
> 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.
> "
> $ dd if=/dev/urandom of=/tmp/data.bin bs=256 count=2 \
> dd if=/tmp/data.bin of=/dev/nvme0n1 bs=256 count=2 \
> dd if=/dev/nvme0n1 bs=256 count=2 of=/tmp/readback.bin
> "
>
> Expected data:
> "
> $ hexdump -vC /tmp/data.bin
> 00000000 97 81 b7 3b 0e 38 2b 4d a7 d3 e0 47 ff c2 4b ca
> 00000010 c1 85 98 f0 4a ac 03 a0 3b ab f3 19 44 dd 06 8b
> ...
> 00000100 7a ce 3c b2 e1 d5 d9 11 88 63 10 59 76 3c dc 32 <-- random
> 00000110 72 32 2a 7d a3 e1 aa 13 7c da 58 a1 7b 21 11 50 <-- data
> "
>
> Faulty readback, collected without this change in place:
> "
> $ hexdump -vC /tmp/readback.bin
> 00000000 97 81 b7 3b 0e 38 2b 4d a7 d3 e0 47 ff c2 4b ca <---.
> 00000010 c1 85 98 f0 4a ac 03 a0 3b ab f3 19 44 dd 06 8b <-. |
> ... | |
> 00000100 97 81 b7 3b 0e 38 2b 4d a7 d3 e0 47 ff c2 4b ca <-:-+- repeated
> 00000110 c1 85 98 f0 4a ac 03 a0 3b ab f3 19 44 dd 06 8b <-+--- data
> ^^^
> |
> '--- Repeat starts at offset 0x100 = 256 Bytes
> "
>
> Fixes: 0d0c551011df ("PCI: rcar-gen4: Add R-Car Gen4 PCIe controller support for host mode")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Marek Vasut <marek.vasut+renesas@xxxxxxxxxxx>
> ---
> Cc: "Krzysztof Wilczyński" <kwilczynski@xxxxxxxxxx>
> Cc: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
> Cc: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
> Cc: Koichiro Den <den@xxxxxxxxxxxxx>
> Cc: Lorenzo Pieralisi <lpieralisi@xxxxxxxxxx>
> Cc: Magnus Damm <magnus.damm@xxxxxxxxx>
> Cc: Manivannan Sadhasivam <mani@xxxxxxxxxx>
> Cc: Rob Herring <robh@xxxxxxxxxx>
> Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@xxxxxxxxxxx>
> Cc: linux-kernel@xxxxxxxxxxxxxxx
> Cc: linux-pci@xxxxxxxxxxxxxxx
> Cc: linux-renesas-soc@xxxxxxxxxxxxxxx
> ---
> drivers/pci/controller/dwc/pcie-rcar-gen4.c | 56 +++++++++++++++++++++
> 1 file changed, 56 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> index 8b03c42f8c84c..82f0a074a71da 100644
> --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> @@ -576,6 +576,7 @@ static int r8a779f0_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable)
> static void rcar_gen4_pcie_additional_common_init(struct rcar_gen4_pcie *rcar)
> {
> struct dw_pcie *dw = &rcar->dw;
> + u16 offset = dw_pcie_find_capability(dw, PCI_CAP_ID_EXP);
> u32 val;
>
> val = dw_pcie_readl_dbi(dw, PCIE_PORT_LANE_SKEW);
> @@ -584,11 +585,66 @@ static void rcar_gen4_pcie_additional_common_init(struct rcar_gen4_pcie *rcar)
> val |= BIT(6);
> dw_pcie_writel_dbi(dw, PCIE_PORT_LANE_SKEW, val);
>
> + val = dw_pcie_readl_dbi(dw, offset + PCI_EXP_DEVCTL);
> + val &= ~(PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ);
> + val |= PCI_EXP_DEVCTL_PAYLOAD_256B | PCI_EXP_DEVCTL_READRQ_256B;
> + dw_pcie_writel_dbi(dw, offset + PCI_EXP_DEVCTL, val);
Instead of limiting the MRRS/MPS values for all devices through quirks, why
can't you just limit the Root Port's MPSS value in PCI_EXP_DEVCAP?
- Mani
> +
> val = readl(rcar->base + PCIEPWRMNGCTRL);
> val |= APP_CLK_REQ_N | APP_CLK_PM_EN;
> writel(val, rcar->base + PCIEPWRMNGCTRL);
> }
>
> +static void rcar_gen4_rc_pcie_quirk(struct pci_dev *dev)
> +{
> + static const struct pci_device_id rcar_gen4_pcie_rc_devid = {
> + PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0030),
> + .class = PCI_CLASS_BRIDGE_PCI_NORMAL, .class_mask = ~0
> + };
> + struct pci_bus *bus = dev->bus;
> + struct pci_dev *bridge;
> +
> + if (pci_is_root_bus(bus))
> + bridge = dev;
> +
> + /* Look for the host bridge */
> + while (!pci_is_root_bus(bus)) {
> + bridge = bus->self;
> + bus = bus->parent;
> + }
> +
> + if (!bridge)
> + return;
> +
> + if (!pci_match_one_device(&rcar_gen4_pcie_rc_devid, bridge))
> + return;
> +
> + /*
> + * R-Car Gen4 PCIe controller has a hardware limitation of 256 Bytes
> + * maximum payload size. The PCIe DMA generates requests of size up
> + * to minimum(Max_Read_Request_Size, Max_Payload_Size). Force limit
> + * both Max_Read_Request_Size and Max_Payload_Size to 256 Bytes and
> + * propagate this limit to all downstream devices.
> + *
> + * For details, refer to:
> + * R-Car S4 R19UH0161EJ0130 Rev.1.30 Jun. 16, 2025 or
> + * R-Car V4H R19UH0186EJ0130 Rev.1.30 Apr. 21, 2025 or
> + * R-Car V4M R19UH0217EJ0100 Rev.1.00 Dec. 12, 2025,
> + * chapters 104.1.1 Features and 104.3.9 DMA Transfer
> + * section DMA Read Transfer.
> + */
> + if (pcie_get_readrq(dev) > 256) {
> + dev_info(&dev->dev, "Limiting MRRS to 256 bytes\n");
> + pcie_set_readrq(dev, 256);
> + }
> +
> + if (pcie_get_mps(dev) > 256) {
> + dev_info(&dev->dev, "Limiting MPS to 256 bytes\n");
> + pcie_set_mps(dev, 256);
> + }
> +}
> +DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, rcar_gen4_rc_pcie_quirk);
> +
> static void rcar_gen4_pcie_phy_reg_update_bits(struct rcar_gen4_pcie *rcar,
> u32 offset, u32 mask, u32 val)
> {
> --
> 2.53.0
>
>
--
மணிவண்ணன் சதாசிவம்