1
2
3#include "gasket_sysfs.h"
4
5#include "gasket_core.h"
6
7#include <linux/device.h>
8#include <linux/printk.h>
9
10
11
12
13
14
15struct gasket_sysfs_mapping {
16
17
18
19
20 struct device *device;
21
22
23 struct gasket_dev *gasket_dev;
24
25
26 struct gasket_sysfs_attribute *attributes;
27
28
29 int attribute_count;
30
31
32 struct mutex mutex;
33
34
35 struct kref refcount;
36};
37
38
39
40
41
42
43
44
45
46
47
48static struct gasket_sysfs_mapping dev_mappings[GASKET_SYSFS_NUM_MAPPINGS];
49
50
51static void release_entry(struct kref *ref)
52{
53
54}
55
56
57static struct gasket_sysfs_mapping *get_mapping(struct device *device)
58{
59 int i;
60
61 for (i = 0; i < GASKET_SYSFS_NUM_MAPPINGS; i++) {
62 mutex_lock(&dev_mappings[i].mutex);
63 if (dev_mappings[i].device == device) {
64 kref_get(&dev_mappings[i].refcount);
65 mutex_unlock(&dev_mappings[i].mutex);
66 return &dev_mappings[i];
67 }
68 mutex_unlock(&dev_mappings[i].mutex);
69 }
70
71 dev_dbg(device, "%s: Mapping to device %s not found\n",
72 __func__, device->kobj.name);
73 return NULL;
74}
75
76
77static void put_mapping(struct gasket_sysfs_mapping *mapping)
78{
79 int i;
80 int num_files_to_remove = 0;
81 struct device_attribute *files_to_remove;
82 struct device *device;
83
84 if (!mapping) {
85 pr_debug("%s: Mapping should not be NULL\n", __func__);
86 return;
87 }
88
89 mutex_lock(&mapping->mutex);
90 if (kref_put(&mapping->refcount, release_entry)) {
91 dev_dbg(mapping->device, "Removing Gasket sysfs mapping\n");
92
93
94
95
96
97
98
99 device = mapping->device;
100 num_files_to_remove = mapping->attribute_count;
101 files_to_remove = kcalloc(num_files_to_remove,
102 sizeof(*files_to_remove),
103 GFP_KERNEL);
104 if (files_to_remove)
105 for (i = 0; i < num_files_to_remove; i++)
106 files_to_remove[i] =
107 mapping->attributes[i].attr;
108 else
109 num_files_to_remove = 0;
110
111 kfree(mapping->attributes);
112 mapping->attributes = NULL;
113 mapping->attribute_count = 0;
114 put_device(mapping->device);
115 mapping->device = NULL;
116 mapping->gasket_dev = NULL;
117 }
118 mutex_unlock(&mapping->mutex);
119
120 if (num_files_to_remove != 0) {
121 for (i = 0; i < num_files_to_remove; ++i)
122 device_remove_file(device, &files_to_remove[i]);
123 kfree(files_to_remove);
124 }
125}
126
127
128
129
130
131
132
133
134static void put_mapping_n(struct gasket_sysfs_mapping *mapping, int times)
135{
136 int i;
137
138 for (i = 0; i < times; i++)
139 put_mapping(mapping);
140}
141
142void gasket_sysfs_init(void)
143{
144 int i;
145
146 for (i = 0; i < GASKET_SYSFS_NUM_MAPPINGS; i++) {
147 dev_mappings[i].device = NULL;
148 mutex_init(&dev_mappings[i].mutex);
149 }
150}
151
152int gasket_sysfs_create_mapping(struct device *device,
153 struct gasket_dev *gasket_dev)
154{
155 struct gasket_sysfs_mapping *mapping;
156 int map_idx = -1;
157
158
159
160
161
162 static DEFINE_MUTEX(function_mutex);
163
164 mutex_lock(&function_mutex);
165 dev_dbg(device, "Creating sysfs entries for device\n");
166
167
168 mapping = get_mapping(device);
169 if (mapping) {
170 dev_err(device,
171 "Attempting to re-initialize sysfs mapping for device\n");
172 put_mapping(mapping);
173 mutex_unlock(&function_mutex);
174 return -EBUSY;
175 }
176
177
178 for (map_idx = 0; map_idx < GASKET_SYSFS_NUM_MAPPINGS; ++map_idx) {
179 mutex_lock(&dev_mappings[map_idx].mutex);
180 if (!dev_mappings[map_idx].device)
181
182 break;
183 mutex_unlock(&dev_mappings[map_idx].mutex);
184 }
185
186 if (map_idx == GASKET_SYSFS_NUM_MAPPINGS) {
187 dev_err(device, "All mappings have been exhausted\n");
188 mutex_unlock(&function_mutex);
189 return -ENOMEM;
190 }
191
192 dev_dbg(device, "Creating sysfs mapping for device %s\n",
193 device->kobj.name);
194
195 mapping = &dev_mappings[map_idx];
196 mapping->attributes = kcalloc(GASKET_SYSFS_MAX_NODES,
197 sizeof(*mapping->attributes),
198 GFP_KERNEL);
199 if (!mapping->attributes) {
200 dev_dbg(device, "Unable to allocate sysfs attribute array\n");
201 mutex_unlock(&mapping->mutex);
202 mutex_unlock(&function_mutex);
203 return -ENOMEM;
204 }
205
206 kref_init(&mapping->refcount);
207 mapping->device = get_device(device);
208 mapping->gasket_dev = gasket_dev;
209 mapping->attribute_count = 0;
210 mutex_unlock(&mapping->mutex);
211 mutex_unlock(&function_mutex);
212
213
214 return 0;
215}
216
217int gasket_sysfs_create_entries(struct device *device,
218 const struct gasket_sysfs_attribute *attrs)
219{
220 int i;
221 int ret;
222 struct gasket_sysfs_mapping *mapping = get_mapping(device);
223
224 if (!mapping) {
225 dev_dbg(device,
226 "Creating entries for device without first initializing mapping\n");
227 return -EINVAL;
228 }
229
230 mutex_lock(&mapping->mutex);
231 for (i = 0; strcmp(attrs[i].attr.attr.name, GASKET_ARRAY_END_MARKER);
232 i++) {
233 if (mapping->attribute_count == GASKET_SYSFS_MAX_NODES) {
234 dev_err(device,
235 "Maximum number of sysfs nodes reached for device\n");
236 mutex_unlock(&mapping->mutex);
237 put_mapping(mapping);
238 return -ENOMEM;
239 }
240
241 ret = device_create_file(device, &attrs[i].attr);
242 if (ret) {
243 dev_dbg(device, "Unable to create device entries\n");
244 mutex_unlock(&mapping->mutex);
245 put_mapping(mapping);
246 return ret;
247 }
248
249 mapping->attributes[mapping->attribute_count] = attrs[i];
250 ++mapping->attribute_count;
251 }
252
253 mutex_unlock(&mapping->mutex);
254 put_mapping(mapping);
255 return 0;
256}
257EXPORT_SYMBOL(gasket_sysfs_create_entries);
258
259void gasket_sysfs_remove_mapping(struct device *device)
260{
261 struct gasket_sysfs_mapping *mapping = get_mapping(device);
262
263 if (!mapping) {
264 dev_err(device,
265 "Attempted to remove non-existent sysfs mapping to device\n");
266 return;
267 }
268
269 put_mapping_n(mapping, 2);
270}
271
272struct gasket_dev *gasket_sysfs_get_device_data(struct device *device)
273{
274 struct gasket_sysfs_mapping *mapping = get_mapping(device);
275
276 if (!mapping) {
277 dev_err(device, "device not registered\n");
278 return NULL;
279 }
280
281 return mapping->gasket_dev;
282}
283EXPORT_SYMBOL(gasket_sysfs_get_device_data);
284
285void gasket_sysfs_put_device_data(struct device *device, struct gasket_dev *dev)
286{
287 struct gasket_sysfs_mapping *mapping = get_mapping(device);
288
289 if (!mapping)
290 return;
291
292
293 put_mapping_n(mapping, 2);
294}
295EXPORT_SYMBOL(gasket_sysfs_put_device_data);
296
297struct gasket_sysfs_attribute *
298gasket_sysfs_get_attr(struct device *device, struct device_attribute *attr)
299{
300 int i;
301 int num_attrs;
302 struct gasket_sysfs_mapping *mapping = get_mapping(device);
303 struct gasket_sysfs_attribute *attrs = NULL;
304
305 if (!mapping)
306 return NULL;
307
308 attrs = mapping->attributes;
309 num_attrs = mapping->attribute_count;
310 for (i = 0; i < num_attrs; ++i) {
311 if (!strcmp(attrs[i].attr.attr.name, attr->attr.name))
312 return &attrs[i];
313 }
314
315 dev_err(device, "Unable to find match for device_attribute %s\n",
316 attr->attr.name);
317 return NULL;
318}
319EXPORT_SYMBOL(gasket_sysfs_get_attr);
320
321void gasket_sysfs_put_attr(struct device *device,
322 struct gasket_sysfs_attribute *attr)
323{
324 int i;
325 int num_attrs;
326 struct gasket_sysfs_mapping *mapping = get_mapping(device);
327 struct gasket_sysfs_attribute *attrs = NULL;
328
329 if (!mapping)
330 return;
331
332 attrs = mapping->attributes;
333 num_attrs = mapping->attribute_count;
334 for (i = 0; i < num_attrs; ++i) {
335 if (&attrs[i] == attr) {
336 put_mapping_n(mapping, 2);
337 return;
338 }
339 }
340
341 dev_err(device, "Unable to put unknown attribute: %s\n",
342 attr->attr.attr.name);
343}
344EXPORT_SYMBOL(gasket_sysfs_put_attr);
345
346ssize_t gasket_sysfs_register_store(struct device *device,
347 struct device_attribute *attr,
348 const char *buf, size_t count)
349{
350 ulong parsed_value = 0;
351 struct gasket_sysfs_mapping *mapping;
352 struct gasket_dev *gasket_dev;
353 struct gasket_sysfs_attribute *gasket_attr;
354
355 if (count < 3 || buf[0] != '0' || buf[1] != 'x') {
356 dev_err(device,
357 "sysfs register write format: \"0x<hex value>\"\n");
358 return -EINVAL;
359 }
360
361 if (kstrtoul(buf, 16, &parsed_value) != 0) {
362 dev_err(device,
363 "Unable to parse input as 64-bit hex value: %s\n", buf);
364 return -EINVAL;
365 }
366
367 mapping = get_mapping(device);
368 if (!mapping) {
369 dev_err(device, "Device driver may have been removed\n");
370 return 0;
371 }
372
373 gasket_dev = mapping->gasket_dev;
374 if (!gasket_dev) {
375 dev_err(device, "Device driver may have been removed\n");
376 return 0;
377 }
378
379 gasket_attr = gasket_sysfs_get_attr(device, attr);
380 if (!gasket_attr) {
381 put_mapping(mapping);
382 return count;
383 }
384
385 gasket_dev_write_64(gasket_dev, parsed_value,
386 gasket_attr->data.bar_address.bar,
387 gasket_attr->data.bar_address.offset);
388
389 if (gasket_attr->write_callback)
390 gasket_attr->write_callback(gasket_dev, gasket_attr,
391 parsed_value);
392
393 gasket_sysfs_put_attr(device, gasket_attr);
394 put_mapping(mapping);
395 return count;
396}
397EXPORT_SYMBOL(gasket_sysfs_register_store);
398