OSDN Git Service

freedreno: add madvise support
authorRob Clark <robclark@freedesktop.org>
Tue, 31 May 2016 16:06:50 +0000 (12:06 -0400)
committerRob Clark <robclark@freedesktop.org>
Wed, 20 Jul 2016 23:42:21 +0000 (19:42 -0400)
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>
freedreno/freedreno_bo_cache.c
freedreno/freedreno_device.c
freedreno/freedreno_priv.h
freedreno/kgsl/kgsl_bo.c
freedreno/msm/msm_bo.c

index 17199d2..58d171e 100644 (file)
@@ -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;
index 15e41f0..027414e 100644 (file)
@@ -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)
index 4159e52..f3ddd77 100644 (file)
 #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);
 };
 
index 2b45b5e..ab3485e 100644 (file)
@@ -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,
 };
 
index cd05a6c..cfaec82 100644 (file)
@@ -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,
 };