Skip to content

Commit 6ce4889

Browse files
chenhuacaitsbogend
authored andcommitted
MIPS: Loongson64: Add kexec/kdump support
Add kexec/kdump support for Loongson64 by: 1, Provide Loongson-specific kexec functions: loongson_kexec_prepare(), loongson_kexec_shutdown() and loongson_crash_shutdown(); 2, Provide Loongson-specific assembly code in kexec_smp_wait(); To start Loongson64, The boot CPU needs 3 parameters: fw_arg0: the number of arguments in cmdline (i.e., argc). fw_arg1: structure holds cmdline such as "root=/dev/sda1 console=tty" (i.e., argv). fw_arg2: environment (i.e., envp, additional boot parameters from LEFI). Non-boot CPUs do not need one parameter as the IPI mailbox base address. They query their own IPI mailbox to get PC, SP and GP in a loopi, until the boot CPU brings them up. loongson_kexec_prepare(): Setup cmdline for kexec/kdump. The kexec/kdump cmdline comes from kexec's "append" option string. This structure will be parsed in fw_init_cmdline() of arch/mips/fw/lib/cmdline.c. Both image ->control_code_page and the cmdline need to be in a safe memory region (memory allocated by the old kernel may be corrupted by the new kernel). In order to maintain compatibility for the old firmware, the low 2MB is reserverd and safe for Loongson. So let KEXEC_CTRL_CODE and KEXEC_ARGV_ ADDR be here. LEFI parameters may be corrupted at runtime, so backup it at mips_reboot_setup(), and then restore it at loongson_kexec_shutdown() /loongson_crash_shutdown(). loongson_kexec_shutdown(): Wake up all present CPUs and let them go to reboot_code_buffer. Pass the kexec parameters to kexec_args. loongson_crash_shutdown(): Pass the kdump parameters to kexec_args. The assembly part in kexec_smp_wait provide a routine as BIOS does, in order to keep secondary CPUs in a querying loop. The layout of low 2MB memory in our design: 0x80000000, the first MB, the first 64K, Exception vectors 0x80010000, the first MB, the second 64K, STR (suspend) data 0x80020000, the first MB, the third and fourth 64K, UEFI HOB 0x80040000, the first MB, the fifth 64K, RT-Thread for SMC 0x80100000, the second MB, the first 64K, KEXEC code 0x80108000, the second MB, the second 64K, KEXEC data Cc: Eric Biederman <ebiederm@xmission.com> Tested-by: Jinyang He <hejinyang@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@kernel.org> Signed-off-by: Jinyang He <hejinyang@loongson.cn> Signed-off-by: Youling Tang <tangyouling@loongson.cn> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
1 parent 99bca61 commit 6ce4889

File tree

4 files changed

+152
-5
lines changed

4 files changed

+152
-5
lines changed

arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,12 @@
157157
.macro smp_slave_setup
158158
.endm
159159

160+
#define USE_KEXEC_SMP_WAIT_FINAL
161+
.macro kexec_smp_wait_final
162+
.set push
163+
.set noreorder
164+
synci 0($0)
165+
.set pop
166+
.endm
167+
160168
#endif /* __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H */

arch/mips/include/asm/mach-loongson64/kernel-entry-init.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,31 @@
7575
.set pop
7676
.endm
7777

