[Skiboot] [PATCH 01/15] interrupts: Add new source ->attributes callback

Benjamin Herrenschmidt benh at kernel.crashing.org
Tue Aug 9 16:38:05 AEST 2016


This allows a given source to provide per-interrupt attributes
such as whether it targets OPAL or Linux and it's estimated
frequency.

The former allows to get rid of the double set of ops used to
decide which interrupts go where on some modules like the PHBs
and the latter will be eventually used to implement smart
caching of the source lookups.

Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
---
 core/interrupts.c    |  9 ++++++---
 hw/npu.c             | 23 +++++++++++++----------
 hw/p7ioc-phb.c       | 25 ++++++++++++++-----------
 hw/p7ioc.c           |  8 ++++++++
 hw/phb3.c            | 26 +++++++++++++++-----------
 hw/phb4.c            | 31 ++++++++++++++++++++++++-------
 hw/psi.c             | 51 +++++++++++++++++++++++++++------------------------
 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;
diff --git a/hw/npu.c b/hw/npu.c
index 65db17f..dae0bb7 100644
--- a/hw/npu.c
+++ b/hw/npu.c
@@ -778,25 +778,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)
@@ -1852,3 +1854,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);
 };
-- 
2.7.4



More information about the Skiboot mailing list