1use alloc::vec::Vec;
9
10use virtio_accel_core::{
11 Accelerator, ArtifactRef, BackendError, BindingRef, BufferRange, BufferUsage, ByteSink,
12 ByteSource, Capabilities, DeviceInfo, DeviceInfoError, EventState, ReleaseFailure,
13 SubmitFailure, Timeout, validate_bindings,
14};
15use virtio_accel_proto::{
16 KnownEventState, Le16, Le32, Le64, ObjectPayload, StatusCode, SubmitResponse, WireConfig,
17 WireDeviceInfo, WireEventState,
18};
19use zerocopy::IntoBytes;
20
21use crate::{
22 BufferCreateOutcome, BufferRecord, ChainRegion, CreateError, DecodedBinding, DecodedRequest,
23 DecodedRequestBody, DecoderLimits, DecoderLimitsError, DeviceState, DeviceStateConfigError,
24 DeviceStateError, FrameDecoder, FramePreflight, FramePreflightError, ObjectId, ObjectNamespace,
25 ResourceCounts, ResourcePolicy, ResponseWriteError, ResponseWriter, RetainedBytes,
26 UnusableFrame, preflight_command_frame, status_from_backend_error,
27 status_from_device_state_error,
28};
29
30pub type AcceleratorState<A> = DeviceState<
31 <A as Accelerator>::Context,
32 <A as Accelerator>::Buffer,
33 <A as Accelerator>::Program,
34 <A as Accelerator>::Queue,
35 <A as Accelerator>::Event,
36>;
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39pub enum DeviceHealth {
40 Running,
41 NeedsReset,
42 BackendDiscardRequired,
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46pub enum ResetDisposition {
47 BackendReusable,
48 BackendDiscardRequired,
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq)]
52pub struct ResetReport {
53 pub disposition: ResetDisposition,
54 pub released: ResourceCounts,
55 pub quarantined: ResourceCounts,
56 pub released_bytes: RetainedBytes,
57 pub quarantined_bytes: RetainedBytes,
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq)]
61pub enum ResetError {
62 NamespaceReuse,
63 State(DeviceStateConfigError),
64}
65
66#[derive(Clone, Copy, Debug, PartialEq, Eq)]
67pub enum CommandProcessorInitError {
68 Backend(BackendError),
69 DeviceInfo(DeviceInfoError),
70 Decoder(DecoderLimitsError),
71 State(DeviceStateConfigError),
72}
73
74#[derive(Clone, Copy, Debug, PartialEq, Eq)]
75pub enum CommandProcessError {
76 Preflight(FramePreflightError),
77 ResponseWrite(ResponseWriteError),
78}
79
80#[derive(Clone, Copy, Debug, PartialEq, Eq)]
81pub enum CommandOutcome {
82 Response {
83 request_id: u64,
84 status: StatusCode,
85 used: u32,
86 },
87 Unusable(UnusableFrame),
88}
89
90#[derive(Clone, Copy, Debug, PartialEq, Eq)]
91enum SubmitCreateError {
92 State(DeviceStateError),
93 OutOfMemory,
94 Rejected(BackendError),
95 Validation(StatusCode),
96}
97
98pub struct CommandProcessor<A: Accelerator> {
104 state: AcceleratorState<A>,
105 accelerator: A,
106 info: DeviceInfo,
107 policy: ResourcePolicy,
108 decoder: FrameDecoder,
109 health: DeviceHealth,
110 quarantined: ResourceCounts,
111 quarantined_bytes: RetainedBytes,
112 last_reset: Option<ResetReport>,
113}
114
115impl<A: Accelerator> core::fmt::Debug for CommandProcessor<A> {
116 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
117 formatter
118 .debug_struct("CommandProcessor")
119 .field("info", &self.info)
120 .field("policy", &self.policy)
121 .field("decoder", &self.decoder)
122 .field("health", &self.health)
123 .finish_non_exhaustive()
124 }
125}
126
127impl<A: Accelerator> CommandProcessor<A> {
128 pub fn new(
129 accelerator: A,
130 config: &WireConfig,
131 namespace: ObjectNamespace,
132 policy: ResourcePolicy,
133 ) -> Result<Self, CommandProcessorInitError> {
134 config.validate().map_err(|error| {
135 CommandProcessorInitError::Decoder(DecoderLimitsError::Config(error))
136 })?;
137 let info = accelerator
138 .device_info()
139 .map_err(CommandProcessorInitError::Backend)?;
140 info.validate()
141 .map_err(CommandProcessorInitError::DeviceInfo)?;
142 let limits =
143 DecoderLimits::new(config, info).map_err(CommandProcessorInitError::Decoder)?;
144 let state = DeviceState::new(namespace, info.limits, policy)
145 .map_err(CommandProcessorInitError::State)?;
146 Ok(Self {
147 state,
148 accelerator,
149 info,
150 policy,
151 decoder: FrameDecoder::new(limits),
152 health: DeviceHealth::Running,
153 quarantined: ResourceCounts::default(),
154 quarantined_bytes: RetainedBytes::default(),
155 last_reset: None,
156 })
157 }
158
159 pub const fn device_info(&self) -> DeviceInfo {
160 self.info
161 }
162
163 pub const fn health(&self) -> DeviceHealth {
164 self.health
165 }
166
167 pub const fn resource_policy(&self) -> ResourcePolicy {
168 self.policy
169 }
170
171 pub const fn retained_bytes(&self) -> RetainedBytes {
173 self.state
174 .retained_bytes()
175 .saturating_add(self.quarantined_bytes)
176 }
177
178 pub const fn decoder(&self) -> &FrameDecoder {
179 &self.decoder
180 }
181
182 pub const fn accelerator(&self) -> &A {
183 &self.accelerator
184 }
185
186 pub const fn state(&self) -> &AcceleratorState<A> {
187 &self.state
188 }
189
190 pub fn reset(&mut self, namespace: ObjectNamespace) -> Result<ResetReport, ResetError> {
197 if self.health == DeviceHealth::BackendDiscardRequired {
198 let report = match self.last_reset {
199 Some(report) => report,
200 None => {
201 let report =
202 self.discard_report(ResourceCounts::default(), RetainedBytes::default());
203 self.last_reset = Some(report);
204 report
205 }
206 };
207 return Ok(report);
208 }
209 if namespace == self.state.namespace() {
210 return Err(ResetError::NamespaceReuse);
211 }
212
213 self.health = DeviceHealth::NeedsReset;
214 self.last_reset = None;
215 let mut released = ResourceCounts::default();
216 let mut released_bytes = RetainedBytes::default();
217 let mut progress = ResetProgress::default();
218
219 self.reset_events(&mut released, &mut progress);
220 if progress.backend_callable {
221 self.reset_queues(&mut released, &mut progress);
222 }
223 if progress.backend_callable {
224 self.reset_programs(&mut released, &mut released_bytes, &mut progress);
225 }
226 if progress.backend_callable {
227 self.reset_buffers(&mut released, &mut released_bytes, &mut progress);
228 }
229 if progress.backend_callable {
230 self.reset_contexts(&mut released, &mut progress);
231 }
232
233 let remaining = self.state.resource_counts();
234 let quarantined = self.quarantined.saturating_add(remaining);
235 let quarantined_bytes = self
236 .quarantined_bytes
237 .saturating_add(self.state.retained_bytes());
238 if progress.backend_reusable
239 && self.state.is_empty()
240 && quarantined.is_empty()
241 && quarantined_bytes.is_empty()
242 {
243 self.state = DeviceState::new(namespace, self.info.limits, self.policy)
244 .map_err(ResetError::State)?;
245 self.health = DeviceHealth::Running;
246 let report = ResetReport {
247 disposition: ResetDisposition::BackendReusable,
248 released,
249 quarantined,
250 released_bytes,
251 quarantined_bytes,
252 };
253 self.last_reset = None;
254 return Ok(report);
255 }
256
257 self.health = DeviceHealth::BackendDiscardRequired;
258 let report = ResetReport {
259 disposition: ResetDisposition::BackendDiscardRequired,
260 released,
261 quarantined,
262 released_bytes,
263 quarantined_bytes,
264 };
265 self.last_reset = Some(report);
266 Ok(report)
267 }
268
269 pub fn process(
275 &mut self,
276 regions: &[ChainRegion],
277 request: &dyn ByteSource,
278 response: &mut dyn ByteSink,
279 ) -> Result<CommandOutcome, CommandProcessError> {
280 match preflight_command_frame(&self.decoder, regions, request, response)
281 .map_err(CommandProcessError::Preflight)?
282 {
283 FramePreflight::Rejected {
284 request_id,
285 status,
286 used,
287 } => Ok(CommandOutcome::Response {
288 request_id,
289 status,
290 used,
291 }),
292 FramePreflight::Unusable(error) => Ok(CommandOutcome::Unusable(error)),
293 FramePreflight::Ready(request) => {
294 if self.health != DeviceHealth::Running {
295 return self.respond_empty(
296 response,
297 StatusCode::DEVICE_LOST,
298 request.request_id(),
299 false,
300 );
301 }
302 self.last_reset = None;
303 self.dispatch(request, response)
304 }
305 }
306 }
307
308 fn dispatch(
309 &mut self,
310 request: DecodedRequest<'_>,
311 response: &mut dyn ByteSink,
312 ) -> Result<CommandOutcome, CommandProcessError> {
313 let request_id = request.request_id();
314 match request.into_body() {
315 DecodedRequestBody::GetDeviceInfo => {
316 let payload = wire_device_info(self.info);
317 self.respond_bytes(
318 response,
319 StatusCode::OK,
320 request_id,
321 payload.as_bytes(),
322 false,
323 )
324 }
325 DecodedRequestBody::CreateContext(desc) => {
326 if let Err(error) = self.info.validate_context_desc(desc) {
327 return self.respond_backend_error(response, request_id, error, false);
328 }
329 let accelerator = &self.accelerator;
330 match self
331 .state
332 .create_context_with(|| accelerator.create_context(desc))
333 {
334 Ok(id) => self.respond_object(response, request_id, id, true),
335 Err(error) => self.respond_create_error(response, request_id, error),
336 }
337 }
338 DecodedRequestBody::DestroyContext { context_id } => {
339 self.destroy_context(response, request_id, context_id)
340 }
341 DecodedRequestBody::AllocateBuffer { context_id, desc } => {
342 if let Err(error) = self.info.validate_buffer_desc(desc) {
343 return self.respond_backend_error(response, request_id, error, false);
344 }
345 let accelerator = &self.accelerator;
346 match self
347 .state
348 .create_buffer_with(context_id, desc, |context, requested| {
349 let allocated = accelerator.allocate_buffer(context, requested)?;
350 Ok(allocated.into_parts())
351 }) {
352 Ok(BufferCreateOutcome::Admitted(id)) => {
353 self.respond_object(response, request_id, id, true)
354 }
355 Ok(BufferCreateOutcome::CleanupRequired { id, error }) => {
356 self.release_unpublished_buffer(response, request_id, id, error)
357 }
358 Err(error) => self.respond_create_error(response, request_id, error),
359 }
360 }
361 DecodedRequestBody::FreeBuffer { buffer_id } => {
362 self.free_buffer(response, request_id, buffer_id)
363 }
364 DecodedRequestBody::WriteBuffer {
365 buffer_id,
366 range,
367 data,
368 } => self.write_buffer(response, request_id, buffer_id, range, &data),
369 DecodedRequestBody::ReadBuffer { buffer_id, range } => {
370 self.read_buffer(response, request_id, buffer_id, range)
371 }
372 DecodedRequestBody::LoadProgram {
373 context_id,
374 format,
375 target,
376 payload,
377 resident_bytes,
378 } => {
379 let accelerator = &self.accelerator;
380 let artifact_bytes = payload.len();
381 match self.state.create_program_with(
382 context_id,
383 artifact_bytes,
384 resident_bytes,
385 |context| {
386 accelerator.load_program(
387 context,
388 ArtifactRef {
389 format,
390 target,
391 payload: &payload,
392 resident_bytes,
393 },
394 )
395 },
396 ) {
397 Ok(id) => self.respond_object(response, request_id, id, true),
398 Err(error) => self.respond_create_error(response, request_id, error),
399 }
400 }
401 DecodedRequestBody::UnloadProgram { program_id } => {
402 self.unload_program(response, request_id, program_id)
403 }
404 DecodedRequestBody::CreateQueue { context_id, desc } => {
405 if let Err(error) = self.info.validate_queue_desc(desc) {
406 return self.respond_backend_error(response, request_id, error, false);
407 }
408 let accelerator = &self.accelerator;
409 match self.state.create_queue_with(context_id, |context| {
410 accelerator.create_queue(context, desc)
411 }) {
412 Ok(id) => self.respond_object(response, request_id, id, true),
413 Err(error) => self.respond_create_error(response, request_id, error),
414 }
415 }
416 DecodedRequestBody::DestroyQueue { queue_id } => {
417 self.destroy_queue(response, request_id, queue_id)
418 }
419 DecodedRequestBody::Submit {
420 queue_id,
421 program_id,
422 bindings,
423 timeout,
424 } => self.submit(
425 response, request_id, queue_id, program_id, bindings, timeout,
426 ),
427 DecodedRequestBody::PollEvent { event_id } => {
428 self.poll_event(response, request_id, event_id)
429 }
430 DecodedRequestBody::CancelEvent { event_id } => {
431 self.cancel_event(response, request_id, event_id)
432 }
433 DecodedRequestBody::DestroyEvent { event_id } => {
434 self.destroy_event(response, request_id, event_id)
435 }
436 }
437 }
438
439 fn submit(
440 &mut self,
441 response: &mut dyn ByteSink,
442 request_id: u64,
443 queue_id: ObjectId,
444 program_id: ObjectId,
445 bindings: Vec<DecodedBinding>,
446 timeout: Timeout,
447 ) -> Result<CommandOutcome, CommandProcessError> {
448 let mut buffer_ids = Vec::new();
449 if buffer_ids.try_reserve_exact(bindings.len()).is_err() {
450 return self.respond_empty(response, StatusCode::OUT_OF_MEMORY, request_id, false);
451 }
452 buffer_ids.extend(bindings.iter().map(|binding| binding.buffer_id));
453
454 let accelerator = &self.accelerator;
455 let max_bindings = self.info.limits.max_bindings_per_submission;
456 let mut admission_status = StatusCode::OK;
457 let mut admission_requires_discard = false;
458 let result = self
459 .state
460 .create_event_with(queue_id, program_id, buffer_ids, |resources| {
461 let mut native_bindings = Vec::new();
462 native_bindings
463 .try_reserve_exact(bindings.len())
464 .map_err(|_| SubmitCreateError::OutOfMemory)?;
465 for binding in &bindings {
466 let (buffer, info) = resources
467 .buffer_with_info_by_id(binding.buffer_id)
468 .map_err(SubmitCreateError::State)?;
469 let desc = info.desc();
470 if binding.range.end() > desc.bytes() {
471 return Err(SubmitCreateError::Validation(StatusCode::OUT_OF_BOUNDS));
472 }
473 if !desc.allows_access(binding.access) {
474 return Err(SubmitCreateError::Validation(StatusCode::PERMISSION_DENIED));
475 }
476 native_bindings.push(BindingRef {
477 slot: binding.slot,
478 buffer,
479 range: binding.range,
480 access: binding.access,
481 });
482 }
483 validate_bindings(&native_bindings, max_bindings).map_err(|error| {
484 SubmitCreateError::Validation(status_from_backend_error(error))
485 })?;
486 match accelerator.submit(
487 resources.queue(),
488 resources.program(),
489 &native_bindings,
490 timeout,
491 ) {
492 Ok(event) => Ok(event),
493 Err(SubmitFailure::Rejected(error)) => Err(SubmitCreateError::Rejected(error)),
494 Err(SubmitFailure::Indeterminate { error, event }) => {
495 admission_status = status_from_backend_error(error);
496 admission_requires_discard = error == BackendError::DeviceLost;
497 Ok(event)
498 }
499 }
500 });
501
502 match result {
503 Ok(event_id) => {
504 if admission_requires_discard {
505 self.require_backend_discard();
506 }
507 self.respond_event_id(response, admission_status, request_id, event_id, true)
508 }
509 Err(CreateError::State(error)) => self.respond_state_error(response, request_id, error),
510 Err(CreateError::Provider(SubmitCreateError::Rejected(error))) => {
511 self.respond_backend_error(response, request_id, error, false)
512 }
513 Err(CreateError::Provider(SubmitCreateError::OutOfMemory)) => {
514 self.respond_empty(response, StatusCode::OUT_OF_MEMORY, request_id, false)
515 }
516 Err(CreateError::Provider(SubmitCreateError::Validation(status))) => {
517 self.respond_empty(response, status, request_id, false)
518 }
519 Err(CreateError::Provider(SubmitCreateError::State(_))) => {
520 self.discard_response(response, request_id)
521 }
522 }
523 }
524
525 fn reset_events(&mut self, released: &mut ResourceCounts, progress: &mut ResetProgress) {
526 let mut cursor = 0;
527 while let Some((next, id)) = self.state.next_event_id(cursor) {
528 cursor = next;
529 if !progress.backend_callable {
530 break;
531 }
532 self.reset_event(id, released, progress);
533 }
534 }
535
536 fn reset_event(
537 &mut self,
538 id: ObjectId,
539 released: &mut ResourceCounts,
540 progress: &mut ResetProgress,
541 ) {
542 let mut event_state = {
543 let event = match self
544 .state
545 .event_record(id)
546 .and_then(|record| record.resource())
547 {
548 Ok(event) => event,
549 Err(_) => {
550 progress.backend_reusable = false;
551 return;
552 }
553 };
554 match self.accelerator.poll_event(event) {
555 Ok(state) => state,
556 Err(error) => {
557 progress.backend_reusable = false;
558 if error == BackendError::DeviceLost {
559 progress.backend_callable = false;
560 }
561 return;
562 }
563 }
564 };
565
566 if event_state == EventState::Pending {
567 if !self
568 .info
569 .capabilities
570 .contains(Capabilities::EVENT_CANCELLATION)
571 {
572 progress.backend_reusable = false;
573 return;
574 }
575 let cancel_result = {
576 let event = match self
577 .state
578 .event_record(id)
579 .and_then(|record| record.resource())
580 {
581 Ok(event) => event,
582 Err(_) => {
583 progress.backend_reusable = false;
584 return;
585 }
586 };
587 self.accelerator.cancel_event(event)
588 };
589 match cancel_result {
590 Ok(()) => event_state = EventState::Cancelled,
591 Err(BackendError::Busy) => {
592 let event = match self
593 .state
594 .event_record(id)
595 .and_then(|record| record.resource())
596 {
597 Ok(event) => event,
598 Err(_) => {
599 progress.backend_reusable = false;
600 return;
601 }
602 };
603 match self.accelerator.poll_event(event) {
604 Ok(state) => event_state = state,
605 Err(error) => {
606 progress.backend_reusable = false;
607 if error == BackendError::DeviceLost {
608 progress.backend_callable = false;
609 }
610 return;
611 }
612 }
613 }
614 Err(error) => {
615 progress.backend_reusable = false;
616 if error == BackendError::DeviceLost {
617 progress.backend_callable = false;
618 }
619 return;
620 }
621 }
622 }
623
624 match event_state {
625 EventState::Pending => {
626 progress.backend_reusable = false;
627 return;
628 }
629 EventState::Failed(BackendError::DeviceLost) => {
630 progress.backend_reusable = false;
631 progress.backend_callable = false;
632 return;
633 }
634 EventState::Complete | EventState::Failed(_) | EventState::Cancelled => {}
635 }
636
637 let event = match self.state.begin_event_release(id) {
638 Ok(event) => event,
639 Err(_) => {
640 progress.backend_reusable = false;
641 return;
642 }
643 };
644 match self.accelerator.destroy_event(event) {
645 Ok(()) => match self.state.commit_event_release(id) {
646 Ok(()) => released.events += 1,
647 Err(_) => {
648 progress.backend_reusable = false;
649 progress.backend_callable = false;
650 }
651 },
652 Err(ReleaseFailure::Rejected { error, resource }) => {
653 progress.backend_reusable = false;
654 if error == BackendError::DeviceLost {
655 progress.backend_callable = false;
656 }
657 if self.state.restore_event_release(id, resource).is_err() {
658 progress.backend_callable = false;
659 }
660 }
661 Err(ReleaseFailure::Indeterminate { .. }) => {
662 progress.backend_reusable = false;
663 progress.backend_callable = false;
664 }
665 }
666 }
667
668 fn reset_queues(&mut self, released: &mut ResourceCounts, progress: &mut ResetProgress) {
669 let mut cursor = 0;
670 while let Some((next, id)) = self.state.next_queue_id(cursor) {
671 cursor = next;
672 let queue = match self.state.begin_queue_release(id) {
673 Ok(queue) => queue,
674 Err(_) => {
675 progress.backend_reusable = false;
676 continue;
677 }
678 };
679 match self.accelerator.destroy_queue(queue) {
680 Ok(()) => match self.state.commit_queue_release(id) {
681 Ok(()) => released.queues += 1,
682 Err(_) => {
683 progress.backend_reusable = false;
684 progress.backend_callable = false;
685 break;
686 }
687 },
688 Err(ReleaseFailure::Rejected { error, resource }) => {
689 progress.backend_reusable = false;
690 if error == BackendError::DeviceLost {
691 progress.backend_callable = false;
692 }
693 if self.state.restore_queue_release(id, resource).is_err() {
694 progress.backend_callable = false;
695 break;
696 }
697 }
698 Err(ReleaseFailure::Indeterminate { .. }) => {
699 progress.backend_reusable = false;
700 progress.backend_callable = false;
701 break;
702 }
703 }
704 }
705 }
706
707 fn reset_programs(
708 &mut self,
709 released: &mut ResourceCounts,
710 released_bytes: &mut RetainedBytes,
711 progress: &mut ResetProgress,
712 ) {
713 let mut cursor = 0;
714 while let Some((next, id)) = self.state.next_program_id(cursor) {
715 cursor = next;
716 let resident_bytes = match self.state.program_record(id) {
717 Ok(record) => record.resident_bytes(),
718 Err(_) => {
719 progress.backend_reusable = false;
720 continue;
721 }
722 };
723 let program = match self.state.begin_program_release(id) {
724 Ok(program) => program,
725 Err(_) => {
726 progress.backend_reusable = false;
727 continue;
728 }
729 };
730 match self.accelerator.unload_program(program) {
731 Ok(()) => match self.state.commit_program_release(id) {
732 Ok(()) => {
733 released.programs += 1;
734 released_bytes.program_resident += u128::from(resident_bytes);
735 }
736 Err(_) => {
737 progress.backend_reusable = false;
738 progress.backend_callable = false;
739 break;
740 }
741 },
742 Err(ReleaseFailure::Rejected { error, resource }) => {
743 progress.backend_reusable = false;
744 if error == BackendError::DeviceLost {
745 progress.backend_callable = false;
746 }
747 if self.state.restore_program_release(id, resource).is_err() {
748 progress.backend_callable = false;
749 break;
750 }
751 }
752 Err(ReleaseFailure::Indeterminate { .. }) => {
753 progress.backend_reusable = false;
754 progress.backend_callable = false;
755 break;
756 }
757 }
758 }
759 }
760
761 fn reset_buffers(
762 &mut self,
763 released: &mut ResourceCounts,
764 released_bytes: &mut RetainedBytes,
765 progress: &mut ResetProgress,
766 ) {
767 let mut cursor = 0;
768 while let Some((next, id)) = self.state.next_buffer_id(cursor) {
769 cursor = next;
770 let allocation_bytes = match self.state.buffer_record(id) {
771 Ok(record) => record.info().allocation_bytes(),
772 Err(_) => {
773 progress.backend_reusable = false;
774 continue;
775 }
776 };
777 let buffer = match self.state.begin_buffer_release(id) {
778 Ok(buffer) => buffer,
779 Err(_) => {
780 progress.backend_reusable = false;
781 continue;
782 }
783 };
784 match self.accelerator.free_buffer(buffer) {
785 Ok(()) => match self.state.commit_buffer_release(id) {
786 Ok(()) => {
787 released.buffers += 1;
788 released_bytes.buffer_backing += u128::from(allocation_bytes);
789 }
790 Err(_) => {
791 progress.backend_reusable = false;
792 progress.backend_callable = false;
793 break;
794 }
795 },
796 Err(ReleaseFailure::Rejected { error, resource }) => {
797 progress.backend_reusable = false;
798 if error == BackendError::DeviceLost {
799 progress.backend_callable = false;
800 }
801 if self.state.restore_buffer_release(id, resource).is_err() {
802 progress.backend_callable = false;
803 break;
804 }
805 }
806 Err(ReleaseFailure::Indeterminate { .. }) => {
807 progress.backend_reusable = false;
808 progress.backend_callable = false;
809 break;
810 }
811 }
812 }
813 }
814
815 fn reset_contexts(&mut self, released: &mut ResourceCounts, progress: &mut ResetProgress) {
816 let mut cursor = 0;
817 while let Some((next, id)) = self.state.next_context_id(cursor) {
818 cursor = next;
819 let context = match self.state.begin_context_release(id) {
820 Ok(context) => context,
821 Err(_) => {
822 progress.backend_reusable = false;
823 continue;
824 }
825 };
826 match self.accelerator.destroy_context(context) {
827 Ok(()) => match self.state.commit_context_release(id) {
828 Ok(()) => released.contexts += 1,
829 Err(_) => {
830 progress.backend_reusable = false;
831 progress.backend_callable = false;
832 break;
833 }
834 },
835 Err(ReleaseFailure::Rejected { error, resource }) => {
836 progress.backend_reusable = false;
837 if error == BackendError::DeviceLost {
838 progress.backend_callable = false;
839 }
840 if self.state.restore_context_release(id, resource).is_err() {
841 progress.backend_callable = false;
842 break;
843 }
844 }
845 Err(ReleaseFailure::Indeterminate { .. }) => {
846 progress.backend_reusable = false;
847 progress.backend_callable = false;
848 break;
849 }
850 }
851 }
852 }
853
854 fn poll_event(
855 &mut self,
856 response: &mut dyn ByteSink,
857 request_id: u64,
858 event_id: ObjectId,
859 ) -> Result<CommandOutcome, CommandProcessError> {
860 let event = match self.state.event_record(event_id) {
861 Ok(record) => match record.resource() {
862 Ok(event) => event,
863 Err(error) => return self.respond_state_error(response, request_id, error),
864 },
865 Err(error) => return self.respond_state_error(response, request_id, error),
866 };
867 match self.accelerator.poll_event(event) {
868 Ok(state) => {
869 if state == EventState::Failed(BackendError::DeviceLost) {
870 self.require_backend_discard();
871 }
872 let payload = wire_event_state(state);
873 self.respond_bytes(
874 response,
875 StatusCode::OK,
876 request_id,
877 payload.as_bytes(),
878 false,
879 )
880 }
881 Err(error) => self.respond_backend_error(response, request_id, error, false),
882 }
883 }
884
885 fn cancel_event(
886 &mut self,
887 response: &mut dyn ByteSink,
888 request_id: u64,
889 event_id: ObjectId,
890 ) -> Result<CommandOutcome, CommandProcessError> {
891 if self.info.validate_event_cancellation().is_err() {
892 return self.respond_empty(response, StatusCode::UNSUPPORTED, request_id, false);
893 }
894 let event = match self.state.event_record(event_id) {
895 Ok(record) => match record.resource() {
896 Ok(event) => event,
897 Err(error) => return self.respond_state_error(response, request_id, error),
898 },
899 Err(error) => return self.respond_state_error(response, request_id, error),
900 };
901 match self.accelerator.cancel_event(event) {
902 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
903 Err(error) => self.respond_backend_error(response, request_id, error, false),
904 }
905 }
906
907 fn destroy_event(
908 &mut self,
909 response: &mut dyn ByteSink,
910 request_id: u64,
911 event_id: ObjectId,
912 ) -> Result<CommandOutcome, CommandProcessError> {
913 let state = {
914 let event = match self.state.event_record(event_id) {
915 Ok(record) => match record.resource() {
916 Ok(event) => event,
917 Err(error) => return self.respond_state_error(response, request_id, error),
918 },
919 Err(error) => return self.respond_state_error(response, request_id, error),
920 };
921 self.accelerator.poll_event(event)
922 };
923 match state {
924 Ok(EventState::Pending) => {
925 return self.respond_empty(response, StatusCode::BUSY, request_id, false);
926 }
927 Ok(EventState::Failed(BackendError::DeviceLost)) => {
928 self.require_backend_discard();
929 return self.respond_empty(response, StatusCode::DEVICE_LOST, request_id, false);
930 }
931 Ok(EventState::Complete | EventState::Failed(_) | EventState::Cancelled) => {}
932 Err(error) => {
933 return self.respond_backend_error(response, request_id, error, false);
934 }
935 }
936
937 let event = match self.state.begin_event_release(event_id) {
938 Ok(event) => event,
939 Err(error) => return self.respond_state_error(response, request_id, error),
940 };
941 match self.accelerator.destroy_event(event) {
942 Ok(()) => match self.state.commit_event_release(event_id) {
943 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
944 Err(_) => self.discard_response(response, request_id),
945 },
946 Err(ReleaseFailure::Rejected { error, resource }) => {
947 match self.state.restore_event_release(event_id, resource) {
948 Ok(()) => self.respond_backend_error(response, request_id, error, false),
949 Err(_) => self.discard_response(response, request_id),
950 }
951 }
952 Err(ReleaseFailure::Indeterminate { .. }) => {
953 if self.state.commit_event_release(event_id).is_ok() {
954 self.quarantined.events += 1;
955 }
956 self.discard_response(response, request_id)
957 }
958 }
959 }
960
961 fn release_unpublished_buffer(
962 &mut self,
963 response: &mut dyn ByteSink,
964 request_id: u64,
965 buffer_id: ObjectId,
966 admission_error: BackendError,
967 ) -> Result<CommandOutcome, CommandProcessError> {
968 let allocation_bytes = match self.state.buffer_record(buffer_id) {
969 Ok(record) => record.info().allocation_bytes(),
970 Err(_) => return self.discard_response(response, request_id),
971 };
972 let buffer = match self.state.begin_buffer_release(buffer_id) {
973 Ok(buffer) => buffer,
974 Err(_) => return self.discard_response(response, request_id),
975 };
976 match self.accelerator.free_buffer(buffer) {
977 Ok(()) => match self.state.commit_buffer_release(buffer_id) {
978 Ok(()) => self.respond_backend_error(response, request_id, admission_error, false),
979 Err(_) => self.discard_response(response, request_id),
980 },
981 Err(ReleaseFailure::Rejected { resource, .. }) => {
982 let _ = self.state.restore_buffer_release(buffer_id, resource);
983 self.discard_response(response, request_id)
984 }
985 Err(ReleaseFailure::Indeterminate { .. }) => {
986 if self.state.commit_buffer_release(buffer_id).is_ok() {
987 self.quarantined.buffers += 1;
988 self.quarantined_bytes.buffer_backing += u128::from(allocation_bytes);
989 }
990 self.discard_response(response, request_id)
991 }
992 }
993 }
994
995 fn write_buffer(
996 &mut self,
997 response: &mut dyn ByteSink,
998 request_id: u64,
999 buffer_id: ObjectId,
1000 range: BufferRange,
1001 data: &dyn ByteSource,
1002 ) -> Result<CommandOutcome, CommandProcessError> {
1003 let result = {
1004 let record = match self.state.buffer_record_mut(buffer_id) {
1005 Ok(record) => record,
1006 Err(error) => {
1007 return self.respond_state_error(response, request_id, error);
1008 }
1009 };
1010 if let Err(status) = validate_transfer(record, range, BufferUsage::TRANSFER_DESTINATION)
1011 {
1012 return self.respond_empty(response, status, request_id, false);
1013 }
1014 let buffer = match record.resource_mut() {
1015 Ok(buffer) => buffer,
1016 Err(error) => {
1017 return self.respond_state_error(response, request_id, error);
1018 }
1019 };
1020 self.accelerator.write_buffer(buffer, range.offset, data)
1021 };
1022
1023 match result {
1024 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
1025 Err(error) => self.respond_backend_error(response, request_id, error, true),
1026 }
1027 }
1028
1029 fn read_buffer(
1030 &mut self,
1031 response: &mut dyn ByteSink,
1032 request_id: u64,
1033 buffer_id: ObjectId,
1034 range: BufferRange,
1035 ) -> Result<CommandOutcome, CommandProcessError> {
1036 let record = match self.state.buffer_record(buffer_id) {
1037 Ok(record) => record,
1038 Err(error) => {
1039 return self.respond_state_error(response, request_id, error);
1040 }
1041 };
1042 if let Err(status) = validate_transfer(record, range, BufferUsage::TRANSFER_SOURCE) {
1043 return self.respond_empty(response, status, request_id, false);
1044 }
1045 let buffer = match record.resource() {
1046 Ok(buffer) => buffer,
1047 Err(error) => {
1048 return self.respond_state_error(response, request_id, error);
1049 }
1050 };
1051
1052 let mut writer = ResponseWriter::new(response, self.decoder.limits().max_response_bytes());
1053 let error = {
1054 let mut payload = writer
1055 .payload(range.bytes())
1056 .map_err(CommandProcessError::ResponseWrite)?;
1057 match self
1058 .accelerator
1059 .read_buffer(buffer, range.offset, &mut payload)
1060 {
1061 Ok(()) => {
1062 let result = payload.commit(StatusCode::OK, request_id);
1063 return self.complete_response(result, StatusCode::OK, request_id, false);
1064 }
1065 Err(error) => error,
1066 }
1067 };
1068 let status = self.backend_status(error);
1069 let result = writer.write_empty(status, request_id);
1070 self.complete_response(result, status, request_id, false)
1071 }
1072
1073 fn destroy_context(
1074 &mut self,
1075 response: &mut dyn ByteSink,
1076 request_id: u64,
1077 id: ObjectId,
1078 ) -> Result<CommandOutcome, CommandProcessError> {
1079 let resource = match self.state.begin_context_release(id) {
1080 Ok(resource) => resource,
1081 Err(error) => return self.respond_state_error(response, request_id, error),
1082 };
1083 match self.accelerator.destroy_context(resource) {
1084 Ok(()) => match self.state.commit_context_release(id) {
1085 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
1086 Err(_) => self.discard_response(response, request_id),
1087 },
1088 Err(ReleaseFailure::Rejected { error, resource }) => {
1089 match self.state.restore_context_release(id, resource) {
1090 Ok(()) => self.respond_backend_error(response, request_id, error, false),
1091 Err(_) => self.discard_response(response, request_id),
1092 }
1093 }
1094 Err(ReleaseFailure::Indeterminate { .. }) => {
1095 if self.state.commit_context_release(id).is_ok() {
1096 self.quarantined.contexts += 1;
1097 }
1098 self.discard_response(response, request_id)
1099 }
1100 }
1101 }
1102
1103 fn free_buffer(
1104 &mut self,
1105 response: &mut dyn ByteSink,
1106 request_id: u64,
1107 id: ObjectId,
1108 ) -> Result<CommandOutcome, CommandProcessError> {
1109 let allocation_bytes = match self.state.buffer_record(id) {
1110 Ok(record) => record.info().allocation_bytes(),
1111 Err(error) => return self.respond_state_error(response, request_id, error),
1112 };
1113 let resource = match self.state.begin_buffer_release(id) {
1114 Ok(resource) => resource,
1115 Err(error) => return self.respond_state_error(response, request_id, error),
1116 };
1117 match self.accelerator.free_buffer(resource) {
1118 Ok(()) => match self.state.commit_buffer_release(id) {
1119 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
1120 Err(_) => self.discard_response(response, request_id),
1121 },
1122 Err(ReleaseFailure::Rejected { error, resource }) => {
1123 match self.state.restore_buffer_release(id, resource) {
1124 Ok(()) => self.respond_backend_error(response, request_id, error, false),
1125 Err(_) => self.discard_response(response, request_id),
1126 }
1127 }
1128 Err(ReleaseFailure::Indeterminate { .. }) => {
1129 if self.state.commit_buffer_release(id).is_ok() {
1130 self.quarantined.buffers += 1;
1131 self.quarantined_bytes.buffer_backing += u128::from(allocation_bytes);
1132 }
1133 self.discard_response(response, request_id)
1134 }
1135 }
1136 }
1137
1138 fn unload_program(
1139 &mut self,
1140 response: &mut dyn ByteSink,
1141 request_id: u64,
1142 id: ObjectId,
1143 ) -> Result<CommandOutcome, CommandProcessError> {
1144 let resident_bytes = match self.state.program_record(id) {
1145 Ok(record) => record.resident_bytes(),
1146 Err(error) => return self.respond_state_error(response, request_id, error),
1147 };
1148 let resource = match self.state.begin_program_release(id) {
1149 Ok(resource) => resource,
1150 Err(error) => return self.respond_state_error(response, request_id, error),
1151 };
1152 match self.accelerator.unload_program(resource) {
1153 Ok(()) => match self.state.commit_program_release(id) {
1154 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
1155 Err(_) => self.discard_response(response, request_id),
1156 },
1157 Err(ReleaseFailure::Rejected { error, resource }) => {
1158 match self.state.restore_program_release(id, resource) {
1159 Ok(()) => self.respond_backend_error(response, request_id, error, false),
1160 Err(_) => self.discard_response(response, request_id),
1161 }
1162 }
1163 Err(ReleaseFailure::Indeterminate { .. }) => {
1164 if self.state.commit_program_release(id).is_ok() {
1165 self.quarantined.programs += 1;
1166 self.quarantined_bytes.program_resident += u128::from(resident_bytes);
1167 }
1168 self.discard_response(response, request_id)
1169 }
1170 }
1171 }
1172
1173 fn destroy_queue(
1174 &mut self,
1175 response: &mut dyn ByteSink,
1176 request_id: u64,
1177 id: ObjectId,
1178 ) -> Result<CommandOutcome, CommandProcessError> {
1179 let resource = match self.state.begin_queue_release(id) {
1180 Ok(resource) => resource,
1181 Err(error) => return self.respond_state_error(response, request_id, error),
1182 };
1183 match self.accelerator.destroy_queue(resource) {
1184 Ok(()) => match self.state.commit_queue_release(id) {
1185 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
1186 Err(_) => self.discard_response(response, request_id),
1187 },
1188 Err(ReleaseFailure::Rejected { error, resource }) => {
1189 match self.state.restore_queue_release(id, resource) {
1190 Ok(()) => self.respond_backend_error(response, request_id, error, false),
1191 Err(_) => self.discard_response(response, request_id),
1192 }
1193 }
1194 Err(ReleaseFailure::Indeterminate { .. }) => {
1195 if self.state.commit_queue_release(id).is_ok() {
1196 self.quarantined.queues += 1;
1197 }
1198 self.discard_response(response, request_id)
1199 }
1200 }
1201 }
1202
1203 fn respond_create_error(
1204 &mut self,
1205 response: &mut dyn ByteSink,
1206 request_id: u64,
1207 error: CreateError<BackendError>,
1208 ) -> Result<CommandOutcome, CommandProcessError> {
1209 match error {
1210 CreateError::State(error) => self.respond_state_error(response, request_id, error),
1211 CreateError::Provider(error) => {
1212 self.respond_backend_error(response, request_id, error, false)
1213 }
1214 }
1215 }
1216
1217 fn respond_state_error(
1218 &mut self,
1219 response: &mut dyn ByteSink,
1220 request_id: u64,
1221 error: DeviceStateError,
1222 ) -> Result<CommandOutcome, CommandProcessError> {
1223 self.respond_empty(
1224 response,
1225 status_from_device_state_error(error),
1226 request_id,
1227 false,
1228 )
1229 }
1230
1231 fn respond_backend_error(
1232 &mut self,
1233 response: &mut dyn ByteSink,
1234 request_id: u64,
1235 error: BackendError,
1236 mutated: bool,
1237 ) -> Result<CommandOutcome, CommandProcessError> {
1238 let status = self.backend_status(error);
1239 self.respond_empty(response, status, request_id, mutated)
1240 }
1241
1242 fn backend_status(&mut self, error: BackendError) -> StatusCode {
1243 if error == BackendError::DeviceLost {
1244 self.require_backend_discard();
1245 }
1246 status_from_backend_error(error)
1247 }
1248
1249 fn require_backend_discard(&mut self) {
1250 self.health = DeviceHealth::BackendDiscardRequired;
1251 self.last_reset = None;
1252 }
1253
1254 fn discard_response(
1255 &mut self,
1256 response: &mut dyn ByteSink,
1257 request_id: u64,
1258 ) -> Result<CommandOutcome, CommandProcessError> {
1259 self.require_backend_discard();
1260 self.respond_empty(response, StatusCode::DEVICE_LOST, request_id, true)
1261 }
1262
1263 fn discard_report(
1264 &self,
1265 released: ResourceCounts,
1266 released_bytes: RetainedBytes,
1267 ) -> ResetReport {
1268 ResetReport {
1269 disposition: ResetDisposition::BackendDiscardRequired,
1270 released,
1271 quarantined: self
1272 .quarantined
1273 .saturating_add(self.state.resource_counts()),
1274 released_bytes,
1275 quarantined_bytes: self
1276 .quarantined_bytes
1277 .saturating_add(self.state.retained_bytes()),
1278 }
1279 }
1280
1281 fn respond_object(
1282 &mut self,
1283 response: &mut dyn ByteSink,
1284 request_id: u64,
1285 id: ObjectId,
1286 mutated: bool,
1287 ) -> Result<CommandOutcome, CommandProcessError> {
1288 let payload = ObjectPayload {
1289 object_id: Le64::new(id.get()),
1290 };
1291 self.respond_bytes(
1292 response,
1293 StatusCode::OK,
1294 request_id,
1295 payload.as_bytes(),
1296 mutated,
1297 )
1298 }
1299
1300 fn respond_event_id(
1301 &mut self,
1302 response: &mut dyn ByteSink,
1303 status: StatusCode,
1304 request_id: u64,
1305 id: ObjectId,
1306 mutated: bool,
1307 ) -> Result<CommandOutcome, CommandProcessError> {
1308 let payload = SubmitResponse {
1309 event_id: Le64::new(id.get()),
1310 };
1311 self.respond_bytes(response, status, request_id, payload.as_bytes(), mutated)
1312 }
1313
1314 fn respond_bytes(
1315 &mut self,
1316 response: &mut dyn ByteSink,
1317 status: StatusCode,
1318 request_id: u64,
1319 payload: &[u8],
1320 mutated: bool,
1321 ) -> Result<CommandOutcome, CommandProcessError> {
1322 let result = (|| {
1323 let mut writer =
1324 ResponseWriter::new(response, self.decoder.limits().max_response_bytes());
1325 let payload_bytes =
1326 u64::try_from(payload.len()).map_err(|_| ResponseWriteError::FrameTooLarge)?;
1327 let mut destination = writer.payload(payload_bytes)?;
1328 destination
1329 .write_at(0, payload)
1330 .map_err(|_| ResponseWriteError::SinkAccess)?;
1331 destination.commit(status, request_id)
1332 })();
1333 self.complete_response(result, status, request_id, mutated)
1334 }
1335
1336 fn respond_empty(
1337 &mut self,
1338 response: &mut dyn ByteSink,
1339 status: StatusCode,
1340 request_id: u64,
1341 mutated: bool,
1342 ) -> Result<CommandOutcome, CommandProcessError> {
1343 let result = ResponseWriter::new(response, self.decoder.limits().max_response_bytes())
1344 .write_empty(status, request_id);
1345 self.complete_response(result, status, request_id, mutated)
1346 }
1347
1348 fn complete_response(
1349 &mut self,
1350 result: Result<u32, ResponseWriteError>,
1351 status: StatusCode,
1352 request_id: u64,
1353 mutated: bool,
1354 ) -> Result<CommandOutcome, CommandProcessError> {
1355 match result {
1356 Ok(used) => Ok(CommandOutcome::Response {
1357 request_id,
1358 status,
1359 used,
1360 }),
1361 Err(error) => {
1362 if mutated && self.health == DeviceHealth::Running {
1363 self.health = DeviceHealth::NeedsReset;
1364 self.last_reset = None;
1365 }
1366 Err(CommandProcessError::ResponseWrite(error))
1367 }
1368 }
1369 }
1370}
1371
1372#[derive(Clone, Copy, Debug)]
1373struct ResetProgress {
1374 backend_reusable: bool,
1375 backend_callable: bool,
1376}
1377
1378impl Default for ResetProgress {
1379 fn default() -> Self {
1380 Self {
1381 backend_reusable: true,
1382 backend_callable: true,
1383 }
1384 }
1385}
1386
1387fn validate_transfer<B>(
1388 record: &BufferRecord<B>,
1389 range: BufferRange,
1390 required_usage: BufferUsage,
1391) -> Result<(), StatusCode> {
1392 if record.in_flight() != 0 {
1393 return Err(StatusCode::BUSY);
1394 }
1395 let desc = record.info().desc();
1396 if range.end() > desc.bytes() {
1397 return Err(StatusCode::OUT_OF_BOUNDS);
1398 }
1399 if !desc.usage.contains(required_usage) {
1400 return Err(StatusCode::PERMISSION_DENIED);
1401 }
1402 Ok(())
1403}
1404
1405fn wire_device_info(info: DeviceInfo) -> WireDeviceInfo {
1406 WireDeviceInfo {
1407 uuid: info.identity.uuid,
1408 class: Le16::new(info.identity.class.get()),
1409 reserved: Le16::new(0),
1410 vendor_id: Le32::new(info.identity.vendor_id),
1411 device_id: Le32::new(info.identity.device_id),
1412 capabilities: Le64::new(info.capabilities.bits()),
1413 max_contexts: Le32::new(info.limits.max_contexts),
1414 max_buffers_per_context: Le32::new(info.limits.max_buffers_per_context),
1415 max_programs_per_context: Le32::new(info.limits.max_programs_per_context),
1416 max_queues_per_context: Le32::new(info.limits.max_queues_per_context),
1417 max_events_per_context: Le32::new(info.limits.max_events_per_context),
1418 max_bindings_per_submission: Le32::new(info.limits.max_bindings_per_submission),
1419 max_buffer_bytes: Le64::new(info.limits.max_buffer_bytes),
1420 max_artifact_bytes: Le64::new(info.limits.max_artifact_bytes),
1421 }
1422}
1423
1424fn wire_event_state(state: EventState) -> WireEventState {
1425 let (state, error) = match state {
1426 EventState::Pending => (KnownEventState::Pending, StatusCode::OK),
1427 EventState::Complete => (KnownEventState::Complete, StatusCode::OK),
1428 EventState::Failed(error) => (KnownEventState::Failed, status_from_backend_error(error)),
1429 EventState::Cancelled => (KnownEventState::Cancelled, StatusCode::OK),
1430 };
1431 WireEventState {
1432 state: Le16::new(state as u16),
1433 error: Le16::new(error.0),
1434 reserved: Le32::new(0),
1435 }
1436}