This patch set implements the MSM_WAIT_IOVA ioctl which lets
userspace sleep until the value at a given iova reaches a certain
condition. This is needed in turnip to implement the
VK_QUERY_RESULT_WAIT_BIT flag for vkGetQueryPoolResults.
First, we add a GPU-wide wait queue that is signaled on all IRQs.
We can then wait on this wait queue inside MSM_WAIT_IOVA until the
condition is met.
The corresponding merge request in mesa can be found at:
https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3279
Changes in v2:
* Updated cleanup logic on error
* Added a mask
* 32 bit values by default
Changes in v3:
* Fixed a bug where the mask was being applied incorrectly
Brian Ho (2):
drm/msm: Add a GPU-wide wait queue
drm/msm: Add MSM_WAIT_IOVA ioctl
drivers/gpu/drm/msm/msm_drv.c | 61 +++++++++++++++++++++++++++++++++--
drivers/gpu/drm/msm/msm_gpu.c | 4 +++
drivers/gpu/drm/msm/msm_gpu.h | 3 ++
include/uapi/drm/msm_drm.h | 14 ++++++++
4 files changed, 80 insertions(+), 2 deletions(-)
--
2.25.0.341.g760bfbb309-goog
Implements an ioctl to wait until a value at a given iova is greater
than or equal to a supplied value.
This will initially be used by turnip (open-source Vulkan driver for
QC in mesa) for occlusion queries where the userspace driver can
block on a query becoming available before continuing via
vkGetQueryPoolResults.
Change-Id: I1413fc34b7eb8ba569c765ad65126e9024341730
Signed-off-by: Brian Ho <[email protected]>
---
drivers/gpu/drm/msm/msm_drv.c | 61 +++++++++++++++++++++++++++++++++--
include/uapi/drm/msm_drm.h | 14 ++++++++
2 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index c84f0a8b3f2c..f746ac86bca3 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -36,10 +36,11 @@
* MSM_GEM_INFO ioctl.
* - 1.4.0 - softpin, MSM_RELOC_BO_DUMP, and GEM_INFO support to set/get
* GEM object's debug name
- * - 1.5.0 - Add SUBMITQUERY_QUERY ioctl
+ * - 1.5.0 - Add SUBMITQUEUE_QUERY ioctl
+ * - 1.6.0 - Add WAIT_IOVA ioctl
*/
#define MSM_VERSION_MAJOR 1
-#define MSM_VERSION_MINOR 5
+#define MSM_VERSION_MINOR 6
#define MSM_VERSION_PATCHLEVEL 0
static const struct drm_mode_config_funcs mode_config_funcs = {
@@ -952,6 +953,61 @@ static int msm_ioctl_submitqueue_close(struct drm_device *dev, void *data,
return msm_submitqueue_remove(file->driver_priv, id);
}
+static int msm_ioctl_wait_iova(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ struct drm_msm_wait_iova *args = data;
+ ktime_t timeout = to_ktime(args->timeout);
+ unsigned long remaining_jiffies = timeout_to_jiffies(&timeout);
+ struct msm_gpu *gpu = priv->gpu;
+ void *base_vaddr;
+ uint64_t *vaddr;
+ int ret;
+
+ if (args->pad)
+ return -EINVAL;
+
+ if (!gpu)
+ return -ENODEV;
+
+ obj = drm_gem_object_lookup(file, args->handle);
+ if (!obj)
+ return -ENOENT;
+
+ if (args->offset + sizeof(*vaddr) < args->offset ||
+ args->offset + sizeof(*vaddr) > obj->size) {
+ ret = -EINVAL;
+ goto err_put_gem_object;
+ }
+
+ base_vaddr = msm_gem_get_vaddr(obj);
+ if (IS_ERR(base_vaddr)) {
+ ret = PTR_ERR(base_vaddr);
+ goto err_put_gem_object;
+ }
+
+ vaddr = base_vaddr + args->offset;
+
+ /* TODO: Support 64 bit reference values with a flag. */
+ ret = wait_event_interruptible_timeout(gpu->event,
+ (int32_t)((uint32_t)(*vaddr & args->mask) -
+ (uint32_t)args->value) >= 0,
+ remaining_jiffies);
+
+ if (ret == 0)
+ ret = -ETIMEDOUT;
+ else if (ret > 0)
+ ret = 0;
+
+ msm_gem_put_vaddr(obj);
+
+err_put_gem_object:
+ drm_gem_object_put_unlocked(obj);
+ return ret;
+}
+
static const struct drm_ioctl_desc msm_ioctls[] = {
DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_RENDER_ALLOW),
@@ -964,6 +1020,7 @@ static const struct drm_ioctl_desc msm_ioctls[] = {
DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_NEW, msm_ioctl_submitqueue_new, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_CLOSE, msm_ioctl_submitqueue_close, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_QUERY, msm_ioctl_submitqueue_query, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_WAIT_IOVA, msm_ioctl_wait_iova, DRM_RENDER_ALLOW),
};
static const struct vm_operations_struct vm_ops = {
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index 0b85ed6a3710..d4eac312f56e 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -298,6 +298,18 @@ struct drm_msm_submitqueue_query {
__u32 pad;
};
+/* This ioctl blocks until the value at bo + offset is greater than or equal
+ * to the reference value.
+ */
+struct drm_msm_wait_iova {
+ __u32 handle; /* in, GEM handle */
+ __u32 pad;
+ struct drm_msm_timespec timeout; /* in */
+ __u64 offset; /* in, offset into bo */
+ __u64 mask; /* in, mask of the value at bo + offset */
+ __u64 value; /* in, reference value, 32 bits */
+};
+
#define DRM_MSM_GET_PARAM 0x00
/* placeholder:
#define DRM_MSM_SET_PARAM 0x01
@@ -315,6 +327,7 @@ struct drm_msm_submitqueue_query {
#define DRM_MSM_SUBMITQUEUE_NEW 0x0A
#define DRM_MSM_SUBMITQUEUE_CLOSE 0x0B
#define DRM_MSM_SUBMITQUEUE_QUERY 0x0C
+#define DRM_MSM_WAIT_IOVA 0x0D
#define DRM_IOCTL_MSM_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GET_PARAM, struct drm_msm_param)
#define DRM_IOCTL_MSM_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_NEW, struct drm_msm_gem_new)
@@ -327,6 +340,7 @@ struct drm_msm_submitqueue_query {
#define DRM_IOCTL_MSM_SUBMITQUEUE_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_NEW, struct drm_msm_submitqueue)
#define DRM_IOCTL_MSM_SUBMITQUEUE_CLOSE DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_CLOSE, __u32)
#define DRM_IOCTL_MSM_SUBMITQUEUE_QUERY DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_QUERY, struct drm_msm_submitqueue_query)
+#define DRM_IOCTL_MSM_WAIT_IOVA DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_WAIT_IOVA, struct drm_msm_wait_iova)
#if defined(__cplusplus)
}
--
2.25.0.341.g760bfbb309-goog
This wait queue is signaled on all IRQs for a given GPU and will be
used as part of the new MSM_WAIT_IOVA ioctl so userspace can sleep
until the value at a given iova reaches a certain condition.
Signed-off-by: Brian Ho <[email protected]>
---
drivers/gpu/drm/msm/msm_gpu.c | 4 ++++
drivers/gpu/drm/msm/msm_gpu.h | 3 +++
2 files changed, 7 insertions(+)
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index a052364a5d74..d7310c1336e5 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -779,6 +779,8 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
static irqreturn_t irq_handler(int irq, void *data)
{
struct msm_gpu *gpu = data;
+ wake_up_all(&gpu->event);
+
return gpu->funcs->irq(gpu);
}
@@ -871,6 +873,8 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
spin_lock_init(&gpu->perf_lock);
+ init_waitqueue_head(&gpu->event);
+
/* Map registers: */
gpu->mmio = msm_ioremap(pdev, config->ioname, name);
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index ab8f0f9c9dc8..60562f065dbc 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -104,6 +104,9 @@ struct msm_gpu {
struct msm_gem_address_space *aspace;
+ /* GPU-wide wait queue that is signaled on all IRQs */
+ wait_queue_head_t event;
+
/* Power Control: */
struct regulator *gpu_reg, *gpu_cx;
struct clk_bulk_data *grp_clks;
--
2.25.0.341.g760bfbb309-goog