armv8: Fix and simplify branch_if_master/branch_if_slave

The branch_if_master macro jumps to a label if the CPU is the "master"
core, which we define as having all affinity levels set to 0. To check
for this condition, we need to mask off some bits from the MPIDR
register, then compare the remaining register value against zero.

The implementation of this was slighly broken (it preserved the upper
RES0 bits), overly complicated and hard to understand, especially since
it lacked comments. The same was true for the very similar
branch_if_slave macro.

Use a much shorter assembly sequence for those checks, use the same
masking for both macros (just negate the final branch), and put some
comments on them, to make it clear what the code does.
This allows to drop the second temporary register for branch_if_master,
so we adjust all call sites as well.

Also use the opportunity to remove a misleading comment: the macro
works fine on SoCs with multiple clusters. Judging by the commit
message, the original problem with the Juno SoC stems from the fact that
the master CPU *can* be configured to be from cluster 1, so the
assumption that the master CPU has all affinity values set to 0 does not
hold there. But this is already mentioned above in a comment, so remove
the extra comment.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
This commit is contained in:
Andre Przywara 2022-02-11 11:29:39 +00:00 committed by Tom Rini
parent f660fe0bd3
commit 5ff4857d35
6 changed files with 15 additions and 28 deletions

View file

@ -200,7 +200,7 @@ ENTRY(lowlevel_init)
#endif #endif
100: 100:
branch_if_master x0, x1, 2f branch_if_master x0, 2f
#if defined(CONFIG_MP) && defined(CONFIG_ARMV8_MULTIENTRY) #if defined(CONFIG_MP) && defined(CONFIG_ARMV8_MULTIENTRY)
/* /*

View file

@ -175,11 +175,11 @@ pie_fixup_done:
bl lowlevel_init bl lowlevel_init
#if defined(CONFIG_ARMV8_SPIN_TABLE) && !defined(CONFIG_SPL_BUILD) #if defined(CONFIG_ARMV8_SPIN_TABLE) && !defined(CONFIG_SPL_BUILD)
branch_if_master x0, x1, master_cpu branch_if_master x0, master_cpu
b spin_table_secondary_jump b spin_table_secondary_jump
/* never return */ /* never return */
#elif defined(CONFIG_ARMV8_MULTIENTRY) #elif defined(CONFIG_ARMV8_MULTIENTRY)
branch_if_master x0, x1, master_cpu branch_if_master x0, master_cpu
/* /*
* Slave CPUs * Slave CPUs
@ -305,7 +305,7 @@ WEAK(lowlevel_init)
#endif #endif
#ifdef CONFIG_ARMV8_MULTIENTRY #ifdef CONFIG_ARMV8_MULTIENTRY
branch_if_master x0, x1, 2f branch_if_master x0, 2f
/* /*
* Slave should wait for master clearing spin table. * Slave should wait for master clearing spin table.

View file

@ -121,19 +121,10 @@ lr .req x30
*/ */
.macro branch_if_slave, xreg, slave_label .macro branch_if_slave, xreg, slave_label
#ifdef CONFIG_ARMV8_MULTIENTRY #ifdef CONFIG_ARMV8_MULTIENTRY
/* NOTE: MPIDR handling will be erroneous on multi-cluster machines */
mrs \xreg, mpidr_el1 mrs \xreg, mpidr_el1
tst \xreg, #0xff /* Test Affinity 0 */ and \xreg, \xreg, 0xffffffffff /* clear bits [63:40] */
b.ne \slave_label and \xreg, \xreg, ~0x00ff000000 /* also clear bits [31:24] */
lsr \xreg, \xreg, #8 cbnz \xreg, \slave_label
tst \xreg, #0xff /* Test Affinity 1 */
b.ne \slave_label
lsr \xreg, \xreg, #8
tst \xreg, #0xff /* Test Affinity 2 */
b.ne \slave_label
lsr \xreg, \xreg, #16
tst \xreg, #0xff /* Test Affinity 3 */
b.ne \slave_label
#endif #endif
.endm .endm
@ -141,16 +132,12 @@ lr .req x30
* Branch if current processor is a master, * Branch if current processor is a master,
* choose processor with all zero affinity value as the master. * choose processor with all zero affinity value as the master.
*/ */
.macro branch_if_master, xreg1, xreg2, master_label .macro branch_if_master, xreg, master_label
#ifdef CONFIG_ARMV8_MULTIENTRY #ifdef CONFIG_ARMV8_MULTIENTRY
/* NOTE: MPIDR handling will be erroneous on multi-cluster machines */ mrs \xreg, mpidr_el1
mrs \xreg1, mpidr_el1 and \xreg, \xreg, 0xffffffffff /* clear bits [63:40] */
lsr \xreg2, \xreg1, #32 and \xreg, \xreg, ~0x00ff000000 /* also clear bits [31:24] */
lsl \xreg2, \xreg2, #32 cbz \xreg, \master_label
lsl \xreg1, \xreg1, #40
lsr \xreg1, \xreg1, #40
orr \xreg1, \xreg1, \xreg2
cbz \xreg1, \master_label
#else #else
b \master_label b \master_label
#endif #endif

View file

@ -64,7 +64,7 @@ ENTRY(lowlevel_init)
#endif #endif
#endif #endif
branch_if_master x0, x1, 2f branch_if_master x0, 2f
/* /*
* Slave should wait for master clearing spin table. * Slave should wait for master clearing spin table.

View file

@ -38,7 +38,7 @@ slave_wait_atf:
#endif #endif
#ifdef CONFIG_ARMV8_MULTIENTRY #ifdef CONFIG_ARMV8_MULTIENTRY
branch_if_master x0, x1, 2f branch_if_master x0, 2f
/* /*
* Slave should wait for master clearing spin table. * Slave should wait for master clearing spin table.

View file

@ -50,7 +50,7 @@ skip_smp_setup:
#endif #endif
#ifdef CONFIG_ARMV8_MULTIENTRY #ifdef CONFIG_ARMV8_MULTIENTRY
branch_if_master x0, x1, 2f branch_if_master x0, 2f
/* /*
* Slave should wait for master clearing spin table. * Slave should wait for master clearing spin table.