aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/interrupts.c9
-rw-r--r--hw/npu.c23
-rw-r--r--hw/p7ioc-phb.c25
-rw-r--r--hw/p7ioc.c8
-rw-r--r--hw/phb3.c26
-rw-r--r--hw/phb4.c31
-rw-r--r--hw/psi.c51
-rw-r--r--include/interrupts.h35
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;
diff --git a/hw/npu.c b/hw/npu.c
index 5247f21..e805f10 100644
--- a/hw/npu.c
+++ b/hw/npu.c
@@ -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)
}
+
diff --git a/hw/p7ioc.c b/hw/p7ioc.c
index 6c0732c..fc035d6 100644
--- a/hw/p7ioc.c
+++ b/hw/p7ioc.c
@@ -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)
}
+
diff --git a/hw/phb3.c b/hw/phb3.c
index 8742c7a..8d34c0f 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -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);
}
+
diff --git a/hw/phb4.c b/hw/phb4.c
index 734146c..e1e8d3f 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -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);
diff --git a/hw/psi.c b/hw/psi.c
index 3efc177..a895050 100644
--- a/hw/psi.c
+++ b/hw/psi.c
@@ -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);
};