diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/kernel/asm-offsets.c | 10 | ||||
-rw-r--r-- | arch/arm/kernel/calls.S | 4 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 111 | ||||
-rw-r--r-- | arch/arm/kernel/entry-common.S | 5 | ||||
-rw-r--r-- | arch/arm/kernel/head-common.S | 7 | ||||
-rw-r--r-- | arch/arm/kernel/thumbee.c | 81 |
7 files changed, 179 insertions, 40 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 00d44c6fbfe9..d5be3f7ac0e3 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -22,6 +22,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | |||
22 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o | 22 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o |
23 | obj-$(CONFIG_ATAGS_PROC) += atags.o | 23 | obj-$(CONFIG_ATAGS_PROC) += atags.o |
24 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o | 24 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o |
25 | obj-$(CONFIG_ARM_THUMBEE) += thumbee.o | ||
25 | 26 | ||
26 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o | 27 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o |
27 | AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 | 28 | AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 |
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 3278e713c32a..0a0d2479274b 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c | |||
@@ -58,6 +58,9 @@ int main(void) | |||
58 | DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value)); | 58 | DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value)); |
59 | DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate)); | 59 | DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate)); |
60 | DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate)); | 60 | DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate)); |
61 | #ifdef CONFIG_ARM_THUMBEE | ||
62 | DEFINE(TI_THUMBEE_STATE, offsetof(struct thread_info, thumbee_state)); | ||
63 | #endif | ||
61 | #ifdef CONFIG_IWMMXT | 64 | #ifdef CONFIG_IWMMXT |
62 | DEFINE(TI_IWMMXT_STATE, offsetof(struct thread_info, fpstate.iwmmxt)); | 65 | DEFINE(TI_IWMMXT_STATE, offsetof(struct thread_info, fpstate.iwmmxt)); |
63 | #endif | 66 | #endif |
@@ -108,5 +111,12 @@ int main(void) | |||
108 | DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush)); | 111 | DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush)); |
109 | DEFINE(PROCINFO_MM_MMUFLAGS, offsetof(struct proc_info_list, __cpu_mm_mmu_flags)); | 112 | DEFINE(PROCINFO_MM_MMUFLAGS, offsetof(struct proc_info_list, __cpu_mm_mmu_flags)); |
110 | DEFINE(PROCINFO_IO_MMUFLAGS, offsetof(struct proc_info_list, __cpu_io_mmu_flags)); | 113 | DEFINE(PROCINFO_IO_MMUFLAGS, offsetof(struct proc_info_list, __cpu_io_mmu_flags)); |
114 | BLANK(); | ||
115 | #ifdef MULTI_DABORT | ||
116 | DEFINE(PROCESSOR_DABT_FUNC, offsetof(struct processor, _data_abort)); | ||
117 | #endif | ||
118 | #ifdef MULTI_PABORT | ||
119 | DEFINE(PROCESSOR_PABT_FUNC, offsetof(struct processor, _prefetch_abort)); | ||
120 | #endif | ||
111 | return 0; | 121 | return 0; |
112 | } | 122 | } |
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 283e14fff993..95f1c121cb30 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S | |||
@@ -359,9 +359,11 @@ | |||
359 | CALL(sys_kexec_load) | 359 | CALL(sys_kexec_load) |
360 | CALL(sys_utimensat) | 360 | CALL(sys_utimensat) |
361 | CALL(sys_signalfd) | 361 | CALL(sys_signalfd) |
362 | /* 350 */ CALL(sys_ni_syscall) | 362 | /* 350 */ CALL(sys_timerfd_create) |
363 | CALL(sys_eventfd) | 363 | CALL(sys_eventfd) |
364 | CALL(sys_fallocate) | 364 | CALL(sys_fallocate) |
365 | CALL(sys_timerfd_settime) | ||
366 | CALL(sys_timerfd_gettime) | ||
365 | #ifndef syscalls_counted | 367 | #ifndef syscalls_counted |
366 | .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls | 368 | .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls |
367 | #define syscalls_counted | 369 | #define syscalls_counted |
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index a46d5b456765..7dca225752c1 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -166,12 +166,12 @@ __dabt_svc: | |||
166 | @ The abort handler must return the aborted address in r0, and | 166 | @ The abort handler must return the aborted address in r0, and |
167 | @ the fault status register in r1. r9 must be preserved. | 167 | @ the fault status register in r1. r9 must be preserved. |
168 | @ | 168 | @ |
169 | #ifdef MULTI_ABORT | 169 | #ifdef MULTI_DABORT |
170 | ldr r4, .LCprocfns | 170 | ldr r4, .LCprocfns |
171 | mov lr, pc | 171 | mov lr, pc |
172 | ldr pc, [r4] | 172 | ldr pc, [r4, #PROCESSOR_DABT_FUNC] |
173 | #else | 173 | #else |
174 | bl CPU_ABORT_HANDLER | 174 | bl CPU_DABORT_HANDLER |
175 | #endif | 175 | #endif |
176 | 176 | ||
177 | @ | 177 | @ |
@@ -209,14 +209,12 @@ __irq_svc: | |||
209 | 209 | ||
210 | irq_handler | 210 | irq_handler |
211 | #ifdef CONFIG_PREEMPT | 211 | #ifdef CONFIG_PREEMPT |
212 | str r8, [tsk, #TI_PREEMPT] @ restore preempt count | ||
212 | ldr r0, [tsk, #TI_FLAGS] @ get flags | 213 | ldr r0, [tsk, #TI_FLAGS] @ get flags |
214 | teq r8, #0 @ if preempt count != 0 | ||
215 | movne r0, #0 @ force flags to 0 | ||
213 | tst r0, #_TIF_NEED_RESCHED | 216 | tst r0, #_TIF_NEED_RESCHED |
214 | blne svc_preempt | 217 | blne svc_preempt |
215 | preempt_return: | ||
216 | ldr r0, [tsk, #TI_PREEMPT] @ read preempt value | ||
217 | str r8, [tsk, #TI_PREEMPT] @ restore preempt count | ||
218 | teq r0, r7 | ||
219 | strne r0, [r0, -r0] @ bug() | ||
220 | #endif | 218 | #endif |
221 | ldr r0, [sp, #S_PSR] @ irqs are already disabled | 219 | ldr r0, [sp, #S_PSR] @ irqs are already disabled |
222 | msr spsr_cxsf, r0 | 220 | msr spsr_cxsf, r0 |
@@ -230,19 +228,11 @@ preempt_return: | |||
230 | 228 | ||
231 | #ifdef CONFIG_PREEMPT | 229 | #ifdef CONFIG_PREEMPT |
232 | svc_preempt: | 230 | svc_preempt: |
233 | teq r8, #0 @ was preempt count = 0 | 231 | mov r8, lr |
234 | ldreq r6, .LCirq_stat | ||
235 | movne pc, lr @ no | ||
236 | ldr r0, [r6, #4] @ local_irq_count | ||
237 | ldr r1, [r6, #8] @ local_bh_count | ||
238 | adds r0, r0, r1 | ||
239 | movne pc, lr | ||
240 | mov r7, #0 @ preempt_schedule_irq | ||
241 | str r7, [tsk, #TI_PREEMPT] @ expects preempt_count == 0 | ||
242 | 1: bl preempt_schedule_irq @ irq en/disable is done inside | 232 | 1: bl preempt_schedule_irq @ irq en/disable is done inside |
243 | ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS | 233 | ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS |
244 | tst r0, #_TIF_NEED_RESCHED | 234 | tst r0, #_TIF_NEED_RESCHED |
245 | beq preempt_return @ go again | 235 | moveq pc, r8 @ go again |
246 | b 1b | 236 | b 1b |
247 | #endif | 237 | #endif |
248 | 238 | ||
@@ -293,7 +283,6 @@ __pabt_svc: | |||
293 | mrs r9, cpsr | 283 | mrs r9, cpsr |
294 | tst r3, #PSR_I_BIT | 284 | tst r3, #PSR_I_BIT |
295 | biceq r9, r9, #PSR_I_BIT | 285 | biceq r9, r9, #PSR_I_BIT |
296 | msr cpsr_c, r9 | ||
297 | 286 | ||
298 | @ | 287 | @ |
299 | @ set args, then call main handler | 288 | @ set args, then call main handler |
@@ -301,7 +290,15 @@ __pabt_svc: | |||
301 | @ r0 - address of faulting instruction | 290 | @ r0 - address of faulting instruction |
302 | @ r1 - pointer to registers on stack | 291 | @ r1 - pointer to registers on stack |
303 | @ | 292 | @ |
304 | mov r0, r2 @ address (pc) | 293 | #ifdef MULTI_PABORT |
294 | mov r0, r2 @ pass address of aborted instruction. | ||
295 | ldr r4, .LCprocfns | ||
296 | mov lr, pc | ||
297 | ldr pc, [r4, #PROCESSOR_PABT_FUNC] | ||
298 | #else | ||
299 | CPU_PABORT_HANDLER(r0, r2) | ||
300 | #endif | ||
301 | msr cpsr_c, r9 @ Maybe enable interrupts | ||
305 | mov r1, sp @ regs | 302 | mov r1, sp @ regs |
306 | bl do_PrefetchAbort @ call abort handler | 303 | bl do_PrefetchAbort @ call abort handler |
307 | 304 | ||
@@ -320,16 +317,12 @@ __pabt_svc: | |||
320 | .align 5 | 317 | .align 5 |
321 | .LCcralign: | 318 | .LCcralign: |
322 | .word cr_alignment | 319 | .word cr_alignment |
323 | #ifdef MULTI_ABORT | 320 | #ifdef MULTI_DABORT |
324 | .LCprocfns: | 321 | .LCprocfns: |
325 | .word processor | 322 | .word processor |
326 | #endif | 323 | #endif |
327 | .LCfp: | 324 | .LCfp: |
328 | .word fp_enter | 325 | .word fp_enter |
329 | #ifdef CONFIG_PREEMPT | ||
330 | .LCirq_stat: | ||
331 | .word irq_stat | ||
332 | #endif | ||
333 | 326 | ||
334 | /* | 327 | /* |
335 | * User mode handlers | 328 | * User mode handlers |
@@ -404,12 +397,12 @@ __dabt_usr: | |||
404 | @ The abort handler must return the aborted address in r0, and | 397 | @ The abort handler must return the aborted address in r0, and |
405 | @ the fault status register in r1. | 398 | @ the fault status register in r1. |
406 | @ | 399 | @ |
407 | #ifdef MULTI_ABORT | 400 | #ifdef MULTI_DABORT |
408 | ldr r4, .LCprocfns | 401 | ldr r4, .LCprocfns |
409 | mov lr, pc | 402 | mov lr, pc |
410 | ldr pc, [r4] | 403 | ldr pc, [r4, #PROCESSOR_DABT_FUNC] |
411 | #else | 404 | #else |
412 | bl CPU_ABORT_HANDLER | 405 | bl CPU_DABORT_HANDLER |
413 | #endif | 406 | #endif |
414 | 407 | ||
415 | @ | 408 | @ |
@@ -455,10 +448,6 @@ __irq_usr: | |||
455 | __und_usr: | 448 | __und_usr: |
456 | usr_entry | 449 | usr_entry |
457 | 450 | ||
458 | tst r3, #PSR_T_BIT @ Thumb mode? | ||
459 | bne __und_usr_unknown @ ignore FP | ||
460 | sub r4, r2, #4 | ||
461 | |||
462 | @ | 451 | @ |
463 | @ fall through to the emulation code, which returns using r9 if | 452 | @ fall through to the emulation code, which returns using r9 if |
464 | @ it has emulated the instruction, or the more conventional lr | 453 | @ it has emulated the instruction, or the more conventional lr |
@@ -468,7 +457,24 @@ __und_usr: | |||
468 | @ | 457 | @ |
469 | adr r9, ret_from_exception | 458 | adr r9, ret_from_exception |
470 | adr lr, __und_usr_unknown | 459 | adr lr, __und_usr_unknown |
471 | 1: ldrt r0, [r4] | 460 | tst r3, #PSR_T_BIT @ Thumb mode? |
461 | subeq r4, r2, #4 @ ARM instr at LR - 4 | ||
462 | subne r4, r2, #2 @ Thumb instr at LR - 2 | ||
463 | 1: ldreqt r0, [r4] | ||
464 | beq call_fpe | ||
465 | @ Thumb instruction | ||
466 | #if __LINUX_ARM_ARCH__ >= 7 | ||
467 | 2: ldrht r5, [r4], #2 | ||
468 | and r0, r5, #0xf800 @ mask bits 111x x... .... .... | ||
469 | cmp r0, #0xe800 @ 32bit instruction if xx != 0 | ||
470 | blo __und_usr_unknown | ||
471 | 3: ldrht r0, [r4] | ||
472 | add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 | ||
473 | orr r0, r0, r5, lsl #16 | ||
474 | #else | ||
475 | b __und_usr_unknown | ||
476 | #endif | ||
477 | |||
472 | @ | 478 | @ |
473 | @ fallthrough to call_fpe | 479 | @ fallthrough to call_fpe |
474 | @ | 480 | @ |
@@ -477,10 +483,14 @@ __und_usr: | |||
477 | * The out of line fixup for the ldrt above. | 483 | * The out of line fixup for the ldrt above. |
478 | */ | 484 | */ |
479 | .section .fixup, "ax" | 485 | .section .fixup, "ax" |
480 | 2: mov pc, r9 | 486 | 4: mov pc, r9 |
481 | .previous | 487 | .previous |
482 | .section __ex_table,"a" | 488 | .section __ex_table,"a" |
483 | .long 1b, 2b | 489 | .long 1b, 4b |
490 | #if __LINUX_ARM_ARCH__ >= 7 | ||
491 | .long 2b, 4b | ||
492 | .long 3b, 4b | ||
493 | #endif | ||
484 | .previous | 494 | .previous |
485 | 495 | ||
486 | /* | 496 | /* |
@@ -507,9 +517,16 @@ __und_usr: | |||
507 | * r10 = this threads thread_info structure. | 517 | * r10 = this threads thread_info structure. |
508 | * lr = unrecognised instruction return address | 518 | * lr = unrecognised instruction return address |
509 | */ | 519 | */ |
520 | @ | ||
521 | @ Fall-through from Thumb-2 __und_usr | ||
522 | @ | ||
523 | #ifdef CONFIG_NEON | ||
524 | adr r6, .LCneon_thumb_opcodes | ||
525 | b 2f | ||
526 | #endif | ||
510 | call_fpe: | 527 | call_fpe: |
511 | #ifdef CONFIG_NEON | 528 | #ifdef CONFIG_NEON |
512 | adr r6, .LCneon_opcodes | 529 | adr r6, .LCneon_arm_opcodes |
513 | 2: | 530 | 2: |
514 | ldr r7, [r6], #4 @ mask value | 531 | ldr r7, [r6], #4 @ mask value |
515 | cmp r7, #0 @ end mask? | 532 | cmp r7, #0 @ end mask? |
@@ -526,6 +543,7 @@ call_fpe: | |||
526 | 1: | 543 | 1: |
527 | #endif | 544 | #endif |
528 | tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27 | 545 | tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27 |
546 | tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2 | ||
529 | #if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) | 547 | #if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) |
530 | and r8, r0, #0x0f000000 @ mask out op-code bits | 548 | and r8, r0, #0x0f000000 @ mask out op-code bits |
531 | teqne r8, #0x0f000000 @ SWI (ARM6/7 bug)? | 549 | teqne r8, #0x0f000000 @ SWI (ARM6/7 bug)? |
@@ -577,7 +595,7 @@ call_fpe: | |||
577 | #ifdef CONFIG_NEON | 595 | #ifdef CONFIG_NEON |
578 | .align 6 | 596 | .align 6 |
579 | 597 | ||
580 | .LCneon_opcodes: | 598 | .LCneon_arm_opcodes: |
581 | .word 0xfe000000 @ mask | 599 | .word 0xfe000000 @ mask |
582 | .word 0xf2000000 @ opcode | 600 | .word 0xf2000000 @ opcode |
583 | 601 | ||
@@ -586,6 +604,16 @@ call_fpe: | |||
586 | 604 | ||
587 | .word 0x00000000 @ mask | 605 | .word 0x00000000 @ mask |
588 | .word 0x00000000 @ opcode | 606 | .word 0x00000000 @ opcode |
607 | |||
608 | .LCneon_thumb_opcodes: | ||
609 | .word 0xef000000 @ mask | ||
610 | .word 0xef000000 @ opcode | ||
611 | |||
612 | .word 0xff100000 @ mask | ||
613 | .word 0xf9000000 @ opcode | ||
614 | |||
615 | .word 0x00000000 @ mask | ||
616 | .word 0x00000000 @ opcode | ||
589 | #endif | 617 | #endif |
590 | 618 | ||
591 | do_fpe: | 619 | do_fpe: |
@@ -619,8 +647,15 @@ __und_usr_unknown: | |||
619 | __pabt_usr: | 647 | __pabt_usr: |
620 | usr_entry | 648 | usr_entry |
621 | 649 | ||
650 | #ifdef MULTI_PABORT | ||
651 | mov r0, r2 @ pass address of aborted instruction. | ||
652 | ldr r4, .LCprocfns | ||
653 | mov lr, pc | ||
654 | ldr pc, [r4, #PROCESSOR_PABT_FUNC] | ||
655 | #else | ||
656 | CPU_PABORT_HANDLER(r0, r2) | ||
657 | #endif | ||
622 | enable_irq @ Enable interrupts | 658 | enable_irq @ Enable interrupts |
623 | mov r0, r2 @ address (pc) | ||
624 | mov r1, sp @ regs | 659 | mov r1, sp @ regs |
625 | bl do_PrefetchAbort @ call abort handler | 660 | bl do_PrefetchAbort @ call abort handler |
626 | /* fall through */ | 661 | /* fall through */ |
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 6c90c50a9ee3..597ed00a08d8 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
@@ -352,6 +352,11 @@ sys_mmap2: | |||
352 | b do_mmap2 | 352 | b do_mmap2 |
353 | #endif | 353 | #endif |
354 | 354 | ||
355 | ENTRY(pabort_ifar) | ||
356 | mrc p15, 0, r0, cr6, cr0, 2 | ||
357 | ENTRY(pabort_noifar) | ||
358 | mov pc, lr | ||
359 | |||
355 | #ifdef CONFIG_OABI_COMPAT | 360 | #ifdef CONFIG_OABI_COMPAT |
356 | 361 | ||
357 | /* | 362 | /* |
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S index 50f667febe29..7e9c00a8a412 100644 --- a/arch/arm/kernel/head-common.S +++ b/arch/arm/kernel/head-common.S | |||
@@ -75,8 +75,13 @@ __error_p: | |||
75 | #ifdef CONFIG_DEBUG_LL | 75 | #ifdef CONFIG_DEBUG_LL |
76 | adr r0, str_p1 | 76 | adr r0, str_p1 |
77 | bl printascii | 77 | bl printascii |
78 | mov r0, r9 | ||
79 | bl printhex8 | ||
80 | adr r0, str_p2 | ||
81 | bl printascii | ||
78 | b __error | 82 | b __error |
79 | str_p1: .asciz "\nError: unrecognized/unsupported processor variant.\n" | 83 | str_p1: .asciz "\nError: unrecognized/unsupported processor variant (0x" |
84 | str_p2: .asciz ").\n" | ||
80 | .align | 85 | .align |
81 | #endif | 86 | #endif |
82 | 87 | ||
diff --git a/arch/arm/kernel/thumbee.c b/arch/arm/kernel/thumbee.c new file mode 100644 index 000000000000..df3f6b7ebcea --- /dev/null +++ b/arch/arm/kernel/thumbee.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * arch/arm/kernel/thumbee.c | ||
3 | * | ||
4 | * Copyright (C) 2008 ARM Limited | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/init.h> | ||
22 | |||
23 | #include <asm/thread_notify.h> | ||
24 | |||
25 | /* | ||
26 | * Access to the ThumbEE Handler Base register | ||
27 | */ | ||
28 | static inline unsigned long teehbr_read() | ||
29 | { | ||
30 | unsigned long v; | ||
31 | asm("mrc p14, 6, %0, c1, c0, 0\n" : "=r" (v)); | ||
32 | return v; | ||
33 | } | ||
34 | |||
35 | static inline void teehbr_write(unsigned long v) | ||
36 | { | ||
37 | asm("mcr p14, 6, %0, c1, c0, 0\n" : : "r" (v)); | ||
38 | } | ||
39 | |||
40 | static int thumbee_notifier(struct notifier_block *self, unsigned long cmd, void *t) | ||
41 | { | ||
42 | struct thread_info *thread = t; | ||
43 | |||
44 | switch (cmd) { | ||
45 | case THREAD_NOTIFY_FLUSH: | ||
46 | thread->thumbee_state = 0; | ||
47 | break; | ||
48 | case THREAD_NOTIFY_SWITCH: | ||
49 | current_thread_info()->thumbee_state = teehbr_read(); | ||
50 | teehbr_write(thread->thumbee_state); | ||
51 | break; | ||
52 | } | ||
53 | |||
54 | return NOTIFY_DONE; | ||
55 | } | ||
56 | |||
57 | static struct notifier_block thumbee_notifier_block = { | ||
58 | .notifier_call = thumbee_notifier, | ||
59 | }; | ||
60 | |||
61 | static int __init thumbee_init(void) | ||
62 | { | ||
63 | unsigned long pfr0; | ||
64 | unsigned int cpu_arch = cpu_architecture(); | ||
65 | |||
66 | if (cpu_arch < CPU_ARCH_ARMv7) | ||
67 | return 0; | ||
68 | |||
69 | /* processor feature register 0 */ | ||
70 | asm("mrc p15, 0, %0, c0, c1, 0\n" : "=r" (pfr0)); | ||
71 | if ((pfr0 & 0x0000f000) != 0x00001000) | ||
72 | return 0; | ||
73 | |||
74 | printk(KERN_INFO "ThumbEE CPU extension supported.\n"); | ||
75 | elf_hwcap |= HWCAP_THUMBEE; | ||
76 | thread_register_notifier(&thumbee_notifier_block); | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | late_initcall(thumbee_init); | ||