From: Xiang Chen chenxiang66@hisilicon.com
Currently even if rmmod the driver of the last device, the rcache iovas still occupies the memory and doesn't release them. Actually we can free them when rmmod the driver of the last device.
Signed-off-by: Xiang Chen chenxiang66@hisilicon.com --- drivers/iommu/dma-iommu.c | 7 +++++++ drivers/iommu/iommu.c | 7 +++++++ drivers/iommu/iova.c | 17 ++++++++++++----- include/linux/dma-iommu.h | 6 +++++- include/linux/iova.h | 5 +++++ 5 files changed, 36 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 7bcdd12..a1431a9 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -54,6 +54,13 @@ struct iommu_dma_cookie { static DEFINE_STATIC_KEY_FALSE(iommu_deferred_attach_enabled); bool iommu_dma_forcedac __read_mostly;
+struct iova_domain *iommu_domain_to_iova(struct iommu_domain *domain) +{ + struct iommu_dma_cookie *cookie = domain->iova_cookie; + + return &cookie->iovad; +} + static int __init iommu_dma_forcedac_setup(char *str) { int ret = kstrtobool(str, &iommu_dma_forcedac); diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 808ab70..9a7ced0 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -9,12 +9,14 @@ #include <linux/device.h> #include <linux/kernel.h> #include <linux/bug.h> +#include <linux/dma-iommu.h> #include <linux/types.h> #include <linux/init.h> #include <linux/export.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/iommu.h> +#include <linux/iova.h> #include <linux/idr.h> #include <linux/notifier.h> #include <linux/err.h> @@ -1667,6 +1669,11 @@ static int iommu_bus_notifier(struct notifier_block *nb, group_action = IOMMU_GROUP_NOTIFY_UNBIND_DRIVER; break; case BUS_NOTIFY_UNBOUND_DRIVER: + if (iommu_group_device_count(group) == 1) { + struct iommu_domain *domain = group->domain; + + free_rcache_cached_iovas(iommu_domain_to_iova(domain)); + } group_action = IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER; break; } diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index b7ecd5b..59926d5 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -503,16 +503,12 @@ alloc_iova_fast(struct iova_domain *iovad, unsigned long size, retry: new_iova = alloc_iova(iovad, size, limit_pfn, true); if (!new_iova) { - unsigned int cpu; - if (!flush_rcache) return 0;
/* Try replenishing IOVAs by flushing rcache. */ flush_rcache = false; - for_each_online_cpu(cpu) - free_cpu_cached_iovas(cpu, iovad); - free_global_cached_iovas(iovad); + free_rcache_cached_iovas(iovad); goto retry; }
@@ -1077,5 +1073,16 @@ static void free_global_cached_iovas(struct iova_domain *iovad) spin_unlock_irqrestore(&rcache->lock, flags); } } + +void free_rcache_cached_iovas(struct iova_domain *iovad) +{ + unsigned int cpu; + + for_each_online_cpu(cpu) + free_cpu_cached_iovas(cpu, iovad); + free_global_cached_iovas(iovad); +} +EXPORT_SYMBOL_GPL(free_rcache_cached_iovas); + MODULE_AUTHOR("Anil S Keshavamurthy anil.s.keshavamurthy@intel.com"); MODULE_LICENSE("GPL"); diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h index 6e75a2d..82c4ec8 100644 --- a/include/linux/dma-iommu.h +++ b/include/linux/dma-iommu.h @@ -41,7 +41,7 @@ void iommu_dma_free_cpu_cached_iovas(unsigned int cpu, struct iommu_domain *domain);
extern bool iommu_dma_forcedac; - +struct iova_domain *iommu_domain_to_iova(struct iommu_domain *domain); #else /* CONFIG_IOMMU_DMA */
struct iommu_domain; @@ -83,5 +83,9 @@ static inline void iommu_dma_get_resv_regions(struct device *dev, struct list_he { }
+struct iova_domain *iommu_domain_to_iova(struct iommu_domain *domain) +{ +} + #endif /* CONFIG_IOMMU_DMA */ #endif /* __DMA_IOMMU_H */ diff --git a/include/linux/iova.h b/include/linux/iova.h index 71d8a2d..7006d9f 100644 --- a/include/linux/iova.h +++ b/include/linux/iova.h @@ -157,6 +157,7 @@ int init_iova_flush_queue(struct iova_domain *iovad, iova_flush_cb flush_cb, iova_entry_dtor entry_dtor); struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn); void put_iova_domain(struct iova_domain *iovad); +void free_rcache_cached_iovas(struct iova_domain *iovad); #else static inline int iova_cache_get(void) { @@ -233,6 +234,10 @@ static inline void put_iova_domain(struct iova_domain *iovad) { }
+static inline void free_rcache_cached_iovas(struct iova_domain *iovad) +{ +} + #endif
#endif