Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 1847

kernel-2.6.18-128.1.10.el5.src.rpm

From: Brad Peters <bpeters@redhat.com>
Date: Thu, 27 Mar 2008 16:22:24 -0400
Subject: [ppc64] fixes removal of virtual cpu from dlpar
Message-id: 47EC0200.60803@redhat.com
O-Subject: Re: [RHEL 5.2 Patch 1/1] Fixes removal of virtual cpu from dlpar (regression)
Bugzilla: 432846

> RHBZ#:
> ------
> https://bugzilla.redhat.com/show_bug.cgi?id=432846
>
> Description:
> ------------
> Regression bug.
>
> Removal of a virtual processor from a dlpar currently fails, while the addition or removal
> of a physical cpu works fine.  This is caused by a cpu being removed with an irq still
> pinned to it, or when the vCPU's CPPR is reset during the cpu removal process,
> fixed by this patch.
>
>
> RHEL Version Found:
> ------------------
> RHEL 5.1
>
> kABI Status:
> ------------
> No symbols were harmed.
>
> Upstream Status:
> ----------------
> Original patches are available here:
> http://ozlabs.org/pipermail/linuxppc-dev/2008-February/051389.html
> http://ozlabs.org/pipermail/linuxppc-dev/2008-February/051390.html
> http://ozlabs.org/pipermail/linuxppc-dev/2008-February/051391.html
> http://ozlabs.org/pipermail/linuxppc-dev/2008-February/051392.html
> http://ozlabs.org/pipermail/linuxppc-dev/2008-February/051393.html
>
> Test Status:
> ------------
> Tested, confirmed.  2/28/08 <bpeters@redhat.com>
>
> ---------------------------------------------------------------
>
> Brad Peters 1-978-392-1000 x 23183
> IBM on-site partner.
>
> Proposed Patch:
> ---------------
> This patch is based on 2.6.18-83.el5
>
>

diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 0ff332c..6948f5f 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -248,7 +248,7 @@ static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary)
 					hard_smp_processor_id());
 		}
 	}
-	xics_teardown_cpu(secondary);
+	xics_kexec_teardown_cpu(secondary);
 }
 #endif /* CONFIG_KEXEC */
 
@@ -346,7 +346,7 @@ static void pSeries_mach_cpu_die(void)
 {
 	local_irq_disable();
 	idle_task_exit();
-	xics_teardown_cpu(0);
+	xics_teardown_cpu();
 	rtas_stop_self();
 	/* Should never get here... */
 	BUG();
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index a011fe4..2534448 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -174,6 +174,46 @@ static inline void lpar_qirr_info(int n_cpu , u8 value)
 
 /* High level handlers and init code */
 
+static void xics_update_irq_servers(void)
+{
+	int i, j;
+	struct device_node *np;
+	u32 ilen;
+	const u32 *ireg, *isize;
+	u32 hcpuid;
+
+	/* Find the server numbers for the boot cpu. */
+	np = of_get_cpu_node(boot_cpuid, NULL);
+	BUG_ON(!np);
+
+	ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
+	if (!ireg) {
+		of_node_put(np);
+		return;
+	}
+
+	i = ilen / sizeof(int);
+	hcpuid = get_hard_smp_processor_id(boot_cpuid);
+
+	/* Global interrupt distribution server is specified in the last
+	 * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
+	 * entry fom this property for current boot cpu id and use it as
+	 * default distribution server
+	 */
+	for (j = 0; j < i; j += 2) {
+		if (ireg[j] == hcpuid) {
+			default_server = hcpuid;
+			default_distrib_server = ireg[j+1];
+
+			isize = of_get_property(np,
+					"ibm,interrupt-server#-size", NULL);
+			if (isize)
+				interrupt_server_size = *isize;
+		}
+	}
+
+	of_node_put(np);
+}
 
 #ifdef CONFIG_SMP
 static int get_irq_server(unsigned int virq, unsigned int strict_check)
@@ -183,6 +223,9 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check)
 	cpumask_t cpumask = irq_desc[virq].affinity;
 	cpumask_t tmp = CPU_MASK_NONE;
 
+	if (! cpu_isset(default_server, cpu_online_map))
+		xics_update_irq_servers();
+
 	if (!distribute_irqs)
 		return default_server;
 
