aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 21:24:37 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 21:24:37 -0400
commita5fcaa210626a79465321e344c91a6a7dc3881fa (patch)
tree8b42dc877829cead9a38fbda664b4c9d3c071fc4 /drivers/char
parent489de30259e667d7bc47da9da44a0270b050cd97 (diff)
parentd4e2cbe9cb9219fc924191a6baa2369140cb5ea8 (diff)
Merge branch 'drm-patches' of ssh://master.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6
* 'drm-patches' of ssh://master.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: drm: convert drawable code to using idr drm: convert drm context code to use Linux idr
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/drm/drmP.h11
-rw-r--r--drivers/char/drm/drm_context.c131
-rw-r--r--drivers/char/drm/drm_drawable.c248
-rw-r--r--drivers/char/drm/drm_drv.c15
4 files changed, 93 insertions, 312 deletions
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 1277693e9ca4..0df87fc3dcb2 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -75,6 +75,8 @@
75#include <asm/pgalloc.h> 75#include <asm/pgalloc.h>
76#include "drm.h" 76#include "drm.h"
77 77
78#include <linux/idr.h>
79
78#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))) 80#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)))
79#define __OS_HAS_MTRR (defined(CONFIG_MTRR)) 81#define __OS_HAS_MTRR (defined(CONFIG_MTRR))
80 82
@@ -676,8 +678,7 @@ struct drm_device {
676 int ctx_count; /**< Number of context handles */ 678 int ctx_count; /**< Number of context handles */
677 struct mutex ctxlist_mutex; /**< For ctxlist */ 679 struct mutex ctxlist_mutex; /**< For ctxlist */
678 680
679 struct drm_map **context_sareas; /**< per-context SAREA's */ 681 struct idr ctx_idr;
680 int max_context;
681 682
682 struct list_head vmalist; /**< List of vmas (for debugging) */ 683 struct list_head vmalist; /**< List of vmas (for debugging) */
683 struct drm_lock_data lock; /**< Information on hardware lock */ 684 struct drm_lock_data lock; /**< Information on hardware lock */
@@ -750,10 +751,7 @@ struct drm_device {
750 /** \name Drawable information */ 751 /** \name Drawable information */
751 /*@{ */ 752 /*@{ */
752 spinlock_t drw_lock; 753 spinlock_t drw_lock;
753 unsigned int drw_bitfield_length; 754 struct idr drw_idr;
754 u32 *drw_bitfield;
755 unsigned int drw_info_length;
756 struct drm_drawable_info **drw_info;
757 /*@} */ 755 /*@} */
758}; 756};
759 757
@@ -903,6 +901,7 @@ extern int drm_update_drawable_info(struct inode *inode, struct file *filp,
903 unsigned int cmd, unsigned long arg); 901 unsigned int cmd, unsigned long arg);
904extern struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, 902extern struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev,
905 drm_drawable_t id); 903 drm_drawable_t id);
904extern void drm_drawable_free_all(struct drm_device *dev);
906 905
907 /* Authentication IOCTL support (drm_auth.h) */ 906 /* Authentication IOCTL support (drm_auth.h) */
908extern int drm_getmagic(struct inode *inode, struct file *filp, 907extern int drm_getmagic(struct inode *inode, struct file *filp,
diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c
index 7fc055adec25..61ad986baa8d 100644
--- a/drivers/char/drm/drm_context.c
+++ b/drivers/char/drm/drm_context.c
@@ -53,26 +53,14 @@
53 * \param ctx_handle context handle. 53 * \param ctx_handle context handle.
54 * 54 *
55 * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry 55 * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
56 * in drm_device::context_sareas, while holding the drm_device::struct_mutex 56 * in drm_device::ctx_idr, while holding the drm_device::struct_mutex
57 * lock. 57 * lock.
58 */ 58 */
59void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle) 59void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
60{ 60{
61 if (ctx_handle < 0) 61 mutex_lock(&dev->struct_mutex);
62 goto failed; 62 idr_remove(&dev->ctx_idr, ctx_handle);
63 if (!dev->ctx_bitmap) 63 mutex_unlock(&dev->struct_mutex);
64 goto failed;
65
66 if (ctx_handle < DRM_MAX_CTXBITMAP) {
67 mutex_lock(&dev->struct_mutex);
68 clear_bit(ctx_handle, dev->ctx_bitmap);
69 dev->context_sareas[ctx_handle] = NULL;
70 mutex_unlock(&dev->struct_mutex);
71 return;
72 }
73 failed:
74 DRM_ERROR("Attempt to free invalid context handle: %d\n", ctx_handle);
75 return;
76} 64}
77 65
78/** 66/**
@@ -81,62 +69,28 @@ void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
81 * \param dev DRM device. 69 * \param dev DRM device.
82 * \return (non-negative) context handle on success or a negative number on failure. 70 * \return (non-negative) context handle on success or a negative number on failure.
83 * 71 *
84 * Find the first zero bit in drm_device::ctx_bitmap and (re)allocates 72 * Allocate a new idr from drm_device::ctx_idr while holding the
85 * drm_device::context_sareas to accommodate the new entry while holding the
86 * drm_device::struct_mutex lock. 73 * drm_device::struct_mutex lock.
87 */ 74 */
88static int drm_ctxbitmap_next(struct drm_device * dev) 75static int drm_ctxbitmap_next(struct drm_device * dev)
89{ 76{
90 int bit; 77 int new_id;
91 78 int ret;
92 if (!dev->ctx_bitmap)
93 return -1;
94 79
80again:
81 if (idr_pre_get(&dev->ctx_idr, GFP_KERNEL) == 0) {
82 DRM_ERROR("Out of memory expanding drawable idr\n");
83 return -ENOMEM;
84 }
95 mutex_lock(&dev->struct_mutex); 85 mutex_lock(&dev->struct_mutex);
96 bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP); 86 ret = idr_get_new_above(&dev->ctx_idr, NULL,
97 if (bit < DRM_MAX_CTXBITMAP) { 87 DRM_RESERVED_CONTEXTS, &new_id);
98 set_bit(bit, dev->ctx_bitmap); 88 if (ret == -EAGAIN) {
99 DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit);
100 if ((bit + 1) > dev->max_context) {
101 dev->max_context = (bit + 1);
102 if (dev->context_sareas) {
103 struct drm_map **ctx_sareas;
104
105 ctx_sareas = drm_realloc(dev->context_sareas,
106 (dev->max_context -
107 1) *
108 sizeof(*dev->
109 context_sareas),
110 dev->max_context *
111 sizeof(*dev->
112 context_sareas),
113 DRM_MEM_MAPS);
114 if (!ctx_sareas) {
115 clear_bit(bit, dev->ctx_bitmap);
116 mutex_unlock(&dev->struct_mutex);
117 return -1;
118 }
119 dev->context_sareas = ctx_sareas;
120 dev->context_sareas[bit] = NULL;
121 } else {
122 /* max_context == 1 at this point */
123 dev->context_sareas =
124 drm_alloc(dev->max_context *
125 sizeof(*dev->context_sareas),
126 DRM_MEM_MAPS);
127 if (!dev->context_sareas) {
128 clear_bit(bit, dev->ctx_bitmap);
129 mutex_unlock(&dev->struct_mutex);
130 return -1;
131 }
132 dev->context_sareas[bit] = NULL;
133 }
134 }
135 mutex_unlock(&dev->struct_mutex); 89 mutex_unlock(&dev->struct_mutex);
136 return bit; 90 goto again;
137 } 91 }
138 mutex_unlock(&dev->struct_mutex); 92 mutex_unlock(&dev->struct_mutex);
139 return -1; 93 return new_id;
140} 94}
141 95
142/** 96/**
@@ -144,31 +98,11 @@ static int drm_ctxbitmap_next(struct drm_device * dev)
144 * 98 *
145 * \param dev DRM device. 99 * \param dev DRM device.
146 * 100 *
147 * Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding 101 * Initialise the drm_device::ctx_idr
148 * the drm_device::struct_mutex lock.
149 */ 102 */
150int drm_ctxbitmap_init(struct drm_device * dev) 103int drm_ctxbitmap_init(struct drm_device * dev)
151{ 104{
152 int i; 105 idr_init(&dev->ctx_idr);
153 int temp;
154
155 mutex_lock(&dev->struct_mutex);
156 dev->ctx_bitmap = (unsigned long *)drm_alloc(PAGE_SIZE,
157 DRM_MEM_CTXBITMAP);
158 if (dev->ctx_bitmap == NULL) {
159 mutex_unlock(&dev->struct_mutex);
160 return -ENOMEM;
161 }
162 memset((void *)dev->ctx_bitmap, 0, PAGE_SIZE);
163 dev->context_sareas = NULL;
164 dev->max_context = -1;
165 mutex_unlock(&dev->struct_mutex);
166
167 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
168 temp = drm_ctxbitmap_next(dev);
169 DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
170 }
171
172 return 0; 106 return 0;
173} 107}
174 108
@@ -177,17 +111,13 @@ int drm_ctxbitmap_init(struct drm_device * dev)
177 * 111 *
178 * \param dev DRM device. 112 * \param dev DRM device.
179 * 113 *
180 * Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding 114 * Free all idr members using drm_ctx_sarea_free helper function
181 * the drm_device::struct_mutex lock. 115 * while holding the drm_device::struct_mutex lock.
182 */ 116 */
183void drm_ctxbitmap_cleanup(struct drm_device * dev) 117void drm_ctxbitmap_cleanup(struct drm_device * dev)
184{ 118{
185 mutex_lock(&dev->struct_mutex); 119 mutex_lock(&dev->struct_mutex);
186 if (dev->context_sareas) 120 idr_remove_all(&dev->ctx_idr);
187 drm_free(dev->context_sareas,
188 sizeof(*dev->context_sareas) *
189 dev->max_context, DRM_MEM_MAPS);
190 drm_free((void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP);
191 mutex_unlock(&dev->struct_mutex); 121 mutex_unlock(&dev->struct_mutex);
192} 122}
193 123
@@ -206,7 +136,7 @@ void drm_ctxbitmap_cleanup(struct drm_device * dev)
206 * \param arg user argument pointing to a drm_ctx_priv_map structure. 136 * \param arg user argument pointing to a drm_ctx_priv_map structure.
207 * \return zero on success or a negative number on failure. 137 * \return zero on success or a negative number on failure.
208 * 138 *
209 * Gets the map from drm_device::context_sareas with the handle specified and 139 * Gets the map from drm_device::ctx_idr with the handle specified and
210 * returns its handle. 140 * returns its handle.
211 */ 141 */
212int drm_getsareactx(struct inode *inode, struct file *filp, 142int drm_getsareactx(struct inode *inode, struct file *filp,
@@ -223,13 +153,13 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
223 return -EFAULT; 153 return -EFAULT;
224 154
225 mutex_lock(&dev->struct_mutex); 155 mutex_lock(&dev->struct_mutex);
226 if (dev->max_context < 0 156
227 || request.ctx_id >= (unsigned)dev->max_context) { 157 map = idr_find(&dev->ctx_idr, request.ctx_id);
158 if (!map) {
228 mutex_unlock(&dev->struct_mutex); 159 mutex_unlock(&dev->struct_mutex);
229 return -EINVAL; 160 return -EINVAL;
230 } 161 }
231 162
232 map = dev->context_sareas[request.ctx_id];
233 mutex_unlock(&dev->struct_mutex); 163 mutex_unlock(&dev->struct_mutex);
234 164
235 request.handle = NULL; 165 request.handle = NULL;
@@ -258,7 +188,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
258 * \return zero on success or a negative number on failure. 188 * \return zero on success or a negative number on failure.
259 * 189 *
260 * Searches the mapping specified in \p arg and update the entry in 190 * Searches the mapping specified in \p arg and update the entry in
261 * drm_device::context_sareas with it. 191 * drm_device::ctx_idr with it.
262 */ 192 */
263int drm_setsareactx(struct inode *inode, struct file *filp, 193int drm_setsareactx(struct inode *inode, struct file *filp,
264 unsigned int cmd, unsigned long arg) 194 unsigned int cmd, unsigned long arg)
@@ -288,11 +218,10 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
288 map = r_list->map; 218 map = r_list->map;
289 if (!map) 219 if (!map)
290 goto bad; 220 goto bad;
291 if (dev->max_context < 0) 221
292 goto bad; 222 if (IS_ERR(idr_replace(&dev->ctx_idr, map, request.ctx_id)))
293 if (request.ctx_id >= (unsigned)dev->max_context)
294 goto bad; 223 goto bad;
295 dev->context_sareas[request.ctx_id] = map; 224
296 mutex_unlock(&dev->struct_mutex); 225 mutex_unlock(&dev->struct_mutex);
297 return 0; 226 return 0;
298} 227}
diff --git a/drivers/char/drm/drm_drawable.c b/drivers/char/drm/drm_drawable.c
index 309e585a5442..d6cdba5644e2 100644
--- a/drivers/char/drm/drm_drawable.c
+++ b/drivers/char/drm/drm_drawable.c
@@ -44,82 +44,29 @@ int drm_adddraw(DRM_IOCTL_ARGS)
44{ 44{
45 DRM_DEVICE; 45 DRM_DEVICE;
46 unsigned long irqflags; 46 unsigned long irqflags;
47 int i, j;
48 u32 *bitfield = dev->drw_bitfield;
49 unsigned int bitfield_length = dev->drw_bitfield_length;
50 struct drm_drawable_info **info = dev->drw_info;
51 unsigned int info_length = dev->drw_info_length;
52 struct drm_draw draw; 47 struct drm_draw draw;
48 int new_id = 0;
49 int ret;
53 50
54 for (i = 0, j = 0; i < bitfield_length; i++) { 51again:
55 if (bitfield[i] == ~0) 52 if (idr_pre_get(&dev->drw_idr, GFP_KERNEL) == 0) {
56 continue; 53 DRM_ERROR("Out of memory expanding drawable idr\n");
57 54 return -ENOMEM;
58 for (; j < 8 * sizeof(*bitfield); j++)
59 if (!(bitfield[i] & (1 << j)))
60 goto done;
61 }
62done:
63
64 if (i == bitfield_length) {
65 bitfield_length++;
66
67 bitfield = drm_alloc(bitfield_length * sizeof(*bitfield),
68 DRM_MEM_BUFS);
69
70 if (!bitfield) {
71 DRM_ERROR("Failed to allocate new drawable bitfield\n");
72 return DRM_ERR(ENOMEM);
73 }
74
75 if (8 * sizeof(*bitfield) * bitfield_length > info_length) {
76 info_length += 8 * sizeof(*bitfield);
77
78 info = drm_alloc(info_length * sizeof(*info),
79 DRM_MEM_BUFS);
80
81 if (!info) {
82 DRM_ERROR("Failed to allocate new drawable info"
83 " array\n");
84
85 drm_free(bitfield,
86 bitfield_length * sizeof(*bitfield),
87 DRM_MEM_BUFS);
88 return DRM_ERR(ENOMEM);
89 }
90 }
91
92 bitfield[i] = 0;
93 } 55 }
94 56
95 draw.handle = i * 8 * sizeof(*bitfield) + j + 1;
96 DRM_DEBUG("%d\n", draw.handle);
97
98 spin_lock_irqsave(&dev->drw_lock, irqflags); 57 spin_lock_irqsave(&dev->drw_lock, irqflags);
99 58 ret = idr_get_new_above(&dev->drw_idr, NULL, 1, &new_id);
100 bitfield[i] |= 1 << j; 59 if (ret == -EAGAIN) {
101 info[draw.handle - 1] = NULL; 60 spin_unlock_irqrestore(&dev->drw_lock, irqflags);
102 61 goto again;
103 if (bitfield != dev->drw_bitfield) {
104 memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length *
105 sizeof(*bitfield));
106 drm_free(dev->drw_bitfield, sizeof(*bitfield) *
107 dev->drw_bitfield_length, DRM_MEM_BUFS);
108 dev->drw_bitfield = bitfield;
109 dev->drw_bitfield_length = bitfield_length;
110 }
111
112 if (info != dev->drw_info) {
113 memcpy(info, dev->drw_info, dev->drw_info_length *
114 sizeof(*info));
115 drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length,
116 DRM_MEM_BUFS);
117 dev->drw_info = info;
118 dev->drw_info_length = info_length;
119 } 62 }
120 63
121 spin_unlock_irqrestore(&dev->drw_lock, irqflags); 64 spin_unlock_irqrestore(&dev->drw_lock, irqflags);
122 65
66 draw.handle = new_id;
67
68 DRM_DEBUG("%d\n", draw.handle);
69
123 DRM_COPY_TO_USER_IOCTL((struct drm_draw __user *)data, draw, sizeof(draw)); 70 DRM_COPY_TO_USER_IOCTL((struct drm_draw __user *)data, draw, sizeof(draw));
124 71
125 return 0; 72 return 0;
@@ -132,133 +79,44 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
132{ 79{
133 DRM_DEVICE; 80 DRM_DEVICE;
134 struct drm_draw draw; 81 struct drm_draw draw;
135 int id, idx;
136 unsigned int shift;
137 unsigned long irqflags; 82 unsigned long irqflags;
138 u32 *bitfield = dev->drw_bitfield;
139 unsigned int bitfield_length = dev->drw_bitfield_length;
140 struct drm_drawable_info **info = dev->drw_info;
141 unsigned int info_length = dev->drw_info_length;
142 83
143 DRM_COPY_FROM_USER_IOCTL(draw, (struct drm_draw __user *) data, 84 DRM_COPY_FROM_USER_IOCTL(draw, (struct drm_draw __user *) data,
144 sizeof(draw)); 85 sizeof(draw));
145 86
146 id = draw.handle - 1;
147 idx = id / (8 * sizeof(*bitfield));
148 shift = id % (8 * sizeof(*bitfield));
149
150 if (idx < 0 || idx >= bitfield_length ||
151 !(bitfield[idx] & (1 << shift))) {
152 DRM_DEBUG("No such drawable %d\n", draw.handle);
153 return 0;
154 }
155
156 spin_lock_irqsave(&dev->drw_lock, irqflags); 87 spin_lock_irqsave(&dev->drw_lock, irqflags);
157 88
158 bitfield[idx] &= ~(1 << shift); 89 drm_free(drm_get_drawable_info(dev, draw.handle),
159 90 sizeof(struct drm_drawable_info), DRM_MEM_BUFS);
160 spin_unlock_irqrestore(&dev->drw_lock, irqflags);
161
162 if (info[id]) {
163 drm_free(info[id]->rects, info[id]->num_rects *
164 sizeof(struct drm_clip_rect), DRM_MEM_BUFS);
165 drm_free(info[id], sizeof(**info), DRM_MEM_BUFS);
166 }
167
168 /* Can we shrink the arrays? */
169 if (idx == bitfield_length - 1) {
170 while (idx >= 0 && !bitfield[idx])
171 --idx;
172
173 bitfield_length = idx + 1;
174
175 bitfield = NULL;
176
177 if (bitfield_length) {
178 if (bitfield_length != dev->drw_bitfield_length)
179 bitfield = drm_alloc(bitfield_length *
180 sizeof(*bitfield),
181 DRM_MEM_BUFS);
182
183 if (!bitfield) {
184 bitfield = dev->drw_bitfield;
185 bitfield_length = dev->drw_bitfield_length;
186 }
187 }
188 }
189
190 if (bitfield != dev->drw_bitfield) {
191 info_length = 8 * sizeof(*bitfield) * bitfield_length;
192
193 if (info_length) {
194 info = drm_alloc(info_length * sizeof(*info),
195 DRM_MEM_BUFS);
196
197 if (!info) {
198 info = dev->drw_info;
199 info_length = dev->drw_info_length;
200 }
201 } else
202 info = NULL;
203
204 spin_lock_irqsave(&dev->drw_lock, irqflags);
205
206 if (bitfield)
207 memcpy(bitfield, dev->drw_bitfield, bitfield_length *
208 sizeof(*bitfield));
209 drm_free(dev->drw_bitfield, sizeof(*bitfield) *
210 dev->drw_bitfield_length, DRM_MEM_BUFS);
211 dev->drw_bitfield = bitfield;
212 dev->drw_bitfield_length = bitfield_length;
213
214 if (info != dev->drw_info) {
215 if (info)
216 memcpy(info, dev->drw_info, info_length *
217 sizeof(*info));
218 drm_free(dev->drw_info, sizeof(*info) *
219 dev->drw_info_length, DRM_MEM_BUFS);
220 dev->drw_info = info;
221 dev->drw_info_length = info_length;
222 }
223 91
224 spin_unlock_irqrestore(&dev->drw_lock, irqflags); 92 idr_remove(&dev->drw_idr, draw.handle);
225 }
226 93
94 spin_unlock_irqrestore(&dev->drw_lock, irqflags);
227 DRM_DEBUG("%d\n", draw.handle); 95 DRM_DEBUG("%d\n", draw.handle);
228 return 0; 96 return 0;
229} 97}
230 98
231int drm_update_drawable_info(DRM_IOCTL_ARGS) { 99int drm_update_drawable_info(DRM_IOCTL_ARGS)
100{
232 DRM_DEVICE; 101 DRM_DEVICE;
233 struct drm_update_draw update; 102 struct drm_update_draw update;
234 unsigned int id, idx, shift; 103 unsigned long irqflags;
235 u32 *bitfield = dev->drw_bitfield;
236 unsigned long irqflags, bitfield_length = dev->drw_bitfield_length;
237 struct drm_drawable_info *info;
238 struct drm_clip_rect *rects; 104 struct drm_clip_rect *rects;
105 struct drm_drawable_info *info;
239 int err; 106 int err;
240 107
241 DRM_COPY_FROM_USER_IOCTL(update, (struct drm_update_draw __user *) data, 108 DRM_COPY_FROM_USER_IOCTL(update, (struct drm_update_draw __user *) data,
242 sizeof(update)); 109 sizeof(update));
243 110
244 id = update.handle - 1; 111 info = idr_find(&dev->drw_idr, update.handle);
245 idx = id / (8 * sizeof(*bitfield));
246 shift = id % (8 * sizeof(*bitfield));
247
248 if (idx < 0 || idx >= bitfield_length ||
249 !(bitfield[idx] & (1 << shift))) {
250 DRM_ERROR("No such drawable %d\n", update.handle);
251 return DRM_ERR(EINVAL);
252 }
253
254 info = dev->drw_info[id];
255
256 if (!info) { 112 if (!info) {
257 info = drm_calloc(1, sizeof(struct drm_drawable_info), DRM_MEM_BUFS); 113 info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS);
258 114 if (!info)
259 if (!info) { 115 return -ENOMEM;
260 DRM_ERROR("Failed to allocate drawable info memory\n"); 116 if (IS_ERR(idr_replace(&dev->drw_idr, info, update.handle))) {
261 return DRM_ERR(ENOMEM); 117 DRM_ERROR("No such drawable %d\n", update.handle);
118 drm_free(info, sizeof(*info), DRM_MEM_BUFS);
119 return -EINVAL;
262 } 120 }
263 } 121 }
264 122
@@ -295,12 +153,11 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) {
295 153
296 info->rects = rects; 154 info->rects = rects;
297 info->num_rects = update.num; 155 info->num_rects = update.num;
298 dev->drw_info[id] = info;
299 156
300 spin_unlock_irqrestore(&dev->drw_lock, irqflags); 157 spin_unlock_irqrestore(&dev->drw_lock, irqflags);
301 158
302 DRM_DEBUG("Updated %d cliprects for drawable %d\n", 159 DRM_DEBUG("Updated %d cliprects for drawable %d\n",
303 info->num_rects, id); 160 info->num_rects, update.handle);
304 break; 161 break;
305 default: 162 default:
306 DRM_ERROR("Invalid update type %d\n", update.type); 163 DRM_ERROR("Invalid update type %d\n", update.type);
@@ -310,11 +167,9 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) {
310 return 0; 167 return 0;
311 168
312error: 169error:
313 if (!dev->drw_info[id]) 170 if (rects != info->rects)
314 drm_free(info, sizeof(*info), DRM_MEM_BUFS); 171 drm_free(rects, update.num * sizeof(struct drm_clip_rect),
315 else if (rects != dev->drw_info[id]->rects) 172 DRM_MEM_BUFS);
316 drm_free(rects, update.num *
317 sizeof(struct drm_clip_rect), DRM_MEM_BUFS);
318 173
319 return err; 174 return err;
320} 175}
@@ -322,20 +177,27 @@ error:
322/** 177/**
323 * Caller must hold the drawable spinlock! 178 * Caller must hold the drawable spinlock!
324 */ 179 */
325struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, drm_drawable_t id) { 180struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, drm_drawable_t id)
326 u32 *bitfield = dev->drw_bitfield; 181{
327 unsigned int idx, shift; 182 return idr_find(&dev->drw_idr, id);
328 183}
329 id--; 184EXPORT_SYMBOL(drm_get_drawable_info);
330 idx = id / (8 * sizeof(*bitfield)); 185
331 shift = id % (8 * sizeof(*bitfield)); 186static int drm_drawable_free(int idr, void *p, void *data)
332 187{
333 if (idx < 0 || idx >= dev->drw_bitfield_length || 188 struct drm_drawable_info *info = p;
334 !(bitfield[idx] & (1 << shift))) { 189
335 DRM_DEBUG("No such drawable %d\n", id); 190 if (info) {
336 return NULL; 191 drm_free(info->rects, info->num_rects *
192 sizeof(struct drm_clip_rect), DRM_MEM_BUFS);
193 drm_free(info, sizeof(*info), DRM_MEM_BUFS);
337 } 194 }
338 195
339 return dev->drw_info[id]; 196 return 0;
197}
198
199void drm_drawable_free_all(struct drm_device *dev)
200{
201 idr_for_each(&dev->drw_idr, drm_drawable_free, NULL);
202 idr_remove_all(&dev->drw_idr);
340} 203}
341EXPORT_SYMBOL(drm_get_drawable_info);
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index d5cf5cfccf78..19994cd865de 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -151,19 +151,10 @@ int drm_lastclose(struct drm_device * dev)
151 if (dev->irq_enabled) 151 if (dev->irq_enabled)
152 drm_irq_uninstall(dev); 152 drm_irq_uninstall(dev);
153 153
154 /* Free drawable information memory */
155 for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield);
156 i++) {
157 struct drm_drawable_info *info = drm_get_drawable_info(dev, i);
158
159 if (info) {
160 drm_free(info->rects, info->num_rects *
161 sizeof(struct drm_clip_rect), DRM_MEM_BUFS);
162 drm_free(info, sizeof(*info), DRM_MEM_BUFS);
163 }
164 }
165
166 mutex_lock(&dev->struct_mutex); 154 mutex_lock(&dev->struct_mutex);
155
156 /* Free drawable information memory */
157 drm_drawable_free_all(dev);
167 del_timer(&dev->timer); 158 del_timer(&dev->timer);
168 159
169 /* Clear pid list */ 160 /* Clear pid list */