From 65e7274008446d2059b7fd7cd6d7b1d6b04da0ce Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 19:03:20 +0200 Subject: [PATCH] ttm create / destroy / ref / unref ioctl. --- linux-core/drmP.h | 207 ++++++++++++++++++++++++++++----------------------- linux-core/drm_bo.c | 8 +- linux-core/drm_ttm.c | 138 ++++++++++++++++++++++++++++------ linux-core/drm_ttm.h | 10 ++- shared-core/drm.h | 4 + 5 files changed, 243 insertions(+), 124 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 9e1e4ba..4358934 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 847b040..35d4aba 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 05bae7d..293b1f8 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 5a7569f..bad21c9 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 feadfc6..450864b 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; -- 2.7.4