1use alloc::vec::Vec;
9
10use virtio_accel_core::{
11 Accelerator, ArtifactRef, BackendError, BindingRef, BufferDesc, BufferRange, BufferUsage,
12 ByteSink, ByteSource, Capabilities, DeviceInfo, DeviceInfoError, EventState, ReleaseFailure,
13 SubmitFailure, Timeout,
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 let mut descs: Vec<BufferDesc> = Vec::new();
463 native_bindings
464 .try_reserve_exact(bindings.len())
465 .map_err(|_| SubmitCreateError::OutOfMemory)?;
466 descs
467 .try_reserve_exact(bindings.len())
468 .map_err(|_| SubmitCreateError::OutOfMemory)?;
469 for binding in &bindings {
470 let (buffer, info) = resources
471 .buffer_with_info_by_id(binding.buffer_id)
472 .map_err(SubmitCreateError::State)?;
473 let desc = info.desc();
474 if binding.range.end() > desc.bytes() {
475 return Err(SubmitCreateError::Validation(StatusCode::OUT_OF_BOUNDS));
476 }
477 descs.push(desc);
478 native_bindings.push(BindingRef {
479 slot: binding.slot,
480 buffer,
481 range: binding.range,
482 access: binding.access,
483 });
484 }
485 BindingRef::validate_for_submit(&native_bindings, &descs, max_bindings).map_err(
486 |error| SubmitCreateError::Validation(status_from_backend_error(error)),
487 )?;
488 match accelerator.submit(
489 resources.queue(),
490 resources.program(),
491 &native_bindings,
492 timeout,
493 ) {
494 Ok(event) => Ok(event),
495 Err(SubmitFailure::Rejected(error)) => Err(SubmitCreateError::Rejected(error)),
496 Err(SubmitFailure::Indeterminate { error, event }) => {
497 admission_status = status_from_backend_error(error);
498 admission_requires_discard = error == BackendError::DeviceLost;
499 Ok(event)
500 }
501 }
502 });
503
504 match result {
505 Ok(event_id) => {
506 if admission_requires_discard {
507 self.require_backend_discard();
508 }
509 self.respond_event_id(response, admission_status, request_id, event_id, true)
510 }
511 Err(CreateError::State(error)) => self.respond_state_error(response, request_id, error),
512 Err(CreateError::Provider(SubmitCreateError::Rejected(error))) => {
513 self.respond_backend_error(response, request_id, error, false)
514 }
515 Err(CreateError::Provider(SubmitCreateError::OutOfMemory)) => {
516 self.respond_empty(response, StatusCode::OUT_OF_MEMORY, request_id, false)
517 }
518 Err(CreateError::Provider(SubmitCreateError::Validation(status))) => {
519 self.respond_empty(response, status, request_id, false)
520 }
521 Err(CreateError::Provider(SubmitCreateError::State(_))) => {
522 self.discard_response(response, request_id)
523 }
524 }
525 }
526
527 fn reset_events(&mut self, released: &mut ResourceCounts, progress: &mut ResetProgress) {
528 let mut cursor = 0;
529 while let Some((next, id)) = self.state.next_event_id(cursor) {
530 cursor = next;
531 if !progress.backend_callable {
532 break;
533 }
534 self.reset_event(id, released, progress);
535 }
536 }
537
538 fn reset_event(
539 &mut self,
540 id: ObjectId,
541 released: &mut ResourceCounts,
542 progress: &mut ResetProgress,
543 ) {
544 let mut event_state = {
545 let event = match self
546 .state
547 .event_record(id)
548 .and_then(|record| record.resource())
549 {
550 Ok(event) => event,
551 Err(_) => {
552 progress.backend_reusable = false;
553 return;
554 }
555 };
556 match self.accelerator.poll_event(event) {
557 Ok(state) => state,
558 Err(error) => {
559 progress.backend_reusable = false;
560 if error == BackendError::DeviceLost {
561 progress.backend_callable = false;
562 }
563 return;
564 }
565 }
566 };
567
568 if event_state == EventState::Pending {
569 if !self
570 .info
571 .capabilities
572 .contains(Capabilities::EVENT_CANCELLATION)
573 {
574 progress.backend_reusable = false;
575 return;
576 }
577 let cancel_result = {
578 let event = match self
579 .state
580 .event_record(id)
581 .and_then(|record| record.resource())
582 {
583 Ok(event) => event,
584 Err(_) => {
585 progress.backend_reusable = false;
586 return;
587 }
588 };
589 self.accelerator.cancel_event(event)
590 };
591 match cancel_result {
592 Ok(()) => event_state = EventState::Cancelled,
593 Err(BackendError::Busy) => {
594 let event = match self
595 .state
596 .event_record(id)
597 .and_then(|record| record.resource())
598 {
599 Ok(event) => event,
600 Err(_) => {
601 progress.backend_reusable = false;
602 return;
603 }
604 };
605 match self.accelerator.poll_event(event) {
606 Ok(state) => event_state = state,
607 Err(error) => {
608 progress.backend_reusable = false;
609 if error == BackendError::DeviceLost {
610 progress.backend_callable = false;
611 }
612 return;
613 }
614 }
615 }
616 Err(error) => {
617 progress.backend_reusable = false;
618 if error == BackendError::DeviceLost {
619 progress.backend_callable = false;
620 }
621 return;
622 }
623 }
624 }
625
626 match event_state {
627 EventState::Pending => {
628 progress.backend_reusable = false;
629 return;
630 }
631 EventState::Failed(BackendError::DeviceLost) => {
632 progress.backend_reusable = false;
633 progress.backend_callable = false;
634 return;
635 }
636 EventState::Complete | EventState::Failed(_) | EventState::Cancelled => {}
637 }
638
639 let event = match self.state.begin_event_release(id) {
640 Ok(event) => event,
641 Err(_) => {
642 progress.backend_reusable = false;
643 return;
644 }
645 };
646 match self.accelerator.destroy_event(event) {
647 Ok(()) => match self.state.commit_event_release(id) {
648 Ok(()) => released.events += 1,
649 Err(_) => {
650 progress.backend_reusable = false;
651 progress.backend_callable = false;
652 }
653 },
654 Err(ReleaseFailure::Rejected { error, resource }) => {
655 progress.backend_reusable = false;
656 if error == BackendError::DeviceLost {
657 progress.backend_callable = false;
658 }
659 if self.state.restore_event_release(id, resource).is_err() {
660 progress.backend_callable = false;
661 }
662 }
663 Err(ReleaseFailure::Indeterminate { .. }) => {
664 progress.backend_reusable = false;
665 progress.backend_callable = false;
666 }
667 }
668 }
669
670 fn reset_queues(&mut self, released: &mut ResourceCounts, progress: &mut ResetProgress) {
671 let mut cursor = 0;
672 while let Some((next, id)) = self.state.next_queue_id(cursor) {
673 cursor = next;
674 let queue = match self.state.begin_queue_release(id) {
675 Ok(queue) => queue,
676 Err(_) => {
677 progress.backend_reusable = false;
678 continue;
679 }
680 };
681 match self.accelerator.destroy_queue(queue) {
682 Ok(()) => match self.state.commit_queue_release(id) {
683 Ok(()) => released.queues += 1,
684 Err(_) => {
685 progress.backend_reusable = false;
686 progress.backend_callable = false;
687 break;
688 }
689 },
690 Err(ReleaseFailure::Rejected { error, resource }) => {
691 progress.backend_reusable = false;
692 if error == BackendError::DeviceLost {
693 progress.backend_callable = false;
694 }
695 if self.state.restore_queue_release(id, resource).is_err() {
696 progress.backend_callable = false;
697 break;
698 }
699 }
700 Err(ReleaseFailure::Indeterminate { .. }) => {
701 progress.backend_reusable = false;
702 progress.backend_callable = false;
703 break;
704 }
705 }
706 }
707 }
708
709 fn reset_programs(
710 &mut self,
711 released: &mut ResourceCounts,
712 released_bytes: &mut RetainedBytes,
713 progress: &mut ResetProgress,
714 ) {
715 let mut cursor = 0;
716 while let Some((next, id)) = self.state.next_program_id(cursor) {
717 cursor = next;
718 let resident_bytes = match self.state.program_record(id) {
719 Ok(record) => record.resident_bytes(),
720 Err(_) => {
721 progress.backend_reusable = false;
722 continue;
723 }
724 };
725 let program = match self.state.begin_program_release(id) {
726 Ok(program) => program,
727 Err(_) => {
728 progress.backend_reusable = false;
729 continue;
730 }
731 };
732 match self.accelerator.unload_program(program) {
733 Ok(()) => match self.state.commit_program_release(id) {
734 Ok(()) => {
735 released.programs += 1;
736 released_bytes.program_resident += u128::from(resident_bytes);
737 }
738 Err(_) => {
739 progress.backend_reusable = false;
740 progress.backend_callable = false;
741 break;
742 }
743 },
744 Err(ReleaseFailure::Rejected { error, resource }) => {
745 progress.backend_reusable = false;
746 if error == BackendError::DeviceLost {
747 progress.backend_callable = false;
748 }
749 if self.state.restore_program_release(id, resource).is_err() {
750 progress.backend_callable = false;
751 break;
752 }
753 }
754 Err(ReleaseFailure::Indeterminate { .. }) => {
755 progress.backend_reusable = false;
756 progress.backend_callable = false;
757 break;
758 }
759 }
760 }
761 }
762
763 fn reset_buffers(
764 &mut self,
765 released: &mut ResourceCounts,
766 released_bytes: &mut RetainedBytes,
767 progress: &mut ResetProgress,
768 ) {
769 let mut cursor = 0;
770 while let Some((next, id)) = self.state.next_buffer_id(cursor) {
771 cursor = next;
772 let allocation_bytes = match self.state.buffer_record(id) {
773 Ok(record) => record.info().allocation_bytes(),
774 Err(_) => {
775 progress.backend_reusable = false;
776 continue;
777 }
778 };
779 let buffer = match self.state.begin_buffer_release(id) {
780 Ok(buffer) => buffer,
781 Err(_) => {
782 progress.backend_reusable = false;
783 continue;
784 }
785 };
786 match self.accelerator.free_buffer(buffer) {
787 Ok(()) => match self.state.commit_buffer_release(id) {
788 Ok(()) => {
789 released.buffers += 1;
790 released_bytes.buffer_backing += u128::from(allocation_bytes);
791 }
792 Err(_) => {
793 progress.backend_reusable = false;
794 progress.backend_callable = false;
795 break;
796 }
797 },
798 Err(ReleaseFailure::Rejected { error, resource }) => {
799 progress.backend_reusable = false;
800 if error == BackendError::DeviceLost {
801 progress.backend_callable = false;
802 }
803 if self.state.restore_buffer_release(id, resource).is_err() {
804 progress.backend_callable = false;
805 break;
806 }
807 }
808 Err(ReleaseFailure::Indeterminate { .. }) => {
809 progress.backend_reusable = false;
810 progress.backend_callable = false;
811 break;
812 }
813 }
814 }
815 }
816
817 fn reset_contexts(&mut self, released: &mut ResourceCounts, progress: &mut ResetProgress) {
818 let mut cursor = 0;
819 while let Some((next, id)) = self.state.next_context_id(cursor) {
820 cursor = next;
821 let context = match self.state.begin_context_release(id) {
822 Ok(context) => context,
823 Err(_) => {
824 progress.backend_reusable = false;
825 continue;
826 }
827 };
828 match self.accelerator.destroy_context(context) {
829 Ok(()) => match self.state.commit_context_release(id) {
830 Ok(()) => released.contexts += 1,
831 Err(_) => {
832 progress.backend_reusable = false;
833 progress.backend_callable = false;
834 break;
835 }
836 },
837 Err(ReleaseFailure::Rejected { error, resource }) => {
838 progress.backend_reusable = false;
839 if error == BackendError::DeviceLost {
840 progress.backend_callable = false;
841 }
842 if self.state.restore_context_release(id, resource).is_err() {
843 progress.backend_callable = false;
844 break;
845 }
846 }
847 Err(ReleaseFailure::Indeterminate { .. }) => {
848 progress.backend_reusable = false;
849 progress.backend_callable = false;
850 break;
851 }
852 }
853 }
854 }
855
856 fn poll_event(
857 &mut self,
858 response: &mut dyn ByteSink,
859 request_id: u64,
860 event_id: ObjectId,
861 ) -> Result<CommandOutcome, CommandProcessError> {
862 let event = match self.state.event_record(event_id) {
863 Ok(record) => match record.resource() {
864 Ok(event) => event,
865 Err(error) => return self.respond_state_error(response, request_id, error),
866 },
867 Err(error) => return self.respond_state_error(response, request_id, error),
868 };
869 match self.accelerator.poll_event(event) {
870 Ok(state) => {
871 if state == EventState::Failed(BackendError::DeviceLost) {
872 self.require_backend_discard();
873 }
874 let payload = wire_event_state(state);
875 self.respond_bytes(
876 response,
877 StatusCode::OK,
878 request_id,
879 payload.as_bytes(),
880 false,
881 )
882 }
883 Err(error) => self.respond_backend_error(response, request_id, error, false),
884 }
885 }
886
887 fn cancel_event(
888 &mut self,
889 response: &mut dyn ByteSink,
890 request_id: u64,
891 event_id: ObjectId,
892 ) -> Result<CommandOutcome, CommandProcessError> {
893 if self.info.validate_event_cancellation().is_err() {
894 return self.respond_empty(response, StatusCode::UNSUPPORTED, request_id, false);
895 }
896 let event = match self.state.event_record(event_id) {
897 Ok(record) => match record.resource() {
898 Ok(event) => event,
899 Err(error) => return self.respond_state_error(response, request_id, error),
900 },
901 Err(error) => return self.respond_state_error(response, request_id, error),
902 };
903 match self.accelerator.cancel_event(event) {
904 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
905 Err(error) => self.respond_backend_error(response, request_id, error, false),
906 }
907 }
908
909 fn destroy_event(
910 &mut self,
911 response: &mut dyn ByteSink,
912 request_id: u64,
913 event_id: ObjectId,
914 ) -> Result<CommandOutcome, CommandProcessError> {
915 let state = {
916 let event = match self.state.event_record(event_id) {
917 Ok(record) => match record.resource() {
918 Ok(event) => event,
919 Err(error) => return self.respond_state_error(response, request_id, error),
920 },
921 Err(error) => return self.respond_state_error(response, request_id, error),
922 };
923 self.accelerator.poll_event(event)
924 };
925 match state {
926 Ok(EventState::Pending) => {
927 return self.respond_empty(response, StatusCode::BUSY, request_id, false);
928 }
929 Ok(EventState::Failed(BackendError::DeviceLost)) => {
930 self.require_backend_discard();
931 return self.respond_empty(response, StatusCode::DEVICE_LOST, request_id, false);
932 }
933 Ok(EventState::Complete | EventState::Failed(_) | EventState::Cancelled) => {}
934 Err(error) => {
935 return self.respond_backend_error(response, request_id, error, false);
936 }
937 }
938
939 let event = match self.state.begin_event_release(event_id) {
940 Ok(event) => event,
941 Err(error) => return self.respond_state_error(response, request_id, error),
942 };
943 match self.accelerator.destroy_event(event) {
944 Ok(()) => match self.state.commit_event_release(event_id) {
945 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
946 Err(_) => self.discard_response(response, request_id),
947 },
948 Err(ReleaseFailure::Rejected { error, resource }) => {
949 match self.state.restore_event_release(event_id, resource) {
950 Ok(()) => self.respond_backend_error(response, request_id, error, false),
951 Err(_) => self.discard_response(response, request_id),
952 }
953 }
954 Err(ReleaseFailure::Indeterminate { .. }) => {
955 if self.state.commit_event_release(event_id).is_ok() {
956 self.quarantined.events += 1;
957 }
958 self.discard_response(response, request_id)
959 }
960 }
961 }
962
963 fn release_unpublished_buffer(
964 &mut self,
965 response: &mut dyn ByteSink,
966 request_id: u64,
967 buffer_id: ObjectId,
968 admission_error: BackendError,
969 ) -> Result<CommandOutcome, CommandProcessError> {
970 let allocation_bytes = match self.state.buffer_record(buffer_id) {
971 Ok(record) => record.info().allocation_bytes(),
972 Err(_) => return self.discard_response(response, request_id),
973 };
974 let buffer = match self.state.begin_buffer_release(buffer_id) {
975 Ok(buffer) => buffer,
976 Err(_) => return self.discard_response(response, request_id),
977 };
978 match self.accelerator.free_buffer(buffer) {
979 Ok(()) => match self.state.commit_buffer_release(buffer_id) {
980 Ok(()) => self.respond_backend_error(response, request_id, admission_error, false),
981 Err(_) => self.discard_response(response, request_id),
982 },
983 Err(ReleaseFailure::Rejected { resource, .. }) => {
984 let _ = self.state.restore_buffer_release(buffer_id, resource);
985 self.discard_response(response, request_id)
986 }
987 Err(ReleaseFailure::Indeterminate { .. }) => {
988 if self.state.commit_buffer_release(buffer_id).is_ok() {
989 self.quarantined.buffers += 1;
990 self.quarantined_bytes.buffer_backing += u128::from(allocation_bytes);
991 }
992 self.discard_response(response, request_id)
993 }
994 }
995 }
996
997 fn write_buffer(
998 &mut self,
999 response: &mut dyn ByteSink,
1000 request_id: u64,
1001 buffer_id: ObjectId,
1002 range: BufferRange,
1003 data: &dyn ByteSource,
1004 ) -> Result<CommandOutcome, CommandProcessError> {
1005 let result = {
1006 let record = match self.state.buffer_record_mut(buffer_id) {
1007 Ok(record) => record,
1008 Err(error) => {
1009 return self.respond_state_error(response, request_id, error);
1010 }
1011 };
1012 if let Err(status) = validate_transfer(record, range, BufferUsage::TRANSFER_DESTINATION)
1013 {
1014 return self.respond_empty(response, status, request_id, false);
1015 }
1016 let buffer = match record.resource_mut() {
1017 Ok(buffer) => buffer,
1018 Err(error) => {
1019 return self.respond_state_error(response, request_id, error);
1020 }
1021 };
1022 self.accelerator.write_buffer(buffer, range.offset, data)
1023 };
1024
1025 match result {
1026 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
1027 Err(error) => self.respond_backend_error(response, request_id, error, true),
1028 }
1029 }
1030
1031 fn read_buffer(
1032 &mut self,
1033 response: &mut dyn ByteSink,
1034 request_id: u64,
1035 buffer_id: ObjectId,
1036 range: BufferRange,
1037 ) -> Result<CommandOutcome, CommandProcessError> {
1038 let record = match self.state.buffer_record(buffer_id) {
1039 Ok(record) => record,
1040 Err(error) => {
1041 return self.respond_state_error(response, request_id, error);
1042 }
1043 };
1044 if let Err(status) = validate_transfer(record, range, BufferUsage::TRANSFER_SOURCE) {
1045 return self.respond_empty(response, status, request_id, false);
1046 }
1047 let buffer = match record.resource() {
1048 Ok(buffer) => buffer,
1049 Err(error) => {
1050 return self.respond_state_error(response, request_id, error);
1051 }
1052 };
1053
1054 let mut writer = ResponseWriter::new(response, self.decoder.limits().max_response_bytes());
1055 let error = {
1056 let mut payload = writer
1057 .payload(range.bytes())
1058 .map_err(CommandProcessError::ResponseWrite)?;
1059 match self
1060 .accelerator
1061 .read_buffer(buffer, range.offset, &mut payload)
1062 {
1063 Ok(()) => {
1064 let result = payload.commit(StatusCode::OK, request_id);
1065 return self.complete_response(result, StatusCode::OK, request_id, false);
1066 }
1067 Err(error) => error,
1068 }
1069 };
1070 let status = self.backend_status(error);
1071 let result = writer.write_empty(status, request_id);
1072 self.complete_response(result, status, request_id, false)
1073 }
1074
1075 fn destroy_context(
1076 &mut self,
1077 response: &mut dyn ByteSink,
1078 request_id: u64,
1079 id: ObjectId,
1080 ) -> Result<CommandOutcome, CommandProcessError> {
1081 let resource = match self.state.begin_context_release(id) {
1082 Ok(resource) => resource,
1083 Err(error) => return self.respond_state_error(response, request_id, error),
1084 };
1085 match self.accelerator.destroy_context(resource) {
1086 Ok(()) => match self.state.commit_context_release(id) {
1087 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
1088 Err(_) => self.discard_response(response, request_id),
1089 },
1090 Err(ReleaseFailure::Rejected { error, resource }) => {
1091 match self.state.restore_context_release(id, resource) {
1092 Ok(()) => self.respond_backend_error(response, request_id, error, false),
1093 Err(_) => self.discard_response(response, request_id),
1094 }
1095 }
1096 Err(ReleaseFailure::Indeterminate { .. }) => {
1097 if self.state.commit_context_release(id).is_ok() {
1098 self.quarantined.contexts += 1;
1099 }
1100 self.discard_response(response, request_id)
1101 }
1102 }
1103 }
1104
1105 fn free_buffer(
1106 &mut self,
1107 response: &mut dyn ByteSink,
1108 request_id: u64,
1109 id: ObjectId,
1110 ) -> Result<CommandOutcome, CommandProcessError> {
1111 let allocation_bytes = match self.state.buffer_record(id) {
1112 Ok(record) => record.info().allocation_bytes(),
1113 Err(error) => return self.respond_state_error(response, request_id, error),
1114 };
1115 let resource = match self.state.begin_buffer_release(id) {
1116 Ok(resource) => resource,
1117 Err(error) => return self.respond_state_error(response, request_id, error),
1118 };
1119 match self.accelerator.free_buffer(resource) {
1120 Ok(()) => match self.state.commit_buffer_release(id) {
1121 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
1122 Err(_) => self.discard_response(response, request_id),
1123 },
1124 Err(ReleaseFailure::Rejected { error, resource }) => {
1125 match self.state.restore_buffer_release(id, resource) {
1126 Ok(()) => self.respond_backend_error(response, request_id, error, false),
1127 Err(_) => self.discard_response(response, request_id),
1128 }
1129 }
1130 Err(ReleaseFailure::Indeterminate { .. }) => {
1131 if self.state.commit_buffer_release(id).is_ok() {
1132 self.quarantined.buffers += 1;
1133 self.quarantined_bytes.buffer_backing += u128::from(allocation_bytes);
1134 }
1135 self.discard_response(response, request_id)
1136 }
1137 }
1138 }
1139
1140 fn unload_program(
1141 &mut self,
1142 response: &mut dyn ByteSink,
1143 request_id: u64,
1144 id: ObjectId,
1145 ) -> Result<CommandOutcome, CommandProcessError> {
1146 let resident_bytes = match self.state.program_record(id) {
1147 Ok(record) => record.resident_bytes(),
1148 Err(error) => return self.respond_state_error(response, request_id, error),
1149 };
1150 let resource = match self.state.begin_program_release(id) {
1151 Ok(resource) => resource,
1152 Err(error) => return self.respond_state_error(response, request_id, error),
1153 };
1154 match self.accelerator.unload_program(resource) {
1155 Ok(()) => match self.state.commit_program_release(id) {
1156 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
1157 Err(_) => self.discard_response(response, request_id),
1158 },
1159 Err(ReleaseFailure::Rejected { error, resource }) => {
1160 match self.state.restore_program_release(id, resource) {
1161 Ok(()) => self.respond_backend_error(response, request_id, error, false),
1162 Err(_) => self.discard_response(response, request_id),
1163 }
1164 }
1165 Err(ReleaseFailure::Indeterminate { .. }) => {
1166 if self.state.commit_program_release(id).is_ok() {
1167 self.quarantined.programs += 1;
1168 self.quarantined_bytes.program_resident += u128::from(resident_bytes);
1169 }
1170 self.discard_response(response, request_id)
1171 }
1172 }
1173 }
1174
1175 fn destroy_queue(
1176 &mut self,
1177 response: &mut dyn ByteSink,
1178 request_id: u64,
1179 id: ObjectId,
1180 ) -> Result<CommandOutcome, CommandProcessError> {
1181 let resource = match self.state.begin_queue_release(id) {
1182 Ok(resource) => resource,
1183 Err(error) => return self.respond_state_error(response, request_id, error),
1184 };
1185 match self.accelerator.destroy_queue(resource) {
1186 Ok(()) => match self.state.commit_queue_release(id) {
1187 Ok(()) => self.respond_empty(response, StatusCode::OK, request_id, true),
1188 Err(_) => self.discard_response(response, request_id),
1189 },
1190 Err(ReleaseFailure::Rejected { error, resource }) => {
1191 match self.state.restore_queue_release(id, resource) {
1192 Ok(()) => self.respond_backend_error(response, request_id, error, false),
1193 Err(_) => self.discard_response(response, request_id),
1194 }
1195 }
1196 Err(ReleaseFailure::Indeterminate { .. }) => {
1197 if self.state.commit_queue_release(id).is_ok() {
1198 self.quarantined.queues += 1;
1199 }
1200 self.discard_response(response, request_id)
1201 }
1202 }
1203 }
1204
1205 fn respond_create_error(
1206 &mut self,
1207 response: &mut dyn ByteSink,
1208 request_id: u64,
1209 error: CreateError<BackendError>,
1210 ) -> Result<CommandOutcome, CommandProcessError> {
1211 match error {
1212 CreateError::State(error) => self.respond_state_error(response, request_id, error),
1213 CreateError::Provider(error) => {
1214 self.respond_backend_error(response, request_id, error, false)
1215 }
1216 }
1217 }
1218
1219 fn respond_state_error(
1220 &mut self,
1221 response: &mut dyn ByteSink,
1222 request_id: u64,
1223 error: DeviceStateError,
1224 ) -> Result<CommandOutcome, CommandProcessError> {
1225 self.respond_empty(
1226 response,
1227 status_from_device_state_error(error),
1228 request_id,
1229 false,
1230 )
1231 }
1232
1233 fn respond_backend_error(
1234 &mut self,
1235 response: &mut dyn ByteSink,
1236 request_id: u64,
1237 error: BackendError,
1238 mutated: bool,
1239 ) -> Result<CommandOutcome, CommandProcessError> {
1240 let status = self.backend_status(error);
1241 self.respond_empty(response, status, request_id, mutated)
1242 }
1243
1244 fn backend_status(&mut self, error: BackendError) -> StatusCode {
1245 if error == BackendError::DeviceLost {
1246 self.require_backend_discard();
1247 }
1248 status_from_backend_error(error)
1249 }
1250
1251 fn require_backend_discard(&mut self) {
1252 self.health = DeviceHealth::BackendDiscardRequired;
1253 self.last_reset = None;
1254 }
1255
1256 fn discard_response(
1257 &mut self,
1258 response: &mut dyn ByteSink,
1259 request_id: u64,
1260 ) -> Result<CommandOutcome, CommandProcessError> {
1261 self.require_backend_discard();
1262 self.respond_empty(response, StatusCode::DEVICE_LOST, request_id, true)
1263 }
1264
1265 fn discard_report(
1266 &self,
1267 released: ResourceCounts,
1268 released_bytes: RetainedBytes,
1269 ) -> ResetReport {
1270 ResetReport {
1271 disposition: ResetDisposition::BackendDiscardRequired,
1272 released,
1273 quarantined: self
1274 .quarantined
1275 .saturating_add(self.state.resource_counts()),
1276 released_bytes,
1277 quarantined_bytes: self
1278 .quarantined_bytes
1279 .saturating_add(self.state.retained_bytes()),
1280 }
1281 }
1282
1283 fn respond_object(
1284 &mut self,
1285 response: &mut dyn ByteSink,
1286 request_id: u64,
1287 id: ObjectId,
1288 mutated: bool,
1289 ) -> Result<CommandOutcome, CommandProcessError> {
1290 let payload = ObjectPayload {
1291 object_id: Le64::new(id.get()),
1292 };
1293 self.respond_bytes(
1294 response,
1295 StatusCode::OK,
1296 request_id,
1297 payload.as_bytes(),
1298 mutated,
1299 )
1300 }
1301
1302 fn respond_event_id(
1303 &mut self,
1304 response: &mut dyn ByteSink,
1305 status: StatusCode,
1306 request_id: u64,
1307 id: ObjectId,
1308 mutated: bool,
1309 ) -> Result<CommandOutcome, CommandProcessError> {
1310 let payload = SubmitResponse {
1311 event_id: Le64::new(id.get()),
1312 };
1313 self.respond_bytes(response, status, request_id, payload.as_bytes(), mutated)
1314 }
1315
1316 fn respond_bytes(
1317 &mut self,
1318 response: &mut dyn ByteSink,
1319 status: StatusCode,
1320 request_id: u64,
1321 payload: &[u8],
1322 mutated: bool,
1323 ) -> Result<CommandOutcome, CommandProcessError> {
1324 let result = (|| {
1325 let mut writer =
1326 ResponseWriter::new(response, self.decoder.limits().max_response_bytes());
1327 let payload_bytes =
1328 u64::try_from(payload.len()).map_err(|_| ResponseWriteError::FrameTooLarge)?;
1329 let mut destination = writer.payload(payload_bytes)?;
1330 destination
1331 .write_at(0, payload)
1332 .map_err(|_| ResponseWriteError::SinkAccess)?;
1333 destination.commit(status, request_id)
1334 })();
1335 self.complete_response(result, status, request_id, mutated)
1336 }
1337
1338 fn respond_empty(
1339 &mut self,
1340 response: &mut dyn ByteSink,
1341 status: StatusCode,
1342 request_id: u64,
1343 mutated: bool,
1344 ) -> Result<CommandOutcome, CommandProcessError> {
1345 let result = ResponseWriter::new(response, self.decoder.limits().max_response_bytes())
1346 .write_empty(status, request_id);
1347 self.complete_response(result, status, request_id, mutated)
1348 }
1349
1350 fn complete_response(
1351 &mut self,
1352 result: Result<u32, ResponseWriteError>,
1353 status: StatusCode,
1354 request_id: u64,
1355 mutated: bool,
1356 ) -> Result<CommandOutcome, CommandProcessError> {
1357 match result {
1358 Ok(used) => Ok(CommandOutcome::Response {
1359 request_id,
1360 status,
1361 used,
1362 }),
1363 Err(error) => {
1364 if mutated && self.health == DeviceHealth::Running {
1365 self.health = DeviceHealth::NeedsReset;
1366 self.last_reset = None;
1367 }
1368 Err(CommandProcessError::ResponseWrite(error))
1369 }
1370 }
1371 }
1372}
1373
1374#[derive(Clone, Copy, Debug)]
1375struct ResetProgress {
1376 backend_reusable: bool,
1377 backend_callable: bool,
1378}
1379
1380impl Default for ResetProgress {
1381 fn default() -> Self {
1382 Self {
1383 backend_reusable: true,
1384 backend_callable: true,
1385 }
1386 }
1387}
1388
1389fn validate_transfer<B>(
1390 record: &BufferRecord<B>,
1391 range: BufferRange,
1392 required_usage: BufferUsage,
1393) -> Result<(), StatusCode> {
1394 if record.in_flight() != 0 {
1395 return Err(StatusCode::BUSY);
1396 }
1397 let desc = record.info().desc();
1398 if range.end() > desc.bytes() {
1399 return Err(StatusCode::OUT_OF_BOUNDS);
1400 }
1401 if !desc.usage.contains(required_usage) {
1402 return Err(StatusCode::PERMISSION_DENIED);
1403 }
1404 Ok(())
1405}
1406
1407fn wire_device_info(info: DeviceInfo) -> WireDeviceInfo {
1408 WireDeviceInfo {
1409 uuid: info.identity.uuid,
1410 class: Le16::new(info.identity.class.get()),
1411 reserved: Le16::new(0),
1412 vendor_id: Le32::new(info.identity.vendor_id),
1413 device_id: Le32::new(info.identity.device_id),
1414 capabilities: Le64::new(info.capabilities.bits()),
1415 max_contexts: Le32::new(info.limits.max_contexts),
1416 max_buffers_per_context: Le32::new(info.limits.max_buffers_per_context),
1417 max_programs_per_context: Le32::new(info.limits.max_programs_per_context),
1418 max_queues_per_context: Le32::new(info.limits.max_queues_per_context),
1419 max_events_per_context: Le32::new(info.limits.max_events_per_context),
1420 max_bindings_per_submission: Le32::new(info.limits.max_bindings_per_submission),
1421 max_buffer_bytes: Le64::new(info.limits.max_buffer_bytes),
1422 max_artifact_bytes: Le64::new(info.limits.max_artifact_bytes),
1423 }
1424}
1425
1426fn wire_event_state(state: EventState) -> WireEventState {
1427 let (state, error) = match state {
1428 EventState::Pending => (KnownEventState::Pending, StatusCode::OK),
1429 EventState::Complete => (KnownEventState::Complete, StatusCode::OK),
1430 EventState::Failed(error) => (KnownEventState::Failed, status_from_backend_error(error)),
1431 EventState::Cancelled => (KnownEventState::Cancelled, StatusCode::OK),
1432 };
1433 WireEventState {
1434 state: Le16::new(state as u16),
1435 error: Le16::new(error.0),
1436 reserved: Le32::new(0),
1437 }
1438}