提交 489d18c8 编写于 作者: B Bibo Mao 提交者: Hongchen Zhang

LoongArch: Remove clock setting during cpu hotplug stage

mainline inclusion
from mainline-v5.19
commit 71610ab1
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I5OHOB
CVE: NA

--------------------------------

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: NWANG Xuerui <git@xen0n.name>
Signed-off-by: NBibo Mao <maobibo@loongson.cn>
Signed-off-by: NHuacai Chen <chenhuacai@loongson.cn>
上级 dfcdb9f7
...@@ -278,116 +278,29 @@ void loongson3_cpu_die(unsigned int cpu) ...@@ -278,116 +278,29 @@ void loongson3_cpu_die(unsigned int cpu)
mb(); mb();
} }
/* void play_dead(void)
* 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)
{ {
register int val; register uint64_t addr;
register void *addr;
register void (*init_fn)(void); register void (*init_fn)(void);
__asm__ __volatile__( idle_task_exit();
" 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));
local_irq_enable(); local_irq_enable();
change_csr_ecfg(ECFG0_IM, ECFGF_IPI); set_csr_ecfg(ECFGF_IPI);
__this_cpu_write(cpu_state, CPU_DEAD);
__smp_mb();
do {
__asm__ __volatile__("idle 0\n\t");
addr = iocsr_read64(LOONGARCH_IOCSR_MBUF0);
} while (addr == 0);
__asm__ __volatile__( init_fn = (void *)TO_CACHE(addr);
" idle 0 \n" iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_CLEAR);
" 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);
init_fn(); init_fn();
unreachable(); 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 #endif
/* /*
......
...@@ -91,7 +91,6 @@ enum cpuhp_state { ...@@ -91,7 +91,6 @@ enum cpuhp_state {
CPUHP_ZCOMP_PREPARE, CPUHP_ZCOMP_PREPARE,
CPUHP_TIMERS_PREPARE, CPUHP_TIMERS_PREPARE,
CPUHP_MIPS_SOC_PREPARE, CPUHP_MIPS_SOC_PREPARE,
CPUHP_LOONGARCH_SOC_PREPARE,
CPUHP_BP_PREPARE_DYN, CPUHP_BP_PREPARE_DYN,
CPUHP_BP_PREPARE_DYN_END = CPUHP_BP_PREPARE_DYN + 20, CPUHP_BP_PREPARE_DYN_END = CPUHP_BP_PREPARE_DYN + 20,
CPUHP_BRINGUP_CPU, CPUHP_BRINGUP_CPU,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册