Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: intel-ish-hid: Use IPC RESET instead of void message in ish_wakeup()

On ISH power-up, the bootloader enters sleep after preparing to load the
main firmware, waiting for the driver to be ready. When the driver is
ready, it sends a void message to wake up the bootloader and load the main
firmware. The main firmware then sends MNG_RESET_NOTIFY to the driver for
handshake.

This void message-based IPC handshake only works if the main firmware has
not been loaded. During hibernation resume, if the restore kernel has the
ISH driver, the driver wakes up the bootloader to load the main firmware
and perform IPC handshake. However, when switching to the image kernel,
since the main firmware is already loaded, sending a void message in the
.restore() callback does not trigger IPC handshake.

By sending MNG_RESET_NOTIFY (IPC RESET message) in ish_wakeup() instead of
a void message, we can explicitly wake up the bootloader and perform IPC
handshake, regardless of the firmware state. Additionally, since
ish_ipc_reset() already waits for recvd_hw_ready, the redundant wait for
recvd_hw_ready in ish_hw_start() is removed.

The timeout for waiting for HW ready is set to 10 seconds, matching the
original timeout value used in ish_wakeup(), to ensure reliable wakeup on
hardware that requires more time, such as the Lenovo ThinkPad X1 Titanium
Gen 1.

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>

authored by

Zhang Lixu and committed by
Jiri Kosina
507561b0 9e097dc9

+16 -23
+16 -23
drivers/hid/intel-ish-hid/ipc/ipc.c
··· 728 728 * ish_wakeup() - wakeup ishfw from waiting-for-host state 729 729 * @dev: ishtp device pointer 730 730 * 731 - * Set the dma enable bit and send a void message to FW, 731 + * Set the dma enable bit and send a IPC RESET message to FW, 732 732 * it wil wakeup FW from waiting-for-host state. 733 + * 734 + * Return: 0 for success else error code. 733 735 */ 734 - static void ish_wakeup(struct ishtp_device *dev) 736 + static int ish_wakeup(struct ishtp_device *dev) 735 737 { 738 + int ret; 739 + 736 740 /* Set dma enable bit */ 737 741 ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED); 738 742 739 743 /* 740 - * Send 0 IPC message so that ISH FW wakes up if it was already 744 + * Send IPC RESET message so that ISH FW wakes up if it was already 741 745 * asleep. 742 746 */ 743 - ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT); 747 + ret = ish_ipc_reset(dev); 744 748 745 749 /* Flush writes to doorbell and REMAP2 */ 746 750 ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS); 751 + 752 + return ret; 747 753 } 748 754 749 755 /** ··· 798 792 pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr); 799 793 800 794 /* Now we can enable ISH DMA operation and wakeup ISHFW */ 801 - ish_wakeup(dev); 802 - 803 - return 0; 795 + return ish_wakeup(dev); 804 796 } 797 + 798 + #define RECVD_HW_READY_TIMEOUT (10 * HZ) 805 799 806 800 /** 807 801 * _ish_ipc_reset() - IPC reset ··· 837 831 } 838 832 839 833 wait_event_interruptible_timeout(dev->wait_hw_ready, 840 - dev->recvd_hw_ready, 2 * HZ); 834 + dev->recvd_hw_ready, 835 + RECVD_HW_READY_TIMEOUT); 841 836 if (!dev->recvd_hw_ready) { 842 837 dev_err(dev->devc, "Timed out waiting for HW ready\n"); 843 838 rv = -ENODEV; ··· 862 855 set_host_ready(dev); 863 856 864 857 /* After that we can enable ISH DMA operation and wakeup ISHFW */ 865 - ish_wakeup(dev); 866 - 867 - /* wait for FW-initiated reset flow */ 868 - if (!dev->recvd_hw_ready) 869 - wait_event_interruptible_timeout(dev->wait_hw_ready, 870 - dev->recvd_hw_ready, 871 - 10 * HZ); 872 - 873 - if (!dev->recvd_hw_ready) { 874 - dev_err(dev->devc, 875 - "[ishtp-ish]: Timed out waiting for FW-initiated reset\n"); 876 - return -ENODEV; 877 - } 878 - 879 - return 0; 858 + return ish_wakeup(dev); 880 859 } 881 860 882 861 /**