Commit 15392f76 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-rust-next-2026-01-26' of...

Merge tag 'drm-rust-next-2026-01-26' of https://gitlab.freedesktop.org/drm/rust/kernel

 into drm-next

DRM Rust changes for v7.0-rc1

DRM:
  - Fix documentation for Registration constructors.
  - Use pin_init::zeroed() for fops initialization.
  - Annotate DRM helpers with __rust_helper.
  - Improve safety documentation for gem::Object::new().
  - Update AlwaysRefCounted imports.

MM:
  - Prevent integer overflow in page_align().

Nova (Core):
  - Prepare for Turing support. This includes parsing and handling
    Turing-specific firmware headers and sections as well as a Turing
    Falcon HAL implementation.
  - Get rid of the Result<impl PinInit<T, E>> anti-pattern.
  - Relocate initializer-specific code into the appropriate initializer.
  - Use CStr::from_bytes_until_nul() to remove custom helpers.
  - Improve handling of unexpected firmware values.
  - Clean up redundant debug prints.
  - Replace c_str!() with native Rust C-string literals.
  - Update nova-core task list.

Nova (DRM):
  - Align GEM object size to system page size.

Tyr:
  - Use generated uAPI bindings for GpuInfo.
  - Replace manual sleeps with read_poll_timeout().
  - Replace c_str!() with native Rust C-string literals.
  - Suppress warnings for unread fields.
  - Fix incorrect register name in print statement.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: "Danilo Krummrich" <dakr@kernel.org>
Link: https://patch.msgid.link/DFYW1WV6DUCG.3K8V2DAVD1Q4A@kernel.org
parents 205bd156 cea7b66a
Loading
Loading
Loading
Loading
+15 −44
Original line number Diff line number Diff line
@@ -41,8 +41,15 @@ trait [1] from the num crate.
Having this generalization also helps with implementing a generic macro that
automatically generates the corresponding mappings between a value and a number.

FromPrimitive support has been worked on in the past, but hasn't been followed
since then [1].

There also have been considerations of ToPrimitive [2].

| Complexity: Beginner
| Link: https://docs.rs/num/latest/num/trait.FromPrimitive.html
| Link: https://lore.kernel.org/all/cover.1750689857.git.y.j3ms.n@gmail.com/ [1]
| Link: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/Implement.20.60FromPrimitive.60.20trait.20.2B.20derive.20macro.20for.20nova-core/with/541971854 [2]

Generic register abstraction [REGA]
-----------------------------------
@@ -134,21 +141,6 @@ A `num` core kernel module is being designed to provide these operations.
| Complexity: Intermediate
| Contact: Alexandre Courbot

IRQ abstractions
----------------

Rust abstractions for IRQ handling.

There is active ongoing work from Daniel Almeida [1] for the "core" abstractions
to request IRQs.

Besides optional review and testing work, the required ``pci::Device`` code
around those core abstractions needs to be worked out.

| Complexity: Intermediate
| Link: https://lore.kernel.org/lkml/20250122163932.46697-1-daniel.almeida@collabora.com/ [1]
| Contact: Daniel Almeida

Page abstraction for foreign pages
----------------------------------

@@ -161,40 +153,16 @@ There is active onging work from Abdiel Janulgue [1] and Lina [2].
| Link: https://lore.kernel.org/linux-mm/20241119112408.779243-1-abdiel.janulgue@gmail.com/ [1]
| Link: https://lore.kernel.org/rust-for-linux/20250202-rust-page-v1-0-e3170d7fe55e@asahilina.net/ [2]

Scatterlist / sg_table abstractions
-----------------------------------

Rust abstractions for scatterlist / sg_table.

There is preceding work from Abdiel Janulgue, which hasn't made it to the
mailing list yet.

| Complexity: Intermediate
| Contact: Abdiel Janulgue

PCI MISC APIs
-------------

Extend the existing PCI device / driver abstractions by SR-IOV, config space,
capability, MSI API abstractions.

