diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2014-03-18 16:52:02 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-03 19:20:24 -0400 |
commit | 180ea05bcedbd67bb22a426bb8d831075727e34a (patch) | |
tree | 05e5918348bc422a5df912204b6f8c36f44c3e13 /drivers/misc/mei | |
parent | a532bbedc85ff3b834ba81e49163a3f543be1775 (diff) |
mei: me: add runtime pm framework
Add runtime pm framework for ME devices.
The runtime pm handlers are used to run
me power gating isolation protocol
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mei')
-rw-r--r-- | drivers/misc/mei/hbm.c | 8 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me.h | 2 | ||||
-rw-r--r-- | drivers/misc/mei/pci-me.c | 92 |
3 files changed, 100 insertions, 2 deletions
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index a725365e2150..b9a4bb5921f1 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/wait.h> | 20 | #include <linux/wait.h> |
21 | #include <linux/mei.h> | 21 | #include <linux/mei.h> |
22 | #include <linux/pm_runtime.h> | ||
22 | 23 | ||
23 | #include "mei_dev.h" | 24 | #include "mei_dev.h" |
24 | #include "hbm.h" | 25 | #include "hbm.h" |
@@ -742,6 +743,13 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
742 | dev->pg_event = MEI_PG_EVENT_RECEIVED; | 743 | dev->pg_event = MEI_PG_EVENT_RECEIVED; |
743 | if (waitqueue_active(&dev->wait_pg)) | 744 | if (waitqueue_active(&dev->wait_pg)) |
744 | wake_up(&dev->wait_pg); | 745 | wake_up(&dev->wait_pg); |
746 | else | ||
747 | /* | ||
748 | * If the driver is not waiting on this then | ||
749 | * this is HW initiated exit from PG. | ||
750 | * Start runtime pm resume sequence to exit from PG. | ||
751 | */ | ||
752 | pm_request_resume(&dev->pdev->dev); | ||
745 | break; | 753 | break; |
746 | 754 | ||
747 | case HOST_CLIENT_PROPERTIES_RES_CMD: | 755 | case HOST_CLIENT_PROPERTIES_RES_CMD: |
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h index 8b412820cc66..0a75ab85b3a2 100644 --- a/drivers/misc/mei/hw-me.h +++ b/drivers/misc/mei/hw-me.h | |||
@@ -24,6 +24,8 @@ | |||
24 | #include "mei_dev.h" | 24 | #include "mei_dev.h" |
25 | #include "client.h" | 25 | #include "client.h" |
26 | 26 | ||
27 | #define MEI_ME_RPM_TIMEOUT 500 /* ms */ | ||
28 | |||
27 | struct mei_me_hw { | 29 | struct mei_me_hw { |
28 | void __iomem *mem_addr; | 30 | void __iomem *mem_addr; |
29 | /* | 31 | /* |
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 95889e2e31ff..fcbf270c2c2a 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #include <linux/interrupt.h> | 33 | #include <linux/interrupt.h> |
34 | #include <linux/miscdevice.h> | 34 | #include <linux/miscdevice.h> |
35 | 35 | ||
36 | #include <linux/pm_runtime.h> | ||
37 | |||
36 | #include <linux/mei.h> | 38 | #include <linux/mei.h> |
37 | 39 | ||
38 | #include "mei_dev.h" | 40 | #include "mei_dev.h" |
@@ -212,6 +214,9 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
212 | goto release_irq; | 214 | goto release_irq; |
213 | } | 215 | } |
214 | 216 | ||
217 | pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_ME_RPM_TIMEOUT); | ||
218 | pm_runtime_use_autosuspend(&pdev->dev); | ||
219 | |||
215 | err = mei_register(dev); | 220 | err = mei_register(dev); |
216 | if (err) | 221 | if (err) |
217 | goto release_irq; | 222 | goto release_irq; |
@@ -220,6 +225,9 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
220 | 225 | ||
221 | schedule_delayed_work(&dev->timer_work, HZ); | 226 | schedule_delayed_work(&dev->timer_work, HZ); |
222 | 227 | ||
228 | if (mei_pg_is_enabled(dev)) | ||
229 | pm_runtime_put_noidle(&pdev->dev); | ||
230 | |||
223 | dev_dbg(&pdev->dev, "initialization successful.\n"); | 231 | dev_dbg(&pdev->dev, "initialization successful.\n"); |
224 | 232 | ||
225 | return 0; | 233 | return 0; |
@@ -259,6 +267,9 @@ static void mei_me_remove(struct pci_dev *pdev) | |||
259 | if (!dev) | 267 | if (!dev) |
260 | return; | 268 | return; |
261 | 269 | ||
270 | if (mei_pg_is_enabled(dev)) | ||
271 | pm_runtime_get_noresume(&pdev->dev); | ||
272 | |||
262 | hw = to_me_hw(dev); | 273 | hw = to_me_hw(dev); |
263 | 274 | ||
264 | 275 | ||
@@ -343,12 +354,89 @@ static int mei_me_pci_resume(struct device *device) | |||
343 | 354 | ||
344 | return 0; | 355 | return 0; |
345 | } | 356 | } |
357 | #endif /* CONFIG_PM_SLEEP */ | ||
358 | |||
359 | #ifdef CONFIG_PM_RUNTIME | ||
360 | static int mei_me_pm_runtime_idle(struct device *device) | ||
361 | { | ||
362 | struct pci_dev *pdev = to_pci_dev(device); | ||
363 | struct mei_device *dev; | ||
364 | |||
365 | dev_dbg(&pdev->dev, "rpm: me: runtime_idle\n"); | ||
366 | |||
367 | dev = pci_get_drvdata(pdev); | ||
368 | if (!dev) | ||
369 | return -ENODEV; | ||
370 | if (mei_write_is_idle(dev)) | ||
371 | pm_schedule_suspend(device, MEI_ME_RPM_TIMEOUT * 2); | ||
372 | |||
373 | return -EBUSY; | ||
374 | } | ||
375 | |||
376 | static int mei_me_pm_runtime_suspend(struct device *device) | ||
377 | { | ||
378 | struct pci_dev *pdev = to_pci_dev(device); | ||
379 | struct mei_device *dev; | ||
380 | int ret; | ||
381 | |||
382 | dev_dbg(&pdev->dev, "rpm: me: runtime suspend\n"); | ||
383 | |||
384 | dev = pci_get_drvdata(pdev); | ||
385 | if (!dev) | ||
386 | return -ENODEV; | ||
387 | |||
388 | mutex_lock(&dev->device_lock); | ||
389 | |||
390 | if (mei_write_is_idle(dev)) | ||
391 | ret = mei_me_pg_set_sync(dev); | ||
392 | else | ||
393 | ret = -EAGAIN; | ||
394 | |||
395 | mutex_unlock(&dev->device_lock); | ||
396 | |||
397 | dev_dbg(&pdev->dev, "rpm: me: runtime suspend ret=%d\n", ret); | ||
398 | |||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | static int mei_me_pm_runtime_resume(struct device *device) | ||
403 | { | ||
404 | struct pci_dev *pdev = to_pci_dev(device); | ||
405 | struct mei_device *dev; | ||
406 | int ret; | ||
407 | |||
408 | dev_dbg(&pdev->dev, "rpm: me: runtime resume\n"); | ||
409 | |||
410 | dev = pci_get_drvdata(pdev); | ||
411 | if (!dev) | ||
412 | return -ENODEV; | ||
413 | |||
414 | mutex_lock(&dev->device_lock); | ||
415 | |||
416 | ret = mei_me_pg_unset_sync(dev); | ||
417 | |||
418 | mutex_unlock(&dev->device_lock); | ||
419 | |||
420 | dev_dbg(&pdev->dev, "rpm: me: runtime resume ret = %d\n", ret); | ||
421 | |||
422 | return ret; | ||
423 | } | ||
424 | #endif /* CONFIG_PM_RUNTIME */ | ||
425 | |||
426 | #ifdef CONFIG_PM | ||
427 | static const struct dev_pm_ops mei_me_pm_ops = { | ||
428 | SET_SYSTEM_SLEEP_PM_OPS(mei_me_pci_suspend, | ||
429 | mei_me_pci_resume) | ||
430 | SET_RUNTIME_PM_OPS( | ||
431 | mei_me_pm_runtime_suspend, | ||
432 | mei_me_pm_runtime_resume, | ||
433 | mei_me_pm_runtime_idle) | ||
434 | }; | ||
346 | 435 | ||
347 | static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume); | ||
348 | #define MEI_ME_PM_OPS (&mei_me_pm_ops) | 436 | #define MEI_ME_PM_OPS (&mei_me_pm_ops) |
349 | #else | 437 | #else |
350 | #define MEI_ME_PM_OPS NULL | 438 | #define MEI_ME_PM_OPS NULL |
351 | #endif /* CONFIG_PM_SLEEP */ | 439 | #endif /* CONFIG_PM */ |
352 | /* | 440 | /* |
353 | * PCI driver structure | 441 | * PCI driver structure |
354 | */ | 442 | */ |