blob: 2d90e697ec9430309c11219d7c0a74290dea72fb [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * DMA-BUF sysfs statistics.
4 *
5 * Copyright (C) 2021 Google LLC.
6 */
7
8#include <linux/dma-buf.h>
9#include <linux/dma-resv.h>
10#include <linux/kobject.h>
11#include <linux/printk.h>
12#include <linux/slab.h>
13#include <linux/sysfs.h>
14
15#include "dma-buf-sysfs-stats.h"
16
17#define to_dma_buf_entry_from_kobj(x) container_of(x, struct dma_buf_sysfs_entry, kobj)
18
19struct dma_buf_stats_attribute {
20 struct attribute attr;
21 ssize_t (*show)(struct dma_buf *dmabuf,
22 struct dma_buf_stats_attribute *attr, char *buf);
23};
24#define to_dma_buf_stats_attr(x) container_of(x, struct dma_buf_stats_attribute, attr)
25
26static ssize_t dma_buf_stats_attribute_show(struct kobject *kobj,
27 struct attribute *attr,
28 char *buf)
29{
30 struct dma_buf_stats_attribute *attribute;
31 struct dma_buf_sysfs_entry *sysfs_entry;
32 struct dma_buf *dmabuf;
33
34 attribute = to_dma_buf_stats_attr(attr);
35 sysfs_entry = to_dma_buf_entry_from_kobj(kobj);
36 dmabuf = sysfs_entry->dmabuf;
37
38 if (!dmabuf || !attribute->show)
39 return -EIO;
40
41 return attribute->show(dmabuf, attribute, buf);
42}
43
44static const struct sysfs_ops dma_buf_stats_sysfs_ops = {
45 .show = dma_buf_stats_attribute_show,
46};
47
48static ssize_t exporter_name_show(struct dma_buf *dmabuf,
49 struct dma_buf_stats_attribute *attr,
50 char *buf)
51{
52 return sprintf(buf, "%s\n", dmabuf->exp_name);
53}
54
55static ssize_t size_show(struct dma_buf *dmabuf,
56 struct dma_buf_stats_attribute *attr,
57 char *buf)
58{
59 return sprintf(buf, "%zu\n", dmabuf->size);
60}
61
62static struct dma_buf_stats_attribute exporter_name_attribute =
63 __ATTR_RO(exporter_name);
64static struct dma_buf_stats_attribute size_attribute = __ATTR_RO(size);
65
66static struct attribute *dma_buf_stats_default_attrs[] = {
67 &exporter_name_attribute.attr,
68 &size_attribute.attr,
69 NULL,
70};
71ATTRIBUTE_GROUPS(dma_buf_stats_default);
72
73static void dma_buf_sysfs_release(struct kobject *kobj)
74{
75 struct dma_buf_sysfs_entry *sysfs_entry;
76
77 sysfs_entry = to_dma_buf_entry_from_kobj(kobj);
78 kfree(sysfs_entry);
79}
80
81static struct kobj_type dma_buf_ktype = {
82 .sysfs_ops = &dma_buf_stats_sysfs_ops,
83 .release = dma_buf_sysfs_release,
84 .default_groups = dma_buf_stats_default_groups,
85};
86
87void dma_buf_stats_teardown(struct dma_buf *dmabuf)
88{
89 struct dma_buf_sysfs_entry *sysfs_entry;
90
91 sysfs_entry = dmabuf->sysfs_entry;
92 if (!sysfs_entry)
93 return;
94
95 kobject_del(&sysfs_entry->kobj);
96 kobject_put(&sysfs_entry->kobj);
97}
98
99static struct kset *dma_buf_stats_kset;
100static struct kset *dma_buf_per_buffer_stats_kset;
101int dma_buf_init_sysfs_statistics(void)
102{
103 dma_buf_stats_kset = kset_create_and_add("dmabuf", NULL, kernel_kobj);
104 if (!dma_buf_stats_kset)
105 return -ENOMEM;
106
107 dma_buf_per_buffer_stats_kset = kset_create_and_add("buffers", NULL,
108 &dma_buf_stats_kset->kobj);
109 if (!dma_buf_per_buffer_stats_kset) {
110 kset_unregister(dma_buf_stats_kset);
111 return -ENOMEM;
112 }
113
114 return 0;
115}
116
117void dma_buf_uninit_sysfs_statistics(void)
118{
119 kset_unregister(dma_buf_per_buffer_stats_kset);
120 kset_unregister(dma_buf_stats_kset);
121}
122
123int dma_buf_stats_setup(struct dma_buf *dmabuf)
124{
125 struct dma_buf_sysfs_entry *sysfs_entry;
126 int ret;
127
128 if (!dmabuf || !dmabuf->file)
129 return -EINVAL;
130
131 if (!dmabuf->exp_name) {
132 pr_err("exporter name must not be empty if stats needed\n");
133 return -EINVAL;
134 }
135
136 sysfs_entry = kzalloc(sizeof(struct dma_buf_sysfs_entry), GFP_KERNEL);
137 if (!sysfs_entry)
138 return -ENOMEM;
139
140 sysfs_entry->kobj.kset = dma_buf_per_buffer_stats_kset;
141 sysfs_entry->dmabuf = dmabuf;
142
143 dmabuf->sysfs_entry = sysfs_entry;
144
145 /* create the directory for buffer stats */
146 ret = kobject_init_and_add(&sysfs_entry->kobj, &dma_buf_ktype, NULL,
147 "%lu", file_inode(dmabuf->file)->i_ino);
148 if (ret)
149 goto err_sysfs_dmabuf;
150
151 return 0;
152
153err_sysfs_dmabuf:
154 kobject_put(&sysfs_entry->kobj);
155 dmabuf->sysfs_entry = NULL;
156 return ret;
157}