--- /dev/null
+From 31bd94abcc7df075ab0e225a841e50a119babe69 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2020 11:53:06 +0200
+Subject: irqdomain/treewide: Keep firmware node unconditionally allocated
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit e3beca48a45b5e0e6e6a4e0124276b8248dcc9bb ]
+
+Quite some non OF/ACPI users of irqdomains allocate firmware nodes of type
+IRQCHIP_FWNODE_NAMED or IRQCHIP_FWNODE_NAMED_ID and free them right after
+creating the irqdomain. The only purpose of these FW nodes is to convey
+name information. When this was introduced the core code did not store the
+pointer to the node in the irqdomain. A recent change stored the firmware
+node pointer in irqdomain for other reasons and missed to notice that the
+usage sites which do the alloc_fwnode/create_domain/free_fwnode sequence
+are broken by this. Storing a dangling pointer is dangerous itself, but in
+case that the domain is destroyed later on this leads to a double free.
+
+Remove the freeing of the firmware node after creating the irqdomain from
+all affected call sites to cure this.
+
+Fixes: 711419e504eb ("irqdomain: Add the missing assignment of domain->fwnode for named fwnode")
+Reported-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: Bjorn Helgaas <bhelgaas@google.com>
+Acked-by: Marc Zyngier <maz@kernel.org>
+Cc: stable@vger.kernel.org
+Link: https://lkml.kernel.org/r/873661qakd.fsf@nanos.tec.linutronix.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/apic/io_apic.c | 10 +++++-----
+ arch/x86/kernel/apic/msi.c | 16 +++++++++++-----
+ arch/x86/kernel/apic/vector.c | 1 -
+ arch/x86/platform/uv/uv_irq.c | 3 ++-
+ drivers/iommu/amd_iommu.c | 5 +++--
+ drivers/iommu/intel_irq_remapping.c | 2 +-
+ drivers/pci/host/vmd.c | 5 +++--
+ 7 files changed, 25 insertions(+), 17 deletions(-)
+
+diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
+index 2271adbc3c42a..b5652233e6745 100644
+--- a/arch/x86/kernel/apic/io_apic.c
++++ b/arch/x86/kernel/apic/io_apic.c
+@@ -2233,12 +2233,12 @@ static int mp_irqdomain_create(int ioapic)
+ ip->irqdomain = irq_domain_create_linear(fn, hwirqs, cfg->ops,
+ (void *)(long)ioapic);
+
+- /* Release fw handle if it was allocated above */
+- if (!cfg->dev)
+- irq_domain_free_fwnode(fn);
+-
+- if (!ip->irqdomain)
++ if (!ip->irqdomain) {
++ /* Release fw handle if it was allocated above */
++ if (!cfg->dev)
++ irq_domain_free_fwnode(fn);
+ return -ENOMEM;
++ }
+
+ ip->irqdomain->parent = parent;
+
+diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
+index f10e7f93b0e2c..8c102d62b8596 100644
+--- a/arch/x86/kernel/apic/msi.c
++++ b/arch/x86/kernel/apic/msi.c
+@@ -149,10 +149,11 @@ void __init arch_init_msi_domain(struct irq_domain *parent)
+ msi_default_domain =
+ pci_msi_create_irq_domain(fn, &pci_msi_domain_info,
+ parent);
+- irq_domain_free_fwnode(fn);
+ }
+- if (!msi_default_domain)
++ if (!msi_default_domain) {
++ irq_domain_free_fwnode(fn);
+ pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
++ }
+ }
+
+ #ifdef CONFIG_IRQ_REMAP
+@@ -185,7 +186,8 @@ struct irq_domain *arch_create_remap_msi_irq_domain(struct irq_domain *parent,
+ if (!fn)
+ return NULL;
+ d = pci_msi_create_irq_domain(fn, &pci_msi_ir_domain_info, parent);
+- irq_domain_free_fwnode(fn);
++ if (!d)
++ irq_domain_free_fwnode(fn);
+ return d;
+ }
+ #endif
+@@ -248,7 +250,8 @@ static struct irq_domain *dmar_get_irq_domain(void)
+ if (fn) {
+ dmar_domain = msi_create_irq_domain(fn, &dmar_msi_domain_info,
+ x86_vector_domain);
+- irq_domain_free_fwnode(fn);
++ if (!dmar_domain)
++ irq_domain_free_fwnode(fn);
+ }
+ out:
+ mutex_unlock(&dmar_lock);
+@@ -373,7 +376,10 @@ struct irq_domain *hpet_create_irq_domain(int hpet_id)
+ }
+
+ d = msi_create_irq_domain(fn, domain_info, parent);
+- irq_domain_free_fwnode(fn);
++ if (!d) {
++ irq_domain_free_fwnode(fn);
++ kfree(domain_info);
++ }
+ return d;
+ }
+
+diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
+index b958082c74a77..36cd34524ac19 100644
+--- a/arch/x86/kernel/apic/vector.c
++++ b/arch/x86/kernel/apic/vector.c
+@@ -457,7 +457,6 @@ int __init arch_early_irq_init(void)
+ x86_vector_domain = irq_domain_create_tree(fn, &x86_vector_domain_ops,
+ NULL);
+ BUG_ON(x86_vector_domain == NULL);
+- irq_domain_free_fwnode(fn);
+ irq_set_default_host(x86_vector_domain);
+
+ arch_init_msi_domain(x86_vector_domain);
+diff --git a/arch/x86/platform/uv/uv_irq.c b/arch/x86/platform/uv/uv_irq.c
+index 03fc397335b74..c9fc725a1dcf4 100644
+--- a/arch/x86/platform/uv/uv_irq.c
++++ b/arch/x86/platform/uv/uv_irq.c
+@@ -171,9 +171,10 @@ static struct irq_domain *uv_get_irq_domain(void)
+ goto out;
+
+ uv_domain = irq_domain_create_tree(fn, &uv_domain_ops, NULL);
+- irq_domain_free_fwnode(fn);
+ if (uv_domain)
+ uv_domain->parent = x86_vector_domain;
++ else
++ irq_domain_free_fwnode(fn);
+ out:
+ mutex_unlock(&uv_lock);
+
+diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
+index 778f167be2d35..494caaa265af0 100644
+--- a/drivers/iommu/amd_iommu.c
++++ b/drivers/iommu/amd_iommu.c
+@@ -4394,9 +4394,10 @@ int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
+ if (!fn)
+ return -ENOMEM;
+ iommu->ir_domain = irq_domain_create_tree(fn, &amd_ir_domain_ops, iommu);
+- irq_domain_free_fwnode(fn);
+- if (!iommu->ir_domain)
++ if (!iommu->ir_domain) {
++ irq_domain_free_fwnode(fn);
+ return -ENOMEM;
++ }
+
+ iommu->ir_domain->parent = arch_get_ir_parent_domain();
+ iommu->msi_domain = arch_create_remap_msi_irq_domain(iommu->ir_domain,
+diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
+index 25842b566c39c..154949a499c21 100644
+--- a/drivers/iommu/intel_irq_remapping.c
++++ b/drivers/iommu/intel_irq_remapping.c
+@@ -536,8 +536,8 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
+ 0, INTR_REMAP_TABLE_ENTRIES,
+ fn, &intel_ir_domain_ops,
+ iommu);
+- irq_domain_free_fwnode(fn);
+ if (!iommu->ir_domain) {
++ irq_domain_free_fwnode(fn);
+ pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id);
+ goto out_free_bitmap;
+ }
+diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c
+index af6d5da10ea5f..05f191ae0ff1b 100644
+--- a/drivers/pci/host/vmd.c
++++ b/drivers/pci/host/vmd.c
+@@ -638,9 +638,10 @@ static int vmd_enable_domain(struct vmd_dev *vmd)
+
+ vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info,
+ x86_vector_domain);
+- irq_domain_free_fwnode(fn);
+- if (!vmd->irq_domain)
++ if (!vmd->irq_domain) {
++ irq_domain_free_fwnode(fn);
+ return -ENODEV;
++ }
+
+ pci_add_resource(&resources, &vmd->resources[0]);
+ pci_add_resource(&resources, &vmd->resources[1]);
+--
+2.25.1
+