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 hidma_mgmt_dev
*mdev
= dev_get_drvdata(dev
);
115 for (i
= 0; i
< ARRAY_SIZE(hidma_mgmt_files
); i
++) {
116 if (strcmp(attr
->attr
.name
, hidma_mgmt_files
[i
].name
) == 0) {
117 sprintf(buf
, "%d\n", hidma_mgmt_files
[i
].get(mdev
));
124 static ssize_t
set_values(struct device
*dev
, struct device_attribute
*attr
,
125 const char *buf
, size_t count
)
127 struct hidma_mgmt_dev
*mdev
= dev_get_drvdata(dev
);
132 rc
= kstrtoul(buf
, 0, &tmp
);
136 for (i
= 0; i
< ARRAY_SIZE(hidma_mgmt_files
); i
++) {
137 if (strcmp(attr
->attr
.name
, hidma_mgmt_files
[i
].name
) == 0) {
138 rc
= hidma_mgmt_files
[i
].set(mdev
, tmp
);
148 static ssize_t
show_values_channel(struct kobject
*kobj
,
149 struct kobj_attribute
*attr
, char *buf
)
151 struct hidma_chan_attr
*chattr
;
152 struct hidma_mgmt_dev
*mdev
;
155 chattr
= container_of(attr
, struct hidma_chan_attr
, attr
);
157 if (strcmp(attr
->attr
.name
, "priority") == 0)
158 sprintf(buf
, "%d\n", mdev
->priority
[chattr
->index
]);
159 else if (strcmp(attr
->attr
.name
, "weight") == 0)
160 sprintf(buf
, "%d\n", mdev
->weight
[chattr
->index
]);
165 static ssize_t
set_values_channel(struct kobject
*kobj
,
166 struct kobj_attribute
*attr
, const char *buf
,
169 struct hidma_chan_attr
*chattr
;
170 struct hidma_mgmt_dev
*mdev
;
174 chattr
= container_of(attr
, struct hidma_chan_attr
, attr
);
177 rc
= kstrtoul(buf
, 0, &tmp
);
181 if (strcmp(attr
->attr
.name
, "priority") == 0) {
182 rc
= set_priority(mdev
, chattr
->index
, tmp
);
185 } else if (strcmp(attr
->attr
.name
, "weight") == 0) {
186 rc
= set_weight(mdev
, chattr
->index
, tmp
);
193 static int create_sysfs_entry(struct hidma_mgmt_dev
*dev
, char *name
, int mode
)
195 struct device_attribute
*attrs
;
198 attrs
= devm_kmalloc(&dev
->pdev
->dev
,
199 sizeof(struct device_attribute
), GFP_KERNEL
);
203 name_copy
= devm_kstrdup(&dev
->pdev
->dev
, name
, GFP_KERNEL
);
207 attrs
->attr
.name
= name_copy
;
208 attrs
->attr
.mode
= mode
;
209 attrs
->show
= show_values
;
210 attrs
->store
= set_values
;
211 sysfs_attr_init(&attrs
->attr
);
213 return device_create_file(&dev
->pdev
->dev
, attrs
);
216 static int create_sysfs_entry_channel(struct hidma_mgmt_dev
*mdev
, char *name
,
218 struct kobject
*parent
)
220 struct hidma_chan_attr
*chattr
;
223 chattr
= devm_kmalloc(&mdev
->pdev
->dev
, sizeof(*chattr
), GFP_KERNEL
);
227 name_copy
= devm_kstrdup(&mdev
->pdev
->dev
, name
, GFP_KERNEL
);
232 chattr
->index
= index
;
233 chattr
->attr
.attr
.name
= name_copy
;
234 chattr
->attr
.attr
.mode
= mode
;
235 chattr
->attr
.show
= show_values_channel
;
236 chattr
->attr
.store
= set_values_channel
;
237 sysfs_attr_init(&chattr
->attr
.attr
);
239 return sysfs_create_file(parent
, &chattr
->attr
.attr
);
242 int hidma_mgmt_init_sys(struct hidma_mgmt_dev
*mdev
)
247 struct kobject
*chanops
;
249 required
= sizeof(*mdev
->chroots
) * mdev
->dma_channels
;
250 mdev
->chroots
= devm_kmalloc(&mdev
->pdev
->dev
, required
, GFP_KERNEL
);
254 chanops
= kobject_create_and_add("chanops", &mdev
->pdev
->dev
.kobj
);
258 /* create each channel directory here */
259 for (i
= 0; i
< mdev
->dma_channels
; i
++) {
262 snprintf(name
, sizeof(name
), "chan%d", i
);
263 mdev
->chroots
[i
] = kobject_create_and_add(name
, chanops
);
264 if (!mdev
->chroots
[i
])
268 /* populate common parameters */
269 for (i
= 0; i
< ARRAY_SIZE(hidma_mgmt_files
); i
++) {
270 rc
= create_sysfs_entry(mdev
, hidma_mgmt_files
[i
].name
,
271 hidma_mgmt_files
[i
].mode
);
276 /* populate parameters that are per channel */
277 for (i
= 0; i
< mdev
->dma_channels
; i
++) {
278 rc
= create_sysfs_entry_channel(mdev
, "priority",
279 (S_IRUGO
| S_IWUGO
), i
,
284 rc
= create_sysfs_entry_channel(mdev
, "weight",
285 (S_IRUGO
| S_IWUGO
), i
,
293 EXPORT_SYMBOL_GPL(hidma_mgmt_init_sys
);