Skip to content

Commit cdeaeb9

Browse files
author
Danilo Krummrich
committed
drm: nova-drm: add initial driver skeleton
Add the initial nova-drm driver skeleton. nova-drm is connected to nova-core through the auxiliary bus and implements the DRM parts of the nova driver stack. For now, it implements the fundamental DRM abstractions, i.e. creates a DRM device and registers it, exposing a three sample IOCTLs. DRM_IOCTL_NOVA_GETPARAM - provides the PCI bar size from the bar that maps the GPUs VRAM from nova-core DRM_IOCTL_NOVA_GEM_CREATE - creates a new dummy DRM GEM object and returns a handle DRM_IOCTL_NOVA_GEM_INFO - provides metadata for the DRM GEM object behind a given handle I implemented a small userspace test suite [1] that utilizes this interface. Link: https://gitlab.freedesktop.org/dakr/drm-test [1] Reviewed-by: Maxime Ripard <mripard@kernel.org> Acked-by: Dave Airlie <airlied@redhat.com> Link: https://lore.kernel.org/r/20250424160452.8070-3-dakr@kernel.org [ Kconfig: depend on DRM=y rather than just DRM. - Danilo ] Signed-off-by: Danilo Krummrich <dakr@kernel.org>
1 parent e041d81 commit cdeaeb9

File tree

12 files changed

+405
-0
lines changed

12 files changed

+405
-0
lines changed

MAINTAINERS

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7594,6 +7594,18 @@ T: git https://gitlab.freedesktop.org/drm/nova.git nova-next
75947594
F: Documentation/gpu/nova/
75957595
F: drivers/gpu/nova-core/
75967596

7597+
DRM DRIVER FOR NVIDIA GPUS [RUST]
7598+
M: Danilo Krummrich <dakr@kernel.org>
7599+
L: nouveau@lists.freedesktop.org
7600+
S: Supported
7601+
Q: https://patchwork.freedesktop.org/project/nouveau/
7602+
B: https://gitlab.freedesktop.org/drm/nova/-/issues
7603+
C: irc://irc.oftc.net/nouveau
7604+
T: git https://gitlab.freedesktop.org/drm/nova.git nova-next
7605+
F: Documentation/gpu/nova/
7606+
F: drivers/gpu/drm/nova/
7607+
F: include/uapi/drm/nova_drm.h
7608+
75977609
DRM DRIVER FOR OLIMEX LCD-OLINUXINO PANELS
75987610
M: Stefan Mavrodiev <stefan@olimex.com>
75997611
S: Maintained

drivers/gpu/drm/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,8 @@ source "drivers/gpu/drm/amd/amdgpu/Kconfig"
343343

344344
source "drivers/gpu/drm/nouveau/Kconfig"
345345

346+
source "drivers/gpu/drm/nova/Kconfig"
347+
346348
source "drivers/gpu/drm/i915/Kconfig"
347349

348350
source "drivers/gpu/drm/xe/Kconfig"

drivers/gpu/drm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
176176
obj-$(CONFIG_DRM_VGEM) += vgem/
177177
obj-$(CONFIG_DRM_VKMS) += vkms/
178178
obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
179+
obj-$(CONFIG_DRM_NOVA) += nova/
179180
obj-$(CONFIG_DRM_EXYNOS) +=exynos/
180181
obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
181182
obj-$(CONFIG_DRM_GMA500) += gma500/

drivers/gpu/drm/nova/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
config DRM_NOVA
2+
tristate "Nova DRM driver"
3+
depends on AUXILIARY_BUS
4+
depends on DRM=y
5+
depends on PCI
6+
depends on RUST
7+
default n
8+
help
9+
Choose this if you want to build the Nova DRM driver for Nvidia
10+
GSP-based GPUs.
11+
12+
This driver is work in progress and may not be functional.
13+
14+
If M is selected, the module will be called nova.

drivers/gpu/drm/nova/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
3+
obj-$(CONFIG_DRM_NOVA) += nova.o

