Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2016 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Christian König
0023  */
0024 
0025 #include <drm/ttm/ttm_range_manager.h>
0026 
0027 #include "amdgpu.h"
0028 
0029 static inline struct amdgpu_gtt_mgr *
0030 to_gtt_mgr(struct ttm_resource_manager *man)
0031 {
0032     return container_of(man, struct amdgpu_gtt_mgr, manager);
0033 }
0034 
0035 /**
0036  * DOC: mem_info_gtt_total
0037  *
0038  * The amdgpu driver provides a sysfs API for reporting current total size of
0039  * the GTT.
0040  * The file mem_info_gtt_total is used for this, and returns the total size of
0041  * the GTT block, in bytes
0042  */
0043 static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev,
0044                           struct device_attribute *attr,
0045                           char *buf)
0046 {
0047     struct drm_device *ddev = dev_get_drvdata(dev);
0048     struct amdgpu_device *adev = drm_to_adev(ddev);
0049     struct ttm_resource_manager *man;
0050 
0051     man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
0052     return sysfs_emit(buf, "%llu\n", man->size);
0053 }
0054 
0055 /**
0056  * DOC: mem_info_gtt_used
0057  *
0058  * The amdgpu driver provides a sysfs API for reporting current total amount of
0059  * used GTT.
0060  * The file mem_info_gtt_used is used for this, and returns the current used
0061  * size of the GTT block, in bytes
0062  */
0063 static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev,
0064                          struct device_attribute *attr,
0065                          char *buf)
0066 {
0067     struct drm_device *ddev = dev_get_drvdata(dev);
0068     struct amdgpu_device *adev = drm_to_adev(ddev);
0069     struct ttm_resource_manager *man = &adev->mman.gtt_mgr.manager;
0070 
0071     return sysfs_emit(buf, "%llu\n", ttm_resource_manager_usage(man));
0072 }
0073 
0074 static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO,
0075                amdgpu_mem_info_gtt_total_show, NULL);
0076 static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO,
0077                amdgpu_mem_info_gtt_used_show, NULL);
0078 
0079 static struct attribute *amdgpu_gtt_mgr_attributes[] = {
0080     &dev_attr_mem_info_gtt_total.attr,
0081     &dev_attr_mem_info_gtt_used.attr,
0082     NULL
0083 };
0084 
0085 const struct attribute_group amdgpu_gtt_mgr_attr_group = {
0086     .attrs = amdgpu_gtt_mgr_attributes
0087 };
0088 
0089 /**
0090  * amdgpu_gtt_mgr_has_gart_addr - Check if mem has address space
0091  *
0092  * @res: the mem object to check
0093  *
0094  * Check if a mem object has already address space allocated.
0095  */
0096 bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *res)
0097 {
0098     struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
0099 
0100     return drm_mm_node_allocated(&node->mm_nodes[0]);
0101 }
0102 
0103 /**
0104  * amdgpu_gtt_mgr_new - allocate a new node
0105  *
0106  * @man: TTM memory type manager
0107  * @tbo: TTM BO we need this range for
0108  * @place: placement flags and restrictions
0109  * @res: the resulting mem object
0110  *
0111  * Dummy, allocate the node but no space for it yet.
0112  */
0113 static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
0114                   struct ttm_buffer_object *tbo,
0115                   const struct ttm_place *place,
0116                   struct ttm_resource **res)
0117 {
0118     struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
0119     uint32_t num_pages = PFN_UP(tbo->base.size);
0120     struct ttm_range_mgr_node *node;
0121     int r;
0122 
0123     node = kzalloc(struct_size(node, mm_nodes, 1), GFP_KERNEL);
0124     if (!node)
0125         return -ENOMEM;
0126 
0127     ttm_resource_init(tbo, place, &node->base);
0128     if (!(place->flags & TTM_PL_FLAG_TEMPORARY) &&
0129         ttm_resource_manager_usage(man) > man->size) {
0130         r = -ENOSPC;
0131         goto err_free;
0132     }
0133 
0134     if (place->lpfn) {
0135         spin_lock(&mgr->lock);
0136         r = drm_mm_insert_node_in_range(&mgr->mm, &node->mm_nodes[0],
0137                         num_pages, tbo->page_alignment,
0138                         0, place->fpfn, place->lpfn,
0139                         DRM_MM_INSERT_BEST);
0140         spin_unlock(&mgr->lock);
0141         if (unlikely(r))
0142             goto err_free;
0143 
0144         node->base.start = node->mm_nodes[0].start;
0145     } else {
0146         node->mm_nodes[0].start = 0;
0147         node->mm_nodes[0].size = node->base.num_pages;
0148         node->base.start = AMDGPU_BO_INVALID_OFFSET;
0149     }
0150 
0151     *res = &node->base;
0152     return 0;
0153 
0154 err_free:
0155     ttm_resource_fini(man, &node->base);
0156     kfree(node);
0157     return r;
0158 }
0159 
0160 /**
0161  * amdgpu_gtt_mgr_del - free ranges
0162  *
0163  * @man: TTM memory type manager
0164  * @res: TTM memory object
0165  *
0166  * Free the allocated GTT again.
0167  */
0168 static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man,
0169                    struct ttm_resource *res)
0170 {
0171     struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
0172     struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
0173 
0174     spin_lock(&mgr->lock);
0175     if (drm_mm_node_allocated(&node->mm_nodes[0]))
0176         drm_mm_remove_node(&node->mm_nodes[0]);
0177     spin_unlock(&mgr->lock);
0178 
0179     ttm_resource_fini(man, res);
0180     kfree(node);
0181 }
0182 
0183 /**
0184  * amdgpu_gtt_mgr_recover - re-init gart
0185  *
0186  * @mgr: amdgpu_gtt_mgr pointer
0187  *
0188  * Re-init the gart for each known BO in the GTT.
0189  */
0190 void amdgpu_gtt_mgr_recover(struct amdgpu_gtt_mgr *mgr)
0191 {
0192     struct ttm_range_mgr_node *node;
0193     struct drm_mm_node *mm_node;
0194     struct amdgpu_device *adev;
0195 
0196     adev = container_of(mgr, typeof(*adev), mman.gtt_mgr);
0197     spin_lock(&mgr->lock);
0198     drm_mm_for_each_node(mm_node, &mgr->mm) {
0199         node = container_of(mm_node, typeof(*node), mm_nodes[0]);
0200         amdgpu_ttm_recover_gart(node->base.bo);
0201     }
0202     spin_unlock(&mgr->lock);
0203 
0204     amdgpu_gart_invalidate_tlb(adev);
0205 }
0206 
0207 /**
0208  * amdgpu_gtt_mgr_debug - dump VRAM table
0209  *
0210  * @man: TTM memory type manager
0211  * @printer: DRM printer to use
0212  *
0213  * Dump the table content using printk.
0214  */
0215 static void amdgpu_gtt_mgr_debug(struct ttm_resource_manager *man,
0216                  struct drm_printer *printer)
0217 {
0218     struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
0219 
0220     spin_lock(&mgr->lock);
0221     drm_mm_print(&mgr->mm, printer);
0222     spin_unlock(&mgr->lock);
0223 }
0224 
0225 static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = {
0226     .alloc = amdgpu_gtt_mgr_new,
0227     .free = amdgpu_gtt_mgr_del,
0228     .debug = amdgpu_gtt_mgr_debug
0229 };
0230 
0231 /**
0232  * amdgpu_gtt_mgr_init - init GTT manager and DRM MM
0233  *
0234  * @adev: amdgpu_device pointer
0235  * @gtt_size: maximum size of GTT
0236  *
0237  * Allocate and initialize the GTT manager.
0238  */
0239 int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size)
0240 {
0241     struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;
0242     struct ttm_resource_manager *man = &mgr->manager;
0243     uint64_t start, size;
0244 
0245     man->use_tt = true;
0246     man->func = &amdgpu_gtt_mgr_func;
0247 
0248     ttm_resource_manager_init(man, &adev->mman.bdev, gtt_size);
0249 
0250     start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS;
0251     size = (adev->gmc.gart_size >> PAGE_SHIFT) - start;
0252     drm_mm_init(&mgr->mm, start, size);
0253     spin_lock_init(&mgr->lock);
0254 
0255     ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, &mgr->manager);
0256     ttm_resource_manager_set_used(man, true);
0257     return 0;
0258 }
0259 
0260 /**
0261  * amdgpu_gtt_mgr_fini - free and destroy GTT manager
0262  *
0263  * @adev: amdgpu_device pointer
0264  *
0265  * Destroy and free the GTT manager, returns -EBUSY if ranges are still
0266  * allocated inside it.
0267  */
0268 void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev)
0269 {
0270     struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;
0271     struct ttm_resource_manager *man = &mgr->manager;
0272     int ret;
0273 
0274     ttm_resource_manager_set_used(man, false);
0275 
0276     ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
0277     if (ret)
0278         return;
0279 
0280     spin_lock(&mgr->lock);
0281     drm_mm_takedown(&mgr->mm);
0282     spin_unlock(&mgr->lock);
0283 
0284     ttm_resource_manager_cleanup(man);
0285     ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, NULL);
0286 }