[PATCH] nouveau: add support for DRM_NOUVEAU_GEM_CPU_PREP_TIMEOUT

Marcin Slusarz marcin.slusarz at gmail.com
Sun Sep 18 06:20:15 PDT 2011


New ioctl is used internally by nouveau_bo_wait to properly handle
timeouts with signals.
---
 include/drm/nouveau_drm.h |   33 ++++++++++++++--------
 nouveau/nouveau_bo.c      |   66 ++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 77 insertions(+), 22 deletions(-)

diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h
index b18cad0..6541766 100644
--- a/include/drm/nouveau_drm.h
+++ b/include/drm/nouveau_drm.h
@@ -25,6 +25,8 @@
 #ifndef __NOUVEAU_DRM_H__
 #define __NOUVEAU_DRM_H__
 
+#include <sys/time.h>
+
 #define NOUVEAU_DRM_HEADER_PATCHLEVEL 16
 
 struct drm_nouveau_channel_alloc {
@@ -179,6 +181,12 @@ struct drm_nouveau_gem_cpu_prep {
 	uint32_t flags;
 };
 
+struct drm_nouveau_gem_cpu_prep_timeout {
+	uint32_t handle;
+	uint32_t flags;
+	struct timespec timeout;
+};
+
 struct drm_nouveau_gem_cpu_fini {
 	uint32_t handle;
 };
@@ -192,17 +200,18 @@ enum nouveau_bus_type {
 struct drm_nouveau_sarea {
 };
 
-#define DRM_NOUVEAU_GETPARAM           0x00
-#define DRM_NOUVEAU_SETPARAM           0x01
-#define DRM_NOUVEAU_CHANNEL_ALLOC      0x02
-#define DRM_NOUVEAU_CHANNEL_FREE       0x03
-#define DRM_NOUVEAU_GROBJ_ALLOC        0x04
-#define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC  0x05
-#define DRM_NOUVEAU_GPUOBJ_FREE        0x06
-#define DRM_NOUVEAU_GEM_NEW            0x40
-#define DRM_NOUVEAU_GEM_PUSHBUF        0x41
-#define DRM_NOUVEAU_GEM_CPU_PREP       0x42
-#define DRM_NOUVEAU_GEM_CPU_FINI       0x43
-#define DRM_NOUVEAU_GEM_INFO           0x44
+#define DRM_NOUVEAU_GETPARAM             0x00
+#define DRM_NOUVEAU_SETPARAM             0x01
+#define DRM_NOUVEAU_CHANNEL_ALLOC        0x02
+#define DRM_NOUVEAU_CHANNEL_FREE         0x03
+#define DRM_NOUVEAU_GROBJ_ALLOC          0x04
+#define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC    0x05
+#define DRM_NOUVEAU_GPUOBJ_FREE          0x06
+#define DRM_NOUVEAU_GEM_NEW              0x40
+#define DRM_NOUVEAU_GEM_PUSHBUF          0x41
+#define DRM_NOUVEAU_GEM_CPU_PREP         0x42
+#define DRM_NOUVEAU_GEM_CPU_FINI         0x43
+#define DRM_NOUVEAU_GEM_INFO             0x44
+#define DRM_NOUVEAU_GEM_CPU_PREP_TIMEOUT 0x45
 
 #endif /* __NOUVEAU_DRM_H__ */
diff --git a/nouveau/nouveau_bo.c b/nouveau/nouveau_bo.c
index d6bb22d..d85eebc 100644
--- a/nouveau/nouveau_bo.c
+++ b/nouveau/nouveau_bo.c
@@ -361,11 +361,48 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pbo)
 }
 
 static int
+nouveau_bo_wait_timeout(int fd, uint32_t handle, uint32_t flags)
+{
+	struct drm_nouveau_gem_cpu_prep_timeout req;
+	int ret;
+
+	req.handle = handle;
+	req.flags = flags;
+	req.timeout.tv_sec = 3;
+	req.timeout.tv_nsec = 0;
+
+	do {
+		ret = drmCommandWriteRead(fd, DRM_NOUVEAU_GEM_CPU_PREP_TIMEOUT,
+					&req, sizeof(req));
+	} while (ret == -EAGAIN);
+
+	return ret;
+}
+
+static int
+nouveau_bo_wait_compat(int fd, uint32_t handle, uint32_t flags)
+{
+	struct drm_nouveau_gem_cpu_prep req;
+	int ret;
+
+	req.handle = handle;
+	req.flags = flags;
+
+	do {
+		ret = drmCommandWrite(fd, DRM_NOUVEAU_GEM_CPU_PREP,
+				      &req, sizeof(req));
+	} while (ret == -EAGAIN);
+
+	return ret;
+}
+
+static int
 nouveau_bo_wait(struct nouveau_bo *bo, int cpu_write, int no_wait, int no_block)
 {
 	struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
 	struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
-	struct drm_nouveau_gem_cpu_prep req;
+	static int timeout_available = -1;
+	uint32_t flags;
 	int ret;
 
 	if (!nvbo->global_handle && !nvbo->write_marker && !cpu_write)
@@ -377,19 +414,28 @@ nouveau_bo_wait(struct nouveau_bo *bo, int cpu_write, int no_wait, int no_block)
 		nouveau_pushbuf_flush(nvbo->pending_channel, 0);
 	}
 
-	req.handle = nvbo->handle;
-	req.flags = 0;
+	flags = 0;
 	if (cpu_write)
-		req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE;
+		flags |= NOUVEAU_GEM_CPU_PREP_WRITE;
 	if (no_wait)
-		req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT;
+		flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT;
 	if (no_block)
-		req.flags |= NOUVEAU_GEM_CPU_PREP_NOBLOCK;
+		flags |= NOUVEAU_GEM_CPU_PREP_NOBLOCK;
+
+	if (timeout_available == 1)
+		ret = nouveau_bo_wait_timeout(nvdev->fd, nvbo->handle, flags);
+	else if (timeout_available == 0)
+		ret = nouveau_bo_wait_compat(nvdev->fd, nvbo->handle, flags);
+	else {
+		ret = nouveau_bo_wait_timeout(nvdev->fd, nvbo->handle, flags);
+		if (ret == -EINVAL) {
+			timeout_available = 0;
+			ret = nouveau_bo_wait_compat(nvdev->fd, nvbo->handle, flags);
+		} else {
+			timeout_available = 1;
+		}
+	}
 
-	do {
-		ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_CPU_PREP,
-				      &req, sizeof(req));
-	} while (ret == -EAGAIN);
 	if (ret)
 		return ret;
 
-- 
1.7.6.1



More information about the dri-devel mailing list