drivers/gpu/drm/nova/driver.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
use kernel::{auxiliary, c_str, device::Core, drm, drm::gem, drm::ioctl, prelude::*, types::ARef};
4+
5+
use crate::file::File;
6+
use crate::gem::NovaObject;
7+
8+
pub(crate) struct NovaDriver {
9+
#[expect(unused)]
10+
drm: ARef<drm::Device<Self>>,
11+
}
12+
13+
/// Convienence type alias for the DRM device type for this driver
14+
pub(crate) type NovaDevice = drm::Device<NovaDriver>;
15+
16+
#[pin_data]
17+
pub(crate) struct NovaData {
18+
pub(crate) adev: ARef<auxiliary::Device>,
19+
}
20+
21+
const INFO: drm::DriverInfo = drm::DriverInfo {
22+
major: 0,
23+
minor: 0,
24+
patchlevel: 0,
25+
name: c_str!("nova"),
26+
desc: c_str!("Nvidia Graphics"),
27+
};
28+
29+
const NOVA_CORE_MODULE_NAME: &CStr = c_str!("NovaCore");
30+
const AUXILIARY_NAME: &CStr = c_str!("nova-drm");
31+
32+
kernel::auxiliary_device_table!(
33+
AUX_TABLE,
34+
MODULE_AUX_TABLE,
35+
<NovaDriver as auxiliary::Driver>::IdInfo,
36+
[(
37+
auxiliary::DeviceId::new(NOVA_CORE_MODULE_NAME, AUXILIARY_NAME),
38+
()
39+
)]
40+
);
41+
42+
impl auxiliary::Driver for NovaDriver {
43+
type IdInfo = ();
44+
const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE;
45+
46+
fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
47+
let data = try_pin_init!(NovaData { adev: adev.into() });
48+
49+
let drm = drm::Device::<Self>::new(adev.as_ref(), data)?;
50+
drm::Registration::new_foreign_owned(&drm, adev.as_ref(), 0)?;
51+
52+
Ok(KBox::new(Self { drm }, GFP_KERNEL)?.into())
53+
}
54+
}
55+
56+
#[vtable]
57+
impl drm::Driver for NovaDriver {
58+
type Data = NovaData;
59+
type File = File;
60+
type Object = gem::Object<NovaObject>;
61+
62+
const INFO: drm::DriverInfo = INFO;
63+
64+
kernel::declare_drm_ioctls! {
65+
(NOVA_GETPARAM, drm_nova_getparam, ioctl::RENDER_ALLOW, File::get_param),
66+
(NOVA_GEM_CREATE, drm_nova_gem_create, ioctl::AUTH | ioctl::RENDER_ALLOW, File::gem_create),
67+
(NOVA_GEM_INFO, drm_nova_gem_info, ioctl::AUTH | ioctl::RENDER_ALLOW, File::gem_info),
68+
}
69+
}

drivers/gpu/drm/nova/file.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
use crate::driver::{NovaDevice, NovaDriver};
4+
use crate::gem::NovaObject;
5+
use crate::uapi::{GemCreate, GemInfo, Getparam};
6+
use kernel::{
7+
alloc::flags::*,
8+
drm::{self, gem::BaseObject},
9+
pci,
10+
prelude::*,
11+
types::Opaque,
12+
uapi,
13+
};
14+
15+
pub(crate) struct File;
16+
17+
impl drm::file::DriverFile for File {
18+
type Driver = NovaDriver;
19+
20+
fn open(_dev: &NovaDevice) -> Result<Pin<KBox<Self>>> {
21+
Ok(KBox::new(Self, GFP_KERNEL)?.into())
22+
}
23+
}
24+
25+
impl File {
26+
/// IOCTL: get_param: Query GPU / driver metadata.
27+
pub(crate) fn get_param(
28+
dev: &NovaDevice,
29+
getparam: &Opaque<uapi::drm_nova_getparam>,
30+
_file: &drm::File<File>,
31+
) -> Result<u32> {
32+
let adev = &dev.adev;
33+
let parent = adev.parent().ok_or(ENOENT)?;
34+
let pdev: &pci::Device = parent.try_into()?;
35+
let getparam: &Getparam = getparam.into();
36+
37+
let value = match getparam.param() as u32 {
38+
uapi::NOVA_GETPARAM_VRAM_BAR_SIZE => pdev.resource_len(1)?,
39+
_ => return Err(EINVAL),
40+
};
41+
42+
getparam.set_value(value);
43+
44+
Ok(0)
45+
}
46+
47+
/// IOCTL: gem_create: Create a new DRM GEM object.
48+
pub(crate) fn gem_create(
49+
dev: &NovaDevice,
50+
req: &Opaque<uapi::drm_nova_gem_create>,
51+
file: &drm::File<File>,
52+
) -> Result<u32> {
53+
let req: &GemCreate = req.into();
54+
let obj = NovaObject::new(dev, req.size().try_into()?)?;
55+
56+
req.set_handle(obj.create_handle(file)?);
57+
58+
Ok(0)
59+
}
60+
61+
/// IOCTL: gem_info: Query GEM metadata.
62+
pub(crate) fn gem_info(
63+
_dev: &NovaDevice,
64+
req: &Opaque<uapi::drm_nova_gem_info>,
65+
file: &drm::File<File>,
66+
) -> Result<u32> {
67+
let req: &GemInfo = req.into();
68+
let bo = NovaObject::lookup_handle(file, req.handle())?;
69+
70+
req.set_size(bo.size().try_into()?);
71+
72+
Ok(0)
73+
}
74+
}

