aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/interrupts.c50
-rw-r--r--hw/phb4.c10
-rw-r--r--hw/psi.c6
-rw-r--r--hw/xive.c60
-rw-r--r--include/interrupts.h3
-rw-r--r--include/xive.h8
6 files changed, 77 insertions, 60 deletions
diff --git a/core/interrupts.c b/core/interrupts.c
index 9bef5f5..1cdf3e4 100644
--- a/core/interrupts.c
+++ b/core/interrupts.c
@@ -32,17 +32,20 @@
#define ICP_MFRR 0xc /* 8-bit access */
static LIST_HEAD(irq_sources);
+static LIST_HEAD(irq_sources2);
static struct lock irq_lock = LOCK_UNLOCKED;
-void __register_irq_source(struct irq_source *is)
+void __register_irq_source(struct irq_source *is, bool secondary)
{
struct irq_source *is1;
+ struct list_head *list = secondary ? &irq_sources2 : &irq_sources;
- prlog(PR_DEBUG, "IRQ: Registering %04x..%04x ops @%p (data %p)\n",
- is->start, is->end - 1, is->ops, is->data);
+ prlog(PR_DEBUG, "IRQ: Registering %04x..%04x ops @%p (data %p)%s\n",
+ is->start, is->end - 1, is->ops, is->data,
+ secondary ? " [secondary]" : "");
lock(&irq_lock);
- list_for_each(&irq_sources, is1, link) {
+ list_for_each(list, is1, link) {
if (is->end > is1->start && is->start < is1->end) {
prerror("register IRQ source overlap !\n");
prerror(" new: %x..%x old: %x..%x\n",
@@ -51,7 +54,7 @@ void __register_irq_source(struct irq_source *is)
assert(0);
}
}
- list_add_tail(&irq_sources, &is->link);
+ list_add_tail(list, &is->link);
unlock(&irq_lock);
}
@@ -67,13 +70,14 @@ void register_irq_source(const struct irq_source_ops *ops, void *data,
is->ops = ops;
is->data = data;
- __register_irq_source(is);
+ __register_irq_source(is, false);
}
void unregister_irq_source(uint32_t start, uint32_t count)
{
struct irq_source *is;
+ /* Note: We currently only unregister from the primary sources */
lock(&irq_lock);
list_for_each(&irq_sources, is, link) {
if (start >= is->start && start < is->end) {
@@ -102,39 +106,24 @@ static struct irq_source *irq_find_source(uint32_t isn)
struct irq_source *is;
lock(&irq_lock);
+ /*
+ * XXX This really needs some kind of caching !
+ */
list_for_each(&irq_sources, is, link) {
if (isn >= is->start && isn < is->end) {
unlock(&irq_lock);
return is;
}
}
- unlock(&irq_lock);
-
- return NULL;
-}
-
-void adjust_irq_source(struct irq_source *is, uint32_t new_count)
-{
- struct irq_source *is1;
- uint32_t new_end = is->start + new_count;
-
- prlog(PR_DEBUG, "IRQ: Adjusting %04x..%04x to %04x..%04x\n",
- is->start, is->end - 1, is->start, new_end - 1);
-
- lock(&irq_lock);
- list_for_each(&irq_sources, is1, link) {
- if (is1 == is)
- continue;
- if (new_end > is1->start && is->start < is1->end) {
- prerror("adjust IRQ source overlap !\n");
- prerror(" new: %x..%x old: %x..%x\n",
- is->start, new_end - 1,
- is1->start, is1->end - 1);
- assert(0);
+ list_for_each(&irq_sources2, is, link) {
+ if (isn >= is->start && isn < is->end) {
+ unlock(&irq_lock);
+ return is;
}
}
- is->end = new_end;
unlock(&irq_lock);
+
+ return NULL;
}
/*
@@ -474,4 +463,3 @@ void init_interrupts(void)
}
}
-
diff --git a/hw/phb4.c b/hw/phb4.c
index a21aa1a..a6a6a51 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -3174,11 +3174,11 @@ static void phb4_create(struct dt_node *np)
phb4_init_hw(p, true);
/* Register all interrupt sources with XIVE */
- xive_register_source(p->base_msi, p->num_irqs - 8, 16, p->int_mmio, 0,
- NULL, NULL);
- xive_register_source(p->base_lsi, 8, 16,
- p->int_mmio + ((p->num_irqs - 8) << 16),
- XIVE_SRC_LSI, p, &phb4_lsi_ops);
+ xive_register_hw_source(p->base_msi, p->num_irqs - 8, 16, p->int_mmio, 0,
+ NULL, NULL);
+ xive_register_hw_source(p->base_lsi, 8, 16,
+ p->int_mmio + ((p->num_irqs - 8) << 16),
+ XIVE_SRC_LSI, p, &phb4_lsi_ops);
/* Platform additional setup */
if (platform.pci_setup_phb)
diff --git a/hw/psi.c b/hw/psi.c
index a7ea12c..9913c3a 100644
--- a/hw/psi.c
+++ b/hw/psi.c
@@ -785,9 +785,9 @@ static void psi_init_p9_interrupts(struct psi *psi)
out_be64(psi->regs + PSIHB_IVT_OFFSET, val);
/* Register sources */
- xive_register_source(psi->interrupt, P9_PSI_NUM_IRQS,
- 12, psi->esb_mmio, XIVE_SRC_LSI,
- psi, &psi_p9_irq_ops);
+ xive_register_hw_source(psi->interrupt, P9_PSI_NUM_IRQS,
+ 12, psi->esb_mmio, XIVE_SRC_LSI,
+ psi, &psi_p9_irq_ops);
}
static void psi_init_interrupts(struct psi *psi)
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);
diff --git a/include/interrupts.h b/include/interrupts.h
index 465073b..6b55099 100644
--- a/include/interrupts.h
+++ b/include/interrupts.h
@@ -291,11 +291,10 @@ struct irq_source {
struct list_node link;
};
-extern void __register_irq_source(struct irq_source *is);
+extern void __register_irq_source(struct irq_source *is, bool secondary);
extern void register_irq_source(const struct irq_source_ops *ops, void *data,
uint32_t start, uint32_t count);
extern void unregister_irq_source(uint32_t start, uint32_t count);
-extern void adjust_irq_source(struct irq_source *is, uint32_t new_count);
extern uint32_t get_psi_interrupt(uint32_t chip_id);
diff --git a/include/xive.h b/include/xive.h
index 367daec..065aa69 100644
--- a/include/xive.h
+++ b/include/xive.h
@@ -376,9 +376,11 @@ uint32_t xive_get_notify_base(uint32_t girq);
#define XIVE_SRC_LSI 0x00000004 /* No Q bit, no retrigger */
struct irq_source_ops;
-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);
+void xive_register_ipi_source(uint32_t base, uint32_t count, void *data,
+ const struct irq_source_ops *ops);
void xive_cpu_callin(struct cpu_thread *cpu);