[PATCH 13/21] drm/xe/eudebug: Add UFENCE events with acks
Matthew Brost
matthew.brost at intel.com
Wed Jul 31 01:33:03 UTC 2024
On Tue, Jul 30, 2024 at 05:05:30PM +0300, Mika Kuoppala wrote:
> Matthew Brost <matthew.brost at intel.com> writes:
>
> > 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.
>
> This is the seqno of event that was associated with ufence. If userspace
> does multiple binds with ufences, it can then pinpoint, with ack ioctl,
> the particular bind it wants to be released, with this seqno.
>
> And userspace can ack out of sequence. As it can potentially
> receive events out of sequence.
>
> Would it help if it would be event_seqno instead of just seqno?
If userspace can ack out of sequence, I'd rename it 'event_id'.
So s/events.seqno/events.id too.
Does that work?
Matt
>
> -Mika
>
> >
> > 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