Re: [PATCH v4 13/18] PCI: dwc: Let glue drivers hide the Root Port MSI capabilities

From: Shawn Lin

Date: Thu Oct 15 2026 - 00:19:04 EST


Hi Koichiro

在 2026/10/15 星期四 11:30, Koichiro Den 写道:
Commit f5cd8a929c82 ("PCI: dwc: Remove MSI/MSIX capability for Root Port
if iMSI-RX is used as MSI controller") hides the Root Port MSI/MSI-X
capabilities when iMSI-RX is the MSI controller, as it cannot receive
the Root Port's own MSIs.

Some platforms cannot deliver them with an external MSI controller
either. The DesignWare core signals Root Port interrupts (AER, PME,
bandwidth, hotplug) as sideband signals on its SII interface and only
turns them into MSI writes with the optional SII2MSI feature. Otherwise
it is up to the vendor wrapper. The controller on R-Car Gen4 SoCs
(DWC 5.20a) appears to lack SII2MSI, and its APP block merely latches
the signals into status registers wired to platform IRQs, so an MSI
targeted at the GIC ITS is never sent.

Add a no_rp_msi flag so glue drivers can request the same INTx fallback
regardless of the MSI controller in use. It is the counterpart of
'keep_rp_msi_en' from commit 3a4e8302e72f ("PCI: imx6: Keep Root Port
MSI capability with iMSI-RX to work around hardware bug"), which keeps
precedence: that one is needed for endpoint MSIs to work at all, whereas
hiding the capability only moves the Root Port services to INTx. The
removal stays in dw_pcie_setup_rc(), which also runs after a Root Port
reset.


With it, dw_pcie_rp will carry three flags with overlapping and
priority-dependent semantics:

use_imsi_rx - the MSI controller is iMSI-RX
keep_rp_msi_en - do NOT remove the RP MSI caps (i.MX6 workaround)
no_rp_msi - the platform never gets the RP's own MSIs

and the resulting condition:

if ((pp->use_imsi_rx || pp->no_rp_msi) && !pp->keep_rp_msi_en)

is getting hard to reason about. Adding no_rp_msi for a single platform
whose controller is not even iMSI-RX makes the combination worse.

Since only R-Car Gen4 needs this, and it has its own host init, would it
be fine for the glue driver to call dw_pcie_remove_capability()
directly? I'd like to avoid growing the shared struct if a local
solution is possible.

Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
Changes since v3:
- No changes.

drivers/pci/controller/dwc/pcie-designware-host.c | 6 ++++--
drivers/pci/controller/dwc/pcie-designware.h | 1 +
2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 774e1936d999..32e179603cf4 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -1191,9 +1191,11 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
* The iMSI-RX module does not support receiving MSI or MSI-X generated
* by the Root Port. If iMSI-RX is used as the MSI controller, remove
* the MSI and MSI-X capabilities of the Root Port to allow the drivers
- * to fall back to INTx instead.
+ * to fall back to INTx instead. Glue drivers set no_rp_msi when the
+ * platform never delivers the Root Port's own MSIs, whatever the MSI
+ * controller in use.
*/
- if (pp->use_imsi_rx && !pp->keep_rp_msi_en) {
+ if ((pp->use_imsi_rx || pp->no_rp_msi) && !pp->keep_rp_msi_en) {
dw_pcie_remove_capability(pci, PCI_CAP_ID_MSI);
dw_pcie_remove_capability(pci, PCI_CAP_ID_MSIX);
}
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 2ce61709b58c..d94116402b74 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -445,6 +445,7 @@ struct dw_pcie_host_ops {
struct dw_pcie_rp {
bool use_imsi_rx:1;
bool keep_rp_msi_en:1;
+ bool no_rp_msi:1;
bool cfg0_io_shared:1;
u64 cfg0_base;
void __iomem *va_cfg0_base;