diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-01 19:30:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-01 19:30:45 -0400 |
commit | 9a2533c3eb91b3e769c2612c5d68e811bfc0ecf6 (patch) | |
tree | 74865c4c40442d109e42bcc72009ebd0c320eba3 | |
parent | d4fdc32517efaab0493c134d5cc070c252d51275 (diff) | |
parent | b74253f78400f9a4b42da84bb1de7540b88ce7c4 (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.h | 8 | ||||
-rw-r--r-- | arch/arm/include/asm/mutex.h | 119 | ||||
-rw-r--r-- | arch/arm/include/asm/setup.h | 4 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 111 | ||||
-rw-r--r-- | arch/arm/kernel/ftrace.c | 17 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 6 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 3 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 8 | ||||
-rw-r--r-- | arch/arm/mm/tlb-v7.S | 12 | ||||
-rw-r--r-- | arch/arm/vfp/entry.S | 16 | ||||
-rw-r--r-- | arch/arm/vfp/vfphw.S | 19 | ||||
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 8 |
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) | |||
215 | static inline void | 215 | static inline void |
216 | vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) | 216 | vivt_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 | |||
223 | static inline void | 225 | static inline void |
224 | vivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn) | 226 | vivt_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 | */ |
26 | static 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 | |||
46 | static 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 | */ | ||
72 | static 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 | */ | ||
105 | static 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 | ||
197 | struct membank { | 197 | struct 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 | ||
220 | extern int arm_add_memory(phys_addr_t start, unsigned long size); | 220 | extern int arm_add_memory(phys_addr_t start, phys_addr_t size); |
221 | extern void early_print(const char *str, ...); | 221 | extern void early_print(const char *str, ...); |
222 | extern void dump_machine_table(void); | 222 | extern 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 | ||
258 | ENDPROC(__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 | @ |
282 | 1: 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 | 459 | 1: ldrt r0, [r4] |
439 | 1: 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 |
466 | 2: | 494 | 2: 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 |
472 | 3: ldrht r0, [r4] | 497 | 3: 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) |
488 | ENDPROC(__und_usr) | 519 | ENDPROC(__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 |
660 | ENDPROC(no_fp) | 688 | ENDPROC(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 | ||
695 | 1: 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 |
667 | ENDPROC(__und_usr_unknown) | 699 | ENDPROC(__und_usr_fault_32) |
700 | ENDPROC(__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) | |||
247 | void machine_halt(void) | 247 | void 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 | ||
511 | int __init arm_add_memory(phys_addr_t start, unsigned long size) | 511 | int __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) | |||
558 | static int __init early_mem(char *p) | 558 | static 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 | ||
403 | asmlinkage void __exception do_undefinstr(struct pt_regs *regs) | 403 | asmlinkage 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 |
44 | 1: | 48 | 1: |
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 |
69 | 1: | 77 | 1: |
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 | @ | ||
22 | ENTRY(do_vfp) | 24 | ENTRY(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. | |
72 | ENTRY(vfp_support_entry) | 72 | ENTRY(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 | } |