132 lines · 3.5 KB · Rust
RawDownload
// 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/ #![expect(private_bounds, reason = "sealed implementation")] /// Memory barrier orderings.////// The semantics of these orderings follows the [`LKMM`] definitions and rules.////// - [`Read`] provides ordering between preceding load operations and succeeding load operations./// - [`Write`] provides ordering between preceding store operations and succeeding store///   operations./// - [`Full`] provides ordering between all the preceding memory accesses and succeeding memory///   accesses.////// [`LKMM`]: srctree/tools/memory-model/pub mod ordering {    pub use crate::sync::atomic::ordering::Full;     /// The annotation type for read-read barrier ordering.    pub struct Read;     /// The annotation type for write-write barrier ordering.    pub struct Write;} pub use ordering::{    Full,    Read,    Write, //}; struct Smp;struct Dma; /// 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!("") };} trait MemoryBarrier<Flavour = ()> {    fn run();} macro_rules! define_barrier {    ($([$flavour:ident])? $ordering:ident, $binding:ident) => {        impl MemoryBarrier$(<$flavour>)? for $ordering {            #[inline]            fn run() {                // SAFETY: barrier methods are safe to call.                unsafe { bindings::$binding() };            }        }    };} define_barrier!(Full, mb);define_barrier!(Read, rmb);define_barrier!(Write, wmb);define_barrier!([Dma] Full, dma_mb);define_barrier!([Dma] Read, dma_rmb);define_barrier!([Dma] Write, dma_wmb);define_barrier!([Smp] Full, smp_mb);define_barrier!([Smp] Read, smp_rmb);define_barrier!([Smp] Write, smp_wmb); /// Memory barrier.////// A barrier that prevents compiler and CPU from reordering memory accesses across the barrier.////// The specific forms of reordering can be specified using the parameter./// - `mb(Read)` provides a read-read barrier./// - `mb(Write)` provides a write-write barrier./// - `mb(Full)` provides a full barrier.////// # Examples////// ```/// # use kernel::sync::barrier::*;/// mb(Read);/// mb(Write);/// mb(Full);/// ```#[inline]#[doc(alias = "rmb")]#[doc(alias = "wmb")]pub fn mb<T: MemoryBarrier>(_: T) {    T::run()} /// Memory barrier between CPUs.////// A barrier that prevents compiler and CPU from reordering memory accesses across the barrier./// Does not prevent re-ordering with respect to other bus-mastering devices.////// See [`mb`] for usage.#[inline]#[doc(alias = "smp_rmb")]#[doc(alias = "smp_wmb")]pub fn smp_mb<T: MemoryBarrier<Smp>>(_: T) {    if cfg!(CONFIG_SMP) {        T::run()    } else {        barrier()    }} /// Memory barrier between local CPU and bus-mastering devices.////// A barrier that prevents compiler and CPU from reordering memory accesses across the barrier./// Does not prevent re-ordering with respect to other CPUs.////// See [`mb`] for usage.#[inline]#[doc(alias = "dma_rmb")]#[doc(alias = "dma_wmb")]pub fn dma_mb<T: MemoryBarrier<Dma>>(_: T) {    T::run()}