1 // SPDX-License-Identifier: GPL-2.0
3 * CMA DebugFS Interface
5 * Copyright (c) 2015 Sasha Levin <sasha.levin@oracle.com>
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>
19 struct hlist_node node
;
24 static int cma_debugfs_get(void *data
, u64
*val
)
26 unsigned long *p
= data
;
32 DEFINE_DEBUGFS_ATTRIBUTE(cma_debugfs_fops
, cma_debugfs_get
, NULL
, "%llu\n");
34 static int cma_used_get(void *data
, u64
*val
)
36 struct cma
*cma
= data
;
39 mutex_lock(&cma
->lock
);
40 /* pages counter is smaller than sizeof(int) */
41 used
= bitmap_weight(cma
->bitmap
, (int)cma_bitmap_maxno(cma
));
42 mutex_unlock(&cma
->lock
);
43 *val
= (u64
)used
<< cma
->order_per_bit
;
47 DEFINE_DEBUGFS_ATTRIBUTE(cma_used_fops
, cma_used_get
, NULL
, "%llu\n");
49 static int cma_maxchunk_get(void *data
, u64
*val
)
51 struct cma
*cma
= data
;
52 unsigned long maxchunk
= 0;
53 unsigned long start
, end
= 0;
54 unsigned long bitmap_maxno
= cma_bitmap_maxno(cma
);
56 mutex_lock(&cma
->lock
);
58 start
= find_next_zero_bit(cma
->bitmap
, bitmap_maxno
, end
);
59 if (start
>= bitmap_maxno
)
61 end
= find_next_bit(cma
->bitmap
, bitmap_maxno
, start
);
62 maxchunk
= max(end
- start
, maxchunk
);
64 mutex_unlock(&cma
->lock
);
65 *val
= (u64
)maxchunk
<< cma
->order_per_bit
;
69 DEFINE_DEBUGFS_ATTRIBUTE(cma_maxchunk_fops
, cma_maxchunk_get
, NULL
, "%llu\n");
71 static void cma_add_to_cma_mem_list(struct cma
*cma
, struct cma_mem
*mem
)
73 spin_lock(&cma
->mem_head_lock
);
74 hlist_add_head(&mem
->node
, &cma
->mem_head
);
75 spin_unlock(&cma
->mem_head_lock
);
78 static struct cma_mem
*cma_get_entry_from_list(struct cma
*cma
)
80 struct cma_mem
*mem
= NULL
;
82 spin_lock(&cma
->mem_head_lock
);
83 if (!hlist_empty(&cma
->mem_head
)) {
84 mem
= hlist_entry(cma
->mem_head
.first
, struct cma_mem
, node
);
85 hlist_del_init(&mem
->node
);
87 spin_unlock(&cma
->mem_head_lock
);
92 static int cma_free_mem(struct cma
*cma
, int count
)
94 struct cma_mem
*mem
= NULL
;
97 mem
= cma_get_entry_from_list(cma
);
101 if (mem
->n
<= count
) {
102 cma_release(cma
, mem
->p
, mem
->n
);
105 } else if (cma
->order_per_bit
== 0) {
106 cma_release(cma
, mem
->p
, count
);
110 cma_add_to_cma_mem_list(cma
, mem
);
112 pr_debug("cma: cannot release partial block when order_per_bit != 0\n");
113 cma_add_to_cma_mem_list(cma
, mem
);
122 static int cma_free_write(void *data
, u64 val
)
125 struct cma
*cma
= data
;
127 return cma_free_mem(cma
, pages
);
129 DEFINE_DEBUGFS_ATTRIBUTE(cma_free_fops
, NULL
, cma_free_write
, "%llu\n");
131 static int cma_alloc_mem(struct cma
*cma
, int count
)
136 mem
= kzalloc(sizeof(*mem
), GFP_KERNEL
);
140 p
= cma_alloc(cma
, count
, 0, false);
149 cma_add_to_cma_mem_list(cma
, mem
);
154 static int cma_alloc_write(void *data
, u64 val
)
157 struct cma
*cma
= data
;
159 return cma_alloc_mem(cma
, pages
);
161 DEFINE_DEBUGFS_ATTRIBUTE(cma_alloc_fops
, NULL
, cma_alloc_write
, "%llu\n");
163 static void cma_debugfs_add_one(struct cma
*cma
, struct dentry
*root_dentry
)
168 scnprintf(name
, sizeof(name
), "cma-%s", cma
->name
);
170 tmp
= debugfs_create_dir(name
, root_dentry
);
172 debugfs_create_file("alloc", 0200, tmp
, cma
, &cma_alloc_fops
);
173 debugfs_create_file("free", 0200, tmp
, cma
, &cma_free_fops
);
174 debugfs_create_file("base_pfn", 0444, tmp
,
175 &cma
->base_pfn
, &cma_debugfs_fops
);
176 debugfs_create_file("count", 0444, tmp
, &cma
->count
, &cma_debugfs_fops
);
177 debugfs_create_file("order_per_bit", 0444, tmp
,
178 &cma
->order_per_bit
, &cma_debugfs_fops
);
179 debugfs_create_file("used", 0444, tmp
, cma
, &cma_used_fops
);
180 debugfs_create_file("maxchunk", 0444, tmp
, cma
, &cma_maxchunk_fops
);
182 cma
->dfs_bitmap
.array
= (u32
*)cma
->bitmap
;
183 cma
->dfs_bitmap
.n_elements
= DIV_ROUND_UP(cma_bitmap_maxno(cma
),
184 BITS_PER_BYTE
* sizeof(u32
));
185 debugfs_create_u32_array("bitmap", 0444, tmp
, &cma
->dfs_bitmap
);
188 static int __init
cma_debugfs_init(void)
190 struct dentry
*cma_debugfs_root
;
193 cma_debugfs_root
= debugfs_create_dir("cma", NULL
);
195 for (i
= 0; i
< cma_area_count
; i
++)
196 cma_debugfs_add_one(&cma_areas
[i
], cma_debugfs_root
);
200 late_initcall(cma_debugfs_init
);