]>
Commit | Line | Data |
---|---|---|
045ab94e RK |
1 | /* |
2 | * Copyright (C) 1996-2000 Russell King - Converted to ARM. | |
3 | * Original Copyright (C) 1995 Linus Torvalds | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | */ | |
9 | #include <linux/cpu.h> | |
10 | #include <linux/delay.h> | |
11 | #include <linux/reboot.h> | |
12 | ||
13 | #include <asm/cacheflush.h> | |
14 | #include <asm/idmap.h> | |
9da5ac23 | 15 | #include <asm/virt.h> |
045ab94e RK |
16 | |
17 | #include "reboot.h" | |
18 | ||
9da5ac23 | 19 | typedef void (*phys_reset_t)(unsigned long, bool); |
045ab94e RK |
20 | |
21 | /* | |
22 | * Function pointers to optional machine specific functions | |
23 | */ | |
24 | void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); | |
25 | void (*pm_power_off)(void); | |
26 | EXPORT_SYMBOL(pm_power_off); | |
27 | ||
28 | /* | |
29 | * A temporary stack to use for CPU reset. This is static so that we | |
30 | * don't clobber it with the identity mapping. When running with this | |
31 | * stack, any references to the current task *will not work* so you | |
32 | * should really do as little as possible before jumping to your reset | |
33 | * code. | |
34 | */ | |
35 | static u64 soft_restart_stack[16]; | |
36 | ||
37 | static void __soft_restart(void *addr) | |
38 | { | |
39 | phys_reset_t phys_reset; | |
40 | ||
41 | /* Take out a flat memory mapping. */ | |
42 | setup_mm_for_reboot(); | |
43 | ||
44 | /* Clean and invalidate caches */ | |
45 | flush_cache_all(); | |
46 | ||
47 | /* Turn off caching */ | |
48 | cpu_proc_fin(); | |
49 | ||
50 | /* Push out any further dirty data, and ensure cache is empty */ | |
51 | flush_cache_all(); | |
52 | ||
53 | /* Switch to the identity mapping. */ | |
28410293 | 54 | phys_reset = (phys_reset_t)virt_to_idmap(cpu_reset); |
9da5ac23 RK |
55 | |
56 | /* original stub should be restored by kvm */ | |
57 | phys_reset((unsigned long)addr, is_hyp_mode_available()); | |
045ab94e RK |
58 | |
59 | /* Should never get here. */ | |
60 | BUG(); | |
61 | } | |
62 | ||
63 | void _soft_restart(unsigned long addr, bool disable_l2) | |
64 | { | |
65 | u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack); | |
66 | ||
67 | /* Disable interrupts first */ | |
68 | raw_local_irq_disable(); | |
69 | local_fiq_disable(); | |
70 | ||
71 | /* Disable the L2 if we're the last man standing. */ | |
72 | if (disable_l2) | |
73 | outer_disable(); | |
74 | ||
75 | /* Change to the new stack and continue with the reset. */ | |
76 | call_with_stack(__soft_restart, (void *)addr, (void *)stack); | |
77 | ||
78 | /* Should never get here. */ | |
79 | BUG(); | |
80 | } | |
81 | ||
82 | void soft_restart(unsigned long addr) | |
83 | { | |
84 | _soft_restart(addr, num_online_cpus() == 1); | |
85 | } | |
86 | ||
87 | /* | |
88 | * Called by kexec, immediately prior to machine_kexec(). | |
89 | * | |
90 | * This must completely disable all secondary CPUs; simply causing those CPUs | |
91 | * to execute e.g. a RAM-based pin loop is not sufficient. This allows the | |
92 | * kexec'd kernel to use any and all RAM as it sees fit, without having to | |
93 | * avoid any code or data used by any SW CPU pin loop. The CPU hotplug | |
94 | * functionality embodied in disable_nonboot_cpus() to achieve this. | |
95 | */ | |
96 | void machine_shutdown(void) | |
97 | { | |
98 | disable_nonboot_cpus(); | |
99 | } | |
100 | ||
101 | /* | |
102 | * Halting simply requires that the secondary CPUs stop performing any | |
103 | * activity (executing tasks, handling interrupts). smp_send_stop() | |
104 | * achieves this. | |
105 | */ | |
106 | void machine_halt(void) | |
107 | { | |
108 | local_irq_disable(); | |
109 | smp_send_stop(); | |
045ab94e RK |
110 | while (1); |
111 | } | |
112 | ||
113 | /* | |
114 | * Power-off simply requires that the secondary CPUs stop performing any | |
115 | * activity (executing tasks, handling interrupts). smp_send_stop() | |
116 | * achieves this. When the system power is turned off, it will take all CPUs | |
117 | * with it. | |
118 | */ | |
119 | void machine_power_off(void) | |
120 | { | |
121 | local_irq_disable(); | |
122 | smp_send_stop(); | |
123 | ||
124 | if (pm_power_off) | |
125 | pm_power_off(); | |
126 | } | |
127 | ||
128 | /* | |
129 | * Restart requires that the secondary CPUs stop performing any activity | |
130 | * while the primary CPU resets the system. Systems with a single CPU can | |
131 | * use soft_restart() as their machine descriptor's .restart hook, since that | |
132 | * will cause the only available CPU to reset. Systems with multiple CPUs must | |
133 | * provide a HW restart implementation, to ensure that all CPUs reset at once. | |
134 | * This is required so that any code running after reset on the primary CPU | |
135 | * doesn't have to co-ordinate with other CPUs to ensure they aren't still | |
136 | * executing pre-reset code, and using RAM that the primary CPU's code wishes | |
137 | * to use. Implementing such co-ordination would be essentially impossible. | |
138 | */ | |
139 | void machine_restart(char *cmd) | |
140 | { | |
141 | local_irq_disable(); | |
142 | smp_send_stop(); | |
143 | ||
144 | if (arm_pm_restart) | |
145 | arm_pm_restart(reboot_mode, cmd); | |
146 | else | |
147 | do_kernel_restart(cmd); | |
148 | ||
149 | /* Give a grace period for failure to restart of 1s */ | |
150 | mdelay(1000); | |
151 | ||
152 | /* Whoops - the platform was unable to reboot. Tell the user! */ | |
153 | printk("Reboot failed -- System halted\n"); | |
045ab94e RK |
154 | while (1); |
155 | } |