Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amdgpu: add VRAM manager v2

Split VRAM allocations into 4MB blocks.

v2: fix typo in comment, some suggested cleanups
v3: document how to disable the feature, fix rebase issue

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Edward O'Callaghan <funfunctor@folklore1984.net>
Tested-by: Mike Lothian <mike@fireburn.co.uk>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Christian König and committed by
Alex Deucher
6a7f76e7 8892f153

+237 -2
+1 -1
drivers/gpu/drm/amd/amdgpu/Makefile
··· 24 24 atombios_encoders.o amdgpu_sa.o atombios_i2c.o \ 25 25 amdgpu_prime.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \ 26 26 amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \ 27 - amdgpu_gtt_mgr.o 27 + amdgpu_gtt_mgr.o amdgpu_vram_mgr.o 28 28 29 29 # add asic specific block 30 30 amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
+1
drivers/gpu/drm/amd/amdgpu/amdgpu.h
··· 97 97 extern int amdgpu_sclk_deep_sleep_en; 98 98 extern char *amdgpu_virtual_display; 99 99 extern unsigned amdgpu_pp_feature_mask; 100 + extern int amdgpu_vram_page_split; 100 101 101 102 #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000 102 103 #define AMDGPU_MAX_USEC_TIMEOUT 100000 /* 100 ms */
+7
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
··· 1052 1052 amdgpu_vm_block_size); 1053 1053 amdgpu_vm_block_size = 9; 1054 1054 } 1055 + 1056 + if ((amdgpu_vram_page_split != -1 && amdgpu_vram_page_split < 16) || 1057 + !amdgpu_check_pot_argument(amdgpu_vram_page_split)) { 1058 + dev_warn(adev->dev, "invalid VRAM page split (%d)\n", 1059 + amdgpu_vram_page_split); 1060 + amdgpu_vram_page_split = 1024; 1061 + } 1055 1062 } 1056 1063 1057 1064 /**
+4
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
··· 85 85 int amdgpu_vm_block_size = -1; 86 86 int amdgpu_vm_fault_stop = 0; 87 87 int amdgpu_vm_debug = 0; 88 + int amdgpu_vram_page_split = 1024; 88 89 int amdgpu_exp_hw_support = 0; 89 90 int amdgpu_sched_jobs = 32; 90 91 int amdgpu_sched_hw_submission = 2; ··· 165 164 166 165 MODULE_PARM_DESC(vm_debug, "Debug VM handling (0 = disabled (default), 1 = enabled)"); 167 166 module_param_named(vm_debug, amdgpu_vm_debug, int, 0644); 167 + 168 + MODULE_PARM_DESC(vram_page_split, "Number of pages after we split VRAM allocations (default 1024, -1 = disable)"); 169 + module_param_named(vram_page_split, amdgpu_vram_page_split, int, 0444); 168 170 169 171 MODULE_PARM_DESC(exp_hw_support, "experimental hw support (1 = enable, 0 = disable (default))"); 170 172 module_param_named(exp_hw_support, amdgpu_exp_hw_support, int, 0444);
+1 -1
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
··· 168 168 break; 169 169 case TTM_PL_VRAM: 170 170 /* "On-card" video ram */ 171 - man->func = &ttm_bo_manager_func; 171 + man->func = &amdgpu_vram_mgr_func; 172 172 man->gpu_offset = adev->mc.vram_start; 173 173 man->flags = TTM_MEMTYPE_FLAG_FIXED | 174 174 TTM_MEMTYPE_FLAG_MAPPABLE;
+1
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
··· 66 66 }; 67 67 68 68 extern const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func; 69 + extern const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func; 69 70 70 71 int amdgpu_gtt_mgr_alloc(struct ttm_mem_type_manager *man, 71 72 struct ttm_buffer_object *tbo,
+222
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
··· 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_search_flags sflags = DRM_MM_SEARCH_DEFAULT; 101 + enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT; 102 + unsigned long lpfn, num_nodes, pages_per_node, pages_left; 103 + unsigned i; 104 + int r; 105 + 106 + lpfn = place->lpfn; 107 + if (!lpfn) 108 + lpfn = man->size; 109 + 110 + if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS || 111 + amdgpu_vram_page_split == -1) { 112 + pages_per_node = ~0ul; 113 + num_nodes = 1; 114 + } else { 115 + pages_per_node = max((uint32_t)amdgpu_vram_page_split, 116 + mem->page_alignment); 117 + num_nodes = DIV_ROUND_UP(mem->num_pages, pages_per_node); 118 + } 119 + 120 + nodes = kcalloc(num_nodes, sizeof(*nodes), GFP_KERNEL); 121 + if (!nodes) 122 + return -ENOMEM; 123 + 124 + if (place->flags & TTM_PL_FLAG_TOPDOWN) { 125 + sflags = DRM_MM_SEARCH_BELOW; 126 + aflags = DRM_MM_CREATE_TOP; 127 + } 128 + 129 + pages_left = mem->num_pages; 130 + 131 + spin_lock(&mgr->lock); 132 + for (i = 0; i < num_nodes; ++i) { 133 + unsigned long pages = min(pages_left, pages_per_node); 134 + uint32_t alignment = mem->page_alignment; 135 + 136 + if (pages == pages_per_node) 137 + alignment = pages_per_node; 138 + else 139 + sflags |= DRM_MM_SEARCH_BEST; 140 + 141 + r = drm_mm_insert_node_in_range_generic(mm, &nodes[i], pages, 142 + alignment, 0, 143 + place->fpfn, lpfn, 144 + sflags, aflags); 145 + if (unlikely(r)) 146 + goto error; 147 + 148 + pages_left -= pages; 149 + } 150 + spin_unlock(&mgr->lock); 151 + 152 + mem->start = num_nodes == 1 ? nodes[0].start : AMDGPU_BO_INVALID_OFFSET; 153 + mem->mm_node = nodes; 154 + 155 + return 0; 156 + 157 + error: 158 + while (i--) 159 + drm_mm_remove_node(&nodes[i]); 160 + spin_unlock(&mgr->lock); 161 + 162 + kfree(nodes); 163 + return r == -ENOSPC ? 0 : r; 164 + } 165 + 166 + /** 167 + * amdgpu_vram_mgr_del - free ranges 168 + * 169 + * @man: TTM memory type manager 170 + * @tbo: TTM BO we need this range for 171 + * @place: placement flags and restrictions 172 + * @mem: TTM memory object 173 + * 174 + * Free the allocated VRAM again. 175 + */ 176 + static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man, 177 + struct ttm_mem_reg *mem) 178 + { 179 + struct amdgpu_vram_mgr *mgr = man->priv; 180 + struct drm_mm_node *nodes = mem->mm_node; 181 + unsigned pages = mem->num_pages; 182 + 183 + if (!mem->mm_node) 184 + return; 185 + 186 + spin_lock(&mgr->lock); 187 + while (pages) { 188 + pages -= nodes->size; 189 + drm_mm_remove_node(nodes); 190 + ++nodes; 191 + } 192 + spin_unlock(&mgr->lock); 193 + 194 + kfree(mem->mm_node); 195 + mem->mm_node = NULL; 196 + } 197 + 198 + /** 199 + * amdgpu_vram_mgr_debug - dump VRAM table 200 + * 201 + * @man: TTM memory type manager 202 + * @prefix: text prefix 203 + * 204 + * Dump the table content using printk. 205 + */ 206 + static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man, 207 + const char *prefix) 208 + { 209 + struct amdgpu_vram_mgr *mgr = man->priv; 210 + 211 + spin_lock(&mgr->lock); 212 + drm_mm_debug_table(&mgr->mm, prefix); 213 + spin_unlock(&mgr->lock); 214 + } 215 + 216 + const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = { 217 + amdgpu_vram_mgr_init, 218 + amdgpu_vram_mgr_fini, 219 + amdgpu_vram_mgr_new, 220 + amdgpu_vram_mgr_del, 221 + amdgpu_vram_mgr_debug 222 + };