xref: /aosp_15_r20/external/crosvm/devices/src/irq_event.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use base::AsRawDescriptor;
6 use base::AsRawDescriptors;
7 use base::Event;
8 use base::RawDescriptor;
9 use base::Result;
10 use serde::Deserialize;
11 use serde::Serialize;
12 
13 /// A structure suitable for implementing edge triggered interrupts in device backends.
14 pub struct IrqEdgeEvent(Event);
15 
16 impl IrqEdgeEvent {
new() -> Result<IrqEdgeEvent>17     pub fn new() -> Result<IrqEdgeEvent> {
18         Event::new().map(IrqEdgeEvent)
19     }
20 
try_clone(&self) -> Result<IrqEdgeEvent>21     pub fn try_clone(&self) -> Result<IrqEdgeEvent> {
22         self.0.try_clone().map(IrqEdgeEvent)
23     }
24 
25     /// Creates an instance of IrqLevelEvent from an existing event.
from_event(trigger_evt: Event) -> IrqEdgeEvent26     pub fn from_event(trigger_evt: Event) -> IrqEdgeEvent {
27         IrqEdgeEvent(trigger_evt)
28     }
29 
get_trigger(&self) -> &Event30     pub fn get_trigger(&self) -> &Event {
31         &self.0
32     }
33 
trigger(&self) -> Result<()>34     pub fn trigger(&self) -> Result<()> {
35         self.0.signal()
36     }
37 
clear_trigger(&self)38     pub fn clear_trigger(&self) {
39         let _ = self.0.wait();
40     }
41 }
42 
43 /// A structure suitable for implementing level triggered interrupts in device backends.
44 ///
45 /// Level-triggered interrupts require the device to monitor a resample event from the IRQ chip,
46 /// which can be retrieved with [`IrqLevelEvent::get_resample()`]. When the guest OS acknowledges
47 /// the interrupt with an End of Interrupt (EOI) command, the IRQ chip will signal the resample
48 /// event. Each time the resample event is signalled, the device should re-check its state and call
49 /// [`IrqLevelEvent::trigger()`] again if the interrupt should still be asserted.
50 #[derive(Debug, Serialize, Deserialize)]
51 pub struct IrqLevelEvent {
52     /// An event used by the device backend to signal hypervisor/VM about data or new unit
53     /// of work being available.
54     trigger_evt: Event,
55     /// An event used by the hypervisor to signal device backend that it completed processing a
56     /// unit of work and that device should re-raise `trigger_evt` if additional work needs to
57     /// be done.
58     resample_evt: Event,
59 }
60 
61 impl IrqLevelEvent {
new() -> Result<IrqLevelEvent>62     pub fn new() -> Result<IrqLevelEvent> {
63         let trigger_evt = Event::new()?;
64         let resample_evt = Event::new()?;
65         Ok(IrqLevelEvent {
66             trigger_evt,
67             resample_evt,
68         })
69     }
70 
try_clone(&self) -> Result<IrqLevelEvent>71     pub fn try_clone(&self) -> Result<IrqLevelEvent> {
72         let trigger_evt = self.trigger_evt.try_clone()?;
73         let resample_evt = self.resample_evt.try_clone()?;
74         Ok(IrqLevelEvent {
75             trigger_evt,
76             resample_evt,
77         })
78     }
79 
80     /// Creates an instance of IrqLevelEvent from an existing pair of events.
from_event_pair(trigger_evt: Event, resample_evt: Event) -> IrqLevelEvent81     pub fn from_event_pair(trigger_evt: Event, resample_evt: Event) -> IrqLevelEvent {
82         IrqLevelEvent {
83             trigger_evt,
84             resample_evt,
85         }
86     }
87 
get_trigger(&self) -> &Event88     pub fn get_trigger(&self) -> &Event {
89         &self.trigger_evt
90     }
91 
get_resample(&self) -> &Event92     pub fn get_resample(&self) -> &Event {
93         &self.resample_evt
94     }
95 
96     /// Allows backend to inject interrupt (typically into guest).
trigger(&self) -> Result<()>97     pub fn trigger(&self) -> Result<()> {
98         self.trigger_evt.signal()
99     }
100 
101     /// Allows code servicing interrupt to consume or clear the event.
clear_trigger(&self)102     pub fn clear_trigger(&self) {
103         let _ = self.trigger_evt.wait();
104     }
105 
106     /// Allows code servicing interrupt to signal that processing is done and that the backend
107     /// should go ahead and re-trigger it if there is more work needs to be done.
108     /// Note that typically resampling is signalled not by individual backends, but rather
109     /// by the code implementing interrupt controller.
trigger_resample(&self) -> Result<()>110     pub fn trigger_resample(&self) -> Result<()> {
111         self.resample_evt.signal()
112     }
113 
114     /// Allows backend to consume or clear the resample event.
clear_resample(&self)115     pub fn clear_resample(&self) {
116         let _ = self.resample_evt.wait();
117     }
118 }
119 
120 impl AsRawDescriptors for IrqEdgeEvent {
as_raw_descriptors(&self) -> Vec<RawDescriptor>121     fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
122         vec![self.0.as_raw_descriptor()]
123     }
124 }
125 
126 impl AsRawDescriptors for IrqLevelEvent {
as_raw_descriptors(&self) -> Vec<RawDescriptor>127     fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
128         vec![
129             self.trigger_evt.as_raw_descriptor(),
130             self.resample_evt.as_raw_descriptor(),
131         ]
132     }
133 }
134