linux/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
<<
>>
Prefs
   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/drmP.h>
  26#include "amdgpu.h"
  27
  28struct amdgpu_vram_mgr {
  29        struct drm_mm mm;
  30        spinlock_t lock;
  31        atomic64_t usage;
  32        atomic64_t vis_usage;
  33};
  34
  35/**
  36 * DOC: mem_info_vram_total
  37 *
  38 * The amdgpu driver provides a sysfs API for reporting current total VRAM
  39 * available on the device
  40 * The file mem_info_vram_total is used for this and returns the total
  41 * amount of VRAM in bytes
  42 */
  43static ssize_t amdgpu_mem_info_vram_total_show(struct device *dev,
  44                struct device_attribute *attr, char *buf)
  45{
  46        struct drm_device *ddev = dev_get_drvdata(dev);
  47        struct amdgpu_device *adev = ddev->dev_private;
  48
  49        return snprintf(buf, PAGE_SIZE, "%llu\n", adev->gmc.real_vram_size);
  50}
  51
  52/**
  53 * DOC: mem_info_vis_vram_total
  54 *
  55 * The amdgpu driver provides a sysfs API for reporting current total
  56 * visible VRAM available on the device
  57 * The file mem_info_vis_vram_total is used for this and returns the total
  58 * amount of visible VRAM in bytes
  59 */
  60static ssize_t amdgpu_mem_info_vis_vram_total_show(struct device *dev,
  61                struct device_attribute *attr, char *buf)
  62{
  63        struct drm_device *ddev = dev_get_drvdata(dev);
  64        struct amdgpu_device *adev = ddev->dev_private;
  65
  66        return snprintf(buf, PAGE_SIZE, "%llu\n", adev->gmc.visible_vram_size);
  67}
  68
  69/**
  70 * DOC: mem_info_vram_used
  71 *
  72 * The amdgpu driver provides a sysfs API for reporting current total VRAM
  73 * available on the device
  74 * The file mem_info_vram_used is used for this and returns the total
  75 * amount of currently used VRAM in bytes
  76 */
  77static ssize_t amdgpu_mem_info_vram_used_show(struct device *dev,
  78                struct device_attribute *attr, char *buf)
  79{
  80        struct drm_device *ddev = dev_get_drvdata(dev);
  81        struct amdgpu_device *adev = ddev->dev_private;
  82
  83        return snprintf(buf, PAGE_SIZE, "%llu\n",
  84                amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]));
  85}
  86
  87/**
  88 * DOC: mem_info_vis_vram_used
  89 *
  90 * The amdgpu driver provides a sysfs API for reporting current total of
  91 * used visible VRAM
  92 * The file mem_info_vis_vram_used is used for this and returns the total
  93 * amount of currently used visible VRAM in bytes
  94 */
  95static ssize_t amdgpu_mem_info_vis_vram_used_show(struct device *dev,
  96                struct device_attribute *attr, char *buf)
  97{
  98        struct drm_device *ddev = dev_get_drvdata(dev);
  99        struct amdgpu_device *adev = ddev->dev_private;
 100
 101        return snprintf(buf, PAGE_SIZE, "%llu\n",
 102                amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]));
 103}
 104
 105static DEVICE_ATTR(mem_info_vram_total, S_IRUGO,
 106                   amdgpu_mem_info_vram_total_show, NULL);
 107static DEVICE_ATTR(mem_info_vis_vram_total, S_IRUGO,
 108                   amdgpu_mem_info_vis_vram_total_show,NULL);
 109static DEVICE_ATTR(mem_info_vram_used, S_IRUGO,
 110                   amdgpu_mem_info_vram_used_show, NULL);
 111static DEVICE_ATTR(mem_info_vis_vram_used, S_IRUGO,
 112                   amdgpu_mem_info_vis_vram_used_show, NULL);
 113
 114/**
 115 * amdgpu_vram_mgr_init - init VRAM manager and DRM MM
 116 *
 117 * @man: TTM memory type manager
 118 * @p_size: maximum size of VRAM
 119 *
 120 * Allocate and initialize the VRAM manager.
 121 */
 122static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man,
 123                                unsigned long p_size)
 124{
 125        struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
 126        struct amdgpu_vram_mgr *mgr;
 127        int ret;
 128
 129        mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
 130        if (!mgr)
 131                return -ENOMEM;
 132
 133        drm_mm_init(&mgr->mm, 0, p_size);
 134        spin_lock_init(&mgr->lock);
 135        man->priv = mgr;
 136
 137        /* Add the two VRAM-related sysfs files */
 138        ret = device_create_file(adev->dev, &dev_attr_mem_info_vram_total);
 139        if (ret) {
 140                DRM_ERROR("Failed to create device file mem_info_vram_total\n");
 141                return ret;
 142        }
 143        ret = device_create_file(adev->dev, &dev_attr_mem_info_vis_vram_total);
 144        if (ret) {
 145                DRM_ERROR("Failed to create device file mem_info_vis_vram_total\n");
 146                return ret;
 147        }
 148        ret = device_create_file(adev->dev, &dev_attr_mem_info_vram_used);
 149        if (ret) {
 150                DRM_ERROR("Failed to create device file mem_info_vram_used\n");
 151                return ret;
 152        }
 153        ret = device_create_file(adev->dev, &dev_attr_mem_info_vis_vram_used);
 154        if (ret) {
 155                DRM_ERROR("Failed to create device file mem_info_vis_vram_used\n");
 156                return ret;
 157        }
 158
 159        return 0;
 160}
 161
 162/**
 163 * amdgpu_vram_mgr_fini - free and destroy VRAM manager
 164 *
 165 * @man: TTM memory type manager
 166 *
 167 * Destroy and free the VRAM manager, returns -EBUSY if ranges are still
 168 * allocated inside it.
 169 */
 170static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man)
 171{
 172        struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
 173        struct amdgpu_vram_mgr *mgr = man->priv;
 174
 175        spin_lock(&mgr->lock);
 176        drm_mm_takedown(&mgr->mm);
 177        spin_unlock(&mgr->lock);
 178        kfree(mgr);
 179        man->priv = NULL;
 180        device_remove_file(adev->dev, &dev_attr_mem_info_vram_total);
 181        device_remove_file(adev->dev, &dev_attr_mem_info_vis_vram_total);
 182        device_remove_file(adev->dev, &dev_attr_mem_info_vram_used);
 183        device_remove_file(adev->dev, &dev_attr_mem_info_vis_vram_used);
 184        return 0;
 185}
 186
 187/**
 188 * amdgpu_vram_mgr_vis_size - Calculate visible node size
 189 *
 190 * @adev: amdgpu device structure
 191 * @node: MM node structure
 192 *
 193 * Calculate how many bytes of the MM node are inside visible VRAM
 194 */
 195static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
 196                                    struct drm_mm_node *node)
 197{
 198        uint64_t start = node->start << PAGE_SHIFT;
 199        uint64_t end = (node->size + node->start) << PAGE_SHIFT;
 200
 201        if (start >= adev->gmc.visible_vram_size)
 202                return 0;
 203
 204        return (end > adev->gmc.visible_vram_size ?
 205                adev->gmc.visible_vram_size : end) - start;
 206}
 207
 208/**
 209 * amdgpu_vram_mgr_bo_visible_size - CPU visible BO size
 210 *
 211 * @bo: &amdgpu_bo buffer object (must be in VRAM)
 212 *
 213 * Returns:
 214 * How much of the given &amdgpu_bo buffer object lies in CPU visible VRAM.
 215 */
 216u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
 217{
 218        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
 219        struct ttm_mem_reg *mem = &bo->tbo.mem;
 220        struct drm_mm_node *nodes = mem->mm_node;
 221        unsigned pages = mem->num_pages;
 222        u64 usage;
 223
 224        if (amdgpu_gmc_vram_full_visible(&adev->gmc))
 225                return amdgpu_bo_size(bo);
 226
 227        if (mem->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT)
 228                return 0;
 229
 230        for (usage = 0; nodes && pages; pages -= nodes->size, nodes++)
 231                usage += amdgpu_vram_mgr_vis_size(adev, nodes);
 232
 233        return usage;
 234}
 235
 236/**
 237 * amdgpu_vram_mgr_virt_start - update virtual start address
 238 *
 239 * @mem: ttm_mem_reg to update
 240 * @node: just allocated node
 241 *
 242 * Calculate a virtual BO start address to easily check if everything is CPU
 243 * accessible.
 244 */
 245static void amdgpu_vram_mgr_virt_start(struct ttm_mem_reg *mem,
 246                                       struct drm_mm_node *node)
 247{
 248        unsigned long start;
 249
 250        start = node->start + node->size;
 251        if (start > mem->num_pages)
 252                start -= mem->num_pages;
 253        else
 254                start = 0;
 255        mem->start = max(mem->start, start);
 256}
 257
 258/**
 259 * amdgpu_vram_mgr_new - allocate new ranges
 260 *
 261 * @man: TTM memory type manager
 262 * @tbo: TTM BO we need this range for
 263 * @place: placement flags and restrictions
 264 * @mem: the resulting mem object
 265 *
 266 * Allocate VRAM for the given BO.
 267 */
 268static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man,
 269                               struct ttm_buffer_object *tbo,
 270                               const struct ttm_place *place,
 271                               struct ttm_mem_reg *mem)
 272{
 273        struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
 274        struct amdgpu_vram_mgr *mgr = man->priv;
 275        struct drm_mm *mm = &mgr->mm;
 276        struct drm_mm_node *nodes;
 277        enum drm_mm_insert_mode mode;
 278        unsigned long lpfn, num_nodes, pages_per_node, pages_left;
 279        uint64_t usage = 0, vis_usage = 0;
 280        unsigned i;
 281        int r;
 282
 283        lpfn = place->lpfn;
 284        if (!lpfn)
 285                lpfn = man->size;
 286
 287        if (place->flags & TTM_PL_FLAG_CONTIGUOUS ||
 288            amdgpu_vram_page_split == -1) {
 289                pages_per_node = ~0ul;
 290                num_nodes = 1;
 291        } else {
 292                pages_per_node = max((uint32_t)amdgpu_vram_page_split,
 293                                     mem->page_alignment);
 294                num_nodes = DIV_ROUND_UP(mem->num_pages, pages_per_node);
 295        }
 296
 297        nodes = kvmalloc_array(num_nodes, sizeof(*nodes),
 298                               GFP_KERNEL | __GFP_ZERO);
 299        if (!nodes)
 300                return -ENOMEM;
 301
 302        mode = DRM_MM_INSERT_BEST;
 303        if (place->flags & TTM_PL_FLAG_TOPDOWN)
 304                mode = DRM_MM_INSERT_HIGH;
 305
 306        mem->start = 0;
 307        pages_left = mem->num_pages;
 308
 309        spin_lock(&mgr->lock);
 310        for (i = 0; pages_left >= pages_per_node; ++i) {
 311                unsigned long pages = rounddown_pow_of_two(pages_left);
 312
 313                r = drm_mm_insert_node_in_range(mm, &nodes[i], pages,
 314                                                pages_per_node, 0,
 315                                                place->fpfn, lpfn,
 316                                                mode);
 317                if (unlikely(r))
 318                        break;
 319
 320                usage += nodes[i].size << PAGE_SHIFT;
 321                vis_usage += amdgpu_vram_mgr_vis_size(adev, &nodes[i]);
 322                amdgpu_vram_mgr_virt_start(mem, &nodes[i]);
 323                pages_left -= pages;
 324        }
 325
 326        for (; pages_left; ++i) {
 327                unsigned long pages = min(pages_left, pages_per_node);
 328                uint32_t alignment = mem->page_alignment;
 329
 330                if (pages == pages_per_node)
 331                        alignment = pages_per_node;
 332
 333                r = drm_mm_insert_node_in_range(mm, &nodes[i],
 334                                                pages, alignment, 0,
 335                                                place->fpfn, lpfn,
 336                                                mode);
 337                if (unlikely(r))
 338                        goto error;
 339
 340                usage += nodes[i].size << PAGE_SHIFT;
 341                vis_usage += amdgpu_vram_mgr_vis_size(adev, &nodes[i]);
 342                amdgpu_vram_mgr_virt_start(mem, &nodes[i]);
 343                pages_left -= pages;
 344        }
 345        spin_unlock(&mgr->lock);
 346
 347        atomic64_add(usage, &mgr->usage);
 348        atomic64_add(vis_usage, &mgr->vis_usage);
 349
 350        mem->mm_node = nodes;
 351
 352        return 0;
 353
 354error:
 355        while (i--)
 356                drm_mm_remove_node(&nodes[i]);
 357        spin_unlock(&mgr->lock);
 358
 359        kvfree(nodes);
 360        return r == -ENOSPC ? 0 : r;
 361}
 362
 363/**
 364 * amdgpu_vram_mgr_del - free ranges
 365 *
 366 * @man: TTM memory type manager
 367 * @tbo: TTM BO we need this range for
 368 * @place: placement flags and restrictions
 369 * @mem: TTM memory object
 370 *
 371 * Free the allocated VRAM again.
 372 */
 373static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man,
 374                                struct ttm_mem_reg *mem)
 375{
 376        struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
 377        struct amdgpu_vram_mgr *mgr = man->priv;
 378        struct drm_mm_node *nodes = mem->mm_node;
 379        uint64_t usage = 0, vis_usage = 0;
 380        unsigned pages = mem->num_pages;
 381
 382        if (!mem->mm_node)
 383                return;
 384
 385        spin_lock(&mgr->lock);
 386        while (pages) {
 387                pages -= nodes->size;
 388                drm_mm_remove_node(nodes);
 389                usage += nodes->size << PAGE_SHIFT;
 390                vis_usage += amdgpu_vram_mgr_vis_size(adev, nodes);
 391                ++nodes;
 392        }
 393        spin_unlock(&mgr->lock);
 394
 395        atomic64_sub(usage, &mgr->usage);
 396        atomic64_sub(vis_usage, &mgr->vis_usage);
 397
 398        kvfree(mem->mm_node);
 399        mem->mm_node = NULL;
 400}
 401
 402/**
 403 * amdgpu_vram_mgr_usage - how many bytes are used in this domain
 404 *
 405 * @man: TTM memory type manager
 406 *
 407 * Returns how many bytes are used in this domain.
 408 */
 409uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man)
 410{
 411        struct amdgpu_vram_mgr *mgr = man->priv;
 412
 413        return atomic64_read(&mgr->usage);
 414}
 415
 416/**
 417 * amdgpu_vram_mgr_vis_usage - how many bytes are used in the visible part
 418 *
 419 * @man: TTM memory type manager
 420 *
 421 * Returns how many bytes are used in the visible part of VRAM
 422 */
 423uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man)
 424{
 425        struct amdgpu_vram_mgr *mgr = man->priv;
 426
 427        return atomic64_read(&mgr->vis_usage);
 428}
 429
 430/**
 431 * amdgpu_vram_mgr_debug - dump VRAM table
 432 *
 433 * @man: TTM memory type manager
 434 * @printer: DRM printer to use
 435 *
 436 * Dump the table content using printk.
 437 */
 438static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man,
 439                                  struct drm_printer *printer)
 440{
 441        struct amdgpu_vram_mgr *mgr = man->priv;
 442
 443        spin_lock(&mgr->lock);
 444        drm_mm_print(&mgr->mm, printer);
 445        spin_unlock(&mgr->lock);
 446
 447        drm_printf(printer, "man size:%llu pages, ram usage:%lluMB, vis usage:%lluMB\n",
 448                   man->size, amdgpu_vram_mgr_usage(man) >> 20,
 449                   amdgpu_vram_mgr_vis_usage(man) >> 20);
 450}
 451
 452const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = {
 453        .init           = amdgpu_vram_mgr_init,
 454        .takedown       = amdgpu_vram_mgr_fini,
 455        .get_node       = amdgpu_vram_mgr_new,
 456        .put_node       = amdgpu_vram_mgr_del,
 457        .debug          = amdgpu_vram_mgr_debug
 458};
 459