1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * arch/arm/kernel/thumbee.c 4 * 5 * Copyright (C) 2008 ARM Limited 6 */ 7 8 #include <linux/kernel.h> 9 #include <linux/init.h> 10 11 #include <asm/cputype.h> 12 #include <asm/system_info.h> 13 #include <asm/thread_notify.h> 14 15 /* 16 * Access to the ThumbEE Handler Base register 17 */ 18 static inline unsigned long teehbr_read(void) 19 { 20 unsigned long v; 21 asm("mrc p14, 6, %0, c1, c0, 0\n" : "=r" (v)); 22 return v; 23 } 24 25 static inline void teehbr_write(unsigned long v) 26 { 27 asm("mcr p14, 6, %0, c1, c0, 0\n" : : "r" (v)); 28 } 29 30 static int thumbee_notifier(struct notifier_block *self, unsigned long cmd, void *t) 31 { 32 struct thread_info *thread = t; 33 34 switch (cmd) { 35 case THREAD_NOTIFY_FLUSH: 36 teehbr_write(0); 37 break; 38 case THREAD_NOTIFY_SWITCH: 39 current_thread_info()->thumbee_state = teehbr_read(); 40 teehbr_write(thread->thumbee_state); 41 break; 42 } 43 44 return NOTIFY_DONE; 45 } 46 47 static struct notifier_block thumbee_notifier_block = { 48 .notifier_call = thumbee_notifier, 49 }; 50 51 static int __init thumbee_init(void) 52 { 53 unsigned long pfr0; 54 unsigned int cpu_arch = cpu_architecture(); 55 56 if (cpu_arch < CPU_ARCH_ARMv7) 57 return 0; 58 59 pfr0 = read_cpuid_ext(CPUID_EXT_PFR0); 60 if ((pfr0 & 0x0000f000) != 0x00001000) 61 return 0; 62 63 pr_info("ThumbEE CPU extension supported.\n"); 64 elf_hwcap |= HWCAP_THUMBEE; 65 thread_register_notifier(&thumbee_notifier_block); 66 67 return 0; 68 } 69 70 late_initcall(thumbee_init); 71