Skip to content

Commit

Permalink
iommu/arm-smmu-v3: Link domains and devices
Browse files Browse the repository at this point in the history
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: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
  • Loading branch information
Jean-Philippe Brucker authored and Will Deacon committed Apr 23, 2019
1 parent 8be39a1 commit 2a7e62f
Showing 1 changed file with 20 additions and 1 deletion.
21 changes: 20 additions & 1 deletion drivers/iommu/arm-smmu-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ struct arm_smmu_device {
struct arm_smmu_master {
struct arm_smmu_device *smmu;
struct arm_smmu_domain *domain;
struct list_head domain_head;
u32 *sids;
unsigned int num_sids;
};
Expand All @@ -607,6 +608,9 @@ struct arm_smmu_domain {
};

struct iommu_domain domain;

struct list_head devices;
spinlock_t devices_lock;
};

struct arm_smmu_option_prop {
Expand Down Expand Up @@ -1504,6 +1508,9 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
}

mutex_init(&smmu_domain->init_mutex);
INIT_LIST_HEAD(&smmu_domain->devices);
spin_lock_init(&smmu_domain->devices_lock);

return &smmu_domain->domain;
}

Expand Down Expand Up @@ -1721,16 +1728,24 @@ static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master)

static void arm_smmu_detach_dev(struct arm_smmu_master *master)
{
if (!master->domain)
unsigned long flags;
struct arm_smmu_domain *smmu_domain = master->domain;

if (!smmu_domain)
return;

spin_lock_irqsave(&smmu_domain->devices_lock, flags);
list_del(&master->domain_head);
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);

master->domain = NULL;
arm_smmu_install_ste_for_dev(master);
}

static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
{
int ret = 0;
unsigned long flags;
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
struct arm_smmu_device *smmu;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
Expand Down Expand Up @@ -1764,6 +1779,10 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)

master->domain = smmu_domain;

spin_lock_irqsave(&smmu_domain->devices_lock, flags);
list_add(&master->domain_head, &smmu_domain->devices);
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);

if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1)
arm_smmu_write_ctx_desc(smmu, &smmu_domain->s1_cfg);

Expand Down

0 comments on commit 2a7e62f

Please sign in to comment.