// Copyright 2022 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use base::AsRawDescriptor;5use base::AsRawDescriptors;6use base::Event;7use base::RawDescriptor;8use base::Result;9use serde::Deserialize;10use serde::Serialize;1112/// A structure suitable for implementing edge triggered interrupts in device backends.13pub struct IrqEdgeEvent(Event);1415impl IrqEdgeEvent {16pub fn new() -> Result<IrqEdgeEvent> {17Event::new().map(IrqEdgeEvent)18}1920pub fn try_clone(&self) -> Result<IrqEdgeEvent> {21self.0.try_clone().map(IrqEdgeEvent)22}2324/// Creates an instance of IrqLevelEvent from an existing event.25pub fn from_event(trigger_evt: Event) -> IrqEdgeEvent {26IrqEdgeEvent(trigger_evt)27}2829pub fn get_trigger(&self) -> &Event {30&self.031}3233pub fn trigger(&self) -> Result<()> {34self.0.signal()35}3637pub fn clear_trigger(&self) {38let _ = self.0.wait();39}40}4142/// A structure suitable for implementing level triggered interrupts in device backends.43///44/// Level-triggered interrupts require the device to monitor a resample event from the IRQ chip,45/// which can be retrieved with [`IrqLevelEvent::get_resample()`]. When the guest OS acknowledges46/// the interrupt with an End of Interrupt (EOI) command, the IRQ chip will signal the resample47/// event. Each time the resample event is signalled, the device should re-check its state and call48/// [`IrqLevelEvent::trigger()`] again if the interrupt should still be asserted.49#[derive(Debug, Serialize, Deserialize)]50pub struct IrqLevelEvent {51/// An event used by the device backend to signal hypervisor/VM about data or new unit52/// of work being available.53trigger_evt: Event,54/// An event used by the hypervisor to signal device backend that it completed processing a55/// unit of work and that device should re-raise `trigger_evt` if additional work needs to56/// be done.57resample_evt: Event,58}5960impl IrqLevelEvent {61pub fn new() -> Result<IrqLevelEvent> {62let trigger_evt = Event::new()?;63let resample_evt = Event::new()?;64Ok(IrqLevelEvent {65trigger_evt,66resample_evt,67})68}6970pub fn try_clone(&self) -> Result<IrqLevelEvent> {71let trigger_evt = self.trigger_evt.try_clone()?;72let resample_evt = self.resample_evt.try_clone()?;73Ok(IrqLevelEvent {74trigger_evt,75resample_evt,76})77}7879/// Creates an instance of IrqLevelEvent from an existing pair of events.80pub fn from_event_pair(trigger_evt: Event, resample_evt: Event) -> IrqLevelEvent {81IrqLevelEvent {82trigger_evt,83resample_evt,84}85}8687pub fn get_trigger(&self) -> &Event {88&self.trigger_evt89}9091pub fn get_resample(&self) -> &Event {92&self.resample_evt93}9495/// Allows backend to inject interrupt (typically into guest).96pub fn trigger(&self) -> Result<()> {97self.trigger_evt.signal()98}99100/// Allows code servicing interrupt to consume or clear the event.101pub fn clear_trigger(&self) {102let _ = self.trigger_evt.wait();103}104105/// Allows code servicing interrupt to signal that processing is done and that the backend106/// should go ahead and re-trigger it if there is more work needs to be done.107/// Note that typically resampling is signalled not by individual backends, but rather108/// by the code implementing interrupt controller.109pub fn trigger_resample(&self) -> Result<()> {110self.resample_evt.signal()111}112113/// Allows backend to consume or clear the resample event.114pub fn clear_resample(&self) {115let _ = self.resample_evt.wait();116}117}118119impl AsRawDescriptors for IrqEdgeEvent {120fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {121vec![self.0.as_raw_descriptor()]122}123}124125impl AsRawDescriptors for IrqLevelEvent {126fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {127vec![128self.trigger_evt.as_raw_descriptor(),129self.resample_evt.as_raw_descriptor(),130]131}132}133134135