[PATCH v2 2/3] HID: Intel-thc-hid: Intel-quicki2c: Refine recover callback
From: Even Xu <even.xu@intel.com>
Date: 2026-07-03 07:58:40
Also in:
lkml
Subsystem:
hid core layer, intel touch host controller (thc) driver, the rest · Maintainers:
Jiri Kosina, Benjamin Tissoires, Even Xu, Xinpeng Sun, Linus Torvalds
Refine recover flow: 1. Use workqueue to handle recover flow instead of processing in irq handler. 2. Call thc_rxdma_reset() API to simplify the recover operation. 3. Disable interrupt during whole recover flow. 4. If recover fails, disable interrupt to avoid interrupt storm. Signed-off-by: Even Xu <even.xu@intel.com> --- .../intel-quicki2c/pci-quicki2c.c | 42 ++++++++++--------- .../intel-quicki2c/quicki2c-dev.h | 2 + 2 files changed, 25 insertions(+), 19 deletions(-)
diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
index 46d3e9a01999..11e0e129b44c 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c@@ -245,28 +245,28 @@ static irqreturn_t quicki2c_irq_quick_handler(int irq, void *dev_id) } /** - * try_recover - Try to recovery THC and Device - * @qcdev: Pointer to quicki2c_device structure + * try_recover - Recover callback to recover THC + * @work: pointer to work_struct * * This function is an error handler, called when fatal error happens. - * It try to reset touch device and re-configure THC to recovery - * communication between touch device and THC. - * - * Return: 0 if successful or error code on failure + * It try to reset Touch Device and re-configure THC to recover + * transferring between Device and THC. */ -static int try_recover(struct quicki2c_device *qcdev) +static void try_recover(struct work_struct *work) { - int ret; + struct quicki2c_device *qcdev = container_of(work, struct quicki2c_device, recover_work); - thc_dma_unconfigure(qcdev->thc_hw); + if (pm_runtime_resume_and_get(qcdev->dev)) + return; - ret = thc_dma_configure(qcdev->thc_hw); - if (ret) { - dev_err(qcdev->dev, "Reconfig DMA failed\n"); - return ret; - } + thc_interrupt_enable(qcdev->thc_hw, false); - return 0; + if (thc_rxdma_reset(qcdev->thc_hw)) + qcdev->state = QUICKI2C_DISABLED; + else + thc_interrupt_enable(qcdev->thc_hw, true); + + pm_runtime_put_autosuspend(qcdev->dev); } static int handle_input_report(struct quicki2c_device *qcdev)
@@ -343,11 +343,10 @@ static irqreturn_t quicki2c_irq_thread_handler(int irq, void *dev_id) } exit: - thc_interrupt_enable(qcdev->thc_hw, true); - if (err_recover) - if (try_recover(qcdev)) - qcdev->state = QUICKI2C_DISABLED; + schedule_work(&qcdev->recover_work); + else + thc_interrupt_enable(qcdev->thc_hw, true); pm_runtime_put_autosuspend(qcdev->dev);
@@ -386,6 +385,7 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io qcdev->ddata = ddata; init_waitqueue_head(&qcdev->reset_ack_wq); + INIT_WORK(&qcdev->recover_work, try_recover); /* THC hardware init */ qcdev->thc_hw = thc_dev_init(qcdev->dev, qcdev->mem_addr);
@@ -771,6 +771,8 @@ static void quicki2c_remove(struct pci_dev *pdev) if (!qcdev) return; + cancel_work_sync(&qcdev->recover_work); + quicki2c_hid_remove(qcdev); quicki2c_dma_deinit(qcdev);
@@ -796,6 +798,8 @@ static void quicki2c_shutdown(struct pci_dev *pdev) if (!qcdev) return; + cancel_work_sync(&qcdev->recover_work); + /* Must stop DMA before reboot to avoid DMA entering into unknown state */ quicki2c_dma_deinit(qcdev);
diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
index 61dbdece59a1..aedf85291e60 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h@@ -222,6 +222,8 @@ struct quicki2c_device { wait_queue_head_t reset_ack_wq; bool reset_ack; + struct work_struct recover_work; + u32 i2c_max_frame_size_enable; u32 i2c_max_frame_size; u32 i2c_int_delay_enable;
--
2.43.0