Skip to content

Commit

Permalink
iommu: Make IOVA domain low limit flexible
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Robin Murphy authored and Joerg Roedel committed Jan 19, 2015
1 parent 85b4545 commit 1b72250
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 11 deletions.
9 changes: 6 additions & 3 deletions drivers/iommu/intel-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down
10 changes: 6 additions & 4 deletions drivers/iommu/iova.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -162,7 +164,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
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;
}
Expand Down Expand Up @@ -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).
*/
Expand Down
7 changes: 3 additions & 4 deletions include/linux/iova.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
};

Expand All @@ -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,
Expand Down

0 comments on commit 1b72250

Please sign in to comment.