public inbox for rust-for-linux@vger.kernel.org
 help / color / mirror / Atom feed
From: "Onur Özkan" <work@onurozkan.dev>
To: Deborah Brouwer <deborah.brouwer@collabora.com>
Cc: "Daniel Almeida" <daniel.almeida@collabora.com>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Benno Lossin" <lossin@kernel.org>, "Gary Guo" <gary@garyguo.net>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Boqun Feng" <boqun@kernel.org>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Trevor Gross" <tmgross@umich.edu>,
	"FUJITA Tomonori" <fujita.tomonori@gmail.com>,
	"Frederic Weisbecker" <frederic@kernel.org>,
	"Thomas Gleixner" <tglx@kernel.org>,
	"Anna-Maria Behnsen" <anna-maria@linutronix.de>,
	"John Stultz" <jstultz@google.com>,
	"Stephen Boyd" <sboyd@kernel.org>,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	rust-for-linux@vger.kernel.org, boris.brezillon@collabora.com,
	beata.michalska@arm.com, lyude@redhat.com, acourbot@nvidia.com,
	alvin.sun@linux.dev
Subject: Re: [PATCH v4 18/20] drm/tyr: add CSF firmware interface support
Date: Mon, 27 Apr 2026 12:08:16 +0300	[thread overview]
Message-ID: <20260427090818.112428-1-work@onurozkan.dev> (raw)
In-Reply-To: <20260424-b4-fw-boot-v4-v4-18-a5d91050789d@collabora.com>

On Fri, 24 Apr 2026 16:39:12 -0700
Deborah Brouwer <deborah.brouwer@collabora.com> wrote:

