diff options
Diffstat (limited to 'drivers/char/drm/drm_bufs.c')
-rw-r--r-- | drivers/char/drm/drm_bufs.c | 75 |
1 files changed, 66 insertions, 9 deletions
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index a6828cc14e58..c11345856ffe 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c | |||
@@ -57,7 +57,8 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, | |||
57 | list_for_each(list, &dev->maplist->head) { | 57 | list_for_each(list, &dev->maplist->head) { |
58 | drm_map_list_t *entry = list_entry(list, drm_map_list_t, head); | 58 | drm_map_list_t *entry = list_entry(list, drm_map_list_t, head); |
59 | if (entry->map && map->type == entry->map->type && | 59 | if (entry->map && map->type == entry->map->type && |
60 | entry->map->offset == map->offset) { | 60 | ((entry->map->offset == map->offset) || |
61 | (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) { | ||
61 | return entry; | 62 | return entry; |
62 | } | 63 | } |
63 | } | 64 | } |
@@ -180,8 +181,20 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, | |||
180 | if (map->type == _DRM_REGISTERS) | 181 | if (map->type == _DRM_REGISTERS) |
181 | map->handle = ioremap(map->offset, map->size); | 182 | map->handle = ioremap(map->offset, map->size); |
182 | break; | 183 | break; |
183 | |||
184 | case _DRM_SHM: | 184 | case _DRM_SHM: |
185 | list = drm_find_matching_map(dev, map); | ||
186 | if (list != NULL) { | ||
187 | if(list->map->size != map->size) { | ||
188 | DRM_DEBUG("Matching maps of type %d with " | ||
189 | "mismatched sizes, (%ld vs %ld)\n", | ||
190 | map->type, map->size, list->map->size); | ||
191 | list->map->size = map->size; | ||
192 | } | ||
193 | |||
194 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | ||
195 | *maplist = list; | ||
196 | return 0; | ||
197 | } | ||
185 | map->handle = vmalloc_user(map->size); | 198 | map->handle = vmalloc_user(map->size); |
186 | DRM_DEBUG("%lu %d %p\n", | 199 | DRM_DEBUG("%lu %d %p\n", |
187 | map->size, drm_order(map->size), map->handle); | 200 | map->size, drm_order(map->size), map->handle); |
@@ -200,15 +213,45 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, | |||
200 | dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */ | 213 | dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */ |
201 | } | 214 | } |
202 | break; | 215 | break; |
203 | case _DRM_AGP: | 216 | case _DRM_AGP: { |
204 | if (drm_core_has_AGP(dev)) { | 217 | drm_agp_mem_t *entry; |
218 | int valid = 0; | ||
219 | |||
220 | if (!drm_core_has_AGP(dev)) { | ||
221 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | ||
222 | return -EINVAL; | ||
223 | } | ||
205 | #ifdef __alpha__ | 224 | #ifdef __alpha__ |
206 | map->offset += dev->hose->mem_space->start; | 225 | map->offset += dev->hose->mem_space->start; |
207 | #endif | 226 | #endif |
208 | map->offset += dev->agp->base; | 227 | /* Note: dev->agp->base may actually be 0 when the DRM |
209 | map->mtrr = dev->agp->agp_mtrr; /* for getmap */ | 228 | * is not in control of AGP space. But if user space is |
229 | * it should already have added the AGP base itself. | ||
230 | */ | ||
231 | map->offset += dev->agp->base; | ||
232 | map->mtrr = dev->agp->agp_mtrr; /* for getmap */ | ||
233 | |||
234 | /* This assumes the DRM is in total control of AGP space. | ||
235 | * It's not always the case as AGP can be in the control | ||
236 | * of user space (i.e. i810 driver). So this loop will get | ||
237 | * skipped and we double check that dev->agp->memory is | ||
238 | * actually set as well as being invalid before EPERM'ing | ||
239 | */ | ||
240 | for (entry = dev->agp->memory; entry; entry = entry->next) { | ||
241 | if ((map->offset >= entry->bound) && | ||
242 | (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) { | ||
243 | valid = 1; | ||
244 | break; | ||
245 | } | ||
210 | } | 246 | } |
247 | if (dev->agp->memory && !valid) { | ||
248 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | ||
249 | return -EPERM; | ||
250 | } | ||
251 | DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size); | ||
252 | |||
211 | break; | 253 | break; |
254 | } | ||
212 | case _DRM_SCATTER_GATHER: | 255 | case _DRM_SCATTER_GATHER: |
213 | if (!dev->sg) { | 256 | if (!dev->sg) { |
214 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | 257 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); |
@@ -267,7 +310,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, | |||
267 | 310 | ||
268 | *maplist = list; | 311 | *maplist = list; |
269 | return 0; | 312 | return 0; |
270 | } | 313 | } |
271 | 314 | ||
272 | int drm_addmap(drm_device_t * dev, unsigned int offset, | 315 | int drm_addmap(drm_device_t * dev, unsigned int offset, |
273 | unsigned int size, drm_map_type_t type, | 316 | unsigned int size, drm_map_type_t type, |
@@ -519,6 +562,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) | |||
519 | { | 562 | { |
520 | drm_device_dma_t *dma = dev->dma; | 563 | drm_device_dma_t *dma = dev->dma; |
521 | drm_buf_entry_t *entry; | 564 | drm_buf_entry_t *entry; |
565 | drm_agp_mem_t *agp_entry; | ||
522 | drm_buf_t *buf; | 566 | drm_buf_t *buf; |
523 | unsigned long offset; | 567 | unsigned long offset; |
524 | unsigned long agp_offset; | 568 | unsigned long agp_offset; |
@@ -529,7 +573,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) | |||
529 | int page_order; | 573 | int page_order; |
530 | int total; | 574 | int total; |
531 | int byte_count; | 575 | int byte_count; |
532 | int i; | 576 | int i, valid; |
533 | drm_buf_t **temp_buflist; | 577 | drm_buf_t **temp_buflist; |
534 | 578 | ||
535 | if (!dma) | 579 | if (!dma) |
@@ -560,6 +604,19 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) | |||
560 | if (dev->queue_count) | 604 | if (dev->queue_count) |
561 | return -EBUSY; /* Not while in use */ | 605 | return -EBUSY; /* Not while in use */ |
562 | 606 | ||
607 | /* Make sure buffers are located in AGP memory that we own */ | ||
608 | valid = 0; | ||
609 | for (agp_entry = dev->agp->memory; agp_entry; agp_entry = agp_entry->next) { | ||
610 | if ((agp_offset >= agp_entry->bound) && | ||
611 | (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { | ||
612 | valid = 1; | ||
613 | break; | ||
614 | } | ||
615 | } | ||
616 | if (dev->agp->memory && !valid) { | ||
617 | DRM_DEBUG("zone invalid\n"); | ||
618 | return -EINVAL; | ||
619 | } | ||
563 | spin_lock(&dev->count_lock); | 620 | spin_lock(&dev->count_lock); |
564 | if (dev->buf_use) { | 621 | if (dev->buf_use) { |
565 | spin_unlock(&dev->count_lock); | 622 | spin_unlock(&dev->count_lock); |