Home | History | Annotate | Line # | Download | only in radeon
radeon_gart.c revision 1.1
      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 #include <drm/drmP.h>
     29 #include <drm/radeon_drm.h>
     30 #include "radeon.h"
     31 
     32 /*
     33  * GART
     34  * The GART (Graphics Aperture Remapping Table) is an aperture
     35  * in the GPU's address space.  System pages can be mapped into
     36  * the aperture and look like contiguous pages from the GPU's
     37  * perspective.  A page table maps the pages in the aperture
     38  * to the actual backing pages in system memory.
     39  *
     40  * Radeon GPUs support both an internal GART, as described above,
     41  * and AGP.  AGP works similarly, but the GART table is configured
     42  * and maintained by the northbridge rather than the driver.
     43  * Radeon hw has a separate AGP aperture that is programmed to
     44  * point to the AGP aperture provided by the northbridge and the
     45  * requests are passed through to the northbridge aperture.
     46  * Both AGP and internal GART can be used at the same time, however
     47  * that is not currently supported by the driver.
     48  *
     49  * This file handles the common internal GART management.
     50  */
     51 
     52 /*
     53  * Common GART table functions.
     54  */
     55 /**
     56  * radeon_gart_table_ram_alloc - allocate system ram for gart page table
     57  *
     58  * @rdev: radeon_device pointer
     59  *
     60  * Allocate system memory for GART page table
     61  * (r1xx-r3xx, non-pcie r4xx, rs400).  These asics require the
     62  * gart table to be in system memory.
     63  * Returns 0 for success, -ENOMEM for failure.
     64  */
     65 int radeon_gart_table_ram_alloc(struct radeon_device *rdev)
     66 {
     67 	void *ptr;
     68 
     69 	ptr = pci_alloc_consistent(rdev->pdev, rdev->gart.table_size,
     70 				   &rdev->gart.table_addr);
     71 	if (ptr == NULL) {
     72 		return -ENOMEM;
     73 	}
     74 #ifdef CONFIG_X86
     75 	if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 ||
     76 	    rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
     77 		set_memory_uc((unsigned long)ptr,
     78 			      rdev->gart.table_size >> PAGE_SHIFT);
     79 	}
     80 #endif
     81 	rdev->gart.ptr = ptr;
     82 	memset((void *)rdev->gart.ptr, 0, rdev->gart.table_size);
     83 	return 0;
     84 }
     85 
     86 /**
     87  * radeon_gart_table_ram_free - free system ram for gart page table
     88  *
     89  * @rdev: radeon_device pointer
     90  *
     91  * Free system memory for GART page table
     92  * (r1xx-r3xx, non-pcie r4xx, rs400).  These asics require the
     93  * gart table to be in system memory.
     94  */
     95 void radeon_gart_table_ram_free(struct radeon_device *rdev)
     96 {
     97 	if (rdev->gart.ptr == NULL) {
     98 		return;
     99 	}
    100 #ifdef CONFIG_X86
    101 	if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 ||
    102 	    rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
    103 		set_memory_wb((unsigned long)rdev->gart.ptr,
    104 			      rdev->gart.table_size >> PAGE_SHIFT);
    105 	}
    106 #endif
    107 	pci_free_consistent(rdev->pdev, rdev->gart.table_size,
    108 			    (void *)rdev->gart.ptr,
    109 			    rdev->gart.table_addr);
    110 	rdev->gart.ptr = NULL;
    111 	rdev->gart.table_addr = 0;
    112 }
    113 
    114 /**
    115  * radeon_gart_table_vram_alloc - allocate vram for gart page table
    116  *
    117  * @rdev: radeon_device pointer
    118  *
    119  * Allocate video memory for GART page table
    120  * (pcie r4xx, r5xx+).  These asics require the
    121  * gart table to be in video memory.
    122  * Returns 0 for success, error for failure.
    123  */
    124 int radeon_gart_table_vram_alloc(struct radeon_device *rdev)
    125 {
    126 	int r;
    127 
    128 	if (rdev->gart.robj == NULL) {
    129 		r = radeon_bo_create(rdev, rdev->gart.table_size,
    130 				     PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
    131 				     NULL, &rdev->gart.robj);
    132 		if (r) {
    133 			return r;
    134 		}
    135 	}
    136 	return 0;
    137 }
    138 
    139 /**
    140  * radeon_gart_table_vram_pin - pin gart page table in vram
    141  *
    142  * @rdev: radeon_device pointer
    143  *
    144  * Pin the GART page table in vram so it will not be moved
    145  * by the memory manager (pcie r4xx, r5xx+).  These asics require the
    146  * gart table to be in video memory.
    147  * Returns 0 for success, error for failure.
    148  */
    149 int radeon_gart_table_vram_pin(struct radeon_device *rdev)
    150 {
    151 	uint64_t gpu_addr;
    152 	int r;
    153 
    154 	r = radeon_bo_reserve(rdev->gart.robj, false);
    155 	if (unlikely(r != 0))
    156 		return r;
    157 	r = radeon_bo_pin(rdev->gart.robj,
    158 				RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
    159 	if (r) {
    160 		radeon_bo_unreserve(rdev->gart.robj);
    161 		return r;
    162 	}
    163 	r = radeon_bo_kmap(rdev->gart.robj, &rdev->gart.ptr);
    164 	if (r)
    165 		radeon_bo_unpin(rdev->gart.robj);
    166 	radeon_bo_unreserve(rdev->gart.robj);
    167 	rdev->gart.table_addr = gpu_addr;
    168 	return r;
    169 }
    170 
    171 /**
    172  * radeon_gart_table_vram_unpin - unpin gart page table in vram
    173  *
    174  * @rdev: radeon_device pointer
    175  *
    176  * Unpin the GART page table in vram (pcie r4xx, r5xx+).
    177  * These asics require the gart table to be in video memory.
    178  */
    179 void radeon_gart_table_vram_unpin(struct radeon_device *rdev)
    180 {
    181 	int r;
    182 
    183 	if (rdev->gart.robj == NULL) {
    184 		return;
    185 	}
    186 	r = radeon_bo_reserve(rdev->gart.robj, false);
    187 	if (likely(r == 0)) {
    188 		radeon_bo_kunmap(rdev->gart.robj);
    189 		radeon_bo_unpin(rdev->gart.robj);
    190 		radeon_bo_unreserve(rdev->gart.robj);
    191 		rdev->gart.ptr = NULL;
    192 	}
    193 }
    194 
    195 /**
    196  * radeon_gart_table_vram_free - free gart page table vram
    197  *
    198  * @rdev: radeon_device pointer
    199  *
    200  * Free the video memory used for the GART page table
    201  * (pcie r4xx, r5xx+).  These asics require the gart table to
    202  * be in video memory.
    203  */
    204 void radeon_gart_table_vram_free(struct radeon_device *rdev)
    205 {
    206 	if (rdev->gart.robj == NULL) {
    207 		return;
    208 	}
    209 	radeon_bo_unref(&rdev->gart.robj);
    210 }
    211 
    212 /*
    213  * Common gart functions.
    214  */
    215 /**
    216  * radeon_gart_unbind - unbind pages from the gart page table
    217  *
    218  * @rdev: radeon_device pointer
    219  * @offset: offset into the GPU's gart aperture
    220  * @pages: number of pages to unbind
    221  *
    222  * Unbinds the requested pages from the gart page table and
    223  * replaces them with the dummy page (all asics).
    224  */
    225 void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
    226 			int pages)
    227 {
    228 	unsigned t;
    229 	unsigned p;
    230 	int i, j;
    231 	u64 page_base;
    232 
    233 	if (!rdev->gart.ready) {
    234 		WARN(1, "trying to unbind memory from uninitialized GART !\n");
    235 		return;
    236 	}
    237 	t = offset / RADEON_GPU_PAGE_SIZE;
    238 	p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
    239 	for (i = 0; i < pages; i++, p++) {
    240 		if (rdev->gart.pages[p]) {
    241 			rdev->gart.pages[p] = NULL;
    242 			rdev->gart.pages_addr[p] = rdev->dummy_page.addr;
    243 			page_base = rdev->gart.pages_addr[p];
    244 			for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
    245 				if (rdev->gart.ptr) {
    246 					radeon_gart_set_page(rdev, t, page_base);
    247 				}
    248 				page_base += RADEON_GPU_PAGE_SIZE;
    249 			}
    250 		}
    251 	}
    252 	mb();
    253 	radeon_gart_tlb_flush(rdev);
    254 }
    255 
    256 /**
    257  * radeon_gart_bind - bind pages into the gart page table
    258  *
    259  * @rdev: radeon_device pointer
    260  * @offset: offset into the GPU's gart aperture
    261  * @pages: number of pages to bind
    262  * @pagelist: pages to bind
    263  * @dma_addr: DMA addresses of pages
    264  *
    265  * Binds the requested pages to the gart page table
    266  * (all asics).
    267  * Returns 0 for success, -EINVAL for failure.
    268  */
    269 int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
    270 		     int pages, struct page **pagelist, dma_addr_t *dma_addr)
    271 {
    272 	unsigned t;
    273 	unsigned p;
    274 	uint64_t page_base;
    275 	int i, j;
    276 
    277 	if (!rdev->gart.ready) {
    278 		WARN(1, "trying to bind memory to uninitialized GART !\n");
    279 		return -EINVAL;
    280 	}
    281 	t = offset / RADEON_GPU_PAGE_SIZE;
    282 	p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
    283 
    284 	for (i = 0; i < pages; i++, p++) {
    285 		rdev->gart.pages_addr[p] = dma_addr[i];
    286 		rdev->gart.pages[p] = pagelist[i];
    287 		if (rdev->gart.ptr) {
    288 			page_base = rdev->gart.pages_addr[p];
    289 			for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
    290 				radeon_gart_set_page(rdev, t, page_base);
    291 				page_base += RADEON_GPU_PAGE_SIZE;
    292 			}
    293 		}
    294 	}
    295 	mb();
    296 	radeon_gart_tlb_flush(rdev);
    297 	return 0;
    298 }
    299 
    300 /**
    301  * radeon_gart_restore - bind all pages in the gart page table
    302  *
    303  * @rdev: radeon_device pointer
    304  *
    305  * Binds all pages in the gart page table (all asics).
    306  * Used to rebuild the gart table on device startup or resume.
    307  */
    308 void radeon_gart_restore(struct radeon_device *rdev)
    309 {
    310 	int i, j, t;
    311 	u64 page_base;
    312 
    313 	if (!rdev->gart.ptr) {
    314 		return;
    315 	}
    316 	for (i = 0, t = 0; i < rdev->gart.num_cpu_pages; i++) {
    317 		page_base = rdev->gart.pages_addr[i];
    318 		for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
    319 			radeon_gart_set_page(rdev, t, page_base);
    320 			page_base += RADEON_GPU_PAGE_SIZE;
    321 		}
    322 	}
    323 	mb();
    324 	radeon_gart_tlb_flush(rdev);
    325 }
    326 
    327 /**
    328  * radeon_gart_init - init the driver info for managing the gart
    329  *
    330  * @rdev: radeon_device pointer
    331  *
    332  * Allocate the dummy page and init the gart driver info (all asics).
    333  * Returns 0 for success, error for failure.
    334  */
    335 int radeon_gart_init(struct radeon_device *rdev)
    336 {
    337 	int r, i;
    338 
    339 	if (rdev->gart.pages) {
    340 		return 0;
    341 	}
    342 	/* We need PAGE_SIZE >= RADEON_GPU_PAGE_SIZE */
    343 	if (PAGE_SIZE < RADEON_GPU_PAGE_SIZE) {
    344 		DRM_ERROR("Page size is smaller than GPU page size!\n");
    345 		return -EINVAL;
    346 	}
    347 	r = radeon_dummy_page_init(rdev);
    348 	if (r)
    349 		return r;
    350 	/* Compute table size */
    351 	rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE;
    352 	rdev->gart.num_gpu_pages = rdev->mc.gtt_size / RADEON_GPU_PAGE_SIZE;
    353 	DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n",
    354 		 rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages);
    355 	/* Allocate pages table */
    356 	rdev->gart.pages = vzalloc(sizeof(void *) * rdev->gart.num_cpu_pages);
    357 	if (rdev->gart.pages == NULL) {
    358 		radeon_gart_fini(rdev);
    359 		return -ENOMEM;
    360 	}
    361 	rdev->gart.pages_addr = vzalloc(sizeof(dma_addr_t) *
    362 					rdev->gart.num_cpu_pages);
    363 	if (rdev->gart.pages_addr == NULL) {
    364 		radeon_gart_fini(rdev);
    365 		return -ENOMEM;
    366 	}
    367 	/* set GART entry to point to the dummy page by default */
    368 	for (i = 0; i < rdev->gart.num_cpu_pages; i++) {
    369 		rdev->gart.pages_addr[i] = rdev->dummy_page.addr;
    370 	}
    371 	return 0;
    372 }
    373 
    374 /**
    375  * radeon_gart_fini - tear down the driver info for managing the gart
    376  *
    377  * @rdev: radeon_device pointer
    378  *
    379  * Tear down the gart driver info and free the dummy page (all asics).
    380  */
    381 void radeon_gart_fini(struct radeon_device *rdev)
    382 {
    383 	if (rdev->gart.pages && rdev->gart.pages_addr && rdev->gart.ready) {
    384 		/* unbind pages */
    385 		radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages);
    386 	}
    387 	rdev->gart.ready = false;
    388 	vfree(rdev->gart.pages);
    389 	vfree(rdev->gart.pages_addr);
    390 	rdev->gart.pages = NULL;
    391 	rdev->gart.pages_addr = NULL;
    392 
    393 	radeon_dummy_page_fini(rdev);
    394 }
    395