use crate::{GicAffinity, IntId, InterruptState, Priority, TriggerMode};
#[derive(Clone, Debug)]
pub(crate) struct InterruptRecord {
intid: IntId,
enabled: bool,
pending: bool,
active: bool,
inflight: bool,
redelivery_pending: bool,
line_asserted: bool,
priority: Priority,
trigger: TriggerMode,
route: Option<GicAffinity>,
cpu_target_mask: Option<u8>,
}
impl InterruptRecord {
pub(crate) const fn new(intid: IntId, trigger: TriggerMode) -> Self {
Self {
intid,
enabled: matches!(intid, IntId::Sgi(_)),
pending: false,
active: false,
inflight: false,
redelivery_pending: false,
line_asserted: false,
priority: Priority::DEFAULT,
trigger,
route: None,
cpu_target_mask: None,
}
}
pub(crate) const fn intid(&self) -> IntId {
self.intid
}
pub(crate) const fn enabled(&self) -> bool {
self.enabled
}
pub(crate) fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
if enabled && self.line_asserted {
self.pending = true;
}
}
pub(crate) const fn pending(&self) -> bool {
self.pending
}
pub(crate) fn set_pending(&mut self, pending: bool) {
self.pending = pending;
if !pending {
self.redelivery_pending = false;
}
}
pub(crate) const fn active(&self) -> bool {
self.active
}
pub(crate) fn set_active(&mut self, active: bool) {
self.active = active;
}
pub(crate) const fn state(&self) -> InterruptState {
match (self.pending, self.active) {
(false, false) => InterruptState::Inactive,
(true, false) => InterruptState::Pending,
(false, true) => InterruptState::Active,
(true, true) => InterruptState::ActivePending,
}
}
pub(crate) fn set_state(&mut self, state: InterruptState) {
(self.pending, self.active) = match state {
InterruptState::Inactive => (false, false),
InterruptState::Pending => (true, false),
InterruptState::Active => (false, true),
InterruptState::ActivePending => (true, true),
};
}
pub(crate) const fn has_delivery_state(&self) -> bool {
self.pending || self.active || self.inflight || self.redelivery_pending
}
pub(crate) fn clear_delivery_state(&mut self) {
self.pending = false;
self.active = false;
self.inflight = false;
self.redelivery_pending = false;
self.line_asserted = false;
}
pub(crate) fn mark_inflight(&mut self) {
self.inflight = true;
}
pub(crate) fn synchronize_inflight(&mut self, state: InterruptState) -> InterruptState {
self.set_state(state);
if self.redelivery_pending {
self.pending = true;
}
let merged = self.state();
if merged == InterruptState::ActivePending {
self.redelivery_pending = false;
}
merged
}
pub(crate) fn cancel_inflight(&mut self) {
if self.redelivery_pending {
self.pending = true;
}
self.inflight = false;
self.redelivery_pending = false;
}
pub(crate) fn finish_inflight(&mut self) {
self.inflight = false;
self.active = false;
self.pending =
self.redelivery_pending || (self.trigger == TriggerMode::Level && self.line_asserted);
self.redelivery_pending = false;
}
pub(crate) fn deactivate_inflight(&mut self, pending_in_delivery: bool) {
self.inflight = false;
self.active = false;
self.pending = pending_in_delivery
|| self.redelivery_pending
|| (self.trigger == TriggerMode::Level && self.line_asserted);
self.redelivery_pending = false;
}
pub(crate) const fn priority(&self) -> Priority {
self.priority
}
pub(crate) fn set_priority(&mut self, priority: Priority) {
self.priority = priority;
}
pub(crate) const fn trigger(&self) -> TriggerMode {
self.trigger
}
pub(crate) fn set_trigger(&mut self, trigger: TriggerMode) {
self.trigger = trigger;
}
pub(crate) const fn route(&self) -> Option<GicAffinity> {
self.route
}
pub(crate) fn set_route(&mut self, route: GicAffinity) {
self.route = Some(route);
self.cpu_target_mask = None;
}
pub(crate) fn clear_route(&mut self) {
self.route = None;
}
pub(crate) const fn cpu_target_mask(&self) -> Option<u8> {
self.cpu_target_mask
}
pub(crate) fn set_cpu_target_mask(&mut self, mask: u8) {
self.cpu_target_mask = Some(mask);
self.route = None;
}
pub(crate) fn set_level(&mut self, asserted: bool) {
let rising_edge = asserted && !self.line_asserted;
self.line_asserted = asserted;
if asserted {
self.pending = true;
if self.inflight && self.active && rising_edge {
self.redelivery_pending = true;
}
} else if self.trigger == TriggerMode::Level && !self.active {
self.pending = false;
self.redelivery_pending = false;
}
}
pub(crate) fn pulse(&mut self) {
self.pending = true;
if self.inflight {
self.redelivery_pending = true;
}
}
pub(crate) fn complete(&mut self) {
self.active = false;
if self.trigger == TriggerMode::Level && self.line_asserted {
self.pending = true;
}
}
pub(crate) const fn deliverable(&self) -> bool {
self.enabled && self.pending
}
}