diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish.h b/drivers/hid/intel-ish-hid/ipc/hw-ish.h index 1065692f90e2..ddd8e8e87cfa 100644 --- a/drivers/hid/intel-ish-hid/ipc/hw-ish.h +++ b/drivers/hid/intel-ish-hid/ipc/hw-ish.h @@ -77,5 +77,6 @@ irqreturn_t ish_irq_handler(int irq, void *dev_id); struct ishtp_device *ish_dev_init(struct pci_dev *pdev); int ish_hw_start(struct ishtp_device *dev); void ish_device_disable(struct ishtp_device *dev); +int ish_disable_dma(struct ishtp_device *dev); #endif /* _ISHTP_HW_ISH_H_ */ diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c index 18fe8af89aad..8f8dfdf64833 100644 --- a/drivers/hid/intel-ish-hid/ipc/ipc.c +++ b/drivers/hid/intel-ish-hid/ipc/ipc.c @@ -672,7 +672,7 @@ eoi: * * Return: 0 for success else error code. */ -static int ish_disable_dma(struct ishtp_device *dev) +int ish_disable_dma(struct ishtp_device *dev) { unsigned int dma_delay; 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; }