Thread (41 messages) flat view 41 messages, 7 authors, 2018-07-22

Re: [PATCH v7 01/10] counter: Introduce the Generic Counter interface

From: Greg KH <gregkh@linuxfoundation.org>
Date: 2018-07-07 15:17:28
Also in: linux-arm-kernel, linux-iio, lkml

On Thu, Jun 21, 2018 at 05:07:08PM -0400, William Breathitt Gray wrote:
This patch introduces the Generic Counter interface for supporting
counter devices.

In the context of the Generic Counter interface, a counter is defined as
a device that reports one or more "counts" based on the state changes of
one or more "signals" as evaluated by a defined "count function."

Driver callbacks should be provided to communicate with the device: to
read and write various Signals and Counts, and to set and get the
"action mode" and "count function" for various Synapses and Counts
respectively.

To support a counter device, a driver must first allocate the available
Counter Signals via counter_signal structures. These Signals should
be stored as an array and set to the signals array member of an
allocated counter_device structure before the Counter is registered to
the system.

Counter Counts may be allocated via counter_count structures, and
respective Counter Signal associations (Synapses) made via
counter_synapse structures. Associated counter_synapse structures are
stored as an array and set to the the synapses array member of the
respective counter_count structure. These counter_count structures are
set to the counts array member of an allocated counter_device structure
before the Counter is registered to the system.

A counter device is registered to the system by passing the respective
initialized counter_device structure to the counter_register function;
similarly, the counter_unregister function unregisters the respective
Counter. The devm_counter_register and devm_counter_unregister functions
serve as device memory-managed versions of the counter_register and
counter_unregister functions respectively.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: William Breathitt Gray <redacted>
---
 MAINTAINERS                       |    7 +
 drivers/Kconfig                   |    2 +
 drivers/Makefile                  |    1 +
 drivers/counter/Kconfig           |   18 +
 drivers/counter/Makefile          |    8 +
 drivers/counter/generic-counter.c | 1519 +++++++++++++++++++++++++++++
 include/linux/counter.h           |  534 ++++++++++
 7 files changed, 2089 insertions(+)
 create mode 100644 drivers/counter/Kconfig
 create mode 100644 drivers/counter/Makefile
 create mode 100644 drivers/counter/generic-counter.c
 create mode 100644 include/linux/counter.h
First cut of review, does counter.h really have to be that big?  It
feels like some of the "internal" functions and structures could be
local to drivers/counter/ right?

+menuconfig COUNTER
+	tristate "Counter support"
+	help
+	  Provides Generic Counter interface support for counter devices.
+
+	  Counter devices are prevalent within a diverse spectrum of industries.
+	  The ubiquitous presence of these devices necessitates a common
+	  interface and standard of interaction and exposure. This driver API
+	  attempts to resolve the issue of duplicate code found among existing
+	  counter device drivers by providing a generic counter interface for
+	  consumption. The Generic Counter interface enables drivers to support
+	  and expose a common set of components and functionality present in
+	  counter devices.
No need to explain an "API" in a Kconfig help text, which is for a user
of the kernel, not for someone writing kernel code.  Odds are individual
drivers will need to select this, or are you going to depend on this
option?

quoted hunk ↗ jump to hunk
diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
new file mode 100644
index 000000000000..ad1ba7109cdc
--- /dev/null
+++ b/drivers/counter/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for Counter devices
+#
+
+# When adding new entries keep the list in alphabetical order
Why does it matter?  :)
+
+obj-$(CONFIG_COUNTER) += counter.o
+counter-y := generic-counter.o
Why not just call your .c file, "counter.c" to keep this simple?
quoted hunk ↗ jump to hunk
diff --git a/drivers/counter/generic-counter.c b/drivers/counter/generic-counter.c
new file mode 100644
index 000000000000..483826c8ce01
--- /dev/null
+++ b/drivers/counter/generic-counter.c
@@ -0,0 +1,1519 @@
+// SPDX-License-Identifier: GPL-2.0-only
Please use the normal SPDX identifiers we are using, as described in the
kernel documentation.  We aren't ready to use the "new" ones just yet.
+/*
+ * Generic Counter interface
+ * Copyright (C) 2017 William Breathitt Gray
It's 2018 now :)
+ */
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/gfp.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#include <linux/counter.h>
Why a blank line?
+
+const char *const count_direction_str[2] = {
+	[COUNT_DIRECTION_FORWARD] = "forward",
+	[COUNT_DIRECTION_BACKWARD] = "backward"
+};
+EXPORT_SYMBOL(count_direction_str);
I have to ask, for all of these, why not EXPORT_SYMBOL_GPL()?

+
+const char *const count_mode_str[4] = {
+	[COUNT_MODE_NORMAL] = "normal",
+	[COUNT_MODE_RANGE_LIMIT] = "range limit",
+	[COUNT_MODE_NON_RECYCLE] = "non-recycle",
+	[COUNT_MODE_MODULO_N] = "modulo-n"
+};
+EXPORT_SYMBOL(count_mode_str);
And why do you need to export strings?


