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 +++++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 49 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 -- 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/kernel/sleep.S | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'arch/arm/kernel') 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) -- 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 + 1 file changed, 1 insertion(+) (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) -- 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/kernel/sleep.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') 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 /* -- 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/kernel/perf_event.c | 4 ++-- arch/arm/kernel/pmu.c | 33 +++++++++++++++++++-------------- 2 files changed, 21 insertions(+), 16 deletions(-) (limited to 'arch/arm/kernel') 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 --- arch/arm/kernel/pmu.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'arch/arm/kernel') 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 +- 1 file changed, 1 insertion(+), 1 deletion(-) (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 -- 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/kernel/sleep.S | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') 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) -- 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 +++++------- 3 files changed, 24 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; -- 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/kernel/entry-armv.S | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/arm/kernel') 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 +++----- 1 file changed, 3 insertions(+), 5 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 */ /* -- 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 ++---- 1 file changed, 2 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 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. -- 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 ++++---------- 1 file changed, 4 insertions(+), 10 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) -- 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 ++ 1 file changed, 2 insertions(+) (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); -- 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/kernel/tcm.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'arch/arm/kernel') 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/kernel/smp_scu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/kernel') 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 +++++++++-- 1 file changed, 9 insertions(+), 2 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. -- 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 +++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 48 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 -- 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 +++ 1 file changed, 3 insertions(+) (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 -- 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 --- arch/arm/kernel/head-nommu.S | 8 ++++++++ arch/arm/kernel/head.S | 8 ++++++++ 2 files changed, 16 insertions(+) (limited to 'arch/arm/kernel') 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/kernel/irq.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'arch/arm/kernel') 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