78+
#define USE_KEXEC_SMP_WAIT_FINAL
79+
.macro kexec_smp_wait_final
80+
/* s0:prid s1:initfn */
81+
/* a0:base t1:cpuid t2:node t9:count */
82+
mfc0 t1, CP0_EBASE
83+
andi t1, MIPS_EBASE_CPUNUM
84+
dins a0, t1, 8, 2 /* insert core id*/
85+
dext t2, t1, 2, 2
86+
dins a0, t2, 44, 2 /* insert node id */
87+
mfc0 s0, CP0_PRID
88+
andi s0, s0, (PRID_IMP_MASK | PRID_REV_MASK)
89+
beq s0, (PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3B_R1), 1f
90+
beq s0, (PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3B_R2), 1f
91+
b 2f /* Loongson-3A1000/3A2000/3A3000/3A4000 */
92+
1: dins a0, t2, 14, 2 /* Loongson-3B1000/3B1500 need bit 15~14 */
93+
2: li t9, 0x100 /* wait for init loop */
94+
3: addiu t9, -1 /* limit mailbox access */
95+
bnez t9, 3b
96+
lw s1, 0x20(a0) /* check PC as an indicator */
97+
beqz s1, 2b
98+
ld s1, 0x20(a0) /* get PC via mailbox reg0 */
99+
ld sp, 0x28(a0) /* get SP via mailbox reg1 */
100+
ld gp, 0x30(a0) /* get GP via mailbox reg2 */
101+
ld a1, 0x38(a0)
102+
jr s1 /* jump to initial PC */
103+
.endm
104+
78105
#endif /* __ASM_MACH_LOONGSON64_KERNEL_ENTRY_H */

arch/mips/kernel/relocate_kernel.S

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <asm/stackframe.h>
1212
#include <asm/addrspace.h>
1313

14+
#include <kernel-entry-init.h>
15+
1416
LEAF(relocate_new_kernel)
1517
PTR_L a0, arg0
1618
PTR_L a1, arg1
@@ -125,11 +127,8 @@ LEAF(kexec_smp_wait)
125127
1: LONG_L s0, (t0)
126128
bne s0, zero,1b
127129

128-
#ifdef CONFIG_CPU_CAVIUM_OCTEON
129-
.set push
130-
.set noreorder
131-
synci 0($0)
132-
.set pop
130+
#ifdef USE_KEXEC_SMP_WAIT_FINAL
131+
kexec_smp_wait_final
133132
#else
134133
sync
135134
#endif

arch/mips/loongson64/reset.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66
* Copyright (C) 2009 Lemote, Inc.
77
* Author: Zhangjin Wu, wuzhangjin@gmail.com
88
*/
9+
#include <linux/cpu.h>
10+
#include <linux/delay.h>
911
#include <linux/init.h>
12+
#include <linux/kexec.h>
1013
#include <linux/pm.h>
14+
#include <linux/slab.h>
1115

16+
#include <asm/bootinfo.h>
1217
#include <asm/idle.h>
1318
#include <asm/reboot.h>
1419

@@ -47,12 +52,120 @@ static void loongson_halt(void)
4752
}
4853
}
4954

