diff options
author | Christian König <christian.koenig@amd.com> | 2015-04-27 11:04:36 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2015-04-27 11:29:56 -0400 |
commit | c29c0876ec05d51a93508a39b90b92c29ba6423d (patch) | |
tree | 3223b5c64ff0d798634fd0f4f8a7fb587aa0e551 | |
parent | 48afbd70ac7b6aa62e8d452091023941d8085f8a (diff) |
drm/radeon: check new address before removing old one
Otherwise the change isn't atomic.
Signed-off-by: Christian König <christian.koenig@amd.com>
CC: stable@vger.kernel.org
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_vm.c | 31 |
1 files changed, 17 insertions, 14 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index cabcb0aafe03..de42fc4a22b8 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c | |||
@@ -473,6 +473,23 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, | |||
473 | } | 473 | } |
474 | 474 | ||
475 | mutex_lock(&vm->mutex); | 475 | mutex_lock(&vm->mutex); |
476 | soffset /= RADEON_GPU_PAGE_SIZE; | ||
477 | eoffset /= RADEON_GPU_PAGE_SIZE; | ||
478 | if (soffset || eoffset) { | ||
479 | struct interval_tree_node *it; | ||
480 | it = interval_tree_iter_first(&vm->va, soffset, eoffset - 1); | ||
481 | if (it && it != &bo_va->it) { | ||
482 | struct radeon_bo_va *tmp; | ||
483 | tmp = container_of(it, struct radeon_bo_va, it); | ||
484 | /* bo and tmp overlap, invalid offset */ | ||
485 | dev_err(rdev->dev, "bo %p va 0x%010Lx conflict with " | ||
486 | "(bo %p 0x%010lx 0x%010lx)\n", bo_va->bo, | ||
487 | soffset, tmp->bo, tmp->it.start, tmp->it.last); | ||
488 | mutex_unlock(&vm->mutex); | ||
489 | return -EINVAL; | ||
490 | } | ||
491 | } | ||
492 | |||
476 | if (bo_va->it.start || bo_va->it.last) { | 493 | if (bo_va->it.start || bo_va->it.last) { |
477 | if (bo_va->addr) { | 494 | if (bo_va->addr) { |
478 | /* add a clone of the bo_va to clear the old address */ | 495 | /* add a clone of the bo_va to clear the old address */ |
@@ -499,21 +516,7 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, | |||
499 | bo_va->it.last = 0; | 516 | bo_va->it.last = 0; |
500 | } | 517 | } |
501 | 518 | ||
502 | soffset /= RADEON_GPU_PAGE_SIZE; | ||
503 | eoffset /= RADEON_GPU_PAGE_SIZE; | ||
504 | if (soffset || eoffset) { | 519 | if (soffset || eoffset) { |
505 | struct interval_tree_node *it; | ||
506 | it = interval_tree_iter_first(&vm->va, soffset, eoffset - 1); | ||
507 | if (it) { | ||
508 | struct radeon_bo_va *tmp; | ||
509 | tmp = container_of(it, struct radeon_bo_va, it); | ||
510 | /* bo and tmp overlap, invalid offset */ | ||
511 | dev_err(rdev->dev, "bo %p va 0x%010Lx conflict with " | ||
512 | "(bo %p 0x%010lx 0x%010lx)\n", bo_va->bo, | ||
513 | soffset, tmp->bo, tmp->it.start, tmp->it.last); | ||
514 | mutex_unlock(&vm->mutex); | ||
515 | return -EINVAL; | ||
516 | } | ||
517 | bo_va->it.start = soffset; | 520 | bo_va->it.start = soffset; |
518 | bo_va->it.last = eoffset - 1; | 521 | bo_va->it.last = eoffset - 1; |
519 | interval_tree_insert(&bo_va->it, &vm->va); | 522 | interval_tree_insert(&bo_va->it, &vm->va); |