summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Clark <robclark@freedesktop.org>2016-05-31 12:06:50 -0400
committerRob Clark <robclark@freedesktop.org>2016-07-20 19:42:21 -0400
commiteb846d46bca614f24c50f3fa89f94a6820e16589 (patch)
treeef805cc2fe2f4ee02694eeeecbf3c8904d20ea47
parent0c270df8dfde6d6d7b7adb236cd3325f2c0115bd (diff)
freedreno: add madvise support
With a new enough drm/msm, we can let the kernel know about buffers that are in the bo cache, so the kernel can free them under memory pressure. Signed-off-by: Rob Clark <robclark@freedesktop.org>
-rw-r--r--freedreno/freedreno_bo_cache.c10
-rw-r--r--freedreno/freedreno_device.c10
-rw-r--r--freedreno/freedreno_priv.h9
-rw-r--r--freedreno/kgsl/kgsl_bo.c6
-rw-r--r--freedreno/msm/msm_bo.c20
5 files changed, 55 insertions, 0 deletions
diff --git a/freedreno/freedreno_bo_cache.c b/freedreno/freedreno_bo_cache.c
index 17199d27..58d171eb 100644
--- a/freedreno/freedreno_bo_cache.c
+++ b/freedreno/freedreno_bo_cache.c
@@ -165,10 +165,18 @@ fd_bo_cache_alloc(struct fd_bo_cache *cache, uint32_t *size, uint32_t flags)
bucket = get_bucket(cache, *size);
/* see if we can be green and recycle: */
+retry:
if (bucket) {
*size = bucket->size;
bo = find_in_bucket(bucket, flags);
if (bo) {
+ if (bo->funcs->madvise(bo, TRUE) <= 0) {
+ /* we've lost the backing pages, delete and try again: */
+ pthread_mutex_lock(&table_lock);
+ bo_del(bo);
+ pthread_mutex_unlock(&table_lock);
+ goto retry;
+ }
atomic_set(&bo->refcnt, 1);
fd_device_ref(bo->dev);
return bo;
@@ -187,6 +195,8 @@ fd_bo_cache_free(struct fd_bo_cache *cache, struct fd_bo *bo)
if (bucket) {
struct timespec time;
+ bo->funcs->madvise(bo, FALSE);
+
clock_gettime(CLOCK_MONOTONIC, &time);
bo->free_time = time.tv_sec;
diff --git a/freedreno/freedreno_device.c b/freedreno/freedreno_device.c
index 15e41f0e..027414ec 100644
--- a/freedreno/freedreno_device.c
+++ b/freedreno/freedreno_device.c
@@ -56,7 +56,15 @@ struct fd_device * fd_device_new(int fd)
if (!strcmp(version->name, "msm")) {
DEBUG_MSG("msm DRM device");
+ if (version->version_major != 1) {
+ ERROR_MSG("unsupported version: %u.%u.%u", version->version_major,
+ version->version_minor, version->version_patchlevel);
+ dev = NULL;
+ goto out;
+ }
+
dev = msm_device_new(fd);
+ dev->version = version->version_minor;
#ifdef HAVE_FREEDRENO_KGSL
} else if (!strcmp(version->name, "kgsl")) {
DEBUG_MSG("kgsl DRM device");
@@ -66,6 +74,8 @@ struct fd_device * fd_device_new(int fd)
ERROR_MSG("unknown device: %s", version->name);
dev = NULL;
}
+
+out:
drmFreeVersion(version);
if (!dev)
diff --git a/freedreno/freedreno_priv.h b/freedreno/freedreno_priv.h
index 4159e526..f3ddd77d 100644
--- a/freedreno/freedreno_priv.h
+++ b/freedreno/freedreno_priv.h
@@ -54,6 +54,13 @@
#include "freedreno_ringbuffer.h"
#include "drm.h"
+#ifndef TRUE
+# define TRUE 1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+
struct fd_device_funcs {
int (*bo_new_handle)(struct fd_device *dev, uint32_t size,
uint32_t flags, uint32_t *handle);
@@ -76,6 +83,7 @@ struct fd_bo_cache {
struct fd_device {
int fd;
+ int version;
atomic_t refcnt;
/* tables to keep track of bo's, to avoid "evil-twin" fd_bo objects:
@@ -139,6 +147,7 @@ struct fd_bo_funcs {
int (*offset)(struct fd_bo *bo, uint64_t *offset);
int (*cpu_prep)(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op);
void (*cpu_fini)(struct fd_bo *bo);
+ int (*madvise)(struct fd_bo *bo, int willneed);
void (*destroy)(struct fd_bo *bo);
};
diff --git a/freedreno/kgsl/kgsl_bo.c b/freedreno/kgsl/kgsl_bo.c
index 2b45b5e2..ab3485e3 100644
--- a/freedreno/kgsl/kgsl_bo.c
+++ b/freedreno/kgsl/kgsl_bo.c
@@ -116,6 +116,11 @@ static void kgsl_bo_cpu_fini(struct fd_bo *bo)
{
}
+static int kgsl_bo_madvise(struct fd_bo *bo, int willneed)
+{
+ return willneed; /* not supported by kgsl */
+}
+
static void kgsl_bo_destroy(struct fd_bo *bo)
{
struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo);
@@ -127,6 +132,7 @@ static const struct fd_bo_funcs funcs = {
.offset = kgsl_bo_offset,
.cpu_prep = kgsl_bo_cpu_prep,
.cpu_fini = kgsl_bo_cpu_fini,
+ .madvise = kgsl_bo_madvise,
.destroy = kgsl_bo_destroy,
};
diff --git a/freedreno/msm/msm_bo.c b/freedreno/msm/msm_bo.c
index cd05a6cd..cfaec827 100644
--- a/freedreno/msm/msm_bo.c
+++ b/freedreno/msm/msm_bo.c
@@ -89,6 +89,25 @@ static void msm_bo_cpu_fini(struct fd_bo *bo)
drmCommandWrite(bo->dev->fd, DRM_MSM_GEM_CPU_FINI, &req, sizeof(req));
}
+static int msm_bo_madvise(struct fd_bo *bo, int willneed)
+{
+ struct drm_msm_gem_madvise req = {
+ .handle = bo->handle,
+ .madv = willneed ? MSM_MADV_WILLNEED : MSM_MADV_DONTNEED,
+ };
+ int ret;
+
+ /* older kernels do not support this: */
+ if (bo->dev->version < 1)
+ return willneed;
+
+ ret = drmCommandWriteRead(bo->dev->fd, DRM_MSM_GEM_MADVISE, &req, sizeof(req));
+ if (ret)
+ return ret;
+
+ return req.retained;
+}
+
static void msm_bo_destroy(struct fd_bo *bo)
{
struct msm_bo *msm_bo = to_msm_bo(bo);
@@ -100,6 +119,7 @@ static const struct fd_bo_funcs funcs = {
.offset = msm_bo_offset,
.cpu_prep = msm_bo_cpu_prep,
.cpu_fini = msm_bo_cpu_fini,
+ .madvise = msm_bo_madvise,
.destroy = msm_bo_destroy,
};