0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/init.h>
0010
0011 #include <asm/cputype.h>
0012 #include <asm/system_info.h>
0013 #include <asm/thread_notify.h>
0014
0015
0016
0017
0018 static inline unsigned long teehbr_read(void)
0019 {
0020 unsigned long v;
0021 asm("mrc p14, 6, %0, c1, c0, 0\n" : "=r" (v));
0022 return v;
0023 }
0024
0025 static inline void teehbr_write(unsigned long v)
0026 {
0027 asm("mcr p14, 6, %0, c1, c0, 0\n" : : "r" (v));
0028 }
0029
0030 static int thumbee_notifier(struct notifier_block *self, unsigned long cmd, void *t)
0031 {
0032 struct thread_info *thread = t;
0033
0034 switch (cmd) {
0035 case THREAD_NOTIFY_FLUSH:
0036 teehbr_write(0);
0037 break;
0038 case THREAD_NOTIFY_SWITCH:
0039 current_thread_info()->thumbee_state = teehbr_read();
0040 teehbr_write(thread->thumbee_state);
0041 break;
0042 }
0043
0044 return NOTIFY_DONE;
0045 }
0046
0047 static struct notifier_block thumbee_notifier_block = {
0048 .notifier_call = thumbee_notifier,
0049 };
0050
0051 static int __init thumbee_init(void)
0052 {
0053 unsigned long pfr0;
0054 unsigned int cpu_arch = cpu_architecture();
0055
0056 if (cpu_arch < CPU_ARCH_ARMv7)
0057 return 0;
0058
0059 pfr0 = read_cpuid_ext(CPUID_EXT_PFR0);
0060 if ((pfr0 & 0x0000f000) != 0x00001000)
0061 return 0;
0062
0063 pr_info("ThumbEE CPU extension supported.\n");
0064 elf_hwcap |= HWCAP_THUMBEE;
0065 thread_register_notifier(&thumbee_notifier_block);
0066
0067 return 0;
0068 }
0069
0070 late_initcall(thumbee_init);