2 * Qualcomm Technologies HIDMA Management SYS interface
4 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 and
8 * only version 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/sysfs.h>
17 #include <linux/platform_device.h>
19 #include "hidma_mgmt.h"
21 struct hidma_chan_attr
{
22 struct hidma_mgmt_dev
*mdev
;
24 struct kobj_attribute attr
;
27 struct hidma_mgmt_fileinfo
{
30 int (*get
)(struct hidma_mgmt_dev
*mdev
);
31 int (*set
)(struct hidma_mgmt_dev
*mdev
, u64 val
);
34 #define IMPLEMENT_GETSET(name) \
35 static int get_##name(struct hidma_mgmt_dev *mdev) \
39 static int set_##name(struct hidma_mgmt_dev *mdev, u64 val) \
46 rc = hidma_mgmt_setup(mdev); \
52 #define DECLARE_ATTRIBUTE(name, mode) \
53 {#name, mode, get_##name, set_##name}
55 IMPLEMENT_GETSET(hw_version_major
)
56 IMPLEMENT_GETSET(hw_version_minor
)
57 IMPLEMENT_GETSET(max_wr_xactions
)
58 IMPLEMENT_GETSET(max_rd_xactions
)
59 IMPLEMENT_GETSET(max_write_request
)
60 IMPLEMENT_GETSET(max_read_request
)
61 IMPLEMENT_GETSET(dma_channels
)
62 IMPLEMENT_GETSET(chreset_timeout_cycles
)
64 static int set_priority(struct hidma_mgmt_dev
*mdev
, unsigned int i
, u64 val
)
69 if (i
>= mdev
->dma_channels
)
72 tmp
= mdev
->priority
[i
];
73 mdev
->priority
[i
] = val
;
74 rc
= hidma_mgmt_setup(mdev
);
76 mdev
->priority
[i
] = tmp
;
80 static int set_weight(struct hidma_mgmt_dev
*mdev
, unsigned int i
, u64 val
)
85 if (i
>= mdev
->dma_channels
)
88 tmp
= mdev
->weight
[i
];
89 mdev
->weight
[i
] = val
;
90 rc
= hidma_mgmt_setup(mdev
);
92 mdev
->weight
[i
] = tmp
;
96 static struct hidma_mgmt_fileinfo hidma_mgmt_files
[] = {
97 DECLARE_ATTRIBUTE(hw_version_major
, S_IRUGO
),
98 DECLARE_ATTRIBUTE(hw_version_minor
, S_IRUGO
),
99 DECLARE_ATTRIBUTE(dma_channels
, S_IRUGO
),
100 DECLARE_ATTRIBUTE(chreset_timeout_cycles
, S_IRUGO
),
101 DECLARE_ATTRIBUTE(max_wr_xactions
, S_IRUGO
),
102 DECLARE_ATTRIBUTE(max_rd_xactions
, S_IRUGO
),
103 DECLARE_ATTRIBUTE(max_write_request
, S_IRUGO
),
104 DECLARE_ATTRIBUTE(max_read_request
, S_IRUGO
),
107 static ssize_t
show_values(struct device
*dev
, struct device_attribute
*attr
,
110 struct platform_device
*pdev
= to_platform_device(dev
);
111 struct hidma_mgmt_dev
*mdev
= platform_get_drvdata(pdev
);
116 for (i
= 0; i
< ARRAY_SIZE(hidma_mgmt_files
); i
++) {
117 if (strcmp(attr
->attr
.name
, hidma_mgmt_files
[i
].name
) == 0) {
118 sprintf(buf
, "%d\n", hidma_mgmt_files
[i
].get(mdev
));
125 static ssize_t
set_values(struct device
*dev
, struct device_attribute
*attr
,
126 const char *buf
, size_t count
)
128 struct platform_device
*pdev
= to_platform_device(dev
);
129 struct hidma_mgmt_dev
*mdev
= platform_get_drvdata(pdev
);
134 rc
= kstrtoul(buf
, 0, &tmp
);
138 for (i
= 0; i
< ARRAY_SIZE(hidma_mgmt_files
); i
++) {
139 if (strcmp(attr
->attr
.name
, hidma_mgmt_files
[i
].name
) == 0) {
140 rc
= hidma_mgmt_files
[i
].set(mdev
, tmp
);
150 static ssize_t
show_values_channel(struct kobject
*kobj
,
151 struct kobj_attribute
*attr
, char *buf
)
153 struct hidma_chan_attr
*chattr
;
154 struct hidma_mgmt_dev
*mdev
;
157 chattr
= container_of(attr
, struct hidma_chan_attr
, attr
);
159 if (strcmp(attr
->attr
.name
, "priority") == 0)
160 sprintf(buf
, "%d\n", mdev
->priority
[chattr
->index
]);
161 else if (strcmp(attr
->attr
.name
, "weight") == 0)
162 sprintf(buf
, "%d\n", mdev
->weight
[chattr
->index
]);
167 static ssize_t
set_values_channel(struct kobject
*kobj
,
168 struct kobj_attribute
*attr
, const char *buf
,
171 struct hidma_chan_attr
*chattr
;
172 struct hidma_mgmt_dev
*mdev
;
176 chattr
= container_of(attr
, struct hidma_chan_attr
, attr
);
179 rc
= kstrtoul(buf
, 0, &tmp
);
183 if (strcmp(attr
->attr
.name
, "priority") == 0) {
184 rc
= set_priority(mdev
, chattr
->index
, tmp
);
187 } else if (strcmp(attr
->attr
.name
, "weight") == 0) {
188 rc
= set_weight(mdev
, chattr
->index
, tmp
);
195 static int create_sysfs_entry(struct hidma_mgmt_dev
*dev
, char *name
, int mode
)
197 struct device_attribute
*attrs
;
200 attrs
= devm_kmalloc(&dev
->pdev
->dev
,
201 sizeof(struct device_attribute
), GFP_KERNEL
);
205 name_copy
= devm_kstrdup(&dev
->pdev
->dev
, name
, GFP_KERNEL
);
209 attrs
->attr
.name
= name_copy
;
210 attrs
->attr
.mode
= mode
;
211 attrs
->show
= show_values
;
212 attrs
->store
= set_values
;
213 sysfs_attr_init(&attrs
->attr
);
215 return device_create_file(&dev
->pdev
->dev
, attrs
);
218 static int create_sysfs_entry_channel(struct hidma_mgmt_dev
*mdev
, char *name
,
220 struct kobject
*parent
)
222 struct hidma_chan_attr
*chattr
;
225 chattr
= devm_kmalloc(&mdev
->pdev
->dev
, sizeof(*chattr
), GFP_KERNEL
);
229 name_copy
= devm_kstrdup(&mdev
->pdev
->dev
, name
, GFP_KERNEL
);
234 chattr
->index
= index
;
235 chattr
->attr
.attr
.name
= name_copy
;
236 chattr
->attr
.attr
.mode
= mode
;
237 chattr
->attr
.show
= show_values_channel
;
238 chattr
->attr
.store
= set_values_channel
;
239 sysfs_attr_init(&chattr
->attr
.attr
);
241 return sysfs_create_file(parent
, &chattr
->attr
.attr
);
244 int hidma_mgmt_init_sys(struct hidma_mgmt_dev
*mdev
)
249 struct kobject
*chanops
;
251 required
= sizeof(*mdev
->chroots
) * mdev
->dma_channels
;
252 mdev
->chroots
= devm_kmalloc(&mdev
->pdev
->dev
, required
, GFP_KERNEL
);
256 chanops
= kobject_create_and_add("chanops", &mdev
->pdev
->dev
.kobj
);
260 /* create each channel directory here */
261 for (i
= 0; i
< mdev
->dma_channels
; i
++) {
264 snprintf(name
, sizeof(name
), "chan%d", i
);
265 mdev
->chroots
[i
] = kobject_create_and_add(name
, chanops
);
266 if (!mdev
->chroots
[i
])
270 /* populate common parameters */
271 for (i
= 0; i
< ARRAY_SIZE(hidma_mgmt_files
); i
++) {
272 rc
= create_sysfs_entry(mdev
, hidma_mgmt_files
[i
].name
,
273 hidma_mgmt_files
[i
].mode
);
278 /* populate parameters that are per channel */
279 for (i
= 0; i
< mdev
->dma_channels
; i
++) {
280 rc
= create_sysfs_entry_channel(mdev
, "priority",
281 (S_IRUGO
| S_IWUGO
), i
,
286 rc
= create_sysfs_entry_channel(mdev
, "weight",
287 (S_IRUGO
| S_IWUGO
), i
,
295 EXPORT_SYMBOL_GPL(hidma_mgmt_init_sys
);