xref: /openbmc/linux/mm/cma_debug.c (revision 5a170e9e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * CMA DebugFS Interface
4  *
5  * Copyright (c) 2015 Sasha Levin <sasha.levin@oracle.com>
6  */
7 
8 
9 #include <linux/debugfs.h>
10 #include <linux/cma.h>
11 #include <linux/list.h>
12 #include <linux/kernel.h>
13 #include <linux/slab.h>
14 #include <linux/mm_types.h>
15 
16 #include "cma.h"
17 
18 struct cma_mem {
19 	struct hlist_node node;
20 	struct page *p;
21 	unsigned long n;
22 };
23 
24 static struct dentry *cma_debugfs_root;
25 
26 static int cma_debugfs_get(void *data, u64 *val)
27 {
28 	unsigned long *p = data;
29 
30 	*val = *p;
31 
32 	return 0;
33 }
34 DEFINE_SIMPLE_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu\n");
35 
36 static int cma_used_get(void *data, u64 *val)
37 {
38 	struct cma *cma = data;
39 	unsigned long used;
40 
41 	mutex_lock(&cma->lock);
42 	/* pages counter is smaller than sizeof(int) */
43 	used = bitmap_weight(cma->bitmap, (int)cma_bitmap_maxno(cma));
44 	mutex_unlock(&cma->lock);
45 	*val = (u64)used << cma->order_per_bit;
46 
47 	return 0;
48 }
49 DEFINE_SIMPLE_ATTRIBUTE(cma_used_fops, cma_used_get, NULL, "%llu\n");
50 
51 static int cma_maxchunk_get(void *data, u64 *val)
52 {
53 	struct cma *cma = data;
54 	unsigned long maxchunk = 0;
55 	unsigned long start, end = 0;
56 	unsigned long bitmap_maxno = cma_bitmap_maxno(cma);
57 
58 	mutex_lock(&cma->lock);
59 	for (;;) {
60 		start = find_next_zero_bit(cma->bitmap, bitmap_maxno, end);
61 		if (start >= cma->count)
62 			break;
63 		end = find_next_bit(cma->bitmap, bitmap_maxno, start);
64 		maxchunk = max(end - start, maxchunk);
65 	}
66 	mutex_unlock(&cma->lock);
67 	*val = (u64)maxchunk << cma->order_per_bit;
68 
69 	return 0;
70 }
71 DEFINE_SIMPLE_ATTRIBUTE(cma_maxchunk_fops, cma_maxchunk_get, NULL, "%llu\n");
72 
73 static void cma_add_to_cma_mem_list(struct cma *cma, struct cma_mem *mem)
74 {
75 	spin_lock(&cma->mem_head_lock);
76 	hlist_add_head(&mem->node, &cma->mem_head);
77 	spin_unlock(&cma->mem_head_lock);
78 }
79 
80 static struct cma_mem *cma_get_entry_from_list(struct cma *cma)
81 {
82 	struct cma_mem *mem = NULL;
83 
84 	spin_lock(&cma->mem_head_lock);
85 	if (!hlist_empty(&cma->mem_head)) {
86 		mem = hlist_entry(cma->mem_head.first, struct cma_mem, node);
87 		hlist_del_init(&mem->node);
88 	}
89 	spin_unlock(&cma->mem_head_lock);
90 
91 	return mem;
92 }
93 
94 static int cma_free_mem(struct cma *cma, int count)
95 {
96 	struct cma_mem *mem = NULL;
97 
98 	while (count) {
99 		mem = cma_get_entry_from_list(cma);
100 		if (mem == NULL)
101 			return 0;
102 
103 		if (mem->n <= count) {
104 			cma_release(cma, mem->p, mem->n);
105 			count -= mem->n;
106 			kfree(mem);
107 		} else if (cma->order_per_bit == 0) {
108 			cma_release(cma, mem->p, count);
109 			mem->p += count;
110 			mem->n -= count;
111 			count = 0;
112 			cma_add_to_cma_mem_list(cma, mem);
113 		} else {
114 			pr_debug("cma: cannot release partial block when order_per_bit != 0\n");
115 			cma_add_to_cma_mem_list(cma, mem);
116 			break;
117 		}
118 	}
119 
120 	return 0;
121 
122 }
123 
124 static int cma_free_write(void *data, u64 val)
125 {
126 	int pages = val;
127 	struct cma *cma = data;
128 
129 	return cma_free_mem(cma, pages);
130 }
131 DEFINE_SIMPLE_ATTRIBUTE(cma_free_fops, NULL, cma_free_write, "%llu\n");
132 
133 static int cma_alloc_mem(struct cma *cma, int count)
134 {
135 	struct cma_mem *mem;
136 	struct page *p;
137 
138 	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
139 	if (!mem)
140 		return -ENOMEM;
141 
142 	p = cma_alloc(cma, count, 0, false);
143 	if (!p) {
144 		kfree(mem);
145 		return -ENOMEM;
146 	}
147 
148 	mem->p = p;
149 	mem->n = count;
150 
151 	cma_add_to_cma_mem_list(cma, mem);
152 
153 	return 0;
154 }
155 
156 static int cma_alloc_write(void *data, u64 val)
157 {
158 	int pages = val;
159 	struct cma *cma = data;
160 
161 	return cma_alloc_mem(cma, pages);
162 }
163 DEFINE_SIMPLE_ATTRIBUTE(cma_alloc_fops, NULL, cma_alloc_write, "%llu\n");
164 
165 static void cma_debugfs_add_one(struct cma *cma, int idx)
166 {
167 	struct dentry *tmp;
168 	char name[16];
169 	int u32s;
170 
171 	scnprintf(name, sizeof(name), "cma-%s", cma->name);
172 
173 	tmp = debugfs_create_dir(name, cma_debugfs_root);
174 
175 	debugfs_create_file("alloc", 0200, tmp, cma, &cma_alloc_fops);
176 	debugfs_create_file("free", 0200, tmp, cma, &cma_free_fops);
177 	debugfs_create_file("base_pfn", 0444, tmp,
178 			    &cma->base_pfn, &cma_debugfs_fops);
179 	debugfs_create_file("count", 0444, tmp, &cma->count, &cma_debugfs_fops);
180 	debugfs_create_file("order_per_bit", 0444, tmp,
181 			    &cma->order_per_bit, &cma_debugfs_fops);
182 	debugfs_create_file("used", 0444, tmp, cma, &cma_used_fops);
183 	debugfs_create_file("maxchunk", 0444, tmp, cma, &cma_maxchunk_fops);
184 
185 	u32s = DIV_ROUND_UP(cma_bitmap_maxno(cma), BITS_PER_BYTE * sizeof(u32));
186 	debugfs_create_u32_array("bitmap", 0444, tmp, (u32 *)cma->bitmap, u32s);
187 }
188 
189 static int __init cma_debugfs_init(void)
190 {
191 	int i;
192 
193 	cma_debugfs_root = debugfs_create_dir("cma", NULL);
194 	if (!cma_debugfs_root)
195 		return -ENOMEM;
196 
197 	for (i = 0; i < cma_area_count; i++)
198 		cma_debugfs_add_one(&cma_areas[i], i);
199 
200 	return 0;
201 }
202 late_initcall(cma_debugfs_init);
203