summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2014-03-18 22:52:04 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-03 19:20:24 -0400
commit04bb139a071fef549892718f8965a7c61b1924e0 (patch)
tree3200b716befdaae434220de06efecb59b5db0f60
parentcfe5ab85634b5fdab2c90249517910ea3df63f6a (diff)
mei: use runtime pm in write and read flow
Take rpm token on operation start to initiate rpm resume if needed. Mark last busy time, release token and advice rpm framework to try to autosuspend on operation end. 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>
-rw-r--r--drivers/misc/mei/client.c84
1 files changed, 71 insertions, 13 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 8c078b808cd..9273e89e6a1 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -18,6 +18,7 @@
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/delay.h>
+#include <linux/pm_runtime.h>
#include <linux/mei.h>
@@ -415,6 +416,10 @@ void mei_host_client_init(struct work_struct *work)
dev->reset_count = 0;
mutex_unlock(&dev->device_lock);
+
+ pm_runtime_mark_last_busy(&dev->pdev->dev);
+ dev_dbg(&dev->pdev->dev, "rpm: autosuspend\n");
+ pm_runtime_autosuspend(&dev->pdev->dev);
}
/**
@@ -425,6 +430,12 @@ void mei_host_client_init(struct work_struct *work)
*/
bool mei_hbuf_acquire(struct mei_device *dev)
{
+ if (mei_pg_state(dev) == MEI_PG_ON ||
+ dev->pg_event == MEI_PG_EVENT_WAIT) {
+ dev_dbg(&dev->pdev->dev, "device is in pg\n");
+ return false;
+ }
+
if (!dev->hbuf_is_ready) {
dev_dbg(&dev->pdev->dev, "hbuf is not ready\n");
return false;
@@ -460,9 +471,18 @@ int mei_cl_disconnect(struct mei_cl *cl)
if (cl->state != MEI_FILE_DISCONNECTING)
return 0;
+ rets = pm_runtime_get(&dev->pdev->dev);
+ if (rets < 0 && rets != -EINPROGRESS) {
+ pm_runtime_put_noidle(&dev->pdev->dev);
+ cl_err(dev, cl, "rpm: get failed %d\n", rets);
+ return rets;
+ }
+
cb = mei_io_cb_init(cl, NULL);
- if (!cb)
- return -ENOMEM;
+ if (!cb) {
+ rets = -ENOMEM;
+ goto free;
+ }
cb->fop_type = MEI_FOP_CLOSE;
if (mei_hbuf_acquire(dev)) {
@@ -494,8 +514,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
cl_err(dev, cl, "wrong status client disconnect.\n");
if (err)
- cl_dbg(dev, cl, "wait failed disconnect err=%08x\n",
- err);
+ cl_dbg(dev, cl, "wait failed disconnect err=%d\n", err);
cl_err(dev, cl, "failed to disconnect from FW client.\n");
}
@@ -503,6 +522,10 @@ int mei_cl_disconnect(struct mei_cl *cl)
mei_io_list_flush(&dev->ctrl_rd_list, cl);
mei_io_list_flush(&dev->ctrl_wr_list, cl);
free:
+ cl_dbg(dev, cl, "rpm: autosuspend\n");
+ pm_runtime_mark_last_busy(&dev->pdev->dev);
+ pm_runtime_put_autosuspend(&dev->pdev->dev);
+
mei_io_cb_free(cb);
return rets;
}
@@ -557,6 +580,13 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
dev = cl->dev;
+ rets = pm_runtime_get(&dev->pdev->dev);
+ if (rets < 0 && rets != -EINPROGRESS) {
+ pm_runtime_put_noidle(&dev->pdev->dev);
+ cl_err(dev, cl, "rpm: get failed %d\n", rets);
+ return rets;
+ }
+
cb = mei_io_cb_init(cl, file);
if (!cb) {
rets = -ENOMEM;
@@ -596,6 +626,10 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
rets = cl->status;
out:
+ cl_dbg(dev, cl, "rpm: autosuspend\n");
+ pm_runtime_mark_last_busy(&dev->pdev->dev);
+ pm_runtime_put_autosuspend(&dev->pdev->dev);
+
mei_io_cb_free(cb);
return rets;
}
@@ -713,23 +747,32 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
return -ENOTTY;
}
+ rets = pm_runtime_get(&dev->pdev->dev);
+ if (rets < 0 && rets != -EINPROGRESS) {
+ pm_runtime_put_noidle(&dev->pdev->dev);
+ cl_err(dev, cl, "rpm: get failed %d\n", rets);
+ return rets;
+ }
+
cb = mei_io_cb_init(cl, NULL);
- if (!cb)
- return -ENOMEM;
+ if (!cb) {
+ rets = -ENOMEM;
+ goto out;
+ }
/* always allocate at least client max message */
length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length);
rets = mei_io_cb_alloc_resp_buf(cb, length);
if (rets)
- goto err;
+ goto out;
cb->fop_type = MEI_FOP_READ;
if (mei_hbuf_acquire(dev)) {
if (mei_hbm_cl_flow_control_req(dev, cl)) {
- cl_err(dev, cl, "flow control send failed\n");
rets = -ENODEV;
- goto err;
+ goto out;
}
+
list_add_tail(&cb->list, &dev->read_list.list);
} else {
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
@@ -737,9 +780,14 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
cl->read_cb = cb;
- return rets;
-err:
- mei_io_cb_free(cb);
+out:
+ cl_dbg(dev, cl, "rpm: autosuspend\n");
+ pm_runtime_mark_last_busy(&dev->pdev->dev);
+ pm_runtime_put_autosuspend(&dev->pdev->dev);
+
+ if (rets)
+ mei_io_cb_free(cb);
+
return rets;
}
@@ -776,7 +824,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
return rets;
if (rets == 0) {
- cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
+ cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
return 0;
}
@@ -856,6 +904,12 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size);
+ rets = pm_runtime_get(&dev->pdev->dev);
+ if (rets < 0 && rets != -EINPROGRESS) {
+ pm_runtime_put_noidle(&dev->pdev->dev);
+ cl_err(dev, cl, "rpm: get failed %d\n", rets);
+ return rets;
+ }
cb->fop_type = MEI_FOP_WRITE;
cb->buf_idx = 0;
@@ -926,6 +980,10 @@ out:
rets = buf->size;
err:
+ cl_dbg(dev, cl, "rpm: autosuspend\n");
+ pm_runtime_mark_last_busy(&dev->pdev->dev);
+ pm_runtime_put_autosuspend(&dev->pdev->dev);
+
return rets;
}