| .. | .. |
|---|
| 22 | 22 | * Authors: Christian König |
|---|
| 23 | 23 | */ |
|---|
| 24 | 24 | |
|---|
| 25 | | -#include <drm/drmP.h> |
|---|
| 26 | 25 | #include "amdgpu.h" |
|---|
| 27 | 26 | |
|---|
| 28 | | -struct amdgpu_gtt_mgr { |
|---|
| 29 | | - struct drm_mm mm; |
|---|
| 30 | | - spinlock_t lock; |
|---|
| 31 | | - atomic64_t available; |
|---|
| 32 | | -}; |
|---|
| 27 | +static inline struct amdgpu_gtt_mgr *to_gtt_mgr(struct ttm_resource_manager *man) |
|---|
| 28 | +{ |
|---|
| 29 | + return container_of(man, struct amdgpu_gtt_mgr, manager); |
|---|
| 30 | +} |
|---|
| 33 | 31 | |
|---|
| 34 | 32 | struct amdgpu_gtt_node { |
|---|
| 35 | 33 | struct drm_mm_node node; |
|---|
| .. | .. |
|---|
| 37 | 35 | }; |
|---|
| 38 | 36 | |
|---|
| 39 | 37 | /** |
|---|
| 38 | + * DOC: mem_info_gtt_total |
|---|
| 39 | + * |
|---|
| 40 | + * The amdgpu driver provides a sysfs API for reporting current total size of |
|---|
| 41 | + * the GTT. |
|---|
| 42 | + * The file mem_info_gtt_total is used for this, and returns the total size of |
|---|
| 43 | + * the GTT block, in bytes |
|---|
| 44 | + */ |
|---|
| 45 | +static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev, |
|---|
| 46 | + struct device_attribute *attr, char *buf) |
|---|
| 47 | +{ |
|---|
| 48 | + struct drm_device *ddev = dev_get_drvdata(dev); |
|---|
| 49 | + struct amdgpu_device *adev = drm_to_adev(ddev); |
|---|
| 50 | + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); |
|---|
| 51 | + |
|---|
| 52 | + return snprintf(buf, PAGE_SIZE, "%llu\n", |
|---|
| 53 | + man->size * PAGE_SIZE); |
|---|
| 54 | +} |
|---|
| 55 | + |
|---|
| 56 | +/** |
|---|
| 57 | + * DOC: mem_info_gtt_used |
|---|
| 58 | + * |
|---|
| 59 | + * The amdgpu driver provides a sysfs API for reporting current total amount of |
|---|
| 60 | + * used GTT. |
|---|
| 61 | + * The file mem_info_gtt_used is used for this, and returns the current used |
|---|
| 62 | + * size of the GTT block, in bytes |
|---|
| 63 | + */ |
|---|
| 64 | +static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev, |
|---|
| 65 | + struct device_attribute *attr, 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 = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); |
|---|
| 70 | + |
|---|
| 71 | + return snprintf(buf, PAGE_SIZE, "%llu\n", |
|---|
| 72 | + amdgpu_gtt_mgr_usage(man)); |
|---|
| 73 | +} |
|---|
| 74 | + |
|---|
| 75 | +static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO, |
|---|
| 76 | + amdgpu_mem_info_gtt_total_show, NULL); |
|---|
| 77 | +static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO, |
|---|
| 78 | + amdgpu_mem_info_gtt_used_show, NULL); |
|---|
| 79 | + |
|---|
| 80 | +static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func; |
|---|
| 81 | +/** |
|---|
| 40 | 82 | * amdgpu_gtt_mgr_init - init GTT manager and DRM MM |
|---|
| 41 | 83 | * |
|---|
| 42 | | - * @man: TTM memory type manager |
|---|
| 43 | | - * @p_size: maximum size of GTT |
|---|
| 84 | + * @adev: amdgpu_device pointer |
|---|
| 85 | + * @gtt_size: maximum size of GTT |
|---|
| 44 | 86 | * |
|---|
| 45 | 87 | * Allocate and initialize the GTT manager. |
|---|
| 46 | 88 | */ |
|---|
| 47 | | -static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, |
|---|
| 48 | | - unsigned long p_size) |
|---|
| 89 | +int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size) |
|---|
| 49 | 90 | { |
|---|
| 50 | | - struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); |
|---|
| 51 | | - struct amdgpu_gtt_mgr *mgr; |
|---|
| 91 | + struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; |
|---|
| 92 | + struct ttm_resource_manager *man = &mgr->manager; |
|---|
| 52 | 93 | uint64_t start, size; |
|---|
| 94 | + int ret; |
|---|
| 53 | 95 | |
|---|
| 54 | | - mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); |
|---|
| 55 | | - if (!mgr) |
|---|
| 56 | | - return -ENOMEM; |
|---|
| 96 | + man->use_tt = true; |
|---|
| 97 | + man->func = &amdgpu_gtt_mgr_func; |
|---|
| 98 | + |
|---|
| 99 | + ttm_resource_manager_init(man, gtt_size >> PAGE_SHIFT); |
|---|
| 57 | 100 | |
|---|
| 58 | 101 | start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; |
|---|
| 59 | 102 | size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; |
|---|
| 60 | 103 | drm_mm_init(&mgr->mm, start, size); |
|---|
| 61 | 104 | spin_lock_init(&mgr->lock); |
|---|
| 62 | | - atomic64_set(&mgr->available, p_size); |
|---|
| 63 | | - man->priv = mgr; |
|---|
| 105 | + atomic64_set(&mgr->available, gtt_size >> PAGE_SHIFT); |
|---|
| 106 | + |
|---|
| 107 | + ret = device_create_file(adev->dev, &dev_attr_mem_info_gtt_total); |
|---|
| 108 | + if (ret) { |
|---|
| 109 | + DRM_ERROR("Failed to create device file mem_info_gtt_total\n"); |
|---|
| 110 | + return ret; |
|---|
| 111 | + } |
|---|
| 112 | + ret = device_create_file(adev->dev, &dev_attr_mem_info_gtt_used); |
|---|
| 113 | + if (ret) { |
|---|
| 114 | + DRM_ERROR("Failed to create device file mem_info_gtt_used\n"); |
|---|
| 115 | + return ret; |
|---|
| 116 | + } |
|---|
| 117 | + |
|---|
| 118 | + ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, &mgr->manager); |
|---|
| 119 | + ttm_resource_manager_set_used(man, true); |
|---|
| 64 | 120 | return 0; |
|---|
| 65 | 121 | } |
|---|
| 66 | 122 | |
|---|
| 67 | 123 | /** |
|---|
| 68 | 124 | * amdgpu_gtt_mgr_fini - free and destroy GTT manager |
|---|
| 69 | 125 | * |
|---|
| 70 | | - * @man: TTM memory type manager |
|---|
| 126 | + * @adev: amdgpu_device pointer |
|---|
| 71 | 127 | * |
|---|
| 72 | 128 | * Destroy and free the GTT manager, returns -EBUSY if ranges are still |
|---|
| 73 | 129 | * allocated inside it. |
|---|
| 74 | 130 | */ |
|---|
| 75 | | -static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man) |
|---|
| 131 | +void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev) |
|---|
| 76 | 132 | { |
|---|
| 77 | | - struct amdgpu_gtt_mgr *mgr = man->priv; |
|---|
| 133 | + struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; |
|---|
| 134 | + struct ttm_resource_manager *man = &mgr->manager; |
|---|
| 135 | + int ret; |
|---|
| 136 | + |
|---|
| 137 | + ttm_resource_manager_set_used(man, false); |
|---|
| 138 | + |
|---|
| 139 | + ret = ttm_resource_manager_force_list_clean(&adev->mman.bdev, man); |
|---|
| 140 | + if (ret) |
|---|
| 141 | + return; |
|---|
| 142 | + |
|---|
| 78 | 143 | spin_lock(&mgr->lock); |
|---|
| 79 | 144 | drm_mm_takedown(&mgr->mm); |
|---|
| 80 | 145 | spin_unlock(&mgr->lock); |
|---|
| 81 | | - kfree(mgr); |
|---|
| 82 | | - man->priv = NULL; |
|---|
| 83 | | - return 0; |
|---|
| 146 | + |
|---|
| 147 | + device_remove_file(adev->dev, &dev_attr_mem_info_gtt_total); |
|---|
| 148 | + device_remove_file(adev->dev, &dev_attr_mem_info_gtt_used); |
|---|
| 149 | + |
|---|
| 150 | + ttm_resource_manager_cleanup(man); |
|---|
| 151 | + ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, NULL); |
|---|
| 84 | 152 | } |
|---|
| 85 | 153 | |
|---|
| 86 | 154 | /** |
|---|
| .. | .. |
|---|
| 90 | 158 | * |
|---|
| 91 | 159 | * Check if a mem object has already address space allocated. |
|---|
| 92 | 160 | */ |
|---|
| 93 | | -bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem) |
|---|
| 161 | +bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem) |
|---|
| 94 | 162 | { |
|---|
| 95 | | - struct amdgpu_gtt_node *node = mem->mm_node; |
|---|
| 96 | | - |
|---|
| 97 | | - return (node->node.start != AMDGPU_BO_INVALID_OFFSET); |
|---|
| 98 | | -} |
|---|
| 99 | | - |
|---|
| 100 | | -/** |
|---|
| 101 | | - * amdgpu_gtt_mgr_alloc - allocate new ranges |
|---|
| 102 | | - * |
|---|
| 103 | | - * @man: TTM memory type manager |
|---|
| 104 | | - * @tbo: TTM BO we need this range for |
|---|
| 105 | | - * @place: placement flags and restrictions |
|---|
| 106 | | - * @mem: the resulting mem object |
|---|
| 107 | | - * |
|---|
| 108 | | - * Allocate the address space for a node. |
|---|
| 109 | | - */ |
|---|
| 110 | | -static int amdgpu_gtt_mgr_alloc(struct ttm_mem_type_manager *man, |
|---|
| 111 | | - struct ttm_buffer_object *tbo, |
|---|
| 112 | | - const struct ttm_place *place, |
|---|
| 113 | | - struct ttm_mem_reg *mem) |
|---|
| 114 | | -{ |
|---|
| 115 | | - struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); |
|---|
| 116 | | - struct amdgpu_gtt_mgr *mgr = man->priv; |
|---|
| 117 | | - struct amdgpu_gtt_node *node = mem->mm_node; |
|---|
| 118 | | - enum drm_mm_insert_mode mode; |
|---|
| 119 | | - unsigned long fpfn, lpfn; |
|---|
| 120 | | - int r; |
|---|
| 121 | | - |
|---|
| 122 | | - if (amdgpu_gtt_mgr_has_gart_addr(mem)) |
|---|
| 123 | | - return 0; |
|---|
| 124 | | - |
|---|
| 125 | | - if (place) |
|---|
| 126 | | - fpfn = place->fpfn; |
|---|
| 127 | | - else |
|---|
| 128 | | - fpfn = 0; |
|---|
| 129 | | - |
|---|
| 130 | | - if (place && place->lpfn) |
|---|
| 131 | | - lpfn = place->lpfn; |
|---|
| 132 | | - else |
|---|
| 133 | | - lpfn = adev->gart.num_cpu_pages; |
|---|
| 134 | | - |
|---|
| 135 | | - mode = DRM_MM_INSERT_BEST; |
|---|
| 136 | | - if (place && place->flags & TTM_PL_FLAG_TOPDOWN) |
|---|
| 137 | | - mode = DRM_MM_INSERT_HIGH; |
|---|
| 138 | | - |
|---|
| 139 | | - spin_lock(&mgr->lock); |
|---|
| 140 | | - r = drm_mm_insert_node_in_range(&mgr->mm, &node->node, mem->num_pages, |
|---|
| 141 | | - mem->page_alignment, 0, fpfn, lpfn, |
|---|
| 142 | | - mode); |
|---|
| 143 | | - spin_unlock(&mgr->lock); |
|---|
| 144 | | - |
|---|
| 145 | | - if (!r) |
|---|
| 146 | | - mem->start = node->node.start; |
|---|
| 147 | | - |
|---|
| 148 | | - return r; |
|---|
| 163 | + return mem->mm_node != NULL; |
|---|
| 149 | 164 | } |
|---|
| 150 | 165 | |
|---|
| 151 | 166 | /** |
|---|
| .. | .. |
|---|
| 158 | 173 | * |
|---|
| 159 | 174 | * Dummy, allocate the node but no space for it yet. |
|---|
| 160 | 175 | */ |
|---|
| 161 | | -static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man, |
|---|
| 176 | +static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, |
|---|
| 162 | 177 | struct ttm_buffer_object *tbo, |
|---|
| 163 | 178 | const struct ttm_place *place, |
|---|
| 164 | | - struct ttm_mem_reg *mem) |
|---|
| 179 | + struct ttm_resource *mem) |
|---|
| 165 | 180 | { |
|---|
| 166 | | - struct amdgpu_gtt_mgr *mgr = man->priv; |
|---|
| 181 | + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); |
|---|
| 167 | 182 | struct amdgpu_gtt_node *node; |
|---|
| 168 | 183 | int r; |
|---|
| 169 | 184 | |
|---|
| .. | .. |
|---|
| 171 | 186 | if ((&tbo->mem == mem || tbo->mem.mem_type != TTM_PL_TT) && |
|---|
| 172 | 187 | atomic64_read(&mgr->available) < mem->num_pages) { |
|---|
| 173 | 188 | spin_unlock(&mgr->lock); |
|---|
| 174 | | - return 0; |
|---|
| 189 | + return -ENOSPC; |
|---|
| 175 | 190 | } |
|---|
| 176 | 191 | atomic64_sub(mem->num_pages, &mgr->available); |
|---|
| 177 | 192 | spin_unlock(&mgr->lock); |
|---|
| 193 | + |
|---|
| 194 | + if (!place->lpfn) { |
|---|
| 195 | + mem->mm_node = NULL; |
|---|
| 196 | + mem->start = AMDGPU_BO_INVALID_OFFSET; |
|---|
| 197 | + return 0; |
|---|
| 198 | + } |
|---|
| 178 | 199 | |
|---|
| 179 | 200 | node = kzalloc(sizeof(*node), GFP_KERNEL); |
|---|
| 180 | 201 | if (!node) { |
|---|
| .. | .. |
|---|
| 182 | 203 | goto err_out; |
|---|
| 183 | 204 | } |
|---|
| 184 | 205 | |
|---|
| 185 | | - node->node.start = AMDGPU_BO_INVALID_OFFSET; |
|---|
| 186 | | - node->node.size = mem->num_pages; |
|---|
| 187 | 206 | node->tbo = tbo; |
|---|
| 188 | | - mem->mm_node = node; |
|---|
| 189 | 207 | |
|---|
| 190 | | - if (place->fpfn || place->lpfn || place->flags & TTM_PL_FLAG_TOPDOWN) { |
|---|
| 191 | | - r = amdgpu_gtt_mgr_alloc(man, tbo, place, mem); |
|---|
| 192 | | - if (unlikely(r)) { |
|---|
| 193 | | - kfree(node); |
|---|
| 194 | | - mem->mm_node = NULL; |
|---|
| 195 | | - r = 0; |
|---|
| 196 | | - goto err_out; |
|---|
| 197 | | - } |
|---|
| 198 | | - } else { |
|---|
| 199 | | - mem->start = node->node.start; |
|---|
| 200 | | - } |
|---|
| 208 | + spin_lock(&mgr->lock); |
|---|
| 209 | + r = drm_mm_insert_node_in_range(&mgr->mm, &node->node, mem->num_pages, |
|---|
| 210 | + mem->page_alignment, 0, place->fpfn, |
|---|
| 211 | + place->lpfn, DRM_MM_INSERT_BEST); |
|---|
| 212 | + spin_unlock(&mgr->lock); |
|---|
| 213 | + |
|---|
| 214 | + if (unlikely(r)) |
|---|
| 215 | + goto err_free; |
|---|
| 216 | + |
|---|
| 217 | + mem->mm_node = node; |
|---|
| 218 | + mem->start = node->node.start; |
|---|
| 201 | 219 | |
|---|
| 202 | 220 | return 0; |
|---|
| 221 | + |
|---|
| 222 | +err_free: |
|---|
| 223 | + kfree(node); |
|---|
| 224 | + |
|---|
| 203 | 225 | err_out: |
|---|
| 204 | 226 | atomic64_add(mem->num_pages, &mgr->available); |
|---|
| 205 | 227 | |
|---|
| .. | .. |
|---|
| 210 | 232 | * amdgpu_gtt_mgr_del - free ranges |
|---|
| 211 | 233 | * |
|---|
| 212 | 234 | * @man: TTM memory type manager |
|---|
| 213 | | - * @tbo: TTM BO we need this range for |
|---|
| 214 | | - * @place: placement flags and restrictions |
|---|
| 215 | 235 | * @mem: TTM memory object |
|---|
| 216 | 236 | * |
|---|
| 217 | 237 | * Free the allocated GTT again. |
|---|
| 218 | 238 | */ |
|---|
| 219 | | -static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man, |
|---|
| 220 | | - struct ttm_mem_reg *mem) |
|---|
| 239 | +static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man, |
|---|
| 240 | + struct ttm_resource *mem) |
|---|
| 221 | 241 | { |
|---|
| 222 | | - struct amdgpu_gtt_mgr *mgr = man->priv; |
|---|
| 242 | + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); |
|---|
| 223 | 243 | struct amdgpu_gtt_node *node = mem->mm_node; |
|---|
| 224 | 244 | |
|---|
| 225 | | - if (!node) |
|---|
| 226 | | - return; |
|---|
| 227 | | - |
|---|
| 228 | | - spin_lock(&mgr->lock); |
|---|
| 229 | | - if (node->node.start != AMDGPU_BO_INVALID_OFFSET) |
|---|
| 245 | + if (node) { |
|---|
| 246 | + spin_lock(&mgr->lock); |
|---|
| 230 | 247 | drm_mm_remove_node(&node->node); |
|---|
| 231 | | - spin_unlock(&mgr->lock); |
|---|
| 232 | | - atomic64_add(mem->num_pages, &mgr->available); |
|---|
| 248 | + spin_unlock(&mgr->lock); |
|---|
| 249 | + kfree(node); |
|---|
| 250 | + } |
|---|
| 233 | 251 | |
|---|
| 234 | | - kfree(node); |
|---|
| 235 | | - mem->mm_node = NULL; |
|---|
| 252 | + atomic64_add(mem->num_pages, &mgr->available); |
|---|
| 236 | 253 | } |
|---|
| 237 | 254 | |
|---|
| 238 | 255 | /** |
|---|
| .. | .. |
|---|
| 242 | 259 | * |
|---|
| 243 | 260 | * Return how many bytes are used in the GTT domain |
|---|
| 244 | 261 | */ |
|---|
| 245 | | -uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man) |
|---|
| 262 | +uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man) |
|---|
| 246 | 263 | { |
|---|
| 247 | | - struct amdgpu_gtt_mgr *mgr = man->priv; |
|---|
| 264 | + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); |
|---|
| 248 | 265 | s64 result = man->size - atomic64_read(&mgr->available); |
|---|
| 249 | 266 | |
|---|
| 250 | 267 | return (result > 0 ? result : 0) * PAGE_SIZE; |
|---|
| 251 | 268 | } |
|---|
| 252 | 269 | |
|---|
| 253 | | -int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man) |
|---|
| 270 | +int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man) |
|---|
| 254 | 271 | { |
|---|
| 255 | | - struct amdgpu_gtt_mgr *mgr = man->priv; |
|---|
| 272 | + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); |
|---|
| 256 | 273 | struct amdgpu_gtt_node *node; |
|---|
| 257 | 274 | struct drm_mm_node *mm_node; |
|---|
| 258 | 275 | int r = 0; |
|---|
| .. | .. |
|---|
| 277 | 294 | * |
|---|
| 278 | 295 | * Dump the table content using printk. |
|---|
| 279 | 296 | */ |
|---|
| 280 | | -static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man, |
|---|
| 297 | +static void amdgpu_gtt_mgr_debug(struct ttm_resource_manager *man, |
|---|
| 281 | 298 | struct drm_printer *printer) |
|---|
| 282 | 299 | { |
|---|
| 283 | | - struct amdgpu_gtt_mgr *mgr = man->priv; |
|---|
| 300 | + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); |
|---|
| 284 | 301 | |
|---|
| 285 | 302 | spin_lock(&mgr->lock); |
|---|
| 286 | 303 | drm_mm_print(&mgr->mm, printer); |
|---|
| .. | .. |
|---|
| 291 | 308 | amdgpu_gtt_mgr_usage(man) >> 20); |
|---|
| 292 | 309 | } |
|---|
| 293 | 310 | |
|---|
| 294 | | -const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func = { |
|---|
| 295 | | - .init = amdgpu_gtt_mgr_init, |
|---|
| 296 | | - .takedown = amdgpu_gtt_mgr_fini, |
|---|
| 297 | | - .get_node = amdgpu_gtt_mgr_new, |
|---|
| 298 | | - .put_node = amdgpu_gtt_mgr_del, |
|---|
| 311 | +static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = { |
|---|
| 312 | + .alloc = amdgpu_gtt_mgr_new, |
|---|
| 313 | + .free = amdgpu_gtt_mgr_del, |
|---|
| 299 | 314 | .debug = amdgpu_gtt_mgr_debug |
|---|
| 300 | 315 | }; |
|---|