LoongArch: Remove clock setting during cpu hotplug stage
authorBibo Mao <maobibo@loongson.cn>
Wed, 20 Jul 2022 07:21:51 +0000 (15:21 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Fri, 29 Jul 2022 10:22:32 +0000 (18:22 +0800)
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>
arch/loongarch/kernel/smp.c
include/linux/cpuhotplug.h

index 73cec62..0974310 100644 (file)
@@ -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);
+
+       __smp_mb();
+       do {
+               __asm__ __volatile__("idle 0\n\t");
+               addr = iocsr_read64(LOONGARCH_IOCSR_MBUF0);
+       } while (addr == 0);
 
-       __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);
+       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
 
 /*
index 19f0dbf..b66c5f3 100644 (file)
@@ -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,