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
>
next prev parent 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