aboutsummaryrefslogtreecommitdiffstats
path: root/xen
diff options
context:
space:
mode:
authorTim Deegan <tim@xen.org>2012-03-13 15:10:56 +0000
committerTim Deegan <tim@xen.org>2012-03-13 15:10:56 +0000
commitb8bac01f1a0e3583b9815c331763cf068175aa11 (patch)
treefcfa7b35122c95107f7aeee8cd6df2a6714c8c35 /xen
parent9e5e386e7c90669709dbc4c2f6cb5ab9e483c6d7 (diff)
downloadxen-b8bac01f1a0e3583b9815c331763cf068175aa11.tar.gz
xen-b8bac01f1a0e3583b9815c331763cf068175aa11.tar.bz2
xen-b8bac01f1a0e3583b9815c331763cf068175aa11.zip
arm: Boot secondary CPUs into C
Secondary CPUs come up directly onto the stack of the appropriate idle vcpu; the boot CPU starts on a statically allocated stack and switches over to the idle vcpu's one once the idle domain has been built. Signed-off-by: Tim Deegan <tim@xen.org> Committed-by: Ian Campbell <ian.campbell@citrix.com>
Diffstat (limited to 'xen')
-rw-r--r--xen/arch/arm/gic.c10
-rw-r--r--xen/arch/arm/gic.h2
-rw-r--r--xen/arch/arm/head.S14
-rw-r--r--xen/arch/arm/setup.c9
-rw-r--r--xen/arch/arm/smpboot.c76
-rw-r--r--xen/include/asm-arm/current.h8
6 files changed, 100 insertions, 19 deletions
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 9125685e51..6a4ebb1a47 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -245,7 +245,6 @@ static void __cpuinit gic_hyp_init(void)
vtr = GICH[GICH_VTR];
nr_lrs = (vtr & GICH_VTR_NRLRGS) + 1;
- printk("GICH: %d list registers available\n", nr_lrs);
GICH[GICH_HCR] = GICH_HCR_EN;
GICH[GICH_MISR] = GICH_MISR_EOI;
@@ -278,6 +277,15 @@ int __init gic_init(void)
return gic.cpus;
}
+/* Set up the per-CPU parts of the GIC for a secondary CPU */
+void __cpuinit gic_init_secondary_cpu(void)
+{
+ spin_lock(&gic.lock);
+ gic_cpu_init();
+ gic_hyp_init();
+ spin_unlock(&gic.lock);
+}
+
void gic_route_irqs(void)
{
/* XXX should get these from DT */
diff --git a/xen/arch/arm/gic.h b/xen/arch/arm/gic.h
index d33995755d..c79ba33c1d 100644
--- a/xen/arch/arm/gic.h
+++ b/xen/arch/arm/gic.h
@@ -140,6 +140,8 @@ extern int gic_route_irq_to_guest(struct domain *d, unsigned int irq,
extern void gic_interrupt(struct cpu_user_regs *regs, int is_fiq);
/* Bring up the interrupt controller, and report # cpus attached */
extern int gic_init(void);
+/* Bring up a secondary CPU's per-CPU GIC interface */
+extern void gic_init_secondary_cpu(void);
/* setup the gic virtual interface for a guest */
extern void gicv_setup(struct domain *d);
#endif
diff --git a/xen/arch/arm/head.S b/xen/arch/arm/head.S
index 22bc8ece6f..606ae66fff 100644
--- a/xen/arch/arm/head.S
+++ b/xen/arch/arm/head.S
@@ -307,17 +307,23 @@ paging:
* and brought up the memory allocator, non-boot CPUs can get their
* own stacks and enter C. */
1: wfe
- b 1b
+ dsb
+ ldr r0, =smp_up_cpu
+ ldr r1, [r0] /* Which CPU is being booted? */
+ teq r1, r12 /* Is it us? */
+ bne 1b
launch:
- ldr sp, =init_stack /* Supply a stack */
+ ldr r0, =init_stack /* Find the boot-time stack */
+ ldr sp, [r0]
add sp, #STACK_SIZE /* (which grows down from the top). */
sub sp, #CPUINFO_sizeof /* Make room for CPU save record */
mov r0, r10 /* Marshal args: - phys_offset */
mov r1, r7 /* - machine type */
mov r2, r8 /* - ATAG address */
- mov r3, r12 /* - CPU ID */
- b start_xen /* and disappear into the land of C */
+ movs r3, r12 /* - CPU ID */
+ beq start_xen /* and disappear into the land of C */
+ b start_secondary /* (to the appropriate entry point) */
/* Fail-stop
* r0: string explaining why */
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 8d919d182b..cd88a1bcd7 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -38,9 +38,6 @@
#include <asm/setup.h>
#include "gic.h"
-/* Xen stack for bringing up the first CPU. */
-unsigned char __initdata init_stack[STACK_SIZE] __attribute__((__aligned__(STACK_SIZE)));
-
extern const char __init_begin[], __init_end[], __bss_start[];
/* Spinlock for serializing CPU bringup */
@@ -286,7 +283,11 @@ void __init start_xen(unsigned long boot_phys_offset,
domain_unpause_by_systemcontroller(dom0);
- reset_stack_and_jump(init_done);
+ /* Switch on to the dynamically allocated stack for the idle vcpu
+ * since the static one we're running on is about to be freed. */
+ memcpy(idle_vcpu[0]->arch.cpu_info, get_cpu_info(),
+ sizeof(struct cpu_info));
+ switch_stack_and_jump(idle_vcpu[0]->arch.cpu_info, init_done);
}
void arch_get_xen_caps(xen_capabilities_info_t *info)
diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
index b4f25eeb71..8119ef2439 100644
--- a/xen/arch/arm/smpboot.c
+++ b/xen/arch/arm/smpboot.c
@@ -16,10 +16,15 @@
* GNU General Public License for more details.
*/
+#include <xen/cpu.h>
#include <xen/cpumask.h>
-#include <xen/smp.h>
-#include <xen/init.h>
#include <xen/errno.h>
+#include <xen/init.h>
+#include <xen/mm.h>
+#include <xen/sched.h>
+#include <xen/smp.h>
+#include <xen/softirq.h>
+#include "gic.h"
cpumask_t cpu_online_map;
EXPORT_SYMBOL(cpu_online_map);
@@ -28,6 +33,13 @@ EXPORT_SYMBOL(cpu_online_map);
cpumask_t cpu_possible_map;
EXPORT_SYMBOL(cpu_possible_map);
+/* Xen stack for bringing up the first CPU. */
+static unsigned char __initdata cpu0_boot_stack[STACK_SIZE]
+ __attribute__((__aligned__(STACK_SIZE)));
+
+/* Pointer to the stack, used by head.S when entering C */
+unsigned char *init_stack = cpu0_boot_stack;
+
void __init
smp_prepare_cpus (unsigned int max_cpus)
{
@@ -43,11 +55,43 @@ smp_prepare_cpus (unsigned int max_cpus)
cpumask_copy(&cpu_present_map, &cpu_possible_map);
}
-/* Bring up a non-boot CPU */
-int __cpu_up(unsigned int cpu)
+/* Shared state for coordinating CPU bringup */
+unsigned long smp_up_cpu = 0;
+
+/* Boot the current CPU */
+void __cpuinit start_secondary(unsigned long boot_phys_offset,
+ unsigned long arm_type,
+ unsigned long atag_paddr,
+ unsigned long cpuid)
{
- /* Not yet... */
- return -ENODEV;
+ memset(get_cpu_info(), 0, sizeof (struct cpu_info));
+
+ /* TODO: handle boards where CPUIDs are not contiguous */
+ set_processor_id(cpuid);
+
+ /* Setup Hyp vector base */
+ WRITE_CP32((uint32_t) hyp_traps_vector, HVBAR);
+
+ dprintk(XENLOG_DEBUG, "CPU %li awake.\n", cpuid);
+
+ gic_init_secondary_cpu();
+
+ set_current(idle_vcpu[cpuid]);
+ this_cpu(curr_vcpu) = current;
+
+ /* Run local notifiers */
+ notify_cpu_starting(cpuid);
+ wmb();
+
+ /* Now report this CPU is up */
+ cpumask_set_cpu(cpuid, &cpu_online_map);
+ wmb();
+
+ local_irq_enable();
+
+ dprintk(XENLOG_DEBUG, "CPU %li booted.\n", cpuid);
+
+ startup_cpu_idle_loop();
}
/* Shut down the current CPU */
@@ -57,6 +101,26 @@ void __cpu_disable(void)
BUG();
}
+/* Bring up a remote CPU */
+int __cpu_up(unsigned int cpu)
+{
+ /* Tell the remote CPU which stack to boot on. */
+ init_stack = idle_vcpu[cpu]->arch.stack;
+
+ /* Unblock the CPU. It should be waiting in the loop in head.S
+ * for an event to arrive when smp_up_cpu matches its cpuid. */
+ smp_up_cpu = cpu;
+ asm volatile("dsb; isb; sev");
+
+ while ( !cpu_online(cpu) )
+ {
+ cpu_relax();
+ process_pending_softirqs();
+ }
+
+ return 0;
+}
+
/* Wait for a remote CPU to die */
void __cpu_die(unsigned int cpu)
{
diff --git a/xen/include/asm-arm/current.h b/xen/include/asm-arm/current.h
index bdce2d488b..36b2be950d 100644
--- a/xen/include/asm-arm/current.h
+++ b/xen/include/asm-arm/current.h
@@ -49,10 +49,10 @@ static inline struct cpu_info *get_cpu_info(void)
#define guest_cpu_user_regs() (&get_cpu_info()->guest_cpu_user_regs)
-#define reset_stack_and_jump(__fn) \
- __asm__ __volatile__ ( \
- "mov sp,%0; b "STR(__fn) \
- : : "r" (guest_cpu_user_regs()) : "memory" )
+#define switch_stack_and_jump(stack, fn) \
+ asm volatile ("mov sp,%0; b " STR(fn) : : "r" (stack) : "memory" )
+
+#define reset_stack_and_jump(fn) switch_stack_and_jump(get_cpu_info(), fn)
#endif