diff options
author | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2013-05-21 10:24:11 -0400 |
---|---|---|
committer | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2013-05-21 10:24:11 -0400 |
commit | 05774088391c7430f6a4c1d5d18196ef17bb3ba9 (patch) | |
tree | f8263dcb34690375f12de8b533c426138b53d5a0 /arch | |
parent | c7788792a5e7b0d5d7f96d0766b4cb6112d47d75 (diff) |
arm: introduce psci_smp_ops
Rename virt_smp_ops to psci_smp_ops and move them to arch/arm/kernel/psci_smp.c.
Remove mach-virt/platsmp.c, now unused.
Compile psci_smp if CONFIG_ARM_PSCI and CONFIG_SMP.
Add a cpu_die smp_op based on psci_ops.cpu_off.
Initialize PSCI before setting smp_ops in setup_arch.
If PSCI is available on the platform, prefer psci_smp_ops over the
platform smp_ops.
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Acked-by: Will Deacon <will.deacon@arm.com>
CC: arnd@arndb.de
CC: marc.zyngier@arm.com
CC: linux@arm.linux.org.uk
CC: nico@linaro.org
CC: rob.herring@calxeda.com
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/psci.h | 9 | ||||
-rw-r--r-- | arch/arm/kernel/Makefile | 5 | ||||
-rw-r--r-- | arch/arm/kernel/psci.c | 7 | ||||
-rw-r--r-- | arch/arm/kernel/psci_smp.c | 84 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-virt/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-virt/platsmp.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-virt/virt.c | 3 |
8 files changed, 106 insertions, 60 deletions
diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h index ce0dbe7c1625..c4ae171850f8 100644 --- a/arch/arm/include/asm/psci.h +++ b/arch/arm/include/asm/psci.h | |||
@@ -32,5 +32,14 @@ struct psci_operations { | |||
32 | }; | 32 | }; |
33 | 33 | ||
34 | extern struct psci_operations psci_ops; | 34 | extern struct psci_operations psci_ops; |
35 | extern struct smp_operations psci_smp_ops; | ||
36 | |||
37 | #ifdef CONFIG_ARM_PSCI | ||
38 | void psci_init(void); | ||
39 | bool psci_smp_available(void); | ||
40 | #else | ||
41 | static inline void psci_init(void) { } | ||
42 | static inline bool psci_smp_available(void) { return false; } | ||
43 | #endif | ||
35 | 44 | ||
36 | #endif /* __ASM_ARM_PSCI_H */ | 45 | #endif /* __ASM_ARM_PSCI_H */ |
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5f3338eacad2..dd9d90ab65d0 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -82,6 +82,9 @@ obj-$(CONFIG_DEBUG_LL) += debug.o | |||
82 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 82 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
83 | 83 | ||
84 | obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o | 84 | obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o |
85 | obj-$(CONFIG_ARM_PSCI) += psci.o | 85 | ifeq ($(CONFIG_ARM_PSCI),y) |
86 | obj-y += psci.o | ||
87 | obj-$(CONFIG_SMP) += psci_smp.o | ||
88 | endif | ||
86 | 89 | ||
87 | extra-y := $(head-y) vmlinux.lds | 90 | extra-y := $(head-y) vmlinux.lds |
diff --git a/arch/arm/kernel/psci.c b/arch/arm/kernel/psci.c index 36531643cc2c..46931880093d 100644 --- a/arch/arm/kernel/psci.c +++ b/arch/arm/kernel/psci.c | |||
@@ -158,7 +158,7 @@ static const struct of_device_id psci_of_match[] __initconst = { | |||
158 | {}, | 158 | {}, |
159 | }; | 159 | }; |
160 | 160 | ||
161 | static int __init psci_init(void) | 161 | void __init psci_init(void) |
162 | { | 162 | { |
163 | struct device_node *np; | 163 | struct device_node *np; |
164 | const char *method; | 164 | const char *method; |
@@ -166,7 +166,7 @@ static int __init psci_init(void) | |||
166 | 166 | ||
167 | np = of_find_matching_node(NULL, psci_of_match); | 167 | np = of_find_matching_node(NULL, psci_of_match); |
168 | if (!np) | 168 | if (!np) |
169 | return 0; | 169 | return; |
170 | 170 | ||
171 | pr_info("probing function IDs from device-tree\n"); | 171 | pr_info("probing function IDs from device-tree\n"); |
172 | 172 | ||
@@ -206,6 +206,5 @@ static int __init psci_init(void) | |||
206 | 206 | ||
207 | out_put_node: | 207 | out_put_node: |
208 | of_node_put(np); | 208 | of_node_put(np); |
209 | return 0; | 209 | return; |
210 | } | 210 | } |
211 | early_initcall(psci_init); | ||
diff --git a/arch/arm/kernel/psci_smp.c b/arch/arm/kernel/psci_smp.c new file mode 100644 index 000000000000..23a11424c568 --- /dev/null +++ b/arch/arm/kernel/psci_smp.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * Copyright (C) 2012 ARM Limited | ||
12 | * | ||
13 | * Author: Will Deacon <will.deacon@arm.com> | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/irqchip/arm-gic.h> | ||
18 | #include <linux/smp.h> | ||
19 | #include <linux/of.h> | ||
20 | |||
21 | #include <asm/psci.h> | ||
22 | #include <asm/smp_plat.h> | ||
23 | |||
24 | /* | ||
25 | * psci_smp assumes that the following is true about PSCI: | ||
26 | * | ||
27 | * cpu_suspend Suspend the execution on a CPU | ||
28 | * @state we don't currently describe affinity levels, so just pass 0. | ||
29 | * @entry_point the first instruction to be executed on return | ||
30 | * returns 0 success, < 0 on failure | ||
31 | * | ||
32 | * cpu_off Power down a CPU | ||
33 | * @state we don't currently describe affinity levels, so just pass 0. | ||
34 | * no return on successful call | ||
35 | * | ||
36 | * cpu_on Power up a CPU | ||
37 | * @cpuid cpuid of target CPU, as from MPIDR | ||
38 | * @entry_point the first instruction to be executed on return | ||
39 | * returns 0 success, < 0 on failure | ||
40 | * | ||
41 | * migrate Migrate the context to a different CPU | ||
42 | * @cpuid cpuid of target CPU, as from MPIDR | ||
43 | * returns 0 success, < 0 on failure | ||
44 | * | ||
45 | */ | ||
46 | |||
47 | extern void secondary_startup(void); | ||
48 | |||
49 | static int __cpuinit psci_boot_secondary(unsigned int cpu, | ||
50 | struct task_struct *idle) | ||
51 | { | ||
52 | if (psci_ops.cpu_on) | ||
53 | return psci_ops.cpu_on(cpu_logical_map(cpu), | ||
54 | __pa(secondary_startup)); | ||
55 | return -ENODEV; | ||
56 | } | ||
57 | |||
58 | #ifdef CONFIG_HOTPLUG_CPU | ||
59 | void __ref psci_cpu_die(unsigned int cpu) | ||
60 | { | ||
61 | const struct psci_power_state ps = { | ||
62 | .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, | ||
63 | }; | ||
64 | |||
65 | if (psci_ops.cpu_off) | ||
66 | psci_ops.cpu_off(ps); | ||
67 | |||
68 | /* We should never return */ | ||
69 | panic("psci: cpu %d failed to shutdown\n", cpu); | ||
70 | } | ||
71 | #else | ||
72 | #define psci_cpu_die NULL | ||
73 | #endif | ||
74 | |||
75 | bool __init psci_smp_available(void) | ||
76 | { | ||
77 | /* is cpu_on available at least? */ | ||
78 | return (psci_ops.cpu_on != NULL); | ||
79 | } | ||
80 | |||
81 | struct smp_operations __initdata psci_smp_ops = { | ||
82 | .smp_boot_secondary = psci_boot_secondary, | ||
83 | .cpu_die = psci_cpu_die, | ||
84 | }; | ||
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 1522c7ae31b0..8f7a6e9926a8 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <asm/cputype.h> | 37 | #include <asm/cputype.h> |
38 | #include <asm/elf.h> | 38 | #include <asm/elf.h> |
39 | #include <asm/procinfo.h> | 39 | #include <asm/procinfo.h> |
40 | #include <asm/psci.h> | ||
40 | #include <asm/sections.h> | 41 | #include <asm/sections.h> |
41 | #include <asm/setup.h> | 42 | #include <asm/setup.h> |
42 | #include <asm/smp_plat.h> | 43 | #include <asm/smp_plat.h> |
@@ -796,9 +797,13 @@ void __init setup_arch(char **cmdline_p) | |||
796 | unflatten_device_tree(); | 797 | unflatten_device_tree(); |
797 | 798 | ||
798 | arm_dt_init_cpu_maps(); | 799 | arm_dt_init_cpu_maps(); |
800 | psci_init(); | ||
799 | #ifdef CONFIG_SMP | 801 | #ifdef CONFIG_SMP |
800 | if (is_smp()) { | 802 | if (is_smp()) { |
801 | smp_set_ops(mdesc->smp); | 803 | if (psci_smp_available()) |
804 | smp_set_ops(&psci_smp_ops); | ||
805 | else if (mdesc->smp) | ||
806 | smp_set_ops(mdesc->smp); | ||
802 | smp_init_cpus(); | 807 | smp_init_cpus(); |
803 | } | 808 | } |
804 | #endif | 809 | #endif |
diff --git a/arch/arm/mach-virt/Makefile b/arch/arm/mach-virt/Makefile index 042afc1f8c44..7ddbfa60227f 100644 --- a/arch/arm/mach-virt/Makefile +++ b/arch/arm/mach-virt/Makefile | |||
@@ -3,4 +3,3 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := virt.o | 5 | obj-y := virt.o |
6 | obj-$(CONFIG_SMP) += platsmp.o | ||
diff --git a/arch/arm/mach-virt/platsmp.c b/arch/arm/mach-virt/platsmp.c deleted file mode 100644 index f4143f5bfa5b..000000000000 --- a/arch/arm/mach-virt/platsmp.c +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | /* | ||
2 | * Dummy Virtual Machine - does what it says on the tin. | ||
3 | * | ||
4 | * Copyright (C) 2012 ARM Ltd | ||
5 | * Author: Will Deacon <will.deacon@arm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/init.h> | ||
21 | #include <linux/smp.h> | ||
22 | #include <linux/of.h> | ||
23 | |||
24 | #include <asm/psci.h> | ||
25 | #include <asm/smp_plat.h> | ||
26 | |||
27 | extern void secondary_startup(void); | ||
28 | |||
29 | static void __init virt_smp_init_cpus(void) | ||
30 | { | ||
31 | } | ||
32 | |||
33 | static void __init virt_smp_prepare_cpus(unsigned int max_cpus) | ||
34 | { | ||
35 | } | ||
36 | |||
37 | static int __cpuinit virt_boot_secondary(unsigned int cpu, | ||
38 | struct task_struct *idle) | ||
39 | { | ||
40 | if (psci_ops.cpu_on) | ||
41 | return psci_ops.cpu_on(cpu_logical_map(cpu), | ||
42 | __pa(secondary_startup)); | ||
43 | return -ENODEV; | ||
44 | } | ||
45 | |||
46 | struct smp_operations __initdata virt_smp_ops = { | ||
47 | .smp_init_cpus = virt_smp_init_cpus, | ||
48 | .smp_prepare_cpus = virt_smp_prepare_cpus, | ||
49 | .smp_boot_secondary = virt_boot_secondary, | ||
50 | }; | ||
diff --git a/arch/arm/mach-virt/virt.c b/arch/arm/mach-virt/virt.c index 061f283f579e..a67d2dd5bb60 100644 --- a/arch/arm/mach-virt/virt.c +++ b/arch/arm/mach-virt/virt.c | |||
@@ -36,11 +36,8 @@ static const char *virt_dt_match[] = { | |||
36 | NULL | 36 | NULL |
37 | }; | 37 | }; |
38 | 38 | ||
39 | extern struct smp_operations virt_smp_ops; | ||
40 | |||
41 | DT_MACHINE_START(VIRT, "Dummy Virtual Machine") | 39 | DT_MACHINE_START(VIRT, "Dummy Virtual Machine") |
42 | .init_irq = irqchip_init, | 40 | .init_irq = irqchip_init, |
43 | .init_machine = virt_init, | 41 | .init_machine = virt_init, |
44 | .smp = smp_ops(virt_smp_ops), | ||
45 | .dt_compat = virt_dt_match, | 42 | .dt_compat = virt_dt_match, |
46 | MACHINE_END | 43 | MACHINE_END |