From 804040d106184a93a9fe188743d1d8a8571dea71 Mon Sep 17 00:00:00 2001 From: Sandrine Bailleux Date: Fri, 10 Jul 2015 16:49:31 +0100 Subject: [PATCH] PSCI: Use a single mailbox for warm reset for FVP and Juno Since there is a unique warm reset entry point, the FVP and Juno port can use a single mailbox instead of maintaining one per core. The mailbox gets programmed only once when plat_setup_psci_ops() is invoked during PSCI initialization. This means mailbox is not zeroed out during wakeup. Change-Id: Ieba032a90b43650f970f197340ebb0ce5548d432 --- docs/porting-guide.md | 3 - include/plat/arm/css/common/css_def.h | 3 +- plat/arm/board/fvp/aarch64/fvp_helpers.S | 80 +++++++++++------------ plat/arm/board/fvp/fvp_def.h | 1 - plat/arm/board/fvp/fvp_pm.c | 31 ++------- plat/arm/css/common/aarch64/css_helpers.S | 30 ++++----- plat/arm/css/common/css_pm.c | 32 ++------- 7 files changed, 64 insertions(+), 116 deletions(-) diff --git a/docs/porting-guide.md b/docs/porting-guide.md index 0f10fd46a..81cbe1be0 100644 --- a/docs/porting-guide.md +++ b/docs/porting-guide.md @@ -468,9 +468,6 @@ return value indicates that the CPU is the primary CPU. This function is called before any access to data is made by the firmware, in order to carry out any essential memory initialization. -The ARM FVP port uses this function to initialize the mailbox memory used for -providing the warm-boot entry-point addresses. - ### Function: plat_get_rotpk_info() diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h index 268438ff6..e3dd2b0f5 100644 --- a/include/plat/arm/css/common/css_def.h +++ b/include/plat/arm/css/common/css_def.h @@ -39,8 +39,7 @@ *************************************************************************/ #define MHU_PAYLOAD_CACHED 0 -#define TRUSTED_MAILBOXES_BASE ARM_TRUSTED_SRAM_BASE -#define TRUSTED_MAILBOX_SHIFT 4 +#define TRUSTED_MAILBOX_BASE ARM_TRUSTED_SRAM_BASE #define NSROM_BASE 0x1f000000 #define NSROM_SIZE 0x00001000 diff --git a/plat/arm/board/fvp/aarch64/fvp_helpers.S b/plat/arm/board/fvp/aarch64/fvp_helpers.S index 2787ee674..9cf3c73c6 100644 --- a/plat/arm/board/fvp/aarch64/fvp_helpers.S +++ b/plat/arm/board/fvp/aarch64/fvp_helpers.S @@ -96,29 +96,30 @@ cb_panic: b cb_panic endfunc plat_secondary_cold_boot_setup - - /* ----------------------------------------------------- + /* --------------------------------------------------------------------- * unsigned long plat_get_my_entrypoint (void); * - * Main job of this routine is to distinguish between - * a cold and warm boot on the current CPU. - * On a cold boot the secondaries first wait for the - * platform to be initialized after which they are - * hotplugged in. The primary proceeds to perform the - * platform initialization. - * On a warm boot, each cpu jumps to the address in its - * mailbox. + * Main job of this routine is to distinguish between a cold and warm + * boot. On FVP, this information can be queried from the power + * controller. The Power Control SYS Status Register (PSYSR) indicates + * the wake-up reason for the CPU. + * + * For a cold boot, return 0. + * For a warm boot, read the mailbox and return the address it contains. * - * TODO: Not a good idea to save lr in a temp reg * TODO: PSYSR is a common register and should be * accessed using locks. Since its not possible * to use locks immediately after a cold reset * we are relying on the fact that after a cold * reset all cpus will read the same WK field - * ----------------------------------------------------- + * --------------------------------------------------------------------- */ func plat_get_my_entrypoint - mov x9, x30 // lr + /* --------------------------------------------------------------------- + * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC + * WakeRequest signal" then it is a warm boot. + * --------------------------------------------------------------------- + */ mrs x2, mpidr_el1 ldr x1, =PWRC_BASE str w2, [x1, #PSYSR_OFF] @@ -128,46 +129,41 @@ func plat_get_my_entrypoint beq warm_reset cmp w2, #WKUP_GICREQ beq warm_reset + + /* Cold reset */ mov x0, #0 - b exit + ret + warm_reset: - /* --------------------------------------------- - * A per-cpu mailbox is maintained in the tru- - * sted DRAM. Its flushed out of the caches - * after every update using normal memory so - * its safe to read it here with SO attributes - * --------------------------------------------- + /* --------------------------------------------------------------------- + * A mailbox is maintained in the trusted SRAM. It is flushed out of the + * caches after every update using normal memory so it is safe to read + * it here with SO attributes. + * --------------------------------------------------------------------- */ - ldr x10, =MBOX_BASE - bl plat_my_core_pos - lsl x0, x0, #ARM_CACHE_WRITEBACK_SHIFT - ldr x0, [x10, x0] + mov_imm x0, MBOX_BASE + ldr x0, [x0] cbz x0, _panic -exit: - ret x9 -_panic: b _panic + ret + + /* --------------------------------------------------------------------- + * The power controller indicates this is a warm reset but the mailbox + * is empty. This should never happen! + * --------------------------------------------------------------------- + */ +_panic: + b _panic endfunc plat_get_my_entrypoint - /* ----------------------------------------------------- + /* --------------------------------------------------------------------- * void platform_mem_init (void); * - * Zero out the mailbox registers in the shared memory. - * The mmu is turned off right now and only the primary can - * ever execute this code. Secondaries will read the - * mailboxes using SO accesses. In short, BL31 will - * update the mailboxes after mapping the tzdram as - * normal memory. It will flush its copy after update. - * BL1 will always read the mailboxes with the MMU off - * ----------------------------------------------------- + * Nothing to do on FVP, the Trusted SRAM is available straight away + * after reset. + * --------------------------------------------------------------------- */ func platform_mem_init - ldr x0, =MBOX_BASE - mov w1, #PLATFORM_CORE_COUNT -loop: - str xzr, [x0], #CACHE_WRITEBACK_GRANULE - subs w1, w1, #1 - b.gt loop ret endfunc platform_mem_init diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h index 842a287b5..692948150 100644 --- a/plat/arm/board/fvp/fvp_def.h +++ b/plat/arm/board/fvp/fvp_def.h @@ -139,7 +139,6 @@ /* Entrypoint mailboxes */ #define MBOX_BASE ARM_SHARED_RAM_BASE -#define MBOX_SIZE 0x200 #endif /* __FVP_DEF_H__ */ diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c index 56d650292..8be51054b 100644 --- a/plat/arm/board/fvp/fvp_pm.c +++ b/plat/arm/board/fvp/fvp_pm.c @@ -43,11 +43,6 @@ #include "fvp_def.h" #include "fvp_private.h" -unsigned long wakeup_address; - -typedef volatile struct mailbox { - unsigned long value __aligned(CACHE_WRITEBACK_GRANULE); -} mailbox_t; #if ARM_RECOM_STATE_ID_ENC /* @@ -74,16 +69,11 @@ const unsigned int arm_pm_idle_states[] = { * Private FVP function to program the mailbox for a cpu before it is released * from reset. ******************************************************************************/ -static void fvp_program_mailbox(uint64_t mpidr, uint64_t address) +static void fvp_program_mailbox(uintptr_t address) { - uint64_t linear_id; - mailbox_t *fvp_mboxes; - - linear_id = plat_arm_calc_core_pos(mpidr); - fvp_mboxes = (mailbox_t *)MBOX_BASE; - fvp_mboxes[linear_id].value = address; - flush_dcache_range((unsigned long) &fvp_mboxes[linear_id], - sizeof(unsigned long)); + uintptr_t *mailbox = (void *) MBOX_BASE; + *mailbox = address; + flush_dcache_range((uintptr_t) mailbox, sizeof(*mailbox)); } /******************************************************************************* @@ -150,9 +140,7 @@ int fvp_pwr_domain_on(u_register_t mpidr) psysr = fvp_pwrc_read_psysr(mpidr); } while (psysr & PSYSR_AFF_L0); - fvp_program_mailbox(mpidr, wakeup_address); fvp_pwrc_write_pponr(mpidr); - return rc; } @@ -200,9 +188,6 @@ void fvp_pwr_domain_suspend(const psci_power_state_t *target_state) /* Get the mpidr for this cpu */ mpidr = read_mpidr_el1(); - /* Program the jump address for the this cpu */ - fvp_program_mailbox(mpidr, wakeup_address); - /* Program the power controller to enable wakeup interrupts. */ fvp_pwrc_set_wen(mpidr); @@ -254,9 +239,6 @@ void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state) */ fvp_pwrc_clr_wen(mpidr); - /* Zero the jump address in the mailbox for this cpu */ - fvp_program_mailbox(mpidr, 0); - /* Enable the gic cpu interface */ arm_gic_cpuif_setup(); @@ -332,9 +314,8 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { *psci_ops = &fvp_plat_psci_ops; - wakeup_address = sec_entrypoint; - flush_dcache_range((unsigned long)&wakeup_address, - sizeof(wakeup_address)); + /* Program the jump address */ + fvp_program_mailbox(sec_entrypoint); return 0; } diff --git a/plat/arm/css/common/aarch64/css_helpers.S b/plat/arm/css/common/aarch64/css_helpers.S index a8c558b67..478d5cf2b 100644 --- a/plat/arm/css/common/aarch64/css_helpers.S +++ b/plat/arm/css/common/aarch64/css_helpers.S @@ -53,28 +53,24 @@ cb_panic: b cb_panic endfunc plat_secondary_cold_boot_setup - /* ----------------------------------------------------- + /* --------------------------------------------------------------------- * unsigned long plat_get_my_entrypoint (void); * - * Main job of this routine is to distinguish between - * a cold and warm boot on the current CPU. - * On a cold boot the secondaries first wait for the - * platform to be initialized after which they are - * hotplugged in. The primary proceeds to perform the - * platform initialization. - * On a warm boot, each cpu jumps to the address in its - * mailbox. + * Main job of this routine is to distinguish between a cold and a warm + * boot. On CSS platforms, this distinction is based on the contents of + * the Trusted Mailbox. It is initialised to zero by the SCP before the + * AP cores are released from reset. Therefore, a zero mailbox means + * it's a cold reset. * - * TODO: Not a good idea to save lr in a temp reg - * ----------------------------------------------------- + * This functions returns the contents of the mailbox, i.e.: + * - 0 for a cold boot; + * - the warm boot entrypoint for a warm boot. + * --------------------------------------------------------------------- */ func plat_get_my_entrypoint - mov x9, x30 // lr - bl plat_my_core_pos - ldr x1, =TRUSTED_MAILBOXES_BASE - lsl x0, x0, #TRUSTED_MAILBOX_SHIFT - ldr x0, [x1, x0] - ret x9 + mov_imm x0, TRUSTED_MAILBOX_BASE + ldr x0, [x0] + ret endfunc plat_get_my_entrypoint /* ----------------------------------------------------------- diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c index 49c364d5c..435ed2aa6 100644 --- a/plat/arm/css/common/css_pm.c +++ b/plat/arm/css/common/css_pm.c @@ -41,7 +41,6 @@ #include #include "css_scpi.h" -unsigned long wakeup_address; #if ARM_RECOM_STATE_ID_ENC /* @@ -68,15 +67,11 @@ const unsigned int arm_pm_idle_states[] = { * Private function to program the mailbox for a cpu before it is released * from reset. ******************************************************************************/ -static void css_program_mailbox(uint64_t mpidr, uint64_t address) +static void css_program_mailbox(uintptr_t address) { - uint64_t linear_id; - uint64_t mbox; - - linear_id = plat_arm_calc_core_pos(mpidr); - mbox = TRUSTED_MAILBOXES_BASE + (linear_id << TRUSTED_MAILBOX_SHIFT); - *((uint64_t *) mbox) = address; - flush_dcache_range(mbox, sizeof(mbox)); + uintptr_t *mailbox = (void *) TRUSTED_MAILBOX_BASE; + *mailbox = address; + flush_dcache_range((uintptr_t) mailbox, sizeof(*mailbox)); } /******************************************************************************* @@ -89,12 +84,6 @@ int css_pwr_domain_on(u_register_t mpidr) * SCP takes care of powering up parent power domains so we * only need to care about level 0 */ - - /* - * Setup mailbox with address for CPU entrypoint when it next powers up - */ - css_program_mailbox(mpidr, wakeup_address); - scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on, scpi_power_on); @@ -124,9 +113,6 @@ void css_pwr_domain_on_finish(const psci_power_state_t *target_state) /* todo: Is this setup only needed after a cold boot? */ arm_gic_pcpu_distif_setup(); - - /* Clear the mailbox for this cpu. */ - css_program_mailbox(read_mpidr_el1(), 0); } /******************************************************************************* @@ -188,11 +174,6 @@ static void css_pwr_domain_suspend(const psci_power_state_t *target_state) assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == ARM_LOCAL_STATE_OFF); - /* - * Setup mailbox with address for CPU entrypoint when it next powers up. - */ - css_program_mailbox(read_mpidr_el1(), wakeup_address); - css_power_down_common(target_state); } @@ -297,8 +278,7 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint, { *psci_ops = &css_ops; - wakeup_address = sec_entrypoint; - flush_dcache_range((unsigned long)&wakeup_address, - sizeof(wakeup_address)); + /* Setup mailbox with entry point. */ + css_program_mailbox(sec_entrypoint); return 0; }