// SPDX-License-Identifier: MIT OR Apache-2.0 // // Copyright (c) 2020-2022 Andre Richter //! Interrupt Controller Driver. mod peripheral_ic; use crate::{ driver, exception, memory::{Address, Virtual}, }; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- /// Wrapper struct for a bitmask indicating pending IRQ numbers. struct PendingIRQs { bitmask: u64, } //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- pub type LocalIRQ = exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; pub type PeripheralIRQ = exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] #[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), } /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- impl PendingIRQs { pub fn new(bitmask: u64) -> Self { Self { bitmask } } } impl Iterator for PendingIRQs { type Item = usize; fn next(&mut self) -> Option { if self.bitmask == 0 { return None; } let next = self.bitmask.trailing_zeros() as usize; self.bitmask &= self.bitmask.wrapping_sub(1); Some(next) } } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- impl InterruptController { // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. const MAX_LOCAL_IRQ_NUMBER: usize = 3; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; /// Create an instance. /// /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( periph_mmio_start_addr: Address, post_init_callback: fn(), ) -> Self { Self { periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), post_init_callback, } } } //------------------------------------------------------------------------------ // OS Interface Code //------------------------------------------------------------------------------ impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { (self.post_init_callback)(); Ok(()) } } impl exception::asynchronous::interface::IRQManager for InterruptController { type IRQNumberType = IRQNumber; fn register_handler( &self, irq: Self::IRQNumberType, descriptor: exception::asynchronous::IRQDescriptor, ) -> Result<(), &'static str> { match irq { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), } } fn enable(&self, irq: Self::IRQNumberType) { match irq { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), } } fn handle_pending_irqs<'irq_context>( &'irq_context self, ic: &exception::asynchronous::IRQContext<'irq_context>, ) { // It can only be a peripheral IRQ pending because enable() does not support local IRQs yet. self.periph.handle_pending_irqs(ic) } fn print_handler(&self) { self.periph.print_handler(); } }