drivers/gpu/drm/nova/gem.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
use kernel::{
4+
drm,
5+
drm::{gem, gem::BaseObject},
6+
prelude::*,
7+
types::ARef,
8+
};
9+
10+
use crate::{
11+
driver::{NovaDevice, NovaDriver},
12+
file::File,
13+
};
14+
15+
/// GEM Object inner driver data
16+
#[pin_data]
17+
pub(crate) struct NovaObject {}
18+
19+
impl gem::BaseDriverObject<gem::Object<NovaObject>> for NovaObject {
20+
fn new(_dev: &NovaDevice, _size: usize) -> impl PinInit<Self, Error> {
21+
try_pin_init!(NovaObject {})
22+
}
23+
}
24+
25+
impl gem::DriverObject for NovaObject {
26+
type Driver = NovaDriver;
27+
}
28+
29+
impl NovaObject {
30+
/// Create a new DRM GEM object.
31+
pub(crate) fn new(dev: &NovaDevice, size: usize) -> Result<ARef<gem::Object<Self>>> {
32+
let aligned_size = size.next_multiple_of(1 << 12);
33+
34+
if size == 0 || size > aligned_size {
35+
return Err(EINVAL);
36+
}
37+
38+
gem::Object::new(dev, aligned_size)
39+
}
40+
41+
/// Look up a GEM object handle for a `File` and return an `ObjectRef` for it.
42+
#[inline]
43+
pub(crate) fn lookup_handle(
44+
file: &drm::File<File>,
45+
handle: u32,
46+
) -> Result<ARef<gem::Object<Self>>> {
47+
gem::Object::lookup_handle(file, handle)
48+
}
49+
}

drivers/gpu/drm/nova/nova.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Nova DRM Driver
4+
5+
mod driver;
6+
mod file;
7+
mod gem;
8+
mod uapi;
9+
10+
use crate::driver::NovaDriver;
11+
12+
kernel::module_auxiliary_driver! {
13+
type: NovaDriver,
14+
name: "Nova",
15+
author: "Danilo Krummrich",
16+
description: "Nova GPU driver",
17+
license: "GPL v2",
18+
}

drivers/gpu/drm/nova/uapi.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
use kernel::uapi;
4+
5+
// TODO Work out some common infrastructure to avoid boilerplate code for uAPI abstractions.
6+
7+
macro_rules! define_uapi_abstraction {
8+
($name:ident <= $inner:ty) => {
9+
#[repr(transparent)]
10+
pub struct $name(::kernel::types::Opaque<$inner>);
11+
12+
impl ::core::convert::From<&::kernel::types::Opaque<$inner>> for &$name {
13+
fn from(value: &::kernel::types::Opaque<$inner>) -> Self {
14+
// SAFETY: `Self` is a transparent wrapper of `$inner`.
15+
unsafe { ::core::mem::transmute(value) }
16+
}
17+
}
18+
};
19+
}
20+
21+
define_uapi_abstraction!(Getparam <= uapi::drm_nova_getparam);
22+
23+
impl Getparam {
24+
pub fn param(&self) -> u64 {
25+
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_getparam`.
26+
unsafe { (*self.0.get()).param }
27+
}
28+
29+
pub fn set_value(&self, v: u64) {
30+
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_getparam`.
31+
unsafe { (*self.0.get()).value = v };
32+
}
33+
}
34+
35+
define_uapi_abstraction!(GemCreate <= uapi::drm_nova_gem_create);
36+
37+
impl GemCreate {
38+
pub fn size(&self) -> u64 {
39+
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_create`.
40+
unsafe { (*self.0.get()).size }
41+
}
42+
43+
pub fn set_handle(&self, handle: u32) {
44+
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_create`.
45+
unsafe { (*self.0.get()).handle = handle };
46+
}
47+
}
48+
49+
define_uapi_abstraction!(GemInfo <= uapi::drm_nova_gem_info);
50+
51+
impl GemInfo {
52+
pub fn handle(&self) -> u32 {
53+
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_info`.
54+
unsafe { (*self.0.get()).handle }
55+
}
56+
57+
pub fn set_size(&self, size: u64) {
58+
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_info`.
59+
unsafe { (*self.0.get()).size = size };
60+
}
61+
}

0 commit comments

Comments
 (0)