[Skiboot] [PATCH v2] interrupts: Convert P8 IRQ assignment to functions

Alistair Popple alistair at popple.id.au
Tue Sep 15 11:20:05 AEST 2015


Interrupts on P8 are currently hard-coded using macros in
include/interrupts.h. The new P8NVL processor has an extra PHB meaning
it supports 4 PHBs in total which leads to the following assert fail
when booting P8NVL based systems:

[6614913194,3] register IRQ source overlap !
[6620562844,3]   new: 2000..27f7 old: 2000..27f7
[6870377440,0] Assert fail: core/interrupts.c:67:0

This patch converts the existing macros to function calls so that
different platforms can support extra PHBs at the expense of a reduced
maximum number of chips.

Signed-off-by: Alistair Popple <alistair at popple.id.au>
---

Changes since v1:
	- Removed global p8_chip_id_bits

core/interrupts.c    | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 hw/phb3.c            | 18 +++++------
 include/interrupts.h | 42 ++++++++++++++-----------
 include/phb3.h       |  4 +--
 4 files changed, 120 insertions(+), 30 deletions(-)

diff --git a/core/interrupts.c b/core/interrupts.c
index 32f43ef..6ed2e9a 100644
--- a/core/interrupts.c
+++ b/core/interrupts.c
@@ -15,6 +15,7 @@
  */

 #include <skiboot.h>
+#include <chip.h>
 #include <cpu.h>
 #include <fsp.h>
 #include <interrupts.h>
@@ -121,7 +122,7 @@ uint32_t get_psi_interrupt(uint32_t chip_id)
 		irq |= P7_PSI_IRQ_BUID << 4;
 		break;
 	case proc_gen_p8:
-		irq = P8_CHIP_IRQ_BLOCK_BASE(chip_id, P8_IRQ_BLOCK_MISC);
+		irq = p8_chip_irq_block_base(chip_id, P8_IRQ_BLOCK_MISC);
 		irq += P8_IRQ_MISC_PSI_BASE;
 		break;
 	default:
@@ -253,6 +254,89 @@ void icp_kick_cpu(struct cpu_thread *cpu)
 	out_8(icp + ICP_MFRR, 0);
 }

