aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-08-01 19:30:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-08-01 19:30:45 -0400
commit9a2533c3eb91b3e769c2612c5d68e811bfc0ecf6 (patch)
tree74865c4c40442d109e42bcc72009ebd0c320eba3
parentd4fdc32517efaab0493c134d5cc070c252d51275 (diff)
parentb74253f78400f9a4b42da84bb1de7540b88ce7c4 (diff)
Merge branch 'fixes' of git://git.linaro.org/people/rmk/linux-arm
Pull ARM fixes from Russell King: "This fixes various issues found during July" * 'fixes' of git://git.linaro.org/people/rmk/linux-arm: ARM: 7479/1: mm: avoid NULL dereference when flushing gate_vma with VIVT caches ARM: Fix undefined instruction exception handling ARM: 7480/1: only call smp_send_stop() on SMP ARM: 7478/1: errata: extend workaround for erratum #720789 ARM: 7477/1: vfp: Always save VFP state in vfp_pm_suspend on UP ARM: 7476/1: vfp: only clear vfp state for current cpu in vfp_pm_suspend ARM: 7468/1: ftrace: Trace function entry before updating index ARM: 7467/1: mutex: use generic xchg-based implementation for ARMv6+ ARM: 7466/1: disable interrupt before spinning endlessly ARM: 7465/1: Handle >4GB memory sizes in device tree and mem=size@start option
-rw-r--r--arch/arm/include/asm/cacheflush.h8
-rw-r--r--arch/arm/include/asm/mutex.h119
-rw-r--r--arch/arm/include/asm/setup.h4
-rw-r--r--arch/arm/kernel/entry-armv.S111
-rw-r--r--arch/arm/kernel/ftrace.c17
-rw-r--r--arch/arm/kernel/process.c2
-rw-r--r--arch/arm/kernel/setup.c6
-rw-r--r--arch/arm/kernel/smp.c3
-rw-r--r--arch/arm/kernel/traps.c8
-rw-r--r--arch/arm/mm/tlb-v7.S12
-rw-r--r--arch/arm/vfp/entry.S16
-rw-r--r--arch/arm/vfp/vfphw.S19
-rw-r--r--arch/arm/vfp/vfpmodule.c8
13 files changed, 139 insertions, 194 deletions
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 004c1bc95d2b..e4448e16046d 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -215,7 +215,9 @@ static inline void vivt_flush_cache_mm(struct mm_struct *mm)
215static inline void 215static inline void
216vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) 216vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
217{ 217{
218 if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) 218 struct mm_struct *mm = vma->vm_mm;
219
220 if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))
219 __cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end), 221 __cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end),
220 vma->vm_flags); 222 vma->vm_flags);
221} 223}
@@ -223,7 +225,9 @@ vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned
223static inline void 225static inline void
224vivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn) 226vivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn)
225{ 227{
226 if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) { 228 struct mm_struct *mm = vma->vm_mm;
229
230 if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) {
227 unsigned long addr = user_addr & PAGE_MASK; 231 unsigned long addr = user_addr & PAGE_MASK;
228 __cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags); 232 __cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags);
229 } 233 }
diff --git a/arch/arm/include/asm/mutex.h b/arch/arm/include/asm/mutex.h
index 93226cf23ae0..b1479fd04a95 100644
--- a/arch/arm/include/asm/mutex.h
+++ b/arch/arm/include/asm/mutex.h
@@ -7,121 +7,10 @@
7 */ 7 */
8#ifndef _ASM_MUTEX_H 8#ifndef _ASM_MUTEX_H
9#define _ASM_MUTEX_H 9#define _ASM_MUTEX_H
10
11#if __LINUX_ARM_ARCH__ < 6
12/* On pre-ARMv6 hardware the swp based implementation is the most efficient. */
13# include <asm-generic/mutex-xchg.h>
14#else
15
16/* 10/*
17 * Attempting to lock a mutex on ARMv6+ can be done with a bastardized 11 * On pre-ARMv6 hardware this results in a swp-based implementation,
18 * atomic decrement (it is not a reliable atomic decrement but it satisfies 12 * which is the most efficient. For ARMv6+, we emit a pair of exclusive
19 * the defined semantics for our purpose, while being smaller and faster 13 * accesses instead.
20 * than a real atomic decrement or atomic swap. The idea is to attempt
21 * decrementing the lock value only once. If once decremented it isn't zero,
22 * or if its store-back fails due to a dispute on the exclusive store, we
23 * simply bail out immediately through the slow path where the lock will be
24 * reattempted until it succeeds.
25 */ 14 */
26static inline void 15#include <asm-generic/mutex-xchg.h>
27__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
28{
29 int __ex_flag, __res;
30
31 __asm__ (
32
33 "ldrex %0, [%2] \n\t"
34 "sub %0, %0, #1 \n\t"
35 "strex %1, %0, [%2] "
36
37 : "=&r" (__res), "=&r" (__ex_flag)
38 : "r" (&(count)->counter)
39 : "cc","memory" );
40
41 __res |= __ex_flag;
42 if (unlikely(__res != 0))
43 fail_fn(count);
44}
45
46static inline int
47__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
48{
49 int __ex_flag, __res;
50
51 __asm__ (
52
53 "ldrex %0, [%2] \n\t"
54 "sub %0, %0, #1 \n\t"
55 "strex %1, %0, [%2] "
56
57 : "=&r" (__res), "=&r" (__ex_flag)
58 : "r" (&(count)->counter)
59 : "cc","memory" );
60
61 __res |= __ex_flag;
62 if (unlikely(__res != 0))
63 __res = fail_fn(count);
64 return __res;
65}
66
67/*
68 * Same trick is used for the unlock fast path. However the original value,
69 * rather than the result, is used to test for success in order to have
70 * better generated assembly.
71 */
72static inline void
73__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
74{
75 int __ex_flag, __res, __orig;
76
77 __asm__ (
78
79 "ldrex %0, [%3] \n\t"
80 "add %1, %0, #1 \n\t"
81 "strex %2, %1, [%3] "
82
83 : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
84 : "r" (&(count)->counter)
85 : "cc","memory" );
86
87 __orig |= __ex_flag;
88 if (unlikely(__orig != 0))
89 fail_fn(count);
90}
91
92/*
93 * If the unlock was done on a contended lock, or if the unlock simply fails
94 * then the mutex remains locked.
95 */
96#define __mutex_slowpath_needs_to_unlock() 1
97
98/*
99 * For __mutex_fastpath_trylock we use another construct which could be
100 * described as a "single value cmpxchg".
101 *
102 * This provides the needed trylock semantics like cmpxchg would, but it is
103 * lighter and less generic than a true cmpxchg implementation.
104 */
105static inline int
106__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
107{
108 int __ex_flag, __res, __orig;
109
110 __asm__ (
111
112 "1: ldrex %0, [%3] \n\t"
113 "subs %1, %0, #1 \n\t"
114 "strexeq %2, %1, [%3] \n\t"
115 "movlt %0, #0 \n\t"
116 "cmpeq %2, #0 \n\t"
117 "bgt 1b "
118
119 : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
120 : "r" (&count->counter)
121 : "cc", "memory" );
122
123 return __orig;
124}
125
126#endif
127#endif 16#endif
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index 23ebc0c82a39..24d284a1bfc7 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -196,7 +196,7 @@ static const struct tagtable __tagtable_##fn __tag = { tag, fn }
196 196
197struct membank { 197struct membank {
198 phys_addr_t start; 198 phys_addr_t start;
199 unsigned long size; 199 phys_addr_t size;
200 unsigned int highmem; 200 unsigned int highmem;
201}; 201};
202 202
@@ -217,7 +217,7 @@ extern struct meminfo meminfo;
217#define bank_phys_end(bank) ((bank)->start + (bank)->size) 217#define bank_phys_end(bank) ((bank)->start + (bank)->size)
218#define bank_phys_size(bank) (bank)->size 218#define bank_phys_size(bank) (bank)->size
219 219
220extern int arm_add_memory(phys_addr_t start, unsigned long size); 220extern int arm_add_memory(phys_addr_t start, phys_addr_t size);
221extern void early_print(const char *str, ...); 221extern void early_print(const char *str, ...);
222extern void dump_machine_table(void); 222extern void dump_machine_table(void);
223 223
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 0d1851ca6eb9..0f82098c9bfe 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -244,6 +244,19 @@ svc_preempt:
244 b 1b 244 b 1b
245#endif 245#endif
246 246
247__und_fault:
248 @ Correct the PC such that it is pointing at the instruction
249 @ which caused the fault. If the faulting instruction was ARM
250 @ the PC will be pointing at the next instruction, and have to
251 @ subtract 4. Otherwise, it is Thumb, and the PC will be
252 @ pointing at the second half of the Thumb instruction. We
253 @ have to subtract 2.
254 ldr r2, [r0, #S_PC]
255 sub r2, r2, r1
256 str r2, [r0, #S_PC]
257 b do_undefinstr
258ENDPROC(__und_fault)
259
247 .align 5 260 .align 5
248__und_svc: 261__und_svc:
249#ifdef CONFIG_KPROBES 262#ifdef CONFIG_KPROBES
@@ -261,25 +274,32 @@ __und_svc:
261 @ 274 @
262 @ r0 - instruction 275 @ r0 - instruction
263 @ 276 @
264#ifndef CONFIG_THUMB2_KERNEL 277#ifndef CONFIG_THUMB2_KERNEL
265 ldr r0, [r4, #-4] 278 ldr r0, [r4, #-4]
266#else 279#else
280 mov r1, #2
267 ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2 281 ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2
268 cmp r0, #0xe800 @ 32-bit instruction if xx >= 0 282 cmp r0, #0xe800 @ 32-bit instruction if xx >= 0
269 ldrhhs r9, [r4] @ bottom 16 bits 283 blo __und_svc_fault
270 orrhs r0, r9, r0, lsl #16 284 ldrh r9, [r4] @ bottom 16 bits
285 add r4, r4, #2
286 str r4, [sp, #S_PC]
287 orr r0, r9, r0, lsl #16
271#endif 288#endif
272 adr r9, BSYM(1f) 289 adr r9, BSYM(__und_svc_finish)
273 mov r2, r4 290 mov r2, r4
274 bl call_fpe 291 bl call_fpe
275 292
293 mov r1, #4 @ PC correction to apply
294__und_svc_fault:
276 mov r0, sp @ struct pt_regs *regs 295 mov r0, sp @ struct pt_regs *regs
277 bl do_undefinstr 296 bl __und_fault
278 297
279 @ 298 @
280 @ IRQs off again before pulling preserved data off the stack 299 @ IRQs off again before pulling preserved data off the stack
281 @ 300 @
2821: disable_irq_notrace 301__und_svc_finish:
302 disable_irq_notrace
283 303
284 @ 304 @
285 @ restore SPSR and restart the instruction 305 @ restore SPSR and restart the instruction
@@ -423,25 +443,33 @@ __und_usr:
423 mov r2, r4 443 mov r2, r4
424 mov r3, r5 444 mov r3, r5
425 445
446 @ r2 = regs->ARM_pc, which is either 2 or 4 bytes ahead of the
447 @ faulting instruction depending on Thumb mode.
448 @ r3 = regs->ARM_cpsr
426 @ 449 @
427 @ fall through to the emulation code, which returns using r9 if 450 @ The emulation code returns using r9 if it has emulated the
428 @ it has emulated the instruction, or the more conventional lr 451 @ instruction, or the more conventional lr if we are to treat
429 @ if we are to treat this as a real undefined instruction 452 @ this as a real undefined instruction
430 @
431 @ r0 - instruction
432 @ 453 @
433 adr r9, BSYM(ret_from_exception) 454 adr r9, BSYM(ret_from_exception)
434 adr lr, BSYM(__und_usr_unknown) 455
435 tst r3, #PSR_T_BIT @ Thumb mode? 456 tst r3, #PSR_T_BIT @ Thumb mode?
436 itet eq @ explicit IT needed for the 1f label 457 bne __und_usr_thumb
437 subeq r4, r2, #4 @ ARM instr at LR - 4 458 sub r4, r2, #4 @ ARM instr at LR - 4
438 subne r4, r2, #2 @ Thumb instr at LR - 2 4591: ldrt r0, [r4]
4391: ldreqt r0, [r4]
440#ifdef CONFIG_CPU_ENDIAN_BE8 460#ifdef CONFIG_CPU_ENDIAN_BE8
441 reveq r0, r0 @ little endian instruction 461 rev r0, r0 @ little endian instruction
442#endif 462#endif
443 beq call_fpe 463 @ r0 = 32-bit ARM instruction which caused the exception
464 @ r2 = PC value for the following instruction (:= regs->ARM_pc)
465 @ r4 = PC value for the faulting instruction
466 @ lr = 32-bit undefined instruction function
467 adr lr, BSYM(__und_usr_fault_32)
468 b call_fpe
469
470__und_usr_thumb:
444 @ Thumb instruction 471 @ Thumb instruction
472 sub r4, r2, #2 @ First half of thumb instr at LR - 2
445#if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7 473#if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7
446/* 474/*
447 * Thumb-2 instruction handling. Note that because pre-v6 and >= v6 platforms 475 * Thumb-2 instruction handling. Note that because pre-v6 and >= v6 platforms
@@ -455,7 +483,7 @@ __und_usr:
455 ldr r5, .LCcpu_architecture 483 ldr r5, .LCcpu_architecture
456 ldr r5, [r5] 484 ldr r5, [r5]
457 cmp r5, #CPU_ARCH_ARMv7 485 cmp r5, #CPU_ARCH_ARMv7
458 blo __und_usr_unknown 486 blo __und_usr_fault_16 @ 16bit undefined instruction
459/* 487/*
460 * The following code won't get run unless the running CPU really is v7, so 488 * The following code won't get run unless the running CPU really is v7, so
461 * coding round the lack of ldrht on older arches is pointless. Temporarily 489 * coding round the lack of ldrht on older arches is pointless. Temporarily
@@ -463,15 +491,18 @@ __und_usr:
463 */ 491 */
464 .arch armv6t2 492 .arch armv6t2
465#endif 493#endif
4662: 4942: ldrht r5, [r4]
467 ARM( ldrht r5, [r4], #2 )
468 THUMB( ldrht r5, [r4] )
469 THUMB( add r4, r4, #2 )
470 cmp r5, #0xe800 @ 32bit instruction if xx != 0 495 cmp r5, #0xe800 @ 32bit instruction if xx != 0
471 blo __und_usr_unknown 496 blo __und_usr_fault_16 @ 16bit undefined instruction
4723: ldrht r0, [r4] 4973: ldrht r0, [r2]
473 add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 498 add r2, r2, #2 @ r2 is PC + 2, make it PC + 4
499 str r2, [sp, #S_PC] @ it's a 2x16bit instr, update
474 orr r0, r0, r5, lsl #16 500 orr r0, r0, r5, lsl #16
501 adr lr, BSYM(__und_usr_fault_32)
502 @ r0 = the two 16-bit Thumb instructions which caused the exception
503 @ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc)
504 @ r4 = PC value for the first 16-bit Thumb instruction
505 @ lr = 32bit undefined instruction function
475 506
476#if __LINUX_ARM_ARCH__ < 7 507#if __LINUX_ARM_ARCH__ < 7
477/* If the target arch was overridden, change it back: */ 508/* If the target arch was overridden, change it back: */
@@ -482,17 +513,13 @@ __und_usr:
482#endif 513#endif
483#endif /* __LINUX_ARM_ARCH__ < 7 */ 514#endif /* __LINUX_ARM_ARCH__ < 7 */
484#else /* !(CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7) */ 515#else /* !(CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7) */
485 b __und_usr_unknown 516 b __und_usr_fault_16
486#endif 517#endif
487 UNWIND(.fnend ) 518 UNWIND(.fnend)
488ENDPROC(__und_usr) 519ENDPROC(__und_usr)
489 520
490 @
491 @ fallthrough to call_fpe
492 @
493
494/* 521/*
495 * The out of line fixup for the ldrt above. 522 * The out of line fixup for the ldrt instructions above.
496 */ 523 */
497 .pushsection .fixup, "ax" 524 .pushsection .fixup, "ax"
498 .align 2 525 .align 2
@@ -524,11 +551,12 @@ ENDPROC(__und_usr)
524 * NEON handler code. 551 * NEON handler code.
525 * 552 *
526 * Emulators may wish to make use of the following registers: 553 * Emulators may wish to make use of the following registers:
527 * r0 = instruction opcode. 554 * r0 = instruction opcode (32-bit ARM or two 16-bit Thumb)
528 * r2 = PC+4 555 * r2 = PC value to resume execution after successful emulation
529 * r9 = normal "successful" return address 556 * r9 = normal "successful" return address
530 * r10 = this threads thread_info structure. 557 * r10 = this threads thread_info structure
531 * lr = unrecognised instruction return address 558 * lr = unrecognised instruction return address
559 * IRQs disabled, FIQs enabled.
532 */ 560 */
533 @ 561 @
534 @ Fall-through from Thumb-2 __und_usr 562 @ Fall-through from Thumb-2 __und_usr
@@ -659,12 +687,17 @@ ENTRY(no_fp)
659 mov pc, lr 687 mov pc, lr
660ENDPROC(no_fp) 688ENDPROC(no_fp)
661 689
662__und_usr_unknown: 690__und_usr_fault_32:
663 enable_irq 691 mov r1, #4
692 b 1f
693__und_usr_fault_16:
694 mov r1, #2
6951: enable_irq
664 mov r0, sp 696 mov r0, sp
665 adr lr, BSYM(ret_from_exception) 697 adr lr, BSYM(ret_from_exception)
666 b do_undefinstr 698 b __und_fault
667ENDPROC(__und_usr_unknown) 699ENDPROC(__und_usr_fault_32)
700ENDPROC(__und_usr_fault_16)
668 701
669 .align 5 702 .align 5
670__pabt_usr: 703__pabt_usr:
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index df0bf0c8cb79..34e56647dcee 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -179,19 +179,20 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
179 old = *parent; 179 old = *parent;
180 *parent = return_hooker; 180 *parent = return_hooker;
181 181
182 err = ftrace_push_return_trace(old, self_addr, &trace.depth,
183 frame_pointer);
184 if (err == -EBUSY) {
185 *parent = old;
186 return;
187 }
188
189 trace.func = self_addr; 182 trace.func = self_addr;
183 trace.depth = current->curr_ret_stack + 1;
190 184
191 /* Only trace if the calling function expects to */ 185 /* Only trace if the calling function expects to */
192 if (!ftrace_graph_entry(&trace)) { 186 if (!ftrace_graph_entry(&trace)) {
193 current->curr_ret_stack--;
194 *parent = old; 187 *parent = old;
188 return;
189 }
190
191 err = ftrace_push_return_trace(old, self_addr, &trace.depth,
192 frame_pointer);
193 if (err == -EBUSY) {
194 *parent = old;
195 return;
195 } 196 }
196} 197}
197 198
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 19c95ea65b2f..693b744fd572 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -247,6 +247,7 @@ void machine_shutdown(void)
247void machine_halt(void) 247void machine_halt(void)
248{ 248{
249 machine_shutdown(); 249 machine_shutdown();
250 local_irq_disable();
250 while (1); 251 while (1);
251} 252}
252 253
@@ -268,6 +269,7 @@ void machine_restart(char *cmd)
268 269
269 /* Whoops - the platform was unable to reboot. Tell the user! */ 270 /* Whoops - the platform was unable to reboot. Tell the user! */
270 printk("Reboot failed -- System halted\n"); 271 printk("Reboot failed -- System halted\n");
272 local_irq_disable();
271 while (1); 273 while (1);
272} 274}
273 275
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index e15d83bb4ea3..a81dcecc7343 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -508,7 +508,7 @@ void __init dump_machine_table(void)
508 /* can't use cpu_relax() here as it may require MMU setup */; 508 /* can't use cpu_relax() here as it may require MMU setup */;
509} 509}
510 510
511int __init arm_add_memory(phys_addr_t start, unsigned long size) 511int __init arm_add_memory(phys_addr_t start, phys_addr_t size)
512{ 512{
513 struct membank *bank = &meminfo.bank[meminfo.nr_banks]; 513 struct membank *bank = &meminfo.bank[meminfo.nr_banks];
514 514
@@ -538,7 +538,7 @@ int __init arm_add_memory(phys_addr_t start, unsigned long size)
538 } 538 }
539#endif 539#endif
540 540
541 bank->size = size & PAGE_MASK; 541 bank->size = size & ~(phys_addr_t)(PAGE_SIZE - 1);
542 542
543 /* 543 /*
544 * Check whether this memory region has non-zero size or 544 * Check whether this memory region has non-zero size or
@@ -558,7 +558,7 @@ int __init arm_add_memory(phys_addr_t start, unsigned long size)
558static int __init early_mem(char *p) 558static int __init early_mem(char *p)
559{ 559{
560 static int usermem __initdata = 0; 560 static int usermem __initdata = 0;
561 unsigned long size; 561 phys_addr_t size;
562 phys_addr_t start; 562 phys_addr_t start;
563 char *endp; 563 char *endp;
564 564
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index aea74f5bc34a..ebd8ad274d76 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -563,7 +563,8 @@ void smp_send_stop(void)
563 563
564 cpumask_copy(&mask, cpu_online_mask); 564 cpumask_copy(&mask, cpu_online_mask);
565 cpumask_clear_cpu(smp_processor_id(), &mask); 565 cpumask_clear_cpu(smp_processor_id(), &mask);
566 smp_cross_call(&mask, IPI_CPU_STOP); 566 if (!cpumask_empty(&mask))
567 smp_cross_call(&mask, IPI_CPU_STOP);
567 568
568 /* Wait up to one second for other CPUs to stop */ 569 /* Wait up to one second for other CPUs to stop */
569 timeout = USEC_PER_SEC; 570 timeout = USEC_PER_SEC;
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 8b97d739b17b..7978d4f0f3ae 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -402,18 +402,10 @@ static int call_undef_hook(struct pt_regs *regs, unsigned int instr)
402 402
403asmlinkage void __exception do_undefinstr(struct pt_regs *regs) 403asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
404{ 404{
405 unsigned int correction = thumb_mode(regs) ? 2 : 4;
406 unsigned int instr; 405 unsigned int instr;
407 siginfo_t info; 406 siginfo_t info;
408 void __user *pc; 407 void __user *pc;
409 408
410 /*
411 * According to the ARM ARM, PC is 2 or 4 bytes ahead,
412 * depending whether we're in Thumb mode or not.
413 * Correct this offset.
414 */
415 regs->ARM_pc -= correction;
416
417 pc = (void __user *)instruction_pointer(regs); 409 pc = (void __user *)instruction_pointer(regs);
418 410
419 if (processor_mode(regs) == SVC_MODE) { 411 if (processor_mode(regs) == SVC_MODE) {
diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S
index 845f461f8ec1..c2021139cb56 100644
--- a/arch/arm/mm/tlb-v7.S
+++ b/arch/arm/mm/tlb-v7.S
@@ -38,11 +38,19 @@ ENTRY(v7wbi_flush_user_tlb_range)
38 dsb 38 dsb
39 mov r0, r0, lsr #PAGE_SHIFT @ align address 39 mov r0, r0, lsr #PAGE_SHIFT @ align address
40 mov r1, r1, lsr #PAGE_SHIFT 40 mov r1, r1, lsr #PAGE_SHIFT
41#ifdef CONFIG_ARM_ERRATA_720789
42 mov r3, #0
43#else
41 asid r3, r3 @ mask ASID 44 asid r3, r3 @ mask ASID
45#endif
42 orr r0, r3, r0, lsl #PAGE_SHIFT @ Create initial MVA 46 orr r0, r3, r0, lsl #PAGE_SHIFT @ Create initial MVA
43 mov r1, r1, lsl #PAGE_SHIFT 47 mov r1, r1, lsl #PAGE_SHIFT
441: 481:
49#ifdef CONFIG_ARM_ERRATA_720789
50 ALT_SMP(mcr p15, 0, r0, c8, c3, 3) @ TLB invalidate U MVA all ASID (shareable)
51#else
45 ALT_SMP(mcr p15, 0, r0, c8, c3, 1) @ TLB invalidate U MVA (shareable) 52 ALT_SMP(mcr p15, 0, r0, c8, c3, 1) @ TLB invalidate U MVA (shareable)
53#endif
46 ALT_UP(mcr p15, 0, r0, c8, c7, 1) @ TLB invalidate U MVA 54 ALT_UP(mcr p15, 0, r0, c8, c7, 1) @ TLB invalidate U MVA
47 55
48 add r0, r0, #PAGE_SZ 56 add r0, r0, #PAGE_SZ
@@ -67,7 +75,11 @@ ENTRY(v7wbi_flush_kern_tlb_range)
67 mov r0, r0, lsl #PAGE_SHIFT 75 mov r0, r0, lsl #PAGE_SHIFT
68 mov r1, r1, lsl #PAGE_SHIFT 76 mov r1, r1, lsl #PAGE_SHIFT
691: 771:
78#ifdef CONFIG_ARM_ERRATA_720789
79 ALT_SMP(mcr p15, 0, r0, c8, c3, 3) @ TLB invalidate U MVA all ASID (shareable)
80#else
70 ALT_SMP(mcr p15, 0, r0, c8, c3, 1) @ TLB invalidate U MVA (shareable) 81 ALT_SMP(mcr p15, 0, r0, c8, c3, 1) @ TLB invalidate U MVA (shareable)
82#endif
71 ALT_UP(mcr p15, 0, r0, c8, c7, 1) @ TLB invalidate U MVA 83 ALT_UP(mcr p15, 0, r0, c8, c7, 1) @ TLB invalidate U MVA
72 add r0, r0, #PAGE_SZ 84 add r0, r0, #PAGE_SZ
73 cmp r0, r1 85 cmp r0, r1
diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
index 4fa9903b83cf..cc926c985981 100644
--- a/arch/arm/vfp/entry.S
+++ b/arch/arm/vfp/entry.S
@@ -7,18 +7,20 @@
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation. 9 * published by the Free Software Foundation.
10 *
11 * Basic entry code, called from the kernel's undefined instruction trap.
12 * r0 = faulted instruction
13 * r5 = faulted PC+4
14 * r9 = successful return
15 * r10 = thread_info structure
16 * lr = failure return
17 */ 10 */
18#include <asm/thread_info.h> 11#include <asm/thread_info.h>
19#include <asm/vfpmacros.h> 12#include <asm/vfpmacros.h>
20#include "../kernel/entry-header.S" 13#include "../kernel/entry-header.S"
21 14
15@ VFP entry point.
16@
17@ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb)
18@ r2 = PC value to resume execution after successful emulation
19@ r9 = normal "successful" return address
20@ r10 = this threads thread_info structure
21@ lr = unrecognised instruction return address
22@ IRQs disabled.
23@
22ENTRY(do_vfp) 24ENTRY(do_vfp)
23#ifdef CONFIG_PREEMPT 25#ifdef CONFIG_PREEMPT
24 ldr r4, [r10, #TI_PREEMPT] @ get preempt count 26 ldr r4, [r10, #TI_PREEMPT] @ get preempt count
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index d50f0e486cf2..ea0349f63586 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -62,13 +62,13 @@
62 62
63@ VFP hardware support entry point. 63@ VFP hardware support entry point.
64@ 64@
65@ r0 = faulted instruction 65@ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb)
66@ r2 = faulted PC+4 66@ r2 = PC value to resume execution after successful emulation
67@ r9 = successful return 67@ r9 = normal "successful" return address
68@ r10 = vfp_state union 68@ r10 = vfp_state union
69@ r11 = CPU number 69@ r11 = CPU number
70@ lr = failure return 70@ lr = unrecognised instruction return address
71 71@ IRQs enabled.
72ENTRY(vfp_support_entry) 72ENTRY(vfp_support_entry)
73 DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10 73 DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10
74 74
@@ -162,9 +162,12 @@ vfp_hw_state_valid:
162 @ exception before retrying branch 162 @ exception before retrying branch
163 @ out before setting an FPEXC that 163 @ out before setting an FPEXC that
164 @ stops us reading stuff 164 @ stops us reading stuff
165 VFPFMXR FPEXC, r1 @ restore FPEXC last 165 VFPFMXR FPEXC, r1 @ Restore FPEXC last
166 sub r2, r2, #4 166 sub r2, r2, #4 @ Retry current instruction - if Thumb
167 str r2, [sp, #S_PC] @ retry the instruction 167 str r2, [sp, #S_PC] @ mode it's two 16-bit instructions,
168 @ else it's one 32-bit instruction, so
169 @ always subtract 4 from the following
170 @ instruction address.
168#ifdef CONFIG_PREEMPT 171#ifdef CONFIG_PREEMPT
169 get_thread_info r10 172 get_thread_info r10
170 ldr r4, [r10, #TI_PREEMPT] @ get preempt count 173 ldr r4, [r10, #TI_PREEMPT] @ get preempt count
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 586961929e96..fb849d044bde 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -457,10 +457,16 @@ static int vfp_pm_suspend(void)
457 457
458 /* disable, just in case */ 458 /* disable, just in case */
459 fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); 459 fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
460 } else if (vfp_current_hw_state[ti->cpu]) {
461#ifndef CONFIG_SMP
462 fmxr(FPEXC, fpexc | FPEXC_EN);
463 vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
464 fmxr(FPEXC, fpexc);
465#endif
460 } 466 }
461 467
462 /* clear any information we had about last context state */ 468 /* clear any information we had about last context state */
463 memset(vfp_current_hw_state, 0, sizeof(vfp_current_hw_state)); 469 vfp_current_hw_state[ti->cpu] = NULL;
464 470
465 return 0; 471 return 0;
466} 472}