diff options
-rw-r--r-- | core/interrupts.c | 9 | ||||
-rw-r--r-- | hw/npu.c | 23 | ||||
-rw-r--r-- | hw/p7ioc-phb.c | 25 | ||||
-rw-r--r-- | hw/p7ioc.c | 8 | ||||
-rw-r--r-- | hw/phb3.c | 26 | ||||
-rw-r--r-- | hw/phb4.c | 31 | ||||
-rw-r--r-- | hw/psi.c | 51 | ||||
-rw-r--r-- | include/interrupts.h | 35 |
8 files changed, 128 insertions, 80 deletions
diff --git a/core/interrupts.c b/core/interrupts.c index f93ce7b..e8f2543 100644 --- a/core/interrupts.c +++ b/core/interrupts.c @@ -210,12 +210,15 @@ void add_opal_interrupts(void) lock(&irq_lock); list_for_each(&irq_sources, is, link) { /* - * Add a source to opal-interrupts if it has an - * ->interrupt callback + * Don't even consider sources that don't have an interrupts + * callback or don't have an attributes one. */ - if (!is->ops->interrupt) + if (!is->ops->interrupt || !is->ops->attributes) continue; for (isn = is->start; isn < is->end; isn++) { + uint64_t attr = is->ops->attributes(is, isn); + if (attr & IRQ_ATTR_TARGET_LINUX) + continue; i = count++; irqs = realloc(irqs, 4 * count); irqs[i] = isn; @@ -773,25 +773,27 @@ static void npu_err_interrupt(struct irq_source *is, uint32_t isn) } } -/* LSIs (OS owned) */ -static const struct irq_source_ops npu_lsi_irq_ops = { - .get_xive = npu_lsi_get_xive, - .set_xive = npu_lsi_set_xive, -}; +static uint64_t npu_lsi_attributes(struct irq_source *is, uint32_t isn) +{ + struct npu *p = is->data; + uint32_t idx = isn - p->base_lsi; + + if (idx >= 4) + return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_RARE; + return IRQ_ATTR_TARGET_LINUX; +} /* Error LSIs (skiboot owned) */ -static const struct irq_source_ops npu_err_lsi_irq_ops = { +static const struct irq_source_ops npu_lsi_irq_ops = { .get_xive = npu_lsi_get_xive, .set_xive = npu_lsi_set_xive, + .attributes = npu_lsi_attributes, .interrupt = npu_err_interrupt, }; static void npu_register_irq(struct npu *p) { - register_irq_source(&npu_lsi_irq_ops, p, - p->base_lsi, 4); - register_irq_source(&npu_err_lsi_irq_ops, p, - p->base_lsi + 4, 4); + register_irq_source(&npu_lsi_irq_ops, p, p->base_lsi, 8); } static void npu_hw_init(struct npu *p) @@ -1847,3 +1849,4 @@ void probe_npu(void) npu_create_phb(np); } + diff --git a/hw/p7ioc-phb.c b/hw/p7ioc-phb.c index 52ff952..8ea393c 100644 --- a/hw/p7ioc-phb.c +++ b/hw/p7ioc-phb.c @@ -2532,6 +2532,17 @@ static void p7ioc_phb_err_interrupt(struct irq_source *is, uint32_t isn) phb_unlock(&p->phb); } +static uint64_t p7ioc_lsi_attributes(struct irq_source *is __unused, + uint32_t isn) +{ + uint32_t irq = (isn & 0x7); + + if (irq == PHB_LSI_PCIE_ERROR) + return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_RARE; + return IRQ_ATTR_TARGET_LINUX; +} + + /* MSIs (OS owned) */ static const struct irq_source_ops p7ioc_msi_irq_ops = { .get_xive = p7ioc_msi_get_xive, @@ -2542,12 +2553,7 @@ static const struct irq_source_ops p7ioc_msi_irq_ops = { static const struct irq_source_ops p7ioc_lsi_irq_ops = { .get_xive = p7ioc_lsi_get_xive, .set_xive = p7ioc_lsi_set_xive, -}; - -/* PHB Errors (Ski owned) */ -static const struct irq_source_ops p7ioc_phb_err_irq_ops = { - .get_xive = p7ioc_lsi_get_xive, - .set_xive = p7ioc_lsi_set_xive, + .attributes = p7ioc_lsi_attributes, .interrupt = p7ioc_phb_err_interrupt, }; @@ -2670,11 +2676,7 @@ void p7ioc_phb_setup(struct p7ioc *ioc, uint8_t index) /* Register OS interrupt sources */ register_irq_source(&p7ioc_msi_irq_ops, p, p->buid_msi << 4, 256); - register_irq_source(&p7ioc_lsi_irq_ops, p, p->buid_lsi << 4, 4); - - /* Register internal interrupt source (LSI 7) */ - register_irq_source(&p7ioc_phb_err_irq_ops, p, - (p->buid_lsi << 4) + PHB_LSI_PCIE_ERROR, 1); + register_irq_source(&p7ioc_lsi_irq_ops, p, p->buid_lsi << 4, 8); /* Initialize IODA table caches */ p7ioc_phb_init_ioda_cache(p); @@ -3265,3 +3267,4 @@ void p7ioc_phb_reset(struct phb *phb) } + @@ -581,9 +581,16 @@ static void p7ioc_rgc_interrupt(struct irq_source *is, uint32_t isn) opal_pci_eeh_set_evt(ioc->phbs[0].phb.opal_id); } +static uint64_t p7ioc_rgc_irq_attributes(struct irq_source *is __unused, + uint32_t isn __unused) +{ + return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_RARE; +} + static const struct irq_source_ops p7ioc_rgc_irq_ops = { .get_xive = p7ioc_rgc_get_xive, .set_xive = p7ioc_rgc_set_xive, + .attributes = p7ioc_rgc_irq_attributes, .interrupt = p7ioc_rgc_interrupt, }; @@ -680,3 +687,4 @@ void probe_p7ioc(void) } + @@ -1798,6 +1798,18 @@ static void phb3_err_interrupt(struct irq_source *is, uint32_t isn) phb3_set_err_pending(p, true); } +static uint64_t phb3_lsi_attributes(struct irq_source *is, uint32_t isn) +{ +#ifndef DISABLE_ERR_INTS + struct phb3 *p = is->data; + uint32_t idx = isn - p->base_lsi; + + if (idx == PHB3_LSI_PCIE_INF || idx == PHB3_LSI_PCIE_ER) + return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_RARE; +#endif + return IRQ_ATTR_TARGET_LINUX; +} + /* MSIs (OS owned) */ static const struct irq_source_ops phb3_msi_irq_ops = { .get_xive = phb3_msi_get_xive, @@ -1808,12 +1820,7 @@ static const struct irq_source_ops phb3_msi_irq_ops = { static const struct irq_source_ops phb3_lsi_irq_ops = { .get_xive = phb3_lsi_get_xive, .set_xive = phb3_lsi_set_xive, -}; - -/* Error LSIs (skiboot owned) */ -static const struct irq_source_ops phb3_err_lsi_irq_ops = { - .get_xive = phb3_lsi_get_xive, - .set_xive = phb3_lsi_set_xive, + .attributes = phb3_lsi_attributes, .interrupt = phb3_err_interrupt, }; @@ -4447,12 +4454,8 @@ static void phb3_create(struct dt_node *np) /* Register interrupt sources */ register_irq_source(&phb3_msi_irq_ops, p, p->base_msi, PHB3_MSI_IRQ_COUNT); - register_irq_source(&phb3_lsi_irq_ops, p, p->base_lsi, 4); + register_irq_source(&phb3_lsi_irq_ops, p, p->base_lsi, 8); -#ifndef DISABLE_ERR_INTS - register_irq_source(&phb3_err_lsi_irq_ops, p, - p->base_lsi + PHB3_LSI_PCIE_INF, 2); -#endif /* Get the HW up and running */ phb3_init_hw(p, true); @@ -4735,3 +4738,4 @@ void probe_phb3(void) phb3_create(np); } + @@ -55,7 +55,7 @@ #include <xive.h> /* Enable this to disable error interrupts for debug purposes */ -#undef DISABLE_ERR_INTS +#define DISABLE_ERR_INTS static void phb4_init_hw(struct phb4 *p, bool first_init); @@ -3048,12 +3048,32 @@ static void phb4_eoi(struct irq_source *is, uint32_t isn) } } -static const struct irq_source_ops phb4_irq_ops = { +static const struct irq_source_ops phb4_msi_ops = { .get_xive = phb4_get_xive, .set_xive = phb4_set_xive, .eoi = phb4_eoi }; +static uint64_t phb4_lsi_attributes(struct irq_source *is __unused, + uint32_t isn __unused) +{ +#ifndef DISABLE_ERR_INTS + struct phb3 *p = is->data; + uint32_t idx = isn - p->base_lsi; + + if (idx == PHB3_LSI_PCIE_INF || idx == PHB3_LSI_PCIE_ER) + return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_RARE; +#endif + return IRQ_ATTR_TARGET_LINUX; +} + +static const struct irq_source_ops phb4_lsi_ops = { + .get_xive = phb4_get_xive, + .set_xive = phb4_set_xive, + .attributes = phb4_lsi_attributes, + .eoi = phb4_eoi +}; + /* Error LSIs (skiboot owned) */ //static const struct irq_source_ops phb3_err_lsi_irq_ops = { // .get_xive = phb3_lsi_get_xive, @@ -3209,12 +3229,9 @@ static void phb4_create(struct dt_node *np) phb4_init_ioda_cache(p); /* Register interrupt sources */ - register_irq_source(&phb4_irq_ops, p, p->base_msi, p->num_irqs); + register_irq_source(&phb4_msi_ops, p, p->base_msi, p->num_irqs - 8); + register_irq_source(&phb4_lsi_ops, p, p->base_lsi, 8); -#ifndef DISABLE_ERR_INTS - // register_irq_source(&phb4_err_lsi_irq_ops, p, - // p->base_lsi + PHB4_LSI_PCIE_INF, 2); -#endif /* Get the HW up and running */ phb4_init_hw(p, true); @@ -432,6 +432,12 @@ static int64_t psi_p7_get_xive(struct irq_source *is, uint32_t isn __unused, return OPAL_SUCCESS; } +static uint64_t psi_p7_irq_attributes(struct irq_source *is __unused, + uint32_t isn __unused) +{ + return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_FREQUENT; +} + static int64_t psi_p8_set_xive(struct irq_source *is, uint32_t isn, uint16_t server, uint8_t priority) { @@ -509,6 +515,23 @@ static int64_t psi_p8_get_xive(struct irq_source *is, uint32_t isn __unused, return OPAL_SUCCESS; } +static uint64_t psi_p8_irq_attributes(struct irq_source *is, uint32_t isn) +{ + struct psi *psi = is->data; + uint32_t idx = isn - psi->interrupt; + uint64_t attr; + + if (idx == P8_IRQ_PSI_HOST_ERR && + psi_ext_irq_policy == EXTERNAL_IRQ_POLICY_LINUX) + return IRQ_ATTR_TARGET_LINUX; + + attr = IRQ_ATTR_TARGET_OPAL; + if (idx == P8_IRQ_PSI_HOST_ERR || idx == P8_IRQ_PSI_LPC || + idx == P8_IRQ_PSI_FSP) + attr |= IRQ_ATTR_TARGET_FREQUENT; + return attr; +} + /* Called on a fast reset, make sure we aren't stuck with * an accepted and never EOId PSI interrupt */ @@ -542,20 +565,17 @@ void psi_irq_reset(void) static const struct irq_source_ops psi_p7_irq_ops = { .get_xive = psi_p7_get_xive, .set_xive = psi_p7_set_xive, + .attributes = psi_p7_irq_attributes, .interrupt = psi_interrupt, }; static const struct irq_source_ops psi_p8_irq_ops = { .get_xive = psi_p8_get_xive, .set_xive = psi_p8_set_xive, + .attributes = psi_p8_irq_attributes, .interrupt = psi_interrupt, }; -static const struct irq_source_ops psi_p8_host_err_ops = { - .get_xive = psi_p8_get_xive, - .set_xive = psi_p8_set_xive, -}; - static void psi_tce_enable(struct psi *psi, bool enable) { void *addr; @@ -693,25 +713,8 @@ static void psi_register_interrupts(struct psi *psi) * external interrupt and the policy for that comes * from the platform */ - if (psi_ext_irq_policy == EXTERNAL_IRQ_POLICY_SKIBOOT) { - register_irq_source(&psi_p8_irq_ops, - psi, - psi->interrupt + P8_IRQ_PSI_SKIBOOT_BASE, - P8_IRQ_PSI_ALL_COUNT); - } else { - register_irq_source(&psi_p8_irq_ops, - psi, - psi->interrupt + P8_IRQ_PSI_SKIBOOT_BASE, - P8_IRQ_PSI_LOCAL_COUNT); - /* - * Host Error is handled by powernv; host error - * is at offset 5 from the PSI base. - */ - register_irq_source(&psi_p8_host_err_ops, - psi, - psi->interrupt + P8_IRQ_PSI_LINUX_BASE, - P8_IRQ_PSI_LINUX_COUNT); - } + register_irq_source(&psi_p8_irq_ops, psi, + psi->interrupt, P8_IRQ_PSI_IRQ_COUNT); break; default: /* Unknown: just no interrupts */ diff --git a/include/interrupts.h b/include/interrupts.h index 3fba9d9..23d785c 100644 --- a/include/interrupts.h +++ b/include/interrupts.h @@ -208,21 +208,16 @@ uint32_t p8_irq_to_phb(uint32_t irq); #define P8_IRQ_MISC_PSI_BASE 0x10 /* 0x10..0x17 */ /* These are handled by skiboot */ -#define P8_IRQ_PSI_SKIBOOT_BASE 0 #define P8_IRQ_PSI_FSP 0 #define P8_IRQ_PSI_OCC 1 #define P8_IRQ_PSI_FSI 2 #define P8_IRQ_PSI_LPC 3 #define P8_IRQ_PSI_LOCAL_ERR 4 -#define P8_IRQ_PSI_LOCAL_COUNT 5 -#define P8_IRQ_PSI_ALL_COUNT 6 +#define P8_IRQ_PSI_HOST_ERR 5 +#define P8_IRQ_PSI_IRQ_COUNT 6 /* TBD: NX, AS, ... */ -/* These are passed onto Linux */ -#define P8_IRQ_PSI_LINUX_BASE 5 -#define P8_IRQ_PSI_HOST_ERR 5 /* Used for UART */ -#define P8_IRQ_PSI_LINUX_COUNT 1 /* Note about interrupt numbers on P9 * ================================== @@ -259,19 +254,31 @@ uint32_t p8_irq_to_phb(uint32_t irq); struct irq_source; /* - * IRQ sources register themselves here. If an "interrupts" callback - * is provided, then all interrupts in that source will appear in - * 'opal-interrupts' and will be handled by us. - * - * The "eoi" callback is optional and can be used for interrupts - * requiring a special EOI at the source level. Typically will - * be used for XIVE interrupts coming from PHBs. + * IRQ sources register themselves here. + * + * The "attributes" callback provides various attributes specific to + * a given interrupt, such as whether it's targetted at OPAL or the + * OS, or whether it's frequent or infrequent. The latter will be used + * later to optimize the lookup of the sources array by providing a small + * cache of the frequent interrupts. + * + * The "eoi" callback is used for XIVE interrupts in XICS emulation + * though we might expose it at some point in XIVE native mode for + * interrupts that require special EOI operations such as possibly + * the LPC interrupts on P9 that need a latch cleared in the LPCHC. */ struct irq_source_ops { int64_t (*set_xive)(struct irq_source *is, uint32_t isn, uint16_t server, uint8_t priority); int64_t (*get_xive)(struct irq_source *is, uint32_t isn, uint16_t *server, uint8_t *priority); + uint64_t (*attributes)(struct irq_source *is, uint32_t isn); +/* LSB is the target */ +#define IRQ_ATTR_TARGET_OPAL 0x0 +#define IRQ_ATTR_TARGET_LINUX 0x1 +/* For OPAL interrupts, estimate frequency */ +#define IRQ_ATTR_TARGET_RARE 0x0 +#define IRQ_ATTR_TARGET_FREQUENT 0x2 void (*interrupt)(struct irq_source *is, uint32_t isn); void (*eoi)(struct irq_source *is, uint32_t isn); }; |