iommu/arm-smmu-v3: Store SteamIDs in master
Simplify the attach/detach code a bit by keeping a pointer to the stream IDs in the master structure. Although not completely obvious here, it does make the subsequent support for ATS, PRI and PASID a bit simpler. Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
parent
b54f4260c7
commit
bcecaee434
@ -594,6 +594,8 @@ struct arm_smmu_device {
|
||||
struct arm_smmu_master {
|
||||
struct arm_smmu_device *smmu;
|
||||
struct arm_smmu_strtab_ent ste;
|
||||
u32 *sids;
|
||||
unsigned int num_sids;
|
||||
};
|
||||
|
||||
/* SMMU private data for an IOMMU domain */
|
||||
@ -1688,19 +1690,18 @@ static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
|
||||
return step;
|
||||
}
|
||||
|
||||
static void arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec)
|
||||
static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master)
|
||||
{
|
||||
int i, j;
|
||||
struct arm_smmu_master *master = fwspec->iommu_priv;
|
||||
struct arm_smmu_device *smmu = master->smmu;
|
||||
|
||||
for (i = 0; i < fwspec->num_ids; ++i) {
|
||||
u32 sid = fwspec->ids[i];
|
||||
for (i = 0; i < master->num_sids; ++i) {
|
||||
u32 sid = master->sids[i];
|
||||
__le64 *step = arm_smmu_get_step_for_sid(smmu, sid);
|
||||
|
||||
/* Bridged PCI devices may end up with duplicated IDs */
|
||||
for (j = 0; j < i; j++)
|
||||
if (fwspec->ids[j] == sid)
|
||||
if (master->sids[j] == sid)
|
||||
break;
|
||||
if (j < i)
|
||||
continue;
|
||||
@ -1709,13 +1710,10 @@ static void arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec)
|
||||
}
|
||||
}
|
||||
|
||||
static void arm_smmu_detach_dev(struct device *dev)
|
||||
static void arm_smmu_detach_dev(struct arm_smmu_master *master)
|
||||
{
|
||||
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
|
||||
struct arm_smmu_master *master = fwspec->iommu_priv;
|
||||
|
||||
master->ste.assigned = false;
|
||||
arm_smmu_install_ste_for_dev(fwspec);
|
||||
arm_smmu_install_ste_for_dev(master);
|
||||
}
|
||||
|
||||
static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
|
||||
@ -1736,7 +1734,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
|
||||
|
||||
/* Already attached to a different domain? */
|
||||
if (ste->assigned)
|
||||
arm_smmu_detach_dev(dev);
|
||||
arm_smmu_detach_dev(master);
|
||||
|
||||
mutex_lock(&smmu_domain->init_mutex);
|
||||
|
||||
@ -1770,7 +1768,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
|
||||
ste->s2_cfg = &smmu_domain->s2_cfg;
|
||||
}
|
||||
|
||||
arm_smmu_install_ste_for_dev(fwspec);
|
||||
arm_smmu_install_ste_for_dev(master);
|
||||
out_unlock:
|
||||
mutex_unlock(&smmu_domain->init_mutex);
|
||||
return ret;
|
||||
@ -1883,12 +1881,14 @@ static int arm_smmu_add_device(struct device *dev)
|
||||
return -ENOMEM;
|
||||
|
||||
master->smmu = smmu;
|
||||
master->sids = fwspec->ids;
|
||||
master->num_sids = fwspec->num_ids;
|
||||
fwspec->iommu_priv = master;
|
||||
}
|
||||
|
||||
/* Check the SIDs are in range of the SMMU and our stream table */
|
||||
for (i = 0; i < fwspec->num_ids; i++) {
|
||||
u32 sid = fwspec->ids[i];
|
||||
for (i = 0; i < master->num_sids; i++) {
|
||||
u32 sid = master->sids[i];
|
||||
|
||||
if (!arm_smmu_sid_in_range(smmu, sid))
|
||||
return -ERANGE;
|
||||
@ -1922,7 +1922,7 @@ static void arm_smmu_remove_device(struct device *dev)
|
||||
master = fwspec->iommu_priv;
|
||||
smmu = master->smmu;
|
||||
if (master && master->ste.assigned)
|
||||
arm_smmu_detach_dev(dev);
|
||||
arm_smmu_detach_dev(master);
|
||||
iommu_group_remove_device(dev);
|
||||
iommu_device_unlink(&smmu->iommu, dev);
|
||||
kfree(master);
|
||||
|
Loading…
Reference in New Issue
Block a user