slim: msm: Revert runtime-PM for Slimbus MSM controller
Using runtime-PM for slimbus MSM controller may cause some race
conditions (e.g. suspend callback is not guaranteed to be complete
when client calls pm_runtime_get_sync). Rely on system-wide suspend
resume callbacks till the race conditions are sorted out.
Change-Id: Ie41aa9fd64c437fc7e2f5699439ca78dedb74cde
Signed-off-by: Sagar Dharia <sdharia@codeaurora.org>
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 4a2ad3f..1e4302b 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -21,7 +21,6 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/clk.h>
-#include <linux/pm_runtime.h>
#include <mach/sps.h>
/* Per spec.max 40 bytes per received message */
@@ -45,7 +44,6 @@
#define MSM_SLIM_PERF_SUMM_THRESHOLD 0x8000
#define MSM_SLIM_NCHANS 32
#define MSM_SLIM_NPORTS 24
-#define MSM_SLIM_AUTOSUSPEND MSEC_PER_SEC
/*
* Need enough descriptors to receive present messages from slaves
@@ -82,7 +80,6 @@
#define QC_DEVID_SAT1 0x3
#define QC_DEVID_SAT2 0x4
#define QC_DEVID_PGD 0x5
-#define QC_MSM_DEVS 5
/* Component registers */
enum comp_reg {
@@ -187,12 +184,6 @@
REF_CLK_GEAR = 15,
};
-enum msm_ctrl_state {
- MSM_CTRL_AWAKE,
- MSM_CTRL_SLEEPING,
- MSM_CTRL_ASLEEP,
-};
-
struct msm_slim_sps_bam {
u32 hdl;
void __iomem *base;
@@ -235,12 +226,10 @@
struct mutex tx_lock;
u8 pgdla;
bool use_rx_msgqs;
+ int suspended;
int pipe_b;
struct completion reconf;
bool reconf_busy;
- bool chan_active;
- enum msm_ctrl_state state;
- int numdevs;
};
struct msm_slim_sat {
@@ -461,11 +450,6 @@
* before exiting ISR
*/
mb();
- if (dev->ctrl.sched.usedslots == 0 &&
- dev->state != MSM_CTRL_SLEEPING) {
- dev->chan_active = false;
- pm_runtime_put(dev->dev);
- }
complete(&dev->reconf);
}
pstat = readl_relaxed(dev->base + PGD_PORT_INT_ST_EEn + (16 * dev->ee));
@@ -665,37 +649,17 @@
u8 *puc;
int timeout;
u8 la = txn->la;
- /*
- * Voting for runtime PM: Slimbus has 2 possible use cases:
- * 1. messaging
- * 2. Data channels
- * Messaging case goes through messaging slots and data channels
- * use their own slots
- * This "get" votes for messaging bandwidth
- */
- if (txn->mc < SLIM_MSG_MC_BEGIN_RECONFIGURATION ||
- txn->mc > SLIM_MSG_MC_RECONFIGURE_NOW ||
- dev->state != MSM_CTRL_SLEEPING)
- pm_runtime_get_sync(dev->dev);
mutex_lock(&dev->tx_lock);
- if (dev->state == MSM_CTRL_ASLEEP) {
- dev_err(dev->dev, "runtime or system PM suspended state");
- mutex_unlock(&dev->tx_lock);
- pm_runtime_put(dev->dev);
- return -EBUSY;
- }
if (txn->mt == SLIM_MSG_MT_CORE &&
- txn->mc == SLIM_MSG_MC_BEGIN_RECONFIGURATION) {
- if (dev->reconf_busy) {
+ txn->mc == SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
+ dev->reconf_busy) {
wait_for_completion(&dev->reconf);
dev->reconf_busy = false;
- }
- /* This "get" votes for data channels */
- if (dev->ctrl.sched.usedslots != 0 &&
- !dev->chan_active) {
- dev->chan_active = true;
- pm_runtime_get(dev->dev);
- }
+ }
+ if (dev->suspended) {
+ dev_err(dev->dev, "No transaction in suspended state");
+ mutex_unlock(&dev->tx_lock);
+ return -EBUSY;
}
txn->rl--;
pbuf = msm_get_msg_buf(ctrl, txn->rl);
@@ -704,10 +668,6 @@
if (txn->dt == SLIM_MSG_DEST_ENUMADDR) {
mutex_unlock(&dev->tx_lock);
- if (txn->mc < SLIM_MSG_MC_BEGIN_RECONFIGURATION ||
- txn->mc > SLIM_MSG_MC_RECONFIGURE_NOW ||
- dev->state != MSM_CTRL_SLEEPING)
- pm_runtime_put(dev->dev);
return -EPROTONOSUPPORT;
}
if (txn->mt == SLIM_MSG_MT_CORE && txn->la == 0xFF &&
@@ -755,15 +715,11 @@
*/
dev->pipes[*puc].connected = false;
mutex_unlock(&dev->tx_lock);
- if (dev->state != MSM_CTRL_SLEEPING)
- pm_runtime_put(dev->dev);
return 0;
}
if (dev->err) {
dev_err(dev->dev, "pipe-port connect err:%d", dev->err);
mutex_unlock(&dev->tx_lock);
- if (dev->state != MSM_CTRL_SLEEPING)
- pm_runtime_put(dev->dev);
return dev->err;
}
*(puc) = *(puc) + dev->pipe_b;
@@ -774,37 +730,10 @@
dev->wr_comp = &done;
msm_send_msg_buf(ctrl, pbuf, txn->rl);
timeout = wait_for_completion_timeout(&done, HZ);
-
- if (dev->state == MSM_CTRL_SLEEPING &&
- txn->mc == SLIM_MSG_MC_RECONFIGURE_NOW &&
- txn->mt == SLIM_MSG_MT_CORE && timeout) {
- timeout = wait_for_completion_timeout(&dev->reconf, HZ);
- dev->reconf_busy = false;
- if (timeout) {
- clk_disable(dev->rclk);
- disable_irq(dev->irq);
- dev->state = MSM_CTRL_ASLEEP;
- }
- }
- if (!timeout && dev->state == MSM_CTRL_SLEEPING &&
- txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
- txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW &&
- txn->mt == SLIM_MSG_MT_CORE) {
- dev->reconf_busy = false;
- dev->state = MSM_CTRL_AWAKE;
- dev_err(dev->dev, "clock pause failed");
- mutex_unlock(&dev->tx_lock);
- return -ETIMEDOUT;
- }
-
- mutex_unlock(&dev->tx_lock);
- if (!txn->rbuf && dev->state == MSM_CTRL_AWAKE)
- pm_runtime_put(dev->dev);
-
if (!timeout)
dev_err(dev->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc,
txn->mt);
-
+ mutex_unlock(&dev->tx_lock);
return timeout ? dev->err : -ETIMEDOUT;
}
@@ -834,7 +763,6 @@
static int msm_clk_pause_wakeup(struct slim_controller *ctrl)
{
struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
- enable_irq(dev->irq);
clk_enable(dev->rclk);
writel_relaxed(1, dev->base + FRM_WAKEUP);
/* Make sure framer wakeup write goes through before exiting function */
@@ -849,7 +777,6 @@
* we get the message
*/
usleep_range(5000, 5000);
- dev->state = MSM_CTRL_AWAKE;
return 0;
}
@@ -994,9 +921,6 @@
e_addr[1] == QC_DEVID_PGD &&
e_addr[2] != QC_CHIPID_SL)
dev->pgdla = laddr;
- dev->numdevs++;
- if (!ret && dev->numdevs == QC_MSM_DEVS)
- pm_runtime_enable(dev->dev);
} else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
mc == SLIM_MSG_MC_REPLY_VALUE) {
@@ -1004,7 +928,6 @@
dev_dbg(dev->dev, "tid:%d, len:%d\n", tid, len - 4);
slim_msg_response(&dev->ctrl, &buf[4], tid,
len - 4);
- pm_runtime_put(dev->dev);
} else if (mc == SLIM_MSG_MC_REPORT_INFORMATION) {
u8 l_addr = buf[2];
u16 ele = (u16)buf[4] << 4;
@@ -1057,19 +980,11 @@
for (i = 0; i < 6; i++)
e_addr[i] = buf[7-i];
- pm_runtime_get_sync(dev->dev);
slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr);
sat->satcl.laddr = laddr;
- } else if (mt != SLIM_MSG_MT_CORE &&
- mc != SLIM_MSG_MC_REPORT_PRESENT)
- pm_runtime_get_sync(dev->dev);
+ }
switch (mc) {
case SLIM_MSG_MC_REPORT_PRESENT:
- /* Remove runtime_pm vote once satellite acks */
- if (mt != SLIM_MSG_MT_CORE) {
- pm_runtime_put(dev->dev);
- continue;
- }
/* send a Manager capability msg */
if (sat->sent_capability)
continue;
@@ -1170,11 +1085,8 @@
default:
break;
}
- if (!gen_ack) {
- if (mc != SLIM_MSG_MC_REPORT_PRESENT)
- pm_runtime_put(dev->dev);
+ if (!gen_ack)
continue;
- }
wbuf[0] = tid;
if (!ret)
wbuf[1] = MSM_SAT_SUCCSS;
@@ -1187,7 +1099,6 @@
txn.wbuf = wbuf;
txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
msm_xfer_msg(&dev->ctrl, &txn);
- pm_runtime_put(dev->dev);
}
}
@@ -1791,9 +1702,6 @@
* function
*/
mb();
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_SLIM_AUTOSUSPEND);
- pm_runtime_set_active(&pdev->dev);
dev_dbg(dev->dev, "MSM SB controller is up!\n");
return 0;
@@ -1827,13 +1735,12 @@
struct resource *slew_mem = dev->slew_mem;
struct msm_slim_sat *sat = dev->satd;
slim_remove_device(&sat->satcl);
- pm_runtime_disable(&pdev->dev);
- pm_runtime_set_suspended(&pdev->dev);
kfree(sat->satch);
destroy_workqueue(sat->wq);
kfree(sat);
free_irq(dev->irq, dev);
slim_del_controller(&dev->ctrl);
+ clk_disable(dev->rclk);
clk_put(dev->rclk);
msm_slim_sps_exit(dev);
kthread_stop(dev->rx_msgq_thread);
@@ -1853,78 +1760,79 @@
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
-static int msm_slim_runtime_idle(struct device *device)
+#ifdef CONFIG_PM
+static int msm_slim_suspend(struct device *device)
{
struct platform_device *pdev = to_platform_device(device);
struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
- dev_dbg(device, "pm_runtime: idle...\n");
- pm_runtime_mark_last_busy(dev->dev);
- pm_request_autosuspend(device);
- return -EAGAIN;
-}
-#endif
-
-/*
- * If PM_RUNTIME is not defined, these 2 functions become helper
- * functions to be called from system suspend/resume. So they are not
- * inside ifdef CONFIG_PM_RUNTIME
- */
-static int msm_slim_runtime_suspend(struct device *device)
-{
- struct platform_device *pdev = to_platform_device(device);
- struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
- dev_dbg(device, "pm_runtime: suspending...\n");
- dev->state = MSM_CTRL_SLEEPING;
- return slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
-}
-
-static int msm_slim_runtime_resume(struct device *device)
-{
- struct platform_device *pdev = to_platform_device(device);
- struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
- dev_dbg(device, "pm_runtime: resuming...\n");
+ int ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
+ /* Make sure clock pause goes through */
mutex_lock(&dev->tx_lock);
- if (dev->state == MSM_CTRL_ASLEEP) {
- mutex_unlock(&dev->tx_lock);
- return slim_ctrl_clk_pause(&dev->ctrl, true, 0);
+ if (!ret && dev->reconf_busy) {
+ wait_for_completion(&dev->reconf);
+ dev->reconf_busy = false;
}
mutex_unlock(&dev->tx_lock);
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int msm_slim_suspend(struct device *dev)
-{
- int ret = 0;
- if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
- dev_dbg(dev, "system suspend");
- ret = msm_slim_runtime_suspend(dev);
- }
- if (ret == -EBUSY) {
+ if (!ret) {
+ clk_disable(dev->rclk);
+ disable_irq(dev->irq);
+ dev->suspended = 1;
+ } else if (ret == -EBUSY) {
/*
- * If the clock pause failed due to active channels, there is
- * a possibility that some audio stream is active during suspend
- * We dont want to return suspend failure in that case so that
- * display and relevant components can still go to suspend.
- * If there is some other error, then it should be passed-on
- * to system level suspend
- */
+ * If the clock pause failed due to active channels, there is
+ * a possibility that some audio stream is active during suspend
+ * We dont want to return suspend failure in that case so that
+ * display and relevant components can still go to suspend.
+ * If there is some other error, then it should be passed-on
+ * to system level suspend
+ */
ret = 0;
}
return ret;
}
-static int msm_slim_resume(struct device *dev)
+static int msm_slim_resume(struct device *device)
{
- /* If runtime_pm is enabled, this resume shouldn't do anything */
- if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
- dev_dbg(dev, "system resume");
- return msm_slim_runtime_resume(dev);
+ struct platform_device *pdev = to_platform_device(device);
+ struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+ mutex_lock(&dev->tx_lock);
+ if (dev->suspended) {
+ dev->suspended = 0;
+ mutex_unlock(&dev->tx_lock);
+ enable_irq(dev->irq);
+ return slim_ctrl_clk_pause(&dev->ctrl, true, 0);
}
+ mutex_unlock(&dev->tx_lock);
return 0;
}
-#endif /* CONFIG_PM_SLEEP */
+#else
+#define msm_slim_suspend NULL
+#define msm_slim_resume NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_RUNTIME
+static int msm_slim_runtime_idle(struct device *dev)
+{
+ dev_dbg(dev, "pm_runtime: idle...\n");
+ return 0;
+}
+
+static int msm_slim_runtime_suspend(struct device *dev)
+{
+ dev_dbg(dev, "pm_runtime: suspending...\n");
+ return 0;
+}
+
+static int msm_slim_runtime_resume(struct device *dev)
+{
+ dev_dbg(dev, "pm_runtime: resuming...\n");
+ return 0;
+}
+#else
+#define msm_slim_runtime_idle NULL
+#define msm_slim_runtime_suspend NULL
+#define msm_slim_runtime_resume NULL
+#endif
static const struct dev_pm_ops msm_slim_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index bb30570..3b79129 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -892,6 +892,10 @@
cur = slim_slicecodefromsize(sl);
ec = ((sl | (1 << 3)) | ((msg->start_offset & 0xFFF) << 4));
+ ret = slim_ctrl_clk_pause(ctrl, true, 0);
+ if (ret)
+ return ret;
+
if (wbuf)
mlen += len;
if (rbuf) {
@@ -1123,6 +1127,10 @@
u8 chan = (u8)(chanh & 0xFF);
struct slim_ich *slc = &ctrl->chans[chan];
+ ret = slim_ctrl_clk_pause(ctrl, true, 0);
+ if (ret)
+ return ret;
+
mutex_lock(&ctrl->m_ctrl);
/* Make sure the channel is not already pending reconf. or active */
if (slc->state >= SLIM_CH_PENDING_ACTIVE) {
@@ -1185,8 +1193,11 @@
int slim_disconnect_ports(struct slim_device *sb, u32 *ph, int nph)
{
struct slim_controller *ctrl = sb->ctrl;
- int i;
+ int i, ret;
+ ret = slim_ctrl_clk_pause(ctrl, true, 0);
+ if (ret)
+ return ret;
mutex_lock(&ctrl->m_ctrl);
for (i = 0; i < nph; i++)
@@ -2378,6 +2389,10 @@
u32 segdist;
struct slim_pending_ch *pch;
+ ret = slim_ctrl_clk_pause(ctrl, true, 0);
+ if (ret)
+ return ret;
+
mutex_lock(&ctrl->sched.m_reconf);
mutex_lock(&ctrl->m_ctrl);
ctrl->sched.pending_msgsl += sb->pending_msgsl - sb->cur_msgsl;