1 // SPDX-License-Identifier: GPL-2.0-only
3 * Qualcomm Technologies HIDMA Management SYS interface
5 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
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
;
16 struct kobj_attribute attr
;
19 struct hidma_mgmt_fileinfo
{
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) \
31 static int set_##name(struct hidma_mgmt_dev *mdev, u64 val) \
38 rc = hidma_mgmt_setup(mdev); \
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
)
61 if (i
>= mdev
->dma_channels
)
64 tmp
= mdev
->priority
[i
];
65 mdev
->priority
[i
] = val
;
66 rc
= hidma_mgmt_setup(mdev
);
68 mdev
->priority
[i
] = tmp
;
72 static int set_weight(struct hidma_mgmt_dev
*mdev
, unsigned int i
, u64 val
)
77 if (i
>= mdev
->dma_channels
)
80 tmp
= mdev
->weight
[i
];
81 mdev
->weight
[i
] = val
;
82 rc
= hidma_mgmt_setup(mdev
);
84 mdev
->weight
[i
] = tmp
;
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
,
102 struct hidma_mgmt_dev
*mdev
= dev_get_drvdata(dev
);
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
));
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
);
124 rc
= kstrtoul(buf
, 0, &tmp
);
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
);
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
;
147 chattr
= container_of(attr
, struct hidma_chan_attr
, attr
);
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
]);
157 static ssize_t
set_values_channel(struct kobject
*kobj
,
158 struct kobj_attribute
*attr
, const char *buf
,
161 struct hidma_chan_attr
*chattr
;
162 struct hidma_mgmt_dev
*mdev
;
166 chattr
= container_of(attr
, struct hidma_chan_attr
, attr
);
169 rc
= kstrtoul(buf
, 0, &tmp
);
173 if (strcmp(attr
->attr
.name
, "priority") == 0) {
174 rc
= set_priority(mdev
, chattr
->index
, tmp
);
177 } else if (strcmp(attr
->attr
.name
, "weight") == 0) {
178 rc
= set_weight(mdev
, chattr
->index
, tmp
);
185 static int create_sysfs_entry(struct hidma_mgmt_dev
*dev
, char *name
, int mode
)
187 struct device_attribute
*attrs
;
190 attrs
= devm_kmalloc(&dev
->pdev
->dev
,
191 sizeof(struct device_attribute
), GFP_KERNEL
);
195 name_copy
= devm_kstrdup(&dev
->pdev
->dev
, name
, GFP_KERNEL
);
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
,
210 struct kobject
*parent
)
212 struct hidma_chan_attr
*chattr
;
215 chattr
= devm_kmalloc(&mdev
->pdev
->dev
, sizeof(*chattr
), GFP_KERNEL
);
219 name_copy
= devm_kstrdup(&mdev
->pdev
->dev
, name
, GFP_KERNEL
);
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
)
239 struct kobject
*chanops
;
241 required
= sizeof(*mdev
->chroots
) * mdev
->dma_channels
;
242 mdev
->chroots
= devm_kmalloc(&mdev
->pdev
->dev
, required
, GFP_KERNEL
);
246 chanops
= kobject_create_and_add("chanops", &mdev
->pdev
->dev
.kobj
);
250 /* create each channel directory here */
251 for (i
= 0; i
< mdev
->dma_channels
; i
++) {
254 snprintf(name
, sizeof(name
), "chan%d", i
);
255 mdev
->chroots
[i
] = kobject_create_and_add(name
, chanops
);
256 if (!mdev
->chroots
[i
])
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
);
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
,
276 rc
= create_sysfs_entry_channel(mdev
, "weight",
277 (S_IRUGO
| S_IWUGO
), i
,
285 EXPORT_SYMBOL_GPL(hidma_mgmt_init_sys
);