|
@@ -6,6 +6,7 @@
|
|
|
#include <common.h>
|
|
|
#include <cpu_func.h>
|
|
|
#include <image.h>
|
|
|
+#include <log.h>
|
|
|
#include <asm/cache.h>
|
|
|
#include <asm/io.h>
|
|
|
#include <asm/system.h>
|
|
@@ -14,17 +15,14 @@
|
|
|
#include <linux/delay.h>
|
|
|
#include "cpu.h"
|
|
|
#include <asm/arch-fsl-layerscape/soc.h>
|
|
|
+#include <efi_loader.h>
|
|
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
|
|
void *get_spin_tbl_addr(void)
|
|
|
{
|
|
|
- return &__spin_table;
|
|
|
-}
|
|
|
-
|
|
|
-phys_addr_t determine_mp_bootpg(void)
|
|
|
-{
|
|
|
- return (phys_addr_t)&secondary_boot_code;
|
|
|
+ /* the spin table is at the beginning */
|
|
|
+ return secondary_boot_code_start;
|
|
|
}
|
|
|
|
|
|
void update_os_arch_secondary_cores(uint8_t os_arch)
|
|
@@ -43,7 +41,7 @@ void update_os_arch_secondary_cores(uint8_t os_arch)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_FSL_LSCH3
|
|
|
-void wake_secondary_core_n(int cluster, int core, int cluster_cores)
|
|
|
+static void wake_secondary_core_n(int cluster, int core, int cluster_cores)
|
|
|
{
|
|
|
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
|
|
struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR);
|
|
@@ -80,7 +78,11 @@ int fsl_layerscape_wake_seconday_cores(void)
|
|
|
#endif
|
|
|
u32 cores, cpu_up_mask = 1;
|
|
|
int i, timeout = 10;
|
|
|
- u64 *table = get_spin_tbl_addr();
|
|
|
+ u64 *table;
|
|
|
+#ifdef CONFIG_EFI_LOADER
|
|
|
+ u64 reloc_addr = U32_MAX;
|
|
|
+ efi_status_t ret;
|
|
|
+#endif
|
|
|
|
|
|
#ifdef COUNTER_FREQUENCY_REAL
|
|
|
/* update for secondary cores */
|
|
@@ -89,16 +91,49 @@ int fsl_layerscape_wake_seconday_cores(void)
|
|
|
(unsigned long)&__real_cntfrq + 8);
|
|
|
#endif
|
|
|
|
|
|
+#ifdef CONFIG_EFI_LOADER
|
|
|
+ /*
|
|
|
+ * EFI will reserve 64kb for its runtime services. This will probably
|
|
|
+ * overlap with our spin table code, which is why we have to relocate
|
|
|
+ * it.
|
|
|
+ * Keep this after the __real_cntfrq update, so we have it when we
|
|
|
+ * copy the complete section here.
|
|
|
+ */
|
|
|
+ ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
|
|
|
+ EFI_RESERVED_MEMORY_TYPE,
|
|
|
+ efi_size_in_pages(secondary_boot_code_size),
|
|
|
+ &reloc_addr);
|
|
|
+ if (ret == EFI_SUCCESS) {
|
|
|
+ debug("Relocating spin table from %llx to %llx (size %lx)\n",
|
|
|
+ (u64)secondary_boot_code_start, reloc_addr,
|
|
|
+ secondary_boot_code_size);
|
|
|
+ memcpy((void *)reloc_addr, secondary_boot_code_start,
|
|
|
+ secondary_boot_code_size);
|
|
|
+ flush_dcache_range(reloc_addr,
|
|
|
+ reloc_addr + secondary_boot_code_size);
|
|
|
+
|
|
|
+ /* set new entry point for secondary cores */
|
|
|
+ secondary_boot_addr += (void *)reloc_addr -
|
|
|
+ secondary_boot_code_start;
|
|
|
+ flush_dcache_range((unsigned long)&secondary_boot_addr,
|
|
|
+ (unsigned long)&secondary_boot_addr + 8);
|
|
|
+
|
|
|
+ /* this will be used to reserve the memory */
|
|
|
+ secondary_boot_code_start = (void *)reloc_addr;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
cores = cpu_mask();
|
|
|
/* Clear spin table so that secondary processors
|
|
|
* observe the correct value after waking up from wfe.
|
|
|
*/
|
|
|
+ table = get_spin_tbl_addr();
|
|
|
memset(table, 0, CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE);
|
|
|
flush_dcache_range((unsigned long)table,
|
|
|
(unsigned long)table +
|
|
|
(CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE));
|
|
|
|
|
|
- printf("Waking secondary cores to start from %lx\n", gd->relocaddr);
|
|
|
+ debug("Waking secondary cores to start from %lx\n", gd->relocaddr);
|
|
|
|
|
|
#ifdef CONFIG_FSL_LSCH3
|
|
|
gur_out32(&gur->bootlocptrh, (u32)(gd->relocaddr >> 32));
|
|
@@ -168,11 +203,11 @@ int fsl_layerscape_wake_seconday_cores(void)
|
|
|
udelay(10);
|
|
|
}
|
|
|
if (timeout <= 0) {
|
|
|
- printf("Not all cores (0x%x) are up (0x%x)\n",
|
|
|
- cores, cpu_up_mask);
|
|
|
+ printf("CPU: Failed to bring up some cores (mask 0x%x)\n",
|
|
|
+ cores ^ cpu_up_mask);
|
|
|
return 1;
|
|
|
}
|
|
|
- printf("All (%d) cores are up.\n", hweight32(cores));
|
|
|
+ printf("CPU: %d cores online\n", hweight32(cores));
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -189,9 +224,9 @@ static int is_pos_valid(unsigned int pos)
|
|
|
|
|
|
int is_core_online(u64 cpu_id)
|
|
|
{
|
|
|
- u64 *table;
|
|
|
+ u64 *table = get_spin_tbl_addr();
|
|
|
int pos = id_to_core(cpu_id);
|
|
|
- table = (u64 *)get_spin_tbl_addr() + pos * WORDS_PER_SPIN_TABLE_ENTRY;
|
|
|
+ table += pos * WORDS_PER_SPIN_TABLE_ENTRY;
|
|
|
return table[SPIN_TABLE_ELEM_STATUS_IDX] == 1;
|
|
|
}
|
|
|
|
|
@@ -237,18 +272,16 @@ static int core_to_pos(int nr)
|
|
|
|
|
|
int cpu_status(u32 nr)
|
|
|
{
|
|
|
- u64 *table;
|
|
|
+ u64 *table = get_spin_tbl_addr();
|
|
|
int pos;
|
|
|
|
|
|
if (nr == 0) {
|
|
|
- table = (u64 *)get_spin_tbl_addr();
|
|
|
printf("table base @ 0x%p\n", table);
|
|
|
} else {
|
|
|
pos = core_to_pos(nr);
|
|
|
if (pos < 0)
|
|
|
return -1;
|
|
|
- table = (u64 *)get_spin_tbl_addr() + pos *
|
|
|
- WORDS_PER_SPIN_TABLE_ENTRY;
|
|
|
+ table += pos * WORDS_PER_SPIN_TABLE_ENTRY;
|
|
|
printf("table @ 0x%p\n", table);
|
|
|
printf(" addr - 0x%016llx\n",
|
|
|
table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX]);
|
|
@@ -264,7 +297,7 @@ int cpu_status(u32 nr)
|
|
|
int cpu_release(u32 nr, int argc, char *const argv[])
|
|
|
{
|
|
|
u64 boot_addr;
|
|
|
- u64 *table = (u64 *)get_spin_tbl_addr();
|
|
|
+ u64 *table = get_spin_tbl_addr();
|
|
|
int pos;
|
|
|
|
|
|
pos = core_to_pos(nr);
|
|
@@ -277,11 +310,12 @@ int cpu_release(u32 nr, int argc, char *const argv[])
|
|
|
flush_dcache_range((unsigned long)table,
|
|
|
(unsigned long)table + SPIN_TABLE_ELEM_SIZE);
|
|
|
asm volatile("dsb st");
|
|
|
- smp_kick_all_cpus(); /* only those with entry addr set will run */
|
|
|
+
|
|
|
/*
|
|
|
- * When the first release command runs, all cores are set to go. Those
|
|
|
- * without a valid entry address will be trapped by "wfe". "sev" kicks
|
|
|
- * them off to check the address again. When set, they continue to run.
|
|
|
+ * The secondary CPUs polling the spin-table above for a non-zero
|
|
|
+ * value. To save power "wfe" is called. Thus call "sev" here to
|
|
|
+ * wake the CPUs and let them check the spin-table again (see
|
|
|
+ * slave_cpu loop in lowlevel.S)
|
|
|
*/
|
|
|
asm volatile("sev");
|
|
|
|