]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: imx6: Keep Root Port MSI capability with iMSI-RX to work around hardware bug
authorRichard Zhu <hongxing.zhu@nxp.com>
Tue, 31 Mar 2026 08:52:52 +0000 (16:52 +0800)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 3 Apr 2026 21:51:27 +0000 (16:51 -0500)
On NXP i.MX7D, i.MX8MM, and i.MX8MQ chipsets, MSIs from the endpoints won't
be received by the iMSI-RX MSI controller if the Root Port MSI capability
is disabled.

Even though the Root Port MSIs won't be received by the iMSI-RX controller
due to design, these chipsets have some weird hardware bug that prevents
the endpoint MSIs from reaching when the Root Port MSI capability is
disabled.

Hence, introduce a new flag, 'dw_pcie_rp::keep_rp_msi_en', set it for the
above mentioned SoCs, and always keep the Root Port MSI capability when
this flag is set.

Note that by keeping Root Port MSI capability, Root Port MSIs such as AER,
PME and others won't be received by default. So users need to use
workarounds such as passing 'pcie_pme=nomsi' cmdline param.

Fixes: f5cd8a929c825 ("PCI: dwc: Remove MSI/MSIX capability for Root Port if iMSI-RX is used as MSI controller")
Suggested-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
[mani: commit log]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
[bhelgaas: fix typos]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260331085252.1243108-1-hongxing.zhu@nxp.com
drivers/pci/controller/dwc/pci-imx6.c
drivers/pci/controller/dwc/pcie-designware-host.c
drivers/pci/controller/dwc/pcie-designware.h

index 24c373020adcb0f85eeb6b0f2937edf89b844079..a1da72dd85b0a21c9385af78516590c4acb26b1a 100644 (file)
@@ -117,6 +117,8 @@ enum imx_pcie_variants {
 #define IMX_PCIE_FLAG_HAS_LUT                  BIT(10)
 #define IMX_PCIE_FLAG_8GT_ECN_ERR051586                BIT(11)
 #define IMX_PCIE_FLAG_SKIP_L23_READY           BIT(12)
+/* Preserve MSI capability for platforms that require it */
+#define IMX_PCIE_FLAG_KEEP_MSI_CAP             BIT(13)
 
 #define imx_check_flag(pci, val)       (pci->drvdata->flags & val)
 
@@ -1828,6 +1830,8 @@ static int imx_pcie_probe(struct platform_device *pdev)
        } else {
                if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_SKIP_L23_READY))
                        pci->pp.skip_l23_ready = true;
+               if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_KEEP_MSI_CAP))
+                       pci->pp.keep_rp_msi_en = true;
                pci->pp.use_atu_msg = true;
                ret = dw_pcie_host_init(&pci->pp);
                if (ret < 0)
@@ -1907,6 +1911,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
        [IMX7D] = {
                .variant = IMX7D,
                .flags = IMX_PCIE_FLAG_SUPPORTS_SUSPEND |
+                        IMX_PCIE_FLAG_KEEP_MSI_CAP |
                         IMX_PCIE_FLAG_HAS_APP_RESET |
                         IMX_PCIE_FLAG_SKIP_L23_READY |
                         IMX_PCIE_FLAG_HAS_PHY_RESET,
@@ -1919,6 +1924,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
        [IMX8MQ] = {
                .variant = IMX8MQ,
                .flags = IMX_PCIE_FLAG_HAS_APP_RESET |
+                        IMX_PCIE_FLAG_KEEP_MSI_CAP |
                         IMX_PCIE_FLAG_HAS_PHY_RESET |
                         IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
                .gpr = "fsl,imx8mq-iomuxc-gpr",
@@ -1933,6 +1939,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
        [IMX8MM] = {
                .variant = IMX8MM,
                .flags = IMX_PCIE_FLAG_SUPPORTS_SUSPEND |
+                        IMX_PCIE_FLAG_KEEP_MSI_CAP |
                         IMX_PCIE_FLAG_HAS_PHYDRV |
                         IMX_PCIE_FLAG_HAS_APP_RESET,
                .gpr = "fsl,imx8mm-iomuxc-gpr",
index 6ae6189e9b8a9021c99ece17504834650debd86b..ded5462deae71d5ba1f71dcb13f614438746677e 100644 (file)
@@ -1171,7 +1171,7 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
         * the MSI and MSI-X capabilities of the Root Port to allow the drivers
         * to fall back to INTx instead.
         */
-       if (pp->use_imsi_rx) {
+       if (pp->use_imsi_rx && !pp->keep_rp_msi_en) {
                dw_pcie_remove_capability(pci, PCI_CAP_ID_MSI);
                dw_pcie_remove_capability(pci, PCI_CAP_ID_MSIX);
        }
index ae6389dd9caa5c27690f998d58729130ea863984..b12c5334552c7e12d3139b3081419f100dbe12d1 100644 (file)
@@ -421,6 +421,7 @@ struct dw_pcie_host_ops {
 
 struct dw_pcie_rp {
        bool                    use_imsi_rx:1;
+       bool                    keep_rp_msi_en:1;
        bool                    cfg0_io_shared:1;
        u64                     cfg0_base;
        void __iomem            *va_cfg0_base;