From 7ade34819ee7dbf1baa95f40155d5706bf680e34 Mon Sep 17 00:00:00 2001
From: Jerome Glisse <jglisse@redhat.com>
Date: Wed, 16 Jan 2013 17:13:38 -0500
Subject: [PATCH] drm/radeon: exclude system placement when validating buffer
 v3

Buffer needs to be in GTT or VRAM no system when being validated to
be use by the gpu. Should fix :

https://bugzilla.kernel.org/show_bug.cgi?id=52491
https://bugs.freedesktop.org/show_bug.cgi?id=58659

v2: Don't erase the original userspace placement, track them so we
    can switch back to them.
v3: Do remove system placement from default placement

Signed-off-by: Jerome Glisse <jglisse@redhat.com>
---
 drivers/gpu/drm/radeon/radeon.h        |  6 ++--
 drivers/gpu/drm/radeon/radeon_object.c | 59 +++++++++++++++++++++-------------
 drivers/gpu/drm/radeon/radeon_ttm.c    | 16 ++++++---
 3 files changed, 51 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 34e5230..34b9001 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -323,8 +323,9 @@ struct radeon_bo {
 	/* Protected by gem.mutex */
 	struct list_head		list;
 	/* Protected by tbo.reserved */
-	u32				placements[3];
-	u32				busy_placements[3];
+	u32				placements[4];
+	u32				busy_placements[4];
+	u32				system_placements[4];
 	struct ttm_placement		placement;
 	struct ttm_buffer_object	tbo;
 	struct ttm_bo_kmap_obj		kmap;
@@ -1865,7 +1866,6 @@ extern void radeon_surface_init(struct radeon_device *rdev);
 extern int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data);
 extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable);
 extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
-extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
 extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
 extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);
 extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 883c95d..dfbaa4a 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -77,42 +77,32 @@ bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo)
 	return false;
 }
 
-void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
+static void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 placements[4], u32 domain)
 {
-	u32 c = 0;
+	u32 c = 1;
 
 	rbo->placement.fpfn = 0;
 	rbo->placement.lpfn = 0;
-	rbo->placement.placement = rbo->placements;
 	if (domain & RADEON_GEM_DOMAIN_VRAM)
-		rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
-					TTM_PL_FLAG_VRAM;
+		placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
 	if (domain & RADEON_GEM_DOMAIN_GTT) {
 		if (rbo->rdev->flags & RADEON_IS_AGP) {
-			rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_TT;
+			placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_TT;
 		} else {
-			rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT;
+			placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT;
 		}
 	}
 	if (domain & RADEON_GEM_DOMAIN_CPU) {
 		if (rbo->rdev->flags & RADEON_IS_AGP) {
-			rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_SYSTEM;
+			placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_SYSTEM;
 		} else {
-			rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM;
+			placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM;
 		}
 	}
-	if (!c)
+	if (c == 1) {
 		rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
-	rbo->placement.num_placement = c;
-
-	c = 0;
-	rbo->placement.busy_placement = rbo->busy_placements;
-	if (rbo->rdev->flags & RADEON_IS_AGP) {
-		rbo->busy_placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_TT;
-	} else {
-		rbo->busy_placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT;
 	}
-	rbo->placement.num_busy_placement = c;
+	placements[0] = c - 1;
 }
 
 int radeon_bo_create(struct radeon_device *rdev,
@@ -153,7 +143,20 @@ int radeon_bo_create(struct radeon_device *rdev,
 	bo->surface_reg = -1;
 	INIT_LIST_HEAD(&bo->list);
 	INIT_LIST_HEAD(&bo->va);
-	radeon_ttm_placement_from_domain(bo, domain);
+	/* placement is prefered userspace bo placement we replace CPU with GTT */
+	if (domain & RADEON_GEM_DOMAIN_CPU) {
+		domain &= ~RADEON_GEM_DOMAIN_CPU;
+		domain |= RADEON_GEM_DOMAIN_GTT;
+	}
+	radeon_ttm_placement_from_domain(bo, bo->placements, domain);
+	/* busy is fallback placement */
+	radeon_ttm_placement_from_domain(bo, bo->busy_placements, RADEON_GEM_DOMAIN_GTT);
+	radeon_ttm_placement_from_domain(bo, bo->system_placements, RADEON_GEM_DOMAIN_CPU);
+	bo->placement.num_placement = bo->placements[0];
+	bo->placement.placement = &bo->placements[1];
+	bo->placement.num_busy_placement = bo->busy_placements[0];
+	bo->placement.busy_placement = &bo->busy_placements[1];
+
 	/* Kernel allocation are uninterruptible */
 	down_read(&rdev->pm.mclk_lock);
 	r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
@@ -241,7 +244,11 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
 
 		return 0;
 	}
-	radeon_ttm_placement_from_domain(bo, domain);
+	radeon_ttm_placement_from_domain(bo, bo->placements, domain);
+	bo->placement.num_placement = bo->placements[0];
+	bo->placement.placement = &bo->placements[1];
+	bo->placement.num_busy_placement = 0;
+	bo->placement.busy_placement = NULL;
 	if (domain == RADEON_GEM_DOMAIN_VRAM) {
 		/* force to pin into visible video ram */
 		bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
@@ -366,6 +373,11 @@ int radeon_bo_list_validate(struct list_head *head)
 	list_for_each_entry(lobj, head, tv.head) {
 		bo = lobj->bo;
 		if (!bo->pin_count) {
+			/* those are the default bo creation placement */
+			bo->placement.num_placement = bo->placements[0];
+			bo->placement.placement = &bo->placements[1];
+			bo->placement.num_busy_placement = bo->busy_placements[0];
+			bo->placement.busy_placement = &bo->busy_placements[1];
 			r = ttm_bo_validate(&bo->tbo, &bo->placement,
 						true, false);
 			if (unlikely(r)) {
@@ -581,7 +593,10 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
 		offset = bo->mem.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.num_placement = rbo->placements[0];
+			rbo->placement.placement = &rbo->placements[1];
+			rbo->placement.num_busy_placement = rbo->busy_placements[0];
+			rbo->placement.busy_placement = &rbo->busy_placements[1];
 			rbo->placement.lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT;
 			r = ttm_bo_validate(bo, &rbo->placement, false, false);
 			if (unlikely(r != 0))
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 1d8ff2f..01aa526 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -188,14 +188,20 @@ static void radeon_evict_flags(struct ttm_buffer_object *bo,
 	rbo = container_of(bo, struct radeon_bo, tbo);
 	switch (bo->mem.mem_type) {
 	case TTM_PL_VRAM:
-		if (rbo->rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready == false)
-			radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_CPU);
-		else
-			radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT);
+		/* first prefer GTT then system */
+		rbo->placement.num_placement = rbo->busy_placements[0];
+		rbo->placement.placement = &rbo->busy_placements[1];
+		rbo->placement.num_busy_placement = rbo->system_placements[0];
+		rbo->placement.busy_placement = &rbo->system_placements[1];
 		break;
 	case TTM_PL_TT:
 	default:
-		radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_CPU);
+		/* GTT is full system it's */
+		rbo->placement.num_placement = rbo->system_placements[0];
+		rbo->placement.placement = &rbo->system_placements[1];
+		rbo->placement.num_busy_placement = 0;
+		rbo->placement.busy_placement = NULL;
+		break;
 	}
 	*placement = rbo->placement;
 }
-- 
1.7.11.7

