1use crate::bnic_driver::BnicDriver;
5use crate::gdma_driver::GdmaDriver;
6use gdma_defs::GdmaDevId;
7use gdma_defs::GdmaQueueType;
8use std::mem::ManuallyDrop;
9use user_driver::DeviceBacking;
10use user_driver::memory::MemoryBlock;
11
12#[derive(Default)]
20pub struct ResourceArena {
21 resources: Vec<Resource>,
22}
23
24pub(crate) enum Resource {
25 MemoryBlock(ManuallyDrop<MemoryBlock>),
26 DmaRegion {
27 dev_id: GdmaDevId,
28 gdma_region: u64,
29 },
30 Eq {
31 dev_id: GdmaDevId,
32 eq_id: u32,
33 },
34 BnicQueue {
35 dev_id: GdmaDevId,
36 wq_type: GdmaQueueType,
37 wq_obj: u64,
38 },
39}
40
41impl ResourceArena {
42 pub fn new() -> Self {
44 Self::default()
45 }
46
47 pub fn is_empty(&self) -> bool {
49 self.resources.is_empty()
50 }
51
52 pub(crate) fn push(&mut self, resource: Resource) {
53 self.resources.push(resource);
54 }
55
56 pub(crate) fn take_dma_region(&mut self, owned_gdma_region: u64) {
57 let i = self
58 .resources
59 .iter()
60 .rposition(|r| matches!(r, Resource::DmaRegion { gdma_region, .. } if *gdma_region == owned_gdma_region))
61 .expect("gdma region must be in arena");
62 self.resources.remove(i);
63 }
64
65 pub(crate) async fn destroy<T: DeviceBacking>(mut self, gdma: &mut GdmaDriver<T>) {
66 let skip_hwc = gdma.get_reset_request_pending().is_some();
67 if skip_hwc {
68 tracing::info!(
69 count = self.resources.len(),
70 "skipping resource teardown during HWC reset request"
71 );
72 }
73 for resource in self.resources.drain(..).rev() {
74 let r = match resource {
75 Resource::MemoryBlock(mem) => {
76 drop(ManuallyDrop::into_inner(mem));
77 Ok(())
78 }
79 Resource::DmaRegion { .. } | Resource::Eq { .. } | Resource::BnicQueue { .. }
82 if skip_hwc =>
83 {
84 continue;
85 }
86 Resource::DmaRegion {
87 dev_id,
88 gdma_region,
89 } => gdma.destroy_dma_region(dev_id, gdma_region).await,
90 Resource::Eq { dev_id, eq_id } => gdma.disable_eq(dev_id, eq_id).await,
91 Resource::BnicQueue {
92 dev_id,
93 wq_type,
94 wq_obj,
95 } => {
96 BnicDriver::new(gdma, dev_id)
97 .destroy_wq_obj(wq_type, wq_obj)
98 .await
99 }
100 };
101 if let Err(err) = r {
102 tracing::error!(
103 error = err.as_ref() as &dyn std::error::Error,
104 "failed to tear down resource"
105 );
106 }
107 }
108 }
109}
110
111impl Drop for ResourceArena {
112 fn drop(&mut self) {
113 if !self.resources.is_empty() {
114 tracing::error!("leaking resources");
115 }
116 }
117}