| // SPDX-License-Identifier: GPL-2.0 |
| |
| //! Memory barriers. |
| //! |
| //! These primitives have the same semantics as their C counterparts: and the precise definitions |
| //! of semantics can be found at [`LKMM`]. |
| //! |
| //! [`LKMM`]: srctree/tools/memory-model/ |
| |
| /// A compiler barrier. |
| /// |
| /// A barrier that prevents compiler from reordering memory accesses across the barrier. |
| #[inline(always)] |
| pub(crate) fn barrier() { |
| // By default, Rust inline asms are treated as being able to access any memory or flags, hence |
| // it suffices as a compiler barrier. |
| // |
| // SAFETY: An empty asm block. |
| unsafe { core::arch::asm!("") }; |
| } |
| |
| /// A full memory barrier. |
| /// |
| /// A barrier that prevents compiler and CPU from reordering memory accesses across the barrier. |
| #[inline(always)] |
| pub fn smp_mb() { |
| if cfg!(CONFIG_SMP) { |
| // SAFETY: `smp_mb()` is safe to call. |
| unsafe { bindings::smp_mb() }; |
| } else { |
| barrier(); |
| } |
| } |
| |
| /// A write-write memory barrier. |
| /// |
| /// A barrier that prevents compiler and CPU from reordering memory write accesses across the |
| /// barrier. |
| #[inline(always)] |
| pub fn smp_wmb() { |
| if cfg!(CONFIG_SMP) { |
| // SAFETY: `smp_wmb()` is safe to call. |
| unsafe { bindings::smp_wmb() }; |
| } else { |
| barrier(); |
| } |
| } |
| |
| /// A read-read memory barrier. |
| /// |
| /// A barrier that prevents compiler and CPU from reordering memory read accesses across the |
| /// barrier. |
| #[inline(always)] |
| pub fn smp_rmb() { |
| if cfg!(CONFIG_SMP) { |
| // SAFETY: `smp_rmb()` is safe to call. |
| unsafe { bindings::smp_rmb() }; |
| } else { |
| barrier(); |
| } |
| } |