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/amdgpu_drm.h>
3362306a36Sopenharmony_ci#ifdef CONFIG_X86
3462306a36Sopenharmony_ci#include <asm/set_memory.h>
3562306a36Sopenharmony_ci#endif
3662306a36Sopenharmony_ci#include "amdgpu.h"
3762306a36Sopenharmony_ci#include <drm/drm_drv.h>
3862306a36Sopenharmony_ci#include <drm/ttm/ttm_tt.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/*
4162306a36Sopenharmony_ci * GART
4262306a36Sopenharmony_ci * The GART (Graphics Aperture Remapping Table) is an aperture
4362306a36Sopenharmony_ci * in the GPU's address space.  System pages can be mapped into
4462306a36Sopenharmony_ci * the aperture and look like contiguous pages from the GPU's
4562306a36Sopenharmony_ci * perspective.  A page table maps the pages in the aperture
4662306a36Sopenharmony_ci * to the actual backing pages in system memory.
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci * Radeon GPUs support both an internal GART, as described above,
4962306a36Sopenharmony_ci * and AGP.  AGP works similarly, but the GART table is configured
5062306a36Sopenharmony_ci * and maintained by the northbridge rather than the driver.
5162306a36Sopenharmony_ci * Radeon hw has a separate AGP aperture that is programmed to
5262306a36Sopenharmony_ci * point to the AGP aperture provided by the northbridge and the
5362306a36Sopenharmony_ci * requests are passed through to the northbridge aperture.
5462306a36Sopenharmony_ci * Both AGP and internal GART can be used at the same time, however
5562306a36Sopenharmony_ci * that is not currently supported by the driver.
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci * This file handles the common internal GART management.
5862306a36Sopenharmony_ci */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/*
6162306a36Sopenharmony_ci * Common GART table functions.
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/**
6562306a36Sopenharmony_ci * amdgpu_gart_dummy_page_init - init dummy page used by the driver
6662306a36Sopenharmony_ci *
6762306a36Sopenharmony_ci * @adev: amdgpu_device pointer
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * Allocate the dummy page used by the driver (all asics).
7062306a36Sopenharmony_ci * This dummy page is used by the driver as a filler for gart entries
7162306a36Sopenharmony_ci * when pages are taken out of the GART
7262306a36Sopenharmony_ci * Returns 0 on sucess, -ENOMEM on failure.
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_cistatic int amdgpu_gart_dummy_page_init(struct amdgpu_device *adev)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct page *dummy_page = ttm_glob.dummy_read_page;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (adev->dummy_page_addr)
7962306a36Sopenharmony_ci		return 0;
8062306a36Sopenharmony_ci	adev->dummy_page_addr = dma_map_page(&adev->pdev->dev, dummy_page, 0,
8162306a36Sopenharmony_ci					     PAGE_SIZE, DMA_BIDIRECTIONAL);
8262306a36Sopenharmony_ci	if (dma_mapping_error(&adev->pdev->dev, adev->dummy_page_addr)) {
8362306a36Sopenharmony_ci		dev_err(&adev->pdev->dev, "Failed to DMA MAP the dummy page\n");
8462306a36Sopenharmony_ci		adev->dummy_page_addr = 0;
8562306a36Sopenharmony_ci		return -ENOMEM;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci	return 0;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/**
9162306a36Sopenharmony_ci * amdgpu_gart_dummy_page_fini - free dummy page used by the driver
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * @adev: amdgpu_device pointer
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * Frees the dummy page used by the driver (all asics).
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_civoid amdgpu_gart_dummy_page_fini(struct amdgpu_device *adev)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	if (!adev->dummy_page_addr)
10062306a36Sopenharmony_ci		return;
10162306a36Sopenharmony_ci	dma_unmap_page(&adev->pdev->dev, adev->dummy_page_addr, PAGE_SIZE,
10262306a36Sopenharmony_ci		       DMA_BIDIRECTIONAL);
10362306a36Sopenharmony_ci	adev->dummy_page_addr = 0;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/**
10762306a36Sopenharmony_ci * amdgpu_gart_table_ram_alloc - allocate system ram for gart page table
10862306a36Sopenharmony_ci *
10962306a36Sopenharmony_ci * @adev: amdgpu_device pointer
11062306a36Sopenharmony_ci *
11162306a36Sopenharmony_ci * Allocate system memory for GART page table for ASICs that don't have
11262306a36Sopenharmony_ci * dedicated VRAM.
11362306a36Sopenharmony_ci * Returns 0 for success, error for failure.
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_ciint amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	unsigned int order = get_order(adev->gart.table_size);
11862306a36Sopenharmony_ci	gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO;
11962306a36Sopenharmony_ci	struct amdgpu_bo *bo = NULL;
12062306a36Sopenharmony_ci	struct sg_table *sg = NULL;
12162306a36Sopenharmony_ci	struct amdgpu_bo_param bp;
12262306a36Sopenharmony_ci	dma_addr_t dma_addr;
12362306a36Sopenharmony_ci	struct page *p;
12462306a36Sopenharmony_ci	int ret;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (adev->gart.bo != NULL)
12762306a36Sopenharmony_ci		return 0;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	p = alloc_pages(gfp_flags, order);
13062306a36Sopenharmony_ci	if (!p)
13162306a36Sopenharmony_ci		return -ENOMEM;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* If the hardware does not support UTCL2 snooping of the CPU caches
13462306a36Sopenharmony_ci	 * then set_memory_wc() could be used as a workaround to mark the pages
13562306a36Sopenharmony_ci	 * as write combine memory.
13662306a36Sopenharmony_ci	 */
13762306a36Sopenharmony_ci	dma_addr = dma_map_page(&adev->pdev->dev, p, 0, adev->gart.table_size,
13862306a36Sopenharmony_ci				DMA_BIDIRECTIONAL);
13962306a36Sopenharmony_ci	if (dma_mapping_error(&adev->pdev->dev, dma_addr)) {
14062306a36Sopenharmony_ci		dev_err(&adev->pdev->dev, "Failed to DMA MAP the GART BO page\n");
14162306a36Sopenharmony_ci		__free_pages(p, order);
14262306a36Sopenharmony_ci		p = NULL;
14362306a36Sopenharmony_ci		return -EFAULT;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	dev_info(adev->dev, "%s dma_addr:%pad\n", __func__, &dma_addr);
14762306a36Sopenharmony_ci	/* Create SG table */
14862306a36Sopenharmony_ci	sg = kmalloc(sizeof(*sg), GFP_KERNEL);
14962306a36Sopenharmony_ci	if (!sg) {
15062306a36Sopenharmony_ci		ret = -ENOMEM;
15162306a36Sopenharmony_ci		goto error;
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci	ret = sg_alloc_table(sg, 1, GFP_KERNEL);
15462306a36Sopenharmony_ci	if (ret)
15562306a36Sopenharmony_ci		goto error;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	sg_dma_address(sg->sgl) = dma_addr;
15862306a36Sopenharmony_ci	sg->sgl->length = adev->gart.table_size;
15962306a36Sopenharmony_ci#ifdef CONFIG_NEED_SG_DMA_LENGTH
16062306a36Sopenharmony_ci	sg->sgl->dma_length = adev->gart.table_size;
16162306a36Sopenharmony_ci#endif
16262306a36Sopenharmony_ci	/* Create SG BO */
16362306a36Sopenharmony_ci	memset(&bp, 0, sizeof(bp));
16462306a36Sopenharmony_ci	bp.size = adev->gart.table_size;
16562306a36Sopenharmony_ci	bp.byte_align = PAGE_SIZE;
16662306a36Sopenharmony_ci	bp.domain = AMDGPU_GEM_DOMAIN_CPU;
16762306a36Sopenharmony_ci	bp.type = ttm_bo_type_sg;
16862306a36Sopenharmony_ci	bp.resv = NULL;
16962306a36Sopenharmony_ci	bp.bo_ptr_size = sizeof(struct amdgpu_bo);
17062306a36Sopenharmony_ci	bp.flags = 0;
17162306a36Sopenharmony_ci	ret = amdgpu_bo_create(adev, &bp, &bo);
17262306a36Sopenharmony_ci	if (ret)
17362306a36Sopenharmony_ci		goto error;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	bo->tbo.sg = sg;
17662306a36Sopenharmony_ci	bo->tbo.ttm->sg = sg;
17762306a36Sopenharmony_ci	bo->allowed_domains = AMDGPU_GEM_DOMAIN_GTT;
17862306a36Sopenharmony_ci	bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	ret = amdgpu_bo_reserve(bo, true);
18162306a36Sopenharmony_ci	if (ret) {
18262306a36Sopenharmony_ci		dev_err(adev->dev, "(%d) failed to reserve bo for GART system bo\n", ret);
18362306a36Sopenharmony_ci		goto error;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT);
18762306a36Sopenharmony_ci	WARN(ret, "Pinning the GART table failed");
18862306a36Sopenharmony_ci	if (ret)
18962306a36Sopenharmony_ci		goto error_resv;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	adev->gart.bo = bo;
19262306a36Sopenharmony_ci	adev->gart.ptr = page_to_virt(p);
19362306a36Sopenharmony_ci	/* Make GART table accessible in VMID0 */
19462306a36Sopenharmony_ci	ret = amdgpu_ttm_alloc_gart(&adev->gart.bo->tbo);
19562306a36Sopenharmony_ci	if (ret)
19662306a36Sopenharmony_ci		amdgpu_gart_table_ram_free(adev);
19762306a36Sopenharmony_ci	amdgpu_bo_unreserve(bo);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	return 0;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cierror_resv:
20262306a36Sopenharmony_ci	amdgpu_bo_unreserve(bo);
20362306a36Sopenharmony_cierror:
20462306a36Sopenharmony_ci	amdgpu_bo_unref(&bo);
20562306a36Sopenharmony_ci	if (sg) {
20662306a36Sopenharmony_ci		sg_free_table(sg);
20762306a36Sopenharmony_ci		kfree(sg);
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci	__free_pages(p, order);
21062306a36Sopenharmony_ci	return ret;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/**
21462306a36Sopenharmony_ci * amdgpu_gart_table_ram_free - free gart page table system ram
21562306a36Sopenharmony_ci *
21662306a36Sopenharmony_ci * @adev: amdgpu_device pointer
21762306a36Sopenharmony_ci *
21862306a36Sopenharmony_ci * Free the system memory used for the GART page tableon ASICs that don't
21962306a36Sopenharmony_ci * have dedicated VRAM.
22062306a36Sopenharmony_ci */
22162306a36Sopenharmony_civoid amdgpu_gart_table_ram_free(struct amdgpu_device *adev)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	unsigned int order = get_order(adev->gart.table_size);
22462306a36Sopenharmony_ci	struct sg_table *sg = adev->gart.bo->tbo.sg;
22562306a36Sopenharmony_ci	struct page *p;
22662306a36Sopenharmony_ci	int ret;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	ret = amdgpu_bo_reserve(adev->gart.bo, false);
22962306a36Sopenharmony_ci	if (!ret) {
23062306a36Sopenharmony_ci		amdgpu_bo_unpin(adev->gart.bo);
23162306a36Sopenharmony_ci		amdgpu_bo_unreserve(adev->gart.bo);
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci	amdgpu_bo_unref(&adev->gart.bo);
23462306a36Sopenharmony_ci	sg_free_table(sg);
23562306a36Sopenharmony_ci	kfree(sg);
23662306a36Sopenharmony_ci	p = virt_to_page(adev->gart.ptr);
23762306a36Sopenharmony_ci	__free_pages(p, order);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	adev->gart.ptr = NULL;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci/**
24362306a36Sopenharmony_ci * amdgpu_gart_table_vram_alloc - allocate vram for gart page table
24462306a36Sopenharmony_ci *
24562306a36Sopenharmony_ci * @adev: amdgpu_device pointer
24662306a36Sopenharmony_ci *
24762306a36Sopenharmony_ci * Allocate video memory for GART page table
24862306a36Sopenharmony_ci * (pcie r4xx, r5xx+).  These asics require the
24962306a36Sopenharmony_ci * gart table to be in video memory.
25062306a36Sopenharmony_ci * Returns 0 for success, error for failure.
25162306a36Sopenharmony_ci */
25262306a36Sopenharmony_ciint amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	if (adev->gart.bo != NULL)
25562306a36Sopenharmony_ci		return 0;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return amdgpu_bo_create_kernel(adev,  adev->gart.table_size, PAGE_SIZE,
25862306a36Sopenharmony_ci				       AMDGPU_GEM_DOMAIN_VRAM, &adev->gart.bo,
25962306a36Sopenharmony_ci				       NULL, (void *)&adev->gart.ptr);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/**
26362306a36Sopenharmony_ci * amdgpu_gart_table_vram_free - free gart page table vram
26462306a36Sopenharmony_ci *
26562306a36Sopenharmony_ci * @adev: amdgpu_device pointer
26662306a36Sopenharmony_ci *
26762306a36Sopenharmony_ci * Free the video memory used for the GART page table
26862306a36Sopenharmony_ci * (pcie r4xx, r5xx+).  These asics require the gart table to
26962306a36Sopenharmony_ci * be in video memory.
27062306a36Sopenharmony_ci */
27162306a36Sopenharmony_civoid amdgpu_gart_table_vram_free(struct amdgpu_device *adev)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	amdgpu_bo_free_kernel(&adev->gart.bo, NULL, (void *)&adev->gart.ptr);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci/*
27762306a36Sopenharmony_ci * Common gart functions.
27862306a36Sopenharmony_ci */
27962306a36Sopenharmony_ci/**
28062306a36Sopenharmony_ci * amdgpu_gart_unbind - unbind pages from the gart page table
28162306a36Sopenharmony_ci *
28262306a36Sopenharmony_ci * @adev: amdgpu_device pointer
28362306a36Sopenharmony_ci * @offset: offset into the GPU's gart aperture
28462306a36Sopenharmony_ci * @pages: number of pages to unbind
28562306a36Sopenharmony_ci *
28662306a36Sopenharmony_ci * Unbinds the requested pages from the gart page table and
28762306a36Sopenharmony_ci * replaces them with the dummy page (all asics).
28862306a36Sopenharmony_ci * Returns 0 for success, -EINVAL for failure.
28962306a36Sopenharmony_ci */
29062306a36Sopenharmony_civoid amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
29162306a36Sopenharmony_ci			int pages)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	unsigned t;
29462306a36Sopenharmony_ci	unsigned p;
29562306a36Sopenharmony_ci	int i, j;
29662306a36Sopenharmony_ci	u64 page_base;
29762306a36Sopenharmony_ci	/* Starting from VEGA10, system bit must be 0 to mean invalid. */
29862306a36Sopenharmony_ci	uint64_t flags = 0;
29962306a36Sopenharmony_ci	int idx;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (!adev->gart.ptr)
30262306a36Sopenharmony_ci		return;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (!drm_dev_enter(adev_to_drm(adev), &idx))
30562306a36Sopenharmony_ci		return;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	t = offset / AMDGPU_GPU_PAGE_SIZE;
30862306a36Sopenharmony_ci	p = t / AMDGPU_GPU_PAGES_IN_CPU_PAGE;
30962306a36Sopenharmony_ci	for (i = 0; i < pages; i++, p++) {
31062306a36Sopenharmony_ci		page_base = adev->dummy_page_addr;
31162306a36Sopenharmony_ci		if (!adev->gart.ptr)
31262306a36Sopenharmony_ci			continue;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) {
31562306a36Sopenharmony_ci			amdgpu_gmc_set_pte_pde(adev, adev->gart.ptr,
31662306a36Sopenharmony_ci					       t, page_base, flags);
31762306a36Sopenharmony_ci			page_base += AMDGPU_GPU_PAGE_SIZE;
31862306a36Sopenharmony_ci		}
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci	mb();
32162306a36Sopenharmony_ci	amdgpu_device_flush_hdp(adev, NULL);
32262306a36Sopenharmony_ci	for_each_set_bit(i, adev->vmhubs_mask, AMDGPU_MAX_VMHUBS)
32362306a36Sopenharmony_ci		amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	drm_dev_exit(idx);
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci/**
32962306a36Sopenharmony_ci * amdgpu_gart_map - map dma_addresses into GART entries
33062306a36Sopenharmony_ci *
33162306a36Sopenharmony_ci * @adev: amdgpu_device pointer
33262306a36Sopenharmony_ci * @offset: offset into the GPU's gart aperture
33362306a36Sopenharmony_ci * @pages: number of pages to bind
33462306a36Sopenharmony_ci * @dma_addr: DMA addresses of pages
33562306a36Sopenharmony_ci * @flags: page table entry flags
33662306a36Sopenharmony_ci * @dst: CPU address of the gart table
33762306a36Sopenharmony_ci *
33862306a36Sopenharmony_ci * Map the dma_addresses into GART entries (all asics).
33962306a36Sopenharmony_ci * Returns 0 for success, -EINVAL for failure.
34062306a36Sopenharmony_ci */
34162306a36Sopenharmony_civoid amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset,
34262306a36Sopenharmony_ci		    int pages, dma_addr_t *dma_addr, uint64_t flags,
34362306a36Sopenharmony_ci		    void *dst)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	uint64_t page_base;
34662306a36Sopenharmony_ci	unsigned i, j, t;
34762306a36Sopenharmony_ci	int idx;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (!drm_dev_enter(adev_to_drm(adev), &idx))
35062306a36Sopenharmony_ci		return;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	t = offset / AMDGPU_GPU_PAGE_SIZE;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	for (i = 0; i < pages; i++) {
35562306a36Sopenharmony_ci		page_base = dma_addr[i];
35662306a36Sopenharmony_ci		for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) {
35762306a36Sopenharmony_ci			amdgpu_gmc_set_pte_pde(adev, dst, t, page_base, flags);
35862306a36Sopenharmony_ci			page_base += AMDGPU_GPU_PAGE_SIZE;
35962306a36Sopenharmony_ci		}
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci	drm_dev_exit(idx);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci/**
36562306a36Sopenharmony_ci * amdgpu_gart_bind - bind pages into the gart page table
36662306a36Sopenharmony_ci *
36762306a36Sopenharmony_ci * @adev: amdgpu_device pointer
36862306a36Sopenharmony_ci * @offset: offset into the GPU's gart aperture
36962306a36Sopenharmony_ci * @pages: number of pages to bind
37062306a36Sopenharmony_ci * @dma_addr: DMA addresses of pages
37162306a36Sopenharmony_ci * @flags: page table entry flags
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * Binds the requested pages to the gart page table
37462306a36Sopenharmony_ci * (all asics).
37562306a36Sopenharmony_ci * Returns 0 for success, -EINVAL for failure.
37662306a36Sopenharmony_ci */
37762306a36Sopenharmony_civoid amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
37862306a36Sopenharmony_ci		     int pages, dma_addr_t *dma_addr,
37962306a36Sopenharmony_ci		     uint64_t flags)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	if (!adev->gart.ptr)
38262306a36Sopenharmony_ci		return;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	amdgpu_gart_map(adev, offset, pages, dma_addr, flags, adev->gart.ptr);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/**
38862306a36Sopenharmony_ci * amdgpu_gart_invalidate_tlb - invalidate gart TLB
38962306a36Sopenharmony_ci *
39062306a36Sopenharmony_ci * @adev: amdgpu device driver pointer
39162306a36Sopenharmony_ci *
39262306a36Sopenharmony_ci * Invalidate gart TLB which can be use as a way to flush gart changes
39362306a36Sopenharmony_ci *
39462306a36Sopenharmony_ci */
39562306a36Sopenharmony_civoid amdgpu_gart_invalidate_tlb(struct amdgpu_device *adev)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	int i;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (!adev->gart.ptr)
40062306a36Sopenharmony_ci		return;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	mb();
40362306a36Sopenharmony_ci	amdgpu_device_flush_hdp(adev, NULL);
40462306a36Sopenharmony_ci	for_each_set_bit(i, adev->vmhubs_mask, AMDGPU_MAX_VMHUBS)
40562306a36Sopenharmony_ci		amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0);
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci/**
40962306a36Sopenharmony_ci * amdgpu_gart_init - init the driver info for managing the gart
41062306a36Sopenharmony_ci *
41162306a36Sopenharmony_ci * @adev: amdgpu_device pointer
41262306a36Sopenharmony_ci *
41362306a36Sopenharmony_ci * Allocate the dummy page and init the gart driver info (all asics).
41462306a36Sopenharmony_ci * Returns 0 for success, error for failure.
41562306a36Sopenharmony_ci */
41662306a36Sopenharmony_ciint amdgpu_gart_init(struct amdgpu_device *adev)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	int r;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (adev->dummy_page_addr)
42162306a36Sopenharmony_ci		return 0;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/* We need PAGE_SIZE >= AMDGPU_GPU_PAGE_SIZE */
42462306a36Sopenharmony_ci	if (PAGE_SIZE < AMDGPU_GPU_PAGE_SIZE) {
42562306a36Sopenharmony_ci		DRM_ERROR("Page size is smaller than GPU page size!\n");
42662306a36Sopenharmony_ci		return -EINVAL;
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci	r = amdgpu_gart_dummy_page_init(adev);
42962306a36Sopenharmony_ci	if (r)
43062306a36Sopenharmony_ci		return r;
43162306a36Sopenharmony_ci	/* Compute table size */
43262306a36Sopenharmony_ci	adev->gart.num_cpu_pages = adev->gmc.gart_size / PAGE_SIZE;
43362306a36Sopenharmony_ci	adev->gart.num_gpu_pages = adev->gmc.gart_size / AMDGPU_GPU_PAGE_SIZE;
43462306a36Sopenharmony_ci	DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n",
43562306a36Sopenharmony_ci		 adev->gart.num_cpu_pages, adev->gart.num_gpu_pages);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	return 0;
43862306a36Sopenharmony_ci}
439