[Skiboot] [PATCH 35/60] xive: Add interrupt allocator
Benjamin Herrenschmidt
benh at kernel.crashing.org
Thu Dec 22 14:16:43 AEDT 2016
This adds the OPAL calls for the OS to allocate and free
new XIVE interrupts (aka IPIs).
Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
---
hw/xive.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 110 insertions(+)
diff --git a/hw/xive.c b/hw/xive.c
index 5c093a7..3010ba9 100644
--- a/hw/xive.c
+++ b/hw/xive.c
@@ -377,6 +377,9 @@ struct xive {
uint32_t int_hw_bot; /* Bottom of HW allocation */
uint32_t int_ipi_top; /* Highest IPI handed out so far + 1 */
+ /* The IPI allocation bitmap */
+ bitmap_t *ipi_alloc_map;
+
/* We keep track of which interrupts were ever enabled to
* speed up xive_reset
*/
@@ -1825,6 +1828,16 @@ static void late_init_one_xive(struct xive *x)
}
}
+static bool xive_check_ipi_free(struct xive *x, uint32_t irq, uint32_t count)
+{
+ uint32_t i, idx = GIRQ_TO_IDX(irq);
+
+ for (i = 0; i < count; i++)
+ if (bitmap_tst_bit(*x->ipi_alloc_map, idx + i))
+ return false;
+ return true;
+}
+
uint32_t xive_alloc_hw_irqs(uint32_t chip_id, uint32_t count, uint32_t align)
{
struct proc_chip *chip = get_chip(chip_id);
@@ -1849,6 +1862,12 @@ uint32_t xive_alloc_hw_irqs(uint32_t chip_id, uint32_t count, uint32_t align)
unlock(&x->lock);
return XIVE_IRQ_ERROR;
}
+ if (!xive_check_ipi_free(x, base, count)) {
+ xive_err(x, "HWIRQ boot allocator request overlaps dynamic allocator\n");
+ unlock(&x->lock);
+ return XIVE_IRQ_ERROR;
+ }
+
x->int_hw_bot = base;
/* Initialize the corresponding IVT entries to sane defaults,
@@ -1889,6 +1908,12 @@ uint32_t xive_alloc_ipi_irqs(uint32_t chip_id, uint32_t count, uint32_t align)
unlock(&x->lock);
return XIVE_IRQ_ERROR;
}
+ if (!xive_check_ipi_free(x, base, count)) {
+ xive_err(x, "IPI boot allocator request overlaps dynamic allocator\n");
+ unlock(&x->lock);
+ return XIVE_IRQ_ERROR;
+ }
+
x->int_ipi_top = base + count;
/* Initialize the corresponding IVT entries to sane defaults,
@@ -2442,6 +2467,8 @@ static struct xive *init_one_xive(struct dt_node *np)
assert(x->eq_map);
x->int_enabled_map = zalloc(BITMAP_BYTES(MAX_INT_ENTRIES));
assert(x->int_enabled_map);
+ x->ipi_alloc_map = zalloc(BITMAP_BYTES(MAX_INT_ENTRIES));
+ assert(x->ipi_alloc_map);
xive_dbg(x, "Handling interrupts [%08x..%08x]\n",
x->int_base, x->int_max - 1);
@@ -3446,6 +3473,87 @@ static int64_t opal_xive_reset(uint64_t version)
return OPAL_SUCCESS;
}
+static int64_t opal_xive_allocate_irq(uint32_t chip_id)
+{
+ struct proc_chip *chip = get_chip(chip_id);
+ int idx, base_idx, max_count, girq;
+ struct xive_ive *ive;
+ struct xive *x;
+
+ if (!chip)
+ return OPAL_PARAMETER;
+ if (!chip->xive)
+ return OPAL_PARAMETER;
+
+ x = chip->xive;
+ lock(&x->lock);
+
+ base_idx = x->int_ipi_top - x->int_base;
+ max_count = x->int_hw_bot - x->int_ipi_top;
+
+ idx = bitmap_find_zero_bit(*x->ipi_alloc_map, base_idx, max_count);
+ if (idx < 0) {
+ unlock(&x->lock);
+ return XIVE_ALLOC_NO_SPACE;
+ }
+ bitmap_set_bit(*x->ipi_alloc_map, idx);
+ girq = x->int_base + idx;
+
+ /* Mark the IVE valid. Don't bother with the HW cache, it's
+ * still masked anyway, the cache will be updated when unmasked
+ * and configured.
+ */
+ ive = xive_get_ive(x, girq);
+ if (!ive) {
+ bitmap_clr_bit(*x->ipi_alloc_map, idx);
+ unlock(&x->lock);
+ return OPAL_PARAMETER;
+ }
+ ive->w = IVE_VALID | IVE_MASKED | SETFIELD(IVE_EQ_DATA, 0ul, girq);
+ unlock(&x->lock);
+
+ return girq;
+}
+
+static int64_t opal_xive_free_irq(uint32_t girq)
+{
+ struct irq_source *is = irq_find_source(girq);
+ struct xive_src *s = container_of(is, struct xive_src, is);
+ struct xive *x = xive_from_isn(girq);
+ struct xive_ive *ive;
+ uint32_t idx;
+
+ if (!x || !is)
+ return OPAL_PARAMETER;
+
+ idx = GIRQ_TO_IDX(girq);
+
+ lock(&x->lock);
+
+ ive = xive_get_ive(x, girq);
+ if (!ive) {
+ unlock(&x->lock);
+ return OPAL_PARAMETER;
+ }
+
+ /* Mask the interrupt source */
+ xive_update_irq_mask(s, girq - s->esb_base, true);
+
+ /* Mark the IVE masked and invalid */
+ ive->w = IVE_MASKED;
+ xive_ivc_scrub(x, x->block_id, idx);
+
+ /* Free it */
+ if (!bitmap_tst_bit(*x->ipi_alloc_map, idx)) {
+ unlock(&x->lock);
+ return OPAL_PARAMETER;
+ }
+ bitmap_clr_bit(*x->ipi_alloc_map, idx);
+ unlock(&x->lock);
+
+ return OPAL_SUCCESS;
+}
+
static void xive_init_globals(void)
{
uint32_t i;
@@ -3520,5 +3628,7 @@ void init_xive(void)
opal_register(OPAL_XIVE_GET_QUEUE_INFO, opal_xive_get_queue_info, 7);
opal_register(OPAL_XIVE_SET_QUEUE_INFO, opal_xive_set_queue_info, 5);
opal_register(OPAL_XIVE_DONATE_PAGE, opal_xive_donate_page, 2);
+ opal_register(OPAL_XIVE_ALLOCATE_IRQ, opal_xive_allocate_irq, 1);
+ opal_register(OPAL_XIVE_FREE_IRQ, opal_xive_free_irq, 1);
}
--
2.9.3
More information about the Skiboot
mailing list