Loading MAINTAINERS +2 −0 Original line number Diff line number Diff line Loading @@ -6764,6 +6764,8 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git S: Maintained F: Documentation/devicetree/bindings/iommu/ F: drivers/iommu/ F: include/linux/iommu.h F: include/linux/iova.h IP MASQUERADING M: Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar> Loading drivers/iommu/iova.c +33 −54 Original line number Diff line number Diff line Loading @@ -100,6 +100,34 @@ __cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free) } } /* Insert the iova into domain rbtree by holding writer lock */ static void iova_insert_rbtree(struct rb_root *root, struct iova *iova, struct rb_node *start) { struct rb_node **new, *parent = NULL; new = (start) ? &start : &(root->rb_node); /* Figure out where to put new node */ while (*new) { struct iova *this = rb_entry(*new, struct iova, node); parent = *new; if (iova->pfn_lo < this->pfn_lo) new = &((*new)->rb_left); else if (iova->pfn_lo > this->pfn_lo) new = &((*new)->rb_right); else { WARN_ON(1); /* this should not happen */ return; } } /* Add new node and rebalance tree. */ rb_link_node(&iova->node, parent, new); rb_insert_color(&iova->node, root); } /* * Computes the padding size required, to make the start address * naturally aligned on the power-of-two order of its size Loading Loading @@ -157,35 +185,8 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, new->pfn_lo = limit_pfn - (size + pad_size) + 1; new->pfn_hi = new->pfn_lo + size - 1; /* Insert the new_iova into domain rbtree by holding writer lock */ /* Add new node and rebalance tree. */ { struct rb_node **entry, *parent = NULL; /* If we have 'prev', it's a valid place to start the insertion. Otherwise, start from the root. */ if (prev) entry = &prev; else entry = &iovad->rbroot.rb_node; /* Figure out where to put new node */ while (*entry) { struct iova *this = rb_entry(*entry, struct iova, node); parent = *entry; if (new->pfn_lo < this->pfn_lo) entry = &((*entry)->rb_left); else if (new->pfn_lo > this->pfn_lo) entry = &((*entry)->rb_right); else BUG(); /* this should not happen */ } /* Add new node and rebalance tree. */ rb_link_node(&new->node, parent, entry); rb_insert_color(&new->node, &iovad->rbroot); } /* If we have 'prev', it's a valid place to start the insertion. */ iova_insert_rbtree(&iovad->rbroot, new, prev); __cached_rbnode_insert_update(iovad, saved_pfn, new); spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); Loading @@ -194,28 +195,6 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, return 0; } static void iova_insert_rbtree(struct rb_root *root, struct iova *iova) { struct rb_node **new = &(root->rb_node), *parent = NULL; /* Figure out where to put new node */ while (*new) { struct iova *this = rb_entry(*new, struct iova, node); parent = *new; if (iova->pfn_lo < this->pfn_lo) new = &((*new)->rb_left); else if (iova->pfn_lo > this->pfn_lo) new = &((*new)->rb_right); else BUG(); /* this should not happen */ } /* Add new node and rebalance tree. */ rb_link_node(&iova->node, parent, new); rb_insert_color(&iova->node, root); } static struct kmem_cache *iova_cache; static unsigned int iova_cache_users; static DEFINE_MUTEX(iova_cache_mutex); Loading Loading @@ -505,7 +484,7 @@ __insert_new_range(struct iova_domain *iovad, iova = alloc_and_init_iova(pfn_lo, pfn_hi); if (iova) iova_insert_rbtree(&iovad->rbroot, iova); iova_insert_rbtree(&iovad->rbroot, iova, NULL); return iova; } Loading Loading @@ -612,11 +591,11 @@ split_and_remove_iova(struct iova_domain *iovad, struct iova *iova, rb_erase(&iova->node, &iovad->rbroot); if (prev) { iova_insert_rbtree(&iovad->rbroot, prev); iova_insert_rbtree(&iovad->rbroot, prev, NULL); iova->pfn_lo = pfn_lo; } if (next) { iova_insert_rbtree(&iovad->rbroot, next); iova_insert_rbtree(&iovad->rbroot, next, NULL); iova->pfn_hi = pfn_hi; } spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); Loading include/linux/iova.h +91 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ static inline unsigned long iova_pfn(struct iova_domain *iovad, dma_addr_t iova) return iova >> iova_shift(iovad); } #if IS_ENABLED(CONFIG_IOMMU_IOVA) int iova_cache_get(void); void iova_cache_put(void); Loading @@ -106,5 +107,95 @@ void put_iova_domain(struct iova_domain *iovad); struct iova *split_and_remove_iova(struct iova_domain *iovad, struct iova *iova, unsigned long pfn_lo, unsigned long pfn_hi); void free_cpu_cached_iovas(unsigned int cpu, struct iova_domain *iovad); #else static inline int iova_cache_get(void) { return -ENOTSUPP; } static inline void iova_cache_put(void) { } static inline struct iova *alloc_iova_mem(void) { return NULL; } static inline void free_iova_mem(struct iova *iova) { } static inline void free_iova(struct iova_domain *iovad, unsigned long pfn) { } static inline void __free_iova(struct iova_domain *iovad, struct iova *iova) { } static inline struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size, unsigned long limit_pfn, bool size_aligned) { return NULL; } static inline void free_iova_fast(struct iova_domain *iovad, unsigned long pfn, unsigned long size) { } static inline unsigned long alloc_iova_fast(struct iova_domain *iovad, unsigned long size, unsigned long limit_pfn) { return 0; } static inline struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo, unsigned long pfn_hi) { return NULL; } static inline void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to) { } static inline void init_iova_domain(struct iova_domain *iovad, unsigned long granule, unsigned long start_pfn, unsigned long pfn_32bit) { } static inline struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn) { return NULL; } static inline void put_iova_domain(struct iova_domain *iovad) { } static inline struct iova *split_and_remove_iova(struct iova_domain *iovad, struct iova *iova, unsigned long pfn_lo, unsigned long pfn_hi) { return NULL; } static inline void free_cpu_cached_iovas(unsigned int cpu, struct iova_domain *iovad) { } #endif #endif Loading
MAINTAINERS +2 −0 Original line number Diff line number Diff line Loading @@ -6764,6 +6764,8 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git S: Maintained F: Documentation/devicetree/bindings/iommu/ F: drivers/iommu/ F: include/linux/iommu.h F: include/linux/iova.h IP MASQUERADING M: Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar> Loading
drivers/iommu/iova.c +33 −54 Original line number Diff line number Diff line Loading @@ -100,6 +100,34 @@ __cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free) } } /* Insert the iova into domain rbtree by holding writer lock */ static void iova_insert_rbtree(struct rb_root *root, struct iova *iova, struct rb_node *start) { struct rb_node **new, *parent = NULL; new = (start) ? &start : &(root->rb_node); /* Figure out where to put new node */ while (*new) { struct iova *this = rb_entry(*new, struct iova, node); parent = *new; if (iova->pfn_lo < this->pfn_lo) new = &((*new)->rb_left); else if (iova->pfn_lo > this->pfn_lo) new = &((*new)->rb_right); else { WARN_ON(1); /* this should not happen */ return; } } /* Add new node and rebalance tree. */ rb_link_node(&iova->node, parent, new); rb_insert_color(&iova->node, root); } /* * Computes the padding size required, to make the start address * naturally aligned on the power-of-two order of its size Loading Loading @@ -157,35 +185,8 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, new->pfn_lo = limit_pfn - (size + pad_size) + 1; new->pfn_hi = new->pfn_lo + size - 1; /* Insert the new_iova into domain rbtree by holding writer lock */ /* Add new node and rebalance tree. */ { struct rb_node **entry, *parent = NULL; /* If we have 'prev', it's a valid place to start the insertion. Otherwise, start from the root. */ if (prev) entry = &prev; else entry = &iovad->rbroot.rb_node; /* Figure out where to put new node */ while (*entry) { struct iova *this = rb_entry(*entry, struct iova, node); parent = *entry; if (new->pfn_lo < this->pfn_lo) entry = &((*entry)->rb_left); else if (new->pfn_lo > this->pfn_lo) entry = &((*entry)->rb_right); else BUG(); /* this should not happen */ } /* Add new node and rebalance tree. */ rb_link_node(&new->node, parent, entry); rb_insert_color(&new->node, &iovad->rbroot); } /* If we have 'prev', it's a valid place to start the insertion. */ iova_insert_rbtree(&iovad->rbroot, new, prev); __cached_rbnode_insert_update(iovad, saved_pfn, new); spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); Loading @@ -194,28 +195,6 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, return 0; } static void iova_insert_rbtree(struct rb_root *root, struct iova *iova) { struct rb_node **new = &(root->rb_node), *parent = NULL; /* Figure out where to put new node */ while (*new) { struct iova *this = rb_entry(*new, struct iova, node); parent = *new; if (iova->pfn_lo < this->pfn_lo) new = &((*new)->rb_left); else if (iova->pfn_lo > this->pfn_lo) new = &((*new)->rb_right); else BUG(); /* this should not happen */ } /* Add new node and rebalance tree. */ rb_link_node(&iova->node, parent, new); rb_insert_color(&iova->node, root); } static struct kmem_cache *iova_cache; static unsigned int iova_cache_users; static DEFINE_MUTEX(iova_cache_mutex); Loading Loading @@ -505,7 +484,7 @@ __insert_new_range(struct iova_domain *iovad, iova = alloc_and_init_iova(pfn_lo, pfn_hi); if (iova) iova_insert_rbtree(&iovad->rbroot, iova); iova_insert_rbtree(&iovad->rbroot, iova, NULL); return iova; } Loading Loading @@ -612,11 +591,11 @@ split_and_remove_iova(struct iova_domain *iovad, struct iova *iova, rb_erase(&iova->node, &iovad->rbroot); if (prev) { iova_insert_rbtree(&iovad->rbroot, prev); iova_insert_rbtree(&iovad->rbroot, prev, NULL); iova->pfn_lo = pfn_lo; } if (next) { iova_insert_rbtree(&iovad->rbroot, next); iova_insert_rbtree(&iovad->rbroot, next, NULL); iova->pfn_hi = pfn_hi; } spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); Loading
include/linux/iova.h +91 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ static inline unsigned long iova_pfn(struct iova_domain *iovad, dma_addr_t iova) return iova >> iova_shift(iovad); } #if IS_ENABLED(CONFIG_IOMMU_IOVA) int iova_cache_get(void); void iova_cache_put(void); Loading @@ -106,5 +107,95 @@ void put_iova_domain(struct iova_domain *iovad); struct iova *split_and_remove_iova(struct iova_domain *iovad, struct iova *iova, unsigned long pfn_lo, unsigned long pfn_hi); void free_cpu_cached_iovas(unsigned int cpu, struct iova_domain *iovad); #else static inline int iova_cache_get(void) { return -ENOTSUPP; } static inline void iova_cache_put(void) { } static inline struct iova *alloc_iova_mem(void) { return NULL; } static inline void free_iova_mem(struct iova *iova) { } static inline void free_iova(struct iova_domain *iovad, unsigned long pfn) { } static inline void __free_iova(struct iova_domain *iovad, struct iova *iova) { } static inline struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size, unsigned long limit_pfn, bool size_aligned) { return NULL; } static inline void free_iova_fast(struct iova_domain *iovad, unsigned long pfn, unsigned long size) { } static inline unsigned long alloc_iova_fast(struct iova_domain *iovad, unsigned long size, unsigned long limit_pfn) { return 0; } static inline struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo, unsigned long pfn_hi) { return NULL; } static inline void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to) { } static inline void init_iova_domain(struct iova_domain *iovad, unsigned long granule, unsigned long start_pfn, unsigned long pfn_32bit) { } static inline struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn) { return NULL; } static inline void put_iova_domain(struct iova_domain *iovad) { } static inline struct iova *split_and_remove_iova(struct iova_domain *iovad, struct iova *iova, unsigned long pfn_lo, unsigned long pfn_hi) { return NULL; } static inline void free_cpu_cached_iovas(unsigned int cpu, struct iova_domain *iovad) { } #endif #endif