> Add initial support for the Command Stream Frontend (CSF) firmware
> interfaces, enabling communication between the driver and the MCU through
> shared memory.
> 
> Implement the global (GLB), command stream group (CSG), and command stream
> (CS) interfaces. These provide access to the firmware control, input, and
> output blocks and allow discovery of the available CSGs and CSs at
> runtime.
> 
> Store the global interface in the firmware state and initialize it after
> firmware boot during probe.
> 
> Co-developed-by: Daniel Almeida <daniel.almeida@collabora.com>
> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
> Co-developed-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Deborah Brouwer <deborah.brouwer@collabora.com>
> ---
>  drivers/gpu/drm/tyr/driver.rs        |    2 +-
>  drivers/gpu/drm/tyr/fw.rs            |   62 +-
>  drivers/gpu/drm/tyr/fw/interfaces.rs | 2005 ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/tyr/gem.rs           |    5 +
>  4 files changed, 2061 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
> index 3225385cd511..20ae114a4180 100644
> --- a/drivers/gpu/drm/tyr/driver.rs
> +++ b/drivers/gpu/drm/tyr/driver.rs
> @@ -189,10 +189,10 @@ fn probe(
>          devres::register(pdev.as_ref(), job_irq, GFP_KERNEL)?;
>  
>          firmware.boot()?;
> -
>          firmware
>              .wait_ready(1000)
>              .inspect_err(|_| pr_err!("Timed out waiting for firmware to be ready.\n"))?;
> +        firmware.enable_global_interface()?;
>  
>          let data = try_pin_init!(TyrDrmDeviceData {
>                  pdev: platform.clone(),
> diff --git a/drivers/gpu/drm/tyr/fw.rs b/drivers/gpu/drm/tyr/fw.rs
> index 14815cdafac8..598e399a58ae 100644
> --- a/drivers/gpu/drm/tyr/fw.rs
> +++ b/drivers/gpu/drm/tyr/fw.rs
> @@ -36,7 +36,8 @@
>      str::CString,
>      sync::{
>          Arc,
> -        ArcBorrow, //
> +        ArcBorrow,
> +        Mutex, //
>      },
>      time,
>      types::ARef, //
> @@ -47,9 +48,12 @@
>          IoMem,
>          TyrDrmDevice, //
>      },
> -    fw::parser::{
> -        FwParser,
> -        ParsedSection, //
> +    fw::{
> +        interfaces::GlobalInterface,
> +        parser::{
> +            FwParser,
> +            ParsedSection, //
> +        },
>      },
>      gem,
>      gem::{
> @@ -73,12 +77,16 @@
>      }, //
>  };
>  
> +mod interfaces;
>  pub(crate) mod irq;
>  mod parser;
>  
>  /// Maximum number of CSG interfaces supported by hardware.
>  const MAX_CSG: usize = 16;
>  
> +/// Maximum number of CS interfaces supported by hardware.
> +const MAX_CS: usize = 16;
> +
>  impl_flags!(
>      #[derive(Debug, Clone, Default, Copy, PartialEq, Eq)]
>      pub(super) struct SectionFlags(u32);
> @@ -100,6 +108,11 @@ pub(super) enum SectionFlag {
>  
>  pub(super) const CACHE_MODE_MASK: SectionFlags = SectionFlags(genmask_u32(3..=4));
>  
> +/// MCU virtual address where the CSF shared memory region starts.
> +///
> +/// This region contains the firmware interface structures for communication between
> +/// the CPU driver and MCU firmware, including the GLB_CONTROL_BLOCK at this base address.
> +/// The firmware binary contains a section marked to be loaded at this address.
>  pub(super) const CSF_MCU_SHARED_REGION_START: u32 = 0x04000000;
>  
>  impl SectionFlags {
> @@ -129,18 +142,18 @@ fn try_from(value: u32) -> Result<Self, Self::Error> {
>  }
>  
>  /// A parsed section of the firmware binary.
> -struct Section {
> +pub(crate) struct Section {
>      // Raw firmware section data for reset purposes
>      #[expect(dead_code)]
>      data: KVec<u8>,
>  
>      // Keep the BO backing this firmware section so that both the
>      // GPU mapping and CPU mapping remain valid until the Section is dropped.
> -    #[expect(dead_code)]
>      mem: gem::KernelBo,
>  }
>  
>  /// Loaded firmware with sections mapped into MCU VM.
> +#[pin_data(PinnedDrop)]
>  pub(crate) struct Firmware {
>      /// Platform device reference (needed to access the MCU JOB_IRQ registers).
>      pdev: ARef<platform::Device>,
> @@ -152,7 +165,6 @@ pub(crate) struct Firmware {
>      vm: Arc<Vm>,
>  
>      /// List of firmware sections.
> -    #[expect(dead_code)]
>      sections: KVec<Section>,
>  
>      /// A condvar representing a wait on a firmware event.
> @@ -160,10 +172,15 @@ pub(crate) struct Firmware {
>  
>      /// Latched to `true` by the IRQ handler when the firmware signals readiness via the GLB bit.
>      pub(crate) fw_ready: Arc<AtomicBool>,
> +
> +    /// The global FW interface.
> +    #[pin]
> +    global_iface: Mutex<GlobalInterface>,
>  }
>  
> -impl Drop for Firmware {
> -    fn drop(&mut self) {
> +#[pinned_drop]
> +impl PinnedDrop for Firmware {
> +    fn drop(self: Pin<&mut Self>) {
>          // AS slots retain a VM ref, we need to kill the circular ref manually.
>          self.vm.kill();
>      }
> @@ -258,21 +275,36 @@ pub(crate) fn new(
>              sections.push(Section { data, mem }, GFP_KERNEL)?;
>          }
>  
> -        let firmware = Arc::new(
> -            Firmware {
> +        let firmware = Arc::pin_init(
> +            try_pin_init!(Firmware {
>                  pdev: pdev.into(),
>                  iomem,
>                  vm,
>                  sections,
>                  ready_wait: new_wait!()?,
>                  fw_ready: Arc::new(AtomicBool::new(false), GFP_KERNEL)?,
> -            },
> +                global_iface <- new_mutex!(GlobalInterface::new()?),
> +            }),
>              GFP_KERNEL,
>          )?;
>  
>          Ok(firmware)
>      }
>  
> +    /// Get the shared memory section containing firmware interface structures.
> +    pub(crate) fn shared_section(&self) -> Result<&Section> {
> +        self.sections
> +            .iter()
> +            .find(|section| section.mem.va_range().start == u64::from(CSF_MCU_SHARED_REGION_START))
> +            .ok_or_else(|| {
> +                pr_err!(
> +                    "CSF shared section not found at 0x{:08x}\n",
> +                    CSF_MCU_SHARED_REGION_START
> +                );
> +                EINVAL
> +            })
> +    }
> +
>      pub(crate) fn boot(&self) -> Result {
>          // SAFETY: Boot is currently only called in the probe path, so we're sure we have a bound
>          // device.
> @@ -303,4 +335,10 @@ pub(crate) fn wait_ready(&self, timeout_ms: u32) -> Result {
>              }
>          })
>      }
> +
> +    /// Enable the global interface.
> +    pub(crate) fn enable_global_interface(&self) -> Result {
> +        let shared_section = self.shared_section()?;
> +        self.global_iface.lock().enable(shared_section)
> +    }
>  }
> diff --git a/drivers/gpu/drm/tyr/fw/interfaces.rs b/drivers/gpu/drm/tyr/fw/interfaces.rs
> new file mode 100644
> index 000000000000..07cdb1c76a3f
> --- /dev/null
> +++ b/drivers/gpu/drm/tyr/fw/interfaces.rs
> @@ -0,0 +1,2005 @@
> +// SPDX-License-Identifier: GPL-2.0 or MIT
> +
> +//! Code to control the global interface of the CSF firmware.
> +//!
> +//! For abbreviation definitions (CEU, CS, CSF, CSG, CSHW, GLB, JASID, MCU, MMU), see the top-level
> +//! module documentation in [`crate::regs`].
> +//!
> +//! # Interface Overview
> +//!
> +//! Tyr interacts with the CSF firmware running on the MCU through shared memory
> +//! interfaces. The CSF manages job submission via a hierarchy of:
> +//! - **GLB**: Global interface - controls operations common to all CSs
> +//! - **CSG**: Command Stream Groups - groups of related command streams
> +//! - **CS**: Command Streams - individual sequences of GPU commands
> +//!
> +//! ```
> +//! ┌──────────────────────────────────────────┐
> +//! │ GPU                                      │
> +//! │ ┌─────┐ ┌──────────────────────────────┐ │
> +//! │ │ MMU │ │  CSF                         │ │
> +//! │ └─────┘ │ ┌────────────┐ ┌─────┐       │ │
> +//! │         │ │ CSHW (CEU) │ │ MCU │       │ │
> +//! │         │ └────────────┘ └─────┘       │ │
> +//! └─────────┼──────────────────────────────┼─┘
> +//!           │ ┌──────────────────────────┐ │
> +//!           │ │ Shared Memory            │ │
> +//!           │ │ ┌────────┐ ┌────┐ ┌────┐ │ │
> +//!           │ │ │  CSG0  │ │GLB │ │ FW │ │ │
> +//!           │ │ │ ┌────┐ │ └────┘ └────┘ │ │
> +//!           │ │ │ │CS0 │ │               │ │
> +//!           │ │ │ └────┘ │               │ │
> +//!           │ │ └────────┘               │ │
> +//!           │ └──────────────────────────┘ │
> +//!           └──────────────┬───────────────┘
> +//!                          │
> +//!                      ┌───┴───┐
> +//!                      │  Tyr  │
> +//!                      └───────┘
> +//! ```
> +//!
> +
> +use crate::fw::Section;
> +use iface::FwInterface;
> +use kernel::{
> +    io::Io,
> +    prelude::*, //
> +};
> +
> +            }

[...]

> +        }
> +    }
> +}
> +
> +use cs::*;
> +use csg::*;
> +use glb::{
> +    control::*,
> +    *, //
> +};

Any reason having these imports at middle of the module?

> +
> +/// State of the global interface.
> +enum GlobalInterfaceState {
> +    /// Interface is not yet initialized.
> +    Disabled,
> +    /// Interface is initialized and operational.
> +    Enabled(EnabledGlobalInterface),
> +}
> +
> +/// When enabled, the Global Interface has control,
> +/// input, and output system memory interfaces, as well as
> +/// the discovered CSG interfaces.
> +#[expect(dead_code)]
> +struct EnabledGlobalInterface {
> +    /// Control block interface - provides version, features, and CSG discovery.
> +    glb_control: FwInterface<GLB_CONTROL_BLOCK_SIZE>,
> +    /// Input block interface - driver writes requests here.
> +    glb_input: FwInterface<GLB_INPUT_BLOCK_SIZE>,
> +    /// Output block interface - firmware writes acknowledgements here.
> +    glb_output: FwInterface<GLB_OUTPUT_BLOCK_SIZE>,
> +    /// Runtime stride between CSG control blocks (read from GLB_GROUP_STRIDE).
> +    csg_stride: usize,
> +    /// Number of CSG interfaces reported by hardware.
> +    csg_num: usize,
> +    /// Discovered CSG interfaces.
> +    csg: KVec<CsgInterface>,
> +}
> +
> +/// Global CSF Interface
> +///
> +/// The CSF controls operations that are common to all CSs.
> +pub(super) struct GlobalInterface {
> +    /// Current interface state (Disabled or Enabled).
> +    state: GlobalInterfaceState,
> +}
> +
> +impl GlobalInterface {
> +    /// Creates a new CSF global interface, initially disabled.
> +    pub(super) fn new() -> Result<Self> {
> +        Ok(Self {
> +            state: GlobalInterfaceState::Disabled,
> +        })
> +    }
> +
> +    /// Enables the global interface and discovers the CSG interfaces.
> +    ///
> +    /// This reads the firmware's control block to set up the global input/output
> +    /// interfaces; it configures timers and shader core allocation; and it discovers
> +    /// available CSG interfaces.
> +    pub(crate) fn enable(&mut self, shared_section: &Section) -> Result {
> +        let vmap = shared_section.mem.bo.owned_vmap::<0>()?;
> +        let va_range = shared_section.mem.va_range();
> +
> +        let glb_control =
> +            FwInterface::<GLB_CONTROL_BLOCK_SIZE>::new(&vmap, &va_range, va_range.start)?;
> +
> +        let version = glb_control.read(GLB_VERSION);
> +        if version.major().get() == 0 {
> +            pr_err!("CSF interface version is 0. Firmware may have failed to boot.\n");
> +            return Err(EINVAL);
> +        }
> +        pr_info!(
> +            "CSF interface version: {}.{}.{}\n",
> +            version.major().get(),
> +            version.minor().get(),
> +            version.patch().get()
> +        );
> +
> +        let input_va = glb_control.read(GLB_INPUT_VA);
> +        let glb_input = FwInterface::<GLB_INPUT_BLOCK_SIZE>::new(
> +            &vmap,
> +            &va_range,
> +            input_va.value().get().into(),
> +        )?;
> +
> +        let output_va = glb_control.read(GLB_OUTPUT_VA);
> +        let glb_output = FwInterface::<GLB_OUTPUT_BLOCK_SIZE>::new(
> +            &vmap,
> +            &va_range,
> +            output_va.value().get().into(),
> +        )?;
> +
> +        // Read how many CSG interfaces exist.
> +        let csg_num = glb_control.read(GLB_GROUP_NUM).value().get();
> +
> +        // Read the stride between CSG control blocks.
> +        let csg_stride = glb_control.read(GLB_GROUP_STRIDE).value().get() as usize;
> +
> +        if csg_stride < CSG_CONTROL_BLOCK_SIZE {
> +            pr_err!(
> +                "CSG stride {} is smaller than control block size {}\n",
> +                csg_stride,
> +                CSG_CONTROL_BLOCK_SIZE
> +            );
> +            return Err(EINVAL);
> +        }
> +
> +        // Validate the CSG number reported.
> +        if csg_num as usize > super::MAX_CSG {
> +            pr_err!(
> +                "Too many CSGs: hardware reports {}, max supported {}\n",
> +                csg_num,
> +                super::MAX_CSG
> +            );
> +            return Err(EINVAL);
> +        }
> +
> +        let enabled = EnabledGlobalInterface {
> +            glb_control,
> +            glb_input,
> +            glb_output,
> +            csg_stride,
> +            csg_num: csg_num as usize,
> +            csg: KVec::with_capacity(csg_num as usize, GFP_KERNEL)?,
> +        };
> +
> +        self.state = GlobalInterfaceState::Enabled(enabled);
> +        self.init_csg(shared_section)?;
> +        Ok(())
> +    }
> +
> +    /// Initialize CSG interfaces.
> +    ///
> +    /// This uses the previously read CSG count to create and enable each CSG interface.
> +    fn init_csg(&mut self, shared_section: &Section) -> Result {
> +        let enabled = match &mut self.state {
> +            GlobalInterfaceState::Enabled(e) => e,
> +            GlobalInterfaceState::Disabled => return Err(EINVAL),
> +        };
> +
> +        for csg_idx in 0..enabled.csg_num {
> +            // Create and enable the CSG interface.
> +            let mut csg = CsgInterface::new(csg_idx)?;
> +            csg.enable(shared_section, csg_idx, enabled.csg_stride)?;
> +
> +            enabled.csg.push(csg, GFP_KERNEL)?;
> +        }
> +
> +        Ok(())
> +    }
> +}
> +
> +/// State of a CSG interface.
> +enum CsgInterfaceState {
> +    /// Interface is not yet initialized.
> +    Disabled,
> +    /// Interface is initialized and operational.
> +    Enabled(EnabledCsgInterface),
> +}
> +
> +/// When enabled, a CSG Interface has control, input, and output system memory interfaces.
> +struct EnabledCsgInterface {
> +    /// Control block interface - provides CSG capabilities and configuration.
> +    #[expect(dead_code)]
> +    csg_control: FwInterface<CSG_CONTROL_BLOCK_SIZE>,
> +    /// Input block interface - driver writes CSG requests here.
> +    #[expect(dead_code)]
> +    csg_input: FwInterface<CSG_INPUT_BLOCK_SIZE>,
> +    /// Output block interface - firmware writes CSG acknowledgements here.
> +    #[expect(dead_code)]
> +    csg_output: FwInterface<CSG_OUTPUT_BLOCK_SIZE>,
> +    /// Runtime stride between CS control blocks (read from GROUP_STREAM_STRIDE).
> +    cs_stride: usize,
> +    /// Number of CS interfaces reported by hardware for this CSG.
> +    cs_num: usize,
> +    /// Discovered CS interfaces.
> +    cs: KVec<CsInterface>,
> +}
> +
> +/// Command Stream Group Interface
> +///
> +/// The CSG interface controls operations for a specific CSG.
> +pub(crate) struct CsgInterface {
> +    /// Current interface state (Disabled or Enabled).
> +    state: CsgInterfaceState,
> +    /// CSG identifier/index number.
> +    #[expect(dead_code)]
> +    csg_idx: usize,
> +}
> +
> +impl CsgInterface {
> +    /// Creates a new disabled CSG interface.
> +    pub(super) fn new(csg_idx: usize) -> Result<Self> {
> +        Ok(Self {
> +            state: CsgInterfaceState::Disabled,
> +            csg_idx,
> +        })
> +    }
> +
> +    /// Enables the CSG interface.
> +    ///
> +    /// This calculates the runtime offset of this CSG's control block and creates
> +    /// a bounded interface to access it. It then reads the input/output interface
> +    /// addresses from the CSG control block.
> +    fn enable(&mut self, shared_section: &Section, csg_idx: usize, csg_stride: usize) -> Result {
> +        use csg::control::{
> +            GROUP_INPUT_VA,
> +            GROUP_OUTPUT_VA,
> +            GROUP_STREAM_NUM,
> +            GROUP_STREAM_STRIDE, //
> +        };
> +        use kernel::io::Io;

Why are these imported inside the function? This is usually done when the
function is gated behind a feature flag to avoid clippy warnings when features
are disabled, but that doesn't seem to be the case here.

> +
> +        let vmap = shared_section.mem.bo.owned_vmap::<0>()?;
> +        let va_range = shared_section.mem.va_range();
> +
> +        // Calculate the runtime offset for this CSG's control block.
> +        // The CSG control blocks start at CSG_GROUP_CONTROL_OFFSET from the GLB control block,
> +        // with each CSG spaced by csg_stride bytes.
> +        let csg_control_offset = CSG_GROUP_CONTROL_OFFSET + csg_idx * csg_stride;
> +
> +        // The CSG control block's MCU virtual address is relative to the shared section start.
> +        let csg_control_va = va_range.start + csg_control_offset as u64;
> +
> +        // Create a bounded interface for this CSG's control block at the calculated address.
> +        let csg_control =
> +            FwInterface::<CSG_CONTROL_BLOCK_SIZE>::new(&vmap, &va_range, csg_control_va)?;
> +
> +        // Read the input and output VAs from the CSG control block.
> +        let input_va = csg_control.read(GROUP_INPUT_VA).value().get();
> +        let csg_input =
> +            FwInterface::<CSG_INPUT_BLOCK_SIZE>::new(&vmap, &va_range, input_va.into())?;
> +
> +        let output_va = csg_control.read(GROUP_OUTPUT_VA).value().get();
> +        let csg_output =
> +            FwInterface::<CSG_OUTPUT_BLOCK_SIZE>::new(&vmap, &va_range, output_va.into())?;
> +
> +        // Read the runtime stride between CS control blocks.
> +        let cs_stride = csg_control.read(GROUP_STREAM_STRIDE).value().get() as usize;
> +
> +        if cs_stride < CS_CONTROL_BLOCK_SIZE {
> +            pr_err!(
> +                "CS stride {} is smaller than control block size {}\n",
> +                cs_stride,
> +                CS_CONTROL_BLOCK_SIZE
> +            );
> +            return Err(EINVAL);
> +        }
> +
> +        // Read how many CS interfaces exist for this CSG.
> +        let cs_num = csg_control.read(GROUP_STREAM_NUM).value().get();
> +
> +        // Validate that the hardware doesn't report more CS than we support.
> +        if cs_num as usize > super::MAX_CS {
> +            pr_err!(
> +                "Too many CS: hardware reports {}, max supported {}\n",
> +                cs_num,
> +                super::MAX_CS
> +            );
> +            return Err(EINVAL);
> +        }
> +
> +        let enabled = EnabledCsgInterface {
> +            csg_control,
> +            csg_input,
> +            csg_output,
> +            cs_stride,
> +            cs_num: cs_num as usize,
> +            cs: KVec::with_capacity(cs_num as usize, GFP_KERNEL)?,
> +        };
> +
> +        self.state = CsgInterfaceState::Enabled(enabled);
> +        self.init_cs(shared_section, csg_control_offset)?;
> +        Ok(())
> +    }
> +
> +    /// Initialize and discover CS interfaces.
> +    ///
> +    /// This uses the previously read CS count to create and enable each CS interface.
> +    fn init_cs(&mut self, shared_section: &Section, csg_control_offset: usize) -> Result {
> +        let enabled = match &mut self.state {
> +            CsgInterfaceState::Enabled(e) => e,
> +            CsgInterfaceState::Disabled => return Err(EINVAL),
> +        };
> +
> +        for cs_idx in 0..enabled.cs_num {
> +            // Create and enable the CS interface.
> +            let mut cs = CsInterface::new(cs_idx)?;
> +            cs.enable(
> +                shared_section,
> +                csg_control_offset,
> +                cs_idx,
> +                enabled.cs_stride,
> +            )?;
> +
> +            enabled.cs.push(cs, GFP_KERNEL)?;
> +        }
> +
> +        Ok(())
> +    }
> +}
> +
> +/// State of a CS interface.
> +enum CsInterfaceState {
> +    /// Interface is not yet initialized.
> +    Disabled,
> +    /// Interface is initialized and operational.
> +    #[expect(dead_code)]
> +    Enabled(EnabledCsInterface),
> +}
> +
> +/// When enabled, a CS Interface has control, input, and output system memory interfaces.
> +struct EnabledCsInterface {
> +    /// Control block interface - provides CS capabilities and configuration.
> +    #[expect(dead_code)]
> +    cs_control: FwInterface<CS_CONTROL_BLOCK_SIZE>,
> +    /// Input block interface - driver writes CS requests here.
> +    #[expect(dead_code)]
> +    cs_input: FwInterface<CS_KERNEL_INPUT_BLOCK_SIZE>,
> +    /// Output block interface - firmware writes CS acknowledgements here.
> +    #[expect(dead_code)]
> +    cs_output: FwInterface<CS_KERNEL_OUTPUT_BLOCK_SIZE>,
> +}
> +
> +/// Command Stream Interface
> +///
> +/// The CS interface controls operations for a specific CS.
> +pub(crate) struct CsInterface {
> +    /// Current interface state (Disabled or Enabled).
> +    state: CsInterfaceState,
> +    /// CS identifier/index number.
> +    #[expect(dead_code)]
> +    cs_idx: usize,
> +}
> +
> +impl CsInterface {
> +    /// Creates a new disabled CS interface.
> +    pub(super) fn new(cs_idx: usize) -> Result<Self> {
> +        Ok(Self {
> +            state: CsInterfaceState::Disabled,
> +            cs_idx,
> +        })
> +    }
> +
> +    /// Enables the CS interface.
> +    ///
> +    /// This calculates the runtime offset of this CS's control block and creates
> +    /// a bounded interface to access it. It then reads the input/output interface
> +    /// addresses from the CS control block.
> +    fn enable(
> +        &mut self,
> +        shared_section: &Section,
> +        csg_control_offset: usize,
> +        cs_idx: usize,
> +        cs_stride: usize,
> +    ) -> Result {
> +        use cs::control::{
> +            STREAM_INPUT_VA,
> +            STREAM_OUTPUT_VA, //
> +        };
> +        use kernel::io::Io;
> +
> +        let vmap = shared_section.mem.bo.owned_vmap::<0>()?;
> +        let va_range = shared_section.mem.va_range();
> +
> +        // Calculate the runtime offset for this CS's control block.
> +        let cs_control_offset = CS_CONTROL_OFFSET + cs_idx * cs_stride;
> +
> +        // The CS control block's MCU virtual address is relative to the shared section start.
> +        let cs_control_va = va_range.start + csg_control_offset as u64 + cs_control_offset as u64;
> +
> +        // Create a bounded interface for this CS's control block at the calculated address.
> +        let cs_control =
> +            FwInterface::<CS_CONTROL_BLOCK_SIZE>::new(&vmap, &va_range, cs_control_va)?;
> +
> +        // Read the input and output VAs from the CS control block.
> +        let input_va = cs_control.read(STREAM_INPUT_VA).value().get();
> +        let cs_input =
> +            FwInterface::<CS_KERNEL_INPUT_BLOCK_SIZE>::new(&vmap, &va_range, input_va.into())?;
> +
> +        let output_va = cs_control.read(STREAM_OUTPUT_VA).value().get();
> +        let cs_output =
> +            FwInterface::<CS_KERNEL_OUTPUT_BLOCK_SIZE>::new(&vmap, &va_range, output_va.into())?;
> +
> +        let enabled = EnabledCsInterface {
> +            cs_control,
> +            cs_input,
> +            cs_output,
> +        };
> +
> +        self.state = CsInterfaceState::Enabled(enabled);
> +
> +        Ok(())
> +    }
> +}
> diff --git a/drivers/gpu/drm/tyr/gem.rs b/drivers/gpu/drm/tyr/gem.rs
> index 4ec373e0bcfa..606d446aafd9 100644
> --- a/drivers/gpu/drm/tyr/gem.rs
> +++ b/drivers/gpu/drm/tyr/gem.rs
> @@ -151,6 +151,11 @@ pub(crate) fn new<Ctx: DeviceContext>(
>              va_range: va..(va + size),
>          })
>      }
> +
> +    /// Returns the GPU virtual address range occupied by this buffer.
> +    pub(crate) fn va_range(&self) -> Range<u64> {
> +        self.va_range.clone()
> +    }
>  }
>  
>  impl Drop for KernelBo {
> 
> -- 
> 2.53.0
> 

  reply	other threads:[~2026-04-27  9:08 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-24 23:38 [PATCH v4 00/20] drm/tyr: firmware loading and MCU boot support Deborah Brouwer
2026-04-24 23:38 ` [PATCH v4 01/20] drm/tyr: remove unused device from platform data Deborah Brouwer
2026-04-24 23:38 ` [PATCH v4 02/20] drm/tyr: select required dependencies in Kconfig Deborah Brouwer
2026-04-27  7:23   ` Boris Brezillon
2026-04-24 23:38 ` [PATCH v4 03/20] drm/tyr: move clock cleanup into Clocks Drop impl Deborah Brouwer
2026-04-24 23:38 ` [PATCH v4 04/20] drm/tyr: rename TyrObject to BoData Deborah Brouwer
2026-04-24 23:38 ` [PATCH v4 05/20] drm/tyr: use shmem GEM object type in TyrDrmDriver Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 06/20] drm/tyr: set DMA mask using GPU physical address Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 07/20] drm/tyr: add shmem backing for GEM objects Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 08/20] drm/tyr: Add generic slot manager Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 09/20] drm/tyr: add MMU module Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 10/20] drm/tyr: add GPU virtual memory module Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 11/20] drm/tyr: add a kernel buffer object Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 12/20] drm/tyr: add parser for firmware binary Deborah Brouwer
2026-04-27  8:09   ` Onur Özkan
2026-04-27  8:20     ` Boris Brezillon
2026-04-24 23:39 ` [PATCH v4 13/20] drm/tyr: add firmware loading and MCU boot support Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 14/20] drm/tyr: add Wait type for GPU events Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 15/20] drm/tyr: add Job IRQ handling Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 16/20] drm/tyr: wait for global interface readiness Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 17/20] drm/tyr: validate presence of CSF shared section Deborah Brouwer
2026-04-24 23:39 ` [PATCH v4 18/20] drm/tyr: add CSF firmware interface support Deborah Brouwer
2026-04-27  9:08   ` Onur Özkan [this message]
2026-04-24 23:39 ` [PATCH v4 19/20] rust: time: add arch_timer_get_rate wrapper Deborah Brouwer
2026-04-27  7:42   ` Andreas Hindborg
2026-04-27  7:53   ` Alice Ryhl
2026-04-27  8:59   ` Onur Özkan
2026-04-24 23:39 ` [PATCH v4 20/20] drm/tyr: program CSF global interface Deborah Brouwer
2026-04-27  8:07 ` [PATCH v4 00/20] drm/tyr: firmware loading and MCU boot support Boris Brezillon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260427090818.112428-1-work@onurozkan.dev \
    --to=work@onurozkan.dev \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=alvin.sun@linux.dev \
    --cc=anna-maria@linutronix.de \
    --cc=beata.michalska@arm.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=boris.brezillon@collabora.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=deborah.brouwer@collabora.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=frederic@kernel.org \
    --cc=fujita.tomonori@gmail.com \
    --cc=gary@garyguo.net \
    --cc=jstultz@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=lyude@redhat.com \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=sboyd@kernel.org \
    --cc=simona@ffwll.ch \
    --cc=tglx@kernel.org \
    --cc=tmgross@umich.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox