int cpu_status(int nr) { u64 *table; 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; printf("table @ 0x%p\n", table); printf(" addr - 0x%016llx\n", table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX]); printf(" status - 0x%016llx\n", table[SPIN_TABLE_ELEM_STATUS_IDX]); printf(" lpid - 0x%016llx\n", table[SPIN_TABLE_ELEM_LPID_IDX]); } return 0; }
int is_core_online(u64 cpu_id) { u64 *table; int pos = id_to_core(cpu_id); table = (u64 *)get_spin_tbl_addr() + pos * WORDS_PER_SPIN_TABLE_ENTRY; return table[SPIN_TABLE_ELEM_STATUS_IDX] == 1; }
void ft_fixup_cpu(void *blob) { int off; __maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr(); fdt32_t *reg; int addr_cells; u64 val, core_id; size_t *boot_code_size = &(__secondary_boot_code_size); off = fdt_path_offset(blob, "/cpus"); if (off < 0) { puts("couldn't find /cpus node\n"); return; } of_bus_default_count_cells(blob, off, &addr_cells, NULL); off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); while (off != -FDT_ERR_NOTFOUND) { reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0); core_id = of_read_number(reg, addr_cells); if (reg) { if (core_id == 0 || (is_core_online(core_id))) { val = spin_tbl_addr; val += id_to_core(core_id) * SPIN_TABLE_ELEM_SIZE; val = cpu_to_fdt64(val); fdt_setprop_string(blob, off, "enable-method", "spin-table"); fdt_setprop(blob, off, "cpu-release-addr", &val, sizeof(val)); } else { debug("skipping offline core\n"); } } else { puts("Warning: found cpu node without reg property\n"); } off = fdt_node_offset_by_prop_value(blob, off, "device_type", "cpu", 4); } fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code, *boot_code_size); }
int cpu_release(int nr, int argc, char * const argv[]) { u64 boot_addr; u64 *table = (u64 *)get_spin_tbl_addr(); int pos; pos = core_to_pos(nr); if (pos <= 0) return -1; table += pos * WORDS_PER_SPIN_TABLE_ENTRY; boot_addr = simple_strtoull(argv[0], NULL, 16); table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX] = boot_addr; 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 */ return 0; }
void ft_fixup_cpu(void *blob) { int off; __maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr(); fdt32_t *reg; int addr_cells; u64 val, core_id; size_t *boot_code_size = &(__secondary_boot_code_size); u32 mask = cpu_pos_mask(); int off_prev = -1; off = fdt_path_offset(blob, "/cpus"); if (off < 0) { puts("couldn't find /cpus node\n"); return; } fdt_support_default_count_cells(blob, off, &addr_cells, NULL); off = fdt_node_offset_by_prop_value(blob, off_prev, "device_type", "cpu", 4); while (off != -FDT_ERR_NOTFOUND) { reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0); if (reg) { core_id = fdt_read_number(reg, addr_cells); if (!test_bit(id_to_core(core_id), &mask)) { fdt_del_node(blob, off); off = off_prev; } } off_prev = off; off = fdt_node_offset_by_prop_value(blob, off_prev, "device_type", "cpu", 4); } #if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT) && \ defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI) int node; u32 psci_ver; /* Check the psci version to determine if the psci is supported */ psci_ver = sec_firmware_support_psci_version(); if (psci_ver == 0xffffffff) { /* remove psci DT node */ node = fdt_path_offset(blob, "/psci"); if (node >= 0) goto remove_psci_node; node = fdt_node_offset_by_compatible(blob, -1, "arm,psci"); if (node >= 0) goto remove_psci_node; node = fdt_node_offset_by_compatible(blob, -1, "arm,psci-0.2"); if (node >= 0) goto remove_psci_node; node = fdt_node_offset_by_compatible(blob, -1, "arm,psci-1.0"); if (node >= 0) goto remove_psci_node; remove_psci_node: if (node >= 0) fdt_del_node(blob, node); } else { return; } #endif off = fdt_path_offset(blob, "/cpus"); if (off < 0) { puts("couldn't find /cpus node\n"); return; } fdt_support_default_count_cells(blob, off, &addr_cells, NULL); off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); while (off != -FDT_ERR_NOTFOUND) { reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0); if (reg) { core_id = fdt_read_number(reg, addr_cells); if (core_id == 0 || (is_core_online(core_id))) { val = spin_tbl_addr; val += id_to_core(core_id) * SPIN_TABLE_ELEM_SIZE; val = cpu_to_fdt64(val); fdt_setprop_string(blob, off, "enable-method", "spin-table"); fdt_setprop(blob, off, "cpu-release-addr", &val, sizeof(val)); } else { debug("skipping offline core\n"); } } else { puts("Warning: found cpu node without reg property\n"); } off = fdt_node_offset_by_prop_value(blob, off, "device_type", "cpu", 4); } fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code, *boot_code_size); #if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD) efi_add_memory_map((uintptr_t)&secondary_boot_code, ALIGN(*boot_code_size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT, EFI_RESERVED_MEMORY_TYPE, false); #endif }
int fsl_layerscape_wake_seconday_cores(void) { struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); #ifdef CONFIG_FSL_LSCH3 struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR); #elif defined(CONFIG_FSL_LSCH2) struct ccsr_scfg __iomem *scfg = (void *)(CONFIG_SYS_FSL_SCFG_ADDR); #endif u32 cores, cpu_up_mask = 1; int i, timeout = 10; u64 *table = get_spin_tbl_addr(); #ifdef COUNTER_FREQUENCY_REAL /* update for secondary cores */ __real_cntfrq = COUNTER_FREQUENCY_REAL; flush_dcache_range((unsigned long)&__real_cntfrq, (unsigned long)&__real_cntfrq + 8); #endif cores = cpu_mask(); /* Clear spin table so that secondary processors * observe the correct value after waking up from wfe. */ 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); #ifdef CONFIG_FSL_LSCH3 gur_out32(&gur->bootlocptrh, (u32)(gd->relocaddr >> 32)); gur_out32(&gur->bootlocptrl, (u32)gd->relocaddr); gur_out32(&gur->scratchrw[6], 1); asm volatile("dsb st" : : : "memory"); rst->brrl = cores; asm volatile("dsb st" : : : "memory"); #elif defined(CONFIG_FSL_LSCH2) scfg_out32(&scfg->scratchrw[0], (u32)(gd->relocaddr >> 32)); scfg_out32(&scfg->scratchrw[1], (u32)gd->relocaddr); asm volatile("dsb st" : : : "memory"); gur_out32(&gur->brrl, cores); asm volatile("dsb st" : : : "memory"); /* Bootup online cores */ scfg_out32(&scfg->corebcr, cores); #endif /* This is needed as a precautionary measure. * If some code before this has accidentally released the secondary * cores then the pre-bootloader code will trap them in a "wfe" unless * the scratchrw[6] is set. In this case we need a sev here to get these * cores moving again. */ asm volatile("sev"); while (timeout--) { flush_dcache_range((unsigned long)table, (unsigned long)table + CONFIG_MAX_CPUS * 64); for (i = 1; i < CONFIG_MAX_CPUS; i++) { if (table[i * WORDS_PER_SPIN_TABLE_ENTRY + SPIN_TABLE_ELEM_STATUS_IDX]) cpu_up_mask |= 1 << i; } if (hweight32(cpu_up_mask) == hweight32(cores)) break; udelay(10); } if (timeout <= 0) { printf("Not all cores (0x%x) are up (0x%x)\n", cores, cpu_up_mask); return 1; } printf("All (%d) cores are up.\n", hweight32(cores)); return 0; }