|
@@ -586,3 +586,106 @@ static struct irq_chip its_irq_chip = {
|
|
|
.irq_eoi = its_eoi_irq,
|
|
|
.irq_set_affinity = its_set_affinity,
|
|
|
};
|
|
|
+
|
|
|
+/*
|
|
|
+ * 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 int its_chunk_to_lpi(int chunk)
|
|
|
+{
|
|
|
+ return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192;
|
|
|
+}
|
|
|
+
|
|
|
+static int 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;
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ pr_info("ITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+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);
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ if (!nr_chunks)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ bitmap = kzalloc(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK) * 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;
|
|
|
+
|
|
|
+out:
|
|
|
+ spin_unlock(&lpi_lock);
|
|
|
+
|
|
|
+ return bitmap;
|
|
|
+}
|
|
|
+
|
|
|
+static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)
|
|
|
+{
|
|
|
+ int lpi;
|
|
|
+
|
|
|
+ spin_lock(&lpi_lock);
|
|
|
+
|
|
|
+ for (lpi = base; lpi < (base + nr_ids); lpi += IRQS_PER_CHUNK) {
|
|
|
+ int chunk = its_lpi_to_chunk(lpi);
|
|
|
+ BUG_ON(chunk > lpi_chunks);
|
|
|
+ if (test_bit(chunk, lpi_bitmap)) {
|
|
|
+ clear_bit(chunk, lpi_bitmap);
|
|
|
+ } else {
|
|
|
+ pr_err("Bad LPI chunk %d\n", chunk);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ spin_unlock(&lpi_lock);
|
|
|
+
|
|
|
+ kfree(bitmap);
|
|
|
+}
|