Skip to contentSkip to conversation

Separate the IOVA library from the intel-iommu driver

RFC In review Sakari Ailus 2 participants 6 messages Nov 21, 2014 – Dec 4, 2014 1 message not in the archive

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover Separate the IOVA library from the intel-iommu driver

Hi,

This set separates the IOVA library from the intel-iommu driver, and makes it usable for other implementations (such as DMA mapping) as well.

While I don't have a DMA mapping implementation to share at the moment, the patches might be useful for the others in the meantime and I wouldn't mind having them in upstream either.

Signature · 2 lines
Kind regards,
Sakari

A message that is not in the archive (sent off-list or not yet received): 1416568303-677-1-git-send-email-sakari.ailus-VuQAYsv1563Yd54FQh9/[email protected]

#2 lore raw

RFC 1/4 iommu: iova: Move iova cache management to the iova library

alloc_iova_mem() and free_iova_mem() are moved to iova.c and made static as well. printk(KERN_ERR, ...) is also replaced by pr_err().

This is done in order to separate intel-iommu from the iova library. As a result, the user of the IOVA library must use iova_cache_get() before using alloc_iova_mem() or free_iova_mem(), and correspondingly iova_cache_put() after using the IOVA library.

---
 drivers/iommu/intel-iommu.c | 34 +++-----------------------------
 drivers/iommu/iova.c        | 48 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/iova.h        |  4 ++--
 3 files changed, 53 insertions(+), 33 deletions(-)
drivers/iommu/intel-iommu.c +3 -31
index a27d6cb..e7673df 100644
@@ -490,7 +490,6 @@ __setup("intel_iommu=", intel_iommu_setup);
 
 static struct kmem_cache *iommu_domain_cache;
 static struct kmem_cache *iommu_devinfo_cache;
-static struct kmem_cache *iommu_iova_cache;
 
 static inline void *alloc_pgtable_page(int node)
 {
@@ -528,16 +527,6 @@ static inline void free_devinfo_mem(void *vaddr)
 	kmem_cache_free(iommu_devinfo_cache, vaddr);
 }
 
-struct iova *alloc_iova_mem(void)
-{
-	return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
-}
-
-void free_iova_mem(struct iova *iova)
-{
-	kmem_cache_free(iommu_iova_cache, iova);
-}
-
 static inline int domain_type_is_vm(struct dmar_domain *domain)
 {
 	return domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE;
@@ -3429,27 +3418,10 @@ static inline int iommu_devinfo_cache_init(void)
 	return ret;
 }
 
-static inline int iommu_iova_cache_init(void)
-{
-	int ret = 0;
-
-	iommu_iova_cache = kmem_cache_create("iommu_iova",
-					 sizeof(struct iova),
-					 0,
-					 SLAB_HWCACHE_ALIGN,
-					 NULL);
-	if (!iommu_iova_cache) {
-		printk(KERN_ERR "Couldn't create iova cache\n");
-		ret = -ENOMEM;
-	}
-
-	return ret;
-}
-
 static int __init iommu_init_mempool(void)
 {
 	int ret;
-	ret = iommu_iova_cache_init();
+	ret = iova_cache_get();
 	if (ret)
 		return ret;
 
@@ -3463,7 +3435,7 @@ static int __init iommu_init_mempool(void)
 
 	kmem_cache_destroy(iommu_domain_cache);
 domain_error:
-	kmem_cache_destroy(iommu_iova_cache);
+	iova_cache_put();
 
 	return -ENOMEM;
 }
@@ -3472,7 +3444,7 @@ static void __init iommu_exit_mempool(void)
 {
 	kmem_cache_destroy(iommu_devinfo_cache);
 	kmem_cache_destroy(iommu_domain_cache);
-	kmem_cache_destroy(iommu_iova_cache);
+	iova_cache_put();
 
 }
 
drivers/iommu/iova.c +48 -0

60 lines not on this page · raw message

include/linux/iova.h +2 -2
index 19e81d5..8572031 100644
@@ -39,8 +39,8 @@ static inline unsigned long iova_size(struct iova *iova)
 	return iova->pfn_hi - iova->pfn_lo + 1;
 }
 
-struct iova *alloc_iova_mem(void);
-void free_iova_mem(struct iova *iova);
+int iova_cache_get(void);
+void iova_cache_put(void);
 void free_iova(struct iova_domain *iovad, unsigned long pfn);
 void __free_iova(struct iova_domain *iovad, struct iova *iova);
 struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size,
Signature · 1 line
2.1.0.231.g7484e3b
#3 lore raw

RFC 2/4 iommu: iova: Export symbols

In reply to a message not in the archive

Use EXPORT_SYMBOL_GPL() to export the iova library symbols. The symbols include:

	init_iova_domain();
	iova_cache_get();
	iova_cache_put();
	alloc_iova();
	find_iova();
	__free_iova();
	free_iova();
	put_iova_domain();
	reserve_iova();

This is necessary in order to use the iova library from a kernel module.

---
 drivers/iommu/iova.c | 9 +++++++++
 1 file changed, 9 insertions(+)
drivers/iommu/iova.c +9 -0
index 6bc7022..e9e62f4 100644
@@ -28,6 +28,7 @@ init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit)
 	iovad->cached32_node = NULL;
 	iovad->dma_32bit_pfn = pfn_32bit;
 }
+EXPORT_SYMBOL_GPL(init_iova_domain);
 
 static struct rb_node *
 __get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn)