| Complexity: Beginner
Extend the existing PCI device / driver abstractions by SR-IOV, capability, MSI
API abstractions.

XArray bindings [XARR]
----------------------

We need bindings for `xa_alloc`/`xa_alloc_cyclic` in order to generate the
auxiliary device IDs.

| Complexity: Intermediate
SR-IOV [1] is work in progress.

Debugfs abstractions
--------------------

Rust abstraction for debugfs APIs.

| Reference: Export GSP log buffers
| Complexity: Intermediate
| Complexity: Beginner
| Link: https://lore.kernel.org/all/20251119-rust-pci-sriov-v1-0-883a94599a97@redhat.com/ [1]

GPU (general)
=============
@@ -233,7 +201,10 @@ Some possible options:
    - maple_tree
  - native Rust collections

There is work in progress for using drm_buddy [1].

| Complexity: Advanced
| Link: https://lore.kernel.org/all/20251219203805.1246586-4-joelagnelf@nvidia.com/ [1]

Instance Memory
---------------
+13 −5
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

use kernel::{
    auxiliary, c_str, device::Core, drm, drm::gem, drm::ioctl, prelude::*, sync::aref::ARef,
    auxiliary,
    device::Core,
    drm::{
        self,
        gem,
        ioctl, //
    },
    prelude::*,
    sync::aref::ARef, //
};

use crate::file::File;
@@ -24,12 +32,12 @@ pub(crate) struct NovaData {
    major: 0,
    minor: 0,
    patchlevel: 0,
    name: c_str!("nova"),
    desc: c_str!("Nvidia Graphics"),
    name: c"nova",
    desc: c"Nvidia Graphics",
};

const NOVA_CORE_MODULE_NAME: &CStr = c_str!("NovaCore");
const AUXILIARY_NAME: &CStr = c_str!("nova-drm");
const NOVA_CORE_MODULE_NAME: &CStr = c"NovaCore";
const AUXILIARY_NAME: &CStr = c"nova-drm";

