aboutsummaryrefslogtreecommitdiff
path: root/hw/xive.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2016-11-14 13:06:15 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-11-15 15:06:03 +1100
commitaecfaf0146ccfb2a4d31fa812d224f8317225e8b (patch)
tree69e5fce2a62b4f6307b5a3559c8fb10b13e6f93b /hw/xive.c
parentbd4eaedc2dda6e7b365eb5e104c07c5d114528e6 (diff)
downloadskiboot-aecfaf0146ccfb2a4d31fa812d224f8317225e8b.zip
skiboot-aecfaf0146ccfb2a4d31fa812d224f8317225e8b.tar.gz
skiboot-aecfaf0146ccfb2a4d31fa812d224f8317225e8b.tar.bz2
xive: Provide a way to override some IPI sources
Some devices such as NX or the NPU will use some of the XIVE provided IPIs for their own interrupts. Thus we need a way for those to provide a custom irq_source_ops for portions of the IPI space in order for them to provide their own attributes() and if needed, interrutps() callbacks. We achieve that by creating a second list of sources which can overlap the primary. The global stock of IPIs is registered by XIVE in the secondary list which is searched when no match is found in the primary. A new API xive_register_ipi_source() is provided for those devices to create an overlapping source structure in the primary list for a subset of the IPIs. Those IPIs must have been previously allocated using xive_alloc_ipi_irqs() Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw/xive.c')
-rw-r--r--hw/xive.c60
1 files changed, 44 insertions, 16 deletions
diff --git a/hw/xive.c b/hw/xive.c
index a9150ed..80a95c2 100644
--- a/hw/xive.c
+++ b/hw/xive.c
@@ -103,6 +103,7 @@
/* Use 64K for everything by default */
#define IC_PAGE_SIZE 0x10000
#define TM_PAGE_SIZE 0x10000
+#define IPI_ESB_SHIFT (16 + 1)
#define IC_BAR_DEFAULT 0x30203100000ull
#define IC_BAR_SIZE (8 * IC_PAGE_SIZE)
@@ -1243,9 +1244,6 @@ uint32_t xive_alloc_hw_irqs(uint32_t chip_id, uint32_t count, uint32_t align)
}
x->int_hw_bot = base;
- /* Adjust the irq source to avoid overlaps */
- adjust_irq_source(&x->ipis.is, base - x->int_base);
-
/* Initialize the corresponding IVT entries to sane defaults,
* IE entry is valid, not routed and masked, EQ data is set
* to the GIRQ number.
@@ -1590,7 +1588,7 @@ static void xive_source_eoi(struct irq_source *is, uint32_t isn)
ive = s->xive->ivt_base;
if (!ive)
return;
- ive += GIRQ_TO_IDX(isn);
+ ive += GIRQ_TO_IDX(isn);
/* If it's invalid or masked, don't do anything */
if ((ive->w & IVE_MASKED) || !(ive->w & IVE_VALID))
@@ -1649,9 +1647,10 @@ static const struct irq_source_ops xive_irq_source_ops = {
.attributes = xive_source_attributes,
};
-static void __xive_register_source(struct xive_src *s, uint32_t base,
- uint32_t count, uint32_t shift,
- void *mmio, uint32_t flags, void *data,
+static void __xive_register_source(struct xive *x, struct xive_src *s,
+ uint32_t base, uint32_t count,
+ uint32_t shift, void *mmio, uint32_t flags,
+ bool secondary, void *data,
const struct irq_source_ops *orig_ops)
{
s->esb_base = base;
@@ -1659,24 +1658,50 @@ static void __xive_register_source(struct xive_src *s, uint32_t base,
s->esb_mmio = mmio;
s->flags = flags;
s->orig_ops = orig_ops;
-
+ s->xive = x;
s->is.start = base;
s->is.end = base + count;
s->is.ops = &xive_irq_source_ops;
s->is.data = data;
- __register_irq_source(&s->is);
+ __register_irq_source(&s->is, secondary);
}
-void xive_register_source(uint32_t base, uint32_t count, uint32_t shift,
- void *mmio, uint32_t flags, void *data,
- const struct irq_source_ops *ops)
+void xive_register_hw_source(uint32_t base, uint32_t count, uint32_t shift,
+ void *mmio, uint32_t flags, void *data,
+ const struct irq_source_ops *ops)
{
struct xive_src *s;
+ struct xive *x = xive_from_isn(base);
+
+ assert(x);
s = malloc(sizeof(struct xive_src));
assert(s);
- __xive_register_source(s, base, count, shift, mmio, flags, data, ops);
+ __xive_register_source(x, s, base, count, shift, mmio, flags,
+ false, data, ops);
+}
+
+void xive_register_ipi_source(uint32_t base, uint32_t count, void *data,
+ const struct irq_source_ops *ops)
+{
+ struct xive_src *s;
+ struct xive *x = xive_from_isn(base);
+ uint32_t base_idx = GIRQ_TO_IDX(base);
+ void *mmio_base;
+
+ assert(x);
+ assert(base >= x->int_base && (base + count) <= x->int_ipi_top);
+
+ s = malloc(sizeof(struct xive_src));
+ assert(s);
+
+ /* Callbacks assume the MMIO base corresponds to the first
+ * interrupt of that source structure so adjust it
+ */
+ mmio_base = x->esb_mmio + (1ul << IPI_ESB_SHIFT) * base_idx;
+ __xive_register_source(x, s, base, count, IPI_ESB_SHIFT, mmio_base,
+ XIVE_SRC_EOI_PAGE1, false, data, ops);
}
static void init_one_xive(struct dt_node *np)
@@ -1744,9 +1769,12 @@ static void init_one_xive(struct dt_node *np)
/* Register built-in source controllers (aka IPIs) */
/* XXX Add new EOI mode for DD2 */
- __xive_register_source(&x->ipis, x->int_base,
- x->int_hw_bot - x->int_base, 16 + 1,
- x->esb_mmio, XIVE_SRC_EOI_PAGE1, NULL, NULL);
+ __xive_register_source(x, &x->ipis, x->int_base,
+ x->int_hw_bot - x->int_base, IPI_ESB_SHIFT,
+ x->esb_mmio, XIVE_SRC_EOI_PAGE1,
+ true, NULL, NULL);
+
+ /* XXX Add registration of escalation sources too */
/* Create a device-tree node for Linux use */
xive_create_mmio_dt_node(x);