| 1 | |
| 2 |
|
| 3 | use super::*;
|
| 4 |
|
| 5 | |
| 6 | struct SmData<'a, 'ctx, T: DriverGpuVm + 'ctx> {
|
| 7 | gpuvm: &'a mut UniqueRefGpuVm<T>,
|
| 8 | user_context: &'a mut T::SmContext<'ctx>,
|
| 9 | }
|
| 10 |
|
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | #[repr(C)]
|
| 17 | struct SmMapData<'a, 'ctx, T: DriverGpuVm> {
|
| 18 | sm_data: SmData<'a, 'ctx, T>,
|
| 19 | vm_bo: &'a GpuVmBo<T>,
|
| 20 | }
|
| 21 |
|
| 22 | |
| 23 | pub struct OpMapRequest<'a, 'ctx, T: DriverGpuVm + 'ctx> {
|
| 24 | |
| 25 | pub addr: u64,
|
| 26 | |
| 27 | pub range: u64,
|
| 28 | |
| 29 | pub gem_offset: u64,
|
| 30 | |
| 31 | pub vm_bo: &'a GpuVmBo<T>,
|
| 32 | |
| 33 | pub context: &'a mut T::SmContext<'ctx>,
|
| 34 | }
|
| 35 |
|
| 36 | impl<'a, 'ctx, T: DriverGpuVm> OpMapRequest<'a, 'ctx, T> {
|
| 37 | fn raw_request(&self) -> bindings::drm_gpuvm_map_req {
|
| 38 | bindings::drm_gpuvm_map_req {
|
| 39 | map: bindings::drm_gpuva_op_map {
|
| 40 | va: bindings::drm_gpuva_op_map__bindgen_ty_1 {
|
| 41 | addr: self.addr,
|
| 42 | range: self.range,
|
| 43 | },
|
| 44 | gem: bindings::drm_gpuva_op_map__bindgen_ty_2 {
|
| 45 | offset: self.gem_offset,
|
| 46 | obj: self.vm_bo.obj().as_raw(),
|
| 47 | },
|
| 48 | },
|
| 49 | }
|
| 50 | }
|
| 51 | }
|
| 52 |
|
| 53 | |
| 54 | pub struct OpMap<'op, T: DriverGpuVm> {
|
| 55 | op: &'op bindings::drm_gpuva_op_map,
|
| 56 | |
| 57 | |
| 58 | vm_bo: &'op GpuVmBo<T>,
|
| 59 | |
| 60 | |
| 61 | |
| 62 | _invariant: PhantomData<*mut &'op mut T>,
|
| 63 | }
|
| 64 |
|
| 65 | impl<'op, T: DriverGpuVm> OpMap<'op, T> {
|
| 66 | |
| 67 | pub fn addr(&self) -> u64 {
|
| 68 | self.op.va.addr
|
| 69 | }
|
| 70 |
|
| 71 | |
| 72 | pub fn length(&self) -> u64 {
|
| 73 | self.op.va.range
|
| 74 | }
|
| 75 |
|
| 76 | |
| 77 | pub fn gem_offset(&self) -> u64 {
|
| 78 | self.op.gem.offset
|
| 79 | }
|
| 80 |
|
| 81 | |
| 82 | pub fn obj(&self) -> &T::Object {
|
| 83 | |
| 84 | unsafe { <T::Object as IntoGEMObject>::from_raw(self.op.gem.obj) }
|
| 85 | }
|
| 86 |
|
| 87 | |
| 88 | pub fn vm_bo(&self) -> &GpuVmBo<T> {
|
| 89 | self.vm_bo
|
| 90 | }
|
| 91 |
|
| 92 | |
| 93 | pub fn insert(self, va: GpuVaAlloc<T>, va_data: impl PinInit<T::VaData>) -> OpMapped<'op, T> {
|
| 94 | let va = va.prepare(va_data);
|
| 95 | |
| 96 | unsafe { bindings::drm_gpuva_map(self.vm_bo.gpuvm().as_raw(), va, self.op) };
|
| 97 |
|
| 98 | let _gpuva_guard = self.vm_bo().lock_gpuva();
|
| 99 | |
| 100 | unsafe { bindings::drm_gpuva_link(va, self.vm_bo.as_raw()) };
|
| 101 |
|
| 102 | OpMapped {
|
| 103 | _invariant: self._invariant,
|
| 104 | }
|
| 105 | }
|
| 106 | }
|
| 107 |
|
| 108 | |
| 109 | pub struct OpMapped<'op, T> {
|
| 110 | _invariant: PhantomData<*mut &'op mut T>,
|
| 111 | }
|
| 112 |
|
| 113 | |
| 114 | pub struct OpUnmap<'op, T: DriverGpuVm> {
|
| 115 | op: &'op bindings::drm_gpuva_op_unmap,
|
| 116 | |
| 117 | |
| 118 | |
| 119 | _invariant: PhantomData<*mut &'op mut T>,
|
| 120 | }
|
| 121 |
|
| 122 | impl<'op, T: DriverGpuVm> OpUnmap<'op, T> {
|
| 123 | |
| 124 | |
| 125 | |
| 126 | |
| 127 | |
| 128 | |
| 129 | pub fn keep(&self) -> bool {
|
| 130 | self.op.keep
|
| 131 | }
|
| 132 |
|
| 133 | |
| 134 | pub fn va(&self) -> &GpuVa<T> {
|
| 135 | |
| 136 | |
| 137 | unsafe { GpuVa::<T>::from_raw(self.op.va) }
|
| 138 | }
|
| 139 |
|
| 140 | |
| 141 | pub fn remove(self) -> (OpUnmapped<'op, T>, GpuVaRemoved<T>) {
|
| 142 | |
| 143 | unsafe { bindings::drm_gpuva_unmap(self.op) };
|
| 144 | |
| 145 | unsafe { bindings::drm_gpuva_unlink_defer(self.op.va) };
|
| 146 |
|
| 147 | |
| 148 | let va = unsafe { GpuVaRemoved::from_raw(self.op.va) };
|
| 149 |
|
| 150 | (
|
| 151 | OpUnmapped {
|
| 152 | _invariant: self._invariant,
|
| 153 | },
|
| 154 | va,
|
| 155 | )
|
| 156 | }
|
| 157 | }
|
| 158 |
|
| 159 | |
| 160 | pub struct OpUnmapped<'op, T> {
|
| 161 | _invariant: PhantomData<*mut &'op mut T>,
|
| 162 | }
|
| 163 |
|
| 164 | |
| 165 | pub struct OpRemap<'op, T: DriverGpuVm> {
|
| 166 | op: &'op bindings::drm_gpuva_op_remap,
|
| 167 | |
| 168 | |
| 169 | |
| 170 | _invariant: PhantomData<*mut &'op mut T>,
|
| 171 | }
|
| 172 |
|
| 173 | impl<'op, T: DriverGpuVm> OpRemap<'op, T> {
|
| 174 | |
| 175 | #[inline]
|
| 176 | pub fn prev(&self) -> Option<&OpRemapMapData> {
|
| 177 | |
| 178 | NonNull::new(self.op.prev).map(|ptr| unsafe { OpRemapMapData::from_raw(ptr) })
|
| 179 | }
|
| 180 |
|
| 181 | |
| 182 | #[inline]
|
| 183 | pub fn next(&self) -> Option<&OpRemapMapData> {
|
| 184 | |
| 185 | NonNull::new(self.op.next).map(|ptr| unsafe { OpRemapMapData::from_raw(ptr) })
|
| 186 | }
|
| 187 |
|
| 188 | |
| 189 | |
| 190 | |
| 191 | |
| 192 | |
| 193 | |
| 194 | #[inline]
|
| 195 | pub fn keep(&self) -> bool {
|
| 196 | |
| 197 | unsafe { (*self.op.unmap).keep }
|
| 198 | }
|
| 199 |
|
| 200 | |
| 201 | #[inline]
|
| 202 | pub fn va_to_unmap(&self) -> &GpuVa<T> {
|
| 203 | |
| 204 | |
| 205 | unsafe { GpuVa::<T>::from_raw((*self.op.unmap).va) }
|
| 206 | }
|
| 207 |
|
| 208 | |
| 209 | #[inline]
|
| 210 | pub fn obj(&self) -> &T::Object {
|
| 211 | self.va_to_unmap().obj()
|
| 212 | }
|
| 213 |
|
| 214 | |
| 215 | #[inline]
|
| 216 | pub fn vm_bo(&self) -> &GpuVmBo<T> {
|
| 217 | self.va_to_unmap().vm_bo()
|
| 218 | }
|
| 219 |
|
| 220 | |
| 221 | pub fn remap(
|
| 222 | self,
|
| 223 | va_alloc: [GpuVaAlloc<T>; 2],
|
| 224 | prev_data: impl PinInit<T::VaData>,
|
| 225 | next_data: impl PinInit<T::VaData>,
|
| 226 | ) -> (OpRemapped<'op, T>, OpRemapRet<T>) {
|
| 227 | let [va1, va2] = va_alloc;
|
| 228 |
|
| 229 | let mut unused_va = None;
|
| 230 | let mut prev_ptr = ptr::null_mut();
|
| 231 | let mut next_ptr = ptr::null_mut();
|
| 232 | if self.prev().is_some() {
|
| 233 | prev_ptr = va1.prepare(prev_data);
|
| 234 | } else {
|
| 235 | unused_va = Some(va1);
|
| 236 | }
|
| 237 | if self.next().is_some() {
|
| 238 | next_ptr = va2.prepare(next_data);
|
| 239 | } else {
|
| 240 | unused_va = Some(va2);
|
| 241 | }
|
| 242 |
|
| 243 | |
| 244 | unsafe { bindings::drm_gpuva_remap(prev_ptr, next_ptr, self.op) };
|
| 245 |
|
| 246 | let gpuva_guard = self.vm_bo().lock_gpuva();
|
| 247 | if !prev_ptr.is_null() {
|
| 248 | |
| 249 | |
| 250 | unsafe { bindings::drm_gpuva_link(prev_ptr, self.vm_bo().as_raw()) };
|
| 251 | }
|
| 252 | if !next_ptr.is_null() {
|
| 253 | |
| 254 | |
| 255 | unsafe { bindings::drm_gpuva_link(next_ptr, self.vm_bo().as_raw()) };
|
| 256 | }
|
| 257 | drop(gpuva_guard);
|
| 258 |
|
| 259 | |
| 260 | unsafe { bindings::drm_gpuva_unlink_defer((*self.op.unmap).va) };
|
| 261 |
|
| 262 | (
|
| 263 | OpRemapped {
|
| 264 | _invariant: self._invariant,
|
| 265 | },
|
| 266 | OpRemapRet {
|
| 267 | |
| 268 | unmapped_va: unsafe { GpuVaRemoved::from_raw((*self.op.unmap).va) },
|
| 269 | unused_va,
|
| 270 | },
|
| 271 | )
|
| 272 | }
|
| 273 | }
|
| 274 |
|
| 275 | |
| 276 | #[repr(transparent)]
|
| 277 | pub struct OpRemapMapData(bindings::drm_gpuva_op_map);
|
| 278 |
|
| 279 | impl OpRemapMapData {
|
| 280 | |
| 281 | |
| 282 | unsafe fn from_raw<'a>(ptr: NonNull<bindings::drm_gpuva_op_map>) -> &'a Self {
|
| 283 | |
| 284 | unsafe { ptr.cast().as_ref() }
|
| 285 | }
|
| 286 |
|
| 287 | |
| 288 | pub fn addr(&self) -> u64 {
|
| 289 | self.0.va.addr
|
| 290 | }
|
| 291 |
|
| 292 | |
| 293 | pub fn length(&self) -> u64 {
|
| 294 | self.0.va.range
|
| 295 | }
|
| 296 |
|
| 297 | |
| 298 | pub fn gem_offset(&self) -> u64 {
|
| 299 | self.0.gem.offset
|
| 300 | }
|
| 301 | }
|
| 302 |
|
| 303 | |
| 304 | pub struct OpRemapRet<T: DriverGpuVm> {
|
| 305 | |
| 306 | pub unmapped_va: GpuVaRemoved<T>,
|
| 307 | |
| 308 | |
| 309 | pub unused_va: Option<GpuVaAlloc<T>>,
|
| 310 | }
|
| 311 |
|
| 312 | |
| 313 | pub struct OpRemapped<'op, T> {
|
| 314 | _invariant: PhantomData<*mut &'op mut T>,
|
| 315 | }
|
| 316 |
|
| 317 | impl<T: DriverGpuVm> UniqueRefGpuVm<T> {
|
| 318 | |
| 319 | |
| 320 | |
| 321 | |
| 322 | #[inline]
|
| 323 | pub fn sm_map(&mut self, req: OpMapRequest<'_, '_, T>) -> Result {
|
| 324 | if req.vm_bo.gpuvm() != &**self {
|
| 325 | return Err(EINVAL);
|
| 326 | }
|
| 327 |
|
| 328 | let gpuvm = self.as_raw();
|
| 329 | let raw_req = req.raw_request();
|
| 330 | |
| 331 | let mut p = SmMapData {
|
| 332 | sm_data: SmData {
|
| 333 | gpuvm: self,
|
| 334 | user_context: req.context,
|
| 335 | },
|
| 336 | vm_bo: req.vm_bo,
|
| 337 | };
|
| 338 | |
| 339 | |
| 340 | |
| 341 | |
| 342 | to_result(unsafe {
|
| 343 | bindings::drm_gpuvm_sm_map(gpuvm, (&raw mut p).cast(), &raw const raw_req)
|
| 344 | })
|
| 345 | }
|
| 346 |
|
| 347 | |
| 348 | |
| 349 | |
| 350 | |
| 351 | #[inline]
|
| 352 | pub fn sm_unmap(&mut self, addr: u64, length: u64, context: &mut T::SmContext<'_>) -> Result {
|
| 353 | let gpuvm = self.as_raw();
|
| 354 | let mut p = SmData {
|
| 355 | gpuvm: self,
|
| 356 | user_context: context,
|
| 357 | };
|
| 358 | |
| 359 | |
| 360 | |
| 361 | to_result(unsafe { bindings::drm_gpuvm_sm_unmap(gpuvm, (&raw mut p).cast(), addr, length) })
|
| 362 | }
|
| 363 | }
|
| 364 |
|
| 365 | impl<T: DriverGpuVm> GpuVm<T> {
|
| 366 | |
| 367 | |
| 368 | pub(super) unsafe extern "C" fn sm_step_map(
|
| 369 | op: *mut bindings::drm_gpuva_op,
|
| 370 | p: *mut c_void,
|
| 371 | ) -> c_int {
|
| 372 | |
| 373 | |
| 374 | let p = unsafe { &mut *p.cast::<SmMapData<'_, '_, T>>() };
|
| 375 | let op = OpMap {
|
| 376 | |
| 377 | op: unsafe { &(*op).__bindgen_anon_1.map },
|
| 378 | vm_bo: p.vm_bo,
|
| 379 | _invariant: PhantomData,
|
| 380 | };
|
| 381 | match p
|
| 382 | .sm_data
|
| 383 | .gpuvm
|
| 384 | .data()
|
| 385 | .sm_step_map(op, p.sm_data.user_context)
|
| 386 | {
|
| 387 | Ok(OpMapped { .. }) => 0,
|
| 388 | Err(err) => err.to_errno(),
|
| 389 | }
|
| 390 | }
|
| 391 |
|
| 392 | |
| 393 | |
| 394 | pub(super) unsafe extern "C" fn sm_step_unmap(
|
| 395 | op: *mut bindings::drm_gpuva_op,
|
| 396 | p: *mut c_void,
|
| 397 | ) -> c_int {
|
| 398 | |
| 399 | let p = unsafe { &mut *p.cast::<SmData<'_, '_, T>>() };
|
| 400 | let op = OpUnmap {
|
| 401 | |
| 402 | op: unsafe { &(*op).__bindgen_anon_1.unmap },
|
| 403 | _invariant: PhantomData,
|
| 404 | };
|
| 405 | match p.gpuvm.data().sm_step_unmap(op, p.user_context) {
|
| 406 | Ok(OpUnmapped { .. }) => 0,
|
| 407 | Err(err) => err.to_errno(),
|
| 408 | }
|
| 409 | }
|
| 410 |
|
| 411 | |
| 412 | |
| 413 | pub(super) unsafe extern "C" fn sm_step_remap(
|
| 414 | op: *mut bindings::drm_gpuva_op,
|
| 415 | p: *mut c_void,
|
| 416 | ) -> c_int {
|
| 417 | |
| 418 | let p = unsafe { &mut *p.cast::<SmData<'_, '_, T>>() };
|
| 419 | let op = OpRemap {
|
| 420 | |
| 421 | op: unsafe { &(*op).__bindgen_anon_1.remap },
|
| 422 | _invariant: PhantomData,
|
| 423 | };
|
| 424 | match p.gpuvm.data().sm_step_remap(op, p.user_context) {
|
| 425 | Ok(OpRemapped { .. }) => 0,
|
| 426 | Err(err) => err.to_errno(),
|
| 427 | }
|
| 428 | }
|
| 429 | }
|