Nova core will be used to export core functionality to other drivers which will bind to it via auxiliary bus devices. Add a NovaCoreApi type which drivers can use to call nova-core methods.
Auxiliary bus drivers can obtain a handle to call nova-core methods on a particular GPU using NovaCoreApi::of(). This takes a reference to a bound auxiliary bus device and returns a handle to NovaCoreApi. Signed-off-by: Alistair Popple <[email protected]> --- Changes since v1: - Rework unsafe pin-init to make safety comments clearer, suggested by Danilo. - s/allow(dead_code)/expect(unused)/ --- drivers/gpu/nova-core/api.rs | 29 +++++++++++++++++++++ drivers/gpu/nova-core/driver.rs | 42 ++++++++++++++++++++++-------- drivers/gpu/nova-core/gsp/hal.rs | 2 +- drivers/gpu/nova-core/nova_core.rs | 1 + 4 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 drivers/gpu/nova-core/api.rs diff --git a/drivers/gpu/nova-core/api.rs b/drivers/gpu/nova-core/api.rs new file mode 100644 index 000000000000..610cfc01111e --- /dev/null +++ b/drivers/gpu/nova-core/api.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Nova-core auxbus data. Contains all the methods used by the auxbus drivers +//! to interact with nova-core. + +use core::pin::Pin; + +use kernel::{ + auxiliary, + device::Bound, + prelude::*, + types::CovariantForLt, // +}; + +use crate::gpu::Gpu; + +/// API handle for the auxiliary bus child drivers to interact with nova-core. +pub struct NovaCoreApi<'bound> { + #[expect(unused)] + pub(crate) gpu: Pin<&'bound Gpu<'bound>>, +} + +impl NovaCoreApi<'_> { + /// Obtain a [`NovaCoreApi`] handle from an auxiliary device registered + /// by nova-core. + pub fn of(adev: &auxiliary::Device<Bound>) -> Result<Pin<&NovaCoreApi<'_>>> { + adev.registration_data::<CovariantForLt!(NovaCoreApi<'_>)>() + } +} diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 48380ac15f68..a5dabc84fbc6 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -18,6 +18,7 @@ types::CovariantForLt, }; +use crate::api::NovaCoreApi; use crate::gpu::Gpu; /// Counter for generating unique auxiliary device IDs. @@ -25,11 +26,14 @@ #[pin_data] pub(crate) struct NovaCore<'bound> { + // Fields are dropped in declaration order: unregister the auxiliary + // device before dropping `gpu`, and drop `gpu` before `bar` because `Gpu` + // borrows `bar`. + #[allow(clippy::type_complexity)] + _reg: auxiliary::Registration<'bound, CovariantForLt!(NovaCoreApi<'_>)>, #[pin] pub(crate) gpu: Gpu<'bound>, bar: pci::Bar<'bound, BAR0_SIZE>, - #[allow(clippy::type_complexity)] - _reg: auxiliary::Registration<'bound, CovariantForLt!(())>, } pub(crate) struct NovaCoreDriver; @@ -86,15 +90,31 @@ fn probe<'bound>( // (`try_pin_init!()` initializes fields in declaration order), lives at a pinned // stable address, and is dropped after `gpu` (struct field drop order). gpu <- Gpu::new(pdev, unsafe { &*core::ptr::from_ref(bar) }), - _reg: auxiliary::Registration::new( - pdev.as_ref(), - c"nova-drm", - // TODO[XARR]: Use XArray or perhaps IDA for proper ID allocation/recycling. For - // now, use a simple atomic counter that never recycles IDs. - AUXILIARY_ID_COUNTER.fetch_add(1, Relaxed), - crate::MODULE_NAME, - (), - )?, + + _reg: { + // SAFETY: `gpu` is initialized before this expression is evaluated + // (`try_pin_init!()` initializes fields in declaration order), lives at + // a pinned stable address, and is dropped after `_reg` (struct field + // drop order). + let gpu = unsafe { + Pin::new_unchecked(&*core::ptr::from_ref(gpu.as_ref().get_ref())) + }; + + // SAFETY: `NovaCore` is dropped when the device is unbound; + // i.e. `mem::forget()` is never called on it. + unsafe { + auxiliary::Registration::new_with_lt( + pdev.as_ref(), + c"nova-drm", + // TODO[XARR]: Use XArray or perhaps IDA for proper ID + // allocation/recycling. For now, use a simple atomic counter that + // never recycles IDs. + AUXILIARY_ID_COUNTER.fetch_add(1, Relaxed), + crate::MODULE_NAME, + NovaCoreApi { gpu }, + )? + } + }, })) }) } diff --git a/drivers/gpu/nova-core/gsp/hal.rs b/drivers/gpu/nova-core/gsp/hal.rs index d3e47ef206de..06647b2b7894 100644 --- a/drivers/gpu/nova-core/gsp/hal.rs +++ b/drivers/gpu/nova-core/gsp/hal.rs @@ -36,7 +36,7 @@ /// The GSP unload code might run in a situation where we cannot load firmware dynamically (e.g. /// because we are in shutdown and the file system is not accessible anymore). Thus, the firmware /// required for unloading is prepared at load time, and stored here until it needs to be run. -pub(super) trait UnloadBundle: Send { +pub(super) trait UnloadBundle: Send + Sync { /// Performs the steps required to properly reset the GSP after it has been stopped. fn run( &self, diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs index 735b8e17c6b6..2d48d16a6ee8 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -13,6 +13,7 @@ #[macro_use] mod bitfield; +pub mod api; mod driver; mod falcon; mod fb; -- 2.54.0
