aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/drm_drawable.c
diff options
context:
space:
mode:
author=?utf-8?q?Michel_D=C3=A4nzer?= <michel@tungstengraphics.com>2006-10-24 09:18:49 -0400
committerairlied <airlied@linux.ie>2006-12-06 23:53:29 -0500
commitb03ed6f2fc519930fe3950365be59f0c079ce5d8 (patch)
tree4c73ebb992b1efa8ad95f63b68ada4357ecbd00b /drivers/char/drm/drm_drawable.c
parent2e54a007622ac75d63bdc1dd71d435446293f4a9 (diff)
drm: drawable locking + memory management fixes + copyright
Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/char/drm/drm_drawable.c')
-rw-r--r--drivers/char/drm/drm_drawable.c262
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 */
40int drm_adddraw(DRM_IOCTL_ARGS) 43int 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 }
59done: 62done:
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 */
112int drm_rmdraw(DRM_IOCTL_ARGS) 131int 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)
173int drm_update_drawable_info(DRM_IOCTL_ARGS) { 212int 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
292error:
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 */
259drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { 305drm_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 }