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:
commit
448b3fe5a0
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue