Line data Source code
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/ttm/ttm_range_manager.h>
26 :
27 : #include "amdgpu.h"
28 :
29 : static inline struct amdgpu_gtt_mgr *
30 : to_gtt_mgr(struct ttm_resource_manager *man)
31 : {
32 0 : return container_of(man, struct amdgpu_gtt_mgr, manager);
33 : }
34 :
35 : /**
36 : * DOC: mem_info_gtt_total
37 : *
38 : * The amdgpu driver provides a sysfs API for reporting current total size of
39 : * the GTT.
40 : * The file mem_info_gtt_total is used for this, and returns the total size of
41 : * the GTT block, in bytes
42 : */
43 0 : static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev,
44 : struct device_attribute *attr,
45 : char *buf)
46 : {
47 0 : struct drm_device *ddev = dev_get_drvdata(dev);
48 0 : struct amdgpu_device *adev = drm_to_adev(ddev);
49 : struct ttm_resource_manager *man;
50 :
51 0 : man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
52 0 : return sysfs_emit(buf, "%llu\n", man->size);
53 : }
54 :
55 : /**
56 : * DOC: mem_info_gtt_used
57 : *
58 : * The amdgpu driver provides a sysfs API for reporting current total amount of
59 : * used GTT.
60 : * The file mem_info_gtt_used is used for this, and returns the current used
61 : * size of the GTT block, in bytes
62 : */
63 0 : static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev,
64 : struct device_attribute *attr,
65 : char *buf)
66 : {
67 0 : struct drm_device *ddev = dev_get_drvdata(dev);
68 0 : struct amdgpu_device *adev = drm_to_adev(ddev);
69 0 : struct ttm_resource_manager *man = &adev->mman.gtt_mgr.manager;
70 :
71 0 : return sysfs_emit(buf, "%llu\n", ttm_resource_manager_usage(man));
72 : }
73 :
74 : static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO,
75 : amdgpu_mem_info_gtt_total_show, NULL);
76 : static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO,
77 : amdgpu_mem_info_gtt_used_show, NULL);
78 :
79 : static struct attribute *amdgpu_gtt_mgr_attributes[] = {
80 : &dev_attr_mem_info_gtt_total.attr,
81 : &dev_attr_mem_info_gtt_used.attr,
82 : NULL
83 : };
84 :
85 : const struct attribute_group amdgpu_gtt_mgr_attr_group = {
86 : .attrs = amdgpu_gtt_mgr_attributes
87 : };
88 :
89 : /**
90 : * amdgpu_gtt_mgr_has_gart_addr - Check if mem has address space
91 : *
92 : * @res: the mem object to check
93 : *
94 : * Check if a mem object has already address space allocated.
95 : */
96 0 : bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *res)
97 : {
98 0 : struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
99 :
100 0 : return drm_mm_node_allocated(&node->mm_nodes[0]);
101 : }
102 :
103 : /**
104 : * amdgpu_gtt_mgr_new - allocate a new node
105 : *
106 : * @man: TTM memory type manager
107 : * @tbo: TTM BO we need this range for
108 : * @place: placement flags and restrictions
109 : * @res: the resulting mem object
110 : *
111 : * Dummy, allocate the node but no space for it yet.
112 : */
113 0 : static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
114 : struct ttm_buffer_object *tbo,
115 : const struct ttm_place *place,
116 : struct ttm_resource **res)
117 : {
118 0 : struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
119 0 : uint32_t num_pages = PFN_UP(tbo->base.size);
120 : struct ttm_range_mgr_node *node;
121 : int r;
122 :
123 0 : node = kzalloc(struct_size(node, mm_nodes, 1), GFP_KERNEL);
124 0 : if (!node)
125 : return -ENOMEM;
126 :
127 0 : ttm_resource_init(tbo, place, &node->base);
128 0 : if (!(place->flags & TTM_PL_FLAG_TEMPORARY) &&
129 0 : ttm_resource_manager_usage(man) > man->size) {
130 : r = -ENOSPC;
131 : goto err_free;
132 : }
133 :
134 0 : if (place->lpfn) {
135 0 : spin_lock(&mgr->lock);
136 0 : r = drm_mm_insert_node_in_range(&mgr->mm, &node->mm_nodes[0],
137 0 : num_pages, tbo->page_alignment,
138 0 : 0, place->fpfn, place->lpfn,
139 : DRM_MM_INSERT_BEST);
140 0 : spin_unlock(&mgr->lock);
141 0 : if (unlikely(r))
142 : goto err_free;
143 :
144 0 : node->base.start = node->mm_nodes[0].start;
145 : } else {
146 0 : node->mm_nodes[0].start = 0;
147 0 : node->mm_nodes[0].size = node->base.num_pages;
148 0 : node->base.start = AMDGPU_BO_INVALID_OFFSET;
149 : }
150 :
151 0 : *res = &node->base;
152 0 : return 0;
153 :
154 : err_free:
155 0 : ttm_resource_fini(man, &node->base);
156 0 : kfree(node);
157 0 : return r;
158 : }
159 :
160 : /**
161 : * amdgpu_gtt_mgr_del - free ranges
162 : *
163 : * @man: TTM memory type manager
164 : * @res: TTM memory object
165 : *
166 : * Free the allocated GTT again.
167 : */
168 0 : static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man,
169 : struct ttm_resource *res)
170 : {
171 0 : struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
172 0 : struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
173 :
174 0 : spin_lock(&mgr->lock);
175 0 : if (drm_mm_node_allocated(&node->mm_nodes[0]))
176 0 : drm_mm_remove_node(&node->mm_nodes[0]);
177 0 : spin_unlock(&mgr->lock);
178 :
179 0 : ttm_resource_fini(man, res);
180 0 : kfree(node);
181 0 : }
182 :
183 : /**
184 : * amdgpu_gtt_mgr_recover - re-init gart
185 : *
186 : * @mgr: amdgpu_gtt_mgr pointer
187 : *
188 : * Re-init the gart for each known BO in the GTT.
189 : */
190 0 : void amdgpu_gtt_mgr_recover(struct amdgpu_gtt_mgr *mgr)
191 : {
192 : struct ttm_range_mgr_node *node;
193 : struct drm_mm_node *mm_node;
194 : struct amdgpu_device *adev;
195 :
196 0 : adev = container_of(mgr, typeof(*adev), mman.gtt_mgr);
197 0 : spin_lock(&mgr->lock);
198 0 : drm_mm_for_each_node(mm_node, &mgr->mm) {
199 0 : node = container_of(mm_node, typeof(*node), mm_nodes[0]);
200 0 : amdgpu_ttm_recover_gart(node->base.bo);
201 : }
202 0 : spin_unlock(&mgr->lock);
203 :
204 0 : amdgpu_gart_invalidate_tlb(adev);
205 0 : }
206 :
207 : /**
208 : * amdgpu_gtt_mgr_debug - dump VRAM table
209 : *
210 : * @man: TTM memory type manager
211 : * @printer: DRM printer to use
212 : *
213 : * Dump the table content using printk.
214 : */
215 0 : static void amdgpu_gtt_mgr_debug(struct ttm_resource_manager *man,
216 : struct drm_printer *printer)
217 : {
218 0 : struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
219 :
220 0 : spin_lock(&mgr->lock);
221 0 : drm_mm_print(&mgr->mm, printer);
222 0 : spin_unlock(&mgr->lock);
223 0 : }
224 :
225 : static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = {
226 : .alloc = amdgpu_gtt_mgr_new,
227 : .free = amdgpu_gtt_mgr_del,
228 : .debug = amdgpu_gtt_mgr_debug
229 : };
230 :
231 : /**
232 : * amdgpu_gtt_mgr_init - init GTT manager and DRM MM
233 : *
234 : * @adev: amdgpu_device pointer
235 : * @gtt_size: maximum size of GTT
236 : *
237 : * Allocate and initialize the GTT manager.
238 : */
239 0 : int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size)
240 : {
241 0 : struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;
242 0 : struct ttm_resource_manager *man = &mgr->manager;
243 : uint64_t start, size;
244 :
245 0 : man->use_tt = true;
246 0 : man->func = &amdgpu_gtt_mgr_func;
247 :
248 0 : ttm_resource_manager_init(man, &adev->mman.bdev, gtt_size);
249 :
250 0 : start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS;
251 0 : size = (adev->gmc.gart_size >> PAGE_SHIFT) - start;
252 0 : drm_mm_init(&mgr->mm, start, size);
253 0 : spin_lock_init(&mgr->lock);
254 :
255 0 : ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, &mgr->manager);
256 0 : ttm_resource_manager_set_used(man, true);
257 0 : return 0;
258 : }
259 :
260 : /**
261 : * amdgpu_gtt_mgr_fini - free and destroy GTT manager
262 : *
263 : * @adev: amdgpu_device pointer
264 : *
265 : * Destroy and free the GTT manager, returns -EBUSY if ranges are still
266 : * allocated inside it.
267 : */
268 0 : void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev)
269 : {
270 0 : struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;
271 0 : struct ttm_resource_manager *man = &mgr->manager;
272 : int ret;
273 :
274 0 : ttm_resource_manager_set_used(man, false);
275 :
276 0 : ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
277 0 : if (ret)
278 : return;
279 :
280 0 : spin_lock(&mgr->lock);
281 0 : drm_mm_takedown(&mgr->mm);
282 0 : spin_unlock(&mgr->lock);
283 :
284 0 : ttm_resource_manager_cleanup(man);
285 0 : ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, NULL);
286 : }
|