kernel::auxiliary_device_table!(
    AUX_TABLE,
+3 −3
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
use kernel::{
    drm,
    drm::{gem, gem::BaseObject},
    page,
    prelude::*,
    sync::aref::ARef,
};
@@ -27,11 +28,10 @@ fn new(_dev: &NovaDevice, _size: usize) -> impl PinInit<Self, Error> {
impl NovaObject {
    /// Create a new DRM GEM object.
    pub(crate) fn new(dev: &NovaDevice, size: usize) -> Result<ARef<gem::Object<Self>>> {
        let aligned_size = size.next_multiple_of(1 << 12);

        if size == 0 || size > aligned_size {
        if size == 0 {
            return Err(EINVAL);
        }
        let aligned_size = page::page_align(size).ok_or(EINVAL)?;

        gem::Object::new(dev, aligned_size)
    }
+24 −31
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0 or MIT

use kernel::c_str;
use kernel::clk::Clk;
use kernel::clk::OptionalClk;
use kernel::device::Bound;
@@ -9,6 +8,7 @@
use kernel::devres::Devres;
use kernel::drm;
use kernel::drm::ioctl;
use kernel::io::poll;
use kernel::new_mutex;
use kernel::of;
use kernel::platform;
@@ -16,10 +16,10 @@
use kernel::regulator;
use kernel::regulator::Regulator;
use kernel::sizes::SZ_2M;
use kernel::sync::aref::ARef;
use kernel::sync::Arc;
use kernel::sync::Mutex;
use kernel::time;
use kernel::types::ARef;

use crate::file::File;
use crate::gem::TyrObject;
@@ -34,7 +34,7 @@

#[pin_data(PinnedDrop)]
pub(crate) struct TyrDriver {
    device: ARef<TyrDevice>,
    _device: ARef<TyrDevice>,
}

#[pin_data(PinnedDrop)]
@@ -68,20 +68,13 @@ unsafe impl Sync for TyrData {}
fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result {
    regs::GPU_CMD.write(dev, iomem, regs::GPU_CMD_SOFT_RESET)?;

    // TODO: We cannot poll, as there is no support in Rust currently, so we
    // sleep. Change this when read_poll_timeout() is implemented in Rust.
    kernel::time::delay::fsleep(time::Delta::from_millis(100));

    if regs::GPU_IRQ_RAWSTAT.read(dev, iomem)? & regs::GPU_IRQ_RAWSTAT_RESET_COMPLETED == 0 {
        dev_err!(dev, "GPU reset failed with errno\n");
        dev_err!(
            dev,
            "GPU_INT_RAWSTAT is {}\n",
            regs::GPU_IRQ_RAWSTAT.read(dev, iomem)?
        );

        return Err(EIO);
    }
    poll::read_poll_timeout(
        || regs::GPU_IRQ_RAWSTAT.read(dev, iomem),
        |status| *status & regs::GPU_IRQ_RAWSTAT_RESET_COMPLETED != 0,
        time::Delta::from_millis(1),
        time::Delta::from_millis(100),
    )
    .inspect_err(|_| dev_err!(dev, "GPU reset failed."))?;

    Ok(())
}
@@ -91,8 +84,8 @@ fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result {
    MODULE_OF_TABLE,
    <TyrDriver as platform::Driver>::IdInfo,
    [
        (of::DeviceId::new(c_str!("rockchip,rk3588-mali")), ()),
        (of::DeviceId::new(c_str!("arm,mali-valhall-csf")), ())
        (of::DeviceId::new(c"rockchip,rk3588-mali"), ()),
        (of::DeviceId::new(c"arm,mali-valhall-csf"), ())
    ]
);

@@ -104,16 +97,16 @@ fn probe(
        pdev: &platform::Device<Core>,
        _info: Option<&Self::IdInfo>,
    ) -> impl PinInit<Self, Error> {
        let core_clk = Clk::get(pdev.as_ref(), Some(c_str!("core")))?;
        let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("stacks")))?;
        let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("coregroup")))?;
        let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?;
        let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?;
        let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?;

        core_clk.prepare_enable()?;
        stacks_clk.prepare_enable()?;
        coregroup_clk.prepare_enable()?;

        let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c_str!("mali"))?;
        let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c_str!("sram"))?;
        let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"mali")?;
        let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?;

        let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
        let iomem = Arc::pin_init(request.iomap_sized::<SZ_2M>(), GFP_KERNEL)?;
@@ -134,8 +127,8 @@ fn probe(
                    coregroup: coregroup_clk,
                }),
                regulators <- new_mutex!(Regulators {
                    mali: mali_regulator,
                    sram: sram_regulator,
                    _mali: mali_regulator,
                    _sram: sram_regulator,
                }),
                gpu_info,
        });
