.. | .. |
---|
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 | }; |
---|