diff options
| author | Bjorn Helgaas <bhelgaas@google.com> | 2026-09-03 12:38:57 -0500 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2026-09-03 12:38:57 -0500 |
| commit | 39ee38a9fa2eaeff030a6c865abb244597c091eb (patch) | |
| tree | 3643c4f0a12ce3df80161f74bc647b47bfbf4ad1 | |
| parent | b78e13e0dabf2685dd08627de78072dfaad93345 (diff) | |
| parent | 4ec1f12bb1ffdd75969f5ea88b22b65f113091c7 (diff) | |
| download | linux-next-39ee38a9fa2eaeff030a6c865abb244597c091eb.tar.gz linux-next-39ee38a9fa2eaeff030a6c865abb244597c091eb.zip | |
Merge branch 'pci/controller/dwc-rcar-gen4'
- Limit Max_Read_Request_Size to 256 to avoid hardware erratum (Marek
Vasut)
- Add a .post_deinit() callback to handle dw_pcie_ep_init() failures (Marek
Vasut)
* pci/controller/dwc-rcar-gen4:
PCI: rcar-gen4: Use .post_deinit() to handle dw_pcie_ep_init() failures
PCI: dwc: Add dw_pcie_ep_ops->post_deinit() callback
PCI: rcar-gen4: Limit Max_Read_Request_Size and Max_Payload_Size to 256 Bytes
| -rw-r--r-- | drivers/pci/controller/dwc/pcie-designware-ep.c | 8 | ||||
| -rw-r--r-- | drivers/pci/controller/dwc/pcie-designware.h | 1 | ||||
| -rw-r--r-- | drivers/pci/controller/dwc/pcie-rcar-gen4.c | 68 |
3 files changed, 70 insertions, 7 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index de8ee3db4360..1a3491b5003e 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -1194,6 +1194,9 @@ void dw_pcie_ep_deinit(struct dw_pcie_ep *ep) epc->mem->window.page_size); pci_epc_mem_exit(epc); + + if (ep->ops->post_deinit) + ep->ops->post_deinit(ep); } EXPORT_SYMBOL_GPL(dw_pcie_ep_deinit); @@ -1553,7 +1556,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) ep->page_size); if (ret < 0) { dev_err(dev, "Failed to initialize address space\n"); - return ret; + goto err_deinit; } ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, @@ -1568,6 +1571,9 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) err_exit_epc_mem: pci_epc_mem_exit(epc); +err_deinit: + if (ep->ops->post_deinit) + ep->ops->post_deinit(ep); return ret; } diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 0735ae940924..a53ac27cd244 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -475,6 +475,7 @@ struct dw_pcie_rp { struct dw_pcie_ep_ops { int (*pre_init)(struct dw_pcie_ep *ep); + void (*post_deinit)(struct dw_pcie_ep *ep); int (*init)(struct dw_pcie_ep *ep); int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no, unsigned int type, u16 interrupt_num); diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index fbe465a29068..5a076aa3f490 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -411,6 +411,57 @@ err: return ret; } +static int rcar_gen4_pcie_enable_device(struct pci_host_bridge *bridge, + struct pci_dev *dev) +{ + /* + * 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. + */ + WARN_ON(pcie_get_mps(dev) > 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 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. + */ + bridge->no_inc_mrrs = 1; + if (pcie_get_readrq(dev) > 256) { + pci_info(dev, "Limiting MRRS to 256 bytes\n"); + pcie_set_readrq(dev, 256); + } + + return 0; +} + /* Host mode */ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp) { @@ -418,6 +469,9 @@ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp) struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw); int ret; + if (pp->bridge) + pp->bridge->enable_device = rcar_gen4_pcie_enable_device; + gpiod_set_value_cansleep(dw->pe_rst, 1); ret = rcar_gen4_pcie_common_init(rcar); @@ -487,6 +541,8 @@ static int rcar_gen4_pcie_ep_pre_init(struct dw_pcie_ep *ep) struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw); int ret; + writel(0, rcar->base + PCIEDMAINTSTSEN); + ret = rcar_gen4_pcie_common_init(rcar); if (ret) return ret; @@ -496,8 +552,11 @@ static int rcar_gen4_pcie_ep_pre_init(struct dw_pcie_ep *ep) return 0; } -static void rcar_gen4_pcie_ep_deinit(struct rcar_gen4_pcie *rcar) +static void rcar_gen4_pcie_ep_post_deinit(struct dw_pcie_ep *ep) { + struct dw_pcie *dw = to_dw_pcie_from_ep(ep); + struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw); + writel(0, rcar->base + PCIEDMAINTSTSEN); rcar_gen4_pcie_common_deinit(rcar); } @@ -552,6 +611,7 @@ static unsigned int rcar_gen4_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep, static const struct dw_pcie_ep_ops pcie_ep_ops = { .pre_init = rcar_gen4_pcie_ep_pre_init, + .post_deinit = rcar_gen4_pcie_ep_post_deinit, .raise_irq = rcar_gen4_pcie_ep_raise_irq, .get_features = rcar_gen4_pcie_ep_get_features, .get_dbi_offset = rcar_gen4_pcie_ep_get_dbi_offset, @@ -570,16 +630,13 @@ static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar) ep->ops = &pcie_ep_ops; ret = dw_pcie_ep_init(ep); - if (ret) { - rcar_gen4_pcie_ep_deinit(rcar); + if (ret) return ret; - } ret = dw_pcie_ep_init_registers(ep); if (ret) { dev_err(dev, "Failed to initialize DWC endpoint registers\n"); dw_pcie_ep_deinit(ep); - rcar_gen4_pcie_ep_deinit(rcar); } pci_epc_init_notify(ep->epc); @@ -590,7 +647,6 @@ static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar) static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar) { dw_pcie_ep_deinit(&rcar->dw.ep); - rcar_gen4_pcie_ep_deinit(rcar); } /* Common */ |
