1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// 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(),
        ]
    }
}