ia64/xen-unstable

changeset 11373:1ef82dd7f66b

[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@us.ibm.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
author Jimi Xenidis <jimix@watson.ibm.com>
date Tue Aug 22 09:53:34 2006 -0400 (2006-08-22)
parents 8cc27cb8516b
children 05b2b8b61cca
files xen/arch/powerpc/boot_of.c xen/arch/powerpc/powerpc64/exceptions.S xen/arch/powerpc/powerpc64/ppc970.c xen/arch/powerpc/setup.c xen/include/asm-powerpc/config.h xen/include/asm-powerpc/current.h xen/include/asm-powerpc/powerpc64/procarea.h xen/include/asm-powerpc/processor.h xen/include/asm-powerpc/smp.h
line diff
     1.1 --- a/xen/arch/powerpc/boot_of.c	Mon Aug 21 10:04:37 2006 -0400
     1.2 +++ b/xen/arch/powerpc/boot_of.c	Tue Aug 22 09:53:34 2006 -0400
     1.3 @@ -32,6 +32,9 @@
     1.4  #include "exceptions.h"
     1.5  #include "of-devtree.h"
     1.6  
     1.7 +/* Secondary processors use this for handshaking with main processor.  */
     1.8 +volatile unsigned int __spin_ack;
     1.9 +
    1.10  static ulong of_vec;
    1.11  static ulong of_msr;
    1.12  static int of_out;
    1.13 @@ -955,7 +958,7 @@ static void boot_of_module(ulong r3, ulo
    1.14  static int __init boot_of_cpus(void)
    1.15  {
    1.16      int cpus;
    1.17 -    int cpu;
    1.18 +    int cpu, bootcpu, logical;
    1.19      int result;
    1.20      u32 cpu_clock[2];
    1.21  
    1.22 @@ -980,10 +983,65 @@ static int __init boot_of_cpus(void)
    1.23      cpu_khz /= 1000;
    1.24      of_printf("OF: clock-frequency = %ld KHz\n", cpu_khz);
    1.25  
    1.26 -    /* FIXME: should not depend on the boot CPU bring the first child */
    1.27 +    /* Look up which CPU we are running on right now.  */
    1.28 +    result = of_getprop(bof_chosen, "cpu", &bootcpu, sizeof (bootcpu));
    1.29 +    if (result == OF_FAILURE)
    1.30 +        of_panic("Failed to look up boot cpu\n");
    1.31 +
    1.32      cpu = of_getpeer(cpu);
    1.33 -    while (cpu > 0) {
    1.34 -        of_start_cpu(cpu, (ulong)spin_start, 0);
    1.35 +
    1.36 +    /* We want a continuous logical cpu number space.  */
    1.37 +    cpu_set(0, cpu_present_map);
    1.38 +    cpu_set(0, cpu_online_map);
    1.39 +
    1.40 +    /* Spin up all CPUS, even if there are more than NR_CPUS, because
    1.41 +     * Open Firmware has them spinning on cache lines which will
    1.42 +     * eventually be scrubbed, which could lead to random CPU activation.
    1.43 +     */
    1.44 +    for (logical = 1; cpu > 0; logical++) {
    1.45 +        unsigned int cpuid, ping, pong;
    1.46 +        unsigned long now, then, timeout;
    1.47 +
    1.48 +        if (cpu == bootcpu) {
    1.49 +            of_printf("skipping boot cpu!\n");
    1.50 +            continue;
    1.51 +        }
    1.52 +
    1.53 +        result = of_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
    1.54 +        if (result == OF_FAILURE)
    1.55 +            of_panic("cpuid lookup failed\n");
    1.56 +
    1.57 +        of_printf("spinning up secondary processor #%d: ", logical);
    1.58 +
    1.59 +        __spin_ack = ~0x0;
    1.60 +        ping = __spin_ack;
    1.61 +        pong = __spin_ack;
    1.62 +        of_printf("ping = 0x%x: ", ping);
    1.63 +
    1.64 +        mb();
    1.65 +        result = of_start_cpu(cpu, (ulong)spin_start, logical);
    1.66 +        if (result == OF_FAILURE)
    1.67 +            of_panic("start cpu failed\n");
    1.68 +
    1.69 +        /* We will give the secondary processor five seconds to reply.  */
    1.70 +        then = mftb();
    1.71 +        timeout = then + (5 * timebase_freq);
    1.72 +
    1.73 +        do {
    1.74 +            now = mftb();
    1.75 +            if (now >= timeout) {
    1.76 +                of_printf("BROKEN: ");
    1.77 +                break;
    1.78 +            }
    1.79 +
    1.80 +            mb();
    1.81 +            pong = __spin_ack;
    1.82 +        } while (pong == ping);
    1.83 +        of_printf("pong = 0x%x\n", pong);
    1.84 +
    1.85 +        if (pong != ping)
    1.86 +            cpu_set(logical, cpu_present_map);
    1.87 +
    1.88          cpu = of_getpeer(cpu);
    1.89      }
    1.90      return 1;
    1.91 @@ -1031,6 +1089,7 @@ multiboot_info_t __init *boot_of_init(
    1.92      boot_of_rtas();
    1.93  
    1.94      /* end of OF */
    1.95 +    of_printf("Quiescing Open Firmware ...\n");
    1.96      of_call("quiesce", 0, 0, NULL);
    1.97  
    1.98      return &mbi;
     2.1 --- a/xen/arch/powerpc/powerpc64/exceptions.S	Mon Aug 21 10:04:37 2006 -0400
     2.2 +++ b/xen/arch/powerpc/powerpc64/exceptions.S	Tue Aug 22 09:53:34 2006 -0400
     2.3 @@ -514,6 +514,43 @@ 1:
     2.4      mtmsrd r3
     2.5      blr
     2.6  
     2.7 +/* The primary processor issues a firmware call to spin us up at this
     2.8 + * address, passing our CPU number in r3.  We only need a function
     2.9 + * entry point instead of a descriptor since this is never called from
    2.10 + * C code.
    2.11 + */	
    2.12      .globl spin_start
    2.13  spin_start:
    2.14 +    /* Write our processor number as an acknowledgment that we're alive.  */
    2.15 +    LOADADDR(r14, __spin_ack)
    2.16 +    stw r3, 0(r14)
    2.17 +    sync
    2.18 +    /* If NR_CPUS is too small, we should just spin forever.  */
    2.19 +    LOADADDR(r15, NR_CPUS)
    2.20 +    cmpd r3, r15
    2.21 +    blt 2f	
    2.22      b .
    2.23 +    /* Find our index in the array of processor_area struct pointers.  */
    2.24 +2:  LOADADDR(r14, global_cpu_table)
    2.25 +    muli r15, r3, 8
    2.26 +    add r14, r14, r15
    2.27 +    /* Spin until the pointer for our processor goes valid.  */
    2.28 +1:  ld r15, 0(r14)
    2.29 +    cmpldi r15, 0
    2.30 +    beq 1b
    2.31 +    /* Dereference the pointer and load our stack pointer.  */
    2.32 +    isync
    2.33 +    ld r1, PAREA_stack(r15)
    2.34 +    li r14, STACK_FRAME_OVERHEAD
    2.35 +    sub r1, r1, r14
    2.36 +    /* Load up the TOC and entry point for the C function to be called.  */
    2.37 +    LOADADDR(r14, secondary_cpu_init)
    2.38 +    ld r2, 8(r14)
    2.39 +    ld r11, 0(r14)
    2.40 +    mtctr r11
    2.41 +    /* Warning: why do we need this synchronizing instruction on 970FX?  */
    2.42 +    isync
    2.43 +    /* Jump into C code now.  */
    2.44 +    bctrl
    2.45 +    nop
    2.46 +    b .
     3.1 --- a/xen/arch/powerpc/powerpc64/ppc970.c	Mon Aug 21 10:04:37 2006 -0400
     3.2 +++ b/xen/arch/powerpc/powerpc64/ppc970.c	Tue Aug 22 09:53:34 2006 -0400
     3.3 @@ -31,6 +31,8 @@
     3.4  
     3.5  #undef SERIALIZE
     3.6  
     3.7 +extern volatile struct processor_area * volatile global_cpu_table[];
     3.8 +
     3.9  unsigned int cpu_rma_order(void)
    3.10  {
    3.11      /* XXX what about non-HV mode? */
    3.12 @@ -38,19 +40,16 @@ unsigned int cpu_rma_order(void)
    3.13      return rma_log_size - PAGE_SHIFT;
    3.14  }
    3.15  
    3.16 -void cpu_initialize(void)
    3.17 +void cpu_initialize(int cpuid)
    3.18  {
    3.19 -    ulong stack;
    3.20 +    ulong r1, r2;
    3.21 +    __asm__ __volatile__ ("mr %0, 1" : "=r" (r1));
    3.22 +    __asm__ __volatile__ ("mr %0, 2" : "=r" (r2));
    3.23  
    3.24 -    parea = xmalloc(struct processor_area);
    3.25 +    /* This is SMP safe because the compiler must use r13 for it.  */
    3.26 +    parea = global_cpu_table[cpuid];
    3.27      ASSERT(parea != NULL);
    3.28  
    3.29 -    stack = (ulong)alloc_xenheap_pages(STACK_ORDER);
    3.30 -
    3.31 -    ASSERT(stack != 0);
    3.32 -    parea->hyp_stack_base = (void *)(stack + STACK_SIZE);
    3.33 -    printk("stack is here: %p\n", parea->hyp_stack_base);
    3.34 -
    3.35      mthsprg0((ulong)parea); /* now ready for exceptions */
    3.36  
    3.37      /* Set decrementers for 1 second to keep them out of the way during
    3.38 @@ -79,7 +78,10 @@ void cpu_initialize(void)
    3.39      s |= 1UL << (63-3);     /* ser-gp */
    3.40      hid0.word |= s;
    3.41  #endif
    3.42 -    printk("hid0: 0x%016lx\n", hid0.word);
    3.43 +
    3.44 +    printk("CPU #%d: Hello World! SP = %lx TOC = %lx HID0 = %lx\n", 
    3.45 +           smp_processor_id(), r1, r2, hid0.word);
    3.46 +
    3.47      mthid0(hid0.word);
    3.48  
    3.49      union hid1 hid1;
     4.1 --- a/xen/arch/powerpc/setup.c	Mon Aug 21 10:04:37 2006 -0400
     4.2 +++ b/xen/arch/powerpc/setup.c	Tue Aug 22 09:53:34 2006 -0400
     4.3 @@ -54,6 +54,14 @@ boolean_param("noht", opt_noht);
     4.4  int opt_earlygdb = 0;
     4.5  boolean_param("earlygdb", opt_earlygdb);
     4.6  
     4.7 +/* opt_nosmp: If true, secondary processors are ignored. */
     4.8 +static int opt_nosmp = 0;
     4.9 +boolean_param("nosmp", opt_nosmp);
    4.10 +
    4.11 +/* maxcpus: maximum number of CPUs to activate. */
    4.12 +static unsigned int max_cpus = NR_CPUS;
    4.13 +integer_param("maxcpus", max_cpus);
    4.14 +
    4.15  u32 tlbflush_clock = 1U;
    4.16  DEFINE_PER_CPU(u32, tlbflush_time);
    4.17  
    4.18 @@ -65,6 +73,7 @@ ulong oftree_end;
    4.19  
    4.20  cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
    4.21  cpumask_t cpu_online_map; /* missing ifdef in schedule.c */
    4.22 +cpumask_t cpu_present_map;
    4.23  
    4.24  /* XXX get this from ISA node in device tree */
    4.25  ulong isa_io_base;
    4.26 @@ -76,6 +85,8 @@ extern void idle_loop(void);
    4.27  /* move us to a header file */
    4.28  extern void initialize_keytable(void);
    4.29  
    4.30 +volatile struct processor_area * volatile global_cpu_table[NR_CPUS];
    4.31 +
    4.32  int is_kernel_text(unsigned long addr)
    4.33  {
    4.34      if (addr >= (unsigned long) &_start &&
    4.35 @@ -212,6 +223,53 @@ static ulong free_xenheap(ulong start, u
    4.36      return ALIGN_UP(end, PAGE_SIZE);
    4.37  }
    4.38  
    4.39 +static void init_parea(int cpuid)
    4.40 +{
    4.41 +    /* Be careful not to shadow the global variable.  */
    4.42 +    volatile struct processor_area *pa;
    4.43 +    void *stack;
    4.44 +
    4.45 +    pa = xmalloc(struct processor_area);
    4.46 +    if (pa == NULL)
    4.47 +        panic("%s: failed to allocate parea for cpu #%d\n", __func__, cpuid);
    4.48 +
    4.49 +    stack = alloc_xenheap_pages(STACK_ORDER);
    4.50 +    if (stack == NULL)
    4.51 +        panic("%s: failed to allocate stack (order %d) for cpu #%d\n", 
    4.52 +              __func__, STACK_ORDER, cpuid);
    4.53 +
    4.54 +    pa->whoami = cpuid;
    4.55 +    pa->hyp_stack_base = (void *)((ulong)stack + STACK_SIZE);
    4.56 +
    4.57 +    /* This store has the effect of invoking secondary_cpu_init.  */
    4.58 +    global_cpu_table[cpuid] = pa;
    4.59 +    mb();
    4.60 +}
    4.61 +
    4.62 +static int kick_secondary_cpus(int maxcpus)
    4.63 +{
    4.64 +    int cpuid;
    4.65 +
    4.66 +    for_each_present_cpu(cpuid) {
    4.67 +        if (cpuid == 0)
    4.68 +            continue;
    4.69 +        if (cpuid >= maxcpus)
    4.70 +            break;
    4.71 +        init_parea(cpuid);
    4.72 +        cpu_set(cpuid, cpu_online_map);
    4.73 +    }
    4.74 +
    4.75 +    return 0;
    4.76 +}
    4.77 +
    4.78 +/* This is the first C code that secondary processors invoke.  */
    4.79 +int secondary_cpu_init(int cpuid, unsigned long r4);
    4.80 +int secondary_cpu_init(int cpuid, unsigned long r4)
    4.81 +{
    4.82 +    cpu_initialize(cpuid);
    4.83 +    while(1);
    4.84 +}
    4.85 +
    4.86  static void __init __start_xen(multiboot_info_t *mbi)
    4.87  {
    4.88      char *cmdline;
    4.89 @@ -361,7 +419,8 @@ static void __init __start_xen(multiboot
    4.90  
    4.91      percpu_init_areas();
    4.92  
    4.93 -    cpu_initialize();
    4.94 +    init_parea(0);
    4.95 +    cpu_initialize(0);
    4.96  
    4.97  #ifdef CONFIG_GDB
    4.98      initialise_gdb();
    4.99 @@ -369,6 +428,14 @@ static void __init __start_xen(multiboot
   4.100          debugger_trap_immediate();
   4.101  #endif
   4.102  
   4.103 +    /* Deal with secondary processors.  */
   4.104 +    if (opt_nosmp) {
   4.105 +        printk("nosmp: leaving secondary processors spinning forever\n");
   4.106 +    } else {
   4.107 +        printk("spinning up at most %d total processors ...\n", max_cpus);
   4.108 +        kick_secondary_cpus(max_cpus);
   4.109 +    }
   4.110 +
   4.111      start_of_day();
   4.112  
   4.113      /* Create initial domain 0. */
   4.114 @@ -446,6 +513,8 @@ void arch_get_xen_caps(xen_capabilities_
   4.115  {
   4.116  }
   4.117  
   4.118 +
   4.119 +
   4.120  /*
   4.121   * Local variables:
   4.122   * mode: C
     5.1 --- a/xen/include/asm-powerpc/config.h	Mon Aug 21 10:04:37 2006 -0400
     5.2 +++ b/xen/include/asm-powerpc/config.h	Tue Aug 22 09:53:34 2006 -0400
     5.3 @@ -51,7 +51,7 @@ extern char __bss_start[];
     5.4  #define CONFIG_GDB 1
     5.5  #define CONFIG_SMP 1
     5.6  #define CONFIG_PCI 1
     5.7 -#define NR_CPUS 1
     5.8 +#define NR_CPUS 16
     5.9  
    5.10  #ifndef ELFSIZE
    5.11  #define ELFSIZE 64
     6.1 --- a/xen/include/asm-powerpc/current.h	Mon Aug 21 10:04:37 2006 -0400
     6.2 +++ b/xen/include/asm-powerpc/current.h	Tue Aug 22 09:53:34 2006 -0400
     6.3 @@ -27,7 +27,7 @@
     6.4  
     6.5  struct vcpu;
     6.6  
     6.7 -register struct processor_area *parea asm("r13");
     6.8 +register volatile struct processor_area *parea asm("r13");
     6.9  
    6.10  static inline struct vcpu *get_current(void)
    6.11  {
     7.1 --- a/xen/include/asm-powerpc/powerpc64/procarea.h	Mon Aug 21 10:04:37 2006 -0400
     7.2 +++ b/xen/include/asm-powerpc/powerpc64/procarea.h	Tue Aug 22 09:53:34 2006 -0400
     7.3 @@ -28,6 +28,7 @@ struct gdb_state;
     7.4  
     7.5  struct processor_area
     7.6  {
     7.7 +    unsigned int whoami;
     7.8      struct vcpu *cur_vcpu;
     7.9      void *hyp_stack_base;
    7.10      ulong saved_regs[2];
     8.1 --- a/xen/include/asm-powerpc/processor.h	Mon Aug 21 10:04:37 2006 -0400
     8.2 +++ b/xen/include/asm-powerpc/processor.h	Tue Aug 22 09:53:34 2006 -0400
     8.3 @@ -40,7 +40,7 @@ struct cpu_user_regs;
     8.4  extern void show_registers(struct cpu_user_regs *);
     8.5  extern void show_execution_state(struct cpu_user_regs *);
     8.6  extern unsigned int cpu_rma_order(void);
     8.7 -extern void cpu_initialize(void);
     8.8 +extern void cpu_initialize(int cpuid);
     8.9  extern void cpu_init_vcpu(struct vcpu *);
    8.10  extern void save_cpu_sprs(struct vcpu *);
    8.11  extern void load_cpu_sprs(struct vcpu *);
     9.1 --- a/xen/include/asm-powerpc/smp.h	Mon Aug 21 10:04:37 2006 -0400
     9.2 +++ b/xen/include/asm-powerpc/smp.h	Tue Aug 22 09:53:34 2006 -0400
     9.3 @@ -28,8 +28,8 @@ extern int smp_num_siblings;
     9.4  
     9.5  /* revisit when we support SMP */
     9.6  #define get_hard_smp_processor_id(i) i
     9.7 -#define hard_smp_processor_id() 0
     9.8 -#define raw_smp_processor_id() 0
     9.9 +#define raw_smp_processor_id() (parea->whoami)
    9.10 +#define hard_smp_processor_id() raw_smp_processor_id()
    9.11  extern cpumask_t cpu_sibling_map[];
    9.12  extern cpumask_t cpu_core_map[];
    9.13