axvirtio_common/pci/transport/
transition.rs1use alloc::sync::Arc;
2
3use axdevice_base::DeviceResult;
4
5use super::{ActivityPermit, QueueNotifyOutcome};
6use crate::pci::{InterruptTransition, VirtioPciInterruptCoordinator};
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub(super) enum InterruptPublicationKind {
10 Queue,
11 Configuration,
12}
13
14pub struct QueueNotification {
17 pub(super) outcome: QueueNotifyOutcome,
18 pub(super) retry_required: bool,
19 pub(super) publication: InterruptPublicationRequest,
20}
21
22impl QueueNotification {
23 pub const fn outcome(&self) -> QueueNotifyOutcome {
25 self.outcome
26 }
27
28 pub const fn requires_poll(&self) -> bool {
33 self.retry_required || matches!(self.outcome, QueueNotifyOutcome::Deferred { .. })
34 }
35
36 pub const fn requires_interrupt_publication(&self) -> bool {
39 self.publication.requires_irq_permit()
40 }
41
42 pub const fn generation(&self) -> Option<VirtioQueueGeneration> {
45 self.publication.generation()
46 }
47
48 pub fn complete(self) {
50 self.publication.cancel();
51 }
52
53 pub fn publish<F>(self, publish_transition: F) -> DeviceResult
56 where
57 F: FnMut(InterruptTransition) -> DeviceResult,
58 {
59 self.publication.publish(publish_transition)
60 }
61
62 pub fn into_interrupt_publication(self) -> InterruptPublicationRequest {
64 self.publication
65 }
66}
67
68pub struct InterruptPublicationRequest {
70 kind: Option<InterruptPublicationKind>,
71 activity: Option<ActivityPermit>,
72 interrupts: Arc<VirtioPciInterruptCoordinator>,
73}
74
75impl core::fmt::Debug for InterruptPublicationRequest {
76 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77 formatter
78 .debug_struct("InterruptPublicationRequest")
79 .field("kind", &self.kind)
80 .field("has_activity", &self.activity.is_some())
81 .finish_non_exhaustive()
82 }
83}
84
85impl InterruptPublicationRequest {
86 pub(super) fn new(
87 interrupts: Arc<VirtioPciInterruptCoordinator>,
88 kind: Option<InterruptPublicationKind>,
89 activity: Option<ActivityPermit>,
90 ) -> Self {
91 Self {
92 kind,
93 activity,
94 interrupts,
95 }
96 }
97
98 pub const fn requires_irq_permit(&self) -> bool {
100 self.kind.is_some()
101 }
102
103 pub const fn generation(&self) -> Option<VirtioQueueGeneration> {
105 match &self.activity {
106 Some(activity) => Some(activity.generation),
107 None => None,
108 }
109 }
110
111 pub fn publish<F>(mut self, mut publish_transition: F) -> DeviceResult
117 where
118 F: FnMut(InterruptTransition) -> DeviceResult,
119 {
120 let Some(kind) = self.kind.take() else {
121 self.activity.take();
122 return Ok(());
123 };
124 let mut transition = match kind {
125 InterruptPublicationKind::Queue => self.interrupts.record_queue_completion(true),
126 InterruptPublicationKind::Configuration => self.interrupts.record_config_change(),
127 };
128 loop {
129 if let Err(error) = publish_transition(transition) {
130 self.interrupts.complete_transition(transition, false);
131 self.activity.take();
132 return Err(error);
133 }
134 transition = self.interrupts.complete_transition(transition, true);
135 if transition == InterruptTransition::None {
136 self.activity.take();
137 return Ok(());
138 }
139 }
140 }
141
142 pub fn cancel(mut self) {
144 self.activity.take();
145 }
146}
147
148#[derive(Clone, Copy, Debug, Eq, PartialEq)]
151pub struct InterruptTransitionIntent {
152 transition: InterruptTransition,
153 generation: VirtioQueueGeneration,
154}
155
156impl InterruptTransitionIntent {
157 pub(super) const fn new(
158 transition: InterruptTransition,
159 generation: VirtioQueueGeneration,
160 ) -> Self {
161 Self {
162 transition,
163 generation,
164 }
165 }
166
167 pub const fn transition(self) -> InterruptTransition {
169 self.transition
170 }
171
172 pub const fn generation(self) -> VirtioQueueGeneration {
174 self.generation
175 }
176}
177
178#[derive(Clone, Copy, Debug, Eq, PartialEq)]
180pub struct VirtioQueueGeneration(pub(super) u64);
181
182impl VirtioQueueGeneration {
183 pub const fn from_value(value: u64) -> Self {
185 Self(value)
186 }
187
188 pub const fn value(self) -> u64 {
190 self.0
191 }
192}
193
194pub struct InterruptTransitionRequest {
196 transition: InterruptTransition,
197 activity: Option<ActivityPermit>,
198 interrupts: Arc<VirtioPciInterruptCoordinator>,
199}
200
201impl core::fmt::Debug for InterruptTransitionRequest {
202 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
203 formatter
204 .debug_struct("InterruptTransitionRequest")
205 .field("transition", &self.transition)
206 .field("has_activity", &self.activity.is_some())
207 .finish_non_exhaustive()
208 }
209}
210
211impl InterruptTransitionRequest {
212 pub(super) fn new(
213 interrupts: Arc<VirtioPciInterruptCoordinator>,
214 transition: InterruptTransition,
215 activity: Option<ActivityPermit>,
216 ) -> Self {
217 Self {
218 transition,
219 activity,
220 interrupts,
221 }
222 }
223
224 pub(super) fn without_activity(
225 interrupts: Arc<VirtioPciInterruptCoordinator>,
226 transition: InterruptTransition,
227 ) -> Self {
228 Self::new(interrupts, transition, None)
229 }
230
231 pub const fn transition(&self) -> InterruptTransition {
233 self.transition
234 }
235}
236
237impl Drop for InterruptTransitionRequest {
238 fn drop(&mut self) {
239 self.interrupts.cancel_transition(self.transition);
240 self.activity.take();
241 }
242}