diff options
| -rw-r--r-- | arch/mips/include/asm/mach-loongson/irq.h | 2 | ||||
| -rw-r--r-- | arch/mips/include/asm/mach-loongson/loongson.h | 1 | ||||
| -rw-r--r-- | arch/mips/loongson/common/init.c | 2 | ||||
| -rw-r--r-- | arch/mips/loongson/common/setup.c | 8 | ||||
| -rw-r--r-- | arch/mips/loongson/loongson-3/Makefile | 2 | ||||
| -rw-r--r-- | arch/mips/loongson/loongson-3/irq.c | 20 | ||||
| -rw-r--r-- | arch/mips/loongson/loongson-3/smp.c | 267 | ||||
| -rw-r--r-- | arch/mips/loongson/loongson-3/smp.h | 29 |
8 files changed, 326 insertions, 5 deletions
diff --git a/arch/mips/include/asm/mach-loongson/irq.h b/arch/mips/include/asm/mach-loongson/irq.h index 29c2dff3aae8..0c77b22a6630 100644 --- a/arch/mips/include/asm/mach-loongson/irq.h +++ b/arch/mips/include/asm/mach-loongson/irq.h | |||
| @@ -37,5 +37,7 @@ | |||
| 37 | 37 | ||
| 38 | #endif | 38 | #endif |
| 39 | 39 | ||
| 40 | extern void loongson3_ipi_interrupt(struct pt_regs *regs); | ||
| 41 | |||
| 40 | #include_next <irq.h> | 42 | #include_next <irq.h> |
| 41 | #endif /* __ASM_MACH_LOONGSON_IRQ_H_ */ | 43 | #endif /* __ASM_MACH_LOONGSON_IRQ_H_ */ |
diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h index 69e9d9ea90c4..f185907e8ce3 100644 --- a/arch/mips/include/asm/mach-loongson/loongson.h +++ b/arch/mips/include/asm/mach-loongson/loongson.h | |||
| @@ -27,6 +27,7 @@ extern void mach_prepare_shutdown(void); | |||
| 27 | /* environment arguments from bootloader */ | 27 | /* environment arguments from bootloader */ |
| 28 | extern u32 cpu_clock_freq; | 28 | extern u32 cpu_clock_freq; |
| 29 | extern u32 memsize, highmemsize; | 29 | extern u32 memsize, highmemsize; |
| 30 | extern struct plat_smp_ops loongson3_smp_ops; | ||
| 30 | 31 | ||
| 31 | /* loongson-specific command line, env and memory initialization */ | 32 | /* loongson-specific command line, env and memory initialization */ |
| 32 | extern void __init prom_init_memory(void); | 33 | extern void __init prom_init_memory(void); |
diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c index 81ba3b4a8f30..f37fe5413b73 100644 --- a/arch/mips/loongson/common/init.c +++ b/arch/mips/loongson/common/init.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/bootmem.h> | 11 | #include <linux/bootmem.h> |
| 12 | #include <asm/smp-ops.h> | ||
| 12 | 13 | ||
| 13 | #include <loongson.h> | 14 | #include <loongson.h> |
| 14 | 15 | ||
| @@ -33,6 +34,7 @@ void __init prom_init(void) | |||
| 33 | 34 | ||
| 34 | /*init the uart base address */ | 35 | /*init the uart base address */ |
| 35 | prom_init_uart_base(); | 36 | prom_init_uart_base(); |
| 37 | register_smp_ops(&loongson3_smp_ops); | ||
| 36 | } | 38 | } |
| 37 | 39 | ||
| 38 | void __init prom_free_prom_memory(void) | 40 | void __init prom_free_prom_memory(void) |
diff --git a/arch/mips/loongson/common/setup.c b/arch/mips/loongson/common/setup.c index 8223f8acfd59..bb4ac922e47a 100644 --- a/arch/mips/loongson/common/setup.c +++ b/arch/mips/loongson/common/setup.c | |||
| @@ -18,9 +18,6 @@ | |||
| 18 | #include <linux/screen_info.h> | 18 | #include <linux/screen_info.h> |
| 19 | #endif | 19 | #endif |
| 20 | 20 | ||
| 21 | void (*__wbflush)(void); | ||
| 22 | EXPORT_SYMBOL(__wbflush); | ||
| 23 | |||
| 24 | static void wbflush_loongson(void) | 21 | static void wbflush_loongson(void) |
| 25 | { | 22 | { |
| 26 | asm(".set\tpush\n\t" | 23 | asm(".set\tpush\n\t" |
| @@ -32,10 +29,11 @@ static void wbflush_loongson(void) | |||
| 32 | ".set mips0\n\t"); | 29 | ".set mips0\n\t"); |
| 33 | } | 30 | } |
| 34 | 31 | ||
| 32 | void (*__wbflush)(void) = wbflush_loongson; | ||
| 33 | EXPORT_SYMBOL(__wbflush); | ||
| 34 | |||
| 35 | void __init plat_mem_setup(void) | 35 | void __init plat_mem_setup(void) |
| 36 | { | 36 | { |
| 37 | __wbflush = wbflush_loongson; | ||
| 38 | |||
| 39 | #ifdef CONFIG_VT | 37 | #ifdef CONFIG_VT |
| 40 | #if defined(CONFIG_VGA_CONSOLE) | 38 | #if defined(CONFIG_VGA_CONSOLE) |
| 41 | conswitchp = &vga_con; | 39 | conswitchp = &vga_con; |
diff --git a/arch/mips/loongson/loongson-3/Makefile b/arch/mips/loongson/loongson-3/Makefile index b9968cd1602e..70152b252ddc 100644 --- a/arch/mips/loongson/loongson-3/Makefile +++ b/arch/mips/loongson/loongson-3/Makefile | |||
| @@ -2,3 +2,5 @@ | |||
| 2 | # Makefile for Loongson-3 family machines | 2 | # Makefile for Loongson-3 family machines |
| 3 | # | 3 | # |
| 4 | obj-y += irq.o | 4 | obj-y += irq.o |
| 5 | |||
| 6 | obj-$(CONFIG_SMP) += smp.o | ||
diff --git a/arch/mips/loongson/loongson-3/irq.c b/arch/mips/loongson/loongson-3/irq.c index b2dc62b97a0f..088fd5e4fd64 100644 --- a/arch/mips/loongson/loongson-3/irq.c +++ b/arch/mips/loongson/loongson-3/irq.c | |||
| @@ -26,6 +26,10 @@ void mach_irq_dispatch(unsigned int pending) | |||
| 26 | { | 26 | { |
| 27 | if (pending & CAUSEF_IP7) | 27 | if (pending & CAUSEF_IP7) |
| 28 | do_IRQ(LOONGSON_TIMER_IRQ); | 28 | do_IRQ(LOONGSON_TIMER_IRQ); |
| 29 | #if defined(CONFIG_SMP) | ||
| 30 | else if (pending & CAUSEF_IP6) | ||
| 31 | loongson3_ipi_interrupt(NULL); | ||
| 32 | #endif | ||
| 29 | else if (pending & CAUSEF_IP3) | 33 | else if (pending & CAUSEF_IP3) |
| 30 | ht_irqdispatch(); | 34 | ht_irqdispatch(); |
| 31 | else if (pending & CAUSEF_IP2) | 35 | else if (pending & CAUSEF_IP2) |
| @@ -45,10 +49,26 @@ static inline void mask_loongson_irq(struct irq_data *d) | |||
| 45 | { | 49 | { |
| 46 | clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); | 50 | clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); |
| 47 | irq_disable_hazard(); | 51 | irq_disable_hazard(); |
| 52 | |||
| 53 | /* Workaround: UART IRQ may deliver to any core */ | ||
| 54 | if (d->irq == LOONGSON_UART_IRQ) { | ||
| 55 | int cpu = smp_processor_id(); | ||
| 56 | |||
| 57 | LOONGSON_INT_ROUTER_INTENCLR = 1 << 10; | ||
| 58 | LOONGSON_INT_ROUTER_LPC = 0x10 + (1<<cpu); | ||
| 59 | } | ||
| 48 | } | 60 | } |
| 49 | 61 | ||
| 50 | static inline void unmask_loongson_irq(struct irq_data *d) | 62 | static inline void unmask_loongson_irq(struct irq_data *d) |
| 51 | { | 63 | { |
| 64 | /* Workaround: UART IRQ may deliver to any core */ | ||
| 65 | if (d->irq == LOONGSON_UART_IRQ) { | ||
| 66 | int cpu = smp_processor_id(); | ||
| 67 | |||
| 68 | LOONGSON_INT_ROUTER_INTENSET = 1 << 10; | ||
| 69 | LOONGSON_INT_ROUTER_LPC = 0x10 + (1<<cpu); | ||
| 70 | } | ||
| 71 | |||
| 52 | set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); | 72 | set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); |
| 53 | irq_enable_hazard(); | 73 | irq_enable_hazard(); |
| 54 | } | 74 | } |
diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c new file mode 100644 index 000000000000..93483c25b4b9 --- /dev/null +++ b/arch/mips/loongson/loongson-3/smp.c | |||
| @@ -0,0 +1,267 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010, 2011, 2012, Lemote, Inc. | ||
| 3 | * Author: Chen Huacai, chenhc@lemote.com | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * as published by the Free Software Foundation; either version 2 | ||
| 8 | * of the License, or (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/cpu.h> | ||
| 19 | #include <linux/sched.h> | ||
| 20 | #include <linux/smp.h> | ||
| 21 | #include <linux/cpufreq.h> | ||
| 22 | #include <asm/processor.h> | ||
| 23 | #include <asm/time.h> | ||
| 24 | #include <asm/clock.h> | ||
| 25 | #include <asm/tlbflush.h> | ||
| 26 | #include <loongson.h> | ||
| 27 | |||
| 28 | #include "smp.h" | ||
| 29 | |||
| 30 | /* read a 32bit value from ipi register */ | ||
| 31 | #define loongson3_ipi_read32(addr) readl(addr) | ||
| 32 | /* read a 64bit value from ipi register */ | ||
| 33 | #define loongson3_ipi_read64(addr) readq(addr) | ||
| 34 | /* write a 32bit value to ipi register */ | ||
| 35 | #define loongson3_ipi_write32(action, addr) \ | ||
| 36 | do { \ | ||
| 37 | writel(action, addr); \ | ||
| 38 | __wbflush(); \ | ||
| 39 | } while (0) | ||
| 40 | /* write a 64bit value to ipi register */ | ||
| 41 | #define loongson3_ipi_write64(action, addr) \ | ||
| 42 | do { \ | ||
| 43 | writeq(action, addr); \ | ||
| 44 | __wbflush(); \ | ||
| 45 | } while (0) | ||
| 46 | |||
| 47 | static void *ipi_set0_regs[] = { | ||
| 48 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0), | ||
| 49 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0), | ||
