Skip to contentSkip to conversation

arm: SMP boot

PATCH In review Tim Deegan 3 participants 27 messages Feb 23, 2012 – Feb 29, 2012

lore
Share & tools
lore

Tim Deegan

author
#0 lore raw

PATCH 1/1 arm: SMP boot

This patch series implements SMP boot for arch/arm, as far as getting all CPUs up and running the idle loop.

The first few patches are semi-independent cleanups and improvements, most of which are needed for the SMP patches later.

Cheers,

Tim.

author
#1 lore raw

PATCH 1/1 arm: strip xen binary

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID 4a7c1420913135fbeba361cd9603e748c074cdac # Parent 0c3d19f40ab145d101de84051c3e00eef17fa1cb
arm: strip xen binary

The symbols in it are wrong anyway and will only confuse people who ought to be looking at xen-syms.

xen/arch/arm/Makefile +1 -1
diff -r 0c3d19f40ab1 -r 4a7c14209131 xen/arch/arm/Makefile
@@ -40,7 +40,7 @@ ALL_OBJS := head.o $(ALL_OBJS)
 	# XXX: VE model loads by VMA so instead of
 	# making a proper ELF we link with LMA == VMA and adjust crudely
 	$(OBJCOPY) --change-addresses +0x80000000 $< $@
-	# XXX strip it
+	$(STRIP) $@
 
 #$(TARGET): $(TARGET)-syms $(efi-y) boot/mkelf32
 #	./boot/mkelf32 $(TARGET)-syms $(TARGET) 0x100000 \
author
#2 lore raw

PATCH 1/1 arm: implement udelay()

In reply to Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID ec051056db2b6d37344629e2f01d17240099d5ec # Parent 4a7c1420913135fbeba361cd9603e748c074cdac
arm: implement udelay()

