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