diff options
| author | Zhang Lixu <lixu.zhang@intel.com> | 2025-10-17 10:22:15 +0800 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.com> | 2025-10-17 17:47:53 +0200 |
| commit | bd1b9a8df598882c69403ee83ba2903b45f9d607 (patch) | |
| tree | e252f29df8dc5396e07c2d5399ba91bb60988704 | |
| parent | 3cbf6544b0af61e8f9201f2c4c82fdaf2b5f3dd3 (diff) | |
HID: intel-ish-ipc: Reset clients state on resume from D3
When ISH resumes from D3, the connection between ishtp clients and firmware
is lost. The ish_resume() function schedules resume_work asynchronously to
re-initiate the connection and then returns immediately. This can cause a
race where the upper-layer ishtp client driver's .resume() may execute
before the connection is fully restored, leaving the client in a stale
connected state. If the client sends messages during this window, the
firmware cannot respond.
To avoid this, reset the ishtp clients' state before returning from
ish_resume() if ISH is resuming from D3.
Signed-off-by: Zhang Lixu <lixu.zhang@intel.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
| -rw-r--r-- | drivers/hid/intel-ish-hid/ipc/pci-ish.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index b748ac6fbfdc..e4499c83c62e 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -147,6 +147,12 @@ static inline bool ish_should_enter_d0i3(struct pci_dev *pdev) static inline bool ish_should_leave_d0i3(struct pci_dev *pdev) { + struct ishtp_device *dev = pci_get_drvdata(pdev); + u32 fwsts = dev->ops->get_fw_status(dev); + + if (dev->suspend_flag || !IPC_IS_ISH_ILUP(fwsts)) + return false; + return !pm_resume_via_firmware() || pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV; } @@ -277,10 +283,8 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work) { struct pci_dev *pdev = to_pci_dev(ish_resume_device); struct ishtp_device *dev = pci_get_drvdata(pdev); - uint32_t fwsts = dev->ops->get_fw_status(dev); - if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag - && IPC_IS_ISH_ILUP(fwsts)) { + if (ish_should_leave_d0i3(pdev)) { if (device_may_wakeup(&pdev->dev)) disable_irq_wake(pdev->irq); @@ -384,6 +388,10 @@ static int __maybe_unused ish_resume(struct device *device) ish_resume_device = device; dev->resume_flag = 1; + /* If ISH resume from D3, reset ishtp clients before return */ + if (!ish_should_leave_d0i3(pdev)) + ishtp_reset_handler(dev); + queue_work(dev->unbound_wq, &resume_work); return 0; |
