reset.c 4.1 KB

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