Subject: [PATCH] Fix interrupt distribution in ppc970

From: Mohan Kumar M <[email-masked]>
Date: Fri, 8 Dec 2006 10:25:37 +0530

Hello,

We have encountered a strange problem with kdump in ppc970 based
machines. When a kdump kernel is booted with maxcpus=1 parameter,
interrupt is distributed to non-existent cpus also. It created lot of
interrupt missing problems.

This problem can be resolved by passing the additional kernel parameter
"noirqdistrib", which uses boot cpu id as interrupt distribution server.

To overcome this problem, I have created the patch, which
checks for the condition if the machine is ppc970 based and maxcpus
kernel parameter is specified. If the condition is met, the default
distribution server is assigned to be current boot cpu instead of
assigning from the gserver#s property.

Tested on PPC970 based box and POWER5 based box.

Any comment, feedback?

Patch is generated over 2.6.19-git7.

o Kdump with maxcpus kernel parameter in PPC970xx creates interrupt
  distribution problem, so set default distribution server to the
  current cpu (i.e. boot cpu)

Signed-off-by: Mohan Kumar M <[email-masked]>

---
 arch/powerpc/platforms/pseries/xics.c |   35 +++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

Index: linux-2.6.19-git7/arch/powerpc/platforms/pseries/xics.c
===================================================================
--- linux-2.6.19-git7.orig/arch/powerpc/platforms/pseries/xics.c
+++ linux-2.6.19-git7/arch/powerpc/platforms/pseries/xics.c
@@ -680,6 +680,27 @@ static struct device_node *cpuid_to_of_n
 	return NULL;
 }
 
+static int is_processor_970(void)
+{
+	unsigned long rval;
+	int rc;
+	rval = PVR_VER(mfspr(SPRN_PVR));
+
+	switch(rval) {
+		case PV_970:
+		case PV_970FX:
+		case PV_970MP:
+		case PV_970GX:
+			rc = 1;
+			break;
+		default:
+			rc = 0;
+			break;
+	}
+
+	return rc;
+}
+
 void __init xics_init_IRQ(void)
 {
 	int i, j;
@@ -688,6 +709,7 @@ void __init xics_init_IRQ(void)
 	const u32 *ireg, *isize;
 	int found = 0;
 	u32 hcpuid;
+	int fix_970_intr_distrib = 0;
 
 	ppc64_boot_msg(0x20, "XICS Init");
 
@@ -707,6 +729,13 @@ void __init xics_init_IRQ(void)
 
 	xics_init_host();
 
+	/* Kdump with maxcpus kernel parameter in PPC970xx creates interrupt
+	 * distribution problem, so set default distribution server to the
+	 * current cpu (i.e. boot cpu)
+	 */
+	if (strstr(saved_command_line, "maxcpus=") && is_processor_970())
+		fix_970_intr_distrib = 1;
+
 	/* Find the server numbers for the boot cpu. */
 	np = cpuid_to_of_node(boot_cpuid);
 	BUG_ON(!np);
@@ -724,7 +753,11 @@ void __init xics_init_IRQ(void)
 	for (j = 0; j < i; j += 2) {
 		if (ireg[j] == hcpuid) {
 			default_server = hcpuid;
-			default_distrib_server = ireg[j+1];
+
+			if (fix_970_intr_distrib)
+				default_distrib_server = hcpuid;
+			else
+				default_distrib_server = ireg[j+1];
 
 			isize = get_property(np,
 					"ibm,interrupt-server#-size", NULL);