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: <20250713164033.3488db3c@jic23-huawei>
Date: Sun, 13 Jul 2025 16:40:33 +0100
From: Jonathan Cameron <jic23@...nel.org>
To: Yassine Oudjana via B4 Relay
 <devnull+y.oudjana.protonmail.com@...nel.org>
Cc: y.oudjana@...tonmail.com, Manivannan Sadhasivam <mani@...nel.org>,
 "David S. Miller" <davem@...emloft.net>, Eric Dumazet
 <edumazet@...gle.com>, Jakub Kicinski <kuba@...nel.org>, Paolo Abeni
 <pabeni@...hat.com>, Simon Horman <horms@...nel.org>, Bjorn Andersson
 <andersson@...nel.org>, Konrad Dybcio <konradybcio@...nel.org>, Masahiro
 Yamada <masahiroy@...nel.org>, Nathan Chancellor <nathan@...nel.org>,
 Nicolas Schier <nicolas.schier@...ux.dev>, David Lechner
 <dlechner@...libre.com>, Nuno Sá <nuno.sa@...log.com>, Andy
 Shevchenko <andy@...nel.org>, Luca Weiss <luca@...aweiss.eu>,
 linux-arm-msm@...r.kernel.org, netdev@...r.kernel.org,
 linux-kernel@...r.kernel.org, linux-kbuild@...r.kernel.org,
 linux-iio@...r.kernel.org
Subject: Re: [PATCH v2 4/4] iio: Add Qualcomm Sensor Manager driver

On Thu, 10 Jul 2025 09:06:30 +0100
Yassine Oudjana via B4 Relay <devnull+y.oudjana.protonmail.com@...nel.org> wrote:

> From: Yassine Oudjana <y.oudjana@...tonmail.com>
> 
> Add a driver for sensors exposed by the Qualcomm Sensor Manager service,
> which is provided by SLPI or ADSP on Qualcomm SoCs. Supported sensors
> include accelerometers, gyroscopes, pressure sensors, proximity sensors
> and magnetometers.
> 
> Signed-off-by: Yassine Oudjana <y.oudjana@...tonmail.com>

As Andy commented - this is big.  Break it up for v3.

So far I haven't understood why a separate accelerometer driver was necessary.
Some comments in the patch description would perhaps help me understand that.

> diff --git a/drivers/iio/accel/qcom_smgr_accel.c b/drivers/iio/accel/qcom_smgr_accel.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..ce854312d1d9386300785f1965d5886c16995806
> --- /dev/null
> +++ b/drivers/iio/accel/qcom_smgr_accel.c
> @@ -0,0 +1,138 @@


