Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'nova-next-v6.16-2025-05-20' of https://gitlab.freedesktop.org/drm/nova into drm-next

Nova changes for v6.16

auxiliary:
- bus abstractions
- implementation for driver registration
- add sample driver

drm:
- implement __drm_dev_alloc()
- DRM core infrastructure Rust abstractions
- device, driver and registration
- DRM IOCTL
- DRM File
- GEM object
- IntoGEMObject rework
- generically implement AlwaysRefCounted through IntoGEMObject
- refactor unsound from_gem_obj() into as_ref()
- refactor into_gem_obj() into as_raw()

driver-core:
- merge topic/device-context-2025-04-17 from driver-core tree
- implement Devres::access()
- fix: doctest build under `!CONFIG_PCI`
- accessor for Device::parent()
- fix: conditionally expect `dead_code` for `parent()`
- impl TryFrom<&Device> bus devices (PCI, platform)

nova-core:
- remove completed Vec extentions from task list
- register auxiliary device for nova-drm
- derive useful traits for Chipset
- add missing GA100 chipset
- take &Device<Bound> in Gpu::new()
- infrastructure to generate register definitions
- fix register layout of NV_PMC_BOOT_0
- move Firmware into own (Rust) module
- fix: select AUXILIARY_BUS

nova-drm:
- initial driver skeleton (depends on drm and auxiliary bus
abstractions)
- fix: select AUXILIARY_BUS

Rust (dependencies):
- implement Opaque::zeroed()
- implement Revocable::try_access_with()
- implement Revocable::access()

From: Danilo Krummrich <dakr@kernel.org>
Link: https://lore.kernel.org/r/aCxAf3RqQAXLDhAj@cassiopeiae

Dave Airlie c4f8ac09 7c1a9408

