LoongArch: Remove clock setting during cpu hotplug stage
On physical machine we can save power by disabling clock of hot removed cpu. However as different platforms require different methods to configure clocks, the code is platform-specific, and probably belongs to firmware/pmu or cpu regulator, rather than generic arch/loongarch code. Also, there is no such register on QEMU virt machine since the clock/frequency regulation is not emulated. This patch removes the hard-coded clock register accesses in generic LoongArch cpu hotplug flow. Reviewed-by: WANG Xuerui <git@xen0n.name> Signed-off-by: Bibo Mao <maobibo@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This commit is contained in:
parent
f62b7626cb
commit
71610ab1d0
@ -278,116 +278,29 @@ void loongson3_cpu_die(unsigned int cpu)
|
||||
mb();
|
||||
}
|
||||
|
||||
/*
|
||||
* The target CPU should go to XKPRANGE (uncached area) and flush
|
||||
* ICache/DCache/VCache before the control CPU can safely disable its clock.
|
||||
*/
|
||||
static void loongson3_play_dead(int *state_addr)
|
||||
void play_dead(void)
|
||||
{
|
||||
register int val;
|
||||
register void *addr;
|
||||
register uint64_t addr;
|
||||
register void (*init_fn)(void);
|
||||
|
||||
__asm__ __volatile__(
|
||||
" li.d %[addr], 0x8000000000000000\n"
|
||||
"1: cacop 0x8, %[addr], 0 \n" /* flush ICache */
|
||||
" cacop 0x8, %[addr], 1 \n"
|
||||
" cacop 0x8, %[addr], 2 \n"
|
||||
" cacop 0x8, %[addr], 3 \n"
|
||||
" cacop 0x9, %[addr], 0 \n" /* flush DCache */
|
||||
" cacop 0x9, %[addr], 1 \n"
|
||||
" cacop 0x9, %[addr], 2 \n"
|
||||
" cacop 0x9, %[addr], 3 \n"
|
||||
" addi.w %[sets], %[sets], -1 \n"
|
||||
" addi.d %[addr], %[addr], 0x40 \n"
|
||||
" bnez %[sets], 1b \n"
|
||||
" li.d %[addr], 0x8000000000000000\n"
|
||||
"2: cacop 0xa, %[addr], 0 \n" /* flush VCache */
|
||||
" cacop 0xa, %[addr], 1 \n"
|
||||
" cacop 0xa, %[addr], 2 \n"
|
||||
" cacop 0xa, %[addr], 3 \n"
|
||||
" cacop 0xa, %[addr], 4 \n"
|
||||
" cacop 0xa, %[addr], 5 \n"
|
||||
" cacop 0xa, %[addr], 6 \n"
|
||||
" cacop 0xa, %[addr], 7 \n"
|
||||
" cacop 0xa, %[addr], 8 \n"
|
||||
" cacop 0xa, %[addr], 9 \n"
|
||||
" cacop 0xa, %[addr], 10 \n"
|
||||
" cacop 0xa, %[addr], 11 \n"
|
||||
" cacop 0xa, %[addr], 12 \n"
|
||||
" cacop 0xa, %[addr], 13 \n"
|
||||
" cacop 0xa, %[addr], 14 \n"
|
||||
" cacop 0xa, %[addr], 15 \n"
|
||||
" addi.w %[vsets], %[vsets], -1 \n"
|
||||
" addi.d %[addr], %[addr], 0x40 \n"
|
||||
" bnez %[vsets], 2b \n"
|
||||
" li.w %[val], 0x7 \n" /* *state_addr = CPU_DEAD; */
|
||||
" st.w %[val], %[state_addr], 0 \n"
|
||||
" dbar 0 \n"
|
||||
" cacop 0x11, %[state_addr], 0 \n" /* flush entry of *state_addr */
|
||||
: [addr] "=&r" (addr), [val] "=&r" (val)
|
||||
: [state_addr] "r" (state_addr),
|
||||
[sets] "r" (cpu_data[smp_processor_id()].dcache.sets),
|
||||
[vsets] "r" (cpu_data[smp_processor_id()].vcache.sets));
|
||||
|
||||
idle_task_exit();
|
||||
local_irq_enable();
|
||||
change_csr_ecfg(ECFG0_IM, ECFGF_IPI);
|
||||
set_csr_ecfg(ECFGF_IPI);
|
||||
__this_cpu_write(cpu_state, CPU_DEAD);
|
||||
|
||||
__asm__ __volatile__(
|
||||
" idle 0 \n"
|
||||
" li.w $t0, 0x1020 \n"
|
||||
" iocsrrd.d %[init_fn], $t0 \n" /* Get init PC */
|
||||
: [init_fn] "=&r" (addr)
|
||||
: /* No Input */
|
||||
: "a0");
|
||||
init_fn = __va(addr);
|
||||
__smp_mb();
|
||||
do {
|
||||
__asm__ __volatile__("idle 0\n\t");
|
||||
addr = iocsr_read64(LOONGARCH_IOCSR_MBUF0);
|
||||
} while (addr == 0);
|
||||
|
||||
init_fn = (void *)TO_CACHE(addr);
|
||||
iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_CLEAR);
|
||||
|
||||
init_fn();
|
||||
unreachable();
|
||||
}
|
||||
|
||||
void play_dead(void)
|
||||
{
|
||||
int *state_addr;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
void (*play_dead_uncached)(int *s);
|
||||
|
||||
idle_task_exit();
|
||||
play_dead_uncached = (void *)TO_UNCACHE(__pa((unsigned long)loongson3_play_dead));
|
||||
state_addr = &per_cpu(cpu_state, cpu);
|
||||
mb();
|
||||
play_dead_uncached(state_addr);
|
||||
}
|
||||
|
||||
static int loongson3_enable_clock(unsigned int cpu)
|
||||
{
|
||||
uint64_t core_id = cpu_data[cpu].core;
|
||||
uint64_t package_id = cpu_data[cpu].package;
|
||||
|
||||
LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongson3_disable_clock(unsigned int cpu)
|
||||
{
|
||||
uint64_t core_id = cpu_data[cpu].core;
|
||||
uint64_t package_id = cpu_data[cpu].package;
|
||||
|
||||
LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_loongson3_notifier(void)
|
||||
{
|
||||
return cpuhp_setup_state_nocalls(CPUHP_LOONGARCH_SOC_PREPARE,
|
||||
"loongarch/loongson:prepare",
|
||||
loongson3_enable_clock,
|
||||
loongson3_disable_clock);
|
||||
}
|
||||
early_initcall(register_loongson3_notifier);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -130,7 +130,6 @@ enum cpuhp_state {
|
||||
CPUHP_ZCOMP_PREPARE,
|
||||
CPUHP_TIMERS_PREPARE,
|
||||
CPUHP_MIPS_SOC_PREPARE,
|
||||
CPUHP_LOONGARCH_SOC_PREPARE,
|
||||
CPUHP_BP_PREPARE_DYN,
|
||||
CPUHP_BP_PREPARE_DYN_END = CPUHP_BP_PREPARE_DYN + 20,
|
||||
CPUHP_BRINGUP_CPU,
|
||||
|
Loading…
Reference in New Issue
Block a user