staticstruct rb_node *iova_find_limit(struct iova_domain *iovad, unsignedlong limit_pfn)
{ struct rb_node *node, *next; /* * Ideally what we'd like to judge here is whether limit_pfn is close * enough to the highest-allocated IOVA that starting the allocation * walk from the anchor node will be quicker than this initial work to * find an exact starting point (especially if that ends up being the * anchor node anyway). This is an incredibly crude approximation which * only really helps the most likely case, but is at least trivially easy.
*/ if (limit_pfn > iovad->dma_32bit_pfn) return &iovad->anchor.node;
node = iovad->rbroot.rb_node; while (to_iova(node)->pfn_hi < limit_pfn)
node = node->rb_right;
search_left: while (node->rb_left && to_iova(node->rb_left)->pfn_lo >= limit_pfn)
node = node->rb_left;
if (!node->rb_left) return node;
next = node->rb_left; while (next->rb_right) {
next = next->rb_right; if (to_iova(next)->pfn_lo >= limit_pfn) {
node = next; goto search_left;
}
}
return node;
}
/* Insert the iova into domain rbtree by holding writer lock */ staticvoid
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 = to_iova(*new);
parent = *new;
if (iova->pfn_lo < this->pfn_lo) new = &((*new)->rb_left); elseif (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);
}
if (size_aligned)
align_mask <<= fls_long(size - 1);
/* Walk the tree backwards */
spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); if (limit_pfn <= iovad->dma_32bit_pfn &&
size >= iovad->max32_alloc_size) goto iova32_full;
/* pfn_lo will point to size aligned address if size_aligned is set */
new->pfn_lo = new_pfn;
new->pfn_hi = new->pfn_lo + size - 1;
/* 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, new);
/** * alloc_iova - allocates an iova * @iovad: - iova domain in question * @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 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).
*/ struct iova *
alloc_iova(struct iova_domain *iovad, unsignedlong size, unsignedlong limit_pfn, bool size_aligned)
{ struct iova *new_iova; int ret;
new_iova = alloc_iova_mem(); if (!new_iova) return NULL;
ret = __alloc_and_insert_iova_range(iovad, size, limit_pfn + 1,
new_iova, size_aligned);
if (ret) {
free_iova_mem(new_iova); return NULL;
}
/** * find_iova - finds an iova for a given pfn * @iovad: - iova domain in question. * @pfn: - page frame number * This function finds and returns an iova belonging to the * given domain which matches the given pfn.
*/ struct iova *find_iova(struct iova_domain *iovad, unsignedlong pfn)
{ unsignedlong flags; struct iova *iova;
/* Take the lock so that no other thread is manipulating the rbtree */
spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
iova = private_find_iova(iovad, pfn);
spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); return iova;
}
EXPORT_SYMBOL_GPL(find_iova);
/** * __free_iova - frees the given iova * @iovad: iova domain in question. * @iova: iova in question. * Frees the given iova belonging to the giving domain
*/ void
__free_iova(struct iova_domain *iovad, struct iova *iova)
{ unsignedlong flags;
/** * free_iova - finds and frees the iova for a given pfn * @iovad: - iova domain in question. * @pfn: - pfn that is allocated previously * This functions finds an iova for a given pfn and then * frees the iova from that domain.
*/ void
free_iova(struct iova_domain *iovad, unsignedlong pfn)
{ unsignedlong flags; struct iova *iova;
/** * alloc_iova_fast - allocates an iova from rcache * @iovad: - iova domain in question * @size: - size of page frames to allocate * @limit_pfn: - max limit address * @flush_rcache: - set to flush rcache on regular allocation failure * This function tries to satisfy an iova allocation from the rcache, * and falls back to regular allocation on failure. If regular allocation * fails too and the flush_rcache flag is set then the rcache will be flushed.
*/ unsignedlong
alloc_iova_fast(struct iova_domain *iovad, unsignedlong size, unsignedlong limit_pfn, bool flush_rcache)
{ unsignedlong iova_pfn; struct iova *new_iova;
/* * Freeing non-power-of-two-sized allocations back into the IOVA caches * will come back to bite us badly, so we have to waste a bit of space * rounding up anything cacheable to make sure that can't happen. The * order of the unadjusted size will still match upon freeing.
*/ if (size < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1)))
size = roundup_pow_of_two(size);
/** * free_iova_fast - free iova pfn range into rcache * @iovad: - iova domain in question. * @pfn: - pfn that is allocated previously * @size: - # of pages in range * This functions frees an iova range by trying to put it into the rcache, * falling back to regular iova deallocation via free_iova() if this fails.
*/ void
free_iova_fast(struct iova_domain *iovad, unsignedlong pfn, unsignedlong size)
{ if (iova_rcache_insert(iovad, pfn, size)) return;
/** * put_iova_domain - destroys the iova domain * @iovad: - iova domain in question. * All the iova's in that domain are destroyed.
*/ void put_iova_domain(struct iova_domain *iovad)
{ struct iova *iova, *tmp;
if (iovad->rcaches)
iova_domain_free_rcaches(iovad);
/** * reserve_iova - reserves an iova in the given range * @iovad: - iova domain pointer * @pfn_lo: - lower page frame address * @pfn_hi:- higher pfn address * This function allocates reserves the address range from pfn_lo to pfn_hi so * that this address is not dished out as part of alloc_iova.
*/ struct iova *
reserve_iova(struct iova_domain *iovad, unsignedlong pfn_lo, unsignedlong pfn_hi)
{ struct rb_node *node; unsignedlong flags; struct iova *iova; unsignedint overlap = 0;
/* We are here either because this is the first reserver node * or need to insert remaining non overlap addr range
*/
iova = __insert_new_range(iovad, pfn_lo, pfn_hi);
finish:
/* * Magazine caches for IOVA ranges. For an introduction to magazines, * see the USENIX 2001 paper "Magazines and Vmem: Extending the Slab * Allocator to Many CPUs and Arbitrary Resources" by Bonwick and Adams. * For simplicity, we use a static magazine size and don't implement the * dynamic size tuning described in the paper.
*/
/* * As kmalloc's buffer size is fixed to power of 2, 127 is chosen to * assure size of 'iova_magazine' to be 1024 bytes, so that no memory * will be wasted. Since only full magazines are inserted into the depot, * we don't need to waste PFN capacity on a separate list head either.
*/ #define IOVA_MAG_SIZE 127
/* * As the mag->next pointer is moved to rcache->depot and reset via * the mag->size assignment, mark it as a transient false positive.
*/
kmemleak_transient_leak(mag->next);
rcache->depot = mag->next;
mag->size = IOVA_MAG_SIZE;
rcache->depot_size--; return mag;
}
/* * Try inserting IOVA range starting with 'iova_pfn' into 'rcache', and * return true on success. Can fail if rcache is full and we can't free * space, and free_iova() (our only caller) will then return the IOVA * range to the rbtree instead.
*/ staticbool __iova_rcache_insert(struct iova_domain *iovad, struct iova_rcache *rcache, unsignedlong iova_pfn)
{ struct iova_cpu_rcache *cpu_rcache; bool can_insert = false; unsignedlong flags;
/* * Caller wants to allocate a new IOVA range from 'rcache'. If we can * satisfy the request, return a matching non-NULL range and remove * it from the 'rcache'.
*/ staticunsignedlong __iova_rcache_get(struct iova_rcache *rcache, unsignedlong limit_pfn)
{ struct iova_cpu_rcache *cpu_rcache; unsignedlong iova_pfn = 0; bool has_pfn = false; unsignedlong flags;
if (has_pfn)
iova_pfn = iova_magazine_pop(cpu_rcache->loaded, limit_pfn);
spin_unlock_irqrestore(&cpu_rcache->lock, flags);
return iova_pfn;
}
/* * Try to satisfy IOVA allocation range from rcache. Fail if requested * size is too big or the DMA limit we are given isn't satisfied by the * top element in the magazine.
*/ staticunsignedlong iova_rcache_get(struct iova_domain *iovad, unsignedlong size, unsignedlong limit_pfn)
{ unsignedint log_size = order_base_2(size);
if (log_size >= IOVA_RANGE_CACHE_MAX_SIZE) return 0;
for (int i = 0; i < IOVA_RANGE_CACHE_MAX_SIZE; ++i) {
rcache = &iovad->rcaches[i]; if (!rcache->cpu_rcaches) break;
for_each_possible_cpu(cpu) {
cpu_rcache = per_cpu_ptr(rcache->cpu_rcaches, cpu);
iova_magazine_free(cpu_rcache->loaded);
iova_magazine_free(cpu_rcache->prev);
}
free_percpu(rcache->cpu_rcaches);
cancel_delayed_work_sync(&rcache->work); while (rcache->depot)
iova_magazine_free(iova_depot_pop(rcache));
}
kfree(iovad->rcaches);
iovad->rcaches = NULL;
}
/* * free all the IOVA ranges cached by a cpu (used when cpu is unplugged)
*/ staticvoid free_cpu_cached_iovas(unsignedint cpu, struct iova_domain *iovad)
{ struct iova_cpu_rcache *cpu_rcache; struct iova_rcache *rcache; unsignedlong flags; int i;
for (i = 0; i < IOVA_RANGE_CACHE_MAX_SIZE; ++i) {
rcache = &iovad->rcaches[i];
cpu_rcache = per_cpu_ptr(rcache->cpu_rcaches, cpu);
spin_lock_irqsave(&cpu_rcache->lock, flags);
iova_magazine_free_pfns(cpu_rcache->loaded, iovad);
iova_magazine_free_pfns(cpu_rcache->prev, iovad);
spin_unlock_irqrestore(&cpu_rcache->lock, flags);
}
}
/* * free all the IOVA ranges of global cache
*/ staticvoid free_global_cached_iovas(struct iova_domain *iovad)
{ struct iova_rcache *rcache; unsignedlong flags;
for (int i = 0; i < IOVA_RANGE_CACHE_MAX_SIZE; ++i) {
rcache = &iovad->rcaches[i];
spin_lock_irqsave(&rcache->lock, flags); while (rcache->depot) { struct iova_magazine *mag = iova_depot_pop(rcache);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.