diff options
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/compiler.h | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/include/linux/compiler.h b/include/linux/compiler.h index d5ad7b1118fc..a1c81f80978e 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h | |||
| @@ -186,6 +186,80 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); | |||
| 186 | # define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__) | 186 | # define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__) |
| 187 | #endif | 187 | #endif |
| 188 | 188 | ||
| 189 | #include <uapi/linux/types.h> | ||
| 190 | |||
| 191 | static __always_inline void data_access_exceeds_word_size(void) | ||
| 192 | #ifdef __compiletime_warning | ||
| 193 | __compiletime_warning("data access exceeds word size and won't be atomic") | ||
| 194 | #endif | ||
| 195 | ; | ||
| 196 | |||
| 197 | static __always_inline void data_access_exceeds_word_size(void) | ||
| 198 | { | ||
| 199 | } | ||
| 200 | |||
| 201 | static __always_inline void __read_once_size(volatile void *p, void *res, int size) | ||
| 202 | { | ||
| 203 | switch (size) { | ||
| 204 | case 1: *(__u8 *)res = *(volatile __u8 *)p; break; | ||
| 205 | case 2: *(__u16 *)res = *(volatile __u16 *)p; break; | ||
| 206 | case 4: *(__u32 *)res = *(volatile __u32 *)p; break; | ||
| 207 | #ifdef CONFIG_64BIT | ||
| 208 | case 8: *(__u64 *)res = *(volatile __u64 *)p; break; | ||
| 209 | #endif | ||
| 210 | default: | ||
| 211 | barrier(); | ||
| 212 | __builtin_memcpy((void *)res, (const void *)p, size); | ||
| 213 | data_access_exceeds_word_size(); | ||
| 214 | barrier(); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | static __always_inline void __assign_once_size(volatile void *p, void *res, int size) | ||
| 219 | { | ||
| 220 | switch (size) { | ||
| 221 | case 1: *(volatile __u8 *)p = *(__u8 *)res; break; | ||
| 222 | case 2: *(volatile __u16 *)p = *(__u16 *)res; break; | ||
| 223 | case 4: *(volatile __u32 *)p = *(__u32 *)res; break; | ||
| 224 | #ifdef CONFIG_64BIT | ||
| 225 | case 8: *(volatile __u64 *)p = *(__u64 *)res; break; | ||
| 226 | #endif | ||
| 227 | default: | ||
| 228 | barrier(); | ||
| 229 | __builtin_memcpy((void *)p, (const void *)res, size); | ||
| 230 | data_access_exceeds_word_size(); | ||
| 231 | barrier(); | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | /* | ||
| 236 | * Prevent the compiler from merging or refetching reads or writes. The | ||
| 237 | * compiler is also forbidden from reordering successive instances of | ||
| 238 | * READ_ONCE, ASSIGN_ONCE and ACCESS_ONCE (see below), but only when the | ||
| 239 | * compiler is aware of some particular ordering. One way to make the | ||
| 240 | * compiler aware of ordering is to put the two invocations of READ_ONCE, | ||
| 241 | * ASSIGN_ONCE or ACCESS_ONCE() in different C statements. | ||
| 242 | * | ||
| 243 | * In contrast to ACCESS_ONCE these two macros will also work on aggregate | ||
| 244 | * data types like structs or unions. If the size of the accessed data | ||
| 245 | * type exceeds the word size of the machine (e.g., 32 bits or 64 bits) | ||
| 246 | * READ_ONCE() and ASSIGN_ONCE() will fall back to memcpy and print a | ||
| 247 | * compile-time warning. | ||
| 248 | * | ||
| 249 | * Their two major use cases are: (1) Mediating communication between | ||
| 250 | * process-level code and irq/NMI handlers, all running on the same CPU, | ||
| 251 | * and (2) Ensuring that the compiler does not fold, spindle, or otherwise | ||
| 252 | * mutilate accesses that either do not require ordering or that interact | ||
| 253 | * with an explicit memory barrier or atomic instruction that provides the | ||
| 254 | * required ordering. | ||
| 255 | */ | ||
| 256 | |||
| 257 | #define READ_ONCE(x) \ | ||
| 258 | ({ typeof(x) __val; __read_once_size(&x, &__val, sizeof(__val)); __val; }) | ||
| 259 | |||
| 260 | #define ASSIGN_ONCE(val, x) \ | ||
| 261 | ({ typeof(x) __val; __val = val; __assign_once_size(&x, &__val, sizeof(__val)); __val; }) | ||
| 262 | |||
| 189 | #endif /* __KERNEL__ */ | 263 | #endif /* __KERNEL__ */ |
| 190 | 264 | ||
| 191 | #endif /* __ASSEMBLY__ */ | 265 | #endif /* __ASSEMBLY__ */ |
