Skip to content

Commit 03c9237

Browse files
committed
rust: gpio: add support for registering irq chips with gpio chip.
This is used by the PL061 driver. Signed-off-by: Wedson Almeida Filho <[email protected]>
1 parent 3593915 commit 03c9237

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
@@ -11,6 +11,9 @@ use core::{
1111
pin::Pin,
1212
};
1313

14+
#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
15+
pub use irqchip::{ChipWithIrqChip, RegistrationWithIrqChip};
16+
1417
/// The direction of a gpio line.
1518
pub enum LineDirection {
1619
/// Direction is input.
@@ -141,14 +144,13 @@ impl<T: Chip> Registration<T> {
141144
parent: &dyn device::RawDevice,
142145
data: T::Data,
143146
) -> Result {
144-
// SAFETY: We never move out of `this`.
145-
let this = unsafe { self.get_unchecked_mut() };
146-
147-
if this.parent.is_some() {
147+
if self.parent.is_some() {
148148
// Already registered.
149149
return Err(Error::EINVAL);
150150
}
151151

152+
// SAFETY: We never move out of `this`.
153+
let this = unsafe { self.get_unchecked_mut() };
152154
{
153155
let gc = this.gc.get_mut();
154156

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

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)