[PATCH] powerpc: iSeries has only 256 IRQs

Stephen Rothwell sfr at canb.auug.org.au
Tue Apr 4 14:56:20 EST 2006


The iSeries Hypervisor only allows us to specify IRQ numbers up to 255 (it
has a u8 field to pass it in).  This patch allows platforms to specify a
maximum to the virtual IRQ numbers we will use and has iSeries set that
to 255.  If not set, the maximum is NR_IRQS - 1 (as before).

Signed-off-by: Stephen Rothwell <sfr at canb.auug.org.au>
---

 arch/powerpc/kernel/irq.c              |   36 ++++++++++++++++++++------------
 arch/powerpc/platforms/iseries/setup.c |    7 ++++++
 include/asm-powerpc/irq.h              |    7 ++++++
 3 files changed, 36 insertions(+), 14 deletions(-)

This has been booted on iSeries partitions that have hardware that would
have previously tried to use IRQ numbers above 255.

-- 
Cheers,
Stephen Rothwell                    sfr at canb.auug.org.au

7d01c880856bae31502095bc68784c1518a680cb
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index bb5c950..57d560c 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -272,18 +272,26 @@ unsigned int virt_irq_to_real_map[NR_IRQ
  * Don't use virtual irqs 0, 1, 2 for devices.
  * The pcnet32 driver considers interrupt numbers < 2 to be invalid,
  * and 2 is the XICS IPI interrupt.
- * We limit virtual irqs to 17 less than NR_IRQS so that when we
- * offset them by 16 (to reserve the first 16 for ISA interrupts)
- * we don't end up with an interrupt number >= NR_IRQS.
+ * We limit virtual irqs to __irq_offet_value less than virt_irq_max so
+ * that when we offset them we don't end up with an interrupt
+ * number > virt_irq_max.
  */
 #define MIN_VIRT_IRQ	3
-#define MAX_VIRT_IRQ	(NR_IRQS - NUM_ISA_INTERRUPTS - 1)
-#define NR_VIRT_IRQS	(MAX_VIRT_IRQ - MIN_VIRT_IRQ + 1)
+
+unsigned int virt_irq_max;
+static unsigned int max_virt_irq;
+static unsigned int nr_virt_irqs;
 
 void
 virt_irq_init(void)
 {
 	int i;
+
+	if ((virt_irq_max == 0) || (virt_irq_max > (NR_IRQS - 1)))
+		virt_irq_max = NR_IRQS - 1;
+	max_virt_irq = virt_irq_max - __irq_offset_value;
+	nr_virt_irqs = max_virt_irq - MIN_VIRT_IRQ + 1;
+
 	for (i = 0; i < NR_IRQS; i++)
 		virt_irq_to_real_map[i] = UNDEFINED_IRQ;
 }
@@ -308,17 +316,17 @@ int virt_irq_create_mapping(unsigned int
 		return real_irq;
 	}
 
-	/* map to a number between MIN_VIRT_IRQ and MAX_VIRT_IRQ */
+	/* map to a number between MIN_VIRT_IRQ and max_virt_irq */
 	virq = real_irq;
-	if (virq > MAX_VIRT_IRQ)
-		virq = (virq % NR_VIRT_IRQS) + MIN_VIRT_IRQ;
+	if (virq > max_virt_irq)
+		virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ;
 
 	/* search for this number or a free slot */
 	first_virq = virq;
 	while (virt_irq_to_real_map[virq] != UNDEFINED_IRQ) {
 		if (virt_irq_to_real_map[virq] == real_irq)
 			return virq;
-		if (++virq > MAX_VIRT_IRQ)
+		if (++virq > max_virt_irq)
 			virq = MIN_VIRT_IRQ;
 		if (virq == first_virq)
 			goto nospace;	/* oops, no free slots */
@@ -330,8 +338,8 @@ int virt_irq_create_mapping(unsigned int
  nospace:
 	if (!warned) {
 		printk(KERN_CRIT "Interrupt table is full\n");
-		printk(KERN_CRIT "Increase NR_IRQS (currently %d) "
-		       "in your kernel sources and rebuild.\n", NR_IRQS);
+		printk(KERN_CRIT "Increase virt_irq_max (currently %d) "
+		       "in your kernel sources and rebuild.\n", virt_irq_max);
 		warned = 1;
 	}
 	return NO_IRQ;
@@ -349,8 +357,8 @@ unsigned int real_irq_to_virt_slowpath(u
 
 	virq = real_irq;
 
-	if (virq > MAX_VIRT_IRQ)
-		virq = (virq % NR_VIRT_IRQS) + MIN_VIRT_IRQ;
+	if (virq > max_virt_irq)
+		virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ;
 
 	first_virq = virq;
 
@@ -360,7 +368,7 @@ unsigned int real_irq_to_virt_slowpath(u
 
 		virq++;
 
-		if (virq >= MAX_VIRT_IRQ)
+		if (virq >= max_virt_irq)
 			virq = 0;
 
 	} while (first_virq != virq);
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 6ce8a40..a6fd9be 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -54,6 +54,7 @@
 #include <asm/iseries/hv_lp_event.h>
 #include <asm/iseries/lpar_map.h>
 #include <asm/udbg.h>
+#include <asm/irq.h>
 
 #include "naca.h"
 #include "setup.h"
@@ -684,6 +685,12 @@ static int __init iseries_probe(void)
 	powerpc_firmware_features |= FW_FEATURE_ISERIES;
 	powerpc_firmware_features |= FW_FEATURE_LPAR;
 
+	/*
+	 * The Hypervisor only allows us up to 256 interrupt
+	 * sources (the irq number is passed in a u8).
+	 */
+	virt_irq_max = 255;
+
 	return 1;
 }
 
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
index 51f87d9..7bc6d73 100644
--- a/include/asm-powerpc/irq.h
+++ b/include/asm-powerpc/irq.h
@@ -54,6 +54,13 @@
  */
 extern unsigned int virt_irq_to_real_map[NR_IRQS];
 
+/* The maximum virtual IRQ number that we support.  This
+ * can be set by the platform and will be reduced by the
+ * value of __irq_offset_value.  It defaults to and is
+ * capped by (NR_IRQS - 1).
+ */
+extern unsigned int virt_irq_max;
+
 /* Create a mapping for a real_irq if it doesn't already exist.
  * Return the virtual irq as a convenience.
  */
-- 
1.2.4

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 191 bytes
Desc: not available
URL: <http://lists.ozlabs.org/pipermail/linuxppc-dev/attachments/20060404/07e83e9c/attachment.pgp>


More information about the Linuxppc-dev mailing list