diff options
Diffstat (limited to 'rust/kernel')
| -rw-r--r-- | rust/kernel/driver.rs | 137 | ||||
| -rw-r--r-- | rust/kernel/i2c.rs | 6 | ||||
| -rw-r--r-- | rust/kernel/platform.rs | 3 | ||||
| -rw-r--r-- | rust/kernel/serdev.rs | 3 |
4 files changed, 19 insertions, 130 deletions
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index 824899d76fed..c9c74c4dde8f 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -107,7 +107,6 @@ use crate::{ acpi, device, - device_id::RawDeviceIdIndex, of, prelude::*, types::Opaque, @@ -292,26 +291,6 @@ macro_rules! module_driver { } } -// Calling the FFI function directly from the `Adapter` impl may result in it being called -// directly from driver modules. This happens since the Rust compiler will use monomorphisation, so -// it might happen that functions are instantiated within the calling driver module. For now, work -// around this with `#[inline(never)]` helpers. -// -// TODO: Remove once a more generic solution has been implemented. For instance, we may be able to -// leverage `bindgen` to take care of this depending on whether a symbol is (already) exported. -#[inline(never)] -#[allow(clippy::missing_safety_doc)] -#[allow(dead_code)] -#[must_use] -unsafe fn acpi_of_match_device( - adev: *const bindings::acpi_device, - of_match_table: *const bindings::of_device_id, - of_id: *mut *const bindings::of_device_id, -) -> bool { - // SAFETY: Safety requirements are the same as `bindings::acpi_of_match_device`. - unsafe { bindings::acpi_of_match_device(adev, of_match_table, of_id) } -} - /// The bus independent adapter to match a drivers and a devices. /// /// This trait should be implemented by the bus specific adapter, which represents the connection @@ -325,117 +304,23 @@ pub trait Adapter { /// The [`acpi::IdTable`] of the corresponding driver fn acpi_id_table() -> Option<acpi::IdTable<Self::IdInfo>>; - /// Returns the driver's private data from the matching entry in the [`acpi::IdTable`], if any. - /// - /// If this returns `None`, it means there is no match with an entry in the [`acpi::IdTable`]. - fn acpi_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { - #[cfg(not(CONFIG_ACPI))] - { - let _ = dev; - None - } - - #[cfg(CONFIG_ACPI)] - { - let table = Self::acpi_id_table()?; - - // SAFETY: - // - `table` has static lifetime, hence it's valid for read, - // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`. - let raw_id = unsafe { bindings::acpi_match_device(table.as_ptr(), dev.as_raw()) }; - - if raw_id.is_null() { - None - } else { - // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct acpi_device_id` - // and does not add additional invariants, so it's safe to transmute. - let id = unsafe { &*raw_id.cast::<acpi::DeviceId>() }; - - // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`. - Some(unsafe { id.info_unchecked::<Self::IdInfo>() }) - } - } - } - /// The [`of::IdTable`] of the corresponding driver. fn of_id_table() -> Option<of::IdTable<Self::IdInfo>>; - /// Returns the driver's private data from the matching entry in the [`of::IdTable`], if any. - /// - /// If this returns `None`, it means there is no match with an entry in the [`of::IdTable`]. - fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { - let table = Self::of_id_table()?; - - #[cfg(not(any(CONFIG_OF, CONFIG_ACPI)))] - { - let _ = (dev, table); - } - - #[cfg(CONFIG_OF)] - { - // SAFETY: - // - `table` has static lifetime, hence it's valid for read, - // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`. - let raw_id = unsafe { bindings::of_match_device(table.as_ptr(), dev.as_raw()) }; - - if !raw_id.is_null() { - // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id` - // and does not add additional invariants, so it's safe to transmute. - let id = unsafe { &*raw_id.cast::<of::DeviceId>() }; - - // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`. - return Some(unsafe { id.info_unchecked::<Self::IdInfo>() }); - } - } - - #[cfg(CONFIG_ACPI)] - { - use core::ptr; - use device::property::FwNode; - - let mut raw_id = ptr::null(); - - let fwnode = dev.fwnode().map_or(ptr::null_mut(), FwNode::as_raw); - - // SAFETY: `fwnode` is a pointer to a valid `fwnode_handle`. A null pointer will be - // passed through the function. - let adev = unsafe { bindings::to_acpi_device_node(fwnode) }; - - // SAFETY: - // - `adev` is a valid pointer to `acpi_device` or is null. It is guaranteed to be - // valid as long as `dev` is alive. - // - `table` has static lifetime, hence it's valid for read. - if unsafe { acpi_of_match_device(adev, table.as_ptr(), &raw mut raw_id) } { - // SAFETY: - // - the function returns true, therefore `raw_id` has been set to a pointer to a - // valid `of_device_id`. - // - `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id` - // and does not add additional invariants, so it's safe to transmute. - let id = unsafe { &*raw_id.cast::<of::DeviceId>() }; - - // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`. - return Some(unsafe { id.info_unchecked::<Self::IdInfo>() }); - } - } - - None - } - /// Returns the driver's private data from the matching entry of any of the ID tables, if any. /// /// If this returns `None`, it means that there is no match in any of the ID tables directly /// associated with a [`device::Device`]. - fn id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { - let id = Self::acpi_id_info(dev); - if id.is_some() { - return id; - } - - let id = Self::of_id_info(dev); - if id.is_some() { - return id; - } - - None + /// + /// # Safety + /// + /// The caller must ensure that the `dev` matched data is of type `Self::IdInfo`. + #[inline] + unsafe fn id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { + // SAFETY: `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`. + let data = unsafe { bindings::device_get_match_data(dev.as_raw()) }; + + // SAFETY: Per safety requirement, `data` is of type `Self::IdInfo`. + unsafe { data.cast::<Self::IdInfo>().as_ref() } } } diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 31f2cfe6be31..2d2191164e25 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -149,8 +149,10 @@ impl<T: Driver> Adapter<T> { // INVARIANT: `idev` is valid for the duration of `probe_callback()`. let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal<'_>>>() }; - let info = - Self::i2c_id_info(idev).or_else(|| <Self as driver::Adapter>::id_info(idev.as_ref())); + let info = Self::i2c_id_info(idev).or_else(|| { + // SAFETY: `idev` matched data is of type `Self::IdInfo`. + unsafe { <Self as driver::Adapter>::id_info(idev.as_ref()) } + }); from_result(|| { let data = T::probe(idev, info); diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 210a815925ce..e12e88113ca5 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -100,7 +100,8 @@ impl<T: Driver> Adapter<T> { // // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() }; - let info = <Self as driver::Adapter>::id_info(pdev.as_ref()); + // SAFETY: `pdev` matched data is of type `Self::IdInfo`. + let info = unsafe { <Self as driver::Adapter>::id_info(pdev.as_ref()) }; from_result(|| { let data = T::probe(pdev, info); diff --git a/rust/kernel/serdev.rs b/rust/kernel/serdev.rs index 383f62b1b713..c0cd24481ee3 100644 --- a/rust/kernel/serdev.rs +++ b/rust/kernel/serdev.rs @@ -162,7 +162,8 @@ impl<T: Driver> Adapter<T> { // // INVARIANT: `sdev` is valid for the duration of `probe_callback()`. let sdev = unsafe { &*sdev.cast::<Device<device::CoreInternal<'_>>>() }; - let info = <Self as driver::Adapter>::id_info(sdev.as_ref()); + // SAFETY: `sdev` matched data is of type `Self::IdInfo`. + let info = unsafe { <Self as driver::Adapter>::id_info(sdev.as_ref()) }; from_result(|| { sdev.as_ref().set_drvdata(try_pin_init!(PrivateData::<T> { |
