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