From: Gary Guo <[email protected]> Nova core's driver data makes use of a few unsafe self-references for device resources. Replace them with pin-init's self reference feature instead.
`auxiliary::Registration` is only allowed to capture a single lifetime, but it needs to capture `&'gpu Gpu<'bar>`. However, we cannot use coercion here as `Gpu` is invariant over `'bar`. As we know that `'bar` outlives `'gpu`, use pin-init's existential lifetime to erase the `'bar` lifetime in `NovaCoreApi`. Swap bar1 and bar0's drop order to make pin-init happy. Signed-off-by: Gary Guo <[email protected]> --- drivers/gpu/nova-core/api.rs | 15 ++++++++++----- drivers/gpu/nova-core/driver.rs | 27 ++++++++------------------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/nova-core/api.rs b/drivers/gpu/nova-core/api.rs index 29207c4bb743..62b1c8fe7125 100644 --- a/drivers/gpu/nova-core/api.rs +++ b/drivers/gpu/nova-core/api.rs @@ -22,9 +22,14 @@ }; /// API handle for the auxiliary bus child drivers to interact with nova-core. -pub struct NovaCoreApi<'bound> { - pub(crate) gpu: Pin<&'bound Gpu<'bound>>, - pub(crate) pdev: &'bound pci::Device<Bound>, +#[pin_data] +pub struct NovaCoreApi<'gpu> +where + exists<'bar>: 'gpu, +{ + #[uses('bar: invariant)] + pub(crate) gpu: Pin<&'gpu Gpu<'bar>>, + pub(crate) pdev: &'gpu pci::Device<Bound>, } impl NovaCoreApi<'_> { @@ -36,12 +41,12 @@ pub fn of(adev: &auxiliary::Device<Bound>) -> Result<NovaCoreApiHandle<'_>> { /// Returns the GPU [`GetGspStaticInfoReply`]. pub fn gsp_static_info(&self) -> &GetGspStaticInfoReply { - &self.gpu.gsp_static_info + self.with_gpu(|gpu| &gpu.gsp_static_info) } /// Returns the GPU [`Spec`]. pub fn spec(&self) -> &Spec { - &self.gpu.spec + self.with_gpu(|gpu| &gpu.spec) } /// Returns the size of the PCIe BAR used for accessing VRAM, typically diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 560a70c4f5a7..7ddde686879f 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -33,11 +33,13 @@ #[pin_data] pub(crate) struct NovaCore<'bound> { #[allow(clippy::type_complexity)] - _reg: auxiliary::Registration<'bound, ForLt!(NovaCoreApi<'_>)>, + #[uses('gpu: invariant)] + _reg: auxiliary::Registration<'gpu, ForLt!(NovaCoreApi<'_>)>, #[pin] - pub(crate) gpu: Gpu<'bound>, - bar: pci::Bar<'bound, BAR0_SIZE>, + #[uses('bar1: invariant, 'bar: invariant)] + pub(crate) gpu: Gpu<'bar1>, bar1: pci::Bar<'bound>, + bar: pci::Bar<'bound, BAR0_SIZE>, } pub(crate) struct NovaCoreDriver; @@ -129,13 +131,10 @@ fn probe<'bound>( crate::irq::doorbell_test::run_selftest(pdev, bar, spec.chipset)?; }, - // TODO: Use self-referential pin-init syntax once available. gpu <- Gpu::new( pdev, - // SAFETY: `bar` is initialized above, pinned, and outlives `gpu`. - unsafe { &*core::ptr::from_ref(bar) }, - // SAFETY: `bar1` is initialized above, pinned, and outlives `gpu`. - unsafe { &*core::ptr::from_ref(bar1) }, + bar, + bar1, ).pin_chain(|_gpu| { #[cfg(CONFIG_NOVA_CORE_SELFTESTS)] _gpu.run_selftests(pdev); @@ -143,16 +142,6 @@ fn probe<'bound>( }), _reg: { - // TODO: Use `&gpu` self-referential pin-init syntax once available. - // - // SAFETY: `gpu` is initialized before this expression is evaluated - // (`try_pin_init!()` initializes fields in initializer 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 { @@ -164,7 +153,7 @@ fn probe<'bound>( // never recycles IDs. AUXILIARY_ID_COUNTER.fetch_add(1, Relaxed), crate::MODULE_NAME, - NovaCoreApi { gpu, pdev }, + pin_init!(NovaCoreApi { gpu, pdev }), )? } }, base-commit: 2efb7a11f1aa4d2dc285fe2680cca22cb9f72f64 -- 2.54.0
