2019-06-04 11:11:33 +03:00
/* SPDX-License-Identifier: GPL-2.0-only */
2012-04-12 10:45:22 +04:00
/ *
* arch/ a r m / c o m m o n / m c p m _ h e a d . S - - k e r n e l e n t r y p o i n t f o r m u l t i - c l u s t e r P M
*
* Created b y : N i c o l a s P i t r e , M a r c h 2 0 1 2
* Copyright : ( C) 2 0 1 2 - 2 0 1 3 L i n a r o L i m i t e d
*
2019-04-14 21:51:10 +03:00
* Refer t o D o c u m e n t a t i o n / a r m / c l u s t e r - p m - r a c e - a v o i d a n c e . r s t
2012-07-17 17:25:42 +04:00
* for d e t a i l s o f t h e s y n c h r o n i s a t i o n a l g o r i t h m s u s e d h e r e .
2012-04-12 10:45:22 +04:00
* /
# include < l i n u x / l i n k a g e . h >
# include < a s m / m c p m . h >
2013-10-08 08:37:19 +04:00
# include < a s m / a s s e m b l e r . h >
2012-04-12 10:45:22 +04:00
2012-08-17 19:07:02 +04:00
# include " v l o c k . h "
2012-07-17 17:25:42 +04:00
.if MCPM_SYNC_CLUSTER_CPUS
.error " cpus m u s t b e t h e f i r s t m e m b e r o f s t r u c t m c p m _ s y n c _ s t r u c t "
.endif
2012-04-12 10:45:22 +04:00
.macro pr_dbg string
# if d e f i n e d ( C O N F I G _ D E B U G _ L L ) & & d e f i n e d ( D E B U G )
b 1 9 0 1 f
1902 : .asciz " CPU "
1903 : .asciz " cluster "
1904 : .asciz " : \string "
.align
1901 : adr r0 , 1 9 0 2 b
bl p r i n t a s c i i
mov r0 , r9
2013-05-31 08:17:29 +04:00
bl p r i n t h e x2
2012-04-12 10:45:22 +04:00
adr r0 , 1 9 0 3 b
bl p r i n t a s c i i
mov r0 , r10
2013-05-31 08:17:29 +04:00
bl p r i n t h e x2
2012-04-12 10:45:22 +04:00
adr r0 , 1 9 0 4 b
bl p r i n t a s c i i
# endif
.endm
.arm
.align
ENTRY( m c p m _ e n t r y _ p o i n t )
2013-10-08 08:37:19 +04:00
ARM_ B E 8 ( s e t e n d b e )
2015-04-21 16:17:25 +03:00
THUMB( b a d r r12 , 1 f )
2012-04-12 10:45:22 +04:00
THUMB( b x r12 )
THUMB( . t h u m b )
1 :
mrc p15 , 0 , r0 , c0 , c0 , 5 @ MPIDR
ubfx r9 , r0 , #0 , #8 @ r9 = cpu
ubfx r10 , r0 , #8 , #8 @ r10 = cluster
mov r3 , #M A X _ C P U S _ P E R _ C L U S T E R
mla r4 , r3 , r10 , r9 @ r4 = canonical CPU index
cmp r4 , #( M A X _ C P U S _ P E R _ C L U S T E R * M A X _ N R _ C L U S T E R S )
blo 2 f
/* We didn't expect this CPU. Try to cheaply make it quiet. */
1 : wfi
wfe
b 1 b
2 : pr_ d b g " k e r n e l m c p m _ e n t r y _ p o i n t \ n "
/ *
2012-07-17 17:25:42 +04:00
* MMU i s o f f s o w e n e e d t o g e t t o v a r i o u s v a r i a b l e s i n a
2012-04-12 10:45:22 +04:00
* position i n d e p e n d e n t w a y .
* /
adr r5 , 3 f
2012-11-28 08:11:20 +04:00
ldmia r5 , { r0 , r6 , r7 , r8 , r11 }
add r0 , r5 , r0 @ r0 = mcpm_entry_early_pokes
2012-04-12 10:45:22 +04:00
add r6 , r5 , r6 @ r6 = mcpm_entry_vectors
2012-07-17 17:25:42 +04:00
ldr r7 , [ r5 , r7 ] @ r7 = mcpm_power_up_setup_phys
add r8 , r5 , r8 @ r8 = mcpm_sync
2012-08-17 19:07:02 +04:00
add r11 , r5 , r11 @ r11 = first_man_locks
2012-07-17 17:25:42 +04:00
2012-11-28 08:11:20 +04:00
@ Perform an early poke, if any
add r0 , r0 , r4 , l s l #3
ldmia r0 , { r0 , r1 }
teq r0 , #0
strne r1 , [ r0 ]
2012-07-17 17:25:42 +04:00
mov r0 , #M C P M _ S Y N C _ C L U S T E R _ S I Z E
mla r8 , r0 , r10 , r8 @ r8 = sync cluster base
@ Signal that this CPU is coming UP:
mov r0 , #C P U _ C O M I N G _ U P
mov r5 , #M C P M _ S Y N C _ C P U _ S I Z E
mla r5 , r9 , r5 , r8 @ r5 = sync cpu address
strb r0 , [ r5 ]
@ At this point, the cluster cannot unexpectedly enter the GOING_DOWN
@ state, because there is at least one active CPU (this CPU).
2012-08-17 19:07:02 +04:00
mov r0 , #V L O C K _ S I Z E
mla r11 , r0 , r10 , r11 @ r11 = cluster first man lock
mov r0 , r11
mov r1 , r9 @ cpu
bl v l o c k _ t r y l o c k @ implies DMB
cmp r0 , #0 @ failed to get the lock?
bne m c p m _ s e t u p _ w a i t @ wait for cluster setup if so
2012-07-17 17:25:42 +04:00
ldrb r0 , [ r8 , #M C P M _ S Y N C _ C L U S T E R _ C L U S T E R ]
cmp r0 , #C L U S T E R _ U P @ c l u s t e r a l r e a d y u p ?
bne m c p m _ s e t u p @ if not, set up the cluster
2012-08-17 19:07:02 +04:00
@ Otherwise, release the first man lock and skip setup:
mov r0 , r11
bl v l o c k _ u n l o c k
2012-07-17 17:25:42 +04:00
b m c p m _ s e t u p _ c o m p l e t e
mcpm_setup :
@ Control dependency implies strb not observable before previous ldrb.
@ Signal that the cluster is being brought up:
mov r0 , #I N B O U N D _ C O M I N G _ U P
strb r0 , [ r8 , #M C P M _ S Y N C _ C L U S T E R _ I N B O U N D ]
dmb
@ Any CPU trying to take the cluster into CLUSTER_GOING_DOWN from this
@ point onwards will observe INBOUND_COMING_UP and abort.
@ Wait for any previously-pending cluster teardown operations to abort
@ or complete:
mcpm_teardown_wait :
ldrb r0 , [ r8 , #M C P M _ S Y N C _ C L U S T E R _ C L U S T E R ]
cmp r0 , #C L U S T E R _ G O I N G _ D O W N
bne f i r s t _ m a n _ s e t u p
wfe
b m c p m _ t e a r d o w n _ w a i t
first_man_setup :
dmb
@ If the outbound gave up before teardown started, skip cluster setup:
cmp r0 , #C L U S T E R _ U P
beq m c p m _ s e t u p _ l e a v e
@ power_up_setup is now responsible for setting up the cluster:
cmp r7 , #0
mov r0 , #1 @ second (cluster) affinity level
blxne r7 @ Call power_up_setup if defined
dmb
mov r0 , #C L U S T E R _ U P
strb r0 , [ r8 , #M C P M _ S Y N C _ C L U S T E R _ C L U S T E R ]
dmb
mcpm_setup_leave :
@ Leave the cluster setup critical section:
mov r0 , #I N B O U N D _ N O T _ C O M I N G _ U P
strb r0 , [ r8 , #M C P M _ S Y N C _ C L U S T E R _ I N B O U N D ]
2013-05-14 13:08:07 +04:00
dsb s t
2012-07-17 17:25:42 +04:00
sev
2012-08-17 19:07:02 +04:00
mov r0 , r11
bl v l o c k _ u n l o c k @ implies DMB
b m c p m _ s e t u p _ c o m p l e t e
@ In the contended case, non-first men wait here for cluster setup
@ to complete:
mcpm_setup_wait :
ldrb r0 , [ r8 , #M C P M _ S Y N C _ C L U S T E R _ C L U S T E R ]
cmp r0 , #C L U S T E R _ U P
wfene
bne m c p m _ s e t u p _ w a i t
dmb
2012-07-17 17:25:42 +04:00
mcpm_setup_complete :
@ If a platform-specific CPU setup hook is needed, it is
@ called from here.
cmp r7 , #0
mov r0 , #0 @ first (CPU) affinity level
blxne r7 @ Call power_up_setup if defined
dmb
@ Mark the CPU as up:
mov r0 , #C P U _ U P
strb r0 , [ r5 ]
@ Observability order of CPU_UP and opening of the gate does not matter.
2012-04-12 10:45:22 +04:00
mcpm_entry_gated :
ldr r5 , [ r6 , r4 , l s l #2 ] @ r5 = CPU entry vector
cmp r5 , #0
wfeeq
beq m c p m _ e n t r y _ g a t e d
2012-07-17 17:25:42 +04:00
dmb
2012-04-12 10:45:22 +04:00
pr_ d b g " r e l e a s e d \ n "
bx r5
.align 2
2012-11-28 08:11:20 +04:00
3 : .word m c p m _ e n t r y _ e a r l y _ p o k e s - .
.word mcpm_entry_vectors - 3 b
2012-07-17 17:25:42 +04:00
.word mcpm_power_up_setup_phys - 3 b
.word mcpm_sync - 3 b
2012-08-17 19:07:02 +04:00
.word first_man_locks - 3 b
2012-04-12 10:45:22 +04:00
ENDPROC( m c p m _ e n t r y _ p o i n t )
.bss
2012-08-17 19:07:02 +04:00
.align CACHE_WRITEBACK_ORDER
.type first_ m a n _ l o c k s , #o b j e c t
first_man_locks :
.space VLOCK_SIZE * MAX_ N R _ C L U S T E R S
.align CACHE_WRITEBACK_ORDER
2012-04-12 10:45:22 +04:00
.type mcpm_ e n t r y _ v e c t o r s , #o b j e c t
ENTRY( m c p m _ e n t r y _ v e c t o r s )
.space 4 * MAX_ N R _ C L U S T E R S * M A X _ C P U S _ P E R _ C L U S T E R
2012-07-17 17:25:42 +04:00
2012-11-28 08:11:20 +04:00
.type mcpm_ e n t r y _ e a r l y _ p o k e s , #o b j e c t
ENTRY( m c p m _ e n t r y _ e a r l y _ p o k e s )
.space 8 * MAX_ N R _ C L U S T E R S * M A X _ C P U S _ P E R _ C L U S T E R
2012-07-17 17:25:42 +04:00
.type mcpm_ p o w e r _ u p _ s e t u p _ p h y s , #o b j e c t
ENTRY( m c p m _ p o w e r _ u p _ s e t u p _ p h y s )
.space 4 @ set by mcpm_sync_init()