svn commit: r327360 - head/sys/powerpc/pseries

Nathan Whitehorn nwhitehorn at FreeBSD.org
Fri Dec 29 21:09:18 UTC 2017


Author: nwhitehorn
Date: Fri Dec 29 21:09:17 2017
New Revision: 327360
URL: https://svnweb.freebsd.org/changeset/base/327360

Log:
  Enhance the CHRP/pSeries platform layer:
  - Densely number CPUs to avoid systems with CPUs with very high ID numbers
  - Always have the BSP be CPU 0 to avoid remnant brokenness with non-0 BSPs
    in other parts of the kernel.
  - Improve parsing of the device tree CPU listings on SMT systems.
  - Allow reboot via RTAS as well as OF for pSeries systems booted by FDT
    without functioning Open Firmware.
  
  Obtained from:	projects/powernv
  MFC after:	3 weeks

Modified:
  head/sys/powerpc/pseries/platform_chrp.c

Modified: head/sys/powerpc/pseries/platform_chrp.c
==============================================================================
--- head/sys/powerpc/pseries/platform_chrp.c	Fri Dec 29 20:33:56 2017	(r327359)
+++ head/sys/powerpc/pseries/platform_chrp.c	Fri Dec 29 21:09:17 2017	(r327360)
@@ -114,6 +114,8 @@ static platform_def_t chrp_platform = {
 
 PLATFORM_DEF(chrp_platform);
 
+#define BSP_MUST_BE_CPU_ZERO
+
 static int
 chrp_probe(platform_t plat)
 {
@@ -279,13 +281,31 @@ chrp_real_maxaddr(platform_t plat)
 static u_long
 chrp_timebase_freq(platform_t plat, struct cpuref *cpuref)
 {
-	phandle_t phandle;
+	char buf[8];
+	phandle_t cpu, dev, root;
+	int res;
 	int32_t ticks = -1;
 
-	phandle = cpuref->cr_hwref;
+	root = OF_peer(0);
 
-	OF_getencprop(phandle, "timebase-frequency", &ticks, sizeof(ticks));
+	dev = OF_child(root);
+	while (dev != 0) {
+		res = OF_getprop(dev, "name", buf, sizeof(buf));
+		if (res > 0 && strcmp(buf, "cpus") == 0)
+			break;
+		dev = OF_peer(dev);
+	}
 
+	for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) {
+		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
+		if (res > 0 && strcmp(buf, "cpu") == 0)
+			break;
+	}
+	if (cpu == 0)
+		return (512000000);
+
+	OF_getencprop(cpu, "timebase-frequency", &ticks, sizeof(ticks));
+
 	if (ticks <= 0)
 		panic("Unable to determine timebase frequency!");
 
@@ -293,11 +313,11 @@ chrp_timebase_freq(platform_t plat, struct cpuref *cpu
 }
 
 static int
-chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
+chrp_cpuref_for_server(struct cpuref *cpuref, int cpu_n, int server)
 {
 	char buf[8];
 	phandle_t cpu, dev, root;
-	int res, cpuid;
+	int res, cpuid, i, j;
 
 	root = OF_peer(0);
 
@@ -318,71 +338,84 @@ chrp_smp_first_cpu(platform_t plat, struct cpuref *cpu
 			return (ENOENT);
 	}
 
-	cpu = OF_child(dev);
-
-	while (cpu != 0) {
+	i = 0;
+	for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) {
 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
-		if (res > 0 && strcmp(buf, "cpu") == 0)
-			break;
-		cpu = OF_peer(cpu);
+		if (res <= 0 || strcmp(buf, "cpu") != 0)
+			continue;
+
+		res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s");
+		if (res > 0) {
+			cell_t interrupt_servers[res/sizeof(cell_t)];
+			OF_getencprop(cpu, "ibm,ppc-interrupt-server#s",
+			    interrupt_servers, res);
+			for (j = 0; j < res/sizeof(cell_t); j++) {
+				cpuid = interrupt_servers[j];
+				if (server != -1 && cpuid == server)
+					break;
+				if (cpu_n != -1 && cpu_n == i)
+					break;
+				i++;
+			}
+
+			if (j != res/sizeof(cell_t))
+				break;
+		} else {
+			res = OF_getencprop(cpu, "reg", &cpuid, sizeof(cpuid));
+			if (res <= 0)
+				cpuid = 0;
+			if (server != -1 && cpuid == server)
+				break;
+			if (cpu_n != -1 && cpu_n == i)
+				break;
+			i++;
+		}
 	}
+
 	if (cpu == 0)
 		return (ENOENT);
 
-	cpuref->cr_hwref = cpu;
-	res = OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
-	    sizeof(cpuid));
-	if (res <= 0)
-		res = OF_getencprop(cpu, "reg", &cpuid, sizeof(cpuid));
-	if (res <= 0)
-		cpuid = 0;
-	cpuref->cr_cpuid = cpuid;
+	cpuref->cr_hwref = cpuid;
+	cpuref->cr_cpuid = i;
 
 	return (0);
 }
 
 static int
+chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
+{
+#ifdef BSP_MUST_BE_CPU_ZERO
+	return (chrp_smp_get_bsp(plat, cpuref));
+#else
+	return (chrp_cpuref_for_server(cpuref, 0, -1));
+#endif
+}
+
+static int
 chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
 {
-	char buf[8];
-	phandle_t cpu;
-	int i, res, cpuid;
+#ifdef BSP_MUST_BE_CPU_ZERO
+	int bsp, ncpus, err;
+	struct cpuref scratch;
 
-	/* 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_getencprop(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);
-			}
-		}
-	}
+	chrp_smp_get_bsp(plat, &scratch);
+	chrp_cpuref_for_server(&scratch, -1, scratch.cr_hwref);
+	bsp = scratch.cr_cpuid;
 
-	/* Next CPU core/package */
-	cpu = OF_peer(cpuref->cr_hwref);
-	while (cpu != 0) {
-		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
-		if (res > 0 && strcmp(buf, "cpu") == 0)
-			break;
-		cpu = OF_peer(cpu);
-	}
-	if (cpu == 0)
+	for (ncpus = bsp; chrp_cpuref_for_server(&scratch, ncpus, -1) !=
+	    ENOENT; ncpus++) {}
+	if (cpuref->cr_cpuid + 1 == ncpus)
 		return (ENOENT);
-
-	cpuref->cr_hwref = cpu;
-	res = OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
-	    sizeof(cpuid));
-	if (res <= 0)
-		res = OF_getencprop(cpu, "reg", &cpuid, sizeof(cpuid));
-	if (res <= 0)
-		cpuid = 0;
-	cpuref->cr_cpuid = cpuid;
-
-	return (0);
+	err = chrp_cpuref_for_server(cpuref,
+	    (cpuref->cr_cpuid + bsp + 1) % ncpus, -1);
+	if (cpuref->cr_cpuid >= bsp)
+		cpuref->cr_cpuid -= bsp;
+	else
+		cpuref->cr_cpuid = ncpus - (bsp - cpuref->cr_cpuid);
+	return (err);
+#else
+	return (chrp_cpuref_for_server(cpuref, cpuref->cr_cpuid+1, -1));
+#endif
 }
 
 static int
