lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220227205608.30812-11-cristian.marussi@arm.com>
Date:   Sun, 27 Feb 2022 20:56:02 +0000
From:   Cristian Marussi <cristian.marussi@....com>
To:     linux-kernel@...r.kernel.org, linux-arm-kernel@...ts.infradead.org
Cc:     sudeep.holla@....com, james.quinlan@...adcom.com,
        Jonathan.Cameron@...wei.com, f.fainelli@...il.com,
        vincent.guittot@...aro.org, souvik.chakravarty@....com,
        peter.hilber@...nsynergy.com, cristian.marussi@....com
Subject: [RFC PATCH 10/16] firmware: arm_scmi: testing: Add Sensor protocol basic support

Add SCMI Sensor protocol testing support exposing SCMI Sensor protocol
operations under debugfs /sys/kernel/debug/scmi/protocol_0x15/<XXX>/,
where the subdirectories <XXX> represents each a distinct sensor resource
with ID equal <XXX>.

Still without any support for testing SCMI Sensor notifications.

Signed-off-by: Cristian Marussi <cristian.marussi@....com>
---
 Documentation/ABI/testing/debugfs-scmi        |  62 +++
 .../arm_scmi/scmi_test_driver/Makefile        |   2 +-
 .../arm_scmi/scmi_test_driver/scmi_test.c     |   2 +
 .../arm_scmi/scmi_test_driver/test_common.h   |   1 +
 .../arm_scmi/scmi_test_driver/test_sensors.c  | 525 ++++++++++++++++++
 5 files changed, 591 insertions(+), 1 deletion(-)
 create mode 100644 drivers/firmware/arm_scmi/scmi_test_driver/test_sensors.c

diff --git a/Documentation/ABI/testing/debugfs-scmi b/Documentation/ABI/testing/debugfs-scmi
index e91c19e7a323..72835516dee8 100644
--- a/Documentation/ABI/testing/debugfs-scmi
+++ b/Documentation/ABI/testing/debugfs-scmi
@@ -155,3 +155,65 @@ Description:	SCMI Clock Protocol enable atomic operation for clock resource
 		Available only if the underlying SCMI transport is atomic
 		capable (/sys/kernel/debug/scmi/transport/is_atomic is True).
 Users:		KSelftest, Debugging
