OSDN Git Service

iommu/arm-smmu-v3: Unregister IOMMU and bus ops on device removal
authorWill Deacon <will@kernel.org>
Thu, 19 Dec 2019 12:03:47 +0000 (12:03 +0000)
committerJoerg Roedel <jroedel@suse.de>
Mon, 23 Dec 2019 13:06:05 +0000 (14:06 +0100)
When removing the SMMUv3 driver, we need to clear any state that we
registered during probe. This includes our bus ops, sysfs entries and
the IOMMU device registered for early firmware probing of masters.

Signed-off-by: Will Deacon <will@kernel.org>
Tested-by: John Garry <john.garry@huawei.com> # smmu v3
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/arm-smmu-v3.c

index 9d4c9de..46160a2 100644 (file)
@@ -3565,6 +3565,45 @@ static unsigned long arm_smmu_resource_size(struct arm_smmu_device *smmu)
                return SZ_128K;
 }
 
+static int arm_smmu_set_bus_ops(struct iommu_ops *ops)
+{
+       int err;
+
+#ifdef CONFIG_PCI
+       if (pci_bus_type.iommu_ops != ops) {
+               if (ops)
+                       pci_request_acs();
+               err = bus_set_iommu(&pci_bus_type, ops);
+               if (err)
+                       return err;
+       }
+#endif
+#ifdef CONFIG_ARM_AMBA
+       if (amba_bustype.iommu_ops != ops) {
+               err = bus_set_iommu(&amba_bustype, ops);
+               if (err)
+                       goto err_reset_pci_ops;
+       }
+#endif
+       if (platform_bus_type.iommu_ops != ops) {
+               err = bus_set_iommu(&platform_bus_type, ops);
+               if (err)
+                       goto err_reset_amba_ops;
+       }
+
+       return 0;
+
+err_reset_amba_ops:
+#ifdef CONFIG_ARM_AMBA
+       bus_set_iommu(&amba_bustype, NULL);
+#endif
+err_reset_pci_ops: __maybe_unused;
+#ifdef CONFIG_PCI
+       bus_set_iommu(&pci_bus_type, NULL);
+#endif
+       return err;
+}
+
 static int arm_smmu_device_probe(struct platform_device *pdev)
 {
        int irq, ret;
@@ -3655,33 +3694,16 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
                return ret;
        }
 
-#ifdef CONFIG_PCI
-       if (pci_bus_type.iommu_ops != &arm_smmu_ops) {
-               pci_request_acs();
-               ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
-               if (ret)
-                       return ret;
-       }
-#endif
-#ifdef CONFIG_ARM_AMBA
-       if (amba_bustype.iommu_ops != &arm_smmu_ops) {
-               ret = bus_set_iommu(&amba_bustype, &arm_smmu_ops);
-               if (ret)
-                       return ret;
-       }
-#endif
-       if (platform_bus_type.iommu_ops != &arm_smmu_ops) {
-               ret = bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
-               if (ret)
-                       return ret;
-       }
-       return 0;
+       return arm_smmu_set_bus_ops(&arm_smmu_ops);
 }
 
 static int arm_smmu_device_remove(struct platform_device *pdev)
 {
        struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
 
+       arm_smmu_set_bus_ops(NULL);
+       iommu_device_unregister(&smmu->iommu);
+       iommu_device_sysfs_remove(&smmu->iommu);
        arm_smmu_device_disable(smmu);
 
        return 0;