irqchip/gic-v3-its: Make free_lpi_range a little cheaper
Using list_add + list_sort to insert an element and keeping the list sorted is a somewhat blunt instrument; one can find the right place to insert in fewer lines of code than the cmp callback uses. Moreover, walking the entire list afterwards to merge adjacent ranges is overkill, since we know that only the just-inserted element may be merged with its neighbours. Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
This commit is contained in:
parent
1c73fac50d
commit
12eade123e
|
@ -26,7 +26,6 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/list_sort.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/mm.h>
|
||||
|
@ -1474,31 +1473,6 @@ static struct lpi_range *mk_lpi_range(u32 base, u32 span)
|
|||
return range;
|
||||
}
|
||||
|
||||
static int lpi_range_cmp(void *priv, struct list_head *a, struct list_head *b)
|
||||
{
|
||||
struct lpi_range *ra, *rb;
|
||||
|
||||
ra = container_of(a, struct lpi_range, entry);
|
||||
rb = container_of(b, struct lpi_range, entry);
|
||||
|
||||
return ra->base_id - rb->base_id;
|
||||
}
|
||||
|
||||
static void merge_lpi_ranges(void)
|
||||
{
|
||||
struct lpi_range *range, *tmp;
|
||||
|
||||
list_for_each_entry_safe(range, tmp, &lpi_range_list, entry) {
|
||||
if (!list_is_last(&range->entry, &lpi_range_list) &&
|
||||
(tmp->base_id == (range->base_id + range->span))) {
|
||||
tmp->base_id = range->base_id;
|
||||
tmp->span += range->span;
|
||||
list_del(&range->entry);
|
||||
kfree(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int alloc_lpi_range(u32 nr_lpis, u32 *base)
|
||||
{
|
||||
struct lpi_range *range, *tmp;
|
||||
|
@ -1528,9 +1502,21 @@ static int alloc_lpi_range(u32 nr_lpis, u32 *base)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void merge_lpi_ranges(struct lpi_range *a, struct lpi_range *b)
|
||||
{
|
||||
if (&a->entry == &lpi_range_list || &b->entry == &lpi_range_list)
|
||||
return;
|
||||
if (a->base_id + a->span != b->base_id)
|
||||
return;
|
||||
b->base_id = a->base_id;
|
||||
b->span += a->span;
|
||||
list_del(&a->entry);
|
||||
kfree(a);
|
||||
}
|
||||
|
||||
static int free_lpi_range(u32 base, u32 nr_lpis)
|
||||
{
|
||||
struct lpi_range *new;
|
||||
struct lpi_range *new, *old;
|
||||
|
||||
new = mk_lpi_range(base, nr_lpis);
|
||||
if (!new)
|
||||
|
@ -1538,9 +1524,24 @@ static int free_lpi_range(u32 base, u32 nr_lpis)
|
|||
|
||||
mutex_lock(&lpi_range_lock);
|
||||
|
||||
list_add(&new->entry, &lpi_range_list);
|
||||
list_sort(NULL, &lpi_range_list, lpi_range_cmp);
|
||||
merge_lpi_ranges();
|
||||
list_for_each_entry_reverse(old, &lpi_range_list, entry) {
|
||||
if (old->base_id < base)
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* old is the last element with ->base_id smaller than base,
|
||||
* so new goes right after it. If there are no elements with
|
||||
* ->base_id smaller than base, &old->entry ends up pointing
|
||||
* at the head of the list, and inserting new it the start of
|
||||
* the list is the right thing to do in that case as well.
|
||||
*/
|
||||
list_add(&new->entry, &old->entry);
|
||||
/*
|
||||
* Now check if we can merge with the preceding and/or
|
||||
* following ranges.
|
||||
*/
|
||||
merge_lpi_ranges(old, new);
|
||||
merge_lpi_ranges(new, list_next_entry(new, entry));
|
||||
|
||||
mutex_unlock(&lpi_range_lock);
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue