mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
rust: auxiliary: sample: demonstrate ForLt with invariant Mutex type
Extend the auxiliary driver sample to demonstrate both access patterns:
- registration_data() with CovariantForLt!(Data<'_>) for the covariant
data type that holds a plain &'bound reference.
- registration_data_with() with ForLt!(MutexData<'_>) for an invariant
data type that wraps a Mutex<&'bound Device>. Since Mutex<T> is
invariant over T, MutexData cannot implement CovariantForLt and must
use the closure-based accessor.
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Link: https://patch.msgid.link/20260626183630.2585057-5-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
@@ -11,14 +11,21 @@ use kernel::{
|
||||
Core, //
|
||||
},
|
||||
driver,
|
||||
new_mutex,
|
||||
pci,
|
||||
prelude::*,
|
||||
types::CovariantForLt,
|
||||
sync::Mutex,
|
||||
types::{
|
||||
CovariantForLt,
|
||||
ForLt, //
|
||||
},
|
||||
InPlaceModule, //
|
||||
};
|
||||
|
||||
const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME;
|
||||
const AUXILIARY_NAME: &CStr = c"auxiliary";
|
||||
const COVARIANT_DEV_ID: u32 = 0;
|
||||
const INVARIANT_DEV_ID: u32 = 1;
|
||||
|
||||
struct AuxiliaryDriver;
|
||||
|
||||
@@ -56,12 +63,26 @@ struct Data<'bound> {
|
||||
parent: &'bound pci::Device<Bound>,
|
||||
}
|
||||
|
||||
/// Registration data with interior mutability.
|
||||
///
|
||||
/// `Mutex<&'bound T>` is invariant over `'bound`, so this type cannot implement
|
||||
/// [`CovariantForLt`](trait@CovariantForLt). Access must go through the closure-based
|
||||
/// [`auxiliary::Device::registration_data_with()`].
|
||||
#[pin_data]
|
||||
struct MutexData<'bound> {
|
||||
#[pin]
|
||||
parent: Mutex<&'bound pci::Device<Bound>>,
|
||||
index: u32,
|
||||
}
|
||||
|
||||
struct ParentDriver;
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
#[pin_data]
|
||||
struct ParentData<'bound> {
|
||||
_reg0: auxiliary::Registration<'bound, CovariantForLt!(Data<'_>)>,
|
||||
_reg1: auxiliary::Registration<'bound, CovariantForLt!(Data<'_>)>,
|
||||
#[pin]
|
||||
_reg1: auxiliary::Registration<'bound, ForLt!(MutexData<'_>)>,
|
||||
}
|
||||
|
||||
kernel::pci_device_table!(
|
||||
@@ -81,17 +102,17 @@ impl pci::Driver for ParentDriver {
|
||||
pdev: &'bound pci::Device<Core<'_>>,
|
||||
_info: &'bound Self::IdInfo,
|
||||
) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
|
||||
Ok(ParentData {
|
||||
try_pin_init!(ParentData {
|
||||
// SAFETY: `ParentData` is the driver's private data, which is dropped when the
|
||||
// device is unbound; i.e. `mem::forget()` is never called on it.
|
||||
_reg0: unsafe {
|
||||
auxiliary::Registration::new_with_lt(
|
||||
pdev.as_ref(),
|
||||
AUXILIARY_NAME,
|
||||
0,
|
||||
COVARIANT_DEV_ID,
|
||||
MODULE_NAME,
|
||||
Data {
|
||||
index: 0,
|
||||
index: COVARIANT_DEV_ID,
|
||||
parent: pdev,
|
||||
},
|
||||
)?
|
||||
@@ -101,12 +122,16 @@ impl pci::Driver for ParentDriver {
|
||||
auxiliary::Registration::new_with_lt(
|
||||
pdev.as_ref(),
|
||||
AUXILIARY_NAME,
|
||||
1,
|
||||
INVARIANT_DEV_ID,
|
||||
MODULE_NAME,
|
||||
Data {
|
||||
index: 1,
|
||||
parent: pdev,
|
||||
},
|
||||
pin_init!(MutexData {
|
||||
parent <- {
|
||||
let pdev: &pci::Device<Bound> = pdev;
|
||||
|
||||
new_mutex!(pdev)
|
||||
},
|
||||
index: INVARIANT_DEV_ID,
|
||||
}),
|
||||
)?
|
||||
},
|
||||
})
|
||||
@@ -115,22 +140,39 @@ impl pci::Driver for ParentDriver {
|
||||
|
||||
impl ParentDriver {
|
||||
fn connect(adev: &auxiliary::Device<Bound>) -> Result {
|
||||
let data = adev.registration_data::<CovariantForLt!(Data<'_>)>()?;
|
||||
let pdev = data.parent;
|
||||
match adev.id() {
|
||||
// CovariantForLt types can use the direct-reference accessor.
|
||||
COVARIANT_DEV_ID => {
|
||||
let data = adev.registration_data::<CovariantForLt!(Data<'_>)>()?;
|
||||
let pdev = data.parent;
|
||||
|
||||
dev_info!(
|
||||
pdev,
|
||||
"Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n",
|
||||
adev.id(),
|
||||
pdev.vendor_id(),
|
||||
pdev.device_id()
|
||||
);
|
||||
dev_info!(
|
||||
pdev,
|
||||
"Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n",
|
||||
adev.id(),
|
||||
pdev.vendor_id(),
|
||||
pdev.device_id()
|
||||
);
|
||||
|
||||
dev_info!(
|
||||
pdev,
|
||||
"Connected to auxiliary device with index {}.\n",
|
||||
data.index
|
||||
);
|
||||
dev_info!(
|
||||
pdev,
|
||||
"Connected to auxiliary device with index {}.\n",
|
||||
data.index
|
||||
);
|
||||
}
|
||||
// Invariant ForLt types (e.g. containing a Mutex) require the closure-based accessor.
|
||||
INVARIANT_DEV_ID => {
|
||||
adev.registration_data_with::<ForLt!(MutexData<'_>), _>(|data| {
|
||||
let pdev = *data.parent.lock();
|
||||
dev_info!(
|
||||
pdev,
|
||||
"Connected to auxiliary device with index {} (via Mutex).\n",
|
||||
data.index
|
||||
);
|
||||
})?;
|
||||
}
|
||||
_ => return Err(EINVAL),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user