提交 4367a183 编写于 作者: J Jean-Philippe Brucker 提交者: Xie XiuQi

iommu/arm-smmu-v3: Link domains and devices

hulk inclusion
category: feature
bugzilla: 14369
CVE: NA
-------------------

When removing a mapping from a domain, we need to send an invalidation to
all devices that might have stored it in their Address Translation Cache
(ATC). In addition when updating the context descriptor of a live domain,
we'll need to send invalidations for all devices attached to it.

Maintain a list of devices in each domain, protected by a spinlock. It is
updated every time we attach or detach devices to and from domains.

It needs to be a spinlock because we'll invalidate ATC entries from
within hardirq-safe contexts, but it may be possible to relax the read
side with RCU later.
Signed-off-by: NJean-Philippe Brucker <jean-philippe.brucker@arm.com>
Signed-off-by: NFang Lijun <fanglijun3@huawei.com>
Reviewed-by: NHanjun Guo <guohanjun@huawei.com>
Reviewed-by: NZhen Lei <thunder.leizhen@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 d73dd486
...@@ -619,6 +619,11 @@ struct arm_smmu_device { ...@@ -619,6 +619,11 @@ struct arm_smmu_device {
struct arm_smmu_master_data { struct arm_smmu_master_data {
struct arm_smmu_device *smmu; struct arm_smmu_device *smmu;
struct arm_smmu_strtab_ent ste; struct arm_smmu_strtab_ent ste;
struct arm_smmu_domain *domain;
struct list_head list; /* domain->devices */
struct device *dev;
}; };
/* SMMU private data for an IOMMU domain */ /* SMMU private data for an IOMMU domain */
...@@ -643,6 +648,9 @@ struct arm_smmu_domain { ...@@ -643,6 +648,9 @@ struct arm_smmu_domain {
}; };
struct iommu_domain domain; struct iommu_domain domain;
struct list_head devices;
spinlock_t devices_lock;
}; };
struct arm_smmu_option_prop { struct arm_smmu_option_prop {
...@@ -1614,6 +1622,9 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type) ...@@ -1614,6 +1622,9 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
} }
mutex_init(&smmu_domain->init_mutex); mutex_init(&smmu_domain->init_mutex);
INIT_LIST_HEAD(&smmu_domain->devices);
spin_lock_init(&smmu_domain->devices_lock);
return &smmu_domain->domain; return &smmu_domain->domain;
} }
...@@ -1832,7 +1843,17 @@ static void arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec) ...@@ -1832,7 +1843,17 @@ 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 device *dev)
{ {
unsigned long flags;
struct arm_smmu_master_data *master = dev->iommu_fwspec->iommu_priv; struct arm_smmu_master_data *master = dev->iommu_fwspec->iommu_priv;
struct arm_smmu_domain *smmu_domain = master->domain;
if (smmu_domain) {
spin_lock_irqsave(&smmu_domain->devices_lock, flags);
list_del(&master->list);
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
master->domain = NULL;
}
master->ste.assigned = false; master->ste.assigned = false;
arm_smmu_install_ste_for_dev(dev->iommu_fwspec); arm_smmu_install_ste_for_dev(dev->iommu_fwspec);
...@@ -1841,6 +1862,7 @@ static void arm_smmu_detach_dev(struct device *dev) ...@@ -1841,6 +1862,7 @@ static void arm_smmu_detach_dev(struct device *dev)
static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
{ {
int ret = 0; int ret = 0;
unsigned long flags;
struct arm_smmu_device *smmu; struct arm_smmu_device *smmu;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
struct arm_smmu_master_data *master; struct arm_smmu_master_data *master;
...@@ -1876,6 +1898,11 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) ...@@ -1876,6 +1898,11 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
} }
ste->assigned = true; ste->assigned = true;
master->domain = smmu_domain;
spin_lock_irqsave(&smmu_domain->devices_lock, flags);
list_add(&master->list, &smmu_domain->devices);
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
if (smmu_domain->stage == ARM_SMMU_DOMAIN_BYPASS) { if (smmu_domain->stage == ARM_SMMU_DOMAIN_BYPASS) {
ste->s1_cfg = NULL; ste->s1_cfg = NULL;
...@@ -2002,6 +2029,7 @@ static int arm_smmu_add_device(struct device *dev) ...@@ -2002,6 +2029,7 @@ static int arm_smmu_add_device(struct device *dev)
return -ENOMEM; return -ENOMEM;
master->smmu = smmu; master->smmu = smmu;
master->dev = dev;
fwspec->iommu_priv = master; fwspec->iommu_priv = master;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册