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

ati_pcigart.c (6208B)


      1/*
      2 * \file ati_pcigart.c
      3 * ATI PCI GART support
      4 *
      5 * \author Gareth Hughes <gareth@valinux.com>
      6 */
      7
      8/*
      9 * Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com
     10 *
     11 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
     12 * All Rights Reserved.
     13 *
     14 * Permission is hereby granted, free of charge, to any person obtaining a
     15 * copy of this software and associated documentation files (the "Software"),
     16 * to deal in the Software without restriction, including without limitation
     17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     18 * and/or sell copies of the Software, and to permit persons to whom the
     19 * Software is furnished to do so, subject to the following conditions:
     20 *
     21 * The above copyright notice and this permission notice (including the next
     22 * paragraph) shall be included in all copies or substantial portions of the
     23 * Software.
     24 *
     25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     28 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     29 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     30 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     31 * DEALINGS IN THE SOFTWARE.
     32 */
     33
     34#include <linux/export.h>
     35#include <linux/pci.h>
     36
     37#include <drm/drm_device.h>
     38#include <drm/drm_legacy.h>
     39#include <drm/drm_print.h>
     40
     41#include "ati_pcigart.h"
     42
     43# define ATI_PCIGART_PAGE_SIZE		4096	/**< PCI GART page size */
     44
     45static int drm_ati_alloc_pcigart_table(struct drm_device *dev,
     46				       struct drm_ati_pcigart_info *gart_info)
     47{
     48	drm_dma_handle_t *dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL);
     49
     50	if (!dmah)
     51		return -ENOMEM;
     52
     53	dmah->size = gart_info->table_size;
     54	dmah->vaddr = dma_alloc_coherent(dev->dev,
     55					 dmah->size,
     56					 &dmah->busaddr,
     57					 GFP_KERNEL);
     58
     59	if (!dmah->vaddr) {
     60		kfree(dmah);
     61		return -ENOMEM;
     62	}
     63
     64	gart_info->table_handle = dmah;
     65	return 0;
     66}
     67
     68static void drm_ati_free_pcigart_table(struct drm_device *dev,
     69				       struct drm_ati_pcigart_info *gart_info)
     70{
     71	drm_dma_handle_t *dmah = gart_info->table_handle;
     72
     73	dma_free_coherent(dev->dev, dmah->size, dmah->vaddr, dmah->busaddr);
     74	kfree(dmah);
     75
     76	gart_info->table_handle = NULL;
     77}
     78
     79int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
     80{
     81	struct drm_sg_mem *entry = dev->sg;
     82	struct pci_dev *pdev = to_pci_dev(dev->dev);
     83	unsigned long pages;
     84	int i;
     85	int max_pages;
     86
     87	/* we need to support large memory configurations */
     88	if (!entry) {
     89		DRM_ERROR("no scatter/gather memory!\n");
     90		return 0;
     91	}
     92
     93	if (gart_info->bus_addr) {
     94
     95		max_pages = (gart_info->table_size / sizeof(u32));
     96		pages = (entry->pages <= max_pages)
     97		  ? entry->pages : max_pages;
     98
     99		for (i = 0; i < pages; i++) {
    100			if (!entry->busaddr[i])
    101				break;
    102			dma_unmap_page(&pdev->dev, entry->busaddr[i],
    103				       PAGE_SIZE, DMA_BIDIRECTIONAL);
    104		}
    105
    106		if (gart_info->gart_table_location == DRM_ATI_GART_MAIN)
    107			gart_info->bus_addr = 0;
    108	}
    109
    110	if (gart_info->gart_table_location == DRM_ATI_GART_MAIN &&
    111	    gart_info->table_handle) {
    112		drm_ati_free_pcigart_table(dev, gart_info);
    113	}
    114
    115	return 1;
    116}
    117
    118int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
    119{
    120	struct drm_local_map *map = &gart_info->mapping;
    121	struct drm_sg_mem *entry = dev->sg;
    122	struct pci_dev *pdev = to_pci_dev(dev->dev);
    123	void *address = NULL;
    124	unsigned long pages;
    125	u32 *pci_gart = NULL, page_base, gart_idx;
    126	dma_addr_t bus_address = 0;
    127	int i, j, ret = -ENOMEM;
    128	int max_ati_pages, max_real_pages;
    129
    130	if (!entry) {
    131		DRM_ERROR("no scatter/gather memory!\n");
    132		goto done;
    133	}
    134
    135	if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
    136		DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
    137
    138		if (dma_set_mask(&pdev->dev, gart_info->table_mask)) {
    139			DRM_ERROR("fail to set dma mask to 0x%Lx\n",
    140				  (unsigned long long)gart_info->table_mask);
    141			ret = -EFAULT;
    142			goto done;
    143		}
    144
    145		ret = drm_ati_alloc_pcigart_table(dev, gart_info);
    146		if (ret) {
    147			DRM_ERROR("cannot allocate PCI GART page!\n");
    148			goto done;
    149		}
    150
    151		pci_gart = gart_info->table_handle->vaddr;
    152		address = gart_info->table_handle->vaddr;
    153		bus_address = gart_info->table_handle->busaddr;
    154	} else {
    155		address = gart_info->addr;
    156		bus_address = gart_info->bus_addr;
    157		DRM_DEBUG("PCI: Gart Table: VRAM %08LX mapped at %08lX\n",
    158			  (unsigned long long)bus_address,
    159			  (unsigned long)address);
    160	}
    161
    162
    163	max_ati_pages = (gart_info->table_size / sizeof(u32));
    164	max_real_pages = max_ati_pages / (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE);
    165	pages = (entry->pages <= max_real_pages)
    166	    ? entry->pages : max_real_pages;
    167
    168	if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
    169		memset(pci_gart, 0, max_ati_pages * sizeof(u32));
    170	} else {
    171		memset_io((void __iomem *)map->handle, 0, max_ati_pages * sizeof(u32));
    172	}
    173
    174	gart_idx = 0;
    175	for (i = 0; i < pages; i++) {
    176		/* we need to support large memory configurations */
    177		entry->busaddr[i] = dma_map_page(&pdev->dev, entry->pagelist[i],
    178						 0, PAGE_SIZE, DMA_BIDIRECTIONAL);
    179		if (dma_mapping_error(&pdev->dev, entry->busaddr[i])) {
    180			DRM_ERROR("unable to map PCIGART pages!\n");
    181			drm_ati_pcigart_cleanup(dev, gart_info);
    182			address = NULL;
    183			bus_address = 0;
    184			ret = -ENOMEM;
    185			goto done;
    186		}
    187		page_base = (u32) entry->busaddr[i];
    188
    189		for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
    190			u32 offset;
    191			u32 val;
    192
    193			switch(gart_info->gart_reg_if) {
    194			case DRM_ATI_GART_IGP:
    195				val = page_base | 0xc;
    196				break;
    197			case DRM_ATI_GART_PCIE:
    198				val = (page_base >> 8) | 0xc;
    199				break;
    200			default:
    201			case DRM_ATI_GART_PCI:
    202				val = page_base;
    203				break;
    204			}
    205			if (gart_info->gart_table_location ==
    206			    DRM_ATI_GART_MAIN) {
    207				pci_gart[gart_idx] = cpu_to_le32(val);
    208			} else {
    209				offset = gart_idx * sizeof(u32);
    210				writel(val, (void __iomem *)map->handle + offset);
    211			}
    212			gart_idx++;
    213			page_base += ATI_PCIGART_PAGE_SIZE;
    214		}
    215	}
    216	ret = 0;
    217
    218#ifdef CONFIG_X86
    219	wbinvd();
    220#else
    221	mb();
    222#endif
    223
    224      done:
    225	gart_info->addr = address;
    226	gart_info->bus_addr = bus_address;
    227	return ret;
    228}