1- // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
1+ // Copyright (C) 2019-2020 Alibaba Cloud, Red Hat, Inc and Amazon.com, Inc. or its affiliates.
2+ // All Rights Reserved.
3+
24// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
35
46//! Traits and Structs to manage interrupt sources for devices.
7+ //!
8+ //! In system programming, an interrupt is a signal to the processor emitted by hardware or
9+ //! software indicating an event that needs immediate attention. An interrupt alerts the processor
10+ //! to a high-priority condition requiring the interruption of the current code the processor is
11+ //! executing. The processor responds by suspending its current activities, saving its state, and
12+ //! executing a function called an interrupt handler (or an interrupt service routine, ISR) to deal
13+ //! with the event. This interruption is temporary, and, after the interrupt handler finishes,
14+ //! unless handling the interrupt has emitted a fatal error, the processor resumes normal
15+ //! activities.
16+ //!
17+ //! Hardware interrupts are used by devices to communicate that they require attention from the
18+ //! operating system, or a bare-metal program running on the CPU if there are no OSes. The act of
19+ //! initiating a hardware interrupt is referred to as an interrupt request (IRQ). Different devices
20+ //! are usually associated with different interrupts using a unique value associated with each
21+ //! interrupt. This makes it possible to know which hardware device caused which interrupts.
22+ //! These interrupt values are often called IRQ lines, or just interrupt lines.
23+ //!
24+ //! Nowadays, IRQ lines is not the only mechanism to deliver device interrupts to processors.
25+ //! MSI [(Message Signaled Interrupt)](https://en.wikipedia.org/wiki/Message_Signaled_Interrupts)
26+ //! is another commonly used alternative in-band method of signaling an interrupt, using special
27+ //! in-band messages to replace traditional out-of-band assertion of dedicated interrupt lines.
28+ //! While more complex to implement in a device, message signaled interrupts have some significant
29+ //! advantages over pin-based out-of-band interrupt signaling. Message signaled interrupts are
30+ //! supported in PCI bus since its version 2.2, and in later available PCI Express bus. Some non-PCI
31+ //! architectures also use message signaled interrupts.
32+ //!
33+ //! While IRQ is a term commonly used by Operating Systems when dealing with hardware
34+ //! interrupts, the IRQ numbers managed by OSes are independent of the ones managed by VMM.
35+ //! For simplicity sake, the term `Interrupt Source` is used instead of IRQ to represent both pin-based
36+ //! interrupts and MSI interrupts.
37+ //!
38+ //! A device may support multiple types of interrupts, and each type of interrupt may support one
39+ //! or multiple interrupt sources. For example, a PCI device may support:
40+ //! * Legacy Irq: exactly one interrupt source.
41+ //! * PCI MSI Irq: 1,2,4,8,16,32 interrupt sources.
42+ //! * PCI MSIx Irq: 2^n(n=0-11) interrupt sources.
43+
44+ pub mod legacy;
45+ pub mod msi;
546
6- use std:: result:: Result ;
47+ use std:: fmt:: { self , Display } ;
48+ use std:: io;
49+ use std:: ops:: Deref ;
750
851/// Abstraction for a simple, push-button like interrupt mechanism.
952/// This helps in abstracting away how events/interrupts are generated when
@@ -18,5 +61,140 @@ pub trait Trigger {
1861 type E : std:: fmt:: Debug ;
1962
2063 /// Trigger an event.
21- fn trigger ( & self ) -> Result < ( ) , Self :: E > ;
64+ fn trigger ( & self ) -> std:: result:: Result < ( ) , Self :: E > ;
65+ }
66+
67+ /// Errors associated with handling interrupts
68+ #[ derive( Debug ) ]
69+ pub enum Error {
70+ /// Operation not supported for this interrupt.
71+ OperationNotSupported ,
72+
73+ /// The specified configuration is not valid.
74+ InvalidConfiguration ,
75+
76+ /// The interrupt was not enabled.
77+ InterruptNotEnabled ,
78+
79+ /// Generic IO error,
80+ IOError ( io:: Error ) ,
81+ }
82+
83+ /// Reuse std::io::Result to simplify interoperability among crates.
84+ pub type Result < T > = std:: result:: Result < T , Error > ;
85+
86+ impl Display for Error {
87+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
88+ write ! ( f, "Interrupt error: " ) ?;
89+ match self {
90+ Error :: OperationNotSupported => write ! ( f, "operation not supported" ) ,
91+ Error :: InvalidConfiguration => write ! ( f, "invalid configuration" ) ,
92+ Error :: InterruptNotEnabled => write ! ( f, "the interrupt was not enabled" ) ,
93+ Error :: IOError ( error) => write ! ( f, "{}" , error) ,
94+ }
95+ }
96+ }
97+
98+ impl From < io:: Error > for Error {
99+ fn from ( e : io:: Error ) -> Error {
100+ Error :: IOError ( e)
101+ }
102+ }
103+
104+ /// Trait for interrupt producers.
105+ pub trait Interrupt {
106+ /// The type of Trigger object used for notifications by this interrupt.
107+ type TriggerType : Trigger ;
108+
109+ /// Inject an interrupt from this interrupt source into the guest.
110+ fn trigger ( & self ) -> std:: result:: Result < ( ) , <Self :: TriggerType as Trigger >:: E > ;
111+
112+ /// Returns an interrupt notifier from this interrupt.
113+ ///
114+ /// An interrupt notifier allows for external components and processes
115+ /// to inject interrupts into a guest, by writing to the file returned
116+ /// by this method.
117+ fn notifier ( & self ) -> Option < Self :: TriggerType > {
118+ None
119+ }
120+
121+ /// Called back when the CPU acknowledges the interrupt.
122+ fn acknowledge ( & self ) { }
123+
124+ /// Returns an end-of-interrupt notifier from this interrupt.
125+ ///
126+ /// An end-of-interrupt notifier allows for external components and processes
127+ /// to be notified when a guest acknowledges an interrupt. This can be used
128+ /// to resample and inject a level-triggered interrupt, or to mitigate the
129+ /// effect of lost timer interrupts.
130+ fn ack_notifier ( & self ) -> Option < Self :: TriggerType > {
131+ None
132+ }
133+
134+ /// Enable generation of interrupts from this interrupt source.
135+ fn enable ( & self ) -> Result < ( ) > ;
136+
137+ /// Disable generation of interrupts from this interrupt source.
138+ fn disable ( & self ) -> Result < ( ) > {
139+ Err ( Error :: OperationNotSupported )
140+ }
141+ }
142+
143+ /// Trait for interrupts that allow users to configure interrupt parameters.
144+ pub trait ConfigurableInterrupt : Interrupt {
145+ /// Type describing the configuration spec of the interrupt.
146+ type Cfg ;
147+
148+ /// Update configuration of the interrupt.
149+ fn update ( & self , config : & Self :: Cfg ) -> Result < ( ) > ;
150+
151+ /// Returns the current configuration of the interrupt.
152+ fn get_config ( & self ) -> Result < Self :: Cfg > ;
153+ }
154+
155+ /// Trait for interrupts that can be masked or unmasked.
156+ pub trait MaskableInterrupt : Interrupt {
157+ /// Mask the interrupt. Masked interrupts are remembered but
158+ /// not delivered.
159+ fn mask ( & self ) -> Result < ( ) > ;
160+
161+ /// Unmask the interrupt, delivering it if it was pending.
162+ fn unmask ( & self ) -> Result < ( ) > ;
163+ }
164+
165+ /// Trait to manage a group of interrupt sources for a device.
166+ ///
167+ /// A device may use an InterruptSourceGroup to manage multiple interrupts of the same type.
168+ /// The group allows a device to request and release interrupts and perform actions on the
169+ /// whole collection of interrupts like enable and disable for cases where enabling or disabling
170+ /// a single interrupt in the group does not make sense. For example, PCI MSI interrupts must be
171+ /// enabled as a group.
172+ pub trait InterruptSourceGroup : Send {
173+ /// Type of the interrupts contained in this group.
174+ type InterruptType : Interrupt ;
175+
176+ /// Interrupt Type returned by get
177+ type InterruptWrapper : Deref < Target = Self :: InterruptType > ;
178+
179+ /// Return whether the group manages no interrupts.
180+ fn is_empty ( & self ) -> bool ;
181+
182+ /// Get number of interrupt sources managed by the group.
183+ fn len ( & self ) -> usize ;
184+
185+ /// Enable the interrupt sources in the group to generate interrupts.
186+ fn enable ( & self ) -> Result < ( ) > ;
187+
188+ /// Disable the interrupt sources in the group to generate interrupts.
189+ fn disable ( & self ) -> Result < ( ) > ;
190+
191+ /// Return the index-th interrupt in the group, or `None` if the index is out
192+ /// of bounds.
193+ fn get ( & self , index : usize ) -> Option < Self :: InterruptWrapper > ;
194+
195+ /// Request new interrupts within this group.
196+ fn allocate_interrupts ( & mut self , size : usize ) -> Result < ( ) > ;
197+
198+ /// Release all interrupts within this group.
199+ fn free_interrupts ( & mut self ) -> Result < ( ) > ;
22200}
0 commit comments