From 9a00318eadbb43db4e9c163c262a22a3c8b5a672 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Thu, 16 Jun 2011 12:09:37 +0100 Subject: ARM: 6963/1: Thumb-2: Relax relocation requirements for non-function symbols The "Thumb bit" of a symbol is only really meaningful for function symbols (STT_FUNC). However, sometimes a branch is relocated against a non-function symbol; for example, PC-relative branches to anonymous assembler local symbols are typically fixed up against the start-of-section symbol, which is not a function symbol. Some inline assembler generates references of this type, such as fixup code generated by macros in . The existing relocation code for R_ARM_THM_CALL/R_ARM_THM_JUMP24 interprets this case as an error, because the target symbol appears to be an ARM symbol; but this is really not the case, since the target symbol is just a base in these cases. The addend defines the precise offset to the target location, but since the addend is encoded in a non-interworking Thumb branch instruction, there is no explicit Thumb bit in the addend. Because these instructions never interwork, the implied Thumb bit in the addend is 1, and the destination is Thumb by definition. This patch removes the extraneous Thumb bit check for non-function symbols, enabling modules containing the affected relocation types to be loaded. No modification to the actual relocation code is required, since this code does not take bit[0] of the location->destination offset into account in any case. Function symbols are always checked for interworking conflicts, as before. Signed-off-by: Dave Martin Acked-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/kernel/module.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index fee7c36349eb..016d6a0830a3 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -193,8 +193,17 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, offset -= 0x02000000; offset += sym->st_value - loc; - /* only Thumb addresses allowed (no interworking) */ - if (!(offset & 1) || + /* + * For function symbols, only Thumb addresses are + * allowed (no interworking). + * + * For non-function symbols, the destination + * has no specific ARM/Thumb disposition, so + * the branch is resolved under the assumption + * that interworking is not required. + */ + if ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC && + !(offset & 1)) || offset <= (s32)0xff000000 || offset >= (s32)0x01000000) { pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", -- cgit v1.2.3 From 573619d165b85152eeddd3b3871002c48cd94e42 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Jun 2011 16:46:01 +0100 Subject: ARM: SMP: wait for CPU to be marked active When we bring a CPU online, we should wait for it to become active before entering the idle thread, so we know that the scheduler and thread migration is going to work. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 344e52b16c8c..e7f92a4321f3 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -318,9 +318,13 @@ asmlinkage void __cpuinit secondary_start_kernel(void) smp_store_cpu_info(cpu); /* - * OK, now it's safe to let the boot CPU continue + * OK, now it's safe to let the boot CPU continue. Wait for + * the CPU migration code to notice that the CPU is online + * before we continue. */ set_cpu_online(cpu, true); + while (!cpu_active(cpu)) + cpu_relax(); /* * OK, it's off to the idle thread for us -- cgit v1.2.3 From b69874e4f530b0103e507f695c010d00cb85a4df Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 21 Jun 2011 18:57:31 +0100 Subject: ARM: pm: arrange for cpu_proc_init() to be called on resume cpu_proc_init() does processor specific initialization, which we do at boot time. We have been omitting to do this on resume, which causes some of this initialization to be skipped. We've also been skipping this on SMP initialization too. Ensure that cpu_proc_init() is always called appropriately by moving it into cpu_init(), and move cpu_init() to a more appropriate point in the boot initialization. Tested-by: Kevin Hilman Acked-by: Jean Pihet Signed-off-by: Russell King --- arch/arm/kernel/setup.c | 99 ++++++++++++++++++++++++----------------------- arch/arm/mm/proc-sa1100.S | 4 +- 2 files changed, 51 insertions(+), 52 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index ed11fb08b05a..edcab02be64c 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -342,54 +342,6 @@ static void __init feat_v6_fixup(void) elf_hwcap &= ~HWCAP_TLS; } -static void __init setup_processor(void) -{ - struct proc_info_list *list; - - /* - * locate processor in the list of supported processor - * types. The linker builds this table for us from the - * entries in arch/arm/mm/proc-*.S - */ - list = lookup_processor_type(read_cpuid_id()); - if (!list) { - printk("CPU configuration botched (ID %08x), unable " - "to continue.\n", read_cpuid_id()); - while (1); - } - - cpu_name = list->cpu_name; - -#ifdef MULTI_CPU - processor = *list->proc; -#endif -#ifdef MULTI_TLB - cpu_tlb = *list->tlb; -#endif -#ifdef MULTI_USER - cpu_user = *list->user; -#endif -#ifdef MULTI_CACHE - cpu_cache = *list->cache; -#endif - - printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", - cpu_name, read_cpuid_id(), read_cpuid_id() & 15, - proc_arch[cpu_architecture()], cr_alignment); - - sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); - sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); - elf_hwcap = list->elf_hwcap; -#ifndef CONFIG_ARM_THUMB - elf_hwcap &= ~HWCAP_THUMB; -#endif - - feat_v6_fixup(); - - cacheid_init(); - cpu_proc_init(); -} - /* * cpu_init - initialise one CPU. * @@ -405,6 +357,8 @@ void cpu_init(void) BUG(); } + cpu_proc_init(); + /* * Define the placement constraint for the inline asm directive below. * In Thumb-2, msr with an immediate value is not allowed. @@ -441,6 +395,54 @@ void cpu_init(void) : "r14"); } +static void __init setup_processor(void) +{ + struct proc_info_list *list; + + /* + * locate processor in the list of supported processor + * types. The linker builds this table for us from the + * entries in arch/arm/mm/proc-*.S + */ + list = lookup_processor_type(read_cpuid_id()); + if (!list) { + printk("CPU configuration botched (ID %08x), unable " + "to continue.\n", read_cpuid_id()); + while (1); + } + + cpu_name = list->cpu_name; + +#ifdef MULTI_CPU + processor = *list->proc; +#endif +#ifdef MULTI_TLB + cpu_tlb = *list->tlb; +#endif +#ifdef MULTI_USER + cpu_user = *list->user; +#endif +#ifdef MULTI_CACHE + cpu_cache = *list->cache; +#endif + + printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", + cpu_name, read_cpuid_id(), read_cpuid_id() & 15, + proc_arch[cpu_architecture()], cr_alignment); + + sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); + sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); + elf_hwcap = list->elf_hwcap; +#ifndef CONFIG_ARM_THUMB + elf_hwcap &= ~HWCAP_THUMB; +#endif + + feat_v6_fixup(); + + cacheid_init(); + cpu_init(); +} + void __init dump_machine_table(void) { struct machine_desc *p; @@ -913,7 +915,6 @@ void __init setup_arch(char **cmdline_p) #endif reserve_crashkernel(); - cpu_init(); tcm_init(); #ifdef CONFIG_MULTI_IRQ_HANDLER diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S index 184a9c997e36..e9c47271732d 100644 --- a/arch/arm/mm/proc-sa1100.S +++ b/arch/arm/mm/proc-sa1100.S @@ -34,7 +34,7 @@ */ #define DCACHELINESIZE 32 - __INIT + .section .text /* * cpu_sa1100_proc_init() @@ -45,8 +45,6 @@ ENTRY(cpu_sa1100_proc_init) mcr p15, 0, r0, c9, c0, 5 @ Allow read-buffer operations from userland mov pc, lr - .section .text - /* * cpu_sa1100_proc_fin() * -- cgit v1.2.3 From 6b5f6ab0e1c33beaed828271f13c03ed02ee3c15 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 13 Jun 2011 13:39:44 +0100 Subject: ARM: pm: make MULTI_CPU and !MULTI_CPU resume paths the same Eliminate the differences between MULTI_CPU and non-MULTI_CPU resume paths, making the saved structure identical irrespective of the way the kernel was configured. Acked-by: Frank Hofmann Tested-by: Kevin Hilman Acked-by: Jean Pihet Signed-off-by: Russell King --- arch/arm/kernel/sleep.S | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 6398ead9d1c0..97a6577aa61e 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -40,9 +40,11 @@ ENTRY(cpu_suspend) #else mov r2, sp @ current virtual SP ldr r0, =cpu_suspend_size + ldr ip, =cpu_do_resume sub sp, sp, r0 @ allocate CPU state on stack mov r0, sp @ save pointer - stmfd sp!, {r1, r2, r3} @ save v:p, virt SP, return fn + add ip, ip, r1 @ convert resume fn to phys + stmfd sp!, {r1, r2, r3, ip} @ save v:p, virt SP, retfn, phys resume fn ldr r3, =sleep_save_sp add r2, sp, r1 @ convert SP to phys #ifdef CONFIG_SMP @@ -120,20 +122,12 @@ ENTRY(cpu_resume) ldr r0, sleep_save_sp @ stack phys addr #endif setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off -#ifdef MULTI_CPU @ load v:p, stack, return fn, resume fn ARM( ldmia r0!, {r1, sp, lr, pc} ) THUMB( ldmia r0!, {r1, r2, r3, r4} ) THUMB( mov sp, r2 ) THUMB( mov lr, r3 ) THUMB( bx r4 ) -#else - @ load v:p, stack, return fn - ARM( ldmia r0!, {r1, sp, lr} ) -THUMB( ldmia r0!, {r1, r2, lr} ) -THUMB( mov sp, r2 ) - b cpu_do_resume -#endif ENDPROC(cpu_resume) sleep_save_sp: -- cgit v1.2.3 From 2fefbcd58590cf33189c6178098e12b31b994b5f Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 13 Jun 2011 13:45:34 +0100 Subject: ARM: pm: move return address (for cpu_resume) to top of stack Move the return address for cpu_resume to the top of stack so that cpu_resume looks more like a normal function. Acked-by: Frank Hofmann Tested-by: Kevin Hilman Acked-by: Jean Pihet Signed-off-by: Russell King --- arch/arm/kernel/sleep.S | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 97a6577aa61e..f8e92513c1bd 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -15,6 +15,7 @@ * r0-r3,r9,r10,lr corrupted */ ENTRY(cpu_suspend) + stmfd sp!, {r3} mov r9, lr #ifdef MULTI_CPU ldr r10, =processor @@ -24,7 +25,7 @@ ENTRY(cpu_suspend) sub sp, sp, r0 @ allocate CPU state on stack mov r0, sp @ save pointer add ip, ip, r1 @ convert resume fn to phys - stmfd sp!, {r1, r2, r3, ip} @ save v:p, virt SP, retfn, phys resume fn + stmfd sp!, {r1, r2, ip} @ save v:p, virt SP, phys resume fn ldr r3, =sleep_save_sp add r2, sp, r1 @ convert SP to phys #ifdef CONFIG_SMP @@ -44,7 +45,7 @@ ENTRY(cpu_suspend) sub sp, sp, r0 @ allocate CPU state on stack mov r0, sp @ save pointer add ip, ip, r1 @ convert resume fn to phys - stmfd sp!, {r1, r2, r3, ip} @ save v:p, virt SP, retfn, phys resume fn + stmfd sp!, {r1, r2, ip} @ save v:p, virt SP, phys resume fn ldr r3, =sleep_save_sp add r2, sp, r1 @ convert SP to phys #ifdef CONFIG_SMP @@ -99,7 +100,7 @@ ENDPROC(cpu_resume_turn_mmu_on) cpu_resume_after_mmu: str r5, [r2, r4, lsl #2] @ restore old mapping mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache - mov pc, lr + ldmfd sp!, {pc} ENDPROC(cpu_resume_after_mmu) /* @@ -122,12 +123,11 @@ ENTRY(cpu_resume) ldr r0, sleep_save_sp @ stack phys addr #endif setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off - @ load v:p, stack, return fn, resume fn - ARM( ldmia r0!, {r1, sp, lr, pc} ) -THUMB( ldmia r0!, {r1, r2, r3, r4} ) + @ load v:p, stack, resume fn + ARM( ldmia r0!, {r1, sp, pc} ) +THUMB( ldmia r0!, {r1, r2, r3} ) THUMB( mov sp, r2 ) -THUMB( mov lr, r3 ) -THUMB( bx r4 ) +THUMB( bx r3 ) ENDPROC(cpu_resume) sleep_save_sp: -- cgit v1.2.3 From 3fd431bd0cbc75a506b90b42619de3b04fe813a7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 13 Jun 2011 13:53:06 +0100 Subject: ARM: pm: extract common code from MULTI_CPU/!MULTI_CPU paths Very little code is different between these two paths now, so extract the common code. Acked-by: Frank Hofmann Tested-by: Kevin Hilman Acked-by: Jean Pihet Signed-off-by: Russell King --- arch/arm/kernel/sleep.S | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index f8e92513c1bd..0a778c30859b 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -19,29 +19,13 @@ ENTRY(cpu_suspend) mov r9, lr #ifdef MULTI_CPU ldr r10, =processor - mov r2, sp @ current virtual SP ldr r0, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function - sub sp, sp, r0 @ allocate CPU state on stack - mov r0, sp @ save pointer - add ip, ip, r1 @ convert resume fn to phys - stmfd sp!, {r1, r2, ip} @ save v:p, virt SP, phys resume fn - ldr r3, =sleep_save_sp - add r2, sp, r1 @ convert SP to phys -#ifdef CONFIG_SMP - ALT_SMP(mrc p15, 0, lr, c0, c0, 5) - ALT_UP(mov lr, #0) - and lr, lr, #15 - str r2, [r3, lr, lsl #2] @ save phys SP #else - str r2, [r3] @ save phys SP -#endif - mov lr, pc - ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state -#else - mov r2, sp @ current virtual SP ldr r0, =cpu_suspend_size ldr ip, =cpu_do_resume +#endif + mov r2, sp @ current virtual SP sub sp, sp, r0 @ allocate CPU state on stack mov r0, sp @ save pointer add ip, ip, r1 @ convert resume fn to phys @@ -56,6 +40,10 @@ ENTRY(cpu_suspend) #else str r2, [r3] @ save phys SP #endif +#ifdef MULTI_CPU + mov lr, pc + ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state +#else bl cpu_do_suspend #endif -- cgit v1.2.3 From 5fa94c812c0001ac7c3d8868e956ec514734a352 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 13 Jun 2011 15:04:14 +0100 Subject: ARM: pm: preserve r4 - r11 across a suspend Make cpu_suspend()..return function preserve r4 to r11 across a suspend cycle. This is in preparation of relieving platform support code from this task. Acked-by: Frank Hofmann Tested-by: Kevin Hilman Acked-by: Jean Pihet Signed-off-by: Russell King --- arch/arm/kernel/sleep.S | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 0a778c30859b..8dbca93417ff 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -12,10 +12,11 @@ * r1 = v:p offset * r3 = virtual return function * Note: sp is decremented to allocate space for CPU state on stack - * r0-r3,r9,r10,lr corrupted + * r0-r3,ip,lr corrupted */ ENTRY(cpu_suspend) stmfd sp!, {r3} + stmfd sp!, {r4 - r11} mov r9, lr #ifdef MULTI_CPU ldr r10, =processor @@ -88,7 +89,7 @@ ENDPROC(cpu_resume_turn_mmu_on) cpu_resume_after_mmu: str r5, [r2, r4, lsl #2] @ restore old mapping mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache - ldmfd sp!, {pc} + ldmfd sp!, {r4 - r11, pc} ENDPROC(cpu_resume_after_mmu) /* -- cgit v1.2.3 From 8111eaa6d424ab3ba8a4d7a3148d4681ae5c6ae3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 13 Jun 2011 15:25:11 +0100 Subject: ARM: pm: reallocate registers to avoid r2, r3 Avoid using r2 and r3 in the suspend code, allowing these to be passed further into the function as arguments. Acked-by: Frank Hofmann Tested-by: Kevin Hilman Acked-by: Jean Pihet Signed-off-by: Russell King --- arch/arm/kernel/sleep.S | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 8dbca93417ff..358be13499da 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -20,26 +20,26 @@ ENTRY(cpu_suspend) mov r9, lr #ifdef MULTI_CPU ldr r10, =processor - ldr r0, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state + ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function #else - ldr r0, =cpu_suspend_size + ldr r5, =cpu_suspend_size ldr ip, =cpu_do_resume #endif - mov r2, sp @ current virtual SP - sub sp, sp, r0 @ allocate CPU state on stack + mov r6, sp @ current virtual SP + sub sp, sp, r5 @ allocate CPU state on stack mov r0, sp @ save pointer add ip, ip, r1 @ convert resume fn to phys - stmfd sp!, {r1, r2, ip} @ save v:p, virt SP, phys resume fn - ldr r3, =sleep_save_sp - add r2, sp, r1 @ convert SP to phys + stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn + ldr r5, =sleep_save_sp + add r6, sp, r1 @ convert SP to phys #ifdef CONFIG_SMP ALT_SMP(mrc p15, 0, lr, c0, c0, 5) ALT_UP(mov lr, #0) and lr, lr, #15 - str r2, [r3, lr, lsl #2] @ save phys SP + str r6, [r5, lr, lsl #2] @ save phys SP #else - str r2, [r3] @ save phys SP + str r6, [r5] @ save phys SP #endif #ifdef MULTI_CPU mov lr, pc -- cgit v1.2.3 From 3799bbe57843d279008c9ec3406838966cad5f15 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 13 Jun 2011 15:28:40 +0100 Subject: ARM: pm: rejig suspend follow-on function calling convention Save the suspend function pointer onto the stack for use when returning. Allocate r2 to pass an argument to the suspend function. Acked-by: Frank Hofmann Tested-by: Kevin Hilman Acked-by: Jean Pihet Signed-off-by: Russell King --- arch/arm/kernel/sleep.S | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 358be13499da..b924bcc32dcd 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -10,6 +10,7 @@ /* * Save CPU state for a suspend * r1 = v:p offset + * r2 = suspend function arg0 * r3 = virtual return function * Note: sp is decremented to allocate space for CPU state on stack * r0-r3,ip,lr corrupted @@ -17,7 +18,6 @@ ENTRY(cpu_suspend) stmfd sp!, {r3} stmfd sp!, {r4 - r11} - mov r9, lr #ifdef MULTI_CPU ldr r10, =processor ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state @@ -33,6 +33,7 @@ ENTRY(cpu_suspend) stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn ldr r5, =sleep_save_sp add r6, sp, r1 @ convert SP to phys + stmfd sp!, {r2, lr} @ save suspend func arg and pointer #ifdef CONFIG_SMP ALT_SMP(mrc p15, 0, lr, c0, c0, 5) ALT_UP(mov lr, #0) @@ -51,12 +52,12 @@ ENTRY(cpu_suspend) @ flush data cache #ifdef MULTI_CACHE ldr r10, =cpu_cache - mov lr, r9 + mov lr, pc ldr pc, [r10, #CACHE_FLUSH_KERN_ALL] #else - mov lr, r9 - b __cpuc_flush_kern_all + bl __cpuc_flush_kern_all #endif + ldmfd sp!, {r0, pc} @ call suspend fn ENDPROC(cpu_suspend) .ltorg -- cgit v1.2.3 From e8856a8797e76e6883ae81f8f9ecbb231cc535df Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 13 Jun 2011 15:58:34 +0100 Subject: ARM: pm: convert cpu_suspend() to a normal function cpu_suspend() has a weird calling method which makes it only possible to call from assembly code: it returns with a modified stack pointer to finish the suspend, but on resume, it 'returns' via a provided pointer. We can make cpu_suspend() appear to be a normal function merely by swapping the resume pointer argument and the link register. Do so, and update all callers to take account of this more traditional behaviour. Acked-by: Frank Hofmann Tested-by: Kevin Hilman Acked-by: Jean Pihet Signed-off-by: Russell King --- arch/arm/include/asm/system.h | 2 ++ arch/arm/kernel/sleep.S | 10 ++++------ arch/arm/mach-exynos4/sleep.S | 7 +++---- arch/arm/mach-pxa/sleep.S | 13 ++++++++++--- arch/arm/mach-s3c64xx/sleep.S | 9 +++------ arch/arm/mach-s5pv210/sleep.S | 7 +++---- arch/arm/mach-sa1100/sleep.S | 13 +++---------- arch/arm/plat-s3c24xx/sleep.S | 10 +++------- 8 files changed, 31 insertions(+), 40 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 832888d0c20c..50be6055df89 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -106,6 +106,8 @@ extern void __show_regs(struct pt_regs *); extern int cpu_architecture(void); extern void cpu_init(void); +extern void cpu_suspend(int, long, unsigned long, void (*)(unsigned long)); +extern void cpu_resume(void); void arm_machine_restart(char mode, const char *cmd); extern void (*arm_pm_restart)(char str, const char *cmd); diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index b924bcc32dcd..e0626779fe92 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -11,13 +11,11 @@ * Save CPU state for a suspend * r1 = v:p offset * r2 = suspend function arg0 - * r3 = virtual return function - * Note: sp is decremented to allocate space for CPU state on stack - * r0-r3,ip,lr corrupted + * r3 = suspend function + * Note: does not return until system resumes */ ENTRY(cpu_suspend) - stmfd sp!, {r3} - stmfd sp!, {r4 - r11} + stmfd sp!, {r4 - r11, lr} #ifdef MULTI_CPU ldr r10, =processor ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state @@ -33,7 +31,7 @@ ENTRY(cpu_suspend) stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn ldr r5, =sleep_save_sp add r6, sp, r1 @ convert SP to phys - stmfd sp!, {r2, lr} @ save suspend func arg and pointer + stmfd sp!, {r2, r3} @ save suspend func arg and pointer #ifdef CONFIG_SMP ALT_SMP(mrc p15, 0, lr, c0, c0, 5) ALT_UP(mov lr, #0) diff --git a/arch/arm/mach-exynos4/sleep.S b/arch/arm/mach-exynos4/sleep.S index 6b62425417a6..d9a2287b4641 100644 --- a/arch/arm/mach-exynos4/sleep.S +++ b/arch/arm/mach-exynos4/sleep.S @@ -42,16 +42,15 @@ ENTRY(s3c_cpu_save) stmfd sp!, { r3 - r12, lr } - ldr r3, =resume_with_mmu + adr r3, BSYM(exynos4_finish_suspend) bl cpu_suspend + ldmfd sp!, { r3 - r12, pc } +exynos4_finish_suspend: ldr r0, =pm_cpu_sleep ldr r0, [ r0 ] mov pc, r0 -resume_with_mmu: - ldmfd sp!, { r3 - r12, pc } - .ltorg /* diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S index 613ddfa2c295..3a67887e6dbd 100644 --- a/arch/arm/mach-pxa/sleep.S +++ b/arch/arm/mach-pxa/sleep.S @@ -35,9 +35,11 @@ ENTRY(pxa3xx_cpu_suspend) #endif stmfd sp!, {r2 - r12, lr} @ save registers on stack mov r1, r0 - ldr r3, =pxa_cpu_resume @ resume function + adr r3, BSYM(pxa3xx_finish_suspend) bl cpu_suspend + b pxa_cpu_resume +pxa3xx_finish_suspend: mov r0, #0x06 @ S2D3C4 mode mcr p14, 0, r0, c7, c0, 0 @ enter sleep @@ -60,9 +62,11 @@ ENTRY(pxa27x_cpu_suspend) #endif stmfd sp!, {r2 - r12, lr} @ save registers on stack mov r2, r0 @ save sleep mode - ldr r3, =pxa_cpu_resume @ resume function + adr r3, BSYM(pxa27x_finish_suspend) bl cpu_suspend + b pxa_cpu_resume +pxa27x_finish_suspend: @ Put the processor to sleep @ (also workaround for sighting 28071) @@ -110,8 +114,11 @@ ENTRY(pxa27x_cpu_suspend) ENTRY(pxa25x_cpu_suspend) stmfd sp!, {r2 - r12, lr} @ save registers on stack mov r2, r0 @ save sleep mode - ldr r3, =pxa_cpu_resume @ resume function + adr r3, BSYM(pxa25x_finish_suspend) bl cpu_suspend + b pxa_cpu_resume + +pxa25x_finish_suspend: @ prepare value for sleep mode mov r1, r0 @ sleep mode diff --git a/arch/arm/mach-s3c64xx/sleep.S b/arch/arm/mach-s3c64xx/sleep.S index 1f87732b2320..dc4f58202101 100644 --- a/arch/arm/mach-s3c64xx/sleep.S +++ b/arch/arm/mach-s3c64xx/sleep.S @@ -36,18 +36,15 @@ ENTRY(s3c_cpu_save) stmfd sp!, { r4 - r12, lr } - ldr r3, =resume_with_mmu + adr r3, BSYM(s3c64xx_finish_suspend) bl cpu_suspend + ldmfd sp!, { r4 - r12, pc } +s3c64xx_finish_suspend: @@ call final suspend code ldr r0, =pm_cpu_sleep ldr pc, [r0] - @@ return to the caller, after the MMU is turned on. - @@ restore the last bits of the stack and return. -resume_with_mmu: - ldmfd sp!, { r4 - r12, pc } @ return, from sp from s3c_cpu_save - /* Sleep magic, the word before the resume entry point so that the * bootloader can check for a resumeable image. */ diff --git a/arch/arm/mach-s5pv210/sleep.S b/arch/arm/mach-s5pv210/sleep.S index a3d649466fb1..1182fc848a79 100644 --- a/arch/arm/mach-s5pv210/sleep.S +++ b/arch/arm/mach-s5pv210/sleep.S @@ -41,16 +41,15 @@ ENTRY(s3c_cpu_save) stmfd sp!, { r3 - r12, lr } - ldr r3, =resume_with_mmu + adr r3, BSYM(s5pv210_finish_suspend) bl cpu_suspend + ldmfd sp!, { r3 - r12, pc } +s5pv210_finish_suspend: ldr r0, =pm_cpu_sleep ldr r0, [ r0 ] mov pc, r0 -resume_with_mmu: - ldmfd sp!, { r3 - r12, pc } - .ltorg /* sleep magic, to allow the bootloader to check for an valid diff --git a/arch/arm/mach-sa1100/sleep.S b/arch/arm/mach-sa1100/sleep.S index 122ab3c66923..f3fe39773f8b 100644 --- a/arch/arm/mach-sa1100/sleep.S +++ b/arch/arm/mach-sa1100/sleep.S @@ -31,9 +31,11 @@ ENTRY(sa1100_cpu_suspend) stmfd sp!, {r4 - r12, lr} @ save registers on stack mov r1, r0 - ldr r3, =sa1100_cpu_resume @ return function + adr r3, BSYM(sa1100_finish_suspend) bl cpu_suspend + ldmfd sp!, {r4 - r12, pc} @ return to caller +sa1100_finish_suspend: @ disable clock switching mcr p15, 0, r1, c15, c2, 2 @@ -139,12 +141,3 @@ sa1110_sdram_controller_fix: str r13, [r12] 20: b 20b @ loop waiting for sleep - -/* - * cpu_sa1100_resume() - * - * entry point from bootloader into kernel during resume - */ - .align 5 -sa1100_cpu_resume: - ldmfd sp!, {r4 - r12, pc} @ return to caller diff --git a/arch/arm/plat-s3c24xx/sleep.S b/arch/arm/plat-s3c24xx/sleep.S index fd7032f84ae7..f822e6282dd4 100644 --- a/arch/arm/plat-s3c24xx/sleep.S +++ b/arch/arm/plat-s3c24xx/sleep.S @@ -49,21 +49,17 @@ ENTRY(s3c_cpu_save) stmfd sp!, { r4 - r12, lr } - ldr r3, =resume_with_mmu + adr r3, BSYM(s3c24xx_finish_suspend) bl cpu_suspend + ldmfd sp!, { r4 - r12, pc } +s3c24xx_finish_suspend: @@ jump to final code to send system to sleep ldr r0, =pm_cpu_sleep @@ldr pc, [ r0 ] ldr r0, [ r0 ] mov pc, r0 - @@ return to the caller, after having the MMU - @@ turned on, this restores the last bits from the - @@ stack -resume_with_mmu: - ldmfd sp!, { r4 - r12, pc } - .ltorg /* sleep magic, to allow the bootloader to check for an valid -- cgit v1.2.3 From 14cd8fd574bce1cfbe510ccb1f73c7c1024d770f Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 21 Jun 2011 16:32:58 +0100 Subject: ARM: pm: move cpu_init() call into core code As we have core code dealing with CPU suspend/resume, we can re-initialize the CPUs exception banked registers via that code rather than having platforms deal with that level of detail. So, move the call to cpu_init() out of platform code into core code. Tested-by: Kevin Hilman Acked-by: Jean Pihet Signed-off-by: Russell King --- arch/arm/kernel/sleep.S | 1 + arch/arm/mach-pxa/pm.c | 1 - arch/arm/mach-sa1100/pm.c | 2 -- arch/arm/plat-samsung/pm.c | 4 ---- 4 files changed, 1 insertion(+), 7 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index e0626779fe92..53922748d101 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -88,6 +88,7 @@ ENDPROC(cpu_resume_turn_mmu_on) cpu_resume_after_mmu: str r5, [r2, r4, lsl #2] @ restore old mapping mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache + bl cpu_init @ restore the und/abt/irq banked regs ldmfd sp!, {r4 - r11, pc} ENDPROC(cpu_resume_after_mmu) diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c index 51e1583265b2..37178a8559b1 100644 --- a/arch/arm/mach-pxa/pm.c +++ b/arch/arm/mach-pxa/pm.c @@ -42,7 +42,6 @@ int pxa_pm_enter(suspend_state_t state) /* *** go zzz *** */ pxa_cpu_pm_fns->enter(state); - cpu_init(); if (state != PM_SUSPEND_STANDBY && pxa_cpu_pm_fns->restore) { /* after sleeping, validate the checksum */ diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index c4661aab22fb..d35885ca97a1 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -77,8 +77,6 @@ static int sa11x0_pm_enter(suspend_state_t state) /* go zzz */ sa1100_cpu_suspend(PLAT_PHYS_OFFSET - PAGE_OFFSET); - cpu_init(); - /* * Ensure not to come back here if it wasn't intended */ diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index 5c0a440d6e16..3828191416b5 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -300,10 +300,6 @@ static int s3c_pm_enter(suspend_state_t state) s3c_cpu_save(0, PLAT_PHYS_OFFSET - PAGE_OFFSET); - /* restore the cpu state using the kernel's cpu init code. */ - - cpu_init(); - /* restore the system state */ s3c_pm_restore_core(); -- cgit v1.2.3 From 2c74a0cefa463a7a483b07ba4d2ea8e4ec7b996c Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 22 Jun 2011 17:41:48 +0100 Subject: ARM: pm: hide 1st and 2nd arguments to cpu_suspend from platform code The first and second arguments shouldn't concern platform code, so hide them from each platforms caller. Tested-by: Kevin Hilman Acked-by: Jean Pihet Signed-off-by: Russell King --- arch/arm/include/asm/suspend.h | 19 +++++++++++++++++++ arch/arm/include/asm/system.h | 2 -- arch/arm/kernel/sleep.S | 4 ++-- arch/arm/mach-omap2/pm34xx.c | 5 +++-- arch/arm/mach-pxa/palmz72.c | 1 + arch/arm/mach-pxa/pxa25x.c | 4 ++-- arch/arm/mach-pxa/pxa27x.c | 4 ++-- arch/arm/mach-pxa/pxa3xx.c | 3 ++- arch/arm/mach-pxa/zeus.c | 4 ++-- arch/arm/mach-sa1100/pm.c | 3 ++- arch/arm/plat-samsung/pm.c | 3 ++- 11 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 arch/arm/include/asm/suspend.h (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h new file mode 100644 index 000000000000..8d5b4461c205 --- /dev/null +++ b/arch/arm/include/asm/suspend.h @@ -0,0 +1,19 @@ +#ifndef __ASM_ARM_SUSPEND_H +#define __ASM_ARM_SUSPEND_H + +#include + +extern void cpu_resume(void); + +/* + * Hide the first two arguments to __cpu_suspend - these are an implementation + * detail which platform code shouldn't have to know about. + */ +static inline void cpu_suspend(unsigned long arg, void (*fn)(unsigned long)) +{ + extern void __cpu_suspend(int, long, unsigned long, + void (*)(unsigned long)); + __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn); +} + +#endif diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 50be6055df89..832888d0c20c 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -106,8 +106,6 @@ extern void __show_regs(struct pt_regs *); extern int cpu_architecture(void); extern void cpu_init(void); -extern void cpu_suspend(int, long, unsigned long, void (*)(unsigned long)); -extern void cpu_resume(void); void arm_machine_restart(char mode, const char *cmd); extern void (*arm_pm_restart)(char str, const char *cmd); diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 53922748d101..c156d0e5f455 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -14,7 +14,7 @@ * r3 = suspend function * Note: does not return until system resumes */ -ENTRY(cpu_suspend) +ENTRY(__cpu_suspend) stmfd sp!, {r4 - r11, lr} #ifdef MULTI_CPU ldr r10, =processor @@ -56,7 +56,7 @@ ENTRY(cpu_suspend) bl __cpuc_flush_kern_all #endif ldmfd sp!, {r0, pc} @ call suspend fn -ENDPROC(cpu_suspend) +ENDPROC(__cpu_suspend) .ltorg /* diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index ae4017750bbe..3e9a13e1ac57 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -31,6 +31,8 @@ #include #include +#include + #include #include "clockdomain.h" #include "powerdomain.h" @@ -411,8 +413,7 @@ void omap_sram_idle(void) * from there before resuming. */ if (save_state == 1 || save_state == 3) - cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, save_state, - omap34xx_do_sram_idle); + cpu_suspend(save_state, omap34xx_do_sram_idle); else omap34xx_do_sram_idle(save_state); diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c index 65f24f0b77e8..5a5329bc33f1 100644 --- a/arch/arm/mach-pxa/palmz72.c +++ b/arch/arm/mach-pxa/palmz72.c @@ -33,6 +33,7 @@ #include #include +#include #include #include diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index fd7725cb5c01..9c434d21a271 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -244,8 +245,7 @@ static void pxa25x_cpu_pm_enter(suspend_state_t state) switch (state) { case PM_SUSPEND_MEM: - cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, PWRMODE_SLEEP, - pxa25x_finish_suspend); + cpu_suspend(PWRMODE_SLEEP, pxa25x_finish_suspend); break; } } diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 824379d43758..9d2400b5f503 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -304,8 +305,7 @@ void pxa27x_cpu_pm_enter(suspend_state_t state) pxa_cpu_standby(); break; case PM_SUSPEND_MEM: - cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, pwrmode, - pxa27x_finish_suspend); + cpu_suspend(pwrmode, pxa27x_finish_suspend); #ifndef CONFIG_IWMMXT asm volatile("mar acc0, %Q0, %R0" : "=r" (acc0)); #endif diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 220fd8c15dab..9fe947b5d5f7 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -167,7 +168,7 @@ static void pxa3xx_cpu_pm_suspend(void) /* overwrite with the resume address */ *p = virt_to_phys(cpu_resume); - cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, 0, pxa3xx_finish_suspend); + cpu_suspend(0, pxa3xx_finish_suspend); *p = saved_data; diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index 28eb410ca779..9b99cc164de5 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -676,8 +677,7 @@ static struct pxa2xx_udc_mach_info zeus_udc_info = { static void zeus_power_off(void) { local_irq_disable(); - cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, PWRMODE_DEEPSLEEP, - pxa27x_finish_suspend); + cpu_suspend(PWRMODE_DEEPSLEEP, pxa27x_finish_suspend); } #else #define zeus_power_off NULL diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index 259ed3bcc3fe..cf9a1e9fb70d 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -75,7 +76,7 @@ static int sa11x0_pm_enter(suspend_state_t state) PSPR = virt_to_phys(cpu_resume); /* go zzz */ - cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, 0, sa1100_finish_suspend); + cpu_suspend(0, sa1100_finish_suspend); /* * Ensure not to come back here if it wasn't intended diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index 3a6d0768ba0c..69d6b040a019 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -298,7 +299,7 @@ static int s3c_pm_enter(suspend_state_t state) * we resume as it saves its own register state and restores it * during the resume. */ - cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, 0, pm_cpu_sleep); + cpu_suspend(0, pm_cpu_sleep); /* restore the system state */ -- cgit v1.2.3 From ac8b9c1ce094d43372d0259de08045ffee745a41 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 26 Jun 2011 10:22:08 +0100 Subject: ARM: entry: prefetch/data abort helpers: convert to macros Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 85 ++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 50 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 90c62cd51ca9..dbe9eb88d550 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -44,6 +44,37 @@ 9997: .endm + .macro pabt_helper + mov r0, r2 @ pass address of aborted instruction. +#ifdef MULTI_PABORT + ldr r4, .LCprocfns + mov lr, pc + ldr pc, [r4, #PROCESSOR_PABT_FUNC] +#else + bl CPU_PABORT_HANDLER +#endif + .endm + + .macro dabt_helper + + @ + @ Call the processor-specific abort handler: + @ + @ r2 - aborted context pc + @ r3 - aborted context cpsr + @ + @ The abort handler must return the aborted address in r0, and + @ the fault status register in r1. r9 must be preserved. + @ +#ifdef MULTI_DABORT + ldr r4, .LCprocfns + mov lr, pc + ldr pc, [r4, #PROCESSOR_DABT_FUNC] +#else + bl CPU_DABORT_HANDLER +#endif + .endm + #ifdef CONFIG_KPROBES .section .kprobes.text,"ax",%progbits #else @@ -159,22 +190,7 @@ __dabt_svc: tst r3, #PSR_I_BIT biceq r9, r9, #PSR_I_BIT - @ - @ Call the processor-specific abort handler: - @ - @ r2 - aborted context pc - @ r3 - aborted context cpsr - @ - @ The abort handler must return the aborted address in r0, and - @ the fault status register in r1. r9 must be preserved. - @ -#ifdef MULTI_DABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_DABT_FUNC] -#else - bl CPU_DABORT_HANDLER -#endif + dabt_helper @ @ set desired IRQ state, then call main handler @@ -298,14 +314,7 @@ __pabt_svc: tst r3, #PSR_I_BIT biceq r9, r9, #PSR_I_BIT - mov r0, r2 @ pass address of aborted instruction. -#ifdef MULTI_PABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_PABT_FUNC] -#else - bl CPU_PABORT_HANDLER -#endif + pabt_helper debug_entry r1 msr cpsr_c, r9 @ Maybe enable interrupts mov r2, sp @ regs @@ -401,23 +410,7 @@ ENDPROC(__pabt_svc) __dabt_usr: usr_entry kuser_cmpxchg_check - - @ - @ Call the processor-specific abort handler: - @ - @ r2 - aborted context pc - @ r3 - aborted context cpsr - @ - @ The abort handler must return the aborted address in r0, and - @ the fault status register in r1. - @ -#ifdef MULTI_DABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_DABT_FUNC] -#else - bl CPU_DABORT_HANDLER -#endif + dabt_helper @ @ IRQs on, then call the main handler @@ -682,15 +675,7 @@ ENDPROC(__und_usr_unknown) .align 5 __pabt_usr: usr_entry - - mov r0, r2 @ pass address of aborted instruction. -#ifdef MULTI_PABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_PABT_FUNC] -#else - bl CPU_PABORT_HANDLER -#endif + pabt_helper debug_entry r1 enable_irq @ Enable interrupts mov r2, sp @ regs -- cgit v1.2.3 From 0402becef94c43bb2bb483653a5cee2fb5049764 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jun 2011 15:46:08 +0100 Subject: ARM: entry: prefetch/data abort helpers: avoid corrupting r4 Replace r4 with ip for calling abort helpers - ip is allowed to be corrupted by called functions in the ABI, so it makes more sense to use such a register. Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index dbe9eb88d550..6855f6dd72d0 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -47,9 +47,9 @@ .macro pabt_helper mov r0, r2 @ pass address of aborted instruction. #ifdef MULTI_PABORT - ldr r4, .LCprocfns + ldr ip, .LCprocfns mov lr, pc - ldr pc, [r4, #PROCESSOR_PABT_FUNC] + ldr pc, [ip, #PROCESSOR_PABT_FUNC] #else bl CPU_PABORT_HANDLER #endif @@ -67,9 +67,9 @@ @ the fault status register in r1. r9 must be preserved. @ #ifdef MULTI_DABORT - ldr r4, .LCprocfns + ldr ip, .LCprocfns mov lr, pc - ldr pc, [r4, #PROCESSOR_DABT_FUNC] + ldr pc, [ip, #PROCESSOR_DABT_FUNC] #else bl CPU_DABORT_HANDLER #endif -- cgit v1.2.3 From 1613cc1119ecdb1bdb950da53065e615e4c4b8db Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jun 2011 10:57:57 +0100 Subject: ARM: entry: no need to increase preempt count for IRQ handlers irq_enter() and irq_exit() already take care of the preempt_count handling for interrupts, which increment and decrement the hardirq bits of the preempt count. So we can remove the preempt count handing in our IRQ entry/exit assembly, like x86 did some 9 years ago. Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 6855f6dd72d0..1e5f387c70ae 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -220,16 +220,12 @@ __irq_svc: #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off #endif -#ifdef CONFIG_PREEMPT - get_thread_info tsk - ldr r8, [tsk, #TI_PREEMPT] @ get preempt count - add r7, r8, #1 @ increment it - str r7, [tsk, #TI_PREEMPT] -#endif irq_handler + #ifdef CONFIG_PREEMPT - str r8, [tsk, #TI_PREEMPT] @ restore preempt count + get_thread_info tsk + ldr r8, [tsk, #TI_PREEMPT] @ get preempt count ldr r0, [tsk, #TI_FLAGS] @ get flags teq r8, #0 @ if preempt count != 0 movne r0, #0 @ force flags to 0 @@ -432,23 +428,8 @@ __irq_usr: bl trace_hardirqs_off #endif - get_thread_info tsk -#ifdef CONFIG_PREEMPT - ldr r8, [tsk, #TI_PREEMPT] @ get preempt count - add r7, r8, #1 @ increment it - str r7, [tsk, #TI_PREEMPT] -#endif - irq_handler -#ifdef CONFIG_PREEMPT - ldr r0, [tsk, #TI_PREEMPT] - str r8, [tsk, #TI_PREEMPT] - teq r0, r7 - ARM( strne r0, [r0, -r0] ) - THUMB( movne r0, #0 ) - THUMB( strne r0, [r0] ) -#endif - + get_thread_info tsk mov why, #0 b ret_to_user_from_irq UNWIND(.fnend ) -- cgit v1.2.3 From fbab1c809467efe001194ab8bb17f0f451a17f97 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jun 2011 16:57:50 +0100 Subject: ARM: entry: no need to check parent IRQ mask in IRQ handler return There's no point checking to see whether IRQs were masked in the parent context when returning from IRQ handling - the fact that we're handling an IRQ means that the parent context must have had IRQs unmasked. Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 1e5f387c70ae..fd42e667a81b 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -234,8 +234,9 @@ __irq_svc: #endif ldr r4, [sp, #S_PSR] @ irqs are already disabled #ifdef CONFIG_TRACE_IRQFLAGS - tst r4, #PSR_I_BIT - bleq trace_hardirqs_on + @ The parent context IRQs must have been enabled to get here in + @ the first place, so there's no point checking the PSR I bit. + bl trace_hardirqs_on #endif svc_exit r4 @ return from exception UNWIND(.fnend ) -- cgit v1.2.3 From f12482c9393da2c1f5cb3217f29aa79c653dd980 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 22 Jun 2011 15:30:51 +0100 Subject: ARM: 6974/1: pmu: refactor reservation Currently, PMU platform_device reservation relies on some minor abuse of the platform_device::id field for determining the type of PMU. This is problematic for device tree based probing, where the ID cannot be controlled. This patch removes reliance on the id field, and depends on each PMU's platform driver to figure out which type it is. As all PMUs handled by the current platform_driver name "arm-pmu" are CPU PMUs, this convention is hardcoded. New PMU types can be supported through the use of {of,platform}_device_id tables Signed-off-by: Mark Rutland Acked-by: Jamie Iles Acked-by: Will Deacon Cc: Rob Herring Cc: Mathieu Desnoyers Signed-off-by: Russell King --- arch/arm/include/asm/pmu.h | 2 +- arch/arm/kernel/perf_event.c | 4 ++-- arch/arm/kernel/pmu.c | 33 +++++++++++++++++++-------------- 3 files changed, 22 insertions(+), 17 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 7544ce6b481a..67c70a31a1be 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -52,7 +52,7 @@ reserve_pmu(enum arm_pmu_type device); * a cookie. */ extern int -release_pmu(struct platform_device *pdev); +release_pmu(enum arm_pmu_type type); /** * init_pmu() - Initialise the PMU. diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index d53c0abc4dd3..a6c643f2d2ca 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -435,7 +435,7 @@ armpmu_reserve_hardware(void) if (irq >= 0) free_irq(irq, NULL); } - release_pmu(pmu_device); + release_pmu(ARM_PMU_DEVICE_CPU); pmu_device = NULL; } @@ -454,7 +454,7 @@ armpmu_release_hardware(void) } armpmu->stop(); - release_pmu(pmu_device); + release_pmu(ARM_PMU_DEVICE_CPU); pmu_device = NULL; } diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c index 2c79eec19262..87942b931c62 100644 --- a/arch/arm/kernel/pmu.c +++ b/arch/arm/kernel/pmu.c @@ -25,36 +25,41 @@ static volatile long pmu_lock; static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES]; -static int __devinit pmu_device_probe(struct platform_device *pdev) +static int __devinit pmu_register(struct platform_device *pdev, + enum arm_pmu_type type) { - - if (pdev->id < 0 || pdev->id >= ARM_NUM_PMU_DEVICES) { + if (type < 0 || type >= ARM_NUM_PMU_DEVICES) { pr_warning("received registration request for unknown " - "device %d\n", pdev->id); + "device %d\n", type); return -EINVAL; } - if (pmu_devices[pdev->id]) + if (pmu_devices[type]) pr_warning("registering new PMU device type %d overwrites " - "previous registration!\n", pdev->id); + "previous registration!\n", type); else pr_info("registered new PMU device of type %d\n", - pdev->id); + type); - pmu_devices[pdev->id] = pdev; + pmu_devices[type] = pdev; return 0; } -static struct platform_driver pmu_driver = { +static int __devinit armpmu_device_probe(struct platform_device *pdev) +{ + return pmu_register(pdev, ARM_PMU_DEVICE_CPU); +} + +static struct platform_driver armpmu_driver = { .driver = { .name = "arm-pmu", }, - .probe = pmu_device_probe, + .probe = armpmu_device_probe, }; static int __init register_pmu_driver(void) { - return platform_driver_register(&pmu_driver); + return platform_driver_register(&armpmu_driver); } device_initcall(register_pmu_driver); @@ -77,11 +82,11 @@ reserve_pmu(enum arm_pmu_type device) EXPORT_SYMBOL_GPL(reserve_pmu); int -release_pmu(struct platform_device *pdev) +release_pmu(enum arm_pmu_type device) { - if (WARN_ON(pdev != pmu_devices[pdev->id])) + if (WARN_ON(!pmu_devices[device])) return -EINVAL; - clear_bit_unlock(pdev->id, &pmu_lock); + clear_bit_unlock(device, &pmu_lock); return 0; } EXPORT_SYMBOL_GPL(release_pmu); -- cgit v1.2.3 From ae0c3751ab08d3fe039d48935e9ad2c46711b23b Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 22 Jun 2011 15:32:48 +0100 Subject: ARM: 6975/1: pmu: reject duplicate PMU registrations Currently, the PMU reservation framework allows for multiple PMUs of the same type to register themselves. This can lead to a bug with the sequence: register_pmu(pmu1); reserve_pmu(pmu_type); register_pmu(pmu2); release_pmu(pmu1); Here, pmu1 cannot be released, and pmu2 cannot be reserved. This patch modifies register_pmu to reject registrations where a PMU is already present, preventing this problem. PMUs which can have multiple instances should not use the PMU reservation framework. Signed-off-by: Mark Rutland Acked-by: Jamie Iles Acked-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/pmu.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c index 87942b931c62..de6b1b0860c2 100644 --- a/arch/arm/kernel/pmu.c +++ b/arch/arm/kernel/pmu.c @@ -34,13 +34,13 @@ static int __devinit pmu_register(struct platform_device *pdev, return -EINVAL; } - if (pmu_devices[type]) - pr_warning("registering new PMU device type %d overwrites " - "previous registration!\n", type); - else - pr_info("registered new PMU device of type %d\n", - type); + if (pmu_devices[type]) { + pr_warning("rejecting duplicate registration of PMU device " + "type %d.", type); + return -ENOSPC; + } + pr_info("registered new PMU device of type %d\n", type); pmu_devices[type] = pdev; return 0; } -- cgit v1.2.3 From e73c34c3d522a60d9f7b38a7683076362bad98f5 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 22 Jun 2011 15:33:55 +0100 Subject: ARM: 6976/1: pmu: add OF probing support This is based on an earlier patch from Rob Herring > Add OF match table to enable OF style driver binding. The dts entry is like > this: > > pmu { > compatible = "arm,cortex-a9-pmu"; > interrupts = <100 101>; > }; > > The use of pdev->id as an index breaks with OF device binding, so set the type > based on the OF compatible string. This modification sets the PMU hardware type based on data embedded in the binding, allowing easy addition of new PMU types in future. Support for new PMU types not provided by devicetree can be added later using platform_device_id tables in a similar fashion. Signed-off-by: Mark Rutland Acked-by: Jamie Iles Acked-by: Rob Herring Cc: Will Deacon Signed-off-by: Russell King --- Documentation/devicetree/bindings/arm/pmu.txt | 21 +++++++++++++++++ arch/arm/kernel/pmu.c | 34 ++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/pmu.txt (limited to 'arch/arm/kernel') diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt new file mode 100644 index 000000000000..1c044eb320cc --- /dev/null +++ b/Documentation/devicetree/bindings/arm/pmu.txt @@ -0,0 +1,21 @@ +* ARM Performance Monitor Units + +ARM cores often have a PMU for counting cpu and cache events like cache misses +and hits. The interface to the PMU is part of the ARM ARM. The ARM PMU +representation in the device tree should be done as under:- + +Required properties: + +- compatible : should be one of + "arm,cortex-a9-pmu" + "arm,cortex-a8-pmu" + "arm,arm1176-pmu" + "arm,arm1136-pmu" +- interrupts : 1 combined interrupt or 1 per core. + +Example: + +pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <100 101>; +}; diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c index de6b1b0860c2..2ce00be697ea 100644 --- a/arch/arm/kernel/pmu.c +++ b/arch/arm/kernel/pmu.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -45,14 +46,45 @@ static int __devinit pmu_register(struct platform_device *pdev, return 0; } +#define OF_MATCH_PMU(_name, _type) { \ + .compatible = _name, \ + .data = (void *)_type, \ +} + +#define OF_MATCH_CPU(name) OF_MATCH_PMU(name, ARM_PMU_DEVICE_CPU) + +static struct of_device_id armpmu_of_device_ids[] = { + OF_MATCH_CPU("arm,cortex-a9-pmu"), + OF_MATCH_CPU("arm,cortex-a8-pmu"), + OF_MATCH_CPU("arm,arm1136-pmu"), + OF_MATCH_CPU("arm,arm1176-pmu"), + {}, +}; + +enum arm_pmu_type armpmu_device_type(struct platform_device *pdev) +{ + const struct of_device_id *of_id; + + /* provided by of_device_id table */ + if (pdev->dev.of_node) { + of_id = of_match_device(armpmu_of_device_ids, &pdev->dev); + BUG_ON(!of_id); + return (enum arm_pmu_type)of_id->data; + } + + /* Provided by a 'legacy' platform_device */ + return ARM_PMU_DEVICE_CPU; +} + static int __devinit armpmu_device_probe(struct platform_device *pdev) { - return pmu_register(pdev, ARM_PMU_DEVICE_CPU); + return pmu_register(pdev, armpmu_device_type(pdev)); } static struct platform_driver armpmu_driver = { .driver = { .name = "arm-pmu", + .of_match_table = armpmu_of_device_ids, }, .probe = armpmu_device_probe, }; -- cgit v1.2.3 From e4b6381009d740bd3a97e6b841d8efe7fc70c1b7 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 22 Jun 2011 15:34:56 +0100 Subject: ARM: 6977/1: pmu: add platform_device_id table support This patch adds support for platform_device_id tables, allowing new PMU types to be registered with the correct type, without requiring new platform_driver shims to provide the type. An single entry for existing devices is provided. Macros matching functionality of the of_device_id table macros are provided for convenience. Signed-off-by: Mark Rutland Acked-by: Jamie Iles Cc: Rob Herring Cc: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/pmu.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c index 2ce00be697ea..2b70709376c3 100644 --- a/arch/arm/kernel/pmu.c +++ b/arch/arm/kernel/pmu.c @@ -61,9 +61,22 @@ static struct of_device_id armpmu_of_device_ids[] = { {}, }; +#define PLAT_MATCH_PMU(_name, _type) { \ + .name = _name, \ + .driver_data = _type, \ +} + +#define PLAT_MATCH_CPU(_name) PLAT_MATCH_PMU(_name, ARM_PMU_DEVICE_CPU) + +static struct platform_device_id armpmu_plat_device_ids[] = { + PLAT_MATCH_CPU("arm-pmu"), + {}, +}; + enum arm_pmu_type armpmu_device_type(struct platform_device *pdev) { const struct of_device_id *of_id; + const struct platform_device_id *pdev_id; /* provided by of_device_id table */ if (pdev->dev.of_node) { @@ -72,8 +85,10 @@ enum arm_pmu_type armpmu_device_type(struct platform_device *pdev) return (enum arm_pmu_type)of_id->data; } - /* Provided by a 'legacy' platform_device */ - return ARM_PMU_DEVICE_CPU; + /* Provided by platform_device_id table */ + pdev_id = platform_get_device_id(pdev); + BUG_ON(!pdev_id); + return pdev_id->driver_data; } static int __devinit armpmu_device_probe(struct platform_device *pdev) @@ -87,6 +102,7 @@ static struct platform_driver armpmu_driver = { .of_match_table = armpmu_of_device_ids, }, .probe = armpmu_device_probe, + .id_table = armpmu_plat_device_ids, }; static int __init register_pmu_driver(void) -- cgit v1.2.3 From b059bdc39321696fe8f344acb7117d57fbd7b475 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jun 2011 15:44:20 +0100 Subject: ARM: entry: rejig register allocation in exception entry handlers This allows us to avoid moving registers twice to work around the clobbered registers when we add calls to trace_hardirqs_{on,off}. Ensure that all SVC handlers return with SPSR in r5 for consistency. Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 81 +++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 38 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index fd42e667a81b..582bb2310446 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -45,7 +45,7 @@ .endm .macro pabt_helper - mov r0, r2 @ pass address of aborted instruction. + mov r0, r4 @ pass address of aborted instruction. #ifdef MULTI_PABORT ldr ip, .LCprocfns mov lr, pc @@ -56,6 +56,8 @@ .endm .macro dabt_helper + mov r2, r4 + mov r3, r5 @ @ Call the processor-specific abort handler: @@ -157,26 +159,26 @@ ENDPROC(__und_invalid) SPFIX( subeq sp, sp, #4 ) stmia sp, {r1 - r12} - ldmia r0, {r1 - r3} - add r5, sp, #S_SP - 4 @ here for interlock avoidance - mov r4, #-1 @ "" "" "" "" - add r0, sp, #(S_FRAME_SIZE + \stack_hole - 4) - SPFIX( addeq r0, r0, #4 ) - str r1, [sp, #-4]! @ save the "real" r0 copied + ldmia r0, {r3 - r5} + add r7, sp, #S_SP - 4 @ here for interlock avoidance + mov r6, #-1 @ "" "" "" "" + add r2, sp, #(S_FRAME_SIZE + \stack_hole - 4) + SPFIX( addeq r2, r2, #4 ) + str r3, [sp, #-4]! @ save the "real" r0 copied @ from the exception stack - mov r1, lr + mov r3, lr @ @ We are now ready to fill in the remaining blanks on the stack: @ - @ r0 - sp_svc - @ r1 - lr_svc - @ r2 - lr_, already fixed up for correct return/restart - @ r3 - spsr_ - @ r4 - orig_r0 (see pt_regs definition in ptrace.h) + @ r2 - sp_svc + @ r3 - lr_svc + @ r4 - lr_, already fixed up for correct return/restart + @ r5 - spsr_ + @ r6 - orig_r0 (see pt_regs definition in ptrace.h) @ - stmia r5, {r0 - r4} + stmia r7, {r2 - r6} .endm .align 5 @@ -187,7 +189,7 @@ __dabt_svc: @ get ready to re-enable interrupts if appropriate @ mrs r9, cpsr - tst r3, #PSR_I_BIT + tst r5, #PSR_I_BIT biceq r9, r9, #PSR_I_BIT dabt_helper @@ -208,8 +210,8 @@ __dabt_svc: @ @ restore SPSR and restart the instruction @ - ldr r2, [sp, #S_PSR] - svc_exit r2 @ return from exception + ldr r5, [sp, #S_PSR] + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__dabt_svc) @@ -232,13 +234,13 @@ __irq_svc: tst r0, #_TIF_NEED_RESCHED blne svc_preempt #endif - ldr r4, [sp, #S_PSR] @ irqs are already disabled + ldr r5, [sp, #S_PSR] #ifdef CONFIG_TRACE_IRQFLAGS @ The parent context IRQs must have been enabled to get here in @ the first place, so there's no point checking the PSR I bit. bl trace_hardirqs_on #endif - svc_exit r4 @ return from exception + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__irq_svc) @@ -273,15 +275,16 @@ __und_svc: @ r0 - instruction @ #ifndef CONFIG_THUMB2_KERNEL - ldr r0, [r2, #-4] + ldr r0, [r4, #-4] #else - ldrh r0, [r2, #-2] @ Thumb instruction at LR - 2 + ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2 and r9, r0, #0xf800 cmp r9, #0xe800 @ 32-bit instruction if xx >= 0 - ldrhhs r9, [r2] @ bottom 16 bits + ldrhhs r9, [r4] @ bottom 16 bits orrhs r0, r9, r0, lsl #16 #endif adr r9, BSYM(1f) + mov r2, r4 bl call_fpe mov r0, sp @ struct pt_regs *regs @@ -295,8 +298,8 @@ __und_svc: @ @ restore SPSR and restart the instruction @ - ldr r2, [sp, #S_PSR] @ Get SVC cpsr - svc_exit r2 @ return from exception + ldr r5, [sp, #S_PSR] @ Get SVC cpsr + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__und_svc) @@ -308,7 +311,7 @@ __pabt_svc: @ re-enable interrupts if appropriate @ mrs r9, cpsr - tst r3, #PSR_I_BIT + tst r5, #PSR_I_BIT biceq r9, r9, #PSR_I_BIT pabt_helper @@ -325,8 +328,8 @@ __pabt_svc: @ @ restore SPSR and restart the instruction @ - ldr r2, [sp, #S_PSR] - svc_exit r2 @ return from exception + ldr r5, [sp, #S_PSR] + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__pabt_svc) @@ -357,23 +360,23 @@ ENDPROC(__pabt_svc) ARM( stmib sp, {r1 - r12} ) THUMB( stmia sp, {r0 - r12} ) - ldmia r0, {r1 - r3} + ldmia r0, {r3 - r5} add r0, sp, #S_PC @ here for interlock avoidance - mov r4, #-1 @ "" "" "" "" + mov r6, #-1 @ "" "" "" "" - str r1, [sp] @ save the "real" r0 copied + str r3, [sp] @ save the "real" r0 copied @ from the exception stack @ @ We are now ready to fill in the remaining blanks on the stack: @ - @ r2 - lr_, already fixed up for correct return/restart - @ r3 - spsr_ - @ r4 - orig_r0 (see pt_regs definition in ptrace.h) + @ r4 - lr_, already fixed up for correct return/restart + @ r5 - spsr_ + @ r6 - orig_r0 (see pt_regs definition in ptrace.h) @ @ Also, separately save sp_usr and lr_usr @ - stmia r0, {r2 - r4} + stmia r0, {r4 - r6} ARM( stmdb r0, {sp, lr}^ ) THUMB( store_user_sp_lr r0, r1, S_SP - S_PC ) @@ -397,7 +400,7 @@ ENDPROC(__pabt_svc) @ if it was interrupted in a critical region. Here we @ perform a quick test inline since it should be false @ 99.9999% of the time. The rest is done out of line. - cmp r2, #TASK_SIZE + cmp r4, #TASK_SIZE blhs kuser_cmpxchg_fixup #endif #endif @@ -441,6 +444,8 @@ ENDPROC(__irq_usr) .align 5 __und_usr: usr_entry + mov r2, r4 + mov r3, r5 @ @ fall through to the emulation code, which returns using r9 if @@ -894,13 +899,13 @@ __kuser_cmpxchg: @ 0xffff0fc0 .text kuser_cmpxchg_fixup: @ Called from kuser_cmpxchg_check macro. - @ r2 = address of interrupted insn (must be preserved). + @ r4 = address of interrupted insn (must be preserved). @ sp = saved regs. r7 and r8 are clobbered. @ 1b = first critical insn, 2b = last critical insn. - @ If r2 >= 1b and r2 <= 2b then saved pc_usr is set to 1b. + @ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b. mov r7, #0xffff0fff sub r7, r7, #(0xffff0fff - (0xffff0fc0 + (1b - __kuser_cmpxchg))) - subs r8, r2, r7 + subs r8, r4, r7 rsbcss r8, r8, #(2b - 1b) strcs r7, [sp, #S_PC] mov pc, lr -- cgit v1.2.3 From 8b4186160b7894ca4583f702a562856d5d9e9118 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jun 2011 19:25:02 +0100 Subject: ARM: entry: prefetch abort helper: pass aborted pc in r4 rather than r0 This avoids unnecessary instructions for CPUs which implement the IFAR (instruction fault address register). Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 2 +- arch/arm/mm/pabort-legacy.S | 3 ++- arch/arm/mm/pabort-v6.S | 3 ++- arch/arm/mm/pabort-v7.S | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 582bb2310446..d644d0240ad3 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -45,7 +45,7 @@ .endm .macro pabt_helper - mov r0, r4 @ pass address of aborted instruction. + @ PABORT handler takes fault address in r4 #ifdef MULTI_PABORT ldr ip, .LCprocfns mov lr, pc diff --git a/arch/arm/mm/pabort-legacy.S b/arch/arm/mm/pabort-legacy.S index 87970eba88ea..8a5d8aaf2d5e 100644 --- a/arch/arm/mm/pabort-legacy.S +++ b/arch/arm/mm/pabort-legacy.S @@ -4,7 +4,7 @@ /* * Function: legacy_pabort * - * Params : r0 = address of aborted instruction + * Params : r4 = address of aborted instruction * * Returns : r0 = address of abort * : r1 = Simulated IFSR with section translation fault status @@ -14,6 +14,7 @@ .align 5 ENTRY(legacy_pabort) + mov r0, r4 mov r1, #5 mov pc, lr ENDPROC(legacy_pabort) diff --git a/arch/arm/mm/pabort-v6.S b/arch/arm/mm/pabort-v6.S index 06e3d1ef2115..eaac1cb7c4cc 100644 --- a/arch/arm/mm/pabort-v6.S +++ b/arch/arm/mm/pabort-v6.S @@ -4,7 +4,7 @@ /* * Function: v6_pabort * - * Params : r0 = address of aborted instruction + * Params : r4 = address of aborted instruction * * Returns : r0 = address of abort * : r1 = IFSR @@ -14,6 +14,7 @@ .align 5 ENTRY(v6_pabort) + mov r0, r4 mrc p15, 0, r1, c5, c0, 1 @ get IFSR mov pc, lr ENDPROC(v6_pabort) diff --git a/arch/arm/mm/pabort-v7.S b/arch/arm/mm/pabort-v7.S index a8b3b300a18d..b515e0b059b3 100644 --- a/arch/arm/mm/pabort-v7.S +++ b/arch/arm/mm/pabort-v7.S @@ -4,7 +4,7 @@ /* * Function: v6_pabort * - * Params : r0 = address of aborted instruction + * Params : r4 = address of aborted instruction * * Returns : r0 = address of abort * : r1 = IFSR -- cgit v1.2.3 From 29cb3cd208dd0e4471bb80bec4facc49ceb199fa Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 2 Jul 2011 09:54:01 +0100 Subject: ARM: pm: allow suspend finisher to return error codes There are SoCs where attempting to enter a low power state is ignored, and the CPU continues executing instructions with all state preserved. It is over-complex at that point to disable the MMU just to call the resume path. Instead, allow the suspend finisher to return error codes to abort suspend in this circumstance, where the cpu_suspend internals will then unwind the saved state on the stack. Also omit the tlb flush as no changes to the page tables will have happened. Signed-off-by: Russell King --- arch/arm/include/asm/suspend.h | 9 +++++---- arch/arm/kernel/sleep.S | 11 +++++++++-- arch/arm/mach-exynos4/pm.c | 2 +- arch/arm/mach-omap2/pm34xx.c | 3 ++- arch/arm/mach-pxa/include/mach/pm.h | 4 ++-- arch/arm/mach-pxa/pxa3xx.c | 2 +- arch/arm/mach-s3c2412/pm.c | 4 +++- arch/arm/mach-s3c2416/pm.c | 4 +++- arch/arm/mach-s3c64xx/pm.c | 2 +- arch/arm/mach-sa1100/pm.c | 2 +- arch/arm/plat-samsung/include/plat/pm.h | 4 ++-- arch/arm/plat-samsung/pm.c | 2 +- 12 files changed, 31 insertions(+), 18 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h index f8db9d096bc7..b0e4e1a02318 100644 --- a/arch/arm/include/asm/suspend.h +++ b/arch/arm/include/asm/suspend.h @@ -10,12 +10,13 @@ extern void cpu_resume(void); * Hide the first two arguments to __cpu_suspend - these are an implementation * detail which platform code shouldn't have to know about. */ -static inline void cpu_suspend(unsigned long arg, void (*fn)(unsigned long)) +static inline int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) { - extern void __cpu_suspend(int, long, unsigned long, - void (*)(unsigned long)); - __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn); + extern int __cpu_suspend(int, long, unsigned long, + int (*)(unsigned long)); + int ret = __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn); flush_tlb_all(); + return ret; } #endif diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index c156d0e5f455..dc902f2c6845 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -12,7 +12,6 @@ * r1 = v:p offset * r2 = suspend function arg0 * r3 = suspend function - * Note: does not return until system resumes */ ENTRY(__cpu_suspend) stmfd sp!, {r4 - r11, lr} @@ -26,7 +25,7 @@ ENTRY(__cpu_suspend) #endif mov r6, sp @ current virtual SP sub sp, sp, r5 @ allocate CPU state on stack - mov r0, sp @ save pointer + mov r0, sp @ save pointer to CPU save block add ip, ip, r1 @ convert resume fn to phys stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn ldr r5, =sleep_save_sp @@ -55,10 +54,17 @@ ENTRY(__cpu_suspend) #else bl __cpuc_flush_kern_all #endif + adr lr, BSYM(cpu_suspend_abort) ldmfd sp!, {r0, pc} @ call suspend fn ENDPROC(__cpu_suspend) .ltorg +cpu_suspend_abort: + ldmia sp!, {r1 - r3} @ pop v:p, virt SP, phys resume fn + mov sp, r2 + ldmfd sp!, {r4 - r11, pc} +ENDPROC(cpu_suspend_abort) + /* * r0 = control register value * r1 = v:p offset (preserved by cpu_do_resume) @@ -89,6 +95,7 @@ cpu_resume_after_mmu: str r5, [r2, r4, lsl #2] @ restore old mapping mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache bl cpu_init @ restore the und/abt/irq banked regs + mov r0, #0 @ return zero on success ldmfd sp!, {r4 - r11, pc} ENDPROC(cpu_resume_after_mmu) diff --git a/arch/arm/mach-exynos4/pm.c b/arch/arm/mach-exynos4/pm.c index 5c01c6076645..533c28f758ca 100644 --- a/arch/arm/mach-exynos4/pm.c +++ b/arch/arm/mach-exynos4/pm.c @@ -280,7 +280,7 @@ static struct sleep_save exynos4_l2cc_save[] = { SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL), }; -void exynos4_cpu_suspend(unsigned long arg) +static int exynos4_cpu_suspend(unsigned long arg) { unsigned long tmp; unsigned long mask = 0xFFFFFFFF; diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 7238a63e24e2..b77d82665abb 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -321,9 +321,10 @@ static void omap34xx_save_context(u32 *save) *save++ = val; } -static void omap34xx_do_sram_idle(unsigned long save_state) +static int omap34xx_do_sram_idle(unsigned long save_state) { omap34xx_cpu_suspend(save_state); + return 0; } void omap_sram_idle(void) diff --git a/arch/arm/mach-pxa/include/mach/pm.h b/arch/arm/mach-pxa/include/mach/pm.h index a566720527cf..51558bcee999 100644 --- a/arch/arm/mach-pxa/include/mach/pm.h +++ b/arch/arm/mach-pxa/include/mach/pm.h @@ -22,8 +22,8 @@ struct pxa_cpu_pm_fns { extern struct pxa_cpu_pm_fns *pxa_cpu_pm_fns; /* sleep.S */ -extern void pxa25x_finish_suspend(unsigned long); -extern void pxa27x_finish_suspend(unsigned long); +extern int pxa25x_finish_suspend(unsigned long); +extern int pxa27x_finish_suspend(unsigned long); extern int pxa_pm_enter(suspend_state_t state); extern int pxa_pm_prepare(void); diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 9fe947b5d5f7..ef1c56a67afc 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -148,7 +148,7 @@ static void pxa3xx_cpu_pm_suspend(void) asm volatile("mra %Q0, %R0, acc0" : "=r" (acc0)); #endif - extern void pxa3xx_finish_suspend(unsigned long); + extern int pxa3xx_finish_suspend(unsigned long); /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */ CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM); diff --git a/arch/arm/mach-s3c2412/pm.c b/arch/arm/mach-s3c2412/pm.c index 9a1fb898db53..f4077efa51fa 100644 --- a/arch/arm/mach-s3c2412/pm.c +++ b/arch/arm/mach-s3c2412/pm.c @@ -37,7 +37,7 @@ extern void s3c2412_sleep_enter(void); -static void s3c2412_cpu_suspend(unsigned long arg) +static int s3c2412_cpu_suspend(unsigned long arg) { unsigned long tmp; @@ -48,6 +48,8 @@ static void s3c2412_cpu_suspend(unsigned long arg) __raw_writel(tmp, S3C2412_PWRCFG); s3c2412_sleep_enter(); + + panic("sleep resumed to originator?"); } static void s3c2412_pm_prepare(void) diff --git a/arch/arm/mach-s3c2416/pm.c b/arch/arm/mach-s3c2416/pm.c index 9e67a2a07a86..9ec54f1d8e75 100644 --- a/arch/arm/mach-s3c2416/pm.c +++ b/arch/arm/mach-s3c2416/pm.c @@ -24,7 +24,7 @@ extern void s3c2412_sleep_enter(void); -static void s3c2416_cpu_suspend(unsigned long arg) +static int s3c2416_cpu_suspend(unsigned long arg) { /* enable wakeup sources regardless of battery state */ __raw_writel(S3C2443_PWRCFG_SLEEP, S3C2443_PWRCFG); @@ -33,6 +33,8 @@ static void s3c2416_cpu_suspend(unsigned long arg) __raw_writel(0x2BED, S3C2443_PWRMODE); s3c2412_sleep_enter(); + + panic("sleep resumed to originator?"); } static void s3c2416_pm_prepare(void) diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c index 7cc1879af722..8bad64370689 100644 --- a/arch/arm/mach-s3c64xx/pm.c +++ b/arch/arm/mach-s3c64xx/pm.c @@ -112,7 +112,7 @@ void s3c_pm_save_core(void) * this. */ -static void s3c64xx_cpu_suspend(unsigned long arg) +static int s3c64xx_cpu_suspend(unsigned long arg) { unsigned long tmp; diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index cf9a1e9fb70d..bf85b8b259d5 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -33,7 +33,7 @@ #include #include -extern void sa1100_finish_suspend(unsigned long); +extern int sa1100_finish_suspend(unsigned long); #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h index 0a5b7faca836..f6749916d194 100644 --- a/arch/arm/plat-samsung/include/plat/pm.h +++ b/arch/arm/plat-samsung/include/plat/pm.h @@ -42,7 +42,7 @@ extern unsigned long s3c_irqwake_eintallow; /* per-cpu sleep functions */ extern void (*pm_cpu_prep)(void); -extern void (*pm_cpu_sleep)(unsigned long); +extern int (*pm_cpu_sleep)(unsigned long); /* Flags for PM Control */ @@ -54,7 +54,7 @@ extern unsigned char pm_uart_udivslot; /* true to save UART UDIVSLOT */ extern void s3c_cpu_resume(void); -extern void s3c2410_cpu_suspend(unsigned long); +extern int s3c2410_cpu_suspend(unsigned long); /* sleep save info */ diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index 69d6b040a019..5fa1742d019b 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -232,7 +232,7 @@ static void __maybe_unused s3c_pm_show_resume_irqs(int start, void (*pm_cpu_prep)(void); -void (*pm_cpu_sleep)(unsigned long); +int (*pm_cpu_sleep)(unsigned long); #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) -- cgit v1.2.3 From 02fe2845d6a837ab02f0738f6cf4591a02cc88d4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jun 2011 11:44:06 +0100 Subject: ARM: entry: avoid enabling interrupts in prefetch/data abort handlers Avoid enabling interrupts if the parent context had interrupts enabled in the abort handler assembly code, and move this into the breakpoint/ page/alignment fault handlers instead. This gets rid of some special-casing for the breakpoint fault handlers from the low level abort handler path. Acked-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 43 ++++++++++++++++++----------------------- arch/arm/kernel/entry-header.S | 19 ------------------ arch/arm/kernel/hw_breakpoint.c | 12 +++++------- arch/arm/mm/alignment.c | 3 +++ arch/arm/mm/fault.c | 4 ++++ 5 files changed, 31 insertions(+), 50 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index d644d0240ad3..c46bafa2f6dc 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -185,20 +185,15 @@ ENDPROC(__und_invalid) __dabt_svc: svc_entry - @ - @ get ready to re-enable interrupts if appropriate - @ - mrs r9, cpsr - tst r5, #PSR_I_BIT - biceq r9, r9, #PSR_I_BIT +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif dabt_helper @ - @ set desired IRQ state, then call main handler + @ call main handler @ - debug_entry r1 - msr cpsr_c, r9 mov r2, sp bl do_DataAbort @@ -211,6 +206,12 @@ __dabt_svc: @ restore SPSR and restart the instruction @ ldr r5, [sp, #S_PSR] +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__dabt_svc) @@ -307,16 +308,11 @@ ENDPROC(__und_svc) __pabt_svc: svc_entry - @ - @ re-enable interrupts if appropriate - @ - mrs r9, cpsr - tst r5, #PSR_I_BIT - biceq r9, r9, #PSR_I_BIT +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif pabt_helper - debug_entry r1 - msr cpsr_c, r9 @ Maybe enable interrupts mov r2, sp @ regs bl do_PrefetchAbort @ call abort handler @@ -329,6 +325,12 @@ __pabt_svc: @ restore SPSR and restart the instruction @ ldr r5, [sp, #S_PSR] +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__pabt_svc) @@ -412,11 +414,6 @@ __dabt_usr: kuser_cmpxchg_check dabt_helper - @ - @ IRQs on, then call the main handler - @ - debug_entry r1 - enable_irq mov r2, sp adr lr, BSYM(ret_from_exception) b do_DataAbort @@ -663,8 +660,6 @@ ENDPROC(__und_usr_unknown) __pabt_usr: usr_entry pabt_helper - debug_entry r1 - enable_irq @ Enable interrupts mov r2, sp @ regs bl do_PrefetchAbort @ call abort handler UNWIND(.fnend ) diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 051166c2a932..4d6ad8348e89 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -165,25 +165,6 @@ .endm #endif /* !CONFIG_THUMB2_KERNEL */ - @ - @ Debug exceptions are taken as prefetch or data aborts. - @ We must disable preemption during the handler so that - @ we can access the debug registers safely. - @ - .macro debug_entry, fsr -#if defined(CONFIG_HAVE_HW_BREAKPOINT) && defined(CONFIG_PREEMPT) - ldr r4, =0x40f @ mask out fsr.fs - and r5, r4, \fsr - cmp r5, #2 @ debug exception - bne 1f - get_thread_info r10 - ldr r6, [r10, #TI_PREEMPT] @ get preempt count - add r11, r6, #1 @ increment it - str r11, [r10, #TI_PREEMPT] -1: -#endif - .endm - /* * These are the registers used in the syscall handler, and allow us to * have in theory up to 7 arguments to a function - r0 to r6. diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 87acc25d7a3e..a927ca1f5566 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -796,7 +796,7 @@ unlock: /* * Called from either the Data Abort Handler [watchpoint] or the - * Prefetch Abort Handler [breakpoint] with preemption disabled. + * Prefetch Abort Handler [breakpoint] with interrupts disabled. */ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, struct pt_regs *regs) @@ -804,8 +804,10 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, int ret = 0; u32 dscr; - /* We must be called with preemption disabled. */ - WARN_ON(preemptible()); + preempt_disable(); + + if (interrupts_enabled(regs)) + local_irq_enable(); /* We only handle watchpoints and hardware breakpoints. */ ARM_DBG_READ(c1, 0, dscr); @@ -824,10 +826,6 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, ret = 1; /* Unhandled fault. */ } - /* - * Re-enable preemption after it was disabled in the - * low-level exception handling code. - */ preempt_enable(); return ret; diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 724ba3bce72c..be7c638b648b 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -727,6 +727,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) int isize = 4; int thumb2_32b = 0; + if (interrupts_enabled(regs)) + local_irq_enable(); + instrptr = instruction_pointer(regs); fs = get_fs(); diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index bc0e1d88fd3b..20e5d5120609 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -285,6 +285,10 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) tsk = current; mm = tsk->mm; + /* Enable interrupts if they were enabled in the parent context. */ + if (interrupts_enabled(regs)) + local_irq_enable(); + /* * If we're in an interrupt or have no user * context, we must not take the fault.. -- cgit v1.2.3 From df295df6c391e322a06dea0d2bc3d22debd15fb9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jun 2011 16:55:58 +0100 Subject: ARM: entry: instrument svc undefined exception handler with irqtrace Add irqtrace function calls to the undefined exception handler, so that we get sane lockdep traces from locking problems in undefined exception handlers. Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index c46bafa2f6dc..920dd3d07957 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -268,6 +268,10 @@ __und_svc: svc_entry #endif +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif + @ @ call emulation code, which returns using r9 if it has emulated @ the instruction, or the more conventional lr if we are to treat @@ -300,6 +304,12 @@ __und_svc: @ restore SPSR and restart the instruction @ ldr r5, [sp, #S_PSR] @ Get SVC cpsr +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__und_svc) -- cgit v1.2.3 From bc089602d206b2abc2d2e8e5324d90342cc0447b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jun 2011 18:28:19 +0100 Subject: ARM: entry: instrument usr exception handlers with irqsoff tracing As we no longer re-enable interrupts in these exception handlers, add the irqsoff tracing calls to them so that the kernel tracks the state more accurately. Note that these calls are conditional on IRQSOFF_TRACER: kernel ----------> user ---------> kernel ^ irqs enabled ^ irqs disabled No kernel code can run on the local CPU until we've re-entered the kernel through one of the exception handlers - and userspace can not take any locks etc. So, the kernel doesn't care about the IRQ mask state while userspace is running unless we're doing IRQ off latency tracing. So, we can (and do) avoid the overhead of updating the IRQ mask state on every kernel->user and user->kernel transition. Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 920dd3d07957..f863ee79093e 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -421,6 +421,11 @@ ENDPROC(__pabt_svc) .align 5 __dabt_usr: usr_entry + +#ifdef CONFIG_IRQSOFF_TRACER + bl trace_hardirqs_off +#endif + kuser_cmpxchg_check dabt_helper @@ -433,12 +438,12 @@ ENDPROC(__dabt_usr) .align 5 __irq_usr: usr_entry - kuser_cmpxchg_check #ifdef CONFIG_IRQSOFF_TRACER bl trace_hardirqs_off #endif + kuser_cmpxchg_check irq_handler get_thread_info tsk mov why, #0 @@ -451,6 +456,11 @@ ENDPROC(__irq_usr) .align 5 __und_usr: usr_entry + +#ifdef CONFIG_IRQSOFF_TRACER + bl trace_hardirqs_off +#endif + mov r2, r4 mov r3, r5 @@ -669,6 +679,11 @@ ENDPROC(__und_usr_unknown) .align 5 __pabt_usr: usr_entry + +#ifdef CONFIG_IRQSOFF_TRACER + bl trace_hardirqs_off +#endif + pabt_helper mov r2, sp @ regs bl do_PrefetchAbort @ call abort handler -- cgit v1.2.3 From f2741b78b607576f0c256604cb3d9256b3428a32 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jun 2011 17:35:19 +0100 Subject: ARM: entry: consolidate trace_hardirqs_off into (svc|usr)_entry macros All handlers now call trace_hardirqs_off, so move this common code into the (svc|usr)_entry assembler macros. Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 47 ++++++++------------------------------------ 1 file changed, 8 insertions(+), 39 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index f863ee79093e..a5b2c40d44e8 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -179,16 +179,15 @@ ENDPROC(__und_invalid) @ r6 - orig_r0 (see pt_regs definition in ptrace.h) @ stmia r7, {r2 - r6} - .endm - - .align 5 -__dabt_svc: - svc_entry #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off #endif + .endm + .align 5 +__dabt_svc: + svc_entry dabt_helper @ @@ -219,11 +218,6 @@ ENDPROC(__dabt_svc) .align 5 __irq_svc: svc_entry - -#ifdef CONFIG_TRACE_IRQFLAGS - bl trace_hardirqs_off -#endif - irq_handler #ifdef CONFIG_PREEMPT @@ -267,11 +261,6 @@ __und_svc: #else svc_entry #endif - -#ifdef CONFIG_TRACE_IRQFLAGS - bl trace_hardirqs_off -#endif - @ @ call emulation code, which returns using r9 if it has emulated @ the instruction, or the more conventional lr if we are to treat @@ -317,11 +306,6 @@ ENDPROC(__und_svc) .align 5 __pabt_svc: svc_entry - -#ifdef CONFIG_TRACE_IRQFLAGS - bl trace_hardirqs_off -#endif - pabt_helper mov r2, sp @ regs bl do_PrefetchAbort @ call abort handler @@ -401,6 +385,10 @@ ENDPROC(__pabt_svc) @ Clear FP to mark the first stack frame @ zero_fp + +#ifdef CONFIG_IRQSOFF_TRACER + bl trace_hardirqs_off +#endif .endm .macro kuser_cmpxchg_check @@ -421,11 +409,6 @@ ENDPROC(__pabt_svc) .align 5 __dabt_usr: usr_entry - -#ifdef CONFIG_IRQSOFF_TRACER - bl trace_hardirqs_off -#endif - kuser_cmpxchg_check dabt_helper @@ -438,11 +421,6 @@ ENDPROC(__dabt_usr) .align 5 __irq_usr: usr_entry - -#ifdef CONFIG_IRQSOFF_TRACER - bl trace_hardirqs_off -#endif - kuser_cmpxchg_check irq_handler get_thread_info tsk @@ -457,10 +435,6 @@ ENDPROC(__irq_usr) __und_usr: usr_entry -#ifdef CONFIG_IRQSOFF_TRACER - bl trace_hardirqs_off -#endif - mov r2, r4 mov r3, r5 @@ -679,11 +653,6 @@ ENDPROC(__und_usr_unknown) .align 5 __pabt_usr: usr_entry - -#ifdef CONFIG_IRQSOFF_TRACER - bl trace_hardirqs_off -#endif - pabt_helper mov r2, sp @ regs bl do_PrefetchAbort @ call abort handler -- cgit v1.2.3 From d9600c99c549732a501cb727157800623a06175d Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 26 Jun 2011 10:34:02 +0100 Subject: ARM: entry: re-allocate registers in irq entry assembly macros This avoids the irq entry assembly corrupting r5, thereby allowing it to be preserved through to the svc exit code. Signed-off-by: Russell King --- arch/arm/include/asm/entry-macro-multi.S | 14 +++++++------- arch/arm/kernel/entry-armv.S | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/entry-macro-multi.S b/arch/arm/include/asm/entry-macro-multi.S index 2da8547de6d6..2f1e2098dfe7 100644 --- a/arch/arm/include/asm/entry-macro-multi.S +++ b/arch/arm/include/asm/entry-macro-multi.S @@ -4,8 +4,8 @@ * Interrupt handling. Preserves r7, r8, r9 */ .macro arch_irq_handler_default - get_irqnr_preamble r5, lr -1: get_irqnr_and_base r0, r6, r5, lr + get_irqnr_preamble r6, lr +1: get_irqnr_and_base r0, r2, r6, lr movne r1, sp @ @ routine called with r0 = irq number, r1 = struct pt_regs * @@ -17,17 +17,17 @@ /* * XXX * - * this macro assumes that irqstat (r6) and base (r5) are + * this macro assumes that irqstat (r2) and base (r6) are * preserved from get_irqnr_and_base above */ - ALT_SMP(test_for_ipi r0, r6, r5, lr) + ALT_SMP(test_for_ipi r0, r2, r6, lr) ALT_UP_B(9997f) movne r1, sp adrne lr, BSYM(1b) bne do_IPI #ifdef CONFIG_LOCAL_TIMERS - test_for_ltirq r0, r6, r5, lr + test_for_ltirq r0, r2, r6, lr movne r0, sp adrne lr, BSYM(1b) bne do_local_timer @@ -40,7 +40,7 @@ .align 5 .global \symbol_name \symbol_name: - mov r4, lr + mov r8, lr arch_irq_handler_default - mov pc, r4 + mov pc, r8 .endm diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index a5b2c40d44e8..b17e57949d3b 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -29,16 +29,16 @@ #include /* - * Interrupt handling. Preserves r7, r8, r9 + * Interrupt handling. */ .macro irq_handler #ifdef CONFIG_MULTI_IRQ_HANDLER - ldr r5, =handle_arch_irq + ldr r1, =handle_arch_irq mov r0, sp - ldr r5, [r5] + ldr r1, [r1] adr lr, BSYM(9997f) - teq r5, #0 - movne pc, r5 + teq r1, #0 + movne pc, r1 #endif arch_irq_handler_default 9997: -- cgit v1.2.3 From 8dfe7ac96fedd4f5219879f63a8a546a33609daf Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 26 Jun 2011 12:37:35 +0100 Subject: ARM: entry: prefetch abort: tail-call the main prefetch abort handler Tail-call the main C prefetch abort handler code from the per-CPU helper code. Also note that the helper function becomes ABI compliant in terms of the registers preserved. Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 8 +++----- arch/arm/mm/pabort-legacy.S | 9 +++++---- arch/arm/mm/pabort-v6.S | 9 +++++---- arch/arm/mm/pabort-v7.S | 11 ++++++----- 4 files changed, 19 insertions(+), 18 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index b17e57949d3b..af2fba7a4cae 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -45,7 +45,7 @@ .endm .macro pabt_helper - @ PABORT handler takes fault address in r4 + @ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5 #ifdef MULTI_PABORT ldr ip, .LCprocfns mov lr, pc @@ -306,9 +306,8 @@ ENDPROC(__und_svc) .align 5 __pabt_svc: svc_entry - pabt_helper mov r2, sp @ regs - bl do_PrefetchAbort @ call abort handler + pabt_helper @ @ IRQs off again before pulling preserved data off the stack @@ -653,9 +652,8 @@ ENDPROC(__und_usr_unknown) .align 5 __pabt_usr: usr_entry - pabt_helper mov r2, sp @ regs - bl do_PrefetchAbort @ call abort handler + pabt_helper UNWIND(.fnend ) /* fall through */ /* diff --git a/arch/arm/mm/pabort-legacy.S b/arch/arm/mm/pabort-legacy.S index 8a5d8aaf2d5e..8bbff025269a 100644 --- a/arch/arm/mm/pabort-legacy.S +++ b/arch/arm/mm/pabort-legacy.S @@ -4,10 +4,11 @@ /* * Function: legacy_pabort * - * Params : r4 = address of aborted instruction + * Params : r2 = pt_regs + * : r4 = address of aborted instruction + * : r5 = psr for parent context * - * Returns : r0 = address of abort - * : r1 = Simulated IFSR with section translation fault status + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current prefetch abort. */ @@ -16,5 +17,5 @@ ENTRY(legacy_pabort) mov r0, r4 mov r1, #5 - mov pc, lr + b do_PrefetchAbort ENDPROC(legacy_pabort) diff --git a/arch/arm/mm/pabort-v6.S b/arch/arm/mm/pabort-v6.S index eaac1cb7c4cc..9627646ce783 100644 --- a/arch/arm/mm/pabort-v6.S +++ b/arch/arm/mm/pabort-v6.S @@ -4,10 +4,11 @@ /* * Function: v6_pabort * - * Params : r4 = address of aborted instruction + * Params : r2 = pt_regs + * : r4 = address of aborted instruction + * : r5 = psr for parent context * - * Returns : r0 = address of abort - * : r1 = IFSR + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current prefetch abort. */ @@ -16,5 +17,5 @@ ENTRY(v6_pabort) mov r0, r4 mrc p15, 0, r1, c5, c0, 1 @ get IFSR - mov pc, lr + b do_PrefetchAbort ENDPROC(v6_pabort) diff --git a/arch/arm/mm/pabort-v7.S b/arch/arm/mm/pabort-v7.S index b515e0b059b3..875761f44f3b 100644 --- a/arch/arm/mm/pabort-v7.S +++ b/arch/arm/mm/pabort-v7.S @@ -2,12 +2,13 @@ #include /* - * Function: v6_pabort + * Function: v7_pabort * - * Params : r4 = address of aborted instruction + * Params : r2 = pt_regs + * : r4 = address of aborted instruction + * : r5 = psr for parent context * - * Returns : r0 = address of abort - * : r1 = IFSR + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current prefetch abort. */ @@ -16,5 +17,5 @@ ENTRY(v7_pabort) mrc p15, 0, r0, c6, c0, 2 @ get IFAR mrc p15, 0, r1, c5, c0, 1 @ get IFSR - mov pc, lr + b do_PrefetchAbort ENDPROC(v7_pabort) -- cgit v1.2.3 From 3e287bec6fde088bff05ee7f998f53e8ac75b922 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 26 Jun 2011 14:35:07 +0100 Subject: ARM: entry: data abort: arrange for CPU abort helpers to take pc/psr in r4/r5 Re-jig the CPU abort helpers to take the PC/PSR in r4/r5 rather than r2/r3. Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 6 ++---- arch/arm/mm/abort-ev4.S | 8 +++----- arch/arm/mm/abort-ev4t.S | 8 ++++---- arch/arm/mm/abort-ev5t.S | 8 ++++---- arch/arm/mm/abort-ev5tj.S | 12 +++++------- arch/arm/mm/abort-ev6.S | 12 +++++------- arch/arm/mm/abort-ev7.S | 4 ++-- arch/arm/mm/abort-lv4t.S | 12 ++++++------ arch/arm/mm/abort-nommu.S | 4 ++-- arch/arm/mm/proc-arm6_7.S | 10 +++++----- 10 files changed, 38 insertions(+), 46 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index af2fba7a4cae..85298c093256 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -56,14 +56,12 @@ .endm .macro dabt_helper - mov r2, r4 - mov r3, r5 @ @ Call the processor-specific abort handler: @ - @ r2 - aborted context pc - @ r3 - aborted context cpsr + @ r4 - aborted context pc + @ r5 - aborted context psr @ @ The abort handler must return the aborted address in r0, and @ the fault status register in r1. r9 must be preserved. diff --git a/arch/arm/mm/abort-ev4.S b/arch/arm/mm/abort-ev4.S index 4f18f9e87bae..beb112bdc049 100644 --- a/arch/arm/mm/abort-ev4.S +++ b/arch/arm/mm/abort-ev4.S @@ -3,8 +3,8 @@ /* * Function: v4_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r4 = aborted context pc + * : r5 = aborted context psr * * Returns : r0 = address of abort * : r1 = FSR, bit 11 = write @@ -21,10 +21,8 @@ ENTRY(v4_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - ldr r3, [r2] @ read aborted ARM instruction + ldr r3, [r4] @ read aborted ARM instruction bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r3, #1 << 20 @ L = 1 -> write? orreq r1, r1, #1 << 11 @ yes. mov pc, lr - - diff --git a/arch/arm/mm/abort-ev4t.S b/arch/arm/mm/abort-ev4t.S index 9910123079ce..eaa4ac023959 100644 --- a/arch/arm/mm/abort-ev4t.S +++ b/arch/arm/mm/abort-ev4t.S @@ -4,8 +4,8 @@ /* * Function: v4t_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r4 = aborted context pc + * : r5 = aborted context psr * * Returns : r0 = address of abort * : r1 = FSR, bit 11 = write @@ -22,8 +22,8 @@ ENTRY(v4t_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - do_thumb_abort fsr=r1, pc=r2, psr=r3, tmp=r3 - ldreq r3, [r2] @ read aborted ARM instruction + do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 + ldreq r3, [r4] @ read aborted ARM instruction bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r3, #1 << 20 @ check write orreq r1, r1, #1 << 11 diff --git a/arch/arm/mm/abort-ev5t.S b/arch/arm/mm/abort-ev5t.S index 800e8d42d39e..97eee7c48019 100644 --- a/arch/arm/mm/abort-ev5t.S +++ b/arch/arm/mm/abort-ev5t.S @@ -4,8 +4,8 @@ /* * Function: v5t_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r4 = aborted context pc + * : r5 = aborted context psr * * Returns : r0 = address of abort * : r1 = FSR, bit 11 = write @@ -22,8 +22,8 @@ ENTRY(v5t_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - do_thumb_abort fsr=r1, pc=r2, psr=r3, tmp=r3 - ldreq r3, [r2] @ read aborted ARM instruction + do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 + ldreq r3, [r4] @ read aborted ARM instruction bic r1, r1, #1 << 11 @ clear bits 11 of FSR do_ldrd_abort tmp=r2, insn=r3 tst r3, #1 << 20 @ check write diff --git a/arch/arm/mm/abort-ev5tj.S b/arch/arm/mm/abort-ev5tj.S index bcb58d2fc11a..9a365cf1936f 100644 --- a/arch/arm/mm/abort-ev5tj.S +++ b/arch/arm/mm/abort-ev5tj.S @@ -4,8 +4,8 @@ /* * Function: v5tj_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r4 = aborted context pc + * : r5 = aborted context psr * * Returns : r0 = address of abort * : r1 = FSR, bit 11 = write @@ -23,13 +23,11 @@ ENTRY(v5tj_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR - tst r3, #PSR_J_BIT @ Java? + tst r5, #PSR_J_BIT @ Java? movne pc, lr - do_thumb_abort fsr=r1, pc=r2, psr=r3, tmp=r3 - ldreq r3, [r2] @ read aborted ARM instruction + do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 + ldreq r3, [r4] @ read aborted ARM instruction do_ldrd_abort tmp=r2, insn=r3 tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. mov pc, lr - - diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S index ef526e702a5c..52db4a3fc5f2 100644 --- a/arch/arm/mm/abort-ev6.S +++ b/arch/arm/mm/abort-ev6.S @@ -4,8 +4,8 @@ /* * Function: v6_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r4 = aborted context pc + * : r5 = aborted context psr * * Returns : r0 = address of abort * : r1 = FSR, bit 11 = write @@ -33,10 +33,10 @@ ENTRY(v6_early_abort) * The test below covers all the write situations, including Java bytecodes */ bic r1, r1, #1 << 11 @ clear bit 11 of FSR - tst r3, #PSR_J_BIT @ Java? + tst r5, #PSR_J_BIT @ Java? movne pc, lr - do_thumb_abort fsr=r1, pc=r2, psr=r3, tmp=r3 - ldreq r3, [r2] @ read aborted ARM instruction + do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 + ldreq r3, [r4] @ read aborted ARM instruction #ifdef CONFIG_CPU_ENDIAN_BE8 reveq r3, r3 #endif @@ -44,5 +44,3 @@ ENTRY(v6_early_abort) tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. mov pc, lr - - diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S index ec88b157d3bb..6cb51431a859 100644 --- a/arch/arm/mm/abort-ev7.S +++ b/arch/arm/mm/abort-ev7.S @@ -3,8 +3,8 @@ /* * Function: v7_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r4 = aborted context pc + * : r5 = aborted context psr * * Returns : r0 = address of abort * : r1 = FSR, bit 11 = write diff --git a/arch/arm/mm/abort-lv4t.S b/arch/arm/mm/abort-lv4t.S index 9fb7b0e25ea1..fea7514225a6 100644 --- a/arch/arm/mm/abort-lv4t.S +++ b/arch/arm/mm/abort-lv4t.S @@ -3,8 +3,8 @@ /* * Function: v4t_late_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r4 = aborted context pc + * : r5 = aborted context psr * * Returns : r0 = address of abort * : r1 = FSR, bit 11 = write @@ -18,7 +18,7 @@ * picture. Unfortunately, this does happen. We live with it. */ ENTRY(v4t_late_abort) - tst r3, #PSR_T_BIT @ check for thumb mode + tst r5, #PSR_T_BIT @ check for thumb mode #ifdef CONFIG_CPU_CP15_MMU mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR @@ -28,7 +28,7 @@ ENTRY(v4t_late_abort) mov r1, #0 #endif bne .data_thumb_abort - ldr r8, [r2] @ read arm instruction + ldr r8, [r4] @ read arm instruction tst r8, #1 << 20 @ L = 1 -> write? orreq r1, r1, #1 << 11 @ yes. and r7, r8, #15 << 24 @@ -52,7 +52,7 @@ ENTRY(v4t_late_abort) /* e */ b .data_unknown /* f */ .data_unknown: @ Part of jumptable - mov r0, r2 + mov r0, r4 mov r1, r8 mov r2, sp bl baddataabort @@ -159,7 +159,7 @@ ENTRY(v4t_late_abort) b .data_unknown @ F: MUL? .data_thumb_abort: - ldrh r8, [r2] @ read instruction + ldrh r8, [r4] @ read instruction tst r8, #1 << 11 @ L = 1 -> write? orreq r1, r1, #1 << 8 @ yes and r7, r8, #15 << 12 diff --git a/arch/arm/mm/abort-nommu.S b/arch/arm/mm/abort-nommu.S index 625e580945b5..9eaef6f846c3 100644 --- a/arch/arm/mm/abort-nommu.S +++ b/arch/arm/mm/abort-nommu.S @@ -3,8 +3,8 @@ /* * Function: nommu_early_abort * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR + * Params : r4 = aborted context pc + * : r5 = aborted context psr * * Returns : r0 = 0 (abort address) * : r1 = 0 (FSR) diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S index 5f79dc4ce3fb..e7be700db08c 100644 --- a/arch/arm/mm/proc-arm6_7.S +++ b/arch/arm/mm/proc-arm6_7.S @@ -29,8 +29,8 @@ ENTRY(cpu_arm7_dcache_clean_area) /* * Function: arm6_7_data_abort () * - * Params : r2 = address of aborted instruction - * : sp = pointer to registers + * Params : r4 = aborted context pc + * : r5 = aborted context psr * * Purpose : obtain information about current aborted instruction * @@ -41,7 +41,7 @@ ENTRY(cpu_arm7_dcache_clean_area) ENTRY(cpu_arm7_data_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - ldr r8, [r2] @ read arm instruction + ldr r8, [r4] @ read arm instruction tst r8, #1 << 20 @ L = 0 -> write? orreq r1, r1, #1 << 11 @ yes. and r7, r8, #15 << 24 @@ -65,7 +65,7 @@ ENTRY(cpu_arm7_data_abort) /* e */ b .data_unknown /* f */ .data_unknown: @ Part of jumptable - mov r0, r2 + mov r0, r4 mov r1, r8 mov r2, sp bl baddataabort @@ -74,7 +74,7 @@ ENTRY(cpu_arm7_data_abort) ENTRY(cpu_arm6_data_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - ldr r8, [r2] @ read arm instruction + ldr r8, [r4] @ read arm instruction tst r8, #1 << 20 @ L = 0 -> write? orreq r1, r1, #1 << 11 @ yes. and r7, r8, #14 << 24 -- cgit v1.2.3 From da7404725781bc7c736e10cae5521e5604e222a5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 26 Jun 2011 16:01:26 +0100 Subject: ARM: entry: data abort: tail-call the main data abort handler Tail-call the main C data abort handler code from the per-CPU helper code. Update the comments in the code wrt the new calling and return register state. Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 14 ++++---------- arch/arm/mm/abort-ev4.S | 11 ++++------- arch/arm/mm/abort-ev4t.S | 11 ++++------- arch/arm/mm/abort-ev5t.S | 11 ++++------- arch/arm/mm/abort-ev5tj.S | 13 +++++-------- arch/arm/mm/abort-ev6.S | 13 +++++-------- arch/arm/mm/abort-ev7.S | 15 ++++++--------- arch/arm/mm/abort-lv4t.S | 43 +++++++++++++++++++++---------------------- arch/arm/mm/abort-macro.S | 4 ++-- arch/arm/mm/abort-nommu.S | 8 ++++---- arch/arm/mm/proc-arm6_7.S | 29 ++++++++++++++--------------- 11 files changed, 73 insertions(+), 99 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 85298c093256..bbdd443b8055 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -60,6 +60,7 @@ @ @ Call the processor-specific abort handler: @ + @ r2 - pt_regs @ r4 - aborted context pc @ r5 - aborted context psr @ @@ -186,13 +187,8 @@ ENDPROC(__und_invalid) .align 5 __dabt_svc: svc_entry - dabt_helper - - @ - @ call main handler - @ mov r2, sp - bl do_DataAbort + dabt_helper @ @ IRQs off again before pulling preserved data off the stack @@ -407,11 +403,9 @@ ENDPROC(__pabt_svc) __dabt_usr: usr_entry kuser_cmpxchg_check - dabt_helper - mov r2, sp - adr lr, BSYM(ret_from_exception) - b do_DataAbort + dabt_helper + b ret_from_exception UNWIND(.fnend ) ENDPROC(__dabt_usr) diff --git a/arch/arm/mm/abort-ev4.S b/arch/arm/mm/abort-ev4.S index beb112bdc049..54473cd4aba9 100644 --- a/arch/arm/mm/abort-ev4.S +++ b/arch/arm/mm/abort-ev4.S @@ -3,14 +3,11 @@ /* * Function: v4_early_abort * - * Params : r4 = aborted context pc + * Params : r2 = pt_regs + * : r4 = aborted context pc * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -25,4 +22,4 @@ ENTRY(v4_early_abort) bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r3, #1 << 20 @ L = 1 -> write? orreq r1, r1, #1 << 11 @ yes. - mov pc, lr + b do_DataAbort diff --git a/arch/arm/mm/abort-ev4t.S b/arch/arm/mm/abort-ev4t.S index eaa4ac023959..9da704e7b86e 100644 --- a/arch/arm/mm/abort-ev4t.S +++ b/arch/arm/mm/abort-ev4t.S @@ -4,14 +4,11 @@ /* * Function: v4t_early_abort * - * Params : r4 = aborted context pc + * Params : r2 = pt_regs + * : r4 = aborted context pc * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -27,4 +24,4 @@ ENTRY(v4t_early_abort) bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r3, #1 << 20 @ check write orreq r1, r1, #1 << 11 - mov pc, lr + b do_DataAbort diff --git a/arch/arm/mm/abort-ev5t.S b/arch/arm/mm/abort-ev5t.S index 751391a5de59..a0908d4653a3 100644 --- a/arch/arm/mm/abort-ev5t.S +++ b/arch/arm/mm/abort-ev5t.S @@ -4,14 +4,11 @@ /* * Function: v5t_early_abort * - * Params : r4 = aborted context pc + * Params : r2 = pt_regs + * : r4 = aborted context pc * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -28,4 +25,4 @@ ENTRY(v5t_early_abort) do_ldrd_abort tmp=ip, insn=r3 tst r3, #1 << 20 @ check write orreq r1, r1, #1 << 11 - mov pc, lr + b do_DataAbort diff --git a/arch/arm/mm/abort-ev5tj.S b/arch/arm/mm/abort-ev5tj.S index ccfbc937054d..4006b7a61264 100644 --- a/arch/arm/mm/abort-ev5tj.S +++ b/arch/arm/mm/abort-ev5tj.S @@ -4,14 +4,11 @@ /* * Function: v5tj_early_abort * - * Params : r4 = aborted context pc + * Params : r2 = pt_regs + * : r4 = aborted context pc * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -24,10 +21,10 @@ ENTRY(v5tj_early_abort) mrc p15, 0, r0, c6, c0, 0 @ get FAR bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r5, #PSR_J_BIT @ Java? - movne pc, lr + bne do_DataAbort do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 ldreq r3, [r4] @ read aborted ARM instruction do_ldrd_abort tmp=ip, insn=r3 tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. - mov pc, lr + b do_DataAbort diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S index b64d886c0be7..ff1f7cc11f87 100644 --- a/arch/arm/mm/abort-ev6.S +++ b/arch/arm/mm/abort-ev6.S @@ -4,14 +4,11 @@ /* * Function: v6_early_abort * - * Params : r4 = aborted context pc + * Params : r2 = pt_regs + * : r4 = aborted context pc * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. * Note: we read user space. This means we might cause a data @@ -34,7 +31,7 @@ ENTRY(v6_early_abort) */ bic r1, r1, #1 << 11 @ clear bit 11 of FSR tst r5, #PSR_J_BIT @ Java? - movne pc, lr + bne do_DataAbort do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 ldreq r3, [r4] @ read aborted ARM instruction #ifdef CONFIG_CPU_ENDIAN_BE8 @@ -43,4 +40,4 @@ ENTRY(v6_early_abort) do_ldrd_abort tmp=ip, insn=r3 tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. - mov pc, lr + b do_DataAbort diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S index 6f98b3a17ac7..703375277ba6 100644 --- a/arch/arm/mm/abort-ev7.S +++ b/arch/arm/mm/abort-ev7.S @@ -3,14 +3,11 @@ /* * Function: v7_early_abort * - * Params : r4 = aborted context pc + * Params : r2 = pt_regs + * : r4 = aborted context pc * : r5 = aborted context psr * - * Returns : r0 = address of abort - * : r1 = FSR, bit 11 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers + * Returns : r4 - r11, r13 preserved * * Purpose : obtain information about current aborted instruction. */ @@ -37,18 +34,18 @@ ENTRY(v7_early_abort) ldr r3, =0x40d @ On permission fault and r3, r1, r3 cmp r3, #0x0d - movne pc, lr + bne do_DataAbort mcr p15, 0, r0, c7, c8, 0 @ Retranslate FAR isb mrc p15, 0, ip, c7, c4, 0 @ Read the PAR and r3, ip, #0x7b @ On translation fault cmp r3, #0x0b - movne pc, lr + bne do_DataAbort bic r1, r1, #0xf @ Fix up FSR FS[5:0] and ip, ip, #0x7e orr r1, r1, ip, LSR #1 #endif - mov pc, lr + b do_DataAbort ENDPROC(v7_early_abort) diff --git a/arch/arm/mm/abort-lv4t.S b/arch/arm/mm/abort-lv4t.S index d032b1f2067b..d432f31cdab5 100644 --- a/arch/arm/mm/abort-lv4t.S +++ b/arch/arm/mm/abort-lv4t.S @@ -3,7 +3,8 @@ /* * Function: v4t_late_abort * - * Params : r4 = aborted context pc + * Params : r2 = pt_regs + * : r4 = aborted context pc * : r5 = aborted context psr * * Returns : r0 = address of abort @@ -47,20 +48,18 @@ ENTRY(v4t_late_abort) /* 9 */ b .data_arm_ldmstm @ ldm*b rn, /* a */ b .data_unknown /* b */ b .data_unknown -/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m -/* d */ mov pc, lr @ ldc rd, [rn, #m] +/* c */ b do_DataAbort @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ b do_DataAbort @ ldc rd, [rn, #m] /* e */ b .data_unknown /* f */ .data_unknown: @ Part of jumptable mov r0, r4 mov r1, r8 - mov r2, sp - bl baddataabort - b ret_from_exception + b baddataabort .data_arm_ldmstm: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup mov r7, #0x11 orr r7, r7, #0x1100 and r6, r8, r7 @@ -79,11 +78,11 @@ ENTRY(v4t_late_abort) subne r7, r7, r6, lsl #2 @ Undo increment addeq r7, r7, r6, lsl #2 @ Undo decrement str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + b do_DataAbort .data_arm_lateldrhpre: tst r8, #1 << 21 @ Check writeback bit - moveq pc, lr @ No writeback -> no fixup + beq do_DataAbort @ No writeback -> no fixup .data_arm_lateldrhpost: and r5, r8, #0x00f @ get Rm / low nibble of immediate value tst r8, #1 << 22 @ if (immediate offset) @@ -97,25 +96,25 @@ ENTRY(v4t_late_abort) subne r7, r7, r6 @ Undo incrmenet addeq r7, r7, r6 @ Undo decrement str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + b do_DataAbort .data_arm_lateldrpreconst: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup .data_arm_lateldrpostconst: movs r9, r8, lsl #20 @ Get offset - moveq pc, lr @ zero -> no fixup + beq do_DataAbort @ zero -> no fixup and r5, r8, #15 << 16 @ Extract 'n' from instruction ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit subne r7, r7, r9, lsr #20 @ Undo increment addeq r7, r7, r9, lsr #20 @ Undo decrement str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + b do_DataAbort .data_arm_lateldrprereg: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup .data_arm_lateldrpostreg: and r7, r8, #15 @ Extract 'm' from instruction ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' @@ -172,10 +171,10 @@ ENTRY(v4t_late_abort) /* 3 */ b .data_unknown /* 4 */ b .data_unknown /* 5 */ b .data_thumb_reg -/* 6 */ mov pc, lr -/* 7 */ mov pc, lr -/* 8 */ mov pc, lr -/* 9 */ mov pc, lr +/* 6 */ b do_DataAbort +/* 7 */ b do_DataAbort +/* 8 */ b do_DataAbort +/* 9 */ b do_DataAbort /* A */ b .data_unknown /* B */ b .data_thumb_pushpop /* C */ b .data_thumb_ldmstm @@ -185,10 +184,10 @@ ENTRY(v4t_late_abort) .data_thumb_reg: tst r8, #1 << 9 - moveq pc, lr + beq do_DataAbort tst r8, #1 << 10 @ If 'S' (signed) bit is set movne r1, #0 @ it must be a load instr - mov pc, lr + b do_DataAbort .data_thumb_pushpop: tst r8, #1 << 10 @@ -207,7 +206,7 @@ ENTRY(v4t_late_abort) addeq r7, r7, r6, lsl #2 @ increment SP if PUSH subne r7, r7, r6, lsl #2 @ decrement SP if POP str r7, [sp, #13 << 2] - mov pc, lr + b do_DataAbort .data_thumb_ldmstm: and r6, r8, #0x55 @ hweight8(r8) @@ -222,4 +221,4 @@ ENTRY(v4t_late_abort) and r6, r6, #15 @ number of regs to transfer sub r7, r7, r6, lsl #2 @ always decrement str r7, [sp, r5, lsr #6] - mov pc, lr + b do_DataAbort diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S index af97a10bc5ed..52162d59407a 100644 --- a/arch/arm/mm/abort-macro.S +++ b/arch/arm/mm/abort-macro.S @@ -18,7 +18,7 @@ orreq \tmp, \tmp, #1 << 11 @ Set L-bit if yes tst \tmp, #1 << 11 @ L = 0 -> write orreq \psr, \psr, #1 << 11 @ yes. - mov pc, lr + b do_DataAbort not_thumb: .endm @@ -34,7 +34,7 @@ not_thumb: bne not_ldrd and \tmp, \insn, #0x000000f0 @ [7:4] == 1101 cmp \tmp, #0x000000d0 - moveq pc, lr + beq do_DataAbort not_ldrd: .endm diff --git a/arch/arm/mm/abort-nommu.S b/arch/arm/mm/abort-nommu.S index 9eaef6f846c3..119cb479c2ab 100644 --- a/arch/arm/mm/abort-nommu.S +++ b/arch/arm/mm/abort-nommu.S @@ -3,11 +3,11 @@ /* * Function: nommu_early_abort * - * Params : r4 = aborted context pc + * Params : r2 = pt_regs + * : r4 = aborted context pc * : r5 = aborted context psr * - * Returns : r0 = 0 (abort address) - * : r1 = 0 (FSR) + * Returns : r4 - r11, r13 preserved * * Note: There is no FSR/FAR on !CPU_CP15_MMU cores. * Just fill zero into the registers. @@ -16,5 +16,5 @@ ENTRY(nommu_early_abort) mov r0, #0 @ clear r0, r1 (no FSR/FAR) mov r1, #0 - mov pc, lr + b do_DataAbort ENDPROC(nommu_early_abort) diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S index d4c328ecf3ba..d755d5b83898 100644 --- a/arch/arm/mm/proc-arm6_7.S +++ b/arch/arm/mm/proc-arm6_7.S @@ -29,7 +29,8 @@ ENTRY(cpu_arm7_dcache_clean_area) /* * Function: arm6_7_data_abort () * - * Params : r4 = aborted context pc + * Params : r2 = pt_regs + * : r4 = aborted context pc * : r5 = aborted context psr * * Purpose : obtain information about current aborted instruction @@ -49,7 +50,7 @@ ENTRY(cpu_arm7_data_abort) nop /* 0 */ b .data_unknown -/* 1 */ mov pc, lr @ swp +/* 1 */ b do_DataAbort @ swp /* 2 */ b .data_unknown /* 3 */ b .data_unknown /* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m @@ -60,16 +61,14 @@ ENTRY(cpu_arm7_data_abort) /* 9 */ b .data_arm_ldmstm @ ldm*b rn, /* a */ b .data_unknown /* b */ b .data_unknown -/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m -/* d */ mov pc, lr @ ldc rd, [rn, #m] +/* c */ b do_DataAbort @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ b do_DataAbort @ ldc rd, [rn, #m] /* e */ b .data_unknown /* f */ .data_unknown: @ Part of jumptable mov r0, r4 mov r1, r8 - mov r2, sp - bl baddataabort - b ret_from_exception + b baddataabort ENTRY(cpu_arm6_data_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR @@ -79,11 +78,11 @@ ENTRY(cpu_arm6_data_abort) orreq r1, r1, #1 << 11 @ yes. and r7, r8, #14 << 24 teq r7, #8 << 24 @ was it ldm/stm - movne pc, lr + bne do_DataAbort .data_arm_ldmstm: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup mov r7, #0x11 orr r7, r7, #0x1100 and r6, r8, r7 @@ -102,7 +101,7 @@ ENTRY(cpu_arm6_data_abort) subne r7, r7, r6, lsl #2 @ Undo increment addeq r7, r7, r6, lsl #2 @ Undo decrement str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + b do_DataAbort .data_arm_apply_r6_and_rn: and r5, r8, #15 << 16 @ Extract 'n' from instruction @@ -111,25 +110,25 @@ ENTRY(cpu_arm6_data_abort) subne r7, r7, r6 @ Undo incrmenet addeq r7, r7, r6 @ Undo decrement str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + b do_DataAbort .data_arm_lateldrpreconst: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup .data_arm_lateldrpostconst: movs r9, r8, lsl #20 @ Get offset - moveq pc, lr @ zero -> no fixup + beq do_DataAbort @ zero -> no fixup and r5, r8, #15 << 16 @ Extract 'n' from instruction ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' tst r8, #1 << 23 @ Check U bit subne r7, r7, r9, lsr #20 @ Undo increment addeq r7, r7, r9, lsr #20 @ Undo decrement str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr + b do_DataAbort .data_arm_lateldrprereg: tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup + beq do_DataAbort @ no writeback -> no fixup .data_arm_lateldrpostreg: and r7, r8, #15 @ Extract 'm' from instruction ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' -- cgit v1.2.3 From 30891c90d81133179cc47eb77c30764a3b5dad5c Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 26 Jun 2011 12:47:08 +0100 Subject: ARM: entry: no need to reload the SPSR value from struct pt_regs The SVC IRQ, prefetch and data abort handlers preserve the SPSR value via r5 across the exception. Rather than re-loading it from pt_regs, use the preserved value instead. Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index bbdd443b8055..fa02a22a4c4b 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -195,10 +195,6 @@ __dabt_svc: @ disable_irq_notrace - @ - @ restore SPSR and restart the instruction - @ - ldr r5, [sp, #S_PSR] #ifdef CONFIG_TRACE_IRQFLAGS tst r5, #PSR_I_BIT bleq trace_hardirqs_on @@ -223,7 +219,7 @@ __irq_svc: tst r0, #_TIF_NEED_RESCHED blne svc_preempt #endif - ldr r5, [sp, #S_PSR] + #ifdef CONFIG_TRACE_IRQFLAGS @ The parent context IRQs must have been enabled to get here in @ the first place, so there's no point checking the PSR I bit. @@ -308,10 +304,6 @@ __pabt_svc: @ disable_irq_notrace - @ - @ restore SPSR and restart the instruction - @ - ldr r5, [sp, #S_PSR] #ifdef CONFIG_TRACE_IRQFLAGS tst r5, #PSR_I_BIT bleq trace_hardirqs_on -- cgit v1.2.3 From f4f38430c94c38187db73a2cf3892cc8b12a2713 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 1 Jul 2011 14:38:12 +0100 Subject: ARM: 6989/1: perf: do not start the PMU when no events are present armpmu_enable can be called in situations where no events are present (for example, from the event rotation tick after a profiled task has exited). In this case, we currently start the PMU anyway which may leave it active inevitably without any events being monitored. This patch adds a simple check to the enabling code so that we avoid starting the PMU when no events are present. Cc: Reported-by: Ashwin Chaugle Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/perf_event.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index d53c0abc4dd3..2b5b1421596c 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -583,7 +583,7 @@ static int armpmu_event_init(struct perf_event *event) static void armpmu_enable(struct pmu *pmu) { /* Enable all of the perf events on hardware. */ - int idx; + int idx, enabled = 0; struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); if (!armpmu) @@ -596,9 +596,11 @@ static void armpmu_enable(struct pmu *pmu) continue; armpmu->enable(&event->hw, idx); + enabled = 1; } - armpmu->start(); + if (enabled) + armpmu->start(); } static void armpmu_disable(struct pmu *pmu) -- cgit v1.2.3 From 0371d3f7e8f1cddaee1f215e42c09a40e235d810 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 5 Jul 2011 19:58:29 +0100 Subject: ARM: move memory layout sanity checking before meminfo initialization Ensure that the meminfo array is sanity checked before we pass the memory to memblock. This helps to ensure that memblock and meminfo agree on the dimensions of memory, especially when more memory is passed than the kernel can deal with. Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/kernel/setup.c | 2 ++ arch/arm/mm/mmu.c | 5 +++-- arch/arm/mm/nommu.c | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index ed11fb08b05a..acbb447ac6b5 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -73,6 +73,7 @@ __setup("fpe=", fpe_setup); #endif extern void paging_init(struct machine_desc *desc); +extern void sanity_check_meminfo(void); extern void reboot_setup(char *str); unsigned int processor_id; @@ -900,6 +901,7 @@ void __init setup_arch(char **cmdline_p) parse_early_param(); + sanity_check_meminfo(); arm_memblock_init(&meminfo, mdesc); paging_init(mdesc); diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 9d9e736c2b4f..594d677b92c8 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -759,7 +759,7 @@ early_param("vmalloc", early_vmalloc); static phys_addr_t lowmem_limit __initdata = 0; -static void __init sanity_check_meminfo(void) +void __init sanity_check_meminfo(void) { int i, j, highmem = 0; @@ -1032,8 +1032,9 @@ void __init paging_init(struct machine_desc *mdesc) { void *zero_page; + memblock_set_current_limit(lowmem_limit); + build_mem_type_table(); - sanity_check_meminfo(); prepare_page_table(); map_lowmem(); devicemaps_init(mdesc); diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index 687d02319a41..941a98c9e8aa 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c @@ -27,6 +27,10 @@ void __init arm_mm_memblock_reserve(void) memblock_reserve(CONFIG_VECTORS_BASE, PAGE_SIZE); } +void __init sanity_check_meminfo(void) +{ +} + /* * paging_init() sets up the page tables, initialises the zone memory * maps, and sets up the zero page, bad page and bad page tables. -- cgit v1.2.3 From 9715efb8dc9ffa629bf5a1215b11bf2f2f29908b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Jul 2011 08:23:06 +0100 Subject: ARM: 6984/1: enhance TCM robustness The PB11MPCore reports "3" DTCM banks, but anything above 2 is an "undefined" value, so push this to become 0. Further add some checks if code is compiled to TCM even if there is no D/ITCM present in the system, and if we can really fit the compiled code. We don't do the BUG() since it's not helpful, it's better to deal with non-present TCM dynamically. If there is nothing compiled to the TCM and no TCM is detected, it will now just shut up even if TCM support is enabled. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/kernel/tcm.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c index f5cf660eefcc..d402d4829524 100644 --- a/arch/arm/kernel/tcm.c +++ b/arch/arm/kernel/tcm.c @@ -134,6 +134,10 @@ static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks, (tcm_region & 1) ? "" : "not "); } + /* Not much fun you can do with a size 0 bank */ + if (tcm_size == 0) + return 0; + /* Force move the TCM bank to where we want it, enable */ tcm_region = *offset | (tcm_region & 0x00000ffeU) | 1; @@ -165,12 +169,20 @@ void __init tcm_init(void) u32 tcm_status = read_cpuid_tcmstatus(); u8 dtcm_banks = (tcm_status >> 16) & 0x03; u8 itcm_banks = (tcm_status & 0x03); + size_t dtcm_code_sz = &__edtcm_data - &__sdtcm_data; + size_t itcm_code_sz = &__eitcm_text - &__sitcm_text; char *start; char *end; char *ram; int ret; int i; + /* Values greater than 2 for D/ITCM banks are "reserved" */ + if (dtcm_banks > 2) + dtcm_banks = 0; + if (itcm_banks > 2) + itcm_banks = 0; + /* Setup DTCM if present */ if (dtcm_banks > 0) { for (i = 0; i < dtcm_banks; i++) { @@ -178,6 +190,13 @@ void __init tcm_init(void) if (ret) return; } + /* This means you compiled more code than fits into DTCM */ + if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) { + pr_info("CPU DTCM: %u bytes of code compiled to " + "DTCM but only %lu bytes of DTCM present\n", + dtcm_code_sz, (dtcm_end - DTCM_OFFSET)); + goto no_dtcm; + } dtcm_res.end = dtcm_end - 1; request_resource(&iomem_resource, &dtcm_res); dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET; @@ -186,12 +205,15 @@ void __init tcm_init(void) start = &__sdtcm_data; end = &__edtcm_data; ram = &__dtcm_start; - /* This means you compiled more code than fits into DTCM */ - BUG_ON((end - start) > (dtcm_end - DTCM_OFFSET)); - memcpy(start, ram, (end-start)); - pr_debug("CPU DTCM: copied data from %p - %p\n", start, end); + memcpy(start, ram, dtcm_code_sz); + pr_debug("CPU DTCM: copied data from %p - %p\n", + start, end); + } else if (dtcm_code_sz) { + pr_info("CPU DTCM: %u bytes of code compiled to DTCM but no " + "DTCM banks present in CPU\n", dtcm_code_sz); } +no_dtcm: /* Setup ITCM if present */ if (itcm_banks > 0) { for (i = 0; i < itcm_banks; i++) { @@ -199,6 +221,13 @@ void __init tcm_init(void) if (ret) return; } + /* This means you compiled more code than fits into ITCM */ + if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) { + pr_info("CPU ITCM: %u bytes of code compiled to " + "ITCM but only %lu bytes of ITCM present\n", + itcm_code_sz, (itcm_end - ITCM_OFFSET)); + return; + } itcm_res.end = itcm_end - 1; request_resource(&iomem_resource, &itcm_res); itcm_iomap[0].length = itcm_end - ITCM_OFFSET; @@ -207,10 +236,12 @@ void __init tcm_init(void) start = &__sitcm_text; end = &__eitcm_text; ram = &__itcm_start; - /* This means you compiled more code than fits into ITCM */ - BUG_ON((end - start) > (itcm_end - ITCM_OFFSET)); - memcpy(start, ram, (end-start)); - pr_debug("CPU ITCM: copied code from %p - %p\n", start, end); + memcpy(start, ram, itcm_code_sz); + pr_debug("CPU ITCM: copied code from %p - %p\n", + start, end); + } else if (itcm_code_sz) { + pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no " + "ITCM banks present in CPU\n", itcm_code_sz); } } -- cgit v1.2.3 From 201043f227576d42529ddb340746a060a00f57f6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Jul 2011 08:23:36 +0100 Subject: ARM: 6985/1: export functions to determine the presence of I/DTCM By allowing code to detect whether DTCM or ITCM is present, code paths involving TCM can be avoided when running on platforms that lack it. This is good for creating single kernels across several archs, if some of them utilize TCM but others don't. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/include/asm/tcm.h | 2 ++ arch/arm/kernel/tcm.c | 21 ++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/include/asm/tcm.h b/arch/arm/include/asm/tcm.h index 5929ef5d927a..8578d726ad78 100644 --- a/arch/arm/include/asm/tcm.h +++ b/arch/arm/include/asm/tcm.h @@ -27,5 +27,7 @@ void *tcm_alloc(size_t len); void tcm_free(void *addr, size_t len); +bool tcm_dtcm_present(void); +bool tcm_itcm_present(void); #endif diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c index d402d4829524..30e302d33e0a 100644 --- a/arch/arm/kernel/tcm.c +++ b/arch/arm/kernel/tcm.c @@ -19,6 +19,8 @@ #include "tcm.h" static struct gen_pool *tcm_pool; +static bool dtcm_present; +static bool itcm_present; /* TCM section definitions from the linker */ extern char __itcm_start, __sitcm_text, __eitcm_text; @@ -90,6 +92,18 @@ void tcm_free(void *addr, size_t len) } EXPORT_SYMBOL(tcm_free); +bool tcm_dtcm_present(void) +{ + return dtcm_present; +} +EXPORT_SYMBOL(tcm_dtcm_present); + +bool tcm_itcm_present(void) +{ + return itcm_present; +} +EXPORT_SYMBOL(tcm_itcm_present); + static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks, u32 *offset) { @@ -208,6 +222,7 @@ void __init tcm_init(void) memcpy(start, ram, dtcm_code_sz); pr_debug("CPU DTCM: copied data from %p - %p\n", start, end); + dtcm_present = true; } else if (dtcm_code_sz) { pr_info("CPU DTCM: %u bytes of code compiled to DTCM but no " "DTCM banks present in CPU\n", dtcm_code_sz); @@ -239,6 +254,7 @@ no_dtcm: memcpy(start, ram, itcm_code_sz); pr_debug("CPU ITCM: copied code from %p - %p\n", start, end); + itcm_present = true; } else if (itcm_code_sz) { pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no " "ITCM banks present in CPU\n", itcm_code_sz); @@ -252,7 +268,6 @@ no_dtcm: */ static int __init setup_tcm_pool(void) { - u32 tcm_status = read_cpuid_tcmstatus(); u32 dtcm_pool_start = (u32) &__edtcm_data; u32 itcm_pool_start = (u32) &__eitcm_text; int ret; @@ -267,7 +282,7 @@ static int __init setup_tcm_pool(void) pr_debug("Setting up TCM memory pool\n"); /* Add the rest of DTCM to the TCM pool */ - if (tcm_status & (0x03 << 16)) { + if (dtcm_present) { if (dtcm_pool_start < dtcm_end) { ret = gen_pool_add(tcm_pool, dtcm_pool_start, dtcm_end - dtcm_pool_start, -1); @@ -284,7 +299,7 @@ static int __init setup_tcm_pool(void) } /* Add the rest of ITCM to the TCM pool */ - if (tcm_status & 0x03) { + if (itcm_present) { if (itcm_pool_start < itcm_end) { ret = gen_pool_add(tcm_pool, itcm_pool_start, itcm_end - itcm_pool_start, -1); -- cgit v1.2.3 From 10cdc7e5129ac26aefece4c7a7d5b1a0285237c2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 13 Jun 2011 15:28:53 +0100 Subject: ARM: 6960/1: allow enabling SCU code on UP The scu_power_mode function can be used on UP builds as it drives signals to an SOC power controller. So make it selectable for !SMP. Signed-off-by: Rob Herring Signed-off-by: Russell King --- arch/arm/Kconfig | 1 - arch/arm/kernel/smp_scu.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index cd8f520dd03d..84fda2bebd7a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1349,7 +1349,6 @@ config SMP_ON_UP config HAVE_ARM_SCU bool - depends on SMP help This option enables support for the ARM system coherency unit diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c index a1e757c3439b..79ed5e7f204a 100644 --- a/arch/arm/kernel/smp_scu.c +++ b/arch/arm/kernel/smp_scu.c @@ -20,6 +20,7 @@ #define SCU_INVALIDATE 0x0c #define SCU_FPGA_REVISION 0x10 +#ifdef CONFIG_SMP /* * Get the number of CPU cores from the SCU configuration */ @@ -50,6 +51,7 @@ void __init scu_enable(void __iomem *scu_base) */ flush_cache_all(); } +#endif /* * Set the executing CPUs power mode as defined. This will be in -- cgit v1.2.3 From 7fa22bd5460bb2021729fa5a1012c60b9b3a56e2 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 7 Jul 2011 01:56:51 +0100 Subject: ARM: 6993/1: platsmp: Allow secondary cpu hotplug with maxcpus=1 If an ARM system has multiple cpus in the same socket and the kernel is booted with maxcpus=1, secondary cpus are possible but not present due to how platform_smp_prepare_cpus() is called. Since most typical ARM processors don't actually support physical hotplug, initialize the present map to be equal to the possible map in generic ARM SMP code. Also, always call platform_smp_prepare_cpus() as long as max_cpus is non-zero (0 means no SMP) to allow platform code to do any SMP setup. After applying this patch it's possible to boot an ARM system with maxcpus=1 on the command line and then hotplug in secondary cpus via sysfs. This is more in line with how x86 does things. Signed-off-by: Stephen Boyd Cc: Paul Mundt Cc: Kukjin Kim Cc: David Brown Cc: Tony Lindgren Cc: Srinidhi Kasagar Cc: Linus Walleij Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 11 +++++++++-- arch/arm/mach-exynos4/platsmp.c | 8 -------- arch/arm/mach-msm/platsmp.c | 8 -------- arch/arm/mach-omap2/omap-smp.c | 8 -------- arch/arm/mach-realview/platsmp.c | 8 -------- arch/arm/mach-shmobile/platsmp.c | 5 ----- arch/arm/mach-tegra/platsmp.c | 8 -------- arch/arm/mach-ux500/platsmp.c | 8 -------- arch/arm/mach-vexpress/ct-ca9x4.c | 4 ---- 9 files changed, 9 insertions(+), 59 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 344e52b16c8c..0ffcf5c0da43 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -361,14 +361,21 @@ void __init smp_prepare_cpus(unsigned int max_cpus) */ if (max_cpus > ncores) max_cpus = ncores; - - if (max_cpus > 1) { + if (ncores > 1 && max_cpus) { /* * Enable the local timer or broadcast device for the * boot CPU, but only if we have more than one CPU. */ percpu_timer_setup(); + /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. A platform should + * re-initialize the map in platform_smp_prepare_cpus() if + * present != possible (e.g. physical hotplug). + */ + init_cpu_present(&cpu_possible_map); + /* * Initialise the SCU if there are more than one CPU * and let them know where to start. diff --git a/arch/arm/mach-exynos4/platsmp.c b/arch/arm/mach-exynos4/platsmp.c index c5e65a02be8d..b68d5bdf04cf 100644 --- a/arch/arm/mach-exynos4/platsmp.c +++ b/arch/arm/mach-exynos4/platsmp.c @@ -154,14 +154,6 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); scu_enable(scu_base_addr()); diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c index 2034098cf015..315b9f365329 100644 --- a/arch/arm/mach-msm/platsmp.c +++ b/arch/arm/mach-msm/platsmp.c @@ -157,12 +157,4 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); } diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index ecfe93c4b585..ce65e9329c7b 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -125,14 +125,6 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); /* * Initialise the SCU and wake up the secondary core using diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 963bf0d8119a..4ae943bafa92 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -68,14 +68,6 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); scu_enable(scu_base_addr()); diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c index f3888feb1c68..66f980625a33 100644 --- a/arch/arm/mach-shmobile/platsmp.c +++ b/arch/arm/mach-shmobile/platsmp.c @@ -64,10 +64,5 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); - shmobile_smp_prepare_cpus(); } diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index b8ae3c978dee..1a594dce8fbc 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -129,14 +129,6 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); scu_enable(scu_base); } diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 0c527fe2cebb..a33df5f4c27a 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -172,14 +172,6 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); scu_enable(scu_base_addr()); wakeup_secondary(); diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c index 765a71ff7f3b..bfd32f52c2db 100644 --- a/arch/arm/mach-vexpress/ct-ca9x4.c +++ b/arch/arm/mach-vexpress/ct-ca9x4.c @@ -229,10 +229,6 @@ static void ct_ca9x4_init_cpu_map(void) static void ct_ca9x4_smp_enable(unsigned int max_cpus) { - int i; - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); - scu_enable(MMIO_P2V(A9_MPCORE_SCU)); } #endif -- cgit v1.2.3 From 90c5ffe592ff3b33afe2bdfe5e9ec630fc599e32 Mon Sep 17 00:00:00 2001 From: Vitaly Kuzmichev Date: Thu, 7 Jul 2011 14:56:05 +0100 Subject: ARM: 6994/1: smp_twd: Fix typo in 'twd_timer_rate' printing To get hundredths of MHz the rate needs to be divided by 10'000. Here is an example: twd_timer_rate = 123456789 Before the patch: twd_timer_rate / 1000000 = 123 (twd_timer_rate / 1000000) % 100 = 23 Result: 123.23MHz. After being fixed: twd_timer_rate / 1000000 = 123 (twd_timer_rate / 10000) % 100 = 45 Result: 123.45MHz. Signed-off-by: Vitaly Kuzmichev Signed-off-by: Russell King --- arch/arm/kernel/smp_twd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 60636f499cb3..2c277d40cee6 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -115,7 +115,7 @@ static void __cpuinit twd_calibrate_rate(void) twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5); printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000, - (twd_timer_rate / 1000000) % 100); + (twd_timer_rate / 10000) % 100); } } -- cgit v1.2.3 From 39df88872f64b8a7c438861460063eadf2ba9011 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 May 2011 11:25:33 +0100 Subject: ARM: vmlinux.lds: move discarded sections to beginning Rather than scattering the discarded sections throughout the linker file, move them to the start. Acked-by: Nicolas Pitre Tested-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/kernel/vmlinux.lds.S | 47 ++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index e5287f21badc..cb46a9bad4f5 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -38,6 +38,28 @@ jiffies = jiffies_64 + 4; SECTIONS { + /* + * unwind exit sections must be discarded before the rest of the + * unwind sections get included. + */ + /DISCARD/ : { + *(.ARM.exidx.exit.text) + *(.ARM.extab.exit.text) + ARM_CPU_DISCARD(*(.ARM.exidx.cpuexit.text)) + ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text)) +#ifndef CONFIG_HOTPLUG + *(.ARM.exidx.devexit.text) + *(.ARM.extab.devexit.text) +#endif +#ifndef CONFIG_MMU + *(.fixup) + *(__ex_table) +#endif +#ifndef CONFIG_SMP_ON_UP + *(.alt.smp.init) +#endif + } + #ifdef CONFIG_XIP_KERNEL . = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR); #else @@ -89,25 +111,6 @@ SECTIONS __init_end = .; #endif - /* - * unwind exit sections must be discarded before the rest of the - * unwind sections get included. - */ - /DISCARD/ : { - *(.ARM.exidx.exit.text) - *(.ARM.extab.exit.text) - ARM_CPU_DISCARD(*(.ARM.exidx.cpuexit.text)) - ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text)) -#ifndef CONFIG_HOTPLUG - *(.ARM.exidx.devexit.text) - *(.ARM.extab.devexit.text) -#endif -#ifndef CONFIG_MMU - *(.fixup) - *(__ex_table) -#endif - } - .text : { /* Real text segment */ _text = .; /* Text and read-only data */ __exception_text_start = .; @@ -270,12 +273,6 @@ SECTIONS /* Default discards */ DISCARDS - -#ifndef CONFIG_SMP_ON_UP - /DISCARD/ : { - *(.alt.smp.init) - } -#endif } /* -- cgit v1.2.3 From 1604d79d372bcf0cf1aebcbdee251bd0f3d56665 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 5 Jul 2011 22:56:41 +0100 Subject: ARM: vmlinux.lds: rearrange .init output section Keep the various linker tables as separate output sections rather than combining them together into one big .init section. This makes the 'vmlinux' easier to see what is placed where. Acked-by: Nicolas Pitre Tested-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/kernel/vmlinux.lds.S | 47 ++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 18 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index cb46a9bad4f5..c8bb9b77c2ea 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -65,48 +65,59 @@ SECTIONS #else . = PAGE_OFFSET + TEXT_OFFSET; #endif - - .init : { /* Init code and data */ + .head.text : { _stext = .; - _sinittext = .; - HEAD_TEXT - INIT_TEXT - ARM_EXIT_KEEP(EXIT_TEXT) - _einittext = .; + HEAD_TEXT + } + INIT_TEXT_SECTION(8) + .exit.text : { + ARM_EXIT_KEEP(EXIT_TEXT) + } + .init.proc.info : { ARM_CPU_DISCARD(PROC_INFO) + } + .init.arch.info : { __arch_info_begin = .; - *(.arch.info.init) + *(.arch.info.init) __arch_info_end = .; + } + .init.tagtable : { __tagtable_begin = .; - *(.taglist.init) + *(.taglist.init) __tagtable_end = .; + } #ifdef CONFIG_SMP_ON_UP + .init.smpalt : { __smpalt_begin = .; - *(.alt.smp.init) + *(.alt.smp.init) __smpalt_end = .; + } #endif - + .init.pv_table : { __pv_table_begin = .; - *(.pv_table) + *(.pv_table) __pv_table_end = .; - + } + .init.data : { +#ifndef CONFIG_XIP_KERNEL + INIT_DATA +#endif INIT_SETUP(16) - INIT_CALLS CON_INITCALL SECURITY_INITCALL INIT_RAM_FS - + } #ifndef CONFIG_XIP_KERNEL - __init_begin = _stext; - INIT_DATA + .exit.data : { ARM_EXIT_KEEP(EXIT_DATA) -#endif } +#endif PERCPU_SECTION(32) #ifndef CONFIG_XIP_KERNEL + __init_begin = _stext; . = ALIGN(PAGE_SIZE); __init_end = .; #endif -- cgit v1.2.3 From 43fc9d2fa5585adfadd0fdc06a20626727cf985a Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 6 Jul 2011 00:01:20 +0100 Subject: ARM: vmlinux.lds: remove .rodata/.rodata1 from main .text segment RODATA() already handles these sections, so allow it to take care of them for us. Acked-by: Nicolas Pitre Tested-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/kernel/vmlinux.lds.S | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index c8bb9b77c2ea..fa812d03ff47 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -136,8 +136,6 @@ SECTIONS *(.fixup) #endif *(.gnu.warning) - *(.rodata) - *(.rodata.*) *(.glue_7) *(.glue_7t) . = ALIGN(4); -- cgit v1.2.3 From 3835d69a6c7048a28d0aea3cb8403d5e83a0f867 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 6 Jul 2011 10:39:34 +0100 Subject: ARM: vmlinux.lds: move init sections between text and data sections Place the init sections between the text and data sections. This means all code is grouped together at the beginning of the kernel image, and all data is at the end of the image. This avoids problems with the 24-bit branch instruction relocations becoming invalid with large initramfs images. Acked-by: Nicolas Pitre Tested-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/kernel/vmlinux.lds.S | 96 +++++++++++++++++++++---------------------- arch/arm/mm/init.c | 4 +- 2 files changed, 50 insertions(+), 50 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index fa812d03ff47..18574b7dbc14 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -69,6 +69,53 @@ SECTIONS _stext = .; HEAD_TEXT } + .text : { /* Real text segment */ + _text = .; /* Text and read-only data */ + __exception_text_start = .; + *(.exception.text) + __exception_text_end = .; + IRQENTRY_TEXT + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT + KPROBES_TEXT +#ifdef CONFIG_MMU + *(.fixup) +#endif + *(.gnu.warning) + *(.glue_7) + *(.glue_7t) + . = ALIGN(4); + *(.got) /* Global offset table */ + ARM_CPU_KEEP(PROC_INFO) + } + + RO_DATA(PAGE_SIZE) + +#ifdef CONFIG_ARM_UNWIND + /* + * Stack unwinding tables + */ + . = ALIGN(8); + .ARM.unwind_idx : { + __start_unwind_idx = .; + *(.ARM.exidx*) + __stop_unwind_idx = .; + } + .ARM.unwind_tab : { + __start_unwind_tab = .; + *(.ARM.extab*) + __stop_unwind_tab = .; + } +#endif + + _etext = .; /* End of text and rodata section */ + +#ifndef CONFIG_XIP_KERNEL + . = ALIGN(PAGE_SIZE); + __init_begin = .; +#endif + INIT_TEXT_SECTION(8) .exit.text : { ARM_EXIT_KEEP(EXIT_TEXT) @@ -116,58 +163,11 @@ SECTIONS PERCPU_SECTION(32) -#ifndef CONFIG_XIP_KERNEL - __init_begin = _stext; - . = ALIGN(PAGE_SIZE); - __init_end = .; -#endif - - .text : { /* Real text segment */ - _text = .; /* Text and read-only data */ - __exception_text_start = .; - *(.exception.text) - __exception_text_end = .; - IRQENTRY_TEXT - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT -#ifdef CONFIG_MMU - *(.fixup) -#endif - *(.gnu.warning) - *(.glue_7) - *(.glue_7t) - . = ALIGN(4); - *(.got) /* Global offset table */ - ARM_CPU_KEEP(PROC_INFO) - } - - RO_DATA(PAGE_SIZE) - -#ifdef CONFIG_ARM_UNWIND - /* - * Stack unwinding tables - */ - . = ALIGN(8); - .ARM.unwind_idx : { - __start_unwind_idx = .; - *(.ARM.exidx*) - __stop_unwind_idx = .; - } - .ARM.unwind_tab : { - __start_unwind_tab = .; - *(.ARM.extab*) - __stop_unwind_tab = .; - } -#endif - - _etext = .; /* End of text and rodata section */ - #ifdef CONFIG_XIP_KERNEL __data_loc = ALIGN(4); /* location in binary */ . = PAGE_OFFSET + TEXT_OFFSET; #else + __init_end = .; . = ALIGN(THREAD_SIZE); __data_loc = .; #endif diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index c19571c40a21..b8e891243153 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -639,8 +639,8 @@ void __init mem_init(void) " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n" #endif " modules : 0x%08lx - 0x%08lx (%4ld MB)\n" - " .init : 0x%p" " - 0x%p" " (%4d kB)\n" " .text : 0x%p" " - 0x%p" " (%4d kB)\n" + " .init : 0x%p" " - 0x%p" " (%4d kB)\n" " .data : 0x%p" " - 0x%p" " (%4d kB)\n" " .bss : 0x%p" " - 0x%p" " (%4d kB)\n", @@ -662,8 +662,8 @@ void __init mem_init(void) #endif MLM(MODULES_VADDR, MODULES_END), - MLK_ROUNDUP(__init_begin, __init_end), MLK_ROUNDUP(_text, _etext), + MLK_ROUNDUP(__init_begin, __init_end), MLK_ROUNDUP(_sdata, _edata), MLK_ROUNDUP(__bss_start, __bss_stop)); -- cgit v1.2.3 From e2f81844efa2d44d326bef48e1c9e48926162bc6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 6 Jul 2011 10:53:22 +0100 Subject: ARM: vmlinux.lds: use _text and _stext the same way as x86 x86 uses _text to mark the start of the kernel image including the head text, and _stext to mark the start of the .text section. Change our vmlinux.lds to conform. An audit of the places which use _stext and _text in arch/arm indicates no users of either symbol are impacted by this change. It does mean a slight change to /proc/iomem output. Acked-by: Nicolas Pitre Tested-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/kernel/vmlinux.lds.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 18574b7dbc14..bf977f8514f6 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -66,11 +66,11 @@ SECTIONS . = PAGE_OFFSET + TEXT_OFFSET; #endif .head.text : { - _stext = .; + _text = .; HEAD_TEXT } .text : { /* Real text segment */ - _text = .; /* Text and read-only data */ + _stext = .; /* Text and read-only data */ __exception_text_start = .; *(.exception.text) __exception_text_end = .; -- cgit v1.2.3 From f8f2a8522a88aacd62a310ce49e8dac530d1b403 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 9 Jul 2011 16:09:43 +0100 Subject: ARM: vfp: fix a hole in VFP thread migration Fix a hole in the VFP thread migration. Lets define two threads. Thread 1, we'll call 'interesting_thread' which is a thread which is running on CPU0, using VFP (so vfp_current_hw_state[0] = &interesting_thread->vfpstate) and gets migrated off to CPU1, where it continues execution of VFP instructions. Thread 2, we'll call 'new_cpu0_thread' which is the thread which takes over on CPU0. This has also been using VFP, and last used VFP on CPU0, but doesn't use it again. The following code will be executed twice: cpu = thread->cpu; /* * On SMP, if VFP is enabled, save the old state in * case the thread migrates to a different CPU. The * restoring is done lazily. */ if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) { vfp_save_state(vfp_current_hw_state[cpu], fpexc); vfp_current_hw_state[cpu]->hard.cpu = cpu; } /* * Thread migration, just force the reloading of the * state on the new CPU in case the VFP registers * contain stale data. */ if (thread->vfpstate.hard.cpu != cpu) vfp_current_hw_state[cpu] = NULL; The first execution will be on CPU0 to switch away from 'interesting_thread'. interesting_thread->cpu will be 0. So, vfp_current_hw_state[0] points at interesting_thread->vfpstate. The hardware state will be saved, along with the CPU number (0) that it was executing on. 'thread' will be 'new_cpu0_thread' with new_cpu0_thread->cpu = 0. Also, because it was executing on CPU0, new_cpu0_thread->vfpstate.hard.cpu = 0, and so the thread migration check is not triggered. This means that vfp_current_hw_state[0] remains pointing at interesting_thread. The second execution will be on CPU1 to switch _to_ 'interesting_thread'. So, 'thread' will be 'interesting_thread' and interesting_thread->cpu now will be 1. The previous thread executing on CPU1 is not relevant to this so we shall ignore that. We get to the thread migration check. Here, we discover that interesting_thread->vfpstate.hard.cpu = 0, yet interesting_thread->cpu is now 1, indicating thread migration. We set vfp_current_hw_state[1] to NULL. So, at this point vfp_current_hw_state[] contains the following: [0] = &interesting_thread->vfpstate [1] = NULL Our interesting thread now executes a VFP instruction, takes a fault which loads the state into the VFP hardware. Now, through the assembly we now have: [0] = &interesting_thread->vfpstate [1] = &interesting_thread->vfpstate CPU1 stops due to ptrace (and so saves its VFP state) using the thread switch code above), and CPU0 calls vfp_sync_hwstate(). if (vfp_current_hw_state[cpu] == &thread->vfpstate) { vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN); BANG, we corrupt interesting_thread's VFP state by overwriting the more up-to-date state saved by CPU1 with the old VFP state from CPU0. Fix this by ensuring that we have sane semantics for the various state describing variables: 1. vfp_current_hw_state[] points to the current owner of the context information stored in each CPUs hardware, or NULL if that state information is invalid. 2. thread->vfpstate.hard.cpu always contains the most recent CPU number which the state was loaded into or NR_CPUS if no CPU owns the state. So, for a particular CPU to be a valid owner of the VFP state for a particular thread t, two things must be true: vfp_current_hw_state[cpu] == &t->vfpstate && t->vfpstate.hard.cpu == cpu. and that is valid from the moment a CPU loads the saved VFP context into the hardware. This gives clear and consistent semantics to interpreting these variables. This patch also fixes thread copying, ensuring that t->vfpstate.hard.cpu is invalidated, otherwise CPU0 may believe it was the last owner. The hole can happen thus: - thread1 runs on CPU2 using VFP, migrates to CPU3, exits and thread_info freed. - New thread allocated from a previously running thread on CPU2, reusing memory for thread1 and copying vfp.hard.cpu. At this point, the following are true: new_thread1->vfpstate.hard.cpu == 2 &new_thread1->vfpstate == vfp_current_hw_state[2] Lastly, this also addresses thread flushing in a similar way to thread copying. Hole is: - thread runs on CPU0, using VFP, migrates to CPU1 but does not use VFP. - thread calls execve(), so thread flush happens, leaving vfp_current_hw_state[0] intact. This vfpstate is memset to 0 causing thread->vfpstate.hard.cpu = 0. - thread migrates back to CPU0 before using VFP. At this point, the following are true: thread->vfpstate.hard.cpu == 0 &thread->vfpstate == vfp_current_hw_state[0] Signed-off-by: Russell King --- arch/arm/kernel/asm-offsets.c | 3 ++ arch/arm/vfp/vfphw.S | 43 +++++++++++++++---- arch/arm/vfp/vfpmodule.c | 98 +++++++++++++++++++++++-------------------- 3 files changed, 89 insertions(+), 55 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 927522cfc12e..16baba2e4369 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -59,6 +59,9 @@ int main(void) DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value)); DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate)); DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate)); +#ifdef CONFIG_SMP + DEFINE(VFP_CPU, offsetof(union vfp_state, hard.cpu)); +#endif #ifdef CONFIG_ARM_THUMBEE DEFINE(TI_THUMBEE_STATE, offsetof(struct thread_info, thumbee_state)); #endif diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 404538ae591d..2d30c7f6edd3 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -82,19 +82,22 @@ ENTRY(vfp_support_entry) ldr r4, [r3, r11, lsl #2] @ vfp_current_hw_state pointer bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled cmp r4, r10 @ this thread owns the hw context? +#ifndef CONFIG_SMP + @ For UP, checking that this thread owns the hw context is + @ sufficient to determine that the hardware state is valid. beq vfp_hw_state_valid + @ On UP, we lazily save the VFP context. As a different + @ thread wants ownership of the VFP hardware, save the old + @ state if there was a previous (valid) owner. + VFPFMXR FPEXC, r5 @ enable VFP, disable any pending @ exceptions, so we can get at the @ rest of it -#ifndef CONFIG_SMP - @ Save out the current registers to the old thread state - @ No need for SMP since this is not done lazily - DBGSTR1 "save old state %p", r4 - cmp r4, #0 - beq no_old_VFP_process + cmp r4, #0 @ if the vfp_current_hw_state is NULL + beq vfp_reload_hw @ then the hw state needs reloading VFPFSTMIA r4, r5 @ save the working registers VFPFMRX r5, FPSCR @ current status #ifndef CONFIG_CPU_FEROCEON @@ -107,11 +110,33 @@ ENTRY(vfp_support_entry) 1: #endif stmia r4, {r1, r5, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2 - @ and point r4 at the word at the - @ start of the register dump +vfp_reload_hw: + +#else + @ For SMP, if this thread does not own the hw context, then we + @ need to reload it. No need to save the old state as on SMP, + @ we always save the state when we switch away from a thread. + bne vfp_reload_hw + + @ This thread has ownership of the current hardware context. + @ However, it may have been migrated to another CPU, in which + @ case the saved state is newer than the hardware context. + @ Check this by looking at the CPU number which the state was + @ last loaded onto. + ldr ip, [r10, #VFP_CPU] + teq ip, r11 + beq vfp_hw_state_valid + +vfp_reload_hw: + @ We're loading this threads state into the VFP hardware. Update + @ the CPU number which contains the most up to date VFP context. + str r11, [r10, #VFP_CPU] + + VFPFMXR FPEXC, r5 @ enable VFP, disable any pending + @ exceptions, so we can get at the + @ rest of it #endif -no_old_VFP_process: DBGSTR1 "load state %p", r10 str r10, [r3, r11, lsl #2] @ update the vfp_current_hw_state pointer @ Load the saved state back into the VFP diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 3640351171b8..08ff93fa533c 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -34,19 +34,52 @@ void vfp_null_entry(void); void (*vfp_vector)(void) = vfp_null_entry; +/* + * Dual-use variable. + * Used in startup: set to non-zero if VFP checks fail + * After startup, holds VFP architecture + */ +unsigned int VFP_arch; + /* * The pointer to the vfpstate structure of the thread which currently * owns the context held in the VFP hardware, or NULL if the hardware * context is invalid. + * + * For UP, this is sufficient to tell which thread owns the VFP context. + * However, for SMP, we also need to check the CPU number stored in the + * saved state too to catch migrations. */ union vfp_state *vfp_current_hw_state[NR_CPUS]; /* - * Dual-use variable. - * Used in startup: set to non-zero if VFP checks fail - * After startup, holds VFP architecture + * Is 'thread's most up to date state stored in this CPUs hardware? + * Must be called from non-preemptible context. */ -unsigned int VFP_arch; +static bool vfp_state_in_hw(unsigned int cpu, struct thread_info *thread) +{ +#ifdef CONFIG_SMP + if (thread->vfpstate.hard.cpu != cpu) + return false; +#endif + return vfp_current_hw_state[cpu] == &thread->vfpstate; +} + +/* + * Force a reload of the VFP context from the thread structure. We do + * this by ensuring that access to the VFP hardware is disabled, and + * clear last_VFP_context. Must be called from non-preemptible context. + */ +static void vfp_force_reload(unsigned int cpu, struct thread_info *thread) +{ + if (vfp_state_in_hw(cpu, thread)) { + fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); + vfp_current_hw_state[cpu] = NULL; + } +#ifdef CONFIG_SMP + thread->vfpstate.hard.cpu = NR_CPUS; +#endif +} /* * Per-thread VFP initialization. @@ -60,6 +93,9 @@ static void vfp_thread_flush(struct thread_info *thread) vfp->hard.fpexc = FPEXC_EN; vfp->hard.fpscr = FPSCR_ROUND_NEAREST; +#ifdef CONFIG_SMP + vfp->hard.cpu = NR_CPUS; +#endif /* * Disable VFP to ensure we initialize it first. We must ensure @@ -90,6 +126,9 @@ static void vfp_thread_copy(struct thread_info *thread) vfp_sync_hwstate(parent); thread->vfpstate = parent->vfpstate; +#ifdef CONFIG_SMP + thread->vfpstate.hard.cpu = NR_CPUS; +#endif } /* @@ -135,17 +174,8 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) * case the thread migrates to a different CPU. The * restoring is done lazily. */ - if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) { + if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) vfp_save_state(vfp_current_hw_state[cpu], fpexc); - vfp_current_hw_state[cpu]->hard.cpu = cpu; - } - /* - * Thread migration, just force the reloading of the - * state on the new CPU in case the VFP registers - * contain stale data. - */ - if (thread->vfpstate.hard.cpu != cpu) - vfp_current_hw_state[cpu] = NULL; #endif /* @@ -449,15 +479,15 @@ static void vfp_pm_init(void) static inline void vfp_pm_init(void) { } #endif /* CONFIG_PM */ +/* + * Ensure that the VFP state stored in 'thread->vfpstate' is up to date + * with the hardware state. + */ void vfp_sync_hwstate(struct thread_info *thread) { unsigned int cpu = get_cpu(); - /* - * If the thread we're interested in is the current owner of the - * hardware VFP state, then we need to save its state. - */ - if (vfp_current_hw_state[cpu] == &thread->vfpstate) { + if (vfp_state_in_hw(cpu, thread)) { u32 fpexc = fmrx(FPEXC); /* @@ -471,36 +501,13 @@ void vfp_sync_hwstate(struct thread_info *thread) put_cpu(); } +/* Ensure that the thread reloads the hardware VFP state on the next use. */ void vfp_flush_hwstate(struct thread_info *thread) { unsigned int cpu = get_cpu(); - /* - * If the thread we're interested in is the current owner of the - * hardware VFP state, then we need to save its state. - */ - if (vfp_current_hw_state[cpu] == &thread->vfpstate) { - u32 fpexc = fmrx(FPEXC); + vfp_force_reload(cpu, thread); - fmxr(FPEXC, fpexc & ~FPEXC_EN); - - /* - * Set the context to NULL to force a reload the next time - * the thread uses the VFP. - */ - vfp_current_hw_state[cpu] = NULL; - } - -#ifdef CONFIG_SMP - /* - * For SMP we still have to take care of the case where the thread - * migrates to another CPU and then back to the original CPU on which - * the last VFP user is still the same thread. Mark the thread VFP - * state as belonging to a non-existent CPU so that the saved one will - * be reloaded in the above case. - */ - thread->vfpstate.hard.cpu = NR_CPUS; -#endif put_cpu(); } @@ -519,8 +526,7 @@ static int vfp_hotplug(struct notifier_block *b, unsigned long action, void *hcpu) { if (action == CPU_DYING || action == CPU_DYING_FROZEN) { - unsigned int cpu = (long)hcpu; - vfp_current_hw_state[cpu] = NULL; + vfp_force_reload((long)hcpu, current_thread_info()); } else if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) vfp_enable(NULL); return NOTIFY_OK; -- cgit v1.2.3 From 540b573875bd26dfe39aa18d22dc195f275fc0df Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Wed, 13 Jul 2011 15:53:30 +0100 Subject: ARM: 6999/1: head, zImage: Always Enter the kernel in ARM state Currently, the documented kernel entry requirements are not explicit about whether the kernel should be entered in ARM or Thumb, leading to an ambiguitity about how to enter Thumb-2 kernels. As a result, the kernel is reliant on the zImage decompressor to enter the kernel proper in the correct instruction set state. This patch changes the boot entry protocol for head.S and Image to be the same as for zImage: in all cases, the kernel is now entered in ARM. Documentation/arm/Booting is updated to reflect this new policy. A different rule will be needed for Cortex-M class CPUs as and when support for those lands in mainline, since these CPUs don't support the ARM instruction set at all: a note is added to the effect that the kernel must be entered in Thumb on such systems. Signed-off-by: Dave Martin Acked-by: Nicolas Pitre Signed-off-by: Russell King --- Documentation/arm/Booting | 5 +++++ arch/arm/boot/compressed/head.S | 3 ++- arch/arm/kernel/head-nommu.S | 8 ++++++++ arch/arm/kernel/head.S | 8 ++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/Documentation/arm/Booting b/Documentation/arm/Booting index 4e686a2ed91e..a341d87d276e 100644 --- a/Documentation/arm/Booting +++ b/Documentation/arm/Booting @@ -164,3 +164,8 @@ In either case, the following conditions must be met: - The boot loader is expected to call the kernel image by jumping directly to the first instruction of the kernel image. + On CPUs supporting the ARM instruction set, the entry must be + made in ARM state, even for a Thumb-2 kernel. + + On CPUs supporting only the Thumb instruction set such as + Cortex-M class CPUs, the entry must be made in Thumb state. diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index f9da41921c52..51af7091d84d 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -353,7 +353,8 @@ not_relocated: mov r0, #0 mov r0, #0 @ must be zero mov r1, r7 @ restore architecture number mov r2, r8 @ restore atags pointer - mov pc, r4 @ call kernel + ARM( mov pc, r4 ) @ call kernel + THUMB( bx r4 ) @ entry point is always ARM .align 2 .type LC0, #object diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index 6b1e0ad9ec3b..d46f25968bec 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S @@ -32,8 +32,16 @@ * numbers for r1. * */ + .arm + __HEAD ENTRY(stext) + + THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. + THUMB( bx r9 ) @ If this is a Thumb-2 kernel, + THUMB( .thumb ) @ switch to Thumb now. + THUMB(1: ) + setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode @ and irqs disabled #ifndef CONFIG_CPU_CP15 diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 278c1b0ebb2e..742b6108a001 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -71,8 +71,16 @@ * crap here - that's what the boot loader (or in extreme, well justified * circumstances, zImage) is for. */ + .arm + __HEAD ENTRY(stext) + + THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. + THUMB( bx r9 ) @ If this is a Thumb-2 kernel, + THUMB( .thumb ) @ switch to Thumb now. + THUMB(1: ) + setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode @ and irqs disabled mrc p15, 0, r9, c0, c0 @ get processor id -- cgit v1.2.3 From 2ef75701d1711a1feee2a82b42a2597ddc05f88b Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jul 2011 14:51:13 +0100 Subject: ARM: CPU hotplug: fix abuse of irqdesc->node irqdesc's node member is supposed to mark the numa node number for the interrupt. Our use of it is non-standard. Remove this, replacing the functionality with a test of the affinity mask. Signed-off-by: Russell King --- arch/arm/common/gic.c | 1 - arch/arm/kernel/irq.c | 10 ++-------- 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 4ddd0a6ac7ff..635d9857b07a 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -189,7 +189,6 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bit = 1 << (cpu + shift); spin_lock(&irq_controller_lock); - d->node = cpu; val = readl_relaxed(reg) & ~mask; writel_relaxed(val | bit, reg); spin_unlock(&irq_controller_lock); diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 83bbad03fcc6..d7aa5c97877c 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -166,15 +166,9 @@ void migrate_irqs(void) bool affinity_broken = false; raw_spin_lock(&desc->lock); - do { - if (desc->action == NULL) - break; - - if (d->node != cpu) - break; - + if (desc->action != NULL && + cpumask_test_cpu(smp_processor_id(), d->affinity)) affinity_broken = migrate_one_irq(d); - } while (0); raw_spin_unlock(&desc->lock); if (affinity_broken && printk_ratelimit()) -- cgit v1.2.3 From ca15af19ac07908c8ca386f6d944a18aa343b868 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jul 2011 15:07:56 +0100 Subject: ARM: CPU hotplug: pass in proper affinity mask on IRQ migration Now that the GIC takes care of selecting a target interrupt from the affinity mask, we don't need all this complexity in the core code anymore. Just detect when we need to break affinity. Signed-off-by: Russell King --- arch/arm/kernel/irq.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index d7aa5c97877c..ab63c05290e5 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -133,17 +133,15 @@ int __init arch_probe_nr_irqs(void) static bool migrate_one_irq(struct irq_data *d) { - unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask); + const struct cpumask *affinity = d->affinity; bool ret = false; - if (cpu >= nr_cpu_ids) { - cpu = cpumask_any(cpu_online_mask); + if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { + affinity cpu_online_mask; ret = true; } - pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu); - - d->chip->irq_set_affinity(d, cpumask_of(cpu), true); + d->chip->irq_set_affinity(d, affinity, true); return ret; } -- cgit v1.2.3 From 78359cb86b8c4c8946f6732eac2757fa5e1d4de4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jul 2011 15:14:21 +0100 Subject: ARM: CPU hotplug: ensure we migrate all IRQs off a downed CPU Our selection of interrupts to consider for IRQ migration is sub- standard. We were potentially including per-CPU interrupts in our migration strategy, but omitting chained interrupts. This caused some interrupts to remain on a downed CPU. We were also trying to migrate interrupts which were not migratable, resulting in an OOPS. Instead, iterate over all interrupts, skipping per-CPU interrupts or interrupts whose affinity does not include the downed CPU, and attempt to set the affinity for every one else if their chip implements irq_set_affinity(). Signed-off-by: Russell King --- arch/arm/kernel/irq.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index ab63c05290e5..0f928a131af8 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -131,46 +131,63 @@ int __init arch_probe_nr_irqs(void) #ifdef CONFIG_HOTPLUG_CPU -static bool migrate_one_irq(struct irq_data *d) +static bool migrate_one_irq(struct irq_desc *desc) { + struct irq_data *d = irq_desc_get_irq_data(desc); const struct cpumask *affinity = d->affinity; + struct irq_chip *c; bool ret = false; + /* + * If this is a per-CPU interrupt, or the affinity does not + * include this CPU, then we have nothing to do. + */ + if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity)) + return false; + if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { - affinity cpu_online_mask; + affinity = cpu_online_mask; ret = true; } - d->chip->irq_set_affinity(d, affinity, true); + c = irq_data_get_irq_chip(d); + if (c->irq_set_affinity) + c->irq_set_affinity(d, affinity, true); + else + pr_debug("IRQ%u: unable to set affinity\n", d->irq); return ret; } /* - * The CPU has been marked offline. Migrate IRQs off this CPU. If - * the affinity settings do not allow other CPUs, force them onto any + * The current CPU has been marked offline. Migrate IRQs off this CPU. + * If the affinity settings do not allow other CPUs, force them onto any * available CPU. + * + * Note: we must iterate over all IRQs, whether they have an attached + * action structure or not, as we need to get chained interrupts too. */ void migrate_irqs(void) { - unsigned int i, cpu = smp_processor_id(); + unsigned int i; struct irq_desc *desc; unsigned long flags; local_irq_save(flags); for_each_irq_desc(i, desc) { - struct irq_data *d = &desc->irq_data; bool affinity_broken = false; + if (!desc) + continue; + raw_spin_lock(&desc->lock); - if (desc->action != NULL && - cpumask_test_cpu(smp_processor_id(), d->affinity)) - affinity_broken = migrate_one_irq(d); + affinity_broken = migrate_one_irq(desc); raw_spin_unlock(&desc->lock); if (affinity_broken && printk_ratelimit()) - pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu); + pr_warning("IRQ%u no longer affine to CPU%u\n", i, + smp_processor_id()); } local_irq_restore(flags); -- cgit v1.2.3