All of lore.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: 37+ 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-27 23:36     ` Deborah Brouwer
2026-04-28  7:13       ` 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 23:34     ` Deborah Brouwer
2026-04-27  7:53   ` Alice Ryhl
2026-04-27 23:34     ` Deborah Brouwer
2026-04-27  8:59   ` Onur Özkan
2026-04-27 23:35     ` Deborah Brouwer
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
2026-04-28 10:56   ` Alice Ryhl
2026-04-28 16:41     ` Deborah Brouwer
2026-04-28 17:02       ` Alice Ryhl

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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.