1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology
5 * Author: Fuxin Zhang, zhangfx@lemote.com
6 * Copyright (C) 2009 Lemote, Inc.
7 * Author: Zhangjin Wu, wuzhangjin@gmail.com
10 #include <linux/delay.h>
11 #include <linux/init.h>
12 #include <linux/kexec.h>
14 #include <linux/reboot.h>
15 #include <linux/slab.h>
17 #include <asm/bootinfo.h>
19 #include <asm/reboot.h>
23 #include <boot_param.h>
25 static int firmware_restart(struct sys_off_data
*unusedd
)
28 void (*fw_restart
)(void) = (void *)loongson_sysconf
.restart_addr
;
34 static int firmware_poweroff(struct sys_off_data
*unused
)
36 void (*fw_poweroff
)(void) = (void *)loongson_sysconf
.poweroff_addr
;
42 #ifdef CONFIG_KEXEC_CORE
44 /* 0X80000000~0X80200000 is safe */
46 #define KEXEC_CTRL_CODE 0xFFFFFFFF80100000UL
47 #define KEXEC_ARGV_ADDR 0xFFFFFFFF80108000UL
48 #define KEXEC_ARGV_SIZE COMMAND_LINE_SIZE
49 #define KEXEC_ENVP_SIZE 4800
51 static int kexec_argc
;
52 static int kdump_argc
;
53 static void *kexec_argv
;
54 static void *kdump_argv
;
55 static void *kexec_envp
;
57 static int loongson_kexec_prepare(struct kimage
*image
)
61 char *str
, *ptr
, *bootloader
= "kexec";
63 /* argv at offset 0, argv[] at offset KEXEC_ARGV_SIZE/2 */
64 if (image
->type
== KEXEC_TYPE_DEFAULT
)
65 argv
= (unsigned int *)kexec_argv
;
67 argv
= (unsigned int *)kdump_argv
;
69 argv
[argc
++] = (unsigned int)(KEXEC_ARGV_ADDR
+ KEXEC_ARGV_SIZE
/2);
71 for (i
= 0; i
< image
->nr_segments
; i
++) {
72 if (!strncmp(bootloader
, (char *)image
->segment
[i
].buf
,
73 strlen(bootloader
))) {
75 * convert command line string to array
76 * of parameters (as bootloader does).
79 str
= (char *)argv
+ KEXEC_ARGV_SIZE
/2;
80 memcpy(str
, image
->segment
[i
].buf
, KEXEC_ARGV_SIZE
/2);
81 ptr
= strchr(str
, ' ');
83 while (ptr
&& (argc
< MAX_ARGS
)) {
86 offt
= (int)(ptr
- str
+ 1);
87 argv
[argc
] = KEXEC_ARGV_ADDR
+ KEXEC_ARGV_SIZE
/2 + offt
;
90 ptr
= strchr(ptr
+ 1, ' ');
96 if (image
->type
== KEXEC_TYPE_DEFAULT
)
101 /* kexec/kdump need a safe page to save reboot_code_buffer */
102 image
->control_code_page
= virt_to_page((void *)KEXEC_CTRL_CODE
);
107 static void loongson_kexec_shutdown(void)
112 /* All CPUs go to reboot_code_buffer */
113 for_each_possible_cpu(cpu
)
114 if (!cpu_online(cpu
))
115 cpu_device_up(get_cpu_device(cpu
));
117 secondary_kexec_args
[0] = TO_UNCAC(0x3ff01000);
119 kexec_args
[0] = kexec_argc
;
120 kexec_args
[1] = fw_arg1
;
121 kexec_args
[2] = fw_arg2
;
122 memcpy((void *)fw_arg1
, kexec_argv
, KEXEC_ARGV_SIZE
);
123 memcpy((void *)fw_arg2
, kexec_envp
, KEXEC_ENVP_SIZE
);
126 static void loongson_crash_shutdown(struct pt_regs
*regs
)
128 default_machine_crash_shutdown(regs
);
129 kexec_args
[0] = kdump_argc
;
130 kexec_args
[1] = fw_arg1
;
131 kexec_args
[2] = fw_arg2
;
133 secondary_kexec_args
[0] = TO_UNCAC(0x3ff01000);
135 memcpy((void *)fw_arg1
, kdump_argv
, KEXEC_ARGV_SIZE
);
136 memcpy((void *)fw_arg2
, kexec_envp
, KEXEC_ENVP_SIZE
);
141 static int __init
mips_reboot_setup(void)
143 if (loongson_sysconf
.restart_addr
) {
144 register_sys_off_handler(SYS_OFF_MODE_RESTART
,
145 SYS_OFF_PRIO_FIRMWARE
,
146 firmware_restart
, NULL
);
149 if (loongson_sysconf
.poweroff_addr
) {
150 register_sys_off_handler(SYS_OFF_MODE_POWER_OFF
,
151 SYS_OFF_PRIO_FIRMWARE
,
152 firmware_poweroff
, NULL
);
155 #ifdef CONFIG_KEXEC_CORE
156 kexec_argv
= kmalloc(KEXEC_ARGV_SIZE
, GFP_KERNEL
);
157 if (WARN_ON(!kexec_argv
))
160 kdump_argv
= kmalloc(KEXEC_ARGV_SIZE
, GFP_KERNEL
);
161 if (WARN_ON(!kdump_argv
))
164 kexec_envp
= kmalloc(KEXEC_ENVP_SIZE
, GFP_KERNEL
);
165 if (WARN_ON(!kexec_envp
))
168 fw_arg1
= KEXEC_ARGV_ADDR
;
169 memcpy(kexec_envp
, (void *)fw_arg2
, KEXEC_ENVP_SIZE
);
171 _machine_kexec_prepare
= loongson_kexec_prepare
;
172 _machine_kexec_shutdown
= loongson_kexec_shutdown
;
173 _machine_crash_shutdown
= loongson_crash_shutdown
;
179 arch_initcall(mips_reboot_setup
);