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

Configure Feed

Select the types of activity you want to include in your feed.

rust: auxiliary: unregister on parent device unbind

Guarantee that an auxiliary driver will be unbound before its parent is
unbound; there is no point in operating an auxiliary device whose parent
has been unbound.

In practice, this guarantee allows us to assume that for a bound
auxiliary device, also the parent device is bound.

This is useful when an auxiliary driver calls into its parent, since it
allows the parent to directly access device resources and its device
private data due to the guaranteed bound device context.

Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

+63 -45
+5 -3
drivers/gpu/nova-core/driver.rs
··· 3 3 use kernel::{ 4 4 auxiliary, c_str, 5 5 device::Core, 6 + devres::Devres, 6 7 pci, 7 8 pci::{Class, ClassMask, Vendor}, 8 9 prelude::*, ··· 17 16 pub(crate) struct NovaCore { 18 17 #[pin] 19 18 pub(crate) gpu: Gpu, 20 - _reg: auxiliary::Registration, 19 + #[pin] 20 + _reg: Devres<auxiliary::Registration>, 21 21 } 22 22 23 23 const BAR0_SIZE: usize = SZ_16M; ··· 67 65 68 66 Ok(try_pin_init!(Self { 69 67 gpu <- Gpu::new(pdev, bar.clone(), bar.access(pdev.as_ref())?), 70 - _reg: auxiliary::Registration::new( 68 + _reg <- auxiliary::Registration::new( 71 69 pdev.as_ref(), 72 70 c_str!("nova-drm"), 73 71 0, // TODO[XARR]: Once it lands, use XArray; for now we don't use the ID. 74 72 crate::MODULE_NAME 75 - )?, 73 + ), 76 74 })) 77 75 }) 78 76 }
+48 -35
rust/kernel/auxiliary.rs
··· 7 7 use crate::{ 8 8 bindings, container_of, device, 9 9 device_id::{RawDeviceId, RawDeviceIdIndex}, 10 + devres::Devres, 10 11 driver, 11 12 error::{from_result, to_result, Result}, 12 13 prelude::*, ··· 280 279 281 280 /// The registration of an auxiliary device. 282 281 /// 283 - /// This type represents the registration of a [`struct auxiliary_device`]. When an instance of this 284 - /// type is dropped, its respective auxiliary device will be unregistered from the system. 282 + /// This type represents the registration of a [`struct auxiliary_device`]. When its parent device 283 + /// is unbound, the corresponding auxiliary device will be unregistered from the system. 285 284 /// 286 285 /// # Invariants 287 286 /// ··· 291 290 292 291 impl Registration { 293 292 /// Create and register a new auxiliary device. 294 - pub fn new(parent: &device::Device, name: &CStr, id: u32, modname: &CStr) -> Result<Self> { 295 - let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?; 296 - let adev = boxed.get(); 293 + pub fn new<'a>( 294 + parent: &'a device::Device<device::Bound>, 295 + name: &'a CStr, 296 + id: u32, 297 + modname: &'a CStr, 298 + ) -> impl PinInit<Devres<Self>, Error> + 'a { 299 + pin_init::pin_init_scope(move || { 300 + let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?; 301 + let adev = boxed.get(); 297 302 298 - // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. 299 - unsafe { 300 - (*adev).dev.parent = parent.as_raw(); 301 - (*adev).dev.release = Some(Device::release); 302 - (*adev).name = name.as_char_ptr(); 303 - (*adev).id = id; 304 - } 303 + // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. 304 + unsafe { 305 + (*adev).dev.parent = parent.as_raw(); 306 + (*adev).dev.release = Some(Device::release); 307 + (*adev).name = name.as_char_ptr(); 308 + (*adev).id = id; 309 + } 305 310 306 - // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, 307 - // which has not been initialized yet. 308 - unsafe { bindings::auxiliary_device_init(adev) }; 309 - 310 - // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be freed 311 - // by `Device::release` when the last reference to the `struct auxiliary_device` is dropped. 312 - let _ = KBox::into_raw(boxed); 313 - 314 - // SAFETY: 315 - // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which has 316 - // been initialialized, 317 - // - `modname.as_char_ptr()` is a NULL terminated string. 318 - let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; 319 - if ret != 0 { 320 311 // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, 321 - // which has been initialialized. 322 - unsafe { bindings::auxiliary_device_uninit(adev) }; 312 + // which has not been initialized yet. 313 + unsafe { bindings::auxiliary_device_init(adev) }; 323 314 324 - return Err(Error::from_errno(ret)); 325 - } 315 + // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be 316 + // freed by `Device::release` when the last reference to the `struct auxiliary_device` 317 + // is dropped. 318 + let _ = KBox::into_raw(boxed); 326 319 327 - // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated successfully. 328 - // 329 - // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is called, 330 - // which happens in `Self::drop()`. 331 - Ok(Self(unsafe { NonNull::new_unchecked(adev) })) 320 + // SAFETY: 321 + // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which 322 + // has been initialized, 323 + // - `modname.as_char_ptr()` is a NULL terminated string. 324 + let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; 325 + if ret != 0 { 326 + // SAFETY: `adev` is guaranteed to be a valid pointer to a 327 + // `struct auxiliary_device`, which has been initialized. 328 + unsafe { bindings::auxiliary_device_uninit(adev) }; 329 + 330 + return Err(Error::from_errno(ret)); 331 + } 332 + 333 + // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated 334 + // successfully. 335 + // 336 + // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is 337 + // called, which happens in `Self::drop()`. 338 + Ok(Devres::new( 339 + parent, 340 + Self(unsafe { NonNull::new_unchecked(adev) }), 341 + )) 342 + }) 332 343 } 333 344 } 334 345
+10 -7
samples/rust/rust_driver_auxiliary.rs
··· 5 5 //! To make this driver probe, QEMU must be run with `-device pci-testdev`. 6 6 7 7 use kernel::{ 8 - auxiliary, c_str, device::Core, driver, error::Error, pci, prelude::*, InPlaceModule, 8 + auxiliary, c_str, device::Core, devres::Devres, driver, error::Error, pci, prelude::*, 9 + InPlaceModule, 9 10 }; 10 11 11 12 use pin_init::PinInit; ··· 41 40 } 42 41 } 43 42 43 + #[pin_data] 44 44 struct ParentDriver { 45 - _reg: [auxiliary::Registration; 2], 45 + #[pin] 46 + _reg0: Devres<auxiliary::Registration>, 47 + #[pin] 48 + _reg1: Devres<auxiliary::Registration>, 46 49 } 47 50 48 51 kernel::pci_device_table!( ··· 62 57 const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; 63 58 64 59 fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { 65 - Ok(Self { 66 - _reg: [ 67 - auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME)?, 68 - auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME)?, 69 - ], 60 + try_pin_init!(Self { 61 + _reg0 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME), 62 + _reg1 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME), 70 63 }) 71 64 } 72 65 }