forked from Minki/linux
drm/amdgpu: separate VMID and PASID handling
Move both into the new files amdgpu_ids.[ch]. No functional change. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
df2869abd9
commit
620f774f46
@ -52,7 +52,8 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
|
||||
amdgpu_prime.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \
|
||||
amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \
|
||||
amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o amdgpu_atomfirmware.o \
|
||||
amdgpu_queue_mgr.o amdgpu_vf_error.o amdgpu_sched.o amdgpu_debugfs.o
|
||||
amdgpu_queue_mgr.o amdgpu_vf_error.o amdgpu_sched.o amdgpu_debugfs.o \
|
||||
amdgpu_ids.o
|
||||
|
||||
# add asic specific block
|
||||
amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
|
||||
|
@ -169,8 +169,8 @@ static const struct kfd2kgd_calls kfd2kgd = {
|
||||
.get_vmem_size = get_vmem_size,
|
||||
.get_gpu_clock_counter = get_gpu_clock_counter,
|
||||
.get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
|
||||
.alloc_pasid = amdgpu_vm_alloc_pasid,
|
||||
.free_pasid = amdgpu_vm_free_pasid,
|
||||
.alloc_pasid = amdgpu_pasid_alloc,
|
||||
.free_pasid = amdgpu_pasid_free,
|
||||
.program_sh_mem_settings = kgd_program_sh_mem_settings,
|
||||
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
|
||||
.init_pipeline = kgd_init_pipeline,
|
||||
|
@ -128,8 +128,8 @@ static const struct kfd2kgd_calls kfd2kgd = {
|
||||
.get_vmem_size = get_vmem_size,
|
||||
.get_gpu_clock_counter = get_gpu_clock_counter,
|
||||
.get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
|
||||
.alloc_pasid = amdgpu_vm_alloc_pasid,
|
||||
.free_pasid = amdgpu_vm_free_pasid,
|
||||
.alloc_pasid = amdgpu_pasid_alloc,
|
||||
.free_pasid = amdgpu_pasid_free,
|
||||
.program_sh_mem_settings = kgd_program_sh_mem_settings,
|
||||
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
|
||||
.init_pipeline = kgd_init_pipeline,
|
||||
|
@ -230,8 +230,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
|
||||
if (r) {
|
||||
dev_err(adev->dev, "failed to emit fence (%d)\n", r);
|
||||
if (job && job->vm_id)
|
||||
amdgpu_vm_reset_id(adev, ring->funcs->vmhub,
|
||||
job->vm_id);
|
||||
amdgpu_vmid_reset(adev, ring->funcs->vmhub, job->vm_id);
|
||||
amdgpu_ring_undo(ring);
|
||||
return r;
|
||||
}
|
||||
|
459
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
Normal file
459
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
Normal file
@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Copyright 2017 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include "amdgpu_ids.h"
|
||||
|
||||
#include <linux/idr.h>
|
||||
#include <linux/dma-fence-array.h>
|
||||
#include <drm/drmP.h>
|
||||
|
||||
#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_pasid_ida);
|
||||
|
||||
/**
|
||||
* amdgpu_pasid_alloc - 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_pasid_alloc(unsigned int bits)
|
||||
{
|
||||
int pasid = -EINVAL;
|
||||
|
||||
for (bits = min(bits, 31U); bits > 0; bits--) {
|
||||
pasid = ida_simple_get(&amdgpu_pasid_ida,
|
||||
1U << (bits - 1), 1U << bits,
|
||||
GFP_KERNEL);
|
||||
if (pasid != -ENOSPC)
|
||||
break;
|
||||
}
|
||||
|
||||
return pasid;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_pasid_free - Free a PASID
|
||||
* @pasid: PASID to free
|
||||
*/
|
||||
void amdgpu_pasid_free(unsigned int pasid)
|
||||
{
|
||||
ida_simple_remove(&amdgpu_pasid_ida, pasid);
|
||||
}
|
||||
|
||||
/*
|
||||
* VMID manager
|
||||
*
|
||||
* VMIDs are a per VMHUB identifier for page tables handling.
|
||||
*/
|
||||
|
||||
/**
|
||||
* amdgpu_vmid_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.
|
||||
*/
|
||||
bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
|
||||
struct amdgpu_vmid *id)
|
||||
{
|
||||
return id->current_gpu_reset_count !=
|
||||
atomic_read(&adev->gpu_reset_counter);
|
||||
}
|
||||
|
||||
/* idr_mgr->lock must be held */
|
||||
static int amdgpu_vmid_grab_reserved_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_vmid *id = vm->reserved_vmid[vmhub];
|
||||
struct amdgpu_vmid_mgr *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_vmid_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_vmid_grab(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_vmid_mgr *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_vmid *id, *idle;
|
||||
struct dma_fence **fences;
|
||||
unsigned i;
|
||||
int r = 0;
|
||||
|
||||
mutex_lock(&id_mgr->lock);
|
||||
if (vm->reserved_vmid[vmhub]) {
|
||||
r = amdgpu_vmid_grab_reserved_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_vmid_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;
|
||||
}
|
||||
|
||||
int amdgpu_vmid_alloc_reserved(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
unsigned vmhub)
|
||||
{
|
||||
struct amdgpu_vmid_mgr *id_mgr;
|
||||
struct amdgpu_vmid *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_vmid, 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;
|
||||
}
|
||||
|
||||
void amdgpu_vmid_free_reserved(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
unsigned vmhub)
|
||||
{
|
||||
struct amdgpu_vmid_mgr *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);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vmid_reset - 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_vmid_reset(struct amdgpu_device *adev, unsigned vmhub,
|
||||
unsigned vmid)
|
||||
{
|
||||
struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
||||
struct amdgpu_vmid *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_vmid_reset_all - reset VMID to zero
|
||||
*
|
||||
* @adev: amdgpu device structure
|
||||
*
|
||||
* Reset VMID to force flush on next use
|
||||
*/
|
||||
void amdgpu_vmid_reset_all(struct amdgpu_device *adev)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
|
||||
struct amdgpu_vmid_mgr *id_mgr =
|
||||
&adev->vm_manager.id_mgr[i];
|
||||
|
||||
for (j = 1; j < id_mgr->num_ids; ++j)
|
||||
amdgpu_vmid_reset(adev, i, j);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vmid_mgr_init - init the VMID manager
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Initialize the VM manager structures
|
||||
*/
|
||||
void amdgpu_vmid_mgr_init(struct amdgpu_device *adev)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
|
||||
struct amdgpu_vmid_mgr *id_mgr =
|
||||
&adev->vm_manager.id_mgr[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_vmid_reset(adev, i, j);
|
||||
amdgpu_sync_create(&id_mgr->ids[i].active);
|
||||
list_add_tail(&id_mgr->ids[j].list, &id_mgr->ids_lru);
|
||||
}
|
||||
}
|
||||
|
||||
adev->vm_manager.fence_context =
|
||||
dma_fence_context_alloc(AMDGPU_MAX_RINGS);
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
|
||||
adev->vm_manager.seqno[i] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vmid_mgr_fini - cleanup VM manager
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Cleanup the VM manager and free resources.
|
||||
*/
|
||||
void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
|
||||
struct amdgpu_vmid_mgr *id_mgr =
|
||||
&adev->vm_manager.id_mgr[i];
|
||||
|
||||
mutex_destroy(&id_mgr->lock);
|
||||
for (j = 0; j < AMDGPU_NUM_VMID; ++j) {
|
||||
struct amdgpu_vmid *id = &id_mgr->ids[j];
|
||||
|
||||
amdgpu_sync_free(&id->active);
|
||||
dma_fence_put(id->flushed_updates);
|
||||
dma_fence_put(id->last_flush);
|
||||
}
|
||||
}
|
||||
}
|
91
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
Normal file
91
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2017 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef __AMDGPU_IDS_H__
|
||||
#define __AMDGPU_IDS_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/dma-fence.h>
|
||||
|
||||
#include "amdgpu_sync.h"
|
||||
|
||||
/* maximum number of VMIDs */
|
||||
#define AMDGPU_NUM_VMID 16
|
||||
|
||||
struct amdgpu_device;
|
||||
struct amdgpu_vm;
|
||||
struct amdgpu_ring;
|
||||
struct amdgpu_sync;
|
||||
struct amdgpu_job;
|
||||
|
||||
struct amdgpu_vmid {
|
||||
struct list_head list;
|
||||
struct amdgpu_sync active;
|
||||
struct dma_fence *last_flush;
|
||||
atomic64_t owner;
|
||||
|
||||
uint64_t pd_gpu_addr;
|
||||
/* last flushed PD/PT update */
|
||||
struct dma_fence *flushed_updates;
|
||||
|
||||
uint32_t current_gpu_reset_count;
|
||||
|
||||
uint32_t gds_base;
|
||||
uint32_t gds_size;
|
||||
uint32_t gws_base;
|
||||
uint32_t gws_size;
|
||||
uint32_t oa_base;
|
||||
uint32_t oa_size;
|
||||
};
|
||||
|
||||
struct amdgpu_vmid_mgr {
|
||||
struct mutex lock;
|
||||
unsigned num_ids;
|
||||
struct list_head ids_lru;
|
||||
struct amdgpu_vmid ids[AMDGPU_NUM_VMID];
|
||||
atomic_t reserved_vmid_num;
|
||||
};
|
||||
|
||||
int amdgpu_pasid_alloc(unsigned int bits);
|
||||
void amdgpu_pasid_free(unsigned int pasid);
|
||||
|
||||
bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
|
||||
struct amdgpu_vmid *id);
|
||||
int amdgpu_vmid_alloc_reserved(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
unsigned vmhub);
|
||||
void amdgpu_vmid_free_reserved(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
unsigned vmhub);
|
||||
int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
|
||||
struct amdgpu_sync *sync, struct dma_fence *fence,
|
||||
struct amdgpu_job *job);
|
||||
void amdgpu_vmid_reset(struct amdgpu_device *adev, unsigned vmhub,
|
||||
unsigned vmid);
|
||||
void amdgpu_vmid_reset_all(struct amdgpu_device *adev);
|
||||
|
||||
void amdgpu_vmid_mgr_init(struct amdgpu_device *adev);
|
||||
void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev);
|
||||
|
||||
#endif
|
@ -161,9 +161,9 @@ static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job,
|
||||
while (fence == NULL && vm && !job->vm_id) {
|
||||
struct amdgpu_ring *ring = job->ring;
|
||||
|
||||
r = amdgpu_vm_grab_id(vm, ring, &job->sync,
|
||||
&job->base.s_fence->finished,
|
||||
job);
|
||||
r = amdgpu_vmid_grab(vm, ring, &job->sync,
|
||||
&job->base.s_fence->finished,
|
||||
job);
|
||||
if (r)
|
||||
DRM_ERROR("Error getting VM ID (%d)\n", r);
|
||||
|
||||
|
@ -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,8 +441,8 @@ 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;
|
||||
|
||||
@ -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;
|
||||
@ -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->vm_id];
|
||||
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;
|
||||
}
|
||||
@ -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
|
||||
*
|
||||
@ -2819,7 +2450,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 +2492,9 @@ bool amdgpu_vm_pasid_fault_credit(struct amdgpu_device *adev,
|
||||
*/
|
||||
void amdgpu_vm_manager_init(struct amdgpu_device *adev)
|
||||
{
|
||||
unsigned i, j;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
|
||||
struct amdgpu_vm_id_manager *id_mgr =
|
||||
&adev->vm_manager.id_mgr[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);
|
||||
@ -2918,24 +2535,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 +2551,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;
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include "amdgpu_sync.h"
|
||||
#include "amdgpu_ring.h"
|
||||
#include "amdgpu_ids.h"
|
||||
|
||||
struct amdgpu_bo_va;
|
||||
struct amdgpu_job;
|
||||
@ -40,9 +41,6 @@ struct amdgpu_bo_list_entry;
|
||||
* GPUVM handling
|
||||
*/
|
||||
|
||||
/* maximum number of VMIDs */
|
||||
#define AMDGPU_NUM_VM 16
|
||||
|
||||
/* Maximum number of PTEs the hardware can write with one command */
|
||||
#define AMDGPU_VM_MAX_UPDATE_SIZE 0x3FFFF
|
||||
|
||||
@ -197,7 +195,7 @@ struct amdgpu_vm {
|
||||
u64 client_id;
|
||||
unsigned int pasid;
|
||||
/* dedicated to vm */
|
||||
struct amdgpu_vm_id *reserved_vmid[AMDGPU_MAX_VMHUBS];
|
||||
struct amdgpu_vmid *reserved_vmid[AMDGPU_MAX_VMHUBS];
|
||||
|
||||
/* Flag to indicate if VM tables are updated by CPU or GPU (SDMA) */
|
||||
bool use_cpu_for_update;
|
||||
@ -212,37 +210,9 @@ struct amdgpu_vm {
|
||||
unsigned int fault_credit;
|
||||
};
|
||||
|
||||
struct amdgpu_vm_id {
|
||||
struct list_head list;
|
||||
struct amdgpu_sync active;
|
||||
struct dma_fence *last_flush;
|
||||
atomic64_t owner;
|
||||
|
||||
uint64_t pd_gpu_addr;
|
||||
/* last flushed PD/PT update */
|
||||
struct dma_fence *flushed_updates;
|
||||
|
||||
uint32_t current_gpu_reset_count;
|
||||
|
||||
uint32_t gds_base;
|
||||
uint32_t gds_size;
|
||||
uint32_t gws_base;
|
||||
uint32_t gws_size;
|
||||
uint32_t oa_base;
|
||||
uint32_t oa_size;
|
||||
};
|
||||
|
||||
struct amdgpu_vm_id_manager {
|
||||
struct mutex lock;
|
||||
unsigned num_ids;
|
||||
struct list_head ids_lru;
|
||||
struct amdgpu_vm_id ids[AMDGPU_NUM_VM];
|
||||
atomic_t reserved_vmid_num;
|
||||
};
|
||||
|
||||
struct amdgpu_vm_manager {
|
||||
/* Handling of VMIDs */
|
||||
struct amdgpu_vm_id_manager id_mgr[AMDGPU_MAX_VMHUBS];
|
||||
struct amdgpu_vmid_mgr id_mgr[AMDGPU_MAX_VMHUBS];
|
||||
|
||||
/* Handling of VM fences */
|
||||
u64 fence_context;
|
||||
@ -280,8 +250,6 @@ struct amdgpu_vm_manager {
|
||||
spinlock_t pasid_lock;
|
||||
};
|
||||
|
||||
int amdgpu_vm_alloc_pasid(unsigned int bits);
|
||||
void amdgpu_vm_free_pasid(unsigned int pasid);
|
||||
void amdgpu_vm_manager_init(struct amdgpu_device *adev);
|
||||
void amdgpu_vm_manager_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
||||
@ -299,13 +267,7 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
||||
int amdgpu_vm_alloc_pts(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
uint64_t saddr, uint64_t size);
|
||||
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);
|
||||
int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_pipe_sync);
|
||||
void amdgpu_vm_reset_id(struct amdgpu_device *adev, unsigned vmhub,
|
||||
unsigned vmid);
|
||||
void amdgpu_vm_reset_all_ids(struct amdgpu_device *adev);
|
||||
int amdgpu_vm_update_directories(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm);
|
||||
int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
|
||||
|
@ -956,7 +956,7 @@ static int gmc_v6_0_resume(void *handle)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_vm_reset_all_ids(adev);
|
||||
amdgpu_vmid_reset_all(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1107,7 +1107,7 @@ static int gmc_v7_0_resume(void *handle)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_vm_reset_all_ids(adev);
|
||||
amdgpu_vmid_reset_all(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1212,7 +1212,7 @@ static int gmc_v8_0_resume(void *handle)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_vm_reset_all_ids(adev);
|
||||
amdgpu_vmid_reset_all(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1056,7 +1056,7 @@ static int gmc_v9_0_resume(void *handle)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_vm_reset_all_ids(adev);
|
||||
amdgpu_vmid_reset_all(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user