Commit 5876dd24 authored by Matthew Garrett's avatar Matthew Garrett Committed by Dave Airlie

radeon: Unmap vram pages when reclocking

Touching vram while the card is reclocking can lead to lockups. Unmap
any pages that could be touched by the CPU and block any accesses to
vram until the reclocking is complete.
Signed-off-by: default avatarMatthew Garrett <mjg@redhat.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 2aba631c
...@@ -1024,6 +1024,7 @@ struct radeon_device { ...@@ -1024,6 +1024,7 @@ struct radeon_device {
struct work_struct hotplug_work; struct work_struct hotplug_work;
int num_crtc; /* number of crtcs */ int num_crtc; /* number of crtcs */
struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */ struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
struct mutex vram_mutex;
/* audio stuff */ /* audio stuff */
struct timer_list audio_timer; struct timer_list audio_timer;
......
...@@ -599,6 +599,7 @@ int radeon_device_init(struct radeon_device *rdev, ...@@ -599,6 +599,7 @@ int radeon_device_init(struct radeon_device *rdev,
spin_lock_init(&rdev->ih.lock); spin_lock_init(&rdev->ih.lock);
mutex_init(&rdev->gem.mutex); mutex_init(&rdev->gem.mutex);
mutex_init(&rdev->pm.mutex); mutex_init(&rdev->pm.mutex);
mutex_init(&rdev->vram_mutex);
rwlock_init(&rdev->fence_drv.lock); rwlock_init(&rdev->fence_drv.lock);
INIT_LIST_HEAD(&rdev->gem.objects); INIT_LIST_HEAD(&rdev->gem.objects);
init_waitqueue_head(&rdev->irq.vblank_queue); init_waitqueue_head(&rdev->irq.vblank_queue);
......
...@@ -112,9 +112,11 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj, ...@@ -112,9 +112,11 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
radeon_ttm_placement_from_domain(bo, domain); radeon_ttm_placement_from_domain(bo, domain);
/* Kernel allocation are uninterruptible */ /* Kernel allocation are uninterruptible */
mutex_lock(&rdev->vram_mutex);
r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type, r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
&bo->placement, 0, 0, !kernel, NULL, size, &bo->placement, 0, 0, !kernel, NULL, size,
&radeon_ttm_bo_destroy); &radeon_ttm_bo_destroy);
mutex_unlock(&rdev->vram_mutex);
if (unlikely(r != 0)) { if (unlikely(r != 0)) {
if (r != -ERESTARTSYS) if (r != -ERESTARTSYS)
dev_err(rdev->dev, dev_err(rdev->dev,
...@@ -170,7 +172,9 @@ void radeon_bo_unref(struct radeon_bo **bo) ...@@ -170,7 +172,9 @@ void radeon_bo_unref(struct radeon_bo **bo)
if ((*bo) == NULL) if ((*bo) == NULL)
return; return;
tbo = &((*bo)->tbo); tbo = &((*bo)->tbo);
mutex_lock(&(*bo)->rdev->vram_mutex);
ttm_bo_unref(&tbo); ttm_bo_unref(&tbo);
mutex_unlock(&(*bo)->rdev->vram_mutex);
if (tbo == NULL) if (tbo == NULL)
*bo = NULL; *bo = NULL;
} }
......
...@@ -32,6 +32,28 @@ ...@@ -32,6 +32,28 @@
static void radeon_pm_idle_work_handler(struct work_struct *work); static void radeon_pm_idle_work_handler(struct work_struct *work);
static int radeon_debugfs_pm_init(struct radeon_device *rdev); static int radeon_debugfs_pm_init(struct radeon_device *rdev);
static void radeon_unmap_vram_bos(struct radeon_device *rdev)
{
struct radeon_bo *bo, *n;
if (list_empty(&rdev->gem.objects))
return;
list_for_each_entry_safe(bo, n, &rdev->gem.objects, list) {
if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
ttm_bo_unmap_virtual(&bo->tbo);
}
if (rdev->gart.table.vram.robj)
ttm_bo_unmap_virtual(&rdev->gart.table.vram.robj->tbo);
if (rdev->stollen_vga_memory)
ttm_bo_unmap_virtual(&rdev->stollen_vga_memory->tbo);
if (rdev->r600_blit.shader_obj)
ttm_bo_unmap_virtual(&rdev->r600_blit.shader_obj->tbo);
}
static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch)
{ {
int i; int i;
...@@ -48,6 +70,10 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) ...@@ -48,6 +70,10 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch)
rdev->irq.gui_idle = false; rdev->irq.gui_idle = false;
radeon_irq_set(rdev); radeon_irq_set(rdev);
mutex_lock(&rdev->vram_mutex);
radeon_unmap_vram_bos(rdev);
if (!static_switch) { if (!static_switch) {
for (i = 0; i < rdev->num_crtc; i++) { for (i = 0; i < rdev->num_crtc; i++) {
if (rdev->pm.active_crtcs & (1 << i)) { if (rdev->pm.active_crtcs & (1 << i)) {
...@@ -68,6 +94,8 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) ...@@ -68,6 +94,8 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch)
} }
} }
mutex_unlock(&rdev->vram_mutex);
/* update display watermarks based on new power state */ /* update display watermarks based on new power state */
radeon_update_bandwidth_info(rdev); radeon_update_bandwidth_info(rdev);
if (rdev->pm.active_crtc_count) if (rdev->pm.active_crtc_count)
......
...@@ -607,13 +607,17 @@ static const struct vm_operations_struct *ttm_vm_ops = NULL; ...@@ -607,13 +607,17 @@ static const struct vm_operations_struct *ttm_vm_ops = NULL;
static int radeon_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) static int radeon_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{ {
struct ttm_buffer_object *bo; struct ttm_buffer_object *bo;
struct radeon_device *rdev;
int r; int r;
bo = (struct ttm_buffer_object *)vma->vm_private_data; bo = (struct ttm_buffer_object *)vma->vm_private_data;
if (bo == NULL) { if (bo == NULL) {
return VM_FAULT_NOPAGE; return VM_FAULT_NOPAGE;
} }
rdev = radeon_get_rdev(bo->bdev);
mutex_lock(&rdev->vram_mutex);
r = ttm_vm_ops->fault(vma, vmf); r = ttm_vm_ops->fault(vma, vmf);
mutex_unlock(&rdev->vram_mutex);
return r; return r;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment