2011-02-06 18:48:39 +03:00
# include < l i n u x / l i n k a g e . h >
2011-02-11 14:32:19 +03:00
# include < l i n u x / t h r e a d s . h >
2011-02-06 18:48:39 +03: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 13:34:30 +04: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 18:48:39 +03:00
/ *
2011-09-01 14:52:33 +04: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
2011-02-06 18:48:39 +03:00
* /
2011-06-22 20:41:48 +04:00
ENTRY( _ _ c p u _ s u s p e n d )
2011-06-13 18:58:34 +04:00
stmfd s p ! , { r4 - r11 , l r }
2011-02-06 18:48:39 +03:00
# ifdef M U L T I _ C P U
ldr r10 , =processor
2011-09-01 14:52:33 +04: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 14:32:19 +03:00
# else
2011-09-01 14:52:33 +04:00
ldr r4 , =cpu_suspend_size
2011-06-13 16:53:06 +04:00
# endif
2011-09-01 14:52:33 +04: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
stmfd s p ! , { r0 , r1 } @ save suspend func arg and pointer
add r0 , s p , #8 @ save pointer to save block
mov r1 , r4 @ size of save block
mov r2 , r5 @ virtual SP
ldr r3 , =sleep_save_sp
2013-05-16 13:34:30 +04:00
ldr r3 , [ r3 , #S L E E P _ S A V E _ S P _ V I R T ]
ALT_ S M P ( m r c p15 , 0 , r9 , c0 , c0 , 5 )
ALT_ U P _ B ( 1 f )
ldr r8 , =mpidr_hash
/ *
* 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 r8 , { r4 - r7 } @ r4 = mpidr mask (r5,r6,r7) = l[0,1,2] shifts
compute_ m p i d r _ h a s h l r , r5 , r6 , r7 , r9 , r4
2011-09-01 14:52:33 +04:00
add r3 , r3 , l r , l s l #2
2013-05-16 13:34:30 +04:00
1 :
2011-09-01 14:52:33 +04:00
bl _ _ c p u _ s u s p e n d _ s a v e
2011-07-02 12:54:01 +04:00
adr l r , B S Y M ( c p u _ s u s p e n d _ a b o r t )
2011-06-13 18:28:40 +04:00
ldmfd s p ! , { r0 , p c } @ call suspend fn
2011-06-22 20:41:48 +04:00
ENDPROC( _ _ c p u _ s u s p e n d )
2011-02-06 18:48:39 +03:00
.ltorg
2011-07-02 12:54:01 +04:00
cpu_suspend_abort :
2011-08-28 01:39:09 +04:00
ldmia s p ! , { r1 - r3 } @ pop phys pgd, virt SP, phys resume fn
2011-08-27 14:17:36 +04:00
teq r0 , #0
moveq r0 , #1 @ force non-zero value
2011-07-02 12:54:01 +04: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 18:48:39 +03:00
/ *
* r0 = c o n t r o l r e g i s t e r v a l u e
* /
2011-09-01 02:26:18 +04:00
.align 5
2011-11-15 15:11:19 +04:00
.pushsection .idmap .text , " ax"
2011-02-06 18:48:39 +03:00
ENTRY( c p u _ r e s u m e _ m m u )
ldr r3 , =cpu_resume_after_mmu
2011-11-22 21:30:28 +04:00
instr_ s y n c
2011-08-26 23:28:52 +04: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 21:30:28 +04:00
instr_ s y n c
2011-08-26 23:28:52 +04:00
mov r0 , r0
mov r0 , r0
2011-02-06 18:48:39 +03:00
mov p c , r3 @ jump to virtual address
2011-09-01 02:26:18 +04:00
ENDPROC( c p u _ r e s u m e _ m m u )
2011-11-15 15:11:19 +04:00
.popsection
2011-02-06 18:48:39 +03:00
cpu_resume_after_mmu :
2011-06-21 19:32:58 +04:00
bl c p u _ i n i t @ restore the und/abt/irq banked regs
2011-07-02 12:54:01 +04:00
mov r0 , #0 @ return zero on success
2011-06-13 18:04:14 +04:00
ldmfd s p ! , { r4 - r11 , p c }
2011-02-06 18:48:39 +03:00
ENDPROC( c p u _ r e s u m e _ a f t e r _ m m u )
/ *
* Note : Yes, p a r t o f t h e f o l l o w i n g c o d e i s l o c a t e d i n t o t h e . d a t a s e c t i o n .
* This i s t o a l l o w s l e e p _ s a v e _ s p t o b e a c c e s s e d w i t h a r e l a t i v e l o a d
* while w e c a n ' t r e l y o n a n y M M U t r a n s l a t i o n . W e c o u l d h a v e p u t
* sleep_ s a v e _ s p i n t h e . t e x t s e c t i o n a s w e l l , b u t s o m e s e t u p s m i g h t
* insist o n i t t o b e t r u l y r e a d - o n l y .
* /
.data
.align
ENTRY( c p u _ r e s u m e )
2013-05-16 13:34:30 +04: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
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-03-22 21:09:14 +03:00
setmode P S R _ I _ B I T | P S R _ F _ B I T | S V C _ M O D E , r1 @ set SVC, irqs off
2011-08-28 01:39:09 +04: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 18:48:39 +03:00
ENDPROC( c p u _ r e s u m e )
2013-05-16 13:34:30 +04:00
.align 2
mpidr_hash_ptr :
.long mpidr_hash - . @ mpidr_hash struct offset
.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 )
_sleep_save_sp :
.space SLEEP_SAVE_SP_SZ @ struct sleep_save_sp