aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/arm-smmu-v3.c
diff options
context:
space:
mode:
authorPeng Fan <van.freenix@gmail.com>2015-11-20 16:56:18 +0800
committerWill Deacon <will.deacon@arm.com>2015-12-17 12:05:33 +0000
commit9a4a9d8c34bc0b0102e8a9dd67ee3910b0bfaeb4 (patch)
treed3f00b4266cfbe5cc38473296e206c07d5e91159 /drivers/iommu/arm-smmu-v3.c
parentiommu/arm-smmu: Use incoming shareability attributes in bypass mode (diff)
downloadlinux-dev-9a4a9d8c34bc0b0102e8a9dd67ee3910b0bfaeb4.tar.xz
linux-dev-9a4a9d8c34bc0b0102e8a9dd67ee3910b0bfaeb4.zip
iommu/arm-smmu: Correct group reference count
The basic flow for add a device: arm_smmu_add_device |->iommu_group_get_for_dev |->iommu_group_get return group; (1) |->ops->device_group : Init/increase reference count to/by 1. |->iommu_group_add_device : Increase reference count by 1. return group (2) |->return 0; Since we are adding one device, the flow is (2) and the group reference count will be increased by 2. So, we need to add iommu_group_put at the end of arm_smmu_add_device to decrease the count by 1. Also take the failure path into consideration when fail to add a device. Signed-off-by: Peng Fan <van.freenix@gmail.com> Cc: Will Deacon <will.deacon@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/iommu/arm-smmu-v3.c')
-rw-r--r--drivers/iommu/arm-smmu-v3.c18
1 files changed, 11 insertions, 7 deletions
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 2e3e235f509c..3ea4d576bf08 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1809,13 +1809,13 @@ static int arm_smmu_add_device(struct device *dev)
smmu = arm_smmu_get_for_pci_dev(pdev);
if (!smmu) {
ret = -ENOENT;
- goto out_put_group;
+ goto out_remove_dev;
}
smmu_group = kzalloc(sizeof(*smmu_group), GFP_KERNEL);
if (!smmu_group) {
ret = -ENOMEM;
- goto out_put_group;
+ goto out_remove_dev;
}
smmu_group->ste.valid = true;
@@ -1831,20 +1831,20 @@ static int arm_smmu_add_device(struct device *dev)
for (i = 0; i < smmu_group->num_sids; ++i) {
/* If we already know about this SID, then we're done */
if (smmu_group->sids[i] == sid)
- return 0;
+ goto out_put_group;
}
/* Check the SID is in range of the SMMU and our stream table */
if (!arm_smmu_sid_in_range(smmu, sid)) {
ret = -ERANGE;
- goto out_put_group;
+ goto out_remove_dev;
}
/* Ensure l2 strtab is initialised */
if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
ret = arm_smmu_init_l2_strtab(smmu, sid);
if (ret)
- goto out_put_group;
+ goto out_remove_dev;
}
/* Resize the SID array for the group */
@@ -1854,16 +1854,20 @@ static int arm_smmu_add_device(struct device *dev)
if (!sids) {
smmu_group->num_sids--;
ret = -ENOMEM;
- goto out_put_group;
+ goto out_remove_dev;
}
/* Add the new SID */
sids[smmu_group->num_sids - 1] = sid;
smmu_group->sids = sids;
- return 0;
out_put_group:
iommu_group_put(group);
+ return 0;
+
+out_remove_dev:
+ iommu_group_remove_device(dev);
+ iommu_group_put(group);
return ret;
}