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