Skip to content

Commit 979d859

Browse files
author
Jiri Kosina
committed
Merge branch 'for-5.4/ish' into for-linus
- fixes for handling power management for intel-ish devices with NO_D3 flag set, from Zhang Lixu Signed-off-by: Jiri Kosina <[email protected]>
2 parents 98656d5 + fc19a57 commit 979d859

File tree

3 files changed

+61
-37
lines changed

3 files changed

+61
-37
lines changed

drivers/hid/intel-ish-hid/ipc/hw-ish.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,6 @@ irqreturn_t ish_irq_handler(int irq, void *dev_id);
7878
struct ishtp_device *ish_dev_init(struct pci_dev *pdev);
7979
int ish_hw_start(struct ishtp_device *dev);
8080
void ish_device_disable(struct ishtp_device *dev);
81+
int ish_disable_dma(struct ishtp_device *dev);
8182

8283
#endif /* _ISHTP_HW_ISH_H_ */

drivers/hid/intel-ish-hid/ipc/ipc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ irqreturn_t ish_irq_handler(int irq, void *dev_id)
672672
*
673673
* Return: 0 for success else error code.
674674
*/
675-
static int ish_disable_dma(struct ishtp_device *dev)
675+
int ish_disable_dma(struct ishtp_device *dev)
676676
{
677677
unsigned int dma_delay;
678678

drivers/hid/intel-ish-hid/ipc/pci-ish.c

Lines changed: 59 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/types.h>
1515
#include <linux/pci.h>
1616
#include <linux/sched.h>
17+
#include <linux/suspend.h>
1718
#include <linux/interrupt.h>
1819
#include <linux/workqueue.h>
1920
#define CREATE_TRACE_POINTS
@@ -98,6 +99,11 @@ static const struct pci_device_id ish_invalid_pci_ids[] = {
9899
{}
99100
};
100101

102+
static inline bool ish_should_enter_d0i3(struct pci_dev *pdev)
103+
{
104+
return !pm_suspend_via_firmware() || pdev->device == CHV_DEVICE_ID;
105+
}
106+
101107
/**
102108
* ish_probe() - PCI driver probe callback
103109
* @pdev: pci device
@@ -148,7 +154,6 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
148154
/* mapping IO device memory */
149155
hw->mem_addr = pcim_iomap_table(pdev)[0];
150156
ishtp->pdev = pdev;
151-
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
152157

153158
/* request and enable interrupt */
154159
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
@@ -185,7 +190,6 @@ static void ish_remove(struct pci_dev *pdev)
185190
struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
186191

187192
ishtp_bus_remove_all_clients(ishtp_dev, false);
188-
pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3;
189193
ish_device_disable(ishtp_dev);
190194
}
191195

@@ -207,34 +211,34 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
207211
{
208212
struct pci_dev *pdev = to_pci_dev(ish_resume_device);
209213
struct ishtp_device *dev = pci_get_drvdata(pdev);
210-
uint32_t fwsts;
211214
int ret;
212215

213-
/* Get ISH FW status */
214-
fwsts = IPC_GET_ISH_FWSTS(dev->ops->get_fw_status(dev));
216+
/* Check the NO_D3 flag to distinguish the resume paths */
217+
if (pdev->dev_flags & PCI_DEV_FLAGS_NO_D3) {
218+
pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3;
219+
disable_irq_wake(pdev->irq);
215220

216-
/*
217-
* If currently, in ISH FW, sensor app is loaded or beyond that,
218-
* it means ISH isn't powered off, in this case, send a resume message.
219-
*/
220-
if (fwsts >= FWSTS_SENSOR_APP_LOADED) {
221221
ishtp_send_resume(dev);
222222

223223
/* Waiting to get resume response */
224224
if (dev->resume_flag)
225225
ret = wait_event_interruptible_timeout(dev->resume_wait,
226226
!dev->resume_flag,
227227
msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
228-
}
229228

230-
/*
231-
* If in ISH FW, sensor app isn't loaded yet, or no resume response.
232-
* That means this platform is not S0ix compatible, or something is
233-
* wrong with ISH FW. So on resume, full reboot of ISH processor will
234-
* happen, so need to go through init sequence again.
235-
*/
236-
if (dev->resume_flag)
229+
/*
230+
* If the flag is not cleared, something is wrong with ISH FW.
231+
* So on resume, need to go through init sequence again.
232+
*/
233+
if (dev->resume_flag)
234+
ish_init(dev);
235+
} else {
236+
/*
237+
* Resume from the D3, full reboot of ISH processor will happen,
238+
* so need to go through init sequence again.
239+
*/
237240
ish_init(dev);
241+
}
238242
}
239243

240244
/**
@@ -250,23 +254,43 @@ static int __maybe_unused ish_suspend(struct device *device)
250254
struct pci_dev *pdev = to_pci_dev(device);
251255
struct ishtp_device *dev = pci_get_drvdata(pdev);
252256

253-
enable_irq_wake(pdev->irq);
254-
/*
255-
* If previous suspend hasn't been asnwered then ISH is likely dead,
256-
* don't attempt nested notification
257-
*/
258-
if (dev->suspend_flag)
259-
return 0;
260-
261-
dev->resume_flag = 0;
262-
dev->suspend_flag = 1;
263-
ishtp_send_suspend(dev);
264-
265-
/* 25 ms should be enough for live ISH to flush all IPC buf */
266-
if (dev->suspend_flag)
267-
wait_event_interruptible_timeout(dev->suspend_wait,
268-
!dev->suspend_flag,
269-
msecs_to_jiffies(25));
257+
if (ish_should_enter_d0i3(pdev)) {
258+
/*
259+
* If previous suspend hasn't been asnwered then ISH is likely
260+
* dead, don't attempt nested notification
261+
*/
262+
if (dev->suspend_flag)
263+
return 0;
264+
265+
dev->resume_flag = 0;
266+
dev->suspend_flag = 1;
267+
ishtp_send_suspend(dev);
268+
269+
/* 25 ms should be enough for live ISH to flush all IPC buf */
270+
if (dev->suspend_flag)
271+
wait_event_interruptible_timeout(dev->suspend_wait,
272+
!dev->suspend_flag,
273+
msecs_to_jiffies(25));
274+
275+
if (dev->suspend_flag) {
276+
/*
277+
* It looks like FW halt, clear the DMA bit, and put
278+
* ISH into D3, and FW would reset on resume.
279+
*/
280+
ish_disable_dma(dev);
281+
} else {
282+
/* Set the NO_D3 flag, the ISH would enter D0i3 */
283+
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
284+
285+
enable_irq_wake(pdev->irq);
286+
}
287+
} else {
288+
/*
289+
* Clear the DMA bit before putting ISH into D3,
290+
* or ISH FW would reset automatically.
291+
*/
292+
ish_disable_dma(dev);
293+
}
270294

271295
return 0;
272296
}
@@ -288,7 +312,6 @@ static int __maybe_unused ish_resume(struct device *device)
288312
ish_resume_device = device;
289313
dev->resume_flag = 1;
290314

291-
disable_irq_wake(pdev->irq);
292315
schedule_work(&resume_work);
293316

294317
return 0;

0 commit comments

Comments
 (0)