at v5.0 4.6 kB view raw
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 18struct cma_mem { 19 struct hlist_node node; 20 struct page *p; 21 unsigned long n; 22}; 23 24static struct dentry *cma_debugfs_root; 25 26static int cma_debugfs_get(void *data, u64 *val) 27{ 28 unsigned long *p = data; 29 30 *val = *p; 31 32 return 0; 33} 34DEFINE_SIMPLE_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu\n"); 35 36static 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} 49DEFINE_SIMPLE_ATTRIBUTE(cma_used_fops, cma_used_get, NULL, "%llu\n"); 50 51static 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} 71DEFINE_SIMPLE_ATTRIBUTE(cma_maxchunk_fops, cma_maxchunk_get, NULL, "%llu\n"); 72 73static 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 80static 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 94static 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 124static 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} 131DEFINE_SIMPLE_ATTRIBUTE(cma_free_fops, NULL, cma_free_write, "%llu\n"); 132 133static 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 156static 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} 163DEFINE_SIMPLE_ATTRIBUTE(cma_alloc_fops, NULL, cma_alloc_write, "%llu\n"); 164 165static 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 189static 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} 202late_initcall(cma_debugfs_init);