@@ -403,14 +436,17 @@ chrp_smp_get_bsp(platform_t plat, struct cpuref *cpure
 	bsp = OF_instance_to_package(inst);
 
 	/* Pick the primary thread. Can it be any other? */
-	cpuref->cr_hwref = bsp;
 	res = OF_getencprop(bsp, "ibm,ppc-interrupt-server#s", &cpuid,
 	    sizeof(cpuid));
 	if (res <= 0)
 		res = OF_getencprop(bsp, "reg", &cpuid, sizeof(cpuid));
 	if (res <= 0)
 		cpuid = 0;
+
+	chrp_cpuref_for_server(cpuref, -1, cpuid);
+#ifdef BSP_MUST_BE_CPU_ZERO
 	cpuref->cr_cpuid = cpuid;
+#endif
 
 	return (0);
 }
@@ -438,7 +474,7 @@ chrp_smp_start_cpu(platform_t plat, struct pcpu *pc)
 	ap_pcpu = pc;
 	powerpc_sync();
 
-	result = rtas_call_method(start_cpu, 3, 1, pc->pc_cpuid, EXC_RST, pc,
+	result = rtas_call_method(start_cpu, 3, 1, pc->pc_hwref, EXC_RST, pc,
 	    &err);
 	if (result < 0 || err != 0) {
 		printf("RTAS error (%d/%d): unable to start AP %d\n",
@@ -456,39 +492,62 @@ chrp_smp_start_cpu(platform_t plat, struct pcpu *pc)
 static struct cpu_group *
 chrp_smp_topo(platform_t plat)
 {
-	struct pcpu *pc, *last_pc;
-	int i, ncores, ncpus;
+	char buf[8];
+	phandle_t cpu, dev, root;
+	int res, nthreads;
 
-	ncores = ncpus = 0;
-	last_pc = NULL;
-	for (i = 0; i <= mp_maxid; i++) {
-		pc = pcpu_find(i);
-		if (pc == NULL)
+	root = OF_peer(0);
+
+	dev = OF_child(root);
+	while (dev != 0) {
+		res = OF_getprop(dev, "name", buf, sizeof(buf));
+		if (res > 0 && strcmp(buf, "cpus") == 0)
+			break;
+		dev = OF_peer(dev);
+	}
+
+	nthreads = 1;
+	for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) {
+		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
+		if (res <= 0 || strcmp(buf, "cpu") != 0)
 			continue;
-		if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref)
-			ncores++;
-		last_pc = pc;
-		ncpus++;
+
+		res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s");
+
+		if (res >= 0)
+			nthreads = res / sizeof(cell_t);
+		else
+			nthreads = 1;
+		break;
 	}
 
-	if (ncpus % ncores != 0) {
+	if (mp_ncpus % nthreads != 0) {
 		printf("WARNING: Irregular SMP topology. Performance may be "
-		     "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores);
+		     "suboptimal (%d threads, %d on first core)\n",
+		     mp_ncpus, nthreads);
 		return (smp_topo_none());
 	}
 
 	/* Don't do anything fancier for non-threaded SMP */
-	if (ncpus == ncores)
+	if (nthreads == 1)
 		return (smp_topo_none());
 
-	return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT));
+	return (smp_topo_1level(CG_SHARE_L1, nthreads, CG_FLAG_SMT));
 }
 #endif
 
 static void
 chrp_reset(platform_t platform)
 {
-	OF_reboot();
+	cell_t token, status;
+
+	if (rtas_exists()) {
+		token = rtas_token_lookup("system-reboot");
+		if (token != -1)
+			rtas_call_method(token, 0, 1, &status);
+	} else {
+		OF_reboot();
+	}
 }
 
 #ifdef __powerpc64__


More information about the svn-src-all mailing list