From 0a00024d7a779b283db2a02130ffa46f47634d0c Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 22 Jun 2017 23:06:48 +0800 Subject: MIPS: Loongson: Add Loongson-3A R3 basic support Loongson-3A R3 is very similar to Loongson-3A R2. All Loongson-3 CPU family: Code-name Brand-name PRId Loongson-3A R1 Loongson-3A1000 0x6305 Loongson-3A R2 Loongson-3A2000 0x6308 Loongson-3A R3 Loongson-3A3000 0x6309 Loongson-3B R1 Loongson-3B1000 0x6306 Loongson-3B R2 Loongson-3B1500 0x6307 Signed-off-by: Huacai Chen Cc: John Crispin Cc: Steven J . Hill Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16585/ Signed-off-by: Ralf Baechle --- arch/mips/loongson64/common/env.c | 1 + arch/mips/loongson64/loongson-3/smp.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'arch/mips/loongson64') diff --git a/arch/mips/loongson64/common/env.c b/arch/mips/loongson64/common/env.c index 6afa21850267..4707abfe9d64 100644 --- a/arch/mips/loongson64/common/env.c +++ b/arch/mips/loongson64/common/env.c @@ -193,6 +193,7 @@ void __init prom_init_env(void) break; case PRID_REV_LOONGSON3A_R1: case PRID_REV_LOONGSON3A_R2: + case PRID_REV_LOONGSON3A_R3: cpu_clock_freq = 900000000; break; case PRID_REV_LOONGSON3B_R1: diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c index 64659fc73940..1629743ba96a 100644 --- a/arch/mips/loongson64/loongson-3/smp.c +++ b/arch/mips/loongson64/loongson-3/smp.c @@ -503,7 +503,7 @@ static void loongson3a_r1_play_dead(int *state_addr) : "a1"); } -static void loongson3a_r2_play_dead(int *state_addr) +static void loongson3a_r2r3_play_dead(int *state_addr) { register int val; register long cpuid, core, node, count; @@ -664,8 +664,9 @@ void play_dead(void) (void *)CKSEG1ADDR((unsigned long)loongson3a_r1_play_dead); break; case PRID_REV_LOONGSON3A_R2: + case PRID_REV_LOONGSON3A_R3: play_dead_at_ckseg1 = - (void *)CKSEG1ADDR((unsigned long)loongson3a_r2_play_dead); + (void *)CKSEG1ADDR((unsigned long)loongson3a_r2r3_play_dead); break; case PRID_REV_LOONGSON3B_R1: case PRID_REV_LOONGSON3B_R2: -- cgit v1.2.3 From b392ee07999aa1f19b3a845fad47ec4275341f71 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 22 Jun 2017 23:06:50 +0800 Subject: MIPS: Loongson: Add NMI handler support Signed-off-by: Huacai Chen Cc: John Crispin Cc: Steven J . Hill Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16587/ Signed-off-by: Ralf Baechle --- arch/mips/loongson64/common/init.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'arch/mips/loongson64') diff --git a/arch/mips/loongson64/common/init.c b/arch/mips/loongson64/common/init.c index 9b987fe98b5b..6ef17120722f 100644 --- a/arch/mips/loongson64/common/init.c +++ b/arch/mips/loongson64/common/init.c @@ -10,13 +10,25 @@ #include #include +#include #include +#include #include /* Loongson CPU address windows config space base address */ unsigned long __maybe_unused _loongson_addrwincfg_base; +static void __init mips_nmi_setup(void) +{ + void *base; + extern char except_vec_nmi; + + base = (void *)(CAC_BASE + 0x380); + memcpy(base, &except_vec_nmi, 0x80); + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); +} + void __init prom_init(void) { #ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG @@ -40,6 +52,7 @@ void __init prom_init(void) /*init the uart base address */ prom_init_uart_base(); register_smp_ops(&loongson3_smp_ops); + board_nmi_handler_setup = mips_nmi_setup; } void __init prom_free_prom_memory(void) -- cgit v1.2.3 From e1b88ca8d72193e48bac026b19b8c686cc7fea25 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 22 Jun 2017 23:06:52 +0800 Subject: MIPS: Loongson-3: IRQ balancing for PCI devices IRQ0 (HPET), IRQ1 (Keyboard), IRQ2 (Cascade), IRQ7 (SCI), IRQ8 (RTC) and IRQ12 (Mouse) are handled by core-0 locally. Other PCI IRQs (3, 4, 5, 6, 14, 15) are balanced by all cores from Node-0. This can improve I/O performance significantly. Signed-off-by: Huacai Chen Cc: John Crispin Cc: Steven J . Hill Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16589/ Signed-off-by: Ralf Baechle --- arch/mips/loongson64/loongson-3/irq.c | 19 +++++++++++++++++-- arch/mips/loongson64/loongson-3/smp.c | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) (limited to 'arch/mips/loongson64') diff --git a/arch/mips/loongson64/loongson-3/irq.c b/arch/mips/loongson64/loongson-3/irq.c index 548f759454dc..2e6e205ed9b9 100644 --- a/arch/mips/loongson64/loongson-3/irq.c +++ b/arch/mips/loongson64/loongson-3/irq.c @@ -9,17 +9,32 @@ #include "smp.h" +extern void loongson3_send_irq_by_ipi(int cpu, int irqs); unsigned int ht_irq[] = {0, 1, 3, 4, 5, 6, 7, 8, 12, 14, 15}; +unsigned int local_irq = 1<<0 | 1<<1 | 1<<2 | 1<<7 | 1<<8 | 1<<12; static void ht_irqdispatch(void) { - unsigned int i, irq; + unsigned int i, irq, irq0, irq1; + static unsigned int dest_cpu = 0; irq = LOONGSON_HT1_INT_VECTOR(0); LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */ + irq0 = irq & local_irq; /* handled by local core */ + irq1 = irq & ~local_irq; /* balanced by other cores */ + + if (dest_cpu == 0 || !cpu_online(dest_cpu)) + irq0 |= irq1; + else + loongson3_send_irq_by_ipi(dest_cpu, irq1); + + dest_cpu = dest_cpu + 1; + if (dest_cpu >= num_possible_cpus() || cpu_data[dest_cpu].package > 0) + dest_cpu = 0; + for (i = 0; i < ARRAY_SIZE(ht_irq); i++) { - if (irq & (0x1 << ht_irq[i])) + if (irq0 & (0x1 << ht_irq[i])) do_IRQ(ht_irq[i]); } } diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c index 1629743ba96a..b7a355c3c408 100644 --- a/arch/mips/loongson64/loongson-3/smp.c +++ b/arch/mips/loongson64/loongson-3/smp.c @@ -254,13 +254,21 @@ loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action) loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu_logical_map(i)]); } +#define IPI_IRQ_OFFSET 6 + +void loongson3_send_irq_by_ipi(int cpu, int irqs) +{ + loongson3_ipi_write32(irqs << IPI_IRQ_OFFSET, ipi_set0_regs[cpu_logical_map(cpu)]); +} + void loongson3_ipi_interrupt(struct pt_regs *regs) { int i, cpu = smp_processor_id(); - unsigned int action, c0count; + unsigned int action, c0count, irqs; /* Load the ipi register to figure out what we're supposed to do */ action = loongson3_ipi_read32(ipi_status0_regs[cpu_logical_map(cpu)]); + irqs = action >> IPI_IRQ_OFFSET; /* Clear the ipi register to clear the interrupt */ loongson3_ipi_write32((u32)action, ipi_clear0_regs[cpu_logical_map(cpu)]); @@ -282,6 +290,14 @@ void loongson3_ipi_interrupt(struct pt_regs *regs) core0_c0count[i] = c0count; __wbflush(); /* Let others see the result ASAP */ } + + if (irqs) { + int irq; + while ((irq = ffs(irqs))) { + do_IRQ(irq-1); + irqs &= ~(1<<(irq-1)); + } + } } #define MAX_LOOPS 800 -- cgit v1.2.3 From ecc38a0968ec3e0605079e49d276d9a4186abdb7 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 22 Jun 2017 23:06:53 +0800 Subject: MIPS: Loongson-3: support irq_set_affinity() in i8259 chip With this patch we can set irq affinity via procfs, so as to improve network performance. Signed-off-by: Huacai Chen Cc: John Crispin Cc: Steven J . Hill Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16590/ Signed-off-by: Ralf Baechle --- arch/mips/loongson64/loongson-3/irq.c | 67 ++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 13 deletions(-) (limited to 'arch/mips/loongson64') diff --git a/arch/mips/loongson64/loongson-3/irq.c b/arch/mips/loongson64/loongson-3/irq.c index 2e6e205ed9b9..7202e52cd046 100644 --- a/arch/mips/loongson64/loongson-3/irq.c +++ b/arch/mips/loongson64/loongson-3/irq.c @@ -10,32 +10,68 @@ #include "smp.h" extern void loongson3_send_irq_by_ipi(int cpu, int irqs); + +unsigned int irq_cpu[16] = {[0 ... 15] = -1}; unsigned int ht_irq[] = {0, 1, 3, 4, 5, 6, 7, 8, 12, 14, 15}; unsigned int local_irq = 1<<0 | 1<<1 | 1<<2 | 1<<7 | 1<<8 | 1<<12; +int plat_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity, + bool force) +{ + unsigned int cpu; + struct cpumask new_affinity; + + /* I/O devices are connected on package-0 */ + cpumask_copy(&new_affinity, affinity); + for_each_cpu(cpu, affinity) + if (cpu_data[cpu].package > 0) + cpumask_clear_cpu(cpu, &new_affinity); + + if (cpumask_empty(&new_affinity)) + return -EINVAL; + + cpumask_copy(d->common->affinity, &new_affinity); + + return IRQ_SET_MASK_OK_NOCOPY; +} + static void ht_irqdispatch(void) { - unsigned int i, irq, irq0, irq1; - static unsigned int dest_cpu = 0; + unsigned int i, irq; + struct irq_data *irqd; + struct cpumask affinity; irq = LOONGSON_HT1_INT_VECTOR(0); LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */ - irq0 = irq & local_irq; /* handled by local core */ - irq1 = irq & ~local_irq; /* balanced by other cores */ + for (i = 0; i < ARRAY_SIZE(ht_irq); i++) { + if (!(irq & (0x1 << ht_irq[i]))) + continue; - if (dest_cpu == 0 || !cpu_online(dest_cpu)) - irq0 |= irq1; - else - loongson3_send_irq_by_ipi(dest_cpu, irq1); + /* handled by local core */ + if (local_irq & (0x1 << ht_irq[i])) { + do_IRQ(ht_irq[i]); + continue; + } - dest_cpu = dest_cpu + 1; - if (dest_cpu >= num_possible_cpus() || cpu_data[dest_cpu].package > 0) - dest_cpu = 0; + irqd = irq_get_irq_data(ht_irq[i]); + cpumask_and(&affinity, irqd->common->affinity, cpu_active_mask); + if (cpumask_empty(&affinity)) { + do_IRQ(ht_irq[i]); + continue; + } - for (i = 0; i < ARRAY_SIZE(ht_irq); i++) { - if (irq0 & (0x1 << ht_irq[i])) + irq_cpu[ht_irq[i]] = cpumask_next(irq_cpu[ht_irq[i]], &affinity); + if (irq_cpu[ht_irq[i]] >= nr_cpu_ids) + irq_cpu[ht_irq[i]] = cpumask_first(&affinity); + + if (irq_cpu[ht_irq[i]] == 0) { do_IRQ(ht_irq[i]); + continue; + } + + /* balanced by other cores */ + loongson3_send_irq_by_ipi(irq_cpu[ht_irq[i]], (0x1 << ht_irq[i])); } } @@ -135,11 +171,16 @@ void irq_router_init(void) void __init mach_init_irq(void) { + struct irq_chip *chip; + clear_c0_status(ST0_IM | ST0_BEV); irq_router_init(); mips_cpu_irq_init(); init_i8259_irqs(); + chip = irq_get_chip(I8259A_IRQ_BASE); + chip->irq_set_affinity = plat_set_irq_affinity; + irq_set_chip_and_handler(LOONGSON_UART_IRQ, &loongson_irq_chip, handle_level_irq); -- cgit v1.2.3 From b9c4dc2cf9af62bc0d2d8504c15175aeac49ad53 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 22 Jun 2017 23:06:54 +0800 Subject: MIPS: Loogson: Make enum loongson_cpu_type more clear Sort enum loongson_cpu_type in a more reasonable manner, this makes the CPU names more clear and extensible. Those already defined enum values are renamed to Legacy_* for compatibility. Signed-off-by: Huacai Chen Cc: John Crispin Cc: Steven J . Hill Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16591/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-loongson64/boot_param.h | 22 ++++++++++++++++------ arch/mips/loongson64/common/env.c | 11 ++++++++--- 2 files changed, 24 insertions(+), 9 deletions(-) (limited to 'arch/mips/loongson64') diff --git a/arch/mips/include/asm/mach-loongson64/boot_param.h b/arch/mips/include/asm/mach-loongson64/boot_param.h index d3f3258b7cd4..9f9bb9c53785 100644 --- a/arch/mips/include/asm/mach-loongson64/boot_param.h +++ b/arch/mips/include/asm/mach-loongson64/boot_param.h @@ -27,12 +27,22 @@ struct efi_memory_map_loongson { } __packed; enum loongson_cpu_type { - Loongson_2E = 0, - Loongson_2F = 1, - Loongson_3A = 2, - Loongson_3B = 3, - Loongson_1A = 4, - Loongson_1B = 5 + Legacy_2E = 0x0, + Legacy_2F = 0x1, + Legacy_3A = 0x2, + Legacy_3B = 0x3, + Legacy_1A = 0x4, + Legacy_1B = 0x5, + Legacy_2G = 0x6, + Legacy_2H = 0x7, + Loongson_1A = 0x100, + Loongson_1B = 0x101, + Loongson_2E = 0x200, + Loongson_2F = 0x201, + Loongson_2G = 0x202, + Loongson_2H = 0x203, + Loongson_3A = 0x300, + Loongson_3B = 0x301 }; /* diff --git a/arch/mips/loongson64/common/env.c b/arch/mips/loongson64/common/env.c index 4707abfe9d64..1e8a955ae5a8 100644 --- a/arch/mips/loongson64/common/env.c +++ b/arch/mips/loongson64/common/env.c @@ -90,7 +90,9 @@ void __init prom_init_env(void) cpu_clock_freq = ecpu->cpu_clock_freq; loongson_sysconf.cputype = ecpu->cputype; - if (ecpu->cputype == Loongson_3A) { + switch (ecpu->cputype) { + case Legacy_3A: + case Loongson_3A: loongson_sysconf.cores_per_node = 4; loongson_sysconf.cores_per_package = 4; smp_group[0] = 0x900000003ff01000; @@ -111,7 +113,9 @@ void __init prom_init_env(void) loongson_freqctrl[3] = 0x900030001fe001d0; loongson_sysconf.ht_control_base = 0x90000EFDFB000000; loongson_sysconf.workarounds = WORKAROUND_CPUFREQ; - } else if (ecpu->cputype == Loongson_3B) { + break; + case Legacy_3B: + case Loongson_3B: loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */ loongson_sysconf.cores_per_package = 8; smp_group[0] = 0x900000003ff01000; @@ -132,7 +136,8 @@ void __init prom_init_env(void) loongson_freqctrl[3] = 0x900060001fe001d0; loongson_sysconf.ht_control_base = 0x90001EFDFB000000; loongson_sysconf.workarounds = WORKAROUND_CPUHOTPLUG; - } else { + break; + default: loongson_sysconf.cores_per_node = 1; loongson_sysconf.cores_per_package = 1; loongson_chipcfg[0] = 0x900000001fe00180; -- cgit v1.2.3