ttm create / destroy / ref / unref ioctl.
parent
c488e25ceb
commit
65e7274008
|
@ -587,6 +587,64 @@ typedef struct drm_mm {
|
|||
drm_mm_node_t root_node;
|
||||
} drm_mm_t;
|
||||
|
||||
|
||||
/*
|
||||
* User space objects and their references.
|
||||
*/
|
||||
|
||||
#define drm_user_object_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
|
||||
|
||||
typedef enum {
|
||||
drm_fence_type,
|
||||
drm_buffer_type,
|
||||
drm_ttm_type
|
||||
|
||||
/*
|
||||
* Add other user space object types here.
|
||||
*/
|
||||
|
||||
} drm_object_type_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A user object is a structure that helps the drm give out user handles
|
||||
* to kernel internal objects and to keep track of these objects so that
|
||||
* they can be destroyed, for example when the user space process exits.
|
||||
* Designed to be accessible using a user space 32-bit handle.
|
||||
*/
|
||||
|
||||
typedef struct drm_user_object{
|
||||
drm_hash_item_t hash;
|
||||
struct list_head list;
|
||||
drm_object_type_t type;
|
||||
atomic_t refcount;
|
||||
int shareable;
|
||||
drm_file_t *owner;
|
||||
void (*ref_struct_locked) (drm_file_t *priv, struct drm_user_object *obj,
|
||||
drm_ref_t ref_action);
|
||||
void (*unref)(drm_file_t *priv, struct drm_user_object *obj,
|
||||
drm_ref_t unref_action);
|
||||
void (*remove)(drm_file_t *priv, struct drm_user_object *obj);
|
||||
} drm_user_object_t;
|
||||
|
||||
/*
|
||||
* A ref object is a structure which is used to
|
||||
* keep track of references to user objects and to keep track of these
|
||||
* references so that they can be destroyed for example when the user space
|
||||
* process exits. Designed to be accessible using a pointer to the _user_ object.
|
||||
*/
|
||||
|
||||
|
||||
typedef struct drm_ref_object {
|
||||
drm_hash_item_t hash;
|
||||
struct list_head list;
|
||||
atomic_t refcount;
|
||||
drm_ref_t unref_action;
|
||||
} drm_ref_object_t;
|
||||
|
||||
|
||||
#include "drm_ttm.h"
|
||||
|
||||
/*
|
||||
|
@ -873,101 +931,6 @@ typedef struct drm_agp_ttm_priv {
|
|||
} drm_agp_ttm_priv;
|
||||
#endif
|
||||
|
||||
|
||||
static __inline__ int drm_core_check_feature(struct drm_device *dev,
|
||||
int feature)
|
||||
{
|
||||
return ((dev->driver->driver_features & feature) ? 1 : 0);
|
||||
}
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
static inline int drm_core_has_AGP(struct drm_device *dev)
|
||||
{
|
||||
return drm_core_check_feature(dev, DRIVER_USE_AGP);
|
||||
}
|
||||
#else
|
||||
#define drm_core_has_AGP(dev) (0)
|
||||
#endif
|
||||
|
||||
#if __OS_HAS_MTRR
|
||||
static inline int drm_core_has_MTRR(struct drm_device *dev)
|
||||
{
|
||||
return drm_core_check_feature(dev, DRIVER_USE_MTRR);
|
||||
}
|
||||
|
||||
#define DRM_MTRR_WC MTRR_TYPE_WRCOMB
|
||||
|
||||
static inline int drm_mtrr_add(unsigned long offset, unsigned long size,
|
||||
unsigned int flags)
|
||||
{
|
||||
return mtrr_add(offset, size, flags, 1);
|
||||
}
|
||||
|
||||
static inline int drm_mtrr_del(int handle, unsigned long offset,
|
||||
unsigned long size, unsigned int flags)
|
||||
{
|
||||
return mtrr_del(handle, offset, size);
|
||||
}
|
||||
|
||||
#else
|
||||
#define drm_core_has_MTRR(dev) (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* User space objects and their references.
|
||||
*/
|
||||
|
||||
#define drm_user_object_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
|
||||
|
||||
typedef enum {
|
||||
drm_fence_type,
|
||||
drm_buffer_type
|
||||
|
||||
/*
|
||||
* Add other user space object types here.
|
||||
*/
|
||||
|
||||
} drm_object_type_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A user object is a structure that helps the drm give out user handles
|
||||
* to kernel internal objects and to keep track of these objects so that
|
||||
* they can be destroyed, for example when the user space process exits.
|
||||
* Designed to be accessible using a user space 32-bit handle.
|
||||
*/
|
||||
|
||||
typedef struct drm_user_object{
|
||||
drm_hash_item_t hash;
|
||||
struct list_head list;
|
||||
drm_object_type_t type;
|
||||
atomic_t refcount;
|
||||
int shareable;
|
||||
drm_file_t *owner;
|
||||
void (*ref_struct_locked) (drm_file_t *priv, struct drm_user_object *obj,
|
||||
drm_ref_t ref_action);
|
||||
void (*unref)(drm_file_t *priv, struct drm_user_object *obj,
|
||||
drm_ref_t unref_action);
|
||||
void (*remove)(drm_file_t *priv, struct drm_user_object *obj);
|
||||
} drm_user_object_t;
|
||||
|
||||
/*
|
||||
* A ref object is a structure which is used to
|
||||
* keep track of references to user objects and to keep track of these
|
||||
* references so that they can be destroyed for example when the user space
|
||||
* process exits. Designed to be accessible using a pointer to the _user_ object.
|
||||
*/
|
||||
|
||||
|
||||
typedef struct drm_ref_object {
|
||||
drm_hash_item_t hash;
|
||||
struct list_head list;
|
||||
atomic_t refcount;
|
||||
drm_ref_t unref_action;
|
||||
} drm_ref_object_t;
|
||||
|
||||
typedef struct drm_fence_object{
|
||||
drm_user_object_t base;
|
||||
atomic_t usage;
|
||||
|
@ -1012,6 +975,46 @@ typedef struct drm_buffer_object{
|
|||
|
||||
|
||||
|
||||
static __inline__ int drm_core_check_feature(struct drm_device *dev,
|
||||
int feature)
|
||||
{
|
||||
return ((dev->driver->driver_features & feature) ? 1 : 0);
|
||||
}
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
static inline int drm_core_has_AGP(struct drm_device *dev)
|
||||
{
|
||||
return drm_core_check_feature(dev, DRIVER_USE_AGP);
|
||||
}
|
||||
#else
|
||||
#define drm_core_has_AGP(dev) (0)
|
||||
#endif
|
||||
|
||||
#if __OS_HAS_MTRR
|
||||
static inline int drm_core_has_MTRR(struct drm_device *dev)
|
||||
{
|
||||
return drm_core_check_feature(dev, DRIVER_USE_MTRR);
|
||||
}
|
||||
|
||||
#define DRM_MTRR_WC MTRR_TYPE_WRCOMB
|
||||
|
||||
static inline int drm_mtrr_add(unsigned long offset, unsigned long size,
|
||||
unsigned int flags)
|
||||
{
|
||||
return mtrr_add(offset, size, flags, 1);
|
||||
}
|
||||
|
||||
static inline int drm_mtrr_del(int handle, unsigned long offset,
|
||||
unsigned long size, unsigned int flags)
|
||||
{
|
||||
return mtrr_del(handle, offset, size);
|
||||
}
|
||||
|
||||
#else
|
||||
#define drm_core_has_MTRR(dev) (0)
|
||||
#endif
|
||||
|
||||
|
||||
/******************************************************************/
|
||||
/** \name Internal function definitions */
|
||||
/*@{*/
|
||||
|
@ -1353,6 +1356,20 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS);
|
|||
|
||||
extern int drm_bo_ioctl(DRM_IOCTL_ARGS);
|
||||
|
||||
/*
|
||||
* Convenience 2*32-bit to 64-bit function
|
||||
*/
|
||||
|
||||
static __inline__ unsigned long combine_64(uint32_t lo, uint32_t hi)
|
||||
{
|
||||
unsigned long ret = lo;
|
||||
|
||||
if (sizeof(ret) > 4) {
|
||||
int shift = 32;
|
||||
lo |= (hi << shift);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Inline replacements for DRM_IOREMAP macros */
|
||||
static __inline__ void drm_core_ioremap(struct drm_map *map,
|
||||
|
|
|
@ -338,13 +338,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS)
|
|||
(void) dev;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg));
|
||||
data_ptr = arg.data_lo;
|
||||
|
||||
if (sizeof(data_ptr) > 4) {
|
||||
int shift = 32;
|
||||
data_ptr |= arg.data_hi << shift;
|
||||
}
|
||||
|
||||
data_ptr = combine_64(arg.data_lo, arg.data_hi);
|
||||
switch(arg.op) {
|
||||
case drm_op_bo:
|
||||
arg.num_requests = drm_do_bo_ioctl(priv, arg.num_requests,
|
||||
|
|
|
@ -42,6 +42,7 @@ typedef struct drm_val_action {
|
|||
int validated;
|
||||
} drm_val_action_t;
|
||||
|
||||
|
||||
/*
|
||||
* We may be manipulating other processes page tables, so for each TTM, keep track of
|
||||
* which mm_structs are currently mapping the ttm so that we can take the appropriate
|
||||
|
@ -275,6 +276,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size)
|
|||
|
||||
ttm->lhandle = 0;
|
||||
atomic_set(&ttm->vma_count, 0);
|
||||
|
||||
ttm->destroy = 0;
|
||||
ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
|
||||
|
@ -746,25 +748,80 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a ttm and add it to the drm book-keeping.
|
||||
* dev->struct_mutex locked.
|
||||
*/
|
||||
|
||||
int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist)
|
||||
static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object)
|
||||
{
|
||||
drm_map_list_t *list = &object->map_list;
|
||||
drm_local_map_t *map;
|
||||
|
||||
if (list->user_token)
|
||||
drm_ht_remove_item(&dev->map_hash, &list->hash);
|
||||
|
||||
map = list->map;
|
||||
|
||||
if (map) {
|
||||
drm_ttm_t *ttm = (drm_ttm_t *)map->offset;
|
||||
if (ttm) {
|
||||
if (drm_destroy_ttm(ttm) != -EBUSY) {
|
||||
drm_free(map, sizeof(*map), DRM_MEM_TTM);
|
||||
}
|
||||
} else {
|
||||
drm_free(map, sizeof(*map), DRM_MEM_TTM);
|
||||
}
|
||||
}
|
||||
|
||||
drm_free(object, sizeof(*object), DRM_MEM_TTM);
|
||||
}
|
||||
|
||||
/*
|
||||
* dev->struct_mutex locked.
|
||||
*/
|
||||
static void drm_ttm_user_object_remove(drm_file_t *priv, drm_user_object_t *base)
|
||||
{
|
||||
drm_ttm_object_t *object;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
|
||||
object = drm_user_object_entry(base, drm_ttm_object_t, base);
|
||||
if (atomic_dec_and_test(&object->usage))
|
||||
drm_ttm_object_remove(dev, object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Create a ttm and add it to the drm book-keeping.
|
||||
* dev->struct_mutex locked.
|
||||
*/
|
||||
|
||||
int drm_ttm_object_create(drm_device_t *dev, unsigned long size,
|
||||
uint32_t flags, drm_ttm_object_t **ttm_object)
|
||||
{
|
||||
drm_ttm_object_t *object;
|
||||
drm_map_list_t *list;
|
||||
drm_map_t *map;
|
||||
drm_ttm_t *ttm;
|
||||
|
||||
map = drm_alloc(sizeof(*map), DRM_MEM_TTM);
|
||||
if (!map)
|
||||
object = drm_calloc(1, sizeof(*object), DRM_MEM_TTM);
|
||||
if (!object)
|
||||
return -ENOMEM;
|
||||
object->flags = flags;
|
||||
list = &object->map_list;
|
||||
|
||||
list->map = drm_calloc(1, sizeof(*map), DRM_MEM_TTM);
|
||||
if (!list->map) {
|
||||
drm_ttm_object_remove(dev, object);
|
||||
return -ENOMEM;
|
||||
}
|
||||
map = list->map;
|
||||
|
||||
ttm = drm_init_ttm(dev, size);
|
||||
|
||||
if (!ttm) {
|
||||
DRM_ERROR("Could not create ttm\n");
|
||||
drm_free(map, sizeof(*map), DRM_MEM_TTM);
|
||||
drm_ttm_object_remove(dev, object);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -772,34 +829,73 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist)
|
|||
map->type = _DRM_TTM;
|
||||
map->flags = _DRM_REMOVABLE;
|
||||
map->size = size;
|
||||
|
||||
list = drm_calloc(1, sizeof(*list), DRM_MEM_TTM);
|
||||
if (!list) {
|
||||
drm_destroy_ttm(ttm);
|
||||
drm_free(map, sizeof(*map), DRM_MEM_TTM);
|
||||
return -ENOMEM;
|
||||
}
|
||||
map->handle = (void *)list;
|
||||
|
||||
map->handle = (void *)object;
|
||||
|
||||
if (drm_ht_just_insert_please(&dev->map_hash, &list->hash,
|
||||
(unsigned long) map->handle,
|
||||
32 - PAGE_SHIFT - 3, PAGE_SHIFT,
|
||||
DRM_MAP_HASH_OFFSET)) {
|
||||
drm_destroy_ttm(ttm);
|
||||
drm_free(map, sizeof(*map), DRM_MEM_TTM);
|
||||
drm_free(list, sizeof(*list), DRM_MEM_TTM);
|
||||
drm_ttm_object_remove(dev, object);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
list->user_token = list->hash.key;
|
||||
list->map = map;
|
||||
|
||||
*maplist = list;
|
||||
object->base.remove = drm_ttm_user_object_remove;
|
||||
object->base.type = drm_ttm_type;
|
||||
object->base.ref_struct_locked = NULL;
|
||||
object->base.unref = NULL;
|
||||
|
||||
atomic_set(&object->usage, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data)
|
||||
{
|
||||
drm_ttm_arg_t arg;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_ttm_object_t *entry;
|
||||
drm_user_object_t *uo;
|
||||
unsigned long size;
|
||||
int ret;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg));
|
||||
|
||||
switch(arg.op) {
|
||||
case drm_ttm_create:
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
size = combine_64(arg.size_lo, arg.size_hi);
|
||||
ret = drm_ttm_object_create(dev, size, arg.flags, &entry);
|
||||
if (ret) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
ret = drm_add_user_object(priv, &entry->base,
|
||||
arg.flags & DRM_TTM_FLAG_SHAREABLE);
|
||||
if (ret) {
|
||||
drm_ttm_object_remove(dev, entry);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
arg.handle = entry->base.hash.key;
|
||||
arg.user_token = entry->map_list.user_token;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
break;
|
||||
case drm_ttm_reference:
|
||||
return drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo);
|
||||
case drm_ttm_unreference:
|
||||
return drm_user_object_unref(priv, arg.handle, drm_ttm_type);
|
||||
case drm_ttm_destroy:
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
uo = drm_lookup_user_object(priv, arg.handle);
|
||||
if (!uo || (uo->type != drm_ttm_type) || uo->owner != priv) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = drm_remove_user_object(priv, uo);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -101,7 +101,15 @@ typedef struct drm_ttm {
|
|||
int destroy;
|
||||
} drm_ttm_t;
|
||||
|
||||
int drm_add_ttm(struct drm_device * dev, unsigned size, drm_map_list_t ** maplist);
|
||||
typedef struct drm_ttm_object {
|
||||
drm_user_object_t base;
|
||||
atomic_t usage;
|
||||
uint32_t flags;
|
||||
drm_map_list_t map_list;
|
||||
} drm_ttm_object_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Bind a part of the ttm starting at page_offset size n_pages into the GTT, at
|
||||
|
|
|
@ -688,6 +688,8 @@ typedef struct drm_bo_arg {
|
|||
unsigned data_hi;
|
||||
} drm_bo_arg_t;
|
||||
|
||||
#define DRM_TTM_FLAG_SHAREABLE 0x00000001
|
||||
|
||||
typedef struct drm_ttm_arg {
|
||||
enum {
|
||||
drm_ttm_create,
|
||||
|
@ -696,8 +698,10 @@ typedef struct drm_ttm_arg {
|
|||
drm_ttm_unreference
|
||||
} op;
|
||||
unsigned handle;
|
||||
unsigned user_token;
|
||||
unsigned size_lo;
|
||||
unsigned size_hi;
|
||||
unsigned flags;
|
||||
}drm_ttm_arg_t;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue