1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef __ASM_GENERIC_MMIOWB_H 3 #define __ASM_GENERIC_MMIOWB_H 4 5 /* 6 * Generic implementation of mmiowb() tracking for spinlocks. 7 * 8 * If your architecture doesn't ensure that writes to an I/O peripheral 9 * within two spinlocked sections on two different CPUs are seen by the 10 * peripheral in the order corresponding to the lock handover, then you 11 * need to follow these FIVE easy steps: 12 * 13 * 1. Implement mmiowb() (and arch_mmiowb_state() if you're fancy) 14 * in asm/mmiowb.h, then #include this file 15 * 2. Ensure your I/O write accessors call mmiowb_set_pending() 16 * 3. Select ARCH_HAS_MMIOWB 17 * 4. Untangle the resulting mess of header files 18 * 5. Complain to your architects 19 */ 20 #ifdef CONFIG_MMIOWB 21 22 #include <linux/compiler.h> 23 #include <asm-generic/mmiowb_types.h> 24 25 #ifndef arch_mmiowb_state 26 #include <asm/percpu.h> 27 #include <asm/smp.h> 28 29 DECLARE_PER_CPU(struct mmiowb_state, __mmiowb_state); 30 #define __mmiowb_state() this_cpu_ptr(&__mmiowb_state) 31 #else 32 #define __mmiowb_state() arch_mmiowb_state() 33 #endif /* arch_mmiowb_state */ 34 35 static inline void mmiowb_set_pending(void) 36 { 37 struct mmiowb_state *ms = __mmiowb_state(); 38 ms->mmiowb_pending = ms->nesting_count; 39 } 40 41 static inline void mmiowb_spin_lock(void) 42 { 43 struct mmiowb_state *ms = __mmiowb_state(); 44 ms->nesting_count++; 45 } 46 47 static inline void mmiowb_spin_unlock(void) 48 { 49 struct mmiowb_state *ms = __mmiowb_state(); 50 51 if (unlikely(ms->mmiowb_pending)) { 52 ms->mmiowb_pending = 0; 53 mmiowb(); 54 } 55 56 ms->nesting_count--; 57 } 58 #else 59 #define mmiowb_set_pending() do { } while (0) 60 #define mmiowb_spin_lock() do { } while (0) 61 #define mmiowb_spin_unlock() do { } while (0) 62 #endif /* CONFIG_MMIOWB */ 63 #endif /* __ASM_GENERIC_MMIOWB_H */ 64