From 5ffbfbbf3c3aa6f3c20c99941e3212e7b41f4474 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Tue, 12 Nov 2024 16:35:36 +0800 Subject: [PATCH 1/2] LoongArch: For all possible CPUs setup logical-physical CPU mapping commit a6654a40a852a4ca18aacced4cf5ca87997818d7 upstream In order to support ACPI-based physical CPU hotplug, we suppose for all "possible" CPUs cpu_logical_map() can work. Because some drivers want to use cpu_logical_map() for all "possible" CPUs, while currently we only setup logical-physical mapping for "present" CPUs. This lack of mapping also causes cpu_to_node() cannot work for hot-added CPUs. All "possible" CPUs are listed in MADT, and the "present" subset is marked as ACPI_MADT_ENABLED. To setup logical-physical CPU mapping for all possible CPUs and keep present CPUs continuous in cpu_present_mask, we parse MADT twice. The first pass handles CPUs with ACPI_MADT_ENABLED and the second pass handles CPUs without ACPI_MADT_ENABLED. The global flag (cpu_enumerated) is removed because acpi_map_cpu() calls cpu_number_map() rather than set_processor_mask() now. Signed-off-by: Huacai Chen Signed-off-by: Xianglai Li Signed-off-by: Kanglong Wang --- arch/loongarch/kernel/acpi.c | 67 ++++++++++++++++++++++------- arch/loongarch/kernel/legacy_boot.c | 24 +++++++++-- arch/loongarch/kernel/legacy_boot.h | 2 +- arch/loongarch/kernel/smp.c | 3 +- 4 files changed, 75 insertions(+), 21 deletions(-) diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c index b5ebc11e2e71..3503661c9d02 100644 --- a/arch/loongarch/kernel/acpi.c +++ b/arch/loongarch/kernel/acpi.c @@ -59,10 +59,9 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) } #ifdef CONFIG_SMP -int set_processor_mask(u32 id, u32 flags) +int set_processor_mask(u32 id, u32 pass) { - - int cpu, cpuid = id; + int cpu = -1, cpuid = id; if (num_processors >= nr_cpu_ids) { pr_warn(PREFIX "nr_cpus/possible_cpus limit of %i reached." @@ -71,26 +70,36 @@ int set_processor_mask(u32 id, u32 flags) return -ENODEV; } + if (cpuid == loongson_sysconf.boot_cpu_id) cpu = 0; - else - cpu = cpumask_next_zero(-1, cpu_present_mask); - - if (flags & ACPI_MADT_ENABLED) { + switch (pass) { + case 1: /* Pass 1 handle enabled processors */ + if (cpu < 0) + cpu = find_first_zero_bit(cpumask_bits(cpu_present_mask), nr_cpu_ids); num_processors++; set_cpu_possible(cpu, true); set_cpu_present(cpu, true); - __cpu_number_map[cpuid] = cpu; - __cpu_logical_map[cpu] = cpuid; - } else + break; + case 2: /* Pass 2 handle disabled processors */ + if (cpu < 0) + cpu = find_first_zero_bit(cpumask_bits(cpu_possible_mask), nr_cpu_ids); disabled_cpus++; + break; + default: + return cpu; + } + + set_cpu_possible(cpu, true); + __cpu_number_map[cpuid] = cpu; + __cpu_logical_map[cpu] = cpuid; return cpu; } #endif static int __init -acpi_parse_processor(union acpi_subtable_headers *header, const unsigned long end) +acpi_parse_p1_processor(union acpi_subtable_headers *header, const unsigned long end) { struct acpi_madt_core_pic *processor = NULL; @@ -101,12 +110,29 @@ acpi_parse_processor(union acpi_subtable_headers *header, const unsigned long en acpi_table_print_madt_entry(&header->common); #ifdef CONFIG_SMP acpi_core_pic[processor->core_id] = *processor; - set_processor_mask(processor->core_id, processor->flags); + if (processor->flags & ACPI_MADT_ENABLED) + set_processor_mask(processor->core_id, 1); #endif return 0; } +static int __init +acpi_parse_p2_processor(union acpi_subtable_headers *header, const unsigned long end) +{ + struct acpi_madt_core_pic *processor = NULL; + + processor = (struct acpi_madt_core_pic *)header; + if (BAD_MADT_ENTRY(processor, end)) + return -EINVAL; + +#ifdef CONFIG_SMP + if (!(processor->flags & ACPI_MADT_ENABLED)) + set_processor_mask(processor->core_id, 2); +#endif + + return 0; +} static int __init acpi_parse_eio_master(union acpi_subtable_headers *header, const unsigned long end) { @@ -138,7 +164,10 @@ static void __init acpi_process_madt(void) legacy_madt_table_init(); acpi_table_parse_madt(ACPI_MADT_TYPE_CORE_PIC, - acpi_parse_processor, MAX_CORE_PIC); + acpi_parse_p1_processor, MAX_CORE_PIC); + + acpi_table_parse_madt(ACPI_MADT_TYPE_CORE_PIC, + acpi_parse_p2_processor, MAX_CORE_PIC); acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC, acpi_parse_eio_master, MAX_IO_PICS); @@ -289,6 +318,10 @@ static int __ref acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) int nid; nid = acpi_get_node(handle); + + if (nid != NUMA_NO_NODE) + nid = early_cpu_to_node(cpu); + if (nid != NUMA_NO_NODE) { set_cpuid_to_node(physid, nid); node_set(nid, numa_nodes_parsed); @@ -303,12 +336,14 @@ int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu { int cpu; - cpu = set_processor_mask(physid, ACPI_MADT_ENABLED); - if (cpu < 0) { + cpu = cpu_number_map(physid); + if (cpu < 0 || cpu >= nr_cpu_ids) { pr_info(PREFIX "Unable to map lapic to logical cpu number\n"); - return cpu; + return -ERANGE; } + num_processors++; + set_cpu_present(cpu, true); acpi_map_cpu2node(handle, cpu, physid); *pcpu = cpu; diff --git a/arch/loongarch/kernel/legacy_boot.c b/arch/loongarch/kernel/legacy_boot.c index 29fdeb93dfd5..89c2eaeab07b 100644 --- a/arch/loongarch/kernel/legacy_boot.c +++ b/arch/loongarch/kernel/legacy_boot.c @@ -63,7 +63,7 @@ struct acpi_madt_msi_pic pchmsi_default[MAX_IO_PICS]; struct acpi_madt_bio_pic pchpic_default[MAX_IO_PICS]; static int -acpi_parse_lapic(union acpi_subtable_headers *header, const unsigned long end) +acpi_parse_p1_lapic(union acpi_subtable_headers *header, const unsigned long end) { struct acpi_madt_local_apic *processor = NULL; @@ -72,7 +72,24 @@ acpi_parse_lapic(union acpi_subtable_headers *header, const unsigned long end) return -EINVAL; acpi_table_print_madt_entry(&header->common); - set_processor_mask(processor->id, processor->lapic_flags); + if (processor->lapic_flags & ACPI_MADT_ENABLED) + set_processor_mask(processor->id, 1); + + return 0; +} + +static int +acpi_parse_p2_lapic(union acpi_subtable_headers *header, const unsigned long end) +{ + struct acpi_madt_local_apic *processor = NULL; + + processor = (struct acpi_madt_local_apic *)header; + if (BAD_MADT_ENTRY(processor, end)) + return -EINVAL; + + acpi_table_print_madt_entry(&header->common); + if (!(processor->lapic_flags & ACPI_MADT_ENABLED)) + set_processor_mask(processor->id, 2); return 0; } @@ -174,7 +191,8 @@ acpi_parse_legacy_pch_pic(union acpi_subtable_headers *header, const unsigned lo __init int legacy_madt_table_init(void) { /* Parse MADT LAPIC entries */ - acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC, acpi_parse_lapic, MAX_CORE_PIC); + acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC, acpi_parse_p1_lapic, MAX_CORE_PIC); + acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC, acpi_parse_p2_lapic, MAX_CORE_PIC); acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_legacy_pch_pic, MAX_IO_PICS); acpi_liointc = &liointc_default; diff --git a/arch/loongarch/kernel/legacy_boot.h b/arch/loongarch/kernel/legacy_boot.h index 65a3d14bfc60..8661d6b96639 100644 --- a/arch/loongarch/kernel/legacy_boot.h +++ b/arch/loongarch/kernel/legacy_boot.h @@ -73,7 +73,7 @@ unsigned long legacy_boot_init(unsigned long argc, extern int bpi_version; extern struct boot_params *efi_bp; extern struct loongsonlist_mem_map *g_mmap; -extern int set_processor_mask(u32 id, u32 flags); +extern int set_processor_mask(u32 id, u32 pass); extern int __init setup_legacy_IRQ(void); extern struct loongson_system_configuration loongson_sysconf; extern unsigned long long smp_group[MAX_PACKAGES]; diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c index 5b154b57e62c..df97c2a5c3ea 100644 --- a/arch/loongarch/kernel/smp.c +++ b/arch/loongarch/kernel/smp.c @@ -373,11 +373,11 @@ void __init loongson_prepare_cpus(unsigned int max_cpus) int i = 0; parse_acpi_topology(); + cpu_data[0].global_id = cpu_logical_map(0); for (i = 0; i < loongson_sysconf.nr_cpus; i++) { set_cpu_present(i, true); csr_mail_send(0, __cpu_logical_map[i], 0); - cpu_data[i].global_id = __cpu_logical_map[i]; } per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; @@ -423,6 +423,7 @@ void loongson_init_secondary(void) cpu_logical_map(cpu) / loongson_sysconf.cores_per_package; cpu_data[cpu].core = pptt_enabled ? cpu_data[cpu].core : cpu_logical_map(cpu) % loongson_sysconf.cores_per_package; + cpu_data[cpu].global_id = cpu_logical_map(cpu); } void loongson_smp_finish(void) -- Gitee From ee837a6f9b97887778cef0b6fb4884ea9035781a Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Wed, 20 Aug 2025 22:23:44 +0800 Subject: [PATCH 2/2] LoongArch: Add cpuhotplug hooks to fix high cpu usage of vCPU threads commit 8ef7f3132e4005a103b382e71abea7ad01fbeb86 upstream 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: Xianglai Li Signed-off-by: Huacai Chen Signed-off-by: Kanglong Wang --- arch/loongarch/kernel/time.c | 22 ++++++++++++++++++++++ include/linux/cpuhotplug.h | 1 + 2 files changed, 23 insertions(+) diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c index 0535e5ddbfb9..4e5df93aa9f0 100644 --- a/arch/loongarch/kernel/time.c +++ b/arch/loongarch/kernel/time.c @@ -5,6 +5,7 @@ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited */ #include +#include #include #include #include @@ -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 __init get_loops_per_jiffy(void) { unsigned long lpj = (unsigned long)const_clock_freq; @@ -168,6 +186,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; } diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 8fe128fab0a5..d316026b8b5f 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -183,6 +183,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_MARCO_TIMER_STARTING, CPUHP_AP_MIPS_GIC_TIMER_STARTING, CPUHP_AP_ARC_TIMER_STARTING, -- Gitee