summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nova
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nova')
-rw-r--r--drivers/gpu/drm/nova/Kconfig17
-rw-r--r--drivers/gpu/drm/nova/Makefile3
-rw-r--r--drivers/gpu/drm/nova/driver.rs88
-rw-r--r--drivers/gpu/drm/nova/file.rs77
-rw-r--r--drivers/gpu/drm/nova/gem.rs51
-rw-r--r--drivers/gpu/drm/nova/nova.rs17
6 files changed, 253 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nova/Kconfig b/drivers/gpu/drm/nova/Kconfig
new file mode 100644
index 000000000..ba16c7440
--- /dev/null
+++ b/drivers/gpu/drm/nova/Kconfig
@@ -0,0 +1,17 @@
+config DRM_NOVA
+ tristate "Nova DRM driver"
+ depends on 64BIT
+ depends on DRM=y
+ depends on PCI
+ depends on RUST
+ depends on !CPU_BIG_ENDIAN
+ select AUXILIARY_BUS
+ select NOVA_CORE
+ default n
+ help
+ Choose this if you want to build the Nova DRM driver for Nvidia
+ GSP-based GPUs.
+
+ This driver is work in progress and may not be functional.
+
+ If M is selected, the module will be called nova-drm.
diff --git a/drivers/gpu/drm/nova/Makefile b/drivers/gpu/drm/nova/Makefile
new file mode 100644
index 000000000..6355f7502
--- /dev/null
+++ b/drivers/gpu/drm/nova/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+# nova-drm is built from drivers/gpu/Makefile.
+# nova.o (rust-analyzer marker - DO NOT REMOVE).
diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs
new file mode 100644
index 000000000..60752bccd
--- /dev/null
+++ b/drivers/gpu/drm/nova/driver.rs
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use kernel::{
+ auxiliary,
+ device::{
+ Core,
+ DeviceContext, //
+ },
+ drm::{
+ self,
+ gem,
+ ioctl, //
+ },
+ prelude::*,
+ sync::aref::ARef, //
+};
+
+use crate::file::File;
+use crate::gem::NovaObject;
+
+pub(crate) struct NovaDriver;
+
+pub(crate) struct Nova<'bound> {
+ #[expect(unused)]
+ drm: ARef<drm::Device<NovaDriver>>,
+ _reg: drm::Registration<'bound, NovaDriver>,
+}
+
+/// Convienence type alias for the DRM device type for this driver
+pub(crate) type NovaDevice<Ctx = drm::Normal> = drm::Device<NovaDriver, Ctx>;
+
+const INFO: drm::DriverInfo = drm::DriverInfo {
+ major: 0,
+ minor: 0,
+ patchlevel: 0,
+ name: c"nova-drm",
+ desc: c"NVIDIA Graphics and Compute",
+};
+
+const NOVA_CORE_MODULE_NAME: &CStr = c"nova-core";
+const AUXILIARY_NAME: &CStr = c"nova-drm";
+
+kernel::auxiliary_device_table!(
+ AUX_TABLE,
+ <NovaDriver as auxiliary::Driver>::IdInfo,
+ [(
+ auxiliary::DeviceId::new(NOVA_CORE_MODULE_NAME, AUXILIARY_NAME),
+ ()
+ )]
+);
+
+impl auxiliary::Driver for NovaDriver {
+ type IdInfo = ();
+ type Data<'bound> = Nova<'bound>;
+ const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE;
+
+ fn probe<'bound>(
+ adev: &'bound auxiliary::Device<Core<'_>>,
+ _info: &'bound Self::IdInfo,
+ ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
+ let drm = drm::UnregisteredDevice::<Self>::new(adev, Ok(()))?;
+ // SAFETY: `reg` is stored in `Nova` and dropped when the driver is unbound; it is
+ // never forgotten.
+ let reg = unsafe { drm::Registration::new(adev.as_ref(), drm, (), 0)? };
+
+ Ok(Nova {
+ drm: reg.device().into(),
+ _reg: reg,
+ })
+ }
+}
+
+#[vtable]
+impl drm::Driver for NovaDriver {
+ type Data = ();
+ type RegistrationData<'a> = ();
+ type File = File;
+ type Object = gem::Object<NovaObject>;
+ type ParentDevice<Ctx: DeviceContext> = auxiliary::Device<Ctx>;
+
+ const INFO: drm::DriverInfo = INFO;
+
+ kernel::declare_drm_ioctls! {
+ (NOVA_GETPARAM, drm_nova_getparam, ioctl::RENDER_ALLOW, File::get_param),
+ (NOVA_GEM_CREATE, drm_nova_gem_create, ioctl::AUTH | ioctl::RENDER_ALLOW, File::gem_create),
+ (NOVA_GEM_INFO, drm_nova_gem_info, ioctl::AUTH | ioctl::RENDER_ALLOW, File::gem_info),
+ }
+}
diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs
new file mode 100644
index 000000000..298c02bac
--- /dev/null
+++ b/drivers/gpu/drm/nova/file.rs
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use crate::driver::{NovaDevice, NovaDriver};
+use crate::gem::NovaObject;
+use kernel::{
+ alloc::flags::*,
+ auxiliary,
+ device::Bound,
+ drm::{
+ self,
+ gem::BaseObject,
+ Registered, //
+ },
+ pci,
+ prelude::*,
+ uapi,
+};
+
+pub(crate) struct File;
+
+impl drm::file::DriverFile for File {
+ type Driver = NovaDriver;
+
+ fn open(_dev: &NovaDevice) -> Result<Pin<KBox<Self>>> {
+ Ok(KBox::new(Self, GFP_KERNEL)?.into())
+ }
+}
+
+impl File {
+ /// IOCTL: get_param: Query GPU / driver metadata.
+ pub(crate) fn get_param(
+ dev: &NovaDevice<Registered>,
+ _reg_data: &(),
+ getparam: &mut uapi::drm_nova_getparam,
+ _file: &drm::File<File>,
+ ) -> Result<u32> {
+ let adev: &auxiliary::Device<Bound> = dev.as_ref();
+ let pdev: &pci::Device<Bound> = adev.parent().try_into()?;
+
+ let value = match getparam.param as u32 {
+ uapi::NOVA_GETPARAM_VRAM_BAR_SIZE => pdev.resource_len(1)?,
+ _ => return Err(EINVAL),
+ };
+
+ getparam.value = Into::<u64>::into(value);
+
+ Ok(0)
+ }
+
+ /// IOCTL: gem_create: Create a new DRM GEM object.
+ pub(crate) fn gem_create(
+ dev: &NovaDevice<Registered>,
+ _reg_data: &(),
+ req: &mut uapi::drm_nova_gem_create,
+ file: &drm::File<File>,
+ ) -> Result<u32> {
+ let obj = NovaObject::new(dev, req.size.try_into()?)?;
+
+ req.handle = obj.create_handle(file)?;
+
+ Ok(0)
+ }
+
+ /// IOCTL: gem_info: Query GEM metadata.
+ pub(crate) fn gem_info(
+ _dev: &NovaDevice<Registered>,
+ _reg_data: &(),
+ req: &mut uapi::drm_nova_gem_info,
+ file: &drm::File<File>,
+ ) -> Result<u32> {
+ let bo = NovaObject::lookup_handle(file, req.handle)?;
+
+ req.size = bo.size().try_into()?;
+
+ Ok(0)
+ }
+}
diff --git a/drivers/gpu/drm/nova/gem.rs b/drivers/gpu/drm/nova/gem.rs
new file mode 100644
index 000000000..2b6fe9dc0
--- /dev/null
+++ b/drivers/gpu/drm/nova/gem.rs
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use kernel::{
+ drm,
+ drm::{
+ gem,
+ gem::BaseObject, //
+ },
+ page,
+ prelude::*,
+ sync::aref::ARef,
+};
+
+use crate::{
+ driver::{NovaDevice, NovaDriver},
+ file::File,
+};
+
+/// GEM Object inner driver data
+#[pin_data]
+pub(crate) struct NovaObject {}
+
+impl gem::DriverObject for NovaObject {
+ type Driver = NovaDriver;
+ type Args = ();
+
+ fn new(_dev: &NovaDevice, _size: usize, _args: Self::Args) -> impl PinInit<Self, Error> {
+ try_pin_init!(NovaObject {})
+ }
+}
+
+impl NovaObject {
+ /// Create a new DRM GEM object.
+ pub(crate) fn new(dev: &NovaDevice, size: usize) -> Result<ARef<gem::Object<Self>>> {
+ if size == 0 {
+ return Err(EINVAL);
+ }
+ let aligned_size = page::page_align(size).ok_or(EINVAL)?;
+
+ gem::Object::<Self>::new(dev, aligned_size, ())
+ }
+
+ /// Look up a GEM object handle for a `File` and return an `ObjectRef` for it.
+ #[inline]
+ pub(crate) fn lookup_handle(
+ file: &drm::File<File>,
+ handle: u32,
+ ) -> Result<ARef<gem::Object<Self>>> {
+ gem::Object::lookup_handle(file, handle)
+ }
+}
diff --git a/drivers/gpu/drm/nova/nova.rs b/drivers/gpu/drm/nova/nova.rs
new file mode 100644
index 000000000..1fd454c7e
--- /dev/null
+++ b/drivers/gpu/drm/nova/nova.rs
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Nova DRM Driver
+
+mod driver;
+mod file;
+mod gem;
+
+use crate::driver::NovaDriver;
+
+kernel::module_auxiliary_driver! {
+ type: NovaDriver,
+ name: "nova-drm",
+ authors: ["Danilo Krummrich"],
+ description: "Nova GPU driver",
+ license: "GPL v2",
+}