mcpm_head.S 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * arch/arm/common/mcpm_head.S -- kernel entry point for multi-cluster PM
  4. *
  5. * Created by: Nicolas Pitre, March 2012
  6. * Copyright: (C) 2012-2013 Linaro Limited
  7. *
  8. * Refer to Documentation/arch/arm/cluster-pm-race-avoidance.rst
  9. * for details of the synchronisation algorithms used here.
  10. */
  11. #include <linux/linkage.h>
  12. #include <asm/mcpm.h>
  13. #include <asm/assembler.h>
  14. #include "vlock.h"
  15. .arch armv7-a
  16. .if MCPM_SYNC_CLUSTER_CPUS
  17. .error "cpus must be the first member of struct mcpm_sync_struct"
  18. .endif
  19. .macro pr_dbg string
  20. #if defined(CONFIG_DEBUG_LL) && defined(DEBUG)
  21. b 1901f
  22. 1902: .asciz "CPU"
  23. 1903: .asciz " cluster"
  24. 1904: .asciz ": \string"
  25. .align
  26. 1901: adr r0, 1902b
  27. bl printascii
  28. mov r0, r9
  29. bl printhex2
  30. adr r0, 1903b
  31. bl printascii
  32. mov r0, r10
  33. bl printhex2
  34. adr r0, 1904b
  35. bl printascii
  36. #endif
  37. .endm
  38. .arm
  39. .align
  40. ENTRY(mcpm_entry_point)
  41. ARM_BE8(setend be)
  42. THUMB( badr r12, 1f )
  43. THUMB( bx r12 )
  44. THUMB( .thumb )
  45. 1:
  46. mrc p15, 0, r0, c0, c0, 5 @ MPIDR
  47. ubfx r9, r0, #0, #8 @ r9 = cpu
  48. ubfx r10, r0, #8, #8 @ r10 = cluster
  49. mov r3, #MAX_CPUS_PER_CLUSTER
  50. mla r4, r3, r10, r9 @ r4 = canonical CPU index
  51. cmp r4, #(MAX_CPUS_PER_CLUSTER * MAX_NR_CLUSTERS)
  52. blo 2f
  53. /* We didn't expect this CPU. Try to cheaply make it quiet. */
  54. 1: wfi
  55. wfe
  56. b 1b
  57. 2: pr_dbg "kernel mcpm_entry_point\n"
  58. /*
  59. * MMU is off so we need to get to various variables in a
  60. * position independent way.
  61. */
  62. adr r5, 3f
  63. ldmia r5, {r0, r6, r7, r8, r11}
  64. add r0, r5, r0 @ r0 = mcpm_entry_early_pokes
  65. add r6, r5, r6 @ r6 = mcpm_entry_vectors
  66. ldr r7, [r5, r7] @ r7 = mcpm_power_up_setup_phys
  67. add r8, r5, r8 @ r8 = mcpm_sync
  68. add r11, r5, r11 @ r11 = first_man_locks
  69. @ Perform an early poke, if any
  70. add r0, r0, r4, lsl #3
  71. ldmia r0, {r0, r1}
  72. teq r0, #0
  73. strne r1, [r0]
  74. mov r0, #MCPM_SYNC_CLUSTER_SIZE
  75. mla r8, r0, r10, r8 @ r8 = sync cluster base
  76. @ Signal that this CPU is coming UP:
  77. mov r0, #CPU_COMING_UP
  78. mov r5, #MCPM_SYNC_CPU_SIZE
  79. mla r5, r9, r5, r8 @ r5 = sync cpu address
  80. strb r0, [r5]
  81. @ At this point, the cluster cannot unexpectedly enter the GOING_DOWN
  82. @ state, because there is at least one active CPU (this CPU).
  83. mov r0, #VLOCK_SIZE
  84. mla r11, r0, r10, r11 @ r11 = cluster first man lock
  85. mov r0, r11
  86. mov r1, r9 @ cpu
  87. bl vlock_trylock @ implies DMB
  88. cmp r0, #0 @ failed to get the lock?
  89. bne mcpm_setup_wait @ wait for cluster setup if so
  90. ldrb r0, [r8, #MCPM_SYNC_CLUSTER_CLUSTER]
  91. cmp r0, #CLUSTER_UP @ cluster already up?
  92. bne mcpm_setup @ if not, set up the cluster
  93. @ Otherwise, release the first man lock and skip setup:
  94. mov r0, r11
  95. bl vlock_unlock
  96. b mcpm_setup_complete
  97. mcpm_setup:
  98. @ Control dependency implies strb not observable before previous ldrb.
  99. @ Signal that the cluster is being brought up:
  100. mov r0, #INBOUND_COMING_UP
  101. strb r0, [r8, #MCPM_SYNC_CLUSTER_INBOUND]
  102. dmb
  103. @ Any CPU trying to take the cluster into CLUSTER_GOING_DOWN from this
  104. @ point onwards will observe INBOUND_COMING_UP and abort.
  105. @ Wait for any previously-pending cluster teardown operations to abort
  106. @ or complete:
  107. mcpm_teardown_wait:
  108. ldrb r0, [r8, #MCPM_SYNC_CLUSTER_CLUSTER]
  109. cmp r0, #CLUSTER_GOING_DOWN
  110. bne first_man_setup
  111. wfe
  112. b mcpm_teardown_wait
  113. first_man_setup:
  114. dmb
  115. @ If the outbound gave up before teardown started, skip cluster setup:
  116. cmp r0, #CLUSTER_UP
  117. beq mcpm_setup_leave
  118. @ power_up_setup is now responsible for setting up the cluster:
  119. cmp r7, #0
  120. mov r0, #1 @ second (cluster) affinity level
  121. blxne r7 @ Call power_up_setup if defined
  122. dmb
  123. mov r0, #CLUSTER_UP
  124. strb r0, [r8, #MCPM_SYNC_CLUSTER_CLUSTER]
  125. dmb
  126. mcpm_setup_leave:
  127. @ Leave the cluster setup critical section:
  128. mov r0, #INBOUND_NOT_COMING_UP
  129. strb r0, [r8, #MCPM_SYNC_CLUSTER_INBOUND]
  130. dsb st
  131. sev
  132. mov r0, r11
  133. bl vlock_unlock @ implies DMB
  134. b mcpm_setup_complete
  135. @ In the contended case, non-first men wait here for cluster setup
  136. @ to complete:
  137. mcpm_setup_wait:
  138. ldrb r0, [r8, #MCPM_SYNC_CLUSTER_CLUSTER]
  139. cmp r0, #CLUSTER_UP
  140. wfene
  141. bne mcpm_setup_wait
  142. dmb
  143. mcpm_setup_complete:
  144. @ If a platform-specific CPU setup hook is needed, it is
  145. @ called from here.
  146. cmp r7, #0
  147. mov r0, #0 @ first (CPU) affinity level
  148. blxne r7 @ Call power_up_setup if defined
  149. dmb
  150. @ Mark the CPU as up:
  151. mov r0, #CPU_UP
  152. strb r0, [r5]
  153. @ Observability order of CPU_UP and opening of the gate does not matter.
  154. mcpm_entry_gated:
  155. ldr r5, [r6, r4, lsl #2] @ r5 = CPU entry vector
  156. cmp r5, #0
  157. wfeeq
  158. beq mcpm_entry_gated
  159. dmb
  160. pr_dbg "released\n"
  161. bx r5
  162. .align 2
  163. 3: .word mcpm_entry_early_pokes - .
  164. .word mcpm_entry_vectors - 3b
  165. .word mcpm_power_up_setup_phys - 3b
  166. .word mcpm_sync - 3b
  167. .word first_man_locks - 3b
  168. ENDPROC(mcpm_entry_point)
  169. .bss
  170. .align CACHE_WRITEBACK_ORDER
  171. .type first_man_locks, #object
  172. first_man_locks:
  173. .space VLOCK_SIZE * MAX_NR_CLUSTERS
  174. .align CACHE_WRITEBACK_ORDER
  175. .type mcpm_entry_vectors, #object
  176. ENTRY(mcpm_entry_vectors)
  177. .space 4 * MAX_NR_CLUSTERS * MAX_CPUS_PER_CLUSTER
  178. .type mcpm_entry_early_pokes, #object
  179. ENTRY(mcpm_entry_early_pokes)
  180. .space 8 * MAX_NR_CLUSTERS * MAX_CPUS_PER_CLUSTER
  181. .type mcpm_power_up_setup_phys, #object
  182. ENTRY(mcpm_power_up_setup_phys)
  183. .space 4 @ set by mcpm_sync_init()