Merge tag 'block-5.11-2021-01-10' of git://git.kernel.dk/linux-block
[linux/fpc-iii.git] / drivers / dma / qcom / hidma_mgmt_sys.c
blob930eae0a6257cf0ed0d82692c06edda96b296c72
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Qualcomm Technologies HIDMA Management SYS interface
5 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
6 */
8 #include <linux/sysfs.h>
9 #include <linux/platform_device.h>
11 #include "hidma_mgmt.h"
13 struct hidma_chan_attr {
14 struct hidma_mgmt_dev *mdev;
15 int index;
16 struct kobj_attribute attr;
19 struct hidma_mgmt_fileinfo {
20 char *name;
21 int mode;
22 int (*get)(struct hidma_mgmt_dev *mdev);
23 int (*set)(struct hidma_mgmt_dev *mdev, u64 val);
26 #define IMPLEMENT_GETSET(name) \
27 static int get_##name(struct hidma_mgmt_dev *mdev) \
28 { \
29 return mdev->name; \
30 } \
31 static int set_##name(struct hidma_mgmt_dev *mdev, u64 val) \
32 { \
33 u64 tmp; \
34 int rc; \
36 tmp = mdev->name; \
37 mdev->name = val; \
38 rc = hidma_mgmt_setup(mdev); \
39 if (rc) \
40 mdev->name = tmp; \
41 return rc; \
44 #define DECLARE_ATTRIBUTE(name, mode) \
45 {#name, mode, get_##name, set_##name}
47 IMPLEMENT_GETSET(hw_version_major)
48 IMPLEMENT_GETSET(hw_version_minor)
49 IMPLEMENT_GETSET(max_wr_xactions)
50 IMPLEMENT_GETSET(max_rd_xactions)
51 IMPLEMENT_GETSET(max_write_request)
52 IMPLEMENT_GETSET(max_read_request)
53 IMPLEMENT_GETSET(dma_channels)
54 IMPLEMENT_GETSET(chreset_timeout_cycles)
56 static int set_priority(struct hidma_mgmt_dev *mdev, unsigned int i, u64 val)
58 u64 tmp;
59 int rc;
61 if (i >= mdev->dma_channels)
62 return -EINVAL;
64 tmp = mdev->priority[i];
65 mdev->priority[i] = val;
66 rc = hidma_mgmt_setup(mdev);
67 if (rc)
68 mdev->priority[i] = tmp;
69 return rc;
72 static int set_weight(struct hidma_mgmt_dev *mdev, unsigned int i, u64 val)
74 u64 tmp;
75 int rc;
77 if (i >= mdev->dma_channels)
78 return -EINVAL;
80 tmp = mdev->weight[i];
81 mdev->weight[i] = val;
82 rc = hidma_mgmt_setup(mdev);
83 if (rc)
84 mdev->weight[i] = tmp;
85 return rc;
88 static struct hidma_mgmt_fileinfo hidma_mgmt_files[] = {
89 DECLARE_ATTRIBUTE(hw_version_major, S_IRUGO),
90 DECLARE_ATTRIBUTE(hw_version_minor, S_IRUGO),
91 DECLARE_ATTRIBUTE(dma_channels, S_IRUGO),
92 DECLARE_ATTRIBUTE(chreset_timeout_cycles, S_IRUGO),
93 DECLARE_ATTRIBUTE(max_wr_xactions, S_IRUGO),
94 DECLARE_ATTRIBUTE(max_rd_xactions, S_IRUGO),
95 DECLARE_ATTRIBUTE(max_write_request, S_IRUGO),
96 DECLARE_ATTRIBUTE(max_read_request, S_IRUGO),
99 static ssize_t show_values(struct device *dev, struct device_attribute *attr,
100 char *buf)
102 struct hidma_mgmt_dev *mdev = dev_get_drvdata(dev);
103 unsigned int i;
105 buf[0] = 0;
107 for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
108 if (strcmp(attr->attr.name, hidma_mgmt_files[i].name) == 0) {
109 sprintf(buf, "%d\n", hidma_mgmt_files[i].get(mdev));
110 break;
113 return strlen(buf);
116 static ssize_t set_values(struct device *dev, struct device_attribute *attr,
117 const char *buf, size_t count)
119 struct hidma_mgmt_dev *mdev = dev_get_drvdata(dev);
120 unsigned long tmp;
121 unsigned int i;
122 int rc;
124 rc = kstrtoul(buf, 0, &tmp);
125 if (rc)
126 return rc;
128 for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
129 if (strcmp(attr->attr.name, hidma_mgmt_files[i].name) == 0) {
130 rc = hidma_mgmt_files[i].set(mdev, tmp);
131 if (rc)
132 return rc;
134 break;
137 return count;
140 static ssize_t show_values_channel(struct kobject *kobj,
141 struct kobj_attribute *attr, char *buf)
143 struct hidma_chan_attr *chattr;
144 struct hidma_mgmt_dev *mdev;
146 buf[0] = 0;
147 chattr = container_of(attr, struct hidma_chan_attr, attr);
148 mdev = chattr->mdev;
149 if (strcmp(attr->attr.name, "priority") == 0)
150 sprintf(buf, "%d\n", mdev->priority[chattr->index]);
151 else if (strcmp(attr->attr.name, "weight") == 0)
152 sprintf(buf, "%d\n", mdev->weight[chattr->index]);
154 return strlen(buf);
157 static ssize_t set_values_channel(struct kobject *kobj,
158 struct kobj_attribute *attr, const char *buf,
159 size_t count)
161 struct hidma_chan_attr *chattr;
162 struct hidma_mgmt_dev *mdev;
163 unsigned long tmp;
164 int rc;
166 chattr = container_of(attr, struct hidma_chan_attr, attr);
167 mdev = chattr->mdev;
169 rc = kstrtoul(buf, 0, &tmp);
170 if (rc)
171 return rc;
173 if (strcmp(attr->attr.name, "priority") == 0) {
174 rc = set_priority(mdev, chattr->index, tmp);
175 if (rc)
176 return rc;
177 } else if (strcmp(attr->attr.name, "weight") == 0) {
178 rc = set_weight(mdev, chattr->index, tmp);
179 if (rc)
180 return rc;
182 return count;
185 static int create_sysfs_entry(struct hidma_mgmt_dev *dev, char *name, int mode)
187 struct device_attribute *attrs;
188 char *name_copy;
190 attrs = devm_kmalloc(&dev->pdev->dev,
191 sizeof(struct device_attribute), GFP_KERNEL);
192 if (!attrs)
193 return -ENOMEM;
195 name_copy = devm_kstrdup(&dev->pdev->dev, name, GFP_KERNEL);
196 if (!name_copy)
197 return -ENOMEM;
199 attrs->attr.name = name_copy;
200 attrs->attr.mode = mode;
201 attrs->show = show_values;
202 attrs->store = set_values;
203 sysfs_attr_init(&attrs->attr);
205 return device_create_file(&dev->pdev->dev, attrs);
208 static int create_sysfs_entry_channel(struct hidma_mgmt_dev *mdev, char *name,
209 int mode, int index,
210 struct kobject *parent)
212 struct hidma_chan_attr *chattr;
213 char *name_copy;
215 chattr = devm_kmalloc(&mdev->pdev->dev, sizeof(*chattr), GFP_KERNEL);
216 if (!chattr)
217 return -ENOMEM;
219 name_copy = devm_kstrdup(&mdev->pdev->dev, name, GFP_KERNEL);
220 if (!name_copy)
221 return -ENOMEM;
223 chattr->mdev = mdev;
224 chattr->index = index;
225 chattr->attr.attr.name = name_copy;
226 chattr->attr.attr.mode = mode;
227 chattr->attr.show = show_values_channel;
228 chattr->attr.store = set_values_channel;
229 sysfs_attr_init(&chattr->attr.attr);
231 return sysfs_create_file(parent, &chattr->attr.attr);
234 int hidma_mgmt_init_sys(struct hidma_mgmt_dev *mdev)
236 unsigned int i;
237 int rc;
238 int required;
239 struct kobject *chanops;
241 required = sizeof(*mdev->chroots) * mdev->dma_channels;
242 mdev->chroots = devm_kmalloc(&mdev->pdev->dev, required, GFP_KERNEL);
243 if (!mdev->chroots)
244 return -ENOMEM;
246 chanops = kobject_create_and_add("chanops", &mdev->pdev->dev.kobj);
247 if (!chanops)
248 return -ENOMEM;
250 /* create each channel directory here */
251 for (i = 0; i < mdev->dma_channels; i++) {
252 char name[20];
254 snprintf(name, sizeof(name), "chan%d", i);
255 mdev->chroots[i] = kobject_create_and_add(name, chanops);
256 if (!mdev->chroots[i])
257 return -ENOMEM;
260 /* populate common parameters */
261 for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
262 rc = create_sysfs_entry(mdev, hidma_mgmt_files[i].name,
263 hidma_mgmt_files[i].mode);
264 if (rc)
265 return rc;
268 /* populate parameters that are per channel */
269 for (i = 0; i < mdev->dma_channels; i++) {
270 rc = create_sysfs_entry_channel(mdev, "priority",
271 (S_IRUGO | S_IWUGO), i,
272 mdev->chroots[i]);
273 if (rc)
274 return rc;
276 rc = create_sysfs_entry_channel(mdev, "weight",
277 (S_IRUGO | S_IWUGO), i,
278 mdev->chroots[i]);
279 if (rc)
280 return rc;
283 return 0;
285 EXPORT_SYMBOL_GPL(hidma_mgmt_init_sys);