[PATCH 13/21] drm/xe/eudebug: Add UFENCE events with acks

Matthew Brost matthew.brost at intel.com
Sat Jul 27 00:40:29 UTC 2024


On Fri, Jul 26, 2024 at 05:08:10PM +0300, Mika Kuoppala wrote:
> When vma is in place, debugger needs to intercept before
> userspace proceeds with the workload. For example to install
> a breakpoint in a eu shader.
> 
> Attach debugger in xe_user_fence, send UFENCE event
> and stall normal user fence signal path to yield if
> there is debugger attached to ufence.
> 
> When ack (ioctl) is received for the corresponding seqno,
> signal ufence.
> 
> v2: ufence worker in own workqueue
> 

Not a complete review again, just a couple of quick comments.

> Signed-off-by: Mika Kuoppala <mika.kuoppala at linux.intel.com>
> ---
>  drivers/gpu/drm/xe/xe_eudebug.c       | 239 +++++++++++++++++++++++++-
>  drivers/gpu/drm/xe/xe_eudebug.h       |   6 +
>  drivers/gpu/drm/xe/xe_eudebug_types.h |  12 ++
>  drivers/gpu/drm/xe/xe_exec.c          |   2 +-
>  drivers/gpu/drm/xe/xe_sync.c          |  49 ++++--
>  drivers/gpu/drm/xe/xe_sync.h          |   8 +-
>  drivers/gpu/drm/xe/xe_sync_types.h    |  26 ++-
>  drivers/gpu/drm/xe/xe_vm.c            |   4 +-
>  include/uapi/drm/xe_drm_eudebug.h     |  15 +-
>  9 files changed, 333 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 8f0e6a56a65e..5dcb7c9464e9 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -35,6 +35,7 @@
>  #include "xe_vm.h"
>  #include "xe_wa.h"
>  #include "xe_force_wake.h"
> +#include "xe_sync.h"
>  
>  /*
>   * If there is no detected event read by userspace, during this period, assume
> @@ -240,11 +241,115 @@ static void xe_eudebug_free(struct kref *ref)
>  	kfree_rcu(d, rcu);
>  }
>  
> -static void xe_eudebug_put(struct xe_eudebug *d)
> +void xe_eudebug_put(struct xe_eudebug *d)
>  {
>  	kref_put(&d->ref, xe_eudebug_free);
>  }
>  
> +struct xe_eudebug_ack {
> +	struct rb_node rb_node;
> +	u64 seqno;

Here we have a seqno but then an RB tree for search which is a bit
incongruent. Let me explain, seqno typically mean something which
signals sequentially in order. But then you have RB tree for searching,
if everything signaled in order a list would be sufficient.

So without looking too much I think we want one of two things.

1. seqno + list
2. key + rb tree

Make sense?

Kinda a nit but naming matters in this case as a name implies in-order
vs out-of-order signaling.

Matt

> +	u64 ts_insert;
> +	struct xe_user_fence *ufence;
> +};
> +
> +#define fetch_ack(x) rb_entry(x, struct xe_eudebug_ack, rb_node)
> +
> +static int compare_ack(const u64 a, const u64 b)
> +{
> +	if (a < b)
> +		return -1;
> +	else if (a > b)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static int ack_insert_cmp(struct rb_node * const node,
> +			  const struct rb_node * const p)
> +{
> +	return compare_ack(fetch_ack(node)->seqno,
> +			   fetch_ack(p)->seqno);
> +}
> +
> +static int ack_lookup_cmp(const void * const key,
> +			  const struct rb_node * const node)
> +{
> +	return compare_ack(*(const u64 *)key,
> +			   fetch_ack(node)->seqno);
> +}
> +
> +static struct xe_eudebug_ack *remove_ack(struct xe_eudebug *d, u64 seqno)
> +{
> +	struct rb_root * const root = &d->acks.tree;
> +	struct rb_node *node;
> +
> +	spin_lock(&d->acks.lock);
> +	node = rb_find(&seqno, root, ack_lookup_cmp);
> +	if (node)
> +		rb_erase(node, root);
> +	spin_unlock(&d->acks.lock);
> +
> +	if (!node)
> +		return NULL;
> +
> +	return rb_entry_safe(node, struct xe_eudebug_ack, rb_node);
> +}
> +
> +static void ufence_signal_worker(struct work_struct *w)
> +{
> +	struct xe_user_fence * const ufence =
> +		container_of(w, struct xe_user_fence, eudebug.worker);
> +
> +	if (READ_ONCE(ufence->signalled))
> +		xe_sync_ufence_signal(ufence);
> +
> +	xe_sync_ufence_put(ufence);
> +}
> +
> +static void kick_ufence_worker(struct xe_user_fence *f)
> +{
> +	INIT_WORK(&f->eudebug.worker, ufence_signal_worker);
> +	queue_work(f->xe->eudebug.ordered_wq, &f->eudebug.worker);
> +}
> +
> +static void handle_ack(struct xe_eudebug *d, struct xe_eudebug_ack *ack,
> +		       bool on_disconnect)
> +{
> +	struct xe_user_fence *f = ack->ufence;
> +	u64 signaller_ack, signalled_by;
> +
> +	signaller_ack = cmpxchg64(&f->eudebug.signalled_seqno, 0, ack->seqno);
> +	signalled_by = f->eudebug.signalled_seqno;
> +
> +	if (!signaller_ack)
> +		kick_ufence_worker(f);
> +	else
> +		xe_sync_ufence_put(f);
> +
> +	eu_dbg(d, "ACK: seqno=%llu: %ssignalled by %s (%llu) (held %lluus)",
> +	       ack->seqno, signaller_ack ? "already " : "",
> +	       on_disconnect ? "disconnect" : "debugger",
> +	       signalled_by,
> +	       ktime_us_delta(ktime_get(), ack->ts_insert));
> +
> +	kfree(ack);
> +}
> +
> +static void release_acks(struct xe_eudebug *d)
> +{
> +	struct xe_eudebug_ack *ack, *n;
> +	struct rb_root root;
> +
> +	spin_lock(&d->acks.lock);
> +	root = d->acks.tree;
> +	d->acks.tree = RB_ROOT;
> +	spin_unlock(&d->acks.lock);
> +
> +	rbtree_postorder_for_each_entry_safe(ack, n, &root, rb_node)
> +		handle_ack(d, ack, true);
> +}
> +
>  static struct task_struct *find_get_target(const pid_t nr)
>  {
>  	struct task_struct *task;
> @@ -328,6 +433,8 @@ static bool xe_eudebug_detach(struct xe_device *xe,
>  
>  	eu_dbg(d, "session %lld detached with %d", d->session, err);
>  
> +	release_acks(d);
> +
>  	/* Our ref with the connection_link */
>  	xe_eudebug_put(d);
>  
> @@ -428,7 +535,7 @@ static struct task_struct *find_task_get(struct xe_file *xef)
>  	return task;
>  }
>  
> -static struct xe_eudebug *
> +struct xe_eudebug *
>  xe_eudebug_get(struct xe_file *xef)
>  {
>  	struct task_struct *task;
> @@ -889,6 +996,44 @@ static long xe_eudebug_read_event(struct xe_eudebug *d,
>  	return ret;
>  }
>  
> +static long
> +xe_eudebug_ack_event_ioctl(struct xe_eudebug *d,
> +			   const unsigned int cmd,
> +			   const u64 arg)
> +{
> +	struct drm_xe_eudebug_ack_event __user * const user_ptr =
> +		u64_to_user_ptr(arg);
> +	struct drm_xe_eudebug_ack_event user_arg;
> +	struct xe_eudebug_ack *ack;
> +	struct xe_device *xe = d->xe;
> +
> +	if (XE_IOCTL_DBG(xe, _IOC_SIZE(cmd) < sizeof(user_arg)))
> +		return -EINVAL;
> +
> +	/* Userland write */
> +	if (XE_IOCTL_DBG(xe, !(_IOC_DIR(cmd) & _IOC_WRITE)))
> +		return -EINVAL;
> +
> +	if (XE_IOCTL_DBG(xe, copy_from_user(&user_arg,
> +					    user_ptr,
> +					    sizeof(user_arg))))
> +		return -EFAULT;
> +
> +	if (XE_IOCTL_DBG(xe, user_arg.flags))
> +		return -EINVAL;
> +
> +	if (XE_IOCTL_DBG(xe, xe_eudebug_detached(d)))
> +		return -ENOTCONN;
> +
> +	ack = remove_ack(d, user_arg.seqno);
> +	if (XE_IOCTL_DBG(xe, !ack))
> +		return -EINVAL;
> +
> +	handle_ack(d, ack, false);
> +
> +	return 0;
> +}
> +
>  static int do_eu_control(struct xe_eudebug *d,
>  			 const struct drm_xe_eudebug_eu_control * const arg,
>  			 struct drm_xe_eudebug_eu_control __user * const user_ptr)
> @@ -1070,7 +1215,10 @@ static long xe_eudebug_ioctl(struct file *file,
>  		ret = xe_eudebug_eu_control(d, arg);
>  		eu_dbg(d, "ioctl cmd=EU_CONTROL ret=%ld\n", ret);
>  		break;
> -
> +	case DRM_XE_EUDEBUG_IOCTL_ACK_EVENT:
> +		ret = xe_eudebug_ack_event_ioctl(d, cmd, arg);
> +		eu_dbg(d, "ioctl cmd=EVENT_ACK ret=%ld\n", ret);
> +		break;
>  	default:
>  		ret = -EINVAL;
>  	}
> @@ -1759,6 +1907,9 @@ xe_eudebug_connect(struct xe_device *xe,
>  	INIT_KFIFO(d->events.fifo);
>  	INIT_WORK(&d->discovery_work, discovery_work_fn);
>  
> +	spin_lock_init(&d->acks.lock);
> +	d->acks.tree = RB_ROOT;
> +
>  	d->res = xe_eudebug_resources_alloc();
>  	if (IS_ERR(d->res)) {
>  		err = PTR_ERR(d->res);
> @@ -2337,6 +2488,70 @@ static int vm_bind_op(struct xe_eudebug *d, struct xe_vm *vm,
>  	return 0;
>  }
>  
> +static int xe_eudebug_track_ufence(struct xe_eudebug *d,
> +				   struct xe_user_fence *f,
> +				   u64 seqno)
> +{
> +	struct xe_eudebug_ack *ack;
> +	struct rb_node *old;
> +
> +	ack = kzalloc(sizeof(*ack), GFP_KERNEL);
> +	if (!ack)
> +		return -ENOMEM;
> +
> +	ack->seqno = seqno;
> +	ack->ts_insert = ktime_get();
> +
> +	spin_lock(&d->acks.lock);
> +	old = rb_find_add(&ack->rb_node,
> +			  &d->acks.tree, ack_insert_cmp);
> +	if (!old) {
> +		kref_get(&f->refcount);
> +		ack->ufence = f;
> +	}
> +	spin_unlock(&d->acks.lock);
> +
> +	if (old) {
> +		eu_dbg(d, "ACK: seqno=%llu: already exists", seqno);
> +		kfree(ack);
> +		return -EEXIST;
> +	}
> +
> +	eu_dbg(d, "ACK: seqno=%llu: tracking started", seqno);
> +
> +	return 0;
> +}
> +
> +static int vm_bind_ufence_event(struct xe_eudebug *d,
> +				struct xe_user_fence *ufence)
> +{
> +	struct xe_eudebug_event *event;
> +	struct xe_eudebug_event_vm_bind_ufence *e;
> +	const u32 sz = sizeof(*e);
> +	const u32 flags = DRM_XE_EUDEBUG_EVENT_CREATE |
> +		DRM_XE_EUDEBUG_EVENT_NEED_ACK;
> +	u64 seqno;
> +	int ret;
> +
> +	seqno = atomic_long_inc_return(&d->events.seqno);
> +
> +	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
> +					seqno, flags, sz, GFP_KERNEL);
> +	if (!event)
> +		return -ENOMEM;
> +
> +	e = cast_event(e, event);
> +
> +	write_member(struct drm_xe_eudebug_event_vm_bind_ufence,
> +		     e, vm_bind_ref_seqno, ufence->eudebug.bind_ref_seqno);
> +
> +	ret = xe_eudebug_track_ufence(d, ufence, seqno);
> +	if (!ret)
> +		ret = xe_eudebug_queue_event(d, event);
> +
> +	return ret;
> +}
> +
>  void xe_eudebug_vm_bind_start(struct xe_vm *vm)
>  {
>  	struct xe_eudebug *d;
> @@ -2507,6 +2722,24 @@ void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int bind_err)
>  		xe_eudebug_put(d);
>  }
>  
> +int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence)
> +{
> +	struct xe_eudebug *d;
> +	int err;
> +
> +	d = ufence->eudebug.debugger;
> +	if (!d || xe_eudebug_detached(d))
> +		return -ENOTCONN;
> +
> +	err = vm_bind_ufence_event(d, ufence);
> +	if (err) {
> +		eu_err(d, "error %d on %s", err, __func__);
> +		xe_eudebug_disconnect(d, err);
> +	}
> +
> +	return 0;
> +}
> +
>  static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
>  {
>  	struct xe_exec_queue *q;
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> index 2cab90773b21..3de54802a6ca 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.h
> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> @@ -15,6 +15,7 @@ struct xe_vm;
>  struct xe_vma;
>  struct xe_exec_queue;
>  struct xe_hw_engine;
> +struct xe_user_fence;
>  
>  int xe_eudebug_connect_ioctl(struct drm_device *dev,
>  			     void *data,
> @@ -38,4 +39,9 @@ void xe_eudebug_vm_bind_start(struct xe_vm *vm);
>  void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range);
>  void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int err);
>  
> +int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence);
> +
> +struct xe_eudebug *xe_eudebug_get(struct xe_file *xef);
> +void xe_eudebug_put(struct xe_eudebug *d);
> +
>  #endif
> diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
> index 1ffe33f15409..a32c51416b5f 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug_types.h
> +++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
> @@ -86,6 +86,7 @@ struct xe_eudebug_eu_control_ops {
>  	int (*stopped)(struct xe_eudebug *e, struct xe_exec_queue *q,
>  		       struct xe_lrc *lrc, u8 *bitmap, unsigned int bitmap_size);
>  };
> +
>  /**
>   * struct xe_eudebug - Top level struct for eudebug: the connection
>   */
> @@ -149,6 +150,12 @@ struct xe_eudebug {
>  		atomic_long_t seqno;
>  	} events;
>  
> +	/* user fences tracked by this debugger */
> +	struct {
> +		spinlock_t lock;
> +		struct rb_root tree;
> +	} acks;
> +
>  	/** @ops operations for eu_control */
>  	struct xe_eudebug_eu_control_ops *ops;
>  };
> @@ -286,4 +293,9 @@ struct xe_eudebug_event_vm_bind_op {
>  	u64 range; /* Zero for unmap all ? */
>  };
>  
> +struct xe_eudebug_event_vm_bind_ufence {
> +	struct xe_eudebug_event base;
> +	u64 vm_bind_ref_seqno;
> +};
> +
>  #endif
> diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c
> index f36980aa26e6..400cb576f3b9 100644
> --- a/drivers/gpu/drm/xe/xe_exec.c
> +++ b/drivers/gpu/drm/xe/xe_exec.c
> @@ -157,7 +157,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
>  	vm = q->vm;
>  
>  	for (num_syncs = 0; num_syncs < args->num_syncs; num_syncs++) {
> -		err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs],
> +		err = xe_sync_entry_parse(xe, xef, vm, &syncs[num_syncs],
>  					  &syncs_user[num_syncs], SYNC_PARSE_FLAG_EXEC |
>  					  (xe_vm_in_lr_mode(vm) ?
>  					   SYNC_PARSE_FLAG_LR_MODE : 0));
> diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c
> index 533246f42256..52d56bfdf932 100644
> --- a/drivers/gpu/drm/xe/xe_sync.c
> +++ b/drivers/gpu/drm/xe/xe_sync.c
> @@ -18,17 +18,7 @@
>  #include "xe_exec_queue.h"
>  #include "xe_macros.h"
>  #include "xe_sched_job_types.h"
> -
> -struct xe_user_fence {
> -	struct xe_device *xe;
> -	struct kref refcount;
> -	struct dma_fence_cb cb;
> -	struct work_struct worker;
> -	struct mm_struct *mm;
> -	u64 __user *addr;
> -	u64 value;
> -	int signalled;
> -};
> +#include "xe_eudebug.h"
>  
>  static void user_fence_destroy(struct kref *kref)
>  {
> @@ -36,6 +26,10 @@ static void user_fence_destroy(struct kref *kref)
>  						 refcount);
>  
>  	mmdrop(ufence->mm);
> +
> +	if (ufence->eudebug.debugger)
> +		xe_eudebug_put(ufence->eudebug.debugger);
> +
>  	kfree(ufence);
>  }
>  
> @@ -49,7 +43,10 @@ static void user_fence_put(struct xe_user_fence *ufence)
>  	kref_put(&ufence->refcount, user_fence_destroy);
>  }
>  
> -static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
> +static struct xe_user_fence *user_fence_create(struct xe_device *xe,
> +					       struct xe_file *xef,
> +					       struct xe_vm *vm,
> +					       u64 addr,
>  					       u64 value)
>  {
>  	struct xe_user_fence *ufence;
> @@ -58,7 +55,7 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
>  	if (!access_ok(ptr, sizeof(ptr)))
>  		return ERR_PTR(-EFAULT);
>  
> -	ufence = kmalloc(sizeof(*ufence), GFP_KERNEL);
> +	ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
>  	if (!ufence)
>  		return ERR_PTR(-ENOMEM);
>  
> @@ -69,12 +66,17 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
>  	ufence->mm = current->mm;
>  	mmgrab(ufence->mm);
>  
> +	if (vm->eudebug_bind.ref) {
> +		ufence->eudebug.debugger = xe_eudebug_get(xef);
> +		ufence->eudebug.bind_ref_seqno = vm->eudebug_bind.ref;
> +	}
> +
>  	return ufence;
>  }
>  
> -static void user_fence_worker(struct work_struct *w)
> +void xe_sync_ufence_signal(struct xe_user_fence *ufence)
>  {
> -	struct xe_user_fence *ufence = container_of(w, struct xe_user_fence, worker);
> +	XE_WARN_ON(!ufence->signalled);
>  
>  	if (mmget_not_zero(ufence->mm)) {
>  		kthread_use_mm(ufence->mm);
> @@ -85,7 +87,20 @@ static void user_fence_worker(struct work_struct *w)
>  	}
>  
>  	wake_up_all(&ufence->xe->ufence_wq);
> +}
> +
> +static void user_fence_worker(struct work_struct *w)
> +{
> +	struct xe_user_fence *ufence = container_of(w, struct xe_user_fence, worker);
> +	int ret;
> +
>  	WRITE_ONCE(ufence->signalled, 1);
> +
> +	/* Lets see if debugger wants to track this */
> +	ret = xe_eudebug_vm_bind_ufence(ufence);
> +	if (ret)
> +		xe_sync_ufence_signal(ufence);
> +
>  	user_fence_put(ufence);
>  }
>  
> @@ -104,6 +119,7 @@ static void user_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
>  }
>  
>  int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
> +			struct xe_vm *vm,
>  			struct xe_sync_entry *sync,
>  			struct drm_xe_sync __user *sync_user,
>  			unsigned int flags)
> @@ -185,7 +201,8 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
>  		if (exec) {
>  			sync->addr = sync_in.addr;
>  		} else {
> -			sync->ufence = user_fence_create(xe, sync_in.addr,
> +			sync->ufence = user_fence_create(xe, xef, vm,
> +							 sync_in.addr,
>  							 sync_in.timeline_value);
>  			if (XE_IOCTL_DBG(xe, IS_ERR(sync->ufence)))
>  				return PTR_ERR(sync->ufence);
> diff --git a/drivers/gpu/drm/xe/xe_sync.h b/drivers/gpu/drm/xe/xe_sync.h
> index 256ffc1e54dc..f5bec2b1b4f6 100644
> --- a/drivers/gpu/drm/xe/xe_sync.h
> +++ b/drivers/gpu/drm/xe/xe_sync.h
> @@ -9,8 +9,12 @@
>  #include "xe_sync_types.h"
>  
>  struct xe_device;
> -struct xe_exec_queue;
>  struct xe_file;
> +struct xe_exec_queue;
> +struct drm_syncobj;
> +struct dma_fence;
> +struct dma_fence_chain;
> +struct drm_xe_sync;
>  struct xe_sched_job;
>  struct xe_vm;
>  
> @@ -19,6 +23,7 @@ struct xe_vm;
>  #define SYNC_PARSE_FLAG_DISALLOW_USER_FENCE	BIT(2)
>  
>  int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
> +			struct xe_vm *vm,
>  			struct xe_sync_entry *sync,
>  			struct drm_xe_sync __user *sync_user,
>  			unsigned int flags);
> @@ -40,5 +45,6 @@ struct xe_user_fence *__xe_sync_ufence_get(struct xe_user_fence *ufence);
>  struct xe_user_fence *xe_sync_ufence_get(struct xe_sync_entry *sync);
>  void xe_sync_ufence_put(struct xe_user_fence *ufence);
>  int xe_sync_ufence_get_status(struct xe_user_fence *ufence);
> +void xe_sync_ufence_signal(struct xe_user_fence *ufence);
>  
>  #endif
> diff --git a/drivers/gpu/drm/xe/xe_sync_types.h b/drivers/gpu/drm/xe/xe_sync_types.h
> index 30ac3f51993b..907c601a6d8c 100644
> --- a/drivers/gpu/drm/xe/xe_sync_types.h
> +++ b/drivers/gpu/drm/xe/xe_sync_types.h
> @@ -7,12 +7,28 @@
>  #define _XE_SYNC_TYPES_H_
>  
>  #include <linux/types.h>
> +#include <linux/spinlock.h>
> +#include <linux/kref.h>
> +#include <linux/dma-fence-array.h>
>  
> -struct drm_syncobj;
> -struct dma_fence;
> -struct dma_fence_chain;
> -struct drm_xe_sync;
> -struct user_fence;
> +struct xe_eudebug;
> +
> +struct xe_user_fence {
> +	struct xe_device *xe;
> +	struct kref refcount;
> +	struct dma_fence_cb cb;
> +	struct work_struct worker;
> +	struct mm_struct *mm;
> +	u64 __user *addr;
> +	u64 value;
> +	int signalled;
> +	struct {
> +		struct xe_eudebug *debugger;
> +		u64 bind_ref_seqno;
> +		u64 signalled_seqno;
> +		struct work_struct worker;
> +	} eudebug;
> +};
>  
>  struct xe_sync_entry {
>  	struct drm_syncobj *syncobj;
> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
> index 657a54b74eea..b117a892e386 100644
> --- a/drivers/gpu/drm/xe/xe_vm.c
> +++ b/drivers/gpu/drm/xe/xe_vm.c
> @@ -3049,9 +3049,11 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
>  		}
>  	}
>  
> +	xe_eudebug_vm_bind_start(vm);
> +
>  	syncs_user = u64_to_user_ptr(args->syncs);
>  	for (num_syncs = 0; num_syncs < args->num_syncs; num_syncs++) {
> -		err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs],
> +		err = xe_sync_entry_parse(xe, xef, vm, &syncs[num_syncs],
>  					  &syncs_user[num_syncs],
>  					  (xe_vm_in_lr_mode(vm) ?
>  					   SYNC_PARSE_FLAG_LR_MODE : 0) |
> diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
> index 789c8aa81c09..1875192e92bd 100644
> --- a/include/uapi/drm/xe_drm_eudebug.h
> +++ b/include/uapi/drm/xe_drm_eudebug.h
> @@ -17,6 +17,7 @@ extern "C" {
>   */
>  #define DRM_XE_EUDEBUG_IOCTL_READ_EVENT		_IO('j', 0x0)
>  #define DRM_XE_EUDEBUG_IOCTL_EU_CONTROL		_IOWR('j', 0x2, struct drm_xe_eudebug_eu_control)
> +#define DRM_XE_EUDEBUG_IOCTL_ACK_EVENT		_IOW('j', 0x4, struct drm_xe_eudebug_ack_event)
>  
>  /* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
>  struct drm_xe_eudebug_event {
> @@ -31,7 +32,8 @@ struct drm_xe_eudebug_event {
>  #define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION	5
>  #define DRM_XE_EUDEBUG_EVENT_VM_BIND		6
>  #define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP		7
> -#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_OP
> +#define DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE	8
> +#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE
>  
>  	__u16 flags;
>  #define DRM_XE_EUDEBUG_EVENT_CREATE		(1 << 0)
> @@ -158,6 +160,17 @@ struct drm_xe_eudebug_event_vm_bind_op {
>  	__u64 range; /* XXX: Zero for unmap all? */
>  };
>  
> +struct drm_xe_eudebug_event_vm_bind_ufence {
> +	struct drm_xe_eudebug_event base;
> +	__u64 vm_bind_ref_seqno; /* *_event_vm_bind.base.seqno */
> +};
> +
> +struct drm_xe_eudebug_ack_event {
> +	__u32 type;
> +	__u32 flags; /* MBZ */
> +	__u64 seqno;
> +};
> +
>  #if defined(__cplusplus)
>  }
>  #endif
> -- 
> 2.34.1
> 


More information about the Intel-xe mailing list