summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c97
1 files changed, 74 insertions, 23 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
index 0d4c77c1b4b5..e3972673fd64 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
@@ -103,7 +103,7 @@ static inline u32 amdgpu_mes_get_hqd_mask(u32 num_pipe,
int amdgpu_mes_init(struct amdgpu_device *adev)
{
- int i, r, num_pipes;
+ int i, r, num_pipes, num_queues = 0;
u32 total_vmid_mask, reserved_vmid_mask;
int num_xcc = adev->gfx.xcc_mask ? NUM_XCC(adev->gfx.xcc_mask) : 1;
u32 gfx_hqd_mask = amdgpu_mes_get_hqd_mask(adev->gfx.me.num_pipe_per_me,
@@ -159,7 +159,8 @@ int amdgpu_mes_init(struct amdgpu_device *adev)
adev->mes.compute_hqd_mask[i] = compute_hqd_mask;
}
- num_pipes = adev->sdma.num_instances;
+ num_pipes = adev->sdma.num_inst_per_xcc ?
+ adev->sdma.num_inst_per_xcc : adev->sdma.num_instances;
if (num_pipes > AMDGPU_MES_MAX_SDMA_PIPES)
dev_warn(adev->dev, "more SDMA pipes than supported by MES! (%d vs %d)\n",
num_pipes, AMDGPU_MES_MAX_SDMA_PIPES);
@@ -216,8 +217,27 @@ int amdgpu_mes_init(struct amdgpu_device *adev)
if (r)
goto error_doorbell;
+ if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(12, 1, 0)) {
+ /* When queue/pipe reset is done in MES instead of in the
+ * driver, MES passes hung queues information to the driver in
+ * hung_queue_hqd_info. Calculate required space to store this
+ * information.
+ */
+ for (i = 0; i < AMDGPU_MES_MAX_GFX_PIPES; i++)
+ num_queues += hweight32(adev->mes.gfx_hqd_mask[i]);
+
+ for (i = 0; i < AMDGPU_MES_MAX_COMPUTE_PIPES; i++)
+ num_queues += hweight32(adev->mes.compute_hqd_mask[i]);
+
+ for (i = 0; i < AMDGPU_MES_MAX_SDMA_PIPES; i++)
+ num_queues += hweight32(adev->mes.sdma_hqd_mask[i]) * num_xcc;
+
+ adev->mes.hung_queue_hqd_info_offset = num_queues;
+ adev->mes.hung_queue_db_array_size = num_queues * 2;
+ }
+
if (adev->mes.hung_queue_db_array_size) {
- for (i = 0; i < AMDGPU_MAX_MES_PIPES * num_xcc; i++) {
+ for (i = 0; i < AMDGPU_MAX_MES_PIPES; i++) {
r = amdgpu_bo_create_kernel(adev,
adev->mes.hung_queue_db_array_size * sizeof(u32),
PAGE_SIZE,
@@ -264,10 +284,10 @@ void amdgpu_mes_fini(struct amdgpu_device *adev)
&adev->mes.event_log_cpu_addr);
for (i = 0; i < AMDGPU_MAX_MES_PIPES * num_xcc; i++) {
- amdgpu_bo_free_kernel(&adev->mes.hung_queue_db_array_gpu_obj[i],
- &adev->mes.hung_queue_db_array_gpu_addr[i],
- &adev->mes.hung_queue_db_array_cpu_addr[i]);
-
+ if (adev->mes.hung_queue_db_array_gpu_obj[i])
+ amdgpu_bo_free_kernel(&adev->mes.hung_queue_db_array_gpu_obj[i],
+ &adev->mes.hung_queue_db_array_gpu_addr[i],
+ &adev->mes.hung_queue_db_array_cpu_addr[i]);
if (adev->mes.sch_ctx_ptr[i])
amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs[i]);
if (adev->mes.query_status_fence_ptr[i])
@@ -281,7 +301,7 @@ void amdgpu_mes_fini(struct amdgpu_device *adev)
mutex_destroy(&adev->mes.mutex_hidden);
}
-int amdgpu_mes_suspend(struct amdgpu_device *adev)
+int amdgpu_mes_suspend(struct amdgpu_device *adev, u32 xcc_id)
{
struct mes_suspend_gang_input input;
int r;
@@ -291,6 +311,10 @@ int amdgpu_mes_suspend(struct amdgpu_device *adev)
memset(&input, 0x0, sizeof(struct mes_suspend_gang_input));
input.suspend_all_gangs = 1;
+ input.xcc_id = xcc_id;
+ if ((amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0)) &&
+ ((adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) >= 0x71))
+ input.suspend_all_sdma_gangs = 1;
/*
* Avoid taking any other locks under MES lock to avoid circular
@@ -305,7 +329,7 @@ int amdgpu_mes_suspend(struct amdgpu_device *adev)
return r;
}
-int amdgpu_mes_resume(struct amdgpu_device *adev)
+int amdgpu_mes_resume(struct amdgpu_device *adev, u32 xcc_id)
{
struct mes_resume_gang_input input;
int r;
@@ -315,6 +339,7 @@ int amdgpu_mes_resume(struct amdgpu_device *adev)
memset(&input, 0x0, sizeof(struct mes_resume_gang_input));
input.resume_all_gangs = 1;
+ input.xcc_id = xcc_id;
/*
* Avoid taking any other locks under MES lock to avoid circular
@@ -428,7 +453,7 @@ int amdgpu_mes_detect_and_reset_hung_queues(struct amdgpu_device *adev,
{
struct mes_detect_and_reset_queue_input input;
u32 *db_array = adev->mes.hung_queue_db_array_cpu_addr[xcc_id];
- int r, i;
+ int hqd_info_offset = adev->mes.hung_queue_hqd_info_offset, r, i;
if (!hung_db_num || !hung_db_array)
return -EINVAL;
@@ -443,26 +468,34 @@ int amdgpu_mes_detect_and_reset_hung_queues(struct amdgpu_device *adev,
adev->mes.hung_queue_db_array_size * sizeof(u32));
input.queue_type = queue_type;
input.detect_only = detect_only;
+ input.xcc_id = xcc_id;
r = adev->mes.funcs->detect_and_reset_hung_queues(&adev->mes,
&input);
- if (r) {
- dev_err(adev->dev, "failed to detect and reset\n");
- } else {
- *hung_db_num = 0;
- for (i = 0; i < adev->mes.hung_queue_hqd_info_offset; i++) {
- if (db_array[i] != AMDGPU_MES_INVALID_DB_OFFSET) {
- hung_db_array[i] = db_array[i];
- *hung_db_num += 1;
- }
+
+ if (r && detect_only) {
+ dev_err(adev->dev, "Failed to detect hung queues\n");
+ return r;
+ }
+
+ *hung_db_num = 0;
+ /* MES passes hung queues' doorbell to driver */
+ for (i = 0; i < adev->mes.hung_queue_hqd_info_offset; i++) {
+ /* Finding hung queues where db_array[i] is a valid doorbell */
+ if (db_array[i] != AMDGPU_MES_INVALID_DB_OFFSET) {
+ hung_db_array[i] = db_array[i];
+ *hung_db_num += 1;
}
+ }
- /*
- * TODO: return HQD info for MES scheduled user compute queue reset cases
- * stored in hung_db_array hqd info offset to full array size
- */
+ if (r && !(*hung_db_num)) {
+ dev_err(adev->dev, "Failed to detect and reset hung queues\n");
+ return r;
}
+ for (i = hqd_info_offset; i < hqd_info_offset + *hung_db_num; i++)
+ hung_db_array[i] = db_array[i];
+
return r;
}
@@ -748,6 +781,18 @@ out:
return r;
}
+void amdgpu_mes_validate_fw_version(struct amdgpu_device *adev)
+{
+ u32 fw_from_ucode = adev->mes.fw_version[AMDGPU_MES_SCHED_PIPE];
+ u32 fw_from_reg = adev->mes.sched_version & AMDGPU_MES_VERSION_MASK;
+
+ if (fw_from_ucode != fw_from_reg)
+ dev_info(adev->dev,
+ "MES firmware reports incorrect version in ucode binary (0x%x vs 0x%x)\n",
+ fw_from_ucode, fw_from_reg);
+}
+
+
bool amdgpu_mes_suspend_resume_all_supported(struct amdgpu_device *adev)
{
uint32_t mes_rev = adev->mes.sched_version & AMDGPU_MES_VERSION_MASK;
@@ -758,6 +803,12 @@ bool amdgpu_mes_suspend_resume_all_supported(struct amdgpu_device *adev)
amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(12, 0, 0));
}
+bool amdgpu_mes_queue_reset_by_mes_supported(struct amdgpu_device *adev)
+{
+ return (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0) &&
+ (adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) >= 0x73);
+}
+
/* Fix me -- node_id is used to identify the correct MES instances in the future */
static int amdgpu_mes_set_enforce_isolation(struct amdgpu_device *adev,
uint32_t node_id, bool enable)