+2757 -192
+6 -10
Documentation/gpu/nova/core/todo.rst
··· 102 102 let boot0 = Boot0::read(&bar); 103 103 pr_info!("Revision: {}\n", boot0.revision()); 104 104 105 + Note: a work-in-progress implementation currently resides in 106 + `drivers/gpu/nova-core/regs/macros.rs` and is used in nova-core. It would be 107 + nice to improve it (possibly using proc macros) and move it to the `kernel` 108 + crate so it can be used by other components as well. 109 + 105 110 | Complexity: Advanced 111 + | Contact: Alexandre Courbot 106 112 107 113 Delay / Sleep abstractions 108 114 -------------------------- ··· 195 189 196 190 | Reference: Export GSP log buffers 197 191 | Complexity: Intermediate 198 - 199 - Vec extensions 200 - -------------- 201 - 202 - Implement ``Vec::truncate`` and ``Vec::resize``. 203 - 204 - Currently this is used for some experimental code to parse the vBIOS. 205 - 206 - | Reference vBIOS support 207 - | Complexity: Beginner 208 192 209 193 GPU (general) 210 194 =============
+17
MAINTAINERS
··· 3880 3880 F: Documentation/driver-api/auxiliary_bus.rst 3881 3881 F: drivers/base/auxiliary.c 3882 3882 F: include/linux/auxiliary_bus.h 3883 + F: rust/helpers/auxiliary.c 3884 + F: rust/kernel/auxiliary.rs 3885 + F: samples/rust/rust_driver_auxiliary.rs 3883 3886 3884 3887 AUXILIARY DISPLAY DRIVERS 3885 3888 M: Andy Shevchenko <andy@kernel.org> ··· 7610 7607 F: Documentation/gpu/nova/ 7611 7608 F: drivers/gpu/nova-core/ 7612 7609 7610 + DRM DRIVER FOR NVIDIA GPUS [RUST] 7611 + M: Danilo Krummrich <dakr@kernel.org> 7612 + L: nouveau@lists.freedesktop.org 7613 + S: Supported 7614 + Q: https://patchwork.freedesktop.org/project/nouveau/ 7615 + B: https://gitlab.freedesktop.org/drm/nova/-/issues 7616 + C: irc://irc.oftc.net/nouveau 7617 + T: git https://gitlab.freedesktop.org/drm/nova.git nova-next 7618 + F: Documentation/gpu/nova/ 7619 + F: drivers/gpu/drm/nova/ 7620 + F: include/uapi/drm/nova_drm.h 7621 + 7613 7622 DRM DRIVER FOR OLIMEX LCD-OLINUXINO PANELS 7614 7623 M: Stefan Mavrodiev <stefan@olimex.com> 7615 7624 S: Maintained ··· 7835 7820 F: Documentation/devicetree/bindings/gpu/ 7836 7821 F: Documentation/gpu/ 7837 7822 F: drivers/gpu/ 7823 + F: rust/kernel/drm/ 7838 7824 F: include/drm/ 7839 7825 F: include/linux/vga* 7840 7826 F: include/uapi/drm/ ··· 7852 7836 F: Documentation/gpu/ 7853 7837 F: drivers/gpu/drm/ 7854 7838 F: drivers/gpu/vga/ 7839 + F: rust/kernel/drm/ 7855 7840 F: include/drm/drm 7856 7841 F: include/linux/vga* 7857 7842 F: include/uapi/drm/
+2
drivers/gpu/drm/Kconfig
··· 274 274 275 275 source "drivers/gpu/drm/nouveau/Kconfig" 276 276 277 + source "drivers/gpu/drm/nova/Kconfig" 278 + 277 279 source "drivers/gpu/drm/i915/Kconfig" 278 280 279 281 source "drivers/gpu/drm/xe/Kconfig"
+1
drivers/gpu/drm/Makefile
··· 177 177 obj-$(CONFIG_DRM_VGEM) += vgem/ 178 178 obj-$(CONFIG_DRM_VKMS) += vkms/ 179 179 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/ 180 + obj-$(CONFIG_DRM_NOVA) += nova/ 180 181 obj-$(CONFIG_DRM_EXYNOS) +=exynos/ 181 182 obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/ 182 183 obj-$(CONFIG_DRM_GMA500) += gma500/
+42 -16
drivers/gpu/drm/drm_drv.c
··· 830 830 EXPORT_SYMBOL(__devm_drm_dev_alloc); 831 831 832 832 /** 833 + * __drm_dev_alloc - Allocation of a &drm_device instance 834 + * @parent: Parent device object 835 + * @driver: DRM driver 836 + * @size: the size of the struct which contains struct drm_device 837 + * @offset: the offset of the &drm_device within the container. 838 + * 839 + * This should *NOT* be by any drivers, but is a dedicated interface for the 840 + * corresponding Rust abstraction. 841 + * 842 + * This is the same as devm_drm_dev_alloc(), but without the corresponding 843 + * resource management through the parent device, but not the same as 844 + * drm_dev_alloc(), since the latter is the deprecated version, which does not 845 + * support subclassing. 846 + * 847 + * Returns: A pointer to new DRM device, or an ERR_PTR on failure. 848 + */ 849 + void *__drm_dev_alloc(struct device *parent, 850 + const struct drm_driver *driver, 851 + size_t size, size_t offset) 852 + { 853 + void *container; 854 + struct drm_device *drm; 855 + int ret; 856 + 857 + container = kzalloc(size, GFP_KERNEL); 858 + if (!container) 859 + return ERR_PTR(-ENOMEM); 860 + 861 + drm = container + offset; 862 + ret = drm_dev_init(drm, driver, parent); 863 + if (ret) { 864 + kfree(container); 865 + return ERR_PTR(ret); 866 + } 867 + drmm_add_final_kfree(drm, container); 868 + 869 + return container; 870 + } 871 + EXPORT_SYMBOL(__drm_dev_alloc); 872 + 873 + /** 833 874 * drm_dev_alloc - Allocate new DRM device 834 875 * @driver: DRM driver to allocate device for 835 876 * @parent: Parent device object ··· 885 844 struct drm_device *drm_dev_alloc(const struct drm_driver *driver, 886 845 struct device *parent) 887 846 { 888 - struct drm_device *dev; 889 - int ret; 890 - 891 - dev = kzalloc(sizeof(*dev), GFP_KERNEL); 892 - if (!dev) 893 - return ERR_PTR(-ENOMEM); 894 - 895 - ret = drm_dev_init(dev, driver, parent); 896 - if (ret) { 897 - kfree(dev); 898 - return ERR_PTR(ret); 899 - } 900 - 901 - drmm_add_final_kfree(dev, dev); 902 - 903 - return dev; 847 + return __drm_dev_alloc(parent, driver, sizeof(struct drm_device), 0); 904 848 } 905 849 EXPORT_SYMBOL(drm_dev_alloc); 906 850
+14
drivers/gpu/drm/nova/Kconfig
··· 1 + config DRM_NOVA 2 + tristate "Nova DRM driver" 3 + depends on DRM=y 4 + depends on PCI 5 + depends on RUST 6 + select AUXILIARY_BUS 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.
+3
drivers/gpu/drm/nova/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + obj-$(CONFIG_DRM_NOVA) += nova.o
+69
drivers/gpu/drm/nova/driver.rs
··· 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 + }
+74
drivers/gpu/drm/nova/file.rs
··· 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 + }
+49
drivers/gpu/drm/nova/gem.rs
··· 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 + }
+18
drivers/gpu/drm/nova/nova.rs
··· 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 + }
+61
drivers/gpu/drm/nova/uapi.rs
··· 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 + }
+1
drivers/gpu/nova-core/Kconfig
··· 3 3 depends on PCI 4 4 depends on RUST 5 5 depends on RUST_FW_LOADER_ABSTRACTIONS 6 + select AUXILIARY_BUS 6 7 default n 7 8 help 8 9 Choose this if you want to build the Nova Core driver for Nvidia
+8 -1
drivers/gpu/nova-core/driver.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 - use kernel::{bindings, c_str, device::Core, pci, prelude::*}; 3 + use kernel::{auxiliary, bindings, c_str, device::Core, pci, prelude::*}; 4 4 5 5 use crate::gpu::Gpu; 6 6 ··· 8 8 pub(crate) struct NovaCore { 9 9 #[pin] 10 10 pub(crate) gpu: Gpu, 11 + _reg: auxiliary::Registration, 11 12 } 12 13 13 14 const BAR0_SIZE: usize = 8; ··· 39 38 let this = KBox::pin_init( 40 39 try_pin_init!(Self { 41 40 gpu <- Gpu::new(pdev, bar)?, 41 + _reg: auxiliary::Registration::new( 42 + pdev.as_ref(), 43 + c_str!("nova-drm"), 44 + 0, // TODO: Once it lands, use XArray; for now we don't use the ID. 45 + crate::MODULE_NAME 46 + )?, 42 47 }), 43 48 GFP_KERNEL, 44 49 )?;
+40 -4
drivers/gpu/nova-core/firmware.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 - use crate::gpu; 3 + //! Contains structures and functions dedicated to the parsing, building and patching of firmwares 4 + //! to be loaded into a given execution unit. 5 + 6 + use kernel::device; 4 7 use kernel::firmware; 8 + use kernel::prelude::*; 9 + use kernel::str::CString; 10 + 11 + use crate::gpu; 12 + use crate::gpu::Chipset; 13 + 14 + pub(crate) const FIRMWARE_VERSION: &str = "535.113.01"; 15 + 16 + /// Structure encapsulating the firmware blobs required for the GPU to operate. 17 + #[expect(dead_code)] 18 + pub(crate) struct Firmware { 19 + booter_load: firmware::Firmware, 20 + booter_unload: firmware::Firmware, 21 + bootloader: firmware::Firmware, 22 + gsp: firmware::Firmware, 23 + } 24 + 25 + impl Firmware { 26 + pub(crate) fn new(dev: &device::Device, chipset: Chipset, ver: &str) -> Result<Firmware> { 27 + let mut chip_name = CString::try_from_fmt(fmt!("{}", chipset))?; 28 + chip_name.make_ascii_lowercase(); 29 + 30 + let request = |name_| { 31 + CString::try_from_fmt(fmt!("nvidia/{}/gsp/{}-{}.bin", &*chip_name, name_, ver)) 32 + .and_then(|path| firmware::Firmware::request(&path, dev)) 33 + }; 34 + 35 + Ok(Firmware { 36 + booter_load: request("booter_load")?, 37 + booter_unload: request("booter_unload")?, 38 + bootloader: request("bootloader")?, 39 + gsp: request("gsp")?, 40 + }) 41 + } 42 + } 5 43 6 44 pub(crate) struct ModInfoBuilder<const N: usize>(firmware::ModInfoBuilder<N>); 7 45 8 46 impl<const N: usize> ModInfoBuilder<N> { 9 - const VERSION: &'static str = "535.113.01"; 10 - 11 47 const fn make_entry_file(self, chipset: &str, fw: &str) -> Self { 12 48 ModInfoBuilder( 13 49 self.0 ··· 53 17 .push("/gsp/") 54 18 .push(fw) 55 19 .push("-") 56 - .push(Self::VERSION) 20 + .push(FIRMWARE_VERSION) 57 21 .push(".bin"), 58 22 ) 59 23 }
+39 -47
drivers/gpu/nova-core/gpu.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 - use kernel::{ 4 - device, devres::Devres, error::code::*, firmware, fmt, pci, prelude::*, str::CString, 5 - }; 3 + use kernel::{device, devres::Devres, error::code::*, pci, prelude::*}; 6 4 7 5 use crate::driver::Bar0; 6 + use crate::firmware::{Firmware, FIRMWARE_VERSION}; 8 7 use crate::regs; 9 8 use crate::util; 10 9 use core::fmt; ··· 12 13 ({ $($variant:ident = $value:expr),* $(,)* }) => 13 14 { 14 15 /// Enum representation of the GPU chipset. 15 - #[derive(fmt::Debug)] 16 + #[derive(fmt::Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] 16 17 pub(crate) enum Chipset { 17 18 $($variant = $value),*, 18 19 } ··· 53 54 TU117 = 0x167, 54 55 TU116 = 0x168, 55 56 // Ampere 57 + GA100 = 0x170, 56 58 GA102 = 0x172, 57 59 GA103 = 0x173, 58 60 GA104 = 0x174, ··· 73 73 Self::TU102 | Self::TU104 | Self::TU106 | Self::TU117 | Self::TU116 => { 74 74 Architecture::Turing 75 75 } 76 - Self::GA102 | Self::GA103 | Self::GA104 | Self::GA106 | Self::GA107 => { 76 + Self::GA100 | Self::GA102 | Self::GA103 | Self::GA104 | Self::GA106 | Self::GA107 => { 77 77 Architecture::Ampere 78 78 } 79 79 Self::AD102 | Self::AD103 | Self::AD104 | Self::AD106 | Self::AD107 => { ··· 100 100 /// Enum representation of the GPU generation. 101 101 #[derive(fmt::Debug)] 102 102 pub(crate) enum Architecture { 103 - Turing, 104 - Ampere, 105 - Ada, 103 + Turing = 0x16, 104 + Ampere = 0x17, 105 + Ada = 0x19, 106 + } 107 + 108 + impl TryFrom<u8> for Architecture { 109 + type Error = Error; 110 + 111 + fn try_from(value: u8) -> Result<Self> { 112 + match value { 113 + 0x16 => Ok(Self::Turing), 114 + 0x17 => Ok(Self::Ampere), 115 + 0x19 => Ok(Self::Ada), 116 + _ => Err(ENODEV), 117 + } 118 + } 106 119 } 107 120 108 121 pub(crate) struct Revision { ··· 124 111 } 125 112 126 113 impl Revision { 127 - fn from_boot0(boot0: regs::Boot0) -> Self { 114 + fn from_boot0(boot0: regs::NV_PMC_BOOT_0) -> Self { 128 115 Self { 129 - major: boot0.major_rev(), 130 - minor: boot0.minor_rev(), 116 + major: boot0.major_revision(), 117 + minor: boot0.minor_revision(), 131 118 } 132 119 } 133 120 } ··· 146 133 } 147 134 148 135 impl Spec { 149 - fn new(bar: &Devres<Bar0>) -> Result<Spec> { 150 - let bar = bar.try_access().ok_or(ENXIO)?; 151 - let boot0 = regs::Boot0::read(&bar); 136 + fn new(bar: &Bar0) -> Result<Spec> { 137 + let boot0 = regs::NV_PMC_BOOT_0::read(bar); 152 138 153 139 Ok(Self { 154 - chipset: boot0.chipset().try_into()?, 140 + chipset: boot0.chipset()?, 155 141 revision: Revision::from_boot0(boot0), 156 - }) 157 - } 158 - } 159 - 160 - /// Structure encapsulating the firmware blobs required for the GPU to operate. 161 - #[expect(dead_code)] 162 - pub(crate) struct Firmware { 163 - booter_load: firmware::Firmware, 164 - booter_unload: firmware::Firmware, 165 - bootloader: firmware::Firmware, 166 - gsp: firmware::Firmware, 167 - } 168 - 169 - impl Firmware { 170 - fn new(dev: &device::Device, spec: &Spec, ver: &str) -> Result<Firmware> { 171 - let mut chip_name = CString::try_from_fmt(fmt!("{}", spec.chipset))?; 172 - chip_name.make_ascii_lowercase(); 173 - 174 - let request = |name_| { 175 - CString::try_from_fmt(fmt!("nvidia/{}/gsp/{}-{}.bin", &*chip_name, name_, ver)) 176 - .and_then(|path| firmware::Firmware::request(&path, dev)) 177 - }; 178 - 179 - Ok(Firmware { 180 - booter_load: request("booter_load")?, 181 - booter_unload: request("booter_unload")?, 182 - bootloader: request("bootloader")?, 183 - gsp: request("gsp")?, 184 142 }) 185 143 } 186 144 } ··· 166 182 } 167 183 168 184 impl Gpu { 169 - pub(crate) fn new(pdev: &pci::Device, bar: Devres<Bar0>) -> Result<impl PinInit<Self>> { 170 - let spec = Spec::new(&bar)?; 171 - let fw = Firmware::new(pdev.as_ref(), &spec, "535.113.01")?; 185 + pub(crate) fn new( 186 + pdev: &pci::Device<device::Bound>, 187 + devres_bar: Devres<Bar0>, 188 + ) -> Result<impl PinInit<Self>> { 189 + let bar = devres_bar.access(pdev.as_ref())?; 190 + let spec = Spec::new(bar)?; 191 + let fw = Firmware::new(pdev.as_ref(), spec.chipset, FIRMWARE_VERSION)?; 172 192 173 193 dev_info!( 174 194 pdev.as_ref(), ··· 182 194 spec.revision 183 195 ); 184 196 185 - Ok(pin_init!(Self { spec, bar, fw })) 197 + Ok(pin_init!(Self { 198 + spec, 199 + bar: devres_bar, 200 + fw 201 + })) 186 202 } 187 203 }
+2
drivers/gpu/nova-core/nova_core.rs
··· 8 8 mod regs; 9 9 mod util; 10 10 11 + pub(crate) const MODULE_NAME: &kernel::str::CStr = <LocalModule as kernel::ModuleMetadata>::NAME; 12 + 11 13 kernel::module_pci_driver! { 12 14 type: driver::NovaCore, 13 15 name: "NovaCore",
+28 -44
drivers/gpu/nova-core/regs.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 - use crate::driver::Bar0; 3 + // Required to retain the original register names used by OpenRM, which are all capital snake case 4 + // but are mapped to types. 5 + #![allow(non_camel_case_types)] 4 6 5 - // TODO 6 - // 7 - // Create register definitions via generic macros. See task "Generic register 8 - // abstraction" in Documentation/gpu/nova/core/todo.rst. 7 + #[macro_use] 8 + mod macros; 9 9 10 - const BOOT0_OFFSET: usize = 0x00000000; 10 + use crate::gpu::{Architecture, Chipset}; 11 + use kernel::prelude::*; 11 12 12 - // 3:0 - chipset minor revision 13 - const BOOT0_MINOR_REV_SHIFT: u8 = 0; 14 - const BOOT0_MINOR_REV_MASK: u32 = 0x0000000f; 13 + /* PMC */ 15 14 16 - // 7:4 - chipset major revision 17 - const BOOT0_MAJOR_REV_SHIFT: u8 = 4; 18 - const BOOT0_MAJOR_REV_MASK: u32 = 0x000000f0; 15 + register!(NV_PMC_BOOT_0 @ 0x00000000, "Basic revision information about the GPU" { 16 + 3:0 minor_revision as u8, "Minor revision of the chip"; 17 + 7:4 major_revision as u8, "Major revision of the chip"; 18 + 8:8 architecture_1 as u8, "MSB of the architecture"; 19 + 23:20 implementation as u8, "Implementation version of the architecture"; 20 + 28:24 architecture_0 as u8, "Lower bits of the architecture"; 21 + }); 19 22 20 - // 23:20 - chipset implementation Identifier (depends on architecture) 21 - const BOOT0_IMPL_SHIFT: u8 = 20; 22 - const BOOT0_IMPL_MASK: u32 = 0x00f00000; 23 - 24 - // 28:24 - chipset architecture identifier 25 - const BOOT0_ARCH_MASK: u32 = 0x1f000000; 26 - 27 - // 28:20 - chipset identifier (virtual register field combining BOOT0_IMPL and 28 - // BOOT0_ARCH) 29 - const BOOT0_CHIPSET_SHIFT: u8 = BOOT0_IMPL_SHIFT; 30 - const BOOT0_CHIPSET_MASK: u32 = BOOT0_IMPL_MASK | BOOT0_ARCH_MASK; 31 - 32 - #[derive(Copy, Clone)] 33 - pub(crate) struct Boot0(u32); 34 - 35 - impl Boot0 { 36 - #[inline] 37 - pub(crate) fn read(bar: &Bar0) -> Self { 38 - Self(bar.read32(BOOT0_OFFSET)) 23 + impl NV_PMC_BOOT_0 { 24 + /// Combines `architecture_0` and `architecture_1` to obtain the architecture of the chip. 25 + pub(crate) fn architecture(self) -> Result<Architecture> { 26 + Architecture::try_from( 27 + self.architecture_0() | (self.architecture_1() << Self::ARCHITECTURE_0.len()), 28 + ) 39 29 } 40 30 41 - #[inline] 42 - pub(crate) fn chipset(&self) -> u32 { 43 - (self.0 & BOOT0_CHIPSET_MASK) >> BOOT0_CHIPSET_SHIFT 44 - } 45 - 46 - #[inline] 47 - pub(crate) fn minor_rev(&self) -> u8 { 48 - ((self.0 & BOOT0_MINOR_REV_MASK) >> BOOT0_MINOR_REV_SHIFT) as u8 49 - } 50 - 51 - #[inline] 52 - pub(crate) fn major_rev(&self) -> u8 { 53 - ((self.0 & BOOT0_MAJOR_REV_MASK) >> BOOT0_MAJOR_REV_SHIFT) as u8 31 + /// Combines `architecture` and `implementation` to obtain a code unique to the chipset. 32 + pub(crate) fn chipset(self) -> Result<Chipset> { 33 + self.architecture() 34 + .map(|arch| { 35 + ((arch as u32) << Self::IMPLEMENTATION.len()) | self.implementation() as u32 36 + }) 37 + .and_then(Chipset::try_from) 54 38 } 55 39 }
+380
drivers/gpu/nova-core/regs/macros.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Macro to define register layout and accessors. 4 + //! 5 + //! A single register typically includes several fields, which are accessed through a combination 6 + //! of bit-shift and mask operations that introduce a class of potential mistakes, notably because 7 + //! not all possible field values are necessarily valid. 8 + //! 9 + //! The macro in this module allow to define, using an intruitive and readable syntax, a dedicated 10 + //! type for each register with its own field accessors that can return an error is a field's value 11 + //! is invalid. 12 + 13 + /// Defines a dedicated type for a register with an absolute offset, alongside with getter and 14 + /// setter methods for its fields and methods to read and write it from an `Io` region. 15 + /// 16 + /// Example: 17 + /// 18 + /// ```no_run 19 + /// register!(BOOT_0 @ 0x00000100, "Basic revision information about the GPU" { 20 + /// 3:0 minor_revision as u8, "Minor revision of the chip"; 21 + /// 7:4 major_revision as u8, "Major revision of the chip"; 22 + /// 28:20 chipset as u32 ?=> Chipset, "Chipset model"; 23 + /// }); 24 + /// ``` 25 + /// 26 + /// This defines a `BOOT_0` type which can be read or written from offset `0x100` of an `Io` 27 + /// region. It is composed of 3 fields, for instance `minor_revision` is made of the 4 less 28 + /// significant bits of the register. Each field can be accessed and modified using accessor 29 + /// methods: 30 + /// 31 + /// ```no_run 32 + /// // Read from the register's defined offset (0x100). 33 + /// let boot0 = BOOT_0::read(&bar); 34 + /// pr_info!("chip revision: {}.{}", boot0.major_revision(), boot0.minor_revision()); 35 + /// 36 + /// // `Chipset::try_from` will be called with the value of the field and returns an error if the 37 + /// // value is invalid. 38 + /// let chipset = boot0.chipset()?; 39 + /// 40 + /// // Update some fields and write the value back. 41 + /// boot0.set_major_revision(3).set_minor_revision(10).write(&bar); 42 + /// 43 + /// // Or just read and update the register in a single step: 44 + /// BOOT_0::alter(&bar, |r| r.set_major_revision(3).set_minor_revision(10)); 45 + /// ``` 46 + /// 47 + /// Fields can be defined as follows: 48 + /// 49 + /// - `as <type>` simply returns the field value casted as the requested integer type, typically 50 + /// `u32`, `u16`, `u8` or `bool`. Note that `bool` fields must have a range of 1 bit. 51 + /// - `as <type> => <into_type>` calls `<into_type>`'s `From::<<type>>` implementation and returns 52 + /// the result. 53 + /// - `as <type> ?=> <try_into_type>` calls `<try_into_type>`'s `TryFrom::<<type>>` implementation 54 + /// and returns the result. This is useful on fields for which not all values are value. 55 + /// 56 + /// The documentation strings are optional. If present, they will be added to the type's 57 + /// definition, or the field getter and setter methods they are attached to. 58 + /// 59 + /// Putting a `+` before the address of the register makes it relative to a base: the `read` and 60 + /// `write` methods take a `base` argument that is added to the specified address before access, 61 + /// and `try_read` and `try_write` methods are also created, allowing access with offsets unknown 62 + /// at compile-time: 63 + /// 64 + /// ```no_run 65 + /// register!(CPU_CTL @ +0x0000010, "CPU core control" { 66 + /// 0:0 start as bool, "Start the CPU core"; 67 + /// }); 68 + /// 69 + /// // Flip the `start` switch for the CPU core which base address is at `CPU_BASE`. 70 + /// let cpuctl = CPU_CTL::read(&bar, CPU_BASE); 71 + /// pr_info!("CPU CTL: {:#x}", cpuctl); 72 + /// cpuctl.set_start(true).write(&bar, CPU_BASE); 73 + /// ``` 74 + macro_rules! register { 75 + // Creates a register at a fixed offset of the MMIO space. 76 + ( 77 + $name:ident @ $offset:literal $(, $comment:literal)? { 78 + $($fields:tt)* 79 + } 80 + ) => { 81 + register!(@common $name $(, $comment)?); 82 + register!(@field_accessors $name { $($fields)* }); 83 + register!(@io $name @ $offset); 84 + }; 85 + 86 + // Creates a register at a relative offset from a base address. 87 + ( 88 + $name:ident @ + $offset:literal $(, $comment:literal)? { 89 + $($fields:tt)* 90 + } 91 + ) => { 92 + register!(@common $name $(, $comment)?); 93 + register!(@field_accessors $name { $($fields)* }); 94 + register!(@io$name @ + $offset); 95 + }; 96 + 97 + // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, `BitOr`, 98 + // and conversion to regular `u32`). 99 + (@common $name:ident $(, $comment:literal)?) => { 100 + $( 101 + #[doc=$comment] 102 + )? 103 + #[repr(transparent)] 104 + #[derive(Clone, Copy, Default)] 105 + pub(crate) struct $name(u32); 106 + 107 + // TODO: display the raw hex value, then the value of all the fields. This requires 108 + // matching the fields, which will complexify the syntax considerably... 109 + impl ::core::fmt::Debug for $name { 110 + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 111 + f.debug_tuple(stringify!($name)) 112 + .field(&format_args!("0x{0:x}", &self.0)) 113 + .finish() 114 + } 115 + } 116 + 117 + impl core::ops::BitOr for $name { 118 + type Output = Self; 119 + 120 + fn bitor(self, rhs: Self) -> Self::Output { 121 + Self(self.0 | rhs.0) 122 + } 123 + } 124 + 125 + impl ::core::convert::From<$name> for u32 { 126 + fn from(reg: $name) -> u32 { 127 + reg.0 128 + } 129 + } 130 + }; 131 + 132 + // Defines all the field getter/methods methods for `$name`. 133 + ( 134 + @field_accessors $name:ident { 135 + $($hi:tt:$lo:tt $field:ident as $type:tt 136 + $(?=> $try_into_type:ty)? 137 + $(=> $into_type:ty)? 138 + $(, $comment:literal)? 139 + ; 140 + )* 141 + } 142 + ) => { 143 + $( 144 + register!(@check_field_bounds $hi:$lo $field as $type); 145 + )* 146 + 147 + #[allow(dead_code)] 148 + impl $name { 149 + $( 150 + register!(@field_accessor $name $hi:$lo $field as $type 151 + $(?=> $try_into_type)? 152 + $(=> $into_type)? 153 + $(, $comment)? 154 + ; 155 + ); 156 + )* 157 + } 158 + }; 159 + 160 + // Boolean fields must have `$hi == $lo`. 161 + (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => { 162 + #[allow(clippy::eq_op)] 163 + const _: () = { 164 + kernel::build_assert!( 165 + $hi == $lo, 166 + concat!("boolean field `", stringify!($field), "` covers more than one bit") 167 + ); 168 + }; 169 + }; 170 + 171 + // Non-boolean fields must have `$hi >= $lo`. 172 + (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => { 173 + #[allow(clippy::eq_op)] 174 + const _: () = { 175 + kernel::build_assert!( 176 + $hi >= $lo, 177 + concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB") 178 + ); 179 + }; 180 + }; 181 + 182 + // Catches fields defined as `bool` and convert them into a boolean value. 183 + ( 184 + @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool => $into_type:ty 185 + $(, $comment:literal)?; 186 + ) => { 187 + register!( 188 + @leaf_accessor $name $hi:$lo $field as bool 189 + { |f| <$into_type>::from(if f != 0 { true } else { false }) } 190 + $into_type => $into_type $(, $comment)?; 191 + ); 192 + }; 193 + 194 + // Shortcut for fields defined as `bool` without the `=>` syntax. 195 + ( 196 + @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?; 197 + ) => { 198 + register!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;); 199 + }; 200 + 201 + // Catches the `?=>` syntax for non-boolean fields. 202 + ( 203 + @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty 204 + $(, $comment:literal)?; 205 + ) => { 206 + register!(@leaf_accessor $name $hi:$lo $field as $type 207 + { |f| <$try_into_type>::try_from(f as $type) } $try_into_type => 208 + ::core::result::Result< 209 + $try_into_type, 210 + <$try_into_type as ::core::convert::TryFrom<$type>>::Error 211 + > 212 + $(, $comment)?;); 213 + }; 214 + 215 + // Catches the `=>` syntax for non-boolean fields. 216 + ( 217 + @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty 218 + $(, $comment:literal)?; 219 + ) => { 220 + register!(@leaf_accessor $name $hi:$lo $field as $type 221 + { |f| <$into_type>::from(f as $type) } $into_type => $into_type $(, $comment)?;); 222 + }; 223 + 224 + // Shortcut for fields defined as non-`bool` without the `=>` or `?=>` syntax. 225 + ( 226 + @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt 227 + $(, $comment:literal)?; 228 + ) => { 229 + register!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;); 230 + }; 231 + 232 + // Generates the accessor methods for a single field. 233 + ( 234 + @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:ty 235 + { $process:expr } $to_type:ty => $res_type:ty $(, $comment:literal)?; 236 + ) => { 237 + kernel::macros::paste!( 238 + const [<$field:upper>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi; 239 + const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); 240 + const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros(); 241 + ); 242 + 243 + $( 244 + #[doc="Returns the value of this field:"] 245 + #[doc=$comment] 246 + )? 247 + #[inline] 248 + pub(crate) fn $field(self) -> $res_type { 249 + kernel::macros::paste!( 250 + const MASK: u32 = $name::[<$field:upper _MASK>]; 251 + const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; 252 + ); 253 + let field = ((self.0 & MASK) >> SHIFT); 254 + 255 + $process(field) 256 + } 257 + 258 + kernel::macros::paste!( 259 + $( 260 + #[doc="Sets the value of this field:"] 261 + #[doc=$comment] 262 + )? 263 + #[inline] 264 + pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self { 265 + const MASK: u32 = $name::[<$field:upper _MASK>]; 266 + const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; 267 + let value = ((value as u32) << SHIFT) & MASK; 268 + self.0 = (self.0 & !MASK) | value; 269 + 270 + self 271 + } 272 + ); 273 + }; 274 + 275 + // Creates the IO accessors for a fixed offset register. 276 + (@io $name:ident @ $offset:literal) => { 277 + #[allow(dead_code)] 278 + impl $name { 279 + #[inline] 280 + pub(crate) fn read<const SIZE: usize, T>(io: &T) -> Self where 281 + T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 282 + { 283 + Self(io.read32($offset)) 284 + } 285 + 286 + #[inline] 287 + pub(crate) fn write<const SIZE: usize, T>(self, io: &T) where 288 + T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 289 + { 290 + io.write32(self.0, $offset) 291 + } 292 + 293 + #[inline] 294 + pub(crate) fn alter<const SIZE: usize, T, F>( 295 + io: &T, 296 + f: F, 297 + ) where 298 + T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 299 + F: ::core::ops::FnOnce(Self) -> Self, 300 + { 301 + let reg = f(Self::read(io)); 302 + reg.write(io); 303 + } 304 + } 305 + }; 306 + 307 + // Create the IO accessors for a relative offset register. 308 + (@io $name:ident @ + $offset:literal) => { 309 + #[allow(dead_code)] 310 + impl $name { 311 + #[inline] 312 + pub(crate) fn read<const SIZE: usize, T>( 313 + io: &T, 314 + base: usize, 315 + ) -> Self where 316 + T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 317 + { 318 + Self(io.read32(base + $offset)) 319 + } 320 + 321 + #[inline] 322 + pub(crate) fn write<const SIZE: usize, T>( 323 + self, 324 + io: &T, 325 + base: usize, 326 + ) where 327 + T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 328 + { 329 + io.write32(self.0, base + $offset) 330 + } 331 + 332 + #[inline] 333 + pub(crate) fn alter<const SIZE: usize, T, F>( 334 + io: &T, 335 + base: usize, 336 + f: F, 337 + ) where 338 + T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 339 + F: ::core::ops::FnOnce(Self) -> Self, 340 + { 341 + let reg = f(Self::read(io, base)); 342 + reg.write(io, base); 343 + } 344 + 345 + #[inline] 346 + pub(crate) fn try_read<const SIZE: usize, T>( 347 + io: &T, 348 + base: usize, 349 + ) -> ::kernel::error::Result<Self> where 350 + T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 351 + { 352 + io.try_read32(base + $offset).map(Self) 353 + } 354 + 355 + #[inline] 356 + pub(crate) fn try_write<const SIZE: usize, T>( 357 + self, 358 + io: &T, 359 + base: usize, 360 + ) -> ::kernel::error::Result<()> where 361 + T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 362 + { 363 + io.try_write32(self.0, base + $offset) 364 + } 365 + 366 + #[inline] 367 + pub(crate) fn try_alter<const SIZE: usize, T, F>( 368 + io: &T, 369 + base: usize, 370 + f: F, 371 + ) -> ::kernel::error::Result<()> where 372 + T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 373 + F: ::core::ops::FnOnce(Self) -> Self, 374 + { 375 + let reg = f(Self::try_read(io, base)?); 376 + reg.try_write(io, base) 377 + } 378 + } 379 + }; 380 + }
+5
include/drm/drm_drv.h
··· 473 473 474 474 struct drm_device *drm_dev_alloc(const struct drm_driver *driver, 475 475 struct device *parent); 476 + 477 + void *__drm_dev_alloc(struct device *parent, 478 + const struct drm_driver *driver, 479 + size_t size, size_t offset); 480 + 476 481 int drm_dev_register(struct drm_device *dev, unsigned long flags); 477 482 void drm_dev_unregister(struct drm_device *dev); 478 483
+101
include/uapi/drm/nova_drm.h
··· 1 + /* SPDX-License-Identifier: MIT */ 2 + 3 + #ifndef __NOVA_DRM_H__ 4 + #define __NOVA_DRM_H__ 5 + 6 + #include "drm.h" 7 + 8 + /* DISCLAIMER: Do not use, this is not a stable uAPI. 9 + * 10 + * This uAPI serves only testing purposes as long as this driver is still in 11 + * development. It is required to implement and test infrastructure which is 12 + * upstreamed in the context of this driver. See also [1]. 13 + * 14 + * [1] https://lore.kernel.org/dri-devel/Zfsj0_tb-0-tNrJy@cassiopeiae/T/#u 15 + */ 16 + 17 + #if defined(__cplusplus) 18 + extern "C" { 19 + #endif 20 + 21 + /* 22 + * NOVA_GETPARAM_VRAM_BAR_SIZE 23 + * 24 + * Query the VRAM BAR size in bytes. 25 + */ 26 + #define NOVA_GETPARAM_VRAM_BAR_SIZE 0x1 27 + 28 + /** 29 + * struct drm_nova_getparam - query GPU and driver metadata 30 + */ 31 + struct drm_nova_getparam { 32 + /** 33 + * @param: The identifier of the parameter to query. 34 + */ 35 + __u64 param; 36 + 37 + /** 38 + * @value: The value for the specified parameter. 39 + */ 40 + __u64 value; 41 + }; 42 + 43 + /** 44 + * struct drm_nova_gem_create - create a new DRM GEM object 45 + */ 46 + struct drm_nova_gem_create { 47 + /** 48 + * @handle: The handle of the new DRM GEM object. 49 + */ 50 + __u32 handle; 51 + 52 + /** 53 + * @pad: 32 bit padding, should be 0. 54 + */ 55 + __u32 pad; 56 + 57 + /** 58 + * @size: The size of the new DRM GEM object. 59 + */ 60 + __u64 size; 61 + }; 62 + 63 + /** 64 + * struct drm_nova_gem_info - query DRM GEM object metadata 65 + */ 66 + struct drm_nova_gem_info { 67 + /** 68 + * @handle: The handle of the DRM GEM object to query. 69 + */ 70 + __u32 handle; 71 + 72 + /** 73 + * @pad: 32 bit padding, should be 0. 74 + */ 75 + __u32 pad; 76 + 77 + /** 78 + * @size: The size of the DRM GEM obejct. 79 + */ 80 + __u64 size; 81 + }; 82 + 83 + #define DRM_NOVA_GETPARAM 0x00 84 + #define DRM_NOVA_GEM_CREATE 0x01 85 + #define DRM_NOVA_GEM_INFO 0x02 86 + 87 + /* Note: this is an enum so that it can be resolved by Rust bindgen. */ 88 + enum { 89 + DRM_IOCTL_NOVA_GETPARAM = DRM_IOWR(DRM_COMMAND_BASE + DRM_NOVA_GETPARAM, 90 + struct drm_nova_getparam), 91 + DRM_IOCTL_NOVA_GEM_CREATE = DRM_IOWR(DRM_COMMAND_BASE + DRM_NOVA_GEM_CREATE, 92 + struct drm_nova_gem_create), 93 + DRM_IOCTL_NOVA_GEM_INFO = DRM_IOWR(DRM_COMMAND_BASE + DRM_NOVA_GEM_INFO, 94 + struct drm_nova_gem_info), 95 + }; 96 + 97 + #if defined(__cplusplus) 98 + } 99 + #endif 100 + 101 + #endif /* __NOVA_DRM_H__ */
+7
rust/bindings/bindings_helper.h
··· 6 6 * Sorted alphabetically. 7 7 */ 8 8 9 + #include <drm/drm_device.h> 10 + #include <drm/drm_drv.h> 11 + #include <drm/drm_file.h> 12 + #include <drm/drm_gem.h> 13 + #include <drm/drm_ioctl.h> 9 14 #include <kunit/test.h> 15 + #include <linux/auxiliary_bus.h> 10 16 #include <linux/blk-mq.h> 11 17 #include <linux/blk_types.h> 12 18 #include <linux/blkdev.h> ··· 61 55 const gfp_t RUST_CONST_HELPER___GFP_HIGHMEM = ___GFP_HIGHMEM; 62 56 const gfp_t RUST_CONST_HELPER___GFP_NOWARN = ___GFP_NOWARN; 63 57 const blk_features_t RUST_CONST_HELPER_BLK_FEAT_ROTATIONAL = BLK_FEAT_ROTATIONAL; 58 + const fop_flags_t RUST_CONST_HELPER_FOP_UNSIGNED_OFFSET = FOP_UNSIGNED_OFFSET;
+23
rust/helpers/auxiliary.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/auxiliary_bus.h> 4 + 5 + void rust_helper_auxiliary_set_drvdata(struct auxiliary_device *adev, void *data) 6 + { 7 + auxiliary_set_drvdata(adev, data); 8 + } 9 + 10 + void *rust_helper_auxiliary_get_drvdata(struct auxiliary_device *adev) 11 + { 12 + return auxiliary_get_drvdata(adev); 13 + } 14 + 15 + void rust_helper_auxiliary_device_uninit(struct auxiliary_device *adev) 16 + { 17 + return auxiliary_device_uninit(adev); 18 + } 19 + 20 + void rust_helper_auxiliary_device_delete(struct auxiliary_device *adev) 21 + { 22 + return auxiliary_device_delete(adev); 23 + }
+23
rust/helpers/drm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <drm/drm_gem.h> 4 + #include <drm/drm_vma_manager.h> 5 + 6 + #ifdef CONFIG_DRM 7 + 8 + void rust_helper_drm_gem_object_get(struct drm_gem_object *obj) 9 + { 10 + drm_gem_object_get(obj); 11 + } 12 + 13 + void rust_helper_drm_gem_object_put(struct drm_gem_object *obj) 14 + { 15 + drm_gem_object_put(obj); 16 + } 17 + 18 + __u64 rust_helper_drm_vma_node_offset_addr(struct drm_vma_offset_node *node) 19 + { 20 + return drm_vma_node_offset_addr(node); 21 + } 22 + 23 + #endif
+2
rust/helpers/helpers.c
··· 7 7 * Sorted alphabetically. 8 8 */ 9 9 10 + #include "auxiliary.c" 10 11 #include "blk.c" 11 12 #include "bug.c" 12 13 #include "build_assert.c" ··· 16 15 #include "cred.c" 17 16 #include "device.c" 18 17 #include "dma.c" 18 + #include "drm.c" 19 19 #include "err.c" 20 20 #include "fs.c" 21 21 #include "io.c"
+5
rust/helpers/pci.c
··· 16 16 { 17 17 return pci_resource_len(pdev, bar); 18 18 } 19 + 20 + bool rust_helper_dev_is_pci(const struct device *dev) 21 + { 22 + return dev_is_pci(dev); 23 + }
+5
rust/helpers/platform.c
··· 11 11 { 12 12 platform_set_drvdata(pdev, data); 13 13 } 14 + 15 + bool rust_helper_dev_is_platform(const struct device *dev) 16 + { 17 + return dev_is_platform(dev); 18 + }
+360
rust/kernel/auxiliary.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Abstractions for the auxiliary bus. 4 + //! 5 + //! C header: [`include/linux/auxiliary_bus.h`](srctree/include/linux/auxiliary_bus.h) 6 + 7 + use crate::{ 8 + bindings, container_of, device, 9 + device_id::RawDeviceId, 10 + driver, 11 + error::{to_result, Result}, 12 + prelude::*, 13 + str::CStr, 14 + types::{ForeignOwnable, Opaque}, 15 + ThisModule, 16 + }; 17 + use core::{ 18 + marker::PhantomData, 19 + ptr::{addr_of_mut, NonNull}, 20 + }; 21 + 22 + /// An adapter for the registration of auxiliary drivers. 23 + pub struct Adapter<T: Driver>(T); 24 + 25 + // SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if 26 + // a preceding call to `register` has been successful. 27 + unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { 28 + type RegType = bindings::auxiliary_driver; 29 + 30 + unsafe fn register( 31 + adrv: &Opaque<Self::RegType>, 32 + name: &'static CStr, 33 + module: &'static ThisModule, 34 + ) -> Result { 35 + // SAFETY: It's safe to set the fields of `struct auxiliary_driver` on initialization. 36 + unsafe { 37 + (*adrv.get()).name = name.as_char_ptr(); 38 + (*adrv.get()).probe = Some(Self::probe_callback); 39 + (*adrv.get()).remove = Some(Self::remove_callback); 40 + (*adrv.get()).id_table = T::ID_TABLE.as_ptr(); 41 + } 42 + 43 + // SAFETY: `adrv` is guaranteed to be a valid `RegType`. 44 + to_result(unsafe { 45 + bindings::__auxiliary_driver_register(adrv.get(), module.0, name.as_char_ptr()) 46 + }) 47 + } 48 + 49 + unsafe fn unregister(adrv: &Opaque<Self::RegType>) { 50 + // SAFETY: `adrv` is guaranteed to be a valid `RegType`. 51 + unsafe { bindings::auxiliary_driver_unregister(adrv.get()) } 52 + } 53 + } 54 + 55 + impl<T: Driver + 'static> Adapter<T> { 56 + extern "C" fn probe_callback( 57 + adev: *mut bindings::auxiliary_device, 58 + id: *const bindings::auxiliary_device_id, 59 + ) -> kernel::ffi::c_int { 60 + // SAFETY: The auxiliary bus only ever calls the probe callback with a valid pointer to a 61 + // `struct auxiliary_device`. 62 + // 63 + // INVARIANT: `adev` is valid for the duration of `probe_callback()`. 64 + let adev = unsafe { &*adev.cast::<Device<device::Core>>() }; 65 + 66 + // SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `struct auxiliary_device_id` 67 + // and does not add additional invariants, so it's safe to transmute. 68 + let id = unsafe { &*id.cast::<DeviceId>() }; 69 + let info = T::ID_TABLE.info(id.index()); 70 + 71 + match T::probe(adev, info) { 72 + Ok(data) => { 73 + // Let the `struct auxiliary_device` own a reference of the driver's private data. 74 + // SAFETY: By the type invariant `adev.as_raw` returns a valid pointer to a 75 + // `struct auxiliary_device`. 76 + unsafe { bindings::auxiliary_set_drvdata(adev.as_raw(), data.into_foreign()) }; 77 + } 78 + Err(err) => return Error::to_errno(err), 79 + } 80 + 81 + 0 82 + } 83 + 84 + extern "C" fn remove_callback(adev: *mut bindings::auxiliary_device) { 85 + // SAFETY: The auxiliary bus only ever calls the remove callback with a valid pointer to a 86 + // `struct auxiliary_device`. 87 + let ptr = unsafe { bindings::auxiliary_get_drvdata(adev) }; 88 + 89 + // SAFETY: `remove_callback` is only ever called after a successful call to 90 + // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized 91 + // `KBox<T>` pointer created through `KBox::into_foreign`. 92 + drop(unsafe { KBox::<T>::from_foreign(ptr) }); 93 + } 94 + } 95 + 96 + /// Declares a kernel module that exposes a single auxiliary driver. 97 + #[macro_export] 98 + macro_rules! module_auxiliary_driver { 99 + ($($f:tt)*) => { 100 + $crate::module_driver!(<T>, $crate::auxiliary::Adapter<T>, { $($f)* }); 101 + }; 102 + } 103 + 104 + /// Abstraction for `bindings::auxiliary_device_id`. 105 + #[repr(transparent)] 106 + #[derive(Clone, Copy)] 107 + pub struct DeviceId(bindings::auxiliary_device_id); 108 + 109 + impl DeviceId { 110 + /// Create a new [`DeviceId`] from name. 111 + pub const fn new(modname: &'static CStr, name: &'static CStr) -> Self { 112 + let name = name.as_bytes_with_nul(); 113 + let modname = modname.as_bytes_with_nul(); 114 + 115 + // TODO: Replace with `bindings::auxiliary_device_id::default()` once stabilized for 116 + // `const`. 117 + // 118 + // SAFETY: FFI type is valid to be zero-initialized. 119 + let mut id: bindings::auxiliary_device_id = unsafe { core::mem::zeroed() }; 120 + 121 + let mut i = 0; 122 + while i < modname.len() { 123 + id.name[i] = modname[i]; 124 + i += 1; 125 + } 126 + 127 + // Reuse the space of the NULL terminator. 128 + id.name[i - 1] = b'.'; 129 + 130 + let mut j = 0; 131 + while j < name.len() { 132 + id.name[i] = name[j]; 133 + i += 1; 134 + j += 1; 135 + } 136 + 137 + Self(id) 138 + } 139 + } 140 + 141 + // SAFETY: 142 + // * `DeviceId` is a `#[repr(transparent)`] wrapper of `auxiliary_device_id` and does not add 143 + // additional invariants, so it's safe to transmute to `RawType`. 144 + // * `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. 145 + unsafe impl RawDeviceId for DeviceId { 146 + type RawType = bindings::auxiliary_device_id; 147 + 148 + const DRIVER_DATA_OFFSET: usize = 149 + core::mem::offset_of!(bindings::auxiliary_device_id, driver_data); 150 + 151 + fn index(&self) -> usize { 152 + self.0.driver_data 153 + } 154 + } 155 + 156 + /// IdTable type for auxiliary drivers. 157 + pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>; 158 + 159 + /// Create a auxiliary `IdTable` with its alias for modpost. 160 + #[macro_export] 161 + macro_rules! auxiliary_device_table { 162 + ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => { 163 + const $table_name: $crate::device_id::IdArray< 164 + $crate::auxiliary::DeviceId, 165 + $id_info_type, 166 + { $table_data.len() }, 167 + > = $crate::device_id::IdArray::new($table_data); 168 + 169 + $crate::module_device_table!("auxiliary", $module_table_name, $table_name); 170 + }; 171 + } 172 + 173 + /// The auxiliary driver trait. 174 + /// 175 + /// Drivers must implement this trait in order to get an auxiliary driver registered. 176 + pub trait Driver { 177 + /// The type holding information about each device id supported by the driver. 178 + /// 179 + /// TODO: Use associated_type_defaults once stabilized: 180 + /// 181 + /// type IdInfo: 'static = (); 182 + type IdInfo: 'static; 183 + 184 + /// The table of device ids supported by the driver. 185 + const ID_TABLE: IdTable<Self::IdInfo>; 186 + 187 + /// Auxiliary driver probe. 188 + /// 189 + /// Called when an auxiliary device is matches a corresponding driver. 190 + fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> Result<Pin<KBox<Self>>>; 191 + } 192 + 193 + /// The auxiliary device representation. 194 + /// 195 + /// This structure represents the Rust abstraction for a C `struct auxiliary_device`. The 196 + /// implementation abstracts the usage of an already existing C `struct auxiliary_device` within 197 + /// Rust code that we get passed from the C side. 198 + /// 199 + /// # Invariants 200 + /// 201 + /// A [`Device`] instance represents a valid `struct auxiliary_device` created by the C portion of 202 + /// the kernel. 203 + #[repr(transparent)] 204 + pub struct Device<Ctx: device::DeviceContext = device::Normal>( 205 + Opaque<bindings::auxiliary_device>, 206 + PhantomData<Ctx>, 207 + ); 208 + 209 + impl<Ctx: device::DeviceContext> Device<Ctx> { 210 + fn as_raw(&self) -> *mut bindings::auxiliary_device { 211 + self.0.get() 212 + } 213 + 214 + /// Returns the auxiliary device' id. 215 + pub fn id(&self) -> u32 { 216 + // SAFETY: By the type invariant `self.as_raw()` is a valid pointer to a 217 + // `struct auxiliary_device`. 218 + unsafe { (*self.as_raw()).id } 219 + } 220 + 221 + /// Returns a reference to the parent [`device::Device`], if any. 222 + pub fn parent(&self) -> Option<&device::Device> { 223 + let ptr: *const Self = self; 224 + // CAST: `Device<Ctx: DeviceContext>` types are transparent to each other. 225 + let ptr: *const Device = ptr.cast(); 226 + // SAFETY: `ptr` was derived from `&self`. 227 + let this = unsafe { &*ptr }; 228 + 229 + this.as_ref().parent() 230 + } 231 + } 232 + 233 + impl Device { 234 + extern "C" fn release(dev: *mut bindings::device) { 235 + // SAFETY: By the type invariant `self.0.as_raw` is a pointer to the `struct device` 236 + // embedded in `struct auxiliary_device`. 237 + let adev = unsafe { container_of!(dev, bindings::auxiliary_device, dev) }.cast_mut(); 238 + 239 + // SAFETY: `adev` points to the memory that has been allocated in `Registration::new`, via 240 + // `KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)`. 241 + let _ = unsafe { KBox::<Opaque<bindings::auxiliary_device>>::from_raw(adev.cast()) }; 242 + } 243 + } 244 + 245 + // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic 246 + // argument. 247 + kernel::impl_device_context_deref!(unsafe { Device }); 248 + kernel::impl_device_context_into_aref!(Device); 249 + 250 + // SAFETY: Instances of `Device` are always reference-counted. 251 + unsafe impl crate::types::AlwaysRefCounted for Device { 252 + fn inc_ref(&self) { 253 + // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. 254 + unsafe { bindings::get_device(self.as_ref().as_raw()) }; 255 + } 256 + 257 + unsafe fn dec_ref(obj: NonNull<Self>) { 258 + // CAST: `Self` a transparent wrapper of `bindings::auxiliary_device`. 259 + let adev: *mut bindings::auxiliary_device = obj.cast().as_ptr(); 260 + 261 + // SAFETY: By the type invariant of `Self`, `adev` is a pointer to a valid 262 + // `struct auxiliary_device`. 263 + let dev = unsafe { addr_of_mut!((*adev).dev) }; 264 + 265 + // SAFETY: The safety requirements guarantee that the refcount is non-zero. 266 + unsafe { bindings::put_device(dev) } 267 + } 268 + } 269 + 270 + impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> { 271 + fn as_ref(&self) -> &device::Device<Ctx> { 272 + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid 273 + // `struct auxiliary_device`. 274 + let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; 275 + 276 + // SAFETY: `dev` points to a valid `struct device`. 277 + unsafe { device::Device::as_ref(dev) } 278 + } 279 + } 280 + 281 + // SAFETY: A `Device` is always reference-counted and can be released from any thread. 282 + unsafe impl Send for Device {} 283 + 284 + // SAFETY: `Device` can be shared among threads because all methods of `Device` 285 + // (i.e. `Device<Normal>) are thread safe. 286 + unsafe impl Sync for Device {} 287 + 288 + /// The registration of an auxiliary device. 289 + /// 290 + /// This type represents the registration of a [`struct auxiliary_device`]. When an instance of this 291 + /// type is dropped, its respective auxiliary device will be unregistered from the system. 292 + /// 293 + /// # Invariants 294 + /// 295 + /// `self.0` always holds a valid pointer to an initialized and registered 296 + /// [`struct auxiliary_device`]. 297 + pub struct Registration(NonNull<bindings::auxiliary_device>); 298 + 299 + impl Registration { 300 + /// Create and register a new auxiliary device. 301 + pub fn new(parent: &device::Device, name: &CStr, id: u32, modname: &CStr) -> Result<Self> { 302 + let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?; 303 + let adev = boxed.get(); 304 + 305 + // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. 306 + unsafe { 307 + (*adev).dev.parent = parent.as_raw(); 308 + (*adev).dev.release = Some(Device::release); 309 + (*adev).name = name.as_char_ptr(); 310 + (*adev).id = id; 311 + } 312 + 313 + // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, 314 + // which has not been initialized yet. 315 + unsafe { bindings::auxiliary_device_init(adev) }; 316 + 317 + // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be freed 318 + // by `Device::release` when the last reference to the `struct auxiliary_device` is dropped. 319 + let _ = KBox::into_raw(boxed); 320 + 321 + // SAFETY: 322 + // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which has 323 + // been initialialized, 324 + // - `modname.as_char_ptr()` is a NULL terminated string. 325 + let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; 326 + if ret != 0 { 327 + // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, 328 + // which has been initialialized. 329 + unsafe { bindings::auxiliary_device_uninit(adev) }; 330 + 331 + return Err(Error::from_errno(ret)); 332 + } 333 + 334 + // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated successfully. 335 + // 336 + // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is called, 337 + // which happens in `Self::drop()`. 338 + Ok(Self(unsafe { NonNull::new_unchecked(adev) })) 339 + } 340 + } 341 + 342 + impl Drop for Registration { 343 + fn drop(&mut self) { 344 + // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered 345 + // `struct auxiliary_device`. 346 + unsafe { bindings::auxiliary_device_delete(self.0.as_ptr()) }; 347 + 348 + // This drops the reference we acquired through `auxiliary_device_init()`. 349 + // 350 + // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered 351 + // `struct auxiliary_device`. 352 + unsafe { bindings::auxiliary_device_uninit(self.0.as_ptr()) }; 353 + } 354 + } 355 + 356 + // SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread. 357 + unsafe impl Send for Registration {} 358 + 359 + // SAFETY: `Registration` does not expose any methods or fields that need synchronization. 360 + unsafe impl Sync for Registration {}
+107 -2
rust/kernel/device.rs
··· 9 9 str::CStr, 10 10 types::{ARef, Opaque}, 11 11 }; 12 - use core::{fmt, ptr}; 12 + use core::{fmt, marker::PhantomData, ptr}; 13 13 14 14 #[cfg(CONFIG_PRINTK)] 15 15 use crate::c_str; ··· 42 42 /// `bindings::device::release` is valid to be called from any thread, hence `ARef<Device>` can be 43 43 /// dropped from any thread. 44 44 #[repr(transparent)] 45 - pub struct Device(Opaque<bindings::device>); 45 + pub struct Device<Ctx: DeviceContext = Normal>(Opaque<bindings::device>, PhantomData<Ctx>); 46 46 47 47 impl Device { 48 48 /// Creates a new reference-counted abstraction instance of an existing `struct device` pointer. ··· 59 59 // SAFETY: By the safety requirements ptr is valid 60 60 unsafe { Self::as_ref(ptr) }.into() 61 61 } 62 + } 62 63 64 + impl<Ctx: DeviceContext> Device<Ctx> { 63 65 /// Obtain the raw `struct device *`. 64 66 pub(crate) fn as_raw(&self) -> *mut bindings::device { 65 67 self.0.get() 68 + } 69 + 70 + /// Returns a reference to the parent device, if any. 71 + #[cfg_attr(not(CONFIG_AUXILIARY_BUS), expect(dead_code))] 72 + pub(crate) fn parent(&self) -> Option<&Self> { 73 + // SAFETY: 74 + // - By the type invariant `self.as_raw()` is always valid. 75 + // - The parent device is only ever set at device creation. 76 + let parent = unsafe { (*self.as_raw()).parent }; 77 + 78 + if parent.is_null() { 79 + None 80 + } else { 81 + // SAFETY: 82 + // - Since `parent` is not NULL, it must be a valid pointer to a `struct device`. 83 + // - `parent` is valid for the lifetime of `self`, since a `struct device` holds a 84 + // reference count of its parent. 85 + Some(unsafe { Self::as_ref(parent) }) 86 + } 66 87 } 67 88 68 89 /// Convert a raw C `struct device` pointer to a `&'a Device`. ··· 210 189 } 211 190 } 212 191 192 + // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic 193 + // argument. 194 + kernel::impl_device_context_deref!(unsafe { Device }); 195 + kernel::impl_device_context_into_aref!(Device); 196 + 213 197 // SAFETY: Instances of `Device` are always reference-counted. 214 198 unsafe impl crate::types::AlwaysRefCounted for Device { 215 199 fn inc_ref(&self) { ··· 251 225 /// any of the bus callbacks, such as `probe()`. 252 226 pub struct Core; 253 227 228 + /// The [`Bound`] context is the context of a bus specific device reference when it is guaranteed to 229 + /// be bound for the duration of its lifetime. 230 + pub struct Bound; 231 + 254 232 mod private { 255 233 pub trait Sealed {} 256 234 235 + impl Sealed for super::Bound {} 257 236 impl Sealed for super::Core {} 258 237 impl Sealed for super::Normal {} 259 238 } 260 239 240 + impl DeviceContext for Bound {} 261 241 impl DeviceContext for Core {} 262 242 impl DeviceContext for Normal {} 243 + 244 + /// # Safety 245 + /// 246 + /// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the 247 + /// generic argument of `$device`. 248 + #[doc(hidden)] 249 + #[macro_export] 250 + macro_rules! __impl_device_context_deref { 251 + (unsafe { $device:ident, $src:ty => $dst:ty }) => { 252 + impl ::core::ops::Deref for $device<$src> { 253 + type Target = $device<$dst>; 254 + 255 + fn deref(&self) -> &Self::Target { 256 + let ptr: *const Self = self; 257 + 258 + // CAST: `$device<$src>` and `$device<$dst>` transparently wrap the same type by the 259 + // safety requirement of the macro. 260 + let ptr = ptr.cast::<Self::Target>(); 261 + 262 + // SAFETY: `ptr` was derived from `&self`. 263 + unsafe { &*ptr } 264 + } 265 + } 266 + }; 267 + } 268 + 269 + /// Implement [`core::ops::Deref`] traits for allowed [`DeviceContext`] conversions of a (bus 270 + /// specific) device. 271 + /// 272 + /// # Safety 273 + /// 274 + /// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the 275 + /// generic argument of `$device`. 276 + #[macro_export] 277 + macro_rules! impl_device_context_deref { 278 + (unsafe { $device:ident }) => { 279 + // SAFETY: This macro has the exact same safety requirement as 280 + // `__impl_device_context_deref!`. 281 + ::kernel::__impl_device_context_deref!(unsafe { 282 + $device, 283 + $crate::device::Core => $crate::device::Bound 284 + }); 285 + 286 + // SAFETY: This macro has the exact same safety requirement as 287 + // `__impl_device_context_deref!`. 288 + ::kernel::__impl_device_context_deref!(unsafe { 289 + $device, 290 + $crate::device::Bound => $crate::device::Normal 291 + }); 292 + }; 293 + } 294 + 295 + #[doc(hidden)] 296 + #[macro_export] 297 + macro_rules! __impl_device_context_into_aref { 298 + ($src:ty, $device:tt) => { 299 + impl ::core::convert::From<&$device<$src>> for $crate::types::ARef<$device> { 300 + fn from(dev: &$device<$src>) -> Self { 301 + (&**dev).into() 302 + } 303 + } 304 + }; 305 + } 306 + 307 + /// Implement [`core::convert::From`], such that all `&Device<Ctx>` can be converted to an 308 + /// `ARef<Device>`. 309 + #[macro_export] 310 + macro_rules! impl_device_context_into_aref { 311 + ($device:tt) => { 312 + ::kernel::__impl_device_context_into_aref!($crate::device::Core, $device); 313 + ::kernel::__impl_device_context_into_aref!($crate::device::Bound, $device); 314 + }; 315 + } 263 316 264 317 #[doc(hidden)] 265 318 #[macro_export]
+46 -10
rust/kernel/devres.rs
··· 8 8 use crate::{ 9 9 alloc::Flags, 10 10 bindings, 11 - device::Device, 11 + device::{Bound, Device}, 12 12 error::{Error, Result}, 13 13 ffi::c_void, 14 14 prelude::*, ··· 45 45 /// # Example 46 46 /// 47 47 /// ```no_run 48 - /// # use kernel::{bindings, c_str, device::Device, devres::Devres, io::{Io, IoRaw}}; 48 + /// # use kernel::{bindings, c_str, device::{Bound, Device}, devres::Devres, io::{Io, IoRaw}}; 49 49 /// # use core::ops::Deref; 50 50 /// 51 51 /// // See also [`pci::Bar`] for a real example. ··· 83 83 /// unsafe { Io::from_raw(&self.0) } 84 84 /// } 85 85 /// } 86 - /// # fn no_run() -> Result<(), Error> { 87 - /// # // SAFETY: Invalid usage; just for the example to get an `ARef<Device>` instance. 88 - /// # let dev = unsafe { Device::get_device(core::ptr::null_mut()) }; 89 - /// 86 + /// # fn no_run(dev: &Device<Bound>) -> Result<(), Error> { 90 87 /// // SAFETY: Invalid usage for example purposes. 91 88 /// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? }; 92 - /// let devres = Devres::new(&dev, iomem, GFP_KERNEL)?; 89 + /// let devres = Devres::new(dev, iomem, GFP_KERNEL)?; 93 90 /// 94 91 /// let res = devres.try_access().ok_or(ENXIO)?; 95 92 /// res.write8(0x42, 0x0); ··· 96 99 pub struct Devres<T>(Arc<DevresInner<T>>); 97 100 98 101 impl<T> DevresInner<T> { 99 - fn new(dev: &Device, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> { 102 + fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> { 100 103 let inner = Arc::pin_init( 101 104 pin_init!( DevresInner { 102 105 dev: dev.into(), ··· 168 171 impl<T> Devres<T> { 169 172 /// Creates a new [`Devres`] instance of the given `data`. The `data` encapsulated within the 170 173 /// returned `Devres` instance' `data` will be revoked once the device is detached. 171 - pub fn new(dev: &Device, data: T, flags: Flags) -> Result<Self> { 174 + pub fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Self> { 172 175 let inner = DevresInner::new(dev, data, flags)?; 173 176 174 177 Ok(Devres(inner)) ··· 176 179 177 180 /// Same as [`Devres::new`], but does not return a `Devres` instance. Instead the given `data` 178 181 /// is owned by devres and will be revoked / dropped, once the device is detached. 179 - pub fn new_foreign_owned(dev: &Device, data: T, flags: Flags) -> Result { 182 + pub fn new_foreign_owned(dev: &Device<Bound>, data: T, flags: Flags) -> Result { 180 183 let _ = DevresInner::new(dev, data, flags)?; 181 184 182 185 Ok(()) 186 + } 187 + 188 + /// Obtain `&'a T`, bypassing the [`Revocable`]. 189 + /// 190 + /// This method allows to directly obtain a `&'a T`, bypassing the [`Revocable`], by presenting 191 + /// a `&'a Device<Bound>` of the same [`Device`] this [`Devres`] instance has been created with. 192 + /// 193 + /// # Errors 194 + /// 195 + /// An error is returned if `dev` does not match the same [`Device`] this [`Devres`] instance 196 + /// has been created with. 197 + /// 198 + /// # Example 199 + /// 200 + /// ```no_run 201 + /// # #![cfg(CONFIG_PCI)] 202 + /// # use kernel::{device::Core, devres::Devres, pci}; 203 + /// 204 + /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) -> Result { 205 + /// let bar = devres.access(dev.as_ref())?; 206 + /// 207 + /// let _ = bar.read32(0x0); 208 + /// 209 + /// // might_sleep() 210 + /// 211 + /// bar.write32(0x42, 0x0); 212 + /// 213 + /// Ok(()) 214 + /// } 215 + /// ``` 216 + pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a T> { 217 + if self.0.dev.as_raw() != dev.as_raw() { 218 + return Err(EINVAL); 219 + } 220 + 221 + // SAFETY: `dev` being the same device as the device this `Devres` has been created for 222 + // proves that `self.0.data` hasn't been revoked and is guaranteed to not be revoked as 223 + // long as `dev` lives; `dev` lives at least as long as `self`. 224 + Ok(unsafe { self.deref().access() }) 183 225 } 184 226 } 185 227
+7 -7
rust/kernel/dma.rs
··· 6 6 7 7 use crate::{ 8 8 bindings, build_assert, 9 - device::Device, 9 + device::{Bound, Device}, 10 10 error::code::*, 11 11 error::Result, 12 12 transmute::{AsBytes, FromBytes}, ··· 22 22 /// # Examples 23 23 /// 24 24 /// ``` 25 - /// use kernel::device::Device; 25 + /// # use kernel::device::{Bound, Device}; 26 26 /// use kernel::dma::{attrs::*, CoherentAllocation}; 27 27 /// 28 - /// # fn test(dev: &Device) -> Result { 28 + /// # fn test(dev: &Device<Bound>) -> Result { 29 29 /// let attribs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN; 30 30 /// let c: CoherentAllocation<u64> = 31 31 /// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, attribs)?; ··· 143 143 /// # Examples 144 144 /// 145 145 /// ``` 146 - /// use kernel::device::Device; 146 + /// # use kernel::device::{Bound, Device}; 147 147 /// use kernel::dma::{attrs::*, CoherentAllocation}; 148 148 /// 149 - /// # fn test(dev: &Device) -> Result { 149 + /// # fn test(dev: &Device<Bound>) -> Result { 150 150 /// let c: CoherentAllocation<u64> = 151 151 /// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_NO_WARN)?; 152 152 /// # Ok::<(), Error>(()) } 153 153 /// ``` 154 154 pub fn alloc_attrs( 155 - dev: &Device, 155 + dev: &Device<Bound>, 156 156 count: usize, 157 157 gfp_flags: kernel::alloc::Flags, 158 158 dma_attrs: Attrs, ··· 194 194 /// Performs the same functionality as [`CoherentAllocation::alloc_attrs`], except the 195 195 /// `dma_attrs` is 0 by default. 196 196 pub fn alloc_coherent( 197 - dev: &Device, 197 + dev: &Device<Bound>, 198 198 count: usize, 199 199 gfp_flags: kernel::alloc::Flags, 200 200 ) -> Result<CoherentAllocation<T>> {
+200
rust/kernel/drm/device.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR MIT 2 + 3 + //! DRM device. 4 + //! 5 + //! C header: [`include/linux/drm/drm_device.h`](srctree/include/linux/drm/drm_device.h) 6 + 7 + use crate::{ 8 + bindings, device, drm, 9 + drm::driver::AllocImpl, 10 + error::from_err_ptr, 11 + error::Result, 12 + prelude::*, 13 + types::{ARef, AlwaysRefCounted, Opaque}, 14 + }; 15 + use core::{mem, ops::Deref, ptr, ptr::NonNull}; 16 + 17 + #[cfg(CONFIG_DRM_LEGACY)] 18 + macro_rules! drm_legacy_fields { 19 + ( $($field:ident: $val:expr),* $(,)? ) => { 20 + bindings::drm_driver { 21 + $( $field: $val ),*, 22 + firstopen: None, 23 + preclose: None, 24 + dma_ioctl: None, 25 + dma_quiescent: None, 26 + context_dtor: None, 27 + irq_handler: None, 28 + irq_preinstall: None, 29 + irq_postinstall: None, 30 + irq_uninstall: None, 31 + get_vblank_counter: None, 32 + enable_vblank: None, 33 + disable_vblank: None, 34 + dev_priv_size: 0, 35 + } 36 + } 37 + } 38 + 39 + #[cfg(not(CONFIG_DRM_LEGACY))] 40 + macro_rules! drm_legacy_fields { 41 + ( $($field:ident: $val:expr),* $(,)? ) => { 42 + bindings::drm_driver { 43 + $( $field: $val ),* 44 + } 45 + } 46 + } 47 + 48 + /// A typed DRM device with a specific `drm::Driver` implementation. 49 + /// 50 + /// The device is always reference-counted. 51 + /// 52 + /// # Invariants 53 + /// 54 + /// `self.dev` is a valid instance of a `struct device`. 55 + #[repr(C)] 56 + #[pin_data] 57 + pub struct Device<T: drm::Driver> { 58 + dev: Opaque<bindings::drm_device>, 59 + #[pin] 60 + data: T::Data, 61 + } 62 + 63 + impl<T: drm::Driver> Device<T> { 64 + const VTABLE: bindings::drm_driver = drm_legacy_fields! { 65 + load: None, 66 + open: Some(drm::File::<T::File>::open_callback), 67 + postclose: Some(drm::File::<T::File>::postclose_callback), 68 + unload: None, 69 + release: None, 70 + master_set: None, 71 + master_drop: None, 72 + debugfs_init: None, 73 + gem_create_object: T::Object::ALLOC_OPS.gem_create_object, 74 + prime_handle_to_fd: T::Object::ALLOC_OPS.prime_handle_to_fd, 75 + prime_fd_to_handle: T::Object::ALLOC_OPS.prime_fd_to_handle, 76 + gem_prime_import: T::Object::ALLOC_OPS.gem_prime_import, 77 + gem_prime_import_sg_table: T::Object::ALLOC_OPS.gem_prime_import_sg_table, 78 + dumb_create: T::Object::ALLOC_OPS.dumb_create, 79 + dumb_map_offset: T::Object::ALLOC_OPS.dumb_map_offset, 80 + show_fdinfo: None, 81 + fbdev_probe: None, 82 + 83 + major: T::INFO.major, 84 + minor: T::INFO.minor, 85 + patchlevel: T::INFO.patchlevel, 86 + name: T::INFO.name.as_char_ptr() as *mut _, 87 + desc: T::INFO.desc.as_char_ptr() as *mut _, 88 + 89 + driver_features: drm::driver::FEAT_GEM, 90 + ioctls: T::IOCTLS.as_ptr(), 91 + num_ioctls: T::IOCTLS.len() as i32, 92 + fops: &Self::GEM_FOPS as _, 93 + }; 94 + 95 + const GEM_FOPS: bindings::file_operations = drm::gem::create_fops(); 96 + 97 + /// Create a new `drm::Device` for a `drm::Driver`. 98 + pub fn new(dev: &device::Device, data: impl PinInit<T::Data, Error>) -> Result<ARef<Self>> { 99 + // SAFETY: 100 + // - `VTABLE`, as a `const` is pinned to the read-only section of the compilation, 101 + // - `dev` is valid by its type invarants, 102 + let raw_drm: *mut Self = unsafe { 103 + bindings::__drm_dev_alloc( 104 + dev.as_raw(), 105 + &Self::VTABLE, 106 + mem::size_of::<Self>(), 107 + mem::offset_of!(Self, dev), 108 + ) 109 + } 110 + .cast(); 111 + let raw_drm = NonNull::new(from_err_ptr(raw_drm)?).ok_or(ENOMEM)?; 112 + 113 + // SAFETY: `raw_drm` is a valid pointer to `Self`. 114 + let raw_data = unsafe { ptr::addr_of_mut!((*raw_drm.as_ptr()).data) }; 115 + 116 + // SAFETY: 117 + // - `raw_data` is a valid pointer to uninitialized memory. 118 + // - `raw_data` will not move until it is dropped. 119 + unsafe { data.__pinned_init(raw_data) }.inspect_err(|_| { 120 + // SAFETY: `__drm_dev_alloc()` was successful, hence `raw_drm` must be valid and the 121 + // refcount must be non-zero. 122 + unsafe { bindings::drm_dev_put(ptr::addr_of_mut!((*raw_drm.as_ptr()).dev).cast()) }; 123 + })?; 124 + 125 + // SAFETY: The reference count is one, and now we take ownership of that reference as a 126 + // `drm::Device`. 127 + Ok(unsafe { ARef::from_raw(raw_drm) }) 128 + } 129 + 130 + pub(crate) fn as_raw(&self) -> *mut bindings::drm_device { 131 + self.dev.get() 132 + } 133 + 134 + /// # Safety 135 + /// 136 + /// `ptr` must be a valid pointer to a `struct device` embedded in `Self`. 137 + unsafe fn from_drm_device(ptr: *const bindings::drm_device) -> *mut Self { 138 + // SAFETY: By the safety requirements of this function `ptr` is a valid pointer to a 139 + // `struct drm_device` embedded in `Self`. 140 + unsafe { crate::container_of!(ptr, Self, dev) }.cast_mut() 141 + } 142 + 143 + /// Not intended to be called externally, except via declare_drm_ioctls!() 144 + /// 145 + /// # Safety 146 + /// 147 + /// Callers must ensure that `ptr` is valid, non-null, and has a non-zero reference count, 148 + /// i.e. it must be ensured that the reference count of the C `struct drm_device` `ptr` points 149 + /// to can't drop to zero, for the duration of this function call and the entire duration when 150 + /// the returned reference exists. 151 + /// 152 + /// Additionally, callers must ensure that the `struct device`, `ptr` is pointing to, is 153 + /// embedded in `Self`. 154 + #[doc(hidden)] 155 + pub unsafe fn as_ref<'a>(ptr: *const bindings::drm_device) -> &'a Self { 156 + // SAFETY: By the safety requirements of this function `ptr` is a valid pointer to a 157 + // `struct drm_device` embedded in `Self`. 158 + let ptr = unsafe { Self::from_drm_device(ptr) }; 159 + 160 + // SAFETY: `ptr` is valid by the safety requirements of this function. 161 + unsafe { &*ptr.cast() } 162 + } 163 + } 164 + 165 + impl<T: drm::Driver> Deref for Device<T> { 166 + type Target = T::Data; 167 + 168 + fn deref(&self) -> &Self::Target { 169 + &self.data 170 + } 171 + } 172 + 173 + // SAFETY: DRM device objects are always reference counted and the get/put functions 174 + // satisfy the requirements. 175 + unsafe impl<T: drm::Driver> AlwaysRefCounted for Device<T> { 176 + fn inc_ref(&self) { 177 + // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. 178 + unsafe { bindings::drm_dev_get(self.as_raw()) }; 179 + } 180 + 181 + unsafe fn dec_ref(obj: NonNull<Self>) { 182 + // SAFETY: The safety requirements guarantee that the refcount is non-zero. 183 + unsafe { bindings::drm_dev_put(obj.cast().as_ptr()) }; 184 + } 185 + } 186 + 187 + impl<T: drm::Driver> AsRef<device::Device> for Device<T> { 188 + fn as_ref(&self) -> &device::Device { 189 + // SAFETY: `bindings::drm_device::dev` is valid as long as the DRM device itself is valid, 190 + // which is guaranteed by the type invariant. 191 + unsafe { device::Device::as_ref((*self.as_raw()).dev) } 192 + } 193 + } 194 + 195 + // SAFETY: A `drm::Device` can be released from any thread. 196 + unsafe impl<T: drm::Driver> Send for Device<T> {} 197 + 198 + // SAFETY: A `drm::Device` can be shared among threads because all immutable methods are protected 199 + // by the synchronization in `struct drm_device`. 200 + unsafe impl<T: drm::Driver> Sync for Device<T> {}
+166
rust/kernel/drm/driver.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR MIT 2 + 3 + //! DRM driver core. 4 + //! 5 + //! C header: [`include/linux/drm/drm_drv.h`](srctree/include/linux/drm/drm_drv.h) 6 + 7 + use crate::{ 8 + bindings, device, 9 + devres::Devres, 10 + drm, 11 + error::{to_result, Result}, 12 + prelude::*, 13 + str::CStr, 14 + types::ARef, 15 + }; 16 + use macros::vtable; 17 + 18 + /// Driver use the GEM memory manager. This should be set for all modern drivers. 19 + pub(crate) const FEAT_GEM: u32 = bindings::drm_driver_feature_DRIVER_GEM; 20 + 21 + /// Information data for a DRM Driver. 22 + pub struct DriverInfo { 23 + /// Driver major version. 24 + pub major: i32, 25 + /// Driver minor version. 26 + pub minor: i32, 27 + /// Driver patchlevel version. 28 + pub patchlevel: i32, 29 + /// Driver name. 30 + pub name: &'static CStr, 31 + /// Driver description. 32 + pub desc: &'static CStr, 33 + } 34 + 35 + /// Internal memory management operation set, normally created by memory managers (e.g. GEM). 36 + pub struct AllocOps { 37 + pub(crate) gem_create_object: Option< 38 + unsafe extern "C" fn( 39 + dev: *mut bindings::drm_device, 40 + size: usize, 41 + ) -> *mut bindings::drm_gem_object, 42 + >, 43 + pub(crate) prime_handle_to_fd: Option< 44 + unsafe extern "C" fn( 45 + dev: *mut bindings::drm_device, 46 + file_priv: *mut bindings::drm_file, 47 + handle: u32, 48 + flags: u32, 49 + prime_fd: *mut core::ffi::c_int, 50 + ) -> core::ffi::c_int, 51 + >, 52 + pub(crate) prime_fd_to_handle: Option< 53 + unsafe extern "C" fn( 54 + dev: *mut bindings::drm_device, 55 + file_priv: *mut bindings::drm_file, 56 + prime_fd: core::ffi::c_int, 57 + handle: *mut u32, 58 + ) -> core::ffi::c_int, 59 + >, 60 + pub(crate) gem_prime_import: Option< 61 + unsafe extern "C" fn( 62 + dev: *mut bindings::drm_device, 63 + dma_buf: *mut bindings::dma_buf, 64 + ) -> *mut bindings::drm_gem_object, 65 + >, 66 + pub(crate) gem_prime_import_sg_table: Option< 67 + unsafe extern "C" fn( 68 + dev: *mut bindings::drm_device, 69 + attach: *mut bindings::dma_buf_attachment, 70 + sgt: *mut bindings::sg_table, 71 + ) -> *mut bindings::drm_gem_object, 72 + >, 73 + pub(crate) dumb_create: Option< 74 + unsafe extern "C" fn( 75 + file_priv: *mut bindings::drm_file, 76 + dev: *mut bindings::drm_device, 77 + args: *mut bindings::drm_mode_create_dumb, 78 + ) -> core::ffi::c_int, 79 + >, 80 + pub(crate) dumb_map_offset: Option< 81 + unsafe extern "C" fn( 82 + file_priv: *mut bindings::drm_file, 83 + dev: *mut bindings::drm_device, 84 + handle: u32, 85 + offset: *mut u64, 86 + ) -> core::ffi::c_int, 87 + >, 88 + } 89 + 90 + /// Trait for memory manager implementations. Implemented internally. 91 + pub trait AllocImpl: super::private::Sealed + drm::gem::IntoGEMObject { 92 + /// The C callback operations for this memory manager. 93 + const ALLOC_OPS: AllocOps; 94 + } 95 + 96 + /// The DRM `Driver` trait. 97 + /// 98 + /// This trait must be implemented by drivers in order to create a `struct drm_device` and `struct 99 + /// drm_driver` to be registered in the DRM subsystem. 100 + #[vtable] 101 + pub trait Driver { 102 + /// Context data associated with the DRM driver 103 + type Data: Sync + Send; 104 + 105 + /// The type used to manage memory for this driver. 106 + type Object: AllocImpl; 107 + 108 + /// The type used to represent a DRM File (client) 109 + type File: drm::file::DriverFile; 110 + 111 + /// Driver metadata 112 + const INFO: DriverInfo; 113 + 114 + /// IOCTL list. See `kernel::drm::ioctl::declare_drm_ioctls!{}`. 115 + const IOCTLS: &'static [drm::ioctl::DrmIoctlDescriptor]; 116 + } 117 + 118 + /// The registration type of a `drm::Device`. 119 + /// 120 + /// Once the `Registration` structure is dropped, the device is unregistered. 121 + pub struct Registration<T: Driver>(ARef<drm::Device<T>>); 122 + 123 + impl<T: Driver> Registration<T> { 124 + /// Creates a new [`Registration`] and registers it. 125 + fn new(drm: &drm::Device<T>, flags: usize) -> Result<Self> { 126 + // SAFETY: `drm.as_raw()` is valid by the invariants of `drm::Device`. 127 + to_result(unsafe { bindings::drm_dev_register(drm.as_raw(), flags) })?; 128 + 129 + Ok(Self(drm.into())) 130 + } 131 + 132 + /// Same as [`Registration::new`}, but transfers ownership of the [`Registration`] to 133 + /// [`Devres`]. 134 + pub fn new_foreign_owned( 135 + drm: &drm::Device<T>, 136 + dev: &device::Device<device::Bound>, 137 + flags: usize, 138 + ) -> Result { 139 + if drm.as_ref().as_raw() != dev.as_raw() { 140 + return Err(EINVAL); 141 + } 142 + 143 + let reg = Registration::<T>::new(drm, flags)?; 144 + Devres::new_foreign_owned(dev, reg, GFP_KERNEL) 145 + } 146 + 147 + /// Returns a reference to the `Device` instance for this registration. 148 + pub fn device(&self) -> &drm::Device<T> { 149 + &self.0 150 + } 151 + } 152 + 153 + // SAFETY: `Registration` doesn't offer any methods or access to fields when shared between 154 + // threads, hence it's safe to share it. 155 + unsafe impl<T: Driver> Sync for Registration<T> {} 156 + 157 + // SAFETY: Registration with and unregistration from the DRM subsystem can happen from any thread. 158 + unsafe impl<T: Driver> Send for Registration<T> {} 159 + 160 + impl<T: Driver> Drop for Registration<T> { 161 + fn drop(&mut self) { 162 + // SAFETY: Safe by the invariant of `ARef<drm::Device<T>>`. The existence of this 163 + // `Registration` also guarantees the this `drm::Device` is actually registered. 164 + unsafe { bindings::drm_dev_unregister(self.0.as_raw()) }; 165 + } 166 + }
+99
rust/kernel/drm/file.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR MIT 2 + 3 + //! DRM File objects. 4 + //! 5 + //! C header: [`include/linux/drm/drm_file.h`](srctree/include/linux/drm/drm_file.h) 6 + 7 + use crate::{bindings, drm, error::Result, prelude::*, types::Opaque}; 8 + use core::marker::PhantomData; 9 + use core::pin::Pin; 10 + 11 + /// Trait that must be implemented by DRM drivers to represent a DRM File (a client instance). 12 + pub trait DriverFile { 13 + /// The parent `Driver` implementation for this `DriverFile`. 14 + type Driver: drm::Driver; 15 + 16 + /// Open a new file (called when a client opens the DRM device). 17 + fn open(device: &drm::Device<Self::Driver>) -> Result<Pin<KBox<Self>>>; 18 + } 19 + 20 + /// An open DRM File. 21 + /// 22 + /// # Invariants 23 + /// 24 + /// `self.0` is a valid instance of a `struct drm_file`. 25 + #[repr(transparent)] 26 + pub struct File<T: DriverFile>(Opaque<bindings::drm_file>, PhantomData<T>); 27 + 28 + impl<T: DriverFile> File<T> { 29 + #[doc(hidden)] 30 + /// Not intended to be called externally, except via declare_drm_ioctls!() 31 + /// 32 + /// # Safety 33 + /// 34 + /// `raw_file` must be a valid pointer to an open `struct drm_file`, opened through `T::open`. 35 + pub unsafe fn as_ref<'a>(ptr: *mut bindings::drm_file) -> &'a File<T> { 36 + // SAFETY: `raw_file` is valid by the safety requirements of this function. 37 + unsafe { &*ptr.cast() } 38 + } 39 + 40 + pub(super) fn as_raw(&self) -> *mut bindings::drm_file { 41 + self.0.get() 42 + } 43 + 44 + fn driver_priv(&self) -> *mut T { 45 + // SAFETY: By the type invariants of `Self`, `self.as_raw()` is always valid. 46 + unsafe { (*self.as_raw()).driver_priv }.cast() 47 + } 48 + 49 + /// Return a pinned reference to the driver file structure. 50 + pub fn inner(&self) -> Pin<&T> { 51 + // SAFETY: By the type invariant the pointer `self.as_raw()` points to a valid and opened 52 + // `struct drm_file`, hence `driver_priv` has been properly initialized by `open_callback`. 53 + unsafe { Pin::new_unchecked(&*(self.driver_priv())) } 54 + } 55 + 56 + /// The open callback of a `struct drm_file`. 57 + pub(crate) extern "C" fn open_callback( 58 + raw_dev: *mut bindings::drm_device, 59 + raw_file: *mut bindings::drm_file, 60 + ) -> core::ffi::c_int { 61 + // SAFETY: A callback from `struct drm_driver::open` guarantees that 62 + // - `raw_dev` is valid pointer to a `struct drm_device`, 63 + // - the corresponding `struct drm_device` has been registered. 64 + let drm = unsafe { drm::Device::as_ref(raw_dev) }; 65 + 66 + // SAFETY: `raw_file` is a valid pointer to a `struct drm_file`. 67 + let file = unsafe { File::<T>::as_ref(raw_file) }; 68 + 69 + let inner = match T::open(drm) { 70 + Err(e) => { 71 + return e.to_errno(); 72 + } 73 + Ok(i) => i, 74 + }; 75 + 76 + // SAFETY: This pointer is treated as pinned, and the Drop guarantee is upheld in 77 + // `postclose_callback()`. 78 + let driver_priv = KBox::into_raw(unsafe { Pin::into_inner_unchecked(inner) }); 79 + 80 + // SAFETY: By the type invariants of `Self`, `self.as_raw()` is always valid. 81 + unsafe { (*file.as_raw()).driver_priv = driver_priv.cast() }; 82 + 83 + 0 84 + } 85 + 86 + /// The postclose callback of a `struct drm_file`. 87 + pub(crate) extern "C" fn postclose_callback( 88 + _raw_dev: *mut bindings::drm_device, 89 + raw_file: *mut bindings::drm_file, 90 + ) { 91 + // SAFETY: This reference won't escape this function 92 + let file = unsafe { File::<T>::as_ref(raw_file) }; 93 + 94 + // SAFETY: `file.driver_priv` has been created in `open_callback` through `KBox::into_raw`. 95 + let _ = unsafe { KBox::from_raw(file.driver_priv()) }; 96 + } 97 + } 98 + 99 + impl<T: DriverFile> super::private::Sealed for File<T> {}
+328
rust/kernel/drm/gem/mod.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR MIT 2 + 3 + //! DRM GEM API 4 + //! 5 + //! C header: [`include/linux/drm/drm_gem.h`](srctree/include/linux/drm/drm_gem.h) 6 + 7 + use crate::{ 8 + alloc::flags::*, 9 + bindings, drm, 10 + drm::driver::{AllocImpl, AllocOps}, 11 + error::{to_result, Result}, 12 + prelude::*, 13 + types::{ARef, AlwaysRefCounted, Opaque}, 14 + }; 15 + use core::{mem, ops::Deref, ptr::NonNull}; 16 + 17 + /// GEM object functions, which must be implemented by drivers. 18 + pub trait BaseDriverObject<T: BaseObject>: Sync + Send + Sized { 19 + /// Create a new driver data object for a GEM object of a given size. 20 + fn new(dev: &drm::Device<T::Driver>, size: usize) -> impl PinInit<Self, Error>; 21 + 22 + /// Open a new handle to an existing object, associated with a File. 23 + fn open( 24 + _obj: &<<T as IntoGEMObject>::Driver as drm::Driver>::Object, 25 + _file: &drm::File<<<T as IntoGEMObject>::Driver as drm::Driver>::File>, 26 + ) -> Result { 27 + Ok(()) 28 + } 29 + 30 + /// Close a handle to an existing object, associated with a File. 31 + fn close( 32 + _obj: &<<T as IntoGEMObject>::Driver as drm::Driver>::Object, 33 + _file: &drm::File<<<T as IntoGEMObject>::Driver as drm::Driver>::File>, 34 + ) { 35 + } 36 + } 37 + 38 + /// Trait that represents a GEM object subtype 39 + pub trait IntoGEMObject: Sized + super::private::Sealed + AlwaysRefCounted { 40 + /// Owning driver for this type 41 + type Driver: drm::Driver; 42 + 43 + /// Returns a reference to the raw `drm_gem_object` structure, which must be valid as long as 44 + /// this owning object is valid. 45 + fn as_raw(&self) -> *mut bindings::drm_gem_object; 46 + 47 + /// Converts a pointer to a `struct drm_gem_object` into a reference to `Self`. 48 + /// 49 + /// # Safety 50 + /// 51 + /// - `self_ptr` must be a valid pointer to `Self`. 52 + /// - The caller promises that holding the immutable reference returned by this function does 53 + /// not violate rust's data aliasing rules and remains valid throughout the lifetime of `'a`. 54 + unsafe fn as_ref<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self; 55 + } 56 + 57 + // SAFETY: All gem objects are refcounted. 58 + unsafe impl<T: IntoGEMObject> AlwaysRefCounted for T { 59 + fn inc_ref(&self) { 60 + // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. 61 + unsafe { bindings::drm_gem_object_get(self.as_raw()) }; 62 + } 63 + 64 + unsafe fn dec_ref(obj: NonNull<Self>) { 65 + // SAFETY: We either hold the only refcount on `obj`, or one of many - meaning that no one 66 + // else could possibly hold a mutable reference to `obj` and thus this immutable reference 67 + // is safe. 68 + let obj = unsafe { obj.as_ref() }.as_raw(); 69 + 70 + // SAFETY: 71 + // - The safety requirements guarantee that the refcount is non-zero. 72 + // - We hold no references to `obj` now, making it safe for us to potentially deallocate it. 73 + unsafe { bindings::drm_gem_object_put(obj) }; 74 + } 75 + } 76 + 77 + /// Trait which must be implemented by drivers using base GEM objects. 78 + pub trait DriverObject: BaseDriverObject<Object<Self>> { 79 + /// Parent `Driver` for this object. 80 + type Driver: drm::Driver; 81 + } 82 + 83 + extern "C" fn open_callback<T: BaseDriverObject<U>, U: BaseObject>( 84 + raw_obj: *mut bindings::drm_gem_object, 85 + raw_file: *mut bindings::drm_file, 86 + ) -> core::ffi::c_int { 87 + // SAFETY: `open_callback` is only ever called with a valid pointer to a `struct drm_file`. 88 + let file = unsafe { 89 + drm::File::<<<U as IntoGEMObject>::Driver as drm::Driver>::File>::as_ref(raw_file) 90 + }; 91 + // SAFETY: `open_callback` is specified in the AllocOps structure for `Object<T>`, ensuring that 92 + // `raw_obj` is indeed contained within a `Object<T>`. 93 + let obj = unsafe { 94 + <<<U as IntoGEMObject>::Driver as drm::Driver>::Object as IntoGEMObject>::as_ref(raw_obj) 95 + }; 96 + 97 + match T::open(obj, file) { 98 + Err(e) => e.to_errno(), 99 + Ok(()) => 0, 100 + } 101 + } 102 + 103 + extern "C" fn close_callback<T: BaseDriverObject<U>, U: BaseObject>( 104 + raw_obj: *mut bindings::drm_gem_object, 105 + raw_file: *mut bindings::drm_file, 106 + ) { 107 + // SAFETY: `open_callback` is only ever called with a valid pointer to a `struct drm_file`. 108 + let file = unsafe { 109 + drm::File::<<<U as IntoGEMObject>::Driver as drm::Driver>::File>::as_ref(raw_file) 110 + }; 111 + // SAFETY: `close_callback` is specified in the AllocOps structure for `Object<T>`, ensuring 112 + // that `raw_obj` is indeed contained within a `Object<T>`. 113 + let obj = unsafe { 114 + <<<U as IntoGEMObject>::Driver as drm::Driver>::Object as IntoGEMObject>::as_ref(raw_obj) 115 + }; 116 + 117 + T::close(obj, file); 118 + } 119 + 120 + impl<T: DriverObject> IntoGEMObject for Object<T> { 121 + type Driver = T::Driver; 122 + 123 + fn as_raw(&self) -> *mut bindings::drm_gem_object { 124 + self.obj.get() 125 + } 126 + 127 + unsafe fn as_ref<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self { 128 + // SAFETY: `obj` is guaranteed to be in an `Object<T>` via the safety contract of this 129 + // function 130 + unsafe { &*crate::container_of!(self_ptr, Object<T>, obj) } 131 + } 132 + } 133 + 134 + /// Base operations shared by all GEM object classes 135 + pub trait BaseObject: IntoGEMObject { 136 + /// Returns the size of the object in bytes. 137 + fn size(&self) -> usize { 138 + // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `struct drm_gem_object`. 139 + unsafe { (*self.as_raw()).size } 140 + } 141 + 142 + /// Creates a new handle for the object associated with a given `File` 143 + /// (or returns an existing one). 144 + fn create_handle( 145 + &self, 146 + file: &drm::File<<<Self as IntoGEMObject>::Driver as drm::Driver>::File>, 147 + ) -> Result<u32> { 148 + let mut handle: u32 = 0; 149 + // SAFETY: The arguments are all valid per the type invariants. 150 + to_result(unsafe { 151 + bindings::drm_gem_handle_create(file.as_raw().cast(), self.as_raw(), &mut handle) 152 + })?; 153 + Ok(handle) 154 + } 155 + 156 + /// Looks up an object by its handle for a given `File`. 157 + fn lookup_handle( 158 + file: &drm::File<<<Self as IntoGEMObject>::Driver as drm::Driver>::File>, 159 + handle: u32, 160 + ) -> Result<ARef<Self>> { 161 + // SAFETY: The arguments are all valid per the type invariants. 162 + let ptr = unsafe { bindings::drm_gem_object_lookup(file.as_raw().cast(), handle) }; 163 + if ptr.is_null() { 164 + return Err(ENOENT); 165 + } 166 + 167 + // SAFETY: 168 + // - A `drm::Driver` can only have a single `File` implementation. 169 + // - `file` uses the same `drm::Driver` as `Self`. 170 + // - Therefore, we're guaranteed that `ptr` must be a gem object embedded within `Self`. 171 + // - And we check if the pointer is null befoe calling as_ref(), ensuring that `ptr` is a 172 + // valid pointer to an initialized `Self`. 173 + let obj = unsafe { Self::as_ref(ptr) }; 174 + 175 + // SAFETY: 176 + // - We take ownership of the reference of `drm_gem_object_lookup()`. 177 + // - Our `NonNull` comes from an immutable reference, thus ensuring it is a valid pointer to 178 + // `Self`. 179 + Ok(unsafe { ARef::from_raw(obj.into()) }) 180 + } 181 + 182 + /// Creates an mmap offset to map the object from userspace. 183 + fn create_mmap_offset(&self) -> Result<u64> { 184 + // SAFETY: The arguments are valid per the type invariant. 185 + to_result(unsafe { bindings::drm_gem_create_mmap_offset(self.as_raw()) })?; 186 + 187 + // SAFETY: The arguments are valid per the type invariant. 188 + Ok(unsafe { bindings::drm_vma_node_offset_addr(&raw mut (*self.as_raw()).vma_node) }) 189 + } 190 + } 191 + 192 + impl<T: IntoGEMObject> BaseObject for T {} 193 + 194 + /// A base GEM object. 195 + /// 196 + /// Invariants 197 + /// 198 + /// - `self.obj` is a valid instance of a `struct drm_gem_object`. 199 + /// - `self.dev` is always a valid pointer to a `struct drm_device`. 200 + #[repr(C)] 201 + #[pin_data] 202 + pub struct Object<T: DriverObject + Send + Sync> { 203 + obj: Opaque<bindings::drm_gem_object>, 204 + dev: NonNull<drm::Device<T::Driver>>, 205 + #[pin] 206 + data: T, 207 + } 208 + 209 + impl<T: DriverObject> Object<T> { 210 + /// The size of this object's structure. 211 + pub const SIZE: usize = mem::size_of::<Self>(); 212 + 213 + const OBJECT_FUNCS: bindings::drm_gem_object_funcs = bindings::drm_gem_object_funcs { 214 + free: Some(Self::free_callback), 215 + open: Some(open_callback::<T, Object<T>>), 216 + close: Some(close_callback::<T, Object<T>>), 217 + print_info: None, 218 + export: None, 219 + pin: None, 220 + unpin: None, 221 + get_sg_table: None, 222 + vmap: None, 223 + vunmap: None, 224 + mmap: None, 225 + status: None, 226 + vm_ops: core::ptr::null_mut(), 227 + evict: None, 228 + rss: None, 229 + }; 230 + 231 + /// Create a new GEM object. 232 + pub fn new(dev: &drm::Device<T::Driver>, size: usize) -> Result<ARef<Self>> { 233 + let obj: Pin<KBox<Self>> = KBox::pin_init( 234 + try_pin_init!(Self { 235 + obj: Opaque::new(bindings::drm_gem_object::default()), 236 + data <- T::new(dev, size), 237 + // INVARIANT: The drm subsystem guarantees that the `struct drm_device` will live 238 + // as long as the GEM object lives. 239 + dev: dev.into(), 240 + }), 241 + GFP_KERNEL, 242 + )?; 243 + 244 + // SAFETY: `obj.as_raw()` is guaranteed to be valid by the initialization above. 245 + unsafe { (*obj.as_raw()).funcs = &Self::OBJECT_FUNCS }; 246 + 247 + // SAFETY: The arguments are all valid per the type invariants. 248 + to_result(unsafe { bindings::drm_gem_object_init(dev.as_raw(), obj.obj.get(), size) })?; 249 + 250 + // SAFETY: We never move out of `Self`. 251 + let ptr = KBox::into_raw(unsafe { Pin::into_inner_unchecked(obj) }); 252 + 253 + // SAFETY: `ptr` comes from `KBox::into_raw` and hence can't be NULL. 254 + let ptr = unsafe { NonNull::new_unchecked(ptr) }; 255 + 256 + // SAFETY: We take over the initial reference count from `drm_gem_object_init()`. 257 + Ok(unsafe { ARef::from_raw(ptr) }) 258 + } 259 + 260 + /// Returns the `Device` that owns this GEM object. 261 + pub fn dev(&self) -> &drm::Device<T::Driver> { 262 + // SAFETY: The DRM subsystem guarantees that the `struct drm_device` will live as long as 263 + // the GEM object lives, hence the pointer must be valid. 264 + unsafe { self.dev.as_ref() } 265 + } 266 + 267 + fn as_raw(&self) -> *mut bindings::drm_gem_object { 268 + self.obj.get() 269 + } 270 + 271 + extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) { 272 + // SAFETY: All of our objects are of type `Object<T>`. 273 + let this = unsafe { crate::container_of!(obj, Self, obj) }.cast_mut(); 274 + 275 + // SAFETY: The C code only ever calls this callback with a valid pointer to a `struct 276 + // drm_gem_object`. 277 + unsafe { bindings::drm_gem_object_release(obj) }; 278 + 279 + // SAFETY: All of our objects are allocated via `KBox`, and we're in the 280 + // free callback which guarantees this object has zero remaining references, 281 + // so we can drop it. 282 + let _ = unsafe { KBox::from_raw(this) }; 283 + } 284 + } 285 + 286 + impl<T: DriverObject> super::private::Sealed for Object<T> {} 287 + 288 + impl<T: DriverObject> Deref for Object<T> { 289 + type Target = T; 290 + 291 + fn deref(&self) -> &Self::Target { 292 + &self.data 293 + } 294 + } 295 + 296 + impl<T: DriverObject> AllocImpl for Object<T> { 297 + const ALLOC_OPS: AllocOps = AllocOps { 298 + gem_create_object: None, 299 + prime_handle_to_fd: None, 300 + prime_fd_to_handle: None, 301 + gem_prime_import: None, 302 + gem_prime_import_sg_table: None, 303 + dumb_create: None, 304 + dumb_map_offset: None, 305 + }; 306 + } 307 + 308 + pub(super) const fn create_fops() -> bindings::file_operations { 309 + // SAFETY: As by the type invariant, it is safe to initialize `bindings::file_operations` 310 + // zeroed. 311 + let mut fops: bindings::file_operations = unsafe { core::mem::zeroed() }; 312 + 313 + fops.owner = core::ptr::null_mut(); 314 + fops.open = Some(bindings::drm_open); 315 + fops.release = Some(bindings::drm_release); 316 + fops.unlocked_ioctl = Some(bindings::drm_ioctl); 317 + #[cfg(CONFIG_COMPAT)] 318 + { 319 + fops.compat_ioctl = Some(bindings::drm_compat_ioctl); 320 + } 321 + fops.poll = Some(bindings::drm_poll); 322 + fops.read = Some(bindings::drm_read); 323 + fops.llseek = Some(bindings::noop_llseek); 324 + fops.mmap = Some(bindings::drm_gem_mmap); 325 + fops.fop_flags = bindings::FOP_UNSIGNED_OFFSET; 326 + 327 + fops 328 + }
+162
rust/kernel/drm/ioctl.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR MIT 2 + 3 + //! DRM IOCTL definitions. 4 + //! 5 + //! C header: [`include/linux/drm/drm_ioctl.h`](srctree/include/linux/drm/drm_ioctl.h) 6 + 7 + use crate::ioctl; 8 + 9 + const BASE: u32 = uapi::DRM_IOCTL_BASE as u32; 10 + 11 + /// Construct a DRM ioctl number with no argument. 12 + #[allow(non_snake_case)] 13 + #[inline(always)] 14 + pub const fn IO(nr: u32) -> u32 { 15 + ioctl::_IO(BASE, nr) 16 + } 17 + 18 + /// Construct a DRM ioctl number with a read-only argument. 19 + #[allow(non_snake_case)] 20 + #[inline(always)] 21 + pub const fn IOR<T>(nr: u32) -> u32 { 22 + ioctl::_IOR::<T>(BASE, nr) 23 + } 24 + 25 + /// Construct a DRM ioctl number with a write-only argument. 26 + #[allow(non_snake_case)] 27 + #[inline(always)] 28 + pub const fn IOW<T>(nr: u32) -> u32 { 29 + ioctl::_IOW::<T>(BASE, nr) 30 + } 31 + 32 + /// Construct a DRM ioctl number with a read-write argument. 33 + #[allow(non_snake_case)] 34 + #[inline(always)] 35 + pub const fn IOWR<T>(nr: u32) -> u32 { 36 + ioctl::_IOWR::<T>(BASE, nr) 37 + } 38 + 39 + /// Descriptor type for DRM ioctls. Use the `declare_drm_ioctls!{}` macro to construct them. 40 + pub type DrmIoctlDescriptor = bindings::drm_ioctl_desc; 41 + 42 + /// This is for ioctl which are used for rendering, and require that the file descriptor is either 43 + /// for a render node, or if it’s a legacy/primary node, then it must be authenticated. 44 + pub const AUTH: u32 = bindings::drm_ioctl_flags_DRM_AUTH; 45 + 46 + /// This must be set for any ioctl which can change the modeset or display state. Userspace must 47 + /// call the ioctl through a primary node, while it is the active master. 48 + /// 49 + /// Note that read-only modeset ioctl can also be called by unauthenticated clients, or when a 50 + /// master is not the currently active one. 51 + pub const MASTER: u32 = bindings::drm_ioctl_flags_DRM_MASTER; 52 + 53 + /// Anything that could potentially wreak a master file descriptor needs to have this flag set. 54 + /// 55 + /// Current that’s only for the SETMASTER and DROPMASTER ioctl, which e.g. logind can call to 56 + /// force a non-behaving master (display compositor) into compliance. 57 + /// 58 + /// This is equivalent to callers with the SYSADMIN capability. 59 + pub const ROOT_ONLY: u32 = bindings::drm_ioctl_flags_DRM_ROOT_ONLY; 60 + 61 + /// This is used for all ioctl needed for rendering only, for drivers which support render nodes. 62 + /// This should be all new render drivers, and hence it should be always set for any ioctl with 63 + /// `AUTH` set. Note though that read-only query ioctl might have this set, but have not set 64 + /// DRM_AUTH because they do not require authentication. 65 + pub const RENDER_ALLOW: u32 = bindings::drm_ioctl_flags_DRM_RENDER_ALLOW; 66 + 67 + /// Internal structures used by the `declare_drm_ioctls!{}` macro. Do not use directly. 68 + #[doc(hidden)] 69 + pub mod internal { 70 + pub use bindings::drm_device; 71 + pub use bindings::drm_file; 72 + pub use bindings::drm_ioctl_desc; 73 + } 74 + 75 + /// Declare the DRM ioctls for a driver. 76 + /// 77 + /// Each entry in the list should have the form: 78 + /// 79 + /// `(ioctl_number, argument_type, flags, user_callback),` 80 + /// 81 + /// `argument_type` is the type name within the `bindings` crate. 82 + /// `user_callback` should have the following prototype: 83 + /// 84 + /// ```ignore 85 + /// fn foo(device: &kernel::drm::Device<Self>, 86 + /// data: &Opaque<uapi::argument_type>, 87 + /// file: &kernel::drm::File<Self::File>, 88 + /// ) -> Result<u32> 89 + /// ``` 90 + /// where `Self` is the drm::drv::Driver implementation these ioctls are being declared within. 91 + /// 92 + /// # Examples 93 + /// 94 + /// ```ignore 95 + /// kernel::declare_drm_ioctls! { 96 + /// (FOO_GET_PARAM, drm_foo_get_param, ioctl::RENDER_ALLOW, my_get_param_handler), 97 + /// } 98 + /// ``` 99 + /// 100 + #[macro_export] 101 + macro_rules! declare_drm_ioctls { 102 + ( $(($cmd:ident, $struct:ident, $flags:expr, $func:expr)),* $(,)? ) => { 103 + const IOCTLS: &'static [$crate::drm::ioctl::DrmIoctlDescriptor] = { 104 + use $crate::uapi::*; 105 + const _:() = { 106 + let i: u32 = $crate::uapi::DRM_COMMAND_BASE; 107 + // Assert that all the IOCTLs are in the right order and there are no gaps, 108 + // and that the size of the specified type is correct. 109 + $( 110 + let cmd: u32 = $crate::macros::concat_idents!(DRM_IOCTL_, $cmd); 111 + ::core::assert!(i == $crate::ioctl::_IOC_NR(cmd)); 112 + ::core::assert!(core::mem::size_of::<$crate::uapi::$struct>() == 113 + $crate::ioctl::_IOC_SIZE(cmd)); 114 + let i: u32 = i + 1; 115 + )* 116 + }; 117 + 118 + let ioctls = &[$( 119 + $crate::drm::ioctl::internal::drm_ioctl_desc { 120 + cmd: $crate::macros::concat_idents!(DRM_IOCTL_, $cmd) as u32, 121 + func: { 122 + #[allow(non_snake_case)] 123 + unsafe extern "C" fn $cmd( 124 + raw_dev: *mut $crate::drm::ioctl::internal::drm_device, 125 + raw_data: *mut ::core::ffi::c_void, 126 + raw_file: *mut $crate::drm::ioctl::internal::drm_file, 127 + ) -> core::ffi::c_int { 128 + // SAFETY: 129 + // - The DRM core ensures the device lives while callbacks are being 130 + // called. 131 + // - The DRM device must have been registered when we're called through 132 + // an IOCTL. 133 + // 134 + // FIXME: Currently there is nothing enforcing that the types of the 135 + // dev/file match the current driver these ioctls are being declared 136 + // for, and it's not clear how to enforce this within the type system. 137 + let dev = $crate::drm::device::Device::as_ref(raw_dev); 138 + // SAFETY: The ioctl argument has size `_IOC_SIZE(cmd)`, which we 139 + // asserted above matches the size of this type, and all bit patterns of 140 + // UAPI structs must be valid. 141 + let data = unsafe { 142 + &*(raw_data as *const $crate::types::Opaque<$crate::uapi::$struct>) 143 + }; 144 + // SAFETY: This is just the DRM file structure 145 + let file = unsafe { $crate::drm::File::as_ref(raw_file) }; 146 + 147 + match $func(dev, data, file) { 148 + Err(e) => e.to_errno(), 149 + Ok(i) => i.try_into() 150 + .unwrap_or($crate::error::code::ERANGE.to_errno()), 151 + } 152 + } 153 + Some($cmd) 154 + }, 155 + flags: $flags, 156 + name: $crate::c_str!(::core::stringify!($cmd)).as_char_ptr(), 157 + } 158 + ),*]; 159 + ioctls 160 + }; 161 + }; 162 + }
+19
rust/kernel/drm/mod.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR MIT 2 + 3 + //! DRM subsystem abstractions. 4 + 5 + pub mod device; 6 + pub mod driver; 7 + pub mod file; 8 + pub mod gem; 9 + pub mod ioctl; 10 + 11 + pub use self::device::Device; 12 + pub use self::driver::Driver; 13 + pub use self::driver::DriverInfo; 14 + pub use self::driver::Registration; 15 + pub use self::file::File; 16 + 17 + pub(crate) mod private { 18 + pub trait Sealed {} 19 + }
+4
rust/kernel/lib.rs
··· 38 38 pub use ffi; 39 39 40 40 pub mod alloc; 41 + #[cfg(CONFIG_AUXILIARY_BUS)] 42 + pub mod auxiliary; 41 43 #[cfg(CONFIG_BLOCK)] 42 44 pub mod block; 43 45 #[doc(hidden)] ··· 50 48 pub mod devres; 51 49 pub mod dma; 52 50 pub mod driver; 51 + #[cfg(CONFIG_DRM = "y")] 52 + pub mod drm; 53 53 pub mod error; 54 54 pub mod faux; 55 55 #[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)]
+32 -23
rust/kernel/pci.rs
··· 6 6 7 7 use crate::{ 8 8 alloc::flags::*, 9 - bindings, device, 9 + bindings, container_of, device, 10 10 device_id::RawDeviceId, 11 11 devres::Devres, 12 12 driver, ··· 360 360 } 361 361 } 362 362 363 - impl Device { 363 + impl<Ctx: device::DeviceContext> Device<Ctx> { 364 364 fn as_raw(&self) -> *mut bindings::pci_dev { 365 365 self.0.get() 366 366 } 367 + } 367 368 369 + impl Device { 368 370 /// Returns the PCI vendor ID. 369 371 pub fn vendor_id(&self) -> u16 { 370 372 // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`. ··· 390 388 // - by its type invariant `self.as_raw` is always a valid pointer to a `struct pci_dev`. 391 389 Ok(unsafe { bindings::pci_resource_len(self.as_raw(), bar.try_into()?) }) 392 390 } 391 + } 393 392 393 + impl Device<device::Bound> { 394 394 /// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks 395 395 /// can be performed on compile time for offsets (plus the requested type size) < SIZE. 396 396 pub fn iomap_region_sized<const SIZE: usize>( ··· 426 422 } 427 423 } 428 424 429 - impl Deref for Device<device::Core> { 430 - type Target = Device; 431 - 432 - fn deref(&self) -> &Self::Target { 433 - let ptr: *const Self = self; 434 - 435 - // CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::pci_dev>`. 436 - let ptr = ptr.cast::<Device>(); 437 - 438 - // SAFETY: `ptr` was derived from `&self`. 439 - unsafe { &*ptr } 440 - } 441 - } 442 - 443 - impl From<&Device<device::Core>> for ARef<Device> { 444 - fn from(dev: &Device<device::Core>) -> Self { 445 - (&**dev).into() 446 - } 447 - } 425 + // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic 426 + // argument. 427 + kernel::impl_device_context_deref!(unsafe { Device }); 428 + kernel::impl_device_context_into_aref!(Device); 448 429 449 430 // SAFETY: Instances of `Device` are always reference-counted. 450 431 unsafe impl crate::types::AlwaysRefCounted for Device { ··· 444 455 } 445 456 } 446 457 447 - impl AsRef<device::Device> for Device { 448 - fn as_ref(&self) -> &device::Device { 458 + impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> { 459 + fn as_ref(&self) -> &device::Device<Ctx> { 449 460 // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid 450 461 // `struct pci_dev`. 451 462 let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; 452 463 453 464 // SAFETY: `dev` points to a valid `struct device`. 454 465 unsafe { device::Device::as_ref(dev) } 466 + } 467 + } 468 + 469 + impl<Ctx: device::DeviceContext> TryFrom<&device::Device<Ctx>> for &Device<Ctx> { 470 + type Error = kernel::error::Error; 471 + 472 + fn try_from(dev: &device::Device<Ctx>) -> Result<Self, Self::Error> { 473 + // SAFETY: By the type invariant of `Device`, `dev.as_raw()` is a valid pointer to a 474 + // `struct device`. 475 + if !unsafe { bindings::dev_is_pci(dev.as_raw()) } { 476 + return Err(EINVAL); 477 + } 478 + 479 + // SAFETY: We've just verified that the bus type of `dev` equals `bindings::pci_bus_type`, 480 + // hence `dev` must be embedded in a valid `struct pci_dev` as guaranteed by the 481 + // corresponding C code. 482 + let pdev = unsafe { container_of!(dev.as_raw(), bindings::pci_dev, dev) }; 483 + 484 + // SAFETY: `pdev` is a valid pointer to a `struct pci_dev`. 485 + Ok(unsafe { &*pdev.cast() }) 455 486 } 456 487 } 457 488
+29 -25
rust/kernel/platform.rs
··· 5 5 //! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h) 6 6 7 7 use crate::{ 8 - bindings, device, driver, 8 + bindings, container_of, device, driver, 9 9 error::{to_result, Result}, 10 10 of, 11 11 prelude::*, 12 12 str::CStr, 13 - types::{ARef, ForeignOwnable, Opaque}, 13 + types::{ForeignOwnable, Opaque}, 14 14 ThisModule, 15 15 }; 16 16 17 17 use core::{ 18 18 marker::PhantomData, 19 - ops::Deref, 20 19 ptr::{addr_of_mut, NonNull}, 21 20 }; 22 21 ··· 183 184 PhantomData<Ctx>, 184 185 ); 185 186 186 - impl Device { 187 + impl<Ctx: device::DeviceContext> Device<Ctx> { 187 188 fn as_raw(&self) -> *mut bindings::platform_device { 188 189 self.0.get() 189 190 } 190 191 } 191 192 192 - impl Deref for Device<device::Core> { 193 - type Target = Device; 194 - 195 - fn deref(&self) -> &Self::Target { 196 - let ptr: *const Self = self; 197 - 198 - // CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::platform_device>`. 199 - let ptr = ptr.cast::<Device>(); 200 - 201 - // SAFETY: `ptr` was derived from `&self`. 202 - unsafe { &*ptr } 203 - } 204 - } 205 - 206 - impl From<&Device<device::Core>> for ARef<Device> { 207 - fn from(dev: &Device<device::Core>) -> Self { 208 - (&**dev).into() 209 - } 210 - } 193 + // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic 194 + // argument. 195 + kernel::impl_device_context_deref!(unsafe { Device }); 196 + kernel::impl_device_context_into_aref!(Device); 211 197 212 198 // SAFETY: Instances of `Device` are always reference-counted. 213 199 unsafe impl crate::types::AlwaysRefCounted for Device { ··· 207 223 } 208 224 } 209 225 210 - impl AsRef<device::Device> for Device { 211 - fn as_ref(&self) -> &device::Device { 226 + impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> { 227 + fn as_ref(&self) -> &device::Device<Ctx> { 212 228 // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid 213 229 // `struct platform_device`. 214 230 let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; 215 231 216 232 // SAFETY: `dev` points to a valid `struct device`. 217 233 unsafe { device::Device::as_ref(dev) } 234 + } 235 + } 236 + 237 + impl<Ctx: device::DeviceContext> TryFrom<&device::Device<Ctx>> for &Device<Ctx> { 238 + type Error = kernel::error::Error; 239 + 240 + fn try_from(dev: &device::Device<Ctx>) -> Result<Self, Self::Error> { 241 + // SAFETY: By the type invariant of `Device`, `dev.as_raw()` is a valid pointer to a 242 + // `struct device`. 243 + if !unsafe { bindings::dev_is_platform(dev.as_raw()) } { 244 + return Err(EINVAL); 245 + } 246 + 247 + // SAFETY: We've just verified that the bus type of `dev` equals 248 + // `bindings::platform_bus_type`, hence `dev` must be embedded in a valid 249 + // `struct platform_device` as guaranteed by the corresponding C code. 250 + let pdev = unsafe { container_of!(dev.as_raw(), bindings::platform_device, dev) }; 251 + 252 + // SAFETY: `pdev` is a valid pointer to a `struct platform_device`. 253 + Ok(unsafe { &*pdev.cast() }) 218 254 } 219 255 } 220 256
+28
rust/kernel/revocable.rs
··· 123 123 } 124 124 } 125 125 126 + /// Tries to access the wrapped object and run a closure on it while the guard is held. 127 + /// 128 + /// This is a convenience method to run short non-sleepable code blocks while ensuring the 129 + /// guard is dropped afterwards. [`Self::try_access`] carries the risk that the caller will 130 + /// forget to explicitly drop that returned guard before calling sleepable code; this method 131 + /// adds an extra safety to make sure it doesn't happen. 132 + /// 133 + /// Returns [`None`] if the object has been revoked and is therefore no longer accessible, or 134 + /// the result of the closure wrapped in [`Some`]. If the closure returns a [`Result`] then the 135 + /// return type becomes `Option<Result<>>`, which can be inconvenient. Users are encouraged to 136 + /// define their own macro that turns the [`Option`] into a proper error code and flattens the 137 + /// inner result into it if it makes sense within their subsystem. 138 + pub fn try_access_with<R, F: FnOnce(&T) -> R>(&self, f: F) -> Option<R> { 139 + self.try_access().map(|t| f(&*t)) 140 + } 141 + 142 + /// Directly access the revocable wrapped object. 143 + /// 144 + /// # Safety 145 + /// 146 + /// The caller must ensure this [`Revocable`] instance hasn't been revoked and won't be revoked 147 + /// as long as the returned `&T` lives. 148 + pub unsafe fn access(&self) -> &T { 149 + // SAFETY: By the safety requirement of this function it is guaranteed that 150 + // `self.data.get()` is a valid pointer to an instance of `T`. 151 + unsafe { &*self.data.get() } 152 + } 153 + 126 154 /// # Safety 127 155 /// 128 156 /// Callers must ensure that there are no more concurrent users of the revocable object.
+8
rust/kernel/types.rs
··· 329 329 } 330 330 } 331 331 332 + /// Creates a new zeroed opaque value. 333 + pub const fn zeroed() -> Self { 334 + Self { 335 + value: UnsafeCell::new(MaybeUninit::zeroed()), 336 + _pin: PhantomPinned, 337 + } 338 + } 339 + 332 340 /// Create an opaque pin-initializer from the given pin-initializer. 333 341 pub fn pin_init(slot: impl PinInit<T>) -> impl PinInit<Self> { 334 342 Self::ffi_init(|ptr: *mut T| {
+2
rust/uapi/uapi_helper.h
··· 7 7 */ 8 8 9 9 #include <uapi/asm-generic/ioctl.h> 10 + #include <uapi/drm/drm.h> 11 + #include <uapi/drm/nova_drm.h> 10 12 #include <uapi/linux/mdio.h> 11 13 #include <uapi/linux/mii.h> 12 14 #include <uapi/linux/ethtool.h>
+12
samples/rust/Kconfig
··· 82 82 83 83 If unsure, say N. 84 84 85 + config SAMPLE_RUST_DRIVER_AUXILIARY 86 + tristate "Auxiliary Driver" 87 + depends on PCI 88 + select AUXILIARY_BUS 89 + help 90 + This option builds the Rust auxiliary driver sample. 91 + 92 + To compile this as a module, choose M here: 93 + the module will be called rust_driver_auxiliary. 94 + 95 + If unsure, say N. 96 + 85 97 config SAMPLE_RUST_HOSTPROGS 86 98 bool "Host programs" 87 99 help
+1
samples/rust/Makefile
··· 8 8 obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o 9 9 obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o 10 10 obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX) += rust_driver_faux.o 11 + obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY) += rust_driver_auxiliary.o 11 12 12 13 rust_print-y := rust_print_main.o rust_print_events.o 13 14
+120
samples/rust/rust_driver_auxiliary.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Rust auxiliary driver sample (based on a PCI driver for QEMU's `pci-testdev`). 4 + //! 5 + //! To make this driver probe, QEMU must be run with `-device pci-testdev`. 6 + 7 + use kernel::{ 8 + auxiliary, bindings, c_str, device::Core, driver, error::Error, pci, prelude::*, str::CStr, 9 + InPlaceModule, 10 + }; 11 + 12 + use pin_init::PinInit; 13 + 14 + const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME; 15 + const AUXILIARY_NAME: &CStr = c_str!("auxiliary"); 16 + 17 + struct AuxiliaryDriver; 18 + 19 + kernel::auxiliary_device_table!( 20 + AUX_TABLE, 21 + MODULE_AUX_TABLE, 22 + <AuxiliaryDriver as auxiliary::Driver>::IdInfo, 23 + [(auxiliary::DeviceId::new(MODULE_NAME, AUXILIARY_NAME), ())] 24 + ); 25 + 26 + impl auxiliary::Driver for AuxiliaryDriver { 27 + type IdInfo = (); 28 + 29 + const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE; 30 + 31 + fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> { 32 + dev_info!( 33 + adev.as_ref(), 34 + "Probing auxiliary driver for auxiliary device with id={}\n", 35 + adev.id() 36 + ); 37 + 38 + ParentDriver::connect(adev)?; 39 + 40 + let this = KBox::new(Self, GFP_KERNEL)?; 41 + 42 + Ok(this.into()) 43 + } 44 + } 45 + 46 + struct ParentDriver { 47 + _reg: [auxiliary::Registration; 2], 48 + } 49 + 50 + kernel::pci_device_table!( 51 + PCI_TABLE, 52 + MODULE_PCI_TABLE, 53 + <ParentDriver as pci::Driver>::IdInfo, 54 + [( 55 + pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5), 56 + () 57 + )] 58 + ); 59 + 60 + impl pci::Driver for ParentDriver { 61 + type IdInfo = (); 62 + 63 + const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; 64 + 65 + fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> { 66 + let this = KBox::new( 67 + Self { 68 + _reg: [ 69 + auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME)?, 70 + auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME)?, 71 + ], 72 + }, 73 + GFP_KERNEL, 74 + )?; 75 + 76 + Ok(this.into()) 77 + } 78 + } 79 + 80 + impl ParentDriver { 81 + fn connect(adev: &auxiliary::Device) -> Result<()> { 82 + let parent = adev.parent().ok_or(EINVAL)?; 83 + let pdev: &pci::Device = parent.try_into()?; 84 + 85 + dev_info!( 86 + adev.as_ref(), 87 + "Connect auxiliary {} with parent: VendorID={:#x}, DeviceID={:#x}\n", 88 + adev.id(), 89 + pdev.vendor_id(), 90 + pdev.device_id() 91 + ); 92 + 93 + Ok(()) 94 + } 95 + } 96 + 97 + #[pin_data] 98 + struct SampleModule { 99 + #[pin] 100 + _pci_driver: driver::Registration<pci::Adapter<ParentDriver>>, 101 + #[pin] 102 + _aux_driver: driver::Registration<auxiliary::Adapter<AuxiliaryDriver>>, 103 + } 104 + 105 + impl InPlaceModule for SampleModule { 106 + fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, Error> { 107 + try_pin_init!(Self { 108 + _pci_driver <- driver::Registration::new(MODULE_NAME, module), 109 + _aux_driver <- driver::Registration::new(MODULE_NAME, module), 110 + }) 111 + } 112 + } 113 + 114 + module! { 115 + type: SampleModule, 116 + name: "rust_driver_auxiliary", 117 + author: "Danilo Krummrich", 118 + description: "Rust auxiliary driver", 119 + license: "GPL v2", 120 + }
+2 -3
samples/rust/rust_driver_pci.rs
··· 83 83 GFP_KERNEL, 84 84 )?; 85 85 86 - let bar = drvdata.bar.try_access().ok_or(ENXIO)?; 87 - 86 + let bar = drvdata.bar.access(pdev.as_ref())?; 88 87 dev_info!( 89 88 pdev.as_ref(), 90 89 "pci-testdev data-match count: {}\n", 91 - Self::testdev(info, &bar)? 90 + Self::testdev(info, bar)? 92 91 ); 93 92 94 93 Ok(drvdata.into())