+
+What:		/sys/kernel/debug/scmi/protocol_0x15/<XXX>/info/*
+Date:		Feb 2022
+KernelVersion:	5.19
+Contact:	cristian.marussi@....com
+Description:	SCMI Sensor Protocol informational RO data for sensor resource
+		with id <XXX>: each entry under info/ subdir maps to an equally
+		named field of struct scmi_sensor_info as documented in
+		include/scmi/protocol.h
+Users:		KSelftest, Debugging
+
+What:		/sys/kernel/debug/scmi/protocol_0x15/<XXX>/reading_get
+Date:		Feb 2022
+KernelVersion:	5.19
+Contact:	cristian.marussi@....com
+Description:	SCMI Sensor Protocol reading_get operation for sensor resource
+		with id <XXX>; a read returns an u64 integer value representing
+		the current sensor reading.
+Users:		KSelftest, Debugging
+
+What:		/sys/kernel/debug/scmi/protocol_0x15/<XXX>/reading_get_timestamped
+Date:		Feb 2022
+KernelVersion:	5.19
+Contact:	cristian.marussi@....com
+Description:	SCMI Sensor Protocol reading_get_timestamped operation for sensor
+		resource with id <XXX>; a read returns a list of pair of values
+		in the form <TSTAMP_u64>:<READING_S64>, where the TSTAMP_u64
+		represents a timestamp taken by the platform when the sensor
+		reading <READING_s64> was sampled.
+Users:		KSelftest, Debugging
+
+What:		/sys/kernel/debug/scmi/protocol_0x15/<XXX>/enable
+Date:		Feb 2022
+KernelVersion:	5.19
+Contact:	cristian.marussi@....com
+Description:	SCMI Sensor Protocol enable operation for sensor resource with
+		id <XXX>; a read returns a boolen value representing the current
+		enable state of the sensor, while writing a boolean value causes
+		that specific sensor to be enabled or disabled.
+Users:		KSelftest, Debugging
+
+What:		/sys/kernel/debug/scmi/protocol_0x15/<XXX>/sensor_config
+Date:		Feb 2022
+KernelVersion:	5.19
+Contact:	cristian.marussi@....com
+Description:	SCMI Sensor Protocol config operation for sensor resource with
+		id <XXX>; a read returns a base-16 integer representing the
+		current sensor configuration as described in the relevant SCMI
+	        specification (SENSOR_CONFIG_GET), while writing a base-16
+		integer value sets the sensor configuration as per the relevant
+		SCMI specification (SENSOR_CONFIG_SET).
+Users:		KSelftest, Debugging
+
+What:		/sys/kernel/debug/scmi/protocol_0x15/<XXX>/trips/<YYY>/set
+Date:		Feb 2022
+KernelVersion:	5.19
+Contact:	cristian.marussi@....com
+Description:	SCMI Sensor Protocol trip points configuration operation for
+		sensor resource with id <XXX> and trip point number <YYY>;
+		writing a base-10 integer value configure and enable trip point
+		<YYY> for sensor <XXX>.
+Users:		KSelftest, Debugging
diff --git a/drivers/firmware/arm_scmi/scmi_test_driver/Makefile b/drivers/firmware/arm_scmi/scmi_test_driver/Makefile
index 6e3ddd177827..458883193f31 100644
--- a/drivers/firmware/arm_scmi/scmi_test_driver/Makefile
+++ b/drivers/firmware/arm_scmi/scmi_test_driver/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-scmi_test_driver-objs := scmi_test.o test_common.o test_clocks.o
+scmi_test_driver-objs := scmi_test.o test_common.o test_clocks.o test_sensors.o
 obj-$(CONFIG_ARM_SCMI_TEST_DRIVER) += scmi_test_driver.o
 
diff --git a/drivers/firmware/arm_scmi/scmi_test_driver/scmi_test.c b/drivers/firmware/arm_scmi/scmi_test_driver/scmi_test.c
index f99aa621684c..04e01dd114c9 100644
--- a/drivers/firmware/arm_scmi/scmi_test_driver/scmi_test.c
+++ b/drivers/firmware/arm_scmi/scmi_test_driver/scmi_test.c
@@ -24,6 +24,7 @@ DEFINE_MUTEX(scmi_test_mtx);
 static
 int (*scmi_test_init[SCMI_MAX_PROTOCOLS])(struct scmi_test_setup *) = {
 	[SCMI_PROTOCOL_CLOCK] = scmi_test_clock_init,
+	[SCMI_PROTOCOL_SENSOR] = scmi_test_sensor_init,
 };
 
 static void
@@ -124,6 +125,7 @@ static int scmi_testing_probe(struct scmi_device *sdev)
 
 static const struct scmi_device_id scmi_id_table[] = {
 	{ SCMI_PROTOCOL_CLOCK, "__scmi_test-clock" },
+	{ SCMI_PROTOCOL_SENSOR, "__scmi_test-sensor" },
 	{ },
 };
 MODULE_DEVICE_TABLE(scmi, scmi_id_table);
diff --git a/drivers/firmware/arm_scmi/scmi_test_driver/test_common.h b/drivers/firmware/arm_scmi/scmi_test_driver/test_common.h
index 3c64cae9fae9..e02c2521f090 100644
--- a/drivers/firmware/arm_scmi/scmi_test_driver/test_common.h
+++ b/drivers/firmware/arm_scmi/scmi_test_driver/test_common.h
@@ -73,5 +73,6 @@ int scmi_test_fixed_buffer_open(struct inode *ino, struct file *filp);
 int scmi_test_release(struct inode *ino, struct file *filp);
 
 int scmi_test_clock_init(struct scmi_test_setup *tsp);
+int scmi_test_sensor_init(struct scmi_test_setup *tsp);
 
 #endif /* __SCMI_TEST_COMMON_H */
