| 1 | |
| 2 | |
| 3 | * Copyright (C) 1996-2000 Russell King - Converted to ARM.
|
| 4 | * Original Copyright (C) 1995 Linus Torvalds
|
| 5 |
|
| 6 | #include <linux/cpu.h>
|
| 7 | #include <linux/delay.h>
|
| 8 | #include <linux/reboot.h>
|
| 9 |
|
| 10 | #include <asm/cacheflush.h>
|
| 11 | #include <asm/idmap.h>
|
| 12 | #include <asm/virt.h>
|
| 13 | #include <asm/system_misc.h>
|
| 14 |
|
| 15 | #include "reboot.h"
|
| 16 |
|
| 17 | typedef void (*phys_reset_t)(unsigned long, bool);
|
| 18 |
|
| 19 | |
| 20 | * Function pointers to optional machine specific functions
|
| 21 |
|
| 22 | void (*pm_power_off)(void);
|
| 23 | EXPORT_SYMBOL(pm_power_off);
|
| 24 |
|
| 25 | |
| 26 | * A temporary stack to use for CPU reset. This is static so that we
|
| 27 | * don't clobber it with the identity mapping. When running with this
|
| 28 | * stack, any references to the current task *will not work* so you
|
| 29 | * should really do as little as possible before jumping to your reset
|
| 30 | * code.
|
| 31 |
|
| 32 | static u64 soft_restart_stack[16];
|
| 33 |
|
| 34 | static void __soft_restart(void *addr)
|
| 35 | {
|
| 36 | phys_reset_t phys_reset;
|
| 37 |
|
| 38 |
|
| 39 | setup_mm_for_reboot();
|
| 40 |
|
| 41 |
|
| 42 | flush_cache_all();
|
| 43 |
|
| 44 |
|
| 45 | cpu_proc_fin();
|
| 46 |
|
| 47 |
|
| 48 | flush_cache_all();
|
| 49 |
|
| 50 |
|
| 51 | phys_reset = (phys_reset_t)virt_to_idmap(cpu_reset);
|
| 52 |
|
| 53 |
|
| 54 | phys_reset((unsigned long)addr, is_hyp_mode_available());
|
| 55 |
|
| 56 |
|
| 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 |
|
| 65 | raw_local_irq_disable();
|
| 66 | local_fiq_disable();
|
| 67 |
|
| 68 |
|
| 69 | if (disable_l2)
|
| 70 | outer_disable();
|
| 71 |
|
| 72 |
|
| 73 | call_with_stack(__soft_restart, (void *)addr, (void *)stack);
|
| 74 |
|
| 75 |
|
| 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 smp_shutdown_nonboot_cpus() to achieve this.
|
| 92 |
|
| 93 | void machine_shutdown(void)
|
| 94 | {
|
| 95 | smp_shutdown_nonboot_cpus(reboot_cpu);
|
| 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 | while (1);
|
| 108 | }
|
| 109 |
|
| 110 | |
| 111 | * Power-off simply requires that the secondary CPUs stop performing any
|
| 112 | * activity (executing tasks, handling interrupts). smp_send_stop()
|
| 113 | * achieves this. When the system power is turned off, it will take all CPUs
|
| 114 | * with it.
|
| 115 |
|
| 116 | void machine_power_off(void)
|
| 117 | {
|
| 118 | local_irq_disable();
|
| 119 | smp_send_stop();
|
| 120 | do_kernel_power_off();
|
| 121 | }
|
| 122 |
|
| 123 | |
| 124 | * Restart requires that the secondary CPUs stop performing any activity
|
| 125 | * while the primary CPU resets the system. Systems with a single CPU can
|
| 126 | * use soft_restart() as their machine descriptor's .restart hook, since that
|
| 127 | * will cause the only available CPU to reset. Systems with multiple CPUs must
|
| 128 | * provide a HW restart implementation, to ensure that all CPUs reset at once.
|
| 129 | * This is required so that any code running after reset on the primary CPU
|
| 130 | * doesn't have to co-ordinate with other CPUs to ensure they aren't still
|
| 131 | * executing pre-reset code, and using RAM that the primary CPU's code wishes
|
| 132 | * to use. Implementing such co-ordination would be essentially impossible.
|
| 133 |
|
| 134 | void machine_restart(char *cmd)
|
| 135 | {
|
| 136 | local_irq_disable();
|
| 137 | smp_send_stop();
|
| 138 |
|
| 139 | do_kernel_restart(cmd);
|
| 140 |
|
| 141 |
|
| 142 | mdelay(1000);
|
| 143 |
|
| 144 |
|
| 145 | printk("Reboot failed -- System halted\n");
|
| 146 | while (1);
|
| 147 | }
|