mirror of
https://github.com/torvalds/linux.git
synced 2024-10-31 01:01:52 +00:00
f8de50eb6b
This code implements a generic IOVA allocation and management. As per Dave's suggestion we are now allocating IO virtual address from Higher DMA limit address rather than lower end address and this eliminated the need to preserve the IO virtual address for multiple devices sharing the same domain virtual address. Also this code uses red black trees to store the allocated and reserved iova nodes. This showed a good performance improvements over previous linear linked list. [akpm@linux-foundation.org: remove inlines] [akpm@linux-foundation.org: coding style fixes] Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Cc: Andi Kleen <ak@suse.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Muli Ben-Yehuda <muli@il.ibm.com> Cc: "Siddha, Suresh B" <suresh.b.siddha@intel.com> Cc: Arjan van de Ven <arjan@infradead.org> Cc: Ashok Raj <ashok.raj@intel.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Christoph Lameter <clameter@sgi.com> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
63 lines
1.9 KiB
C
63 lines
1.9 KiB
C
/*
|
|
* Copyright (c) 2006, Intel Corporation.
|
|
*
|
|
* This file is released under the GPLv2.
|
|
*
|
|
* Copyright (C) 2006 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
|
|
*
|
|
*/
|
|
|
|
#ifndef _IOVA_H_
|
|
#define _IOVA_H_
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/rbtree.h>
|
|
#include <linux/dma-mapping.h>
|
|
|
|
/*
|
|
* We need a fixed PAGE_SIZE of 4K irrespective of
|
|
* arch PAGE_SIZE for IOMMU page tables.
|
|
*/
|
|
#define PAGE_SHIFT_4K (12)
|
|
#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
|
|
#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
|
|
#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
|
|
|
|
/* IO virtual address start page frame number */
|
|
#define IOVA_START_PFN (1)
|
|
|
|
#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K)
|
|
#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
|
|
#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
|
|
|
|
/* iova structure */
|
|
struct iova {
|
|
struct rb_node node;
|
|
unsigned long pfn_hi; /* IOMMU dish out addr hi */
|
|
unsigned long pfn_lo; /* IOMMU dish out addr lo */
|
|
};
|
|
|
|
/* holds all the iova translations for a domain */
|
|
struct iova_domain {
|
|
spinlock_t iova_alloc_lock;/* Lock to protect iova allocation */
|
|
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 */
|
|
};
|
|
|
|
struct iova *alloc_iova_mem(void);
|
|
void free_iova_mem(struct iova *iova);
|
|
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,
|
|
unsigned long limit_pfn);
|
|
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);
|
|
struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
|
|
void put_iova_domain(struct iova_domain *iovad);
|
|
|
|
#endif
|