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>
This commit is contained in:
Zhang Lixu
2025-10-17 10:22:15 +08:00
committed by Jiri Kosina
parent 3cbf6544b0
commit bd1b9a8df5

View File

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