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>
main
Rob Clark 2016-05-31 12:06:50 -04:00
parent 0c270df8df
commit eb846d46bc
5 changed files with 55 additions and 0 deletions

View 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); bucket = get_bucket(cache, *size);
/* see if we can be green and recycle: */ /* see if we can be green and recycle: */
retry:
if (bucket) { if (bucket) {
*size = bucket->size; *size = bucket->size;
bo = find_in_bucket(bucket, flags); bo = find_in_bucket(bucket, flags);
if (bo) { 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); atomic_set(&bo->refcnt, 1);
fd_device_ref(bo->dev); fd_device_ref(bo->dev);
return bo; return bo;
@ -187,6 +195,8 @@ fd_bo_cache_free(struct fd_bo_cache *cache, struct fd_bo *bo)
if (bucket) { if (bucket) {
struct timespec time; struct timespec time;
bo->funcs->madvise(bo, FALSE);
clock_gettime(CLOCK_MONOTONIC, &time); clock_gettime(CLOCK_MONOTONIC, &time);
bo->free_time = time.tv_sec; bo->free_time = time.tv_sec;

View File

@ -56,7 +56,15 @@ struct fd_device * fd_device_new(int fd)
if (!strcmp(version->name, "msm")) { if (!strcmp(version->name, "msm")) {
DEBUG_MSG("msm DRM device"); 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 = msm_device_new(fd);
dev->version = version->version_minor;
#ifdef HAVE_FREEDRENO_KGSL #ifdef HAVE_FREEDRENO_KGSL
} else if (!strcmp(version->name, "kgsl")) { } else if (!strcmp(version->name, "kgsl")) {
DEBUG_MSG("kgsl DRM device"); DEBUG_MSG("kgsl DRM device");
@ -66,6 +74,8 @@ struct fd_device * fd_device_new(int fd)
ERROR_MSG("unknown device: %s", version->name); ERROR_MSG("unknown device: %s", version->name);
dev = NULL; dev = NULL;
} }
out:
drmFreeVersion(version); drmFreeVersion(version);
if (!dev) if (!dev)

View File

@ -54,6 +54,13 @@
#include "freedreno_ringbuffer.h" #include "freedreno_ringbuffer.h"
#include "drm.h" #include "drm.h"
#ifndef TRUE
# define TRUE 1
#endif
#ifndef FALSE
# define FALSE 0
#endif
struct fd_device_funcs { struct fd_device_funcs {
int (*bo_new_handle)(struct fd_device *dev, uint32_t size, int (*bo_new_handle)(struct fd_device *dev, uint32_t size,
uint32_t flags, uint32_t *handle); uint32_t flags, uint32_t *handle);
@ -76,6 +83,7 @@ struct fd_bo_cache {
struct fd_device { struct fd_device {
int fd; int fd;
int version;
atomic_t refcnt; atomic_t refcnt;
/* tables to keep track of bo's, to avoid "evil-twin" fd_bo objects: /* 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 (*offset)(struct fd_bo *bo, uint64_t *offset);
int (*cpu_prep)(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op); int (*cpu_prep)(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op);
void (*cpu_fini)(struct fd_bo *bo); void (*cpu_fini)(struct fd_bo *bo);
int (*madvise)(struct fd_bo *bo, int willneed);
void (*destroy)(struct fd_bo *bo); void (*destroy)(struct fd_bo *bo);
}; };

View 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) static void kgsl_bo_destroy(struct fd_bo *bo)
{ {
struct kgsl_bo *kgsl_bo = to_kgsl_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, .offset = kgsl_bo_offset,
.cpu_prep = kgsl_bo_cpu_prep, .cpu_prep = kgsl_bo_cpu_prep,
.cpu_fini = kgsl_bo_cpu_fini, .cpu_fini = kgsl_bo_cpu_fini,
.madvise = kgsl_bo_madvise,
.destroy = kgsl_bo_destroy, .destroy = kgsl_bo_destroy,
}; };

View 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)); 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) static void msm_bo_destroy(struct fd_bo *bo)
{ {
struct msm_bo *msm_bo = to_msm_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, .offset = msm_bo_offset,
.cpu_prep = msm_bo_cpu_prep, .cpu_prep = msm_bo_cpu_prep,
.cpu_fini = msm_bo_cpu_fini, .cpu_fini = msm_bo_cpu_fini,
.madvise = msm_bo_madvise,
.destroy = msm_bo_destroy, .destroy = msm_bo_destroy,
}; };