18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2008 Advanced Micro Devices, Inc.
38c2ecf20Sopenharmony_ci * Copyright 2008 Red Hat Inc.
48c2ecf20Sopenharmony_ci * Copyright 2009 Jerome Glisse.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
88c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
98c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
108c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
118c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
148c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
198c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
208c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
218c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
228c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * Authors: Dave Airlie
258c2ecf20Sopenharmony_ci *          Alex Deucher
268c2ecf20Sopenharmony_ci *          Jerome Glisse
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <linux/pci.h>
308c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <drm/radeon_drm.h>
338c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
348c2ecf20Sopenharmony_ci#include <asm/set_memory.h>
358c2ecf20Sopenharmony_ci#endif
368c2ecf20Sopenharmony_ci#include "radeon.h"
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/*
398c2ecf20Sopenharmony_ci * GART
408c2ecf20Sopenharmony_ci * The GART (Graphics Aperture Remapping Table) is an aperture
418c2ecf20Sopenharmony_ci * in the GPU's address space.  System pages can be mapped into
428c2ecf20Sopenharmony_ci * the aperture and look like contiguous pages from the GPU's
438c2ecf20Sopenharmony_ci * perspective.  A page table maps the pages in the aperture
448c2ecf20Sopenharmony_ci * to the actual backing pages in system memory.
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci * Radeon GPUs support both an internal GART, as described above,
478c2ecf20Sopenharmony_ci * and AGP.  AGP works similarly, but the GART table is configured
488c2ecf20Sopenharmony_ci * and maintained by the northbridge rather than the driver.
498c2ecf20Sopenharmony_ci * Radeon hw has a separate AGP aperture that is programmed to
508c2ecf20Sopenharmony_ci * point to the AGP aperture provided by the northbridge and the
518c2ecf20Sopenharmony_ci * requests are passed through to the northbridge aperture.
528c2ecf20Sopenharmony_ci * Both AGP and internal GART can be used at the same time, however
538c2ecf20Sopenharmony_ci * that is not currently supported by the driver.
548c2ecf20Sopenharmony_ci *
558c2ecf20Sopenharmony_ci * This file handles the common internal GART management.
568c2ecf20Sopenharmony_ci */
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/*
598c2ecf20Sopenharmony_ci * Common GART table functions.
608c2ecf20Sopenharmony_ci */
618c2ecf20Sopenharmony_ci/**
628c2ecf20Sopenharmony_ci * radeon_gart_table_ram_alloc - allocate system ram for gart page table
638c2ecf20Sopenharmony_ci *
648c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
658c2ecf20Sopenharmony_ci *
668c2ecf20Sopenharmony_ci * Allocate system memory for GART page table
678c2ecf20Sopenharmony_ci * (r1xx-r3xx, non-pcie r4xx, rs400).  These asics require the
688c2ecf20Sopenharmony_ci * gart table to be in system memory.
698c2ecf20Sopenharmony_ci * Returns 0 for success, -ENOMEM for failure.
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_ciint radeon_gart_table_ram_alloc(struct radeon_device *rdev)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	void *ptr;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	ptr = dma_alloc_coherent(&rdev->pdev->dev, rdev->gart.table_size,
768c2ecf20Sopenharmony_ci				 &rdev->gart.table_addr, GFP_KERNEL);
778c2ecf20Sopenharmony_ci	if (ptr == NULL) {
788c2ecf20Sopenharmony_ci		return -ENOMEM;
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
818c2ecf20Sopenharmony_ci	if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 ||
828c2ecf20Sopenharmony_ci	    rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
838c2ecf20Sopenharmony_ci		set_memory_uc((unsigned long)ptr,
848c2ecf20Sopenharmony_ci			      rdev->gart.table_size >> PAGE_SHIFT);
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci#endif
878c2ecf20Sopenharmony_ci	rdev->gart.ptr = ptr;
888c2ecf20Sopenharmony_ci	return 0;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/**
928c2ecf20Sopenharmony_ci * radeon_gart_table_ram_free - free system ram for gart page table
938c2ecf20Sopenharmony_ci *
948c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
958c2ecf20Sopenharmony_ci *
968c2ecf20Sopenharmony_ci * Free system memory for GART page table
978c2ecf20Sopenharmony_ci * (r1xx-r3xx, non-pcie r4xx, rs400).  These asics require the
988c2ecf20Sopenharmony_ci * gart table to be in system memory.
998c2ecf20Sopenharmony_ci */
1008c2ecf20Sopenharmony_civoid radeon_gart_table_ram_free(struct radeon_device *rdev)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	if (rdev->gart.ptr == NULL) {
1038c2ecf20Sopenharmony_ci		return;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
1068c2ecf20Sopenharmony_ci	if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 ||
1078c2ecf20Sopenharmony_ci	    rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
1088c2ecf20Sopenharmony_ci		set_memory_wb((unsigned long)rdev->gart.ptr,
1098c2ecf20Sopenharmony_ci			      rdev->gart.table_size >> PAGE_SHIFT);
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci#endif
1128c2ecf20Sopenharmony_ci	dma_free_coherent(&rdev->pdev->dev, rdev->gart.table_size,
1138c2ecf20Sopenharmony_ci			  (void *)rdev->gart.ptr, rdev->gart.table_addr);
1148c2ecf20Sopenharmony_ci	rdev->gart.ptr = NULL;
1158c2ecf20Sopenharmony_ci	rdev->gart.table_addr = 0;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/**
1198c2ecf20Sopenharmony_ci * radeon_gart_table_vram_alloc - allocate vram for gart page table
1208c2ecf20Sopenharmony_ci *
1218c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
1228c2ecf20Sopenharmony_ci *
1238c2ecf20Sopenharmony_ci * Allocate video memory for GART page table
1248c2ecf20Sopenharmony_ci * (pcie r4xx, r5xx+).  These asics require the
1258c2ecf20Sopenharmony_ci * gart table to be in video memory.
1268c2ecf20Sopenharmony_ci * Returns 0 for success, error for failure.
1278c2ecf20Sopenharmony_ci */
1288c2ecf20Sopenharmony_ciint radeon_gart_table_vram_alloc(struct radeon_device *rdev)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	int r;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (rdev->gart.robj == NULL) {
1338c2ecf20Sopenharmony_ci		r = radeon_bo_create(rdev, rdev->gart.table_size,
1348c2ecf20Sopenharmony_ci				     PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
1358c2ecf20Sopenharmony_ci				     0, NULL, NULL, &rdev->gart.robj);
1368c2ecf20Sopenharmony_ci		if (r) {
1378c2ecf20Sopenharmony_ci			return r;
1388c2ecf20Sopenharmony_ci		}
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci	return 0;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/**
1448c2ecf20Sopenharmony_ci * radeon_gart_table_vram_pin - pin gart page table in vram
1458c2ecf20Sopenharmony_ci *
1468c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
1478c2ecf20Sopenharmony_ci *
1488c2ecf20Sopenharmony_ci * Pin the GART page table in vram so it will not be moved
1498c2ecf20Sopenharmony_ci * by the memory manager (pcie r4xx, r5xx+).  These asics require the
1508c2ecf20Sopenharmony_ci * gart table to be in video memory.
1518c2ecf20Sopenharmony_ci * Returns 0 for success, error for failure.
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_ciint radeon_gart_table_vram_pin(struct radeon_device *rdev)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	uint64_t gpu_addr;
1568c2ecf20Sopenharmony_ci	int r;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	r = radeon_bo_reserve(rdev->gart.robj, false);
1598c2ecf20Sopenharmony_ci	if (unlikely(r != 0))
1608c2ecf20Sopenharmony_ci		return r;
1618c2ecf20Sopenharmony_ci	r = radeon_bo_pin(rdev->gart.robj,
1628c2ecf20Sopenharmony_ci				RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
1638c2ecf20Sopenharmony_ci	if (r) {
1648c2ecf20Sopenharmony_ci		radeon_bo_unreserve(rdev->gart.robj);
1658c2ecf20Sopenharmony_ci		return r;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci	r = radeon_bo_kmap(rdev->gart.robj, &rdev->gart.ptr);
1688c2ecf20Sopenharmony_ci	if (r)
1698c2ecf20Sopenharmony_ci		radeon_bo_unpin(rdev->gart.robj);
1708c2ecf20Sopenharmony_ci	radeon_bo_unreserve(rdev->gart.robj);
1718c2ecf20Sopenharmony_ci	rdev->gart.table_addr = gpu_addr;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (!r) {
1748c2ecf20Sopenharmony_ci		int i;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci		/* We might have dropped some GART table updates while it wasn't
1778c2ecf20Sopenharmony_ci		 * mapped, restore all entries
1788c2ecf20Sopenharmony_ci		 */
1798c2ecf20Sopenharmony_ci		for (i = 0; i < rdev->gart.num_gpu_pages; i++)
1808c2ecf20Sopenharmony_ci			radeon_gart_set_page(rdev, i, rdev->gart.pages_entry[i]);
1818c2ecf20Sopenharmony_ci		mb();
1828c2ecf20Sopenharmony_ci		radeon_gart_tlb_flush(rdev);
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return r;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/**
1898c2ecf20Sopenharmony_ci * radeon_gart_table_vram_unpin - unpin gart page table in vram
1908c2ecf20Sopenharmony_ci *
1918c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
1928c2ecf20Sopenharmony_ci *
1938c2ecf20Sopenharmony_ci * Unpin the GART page table in vram (pcie r4xx, r5xx+).
1948c2ecf20Sopenharmony_ci * These asics require the gart table to be in video memory.
1958c2ecf20Sopenharmony_ci */
1968c2ecf20Sopenharmony_civoid radeon_gart_table_vram_unpin(struct radeon_device *rdev)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	int r;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (rdev->gart.robj == NULL) {
2018c2ecf20Sopenharmony_ci		return;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci	r = radeon_bo_reserve(rdev->gart.robj, false);
2048c2ecf20Sopenharmony_ci	if (likely(r == 0)) {
2058c2ecf20Sopenharmony_ci		radeon_bo_kunmap(rdev->gart.robj);
2068c2ecf20Sopenharmony_ci		radeon_bo_unpin(rdev->gart.robj);
2078c2ecf20Sopenharmony_ci		radeon_bo_unreserve(rdev->gart.robj);
2088c2ecf20Sopenharmony_ci		rdev->gart.ptr = NULL;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci/**
2138c2ecf20Sopenharmony_ci * radeon_gart_table_vram_free - free gart page table vram
2148c2ecf20Sopenharmony_ci *
2158c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
2168c2ecf20Sopenharmony_ci *
2178c2ecf20Sopenharmony_ci * Free the video memory used for the GART page table
2188c2ecf20Sopenharmony_ci * (pcie r4xx, r5xx+).  These asics require the gart table to
2198c2ecf20Sopenharmony_ci * be in video memory.
2208c2ecf20Sopenharmony_ci */
2218c2ecf20Sopenharmony_civoid radeon_gart_table_vram_free(struct radeon_device *rdev)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	if (rdev->gart.robj == NULL) {
2248c2ecf20Sopenharmony_ci		return;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci	radeon_bo_unref(&rdev->gart.robj);
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci/*
2308c2ecf20Sopenharmony_ci * Common gart functions.
2318c2ecf20Sopenharmony_ci */
2328c2ecf20Sopenharmony_ci/**
2338c2ecf20Sopenharmony_ci * radeon_gart_unbind - unbind pages from the gart page table
2348c2ecf20Sopenharmony_ci *
2358c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
2368c2ecf20Sopenharmony_ci * @offset: offset into the GPU's gart aperture
2378c2ecf20Sopenharmony_ci * @pages: number of pages to unbind
2388c2ecf20Sopenharmony_ci *
2398c2ecf20Sopenharmony_ci * Unbinds the requested pages from the gart page table and
2408c2ecf20Sopenharmony_ci * replaces them with the dummy page (all asics).
2418c2ecf20Sopenharmony_ci */
2428c2ecf20Sopenharmony_civoid radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
2438c2ecf20Sopenharmony_ci			int pages)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	unsigned t;
2468c2ecf20Sopenharmony_ci	unsigned p;
2478c2ecf20Sopenharmony_ci	int i, j;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (!rdev->gart.ready) {
2508c2ecf20Sopenharmony_ci		WARN(1, "trying to unbind memory from uninitialized GART !\n");
2518c2ecf20Sopenharmony_ci		return;
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci	t = offset / RADEON_GPU_PAGE_SIZE;
2548c2ecf20Sopenharmony_ci	p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
2558c2ecf20Sopenharmony_ci	for (i = 0; i < pages; i++, p++) {
2568c2ecf20Sopenharmony_ci		if (rdev->gart.pages[p]) {
2578c2ecf20Sopenharmony_ci			rdev->gart.pages[p] = NULL;
2588c2ecf20Sopenharmony_ci			for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
2598c2ecf20Sopenharmony_ci				rdev->gart.pages_entry[t] = rdev->dummy_page.entry;
2608c2ecf20Sopenharmony_ci				if (rdev->gart.ptr) {
2618c2ecf20Sopenharmony_ci					radeon_gart_set_page(rdev, t,
2628c2ecf20Sopenharmony_ci							     rdev->dummy_page.entry);
2638c2ecf20Sopenharmony_ci				}
2648c2ecf20Sopenharmony_ci			}
2658c2ecf20Sopenharmony_ci		}
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci	if (rdev->gart.ptr) {
2688c2ecf20Sopenharmony_ci		mb();
2698c2ecf20Sopenharmony_ci		radeon_gart_tlb_flush(rdev);
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci/**
2748c2ecf20Sopenharmony_ci * radeon_gart_bind - bind pages into the gart page table
2758c2ecf20Sopenharmony_ci *
2768c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
2778c2ecf20Sopenharmony_ci * @offset: offset into the GPU's gart aperture
2788c2ecf20Sopenharmony_ci * @pages: number of pages to bind
2798c2ecf20Sopenharmony_ci * @pagelist: pages to bind
2808c2ecf20Sopenharmony_ci * @dma_addr: DMA addresses of pages
2818c2ecf20Sopenharmony_ci * @flags: RADEON_GART_PAGE_* flags
2828c2ecf20Sopenharmony_ci *
2838c2ecf20Sopenharmony_ci * Binds the requested pages to the gart page table
2848c2ecf20Sopenharmony_ci * (all asics).
2858c2ecf20Sopenharmony_ci * Returns 0 for success, -EINVAL for failure.
2868c2ecf20Sopenharmony_ci */
2878c2ecf20Sopenharmony_ciint radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
2888c2ecf20Sopenharmony_ci		     int pages, struct page **pagelist, dma_addr_t *dma_addr,
2898c2ecf20Sopenharmony_ci		     uint32_t flags)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	unsigned t;
2928c2ecf20Sopenharmony_ci	unsigned p;
2938c2ecf20Sopenharmony_ci	uint64_t page_base, page_entry;
2948c2ecf20Sopenharmony_ci	int i, j;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (!rdev->gart.ready) {
2978c2ecf20Sopenharmony_ci		WARN(1, "trying to bind memory to uninitialized GART !\n");
2988c2ecf20Sopenharmony_ci		return -EINVAL;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci	t = offset / RADEON_GPU_PAGE_SIZE;
3018c2ecf20Sopenharmony_ci	p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	for (i = 0; i < pages; i++, p++) {
3048c2ecf20Sopenharmony_ci		rdev->gart.pages[p] = pagelist[i];
3058c2ecf20Sopenharmony_ci		page_base = dma_addr[i];
3068c2ecf20Sopenharmony_ci		for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
3078c2ecf20Sopenharmony_ci			page_entry = radeon_gart_get_page_entry(page_base, flags);
3088c2ecf20Sopenharmony_ci			rdev->gart.pages_entry[t] = page_entry;
3098c2ecf20Sopenharmony_ci			if (rdev->gart.ptr) {
3108c2ecf20Sopenharmony_ci				radeon_gart_set_page(rdev, t, page_entry);
3118c2ecf20Sopenharmony_ci			}
3128c2ecf20Sopenharmony_ci			page_base += RADEON_GPU_PAGE_SIZE;
3138c2ecf20Sopenharmony_ci		}
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci	if (rdev->gart.ptr) {
3168c2ecf20Sopenharmony_ci		mb();
3178c2ecf20Sopenharmony_ci		radeon_gart_tlb_flush(rdev);
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci	return 0;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci/**
3238c2ecf20Sopenharmony_ci * radeon_gart_init - init the driver info for managing the gart
3248c2ecf20Sopenharmony_ci *
3258c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
3268c2ecf20Sopenharmony_ci *
3278c2ecf20Sopenharmony_ci * Allocate the dummy page and init the gart driver info (all asics).
3288c2ecf20Sopenharmony_ci * Returns 0 for success, error for failure.
3298c2ecf20Sopenharmony_ci */
3308c2ecf20Sopenharmony_ciint radeon_gart_init(struct radeon_device *rdev)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	int r, i;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (rdev->gart.pages) {
3358c2ecf20Sopenharmony_ci		return 0;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci	/* We need PAGE_SIZE >= RADEON_GPU_PAGE_SIZE */
3388c2ecf20Sopenharmony_ci	if (PAGE_SIZE < RADEON_GPU_PAGE_SIZE) {
3398c2ecf20Sopenharmony_ci		DRM_ERROR("Page size is smaller than GPU page size!\n");
3408c2ecf20Sopenharmony_ci		return -EINVAL;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci	r = radeon_dummy_page_init(rdev);
3438c2ecf20Sopenharmony_ci	if (r)
3448c2ecf20Sopenharmony_ci		return r;
3458c2ecf20Sopenharmony_ci	/* Compute table size */
3468c2ecf20Sopenharmony_ci	rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE;
3478c2ecf20Sopenharmony_ci	rdev->gart.num_gpu_pages = rdev->mc.gtt_size / RADEON_GPU_PAGE_SIZE;
3488c2ecf20Sopenharmony_ci	DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n",
3498c2ecf20Sopenharmony_ci		 rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages);
3508c2ecf20Sopenharmony_ci	/* Allocate pages table */
3518c2ecf20Sopenharmony_ci	rdev->gart.pages = vzalloc(array_size(sizeof(void *),
3528c2ecf20Sopenharmony_ci				   rdev->gart.num_cpu_pages));
3538c2ecf20Sopenharmony_ci	if (rdev->gart.pages == NULL) {
3548c2ecf20Sopenharmony_ci		radeon_gart_fini(rdev);
3558c2ecf20Sopenharmony_ci		return -ENOMEM;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci	rdev->gart.pages_entry = vmalloc(array_size(sizeof(uint64_t),
3588c2ecf20Sopenharmony_ci						    rdev->gart.num_gpu_pages));
3598c2ecf20Sopenharmony_ci	if (rdev->gart.pages_entry == NULL) {
3608c2ecf20Sopenharmony_ci		radeon_gart_fini(rdev);
3618c2ecf20Sopenharmony_ci		return -ENOMEM;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci	/* set GART entry to point to the dummy page by default */
3648c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->gart.num_gpu_pages; i++)
3658c2ecf20Sopenharmony_ci		rdev->gart.pages_entry[i] = rdev->dummy_page.entry;
3668c2ecf20Sopenharmony_ci	return 0;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci/**
3708c2ecf20Sopenharmony_ci * radeon_gart_fini - tear down the driver info for managing the gart
3718c2ecf20Sopenharmony_ci *
3728c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer
3738c2ecf20Sopenharmony_ci *
3748c2ecf20Sopenharmony_ci * Tear down the gart driver info and free the dummy page (all asics).
3758c2ecf20Sopenharmony_ci */
3768c2ecf20Sopenharmony_civoid radeon_gart_fini(struct radeon_device *rdev)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	if (rdev->gart.ready) {
3798c2ecf20Sopenharmony_ci		/* unbind pages */
3808c2ecf20Sopenharmony_ci		radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages);
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci	rdev->gart.ready = false;
3838c2ecf20Sopenharmony_ci	vfree(rdev->gart.pages);
3848c2ecf20Sopenharmony_ci	vfree(rdev->gart.pages_entry);
3858c2ecf20Sopenharmony_ci	rdev->gart.pages = NULL;
3868c2ecf20Sopenharmony_ci	rdev->gart.pages_entry = NULL;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	radeon_dummy_page_fini(rdev);
3898c2ecf20Sopenharmony_ci}
390