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

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
Loading
Loading
Loading
Loading
+32 −13
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>

#define USB_VENDOR_ID_CORSAIR			0x1b1c
@@ -77,8 +78,11 @@
struct ccp_device {
	struct hid_device *hdev;
	struct device *hwmon_dev;
	/* For reinitializing the completion below */
	spinlock_t wait_input_report_lock;
	struct completion wait_input_report;
	struct mutex mutex; /* whenever buffer is used, lock before send_usb_cmd */
	u8 *cmd_buffer;
	u8 *buffer;
	int target[6];
	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,
	unsigned long t;
	int ret;

	memset(ccp->buffer, 0x00, OUT_BUFFER_SIZE);
	ccp->buffer[0] = command;
	ccp->buffer[1] = byte1;
	ccp->buffer[2] = byte2;
	ccp->buffer[3] = byte3;
	memset(ccp->cmd_buffer, 0x00, OUT_BUFFER_SIZE);
	ccp->cmd_buffer[0] = command;
	ccp->cmd_buffer[1] = byte1;
	ccp->cmd_buffer[2] = byte2;
	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);
	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)
		return ret;

@@ -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);

	/* only copy buffer when requested */
	if (completion_done(&ccp->wait_input_report))
		return 0;

	spin_lock(&ccp->wait_input_report_lock);
	if (!completion_done(&ccp->wait_input_report)) {
		memcpy(ccp->buffer, data, min(IN_BUFFER_SIZE, size));
	complete(&ccp->wait_input_report);
		complete_all(&ccp->wait_input_report);
	}
	spin_unlock(&ccp->wait_input_report_lock);

	return 0;
}
@@ -492,7 +505,11 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
	if (!ccp)
		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)
		return -ENOMEM;

@@ -510,7 +527,9 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)

	ccp->hdev = hdev;
	hid_set_drvdata(hdev, ccp);

	mutex_init(&ccp->mutex);
	spin_lock_init(&ccp->wait_input_report_lock);
	init_completion(&ccp->wait_input_report);

	hid_device_io_start(hdev);
+3 −3
Original line number Diff line number Diff line
@@ -80,11 +80,11 @@ struct ucd9000_debugfs_entry {
 * 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
 * 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
 * 200us the issue seems to go away. Add a bit of extra margin to allow for
 * following access. The 500 is based on experimental data. At a delay of
 * 350us the issue seems to go away. Add a bit of extra margin to allow for
 * 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)
{