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