drm/radeon/kms: consolidate GART code, fix segfault after GPU lockup V2

After GPU lockup VRAM gart table is unpinned and thus its pointer
becomes unvalid. This patch move the unpin code to a common helper
function and set pointer to NULL so that page update code can check
if it should update GPU page table or not. That way bo still bound
to GART can be unbound (pci_unmap_page for all there page) properly
while there is no need to update the GPU page table.

V2 move the test for null gart out of the loop, small optimization

Signed-off-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index fdc3a9a..ba7ab79 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -49,27 +49,27 @@
 			      rdev->gart.table_size >> PAGE_SHIFT);
 	}
 #endif
-	rdev->gart.table.ram.ptr = ptr;
-	memset((void *)rdev->gart.table.ram.ptr, 0, rdev->gart.table_size);
+	rdev->gart.ptr = ptr;
+	memset((void *)rdev->gart.ptr, 0, rdev->gart.table_size);
 	return 0;
 }
 
 void radeon_gart_table_ram_free(struct radeon_device *rdev)
 {
-	if (rdev->gart.table.ram.ptr == NULL) {
+	if (rdev->gart.ptr == NULL) {
 		return;
 	}
 #ifdef CONFIG_X86
 	if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 ||
 	    rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
-		set_memory_wb((unsigned long)rdev->gart.table.ram.ptr,
+		set_memory_wb((unsigned long)rdev->gart.ptr,
 			      rdev->gart.table_size >> PAGE_SHIFT);
 	}
 #endif
 	pci_free_consistent(rdev->pdev, rdev->gart.table_size,
-			    (void *)rdev->gart.table.ram.ptr,
+			    (void *)rdev->gart.ptr,
 			    rdev->gart.table_addr);
-	rdev->gart.table.ram.ptr = NULL;
+	rdev->gart.ptr = NULL;
 	rdev->gart.table_addr = 0;
 }
 
@@ -77,10 +77,10 @@
 {
 	int r;
 
-	if (rdev->gart.table.vram.robj == NULL) {
+	if (rdev->gart.robj == NULL) {
 		r = radeon_bo_create(rdev, rdev->gart.table_size,
 				     PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
-				     &rdev->gart.table.vram.robj);
+				     &rdev->gart.robj);
 		if (r) {
 			return r;
 		}
@@ -93,38 +93,46 @@
 	uint64_t gpu_addr;
 	int r;
 
-	r = radeon_bo_reserve(rdev->gart.table.vram.robj, false);
+	r = radeon_bo_reserve(rdev->gart.robj, false);
 	if (unlikely(r != 0))
 		return r;
-	r = radeon_bo_pin(rdev->gart.table.vram.robj,
+	r = radeon_bo_pin(rdev->gart.robj,
 				RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
 	if (r) {
-		radeon_bo_unreserve(rdev->gart.table.vram.robj);
+		radeon_bo_unreserve(rdev->gart.robj);
 		return r;
 	}
-	r = radeon_bo_kmap(rdev->gart.table.vram.robj,
-				(void **)&rdev->gart.table.vram.ptr);
+	r = radeon_bo_kmap(rdev->gart.robj, &rdev->gart.ptr);
 	if (r)
-		radeon_bo_unpin(rdev->gart.table.vram.robj);
-	radeon_bo_unreserve(rdev->gart.table.vram.robj);
+		radeon_bo_unpin(rdev->gart.robj);
+	radeon_bo_unreserve(rdev->gart.robj);
 	rdev->gart.table_addr = gpu_addr;
 	return r;
 }
 
-void radeon_gart_table_vram_free(struct radeon_device *rdev)
+void radeon_gart_table_vram_unpin(struct radeon_device *rdev)
 {
 	int r;
 
-	if (rdev->gart.table.vram.robj == NULL) {
+	if (rdev->gart.robj == NULL) {
 		return;
 	}
-	r = radeon_bo_reserve(rdev->gart.table.vram.robj, false);
+	r = radeon_bo_reserve(rdev->gart.robj, false);
 	if (likely(r == 0)) {
-		radeon_bo_kunmap(rdev->gart.table.vram.robj);
-		radeon_bo_unpin(rdev->gart.table.vram.robj);
-		radeon_bo_unreserve(rdev->gart.table.vram.robj);
+		radeon_bo_kunmap(rdev->gart.robj);
+		radeon_bo_unpin(rdev->gart.robj);
+		radeon_bo_unreserve(rdev->gart.robj);
+		rdev->gart.ptr = NULL;
 	}
-	radeon_bo_unref(&rdev->gart.table.vram.robj);
+}
+
+void radeon_gart_table_vram_free(struct radeon_device *rdev)
+{
+	if (rdev->gart.robj == NULL) {
+		return;
+	}
+	radeon_gart_table_vram_unpin(rdev);
+	radeon_bo_unref(&rdev->gart.robj);
 }
 
 
@@ -151,12 +159,14 @@
 		if (rdev->gart.pages[p]) {
 			if (!rdev->gart.ttm_alloced[p])
 				pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p],
-				       		PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+						PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
 			rdev->gart.pages[p] = NULL;
 			rdev->gart.pages_addr[p] = rdev->dummy_page.addr;
 			page_base = rdev->gart.pages_addr[p];
 			for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
-				radeon_gart_set_page(rdev, t, page_base);
+				if (rdev->gart.ptr) {
+					radeon_gart_set_page(rdev, t, page_base);
+				}
 				page_base += RADEON_GPU_PAGE_SIZE;
 			}
 		}
@@ -199,10 +209,12 @@
 			}
 		}
 		rdev->gart.pages[p] = pagelist[i];
-		page_base = rdev->gart.pages_addr[p];
-		for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
-			radeon_gart_set_page(rdev, t, page_base);
-			page_base += RADEON_GPU_PAGE_SIZE;
+		if (rdev->gart.ptr) {
+			page_base = rdev->gart.pages_addr[p];
+			for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
+				radeon_gart_set_page(rdev, t, page_base);
+				page_base += RADEON_GPU_PAGE_SIZE;
+			}
 		}
 	}
 	mb();
@@ -215,6 +227,9 @@
 	int i, j, t;
 	u64 page_base;
 
+	if (!rdev->gart.ptr) {
+		return;
+	}
 	for (i = 0, t = 0; i < rdev->gart.num_cpu_pages; i++) {
 		page_base = rdev->gart.pages_addr[i];
 		for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {