• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
11 /// A structure suitable for implementing edge triggered interrupts in device backends.
12 pub struct IrqEdgeEvent(Event);
13 
14 impl IrqEdgeEvent {
new() -> Result<IrqEdgeEvent>15     pub fn new() -> Result<IrqEdgeEvent> {
16         Event::new().map(IrqEdgeEvent)
17     }
18 
try_clone(&self) -> Result<IrqEdgeEvent>19     pub fn try_clone(&self) -> Result<IrqEdgeEvent> {
20         self.0.try_clone().map(IrqEdgeEvent)
21     }
22 
23     /// Creates an instance of IrqLevelEvent from an existing event.
from_event(trigger_evt: Event) -> IrqEdgeEvent24     pub fn from_event(trigger_evt: Event) -> IrqEdgeEvent {
25         IrqEdgeEvent(trigger_evt)
26     }
27 
get_trigger(&self) -> &Event28     pub fn get_trigger(&self) -> &Event {
29         &self.0
30     }
31 
trigger(&self) -> Result<()>32     pub fn trigger(&self) -> Result<()> {
33         self.0.signal()
34     }
35 
clear_trigger(&self)36     pub fn clear_trigger(&self) {
37         let _ = self.0.wait();
38     }
39 }
40 
41 /// A structure suitable for implementing level triggered interrupts in device backends.
42 ///
43 /// Level-triggered interrupts require the device to monitor a resample event from the IRQ chip,
44 /// which can be retrieved with [`IrqLevelEvent::get_resample()`]. When the guest OS acknowledges
45 /// the interrupt with an End of Interrupt (EOI) command, the IRQ chip will signal the resample
46 /// event. Each time the resample event is signalled, the device should re-check its state and call
47 /// [`IrqLevelEvent::trigger()`] again if the interrupt should still be asserted.
48 pub struct IrqLevelEvent {
49     /// An event used by the device backend to signal hypervisor/VM about data or new unit
50     /// of work being available.
51     trigger_evt: Event,
52     /// An event used by the hypervisor to signal device backend that it completed processing a unit
53     /// of work and that device should re-raise `trigger_evt` if additional work needs to be done.
54     resample_evt: Event,
55 }
56 
57 impl IrqLevelEvent {
new() -> Result<IrqLevelEvent>58     pub fn new() -> Result<IrqLevelEvent> {
59         let trigger_evt = Event::new()?;
60         let resample_evt = Event::new()?;
61         Ok(IrqLevelEvent {
62             trigger_evt,
63             resample_evt,
64         })
65     }
66 
try_clone(&self) -> Result<IrqLevelEvent>67     pub fn try_clone(&self) -> Result<IrqLevelEvent> {
68         let trigger_evt = self.trigger_evt.try_clone()?;
69         let resample_evt = self.resample_evt.try_clone()?;
70         Ok(IrqLevelEvent {
71             trigger_evt,
72             resample_evt,
73         })
74     }
75 
76     /// Creates an instance of IrqLevelEvent from an existing pair of events.
from_event_pair(trigger_evt: Event, resample_evt: Event) -> IrqLevelEvent77     pub fn from_event_pair(trigger_evt: Event, resample_evt: Event) -> IrqLevelEvent {
78         IrqLevelEvent {
79             trigger_evt,
80             resample_evt,
81         }
82     }
83 
get_trigger(&self) -> &Event84     pub fn get_trigger(&self) -> &Event {
85         &self.trigger_evt
86     }
87 
get_resample(&self) -> &Event88     pub fn get_resample(&self) -> &Event {
89         &self.resample_evt
90     }
91 
92     /// Allows backend to inject interrupt (typically into guest).
trigger(&self) -> Result<()>93     pub fn trigger(&self) -> Result<()> {
94         self.trigger_evt.signal()
95     }
96 
97     /// Allows code servicing interrupt to consume or clear the event.
clear_trigger(&self)98     pub fn clear_trigger(&self) {
99         let _ = self.trigger_evt.wait();
100     }
101 
102     /// Allows code servicing interrupt to signal that processing is done and that the backend
103     /// should go ahead and re-trigger it if there is more work needs to be done.
104     /// Note that typically resampling is signalled not by individual backends, but rather
105     /// by the code implementing interrupt controller.
trigger_resample(&self) -> Result<()>106     pub fn trigger_resample(&self) -> Result<()> {
107         self.resample_evt.signal()
108     }
109 
110     /// Allows backend to consume or clear the resample event.
clear_resample(&self)111     pub fn clear_resample(&self) {
112         let _ = self.resample_evt.wait();
113     }
114 }
115 
116 impl AsRawDescriptors for IrqEdgeEvent {
as_raw_descriptors(&self) -> Vec<RawDescriptor>117     fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
118         vec![self.0.as_raw_descriptor()]
119     }
120 }
121 
122 impl AsRawDescriptors for IrqLevelEvent {
as_raw_descriptors(&self) -> Vec<RawDescriptor>123     fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
124         vec![
125             self.trigger_evt.as_raw_descriptor(),
126             self.resample_evt.as_raw_descriptor(),
127         ]
128     }
129 }
130