FAILED: patch "[PATCH] PCI: mediatek: Fix IRQ domain leak when port fails to enable" failed to apply to 5.10-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x f865a57896bd92d7662eb2818d8f48872e2cbbc7
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026071332-nectar-acre-e146@gregkh' --subject-prefix 'PATCH 5.10.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From f865a57896bd92d7662eb2818d8f48872e2cbbc7 Mon Sep 17 00:00:00 2001
From: Manivannan Sadhasivam <[email protected]>
Date: Thu, 21 May 2026 23:16:17 +0530
Subject: [PATCH] PCI: mediatek: Fix IRQ domain leak when port fails to enable
When mtk_pcie_enable_port() fails, mtk_pcie_port_free() removes the port from pcie->ports and frees the port structure. However, the IRQ domains set up earlier by mtk_pcie_init_irq_domain() are never freed.
Fix this by refactoring mtk_pcie_irq_teardown() into a per-port helper, mtk_pcie_irq_teardown_port(), and calling it from mtk_pcie_setup() when mtk_pcie_enable_port() fails. Since the IRQ teardown must only happen in the probe error path (during resume, child devices may have active MSI mappings and the NOIRQ context prohibits sleeping locks), mtk_pcie_enable_port() is changed to return an error code so callers can distinguish the two paths and act accordingly.
This issue was reported by Sashiko while reviewing the EcoNet EN7528 SoC support series.
drivers/pci/controller/pcie-mediatek.c +41 -24
@@ -530,23 +530,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)writel (val, port->base +PCIE_INT_MASK ); } +static void mtk_pcie_irq_teardown_port (struct mtk_pcie_port *port) +{ +irq_set_chained_handler_and_data (port->irq,NULL ,NULL ); + +if (port->irq_domain) +irq_domain_remove (port->irq_domain); + +if (IS_ENABLED (CONFIG_PCI_MSI )) { +if (port->inner_domain) +irq_domain_remove (port->inner_domain); + } + +irq_dispose_mapping (port->irq); +} +static void mtk_pcie_irq_teardown (struct mtk_pcie *pcie) {struct mtk_pcie_port *port, *tmp; -list_for_each_entry_safe (port, tmp, &pcie->ports, list) { -irq_set_chained_handler_and_data (port->irq,NULL ,NULL ); - -if (port->irq_domain) -irq_domain_remove (port->irq_domain); - -if (IS_ENABLED (CONFIG_PCI_MSI )) { -if (port->inner_domain) -irq_domain_remove (port->inner_domain); - } - -irq_dispose_mapping (port->irq); - } +list_for_each_entry_safe (port, tmp, &pcie->ports, list) +mtk_pcie_irq_teardown_port (port); } static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
@@ -866,7 +870,7 @@ static int mtk_pcie_startup_port_an7583(struct mtk_pcie_port *port)return mtk_pcie_startup_port_v2 (port); } -static void mtk_pcie_enable_port (struct mtk_pcie_port *port) +static int mtk_pcie_enable_port (struct mtk_pcie_port *port) {struct mtk_pcie *pcie = port->pcie;struct device *dev = pcie->dev;
@@ -875,7 +879,7 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port) err =clk_prepare_enable (port->sys_ck);if (err) {dev_err (dev,"failed to enable sys_ck%d clock\n" , port->slot); - goto err_sys_clk; +return err; } err =clk_prepare_enable (port->ahb_ck);
@@ -923,11 +927,15 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port) goto err_phy_on; } -if (!pcie->soc->startup (port)) -return ; + err = pcie->soc->startup (port); +if (err) { +dev_info (dev,"Port%d link down\n" , port->slot); + goto err_soc_startup; + } -dev_info (dev,"Port%d link down\n" , port->slot); +return 0 ; +err_soc_startup:phy_power_off (port->phy); err_phy_on:phy_exit (port->phy);
@@ -943,8 +951,8 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port)clk_disable_unprepare (port->ahb_ck); err_ahb_clk:clk_disable_unprepare (port->sys_ck); -err_sys_clk: -mtk_pcie_port_free (port); + +return err; } static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
@@ -1110,8 +1118,13 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)return err;/* enable each port, and then check link status */ -list_for_each_entry_safe (port, tmp, &pcie->ports, list) -mtk_pcie_enable_port (port); +list_for_each_entry_safe (port, tmp, &pcie->ports, list) { + err =mtk_pcie_enable_port (port); +if (err) { +mtk_pcie_irq_teardown_port (port); +mtk_pcie_port_free (port); + } + }/* power down PCIe subsys if slots are all empty (link down) */ if (list_empty (&pcie->ports))
@@ -1210,14 +1223,18 @@ static int mtk_pcie_resume_noirq(struct device *dev) {struct mtk_pcie *pcie =dev_get_drvdata (dev);struct mtk_pcie_port *port, *tmp; +int err;if (list_empty (&pcie->ports))return 0 ;clk_prepare_enable (pcie->free_ck); -list_for_each_entry_safe (port, tmp, &pcie->ports, list) -mtk_pcie_enable_port (port); +list_for_each_entry_safe (port, tmp, &pcie->ports, list) { + err =mtk_pcie_enable_port (port); +if (err) +mtk_pcie_port_free (port); + }/* In case of EP was removed while system suspend. */ if (list_empty (&pcie->ports))
Sasha Levin
maintainerPATCH 1/3 PCI: controller: Use dev_fwnode() instead of of_fwnode_handle()
From: "Jiri Slaby (SUSE)" <[email protected]>
[ Upstream commit a103d2dede5683dabbac2c3374bc24b6a9434478 ]
All irq_domain functions now accept fwnode instead of of_node. But many PCI controllers still extract dev to of_node and then of_node to fwnode.
Instead, clean this up and simply use the dev_fwnode() helper to extract fwnode directly from dev. Internally, it still does dev => of_node => fwnode steps, but it's now hidden from the users.
In the case of altera, this also removes an unused 'node' variable that is only used when CONFIG_OF is enabled:
drivers/pci/controller/pcie-altera.c: In function 'altera_pcie_init_irq_domain':
drivers/pci/controller/pcie-altera.c:855:29: error: unused variable 'node' [-Werror=unused-variable]
855 | struct device_node *node = dev->of_node;
Stable-dep-of: f865a57896bd ("PCI: mediatek: Fix IRQ domain leak when port fails to enable")
--- drivers/pci/controller/dwc/pcie-designware-host.c | 2 +- drivers/pci/controller/mobiveil/pcie-mobiveil-host.c | 8 +++----- drivers/pci/controller/pcie-altera-msi.c | 2 +- drivers/pci/controller/pcie-altera.c | 3 +-- drivers/pci/controller/pcie-mediatek.c | 2 +- drivers/pci/controller/pcie-xilinx-nwl.c | 2 +- 6 files changed, 8 insertions(+), 11 deletions(-)
drivers/pci/controller/dwc/pcie-designware-host.c +1 -1
@@ -233,7 +233,7 @@ static const struct irq_domain_ops dw_pcie_msi_domain_ops = {int dw_pcie_allocate_domains (struct pcie_port *pp) {struct dw_pcie *pci =to_dw_pcie_from_pp (pp); -struct fwnode_handle *fwnode =of_node_to_fwnode (pci->dev->of_node); +struct fwnode_handle *fwnode =dev_fwnode (pci->dev); pp->irq_domain =irq_domain_create_linear (fwnode, pp->num_vectors, &dw_pcie_msi_domain_ops, pp);
drivers/pci/controller/mobiveil/pcie-mobiveil-host.c +3 -5
@@ -452,7 +452,7 @@ static const struct irq_domain_ops msi_domain_ops = {static int mobiveil_allocate_msi_domains (struct mobiveil_pcie *pcie) {struct device *dev = &pcie->pdev->dev; -struct fwnode_handle *fwnode =of_node_to_fwnode (dev->of_node); +struct fwnode_handle *fwnode =dev_fwnode (dev);struct mobiveil_msi *msi = &pcie->rp.msi;mutex_init (&msi->lock);
@@ -478,13 +478,11 @@ static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie)static int mobiveil_pcie_init_irq_domain (struct mobiveil_pcie *pcie) {struct device *dev = &pcie->pdev->dev; -struct device_node *node = dev->of_node;struct mobiveil_root_port *rp = &pcie->rp;/* setup INTx */ - rp->intx_domain =irq_domain_add_linear (node,PCI_NUM_INTX , - &intx_domain_ops, pcie); - + rp->intx_domain =irq_domain_create_linear (dev_fwnode (dev),PCI_NUM_INTX , &intx_domain_ops, + pcie);if (!rp->intx_domain) {dev_err (dev,"Failed to get a INTx IRQ domain\n" );return -ENOMEM ;
drivers/pci/controller/pcie-altera-msi.c +1 -1
@@ -173,7 +173,7 @@ static const struct irq_domain_ops msi_domain_ops = {static int altera_allocate_domains (struct altera_msi *msi) { -struct fwnode_handle *fwnode =of_node_to_fwnode (msi->pdev->dev.of_node); +struct fwnode_handle *fwnode =dev_fwnode (&msi->pdev->dev); msi->inner_domain =irq_domain_add_linear (NULL , msi->num_of_vectors, &msi_domain_ops, msi);
drivers/pci/controller/pcie-altera.c +1 -2
@@ -672,10 +672,9 @@ static void altera_pcie_isr(struct irq_desc *desc)static int altera_pcie_init_irq_domain (struct altera_pcie *pcie) {struct device *dev = &pcie->pdev->dev; -struct device_node *node = dev->of_node;/* Setup INTx */ - pcie->irq_domain =irq_domain_add_linear (node,PCI_NUM_INTX , + pcie->irq_domain =irq_domain_create_linear (dev_fwnode (dev),PCI_NUM_INTX , &intx_domain_ops, pcie);if (!pcie->irq_domain) {dev_err (dev,"Failed to get a INTx IRQ domain\n" );
drivers/pci/controller/pcie-mediatek.c +1 -1
@@ -494,7 +494,7 @@ static struct msi_domain_info mtk_msi_domain_info = {static int mtk_pcie_allocate_msi_domains (struct mtk_pcie_port *port) { -struct fwnode_handle *fwnode =of_node_to_fwnode (port->pcie->dev->of_node); +struct fwnode_handle *fwnode =dev_fwnode (port->pcie->dev);mutex_init (&port->lock);
drivers/pci/controller/pcie-xilinx-nwl.c +1 -1
@@ -515,7 +515,7 @@ static int nwl_pcie_init_msi_irq_domain(struct nwl_pcie *pcie) {#ifdef CONFIG_PCI_MSI struct device *dev = pcie->dev; -struct fwnode_handle *fwnode =of_node_to_fwnode (dev->of_node); +struct fwnode_handle *fwnode =dev_fwnode (dev);struct nwl_msi *msi = &pcie->msi; msi->dev_domain = irq_domain_add_linear(NULL, INT_PCI_MSI_NR,
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 PCI: mediatek: Convert bool to single quirks entry and bitmap
From: Christian Marangi <[email protected]>
[ Upstream commit 04305367fab7ec9c98eeba315ad09c8b20abce93 ]
To clean Mediatek SoC PCIe struct, convert all the bool to a bitmap and use a single quirks to reference all the values. This permits cleaner addition of new quirk without having to define a new bool in the struct.
Stable-dep-of: f865a57896bd ("PCI: mediatek: Fix IRQ domain leak when port fails to enable")
--- drivers/pci/controller/pcie-mediatek.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
drivers/pci/controller/pcie-mediatek.c +16 -9
@@ -139,22 +139,30 @@struct mtk_pcie_port ; +/** +* enum mtk_pcie_quirks - MTK PCIe quirks +* @MTK_PCIE_FIX_CLASS_ID: host's class ID needed to be fixed +* @MTK_PCIE_FIX_DEVICE_ID: host's device ID needed to be fixed +*/ +enum mtk_pcie_quirks { +MTK_PCIE_FIX_CLASS_ID =BIT (0 ), +MTK_PCIE_FIX_DEVICE_ID =BIT (1 ), +}; +/** * struct mtk_pcie_soc - differentiate between host generations -* @need_fix_class_id: whether this host's class ID needed to be fixed or not -* @need_fix_device_id: whether this host's device ID needed to be fixed or not * @device_id: device ID which this host need to be fixed * @ops: pointer to configuration access functions * @startup: pointer to controller setting functions * @setup_irq: pointer to initialize IRQ functions +* @quirks: PCIe device quirks. */ struct mtk_pcie_soc { -bool need_fix_class_id; -bool need_fix_device_id;unsigned int device_id;struct pci_ops *ops;int (*startup)(struct mtk_pcie_port *port);int (*setup_irq)(struct mtk_pcie_port *port,struct device_node *node); +enum mtk_pcie_quirks quirks; };/**
@@ -707,7 +715,7 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)writel (val, port->base +PCIE_RST_CTRL );/* Set up vendor ID and class code */ -if (soc->need_fix_class_id) { +if (soc->quirks &MTK_PCIE_FIX_CLASS_ID ) { val =PCI_VENDOR_ID_MEDIATEK ;writew (val, port->base +PCIE_CONF_VEND_ID );
@@ -715,7 +723,7 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)writew (val, port->base +PCIE_CONF_CLASS_ID ); } -if (soc->need_fix_device_id) +if (soc->quirks &MTK_PCIE_FIX_DEVICE_ID )writew (soc->device_id, port->base +PCIE_CONF_DEVICE_ID );/* 100ms timeout value should be enough for Gen1/2 training */
@@ -1195,19 +1203,18 @@ static const struct mtk_pcie_soc mtk_pcie_soc_mt2712 = { };static const struct mtk_pcie_soc mtk_pcie_soc_mt7622 = { - .need_fix_class_id = true, .ops = &mtk_pcie_ops_v2, .startup = mtk_pcie_startup_port_v2, .setup_irq = mtk_pcie_setup_irq, + .quirks =MTK_PCIE_FIX_CLASS_ID , };static const struct mtk_pcie_soc mtk_pcie_soc_mt7629 = { - .need_fix_class_id = true, - .need_fix_device_id = true, .device_id =PCI_DEVICE_ID_MEDIATEK_7629 , .ops = &mtk_pcie_ops_v2, .startup = mtk_pcie_startup_port_v2, .setup_irq = mtk_pcie_setup_irq, + .quirks =MTK_PCIE_FIX_CLASS_ID |MTK_PCIE_FIX_DEVICE_ID , };static const struct of_device_id mtk_pcie_ids[] = {
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 PCI: mediatek: Fix IRQ domain leak when port fails to enable
In reply to Sasha LevinFrom: Manivannan Sadhasivam <[email protected]>
[ Upstream commit f865a57896bd92d7662eb2818d8f48872e2cbbc7 ]
When mtk_pcie_enable_port() fails, mtk_pcie_port_free() removes the port from pcie->ports and frees the port structure. However, the IRQ domains set up earlier by mtk_pcie_init_irq_domain() are never freed.
Fix this by refactoring mtk_pcie_irq_teardown() into a per-port helper, mtk_pcie_irq_teardown_port(), and calling it from mtk_pcie_setup() when mtk_pcie_enable_port() fails. Since the IRQ teardown must only happen in the probe error path (during resume, child devices may have active MSI mappings and the NOIRQ context prohibits sleeping locks), mtk_pcie_enable_port() is changed to return an error code so callers can distinguish the two paths and act accordingly.
This issue was reported by Sashiko while reviewing the EcoNet EN7528 SoC support series.
--- drivers/pci/controller/pcie-mediatek.c | 67 ++++++++++++++++---------- 1 file changed, 42 insertions(+), 25 deletions(-)
drivers/pci/controller/pcie-mediatek.c +42 -25
@@ -538,25 +538,29 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)writel (val, port->base +PCIE_INT_MASK ); } -static void mtk_pcie_irq_teardown (struct mtk_pcie *pcie) +static void mtk_pcie_irq_teardown_port (struct mtk_pcie_port *port) { -struct mtk_pcie_port *port, *tmp; +irq_set_chained_handler_and_data (port->irq,NULL ,NULL ); -list_for_each_entry_safe (port, tmp, &pcie->ports, list) { -irq_set_chained_handler_and_data (port->irq,NULL ,NULL ); +if (port->irq_domain) +irq_domain_remove (port->irq_domain); -if (port->irq_domain) -irq_domain_remove (port->irq_domain); +if (IS_ENABLED (CONFIG_PCI_MSI )) { +if (port->msi_domain) +irq_domain_remove (port->msi_domain); +if (port->inner_domain) +irq_domain_remove (port->inner_domain); + } -if (IS_ENABLED (CONFIG_PCI_MSI )) { -if (port->msi_domain) -irq_domain_remove (port->msi_domain); -if (port->inner_domain) -irq_domain_remove (port->inner_domain); - } +irq_dispose_mapping (port->irq); +} -irq_dispose_mapping (port->irq); - } +static void mtk_pcie_irq_teardown (struct mtk_pcie *pcie) +{ +struct mtk_pcie_port *port, *tmp; + +list_for_each_entry_safe (port, tmp, &pcie->ports, list) +mtk_pcie_irq_teardown_port (port); } static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
@@ -833,7 +837,7 @@ static int mtk_pcie_startup_port(struct mtk_pcie_port *port)return 0 ; } -static void mtk_pcie_enable_port (struct mtk_pcie_port *port) +static int mtk_pcie_enable_port (struct mtk_pcie_port *port) {struct mtk_pcie *pcie = port->pcie;struct device *dev = pcie->dev;
@@ -842,7 +846,7 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port) err =clk_prepare_enable (port->sys_ck);if (err) {dev_err (dev,"failed to enable sys_ck%d clock\n" , port->slot); - goto err_sys_clk; +return err; } err =clk_prepare_enable (port->ahb_ck);
@@ -890,11 +894,15 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port) goto err_phy_on; } -if (!pcie->soc->startup (port)) -return ; + err = pcie->soc->startup (port); +if (err) { +dev_info (dev,"Port%d link down\n" , port->slot); + goto err_soc_startup; + } -dev_info (dev,"Port%d link down\n" , port->slot); +return 0 ; +err_soc_startup:phy_power_off (port->phy); err_phy_on:phy_exit (port->phy);
@@ -910,8 +918,8 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port)clk_disable_unprepare (port->ahb_ck); err_ahb_clk:clk_disable_unprepare (port->sys_ck); -err_sys_clk: -mtk_pcie_port_free (port); + +return err; } static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
@@ -1066,8 +1074,13 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)return err;/* enable each port, and then check link status */ -list_for_each_entry_safe (port, tmp, &pcie->ports, list) -mtk_pcie_enable_port (port); +list_for_each_entry_safe (port, tmp, &pcie->ports, list) { + err =mtk_pcie_enable_port (port); +if (err) { +mtk_pcie_irq_teardown_port (port); +mtk_pcie_port_free (port); + } + }/* power down PCIe subsys if slots are all empty (link down) */ if (list_empty (&pcie->ports))
@@ -1170,14 +1183,18 @@ static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev) {struct mtk_pcie *pcie =dev_get_drvdata (dev);struct mtk_pcie_port *port, *tmp; +int err;if (list_empty (&pcie->ports))return 0 ;clk_prepare_enable (pcie->free_ck); -list_for_each_entry_safe (port, tmp, &pcie->ports, list) -mtk_pcie_enable_port (port); +list_for_each_entry_safe (port, tmp, &pcie->ports, list) { + err =mtk_pcie_enable_port (port); +if (err) +mtk_pcie_port_free (port); + }/* In case of EP was removed while system suspend. */ if (list_empty (&pcie->ports))
Signature · 1 line
2.53.0