aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mei
diff options
context:
space:
mode:
authorAlexander Usyskin <alexander.usyskin@intel.com>2014-03-18 16:52:03 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-03 19:20:24 -0400
commitcfe5ab85634b5fdab2c90249517910ea3df63f6a (patch)
treef36e16edde25360a1a1a480d1792a8af7dcac878 /drivers/misc/mei
parent180ea05bcedbd67bb22a426bb8d831075727e34a (diff)
mei: txe: add runtime pm framework
Add runtime pm framework for TXE devices. The runtime pm handlers are used to run txe power gating isolation protocol. Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mei')
-rw-r--r--drivers/misc/mei/hw-txe.h2
-rw-r--r--drivers/misc/mei/pci-txe.c101
2 files changed, 99 insertions, 4 deletions
diff --git a/drivers/misc/mei/hw-txe.h b/drivers/misc/mei/hw-txe.h
index 799f9f25f424..e8dd2d165c25 100644
--- a/drivers/misc/mei/hw-txe.h
+++ b/drivers/misc/mei/hw-txe.h
@@ -22,6 +22,8 @@
22#include "hw.h" 22#include "hw.h"
23#include "hw-txe-regs.h" 23#include "hw-txe-regs.h"
24 24
25#define MEI_TXI_RPM_TIMEOUT 500 /* ms */
26
25/* Flatten Hierarchy interrupt cause */ 27/* Flatten Hierarchy interrupt cause */
26#define TXE_INTR_READINESS_BIT 0 /* HISR_INT_0_STS */ 28#define TXE_INTR_READINESS_BIT 0 /* HISR_INT_0_STS */
27#define TXE_INTR_READINESS HISR_INT_0_STS 29#define TXE_INTR_READINESS HISR_INT_0_STS
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
index ad3adb009a1e..31d86e76fb7f 100644
--- a/drivers/misc/mei/pci-txe.c
+++ b/drivers/misc/mei/pci-txe.c
@@ -27,6 +27,7 @@
27#include <linux/jiffies.h> 27#include <linux/jiffies.h>
28#include <linux/interrupt.h> 28#include <linux/interrupt.h>
29#include <linux/workqueue.h> 29#include <linux/workqueue.h>
30#include <linux/pm_runtime.h>
30 31
31#include <linux/mei.h> 32#include <linux/mei.h>
32 33
@@ -137,12 +138,17 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
137 goto release_irq; 138 goto release_irq;
138 } 139 }
139 140
141 pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT);
142 pm_runtime_use_autosuspend(&pdev->dev);
143
140 err = mei_register(dev); 144 err = mei_register(dev);
141 if (err) 145 if (err)
142 goto release_irq; 146 goto release_irq;
143 147
144 pci_set_drvdata(pdev, dev); 148 pci_set_drvdata(pdev, dev);
145 149
150 pm_runtime_put_noidle(&pdev->dev);
151
146 return 0; 152 return 0;
147 153
148release_irq: 154release_irq:
@@ -187,6 +193,8 @@ static void mei_txe_remove(struct pci_dev *pdev)
187 return; 193 return;
188 } 194 }
189 195
196 pm_runtime_get_noresume(&pdev->dev);
197
190 hw = to_txe_hw(dev); 198 hw = to_txe_hw(dev);
191 199
192 mei_stop(dev); 200 mei_stop(dev);
@@ -265,15 +273,100 @@ static int mei_txe_pci_resume(struct device *device)
265 273
266 return err; 274 return err;
267} 275}
276#endif /* CONFIG_PM_SLEEP */
277
278#ifdef CONFIG_PM_RUNTIME
279static int mei_txe_pm_runtime_idle(struct device *device)
280{
281 struct pci_dev *pdev = to_pci_dev(device);
282 struct mei_device *dev;
283
284 dev_dbg(&pdev->dev, "rpm: txe: runtime_idle\n");
285
286 dev = pci_get_drvdata(pdev);
287 if (!dev)
288 return -ENODEV;
289 if (mei_write_is_idle(dev))
290 pm_schedule_suspend(device, MEI_TXI_RPM_TIMEOUT * 2);
291
292 return -EBUSY;
293}
294static int mei_txe_pm_runtime_suspend(struct device *device)
295{
296 struct pci_dev *pdev = to_pci_dev(device);
297 struct mei_device *dev;
298 int ret;
299
300 dev_dbg(&pdev->dev, "rpm: txe: runtime suspend\n");
301
302 dev = pci_get_drvdata(pdev);
303 if (!dev)
304 return -ENODEV;
268 305
269static SIMPLE_DEV_PM_OPS(mei_txe_pm_ops, 306 mutex_lock(&dev->device_lock);
270 mei_txe_pci_suspend, 307
271 mei_txe_pci_resume); 308 if (mei_write_is_idle(dev))
309 ret = mei_txe_aliveness_set_sync(dev, 0);
310 else
311 ret = -EAGAIN;
312
313 /*
314 * If everything is okay we're about to enter PCI low
315 * power state (D3) therefor we need to disable the
316 * interrupts towards host.
317 * However if device is not wakeable we do not enter
318 * D-low state and we need to keep the interrupt kicking
319 */
320 if (!ret && pci_dev_run_wake(pdev))
321 mei_disable_interrupts(dev);
322
323 dev_dbg(&pdev->dev, "rpm: txe: runtime suspend ret=%d\n", ret);
324
325 mutex_unlock(&dev->device_lock);
326 return ret;
327}
328
329static int mei_txe_pm_runtime_resume(struct device *device)
330{
331 struct pci_dev *pdev = to_pci_dev(device);
332 struct mei_device *dev;
333 int ret;
334
335 dev_dbg(&pdev->dev, "rpm: txe: runtime resume\n");
336
337 dev = pci_get_drvdata(pdev);
338 if (!dev)
339 return -ENODEV;
340
341 mutex_lock(&dev->device_lock);
342
343 mei_enable_interrupts(dev);
344
345 ret = mei_txe_aliveness_set_sync(dev, 1);
346
347 mutex_unlock(&dev->device_lock);
348
349 dev_dbg(&pdev->dev, "rpm: txe: runtime resume ret = %d\n", ret);
350
351 return ret;
352}
353#endif /* CONFIG_PM_RUNTIME */
354
355#ifdef CONFIG_PM
356static const struct dev_pm_ops mei_txe_pm_ops = {
357 SET_SYSTEM_SLEEP_PM_OPS(mei_txe_pci_suspend,
358 mei_txe_pci_resume)
359 SET_RUNTIME_PM_OPS(
360 mei_txe_pm_runtime_suspend,
361 mei_txe_pm_runtime_resume,
362 mei_txe_pm_runtime_idle)
363};
272 364
273#define MEI_TXE_PM_OPS (&mei_txe_pm_ops) 365#define MEI_TXE_PM_OPS (&mei_txe_pm_ops)
274#else 366#else
275#define MEI_TXE_PM_OPS NULL 367#define MEI_TXE_PM_OPS NULL
276#endif /* CONFIG_PM_SLEEP */ 368#endif /* CONFIG_PM */
369
277/* 370/*
278 * PCI driver structure 371 * PCI driver structure
279 */ 372 */