diff options
author | Peng Fan <van.freenix@gmail.com> | 2015-11-20 03:56:18 -0500 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2015-12-17 07:05:33 -0500 |
commit | 9a4a9d8c34bc0b0102e8a9dd67ee3910b0bfaeb4 (patch) | |
tree | d3f00b4266cfbe5cc38473296e206c07d5e91159 /drivers/iommu | |
parent | a0eacd89e35e55aad284cc2e6865bf2dcf7037ba (diff) |
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')
-rw-r--r-- | drivers/iommu/arm-smmu-v3.c | 18 | ||||
-rw-r--r-- | drivers/iommu/arm-smmu.c | 1 |
2 files changed, 12 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) | |||
1809 | smmu = arm_smmu_get_for_pci_dev(pdev); | 1809 | smmu = arm_smmu_get_for_pci_dev(pdev); |
1810 | if (!smmu) { | 1810 | if (!smmu) { |
1811 | ret = -ENOENT; | 1811 | ret = -ENOENT; |
1812 | goto out_put_group; | 1812 | goto out_remove_dev; |
1813 | } | 1813 | } |
1814 | 1814 | ||
1815 | smmu_group = kzalloc(sizeof(*smmu_group), GFP_KERNEL); | 1815 | smmu_group = kzalloc(sizeof(*smmu_group), GFP_KERNEL); |
1816 | if (!smmu_group) { | 1816 | if (!smmu_group) { |
1817 | ret = -ENOMEM; | 1817 | ret = -ENOMEM; |
1818 | goto out_put_group; | 1818 | goto out_remove_dev; |
1819 | } | 1819 | } |
1820 | 1820 | ||
1821 | smmu_group->ste.valid = true; | 1821 | smmu_group->ste.valid = true; |
@@ -1831,20 +1831,20 @@ static int arm_smmu_add_device(struct device *dev) | |||
1831 | for (i = 0; i < smmu_group->num_sids; ++i) { | 1831 | for (i = 0; i < smmu_group->num_sids; ++i) { |
1832 | /* If we already know about this SID, then we're done */ | 1832 | /* If we already know about this SID, then we're done */ |
1833 | if (smmu_group->sids[i] == sid) | 1833 | if (smmu_group->sids[i] == sid) |
1834 | return 0; | 1834 | goto out_put_group; |
1835 | } | 1835 | } |
1836 | 1836 | ||
1837 | /* Check the SID is in range of the SMMU and our stream table */ | 1837 | /* Check the SID is in range of the SMMU and our stream table */ |
1838 | if (!arm_smmu_sid_in_range(smmu, sid)) { | 1838 | if (!arm_smmu_sid_in_range(smmu, sid)) { |
1839 | ret = -ERANGE; | 1839 | ret = -ERANGE; |
1840 | goto out_put_group; | 1840 | goto out_remove_dev; |
1841 | } | 1841 | } |
1842 | 1842 | ||
1843 | /* Ensure l2 strtab is initialised */ | 1843 | /* Ensure l2 strtab is initialised */ |
1844 | if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) { | 1844 | if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) { |
1845 | ret = arm_smmu_init_l2_strtab(smmu, sid); | 1845 | ret = arm_smmu_init_l2_strtab(smmu, sid); |
1846 | if (ret) | 1846 | if (ret) |
1847 | goto out_put_group; | 1847 | goto out_remove_dev; |
1848 | } | 1848 | } |
1849 | 1849 | ||
1850 | /* Resize the SID array for the group */ | 1850 | /* Resize the SID array for the group */ |
@@ -1854,16 +1854,20 @@ static int arm_smmu_add_device(struct device *dev) | |||
1854 | if (!sids) { | 1854 | if (!sids) { |
1855 | smmu_group->num_sids--; | 1855 | smmu_group->num_sids--; |
1856 | ret = -ENOMEM; | 1856 | ret = -ENOMEM; |
1857 | goto out_put_group; | 1857 | goto out_remove_dev; |
1858 | } | 1858 | } |
1859 | 1859 | ||
1860 | /* Add the new SID */ | 1860 | /* Add the new SID */ |
1861 | sids[smmu_group->num_sids - 1] = sid; | 1861 | sids[smmu_group->num_sids - 1] = sid; |
1862 | smmu_group->sids = sids; | 1862 | smmu_group->sids = sids; |
1863 | return 0; | ||
1864 | 1863 | ||
1865 | out_put_group: | 1864 | out_put_group: |
1866 | iommu_group_put(group); | 1865 | iommu_group_put(group); |
1866 | return 0; | ||
1867 | |||
1868 | out_remove_dev: | ||
1869 | iommu_group_remove_device(dev); | ||
1870 | iommu_group_put(group); | ||
1867 | return ret; | 1871 | return ret; |
1868 | } | 1872 | } |
1869 | 1873 | ||
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 1ce4b85d5216..6ed169bcb39d 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c | |||
@@ -1355,6 +1355,7 @@ static int arm_smmu_add_device(struct device *dev) | |||
1355 | if (IS_ERR(group)) | 1355 | if (IS_ERR(group)) |
1356 | return PTR_ERR(group); | 1356 | return PTR_ERR(group); |
1357 | 1357 | ||
1358 | iommu_group_put(group); | ||
1358 | return 0; | 1359 | return 0; |
1359 | } | 1360 | } |
1360 | 1361 | ||