@@ -672,82 +672,127 @@ static struct irq_chip its_irq_chip = {
.irq_compose_msi_msg = its_irq_compose_msi_msg,
};
-/*
- * How we allocate LPIs:
- *
- * The GIC has id_bits bits for interrupt identifiers. From there, we
- * must subtract 8192 which are reserved for SGIs/PPIs/SPIs. Then, as
- * we allocate LPIs by chunks of 32, we can shift the whole thing by 5
- * bits to the right.
- *
- * This gives us (((1UL << id_bits) - 8192) >> 5) possible allocations.
- */
-#define IRQS_PER_CHUNK_SHIFT 5
-#define IRQS_PER_CHUNK (1 << IRQS_PER_CHUNK_SHIFT)
-
-static unsigned long *lpi_bitmap;
-static u32 lpi_chunks;
-static DEFINE_SPINLOCK(lpi_lock);
-static int its_lpi_to_chunk(int lpi)
-{
- return (lpi - 8192) >> IRQS_PER_CHUNK_SHIFT;
-}
+static struct list_head lpi_free_list;
+static struct list_head lpi_alloc_list;
+typedef struct lpi_mng {
+ struct list_head lpi_list;
+ int base;
+ int len;
+} lpi_mng_t;
-static int its_chunk_to_lpi(int chunk)
-{
- return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192;
-}
+static DEFINE_SPINLOCK(lpi_lock);
static int __init its_lpi_init(u32 id_bits)
{
- lpi_chunks = its_lpi_to_chunk(1UL << id_bits);
- lpi_bitmap = kzalloc(BITS_TO_LONGS(lpi_chunks) * sizeof(long),
- GFP_KERNEL);
- if (!lpi_bitmap) {
- lpi_chunks = 0;
+
+ u32 nr_irq = 1UL << id_bits;
+ lpi_mng_t *lpi_free_mng = NULL;
+ lpi_mng_t *lpi_new = NULL;
+ INIT_LIST_HEAD(&lpi_free_list);
+ INIT_LIST_HEAD(&lpi_alloc_list);
+
+ lpi_free_mng = kzalloc(sizeof(lpi_mng_t), GFP_ATOMIC);
+ if(!lpi_free_mng) {
return -ENOMEM;
}
+ lpi_free_mng->base = 0;
+ lpi_free_mng->len = nr_irq;
+ list_add(&lpi_free_mng->lpi_list, &lpi_free_list);
+
+ do {
+ lpi_free_mng = list_first_entry(&lpi_free_list, lpi_mng_t, lpi_list);
+ if(lpi_free_mng->len == 8192) {
+ /*It is not lpi, so we delete */
+ if(lpi_free_mng->base == 0) {
+ list_del_init(&lpi_free_mng->lpi_list);
+ kfree(lpi_free_mng);
+ continue;
+ }
+ if(lpi_free_mng->base == 8192) {
+ goto out;
+ }
+ }
+ if(lpi_free_mng->len > 8192) {
+ lpi_new = kzalloc(sizeof (lpi_mng_t),
+ GFP_ATOMIC);
+ if(!lpi_new) {
+ return -ENOMEM;
+ }
+ lpi_free_mng->len /= 2;
+ lpi_new->base = lpi_free_mng->base + lpi_free_mng->len;
+ lpi_new->len = lpi_free_mng->len;
+ list_add(&lpi_new->lpi_list,&lpi_free_mng->lpi_list);
+ }
+ }while(1);
- pr_info("ITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks);
+out:
+ pr_info("ITS: Allocated %d LPIs\n", nr_irq - 8192);
return 0;
}
+static lpi_mng_t* its_alloc_lpi(int nr_irqs)
+{
+ lpi_mng_t *lpi_alloc_mng = NULL;
+ lpi_mng_t *lpi_split = NULL;
+ lpi_mng_t *lpi_new = NULL;
+ int base;
+
+ base = 0x7fffffff;
+ do {
+ list_for_each_entry(lpi_alloc_mng, &lpi_free_list, lpi_list) {
+ if(nr_irqs > lpi_alloc_mng->len) {
+ continue;
+ }
+ if(nr_irqs == lpi_alloc_mng->len) {
+ list_del_init(&lpi_alloc_mng->lpi_list);
+ list_add(&lpi_alloc_mng->lpi_list, &lpi_alloc_list);
+ return lpi_alloc_mng;
+ }
+ if((nr_irqs < lpi_alloc_mng->len) && (lpi_alloc_mng->base < base)) {
+ base = lpi_alloc_mng->base;
+ lpi_split = lpi_alloc_mng;
+ }
+ }
+ lpi_new = kzalloc(sizeof (lpi_mng_t),
+ GFP_ATOMIC);
+ if(!lpi_new || !lpi_split) {
+ return NULL;
+ }
+
+ lpi_split->len /= 2;
+ lpi_new->base = lpi_split->base + lpi_split->len;
+ lpi_new->len = lpi_split->len;
+ list_add(&lpi_new->lpi_list,&lpi_split->lpi_list);
+
+ } while(1);
+}
+
static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids)
{
unsigned long *bitmap = NULL;
- int chunk_id;
- int nr_chunks;
- int i;
-
- nr_chunks = DIV_ROUND_UP(nr_irqs, IRQS_PER_CHUNK);
+ lpi_mng_t *lpi_alloc_mng = NULL;
spin_lock(&lpi_lock);
- do {
- chunk_id = bitmap_find_next_zero_area(lpi_bitmap, lpi_chunks,
- 0, nr_chunks, 0);
- if (chunk_id < lpi_chunks)
- break;
-
- nr_chunks--;
- } while (nr_chunks > 0);
+ lpi_alloc_mng = its_alloc_lpi(nr_irqs);
- if (!nr_chunks)
+ if (!lpi_alloc_mng)
goto out;
- bitmap = kzalloc(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK) * sizeof (long),
+ bitmap = kzalloc(BITS_TO_LONGS(nr_irqs) * sizeof (long),
GFP_ATOMIC);
if (!bitmap)
goto out;
- for (i = 0; i < nr_chunks; i++)
- set_bit(chunk_id + i, lpi_bitmap);
- *base = its_chunk_to_lpi(chunk_id);
- *nr_ids = nr_chunks * IRQS_PER_CHUNK;
+ *base = lpi_alloc_mng->base;
+ *nr_ids = lpi_alloc_mng->len;
out:
spin_unlock(&lpi_lock);
@@ -758,21 +803,47 @@ out:
return bitmap;
}