xref: /linux/rust/kernel/drm/driver.rs (revision d317e4585fa39bcee4d075f5c485494b0f238713)
1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 
3 //! DRM driver core.
4 //!
5 //! C header: [`include/drm/drm_drv.h`](srctree/include/drm/drm_drv.h)
6 
7 use crate::{
8     bindings,
9     device,
10     devres,
11     drm,
12     error::to_result,
13     prelude::*,
14     sync::aref::ARef, //
15 };
16 use core::{
17     mem,
18     ptr::NonNull, //
19 };
20 
21 /// Driver use the GEM memory manager. This should be set for all modern drivers.
22 pub(crate) const FEAT_GEM: u32 = bindings::drm_driver_feature_DRIVER_GEM;
23 /// Driver supports render nodes, i.e.: /dev/dri/renderDXX devices.
24 pub(crate) const FEAT_RENDER: u32 = bindings::drm_driver_feature_DRIVER_RENDER;
25 
26 /// Information data for a DRM Driver.
27 pub struct DriverInfo {
28     /// Driver major version.
29     pub major: i32,
30     /// Driver minor version.
31     pub minor: i32,
32     /// Driver patchlevel version.
33     pub patchlevel: i32,
34     /// Driver name.
35     pub name: &'static CStr,
36     /// Driver description.
37     pub desc: &'static CStr,
38 }
39 
40 /// Internal memory management operation set, normally created by memory managers (e.g. GEM).
41 pub struct AllocOps {
42     pub(crate) gem_create_object: Option<
43         unsafe extern "C" fn(
44             dev: *mut bindings::drm_device,
45             size: usize,
46         ) -> *mut bindings::drm_gem_object,
47     >,
48     pub(crate) prime_handle_to_fd: Option<
49         unsafe extern "C" fn(
50             dev: *mut bindings::drm_device,
51             file_priv: *mut bindings::drm_file,
52             handle: u32,
53             flags: u32,
54             prime_fd: *mut core::ffi::c_int,
55         ) -> core::ffi::c_int,
56     >,
57     pub(crate) prime_fd_to_handle: Option<
58         unsafe extern "C" fn(
59             dev: *mut bindings::drm_device,
60             file_priv: *mut bindings::drm_file,
61             prime_fd: core::ffi::c_int,
62             handle: *mut u32,
63         ) -> core::ffi::c_int,
64     >,
65     pub(crate) gem_prime_import: Option<
66         unsafe extern "C" fn(
67             dev: *mut bindings::drm_device,
68             dma_buf: *mut bindings::dma_buf,
69         ) -> *mut bindings::drm_gem_object,
70     >,
71     pub(crate) gem_prime_import_sg_table: Option<
72         unsafe extern "C" fn(
73             dev: *mut bindings::drm_device,
74             attach: *mut bindings::dma_buf_attachment,
75             sgt: *mut bindings::sg_table,
76         ) -> *mut bindings::drm_gem_object,
77     >,
78     pub(crate) dumb_create: Option<
79         unsafe extern "C" fn(
80             file_priv: *mut bindings::drm_file,
81             dev: *mut bindings::drm_device,
82             args: *mut bindings::drm_mode_create_dumb,
83         ) -> core::ffi::c_int,
84     >,
85     pub(crate) dumb_map_offset: Option<
86         unsafe extern "C" fn(
87             file_priv: *mut bindings::drm_file,
88             dev: *mut bindings::drm_device,
89             handle: u32,
90             offset: *mut u64,
91         ) -> core::ffi::c_int,
92     >,
93 }
94 
95 /// Trait for memory manager implementations. Implemented internally.
96 pub trait AllocImpl: super::private::Sealed + drm::gem::IntoGEMObject {
97     /// The [`Driver`] implementation for this [`AllocImpl`].
98     type Driver: drm::Driver;
99 
100     /// The C callback operations for this memory manager.
101     const ALLOC_OPS: AllocOps;
102 }
103 
104 /// The DRM `Driver` trait.
105 ///
106 /// This trait must be implemented by drivers in order to create a `struct drm_device` and `struct
107 /// drm_driver` to be registered in the DRM subsystem.
108 #[vtable]
109 pub trait Driver {
110     /// Context data associated with the DRM driver
111     type Data: Sync + Send;
112 
113     /// The type used to manage memory for this driver.
114     type Object<Ctx: drm::DeviceContext>: AllocImpl;
115 
116     /// The type used to represent a DRM File (client)
117     type File: drm::file::DriverFile;
118 
119     /// Driver metadata
120     const INFO: DriverInfo;
121 
122     /// IOCTL list. See `kernel::drm::ioctl::declare_drm_ioctls!{}`.
123     const IOCTLS: &'static [drm::ioctl::DrmIoctlDescriptor];
124 
125     /// Sets the `DRIVER_RENDER` feature for this driver.
126     ///
127     /// When enabled, the driver exposes `/dev/dri/renderDXX` render nodes to
128     /// userspace. The render node is an alternate low-priviledge way to access
129     /// the driver, which is enforced on a per-ioctl level. Userspace processes
130     /// that open the render node can only invoke ioctls explicitly listed as
131     /// usable from the render node (i.e. marked DRM_RENDER_ALLOW), whereas
132     /// userspace processes using the master node can invoke any ioctl.
133     const FEAT_RENDER: bool = false;
134 }
135 
136 /// The registration type of a `drm::Device`.
137 ///
138 /// Once the `Registration` structure is dropped, the device is unregistered.
139 pub struct Registration<T: Driver>(ARef<drm::Device<T>>);
140 
141 impl<T: Driver> Registration<T> {
142     fn new(drm: drm::UnregisteredDevice<T>, flags: usize) -> Result<Self> {
143         // SAFETY: `drm.as_raw()` is valid by the invariants of `drm::Device`.
144         to_result(unsafe { bindings::drm_dev_register(drm.as_raw(), flags) })?;
145 
146         // SAFETY: We just called `drm_dev_register` above
147         let new = NonNull::from(unsafe { drm.assume_ctx() });
148 
149         // Leak the ARef from UnregisteredDevice in preparation for transferring its ownership.
150         mem::forget(drm);
151 
152         // SAFETY: `drm`'s `Drop` constructor was never called, ensuring that there remains at least
153         // one reference to the device - which we take ownership over here.
154         let new = unsafe { ARef::from_raw(new) };
155 
156         Ok(Self(new))
157     }
158 
159     /// Registers a new [`UnregisteredDevice`](drm::UnregisteredDevice) with userspace.
160     ///
161     /// Ownership of the [`Registration`] object is passed to [`devres::register`].
162     pub fn new_foreign_owned<'a>(
163         drm: drm::UnregisteredDevice<T>,
164         dev: &'a device::Device<device::Bound>,
165         flags: usize,
166     ) -> Result<&'a drm::Device<T>>
167     where
168         T: 'static,
169     {
170         if drm.as_ref().as_raw() != dev.as_raw() {
171             return Err(EINVAL);
172         }
173 
174         let reg = Registration::<T>::new(drm, flags)?;
175         let drm = NonNull::from(reg.device());
176 
177         devres::register(dev, reg, GFP_KERNEL)?;
178 
179         // SAFETY: Since `reg` was passed to devres::register(), the device now owns the lifetime
180         // of the DRM registration - ensuring that this references lives for at least as long as 'a.
181         Ok(unsafe { drm.as_ref() })
182     }
183 
184     /// Returns a reference to the `Device` instance for this registration.
185     pub fn device(&self) -> &drm::Device<T> {
186         &self.0
187     }
188 }
189 
190 // SAFETY: `Registration` doesn't offer any methods or access to fields when shared between
191 // threads, hence it's safe to share it.
192 unsafe impl<T: Driver> Sync for Registration<T> {}
193 
194 // SAFETY: Registration with and unregistration from the DRM subsystem can happen from any thread.
195 unsafe impl<T: Driver> Send for Registration<T> {}
196 
197 impl<T: Driver> Drop for Registration<T> {
198     fn drop(&mut self) {
199         // SAFETY: Safe by the invariant of `ARef<drm::Device<T>>`. The existence of this
200         // `Registration` also guarantees the this `drm::Device` is actually registered.
201         unsafe { bindings::drm_dev_unregister(self.0.as_raw()) };
202     }
203 }
204