cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

radeon_gart.c (10863B)


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