From e616c591405c168f6dc3dfd1221e105adfe49b8d Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 27 Sep 2009 20:55:43 +0100 Subject: ARM: Don't allow highmem on SMP platforms without h/w TLB ops broadcast We suffer an unfortunate combination of "features" which makes highmem support on platforms without hardware TLB maintainence broadcast difficult: - we need kmap_high_get() support for DMA cache coherence - this requires kmap_high() to take a spinlock with IRQs disabled - kmap_high() occasionally calls flush_all_zero_pkmaps() to clear out old mappings - flush_all_zero_pkmaps() calls flush_tlb_kernel_range(), which on s/w IPI'd systems eventually calls smp_call_function_many() - smp_call_function_many() must not be called with IRQs disabled: WARNING: at kernel/smp.c:380 smp_call_function_many+0xc4/0x240() Modules linked in: Backtrace: [] (dump_backtrace+0x0/0x108) from [] (dump_stack+0x18/0x1c) r6:c007cd18 r5:c02ff228 r4:0000017c [] (dump_stack+0x0/0x1c) from [] (warn_slowpath_common+0x50/0x80) [] (warn_slowpath_common+0x0/0x80) from [] (warn_slowpath_null+0x18/0x1c) r7:00000003 r6:00000001 r5:c1ff4000 r4:c035fa34 [] (warn_slowpath_null+0x0/0x1c) from [] (smp_call_function_many+0xc4/0x240) [] (smp_call_function_many+0x0/0x240) from [] (smp_call_function+0x2c/0x38) [] (smp_call_function+0x0/0x38) from [] (on_each_cpu+0x1c/0x38) [] (on_each_cpu+0x0/0x38) from [] (flush_tlb_kernel_range+0x50/0x58) r6:00000001 r5:00000800 r4:c05f3590 [] (flush_tlb_kernel_range+0x0/0x58) from [] (flush_all_zero_pkmaps+0xc0/0xe8) [] (flush_all_zero_pkmaps+0x0/0xe8) from [] (kmap_high+0x8c/0x1e0) [] (kmap_high+0x0/0x1e0) from [] (kmap+0x44/0x5c) [] (kmap+0x0/0x5c) from [] (cramfs_readpage+0x3c/0x194) [] (cramfs_readpage+0x0/0x194) from [] (__do_page_cache_readahead+0x1f0/0x290) [] (__do_page_cache_readahead+0x0/0x290) from [] (ra_submit+0x30/0x38) [] (ra_submit+0x0/0x38) from [] (filemap_fault+0x3dc/0x438) r4:c1819988 [] (filemap_fault+0x0/0x438) from [] (__do_fault+0x58/0x43c) [] (__do_fault+0x0/0x43c) from [] (handle_mm_fault+0x104/0x318) [] (handle_mm_fault+0x0/0x318) from [] (do_page_fault+0x188/0x1e4) [] (do_page_fault+0x0/0x1e4) from [] (do_translation_fault+0x7c/0x84) [] (do_translation_fault+0x0/0x84) from [] (do_DataAbort+0x40/0xa4) r8:c1ff5e20 r7:c0340120 r6:00000805 r5:c1ff5e54 r4:c03400d0 [] (do_DataAbort+0x0/0xa4) from [] (__dabt_svc+0x4c/0x60) ... So we disable highmem support on these systems. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index e0d32770bb3d..9d015ee5747a 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -36,6 +36,7 @@ #include #include #include +#include /* * as from 2.5, kernels no longer have an init_tasks structure @@ -586,12 +587,6 @@ struct tlb_args { unsigned long ta_end; }; -/* all SMP configurations have the extended CPUID registers */ -static inline int tlb_ops_need_broadcast(void) -{ - return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2; -} - static inline void ipi_flush_tlb_all(void *ignored) { local_flush_tlb_all(); -- cgit v1.2.2 From 90140c30a7b8c77e8872a389d48678d78e58789f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 27 Sep 2009 21:04:48 +0100 Subject: ARM: Fix __cpuexit section mismatch warnings Fix: WARNING: vmlinux.o(.text+0x247c): Section mismatch in reference from the function cpu_idle() to the function .cpuexit.text:cpu_die() The function cpu_idle() references a function in an exit section. Often the function cpu_die() has valid usage outside the exit section and the fix is to remove the __cpuexit annotation of cpu_die. WARNING: vmlinux.o(.cpuexit.text+0x3c): Section mismatch in reference from the function cpu_die() to the function .cpuinit.text:secondary_start_kernel() The function __cpuexit cpu_die() references a function __cpuinit secondary_start_kernel(). This is often seen when error handling in the exit function uses functionality in the init path. The fix is often to remove the __cpuinit annotation of secondary_start_kernel() so it may be used outside an init section. Sam says: > The annotation of cpu_die() is wrong. > To be annotated __cpuexit the function shall: > - be used in exit context and only in exit context with HOTPLUG_CPU=n > - be used outside exit context with HOTPLUG_CPU=y So, this also means __cpu_disable(), __cpu_die() and twd_timer_stop() are also wrong. However, removing __cpuexit from cpu_die() creates: WARNING: vmlinux.o(.text+0x6834): Section mismatch in reference from the function cpu_die() to the function .cpuinit.text:secondary_start_kernel() The function cpu_die() references the function __cpuinit secondary_start_kernel(). This is often because cpu_die lacks a __cpuinit annotation or the annotation of secondary_start_kernel is wrong. so fix this using __ref. Signed-off-by: Russell King Acked-by: Sam Ravnborg --- arch/arm/kernel/smp.c | 6 +++--- arch/arm/kernel/smp_twd.c | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 9d015ee5747a..57162af53dc9 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -154,7 +154,7 @@ int __cpuinit __cpu_up(unsigned int cpu) /* * __cpu_disable runs on the processor to be shutdown. */ -int __cpuexit __cpu_disable(void) +int __cpu_disable(void) { unsigned int cpu = smp_processor_id(); struct task_struct *p; @@ -201,7 +201,7 @@ int __cpuexit __cpu_disable(void) * called on the thread which is asking for a CPU to be shutdown - * waits until shutdown has completed, or it is timed out. */ -void __cpuexit __cpu_die(unsigned int cpu) +void __cpu_die(unsigned int cpu) { if (!platform_cpu_kill(cpu)) printk("CPU%u: unable to kill\n", cpu); @@ -215,7 +215,7 @@ void __cpuexit __cpu_die(unsigned int cpu) * of the other hotplug-cpu capable cores, so presumably coming * out of idle fixes this. */ -void __cpuexit cpu_die(void) +void __ref cpu_die(void) { unsigned int cpu = smp_processor_id(); diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index d8c88c633c6f..a73a34dccf2a 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -166,10 +166,12 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) clockevents_register_device(clk); } +#ifdef CONFIG_HOTPLUG_CPU /* * take a local timer down */ -void __cpuexit twd_timer_stop(void) +void twd_timer_stop(void) { __raw_writel(0, twd_base + TWD_TIMER_CONTROL); } +#endif -- cgit v1.2.2 From aa45ee8fc0ee87c1711b5fe8eb3556d06530c39e Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 28 Sep 2009 11:41:51 +0100 Subject: ARM: Ensure do_cache_op takes mmap_sem do_cache_op() uses find_vma() to validate its arguments without holding any locking. This means that the VMA could vanish beneath us. Fix this by taking a read lock on mmap_sem. Signed-off-by: Russell King --- arch/arm/kernel/traps.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 57eb0f6f6005..467b69ed1021 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -418,12 +418,14 @@ static int bad_syscall(int n, struct pt_regs *regs) static inline void do_cache_op(unsigned long start, unsigned long end, int flags) { + struct mm_struct *mm = current->active_mm; struct vm_area_struct *vma; if (end < start || flags) return; - vma = find_vma(current->active_mm, start); + down_read(&mm->mmap_sem); + vma = find_vma(mm, start); if (vma && vma->vm_start < end) { if (start < vma->vm_start) start = vma->vm_start; @@ -432,6 +434,7 @@ do_cache_op(unsigned long start, unsigned long end, int flags) flush_cache_user_range(vma, start, end); } + up_read(&mm->mmap_sem); } /* -- cgit v1.2.2 From 6176d39471943a2e574782cbf62deded19b96aa0 Mon Sep 17 00:00:00 2001 From: Dmitry Artamonow Date: Tue, 29 Sep 2009 06:12:37 +0100 Subject: ARM: 5734/1: arm: fix compilation of entry-common.S for older CPUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 181f817eaaca4c1f introduced some new code to entry-common.S Sadly, this new code uses 'bx' instruction which is available only on ARMv5 and higher CPUs. This causes following compilation errors when building kernel for StrongARM (ARMv4): arch/arm/kernel/entry-common.S: Assembler messages: arch/arm/kernel/entry-common.S:129: Error: selected processor does not support `bx ip' arch/arm/kernel/entry-common.S:138: Error: selected processor does not support `bx ip' Fix these errors by using 'mov pc' instead of 'bx'. Signed-off-by: Dmitry Artamonow Acked-by: Uwe Kleine-König Signed-off-by: Russell King --- arch/arm/kernel/entry-common.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 807cfebb0f44..825db52e558a 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -126,7 +126,7 @@ ENTRY(__gnu_mcount_nc) cmp r0, r2 bne gnu_trace ldmia sp!, {r0-r3, ip, lr} - bx ip + mov pc, ip gnu_trace: ldr r1, [sp, #20] @ lr of instrumented routine @@ -135,7 +135,7 @@ gnu_trace: mov lr, pc mov pc, r2 ldmia sp!, {r0-r3, ip, lr} - bx ip + mov pc, ip ENTRY(mcount) stmdb sp!, {r0-r3, lr} -- cgit v1.2.2 From 31abdb744179159f8b605f56da5b197b188e1689 Mon Sep 17 00:00:00 2001 From: David Brown Date: Thu, 1 Oct 2009 17:43:29 +0100 Subject: ARM: 5739/1: ARM: allow empty ATAG_CORE From: David Brown The ATAG_CORE is allowed to be empty. Although this is handled by parse_tag_core(), __vet_atags during startup rejects this tag unless it contains data. Allow the initial tag to be either the full size, or empty. Signed-off-by: David Brown Signed-off-by: Russell King --- arch/arm/kernel/head-common.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S index 93ad576b2d74..885a7214418d 100644 --- a/arch/arm/kernel/head-common.S +++ b/arch/arm/kernel/head-common.S @@ -13,6 +13,7 @@ #define ATAG_CORE 0x54410001 #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) +#define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2) .align 2 .type __switch_data, %object @@ -251,7 +252,8 @@ __vet_atags: bne 1f ldr r5, [r2, #0] @ is first tag ATAG_CORE? - subs r5, r5, #ATAG_CORE_SIZE + cmp r5, #ATAG_CORE_SIZE + cmpne r5, #ATAG_CORE_SIZE_EMPTY bne 1f ldr r5, [r2, #4] ldr r6, =ATAG_CORE -- cgit v1.2.2 From 4fb2847437d871fe579f820ceb18031db3359901 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Fri, 25 Sep 2009 13:39:47 +0100 Subject: ARM: 5727/1: Pass IFSR register to do_PrefetchAbort() Instruction fault status register, IFSR, was introduced on ARMv6 to provide status information about the last insturction fault. It needed for proper prefetch abort handling. Now we have three prefetch abort model: * legacy - for CPUs before ARMv6. They doesn't provide neither IFSR nor IFAR. We simulate IFSR with section translation fault status for them to generalize code; * ARMv6 - provides IFSR, but not IFAR; * ARMv7 - provides both IFSR and IFAR. Signed-off-by: Kirill A. Shutemov Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 18 ++++++------------ arch/arm/kernel/entry-common.S | 7 ------- 2 files changed, 6 insertions(+), 19 deletions(-) (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 0a2ba51cf35d..322410be573c 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -311,22 +311,16 @@ __pabt_svc: tst r3, #PSR_I_BIT biceq r9, r9, #PSR_I_BIT - @ - @ set args, then call main handler - @ - @ r0 - address of faulting instruction - @ r1 - pointer to registers on stack - @ -#ifdef MULTI_PABORT mov r0, r2 @ pass address of aborted instruction. +#ifdef MULTI_PABORT ldr r4, .LCprocfns mov lr, pc ldr pc, [r4, #PROCESSOR_PABT_FUNC] #else - CPU_PABORT_HANDLER(r0, r2) + bl CPU_PABORT_HANDLER #endif msr cpsr_c, r9 @ Maybe enable interrupts - mov r1, sp @ regs + mov r2, sp @ regs bl do_PrefetchAbort @ call abort handler @ @@ -701,16 +695,16 @@ ENDPROC(__und_usr_unknown) __pabt_usr: usr_entry -#ifdef MULTI_PABORT mov r0, r2 @ pass address of aborted instruction. +#ifdef MULTI_PABORT ldr r4, .LCprocfns mov lr, pc ldr pc, [r4, #PROCESSOR_PABT_FUNC] #else - CPU_PABORT_HANDLER(r0, r2) + bl CPU_PABORT_HANDLER #endif enable_irq @ Enable interrupts - mov r1, sp @ regs + mov r2, sp @ regs bl do_PrefetchAbort @ call abort handler UNWIND(.fnend ) /* fall through */ diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 825db52e558a..f0fe95b7085d 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -425,13 +425,6 @@ sys_mmap2: #endif ENDPROC(sys_mmap2) -ENTRY(pabort_ifar) - mrc p15, 0, r0, cr6, cr0, 2 -ENTRY(pabort_noifar) - mov pc, lr -ENDPROC(pabort_ifar) -ENDPROC(pabort_noifar) - #ifdef CONFIG_OABI_COMPAT /* -- cgit v1.2.2