linux/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR MIT
   2/*
   3 * Copyright 2016-2021 Advanced Micro Devices, Inc.
   4 *
   5 * Permission is hereby granted, free of charge, to any person obtaining a
   6 * copy of this software and associated documentation files (the "Software"),
   7 * to deal in the Software without restriction, including without limitation
   8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   9 * and/or sell copies of the Software, and to permit persons to whom the
  10 * Software is furnished to do so, subject to the following conditions:
  11 *
  12 * The above copyright notice and this permission notice shall be included in
  13 * all copies or substantial portions of the Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  21 * OTHER DEALINGS IN THE SOFTWARE.
  22 *
  23 * Authors: Christian König, Felix Kuehling
  24 */
  25
  26#include "amdgpu.h"
  27
  28static inline struct amdgpu_preempt_mgr *
  29to_preempt_mgr(struct ttm_resource_manager *man)
  30{
  31        return container_of(man, struct amdgpu_preempt_mgr, manager);
  32}
  33
  34/**
  35 * DOC: mem_info_preempt_used
  36 *
  37 * The amdgpu driver provides a sysfs API for reporting current total amount of
  38 * used preemptible memory.
  39 * The file mem_info_preempt_used is used for this, and returns the current
  40 * used size of the preemptible block, in bytes
  41 */
  42static ssize_t mem_info_preempt_used_show(struct device *dev,
  43                                          struct device_attribute *attr,
  44                                          char *buf)
  45{
  46        struct drm_device *ddev = dev_get_drvdata(dev);
  47        struct amdgpu_device *adev = drm_to_adev(ddev);
  48        struct ttm_resource_manager *man;
  49
  50        man = ttm_manager_type(&adev->mman.bdev, AMDGPU_PL_PREEMPT);
  51        return sysfs_emit(buf, "%llu\n", amdgpu_preempt_mgr_usage(man));
  52}
  53
  54static DEVICE_ATTR_RO(mem_info_preempt_used);
  55
  56/**
  57 * amdgpu_preempt_mgr_new - allocate a new node
  58 *
  59 * @man: TTM memory type manager
  60 * @tbo: TTM BO we need this range for
  61 * @place: placement flags and restrictions
  62 * @mem: the resulting mem object
  63 *
  64 * Dummy, just count the space used without allocating resources or any limit.
  65 */
  66static int amdgpu_preempt_mgr_new(struct ttm_resource_manager *man,
  67                                  struct ttm_buffer_object *tbo,
  68                                  const struct ttm_place *place,
  69                                  struct ttm_resource **res)
  70{
  71        struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man);
  72
  73        *res = kzalloc(sizeof(**res), GFP_KERNEL);
  74        if (!*res)
  75                return -ENOMEM;
  76
  77        ttm_resource_init(tbo, place, *res);
  78        (*res)->start = AMDGPU_BO_INVALID_OFFSET;
  79
  80        atomic64_add((*res)->num_pages, &mgr->used);
  81        return 0;
  82}
  83
  84/**
  85 * amdgpu_preempt_mgr_del - free ranges
  86 *
  87 * @man: TTM memory type manager
  88 * @mem: TTM memory object
  89 *
  90 * Free the allocated GTT again.
  91 */
  92static void amdgpu_preempt_mgr_del(struct ttm_resource_manager *man,
  93                                   struct ttm_resource *res)
  94{
  95        struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man);
  96
  97        atomic64_sub(res->num_pages, &mgr->used);
  98        kfree(res);
  99}
 100
 101/**
 102 * amdgpu_preempt_mgr_usage - return usage of PREEMPT domain
 103 *
 104 * @man: TTM memory type manager
 105 *
 106 * Return how many bytes are used in the GTT domain
 107 */
 108uint64_t amdgpu_preempt_mgr_usage(struct ttm_resource_manager *man)
 109{
 110        struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man);
 111        s64 result = atomic64_read(&mgr->used);
 112
 113        return (result > 0 ? result : 0) * PAGE_SIZE;
 114}
 115
 116/**
 117 * amdgpu_preempt_mgr_debug - dump VRAM table
 118 *
 119 * @man: TTM memory type manager
 120 * @printer: DRM printer to use
 121 *
 122 * Dump the table content using printk.
 123 */
 124static void amdgpu_preempt_mgr_debug(struct ttm_resource_manager *man,
 125                                     struct drm_printer *printer)
 126{
 127        struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man);
 128
 129        drm_printf(printer, "man size:%llu pages, preempt used:%lld pages\n",
 130                   man->size, (u64)atomic64_read(&mgr->used));
 131}
 132
 133static const struct ttm_resource_manager_func amdgpu_preempt_mgr_func = {
 134        .alloc = amdgpu_preempt_mgr_new,
 135        .free = amdgpu_preempt_mgr_del,
 136        .debug = amdgpu_preempt_mgr_debug
 137};
 138
 139/**
 140 * amdgpu_preempt_mgr_init - init PREEMPT manager and DRM MM
 141 *
 142 * @adev: amdgpu_device pointer
 143 *
 144 * Allocate and initialize the GTT manager.
 145 */
 146int amdgpu_preempt_mgr_init(struct amdgpu_device *adev)
 147{
 148        struct amdgpu_preempt_mgr *mgr = &adev->mman.preempt_mgr;
 149        struct ttm_resource_manager *man = &mgr->manager;
 150        int ret;
 151
 152        man->use_tt = true;
 153        man->func = &amdgpu_preempt_mgr_func;
 154
 155        ttm_resource_manager_init(man, (1 << 30));
 156
 157        atomic64_set(&mgr->used, 0);
 158
 159        ret = device_create_file(adev->dev, &dev_attr_mem_info_preempt_used);
 160        if (ret) {
 161                DRM_ERROR("Failed to create device file mem_info_preempt_used\n");
 162                return ret;
 163        }
 164
 165        ttm_set_driver_manager(&adev->mman.bdev, AMDGPU_PL_PREEMPT,
 166                               &mgr->manager);
 167        ttm_resource_manager_set_used(man, true);
 168        return 0;
 169}
 170
 171/**
 172 * amdgpu_preempt_mgr_fini - free and destroy GTT manager
 173 *
 174 * @adev: amdgpu_device pointer
 175 *
 176 * Destroy and free the GTT manager, returns -EBUSY if ranges are still
 177 * allocated inside it.
 178 */
 179void amdgpu_preempt_mgr_fini(struct amdgpu_device *adev)
 180{
 181        struct amdgpu_preempt_mgr *mgr = &adev->mman.preempt_mgr;
 182        struct ttm_resource_manager *man = &mgr->manager;
 183        int ret;
 184
 185        ttm_resource_manager_set_used(man, false);
 186
 187        ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
 188        if (ret)
 189                return;
 190
 191        device_remove_file(adev->dev, &dev_attr_mem_info_preempt_used);
 192
 193        ttm_resource_manager_cleanup(man);
 194        ttm_set_driver_manager(&adev->mman.bdev, AMDGPU_PL_PREEMPT, NULL);
 195}
 196