1 /* 2 * Copyright 2008 Advanced Micro Devices, Inc. 3 * Copyright 2008 Red Hat Inc. 4 * Copyright 2009 Jerome Glisse. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: Dave Airlie 25 * Alex Deucher 26 * Jerome Glisse 27 * 28 * $FreeBSD: head/sys/dev/drm2/radeon/radeon_gart.c 254885 2013-08-25 19:37:15Z dumbbell $ 29 */ 30 #include <drm/drmP.h> 31 #include "drm/drm_legacy.h" /* for drm_dma_handle_t */ 32 #include <drm/radeon_drm.h> 33 #include "radeon.h" 34 35 /* 36 * GART 37 * The GART (Graphics Aperture Remapping Table) is an aperture 38 * in the GPU's address space. System pages can be mapped into 39 * the aperture and look like contiguous pages from the GPU's 40 * perspective. A page table maps the pages in the aperture 41 * to the actual backing pages in system memory. 42 * 43 * Radeon GPUs support both an internal GART, as described above, 44 * and AGP. AGP works similarly, but the GART table is configured 45 * and maintained by the northbridge rather than the driver. 46 * Radeon hw has a separate AGP aperture that is programmed to 47 * point to the AGP aperture provided by the northbridge and the 48 * requests are passed through to the northbridge aperture. 49 * Both AGP and internal GART can be used at the same time, however 50 * that is not currently supported by the driver. 51 * 52 * This file handles the common internal GART management. 53 */ 54 55 /* 56 * Common GART table functions. 57 */ 58 /** 59 * radeon_gart_table_ram_alloc - allocate system ram for gart page table 60 * 61 * @rdev: radeon_device pointer 62 * 63 * Allocate system memory for GART page table 64 * (r1xx-r3xx, non-pcie r4xx, rs400). These asics require the 65 * gart table to be in system memory. 66 * Returns 0 for success, -ENOMEM for failure. 67 */ 68 int radeon_gart_table_ram_alloc(struct radeon_device *rdev) 69 { 70 drm_dma_handle_t *dmah; 71 72 dmah = drm_pci_alloc(rdev->ddev, rdev->gart.table_size, 73 PAGE_SIZE); 74 if (dmah == NULL) { 75 return -ENOMEM; 76 } 77 rdev->gart.dmah = dmah; 78 rdev->gart.ptr = dmah->vaddr; 79 #if defined(__i386) || defined(__amd64) 80 if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || 81 rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { 82 pmap_change_attr((vm_offset_t)rdev->gart.ptr, 83 rdev->gart.table_size >> PAGE_SHIFT, PAT_UNCACHED); 84 } 85 #endif 86 rdev->gart.table_addr = dmah->busaddr; 87 memset((void *)rdev->gart.ptr, 0, rdev->gart.table_size); 88 return 0; 89 } 90 91 /** 92 * radeon_gart_table_ram_free - free system ram for gart page table 93 * 94 * @rdev: radeon_device pointer 95 * 96 * Free system memory for GART page table 97 * (r1xx-r3xx, non-pcie r4xx, rs400). These asics require the 98 * gart table to be in system memory. 99 */ 100 void radeon_gart_table_ram_free(struct radeon_device *rdev) 101 { 102 if (rdev->gart.ptr == NULL) { 103 return; 104 } 105 #if defined(__i386) || defined(__amd64) 106 if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || 107 rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { 108 pmap_change_attr((vm_offset_t)rdev->gart.ptr, 109 rdev->gart.table_size >> PAGE_SHIFT, PAT_WRITE_COMBINING); 110 } 111 #endif 112 drm_pci_free(rdev->ddev, rdev->gart.dmah); 113 rdev->gart.dmah = NULL; 114 rdev->gart.ptr = NULL; 115 rdev->gart.table_addr = 0; 116 } 117 118 /** 119 * radeon_gart_table_vram_alloc - allocate vram for gart page table 120 * 121 * @rdev: radeon_device pointer 122 * 123 * Allocate video memory for GART page table 124 * (pcie r4xx, r5xx+). These asics require the 125 * gart table to be in video memory. 126 * Returns 0 for success, error for failure. 127 */ 128 int radeon_gart_table_vram_alloc(struct radeon_device *rdev) 129 { 130 int r; 131 132 if (rdev->gart.robj == NULL) { 133 r = radeon_bo_create(rdev, rdev->gart.table_size, 134 PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, 135 0, NULL, &rdev->gart.robj); 136 if (r) { 137 return r; 138 } 139 } 140 return 0; 141 } 142 143 /** 144 * radeon_gart_table_vram_pin - pin gart page table in vram 145 * 146 * @rdev: radeon_device pointer 147 * 148 * Pin the GART page table in vram so it will not be moved 149 * by the memory manager (pcie r4xx, r5xx+). These asics require the 150 * gart table to be in video memory. 151 * Returns 0 for success, error for failure. 152 */ 153 int radeon_gart_table_vram_pin(struct radeon_device *rdev) 154 { 155 u64 gpu_addr; 156 int r; 157 158 r = radeon_bo_reserve(rdev->gart.robj, false); 159 if (unlikely(r != 0)) 160 return r; 161 r = radeon_bo_pin(rdev->gart.robj, 162 RADEON_GEM_DOMAIN_VRAM, &gpu_addr); 163 if (r) { 164 radeon_bo_unreserve(rdev->gart.robj); 165 return r; 166 } 167 r = radeon_bo_kmap(rdev->gart.robj, &rdev->gart.ptr); 168 if (r) 169 radeon_bo_unpin(rdev->gart.robj); 170 radeon_bo_unreserve(rdev->gart.robj); 171 rdev->gart.table_addr = gpu_addr; 172 return r; 173 } 174 175 /** 176 * radeon_gart_table_vram_unpin - unpin gart page table in vram 177 * 178 * @rdev: radeon_device pointer 179 * 180 * Unpin the GART page table in vram (pcie r4xx, r5xx+). 181 * These asics require the gart table to be in video memory. 182 */ 183 void radeon_gart_table_vram_unpin(struct radeon_device *rdev) 184 { 185 int r; 186 187 if (rdev->gart.robj == NULL) { 188 return; 189 } 190 r = radeon_bo_reserve(rdev->gart.robj, false); 191 if (likely(r == 0)) { 192 radeon_bo_kunmap(rdev->gart.robj); 193 radeon_bo_unpin(rdev->gart.robj); 194 radeon_bo_unreserve(rdev->gart.robj); 195 rdev->gart.ptr = NULL; 196 } 197 } 198 199 /** 200 * radeon_gart_table_vram_free - free gart page table vram 201 * 202 * @rdev: radeon_device pointer 203 * 204 * Free the video memory used for the GART page table 205 * (pcie r4xx, r5xx+). These asics require the gart table to 206 * be in video memory. 207 */ 208 void radeon_gart_table_vram_free(struct radeon_device *rdev) 209 { 210 if (rdev->gart.robj == NULL) { 211 return; 212 } 213 radeon_bo_unref(&rdev->gart.robj); 214 } 215 216 /* 217 * Common gart functions. 218 */ 219 /** 220 * radeon_gart_unbind - unbind pages from the gart page table 221 * 222 * @rdev: radeon_device pointer 223 * @offset: offset into the GPU's gart aperture 224 * @pages: number of pages to unbind 225 * 226 * Unbinds the requested pages from the gart page table and 227 * replaces them with the dummy page (all asics). 228 */ 229 void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, 230 int pages) 231 { 232 unsigned t; 233 unsigned p; 234 int i, j; 235 u64 page_base; 236 237 if (!rdev->gart.ready) { 238 WARN(1, "trying to unbind memory from uninitialized GART !\n"); 239 return; 240 } 241 t = offset / RADEON_GPU_PAGE_SIZE; 242 p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); 243 for (i = 0; i < pages; i++, p++) { 244 if (rdev->gart.pages[p]) { 245 rdev->gart.pages[p] = NULL; 246 rdev->gart.pages_addr[p] = rdev->dummy_page.addr; 247 page_base = rdev->gart.pages_addr[p]; 248 for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { 249 if (rdev->gart.ptr) { 250 radeon_gart_set_page(rdev, t, page_base, 251 RADEON_GART_PAGE_DUMMY); 252 } 253 page_base += RADEON_GPU_PAGE_SIZE; 254 } 255 } 256 } 257 mb(); 258 radeon_gart_tlb_flush(rdev); 259 } 260 261 /** 262 * radeon_gart_bind - bind pages into the gart page table 263 * 264 * @rdev: radeon_device pointer 265 * @offset: offset into the GPU's gart aperture 266 * @pages: number of pages to bind 267 * @pagelist: pages to bind 268 * @dma_addr: DMA addresses of pages 269 * @flags: RADEON_GART_PAGE_* flags 270 * 271 * Binds the requested pages to the gart page table 272 * (all asics). 273 * Returns 0 for success, -EINVAL for failure. 274 */ 275 int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, 276 int pages, struct page **pagelist, dma_addr_t *dma_addr, 277 uint32_t flags) 278 { 279 unsigned t; 280 unsigned p; 281 uint64_t page_base; 282 int i, j; 283 284 if (!rdev->gart.ready) { 285 WARN(1, "trying to bind memory to uninitialized GART !\n"); 286 return -EINVAL; 287 } 288 t = offset / RADEON_GPU_PAGE_SIZE; 289 p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); 290 291 for (i = 0; i < pages; i++, p++) { 292 rdev->gart.pages_addr[p] = dma_addr[i]; 293 rdev->gart.pages[p] = pagelist[i]; 294 if (rdev->gart.ptr) { 295 page_base = rdev->gart.pages_addr[p]; 296 for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { 297 radeon_gart_set_page(rdev, t, page_base, flags); 298 page_base += RADEON_GPU_PAGE_SIZE; 299 } 300 } 301 } 302 mb(); 303 radeon_gart_tlb_flush(rdev); 304 return 0; 305 } 306 307 /** 308 * radeon_gart_init - init the driver info for managing the gart 309 * 310 * @rdev: radeon_device pointer 311 * 312 * Allocate the dummy page and init the gart driver info (all asics). 313 * Returns 0 for success, error for failure. 314 */ 315 int radeon_gart_init(struct radeon_device *rdev) 316 { 317 int r, i; 318 319 if (rdev->gart.pages) { 320 return 0; 321 } 322 /* We need PAGE_SIZE >= RADEON_GPU_PAGE_SIZE */ 323 if (PAGE_SIZE < RADEON_GPU_PAGE_SIZE) { 324 DRM_ERROR("Page size is smaller than GPU page size!\n"); 325 return -EINVAL; 326 } 327 r = radeon_dummy_page_init(rdev); 328 if (r) 329 return r; 330 /* Compute table size */ 331 rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE; 332 rdev->gart.num_gpu_pages = rdev->mc.gtt_size / RADEON_GPU_PAGE_SIZE; 333 DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n", 334 rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages); 335 /* Allocate pages table */ 336 rdev->gart.pages = kmalloc(sizeof(void *) * rdev->gart.num_cpu_pages, 337 M_DRM, M_ZERO | M_WAITOK); 338 if (rdev->gart.pages == NULL) { 339 radeon_gart_fini(rdev); 340 return -ENOMEM; 341 } 342 rdev->gart.pages_addr = kmalloc(sizeof(dma_addr_t) * rdev->gart.num_cpu_pages, 343 M_DRM, M_ZERO | M_WAITOK); 344 if (rdev->gart.pages_addr == NULL) { 345 radeon_gart_fini(rdev); 346 return -ENOMEM; 347 } 348 /* set GART entry to point to the dummy page by default */ 349 for (i = 0; i < rdev->gart.num_cpu_pages; i++) { 350 rdev->gart.pages_addr[i] = rdev->dummy_page.addr; 351 } 352 return 0; 353 } 354 355 /** 356 * radeon_gart_fini - tear down the driver info for managing the gart 357 * 358 * @rdev: radeon_device pointer 359 * 360 * Tear down the gart driver info and free the dummy page (all asics). 361 */ 362 void radeon_gart_fini(struct radeon_device *rdev) 363 { 364 if (rdev->gart.pages && rdev->gart.pages_addr && rdev->gart.ready) { 365 /* unbind pages */ 366 radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages); 367 } 368 rdev->gart.ready = false; 369 kfree(rdev->gart.pages); 370 kfree(rdev->gart.pages_addr); 371 rdev->gart.pages = NULL; 372 rdev->gart.pages_addr = NULL; 373 374 radeon_dummy_page_fini(rdev); 375 } 376