0006-riscv-add-support-for-multi-hart-systems.patch 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. From 3dea63c8445b25eb3de471410bbafcf54c9f0e9b Mon Sep 17 00:00:00 2001
  2. From: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
  3. Date: Sun, 17 Mar 2019 19:28:37 +0100
  4. Subject: [PATCH 06/18] riscv: add support for multi-hart systems
  5. On RISC-V, all harts boot independently. To be able to run on a
  6. multi-hart system, U-Boot must be extended with the functionality to
  7. manage all harts in the system. All harts entering U-Boot are registered
  8. in the available_harts mask stored in global data. A hart lottery system
  9. as used in the Linux kernel selects the hart U-Boot runs on. All other
  10. harts are halted. U-Boot can delegate functions to them using
  11. smp_call_function().
  12. Every hart has a valid pointer to the global data structure and a 8KiB
  13. stack by default. The stack size is set with CONFIG_STACK_SIZE_SHIFT.
  14. Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
  15. Reviewed-by: Anup Patel <anup.patel@wdc.com>
  16. Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
  17. Tested-by: Bin Meng <bmeng.cn@gmail.com>
  18. ---
  19. arch/riscv/Kconfig | 4 ++
  20. arch/riscv/cpu/cpu.c | 9 ++-
  21. arch/riscv/cpu/start.S | 134 ++++++++++++++++++++++++++++++++++-
  22. arch/riscv/include/asm/csr.h | 1 +
  23. arch/riscv/lib/asm-offsets.c | 1 +
  24. 5 files changed, 147 insertions(+), 2 deletions(-)
  25. diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
  26. index 9da609b33b..3a4470daf3 100644
  27. --- a/arch/riscv/Kconfig
  28. +++ b/arch/riscv/Kconfig
  29. @@ -144,4 +144,8 @@ config SBI_IPI
  30. default y if RISCV_SMODE
  31. depends on SMP
  32. +config STACK_SIZE_SHIFT
  33. + int
  34. + default 13
  35. +
  36. endmenu
  37. diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
  38. index e662140427..c32de8a4c3 100644
  39. --- a/arch/riscv/cpu/cpu.c
  40. +++ b/arch/riscv/cpu/cpu.c
  41. @@ -12,10 +12,17 @@
  42. #include <dm/uclass-internal.h>
  43. /*
  44. - * prior_stage_fdt_address must be stored in the data section since it is used
  45. + * The variables here must be stored in the data section since they are used
  46. * before the bss section is available.
  47. */
  48. phys_addr_t prior_stage_fdt_address __attribute__((section(".data")));
  49. +u32 hart_lottery __attribute__((section(".data"))) = 0;
  50. +
  51. +/*
  52. + * The main hart running U-Boot has acquired available_harts_lock until it has
  53. + * finished initialization of global data.
  54. + */
  55. +u32 available_harts_lock = 1;
  56. static inline bool supports_extension(char ext)
  57. {
  58. diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
  59. index bcc0ff696d..f55b8cbc37 100644
  60. --- a/arch/riscv/cpu/start.S
  61. +++ b/arch/riscv/cpu/start.S
  62. @@ -13,6 +13,7 @@
  63. #include <config.h>
  64. #include <common.h>
  65. #include <elf.h>
  66. +#include <asm/csr.h>
  67. #include <asm/encoding.h>
  68. #include <generated/asm-offsets.h>
  69. @@ -45,6 +46,23 @@ _start:
  70. /* mask all interrupts */
  71. csrw MODE_PREFIX(ie), zero
  72. +#ifdef CONFIG_SMP
  73. + /* check if hart is within range */
  74. + /* tp: hart id */
  75. + li t0, CONFIG_NR_CPUS
  76. + bge tp, t0, hart_out_of_bounds_loop
  77. +#endif
  78. +
  79. +#ifdef CONFIG_SMP
  80. + /* set xSIE bit to receive IPIs */
  81. +#ifdef CONFIG_RISCV_MMODE
  82. + li t0, MIE_MSIE
  83. +#else
  84. + li t0, SIE_SSIE
  85. +#endif
  86. + csrs MODE_PREFIX(ie), t0
  87. +#endif
  88. +
  89. /*
  90. * Set stackpointer in internal/ex RAM to call board_init_f
  91. */
  92. @@ -56,7 +74,30 @@ call_board_init_f:
  93. call_board_init_f_0:
  94. mv a0, sp
  95. jal board_init_f_alloc_reserve
  96. +
  97. + /*
  98. + * Set global data pointer here for all harts, uninitialized at this
  99. + * point.
  100. + */
  101. + mv gp, a0
  102. +
  103. + /* setup stack */
  104. +#ifdef CONFIG_SMP
  105. + /* tp: hart id */
  106. + slli t0, tp, CONFIG_STACK_SIZE_SHIFT
  107. + sub sp, a0, t0
  108. +#else
  109. mv sp, a0
  110. +#endif
  111. +
  112. + /*
  113. + * Pick hart to initialize global data and run U-Boot. The other harts
  114. + * wait for initialization to complete.
  115. + */
  116. + la t0, hart_lottery
  117. + li s2, 1
  118. + amoswap.w s2, t1, 0(t0)
  119. + bnez s2, wait_for_gd_init
  120. la t0, prior_stage_fdt_address
  121. SREG s1, 0(t0)
  122. @@ -66,6 +107,33 @@ call_board_init_f_0:
  123. /* save the boot hart id to global_data */
  124. SREG tp, GD_BOOT_HART(gp)
  125. + la t0, available_harts_lock
  126. + fence rw, w
  127. + amoswap.w zero, zero, 0(t0)
  128. +
  129. +wait_for_gd_init:
  130. + la t0, available_harts_lock
  131. + li t1, 1
  132. +1: amoswap.w t1, t1, 0(t0)
  133. + fence r, rw
  134. + bnez t1, 1b
  135. +
  136. + /* register available harts in the available_harts mask */
  137. + li t1, 1
  138. + sll t1, t1, tp
  139. + LREG t2, GD_AVAILABLE_HARTS(gp)
  140. + or t2, t2, t1
  141. + SREG t2, GD_AVAILABLE_HARTS(gp)
  142. +
  143. + fence rw, w
  144. + amoswap.w zero, zero, 0(t0)
  145. +
  146. + /*
  147. + * Continue on hart lottery winner, others branch to
  148. + * secondary_hart_loop.
  149. + */
  150. + bnez s2, secondary_hart_loop
  151. +
  152. /* Enable cache */
  153. jal icache_enable
  154. jal dcache_enable
  155. @@ -95,7 +163,14 @@ relocate_code:
  156. *Set up the stack
  157. */
  158. stack_setup:
  159. +#ifdef CONFIG_SMP
  160. + /* tp: hart id */
  161. + slli t0, tp, CONFIG_STACK_SIZE_SHIFT
  162. + sub sp, s2, t0
  163. +#else
  164. mv sp, s2
  165. +#endif
  166. +
  167. la t0, _start
  168. sub t6, s4, t0 /* t6 <- relocation offset */
  169. beq t0, s4, clear_bss /* skip relocation */
  170. @@ -175,13 +250,30 @@ clear_bss:
  171. add t0, t0, t6 /* t0 <- rel __bss_start in RAM */
  172. la t1, __bss_end /* t1 <- rel __bss_end in FLASH */
  173. add t1, t1, t6 /* t1 <- rel __bss_end in RAM */
  174. - beq t0, t1, call_board_init_r
  175. + beq t0, t1, relocate_secondary_harts
  176. clbss_l:
  177. SREG zero, 0(t0) /* clear loop... */
  178. addi t0, t0, REGBYTES
  179. bne t0, t1, clbss_l
  180. +relocate_secondary_harts:
  181. +#ifdef CONFIG_SMP
  182. + /* send relocation IPI */
  183. + la t0, secondary_hart_relocate
  184. + add a0, t0, t6
  185. +
  186. + /* store relocation offset */
  187. + mv s5, t6
  188. +
  189. + mv a1, s2
  190. + mv a2, s3
  191. + jal smp_call_function
  192. +
  193. + /* restore relocation offset */
  194. + mv t6, s5
  195. +#endif
  196. +
  197. /*
  198. * We are done. Do not return, instead branch to second part of board
  199. * initialization, now running from RAM.
  200. @@ -202,3 +294,43 @@ call_board_init_r:
  201. * jump to it ...
  202. */
  203. jr t4 /* jump to board_init_r() */
  204. +
  205. +#ifdef CONFIG_SMP
  206. +hart_out_of_bounds_loop:
  207. + /* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */
  208. + wfi
  209. + j hart_out_of_bounds_loop
  210. +#endif
  211. +
  212. +#ifdef CONFIG_SMP
  213. +/* SMP relocation entry */
  214. +secondary_hart_relocate:
  215. + /* a1: new sp */
  216. + /* a2: new gd */
  217. + /* tp: hart id */
  218. +
  219. + /* setup stack */
  220. + slli t0, tp, CONFIG_STACK_SIZE_SHIFT
  221. + sub sp, a1, t0
  222. +
  223. + /* update global data pointer */
  224. + mv gp, a2
  225. +#endif
  226. +
  227. +secondary_hart_loop:
  228. + wfi
  229. +
  230. +#ifdef CONFIG_SMP
  231. + csrr t0, MODE_PREFIX(ip)
  232. +#ifdef CONFIG_RISCV_MMODE
  233. + andi t0, t0, MIE_MSIE
  234. +#else
  235. + andi t0, t0, SIE_SSIE
  236. +#endif
  237. + beqz t0, secondary_hart_loop
  238. +
  239. + mv a0, tp
  240. + jal handle_ipi
  241. +#endif
  242. +
  243. + j secondary_hart_loop
  244. diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
  245. index 86136f542c..644e6baa15 100644
  246. --- a/arch/riscv/include/asm/csr.h
  247. +++ b/arch/riscv/include/asm/csr.h
  248. @@ -46,6 +46,7 @@
  249. #endif
  250. /* Interrupt Enable and Interrupt Pending flags */
  251. +#define MIE_MSIE _AC(0x00000008, UL) /* Software Interrupt Enable */
  252. #define SIE_SSIE _AC(0x00000002, UL) /* Software Interrupt Enable */
  253. #define SIE_STIE _AC(0x00000020, UL) /* Timer Interrupt Enable */
  254. diff --git a/arch/riscv/lib/asm-offsets.c b/arch/riscv/lib/asm-offsets.c
  255. index e0b71f5691..f998402bd1 100644
  256. --- a/arch/riscv/lib/asm-offsets.c
  257. +++ b/arch/riscv/lib/asm-offsets.c
  258. @@ -14,6 +14,7 @@
  259. int main(void)
  260. {
  261. DEFINE(GD_BOOT_HART, offsetof(gd_t, arch.boot_hart));
  262. + DEFINE(GD_AVAILABLE_HARTS, offsetof(gd_t, arch.available_harts));
  263. return 0;
  264. }
  265. --
  266. 2.21.0