iommu: Make IOVA domain low limit flexible
authorRobin Murphy <robin.murphy@arm.com>
Mon, 12 Jan 2015 17:51:15 +0000 (17:51 +0000)
committerJoerg Roedel <jroedel@suse.de>
Mon, 19 Jan 2015 13:55:22 +0000 (14:55 +0100)
To share the IOVA allocator with other architectures, it needs to
accommodate more general aperture restrictions; move the lower limit
from a compile-time constant to a runtime domain property to allow
IOVA domains with different requirements to co-exist.

Also reword the slightly unclear description of alloc_iova since we're
touching it anyway.

Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/intel-iommu.c
drivers/iommu/iova.c
include/linux/iova.h

index e758d8ed8fb5568930e002cd8e13476000b0b5ac..86f9e82b015b6041fa570250d5b68a2c9290b72c 100644 (file)
@@ -71,6 +71,9 @@
                                __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
 #define DOMAIN_MAX_ADDR(gaw)   (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
 
+/* IO virtual address start page frame number */
+#define IOVA_START_PFN         (1)
+
 #define IOVA_PFN(addr)         ((addr) >> PAGE_SHIFT)
 #define DMA_32BIT_PFN          IOVA_PFN(DMA_BIT_MASK(32))
 #define DMA_64BIT_PFN          IOVA_PFN(DMA_BIT_MASK(64))
@@ -1632,7 +1635,7 @@ static int dmar_init_reserved_ranges(void)
        struct iova *iova;
        int i;
 
-       init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
+       init_iova_domain(&reserved_iova_list, IOVA_START_PFN, DMA_32BIT_PFN);
 
        lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
                &reserved_rbtree_key);
@@ -1690,7 +1693,7 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
        int adjust_width, agaw;
        unsigned long sagaw;
 
-       init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
+       init_iova_domain(&domain->iovad, IOVA_START_PFN, DMA_32BIT_PFN);
        domain_reserve_special_ranges(domain);
 
        /* calculate AGAW */
@@ -4313,7 +4316,7 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)
 {
        int adjust_width;
 
-       init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
+       init_iova_domain(&domain->iovad, IOVA_START_PFN, DMA_32BIT_PFN);
        domain_reserve_special_ranges(domain);
 
        /* calculate AGAW */
index 520b8c8ae0c4df19e3fb28813e1d657b95c4c708..a3dbba8caa19f8a77d3031624b7d4f76a0674b7d 100644 (file)
@@ -55,11 +55,13 @@ void free_iova_mem(struct iova *iova)
 }
 
 void
-init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit)
+init_iova_domain(struct iova_domain *iovad, unsigned long start_pfn,
+       unsigned long pfn_32bit)
 {
        spin_lock_init(&iovad->iova_rbtree_lock);
        iovad->rbroot = RB_ROOT;
        iovad->cached32_node = NULL;
+       iovad->start_pfn = start_pfn;
        iovad->dma_32bit_pfn = pfn_32bit;
 }
 
@@ -162,7 +164,7 @@ move_left:
        if (!curr) {
                if (size_aligned)
                        pad_size = iova_get_pad_size(size, limit_pfn);
-               if ((IOVA_START_PFN + size + pad_size) > limit_pfn) {
+               if ((iovad->start_pfn + size + pad_size) > limit_pfn) {
                        spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
                        return -ENOMEM;
                }
@@ -237,8 +239,8 @@ iova_insert_rbtree(struct rb_root *root, struct iova *iova)
  * @size: - size of page frames to allocate
  * @limit_pfn: - max limit address
  * @size_aligned: - set if size_aligned address range is required
- * This function allocates an iova in the range limit_pfn to IOVA_START_PFN
- * looking from limit_pfn instead from IOVA_START_PFN. If the size_aligned
+ * This function allocates an iova in the range iovad->start_pfn to limit_pfn,
+ * searching top-down from limit_pfn to iovad->start_pfn. If the size_aligned
  * flag is set then the allocated address iova->pfn_lo will be naturally
  * aligned on roundup_power_of_two(size).
  */
index ad0507c61cc7cce36aa7b76fc860e063d9a753c9..591b19626b4653b4bd391e68bc969107b54ec0ab 100644 (file)
@@ -16,9 +16,6 @@
 #include <linux/rbtree.h>
 #include <linux/dma-mapping.h>
 
-/* IO virtual address start page frame number */
-#define IOVA_START_PFN         (1)
-
 /* iova structure */
 struct iova {
        struct rb_node  node;
@@ -31,6 +28,7 @@ struct iova_domain {
        spinlock_t      iova_rbtree_lock; /* Lock to protect update of rbtree */
        struct rb_root  rbroot;         /* iova domain rbtree root */
        struct rb_node  *cached32_node; /* Save last alloced node */
+       unsigned long   start_pfn;      /* Lower limit for this domain */
        unsigned long   dma_32bit_pfn;
 };
 
@@ -52,7 +50,8 @@ struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size,
 struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo,
        unsigned long pfn_hi);
 void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to);
-void init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit);
+void init_iova_domain(struct iova_domain *iovad, unsigned long start_pfn,
+       unsigned long pfn_32bit);
 struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
 void put_iova_domain(struct iova_domain *iovad);
 struct iova *split_and_remove_iova(struct iova_domain *iovad,