From 548d3d141c8a54c1b56cbeaf5d88186734f37c5b Mon Sep 17 00:00:00 2001 From: Gu Yuchen Date: Tue, 3 Jun 2025 11:12:08 +0800 Subject: [PATCH 1/8] sw64: set module region to the 2GB space below vmalloc area Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICC5ID -------------------------------- The module region used to be allocated across the entire vmalloc area using generic module_alloc function. If a considerable portion of the vmalloc area is occupied by a large application, the sections of the same module are scattered beyond the relocation limit of the module. Architecture-specific module_alloc is implemented, moving modules to the 2GB region before vmalloc_start. Signed-off-by: Gu Yuchen Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/pgtable.h | 4 +++- arch/sw_64/kernel/module.c | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/sw_64/include/asm/pgtable.h b/arch/sw_64/include/asm/pgtable.h index 189580d524bf..82881f9e3fae 100644 --- a/arch/sw_64/include/asm/pgtable.h +++ b/arch/sw_64/include/asm/pgtable.h @@ -78,7 +78,9 @@ static inline void set_p4d(p4d_t *p4dp, p4d_t p4d) /* Number of pointers that fit on a page: this will go away. */ #define PTRS_PER_PAGE (1UL << (PAGE_SHIFT - 3)) -#define VMALLOC_START (-2 * PGDIR_SIZE) +#define MODULES_VADDR 0xfffff00000000000 +#define MODULES_END 0xfffff0007fffffff +#define VMALLOC_START 0xfffff00080000000 #ifndef CONFIG_SPARSEMEM_VMEMMAP #define VMALLOC_END (-PGDIR_SIZE) #else diff --git a/arch/sw_64/kernel/module.c b/arch/sw_64/kernel/module.c index 2904bb750eb5..8c08115fd615 100644 --- a/arch/sw_64/kernel/module.c +++ b/arch/sw_64/kernel/module.c @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include +#include +#include #define DEBUGP(fmt...) @@ -280,3 +283,10 @@ apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, return 0; } + +void *module_alloc(unsigned long size) +{ + return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, + GFP_KERNEL, PAGE_KERNEL, 0, + NUMA_NO_NODE, __builtin_return_address(0)); +} -- Gitee From 19e59a648305820a5bb67c06bcbf178e78795c61 Mon Sep 17 00:00:00 2001 From: Lei Yilong Date: Tue, 10 Jun 2025 09:31:34 +0800 Subject: [PATCH 2/8] sw64: pintc: fix guest pintc init Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICC5ID -------------------------------- Ioremap now map I/O physical addresses to the vmalloc segment instead of use __va() . Guest passes size 0 to ioremap, it will return NULL. Actually, the guest will not use this io address, so we skip this address check directly. Signed-off-by: Lei Yilong Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/irqchip/irq-sunway-pintc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-sunway-pintc.c b/drivers/irqchip/irq-sunway-pintc.c index f6dc603e43b2..6821c8a6d0cc 100644 --- a/drivers/irqchip/irq-sunway-pintc.c +++ b/drivers/irqchip/irq-sunway-pintc.c @@ -671,7 +671,7 @@ static int __init pintc_acpi_init_mcu(struct pintc_chip_data *chip_data, chip_data->mcu_irq_num = mcu->gsi_count; chip_data->mcu_base = ioremap(mcu->address, mcu->size); - if (!chip_data->mcu_base) { + if (!chip_data->vt && !chip_data->mcu_base) { pr_err("failed to map mcu base address\n"); ret = -ENXIO; goto out_acpi_free_fwnode; @@ -762,7 +762,7 @@ int __init pintc_acpi_init(struct irq_domain *parent, chip_data->version = pintc->version; chip_data->pintc_base = ioremap(pintc->address, pintc->size); - if (!chip_data->pintc_base) { + if (!virtual && !chip_data->pintc_base) { pr_err("failed to map pintc base address\n"); ret = -ENXIO; goto out_acpi_free_chip_data; -- Gitee From 3d39a42086f5c81a66959c51869c399ee9d7228d Mon Sep 17 00:00:00 2001 From: Yu Jiayi Date: Fri, 6 Jun 2025 10:50:19 +0800 Subject: [PATCH 3/8] sw64: kvm: fix undefined compile issues for kvm module Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICC5ID -------------------------------- If use 'CONFIG_KVM=m' to compile, smp_rcb and run_mode_guest_key are undefined. Their use is introduced by optimizing the guest interrupt. This patch we export smp_rcb definition to symbol table and avoid run_mode_guest_key call in guest interrupt notification. Signed-off-by: Yu Jiayi Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/smp.c | 1 + arch/sw_64/kvm/kvm_core4.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/sw_64/kernel/smp.c b/arch/sw_64/kernel/smp.c index 51a75938de53..6f31481e32ab 100644 --- a/arch/sw_64/kernel/smp.c +++ b/arch/sw_64/kernel/smp.c @@ -22,6 +22,7 @@ #include "proto.h" struct smp_rcb_struct *smp_rcb; +EXPORT_SYMBOL(smp_rcb); extern struct cpuinfo_sw64 cpu_data[NR_CPUS]; diff --git a/arch/sw_64/kvm/kvm_core4.c b/arch/sw_64/kvm/kvm_core4.c index d1d04f9f8f54..0a1e33020fb0 100644 --- a/arch/sw_64/kvm/kvm_core4.c +++ b/arch/sw_64/kvm/kvm_core4.c @@ -134,6 +134,7 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) static int feat_vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number) { + int rcid; int cpu = vcpu->cpu; int me = smp_processor_id(); @@ -144,7 +145,9 @@ static int feat_vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number) && cpu_online(cpu)) { if (vcpu->arch.vcb.vcpu_irq_disabled) return 0; - send_ipi(cpu, II_II1); + /* send_ipi */ + rcid = cpu_to_rcid(cpu); + sendii(rcid, II_II1, 0); } } else kvm_vcpu_kick(vcpu); -- Gitee From 8fe00d6254ca6c79a23902253b79c531e9f514b1 Mon Sep 17 00:00:00 2001 From: Gu Yuchen Date: Fri, 6 Jun 2025 16:34:58 +0800 Subject: [PATCH 4/8] sw64: ftrace: remove temporary registers left in context saving Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICC5ID -------------------------------- In the ftrace context saving process, unused temporary registers do not need to be saved and restored. In previous modifications, the temporary registers $22-$25 are not removed. This commit removes them. Signed-off-by: Gu Yuchen Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/entry-ftrace.S | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/sw_64/kernel/entry-ftrace.S b/arch/sw_64/kernel/entry-ftrace.S index c56166d434eb..bdd6cd5a63a8 100644 --- a/arch/sw_64/kernel/entry-ftrace.S +++ b/arch/sw_64/kernel/entry-ftrace.S @@ -104,10 +104,6 @@ stl $19, PT_REGS_R19($sp) stl $20, PT_REGS_R20($sp) stl $21, PT_REGS_R21($sp) - stl $22, PT_REGS_R22($sp) - stl $23, PT_REGS_R23($sp) - stl $24, PT_REGS_R24($sp) - stl $25, PT_REGS_R25($sp) stl $26, PT_REGS_R26($sp) stl $27, PT_REGS_R27($sp) stl $28, PT_REGS_R28($sp) @@ -132,10 +128,6 @@ ldl $19, PT_REGS_R19($sp) ldl $20, PT_REGS_R20($sp) ldl $21, PT_REGS_R21($sp) - ldl $22, PT_REGS_R22($sp) - ldl $23, PT_REGS_R23($sp) - ldl $24, PT_REGS_R24($sp) - ldl $25, PT_REGS_R25($sp) ldl $26, PT_REGS_R26($sp) ldl $27, PT_REGS_R27($sp) ldl $28, PT_REGS_R28($sp) -- Gitee From a0bec4f7ed4fd315fcded64c9083518a19df7292 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Mon, 28 Apr 2025 10:59:33 +0800 Subject: [PATCH 5/8] sw64: cpufreq: optimize the granularity of cpufreq Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICC5ID -------------------------------- Optimize the granularity of cpufreq according to the actual clock domain to improve system energy efficiency. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/cpu.h | 20 +++++- arch/sw_64/kernel/cpu.c | 32 +++++----- arch/sw_64/kernel/setup.c | 2 +- arch/sw_64/kernel/time.c | 2 +- arch/sw_64/lib/udelay.c | 4 +- drivers/clocksource/timer-sw64.c | 20 ++---- drivers/cpufreq/sunway-cpufreq.c | 103 ++++++++++++++++--------------- 7 files changed, 97 insertions(+), 86 deletions(-) diff --git a/arch/sw_64/include/asm/cpu.h b/arch/sw_64/include/asm/cpu.h index 1b8c479e4e6a..d8a87f54fe60 100644 --- a/arch/sw_64/include/asm/cpu.h +++ b/arch/sw_64/include/asm/cpu.h @@ -6,6 +6,9 @@ #include #include +#define KHZ (1000UL) +#define MHZ (1000UL * 1000UL) + #define current_cpu_data cpu_data[smp_processor_id()] enum hmcall_cpuid_cmd { @@ -47,10 +50,23 @@ extern struct cpuinfo_sw64 cpu_data[NR_CPUS]; extern cpumask_t cpu_offline; extern void store_cpu_data(int cpu); -extern unsigned long get_cpu_freq(void); -extern void update_cpu_freq(unsigned long khz); extern unsigned int get_cpu_cache_size(int cpu, int level, enum cache_type type); extern unsigned int get_cpu_cacheline_size(int cpu, int level, enum cache_type type); +/* Hz */ +static inline unsigned long sunway_max_cpu_freq(void) +{ + return cpuid(GET_CPU_FREQ, 0) * MHZ; +} + +#ifdef CONFIG_SW64_CPUFREQ +extern unsigned long get_cpu_freq(unsigned int cpu); +#else +static inline unsigned long get_cpu_freq(unsigned int cpu) +{ + return sunway_max_cpu_freq(); +} +#endif + #endif /* _ASM_SW64_CPU_H */ diff --git a/arch/sw_64/kernel/cpu.c b/arch/sw_64/kernel/cpu.c index a30a825997da..84b4a66a06e9 100644 --- a/arch/sw_64/kernel/cpu.c +++ b/arch/sw_64/kernel/cpu.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -40,25 +41,11 @@ EXPORT_SYMBOL(cpu_data); cpumask_t cpu_offline = CPU_MASK_NONE; -static unsigned long cpu_freq; static unsigned long cpu_info; static __u16 family; static char vendor_id[64]; static char model_id[64]; -unsigned long get_cpu_freq(void) -{ - if (likely(cpu_freq)) - return cpu_freq; - - return cpuid(GET_CPU_FREQ, 0) * 1000UL * 1000UL; -} - -void update_cpu_freq(unsigned long khz) -{ - cpu_freq = khz * 1000; -} - /* Move global data into per-processor storage */ void store_cpu_data(int cpu) { @@ -240,7 +227,7 @@ static int show_cpuinfo(struct seq_file *f, void *slot) unsigned int l3_cache_size, l3_cachline_size; unsigned long freq; - freq = cpuid(GET_CPU_FREQ, 0); + freq = sunway_max_cpu_freq() / MHZ; for_each_online_cpu(i) { l3_cache_size = get_cpu_cache_size(i, 3, CACHE_TYPE_UNIFIED); @@ -267,7 +254,7 @@ static int show_cpuinfo(struct seq_file *f, void *slot) "cache size\t: %u KB\n" "physical id\t: %d\n" "bogomips\t: %lu.%02lu\n", - get_cpu_freq() / 1000 / 1000, l3_cache_size >> 10, + get_cpu_freq(i) / 1000 / 1000, l3_cache_size >> 10, cpu_topology[i].package_id, loops_per_jiffy / (500000/HZ), (loops_per_jiffy / (5000/HZ)) % 100); @@ -313,3 +300,16 @@ bool arch_match_cpu_phys_id(int cpu, u64 phys_id) return phys_id == cpu_physical_id(cpu); } +#ifdef CONFIG_SW64_CPUFREQ + +unsigned long get_cpu_freq(unsigned int cpu) +{ + unsigned long freq = cpufreq_quick_get(cpu); + + if (likely(freq)) + return freq * KHZ; + + return sunway_max_cpu_freq(); +} + +#endif diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index 83611fba0092..6ddccb4a5822 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -137,7 +137,7 @@ EXPORT_SYMBOL(screen_info); #ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF u64 hw_nmi_get_sample_period(int watchdog_thresh) { - return get_cpu_freq() * watchdog_thresh; + return sunway_max_cpu_freq() * watchdog_thresh; } #endif diff --git a/arch/sw_64/kernel/time.c b/arch/sw_64/kernel/time.c index 503f9e1beb43..c6cefd4383b5 100644 --- a/arch/sw_64/kernel/time.c +++ b/arch/sw_64/kernel/time.c @@ -31,7 +31,7 @@ time_init(void) { unsigned long cycle_freq; - cycle_freq = get_cpu_freq(); + cycle_freq = sunway_max_cpu_freq(); pr_info("CPU Cycle frequency = %ld Hz\n", cycle_freq); diff --git a/arch/sw_64/lib/udelay.c b/arch/sw_64/lib/udelay.c index c60601d56b0e..ba5efe4b4549 100644 --- a/arch/sw_64/lib/udelay.c +++ b/arch/sw_64/lib/udelay.c @@ -32,7 +32,7 @@ EXPORT_SYMBOL(__delay); void udelay(unsigned long usecs) { - unsigned long loops = usecs * get_cpu_freq() / 1000000; + unsigned long loops = usecs * get_cpu_freq(smp_processor_id()) / 1000000; unsigned long tmp; __asm__ __volatile__( @@ -47,7 +47,7 @@ EXPORT_SYMBOL(udelay); void ndelay(unsigned long nsecs) { - unsigned long loops = nsecs * get_cpu_freq() / 1000000000; + unsigned long loops = nsecs * get_cpu_freq(smp_processor_id()) / 1000000000; unsigned long tmp; __asm__ __volatile__( diff --git a/drivers/clocksource/timer-sw64.c b/drivers/clocksource/timer-sw64.c index e83c8b5230d3..ac5901c83eba 100644 --- a/drivers/clocksource/timer-sw64.c +++ b/drivers/clocksource/timer-sw64.c @@ -174,7 +174,7 @@ void __init sw64_setup_clocksource(void) else clocksource_register_khz(&clocksource_vtime, mclk_khz); #else - clocksource_register_hz(&clocksource_tc, get_cpu_freq()); + clocksource_register_hz(&clocksource_tc, sunway_max_cpu_freq()); pr_info("Setup clocksource TC, mult = %d\n", clocksource_tc.mult); #endif } @@ -208,23 +208,13 @@ void __init setup_sched_clock(void) sc_shift = 7; step = 1UL << sc_shift; - sc_multi = step * NSEC_PER_SEC / get_cpu_freq(); + sc_multi = step * NSEC_PER_SEC / sunway_max_cpu_freq(); calibrate_sched_clock(); pr_info("sched_clock: sc_multi=%llu, sc_shift=%llu\n", sc_multi, sc_shift); } -#ifdef CONFIG_GENERIC_SCHED_CLOCK -static u64 notrace read_sched_clock(void) -{ - return (rdtc() - sc_start) >> sc_shift; -} - -void __init sw64_sched_clock_init(void) -{ - sched_clock_register(sched_clock_read, BITS_PER_LONG, get_cpu_freq() >> sc_shift); -} -#else /* !CONFIG_GENERIC_SCHED_CLOCK */ +#ifndef CONFIG_GENERIC_SCHED_CLOCK /* * scheduler clock - returns current time in nanoseconds. */ @@ -428,7 +418,7 @@ void sw64_setup_timer(void) struct clock_event_device *swevt = &per_cpu(timer_events, cpu); /* min_delta ticks => 100ns */ - min_delta = get_cpu_freq()/1000/1000/10; + min_delta = sunway_max_cpu_freq()/1000/1000/10; if (is_in_guest()) { memcpy(swevt, &vtimer_clockevent, sizeof(*swevt)); @@ -443,7 +433,7 @@ void sw64_setup_timer(void) } swevt->cpumask = cpumask_of(cpu); swevt->set_state_shutdown(swevt); - clockevents_config_and_register(swevt, get_cpu_freq(), min_delta, ULONG_MAX); + clockevents_config_and_register(swevt, sunway_max_cpu_freq(), min_delta, ULONG_MAX); } void sw64_timer_interrupt(void) diff --git a/drivers/cpufreq/sunway-cpufreq.c b/drivers/cpufreq/sunway-cpufreq.c index 41a6b21ff827..ba12dad3b28b 100644 --- a/drivers/cpufreq/sunway-cpufreq.c +++ b/drivers/cpufreq/sunway-cpufreq.c @@ -77,9 +77,6 @@ struct cpufreq_frequency_table freq_table[] = { FV(2850, 0), {0, 0, CPUFREQ_TABLE_END}, }; -static void __init fill_freq_table(struct cpufreq_frequency_table *ft) -{ -} #endif #ifdef CONFIG_PLATFORM_XUELANG @@ -135,11 +132,14 @@ static void __init fill_freq_table(struct cpufreq_frequency_table *ft) static unsigned int sunway_get_rate(struct cpufreq_policy *policy) { - int i; + int i, node; u64 val; - void __iomem *spbu_base = misc_platform_get_spbu_base(0); + void __iomem *spbu_base; struct cpufreq_frequency_table *ft = policy->freq_table; + node = per_cpu(hard_node_id, policy->cpu); + spbu_base = misc_platform_get_spbu_base(node); + /* PLL2 provides working frequency for core */ val = readq(spbu_base + OFFSET_CLK_CTL) >> CORE_PLL2_CFG_SHIFT; val &= CORE_PLL2_CFG_MASK; @@ -147,7 +147,7 @@ static unsigned int sunway_get_rate(struct cpufreq_policy *policy) for (i = 0; ft[i].frequency != CPUFREQ_TABLE_END; i++) { if (val == i) { if (ft[i].frequency == CPUFREQ_ENTRY_INVALID) - return cpuid(GET_CPU_FREQ, 0) * 1000UL; + return sunway_max_cpu_freq() / KHZ; return ft[i].frequency; } } @@ -155,40 +155,42 @@ static unsigned int sunway_get_rate(struct cpufreq_policy *policy) return 0; } -static int sunway_set_rate(unsigned int index) +static int sunway_set_rate(struct cpufreq_policy *policy, unsigned int index) { - int i, retry, cpu_num; + int retry, node; void __iomem *spbu_base; - cpu_num = sw64_chip->get_cpu_num(); - for (i = 0; i < cpu_num; i++) { - spbu_base = misc_platform_get_spbu_base(i); - - /* select PLL0/PLL1 */ - writeq(CLK_LV1_SEL_PROTECT, spbu_base + OFFSET_CLU_LV1_SEL); - /* reset PLL2 */ - writeq(CLK2_PROTECT | CORE_CLK2_RESET | CORE_CLK2_VALID, spbu_base + OFFSET_CLK_CTL); - /* configure PLL2_CFG */ - writeq(CLK2_PROTECT | CORE_CLK2_VALID | (unsigned long)index << CORE_PLL2_CFG_SHIFT, - spbu_base + OFFSET_CLK_CTL); - udelay(1); - /* reset over */ - writeq(CORE_CLK2_VALID, spbu_base + OFFSET_CLK_CTL); - retry = 0; - while (retry < MAX_RETRY) { - if (readq(spbu_base + OFFSET_CLK_CTL) & CORE_CLK2_LOCK) - break; - retry++; - udelay(100); - } - if (retry == MAX_RETRY) - return -ETIME; - /* configure over */ - writeq(0, spbu_base + OFFSET_CLK_CTL); - /* select PLL2/PLL2 */ - writeq(CLK_LV1_SEL_MUXA | CLK_LV1_SEL_MUXB | CLK_LV1_SEL_PROTECT, - spbu_base + OFFSET_CLU_LV1_SEL); + node = per_cpu(hard_node_id, policy->cpu); + spbu_base = misc_platform_get_spbu_base(node); + + /* select PLL0/PLL1 */ + writeq(CLK_LV1_SEL_PROTECT, spbu_base + OFFSET_CLU_LV1_SEL); + /* reset PLL2 */ + writeq(CLK2_PROTECT | CORE_CLK2_RESET | CORE_CLK2_VALID, spbu_base + OFFSET_CLK_CTL); + /* configure PLL2_CFG */ + writeq(CLK2_PROTECT | CORE_CLK2_VALID | (unsigned long)index << CORE_PLL2_CFG_SHIFT, + spbu_base + OFFSET_CLK_CTL); + + udelay(1); + /* reset over */ + writeq(CORE_CLK2_VALID, spbu_base + OFFSET_CLK_CTL); + retry = 0; + while (retry < MAX_RETRY) { + if (readq(spbu_base + OFFSET_CLK_CTL) & CORE_CLK2_LOCK) + break; + retry++; + udelay(100); } + + if (retry == MAX_RETRY) + return -ETIME; + + /* configure over */ + writeq(0, spbu_base + OFFSET_CLK_CTL); + /* select PLL2/PLL2 */ + writeq(CLK_LV1_SEL_MUXA | CLK_LV1_SEL_MUXB | CLK_LV1_SEL_PROTECT, + spbu_base + OFFSET_CLU_LV1_SEL); + return 0; } @@ -205,9 +207,6 @@ static unsigned int sunway_cpufreq_get(unsigned int cpu) return sunway_get_rate(policy); } -/* - * Here we notify other drivers of the proposed change and the final change. - */ static int sunway_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) { @@ -218,24 +217,27 @@ static int sunway_cpufreq_target(struct cpufreq_policy *policy, return -ENODEV; /* setting the cpu frequency */ - ret = sunway_set_rate(index); + ret = sunway_set_rate(policy, index); if (ret) return ret; - update_cpu_freq(freq_table[index].frequency); return 0; } static int sunway_cpufreq_init(struct cpufreq_policy *policy) { - cpufreq_generic_init(policy, freq_table, 0); + int cpu, node; - return 0; -} + node = per_cpu(hard_node_id, policy->cpu); -static int sunway_cpufreq_verify(struct cpufreq_policy_data *policy) -{ - return cpufreq_frequency_table_verify(policy, freq_table); + for_each_possible_cpu(cpu) { + if (per_cpu(hard_node_id, cpu) == node) + cpumask_set_cpu(cpu, policy->cpus); + } + + policy->freq_table = freq_table; + + return 0; } static int sunway_cpufreq_exit(struct cpufreq_policy *policy) @@ -251,7 +253,7 @@ static struct cpufreq_driver sunway_cpufreq_driver = { .name = "sunway-cpufreq", .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .init = sunway_cpufreq_init, - .verify = sunway_cpufreq_verify, + .verify = cpufreq_generic_frequency_table_verify, .target_index = sunway_cpufreq_target, .get = sunway_cpufreq_get, .exit = sunway_cpufreq_exit, @@ -261,14 +263,17 @@ static struct cpufreq_driver sunway_cpufreq_driver = { static int __init cpufreq_init(void) { int i, ret; - unsigned long max_rate = get_cpu_freq() / 1000; + unsigned long max_rate = sunway_max_cpu_freq() / KHZ; /* KHz */ if (!is_in_host()) { pr_warn("cpufreq driver of Sunway platforms is only supported in host mode\n"); return -ENODEV; } +#ifdef CONFIG_PLATFORM_XUELANG fill_freq_table(freq_table); +#endif + for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { if (max_rate == freq_table[i].frequency) freq_table[i+1].frequency = CPUFREQ_TABLE_END; -- Gitee From f182d3ff7883ec96e6d4fe6a568fa5bbe36fde68 Mon Sep 17 00:00:00 2001 From: Gao Chen Date: Fri, 13 Jun 2025 01:12:04 +0800 Subject: [PATCH 6/8] sw64: ioremap: fix IO interfaces Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICC5ID -------------------------------- Referencing asm-generic/io.h causes the definitions of interfaces like inb, inw, inl, outb, outw, outl in arch/sw_64/lib/iomap.c to be overridden by the generic implementation. This patch fixes the issue by defining sw64 interfaces before including asm-generic/io.h. Signed-off-by: Gao Chen Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/io.h | 13 +++++++++++++ arch/sw_64/lib/iomap.c | 6 ------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/sw_64/include/asm/io.h b/arch/sw_64/include/asm/io.h index 6236a79c10b0..a4bfffd7a586 100644 --- a/arch/sw_64/include/asm/io.h +++ b/arch/sw_64/include/asm/io.h @@ -33,6 +33,19 @@ static inline void *phys_to_virt(unsigned long address) /* Maximum PIO space address supported? */ #define IO_SPACE_LIMIT 0xffffffffffffffff +extern u8 inb(unsigned long port); +extern u16 inw(unsigned long port); +extern u32 inl(unsigned long port); +extern void outb(u8 b, unsigned long port); +extern void outw(u16 b, unsigned long port); +extern void outl(u32 b, unsigned long port); +#define inb inb +#define inw inw +#define inl inl +#define outb outb +#define outw outw +#define outl outl + /* * Change addresses as seen by the kernel (virtual) to addresses as * seen by a device (bus), and vice versa. diff --git a/arch/sw_64/lib/iomap.c b/arch/sw_64/lib/iomap.c index 180d9abeff88..8377313e1a71 100644 --- a/arch/sw_64/lib/iomap.c +++ b/arch/sw_64/lib/iomap.c @@ -14,42 +14,36 @@ extern unsigned long legacy_io_shift; /* * Here comes the sw64 implementation of the IOMAP interfaces. */ -#undef inb u8 inb(unsigned long port) { return ioread8(ioport_map(port, 1)); } EXPORT_SYMBOL(inb); -#undef inw u16 inw(unsigned long port) { return ioread16(ioport_map(port, 2)); } EXPORT_SYMBOL(inw); -#undef inl u32 inl(unsigned long port) { return ioread32(ioport_map(port, 4)); } EXPORT_SYMBOL(inl); -#undef outb void outb(u8 b, unsigned long port) { iowrite8(b, ioport_map(port, 1)); } EXPORT_SYMBOL(outb); -#undef outw void outw(u16 b, unsigned long port) { iowrite16(b, ioport_map(port, 2)); } EXPORT_SYMBOL(outw); -#undef outl void outl(u32 b, unsigned long port) { iowrite32(b, ioport_map(port, 4)); -- Gitee From d6c78bde4c3ad699ee23a0ba9c09e7e99fb4b72b Mon Sep 17 00:00:00 2001 From: Jing Li Date: Tue, 31 Dec 2024 17:00:38 +0800 Subject: [PATCH 7/8] sw64: irqchip: add support for PINTC on all NUMA nodes Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICC5ID -------------------------------- Now, devices located outside NUMA node 0 can also report interrupts to PINTC. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/hw_irq.h | 2 - drivers/irqchip/irq-sunway-pintc.c | 106 +++++++++++++++++------------ 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/arch/sw_64/include/asm/hw_irq.h b/arch/sw_64/include/asm/hw_irq.h index 5f79b06b3fa6..905dbafb10df 100644 --- a/arch/sw_64/include/asm/hw_irq.h +++ b/arch/sw_64/include/asm/hw_irq.h @@ -9,8 +9,6 @@ DECLARE_PER_CPU(unsigned long, irq_pmi_count); #define ACTUAL_NR_IRQS nr_irqs -extern struct irq_domain *mcu_irq_domain; - #ifdef CONFIG_PCI_MSI typedef unsigned int vector_irq_t[PERCPU_MSI_IRQS] ____cacheline_aligned; DECLARE_PER_CPU(vector_irq_t, vector_irq); diff --git a/drivers/irqchip/irq-sunway-pintc.c b/drivers/irqchip/irq-sunway-pintc.c index 6821c8a6d0cc..0163c6c04d5f 100644 --- a/drivers/irqchip/irq-sunway-pintc.c +++ b/drivers/irqchip/irq-sunway-pintc.c @@ -67,7 +67,7 @@ #define OFFSET_ADR_INT_CONFIG 0x1580UL /* PINTC version >= 2 */ #define OFFSET_DEVINTWK_INTEN 0x1600UL -#define SW_PINTC_MCU_GSI_BASE 64 +#define PINTC_GSI_BASE(node) (64 + 512 * (node)) #define INTPU_BASE_V1 0x802a00000000 #define INTPU_SIZE_V1 0x1680 @@ -75,6 +75,8 @@ #define MCU_BASE_V1 0x803000000000 #define MCU_SIZE_V1 0x8f00 +#define SUNWAY_MAX_NODES 8 + DECLARE_PER_CPU(unsigned long, hard_node_id); struct pintc_chip_data { @@ -89,13 +91,13 @@ struct pintc_chip_data { raw_spinlock_t mcu_lock; }; -static struct pintc_chip_data *chip_datas[MAX_NUMNODES]; +static struct pintc_chip_data *chip_datas[SUNWAY_MAX_NODES]; static struct pintc_chip_data *pintc_alloc_chip_data(u32 node) { struct pintc_chip_data *chip_data; - if (WARN_ON(node >= MAX_NUMNODES)) + if (WARN_ON(node >= SUNWAY_MAX_NODES)) return NULL; chip_data = kzalloc_node(sizeof(struct pintc_chip_data), @@ -111,7 +113,7 @@ static void pintc_free_chip_data(struct pintc_chip_data *chip_data) if (!chip_data) return; - if (WARN_ON((chip_data->node >= MAX_NUMNODES) || + if (WARN_ON((chip_data->node >= SUNWAY_MAX_NODES) || (chip_datas[chip_data->node] != chip_data))) return; @@ -285,13 +287,14 @@ static int mcu_irq_set_affinity(struct irq_data *irq_data, return assign_mcu_irq_config(chip_data, &targets); } -static struct irq_chip pintc_mcu_chip = { - .name = "MCU-INT", - .irq_enable = mcu_irq_enable, - .irq_disable = mcu_irq_disable, - .irq_mask = mcu_irq_disable, - .irq_unmask = mcu_irq_enable, - .irq_set_affinity = mcu_irq_set_affinity, +static struct irq_chip pintc_mcu_chips[SUNWAY_MAX_NODES] = { + [0 ... SUNWAY_MAX_NODES - 1] = { + .irq_enable = mcu_irq_enable, + .irq_disable = mcu_irq_disable, + .irq_mask = mcu_irq_disable, + .irq_unmask = mcu_irq_enable, + .irq_set_affinity = mcu_irq_set_affinity, + } }; static struct irq_chip pintc_mcu_vt_chip = { @@ -303,6 +306,9 @@ static int pintc_mcu_translate(struct irq_domain *domain, unsigned long *hwirq, unsigned int *type) { + struct pintc_chip_data *chip_data = domain->host_data; + u32 node = chip_data->node; + if (WARN_ON(fwspec->param_count < 1)) return -EINVAL; @@ -315,9 +321,9 @@ static int pintc_mcu_translate(struct irq_domain *domain, /* ACPI */ if (is_fwnode_irqchip(fwspec->fwnode)) { - if (WARN_ON(fwspec->param[0] < SW_PINTC_MCU_GSI_BASE)) + if (WARN_ON(fwspec->param[0] < PINTC_GSI_BASE(node))) return -EINVAL; - *hwirq = fwspec->param[0] - SW_PINTC_MCU_GSI_BASE; + *hwirq = fwspec->param[0] - PINTC_GSI_BASE(node); *type = IRQ_TYPE_NONE; return 0; } @@ -376,13 +382,14 @@ static const struct irq_domain_ops pintc_mcu_domain_ops = { .free = pintc_mcu_free_irqs, }; -struct irq_domain *mcu_irq_domain; -EXPORT_SYMBOL(mcu_irq_domain); +static struct irq_domain *mcu_domains[SUNWAY_MAX_NODES]; static int __init pintc_init_mcu(struct pintc_chip_data *chip_data, struct fwnode_handle *handle) { unsigned int mcu_irq_num = chip_data->mcu_irq_num; + u32 node = chip_data->node; + char *chip_name; if (chip_data->vt) { chip_data->mcu_chip = &pintc_mcu_vt_chip; @@ -392,25 +399,37 @@ static int __init pintc_init_mcu(struct pintc_chip_data *chip_data, * "irq_domain_create_legacy", we have to call * "__irq_domain_add" directly. */ - mcu_irq_domain = __irq_domain_add(handle, mcu_irq_num, + mcu_domains[node] = __irq_domain_add(handle, mcu_irq_num, mcu_irq_num, 0, &pintc_mcu_domain_ops, chip_data); - if (mcu_irq_domain) - irq_domain_associate_many(mcu_irq_domain, + if (mcu_domains[node]) + irq_domain_associate_many(mcu_domains[node], 0, 0, mcu_irq_num); } else { - chip_data->mcu_chip = &pintc_mcu_chip; - mcu_irq_domain = irq_domain_create_linear(handle, mcu_irq_num, + chip_data->mcu_chip = &pintc_mcu_chips[node]; + + chip_name = kzalloc_node(sizeof("MCUX-INT"), GFP_KERNEL, node); + if (!chip_name) + return -ENOMEM; + + snprintf(chip_name, sizeof("MCUX-INT"), "MCU%u-INT", node); + chip_data->mcu_chip->name = chip_name; + + mcu_domains[node] = irq_domain_create_linear(handle, mcu_irq_num, &pintc_mcu_domain_ops, chip_data); + /* Mask all interrupts for now */ writeq(0x0, chip_data->mcu_base + OFFSET_MCU_DVC_INT_EN); - /* When building the root domain, move it to a better location */ - if (mcu_irq_domain) + if (mcu_domains[node]) pintc_mcu_enable(chip_data->pintc_base); + else { + chip_data->mcu_chip->name = NULL; + kfree(chip_name); + } } - if (!mcu_irq_domain) { + if (!mcu_domains[node]) { pr_err("failed to create MCU irq domain\n"); return -ENOMEM; } @@ -424,24 +443,24 @@ static int __init pintc_init_mcu(struct pintc_chip_data *chip_data, return 0; } -/* Currently, only MCU controller on node 0 is supported */ void handle_dev_int(struct pt_regs *regs) { unsigned long stat, val; unsigned int hwirq; + u32 node = __this_cpu_read(hard_node_id); /* Disable global irq of MCU due to some hardware reasons */ - val = pintc_mcu_disable_and_save(chip_datas[0]); + val = pintc_mcu_disable_and_save(chip_datas[node]); - stat = readq(chip_datas[0]->mcu_base + OFFSET_MCU_DVC_INT); + stat = readq(chip_datas[node]->mcu_base + OFFSET_MCU_DVC_INT); while (stat) { hwirq = ffs(stat) - 1; - handle_domain_irq(mcu_irq_domain, hwirq, regs); + handle_domain_irq(mcu_domains[node], hwirq, regs); stat &= ~(1UL << hwirq); } - pintc_mcu_restore(chip_datas[0], val); + pintc_mcu_restore(chip_datas[node], val); } void handle_fault_int(void) @@ -487,13 +506,6 @@ void handle_fault_int(void) static int __init pintc_of_init_mcu(struct pintc_chip_data *chip_data, struct device_node *pintc) { - /* Not yet supported */ - if (chip_data->node > 0) { - pr_info("MCU version [%u] on node [%u] skipped\n", - chip_data->version, chip_data->node); - return 0; - } - return pintc_init_mcu(chip_data, of_node_to_fwnode(pintc)); } @@ -608,6 +620,7 @@ enum sw_pintc_sub_type { static int __init lpc_intc_parse_madt(union acpi_subtable_headers *header, const unsigned long end) { + static bool initialized[SUNWAY_MAX_NODES]; struct acpi_madt_sw_lpc_intc *lpc_intc; lpc_intc = (struct acpi_madt_sw_lpc_intc *)header; @@ -616,13 +629,22 @@ static int __init lpc_intc_parse_madt(union acpi_subtable_headers *header, if (lpc_intc->node > 0) return 0; + if (initialized[lpc_intc->node]) + return 0; + + /* LPC controller is the child of MCU controller */ + if (!mcu_domains[lpc_intc->node]) + return 0; + if ((lpc_intc->version == ACPI_MADT_SW_LPC_INTC_VERSION_NONE) || (lpc_intc->version >= ACPI_MADT_SW_LPC_INTC_VERSION_RESERVED)) { pr_err("invalid LPC-INTC version\n"); return -EINVAL; } - return lpc_intc_acpi_init(mcu_irq_domain, lpc_intc); + initialized[lpc_intc->node] = true; + + return lpc_intc_acpi_init(mcu_domains[lpc_intc->node], lpc_intc); } static bool __init @@ -642,22 +664,16 @@ static int __init pintc_acpi_init_mcu(struct pintc_chip_data *chip_data, struct acpi_madt_sw_sub_pintc *mcu) { struct fwnode_handle *handle; + u32 node = chip_data->node; int ret; - /* Not yet supported */ - if (chip_data->node > 0) { - pr_info("MCU version [%u] on node [%u] skipped\n", - chip_data->version, chip_data->node); - return 0; - } - if (!mcu->status) { pr_info("MCU version [%u] on node [%u] disabled\n", chip_data->version, chip_data->node); return 0; } - if (mcu->gsi_base != SW_PINTC_MCU_GSI_BASE) { + if (mcu->gsi_base != PINTC_GSI_BASE(node)) { pr_err("invalid MCU GSI\n"); return -EINVAL; } @@ -694,7 +710,7 @@ static int __init pintc_acpi_init_mcu(struct pintc_chip_data *chip_data, return 0; out_acpi_free_mcu_domain: - irq_domain_remove(mcu_irq_domain); + irq_domain_remove(mcu_domains[node]); out_acpi_unmap_mcu: iounmap(chip_data->mcu_base); out_acpi_free_fwnode: -- Gitee From c0b4d88477e8124609fe7da7960633ad4be20d9d Mon Sep 17 00:00:00 2001 From: Jing Li Date: Wed, 28 May 2025 14:47:01 +0800 Subject: [PATCH 8/8] sw64: irqchip: update effective affinity for PINTC Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICC5ID -------------------------------- Since CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK is selected, it is necessary to update effective affinity when setting affinity for PINTC. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/irqchip/irq-sunway-pintc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-sunway-pintc.c b/drivers/irqchip/irq-sunway-pintc.c index 0163c6c04d5f..7305deb332e8 100644 --- a/drivers/irqchip/irq-sunway-pintc.c +++ b/drivers/irqchip/irq-sunway-pintc.c @@ -243,9 +243,10 @@ static void update_pintc_mcu_target(struct pintc_chip_data *chip_data, raw_spin_unlock_irqrestore(&chip_data->pintc_lock, flags); } -static int assign_mcu_irq_config(struct pintc_chip_data *chip_data, +static int assign_mcu_irq_config(struct irq_data *irq_data, cpumask_t *targets) { + struct pintc_chip_data *chip_data = irq_data->chip_data; unsigned long dev_int_tar; unsigned int cpu; int rcid; @@ -270,13 +271,14 @@ static int assign_mcu_irq_config(struct pintc_chip_data *chip_data, dev_int_tar = make_pintc_int_target(chip_data->version, rcid); update_pintc_mcu_target(chip_data, dev_int_tar); + irq_data_update_effective_affinity(irq_data, cpumask_of(cpu)); + return 0; } static int mcu_irq_set_affinity(struct irq_data *irq_data, const struct cpumask *dest, bool force) { - struct pintc_chip_data *chip_data = irq_data->chip_data; cpumask_t targets; if (cpumask_any_and(dest, cpu_online_mask) >= nr_cpu_ids) @@ -284,7 +286,7 @@ static int mcu_irq_set_affinity(struct irq_data *irq_data, cpumask_and(&targets, dest, cpu_online_mask); - return assign_mcu_irq_config(chip_data, &targets); + return assign_mcu_irq_config(irq_data, &targets); } static struct irq_chip pintc_mcu_chips[SUNWAY_MAX_NODES] = { -- Gitee