diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c | 141 | 
1 files changed, 139 insertions, 2 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 01cb89ffbd56..73b8cca35bab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -35,6 +35,7 @@  #endif  #include "amdgpu.h"  #include <drm/drm_drv.h> +#include <drm/ttm/ttm_tt.h>  /*   * GART @@ -103,6 +104,142 @@ void amdgpu_gart_dummy_page_fini(struct amdgpu_device *adev)  }  /** + * amdgpu_gart_table_ram_alloc - allocate system ram for gart page table + * + * @adev: amdgpu_device pointer + * + * Allocate system memory for GART page table for ASICs that don't have + * dedicated VRAM. + * Returns 0 for success, error for failure. + */ +int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev) +{ +	unsigned int order = get_order(adev->gart.table_size); +	gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO; +	struct amdgpu_bo *bo = NULL; +	struct sg_table *sg = NULL; +	struct amdgpu_bo_param bp; +	dma_addr_t dma_addr; +	struct page *p; +	int ret; + +	if (adev->gart.bo != NULL) +		return 0; + +	p = alloc_pages(gfp_flags, order); +	if (!p) +		return -ENOMEM; + +	/* If the hardware does not support UTCL2 snooping of the CPU caches +	 * then set_memory_wc() could be used as a workaround to mark the pages +	 * as write combine memory. +	 */ +	dma_addr = dma_map_page(&adev->pdev->dev, p, 0, adev->gart.table_size, +				DMA_BIDIRECTIONAL); +	if (dma_mapping_error(&adev->pdev->dev, dma_addr)) { +		dev_err(&adev->pdev->dev, "Failed to DMA MAP the GART BO page\n"); +		__free_pages(p, order); +		p = NULL; +		return -EFAULT; +	} + +	dev_info(adev->dev, "%s dma_addr:%pad\n", __func__, &dma_addr); +	/* Create SG table */ +	sg = kmalloc(sizeof(*sg), GFP_KERNEL); +	if (!sg) { +		ret = -ENOMEM; +		goto error; +	} +	ret = sg_alloc_table(sg, 1, GFP_KERNEL); +	if (ret) +		goto error; + +	sg_dma_address(sg->sgl) = dma_addr; +	sg->sgl->length = adev->gart.table_size; +#ifdef CONFIG_NEED_SG_DMA_LENGTH +	sg->sgl->dma_length = adev->gart.table_size; +#endif +	/* Create SG BO */ +	memset(&bp, 0, sizeof(bp)); +	bp.size = adev->gart.table_size; +	bp.byte_align = PAGE_SIZE; +	bp.domain = AMDGPU_GEM_DOMAIN_CPU; +	bp.type = ttm_bo_type_sg; +	bp.resv = NULL; +	bp.bo_ptr_size = sizeof(struct amdgpu_bo); +	bp.flags = 0; +	ret = amdgpu_bo_create(adev, &bp, &bo); +	if (ret) +		goto error; + +	bo->tbo.sg = sg; +	bo->tbo.ttm->sg = sg; +	bo->allowed_domains = AMDGPU_GEM_DOMAIN_GTT; +	bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT; + +	ret = amdgpu_bo_reserve(bo, true); +	if (ret) { +		dev_err(adev->dev, "(%d) failed to reserve bo for GART system bo\n", ret); +		goto error; +	} + +	ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT); +	WARN(ret, "Pinning the GART table failed"); +	if (ret) +		goto error_resv; + +	adev->gart.bo = bo; +	adev->gart.ptr = page_to_virt(p); +	/* Make GART table accessible in VMID0 */ +	ret = amdgpu_ttm_alloc_gart(&adev->gart.bo->tbo); +	if (ret) +		amdgpu_gart_table_ram_free(adev); +	amdgpu_bo_unreserve(bo); + +	return 0; + +error_resv: +	amdgpu_bo_unreserve(bo); +error: +	amdgpu_bo_unref(&bo); +	if (sg) { +		sg_free_table(sg); +		kfree(sg); +	} +	__free_pages(p, order); +	return ret; +} + +/** + * amdgpu_gart_table_ram_free - free gart page table system ram + * + * @adev: amdgpu_device pointer + * + * Free the system memory used for the GART page tableon ASICs that don't + * have dedicated VRAM. + */ +void amdgpu_gart_table_ram_free(struct amdgpu_device *adev) +{ +	unsigned int order = get_order(adev->gart.table_size); +	struct sg_table *sg = adev->gart.bo->tbo.sg; +	struct page *p; +	int ret; + +	ret = amdgpu_bo_reserve(adev->gart.bo, false); +	if (!ret) { +		amdgpu_bo_unpin(adev->gart.bo); +		amdgpu_bo_unreserve(adev->gart.bo); +	} +	amdgpu_bo_unref(&adev->gart.bo); +	sg_free_table(sg); +	kfree(sg); +	p = virt_to_page(adev->gart.ptr); +	__free_pages(p, order); + +	adev->gart.ptr = NULL; +} + +/**   * amdgpu_gart_table_vram_alloc - allocate vram for gart page table   *   * @adev: amdgpu_device pointer @@ -182,7 +319,7 @@ void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,  	}  	mb();  	amdgpu_device_flush_hdp(adev, NULL); -	for (i = 0; i < adev->num_vmhubs; i++) +	for_each_set_bit(i, adev->vmhubs_mask, AMDGPU_MAX_VMHUBS)  		amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0);  	drm_dev_exit(idx); @@ -264,7 +401,7 @@ void amdgpu_gart_invalidate_tlb(struct amdgpu_device *adev)  	mb();  	amdgpu_device_flush_hdp(adev, NULL); -	for (i = 0; i < adev->num_vmhubs; i++) +	for_each_set_bit(i, adev->vmhubs_mask, AMDGPU_MAX_VMHUBS)  		amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0);  }  | 
