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