55+
#ifdef CONFIG_KEXEC
56+
57+
/* 0X80000000~0X80200000 is safe */
58+
#define MAX_ARGS 64
59+
#define KEXEC_CTRL_CODE 0xFFFFFFFF80100000UL
60+
#define KEXEC_ARGV_ADDR 0xFFFFFFFF80108000UL
61+
#define KEXEC_ARGV_SIZE COMMAND_LINE_SIZE
62+
#define KEXEC_ENVP_SIZE 4800
63+
64+
static int kexec_argc;
65+
static int kdump_argc;
66+
static void *kexec_argv;
67+
static void *kdump_argv;
68+
static void *kexec_envp;
69+
70+
static int loongson_kexec_prepare(struct kimage *image)
71+
{
72+
int i, argc = 0;
73+
unsigned int *argv;
74+
char *str, *ptr, *bootloader = "kexec";
75+
76+
/* argv at offset 0, argv[] at offset KEXEC_ARGV_SIZE/2 */
77+
if (image->type == KEXEC_TYPE_DEFAULT)
78+
argv = (unsigned int *)kexec_argv;
79+
else
80+
argv = (unsigned int *)kdump_argv;
81+
82+
argv[argc++] = (unsigned int)(KEXEC_ARGV_ADDR + KEXEC_ARGV_SIZE/2);
83+
84+
for (i = 0; i < image->nr_segments; i++) {
85+
if (!strncmp(bootloader, (char *)image->segment[i].buf,
86+
strlen(bootloader))) {
87+
/*
88+
* convert command line string to array
89+
* of parameters (as bootloader does).
90+
*/
91+
int offt;
92+
str = (char *)argv + KEXEC_ARGV_SIZE/2;
93+
memcpy(str, image->segment[i].buf, KEXEC_ARGV_SIZE/2);
94+
ptr = strchr(str, ' ');
95+
96+
while (ptr && (argc < MAX_ARGS)) {
97+
*ptr = '\0';
98+
if (ptr[1] != ' ') {
99+
offt = (int)(ptr - str + 1);
100+
argv[argc] = KEXEC_ARGV_ADDR + KEXEC_ARGV_SIZE/2 + offt;
101+
argc++;
102+
}
103+
ptr = strchr(ptr + 1, ' ');
104+
}
105+
break;
106+
}
107+
}
108+
109+
if (image->type == KEXEC_TYPE_DEFAULT)
110+
kexec_argc = argc;
111+
else
112+
kdump_argc = argc;
113+
114+
/* kexec/kdump need a safe page to save reboot_code_buffer */
115+
image->control_code_page = virt_to_page((void *)KEXEC_CTRL_CODE);
116+
117+
return 0;
118+
}
119+
120+
static void loongson_kexec_shutdown(void)
121+
{
122+
#ifdef CONFIG_SMP
123+
int cpu;
124+
125+
/* All CPUs go to reboot_code_buffer */
126+
for_each_possible_cpu(cpu)
127+
if (!cpu_online(cpu))
128+
cpu_device_up(get_cpu_device(cpu));
129+
#endif
130+
kexec_args[0] = kexec_argc;
131+
kexec_args[1] = fw_arg1;
132+
kexec_args[2] = fw_arg2;
133+
secondary_kexec_args[0] = TO_UNCAC(0x3ff01000);
134+
memcpy((void *)fw_arg1, kexec_argv, KEXEC_ARGV_SIZE);
135+
memcpy((void *)fw_arg2, kexec_envp, KEXEC_ENVP_SIZE);
136+
}
137+
138+
static void loongson_crash_shutdown(struct pt_regs *regs)
139+
{
140+
default_machine_crash_shutdown(regs);
141+
kexec_args[0] = kdump_argc;
142+
kexec_args[1] = fw_arg1;
143+
kexec_args[2] = fw_arg2;
144+
secondary_kexec_args[0] = TO_UNCAC(0x3ff01000);
145+
memcpy((void *)fw_arg1, kdump_argv, KEXEC_ARGV_SIZE);
146+
memcpy((void *)fw_arg2, kexec_envp, KEXEC_ENVP_SIZE);
147+
}
148+
149+
#endif
150+
50151
static int __init mips_reboot_setup(void)
51152
{
52153
_machine_restart = loongson_restart;
53154
_machine_halt = loongson_halt;
54155
pm_power_off = loongson_poweroff;
55156

157+
#ifdef CONFIG_KEXEC
158+
kexec_argv = kmalloc(KEXEC_ARGV_SIZE, GFP_KERNEL);
159+
kdump_argv = kmalloc(KEXEC_ARGV_SIZE, GFP_KERNEL);
160+
kexec_envp = kmalloc(KEXEC_ENVP_SIZE, GFP_KERNEL);
161+
fw_arg1 = KEXEC_ARGV_ADDR;
162+
memcpy(kexec_envp, (void *)fw_arg2, KEXEC_ENVP_SIZE);
163+
164+
_machine_kexec_prepare = loongson_kexec_prepare;
165+
_machine_kexec_shutdown = loongson_kexec_shutdown;
166+
_machine_crash_shutdown = loongson_crash_shutdown;
167+
#endif
168+
56169
return 0;
57170
}
58171

0 commit comments

Comments
 (0)