aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorDengcheng Zhu <dzhu@wavecomp.com>2018-09-11 17:49:21 -0400
committerPaul Burton <paul.burton@mips.com>2018-09-22 13:31:50 -0400
commit62cac480f33f8f9413d609cb1601b0ee521a86b8 (patch)
tree92d3e1e0e580cbc175cd27b77b0ddf7c931ac338 /arch/mips/kernel
parentdc57aaf95a516f70e2d527d8287a0332c481a226 (diff)
MIPS: kexec: Make a framework for both jumping and halting on nonboot CPUs
The existing implementation lets machine_kexec() CPU jump to reboot code buffer, whereas other CPUs to relocated_kexec_smp_wait. The natural way to bring up an SMP new kernel would be to let CPU0 do it while others being halted. For those failing to do so, fall back to the jumping method. Signed-off-by: Dengcheng Zhu <dzhu@wavecomp.com> [paul.burton@mips.com: Guard kexec_nonboot_cpu_jump with CONFIG_SMP] Signed-off-by: Paul Burton <paul.burton@mips.com> Patchwork: https://patchwork.linux-mips.org/patch/20570/ Cc: pburton@wavecomp.com Cc: ralf@linux-mips.org Cc: linux-mips@linux-mips.org Cc: rachel.mozes@intel.com
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/crash.c4
-rw-r--r--arch/mips/kernel/machine_kexec.c90
-rw-r--r--arch/mips/kernel/smp-bmips.c7
3 files changed, 93 insertions, 8 deletions
diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c
index 4c07a43a3242..2c7288041a99 100644
--- a/arch/mips/kernel/crash.c
+++ b/arch/mips/kernel/crash.c
@@ -46,7 +46,9 @@ static void crash_shutdown_secondary(void *passed_regs)
46 46
47 while (!atomic_read(&kexec_ready_to_reboot)) 47 while (!atomic_read(&kexec_ready_to_reboot))
48 cpu_relax(); 48 cpu_relax();
49 relocated_kexec_smp_wait(NULL); 49
50 kexec_reboot();
51
50 /* NOTREACHED */ 52 /* NOTREACHED */
51} 53}
52 54
diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c
index 4b3726e4fe3a..14ced77c5ef6 100644
--- a/arch/mips/kernel/machine_kexec.c
+++ b/arch/mips/kernel/machine_kexec.c
@@ -19,15 +19,19 @@ extern const size_t relocate_new_kernel_size;
19extern unsigned long kexec_start_address; 19extern unsigned long kexec_start_address;
20extern unsigned long kexec_indirection_page; 20extern unsigned long kexec_indirection_page;
21 21
22int (*_machine_kexec_prepare)(struct kimage *) = NULL; 22static unsigned long reboot_code_buffer;
23void (*_machine_kexec_shutdown)(void) = NULL; 23
24void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
25#ifdef CONFIG_SMP 24#ifdef CONFIG_SMP
26void (*relocated_kexec_smp_wait) (void *); 25static void (*relocated_kexec_smp_wait)(void *);
26
27atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); 27atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0);
28void (*_crash_smp_send_stop)(void) = NULL; 28void (*_crash_smp_send_stop)(void) = NULL;
29#endif 29#endif
30 30
31int (*_machine_kexec_prepare)(struct kimage *) = NULL;
32void (*_machine_kexec_shutdown)(void) = NULL;
33void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
34
31static void kexec_image_info(const struct kimage *kimage) 35static void kexec_image_info(const struct kimage *kimage)
32{ 36{
33 unsigned long i; 37 unsigned long i;
@@ -51,10 +55,16 @@ static void kexec_image_info(const struct kimage *kimage)
51int 55int
52machine_kexec_prepare(struct kimage *kimage) 56machine_kexec_prepare(struct kimage *kimage)
53{ 57{
58#ifdef CONFIG_SMP
59 if (!kexec_nonboot_cpu_func())
60 return -EINVAL;
61#endif
62
54 kexec_image_info(kimage); 63 kexec_image_info(kimage);
55 64
56 if (_machine_kexec_prepare) 65 if (_machine_kexec_prepare)
57 return _machine_kexec_prepare(kimage); 66 return _machine_kexec_prepare(kimage);
67
58 return 0; 68 return 0;
59} 69}
60 70
@@ -63,11 +73,41 @@ machine_kexec_cleanup(struct kimage *kimage)
63{ 73{
64} 74}
65 75
76#ifdef CONFIG_SMP
77static void kexec_shutdown_secondary(void *param)
78{
79 int cpu = smp_processor_id();
80
81 if (!cpu_online(cpu))
82 return;
83
84 /* We won't be sent IPIs any more. */
85 set_cpu_online(cpu, false);
86
87 local_irq_disable();
88 while (!atomic_read(&kexec_ready_to_reboot))
89 cpu_relax();
90
91 kexec_reboot();
92
93 /* NOTREACHED */
94}
95#endif
96
66void 97void
67machine_shutdown(void) 98machine_shutdown(void)
68{ 99{
69 if (_machine_kexec_shutdown) 100 if (_machine_kexec_shutdown)
70 _machine_kexec_shutdown(); 101 _machine_kexec_shutdown();
102
103#ifdef CONFIG_SMP
104 smp_call_function(kexec_shutdown_secondary, NULL, 0);
105
106 while (num_online_cpus() > 1) {
107 cpu_relax();
108 mdelay(1);
109 }
110#endif
71} 111}
72 112
73void 113void
@@ -79,12 +119,47 @@ machine_crash_shutdown(struct pt_regs *regs)
79 default_machine_crash_shutdown(regs); 119 default_machine_crash_shutdown(regs);
80} 120}
81 121
82typedef void (*noretfun_t)(void) __noreturn; 122#ifdef CONFIG_SMP
123void kexec_nonboot_cpu_jump(void)
124{
125 local_flush_icache_range((unsigned long)relocated_kexec_smp_wait,
126 reboot_code_buffer + relocate_new_kernel_size);
127
128 relocated_kexec_smp_wait(NULL);
129}
130#endif
131
132void kexec_reboot(void)
133{
134 void (*do_kexec)(void) __noreturn;
135
136#ifdef CONFIG_SMP
137 if (smp_processor_id() > 0) {
138 /*
139 * Instead of cpu_relax() or wait, this is needed for kexec
140 * smp reboot. Kdump usually doesn't require an smp new
141 * kernel, but kexec may do.
142 */
143 kexec_nonboot_cpu();
144
145 /* NOTREACHED */
146 }
147#endif
148
149 /*
150 * Make sure we get correct instructions written by the
151 * machine_kexec() CPU.
152 */
153 local_flush_icache_range(reboot_code_buffer,
154 reboot_code_buffer + relocate_new_kernel_size);
155
156 do_kexec = (void *)reboot_code_buffer;
157 do_kexec();
158}
83 159
84void 160void
85machine_kexec(struct kimage *image) 161machine_kexec(struct kimage *image)
86{ 162{
87 unsigned long reboot_code_buffer;
88 unsigned long entry; 163 unsigned long entry;
89 unsigned long *ptr; 164 unsigned long *ptr;
90 165
@@ -128,6 +203,7 @@ machine_kexec(struct kimage *image)
128 203
129 printk("Will call new kernel at %08lx\n", image->start); 204 printk("Will call new kernel at %08lx\n", image->start);
130 printk("Bye ...\n"); 205 printk("Bye ...\n");
206 /* Make reboot code buffer available to the boot CPU. */
131 __flush_cache_all(); 207 __flush_cache_all();
132#ifdef CONFIG_SMP 208#ifdef CONFIG_SMP
133 /* All secondary cpus now may jump to kexec_wait cycle */ 209 /* All secondary cpus now may jump to kexec_wait cycle */
@@ -136,5 +212,5 @@ machine_kexec(struct kimage *image)
136 smp_wmb(); 212 smp_wmb();
137 atomic_set(&kexec_ready_to_reboot, 1); 213 atomic_set(&kexec_ready_to_reboot, 1);
138#endif 214#endif
139 ((noretfun_t) reboot_code_buffer)(); 215 kexec_reboot();
140} 216}
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index 159e83add4bb..76fae9b79f13 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -25,6 +25,7 @@
25#include <linux/linkage.h> 25#include <linux/linkage.h>
26#include <linux/bug.h> 26#include <linux/bug.h>
27#include <linux/kernel.h> 27#include <linux/kernel.h>
28#include <linux/kexec.h>
28 29
29#include <asm/time.h> 30#include <asm/time.h>
30#include <asm/pgtable.h> 31#include <asm/pgtable.h>
@@ -423,6 +424,9 @@ const struct plat_smp_ops bmips43xx_smp_ops = {
423 .cpu_disable = bmips_cpu_disable, 424 .cpu_disable = bmips_cpu_disable,
424 .cpu_die = bmips_cpu_die, 425 .cpu_die = bmips_cpu_die,
425#endif 426#endif
427#ifdef CONFIG_KEXEC
428 .kexec_nonboot_cpu = kexec_nonboot_cpu_jump,
429#endif
426}; 430};
427 431
428const struct plat_smp_ops bmips5000_smp_ops = { 432const struct plat_smp_ops bmips5000_smp_ops = {
@@ -437,6 +441,9 @@ const struct plat_smp_ops bmips5000_smp_ops = {
437 .cpu_disable = bmips_cpu_disable, 441 .cpu_disable = bmips_cpu_disable,
438 .cpu_die = bmips_cpu_die, 442 .cpu_die = bmips_cpu_die,
439#endif 443#endif
444#ifdef CONFIG_KEXEC
445 .kexec_nonboot_cpu = kexec_nonboot_cpu_jump,
446#endif
440}; 447};
441 448
442#endif /* CONFIG_SMP */ 449#endif /* CONFIG_SMP */