A runtime compute partition switch updates the XCP mode and IMU
partition without passing through MES hw init. The MES KIQ and
scheduler therefore remain programmed for the previous partition,
including its cooperative mode.
After committing the new mode, tear KIQ down on every XCC, clear the
KIQ and scheduler rings and their writeback pointers, and initialize
KIQ again. This remaps both queues and sends SET_HW_RSRC followed by
SET_HW_RSRC_1 with cooperative mode enabled for SPX, DPX, and QPX and
disabled for CPX.
---
drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 5 +++
drivers/gpu/drm/amd/amdgpu/mes_v12_1.c | 54 +++++++++++++++++++++++++
drivers/gpu/drm/amd/amdgpu/soc_v1_0.c | 9 +++++
3 files changed, 68 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
index 0f368fbd2c80..5a14f4e7b64d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
@@ -141,6 +141,8 @@ struct amdgpu_mes {
uint32_t xcc_id);
int (*kiq_hw_fini)(struct amdgpu_device
*adev,
uint32_t xcc_id);
+ /* Tear down KIQ, clear its rings, and run kiq_hw_init again. */
+ int (*kiq_hw_reinit)(struct amdgpu_device
*adev);
/* MES doorbells */
uint32_t db_start_dw_offset;
@@ -553,6 +555,9 @@ struct amdgpu_mqd {
(adev)->mes.kiq_hw_init((adev), (xcc_id))
#define amdgpu_mes_kiq_hw_fini(adev, xcc_id) \
(adev)->mes.kiq_hw_fini((adev), (xcc_id))
+#define amdgpu_mes_kiq_hw_reinit(adev) \
+ ((adev)->mes.kiq_hw_reinit ? \
+ (adev)->mes.kiq_hw_reinit(adev) : 0)
int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe);
void amdgpu_mes_validate_fw_version(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c
b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c
index 5573fe981a22..760c93740a7e 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c
@@ -42,6 +42,7 @@ static int mes_v12_1_hw_fini(struct amdgpu_ip_block
*ip_block);
static int mes_v12_1_kiq_hw_init(struct amdgpu_device *adev, uint32_t xcc_id);
static int mes_v12_1_kiq_hw_fini(struct amdgpu_device *adev, uint32_t xcc_id);
static int mes_v12_1_setup_coop_mode(struct amdgpu_device *adev, int xcc_id);
+static int mes_v12_1_kiq_hw_reinit(struct amdgpu_device *adev);
#define MES_EOP_SIZE 2048
#define MES12_HUNG_DB_OFFSET_ARRAY_SIZE 8 /* [0:3] = db offset [4:7] hqd info
*/
@@ -674,6 +675,14 @@ static int mes_v12_1_set_hw_resources_1(struct amdgpu_mes
*mes,
mes->shared_cmd_buf_gpu_addr[MES_PIPE_INST(master_xcc_id, pipe)];
}
+ dev_dbg(mes->adev->dev,
+ "MES(%d, %d) SET_HW_RSRC_1 coop=%u enable_coop=%u kiq_ver=0x%x
mode=%s\n",
+ xcc_id, pipe, mes_set_hw_res_1_pkt.mes_coop_mode,
+ mes->enable_coop_mode,
+ mes->kiq_version & AMDGPU_MES_VERSION_MASK,
+ amdgpu_gfx_compute_mode_desc(mes->adev->xcp_mgr ?
+ mes->adev->xcp_mgr->mode : -1));
+
return mes_v12_1_submit_pkt_and_poll_completion(mes, xcc_id, pipe,
&mes_set_hw_res_1_pkt, sizeof(mes_set_hw_res_1_pkt),
offsetof(union MESAPI_SET_HW_RESOURCES_1, api_status));
@@ -1530,6 +1539,7 @@ static int mes_v12_1_sw_init(struct amdgpu_ip_block
*ip_block)
adev->mes.funcs = &mes_v12_1_funcs;
adev->mes.kiq_hw_init = &mes_v12_1_kiq_hw_init;
adev->mes.kiq_hw_fini = &mes_v12_1_kiq_hw_fini;
+ adev->mes.kiq_hw_reinit = &mes_v12_1_kiq_hw_reinit;
adev->mes.enable_legacy_queue_map = true;
adev->mes.event_log_size = AMDGPU_MAX_MES_PIPES *
@@ -1774,6 +1784,50 @@ static int mes_v12_1_setup_coop_mode(struct
amdgpu_device *adev, int xcc_id)
return r;
}
+/*
+ * Runtime partition switches do not pass through MES IP hw_init. Tear KIQ
+ * down, clear both MES rings, and run kiq_hw_init again. That init maps
+ * the KIQ and scheduler queues and, through setup_coop_mode, programs
+ * mes_coop_mode for the new partition.
+ *
+ * If a scheduler ring is not ready, MES has not been initialized yet and
+ * the kiq_hw_init call from CP resume covers this mode.
+ */
+static int mes_v12_1_kiq_hw_reinit(struct amdgpu_device *adev)
+{
+ int xcc_id, pipe, num_xcc = NUM_XCC(adev->gfx.xcc_mask);
+ int r;
+
+ for (xcc_id = 0; xcc_id < num_xcc; xcc_id++) {
+ if (!adev->mes.ring[MES_PIPE_INST(xcc_id,
+
AMDGPU_MES_SCHED_PIPE)].sched.ready)
+ return 0;
+ }
+
+ for (xcc_id = 0; xcc_id < num_xcc; xcc_id++) {
+ r = mes_v12_1_kiq_hw_fini(adev, xcc_id);
+ if (r)
+ return r;
+
+ /*
+ * The firmware restarts with its read pointer at zero, so
+ * leaving the old contents and writeback pointers in place
+ * would make it replay stale packets.
+ */
+ for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++)
+ amdgpu_ring_clear_ring_and_ptrs(
+ &adev->mes.ring[MES_PIPE_INST(xcc_id, pipe)]);
+ }
+
+ for (xcc_id = 0; xcc_id < num_xcc; xcc_id++) {
+ r = mes_v12_1_kiq_hw_init(adev, xcc_id);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
static int mes_v12_1_xcc_hw_init(struct amdgpu_ip_block *ip_block, int xcc_id)
{
int r;
diff --git a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c
b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c
index 506060fc5368..95ebbd4a7369 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c
@@ -1100,6 +1100,15 @@ static int soc_v1_0_switch_partition_mode(struct
amdgpu_xcp_mgr *xcp_mgr,
*num_xcps = num_xcc / num_xcc_per_xcp;
amdgpu_xcp_init(xcp_mgr, *num_xcps, mode);
+ /*
+ * xcp_mgr->mode is the new partition now. MES KIQ was programmed for
+ * the previous mode and is not reset by the IMU switch, so tear it
+ * down, clear the rings, and run kiq_hw_init again.
+ */
+ ret = amdgpu_mes_kiq_hw_reinit(adev);
+ if (ret)
+ goto out;
+
ret = amdgpu_xcp_post_partition_switch(xcp_mgr, flags);
if (!ret)
__soc_v1_0_update_available_partition_mode(xcp_mgr);