Commit 448b3fe5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-v6.9-rc8' of...

Merge tag 'hwmon-for-v6.9-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon fixes from Guenter Roeck:

 - pmbus/ucd9000: Increase chip access delay to avoid random access
   errors

 - corsair-cpro: Protect kernel code against parallel hidraw access from
   userspace

* tag 'hwmon-for-v6.9-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (pmbus/ucd9000) Increase delay from 250 to 500us
  hwmon: (corsair-cpro) Protect ccp->wait_input_report with a spinlock
  hwmon: (corsair-cpro) Use complete_all() instead of complete() in ccp_raw_event()
  hwmon: (corsair-cpro) Use a separate buffer for sending commands
parents 8c3b7565 26e8383b
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#define USB_VENDOR_ID_CORSAIR 0x1b1c #define USB_VENDOR_ID_CORSAIR 0x1b1c
...@@ -77,8 +78,11 @@ ...@@ -77,8 +78,11 @@
struct ccp_device { struct ccp_device {
struct hid_device *hdev; struct hid_device *hdev;
struct device *hwmon_dev; struct device *hwmon_dev;
/* For reinitializing the completion below */
spinlock_t wait_input_report_lock;
struct completion wait_input_report; struct completion wait_input_report;
struct mutex mutex; /* whenever buffer is used, lock before send_usb_cmd */ struct mutex mutex; /* whenever buffer is used, lock before send_usb_cmd */
u8 *cmd_buffer;
u8 *buffer; u8 *buffer;
int target[6]; int target[6];
DECLARE_BITMAP(temp_cnct, NUM_TEMP_SENSORS); DECLARE_BITMAP(temp_cnct, NUM_TEMP_SENSORS);
...@@ -111,15 +115,23 @@ static int send_usb_cmd(struct ccp_device *ccp, u8 command, u8 byte1, u8 byte2, ...@@ -111,15 +115,23 @@ static int send_usb_cmd(struct ccp_device *ccp, u8 command, u8 byte1, u8 byte2,
unsigned long t; unsigned long t;
int ret; int ret;
memset(ccp->buffer, 0x00, OUT_BUFFER_SIZE); memset(ccp->cmd_buffer, 0x00, OUT_BUFFER_SIZE);
ccp->buffer[0] = command; ccp->cmd_buffer[0] = command;
ccp->buffer[1] = byte1; ccp->cmd_buffer[1] = byte1;
ccp->buffer[2] = byte2; ccp->cmd_buffer[2] = byte2;
ccp->buffer[3] = byte3; ccp->cmd_buffer[3] = byte3;
/*
* Disable raw event parsing for a moment to safely reinitialize the
* completion. Reinit is done because hidraw could have triggered
* the raw event parsing and marked the ccp->wait_input_report
* completion as done.
*/
spin_lock_bh(&ccp->wait_input_report_lock);
reinit_completion(&ccp->wait_input_report); reinit_completion(&ccp->wait_input_report);
spin_unlock_bh(&ccp->wait_input_report_lock);
ret = hid_hw_output_report(ccp->hdev, ccp->buffer, OUT_BUFFER_SIZE); ret = hid_hw_output_report(ccp->hdev, ccp->cmd_buffer, OUT_BUFFER_SIZE);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -135,11 +147,12 @@ static int ccp_raw_event(struct hid_device *hdev, struct hid_report *report, u8 ...@@ -135,11 +147,12 @@ static int ccp_raw_event(struct hid_device *hdev, struct hid_report *report, u8
struct ccp_device *ccp = hid_get_drvdata(hdev); struct ccp_device *ccp = hid_get_drvdata(hdev);
/* only copy buffer when requested */ /* only copy buffer when requested */
if (completion_done(&ccp->wait_input_report)) spin_lock(&ccp->wait_input_report_lock);
return 0; if (!completion_done(&ccp->wait_input_report)) {
memcpy(ccp->buffer, data, min(IN_BUFFER_SIZE, size));
memcpy(ccp->buffer, data, min(IN_BUFFER_SIZE, size)); complete_all(&ccp->wait_input_report);
complete(&ccp->wait_input_report); }
spin_unlock(&ccp->wait_input_report_lock);
return 0; return 0;
} }
...@@ -492,7 +505,11 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -492,7 +505,11 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!ccp) if (!ccp)
return -ENOMEM; return -ENOMEM;
ccp->buffer = devm_kmalloc(&hdev->dev, OUT_BUFFER_SIZE, GFP_KERNEL); ccp->cmd_buffer = devm_kmalloc(&hdev->dev, OUT_BUFFER_SIZE, GFP_KERNEL);
if (!ccp->cmd_buffer)
return -ENOMEM;
ccp->buffer = devm_kmalloc(&hdev->dev, IN_BUFFER_SIZE, GFP_KERNEL);
if (!ccp->buffer) if (!ccp->buffer)
return -ENOMEM; return -ENOMEM;
...@@ -510,7 +527,9 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -510,7 +527,9 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
ccp->hdev = hdev; ccp->hdev = hdev;
hid_set_drvdata(hdev, ccp); hid_set_drvdata(hdev, ccp);
mutex_init(&ccp->mutex); mutex_init(&ccp->mutex);
spin_lock_init(&ccp->wait_input_report_lock);
init_completion(&ccp->wait_input_report); init_completion(&ccp->wait_input_report);
hid_device_io_start(hdev); hid_device_io_start(hdev);
......
...@@ -80,11 +80,11 @@ struct ucd9000_debugfs_entry { ...@@ -80,11 +80,11 @@ struct ucd9000_debugfs_entry {
* It has been observed that the UCD90320 randomly fails register access when * It has been observed that the UCD90320 randomly fails register access when
* doing another access right on the back of a register write. To mitigate this * doing another access right on the back of a register write. To mitigate this
* make sure that there is a minimum delay between a write access and the * make sure that there is a minimum delay between a write access and the
* following access. The 250us is based on experimental data. At a delay of * following access. The 500 is based on experimental data. At a delay of
* 200us the issue seems to go away. Add a bit of extra margin to allow for * 350us the issue seems to go away. Add a bit of extra margin to allow for
* system to system differences. * system to system differences.
*/ */
#define UCD90320_WAIT_DELAY_US 250 #define UCD90320_WAIT_DELAY_US 500
static inline void ucd90320_wait(const struct ucd9000_data *data) static inline void ucd90320_wait(const struct ucd9000_data *data)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment