diff options
| -rw-r--r-- | drivers/char/drm/drmP.h | 6 | ||||
| -rw-r--r-- | drivers/char/drm/drm_drawable.c | 248 | ||||
| -rw-r--r-- | drivers/char/drm/drm_drv.c | 15 |
3 files changed, 60 insertions, 209 deletions
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index b1cafe36611e..0df87fc3dcb2 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h | |||
| @@ -751,10 +751,7 @@ struct drm_device { | |||
| 751 | /** \name Drawable information */ | 751 | /** \name Drawable information */ |
| 752 | /*@{ */ | 752 | /*@{ */ |
| 753 | spinlock_t drw_lock; | 753 | spinlock_t drw_lock; |
| 754 | unsigned int drw_bitfield_length; | 754 | struct idr drw_idr; |
| 755 | u32 *drw_bitfield; | ||
| 756 | unsigned int drw_info_length; | ||
| 757 | struct drm_drawable_info **drw_info; | ||
| 758 | /*@} */ | 755 | /*@} */ |
| 759 | }; | 756 | }; |
| 760 | 757 | ||
| @@ -904,6 +901,7 @@ extern int drm_update_drawable_info(struct inode *inode, struct file *filp, | |||
| 904 | unsigned int cmd, unsigned long arg); | 901 | unsigned int cmd, unsigned long arg); |
| 905 | extern struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, | 902 | extern struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, |
| 906 | drm_drawable_t id); | 903 | drm_drawable_t id); |
| 904 | extern void drm_drawable_free_all(struct drm_device *dev); | ||
| 907 | 905 | ||
| 908 | /* Authentication IOCTL support (drm_auth.h) */ | 906 | /* Authentication IOCTL support (drm_auth.h) */ |
| 909 | extern int drm_getmagic(struct inode *inode, struct file *filp, | 907 | extern int drm_getmagic(struct inode *inode, struct file *filp, |
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++) { | 51 | again: |
| 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 | } | ||
| 62 | done: | ||
| 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 | ||
| 231 | int drm_update_drawable_info(DRM_IOCTL_ARGS) { | 99 | int 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 | ||
| 312 | error: | 169 | error: |
| 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 | */ |
| 325 | struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, drm_drawable_t id) { | 180 | struct 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--; | 184 | EXPORT_SYMBOL(drm_get_drawable_info); |
| 330 | idx = id / (8 * sizeof(*bitfield)); | 185 | |
| 331 | shift = id % (8 * sizeof(*bitfield)); | 186 | static 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 | |||
| 199 | void 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 | } |
| 341 | EXPORT_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 */ |
