Re: [PATCH 4/4] drm/xe: Add watch_queue-based device event notification

From: Thomas Hellström

Date: Mon Jul 20 2026 - 06:47:02 EST


On Sun, 2026-07-19 at 21:29 -0700, Matthew Brost wrote:
> On Fri, Jun 12, 2026 at 03:53:40PM +0200, Thomas Hellström wrote:
> > Add a watch_queue notification channel tied to struct xe_file so
> > that
> > userspace can subscribe to asynchronous GPU device events via the
> > general kernel notification mechanism.
> >
> > Introduce DRM_IOCTL_XE_WATCH_QUEUE to let userspace subscribe a
> > notification pipe (opened with pipe2(O_NOTIFICATION_PIPE)) to the
> > device
> > event stream.  Embed the watch_id field (0-255) in the
> > WATCH_INFO_ID
> > field of every notification, allowing multiple watches to share a
> > single
> > pipe and be told apart by the reader.
> >
> > Deliver notifications as struct drm_xe_watch_notification records,
> > with
> > type always set to WATCH_TYPE_DRM_XE_NOTIFY and subtype drawn from
> > enum
> > drm_xe_watch_event.  Define DRM_XE_WATCH_EVENT_VM_ERR as the first
> > event, posted by the preempt-rebind worker when a VM encounters an
> > unrecoverable error.  Expose xe_watch_queue_post_vm_err_event() as
> > the
> > in-kernel posting API.
> >
> > Add event definitions in a separate uapi header,
> > <drm/xe_drm_events.h>.
> > The main reason is that the header needs to include
> > <linux/watch_queue.h>
> > which in turn includes <linux/fcntl.h> which may conflict with the
> > system <fcntl.h>. Hence user-space must pay special attention when
> > including this file.
> >
> > Assisted-by: GitHub_Copilot:claude-sonnet-4.6
> > Signed-off-by: Thomas Hellström <thomas.hellstrom@xxxxxxxxxxxxxxx>
> > ---
> >  MAINTAINERS                          |   1 +
> >  drivers/gpu/drm/xe/Kconfig           |   1 +
> >  drivers/gpu/drm/xe/Makefile          |   1 +
> >  drivers/gpu/drm/xe/xe_device.c       |   7 ++
> >  drivers/gpu/drm/xe/xe_device_types.h |   6 ++
> >  drivers/gpu/drm/xe/xe_vm.c           |   4 +
> >  drivers/gpu/drm/xe/xe_vm_types.h     |   2 +
> >  drivers/gpu/drm/xe/xe_watch_queue.c  | 111
> > +++++++++++++++++++++++++++
> >  drivers/gpu/drm/xe/xe_watch_queue.h  |  20 +++++
> >  include/uapi/drm/xe_drm.h            |  45 +++++++++++
> >  include/uapi/drm/xe_drm_events.h     |  62 +++++++++++++++
> >  11 files changed, 260 insertions(+)
> >  create mode 100644 drivers/gpu/drm/xe/xe_watch_queue.c
> >  create mode 100644 drivers/gpu/drm/xe/xe_watch_queue.h
> >  create mode 100644 include/uapi/drm/xe_drm_events.h
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 8c0d9965c636..b7e02cfa692b 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -12900,6 +12900,7 @@ F: Documentation/gpu/xe/
> >  F: drivers/gpu/drm/xe/
> >  F: include/drm/intel/
> >  F: include/uapi/drm/xe_drm.h
> > +F: include/uapi/drm/xe_drm_events.h
> >  
> >  INTEL ELKHART LAKE PSE I/O DRIVER
> >  M: Raag Jadav <raag.jadav@xxxxxxxxx>
> > diff --git a/drivers/gpu/drm/xe/Kconfig
> > b/drivers/gpu/drm/xe/Kconfig
> > index 4d7dcaff2b91..dbdc2fb49c53 100644
> > --- a/drivers/gpu/drm/xe/Kconfig
> > +++ b/drivers/gpu/drm/xe/Kconfig
> > @@ -25,6 +25,7 @@ config DRM_XE
> >   select DRM_MIPI_DSI
> >   select RELAY
> >   select IRQ_WORK
> > + select WATCH_QUEUE
> >   # xe depends on ACPI_VIDEO when ACPI is enabled
> >   # but for select to work, need to select ACPI_VIDEO's
> > dependencies, ick
> >   select BACKLIGHT_CLASS_DEVICE if ACPI
> > diff --git a/drivers/gpu/drm/xe/Makefile
> > b/drivers/gpu/drm/xe/Makefile
> > index 8e7b146880f4..fc8b4023a044 100644
> > --- a/drivers/gpu/drm/xe/Makefile
> > +++ b/drivers/gpu/drm/xe/Makefile
> > @@ -150,6 +150,7 @@ xe-y += xe_bb.o \
> >   xe_vsec.o \
> >   xe_wa.o \
> >   xe_wait_user_fence.o \
> > + xe_watch_queue.o \
> >   xe_wopcm.o
> >  
> >  xe-$(CONFIG_I2C) += xe_i2c.o
> > diff --git a/drivers/gpu/drm/xe/xe_device.c
> > b/drivers/gpu/drm/xe/xe_device.c
> > index 867d7c55dc03..788ef2fbd6e5 100644
> > --- a/drivers/gpu/drm/xe/xe_device.c
> > +++ b/drivers/gpu/drm/xe/xe_device.c
> > @@ -9,6 +9,7 @@
> >  #include <linux/delay.h>
> >  #include <linux/fault-inject.h>
> >  #include <linux/units.h>
> > +#include <linux/watch_queue.h>
> >  
> >  #include <drm/drm_client.h>
> >  #include <drm/drm_gem_ttm_helper.h>
> > @@ -77,6 +78,7 @@
> >  #include "xe_vsec.h"
> >  #include "xe_wait_user_fence.h"
> >  #include "xe_wa.h"
> > +#include "xe_watch_queue.h"
> >  
> >  #include <generated/xe_device_wa_oob.h>
> >  #include <generated/xe_wa_oob.h>
> > @@ -112,6 +114,8 @@ static int xe_file_open(struct drm_device *dev,
> > struct drm_file *file)
> >   file->driver_priv = xef;
> >   kref_init(&xef->refcount);
> >  
> > + init_watch_list(&xef->watch_list, NULL);
> > +
> >   task = get_pid_task(rcu_access_pointer(file->pid),
> > PIDTYPE_PID);
> >   if (task) {
> >   xef->process_name = kstrdup(task->comm,
> > GFP_KERNEL);
> > @@ -126,6 +130,8 @@ static void xe_file_destroy(struct kref *ref)
> >  {
> >   struct xe_file *xef = container_of(ref, struct xe_file,
> > refcount);
> >  
> > + remove_watch_from_object(&xef->watch_list, NULL, 0, true);
> > +
> >   xa_destroy(&xef->exec_queue.xa);
> >   mutex_destroy(&xef->exec_queue.lock);
> >   xa_destroy(&xef->vm.xa);
> > @@ -216,6 +222,7 @@ static const struct drm_ioctl_desc xe_ioctls[]
> > = {
> >   DRM_IOCTL_DEF_DRV(XE_VM_GET_PROPERTY,
> > xe_vm_get_property_ioctl,
> >     DRM_RENDER_ALLOW),
> >   DRM_IOCTL_DEF_DRV(XE_VM_RESTART, xe_vm_restart_ioctl,
> > DRM_RENDER_ALLOW),
> > + DRM_IOCTL_DEF_DRV(XE_WATCH_QUEUE, xe_watch_queue_ioctl,
> > DRM_RENDER_ALLOW),
> >  };
> >  
> >  static long xe_drm_ioctl(struct file *file, unsigned int cmd,
> > unsigned long arg)
> > diff --git a/drivers/gpu/drm/xe/xe_device_types.h
> > b/drivers/gpu/drm/xe/xe_device_types.h
> > index 32dd2ffbc796..ca726ada30a7 100644
> > --- a/drivers/gpu/drm/xe/xe_device_types.h
> > +++ b/drivers/gpu/drm/xe/xe_device_types.h
> > @@ -11,6 +11,7 @@
> >  #include <drm/drm_device.h>
> >  #include <drm/drm_file.h>
> >  #include <drm/ttm/ttm_device.h>
> > +#include <linux/watch_queue.h>
> >  
> >  #include "xe_devcoredump_types.h"
> >  #include "xe_drm_ras_types.h"
> > @@ -632,6 +633,11 @@ struct xe_file {
> >  
> >   /** @refcount: ref count of this xe file */
> >   struct kref refcount;
> > +
> > +#ifdef CONFIG_WATCH_QUEUE
> > + /** @watch_list: per-file notification source for device
> > events */
> > + struct watch_list watch_list;
> > +#endif
> >  };
> >  
> >  #endif
> > diff --git a/drivers/gpu/drm/xe/xe_vm.c
> > b/drivers/gpu/drm/xe/xe_vm.c
> > index b69a2e5bd9c9..232de0d948d2 100644
> > --- a/drivers/gpu/drm/xe/xe_vm.c
> > +++ b/drivers/gpu/drm/xe/xe_vm.c
> > @@ -13,6 +13,7 @@
> >  #include <drm/drm_print.h>
> >  #include <drm/ttm/ttm_tt.h>
> >  #include <uapi/drm/xe_drm.h>
> > +#include <uapi/drm/xe_drm_events.h>
> >  #include <linux/ascii85.h>
> >  #include <linux/delay.h>
> >  #include <linux/kthread.h>
> > @@ -45,6 +46,7 @@
> >  #include "xe_trace_bo.h"
> >  #include "xe_vm_madvise.h"
> >  #include "xe_wa.h"
> > +#include "xe_watch_queue.h"
> >  
> >  #ifdef CONFIG_FAULT_INJECTION
> >  static DECLARE_FAULT_ATTR(rebind_enospc);
> > @@ -584,6 +586,7 @@ static void preempt_rebind_work_func(struct
> > work_struct *w)
> >   }
> >  
> >   if (err) {
> > + xe_watch_queue_post_vm_err_event(vm->xef, vm->id,
> > err);
> >   if ((err == -ENOMEM || err == -ENOSPC) &&
> > xe_vm_is_restartable(vm)) {
> >   vm->preempt.rebind_deactivated = true;
> >   drm_dbg(&vm->xe->drm, "Rebind deactivated
> > VM on error %pe\n",
> > @@ -2229,6 +2232,7 @@ int xe_vm_create_ioctl(struct drm_device
> > *dev, void *data,
> >   if (err)
> >   goto err_close_and_put;
> >  
> > + vm->id = id;
> >   args->vm_id = id;
> >  
> >   return 0;
> > diff --git a/drivers/gpu/drm/xe/xe_vm_types.h
> > b/drivers/gpu/drm/xe/xe_vm_types.h
> > index 7d295c3b8456..19a673099588 100644
> > --- a/drivers/gpu/drm/xe/xe_vm_types.h
> > +++ b/drivers/gpu/drm/xe/xe_vm_types.h
> > @@ -407,6 +407,8 @@ struct xe_vm {
> >   bool batch_invalidate_tlb;
> >   /** @xef: Xe file handle for tracking this VM's drm client
> > */
> >   struct xe_file *xef;
> > + /** @id: The id of the VM in the VM table of @xef. */
> > + u32 id;
> >  };
> >  
> >  /** struct xe_vma_op_map - VMA map operation */
> > diff --git a/drivers/gpu/drm/xe/xe_watch_queue.c
> > b/drivers/gpu/drm/xe/xe_watch_queue.c
> > new file mode 100644
> > index 000000000000..32763591075b
> > --- /dev/null
> > +++ b/drivers/gpu/drm/xe/xe_watch_queue.c
> > @@ -0,0 +1,111 @@
> > +// SPDX-License-Identifier: MIT
> > +/*
> > + * Copyright © 2026 Intel Corporation
> > + */
> > +
> > +#include <linux/slab.h>
> > +#include <linux/timekeeping.h>
> > +#include <linux/watch_queue.h>
> > +
> > +#include <uapi/drm/xe_drm.h>
> > +#include <uapi/drm/xe_drm_events.h>
> > +
> > +#include "xe_device.h"
> > +#include "xe_device_types.h"
> > +#include "xe_macros.h"
> > +#include "xe_watch_queue.h"
> > +
> > +/**
> > + * struct xe_watch_notification_vm_err - kernel-side VM error
> > event notification
> > + * @base: common watch notification header; type is
> > %WATCH_TYPE_DRM_XE_NOTIFY,
> > + *        subtype is %DRM_XE_WATCH_EVENT_VM_ERR
> > + * @vm_id: ID of the VM that hit error
> > + * @error_code: error code describing the error condition
> > (negative errno)
> > + * @timestamp_ns: CLOCK_MONOTONIC timestamp in nanoseconds at the
> > point the
> > + *                error was detected
> > + *
> > + * Layout mirrors &struct drm_xe_watch_notification_vm_err.
> > + */
> > +struct xe_watch_notification_vm_err {
> > + struct watch_notification base;
> > + u32 vm_id;
> > + s32 error_code;
> > + u64 timestamp_ns;
> > +};
> > +
> > +/**
> > + * xe_watch_queue_ioctl() - Subscribe a pipe to per-file device
> > event notifications
> > + * @dev: DRM device
> > + * @data: pointer to &struct drm_xe_watch_queue from userspace
> > + * @file: DRM file handle of the subscribing process
> > + *
> > + * Subscribes a notification pipe to receive Xe device events for
> > the calling
> > + * process's file handle.  Only events scoped to this file (e.g.
> > VM error on a
> > + * VM owned by this file) are delivered.  The pipe must have been
> > opened with
> > + * O_NOTIFICATION_PIPE and sized with %IOC_WATCH_QUEUE_SET_SIZE
> > before calling
> > + * this IOCTL.
> > + *
> > + * Return: 0 on success, negative errno on failure.
> > + */
> > +int xe_watch_queue_ioctl(struct drm_device *dev, void *data,
> > struct drm_file *file)
> > +{
> > + struct xe_file *xef = file->driver_priv;
> > + struct xe_device *xe = to_xe_device(dev);
> > + struct drm_xe_watch_queue *args = data;
> > + struct watch_queue *wqueue;
> > + struct watch *watch;
> > + int ret;
> > +
> > + if (XE_IOCTL_DBG(xe, args->flags || args->pad))
> > + return -EINVAL;
> > + if (XE_IOCTL_DBG(xe, args->watch_id > 0xff))
> > + return -EINVAL;
> > +
> > + wqueue = get_watch_queue(args->fd);
> > + if (XE_IOCTL_DBG(xe, IS_ERR(wqueue)))
> > + return PTR_ERR(wqueue);
> > +
> > + watch = kzalloc_obj(*watch, GFP_KERNEL | __GFP_ACCOUNT);
> > + if (XE_IOCTL_DBG(xe, !watch)) {
> > + ret = -ENOMEM;
> > + goto out_put_queue;
> > + }
> > +
> > + init_watch(watch, wqueue);
> > + watch->id = 0;
> > + watch->info_id = (u32)args->watch_id <<
> > WATCH_INFO_ID__SHIFT;
> > +
> > + ret = add_watch_to_object(watch, &xef->watch_list);
> > + if (XE_IOCTL_DBG(xe, ret))
> > + kfree(watch);
> > +
> > +out_put_queue:
> > + put_watch_queue(wqueue);
> > + return ret;
> > +}
> > +
> > +/**
> > + * xe_watch_queue_post_vm_err_event() - Post a VM error event
> > + * @xef: xe file handle that owns the VM
> > + * @vm_id: userspace ID of the VM that hit error
> > + * @error_code: error code describing the error condition
> > (negative errno)
> > + *
> > + * Posts a %DRM_XE_WATCH_EVENT_VM_ERR notification carrying @vm_id
> > and
> > + * @error_code to every pipe that @xef has subscribed via
> > + * %DRM_IOCTL_XE_WATCH_QUEUE.  Only the owning process is
> > notified,
> > + * preventing information leaks to other clients.
> > + */
> > +void xe_watch_queue_post_vm_err_event(struct xe_file *xef, u32
> > vm_id,
> > +       int error_code)
> > +{
> > + struct xe_watch_notification_vm_err n = {};
> > +
> > + n.base.type    = WATCH_TYPE_DRM_XE_NOTIFY;
> > + n.base.subtype = DRM_XE_WATCH_EVENT_VM_ERR;
> > + n.base.info    = watch_sizeof(struct
> > xe_watch_notification_vm_err);
> > + n.vm_id        = vm_id;
> > + n.error_code   = error_code;
> > + n.timestamp_ns = ktime_get_ns();
> > +
> > + post_watch_notification(&xef->watch_list, &n.base,
> > current_cred(), 0);
>
> Is this reclaim safe (i.e., could we post a watch notification in
> direct
> reclaim from our shrinker)? From my look, I think the answer is yes.
> I
> ask because whatever we land here, I think the answer must be KMD-
> >UMD
> events are reclaim safe.

>From my understanding, inside post_watch_notification() there is no
memory allocation, and the only locks that become tainted are
spinlocks, so this should be safe, and tainting the spinlocks would not
affect any existing or future users in the tree.

/Thomas


>
> Matt
>
> > +}
> > diff --git a/drivers/gpu/drm/xe/xe_watch_queue.h
> > b/drivers/gpu/drm/xe/xe_watch_queue.h
> > new file mode 100644
> > index 000000000000..ad199ee68205
> > --- /dev/null
> > +++ b/drivers/gpu/drm/xe/xe_watch_queue.h
> > @@ -0,0 +1,20 @@
> > +/* SPDX-License-Identifier: MIT */
> > +/*
> > + * Copyright © 2026 Intel Corporation
> > + */
> > +
> > +#ifndef _XE_WATCH_QUEUE_H_
> > +#define _XE_WATCH_QUEUE_H_
> > +
> > +#include <linux/types.h>
> > +
> > +struct drm_device;
> > +struct drm_file;
> > +struct xe_file;
> > +
> > +int xe_watch_queue_ioctl(struct drm_device *dev, void *data,
> > + struct drm_file *file);
> > +void xe_watch_queue_post_vm_err_event(struct xe_file *xef, u32
> > vm_id,
> > +       int error_code);
> > +
> > +#endif /* _XE_WATCH_QUEUE_H_ */
> > diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
> > index 8d5e3f06b8d4..0083dd712f7e 100644
> > --- a/include/uapi/drm/xe_drm.h
> > +++ b/include/uapi/drm/xe_drm.h
> > @@ -86,6 +86,7 @@ extern "C" {
> >   *  - &DRM_IOCTL_XE_EXEC_QUEUE_SET_PROPERTY
> >   *  - &DRM_IOCTL_XE_VM_GET_PROPERTY
> >   *  - &DRM_IOCTL_XE_VM_RESTART
> > + *  - &DRM_IOCTL_XE_WATCH_QUEUE
> >   */
> >  
> >  /*
> > @@ -112,6 +113,7 @@ extern "C" {
> >  #define DRM_XE_EXEC_QUEUE_SET_PROPERTY 0x0e
> >  #define DRM_XE_VM_GET_PROPERTY 0x0f
> >  #define DRM_XE_VM_RESTART 0x10
> > +#define DRM_XE_WATCH_QUEUE 0x11
> >  
> >  /* Must be kept compact -- no holes */
> >  
> > @@ -132,6 +134,7 @@ extern "C" {
> >  #define
> > DRM_IOCTL_XE_EXEC_QUEUE_SET_PROPERTY DRM_IOW(DRM_COMMAND_BASE + DRM_XE_EXEC_QUEUE_SET_PROPERTY,structdrm_xe_exec_queue_set_property)
> >  #define
> > DRM_IOCTL_XE_VM_GET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_VM_GET_PROPERTY,structdrm_xe_vm_get_property)
> >  #define
> > DRM_IOCTL_XE_VM_RESTART DRM_IOW(DRM_COMMAND_BASE + DRM_XE_VM_RESTART,structdrm_xe_vm_restart)
> > +#define
> > DRM_IOCTL_XE_WATCH_QUEUE DRM_IOW(DRM_COMMAND_BASE + DRM_XE_WATCH_QUEUE,structdrm_xe_watch_queue)
> >  
> >  /**
> >   * DOC: Xe IOCTL Extensions
> > @@ -2653,6 +2656,48 @@ enum drm_xe_ras_error_component {
> >   [DRM_XE_RAS_ERR_COMP_SOC_INTERNAL] = "soc-
> > internal" \
> >  }
> >  
> > +/**
> > + * DOC: DRM_XE_WATCH_QUEUE
> > + *
> > + * Subscribe a notification pipe to receive device events for the
> > calling
> > + * process's DRM file handle.  Events are scoped to the
> > subscribing file:
> > + * only events that belong to that file (for example, VM error on
> > a VM created
> > + * through the same file) are delivered, preventing information
> > leaks between
> > + * processes sharing the same GPU device.
> > + *
> > + * The pipe must first be opened with O_NOTIFICATION_PIPE (i.e.
> > O_EXCL passed
> > + * to pipe2()) and sized via %IOC_WATCH_QUEUE_SET_SIZE before
> > subscribing.
> > + *
> > + * Events are delivered as notification records read from the
> > pipe.  The
> > + * @watch_id field is embedded in the notification info field and
> > can be used
> > + * to distinguish multiple watches sharing a pipe.
> > + *
> > + * Currently defined event subtypes:
> > + *  - %DRM_XE_WATCH_EVENT_VM_ERR - a VM owned by this file has
> > encountered an error
> > + */
> > +
> > +/**
> > + * struct drm_xe_watch_queue - subscribe to device event
> > notifications
> > + *
> > + * Used with %DRM_IOCTL_XE_WATCH_QUEUE.  Notifications are scoped
> > to the
> > + * DRM file handle used to issue this IOCTL.
> > + */
> > +struct drm_xe_watch_queue {
> > + /** @fd: file descriptor of pipe opened with
> > O_NOTIFICATION_PIPE */
> > + __u32 fd;
> > +
> > + /**
> > + * @watch_id: identifier (0–255) embedded in the watch
> > notification
> > + * info field; allows multiplexing several watches on one
> > pipe
> > + */
> > + __u32 watch_id;
> > +
> > + /** @flags: must be zero */
> > + __u32 flags;
> > +
> > + /** @pad: reserved, must be zero */
> > + __u32 pad;
> > +};
> >  #if defined(__cplusplus)
> >  }
> >  #endif
> > diff --git a/include/uapi/drm/xe_drm_events.h
> > b/include/uapi/drm/xe_drm_events.h
> > new file mode 100644
> > index 000000000000..6cc7528bfb9b
> > --- /dev/null
> > +++ b/include/uapi/drm/xe_drm_events.h
> > @@ -0,0 +1,62 @@
> > +/* SPDX-License-Identifier: MIT */
> > +/*
> > + * Copyright © 2026 Intel Corporation
> > + */
> > +
> > +#ifndef _UAPI_XE_DRM_EVENTS_H_
> > +#define _UAPI_XE_DRM_EVENTS_H_
> > +
> > +#include <linux/types.h>
> > +#include <linux/watch_queue.h>
> > +
> > +#if defined(__cplusplus)
> > +extern "C" {
> > +#endif
> > +
> > +/**
> > + * enum drm_xe_watch_event - Xe device watch event subtypes
> > + *
> > + * Subtypes for notifications delivered via
> > %WATCH_TYPE_DRM_XE_NOTIFY when
> > + * reading from a pipe subscribed with %DRM_IOCTL_XE_WATCH_QUEUE.
> > + */
> > +enum drm_xe_watch_event {
> > + /**
> > + * @DRM_XE_WATCH_EVENT_VM_ERR: a VM has encountered an
> > error.
> > + *
> > + * Indicates that a fatal or resource error occurred
> > within the given
> > + * VM.  The vm_id of the affected VM is carried in the
> > + * @drm_xe_watch_notification_vm_err::vm_id field of the
> > extended
> > + * notification record.
> > + */
> > + DRM_XE_WATCH_EVENT_VM_ERR = 0,
> > +};
> > +
> > +/**
> > + * struct drm_xe_watch_notification_vm_err - VM error event
> > notification
> > + *
> > + * Notification record delivered for %DRM_XE_WATCH_EVENT_VM_ERR.
> > + * The record type is always %WATCH_TYPE_DRM_XE_NOTIFY and the
> > subtype is
> > + * %DRM_XE_WATCH_EVENT_VM_ERR.
> > + */
> > +struct drm_xe_watch_notification_vm_err {
> > + /** @base: common watch notification header */
> > + struct watch_notification base;
> > +
> > + /** @vm_id: ID of the VM that encountered an error */
> > + __u32 vm_id;
> > +
> > + /** @error_code: error code describing the error condition
> > (negative errno) */
> > + __s32 error_code;
> > +
> > + /**
> > + * @timestamp_ns: CLOCK_MONOTONIC timestamp in nanoseconds
> > at the
> > + * point the error was detected
> > + */
> > + __u64 timestamp_ns;
> > +};
> > +
> > +#if defined(__cplusplus)
> > +}
> > +#endif
> > +
> > +#endif /* _UAPI_XE_DRM_EVENTS_H_ */
> > --
> > 2.54.0
> >