diff --git a/drivers/firmware/arm_scmi/scmi_test_driver/test_sensors.c b/drivers/firmware/arm_scmi/scmi_test_driver/test_sensors.c
new file mode 100644
index 000000000000..23206c2bac98
--- /dev/null
+++ b/drivers/firmware/arm_scmi/scmi_test_driver/test_sensors.c
@@ -0,0 +1,525 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SCMI Testing Driver - Clock Protocol
+ *
+ * Copyright (C) 2022 ARM Ltd.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/dcache.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/kstrtox.h>
+#include <linux/scmi_protocol.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+
+#include "test_common.h"
+
+struct scmi_sensor_data {
+	unsigned int version;
+	int count;
+	const struct scmi_sensor_info **sinfo;
+};
+
+static int scmi_test_sensor_reading_open(struct inode *ino, struct file *filp)
+{
+	unsigned int id;
+	size_t blen;
+	struct scmi_test_buffer *data;
+	struct scmi_test_setup *tsp = filp->f_inode->i_private;
+	struct scmi_sensor_data *sdata = tsp->priv;
+	const char *id_str = filp->f_path.dentry->d_parent->d_name.name;
+
+	/* Grab clk ID from debugfs entry naming if any */
+	if (kstrtouint(id_str, 10, &id))
+		return -EINVAL;
+
+	if (!sdata->sinfo[id]->num_axis)
+		blen = SCMI_TEST_DEFAULT_BUF_SZ;
+	else
+		blen = 48 * sdata->sinfo[id]->num_axis;
+
+	data = kzalloc(sizeof(*data) + blen, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->id = id;
+	data->len = blen;
+	filp->private_data = data;
+
+	return 0;
+}
+
+static ssize_t scmi_test_sensor_reading_get(struct file *filp, char __user *buf,
+					    size_t count, loff_t *ppos)
+{
+	struct scmi_test_buffer *data = filp->private_data;
+
+	if (!data)
+		return 0;
+
+	if (!data->used) {
+		int ret;
+		bool tstamp_req;
+		u64 value;
+		struct scmi_test_setup *tsp = filp->f_inode->i_private;
+		const struct scmi_sensor_proto_ops *sensor_ops = tsp->ops;
+
+		tstamp_req = !strncmp(filp->f_path.dentry->d_name.name,
+				      "reading_get_timestamped",
+				      strlen("reading_get_timestamped"));
+
+		if (!tstamp_req) {
+			ret = sensor_ops->reading_get(tsp->ph, data->id,
+						      &value);
+			if (ret)
+				return ret;
+
+			data->used = scnprintf(data->buf, data->len, "%llu\n",
+					       value);
+		} else {
+			u8 count;
+			int i;
+			struct scmi_sensor_reading *readings;
+			const struct scmi_sensor_info *sinfo;
+			struct scmi_sensor_data *sdata = tsp->priv;
+
+			sinfo = sdata->sinfo[data->id];
+			if (!sinfo)
+				return -EINVAL;
+
+			count = sinfo->num_axis ?: 1;
+			readings = kcalloc(count, sizeof(*readings),
+					   GFP_KERNEL);
+			if (!readings)
+				return -ENOMEM;
+
+			ret = sensor_ops->reading_get_timestamped(tsp->ph,
+								  data->id,
+								  count,
+								  readings);
+			if (ret) {
+				kfree(readings);
+				return ret;
+			}
+
+			for (i = 0; i < count; i++)
+				data->used += scnprintf(data->buf + data->used,
+							data->len - data->used,
+							"%llu:%lld ",
+							readings[i].timestamp,
+							readings[i].value);
+
+			data->used += scnprintf(data->buf + data->used,
+						data->len - data->used, "\n");
+
+			kfree(readings);
+		}
+	}
+
+	return simple_read_from_buffer(buf, count, ppos, data->buf, data->used);
+}
+
+static const struct file_operations test_sensor_reading_get_fops_ro = {
+	.open = scmi_test_sensor_reading_open,
+	.release = scmi_test_release,
+	.read = scmi_test_sensor_reading_get,
+};
+
+static ssize_t scmi_test_sensor_enable_read(struct file *filp, char __user *buf,
+					    size_t count, loff_t *ppos)
+{
+	int ret;
+	struct scmi_test_buffer *data = filp->private_data;
+
+	if (!data)
+		return 0;
+
+	if (!data->used) {
+		u32 sensor_config;
+		struct scmi_test_setup *tsp = filp->f_inode->i_private;
+		const struct scmi_sensor_proto_ops *sensor_ops = tsp->ops;
+
+		ret = sensor_ops->config_get(tsp->ph, data->id, &sensor_config);
+		if (ret)
+			return ret;
+
+		data->used = scnprintf(data->buf, data->len, "%lu\n",
+				       SCMI_SENS_CFG_IS_ENABLED(sensor_config));
+	}
+
+	return simple_read_from_buffer(buf, count, ppos, data->buf, data->used);
+}
+
+static ssize_t scmi_test_sensor_enable_write(struct file *filp,
+					     const char __user *buf,
+					     size_t count, loff_t *ppos)
+{
+	bool enabled;
+	int ret;
+	u32 sensor_config;
+	struct scmi_test_setup *tsp = filp->f_inode->i_private;
+	const struct scmi_sensor_proto_ops *sensor_ops = tsp->ops;
+	struct scmi_test_buffer *data = filp->private_data;
+
+	if (!data)
+		return 0;
+
+	ret = kstrtobool_from_user(buf, count, &enabled);
+	if (ret)
+		return ret;
+
+	ret = sensor_ops->config_get(tsp->ph, data->id, &sensor_config);
+	if (ret)
+		return ret;
+
+	sensor_config &= ~SCMI_SENS_CFG_SENSOR_ENABLED_MASK;
+	sensor_config |= FIELD_PREP(SCMI_SENS_CFG_SENSOR_ENABLED_MASK, enabled);
+
+	ret = sensor_ops->config_set(tsp->ph, data->id, sensor_config);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static const struct file_operations test_sensor_enable_fops_rw = {
+	.open = scmi_test_setup_open,
+	.release = scmi_test_release,
+	.read = scmi_test_sensor_enable_read,
+	.write = scmi_test_sensor_enable_write,
+};
+
+static ssize_t scmi_test_sensor_config_read(struct file *filp, char __user *buf,
+					    size_t count, loff_t *ppos)
+{
+	int ret;
+	struct scmi_test_buffer *data = filp->private_data;
+
+	if (!data)
+		return 0;
+
+	if (!data->used) {
+		u32 sensor_config;
+		struct scmi_test_setup *tsp = filp->f_inode->i_private;
+		const struct scmi_sensor_proto_ops *sensor_ops = tsp->ops;
+
+		ret = sensor_ops->config_get(tsp->ph, data->id, &sensor_config);
+		if (ret)
+			return ret;
+
+		data->used = scnprintf(data->buf, data->len, "0x%X\n",
+				       sensor_config);
+	}
+
+	return simple_read_from_buffer(buf, count, ppos, data->buf, data->used);
+}
+
+static ssize_t scmi_test_sensor_config_write(struct file *filp,
+					     const char __user *buf,
+					     size_t count, loff_t *ppos)
+{
+	int ret;
+	u32 sensor_config;
+	struct scmi_test_setup *tsp = filp->f_inode->i_private;
+	const struct scmi_sensor_proto_ops *sensor_ops = tsp->ops;
+	struct scmi_test_buffer *data = filp->private_data;
+
+	if (!data)
+		return 0;
+
+	ret = kstrtou32_from_user(buf, count, 16, &sensor_config);
+	if (ret)
+		return ret;
+
+	ret = sensor_ops->config_set(tsp->ph, data->id, sensor_config);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static const struct file_operations test_sensor_config_fops_rw = {
+	.open = scmi_test_setup_open,
+	.release = scmi_test_release,
+	.read = scmi_test_sensor_config_read,
+	.write = scmi_test_sensor_config_write,
+};
+
+static ssize_t scmi_test_sensor_trip_config_write(struct file *filp,
+						  const char __user *buf,
+						  size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned int sid;
+	u64 trip_config;
+	struct scmi_test_setup *tsp = filp->f_inode->i_private;
+	const struct scmi_sensor_proto_ops *sensor_ops = tsp->ops;
+	struct scmi_test_buffer *data = filp->private_data;
+	/* protocol_0x15/008/trips/001/set */
+	const char *sid_str =
+		filp->f_path.dentry->d_parent->d_parent->d_parent->d_name.name;
+
+	if (!data || kstrtouint(sid_str, 10, &sid))
+		return 0;
+
+	/* Cannot clear !!! Not supported by .trip_point_config */
+	ret = kstrtou64_from_user(buf, count, 10, &trip_config);
+	if (ret)
+		return ret;
+
+	ret = sensor_ops->trip_point_config(tsp->ph, sid,
+					    data->id, trip_config);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static const struct file_operations test_sensor_trip_config_fops = {
+	.open = scmi_test_setup_open,
+	.release = scmi_test_release,
+	.write = scmi_test_sensor_trip_config_write,
+};
+
+static void scmi_test_sensor_trips_debugfs(struct dentry *pdentry,
+					   struct scmi_test_setup *tsp,
+					   unsigned int num_points)
+{
+	struct dentry *trips_dentry;
+
+	trips_dentry = debugfs_create_dir("trips", pdentry);
+
+	if (!IS_ERR(trips_dentry)) {
+		int i;
+
+		for (i = 0; i < num_points; i++) {
+			char point_dir[16];
+			struct dentry *point_dentry;
+
+			snprintf(point_dir, 16, "%03d", i);
+			point_dentry =
+				debugfs_create_dir(point_dir, trips_dentry);
+			if (!IS_ERR(point_dentry))
+				debugfs_create_file("set", 0200,
+						    point_dentry, tsp,
+						&test_sensor_trip_config_fops);
+		}
+	}
+}
+
+static int scmi_test_sensor_intervals_open(struct inode *ino, struct file *filp)
+{
+	size_t ilen;
+	struct scmi_test_buffer *data;
+	struct scmi_sensor_intervals_info *i = filp->f_inode->i_private;
+
+	/* 65536^-16\n */
+	ilen = i->count * 16;
+	data = kzalloc(sizeof(*data) + ilen, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->len = ilen;
+	filp->private_data = data;
+
+	return 0;
+}
+
+static ssize_t scmi_test_sensor_intervals_read(struct file *filp,
+					       char __user *buf,
+					       size_t count, loff_t *ppos)
+{
+	struct scmi_test_buffer *data = filp->private_data;
+
+	if (!data)
+		return 0;
+
+	if (!data->used) {
+		int c;
+		struct scmi_sensor_intervals_info *i = filp->f_inode->i_private;
+
+		for (c = 0; c < i->count; c++)
+			data->used += scnprintf(data->buf + data->used,
+						data->len - data->used,
+						"%lu^%d ",
+					SCMI_SENS_INTVL_GET_SECS(i->desc[c]),
+					SCMI_SENS_INTVL_GET_EXP(i->desc[c]));
+
+		data->used += scnprintf(data->buf + data->used,
+					data->len - data->used, "\n");
+	}
+
+	return simple_read_from_buffer(buf, count, ppos, data->buf, data->used);
+}
+
+static const struct file_operations test_sensor_intervals_fops = {
+	.open = scmi_test_sensor_intervals_open,
+	.release = scmi_test_release,
+	.read = scmi_test_sensor_intervals_read,
+};
+
+static void
+scmi_test_debugfs_sensor_info_create(const struct scmi_sensor_info *si,
+				     struct dentry *top_dentry)
+{
+	struct dentry *parent;
+	struct scmi_sensor_info *sinfo = (struct scmi_sensor_info *)si;
+
+	parent = debugfs_create_dir("info", top_dentry);
+	if (IS_ERR(parent))
+		return;
+
+	debugfs_create_u32("type", 0400, parent, &sinfo->type);
+	debugfs_create_s32("scale", 0400, parent, &sinfo->scale);
+	debugfs_create_u32("num_trip_points", 0400, parent,
+			   &sinfo->num_trip_points);
+	debugfs_create_bool("async", 0400, parent, &sinfo->async);
+	debugfs_create_bool("continuos_updates", 0400, parent,
+			    &sinfo->update);
+	debugfs_create_bool("timestamped", 0400, parent,
+			    &sinfo->timestamped);
+	debugfs_create_s32("tstamp_scale", 0400, parent,
+			   &sinfo->tstamp_scale);
+
+	debugfs_create_u32("num_axis", 0400, parent, &sinfo->num_axis);
+	if (sinfo->num_axis) {
+		int i;
+		struct dentry *axes;
+
+		axes = debugfs_create_dir("axes", parent);
+		if (IS_ERR(axes))
+			return;
+
+		for (i = 0; i < sinfo->num_axis; i++) {
+			char axis_dir[16];
+			struct dentry *axis;
+
+			snprintf(axis_dir, 16, "%03d", i);
+			axis = debugfs_create_dir(axis_dir, axes);
+			if (IS_ERR(axis))
+				return;
+
+			debugfs_create_u32("type", 0400, axis,
+					   &sinfo->axis[i].type);
+			debugfs_create_s32("scale", 0400, axis,
+					   &sinfo->axis[i].scale);
+			debugfs_create_file("name", 0400, axis,
+					    sinfo->axis[i].name,
+					    &scmi_test_string_file_fops);
+			if (sinfo->axis[i].extended_attrs) {
+				debugfs_create_u32("resolution", 0400, axis,
+						   &sinfo->axis[i].resolution);
+				debugfs_create_s32("exponent", 0400, axis,
+						   &sinfo->axis[i].exponent);
+				debugfs_create_s64("min_range", 0400, axis,
+						   &sinfo->axis[i].attrs.min_range);
+				debugfs_create_s64("max_range", 0400, axis,
+						   &sinfo->axis[i].attrs.max_range);
+			}
+		}
+	}
+
+	if (sinfo->intervals.segmented && sinfo->intervals.count == 3) {
+		debugfs_create_u32("interval_low", 0400, parent,
+				   &sinfo->intervals.desc[SCMI_SENS_INTVL_SEGMENT_LOW]);
+		debugfs_create_u32("interval_high", 0400, parent,
+				   &sinfo->intervals.desc[SCMI_SENS_INTVL_SEGMENT_HIGH]);
+		debugfs_create_u32("interval_step", 0400, parent,
+				   &sinfo->intervals.desc[SCMI_SENS_INTVL_SEGMENT_STEP]);
+	} else {
+		debugfs_create_file("intervals", 0400, parent,
+				    &sinfo->intervals,
+				    &test_sensor_intervals_fops);
+	}
+
+	debugfs_create_u32("sensor_config", 0400, parent,
+			   &sinfo->sensor_config);
+
+	debugfs_create_file("name", 0400, parent, sinfo->name,
+			    &scmi_test_string_file_fops);
+
+	if (sinfo->extended_scalar_attrs) {
+		debugfs_create_u32("sensor_power", 0400, parent,
+				   &sinfo->sensor_power);
+		debugfs_create_u32("resolution", 0400, parent,
+				   &sinfo->resolution);
+		debugfs_create_s32("exponent", 0400, parent,
+				   &sinfo->exponent);
+		debugfs_create_s64("min_range", 0400, parent,
+				   &sinfo->scalar_attrs.min_range);
+		debugfs_create_s64("max_range", 0400, parent,
+				   &sinfo->scalar_attrs.max_range);
+	}
+}
+
+int scmi_test_sensor_init(struct scmi_test_setup *tsp)
+{
+	int i;
+	struct scmi_sensor_data *sdata;
+	const struct scmi_sensor_proto_ops *sensor_ops;
+	struct device *dev = &tsp->sdev->dev;
+
+	sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL);
+	if (!sdata)
+		return -ENOMEM;
+
+	sensor_ops = tsp->ops;
+	sdata->version = sensor_ops->version_get(tsp->ph);
+	sdata->count = sensor_ops->count_get(tsp->ph);
+
+	if (sdata->count <= 0) {
+		dev_err(dev, "number of domains invalid: %d\n",
+			sdata->count);
+		return sdata->count ?: -EINVAL;
+	}
+
+	sdata->sinfo = devm_kcalloc(dev, sdata->count,
+				    sizeof(sdata->sinfo), GFP_KERNEL);
+	if (!sdata->sinfo)
+		return -ENOMEM;
+
+	for (i = 0; i < sdata->count; i++)
+		sdata->sinfo[i] = sensor_ops->info_get(tsp->ph, i);
+
+	tsp->priv = sdata;
+	debugfs_create_x32("version", 0400, tsp->parent, &sdata->version);
+
+	dev_info(dev, "Found %d sensor resources.\n", sdata->count);
+
+	for (i = 0; i < sdata->count; i++) {
+		char sensor_dir[16];
+		struct dentry *sensor_dentry;
+
+		if (!sdata->sinfo[i])
+			continue;
+
+		snprintf(sensor_dir, 16, "%03d", i);
+		sensor_dentry = debugfs_create_dir(sensor_dir, tsp->parent);
+		if (!IS_ERR(sensor_dentry)) {
+			scmi_test_debugfs_sensor_info_create(sdata->sinfo[i],
+							     sensor_dentry);
+			debugfs_create_file("reading_get", 0400,
+					    sensor_dentry, tsp,
+					    &test_sensor_reading_get_fops_ro);
+			debugfs_create_file("reading_get_timestamped", 0400,
+					    sensor_dentry, tsp,
+					    &test_sensor_reading_get_fops_ro);
+			debugfs_create_file("enable", 0600,
+					    sensor_dentry, tsp,
+					    &test_sensor_enable_fops_rw);
+			debugfs_create_file("sensor_config", 0600,
+					    sensor_dentry, tsp,
+					    &test_sensor_config_fops_rw);
+
+			if (sdata->sinfo[i]->num_trip_points)
+				scmi_test_sensor_trips_debugfs(sensor_dentry,
+							       tsp,
+					      sdata->sinfo[i]->num_trip_points);
+		}
+	}
+
+	return 0;
+}
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