162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2008 Advanced Micro Devices, Inc.
362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc.
462306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
762306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
862306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
962306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1062306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
1162306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1462306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1762306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1862306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1962306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
2062306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2162306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2262306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * Authors: Dave Airlie
2562306a36Sopenharmony_ci *          Alex Deucher
2662306a36Sopenharmony_ci *          Jerome Glisse
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <linux/pci.h>
3062306a36Sopenharmony_ci#include <linux/vmalloc.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <drm/radeon_drm.h>
3362306a36Sopenharmony_ci#ifdef CONFIG_X86
3462306a36Sopenharmony_ci#include <asm/set_memory.h>
3562306a36Sopenharmony_ci#endif
3662306a36Sopenharmony_ci#include "radeon.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/*
3962306a36Sopenharmony_ci * GART
4062306a36Sopenharmony_ci * The GART (Graphics Aperture Remapping Table) is an aperture
4162306a36Sopenharmony_ci * in the GPU's address space.  System pages can be mapped into
4262306a36Sopenharmony_ci * the aperture and look like contiguous pages from the GPU's
4362306a36Sopenharmony_ci * perspective.  A page table maps the pages in the aperture
4462306a36Sopenharmony_ci * to the actual backing pages in system memory.
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci * Radeon GPUs support both an internal GART, as described above,
4762306a36Sopenharmony_ci * and AGP.  AGP works similarly, but the GART table is configured
4862306a36Sopenharmony_ci * and maintained by the northbridge rather than the driver.
4962306a36Sopenharmony_ci * Radeon hw has a separate AGP aperture that is programmed to
5062306a36Sopenharmony_ci * point to the AGP aperture provided by the northbridge and the
5162306a36Sopenharmony_ci * requests are passed through to the northbridge aperture.
5262306a36Sopenharmony_ci * Both AGP and internal GART can be used at the same time, however
5362306a36Sopenharmony_ci * that is not currently supported by the driver.
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci * This file handles the common internal GART management.
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/*
5962306a36Sopenharmony_ci * Common GART table functions.
6062306a36Sopenharmony_ci */
6162306a36Sopenharmony_ci/**
6262306a36Sopenharmony_ci * radeon_gart_table_ram_alloc - allocate system ram for gart page table
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci * @rdev: radeon_device pointer
6562306a36Sopenharmony_ci *
6662306a36Sopenharmony_ci * Allocate system memory for GART page table
6762306a36Sopenharmony_ci * (r1xx-r3xx, non-pcie r4xx, rs400).  These asics require the
6862306a36Sopenharmony_ci * gart table to be in system memory.
6962306a36Sopenharmony_ci * Returns 0 for success, -ENOMEM for failure.
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_ciint radeon_gart_table_ram_alloc(struct radeon_device *rdev)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	void *ptr;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	ptr = dma_alloc_coherent(&rdev->pdev->dev, rdev->gart.table_size,
7662306a36Sopenharmony_ci				 &rdev->gart.table_addr, GFP_KERNEL);
7762306a36Sopenharmony_ci	if (!ptr)
7862306a36Sopenharmony_ci		return -ENOMEM;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#ifdef CONFIG_X86
8162306a36Sopenharmony_ci	if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 ||
8262306a36Sopenharmony_ci	    rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
8362306a36Sopenharmony_ci		set_memory_uc((unsigned long)ptr,
8462306a36Sopenharmony_ci			      rdev->gart.table_size >> PAGE_SHIFT);
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci#endif
8762306a36Sopenharmony_ci	rdev->gart.ptr = ptr;
8862306a36Sopenharmony_ci	return 0;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/**
9262306a36Sopenharmony_ci * radeon_gart_table_ram_free - free system ram for gart page table
9362306a36Sopenharmony_ci *
9462306a36Sopenharmony_ci * @rdev: radeon_device pointer
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * Free system memory for GART page table
9762306a36Sopenharmony_ci * (r1xx-r3xx, non-pcie r4xx, rs400).  These asics require the
9862306a36Sopenharmony_ci * gart table to be in system memory.
9962306a36Sopenharmony_ci */
10062306a36Sopenharmony_civoid radeon_gart_table_ram_free(struct radeon_device *rdev)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	if (!rdev->gart.ptr)
10362306a36Sopenharmony_ci		return;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#ifdef CONFIG_X86
10662306a36Sopenharmony_ci	if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 ||
10762306a36Sopenharmony_ci	    rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
10862306a36Sopenharmony_ci		set_memory_wb((unsigned long)rdev->gart.ptr,
10962306a36Sopenharmony_ci			      rdev->gart.table_size >> PAGE_SHIFT);
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci#endif
11262306a36Sopenharmony_ci	dma_free_coherent(&rdev->pdev->dev, rdev->gart.table_size,
11362306a36Sopenharmony_ci			  (void *)rdev->gart.ptr, rdev->gart.table_addr);
11462306a36Sopenharmony_ci	rdev->gart.ptr = NULL;
11562306a36Sopenharmony_ci	rdev->gart.table_addr = 0;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/**
11962306a36Sopenharmony_ci * radeon_gart_table_vram_alloc - allocate vram for gart page table
12062306a36Sopenharmony_ci *
12162306a36Sopenharmony_ci * @rdev: radeon_device pointer
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * Allocate video memory for GART page table
12462306a36Sopenharmony_ci * (pcie r4xx, r5xx+).  These asics require the
12562306a36Sopenharmony_ci * gart table to be in video memory.
12662306a36Sopenharmony_ci * Returns 0 for success, error for failure.
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_ciint radeon_gart_table_vram_alloc(struct radeon_device *rdev)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	int r;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (rdev->gart.robj == NULL) {
13362306a36Sopenharmony_ci		r = radeon_bo_create(rdev, rdev->gart.table_size,
13462306a36Sopenharmony_ci				     PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
13562306a36Sopenharmony_ci				     0, NULL, NULL, &rdev->gart.robj);
13662306a36Sopenharmony_ci		if (r)
13762306a36Sopenharmony_ci			return r;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci	return 0;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/**
14362306a36Sopenharmony_ci * radeon_gart_table_vram_pin - pin gart page table in vram
14462306a36Sopenharmony_ci *
14562306a36Sopenharmony_ci * @rdev: radeon_device pointer
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci * Pin the GART page table in vram so it will not be moved
14862306a36Sopenharmony_ci * by the memory manager (pcie r4xx, r5xx+).  These asics require the
14962306a36Sopenharmony_ci * gart table to be in video memory.
15062306a36Sopenharmony_ci * Returns 0 for success, error for failure.
15162306a36Sopenharmony_ci */
15262306a36Sopenharmony_ciint radeon_gart_table_vram_pin(struct radeon_device *rdev)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	uint64_t gpu_addr;
15562306a36Sopenharmony_ci	int r;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	r = radeon_bo_reserve(rdev->gart.robj, false);
15862306a36Sopenharmony_ci	if (unlikely(r != 0))
15962306a36Sopenharmony_ci		return r;
16062306a36Sopenharmony_ci	r = radeon_bo_pin(rdev->gart.robj,
16162306a36Sopenharmony_ci				RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
16262306a36Sopenharmony_ci	if (r) {
16362306a36Sopenharmony_ci		radeon_bo_unreserve(rdev->gart.robj);
16462306a36Sopenharmony_ci		return r;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci	r = radeon_bo_kmap(rdev->gart.robj, &rdev->gart.ptr);
16762306a36Sopenharmony_ci	if (r)
16862306a36Sopenharmony_ci		radeon_bo_unpin(rdev->gart.robj);
16962306a36Sopenharmony_ci	radeon_bo_unreserve(rdev->gart.robj);
17062306a36Sopenharmony_ci	rdev->gart.table_addr = gpu_addr;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (!r) {
17362306a36Sopenharmony_ci		int i;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		/* We might have dropped some GART table updates while it wasn't
17662306a36Sopenharmony_ci		 * mapped, restore all entries
17762306a36Sopenharmony_ci		 */
17862306a36Sopenharmony_ci		for (i = 0; i < rdev->gart.num_gpu_pages; i++)
17962306a36Sopenharmony_ci			radeon_gart_set_page(rdev, i, rdev->gart.pages_entry[i]);
18062306a36Sopenharmony_ci		mb();
18162306a36Sopenharmony_ci		radeon_gart_tlb_flush(rdev);
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return r;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/**
18862306a36Sopenharmony_ci * radeon_gart_table_vram_unpin - unpin gart page table in vram
18962306a36Sopenharmony_ci *
19062306a36Sopenharmony_ci * @rdev: radeon_device pointer
19162306a36Sopenharmony_ci *
19262306a36Sopenharmony_ci * Unpin the GART page table in vram (pcie r4xx, r5xx+).
19362306a36Sopenharmony_ci * These asics require the gart table to be in video memory.
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_civoid radeon_gart_table_vram_unpin(struct radeon_device *rdev)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	int r;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (!rdev->gart.robj)
20062306a36Sopenharmony_ci		return;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	r = radeon_bo_reserve(rdev->gart.robj, false);
20362306a36Sopenharmony_ci	if (likely(r == 0)) {
20462306a36Sopenharmony_ci		radeon_bo_kunmap(rdev->gart.robj);
20562306a36Sopenharmony_ci		radeon_bo_unpin(rdev->gart.robj);
20662306a36Sopenharmony_ci		radeon_bo_unreserve(rdev->gart.robj);
20762306a36Sopenharmony_ci		rdev->gart.ptr = NULL;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/**
21262306a36Sopenharmony_ci * radeon_gart_table_vram_free - free gart page table vram
21362306a36Sopenharmony_ci *
21462306a36Sopenharmony_ci * @rdev: radeon_device pointer
21562306a36Sopenharmony_ci *
21662306a36Sopenharmony_ci * Free the video memory used for the GART page table
21762306a36Sopenharmony_ci * (pcie r4xx, r5xx+).  These asics require the gart table to
21862306a36Sopenharmony_ci * be in video memory.
21962306a36Sopenharmony_ci */
22062306a36Sopenharmony_civoid radeon_gart_table_vram_free(struct radeon_device *rdev)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	if (!rdev->gart.robj)
22362306a36Sopenharmony_ci		return;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	radeon_bo_unref(&rdev->gart.robj);
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/*
22962306a36Sopenharmony_ci * Common gart functions.
23062306a36Sopenharmony_ci */
23162306a36Sopenharmony_ci/**
23262306a36Sopenharmony_ci * radeon_gart_unbind - unbind pages from the gart page table
23362306a36Sopenharmony_ci *
23462306a36Sopenharmony_ci * @rdev: radeon_device pointer
23562306a36Sopenharmony_ci * @offset: offset into the GPU's gart aperture
23662306a36Sopenharmony_ci * @pages: number of pages to unbind
23762306a36Sopenharmony_ci *
23862306a36Sopenharmony_ci * Unbinds the requested pages from the gart page table and
23962306a36Sopenharmony_ci * replaces them with the dummy page (all asics).
24062306a36Sopenharmony_ci */
24162306a36Sopenharmony_civoid radeon_gart_unbind(struct radeon_device *rdev, unsigned int offset,
24262306a36Sopenharmony_ci			int pages)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	unsigned int t, p;
24562306a36Sopenharmony_ci	int i, j;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (!rdev->gart.ready) {
24862306a36Sopenharmony_ci		WARN(1, "trying to unbind memory from uninitialized GART !\n");
24962306a36Sopenharmony_ci		return;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci	t = offset / RADEON_GPU_PAGE_SIZE;
25262306a36Sopenharmony_ci	p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
25362306a36Sopenharmony_ci	for (i = 0; i < pages; i++, p++) {
25462306a36Sopenharmony_ci		if (rdev->gart.pages[p]) {
25562306a36Sopenharmony_ci			rdev->gart.pages[p] = NULL;
25662306a36Sopenharmony_ci			for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
25762306a36Sopenharmony_ci				rdev->gart.pages_entry[t] = rdev->dummy_page.entry;
25862306a36Sopenharmony_ci				if (rdev->gart.ptr) {
25962306a36Sopenharmony_ci					radeon_gart_set_page(rdev, t,
26062306a36Sopenharmony_ci							     rdev->dummy_page.entry);
26162306a36Sopenharmony_ci				}
26262306a36Sopenharmony_ci			}
26362306a36Sopenharmony_ci		}
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci	if (rdev->gart.ptr) {
26662306a36Sopenharmony_ci		mb();
26762306a36Sopenharmony_ci		radeon_gart_tlb_flush(rdev);
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/**
27262306a36Sopenharmony_ci * radeon_gart_bind - bind pages into the gart page table
27362306a36Sopenharmony_ci *
27462306a36Sopenharmony_ci * @rdev: radeon_device pointer
27562306a36Sopenharmony_ci * @offset: offset into the GPU's gart aperture
27662306a36Sopenharmony_ci * @pages: number of pages to bind
27762306a36Sopenharmony_ci * @pagelist: pages to bind
27862306a36Sopenharmony_ci * @dma_addr: DMA addresses of pages
27962306a36Sopenharmony_ci * @flags: RADEON_GART_PAGE_* flags
28062306a36Sopenharmony_ci *
28162306a36Sopenharmony_ci * Binds the requested pages to the gart page table
28262306a36Sopenharmony_ci * (all asics).
28362306a36Sopenharmony_ci * Returns 0 for success, -EINVAL for failure.
28462306a36Sopenharmony_ci */
28562306a36Sopenharmony_ciint radeon_gart_bind(struct radeon_device *rdev, unsigned int offset,
28662306a36Sopenharmony_ci		     int pages, struct page **pagelist, dma_addr_t *dma_addr,
28762306a36Sopenharmony_ci		     uint32_t flags)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	unsigned int t, p;
29062306a36Sopenharmony_ci	uint64_t page_base, page_entry;
29162306a36Sopenharmony_ci	int i, j;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	if (!rdev->gart.ready) {
29462306a36Sopenharmony_ci		WARN(1, "trying to bind memory to uninitialized GART !\n");
29562306a36Sopenharmony_ci		return -EINVAL;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci	t = offset / RADEON_GPU_PAGE_SIZE;
29862306a36Sopenharmony_ci	p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	for (i = 0; i < pages; i++, p++) {
30162306a36Sopenharmony_ci		rdev->gart.pages[p] = pagelist ? pagelist[i] :
30262306a36Sopenharmony_ci			rdev->dummy_page.page;
30362306a36Sopenharmony_ci		page_base = dma_addr[i];
30462306a36Sopenharmony_ci		for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
30562306a36Sopenharmony_ci			page_entry = radeon_gart_get_page_entry(page_base, flags);
30662306a36Sopenharmony_ci			rdev->gart.pages_entry[t] = page_entry;
30762306a36Sopenharmony_ci			if (rdev->gart.ptr)
30862306a36Sopenharmony_ci				radeon_gart_set_page(rdev, t, page_entry);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci			page_base += RADEON_GPU_PAGE_SIZE;
31162306a36Sopenharmony_ci		}
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci	if (rdev->gart.ptr) {
31462306a36Sopenharmony_ci		mb();
31562306a36Sopenharmony_ci		radeon_gart_tlb_flush(rdev);
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci	return 0;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci/**
32162306a36Sopenharmony_ci * radeon_gart_init - init the driver info for managing the gart
32262306a36Sopenharmony_ci *
32362306a36Sopenharmony_ci * @rdev: radeon_device pointer
32462306a36Sopenharmony_ci *
32562306a36Sopenharmony_ci * Allocate the dummy page and init the gart driver info (all asics).
32662306a36Sopenharmony_ci * Returns 0 for success, error for failure.
32762306a36Sopenharmony_ci */
32862306a36Sopenharmony_ciint radeon_gart_init(struct radeon_device *rdev)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	int r, i;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (rdev->gart.pages)
33362306a36Sopenharmony_ci		return 0;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* We need PAGE_SIZE >= RADEON_GPU_PAGE_SIZE */
33662306a36Sopenharmony_ci	if (PAGE_SIZE < RADEON_GPU_PAGE_SIZE) {
33762306a36Sopenharmony_ci		DRM_ERROR("Page size is smaller than GPU page size!\n");
33862306a36Sopenharmony_ci		return -EINVAL;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci	r = radeon_dummy_page_init(rdev);
34162306a36Sopenharmony_ci	if (r)
34262306a36Sopenharmony_ci		return r;
34362306a36Sopenharmony_ci	/* Compute table size */
34462306a36Sopenharmony_ci	rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE;
34562306a36Sopenharmony_ci	rdev->gart.num_gpu_pages = rdev->mc.gtt_size / RADEON_GPU_PAGE_SIZE;
34662306a36Sopenharmony_ci	DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n",
34762306a36Sopenharmony_ci		 rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages);
34862306a36Sopenharmony_ci	/* Allocate pages table */
34962306a36Sopenharmony_ci	rdev->gart.pages = vzalloc(array_size(sizeof(void *),
35062306a36Sopenharmony_ci				   rdev->gart.num_cpu_pages));
35162306a36Sopenharmony_ci	if (rdev->gart.pages == NULL) {
35262306a36Sopenharmony_ci		radeon_gart_fini(rdev);
35362306a36Sopenharmony_ci		return -ENOMEM;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci	rdev->gart.pages_entry = vmalloc(array_size(sizeof(uint64_t),
35662306a36Sopenharmony_ci						    rdev->gart.num_gpu_pages));
35762306a36Sopenharmony_ci	if (rdev->gart.pages_entry == NULL) {
35862306a36Sopenharmony_ci		radeon_gart_fini(rdev);
35962306a36Sopenharmony_ci		return -ENOMEM;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci	/* set GART entry to point to the dummy page by default */
36262306a36Sopenharmony_ci	for (i = 0; i < rdev->gart.num_gpu_pages; i++)
36362306a36Sopenharmony_ci		rdev->gart.pages_entry[i] = rdev->dummy_page.entry;
36462306a36Sopenharmony_ci	return 0;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/**
36862306a36Sopenharmony_ci * radeon_gart_fini - tear down the driver info for managing the gart
36962306a36Sopenharmony_ci *
37062306a36Sopenharmony_ci * @rdev: radeon_device pointer
37162306a36Sopenharmony_ci *
37262306a36Sopenharmony_ci * Tear down the gart driver info and free the dummy page (all asics).
37362306a36Sopenharmony_ci */
37462306a36Sopenharmony_civoid radeon_gart_fini(struct radeon_device *rdev)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	if (rdev->gart.ready) {
37762306a36Sopenharmony_ci		/* unbind pages */
37862306a36Sopenharmony_ci		radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages);
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci	rdev->gart.ready = false;
38162306a36Sopenharmony_ci	vfree(rdev->gart.pages);
38262306a36Sopenharmony_ci	vfree(rdev->gart.pages_entry);
38362306a36Sopenharmony_ci	rdev->gart.pages = NULL;
38462306a36Sopenharmony_ci	rdev->gart.pages_entry = NULL;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	radeon_dummy_page_fini(rdev);
38762306a36Sopenharmony_ci}
388