* [PATCH v2 1/5] dt-bindings: PCI: rcar-gen4-pci-host: Add R-Car X5H PCIe4 compatible
2026-07-20 2:02 [PATCH v2 0/5] PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4 Marek Vasut
@ 2026-07-20 2:02 ` Marek Vasut
2026-07-20 2:18 ` sashiko-bot
2026-07-20 2:02 ` [PATCH v2 2/5] PCI: dwc: rcar-gen4: Rework rcar_gen4_pcie_drvdata .additional_common_init into .init Marek Vasut
` (3 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Marek Vasut @ 2026-07-20 2:02 UTC (permalink / raw)
To: linux-pci
Cc: Marek Vasut, Krzysztof Kozlowski, Krzysztof Wilczyński,
Bjorn Helgaas, Conor Dooley, Geert Uytterhoeven,
Krzysztof Kozlowski, Lorenzo Pieralisi, Manivannan Sadhasivam,
Rob Herring, Yoshihiro Shimoda, devicetree, linux-kernel,
linux-renesas-soc
Document bindings for R-Car X5H (R8A78000) PCIe4 host module.
The binding document is deliberately using "renesas,rcar-gen5-pcie4"
DT compatible string to discern R-Car X5H PCIe4 controller supported
by this binding, from R-Car X5H PCIe6 controller which will use a
separate binding.
The R-Car X5H PCIe4 controller does no longer include PHY register
range, the PHY is now a separate IP and referenced via the 'phy' DT
property. The 'reg' and 'reg-names' DT properties therefore differ
between R-Car Gen4 PCIe and R-Car X5H PCIe4, and the difference is
handled in the allOf section.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
Cc: "Krzysztof Wilczyński" <kwilczynski@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Manivannan Sadhasivam <mani@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
V2: Add RB from Krzysztof
---
.../bindings/pci/rcar-gen4-pci-host.yaml | 74 +++++++++++++------
1 file changed, 52 insertions(+), 22 deletions(-)
diff --git a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
index 64f456c6a75a1..9767a52f3904e 100644
--- a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
+++ b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
@@ -10,30 +10,20 @@ title: Renesas R-Car Gen4 PCIe Host
maintainers:
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
-allOf:
- - $ref: snps,dw-pcie.yaml#
-
properties:
compatible:
- items:
- - enum:
- - renesas,r8a779f0-pcie # R-Car S4-8
- - renesas,r8a779g0-pcie # R-Car V4H
- - renesas,r8a779h0-pcie # R-Car V4M
- - const: renesas,rcar-gen4-pcie # R-Car Gen4
-
- reg:
- maxItems: 7
-
- reg-names:
- items:
- - const: dbi
- - const: dbi2
- - const: atu
- - const: dma
- - const: app
- - const: phy
- - const: config
+ oneOf:
+ - items:
+ - enum:
+ - renesas,r8a779f0-pcie # R-Car S4-8
+ - renesas,r8a779g0-pcie # R-Car V4H
+ - renesas,r8a779h0-pcie # R-Car V4M
+ - const: renesas,rcar-gen4-pcie # R-Car Gen4
+
+ - items:
+ - enum:
+ - renesas,r8a78000-pcie4 # R-Car X5H PCIe4
+ - const: renesas,rcar-gen5-pcie4 # R-Car Gen5 PCIe4
interrupts:
maxItems: 4
@@ -84,6 +74,46 @@ required:
- resets
- reset-names
+allOf:
+ - $ref: snps,dw-pcie.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,rcar-gen4-pcie
+ then:
+ properties:
+ reg:
+ maxItems: 7
+
+ reg-names:
+ items:
+ - const: dbi
+ - const: dbi2
+ - const: atu
+ - const: dma
+ - const: app
+ - const: phy
+ - const: config
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,rcar-gen5-pcie4
+ then:
+ properties:
+ reg:
+ maxItems: 6
+
+ reg-names:
+ items:
+ - const: dbi
+ - const: dbi2
+ - const: atu
+ - const: dma
+ - const: app
+ - const: config
+
unevaluatedProperties: false
examples:
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 2/5] PCI: dwc: rcar-gen4: Rework rcar_gen4_pcie_drvdata .additional_common_init into .init
2026-07-20 2:02 [PATCH v2 0/5] PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4 Marek Vasut
2026-07-20 2:02 ` [PATCH v2 1/5] dt-bindings: PCI: rcar-gen4-pci-host: Add R-Car X5H PCIe4 compatible Marek Vasut
@ 2026-07-20 2:02 ` Marek Vasut
2026-07-20 2:15 ` sashiko-bot
2026-07-20 2:02 ` [PATCH v2 3/5] PCI: dwc: rcar-gen4: Split .start_link into ltssm_control and speed_control Marek Vasut
` (2 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Marek Vasut @ 2026-07-20 2:02 UTC (permalink / raw)
To: linux-pci
Cc: Marek Vasut, Krzysztof Wilczyński, Bjorn Helgaas,
Conor Dooley, Geert Uytterhoeven, Krzysztof Kozlowski,
Lorenzo Pieralisi, Manivannan Sadhasivam, Rob Herring,
Yoshihiro Shimoda, devicetree, linux-kernel, linux-renesas-soc
Rework the current complicated initialization callchain that invokes
host_init->common_init->additional_common_init() for host and
ep_init->common_init->additional_common_init() for endpoint into
simpler host_init->init() and ep_init->init() .
The init callback is now always implmented for all R-Car Gen4 SoCs,
therefore there is no need to check whether the callback is not NULL.
For R-Car S4 the .init callback is rcar_gen4_pcie_common_init(),
for R-Car V4H and V4M the .init callback is implemented using a
new function rcar_gen4_v4h_v4m_pcie_init() which calls the common
rcar_gen4_pcie_common_init() followed by R-Car V4H and V4M specific
hardware initialization. The hardware initialization sequence remains
unchanged.
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
Cc: "Krzysztof Wilczyński" <kwilczynski@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Manivannan Sadhasivam <mani@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
V2: Rename additional_common_init to init, reworked from previous patch
PCI: dwc: rcar-gen4: Return error code from .additional_common_init
---
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 56 ++++++++++++---------
1 file changed, 32 insertions(+), 24 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 5f7211b91ee5b..5724f64eadfad 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -87,7 +87,7 @@ MODULE_FIRMWARE(RCAR_GEN4_PCIE_FIRMWARE_NAME);
struct rcar_gen4_pcie;
struct rcar_gen4_pcie_drvdata {
- void (*additional_common_init)(struct rcar_gen4_pcie *rcar);
+ int (*init)(struct rcar_gen4_pcie *rcar);
int (*ltssm_control)(struct rcar_gen4_pcie *rcar, bool enable);
enum dw_pcie_device_mode mode;
};
@@ -241,9 +241,6 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
reset_control_status(dw->core_rsts[DW_PCIE_PWR_RST].rstc);
fsleep(1000);
- if (rcar->drvdata->additional_common_init)
- rcar->drvdata->additional_common_init(rcar);
-
return 0;
err_unprepare:
@@ -252,6 +249,31 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
return ret;
}
+static int rcar_gen4_v4h_v4m_pcie_init(struct rcar_gen4_pcie *rcar)
+{
+ struct dw_pcie *dw = &rcar->dw;
+ u32 val;
+ int ret;
+
+ /* R-Car Gen4 common initialization. */
+ ret = rcar_gen4_pcie_common_init(rcar);
+ if (ret)
+ return ret;
+
+ /* R-Car V4H and V4M specific additional initialization. */
+ val = dw_pcie_readl_dbi(dw, PCIE_PORT_LANE_SKEW);
+ val &= ~PORT_LANE_SKEW_INSERT_MASK;
+ if (dw->num_lanes < 4)
+ val |= BIT(6);
+ dw_pcie_writel_dbi(dw, PCIE_PORT_LANE_SKEW, val);
+
+ val = readl(rcar->base + PCIEPWRMNGCTRL);
+ val |= APP_CLK_REQ_N | APP_CLK_PM_EN;
+ writel(val, rcar->base + PCIEPWRMNGCTRL);
+
+ return 0;
+}
+
static void rcar_gen4_pcie_common_deinit(struct rcar_gen4_pcie *rcar)
{
struct dw_pcie *dw = &rcar->dw;
@@ -420,7 +442,7 @@ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
gpiod_set_value_cansleep(dw->pe_rst, 1);
- ret = rcar_gen4_pcie_common_init(rcar);
+ ret = rcar->drvdata->init(rcar);
if (ret)
return ret;
@@ -487,7 +509,7 @@ static void rcar_gen4_pcie_ep_pre_init(struct dw_pcie_ep *ep)
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
int ret;
- ret = rcar_gen4_pcie_common_init(rcar);
+ ret = rcar->drvdata->init(rcar);
if (ret)
return;
@@ -681,22 +703,6 @@ static int r8a779f0_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable)
return 0;
}
-static void rcar_gen4_pcie_additional_common_init(struct rcar_gen4_pcie *rcar)
-{
- struct dw_pcie *dw = &rcar->dw;
- u32 val;
-
- val = dw_pcie_readl_dbi(dw, PCIE_PORT_LANE_SKEW);
- val &= ~PORT_LANE_SKEW_INSERT_MASK;
- if (dw->num_lanes < 4)
- val |= BIT(6);
- dw_pcie_writel_dbi(dw, PCIE_PORT_LANE_SKEW, val);
-
- val = readl(rcar->base + PCIEPWRMNGCTRL);
- val |= APP_CLK_REQ_N | APP_CLK_PM_EN;
- writel(val, rcar->base + PCIEPWRMNGCTRL);
-}
-
static void rcar_gen4_pcie_phy_reg_update_bits(struct rcar_gen4_pcie *rcar,
u32 offset, u32 mask, u32 val)
{
@@ -848,23 +854,25 @@ static int rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable
}
static struct rcar_gen4_pcie_drvdata drvdata_r8a779f0_pcie = {
+ .init = rcar_gen4_pcie_common_init,
.ltssm_control = r8a779f0_pcie_ltssm_control,
.mode = DW_PCIE_RC_TYPE,
};
static struct rcar_gen4_pcie_drvdata drvdata_r8a779f0_pcie_ep = {
+ .init = rcar_gen4_pcie_common_init,
.ltssm_control = r8a779f0_pcie_ltssm_control,
.mode = DW_PCIE_EP_TYPE,
};
static struct rcar_gen4_pcie_drvdata drvdata_rcar_gen4_pcie = {
- .additional_common_init = rcar_gen4_pcie_additional_common_init,
+ .init = rcar_gen4_v4h_v4m_pcie_init,
.ltssm_control = rcar_gen4_pcie_ltssm_control,
.mode = DW_PCIE_RC_TYPE,
};
static struct rcar_gen4_pcie_drvdata drvdata_rcar_gen4_pcie_ep = {
- .additional_common_init = rcar_gen4_pcie_additional_common_init,
+ .init = rcar_gen4_v4h_v4m_pcie_init,
.ltssm_control = rcar_gen4_pcie_ltssm_control,
.mode = DW_PCIE_EP_TYPE,
};
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH v2 2/5] PCI: dwc: rcar-gen4: Rework rcar_gen4_pcie_drvdata .additional_common_init into .init
2026-07-20 2:02 ` [PATCH v2 2/5] PCI: dwc: rcar-gen4: Rework rcar_gen4_pcie_drvdata .additional_common_init into .init Marek Vasut
@ 2026-07-20 2:15 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-20 2:15 UTC (permalink / raw)
To: Marek Vasut; +Cc: linux-pci, wsa+renesas, conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Silent failure in `rcar_gen4_pcie_ep_pre_init()` and asymmetric teardown in endpoint error paths lead to kernel panics and unbalanced clock disables.
--
--- Patch [2]: [PATCH v2 2/5] PCI: dwc: rcar-gen4: Rework rcar_gen4_pcie_drvdata .additional_common_init into .init ---
commit f4863c849aaf3cf13744faee6e2f333b5420b025
Author: Marek Vasut <marek.vasut+renesas@mailbox.org>
PCI: dwc: rcar-gen4: Rework rcar_gen4_pcie_drvdata .additional_common_init into .init
This commit simplifies the PCIe initialization callchain for R-Car Gen4 SoCs.
It replaces the additional_common_init callback with a unified init callback
for both host and endpoint configurations.
> diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> index 5f7211b91ee5b..5724f64eadfad 100644
> --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
[ ... ]
> @@ -487,7 +509,7 @@ static void rcar_gen4_pcie_ep_pre_init(struct dw_pcie_ep *ep)
> struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
> int ret;
>
> - ret = rcar_gen4_pcie_common_init(rcar);
> + ret = rcar->drvdata->init(rcar);
> if (ret)
> return;
[Severity: High]
This is a pre-existing issue, but since this area is being modified, does the
early return here lead to a kernel panic if initialization fails?
If rcar->drvdata->init() fails, it returns early but cannot propagate the
error because pre_init() returns void. Execution then continues into
dw_pcie_ep_init_registers(), which accesses unclocked DWC registers, resulting
in an SError panic.
Also, if dw_pcie_ep_init() fails before calling ep->ops->pre_init() (such as
in devm_pci_epc_create()), the error path in rcar_gen4_add_dw_pcie_ep()
unconditionally calls rcar_gen4_pcie_ep_deinit(). That function performs an
MMIO write to PCIEDMAINTSTSEN while clocks are disabled, causing another
SError panic, and warns about unbalanced clock disables.
Could these endpoint error paths be reworked so the kernel fails gracefully
instead of crashing?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720020505.315335-1-marek.vasut+renesas@mailbox.org?part=2
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 3/5] PCI: dwc: rcar-gen4: Split .start_link into ltssm_control and speed_control
2026-07-20 2:02 [PATCH v2 0/5] PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4 Marek Vasut
2026-07-20 2:02 ` [PATCH v2 1/5] dt-bindings: PCI: rcar-gen4-pci-host: Add R-Car X5H PCIe4 compatible Marek Vasut
2026-07-20 2:02 ` [PATCH v2 2/5] PCI: dwc: rcar-gen4: Rework rcar_gen4_pcie_drvdata .additional_common_init into .init Marek Vasut
@ 2026-07-20 2:02 ` Marek Vasut
2026-07-20 2:10 ` sashiko-bot
2026-07-20 2:02 ` [PATCH v2 4/5] PCI: dwc: rcar-gen4: Handle PERST via reset subsystem Marek Vasut
2026-07-20 2:02 ` [PATCH v2 5/5] PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4 Marek Vasut
4 siblings, 1 reply; 11+ messages in thread
From: Marek Vasut @ 2026-07-20 2:02 UTC (permalink / raw)
To: linux-pci
Cc: Marek Vasut, Krzysztof Wilczyński, Bjorn Helgaas,
Conor Dooley, Geert Uytterhoeven, Krzysztof Kozlowski,
Lorenzo Pieralisi, Manivannan Sadhasivam, Rob Herring,
Yoshihiro Shimoda, devicetree, linux-kernel, linux-renesas-soc
Introduce new .speed_control callback and implement it on R-Car Gen4.
The callback implements the second half of what is currently present
in rcar_gen4_pcie_start_link(), and rcar_gen4_pcie_start_link() does
call the .speed_control callback. This is a preparatory patch for
R-Car Gen5 support, where the .speed_control implementation is
different.
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
Cc: "Krzysztof Wilczyński" <kwilczynski@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Manivannan Sadhasivam <mani@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
V2: No change
---
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 39 ++++++++++++++-------
1 file changed, 26 insertions(+), 13 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 5724f64eadfad..73b01e74b42cb 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -89,6 +89,7 @@ struct rcar_gen4_pcie;
struct rcar_gen4_pcie_drvdata {
int (*init)(struct rcar_gen4_pcie *rcar);
int (*ltssm_control)(struct rcar_gen4_pcie *rcar, bool enable);
+ int (*speed_control)(struct rcar_gen4_pcie *rcar);
enum dw_pcie_device_mode mode;
};
@@ -140,20 +141,10 @@ static int rcar_gen4_pcie_speed_change(struct dw_pcie *dw)
return -ETIMEDOUT;
}
-/*
- * Enable LTSSM of this controller and manually initiate the speed change.
- * Always return 0.
- */
-static int rcar_gen4_pcie_start_link(struct dw_pcie *dw)
+static int rcar_gen4_pcie_speed_control(struct rcar_gen4_pcie *rcar)
{
- struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
- int i, changes, ret;
-
- if (rcar->drvdata->ltssm_control) {
- ret = rcar->drvdata->ltssm_control(rcar, true);
- if (ret)
- return ret;
- }
+ struct dw_pcie *dw = &rcar->dw;
+ int i, changes;
/*
* Require direct speed change with retrying here if the max_link_speed
@@ -177,6 +168,24 @@ static int rcar_gen4_pcie_start_link(struct dw_pcie *dw)
return 0;
}
+/*
+ * Enable LTSSM of this controller and manually initiate the speed change.
+ * Always return 0.
+ */
+static int rcar_gen4_pcie_start_link(struct dw_pcie *dw)
+{
+ struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
+ int ret;
+
+ if (rcar->drvdata->ltssm_control) {
+ ret = rcar->drvdata->ltssm_control(rcar, true);
+ if (ret)
+ return ret;
+ }
+
+ return rcar->drvdata->speed_control(rcar);
+}
+
static void rcar_gen4_pcie_stop_link(struct dw_pcie *dw)
{
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
@@ -856,24 +865,28 @@ static int rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable
static struct rcar_gen4_pcie_drvdata drvdata_r8a779f0_pcie = {
.init = rcar_gen4_pcie_common_init,
.ltssm_control = r8a779f0_pcie_ltssm_control,
+ .speed_control = rcar_gen4_pcie_speed_control,
.mode = DW_PCIE_RC_TYPE,
};
static struct rcar_gen4_pcie_drvdata drvdata_r8a779f0_pcie_ep = {
.init = rcar_gen4_pcie_common_init,
.ltssm_control = r8a779f0_pcie_ltssm_control,
+ .speed_control = rcar_gen4_pcie_speed_control,
.mode = DW_PCIE_EP_TYPE,
};
static struct rcar_gen4_pcie_drvdata drvdata_rcar_gen4_pcie = {
.init = rcar_gen4_v4h_v4m_pcie_init,
.ltssm_control = rcar_gen4_pcie_ltssm_control,
+ .speed_control = rcar_gen4_pcie_speed_control,
.mode = DW_PCIE_RC_TYPE,
};
static struct rcar_gen4_pcie_drvdata drvdata_rcar_gen4_pcie_ep = {
.init = rcar_gen4_v4h_v4m_pcie_init,
.ltssm_control = rcar_gen4_pcie_ltssm_control,
+ .speed_control = rcar_gen4_pcie_speed_control,
.mode = DW_PCIE_EP_TYPE,
};
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 4/5] PCI: dwc: rcar-gen4: Handle PERST via reset subsystem
2026-07-20 2:02 [PATCH v2 0/5] PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4 Marek Vasut
` (2 preceding siblings ...)
2026-07-20 2:02 ` [PATCH v2 3/5] PCI: dwc: rcar-gen4: Split .start_link into ltssm_control and speed_control Marek Vasut
@ 2026-07-20 2:02 ` Marek Vasut
2026-07-20 2:16 ` sashiko-bot
2026-07-20 2:02 ` [PATCH v2 5/5] PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4 Marek Vasut
4 siblings, 1 reply; 11+ messages in thread
From: Marek Vasut @ 2026-07-20 2:02 UTC (permalink / raw)
To: linux-pci
Cc: Marek Vasut, Krzysztof Wilczyński, Bjorn Helgaas,
Conor Dooley, Geert Uytterhoeven, Krzysztof Kozlowski,
Lorenzo Pieralisi, Manivannan Sadhasivam, Rob Herring,
Yoshihiro Shimoda, devicetree, linux-kernel, linux-renesas-soc
Handle PERST via both GPIO and reset subsystem. On R-Car Gen4, the
PERST signal is operated as a GPIO, on R-Car Gen5 it might only be
accessible via SCMI reset via reset subsystem. Support both options.
This is a preparatory patch for R-Car Gen5 support.
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
Cc: "Krzysztof Wilczyński" <kwilczynski@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Manivannan Sadhasivam <mani@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
V2: - Use dev_err_probe() for perst in rcar_gen4_pcie_get_resources()
- Use of_get_next_available_child() to obtain root port OF node
- Switch to of_reset_control_get_optional_exclusive() to deal with
R-Car Gen4, where the PERST is handled as GPIO instead of reset
- Rename rcar_gen4_pcie_host_perst() to rcar_gen4_pcie_host_perst_assert()
and use bool type for assert and deassert selection
- Add missing reset_control_put() into rcar_gen4_pcie_probe() fail path
---
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 39 ++++++++++++++++++---
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 73b01e74b42cb..2ee8b344ec541 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -98,6 +98,7 @@ struct rcar_gen4_pcie {
void __iomem *base;
void __iomem *phy_base;
struct platform_device *pdev;
+ struct reset_control *perst;
const struct rcar_gen4_pcie_drvdata *drvdata;
};
#define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
@@ -316,12 +317,23 @@ static void rcar_gen4_pcie_unprepare(struct rcar_gen4_pcie *rcar)
static int rcar_gen4_pcie_get_resources(struct rcar_gen4_pcie *rcar)
{
+ struct device *dev = rcar->dw.dev;
+ struct device_node *root_port;
+
rcar->phy_base = devm_platform_ioremap_resource_byname(rcar->pdev, "phy");
if (IS_ERR(rcar->phy_base))
return PTR_ERR(rcar->phy_base);
+ root_port = of_get_next_available_child(dev->of_node, NULL);
+ rcar->perst = of_reset_control_get_optional_exclusive(root_port, "perst");
+ of_node_put(root_port);
+ if (IS_ERR(rcar->perst))
+ return dev_err_probe(dev, PTR_ERR(rcar->perst), "Failed to get PERST#\n");
+
/* Renesas-specific registers */
rcar->base = devm_platform_ioremap_resource_byname(rcar->pdev, "app");
+ if (IS_ERR(rcar->base))
+ reset_control_put(rcar->perst);
return PTR_ERR_OR_ZERO(rcar->base);
}
@@ -442,6 +454,22 @@ static int rcar_gen4_pcie_host_msi_init(struct dw_pcie_rp *pp)
return ret;
}
+static void rcar_gen4_pcie_host_perst_assert(struct dw_pcie_rp *pp, bool assert)
+{
+ struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
+ struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
+
+ gpiod_set_value_cansleep(dw->pe_rst, assert);
+
+ if (!rcar->perst)
+ return;
+
+ if (assert)
+ reset_control_assert(rcar->perst);
+ else
+ reset_control_deassert(rcar->perst);
+}
+
/* Host mode */
static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
{
@@ -449,7 +477,7 @@ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
int ret;
- gpiod_set_value_cansleep(dw->pe_rst, 1);
+ rcar_gen4_pcie_host_perst_assert(pp, true);
ret = rcar->drvdata->init(rcar);
if (ret)
@@ -470,7 +498,7 @@ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
msleep(PCIE_T_PVPERL_MS); /* pe_rst requires 100msec delay */
- gpiod_set_value_cansleep(dw->pe_rst, 0);
+ rcar_gen4_pcie_host_perst_assert(pp, false);
return 0;
@@ -484,7 +512,7 @@ static void rcar_gen4_pcie_host_deinit(struct dw_pcie_rp *pp)
struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
- gpiod_set_value_cansleep(dw->pe_rst, 1);
+ rcar_gen4_pcie_host_perst_assert(pp, true);
rcar_gen4_pcie_common_deinit(rcar);
}
@@ -654,7 +682,7 @@ static int rcar_gen4_pcie_probe(struct platform_device *pdev)
err = rcar_gen4_pcie_prepare(rcar);
if (err)
- return err;
+ goto err_prepare;
err = rcar_gen4_add_dw_pcie(rcar);
if (err)
@@ -662,6 +690,8 @@ static int rcar_gen4_pcie_probe(struct platform_device *pdev)
return 0;
+err_prepare:
+ reset_control_put(rcar->perst);
err_unprepare:
rcar_gen4_pcie_unprepare(rcar);
@@ -688,6 +718,7 @@ static void rcar_gen4_pcie_remove(struct platform_device *pdev)
rcar_gen4_remove_dw_pcie(rcar);
rcar_gen4_pcie_unprepare(rcar);
+ reset_control_put(rcar->perst);
}
static int r8a779f0_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable)
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH v2 4/5] PCI: dwc: rcar-gen4: Handle PERST via reset subsystem
2026-07-20 2:02 ` [PATCH v2 4/5] PCI: dwc: rcar-gen4: Handle PERST via reset subsystem Marek Vasut
@ 2026-07-20 2:16 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-20 2:16 UTC (permalink / raw)
To: Marek Vasut; +Cc: linux-pci, conor+dt, wsa+renesas, robh, devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Incorrectly ordered error labels in `rcar_gen4_pcie_probe()` result in a leaked reset control and unbalanced runtime PM operations.
- [High] Probe fails unconditionally with -EINVAL on device trees without a root port child node (e.g., existing R-Car Gen4 DTs and PCIe endpoints).
--
--- Patch [4]: [PATCH v2 4/5] PCI: dwc: rcar-gen4: Handle PERST via reset subsystem ---
commit ee4c8b0343b92a78672b94439fca7074d908ca06
Author: Marek Vasut <marek.vasut+renesas@mailbox.org>
PCI: dwc: rcar-gen4: Handle PERST via reset subsystem
Handle PERST via both GPIO and reset subsystem. On R-Car Gen4, the PERST
signal is operated as a GPIO, on R-Car Gen5 it might only be accessible via
SCMI reset via reset subsystem. Support both options.
> diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> index 73b01e74b42cb..f88168f2df195 100644
> --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
[ ... ]
> @@ -316,12 +317,23 @@ static void rcar_gen4_pcie_unprepare(struct rcar_gen4_pcie *rcar)
>
> static int rcar_gen4_pcie_get_resources(struct rcar_gen4_pcie *rcar)
> {
> + struct device *dev = rcar->dw.dev;
> + struct device_node *root_port;
> +
> rcar->phy_base = devm_platform_ioremap_resource_byname(rcar->pdev, "phy");
> if (IS_ERR(rcar->phy_base))
> return PTR_ERR(rcar->phy_base);
>
> + root_port = of_get_next_available_child(dev->of_node, NULL);
> + rcar->perst = of_reset_control_get_optional_exclusive(root_port, "perst");
[Severity: High]
Does this cause a probe failure on device trees without a root port child
node?
If of_get_next_available_child() returns NULL (for example, on existing R-Car
Gen4 setups or endpoints), passing a NULL root_port to
of_reset_control_get_optional_exclusive() will return ERR_PTR(-EINVAL). This
error is then returned, causing the probe to fail unconditionally.
> + of_node_put(root_port);
> + if (IS_ERR(rcar->perst))
> + return dev_err_probe(dev, PTR_ERR(rcar->perst), "Failed to get PERST#\n");
> +
> /* Renesas-specific registers */
> rcar->base = devm_platform_ioremap_resource_byname(rcar->pdev, "app");
> + if (IS_ERR(rcar->base))
> + reset_control_put(rcar->perst);
>
> return PTR_ERR_OR_ZERO(rcar->base);
> }
[ ... ]
> @@ -654,7 +682,7 @@ static int rcar_gen4_pcie_probe(struct platform_device *pdev)
>
> err = rcar_gen4_pcie_prepare(rcar);
> if (err)
> - return err;
> + goto err_prepare;
>
> err = rcar_gen4_add_dw_pcie(rcar);
> if (err)
> @@ -662,6 +690,8 @@ static int rcar_gen4_pcie_probe(struct platform_device *pdev)
>
> return 0;
>
> +err_prepare:
> + reset_control_put(rcar->perst);
> err_unprepare:
> rcar_gen4_pcie_unprepare(rcar);
[Severity: High]
Are the error labels out of order here?
If rcar_gen4_pcie_prepare() fails, the code jumps to err_prepare which then
falls through to err_unprepare. This calls rcar_gen4_pcie_unprepare() and
performs an unbalanced pm_runtime_put().
Conversely, if rcar_gen4_add_dw_pcie() fails, the code jumps to err_unprepare,
skipping err_prepare entirely. This results in a leaked rcar->perst reset
control.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720020505.315335-1-marek.vasut+renesas@mailbox.org?part=4
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 5/5] PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4
2026-07-20 2:02 [PATCH v2 0/5] PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4 Marek Vasut
` (3 preceding siblings ...)
2026-07-20 2:02 ` [PATCH v2 4/5] PCI: dwc: rcar-gen4: Handle PERST via reset subsystem Marek Vasut
@ 2026-07-20 2:02 ` Marek Vasut
2026-07-20 2:18 ` sashiko-bot
4 siblings, 1 reply; 11+ messages in thread
From: Marek Vasut @ 2026-07-20 2:02 UTC (permalink / raw)
To: linux-pci
Cc: Marek Vasut, Krzysztof Wilczyński, Bjorn Helgaas,
Conor Dooley, Geert Uytterhoeven, Krzysztof Kozlowski,
Lorenzo Pieralisi, Manivannan Sadhasivam, Rob Herring,
Yoshihiro Shimoda, devicetree, linux-kernel, linux-renesas-soc
Add support for R8A78000 (R-Car X5H) PCIe4.
This driver previously supported R-Car Gen4 S4/V4H/V4M. PCIe features
of R-Car X5H PCIe4 are almost all the same.
The controller initialization sequence is slightly different and is
factored out into controller specific callbacks, in a manner similar
to previous R-Car Gen4 handling.
The controller does have a PHY attached to it, but the PHY is operated
by a separate PHY driver, the PHY driver instance binding is handled
in rcar_gen4_pcie_get_resources() and controlled in the aforementioned
controller specific callbacks.
The controller driver is deliberately using "renesas,rcar-gen5-pcie4"
DT compatible string to discern R-Car X5H PCIe4 controller supported
by this driver, from R-Car X5H PCIe6 controller which will most likely
use a separate driver.
The R-Car X5H PCIe4 controller embeds HDMA instead of EDMA embedded
in the R-Car Gen4 PCIe controller, "dw-edma" driver supports both
DMA variants.
Endpoint mode is currently not implemented for R-Car Gen5 PCIe4.
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
Cc: "Krzysztof Wilczyński" <kwilczynski@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Manivannan Sadhasivam <mani@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
V2: No change
---
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 115 +++++++++++++++++++-
1 file changed, 113 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 2ee8b344ec541..f403e11c884a4 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -19,6 +19,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/pci.h>
+#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -36,6 +37,7 @@
/* MSI Capability */
#define MSICAP0 0x0050
+#define MSICAP0_MMESCAP_MASK GENMASK(19, 17)
#define MSICAP0_MSIE BIT(16)
/* PCIe Interrupt Status 0 */
@@ -74,6 +76,11 @@
#define PCIEPWRMNGCTRL 0x0070
#define APP_CLK_REQ_N BIT(11)
#define APP_CLK_PM_EN BIT(10)
+#define APP_READY_ENTR_L23 BIT(6)
+#define APP_REQ_ENTR_L1 BIT(5)
+
+/* PCI Express capability */
+#define EXPCAP(x) (0x0070 + (x))
#define RCAR_NUM_SPEED_CHANGE_RETRIES 10
#define RCAR_MAX_LINK_SPEED 4
@@ -97,6 +104,7 @@ struct rcar_gen4_pcie {
struct dw_pcie dw;
void __iomem *base;
void __iomem *phy_base;
+ struct phy *phy;
struct platform_device *pdev;
struct reset_control *perst;
const struct rcar_gen4_pcie_drvdata *drvdata;
@@ -169,6 +177,35 @@ static int rcar_gen4_pcie_speed_control(struct rcar_gen4_pcie *rcar)
return 0;
}
+static int rcar_gen5_pcie_speed_control(struct rcar_gen4_pcie *rcar)
+{
+ struct dw_pcie *dw = &rcar->dw;
+ u32 lnkcap = dw_pcie_readl_dbi(dw, EXPCAP(PCI_EXP_LNKCAP));
+ u32 lnksta = dw_pcie_readw_dbi(dw, EXPCAP(PCI_EXP_LNKSTA));
+ u32 val, retries;
+
+ if ((lnksta & PCI_EXP_LNKSTA_CLS) == (lnkcap & PCI_EXP_LNKCAP_SLS))
+ return 0;
+
+ /* Retrain link */
+ val = dw_pcie_readl_dbi(dw, EXPCAP(PCI_EXP_LNKCTL));
+ val |= PCI_EXP_LNKCTL_RL;
+ dw_pcie_writel_dbi(dw, EXPCAP(PCI_EXP_LNKCTL), val);
+
+ /* Wait for link retrain */
+ for (retries = 0; retries <= 10; retries++) {
+ lnksta = dw_pcie_readw_dbi(dw, EXPCAP(PCI_EXP_LNKSTA));
+
+ /* Check retrain flag */
+ if (!(lnksta & PCI_EXP_LNKSTA_LT))
+ break;
+
+ usleep_range(1000, 1100);
+ }
+
+ return 0;
+}
+
/*
* Enable LTSSM of this controller and manually initiate the speed change.
* Always return 0.
@@ -284,6 +321,44 @@ static int rcar_gen4_v4h_v4m_pcie_init(struct rcar_gen4_pcie *rcar)
return 0;
}
+static int rcar_gen5_pcie_init(struct rcar_gen4_pcie *rcar)
+{
+ struct dw_pcie *dw = &rcar->dw;
+ int ret;
+ u32 val;
+
+ /* R-Car Gen4 and Gen5 common initialization. */
+ ret = rcar_gen4_pcie_common_init(rcar);
+ if (ret)
+ return ret;
+
+ /* R-Car Gen5 specific additional initialization. */
+ ret = phy_init(rcar->phy);
+ if (ret)
+ return ret;
+
+ dw_pcie_dbi_ro_wr_en(dw);
+
+ val = dw_pcie_readl_dbi(dw, PCIE_PORT_LANE_SKEW);
+ val &= ~PORT_LANE_SKEW_INSERT_MASK;
+ if (dw->num_lanes < 8)
+ val |= BIT(6);
+ dw_pcie_writel_dbi(dw, PCIE_PORT_LANE_SKEW, val);
+
+ val = dw_pcie_readl_dbi(dw, MSICAP0);
+ FIELD_MODIFY(MSICAP0_MMESCAP_MASK, &val, 4);
+ dw_pcie_writel_dbi(dw, MSICAP0, val);
+
+ dw_pcie_dbi_ro_wr_dis(dw);
+
+ val = readl(rcar->base + PCIEPWRMNGCTRL);
+ val |= APP_CLK_REQ_N | APP_CLK_PM_EN |
+ APP_READY_ENTR_L23 | APP_REQ_ENTR_L1;
+ writel(val, rcar->base + PCIEPWRMNGCTRL);
+
+ return 0;
+}
+
static void rcar_gen4_pcie_common_deinit(struct rcar_gen4_pcie *rcar)
{
struct dw_pcie *dw = &rcar->dw;
@@ -321,8 +396,11 @@ static int rcar_gen4_pcie_get_resources(struct rcar_gen4_pcie *rcar)
struct device_node *root_port;
rcar->phy_base = devm_platform_ioremap_resource_byname(rcar->pdev, "phy");
- if (IS_ERR(rcar->phy_base))
- return PTR_ERR(rcar->phy_base);
+ if (IS_ERR(rcar->phy_base)) {
+ rcar->phy = devm_phy_get(dev, NULL);
+ if (IS_ERR(rcar->phy))
+ return PTR_ERR(rcar->phy);
+ }
root_port = of_get_next_available_child(dev->of_node, NULL);
rcar->perst = of_reset_control_get_optional_exclusive(root_port, "perst");
@@ -743,6 +821,28 @@ static int r8a779f0_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable)
return 0;
}
+static int rcar_gen5_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable)
+{
+ u32 val;
+
+ val = readl(rcar->base + PCIERSTCTRL1);
+ if (enable) {
+ val |= APP_LTSSM_ENABLE;
+ val &= ~APP_HOLD_PHY_RST;
+ } else {
+ val &= ~APP_LTSSM_ENABLE;
+ val |= APP_HOLD_PHY_RST;
+ }
+ writel(val, rcar->base + PCIERSTCTRL1);
+
+ if (enable)
+ phy_power_on(rcar->phy);
+ else
+ phy_power_off(rcar->phy);
+
+ return 0;
+}
+
static void rcar_gen4_pcie_phy_reg_update_bits(struct rcar_gen4_pcie *rcar,
u32 offset, u32 mask, u32 val)
{
@@ -921,6 +1021,13 @@ static struct rcar_gen4_pcie_drvdata drvdata_rcar_gen4_pcie_ep = {
.mode = DW_PCIE_EP_TYPE,
};
+static struct rcar_gen4_pcie_drvdata drvdata_rcar_gen5_pcie = {
+ .init = rcar_gen5_pcie_init,
+ .ltssm_control = rcar_gen5_pcie_ltssm_control,
+ .speed_control = rcar_gen5_pcie_speed_control,
+ .mode = DW_PCIE_RC_TYPE,
+};
+
static const struct of_device_id rcar_gen4_pcie_of_match[] = {
{
.compatible = "renesas,r8a779f0-pcie",
@@ -938,6 +1045,10 @@ static const struct of_device_id rcar_gen4_pcie_of_match[] = {
.compatible = "renesas,rcar-gen4-pcie-ep",
.data = &drvdata_rcar_gen4_pcie_ep,
},
+ {
+ .compatible = "renesas,rcar-gen5-pcie4",
+ .data = &drvdata_rcar_gen5_pcie,
+ },
{},
};
MODULE_DEVICE_TABLE(of, rcar_gen4_pcie_of_match);
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH v2 5/5] PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4
2026-07-20 2:02 ` [PATCH v2 5/5] PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4 Marek Vasut
@ 2026-07-20 2:18 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-20 2:18 UTC (permalink / raw)
To: Marek Vasut; +Cc: devicetree, conor+dt, linux-pci, wsa+renesas, robh
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Missing `phy_exit()` call on error paths and driver teardown causes a leak of PHY resources.
- [High] Missing cleanup of core clocks and reset states when `phy_init()` fails in `rcar_gen5_pcie_init()`.
- [High] Incorrect initialization sequence in `rcar_gen5_pcie_ltssm_control()` and ignored error check for `phy_power_on()`.
- [High] A 32-bit read-modify-write of `PCI_EXP_LNKCTL` inadvertently clears Write-1-to-Clear (W1C) bits in the adjacent `PCI_EXP_LNKSTA` register.
- [High] Dereference of `ERR_PTR` in `rcar->phy_base` on Gen4 code paths if a malformed Device Tree is provided.
--
--- Patch [5]: [PATCH v2 5/5] PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4 ---
commit cab5ad82173a65768d51a17315ea45161e805bdf
Author: Marek Vasut <marek.vasut+renesas@mailbox.org>
PCI: dwc: rcar-gen4: Add support for R-Car X5H PCIe4
Add support for R8A78000 (R-Car X5H) PCIe4. The controller initialization
sequence is factored out into controller-specific callbacks. Endpoint mode
is currently not implemented for R-Car Gen5 PCIe4.
> diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> index f88168f2df195..794c42c53380d 100644
> --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
[ ... ]
> @@ -169,6 +177,35 @@ static int rcar_gen4_pcie_speed_control(struct rcar_gen4_pcie *rcar)
> +static int rcar_gen5_pcie_speed_control(struct rcar_gen4_pcie *rcar)
> +{
> + struct dw_pcie *dw = &rcar->dw;
> + u32 lnkcap = dw_pcie_readl_dbi(dw, EXPCAP(PCI_EXP_LNKCAP));
> + u32 lnksta = dw_pcie_readw_dbi(dw, EXPCAP(PCI_EXP_LNKSTA));
> + u32 val, retries;
> +
> + if ((lnksta & PCI_EXP_LNKSTA_CLS) == (lnkcap & PCI_EXP_LNKCAP_SLS))
> + return 0;
> +
> + /* Retrain link */
> + val = dw_pcie_readl_dbi(dw, EXPCAP(PCI_EXP_LNKCTL));
> + val |= PCI_EXP_LNKCTL_RL;
> + dw_pcie_writel_dbi(dw, EXPCAP(PCI_EXP_LNKCTL), val);
[Severity: High]
Will this 32-bit read-modify-write access unintentionally clear Write-1-to-Clear
(W1C) bits in the adjacent PCI_EXP_LNKSTA register?
Since PCI_EXP_LNKCTL (offset 0x10) and PCI_EXP_LNKSTA (offset 0x12) share the
same 32-bit Dword, any W1C bits set in the Link Status register will be read as
1 and written back as 1, clearing them. Could a 16-bit accessor be used instead?
> +
> + /* Wait for link retrain */
[ ... ]
> @@ -284,6 +321,44 @@ static int rcar_gen4_v4h_v4m_pcie_init(struct rcar_gen4_pcie *rcar)
> +static int rcar_gen5_pcie_init(struct rcar_gen4_pcie *rcar)
> +{
> + struct dw_pcie *dw = &rcar->dw;
> + int ret;
> + u32 val;
> +
> + /* R-Car Gen4 and Gen5 common initialization. */
> + ret = rcar_gen4_pcie_common_init(rcar);
> + if (ret)
> + return ret;
> +
> + /* R-Car Gen5 specific additional initialization. */
> + ret = phy_init(rcar->phy);
> + if (ret)
> + return ret;
[Severity: High]
If this fails, do we need to clean up the resources just initialized by
rcar_gen4_pcie_common_init()? It looks like returning the error directly leaves
core clocks enabled and resets unhandled.
[Severity: High]
Since phy_init() is called on the successful initialization path, shouldn't
there be a matching phy_exit() in the deinitialization paths (such as
rcar_gen4_pcie_common_deinit) to prevent leaking PHY resources when the device
is unbound?
> +
> + dw_pcie_dbi_ro_wr_en(dw);
[ ... ]
> @@ -321,8 +396,11 @@ static int rcar_gen4_pcie_get_resources(struct rcar_gen4_pcie *rcar)
> struct device_node *root_port;
>
> rcar->phy_base = devm_platform_ioremap_resource_byname(rcar->pdev, "phy");
> - if (IS_ERR(rcar->phy_base))
> - return PTR_ERR(rcar->phy_base);
> + if (IS_ERR(rcar->phy_base)) {
> + rcar->phy = devm_phy_get(dev, NULL);
> + if (IS_ERR(rcar->phy))
> + return PTR_ERR(rcar->phy);
> + }
[Severity: High]
If the device tree lacks the phy memory region but provides a phys node,
the fallback devm_phy_get() succeeds, leaving rcar->phy_base containing an
error pointer.
Later on, if Gen4 code paths like rcar_gen4_pcie_ltssm_control() execute,
they unconditionally call rcar_gen4_pcie_phy_reg_update_bits():
rcar_gen4_pcie_phy_reg_update_bits()
tmp = readl(rcar->phy_base + offset);
Can this dereference the error pointer and crash? Should rcar->phy_base be set
to NULL after falling back to devm_phy_get()?
>
> root_port = of_get_next_available_child(dev->of_node, NULL);
[ ... ]
> @@ -743,6 +821,28 @@ static int r8a779f0_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable)
> +static int rcar_gen5_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable)
> +{
> + u32 val;
> +
> + val = readl(rcar->base + PCIERSTCTRL1);
> + if (enable) {
> + val |= APP_LTSSM_ENABLE;
> + val &= ~APP_HOLD_PHY_RST;
> + } else {
> + val &= ~APP_LTSSM_ENABLE;
> + val |= APP_HOLD_PHY_RST;
> + }
> + writel(val, rcar->base + PCIERSTCTRL1);
> +
> + if (enable)
> + phy_power_on(rcar->phy);
> + else
> + phy_power_off(rcar->phy);
> +
> + return 0;
> +}
[Severity: High]
Is it expected to enable the LTSSM and drop the PHY reset before calling
phy_power_on()? Normally, wouldn't the PHY need to be powered and stabilized
before activating the MAC's LTSSM?
Also, if phy_power_on() fails, shouldn't we handle the error instead of
unconditionally returning 0?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720020505.315335-1-marek.vasut+renesas@mailbox.org?part=5
^ permalink raw reply [flat|nested] 11+ messages in thread