Commit 8ef7f313 authored by Xianglai Li's avatar Xianglai Li Committed by Huacai Chen
Browse files

LoongArch: Add cpuhotplug hooks to fix high cpu usage of vCPU threads



When the CPU is offline, the timer of LoongArch is not correctly closed.
This is harmless for real machines, but resulting in an excessively high
cpu usage rate of the offline vCPU thread in the virtual machines.

To correctly close the timer, we have made the following modifications:

Register the cpu hotplug event (CPUHP_AP_LOONGARCH_ARCH_TIMER_STARTING)
for LoongArch. This event's hooks will be called to close the timer when
the CPU is offline.

Clear the timer interrupt when the timer is turned off. Since before the
timer is turned off, there may be a timer interrupt that has already been
in the pending state due to the interruption of the disabled, which also
affects the halt state of the offline vCPU.

Signed-off-by: default avatarXianglai Li <lixianglai@loongson.cn>
Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
parent f7794a4d
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
 */
#include <linux/clockchips.h>
#include <linux/cpuhotplug.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/init.h>
@@ -102,6 +103,23 @@ static int constant_timer_next_event(unsigned long delta, struct clock_event_dev
	return 0;
}

static int arch_timer_starting(unsigned int cpu)
{
	set_csr_ecfg(ECFGF_TIMER);

	return 0;
}

static int arch_timer_dying(unsigned int cpu)
{
	constant_set_state_shutdown(this_cpu_ptr(&constant_clockevent_device));

	/* Clear Timer Interrupt */
	write_csr_tintclear(CSR_TINTCLR_TI);

	return 0;
}

static unsigned long get_loops_per_jiffy(void)
{
	unsigned long lpj = (unsigned long)const_clock_freq;
@@ -172,6 +190,10 @@ int constant_clockevent_init(void)
	lpj_fine = get_loops_per_jiffy();
	pr_info("Constant clock event device register\n");

	cpuhp_setup_state(CPUHP_AP_LOONGARCH_ARCH_TIMER_STARTING,
			  "clockevents/loongarch/timer:starting",
			  arch_timer_starting, arch_timer_dying);

	return 0;
}

+1 −0
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ enum cpuhp_state {
	CPUHP_AP_QCOM_TIMER_STARTING,
	CPUHP_AP_TEGRA_TIMER_STARTING,
	CPUHP_AP_ARMADA_TIMER_STARTING,
	CPUHP_AP_LOONGARCH_ARCH_TIMER_STARTING,
	CPUHP_AP_MIPS_GIC_TIMER_STARTING,
	CPUHP_AP_ARC_TIMER_STARTING,
	CPUHP_AP_REALTEK_TIMER_STARTING,