Skip to content

Commit fbb7b1a

Browse files
authored
Merge pull request #565 from wedsonaf/gpio-irq
rust: gpio: add support for registering irq chips with gpio chip.
2 parents 0028943 + fbba2d5 commit fbb7b1a

File tree

3 files changed

+321
-4
lines changed

3 files changed

+321
-4
lines changed

rust/helpers.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <linux/security.h>
1414
#include <asm/io.h>
1515
#include <linux/irq.h>
16+
#include <linux/irqchip/chained_irq.h>
17+
#include <linux/irqdomain.h>
1618
#include <linux/amba/bus.h>
1719

1820
__noreturn void rust_helper_BUG(void)
@@ -374,6 +376,32 @@ void *rust_helper_irq_data_get_irq_chip_data(struct irq_data *d)
374376
}
375377
EXPORT_SYMBOL_GPL(rust_helper_irq_data_get_irq_chip_data);
376378

379+
struct irq_chip *rust_helper_irq_desc_get_chip(struct irq_desc *desc)
380+
{
381+
return irq_desc_get_chip(desc);
382+
}
383+
EXPORT_SYMBOL_GPL(rust_helper_irq_desc_get_chip);
384+
385+
void *rust_helper_irq_desc_get_handler_data(struct irq_desc *desc)
386+
{
387+
return irq_desc_get_handler_data(desc);
388+
}
389+
EXPORT_SYMBOL_GPL(rust_helper_irq_desc_get_handler_data);
390+
391+
void rust_helper_chained_irq_enter(struct irq_chip *chip,
392+
struct irq_desc *desc)
393+
{
394+
chained_irq_enter(chip, desc);
395+
}
396+
EXPORT_SYMBOL_GPL(rust_helper_chained_irq_enter);
397+
398+
void rust_helper_chained_irq_exit(struct irq_chip *chip,
399+
struct irq_desc *desc)
400+
{
401+
chained_irq_exit(chip, desc);
402+
}
403+
EXPORT_SYMBOL_GPL(rust_helper_chained_irq_exit);
404+
377405
/* We use bindgen's --size_t-is-usize option to bind the C size_t type
378406
* as the Rust usize type, so we can use it in contexts where Rust
379407
* expects a usize like slice (array) indices. usize is defined to be

rust/kernel/gpio.rs

Lines changed: 177 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ use core::{
1313
pin::Pin,
1414
};
1515

16+
#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
17+
pub use irqchip::{ChipWithIrqChip, RegistrationWithIrqChip};
18+
1619
/// The direction of a gpio line.
1720
pub enum LineDirection {
1821
/// Direction is input.
@@ -143,14 +146,13 @@ impl<T: Chip> Registration<T> {
143146
parent: &dyn device::RawDevice,
144147
data: T::Data,
145148
) -> Result {
146-
// SAFETY: We never move out of `this`.
147-
let this = unsafe { self.get_unchecked_mut() };
148-
149-
if this.parent.is_some() {
149+
if self.parent.is_some() {
150150
// Already registered.
151151
return Err(Error::EINVAL);
152152
}
153153

154+
// SAFETY: We never move out of `this`.
155+
let this = unsafe { self.get_unchecked_mut() };
154156
{
155157
let gc = this.gc.get_mut();
156158

@@ -299,3 +301,174 @@ unsafe extern "C" fn set_callback<T: Chip>(
299301
let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
300302
T::set(data, offset, value != 0);
301303
}
304+
305+
#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
306+
mod irqchip {
307+
use super::*;
308+
use crate::irq;
309+
310+
/// A gpio chip that includes an irq chip.
311+
pub trait ChipWithIrqChip: Chip {
312+
/// Implements the irq flow for the gpio chip.
313+
fn handle_irq_flow(
314+
_data: <Self::Data as PointerWrapper>::Borrowed<'_>,
315+
_desc: &irq::Descriptor,
316+
_domain: &irq::Domain,
317+
);
318+
}
319+
320+
/// A registration of a gpio chip that includes an irq chip.
321+
pub struct RegistrationWithIrqChip<T: ChipWithIrqChip> {
322+
reg: Registration<T>,
323+
irq_chip: UnsafeCell<bindings::irq_chip>,
324+
parent_irq: u32,
325+
}
326+
327+
impl<T: ChipWithIrqChip> RegistrationWithIrqChip<T> {
328+
/// Creates a new [`RegistrationWithIrqChip`] but does not register it yet.
329+
///
330+
/// It is allowed to move.
331+
pub fn new() -> Self {
332+
Self {
333+
reg: Registration::new(),
334+
irq_chip: UnsafeCell::new(bindings::irq_chip::default()),
335+
parent_irq: 0,
336+
}
337+
}
338+
339+
/// Registers a gpio chip and its irq chip with the rest of the kernel.
340+
pub fn register<U: irq::Chip<Data = T::Data>>(
341+
mut self: Pin<&mut Self>,
342+
gpio_count: u16,
343+
base: Option<i32>,
344+
parent: &dyn device::RawDevice,
345+
data: T::Data,
346+
parent_irq: u32,
347+
) -> Result {
348+
if self.reg.parent.is_some() {
349+
// Already registered.
350+
return Err(Error::EINVAL);
351+
}
352+
353+
// SAFETY: We never move out of `this`.
354+
let this = unsafe { self.as_mut().get_unchecked_mut() };
355+
356+
// Initialise the irq_chip.
357+
{
358+
let irq_chip = this.irq_chip.get_mut();
359+
irq_chip.name = parent.name().as_char_ptr();
360+
361+
// SAFETY: The gpio subsystem configures a pointer to `gpio_chip` as the irq chip
362+
// data, so we use `IrqChipAdapter` to convert to the `T::Data`, which is the same
363+
// as `irq::Chip::Data` per the bound above.
364+
unsafe { irq::init_chip::<IrqChipAdapter<U>>(irq_chip) };
365+
}
366+
367+
// Initialise gc irq state.
368+
{
369+
let girq = &mut this.reg.gc.get_mut().irq;
370+
girq.chip = this.irq_chip.get();
371+
// SAFETY: By leaving `parent_handler_data` set to `null`, the gpio subsystem
372+
// initialises it to a pointer to the gpio chip, which is what `FlowHandler<T>`
373+
// expects.
374+
girq.parent_handler = unsafe { irq::new_flow_handler::<FlowHandler<T>>() };
375+
girq.num_parents = 1;
376+
girq.parents = &mut this.parent_irq;
377+
this.parent_irq = parent_irq;
378+
girq.default_type = bindings::IRQ_TYPE_NONE;
379+
girq.handler = Some(bindings::handle_bad_irq);
380+
}
381+
382+
// SAFETY: `reg` is pinned when `self` is.
383+
let pinned = unsafe { self.map_unchecked_mut(|r| &mut r.reg) };
384+
pinned.register(gpio_count, base, parent, data)
385+
}
386+
}
387+
388+
impl<T: ChipWithIrqChip> Default for RegistrationWithIrqChip<T> {
389+
fn default() -> Self {
390+
Self::new()
391+
}
392+
}
393+
394+
// SAFETY: `RegistrationWithIrqChip` doesn't offer any methods or access to fields when shared
395+
// between threads or CPUs, so it is safe to share it.
396+
unsafe impl<T: ChipWithIrqChip> Sync for RegistrationWithIrqChip<T> {}
397+
398+
// SAFETY: Registration with and unregistration from the gpio subsystem (including irq chips for
399+
// them) can happen from any thread. Additionally, `T::Data` (which is dropped during
400+
// unregistration) is `Send`, so it is ok to move `Registration` to different threads.
401+
unsafe impl<T: ChipWithIrqChip> Send for RegistrationWithIrqChip<T> where T::Data: Send {}
402+
403+
struct FlowHandler<T: ChipWithIrqChip>(PhantomData<T>);
404+
405+
impl<T: ChipWithIrqChip> irq::FlowHandler for FlowHandler<T> {
406+
type Data = *mut bindings::gpio_chip;
407+
408+
fn handle_irq_flow(gc: *mut bindings::gpio_chip, desc: &irq::Descriptor) {
409+
// SAFETY: `FlowHandler` is only used in gpio chips, and it is removed when the gpio is
410+
// unregistered, so we know that `gc` must still be valid. We also know that the value
411+
// stored as gpio data was returned by `T::Data::into_pointer` again because
412+
// `FlowHandler` is a private structure only used in this way.
413+
let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc)) };
414+
415+
// SAFETY: `gc` is valid (see comment above), so we can dereference it.
416+
let domain = unsafe { irq::Domain::from_ptr((*gc).irq.domain) };
417+
418+
T::handle_irq_flow(data, desc, &domain);
419+
}
420+
}
421+
422+
/// Adapter from an irq chip with `gpio_chip` pointer as context to one where the gpio chip
423+
/// data is passed as context.
424+
struct IrqChipAdapter<T: irq::Chip>(PhantomData<T>);
425+
426+
impl<T: irq::Chip> irq::Chip for IrqChipAdapter<T> {
427+
type Data = *mut bindings::gpio_chip;
428+
const TO_USE: irq::ToUse = T::TO_USE;
429+
430+
fn ack(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
431+
// SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
432+
// gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
433+
// registered, so `gc` is valid.
434+
let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
435+
T::ack(data, irq_data);
436+
}
437+
438+
fn mask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
439+
// SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
440+
// gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
441+
// registered, so `gc` is valid.
442+
let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
443+
T::mask(data, irq_data);
444+
}
445+
446+
fn unmask(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
447+
// SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
448+
// gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
449+
// registered, so `gc` is valid.
450+
let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
451+
T::unmask(data, irq_data);
452+
}
453+
454+
fn set_type(
455+
gc: *mut bindings::gpio_chip,
456+
irq_data: &mut irq::LockedIrqData,
457+
flow_type: u32,
458+
) -> Result<irq::ExtraResult> {
459+
// SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
460+
// gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
461+
// registered, so `gc` is valid.
462+
let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
463+
T::set_type(data, irq_data, flow_type)
464+
}
465+
466+
fn set_wake(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData, on: bool) -> Result {
467+
// SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
468+
// gpio chip is known to come from `T::Data`, and only valid while the gpio chip is
469+
// registered, so `gc` is valid.
470+
let data = unsafe { T::Data::borrow(bindings::gpiochip_get_data(gc as _)) };
471+
T::set_wake(data, irq_data, on)
472+
}
473+
}
474+
}

rust/kernel/irq.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,119 @@ impl Type {
289289
/// The interrupt is triggered while the signal is held low.
290290
pub const LEVEL_LOW: u32 = bindings::IRQ_TYPE_LEVEL_LOW;
291291
}
292+
293+
/// Wraps the kernel's `struct irq_desc`.
294+
///
295+
/// # Invariants
296+
///
297+
/// The pointer `Descriptor::ptr` is non-null and valid.
298+
pub struct Descriptor {
299+
pub(crate) ptr: *mut bindings::irq_desc,
300+
}
301+
302+
impl Descriptor {
303+
/// Constructs a new `struct irq_desc` wrapper.
304+
///
305+
/// # Safety
306+
///
307+
/// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
308+
unsafe fn from_ptr(ptr: *mut bindings::irq_desc) -> Self {
309+
// INVARIANT: The safety requirements ensure the invariant.
310+
Self { ptr }
311+
}
312+
313+
/// Calls `chained_irq_enter` and returns a guard that calls `chained_irq_exit` once dropped.
314+
///
315+
/// It is meant to be used by chained irq handlers to dispatch irqs to the next handlers.
316+
pub fn enter_chained(&self) -> ChainedGuard<'_> {
317+
// SAFETY: By the type invariants, `ptr` is always non-null and valid.
318+
let irq_chip = unsafe { bindings::irq_desc_get_chip(self.ptr) };
319+
320+
// SAFETY: By the type invariants, `ptr` is always non-null and valid. `irq_chip` was just
321+
// returned from `ptr`, so it is still valid too.
322+
unsafe { bindings::chained_irq_enter(irq_chip, self.ptr) };
323+
ChainedGuard {
324+
desc: self,
325+
irq_chip,
326+
}
327+
}
328+
}
329+
330+
/// A guard to call `chained_irq_exit` after `chained_irq_enter` was called.
331+
///
332+
/// It is also used as evidence that a previous `chained_irq_enter` was called. So there are no
333+
/// public constructors and it is only created after indeed calling `chained_irq_enter`.
334+
pub struct ChainedGuard<'a> {
335+
desc: &'a Descriptor,
336+
irq_chip: *mut bindings::irq_chip,
337+
}
338+
339+
impl Drop for ChainedGuard<'_> {
340+
fn drop(&mut self) {
341+
// SAFETY: The lifetime of `ChainedGuard` guarantees that `self.desc` remains valid, so it
342+
// also guarantess `irq_chip` (which was returned from it) and `self.desc.ptr` (guaranteed
343+
// by the type invariants).
344+
unsafe { bindings::chained_irq_exit(self.irq_chip, self.desc.ptr) };
345+
}
346+
}
347+
348+
/// Wraps the kernel's `struct irq_domain`.
349+
///
350+
/// # Invariants
351+
///
352+
/// The pointer `Domain::ptr` is non-null and valid.
353+
pub struct Domain {
354+
ptr: *mut bindings::irq_domain,
355+
}
356+
357+
impl Domain {
358+
/// Constructs a new `struct irq_domain` wrapper.
359+
///
360+
/// # Safety
361+
///
362+
/// The pointer `ptr` must be non-null and valid for the lifetime of the returned object.
363+
pub(crate) unsafe fn from_ptr(ptr: *mut bindings::irq_domain) -> Self {
364+
// INVARIANT: The safety requirements ensure the invariant.
365+
Self { ptr }
366+
}
367+
368+
/// Invokes the chained handler of the given hw irq of the given domain.
369+
///
370+
/// It requires evidence that `chained_irq_enter` was called, which is done by passing a
371+
/// `ChainedGuard` instance.
372+
pub fn generic_handle_chained(&self, hwirq: u32, _guard: &ChainedGuard<'_>) {
373+
// SAFETY: `ptr` is valid by the type invariants.
374+
unsafe { bindings::generic_handle_domain_irq(self.ptr, hwirq) };
375+
}
376+
}
377+
378+
/// A high-level irq flow handler.
379+
pub trait FlowHandler {
380+
/// The data associated with the handler.
381+
type Data: PointerWrapper;
382+
383+
/// Implements the irq flow for the given descriptor.
384+
fn handle_irq_flow(data: <Self::Data as PointerWrapper>::Borrowed<'_>, desc: &Descriptor);
385+
}
386+
387+
/// Returns the raw irq flow handler corresponding to the (high-level) one defined in `T`.
388+
///
389+
/// # Safety
390+
///
391+
/// The caller must ensure that the value stored in the irq handler data (as returned by
392+
/// `irq_desc_get_handler_data`) is the result of calling [`PointerWrapper::into_pointer] for the
393+
/// [`T::Data`] type.
394+
pub(crate) unsafe fn new_flow_handler<T: FlowHandler>() -> bindings::irq_flow_handler_t {
395+
Some(irq_flow_handler::<T>)
396+
}
397+
398+
unsafe extern "C" fn irq_flow_handler<T: FlowHandler>(desc: *mut bindings::irq_desc) {
399+
// SAFETY: By the safety requirements of `new_flow_handler`, we know that the value returned by
400+
// `irq_desc_get_handler_data` comes from calling `T::Data::into_pointer`. `desc` is valid by
401+
// the C API contract.
402+
let data = unsafe { T::Data::borrow(bindings::irq_desc_get_handler_data(desc)) };
403+
404+
// SAFETY: The C API guarantees that `desc` is valid for the duration of this call, which
405+
// outlives the lifetime returned by `from_desc`.
406+
T::handle_irq_flow(data, &unsafe { Descriptor::from_ptr(desc) });
407+
}

0 commit comments

Comments
 (0)