1 /* 2 * linux/include/asm-arm/proc-armv/system.h 3 * 4 * Copyright (C) 1996 Russell King 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 #ifndef __ASM_PROC_SYSTEM_H 11 #define __ASM_PROC_SYSTEM_H 12 13 /* 14 * Save the current interrupt enable state & disable IRQs 15 */ 16 #ifdef CONFIG_ARM64 17 18 /* 19 * Save the current interrupt enable state 20 * and disable IRQs/FIQs 21 */ 22 #define local_irq_save(flags) \ 23 ({ \ 24 asm volatile( \ 25 "mrs %0, daif" \ 26 "msr daifset, #3" \ 27 : "=r" (flags) \ 28 : \ 29 : "memory"); \ 30 }) 31 32 /* 33 * restore saved IRQ & FIQ state 34 */ 35 #define local_irq_restore(flags) \ 36 ({ \ 37 asm volatile( \ 38 "msr daif, %0" \ 39 : \ 40 : "r" (flags) \ 41 : "memory"); \ 42 }) 43 44 /* 45 * Enable IRQs/FIQs 46 */ 47 #define local_irq_enable() \ 48 ({ \ 49 asm volatile( \ 50 "msr daifclr, #3" \ 51 : \ 52 : \ 53 : "memory"); \ 54 }) 55 56 /* 57 * Disable IRQs/FIQs 58 */ 59 #define local_irq_disable() \ 60 ({ \ 61 asm volatile( \ 62 "msr daifset, #3" \ 63 : \ 64 : \ 65 : "memory"); \ 66 }) 67 68 #else /* CONFIG_ARM64 */ 69 70 #define local_irq_save(x) \ 71 ({ \ 72 unsigned long temp; \ 73 __asm__ __volatile__( \ 74 "mrs %0, cpsr @ local_irq_save\n" \ 75 " orr %1, %0, #128\n" \ 76 " msr cpsr_c, %1" \ 77 : "=r" (x), "=r" (temp) \ 78 : \ 79 : "memory"); \ 80 }) 81 82 /* 83 * Enable IRQs 84 */ 85 #define local_irq_enable() \ 86 ({ \ 87 unsigned long temp; \ 88 __asm__ __volatile__( \ 89 "mrs %0, cpsr @ local_irq_enable\n" \ 90 " bic %0, %0, #128\n" \ 91 " msr cpsr_c, %0" \ 92 : "=r" (temp) \ 93 : \ 94 : "memory"); \ 95 }) 96 97 /* 98 * Disable IRQs 99 */ 100 #define local_irq_disable() \ 101 ({ \ 102 unsigned long temp; \ 103 __asm__ __volatile__( \ 104 "mrs %0, cpsr @ local_irq_disable\n" \ 105 " orr %0, %0, #128\n" \ 106 " msr cpsr_c, %0" \ 107 : "=r" (temp) \ 108 : \ 109 : "memory"); \ 110 }) 111 112 /* 113 * Enable FIQs 114 */ 115 #define __stf() \ 116 ({ \ 117 unsigned long temp; \ 118 __asm__ __volatile__( \ 119 "mrs %0, cpsr @ stf\n" \ 120 " bic %0, %0, #64\n" \ 121 " msr cpsr_c, %0" \ 122 : "=r" (temp) \ 123 : \ 124 : "memory"); \ 125 }) 126 127 /* 128 * Disable FIQs 129 */ 130 #define __clf() \ 131 ({ \ 132 unsigned long temp; \ 133 __asm__ __volatile__( \ 134 "mrs %0, cpsr @ clf\n" \ 135 " orr %0, %0, #64\n" \ 136 " msr cpsr_c, %0" \ 137 : "=r" (temp) \ 138 : \ 139 : "memory"); \ 140 }) 141 142 /* 143 * Save the current interrupt enable state. 144 */ 145 #define local_save_flags(x) \ 146 ({ \ 147 __asm__ __volatile__( \ 148 "mrs %0, cpsr @ local_save_flags\n" \ 149 : "=r" (x) \ 150 : \ 151 : "memory"); \ 152 }) 153 154 /* 155 * restore saved IRQ & FIQ state 156 */ 157 #define local_irq_restore(x) \ 158 __asm__ __volatile__( \ 159 "msr cpsr_c, %0 @ local_irq_restore\n" \ 160 : \ 161 : "r" (x) \ 162 : "memory") 163 164 #endif /* CONFIG_ARM64 */ 165 166 #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110) || \ 167 defined(CONFIG_ARM64) 168 /* 169 * On the StrongARM, "swp" is terminally broken since it bypasses the 170 * cache totally. This means that the cache becomes inconsistent, and, 171 * since we use normal loads/stores as well, this is really bad. 172 * Typically, this causes oopsen in filp_close, but could have other, 173 * more disasterous effects. There are two work-arounds: 174 * 1. Disable interrupts and emulate the atomic swap 175 * 2. Clean the cache, perform atomic swap, flush the cache 176 * 177 * We choose (1) since its the "easiest" to achieve here and is not 178 * dependent on the processor type. 179 */ 180 #define swp_is_buggy 181 #endif 182 183 static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) 184 { 185 extern void __bad_xchg(volatile void *, int); 186 unsigned long ret; 187 #ifdef swp_is_buggy 188 unsigned long flags; 189 #endif 190 191 switch (size) { 192 #ifdef swp_is_buggy 193 case 1: 194 local_irq_save(flags); 195 ret = *(volatile unsigned char *)ptr; 196 *(volatile unsigned char *)ptr = x; 197 local_irq_restore(flags); 198 break; 199 200 case 4: 201 local_irq_save(flags); 202 ret = *(volatile unsigned long *)ptr; 203 *(volatile unsigned long *)ptr = x; 204 local_irq_restore(flags); 205 break; 206 #else 207 case 1: __asm__ __volatile__ ("swpb %0, %1, [%2]" 208 : "=&r" (ret) 209 : "r" (x), "r" (ptr) 210 : "memory"); 211 break; 212 case 4: __asm__ __volatile__ ("swp %0, %1, [%2]" 213 : "=&r" (ret) 214 : "r" (x), "r" (ptr) 215 : "memory"); 216 break; 217 #endif 218 default: __bad_xchg(ptr, size), ret = 0; 219 } 220 221 return ret; 222 } 223 224 #endif 225