reset.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  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
  8. */
  9. #include <linux/cpu.h>
  10. #include <linux/delay.h>
  11. #include <linux/init.h>
  12. #include <linux/kexec.h>
  13. #include <linux/pm.h>
  14. #include <linux/reboot.h>
  15. #include <linux/slab.h>
  16. #include <asm/bootinfo.h>
  17. #include <asm/idle.h>
  18. #include <asm/reboot.h>
  19. #include <asm/bug.h>
  20. #include <loongson.h>
  21. #include <boot_param.h>
  22. static int firmware_restart(struct sys_off_data *unusedd)
  23. {
  24. void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr;
  25. fw_restart();
  26. return NOTIFY_DONE;
  27. }
  28. static int firmware_poweroff(struct sys_off_data *unused)
  29. {
  30. void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr;
  31. fw_poweroff();
  32. return NOTIFY_DONE;
  33. }
  34. #ifdef CONFIG_KEXEC_CORE
  35. /* 0X80000000~0X80200000 is safe */
  36. #define MAX_ARGS 64
  37. #define KEXEC_CTRL_CODE 0xFFFFFFFF80100000UL
  38. #define KEXEC_ARGV_ADDR 0xFFFFFFFF80108000UL
  39. #define KEXEC_ARGV_SIZE COMMAND_LINE_SIZE
  40. #define KEXEC_ENVP_SIZE 4800
  41. static int kexec_argc;
  42. static int kdump_argc;
  43. static void *kexec_argv;
  44. static void *kdump_argv;
  45. static void *kexec_envp;
  46. static int loongson_kexec_prepare(struct kimage *image)
  47. {
  48. int i, argc = 0;
  49. unsigned int *argv;
  50. char *str, *ptr, *bootloader = "kexec";
  51. /* argv at offset 0, argv[] at offset KEXEC_ARGV_SIZE/2 */
  52. if (image->type == KEXEC_TYPE_DEFAULT)
  53. argv = (unsigned int *)kexec_argv;
  54. else
  55. argv = (unsigned int *)kdump_argv;
  56. argv[argc++] = (unsigned int)(KEXEC_ARGV_ADDR + KEXEC_ARGV_SIZE/2);
  57. for (i = 0; i < image->nr_segments; i++) {
  58. if (!strncmp(bootloader, (char *)image->segment[i].buf,
  59. strlen(bootloader))) {
  60. /*
  61. * convert command line string to array
  62. * of parameters (as bootloader does).
  63. */
  64. int offt;
  65. str = (char *)argv + KEXEC_ARGV_SIZE/2;
  66. memcpy(str, image->segment[i].buf, KEXEC_ARGV_SIZE/2);
  67. ptr = strchr(str, ' ');
  68. while (ptr && (argc < MAX_ARGS)) {
  69. *ptr = '\0';
  70. if (ptr[1] != ' ') {
  71. offt = (int)(ptr - str + 1);
  72. argv[argc] = KEXEC_ARGV_ADDR + KEXEC_ARGV_SIZE/2 + offt;
  73. argc++;
  74. }
  75. ptr = strchr(ptr + 1, ' ');
  76. }
  77. break;
  78. }
  79. }
  80. if (image->type == KEXEC_TYPE_DEFAULT)
  81. kexec_argc = argc;
  82. else
  83. kdump_argc = argc;
  84. /* kexec/kdump need a safe page to save reboot_code_buffer */
  85. image->control_code_page = virt_to_page((void *)KEXEC_CTRL_CODE);
  86. return 0;
  87. }
  88. static void loongson_kexec_shutdown(void)
  89. {
  90. #ifdef CONFIG_SMP
  91. int cpu;
  92. /* All CPUs go to reboot_code_buffer */
  93. for_each_possible_cpu(cpu)
  94. if (!cpu_online(cpu))
  95. cpu_device_up(get_cpu_device(cpu));
  96. secondary_kexec_args[0] = TO_UNCAC(0x3ff01000);
  97. #endif
  98. kexec_args[0] = kexec_argc;
  99. kexec_args[1] = fw_arg1;
  100. kexec_args[2] = fw_arg2;
  101. memcpy((void *)fw_arg1, kexec_argv, KEXEC_ARGV_SIZE);
  102. memcpy((void *)fw_arg2, kexec_envp, KEXEC_ENVP_SIZE);
  103. }
  104. static void loongson_crash_shutdown(struct pt_regs *regs)
  105. {
  106. default_machine_crash_shutdown(regs);
  107. kexec_args[0] = kdump_argc;
  108. kexec_args[1] = fw_arg1;
  109. kexec_args[2] = fw_arg2;
  110. #ifdef CONFIG_SMP
  111. secondary_kexec_args[0] = TO_UNCAC(0x3ff01000);
  112. #endif
  113. memcpy((void *)fw_arg1, kdump_argv, KEXEC_ARGV_SIZE);
  114. memcpy((void *)fw_arg2, kexec_envp, KEXEC_ENVP_SIZE);
  115. }
  116. #endif
  117. static int __init mips_reboot_setup(void)
  118. {
  119. if (loongson_sysconf.restart_addr) {
  120. register_sys_off_handler(SYS_OFF_MODE_RESTART,
  121. SYS_OFF_PRIO_FIRMWARE,
  122. firmware_restart, NULL);
  123. }
  124. if (loongson_sysconf.poweroff_addr) {
  125. register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
  126. SYS_OFF_PRIO_FIRMWARE,
  127. firmware_poweroff, NULL);
  128. }
  129. #ifdef CONFIG_KEXEC_CORE
  130. kexec_argv = kmalloc(KEXEC_ARGV_SIZE, GFP_KERNEL);
  131. if (WARN_ON(!kexec_argv))
  132. return -ENOMEM;
  133. kdump_argv = kmalloc(KEXEC_ARGV_SIZE, GFP_KERNEL);
  134. if (WARN_ON(!kdump_argv))
  135. return -ENOMEM;
  136. kexec_envp = kmalloc(KEXEC_ENVP_SIZE, GFP_KERNEL);
  137. if (WARN_ON(!kexec_envp))
  138. return -ENOMEM;
  139. fw_arg1 = KEXEC_ARGV_ADDR;
  140. memcpy(kexec_envp, (void *)fw_arg2, KEXEC_ENVP_SIZE);
  141. _machine_kexec_prepare = loongson_kexec_prepare;
  142. _machine_kexec_shutdown = loongson_kexec_shutdown;
  143. _machine_crash_shutdown = loongson_crash_shutdown;
  144. #endif
  145. return 0;
  146. }
  147. arch_initcall(mips_reboot_setup);