|
@@ -33,52 +33,6 @@
|
|
|
#include "amdgpu.h"
|
|
|
#include "amdgpu_trace.h"
|
|
|
|
|
|
-/*
|
|
|
- * PASID manager
|
|
|
- *
|
|
|
- * PASIDs are global address space identifiers that can be shared
|
|
|
- * between the GPU, an IOMMU and the driver. VMs on different devices
|
|
|
- * may use the same PASID if they share the same address
|
|
|
- * space. Therefore PASIDs are allocated using a global IDA. VMs are
|
|
|
- * looked up from the PASID per amdgpu_device.
|
|
|
- */
|
|
|
-static DEFINE_IDA(amdgpu_vm_pasid_ida);
|
|
|
-
|
|
|
-/**
|
|
|
- * amdgpu_vm_alloc_pasid - Allocate a PASID
|
|
|
- * @bits: Maximum width of the PASID in bits, must be at least 1
|
|
|
- *
|
|
|
- * Allocates a PASID of the given width while keeping smaller PASIDs
|
|
|
- * available if possible.
|
|
|
- *
|
|
|
- * Returns a positive integer on success. Returns %-EINVAL if bits==0.
|
|
|
- * Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on
|
|
|
- * memory allocation failure.
|
|
|
- */
|
|
|
-int amdgpu_vm_alloc_pasid(unsigned int bits)
|
|
|
-{
|
|
|
- int pasid = -EINVAL;
|
|
|
-
|
|
|
- for (bits = min(bits, 31U); bits > 0; bits--) {
|
|
|
- pasid = ida_simple_get(&amdgpu_vm_pasid_ida,
|
|
|
- 1U << (bits - 1), 1U << bits,
|
|
|
- GFP_KERNEL);
|
|
|
- if (pasid != -ENOSPC)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return pasid;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * amdgpu_vm_free_pasid - Free a PASID
|
|
|
- * @pasid: PASID to free
|
|
|
- */
|
|
|
-void amdgpu_vm_free_pasid(unsigned int pasid)
|
|
|
-{
|
|
|
- ida_simple_remove(&amdgpu_vm_pasid_ida, pasid);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* GPUVM
|
|
|
* GPUVM is similar to the legacy gart on older asics, however
|
|
@@ -447,286 +401,6 @@ int amdgpu_vm_alloc_pts(struct amdgpu_device *adev,
|
|
|
adev->vm_manager.root_level);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * amdgpu_vm_had_gpu_reset - check if reset occured since last use
|
|
|
- *
|
|
|
- * @adev: amdgpu_device pointer
|
|
|
- * @id: VMID structure
|
|
|
- *
|
|
|
- * Check if GPU reset occured since last use of the VMID.
|
|
|
- */
|
|
|
-static bool amdgpu_vm_had_gpu_reset(struct amdgpu_device *adev,
|
|
|
- struct amdgpu_vm_id *id)
|
|
|
-{
|
|
|
- return id->current_gpu_reset_count !=
|
|
|
- atomic_read(&adev->gpu_reset_counter);
|
|
|
-}
|
|
|
-
|
|
|
-static bool amdgpu_vm_reserved_vmid_ready(struct amdgpu_vm *vm, unsigned vmhub)
|
|
|
-{
|
|
|
- return !!vm->reserved_vmid[vmhub];
|
|
|
-}
|
|
|
-
|
|
|
-/* idr_mgr->lock must be held */
|
|
|
-static int amdgpu_vm_grab_reserved_vmid_locked(struct amdgpu_vm *vm,
|
|
|
- struct amdgpu_ring *ring,
|
|
|
- struct amdgpu_sync *sync,
|
|
|
- struct dma_fence *fence,
|
|
|
- struct amdgpu_job *job)
|
|
|
-{
|
|
|
- struct amdgpu_device *adev = ring->adev;
|
|
|
- unsigned vmhub = ring->funcs->vmhub;
|
|
|
- uint64_t fence_context = adev->fence_context + ring->idx;
|
|
|
- struct amdgpu_vm_id *id = vm->reserved_vmid[vmhub];
|
|
|
- struct amdgpu_vm_id_manager *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
|
|
- struct dma_fence *updates = sync->last_vm_update;
|
|
|
- int r = 0;
|
|
|
- struct dma_fence *flushed, *tmp;
|
|
|
- bool needs_flush = vm->use_cpu_for_update;
|
|
|
-
|
|
|
- flushed = id->flushed_updates;
|
|
|
- if ((amdgpu_vm_had_gpu_reset(adev, id)) ||
|
|
|
- (atomic64_read(&id->owner) != vm->client_id) ||
|
|
|
- (job->vm_pd_addr != id->pd_gpu_addr) ||
|
|
|
- (updates && (!flushed || updates->context != flushed->context ||
|
|
|
- dma_fence_is_later(updates, flushed))) ||
|
|
|
- (!id->last_flush || (id->last_flush->context != fence_context &&
|
|
|
- !dma_fence_is_signaled(id->last_flush)))) {
|
|
|
- needs_flush = true;
|
|
|
- /* to prevent one context starved by another context */
|
|
|
- id->pd_gpu_addr = 0;
|
|
|
- tmp = amdgpu_sync_peek_fence(&id->active, ring);
|
|
|
- if (tmp) {
|
|
|
- r = amdgpu_sync_fence(adev, sync, tmp, false);
|
|
|
- return r;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Good we can use this VMID. Remember this submission as
|
|
|
- * user of the VMID.
|
|
|
- */
|
|
|
- r = amdgpu_sync_fence(ring->adev, &id->active, fence, false);
|
|
|
- if (r)
|
|
|
- goto out;
|
|
|
-
|
|
|
- if (updates && (!flushed || updates->context != flushed->context ||
|
|
|
- dma_fence_is_later(updates, flushed))) {
|
|
|
- dma_fence_put(id->flushed_updates);
|
|
|
- id->flushed_updates = dma_fence_get(updates);
|
|
|
- }
|
|
|
- id->pd_gpu_addr = job->vm_pd_addr;
|
|
|
- atomic64_set(&id->owner, vm->client_id);
|
|
|
- job->vm_needs_flush = needs_flush;
|
|
|
- if (needs_flush) {
|
|
|
- dma_fence_put(id->last_flush);
|
|
|
- id->last_flush = NULL;
|
|
|
- }
|
|
|
- job->vm_id = id - id_mgr->ids;
|
|
|
- trace_amdgpu_vm_grab_id(vm, ring, job);
|
|
|
-out:
|
|
|
- return r;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * amdgpu_vm_grab_id - allocate the next free VMID
|
|
|
- *
|
|
|
- * @vm: vm to allocate id for
|
|
|
- * @ring: ring we want to submit job to
|
|
|
- * @sync: sync object where we add dependencies
|
|
|
- * @fence: fence protecting ID from reuse
|
|
|
- *
|
|
|
- * Allocate an id for the vm, adding fences to the sync obj as necessary.
|
|
|
- */
|
|
|
-int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
|
|
|
- struct amdgpu_sync *sync, struct dma_fence *fence,
|
|
|
- struct amdgpu_job *job)
|
|
|
-{
|
|
|
- struct amdgpu_device *adev = ring->adev;
|
|
|
- unsigned vmhub = ring->funcs->vmhub;
|
|
|
- struct amdgpu_vm_id_manager *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
|
|
- uint64_t fence_context = adev->fence_context + ring->idx;
|
|
|
- struct dma_fence *updates = sync->last_vm_update;
|
|
|
- struct amdgpu_vm_id *id, *idle;
|
|
|
- struct dma_fence **fences;
|
|
|
- unsigned i;
|
|
|
- int r = 0;
|
|
|
-
|
|
|
- mutex_lock(&id_mgr->lock);
|
|
|
- if (amdgpu_vm_reserved_vmid_ready(vm, vmhub)) {
|
|
|
- r = amdgpu_vm_grab_reserved_vmid_locked(vm, ring, sync, fence, job);
|
|
|
- mutex_unlock(&id_mgr->lock);
|
|
|
- return r;
|
|
|
- }
|
|
|
- fences = kmalloc_array(sizeof(void *), id_mgr->num_ids, GFP_KERNEL);
|
|
|
- if (!fences) {
|
|
|
- mutex_unlock(&id_mgr->lock);
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
- /* Check if we have an idle VMID */
|
|
|
- i = 0;
|
|
|
- list_for_each_entry(idle, &id_mgr->ids_lru, list) {
|
|
|
- fences[i] = amdgpu_sync_peek_fence(&idle->active, ring);
|
|
|
- if (!fences[i])
|
|
|
- break;
|
|
|
- ++i;
|
|
|
- }
|
|
|
-
|
|
|
- /* If we can't find a idle VMID to use, wait till one becomes available */
|
|
|
- if (&idle->list == &id_mgr->ids_lru) {
|
|
|
- u64 fence_context = adev->vm_manager.fence_context + ring->idx;
|
|
|
- unsigned seqno = ++adev->vm_manager.seqno[ring->idx];
|
|
|
- struct dma_fence_array *array;
|
|
|
- unsigned j;
|
|
|
-
|
|
|
- for (j = 0; j < i; ++j)
|
|
|
- dma_fence_get(fences[j]);
|
|
|
-
|
|
|
- array = dma_fence_array_create(i, fences, fence_context,
|
|
|
- seqno, true);
|
|
|
- if (!array) {
|
|
|
- for (j = 0; j < i; ++j)
|
|
|
- dma_fence_put(fences[j]);
|
|
|
- kfree(fences);
|
|
|
- r = -ENOMEM;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- r = amdgpu_sync_fence(ring->adev, sync, &array->base, false);
|
|
|
- dma_fence_put(&array->base);
|
|
|
- if (r)
|
|
|
- goto error;
|
|
|
-
|
|
|
- mutex_unlock(&id_mgr->lock);
|
|
|
- return 0;
|
|
|
-
|
|
|
- }
|
|
|
- kfree(fences);
|
|
|
-
|
|
|
- job->vm_needs_flush = vm->use_cpu_for_update;
|
|
|
- /* Check if we can use a VMID already assigned to this VM */
|
|
|
- list_for_each_entry_reverse(id, &id_mgr->ids_lru, list) {
|
|
|
- struct dma_fence *flushed;
|
|
|
- bool needs_flush = vm->use_cpu_for_update;
|
|
|
-
|
|
|
- /* Check all the prerequisites to using this VMID */
|
|
|
- if (amdgpu_vm_had_gpu_reset(adev, id))
|
|
|
- continue;
|
|
|
-
|
|
|
- if (atomic64_read(&id->owner) != vm->client_id)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (job->vm_pd_addr != id->pd_gpu_addr)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (!id->last_flush ||
|
|
|
- (id->last_flush->context != fence_context &&
|
|
|
- !dma_fence_is_signaled(id->last_flush)))
|
|
|
- needs_flush = true;
|
|
|
-
|
|
|
- flushed = id->flushed_updates;
|
|
|
- if (updates && (!flushed || dma_fence_is_later(updates, flushed)))
|
|
|
- needs_flush = true;
|
|
|
-
|
|
|
- /* Concurrent flushes are only possible starting with Vega10 */
|
|
|
- if (adev->asic_type < CHIP_VEGA10 && needs_flush)
|
|
|
- continue;
|
|
|
-
|
|
|
- /* Good we can use this VMID. Remember this submission as
|
|
|
- * user of the VMID.
|
|
|
- */
|
|
|
- r = amdgpu_sync_fence(ring->adev, &id->active, fence, false);
|
|
|
- if (r)
|
|
|
- goto error;
|
|
|
-
|
|
|
- if (updates && (!flushed || dma_fence_is_later(updates, flushed))) {
|
|
|
- dma_fence_put(id->flushed_updates);
|
|
|
- id->flushed_updates = dma_fence_get(updates);
|
|
|
- }
|
|
|
-
|
|
|
- if (needs_flush)
|
|
|
- goto needs_flush;
|
|
|
- else
|
|
|
- goto no_flush_needed;
|
|
|
-
|
|
|
- };
|
|
|
-
|
|
|
- /* Still no ID to use? Then use the idle one found earlier */
|
|
|
- id = idle;
|
|
|
-
|
|
|
- /* Remember this submission as user of the VMID */
|
|
|
- r = amdgpu_sync_fence(ring->adev, &id->active, fence, false);
|
|
|
- if (r)
|
|
|
- goto error;
|
|
|
-
|
|
|
- id->pd_gpu_addr = job->vm_pd_addr;
|
|
|
- dma_fence_put(id->flushed_updates);
|
|
|
- id->flushed_updates = dma_fence_get(updates);
|
|
|
- atomic64_set(&id->owner, vm->client_id);
|
|
|
-
|
|
|
-needs_flush:
|
|
|
- job->vm_needs_flush = true;
|
|
|
- dma_fence_put(id->last_flush);
|
|
|
- id->last_flush = NULL;
|
|
|
-
|
|
|
-no_flush_needed:
|
|
|
- list_move_tail(&id->list, &id_mgr->ids_lru);
|
|
|
-
|
|
|
- job->vm_id = id - id_mgr->ids;
|
|
|
- trace_amdgpu_vm_grab_id(vm, ring, job);
|
|
|
-
|
|
|
-error:
|
|
|
- mutex_unlock(&id_mgr->lock);
|
|
|
- return r;
|
|
|
-}
|
|
|
-
|
|
|
-static void amdgpu_vm_free_reserved_vmid(struct amdgpu_device *adev,
|
|
|
- struct amdgpu_vm *vm,
|
|
|
- unsigned vmhub)
|
|
|
-{
|
|
|
- struct amdgpu_vm_id_manager *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
|
|
-
|
|
|
- mutex_lock(&id_mgr->lock);
|
|
|
- if (vm->reserved_vmid[vmhub]) {
|
|
|
- list_add(&vm->reserved_vmid[vmhub]->list,
|
|
|
- &id_mgr->ids_lru);
|
|
|
- vm->reserved_vmid[vmhub] = NULL;
|
|
|
- atomic_dec(&id_mgr->reserved_vmid_num);
|
|
|
- }
|
|
|
- mutex_unlock(&id_mgr->lock);
|
|
|
-}
|
|
|
-
|
|
|
-static int amdgpu_vm_alloc_reserved_vmid(struct amdgpu_device *adev,
|
|
|
- struct amdgpu_vm *vm,
|
|
|
- unsigned vmhub)
|
|
|
-{
|
|
|
- struct amdgpu_vm_id_manager *id_mgr;
|
|
|
- struct amdgpu_vm_id *idle;
|
|
|
- int r = 0;
|
|
|
-
|
|
|
- id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
|
|
- mutex_lock(&id_mgr->lock);
|
|
|
- if (vm->reserved_vmid[vmhub])
|
|
|
- goto unlock;
|
|
|
- if (atomic_inc_return(&id_mgr->reserved_vmid_num) >
|
|
|
- AMDGPU_VM_MAX_RESERVED_VMID) {
|
|
|
- DRM_ERROR("Over limitation of reserved vmid\n");
|
|
|
- atomic_dec(&id_mgr->reserved_vmid_num);
|
|
|
- r = -EINVAL;
|
|
|
- goto unlock;
|
|
|
- }
|
|
|
- /* Select the first entry VMID */
|
|
|
- idle = list_first_entry(&id_mgr->ids_lru, struct amdgpu_vm_id, list);
|
|
|
- list_del_init(&idle->list);
|
|
|
- vm->reserved_vmid[vmhub] = idle;
|
|
|
- mutex_unlock(&id_mgr->lock);
|
|
|
-
|
|
|
- return 0;
|
|
|
-unlock:
|
|
|
- mutex_unlock(&id_mgr->lock);
|
|
|
- return r;
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* amdgpu_vm_check_compute_bug - check whether asic has compute vm bug
|
|
|
*
|
|
@@ -767,14 +441,14 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring,
|
|
|
{
|
|
|
struct amdgpu_device *adev = ring->adev;
|
|
|
unsigned vmhub = ring->funcs->vmhub;
|
|
|
- struct amdgpu_vm_id_manager *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
|
|
- struct amdgpu_vm_id *id;
|
|
|
+ struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
|
|
+ struct amdgpu_vmid *id;
|
|
|
bool gds_switch_needed;
|
|
|
bool vm_flush_needed = job->vm_needs_flush || ring->has_compute_vm_bug;
|
|
|
|
|
|
- if (job->vm_id == 0)
|
|
|
+ if (job->vmid == 0)
|
|
|
return false;
|
|
|
- id = &id_mgr->ids[job->vm_id];
|
|
|
+ id = &id_mgr->ids[job->vmid];
|
|
|
gds_switch_needed = ring->funcs->emit_gds_switch && (
|
|
|
id->gds_base != job->gds_base ||
|
|
|
id->gds_size != job->gds_size ||
|
|
@@ -783,7 +457,7 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring,
|
|
|
id->oa_base != job->oa_base ||
|
|
|
id->oa_size != job->oa_size);
|
|
|
|
|
|
- if (amdgpu_vm_had_gpu_reset(adev, id))
|
|
|
+ if (amdgpu_vmid_had_gpu_reset(adev, id))
|
|
|
return true;
|
|
|
|
|
|
return vm_flush_needed || gds_switch_needed;
|
|
@@ -798,7 +472,7 @@ static bool amdgpu_vm_is_large_bar(struct amdgpu_device *adev)
|
|
|
* amdgpu_vm_flush - hardware flush the vm
|
|
|
*
|
|
|
* @ring: ring to use for flush
|
|
|
- * @vm_id: vmid number to use
|
|
|
+ * @vmid: vmid number to use
|
|
|
* @pd_addr: address of the page directory
|
|
|
*
|
|
|
* Emit a VM flush when it is necessary.
|
|
@@ -807,8 +481,8 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_
|
|
|
{
|
|
|
struct amdgpu_device *adev = ring->adev;
|
|
|
unsigned vmhub = ring->funcs->vmhub;
|
|
|
- struct amdgpu_vm_id_manager *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
|
|
- struct amdgpu_vm_id *id = &id_mgr->ids[job->vm_id];
|
|
|
+ struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
|
|
+ struct amdgpu_vmid *id = &id_mgr->ids[job->vmid];
|
|
|
bool gds_switch_needed = ring->funcs->emit_gds_switch && (
|
|
|
id->gds_base != job->gds_base ||
|
|
|
id->gds_size != job->gds_size ||
|
|
@@ -820,7 +494,7 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_
|
|
|
unsigned patch_offset = 0;
|
|
|
int r;
|
|
|
|
|
|
- if (amdgpu_vm_had_gpu_reset(adev, id)) {
|
|
|
+ if (amdgpu_vmid_had_gpu_reset(adev, id)) {
|
|
|
gds_switch_needed = true;
|
|
|
vm_flush_needed = true;
|
|
|
}
|
|
@@ -837,8 +511,8 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_
|
|
|
if (ring->funcs->emit_vm_flush && vm_flush_needed) {
|
|
|
struct dma_fence *fence;
|
|
|
|
|
|
- trace_amdgpu_vm_flush(ring, job->vm_id, job->vm_pd_addr);
|
|
|
- amdgpu_ring_emit_vm_flush(ring, job->vm_id, job->vm_pd_addr);
|
|
|
+ trace_amdgpu_vm_flush(ring, job->vmid, job->vm_pd_addr);
|
|
|
+ amdgpu_ring_emit_vm_flush(ring, job->vmid, job->vm_pd_addr);
|
|
|
|
|
|
r = amdgpu_fence_emit(ring, &fence);
|
|
|
if (r)
|
|
@@ -858,7 +532,7 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_
|
|
|
id->gws_size = job->gws_size;
|
|
|
id->oa_base = job->oa_base;
|
|
|
id->oa_size = job->oa_size;
|
|
|
- amdgpu_ring_emit_gds_switch(ring, job->vm_id, job->gds_base,
|
|
|
+ amdgpu_ring_emit_gds_switch(ring, job->vmid, job->gds_base,
|
|
|
job->gds_size, job->gws_base,
|
|
|
job->gws_size, job->oa_base,
|
|
|
job->oa_size);
|
|
@@ -875,49 +549,6 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * amdgpu_vm_reset_id - reset VMID to zero
|
|
|
- *
|
|
|
- * @adev: amdgpu device structure
|
|
|
- * @vm_id: vmid number to use
|
|
|
- *
|
|
|
- * Reset saved GDW, GWS and OA to force switch on next flush.
|
|
|
- */
|
|
|
-void amdgpu_vm_reset_id(struct amdgpu_device *adev, unsigned vmhub,
|
|
|
- unsigned vmid)
|
|
|
-{
|
|
|
- struct amdgpu_vm_id_manager *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
|
|
- struct amdgpu_vm_id *id = &id_mgr->ids[vmid];
|
|
|
-
|
|
|
- atomic64_set(&id->owner, 0);
|
|
|
- id->gds_base = 0;
|
|
|
- id->gds_size = 0;
|
|
|
- id->gws_base = 0;
|
|
|
- id->gws_size = 0;
|
|
|
- id->oa_base = 0;
|
|
|
- id->oa_size = 0;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * amdgpu_vm_reset_all_id - reset VMID to zero
|
|
|
- *
|
|
|
- * @adev: amdgpu device structure
|
|
|
- *
|
|
|
- * Reset VMID to force flush on next use
|
|
|
- */
|
|
|
-void amdgpu_vm_reset_all_ids(struct amdgpu_device *adev)
|
|
|
-{
|
|
|
- unsigned i, j;
|
|
|
-
|
|
|
- for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
|
|
|
- struct amdgpu_vm_id_manager *id_mgr =
|
|
|
- &adev->vm_manager.id_mgr[i];
|
|
|
-
|
|
|
- for (j = 1; j < id_mgr->num_ids; ++j)
|
|
|
- amdgpu_vm_reset_id(adev, i, j);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* amdgpu_vm_bo_find - find the bo_va for a specific vm & bo
|
|
|
*
|
|
@@ -1569,13 +1200,19 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
|
|
|
*
|
|
|
* The second command is for the shadow pagetables.
|
|
|
*/
|
|
|
- ncmds = ((nptes >> min(adev->vm_manager.block_size, 11u)) + 1) * 2;
|
|
|
+ if (vm->root.base.bo->shadow)
|
|
|
+ ncmds = ((nptes >> min(adev->vm_manager.block_size, 11u)) + 1) * 2;
|
|
|
+ else
|
|
|
+ ncmds = ((nptes >> min(adev->vm_manager.block_size, 11u)) + 1);
|
|
|
|
|
|
/* padding, etc. */
|
|
|
ndw = 64;
|
|
|
|
|
|
/* one PDE write for each huge page */
|
|
|
- ndw += ((nptes >> adev->vm_manager.block_size) + 1) * 6;
|
|
|
+ if (vm->root.base.bo->shadow)
|
|
|
+ ndw += ((nptes >> adev->vm_manager.block_size) + 1) * 6 * 2;
|
|
|
+ else
|
|
|
+ ndw += ((nptes >> adev->vm_manager.block_size) + 1) * 6;
|
|
|
|
|
|
if (pages_addr) {
|
|
|
/* copy commands needed */
|
|
@@ -2114,8 +1751,26 @@ struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
|
|
|
INIT_LIST_HEAD(&bo_va->valids);
|
|
|
INIT_LIST_HEAD(&bo_va->invalids);
|
|
|
|
|
|
- if (bo)
|
|
|
- list_add_tail(&bo_va->base.bo_list, &bo->va);
|
|
|
+ if (!bo)
|
|
|
+ return bo_va;
|
|
|
+
|
|
|
+ list_add_tail(&bo_va->base.bo_list, &bo->va);
|
|
|
+
|
|
|
+ if (bo->tbo.resv != vm->root.base.bo->tbo.resv)
|
|
|
+ return bo_va;
|
|
|
+
|
|
|
+ if (bo->preferred_domains &
|
|
|
+ amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type))
|
|
|
+ return bo_va;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We checked all the prerequisites, but it looks like this per VM BO
|
|
|
+ * is currently evicted. add the BO to the evicted list to make sure it
|
|
|
+ * is validated on next VM use to avoid fault.
|
|
|
+ * */
|
|
|
+ spin_lock(&vm->status_lock);
|
|
|
+ list_move_tail(&bo_va->base.vm_status, &vm->evicted);
|
|
|
+ spin_unlock(&vm->status_lock);
|
|
|
|
|
|
return bo_va;
|
|
|
}
|
|
@@ -2625,7 +2280,6 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
|
|
uint64_t init_pde_value = 0;
|
|
|
|
|
|
vm->va = RB_ROOT_CACHED;
|
|
|
- vm->client_id = atomic64_inc_return(&adev->vm_manager.client_counter);
|
|
|
for (i = 0; i < AMDGPU_MAX_VMHUBS; i++)
|
|
|
vm->reserved_vmid[i] = NULL;
|
|
|
spin_lock_init(&vm->status_lock);
|
|
@@ -2819,7 +2473,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
|
|
amdgpu_bo_unref(&root);
|
|
|
dma_fence_put(vm->last_update);
|
|
|
for (i = 0; i < AMDGPU_MAX_VMHUBS; i++)
|
|
|
- amdgpu_vm_free_reserved_vmid(adev, vm, i);
|
|
|
+ amdgpu_vmid_free_reserved(adev, vm, i);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -2861,23 +2515,9 @@ bool amdgpu_vm_pasid_fault_credit(struct amdgpu_device *adev,
|
|
|
*/
|
|
|
void amdgpu_vm_manager_init(struct amdgpu_device *adev)
|
|
|
{
|
|
|
- unsigned i, j;
|
|
|
-
|
|
|
- for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
|
|
|
- struct amdgpu_vm_id_manager *id_mgr =
|
|
|
- &adev->vm_manager.id_mgr[i];
|
|
|
+ unsigned i;
|
|
|
|
|
|
- mutex_init(&id_mgr->lock);
|
|
|
- INIT_LIST_HEAD(&id_mgr->ids_lru);
|
|
|
- atomic_set(&id_mgr->reserved_vmid_num, 0);
|
|
|
-
|
|
|
- /* skip over VMID 0, since it is the system VM */
|
|
|
- for (j = 1; j < id_mgr->num_ids; ++j) {
|
|
|
- amdgpu_vm_reset_id(adev, i, j);
|
|
|
- amdgpu_sync_create(&id_mgr->ids[i].active);
|
|
|
- list_add_tail(&id_mgr->ids[j].list, &id_mgr->ids_lru);
|
|
|
- }
|
|
|
- }
|
|
|
+ amdgpu_vmid_mgr_init(adev);
|
|
|
|
|
|
adev->vm_manager.fence_context =
|
|
|
dma_fence_context_alloc(AMDGPU_MAX_RINGS);
|
|
@@ -2885,7 +2525,6 @@ void amdgpu_vm_manager_init(struct amdgpu_device *adev)
|
|
|
adev->vm_manager.seqno[i] = 0;
|
|
|
|
|
|
atomic_set(&adev->vm_manager.vm_pte_next_ring, 0);
|
|
|
- atomic64_set(&adev->vm_manager.client_counter, 0);
|
|
|
spin_lock_init(&adev->vm_manager.prt_lock);
|
|
|
atomic_set(&adev->vm_manager.num_prt_users, 0);
|
|
|
|
|
@@ -2918,24 +2557,10 @@ void amdgpu_vm_manager_init(struct amdgpu_device *adev)
|
|
|
*/
|
|
|
void amdgpu_vm_manager_fini(struct amdgpu_device *adev)
|
|
|
{
|
|
|
- unsigned i, j;
|
|
|
-
|
|
|
WARN_ON(!idr_is_empty(&adev->vm_manager.pasid_idr));
|
|
|
idr_destroy(&adev->vm_manager.pasid_idr);
|
|
|
|
|
|
- for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
|
|
|
- struct amdgpu_vm_id_manager *id_mgr =
|
|
|
- &adev->vm_manager.id_mgr[i];
|
|
|
-
|
|
|
- mutex_destroy(&id_mgr->lock);
|
|
|
- for (j = 0; j < AMDGPU_NUM_VM; ++j) {
|
|
|
- struct amdgpu_vm_id *id = &id_mgr->ids[j];
|
|
|
-
|
|
|
- amdgpu_sync_free(&id->active);
|
|
|
- dma_fence_put(id->flushed_updates);
|
|
|
- dma_fence_put(id->last_flush);
|
|
|
- }
|
|
|
- }
|
|
|
+ amdgpu_vmid_mgr_fini(adev);
|
|
|
}
|
|
|
|
|
|
int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
|
@@ -2948,13 +2573,12 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
|
|
switch (args->in.op) {
|
|
|
case AMDGPU_VM_OP_RESERVE_VMID:
|
|
|
/* current, we only have requirement to reserve vmid from gfxhub */
|
|
|
- r = amdgpu_vm_alloc_reserved_vmid(adev, &fpriv->vm,
|
|
|
- AMDGPU_GFXHUB);
|
|
|
+ r = amdgpu_vmid_alloc_reserved(adev, &fpriv->vm, AMDGPU_GFXHUB);
|
|
|
if (r)
|
|
|
return r;
|
|
|
break;
|
|
|
case AMDGPU_VM_OP_UNRESERVE_VMID:
|
|
|
- amdgpu_vm_free_reserved_vmid(adev, &fpriv->vm, AMDGPU_GFXHUB);
|
|
|
+ amdgpu_vmid_free_reserved(adev, &fpriv->vm, AMDGPU_GFXHUB);
|
|
|
break;
|
|
|
default:
|
|
|
return -EINVAL;
|