From: Dominik Grzegorzek <dominik.grzegorzek@xxxxxxxxx> Ad a part of eu debug feature introduce debug metadata objects. These are to be used to pass metadata between client and debugger, by attaching them to vm_bind operations. todo: WORK_IN_PROGRESS_* defines need to be reworded/refined when the real usage and need is established by l0+gdb. v2: - include uapi/drm/xe_drm.h - metadata behind kconfig (Mika) - dont leak args->id on error (Matt Auld) Cc: Matthew Auld <matthew.auld@xxxxxxxxx> Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@xxxxxxxxx> Signed-off-by: Mika Kuoppala <mika.kuoppala@xxxxxxxxxxxxxxx> --- drivers/gpu/drm/xe/Makefile | 3 +- drivers/gpu/drm/xe/xe_debug_metadata.c | 107 +++++++++++++++++++ drivers/gpu/drm/xe/xe_debug_metadata.h | 50 +++++++++ drivers/gpu/drm/xe/xe_debug_metadata_types.h | 25 +++++ drivers/gpu/drm/xe/xe_device.c | 5 + drivers/gpu/drm/xe/xe_device.h | 2 + drivers/gpu/drm/xe/xe_device_types.h | 7 ++ drivers/gpu/drm/xe/xe_eudebug.c | 13 +++ include/uapi/drm/xe_drm.h | 53 ++++++++- 9 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata.c create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata.h create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata_types.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 33f457e4fcd3..e7dc299ea178 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -117,7 +117,8 @@ xe-y += xe_bb.o \ xe_wa.o \ xe_wopcm.o -xe-$(CONFIG_DRM_XE_EUDEBUG) += xe_eudebug.o +xe-$(CONFIG_DRM_XE_EUDEBUG) += xe_eudebug.o \ + xe_debug_metadata.o xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o diff --git a/drivers/gpu/drm/xe/xe_debug_metadata.c b/drivers/gpu/drm/xe/xe_debug_metadata.c new file mode 100644 index 000000000000..1dfed9aed285 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_debug_metadata.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ +#include "xe_debug_metadata.h" + +#include <drm/drm_device.h> +#include <drm/drm_file.h> +#include <uapi/drm/xe_drm.h> + +#include "xe_device.h" +#include "xe_macros.h" + +static void xe_debug_metadata_release(struct kref *ref) +{ + struct xe_debug_metadata *mdata = container_of(ref, struct xe_debug_metadata, refcount); + + kvfree(mdata->ptr); + kfree(mdata); +} + +void xe_debug_metadata_put(struct xe_debug_metadata *mdata) +{ + kref_put(&mdata->refcount, xe_debug_metadata_release); +} + +int xe_debug_metadata_create_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file) +{ + struct xe_device *xe = to_xe_device(dev); + struct xe_file *xef = to_xe_file(file); + struct drm_xe_debug_metadata_create *args = data; + struct xe_debug_metadata *mdata; + int err; + u32 id; + + if (XE_IOCTL_DBG(xe, args->extensions)) + return -EINVAL; + + if (XE_IOCTL_DBG(xe, args->type > DRM_XE_DEBUG_METADATA_PROGRAM_MODULE)) + return -EINVAL; + + if (XE_IOCTL_DBG(xe, !args->user_addr || !args->len)) + return -EINVAL; + + if (XE_IOCTL_DBG(xe, !access_ok(u64_to_user_ptr(args->user_addr), args->len))) + return -EFAULT; + + mdata = kzalloc(sizeof(*mdata), GFP_KERNEL); + if (!mdata) + return -ENOMEM; + + mdata->len = args->len; + mdata->type = args->type; + + mdata->ptr = kvmalloc(mdata->len, GFP_KERNEL); + if (!mdata->ptr) { + kfree(mdata); + return -ENOMEM; + } + kref_init(&mdata->refcount); + + err = copy_from_user(mdata->ptr, u64_to_user_ptr(args->user_addr), mdata->len); + if (err) { + err = -EFAULT; + goto put_mdata; + } + + mutex_lock(&xef->eudebug.metadata.lock); + err = xa_alloc(&xef->eudebug.metadata.xa, &id, mdata, xa_limit_32b, GFP_KERNEL); + mutex_unlock(&xef->eudebug.metadata.lock); + + if (err) + goto put_mdata; + + args->metadata_id = id; + + return 0; + +put_mdata: + xe_debug_metadata_put(mdata); + return err; +} + +int xe_debug_metadata_destroy_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file) +{ + struct xe_device *xe = to_xe_device(dev); + struct xe_file *xef = to_xe_file(file); + struct drm_xe_debug_metadata_destroy * const args = data; + struct xe_debug_metadata *mdata; + + if (XE_IOCTL_DBG(xe, args->extensions)) + return -EINVAL; + + mutex_lock(&xef->eudebug.metadata.lock); + mdata = xa_erase(&xef->eudebug.metadata.xa, args->metadata_id); + mutex_unlock(&xef->eudebug.metadata.lock); + if (XE_IOCTL_DBG(xe, !mdata)) + return -ENOENT; + + xe_debug_metadata_put(mdata); + + return 0; +} diff --git a/drivers/gpu/drm/xe/xe_debug_metadata.h b/drivers/gpu/drm/xe/xe_debug_metadata.h new file mode 100644 index 000000000000..3266c25e657e --- /dev/null +++ b/drivers/gpu/drm/xe/xe_debug_metadata.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _XE_DEBUG_METADATA_H_ +#define _XE_DEBUG_METADATA_H_ + +struct drm_device; +struct drm_file; + +#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG) + +#include "xe_debug_metadata_types.h" + +void xe_debug_metadata_put(struct xe_debug_metadata *mdata); + +int xe_debug_metadata_create_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file); + +int xe_debug_metadata_destroy_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file); +#else /* CONFIG_DRM_XE_EUDEBUG */ + +#include <linux/errno.h> + +struct xe_debug_metadata; + +static inline void xe_debug_metadata_put(struct xe_debug_metadata *mdata) { } + +static inline int xe_debug_metadata_create_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file) +{ + return -EOPNOTSUPP; +} + +static inline int xe_debug_metadata_destroy_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file) +{ + return -EOPNOTSUPP; +} + +#endif /* CONFIG_DRM_XE_EUDEBUG */ + + +#endif diff --git a/drivers/gpu/drm/xe/xe_debug_metadata_types.h b/drivers/gpu/drm/xe/xe_debug_metadata_types.h new file mode 100644 index 000000000000..624852920f58 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_debug_metadata_types.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _XE_DEBUG_METADATA_TYPES_H_ +#define _XE_DEBUG_METADATA_TYPES_H_ + +#include <linux/kref.h> + +struct xe_debug_metadata { + /** @type: type of given metadata */ + u64 type; + + /** @ptr: copy of userptr, given as a metadata payload */ + void *ptr; + + /** @len: length, in bytes of the metadata */ + u64 len; + + /** @ref: reference count */ + struct kref refcount; +}; + +#endif diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index dc0336215912..a7a715475184 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -25,6 +25,7 @@ #include "xe_bo.h" #include "xe_debugfs.h" #include "xe_devcoredump.h" +#include "xe_debug_metadata.h" #include "xe_dma_buf.h" #include "xe_drm_client.h" #include "xe_drv.h" @@ -197,6 +198,10 @@ static const struct drm_ioctl_desc xe_ioctls[] = { DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(XE_OBSERVATION, xe_observation_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(XE_EUDEBUG_CONNECT, xe_eudebug_connect_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(XE_DEBUG_METADATA_CREATE, xe_debug_metadata_create_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(XE_DEBUG_METADATA_DESTROY, xe_debug_metadata_destroy_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.h b/drivers/gpu/drm/xe/xe_device.h index 088831a6b863..f89f1f0fc25e 100644 --- a/drivers/gpu/drm/xe/xe_device.h +++ b/drivers/gpu/drm/xe/xe_device.h @@ -218,6 +218,8 @@ static inline int xe_eudebug_needs_lock(const unsigned int cmd) case DRM_XE_EXEC_QUEUE_CREATE: case DRM_XE_EXEC_QUEUE_DESTROY: case DRM_XE_EUDEBUG_CONNECT: + case DRM_XE_DEBUG_METADATA_CREATE: + case DRM_XE_DEBUG_METADATA_DESTROY: return 1; } diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 7b893a86d83f..4ab9f06eba2d 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -684,6 +684,13 @@ struct xe_file { struct { /** @client_link: list entry in xe_device.clients.list */ struct list_head client_link; + + struct { + /** @xa: xarray to store debug metadata */ + struct xarray xa; + /** @lock: protects debug metadata xarray */ + struct mutex lock; + } metadata; } eudebug; #endif }; diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c index e5949e4dcad8..e9092ed0b344 100644 --- a/drivers/gpu/drm/xe/xe_eudebug.c +++ b/drivers/gpu/drm/xe/xe_eudebug.c @@ -21,6 +21,7 @@ #include "xe_assert.h" #include "xe_bo.h" #include "xe_device.h" +#include "xe_debug_metadata.h" #include "xe_eudebug.h" #include "xe_eudebug_types.h" #include "xe_exec_queue.h" @@ -2141,6 +2142,8 @@ void xe_eudebug_file_open(struct xe_file *xef) struct xe_eudebug *d; INIT_LIST_HEAD(&xef->eudebug.client_link); + mutex_init(&xef->eudebug.metadata.lock); + xa_init_flags(&xef->eudebug.metadata.xa, XA_FLAGS_ALLOC1); down_read(&xef->xe->eudebug.discovery_lock); @@ -2158,12 +2161,22 @@ void xe_eudebug_file_open(struct xe_file *xef) void xe_eudebug_file_close(struct xe_file *xef) { struct xe_eudebug *d; + unsigned long idx; + struct xe_debug_metadata *mdata; down_read(&xef->xe->eudebug.discovery_lock); d = xe_eudebug_get(xef); if (d) xe_eudebug_event_put(d, client_destroy_event(d, xef)); + mutex_lock(&xef->eudebug.metadata.lock); + xa_for_each(&xef->eudebug.metadata.xa, idx, mdata) + xe_debug_metadata_put(mdata); + mutex_unlock(&xef->eudebug.metadata.lock); + + xa_destroy(&xef->eudebug.metadata.xa); + mutex_destroy(&xef->eudebug.metadata.lock); + spin_lock(&xef->xe->clients.lock); list_del_init(&xef->eudebug.client_link); spin_unlock(&xef->xe->clients.lock); diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index d0b9ef0799b2..1a452a8d2a2a 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -103,7 +103,8 @@ extern "C" { #define DRM_XE_WAIT_USER_FENCE 0x0a #define DRM_XE_OBSERVATION 0x0b #define DRM_XE_EUDEBUG_CONNECT 0x0c - +#define DRM_XE_DEBUG_METADATA_CREATE 0x0d +#define DRM_XE_DEBUG_METADATA_DESTROY 0x0e /* Must be kept compact -- no holes */ #define DRM_IOCTL_XE_DEVICE_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_DEVICE_QUERY, struct drm_xe_device_query) @@ -119,6 +120,8 @@ extern "C" { #define DRM_IOCTL_XE_WAIT_USER_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_WAIT_USER_FENCE, struct drm_xe_wait_user_fence) #define DRM_IOCTL_XE_OBSERVATION DRM_IOW(DRM_COMMAND_BASE + DRM_XE_OBSERVATION, struct drm_xe_observation_param) #define DRM_IOCTL_XE_EUDEBUG_CONNECT DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_EUDEBUG_CONNECT, struct drm_xe_eudebug_connect) +#define DRM_IOCTL_XE_DEBUG_METADATA_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_DEBUG_METADATA_CREATE, struct drm_xe_debug_metadata_create) +#define DRM_IOCTL_XE_DEBUG_METADATA_DESTROY DRM_IOW(DRM_COMMAND_BASE + DRM_XE_DEBUG_METADATA_DESTROY, struct drm_xe_debug_metadata_destroy) /** * DOC: Xe IOCTL Extensions @@ -1733,6 +1736,54 @@ struct drm_xe_eudebug_connect { __u32 version; /* output: current ABI (ioctl / events) version */ }; +/* + * struct drm_xe_debug_metadata_create - Create debug metadata + * + * Add a region of user memory to be marked as debug metadata. + * When the debugger attaches, the metadata regions will be delivered + * for debugger. Debugger can then map these regions to help decode + * the program state. + * + * Returns handle to created metadata entry. + */ +struct drm_xe_debug_metadata_create { + /** @extensions: Pointer to the first extension struct, if any */ + __u64 extensions; + +#define DRM_XE_DEBUG_METADATA_ELF_BINARY 0 +#define DRM_XE_DEBUG_METADATA_PROGRAM_MODULE 1 +#define WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_MODULE_AREA 2 +#define WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SBA_AREA 3 +#define WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA 4 +#define WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_NUM (1 + \ + WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA) + + /** @type: Type of metadata */ + __u64 type; + + /** @user_addr: pointer to start of the metadata */ + __u64 user_addr; + + /** @len: length, in bytes of the medata */ + __u64 len; + + /** @metadata_id: created metadata handle (out) */ + __u32 metadata_id; +}; + +/** + * struct drm_xe_debug_metadata_destroy - Destroy debug metadata + * + * Destroy debug metadata. + */ +struct drm_xe_debug_metadata_destroy { + /** @extensions: Pointer to the first extension struct, if any */ + __u64 extensions; + + /** @metadata_id: metadata handle to destroy */ + __u32 metadata_id; +}; + #include "xe_drm_eudebug.h" #if defined(__cplusplus) -- 2.43.0