Skip to content

Commit

Permalink
Merge pull request torvalds#618 from wedsonaf/platform
Browse files Browse the repository at this point in the history
rust: convert `platform` to use `driver`
  • Loading branch information
wedsonaf authored Jan 14, 2022
2 parents efbcb28 + 2caae00 commit 97668ff
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 334 deletions.
60 changes: 27 additions & 33 deletions drivers/char/hw_random/bcm2835_rng_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
#![feature(allocator_api, global_asm)]

use kernel::{
c_str, file::File, file_operations::FileOperations, io_buffer::IoBufferWriter, miscdev,
of::ConstOfMatchTable, platform, platform::PlatformDriver, prelude::*,
c_str, device, file::File, file_operations::FileOperations, io_buffer::IoBufferWriter, miscdev,
module_platform_driver, of, platform, prelude::*, sync::Ref,
};

module! {
type: RngModule,
module_platform_driver! {
type: RngDriver,
name: b"bcm2835_rng_rust",
author: b"Rust for Linux Contributors",
description: b"BCM2835 Random Number Generator (RNG) driver",
Expand All @@ -38,35 +38,29 @@ impl FileOperations for RngDevice {
}
}

struct RngDriver;

impl PlatformDriver for RngDriver {
type DrvData = Pin<Box<miscdev::Registration<RngDevice>>>;

fn probe(device_id: i32) -> Result<Self::DrvData> {
pr_info!("probing discovered hwrng with id {}\n", device_id);
let drv_data = miscdev::Registration::new_pinned(c_str!("rust_hwrng"), None, ())?;
Ok(drv_data)
}
type DeviceData = device::Data<miscdev::Registration<RngDevice>, (), ()>;

fn remove(device_id: i32, _drv_data: Self::DrvData) -> Result {
pr_info!("removing hwrng with id {}\n", device_id);
Ok(())
}
}

struct RngModule {
_pdev: Pin<Box<platform::Registration>>,
}

impl KernelModule for RngModule {
fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
const OF_MATCH_TBL: ConstOfMatchTable<1> =
ConstOfMatchTable::new_const([c_str!("brcm,bcm2835-rng")]);

let pdev =
platform::Registration::new_pinned::<RngDriver>(name, Some(&OF_MATCH_TBL), module)?;

Ok(RngModule { _pdev: pdev })
struct RngDriver;
impl platform::Driver for RngDriver {
type Data = Ref<DeviceData>;

kernel::define_of_id_table! {(), [
(of::DeviceId::Compatible(b"brcm,bcm2835-rng"), None),
]}

fn probe(dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result<Self::Data> {
pr_info!("probing discovered hwrng with id {}\n", dev.id());
let data = kernel::new_device_data!(
miscdev::Registration::new(),
(),
(),
"BCM2835::Registrations"
)?;

data.registrations()
.ok_or(Error::ENXIO)?
.as_pinned_mut()
.register(c_str!("rust_hwrng"), None, ())?;
Ok(data.into())
}
}
10 changes: 5 additions & 5 deletions drivers/gpio/gpio_pl061_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#![feature(global_asm, allocator_api)]

use kernel::{
amba, bit, bits_iter, declare_amba_id_table, device, gpio,
amba, bit, bits_iter, define_amba_id_table, device, gpio,
io_mem::IoMem,
irq::{self, ExtraResult, IrqData, LockedIrqData},
power,
Expand Down Expand Up @@ -261,11 +261,11 @@ impl amba::Driver for PL061Device {
type Data = Ref<DeviceData>;
type PowerOps = Self;

declare_amba_id_table! [
{ id: 0x00041061, mask: 0x000fffff, data: () },
];
define_amba_id_table! {(), [
({id: 0x00041061, mask: 0x000fffff}, None),
]}

fn probe(dev: &mut amba::Device, _id: &amba::DeviceId) -> Result<Ref<DeviceData>> {
fn probe(dev: &mut amba::Device, _data: Option<&Self::IdInfo>) -> Result<Ref<DeviceData>> {
let res = dev.take_resource().ok_or(Error::ENXIO)?;
let irq = dev.irq(0).ok_or(Error::ENXIO)?;

Expand Down
8 changes: 8 additions & 0 deletions rust/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/amba/bus.h>
#include <linux/of_device.h>

__noreturn void rust_helper_BUG(void)
{
Expand Down Expand Up @@ -477,6 +478,13 @@ void rust_helper_put_cred(const struct cred *cred) {
}
EXPORT_SYMBOL_GPL(rust_helper_put_cred);

const struct of_device_id *rust_helper_of_match_device(
const struct of_device_id *matches, const struct device *dev)
{
return of_match_device(matches, dev);
}
EXPORT_SYMBOL_GPL(rust_helper_of_match_device);

/* We use bindgen's --size_t-is-usize option to bind the C size_t type
* as the Rust usize type, so we can use it in contexts where Rust
* expects a usize like slice (array) indices. usize is defined to be
Expand Down
102 changes: 54 additions & 48 deletions rust/kernel/amba.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
// SPDX-License-Identifier: GPL-2.0

//! Amba devices drivers.
//! Amba devices and drivers.
//!
//! C header: [`include/linux/amba/bus.h`](../../../../include/linux/amba/bus.h)

use crate::{
bindings, c_types, device, driver, error::from_kernel_result, io_mem::Resource, power,
str::CStr, to_result, types::PointerWrapper, Error, Result, ThisModule,
str::CStr, to_result, types::PointerWrapper, Result, ThisModule,
};

/// A registration of an amba driver.
pub type Registration<T> = driver::Registration<Adapter<T>>;

/// Id of an Amba device.
pub struct DeviceId<T = ()> {
#[derive(Clone, Copy)]
pub struct DeviceId {
/// Device id.
pub id: u32,

/// Mask that identifies which bits are valid in the device id.
pub mask: u32,
}

// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `amba_id::data`.
unsafe impl const driver::RawDeviceId for DeviceId {
type RawType = bindings::amba_id;
const ZERO: Self::RawType = bindings::amba_id {
id: 0,
mask: 0,
data: core::ptr::null_mut(),
};

/// Context data to be associated with the device id. This is carried over to [`Driver::probe`]
/// so that drivers can encode any information they may need then.
pub data: T,
fn to_rawid(&self, offset: isize) -> Self::RawType {
bindings::amba_id {
id: self.id,
mask: self.mask,
data: offset as _,
}
}
}

/// An amba driver.
Expand All @@ -39,11 +54,11 @@ pub trait Driver {
/// The type holding information about each device id supported by the driver.
type IdInfo: 'static = ();

/// The table of device ids supported by the drivers.
const ID_TABLE: &'static [DeviceId<Self::IdInfo>];
/// The table of device ids supported by the driver.
const ID_TABLE: Option<driver::IdTable<'static, DeviceId, Self::IdInfo>> = None;

/// Probes for the device with the given id.
fn probe(dev: &mut Device, id: &DeviceId<Self::IdInfo>) -> Result<Self::Data>;
fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;

/// Cleans any resources up that are associated with the device.
///
Expand All @@ -56,24 +71,22 @@ pub struct Adapter<T: Driver>(T);

impl<T: Driver> driver::DriverOps for Adapter<T> {
type RegType = bindings::amba_driver;
type RawIdType = bindings::amba_id;
type IdType = DeviceId<T::IdInfo>;
const ID_TABLE: &'static [Self::IdType] = T::ID_TABLE;

unsafe fn register(
reg: *mut bindings::amba_driver,
name: &'static CStr,
module: &'static ThisModule,
id_table: *const bindings::amba_id,
) -> Result {
// SAFETY: By the safety requirements of this function (defined in the trait defintion),
// `reg` is non-null and valid.
let amba = unsafe { &mut *reg };
amba.drv.name = name.as_char_ptr();
amba.drv.owner = module.0;
amba.id_table = id_table;
amba.probe = Some(probe_callback::<T>);
amba.remove = Some(remove_callback::<T>);
if let Some(t) = T::ID_TABLE {
amba.id_table = t.as_ref();
}
if cfg!(CONFIG_PM) {
// SAFETY: `probe_callback` sets the driver data after calling `T::Data::into_pointer`,
// and we guarantee that `T::Data` is the same as `T::PowerOps::Data` by a constraint
Expand All @@ -90,14 +103,6 @@ impl<T: Driver> driver::DriverOps for Adapter<T> {
// `reg` was passed (and updated) by a previous successful call to `amba_driver_register`.
unsafe { bindings::amba_driver_unregister(reg) };
}

fn to_raw_id(index: usize, id: &Self::IdType) -> Self::RawIdType {
bindings::amba_id {
id: id.id,
mask: id.mask,
data: index as _,
}
}
}

unsafe extern "C" fn probe_callback<T: Driver>(
Expand All @@ -109,11 +114,18 @@ unsafe extern "C" fn probe_callback<T: Driver>(
// duration of this call, so it is guaranteed to remain alive for the lifetime of `dev`.
let mut dev = unsafe { Device::from_ptr(adev) };
// SAFETY: `aid` is valid by the requirements the contract with the C code.
let index = unsafe { (*aid).data } as usize;
if index >= T::ID_TABLE.len() {
return Err(Error::ENXIO);
}
let data = T::probe(&mut dev, &T::ID_TABLE[index])?;
let offset = unsafe { (*aid).data };
let info = if offset.is_null() {
None
} else {
// SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`,
// which guarantees that the resulting pointer is within the table.
let ptr = unsafe { aid.cast::<u8>().offset(offset as _).cast::<Option<T::IdInfo>>() };
// SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for
// read.
unsafe { (&*ptr).as_ref() }
};
let data = T::probe(&mut dev, info)?;
let ptr = T::Data::into_pointer(data);
// SAFETY: `adev` is valid for write by the contract with the C code.
unsafe { bindings::amba_set_drvdata(adev, ptr as _) };
Expand Down Expand Up @@ -193,17 +205,17 @@ unsafe impl device::RawDevice for Device {
///
/// ```ignore
/// # use kernel::prelude::*;
/// # use kernel::{amba, declare_amba_id_table, module_amba_driver};
/// # use kernel::{amba, define_amba_id_table, module_amba_driver};
/// #
/// struct MyDriver;
/// impl amba::Driver for MyDriver {
/// // [...]
/// # fn probe(_dev: &mut amba::Device, _id: &amba::DeviceId<Self::IdInfo>) -> Result {
/// # fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
/// # Ok(())
/// # }
/// # declare_amba_id_table! [
/// # { id: 0x00041061, mask: 0x000fffff, data: () },
/// # ];
/// # define_amba_id_table! {(), [
/// # ({ id: 0x00041061, mask: 0x000fffff }, None),
/// # ]}
/// }
///
/// module_amba_driver! {
Expand All @@ -220,34 +232,28 @@ macro_rules! module_amba_driver {
};
}

/// Declares the id table for amba devices.
/// Defines the id table for amba devices.
///
/// # Examples
///
/// ```
/// # use kernel::prelude::*;
/// # use kernel::{amba, declare_amba_id_table};
/// # use kernel::{amba, define_amba_id_table};
/// #
/// # struct Sample;
/// # impl kernel::amba::Driver for Sample {
/// # fn probe(_dev: &mut amba::Device, _id: &amba::DeviceId<Self::IdInfo>) -> Result {
/// # fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
/// # Ok(())
/// # }
/// declare_amba_id_table! [
/// { id: 0x00041061, mask: 0x000fffff, data: () },
/// ];
/// define_amba_id_table! {(), [
/// ({ id: 0x00041061, mask: 0x000fffff }, None),
/// ]}
/// # }
/// ```
#[macro_export]
macro_rules! declare_amba_id_table {
($({$($entry:tt)*},)*) => {
const ID_TABLE: &'static [$crate::amba::DeviceId<Self::IdInfo>] = &[
$( $crate::amba::DeviceId { $($entry)* },)*
];
macro_rules! define_amba_id_table {
($data_type:ty, $($t:tt)*) => {
type IdInfo = $data_type;
$crate::define_id_table!(ID_TABLE, $crate::amba::DeviceId, $data_type, $($t)*);
};

// Cover case without a trailing comma.
($(($($entry:tt)*)),*) => {
$crate::declare_amba_id_table!{ $({$($entry)*},)*}
}
}
Loading

0 comments on commit 97668ff

Please sign in to comment.