diff --git a/arch/sw_64/include/asm/bitops.h b/arch/sw_64/include/asm/bitops.h index b3cdabd95abfc0b4d49591d5b1f9d5e7fefe230a..ec19d38efb6197a8b271254f5a8055cfbcba0753 100644 --- a/arch/sw_64/include/asm/bitops.h +++ b/arch/sw_64/include/asm/bitops.h @@ -438,6 +438,26 @@ arch___test_and_change_bit(unsigned long nr, volatile unsigned long *addr) #define arch_test_bit generic_test_bit #define arch_test_bit_acquire generic_test_bit_acquire +static inline bool xor_unlock_is_negative_byte(unsigned long mask, + volatile unsigned long *p) +{ + unsigned long temp, old; + + __asm__ __volatile__( + "1: ldl %0,%4\n" + " mov %0,%2\n" + " xor %0,%3,%0\n" + " stl %0,%1\n" + " beq %0,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (*p), "=&r" (old) + :"Ir" (mask), "m" (*p)); + + return (old & BIT(7)) != 0; +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. diff --git a/arch/sw_64/include/asm/cpu.h b/arch/sw_64/include/asm/cpu.h index 37368a9d4d522943b22ae5947312bd197ff3dc7f..9fc739dacfaba88fc6eca5130f55c31cd8f217b3 100644 --- a/arch/sw_64/include/asm/cpu.h +++ b/arch/sw_64/include/asm/cpu.h @@ -7,6 +7,9 @@ #include #include +#define KHZ (1000UL) +#define MHZ (1000UL * 1000UL) + #define current_cpu_data cpu_data[smp_processor_id()] enum hmcall_cpuid_cmd { @@ -48,10 +51,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 59418a5fb1d399cf6ea8cf885fbf51321c7eec2c..b0167e9fd814dda359d18b71847a5c80a6cc584d 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]; DECLARE_PER_CPU(vector_irq_t, vector_irq); diff --git a/arch/sw_64/kernel/cpu.c b/arch/sw_64/kernel/cpu.c index 412d83bc49adb46f37b8317fd215439f50785302..172cca36e42d22a5a22843ef1d729bfe3f815c7a 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); @@ -312,3 +299,17 @@ 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 5dbae49918757623c90d00138a3ca6fc1f550dd2..9274ca8d976924b33da78ae2cd7c0d8002bea043 100644 --- a/arch/sw_64/kernel/entry-ftrace.S +++ b/arch/sw_64/kernel/entry-ftrace.S @@ -341,6 +341,7 @@ ftrace_regs_call: RESTORE_GRAPH_REG_ARGS call ftrace_graph_caller #endif + ldl $2, PT_REGS_R2($sp) // load direct call addr RESTORE_PT_REGS bne $2, .Ldirect ret $31, ($28), 1 diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index 6eee740ce7e5784efa7ccee05269b62a0d320b4d..8cfcc30aad2eb4bc58af26b8a87e9f567a09d598 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -133,7 +133,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 08e0123956a37bda0d2c91de1bfbcf5a260d89d9..d150d81a912917f570f2395f8c80bd738cb59a7d 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 57f1176472f3a047f928874c3560a8023a07c869..4b6376f3c0394bb5449b8c606b641b0d10e429c2 100644 --- a/arch/sw_64/kvm/kvm_core4.c +++ b/arch/sw_64/kvm/kvm_core4.c @@ -126,6 +126,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(); @@ -136,7 +137,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/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 9af19cb362fc8c8222e7073014afaf5214bf4df6..d925d2650bde16df52add5d892ee209f84b151ad 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 6aaebea7c74b17d84092b4b841ca486a5056707a..9e87b84015f6f2adf2acac82eb5aea0cda08b5ea 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; - generic_handle_domain_irq(mcu_irq_domain, hwirq); + generic_handle_domain_irq(mcu_domains[node], hwirq); 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;