diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c index b5ebc11e2e71c3e94a4b6c5cf5e3941544c12bca..3503661c9d027652a38b347e090067e8303a3e3b 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 29fdeb93dfd5eeb496168e357bc03dc44437fe9e..89c2eaeab07b5855849098b91b4ecef3258763ca 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 65a3d14bfc6081cab4e345dae3aa350aadbdfc8c..8661d6b96639213d5b36a350b6e19d246da43349 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 5b154b57e62c08df298c373f75c03ec42e3d920d..df97c2a5c3ea6579982e24083ff028ba733980cc 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) diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c index 0535e5ddbfb9c9ca01b90e7bf277d9ad1f9b7944..4e5df93aa9f012352d52a2cc7e775bf0d5bb1da0 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 8fe128fab0a52de8533bf9de01397645d608b24f..d316026b8b5f0634936d2e7cab7afaa5926cc8d9 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,