Blame view

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