| From 8eaee8d0fcde4bd505126f104b43545dea09b9f3 Mon Sep 17 00:00:00 2001 |
| From: Magnus Damm <damm+renesas@opensource.se> |
| Date: Mon, 16 Oct 2017 21:29:46 +0900 |
| Subject: [PATCH 0101/1795] iommu/ipmmu-vmsa: Enable multi context support |
| |
| Add support for up to 8 contexts. Each context is mapped to one |
| domain. One domain is assigned one or more slave devices. Contexts |
| are allocated dynamically and slave devices are grouped together |
| based on which IPMMU device they are connected to. This makes slave |
| devices tied to the same IPMMU device share the same IOVA space. |
| |
| Signed-off-by: Magnus Damm <damm+renesas@opensource.se> |
| Signed-off-by: Alex Williamson <alex.williamson@redhat.com> |
| (cherry picked from commit 5fd163416fb7b6592521c39f867d5ae6360e7924) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> |
| --- |
| drivers/iommu/ipmmu-vmsa.c | 30 ++++++++++++++++++++++-------- |
| 1 file changed, 22 insertions(+), 8 deletions(-) |
| |
| diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c |
| index 5db853b92d3b..c70efd80f740 100644 |
| --- a/drivers/iommu/ipmmu-vmsa.c |
| +++ b/drivers/iommu/ipmmu-vmsa.c |
| @@ -37,11 +37,12 @@ |
| |
| #include "io-pgtable.h" |
| |
| -#define IPMMU_CTX_MAX 1 |
| +#define IPMMU_CTX_MAX 8 |
| |
| struct ipmmu_features { |
| bool use_ns_alias_offset; |
| bool has_cache_leaf_nodes; |
| + unsigned int number_of_contexts; |
| }; |
| |
| struct ipmmu_vmsa_device { |
| @@ -51,6 +52,7 @@ struct ipmmu_vmsa_device { |
| struct ipmmu_vmsa_device *root; |
| const struct ipmmu_features *features; |
| unsigned int num_utlbs; |
| + unsigned int num_ctx; |
| spinlock_t lock; /* Protects ctx and domains[] */ |
| DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); |
| struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX]; |
| @@ -352,11 +354,12 @@ static int ipmmu_domain_allocate_context(struct ipmmu_vmsa_device *mmu, |
| |
| spin_lock_irqsave(&mmu->lock, flags); |
| |
| - ret = find_first_zero_bit(mmu->ctx, IPMMU_CTX_MAX); |
| - if (ret != IPMMU_CTX_MAX) { |
| + ret = find_first_zero_bit(mmu->ctx, mmu->num_ctx); |
| + if (ret != mmu->num_ctx) { |
| mmu->domains[ret] = domain; |
| set_bit(ret, mmu->ctx); |
| - } |
| + } else |
| + ret = -EBUSY; |
| |
| spin_unlock_irqrestore(&mmu->lock, flags); |
| |
| @@ -409,8 +412,8 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) |
| * Find an unused context. |
| */ |
| ret = ipmmu_domain_allocate_context(domain->mmu->root, domain); |
| - if (ret == IPMMU_CTX_MAX) |
| - return -EBUSY; |
| + if (ret < 0) |
| + return ret; |
| |
| domain->context_id = ret; |
| |
| @@ -539,7 +542,7 @@ static irqreturn_t ipmmu_irq(int irq, void *dev) |
| /* |
| * Check interrupts for all active contexts. |
| */ |
| - for (i = 0; i < IPMMU_CTX_MAX; i++) { |
| + for (i = 0; i < mmu->num_ctx; i++) { |
| if (!mmu->domains[i]) |
| continue; |
| if (ipmmu_domain_irq(mmu->domains[i]) == IRQ_HANDLED) |
| @@ -624,6 +627,13 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, |
| /* The domain hasn't been used yet, initialize it. */ |
| domain->mmu = mmu; |
| ret = ipmmu_domain_init_context(domain); |
| + if (ret < 0) { |
| + dev_err(dev, "Unable to initialize IPMMU context\n"); |
| + domain->mmu = NULL; |
| + } else { |
| + dev_info(dev, "Using IPMMU context %u\n", |
| + domain->context_id); |
| + } |
| } else if (domain->mmu != mmu) { |
| /* |
| * Something is wrong, we can't attach two devices using |
| @@ -853,13 +863,14 @@ static void ipmmu_device_reset(struct ipmmu_vmsa_device *mmu) |
| unsigned int i; |
| |
| /* Disable all contexts. */ |
| - for (i = 0; i < 4; ++i) |
| + for (i = 0; i < mmu->num_ctx; ++i) |
| ipmmu_write(mmu, i * IM_CTX_SIZE + IMCTR, 0); |
| } |
| |
| static const struct ipmmu_features ipmmu_features_default = { |
| .use_ns_alias_offset = true, |
| .has_cache_leaf_nodes = false, |
| + .number_of_contexts = 1, /* software only tested with one context */ |
| }; |
| |
| static const struct of_device_id ipmmu_of_ids[] = { |
| @@ -913,6 +924,9 @@ static int ipmmu_probe(struct platform_device *pdev) |
| if (mmu->features->use_ns_alias_offset) |
| mmu->base += IM_NS_ALIAS_OFFSET; |
| |
| + mmu->num_ctx = min_t(unsigned int, IPMMU_CTX_MAX, |
| + mmu->features->number_of_contexts); |
| + |
| irq = platform_get_irq(pdev, 0); |
| |
| /* |
| -- |
| 2.19.0 |
| |