[v3] hwmon: (aquacomputer_d5next) Add selective 200ms delay after sending ctrl report

Message ID 20230807172004.456968-1-savicaleksa83@gmail.com
State New
Headers
Series [v3] hwmon: (aquacomputer_d5next) Add selective 200ms delay after sending ctrl report |

Commit Message

Aleksa Savic Aug. 7, 2023, 5:20 p.m. UTC
  Add a 200ms delay after sending a ctrl report to Quadro,
Octo, D5 Next and Aquaero to give them enough time to
process the request and save the data to memory. Otherwise,
under heavier userspace loads where multiple sysfs entries
are usually set in quick succession, a new ctrl report could
be requested from the device while it's still processing the
previous one and fail with -EPIPE. The delay is only applied
if two ctrl report operations are near each other in time.

Reported by a user on Github [1] and tested by both of us.

[1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/issues/82

Fixes: 752b927951ea ("hwmon: (aquacomputer_d5next) Add support for Aquacomputer Octo")
Signed-off-by: Aleksa Savic <savicaleksa83@gmail.com>
---
Changes in v3:
- Reworked code to track the last time of a ctrl report
  operation and only delay if necessary, as per suggestion

Changes in v2:
- Added missing <linux/delay.h> include
---
 drivers/hwmon/aquacomputer_d5next.c | 37 ++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)
  

Comments

