// SPDX-License-Identifier: MIT
/*
* Copyright 2023 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 <linux/firmware.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <drm/drm_exec.h>
#include <drm/drm_drv.h>
#include "amdgpu.h"
#include "amdgpu_umsch_mm.h"
#include "umsch_mm_v4_0.h"
struct umsch_mm_test_ctx_data {
uint8_t process_csa[PAGE_SIZE];
uint8_t vpe_ctx_csa[PAGE_SIZE];
uint8_t vcn_ctx_csa[PAGE_SIZE];
};
struct umsch_mm_test_mqd_data {
uint8_t vpe_mqd[PAGE_SIZE];
uint8_t vcn_mqd[PAGE_SIZE];
};
struct umsch_mm_test_ring_data {
uint8_t vpe_ring[PAGE_SIZE];
uint8_t vpe_ib[PAGE_SIZE];
uint8_t vcn_ring[PAGE_SIZE];
uint8_t vcn_ib[PAGE_SIZE];
};
struct umsch_mm_test_queue_info {
uint64_t mqd_addr;
uint64_t csa_addr;
uint32_t doorbell_offset_0;
uint32_t doorbell_offset_1;
enum UMSCH_SWIP_ENGINE_TYPE engine;
};
struct umsch_mm_test {
struct amdgpu_bo *ctx_data_obj;
uint64_t ctx_data_gpu_addr;
uint32_t *ctx_data_cpu_addr;
struct amdgpu_bo *mqd_data_obj;
uint64_t mqd_data_gpu_addr;
uint32_t *mqd_data_cpu_addr;
struct amdgpu_bo *ring_data_obj;
uint64_t ring_data_gpu_addr;
uint32_t *ring_data_cpu_addr;
struct amdgpu_vm *vm;
struct amdgpu_bo_va *bo_va;
uint32_t pasid;
uint32_t vm_cntx_cntl;
uint32_t num_queues;
};
static int map_ring_data(struct amdgpu_device *adev, struct amdgpu_vm *vm,
struct amdgpu_bo *bo, struct amdgpu_bo_va **bo_va,
uint64_t addr, uint32_t size)
{
struct amdgpu_sync sync;
struct drm_exec exec;
int r;
amdgpu_sync_create(&sync);
drm_exec_init(&exec, 0, 0);
drm_exec_until_all_locked(&exec) {
r = drm_exec_lock_obj(&exec, &bo->tbo.base);
drm_exec_retry_on_contention(&exec);
if (unlikely(r))
goto error_fini_exec;
r = amdgpu_vm_lock_pd(vm, &exec, 0);
drm_exec_retry_on_contention(&exec);
if (unlikely(r))
goto error_fini_exec;
}
*bo_va = amdgpu_vm_bo_add(adev, vm, bo);
if (!*bo_va) {
r = -ENOMEM;
goto error_fini_exec;
}
r = amdgpu_vm_bo_map(adev, *bo_va, addr, 0, size,
AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE |
AMDGPU_PTE_EXECUTABLE);
if (r)
goto error_del_bo_va;
r = amdgpu_vm_bo_update(adev, *bo_va, false);
if (r)
goto error_del_bo_va;
amdgpu_sync_fence(&sync, (*bo_va)->last_pt_update);
r = amdgpu_vm_update_pdes(adev, vm, false);
if (r)
goto error_del_bo_va;
amdgpu_sync_fence(&sync, vm->last_update);
amdgpu_sync_wait(&sync, false);
drm_exec_fini(&exec);
amdgpu_sync_free(&sync);
return 0;
error_del_bo_va:
amdgpu_vm_bo_del(adev, *bo_va);
amdgpu_sync_free(&sync);
error_fini_exec:
drm_exec_fini(&exec);
amdgpu_sync_free(&sync);
return r;
}
static int unmap_ring_data(struct amdgpu_device *adev, struct amdgpu_vm *vm,
struct amdgpu_bo *bo, struct amdgpu_bo_va *bo_va,
uint64_t addr)
{
struct drm_exec exec;
long r;
drm_exec_init(&exec, 0, 0);
drm_exec_until_all_locked(&exec) {
r = drm_exec_lock_obj(&exec, &bo->tbo.base);
drm_exec_retry_on_contention(&exec);
if (unlikely(r))
goto out_unlock;
r = amdgpu_vm_lock_pd(vm, &exec, 0);
drm_exec_retry_on_contention(&exec);
if (unlikely(r))
goto out_unlock;
}
r = amdgpu_vm_bo_unmap(adev, bo_va, addr);
if (r)
goto out_unlock;
amdgpu_vm_bo_del(adev, bo_va);
out_unlock:
drm_exec_fini(&exec);
return r;
}
static void setup_vpe_queue(struct amdgpu_device *adev,
struct umsch_mm_test *test,
struct umsch_mm_test_queue_info *qinfo)
{
struct MQD_INFO *mqd = (struct MQD_INFO *)test->mqd_data_cpu_addr;
uint64_t ring_gpu_addr = test->ring_data_gpu_addr;
mqd->rb_base_lo = (ring_gpu_addr >> 8);
mqd->rb_base_hi = (ring_gpu_addr >> 40);
mqd->rb_size = PAGE_SIZE / 4;
mqd->wptr_val = 0;
mqd->rptr_val = 0;
mqd->unmapped = 1;
if (adev->vpe.collaborate_mode)
memcpy(++mqd, test->mqd_data_cpu_addr, sizeof(struct MQD_INFO));
qinfo->mqd_addr = test->mqd_data_gpu_addr;
q