diff options
author | Alexander Usyskin <alexander.usyskin@intel.com> | 2014-03-18 16:52:03 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-03 19:20:24 -0400 |
commit | cfe5ab85634b5fdab2c90249517910ea3df63f6a (patch) | |
tree | f36e16edde25360a1a1a480d1792a8af7dcac878 /drivers/misc/mei | |
parent | 180ea05bcedbd67bb22a426bb8d831075727e34a (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.h | 2 | ||||
-rw-r--r-- | drivers/misc/mei/pci-txe.c | 101 |
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 | ||
148 | release_irq: | 154 | release_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 | ||
279 | static 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 | } | ||
294 | static 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 | ||
269 | static 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 | |||
329 | static 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 | ||
356 | static 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 | */ |