Guenter Roeck Aug. 10, 2023, 4:09 a.m. UTC | #1
On Mon, Aug 07, 2023 at 07:20:03PM +0200, Aleksa Savic wrote:
> Add a 200ms delay after sending a ctrl report to Quadro,
> Octo, D5 Next and Aquaero to give them enough time to
> process the request and save the data to memory. Otherwise,
> under heavier userspace loads where multiple sysfs entries
> are usually set in quick succession, a new ctrl report could
> be requested from the device while it's still processing the
> previous one and fail with -EPIPE. The delay is only applied
> if two ctrl report operations are near each other in time.
> 
> Reported by a user on Github [1] and tested by both of us.
> 
> [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/issues/82
> 
> Fixes: 752b927951ea ("hwmon: (aquacomputer_d5next) Add support for Aquacomputer Octo")
> Signed-off-by: Aleksa Savic <savicaleksa83@gmail.com>

I would have suggested to use fsleep() to avoid unnecessary
sleep times if they are small, bt I guess it doesn't make much
of a difference.

Applied.

Thanks,
Guenter
  
Aleksa Savic Aug. 10, 2023, 6:15 p.m. UTC | #2
On 2023-08-10 06:09:13 GMT+02:00, Guenter Roeck wrote:
> On Mon, Aug 07, 2023 at 07:20:03PM +0200, Aleksa Savic wrote:
>> Add a 200ms delay after sending a ctrl report to Quadro,
>> Octo, D5 Next and Aquaero to give them enough time to
>> process the request and save the data to memory. Otherwise,
>> under heavier userspace loads where multiple sysfs entries
>> are usually set in quick succession, a new ctrl report could
>> be requested from the device while it's still processing the
>> previous one and fail with -EPIPE. The delay is only applied
>> if two ctrl report operations are near each other in time.
>>
>> Reported by a user on Github [1] and tested by both of us.
>>
>> [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/issues/82
>>
>> Fixes: 752b927951ea ("hwmon: (aquacomputer_d5next) Add support for Aquacomputer Octo")
>> Signed-off-by: Aleksa Savic <savicaleksa83@gmail.com>
> 
> I would have suggested to use fsleep() to avoid unnecessary
> sleep times if they are small, bt I guess it doesn't make much
> of a difference.

Will keep that in mind.

> 
> Applied.

Will this patch perhaps be marked for stable?

Thanks,
Aleksa

> 
> Thanks,
> Guenter
  
Guenter Roeck Aug. 11, 2023, 11:05 p.m. UTC | #3
On 8/10/23 11:15, Aleksa Savic wrote:
> On 2023-08-10 06:09:13 GMT+02:00, Guenter Roeck wrote:
>> On Mon, Aug 07, 2023 at 07:20:03PM +0200, Aleksa Savic wrote:
>>> Add a 200ms delay after sending a ctrl report to Quadro,
>>> Octo, D5 Next and Aquaero to give them enough time to
>>> process the request and save the data to memory. Otherwise,
>>> under heavier userspace loads where multiple sysfs entries
>>> are usually set in quick succession, a new ctrl report could
>>> be requested from the device while it's still processing the
>>> previous one and fail with -EPIPE. The delay is only applied
>>> if two ctrl report operations are near each other in time.
>>>
>>> Reported by a user on Github [1] and tested by both of us.
>>>
>>> [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/issues/82
>>>
>>> Fixes: 752b927951ea ("hwmon: (aquacomputer_d5next) Add support for Aquacomputer Octo")
>>> Signed-off-by: Aleksa Savic <savicaleksa83@gmail.com>
>>
>> I would have suggested to use fsleep() to avoid unnecessary
>> sleep times if they are small, bt I guess it doesn't make much
>> of a difference.
> 
> Will keep that in mind.
> 
>>
>> Applied.
> 
> Will this patch perhaps be marked for stable?
> 

It has a Fixes: tag, so it will be applied to affected stable releases
automatically, at least if it applies cleanly. I could have added Cc:
stable@ to make it explicit, but I had pushed it already, and I didn't
want to rebase the branch just for that.

Guenter
  
Aleksa Savic Aug. 12, 2023, 6:49 p.m. UTC | #4
On 2023-08-12 01:05:19 GMT+02:00, Guenter Roeck wrote:
> 
> It has a Fixes: tag, so it will be applied to affected stable releases
> automatically, at least if it applies cleanly. I could have added Cc:
> stable@ to make it explicit, but I had pushed it already, and I didn't
> want to rebase the branch just for that.
> 
> Guenter
> 

Didn't know explicit Cc wasn't necessary, thanks.

Aleksa
  
Guenter Roeck Aug. 14, 2023, 1:42 p.m. UTC | #5
On Sat, Aug 12, 2023 at 08:49:49PM +0200, Aleksa Savic wrote:
> On 2023-08-12 01:05:19 GMT+02:00, Guenter Roeck wrote:
> > 
> > It has a Fixes: tag, so it will be applied to affected stable releases
> > automatically, at least if it applies cleanly. I could have added Cc:
> > stable@ to make it explicit, but I had pushed it already, and I didn't
> > want to rebase the branch just for that.
> > 
> > Guenter
> > 
> 
> Didn't know explicit Cc wasn't necessary, thanks.
> 

Preferred but not necessary. You should have received an e-mail telling
you that the patch did not apply to 6.1.y. If you want it applied there,
send a backport to stable@ with a subject such as [PATCH v6.1] ...
and backport comments after "---".

Guenter
  

Patch

diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c
index a997dbcb563f..023807859be7 100644
--- a/drivers/hwmon/aquacomputer_d5next.c
+++ b/drivers/hwmon/aquacomputer_d5next.c
@@ -13,9 +13,11 @@ 
 
 #include <linux/crc16.h>
 #include <linux/debugfs.h>
+#include <linux/delay.h>
 #include <linux/hid.h>
 #include <linux/hwmon.h>
 #include <linux/jiffies.h>
+#include <linux/ktime.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/seq_file.h>
@@ -63,6 +65,8 @@  static const char *const aqc_device_names[] = {
 #define CTRL_REPORT_ID			0x03
 #define AQUAERO_CTRL_REPORT_ID		0x0b
 
+#define CTRL_REPORT_DELAY		200	/* ms */
+
 /* The HID report that the official software always sends
  * after writing values, currently same for all devices
  */
@@ -527,6 +531,9 @@  struct aqc_data {
 	int secondary_ctrl_report_size;
 	u8 *secondary_ctrl_report;
 
+	ktime_t last_ctrl_report_op;
+	int ctrl_report_delay;	/* Delay between two ctrl report operations, in ms */
+
 	int buffer_size;
 	u8 *buffer;
 	int checksum_start;
@@ -611,17 +618,35 @@  static int aqc_aquastreamxt_convert_fan_rpm(u16 val)
 	return 0;
 }
 
+static void aqc_delay_ctrl_report(struct aqc_data *priv)
+{
+	/*
+	 * If previous read or write is too close to this one, delay the current operation
+	 * to give the device enough time to process the previous one.
+	 */
+	if (priv->ctrl_report_delay) {
+		s64 delta = ktime_ms_delta(ktime_get(), priv->last_ctrl_report_op);
+
+		if (delta < priv->ctrl_report_delay)
+			msleep(priv->ctrl_report_delay - delta);
+	}
+}
+
 /* Expects the mutex to be locked */
 static int aqc_get_ctrl_data(struct aqc_data *priv)
 {
 	int ret;
 
+	aqc_delay_ctrl_report(priv);
+
 	memset(priv->buffer, 0x00, priv->buffer_size);
 	ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size,
 				 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
 	if (ret < 0)
 		ret = -ENODATA;
 
+	priv->last_ctrl_report_op = ktime_get();
+
 	return ret;
 }
 
@@ -631,6 +656,8 @@  static int aqc_send_ctrl_data(struct aqc_data *priv)
 	int ret;
 	u16 checksum;
 
+	aqc_delay_ctrl_report(priv);
+
 	/* Checksum is not needed for Aquaero */
 	if (priv->kind != aquaero) {
 		/* Init and xorout value for CRC-16/USB is 0xffff */
@@ -646,12 +673,16 @@  static int aqc_send_ctrl_data(struct aqc_data *priv)
 	ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size,
 				 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 	if (ret < 0)
-		return ret;
+		goto record_access_and_ret;
 
 	/* The official software sends this report after every change, so do it here as well */
 	ret = hid_hw_raw_request(priv->hdev, priv->secondary_ctrl_report_id,
 				 priv->secondary_ctrl_report, priv->secondary_ctrl_report_size,
 				 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+
+record_access_and_ret:
+	priv->last_ctrl_report_op = ktime_get();
+
 	return ret;
 }
 
@@ -1524,6 +1555,7 @@  static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
 		priv->buffer_size = AQUAERO_CTRL_REPORT_SIZE;
 		priv->temp_ctrl_offset = AQUAERO_TEMP_CTRL_OFFSET;
+		priv->ctrl_report_delay = CTRL_REPORT_DELAY;
 
 		priv->temp_label = label_temp_sensors;
 		priv->virtual_temp_label = label_virtual_temp_sensors;
@@ -1547,6 +1579,7 @@  static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
 		priv->temp_ctrl_offset = D5NEXT_TEMP_CTRL_OFFSET;
 
 		priv->buffer_size = D5NEXT_CTRL_REPORT_SIZE;
+		priv->ctrl_report_delay = CTRL_REPORT_DELAY;
 
 		priv->power_cycle_count_offset = D5NEXT_POWER_CYCLES;
 
@@ -1597,6 +1630,7 @@  static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
 		priv->temp_ctrl_offset = OCTO_TEMP_CTRL_OFFSET;
 
 		priv->buffer_size = OCTO_CTRL_REPORT_SIZE;
+		priv->ctrl_report_delay = CTRL_REPORT_DELAY;
 
 		priv->power_cycle_count_offset = OCTO_POWER_CYCLES;
 
@@ -1624,6 +1658,7 @@  static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
 		priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET;
 
 		priv->buffer_size = QUADRO_CTRL_REPORT_SIZE;
+		priv->ctrl_report_delay = CTRL_REPORT_DELAY;
 
 		priv->flow_pulses_ctrl_offset = QUADRO_FLOW_PULSES_CTRL_OFFSET;
 		priv->power_cycle_count_offset = QUADRO_POWER_CYCLES;