summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Palacek <William.Palacek@amd.com>2026-10-19 15:41:15 -0400
committerAlex Deucher <alexander.deucher@amd.com>2026-10-27 13:50:56 -0400
commit92249023caee17bfc6f29c71d6aaa5f2298cf507 (patch)
tree7aa6e1024fd0ca7c4103eec61ffb3ac037117483
parent1ac3b84e10d23f4cd47150f55323896f4cc5a4d2 (diff)
downloadlinux-next-92249023caee17bfc6f29c71d6aaa5f2298cf507.tar.gz
linux-next-92249023caee17bfc6f29c71d6aaa5f2298cf507.zip
drm/amdkfd: Validate the control stack of a restored queue
kfd_criu_restore_queue() takes the control stack size from the checkpoint image without the topology check create-queue does in kfd_queue_acquire_buffers(), which restore stopped calling in commit 1cafa8b29e02 ("drm/amdkfd: Don't acquire buffers during CRIU queue restore."). An image size of 0x300000 is accepted and sizes the MQD allocation, and 0xFFFFFFFF trips a page allocator warning in kmalloc(). restore_mqd() also keeps the image's cp_hqd_cntl_stack_size, cp_hqd_cntl_stack_offset and cp_hqd_wg_state_offset. With offset > size or wave state offset < size, get_wave_state() returns wrapped sizes. Take the per-XCC size from topology, 0 for queues without a control stack, and reject larger images. In restore_mqd(), set the size to it and bound both offsets as init_mqd() does. Fixes: 626f7b3190b4 ("drm/amdkfd: CRIU add queues support") Fixes: 42c6c48214b7 ("drm/amdkfd: CRIU checkpoint and restore queue mqds") Signed-off-by: William Palacek <William.Palacek@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c30
8 files changed, 42 insertions, 9 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h
index 38b46b696243..d63f7e9fae30 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h
@@ -138,6 +138,15 @@ struct mqd_manager {
uint32_t ctl_stack_size;
};
+/* Keep offset <= size <= wave state offset, as init_mqd() and CP do */
+static inline void kfd_mqd_restore_ctl_stack(u32 *size, u32 *offset, u32 *wg_offset,
+ u32 ctl_stack_size)
+{
+ *size = ctl_stack_size;
+ *offset = min(*offset, ctl_stack_size);
+ *wg_offset = max(*wg_offset, ctl_stack_size);
+}
+
struct mqd_user_context_save_area_header {
/* Byte offset from start of user context
* save area to the last saved top (lowest
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
index 25f5a2cf02ff..922615b713a9 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
@@ -305,6 +305,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
addr = mqd_mem_obj->gpu_addr;
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
*mqd = m;
if (gart_addr)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
index a1eecdf63b0c..62c3023152a5 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
@@ -340,6 +340,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
addr = mqd_mem_obj->gpu_addr;
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
*mqd = m;
if (gart_addr)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
index e0574fa325c4..1d9b4890909f 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
@@ -394,6 +394,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
/* Update MQD base address to the newly allocated location */
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
index 04e1575dfe76..e34103067fa0 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
@@ -693,6 +693,8 @@ static void restore_mqd_v12_1(struct mqd_manager *mm, void **mqd,
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size) *
NUM_XCC(mm->dev->xcc_mask));
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
/* Update MQD base address to the newly allocated location */
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
index 80df86f7c4d5..e18c86c87d1c 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
@@ -462,6 +462,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
addr = mqd_mem_obj->gpu_addr;
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
*mqd = m;
if (gart_addr)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
index 029572548c14..5ead0d5613b6 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
@@ -317,6 +317,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
addr = mqd_mem_obj->gpu_addr;
memcpy(m, mqd_src, sizeof(*m));
+ kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset,
+ &m->cp_hqd_wg_state_offset, qp->ctl_stack_size);
*mqd = m;
if (gart_addr)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index a15a826519ad..78ab759ad854 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -26,6 +26,7 @@
#include <linux/list.h>
#include "kfd_device_queue_manager.h"
#include "kfd_priv.h"
+#include "kfd_topology.h"
#include "kfd_kernel_queue.h"
#include "amdgpu_amdkfd.h"
#include "amdgpu_reset.h"
@@ -983,7 +984,7 @@ int kfd_criu_checkpoint_queues(struct kfd_process *p,
}
static void set_queue_properties_from_criu(struct queue_properties *qp,
- struct kfd_criu_queue_priv_data *q_data, uint32_t num_xcc)
+ struct kfd_criu_queue_priv_data *q_data)
{
qp->is_interop = false;
qp->queue_percent = q_data->q_percent;
@@ -996,11 +997,6 @@ static void set_queue_properties_from_criu(struct queue_properties *qp,
qp->eop_ring_buffer_size = q_data->eop_ring_buffer_size;
qp->ctx_save_restore_area_address = q_data->ctx_save_restore_area_address;
qp->ctx_save_restore_area_size = q_data->ctx_save_restore_area_size;
- if (q_data->type == KFD_QUEUE_TYPE_COMPUTE)
- qp->ctl_stack_size = q_data->ctl_stack_size / num_xcc;
- else
- qp->ctl_stack_size = q_data->ctl_stack_size;
-
qp->type = q_data->type;
qp->format = q_data->format;
}
@@ -1012,6 +1008,7 @@ int kfd_criu_restore_queue(struct kfd_process *p,
{
uint8_t *mqd, *ctl_stack, *q_extra_data = NULL;
struct kfd_criu_queue_priv_data *q_data;
+ struct kfd_topology_device *topo_dev;
struct kfd_process_device *pdd;
uint64_t q_extra_data_size;
struct queue_properties qp;
@@ -1048,6 +1045,24 @@ int kfd_criu_restore_queue(struct kfd_process *p,
goto exit;
}
+ memset(&qp, 0, sizeof(qp));
+ set_queue_properties_from_criu(&qp, q_data);
+
+ /* Per-XCC control stack size from topology, as create-queue requires */
+ if (qp.type == KFD_QUEUE_TYPE_COMPUTE && pdd->dev->kfd->cwsr_enabled) {
+ topo_dev = kfd_topology_device_by_id(pdd->dev->id);
+ if (!topo_dev) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ qp.ctl_stack_size = topo_dev->node_props.ctl_stack_size;
+ }
+
+ if (q_data->ctl_stack_size > (u64)qp.ctl_stack_size * NUM_XCC(pdd->dev->xcc_mask)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
*priv_data_offset += sizeof(*q_data);
q_extra_data_size = (uint64_t)q_data->ctl_stack_size + q_data->mqd_size;
@@ -1077,9 +1092,6 @@ int kfd_criu_restore_queue(struct kfd_process *p,
mqd = q_extra_data;
ctl_stack = mqd + q_data->mqd_size;
- memset(&qp, 0, sizeof(qp));
- set_queue_properties_from_criu(&qp, q_data, NUM_XCC(pdd->dev->xcc_mask));
-
print_queue_properties(&qp);
ret = pqm_create_queue(&p->pqm, pdd->dev, &qp, &queue_id, q_data, mqd, ctl_stack, NULL);