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 28 struct amdgpu_vram_mgr { 29 struct drm_mm mm; 30 spinlock_t lock; 31 }; 32 33 /** 34 * amdgpu_vram_mgr_init - init VRAM manager and DRM MM 35 * 36 * @man: TTM memory type manager 37 * @p_size: maximum size of VRAM 38 * 39 * Allocate and initialize the VRAM manager. 40 */ 41 static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man, 42 unsigned long p_size) 43 { 44 struct amdgpu_vram_mgr *mgr; 45 46 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); 47 if (!mgr) 48 return -ENOMEM; 49 50 drm_mm_init(&mgr->mm, 0, p_size); 51 spin_lock_init(&mgr->lock); 52 man->priv = mgr; 53 return 0; 54 } 55 56 /** 57 * amdgpu_vram_mgr_fini - free and destroy VRAM manager 58 * 59 * @man: TTM memory type manager 60 * 61 * Destroy and free the VRAM manager, returns -EBUSY if ranges are still 62 * allocated inside it. 63 */ 64 static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man) 65 { 66 struct amdgpu_vram_mgr *mgr = man->priv; 67 68 spin_lock(&mgr->lock); 69 if (!drm_mm_clean(&mgr->mm)) { 70 spin_unlock(&mgr->lock); 71 return -EBUSY; 72 } 73 74 drm_mm_takedown(&mgr->mm); 75 spin_unlock(&mgr->lock); 76 kfree(mgr); 77 man->priv = NULL; 78 return 0; 79 } 80 81 /** 82 * amdgpu_vram_mgr_new - allocate new ranges 83 * 84 * @man: TTM memory type manager 85 * @tbo: TTM BO we need this range for 86 * @place: placement flags and restrictions 87 * @mem: the resulting mem object 88 * 89 * Allocate VRAM for the given BO. 90 */ 91 static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man, 92 struct ttm_buffer_object *tbo, 93 const struct ttm_place *place, 94 struct ttm_mem_reg *mem) 95 { 96 struct amdgpu_bo *bo = container_of(tbo, struct amdgpu_bo, tbo); 97 struct amdgpu_vram_mgr *mgr = man->priv; 98 struct drm_mm *mm = &mgr->mm; 99 struct drm_mm_node *nodes; 100 enum drm_mm_insert_mode mode; 101 unsigned long lpfn, num_nodes, pages_per_node, pages_left; 102 unsigned i; 103 int r; 104 105 lpfn = place->lpfn; 106 if (!lpfn) 107 lpfn = man->size; 108 109 if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS || 110 place->lpfn || amdgpu_vram_page_split == -1) { 111 pages_per_node = ~0ul; 112 num_nodes = 1; 113 } else { 114 pages_per_node = max((uint32_t)amdgpu_vram_page_split, 115 mem->page_alignment); 116 num_nodes = DIV_ROUND_UP(mem->num_pages, pages_per_node); 117 } 118 119 nodes = kcalloc(num_nodes, sizeof(*nodes), GFP_KERNEL); 120 if (!nodes) 121 return -ENOMEM; 122 123 mode = DRM_MM_INSERT_BEST; 124 if (place->flags & TTM_PL_FLAG_TOPDOWN) 125 mode = DRM_MM_INSERT_HIGH; 126 127 pages_left = mem->num_pages; 128 129 spin_lock(&mgr->lock); 130 for (i = 0; i < num_nodes; ++i) { 131 unsigned long pages = min(pages_left, pages_per_node); 132 uint32_t alignment = mem->page_alignment; 133 134 if (pages == pages_per_node) 135 alignment = pages_per_node; 136 137 r = drm_mm_insert_node_in_range(mm, &nodes[i], 138 pages, alignment, 0, 139 place->fpfn, lpfn, 140 mode); 141 if (unlikely(r)) 142 goto error; 143 144 pages_left -= pages; 145 } 146 spin_unlock(&mgr->lock); 147 148 mem->start = num_nodes == 1 ? nodes[0].start : AMDGPU_BO_INVALID_OFFSET; 149 mem->mm_node = nodes; 150 151 return 0; 152 153 error: 154 while (i--) 155 drm_mm_remove_node(&nodes[i]); 156 spin_unlock(&mgr->lock); 157 158 kfree(nodes); 159 return r == -ENOSPC ? 0 : r; 160 } 161 162 /** 163 * amdgpu_vram_mgr_del - free ranges 164 * 165 * @man: TTM memory type manager 166 * @tbo: TTM BO we need this range for 167 * @place: placement flags and restrictions 168 * @mem: TTM memory object 169 * 170 * Free the allocated VRAM again. 171 */ 172 static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man, 173 struct ttm_mem_reg *mem) 174 { 175 struct amdgpu_vram_mgr *mgr = man->priv; 176 struct drm_mm_node *nodes = mem->mm_node; 177 unsigned pages = mem->num_pages; 178 179 if (!mem->mm_node) 180 return; 181 182 spin_lock(&mgr->lock); 183 while (pages) { 184 pages -= nodes->size; 185 drm_mm_remove_node(nodes); 186 ++nodes; 187 } 188 spin_unlock(&mgr->lock); 189 190 kfree(mem->mm_node); 191 mem->mm_node = NULL; 192 } 193 194 /** 195 * amdgpu_vram_mgr_debug - dump VRAM table 196 * 197 * @man: TTM memory type manager 198 * @prefix: text prefix 199 * 200 * Dump the table content using printk. 201 */ 202 static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man, 203 const char *prefix) 204 { 205 struct amdgpu_vram_mgr *mgr = man->priv; 206 struct drm_printer p = drm_debug_printer(prefix); 207 208 spin_lock(&mgr->lock); 209 drm_mm_print(&mgr->mm, &p); 210 spin_unlock(&mgr->lock); 211 } 212 213 const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = { 214 amdgpu_vram_mgr_init, 215 amdgpu_vram_mgr_fini, 216 amdgpu_vram_mgr_new, 217 amdgpu_vram_mgr_del, 218 amdgpu_vram_mgr_debug 219 }; 220