@@ -230,6 +231,7 @@ int iova_cache_get(void)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(iova_cache_get);
 
 void iova_cache_put(void)
 {
@@ -243,6 +245,7 @@ void iova_cache_put(void)
 		kmem_cache_destroy(iova_cache);
 	mutex_unlock(&iova_cache_mutex);
 }
+EXPORT_SYMBOL_GPL(iova_cache_put);
 
 /**
  * alloc_iova - allocates an iova
@@ -283,6 +286,7 @@ alloc_iova(struct iova_domain *iovad, unsigned long size,
 
 	return new_iova;
 }
+EXPORT_SYMBOL_GPL(alloc_iova);
 
 /**
  * find_iova - find's an iova for a given pfn
@@ -323,6 +327,7 @@ struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn)
 	spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(find_iova);
 
 /**
  * __free_iova - frees the given iova
@@ -341,6 +346,7 @@ __free_iova(struct iova_domain *iovad, struct iova *iova)
 	spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
 	free_iova_mem(iova);
 }
+EXPORT_SYMBOL_GPL(__free_iova);
 
 /**
  * free_iova - finds and frees the iova for a given pfn
@@ -357,6 +363,7 @@ free_iova(struct iova_domain *iovad, unsigned long pfn)
 		__free_iova(iovad, iova);
 
 }
+EXPORT_SYMBOL_GPL(free_iova);
 
 /**
  * put_iova_domain - destroys the iova doamin
@@ -378,6 +385,7 @@ void put_iova_domain(struct iova_domain *iovad)
 	}
 	spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
 }
+EXPORT_SYMBOL_GPL(put_iova_domain);
 
 static int
 __is_range_overlap(struct rb_node *node,
@@ -467,6 +475,7 @@ finish:
 	spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
 	return iova;
 }
+EXPORT_SYMBOL_GPL(reserve_iova);
 
 /**
  * copy_reserved_iova - copies the reserved between domains
Signature · 1 line
2.1.0.231.g7484e3b
#4 lore raw

RFC 3/4 iommu: iova: Make the iova library buildable as a module

In reply to a message not in the archive

The iova library is usable elsewhere than just the intel-iommu driver, thus make it also buildable a module.

---
 drivers/iommu/Kconfig  | 4 ++++
 drivers/iommu/Makefile | 3 ++-
 drivers/iommu/iova.c   | 4 ++++
 3 files changed, 10 insertions(+), 1 deletion(-)
drivers/iommu/Kconfig +4 -0
index dd51122..b139748 100644
@@ -87,11 +87,15 @@ config AMD_IOMMU_V2
 config DMAR_TABLE
 	bool
 
+config IOMMU_IOVA
+	tristate
+
 config INTEL_IOMMU
 	bool "Support for Intel IOMMU using DMA Remapping Devices"
 	depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC)
 	select IOMMU_API
 	select DMAR_TABLE
+	select IOMMU_IOVA
 	help
 	  DMA remapping (DMAR) devices support enables independent address
 	  translations for Direct Memory Access (DMA) from devices.
drivers/iommu/Makefile +2 -1
index 16edef7..66668a6 100644
@@ -7,7 +7,8 @@ obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
 obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
 obj-$(CONFIG_ARM_SMMU) += arm-smmu.o
 obj-$(CONFIG_DMAR_TABLE) += dmar.o
-obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
+obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o
+obj-$(CONFIG_IOMMU_IOVA) += iova.o
 obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o
 obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
 obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
drivers/iommu/iova.c +4 -0
index e9e62f4..c9142b2 100644
@@ -18,6 +18,7 @@
  */
 
 #include <linux/iova.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 
 void
@@ -542,3 +543,6 @@ error:
 		free_iova_mem(prev);
 	return NULL;
 }
+
+MODULE_AUTHOR("Anil S Keshavamurthy <[email protected]>");
+MODULE_LICENSE("GPL");
Signature · 1 line
2.1.0.231.g7484e3b
#5 lore raw

RFC 4/4 mm: EXPORT_SYMBOL_GPL({find_vm_area,get_vm_area_caller});

In reply to a message not in the archive

These APIs are needed in DMA mapping API implementation as a module. Device specific IOMMUs with associated DMA mapping implementations should be buildable as modules.

---
 mm/vmalloc.c | 2 ++
 1 file changed, 2 insertions(+)
mm/vmalloc.c +2 -0
index 90520af..f22c01c 100644
@@ -1379,6 +1379,7 @@ struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
 	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
 				  NUMA_NO_NODE, GFP_KERNEL, caller);
 }
+EXPORT_SYMBOL_GPL(get_vm_area_caller);
 
 /**
  *	find_vm_area  -  find a continuous kernel virtual area
@@ -1398,6 +1399,7 @@ struct vm_struct *find_vm_area(const void *addr)
 
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(find_vm_area);
 
 /**
  *	remove_vm_area  -  find and remove a continuous kernel virtual area
Signature · 1 line
2.1.0.231.g7484e3b
#6 lore raw
In reply to a message not in the archive
Quoted 8 lines · Sakari Ailus

Hi,

This set separates the IOVA library from the intel-iommu driver, and makes it usable for other implementations (such as DMA mapping) as well.

While I don't have a DMA mapping implementation to share at the moment, the patches might be useful for the others in the meantime and I wouldn't mind having them in upstream either.

the caveat that I don't actually want to see various IOMMU drivers *using* the IOVA code directly.

Where possible, we really want to be *losing* the separate DMA API implementation, which would do nothing but call this library and then use the underlying IOMMU API functions with the IOVAs that result. Let the whole of that wrapper be generic, rather than just abstracting out the IOVA allocator for everyone to use in their own wrapper.

Signature · 1 line
dwmw2