use rdif_intc::Intc;
use rdrive::Device;
mod v2;
mod v3;
use core::sync::atomic::{AtomicU8, Ordering};
#[derive(Clone, Copy, Eq, PartialEq)]
enum GicBackend {
None = 0,
V2 = 2,
V3 = 3,
}
static GIC_BACKEND: AtomicU8 = AtomicU8::new(GicBackend::None as u8);
fn set_backend(backend: GicBackend) {
GIC_BACKEND.store(backend as u8, Ordering::Release);
}
fn backend() -> GicBackend {
match GIC_BACKEND.load(Ordering::Acquire) {
2 => GicBackend::V2,
3 => GicBackend::V3,
_ => GicBackend::None,
}
}
pub fn init_current_cpu() {
let cpu_idx = crate::cpu::current_cpu_idx()
.unwrap_or_else(|| panic!("current logical CPU index is not available for GIC init"));
init_cpu(cpu_idx);
}
pub fn init_cpu(cpu_idx: usize) {
match backend() {
GicBackend::V2 => v2::init_cpu(),
GicBackend::V3 => v3::init_cpu(cpu_idx),
GicBackend::None => {
if v3::is_support_icc() {
v3::init_cpu(cpu_idx);
} else {
v2::init_cpu();
}
}
}
}
fn get_gicd() -> Device<Intc> {
rdrive::get_one().expect("no interrupt controller found")
}
pub fn irq_set_enable(irq: rdrive::IrqId, enable: bool) {
let raw = irq.into();
match backend() {
GicBackend::V2 => v2::irq_set_enable(raw, enable),
GicBackend::V3 => v3::irq_set_enable(raw, enable),
GicBackend::None => {
v2::irq_set_enable(raw, enable);
v3::irq_set_enable(raw, enable);
}
}
}
pub fn irq_set_affinity(
irq: rdrive::IrqId,
affinity: crate::irq::IrqAffinity,
) -> Result<(), &'static str> {
let raw = irq.into();
match backend() {
GicBackend::V2 => v2::irq_set_affinity(raw, affinity),
GicBackend::V3 => v3::irq_set_affinity(raw, affinity),
GicBackend::None => {
if v3::is_support_icc() {
v3::irq_set_affinity(raw, affinity)
} else {
v2::irq_set_affinity(raw, affinity)
}
}
}
}
pub fn send_ipi(irq: rdrive::IrqId, target: crate::irq::IpiTarget) {
let raw = irq.into();
match backend() {
GicBackend::V2 => v2::send_ipi(raw, target),
GicBackend::V3 => v3::send_ipi(raw, target),
GicBackend::None => {
if v3::is_support_icc() {
v3::send_ipi(raw, target);
} else {
v2::send_ipi(raw, target);
}
}
}
}
fn hardware_cpu_id(cpu_idx: usize) -> usize {
someboot::smp::cpu_idx_to_id(cpu_idx).unwrap_or(cpu_idx)
}
pub enum ActiveIrq {
V2(v2::ActiveIrq),
V3(v3::ActiveIrq),
}
impl ActiveIrq {
pub fn id(&self) -> rdrive::IrqId {
match self {
Self::V2(active) => active.id(),
Self::V3(active) => active.id(),
}
}
}
pub fn begin_irq() -> Option<ActiveIrq> {
match backend() {
GicBackend::V2 => v2::begin_irq().map(ActiveIrq::V2),
GicBackend::V3 => v3::begin_irq().map(ActiveIrq::V3),
GicBackend::None => {
if v3::is_support_icc() {
v3::begin_irq().map(ActiveIrq::V3)
} else {
v2::begin_irq().map(ActiveIrq::V2)
}
}
}
}