brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · 0760e70 Raw
323 lines · c
1/*2 * Copyright 2016 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * 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 OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: Christian König23 */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_total37 *38 * The amdgpu driver provides a sysfs API for reporting current total size of39 * the GTT.40 * The file mem_info_gtt_total is used for this, and returns the total size of41 * the GTT block, in bytes42 */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_used57 *58 * The amdgpu driver provides a sysfs API for reporting current total amount of59 * used GTT.60 * The file mem_info_gtt_used is used for this, and returns the current used61 * size of the GTT block, in bytes62 */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	NULL83};84 85const struct attribute_group amdgpu_gtt_mgr_attr_group = {86	.attrs = amdgpu_gtt_mgr_attributes87};88 89/**90 * amdgpu_gtt_mgr_has_gart_addr - Check if mem has address space91 *92 * @res: the mem object to check93 *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 node105 *106 * @man: TTM memory type manager107 * @tbo: TTM BO we need this range for108 * @place: placement flags and restrictions109 * @res: the resulting mem object110 *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 = PFN_UP(node->base.size);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 ranges162 *163 * @man: TTM memory type manager164 * @res: TTM memory object165 *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 gart185 *186 * @mgr: amdgpu_gtt_mgr pointer187 *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 205/**206 * amdgpu_gtt_mgr_intersects - test for intersection207 *208 * @man: Our manager object209 * @res: The resource to test210 * @place: The place for the new allocation211 * @size: The size of the new allocation212 *213 * Simplified intersection test, only interesting if we need GART or not.214 */215static bool amdgpu_gtt_mgr_intersects(struct ttm_resource_manager *man,216				      struct ttm_resource *res,217				      const struct ttm_place *place,218				      size_t size)219{220	return !place->lpfn || amdgpu_gtt_mgr_has_gart_addr(res);221}222 223/**224 * amdgpu_gtt_mgr_compatible - test for compatibility225 *226 * @man: Our manager object227 * @res: The resource to test228 * @place: The place for the new allocation229 * @size: The size of the new allocation230 *231 * Simplified compatibility test.232 */233static bool amdgpu_gtt_mgr_compatible(struct ttm_resource_manager *man,234				      struct ttm_resource *res,235				      const struct ttm_place *place,236				      size_t size)237{238	return !place->lpfn || amdgpu_gtt_mgr_has_gart_addr(res);239}240 241/**242 * amdgpu_gtt_mgr_debug - dump VRAM table243 *244 * @man: TTM memory type manager245 * @printer: DRM printer to use246 *247 * Dump the table content using printk.248 */249static void amdgpu_gtt_mgr_debug(struct ttm_resource_manager *man,250				 struct drm_printer *printer)251{252	struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);253 254	spin_lock(&mgr->lock);255	drm_mm_print(&mgr->mm, printer);256	spin_unlock(&mgr->lock);257}258 259static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = {260	.alloc = amdgpu_gtt_mgr_new,261	.free = amdgpu_gtt_mgr_del,262	.intersects = amdgpu_gtt_mgr_intersects,263	.compatible = amdgpu_gtt_mgr_compatible,264	.debug = amdgpu_gtt_mgr_debug265};266 267/**268 * amdgpu_gtt_mgr_init - init GTT manager and DRM MM269 *270 * @adev: amdgpu_device pointer271 * @gtt_size: maximum size of GTT272 *273 * Allocate and initialize the GTT manager.274 */275int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size)276{277	struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;278	struct ttm_resource_manager *man = &mgr->manager;279	uint64_t start, size;280 281	man->use_tt = true;282	man->func = &amdgpu_gtt_mgr_func;283 284	ttm_resource_manager_init(man, &adev->mman.bdev, gtt_size);285 286	start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS;287	size = (adev->gmc.gart_size >> PAGE_SHIFT) - start;288	drm_mm_init(&mgr->mm, start, size);289	spin_lock_init(&mgr->lock);290 291	ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, &mgr->manager);292	ttm_resource_manager_set_used(man, true);293	return 0;294}295 296/**297 * amdgpu_gtt_mgr_fini - free and destroy GTT manager298 *299 * @adev: amdgpu_device pointer300 *301 * Destroy and free the GTT manager, returns -EBUSY if ranges are still302 * allocated inside it.303 */304void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev)305{306	struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;307	struct ttm_resource_manager *man = &mgr->manager;308	int ret;309 310	ttm_resource_manager_set_used(man, false);311 312	ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man);313	if (ret)314		return;315 316	spin_lock(&mgr->lock);317	drm_mm_takedown(&mgr->mm);318	spin_unlock(&mgr->lock);319 320	ttm_resource_manager_cleanup(man);321	ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, NULL);322}323