[PATCH] MIPS: Loongson64: Add kexec/kdump support
Jinyang He
hejinyang at loongson.cn
Tue Sep 15 22:14:33 EDT 2020
On 09/16/2020 09:33 AM, Jiaxun Yang wrote:
>
> 于 2020年9月15日 GMT+08:00 下午9:07:43, Jinyang He <hejinyang at loongson.cn> 写到:
>> Add loongson_kexec_prepare(), loongson_kexec_shutdown() and
>> loongson_kexec_crashdown() for passing the parameters of kexec_args.
>>
>> To start loongson64, CPU0 needs 3 parameters:
>> fw_arg0: the number of cmd.
>> fw_arg1: cmd structure which seems strange, the cmd array[index]'s
>> value is cmd string's address, index >= 1.
>> fw_arg2: environment.
>>
>> Secondary CPUs do not need parameter at once. They query their
>> mailbox to get PC, SP and GP in a loop before CPU0 brings them up
>> and passes these parameters via mailbox.
>>
>> loongson_kexec_prepare(): Alloc new memory to save cmd for kexec.
>> Combine the kexec append option string as cmd structure, and the cmd
>> struct will be parsed in fw_init_cmdline() of arch/mips/fw/lib/cmdline.c.
>> image->control_code_page need pointing to a safe memory page. In order to
>> maintain compatibility for the old firmware the low 2MB is reserverd
>> and safe for Loongson. So let it points here.
>>
>> 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 provide a way like BIOS doing to keep secondary
>> CPUs in a querying loop.
>>
>> This patch referenced [1][2][3].
>>
>> [1] arch/mips/cavium-octeon/setup.c
>> [2] https://patchwork.kernel.org/patch/10799217/
>> [3] https://gitee.com/loongsonlab/qemu/blob/master/hw/mips/loongson3a_rom.h
>>
>> Co-developed-by: Youling Tang <tangyouling at loongson.cn>
>> Signed-off-by: Youling Tang <tangyouling at loongson.cn>
>> Signed-off-by: Jinyang He <hejinyang at loongson.cn>
>> ---
>> arch/mips/kernel/relocate_kernel.S | 19 ++++++++
>> arch/mips/loongson64/reset.c | 88 ++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 107 insertions(+)
>>
>> diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S
>> index ac87089..061cbfb 100644
>> --- a/arch/mips/kernel/relocate_kernel.S
>> +++ b/arch/mips/kernel/relocate_kernel.S
>> @@ -133,6 +133,25 @@ LEAF(kexec_smp_wait)
>> #else
>> sync
>> #endif
>> +
>> +#ifdef CONFIG_CPU_LOONGSON64
>> +#define MAILBOX_BASE 0x900000003ff01000
> Please avoid hardcoded SMP information. You're breaking Loongson 3B support.
>
Ok, I see. Since my machine is Loongson 3A. I'll send v2
after I test it in 3B.
Thanks.
- Jinyang
>> + mfc0 t1, CP0_EBASE
>> + andi t1, MIPS_EBASE_CPUNUM
>> + dli t0, MAILBOX_BASE
>> + andi t3, t1, 0x3
>> + sll t3, 8
>> + or t0, t0, t3 /* insert core id */
>> + andi t2, t1, 0xc
>> + dsll t2, 42
>> + or t0, t0, t2 /* insert node id */
>> +1: ld s1, 0x20(t0) /* get PC via mailbox0 */
>> + beqz s1, 1b
>> + ld sp, 0x28(t0) /* get SP via mailbox1 */
>> + ld gp, 0x30(t0) /* get GP via mailbox2 */
>> + ld a1, 0x38(t0)
>> + jr s1
>> +#endif
>> j s1
>> END(kexec_smp_wait)
>> #endif
>> diff --git a/arch/mips/loongson64/reset.c b/arch/mips/loongson64/reset.c
>> index 3bb8a1e..322c326 100644
>> --- a/arch/mips/loongson64/reset.c
>> +++ b/arch/mips/loongson64/reset.c
>> @@ -47,12 +47,100 @@ static void loongson_halt(void)
>> }
>> }
>>
>> +#ifdef CONFIG_KEXEC
>> +#include <linux/cpu.h>
>> +#include <linux/kexec.h>
>> +
>> +#include <asm/bootinfo.h>
>> +
>> +#define CONTROL_CODE_PAGE 0xFFFFFFFF80000000UL
>> +static int kexec_argc;
>> +static int kdump_argc;
>> +static void *kexec_argv;
>> +static void *kdump_argv;
>> +
>> +static int loongson_kexec_prepare(struct kimage *image)
>> +{
>> + int i, offt, argc = 0;
>> + int *argv;
>> + char *str, *ptr, *bootloader = "kexec";
>> +
>> + argv = kmalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
>> + if (!argv)
>> + return -ENOMEM;
>> +
>> + for (i = 0; i < image->nr_segments; i++) {
>> + if (!strncmp(bootloader, (char *)image->segment[i].buf,
>> + strlen(bootloader))) {
>> + argv[argc++] = fw_arg1 + COMMAND_LINE_SIZE/2;
>> + str = (char *)argv + COMMAND_LINE_SIZE/2;
>> + memcpy(str, image->segment[i].buf, COMMAND_LINE_SIZE/2);
>> + ptr = strchr(str, ' ');
>> + while (ptr) {
>> + *ptr = '\0';
>> + if (ptr[1] != ' ') {
>> + offt = (int)(ptr - str + 1);
>> + argv[argc++] = fw_arg1 + COMMAND_LINE_SIZE/2 + offt;
>> + }
>> + ptr = strchr(ptr + 1, ' ');
>> + }
>> + break;
>> + }
>> + }
>> +
>> + /* Kexec/kdump needs a safe page to save reboot_code_buffer. */
>> + image->control_code_page = virt_to_page((void *)CONTROL_CODE_PAGE);
>> +
>> + if (image->type == KEXEC_TYPE_CRASH) {
>> + kfree(kdump_argv);
>> + kdump_argc = argc;
>> + kdump_argv = argv;
>> + } else {
>> + kfree(kexec_argv);
>> + kexec_argc = argc;
>> + kexec_argv = argv;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void loongson_kexec_shutdown(void)
>> +{
>> +#ifdef CONFIG_SMP
>> + bringup_nonboot_cpus(loongson_sysconf.nr_cpus);
>> +#endif
>> + fw_arg0 = kexec_argc;
>> + memcpy((void *)fw_arg1, kexec_argv, COMMAND_LINE_SIZE);
>> +
>> + kexec_args[0] = fw_arg0;
>> + kexec_args[1] = fw_arg1;
>> + kexec_args[2] = fw_arg2;
>> +}
>> +
>> +static void loongson_crash_shutdown(struct pt_regs *regs)
>> +{
>> + default_machine_crash_shutdown(regs);
>> + fw_arg0 = kdump_argc;
>> + memcpy((void *)fw_arg1, kdump_argv, COMMAND_LINE_SIZE);
>> +
>> + kexec_args[0] = fw_arg0;
>> + kexec_args[1] = fw_arg1;
>> + kexec_args[2] = fw_arg2;
>> +}
>> +#endif
>> +
>> static int __init mips_reboot_setup(void)
>> {
>> _machine_restart = loongson_restart;
>> _machine_halt = loongson_halt;
>> pm_power_off = loongson_poweroff;
>>
>> +#ifdef CONFIG_KEXEC
>> + _machine_kexec_prepare = loongson_kexec_prepare;
>> + _machine_kexec_shutdown = loongson_kexec_shutdown;
>> + _machine_crash_shutdown = loongson_crash_shutdown;
>> +#endif
>> +
>> return 0;
>> }
>>
More information about the kexec
mailing list