@@ -143,7 +136,7 @@ fn probe(
        let tdev: ARef<TyrDevice> = drm::Device::new(pdev.as_ref(), data)?;
        drm::driver::Registration::new_foreign_owned(&tdev, pdev.as_ref(), 0)?;

        let driver = TyrDriver { device: tdev };
        let driver = TyrDriver { _device: tdev };

        // We need this to be dev_info!() because dev_dbg!() does not work at
        // all in Rust for now, and we need to see whether probe succeeded.
@@ -174,8 +167,8 @@ fn drop(self: Pin<&mut Self>) {
    major: 1,
    minor: 5,
    patchlevel: 0,
    name: c_str!("panthor"),
    desc: c_str!("ARM Mali Tyr DRM driver"),
    name: c"panthor",
    desc: c"ARM Mali Tyr DRM driver",
};

#[vtable]
@@ -200,6 +193,6 @@ struct Clocks {

#[pin_data]
struct Regulators {
    mali: Regulator<regulator::Enabled>,
    sram: Regulator<regulator::Enabled>,
    _mali: Regulator<regulator::Enabled>,
    _sram: Regulator<regulator::Enabled>,
}
+31 −34
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0 or MIT

use core::ops::Deref;
use core::ops::DerefMut;
use kernel::bits::genmask_u32;
use kernel::device::Bound;
use kernel::device::Device;
use kernel::devres::Devres;
use kernel::io::poll;
use kernel::platform;
use kernel::prelude::*;
use kernel::time;
use kernel::time::Delta;
use kernel::transmute::AsBytes;
use kernel::uapi;

@@ -19,29 +22,9 @@
/// # Invariants
///
/// - The layout of this struct identical to the C `struct drm_panthor_gpu_info`.
#[repr(C)]
pub(crate) struct GpuInfo {
    pub(crate) gpu_id: u32,
    pub(crate) gpu_rev: u32,
    pub(crate) csf_id: u32,
    pub(crate) l2_features: u32,
    pub(crate) tiler_features: u32,
    pub(crate) mem_features: u32,
    pub(crate) mmu_features: u32,
    pub(crate) thread_features: u32,
    pub(crate) max_threads: u32,
    pub(crate) thread_max_workgroup_size: u32,
    pub(crate) thread_max_barrier_size: u32,
    pub(crate) coherency_features: u32,
    pub(crate) texture_features: [u32; 4],
    pub(crate) as_present: u32,
    pub(crate) selected_coherency: u32,
    pub(crate) shader_present: u64,
    pub(crate) l2_present: u64,
    pub(crate) tiler_present: u64,
    pub(crate) core_features: u32,
    pub(crate) pad: u32,
}
#[repr(transparent)]
#[derive(Clone, Copy)]
pub(crate) struct GpuInfo(pub(crate) uapi::drm_panthor_gpu_info);

impl GpuInfo {
    pub(crate) fn new(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result<Self> {
@@ -74,7 +57,7 @@ pub(crate) fn new(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result<Self> {
        let l2_present = u64::from(regs::GPU_L2_PRESENT_LO.read(dev, iomem)?);
        let l2_present = l2_present | u64::from(regs::GPU_L2_PRESENT_HI.read(dev, iomem)?) << 32;

        Ok(Self {
        Ok(Self(uapi::drm_panthor_gpu_info {
            gpu_id,
            gpu_rev,
            csf_id,
@@ -96,7 +79,8 @@ pub(crate) fn new(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result<Self> {
            tiler_present,
            core_features,
            pad: 0,
        })
            gpu_features: 0,
        }))
    }

    pub(crate) fn log(&self, pdev: &platform::Device) {
@@ -155,6 +139,20 @@ pub(crate) fn pa_bits(&self) -> u32 {
    }
}

impl Deref for GpuInfo {
    type Target = uapi::drm_panthor_gpu_info;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for GpuInfo {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

// SAFETY: `GpuInfo`'s invariant guarantees that it is the same type that is
// already exposed to userspace by the C driver. This implies that it fulfills
// the requirements for `AsBytes`.
@@ -207,14 +205,13 @@ fn from(value: u32) -> Self {
pub(crate) fn l2_power_on(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result {
    regs::L2_PWRON_LO.write(dev, iomem, 1)?;

    // TODO: We cannot poll, as there is no support in Rust currently, so we
    // sleep. Change this when read_poll_timeout() is implemented in Rust.
    kernel::time::delay::fsleep(time::Delta::from_millis(100));

    if regs::L2_READY_LO.read(dev, iomem)? != 1 {
        dev_err!(dev, "Failed to power on the GPU\n");
        return Err(EIO);
    }
    poll::read_poll_timeout(
        || regs::L2_READY_LO.read(dev, iomem),
        |status| *status == 1,
        Delta::from_millis(1),
        Delta::from_millis(100),
    )
    .inspect_err(|_| dev_err!(dev, "Failed to power on the GPU."))?;

    Ok(())
}
Loading