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

amdgpu_gtt_mgr.c (7967B)


      1/*
      2 * Copyright 2016 Advanced Micro Devices, Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 * Authors: Christian König
     23 */
     24
     25#include <drm/ttm/ttm_range_manager.h>
     26
     27#include "amdgpu.h"
     28
     29static inline struct amdgpu_gtt_mgr *
     30to_gtt_mgr(struct ttm_resource_manager *man)
     31{
     32	return container_of(man, struct amdgpu_gtt_mgr, manager);
     33}
     34
     35/**
     36 * DOC: mem_info_gtt_total
     37 *
     38 * The amdgpu driver provides a sysfs API for reporting current total size of
     39 * the GTT.
     40 * The file mem_info_gtt_total is used for this, and returns the total size of
     41 * the GTT block, in bytes
     42 */
     43static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev,
     44					      struct device_attribute *attr,
     45					      char *buf)
     46{
     47	struct drm_device *ddev = dev_get_drvdata(dev);
     48	struct amdgpu_device *adev = drm_to_adev(ddev);
     49	struct ttm_resource_manager *man;
     50
     51	man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
     52	return sysfs_emit(buf, "%llu\n", man->size);
     53}
     54
     55/**
     56 * DOC: mem_info_gtt_used
     57 *
     58 * The amdgpu driver provides a sysfs API for reporting current total amount of
     59 * used GTT.
     60 * The file mem_info_gtt_used is used for this, and returns the current used
     61 * size of the GTT block, in bytes
     62 */
     63static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev,
     64					     struct device_attribute *attr,
     65					     char *buf)
     66{
     67	struct drm_device *ddev = dev_get_drvdata(dev);
     68	struct amdgpu_device *adev = drm_to_adev(ddev);
     69	struct ttm_resource_manager *man = &adev->mman.gtt_mgr.manager;
     70
     71	return sysfs_emit(buf, "%llu\n", ttm_resource_manager_usage(man));
     72}
     73
     74static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO,
     75	           amdgpu_mem_info_gtt_total_show, NULL);
     76static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO,
     77	           amdgpu_mem_info_gtt_used_show, NULL);
     78
     79static struct attribute *amdgpu_gtt_mgr_attributes[] = {
     80	&dev_attr_mem_info_gtt_total.attr,
     81	&dev_attr_mem_info_gtt_used.attr,
     82	NULL
     83};
     84
     85const struct attribute_group amdgpu_gtt_mgr_attr_group = {
     86	.attrs = amdgpu_gtt_mgr_attributes
     87};
     88
     89/**
     90 * amdgpu_gtt_mgr_has_gart_addr - Check if mem has address space
     91 *
     92 * @res: the mem object to check
     93 *
     94 * Check if a mem object has already address space allocated.
     95 */
     96bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *res)
     97{
     98	struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
     99
    100	return drm_mm_node_allocated(&node->mm_nodes[0]);
    101}
    102
    103/**
    104 * amdgpu_gtt_mgr_new - allocate a new node
    105 *
    106 * @man: TTM memory type manager
    107 * @tbo: TTM BO we need this range for
    108 * @place: placement flags and restrictions
    109 * @res: the resulting mem object
    110 *
    111 * Dummy, allocate the node but no space for it yet.
    112 */
    113static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
    114			      struct ttm_buffer_object *tbo,
    115			      const struct ttm_place *place,
    116			      struct ttm_resource **res)
    117{
    118	struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
    119	uint32_t num_pages = PFN_UP(tbo->base.size);
    120	struct ttm_range_mgr_node *node;
    121	int r;
    122
    123	node = kzalloc(struct_size(node, mm_nodes, 1), GFP_KERNEL);
    124	if (!node)
    125		return -ENOMEM;
    126
    127	ttm_resource_init(tbo, place, &node->base);
    128	if (!(place->flags & TTM_PL_FLAG_TEMPORARY) &&
    129	    ttm_resource_manager_usage(man) > man->size) {
    130		r = -ENOSPC;
    131		goto err_free;
    132	}
    133
    134	if (place->lpfn) {
    135		spin_lock(&mgr->lock);
    136		r = drm_mm_insert_node_in_range(&mgr->mm, &node->mm_nodes[0],
    137						num_pages, tbo->page_alignment,
    138						0, place->fpfn, place->lpfn,
    139						DRM_MM_INSERT_BEST);
    140		spin_unlock(&mgr->lock);
    141		if (unlikely(r))
    142			goto err_free;
    143
    144		node->base.start = node->mm_nodes[0].start;
    145	} else {
    146		node->mm_nodes[0].start = 0;
    147		node->mm_nodes[0].size = node->base.num_pages;
    148		node->base.start = AMDGPU_BO_INVALID_OFFSET;
    149	}
    150
    151	*res = &node->base;
    152	return 0;
    153
    154err_free:
    155	ttm_resource_fini(man, &node->base);
    156	kfree(node);
    157	return r;
    158}
    159
    160/**
    161 * amdgpu_gtt_mgr_del - free ranges
    162 *
    163 * @man: TTM memory type manager
    164 * @res: TTM memory object
    165 *
    166 * Free the allocated GTT again.
    167 */
    168static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man,
    169			       struct ttm_resource *res)
    170{
    171	struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
    172	struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
    173
    174	spin_lock(&mgr->lock);
    175	if (drm_mm_node_allocated(&node->mm_nodes[0]))
    176		drm_mm_remove_node(&node->mm_nodes[0]);
    177	spin_unlock(&mgr->lock);
    178
    179	ttm_resource_fini(man, res);
    180	kfree(node);
    181}
    182
    183/**
    184 * amdgpu_gtt_mgr_recover - re-init gart
    185 *
    186 * @mgr: amdgpu_gtt_mgr pointer
    187 *
    188 * Re-init the gart for each known BO in the GTT.
    189 */
    190void amdgpu_gtt_mgr_recover(struct amdgpu_gtt_mgr *mgr)
    191{
    192	struct ttm_range_mgr_node *node;
    193	struct drm_mm_node *mm_node;
    194	struct amdgpu_device *adev;
    195
    196	adev = container_of(mgr, typeof(*adev), mman.gtt_mgr);
    197	spin_lock(&mgr->lock);
    198	drm_mm_for_each_node(mm_node, &mgr->mm) {
    199		node = container_of(mm_node, typeof(*node), mm_nodes[0]);
    200		amdgpu_ttm_recover_gart(node->base.bo);
    201	}
    202	spin_unlock(&mgr->lock);
    203
    204	amdgpu_gart_invalidate_tlb(adev);
    205}
    206
    207/**
    208 * amdgpu_gtt_mgr_debug - dump VRAM table
    209 *
    210 * @man: TTM memory type manager
    211 * @printer: DRM printer to use
    212 *
    213 * Dump the table content using printk.
    214 */
    215static void amdgpu_gtt_mgr_debug(struct ttm_resource_manager *man,
    216				 struct drm_printer *printer)
    217{
    218	struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
    219
    220	spin_lock(&mgr->lock);
    221	drm_mm_print(&mgr->mm, printer);
    222	spin_unlock(&mgr->lock);
    223}
    224
    225static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = {
    226	.alloc = amdgpu_gtt_mgr_new,
    227	.free = amdgpu_gtt_mgr_del,
    228	.debug = amdgpu_gtt_mgr_debug
    229};
    230
    231/**
    232 * amdgpu_gtt_mgr_init - init GTT manager and DRM MM
    233 *
    234 * @adev: amdgpu_device pointer
    235 * @gtt_size: maximum size of GTT
    236 *
    237 * Allocate and initialize the GTT manager.
    238 */
    239int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size)
    240{
    241	struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;
    242	struct ttm_resource_manager *man = &mgr->manager;
    243	uint64_t start, size;
    244
    245	man->use_tt = true;
    246	man->func = &amdgpu_gtt_mgr_func;
    247
    248	ttm_resource_manager_init(man, &adev->mman.bdev, gtt_size);
    249
    250	start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS;
    251	size = (adev->gmc.gart_size >> PAGE_SHIFT) - start;
    252	drm_mm_init(&mgr->mm, start, size);
    253	spin_lock_init(&mgr->lock);
    254
    255	ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, &mgr->manager);
    256	ttm_resource_manager_set_used(man, true);
    257	return 0;
    258}
    259
    260/**
    261 * amdgpu_gtt_mgr_fini - free and destroy GTT manager
    262 *
    263 * @adev: amdgpu_device pointer
    264 *
    265 * Destroy and free the GTT manager, returns -EBUSY if ranges are still
    266 * allocated inside it.
    267 */
    268void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev)
    269{
    270	struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;
    271	struct ttm_resource_manager *man = &mgr->manager;
    272	int ret;
    273
    274	ttm_resource_manager_set_used(man, false);
    275
    276	ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
    277	if (ret)
    278		return;
    279
    280	spin_lock(&mgr->lock);
    281	drm_mm_takedown(&mgr->mm);
    282	spin_unlock(&mgr->lock);
    283
    284	ttm_resource_manager_cleanup(man);
    285	ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, NULL);
    286}