UMSCH supports context suspend and resume whenever buffer
evection and restore is initiated.
Using new function format due to api change (David)
V2 - remove powergating call as it is not needed for resume
use drv_err() instead of DRM_ERROR()
Signed-off-by: Saleemkhan Jamadar <[email protected]>
Signed-off-by: David (Ming Qiang) Wu <[email protected]>
Acked-by: Alex Deucher <[email protected]>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c | 52 +++++++++++++++
drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.h | 24 +++++++
drivers/gpu/drm/amd/amdgpu/umsch_mm_v4_0.c | 66 ++++++++++++++++++++
3 files changed, 142 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c
b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c
index 5a9589b56534..20e9b81fbe06 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c
@@ -656,6 +656,56 @@ static void amdgpu_umsch_destroy_queue(struct
amdgpu_usermode_queue *queue)
mutex_unlock(&umsch->mutex_hidden);
}
+static int amdgpu_umsch_queue_preempt(struct amdgpu_usermode_queue *queue)
+{
+ struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
+ struct amdgpu_device *adev = uq_mgr->adev;
+ struct amdgpu_umsch_mm *umsch = &adev->umsch_mm;
+ struct amdgpu_userq_obj *ctx = &queue->fw_obj;
+ struct amdgpu_userq_obj *sfence = &queue->suspend_fence_obj;
+ struct umsch_suspend args;
+ int r;
+
+ memset(&args, 0, sizeof(struct umsch_suspend));
+ args.context_csa_addr = ctx->gpu_addr + PAGE_SIZE;
+ args.suspend_fence_addr = sfence->gpu_addr;
+ args.suspend_fence_value = umsch->ring.fence_drv.sync_seq + 1;
+
+ amdgpu_umsch_mm_lock(&adev->umsch_mm);
+ r = umsch->funcs->suspend_queue_ctx(umsch, &args);
+ amdgpu_umsch_mm_unlock(&adev->umsch_mm);
+ if (r)
+ dev_err(adev->dev, "Failed to suspend queue for IP %d err
%d.\n",
+ queue->queue_type, r);
+
+ return r;
+}
+
+static int amdgpu_umsch_queue_restore(struct amdgpu_usermode_queue *queue)
+{
+ struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
+ struct amdgpu_device *adev = uq_mgr->adev;
+ struct amdgpu_umsch_mm *umsch = &adev->umsch_mm;
+ struct amdgpu_userq_obj *ctx = &queue->fw_obj;
+ struct umsch_resume args;
+ int r;
+
+ memset(&args, 0, sizeof(struct umsch_resume));
+ args.context_csa_addr = ctx->gpu_addr + PAGE_SIZE;
+ if (queue->queue_type == AMDGPU_HW_IP_VCN_ENC)
+ args.engine_type = UMSCH_SWIP_ENGINE_TYPE_VCN;
+
+ args.resume_option = RESUME_CONTEXT;
+ amdgpu_umsch_mm_lock(&adev->umsch_mm);
+ r = umsch->funcs->resume_queue_ctx(umsch, &args);
+ amdgpu_umsch_mm_unlock(&adev->umsch_mm);
+ if (r)
+ dev_err(adev->dev, "Failed to resume queue for IP %d err %d.\n",
+ queue->queue_type, r);
+
+ return r;
+}
+
void amdgpu_umsch_fwlog_init(struct amdgpu_umsch_mm *umsch_mm)
{
#if defined(CONFIG_DEBUG_FS)
@@ -781,4 +831,6 @@ const struct amdgpu_userq_funcs userq_umsch_4_0_funcs = {
.mqd_destroy = amdgpu_umsch_destroy_queue,
.map = amdgpu_umsch_userq_map,
.unmap = amdgpu_umsch_userq_unmap,
+ .preempt = amdgpu_umsch_queue_preempt,
+ .restore = amdgpu_umsch_queue_restore,
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.h
b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.h
index 6b827c92e817..cbe1ec7363a3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.h
@@ -41,6 +41,11 @@ enum UMSCH_CONTEXT_PRIORITY_LEVEL {
CONTEXT_PRIORITY_NUM_LEVELS
};
+enum UMSCH_RESUME_OPTIONS {
+ RESUME_CONTEXT = 0,
+ RESUME_ENGINE_SCHEDULE = 1,
+};
+
struct umsch_mm_set_resource_input {
uint32_t vmid_mask_mm_vcn;
uint32_t vmid_mask_mm_vpe;
@@ -117,6 +122,20 @@ struct MQD_INFO {
uint32_t vmid;
};
+struct umsch_suspend {
+ uint64_t context_csa_addr;
+ uint64_t suspend_fence_addr;
+ uint32_t suspend_fence_value;
+ uint32_t context_csa_array_index;
+};
+
+struct umsch_resume {
+ enum UMSCH_RESUME_OPTIONS resume_option;
+ uint64_t context_csa_addr;
+ enum UMSCH_SWIP_ENGINE_TYPE engine_type;
+ uint32_t context_csa_array_index;
+};
+
struct amdgpu_umsch_mm;
struct umsch_mm_funcs {
@@ -132,6 +151,11 @@ struct umsch_mm_funcs {
int (*ring_start)(struct amdgpu_umsch_mm *umsch);
int (*ring_stop)(struct amdgpu_umsch_mm *umsch);
int (*ring_fini)(struct amdgpu_umsch_mm *umsch);
+ int (*suspend_queue_ctx)(struct amdgpu_umsch_mm *umsch,
+ struct umsch_suspend *input);
+ int (*resume_queue_ctx)(struct amdgpu_umsch_mm *umsch,
+ struct umsch_resume *input);
+
};
struct amdgpu_umsch_mm {
diff --git a/drivers/gpu/drm/amd/amdgpu/umsch_mm_v4_0.c
b/drivers/gpu/drm/amd/amdgpu/umsch_mm_v4_0.c
index 60d1fdfb2af5..c1e47ea8e82a 100644
--- a/drivers/gpu/drm/amd/amdgpu/umsch_mm_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/umsch_mm_v4_0.c
@@ -411,6 +411,70 @@ static int umsch_mm_v4_0_remove_queue(struct
amdgpu_umsch_mm *umsch,
return 0;
}
+static int umsch_mm_v4_0_suspend_context(struct amdgpu_umsch_mm *umsch,
+ struct umsch_suspend *input_ptr)
+{
+ union UMSCHAPI__SUSPEND suspend = { 0 };
+ struct amdgpu_device *adev = umsch->ring.adev;
+ int r;
+
+ suspend.header.type = UMSCH_API_TYPE_SCHEDULER;
+ suspend.header.opcode = UMSCH_API_SUSPEND;
+ suspend.header.dwsize = API_FRAME_SIZE_IN_DWORDS;
+
+ suspend.context_csa_addr = input_ptr->context_csa_addr;
+ suspend.suspend_fence_addr = input_ptr->suspend_fence_addr;
+ suspend.suspend_fence_value = input_ptr->suspend_fence_value;
+
+ suspend.api_status.api_completion_fence_addr =
umsch->ring.fence_drv.gpu_addr;
+ suspend.api_status.api_completion_fence_value =
++umsch->ring.fence_drv.sync_seq;
+
+ r = amdgpu_umsch_mm_submit_pkt(umsch, &suspend.max_dwords_in_api,
+ API_FRAME_SIZE_IN_DWORDS);
+ if (r)
+ return r;
+
+ r = amdgpu_umsch_mm_query_fence(umsch);
+ if (r) {
+ dev_err(adev->dev, "UMSCH suspend queue: Failed ret %d\n", r);
+ return r;
+ }
+
+ return r;
+}
+
+static int umsch_mm_v4_0_resume_context(struct amdgpu_umsch_mm *umsch,
+ struct umsch_resume *input_ptr)
+{
+ union UMSCHAPI__RESUME resume = { 0 };
+ struct amdgpu_device *adev = umsch->ring.adev;
+ int r;
+
+ resume.header.type = UMSCH_API_TYPE_SCHEDULER;
+ resume.header.opcode = UMSCH_API_RESUME;
+ resume.header.dwsize = API_FRAME_SIZE_IN_DWORDS;
+
+ resume.resume_option = (enum
UMSCH_RESUME_OPTION)input_ptr->resume_option;
+ resume.context_csa_addr = input_ptr->context_csa_addr;
+ resume.engine_type = (enum UMSCH_ENGINE_TYPE)input_ptr->engine_type;
+
+ resume.api_status.api_completion_fence_addr =
umsch->ring.fence_drv.gpu_addr;
+ resume.api_status.api_completion_fence_value =
++umsch->ring.fence_drv.sync_seq;
+
+ r = amdgpu_umsch_mm_submit_pkt(umsch, &resume.max_dwords_in_api,
+ API_FRAME_SIZE_IN_DWORDS);
+ if (r)
+ return r;
+
+ r = amdgpu_umsch_mm_query_fence(umsch);
+ if (r) {
+ dev_err(adev->dev, "UMSCH resume queue: Failed ret %d\n", r);
+ return r;
+ }
+
+ return r;
+}
+
static int umsch_mm_v4_0_set_regs(struct amdgpu_umsch_mm *umsch)
{
struct amdgpu_device *adev = container_of(umsch, struct amdgpu_device,
umsch_mm);
@@ -431,6 +495,8 @@ static const struct umsch_mm_funcs umsch_mm_v4_0_funcs = {
.ring_init = amdgpu_umsch_mm_ring_init,
.ring_start = umsch_mm_v4_0_ring_start,
.ring_stop = umsch_mm_v4_0_ring_stop,
+ .suspend_queue_ctx = umsch_mm_v4_0_suspend_context,
+ .resume_queue_ctx = umsch_mm_v4_0_resume_context,
};
void umsch_mm_v4_0_set_funcs(struct amdgpu_umsch_mm *umsch)
--
2.43.0