From c1ca58f6982bb815c27a4a75f0f430f87b624f66 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Thu, 8 Aug 2019 18:21:11 +0800 Subject: HID: intel-ish-hid: ipc: set NO_D3 flag only when needed Currently, the NO_D3 flag is set in ish_probe(), and cleared in ish_remove(). So even if the system goes into S3, ISH is still in D0i3 state. It makes more sense that put ISH into D3 as system goes into S3 and put ISH into D0i3 as system goes into suspend-to-idle. I remove the NO_D3 setting in ish_probe(), so that ISH can enter D3 state when system enters S3. Only set N0_D3 flag when system enters the suspend-to-idle or platform specified, and clear it when system resume. When the ISH enters D3, the FW will check the DMA bit status. If the DMA bit is set, the FW will reset automatically. So the DMA bit need be clear before putting ISH into D3 state. Signed-off-by: Zhang Lixu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/hid/intel-ish-hid/ipc/pci-ish.c') diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index aa80b4d3b740..89b14d2edd0b 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #define CREATE_TRACE_POINTS @@ -97,6 +98,11 @@ static const struct pci_device_id ish_invalid_pci_ids[] = { {} }; +static inline bool ish_should_enter_d0i3(struct pci_dev *pdev) +{ + return !pm_suspend_via_firmware() || pdev->device == CHV_DEVICE_ID; +} + /** * ish_probe() - PCI driver probe callback * @pdev: pci device @@ -147,7 +153,6 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* mapping IO device memory */ hw->mem_addr = pcim_iomap_table(pdev)[0]; ishtp->pdev = pdev; - pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; /* request and enable interrupt */ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); @@ -184,7 +189,6 @@ static void ish_remove(struct pci_dev *pdev) struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev); ishtp_bus_remove_all_clients(ishtp_dev, false); - pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3; ish_device_disable(ishtp_dev); } @@ -209,6 +213,8 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work) uint32_t fwsts; int ret; + pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3; + /* Get ISH FW status */ fwsts = IPC_GET_ISH_FWSTS(dev->ops->get_fw_status(dev)); @@ -267,6 +273,17 @@ static int __maybe_unused ish_suspend(struct device *device) !dev->suspend_flag, msecs_to_jiffies(25)); + if (ish_should_enter_d0i3(pdev)) { + /* Set the NO_D3 flag, the ISH would enter D0i3 */ + pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; + } else { + /* + * Clear the DMA bit before putting ISH into D3, + * or ISH FW would reset automatically. + */ + ish_disable_dma(dev); + } + return 0; } -- cgit v1.2.3-59-g8ed1b From 2db8edaa88c1208f7346c65041120081e2434d2a Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Thu, 8 Aug 2019 18:21:12 +0800 Subject: HID: intel-ish-hid: ipc: make ish suspend paths clear For suspend-to-idle, send suspend message and set N0_D3 flag to put the ISH into D0i3 state. For suspend-to-mem, disable the DMA bit before ISH entering D3, and NO_D3 flag is cleared by default, then the ISH would enter D3. Signed-off-by: Zhang Lixu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 52 ++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 21 deletions(-) (limited to 'drivers/hid/intel-ish-hid/ipc/pci-ish.c') diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 89b14d2edd0b..35081f2cf781 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -223,6 +223,8 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work) * it means ISH isn't powered off, in this case, send a resume message. */ if (fwsts >= FWSTS_SENSOR_APP_LOADED) { + disable_irq_wake(pdev->irq); + ishtp_send_resume(dev); /* Waiting to get resume response */ @@ -255,27 +257,36 @@ static int __maybe_unused ish_suspend(struct device *device) struct pci_dev *pdev = to_pci_dev(device); struct ishtp_device *dev = pci_get_drvdata(pdev); - enable_irq_wake(pdev->irq); - /* - * If previous suspend hasn't been asnwered then ISH is likely dead, - * don't attempt nested notification - */ - if (dev->suspend_flag) - return 0; - - dev->resume_flag = 0; - dev->suspend_flag = 1; - ishtp_send_suspend(dev); - - /* 25 ms should be enough for live ISH to flush all IPC buf */ - if (dev->suspend_flag) - wait_event_interruptible_timeout(dev->suspend_wait, - !dev->suspend_flag, - msecs_to_jiffies(25)); - if (ish_should_enter_d0i3(pdev)) { - /* Set the NO_D3 flag, the ISH would enter D0i3 */ - pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; + /* + * If previous suspend hasn't been asnwered then ISH is likely + * dead, don't attempt nested notification + */ + if (dev->suspend_flag) + return 0; + + dev->resume_flag = 0; + dev->suspend_flag = 1; + ishtp_send_suspend(dev); + + /* 25 ms should be enough for live ISH to flush all IPC buf */ + if (dev->suspend_flag) + wait_event_interruptible_timeout(dev->suspend_wait, + !dev->suspend_flag, + msecs_to_jiffies(25)); + + if (dev->suspend_flag) { + /* + * It looks like FW halt, clear the DMA bit, and put + * ISH into D3, and FW would reset on resume. + */ + ish_disable_dma(dev); + } else { + /* Set the NO_D3 flag, the ISH would enter D0i3 */ + pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; + + enable_irq_wake(pdev->irq); + } } else { /* * Clear the DMA bit before putting ISH into D3, @@ -304,7 +315,6 @@ static int __maybe_unused ish_resume(struct device *device) ish_resume_device = device; dev->resume_flag = 1; - disable_irq_wake(pdev->irq); schedule_work(&resume_work); return 0; -- cgit v1.2.3-59-g8ed1b From fc19a57dd4834a939b5eef574c61cd4f81af6cf8 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Thu, 8 Aug 2019 18:21:13 +0800 Subject: HID: intel-ish-hid: ipc: check the NO_D3 flag to distinguish resume paths The NO_D3 flag would be set if the ISH enter D0i3 in ish_suspend(), The resume paths can be distinguished by checking the NO_D3 flag. It's more reasonable than checking the FW status. Signed-off-by: Zhang Lixu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 34 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 19 deletions(-) (limited to 'drivers/hid/intel-ish-hid/ipc/pci-ish.c') diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 35081f2cf781..f269852304e5 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -210,19 +210,11 @@ 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; int ret; - pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3; - - /* Get ISH FW status */ - fwsts = IPC_GET_ISH_FWSTS(dev->ops->get_fw_status(dev)); - - /* - * If currently, in ISH FW, sensor app is loaded or beyond that, - * it means ISH isn't powered off, in this case, send a resume message. - */ - if (fwsts >= FWSTS_SENSOR_APP_LOADED) { + /* Check the NO_D3 flag to distinguish the resume paths */ + if (pdev->dev_flags & PCI_DEV_FLAGS_NO_D3) { + pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3; disable_irq_wake(pdev->irq); ishtp_send_resume(dev); @@ -232,16 +224,20 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work) ret = wait_event_interruptible_timeout(dev->resume_wait, !dev->resume_flag, msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS)); - } - /* - * If in ISH FW, sensor app isn't loaded yet, or no resume response. - * That means this platform is not S0ix compatible, or something is - * wrong with ISH FW. So on resume, full reboot of ISH processor will - * happen, so need to go through init sequence again. - */ - if (dev->resume_flag) + /* + * If the flag is not cleared, something is wrong with ISH FW. + * So on resume, need to go through init sequence again. + */ + if (dev->resume_flag) + ish_init(dev); + } else { + /* + * Resume from the D3, full reboot of ISH processor will happen, + * so need to go through init sequence again. + */ ish_init(dev); + } } /** -- cgit v1.2.3-59-g8ed1b