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

Reply via email to