blob: 44b173a38278f4d805d632edc1ae659f35b83ae6 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use base::AsRawDescriptor;
use base::AsRawDescriptors;
use base::Event;
use base::RawDescriptor;
use base::Result;
use serde::Deserialize;
use serde::Serialize;
/// A structure suitable for implementing edge triggered interrupts in device backends.
pub struct IrqEdgeEvent(Event);
impl IrqEdgeEvent {
pub fn new() -> Result<IrqEdgeEvent> {
Event::new().map(IrqEdgeEvent)
}
pub fn try_clone(&self) -> Result<IrqEdgeEvent> {
self.0.try_clone().map(IrqEdgeEvent)
}
/// Creates an instance of IrqLevelEvent from an existing event.
pub fn from_event(trigger_evt: Event) -> IrqEdgeEvent {
IrqEdgeEvent(trigger_evt)
}
pub fn get_trigger(&self) -> &Event {
&self.0
}
pub fn trigger(&self) -> Result<()> {
self.0.signal()
}
pub fn clear_trigger(&self) {
let _ = self.0.wait();
}
}
/// A structure suitable for implementing level triggered interrupts in device backends.
///
/// Level-triggered interrupts require the device to monitor a resample event from the IRQ chip,
/// which can be retrieved with [`IrqLevelEvent::get_resample()`]. When the guest OS acknowledges
/// the interrupt with an End of Interrupt (EOI) command, the IRQ chip will signal the resample
/// event. Each time the resample event is signalled, the device should re-check its state and call
/// [`IrqLevelEvent::trigger()`] again if the interrupt should still be asserted.
#[derive(Debug, Serialize, Deserialize)]
pub struct IrqLevelEvent {
/// An event used by the device backend to signal hypervisor/VM about data or new unit
/// of work being available.
trigger_evt: Event,
/// An event used by the hypervisor to signal device backend that it completed processing a
/// unit of work and that device should re-raise `trigger_evt` if additional work needs to
/// be done.
resample_evt: Event,
}
impl IrqLevelEvent {
pub fn new() -> Result<IrqLevelEvent> {
let trigger_evt = Event::new()?;
let resample_evt = Event::new()?;
Ok(IrqLevelEvent {
trigger_evt,
resample_evt,
})
}
pub fn try_clone(&self) -> Result<IrqLevelEvent> {
let trigger_evt = self.trigger_evt.try_clone()?;
let resample_evt = self.resample_evt.try_clone()?;
Ok(IrqLevelEvent {
trigger_evt,
resample_evt,
})
}
/// Creates an instance of IrqLevelEvent from an existing pair of events.
pub fn from_event_pair(trigger_evt: Event, resample_evt: Event) -> IrqLevelEvent {
IrqLevelEvent {
trigger_evt,
resample_evt,
}
}
pub fn get_trigger(&self) -> &Event {
&self.trigger_evt
}
pub fn get_resample(&self) -> &Event {
&self.resample_evt
}
/// Allows backend to inject interrupt (typically into guest).
pub fn trigger(&self) -> Result<()> {
self.trigger_evt.signal()
}
/// Allows code servicing interrupt to consume or clear the event.
pub fn clear_trigger(&self) {
let _ = self.trigger_evt.wait();
}
/// Allows code servicing interrupt to signal that processing is done and that the backend
/// should go ahead and re-trigger it if there is more work needs to be done.
/// Note that typically resampling is signalled not by individual backends, but rather
/// by the code implementing interrupt controller.
pub fn trigger_resample(&self) -> Result<()> {
self.resample_evt.signal()
}
/// Allows backend to consume or clear the resample event.
pub fn clear_resample(&self) {
let _ = self.resample_evt.wait();
}
}
impl AsRawDescriptors for IrqEdgeEvent {
fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
vec![self.0.as_raw_descriptor()]
}
}
impl AsRawDescriptors for IrqLevelEvent {
fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
vec![
self.trigger_evt.as_raw_descriptor(),
self.resample_evt.as_raw_descriptor(),
]
}
}