diff --git a/arch/sw_64/include/asm/cpu.h b/arch/sw_64/include/asm/cpu.h index 1b8c479e4e6a6faed8e4038f86d73852e3e533f9..d8a87f54fe60f48512654fb4caefeac4bbf85c57 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/include/asm/hw_irq.h b/arch/sw_64/include/asm/hw_irq.h index 5f79b06b3fa6544de8aeb59a1852a4d36693f51c..905dbafb10dfe79c0ff09aacdc8d95483f6c64e7 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/arch/sw_64/include/asm/io.h b/arch/sw_64/include/asm/io.h index 6236a79c10b0de3303e81b4defff3a6c30d4a741..a4bfffd7a586e934ed4ef7a338a577e83813f4b6 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/include/asm/pgtable.h b/arch/sw_64/include/asm/pgtable.h index 189580d524bf74f13e1e9c7fa01df889f752d5b6..82881f9e3faef6e11dbdb60bb306c55b387b0055 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/cpu.c b/arch/sw_64/kernel/cpu.c index a30a825997da25cdcc675b8ab8be70b7e95268d9..84b4a66a06e9a32fb9a20267bcde77eb38e9e54d 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/entry-ftrace.S b/arch/sw_64/kernel/entry-ftrace.S index c56166d434ebda4dd40498d468227eded0dee8b6..bdd6cd5a63a86c83f8bc4484c523ce5797e55428 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) diff --git a/arch/sw_64/kernel/module.c b/arch/sw_64/kernel/module.c index 2904bb750eb5d0b272e7017bb580bdfdb11c4033..8c08115fd6159a4102eb5ed9c1bddb0ee6b5a29d 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)); +} diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index 83611fba009296e4829e5f69d65e67368e3f2b96..6ddccb4a5822b8df09a235a371c638f2c1c27aed 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/smp.c b/arch/sw_64/kernel/smp.c index 51a75938de53c3cabee536ff39039fea6498b9cb..6f31481e32ab0aa24281d25f0fbec7f4d7a29e24 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/kernel/time.c b/arch/sw_64/kernel/time.c index 503f9e1beb4399f353851d9912594c4352b4594d..c6cefd4383b54e5ca84b3b212fcfd8a31a74c001 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/kvm/kvm_core4.c b/arch/sw_64/kvm/kvm_core4.c index d1d04f9f8f548a9e9b9b6ed46c0ceeacfa26ca01..0a1e33020fb0bb0239106991e34bbfac5df33bcd 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); diff --git a/arch/sw_64/lib/iomap.c b/arch/sw_64/lib/iomap.c index 180d9abeff8833d0e4e09923fefd5a30f37ab833..8377313e1a719dc968cab6a21988dada862eced2 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)); diff --git a/arch/sw_64/lib/udelay.c b/arch/sw_64/lib/udelay.c index c60601d56b0e1994ce2bc653610a791bd6645eeb..ba5efe4b4549a3d733317df85e33b671cd90d43d 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 e83c8b5230d338103db4df72acfdc0e760f866d5..ac5901c83eba26d5e6702c969836908a8e2eab7f 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 41a6b21ff8276984f4e4d51ddcff1bc93e42b197..ba12dad3b28b5f745b11da615b91613707aa549f 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; diff --git a/drivers/irqchip/irq-sunway-pintc.c b/drivers/irqchip/irq-sunway-pintc.c index f6dc603e43b2bfda630179609f837562d015596d..7305deb332e8d52476799aeae5595f3818f131a7 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; @@ -241,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; @@ -268,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) @@ -282,16 +286,17 @@ 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_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 +308,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 +323,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 +384,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 +401,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 +445,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 +508,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 +622,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 +631,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 +666,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; } @@ -671,7 +689,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; @@ -694,7 +712,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: @@ -762,7 +780,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;