+/* Returns the number of chip ID bits used for interrupt numbers */
+static uint32_t p8_chip_id_bits(uint32_t chip)
+{
+	struct proc_chip *proc_chip = get_chip(chip);
+
+	assert(proc_chip);
+	switch (proc_chip->type) {
+	case PROC_CHIP_P8_MURANO:
+	case PROC_CHIP_P8_VENICE:
+		return 6;
+		break;
+
+	case PROC_CHIP_P8_NAPLES:
+		return 5;
+		break;
+
+	default:
+		/* This shouldn't be called on non-P8 based systems */
+		assert(0);
+		return 0;
+		break;
+	}
+}
+
+/* The chip id mask is the upper p8_chip_id_bits of the irq number */
+static uint32_t chip_id_mask(uint32_t chip)
+{
+	uint32_t chip_id_bits = p8_chip_id_bits(chip);
+	uint32_t chip_id_mask;
+
+	chip_id_mask = ((1 << chip_id_bits) - 1);
+	chip_id_mask <<= P8_IRQ_BITS - chip_id_bits;
+	return chip_id_mask;
+}
+
+/* The block mask is what remains of the 19 bit irq number after
+ * removing the upper 5 or 6 bits for the chip# and the lower 11 bits
+ * for the number of bits per block. */
+static uint32_t block_mask(uint32_t chip)
+{
+	uint32_t chip_id_bits = p8_chip_id_bits(chip);
+	uint32_t irq_block_mask;
+
+	irq_block_mask = P8_IRQ_BITS - chip_id_bits - P8_IVE_BITS;
+	irq_block_mask = ((1 << irq_block_mask) - 1) << P8_IVE_BITS;
+	return irq_block_mask;
+}
+
+uint32_t p8_chip_irq_block_base(uint32_t chip, uint32_t block)
+{
+	uint32_t irq;
+
+	assert(chip < (1 << p8_chip_id_bits(chip)));
+	irq = SETFIELD(chip_id_mask(chip), 0, chip);
+	irq = SETFIELD(block_mask(chip), irq, block);
+
+	return irq;
+}
+
+uint32_t p8_chip_irq_phb_base(uint32_t chip, uint32_t phb)
+{
+	assert(chip < (1 << p8_chip_id_bits(chip)));
+
+	return p8_chip_irq_block_base(chip, phb + P8_IRQ_BLOCK_PHB_BASE);
+}
+
+uint32_t p8_irq_to_chip(uint32_t irq)
+{
+	/* This assumes we only have one type of cpu in a system,
+	 * which should be ok. */
+	return GETFIELD(chip_id_mask(this_cpu()->chip_id), irq);
+}
+
+uint32_t p8_irq_to_block(uint32_t irq)
+{
+	return GETFIELD(block_mask(this_cpu()->chip_id), irq);
+}
+
+uint32_t p8_irq_to_phb(uint32_t irq)
+{
+	return p8_irq_to_block(irq) - P8_IRQ_BLOCK_PHB_BASE;
+}
+
 static struct irq_source *irq_find_source(uint32_t isn)
 {
 	struct irq_source *is;
diff --git a/hw/phb3.c b/hw/phb3.c
index 5fd0130..ef5d36c 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -1550,8 +1550,8 @@ static int64_t phb3_msi_get_xive(void *data,
 	uint32_t chip, index, irq;
 	uint64_t ive;

-	chip = P8_IRQ_TO_CHIP(isn);
-	index = P8_IRQ_TO_PHB(isn);
+	chip = p8_irq_to_chip(isn);
+	index = p8_irq_to_phb(isn);
 	irq = PHB3_IRQ_NUM(isn);

 	if (chip != p->chip_id ||
@@ -1580,8 +1580,8 @@ static int64_t phb3_msi_set_xive(void *data,
 	uint64_t *cache, ive_num, data64, m_server, m_prio;
 	uint32_t *ive;

-	chip = P8_IRQ_TO_CHIP(isn);
-	index = P8_IRQ_TO_PHB(isn);
+	chip = p8_irq_to_chip(isn);
+	index = p8_irq_to_phb(isn);
 	ive_num = PHB3_IRQ_NUM(isn);

 	if (p->state == PHB3_STATE_BROKEN || !p->tbl_rtt)
@@ -1642,8 +1642,8 @@ static int64_t phb3_lsi_get_xive(void *data,
 	uint32_t chip, index, irq;
 	uint64_t lxive;

-	chip = P8_IRQ_TO_CHIP(isn);
-	index = P8_IRQ_TO_PHB(isn);
+	chip = p8_irq_to_chip(isn);
+	index = p8_irq_to_phb(isn);
 	irq = PHB3_IRQ_NUM(isn);

 	if (chip != p->chip_id	||
@@ -1668,8 +1668,8 @@ static int64_t phb3_lsi_set_xive(void *data,
 	uint32_t chip, index, irq, entry;
 	uint64_t lxive;

-	chip = P8_IRQ_TO_CHIP(isn);
-	index = P8_IRQ_TO_PHB(isn);
+	chip = p8_irq_to_chip(isn);
+	index = p8_irq_to_phb(isn);
 	irq = PHB3_IRQ_NUM(isn);

 	if (p->state == PHB3_STATE_BROKEN)
@@ -4444,7 +4444,7 @@ static void phb3_probe_pbcq(struct dt_node *pbcq)
 	/* Set the interrupt routing stuff, 8 relevant bits in mask
 	 * (11 bits per PHB)
 	 */
-	val = P8_CHIP_IRQ_PHB_BASE(gcid, pno);
+	val = p8_chip_irq_phb_base(gcid, pno);
 	val = (val << 45);
 	xscom_write(gcid, pe_xscom + 0x1a, val);
 	xscom_write(gcid, pe_xscom + 0x1b, 0xff00000000000000ul);
diff --git a/include/interrupts.h b/include/interrupts.h
index 9239b86..d144dcd 100644
--- a/include/interrupts.h
+++ b/include/interrupts.h
@@ -152,19 +152,26 @@
  * are naturally power-of-two aligned
  *
  * Our P8 Interrupt map consits thus of dividing the chip space
- * into 4 "blocks" of 2048 interrupts. Block 0 is for random chip
+ * into "blocks" of 2048 interrupts. Block 0 is for random chip
  * interrupt sources (NX, PSI, OCC, ...) and keeps sources 0..15
- * clear to avoid conflits with IPIs etc.... Block 1..3 are assigned
- * to PHB 0..2 respectively.
+ * clear to avoid conflits with IPIs etc.... Block 1..n are assigned
+ * to PHB 0..n respectively. The number of blocks is determined by the
+ * number of bits assigned to chips.
  *
  * That gives us an interrupt number made of:
- *  18                13 12  11  10                         0
+ *  18               n+1 n   11  10                         0
  *  |                  | |    | |                           |
  * +--------------------+------+-----------------------------+
  * |        Chip#       | PHB# |             IVE#            |
  * +--------------------+------+-----------------------------+
  *
- * We can thus support a max of 2^6 = 64 chips
+ * Where n = 18 - p8_chip_id_bits
+ *
+ * For P8 we have 6 bits for Chip# as defined by p8_chip_id_bits. We
+ * therefore support a max of 2^6 = 64 chips.
+ *
+ * For P8NVL we have an extra PHB and so we assign 5 bits for Chip#
+ * and therefore support a max of 32 chips.
  *
  * Each PHB supports 2K interrupt sources, which is shared by
  * LSI and MSI. With default configuration, MSI would use range
@@ -174,21 +181,20 @@
  *
  */

-#define P8_CHIP_IRQ_BASE(chip)			((chip) << 13)
-#define P8_CHIP_IRQ_BLOCK_BASE(chip, block)	(P8_CHIP_IRQ_BASE(chip) \
-						 | ((block) << 11))
-#define P8_IRQ_BLOCK_MISC	0
-#define P8_IRQ_BLOCK_PHB0	1
-#define P8_IRQ_BLOCK_PHB1	2
-#define P8_IRQ_BLOCK_PHB2	3
+uint32_t p8_chip_irq_block_base(uint32_t chip, uint32_t block);
+uint32_t p8_chip_irq_phb_base(uint32_t chip, uint32_t phb);
+uint32_t p8_irq_to_chip(uint32_t irq);
+uint32_t p8_irq_to_block(uint32_t irq);
+uint32_t p8_irq_to_phb(uint32_t irq);

-#define P8_CHIP_IRQ_PHB_BASE(chip, phb)		(P8_CHIP_IRQ_BLOCK_BASE(chip,\
-						  (phb) + P8_IRQ_BLOCK_PHB0))
+/* Total number of bits in the P8 interrupt space */
+#define P8_IRQ_BITS		19

-#define P8_IRQ_TO_CHIP(irq)			(((irq) >> 13) & 0x3f)
-#define P8_IRQ_TO_BLOCK(irq)			(((irq) >> 11) & 0x03)
-#define P8_IRQ_TO_PHB(irq)			(P8_IRQ_TO_BLOCK(irq) - \
-						 P8_IRQ_BLOCK_PHB0)
+/* Number of bits per block */
+#define P8_IVE_BITS		11
+
+#define P8_IRQ_BLOCK_MISC	0
+#define P8_IRQ_BLOCK_PHB_BASE	1

 /* Assignment of the "MISC" block:
  * -------------------------------
diff --git a/include/phb3.h b/include/phb3.h
index 3accd9e..8f3c170 100644
--- a/include/phb3.h
+++ b/include/phb3.h
@@ -52,9 +52,9 @@
 #define PHB3_LSI_IRQ_COUNT		8
 #define PHB3_LSI_IRQ_MAX		(PHB3_LSI_IRQ_MIN+PHB3_LSI_IRQ_COUNT-1)

-#define PHB3_MSI_IRQ_BASE(chip, phb)	(P8_CHIP_IRQ_PHB_BASE(chip, phb) | \
+#define PHB3_MSI_IRQ_BASE(chip, phb)	(p8_chip_irq_phb_base(chip, phb) | \
 					 PHB3_MSI_IRQ_MIN)
-#define PHB3_LSI_IRQ_BASE(chip, phb)	(P8_CHIP_IRQ_PHB_BASE(chip, phb) | \
+#define PHB3_LSI_IRQ_BASE(chip, phb)	(p8_chip_irq_phb_base(chip, phb) | \
 					 PHB3_LSI_IRQ_MIN)
 #define PHB3_IRQ_NUM(irq)		(irq & 0x7FF)

--
2.1.4


More information about the Skiboot mailing list