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__
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to