diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 037fcf826407f4868517ab8841e47e816652a762..58a90521630e8ed75124551c4c4b9bc056a8f222 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -85,6 +85,8 @@ struct iommu_dma_cookie { /* Options for dma-iommu use */ struct iommu_dma_options options; struct mutex mutex; + + struct work_struct free_iova_work; }; static DEFINE_STATIC_KEY_FALSE(iommu_deferred_attach_enabled); @@ -184,17 +186,11 @@ static void fq_flush_iotlb(struct iommu_dma_cookie *cookie) static void fq_flush_timeout(struct timer_list *t) { struct iommu_dma_cookie *cookie = from_timer(cookie, t, fq_timer); - int cpu; atomic_set(&cookie->fq_timer_on, 0); fq_flush_iotlb(cookie); - if (cookie->options.qt == IOMMU_DMA_OPTS_SINGLE_QUEUE) { - fq_ring_free(cookie, cookie->single_fq); - } else { - for_each_possible_cpu(cpu) - fq_ring_free(cookie, per_cpu_ptr(cookie->percpu_fq, cpu)); - } + schedule_work(&cookie->free_iova_work); } static void queue_iova(struct iommu_dma_cookie *cookie, @@ -279,6 +275,7 @@ static void iommu_dma_free_fq(struct iommu_dma_cookie *cookie) return; del_timer_sync(&cookie->fq_timer); + flush_work(&cookie->free_iova_work); if (cookie->options.qt == IOMMU_DMA_OPTS_SINGLE_QUEUE) iommu_dma_free_fq_single(cookie->single_fq); else @@ -330,6 +327,20 @@ static int iommu_dma_init_fq_percpu(struct iommu_dma_cookie *cookie) return 0; } +static void free_iova_work_func(struct work_struct *work) +{ + struct iommu_dma_cookie *cookie = container_of(work, struct iommu_dma_cookie, free_iova_work); + int cpu; + + if (cookie->options.qt == IOMMU_DMA_OPTS_SINGLE_QUEUE) { + fq_ring_free(cookie, cookie->single_fq); + } else { + for_each_possible_cpu(cpu) + fq_ring_free(cookie, per_cpu_ptr(cookie->percpu_fq, cpu)); + } + +} + /* sysfs updates are serialised by the mutex of the group owning @domain */ int iommu_dma_init_fq(struct iommu_domain *domain) { @@ -352,6 +363,7 @@ int iommu_dma_init_fq(struct iommu_domain *domain) return -ENOMEM; } + INIT_WORK(&cookie->free_iova_work, free_iova_work_func); timer_setup(&cookie->fq_timer, fq_flush_timeout, 0); atomic_set(&cookie->fq_timer_on, 0); /*