+
+ssize_t counter_signal_enum_read(struct counter_device *counter,
+				 struct counter_signal *signal, void *priv,
+				 char *buf)
+{
+	const struct counter_signal_enum_ext *const e = priv;
+	int err;
+	size_t index;
+
+	if (!e->get)
+		return -EINVAL;
How can e->get not be set?  Shouldn't you just not have called into this
if so?
+
+	err = e->get(counter, signal, &index);
+	if (err)
+		return err;
+
+	if (index >= e->num_items)
+		return -EINVAL;
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n", e->items[index]);
No need to do the scnprintf() crud, it's a sysfs file, a simple
sprintf() works just fine.  Yeah, it makes people nervous, and it should :)

+}
+EXPORT_SYMBOL(counter_signal_enum_read);
sysfs attribute files really should be EXPORT_SYMBOL_GPL() please.
+
+ssize_t counter_signal_enum_write(struct counter_device *counter,
+				  struct counter_signal *signal, void *priv,
+				  const char *buf, size_t len)
+{
+	const struct counter_signal_enum_ext *const e = priv;
+	ssize_t index;
+	int err;
+
+	if (!e->set)
+		return -EINVAL;
Again, how can this be true?

+
+	index = __sysfs_match_string(e->items, e->num_items, buf);
+	if (index < 0)
+		return index;
+
+	err = e->set(counter, signal, index);
+	if (err)
+		return err;
+
+	return len;
+}
+EXPORT_SYMBOL(counter_signal_enum_write);
+
+ssize_t counter_signal_enum_available_read(struct counter_device *counter,
+					   struct counter_signal *signal,
+					   void *priv, char *buf)
+{
+	const struct counter_signal_enum_ext *const e = priv;
+	size_t i;
+	size_t len = 0;
+
+	if (!e->num_items)
+		return 0;
+
+	for (i = 0; i < e->num_items; i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n",
+			e->items[i]);
a list of items?  In sysfs?  Are you _SURE_ you want to do that?
+
+	return len;
+}
+EXPORT_SYMBOL(counter_signal_enum_available_read);
+
+ssize_t counter_count_enum_read(struct counter_device *counter,
+				struct counter_count *count, void *priv,
+				char *buf)
+{
+	const struct counter_count_enum_ext *const e = priv;
+	int err;
+	size_t index;
+
+	if (!e->get)
+		return -EINVAL;

Same comment everywhere for this...

let's skip lower in the files...
+static int counter_attribute_create(
+	struct counter_device_attr_group *const group,
+	const char *const prefix,
+	const char *const name,
+	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+			char *buf),
+	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t len),
Typedefs for these function pointers are good to have.
+	void *const component)
That's a crazy list of parameters...

+{
+	struct counter_device_attr *counter_attr;
+	struct device_attribute *dev_attr;
+	int err;
+	struct list_head *const attr_list = &group->attr_list;
+
+	/* Allocate a Counter device attribute */
+	counter_attr = kzalloc(sizeof(*counter_attr), GFP_KERNEL);
+	if (!counter_attr)
+		return -ENOMEM;
+	dev_attr = &counter_attr->dev_attr;
+
+	sysfs_attr_init(&dev_attr->attr);
+
+	/* Configure device attribute */
+	dev_attr->attr.name = kasprintf(GFP_KERNEL, "%s%s", prefix, name);
+	if (!dev_attr->attr.name) {
+		err = -ENOMEM;
+		goto err_free_counter_attr;
+	}
+	if (show) {
+		dev_attr->attr.mode |= 0444;
+		dev_attr->show = show;
+	}
+	if (store) {
+		dev_attr->attr.mode |= 0200;
+		dev_attr->store = store;
+	}
+
+	/* Store associated Counter component with attribute */
+	counter_attr->component = component;
+
+	/* Keep track of the attribute for later cleanup */
+	list_add(&counter_attr->l, attr_list);
+	group->num_attr++;
So you are dynamically creating sysfs attributes?  Why not just have one
big group and only enable them if needed?  That would make things a lot
simpler, right?
+struct signal_comp_t {
"_t"???
+	struct counter_signal	*signal;
+};
+
+static ssize_t counter_signal_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	const struct counter_device_attr *const devattr = to_counter_attr(attr);
+	const struct signal_comp_t *const component = devattr->component;
+	struct counter_signal *const signal = component->signal;
+	int err;
+	struct signal_read_value val = { .buf = buf };
+
+	err = counter->ops->signal_read(counter, signal, &val);
+	if (err)
+		return err;
+
+	return val.len;
+}
+
+struct name_comp_t {
"_t"???

Same for the rest of this file...
quoted hunk ↗ jump to hunk
diff --git a/include/linux/counter.h b/include/linux/counter.h
new file mode 100644
index 000000000000..88fc82ee30a7
--- /dev/null
+++ b/include/linux/counter.h
@@ -0,0 +1,534 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
Same identifier issue.
+/*
+ * Counter interface
+ * Copyright (C) 2017 William Breathitt Gray
2018!

And again, it looks like this file can be a lot smaller, but I don't see
a user of it just yet, so I don't really know...

thanks,

greg k-h
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help