diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 54a8fe0a628bcc0717439baea1c5b400d2fcca31..aed9d2b35bbb21580f4ef46be64e404cd540a791 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -2280,26 +2280,43 @@ static int arm_smmu_add_device(struct device *dev) for (i = 0; i < fwspec->num_ids; i++) { u32 sid = fwspec->ids[i]; - if (!arm_smmu_sid_in_range(smmu, sid)) - return -ERANGE; + if (!arm_smmu_sid_in_range(smmu, sid)) { + ret = -ERANGE; + goto err_free_master; + } /* Ensure l2 strtab is initialised */ if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) { ret = arm_smmu_init_l2_strtab(smmu, sid); if (ret) - return ret; + goto err_free_master; } } master->ssid_bits = min(smmu->ssid_bits, fwspec->num_pasid_bits); + ret = iommu_device_link(&smmu->iommu, dev); + if (ret) + goto err_free_master; + group = iommu_group_get_for_dev(dev); - if (!IS_ERR(group)) { - iommu_group_put(group); - iommu_device_link(&smmu->iommu, dev); + if (IS_ERR(group)) { + ret = PTR_ERR(group); + goto err_unlink; } - return PTR_ERR_OR_ZERO(group); + iommu_group_put(group); + + return 0; + +err_unlink: + iommu_device_unlink(&smmu->iommu, dev); + +err_free_master: + kfree(master); + fwspec->iommu_priv = NULL; + + return ret; } static void arm_smmu_remove_device(struct device *dev) @@ -2312,9 +2329,12 @@ static void arm_smmu_remove_device(struct device *dev) return; master = fwspec->iommu_priv; + if (!master) + return; + smmu = master->smmu; iopf_queue_remove_device(dev); - if (master && master->ste.assigned) + if (master->ste.assigned) arm_smmu_detach_dev(dev); iommu_group_remove_device(dev); iommu_device_unlink(&smmu->iommu, dev);