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) publication: InterruptPublicationRequest,
19}
20
21impl QueueNotification {
22 pub const fn outcome(&self) -> QueueNotifyOutcome {
24 self.outcome
25 }
26
27 pub const fn requires_interrupt_publication(&self) -> bool {
30 self.publication.requires_irq_permit()
31 }
32
33 pub const fn generation(&self) -> Option<VirtioQueueGeneration> {
36 self.publication.generation()
37 }
38
39 pub fn complete(self) {
41 self.publication.cancel();
42 }
43
44 pub fn publish<F>(self, publish_transition: F) -> DeviceResult
47 where
48 F: FnMut(InterruptTransition) -> DeviceResult,
49 {
50 self.publication.publish(publish_transition)
51 }
52
53 pub fn into_interrupt_publication(self) -> InterruptPublicationRequest {
55 self.publication
56 }
57}
58
59pub struct InterruptPublicationRequest {
61 kind: Option<InterruptPublicationKind>,
62 activity: Option<ActivityPermit>,
63 interrupts: Arc<VirtioPciInterruptCoordinator>,
64}
65
66impl core::fmt::Debug for InterruptPublicationRequest {
67 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
68 formatter
69 .debug_struct("InterruptPublicationRequest")
70 .field("kind", &self.kind)
71 .field("has_activity", &self.activity.is_some())
72 .finish_non_exhaustive()
73 }
74}
75
76impl InterruptPublicationRequest {
77 pub(super) fn new(
78 interrupts: Arc<VirtioPciInterruptCoordinator>,
79 kind: Option<InterruptPublicationKind>,
80 activity: Option<ActivityPermit>,
81 ) -> Self {
82 Self {
83 kind,
84 activity,
85 interrupts,
86 }
87 }
88
89 pub const fn requires_irq_permit(&self) -> bool {
91 self.kind.is_some()
92 }
93
94 pub const fn generation(&self) -> Option<VirtioQueueGeneration> {
96 match &self.activity {
97 Some(activity) => Some(activity.generation),
98 None => None,
99 }
100 }
101
102 pub fn publish<F>(mut self, mut publish_transition: F) -> DeviceResult
108 where
109 F: FnMut(InterruptTransition) -> DeviceResult,
110 {
111 let Some(kind) = self.kind.take() else {
112 self.activity.take();
113 return Ok(());
114 };
115 let mut transition = match kind {
116 InterruptPublicationKind::Queue => self.interrupts.record_queue_completion(true),
117 InterruptPublicationKind::Configuration => self.interrupts.record_config_change(),
118 };
119 loop {
120 if let Err(error) = publish_transition(transition) {
121 self.interrupts.complete_transition(transition, false);
122 self.activity.take();
123 return Err(error);
124 }
125 transition = self.interrupts.complete_transition(transition, true);
126 if transition == InterruptTransition::None {
127 self.activity.take();
128 return Ok(());
129 }
130 }
131 }
132
133 pub fn cancel(mut self) {
135 self.activity.take();
136 }
137}
138
139#[derive(Clone, Copy, Debug, Eq, PartialEq)]
142pub struct InterruptTransitionIntent {
143 transition: InterruptTransition,
144 generation: VirtioQueueGeneration,
145}
146
147impl InterruptTransitionIntent {
148 pub(super) const fn new(
149 transition: InterruptTransition,
150 generation: VirtioQueueGeneration,
151 ) -> Self {
152 Self {
153 transition,
154 generation,
155 }
156 }
157
158 pub const fn transition(self) -> InterruptTransition {
160 self.transition
161 }
162
163 pub const fn generation(self) -> VirtioQueueGeneration {
165 self.generation
166 }
167}
168
169#[derive(Clone, Copy, Debug, Eq, PartialEq)]
171pub struct VirtioQueueGeneration(pub(super) u64);
172
173impl VirtioQueueGeneration {
174 pub const fn from_value(value: u64) -> Self {
176 Self(value)
177 }
178
179 pub const fn value(self) -> u64 {
181 self.0
182 }
183}
184
185pub struct InterruptTransitionRequest {
187 transition: InterruptTransition,
188 activity: Option<ActivityPermit>,
189 interrupts: Arc<VirtioPciInterruptCoordinator>,
190}
191
192impl core::fmt::Debug for InterruptTransitionRequest {
193 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
194 formatter
195 .debug_struct("InterruptTransitionRequest")
196 .field("transition", &self.transition)
197 .field("has_activity", &self.activity.is_some())
198 .finish_non_exhaustive()
199 }
200}
201
202impl InterruptTransitionRequest {
203 pub(super) fn new(
204 interrupts: Arc<VirtioPciInterruptCoordinator>,
205 transition: InterruptTransition,
206 activity: Option<ActivityPermit>,
207 ) -> Self {
208 Self {
209 transition,
210 activity,
211 interrupts,
212 }
213 }
214
215 pub(super) fn without_activity(
216 interrupts: Arc<VirtioPciInterruptCoordinator>,
217 transition: InterruptTransition,
218 ) -> Self {
219 Self::new(interrupts, transition, None)
220 }
221
222 pub const fn transition(&self) -> InterruptTransition {
224 self.transition
225 }
226}
227
228impl Drop for InterruptTransitionRequest {
229 fn drop(&mut self) {
230 self.interrupts.cancel_transition(self.transition);
231 self.activity.take();
232 }
233}