> +static void qcom_smgr_accel_remove(struct platform_device *pdev)
> +{
> +	struct qcom_smgr_sensor *sensor = platform_get_drvdata(pdev);
> +
> +	sensor->iio_dev = NULL;

Add a comment for why this is needed. I can't immediately spot anything
explicitly checking it so it doesn't seem to be about safe handling
of device removal or similar.


> +}
> +
> +static const struct platform_device_id qcom_smgr_accel_ids[] = {
> +	{ .name = "qcom-smgr-accel" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(platform, qcom_smgr_accel_ids);
> +
> +static struct platform_driver qcom_smgr_accel_driver = {
> +	.probe = qcom_smgr_accel_probe,
> +	.remove = qcom_smgr_accel_remove,
> +	.driver	= {
> +		.name = "qcom_smgr_accel",
> +	},
> +	.id_table = qcom_smgr_accel_ids,
> +};
> +module_platform_driver(qcom_smgr_accel_driver);
> +
> +MODULE_AUTHOR("Yassine Oudjana <y.oudjana@...tonmail.com>");
> +MODULE_DESCRIPTION("Qualcomm Sensor Manager accelerometer driver");
> +MODULE_LICENSE("GPL");

I'm struggling to understand what the relationship between this driver
the main sensor driver is.

> diff --git a/drivers/iio/common/qcom_smgr/qcom_smgr.c b/drivers/iio/common/qcom_smgr/qcom_smgr.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..79d1160f7a5c32f1a9e0a20f29e304e5cb18be8f
> --- /dev/null
> +++ b/drivers/iio/common/qcom_smgr/qcom_smgr.c
> @@ -0,0 +1,840 @@

> +static void qcom_smgr_buffering_report_handler(struct qmi_handle *hdl,
> +					       struct sockaddr_qrtr *sq,
> +					       struct qmi_txn *txn,
> +					       const void *data)
> +{
> +	struct qcom_smgr *smgr =
> +		container_of(hdl, struct qcom_smgr, sns_smgr_hdl);
> +	const struct sns_smgr_buffering_report_ind *ind = data;
> +	struct qcom_smgr_sensor *sensor;
> +	struct qcom_smgr_iio_data iio_data;
> +	int temp;
> +	u8 i, j;
> +
> +	for (i = 0; i < smgr->sensor_count; ++i) {
> +		sensor = &smgr->sensors[i];
> +
> +		/* Find sensor matching report */
> +		if (sensor->id == ind->report_id)
> +			break;
> +	}
> +
> +	if (i == smgr->sensor_count) {
> +		dev_warn_ratelimited(smgr->dev,
> +			"Received buffering report with unknown ID: %02x",
> +			ind->report_id);
> +		return;
> +	}
> +
> +	/*
> +	 * Construct data to be passed to IIO. Since we are matching report rate
> +	 * with sample rate, we only get a single sample in every report.
> +	 */
> +	for (j = 0; j < ARRAY_SIZE(ind->samples[0].values); ++j)
> +		iio_data.values[j] = ind->samples[0].values[j];
> +
> +	/*
> +	 * SMGR reports sensor data in 32-bit fixed-point values, with 16 bits
> +	 * holding the integer part and the other 16 bits holding the numerator
> +	 * of a fraction with the denominator 2**16.
> +	 *
> +	 * Proximity sensor values are reported differently from other sensors.
> +	 * The value reported is a boolean (0 or 1, still in the same fixed-point
> +	 * format) where 1 means the sensor is activated, i.e. something is
> +	 * within its range. Use the reported range to pass an actual distance
> +	 * value to IIO. We pass the sensor range when nothing is within range
> +	 * (sensor maxed out) and 0 when something is within range (assume
> +	 * sensor is covered).
> +	 */
> +	if (sensor->type == SNS_SMGR_SENSOR_TYPE_PROX_LIGHT) {
> +		temp = le32_to_cpu(iio_data.values[0]);
> +		temp >>= SMGR_VALUE_DECIMAL_OFFSET;
> +		temp = ~temp & 1;
> +		temp *= sensor->data_types[0].range;
> +		iio_data.values[0] = cpu_to_le32(temp);
> +	}
> +
> +	iio_push_to_buffers(sensor->iio_dev, &iio_data);
You have a structure with space for timestamps but don't provide one which
is odd.  Either don't make space, or provide it.

> +}

> +
> +static int qcom_smgr_sensor_predisable(struct iio_dev *iio_dev)
> +{
> +	struct qcom_smgr *smgr = dev_get_drvdata(iio_dev->dev.parent);
> +	struct qcom_smgr_iio_priv *priv = iio_priv(iio_dev);
> +	struct qcom_smgr_sensor *sensor = priv->sensor;
> +
> +	dev_info(smgr->dev, "disable buffering %02x\n", sensor->id);

Too nosy. dev_dbg()

> +	return qcom_smgr_request_buffering(smgr, sensor, false);
> +}

> +static int qcom_smgr_iio_read_raw(struct iio_dev *iio_dev,
> +				  struct iio_chan_spec const *chan, int *val,
> +				  int *val2, long mask)
> +{
> +	struct qcom_smgr_iio_priv *priv = iio_priv(iio_dev);
> +
> +	switch (mask) {

No sysfs access at all to data is unusual but not completely unheard of.

> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		*val = priv->sensor->data_types[0].cur_sample_rate;
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_SCALE:
> +		*val = 1;
> +		*val2 = 1 << SMGR_VALUE_DECIMAL_OFFSET;
> +		return IIO_VAL_FRACTIONAL;
> +	default:
> +		return -EINVAL;
> +	}

> +
> +static const struct iio_chan_spec qcom_smgr_pressure_iio_channels[] = {
> +	{
> +		.type = IIO_PRESSURE,
> +		.scan_index = 0,
> +		.scan_type = {
> +			.sign = 'u',
> +			.realbits = 32,
> +			.storagebits = 32,
> +			.endianness = IIO_LE,
> +		},
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) |
> +				      BIT(IIO_CHAN_INFO_SAMP_FREQ)
> +	},
> +	{
> +		.type = IIO_TIMESTAMP,
> +		.channel = -1,
> +		.scan_index = 3,

Why 3?

> +		.scan_type = {
> +			.sign = 'u',
> +			.realbits = 32,

If it's realbits 32 and no shift, why not store it in a 32 bit value?
I assume this is a hardware provided timestamp rather than typical software
filled in one?  Anyhow, I'm not immediately spotting it being used yet
so for now perhaps best to drop the channel descriptions.

> +			.storagebits = 64,
> +			.endianness = IIO_LE,
> +		},
> +	}
> +};

> +static int qcom_smgr_register_sensor(struct qcom_smgr *smgr,
> +				     struct qcom_smgr_sensor *sensor)
> +{
> +	struct iio_dev *iio_dev;
> +	struct qcom_smgr_iio_priv *priv;
> +	int ret;

> +	sensor->iio_dev = iio_dev;
> +
> +	ret = devm_iio_kfifo_buffer_setup(smgr->dev, iio_dev,
> +					  &qcom_smgr_buffer_ops);
> +	if (ret) {
> +		dev_err(smgr->dev, "Failed to setup buffer: %pe\n",

Use return dev_err_probe() for all errors that occur in code that only
runs at probe() time.

> +			ERR_PTR(ret));
> +		return ret;
> +	}
> +
> +	ret = devm_iio_device_register(smgr->dev, iio_dev);
> +	if (ret) {
> +		dev_err(smgr->dev, "Failed to register IIO device: %pe\n",
> +			ERR_PTR(ret));
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int qcom_smgr_probe(struct qrtr_device *qdev)
> +{
> +	struct qcom_smgr *smgr;
> +	int i, j;
> +	int ret;
> +
> +	smgr = devm_kzalloc(&qdev->dev, sizeof(*smgr), GFP_KERNEL);
> +	if (!smgr)
> +		return -ENOMEM;
> +
> +	smgr->dev = &qdev->dev;
> +
> +	smgr->sns_smgr_info.sq_family = AF_QIPCRTR;
> +	smgr->sns_smgr_info.sq_node = qdev->node;
> +	smgr->sns_smgr_info.sq_port = qdev->port;
> +
> +	dev_set_drvdata(&qdev->dev, smgr);
This code is a bit random on whether it uses qdev->dev, or smgr->dev

I'd be tempted to just introce
	struct device *dev = &qdev->dev; and use that pretty much everywhere.

> +
> +	ret = qmi_handle_init(&smgr->sns_smgr_hdl,
> +			      SNS_SMGR_SINGLE_SENSOR_INFO_RESP_MAX_LEN, NULL,
> +			      qcom_smgr_msg_handlers);
> +	if (ret < 0)
> +		return dev_err_probe(smgr->dev, ret,
> +			"Failed to initialize sensor manager handle\n");
> +
> +	ret = devm_add_action_or_reset(smgr->dev,
> +				       (void(*)(void *))qmi_handle_release,

I'd much prefer a local wrapper to casting types of functions.

> +				       &smgr->sns_smgr_hdl);
> +	if (ret)
> +		return ret;
> +
> +	ret = qcom_smgr_request_all_sensor_info(smgr, &smgr->sensors);
> +	if (ret < 0)
> +		return dev_err_probe(smgr->dev, ret,
> +			"Failed to get available sensors\n");
> +
> +	smgr->sensor_count = ret;
> +
> +	/* Get primary and secondary sensors from each sensor ID */
> +	for (i = 0; i < smgr->sensor_count; i++) {
> +		ret = qcom_smgr_request_single_sensor_info(smgr,
> +							   &smgr->sensors[i]);
> +		if (ret < 0)
> +			return dev_err_probe(smgr->dev, ret,
> +				"Failed to get sensors from ID 0x%02x\n",
> +				smgr->sensors[i].id);
> +
> +		for (j = 0; j < smgr->sensors[i].data_type_count; j++) {
> +			/* Default to maximum sample rate */
> +			smgr->sensors[i].data_types->cur_sample_rate =
> +				smgr->sensors[i].data_types->max_sample_rate;
> +
> +			dev_dbg(smgr->dev, "0x%02x,%d: %s %s\n",
> +				smgr->sensors[i].id, j,
> +				smgr->sensors[i].data_types[j].vendor,
> +				smgr->sensors[i].data_types[j].name);
> +		}
> +
> +		/* Skip if sensor type is not supported */
> +		if (smgr->sensors[i]->type == SNS_SMGR_SENSOR_TYPE_UNKNOWN ||
> +		    !qcom_smgr_sensor_type_iio_channels[smgr->sensors[i]->type])
> +			continue;
> +
> +		ret = qcom_smgr_register_sensor(smgr, &smgr->sensors[i]);
> +		if (ret)
> +			return dev_err_probe(smgr->dev, ret,
> +				"Failed to register sensor 0x%02x\n",
> +				smgr->sensors[i].id);
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct qrtr_device_id qcom_smgr_qrtr_match[] = {
> +	{
> +		.service = SNS_SMGR_QMI_SVC_ID,
> +		/* Found on MSM8953 */
> +		.instance = QRTR_INSTANCE_CONST(0, 1)
> +	},
> +	{
> +		.service = SNS_SMGR_QMI_SVC_ID,
> +		/* Found on MSM8974 and MSM8226 */
> +		.instance = QRTR_INSTANCE_CONST(1, 0)
> +	},
> +	{
> +		.service = SNS_SMGR_QMI_SVC_ID,
> +		/* Found on MSM8996 and SDM660 */
> +		.instance = QRTR_INSTANCE_CONST(1, 50)
> +	},
> +	{ },

No comma on a terminating entry like this.

> +};
> +MODULE_DEVICE_TABLE(qrtr, qcom_smgr_qrtr_match);


> +const struct qmi_elem_info sns_smgr_buffering_report_ind_ei[] = {
> +	{
> +		.data_type = QMI_UNSIGNED_1_BYTE,
> +		.elem_len = 1,
> +		.elem_size = sizeof_field(struct sns_smgr_buffering_report_ind,
> +					  report_id),
> +		.array_type = NO_ARRAY,
> +		.tlv_type = 0x01,
> +		.offset = offsetof(struct sns_smgr_buffering_report_ind,
> +				   report_id),
> +	},
> +	{
> +		.data_type = QMI_STRUCT,
> +		.elem_len = 1,
> +		.elem_size = sizeof_field(struct sns_smgr_buffering_report_ind,
> +					  metadata),
> +		.array_type = NO_ARRAY,
> +		.tlv_type = 0x02,
> +		.offset = offsetof(struct sns_smgr_buffering_report_ind,
> +				   metadata),
> +		.ei_array = sns_smgr_buffering_report_metadata_ei,
> +	},
> +	{
> +		.data_type = QMI_DATA_LEN,
> +		.elem_len = 1,
> +		.elem_size = sizeof_field(struct sns_smgr_buffering_report_ind,
> +					  samples_len),
> +		.array_type = NO_ARRAY,
> +		.tlv_type = 0x03,
> +		.offset = offsetof(struct sns_smgr_buffering_report_ind,
> +				   samples_len),
> +	},
> +	{
> +		.data_type = QMI_STRUCT,
> +		.elem_len = SNS_SMGR_SAMPLES_MAX_LEN,
> +		.elem_size = sizeof(struct sns_smgr_buffering_report_sample),
> +		.array_type = VAR_LEN_ARRAY,
> +		.tlv_type = 0x03,
> +		.offset =
> +			offsetof(struct sns_smgr_buffering_report_ind, samples),

I'm fine with slightly over 80 chars to avoid readability issues like this.


> diff --git a/include/linux/iio/common/qcom_smgr.h b/include/linux/iio/common/qcom_smgr.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..fdd3de12bb0a48f1fb9e51cd0463c9a9b9ed500f
> --- /dev/null
> +++ b/include/linux/iio/common/qcom_smgr.h
> @@ -0,0 +1,80 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef __QCOM_SMGR_H__
> +#define __QCOM_SMGR_H__
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/types.h>
> +#include <linux/soc/qcom/qmi.h>
> +#include <linux/types.h>

> +
> +struct qcom_smgr_sensor {
> +	u8 id;
> +	enum qcom_smgr_sensor_type type;
> +
> +	u8 data_type_count;
> +	/*
> +	 * Only SNS_SMGR_DATA_TYPE_PRIMARY is used at the moment, but we store
> +	 * SNS_SMGR_DATA_TYPE_SECONDARY when available as well for future use.
> +	 */
> +	struct qcom_smgr_data_type_item *data_types;
> +
> +	struct iio_dev *iio_dev;
> +};
> +
> +struct qcom_smgr_iio_priv {
> +	struct qcom_smgr_sensor *sensor;
> +
> +	int samp_freq_vals[3];
> +};
> +
> +
> +struct qcom_smgr_iio_data {
> +	u32 values[3];
> +	u64 timestamp;

Timestamps in kernel tend to be s64. Also for IIO buffers aligned_s64 required.
Whilst this will probably never be used on an architecture that doesn't naturally
align 8 byte variables, we should still code for it.

Given this tends to be used locally maybe just define it where you need it.


> +};

> 


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