Patchwork [03/12] hw/arm_boot.c: Make SMP boards specify address to poll in bootup loop

login
register
mail settings
Submitter Peter Maydell
Date Jan. 13, 2012, 8:52 p.m.
Message ID <1326487969-12462-4-git-send-email-peter.maydell@linaro.org>
Download mbox | patch
Permalink /patch/135990/
State New
Headers show

Comments

Peter Maydell - Jan. 13, 2012, 8:52 p.m.
From: Evgeny Voevodin <e.voevodin@samsung.com>

The secondary CPU bootloader in arm_boot.c holds secondary CPUs in a
pen until the primary CPU releases them. Make boards specify the
address to be polled to determine whether to leave the pen (it was
previously hardcoded to 0x10000030, which is a Versatile Express/
Realview specific system register address).

Signed-off-by: Evgeny Voevodin <e.voevodin@samsung.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm-misc.h |    1 +
 hw/arm_boot.c |   18 ++++++++++--------
 hw/realview.c |    2 ++
 hw/vexpress.c |    2 ++
 4 files changed, 15 insertions(+), 8 deletions(-)
Alexander Graf - Jan. 16, 2012, 1:56 a.m.
On 13.01.2012, at 21:52, Peter Maydell wrote:

> From: Evgeny Voevodin <e.voevodin@samsung.com>
> 
> The secondary CPU bootloader in arm_boot.c holds secondary CPUs in a
> pen until the primary CPU releases them. Make boards specify the
> address to be polled to determine whether to leave the pen (it was
> previously hardcoded to 0x10000030, which is a Versatile Express/
> Realview specific system register address).

Is smp_boot implementing the same logic as hw/ppce500_spin.c? It looks like the normal u-boot way of waiting for a magic address to be written with boot info. What I don't understand is the WFI. How can you wait for an interrupt if the trigger is a memory write? Or are you actually getting IPIs?


Alex
Peter Maydell - Jan. 16, 2012, 8:31 a.m.
On 16 January 2012 01:56, Alexander Graf <agraf@suse.de> wrote:
>
> On 13.01.2012, at 21:52, Peter Maydell wrote:
>
>> From: Evgeny Voevodin <e.voevodin@samsung.com>
>>
>> The secondary CPU bootloader in arm_boot.c holds secondary CPUs in a
>> pen until the primary CPU releases them. Make boards specify the
>> address to be polled to determine whether to leave the pen (it was
>> previously hardcoded to 0x10000030, which is a Versatile Express/
>> Realview specific system register address).
>
> Is smp_boot implementing the same logic as hw/ppce500_spin.c? It
> looks like the normal u-boot way of waiting for a magic address
> to be written with boot info. What I don't understand is the WFI.
> How can you wait for an interrupt if the trigger is a memory
> write? Or are you actually getting IPIs?

Basically this code is implementing the boot-rom half of
what is technically a platform-specific contract[*] between
the boot rom and the Linux kernel. The kernel end has to
(a) write the secondary CPU's entry point into the register
being polled and (b) send the CPU a softirq (an IPI, in
other words). The WFI basically allows h/w to avoid running
3 cores at 100% when we're booting a uniprocessor OS.
So the arm_boot end has to (a) enable the CPU's interrupt
controller, (b) wait for interrupt, (c) get the entry point
and jump to it.

[*] realview, vexpress, highbank and exynos4 all do something
that's sufficiently similar that we can handle them all by
parameterising the secondary boot code a bit. omap is kinda
different but then we don't support -kernel with omap anyway.

-- PMM
andrzej zaborowski - Jan. 16, 2012, 11:31 p.m.
On 16 January 2012 09:31, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 16 January 2012 01:56, Alexander Graf <agraf@suse.de> wrote:
>>
>> On 13.01.2012, at 21:52, Peter Maydell wrote:
>>
>>> From: Evgeny Voevodin <e.voevodin@samsung.com>
>>>
>>> The secondary CPU bootloader in arm_boot.c holds secondary CPUs in a
>>> pen until the primary CPU releases them. Make boards specify the
>>> address to be polled to determine whether to leave the pen (it was
>>> previously hardcoded to 0x10000030, which is a Versatile Express/
>>> Realview specific system register address).
>>
>> Is smp_boot implementing the same logic as hw/ppce500_spin.c? It
>> looks like the normal u-boot way of waiting for a magic address
>> to be written with boot info. What I don't understand is the WFI.
>> How can you wait for an interrupt if the trigger is a memory
>> write? Or are you actually getting IPIs?
>
> Basically this code is implementing the boot-rom half of
> what is technically a platform-specific contract[*] between
> the boot rom and the Linux kernel. The kernel end has to
> (a) write the secondary CPU's entry point into the register
> being polled and (b) send the CPU a softirq (an IPI, in
> other words). The WFI basically allows h/w to avoid running
> 3 cores at 100% when we're booting a uniprocessor OS.
> So the arm_boot end has to (a) enable the CPU's interrupt
> controller, (b) wait for interrupt, (c) get the entry point
> and jump to it.
>
> [*] realview, vexpress, highbank and exynos4 all do something
> that's sufficiently similar that we can handle them all by
> parameterising the secondary boot code a bit. omap is kinda
> different but then we don't support -kernel with omap anyway.

In the last sentence you mean the SMP case, right?

