diff options
-rw-r--r-- | core/interrupts.c | 22 | ||||
-rw-r--r-- | hw/xive.c | 10 | ||||
-rw-r--r-- | hw/xive2.c | 10 | ||||
-rw-r--r-- | include/interrupts.h | 1 |
4 files changed, 38 insertions, 5 deletions
diff --git a/core/interrupts.c b/core/interrupts.c index 35571f2..03a37b2 100644 --- a/core/interrupts.c +++ b/core/interrupts.c @@ -199,6 +199,21 @@ uint32_t get_ics_phandle(void) abort(); } +static bool source_has_opal_interrupts(struct irq_source *is) +{ + /* check with the source first */ + if (is->ops->has_opal_interrupts) + return is->ops->has_opal_interrupts(is); + /* + * Default case: to handle an interrupt in opal, a source + * needs at least an attribute callback to declare it and a + * handler + */ + if (!is->ops->interrupt || !is->ops->attributes) + return false; + return true; +} + void add_opal_interrupts(void) { struct irq_source *is; @@ -214,11 +229,8 @@ void add_opal_interrupts(void) lock(&irq_lock); list_for_each(&irq_sources, is, link) { - /* - * Don't even consider sources that don't have an interrupts - * callback or don't have an attributes one. - */ - if (!is->ops->interrupt || !is->ops->attributes) + + if (!source_has_opal_interrupts(is)) continue; for (isn = is->start; isn < is->end; isn++) { uint64_t attr = is->ops->attributes(is, isn); @@ -2520,6 +2520,15 @@ void xive_source_mask(struct irq_source *is, uint32_t isn) xive_update_irq_mask(s, isn - s->esb_base, true); } +static bool xive_has_opal_interrupts(struct irq_source *is) +{ + struct xive_src *s = container_of(is, struct xive_src, is); + + if (!s->orig_ops || !s->orig_ops->attributes || !s->orig_ops->interrupt) + return false; + return true; +} + static const struct irq_source_ops xive_irq_source_ops = { .get_xive = xive_source_get_xive, .set_xive = xive_source_set_xive, @@ -2527,6 +2536,7 @@ static const struct irq_source_ops xive_irq_source_ops = { .interrupt = xive_source_interrupt, .attributes = xive_source_attributes, .name = xive_source_name, + .has_opal_interrupts = xive_has_opal_interrupts, }; static void __xive_register_source(struct xive *x, struct xive_src *s, @@ -2644,10 +2644,20 @@ void xive2_source_mask(struct irq_source *is, uint32_t isn) xive_update_irq_mask(s, isn - s->esb_base, true); } +static bool xive_has_opal_interrupts(struct irq_source *is) +{ + struct xive_src *s = container_of(is, struct xive_src, is); + + if (!s->orig_ops || !s->orig_ops->attributes || !s->orig_ops->interrupt) + return false; + return true; +} + static const struct irq_source_ops xive_irq_source_ops = { .interrupt = xive_source_interrupt, .attributes = xive_source_attributes, .name = xive_source_name, + .has_opal_interrupts = xive_has_opal_interrupts, }; static void __xive_register_source(struct xive *x, struct xive_src *s, diff --git a/include/interrupts.h b/include/interrupts.h index 7ffcc6c..6958fa6 100644 --- a/include/interrupts.h +++ b/include/interrupts.h @@ -153,6 +153,7 @@ struct irq_source_ops { void (*interrupt)(struct irq_source *is, uint32_t isn); void (*eoi)(struct irq_source *is, uint32_t isn); char *(*name)(struct irq_source *is, uint32_t isn); + bool (*has_opal_interrupts)(struct irq_source *is); }; struct irq_source { |