devices/
irq_event.rs

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
5use base::AsRawDescriptor;
6use base::AsRawDescriptors;
7use base::Event;
8use base::RawDescriptor;
9use base::Result;
10use serde::Deserialize;
11use serde::Serialize;
12
13/// A structure suitable for implementing edge triggered interrupts in device backends.
14pub struct IrqEdgeEvent(Event);
15
16impl IrqEdgeEvent {
17    pub fn new() -> Result<IrqEdgeEvent> {
18        Event::new().map(IrqEdgeEvent)
19    }
20
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.
26    pub fn from_event(trigger_evt: Event) -> IrqEdgeEvent {
27        IrqEdgeEvent(trigger_evt)
28    }
29
30    pub fn get_trigger(&self) -> &Event {
31        &self.0
32    }
33
34    pub fn trigger(&self) -> Result<()> {
35        self.0.signal()
36    }
37
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)]
51pub 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
61impl 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
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.
81    pub fn from_event_pair(trigger_evt: Event, resample_evt: Event) -> IrqLevelEvent {
82        IrqLevelEvent {
83            trigger_evt,
84            resample_evt,
85        }
86    }
87
88    pub fn get_trigger(&self) -> &Event {
89        &self.trigger_evt
90    }
91
92    pub fn get_resample(&self) -> &Event {
93        &self.resample_evt
94    }
95
96    /// Allows backend to inject interrupt (typically into guest).
97    pub fn trigger(&self) -> Result<()> {
98        self.trigger_evt.signal()
99    }
100
101    /// Allows code servicing interrupt to consume or clear the event.
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.
110    pub fn trigger_resample(&self) -> Result<()> {
111        self.resample_evt.signal()
112    }
113
114    /// Allows backend to consume or clear the resample event.
115    pub fn clear_resample(&self) {
116        let _ = self.resample_evt.wait();
117    }
118}
119
120impl AsRawDescriptors for IrqEdgeEvent {
121    fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
122        vec![self.0.as_raw_descriptor()]
123    }
124}
125
126impl AsRawDescriptors for IrqLevelEvent {
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}