xen/arch/arm/dummy.S +0 -1
diff -r 4a7c14209131 -r ec051056db2b xen/arch/arm/dummy.S
@@ -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
diff -r 4a7c14209131 -r ec051056db2b xen/arch/arm/time.c
@@ -171,6 +171,16 @@ void __cpuinit init_timer_interrupt(void
     request_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;
+    do {
+        dsb();
+        isb();
+    } while ( get_s_time() - deadline < 0 );
+}
+
 /*
  * Local variables:
  * mode: C
xen/include/asm-arm/delay.h +1 -2
diff -r 4a7c14209131 -r ec051056db2b xen/include/asm-arm/delay.h
@@ -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) */
 /*
#3 lore raw

Re: [PATCH 02 of 10] arm: implement udelay()

Quoted 4 lines · Tim Deegan

arm: implement udelay()

[...]

Quoted 4 lines

diff -r 4a7c14209131 -r ec051056db2b xen/arch/arm/time.c

xen/arch/arm/time.c void __cpuinit init_timer_interrupt(void · line 180

Quoted 10 lines
xen/arch/arm/time.c +7 -0
@@ -171,6 +171,16 @@ void __cpuinit init_timer_interrupt(void
     request_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;
+    do {
+        dsb();
+        isb();

What are these barriers for?

David

Quoted 6 lines
xen/arch/arm/time.c +3 -0
+    } while ( get_s_time() - deadline < 0 );
+}
+
 /*
  * Local variables:
  * mode: C
author
#4 lore raw

Re: [PATCH 02 of 10] arm: implement udelay()

Quoted 13 lines · David Vrabel
Quoted 4 lines · Tim Deegan

arm: implement udelay()

[...]

Quoted 7 lines

diff -r 4a7c14209131 -r ec051056db2b xen/arch/arm/time.c

xen/arch/arm/time.c +0 -0
@@ -171,6 +171,16 @@ void __cpuinit init_timer_interrupt(void
     request_irq(30, timer_interrupt, 0, "phytimer", NULL);
 }
 
Quoted 9 lines

xen/arch/arm/time.c void __cpuinit init_timer_interrupt(void · line 180

Quoted 7 lines
xen/arch/arm/time.c +7 -0
+/* Wait a set number of microseconds */
+void udelay(unsigned long usecs)
+{
+    s_time_t deadline = get_s_time() + 1000 * (s_time_t) usecs;
+    do {
+        dsb();
+        isb();

What are these barriers for?

To make sure the CPU doesn't hoist any instructions past the wait loop. :) They don't really have to be inside the loop body; I can change that if you like.

Tim.

author
#5 lore raw

PATCH 1/1 arm: Move some GIC distributor init out of the per-CPU init function

In reply to Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID 437ad1207a175c9ad376871f3f4c075dbcd5b6e6
# Parent ec051056db2b6d37344629e2f01d17240099d5ec
arm: Move some GIC distributor init out of the per-CPU init function

xen/arch/arm/gic.c +6 -8
diff -r ec051056db2b -r 437ad1207a17 xen/arch/arm/gic.c
@@ -216,14 +216,6 @@ static void __init gic_dist_init(void)
     for ( i = 32; i < gic.lines; i += 32 )
         GICD[GICD_ICENABLER + i / 32] = ~0ul;
 
-    /* Turn on the distributor */
-    GICD[GICD_CTLR] = GICD_CTL_ENABLE;
-}
-
-static void __cpuinit gic_cpu_init(void)
-{
-    int i;
-
     /* Disable all PPI and enable all SGI */
     GICD[GICD_ICENABLER] = 0xffff0000; /* Disable all PPI */
     GICD[GICD_ISENABLER] = 0x0000ffff; /* Enable all SGI */
@@ -231,6 +223,12 @@ static void __cpuinit gic_cpu_init(void)
     for (i = 0; i < 32; i += 4)
         GICD[GICD_IPRIORITYR + i / 4] = 0xa0a0a0a0;
 
+    /* Turn on the distributor */
+    GICD[GICD_CTLR] = GICD_CTL_ENABLE;
+}
+
+static void __cpuinit gic_cpu_init(void)
+{
     /* Local settings: interface controller */
     GICC[GICC_PMR] = 0xff;                /* Don't mask by priority */
     GICC[GICC_BPR] = 0;                   /* Finest granularity of priority */
#6 lore raw

Re: [PATCH 03 of 10] arm: Move some GIC distributor init out of the per-CPU init function

Quoted 17 lines · Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID 437ad1207a175c9ad376871f3f4c075dbcd5b6e6
# Parent ec051056db2b6d37344629e2f01d17240099d5ec
arm: Move some GIC distributor init out of the per-CPU init function

diff -r ec051056db2b -r 437ad1207a17 xen/arch/arm/gic.c

xen/arch/arm/gic.c +0 -1
@@ -216,14 +216,6 @@ static void __init gic_dist_init(void)
     for ( i = 32; i < gic.lines; i += 32 )
         GICD[GICD_ICENABLER + i / 32] = ~0ul;
 
-    /* Turn on the distributor */

xen/arch/arm/gic.c static void __init gic_dist_init(void) · line 221

Quoted 10 lines
xen/arch/arm/gic.c +0 -7
-    GICD[GICD_CTLR] = GICD_CTL_ENABLE;
-}
-
-static void __cpuinit gic_cpu_init(void)
-{
-    int i;
-
     /* Disable all PPI and enable all SGI */
     GICD[GICD_ICENABLER] = 0xffff0000; /* Disable all PPI */
     GICD[GICD_ISENABLER] = 0x0000ffff; /* Enable all SGI */

PPIs and SGIs are per physical-CPU and therefore, I think, the GICD registers of various sorts which refer to the first 32 interrupts are per physical-CPU as well. IOW moving these from gic_cpu_init to gic_dist_init is wrong?

Quoted 13 lines
xen/arch/arm/gic.c +6 -0
@@ -231,6 +223,12 @@ static void __cpuinit gic_cpu_init(void)
     for (i = 0; i < 32; i += 4)
         GICD[GICD_IPRIORITYR + i / 4] = 0xa0a0a0a0;
 
+    /* Turn on the distributor */
+    GICD[GICD_CTLR] = GICD_CTL_ENABLE;
+}
+
+static void __cpuinit gic_cpu_init(void)
+{
     /* Local settings: interface controller */
     GICC[GICC_PMR] = 0xff;                /* Don't mask by priority */
     GICC[GICC_BPR] = 0;                   /* Finest granularity of priority */
author
#7 lore raw

Re: [PATCH 03 of 10] arm: Move some GIC distributor init out of the per-CPU init function

Quoted 17 lines · Ian Campbell
Quoted 16 lines · Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID 437ad1207a175c9ad376871f3f4c075dbcd5b6e6
# Parent ec051056db2b6d37344629e2f01d17240099d5ec
arm: Move some GIC distributor init out of the per-CPU init function

diff -r ec051056db2b -r 437ad1207a17 xen/arch/arm/gic.c

xen/arch/arm/gic.c +0 -0
@@ -216,14 +216,6 @@ static void __init gic_dist_init(void)
     for ( i = 32; i < gic.lines; i += 32 )
         GICD[GICD_ICENABLER + i / 32] = ~0ul;
 
Quoted 16 lines

xen/arch/arm/gic.c static void __init gic_dist_init(void) · line 221

Quoted 11 lines
xen/arch/arm/gic.c +0 -8
-    /* Turn on the distributor */
-    GICD[GICD_CTLR] = GICD_CTL_ENABLE;
-}
-
-static void __cpuinit gic_cpu_init(void)
-{
-    int i;
-
     /* Disable all PPI and enable all SGI */
     GICD[GICD_ICENABLER] = 0xffff0000; /* Disable all PPI */
     GICD[GICD_ISENABLER] = 0x0000ffff; /* Enable all SGI */

PPIs and SGIs are per physical-CPU and therefore, I think, the GICD registers of various sorts which refer to the first 32 interrupts are per physical-CPU as well. IOW moving these from gic_cpu_init to gic_dist_init is wrong?

Yep, you're right ISENABLER0 and ICENABLER0 are banked. I'll replace this with a comment explaining that.

Cheers,

Tim.

#8 lore raw

Re: [PATCH 03 of 10] arm: Move some GIC distributor init out of the per-CPU init function

Quoted 35 lines · Tim Deegan
Quoted 17 lines · Ian Campbell
Quoted 16 lines · Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID 437ad1207a175c9ad376871f3f4c075dbcd5b6e6
# Parent ec051056db2b6d37344629e2f01d17240099d5ec
arm: Move some GIC distributor init out of the per-CPU init function

diff -r ec051056db2b -r 437ad1207a17 xen/arch/arm/gic.c

xen/arch/arm/gic.c +0 -0
@@ -216,14 +216,6 @@ static void __init gic_dist_init(void)
     for ( i = 32; i < gic.lines; i += 32 )
         GICD[GICD_ICENABLER + i / 32] = ~0ul;
 
Quoted 16 lines

xen/arch/arm/gic.c static void __init gic_dist_init(void) · line 221

Quoted 11 lines
xen/arch/arm/gic.c +0 -8
-    /* Turn on the distributor */
-    GICD[GICD_CTLR] = GICD_CTL_ENABLE;
-}
-
-static void __cpuinit gic_cpu_init(void)
-{
-    int i;
-
     /* Disable all PPI and enable all SGI */
     GICD[GICD_ICENABLER] = 0xffff0000; /* Disable all PPI */
     GICD[GICD_ISENABLER] = 0x0000ffff; /* Enable all SGI */

PPIs and SGIs are per physical-CPU and therefore, I think, the GICD registers of various sorts which refer to the first 32 interrupts are per physical-CPU as well. IOW moving these from gic_cpu_init to gic_dist_init is wrong?

Quoted 1 line

Yep, you're right ISENABLER0 and ICENABLER0 are banked.

BTW so are GICD_IPRIORITYR0..4 which are initialised just outside the context here. More generally all the per-IRQ registers are banked for the first few which cover the PPIs and SGIs.

Quoted 1 line

I'll replace this with a comment explaining that.

Thanks.

author
#9 lore raw

PATCH 1/1 arm: Handle booting on SMP platforms

In reply to Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID 8f322ab538572e1a12c8ed716ddd5cb4c122e9ed # Parent 437ad1207a175c9ad376871f3f4c075dbcd5b6e6
arm: Handle booting on SMP platforms

Make all non-boot CPUs wait forever instead of trying to boot in parallel.

xen/arch/arm/head.S +13 -0
diff -r 437ad1207a17 -r 8f322ab53857 xen/arch/arm/head.S
@@ -61,6 +61,19 @@ start:
 	add   r8, r10                /* r8 := paddr(DTB) */
 #endif
 
+	/* Are we the boot CPU? */
+	mrc   CP32(r0, MPIDR)
+	tst   r0, #(1<<31)           /* Multiprocessor extension supported? */
+	beq   boot_cpu
+	tst   r0, #(1<<30)           /* Uniprocessor system? */
+	bne   boot_cpu
+	bics  r0, r0, #(0xff << 24)  /* Ignore flags */
+	beq   boot_cpu               /* If all other fields are 0, we win */
+
+1:	wfi
+	b     1b
+	
+boot_cpu:
 #ifdef EARLY_UART_ADDRESS
 	/* Say hello */
 	ldr   r11, =EARLY_UART_ADDRESS  /* r11 := UART base address */
xen/include/asm-arm/cpregs.h +1 -0
diff -r 437ad1207a17 -r 8f322ab53857 xen/include/asm-arm/cpregs.h
@@ -91,6 +91,7 @@
 /* Coprocessor 15 */
 
 /* CP15 CR0: CPUID and Cache Type Registers */
+#define MPIDR           p15,0,c0,c0,5   /* Multiprocessor Affinity Register */
 #define ID_PFR0         p15,0,c0,c1,0   /* Processor Feature Register 0 */
 #define ID_PFR1         p15,0,c0,c1,1   /* Processor Feature Register 1 */
 #define ID_DFR0         p15,0,c0,c1,2   /* Debug Feature Register 0 */
author
#10 lore raw

PATCH 1/1 arm: More SMP bringup

In reply to Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID 1e9c6bd7cc99d1af0107aa927ee2ba03721449b7 # Parent 8f322ab538572e1a12c8ed716ddd5cb4c122e9ed
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
diff -r 8f322ab53857 -r 1e9c6bd7cc99 xen/arch/arm/gic.c
@@ -248,7 +248,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;
@@ -270,6 +270,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
diff -r 8f322ab53857 -r 1e9c6bd7cc99 xen/arch/arm/gic.h
@@ -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 +73 -14

152 lines not on this page · raw message

xen/arch/arm/mm.c +12 -9
diff -r 8f322ab53857 -r 1e9c6bd7cc99 xen/arch/arm/mm.c
@@ -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 lo
     lpae_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,19 @@ void __init setup_pagetables(unsigned lo
     for ( 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 */
+        pte.bits = 0;
+        dest_va = (unsigned long)_start + boot_phys_offset;
+        p[second_linear_offset(dest_va)] = pte;
+    }
     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;
     asm volatile (
         STORE_CP64(0, HTTBR)          /* Change translation base */
         "dsb;"                        /* Ensure visibility of HTTBR update */
@@ -198,7 +201,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 -6
diff -r 8f322ab53857 -r 1e9c6bd7cc99 xen/arch/arm/setup.c
@@ -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 lon
     end_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,6 +182,22 @@ void __init start_xen(unsigned long boot
     console_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 */
+    asm volatile("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() */
@@ -208,8 +232,6 @@ void __init start_xen(unsigned long boot
 
     init_IRQ();
 
-    gic_init();
-
     gic_route_irqs();
 
     init_maintenance_interrupt();
#11 lore raw

Re: [PATCH 05 of 10] arm: More SMP bringup

On Thu, 2012-02-23 at 17:40 +0000, Tim Deegan wrote:
[...]

xen/arch/arm/head.S paging: · line 280

Quoted 8 lines
xen/arch/arm/head.S +8 -0
+	/* Signal the next non-boot CPU to come and join us here */
+	ldr   r0, =boot_gate         /* VA of gate */
+	add   r0, r0, r10            /* PA of gate */
+	mov   r1, #0                 /* (0 == unlocked) */
+	str   r1, [r0]
+	dsb
+	isb
+	sev

Here we have released the next CPU from the holding pen...

[...]

xen/arch/arm/head.S paging: · line 300

Quoted 6 lines
xen/arch/arm/head.S +6 -0
+	/* Non-boot CPUs report that they've got this far */
+	ldr   r0, =ready_cpus
+	ldr   r1, [r0]               /* Read count of ready CPUs */
+	add   r1, r1, #1             /* ++ */
+	str   r1, [r0]               /* Writeback */
+	dsb

... and here we do a non-atomic update of a shared variable.

What prevents the following CPU from catching us up and conflicting here?

Would we be better signalling the next CPU after the increment instead?

Ian.

author
#12 lore raw

Re: [PATCH 05 of 10] arm: More SMP bringup

Quoted 23 lines · Ian Campbell

On Thu, 2012-02-23 at 17:40 +0000, Tim Deegan wrote:
[...]

xen/arch/arm/head.S paging: · line 280

Quoted 8 lines
xen/arch/arm/head.S +8 -0
+	/* Signal the next non-boot CPU to come and join us here */
+	ldr   r0, =boot_gate         /* VA of gate */
+	add   r0, r0, r10            /* PA of gate */
+	mov   r1, #0                 /* (0 == unlocked) */
+	str   r1, [r0]
+	dsb
+	isb
+	sev

Here we have released the next CPU from the holding pen...

[...]

xen/arch/arm/head.S paging: · line 300

Quoted 6 lines
xen/arch/arm/head.S +6 -0
+	/* Non-boot CPUs report that they've got this far */
+	ldr   r0, =ready_cpus
+	ldr   r1, [r0]               /* Read count of ready CPUs */
+	add   r1, r1, #1             /* ++ */
+	str   r1, [r0]               /* Writeback */
+	dsb

... and here we do a non-atomic update of a shared variable.

Quoted 4 lines

What prevents the following CPU from catching us up and conflicting here?

Would we be better signalling the next CPU after the increment instead?

Yes, we would. I'll fix that.

Tim.

author
#13 lore raw

PATCH 1/1 arm: per-cpu areas

In reply to Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID 3b1d7a91a2596baca178e8b5610b3cbc299fa5ea # Parent 1e9c6bd7cc99d1af0107aa927ee2ba03721449b7
arm: per-cpu areas

xen/arch/arm/Makefile +1 -0
diff -r 1e9c6bd7cc99 -r 3b1d7a91a259 xen/arch/arm/Makefile
@@ -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
diff -r 1e9c6bd7cc99 -r 3b1d7a91a259 xen/arch/arm/dummy.S
@@ -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
diff -r 1e9c6bd7cc99 -r 3b1d7a91a259 xen/include/asm-arm/percpu.h
@@ -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
Acked-by on v1 1/1
#14 lore raw

Re: [PATCH 06 of 10] arm: per-cpu areas

Quoted 8 lines · Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID 3b1d7a91a2596baca178e8b5610b3cbc299fa5ea # Parent 1e9c6bd7cc99d1af0107aa927ee2ba03721449b7
arm: per-cpu areas

I tried to apply this along with #1 and #4 but the result hung at just after freeing initial memory. I expect that's due to missing #2,#3 or #5 rather than a bug here.

With that in mind:

Quoted 129 lines

diff -r 1e9c6bd7cc99 -r 3b1d7a91a259 xen/arch/arm/Makefile

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

diff -r 1e9c6bd7cc99 -r 3b1d7a91a259 xen/arch/arm/dummy.S

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);

diff -r 1e9c6bd7cc99 -r 3b1d7a91a259 xen/arch/arm/percpu.c

xen/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 1e9c6bd7cc99 -r 3b1d7a91a259 xen/include/asm-arm/percpu.h

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
 
author
#15 lore raw

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 1330018799 0
# Node ID fd78d23ba19de4129e21cdc7303848b105057227 # Parent 3b1d7a91a2596baca178e8b5610b3cbc299fa5ea
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
diff -r 3b1d7a91a259 -r fd78d23ba19d xen/arch/arm/dummy.S
@@ -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
diff -r 3b1d7a91a259 -r fd78d23ba19d xen/arch/arm/setup.c
@@ -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)));
 
@@ -206,7 +203,7 @@ void __init start_xen(unsigned long boot
     cpumask_set_cpu(smp_processor_id(), &cpu_online_map);
     cpumask_set_cpu(smp_processor_id(), &cpu_present_map);
 
-    smp_prepare_cpus(max_cpus);
+    smp_prepare_cpus(cpus);
 
     init_xen_time();
 
@@ -253,7 +250,7 @@ void __init start_xen(unsigned long boot
 
     for_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

Acked-by on v1 1/1
#16 lore raw

Re: [PATCH 07 of 10] arm: start plumbing in SMP bringup in C

Quoted 10 lines · Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID fd78d23ba19de4129e21cdc7303848b105057227 # Parent 3b1d7a91a2596baca178e8b5610b3cbc299fa5ea
arm: start plumbing in SMP bringup in C

Still a noop, but no longer just a dummy symbol.

Quoted 104 lines

diff -r 3b1d7a91a259 -r fd78d23ba19d xen/arch/arm/dummy.S

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);

diff -r 3b1d7a91a259 -r fd78d23ba19d xen/arch/arm/setup.c

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)));
 
@@ -206,7 +203,7 @@ void __init start_xen(unsigned long boot
     cpumask_set_cpu(smp_processor_id(), &cpu_online_map);
     cpumask_set_cpu(smp_processor_id(), &cpu_present_map);
 
-    smp_prepare_cpus(max_cpus);
+    smp_prepare_cpus(cpus);
 
     init_xen_time();
 
@@ -253,7 +250,7 @@ void __init start_xen(unsigned long boot
 
     for_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 )

diff -r 3b1d7a91a259 -r fd78d23ba19d xen/arch/arm/smpboot.c

xen/arch/arm/smpboot.c +33 -8
@@ -19,6 +19,7 @@
 #include <xen/cpumask.h>
 #include <xen/smp.h>
 #include <xen/init.h>
+#include <xen/errno.h>
 
 cpumask_t cpu_online_map;
 EXPORT_SYMBOL(cpu_online_map);
@@ -30,16 +31,40 @@ EXPORT_SYMBOL(cpu_possible_map);
 void __init
 smp_prepare_cpus (unsigned int max_cpus)
 {
-        set_processor_id(0); /* needed early, for smp_processor_id() */
+    int i;
+    set_processor_id(0); /* needed early, for smp_processor_id() */
 
-        cpumask_clear(&cpu_online_map);
-        cpumask_clear(&cpu_present_map);
-        cpumask_clear(&cpu_possible_map);
-        cpumask_set_cpu(0, &cpu_online_map);
-        cpumask_set_cpu(0, &cpu_present_map);
-        cpumask_set_cpu(0, &cpu_possible_map);
-        return;
+    cpumask_clear(&cpu_online_map);
+    cpumask_set_cpu(0, &cpu_online_map);
+
+    cpumask_clear(&cpu_possible_map);
+    for ( i = 0; i < max_cpus; i++ )
+        cpumask_set_cpu(i, &cpu_possible_map);
+    cpumask_copy(&cpu_present_map, &cpu_possible_map);
 }
+
+/* Bring up a non-boot CPU */
+int __cpu_up(unsigned int cpu)
+{
+    /* Not yet... */
+    return -ENODEV;
+}
+
+/* Shut down the current CPU */
+void __cpu_disable(void)
+{
+    /* TODO: take down timers, GIC, &c. */
+    BUG();
+}
+
+/* Wait for a remote CPU to die */
+void __cpu_die(unsigned int cpu)
+{
+    /* TODO: interlock with __cpu_disable */
+    BUG();
+}
+
+
 /*
  * Local variables:
  * mode: C
author
#17 lore raw

PATCH 1/1 arm: Boot secondary CPUs into C

In reply to Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID d35b52e5fde829dfbaf3da73e0716d004faded2f # Parent fd78d23ba19de4129e21cdc7303848b105057227
arm: Boot secondary CPUs into C

xen/arch/arm/gic.c +9 -1
diff -r fd78d23ba19d -r d35b52e5fde8 xen/arch/arm/gic.c
@@ -241,7 +241,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;
@@ -274,6 +273,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
diff -r fd78d23ba19d -r d35b52e5fde8 xen/arch/arm/gic.h
@@ -140,6 +140,8 @@ extern int gic_route_irq_to_guest(struct
 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
xen/arch/arm/head.S +10 -4
diff -r fd78d23ba19d -r d35b52e5fde8 xen/arch/arm/head.S
@@ -305,17 +305,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_stacks       /* Find the boot-time stack */
+	ldr   sp, [r0, r12, lsl #2]  /* (the one for this CPU) */
 	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 +2 -3
diff -r fd78d23ba19d -r d35b52e5fde8 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 */
@@ -179,6 +176,8 @@ void __init start_xen(unsigned long boot
     console_init_preirq();
 #endif
 
+    percpu_init_areas();
+
     cpus = gic_init();
 
     printk("Waiting for %i other CPUs to be ready\n", cpus - 1);
xen/arch/arm/smpboot.c +77 -6

110 lines not on this page · raw message

#18 lore raw

Re: [PATCH 08 of 10] arm: Boot secondary CPUs into C

Quoted 8 lines · Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID d35b52e5fde829dfbaf3da73e0716d004faded2f # Parent fd78d23ba19de4129e21cdc7303848b105057227
arm: Boot secondary CPUs into C

I think this need rebasing a bit past the per-vcpu stacks changes so I wont' ack just yet although I like the general shape of it.

xen/arch/arm/smpboot.c EXPORT_SYMBOL(cpu_online_map); · line 42

Quoted 11 lines
xen/arch/arm/smpboot.c +7 -0
@@ -28,6 +33,14 @@ 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 cpu0_stack[STACK_SIZE]
+       __attribute__((__aligned__(STACK_SIZE)));
+
+/* Remember where the boot-time stacks live */
+/* TODO: overhaul this, and get_processor_id(), for per-vcpu stacks */
+unsigned char *init_stacks[NR_CPUS] = { cpu0_stack, 0 };

Do we need to track the per-CPU idle stacks after the CPUs have been brought up?

We are already serialized due to the use of the shared smp_up_cpu so could we get away with a single "smp_bringup_args" area and avoid the NR_CPUS array?

Ian.

author
#19 lore raw

PATCH 1/1 arm: SMP CPU shutdown

In reply to Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID a78bc9b8421492e0545c6d52c7a32b9de9737d61 # Parent d35b52e5fde829dfbaf3da73e0716d004faded2f
arm: SMP CPU shutdown

For completeness, also implelent the CPU shutdown path.

xen/arch/arm/domain.c +4 -6
diff -r d35b52e5fde8 -r a78bc9b84214 xen/arch/arm/domain.c
@@ -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
diff -r d35b52e5fde8 -r a78bc9b84214 xen/arch/arm/gic.c
@@ -235,6 +235,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;
@@ -246,6 +251,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)
 {
@@ -282,6 +292,15 @@ void __cpuinit gic_init_secondary_cpu(vo
     spin_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
diff -r d35b52e5fde8 -r a78bc9b84214 xen/arch/arm/gic.h
@@ -142,6 +142,8 @@ extern void gic_interrupt(struct cpu_use
 extern 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
diff -r d35b52e5fde8 -r a78bc9b84214 xen/include/asm-arm/smp.h
@@ -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:
#20 lore raw

Re: [PATCH 09 of 10] arm: SMP CPU shutdown

Quoted 8 lines · Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID a78bc9b8421492e0545c6d52c7a32b9de9737d61 # Parent d35b52e5fde829dfbaf3da73e0716d004faded2f
arm: SMP CPU shutdown

For completeness, also implelent the CPU shutdown path.

Does something free the init_stack for a CPU as it goes down?

Alternatively the bring up path could reuse it if the CPU came back but we don't seem to do that either.

Quoted 1 line

Typo here.

[...]

xen/arch/arm/smpboot.c void __cpuinit start_secondary(unsigned · line 119

Quoted 8 lines
xen/arch/arm/smpboot.c +8 -0
+    /* It's now safe to remove this processor from the online map */
+    cpumask_clear_cpu(cpu, &cpu_online_map);
+
+    if ( cpu_disable_scheduler(cpu) )
+        BUG();
+    mb();
+
+    /* Return to caller; eventually the IPI mecahnism will unwind and the 

mechanism

xen/arch/arm/smpboot.c void __cpuinit start_secondary(unsigned · line 126

Quoted 7 lines
xen/arch/arm/smpboot.c +7 -0
+     * scheduler will drop to the idle loop, which will call stop_cpu(). */
+}
+
+void stop_cpu(void)
+{
+    local_irq_disable();
+    cpu_is_dead = 1;

Do we lock this variable? What stops multiple CPUs coming down at once?

xen/arch/arm/smpboot.c void __cpuinit start_secondary(unsigned · line 134

Quoted 8 lines
xen/arch/arm/smpboot.c +5 -0
+    /* Make sure the write happens before we sleep forever */
+    dsb();
+    isb();
+    while ( 1 ) 
+        asm volatile("wfi");
 }
 
 /* Bring up a remote CPU */

Ian.

author
#21 lore raw

Re: [PATCH 09 of 10] arm: SMP CPU shutdown

Quoted 11 lines · Ian Campbell
Quoted 8 lines · Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID a78bc9b8421492e0545c6d52c7a32b9de9737d61 # Parent d35b52e5fde829dfbaf3da73e0716d004faded2f
arm: SMP CPU shutdown

For completeness, also implelent the CPU shutdown path.

Does something free the init_stack for a CPU as it goes down?

Er, no. :)

Quoted 2 lines

Alternatively the bring up path could reuse it if the CPU came back but we don't seem to do that either.

I'll make it so.

Quoted 3 lines
Quoted 1 line

Typo here.

WHat TYpo? I ALways SIgn MY NAme THat WAy.

Quoted 11 lines

[...]

xen/arch/arm/smpboot.c void __cpuinit start_secondary(unsigned · line 119

Quoted 8 lines
xen/arch/arm/smpboot.c +8 -0
+    /* It's now safe to remove this processor from the online map */
+    cpumask_clear_cpu(cpu, &cpu_online_map);
+
+    if ( cpu_disable_scheduler(cpu) )
+        BUG();
+    mb();
+
+    /* Return to caller; eventually the IPI mecahnism will unwind and the 

mechanism

ta.

Quoted 9 lines

xen/arch/arm/smpboot.c void __cpuinit start_secondary(unsigned · line 126

Quoted 7 lines
xen/arch/arm/smpboot.c +7 -0
+     * scheduler will drop to the idle loop, which will call stop_cpu(). */
+}
+
+void stop_cpu(void)
+{
+    local_irq_disable();
+    cpu_is_dead = 1;

Do we lock this variable? What stops multiple CPUs coming down at once?

IIRC that's serialized at a higher level, and the x86 equivalent similarly uses static variables for signalling. Will double-check before I re-send this series (probably next week).

Cheers,

Tim.

author
#22 lore raw

PATCH 1/1 arm: Shutdown and reboot

In reply to Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID 8a2d38ab67ccaf8637e223feb0d0678433974e93 # Parent a78bc9b8421492e0545c6d52c7a32b9de9737d61
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 +50 -5
diff -r a78bc9b84214 -r 8a2d38ab67cc xen/arch/arm/shutdown.c
@@ -1,18 +1,63 @@
 #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)
+{
+#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
diff -r a78bc9b84214 -r 8a2d38ab67cc xen/include/asm-arm/config.h
@@ -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__ */
 /*
Acked-by on v1 1/1
#23 lore raw

Re: [PATCH 10 of 10] arm: Shutdown and reboot

Quoted 11 lines · Tim Deegan

# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1330018799 0
# Node ID 8a2d38ab67ccaf8637e223feb0d0678433974e93 # Parent a78bc9b8421492e0545c6d52c7a32b9de9737d61
arm: Shutdown and reboot

Reboot runes grabbed from linux's SP810 reset function. Doesn't seem to work on the model, though.

But please add an "XXX get this from device tree" somewhere appropriate ;-)

Quoted 86 lines

diff -r a78bc9b84214 -r 8a2d38ab67cc xen/arch/arm/shutdown.c

xen/arch/arm/shutdown.c +50 -5
@@ -1,18 +1,63 @@
 #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)
+{
+#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

diff -r a78bc9b84214 -r 8a2d38ab67cc xen/include/asm-arm/config.h

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__ */
 /*
#24 lore raw
In reply to Tim Deegan
Quoted 5 lines · Tim Deegan

This patch series implements SMP boot for arch/arm, as far as getting all CPUs up and running the idle loop.

The first few patches are semi-independent cleanups and improvements, most of which are needed for the SMP patches later.

I have applied:
01: arm: strip xen binary
04: arm: Handle booting on SMP platforms

I looked at taking a few others but they had dependencies on things which I or others have commented on. I'll go through and ack them as appropriate now.

Ian.

#25 lore raw
In reply to Tim Deegan
Quoted 2 lines · Tim Deegan

This patch series implements SMP boot for arch/arm, as far as getting all CPUs up and running the idle loop.

What additional steps are needed when building the model to get an SMP system?

Ideally this would eventually be documented in
http://wiki.xen.org/wiki/Xen_ARMv7_with_Virtualization_Extensions/FastModels but it is probably a bit premature for that right now.

I think it is sufficient to do the following after opening the project ("sgcanvas <SGPROJ>") and before clicking the "Build" button.

* Right click the header of the "cluster" in the diagram (the top bit of the box which says "cluster" in it)
* Select "Object Properties" from the context menu
* In the "Parameters" tab update the "num_cores" variable, e.g. to "0x4"
* Click build and continue as usual.

Do that sound about right? It appears to work for me at least. I've not applied all your patches so I can't see how many processors there really are.

Ian.

author
#26 lore raw
Quoted 13 lines · Ian Campbell
Quoted 2 lines · Tim Deegan

This patch series implements SMP boot for arch/arm, as far as getting all CPUs up and running the idle loop.

What additional steps are needed when building the model to get an SMP system?

Ideally this would eventually be documented in
http://wiki.xen.org/wiki/Xen_ARMv7_with_Virtualization_Extensions/FastModels but it is probably a bit premature for that right now.

I think it is sufficient to do the following after opening the project ("sgcanvas <SGPROJ>") and before clicking the "Build" button.

Quoted 6 lines

* Right click the header of the "cluster" in the diagram (the top bit of the box which says "cluster" in it)
* Select "Object Properties" from the context menu
* In the "Parameters" tab update the "num_cores" variable, e.g. to "0x4"
* Click build and continue as usual.

Yes, that is exactly what I did.

Tim.