ttm create / destroy / ref / unref ioctl.

main
Thomas Hellstrom 2006-08-27 19:03:20 +02:00
parent c488e25ceb
commit 65e7274008
5 changed files with 243 additions and 124 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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;