From: srinivas.kandagatla@linaro.org
To: Mark Brown <broonie@kernel.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
alsa-devel@alsa-project.org
Cc: Mark Rutland <mark.rutland@arm.com>,
devicetree@vger.kernel.org, Jonathan Corbet <corbet@lwn.net>,
linux-arm-msm@vger.kernel.org, linux-doc@vger.kernel.org,
j.neuschaefer@gmx.net, linux-kernel@vger.kernel.org,
Rob Herring <robh+dt@kernel.org>,
Srinivas Kandagatla <srinivas.kandagatla@linaro.org>,
pombredanne@nexb.com, sdharia@codeaurora.org
Subject: [PATCH v9 07/13] slimbus: Add support for 'clock-pause' feature
Date: Thu, 7 Dec 2017 10:27:14 +0000 [thread overview]
Message-ID: <20171207102720.21071-8-srinivas.kandagatla@linaro.org> (raw)
In-Reply-To: <20171207102720.21071-1-srinivas.kandagatla@linaro.org>
From: Sagar Dharia <sdharia@codeaurora.org>
Per SLIMbus specification, a reconfiguration sequence known as
'clock pause' needs to be broadcast over the bus while entering low-
power mode. Clock-pause is initiated by the controller driver.
To exit clock-pause, controller typically wakes up the framer device.
Since wakeup precedure is controller-specific, framework calls it via
controller's function pointer to invoke it.
Signed-off-by: Sagar Dharia <sdharia@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
drivers/slimbus/Makefile | 2 +-
drivers/slimbus/core.c | 16 ++++++
drivers/slimbus/messaging.c | 35 ++++++++++++-
drivers/slimbus/sched.c | 119 ++++++++++++++++++++++++++++++++++++++++++++
drivers/slimbus/slimbus.h | 53 ++++++++++++++++++++
5 files changed, 223 insertions(+), 2 deletions(-)
create mode 100644 drivers/slimbus/sched.c
diff --git a/drivers/slimbus/Makefile b/drivers/slimbus/Makefile
index 568a14c7be78..cd6833ed521a 100644
--- a/drivers/slimbus/Makefile
+++ b/drivers/slimbus/Makefile
@@ -3,4 +3,4 @@
# Makefile for kernel SLIMbus framework.
#
obj-$(CONFIG_SLIMBUS) += slimbus.o
-slimbus-y := core.o messaging.o
+slimbus-y := core.o messaging.o sched.o
diff --git a/drivers/slimbus/core.c b/drivers/slimbus/core.c
index cd2a47dec635..8b4b6b9f0dbf 100644
--- a/drivers/slimbus/core.c
+++ b/drivers/slimbus/core.c
@@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/idr.h>
#include <linux/of.h>
+#include <linux/pm_runtime.h>
#include <linux/slimbus.h>
#include "slimbus.h"
@@ -216,6 +217,8 @@ int slim_register_controller(struct slim_controller *ctrl)
ida_init(&ctrl->laddr_ida);
idr_init(&ctrl->tid_idr);
mutex_init(&ctrl->lock);
+ mutex_init(&ctrl->sched.m_reconf);
+ init_completion(&ctrl->sched.pause_comp);
dev_dbg(ctrl->dev, "Bus [%s] registered:dev:%p\n",
ctrl->name, ctrl->dev);
@@ -247,6 +250,8 @@ int slim_unregister_controller(struct slim_controller *ctrl)
{
/* Remove all clients */
device_for_each_child(ctrl->dev, NULL, slim_ctrl_remove_device);
+ /* Enter Clock Pause */
+ slim_ctrl_clk_pause(ctrl, false, 0);
ida_simple_remove(&ctrl_ida, ctrl->id);
return 0;
@@ -414,6 +419,14 @@ int slim_device_report_present(struct slim_controller *ctrl,
struct slim_device *sbdev;
int ret;
+ ret = pm_runtime_get_sync(ctrl->dev);
+
+ if (ctrl->sched.clk_state != SLIM_CLK_ACTIVE) {
+ dev_err(ctrl->dev, "slim ctrl not active,state:%d, ret:%d\n",
+ ctrl->sched.clk_state, ret);
+ goto slimbus_not_active;
+ }
+
sbdev = slim_get_device(ctrl, e_addr);
if (IS_ERR(sbdev))
return -ENODEV;
@@ -425,6 +438,9 @@ int slim_device_report_present(struct slim_controller *ctrl,
ret = slim_device_alloc_laddr(sbdev, true);
+slimbus_not_active:
+ pm_runtime_mark_last_busy(ctrl->dev);
+ pm_runtime_put_autosuspend(ctrl->dev);
return ret;
}
EXPORT_SYMBOL_GPL(slim_device_report_present);
diff --git a/drivers/slimbus/messaging.c b/drivers/slimbus/messaging.c
index 42798ff06e85..9f19ee6ed10b 100644
--- a/drivers/slimbus/messaging.c
+++ b/drivers/slimbus/messaging.c
@@ -2,6 +2,7 @@
// Copyright (c) 2011-2017, The Linux Foundation
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include "slimbus.h"
/**
@@ -44,6 +45,10 @@ void slim_msg_response(struct slim_controller *ctrl, u8 *reply, u8 tid, u8 len)
memcpy(msg->rbuf, reply, len);
if (txn->comp)
complete(txn->comp);
+
+ /* Remove runtime-pm vote now that response was received for TID txn */
+ pm_runtime_mark_last_busy(ctrl->dev);
+ pm_runtime_put_autosuspend(ctrl->dev);
}
EXPORT_SYMBOL_GPL(slim_msg_response);
@@ -63,10 +68,29 @@ EXPORT_SYMBOL_GPL(slim_msg_response);
int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn)
{
DECLARE_COMPLETION_ONSTACK(done);
- bool need_tid;
+ bool need_tid = false, clk_pause_msg = false;
unsigned long flags;
int ret, tid, timeout;
+ /*
+ * do not vote for runtime-PM if the transactions are part of clock
+ * pause sequence
+ */
+ if (ctrl->sched.clk_state == SLIM_CLK_ENTERING_PAUSE &&
+ (txn->mt == SLIM_MSG_MT_CORE &&
+ txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
+ txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW))
+ clk_pause_msg = true;
+
+ if (!clk_pause_msg) {
+ ret = pm_runtime_get_sync(ctrl->dev);
+ if (ctrl->sched.clk_state != SLIM_CLK_ACTIVE) {
+ dev_err(ctrl->dev, "ctrl wrong state:%d, ret:%d\n",
+ ctrl->sched.clk_state, ret);
+ goto slim_xfer_err;
+ }
+ }
+
need_tid = slim_tid_txn(txn->mt, txn->mc);
if (need_tid) {
@@ -105,6 +129,15 @@ int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn)
dev_err(ctrl->dev, "Tx:MT:0x%x, MC:0x%x, LA:0x%x failed:%d\n",
txn->mt, txn->mc, txn->la, ret);
+slim_xfer_err:
+ if (!clk_pause_msg && (!need_tid || ret == -ETIMEDOUT)) {
+ /*
+ * remove runtime-pm vote if this was TX only, or
+ * if there was error during this transaction
+ */
+ pm_runtime_mark_last_busy(ctrl->dev);
+ pm_runtime_mark_last_busy(ctrl->dev);
+ }
return ret;
}
diff --git a/drivers/slimbus/sched.c b/drivers/slimbus/sched.c
new file mode 100644
index 000000000000..c7dc646af31e
--- /dev/null
+++ b/drivers/slimbus/sched.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2011-2017, The Linux Foundation
+
+#include <linux/errno.h>
+#include "slimbus.h"
+
+/**
+ * slim_ctrl_clk_pause() - Called by slimbus controller to enter/exit
+ * 'clock pause'
+ * @ctrl: controller requesting bus to be paused or woken up
+ * @wakeup: Wakeup this controller from clock pause.
+ * @restart: Restart time value per spec used for clock pause. This value
+ * isn't used when controller is to be woken up.
+ *
+ * Slimbus specification needs this sequence to turn-off clocks for the bus.
+ * The sequence involves sending 3 broadcast messages (reconfiguration
+ * sequence) to inform all devices on the bus.
+ * To exit clock-pause, controller typically wakes up active framer device.
+ * This API executes clock pause reconfiguration sequence if wakeup is false.
+ * If wakeup is true, controller's wakeup is called.
+ * For entering clock-pause, -EBUSY is returned if a message txn in pending.
+ */
+int slim_ctrl_clk_pause(struct slim_controller *ctrl, bool wakeup, u8 restart)
+{
+ int i, ret = 0;
+ unsigned long flags;
+ struct slim_sched *sched = &ctrl->sched;
+ struct slim_val_inf msg = {0, 0, NULL, NULL};
+
+ DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION,
+ 3, SLIM_LA_MANAGER, &msg);
+
+ if (wakeup == false && restart > SLIM_CLK_UNSPECIFIED)
+ return -EINVAL;
+
+ mutex_lock(&sched->m_reconf);
+ if (wakeup) {
+ if (sched->clk_state == SLIM_CLK_ACTIVE) {
+ mutex_unlock(&sched->m_reconf);
+ return 0;
+ }
+
+ /*
+ * Fine-tune calculation based on clock gear,
+ * message-bandwidth after bandwidth management
+ */
+ ret = wait_for_completion_timeout(&sched->pause_comp,
+ msecs_to_jiffies(100));
+ if (!ret) {
+ mutex_unlock(&sched->m_reconf);
+ pr_err("Previous clock pause did not finish");
+ return -ETIMEDOUT;
+ }
+ ret = 0;
+
+ /*
+ * Slimbus framework will call controller wakeup
+ * Controller should make sure that it sets active framer
+ * out of clock pause
+ */
+ if (sched->clk_state == SLIM_CLK_PAUSED && ctrl->wakeup)
+ ret = ctrl->wakeup(ctrl);
+ if (!ret)
+ sched->clk_state = SLIM_CLK_ACTIVE;
+ mutex_unlock(&sched->m_reconf);
+
+ return ret;
+ }
+
+ /* already paused */
+ if (ctrl->sched.clk_state == SLIM_CLK_PAUSED) {
+ mutex_unlock(&sched->m_reconf);
+ return 0;
+ }
+
+ spin_lock_irqsave(&ctrl->txn_lock, flags);
+ for (i = 0; i < SLIM_MAX_TIDS; i++) {
+ /* Pending response for a message */
+ if (idr_find(&ctrl->tid_idr, i)) {
+ spin_unlock_irqrestore(&ctrl->txn_lock, flags);
+ mutex_unlock(&sched->m_reconf);
+ return -EBUSY;
+ }
+ }
+ spin_unlock_irqrestore(&ctrl->txn_lock, flags);
+
+ sched->clk_state = SLIM_CLK_ENTERING_PAUSE;
+
+ /* clock pause sequence */
+ ret = slim_do_transfer(ctrl, &txn);
+ if (ret)
+ goto clk_pause_ret;
+
+ txn.mc = SLIM_MSG_MC_NEXT_PAUSE_CLOCK;
+ txn.rl = 4;
+ msg.num_bytes = 1;
+ msg.wbuf = &restart;
+ ret = slim_do_transfer(ctrl, &txn);
+ if (ret)
+ goto clk_pause_ret;
+
+ txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW;
+ txn.rl = 3;
+ msg.num_bytes = 1;
+ msg.wbuf = NULL;
+ ret = slim_do_transfer(ctrl, &txn);
+
+clk_pause_ret:
+ if (ret) {
+ sched->clk_state = SLIM_CLK_ACTIVE;
+ } else {
+ sched->clk_state = SLIM_CLK_PAUSED;
+ complete(&sched->pause_comp);
+ }
+ mutex_unlock(&sched->m_reconf);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(slim_ctrl_clk_pause);
diff --git a/drivers/slimbus/slimbus.h b/drivers/slimbus/slimbus.h
index 80c3ec44afbd..e002763e7f6e 100644
--- a/drivers/slimbus/slimbus.h
+++ b/drivers/slimbus/slimbus.h
@@ -12,6 +12,16 @@
/* SLIMbus message types. Related to interpretation of message code. */
#define SLIM_MSG_MT_CORE 0x0
+/* Clock pause Reconfiguration messages */
+#define SLIM_MSG_MC_BEGIN_RECONFIGURATION 0x40
+#define SLIM_MSG_MC_NEXT_PAUSE_CLOCK 0x4A
+#define SLIM_MSG_MC_RECONFIGURE_NOW 0x5F
+
+/* Clock pause values per SLIMbus spec */
+#define SLIM_CLK_FAST 0
+#define SLIM_CLK_CONST_PHASE 1
+#define SLIM_CLK_UNSPECIFIED 2
+
/* Destination type Values */
#define SLIM_MSG_DEST_LOGICALADDR 0
#define SLIM_MSG_DEST_ENUMADDR 1
@@ -78,6 +88,42 @@ struct slim_msg_txn {
#define DEFINE_SLIM_LDEST_TXN(name, mc, rl, la, msg) \
struct slim_msg_txn name = { rl, 0, mc, SLIM_MSG_DEST_LOGICALADDR, 0,\
0, la, msg, }
+
+#define DEFINE_SLIM_BCAST_TXN(name, mc, rl, la, msg) \
+ struct slim_msg_txn name = { rl, 0, mc, SLIM_MSG_DEST_BROADCAST, 0,\
+ 0, la, msg, }
+/**
+ * enum slim_clk_state: SLIMbus controller's clock state used internally for
+ * maintaining current clock state.
+ * @SLIM_CLK_ACTIVE: SLIMbus clock is active
+ * @SLIM_CLK_ENTERING_PAUSE: SLIMbus clock pause sequence is being sent on the
+ * bus. If this succeeds, state changes to SLIM_CLK_PAUSED. If the
+ * transition fails, state changes back to SLIM_CLK_ACTIVE
+ * @SLIM_CLK_PAUSED: SLIMbus controller clock has paused.
+ */
+enum slim_clk_state {
+ SLIM_CLK_ACTIVE,
+ SLIM_CLK_ENTERING_PAUSE,
+ SLIM_CLK_PAUSED,
+};
+
+/**
+ * struct slim_sched: Framework uses this structure internally for scheduling.
+ * @clk_state: Controller's clock state from enum slim_clk_state
+ * @pause_comp: Signals completion of clock pause sequence. This is useful when
+ * client tries to call SLIMbus transaction when controller is entering
+ * clock pause.
+ * @m_reconf: This mutex is held until current reconfiguration (data channel
+ * scheduling, message bandwidth reservation) is done. Message APIs can
+ * use the bus concurrently when this mutex is held since elemental access
+ * messages can be sent on the bus when reconfiguration is in progress.
+ */
+struct slim_sched {
+ enum slim_clk_state clk_state;
+ struct completion pause_comp;
+ struct mutex m_reconf;
+};
+
/**
* struct slim_controller - Controls every instance of SLIMbus
* (similar to 'master' on SPI)
@@ -93,6 +139,7 @@ struct slim_msg_txn {
* @devices: Slim device list
* @tid_idr: tid id allocator
* @txn_lock: Lock to protect table of transactions
+ * @sched: scheduler structure used by the controller
* @xfer_msg: Transfer a message on this controller (this can be a broadcast
* control/status message like data channel setup, or a unicast message
* like value element read/write.
@@ -103,6 +150,9 @@ struct slim_msg_txn {
* address table and get_laddr can be used in that case so that controller
* can do this assignment. Use case is when the master is on the remote
* processor side, who is resposible for allocating laddr.
+ * @wakeup: This function pointer implements controller-specific procedure
+ * to wake it up from clock-pause. Framework will call this to bring
+ * the controller out of clock pause.
*
* 'Manager device' is responsible for device management, bandwidth
* allocation, channel setup, and port associations per channel.
@@ -137,12 +187,14 @@ struct slim_controller {
struct list_head devices;
struct idr tid_idr;
spinlock_t txn_lock;
+ struct slim_sched sched;
int (*xfer_msg)(struct slim_controller *ctrl,
struct slim_msg_txn *tx);
int (*set_laddr)(struct slim_controller *ctrl,
struct slim_eaddr *ea, u8 laddr);
int (*get_laddr)(struct slim_controller *ctrl,
struct slim_eaddr *ea, u8 *laddr);
+ int (*wakeup)(struct slim_controller *ctrl);
};
int slim_device_report_present(struct slim_controller *ctrl,
@@ -152,6 +204,7 @@ int slim_register_controller(struct slim_controller *ctrl);
int slim_unregister_controller(struct slim_controller *ctrl);
void slim_msg_response(struct slim_controller *ctrl, u8 *reply, u8 tid, u8 l);
int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn);
+int slim_ctrl_clk_pause(struct slim_controller *ctrl, bool wakeup, u8 restart);
static inline bool slim_tid_txn(u8 mt, u8 mc)
{
--
2.15.0
next prev parent reply other threads:[~2017-12-07 10:27 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-12-07 10:27 [PATCH v9 00/13] Introduce framework for SLIMbus device driver srinivas.kandagatla
2017-12-07 10:27 ` [PATCH v9 01/13] Documentation: Add SLIMbus summary srinivas.kandagatla
2017-12-07 17:32 ` Jonathan Corbet
2017-12-07 23:22 ` Srinivas Kandagatla
2017-12-08 8:44 ` Vinod Koul
2017-12-08 9:09 ` Srinivas Kandagatla
[not found] ` <138216ca-4351-f895-fae2-0289cf2a3872-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-12-11 23:34 ` Jonathan Corbet
2017-12-07 10:27 ` [PATCH v9 02/13] dt-bindings: Add SLIMbus bindings srinivas.kandagatla
2017-12-07 10:27 ` [PATCH v9 03/13] slimbus: Add SLIMbus bus type srinivas.kandagatla
2017-12-07 10:27 ` [PATCH v9 04/13] slimbus: core: Add slim controllers support srinivas.kandagatla
2017-12-07 10:27 ` [PATCH v9 05/13] slimbus: core: add support to device tree helper srinivas.kandagatla
2017-12-07 10:27 ` [PATCH v9 06/13] slimbus: Add messaging APIs to slimbus framework srinivas.kandagatla
2017-12-07 10:27 ` srinivas.kandagatla [this message]
2017-12-07 10:27 ` [PATCH v9 08/13] regmap: add SLIMbus support srinivas.kandagatla
2017-12-07 10:27 ` [PATCH v9 09/13] slimbus: core: add common defines required for controllers srinivas.kandagatla
[not found] ` <20171207102720.21071-1-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-12-07 10:27 ` [PATCH v9 10/13] dt-bindings: Add qcom slimbus controller bindings srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A
2017-12-07 10:27 ` [PATCH v9 11/13] slimbus: qcom: Add Qualcomm Slimbus controller driver srinivas.kandagatla
2017-12-07 10:27 ` [PATCH v9 12/13] slimbus: qcom: Add runtime-pm support using clock-pause srinivas.kandagatla
2017-12-07 10:27 ` [PATCH v9 13/13] MAINTAINERS: Add SLIMbus maintainer srinivas.kandagatla
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171207102720.21071-8-srinivas.kandagatla@linaro.org \
--to=srinivas.kandagatla@linaro.org \
--cc=alsa-devel@alsa-project.org \
--cc=broonie@kernel.org \
--cc=corbet@lwn.net \
--cc=devicetree@vger.kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=j.neuschaefer@gmx.net \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=pombredanne@nexb.com \
--cc=robh+dt@kernel.org \
--cc=sdharia@codeaurora.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).