mcpm_head.S 5.3 KB

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