diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 13 | ||||
-rw-r--r-- | arch/arm/kernel/bios32.c | 9 | ||||
-rw-r--r-- | arch/arm/kernel/entry-common.S | 4 | ||||
-rw-r--r-- | arch/arm/kernel/entry-header.S | 124 | ||||
-rw-r--r-- | arch/arm/kernel/entry-v7m.S | 143 | ||||
-rw-r--r-- | arch/arm/kernel/head-nommu.S | 10 | ||||
-rw-r--r-- | arch/arm/kernel/psci.c | 7 | ||||
-rw-r--r-- | arch/arm/kernel/psci_smp.c | 84 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 26 | ||||
-rw-r--r-- | arch/arm/kernel/topology.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 8 |
11 files changed, 414 insertions, 16 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5f3338eacad2..f4285b5ffb05 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -15,7 +15,7 @@ CFLAGS_REMOVE_return_address.o = -pg | |||
15 | 15 | ||
16 | # Object file lists. | 16 | # Object file lists. |
17 | 17 | ||
18 | obj-y := elf.o entry-armv.o entry-common.o irq.o opcodes.o \ | 18 | obj-y := elf.o entry-common.o irq.o opcodes.o \ |
19 | process.o ptrace.o return_address.o sched_clock.o \ | 19 | process.o ptrace.o return_address.o sched_clock.o \ |
20 | setup.o signal.o stacktrace.o sys_arm.o time.o traps.o | 20 | setup.o signal.o stacktrace.o sys_arm.o time.o traps.o |
21 | 21 | ||
@@ -23,6 +23,12 @@ obj-$(CONFIG_ATAGS) += atags_parse.o | |||
23 | obj-$(CONFIG_ATAGS_PROC) += atags_proc.o | 23 | obj-$(CONFIG_ATAGS_PROC) += atags_proc.o |
24 | obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += atags_compat.o | 24 | obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += atags_compat.o |
25 | 25 | ||
26 | ifeq ($(CONFIG_CPU_V7M),y) | ||
27 | obj-y += entry-v7m.o | ||
28 | else | ||
29 | obj-y += entry-armv.o | ||
30 | endif | ||
31 | |||
26 | obj-$(CONFIG_OC_ETM) += etm.o | 32 | obj-$(CONFIG_OC_ETM) += etm.o |
27 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o | 33 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o |
28 | obj-$(CONFIG_ISA_DMA_API) += dma.o | 34 | obj-$(CONFIG_ISA_DMA_API) += dma.o |
@@ -82,6 +88,9 @@ obj-$(CONFIG_DEBUG_LL) += debug.o | |||
82 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 88 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
83 | 89 | ||
84 | obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o | 90 | obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o |
85 | obj-$(CONFIG_ARM_PSCI) += psci.o | 91 | ifeq ($(CONFIG_ARM_PSCI),y) |
92 | obj-y += psci.o | ||
93 | obj-$(CONFIG_SMP) += psci_smp.o | ||
94 | endif | ||
86 | 95 | ||
87 | extra-y := $(head-y) vmlinux.lds | 96 | extra-y := $(head-y) vmlinux.lds |
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index b2ed73c45489..261fcc826169 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c | |||
@@ -445,7 +445,8 @@ static int pcibios_init_resources(int busnr, struct pci_sys_data *sys) | |||
445 | return 0; | 445 | return 0; |
446 | } | 446 | } |
447 | 447 | ||
448 | static void pcibios_init_hw(struct hw_pci *hw, struct list_head *head) | 448 | static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, |
449 | struct list_head *head) | ||
449 | { | 450 | { |
450 | struct pci_sys_data *sys = NULL; | 451 | struct pci_sys_data *sys = NULL; |
451 | int ret; | 452 | int ret; |
@@ -480,7 +481,7 @@ static void pcibios_init_hw(struct hw_pci *hw, struct list_head *head) | |||
480 | if (hw->scan) | 481 | if (hw->scan) |
481 | sys->bus = hw->scan(nr, sys); | 482 | sys->bus = hw->scan(nr, sys); |
482 | else | 483 | else |
483 | sys->bus = pci_scan_root_bus(NULL, sys->busnr, | 484 | sys->bus = pci_scan_root_bus(parent, sys->busnr, |
484 | hw->ops, sys, &sys->resources); | 485 | hw->ops, sys, &sys->resources); |
485 | 486 | ||
486 | if (!sys->bus) | 487 | if (!sys->bus) |
@@ -497,7 +498,7 @@ static void pcibios_init_hw(struct hw_pci *hw, struct list_head *head) | |||
497 | } | 498 | } |
498 | } | 499 | } |
499 | 500 | ||
500 | void pci_common_init(struct hw_pci *hw) | 501 | void pci_common_init_dev(struct device *parent, struct hw_pci *hw) |
501 | { | 502 | { |
502 | struct pci_sys_data *sys; | 503 | struct pci_sys_data *sys; |
503 | LIST_HEAD(head); | 504 | LIST_HEAD(head); |
@@ -505,7 +506,7 @@ void pci_common_init(struct hw_pci *hw) | |||
505 | pci_add_flags(PCI_REASSIGN_ALL_RSRC); | 506 | pci_add_flags(PCI_REASSIGN_ALL_RSRC); |
506 | if (hw->preinit) | 507 | if (hw->preinit) |
507 | hw->preinit(); | 508 | hw->preinit(); |
508 | pcibios_init_hw(hw, &head); | 509 | pcibios_init_hw(parent, hw, &head); |
509 | if (hw->postinit) | 510 | if (hw->postinit) |
510 | hw->postinit(); | 511 | hw->postinit(); |
511 | 512 | ||
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index bc5bc0a97131..85a72b0809ca 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
@@ -350,6 +350,9 @@ ENDPROC(ftrace_stub) | |||
350 | 350 | ||
351 | .align 5 | 351 | .align 5 |
352 | ENTRY(vector_swi) | 352 | ENTRY(vector_swi) |
353 | #ifdef CONFIG_CPU_V7M | ||
354 | v7m_exception_entry | ||
355 | #else | ||
353 | sub sp, sp, #S_FRAME_SIZE | 356 | sub sp, sp, #S_FRAME_SIZE |
354 | stmia sp, {r0 - r12} @ Calling r0 - r12 | 357 | stmia sp, {r0 - r12} @ Calling r0 - r12 |
355 | ARM( add r8, sp, #S_PC ) | 358 | ARM( add r8, sp, #S_PC ) |
@@ -360,6 +363,7 @@ ENTRY(vector_swi) | |||
360 | str lr, [sp, #S_PC] @ Save calling PC | 363 | str lr, [sp, #S_PC] @ Save calling PC |
361 | str r8, [sp, #S_PSR] @ Save CPSR | 364 | str r8, [sp, #S_PSR] @ Save CPSR |
362 | str r0, [sp, #S_OLD_R0] @ Save OLD_R0 | 365 | str r0, [sp, #S_OLD_R0] @ Save OLD_R0 |
366 | #endif | ||
363 | zero_fp | 367 | zero_fp |
364 | 368 | ||
365 | /* | 369 | /* |
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 160f3376ba6d..de23a9beed13 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <asm/asm-offsets.h> | 5 | #include <asm/asm-offsets.h> |
6 | #include <asm/errno.h> | 6 | #include <asm/errno.h> |
7 | #include <asm/thread_info.h> | 7 | #include <asm/thread_info.h> |
8 | #include <asm/v7m.h> | ||
8 | 9 | ||
9 | @ Bad Abort numbers | 10 | @ Bad Abort numbers |
10 | @ ----------------- | 11 | @ ----------------- |
@@ -44,6 +45,116 @@ | |||
44 | #endif | 45 | #endif |
45 | .endm | 46 | .endm |
46 | 47 | ||
48 | #ifdef CONFIG_CPU_V7M | ||
49 | /* | ||
50 | * ARMv7-M exception entry/exit macros. | ||
51 | * | ||
52 | * xPSR, ReturnAddress(), LR (R14), R12, R3, R2, R1, and R0 are | ||
53 | * automatically saved on the current stack (32 words) before | ||
54 | * switching to the exception stack (SP_main). | ||
55 | * | ||
56 | * If exception is taken while in user mode, SP_main is | ||
57 | * empty. Otherwise, SP_main is aligned to 64 bit automatically | ||
58 | * (CCR.STKALIGN set). | ||
59 | * | ||
60 | * Linux assumes that the interrupts are disabled when entering an | ||
61 | * exception handler and it may BUG if this is not the case. Interrupts | ||
62 | * are disabled during entry and reenabled in the exit macro. | ||
63 | * | ||
64 | * v7m_exception_slow_exit is used when returning from SVC or PendSV. | ||
65 | * When returning to kernel mode, we don't return from exception. | ||
66 | */ | ||
67 | .macro v7m_exception_entry | ||
68 | @ determine the location of the registers saved by the core during | ||
69 | @ exception entry. Depending on the mode the cpu was in when the | ||
70 | @ exception happend that is either on the main or the process stack. | ||
71 | @ Bit 2 of EXC_RETURN stored in the lr register specifies which stack | ||
72 | @ was used. | ||
73 | tst lr, #EXC_RET_STACK_MASK | ||
74 | mrsne r12, psp | ||
75 | moveq r12, sp | ||
76 | |||
77 | @ we cannot rely on r0-r3 and r12 matching the value saved in the | ||
78 | @ exception frame because of tail-chaining. So these have to be | ||
79 | @ reloaded. | ||
80 | ldmia r12!, {r0-r3} | ||
81 | |||
82 | @ Linux expects to have irqs off. Do it here before taking stack space | ||
83 | cpsid i | ||
84 | |||
85 | sub sp, #S_FRAME_SIZE-S_IP | ||
86 | stmdb sp!, {r0-r11} | ||
87 | |||
88 | @ load saved r12, lr, return address and xPSR. | ||
89 | @ r0-r7 are used for signals and never touched from now on. Clobbering | ||
90 | @ r8-r12 is OK. | ||
91 | mov r9, r12 | ||
92 | ldmia r9!, {r8, r10-r12} | ||
93 | |||
94 | @ calculate the original stack pointer value. | ||
95 | @ r9 currently points to the memory location just above the auto saved | ||
96 | @ xPSR. | ||
97 | @ The cpu might automatically 8-byte align the stack. Bit 9 | ||
98 | @ of the saved xPSR specifies if stack aligning took place. In this case | ||
99 | @ another 32-bit value is included in the stack. | ||
100 | |||
101 | tst r12, V7M_xPSR_FRAMEPTRALIGN | ||
102 | addne r9, r9, #4 | ||
103 | |||
104 | @ store saved r12 using str to have a register to hold the base for stm | ||
105 | str r8, [sp, #S_IP] | ||
106 | add r8, sp, #S_SP | ||
107 | @ store r13-r15, xPSR | ||
108 | stmia r8!, {r9-r12} | ||
109 | @ store old_r0 | ||
110 | str r0, [r8] | ||
111 | .endm | ||
112 | |||
113 | /* | ||
114 | * PENDSV and SVCALL are configured to have the same exception | ||
115 | * priorities. As a kernel thread runs at SVCALL execution priority it | ||
116 | * can never be preempted and so we will never have to return to a | ||
117 | * kernel thread here. | ||
118 | */ | ||
119 | .macro v7m_exception_slow_exit ret_r0 | ||
120 | cpsid i | ||
121 | ldr lr, =EXC_RET_THREADMODE_PROCESSSTACK | ||
122 | |||
123 | @ read original r12, sp, lr, pc and xPSR | ||
124 | add r12, sp, #S_IP | ||
125 | ldmia r12, {r1-r5} | ||
126 | |||
127 | @ an exception frame is always 8-byte aligned. To tell the hardware if | ||
128 | @ the sp to be restored is aligned or not set bit 9 of the saved xPSR | ||
129 | @ accordingly. | ||
130 | tst r2, #4 | ||
131 | subne r2, r2, #4 | ||
132 | orrne r5, V7M_xPSR_FRAMEPTRALIGN | ||
133 | biceq r5, V7M_xPSR_FRAMEPTRALIGN | ||
134 | |||
135 | @ write basic exception frame | ||
136 | stmdb r2!, {r1, r3-r5} | ||
137 | ldmia sp, {r1, r3-r5} | ||
138 | .if \ret_r0 | ||
139 | stmdb r2!, {r0, r3-r5} | ||
140 | .else | ||
141 | stmdb r2!, {r1, r3-r5} | ||
142 | .endif | ||
143 | |||
144 | @ restore process sp | ||
145 | msr psp, r2 | ||
146 | |||
147 | @ restore original r4-r11 | ||
148 | ldmia sp!, {r0-r11} | ||
149 | |||
150 | @ restore main sp | ||
151 | add sp, sp, #S_FRAME_SIZE-S_IP | ||
152 | |||
153 | cpsie i | ||
154 | bx lr | ||
155 | .endm | ||
156 | #endif /* CONFIG_CPU_V7M */ | ||
157 | |||
47 | @ | 158 | @ |
48 | @ Store/load the USER SP and LR registers by switching to the SYS | 159 | @ Store/load the USER SP and LR registers by switching to the SYS |
49 | @ mode. Useful in Thumb-2 mode where "stm/ldm rd, {sp, lr}^" is not | 160 | @ mode. Useful in Thumb-2 mode where "stm/ldm rd, {sp, lr}^" is not |
@@ -165,6 +276,18 @@ | |||
165 | rfeia sp! | 276 | rfeia sp! |
166 | .endm | 277 | .endm |
167 | 278 | ||
279 | #ifdef CONFIG_CPU_V7M | ||
280 | /* | ||
281 | * Note we don't need to do clrex here as clearing the local monitor is | ||
282 | * part of each exception entry and exit sequence. | ||
283 | */ | ||
284 | .macro restore_user_regs, fast = 0, offset = 0 | ||
285 | .if \offset | ||
286 | add sp, #\offset | ||
287 | .endif | ||
288 | v7m_exception_slow_exit ret_r0 = \fast | ||
289 | .endm | ||
290 | #else /* ifdef CONFIG_CPU_V7M */ | ||
168 | .macro restore_user_regs, fast = 0, offset = 0 | 291 | .macro restore_user_regs, fast = 0, offset = 0 |
169 | clrex @ clear the exclusive monitor | 292 | clrex @ clear the exclusive monitor |
170 | mov r2, sp | 293 | mov r2, sp |
@@ -181,6 +304,7 @@ | |||
181 | add sp, sp, #S_FRAME_SIZE - S_SP | 304 | add sp, sp, #S_FRAME_SIZE - S_SP |
182 | movs pc, lr @ return & move spsr_svc into cpsr | 305 | movs pc, lr @ return & move spsr_svc into cpsr |
183 | .endm | 306 | .endm |
307 | #endif /* ifdef CONFIG_CPU_V7M / else */ | ||
184 | 308 | ||
185 | .macro get_thread_info, rd | 309 | .macro get_thread_info, rd |
186 | mov \rd, sp | 310 | mov \rd, sp |
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S new file mode 100644 index 000000000000..e00621f1403f --- /dev/null +++ b/arch/arm/kernel/entry-v7m.S | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/entry-v7m.S | ||
3 | * | ||
4 | * Copyright (C) 2008 ARM Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Low-level vector interface routines for the ARMv7-M architecture | ||
11 | */ | ||
12 | #include <asm/memory.h> | ||
13 | #include <asm/glue.h> | ||
14 | #include <asm/thread_notify.h> | ||
15 | #include <asm/v7m.h> | ||
16 | |||
17 | #include <mach/entry-macro.S> | ||
18 | |||
19 | #include "entry-header.S" | ||
20 | |||
21 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
22 | #error "CONFIG_TRACE_IRQFLAGS not supported on the current ARMv7M implementation" | ||
23 | #endif | ||
24 | |||
25 | __invalid_entry: | ||
26 | v7m_exception_entry | ||
27 | adr r0, strerr | ||
28 | mrs r1, ipsr | ||
29 | mov r2, lr | ||
30 | bl printk | ||
31 | mov r0, sp | ||
32 | bl show_regs | ||
33 | 1: b 1b | ||
34 | ENDPROC(__invalid_entry) | ||
35 | |||
36 | strerr: .asciz "\nUnhandled exception: IPSR = %08lx LR = %08lx\n" | ||
37 | |||
38 | .align 2 | ||
39 | __irq_entry: | ||
40 | v7m_exception_entry | ||
41 | |||
42 | @ | ||
43 | @ Invoke the IRQ handler | ||
44 | @ | ||
45 | mrs r0, ipsr | ||
46 | ldr r1, =V7M_xPSR_EXCEPTIONNO | ||
47 | and r0, r1 | ||
48 | sub r0, #16 | ||
49 | mov r1, sp | ||
50 | stmdb sp!, {lr} | ||
51 | @ routine called with r0 = irq number, r1 = struct pt_regs * | ||
52 | bl nvic_do_IRQ | ||
53 | |||
54 | pop {lr} | ||
55 | @ | ||
56 | @ Check for any pending work if returning to user | ||
57 | @ | ||
58 | ldr r1, =BASEADDR_V7M_SCB | ||
59 | ldr r0, [r1, V7M_SCB_ICSR] | ||
60 | tst r0, V7M_SCB_ICSR_RETTOBASE | ||
61 | beq 2f | ||
62 | |||
63 | get_thread_info tsk | ||
64 | ldr r2, [tsk, #TI_FLAGS] | ||
65 | tst r2, #_TIF_WORK_MASK | ||
66 | beq 2f @ no work pending | ||
67 | mov r0, #V7M_SCB_ICSR_PENDSVSET | ||
68 | str r0, [r1, V7M_SCB_ICSR] @ raise PendSV | ||
69 | |||
70 | 2: | ||
71 | @ registers r0-r3 and r12 are automatically restored on exception | ||
72 | @ return. r4-r7 were not clobbered in v7m_exception_entry so for | ||
73 | @ correctness they don't need to be restored. So only r8-r11 must be | ||
74 | @ restored here. The easiest way to do so is to restore r0-r7, too. | ||
75 | ldmia sp!, {r0-r11} | ||
76 | add sp, #S_FRAME_SIZE-S_IP | ||
77 | cpsie i | ||
78 | bx lr | ||
79 | ENDPROC(__irq_entry) | ||
80 | |||
81 | __pendsv_entry: | ||
82 | v7m_exception_entry | ||
83 | |||
84 | ldr r1, =BASEADDR_V7M_SCB | ||
85 | mov r0, #V7M_SCB_ICSR_PENDSVCLR | ||
86 | str r0, [r1, V7M_SCB_ICSR] @ clear PendSV | ||
87 | |||
88 | @ execute the pending work, including reschedule | ||
89 | get_thread_info tsk | ||
90 | mov why, #0 | ||
91 | b ret_to_user | ||
92 | ENDPROC(__pendsv_entry) | ||
93 | |||
94 | /* | ||
95 | * Register switch for ARMv7-M processors. | ||
96 | * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info | ||
97 | * previous and next are guaranteed not to be the same. | ||
98 | */ | ||
99 | ENTRY(__switch_to) | ||
100 | .fnstart | ||
101 | .cantunwind | ||
102 | add ip, r1, #TI_CPU_SAVE | ||
103 | stmia ip!, {r4 - r11} @ Store most regs on stack | ||
104 | str sp, [ip], #4 | ||
105 | str lr, [ip], #4 | ||
106 | mov r5, r0 | ||
107 | add r4, r2, #TI_CPU_SAVE | ||
108 | ldr r0, =thread_notify_head | ||
109 | mov r1, #THREAD_NOTIFY_SWITCH | ||
110 | bl atomic_notifier_call_chain | ||
111 | mov ip, r4 | ||
112 | mov r0, r5 | ||
113 | ldmia ip!, {r4 - r11} @ Load all regs saved previously | ||
114 | ldr sp, [ip] | ||
115 | ldr pc, [ip, #4]! | ||
116 | .fnend | ||
117 | ENDPROC(__switch_to) | ||
118 | |||
119 | .data | ||
120 | .align 8 | ||
121 | /* | ||
122 | * Vector table (64 words => 256 bytes natural alignment) | ||
123 | */ | ||
124 | ENTRY(vector_table) | ||
125 | .long 0 @ 0 - Reset stack pointer | ||
126 | .long __invalid_entry @ 1 - Reset | ||
127 | .long __invalid_entry @ 2 - NMI | ||
128 | .long __invalid_entry @ 3 - HardFault | ||
129 | .long __invalid_entry @ 4 - MemManage | ||
130 | .long __invalid_entry @ 5 - BusFault | ||
131 | .long __invalid_entry @ 6 - UsageFault | ||
132 | .long __invalid_entry @ 7 - Reserved | ||
133 | .long __invalid_entry @ 8 - Reserved | ||
134 | .long __invalid_entry @ 9 - Reserved | ||
135 | .long __invalid_entry @ 10 - Reserved | ||
136 | .long vector_swi @ 11 - SVCall | ||
137 | .long __invalid_entry @ 12 - Debug Monitor | ||
138 | .long __invalid_entry @ 13 - Reserved | ||
139 | .long __pendsv_entry @ 14 - PendSV | ||
140 | .long __invalid_entry @ 15 - SysTick | ||
141 | .rept 64 - 16 | ||
142 | .long __irq_entry @ 16..64 - External Interrupts | ||
143 | .endr | ||
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index 6a2e09c952c7..8812ce88f7a1 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <asm/asm-offsets.h> | 19 | #include <asm/asm-offsets.h> |
20 | #include <asm/cp15.h> | 20 | #include <asm/cp15.h> |
21 | #include <asm/thread_info.h> | 21 | #include <asm/thread_info.h> |
22 | #include <asm/v7m.h> | ||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * Kernel startup entry point. | 25 | * Kernel startup entry point. |
@@ -50,10 +51,13 @@ ENTRY(stext) | |||
50 | 51 | ||
51 | setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode | 52 | setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode |
52 | @ and irqs disabled | 53 | @ and irqs disabled |
53 | #ifndef CONFIG_CPU_CP15 | 54 | #if defined(CONFIG_CPU_CP15) |
54 | ldr r9, =CONFIG_PROCESSOR_ID | ||
55 | #else | ||
56 | mrc p15, 0, r9, c0, c0 @ get processor id | 55 | mrc p15, 0, r9, c0, c0 @ get processor id |
56 | #elif defined(CONFIG_CPU_V7M) | ||
57 | ldr r9, =BASEADDR_V7M_SCB | ||
58 | ldr r9, [r9, V7M_SCB_CPUID] | ||
59 | #else | ||
60 | ldr r9, =CONFIG_PROCESSOR_ID | ||
57 | #endif | 61 | #endif |
58 | bl __lookup_processor_type @ r5=procinfo r9=cpuid | 62 | bl __lookup_processor_type @ r5=procinfo r9=cpuid |
59 | movs r10, r5 @ invalid processor (r5=0)? | 63 | movs r10, r5 @ invalid processor (r5=0)? |
diff --git a/arch/arm/kernel/psci.c b/arch/arm/kernel/psci.c index 36531643cc2c..46931880093d 100644 --- a/arch/arm/kernel/psci.c +++ b/arch/arm/kernel/psci.c | |||
@@ -158,7 +158,7 @@ static const struct of_device_id psci_of_match[] __initconst = { | |||
158 | {}, | 158 | {}, |
159 | }; | 159 | }; |
160 | 160 | ||
161 | static int __init psci_init(void) | 161 | void __init psci_init(void) |
162 | { | 162 | { |
163 | struct device_node *np; | 163 | struct device_node *np; |
164 | const char *method; | 164 | const char *method; |
@@ -166,7 +166,7 @@ static int __init psci_init(void) | |||
166 | 166 | ||
167 | np = of_find_matching_node(NULL, psci_of_match); | 167 | np = of_find_matching_node(NULL, psci_of_match); |
168 | if (!np) | 168 | if (!np) |
169 | return 0; | 169 | return; |
170 | 170 | ||
171 | pr_info("probing function IDs from device-tree\n"); | 171 | pr_info("probing function IDs from device-tree\n"); |
172 | 172 | ||
@@ -206,6 +206,5 @@ static int __init psci_init(void) | |||
206 | 206 | ||
207 | out_put_node: | 207 | out_put_node: |
208 | of_node_put(np); | 208 | of_node_put(np); |
209 | return 0; | 209 | return; |
210 | } | 210 | } |
211 | early_initcall(psci_init); | ||
diff --git a/arch/arm/kernel/psci_smp.c b/arch/arm/kernel/psci_smp.c new file mode 100644 index 000000000000..23a11424c568 --- /dev/null +++ b/arch/arm/kernel/psci_smp.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * Copyright (C) 2012 ARM Limited | ||
12 | * | ||
13 | * Author: Will Deacon <will.deacon@arm.com> | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/irqchip/arm-gic.h> | ||
18 | #include <linux/smp.h> | ||
19 | #include <linux/of.h> | ||
20 | |||
21 | #include <asm/psci.h> | ||
22 | #include <asm/smp_plat.h> | ||
23 | |||
24 | /* | ||
25 | * psci_smp assumes that the following is true about PSCI: | ||
26 | * | ||
27 | * cpu_suspend Suspend the execution on a CPU | ||
28 | * @state we don't currently describe affinity levels, so just pass 0. | ||
29 | * @entry_point the first instruction to be executed on return | ||
30 | * returns 0 success, < 0 on failure | ||
31 | * | ||
32 | * cpu_off Power down a CPU | ||
33 | * @state we don't currently describe affinity levels, so just pass 0. | ||
34 | * no return on successful call | ||
35 | * | ||
36 | * cpu_on Power up a CPU | ||
37 | * @cpuid cpuid of target CPU, as from MPIDR | ||
38 | * @entry_point the first instruction to be executed on return | ||
39 | * returns 0 success, < 0 on failure | ||
40 | * | ||
41 | * migrate Migrate the context to a different CPU | ||
42 | * @cpuid cpuid of target CPU, as from MPIDR | ||
43 | * returns 0 success, < 0 on failure | ||
44 | * | ||
45 | */ | ||
46 | |||
47 | extern void secondary_startup(void); | ||
48 | |||
49 | static int __cpuinit psci_boot_secondary(unsigned int cpu, | ||
50 | struct task_struct *idle) | ||
51 | { | ||
52 | if (psci_ops.cpu_on) | ||
53 | return psci_ops.cpu_on(cpu_logical_map(cpu), | ||
54 | __pa(secondary_startup)); | ||
55 | return -ENODEV; | ||
56 | } | ||
57 | |||
58 | #ifdef CONFIG_HOTPLUG_CPU | ||
59 | void __ref psci_cpu_die(unsigned int cpu) | ||
60 | { | ||
61 | const struct psci_power_state ps = { | ||
62 | .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, | ||
63 | }; | ||
64 | |||
65 | if (psci_ops.cpu_off) | ||
66 | psci_ops.cpu_off(ps); | ||
67 | |||
68 | /* We should never return */ | ||
69 | panic("psci: cpu %d failed to shutdown\n", cpu); | ||
70 | } | ||
71 | #else | ||
72 | #define psci_cpu_die NULL | ||
73 | #endif | ||
74 | |||
75 | bool __init psci_smp_available(void) | ||
76 | { | ||
77 | /* is cpu_on available at least? */ | ||
78 | return (psci_ops.cpu_on != NULL); | ||
79 | } | ||
80 | |||
81 | struct smp_operations __initdata psci_smp_ops = { | ||
82 | .smp_boot_secondary = psci_boot_secondary, | ||
83 | .cpu_die = psci_cpu_die, | ||
84 | }; | ||
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 1522c7ae31b0..a1a2fbaaa31c 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <asm/cputype.h> | 37 | #include <asm/cputype.h> |
38 | #include <asm/elf.h> | 38 | #include <asm/elf.h> |
39 | #include <asm/procinfo.h> | 39 | #include <asm/procinfo.h> |
40 | #include <asm/psci.h> | ||
40 | #include <asm/sections.h> | 41 | #include <asm/sections.h> |
41 | #include <asm/setup.h> | 42 | #include <asm/setup.h> |
42 | #include <asm/smp_plat.h> | 43 | #include <asm/smp_plat.h> |
@@ -128,7 +129,9 @@ struct stack { | |||
128 | u32 und[3]; | 129 | u32 und[3]; |
129 | } ____cacheline_aligned; | 130 | } ____cacheline_aligned; |
130 | 131 | ||
132 | #ifndef CONFIG_CPU_V7M | ||
131 | static struct stack stacks[NR_CPUS]; | 133 | static struct stack stacks[NR_CPUS]; |
134 | #endif | ||
132 | 135 | ||
133 | char elf_platform[ELF_PLATFORM_SIZE]; | 136 | char elf_platform[ELF_PLATFORM_SIZE]; |
134 | EXPORT_SYMBOL(elf_platform); | 137 | EXPORT_SYMBOL(elf_platform); |
@@ -207,7 +210,7 @@ static const char *proc_arch[] = { | |||
207 | "5TEJ", | 210 | "5TEJ", |
208 | "6TEJ", | 211 | "6TEJ", |
209 | "7", | 212 | "7", |
210 | "?(11)", | 213 | "7M", |
211 | "?(12)", | 214 | "?(12)", |
212 | "?(13)", | 215 | "?(13)", |
213 | "?(14)", | 216 | "?(14)", |
@@ -216,6 +219,12 @@ static const char *proc_arch[] = { | |||
216 | "?(17)", | 219 | "?(17)", |
217 | }; | 220 | }; |
218 | 221 | ||
222 | #ifdef CONFIG_CPU_V7M | ||
223 | static int __get_cpu_architecture(void) | ||
224 | { | ||
225 | return CPU_ARCH_ARMv7M; | ||
226 | } | ||
227 | #else | ||
219 | static int __get_cpu_architecture(void) | 228 | static int __get_cpu_architecture(void) |
220 | { | 229 | { |
221 | int cpu_arch; | 230 | int cpu_arch; |
@@ -248,6 +257,7 @@ static int __get_cpu_architecture(void) | |||
248 | 257 | ||
249 | return cpu_arch; | 258 | return cpu_arch; |
250 | } | 259 | } |
260 | #endif | ||
251 | 261 | ||
252 | int __pure cpu_architecture(void) | 262 | int __pure cpu_architecture(void) |
253 | { | 263 | { |
@@ -293,7 +303,9 @@ static void __init cacheid_init(void) | |||
293 | { | 303 | { |
294 | unsigned int arch = cpu_architecture(); | 304 | unsigned int arch = cpu_architecture(); |
295 | 305 | ||
296 | if (arch >= CPU_ARCH_ARMv6) { | 306 | if (arch == CPU_ARCH_ARMv7M) { |
307 | cacheid = 0; | ||
308 | } else if (arch >= CPU_ARCH_ARMv6) { | ||
297 | unsigned int cachetype = read_cpuid_cachetype(); | 309 | unsigned int cachetype = read_cpuid_cachetype(); |
298 | if ((cachetype & (7 << 29)) == 4 << 29) { | 310 | if ((cachetype & (7 << 29)) == 4 << 29) { |
299 | /* ARMv7 register format */ | 311 | /* ARMv7 register format */ |
@@ -392,6 +404,7 @@ static void __init feat_v6_fixup(void) | |||
392 | */ | 404 | */ |
393 | void notrace cpu_init(void) | 405 | void notrace cpu_init(void) |
394 | { | 406 | { |
407 | #ifndef CONFIG_CPU_V7M | ||
395 | unsigned int cpu = smp_processor_id(); | 408 | unsigned int cpu = smp_processor_id(); |
396 | struct stack *stk = &stacks[cpu]; | 409 | struct stack *stk = &stacks[cpu]; |
397 | 410 | ||
@@ -442,6 +455,7 @@ void notrace cpu_init(void) | |||
442 | "I" (offsetof(struct stack, und[0])), | 455 | "I" (offsetof(struct stack, und[0])), |
443 | PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE) | 456 | PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE) |
444 | : "r14"); | 457 | : "r14"); |
458 | #endif | ||
445 | } | 459 | } |
446 | 460 | ||
447 | int __cpu_logical_map[NR_CPUS]; | 461 | int __cpu_logical_map[NR_CPUS]; |
@@ -796,9 +810,15 @@ void __init setup_arch(char **cmdline_p) | |||
796 | unflatten_device_tree(); | 810 | unflatten_device_tree(); |
797 | 811 | ||
798 | arm_dt_init_cpu_maps(); | 812 | arm_dt_init_cpu_maps(); |
813 | psci_init(); | ||
799 | #ifdef CONFIG_SMP | 814 | #ifdef CONFIG_SMP |
800 | if (is_smp()) { | 815 | if (is_smp()) { |
801 | smp_set_ops(mdesc->smp); | 816 | if (!mdesc->smp_init || !mdesc->smp_init()) { |
817 | if (psci_smp_available()) | ||
818 | smp_set_ops(&psci_smp_ops); | ||
819 | else if (mdesc->smp) | ||
820 | smp_set_ops(mdesc->smp); | ||
821 | } | ||
802 | smp_init_cpus(); | 822 | smp_init_cpus(); |
803 | } | 823 | } |
804 | #endif | 824 | #endif |
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index f10316b4ecdc..c5a59546a256 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/cpu.h> | 14 | #include <linux/cpu.h> |
15 | #include <linux/cpumask.h> | 15 | #include <linux/cpumask.h> |
16 | #include <linux/export.h> | ||
16 | #include <linux/init.h> | 17 | #include <linux/init.h> |
17 | #include <linux/percpu.h> | 18 | #include <linux/percpu.h> |
18 | #include <linux/node.h> | 19 | #include <linux/node.h> |
@@ -200,6 +201,7 @@ static inline void update_cpu_power(unsigned int cpuid, unsigned int mpidr) {} | |||
200 | * cpu topology table | 201 | * cpu topology table |
201 | */ | 202 | */ |
202 | struct cputopo_arm cpu_topology[NR_CPUS]; | 203 | struct cputopo_arm cpu_topology[NR_CPUS]; |
204 | EXPORT_SYMBOL_GPL(cpu_topology); | ||
203 | 205 | ||
204 | const struct cpumask *cpu_coregroup_mask(int cpu) | 206 | const struct cpumask *cpu_coregroup_mask(int cpu) |
205 | { | 207 | { |
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 18b32e8e4497..486e12a0f26a 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -812,6 +812,7 @@ static void __init kuser_get_tls_init(unsigned long vectors) | |||
812 | 812 | ||
813 | void __init early_trap_init(void *vectors_base) | 813 | void __init early_trap_init(void *vectors_base) |
814 | { | 814 | { |
815 | #ifndef CONFIG_CPU_V7M | ||
815 | unsigned long vectors = (unsigned long)vectors_base; | 816 | unsigned long vectors = (unsigned long)vectors_base; |
816 | extern char __stubs_start[], __stubs_end[]; | 817 | extern char __stubs_start[], __stubs_end[]; |
817 | extern char __vectors_start[], __vectors_end[]; | 818 | extern char __vectors_start[], __vectors_end[]; |
@@ -843,4 +844,11 @@ void __init early_trap_init(void *vectors_base) | |||
843 | 844 | ||
844 | flush_icache_range(vectors, vectors + PAGE_SIZE); | 845 | flush_icache_range(vectors, vectors + PAGE_SIZE); |
845 | modify_domain(DOMAIN_USER, DOMAIN_CLIENT); | 846 | modify_domain(DOMAIN_USER, DOMAIN_CLIENT); |
847 | #else /* ifndef CONFIG_CPU_V7M */ | ||
848 | /* | ||
849 | * on V7-M there is no need to copy the vector table to a dedicated | ||
850 | * memory area. The address is configurable and so a table in the kernel | ||
851 | * image can be used. | ||
852 | */ | ||
853 | #endif | ||
846 | } | 854 | } |