drm/xe: Enforce correct user fence signaling order using

Prevent application hangs caused by out-of-order fence signaling when
user fences are attached. Use drm_syncobj (via dma-fence-chain) to
guarantee that each user fence signals in order, regardless of the
signaling order of the attached fences. Ensure user fence writebacks to
user space occur in the correct sequence.

v7:
 - Skip drm_syncbj create of error (CI)

Fixes: dd08ebf6c3 ("drm/xe: Introduce a new DRM driver for Intel GPUs")
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Link: https://patch.msgid.link/20251031234050.3043507-2-matthew.brost@intel.com
This commit is contained in:
Matthew Brost
2025-10-31 16:40:45 -07:00
parent a4ff26b7c8
commit adda4e855a
9 changed files with 86 additions and 18 deletions

View File

@@ -10,6 +10,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_managed.h>
#include <drm/drm_syncobj.h>
#include <uapi/drm/xe_drm.h>
#include <generated/xe_wa_oob.h>
@@ -1390,7 +1391,9 @@ static int xe_oa_user_extensions(struct xe_oa *oa, enum xe_oa_user_extn_from fro
return 0;
}
static int xe_oa_parse_syncs(struct xe_oa *oa, struct xe_oa_open_param *param)
static int xe_oa_parse_syncs(struct xe_oa *oa,
struct xe_oa_stream *stream,
struct xe_oa_open_param *param)
{
int ret, num_syncs, num_ufence = 0;
@@ -1410,7 +1413,9 @@ static int xe_oa_parse_syncs(struct xe_oa *oa, struct xe_oa_open_param *param)
for (num_syncs = 0; num_syncs < param->num_syncs; num_syncs++) {
ret = xe_sync_entry_parse(oa->xe, param->xef, &param->syncs[num_syncs],
&param->syncs_user[num_syncs], 0);
&param->syncs_user[num_syncs],
stream->ufence_syncobj,
++stream->ufence_timeline_value, 0);
if (ret)
goto err_syncs;
@@ -1540,7 +1545,7 @@ static long xe_oa_config_locked(struct xe_oa_stream *stream, u64 arg)
return -ENODEV;
param.xef = stream->xef;
err = xe_oa_parse_syncs(stream->oa, &param);
err = xe_oa_parse_syncs(stream->oa, stream, &param);
if (err)
goto err_config_put;
@@ -1636,6 +1641,7 @@ static void xe_oa_destroy_locked(struct xe_oa_stream *stream)
if (stream->exec_q)
xe_exec_queue_put(stream->exec_q);
drm_syncobj_put(stream->ufence_syncobj);
kfree(stream);
}
@@ -1827,6 +1833,7 @@ static int xe_oa_stream_open_ioctl_locked(struct xe_oa *oa,
struct xe_oa_open_param *param)
{
struct xe_oa_stream *stream;
struct drm_syncobj *ufence_syncobj;
int stream_fd;
int ret;
@@ -1837,17 +1844,31 @@ static int xe_oa_stream_open_ioctl_locked(struct xe_oa *oa,
goto exit;
}
ret = drm_syncobj_create(&ufence_syncobj, DRM_SYNCOBJ_CREATE_SIGNALED,
NULL);
if (ret)
goto exit;
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
if (!stream) {
ret = -ENOMEM;
goto exit;
goto err_syncobj;
}
stream->ufence_syncobj = ufence_syncobj;
stream->oa = oa;
ret = xe_oa_stream_init(stream, param);
ret = xe_oa_parse_syncs(oa, stream, param);
if (ret)
goto err_free;
ret = xe_oa_stream_init(stream, param);
if (ret) {
while (param->num_syncs--)
xe_sync_entry_cleanup(&param->syncs[param->num_syncs]);
kfree(param->syncs);
goto err_free;
}
if (!param->disabled) {
ret = xe_oa_enable_locked(stream);
if (ret)
@@ -1871,6 +1892,8 @@ err_destroy:
xe_oa_stream_destroy(stream);
err_free:
kfree(stream);
err_syncobj:
drm_syncobj_put(ufence_syncobj);
exit:
return ret;
}
@@ -2084,22 +2107,14 @@ int xe_oa_stream_open_ioctl(struct drm_device *dev, u64 data, struct drm_file *f
goto err_exec_q;
}
ret = xe_oa_parse_syncs(oa, &param);
if (ret)
goto err_exec_q;
mutex_lock(&param.hwe->gt->oa.gt_lock);
ret = xe_oa_stream_open_ioctl_locked(oa, &param);
mutex_unlock(&param.hwe->gt->oa.gt_lock);
if (ret < 0)
goto err_sync_cleanup;
goto err_exec_q;
return ret;
err_sync_cleanup:
while (param.num_syncs--)
xe_sync_entry_cleanup(&param.syncs[param.num_syncs]);
kfree(param.syncs);
err_exec_q:
if (param.exec_q)
xe_exec_queue_put(param.exec_q);