aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/intel-ish-hid/ipc/pci-ish.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-09-23 12:18:13 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-23 12:18:13 -0700
commit1ad0bc78948652edc3067b6b49ba31b1598faa4a (patch)
tree08c6262440c87e6241e5fc3732fff5fd3193b60e /drivers/hid/intel-ish-hid/ipc/pci-ish.c
parentMerge tag 'safesetid-bugfix-5.4' of git://github.com/micah-morton/linux (diff)
parentMerge branch 'for-5.4/wacom' into for-linus (diff)
downloadlinux-dev-1ad0bc78948652edc3067b6b49ba31b1598faa4a.tar.xz
linux-dev-1ad0bc78948652edc3067b6b49ba31b1598faa4a.zip
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Jiri Kosina: - syzbot memory corruption fixes for hidraw, Prodikeys, Logitech and Sony drivers from Alan Stern and Roderick Colenbrander - stuck 'fn' key fix for hid-apple from Joao Moreno - proper propagation of EPOLLOUT from hiddev and hidraw, from Fabian Henneke - fixes for handling power management for intel-ish devices with NO_D3 flag set, from Zhang Lixu - extension of supported usage range for customer page, as some Logitech devices are actually making use of it. From Olivier Gay. - hid-multitouch is no longer filtering mice node creation, from Benjamin Tissoires - MobileStudio Pro 13 support, from Ping Cheng - a few other device ID additions and assorted smaller fixes * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (27 commits) HID: core: fix dmesg flooding if report field larger than 32bit HID: core: Add printk_once variants to hid_warn() etc HID: core: reformat and reduce hid_printk macros HID: prodikeys: Fix general protection fault during probe HID: wacom: add new MobileStudio Pro 13 support HID: sony: Fix memory corruption issue on cleanup. HID: i2c-hid: modify quirks for weida's devices HID: apple: Fix stuck function keys when using FN HID: sb0540: add support for Creative SB0540 IR receivers HID: Add quirk for HP X500 PIXART OEM mouse HID: logitech-dj: Fix crash when initial logi_dj_recv_query_paired_devices fails hid-logitech-dj: add the new Lightspeed receiver HID: logitech-dj: add support of the G700(s) receiver HID: multitouch: add support for the Smart Tech panel HID: multitouch: do not filter mice nodes HID: do not call hid_set_drvdata(hdev, NULL) in drivers HID: wacom: do not call hid_set_drvdata(hdev, NULL) HID: logitech: Fix general protection fault caused by Logitech driver HID: hidraw: Fix invalid read in hidraw_ioctl HID: wacom: support named keys on older devices ...
Diffstat (limited to 'drivers/hid/intel-ish-hid/ipc/pci-ish.c')
-rw-r--r--drivers/hid/intel-ish-hid/ipc/pci-ish.c95
1 files changed, 59 insertions, 36 deletions
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
index 279567baca3d..784dcc8c7022 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 <linux/types.h>
#include <linux/pci.h>
#include <linux/sched.h>
+#include <linux/suspend.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#define CREATE_TRACE_POINTS
@@ -98,6 +99,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
@@ -148,7 +154,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);
@@ -185,7 +190,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);
}
@@ -207,17 +211,13 @@ 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;
- /* Get ISH FW status */
- fwsts = IPC_GET_ISH_FWSTS(dev->ops->get_fw_status(dev));
+ /* 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);
- /*
- * 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) {
ishtp_send_resume(dev);
/* Waiting to get resume response */
@@ -225,16 +225,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);
+ }
}
/**
@@ -250,23 +254,43 @@ 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)) {
+ /*
+ * 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,
+ * or ISH FW would reset automatically.
+ */
+ ish_disable_dma(dev);
+ }
return 0;
}
@@ -288,7 +312,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;