summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2006-08-27 19:03:20 +0200
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2006-08-27 19:03:20 +0200
commit65e7274008446d2059b7fd7cd6d7b1d6b04da0ce (patch)
treecea687a01de551075f0e4b54768a370cc0d5331a
parentc488e25ceb421c6f84f110d786d9814ac4dba1b2 (diff)
ttm create / destroy / ref / unref ioctl.
-rw-r--r--linux-core/drmP.h207
-rw-r--r--linux-core/drm_bo.c8
-rw-r--r--linux-core/drm_ttm.c138
-rw-r--r--linux-core/drm_ttm.h10
-rw-r--r--shared-core/drm.h4
5 files changed, 243 insertions, 124 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 9e1e4ba8..43589342 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -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,
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index 847b0406..35d4aba7 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -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,
diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c
index 05bae7de..293b1f8c 100644
--- a/linux-core/drm_ttm.c
+++ b/linux-core/drm_ttm.c
@@ -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;
}
diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h
index 5a7569ff..bad21c97 100644
--- a/linux-core/drm_ttm.h
+++ b/linux-core/drm_ttm.h
@@ -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
diff --git a/shared-core/drm.h b/shared-core/drm.h
index feadfc67..450864bc 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -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;