diff options
author | Alan Hourihane <alanh@fairlite.demon.co.uk> | 2007-06-29 20:09:44 +0100 |
---|---|---|
committer | Alan Hourihane <alanh@fairlite.demon.co.uk> | 2007-06-29 20:09:44 +0100 |
commit | 8a78dead291ffdb5a8774419cdca369a1e27cad9 (patch) | |
tree | 399b8378e32036bdc7dadc10c639465a8fb21681 /linux-core/drm_compat.c | |
parent | e79e2a58161d44754fd55507e155b7e12a09c4d2 (diff) | |
parent | a27af4c4a665864df09123f177ca7269e48f6171 (diff) |
Merge branch 'master' of git+ssh://git.freedesktop.org/git/mesa/drm into modesetting-101
Conflicts:
linux-core/drm_drv.c
linux-core/drm_fops.c
linux-core/drm_objects.h
linux-core/drm_stub.c
shared-core/i915_dma.c
Diffstat (limited to 'linux-core/drm_compat.c')
-rw-r--r-- | linux-core/drm_compat.c | 123 |
1 files changed, 123 insertions, 0 deletions
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 |