16a7f76e7SChristian König /* 26a7f76e7SChristian König * Copyright 2016 Advanced Micro Devices, Inc. 36a7f76e7SChristian König * 46a7f76e7SChristian König * Permission is hereby granted, free of charge, to any person obtaining a 56a7f76e7SChristian König * copy of this software and associated documentation files (the "Software"), 66a7f76e7SChristian König * to deal in the Software without restriction, including without limitation 76a7f76e7SChristian König * the rights to use, copy, modify, merge, publish, distribute, sublicense, 86a7f76e7SChristian König * and/or sell copies of the Software, and to permit persons to whom the 96a7f76e7SChristian König * Software is furnished to do so, subject to the following conditions: 106a7f76e7SChristian König * 116a7f76e7SChristian König * The above copyright notice and this permission notice shall be included in 126a7f76e7SChristian König * all copies or substantial portions of the Software. 136a7f76e7SChristian König * 146a7f76e7SChristian König * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 156a7f76e7SChristian König * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 166a7f76e7SChristian König * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 176a7f76e7SChristian König * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 186a7f76e7SChristian König * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 196a7f76e7SChristian König * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 206a7f76e7SChristian König * OTHER DEALINGS IN THE SOFTWARE. 216a7f76e7SChristian König * 226a7f76e7SChristian König * Authors: Christian König 236a7f76e7SChristian König */ 246a7f76e7SChristian König 256a7f76e7SChristian König #include <drm/drmP.h> 266a7f76e7SChristian König #include "amdgpu.h" 276a7f76e7SChristian König 286a7f76e7SChristian König struct amdgpu_vram_mgr { 296a7f76e7SChristian König struct drm_mm mm; 306a7f76e7SChristian König spinlock_t lock; 313c848bb3SChristian König atomic64_t usage; 323c848bb3SChristian König atomic64_t vis_usage; 336a7f76e7SChristian König }; 346a7f76e7SChristian König 356a7f76e7SChristian König /** 3655c374e9SKent Russell * DOC: mem_info_vram_total 3755c374e9SKent Russell * 3855c374e9SKent Russell * The amdgpu driver provides a sysfs API for reporting current total VRAM 3955c374e9SKent Russell * available on the device 4055c374e9SKent Russell * The file mem_info_vram_total is used for this and returns the total 4155c374e9SKent Russell * amount of VRAM in bytes 4255c374e9SKent Russell */ 4355c374e9SKent Russell static ssize_t amdgpu_mem_info_vram_total_show(struct device *dev, 4455c374e9SKent Russell struct device_attribute *attr, char *buf) 4555c374e9SKent Russell { 4655c374e9SKent Russell struct drm_device *ddev = dev_get_drvdata(dev); 4755c374e9SKent Russell struct amdgpu_device *adev = ddev->dev_private; 4855c374e9SKent Russell 4955c374e9SKent Russell return snprintf(buf, PAGE_SIZE, "%llu\n", adev->gmc.real_vram_size); 5055c374e9SKent Russell } 5155c374e9SKent Russell 5255c374e9SKent Russell /** 5355c374e9SKent Russell * DOC: mem_info_vis_vram_total 5455c374e9SKent Russell * 5555c374e9SKent Russell * The amdgpu driver provides a sysfs API for reporting current total 5655c374e9SKent Russell * visible VRAM available on the device 5755c374e9SKent Russell * The file mem_info_vis_vram_total is used for this and returns the total 5855c374e9SKent Russell * amount of visible VRAM in bytes 5955c374e9SKent Russell */ 6055c374e9SKent Russell static ssize_t amdgpu_mem_info_vis_vram_total_show(struct device *dev, 6155c374e9SKent Russell struct device_attribute *attr, char *buf) 6255c374e9SKent Russell { 6355c374e9SKent Russell struct drm_device *ddev = dev_get_drvdata(dev); 6455c374e9SKent Russell struct amdgpu_device *adev = ddev->dev_private; 6555c374e9SKent Russell 6655c374e9SKent Russell return snprintf(buf, PAGE_SIZE, "%llu\n", adev->gmc.visible_vram_size); 6755c374e9SKent Russell } 6855c374e9SKent Russell 6955c374e9SKent Russell /** 7055c374e9SKent Russell * DOC: mem_info_vram_used 7155c374e9SKent Russell * 7255c374e9SKent Russell * The amdgpu driver provides a sysfs API for reporting current total VRAM 7355c374e9SKent Russell * available on the device 7455c374e9SKent Russell * The file mem_info_vram_used is used for this and returns the total 7555c374e9SKent Russell * amount of currently used VRAM in bytes 7655c374e9SKent Russell */ 7755c374e9SKent Russell static ssize_t amdgpu_mem_info_vram_used_show(struct device *dev, 7855c374e9SKent Russell struct device_attribute *attr, char *buf) 7955c374e9SKent Russell { 8055c374e9SKent Russell struct drm_device *ddev = dev_get_drvdata(dev); 8155c374e9SKent Russell struct amdgpu_device *adev = ddev->dev_private; 8255c374e9SKent Russell 8355c374e9SKent Russell return snprintf(buf, PAGE_SIZE, "%llu\n", 8455c374e9SKent Russell amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM])); 8555c374e9SKent Russell } 8655c374e9SKent Russell 8755c374e9SKent Russell /** 8855c374e9SKent Russell * DOC: mem_info_vis_vram_used 8955c374e9SKent Russell * 9055c374e9SKent Russell * The amdgpu driver provides a sysfs API for reporting current total of 9155c374e9SKent Russell * used visible VRAM 9255c374e9SKent Russell * The file mem_info_vis_vram_used is used for this and returns the total 9355c374e9SKent Russell * amount of currently used visible VRAM in bytes 9455c374e9SKent Russell */ 9555c374e9SKent Russell static ssize_t amdgpu_mem_info_vis_vram_used_show(struct device *dev, 9655c374e9SKent Russell struct device_attribute *attr, char *buf) 9755c374e9SKent Russell { 9855c374e9SKent Russell struct drm_device *ddev = dev_get_drvdata(dev); 9955c374e9SKent Russell struct amdgpu_device *adev = ddev->dev_private; 10055c374e9SKent Russell 10155c374e9SKent Russell return snprintf(buf, PAGE_SIZE, "%llu\n", 10255c374e9SKent Russell amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM])); 10355c374e9SKent Russell } 10455c374e9SKent Russell 10555c374e9SKent Russell static DEVICE_ATTR(mem_info_vram_total, S_IRUGO, 10655c374e9SKent Russell amdgpu_mem_info_vram_total_show, NULL); 10755c374e9SKent Russell static DEVICE_ATTR(mem_info_vis_vram_total, S_IRUGO, 10855c374e9SKent Russell amdgpu_mem_info_vis_vram_total_show,NULL); 10955c374e9SKent Russell static DEVICE_ATTR(mem_info_vram_used, S_IRUGO, 11055c374e9SKent Russell amdgpu_mem_info_vram_used_show, NULL); 11155c374e9SKent Russell static DEVICE_ATTR(mem_info_vis_vram_used, S_IRUGO, 11255c374e9SKent Russell amdgpu_mem_info_vis_vram_used_show, NULL); 11355c374e9SKent Russell 11455c374e9SKent Russell /** 1156a7f76e7SChristian König * amdgpu_vram_mgr_init - init VRAM manager and DRM MM 1166a7f76e7SChristian König * 1176a7f76e7SChristian König * @man: TTM memory type manager 1186a7f76e7SChristian König * @p_size: maximum size of VRAM 1196a7f76e7SChristian König * 1206a7f76e7SChristian König * Allocate and initialize the VRAM manager. 1216a7f76e7SChristian König */ 1226a7f76e7SChristian König static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man, 1236a7f76e7SChristian König unsigned long p_size) 1246a7f76e7SChristian König { 12555c374e9SKent Russell struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); 1266a7f76e7SChristian König struct amdgpu_vram_mgr *mgr; 12755c374e9SKent Russell int ret; 1286a7f76e7SChristian König 1296a7f76e7SChristian König mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); 1306a7f76e7SChristian König if (!mgr) 1316a7f76e7SChristian König return -ENOMEM; 1326a7f76e7SChristian König 1336a7f76e7SChristian König drm_mm_init(&mgr->mm, 0, p_size); 1346a7f76e7SChristian König spin_lock_init(&mgr->lock); 1356a7f76e7SChristian König man->priv = mgr; 13655c374e9SKent Russell 13755c374e9SKent Russell /* Add the two VRAM-related sysfs files */ 13855c374e9SKent Russell ret = device_create_file(adev->dev, &dev_attr_mem_info_vram_total); 13955c374e9SKent Russell if (ret) { 14055c374e9SKent Russell DRM_ERROR("Failed to create device file mem_info_vram_total\n"); 14155c374e9SKent Russell return ret; 14255c374e9SKent Russell } 14355c374e9SKent Russell ret = device_create_file(adev->dev, &dev_attr_mem_info_vis_vram_total); 14455c374e9SKent Russell if (ret) { 14555c374e9SKent Russell DRM_ERROR("Failed to create device file mem_info_vis_vram_total\n"); 14655c374e9SKent Russell return ret; 14755c374e9SKent Russell } 14855c374e9SKent Russell ret = device_create_file(adev->dev, &dev_attr_mem_info_vram_used); 14955c374e9SKent Russell if (ret) { 15055c374e9SKent Russell DRM_ERROR("Failed to create device file mem_info_vram_used\n"); 15155c374e9SKent Russell return ret; 15255c374e9SKent Russell } 15355c374e9SKent Russell ret = device_create_file(adev->dev, &dev_attr_mem_info_vis_vram_used); 15455c374e9SKent Russell if (ret) { 15555c374e9SKent Russell DRM_ERROR("Failed to create device file mem_info_vis_vram_used\n"); 15655c374e9SKent Russell return ret; 15755c374e9SKent Russell } 15855c374e9SKent Russell 1596a7f76e7SChristian König return 0; 1606a7f76e7SChristian König } 1616a7f76e7SChristian König 1626a7f76e7SChristian König /** 1636a7f76e7SChristian König * amdgpu_vram_mgr_fini - free and destroy VRAM manager 1646a7f76e7SChristian König * 1656a7f76e7SChristian König * @man: TTM memory type manager 1666a7f76e7SChristian König * 1676a7f76e7SChristian König * Destroy and free the VRAM manager, returns -EBUSY if ranges are still 1686a7f76e7SChristian König * allocated inside it. 1696a7f76e7SChristian König */ 1706a7f76e7SChristian König static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man) 1716a7f76e7SChristian König { 17255c374e9SKent Russell struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); 1736a7f76e7SChristian König struct amdgpu_vram_mgr *mgr = man->priv; 1746a7f76e7SChristian König 1756a7f76e7SChristian König spin_lock(&mgr->lock); 1766a7f76e7SChristian König drm_mm_takedown(&mgr->mm); 1776a7f76e7SChristian König spin_unlock(&mgr->lock); 1786a7f76e7SChristian König kfree(mgr); 1796a7f76e7SChristian König man->priv = NULL; 18055c374e9SKent Russell device_remove_file(adev->dev, &dev_attr_mem_info_vram_total); 18155c374e9SKent Russell device_remove_file(adev->dev, &dev_attr_mem_info_vis_vram_total); 18255c374e9SKent Russell device_remove_file(adev->dev, &dev_attr_mem_info_vram_used); 18355c374e9SKent Russell device_remove_file(adev->dev, &dev_attr_mem_info_vis_vram_used); 1846a7f76e7SChristian König return 0; 1856a7f76e7SChristian König } 1866a7f76e7SChristian König 1876a7f76e7SChristian König /** 1883c848bb3SChristian König * amdgpu_vram_mgr_vis_size - Calculate visible node size 1893c848bb3SChristian König * 1903c848bb3SChristian König * @adev: amdgpu device structure 1913c848bb3SChristian König * @node: MM node structure 1923c848bb3SChristian König * 1933c848bb3SChristian König * Calculate how many bytes of the MM node are inside visible VRAM 1943c848bb3SChristian König */ 1953c848bb3SChristian König static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev, 1963c848bb3SChristian König struct drm_mm_node *node) 1973c848bb3SChristian König { 1983c848bb3SChristian König uint64_t start = node->start << PAGE_SHIFT; 1993c848bb3SChristian König uint64_t end = (node->size + node->start) << PAGE_SHIFT; 2003c848bb3SChristian König 201770d13b1SChristian König if (start >= adev->gmc.visible_vram_size) 2023c848bb3SChristian König return 0; 2033c848bb3SChristian König 204770d13b1SChristian König return (end > adev->gmc.visible_vram_size ? 205770d13b1SChristian König adev->gmc.visible_vram_size : end) - start; 2063c848bb3SChristian König } 2073c848bb3SChristian König 2083c848bb3SChristian König /** 209ddc21af4SMichel Dänzer * amdgpu_vram_mgr_bo_visible_size - CPU visible BO size 2105e9244ffSMichel Dänzer * 2115e9244ffSMichel Dänzer * @bo: &amdgpu_bo buffer object (must be in VRAM) 2125e9244ffSMichel Dänzer * 2135e9244ffSMichel Dänzer * Returns: 214ddc21af4SMichel Dänzer * How much of the given &amdgpu_bo buffer object lies in CPU visible VRAM. 2155e9244ffSMichel Dänzer */ 216ddc21af4SMichel Dänzer u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo) 2175e9244ffSMichel Dänzer { 2187303b39eSMichel Dänzer struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); 2197303b39eSMichel Dänzer struct ttm_mem_reg *mem = &bo->tbo.mem; 2207303b39eSMichel Dänzer struct drm_mm_node *nodes = mem->mm_node; 2217303b39eSMichel Dänzer unsigned pages = mem->num_pages; 222ddc21af4SMichel Dänzer u64 usage; 2237303b39eSMichel Dänzer 2249735bf19SMichel Dänzer if (amdgpu_gmc_vram_full_visible(&adev->gmc)) 2255e9244ffSMichel Dänzer return amdgpu_bo_size(bo); 2265e9244ffSMichel Dänzer 227ddc21af4SMichel Dänzer if (mem->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT) 228ddc21af4SMichel Dänzer return 0; 229ddc21af4SMichel Dänzer 230ddc21af4SMichel Dänzer for (usage = 0; nodes && pages; pages -= nodes->size, nodes++) 231ddc21af4SMichel Dänzer usage += amdgpu_vram_mgr_vis_size(adev, nodes); 2327303b39eSMichel Dänzer 2337303b39eSMichel Dänzer return usage; 2345e9244ffSMichel Dänzer } 2355e9244ffSMichel Dänzer 2365e9244ffSMichel Dänzer /** 237433ca054SChristian König * amdgpu_vram_mgr_virt_start - update virtual start address 238433ca054SChristian König * 239433ca054SChristian König * @mem: ttm_mem_reg to update 240433ca054SChristian König * @node: just allocated node 241433ca054SChristian König * 242433ca054SChristian König * Calculate a virtual BO start address to easily check if everything is CPU 243433ca054SChristian König * accessible. 244433ca054SChristian König */ 245433ca054SChristian König static void amdgpu_vram_mgr_virt_start(struct ttm_mem_reg *mem, 246433ca054SChristian König struct drm_mm_node *node) 247433ca054SChristian König { 248433ca054SChristian König unsigned long start; 249433ca054SChristian König 250433ca054SChristian König start = node->start + node->size; 251433ca054SChristian König if (start > mem->num_pages) 252433ca054SChristian König start -= mem->num_pages; 253433ca054SChristian König else 254433ca054SChristian König start = 0; 255433ca054SChristian König mem->start = max(mem->start, start); 256433ca054SChristian König } 257433ca054SChristian König 258433ca054SChristian König /** 2596a7f76e7SChristian König * amdgpu_vram_mgr_new - allocate new ranges 2606a7f76e7SChristian König * 2616a7f76e7SChristian König * @man: TTM memory type manager 2626a7f76e7SChristian König * @tbo: TTM BO we need this range for 2636a7f76e7SChristian König * @place: placement flags and restrictions 2646a7f76e7SChristian König * @mem: the resulting mem object 2656a7f76e7SChristian König * 2666a7f76e7SChristian König * Allocate VRAM for the given BO. 2676a7f76e7SChristian König */ 2686a7f76e7SChristian König static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man, 2696a7f76e7SChristian König struct ttm_buffer_object *tbo, 2706a7f76e7SChristian König const struct ttm_place *place, 2716a7f76e7SChristian König struct ttm_mem_reg *mem) 2726a7f76e7SChristian König { 2733c848bb3SChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); 2746a7f76e7SChristian König struct amdgpu_vram_mgr *mgr = man->priv; 2756a7f76e7SChristian König struct drm_mm *mm = &mgr->mm; 2766a7f76e7SChristian König struct drm_mm_node *nodes; 2774e64e553SChris Wilson enum drm_mm_insert_mode mode; 2786a7f76e7SChristian König unsigned long lpfn, num_nodes, pages_per_node, pages_left; 2793c848bb3SChristian König uint64_t usage = 0, vis_usage = 0; 2806a7f76e7SChristian König unsigned i; 2816a7f76e7SChristian König int r; 2826a7f76e7SChristian König 2836a7f76e7SChristian König lpfn = place->lpfn; 2846a7f76e7SChristian König if (!lpfn) 2856a7f76e7SChristian König lpfn = man->size; 2866a7f76e7SChristian König 28789bb5752SChristian König if (place->flags & TTM_PL_FLAG_CONTIGUOUS || 28889bb5752SChristian König amdgpu_vram_page_split == -1) { 2896a7f76e7SChristian König pages_per_node = ~0ul; 2906a7f76e7SChristian König num_nodes = 1; 2916a7f76e7SChristian König } else { 2926a7f76e7SChristian König pages_per_node = max((uint32_t)amdgpu_vram_page_split, 2936a7f76e7SChristian König mem->page_alignment); 2946a7f76e7SChristian König num_nodes = DIV_ROUND_UP(mem->num_pages, pages_per_node); 2956a7f76e7SChristian König } 2966a7f76e7SChristian König 2976fa39bc1SMichel Dänzer nodes = kvmalloc_array(num_nodes, sizeof(*nodes), 2986fa39bc1SMichel Dänzer GFP_KERNEL | __GFP_ZERO); 2996a7f76e7SChristian König if (!nodes) 3006a7f76e7SChristian König return -ENOMEM; 3016a7f76e7SChristian König 3024e64e553SChris Wilson mode = DRM_MM_INSERT_BEST; 3034e64e553SChris Wilson if (place->flags & TTM_PL_FLAG_TOPDOWN) 3044e64e553SChris Wilson mode = DRM_MM_INSERT_HIGH; 3056a7f76e7SChristian König 30689bb5752SChristian König mem->start = 0; 3076a7f76e7SChristian König pages_left = mem->num_pages; 3086a7f76e7SChristian König 3096a7f76e7SChristian König spin_lock(&mgr->lock); 310433ca054SChristian König for (i = 0; pages_left >= pages_per_node; ++i) { 311433ca054SChristian König unsigned long pages = rounddown_pow_of_two(pages_left); 312433ca054SChristian König 313433ca054SChristian König r = drm_mm_insert_node_in_range(mm, &nodes[i], pages, 314433ca054SChristian König pages_per_node, 0, 315433ca054SChristian König place->fpfn, lpfn, 316433ca054SChristian König mode); 317433ca054SChristian König if (unlikely(r)) 318433ca054SChristian König break; 319433ca054SChristian König 320433ca054SChristian König usage += nodes[i].size << PAGE_SHIFT; 321433ca054SChristian König vis_usage += amdgpu_vram_mgr_vis_size(adev, &nodes[i]); 322433ca054SChristian König amdgpu_vram_mgr_virt_start(mem, &nodes[i]); 323433ca054SChristian König pages_left -= pages; 324433ca054SChristian König } 325433ca054SChristian König 326433ca054SChristian König for (; pages_left; ++i) { 3276a7f76e7SChristian König unsigned long pages = min(pages_left, pages_per_node); 3286a7f76e7SChristian König uint32_t alignment = mem->page_alignment; 3296a7f76e7SChristian König 3306a7f76e7SChristian König if (pages == pages_per_node) 3316a7f76e7SChristian König alignment = pages_per_node; 3326a7f76e7SChristian König 3334e64e553SChris Wilson r = drm_mm_insert_node_in_range(mm, &nodes[i], 3344e64e553SChris Wilson pages, alignment, 0, 3356a7f76e7SChristian König place->fpfn, lpfn, 3364e64e553SChris Wilson mode); 3376a7f76e7SChristian König if (unlikely(r)) 3386a7f76e7SChristian König goto error; 3396a7f76e7SChristian König 3403c848bb3SChristian König usage += nodes[i].size << PAGE_SHIFT; 3413c848bb3SChristian König vis_usage += amdgpu_vram_mgr_vis_size(adev, &nodes[i]); 342433ca054SChristian König amdgpu_vram_mgr_virt_start(mem, &nodes[i]); 3436a7f76e7SChristian König pages_left -= pages; 3446a7f76e7SChristian König } 3456a7f76e7SChristian König spin_unlock(&mgr->lock); 3466a7f76e7SChristian König 3473c848bb3SChristian König atomic64_add(usage, &mgr->usage); 3483c848bb3SChristian König atomic64_add(vis_usage, &mgr->vis_usage); 3493c848bb3SChristian König 3506a7f76e7SChristian König mem->mm_node = nodes; 3516a7f76e7SChristian König 3526a7f76e7SChristian König return 0; 3536a7f76e7SChristian König 3546a7f76e7SChristian König error: 3556a7f76e7SChristian König while (i--) 3566a7f76e7SChristian König drm_mm_remove_node(&nodes[i]); 3576a7f76e7SChristian König spin_unlock(&mgr->lock); 3586a7f76e7SChristian König 3596fa39bc1SMichel Dänzer kvfree(nodes); 3606a7f76e7SChristian König return r == -ENOSPC ? 0 : r; 3616a7f76e7SChristian König } 3626a7f76e7SChristian König 3636a7f76e7SChristian König /** 3646a7f76e7SChristian König * amdgpu_vram_mgr_del - free ranges 3656a7f76e7SChristian König * 3666a7f76e7SChristian König * @man: TTM memory type manager 3676a7f76e7SChristian König * @tbo: TTM BO we need this range for 3686a7f76e7SChristian König * @place: placement flags and restrictions 3696a7f76e7SChristian König * @mem: TTM memory object 3706a7f76e7SChristian König * 3716a7f76e7SChristian König * Free the allocated VRAM again. 3726a7f76e7SChristian König */ 3736a7f76e7SChristian König static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man, 3746a7f76e7SChristian König struct ttm_mem_reg *mem) 3756a7f76e7SChristian König { 3763c848bb3SChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); 3776a7f76e7SChristian König struct amdgpu_vram_mgr *mgr = man->priv; 3786a7f76e7SChristian König struct drm_mm_node *nodes = mem->mm_node; 3793c848bb3SChristian König uint64_t usage = 0, vis_usage = 0; 3806a7f76e7SChristian König unsigned pages = mem->num_pages; 3816a7f76e7SChristian König 3826a7f76e7SChristian König if (!mem->mm_node) 3836a7f76e7SChristian König return; 3846a7f76e7SChristian König 3856a7f76e7SChristian König spin_lock(&mgr->lock); 3866a7f76e7SChristian König while (pages) { 3876a7f76e7SChristian König pages -= nodes->size; 3886a7f76e7SChristian König drm_mm_remove_node(nodes); 3893c848bb3SChristian König usage += nodes->size << PAGE_SHIFT; 3903c848bb3SChristian König vis_usage += amdgpu_vram_mgr_vis_size(adev, nodes); 3916a7f76e7SChristian König ++nodes; 3926a7f76e7SChristian König } 3936a7f76e7SChristian König spin_unlock(&mgr->lock); 3946a7f76e7SChristian König 3953c848bb3SChristian König atomic64_sub(usage, &mgr->usage); 3963c848bb3SChristian König atomic64_sub(vis_usage, &mgr->vis_usage); 3973c848bb3SChristian König 3986fa39bc1SMichel Dänzer kvfree(mem->mm_node); 3996a7f76e7SChristian König mem->mm_node = NULL; 4006a7f76e7SChristian König } 4016a7f76e7SChristian König 4026a7f76e7SChristian König /** 4033c848bb3SChristian König * amdgpu_vram_mgr_usage - how many bytes are used in this domain 4043c848bb3SChristian König * 4053c848bb3SChristian König * @man: TTM memory type manager 4063c848bb3SChristian König * 4073c848bb3SChristian König * Returns how many bytes are used in this domain. 4083c848bb3SChristian König */ 4093c848bb3SChristian König uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man) 4103c848bb3SChristian König { 4113c848bb3SChristian König struct amdgpu_vram_mgr *mgr = man->priv; 4123c848bb3SChristian König 4133c848bb3SChristian König return atomic64_read(&mgr->usage); 4143c848bb3SChristian König } 4153c848bb3SChristian König 4163c848bb3SChristian König /** 4173c848bb3SChristian König * amdgpu_vram_mgr_vis_usage - how many bytes are used in the visible part 4183c848bb3SChristian König * 4193c848bb3SChristian König * @man: TTM memory type manager 4203c848bb3SChristian König * 4213c848bb3SChristian König * Returns how many bytes are used in the visible part of VRAM 4223c848bb3SChristian König */ 4233c848bb3SChristian König uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man) 4243c848bb3SChristian König { 4253c848bb3SChristian König struct amdgpu_vram_mgr *mgr = man->priv; 4263c848bb3SChristian König 4273c848bb3SChristian König return atomic64_read(&mgr->vis_usage); 4283c848bb3SChristian König } 4293c848bb3SChristian König 4303c848bb3SChristian König /** 4316a7f76e7SChristian König * amdgpu_vram_mgr_debug - dump VRAM table 4326a7f76e7SChristian König * 4336a7f76e7SChristian König * @man: TTM memory type manager 434373533f8SChristian König * @printer: DRM printer to use 4356a7f76e7SChristian König * 4366a7f76e7SChristian König * Dump the table content using printk. 4376a7f76e7SChristian König */ 4386a7f76e7SChristian König static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man, 439373533f8SChristian König struct drm_printer *printer) 4406a7f76e7SChristian König { 4416a7f76e7SChristian König struct amdgpu_vram_mgr *mgr = man->priv; 4426a7f76e7SChristian König 4436a7f76e7SChristian König spin_lock(&mgr->lock); 444373533f8SChristian König drm_mm_print(&mgr->mm, printer); 4456a7f76e7SChristian König spin_unlock(&mgr->lock); 44697cbb284SChristian König 44797cbb284SChristian König drm_printf(printer, "man size:%llu pages, ram usage:%lluMB, vis usage:%lluMB\n", 4483c848bb3SChristian König man->size, amdgpu_vram_mgr_usage(man) >> 20, 4493c848bb3SChristian König amdgpu_vram_mgr_vis_usage(man) >> 20); 4506a7f76e7SChristian König } 4516a7f76e7SChristian König 4526a7f76e7SChristian König const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = { 4532a9d6d26SKees Cook .init = amdgpu_vram_mgr_init, 4542a9d6d26SKees Cook .takedown = amdgpu_vram_mgr_fini, 4552a9d6d26SKees Cook .get_node = amdgpu_vram_mgr_new, 4562a9d6d26SKees Cook .put_node = amdgpu_vram_mgr_del, 4572a9d6d26SKees Cook .debug = amdgpu_vram_mgr_debug 4586a7f76e7SChristian König }; 459