xref: /linux/drivers/counter/counter-sysfs.c (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Generic Counter sysfs interface
4  * Copyright (C) 2020 William Breathitt Gray
5  */
6 #include <linux/counter.h>
7 #include <linux/device.h>
8 #include <linux/err.h>
9 #include <linux/gfp.h>
10 #include <linux/kernel.h>
11 #include <linux/kfifo.h>
12 #include <linux/kstrtox.h>
13 #include <linux/list.h>
14 #include <linux/mutex.h>
15 #include <linux/spinlock.h>
16 #include <linux/string.h>
17 #include <linux/sysfs.h>
18 #include <linux/types.h>
19 
20 #include "counter-sysfs.h"
21 
counter_from_dev(struct device * dev)22 static inline struct counter_device *counter_from_dev(struct device *dev)
23 {
24 	return container_of(dev, struct counter_device, dev);
25 }
26 
27 /**
28  * struct counter_attribute - Counter sysfs attribute
29  * @dev_attr:	device attribute for sysfs
30  * @l:		node to add Counter attribute to attribute group list
31  * @comp:	Counter component callbacks and data
32  * @scope:	Counter scope of the attribute
33  * @parent:	pointer to the parent component
34  */
35 struct counter_attribute {
36 	struct device_attribute dev_attr;
37 	struct list_head l;
38 
39 	struct counter_comp comp;
40 	enum counter_scope scope;
41 	void *parent;
42 };
43 
44 #define to_counter_attribute(_dev_attr) \
45 	container_of(_dev_attr, struct counter_attribute, dev_attr)
46 
47 /**
48  * struct counter_attribute_group - container for attribute group
49  * @name:	name of the attribute group
50  * @attr_list:	list to keep track of created attributes
51  * @num_attr:	number of attributes
52  */
53 struct counter_attribute_group {
54 	const char *name;
55 	struct list_head attr_list;
56 	size_t num_attr;
57 };
58 
59 static const char *const counter_function_str[] = {
60 	[COUNTER_FUNCTION_INCREASE] = "increase",
61 	[COUNTER_FUNCTION_DECREASE] = "decrease",
62 	[COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
63 	[COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
64 	[COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
65 	[COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
66 	[COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
67 	[COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4"
68 };
69 
70 static const char *const counter_signal_value_str[] = {
71 	[COUNTER_SIGNAL_LEVEL_LOW] = "low",
72 	[COUNTER_SIGNAL_LEVEL_HIGH] = "high"
73 };
74 
75 static const char *const counter_synapse_action_str[] = {
76 	[COUNTER_SYNAPSE_ACTION_NONE] = "none",
77 	[COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge",
78 	[COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge",
79 	[COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges"
80 };
81 
82 static const char *const counter_count_direction_str[] = {
83 	[COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
84 	[COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
85 };
86 
87 static const char *const counter_count_mode_str[] = {
88 	[COUNTER_COUNT_MODE_NORMAL] = "normal",
89 	[COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
90 	[COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
91 	[COUNTER_COUNT_MODE_MODULO_N] = "modulo-n",
92 	[COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT] = "interrupt on terminal count",
93 	[COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT] = "hardware retriggerable one-shot",
94 	[COUNTER_COUNT_MODE_RATE_GENERATOR] = "rate generator",
95 	[COUNTER_COUNT_MODE_SQUARE_WAVE_MODE] = "square wave mode",
96 	[COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE] = "software triggered strobe",
97 	[COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE] = "hardware triggered strobe",
98 };
99 
100 static const char *const counter_signal_polarity_str[] = {
101 	[COUNTER_SIGNAL_POLARITY_POSITIVE] = "positive",
102 	[COUNTER_SIGNAL_POLARITY_NEGATIVE] = "negative"
103 };
104 
counter_comp_u8_show(struct device * dev,struct device_attribute * attr,char * buf)105 static ssize_t counter_comp_u8_show(struct device *dev,
106 				    struct device_attribute *attr, char *buf)
107 {
108 	const struct counter_attribute *const a = to_counter_attribute(attr);
109 	struct counter_device *const counter = counter_from_dev(dev);
110 	int err;
111 	u8 data = 0;
112 
113 	switch (a->scope) {
114 	case COUNTER_SCOPE_DEVICE:
115 		err = a->comp.device_u8_read(counter, &data);
116 		break;
117 	case COUNTER_SCOPE_SIGNAL:
118 		err = a->comp.signal_u8_read(counter, a->parent, &data);
119 		break;
120 	case COUNTER_SCOPE_COUNT:
121 		err = a->comp.count_u8_read(counter, a->parent, &data);
122 		break;
123 	default:
124 		return -EINVAL;
125 	}
126 	if (err < 0)
127 		return err;
128 
129 	if (a->comp.type == COUNTER_COMP_BOOL)
130 		/* data should already be boolean but ensure just to be safe */
131 		data = !!data;
132 
133 	return sysfs_emit(buf, "%u\n", (unsigned int)data);
134 }
135 
counter_comp_u8_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)136 static ssize_t counter_comp_u8_store(struct device *dev,
137 				     struct device_attribute *attr,
138 				     const char *buf, size_t len)
139 {
140 	const struct counter_attribute *const a = to_counter_attribute(attr);
141 	struct counter_device *const counter = counter_from_dev(dev);
142 	int err;
143 	bool bool_data = 0;
144 	u8 data = 0;
145 
146 	if (a->comp.type == COUNTER_COMP_BOOL) {
147 		err = kstrtobool(buf, &bool_data);
148 		data = bool_data;
149 	} else
150 		err = kstrtou8(buf, 0, &data);
151 	if (err < 0)
152 		return err;
153 
154 	switch (a->scope) {
155 	case COUNTER_SCOPE_DEVICE:
156 		err = a->comp.device_u8_write(counter, data);
157 		break;
158 	case COUNTER_SCOPE_SIGNAL:
159 		err = a->comp.signal_u8_write(counter, a->parent, data);
160 		break;
161 	case COUNTER_SCOPE_COUNT:
162 		err = a->comp.count_u8_write(counter, a->parent, data);
163 		break;
164 	default:
165 		return -EINVAL;
166 	}
167 	if (err < 0)
168 		return err;
169 
170 	return len;
171 }
172 
counter_comp_u32_show(struct device * dev,struct device_attribute * attr,char * buf)173 static ssize_t counter_comp_u32_show(struct device *dev,
174 				     struct device_attribute *attr, char *buf)
175 {
176 	const struct counter_attribute *const a = to_counter_attribute(attr);
177 	struct counter_device *const counter = counter_from_dev(dev);
178 	const struct counter_available *const avail = a->comp.priv;
179 	int err;
180 	u32 data = 0;
181 
182 	switch (a->scope) {
183 	case COUNTER_SCOPE_DEVICE:
184 		err = a->comp.device_u32_read(counter, &data);
185 		break;
186 	case COUNTER_SCOPE_SIGNAL:
187 		err = a->comp.signal_u32_read(counter, a->parent, &data);
188 		break;
189 	case COUNTER_SCOPE_COUNT:
190 		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
191 			err = a->comp.action_read(counter, a->parent,
192 						  a->comp.priv, &data);
193 		else
194 			err = a->comp.count_u32_read(counter, a->parent, &data);
195 		break;
196 	default:
197 		return -EINVAL;
198 	}
199 	if (err < 0)
200 		return err;
201 
202 	switch (a->comp.type) {
203 	case COUNTER_COMP_FUNCTION:
204 		return sysfs_emit(buf, "%s\n", counter_function_str[data]);
205 	case COUNTER_COMP_SIGNAL_LEVEL:
206 		return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]);
207 	case COUNTER_COMP_SYNAPSE_ACTION:
208 		return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]);
209 	case COUNTER_COMP_ENUM:
210 		return sysfs_emit(buf, "%s\n", avail->strs[data]);
211 	case COUNTER_COMP_COUNT_DIRECTION:
212 		return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]);
213 	case COUNTER_COMP_COUNT_MODE:
214 		return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]);
215 	case COUNTER_COMP_SIGNAL_POLARITY:
216 		return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
217 	default:
218 		return sysfs_emit(buf, "%u\n", (unsigned int)data);
219 	}
220 }
221 
counter_find_enum(u32 * const enum_item,const u32 * const enums,const size_t num_enums,const char * const buf,const char * const string_array[])222 static int counter_find_enum(u32 *const enum_item, const u32 *const enums,
223 			     const size_t num_enums, const char *const buf,
224 			     const char *const string_array[])
225 {
226 	size_t index;
227 
228 	for (index = 0; index < num_enums; index++) {
229 		*enum_item = enums[index];
230 		if (sysfs_streq(buf, string_array[*enum_item]))
231 			return 0;
232 	}
233 
234 	return -EINVAL;
235 }
236 
counter_comp_u32_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)237 static ssize_t counter_comp_u32_store(struct device *dev,
238 				      struct device_attribute *attr,
239 				      const char *buf, size_t len)
240 {
241 	const struct counter_attribute *const a = to_counter_attribute(attr);
242 	struct counter_device *const counter = counter_from_dev(dev);
243 	struct counter_count *const count = a->parent;
244 	struct counter_synapse *const synapse = a->comp.priv;
245 	const struct counter_available *const avail = a->comp.priv;
246 	int err;
247 	u32 data = 0;
248 
249 	switch (a->comp.type) {
250 	case COUNTER_COMP_FUNCTION:
251 		err = counter_find_enum(&data, count->functions_list,
252 					count->num_functions, buf,
253 					counter_function_str);
254 		break;
255 	case COUNTER_COMP_SYNAPSE_ACTION:
256 		err = counter_find_enum(&data, synapse->actions_list,
257 					synapse->num_actions, buf,
258 					counter_synapse_action_str);
259 		break;
260 	case COUNTER_COMP_ENUM:
261 		err = __sysfs_match_string(avail->strs, avail->num_items, buf);
262 		data = err;
263 		break;
264 	case COUNTER_COMP_COUNT_MODE:
265 		err = counter_find_enum(&data, avail->enums, avail->num_items,
266 					buf, counter_count_mode_str);
267 		break;
268 	case COUNTER_COMP_SIGNAL_POLARITY:
269 		err = counter_find_enum(&data, avail->enums, avail->num_items,
270 					buf, counter_signal_polarity_str);
271 		break;
272 	default:
273 		err = kstrtou32(buf, 0, &data);
274 		break;
275 	}
276 	if (err < 0)
277 		return err;
278 
279 	switch (a->scope) {
280 	case COUNTER_SCOPE_DEVICE:
281 		err = a->comp.device_u32_write(counter, data);
282 		break;
283 	case COUNTER_SCOPE_SIGNAL:
284 		err = a->comp.signal_u32_write(counter, a->parent, data);
285 		break;
286 	case COUNTER_SCOPE_COUNT:
287 		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
288 			err = a->comp.action_write(counter, count, synapse,
289 						   data);
290 		else
291 			err = a->comp.count_u32_write(counter, count, data);
292 		break;
293 	default:
294 		return -EINVAL;
295 	}
296 	if (err < 0)
297 		return err;
298 
299 	return len;
300 }
301 
counter_comp_u64_show(struct device * dev,struct device_attribute * attr,char * buf)302 static ssize_t counter_comp_u64_show(struct device *dev,
303 				     struct device_attribute *attr, char *buf)
304 {
305 	const struct counter_attribute *const a = to_counter_attribute(attr);
306 	struct counter_device *const counter = counter_from_dev(dev);
307 	int err;
308 	u64 data = 0;
309 
310 	switch (a->scope) {
311 	case COUNTER_SCOPE_DEVICE:
312 		err = a->comp.device_u64_read(counter, &data);
313 		break;
314 	case COUNTER_SCOPE_SIGNAL:
315 		err = a->comp.signal_u64_read(counter, a->parent, &data);
316 		break;
317 	case COUNTER_SCOPE_COUNT:
318 		err = a->comp.count_u64_read(counter, a->parent, &data);
319 		break;
320 	default:
321 		return -EINVAL;
322 	}
323 	if (err < 0)
324 		return err;
325 
326 	return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
327 }
328 
counter_comp_u64_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)329 static ssize_t counter_comp_u64_store(struct device *dev,
330 				      struct device_attribute *attr,
331 				      const char *buf, size_t len)
332 {
333 	const struct counter_attribute *const a = to_counter_attribute(attr);
334 	struct counter_device *const counter = counter_from_dev(dev);
335 	int err;
336 	u64 data = 0;
337 
338 	err = kstrtou64(buf, 0, &data);
339 	if (err < 0)
340 		return err;
341 
342 	switch (a->scope) {
343 	case COUNTER_SCOPE_DEVICE:
344 		err = a->comp.device_u64_write(counter, data);
345 		break;
346 	case COUNTER_SCOPE_SIGNAL:
347 		err = a->comp.signal_u64_write(counter, a->parent, data);
348 		break;
349 	case COUNTER_SCOPE_COUNT:
350 		err = a->comp.count_u64_write(counter, a->parent, data);
351 		break;
352 	default:
353 		return -EINVAL;
354 	}
355 	if (err < 0)
356 		return err;
357 
358 	return len;
359 }
360 
counter_comp_array_u32_show(struct device * dev,struct device_attribute * attr,char * buf)361 static ssize_t counter_comp_array_u32_show(struct device *dev,
362 					   struct device_attribute *attr,
363 					   char *buf)
364 {
365 	const struct counter_attribute *const a = to_counter_attribute(attr);
366 	struct counter_device *const counter = counter_from_dev(dev);
367 	const struct counter_array *const element = a->comp.priv;
368 	int err;
369 	u32 data = 0;
370 
371 	if (a->scope != COUNTER_SCOPE_SIGNAL ||
372 	    element->type != COUNTER_COMP_SIGNAL_POLARITY)
373 		return -EINVAL;
374 
375 	err = a->comp.signal_array_u32_read(counter, a->parent, element->idx,
376 					    &data);
377 	if (err < 0)
378 		return err;
379 
380 	return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
381 }
382 
counter_comp_array_u32_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)383 static ssize_t counter_comp_array_u32_store(struct device *dev,
384 					    struct device_attribute *attr,
385 					    const char *buf, size_t len)
386 {
387 	const struct counter_attribute *const a = to_counter_attribute(attr);
388 	struct counter_device *const counter = counter_from_dev(dev);
389 	const struct counter_array *const element = a->comp.priv;
390 	int err;
391 	u32 data = 0;
392 
393 	if (element->type != COUNTER_COMP_SIGNAL_POLARITY ||
394 	    a->scope != COUNTER_SCOPE_SIGNAL)
395 		return -EINVAL;
396 
397 	err = counter_find_enum(&data, element->avail->enums,
398 				element->avail->num_items, buf,
399 				counter_signal_polarity_str);
400 	if (err < 0)
401 		return err;
402 
403 	err = a->comp.signal_array_u32_write(counter, a->parent, element->idx,
404 					     data);
405 	if (err < 0)
406 		return err;
407 
408 	return len;
409 }
410 
counter_comp_array_u64_show(struct device * dev,struct device_attribute * attr,char * buf)411 static ssize_t counter_comp_array_u64_show(struct device *dev,
412 					   struct device_attribute *attr,
413 					   char *buf)
414 {
415 	const struct counter_attribute *const a = to_counter_attribute(attr);
416 	struct counter_device *const counter = counter_from_dev(dev);
417 	const struct counter_array *const element = a->comp.priv;
418 	int err;
419 	u64 data = 0;
420 
421 	switch (a->scope) {
422 	case COUNTER_SCOPE_DEVICE:
423 		err = a->comp.device_array_u64_read(counter, element->idx,
424 						    &data);
425 		break;
426 	case COUNTER_SCOPE_SIGNAL:
427 		err = a->comp.signal_array_u64_read(counter, a->parent,
428 						    element->idx, &data);
429 		break;
430 	case COUNTER_SCOPE_COUNT:
431 		err = a->comp.count_array_u64_read(counter, a->parent,
432 						   element->idx, &data);
433 		break;
434 	default:
435 		return -EINVAL;
436 	}
437 	if (err < 0)
438 		return err;
439 
440 	return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
441 }
442 
counter_comp_array_u64_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)443 static ssize_t counter_comp_array_u64_store(struct device *dev,
444 					    struct device_attribute *attr,
445 					    const char *buf, size_t len)
446 {
447 	const struct counter_attribute *const a = to_counter_attribute(attr);
448 	struct counter_device *const counter = counter_from_dev(dev);
449 	const struct counter_array *const element = a->comp.priv;
450 	int err;
451 	u64 data = 0;
452 
453 	err = kstrtou64(buf, 0, &data);
454 	if (err < 0)
455 		return err;
456 
457 	switch (a->scope) {
458 	case COUNTER_SCOPE_DEVICE:
459 		err = a->comp.device_array_u64_write(counter, element->idx,
460 						     data);
461 		break;
462 	case COUNTER_SCOPE_SIGNAL:
463 		err = a->comp.signal_array_u64_write(counter, a->parent,
464 						     element->idx, data);
465 		break;
466 	case COUNTER_SCOPE_COUNT:
467 		err = a->comp.count_array_u64_write(counter, a->parent,
468 						    element->idx, data);
469 		break;
470 	default:
471 		return -EINVAL;
472 	}
473 	if (err < 0)
474 		return err;
475 
476 	return len;
477 }
478 
enums_available_show(const u32 * const enums,const size_t num_enums,const char * const strs[],char * buf)479 static ssize_t enums_available_show(const u32 *const enums,
480 				    const size_t num_enums,
481 				    const char *const strs[], char *buf)
482 {
483 	size_t len = 0;
484 	size_t index;
485 
486 	for (index = 0; index < num_enums; index++)
487 		len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]);
488 
489 	return len;
490 }
491 
strs_available_show(const struct counter_available * const avail,char * buf)492 static ssize_t strs_available_show(const struct counter_available *const avail,
493 				   char *buf)
494 {
495 	size_t len = 0;
496 	size_t index;
497 
498 	for (index = 0; index < avail->num_items; index++)
499 		len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]);
500 
501 	return len;
502 }
503 
counter_comp_available_show(struct device * dev,struct device_attribute * attr,char * buf)504 static ssize_t counter_comp_available_show(struct device *dev,
505 					   struct device_attribute *attr,
506 					   char *buf)
507 {
508 	const struct counter_attribute *const a = to_counter_attribute(attr);
509 	const struct counter_count *const count = a->parent;
510 	const struct counter_synapse *const synapse = a->comp.priv;
511 	const struct counter_available *const avail = a->comp.priv;
512 
513 	switch (a->comp.type) {
514 	case COUNTER_COMP_FUNCTION:
515 		return enums_available_show(count->functions_list,
516 					    count->num_functions,
517 					    counter_function_str, buf);
518 	case COUNTER_COMP_SYNAPSE_ACTION:
519 		return enums_available_show(synapse->actions_list,
520 					    synapse->num_actions,
521 					    counter_synapse_action_str, buf);
522 	case COUNTER_COMP_ENUM:
523 		return strs_available_show(avail, buf);
524 	case COUNTER_COMP_COUNT_MODE:
525 		return enums_available_show(avail->enums, avail->num_items,
526 					    counter_count_mode_str, buf);
527 	default:
528 		return -EINVAL;
529 	}
530 }
531 
counter_avail_attr_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const comp,void * const parent)532 static int counter_avail_attr_create(struct device *const dev,
533 	struct counter_attribute_group *const group,
534 	const struct counter_comp *const comp, void *const parent)
535 {
536 	struct counter_attribute *counter_attr;
537 	struct device_attribute *dev_attr;
538 
539 	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
540 	if (!counter_attr)
541 		return -ENOMEM;
542 
543 	/* Configure Counter attribute */
544 	counter_attr->comp.type = comp->type;
545 	counter_attr->comp.priv = comp->priv;
546 	counter_attr->parent = parent;
547 
548 	/* Initialize sysfs attribute */
549 	dev_attr = &counter_attr->dev_attr;
550 	sysfs_attr_init(&dev_attr->attr);
551 
552 	/* Configure device attribute */
553 	dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available",
554 					     comp->name);
555 	if (!dev_attr->attr.name)
556 		return -ENOMEM;
557 	dev_attr->attr.mode = 0444;
558 	dev_attr->show = counter_comp_available_show;
559 
560 	/* Store list node */
561 	list_add(&counter_attr->l, &group->attr_list);
562 	group->num_attr++;
563 
564 	return 0;
565 }
566 
counter_attr_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const comp,const enum counter_scope scope,void * const parent)567 static int counter_attr_create(struct device *const dev,
568 			       struct counter_attribute_group *const group,
569 			       const struct counter_comp *const comp,
570 			       const enum counter_scope scope,
571 			       void *const parent)
572 {
573 	const struct counter_array *const array = comp->priv;
574 	struct counter_attribute *counter_attr;
575 	struct device_attribute *dev_attr;
576 
577 	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
578 	if (!counter_attr)
579 		return -ENOMEM;
580 
581 	/* Configure Counter attribute */
582 	counter_attr->comp = *comp;
583 	counter_attr->scope = scope;
584 	counter_attr->parent = parent;
585 
586 	/* Configure device attribute */
587 	dev_attr = &counter_attr->dev_attr;
588 	sysfs_attr_init(&dev_attr->attr);
589 	dev_attr->attr.name = comp->name;
590 	switch (comp->type) {
591 	case COUNTER_COMP_U8:
592 	case COUNTER_COMP_BOOL:
593 		if (comp->device_u8_read) {
594 			dev_attr->attr.mode |= 0444;
595 			dev_attr->show = counter_comp_u8_show;
596 		}
597 		if (comp->device_u8_write) {
598 			dev_attr->attr.mode |= 0200;
599 			dev_attr->store = counter_comp_u8_store;
600 		}
601 		break;
602 	case COUNTER_COMP_SIGNAL_LEVEL:
603 	case COUNTER_COMP_FUNCTION:
604 	case COUNTER_COMP_SYNAPSE_ACTION:
605 	case COUNTER_COMP_ENUM:
606 	case COUNTER_COMP_COUNT_DIRECTION:
607 	case COUNTER_COMP_COUNT_MODE:
608 	case COUNTER_COMP_SIGNAL_POLARITY:
609 		if (comp->device_u32_read) {
610 			dev_attr->attr.mode |= 0444;
611 			dev_attr->show = counter_comp_u32_show;
612 		}
613 		if (comp->device_u32_write) {
614 			dev_attr->attr.mode |= 0200;
615 			dev_attr->store = counter_comp_u32_store;
616 		}
617 		break;
618 	case COUNTER_COMP_U64:
619 		if (comp->device_u64_read) {
620 			dev_attr->attr.mode |= 0444;
621 			dev_attr->show = counter_comp_u64_show;
622 		}
623 		if (comp->device_u64_write) {
624 			dev_attr->attr.mode |= 0200;
625 			dev_attr->store = counter_comp_u64_store;
626 		}
627 		break;
628 	case COUNTER_COMP_ARRAY:
629 		switch (array->type) {
630 		case COUNTER_COMP_SIGNAL_POLARITY:
631 			if (comp->signal_array_u32_read) {
632 				dev_attr->attr.mode |= 0444;
633 				dev_attr->show = counter_comp_array_u32_show;
634 			}
635 			if (comp->signal_array_u32_write) {
636 				dev_attr->attr.mode |= 0200;
637 				dev_attr->store = counter_comp_array_u32_store;
638 			}
639 			break;
640 		case COUNTER_COMP_U64:
641 			if (comp->device_array_u64_read) {
642 				dev_attr->attr.mode |= 0444;
643 				dev_attr->show = counter_comp_array_u64_show;
644 			}
645 			if (comp->device_array_u64_write) {
646 				dev_attr->attr.mode |= 0200;
647 				dev_attr->store = counter_comp_array_u64_store;
648 			}
649 			break;
650 		default:
651 			return -EINVAL;
652 		}
653 		break;
654 	default:
655 		return -EINVAL;
656 	}
657 
658 	/* Store list node */
659 	list_add(&counter_attr->l, &group->attr_list);
660 	group->num_attr++;
661 
662 	/* Create "*_available" attribute if needed */
663 	switch (comp->type) {
664 	case COUNTER_COMP_FUNCTION:
665 	case COUNTER_COMP_SYNAPSE_ACTION:
666 	case COUNTER_COMP_ENUM:
667 	case COUNTER_COMP_COUNT_MODE:
668 		return counter_avail_attr_create(dev, group, comp, parent);
669 	default:
670 		return 0;
671 	}
672 }
673 
counter_comp_name_show(struct device * dev,struct device_attribute * attr,char * buf)674 static ssize_t counter_comp_name_show(struct device *dev,
675 				      struct device_attribute *attr, char *buf)
676 {
677 	return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name);
678 }
679 
counter_name_attr_create(struct device * const dev,struct counter_attribute_group * const group,const char * const name)680 static int counter_name_attr_create(struct device *const dev,
681 				    struct counter_attribute_group *const group,
682 				    const char *const name)
683 {
684 	struct counter_attribute *counter_attr;
685 
686 	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
687 	if (!counter_attr)
688 		return -ENOMEM;
689 
690 	/* Configure Counter attribute */
691 	counter_attr->comp.name = name;
692 
693 	/* Configure device attribute */
694 	sysfs_attr_init(&counter_attr->dev_attr.attr);
695 	counter_attr->dev_attr.attr.name = "name";
696 	counter_attr->dev_attr.attr.mode = 0444;
697 	counter_attr->dev_attr.show = counter_comp_name_show;
698 
699 	/* Store list node */
700 	list_add(&counter_attr->l, &group->attr_list);
701 	group->num_attr++;
702 
703 	return 0;
704 }
705 
counter_comp_id_show(struct device * dev,struct device_attribute * attr,char * buf)706 static ssize_t counter_comp_id_show(struct device *dev,
707 				    struct device_attribute *attr, char *buf)
708 {
709 	const size_t id = (size_t)to_counter_attribute(attr)->comp.priv;
710 
711 	return sysfs_emit(buf, "%zu\n", id);
712 }
713 
counter_comp_id_attr_create(struct device * const dev,struct counter_attribute_group * const group,const char * name,const size_t id)714 static int counter_comp_id_attr_create(struct device *const dev,
715 				       struct counter_attribute_group *const group,
716 				       const char *name, const size_t id)
717 {
718 	struct counter_attribute *counter_attr;
719 
720 	/* Allocate Counter attribute */
721 	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
722 	if (!counter_attr)
723 		return -ENOMEM;
724 
725 	/* Generate component ID name */
726 	name = devm_kasprintf(dev, GFP_KERNEL, "%s_component_id", name);
727 	if (!name)
728 		return -ENOMEM;
729 
730 	/* Configure Counter attribute */
731 	counter_attr->comp.priv = (void *)id;
732 
733 	/* Configure device attribute */
734 	sysfs_attr_init(&counter_attr->dev_attr.attr);
735 	counter_attr->dev_attr.attr.name = name;
736 	counter_attr->dev_attr.attr.mode = 0444;
737 	counter_attr->dev_attr.show = counter_comp_id_show;
738 
739 	/* Store list node */
740 	list_add(&counter_attr->l, &group->attr_list);
741 	group->num_attr++;
742 
743 	return 0;
744 }
745 
counter_ext_attrs_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const ext,const enum counter_scope scope,void * const parent,const size_t id)746 static int counter_ext_attrs_create(struct device *const dev,
747 				    struct counter_attribute_group *const group,
748 				    const struct counter_comp *const ext,
749 				    const enum counter_scope scope,
750 				    void *const parent, const size_t id)
751 {
752 	int err;
753 
754 	/* Create main extension attribute */
755 	err = counter_attr_create(dev, group, ext, scope, parent);
756 	if (err < 0)
757 		return err;
758 
759 	/* Create extension id attribute */
760 	return counter_comp_id_attr_create(dev, group, ext->name, id);
761 }
762 
counter_array_attrs_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const comp,const enum counter_scope scope,void * const parent,const size_t id)763 static int counter_array_attrs_create(struct device *const dev,
764 				      struct counter_attribute_group *const group,
765 				      const struct counter_comp *const comp,
766 				      const enum counter_scope scope,
767 				      void *const parent, const size_t id)
768 {
769 	const struct counter_array *const array = comp->priv;
770 	struct counter_comp ext = *comp;
771 	struct counter_array *element;
772 	size_t idx;
773 	int err;
774 
775 	/* Create an attribute for each array element */
776 	for (idx = 0; idx < array->length; idx++) {
777 		/* Generate array element attribute name */
778 		ext.name = devm_kasprintf(dev, GFP_KERNEL, "%s%zu", comp->name,
779 					  idx);
780 		if (!ext.name)
781 			return -ENOMEM;
782 
783 		/* Allocate and configure array element */
784 		element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL);
785 		if (!element)
786 			return -ENOMEM;
787 		element->type = array->type;
788 		element->avail = array->avail;
789 		element->idx = idx;
790 		ext.priv = element;
791 
792 		/* Create all attributes associated with the array element */
793 		err = counter_ext_attrs_create(dev, group, &ext, scope, parent,
794 					       id + idx);
795 		if (err < 0)
796 			return err;
797 	}
798 
799 	return 0;
800 }
801 
counter_sysfs_exts_add(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const exts,const size_t num_ext,const enum counter_scope scope,void * const parent)802 static int counter_sysfs_exts_add(struct device *const dev,
803 				  struct counter_attribute_group *const group,
804 				  const struct counter_comp *const exts,
805 				  const size_t num_ext,
806 				  const enum counter_scope scope,
807 				  void *const parent)
808 {
809 	size_t i;
810 	const struct counter_comp *ext;
811 	int err;
812 	size_t id = 0;
813 	const struct counter_array *array;
814 
815 	/* Create attributes for each extension */
816 	for (i = 0; i < num_ext; i++) {
817 		ext = &exts[i];
818 		if (ext->type == COUNTER_COMP_ARRAY) {
819 			err = counter_array_attrs_create(dev, group, ext, scope,
820 							 parent, id);
821 			array = ext->priv;
822 			id += array->length;
823 		} else {
824 			err = counter_ext_attrs_create(dev, group, ext, scope,
825 						       parent, id);
826 			id++;
827 		}
828 		if (err < 0)
829 			return err;
830 	}
831 
832 	return 0;
833 }
834 
835 static struct counter_comp counter_signal_comp = {
836 	.type = COUNTER_COMP_SIGNAL_LEVEL,
837 	.name = "signal",
838 };
839 
counter_signal_attrs_create(struct counter_device * const counter,struct counter_attribute_group * const cattr_group,struct counter_signal * const signal)840 static int counter_signal_attrs_create(struct counter_device *const counter,
841 	struct counter_attribute_group *const cattr_group,
842 	struct counter_signal *const signal)
843 {
844 	const enum counter_scope scope = COUNTER_SCOPE_SIGNAL;
845 	struct device *const dev = &counter->dev;
846 	int err;
847 	struct counter_comp comp;
848 
849 	/* Create main Signal attribute */
850 	comp = counter_signal_comp;
851 	comp.signal_u32_read = counter->ops->signal_read;
852 	err = counter_attr_create(dev, cattr_group, &comp, scope, signal);
853 	if (err < 0)
854 		return err;
855 
856 	/* Create Signal name attribute */
857 	err = counter_name_attr_create(dev, cattr_group, signal->name);
858 	if (err < 0)
859 		return err;
860 
861 	/* Add Signal extensions */
862 	return counter_sysfs_exts_add(dev, cattr_group, signal->ext,
863 				      signal->num_ext, scope, signal);
864 }
865 
counter_sysfs_signals_add(struct counter_device * const counter,struct counter_attribute_group * const groups)866 static int counter_sysfs_signals_add(struct counter_device *const counter,
867 	struct counter_attribute_group *const groups)
868 {
869 	size_t i;
870 	int err;
871 
872 	/* Add each Signal */
873 	for (i = 0; i < counter->num_signals; i++) {
874 		/* Generate Signal attribute directory name */
875 		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
876 						"signal%zu", i);
877 		if (!groups[i].name)
878 			return -ENOMEM;
879 
880 		/* Create all attributes associated with Signal */
881 		err = counter_signal_attrs_create(counter, groups + i,
882 						  counter->signals + i);
883 		if (err < 0)
884 			return err;
885 	}
886 
887 	return 0;
888 }
889 
counter_sysfs_synapses_add(struct counter_device * const counter,struct counter_attribute_group * const group,struct counter_count * const count)890 static int counter_sysfs_synapses_add(struct counter_device *const counter,
891 	struct counter_attribute_group *const group,
892 	struct counter_count *const count)
893 {
894 	size_t i;
895 
896 	/* Add each Synapse */
897 	for (i = 0; i < count->num_synapses; i++) {
898 		struct device *const dev = &counter->dev;
899 		struct counter_synapse *synapse;
900 		size_t id;
901 		struct counter_comp comp;
902 		int err;
903 
904 		synapse = count->synapses + i;
905 
906 		/* Generate Synapse action name */
907 		id = synapse->signal - counter->signals;
908 		comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action",
909 					   id);
910 		if (!comp.name)
911 			return -ENOMEM;
912 
913 		/* Create action attribute */
914 		comp.type = COUNTER_COMP_SYNAPSE_ACTION;
915 		comp.action_read = counter->ops->action_read;
916 		comp.action_write = counter->ops->action_write;
917 		comp.priv = synapse;
918 		err = counter_attr_create(dev, group, &comp,
919 					  COUNTER_SCOPE_COUNT, count);
920 		if (err < 0)
921 			return err;
922 
923 		/* Create Synapse component ID attribute */
924 		err = counter_comp_id_attr_create(dev, group, comp.name, i);
925 		if (err < 0)
926 			return err;
927 	}
928 
929 	return 0;
930 }
931 
932 static struct counter_comp counter_count_comp =
933 	COUNTER_COMP_COUNT_U64("count", NULL, NULL);
934 
935 static struct counter_comp counter_function_comp = {
936 	.type = COUNTER_COMP_FUNCTION,
937 	.name = "function",
938 };
939 
counter_count_attrs_create(struct counter_device * const counter,struct counter_attribute_group * const cattr_group,struct counter_count * const count)940 static int counter_count_attrs_create(struct counter_device *const counter,
941 	struct counter_attribute_group *const cattr_group,
942 	struct counter_count *const count)
943 {
944 	const enum counter_scope scope = COUNTER_SCOPE_COUNT;
945 	struct device *const dev = &counter->dev;
946 	int err;
947 	struct counter_comp comp;
948 
949 	/* Create main Count attribute */
950 	comp = counter_count_comp;
951 	comp.count_u64_read = counter->ops->count_read;
952 	comp.count_u64_write = counter->ops->count_write;
953 	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
954 	if (err < 0)
955 		return err;
956 
957 	/* Create Count name attribute */
958 	err = counter_name_attr_create(dev, cattr_group, count->name);
959 	if (err < 0)
960 		return err;
961 
962 	/* Create Count function attribute */
963 	comp = counter_function_comp;
964 	comp.count_u32_read = counter->ops->function_read;
965 	comp.count_u32_write = counter->ops->function_write;
966 	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
967 	if (err < 0)
968 		return err;
969 
970 	/* Add Count extensions */
971 	return counter_sysfs_exts_add(dev, cattr_group, count->ext,
972 				      count->num_ext, scope, count);
973 }
974 
counter_sysfs_counts_add(struct counter_device * const counter,struct counter_attribute_group * const groups)975 static int counter_sysfs_counts_add(struct counter_device *const counter,
976 	struct counter_attribute_group *const groups)
977 {
978 	size_t i;
979 	struct counter_count *count;
980 	int err;
981 
982 	/* Add each Count */
983 	for (i = 0; i < counter->num_counts; i++) {
984 		count = counter->counts + i;
985 
986 		/* Generate Count attribute directory name */
987 		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
988 						"count%zu", i);
989 		if (!groups[i].name)
990 			return -ENOMEM;
991 
992 		/* Add sysfs attributes of the Synapses */
993 		err = counter_sysfs_synapses_add(counter, groups + i, count);
994 		if (err < 0)
995 			return err;
996 
997 		/* Create all attributes associated with Count */
998 		err = counter_count_attrs_create(counter, groups + i, count);
999 		if (err < 0)
1000 			return err;
1001 	}
1002 
1003 	return 0;
1004 }
1005 
counter_num_signals_read(struct counter_device * counter,u8 * val)1006 static int counter_num_signals_read(struct counter_device *counter, u8 *val)
1007 {
1008 	*val = counter->num_signals;
1009 	return 0;
1010 }
1011 
counter_num_counts_read(struct counter_device * counter,u8 * val)1012 static int counter_num_counts_read(struct counter_device *counter, u8 *val)
1013 {
1014 	*val = counter->num_counts;
1015 	return 0;
1016 }
1017 
counter_events_queue_size_read(struct counter_device * counter,u64 * val)1018 static int counter_events_queue_size_read(struct counter_device *counter,
1019 					  u64 *val)
1020 {
1021 	*val = kfifo_size(&counter->events);
1022 	return 0;
1023 }
1024 
counter_events_queue_size_write(struct counter_device * counter,u64 val)1025 static int counter_events_queue_size_write(struct counter_device *counter,
1026 					   u64 val)
1027 {
1028 	DECLARE_KFIFO_PTR(events, struct counter_event);
1029 	int err;
1030 	unsigned long flags;
1031 
1032 	/* Allocate new events queue */
1033 	err = kfifo_alloc(&events, val, GFP_KERNEL);
1034 	if (err)
1035 		return err;
1036 
1037 	/* Swap in new events queue */
1038 	mutex_lock(&counter->events_out_lock);
1039 	spin_lock_irqsave(&counter->events_in_lock, flags);
1040 	kfifo_free(&counter->events);
1041 	counter->events.kfifo = events.kfifo;
1042 	spin_unlock_irqrestore(&counter->events_in_lock, flags);
1043 	mutex_unlock(&counter->events_out_lock);
1044 
1045 	return 0;
1046 }
1047 
1048 static struct counter_comp counter_num_signals_comp =
1049 	COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
1050 
1051 static struct counter_comp counter_num_counts_comp =
1052 	COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
1053 
1054 static struct counter_comp counter_events_queue_size_comp =
1055 	COUNTER_COMP_DEVICE_U64("events_queue_size",
1056 				counter_events_queue_size_read,
1057 				counter_events_queue_size_write);
1058 
counter_sysfs_attr_add(struct counter_device * const counter,struct counter_attribute_group * cattr_group)1059 static int counter_sysfs_attr_add(struct counter_device *const counter,
1060 				  struct counter_attribute_group *cattr_group)
1061 {
1062 	const enum counter_scope scope = COUNTER_SCOPE_DEVICE;
1063 	struct device *const dev = &counter->dev;
1064 	int err;
1065 
1066 	/* Add Signals sysfs attributes */
1067 	err = counter_sysfs_signals_add(counter, cattr_group);
1068 	if (err < 0)
1069 		return err;
1070 	cattr_group += counter->num_signals;
1071 
1072 	/* Add Counts sysfs attributes */
1073 	err = counter_sysfs_counts_add(counter, cattr_group);
1074 	if (err < 0)
1075 		return err;
1076 	cattr_group += counter->num_counts;
1077 
1078 	/* Create name attribute */
1079 	err = counter_name_attr_create(dev, cattr_group, counter->name);
1080 	if (err < 0)
1081 		return err;
1082 
1083 	/* Create num_signals attribute */
1084 	err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp,
1085 				  scope, NULL);
1086 	if (err < 0)
1087 		return err;
1088 
1089 	/* Create num_counts attribute */
1090 	err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp,
1091 				  scope, NULL);
1092 	if (err < 0)
1093 		return err;
1094 
1095 	/* Create events_queue_size attribute */
1096 	err = counter_attr_create(dev, cattr_group,
1097 				  &counter_events_queue_size_comp, scope, NULL);
1098 	if (err < 0)
1099 		return err;
1100 
1101 	/* Add device extensions */
1102 	return counter_sysfs_exts_add(dev, cattr_group, counter->ext,
1103 				      counter->num_ext, scope, NULL);
1104 
1105 	return 0;
1106 }
1107 
1108 /**
1109  * counter_sysfs_add - Adds Counter sysfs attributes to the device structure
1110  * @counter:	Pointer to the Counter device structure
1111  *
1112  * Counter sysfs attributes are created and added to the respective device
1113  * structure for later registration to the system. Resource-managed memory
1114  * allocation is performed by this function, and this memory should be freed
1115  * when no longer needed (automatically by a device_unregister call, or
1116  * manually by a devres_release_all call).
1117  */
counter_sysfs_add(struct counter_device * const counter)1118 int counter_sysfs_add(struct counter_device *const counter)
1119 {
1120 	struct device *const dev = &counter->dev;
1121 	const size_t num_groups = counter->num_signals + counter->num_counts + 1;
1122 	struct counter_attribute_group *cattr_groups;
1123 	size_t i, j;
1124 	int err;
1125 	struct attribute_group *groups;
1126 	struct counter_attribute *p;
1127 
1128 	/* Allocate space for attribute groups (signals, counts, and ext) */
1129 	cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups),
1130 				    GFP_KERNEL);
1131 	if (!cattr_groups)
1132 		return -ENOMEM;
1133 
1134 	/* Initialize attribute lists */
1135 	for (i = 0; i < num_groups; i++)
1136 		INIT_LIST_HEAD(&cattr_groups[i].attr_list);
1137 
1138 	/* Add Counter device sysfs attributes */
1139 	err = counter_sysfs_attr_add(counter, cattr_groups);
1140 	if (err < 0)
1141 		return err;
1142 
1143 	/* Allocate attribute group pointers for association with device */
1144 	dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups),
1145 				   GFP_KERNEL);
1146 	if (!dev->groups)
1147 		return -ENOMEM;
1148 
1149 	/* Allocate space for attribute groups */
1150 	groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL);
1151 	if (!groups)
1152 		return -ENOMEM;
1153 
1154 	/* Prepare each group of attributes for association */
1155 	for (i = 0; i < num_groups; i++) {
1156 		groups[i].name = cattr_groups[i].name;
1157 
1158 		/* Allocate space for attribute pointers */
1159 		groups[i].attrs = devm_kcalloc(dev,
1160 					       cattr_groups[i].num_attr + 1,
1161 					       sizeof(*groups[i].attrs),
1162 					       GFP_KERNEL);
1163 		if (!groups[i].attrs)
1164 			return -ENOMEM;
1165 
1166 		/* Add attribute pointers to attribute group */
1167 		j = 0;
1168 		list_for_each_entry(p, &cattr_groups[i].attr_list, l)
1169 			groups[i].attrs[j++] = &p->dev_attr.attr;
1170 
1171 		/* Associate attribute group */
1172 		dev->groups[i] = &groups[i];
1173 	}
1174 
1175 	return 0;
1176 }
1177