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