diff options
-rw-r--r-- | linux-core/drm_bo.c | 31 | ||||
-rw-r--r-- | linux-core/drm_bo_move.c | 5 | ||||
-rw-r--r-- | linux-core/drm_vm.c | 24 |
3 files changed, 38 insertions, 22 deletions
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 67e7d37f..3e0d05d2 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1149,7 +1149,7 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, */ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_mem_flags, - int no_wait, int force_no_move) + int no_wait, int force_no_move, int move_unfenced) { drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -1162,14 +1162,6 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_mem_flags, drm_bo_busy(bo); /* - * Make sure we're not mapped. - */ - - ret = drm_bo_wait_unmapped(bo, no_wait); - if (ret) - return ret; - - /* * Wait for outstanding fences. */ @@ -1195,15 +1187,15 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_mem_flags, * Determine where to move the buffer. */ ret = drm_bo_mem_space(dev, &mem, no_wait); - mutex_unlock(&bm->evict_mutex); if (ret) - return ret; + goto out_unlock; ret = drm_bo_handle_move_mem(bo, &mem, 0, no_wait); - if (ret) { - mutex_lock(&dev->struct_mutex); + out_unlock: + if (ret || !move_unfenced) { + mutex_lock(&dev->struct_mutex); if (mem.mm_node) { drm_mm_put_block(mem.mm_node); mem.mm_node = NULL; @@ -1214,6 +1206,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_mem_flags, mutex_unlock(&dev->struct_mutex); } + mutex_unlock(&bm->evict_mutex); return ret; } @@ -1293,6 +1286,10 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, return ret; } + ret = drm_bo_wait_unmapped(bo, no_wait); + if (ret) + return ret; + if (bo->type == drm_bo_type_fake) { ret = drm_bo_check_fake(dev, &bo->mem); if (ret) @@ -1315,7 +1312,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, if (!drm_bo_mem_compat(&bo->mem)) { ret = drm_bo_move_buffer(bo, bo->mem.mask & DRM_BO_MASK_MEMTYPE, - no_wait, 1); + no_wait, 1, move_unfenced); if (ret) { if (ret != -EAGAIN) DRM_ERROR("Failed moving buffer.\n"); @@ -1728,11 +1725,9 @@ static int drm_bo_force_list_clean(drm_device_t * dev, unsigned long _end = jiffies + 3 * DRM_HZ; do { ret = drm_bo_wait(entry, 0, 1, 0); - if (ret && allow_errors) { - if (ret == -EINTR) - ret = -EAGAIN; + if (ret && allow_errors) goto out_err; - } + } while (ret && !time_after_eq(jiffies, _end)); if (entry->fence) { diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index d2c44501..53f7fea8 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -295,10 +295,7 @@ int drm_buffer_object_transfer(drm_buffer_object_t *bo, INIT_LIST_HEAD(&fbo->ddestroy); INIT_LIST_HEAD(&fbo->lru); - bo->mem.mm_node = NULL; - bo->ttm = NULL; atomic_inc(&bo->fence->usage); - bo->mem.flags = 0; fbo->mem.mm_node->private = (void *)fbo; atomic_set(&fbo->usage, 1); @@ -355,7 +352,7 @@ int drm_bo_move_accel_cleanup(drm_buffer_object_t *bo, /* This should help pipeline ordinary buffer moves. * * Hang old buffer memory on a new buffer object, - * and leave it to be released when the blit + * and leave it to be released when the GPU * operation has completed. */ diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 5afa9800..4a41e761 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -746,6 +746,30 @@ struct page *drm_bo_vm_fault(struct vm_area_struct *vma, mutex_lock(&bo->mutex); + /* + * If buffer happens to be in a non-mappable location, + * move it to a mappable. + */ + + if (!(bo->mem.flags & DRM_BO_FLAG_MAPPABLE)) { + uint32_t mask_save = bo->mem.mask; + uint32_t new_mask = bo->mem.mask | + DRM_BO_FLAG_MAPPABLE | + DRM_BO_FLAG_FORCE_MAPPABLE; + + err = drm_bo_move_buffer(bo, new_mask, 0, 0); + bo->mem.mask = mask_save; + + if (!err) + err = drm_bo_wait(bo, 0, 0, 0); + + if (err) { + data->type = (err == -EAGAIN) ? + VM_FAULT_MINOR : VM_FAULT_SIGBUS; + goto out_unlock; + } + } + if (address > vma->vm_end) { data->type = VM_FAULT_SIGBUS; goto out_unlock; |