]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/radeon/radeon_object.c
drm/radeon/kms: take vram mutex pointer before derefing object.
[karo-tx-linux.git] / drivers / gpu / drm / radeon / radeon_object.c
index f1da370928eb7656d5f9fc474fd8cfceb3222ae2..a8d18bcae7db08ba2c62cd2cedb45acc3afdeac5 100644 (file)
@@ -30,6 +30,7 @@
  *    Dave Airlie
  */
 #include <linux/list.h>
+#include <linux/slab.h>
 #include <drm/drmP.h>
 #include "radeon_drm.h"
 #include "radeon.h"
@@ -111,9 +112,11 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
 
        radeon_ttm_placement_from_domain(bo, domain);
        /* Kernel allocation are uninterruptible */
+       mutex_lock(&rdev->vram_mutex);
        r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
                        &bo->placement, 0, 0, !kernel, NULL, size,
                        &radeon_ttm_bo_destroy);
+       mutex_unlock(&rdev->vram_mutex);
        if (unlikely(r != 0)) {
                if (r != -ERESTARTSYS)
                        dev_err(rdev->dev,
@@ -165,11 +168,15 @@ void radeon_bo_kunmap(struct radeon_bo *bo)
 void radeon_bo_unref(struct radeon_bo **bo)
 {
        struct ttm_buffer_object *tbo;
+       struct radeon_device *rdev;
 
        if ((*bo) == NULL)
                return;
+       rdev = (*bo)->rdev;
        tbo = &((*bo)->tbo);
+       mutex_lock(&rdev->vram_mutex);
        ttm_bo_unref(&tbo);
+       mutex_unlock(&rdev->vram_mutex);
        if (tbo == NULL)
                *bo = NULL;
 }
@@ -178,7 +185,6 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr)
 {
        int r, i;
 
-       radeon_ttm_placement_from_domain(bo, domain);
        if (bo->pin_count) {
                bo->pin_count++;
                if (gpu_addr)
@@ -186,9 +192,13 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr)
                return 0;
        }
        radeon_ttm_placement_from_domain(bo, domain);
+       if (domain == RADEON_GEM_DOMAIN_VRAM) {
+               /* force to pin into visible video ram */
+               bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
+       }
        for (i = 0; i < bo->placement.num_placement; i++)
                bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
-       r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
+       r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false, false);
        if (likely(r == 0)) {
                bo->pin_count = 1;
                if (gpu_addr != NULL)
@@ -212,7 +222,7 @@ int radeon_bo_unpin(struct radeon_bo *bo)
                return 0;
        for (i = 0; i < bo->placement.num_placement; i++)
                bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
-       r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
+       r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false, false);
        if (unlikely(r != 0))
                dev_err(bo->rdev->dev, "%p validate failed for unpin\n", bo);
        return r;
@@ -327,7 +337,7 @@ int radeon_bo_list_validate(struct list_head *head)
                                                                lobj->rdomain);
                        }
                        r = ttm_bo_validate(&bo->tbo, &bo->placement,
-                                               true, false);
+                                               true, false, false);
                        if (unlikely(r))
                                return r;
                }
@@ -495,11 +505,33 @@ void radeon_bo_move_notify(struct ttm_buffer_object *bo,
        radeon_bo_check_tiling(rbo, 0, 1);
 }
 
-void radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
+int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
 {
+       struct radeon_device *rdev;
        struct radeon_bo *rbo;
+       unsigned long offset, size;
+       int r;
+
        if (!radeon_ttm_bo_is_radeon_bo(bo))
-               return;
+               return 0;
        rbo = container_of(bo, struct radeon_bo, tbo);
        radeon_bo_check_tiling(rbo, 0, 0);
+       rdev = rbo->rdev;
+       if (bo->mem.mem_type == TTM_PL_VRAM) {
+               size = bo->mem.num_pages << PAGE_SHIFT;
+               offset = bo->mem.mm_node->start << PAGE_SHIFT;
+               if ((offset + size) > rdev->mc.visible_vram_size) {
+                       /* hurrah the memory is not visible ! */
+                       radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM);
+                       rbo->placement.lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT;
+                       r = ttm_bo_validate(bo, &rbo->placement, false, true, false);
+                       if (unlikely(r != 0))
+                               return r;
+                       offset = bo->mem.mm_node->start << PAGE_SHIFT;
+                       /* this should not happen */
+                       if ((offset + size) > rdev->mc.visible_vram_size)
+                               return -EINVAL;
+               }
+       }
+       return 0;
 }