xref: /linux/rust/kernel/sync/barrier.rs (revision 88b489385bfe3713497a63c0dcf4dd7852cf4568)
1*d9ea5a41SBoqun Feng // SPDX-License-Identifier: GPL-2.0
2*d9ea5a41SBoqun Feng 
3*d9ea5a41SBoqun Feng //! Memory barriers.
4*d9ea5a41SBoqun Feng //!
5*d9ea5a41SBoqun Feng //! These primitives have the same semantics as their C counterparts: and the precise definitions
6*d9ea5a41SBoqun Feng //! of semantics can be found at [`LKMM`].
7*d9ea5a41SBoqun Feng //!
8*d9ea5a41SBoqun Feng //! [`LKMM`]: srctree/tools/memory-model/
9*d9ea5a41SBoqun Feng 
10*d9ea5a41SBoqun Feng /// A compiler barrier.
11*d9ea5a41SBoqun Feng ///
12*d9ea5a41SBoqun Feng /// A barrier that prevents compiler from reordering memory accesses across the barrier.
13*d9ea5a41SBoqun Feng #[inline(always)]
barrier()14*d9ea5a41SBoqun Feng pub(crate) fn barrier() {
15*d9ea5a41SBoqun Feng     // By default, Rust inline asms are treated as being able to access any memory or flags, hence
16*d9ea5a41SBoqun Feng     // it suffices as a compiler barrier.
17*d9ea5a41SBoqun Feng     //
18*d9ea5a41SBoqun Feng     // SAFETY: An empty asm block.
19*d9ea5a41SBoqun Feng     unsafe { core::arch::asm!("") };
20*d9ea5a41SBoqun Feng }
21*d9ea5a41SBoqun Feng 
22*d9ea5a41SBoqun Feng /// A full memory barrier.
23*d9ea5a41SBoqun Feng ///
24*d9ea5a41SBoqun Feng /// A barrier that prevents compiler and CPU from reordering memory accesses across the barrier.
25*d9ea5a41SBoqun Feng #[inline(always)]
smp_mb()26*d9ea5a41SBoqun Feng pub fn smp_mb() {
27*d9ea5a41SBoqun Feng     if cfg!(CONFIG_SMP) {
28*d9ea5a41SBoqun Feng         // SAFETY: `smp_mb()` is safe to call.
29*d9ea5a41SBoqun Feng         unsafe { bindings::smp_mb() };
30*d9ea5a41SBoqun Feng     } else {
31*d9ea5a41SBoqun Feng         barrier();
32*d9ea5a41SBoqun Feng     }
33*d9ea5a41SBoqun Feng }
34*d9ea5a41SBoqun Feng 
35*d9ea5a41SBoqun Feng /// A write-write memory barrier.
36*d9ea5a41SBoqun Feng ///
37*d9ea5a41SBoqun Feng /// A barrier that prevents compiler and CPU from reordering memory write accesses across the
38*d9ea5a41SBoqun Feng /// barrier.
39*d9ea5a41SBoqun Feng #[inline(always)]
smp_wmb()40*d9ea5a41SBoqun Feng pub fn smp_wmb() {
41*d9ea5a41SBoqun Feng     if cfg!(CONFIG_SMP) {
42*d9ea5a41SBoqun Feng         // SAFETY: `smp_wmb()` is safe to call.
43*d9ea5a41SBoqun Feng         unsafe { bindings::smp_wmb() };
44*d9ea5a41SBoqun Feng     } else {
45*d9ea5a41SBoqun Feng         barrier();
46*d9ea5a41SBoqun Feng     }
47*d9ea5a41SBoqun Feng }
48*d9ea5a41SBoqun Feng 
49*d9ea5a41SBoqun Feng /// A read-read memory barrier.
50*d9ea5a41SBoqun Feng ///
51*d9ea5a41SBoqun Feng /// A barrier that prevents compiler and CPU from reordering memory read accesses across the
52*d9ea5a41SBoqun Feng /// barrier.
53*d9ea5a41SBoqun Feng #[inline(always)]
smp_rmb()54*d9ea5a41SBoqun Feng pub fn smp_rmb() {
55*d9ea5a41SBoqun Feng     if cfg!(CONFIG_SMP) {
56*d9ea5a41SBoqun Feng         // SAFETY: `smp_rmb()` is safe to call.
57*d9ea5a41SBoqun Feng         unsafe { bindings::smp_rmb() };
58*d9ea5a41SBoqun Feng     } else {
59*d9ea5a41SBoqun Feng         barrier();
60*d9ea5a41SBoqun Feng     }
61*d9ea5a41SBoqun Feng }
62