Cheers
Peter Maydell - Jan. 16, 2012, 11:41 p.m.
On 16 January 2012 23:31, andrzej zaborowski <balrogg@gmail.com> wrote:
> On 16 January 2012 09:31, Peter Maydell <peter.maydell@linaro.org> wrote:
>> [*] realview, vexpress, highbank and exynos4 all do something
>> that's sufficiently similar that we can handle them all by
>> parameterising the secondary boot code a bit. omap is kinda
>> different but then we don't support -kernel with omap anyway.
>
> In the last sentence you mean the SMP case, right?

Hmm, I think I was a bit confused there. So (a) you're right that
the non-SMP case doesn't have a platform dependency so it will
work on anything that wants to call arm_load_kernel (including
omap boards). (b) omap1-3 are all single core anyhow, and I don't
know of anybody who's proposing to write an omap4 model right now
(c) the currently-out-of-tree omap3 models don't call arm_load_kernel
but instead have a model of the omap3 boot rom and just boot from
SD card images like the real hardware. [It's (c) that I was vaguely
thinking of when I wrote that remark.]

-- PMM
andrzej zaborowski - Jan. 17, 2012, 1:16 a.m.
On 13 January 2012 21:52, Peter Maydell <peter.maydell@linaro.org> wrote:
> From: Evgeny Voevodin <e.voevodin@samsung.com>
>
> The secondary CPU bootloader in arm_boot.c holds secondary CPUs in a
> pen until the primary CPU releases them. Make boards specify the
> address to be polled to determine whether to leave the pen (it was
> previously hardcoded to 0x10000030, which is a Versatile Express/
> Realview specific system register address).

I applied this patch out of the series to reduce cross dependency, thanks.

Cheers

Patch

diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index af403a1..6e8ae6b 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -31,6 +31,7 @@  struct arm_boot_info {
     const char *initrd_filename;
     target_phys_addr_t loader_start;
     target_phys_addr_t smp_loader_start;
+    target_phys_addr_t smp_bootreg_addr;
     target_phys_addr_t smp_priv_base;
     int nb_cpus;
     int board_id;
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 215d5de..bf509a8 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -31,17 +31,17 @@  static uint32_t bootloader[] = {
 /* Entry point for secondary CPUs.  Enable interrupt controller and
    Issue WFI until start address is written to system controller.  */
 static uint32_t smpboot[] = {
-  0xe59f0020, /* ldr     r0, privbase */
-  0xe3a01001, /* mov     r1, #1 */
-  0xe5801100, /* str     r1, [r0, #0x100] */
-  0xe3a00201, /* mov     r0, #0x10000000 */
-  0xe3800030, /* orr     r0, #0x30 */
+  0xe59f201c, /* ldr r2, privbase */
+  0xe59f001c, /* ldr r0, startaddr */
+  0xe3a01001, /* mov r1, #1 */
+  0xe5821100, /* str r1, [r2, #256] */
   0xe320f003, /* wfi */
   0xe5901000, /* ldr     r1, [r0] */
   0xe1110001, /* tst     r1, r1 */
   0x0afffffb, /* beq     <wfi> */
   0xe12fff11, /* bx      r1 */
-  0 /* privbase: Private memory region base address.  */
+  0,          /* privbase: Private memory region base address.  */
+  0           /* bootreg: Boot register address is held here */
 };
 
 #define WRITE_WORD(p, value) do { \
@@ -197,6 +197,7 @@  static void do_cpu_reset(void *opaque)
                                     info->loader_start);
                 }
             } else {
+                stl_phys_notdirty(info->smp_bootreg_addr, 0);
                 env->regs[15] = info->smp_loader_start;
             }
         }
@@ -272,8 +273,9 @@  void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
         rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader),
                            info->loader_start);
         if (info->nb_cpus > 1) {
-            smpboot[10] = info->smp_priv_base;
-            for (n = 0; n < sizeof(smpboot) / 4; n++) {
+            smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
+            smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base;
+            for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
                 smpboot[n] = tswap32(smpboot[n]);
             }
             rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
diff --git a/hw/realview.c b/hw/realview.c
index e52babc..d2fde44 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -21,6 +21,7 @@ 
 #include "exec-memory.h"
 
 #define SMP_BOOT_ADDR 0xe0000000
+#define SMP_BOOTREG_ADDR 0x10000030
 
 typedef struct {
     SysBusDevice busdev;
@@ -96,6 +97,7 @@  static void realview_register_devices(void)
 
 static struct arm_boot_info realview_binfo = {
     .smp_loader_start = SMP_BOOT_ADDR,
+    .smp_bootreg_addr = SMP_BOOTREG_ADDR,
 };
 
 /* The following two lists must be consistent.  */
diff --git a/hw/vexpress.c b/hw/vexpress.c
index 613be65..64fab45 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -31,11 +31,13 @@ 
 #include "exec-memory.h"
 
 #define SMP_BOOT_ADDR 0xe0000000
+#define SMP_BOOTREG_ADDR 0x10000030
 
 #define VEXPRESS_BOARD_ID 0x8e0
 
 static struct arm_boot_info vexpress_binfo = {
     .smp_loader_start = SMP_BOOT_ADDR,
+    .smp_bootreg_addr = SMP_BOOTREG_ADDR,
 };
 
 static void vexpress_a9_init(ram_addr_t ram_size,