| 1 | |
| 2 | * Copyright 2017 Advanced Micro Devices, Inc.
|
| 3 | *
|
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a
|
| 5 | * copy of this software and associated documentation files (the "Software"),
|
| 6 | * to deal in the Software without restriction, including without limitation
|
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
| 8 | * and/or sell copies of the Software, and to permit persons to whom the
|
| 9 | * Software is furnished to do so, subject to the following conditions:
|
| 10 | *
|
| 11 | * The above copyright notice and this permission notice shall be included in
|
| 12 | * all copies or substantial portions of the Software.
|
| 13 | *
|
| 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
| 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
| 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
| 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
| 20 | * OTHER DEALINGS IN THE SOFTWARE.
|
| 21 | *
|
| 22 |
|
| 23 | #include "amdgpu_ids.h"
|
| 24 |
|
| 25 | #include <linux/xarray.h>
|
| 26 | #include <linux/dma-fence-array.h>
|
| 27 |
|
| 28 |
|
| 29 | #include "amdgpu.h"
|
| 30 | #include "amdgpu_trace.h"
|
| 31 |
|
| 32 | |
| 33 | * PASID manager
|
| 34 | *
|
| 35 | * PASIDs are global address space identifiers that can be shared
|
| 36 | * between the GPU, an IOMMU and the driver. VMs on different devices
|
| 37 | * may use the same PASID if they share the same address
|
| 38 | * space. Therefore PASIDs are allocated using IDR cyclic allocator
|
| 39 | * (similar to kernel PID allocation) which naturally delays reuse.
|
| 40 | * VMs are looked up from the PASID per amdgpu_device.
|
| 41 |
|
| 42 |
|
| 43 | static DEFINE_XARRAY_FLAGS(amdgpu_pasid_xa, XA_FLAGS_LOCK_IRQ | XA_FLAGS_ALLOC1);
|
| 44 | static u32 amdgpu_pasid_xa_next;
|
| 45 |
|
| 46 |
|
| 47 | struct amdgpu_pasid_cb {
|
| 48 | struct dma_fence_cb cb;
|
| 49 | u32 pasid;
|
| 50 | };
|
| 51 |
|
| 52 | |
| 53 | * amdgpu_pasid_alloc - Allocate a PASID
|
| 54 | * @bits: Number of PASID bits supported by the hardware
|
| 55 | * @fpriv: DRM file private to associate with the PASID
|
| 56 | *
|
| 57 | * Uses the kernel's XArray cyclic allocator.
|
| 58 | * Allocates sequentially with automatic wrap-around.
|
| 59 | *
|
| 60 | * Returns:
|
| 61 | * Allocated PASID on success or a negative error code on failure.
|
| 62 |
|
| 63 | int amdgpu_pasid_alloc(unsigned int bits, struct amdgpu_fpriv *fpriv)
|
| 64 | {
|
| 65 | u32 pasid;
|
| 66 | int r;
|
| 67 |
|
| 68 | if (bits == 0)
|
| 69 | return -EINVAL;
|
| 70 |
|
| 71 | r = xa_alloc_cyclic_irq(&amdgpu_pasid_xa, &pasid, fpriv,
|
| 72 | XA_LIMIT(1, (1U << bits) - 1),
|
| 73 | &amdgpu_pasid_xa_next, GFP_KERNEL);
|
| 74 | if (r < 0)
|
| 75 | return r;
|
| 76 |
|
| 77 | trace_amdgpu_pasid_allocated(pasid);
|
| 78 | return pasid;
|
| 79 | }
|
| 80 |
|
| 81 | |
| 82 | * amdgpu_pasid_free - Free a PASID
|
| 83 | * @pasid: PASID to free
|
| 84 | *
|
| 85 | * Called in IRQ context.
|
| 86 |
|
| 87 | void amdgpu_pasid_free(u32 pasid)
|
| 88 | {
|
| 89 | unsigned long flags;
|
| 90 |
|
| 91 | trace_amdgpu_pasid_freed(pasid);
|
| 92 |
|
| 93 | xa_lock_irqsave(&amdgpu_pasid_xa, flags);
|
| 94 | __xa_erase(&amdgpu_pasid_xa, pasid);
|
| 95 | xa_unlock_irqrestore(&amdgpu_pasid_xa, flags);
|
| 96 | }
|
| 97 |
|
| 98 | static void amdgpu_pasid_free_cb(struct dma_fence *fence,
|
| 99 | struct dma_fence_cb *_cb)
|
| 100 | {
|
| 101 | struct amdgpu_pasid_cb *cb =
|
| 102 | container_of(_cb, struct amdgpu_pasid_cb, cb);
|
| 103 |
|
| 104 | amdgpu_pasid_free(cb->pasid);
|
| 105 | dma_fence_put(fence);
|
| 106 | kfree(cb);
|
| 107 | }
|
| 108 |
|
| 109 | |
| 110 | * amdgpu_pasid_clear_owner - Clear the owner associated with a PASID
|
| 111 | * @pasid: PASID whose owner should be cleared
|
| 112 | *
|
| 113 | * Replace the stored owner with NULL while keeping the PASID allocated.
|
| 114 | *
|
| 115 | * This is used by the delayed PASID free path so that future PASID
|
| 116 | * lookups cannot resolve a stale DRM file-private object while the PASID
|
| 117 | * is still waiting for outstanding fences before being released.
|
| 118 |
|
| 119 | static void amdgpu_pasid_clear_owner(u32 pasid)
|
| 120 | {
|
| 121 | unsigned long flags;
|
| 122 |
|
| 123 | if (!pasid)
|
| 124 | return;
|
| 125 |
|
| 126 | xa_lock_irqsave(&amdgpu_pasid_xa, flags);
|
| 127 | __xa_store(&amdgpu_pasid_xa, pasid, NULL, GFP_ATOMIC);
|
| 128 | xa_unlock_irqrestore(&amdgpu_pasid_xa, flags);
|
| 129 | }
|
| 130 |
|
| 131 | |
| 132 | * amdgpu_pasid_lock - acquire the global PASID xarray lock
|
| 133 | * @flags: storage for interrupt state
|
| 134 | *
|
| 135 | * Acquire the global PASID xarray lock with interrupts disabled.
|
| 136 | * The saved interrupt state must be passed to
|
| 137 | * amdgpu_pasid_unlock().
|
| 138 |
|
| 139 | void amdgpu_pasid_lock(unsigned long *flags)
|
| 140 | {
|
| 141 | xa_lock_irqsave(&amdgpu_pasid_xa, *flags);
|
| 142 | }
|
| 143 |
|
| 144 | |
| 145 | * amdgpu_pasid_unlock - release the global PASID xarray lock
|
| 146 | * @flags: interrupt state returned by amdgpu_pasid_lock()
|
| 147 | *
|
| 148 | * Release the global PASID xarray lock and restore the previous
|
| 149 | * interrupt state.
|
| 150 |
|
| 151 | void amdgpu_pasid_unlock(unsigned long flags)
|
| 152 | {
|
| 153 | xa_unlock_irqrestore(&amdgpu_pasid_xa, flags);
|
| 154 | }
|
| 155 |
|
| 156 | |
| 157 | * amdgpu_pasid_get_fpriv_locked - get the DRM owner of a PASID
|
| 158 | * @pasid: PASID to resolve
|
| 159 | *
|
| 160 | * The caller must hold the PASID XArray lock.
|
| 161 | *
|
| 162 | * Returns:
|
| 163 | * Pointer to the owning DRM file private, or %NULL if the PASID has no
|
| 164 | * current owner.
|
| 165 | *
|
| 166 | * The returned pointer is only valid while the PASID lock remains held
|
| 167 | * and must not be retained after calling amdgpu_pasid_unlock().
|
| 168 |
|
| 169 | struct amdgpu_fpriv *amdgpu_pasid_get_fpriv_locked(u32 pasid)
|
| 170 | {
|
| 171 | return xa_load(&amdgpu_pasid_xa, pasid);
|
| 172 | }
|
| 173 |
|
| 174 | |
| 175 | * amdgpu_pasid_free_delayed - free pasid when fences signal
|
| 176 | *
|
| 177 | * @resv: reservation object with the fences to wait for
|
| 178 | * @pasid: pasid to free
|
| 179 | *
|
| 180 | * Free the pasid only after all the fences in resv are signaled.
|
| 181 |
|
| 182 | void amdgpu_pasid_free_delayed(struct dma_resv *resv,
|
| 183 | u32 pasid)
|
| 184 | {
|
| 185 | struct amdgpu_pasid_cb *cb;
|
| 186 | struct dma_fence *fence;
|
| 187 | int r;
|
| 188 |
|
| 189 | amdgpu_pasid_clear_owner(pasid);
|
| 190 |
|
| 191 | r = dma_resv_get_singleton(resv, DMA_RESV_USAGE_BOOKKEEP, &fence);
|
| 192 | if (r)
|
| 193 | goto fallback;
|
| 194 |
|
| 195 | if (!fence) {
|
| 196 | amdgpu_pasid_free(pasid);
|
| 197 | return;
|
| 198 | }
|
| 199 |
|
| 200 | cb = kmalloc_obj(*cb);
|
| 201 | if (!cb) {
|
| 202 |
|
| 203 | dma_fence_wait(fence, false);
|
| 204 | dma_fence_put(fence);
|
| 205 | amdgpu_pasid_free(pasid);
|
| 206 | } else {
|
| 207 | cb->pasid = pasid;
|
| 208 | if (dma_fence_add_callback(fence, &cb->cb,
|
| 209 | amdgpu_pasid_free_cb))
|
| 210 | amdgpu_pasid_free_cb(fence, &cb->cb);
|
| 211 | }
|
| 212 |
|
| 213 | return;
|
| 214 |
|
| 215 | fallback:
|
| 216 | |
| 217 | * block for all the fences to complete.
|
| 218 |
|
| 219 | dma_resv_wait_timeout(resv, DMA_RESV_USAGE_BOOKKEEP,
|
| 220 | false, MAX_SCHEDULE_TIMEOUT);
|
| 221 | amdgpu_pasid_free(pasid);
|
| 222 | }
|
| 223 |
|
| 224 | |
| 225 | * VMID manager
|
| 226 | *
|
| 227 | * VMIDs are a per VMHUB identifier for page tables handling.
|
| 228 |
|
| 229 |
|
| 230 | |
| 231 | * amdgpu_vmid_had_gpu_reset - check if reset occured since last use
|
| 232 | *
|
| 233 | * @adev: amdgpu_device pointer
|
| 234 | * @id: VMID structure
|
| 235 | *
|
| 236 | * Check if GPU reset occured since last use of the VMID.
|
| 237 |
|
| 238 | bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
|
| 239 | struct amdgpu_vmid *id)
|
| 240 | {
|
| 241 | return id->current_gpu_reset_count !=
|
| 242 | atomic_read(&adev->gpu_reset_counter);
|
| 243 | }
|
| 244 |
|
| 245 |
|
| 246 | static bool amdgpu_vmid_gds_switch_needed(struct amdgpu_vmid *id,
|
| 247 | struct amdgpu_job *job)
|
| 248 | {
|
| 249 | return id->gds_base != job->gds_base ||
|
| 250 | id->gds_size != job->gds_size ||
|
| 251 | id->gws_base != job->gws_base ||
|
| 252 | id->gws_size != job->gws_size ||
|
| 253 | id->oa_base != job->oa_base ||
|
| 254 | id->oa_size != job->oa_size;
|
| 255 | }
|
| 256 |
|
| 257 |
|
| 258 | static bool amdgpu_vmid_compatible(struct amdgpu_vmid *id,
|
| 259 | struct amdgpu_job *job)
|
| 260 | {
|
| 261 | return id->pd_gpu_addr == job->vm_pd_addr &&
|
| 262 | !amdgpu_vmid_gds_switch_needed(id, job);
|
| 263 | }
|
| 264 |
|
| 265 | |
| 266 | * amdgpu_vmid_grab_idle - grab idle VMID
|
| 267 | *
|
| 268 | * @ring: ring we want to submit job to
|
| 269 | * @idle: resulting idle VMID
|
| 270 | * @fence: fence to wait for if no id could be grabbed
|
| 271 | *
|
| 272 | * Try to find an idle VMID, if none is idle add a fence to wait to the sync
|
| 273 | * object. Returns -ENOMEM when we are out of memory.
|
| 274 |
|
| 275 | static int amdgpu_vmid_grab_idle(struct amdgpu_ring *ring,
|
| 276 | struct amdgpu_vmid **idle,
|
| 277 | struct dma_fence **fence)
|
| 278 | {
|
| 279 | struct amdgpu_device *adev = ring->adev;
|
| 280 | unsigned vmhub = ring->vm_hub;
|
| 281 | struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
| 282 |
|
| 283 |
|
| 284 | if (!dma_fence_is_signaled(ring->vmid_wait)) {
|
| 285 | *fence = dma_fence_get(ring->vmid_wait);
|
| 286 | return 0;
|
| 287 | }
|
| 288 |
|
| 289 |
|
| 290 | list_for_each_entry_reverse((*idle), &id_mgr->ids_lru, list) {
|
| 291 |
|
| 292 | struct amdgpu_ring *r = adev->vm_manager.concurrent_flush ?
|
| 293 | NULL : ring;
|
| 294 |
|
| 295 | *fence = amdgpu_sync_peek_fence(&(*idle)->active, r);
|
| 296 | if (!(*fence))
|
| 297 | return 0;
|
| 298 | }
|
| 299 |
|
| 300 | |
| 301 | * If we can't find a idle VMID to use, wait on a fence from the least
|
| 302 | * recently used in the hope that it will be available soon.
|
| 303 |
|
| 304 | *idle = NULL;
|
| 305 | dma_fence_put(ring->vmid_wait);
|
| 306 | ring->vmid_wait = dma_fence_get(*fence);
|
| 307 |
|
| 308 |
|
| 309 | dma_fence_get(*fence);
|
| 310 | return 0;
|
| 311 | }
|
| 312 |
|
| 313 | |
| 314 | * amdgpu_vmid_grab_reserved - try to assign reserved VMID
|
| 315 | *
|
| 316 | * @vm: vm to allocate id for
|
| 317 | * @ring: ring we want to submit job to
|
| 318 | * @job: job who wants to use the VMID
|
| 319 | * @id: resulting VMID
|
| 320 | * @fence: fence to wait for if no id could be grabbed
|
| 321 | *
|
| 322 | * Try to assign a reserved VMID.
|
| 323 |
|
| 324 | static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
|
| 325 | struct amdgpu_ring *ring,
|
| 326 | struct amdgpu_job *job,
|
| 327 | struct amdgpu_vmid **id,
|
| 328 | struct dma_fence **fence)
|
| 329 | {
|
| 330 | struct amdgpu_device *adev = ring->adev;
|
| 331 | unsigned vmhub = ring->vm_hub;
|
| 332 | uint64_t fence_context = adev->fence_context + ring->idx;
|
| 333 | bool needs_flush = vm->use_cpu_for_update;
|
| 334 | uint64_t updates = amdgpu_vm_tlb_seq(vm);
|
| 335 | int r;
|
| 336 |
|
| 337 | *id = vm->reserved_vmid[vmhub];
|
| 338 | if ((*id)->owner != vm->immediate.fence_context ||
|
| 339 | !amdgpu_vmid_compatible(*id, job) ||
|
| 340 | (*id)->flushed_updates < updates ||
|
| 341 | !(*id)->last_flush ||
|
| 342 | ((*id)->last_flush->context != fence_context &&
|
| 343 | !dma_fence_is_signaled((*id)->last_flush)))
|
| 344 | needs_flush = true;
|
| 345 |
|
| 346 | if ((*id)->owner != vm->immediate.fence_context ||
|
| 347 | (!adev->vm_manager.concurrent_flush && needs_flush)) {
|
| 348 | struct dma_fence *tmp;
|
| 349 |
|
| 350 | |
| 351 | * same time
|
| 352 |
|
| 353 | if (adev->vm_manager.concurrent_flush)
|
| 354 | ring = NULL;
|
| 355 |
|
| 356 |
|
| 357 | (*id)->pd_gpu_addr = 0;
|
| 358 | tmp = amdgpu_sync_peek_fence(&(*id)->active, ring);
|
| 359 | if (tmp) {
|
| 360 | *id = NULL;
|
| 361 | *fence = dma_fence_get(tmp);
|
| 362 | return 0;
|
| 363 | }
|
| 364 | }
|
| 365 |
|
| 366 | |
| 367 | * user of the VMID.
|
| 368 |
|
| 369 | r = amdgpu_sync_fence(&(*id)->active, &job->base.s_fence->finished,
|
| 370 | GFP_ATOMIC);
|
| 371 | if (r)
|
| 372 | return r;
|
| 373 |
|
| 374 | job->vm_needs_flush = needs_flush;
|
| 375 | job->spm_update_needed = true;
|
| 376 | return 0;
|
| 377 | }
|
| 378 |
|
| 379 | |
| 380 | * amdgpu_vmid_grab_used - try to reuse a VMID
|
| 381 | *
|
| 382 | * @vm: vm to allocate id for
|
| 383 | * @ring: ring we want to submit job to
|
| 384 | * @job: job who wants to use the VMID
|
| 385 | * @id: resulting VMID
|
| 386 | *
|
| 387 | * Try to reuse a VMID for this submission.
|
| 388 |
|
| 389 | static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm,
|
| 390 | struct amdgpu_ring *ring,
|
| 391 | struct amdgpu_job *job,
|
| 392 | struct amdgpu_vmid **id)
|
| 393 | {
|
| 394 | struct amdgpu_device *adev = ring->adev;
|
| 395 | unsigned vmhub = ring->vm_hub;
|
| 396 | struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
| 397 | uint64_t fence_context = adev->fence_context + ring->idx;
|
| 398 | uint64_t updates = amdgpu_vm_tlb_seq(vm);
|
| 399 | int r;
|
| 400 |
|
| 401 | job->vm_needs_flush = vm->use_cpu_for_update;
|
| 402 |
|
| 403 |
|
| 404 | list_for_each_entry_reverse((*id), &id_mgr->ids_lru, list) {
|
| 405 | bool needs_flush = vm->use_cpu_for_update;
|
| 406 |
|
| 407 |
|
| 408 | if ((*id)->owner != vm->immediate.fence_context)
|
| 409 | continue;
|
| 410 |
|
| 411 | if (!amdgpu_vmid_compatible(*id, job))
|
| 412 | continue;
|
| 413 |
|
| 414 | if (!(*id)->last_flush ||
|
| 415 | ((*id)->last_flush->context != fence_context &&
|
| 416 | !dma_fence_is_signaled((*id)->last_flush)))
|
| 417 | needs_flush = true;
|
| 418 |
|
| 419 | if ((*id)->flushed_updates < updates)
|
| 420 | needs_flush = true;
|
| 421 |
|
| 422 | if (needs_flush && !adev->vm_manager.concurrent_flush)
|
| 423 | continue;
|
| 424 |
|
| 425 | |
| 426 | * user of the VMID.
|
| 427 |
|
| 428 | r = amdgpu_sync_fence(&(*id)->active,
|
| 429 | &job->base.s_fence->finished,
|
| 430 | GFP_ATOMIC);
|
| 431 | if (r)
|
| 432 | return r;
|
| 433 |
|
| 434 | job->vm_needs_flush |= needs_flush;
|
| 435 | return 0;
|
| 436 | }
|
| 437 |
|
| 438 | *id = NULL;
|
| 439 | return 0;
|
| 440 | }
|
| 441 |
|
| 442 | |
| 443 | * amdgpu_vmid_grab - allocate the next free VMID
|
| 444 | *
|
| 445 | * @vm: vm to allocate id for
|
| 446 | * @ring: ring we want to submit job to
|
| 447 | * @job: job who wants to use the VMID
|
| 448 | * @fence: fence to wait for if no id could be grabbed
|
| 449 | *
|
| 450 | * Allocate an id for the vm, adding fences to the sync obj as necessary.
|
| 451 |
|
| 452 | int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
|
| 453 | struct amdgpu_job *job, struct dma_fence **fence)
|
| 454 | {
|
| 455 | struct amdgpu_device *adev = ring->adev;
|
| 456 | unsigned vmhub = ring->vm_hub;
|
| 457 | struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
| 458 | struct amdgpu_vmid *idle = NULL;
|
| 459 | struct amdgpu_vmid *id = NULL;
|
| 460 | int r = 0;
|
| 461 |
|
| 462 | mutex_lock(&id_mgr->lock);
|
| 463 | r = amdgpu_vmid_grab_idle(ring, &idle, fence);
|
| 464 | if (r || !idle)
|
| 465 | goto error;
|
| 466 |
|
| 467 | if (amdgpu_vmid_uses_reserved(vm, vmhub)) {
|
| 468 | r = amdgpu_vmid_grab_reserved(vm, ring, job, &id, fence);
|
| 469 | if (r || !id)
|
| 470 | goto error;
|
| 471 | } else {
|
| 472 | r = amdgpu_vmid_grab_used(vm, ring, job, &id);
|
| 473 | if (r)
|
| 474 | goto error;
|
| 475 |
|
| 476 | if (!id) {
|
| 477 |
|
| 478 | id = idle;
|
| 479 |
|
| 480 |
|
| 481 | r = amdgpu_sync_fence(&id->active,
|
| 482 | &job->base.s_fence->finished,
|
| 483 | GFP_ATOMIC);
|
| 484 | if (r)
|
| 485 | goto error;
|
| 486 |
|
| 487 | job->vm_needs_flush = true;
|
| 488 | }
|
| 489 |
|
| 490 | list_move_tail(&id->list, &id_mgr->ids_lru);
|
| 491 | }
|
| 492 |
|
| 493 | job->gds_switch_needed = amdgpu_vmid_gds_switch_needed(id, job);
|
| 494 | if (job->vm_needs_flush) {
|
| 495 | id->flushed_updates = amdgpu_vm_tlb_seq(vm);
|
| 496 | dma_fence_put(id->last_flush);
|
| 497 | id->last_flush = NULL;
|
| 498 | }
|
| 499 | job->vmid = id - id_mgr->ids;
|
| 500 | job->pasid = vm->pasid;
|
| 501 |
|
| 502 | id->gds_base = job->gds_base;
|
| 503 | id->gds_size = job->gds_size;
|
| 504 | id->gws_base = job->gws_base;
|
| 505 | id->gws_size = job->gws_size;
|
| 506 | id->oa_base = job->oa_base;
|
| 507 | id->oa_size = job->oa_size;
|
| 508 | id->pd_gpu_addr = job->vm_pd_addr;
|
| 509 | id->owner = vm->immediate.fence_context;
|
| 510 |
|
| 511 | trace_amdgpu_vm_grab_id(vm, ring, job);
|
| 512 |
|
| 513 | error:
|
| 514 | mutex_unlock(&id_mgr->lock);
|
| 515 | return r;
|
| 516 | }
|
| 517 |
|
| 518 | |
| 519 | * amdgpu_vmid_uses_reserved - check if a VM will use a reserved VMID
|
| 520 | * @vm: the VM to check
|
| 521 | * @vmhub: the VMHUB which will be used
|
| 522 | *
|
| 523 | * Returns: True if the VM will use a reserved VMID.
|
| 524 |
|
| 525 | bool amdgpu_vmid_uses_reserved(struct amdgpu_vm *vm, unsigned int vmhub)
|
| 526 | {
|
| 527 | return vm->reserved_vmid[vmhub];
|
| 528 | }
|
| 529 |
|
| 530 | |
| 531 | * amdgpu_vmid_alloc_reserved - reserve a specific VMID for this vm
|
| 532 | * @adev: amdgpu device structure
|
| 533 | * @vm: the VM to reserve an ID for
|
| 534 | * @vmhub: the VMHUB which should be used
|
| 535 | *
|
| 536 | * Mostly used to have a reserved VMID for debugging and SPM.
|
| 537 | *
|
| 538 | * Returns: 0 for success, -ENOENT if an ID is already reserved.
|
| 539 |
|
| 540 | int amdgpu_vmid_alloc_reserved(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
| 541 | unsigned vmhub)
|
| 542 | {
|
| 543 | struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
| 544 | struct amdgpu_vmid *id;
|
| 545 | int r = 0;
|
| 546 |
|
| 547 | mutex_lock(&id_mgr->lock);
|
| 548 | if (vm->reserved_vmid[vmhub])
|
| 549 | goto unlock;
|
| 550 | if (id_mgr->reserved_vmid) {
|
| 551 | r = -ENOENT;
|
| 552 | goto unlock;
|
| 553 | }
|
| 554 |
|
| 555 | id = list_first_entry(&id_mgr->ids_lru, struct amdgpu_vmid, list);
|
| 556 | list_del_init(&id->list);
|
| 557 | vm->reserved_vmid[vmhub] = id;
|
| 558 | id_mgr->reserved_vmid = true;
|
| 559 | mutex_unlock(&id_mgr->lock);
|
| 560 |
|
| 561 | return 0;
|
| 562 | unlock:
|
| 563 | mutex_unlock(&id_mgr->lock);
|
| 564 | return r;
|
| 565 | }
|
| 566 |
|
| 567 | |
| 568 | * amdgpu_vmid_free_reserved - free up a reserved VMID again
|
| 569 | * @adev: amdgpu device structure
|
| 570 | * @vm: the VM with the reserved ID
|
| 571 | * @vmhub: the VMHUB which should be used
|
| 572 |
|
| 573 | void amdgpu_vmid_free_reserved(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
| 574 | unsigned vmhub)
|
| 575 | {
|
| 576 | struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
| 577 |
|
| 578 | mutex_lock(&id_mgr->lock);
|
| 579 | if (vm->reserved_vmid[vmhub]) {
|
| 580 | list_add(&vm->reserved_vmid[vmhub]->list,
|
| 581 | &id_mgr->ids_lru);
|
| 582 | vm->reserved_vmid[vmhub] = NULL;
|
| 583 | id_mgr->reserved_vmid = false;
|
| 584 | }
|
| 585 | mutex_unlock(&id_mgr->lock);
|
| 586 | }
|
| 587 |
|
| 588 | |
| 589 | * amdgpu_vmid_reset - reset VMID to zero
|
| 590 | *
|
| 591 | * @adev: amdgpu device structure
|
| 592 | * @vmhub: vmhub type
|
| 593 | * @vmid: vmid number to use
|
| 594 | *
|
| 595 | * Reset saved GDW, GWS and OA to force switch on next flush.
|
| 596 |
|
| 597 | void amdgpu_vmid_reset(struct amdgpu_device *adev, unsigned vmhub,
|
| 598 | unsigned vmid)
|
| 599 | {
|
| 600 | struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
| 601 | struct amdgpu_vmid *id = &id_mgr->ids[vmid];
|
| 602 |
|
| 603 | mutex_lock(&id_mgr->lock);
|
| 604 | id->owner = 0;
|
| 605 | id->gds_base = 0;
|
| 606 | id->gds_size = 0;
|
| 607 | id->gws_base = 0;
|
| 608 | id->gws_size = 0;
|
| 609 | id->oa_base = 0;
|
| 610 | id->oa_size = 0;
|
| 611 | mutex_unlock(&id_mgr->lock);
|
| 612 | }
|
| 613 |
|
| 614 | |
| 615 | * amdgpu_vmid_reset_all - reset VMID to zero
|
| 616 | *
|
| 617 | * @adev: amdgpu device structure
|
| 618 | *
|
| 619 | * Reset VMID to force flush on next use
|
| 620 |
|
| 621 | void amdgpu_vmid_reset_all(struct amdgpu_device *adev)
|
| 622 | {
|
| 623 | unsigned i, j;
|
| 624 |
|
| 625 | for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
|
| 626 | struct amdgpu_vmid_mgr *id_mgr =
|
| 627 | &adev->vm_manager.id_mgr[i];
|
| 628 |
|
| 629 | for (j = 1; j < id_mgr->num_ids; ++j)
|
| 630 | amdgpu_vmid_reset(adev, i, j);
|
| 631 | }
|
| 632 | }
|
| 633 |
|
| 634 | |
| 635 | * amdgpu_vmid_mgr_init - init the VMID manager
|
| 636 | *
|
| 637 | * @adev: amdgpu_device pointer
|
| 638 | *
|
| 639 | * Initialize the VM manager structures
|
| 640 |
|
| 641 | void amdgpu_vmid_mgr_init(struct amdgpu_device *adev)
|
| 642 | {
|
| 643 | unsigned i, j;
|
| 644 |
|
| 645 | for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
|
| 646 | struct amdgpu_vmid_mgr *id_mgr =
|
| 647 | &adev->vm_manager.id_mgr[i];
|
| 648 |
|
| 649 | mutex_init(&id_mgr->lock);
|
| 650 | INIT_LIST_HEAD(&id_mgr->ids_lru);
|
| 651 |
|
| 652 |
|
| 653 | if (amdgpu_ip_version(adev, GC_HWIP, 0) < IP_VERSION(10, 0, 0))
|
| 654 |
|
| 655 | id_mgr->num_ids = adev->vm_manager.first_kfd_vmid;
|
| 656 | else if (AMDGPU_IS_MMHUB0(i) ||
|
| 657 | AMDGPU_IS_MMHUB1(i))
|
| 658 | id_mgr->num_ids = 16;
|
| 659 | else
|
| 660 |
|
| 661 | id_mgr->num_ids = adev->vm_manager.first_kfd_vmid;
|
| 662 |
|
| 663 |
|
| 664 | for (j = 1; j < id_mgr->num_ids; ++j) {
|
| 665 | amdgpu_vmid_reset(adev, i, j);
|
| 666 | amdgpu_sync_create(&id_mgr->ids[j].active);
|
| 667 | list_add_tail(&id_mgr->ids[j].list, &id_mgr->ids_lru);
|
| 668 | }
|
| 669 | }
|
| 670 | }
|
| 671 |
|
| 672 | |
| 673 | * amdgpu_vmid_mgr_fini - cleanup VM manager
|
| 674 | *
|
| 675 | * @adev: amdgpu_device pointer
|
| 676 | *
|
| 677 | * Cleanup the VM manager and free resources.
|
| 678 |
|
| 679 | void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)
|
| 680 | {
|
| 681 | unsigned i, j;
|
| 682 |
|
| 683 | for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
|
| 684 | struct amdgpu_vmid_mgr *id_mgr =
|
| 685 | &adev->vm_manager.id_mgr[i];
|
| 686 |
|
| 687 | mutex_destroy(&id_mgr->lock);
|
| 688 | for (j = 0; j < AMDGPU_NUM_VMID; ++j) {
|
| 689 | struct amdgpu_vmid *id = &id_mgr->ids[j];
|
| 690 |
|
| 691 | amdgpu_sync_free(&id->active);
|
| 692 | dma_fence_put(id->last_flush);
|
| 693 | dma_fence_put(id->pasid_mapping);
|
| 694 | }
|
| 695 | }
|
| 696 | }
|
| 697 |
|
| 698 | |
| 699 | * amdgpu_pasid_mgr_cleanup - cleanup PASID manager
|
| 700 | *
|
| 701 | * Cleanup the IDR allocator.
|
| 702 |
|
| 703 | void amdgpu_pasid_mgr_cleanup(void)
|
| 704 | {
|
| 705 | xa_destroy(&amdgpu_pasid_xa);
|
| 706 | }
|