diff mbox series

PCI: vmd: Keep fwnode allocated through VMD irqdomain life

Message ID 20200625162450.5419-2-jonathan.derrick@intel.com (mailing list archive)
State Changes Requested, archived
Headers show
Series PCI: vmd: Keep fwnode allocated through VMD irqdomain life | expand

Commit Message

Jon Derrick June 25, 2020, 4:24 p.m. UTC
From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

The VMD domain does not subscribe to ACPI, and so does not operate on
it's irqdomain fwnode. It was freeing the handle after allocation of the
domain. As of 181e9d4efaf6a (irqdomain: Make __irq_domain_add() less
OF-dependent), the fwnode is put during irq_domain_remove causing a page
fault. This patch keeps VMD's fwnode allocated through the lifetime of
the VMD irqdomain.

Fixes: ae904cafd59d ("PCI/vmd: Create named irq domain")
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Co-developed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Jon Derrick <jonathan.derrick@intel.com>
---
Hi Lorenzo, Bjorn,

Please take this patch for v5.8 fixes. It fixes an issue during VMD
unload.

Thanks
Jon

 drivers/pci/controller/vmd.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
index e386d4eac407..ebec0a6e77ed 100644
--- a/drivers/pci/controller/vmd.c
+++ b/drivers/pci/controller/vmd.c
@@ -546,9 +546,10 @@  static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
 
 	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_offset(&resources, &vmd->resources[1], offset[0]);
@@ -559,6 +560,7 @@  static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
 	if (!vmd->bus) {
 		pci_free_resource_list(&resources);
 		irq_domain_remove(vmd->irq_domain);
+		irq_domain_free_fwnode(fn);
 		return -ENODEV;
 	}
 
@@ -672,6 +674,7 @@  static void vmd_cleanup_srcu(struct vmd_dev *vmd)
 static void vmd_remove(struct pci_dev *dev)
 {
 	struct vmd_dev *vmd = pci_get_drvdata(dev);
+	struct fwnode_handle *fn = vmd->irq_domain->fwnode;
 
 	sysfs_remove_link(&vmd->dev->dev.kobj, "domain");
 	pci_stop_root_bus(vmd->bus);
@@ -679,6 +682,7 @@  static void vmd_remove(struct pci_dev *dev)
 	vmd_cleanup_srcu(vmd);
 	vmd_detach_resources(vmd);
 	irq_domain_remove(vmd->irq_domain);
+	irq_domain_free_fwnode(fn);
 }
 
 #ifdef CONFIG_PM_SLEEP