1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * CMA DebugFS Interface
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2015 Sasha Levin <sasha.levin@oracle.com>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (C) 2022 Rockchip Electronics Co. Ltd.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/debugfs.h>
12*4882a593Smuzhiyun #include <linux/fs.h>
13*4882a593Smuzhiyun #include <linux/seq_file.h>
14*4882a593Smuzhiyun #include <linux/cma.h>
15*4882a593Smuzhiyun #include <linux/list.h>
16*4882a593Smuzhiyun #include <linux/kernel.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <linux/mm_types.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include "cma.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static size_t
u32_format_array_hex(char * buf,size_t bufsize,u32 * array,int array_size)23*4882a593Smuzhiyun u32_format_array_hex(char *buf, size_t bufsize, u32 *array, int array_size)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun int i = 0;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun while (--array_size >= 0) {
28*4882a593Smuzhiyun size_t len;
29*4882a593Smuzhiyun char term = (array_size && (++i % 8)) ? ' ' : '\n';
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun len = snprintf(buf, bufsize, "%08X%c", *array++, term);
32*4882a593Smuzhiyun buf += len;
33*4882a593Smuzhiyun bufsize -= len;
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun return 0;
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun
u32_array_open_hex(struct inode * inode,struct file * file)39*4882a593Smuzhiyun static int u32_array_open_hex(struct inode *inode, struct file *file)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun struct debugfs_u32_array *data = inode->i_private;
42*4882a593Smuzhiyun int size, elements = data->n_elements;
43*4882a593Smuzhiyun char *buf;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun /*
46*4882a593Smuzhiyun * Max size:
47*4882a593Smuzhiyun * - 8 digits + ' '/'\n' = 9 bytes per number
48*4882a593Smuzhiyun * - terminating NUL character
49*4882a593Smuzhiyun */
50*4882a593Smuzhiyun size = elements * 9;
51*4882a593Smuzhiyun buf = kmalloc(size + 1, GFP_KERNEL);
52*4882a593Smuzhiyun if (!buf)
53*4882a593Smuzhiyun return -ENOMEM;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun buf[size] = 0;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun file->private_data = buf;
58*4882a593Smuzhiyun u32_format_array_hex(buf, size + 1, data->array, data->n_elements);
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun return nonseekable_open(inode, file);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun static ssize_t
u32_array_read(struct file * file,char __user * buf,size_t len,loff_t * ppos)64*4882a593Smuzhiyun u32_array_read(struct file *file, char __user *buf, size_t len, loff_t *ppos)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun size_t size = strlen(file->private_data);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun return simple_read_from_buffer(buf, len, ppos,
69*4882a593Smuzhiyun file->private_data, size);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
u32_array_release(struct inode * inode,struct file * file)72*4882a593Smuzhiyun static int u32_array_release(struct inode *inode, struct file *file)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun kfree(file->private_data);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun return 0;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun static const struct file_operations u32_array_hex_fops = {
80*4882a593Smuzhiyun .owner = THIS_MODULE,
81*4882a593Smuzhiyun .open = u32_array_open_hex,
82*4882a593Smuzhiyun .release = u32_array_release,
83*4882a593Smuzhiyun .read = u32_array_read,
84*4882a593Smuzhiyun .llseek = no_llseek,
85*4882a593Smuzhiyun };
86*4882a593Smuzhiyun
debugfs_create_u32_array_hex(const char * name,umode_t mode,struct dentry * parent,struct debugfs_u32_array * array)87*4882a593Smuzhiyun static void debugfs_create_u32_array_hex(const char *name, umode_t mode,
88*4882a593Smuzhiyun struct dentry *parent,
89*4882a593Smuzhiyun struct debugfs_u32_array *array)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun debugfs_create_file_unsafe(name, mode, parent, array, &u32_array_hex_fops);
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
cma_debugfs_add_one(struct cma * cma,struct dentry * root_dentry)94*4882a593Smuzhiyun static int cma_debugfs_add_one(struct cma *cma, struct dentry *root_dentry)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun struct dentry *tmp;
97*4882a593Smuzhiyun char name[16];
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun scnprintf(name, sizeof(name), "cma-%s", cma->name);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun tmp = debugfs_lookup(name, root_dentry);
102*4882a593Smuzhiyun if (!tmp)
103*4882a593Smuzhiyun return -EPROBE_DEFER;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun debugfs_create_u32_array_hex("bitmap_hex", 0444, tmp, &cma->dfs_bitmap);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun return 0;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
rk_cma_debugfs_init(void)110*4882a593Smuzhiyun static int __init rk_cma_debugfs_init(void)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun struct dentry *cma_debugfs_root;
113*4882a593Smuzhiyun int ret;
114*4882a593Smuzhiyun int i;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun cma_debugfs_root = debugfs_lookup("cma", NULL);
117*4882a593Smuzhiyun if (!cma_debugfs_root)
118*4882a593Smuzhiyun return -EPROBE_DEFER;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun for (i = 0; i < cma_area_count; i++) {
121*4882a593Smuzhiyun ret = cma_debugfs_add_one(&cma_areas[i], cma_debugfs_root);
122*4882a593Smuzhiyun if (ret)
123*4882a593Smuzhiyun return ret;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun return 0;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun late_initcall(rk_cma_debugfs_init);
129