mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-21 23:16:50 +08:00
drm/xe: Forcefully tear down exec queues in GuC submit fini
In GuC submit fini, forcefully tear down any exec queues by disabling
CTs, stopping the scheduler (which cleans up lost G2H), killing all
remaining queues, and resuming scheduling to allow any remaining cleanup
actions to complete and signal any remaining fences.
Split guc_submit_fini into device related and software only part. Using
device-managed and drm-managed action guarantees the correct ordering of
cleanup.
Fixes: dd08ebf6c3 ("drm/xe: Introduce a new DRM driver for Intel GPUs")
Cc: stable@vger.kernel.org
Reviewed-by: Zhanjun Dong <zhanjun.dong@intel.com>
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Link: https://patch.msgid.link/20260310225039.1320161-3-zhanjun.dong@intel.com
(cherry picked from commit a6ab444a111a59924bd9d0c1e0613a75a0a40b89)
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
This commit is contained in:
committed by
Thomas Hellström
parent
26c638d560
commit
fb3738693c
@@ -1347,15 +1347,37 @@ int xe_guc_enable_communication(struct xe_guc *guc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xe_guc_suspend(struct xe_guc *guc)
|
||||
/**
|
||||
* xe_guc_softreset() - Soft reset GuC
|
||||
* @guc: The GuC object
|
||||
*
|
||||
* Send soft reset command to GuC through mmio send.
|
||||
*
|
||||
* Return: 0 if success, otherwise error code
|
||||
*/
|
||||
int xe_guc_softreset(struct xe_guc *guc)
|
||||
{
|
||||
struct xe_gt *gt = guc_to_gt(guc);
|
||||
u32 action[] = {
|
||||
XE_GUC_ACTION_CLIENT_SOFT_RESET,
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (!xe_uc_fw_is_running(&guc->fw))
|
||||
return 0;
|
||||
|
||||
ret = xe_guc_mmio_send(guc, action, ARRAY_SIZE(action));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xe_guc_suspend(struct xe_guc *guc)
|
||||
{
|
||||
struct xe_gt *gt = guc_to_gt(guc);
|
||||
int ret;
|
||||
|
||||
ret = xe_guc_softreset(guc);
|
||||
if (ret) {
|
||||
xe_gt_err(gt, "GuC suspend failed: %pe\n", ERR_PTR(ret));
|
||||
return ret;
|
||||
|
||||
@@ -44,6 +44,7 @@ int xe_guc_opt_in_features_enable(struct xe_guc *guc);
|
||||
void xe_guc_runtime_suspend(struct xe_guc *guc);
|
||||
void xe_guc_runtime_resume(struct xe_guc *guc);
|
||||
int xe_guc_suspend(struct xe_guc *guc);
|
||||
int xe_guc_softreset(struct xe_guc *guc);
|
||||
void xe_guc_notify(struct xe_guc *guc);
|
||||
int xe_guc_auth_huc(struct xe_guc *guc, u32 rsa_addr);
|
||||
int xe_guc_mmio_send(struct xe_guc *guc, const u32 *request, u32 len);
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
|
||||
#define XE_GUC_EXEC_QUEUE_CGP_CONTEXT_ERROR_LEN 6
|
||||
|
||||
static int guc_submit_reset_prepare(struct xe_guc *guc);
|
||||
|
||||
static struct xe_guc *
|
||||
exec_queue_to_guc(struct xe_exec_queue *q)
|
||||
{
|
||||
@@ -239,7 +241,7 @@ static bool exec_queue_killed_or_banned_or_wedged(struct xe_exec_queue *q)
|
||||
EXEC_QUEUE_STATE_BANNED));
|
||||
}
|
||||
|
||||
static void guc_submit_fini(struct drm_device *drm, void *arg)
|
||||
static void guc_submit_sw_fini(struct drm_device *drm, void *arg)
|
||||
{
|
||||
struct xe_guc *guc = arg;
|
||||
struct xe_device *xe = guc_to_xe(guc);
|
||||
@@ -257,6 +259,19 @@ static void guc_submit_fini(struct drm_device *drm, void *arg)
|
||||
xa_destroy(&guc->submission_state.exec_queue_lookup);
|
||||
}
|
||||
|
||||
static void guc_submit_fini(void *arg)
|
||||
{
|
||||
struct xe_guc *guc = arg;
|
||||
|
||||
/* Forcefully kill any remaining exec queues */
|
||||
xe_guc_ct_stop(&guc->ct);
|
||||
guc_submit_reset_prepare(guc);
|
||||
xe_guc_softreset(guc);
|
||||
xe_guc_submit_stop(guc);
|
||||
xe_uc_fw_sanitize(&guc->fw);
|
||||
xe_guc_submit_pause_abort(guc);
|
||||
}
|
||||
|
||||
static void guc_submit_wedged_fini(void *arg)
|
||||
{
|
||||
struct xe_guc *guc = arg;
|
||||
@@ -326,7 +341,11 @@ int xe_guc_submit_init(struct xe_guc *guc, unsigned int num_ids)
|
||||
|
||||
guc->submission_state.initialized = true;
|
||||
|
||||
return drmm_add_action_or_reset(&xe->drm, guc_submit_fini, guc);
|
||||
err = drmm_add_action_or_reset(&xe->drm, guc_submit_sw_fini, guc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return devm_add_action_or_reset(xe->drm.dev, guc_submit_fini, guc);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2230,6 +2249,7 @@ static const struct xe_exec_queue_ops guc_exec_queue_ops = {
|
||||
static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q)
|
||||
{
|
||||
struct xe_gpu_scheduler *sched = &q->guc->sched;
|
||||
bool do_destroy = false;
|
||||
|
||||
/* Stop scheduling + flush any DRM scheduler operations */
|
||||
xe_sched_submission_stop(sched);
|
||||
@@ -2237,7 +2257,7 @@ static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q)
|
||||
/* Clean up lost G2H + reset engine state */
|
||||
if (exec_queue_registered(q)) {
|
||||
if (exec_queue_destroyed(q))
|
||||
__guc_exec_queue_destroy(guc, q);
|
||||
do_destroy = true;
|
||||
}
|
||||
if (q->guc->suspend_pending) {
|
||||
set_exec_queue_suspended(q);
|
||||
@@ -2273,18 +2293,15 @@ static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q)
|
||||
xe_guc_exec_queue_trigger_cleanup(q);
|
||||
}
|
||||
}
|
||||
|
||||
if (do_destroy)
|
||||
__guc_exec_queue_destroy(guc, q);
|
||||
}
|
||||
|
||||
int xe_guc_submit_reset_prepare(struct xe_guc *guc)
|
||||
static int guc_submit_reset_prepare(struct xe_guc *guc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (xe_gt_WARN_ON(guc_to_gt(guc), vf_recovery(guc)))
|
||||
return 0;
|
||||
|
||||
if (!guc->submission_state.initialized)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Using an atomic here rather than submission_state.lock as this
|
||||
* function can be called while holding the CT lock (engine reset
|
||||
@@ -2299,6 +2316,17 @@ int xe_guc_submit_reset_prepare(struct xe_guc *guc)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xe_guc_submit_reset_prepare(struct xe_guc *guc)
|
||||
{
|
||||
if (xe_gt_WARN_ON(guc_to_gt(guc), vf_recovery(guc)))
|
||||
return 0;
|
||||
|
||||
if (!guc->submission_state.initialized)
|
||||
return 0;
|
||||
|
||||
return guc_submit_reset_prepare(guc);
|
||||
}
|
||||
|
||||
void xe_guc_submit_reset_wait(struct xe_guc *guc)
|
||||
{
|
||||
wait_event(guc->ct.wq, xe_device_wedged(guc_to_xe(guc)) ||
|
||||
|
||||
Reference in New Issue
Block a user