Only dma-iommu.c uses the FQ, so it is wasteful and slightly disorganised
to hold all the FQ memories in the iova_domain structure.

So create a new structure, fq_domain, which is a new separate member in
iommu_dma_cookie for DMA IOVA type.

Signed-off-by: John Garry <john.ga...@huawei.com>
---
 drivers/iommu/dma-iommu.c | 37 ++++++++++-----
 drivers/iommu/iova.c      | 98 +++++++++++++++++++--------------------
 include/linux/iova.h      | 30 ++++++++----
 3 files changed, 94 insertions(+), 71 deletions(-)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index a99b3445fef8..279ee13bceb2 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -41,7 +41,10 @@ struct iommu_dma_cookie {
        enum iommu_dma_cookie_type      type;
        union {
                /* Full allocator for IOMMU_DMA_IOVA_COOKIE */
-               struct iova_domain      iovad;
+               struct {
+                       struct iova_domain      iovad;
+                       struct fq_domain        fq;
+               };
                /* Trivial linear page allocator for IOMMU_DMA_MSI_COOKIE */
                dma_addr_t              msi_iova;
        };
@@ -162,8 +165,10 @@ void iommu_put_dma_cookie(struct iommu_domain *domain)
        if (!cookie)
                return;
 
-       if (cookie->type == IOMMU_DMA_IOVA_COOKIE && cookie->iovad.granule)
+       if (cookie->type == IOMMU_DMA_IOVA_COOKIE && cookie->iovad.granule) {
+               iova_free_flush_queue(&cookie->fq);
                put_iova_domain(&cookie->iovad);
+       }
 
        list_for_each_entry_safe(msi, tmp, &cookie->msi_page_list, list) {
                list_del(&msi->list);
@@ -301,12 +306,12 @@ static int iova_reserve_iommu_regions(struct device *dev,
        return ret;
 }
 
-static void iommu_dma_flush_iotlb_all(struct iova_domain *iovad)
+static void iommu_dma_flush_iotlb_all(struct fq_domain *fq_domain)
 {
        struct iommu_dma_cookie *cookie;
        struct iommu_domain *domain;
 
-       cookie = container_of(iovad, struct iommu_dma_cookie, iovad);
+       cookie = container_of(fq_domain, struct iommu_dma_cookie, fq);
        domain = cookie->fq_domain;
 
        domain->ops->flush_iotlb_all(domain);
@@ -321,17 +326,21 @@ static bool dev_is_untrusted(struct device *dev)
 int iommu_dma_init_fq(struct iommu_domain *domain)
 {
        struct iommu_dma_cookie *cookie = domain->iova_cookie;
+       struct fq_domain *fq = &cookie->fq;
        int ret;
 
        if (cookie->fq_domain)
                return 0;
 
-       ret = init_iova_flush_queue(&cookie->iovad, iommu_dma_flush_iotlb_all,
+       ret = init_iova_flush_queue(fq, iommu_dma_flush_iotlb_all,
                                    iommu_dma_entry_dtor);
        if (ret) {
                pr_warn("iova flush queue initialization failed\n");
                return ret;
        }
+
+       fq->iovad = &cookie->iovad;
+
        /*
         * Prevent incomplete iovad->fq being observable. Pairs with path from
         * __iommu_dma_unmap() through iommu_dma_free_iova() to queue_iova()
@@ -359,11 +368,13 @@ static int iommu_dma_init_domain(struct iommu_domain 
*domain, dma_addr_t base,
        struct iommu_dma_cookie *cookie = domain->iova_cookie;
        unsigned long order, base_pfn;
        struct iova_domain *iovad;
+       struct fq_domain *fq;
 
        if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE)
                return -EINVAL;
 
        iovad = &cookie->iovad;
+       fq = &cookie->fq;
 
        /* Use the smallest supported page size for IOVA granularity */
        order = __ffs(domain->pgsize_bitmap);
@@ -392,6 +403,9 @@ static int iommu_dma_init_domain(struct iommu_domain 
*domain, dma_addr_t base,
                return 0;
        }
 
+       fq->flush_cb = NULL;
+       fq->fq = NULL;
+
        init_iova_domain(iovad, 1UL << order, base_pfn);
 
        /* If the FQ fails we can simply fall back to strict mode */
@@ -468,15 +482,16 @@ static void iommu_dma_free_iova(struct iommu_dma_cookie 
*cookie,
        struct iova_domain *iovad = &cookie->iovad;
 
        /* The MSI case is only ever cleaning up its most recent allocation */
-       if (cookie->type == IOMMU_DMA_MSI_COOKIE)
+       if (cookie->type == IOMMU_DMA_MSI_COOKIE) {
                cookie->msi_iova -= size;
-       else if (gather && gather->queued)
-               queue_iova(iovad, iova_pfn(iovad, iova),
-                               size >> iova_shift(iovad),
-                               (unsigned long)gather->freelist);
-       else
+       } else if (gather && gather->queued) {
+               queue_iova(&cookie->fq, iova_pfn(iovad, iova),
+                          size >> iova_shift(iovad),
+                          (unsigned long)gather->freelist);
+       } else {
                free_iova_fast(iovad, iova_pfn(iovad, iova),
                                size >> iova_shift(iovad));
+       }
 }
 
 static void __iommu_dma_unmap(struct device *dev, dma_addr_t dma_addr,
diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index ff567cbc42f7..262a08eb547f 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -24,7 +24,7 @@ static unsigned long iova_rcache_get(struct iova_domain 
*iovad,
 static void init_iova_rcaches(struct iova_domain *iovad);
 static void free_cpu_cached_iovas(unsigned int cpu, struct iova_domain *iovad);
 static void free_iova_rcaches(struct iova_domain *iovad);
-static void fq_destroy_all_entries(struct iova_domain *iovad);
+static void fq_destroy_all_entries(struct fq_domain *fq_domain);
 static void fq_flush_timeout(struct timer_list *t);
 
 static int iova_cpuhp_dead(unsigned int cpu, struct hlist_node *node)
@@ -63,8 +63,6 @@ init_iova_domain(struct iova_domain *iovad, unsigned long 
granule,
        iovad->start_pfn = start_pfn;
        iovad->dma_32bit_pfn = 1UL << (32 - iova_shift(iovad));
        iovad->max32_alloc_size = iovad->dma_32bit_pfn;
-       iovad->flush_cb = NULL;
-       iovad->fq = NULL;
        iovad->anchor.pfn_lo = iovad->anchor.pfn_hi = IOVA_ANCHOR;
        rb_link_node(&iovad->anchor.node, NULL, &iovad->rbroot.rb_node);
        rb_insert_color(&iovad->anchor.node, &iovad->rbroot);
@@ -73,43 +71,44 @@ init_iova_domain(struct iova_domain *iovad, unsigned long 
granule,
 }
 EXPORT_SYMBOL_GPL(init_iova_domain);
 
-static bool has_iova_flush_queue(struct iova_domain *iovad)
+static bool has_iova_flush_queue(struct fq_domain *fq_domain)
 {
-       return !!iovad->fq;
+       return !!fq_domain->fq;
 }
 
-static void free_iova_flush_queue(struct iova_domain *iovad)
+void iova_free_flush_queue(struct fq_domain *fq_domain)
 {
-       if (!has_iova_flush_queue(iovad))
+       if (!has_iova_flush_queue(fq_domain))
                return;
 
-       if (timer_pending(&iovad->fq_timer))
-               del_timer(&iovad->fq_timer);
+       if (timer_pending(&fq_domain->fq_timer))
+               del_timer(&fq_domain->fq_timer);
 
-       fq_destroy_all_entries(iovad);
+       fq_destroy_all_entries(fq_domain);
 
-       free_percpu(iovad->fq);
+       free_percpu(fq_domain->fq);
 
-       iovad->fq         = NULL;
-       iovad->flush_cb   = NULL;
-       iovad->entry_dtor = NULL;
+       fq_domain->fq         = NULL;
+       fq_domain->flush_cb   = NULL;
+       fq_domain->entry_dtor = NULL;
+       fq_domain->iovad      = NULL;
 }
 
-int init_iova_flush_queue(struct iova_domain *iovad,
+int init_iova_flush_queue(struct fq_domain *fq_domain,
                          iova_flush_cb flush_cb, iova_entry_dtor entry_dtor)
 {
        struct iova_fq __percpu *queue;
        int cpu;
 
-       atomic64_set(&iovad->fq_flush_start_cnt,  0);
-       atomic64_set(&iovad->fq_flush_finish_cnt, 0);
+       atomic64_set(&fq_domain->fq_flush_start_cnt,  0);
+       atomic64_set(&fq_domain->fq_flush_finish_cnt, 0);
 
        queue = alloc_percpu(struct iova_fq);
        if (!queue)
                return -ENOMEM;
 
-       iovad->flush_cb   = flush_cb;
-       iovad->entry_dtor = entry_dtor;
+       fq_domain->flush_cb   = flush_cb;
+       fq_domain->entry_dtor = entry_dtor;
 
        for_each_possible_cpu(cpu) {
                struct iova_fq *fq;
@@ -121,10 +120,10 @@ int init_iova_flush_queue(struct iova_domain *iovad,
                spin_lock_init(&fq->lock);
        }
 
-       iovad->fq = queue;
+       fq_domain->fq = queue;
 
-       timer_setup(&iovad->fq_timer, fq_flush_timeout, 0);
-       atomic_set(&iovad->fq_timer_on, 0);
+       timer_setup(&fq_domain->fq_timer, fq_flush_timeout, 0);
+       atomic_set(&fq_domain->fq_timer_on, 0);
 
        return 0;
 }
@@ -568,9 +567,9 @@ static inline unsigned fq_ring_add(struct iova_fq *fq)
        return idx;
 }
 
-static void fq_ring_free(struct iova_domain *iovad, struct iova_fq *fq)
+static void fq_ring_free(struct fq_domain *fq_domain, struct iova_fq *fq)
 {
-       u64 counter = atomic64_read(&iovad->fq_flush_finish_cnt);
+       u64 counter = atomic64_read(&fq_domain->fq_flush_finish_cnt);
        unsigned idx;
 
        assert_spin_locked(&fq->lock);
@@ -580,10 +579,10 @@ static void fq_ring_free(struct iova_domain *iovad, 
struct iova_fq *fq)
                if (fq->entries[idx].counter >= counter)
                        break;
 
-               if (iovad->entry_dtor)
-                       iovad->entry_dtor(fq->entries[idx].data);
+               if (fq_domain->entry_dtor)
+                       fq_domain->entry_dtor(fq->entries[idx].data);
 
-               free_iova_fast(iovad,
+               free_iova_fast(fq_domain->iovad,
                               fq->entries[idx].iova_pfn,
                               fq->entries[idx].pages);
 
@@ -591,14 +590,14 @@ static void fq_ring_free(struct iova_domain *iovad, 
struct iova_fq *fq)
        }
 }
 
-static void iova_domain_flush(struct iova_domain *iovad)
+static void iova_domain_flush(struct fq_domain *fq_domain)
 {
-       atomic64_inc(&iovad->fq_flush_start_cnt);
-       iovad->flush_cb(iovad);
-       atomic64_inc(&iovad->fq_flush_finish_cnt);
+       atomic64_inc(&fq_domain->fq_flush_start_cnt);
+       fq_domain->flush_cb(fq_domain);
+       atomic64_inc(&fq_domain->fq_flush_finish_cnt);
 }
 
-static void fq_destroy_all_entries(struct iova_domain *iovad)
+static void fq_destroy_all_entries(struct fq_domain *fq_domain)
 {
        int cpu;
 
@@ -607,38 +606,38 @@ static void fq_destroy_all_entries(struct iova_domain 
*iovad)
         * bother to free iovas, just call the entry_dtor on all remaining
         * entries.
         */
-       if (!iovad->entry_dtor)
+       if (!fq_domain->entry_dtor)
                return;
 
        for_each_possible_cpu(cpu) {
-               struct iova_fq *fq = per_cpu_ptr(iovad->fq, cpu);
+               struct iova_fq *fq = per_cpu_ptr(fq_domain->fq, cpu);
                int idx;
 
                fq_ring_for_each(idx, fq)
-                       iovad->entry_dtor(fq->entries[idx].data);
+                       fq_domain->entry_dtor(fq->entries[idx].data);
        }
 }
 
 static void fq_flush_timeout(struct timer_list *t)
 {
-       struct iova_domain *iovad = from_timer(iovad, t, fq_timer);
+       struct fq_domain *fq_domain = from_timer(fq_domain, t, fq_timer);
        int cpu;
 
-       atomic_set(&iovad->fq_timer_on, 0);
-       iova_domain_flush(iovad);
+       atomic_set(&fq_domain->fq_timer_on, 0);
+       iova_domain_flush(fq_domain);
 
        for_each_possible_cpu(cpu) {
                unsigned long flags;
                struct iova_fq *fq;
 
-               fq = per_cpu_ptr(iovad->fq, cpu);
+               fq = per_cpu_ptr(fq_domain->fq, cpu);
                spin_lock_irqsave(&fq->lock, flags);
-               fq_ring_free(iovad, fq);
+               fq_ring_free(fq_domain, fq);
                spin_unlock_irqrestore(&fq->lock, flags);
        }
 }
 
-void queue_iova(struct iova_domain *iovad,
+void queue_iova(struct fq_domain *fq_domain,
                unsigned long pfn, unsigned long pages,
                unsigned long data)
 {
@@ -655,7 +654,7 @@ void queue_iova(struct iova_domain *iovad,
         */
        smp_mb();
 
-       fq = raw_cpu_ptr(iovad->fq);
+       fq = raw_cpu_ptr(fq_domain->fq);
        spin_lock_irqsave(&fq->lock, flags);
 
        /*
@@ -663,11 +662,11 @@ void queue_iova(struct iova_domain *iovad,
         * flushed out on another CPU. This makes the fq_full() check below less
         * likely to be true.
         */
-       fq_ring_free(iovad, fq);
+       fq_ring_free(fq_domain, fq);
 
        if (fq_full(fq)) {
-               iova_domain_flush(iovad);
-               fq_ring_free(iovad, fq);
+               iova_domain_flush(fq_domain);
+               fq_ring_free(fq_domain, fq);
        }
 
        idx = fq_ring_add(fq);
@@ -675,14 +674,14 @@ void queue_iova(struct iova_domain *iovad,
        fq->entries[idx].iova_pfn = pfn;
        fq->entries[idx].pages    = pages;
        fq->entries[idx].data     = data;
-       fq->entries[idx].counter  = atomic64_read(&iovad->fq_flush_start_cnt);
+       fq->entries[idx].counter  = 
atomic64_read(&fq_domain->fq_flush_start_cnt);
 
        spin_unlock_irqrestore(&fq->lock, flags);
 
        /* Avoid false sharing as much as possible. */
-       if (!atomic_read(&iovad->fq_timer_on) &&
-           !atomic_xchg(&iovad->fq_timer_on, 1))
-               mod_timer(&iovad->fq_timer,
+       if (!atomic_read(&fq_domain->fq_timer_on) &&
+           !atomic_xchg(&fq_domain->fq_timer_on, 1))
+               mod_timer(&fq_domain->fq_timer,
                          jiffies + msecs_to_jiffies(IOVA_FQ_TIMEOUT));
 }
 
@@ -698,7 +697,6 @@ void put_iova_domain(struct iova_domain *iovad)
        cpuhp_state_remove_instance_nocalls(CPUHP_IOMMU_IOVA_DEAD,
                                            &iovad->cpuhp_dead);
 
-       free_iova_flush_queue(iovad);
        free_iova_rcaches(iovad);
        rbtree_postorder_for_each_entry_safe(iova, tmp, &iovad->rbroot, node)
                free_iova_mem(iova);
diff --git a/include/linux/iova.h b/include/linux/iova.h
index 71d8a2de6635..4975b65ab810 100644
--- a/include/linux/iova.h
+++ b/include/linux/iova.h
@@ -36,12 +36,13 @@ struct iova_rcache {
 };
 
 struct iova_domain;
+struct fq_domain;
 
 /* Call-Back from IOVA code into IOMMU drivers */
-typedef void (* iova_flush_cb)(struct iova_domain *domain);
+typedef void (*iova_flush_cb)(struct fq_domain *fq_domain);
 
 /* Destructor for per-entry data */
-typedef void (* iova_entry_dtor)(unsigned long data);
+typedef void (*iova_entry_dtor)(unsigned long data);
 
 /* Number of entries per Flush Queue */
 #define IOVA_FQ_SIZE   256
@@ -74,6 +75,12 @@ struct iova_domain {
        unsigned long   start_pfn;      /* Lower limit for this domain */
        unsigned long   dma_32bit_pfn;
        unsigned long   max32_alloc_size; /* Size of last failed allocation */
+       struct iova     anchor;         /* rbtree lookup anchor */
+       struct iova_rcache rcaches[IOVA_RANGE_CACHE_MAX_SIZE];  /* IOVA range 
caches */
+       struct hlist_node       cpuhp_dead;
+};
+
+struct fq_domain {
        struct iova_fq __percpu *fq;    /* Flush Queue */
 
        atomic64_t      fq_flush_start_cnt;     /* Number of TLB flushes that
@@ -82,9 +89,6 @@ struct iova_domain {
        atomic64_t      fq_flush_finish_cnt;    /* Number of TLB flushes that
                                                   have been finished */
 
-       struct iova     anchor;         /* rbtree lookup anchor */
-       struct iova_rcache rcaches[IOVA_RANGE_CACHE_MAX_SIZE];  /* IOVA range 
caches */
-
        iova_flush_cb   flush_cb;       /* Call-Back function to flush IOMMU
                                           TLBs */
 
@@ -95,7 +99,7 @@ struct iova_domain {
                                                   flush-queues */
        atomic_t fq_timer_on;                   /* 1 when timer is active, 0
                                                   when not */
-       struct hlist_node       cpuhp_dead;
+       struct iova_domain *iovad;
 };
 
 static inline unsigned long iova_size(struct iova *iova)
@@ -144,7 +148,7 @@ struct iova *alloc_iova(struct iova_domain *iovad, unsigned 
long size,
        bool size_aligned);
 void free_iova_fast(struct iova_domain *iovad, unsigned long pfn,
                    unsigned long size);
-void queue_iova(struct iova_domain *iovad,
+void queue_iova(struct fq_domain *fq_domain,
                unsigned long pfn, unsigned long pages,
                unsigned long data);
 unsigned long alloc_iova_fast(struct iova_domain *iovad, unsigned long size,
@@ -153,8 +157,10 @@ struct iova *reserve_iova(struct iova_domain *iovad, 
unsigned long pfn_lo,
        unsigned long pfn_hi);
 void init_iova_domain(struct iova_domain *iovad, unsigned long granule,
        unsigned long start_pfn);
-int init_iova_flush_queue(struct iova_domain *iovad,
+int init_iova_flush_queue(struct fq_domain *fq_domain,
                          iova_flush_cb flush_cb, iova_entry_dtor entry_dtor);
+void iova_free_flush_queue(struct fq_domain *fq_domain);
+
 struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
 void put_iova_domain(struct iova_domain *iovad);
 #else
@@ -189,7 +195,7 @@ static inline void free_iova_fast(struct iova_domain *iovad,
 {
 }
 
-static inline void queue_iova(struct iova_domain *iovad,
+static inline void queue_iova(struct fq_domain *fq_domain,
                              unsigned long pfn, unsigned long pages,
                              unsigned long data)
 {
@@ -216,13 +222,17 @@ static inline void init_iova_domain(struct iova_domain 
*iovad,
 {
 }
 
-static inline int init_iova_flush_queue(struct iova_domain *iovad,
+static inline int init_iova_flush_queue(struct fq_domain *fq_domain,
                                        iova_flush_cb flush_cb,
                                        iova_entry_dtor entry_dtor)
 {
        return -ENODEV;
 }
 
+static inline void iova_free_flush_queue(struct fq_domain *fq_domain)
+{
+}
+
 static inline struct iova *find_iova(struct iova_domain *iovad,
                                     unsigned long pfn)
 {
-- 
2.26.2

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to