diff --git a/drivers/i2c/busses/i2c_bcm2835_rust.rs b/drivers/i2c/busses/i2c_bcm2835_rust.rs index 6d127a721dcf8..7de55ebf8b313 100644 --- a/drivers/i2c/busses/i2c_bcm2835_rust.rs +++ b/drivers/i2c/busses/i2c_bcm2835_rust.rs @@ -1,9 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 //! BCM2835 master mode driver - -use core::ops::Not; - use kernel::{ bindings, clk::Clk, @@ -74,9 +71,6 @@ pub const BCM2835_I2C_REDL_SHIFT: u32 = 0; pub const BCM2835_I2C_CDIV_MIN: u32 = 0x0002; pub const BCM2835_I2C_CDIV_MAX: u32 = 0xFFFE; -// Debug and Clk_tout_ms is static mut in C code. -// Take as const for now. - pub const DEBUG: i32 = 0; /// SMBUs-recommended 35ms @@ -133,8 +127,8 @@ struct ClkBcm2835I2c<'c> { impl<'c> ClkBcm2835I2c<'c> { fn from_raw<'a>(ptr: *mut Self) -> &'a mut Self { - let prt = ptr.cast::(); - unsafe { &mut *prt } + let ptr = ptr.cast::(); + unsafe { &mut *ptr } } } @@ -196,12 +190,12 @@ fn clk_bcm2835_i2c_set_rate(hw: &ClkHw, rate: u64, parent_rate: u64) -> Result<( Ok(()) } -fn clk_bcm2835_i2c_round_rate(hw: &ClkHw, rate: u64, parent_rate: &mut u64) -> i32 { +fn clk_bcm2835_i2c_round_rate(hw: &ClkHw, rate: u64, parent_rate: &mut u64) -> i64 { let Ok(divider) = clk_bcm2835_i2c_calc_divider(rate, *parent_rate) else { return 0; }; - parent_rate.div_ceil(divider) as i32 + parent_rate.div_ceil(divider) as i64 } fn clk_bcm2835_i2c_recalc_rate(hw: &ClkHw, parent_rate: u64) -> u64 { @@ -654,6 +648,13 @@ impl platform::Driver for Bcm2835I2cDriver { let dev_data = kernel::new_device_data!((), (), Bcm2835I2cData {}, "BCM2835_I2C device data")?; + /* + * Disable the hardware clock stretching timeout. SMBUS + * specifies a limit for how long the device can stretch the + * clock, but core I2C doesn't. + */ + i2c_dev.bcm2835_i2c_writel(BCM2835_I2C_CLKT, 0); + i2c_dev.bcm2835_i2c_writel(BCM2835_I2C_C, 0); Ok(dev_data.into()) } diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index eff9348644896..0b4b395476c66 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -33,6 +33,8 @@ #include #include #include +#include +#include /* `bindgen` gets confused at certain things. */ const size_t BINDINGS_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN; diff --git a/rust/kernel/completion.rs b/rust/kernel/completion.rs index 8774313e6887a..71e09327cd3b6 100644 --- a/rust/kernel/completion.rs +++ b/rust/kernel/completion.rs @@ -5,13 +5,7 @@ //! C header: [`include/linux/completion.h`] //! -use crate::{ - types::Opaque, - str::CStr, - sync::LockClassKey, - prelude::PinInit, - bindings, -}; +use crate::{bindings, prelude::PinInit, str::CStr, sync::LockClassKey, types::Opaque}; /// Linux completion wrapper /// @@ -42,8 +36,7 @@ impl Completion { /// Creates a new instance of [`Completion`]. #[inline] #[allow(clippy::new_ret_no_self)] - pub fn new(name: &'static CStr, key: LockClassKey) -> impl PinInit - { + pub fn new(name: &'static CStr, key: LockClassKey) -> impl PinInit { unsafe { kernel::init::pin_init_from_closure(move |slot| { let slot = Self::raw_get(slot); @@ -73,25 +66,34 @@ impl Completion { unsafe { Opaque::raw_get(core::ptr::addr_of!((*ptr).0)) } } - /// completion reinit + /// completion reinit pub fn reinit(&self) { - unsafe {(*(self.0.get())).done = 0;} + unsafe { + (*(self.0.get())).done = 0; + } } /// This waits to be signaled for completion of a specific task. It is NOT /// interruptible and there is no timeout. pub fn wait_for_completion(&self) { // SAFETY: call ffi and ptr is valid - unsafe{ - bindings::wait_for_completion(self.0.get()) - } + unsafe { bindings::wait_for_completion(self.0.get()) } } - /// complete + /// complete pub fn complete(&self) { // SAFETY: call ffi and ptr is valid + unsafe { bindings::complete(self.0.get()) } + } + + /// Initialize a dynamically allocated completion + pub fn init_completion(&self) { unsafe { - bindings::complete(self.0.get()) + (*(self.0.get())).done = 0; + let wait = &mut (*(self.0.get())).wait; + let name = concat!(stringify!(wait), "\0").as_ptr() as *const core::ffi::c_char; + let key = LockClassKey().as_ptr(); + bindings::__init_swait_queue_head(wait, name, key); } } @@ -104,10 +106,10 @@ impl Completion { return 0; } - if left_jiff/(bindings::HZ as usize) == 0 { + if left_jiff / (bindings::HZ as usize) == 0 { return 1; } else { - return left_jiff/(bindings::HZ as usize); + return left_jiff / (bindings::HZ as usize); } } @@ -117,7 +119,9 @@ impl Completion { fn wait_for_completion_timeout(&self, jiff: usize) -> usize { // SAFETY: call ffi and ptr is valid unsafe { - bindings::wait_for_completion_timeout(self.0.get(), jiff.try_into().unwrap()).try_into().unwrap() + bindings::wait_for_completion_timeout(self.0.get(), jiff.try_into().unwrap()) + .try_into() + .unwrap() } } } diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index c1b4ed84436f5..6d1cf7e7ad025 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -11,6 +11,7 @@ use crate::{ dev_err, error::{code::*, from_err_ptr, to_result, Result}, macros::pin_data, + of::DeviceNode, pin_init, pr_crit, str::CStr, sync::{ @@ -213,6 +214,13 @@ impl Device { Ok(Clk::from_raw(raw)) } + /// Get node from dev + pub fn of_node(&self) -> &mut DeviceNode { + // safety: IS_ENABLED(CONFIG_OF) || dev ptr is valid + let ptr = unsafe { (*(self.raw_device())).of_node }; + DeviceNode::from_raw(ptr) + } + /// Allocate a new clock, register it and return an opaque cookie pub fn clk_register(&self, clk_hw: &mut ClkHw) -> Result<&mut Clk> { // SAFETY: call ffi and ptr is valid @@ -288,7 +296,6 @@ impl Clone for Device { Device::from_dev(self) } } - /// Device data. /// /// When a device is removed (for whatever reason, for example, because the device was unplugged or diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 27a9477add334..90c41e0a6cb98 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -5,7 +5,7 @@ use crate::{ str::CStr, types::{ForeignOwnable, Opaque}, }; -use alloc::vec::{self, Vec}; +use alloc::vec::Vec; use core::mem::MaybeUninit; use core::{ffi::c_void, marker::PhantomData}; use macros::vtable; @@ -178,6 +178,14 @@ impl I2cAdapter { pub fn timeout(&self) -> usize { unsafe { self.0.timeout as usize } } + + //pub fn set_up(self) +} + +impl Drop for I2cAdapter { + fn drop(&mut self) { + unsafe { bindings::i2c_del_adapter(self.as_ptr()) } + } } /// Represents i2c_smbus_data /// diff --git a/rust/kernel/interrupt.rs b/rust/kernel/interrupt.rs new file mode 100644 index 0000000000000..3a7f0271af811 --- /dev/null +++ b/rust/kernel/interrupt.rs @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Generic devices that are part of the kernel's driver model. +//! +//! C header: [`include/linux/device.h`](../../../../include/linux/.h) + +use crate::{ + device::{Device, RawDevice}, + error::{to_result, Result}, + irq, + str::CStr, +}; +use core::{marker::PhantomData, task::Context}; + +pub const IRQF_TRIGGER_NONE: u32 = bindings::IRQF_TRIGGER_NONE; +pub const IRQF_TRIGGER_RISING: u32 = bindings::IRQF_TRIGGER_RISING; +pub const IRQF_TRIGGER_FALLING: u32 = bindings::IRQF_TRIGGER_FALLING; +pub const IRQF_TRIGGER_HIGH: u32 = bindings::IRQF_TRIGGER_HIGH; +pub const IRQF_TRIGGER_LOW: u32 = bindings::IRQF_TRIGGER_LOW; +pub const IRQF_TRIGGER_MASK: u32 = bindings::IRQF_TRIGGER_MASK; +pub const IRQF_TRIGGER_PROBE: u32 = bindings::IRQF_TRIGGER_PROBE; +pub const IRQF_SHARED: u32 = bindings::IRQF_SHARED; +pub const IRQF_PROBE_SHARED: u32 = bindings::IRQF_PROBE_SHARED; +pub const __IRQF_TIMER: u32 = bindings::__IRQF_TIMER; +pub const IRQF_PERCPU: u32 = bindings::IRQF_PERCPU; +pub const IRQF_NOBALANCING: u32 = bindings::IRQF_NOBALANCING; +pub const IRQF_IRQPOLL: u32 = bindings::IRQF_IRQPOLL; +pub const IRQF_ONESHOT: u32 = bindings::IRQF_ONESHOT; +pub const IRQF_NO_SUSPEND: u32 = bindings::IRQF_NO_SUSPEND; +pub const IRQF_FORCE_RESUME: u32 = bindings::IRQF_FORCE_RESUME; +pub const IRQF_NO_THREAD: u32 = bindings::IRQF_NO_THREAD; +pub const IRQF_EARLY_RESUME: u32 = bindings::IRQF_EARLY_RESUME; +pub const IRQF_COND_SUSPEND: u32 = bindings::IRQF_COND_SUSPEND; +pub const IRQF_NO_AUTOEN: u32 = bindings::IRQF_NO_AUTOEN; +pub const IRQF_NO_DEBUG: u32 = bindings::IRQF_NO_DEBUG; +pub const IRQF_TIMER: u32 = bindings::IRQF_TIMER; +pub const IRQ_NOTCONNECTED: u32 = bindings::IRQ_NOTCONNECTED; + +pub trait IrqHandler { + /// User data that will be accessible to all operations + type Context; + + fn handler(irq: i32, ctx: &mut Self::Context) -> irq::Return; +} + +pub(crate) struct Adapter(PhantomData, PhantomData) +where + H: IrqHandler; + +impl Adapter +where + H: IrqHandler, +{ + unsafe extern "C" fn handler_callback( + arg1: i32, + arg2: *mut core::ffi::c_void, + ) -> bindings::irqreturn_t { + let dev = unsafe { &mut *(arg2 as *const _ as *mut _) }; + H::handler(arg1, dev) as bindings::irqreturn_t + } + + const VTABLE: bindings::irq_handler_t = Some(Self::handler_callback); + + const fn build() -> &'static bindings::irq_handler_t { + &Self::VTABLE + } +} + +pub fn request_irq(irq: u32, handler: H, flags: u64, name: &'static CStr, dev: &T) -> Result +where + H: IrqHandler, +{ + let ret = unsafe { + bindings::request_threaded_irq( + irq, + *Adapter::::build(), + None, + flags, + name.as_char_ptr(), + dev as *const _ as *mut core::ffi::c_void, + ) + }; + to_result(ret) +} + +pub fn request_percpu_irq( + irq: u32, + handler: H, + dev_name: &'static CStr, + percpu_dev_id: &T, +) -> Result +where + H: IrqHandler, +{ + let ret = unsafe { + bindings::__request_percpu_irq( + irq, + *Adapter::::build(), + 0, + dev_name.as_char_ptr(), + percpu_dev_id as *const _ as *mut core::ffi::c_void, + ) + }; + to_result(ret) +} + +pub fn devm_request_irq( + dev: Device, + irq: u32, + handler: H, + flags: u64, + dev_name: &'static CStr, + dev_id: &T, +) -> Result +where + H: IrqHandler, +{ + let ret = unsafe { + bindings::devm_request_threaded_irq( + dev.raw_device(), + irq, + *Adapter::::build(), + None, + flags, + dev_name.as_char_ptr(), + dev_id as *const _ as *mut core::ffi::c_void, + ) + }; + to_result(ret) +} diff --git a/rust/kernel/io_pgtable.rs b/rust/kernel/io_pgtable.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 45a1c9a684c47..514f89646f9fa 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -78,6 +78,7 @@ pub mod task; pub mod timekeeping; pub mod types; pub mod user_ptr; +pub mod interrupt; use core::marker::PhantomData; diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs index 3882350425c5c..c77f3da713ec2 100644 --- a/rust/kernel/of.rs +++ b/rust/kernel/of.rs @@ -88,3 +88,30 @@ impl DeviceId { id } } + +pub struct Property(bindings::property); + +impl Property { + #[inline] + pub fn as_ptr(&self) -> *const bindings::property { + &self.0 + } +} + +pub struct DeviceNode(bindings::device_node); + +impl DeviceNode { + pub fn from_raw<'a>(ptr: *mut bindings::device_node) -> &'a mut Self { + let ptr = ptr.cast::(); + unsafe { &mut *ptr } + } + + #[inline] + pub fn as_ptr(&self) -> *const bindings::device_node { + &self.0 + } + + pub fn flags(&self) -> u64 { + self.0._flags + } +}