(v2) arm: SMP boot
PATCH 1/1 (v2) arm: SMP boot
This patch series implements SMP boot for arch/arm, as far as getting all CPUs up and running the idle loop.
Changes from v1:
- moved barriers out of loop in udelay()
- dropped broken GIC change in favour of explanatory comment
- made the increment of ready_cpus atomic (I couldn't move the increment to before signalling the next CPU because the PT switch has to happen between them)
- Made secondary CPUs come up directly on the idle vcpus' stacks, avoiding the whole business of allocating and tracking boot stacks.
- Added a new patch to do late-boot MMU fixups on secondary CPUs.
Cheers,
Tim.
PATCH 1/1 arm: implement udelay()
# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331300346 0
# Node ID 7a00e582027ed2793f4ee393f94ddf790b61c39f # Parent 10c5ba0b5af2dd209d4f7d27649dea5827652d9c
arm: implement udelay()
xen/arch/arm/dummy.S +0 -1
@@ -62,5 +62,4 @@ DUMMY(gmfn_to_mfn); DUMMY(hypercall_create_continuation); DUMMY(send_timer_event); DUMMY(share_xen_page_with_privileged_guests); -DUMMY(__udelay); DUMMY(wallclock_time);
xen/arch/arm/time.c +10 -0
@@ -171,6 +171,16 @@ void __cpuinit init_timer_interrupt(voidrequest_irq (30 , timer_interrupt,0 ,"phytimer" ,NULL ); } +/* Wait a set number of microseconds */ +void udelay (unsigned long usecs) +{ +s_time_t deadline =get_s_time () +1000 * (s_time_t ) usecs; +while (get_s_time () - deadline <0 ) + ; +dsb (); +isb (); +} +/* * Local variables: * mode: C
xen/include/asm-arm/delay.h +1 -2
@@ -1,8 +1,7 @@#ifndef _ARM_DELAY_H#define _ARM_DELAY_H -extern void __udelay (unsigned long usecs); -#define udelay (n) __udelay(n) +extern void udelay (unsigned long usecs);#endif /* defined(_ARM_DELAY_H) */ /*
PATCH 1/1 arm: Add a comment explaining the GICD writes in the GICC init function
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331300346 0
# Node ID 51da35a2e502779efb78402013da38a1960a6129
# Parent 7a00e582027ed2793f4ee393f94ddf790b61c39f
arm: Add a comment explaining the GICD writes in the GICC init function.
xen/arch/arm/gic.c +3 -1
@@ -224,7 +224,9 @@ static void __cpuinit gic_cpu_init(void) {int i; -/* Disable all PPI and enable all SGI */ +/* The first 32 interrupts (PPI and SGI) are banked per-cpu, so +* even though they are controlled with GICD registers, they must +* be set up here with the other per-cpu state. */ GICD [GICD_ICENABLER ] =0xffff0000 ;/* Disable all PPI */ GICD [GICD_ISENABLER ] =0x0000ffff ;/* Enable all SGI */ /* Set PPI and SGI priorities */
PATCH 1/1 arm: More SMP bringup
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331300346 0
# Node ID ef66ce0f4fb3bfe72acd691e4db33f0c1ea9137d # Parent 51da35a2e502779efb78402013da38a1960a6129
arm: More SMP bringup
Bring non-boot CPUs up as far as running on the relocated pagetables, one at a time, before the non-relocated copy of Xen gets reused for general memory pools.
Don't yet bring them up into C; that will happen later when stacks are allocated.
xen/arch/arm/gic.c +3 -1
@@ -252,7 +252,7 @@ static void __cpuinit gic_hyp_init(void) }/* Set up the GIC */ -void gic_init (void ) +int __init gic_init (void ) {/* XXX FIXME get this from devicetree */ gic.dbase =GIC_BASE_ADDRESS +GIC_DR_OFFSET ;
@@ -274,6 +274,8 @@ void gic_init(void)gic_hyp_init ();spin_unlock (&gic.lock); + +return gic.cpus; }void gic_route_irqs (void )
xen/arch/arm/gic.h +2 -2
@@ -138,8 +138,8 @@ extern int gic_route_irq_to_guest(struct/* Accept an interrupt from the GIC and dispatch its handler */ extern void gic_interrupt (struct cpu_user_regs *regs,int is_fiq); -/* Bring up the interrupt controller */ -extern void gic_init (void ); +/* Bring up the interrupt controller, and report # cpus attached */ +extern int gic_init (void );/* setup the gic virtual interface for a guest */ extern void gicv_setup (struct domain *d);#endif
xen/arch/arm/head.S +75 -14
154 lines not on this page · raw message
xen/arch/arm/mm.c +11 -9
@@ -36,6 +36,9 @@ lpae_t xen_second[LPAE_ENTRIES*4] __attr static lpae_t xen_fixmap[LPAE_ENTRIES] __attribute__((__aligned__(4096))); static lpae_t xen_xenmap[LPAE_ENTRIES] __attribute__((__aligned__(4096))); +/* Non-boot CPUs use this to find the correct pagetables. */ +uint64_t boot_httbr; +/* Limits of the Xen heap */ unsigned long xenheap_mfn_start, xenheap_mfn_end;unsigned long xenheap_virt_end;
@@ -156,14 +159,6 @@ void __init setup_pagetables(unsigned lolpae_t pte, *p;int i; -if ( boot_phys_offset !=0 ) - { -/* Remove the old identity mapping of the boot paddr */ - pte.bits =0 ; - dest_va = (unsigned long )_start + boot_phys_offset; -write_pte (xen_second +second_linear_offset (dest_va), pte); - } - xen_paddr =device_tree_get_xen_paddr ();/* Map the destination in the boot misc area. */
@@ -186,11 +181,18 @@ void __init setup_pagetables(unsigned lofor ( i =0 ; i <4 ; i++) p[i].pt.base += (phys_offset - boot_phys_offset) >>PAGE_SHIFT ; p = (void *) xen_second + dest_va - (unsigned long ) _start; +if ( boot_phys_offset !=0 ) + { +/* Remove the old identity mapping of the boot paddr */ +unsigned long va = (unsigned long )_start + boot_phys_offset; + p[second_linear_offset (va)].bits =0 ; + }for ( i =0 ; i <4 *LPAE_ENTRIES ; i++)if ( p[i].pt.valid ) p[i].pt.base += (phys_offset - boot_phys_offset) >>PAGE_SHIFT ;/* Change pagetables to the copy in the relocated Xen */ + boot_httbr = (unsigned long ) xen_pgtable + phys_offset; asmvolatile ( STORE_CP64(0, HTTBR) /* Change translation base */ "dsb;" /* Ensure visibility of HTTBR update */
@@ -198,7 +200,7 @@ void __init setup_pagetables(unsigned lo STORE_CP32(0, BPIALL) /* Flush branch predictor */ "dsb;" /* Ensure completion of TLB+BP flush */ "isb;" - : : "r" ((unsigned long) xen_pgtable + phys_offset) : "memory"); + : : "r" (boot_httbr) : "memory"); /* Undo the temporary map */ pte.bits =0 ;
xen/arch/arm/setup.c +28 -10
@@ -44,7 +44,12 @@ static unsigned int __initdata max_cpus/* Xen stack for bringing up the first CPU. */ unsigned char __initdata init_stack[STACK_SIZE] __attribute__((__aligned__(STACK_SIZE))); -extern char __init_begin[], __init_end[], __bss_start[]; +extern const char __init_begin[], __init_end[], __bss_start[]; + +/* Spinlock for serializing CPU bringup */ +unsigned long __initdata boot_gate =1 ; +/* Number of non-boot CPUs ready to enter C */ +unsigned long __initdata ready_cpus =0 ; static __attribute_used__ void init_done(void) {
@@ -151,14 +156,17 @@ static void __init setup_mm(unsigned lonend_boot_allocator (); } +/* C entry point for boot CPU */ void __init start_xen (unsigned long boot_phys_offset,unsigned long arm_type, -unsigned long atag_paddr) - +unsigned long atag_paddr, +unsigned long cpuid) {void *fdt;size_t fdt_size; -int i; +int cpus, i; +paddr_t gate_pa; +unsigned long *gate; fdt = (void *)BOOT_MISC_VIRT_START + (atag_paddr & ((1 <<SECOND_SHIFT ) -1 ));
@@ -174,14 +182,26 @@ void __init start_xen(unsigned long bootconsole_init_preirq ();#endif + cpus =gic_init (); + +printk ("Waiting for %i other CPUs to be ready\n" , cpus -1 ); +/* Bring the other CPUs up to paging before the original +* copy of .text gets overwritten. We need to use the unrelocated +* copy of boot_gate as that's the one the others can see. */ + gate_pa = ((unsigned long ) &boot_gate) + boot_phys_offset; + gate =map_domain_page (gate_pa >>PAGE_SHIFT ) + (gate_pa & ~PAGE_MASK ); + *gate =0 ; +unmap_domain_page (gate); +/* Now send an event to wake the first non-boot CPU */ + asmvolatile ("dsb; isb; sev" ); +/* And wait for them all to be ready. */ +while ( ready_cpus +1 < cpus ) +smp_rmb (); +__set_current ((struct vcpu *)0xfffff000 );/* debug sanity */ idle_vcpu[0 ] = current;set_processor_id (0 );/* needed early, for smp_processor_id() */ -/* TODO: smp_prepare_boot_cpu(void) */ -cpumask_set_cpu (smp_processor_id (), &cpu_online_map); -cpumask_set_cpu (smp_processor_id (), &cpu_present_map); -smp_prepare_cpus (max_cpus);init_xen_time ();
@@ -208,8 +228,6 @@ void __init start_xen(unsigned long bootinit_IRQ (); -gic_init (); -gic_route_irqs ();init_maintenance_interrupt ();
PATCH 1/1 arm: per-cpu areas
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331300346 0
# Node ID ded775f8a1278c98d8341338b47df0700992e01b # Parent ef66ce0f4fb3bfe72acd691e4db33f0c1ea9137d
arm: per-cpu areas
xen/arch/arm/Makefile +1 -0
@@ -13,6 +13,7 @@ obj-y += irq.o obj-y += kernel.o obj-y += mm.o obj-y += p2m.o +obj-y += percpu.o obj-y += guestcopy.o obj-y += setup.o obj-y += time.o
xen/arch/arm/dummy.S +0 -1
@@ -14,7 +14,6 @@ DUMMY(per_cpu__cpu_core_mask); DUMMY(per_cpu__cpu_sibling_mask); DUMMY(node_online_map); DUMMY(smp_send_state_dump); -DUMMY(__per_cpu_offset); /* PIRQ support */ DUMMY(alloc_pirq_struct);
xen/arch/arm/percpu.c new file +85 -0
85 lines not on this page · raw message
xen/include/asm-arm/percpu.h +5 -2
@@ -12,8 +12,11 @@ void percpu_init_areas(void); __attribute__((__section__(".bss.percpu" #suffix))) \ __typeof__(type) per_cpu_##name -#define per_cpu (var, cpu) ((&per_cpu__##var)[cpu?0:0]) -#define __get_cpu_var (var) per_cpu__##var + +#define per_cpu (var, cpu) \ + (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu])) +#define __get_cpu_var (var) \ + (*RELOC_HIDE(&per_cpu__##var, get_cpu_info()->per_cpu_offset))#define DECLARE_PER_CPU (type, name) extern __typeof__(type) per_cpu__##name
Re: [PATCH 4 of 9] arm: per-cpu areas
Hold off on this - it seems to mess up context switches (something to so with current being a per-cpu variable and per-cpu variables being accessed via the current vcpu's stack...)
Tim.
Quoted 143 lines · Tim Deegan
# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331300346 0
# Node IDded775f8a1278c98d8341338b47df0700992e01b# Parentef66ce0f4fb3bfe72acd691e4db33f0c1ea9137d
arm: per-cpu areasSigned-off-by Tim Deegan <[email protected]>Acked-by Ian Campbell <[email protected]>diff -r
ef66ce0f4fb3-rded775f8a127xen/arch/arm/Makefilexen/arch/arm/Makefile +1
-0@@ -13,6 +13,7 @@ obj-y += irq.o obj-y += kernel.o obj-y += mm.o obj-y += p2m.o +obj-y += percpu.o obj-y += guestcopy.o obj-y += setup.o obj-y += time.odiff -r
ef66ce0f4fb3-rded775f8a127xen/arch/arm/dummy.Sxen/arch/arm/dummy.S +0
-1@@ -14,7 +14,6 @@ DUMMY(per_cpu__cpu_core_mask); DUMMY(per_cpu__cpu_sibling_mask); DUMMY(node_online_map); DUMMY(smp_send_state_dump); -DUMMY(__per_cpu_offset); /* PIRQ support */ DUMMY(alloc_pirq_struct);diff -r
ef66ce0f4fb3-rded775f8a127xen/arch/arm/percpu.cxen/arch/arm/percpu.c new file +85
-0@@ -0,0 +1,85 @@ +#include <xen/config.h> +#include <xen/percpu.h> +#include <xen/cpu.h> +#include <xen/init.h> +#include <xen/mm.h> +#include <xen/rcupdate.h> + +unsigned long __per_cpu_offset[NR_CPUS ]; +#define INVALID_PERCPU_AREA (-(long)__per_cpu_start) +#define PERCPU_ORDER (get_order_from_bytes(__per_cpu_data_end-__per_cpu_start)) + +void __init percpu_init_areas (void ) +{ +unsigned int cpu; +for ( cpu =1 ; cpu <NR_CPUS ; cpu++ ) + __per_cpu_offset[cpu] =INVALID_PERCPU_AREA ; +} + +static int init_percpu_area (unsigned int cpu) +{ +char *p; +if ( __per_cpu_offset[cpu] !=INVALID_PERCPU_AREA ) +return -EBUSY ; +if ( (p =alloc_xenheap_pages (PERCPU_ORDER ,0 )) ==NULL ) +return -ENOMEM ; +memset (p,0 , __per_cpu_data_end - __per_cpu_start); + __per_cpu_offset[cpu] = p - __per_cpu_start; +return 0 ; +} + +struct free_info { +unsigned int cpu; +struct rcu_head rcu; +}; +static DEFINE_PER_CPU(struct free_info, free_info); + +static void _free_percpu_area (struct rcu_head *head) +{ + struct free_info *info = container_of(head, struct free_info, rcu); +unsigned int cpu = info->cpu; +char *p = __per_cpu_start + __per_cpu_offset[cpu]; +free_xenheap_pages (p,PERCPU_ORDER ); + __per_cpu_offset[cpu] =INVALID_PERCPU_AREA ; +} + +static void free_percpu_area (unsigned int cpu) +{ +struct free_info *info = &per_cpu (free_info, cpu); + info->cpu = cpu; +call_rcu (&info->rcu, _free_percpu_area); +} + +static int cpu_percpu_callback ( +struct notifier_block *nfb,unsigned long action,void *hcpu) +{ +unsigned int cpu = (unsigned long )hcpu; +int rc =0 ; + +switch ( action ) + { +case CPU_UP_PREPARE : + rc =init_percpu_area (cpu); +break ; +case CPU_UP_CANCELED : +case CPU_DEAD : +free_percpu_area (cpu); +break ; +default : +break ; + } + +return !rc ?NOTIFY_DONE :notifier_from_errno (rc); +} + +static struct notifier_block cpu_percpu_nfb = { + .notifier_call = cpu_percpu_callback, + .priority =100 /* highest priority */ +}; + +static int __init percpu_presmp_init (void ) +{ +register_cpu_notifier (&cpu_percpu_nfb); +return 0 ; +} +presmp_initcall (percpu_presmp_init);diff -r
ef66ce0f4fb3-rded775f8a127xen/include/asm-arm/percpu.hxen/include/asm-arm/percpu.h +5
-2@@ -12,8 +12,11 @@ void percpu_init_areas(void); __attribute__((__section__(".bss.percpu" #suffix))) \ __typeof__(type) per_cpu_##name -#define per_cpu (var, cpu) ((&per_cpu__##var)[cpu?0:0]) -#define __get_cpu_var (var) per_cpu__##var + +#define per_cpu (var, cpu) \ + (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu])) +#define __get_cpu_var (var) \ + (*RELOC_HIDE(&per_cpu__##var, get_cpu_info()->per_cpu_offset))#define DECLARE_PER_CPU (type, name) extern __typeof__(type) per_cpu__##name_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel
PATCH 1/1 arm: start plumbing in SMP bringup in C
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331300346 0
# Node ID 469d9fc8e755b8bd0de386c8cd505229ecdf061f # Parent ded775f8a1278c98d8341338b47df0700992e01b
arm: start plumbing in SMP bringup in C
Still a noop, but no longer just a dummy symbol.
xen/arch/arm/dummy.S +0 -3
@@ -7,9 +7,6 @@ x: .word 0xe7f000f0 /* Undefined instruc x: mov pc, lr /* SMP support */ -DUMMY(__cpu_die); -DUMMY(__cpu_disable); -DUMMY(__cpu_up); DUMMY(per_cpu__cpu_core_mask); DUMMY(per_cpu__cpu_sibling_mask); DUMMY(node_online_map);
xen/arch/arm/setup.c +2 -5
@@ -38,9 +38,6 @@#include <asm/setup.h> #include "gic.h" -/* maxcpus: maximum number of CPUs to activate. */ -static unsigned int __initdata max_cpus =NR_CPUS ; -/* Xen stack for bringing up the first CPU. */ unsigned char __initdata init_stack[STACK_SIZE] __attribute__((__aligned__(STACK_SIZE)));
@@ -202,7 +199,7 @@ void __init start_xen(unsigned long boot idle_vcpu[0 ] = current;set_processor_id (0 );/* needed early, for smp_processor_id() */ -smp_prepare_cpus (max_cpus); +smp_prepare_cpus (cpus);init_xen_time ();
@@ -249,7 +246,7 @@ void __init start_xen(unsigned long bootfor_each_present_cpu ( i ) { -if ( (num_online_cpus () < max_cpus) && !cpu_online (i) ) +if ( (num_online_cpus () < cpus) && !cpu_online (i) ) {int ret =cpu_up (i);if ( ret !=0 )
xen/arch/arm/smpboot.c +33 -8
55 lines not on this page · raw message
PATCH 1/1 arm: Boot secondary CPUs into C
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331300346 0
# Node ID 1b26b83318b378a6e41916e230e27030ee4539e0 # Parent 469d9fc8e755b8bd0de386c8cd505229ecdf061f
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.
xen/arch/arm/gic.c +9 -1
@@ -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 */
xen/arch/arm/gic.h +2 -0
@@ -140,6 +140,8 @@ extern int gic_route_irq_to_guest(structextern 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
xen/arch/arm/head.S +10 -4
@@ -307,17 +307,23 @@ 1: ldrex r1, [r0] /* * 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 */
xen/arch/arm/setup.c +7 -5
@@ -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 */
@@ -179,6 +176,8 @@ void __init start_xen(unsigned long bootconsole_init_preirq ();#endif +percpu_init_areas (); + cpus =gic_init ();printk ("Waiting for %i other CPUs to be ready\n" , cpus -1 );
@@ -197,7 +196,6 @@ void __init start_xen(unsigned long boot__set_current ((struct vcpu *)0xfffff000 );/* debug sanity */ idle_vcpu[0 ] = current; -set_processor_id (0 );/* needed early, for smp_processor_id() */ smp_prepare_cpus (cpus);
@@ -284,7 +282,11 @@ void __init start_xen(unsigned long bootdomain_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)
xen/arch/arm/smpboot.c +70 -6
103 lines not on this page · raw message
xen/include/asm-arm/current.h +4 -4
@@ -47,10 +47,10 @@ static inline struct cpu_info *get_cpu_i#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
PATCH 1/1 arm: SMP CPU shutdown
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331300346 0
# Node ID 80b1ce050d104d9bb2ea41634e886cdc0f175c3e # Parent 1b26b83318b378a6e41916e230e27030ee4539e0
arm: SMP CPU shutdown
For completeness, also implelent the CPU shutdown path.
xen/arch/arm/domain.c +4 -6
@@ -31,12 +31,10 @@ void idle_loop(void) {for ( ; ; ) { -/* TODO -if ( cpu_is_offline(smp_processor_id()) ) -play_dead(); -(*pm_idle)(); -BUG(); -*/ +if (cpu_is_offline (smp_processor_id ()) ) +stop_cpu (); + +/* TODO: (*pm_idle)(); */ do_tasklet ();do_softirq (); }
xen/arch/arm/gic.c +19 -0
@@ -239,6 +239,11 @@ static void __cpuinit gic_cpu_init(void)GICC [GICC_CTLR ] =GICC_CTL_ENABLE |GICC_CTL_EOI ;/* Turn on delivery */ } +static void gic_cpu_disable (void ) +{ +GICC [GICC_CTLR ] =0 ; +} +static void __cpuinit gic_hyp_init (void ) {uint32_t vtr;
@@ -250,6 +255,11 @@ static void __cpuinit gic_hyp_init(void)GICH [GICH_MISR ] =GICH_MISR_EOI ; } +static void __cpuinit gic_hyp_disable (void ) +{ +GICH [GICH_HCR ] =0 ; +} +/* Set up the GIC */ int __init gic_init (void ) {
@@ -286,6 +296,15 @@ void __cpuinit gic_init_secondary_cpu(vospin_unlock (&gic.lock); } +/* Shut down the per-CPU GIC interface */ +void gic_disable_cpu (void ) +{ +spin_lock (&gic.lock); +gic_cpu_disable (); +gic_hyp_disable (); +spin_unlock (&gic.lock); +} +void gic_route_irqs (void ) {/* XXX should get these from DT */
xen/arch/arm/gic.h +2 -0
@@ -142,6 +142,8 @@ extern void gic_interrupt(struct cpu_useextern int gic_init (void );/* Bring up a secondary CPU's per-CPU GIC interface */ extern void gic_init_secondary_cpu (void ); +/* Take down a CPU's per-CPU GIC interface */ +extern void gic_disable_cpu (void );/* setup the gic virtual interface for a guest */ extern void gicv_setup (struct domain *d);#endif
xen/arch/arm/smpboot.c +44 -4
72 lines not on this page · raw message
xen/include/asm-arm/smp.h +2 -0
@@ -14,6 +14,8 @@ DECLARE_PER_CPU(cpumask_var_t, cpu_core_#define raw_smp_processor_id () (get_processor_id()) +extern void stop_cpu (void ); +#endif /* * Local variables:
PATCH 1/1 arm: Shutdown and reboot
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331300346 0
# Node ID 78eebd867ba25f5165283b45122d1006370ae71d # Parent 80b1ce050d104d9bb2ea41634e886cdc0f175c3e
arm: Shutdown and reboot
Reboot runes grabbed from linux's SP810 reset function. Doesn't seem to work on the model, though.
xen/arch/arm/shutdown.c +51 -5
@@ -1,18 +1,64 @@#include <xen/config.h> +#include <xen/console.h> +#include <xen/cpu.h> +#include <xen/delay.h> #include <xen/lib.h> +#include <xen/mm.h> +#include <xen/smp.h> + +static void raw_machine_reset (void ) +{ +/* XXX get this from device tree */ +#ifdef SP810_ADDRESS +/* Use the SP810 system controller to force a reset */ +volatile uint32_t *sp810; +set_fixmap (FIXMAP_MISC ,SP810_ADDRESS >>PAGE_SHIFT ,DEV_SHARED ); + sp810 = ((uint32_t *) + (FIXMAP_ADDR (FIXMAP_MISC ) + (SP810_ADDRESS & ~PAGE_MASK ))); + sp810[0 ] =0x3 ;/* switch to slow mode */ +dsb ();isb (); + sp810[1 ] =0x1 ;/* writing any value to SCSYSSTAT reg will reset system */ +dsb ();isb (); +clear_fixmap (FIXMAP_MISC ); +#endif +} + +static void halt_this_cpu (void *arg) +{ +__cpu_disable (); +stop_cpu (); +}void machine_halt (void ) { -/* TODO: halt */ -while (1 ) ; +watchdog_disable (); +console_start_sync (); +local_irq_enable (); +smp_call_function (halt_this_cpu,NULL ,0 ); +halt_this_cpu (NULL ); }void machine_restart (unsigned int delay_millisecs) { -/* TODO: restart */ -printk ("Cannot restart yet\n" ); -while (1 ); +int timeout =10 ; + +local_irq_enable (); +smp_call_function (halt_this_cpu,NULL ,0 ); +local_irq_disable (); + +mdelay (delay_millisecs); + +/* Wait at most another 10ms for all other CPUs to go offline. */ +while ( (num_online_cpus () >1 ) && (timeout-- >0 ) ) +mdelay (1 ); + +while (1 ) + { +raw_machine_reset (); +mdelay (100 ); + } } +/* * Local variables: * mode: C
xen/include/asm-arm/config.h +3 -0
@@ -119,6 +119,9 @@ extern unsigned long frametable_virt_end#define GIC_CR_OFFSET 0x2000#define GIC_HR_OFFSET 0x4000/* Guess work http://lists.infradead.org/pipermail/linux-arm-kernel/2011-September/064219.html */ #define GIC_VR_OFFSET 0x6000/* Virtual Machine CPU interface) */ +/* Board-specific: base address of system controller */ +#define SP810_ADDRESS 0x1C020000 +#endif /* __ARM_CONFIG_H__ */ /*
PATCH 1/1 arm: new hook for late MMU setup on secondary CPUs
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331300395 0
# Node ID e18aa8c6c1f472bad15310a6e38457697d71540d # Parent 78eebd867ba25f5165283b45122d1006370ae71d
arm: new hook for late MMU setup on secondary CPUs
The boot CPU turns on W^X in setup_pagetables(). Do the same for other CPUs after they boot. If we go to per-CPU pagetables, this is where that will happen.
xen/arch/arm/mm.c +7 -0
@@ -263,6 +263,13 @@ void __init setup_pagetables(unsigned loWRITE_CP32 (READ_CP32 (HSCTLR ) |SCTLR_WXN ,HSCTLR ); } +/* MMU setup for secondary CPUS (which already have paging enabled) */ +void __cpuinit mmu_init_secondary_cpu (void ) +{ +/* From now on, no mapping may be both writable and executable. */ +WRITE_CP32 (READ_CP32 (HSCTLR ) |SCTLR_WXN ,HSCTLR ); +} +/* Create Xen's mappings of memory. * Base and virt must be 32MB aligned and size a multiple of 32MB. */ static void __init create_mappings(unsigned long virt,
xen/arch/arm/smpboot.c +1 -0
@@ -76,6 +76,7 @@ void __cpuinit start_secondary(unsigneddprintk (XENLOG_DEBUG ,"CPU %li awake.\n" , cpuid); +mmu_init_secondary_cpu ();gic_init_secondary_cpu ();set_current (idle_vcpu[cpuid]);
xen/include/asm-arm/mm.h +2 -0
@@ -136,6 +136,8 @@ extern unsigned long total_pages;/* Boot-time pagetable setup */ extern void setup_pagetables (unsigned long boot_phys_offset); +/* MMU setup for seccondary CPUS (which already have paging enabled) */ +extern void __cpuinit mmu_init_secondary_cpu (void );/* Set up the xenheap: up to 1GB of contiguous, always-mapped memory. * Base must be 32MB aligned and size a multiple of 32MB. */ extern void setup_xenheap_mappings (unsigned long base_mfn,unsigned long nr_mfns);