1/*	$NetBSD: amdgpu_vram_mgr.c,v 1.4 2021/12/19 12:31:45 riastradh Exp $	*/
2
3/*
4 * Copyright 2016 Advanced Micro Devices, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors: Christian K��nig
25 */
26
27#include <sys/cdefs.h>
28__KERNEL_RCSID(0, "$NetBSD: amdgpu_vram_mgr.c,v 1.4 2021/12/19 12:31:45 riastradh Exp $");
29
30#include "amdgpu.h"
31#include "amdgpu_vm.h"
32#include "amdgpu_atomfirmware.h"
33#include "atom.h"
34
35struct amdgpu_vram_mgr {
36	struct drm_mm mm;
37	spinlock_t lock;
38	atomic64_t usage;
39	atomic64_t vis_usage;
40};
41
42#ifndef __NetBSD__		/* XXX amdgpu sysfs */
43
44/**
45 * DOC: mem_info_vram_total
46 *
47 * The amdgpu driver provides a sysfs API for reporting current total VRAM
48 * available on the device
49 * The file mem_info_vram_total is used for this and returns the total
50 * amount of VRAM in bytes
51 */
52static ssize_t amdgpu_mem_info_vram_total_show(struct device *dev,
53		struct device_attribute *attr, char *buf)
54{
55	struct drm_device *ddev = dev_get_drvdata(dev);
56	struct amdgpu_device *adev = ddev->dev_private;
57
58	return snprintf(buf, PAGE_SIZE, "%llu\n", adev->gmc.real_vram_size);
59}
60
61/**
62 * DOC: mem_info_vis_vram_total
63 *
64 * The amdgpu driver provides a sysfs API for reporting current total
65 * visible VRAM available on the device
66 * The file mem_info_vis_vram_total is used for this and returns the total
67 * amount of visible VRAM in bytes
68 */
69static ssize_t amdgpu_mem_info_vis_vram_total_show(struct device *dev,
70		struct device_attribute *attr, char *buf)
71{
72	struct drm_device *ddev = dev_get_drvdata(dev);
73	struct amdgpu_device *adev = ddev->dev_private;
74
75	return snprintf(buf, PAGE_SIZE, "%llu\n", adev->gmc.visible_vram_size);
76}
77
78/**
79 * DOC: mem_info_vram_used
80 *
81 * The amdgpu driver provides a sysfs API for reporting current total VRAM
82 * available on the device
83 * The file mem_info_vram_used is used for this and returns the total
84 * amount of currently used VRAM in bytes
85 */
86static ssize_t amdgpu_mem_info_vram_used_show(struct device *dev,
87		struct device_attribute *attr, char *buf)
88{
89	struct drm_device *ddev = dev_get_drvdata(dev);
90	struct amdgpu_device *adev = ddev->dev_private;
91
92	return snprintf(buf, PAGE_SIZE, "%llu\n",
93		amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]));
94}
95
96/**
97 * DOC: mem_info_vis_vram_used
98 *
99 * The amdgpu driver provides a sysfs API for reporting current total of
100 * used visible VRAM
101 * The file mem_info_vis_vram_used is used for this and returns the total
102 * amount of currently used visible VRAM in bytes
103 */
104static ssize_t amdgpu_mem_info_vis_vram_used_show(struct device *dev,
105		struct device_attribute *attr, char *buf)
106{
107	struct drm_device *ddev = dev_get_drvdata(dev);
108	struct amdgpu_device *adev = ddev->dev_private;
109
110	return snprintf(buf, PAGE_SIZE, "%llu\n",
111		amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]));
112}
113
114static ssize_t amdgpu_mem_info_vram_vendor(struct device *dev,
115						 struct device_attribute *attr,
116						 char *buf)
117{
118	struct drm_device *ddev = dev_get_drvdata(dev);
119	struct amdgpu_device *adev = ddev->dev_private;
120
121	switch (adev->gmc.vram_vendor) {
122	case SAMSUNG:
123		return snprintf(buf, PAGE_SIZE, "samsung\n");
124	case INFINEON:
125		return snprintf(buf, PAGE_SIZE, "infineon\n");
126	case ELPIDA:
127		return snprintf(buf, PAGE_SIZE, "elpida\n");
128	case ETRON:
129		return snprintf(buf, PAGE_SIZE, "etron\n");
130	case NANYA:
131		return snprintf(buf, PAGE_SIZE, "nanya\n");
132	case HYNIX:
133		return snprintf(buf, PAGE_SIZE, "hynix\n");
134	case MOSEL:
135		return snprintf(buf, PAGE_SIZE, "mosel\n");
136	case WINBOND:
137		return snprintf(buf, PAGE_SIZE, "winbond\n");
138	case ESMT:
139		return snprintf(buf, PAGE_SIZE, "esmt\n");
140	case MICRON:
141		return snprintf(buf, PAGE_SIZE, "micron\n");
142	default:
143		return snprintf(buf, PAGE_SIZE, "unknown\n");
144	}
145}
146
147static DEVICE_ATTR(mem_info_vram_total, S_IRUGO,
148		   amdgpu_mem_info_vram_total_show, NULL);
149static DEVICE_ATTR(mem_info_vis_vram_total, S_IRUGO,
150		   amdgpu_mem_info_vis_vram_total_show,NULL);
151static DEVICE_ATTR(mem_info_vram_used, S_IRUGO,
152		   amdgpu_mem_info_vram_used_show, NULL);
153static DEVICE_ATTR(mem_info_vis_vram_used, S_IRUGO,
154		   amdgpu_mem_info_vis_vram_used_show, NULL);
155static DEVICE_ATTR(mem_info_vram_vendor, S_IRUGO,
156		   amdgpu_mem_info_vram_vendor, NULL);
157
158#endif	/* __NetBSD__ */
159
160/**
161 * amdgpu_vram_mgr_init - init VRAM manager and DRM MM
162 *
163 * @man: TTM memory type manager
164 * @p_size: maximum size of VRAM
165 *
166 * Allocate and initialize the VRAM manager.
167 */
168static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man,
169				unsigned long p_size)
170{
171	struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
172	struct amdgpu_vram_mgr *mgr;
173	int ret;
174
175	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
176	if (!mgr)
177		return -ENOMEM;
178
179	drm_mm_init(&mgr->mm, 0, p_size);
180	spin_lock_init(&mgr->lock);
181	man->priv = mgr;
182
183#ifdef __NetBSD__	     /* XXX amdgpu sysfs */
184	__USE(adev);
185	__USE(ret);
186#else
187	/* Add the two VRAM-related sysfs files */
188	ret = device_create_file(adev->dev, &dev_attr_mem_info_vram_total);
189	if (ret) {
190		DRM_ERROR("Failed to create device file mem_info_vram_total\n");
191		return ret;
192	}
193	ret = device_create_file(adev->dev, &dev_attr_mem_info_vis_vram_total);
194	if (ret) {
195		DRM_ERROR("Failed to create device file mem_info_vis_vram_total\n");
196		return ret;
197	}
198	ret = device_create_file(adev->dev, &dev_attr_mem_info_vram_used);
199	if (ret) {
200		DRM_ERROR("Failed to create device file mem_info_vram_used\n");
201		return ret;
202	}
203	ret = device_create_file(adev->dev, &dev_attr_mem_info_vis_vram_used);
204	if (ret) {
205		DRM_ERROR("Failed to create device file mem_info_vis_vram_used\n");
206		return ret;
207	}
208	ret = device_create_file(adev->dev, &dev_attr_mem_info_vram_vendor);
209	if (ret) {
210		DRM_ERROR("Failed to create device file mem_info_vram_vendor\n");
211		return ret;
212	}
213#endif	/* __NetBSD__ */
214
215	return 0;
216}
217
218/**
219 * amdgpu_vram_mgr_fini - free and destroy VRAM manager
220 *
221 * @man: TTM memory type manager
222 *
223 * Destroy and free the VRAM manager, returns -EBUSY if ranges are still
224 * allocated inside it.
225 */
226static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man)
227{
228	struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
229	struct amdgpu_vram_mgr *mgr = man->priv;
230
231	spin_lock(&mgr->lock);
232	drm_mm_takedown(&mgr->mm);
233	spin_unlock(&mgr->lock);
234	spin_lock_destroy(&mgr->lock);
235	kfree(mgr);
236	man->priv = NULL;
237#ifdef __NetBSD__		/* XXX amdgpu sysfs */
238	__USE(adev);
239#else
240	device_remove_file(adev->dev, &dev_attr_mem_info_vram_total);
241	device_remove_file(adev->dev, &dev_attr_mem_info_vis_vram_total);
242	device_remove_file(adev->dev, &dev_attr_mem_info_vram_used);
243	device_remove_file(adev->dev, &dev_attr_mem_info_vis_vram_used);
244	device_remove_file(adev->dev, &dev_attr_mem_info_vram_vendor);
245#endif
246	return 0;
247}
248
249/**
250 * amdgpu_vram_mgr_vis_size - Calculate visible node size
251 *
252 * @adev: amdgpu device structure
253 * @node: MM node structure
254 *
255 * Calculate how many bytes of the MM node are inside visible VRAM
256 */
257static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
258				    struct drm_mm_node *node)
259{
260	uint64_t start = node->start << PAGE_SHIFT;
261	uint64_t end = (node->size + node->start) << PAGE_SHIFT;
262
263	if (start >= adev->gmc.visible_vram_size)
264		return 0;
265
266	return (end > adev->gmc.visible_vram_size ?
267		adev->gmc.visible_vram_size : end) - start;
268}
269
270/**
271 * amdgpu_vram_mgr_bo_visible_size - CPU visible BO size
272 *
273 * @bo: &amdgpu_bo buffer object (must be in VRAM)
274 *
275 * Returns:
276 * How much of the given &amdgpu_bo buffer object lies in CPU visible VRAM.
277 */
278u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
279{
280	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
281	struct ttm_mem_reg *mem = &bo->tbo.mem;
282	struct drm_mm_node *nodes = mem->mm_node;
283	unsigned pages = mem->num_pages;
284	u64 usage;
285
286	if (amdgpu_gmc_vram_full_visible(&adev->gmc))
287		return amdgpu_bo_size(bo);
288
289	if (mem->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT)
290		return 0;
291
292	for (usage = 0; nodes && pages; pages -= nodes->size, nodes++)
293		usage += amdgpu_vram_mgr_vis_size(adev, nodes);
294
295	return usage;
296}
297
298/**
299 * amdgpu_vram_mgr_virt_start - update virtual start address
300 *
301 * @mem: ttm_mem_reg to update
302 * @node: just allocated node
303 *
304 * Calculate a virtual BO start address to easily check if everything is CPU
305 * accessible.
306 */
307static void amdgpu_vram_mgr_virt_start(struct ttm_mem_reg *mem,
308				       struct drm_mm_node *node)
309{
310	unsigned long start;
311
312	start = node->start + node->size;
313	if (start > mem->num_pages)
314		start -= mem->num_pages;
315	else
316		start = 0;
317	mem->start = max(mem->start, start);
318}
319
320/**
321 * amdgpu_vram_mgr_new - allocate new ranges
322 *
323 * @man: TTM memory type manager
324 * @tbo: TTM BO we need this range for
325 * @place: placement flags and restrictions
326 * @mem: the resulting mem object
327 *
328 * Allocate VRAM for the given BO.
329 */
330static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man,
331			       struct ttm_buffer_object *tbo,
332			       const struct ttm_place *place,
333			       struct ttm_mem_reg *mem)
334{
335	struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
336	struct amdgpu_vram_mgr *mgr = man->priv;
337	struct drm_mm *mm = &mgr->mm;
338	struct drm_mm_node *nodes;
339	enum drm_mm_insert_mode mode;
340	unsigned long lpfn, num_nodes, pages_per_node, pages_left;
341	uint64_t vis_usage = 0, mem_bytes, max_bytes;
342	unsigned i;
343	int r;
344
345	lpfn = place->lpfn;
346	if (!lpfn)
347		lpfn = man->size;
348
349	max_bytes = adev->gmc.mc_vram_size;
350	if (tbo->type != ttm_bo_type_kernel)
351		max_bytes -= AMDGPU_VM_RESERVED_VRAM;
352
353	/* bail out quickly if there's likely not enough VRAM for this BO */
354	mem_bytes = (u64)mem->num_pages << PAGE_SHIFT;
355	if (atomic64_add_return(mem_bytes, &mgr->usage) > max_bytes) {
356		atomic64_sub(mem_bytes, &mgr->usage);
357		mem->mm_node = NULL;
358		return 0;
359	}
360
361	if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
362		pages_per_node = ~0ul;
363		num_nodes = 1;
364	} else {
365#ifdef CONFIG_TRANSPARENT_HUGEPAGE
366		pages_per_node = HPAGE_PMD_NR;
367#else
368		/* default to 2MB */
369		pages_per_node = (2UL << (20UL - PAGE_SHIFT));
370#endif
371		pages_per_node = max((uint32_t)pages_per_node, mem->page_alignment);
372		num_nodes = DIV_ROUND_UP(mem->num_pages, pages_per_node);
373	}
374
375	nodes = kvmalloc_array((uint32_t)num_nodes, sizeof(*nodes),
376			       GFP_KERNEL | __GFP_ZERO);
377	if (!nodes) {
378		atomic64_sub(mem_bytes, &mgr->usage);
379		return -ENOMEM;
380	}
381
382	mode = DRM_MM_INSERT_BEST;
383	if (place->flags & TTM_PL_FLAG_TOPDOWN)
384		mode = DRM_MM_INSERT_HIGH;
385
386	mem->start = 0;
387	pages_left = mem->num_pages;
388
389	spin_lock(&mgr->lock);
390	for (i = 0; pages_left >= pages_per_node; ++i) {
391		unsigned long pages = rounddown_pow_of_two(pages_left);
392
393		r = drm_mm_insert_node_in_range(mm, &nodes[i], pages,
394						pages_per_node, 0,
395						place->fpfn, lpfn,
396						mode);
397		if (unlikely(r))
398			break;
399
400		vis_usage += amdgpu_vram_mgr_vis_size(adev, &nodes[i]);
401		amdgpu_vram_mgr_virt_start(mem, &nodes[i]);
402		pages_left -= pages;
403	}
404
405	for (; pages_left; ++i) {
406		unsigned long pages = min(pages_left, pages_per_node);
407		uint32_t alignment = mem->page_alignment;
408
409		if (pages == pages_per_node)
410			alignment = pages_per_node;
411
412		r = drm_mm_insert_node_in_range(mm, &nodes[i],
413						pages, alignment, 0,
414						place->fpfn, lpfn,
415						mode);
416		if (unlikely(r))
417			goto error;
418
419		vis_usage += amdgpu_vram_mgr_vis_size(adev, &nodes[i]);
420		amdgpu_vram_mgr_virt_start(mem, &nodes[i]);
421		pages_left -= pages;
422	}
423	spin_unlock(&mgr->lock);
424
425	atomic64_add(vis_usage, &mgr->vis_usage);
426
427	mem->mm_node = nodes;
428
429	return 0;
430
431error:
432	while (i--)
433		drm_mm_remove_node(&nodes[i]);
434	spin_unlock(&mgr->lock);
435	atomic64_sub(mem->num_pages << PAGE_SHIFT, &mgr->usage);
436
437	kvfree(nodes);
438	return r == -ENOSPC ? 0 : r;
439}
440
441/**
442 * amdgpu_vram_mgr_del - free ranges
443 *
444 * @man: TTM memory type manager
445 * @tbo: TTM BO we need this range for
446 * @place: placement flags and restrictions
447 * @mem: TTM memory object
448 *
449 * Free the allocated VRAM again.
450 */
451static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man,
452				struct ttm_mem_reg *mem)
453{
454	struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
455	struct amdgpu_vram_mgr *mgr = man->priv;
456	struct drm_mm_node *nodes = mem->mm_node;
457	uint64_t usage = 0, vis_usage = 0;
458	unsigned pages = mem->num_pages;
459
460	if (!mem->mm_node)
461		return;
462
463	spin_lock(&mgr->lock);
464	while (pages) {
465		pages -= nodes->size;
466		drm_mm_remove_node(nodes);
467		usage += nodes->size << PAGE_SHIFT;
468		vis_usage += amdgpu_vram_mgr_vis_size(adev, nodes);
469		++nodes;
470	}
471	spin_unlock(&mgr->lock);
472
473	atomic64_sub(usage, &mgr->usage);
474	atomic64_sub(vis_usage, &mgr->vis_usage);
475
476	kvfree(mem->mm_node);
477	mem->mm_node = NULL;
478}
479
480/**
481 * amdgpu_vram_mgr_usage - how many bytes are used in this domain
482 *
483 * @man: TTM memory type manager
484 *
485 * Returns how many bytes are used in this domain.
486 */
487uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man)
488{
489	struct amdgpu_vram_mgr *mgr = man->priv;
490
491	return atomic64_read(&mgr->usage);
492}
493
494/**
495 * amdgpu_vram_mgr_vis_usage - how many bytes are used in the visible part
496 *
497 * @man: TTM memory type manager
498 *
499 * Returns how many bytes are used in the visible part of VRAM
500 */
501uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man)
502{
503	struct amdgpu_vram_mgr *mgr = man->priv;
504
505	return atomic64_read(&mgr->vis_usage);
506}
507
508/**
509 * amdgpu_vram_mgr_debug - dump VRAM table
510 *
511 * @man: TTM memory type manager
512 * @printer: DRM printer to use
513 *
514 * Dump the table content using printk.
515 */
516static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man,
517				  struct drm_printer *printer)
518{
519	struct amdgpu_vram_mgr *mgr = man->priv;
520
521	spin_lock(&mgr->lock);
522	drm_mm_print(&mgr->mm, printer);
523	spin_unlock(&mgr->lock);
524
525	drm_printf(printer, "man size:%"PRIu64" pages, ram usage:%"PRIu64"MB, vis usage:%"PRIu64"MB\n",
526		   man->size, amdgpu_vram_mgr_usage(man) >> 20,
527		   amdgpu_vram_mgr_vis_usage(man) >> 20);
528}
529
530const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = {
531	.init		= amdgpu_vram_mgr_init,
532	.takedown	= amdgpu_vram_mgr_fini,
533	.get_node	= amdgpu_vram_mgr_new,
534	.put_node	= amdgpu_vram_mgr_del,
535	.debug		= amdgpu_vram_mgr_debug
536};
537