[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [POWERPC] Enable SMP, smp_processor_id, for_each_cpu, nosmp, maxcpus=X



# HG changeset patch
# User Jimi Xenidis <jimix@xxxxxxxxxxxxxx>
# Node ID 1ef82dd7f66b05e02aa5b9d0d6e55b2fc5f00db9
# Parent  8cc27cb8516b79cf310a6bda55b9bc6621835df6
[POWERPC] Enable SMP, smp_processor_id, for_each_cpu, nosmp, maxcpus=X

Add support for the "nosmp" and "maxcpus=X" command line options, and
address Hollis' concerns about comments, prototypes, and panic messages.

Handshake with secondary processors, move all of them out of their OF
spinloop even if there are more of them than NR_CPUS, enumerate them
according to a logical rather than firmware numerical space, give them a
stack, make them run C code to initialize their HIDs, initialize their
r13 registers to a per-processor pointer, enable smp_processor_id and
and properly set the maps of present and online CPUs.

Tested on 2-way JS20, 4-way JS21, and 16-way systemsim-gpul, with
NR_CPUS from 1 to 64, nosmp, and maxcpus from 1 to 3.

Signed-off-by: Amos Waterland <apw@xxxxxxxxxx>
Signed-off-by: Hollis Blanchard <hollisb@xxxxxxxxxx>
---
 xen/arch/powerpc/boot_of.c                   |   67 +++++++++++++++++++++++--
 xen/arch/powerpc/powerpc64/exceptions.S      |   37 ++++++++++++++
 xen/arch/powerpc/powerpc64/ppc970.c          |   22 ++++----
 xen/arch/powerpc/setup.c                     |   71 ++++++++++++++++++++++++++-
 xen/include/asm-powerpc/config.h             |    2 
 xen/include/asm-powerpc/current.h            |    2 
 xen/include/asm-powerpc/powerpc64/procarea.h |    1 
 xen/include/asm-powerpc/processor.h          |    2 
 xen/include/asm-powerpc/smp.h                |    4 -
 9 files changed, 188 insertions(+), 20 deletions(-)

diff -r 8cc27cb8516b -r 1ef82dd7f66b xen/arch/powerpc/boot_of.c
--- a/xen/arch/powerpc/boot_of.c        Mon Aug 21 10:04:37 2006 -0400
+++ b/xen/arch/powerpc/boot_of.c        Tue Aug 22 09:53:34 2006 -0400
@@ -31,6 +31,9 @@
 #include <asm/io.h>
 #include "exceptions.h"
 #include "of-devtree.h"
+
+/* Secondary processors use this for handshaking with main processor.  */
+volatile unsigned int __spin_ack;
 
 static ulong of_vec;
 static ulong of_msr;
@@ -955,7 +958,7 @@ static int __init boot_of_cpus(void)
 static int __init boot_of_cpus(void)
 {
     int cpus;
-    int cpu;
+    int cpu, bootcpu, logical;
     int result;
     u32 cpu_clock[2];
 
@@ -980,10 +983,65 @@ static int __init boot_of_cpus(void)
     cpu_khz /= 1000;
     of_printf("OF: clock-frequency = %ld KHz\n", cpu_khz);
 
-    /* FIXME: should not depend on the boot CPU bring the first child */
+    /* Look up which CPU we are running on right now.  */
+    result = of_getprop(bof_chosen, "cpu", &bootcpu, sizeof (bootcpu));
+    if (result == OF_FAILURE)
+        of_panic("Failed to look up boot cpu\n");
+
     cpu = of_getpeer(cpu);
-    while (cpu > 0) {
-        of_start_cpu(cpu, (ulong)spin_start, 0);
+
+    /* We want a continuous logical cpu number space.  */
+    cpu_set(0, cpu_present_map);
+    cpu_set(0, cpu_online_map);
+
+    /* Spin up all CPUS, even if there are more than NR_CPUS, because
+     * Open Firmware has them spinning on cache lines which will
+     * eventually be scrubbed, which could lead to random CPU activation.
+     */
+    for (logical = 1; cpu > 0; logical++) {
+        unsigned int cpuid, ping, pong;
+        unsigned long now, then, timeout;
+
+        if (cpu == bootcpu) {
+            of_printf("skipping boot cpu!\n");
+            continue;
+        }
+
+        result = of_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
+        if (result == OF_FAILURE)
+            of_panic("cpuid lookup failed\n");
+
+        of_printf("spinning up secondary processor #%d: ", logical);
+
+        __spin_ack = ~0x0;
+        ping = __spin_ack;
+        pong = __spin_ack;
+        of_printf("ping = 0x%x: ", ping);
+
+        mb();
+        result = of_start_cpu(cpu, (ulong)spin_start, logical);
+        if (result == OF_FAILURE)
+            of_panic("start cpu failed\n");
+
+        /* We will give the secondary processor five seconds to reply.  */
+        then = mftb();
+        timeout = then + (5 * timebase_freq);
+
+        do {
+            now = mftb();
+            if (now >= timeout) {
+                of_printf("BROKEN: ");
+                break;
+            }
+
+            mb();
+            pong = __spin_ack;
+        } while (pong == ping);
+        of_printf("pong = 0x%x\n", pong);
+
+        if (pong != ping)
+            cpu_set(logical, cpu_present_map);
+
         cpu = of_getpeer(cpu);
     }
     return 1;
@@ -1031,6 +1089,7 @@ multiboot_info_t __init *boot_of_init(
     boot_of_rtas();
 
     /* end of OF */
+    of_printf("Quiescing Open Firmware ...\n");
     of_call("quiesce", 0, 0, NULL);
 
     return &mbi;
diff -r 8cc27cb8516b -r 1ef82dd7f66b xen/arch/powerpc/powerpc64/exceptions.S
--- a/xen/arch/powerpc/powerpc64/exceptions.S   Mon Aug 21 10:04:37 2006 -0400
+++ b/xen/arch/powerpc/powerpc64/exceptions.S   Tue Aug 22 09:53:34 2006 -0400
@@ -514,6 +514,43 @@ _GLOBAL(sleep)
     mtmsrd r3
     blr
 
+/* The primary processor issues a firmware call to spin us up at this
+ * address, passing our CPU number in r3.  We only need a function
+ * entry point instead of a descriptor since this is never called from
+ * C code.
+ */    
     .globl spin_start
 spin_start:
+    /* Write our processor number as an acknowledgment that we're alive.  */
+    LOADADDR(r14, __spin_ack)
+    stw r3, 0(r14)
+    sync
+    /* If NR_CPUS is too small, we should just spin forever.  */
+    LOADADDR(r15, NR_CPUS)
+    cmpd r3, r15
+    blt 2f     
     b .
+    /* Find our index in the array of processor_area struct pointers.  */
+2:  LOADADDR(r14, global_cpu_table)
+    muli r15, r3, 8
+    add r14, r14, r15
+    /* Spin until the pointer for our processor goes valid.  */
+1:  ld r15, 0(r14)
+    cmpldi r15, 0
+    beq 1b
+    /* Dereference the pointer and load our stack pointer.  */
+    isync
+    ld r1, PAREA_stack(r15)
+    li r14, STACK_FRAME_OVERHEAD
+    sub r1, r1, r14
+    /* Load up the TOC and entry point for the C function to be called.  */
+    LOADADDR(r14, secondary_cpu_init)
+    ld r2, 8(r14)
+    ld r11, 0(r14)
+    mtctr r11
+    /* Warning: why do we need this synchronizing instruction on 970FX?  */
+    isync
+    /* Jump into C code now.  */
+    bctrl
+    nop
+    b .
diff -r 8cc27cb8516b -r 1ef82dd7f66b xen/arch/powerpc/powerpc64/ppc970.c
--- a/xen/arch/powerpc/powerpc64/ppc970.c       Mon Aug 21 10:04:37 2006 -0400
+++ b/xen/arch/powerpc/powerpc64/ppc970.c       Tue Aug 22 09:53:34 2006 -0400
@@ -31,6 +31,8 @@
 
 #undef SERIALIZE
 
+extern volatile struct processor_area * volatile global_cpu_table[];
+
 unsigned int cpu_rma_order(void)
 {
     /* XXX what about non-HV mode? */
@@ -38,18 +40,15 @@ unsigned int cpu_rma_order(void)
     return rma_log_size - PAGE_SHIFT;
 }
 
-void cpu_initialize(void)
+void cpu_initialize(int cpuid)
 {
-    ulong stack;
+    ulong r1, r2;
+    __asm__ __volatile__ ("mr %0, 1" : "=r" (r1));
+    __asm__ __volatile__ ("mr %0, 2" : "=r" (r2));
 
-    parea = xmalloc(struct processor_area);
+    /* This is SMP safe because the compiler must use r13 for it.  */
+    parea = global_cpu_table[cpuid];
     ASSERT(parea != NULL);
-
-    stack = (ulong)alloc_xenheap_pages(STACK_ORDER);
-
-    ASSERT(stack != 0);
-    parea->hyp_stack_base = (void *)(stack + STACK_SIZE);
-    printk("stack is here: %p\n", parea->hyp_stack_base);
 
     mthsprg0((ulong)parea); /* now ready for exceptions */
 
@@ -79,7 +78,10 @@ void cpu_initialize(void)
     s |= 1UL << (63-3);     /* ser-gp */
     hid0.word |= s;
 #endif
-    printk("hid0: 0x%016lx\n", hid0.word);
+
+    printk("CPU #%d: Hello World! SP = %lx TOC = %lx HID0 = %lx\n", 
+           smp_processor_id(), r1, r2, hid0.word);
+
     mthid0(hid0.word);
 
     union hid1 hid1;
diff -r 8cc27cb8516b -r 1ef82dd7f66b xen/arch/powerpc/setup.c
--- a/xen/arch/powerpc/setup.c  Mon Aug 21 10:04:37 2006 -0400
+++ b/xen/arch/powerpc/setup.c  Tue Aug 22 09:53:34 2006 -0400
@@ -54,6 +54,14 @@ int opt_earlygdb = 0;
 int opt_earlygdb = 0;
 boolean_param("earlygdb", opt_earlygdb);
 
+/* opt_nosmp: If true, secondary processors are ignored. */
+static int opt_nosmp = 0;
+boolean_param("nosmp", opt_nosmp);
+
+/* maxcpus: maximum number of CPUs to activate. */
+static unsigned int max_cpus = NR_CPUS;
+integer_param("maxcpus", max_cpus);
+
 u32 tlbflush_clock = 1U;
 DEFINE_PER_CPU(u32, tlbflush_time);
 
@@ -65,6 +73,7 @@ ulong oftree_end;
 
 cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
 cpumask_t cpu_online_map; /* missing ifdef in schedule.c */
+cpumask_t cpu_present_map;
 
 /* XXX get this from ISA node in device tree */
 ulong isa_io_base;
@@ -75,6 +84,8 @@ extern void idle_loop(void);
 
 /* move us to a header file */
 extern void initialize_keytable(void);
+
+volatile struct processor_area * volatile global_cpu_table[NR_CPUS];
 
 int is_kernel_text(unsigned long addr)
 {
@@ -210,6 +221,53 @@ static ulong free_xenheap(ulong start, u
         init_xenheap_pages(start, end);
     }
     return ALIGN_UP(end, PAGE_SIZE);
+}
+
+static void init_parea(int cpuid)
+{
+    /* Be careful not to shadow the global variable.  */
+    volatile struct processor_area *pa;
+    void *stack;
+
+    pa = xmalloc(struct processor_area);
+    if (pa == NULL)
+        panic("%s: failed to allocate parea for cpu #%d\n", __func__, cpuid);
+
+    stack = alloc_xenheap_pages(STACK_ORDER);
+    if (stack == NULL)
+        panic("%s: failed to allocate stack (order %d) for cpu #%d\n", 
+              __func__, STACK_ORDER, cpuid);
+
+    pa->whoami = cpuid;
+    pa->hyp_stack_base = (void *)((ulong)stack + STACK_SIZE);
+
+    /* This store has the effect of invoking secondary_cpu_init.  */
+    global_cpu_table[cpuid] = pa;
+    mb();
+}
+
+static int kick_secondary_cpus(int maxcpus)
+{
+    int cpuid;
+
+    for_each_present_cpu(cpuid) {
+        if (cpuid == 0)
+            continue;
+        if (cpuid >= maxcpus)
+            break;
+        init_parea(cpuid);
+        cpu_set(cpuid, cpu_online_map);
+    }
+
+    return 0;
+}
+
+/* This is the first C code that secondary processors invoke.  */
+int secondary_cpu_init(int cpuid, unsigned long r4);
+int secondary_cpu_init(int cpuid, unsigned long r4)
+{
+    cpu_initialize(cpuid);
+    while(1);
 }
 
 static void __init __start_xen(multiboot_info_t *mbi)
@@ -361,13 +419,22 @@ static void __init __start_xen(multiboot
 
     percpu_init_areas();
 
-    cpu_initialize();
+    init_parea(0);
+    cpu_initialize(0);
 
 #ifdef CONFIG_GDB
     initialise_gdb();
     if (opt_earlygdb)
         debugger_trap_immediate();
 #endif
+
+    /* Deal with secondary processors.  */
+    if (opt_nosmp) {
+        printk("nosmp: leaving secondary processors spinning forever\n");
+    } else {
+        printk("spinning up at most %d total processors ...\n", max_cpus);
+        kick_secondary_cpus(max_cpus);
+    }
 
     start_of_day();
 
@@ -445,6 +512,8 @@ void arch_get_xen_caps(xen_capabilities_
 void arch_get_xen_caps(xen_capabilities_info_t info)
 {
 }
+
+
 
 /*
  * Local variables:
diff -r 8cc27cb8516b -r 1ef82dd7f66b xen/include/asm-powerpc/config.h
--- a/xen/include/asm-powerpc/config.h  Mon Aug 21 10:04:37 2006 -0400
+++ b/xen/include/asm-powerpc/config.h  Tue Aug 22 09:53:34 2006 -0400
@@ -51,7 +51,7 @@ extern char __bss_start[];
 #define CONFIG_GDB 1
 #define CONFIG_SMP 1
 #define CONFIG_PCI 1
-#define NR_CPUS 1
+#define NR_CPUS 16
 
 #ifndef ELFSIZE
 #define ELFSIZE 64
diff -r 8cc27cb8516b -r 1ef82dd7f66b xen/include/asm-powerpc/current.h
--- a/xen/include/asm-powerpc/current.h Mon Aug 21 10:04:37 2006 -0400
+++ b/xen/include/asm-powerpc/current.h Tue Aug 22 09:53:34 2006 -0400
@@ -27,7 +27,7 @@
 
 struct vcpu;
 
-register struct processor_area *parea asm("r13");
+register volatile struct processor_area *parea asm("r13");
 
 static inline struct vcpu *get_current(void)
 {
diff -r 8cc27cb8516b -r 1ef82dd7f66b 
xen/include/asm-powerpc/powerpc64/procarea.h
--- a/xen/include/asm-powerpc/powerpc64/procarea.h      Mon Aug 21 10:04:37 
2006 -0400
+++ b/xen/include/asm-powerpc/powerpc64/procarea.h      Tue Aug 22 09:53:34 
2006 -0400
@@ -28,6 +28,7 @@ struct gdb_state;
 
 struct processor_area
 {
+    unsigned int whoami;
     struct vcpu *cur_vcpu;
     void *hyp_stack_base;
     ulong saved_regs[2];
diff -r 8cc27cb8516b -r 1ef82dd7f66b xen/include/asm-powerpc/processor.h
--- a/xen/include/asm-powerpc/processor.h       Mon Aug 21 10:04:37 2006 -0400
+++ b/xen/include/asm-powerpc/processor.h       Tue Aug 22 09:53:34 2006 -0400
@@ -40,7 +40,7 @@ extern void show_registers(struct cpu_us
 extern void show_registers(struct cpu_user_regs *);
 extern void show_execution_state(struct cpu_user_regs *);
 extern unsigned int cpu_rma_order(void);
-extern void cpu_initialize(void);
+extern void cpu_initialize(int cpuid);
 extern void cpu_init_vcpu(struct vcpu *);
 extern void save_cpu_sprs(struct vcpu *);
 extern void load_cpu_sprs(struct vcpu *);
diff -r 8cc27cb8516b -r 1ef82dd7f66b xen/include/asm-powerpc/smp.h
--- a/xen/include/asm-powerpc/smp.h     Mon Aug 21 10:04:37 2006 -0400
+++ b/xen/include/asm-powerpc/smp.h     Tue Aug 22 09:53:34 2006 -0400
@@ -28,8 +28,8 @@ extern int smp_num_siblings;
 
 /* revisit when we support SMP */
 #define get_hard_smp_processor_id(i) i
-#define hard_smp_processor_id() 0
-#define raw_smp_processor_id() 0
+#define raw_smp_processor_id() (parea->whoami)
+#define hard_smp_processor_id() raw_smp_processor_id()
 extern cpumask_t cpu_sibling_map[];
 extern cpumask_t cpu_core_map[];
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.