Commit 0995c2fc authored by Matthew Brost's avatar Matthew Brost Committed by Lucas De Marchi
Browse files

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: dd08ebf6 ("drm/xe: Introduce a new DRM driver for Intel GPUs")
Signed-off-by: default avatarMatthew Brost <matthew.brost@intel.com>
Reviewed-by: default avatarThomas Hellström <thomas.hellstrom@linux.intel.com>
Link: https://patch.msgid.link/20251031234050.3043507-2-matthew.brost@intel.com


(cherry picked from commit adda4e85)
Signed-off-by: default avatarLucas De Marchi <lucas.demarchi@intel.com>
parent b11a020d
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -165,7 +165,8 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)

	for (num_syncs = 0; num_syncs < args->num_syncs; num_syncs++) {
		err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs],
					  &syncs_user[num_syncs], SYNC_PARSE_FLAG_EXEC |
					  &syncs_user[num_syncs], NULL, 0,
					  SYNC_PARSE_FLAG_EXEC |
					  (xe_vm_in_lr_mode(vm) ?
					   SYNC_PARSE_FLAG_LR_MODE : 0));
		if (err)
+14 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_syncobj.h>
#include <uapi/drm/xe_drm.h>

#include "xe_dep_scheduler.h"
@@ -324,6 +325,16 @@ struct xe_exec_queue *xe_exec_queue_create_bind(struct xe_device *xe,
	}
	xe_vm_put(migrate_vm);

	if (!IS_ERR(q)) {
		int err = drm_syncobj_create(&q->ufence_syncobj,
					     DRM_SYNCOBJ_CREATE_SIGNALED,
					     NULL);
		if (err) {
			xe_exec_queue_put(q);
			return ERR_PTR(err);
		}
	}

	return q;
}
ALLOW_ERROR_INJECTION(xe_exec_queue_create_bind, ERRNO);
@@ -333,6 +344,9 @@ void xe_exec_queue_destroy(struct kref *ref)
	struct xe_exec_queue *q = container_of(ref, struct xe_exec_queue, refcount);
	struct xe_exec_queue *eq, *next;

	if (q->ufence_syncobj)
		drm_syncobj_put(q->ufence_syncobj);

	if (xe_exec_queue_uses_pxp(q))
		xe_pxp_exec_queue_remove(gt_to_xe(q->gt)->pxp, q);

+7 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include "xe_hw_fence_types.h"
#include "xe_lrc_types.h"

struct drm_syncobj;
struct xe_execlist_exec_queue;
struct xe_gt;
struct xe_guc_exec_queue;
@@ -155,6 +156,12 @@ struct xe_exec_queue {
		struct list_head link;
	} pxp;

	/** @ufence_syncobj: User fence syncobj */
	struct drm_syncobj *ufence_syncobj;

	/** @ufence_timeline_value: User fence timeline value */
	u64 ufence_timeline_value;

	/** @ops: submission backend exec queue operations */
	const struct xe_exec_queue_ops *ops;

+30 −15
Original line number Diff line number Diff line
@@ -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>
@@ -1389,7 +1390,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;

@@ -1409,7 +1412,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;

@@ -1539,7 +1544,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;

@@ -1635,6 +1640,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);
}

@@ -1826,6 +1832,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;

@@ -1836,17 +1843,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)
@@ -1870,6 +1891,8 @@ static int xe_oa_stream_open_ioctl_locked(struct xe_oa *oa,
	xe_oa_stream_destroy(stream);
err_free:
	kfree(stream);
err_syncobj:
	drm_syncobj_put(ufence_syncobj);
exit:
	return ret;
}
@@ -2083,22 +2106,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);
+8 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
#include "regs/xe_reg_defs.h"
#include "xe_hw_engine_types.h"

struct drm_syncobj;

#define DEFAULT_XE_OA_BUFFER_SIZE SZ_16M

enum xe_oa_report_header {
@@ -248,6 +250,12 @@ struct xe_oa_stream {
	/** @xef: xe_file with which the stream was opened */
	struct xe_file *xef;

	/** @ufence_syncobj: User fence syncobj */
	struct drm_syncobj *ufence_syncobj;

	/** @ufence_timeline_value: User fence timeline value */
	u64 ufence_timeline_value;

	/** @last_fence: fence to use in stream destroy when needed */
	struct dma_fence *last_fence;

Loading