xref: /OK3568_Linux_fs/kernel/drivers/soc/rockchip/rk_dmabuf_procfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2022 Rockchip Electronics Co. Ltd.
4  */
5 
6 #include <linux/dma-buf.h>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
9 #include <linux/proc_fs.h>
10 #include <linux/scatterlist.h>
11 #include <linux/seq_file.h>
12 #include <linux/slab.h>
13 
14 #define K(size) ((unsigned long)((size) >> 10))
15 static struct device *dmabuf_dev;
16 
rk_dmabuf_dump_empty_sgt(struct dma_buf * dmabuf,void * private)17 static void rk_dmabuf_dump_empty_sgt(struct dma_buf *dmabuf, void *private)
18 {
19 	struct dma_buf_attachment *a;
20 	struct seq_file *s = private;
21 	struct scatterlist *sg;
22 	struct sg_table *sgt;
23 	phys_addr_t end, len;
24 	int i;
25 
26 	a = dma_buf_attach(dmabuf, dmabuf_dev);
27 	if (IS_ERR(a))
28 		return;
29 
30 	sgt = dma_buf_map_attachment(a, DMA_BIDIRECTIONAL);
31 	if (IS_ERR(sgt)) {
32 		dma_buf_detach(dmabuf, a);
33 		return;
34 	}
35 
36 	for_each_sgtable_sg(sgt, sg, i) {
37 		end = sg->dma_address + sg->length - 1;
38 		len = sg->length;
39 		if (i)
40 			seq_printf(s, "%65s", " ");
41 		else
42 			seq_printf(s, "%px %-16.16s %-16.16s %10lu KiB",
43 				   dmabuf, dmabuf->name,
44 				   dmabuf->exp_name, K(dmabuf->size));
45 		seq_printf(s, "%4d: %pa..%pa (%10lu %s)\n", i,
46 			   &sg->dma_address, &end,
47 			   (len >> 10) ? (K(len)) : (unsigned long)len,
48 			   (len >> 10) ? "KiB" : "Bytes");
49 	}
50 	dma_buf_unmap_attachment(a, sgt, DMA_BIDIRECTIONAL);
51 	dma_buf_detach(dmabuf, a);
52 }
53 
rk_dmabuf_dump_sgt(const struct dma_buf * dmabuf,void * private)54 static void rk_dmabuf_dump_sgt(const struct dma_buf *dmabuf, void *private)
55 {
56 	struct seq_file *s = private;
57 	struct scatterlist *sg;
58 	struct dma_buf_attachment *a, *t;
59 	phys_addr_t end, len;
60 	int i;
61 
62 	list_for_each_entry_safe(a, t, &dmabuf->attachments, node) {
63 		if (!a->sgt)
64 			continue;
65 		for_each_sgtable_sg(a->sgt, sg, i) {
66 			end = sg->dma_address + sg->length - 1;
67 			len = sg->length;
68 			if (i)
69 				seq_printf(s, "%65s", " ");
70 			else
71 				seq_printf(s, "%px %-16.16s %-16.16s %10lu KiB",
72 					   dmabuf, dmabuf->name,
73 					   dmabuf->exp_name, K(dmabuf->size));
74 			seq_printf(s, "%4d: %pa..%pa (%10lu %s)\n", i,
75 				   &sg->dma_address, &end,
76 				   (len >> 10) ? (K(len)) : (unsigned long)len,
77 				   (len >> 10) ? "KiB" : "Bytes");
78 		}
79 		return;
80 	}
81 	/* Try to attach and map the dmabufs without sgt. */
82 	if (IS_ENABLED(CONFIG_RK_DMABUF_DEBUG_ADVANCED)) {
83 		struct dma_buf *dbuf = (struct dma_buf *)dmabuf;
84 
85 		get_dma_buf(dbuf);
86 		rk_dmabuf_dump_empty_sgt(dbuf, s);
87 		dma_buf_put(dbuf);
88 	}
89 }
90 
rk_dmabuf_cb(const struct dma_buf * dmabuf,void * private)91 static int rk_dmabuf_cb(const struct dma_buf *dmabuf, void *private)
92 {
93 	struct seq_file *s = private;
94 
95 	rk_dmabuf_dump_sgt(dmabuf, s);
96 
97 	return 0;
98 }
99 
rk_dmabuf_cb3(const struct dma_buf * dmabuf,void * private)100 static int rk_dmabuf_cb3(const struct dma_buf *dmabuf, void *private)
101 {
102 	struct seq_file *s = private;
103 	struct dma_buf_attachment *a, *t;
104 
105 	seq_printf(s, "%px %-16.16s %-16.16s %10lu KiB",
106 		   dmabuf, dmabuf->name,
107 		   dmabuf->exp_name, K(dmabuf->size));
108 	list_for_each_entry_safe(a, t, &dmabuf->attachments, node) {
109 		seq_printf(s, " %s", dev_name(a->dev));
110 	}
111 	seq_puts(s, "\n");
112 
113 	return 0;
114 }
115 
rk_dmabuf_sgt_show(struct seq_file * s,void * v)116 static int rk_dmabuf_sgt_show(struct seq_file *s, void *v)
117 {
118 	seq_printf(s, "%16s %-16s %-16s %14s %8s\n\n",
119 		   "DMABUF", "NAME", "EXPORT", "SIZE:KiB", "SGLIST");
120 
121 	return get_each_dmabuf(rk_dmabuf_cb, s);
122 }
123 
rk_dmabuf_dev_show(struct seq_file * s,void * v)124 static int rk_dmabuf_dev_show(struct seq_file *s, void *v)
125 {
126 	seq_printf(s, "%16s %-16s %-16s %14s %8s\n\n",
127 		   "DMABUF", "NAME", "EXPORT", "SIZE:KiB", "AttachedDevices");
128 
129 	return get_each_dmabuf(rk_dmabuf_cb3, s);
130 }
131 
rk_dmabuf_size_show(struct seq_file * s,void * v)132 static int rk_dmabuf_size_show(struct seq_file *s, void *v)
133 {
134 	seq_printf(s, "Total: %lu KiB\n", K(dma_buf_get_total_size()));
135 
136 	return 0;
137 }
138 
rk_dmabuf_peak_show(struct seq_file * s,void * v)139 static int rk_dmabuf_peak_show(struct seq_file *s, void *v)
140 {
141 	seq_printf(s, "Peak: %lu MiB\n", K(K(dma_buf_get_peak_size())));
142 
143 	return 0;
144 }
145 
rk_dmabuf_peak_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)146 static ssize_t rk_dmabuf_peak_write(struct file *file,
147 				    const char __user *buffer,
148 				    size_t count, loff_t *ppos)
149 {
150 	char c;
151 	int rc;
152 
153 	rc = get_user(c, buffer);
154 	if (rc)
155 		return rc;
156 
157 	if (c != '0')
158 		return -EINVAL;
159 
160 	dma_buf_reset_peak_size();
161 
162 	return count;
163 }
164 
rk_dmabuf_peak_open(struct inode * inode,struct file * file)165 static int rk_dmabuf_peak_open(struct inode *inode, struct file *file)
166 {
167 	return single_open(file, rk_dmabuf_peak_show, NULL);
168 }
169 
170 static const struct proc_ops rk_dmabuf_peak_ops = {
171 	.proc_open	= rk_dmabuf_peak_open,
172 	.proc_read	= seq_read,
173 	.proc_lseek	= seq_lseek,
174 	.proc_release	= single_release,
175 	.proc_write	= rk_dmabuf_peak_write,
176 };
177 
rk_dmabuf_init(void)178 static int __init rk_dmabuf_init(void)
179 {
180 	struct platform_device *pdev;
181 	struct platform_device_info dev_info = {
182 		.name		= "dmabuf",
183 		.id		= PLATFORM_DEVID_NONE,
184 		.dma_mask	= DMA_BIT_MASK(64),
185 	};
186 	struct proc_dir_entry *root = proc_mkdir("rk_dmabuf", NULL);
187 
188 	pdev = platform_device_register_full(&dev_info);
189 	dma_set_max_seg_size(&pdev->dev, (unsigned int)DMA_BIT_MASK(64));
190 	dmabuf_dev = pdev ? &pdev->dev : NULL;
191 
192 	proc_create_single("sgt", 0, root, rk_dmabuf_sgt_show);
193 	proc_create_single("dev", 0, root, rk_dmabuf_dev_show);
194 	proc_create_single("size", 0, root, rk_dmabuf_size_show);
195 	proc_create("peak", 0644, root, &rk_dmabuf_peak_ops);
196 
197 	return 0;
198 }
199 late_initcall_sync(rk_dmabuf_init);
200 
201 MODULE_LICENSE("GPL");
202 MODULE_AUTHOR("Jianqun Xu <jay.xu@rock-chips.com>");
203 MODULE_DESCRIPTION("ROCKCHIP DMABUF Driver");
204 MODULE_ALIAS("platform:rk-dmabuf");
205