hwmon fixes for v6.9-rc8

- pmbus/ucd9000: Increase chip access delay to avoid random access
   errors
 
 - corsair-cpro: Protect kernel code against parallel hidraw access
   from userspace
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmY8/IQACgkQyx8mb86f
 mYF5YxAAjdKo6Ch/0LaGvUVsOj7fZaKNWX2YW91nCcJCjO0LsliuXZqRj/v1EDxr
 S63ropzUdC+oX8JnYaEpmzK3+KdmrvGQjrwz4zSsD9QIrKDEj2kqZvy6/cnLUvTF
 2X5JX1DjDZNiSiR3tQNJR1NIO0JTtMJ6S2qxZgVp77k6CKfxPpG4NYfBw+7bw2w1
 l+rV4RaquIeZSQzMfZYoRQfNTIneG1nt4JyjD/RN9zmiFikypRrN9PoQs6MzMj/F
 +OjKeXCz11a8rIaJRqKPiRf8uE086qX7TFd7eLKDeP16cCg22CBitIeP95+k8fIZ
 grmA/RtCuNicJlpX5fCysYosYtG6kCdbor6VXpOoY5/bmZNjhrirRiIsa6ueYeNr
 eGA1PEqUfUR6Ot4ZtdWjkKMLo81WtaJDYtYPusRyOcHSXC/PH6xYLuEIFt5nSA/k
 Wvi1yYv/uY9ki3eMSMKI4X59DEnb390lho8OXpk6yHh166AlWmWXVXUw7kVNGvuw
 gIjMlMZ4VDvk9sdqhn6ToW5AZKqaRzgti4VmEzjjr8u3GkD9SwO9klN9EuX4IRj7
 Rgk7JfH+XkSVZCcp01bb7gHK3PwMEtoOvxO/8aq3j7h144blk5gP22c32eT/uTCx
 rIDxF7gtcdQWr6BYz5d1EcZW89kZW8zMtLExAlHGB/dVEHuXWS8=
 =sjbz
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2024-05-09 10:17:22 -07:00
commit 448b3fe5a0
2 changed files with 34 additions and 15 deletions

View File

@ -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;
memcpy(ccp->buffer, data, min(IN_BUFFER_SIZE, size));
complete(&ccp->wait_input_report);
spin_lock(&ccp->wait_input_report_lock);
if (!completion_done(&ccp->wait_input_report)) {
memcpy(ccp->buffer, data, min(IN_BUFFER_SIZE, size));
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);

View File

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