summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/drmP.h7
-rw-r--r--linux-core/drm_compat.c123
-rw-r--r--linux-core/drm_compat.h9
-rw-r--r--linux-core/drm_context.c56
-rw-r--r--linux-core/drm_drawable.c19
-rw-r--r--linux-core/drm_drv.c12
-rw-r--r--linux-core/drm_stub.c1
7 files changed, 176 insertions, 51 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 94cb4eee..dd3a69df 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -571,8 +571,6 @@ typedef struct drm_ctx_list {
} drm_ctx_list_t;
struct drm_ctx_sarea_list {
- struct list_head head;
- int ctx_id;
drm_map_t *map;
};
@@ -601,8 +599,6 @@ typedef struct ati_pcigart_info {
} drm_ati_pcigart_info;
struct drm_drawable_list {
- struct list_head head;
- int id;
drm_drawable_info_t info;
};
@@ -753,7 +749,6 @@ typedef struct drm_device {
struct mutex ctxlist_mutex; /**< For ctxlist */
struct idr ctx_idr;
- struct list_head context_sarealist;
struct list_head vmalist; /**< List of vmas (for debugging) */
drm_lock_data_t lock; /**< Information on hardware lock */
@@ -830,7 +825,6 @@ typedef struct drm_device {
/*@{ */
spinlock_t drw_lock;
struct idr drw_idr;
- struct list_head drwlist;
/*@} */
} drm_device_t;
@@ -1008,6 +1002,7 @@ extern int drm_update_drawable_info(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev,
drm_drawable_t id);
+extern void drm_drawable_free_all(drm_device_t *dev);
/* Authentication IOCTL support (drm_auth.h) */
extern int drm_getmagic(struct inode *inode, struct file *filp,
diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c
index 9ac5658c..08d20d06 100644
--- a/linux-core/drm_compat.c
+++ b/linux-core/drm_compat.c
@@ -555,3 +555,126 @@ void drm_bo_finish_unmap(drm_buffer_object_t *bo)
#endif
+#ifdef DRM_IDR_COMPAT_FN
+/* only called when idp->lock is held */
+static void __free_layer(struct idr *idp, struct idr_layer *p)
+{
+ p->ary[0] = idp->id_free;
+ idp->id_free = p;
+ idp->id_free_cnt++;
+}
+
+static void free_layer(struct idr *idp, struct idr_layer *p)
+{
+ unsigned long flags;
+
+ /*
+ * Depends on the return element being zeroed.
+ */
+ spin_lock_irqsave(&idp->lock, flags);
+ __free_layer(idp, p);
+ spin_unlock_irqrestore(&idp->lock, flags);
+}
+
+/**
+ * idr_for_each - iterate through all stored pointers
+ * @idp: idr handle
+ * @fn: function to be called for each pointer
+ * @data: data passed back to callback function
+ *
+ * Iterate over the pointers registered with the given idr. The
+ * callback function will be called for each pointer currently
+ * registered, passing the id, the pointer and the data pointer passed
+ * to this function. It is not safe to modify the idr tree while in
+ * the callback, so functions such as idr_get_new and idr_remove are
+ * not allowed.
+ *
+ * We check the return of @fn each time. If it returns anything other
+ * than 0, we break out and return that value.
+ *
+* The caller must serialize idr_find() vs idr_get_new() and idr_remove().
+ */
+int idr_for_each(struct idr *idp,
+ int (*fn)(int id, void *p, void *data), void *data)
+{
+ int n, id, max, error = 0;
+ struct idr_layer *p;
+ struct idr_layer *pa[MAX_LEVEL];
+ struct idr_layer **paa = &pa[0];
+
+ n = idp->layers * IDR_BITS;
+ p = idp->top;
+ max = 1 << n;
+
+ id = 0;
+ while (id < max) {
+ while (n > 0 && p) {
+ n -= IDR_BITS;
+ *paa++ = p;
+ p = p->ary[(id >> n) & IDR_MASK];
+ }
+
+ if (p) {
+ error = fn(id, (void *)p, data);
+ if (error)
+ break;
+ }
+
+ id += 1 << n;
+ while (n < fls(id)) {
+ n += IDR_BITS;
+ p = *--paa;
+ }
+ }
+
+ return error;
+}
+EXPORT_SYMBOL(idr_for_each);
+
+/**
+ * idr_remove_all - remove all ids from the given idr tree
+ * @idp: idr handle
+ *
+ * idr_destroy() only frees up unused, cached idp_layers, but this
+ * function will remove all id mappings and leave all idp_layers
+ * unused.
+ *
+ * A typical clean-up sequence for objects stored in an idr tree, will
+ * use idr_for_each() to free all objects, if necessay, then
+ * idr_remove_all() to remove all ids, and idr_destroy() to free
+ * up the cached idr_layers.
+ */
+void idr_remove_all(struct idr *idp)
+{
+ int n, id, max, error = 0;
+ struct idr_layer *p;
+ struct idr_layer *pa[MAX_LEVEL];
+ struct idr_layer **paa = &pa[0];
+
+ n = idp->layers * IDR_BITS;
+ p = idp->top;
+ max = 1 << n;
+
+ id = 0;
+ while (id < max && !error) {
+ while (n > IDR_BITS && p) {
+ n -= IDR_BITS;
+ *paa++ = p;
+ p = p->ary[(id >> n) & IDR_MASK];
+ }
+
+ id += 1 << n;
+ while (n < fls(id)) {
+ if (p) {
+ memset(p, 0, sizeof *p);
+ free_layer(idp, p);
+ }
+ n += IDR_BITS;
+ p = *--paa;
+ }
+ }
+ idp->top = NULL;
+ idp->layers = 0;
+}
+EXPORT_SYMBOL(idr_remove_all);
+#endif
diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h
index bc5fadc5..024059ac 100644
--- a/linux-core/drm_compat.h
+++ b/linux-core/drm_compat.h
@@ -305,4 +305,13 @@ extern int drm_bo_remap_bound(struct drm_buffer_object *bo);
extern int drm_bo_map_bound(struct vm_area_struct *vma);
#endif
+
+/* fixme when functions are upstreamed */
+#define DRM_IDR_COMPAT_FN
+#ifdef DRM_IDR_COMPAT_FN
+int idr_for_each(struct idr *idp,
+ int (*fn)(int id, void *p, void *data), void *data);
+void idr_remove_all(struct idr *idp);
+#endif
+
#endif
diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c
index 5cb79b14..101a298c 100644
--- a/linux-core/drm_context.c
+++ b/linux-core/drm_context.c
@@ -53,19 +53,18 @@
* \param ctx_handle context handle.
*
* Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
- * in drm_device::context_sareas, while holding the drm_device::struct_mutex
+ * in drm_device::ctx_idr, while holding the drm_device::struct_mutex
* lock.
*/
void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
{
- struct drm_ctx_sarea_list *ctx_sarea;
+ struct drm_ctx_sarea_list *ctx;
mutex_lock(&dev->struct_mutex);
- ctx_sarea = idr_find(&dev->ctx_idr, ctx_handle);
- if (ctx_sarea) {
+ ctx = idr_find(&dev->ctx_idr, ctx_handle);
+ if (ctx) {
idr_remove(&dev->ctx_idr, ctx_handle);
- list_del(&ctx_sarea->head);
- drm_free(ctx_sarea, sizeof(struct drm_ctx_sarea_list), DRM_MEM_BUFS);
+ drm_free(ctx, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST);
} else
DRM_ERROR("Attempt to free invalid context handle: %d\n", ctx_handle);
mutex_unlock(&dev->struct_mutex);
@@ -78,8 +77,7 @@ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
* \param dev DRM device.
* \return (non-negative) context handle on success or a negative number on failure.
*
- * Find the first zero bit in drm_device::ctx_bitmap and (re)allocates
- * drm_device::context_sareas to accommodate the new entry while holding the
+ * Allocate a new idr from drm_device::ctx_idr while holding the
* drm_device::struct_mutex lock.
*/
static int drm_ctxbitmap_next(drm_device_t * dev)
@@ -88,14 +86,14 @@ static int drm_ctxbitmap_next(drm_device_t * dev)
int ret;
struct drm_ctx_sarea_list *new_ctx;
- new_ctx = drm_calloc(1, sizeof(struct drm_ctx_sarea_list), DRM_MEM_BUFS);
+ new_ctx = drm_calloc(1, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST);
if (!new_ctx)
return -1;
again:
if (idr_pre_get(&dev->ctx_idr, GFP_KERNEL) == 0) {
DRM_ERROR("Out of memory expanding drawable idr\n");
- drm_free(new_ctx, sizeof(struct drm_ctx_sarea_list), DRM_MEM_BUFS);
+ drm_free(new_ctx, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST);
return -ENOMEM;
}
mutex_lock(&dev->struct_mutex);
@@ -106,9 +104,6 @@ again:
}
mutex_unlock(&dev->struct_mutex);
-
- new_ctx->ctx_id = new_id;
- list_add(&new_ctx->head, &dev->context_sarealist);
return new_id;
}
@@ -117,14 +112,20 @@ again:
*
* \param dev DRM device.
*
- * Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding
- * the drm_device::struct_mutex lock.
+ * Initialise the drm_device::ctx_idr
*/
int drm_ctxbitmap_init(drm_device_t * dev)
{
idr_init(&dev->ctx_idr);
- INIT_LIST_HEAD(&dev->context_sarealist);
+ return 0;
+}
+
+
+static int drm_ctx_sarea_free(int id, void *p, void *data)
+{
+ struct drm_ctx_sarea_list *ctx_entry = p;
+ drm_free(ctx_entry, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST);
return 0;
}
@@ -133,18 +134,14 @@ int drm_ctxbitmap_init(drm_device_t * dev)
*
* \param dev DRM device.
*
- * Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding
- * the drm_device::struct_mutex lock.
+ * Free all idr members using drm_ctx_sarea_free helper function
+ * while holding the drm_device::struct_mutex lock.
*/
void drm_ctxbitmap_cleanup(drm_device_t * dev)
{
- struct drm_ctx_sarea_list *ctx_entry, *ctx_temp;
-
mutex_lock(&dev->struct_mutex);
- list_for_each_entry_safe(ctx_entry, ctx_temp, &dev->context_sarealist, head) {
- idr_remove(&dev->ctx_idr, ctx_entry->ctx_id);
- drm_free(ctx_entry, sizeof(struct drm_ctx_sarea_list), DRM_MEM_MAPS);
- }
+ idr_for_each(&dev->ctx_idr, drm_ctx_sarea_free, NULL);
+ idr_remove_all(&dev->ctx_idr);
mutex_unlock(&dev->struct_mutex);
}
@@ -163,7 +160,7 @@ void drm_ctxbitmap_cleanup(drm_device_t * dev)
* \param arg user argument pointing to a drm_ctx_priv_map structure.
* \return zero on success or a negative number on failure.
*
- * Gets the map from drm_device::context_sareas with the handle specified and
+ * Gets the map from drm_device::ctx_idr with the handle specified and
* returns its handle.
*/
int drm_getsareactx(struct inode *inode, struct file *filp,
@@ -187,8 +184,8 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
-
map = ctx_sarea->map;
+
mutex_unlock(&dev->struct_mutex);
request.handle = NULL;
@@ -217,7 +214,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
* \return zero on success or a negative number on failure.
*
* Searches the mapping specified in \p arg and update the entry in
- * drm_device::context_sareas with it.
+ * drm_device::ctx_idr with it.
*/
int drm_setsareactx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
@@ -251,10 +248,9 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
mutex_lock(&dev->struct_mutex);
ctx_sarea = idr_find(&dev->ctx_idr, request.ctx_id);
- if (!ctx_sarea) {
+ if (!ctx_sarea)
goto bad;
- }
-
+
ctx_sarea->map = map;
mutex_unlock(&dev->struct_mutex);
return 0;
diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c
index d599430b..eb44a189 100644
--- a/linux-core/drm_drawable.c
+++ b/linux-core/drm_drawable.c
@@ -67,11 +67,8 @@ again:
goto again;
}
- list_add(&draw_info->head, &dev->drwlist);
-
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- draw_info->id = new_id;
draw.handle = new_id;
DRM_DEBUG("%d\n", draw.handle);
@@ -102,7 +99,6 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
spin_lock_irqsave(&dev->drw_lock, irqflags);
- list_del(&draw_info->head);
idr_remove(&dev->drw_idr, draw.handle);
drm_free(draw_info, sizeof(struct drm_drawable_list), DRM_MEM_BUFS);
@@ -199,3 +195,18 @@ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id)
return &draw_info->info;
}
EXPORT_SYMBOL(drm_get_drawable_info);
+
+static int drm_drawable_free(int idr, void *p, void *data)
+{
+ struct drm_drawable_list *drw_entry = p;
+ drm_free(drw_entry->info.rects, drw_entry->info.num_rects *
+ sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+ drm_free(drw_entry, sizeof(struct drm_drawable_list), DRM_MEM_BUFS);
+ return 0;
+}
+
+void drm_drawable_free_all(drm_device_t *dev)
+{
+ idr_for_each(&dev->drw_idr, drm_drawable_free, NULL);
+ idr_remove_all(&dev->drw_idr);
+}
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index 1695a792..d5eb9713 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -142,7 +142,6 @@ int drm_lastclose(drm_device_t * dev)
drm_magic_entry_t *pt, *next;
drm_map_list_t *r_list, *list_t;
drm_vma_entry_t *vma, *vma_temp;
- struct drm_drawable_list *drw_entry, *drw_temp;
int i;
DRM_DEBUG("\n");
@@ -167,16 +166,9 @@ int drm_lastclose(drm_device_t * dev)
drm_irq_uninstall(dev);
/* Free drawable information memory */
- list_for_each_entry_safe(drw_entry, drw_temp, &dev->drwlist, head) {
- drm_free(drw_entry->info.rects, drw_entry->info.num_rects *
- sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
-
- idr_remove(&dev->drw_idr, drw_entry->id);
- list_del(&drw_entry->head);
- drm_free(drw_entry, sizeof(struct drm_drawable_list), DRM_MEM_BUFS);
- }
-
mutex_lock(&dev->struct_mutex);
+
+ drm_drawable_free_all(dev);
del_timer(&dev->timer);
if (dev->unique) {
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c
index 7b0a0f97..f57ed9cc 100644
--- a/linux-core/drm_stub.c
+++ b/linux-core/drm_stub.c
@@ -60,7 +60,6 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
{
int retcode;
- INIT_LIST_HEAD(&dev->drwlist);
INIT_LIST_HEAD(&dev->filelist);
INIT_LIST_HEAD(&dev->ctxlist);
INIT_LIST_HEAD(&dev->vmalist);