Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 24 May 2011 14:12:31 +0000 (UTC)
From:      Nathan Whitehorn <nwhitehorn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r222256 - projects/pseries/powerpc/pseries
Message-ID:  <201105241412.p4OECVHf071663@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: nwhitehorn
Date: Tue May 24 14:12:31 2011
New Revision: 222256
URL: http://svn.freebsd.org/changeset/base/222256

Log:
  Add SMP support on CHRP/PAPR system, including support for multi-threaded
  CPUs.

Modified:
  projects/pseries/powerpc/pseries/platform_chrp.c

Modified: projects/pseries/powerpc/pseries/platform_chrp.c
==============================================================================
--- projects/pseries/powerpc/pseries/platform_chrp.c	Tue May 24 14:10:33 2011	(r222255)
+++ projects/pseries/powerpc/pseries/platform_chrp.c	Tue May 24 14:12:31 2011	(r222256)
@@ -43,8 +43,10 @@ __FBSDID("$FreeBSD$");
 #include <machine/hid.h>
 #include <machine/platformvar.h>
 #include <machine/pmap.h>
+#include <machine/rtas.h>
 #include <machine/smp.h>
 #include <machine/spr.h>
+#include <machine/trap_aim.h>
 
 #include <dev/ofw/openfirm.h>
 #include <machine/ofw_machdep.h>
@@ -150,33 +152,12 @@ chrp_timebase_freq(platform_t plat, stru
 	return (ticks);
 }
 
-
-static int
-chrp_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu)
-{
-	cell_t cpuid, res;
-
-	cpuref->cr_hwref = cpu;
-	res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
-
-	/*
-	 * psim doesn't have a reg property, so assume 0 as for the
-	 * uniprocessor case in the CHRP spec. 
-	 */
-	if (res < 0) {
-		cpuid = 0;
-	}
-
-	cpuref->cr_cpuid = cpuid & 0xff;
-	return (0);
-}
-
 static int
 chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
 {
 	char buf[8];
 	phandle_t cpu, dev, root;
-	int res;
+	int res, cpuid;
 
 	root = OF_peer(0);
 
@@ -208,7 +189,16 @@ chrp_smp_first_cpu(platform_t plat, stru
 	if (cpu == 0)
 		return (ENOENT);
 
-	return (chrp_smp_fill_cpuref(cpuref, cpu));
+	cpuref->cr_hwref = cpu;
+	res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
+	    sizeof(cpuid));
+	if (res <= 0)
+		res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
+	if (res <= 0)
+		cpuid = 0;
+	cpuref->cr_cpuid = cpuid;
+
+	return (0);
 }
 
 static int
@@ -216,8 +206,23 @@ chrp_smp_next_cpu(platform_t plat, struc
 {
 	char buf[8];
 	phandle_t cpu;
-	int res;
+	int i, res, cpuid;
+
+	/* Check for whether it should be the next thread */
+	res = OF_getproplen(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s");
+	if (res > 0) {
+		cell_t interrupt_servers[res/sizeof(cell_t)];
+		OF_getprop(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s",
+		    interrupt_servers, res);
+		for (i = 0; i < res/sizeof(cell_t) - 1; i++) {
+			if (interrupt_servers[i] == cpuref->cr_cpuid) {
+				cpuref->cr_cpuid = interrupt_servers[i+1];
+				return (0);
+			}
+		}
+	}
 
+	/* Next CPU core/package */
 	cpu = OF_peer(cpuref->cr_hwref);
 	while (cpu != 0) {
 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
@@ -228,7 +233,16 @@ chrp_smp_next_cpu(platform_t plat, struc
 	if (cpu == 0)
 		return (ENOENT);
 
-	return (chrp_smp_fill_cpuref(cpuref, cpu));
+	cpuref->cr_hwref = cpu;
+	res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
+	    sizeof(cpuid));
+	if (res <= 0)
+		res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
+	if (res <= 0)
+		cpuid = 0;
+	cpuref->cr_cpuid = cpuid;
+
+	return (0);
 }
 
 static int
@@ -236,7 +250,7 @@ chrp_smp_get_bsp(platform_t plat, struct
 {
 	ihandle_t inst;
 	phandle_t bsp, chosen;
-	int res;
+	int res, cpuid;
 
 	chosen = OF_finddevice("/chosen");
 	if (chosen == 0)
@@ -247,14 +261,55 @@ chrp_smp_get_bsp(platform_t plat, struct
 		return (ENXIO);
 
 	bsp = OF_instance_to_package(inst);
-	return (chrp_smp_fill_cpuref(cpuref, bsp));
+
+	/* Pick the primary thread. Can it be any other? */
+	cpuref->cr_hwref = bsp;
+	res = OF_getprop(bsp, "ibm,ppc-interrupt-server#s", &cpuid,
+	    sizeof(cpuid));
+	if (res <= 0)
+		res = OF_getprop(bsp, "reg", &cpuid, sizeof(cpuid));
+	if (res <= 0)
+		cpuid = 0;
+	cpuref->cr_cpuid = cpuid;
+
+	return (0);
 }
 
 static int
 chrp_smp_start_cpu(platform_t plat, struct pcpu *pc)
 {
-	/* XXX: Uses RTAS call, will add later */
-	return (ENXIO);
+	cell_t start_cpu;
+	int result, err, timeout;
+
+	if (!rtas_exists()) {
+		printf("RTAS unitialized: unable to start AP %d\n",
+		    pc->pc_cpuid);
+		return (ENXIO);
+	}
+
+	start_cpu = rtas_token_lookup("start-cpu");
+	if (start_cpu == -1) {
+		printf("RTAS unknown method: unable to start AP %d\n",
+		    pc->pc_cpuid);
+		return (ENXIO);
+	}
+
+	ap_pcpu = pc;
+	powerpc_sync();
+
+	result = rtas_call_method(start_cpu, 3, 1, pc->pc_cpuid, EXC_RST, pc,
+	    &err);
+	if (result < 0 || err != 0) {
+		printf("RTAS error (%d/%d): unable to start AP %d\n",
+		    result, err, pc->pc_cpuid);
+		return (ENXIO);
+	}
+
+	timeout = 10000;
+	while (!pc->pc_awake && timeout--)
+		DELAY(100);
+
+	return ((pc->pc_awake) ? 0 : EBUSY);
 }
 
 static void



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105241412.p4OECVHf071663>