On Tue, Oct 27, 2026 at 12:41:03AM +0800, Ke Sun wrote:
> From: Sami Tolvanen <[email protected]>
>
> Tyr maps shmem-backed buffers write-combine, but the shmem layer
> zero-inits new pages through a cached mapping. On a non-coherent device
> those stale cache lines can land over later uncached writes, so the GPU
> or userspace reads a freshly written value back as zero.
>
> Read the device's coherence once at probe and map buffers write-back
> when it's coherent, write-combine otherwise. BO_CREATE fetches the
> sgtable at creation time so dma_map_sgtable() flushes the zeroed pages
> before anyone accesses them uncached.
>
> Signed-off-by: Sami Tolvanen <[email protected]>
> [ Drop the map_wc-conditional sg_table call, now fetched
> unconditionally in BO_CREATE. - Alvin ]
> Co-developed-by: Alvin Sun <[email protected]>
> Signed-off-by: Alvin Sun <[email protected]>
> ---
This patch no longer does what its subject and commit message says
it does. Since you are basically just threading coherent
through to all the places where a shmem::ObjectConfig::map_wc needs
to be set, reword this patch or consider if it should be part
of the bo ioctls patch.
Also, don't split up the tests inside should_map_wc() helper
over different patches. Just introduce the full helper in
a one place testing for both coherent and the DRM_PANTHOR_BO_WB_MMAP
flag.
> drivers/gpu/drm/tyr/driver.rs | 10 ++++++++++
> drivers/gpu/drm/tyr/file.rs | 5 +++--
> drivers/gpu/drm/tyr/fw.rs | 4 +++-
> drivers/gpu/drm/tyr/gem.rs | 34 +++++++++++++++++++++++++---------
> drivers/gpu/drm/tyr/vm.rs | 9 ++++++---
> 5 files changed, 47 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
> index f4f31b24180b4..633d1cab3cea9 100644
> --- a/drivers/gpu/drm/tyr/driver.rs
> +++ b/drivers/gpu/drm/tyr/driver.rs
> @@ -88,6 +88,12 @@ pub(crate) struct TyrDrmRegistrationData<'drm> {
>
> /// GPU information read from hardware during probe.
> pub(crate) gpu_info: GpuInfo,
> +
> + /// Whether the device is reported as DMA-coherent by firmware.
> + ///
> + /// Cached at probe via `device_get_dma_attr()`. Drives the BO
> + /// cacheability policy in `crate::gem::should_map_wc`.
> + pub(crate) coherent: bool,
> }
>
> fn issue_soft_reset(dev: &Device, iomem: &IoMem<'_>) -> Result {
> @@ -152,6 +158,8 @@ fn probe<'bound>(
> // other threads of execution.
> unsafe {
> pdev.dma_set_mask_and_coherent(DmaMask::try_new(pa_bits)?)? };
>
> + let coherent = pdev.as_ref().dma_attr().is_coherent();
> +
> let unreg_dev =
> drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev, Ok(()))?;
>
> let mmu = Mmu::new(pdev.as_ref(), iomem.as_arc_borrow(),
> &gpu_info)?;
> @@ -162,6 +170,7 @@ fn probe<'bound>(
> &unreg_dev,
> mmu.as_arc_borrow(),
> &gpu_info,
> + coherent,
> )?;
>
> firmware.boot()?;
> @@ -187,6 +196,7 @@ fn probe<'bound>(
> }),
> iomem,
> gpu_info,
> + coherent,
> }),
> )},
> _: { dev_dbg!(pdev, "Tyr initialized correctly.") },
> diff --git a/drivers/gpu/drm/tyr/file.rs b/drivers/gpu/drm/tyr/file.rs
> index 9ffb42f0d8851..d4d6a6742b2e1 100644
> --- a/drivers/gpu/drm/tyr/file.rs
> +++ b/drivers/gpu/drm/tyr/file.rs
> @@ -113,6 +113,7 @@ pub(crate) fn vm_create(
> pfile.reg.mmu.as_arc_borrow(),
> &pfile.reg.gpu_info,
> UserVaRequest::from_uapi(vmcreate.user_va_range),
> + pfile.reg.coherent,
> )?;
> let user_va_range = vm.layout.user.end;
> let id = pfile.vm_pool.add(vm).map_err(|e| {
> @@ -253,7 +254,7 @@ pub(crate) fn vm_get_state(
>
> pub(crate) fn bo_create(
> ddev: &TyrDrmDevice<Registered>,
> - _reg_data: &TyrDrmRegistrationData<'_>,
> + reg_data: &TyrDrmRegistrationData<'_>,
> bocreate: &mut uapi::drm_panthor_bo_create,
> file: &TyrDrmFile,
> ) -> Result<u32> {
> @@ -284,7 +285,7 @@ pub(crate) fn bo_create(
> );
> EINVAL
> })?;
> - let bo = crate::gem::new_object(ddev, size, bocreate.flags)?;
> + let bo = crate::gem::new_object(ddev, size, bocreate.flags,
> reg_data.coherent)?;
> bocreate.handle = bo.create_handle(file)?;
> bocreate.size = bo.size() as u64;
>
> diff --git a/drivers/gpu/drm/tyr/fw.rs b/drivers/gpu/drm/tyr/fw.rs
> index 81e8103368bc2..b24560ae10a4e 100644
> --- a/drivers/gpu/drm/tyr/fw.rs
> +++ b/drivers/gpu/drm/tyr/fw.rs
> @@ -217,8 +217,9 @@ pub(crate) fn new(
> ddev: &TyrDrmDevice,
> mmu: ArcBorrow<'_, Mmu<'drm>>,
> gpu_info: &GpuInfo,
> + coherent: bool,
> ) -> Result<Firmware<'drm>> {
> - let vm = Vm::new_for_fw(dev, ddev, mmu, gpu_info)?;
> + let vm = Vm::new_for_fw(dev, ddev, mmu, gpu_info, coherent)?;
> vm.activate()?;
>
> let sections = (|| -> Result<KVec<Section<'drm>>> {
> @@ -235,6 +236,7 @@ pub(crate) fn new(
> size,
> KernelBoVaAlloc::Explicit(va),
> parsed.vm_map_flags,
> + coherent,
> )?;
>
> let section_start = parsed.data_range.start as usize;
> diff --git a/drivers/gpu/drm/tyr/gem.rs b/drivers/gpu/drm/tyr/gem.rs
> index 14f3e182b98e2..fad0720ce7123 100644
> --- a/drivers/gpu/drm/tyr/gem.rs
> +++ b/drivers/gpu/drm/tyr/gem.rs
> @@ -63,19 +63,35 @@ fn new(_dev: &TyrDrmDevice, _size: usize, args:
> BoCreateArgs) -> impl PinInit<Se
> /// Type alias for Tyr GEM buffer objects.
> pub(crate) type Bo = gem::shmem::Object<BoData>;
>
> +/// Returns whether a BO should be mapped write-combine given the device's
> +/// DMA coherence.
> +pub(crate) fn should_map_wc(coherent: bool) -> bool {
> + if coherent {
> + return false;
> + }
> +
> + true
> +}
> +
> /// Create a new GEM buffer object.
> -pub(crate) fn new_object(ddev: &TyrDrmDevice, size: usize, flags: u32) ->
> Result<ARef<Bo>> {
> +pub(crate) fn new_object(
> + ddev: &TyrDrmDevice,
> + size: usize,
> + flags: u32,
> + coherent: bool,
> +) -> Result<ARef<Bo>> {
> if size == 0 {
> return Err(EINVAL);
> }
>
> let aligned_size =
> size.checked_next_multiple_of(PAGE_SIZE).ok_or(EINVAL)?;
>
> + let map_wc = should_map_wc(coherent);
> let bo = Bo::new(
> ddev,
> aligned_size,
> shmem::ObjectConfig {
> - map_wc: true,
> + map_wc,
> parent_resv_obj: None,
> },
> BoCreateArgs { flags },
> @@ -94,18 +110,17 @@ pub(crate) fn lookup_handle(file: &TyrDrmFile, handle:
> u32) -> Result<ARef<Bo>>
> }
>
> /// Creates a dummy GEM object to serve as the root of a GPUVM.
> -pub(crate) fn new_dummy_object(ddev: &TyrDrmDevice) -> Result<ARef<Bo>> {
> - let bo = Bo::new(
> +pub(crate) fn new_dummy_object(ddev: &TyrDrmDevice, coherent: bool) ->
> Result<ARef<Bo>> {
> + // FIXME: use a Rust resv-object abstraction once available, rather than
> a real BO.
> + Bo::new(
> ddev,
> 4096,
> shmem::ObjectConfig {
> - map_wc: true,
> + map_wc: should_map_wc(coherent),
> parent_resv_obj: None,
> },
> BoCreateArgs { flags: 0 },
> - )?;
> -
> - Ok(bo)
> + )
> }
>
> /// Specifies how to choose a GPU virtual address for a [`KernelBo`].
> @@ -143,6 +158,7 @@ pub(crate) fn new(
> size: u64,
> va_alloc: KernelBoVaAlloc,
> flags: VmMapFlags,
> + coherent: bool,
> ) -> Result<Self> {
> if size == 0 {
> dev_err!(vm.dev(), "Cannot create KernelBo with size 0");
> @@ -158,7 +174,7 @@ pub(crate) fn new(
> ddev,
> bo_size,
> shmem::ObjectConfig {
> - map_wc: true,
> + map_wc: should_map_wc(coherent),
> parent_resv_obj: None,
> },
> BoCreateArgs { flags: 0 },
> diff --git a/drivers/gpu/drm/tyr/vm.rs b/drivers/gpu/drm/tyr/vm.rs
> index 5c3be79b2c595..fc034514c2ce9 100644
> --- a/drivers/gpu/drm/tyr/vm.rs
> +++ b/drivers/gpu/drm/tyr/vm.rs
> @@ -473,13 +473,14 @@ pub(crate) fn new_for_fw(
> ddev: &TyrDrmDevice,
> mmu: ArcBorrow<'_, Mmu<'drm>>,
> gpu_info: &GpuInfo,
> + coherent: bool,
> ) -> Result<Arc<Vm<'drm>>> {
> // As in panthor: the CSF MCU is a Cortex-M7 and can only address 4G.
> let layout = VmLayout {
> full: 0..u64::SZ_4G,
> user: 0..0u64,
> };
> - Self::new_internal(dev, ddev, mmu, gpu_info, layout)
> + Self::new_internal(dev, ddev, mmu, gpu_info, layout, coherent)
> }
>
> /// Creates a user VM, splitting the GPU VA range per `user_va`.
> @@ -489,6 +490,7 @@ pub(crate) fn new_for_user(
> mmu: ArcBorrow<'_, Mmu<'drm>>,
> gpu_info: &GpuInfo,
> user_va: UserVaRequest,
> + coherent: bool,
> ) -> Result<Arc<Vm<'drm>>> {
> let mmu_features = MMU_FEATURES::from_raw(gpu_info.mmu_features);
> let va_bits = mmu_features.va_bits().get();
> @@ -502,7 +504,7 @@ pub(crate) fn new_for_user(
> range.end
> );
> })?;
> - Self::new_internal(dev, ddev, mmu, gpu_info, layout)
> + Self::new_internal(dev, ddev, mmu, gpu_info, layout, coherent)
> }
>
> /// Initializes a VM with the given layout.
> @@ -512,6 +514,7 @@ fn new_internal(
> mmu: ArcBorrow<'_, Mmu<'drm>>,
> gpu_info: &GpuInfo,
> layout: VmLayout,
> + coherent: bool,
> ) -> Result<Arc<Vm<'drm>>> {
> let mmu_features = MMU_FEATURES::from_raw(gpu_info.mmu_features);
> let va_bits = mmu_features.va_bits().get();
> @@ -520,7 +523,7 @@ fn new_internal(
> let reserve_range = 0..0u64;
>
> // dummy_obj is used to initialize the GPUVM tree.
> - let dummy_obj = gem::new_dummy_object(ddev).inspect_err(|e| {
> + let dummy_obj = gem::new_dummy_object(ddev,
> coherent).inspect_err(|e| {
> dev_err!(dev, "Failed to create dummy GEM object: {:?}", e);
> })?;
>
>
> --
> 2.43.0
>