diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index 24e3f0cdabbf444a44d8c4fe3ea6f966d6b28b1b..fd9ab92e9d1ffed35e578b47bc986f03697da4f0 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -78,6 +78,7 @@ static void free_iova_flush_queue(struct iova_domain *iovad) del_timer_sync(&iovad->fq_timer); + flush_work(&iovad->free_iova_work); fq_destroy_all_entries(iovad); free_percpu(iovad->fq); @@ -87,6 +88,24 @@ static void free_iova_flush_queue(struct iova_domain *iovad) iovad->entry_dtor = NULL; } +static void fq_ring_free(struct iova_domain *iovad, struct iova_fq *fq); +static void free_iova_work_func(struct work_struct *work) +{ + struct iova_domain *iovad; + int cpu; + + iovad = container_of(work, struct iova_domain, free_iova_work); + for_each_possible_cpu(cpu) { + unsigned long flags; + struct iova_fq *fq; + + fq = per_cpu_ptr(iovad->fq, cpu); + spin_lock_irqsave(&fq->lock, flags); + fq_ring_free(iovad, fq); + spin_unlock_irqrestore(&fq->lock, flags); + } +} + int init_iova_flush_queue(struct iova_domain *iovad, iova_flush_cb flush_cb, iova_entry_dtor entry_dtor) { @@ -117,6 +136,7 @@ int init_iova_flush_queue(struct iova_domain *iovad, iovad->fq = queue; + INIT_WORK(&iovad->free_iova_work, free_iova_work_func); timer_setup(&iovad->fq_timer, fq_flush_timeout, 0); atomic_set(&iovad->fq_timer_on, 0); @@ -541,20 +561,11 @@ static void fq_destroy_all_entries(struct iova_domain *iovad) static void fq_flush_timeout(struct timer_list *t) { struct iova_domain *iovad = from_timer(iovad, t, fq_timer); - int cpu; atomic_set(&iovad->fq_timer_on, 0); iova_domain_flush(iovad); - for_each_possible_cpu(cpu) { - unsigned long flags; - struct iova_fq *fq; - - fq = per_cpu_ptr(iovad->fq, cpu); - spin_lock_irqsave(&fq->lock, flags); - fq_ring_free(iovad, fq); - spin_unlock_irqrestore(&fq->lock, flags); - } + schedule_work(&iovad->free_iova_work); } void queue_iova(struct iova_domain *iovad, diff --git a/include/linux/iova.h b/include/linux/iova.h index 35c453085a4fd12b6205eff23de8d52c26e128c3..983872f0ddd6115327c03bfd1fa6e9915948e7ca 100644 --- a/include/linux/iova.h +++ b/include/linux/iova.h @@ -97,6 +97,7 @@ struct iova_domain { flush-queues */ atomic_t fq_timer_on; /* 1 when timer is active, 0 when not */ + struct work_struct free_iova_work; }; static inline unsigned long iova_size(struct iova *iova)