* [PATCH v5 1/4] dt-bindings: PCI: renesas,r9a08g045-pcie: Add RZ/V2H(P) support
2026-06-29 22:09 [PATCH v5 0/4] Add PCIe support for RZ/V2H(P) SoC Prabhakar
@ 2026-06-29 22:09 ` Prabhakar
2026-06-29 22:15 ` sashiko-bot
2026-06-29 22:09 ` [PATCH v5 2/4] PCI: rzg3s-host: Use shared reset controls for power domain resets Prabhakar
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Prabhakar @ 2026-06-29 22:09 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Lorenzo Pieralisi, Claudiu Beznea, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel,
Geert Uytterhoeven, Magnus Damm, linux-pci
Cc: linux-renesas-soc, devicetree, linux-kernel, Prabhakar, Biju Das,
Fabrizio Castro, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Add support for the PCIe controller found on the Renesas RZ/V2H(P) SoC.
The RZ/V2H(P) controller is similar to the RZ/G3E variant but includes
additional registers and configuration bits for PCIe lane control. It
supports multilink operation configured as either a single x4 link
or two independent x2 link controllers.
Unlike earlier SoCs supported by this driver which only feature a single
PCIe controller, the RZ/V2H(P) SoC implements two controllers. Both
instances rely on the system controller (SYSC) for configuration, but
the required registers reside at different offsets for each controller.
To correctly identify the controller instance and map the corresponding
system controller registers, update the "renesas,sysc" property to a
phandle-array. For the RZ/V2H(P) SoC, require an accompanying cell to
specify the controller instance index (0 or 1). For all earlier SoCs,
strictly restrict the property to a single phandle with zero argument
cells.
Additionally, make the "num-lanes" property mandatory for this SoC and
restrict its values according to the hardware capabilities.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
v4->v5:
- No change
v3->v4:
- Added RB tags.
v2->v3:
- Dropped using linux,pci-domain property.
- Switched property to phandle-array for renesas,sysc
to support multiple controllers with different SYSC register sets.
- Updated commit message for clarity.
v1->v2:
- Updated commit message.
- Dropped un-necessary new line in schema.
---
.../bindings/pci/renesas,r9a08g045-pcie.yaml | 34 +++++++++++++++++--
1 file changed, 31 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml b/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml
index 90086909e921..09d78bd1a577 100644
--- a/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml
@@ -14,7 +14,7 @@ description: |
with PCIe Base Specification 4.0 and supports different link speeds
depending on the SoC variant:
- Gen2 (5 GT/s): RZ/G3S
- - Gen3 (8 GT/s): RZ/G3E, RZ/V2N
+ - Gen3 (8 GT/s): RZ/G3E, RZ/V2H(P), RZ/V2N
properties:
compatible:
@@ -22,6 +22,7 @@ properties:
- enum:
- renesas,r9a08g045-pcie # RZ/G3S
- renesas,r9a09g047-pcie # RZ/G3E
+ - renesas,r9a09g057-pcie # RZ/V2H(P)
- items:
- const: renesas,r9a09g056-pcie # RZ/V2N
- const: renesas,r9a09g047-pcie
@@ -139,7 +140,13 @@ properties:
- clkl1pm clock request state
- power off information in L2 state
- errors (fatal, non-fatal, correctable)
- $ref: /schemas/types.yaml#/definitions/phandle
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ - items:
+ - description: Phandle to system controller
+ - description: PCIe controller index
+ enum: [0, 1]
+ minItems: 1
patternProperties:
"^pcie@0,[0-0]$":
@@ -220,7 +227,9 @@ allOf:
properties:
compatible:
contains:
- const: renesas,r9a09g047-pcie
+ enum:
+ - renesas,r9a09g047-pcie
+ - renesas,r9a09g057-pcie
then:
properties:
interrupts:
@@ -235,6 +244,25 @@ allOf:
maxItems: 1
reset-names:
maxItems: 1
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a09g057-pcie
+ then:
+ properties:
+ num-lanes:
+ enum: [2, 4]
+ renesas,sysc:
+ items:
+ - minItems: 2
+ required:
+ - num-lanes
+ else:
+ properties:
+ renesas,sysc:
+ items:
+ - maxItems: 1
unevaluatedProperties: false
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v5 1/4] dt-bindings: PCI: renesas,r9a08g045-pcie: Add RZ/V2H(P) support
2026-06-29 22:09 ` [PATCH v5 1/4] dt-bindings: PCI: renesas,r9a08g045-pcie: Add RZ/V2H(P) support Prabhakar
@ 2026-06-29 22:15 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-06-29 22:15 UTC (permalink / raw)
To: Prabhakar; +Cc: robh, linux-pci, devicetree, conor+dt, wsa+renesas
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add support for the PCIe controller found on the Renesas RZ/V2H(P) SoC.
>
> The RZ/V2H(P) controller is similar to the RZ/G3E variant but includes
> additional registers and configuration bits for PCIe lane control. It
> supports multilink operation configured as either a single x4 link
> or two independent x2 link controllers.
>
> Unlike earlier SoCs supported by this driver which only feature a single
> PCIe controller, the RZ/V2H(P) SoC implements two controllers. Both
> instances rely on the system controller (SYSC) for configuration, but
> the required registers reside at different offsets for each controller.
>
> To correctly identify the controller instance and map the corresponding
> system controller registers, update the "renesas,sysc" property to a
> phandle-array. For the RZ/V2H(P) SoC, require an accompanying cell to
> specify the controller instance index (0 or 1). For all earlier SoCs,
> strictly restrict the property to a single phandle with zero argument
> cells.
>
> Additionally, make the "num-lanes" property mandatory for this SoC and
> restrict its values according to the hardware capabilities.
>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260629220932.861445-1-prabhakar.mahadev-lad.rj@bp.renesas.com?part=1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v5 2/4] PCI: rzg3s-host: Use shared reset controls for power domain resets
2026-06-29 22:09 [PATCH v5 0/4] Add PCIe support for RZ/V2H(P) SoC Prabhakar
2026-06-29 22:09 ` [PATCH v5 1/4] dt-bindings: PCI: renesas,r9a08g045-pcie: Add RZ/V2H(P) support Prabhakar
@ 2026-06-29 22:09 ` Prabhakar
2026-06-29 22:19 ` sashiko-bot
2026-06-29 22:09 ` [PATCH v5 3/4] PCI: rzg3s-host: Prepare System Controller handling for multiple controllers Prabhakar
2026-06-29 22:09 ` [PATCH v5 4/4] PCI: rzg3s-host: Add support for RZ/V2H(P) SoC Prabhakar
3 siblings, 1 reply; 9+ messages in thread
From: Prabhakar @ 2026-06-29 22:09 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Lorenzo Pieralisi, Claudiu Beznea, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel,
Geert Uytterhoeven, Magnus Damm, linux-pci
Cc: linux-renesas-soc, devicetree, linux-kernel, Prabhakar, Biju Das,
Fabrizio Castro, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Switch to shared reset controls for PCIe power resets to prepare for
RZ/V2H(P) support. On this platform, multiple PCIe controllers share
the same reset line, requiring shared ownership of the reset control.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
v4->v5:
- No change
v3->v4:
- Added RB/TB tags.
v2->v3:
- No change.
v1->v2:
- Updated commit message.
---
drivers/pci/controller/pcie-rzg3s-host.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
index 66f687304c1c..cca2617f2915 100644
--- a/drivers/pci/controller/pcie-rzg3s-host.c
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -1277,9 +1277,9 @@ static int rzg3s_pcie_resets_prepare_and_get(struct rzg3s_pcie_host *host)
for (i = 0; i < data->num_cfg_resets; i++)
host->cfg_resets[i].id = data->cfg_resets[i];
- ret = devm_reset_control_bulk_get_exclusive(host->dev,
- data->num_power_resets,
- host->power_resets);
+ ret = devm_reset_control_bulk_get_shared(host->dev,
+ data->num_power_resets,
+ host->power_resets);
if (ret)
return ret;
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v5 2/4] PCI: rzg3s-host: Use shared reset controls for power domain resets
2026-06-29 22:09 ` [PATCH v5 2/4] PCI: rzg3s-host: Use shared reset controls for power domain resets Prabhakar
@ 2026-06-29 22:19 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-06-29 22:19 UTC (permalink / raw)
To: Prabhakar; +Cc: wsa+renesas, linux-pci, robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] The PCIe reference clock (`port->refclk`) is permanently leaked (enable count imbalance) if `pci_host_probe()` fails during driver probe.
- [High] Hardware access violation in `rzg3s_pcie_suspend_noirq()` causes system crash by writing to unclocked AXI registers.
- [High] Missing chained IRQ handler cleanup on probe error paths leads to Use-After-Free.
--
commit f0476ca1c132af88924c762e84517c32e45ebd21
Author: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
PCI: rzg3s-host: Use shared reset controls for power domain resets
This commit switches the PCIe power resets to use shared reset controls
to prepare for RZ/V2H(P) support. On this platform, multiple PCIe
controllers share the same reset line.
> diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
> index 66f687304c1cb..cca2617f29157 100644
> --- a/drivers/pci/controller/pcie-rzg3s-host.c
> +++ b/drivers/pci/controller/pcie-rzg3s-host.c
> @@ -1277,9 +1277,9 @@ static int rzg3s_pcie_resets_prepare_and_get(struct rzg3s_pcie_host *host)
> for (i = 0; i < data->num_cfg_resets; i++)
> host->cfg_resets[i].id = data->cfg_resets[i];
>
> - ret = devm_reset_control_bulk_get_exclusive(host->dev,
> - data->num_power_resets,
> - host->power_resets);
> + ret = devm_reset_control_bulk_get_shared(host->dev,
> + data->num_power_resets,
> + host->power_resets);
[Severity: High]
This isn't a bug introduced by this patch, but looking at rzg3s_pcie_probe(),
is it possible we are leaking the reference clock enable count on probe failure?
In rzg3s_pcie_host_init_port(), the clock is prepared and enabled:
ret = clk_prepare_enable(port->refclk);
if (ret)
return dev_err_probe(dev, ret, "Failed to enable refclk!\n");
If pci_host_probe() fails later in the probe sequence, the cleanup path
drops the reference without disabling it:
port_refclk_put:
clk_put(host->port.refclk);
Could this keep the reference clock and its parent PLLs permanently enabled,
preventing the SoC from reaching deep sleep states?
[Severity: High]
This is a pre-existing issue, but does rzg3s_pcie_suspend_noirq() have a
hardware access violation?
The runtime PM domain and clocks are gated by pm_runtime_put_sync() before
invoking the de-initialization callback:
ret = pm_runtime_put_sync(dev);
if (ret)
return ret;
clk_disable_unprepare(port->refclk);
/* SoC-specific de-initialization */
ret = data->config_deinit(host);
When rzg3e_pcie_config_deinit() is called, it accesses the controller's
AXI register space:
static int rzg3e_pcie_config_deinit(struct rzg3s_pcie_host *host)
{
writel_relaxed(0, host->axi + RZG3S_PCI_RESET);
return 0;
}
Can writing to a memory-mapped peripheral register while its bus clock is
gated cause an immediate bus fault or system crash during suspend?
[Severity: High]
This isn't a bug introduced by this patch, but is there a use-after-free
risk in rzg3s_pcie_teardown_irqdomain() if a probe failure occurs?
During rzg3s_pcie_init_irqdomain(), chained handlers are registered and a
pointer to the host context is installed into the underlying interrupt:
irq_set_chained_handler_and_data(irq,
rzg3s_pcie_intx_irq_handler,
host);
If the probe fails downstream, rzg3s_pcie_teardown_irqdomain() removes the
domain but doesn't clear the chained handlers:
static void rzg3s_pcie_teardown_irqdomain(struct rzg3s_pcie_host *host)
{
if (IS_ENABLED(CONFIG_PCI_MSI))
rzg3s_pcie_teardown_msi(host);
irq_domain_remove(host->intx_domain);
}
Since the host structure is allocated with devm_pci_alloc_host_bridge(),
it gets freed when probe returns an error. Would an interrupt firing after
this point lead to a kernel panic by dereferencing the freed host pointer?
> if (ret)
> return ret;
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260629220932.861445-1-prabhakar.mahadev-lad.rj@bp.renesas.com?part=2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v5 3/4] PCI: rzg3s-host: Prepare System Controller handling for multiple controllers
2026-06-29 22:09 [PATCH v5 0/4] Add PCIe support for RZ/V2H(P) SoC Prabhakar
2026-06-29 22:09 ` [PATCH v5 1/4] dt-bindings: PCI: renesas,r9a08g045-pcie: Add RZ/V2H(P) support Prabhakar
2026-06-29 22:09 ` [PATCH v5 2/4] PCI: rzg3s-host: Use shared reset controls for power domain resets Prabhakar
@ 2026-06-29 22:09 ` Prabhakar
2026-06-29 22:21 ` sashiko-bot
2026-06-29 22:09 ` [PATCH v5 4/4] PCI: rzg3s-host: Add support for RZ/V2H(P) SoC Prabhakar
3 siblings, 1 reply; 9+ messages in thread
From: Prabhakar @ 2026-06-29 22:09 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Lorenzo Pieralisi, Claudiu Beznea, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel,
Geert Uytterhoeven, Magnus Damm, linux-pci
Cc: linux-renesas-soc, devicetree, linux-kernel, Prabhakar, Biju Das,
Fabrizio Castro, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Prepare the driver to handle multiple PCIe controllers with distinct
System Controller (SYSC) register sets, as required by RZ/V2H(P). The
current design stores a single sysc_info structure per SoC, which is
insufficient for multi-controller configurations.
Introduce controller identifiers and extend struct rzg3s_pcie_soc_data
to hold a sysc_info array indexed per PCIe controller. Add a
controller_id field to struct rzg3s_pcie_host and select the appropriate
System Controller information during probe based on the hardware
instance.
Keep existing single-controller SoCs functionally unchanged while
preparing the driver for RZ/V2H(P) multi-controller support.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
v4->v5:
- No change
v3->v4:
- Added RB/TB tags.
v2->v3:
- No change.
v1->v2:
- Renamed RZG3S_PCIE_CHANNEL_ID* to RZG3S_PCIE_CONTROLLER_ID* for clarity.
- Updated commit message.
---
drivers/pci/controller/pcie-rzg3s-host.c | 48 ++++++++++++++++--------
1 file changed, 33 insertions(+), 15 deletions(-)
diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
index cca2617f2915..03d79e98c9c9 100644
--- a/drivers/pci/controller/pcie-rzg3s-host.c
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -242,6 +242,18 @@ struct rzg3s_pcie_msi {
int irq;
};
+/**
+ * enum rzg3s_pcie_controller_id - RZ/G3S PCIe controller IDs
+ * @RZG3S_PCIE_CONTROLLER_ID_0: PCIe controller 0
+ * @RZG3S_PCIE_CONTROLLER_ID_1: PCIe controller 1
+ * @RZG3S_PCIE_CONTROLLER_ID_MAX: Max PCIe controllers
+ */
+enum rzg3s_pcie_controller_id {
+ RZG3S_PCIE_CONTROLLER_ID_0,
+ RZG3S_PCIE_CONTROLLER_ID_1,
+ RZG3S_PCIE_CONTROLLER_ID_MAX,
+};
+
struct rzg3s_pcie_host;
/**
@@ -254,7 +266,7 @@ struct rzg3s_pcie_host;
* power-on
* @cfg_resets: array with the resets that need to be de-asserted after
* configuration
- * @sysc_info: SYSC info
+ * @sysc_info: System Controller info for each controller
* @num_power_resets: number of power resets
* @num_cfg_resets: number of configuration resets
*/
@@ -265,7 +277,7 @@ struct rzg3s_pcie_soc_data {
int (*config_deinit)(struct rzg3s_pcie_host *host);
const char * const *power_resets;
const char * const *cfg_resets;
- struct rzg3s_sysc_info sysc_info;
+ struct rzg3s_sysc_info sysc_info[RZG3S_PCIE_CONTROLLER_ID_MAX];
u8 num_power_resets;
u8 num_cfg_resets;
};
@@ -297,6 +309,7 @@ struct rzg3s_pcie_port {
* @hw_lock: lock for access to the HW resources
* @intx_irqs: INTx interrupts
* @max_link_speed: maximum supported link speed
+ * @controller_id: PCIe controller identifier, used for System Controller access
*/
struct rzg3s_pcie_host {
void __iomem *axi;
@@ -312,6 +325,7 @@ struct rzg3s_pcie_host {
raw_spinlock_t hw_lock;
int intx_irqs[PCI_NUM_INTX];
int max_link_speed;
+ enum rzg3s_pcie_controller_id controller_id;
};
#define rzg3s_msi_to_host(_msi) container_of(_msi, struct rzg3s_pcie_host, msi)
@@ -1699,7 +1713,7 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
return -ENOMEM;
sysc = host->sysc;
- sysc->info = &host->data->sysc_info;
+ sysc->info = &host->data->sysc_info[host->controller_id];
host->axi = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(host->axi))
@@ -1892,10 +1906,12 @@ static const struct rzg3s_pcie_soc_data rzg3s_soc_data = {
.config_deinit = rzg3s_pcie_config_deinit,
.init_phy = rzg3s_soc_pcie_init_phy,
.sysc_info = {
- .functions = {
- [RZG3S_SYSC_FUNC_ID_RST_RSM_B] = {
- .offset = 0xd74,
- .mask = BIT(0),
+ [RZG3S_PCIE_CONTROLLER_ID_0] = {
+ .functions = {
+ [RZG3S_SYSC_FUNC_ID_RST_RSM_B] = {
+ .offset = 0xd74,
+ .mask = BIT(0),
+ },
},
},
},
@@ -1910,14 +1926,16 @@ static const struct rzg3s_pcie_soc_data rzg3e_soc_data = {
.config_post_init = rzg3e_pcie_config_post_init,
.config_deinit = rzg3e_pcie_config_deinit,
.sysc_info = {
- .functions = {
- [RZG3S_SYSC_FUNC_ID_L1_ALLOW] = {
- .offset = 0x1020,
- .mask = BIT(0),
- },
- [RZG3S_SYSC_FUNC_ID_MODE] = {
- .offset = 0x1024,
- .mask = BIT(0),
+ [RZG3S_PCIE_CONTROLLER_ID_0] = {
+ .functions = {
+ [RZG3S_SYSC_FUNC_ID_L1_ALLOW] = {
+ .offset = 0x1020,
+ .mask = BIT(0),
+ },
+ [RZG3S_SYSC_FUNC_ID_MODE] = {
+ .offset = 0x1024,
+ .mask = BIT(0),
+ },
},
},
},
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v5 3/4] PCI: rzg3s-host: Prepare System Controller handling for multiple controllers
2026-06-29 22:09 ` [PATCH v5 3/4] PCI: rzg3s-host: Prepare System Controller handling for multiple controllers Prabhakar
@ 2026-06-29 22:21 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-06-29 22:21 UTC (permalink / raw)
To: Prabhakar; +Cc: wsa+renesas, robh, linux-pci, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Failure to clear chained IRQ handlers in the error path leads to a Use-After-Free of the `host` structure.
--
commit 9d15bfaf7ab0514922ec90d6892801c1f1eeb157
Author: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
PCI: rzg3s-host: Prepare System Controller handling for multiple controllers
This commit prepares the RZ/G3S PCIe driver to support multiple PCIe
controllers by extending the System Controller (SYSC) information storage.
It introduces an array of sysc_info structures indexed by a new controller
ID field. Existing single-controller SoCs remain functionally unchanged.
> diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
> index cca2617f29157..03d79e98c9c99 100644
> --- a/drivers/pci/controller/pcie-rzg3s-host.c
> +++ b/drivers/pci/controller/pcie-rzg3s-host.c
[ ... ]
> @@ -1699,7 +1713,7 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
> return -ENOMEM;
>
> sysc = host->sysc;
> - sysc->info = &host->data->sysc_info;
> + sysc->info = &host->data->sysc_info[host->controller_id];
[Severity: High]
This is a pre-existing issue, but I noticed a potential memory safety concern
in the error handling path of rzg3s_pcie_probe().
If probe fails later and executes the error path, it calls
rzg3s_pcie_teardown_irqdomain(). Looking at rzg3s_pcie_teardown_irqdomain(),
it executes:
irq_domain_remove(host->intx_domain);
However, it does not appear to clear the chained interrupt handlers.
Because the host structure is allocated via devm_pci_alloc_host_bridge(),
it will be automatically freed when the probe fails.
Could this leave a dangling pointer in the parent interrupt controller,
resulting in a use-after-free if the hardware triggers
rzg3s_pcie_intx_irq_handler() after the teardown?
>
> host->axi = devm_platform_ioremap_resource(pdev, 0);
> if (IS_ERR(host->axi))
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260629220932.861445-1-prabhakar.mahadev-lad.rj@bp.renesas.com?part=3
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v5 4/4] PCI: rzg3s-host: Add support for RZ/V2H(P) SoC
2026-06-29 22:09 [PATCH v5 0/4] Add PCIe support for RZ/V2H(P) SoC Prabhakar
` (2 preceding siblings ...)
2026-06-29 22:09 ` [PATCH v5 3/4] PCI: rzg3s-host: Prepare System Controller handling for multiple controllers Prabhakar
@ 2026-06-29 22:09 ` Prabhakar
2026-06-29 22:16 ` sashiko-bot
3 siblings, 1 reply; 9+ messages in thread
From: Prabhakar @ 2026-06-29 22:09 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Lorenzo Pieralisi, Claudiu Beznea, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel,
Geert Uytterhoeven, Magnus Damm, linux-pci
Cc: linux-renesas-soc, devicetree, linux-kernel, Prabhakar, Biju Das,
Fabrizio Castro, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Add support for the RZ/V2H(P) SoC PCIe controllers to the rzg3s-host
driver.
The RZ/V2H(P) SoC features two independent PCIe controllers that share
four physical lanes. The hardware supports two configuration modes:
single x4 mode where the first controller uses all four lanes, or dual
x2 mode where both controllers use two lanes each.
Introduce a setup_lanes() function pointer to configure the PCIe lanes
based on the hardware instance. Implement rzv2h_pcie_setup_lanes() to
detect the configuration at boot time and program the lane mode via the
system controller.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
v4->v5:
- No change
v3->v4:
- In rzv2h_pcie_setup_lanes() returned early in case of error
- Added RB/TB tags
v2->v3:
- Parsed controller-id from the "renesas,sysc" property instead of
using linux,pci-domain.
v1->v2:
- Updated commit message.
- Added locks to protect shared lane configuration state and
prevent concurrent access issues during probe.
- Added cleanup action to release lanes on driver removal.
- Reconfigured RZG3S_SYSC_FUNC_ID_LINK_MASTER in resume path.
- Renamed num_channels to num_pcie_controllers for clarity.
---
drivers/pci/controller/pcie-rzg3s-host.c | 181 +++++++++++++++++++++++
1 file changed, 181 insertions(+)
diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
index 03d79e98c9c9..a1a78bdb7af1 100644
--- a/drivers/pci/controller/pcie-rzg3s-host.c
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -180,6 +180,16 @@
/* Timeouts experimentally determined */
#define RZG3S_REQ_ISSUE_TIMEOUT_US 2500
+/**
+ * enum rzg3s_sysc_link_mode - PCIe link configuration modes
+ * @RZG3S_SYSC_LINK_MODE_SINGLE_X4: Single port with x4 lanes
+ * @RZG3S_SYSC_LINK_MODE_DUAL_X2: Dual ports with x2 lanes each
+ */
+enum rzg3s_sysc_link_mode {
+ RZG3S_SYSC_LINK_MODE_SINGLE_X4 = 1,
+ RZG3S_SYSC_LINK_MODE_DUAL_X2 = 3,
+};
+
/**
* struct rzg3s_sysc_function - System Controller function descriptor
* @offset: Register offset from the System Controller base address
@@ -195,12 +205,14 @@ struct rzg3s_sysc_function {
* @RZG3S_SYSC_FUNC_ID_RST_RSM_B: RST_RSM_B SYSC function ID
* @RZG3S_SYSC_FUNC_ID_L1_ALLOW: L1 allow SYSC function ID
* @RZG3S_SYSC_FUNC_ID_MODE: Mode SYSC function ID
+ * @RZG3S_SYSC_FUNC_ID_LINK_MASTER: Link master SYSC function ID
* @RZG3S_SYSC_FUNC_ID_MAX: Max SYSC function ID
*/
enum rzg3s_sysc_func_id {
RZG3S_SYSC_FUNC_ID_RST_RSM_B,
RZG3S_SYSC_FUNC_ID_L1_ALLOW,
RZG3S_SYSC_FUNC_ID_MODE,
+ RZG3S_SYSC_FUNC_ID_LINK_MASTER,
RZG3S_SYSC_FUNC_ID_MAX,
};
@@ -262,6 +274,7 @@ struct rzg3s_pcie_host;
* @config_pre_init: Optional callback for SoC-specific pre-configuration
* @config_post_init: Callback for SoC-specific post-configuration
* @config_deinit: Callback for SoC-specific de-initialization
+ * @setup_lanes: Callback for setting up the number of lanes
* @power_resets: array with the resets that need to be de-asserted after
* power-on
* @cfg_resets: array with the resets that need to be de-asserted after
@@ -269,17 +282,20 @@ struct rzg3s_pcie_host;
* @sysc_info: System Controller info for each controller
* @num_power_resets: number of power resets
* @num_cfg_resets: number of configuration resets
+ * @num_pcie_controllers: number of PCIe controllers
*/
struct rzg3s_pcie_soc_data {
int (*init_phy)(struct rzg3s_pcie_host *host);
void (*config_pre_init)(struct rzg3s_pcie_host *host);
int (*config_post_init)(struct rzg3s_pcie_host *host);
int (*config_deinit)(struct rzg3s_pcie_host *host);
+ int (*setup_lanes)(struct rzg3s_pcie_host *host);
const char * const *power_resets;
const char * const *cfg_resets;
struct rzg3s_sysc_info sysc_info[RZG3S_PCIE_CONTROLLER_ID_MAX];
u8 num_power_resets;
u8 num_cfg_resets;
+ u8 num_pcie_controllers;
};
/**
@@ -310,6 +326,7 @@ struct rzg3s_pcie_port {
* @intx_irqs: INTx interrupts
* @max_link_speed: maximum supported link speed
* @controller_id: PCIe controller identifier, used for System Controller access
+ * @num_lanes: The number of lanes
*/
struct rzg3s_pcie_host {
void __iomem *axi;
@@ -326,10 +343,23 @@ struct rzg3s_pcie_host {
int intx_irqs[PCI_NUM_INTX];
int max_link_speed;
enum rzg3s_pcie_controller_id controller_id;
+ u8 num_lanes;
};
#define rzg3s_msi_to_host(_msi) container_of(_msi, struct rzg3s_pcie_host, msi)
+/*
+ * RZ/V2H(P) supports a total of 4 lanes shared across two controllers.
+ * rzv2h_lane_lock serialises both the counter update and the SYSC
+ * register write so that concurrent async probes cannot race on the
+ * shared LINK_MASTER register (offset 0x1060).
+ * rzv2h_num_total_lanes tracks global lane usage to prevent
+ * over-allocation or invalid bifurcation modes.
+ */
+#define RZV2H_PCIE_MAX_LANES 4
+static DEFINE_SPINLOCK(rzv2h_lane_lock);
+static u8 rzv2h_num_total_lanes;
+
static int rzg3s_sysc_config_func(struct rzg3s_sysc *sysc,
enum rzg3s_sysc_func_id fid, u32 val)
{
@@ -1156,6 +1186,13 @@ static int rzg3s_pcie_config_init(struct rzg3s_pcie_host *host)
rzg3s_pcie_update_bits(host->pcie, PCI_CLASS_REVISION, mask,
field_prep(mask, PCI_CLASS_BRIDGE_PCI_NORMAL));
+ if (host->num_lanes) {
+ rzg3s_pcie_update_bits(host->pcie + RZG3S_PCI_CFG_PCIEC,
+ PCI_EXP_LNKCAP, PCI_EXP_LNKCAP_MLW,
+ FIELD_PREP(PCI_EXP_LNKCAP_MLW,
+ host->num_lanes));
+ }
+
/* Disable access control to the CFGU */
writel_relaxed(0, host->axi + RZG3S_PCI_PERM);
@@ -1688,6 +1725,76 @@ rzg3s_pcie_host_setup(struct rzg3s_pcie_host *host,
return ret;
}
+static int rzg3s_pcie_get_controller_id(struct rzg3s_pcie_host *host)
+{
+ struct device_node *np = host->dev->of_node;
+ struct of_phandle_args sysc_args;
+ int ret;
+
+ if (host->data->num_pcie_controllers == 1)
+ return 0;
+
+ ret = of_parse_phandle_with_fixed_args(np, "renesas,sysc", 1, 0, &sysc_args);
+ if (ret)
+ return ret;
+
+ of_node_put(sysc_args.np);
+
+ if (sysc_args.args[0] >= host->data->num_pcie_controllers ||
+ sysc_args.args[0] >= RZG3S_PCIE_CONTROLLER_ID_MAX)
+ return -EINVAL;
+
+ host->controller_id = sysc_args.args[0];
+
+ return 0;
+}
+
+static int rzv2h_pcie_setup_lanes(struct rzg3s_pcie_host *host)
+{
+ struct device_node *np = host->dev->of_node;
+ u32 num_lanes;
+ int ret;
+
+ ret = of_property_read_u32(np, "num-lanes", &num_lanes);
+ if (ret)
+ return ret;
+
+ /*
+ * RZ/V2H(P) supports up to 4 lanes, but only in single x4 mode
+ * for the first controller. Dual x2 mode is supported with 2
+ * lanes for both controllers.
+ */
+ if (num_lanes != 4 && num_lanes != 2)
+ return -EINVAL;
+
+ if (host->controller_id == RZG3S_PCIE_CONTROLLER_ID_1 && num_lanes > 2)
+ return -EINVAL;
+
+ guard(spinlock)(&rzv2h_lane_lock);
+ if (rzv2h_num_total_lanes + num_lanes > RZV2H_PCIE_MAX_LANES)
+ return -EINVAL;
+
+ ret = rzg3s_sysc_config_func(host->sysc, RZG3S_SYSC_FUNC_ID_LINK_MASTER,
+ num_lanes == 2 ?
+ RZG3S_SYSC_LINK_MODE_DUAL_X2 :
+ RZG3S_SYSC_LINK_MODE_SINGLE_X4);
+ if (ret)
+ return ret;
+
+ rzv2h_num_total_lanes += num_lanes;
+ host->num_lanes = num_lanes;
+
+ return 0;
+}
+
+static void rzv2h_pcie_release_lanes(void *data)
+{
+ struct rzg3s_pcie_host *host = data;
+
+ guard(spinlock)(&rzv2h_lane_lock);
+ rzv2h_num_total_lanes -= host->num_lanes;
+}
+
static int rzg3s_pcie_probe(struct platform_device *pdev)
{
struct pci_host_bridge *bridge;
@@ -1712,6 +1819,10 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
if (!host->sysc)
return -ENOMEM;
+ ret = rzg3s_pcie_get_controller_id(host);
+ if (ret)
+ return ret;
+
sysc = host->sysc;
sysc->info = &host->data->sysc_info[host->controller_id];
@@ -1741,6 +1852,16 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
if (ret)
goto port_refclk_put;
+ if (host->data->setup_lanes) {
+ ret = host->data->setup_lanes(host);
+ if (ret)
+ goto sysc_signal_restore;
+
+ ret = devm_add_action_or_reset(dev, rzv2h_pcie_release_lanes, host);
+ if (ret)
+ goto sysc_signal_restore;
+ }
+
ret = rzg3s_pcie_resets_prepare_and_get(host);
if (ret)
goto sysc_signal_restore;
@@ -1855,6 +1976,16 @@ static int rzg3s_pcie_resume_noirq(struct device *dev)
if (ret)
return ret;
+ if (host->num_lanes) {
+ ret = rzg3s_sysc_config_func(host->sysc,
+ RZG3S_SYSC_FUNC_ID_LINK_MASTER,
+ host->num_lanes == 2 ?
+ RZG3S_SYSC_LINK_MODE_DUAL_X2 :
+ RZG3S_SYSC_LINK_MODE_SINGLE_X4);
+ if (ret)
+ goto assert_rst_rsm_b;
+ }
+
ret = rzg3s_pcie_power_resets_deassert(host);
if (ret)
goto assert_rst_rsm_b;
@@ -1902,6 +2033,7 @@ static const struct rzg3s_pcie_soc_data rzg3s_soc_data = {
.num_power_resets = ARRAY_SIZE(rzg3s_soc_power_resets),
.cfg_resets = rzg3s_soc_cfg_resets,
.num_cfg_resets = ARRAY_SIZE(rzg3s_soc_cfg_resets),
+ .num_pcie_controllers = 1,
.config_post_init = rzg3s_pcie_config_post_init,
.config_deinit = rzg3s_pcie_config_deinit,
.init_phy = rzg3s_soc_pcie_init_phy,
@@ -1922,6 +2054,7 @@ static const char * const rzg3e_soc_power_resets[] = { "aresetn" };
static const struct rzg3s_pcie_soc_data rzg3e_soc_data = {
.power_resets = rzg3e_soc_power_resets,
.num_power_resets = ARRAY_SIZE(rzg3e_soc_power_resets),
+ .num_pcie_controllers = 1,
.config_pre_init = rzg3e_pcie_config_pre_init,
.config_post_init = rzg3e_pcie_config_post_init,
.config_deinit = rzg3e_pcie_config_deinit,
@@ -1941,6 +2074,50 @@ static const struct rzg3s_pcie_soc_data rzg3e_soc_data = {
},
};
+static const struct rzg3s_pcie_soc_data rzv2h_soc_data = {
+ .power_resets = rzg3e_soc_power_resets,
+ .num_power_resets = ARRAY_SIZE(rzg3e_soc_power_resets),
+ .num_pcie_controllers = 2,
+ .config_pre_init = rzg3e_pcie_config_pre_init,
+ .config_post_init = rzg3e_pcie_config_post_init,
+ .config_deinit = rzg3e_pcie_config_deinit,
+ .setup_lanes = rzv2h_pcie_setup_lanes,
+ .sysc_info = {
+ [RZG3S_PCIE_CONTROLLER_ID_0] = {
+ .functions = {
+ [RZG3S_SYSC_FUNC_ID_L1_ALLOW] = {
+ .offset = 0x1020,
+ .mask = BIT(0),
+ },
+ [RZG3S_SYSC_FUNC_ID_MODE] = {
+ .offset = 0x1024,
+ .mask = BIT(0),
+ },
+ [RZG3S_SYSC_FUNC_ID_LINK_MASTER] = {
+ .offset = 0x1060,
+ .mask = GENMASK(9, 8),
+ },
+ },
+ },
+ [RZG3S_PCIE_CONTROLLER_ID_1] = {
+ .functions = {
+ [RZG3S_SYSC_FUNC_ID_L1_ALLOW] = {
+ .offset = 0x1050,
+ .mask = BIT(0),
+ },
+ [RZG3S_SYSC_FUNC_ID_MODE] = {
+ .offset = 0x1054,
+ .mask = BIT(0),
+ },
+ [RZG3S_SYSC_FUNC_ID_LINK_MASTER] = {
+ .offset = 0x1060,
+ .mask = GENMASK(9, 8),
+ },
+ },
+ },
+ },
+};
+
static const struct of_device_id rzg3s_pcie_of_match[] = {
{
.compatible = "renesas,r9a08g045-pcie",
@@ -1950,6 +2127,10 @@ static const struct of_device_id rzg3s_pcie_of_match[] = {
.compatible = "renesas,r9a09g047-pcie",
.data = &rzg3e_soc_data,
},
+ {
+ .compatible = "renesas,r9a09g057-pcie",
+ .data = &rzv2h_soc_data,
+ },
{}
};
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread