![]() |
|
|||
0001 /* 0002 * Copyright 2008 Advanced Micro Devices, Inc. 0003 * Copyright 2008 Red Hat Inc. 0004 * Copyright 2009 Jerome Glisse. 0005 * 0006 * Permission is hereby granted, free of charge, to any person obtaining a 0007 * copy of this software and associated documentation files (the "Software"), 0008 * to deal in the Software without restriction, including without limitation 0009 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 0010 * and/or sell copies of the Software, and to permit persons to whom the 0011 * Software is furnished to do so, subject to the following conditions: 0012 * 0013 * The above copyright notice and this permission notice shall be included in 0014 * all copies or substantial portions of the Software. 0015 * 0016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 0019 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 0020 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 0021 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 0022 * OTHER DEALINGS IN THE SOFTWARE. 0023 * 0024 * Authors: Dave Airlie 0025 * Alex Deucher 0026 * Jerome Glisse 0027 */ 0028 0029 #include <linux/pci.h> 0030 #include <linux/vmalloc.h> 0031 0032 #include <drm/amdgpu_drm.h> 0033 #ifdef CONFIG_X86 0034 #include <asm/set_memory.h> 0035 #endif 0036 #include "amdgpu.h" 0037 #include <drm/drm_drv.h> 0038 0039 /* 0040 * GART 0041 * The GART (Graphics Aperture Remapping Table) is an aperture 0042 * in the GPU's address space. System pages can be mapped into 0043 * the aperture and look like contiguous pages from the GPU's 0044 * perspective. A page table maps the pages in the aperture 0045 * to the actual backing pages in system memory. 0046 * 0047 * Radeon GPUs support both an internal GART, as described above, 0048 * and AGP. AGP works similarly, but the GART table is configured 0049 * and maintained by the northbridge rather than the driver. 0050 * Radeon hw has a separate AGP aperture that is programmed to 0051 * point to the AGP aperture provided by the northbridge and the 0052 * requests are passed through to the northbridge aperture. 0053 * Both AGP and internal GART can be used at the same time, however 0054 * that is not currently supported by the driver. 0055 * 0056 * This file handles the common internal GART management. 0057 */ 0058 0059 /* 0060 * Common GART table functions. 0061 */ 0062 0063 /** 0064 * amdgpu_gart_dummy_page_init - init dummy page used by the driver 0065 * 0066 * @adev: amdgpu_device pointer 0067 * 0068 * Allocate the dummy page used by the driver (all asics). 0069 * This dummy page is used by the driver as a filler for gart entries 0070 * when pages are taken out of the GART 0071 * Returns 0 on sucess, -ENOMEM on failure. 0072 */ 0073 static int amdgpu_gart_dummy_page_init(struct amdgpu_device *adev) 0074 { 0075 struct page *dummy_page = ttm_glob.dummy_read_page; 0076 0077 if (adev->dummy_page_addr) 0078 return 0; 0079 adev->dummy_page_addr = dma_map_page(&adev->pdev->dev, dummy_page, 0, 0080 PAGE_SIZE, DMA_BIDIRECTIONAL); 0081 if (dma_mapping_error(&adev->pdev->dev, adev->dummy_page_addr)) { 0082 dev_err(&adev->pdev->dev, "Failed to DMA MAP the dummy page\n"); 0083 adev->dummy_page_addr = 0; 0084 return -ENOMEM; 0085 } 0086 return 0; 0087 } 0088 0089 /** 0090 * amdgpu_gart_dummy_page_fini - free dummy page used by the driver 0091 * 0092 * @adev: amdgpu_device pointer 0093 * 0094 * Frees the dummy page used by the driver (all asics). 0095 */ 0096 void amdgpu_gart_dummy_page_fini(struct amdgpu_device *adev) 0097 { 0098 if (!adev->dummy_page_addr) 0099 return; 0100 dma_unmap_page(&adev->pdev->dev, adev->dummy_page_addr, PAGE_SIZE, 0101 DMA_BIDIRECTIONAL); 0102 adev->dummy_page_addr = 0; 0103 } 0104 0105 /** 0106 * amdgpu_gart_table_vram_alloc - allocate vram for gart page table 0107 * 0108 * @adev: amdgpu_device pointer 0109 * 0110 * Allocate video memory for GART page table 0111 * (pcie r4xx, r5xx+). These asics require the 0112 * gart table to be in video memory. 0113 * Returns 0 for success, error for failure. 0114 */ 0115 int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev) 0116 { 0117 if (adev->gart.bo != NULL) 0118 return 0; 0119 0120 return amdgpu_bo_create_kernel(adev, adev->gart.table_size, PAGE_SIZE, 0121 AMDGPU_GEM_DOMAIN_VRAM, &adev->gart.bo, 0122 NULL, (void *)&adev->gart.ptr); 0123 } 0124 0125 /** 0126 * amdgpu_gart_table_vram_free - free gart page table vram 0127 * 0128 * @adev: amdgpu_device pointer 0129 * 0130 * Free the video memory used for the GART page table 0131 * (pcie r4xx, r5xx+). These asics require the gart table to 0132 * be in video memory. 0133 */ 0134 void amdgpu_gart_table_vram_free(struct amdgpu_device *adev) 0135 { 0136 amdgpu_bo_free_kernel(&adev->gart.bo, NULL, (void *)&adev->gart.ptr); 0137 } 0138 0139 /* 0140 * Common gart functions. 0141 */ 0142 /** 0143 * amdgpu_gart_unbind - unbind pages from the gart page table 0144 * 0145 * @adev: amdgpu_device pointer 0146 * @offset: offset into the GPU's gart aperture 0147 * @pages: number of pages to unbind 0148 * 0149 * Unbinds the requested pages from the gart page table and 0150 * replaces them with the dummy page (all asics). 0151 * Returns 0 for success, -EINVAL for failure. 0152 */ 0153 void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset, 0154 int pages) 0155 { 0156 unsigned t; 0157 unsigned p; 0158 int i, j; 0159 u64 page_base; 0160 /* Starting from VEGA10, system bit must be 0 to mean invalid. */ 0161 uint64_t flags = 0; 0162 int idx; 0163 0164 if (!adev->gart.ptr) 0165 return; 0166 0167 if (!drm_dev_enter(adev_to_drm(adev), &idx)) 0168 return; 0169 0170 t = offset / AMDGPU_GPU_PAGE_SIZE; 0171 p = t / AMDGPU_GPU_PAGES_IN_CPU_PAGE; 0172 for (i = 0; i < pages; i++, p++) { 0173 page_base = adev->dummy_page_addr; 0174 if (!adev->gart.ptr) 0175 continue; 0176 0177 for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) { 0178 amdgpu_gmc_set_pte_pde(adev, adev->gart.ptr, 0179 t, page_base, flags); 0180 page_base += AMDGPU_GPU_PAGE_SIZE; 0181 } 0182 } 0183 mb(); 0184 amdgpu_device_flush_hdp(adev, NULL); 0185 for (i = 0; i < adev->num_vmhubs; i++) 0186 amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0); 0187 0188 drm_dev_exit(idx); 0189 } 0190 0191 /** 0192 * amdgpu_gart_map - map dma_addresses into GART entries 0193 * 0194 * @adev: amdgpu_device pointer 0195 * @offset: offset into the GPU's gart aperture 0196 * @pages: number of pages to bind 0197 * @dma_addr: DMA addresses of pages 0198 * @flags: page table entry flags 0199 * @dst: CPU address of the gart table 0200 * 0201 * Map the dma_addresses into GART entries (all asics). 0202 * Returns 0 for success, -EINVAL for failure. 0203 */ 0204 void amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, 0205 int pages, dma_addr_t *dma_addr, uint64_t flags, 0206 void *dst) 0207 { 0208 uint64_t page_base; 0209 unsigned i, j, t; 0210 int idx; 0211 0212 if (!drm_dev_enter(adev_to_drm(adev), &idx)) 0213 return; 0214 0215 t = offset / AMDGPU_GPU_PAGE_SIZE; 0216 0217 for (i = 0; i < pages; i++) { 0218 page_base = dma_addr[i]; 0219 for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) { 0220 amdgpu_gmc_set_pte_pde(adev, dst, t, page_base, flags); 0221 page_base += AMDGPU_GPU_PAGE_SIZE; 0222 } 0223 } 0224 drm_dev_exit(idx); 0225 } 0226 0227 /** 0228 * amdgpu_gart_bind - bind pages into the gart page table 0229 * 0230 * @adev: amdgpu_device pointer 0231 * @offset: offset into the GPU's gart aperture 0232 * @pages: number of pages to bind 0233 * @dma_addr: DMA addresses of pages 0234 * @flags: page table entry flags 0235 * 0236 * Binds the requested pages to the gart page table 0237 * (all asics). 0238 * Returns 0 for success, -EINVAL for failure. 0239 */ 0240 void amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset, 0241 int pages, dma_addr_t *dma_addr, 0242 uint64_t flags) 0243 { 0244 if (!adev->gart.ptr) 0245 return; 0246 0247 amdgpu_gart_map(adev, offset, pages, dma_addr, flags, adev->gart.ptr); 0248 } 0249 0250 /** 0251 * amdgpu_gart_invalidate_tlb - invalidate gart TLB 0252 * 0253 * @adev: amdgpu device driver pointer 0254 * 0255 * Invalidate gart TLB which can be use as a way to flush gart changes 0256 * 0257 */ 0258 void amdgpu_gart_invalidate_tlb(struct amdgpu_device *adev) 0259 { 0260 int i; 0261 0262 if (!adev->gart.ptr) 0263 return; 0264 0265 mb(); 0266 amdgpu_device_flush_hdp(adev, NULL); 0267 for (i = 0; i < adev->num_vmhubs; i++) 0268 amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0); 0269 } 0270 0271 /** 0272 * amdgpu_gart_init - init the driver info for managing the gart 0273 * 0274 * @adev: amdgpu_device pointer 0275 * 0276 * Allocate the dummy page and init the gart driver info (all asics). 0277 * Returns 0 for success, error for failure. 0278 */ 0279 int amdgpu_gart_init(struct amdgpu_device *adev) 0280 { 0281 int r; 0282 0283 if (adev->dummy_page_addr) 0284 return 0; 0285 0286 /* We need PAGE_SIZE >= AMDGPU_GPU_PAGE_SIZE */ 0287 if (PAGE_SIZE < AMDGPU_GPU_PAGE_SIZE) { 0288 DRM_ERROR("Page size is smaller than GPU page size!\n"); 0289 return -EINVAL; 0290 } 0291 r = amdgpu_gart_dummy_page_init(adev); 0292 if (r) 0293 return r; 0294 /* Compute table size */ 0295 adev->gart.num_cpu_pages = adev->gmc.gart_size / PAGE_SIZE; 0296 adev->gart.num_gpu_pages = adev->gmc.gart_size / AMDGPU_GPU_PAGE_SIZE; 0297 DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n", 0298 adev->gart.num_cpu_pages, adev->gart.num_gpu_pages); 0299 0300 return 0; 0301 }
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |