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