diff options
author | Gregory CLEMENT <gregory.clement@free-electrons.com> | 2012-11-14 16:51:08 -0500 |
---|---|---|
committer | Gregory CLEMENT <gregory.clement@free-electrons.com> | 2012-11-21 10:49:38 -0500 |
commit | 45f5984a8a528f7507f3ec860d297934d4449ad1 (patch) | |
tree | 2491bbc83f450f2630ab2b3792698f29c374b79b | |
parent | de4901933f6dfc0180f761790d3f47fc64e6270f (diff) |
arm: mvebu: Add SMP support for Armada XP
This enables SMP support on the Armada XP processor. It adds the
mandatory functions to support SMP such as: the SMP initialization
functions in platsmp.c, the secondary CPU entry point in headsmp.S and
the CPU hotplug initial support in hotplug.c.
Signed-off-by: Yehuda Yitschak <yehuday@marvell.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Reviewed-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | arch/arm/configs/mvebu_defconfig | 3 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/armada-370-xp.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/common.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/headsmp.S | 49 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/hotplug.c | 30 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/platsmp.c | 122 |
8 files changed, 213 insertions, 0 deletions
diff --git a/arch/arm/configs/mvebu_defconfig b/arch/arm/configs/mvebu_defconfig index 3458752c4bb2..da598d37a65f 100644 --- a/arch/arm/configs/mvebu_defconfig +++ b/arch/arm/configs/mvebu_defconfig | |||
@@ -12,6 +12,9 @@ CONFIG_ARCH_MVEBU=y | |||
12 | CONFIG_MACH_ARMADA_370=y | 12 | CONFIG_MACH_ARMADA_370=y |
13 | CONFIG_MACH_ARMADA_XP=y | 13 | CONFIG_MACH_ARMADA_XP=y |
14 | # CONFIG_CACHE_L2X0 is not set | 14 | # CONFIG_CACHE_L2X0 is not set |
15 | # CONFIG_SWP_EMULATE is not set | ||
16 | CONFIG_SMP=y | ||
17 | # CONFIG_LOCAL_TIMERS is not set | ||
15 | CONFIG_AEABI=y | 18 | CONFIG_AEABI=y |
16 | CONFIG_HIGHMEM=y | 19 | CONFIG_HIGHMEM=y |
17 | # CONFIG_COMPACTION is not set | 20 | # CONFIG_COMPACTION is not set |
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index f4c3bf88f178..c934e1d4933d 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig | |||
@@ -21,6 +21,7 @@ menu "Marvell SOC with device tree" | |||
21 | config MACH_ARMADA_370_XP | 21 | config MACH_ARMADA_370_XP |
22 | bool | 22 | bool |
23 | select ARMADA_370_XP_TIMER | 23 | select ARMADA_370_XP_TIMER |
24 | select HAVE_SMP | ||
24 | select CPU_PJ4B | 25 | select CPU_PJ4B |
25 | 26 | ||
26 | config MACH_ARMADA_370 | 27 | config MACH_ARMADA_370 |
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 2e3ec11c51e6..5dcb369b58aa 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile | |||
@@ -3,3 +3,5 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \ | |||
3 | 3 | ||
4 | obj-y += system-controller.o | 4 | obj-y += system-controller.o |
5 | obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o coherency.o coherency_ll.o pmsu.o | 5 | obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o coherency.o coherency_ll.o pmsu.o |
6 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | ||
7 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | ||
diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index 3292d6da5dc7..472e70ffce8d 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.c +++ b/arch/arm/mach-mvebu/armada-370-xp.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <asm/mach/time.h> | 23 | #include <asm/mach/time.h> |
24 | #include "armada-370-xp.h" | 24 | #include "armada-370-xp.h" |
25 | #include "common.h" | 25 | #include "common.h" |
26 | #include "coherency.h" | ||
26 | 27 | ||
27 | static struct map_desc armada_370_xp_io_desc[] __initdata = { | 28 | static struct map_desc armada_370_xp_io_desc[] __initdata = { |
28 | { | 29 | { |
@@ -51,6 +52,7 @@ struct sys_timer armada_370_xp_timer = { | |||
51 | static void __init armada_370_xp_dt_init(void) | 52 | static void __init armada_370_xp_dt_init(void) |
52 | { | 53 | { |
53 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); | 54 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); |
55 | coherency_init(); | ||
54 | } | 56 | } |
55 | 57 | ||
56 | static const char * const armada_370_xp_dt_board_dt_compat[] = { | 58 | static const char * const armada_370_xp_dt_board_dt_compat[] = { |
@@ -60,6 +62,7 @@ static const char * const armada_370_xp_dt_board_dt_compat[] = { | |||
60 | }; | 62 | }; |
61 | 63 | ||
62 | DT_MACHINE_START(ARMADA_XP_DT, "Marvell Aramada 370/XP (Device Tree)") | 64 | DT_MACHINE_START(ARMADA_XP_DT, "Marvell Aramada 370/XP (Device Tree)") |
65 | .smp = smp_ops(armada_xp_smp_ops), | ||
63 | .init_machine = armada_370_xp_dt_init, | 66 | .init_machine = armada_370_xp_dt_init, |
64 | .map_io = armada_370_xp_map_io, | 67 | .map_io = armada_370_xp_map_io, |
65 | .init_irq = armada_370_xp_init_irq, | 68 | .init_irq = armada_370_xp_init_irq, |
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index 9285d0496651..aa27bc2ffb60 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/arch/arm/mach-mvebu/common.h | |||
@@ -20,6 +20,9 @@ void mvebu_restart(char mode, const char *cmd); | |||
20 | void armada_370_xp_init_irq(void); | 20 | void armada_370_xp_init_irq(void); |
21 | void armada_370_xp_handle_irq(struct pt_regs *regs); | 21 | void armada_370_xp_handle_irq(struct pt_regs *regs); |
22 | 22 | ||
23 | void armada_xp_cpu_die(unsigned int cpu); | ||
23 | int armada_370_xp_coherency_init(void); | 24 | int armada_370_xp_coherency_init(void); |
24 | int armada_370_xp_pmsu_init(void); | 25 | int armada_370_xp_pmsu_init(void); |
26 | void armada_xp_secondary_startup(void); | ||
27 | extern struct smp_operations armada_xp_smp_ops; | ||
25 | #endif | 28 | #endif |
diff --git a/arch/arm/mach-mvebu/headsmp.S b/arch/arm/mach-mvebu/headsmp.S new file mode 100644 index 000000000000..a06e0ede8c08 --- /dev/null +++ b/arch/arm/mach-mvebu/headsmp.S | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * SMP support: Entry point for secondary CPUs | ||
3 | * | ||
4 | * Copyright (C) 2012 Marvell | ||
5 | * | ||
6 | * Yehuda Yitschak <yehuday@marvell.com> | ||
7 | * Gregory CLEMENT <gregory.clement@free-electrons.com> | ||
8 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public | ||
11 | * License version 2. This program is licensed "as is" without any | ||
12 | * warranty of any kind, whether express or implied. | ||
13 | * | ||
14 | * This file implements the assembly entry point for secondary CPUs in | ||
15 | * an SMP kernel. The only thing we need to do is to add the CPU to | ||
16 | * the coherency fabric by writing to 2 registers. Currently the base | ||
17 | * register addresses are hard coded due to the early initialisation | ||
18 | * problems. | ||
19 | */ | ||
20 | |||
21 | #include <linux/linkage.h> | ||
22 | #include <linux/init.h> | ||
23 | |||
24 | /* | ||
25 | * At this stage the secondary CPUs don't have acces yet to the MMU, so | ||
26 | * we have to provide physical addresses | ||
27 | */ | ||
28 | #define ARMADA_XP_CFB_BASE 0xD0020200 | ||
29 | |||
30 | __CPUINIT | ||
31 | |||
32 | /* | ||
33 | * Armada XP specific entry point for secondary CPUs. | ||
34 | * We add the CPU to the coherency fabric and then jump to secondary | ||
35 | * startup | ||
36 | */ | ||
37 | ENTRY(armada_xp_secondary_startup) | ||
38 | |||
39 | /* Read CPU id */ | ||
40 | mrc p15, 0, r1, c0, c0, 5 | ||
41 | and r1, r1, #0xF | ||
42 | |||
43 | /* Add CPU to coherency fabric */ | ||
44 | ldr r0, =ARMADA_XP_CFB_BASE | ||
45 | |||
46 | bl ll_set_cpu_coherent | ||
47 | b secondary_startup | ||
48 | |||
49 | ENDPROC(armada_xp_secondary_startup) | ||
diff --git a/arch/arm/mach-mvebu/hotplug.c b/arch/arm/mach-mvebu/hotplug.c new file mode 100644 index 000000000000..b228b6a80c85 --- /dev/null +++ b/arch/arm/mach-mvebu/hotplug.c | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Symmetric Multi Processing (SMP) support for Armada XP | ||
3 | * | ||
4 | * Copyright (C) 2012 Marvell | ||
5 | * | ||
6 | * Lior Amsalem <alior@marvell.com> | ||
7 | * Gregory CLEMENT <gregory.clement@free-electrons.com> | ||
8 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public | ||
11 | * License version 2. This program is licensed "as is" without any | ||
12 | * warranty of any kind, whether express or implied. | ||
13 | */ | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/smp.h> | ||
17 | #include <asm/proc-fns.h> | ||
18 | |||
19 | /* | ||
20 | * platform-specific code to shutdown a CPU | ||
21 | * | ||
22 | * Called with IRQs disabled | ||
23 | */ | ||
24 | void __ref armada_xp_cpu_die(unsigned int cpu) | ||
25 | { | ||
26 | cpu_do_idle(); | ||
27 | |||
28 | /* We should never return from idle */ | ||
29 | panic("mvebu: cpu %d unexpectedly exit from shutdown\n", cpu); | ||
30 | } | ||
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c new file mode 100644 index 000000000000..fe16aaf7c19c --- /dev/null +++ b/arch/arm/mach-mvebu/platsmp.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * Symmetric Multi Processing (SMP) support for Armada XP | ||
3 | * | ||
4 | * Copyright (C) 2012 Marvell | ||
5 | * | ||
6 | * Lior Amsalem <alior@marvell.com> | ||
7 | * Yehuda Yitschak <yehuday@marvell.com> | ||
8 | * Gregory CLEMENT <gregory.clement@free-electrons.com> | ||
9 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | ||
10 | * | ||
11 | * This file is licensed under the terms of the GNU General Public | ||
12 | * License version 2. This program is licensed "as is" without any | ||
13 | * warranty of any kind, whether express or implied. | ||
14 | * | ||
15 | * The Armada XP SoC has 4 ARMv7 PJ4B CPUs running in full HW coherency | ||
16 | * This file implements the routines for preparing the SMP infrastructure | ||
17 | * and waking up the secondary CPUs | ||
18 | */ | ||
19 | |||
20 | #include <linux/init.h> | ||
21 | #include <linux/smp.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <asm/cacheflush.h> | ||
25 | #include <asm/smp_plat.h> | ||
26 | #include "common.h" | ||
27 | #include "armada-370-xp.h" | ||
28 | #include "pmsu.h" | ||
29 | #include "coherency.h" | ||
30 | |||
31 | void __init set_secondary_cpus_clock(void) | ||
32 | { | ||
33 | int thiscpu; | ||
34 | unsigned long rate; | ||
35 | struct clk *cpu_clk = NULL; | ||
36 | struct device_node *np = NULL; | ||
37 | |||
38 | thiscpu = smp_processor_id(); | ||
39 | for_each_node_by_type(np, "cpu") { | ||
40 | int err; | ||
41 | int cpu; | ||
42 | |||
43 | err = of_property_read_u32(np, "reg", &cpu); | ||
44 | if (WARN_ON(err)) | ||
45 | return; | ||
46 | |||
47 | if (cpu == thiscpu) { | ||
48 | cpu_clk = of_clk_get(np, 0); | ||
49 | break; | ||
50 | } | ||
51 | } | ||
52 | if (WARN_ON(IS_ERR(cpu_clk))) | ||
53 | return; | ||
54 | clk_prepare_enable(cpu_clk); | ||
55 | rate = clk_get_rate(cpu_clk); | ||
56 | |||
57 | /* set all the other CPU clk to the same rate than the boot CPU */ | ||
58 | for_each_node_by_type(np, "cpu") { | ||
59 | int err; | ||
60 | int cpu; | ||
61 | |||
62 | err = of_property_read_u32(np, "reg", &cpu); | ||
63 | if (WARN_ON(err)) | ||
64 | return; | ||
65 | |||
66 | if (cpu != thiscpu) { | ||
67 | cpu_clk = of_clk_get(np, 0); | ||
68 | clk_set_rate(cpu_clk, rate); | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | static void __cpuinit armada_xp_secondary_init(unsigned int cpu) | ||
74 | { | ||
75 | armada_xp_mpic_smp_cpu_init(); | ||
76 | } | ||
77 | |||
78 | static int __cpuinit armada_xp_boot_secondary(unsigned int cpu, | ||
79 | struct task_struct *idle) | ||
80 | { | ||
81 | pr_info("Booting CPU %d\n", cpu); | ||
82 | |||
83 | armada_xp_boot_cpu(cpu, armada_xp_secondary_startup); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static void __init armada_xp_smp_init_cpus(void) | ||
89 | { | ||
90 | unsigned int i, ncores; | ||
91 | ncores = coherency_get_cpu_count(); | ||
92 | |||
93 | /* Limit possible CPUs to defconfig */ | ||
94 | if (ncores > nr_cpu_ids) { | ||
95 | pr_warn("SMP: %d CPUs physically present. Only %d configured.", | ||
96 | ncores, nr_cpu_ids); | ||
97 | pr_warn("Clipping CPU count to %d\n", nr_cpu_ids); | ||
98 | ncores = nr_cpu_ids; | ||
99 | } | ||
100 | |||
101 | for (i = 0; i < ncores; i++) | ||
102 | set_cpu_possible(i, true); | ||
103 | |||
104 | set_smp_cross_call(armada_mpic_send_doorbell); | ||
105 | } | ||
106 | |||
107 | void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus) | ||
108 | { | ||
109 | set_secondary_cpus_clock(); | ||
110 | flush_cache_all(); | ||
111 | set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); | ||
112 | } | ||
113 | |||
114 | struct smp_operations armada_xp_smp_ops __initdata = { | ||
115 | .smp_init_cpus = armada_xp_smp_init_cpus, | ||
116 | .smp_prepare_cpus = armada_xp_smp_prepare_cpus, | ||
117 | .smp_secondary_init = armada_xp_secondary_init, | ||
118 | .smp_boot_secondary = armada_xp_boot_secondary, | ||
119 | #ifdef CONFIG_HOTPLUG_CPU | ||
120 | .cpu_die = armada_xp_cpu_die, | ||
121 | #endif | ||
122 | }; | ||