| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  | /* | 
					
						
							|  |  |  |  * arch/arm/common/mcpm_head.S -- kernel entry point for multi-cluster PM | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Created by:  Nicolas Pitre, March 2012 | 
					
						
							|  |  |  |  * Copyright:   (C) 2012-2013  Linaro Limited | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify
 | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License version 2 as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Refer to Documentation/arm/cluster-pm-race-avoidance.txt | 
					
						
							|  |  |  |  * for details of the synchronisation algorithms used here. | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/linkage.h> | 
					
						
							|  |  |  | #include <asm/mcpm.h> | 
					
						
							| 
									
										
										
										
											2013-10-07 21:37:19 -07:00
										 |  |  | #include <asm/assembler.h> | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-17 16:07:02 +01:00
										 |  |  | #include "vlock.h" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | .if MCPM_SYNC_CLUSTER_CPUS
 | 
					
						
							|  |  |  | .error "cpus must be the first member of struct mcpm_sync_struct" | 
					
						
							|  |  |  | .endif | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  | 	.macro	pr_dbg	string | 
					
						
							|  |  |  | #if defined(CONFIG_DEBUG_LL) && defined(DEBUG) | 
					
						
							|  |  |  | 	b	1901f | 
					
						
							|  |  |  | 1902:	.asciz	"CPU" | 
					
						
							|  |  |  | 1903:	.asciz	" cluster" | 
					
						
							|  |  |  | 1904:	.asciz	": \string" | 
					
						
							|  |  |  | 	.align | 
					
						
							|  |  |  | 1901:	adr	r0, 1902b | 
					
						
							|  |  |  | 	bl	printascii | 
					
						
							|  |  |  | 	mov	r0, r9 | 
					
						
							| 
									
										
										
										
											2013-05-31 05:17:29 +01:00
										 |  |  | 	bl	printhex2 | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  | 	adr	r0, 1903b | 
					
						
							|  |  |  | 	bl	printascii | 
					
						
							|  |  |  | 	mov	r0, r10 | 
					
						
							| 
									
										
										
										
											2013-05-31 05:17:29 +01:00
										 |  |  | 	bl	printhex2 | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  | 	adr	r0, 1904b | 
					
						
							|  |  |  | 	bl	printascii | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 	.endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.arm | 
					
						
							|  |  |  | 	.align | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ENTRY(mcpm_entry_point) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-07 21:37:19 -07:00
										 |  |  |  ARM_BE8(setend        be) | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  |  THUMB(	adr	r12, BSYM(1f)	) | 
					
						
							|  |  |  |  THUMB(	bx	r12		) | 
					
						
							|  |  |  |  THUMB(	.thumb			) | 
					
						
							|  |  |  | 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, #MAX_CPUS_PER_CLUSTER | 
					
						
							|  |  |  | 	mla	r4, r3, r10, r9			@ r4 = canonical CPU index
 | 
					
						
							|  |  |  | 	cmp	r4, #(MAX_CPUS_PER_CLUSTER * MAX_NR_CLUSTERS) | 
					
						
							|  |  |  | 	blo	2f | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* We didn't expect this CPU.  Try to cheaply make it quiet. */ | 
					
						
							|  |  |  | 1:	wfi | 
					
						
							|  |  |  | 	wfe | 
					
						
							|  |  |  | 	b	1b | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2:	pr_dbg	"kernel mcpm_entry_point\n" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | 	 * MMU is off so we need to get to various variables in a | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  | 	 * position independent way. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	adr	r5, 3f | 
					
						
							| 
									
										
										
										
											2012-11-27 23:11:20 -05:00
										 |  |  | 	ldmia	r5, {r0, r6, r7, r8, r11} | 
					
						
							|  |  |  | 	add	r0, r5, r0			@ r0 = mcpm_entry_early_pokes
 | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  | 	add	r6, r5, r6			@ r6 = mcpm_entry_vectors
 | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | 	ldr	r7, [r5, r7]			@ r7 = mcpm_power_up_setup_phys
 | 
					
						
							|  |  |  | 	add	r8, r5, r8			@ r8 = mcpm_sync
 | 
					
						
							| 
									
										
										
										
											2012-08-17 16:07:02 +01:00
										 |  |  | 	add	r11, r5, r11			@ r11 = first_man_locks
 | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-27 23:11:20 -05:00
										 |  |  | 	@ Perform an early poke, if any
 | 
					
						
							|  |  |  | 	add	r0, r0, r4, lsl #3 | 
					
						
							|  |  |  | 	ldmia	r0, {r0, r1} | 
					
						
							|  |  |  | 	teq	r0, #0 | 
					
						
							|  |  |  | 	strne	r1, [r0] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | 	mov	r0, #MCPM_SYNC_CLUSTER_SIZE | 
					
						
							|  |  |  | 	mla	r8, r0, r10, r8			@ r8 = sync cluster base
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@ Signal that this CPU is coming UP:
 | 
					
						
							|  |  |  | 	mov	r0, #CPU_COMING_UP | 
					
						
							|  |  |  | 	mov	r5, #MCPM_SYNC_CPU_SIZE | 
					
						
							|  |  |  | 	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 16:07:02 +01:00
										 |  |  | 	mov	r0, #VLOCK_SIZE | 
					
						
							|  |  |  | 	mla	r11, r0, r10, r11		@ r11 = cluster first man lock
 | 
					
						
							|  |  |  | 	mov	r0, r11 | 
					
						
							|  |  |  | 	mov	r1, r9				@ cpu
 | 
					
						
							|  |  |  | 	bl	vlock_trylock			@ implies DMB
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cmp	r0, #0				@ failed to get the lock?
 | 
					
						
							|  |  |  | 	bne	mcpm_setup_wait		@ wait for cluster setup if so
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | 	ldrb	r0, [r8, #MCPM_SYNC_CLUSTER_CLUSTER] | 
					
						
							|  |  |  | 	cmp	r0, #CLUSTER_UP			@ cluster already up? | 
					
						
							|  |  |  | 	bne	mcpm_setup			@ if not, set up the cluster
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-17 16:07:02 +01:00
										 |  |  | 	@ Otherwise, release the first man lock and skip setup:
 | 
					
						
							|  |  |  | 	mov	r0, r11 | 
					
						
							|  |  |  | 	bl	vlock_unlock | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | 	b	mcpm_setup_complete | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | mcpm_setup: | 
					
						
							|  |  |  | 	@ Control dependency implies strb not observable before previous ldrb.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@ Signal that the cluster is being brought up:
 | 
					
						
							|  |  |  | 	mov	r0, #INBOUND_COMING_UP | 
					
						
							|  |  |  | 	strb	r0, [r8, #MCPM_SYNC_CLUSTER_INBOUND] | 
					
						
							|  |  |  | 	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, #MCPM_SYNC_CLUSTER_CLUSTER] | 
					
						
							|  |  |  | 	cmp	r0, #CLUSTER_GOING_DOWN | 
					
						
							|  |  |  | 	bne	first_man_setup | 
					
						
							|  |  |  | 	wfe | 
					
						
							|  |  |  | 	b	mcpm_teardown_wait | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | first_man_setup: | 
					
						
							|  |  |  | 	dmb | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@ If the outbound gave up before teardown started, skip cluster setup:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cmp	r0, #CLUSTER_UP | 
					
						
							|  |  |  | 	beq	mcpm_setup_leave | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@ 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, #CLUSTER_UP | 
					
						
							|  |  |  | 	strb	r0, [r8, #MCPM_SYNC_CLUSTER_CLUSTER] | 
					
						
							|  |  |  | 	dmb | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | mcpm_setup_leave: | 
					
						
							|  |  |  | 	@ Leave the cluster setup critical section:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mov	r0, #INBOUND_NOT_COMING_UP | 
					
						
							|  |  |  | 	strb	r0, [r8, #MCPM_SYNC_CLUSTER_INBOUND] | 
					
						
							| 
									
										
										
										
											2013-05-14 10:08:07 +01:00
										 |  |  | 	dsb	st | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | 	sev | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-17 16:07:02 +01:00
										 |  |  | 	mov	r0, r11 | 
					
						
							|  |  |  | 	bl	vlock_unlock	@ implies DMB
 | 
					
						
							|  |  |  | 	b	mcpm_setup_complete | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@ In the contended case, non-first men wait here for cluster setup
 | 
					
						
							|  |  |  | 	@ to complete:
 | 
					
						
							|  |  |  | mcpm_setup_wait: | 
					
						
							|  |  |  | 	ldrb	r0, [r8, #MCPM_SYNC_CLUSTER_CLUSTER] | 
					
						
							|  |  |  | 	cmp	r0, #CLUSTER_UP | 
					
						
							|  |  |  | 	wfene | 
					
						
							|  |  |  | 	bne	mcpm_setup_wait | 
					
						
							|  |  |  | 	dmb | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01: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, #CPU_UP | 
					
						
							|  |  |  | 	strb	r0, [r5] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@ Observability order of CPU_UP and opening of the gate does not matter.
 | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | mcpm_entry_gated: | 
					
						
							|  |  |  | 	ldr	r5, [r6, r4, lsl #2]		@ r5 = CPU entry vector
 | 
					
						
							|  |  |  | 	cmp	r5, #0 | 
					
						
							|  |  |  | 	wfeeq | 
					
						
							|  |  |  | 	beq	mcpm_entry_gated | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | 	dmb | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  | 	pr_dbg	"released\n" | 
					
						
							|  |  |  | 	bx	r5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.align	2
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-27 23:11:20 -05:00
										 |  |  | 3:	.word	mcpm_entry_early_pokes - . | 
					
						
							|  |  |  | 	.word	mcpm_entry_vectors - 3b | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | 	.word	mcpm_power_up_setup_phys - 3b | 
					
						
							|  |  |  | 	.word	mcpm_sync - 3b | 
					
						
							| 
									
										
										
										
											2012-08-17 16:07:02 +01:00
										 |  |  | 	.word	first_man_locks - 3b | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | ENDPROC(mcpm_entry_point) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.bss | 
					
						
							| 
									
										
										
										
											2012-08-17 16:07:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	.align	CACHE_WRITEBACK_ORDER
 | 
					
						
							|  |  |  | 	.type	first_man_locks, #object | 
					
						
							|  |  |  | first_man_locks: | 
					
						
							|  |  |  | 	.space	VLOCK_SIZE * MAX_NR_CLUSTERS | 
					
						
							|  |  |  | 	.align	CACHE_WRITEBACK_ORDER
 | 
					
						
							| 
									
										
										
										
											2012-04-12 02:45:22 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	.type	mcpm_entry_vectors, #object | 
					
						
							|  |  |  | ENTRY(mcpm_entry_vectors) | 
					
						
							|  |  |  | 	.space	4 * MAX_NR_CLUSTERS * MAX_CPUS_PER_CLUSTER | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-27 23:11:20 -05:00
										 |  |  | 	.type	mcpm_entry_early_pokes, #object | 
					
						
							|  |  |  | ENTRY(mcpm_entry_early_pokes) | 
					
						
							|  |  |  | 	.space	8 * MAX_NR_CLUSTERS * MAX_CPUS_PER_CLUSTER | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-17 14:25:42 +01:00
										 |  |  | 	.type	mcpm_power_up_setup_phys, #object | 
					
						
							|  |  |  | ENTRY(mcpm_power_up_setup_phys) | 
					
						
							|  |  |  | 	.space  4		@ set by mcpm_sync_init()
 |