2011-02-06 15:48:39 +00:00
# include < l i n u x / l i n k a g e . h >
2011-02-11 11:32:19 +00:00
# include < l i n u x / t h r e a d s . h >
2011-02-06 15:48:39 +00:00
# include < a s m / a s m - o f f s e t s . h >
# include < a s m / a s s e m b l e r . h >
# include < a s m / g l u e - c a c h e . h >
# include < a s m / g l u e - p r o c . h >
.text
2013-05-16 10:34:30 +01:00
/ *
* Implementation o f M P I D R h a s h a l g o r i t h m t h r o u g h s h i f t i n g
* and O R ' i n g .
*
* @dst: register containing hash result
* @rs0: register containing affinity level 0 bit shift
* @rs1: register containing affinity level 1 bit shift
* @rs2: register containing affinity level 2 bit shift
* @mpidr: register containing MPIDR value
* @mask: register containing MPIDR mask
*
* Pseudo C - c o d e :
*
* u3 2 d s t ;
*
* compute_ m p i d r _ h a s h ( u 3 2 r s0 , u 3 2 r s1 , u 3 2 r s2 , u 3 2 m p i d r , u 3 2 m a s k ) {
* u3 2 a f f0 , a f f1 , a f f2 ;
* u3 2 m p i d r _ m a s k e d = m p i d r & m a s k ;
* aff0 = m p i d r _ m a s k e d & 0 x f f ;
* aff1 = m p i d r _ m a s k e d & 0 x f f00 ;
* aff2 = m p i d r _ m a s k e d & 0 x f f00 0 0 ;
* dst = ( a f f0 > > r s0 | a f f1 > > r s1 | a f f2 > > r s2 ) ;
* }
* Input r e g i s t e r s : r s0 , r s1 , r s2 , m p i d r , m a s k
* Output r e g i s t e r : d s t
* Note : input a n d o u t p u t r e g i s t e r s m u s t b e d i s j o i n t r e g i s t e r s e t s
( eg : a m a c r o i n s t a n c e w i t h m p i d r = r1 a n d d s t = r1 i s i n v a l i d )
* /
.macro compute_mpidr_hash dst, r s0 , r s1 , r s2 , m p i d r , m a s k
and \ m p i d r , \ m p i d r , \ m a s k @ mask out MPIDR bits
and \ d s t , \ m p i d r , #0xff @ mask=aff0
ARM( m o v \ d s t , \ d s t , l s r \ r s0 ) @ dst=aff0>>rs0
THUMB( l s r \ d s t , \ d s t , \ r s0 )
and \ m a s k , \ m p i d r , #0xff00 @ mask = aff1
ARM( o r r \ d s t , \ d s t , \ m a s k , l s r \ r s1 ) @ dst|=(aff1>>rs1)
THUMB( l s r \ m a s k , \ m a s k , \ r s1 )
THUMB( o r r \ d s t , \ d s t , \ m a s k )
and \ m a s k , \ m p i d r , #0xff0000 @ mask = aff2
ARM( o r r \ d s t , \ d s t , \ m a s k , l s r \ r s2 ) @ dst|=(aff2>>rs2)
THUMB( l s r \ m a s k , \ m a s k , \ r s2 )
THUMB( o r r \ d s t , \ d s t , \ m a s k )
.endm
2011-02-06 15:48:39 +00:00
/ *
2011-09-01 11:52:33 +01:00
* Save C P U s t a t e f o r a s u s p e n d . T h i s s a v e s t h e C P U g e n e r a l p u r p o s e
* registers, a n d a l l o c a t e s s p a c e o n t h e k e r n e l s t a c k t o s a v e t h e C P U
* specific r e g i s t e r s a n d s o m e o t h e r d a t a f o r r e s u m e .
* r0 = s u s p e n d f u n c t i o n a r g 0
* r1 = s u s p e n d f u n c t i o n
2013-07-18 16:50:59 -04:00
* r2 = M P I D R v a l u e t h e r e s u m i n g C P U w i l l u s e
2011-02-06 15:48:39 +00:00
* /
2011-06-22 17:41:48 +01:00
ENTRY( _ _ c p u _ s u s p e n d )
2011-06-13 15:58:34 +01:00
stmfd s p ! , { r4 - r11 , l r }
2011-02-06 15:48:39 +00:00
# ifdef M U L T I _ C P U
ldr r10 , =processor
2011-09-01 11:52:33 +01:00
ldr r4 , [ r10 , #C P U _ S L E E P _ S I Z E ] @ s i z e o f C P U s l e e p s t a t e
2011-02-11 11:32:19 +00:00
# else
2011-09-01 11:52:33 +01:00
ldr r4 , =cpu_suspend_size
2011-06-13 13:53:06 +01:00
# endif
2011-09-01 11:52:33 +01:00
mov r5 , s p @ current virtual SP
add r4 , r4 , #12 @ Space for pgd, virt sp, phys resume fn
sub s p , s p , r4 @ allocate CPU state on stack
ldr r3 , =sleep_save_sp
2013-07-18 16:50:59 -04:00
stmfd s p ! , { r0 , r1 } @ save suspend func arg and pointer
2013-05-16 10:34:30 +01:00
ldr r3 , [ r3 , #S L E E P _ S A V E _ S P _ V I R T ]
2013-07-18 16:50:59 -04:00
ALT_ S M P ( l d r r0 , =mpidr_hash )
ALT_ U P _ B ( 1 f )
/* This ldmia relies on the memory layout of the mpidr_hash struct */
ldmia r0 , { r1 , r6 - r8 } @ r1 = mpidr mask (r6,r7,r8) = l[0,1,2] shifts
compute_ m p i d r _ h a s h r0 , r6 , r7 , r8 , r2 , r1
add r3 , r3 , r0 , l s l #2
1 : mov r2 , r5 @ virtual SP
mov r1 , r4 @ size of save block
add r0 , s p , #8 @ pointer to save block
2011-09-01 11:52:33 +01:00
bl _ _ c p u _ s u s p e n d _ s a v e
2015-04-21 14:17:25 +01:00
badr l r , c p u _ s u s p e n d _ a b o r t
2011-06-13 15:28:40 +01:00
ldmfd s p ! , { r0 , p c } @ call suspend fn
2011-06-22 17:41:48 +01:00
ENDPROC( _ _ c p u _ s u s p e n d )
2011-02-06 15:48:39 +00:00
.ltorg
2011-07-02 09:54:01 +01:00
cpu_suspend_abort :
2011-08-27 22:39:09 +01:00
ldmia s p ! , { r1 - r3 } @ pop phys pgd, virt SP, phys resume fn
2011-08-27 11:17:36 +01:00
teq r0 , #0
moveq r0 , #1 @ force non-zero value
2011-07-02 09:54:01 +01:00
mov s p , r2
ldmfd s p ! , { r4 - r11 , p c }
ENDPROC( c p u _ s u s p e n d _ a b o r t )
2011-02-06 15:48:39 +00:00
/ *
* r0 = c o n t r o l r e g i s t e r v a l u e
* /
2011-08-31 23:26:18 +01:00
.align 5
2011-11-15 11:11:19 +00:00
.pushsection .idmap .text , " ax"
2011-02-06 15:48:39 +00:00
ENTRY( c p u _ r e s u m e _ m m u )
ldr r3 , =cpu_resume_after_mmu
2011-11-22 17:30:28 +00:00
instr_ s y n c
2011-08-26 20:28:52 +01:00
mcr p15 , 0 , r0 , c1 , c0 , 0 @ turn on MMU, I-cache, etc
mrc p15 , 0 , r0 , c0 , c0 , 0 @ read id reg
2011-11-22 17:30:28 +00:00
instr_ s y n c
2011-08-26 20:28:52 +01:00
mov r0 , r0
mov r0 , r0
2014-06-30 16:29:12 +01:00
ret r3 @ jump to virtual address
2011-08-31 23:26:18 +01:00
ENDPROC( c p u _ r e s u m e _ m m u )
2011-11-15 11:11:19 +00:00
.popsection
2011-02-06 15:48:39 +00:00
cpu_resume_after_mmu :
2011-06-21 16:32:58 +01:00
bl c p u _ i n i t @ restore the und/abt/irq banked regs
2011-07-02 09:54:01 +01:00
mov r0 , #0 @ return zero on success
2011-06-13 15:04:14 +01:00
ldmfd s p ! , { r4 - r11 , p c }
2011-02-06 15:48:39 +00:00
ENDPROC( c p u _ r e s u m e _ a f t e r _ m m u )
2015-03-25 07:39:21 +01:00
.text
2011-02-06 15:48:39 +00:00
.align
2015-06-12 09:24:17 +01:00
# ifdef C O N F I G _ M M U
2015-06-09 19:24:23 +01:00
.arm
ENTRY( c p u _ r e s u m e _ a r m )
2015-06-12 21:19:35 +01:00
THUMB( b a d r r9 , 1 f ) @ Kernel is entered in ARM.
2015-06-09 19:24:23 +01:00
THUMB( b x r9 ) @ If this is a Thumb-2 kernel,
THUMB( . t h u m b ) @ switch to Thumb now.
THUMB( 1 : )
2015-06-12 09:24:17 +01:00
# endif
2011-02-06 15:48:39 +00:00
ENTRY( c p u _ r e s u m e )
2013-02-01 09:40:42 +00:00
ARM_ B E 8 ( s e t e n d b e ) @ ensure we are in BE mode
2014-05-08 17:31:40 +01:00
# ifdef C O N F I G _ A R M _ V I R T _ E X T
bl _ _ h y p _ s t u b _ i n s t a l l _ s e c o n d a r y
# endif
safe_ s v c m o d e _ m a s k a l l r1
2013-05-16 10:34:30 +01:00
mov r1 , #0
ALT_ S M P ( m r c p15 , 0 , r0 , c0 , c0 , 5 )
ALT_ U P _ B ( 1 f )
adr r2 , m p i d r _ h a s h _ p t r
ldr r3 , [ r2 ]
add r2 , r2 , r3 @ r2 = struct mpidr_hash phys address
/ *
* This l d m i a r e l i e s o n t h e m e m o r y l a y o u t o f t h e m p i d r _ h a s h
* struct m p i d r _ h a s h .
* /
ldmia r2 , { r3 - r6 } @ r3 = mpidr mask (r4,r5,r6) = l[0,1,2] shifts
compute_ m p i d r _ h a s h r1 , r4 , r5 , r6 , r0 , r3
1 :
adr r0 , _ s l e e p _ s a v e _ s p
2015-03-25 07:39:21 +01:00
ldr r2 , [ r0 ]
add r0 , r0 , r2
2013-05-16 10:34:30 +01:00
ldr r0 , [ r0 , #S L E E P _ S A V E _ S P _ P H Y S ]
ldr r0 , [ r0 , r1 , l s l #2 ]
2011-08-27 22:39:09 +01:00
@ load phys pgd, stack, resume fn
ARM( l d m i a r0 ! , { r1 , s p , p c } )
THUMB( l d m i a r0 ! , { r1 , r2 , r3 } )
THUMB( m o v s p , r2 )
THUMB( b x r3 )
2011-02-06 15:48:39 +00:00
ENDPROC( c p u _ r e s u m e )
2015-06-12 09:24:17 +01:00
# ifdef C O N F I G _ M M U
2015-06-09 19:24:23 +01:00
ENDPROC( c p u _ r e s u m e _ a r m )
2015-06-12 09:24:17 +01:00
# endif
2011-02-06 15:48:39 +00:00
2013-05-16 10:34:30 +01:00
.align 2
2015-03-25 07:39:21 +01:00
_sleep_save_sp :
.long sleep_save_sp - .
2013-05-16 10:34:30 +01:00
mpidr_hash_ptr :
.long mpidr_hash - . @ mpidr_hash struct offset
2015-03-25 07:39:21 +01:00
.data
2013-05-16 10:34:30 +01:00
.type sleep_ s a v e _ s p , #o b j e c t
ENTRY( s l e e p _ s a v e _ s p )
.space SLEEP_SAVE_SP_SZ @ struct sleep_save_sp