Commit 05774088391c7430f6a4c1d5d18196ef17bb3ba9
1 parent
c7788792a5
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
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
Showing 8 changed files with 106 additions and 60 deletions Side-by-side Diff
arch/arm/include/asm/psci.h
... | ... | @@ -32,6 +32,15 @@ |
32 | 32 | }; |
33 | 33 | |
34 | 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 | 45 | #endif /* __ASM_ARM_PSCI_H */ |
arch/arm/kernel/Makefile
... | ... | @@ -82,7 +82,10 @@ |
82 | 82 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
83 | 83 | |
84 | 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 | 90 | extra-y := $(head-y) vmlinux.lds |
arch/arm/kernel/psci.c
... | ... | @@ -158,7 +158,7 @@ |
158 | 158 | {}, |
159 | 159 | }; |
160 | 160 | |
161 | -static int __init psci_init(void) | |
161 | +void __init psci_init(void) | |
162 | 162 | { |
163 | 163 | struct device_node *np; |
164 | 164 | const char *method; |
... | ... | @@ -166,7 +166,7 @@ |
166 | 166 | |
167 | 167 | np = of_find_matching_node(NULL, psci_of_match); |
168 | 168 | if (!np) |
169 | - return 0; | |
169 | + return; | |
170 | 170 | |
171 | 171 | pr_info("probing function IDs from device-tree\n"); |
172 | 172 | |
173 | 173 | |
... | ... | @@ -206,7 +206,6 @@ |
206 | 206 | |
207 | 207 | out_put_node: |
208 | 208 | of_node_put(np); |
209 | - return 0; | |
209 | + return; | |
210 | 210 | } |
211 | -early_initcall(psci_init); |
arch/arm/kernel/psci_smp.c
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 | +}; |
arch/arm/kernel/setup.c
... | ... | @@ -37,6 +37,7 @@ |
37 | 37 | #include <asm/cputype.h> |
38 | 38 | #include <asm/elf.h> |
39 | 39 | #include <asm/procinfo.h> |
40 | +#include <asm/psci.h> | |
40 | 41 | #include <asm/sections.h> |
41 | 42 | #include <asm/setup.h> |
42 | 43 | #include <asm/smp_plat.h> |
43 | 44 | |
... | ... | @@ -796,9 +797,13 @@ |
796 | 797 | unflatten_device_tree(); |
797 | 798 | |
798 | 799 | arm_dt_init_cpu_maps(); |
800 | + psci_init(); | |
799 | 801 | #ifdef CONFIG_SMP |
800 | 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 | 807 | smp_init_cpus(); |
803 | 808 | } |
804 | 809 | #endif |
arch/arm/mach-virt/Makefile
arch/arm/mach-virt/platsmp.c
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 | -}; |
arch/arm/mach-virt/virt.c
... | ... | @@ -36,12 +36,9 @@ |
36 | 36 | NULL |
37 | 37 | }; |
38 | 38 | |
39 | -extern struct smp_operations virt_smp_ops; | |
40 | - | |
41 | 39 | DT_MACHINE_START(VIRT, "Dummy Virtual Machine") |
42 | 40 | .init_irq = irqchip_init, |
43 | 41 | .init_machine = virt_init, |
44 | - .smp = smp_ops(virt_smp_ops), | |
45 | 42 | .dt_compat = virt_dt_match, |
46 | 43 | MACHINE_END |