brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · 602fff8 Raw
198 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * CMA DebugFS Interface4 *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 int cma_debugfs_get(void *data, u64 *val)25{26	unsigned long *p = data;27 28	*val = *p;29 30	return 0;31}32DEFINE_DEBUGFS_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu\n");33 34static int cma_used_get(void *data, u64 *val)35{36	struct cma *cma = data;37	unsigned long used;38 39	spin_lock_irq(&cma->lock);40	/* pages counter is smaller than sizeof(int) */41	used = bitmap_weight(cma->bitmap, (int)cma_bitmap_maxno(cma));42	spin_unlock_irq(&cma->lock);43	*val = (u64)used << cma->order_per_bit;44 45	return 0;46}47DEFINE_DEBUGFS_ATTRIBUTE(cma_used_fops, cma_used_get, NULL, "%llu\n");48 49static int cma_maxchunk_get(void *data, u64 *val)50{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);55 56	spin_lock_irq(&cma->lock);57	for (;;) {58		start = find_next_zero_bit(cma->bitmap, bitmap_maxno, end);59		if (start >= bitmap_maxno)60			break;61		end = find_next_bit(cma->bitmap, bitmap_maxno, start);62		maxchunk = max(end - start, maxchunk);63	}64	spin_unlock_irq(&cma->lock);65	*val = (u64)maxchunk << cma->order_per_bit;66 67	return 0;68}69DEFINE_DEBUGFS_ATTRIBUTE(cma_maxchunk_fops, cma_maxchunk_get, NULL, "%llu\n");70 71static void cma_add_to_cma_mem_list(struct cma *cma, struct cma_mem *mem)72{73	spin_lock(&cma->mem_head_lock);74	hlist_add_head(&mem->node, &cma->mem_head);75	spin_unlock(&cma->mem_head_lock);76}77 78static struct cma_mem *cma_get_entry_from_list(struct cma *cma)79{80	struct cma_mem *mem = NULL;81 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);86	}87	spin_unlock(&cma->mem_head_lock);88 89	return mem;90}91 92static int cma_free_mem(struct cma *cma, int count)93{94	struct cma_mem *mem = NULL;95 96	while (count) {97		mem = cma_get_entry_from_list(cma);98		if (mem == NULL)99			return 0;100 101		if (mem->n <= count) {102			cma_release(cma, mem->p, mem->n);103			count -= mem->n;104			kfree(mem);105		} else if (cma->order_per_bit == 0) {106			cma_release(cma, mem->p, count);107			mem->p += count;108			mem->n -= count;109			count = 0;110			cma_add_to_cma_mem_list(cma, mem);111		} else {112			pr_debug("cma: cannot release partial block when order_per_bit != 0\n");113			cma_add_to_cma_mem_list(cma, mem);114			break;115		}116	}117 118	return 0;119 120}121 122static int cma_free_write(void *data, u64 val)123{124	int pages = val;125	struct cma *cma = data;126 127	return cma_free_mem(cma, pages);128}129DEFINE_DEBUGFS_ATTRIBUTE(cma_free_fops, NULL, cma_free_write, "%llu\n");130 131static int cma_alloc_mem(struct cma *cma, int count)132{133	struct cma_mem *mem;134	struct page *p;135 136	mem = kzalloc(sizeof(*mem), GFP_KERNEL);137	if (!mem)138		return -ENOMEM;139 140	p = cma_alloc(cma, count, 0, false);141	if (!p) {142		kfree(mem);143		return -ENOMEM;144	}145 146	mem->p = p;147	mem->n = count;148 149	cma_add_to_cma_mem_list(cma, mem);150 151	return 0;152}153 154static int cma_alloc_write(void *data, u64 val)155{156	int pages = val;157	struct cma *cma = data;158 159	return cma_alloc_mem(cma, pages);160}161DEFINE_DEBUGFS_ATTRIBUTE(cma_alloc_fops, NULL, cma_alloc_write, "%llu\n");162 163static void cma_debugfs_add_one(struct cma *cma, struct dentry *root_dentry)164{165	struct dentry *tmp;166 167	tmp = debugfs_create_dir(cma->name, root_dentry);168 169	debugfs_create_file("alloc", 0200, tmp, cma, &cma_alloc_fops);170	debugfs_create_file("free", 0200, tmp, cma, &cma_free_fops);171	debugfs_create_file("base_pfn", 0444, tmp,172			    &cma->base_pfn, &cma_debugfs_fops);173	debugfs_create_file("count", 0444, tmp, &cma->count, &cma_debugfs_fops);174	debugfs_create_file("order_per_bit", 0444, tmp,175			    &cma->order_per_bit, &cma_debugfs_fops);176	debugfs_create_file("used", 0444, tmp, cma, &cma_used_fops);177	debugfs_create_file("maxchunk", 0444, tmp, cma, &cma_maxchunk_fops);178 179	cma->dfs_bitmap.array = (u32 *)cma->bitmap;180	cma->dfs_bitmap.n_elements = DIV_ROUND_UP(cma_bitmap_maxno(cma),181						  BITS_PER_BYTE * sizeof(u32));182	debugfs_create_u32_array("bitmap", 0444, tmp, &cma->dfs_bitmap);183}184 185static int __init cma_debugfs_init(void)186{187	struct dentry *cma_debugfs_root;188	int i;189 190	cma_debugfs_root = debugfs_create_dir("cma", NULL);191 192	for (i = 0; i < cma_area_count; i++)193		cma_debugfs_add_one(&cma_areas[i], cma_debugfs_root);194 195	return 0;196}197late_initcall(cma_debugfs_init);198