diff options
-rw-r--r-- | drivers/char/drm/drm_drawable.c | 262 |
1 files changed, 155 insertions, 107 deletions
diff --git a/drivers/char/drm/drm_drawable.c b/drivers/char/drm/drm_drawable.c index e5f97def26bf..5580c5731eb8 100644 --- a/drivers/char/drm/drm_drawable.c +++ b/drivers/char/drm/drm_drawable.c | |||
@@ -12,6 +12,7 @@ | |||
12 | * | 12 | * |
13 | * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. | 13 | * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. |
14 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. | 14 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. |
15 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota. | ||
15 | * All Rights Reserved. | 16 | * All Rights Reserved. |
16 | * | 17 | * |
17 | * Permission is hereby granted, free of charge, to any person obtaining a | 18 | * Permission is hereby granted, free of charge, to any person obtaining a |
@@ -36,70 +37,86 @@ | |||
36 | 37 | ||
37 | #include "drmP.h" | 38 | #include "drmP.h" |
38 | 39 | ||
39 | /** No-op. */ | 40 | /** |
41 | * Allocate drawable ID and memory to store information about it. | ||
42 | */ | ||
40 | int drm_adddraw(DRM_IOCTL_ARGS) | 43 | int drm_adddraw(DRM_IOCTL_ARGS) |
41 | { | 44 | { |
42 | DRM_DEVICE; | 45 | DRM_DEVICE; |
43 | unsigned long irqflags; | 46 | unsigned long irqflags; |
44 | int i, j = 0; | 47 | int i, j; |
48 | u32 *bitfield = dev->drw_bitfield; | ||
49 | unsigned int bitfield_length = dev->drw_bitfield_length; | ||
50 | drm_drawable_info_t **info = dev->drw_info; | ||
51 | unsigned int info_length = dev->drw_info_length; | ||
45 | drm_draw_t draw; | 52 | drm_draw_t draw; |
46 | 53 | ||
47 | spin_lock_irqsave(&dev->drw_lock, irqflags); | 54 | for (i = 0, j = 0; i < bitfield_length; i++) { |
48 | 55 | if (bitfield[i] == ~0) | |
49 | for (i = 0; i < dev->drw_bitfield_length; i++) { | ||
50 | u32 bitfield = dev->drw_bitfield[i]; | ||
51 | |||
52 | if (bitfield == ~0) | ||
53 | continue; | 56 | continue; |
54 | 57 | ||
55 | for (; j < sizeof(bitfield); j++) | 58 | for (; j < 8 * sizeof(*bitfield); j++) |
56 | if (!(bitfield & (1 << j))) | 59 | if (!(bitfield[i] & (1 << j))) |
57 | goto done; | 60 | goto done; |
58 | } | 61 | } |
59 | done: | 62 | done: |
60 | 63 | ||
61 | if (i == dev->drw_bitfield_length) { | 64 | if (i == bitfield_length) { |
62 | u32 *new_bitfield = drm_realloc(dev->drw_bitfield, i * 4, | 65 | bitfield_length++; |
63 | (i + 1) * 4, DRM_MEM_BUFS); | 66 | |
67 | bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), | ||
68 | DRM_MEM_BUFS); | ||
64 | 69 | ||
65 | if (!new_bitfield) { | 70 | if (!bitfield) { |
66 | DRM_ERROR("Failed to allocate new drawable bitfield\n"); | 71 | DRM_ERROR("Failed to allocate new drawable bitfield\n"); |
67 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
68 | return DRM_ERR(ENOMEM); | 72 | return DRM_ERR(ENOMEM); |
69 | } | 73 | } |
70 | 74 | ||
71 | if (32 * (i + 1) > dev->drw_info_length) { | 75 | if (8 * sizeof(*bitfield) * bitfield_length > info_length) { |
72 | void *new_info = drm_realloc(dev->drw_info, | 76 | info_length += 8 * sizeof(*bitfield); |
73 | dev->drw_info_length * | ||
74 | sizeof(drm_drawable_info_t*), | ||
75 | 32 * (i + 1) * | ||
76 | sizeof(drm_drawable_info_t*), | ||
77 | DRM_MEM_BUFS); | ||
78 | 77 | ||
79 | if (!new_info) { | 78 | info = drm_alloc(info_length * sizeof(*info), |
79 | DRM_MEM_BUFS); | ||
80 | |||
81 | if (!info) { | ||
80 | DRM_ERROR("Failed to allocate new drawable info" | 82 | DRM_ERROR("Failed to allocate new drawable info" |
81 | " array\n"); | 83 | " array\n"); |
82 | 84 | ||
83 | drm_free(new_bitfield, (i + 1) * 4, DRM_MEM_BUFS); | 85 | drm_free(bitfield, |
84 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 86 | bitfield_length * sizeof(*bitfield), |
87 | DRM_MEM_BUFS); | ||
85 | return DRM_ERR(ENOMEM); | 88 | return DRM_ERR(ENOMEM); |
86 | } | 89 | } |
87 | |||
88 | dev->drw_info = (drm_drawable_info_t**)new_info; | ||
89 | } | 90 | } |
90 | 91 | ||
91 | new_bitfield[i] = 0; | 92 | bitfield[i] = 0; |
92 | |||
93 | dev->drw_bitfield = new_bitfield; | ||
94 | dev->drw_bitfield_length++; | ||
95 | } | 93 | } |
96 | 94 | ||
97 | dev->drw_bitfield[i] |= 1 << j; | 95 | draw.handle = i * 8 * sizeof(*bitfield) + j; |
98 | |||
99 | draw.handle = i * sizeof(u32) + j; | ||
100 | DRM_DEBUG("%d\n", draw.handle); | 96 | DRM_DEBUG("%d\n", draw.handle); |
101 | 97 | ||
102 | dev->drw_info[draw.handle] = NULL; | 98 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
99 | |||
100 | bitfield[i] |= 1 << j; | ||
101 | info[draw.handle] = NULL; | ||
102 | |||
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 | } | ||
103 | 120 | ||
104 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 121 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
105 | 122 | ||
@@ -108,63 +125,85 @@ done: | |||
108 | return 0; | 125 | return 0; |
109 | } | 126 | } |
110 | 127 | ||
111 | /** No-op. */ | 128 | /** |
129 | * Free drawable ID and memory to store information about it. | ||
130 | */ | ||
112 | int drm_rmdraw(DRM_IOCTL_ARGS) | 131 | int drm_rmdraw(DRM_IOCTL_ARGS) |
113 | { | 132 | { |
114 | DRM_DEVICE; | 133 | DRM_DEVICE; |
115 | drm_draw_t draw; | 134 | drm_draw_t draw; |
116 | unsigned int idx, mod; | 135 | unsigned int idx, shift; |
117 | unsigned long irqflags; | 136 | unsigned long irqflags; |
137 | u32 *bitfield = dev->drw_bitfield; | ||
138 | unsigned int bitfield_length = dev->drw_bitfield_length; | ||
139 | drm_drawable_info_t **info = dev->drw_info; | ||
140 | unsigned int info_length = dev->drw_info_length; | ||
118 | 141 | ||
119 | DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, | 142 | DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, |
120 | sizeof(draw)); | 143 | sizeof(draw)); |
121 | 144 | ||
122 | idx = draw.handle / 32; | 145 | idx = draw.handle / (8 * sizeof(*bitfield)); |
123 | mod = draw.handle % 32; | 146 | shift = draw.handle % (8 * sizeof(*bitfield)); |
124 | 147 | ||
125 | spin_lock_irqsave(&dev->drw_lock, irqflags); | 148 | if (idx >= bitfield_length || |
126 | 149 | !(bitfield[idx] & (1 << shift))) { | |
127 | if (idx >= dev->drw_bitfield_length || | ||
128 | !(dev->drw_bitfield[idx] & (1 << mod))) { | ||
129 | DRM_DEBUG("No such drawable %d\n", draw.handle); | 150 | DRM_DEBUG("No such drawable %d\n", draw.handle); |
130 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
131 | return 0; | 151 | return 0; |
132 | } | 152 | } |
133 | 153 | ||
134 | dev->drw_bitfield[idx] &= ~(1 << mod); | 154 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
155 | |||
156 | bitfield[idx] &= ~(1 << shift); | ||
157 | |||
158 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
135 | 159 | ||
136 | if (idx == (dev->drw_bitfield_length - 1)) { | 160 | /* Can we shrink the arrays? */ |
137 | while (idx >= 0 && !dev->drw_bitfield[idx]) | 161 | if (idx == bitfield_length - 1) { |
162 | while (idx >= 0 && !bitfield[idx]) | ||
138 | --idx; | 163 | --idx; |
139 | 164 | ||
140 | if (idx != draw.handle / 32) { | 165 | bitfield_length = idx + 1; |
141 | u32 *new_bitfield = drm_realloc(dev->drw_bitfield, | ||
142 | dev->drw_bitfield_length * 4, | ||
143 | (idx + 1) * 4, | ||
144 | DRM_MEM_BUFS); | ||
145 | 166 | ||
146 | if (new_bitfield || idx == -1) { | 167 | if (idx != draw.handle / (8 * sizeof(*bitfield))) |
147 | dev->drw_bitfield = new_bitfield; | 168 | bitfield = drm_alloc(bitfield_length * |
148 | dev->drw_bitfield_length = idx + 1; | 169 | sizeof(*bitfield), DRM_MEM_BUFS); |
149 | } | 170 | |
171 | if (!bitfield && bitfield_length) { | ||
172 | bitfield = dev->drw_bitfield; | ||
173 | bitfield_length = dev->drw_bitfield_length; | ||
150 | } | 174 | } |
151 | } | 175 | } |
152 | 176 | ||
153 | if (32 * dev->drw_bitfield_length < dev->drw_info_length) { | 177 | if (bitfield != dev->drw_bitfield) { |
154 | void *new_info = drm_realloc(dev->drw_info, | 178 | info_length = 8 * sizeof(*bitfield) * bitfield_length; |
155 | dev->drw_info_length * | 179 | |
156 | sizeof(drm_drawable_info_t*), | 180 | info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS); |
157 | 32 * dev->drw_bitfield_length * | 181 | |
158 | sizeof(drm_drawable_info_t*), | 182 | if (!info && info_length) { |
159 | DRM_MEM_BUFS); | 183 | info = dev->drw_info; |
160 | 184 | info_length = dev->drw_info_length; | |
161 | if (new_info || !dev->drw_bitfield_length) { | ||
162 | dev->drw_info = (drm_drawable_info_t**)new_info; | ||
163 | dev->drw_info_length = 32 * dev->drw_bitfield_length; | ||
164 | } | 185 | } |
165 | } | ||
166 | 186 | ||
167 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 187 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
188 | |||
189 | memcpy(bitfield, dev->drw_bitfield, bitfield_length * | ||
190 | sizeof(*bitfield)); | ||
191 | drm_free(dev->drw_bitfield, sizeof(*bitfield) * | ||
192 | dev->drw_bitfield_length, DRM_MEM_BUFS); | ||
193 | dev->drw_bitfield = bitfield; | ||
194 | dev->drw_bitfield_length = bitfield_length; | ||
195 | |||
196 | if (info != dev->drw_info) { | ||
197 | memcpy(info, dev->drw_info, info_length * | ||
198 | sizeof(*info)); | ||
199 | drm_free(dev->drw_info, sizeof(*info) * | ||
200 | dev->drw_info_length, DRM_MEM_BUFS); | ||
201 | dev->drw_info = info; | ||
202 | dev->drw_info_length = info_length; | ||
203 | } | ||
204 | |||
205 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
206 | } | ||
168 | 207 | ||
169 | DRM_DEBUG("%d\n", draw.handle); | 208 | DRM_DEBUG("%d\n", draw.handle); |
170 | return 0; | 209 | return 0; |
@@ -173,24 +212,22 @@ int drm_rmdraw(DRM_IOCTL_ARGS) | |||
173 | int drm_update_drawable_info(DRM_IOCTL_ARGS) { | 212 | int drm_update_drawable_info(DRM_IOCTL_ARGS) { |
174 | DRM_DEVICE; | 213 | DRM_DEVICE; |
175 | drm_update_draw_t update; | 214 | drm_update_draw_t update; |
176 | unsigned int id, idx, mod; | 215 | unsigned int id, idx, shift; |
177 | unsigned long irqflags; | 216 | u32 *bitfield = dev->drw_bitfield; |
217 | unsigned long irqflags, bitfield_length = dev->drw_bitfield_length; | ||
178 | drm_drawable_info_t *info; | 218 | drm_drawable_info_t *info; |
179 | void *new_data; | 219 | drm_clip_rect_t *rects; |
220 | int err; | ||
180 | 221 | ||
181 | DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, | 222 | DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, |
182 | sizeof(update)); | 223 | sizeof(update)); |
183 | 224 | ||
184 | id = update.handle; | 225 | id = update.handle; |
185 | idx = id / 32; | 226 | idx = id / (8 * sizeof(*bitfield)); |
186 | mod = id % 32; | 227 | shift = id % (8 * sizeof(*bitfield)); |
187 | 228 | ||
188 | spin_lock_irqsave(&dev->drw_lock, irqflags); | 229 | if (idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { |
189 | |||
190 | if (idx >= dev->drw_bitfield_length || | ||
191 | !(dev->drw_bitfield[idx] & (1 << mod))) { | ||
192 | DRM_ERROR("No such drawable %d\n", update.handle); | 230 | DRM_ERROR("No such drawable %d\n", update.handle); |
193 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
194 | return DRM_ERR(EINVAL); | 231 | return DRM_ERR(EINVAL); |
195 | } | 232 | } |
196 | 233 | ||
@@ -201,66 +238,77 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) { | |||
201 | 238 | ||
202 | if (!info) { | 239 | if (!info) { |
203 | DRM_ERROR("Failed to allocate drawable info memory\n"); | 240 | DRM_ERROR("Failed to allocate drawable info memory\n"); |
204 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
205 | return DRM_ERR(ENOMEM); | 241 | return DRM_ERR(ENOMEM); |
206 | } | 242 | } |
207 | |||
208 | dev->drw_info[id] = info; | ||
209 | } | 243 | } |
210 | 244 | ||
211 | switch (update.type) { | 245 | switch (update.type) { |
212 | case DRM_DRAWABLE_CLIPRECTS: | 246 | case DRM_DRAWABLE_CLIPRECTS: |
213 | if (update.num != info->num_rects) { | 247 | if (update.num != info->num_rects) { |
214 | new_data = drm_alloc(update.num * | 248 | rects = drm_alloc(update.num * sizeof(drm_clip_rect_t), |
215 | sizeof(drm_clip_rect_t), | 249 | DRM_MEM_BUFS); |
216 | DRM_MEM_BUFS); | 250 | } else |
217 | 251 | rects = info->rects; | |
218 | if (!new_data) { | 252 | |
219 | DRM_ERROR("Can't allocate cliprect memory\n"); | 253 | if (update.num && !rects) { |
220 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 254 | DRM_ERROR("Failed to allocate cliprect memory\n"); |
221 | return DRM_ERR(ENOMEM); | 255 | err = DRM_ERR(ENOMEM); |
222 | } | 256 | goto error; |
223 | |||
224 | info->rects = new_data; | ||
225 | } | 257 | } |
226 | 258 | ||
227 | if (DRM_COPY_FROM_USER(info->rects, | 259 | if (update.num && DRM_COPY_FROM_USER(rects, |
228 | (drm_clip_rect_t __user *) | 260 | (drm_clip_rect_t __user *) |
229 | (unsigned long)update.data, | 261 | (unsigned long)update.data, |
230 | update.num * sizeof(drm_clip_rect_t))) { | 262 | update.num * |
231 | DRM_ERROR("Can't copy cliprects from userspace\n"); | 263 | sizeof(*rects))) { |
232 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 264 | DRM_ERROR("Failed to copy cliprects from userspace\n"); |
233 | return DRM_ERR(EFAULT); | 265 | err = DRM_ERR(EFAULT); |
266 | goto error; | ||
234 | } | 267 | } |
235 | 268 | ||
236 | if (update.num != info->num_rects) { | 269 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
270 | |||
271 | if (rects != info->rects) { | ||
237 | drm_free(info->rects, info->num_rects * | 272 | drm_free(info->rects, info->num_rects * |
238 | sizeof(drm_clip_rect_t), DRM_MEM_BUFS); | 273 | sizeof(drm_clip_rect_t), DRM_MEM_BUFS); |
239 | info->num_rects = update.num; | ||
240 | } | 274 | } |
241 | 275 | ||
276 | info->rects = rects; | ||
277 | info->num_rects = update.num; | ||
278 | dev->drw_info[id] = info; | ||
279 | |||
280 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
281 | |||
242 | DRM_DEBUG("Updated %d cliprects for drawable %d\n", | 282 | DRM_DEBUG("Updated %d cliprects for drawable %d\n", |
243 | info->num_rects, id); | 283 | info->num_rects, id); |
244 | break; | 284 | break; |
245 | default: | 285 | default: |
246 | DRM_ERROR("Invalid update type %d\n", update.type); | 286 | DRM_ERROR("Invalid update type %d\n", update.type); |
247 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
248 | return DRM_ERR(EINVAL); | 287 | return DRM_ERR(EINVAL); |
249 | } | 288 | } |
250 | 289 | ||
251 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
252 | |||
253 | return 0; | 290 | return 0; |
291 | |||
292 | error: | ||
293 | if (!dev->drw_info[id]) | ||
294 | drm_free(info, sizeof(*info), DRM_MEM_BUFS); | ||
295 | else if (rects != dev->drw_info[id]->rects) | ||
296 | drm_free(rects, update.num * | ||
297 | sizeof(drm_clip_rect_t), DRM_MEM_BUFS); | ||
298 | |||
299 | return err; | ||
254 | } | 300 | } |
255 | 301 | ||
256 | /** | 302 | /** |
257 | * Caller must hold the drawable spinlock! | 303 | * Caller must hold the drawable spinlock! |
258 | */ | 304 | */ |
259 | drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { | 305 | drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { |
260 | unsigned int idx = id / 32, mod = id % 32; | 306 | u32 *bitfield = dev->drw_bitfield; |
307 | unsigned int idx = id / (8 * sizeof(*bitfield)); | ||
308 | unsigned int shift = id % (8 * sizeof(*bitfield)); | ||
261 | 309 | ||
262 | if (idx >= dev->drw_bitfield_length || | 310 | if (idx >= dev->drw_bitfield_length || |
263 | !(dev->drw_bitfield[idx] & (1 << mod))) { | 311 | !(bitfield[idx] & (1 << shift))) { |
264 | DRM_DEBUG("No such drawable %d\n", id); | 312 | DRM_DEBUG("No such drawable %d\n", id); |
265 | return NULL; | 313 | return NULL; |
266 | } | 314 | } |