@@ -681,38 +724,11 @@ static void __init xics_setup_8259_cascade(void)
 	set_irq_chained_handler(cascade, pseries_8259_cascade);
 }
 
-static struct device_node *cpuid_to_of_node(int cpu)
-{
-	struct device_node *np;
-	u32 hcpuid = get_hard_smp_processor_id(cpu);
-
-	for_each_node_by_type(np, "cpu") {
-		int i, len;
-		const u32 *intserv;
-
-		intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
-
-		if (!intserv)
-			intserv = get_property(np, "reg", &len);
-
-		i = len / sizeof(u32);
-
-		while (i--)
-			if (intserv[i] == hcpuid)
-				return np;
-	}
-
-	return NULL;
-}
-
 void __init xics_init_IRQ(void)
 {
-	int i, j;
 	struct device_node *np;
-	u32 ilen, indx = 0;
-	const u32 *ireg, *isize;
+	u32 indx = 0;
 	int found = 0;
-	u32 hcpuid;
 
 	ppc64_boot_msg(0x20, "XICS Init");
 
@@ -731,35 +747,7 @@ void __init xics_init_IRQ(void)
 		return;
 
 	xics_init_host();
-
-	/* Find the server numbers for the boot cpu. */
-	np = cpuid_to_of_node(boot_cpuid);
-	BUG_ON(!np);
-	ireg = get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
-	if (!ireg)
-		goto skip_gserver_check;
-	i = ilen / sizeof(int);
-	hcpuid = get_hard_smp_processor_id(boot_cpuid);
-
-	/* Global interrupt distribution server is specified in the last
-	 * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
-	 * entry fom this property for current boot cpu id and use it as
-	 * default distribution server
-	 */
-	for (j = 0; j < i; j += 2) {
-		if (ireg[j] == hcpuid) {
-			default_server = hcpuid;
-			default_distrib_server = ireg[j+1];
-
-			isize = get_property(np,
-
-					"ibm,interrupt-server#-size", NULL);
-			if (isize)
-				interrupt_server_size = *isize;
-		}
-	}
-skip_gserver_check:
-	of_node_put(np);
+	xics_update_irq_servers();
 
 	if (firmware_has_feature(FW_FEATURE_LPAR))
 		ppc_md.get_irq = xics_get_irq_lpar;
@@ -796,11 +784,9 @@ void xics_request_IPIs(void)
 }
 #endif /* CONFIG_SMP */
 
-void xics_teardown_cpu(int secondary)
+void xics_teardown_cpu(void)
 {
 	int cpu = smp_processor_id();
-	unsigned int ipi;
-	struct irq_desc *desc;
 
 	xics_set_cpu_priority(cpu, 0);
 
@@ -811,9 +797,18 @@ void xics_teardown_cpu(int secondary)
 		lpar_qirr_info(cpu, 0xff);
 	else
 		direct_qirr_info(cpu, 0xff);
+}
+
+void xics_kexec_teardown_cpu(int secondary)
+{
+	unsigned int ipi;
+	struct irq_desc *desc;
+	int cpu = smp_processor_id();
+
+	xics_teardown_cpu();
 
 	/*
-	 * we need to EOI the IPI if we got here from kexec down IPI
+	 * we need to EOI the IPI
 	 *
 	 * probably need to check all the other interrupts too
 	 * should we be flagging idle loop instead?
@@ -902,8 +897,8 @@ void xics_migrate_irqs_away(void)
 		       virq, cpu);
 
 		/* Reset affinity to all cpus */
+		irq_desc[virq].affinity = CPU_MASK_ALL;
 		desc->chip->set_affinity(virq, CPU_MASK_ALL);
-		irq_desc[irq].affinity = CPU_MASK_ALL;
 unlock:
 		spin_unlock_irqrestore(&desc->lock, flags);
 	}
diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h
index 6ee1055..e3f0899 100644
--- a/arch/powerpc/platforms/pseries/xics.h
+++ b/arch/powerpc/platforms/pseries/xics.h
@@ -16,7 +16,8 @@
 
 extern void xics_init_IRQ(void);
 extern void xics_setup_cpu(void);
-extern void xics_teardown_cpu(int secondary);
+extern void xics_teardown_cpu(void);
+extern void xics_kexec_teardown_cpu(int secondary);
 extern void xics_cause_IPI(int cpu);
 extern  void xics_request_IPIs(void);
 extern void xics_migrate_irqs_away(void);