diff mbox series

[v2,05/12] iio: st_sensors: Add a local lock for protecting odr

Message ID 20220202140208.391394-6-miquel.raynal@bootlin.com (mailing list archive)
State Changes Requested
Headers show
Series Miscellaneous IIO core enhancements | expand

Commit Message

Miquel Raynal Feb. 2, 2022, 2:02 p.m. UTC
Right now the (framework) mlock lock is (ab)used for multiple purposes:
1- protecting concurrent accesses over the odr local cache
2- avoid changing samplig frequency whilst buffer is running

Let's start by handling situation #1 with a local lock.

Suggested-by: Jonathan Cameron <jic23@kernel.org>
Cc: Denis Ciocca <denis.ciocca@st.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 .../iio/common/st_sensors/st_sensors_core.c   | 28 +++++++++++++------
 include/linux/iio/common/st_sensors.h         |  3 ++
 2 files changed, 23 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 6c027150a5a4..d0419234a747 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -71,16 +71,18 @@  static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings,
 
 int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
 {
-	int err;
+	int err = 0;
 	struct st_sensor_odr_avl odr_out = {0, 0};
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 
+	mutex_lock(&sdata->odr_lock);
+
 	if (!sdata->sensor_settings->odr.mask)
-		return 0;
+		goto unlock_mutex;
 
 	err = st_sensors_match_odr(sdata->sensor_settings, odr, &odr_out);
 	if (err < 0)
-		goto st_sensors_match_odr_error;
+		goto unlock_mutex;
 
 	if ((sdata->sensor_settings->odr.addr ==
 					sdata->sensor_settings->pw.addr) &&
@@ -103,7 +105,9 @@  int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
 	if (err >= 0)
 		sdata->odr = odr_out.hz;
 
-st_sensors_match_odr_error:
+unlock_mutex:
+	mutex_unlock(&sdata->odr_lock);
+
 	return err;
 }
 EXPORT_SYMBOL(st_sensors_set_odr);
@@ -162,6 +166,8 @@  int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
 	struct st_sensor_odr_avl odr_out = {0, 0};
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 
+	mutex_lock(&sdata->odr_lock);
+
 	if (enable) {
 		tmp_value = sdata->sensor_settings->pw.value_on;
 		if ((sdata->sensor_settings->odr.addr ==
@@ -171,7 +177,7 @@  int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
 			err = st_sensors_match_odr(sdata->sensor_settings,
 							sdata->odr, &odr_out);
 			if (err < 0)
-				goto set_enable_error;
+				goto unlock_mutex;
 			tmp_value = odr_out.value;
 			found = true;
 		}
@@ -179,7 +185,7 @@  int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
 				sdata->sensor_settings->pw.addr,
 				sdata->sensor_settings->pw.mask, tmp_value);
 		if (err < 0)
-			goto set_enable_error;
+			goto unlock_mutex;
 
 		sdata->enabled = true;
 
@@ -191,12 +197,14 @@  int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
 				sdata->sensor_settings->pw.mask,
 				sdata->sensor_settings->pw.value_off);
 		if (err < 0)
-			goto set_enable_error;
+			goto unlock_mutex;
 
 		sdata->enabled = false;
 	}
 
-set_enable_error:
+unlock_mutex:
+	mutex_unlock(&sdata->odr_lock);
+
 	return err;
 }
 EXPORT_SYMBOL(st_sensors_set_enable);
@@ -361,6 +369,8 @@  int st_sensors_init_sensor(struct iio_dev *indio_dev,
 	struct st_sensors_platform_data *of_pdata;
 	int err = 0;
 
+	mutex_init(&sdata->odr_lock);
+
 	/* If OF/DT pdata exists, it will take precedence of anything else */
 	of_pdata = st_sensors_dev_probe(indio_dev->dev.parent, pdata);
 	if (IS_ERR(of_pdata))
@@ -558,8 +568,10 @@  int st_sensors_read_info_raw(struct iio_dev *indio_dev,
 		if (err < 0)
 			goto out;
 
+		mutex_lock(&sdata->odr_lock);
 		msleep((sdata->sensor_settings->bootime * 1000) / sdata->odr);
 		err = st_sensors_read_axis_data(indio_dev, ch, val);
+		mutex_unlock(&sdata->odr_lock);
 		if (err < 0)
 			goto out;
 
diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h
index 22f67845cdd3..db4a1b260348 100644
--- a/include/linux/iio/common/st_sensors.h
+++ b/include/linux/iio/common/st_sensors.h
@@ -237,6 +237,7 @@  struct st_sensor_settings {
  * @hw_irq_trigger: if we're using the hardware interrupt on the sensor.
  * @hw_timestamp: Latest timestamp from the interrupt handler, when in use.
  * @buffer_data: Data used by buffer part.
+ * @odr_lock: Local lock for preventing concurrent ODR accesses/changes
  */
 struct st_sensor_data {
 	struct iio_trigger *trig;
@@ -261,6 +262,8 @@  struct st_sensor_data {
 	s64 hw_timestamp;
 
 	char buffer_data[ST_SENSORS_MAX_BUFFER_SIZE] ____cacheline_aligned;
+
+	struct mutex odr_lock;
 };
 
 #ifdef CONFIG_IIO_BUFFER