aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/remoteproc/qcom_sysmon.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-03-14 09:00:06 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-14 09:00:06 -0700
commit2f194646fecaa9fd4607b670ee9ef84d9ed04566 (patch)
tree5012f3fc7232f509102ee6a3007997043e987390 /drivers/remoteproc/qcom_sysmon.c
parentMerge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux (diff)
parentremoteproc: fix for "dma-mapping: remove the DMA_MEMORY_EXCLUSIVE flag" (diff)
downloadlinux-dev-2f194646fecaa9fd4607b670ee9ef84d9ed04566.tar.xz
linux-dev-2f194646fecaa9fd4607b670ee9ef84d9ed04566.zip
Merge tag 'rproc-v5.1' of git://github.com/andersson/remoteproc
Pull remoteproc updates from Bjorn Andersson: "This contains the last patches in Loic's remoteproc resource table handling changes, a number of updates to documentation, support for invoking the crash handler (for testing purposes), a fix for the handling of virtio devices during recovery, performance state votes in Qualcomm modem driver, support for specifying board specific firmware path for Qualcomm modem driver and improved support for graceful shutdown of Qualcomm remoteprocs" * tag 'rproc-v5.1' of git://github.com/andersson/remoteproc: (33 commits) remoteproc: fix for "dma-mapping: remove the DMA_MEMORY_EXCLUSIVE flag" remoteproc: fix rproc_check_carveout_da() returned error and comments remoteproc: fix trace buffer va initialization remoteproc: fix rproc_alloc_carveout() for rproc with iommu domain remoteproc: add warning on resource table cast remoteproc: fix rproc_alloc_carveout() bad variable cast remoteproc: fix rproc_da_to_va in case of unallocated carveout remoteproc: correct rproc_mem_entry_init() comments remoteproc: fix recovery procedure rpmsg: virtio: change header file sort style rpmsg: virtio: allocate buffer from parent remoteproc: st: add reserved memory support remoteproc: create vdev subdevice with specific dma memory pool remoteproc: q6v5_adsp: Remove voting for lpass_aon clock dt-binding: remoteproc: Remove lpass_aon clock from adsp pil clock list remoteproc: q6v5-mss: Active powerdomain for SDM845 remoteproc: q6v5-mss: Vote for rpmh power domains remoteproc: qcom: Add support for parsing fw dt bindings remoteproc: qcom_q6v5: don't auto boot remote processor remoteproc: qcom: Wait for shutdown-ack/ind on sysmon shutdown ...
Diffstat (limited to 'drivers/remoteproc/qcom_sysmon.c')
-rw-r--r--drivers/remoteproc/qcom_sysmon.c82
1 files changed, 78 insertions, 4 deletions
diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c
index e976a602b015..c231314eab66 100644
--- a/drivers/remoteproc/qcom_sysmon.c
+++ b/drivers/remoteproc/qcom_sysmon.c
@@ -6,8 +6,9 @@
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/slab.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/notifier.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/remoteproc/qcom_rproc.h>
@@ -25,6 +26,7 @@ struct qcom_sysmon {
const char *name;
+ int shutdown_irq;
int ssctl_version;
int ssctl_instance;
@@ -34,6 +36,8 @@ struct qcom_sysmon {
struct rpmsg_endpoint *ept;
struct completion comp;
+ struct completion ind_comp;
+ struct completion shutdown_comp;
struct mutex lock;
bool ssr_ack;
@@ -137,6 +141,7 @@ static int sysmon_callback(struct rpmsg_device *rpdev, void *data, int count,
}
#define SSCTL_SHUTDOWN_REQ 0x21
+#define SSCTL_SHUTDOWN_READY_IND 0x21
#define SSCTL_SUBSYS_EVENT_REQ 0x23
#define SSCTL_MAX_MSG_LEN 7
@@ -252,6 +257,29 @@ static struct qmi_elem_info ssctl_subsys_event_resp_ei[] = {
{}
};
+static struct qmi_elem_info ssctl_shutdown_ind_ei[] = {
+ {}
+};
+
+static void sysmon_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn, const void *data)
+{
+ struct qcom_sysmon *sysmon = container_of(qmi, struct qcom_sysmon, qmi);
+
+ complete(&sysmon->ind_comp);
+}
+
+static struct qmi_msg_handler qmi_indication_handler[] = {
+ {
+ .type = QMI_INDICATION,
+ .msg_id = SSCTL_SHUTDOWN_READY_IND,
+ .ei = ssctl_shutdown_ind_ei,
+ .decoded_size = 0,
+ .fn = sysmon_ind_cb
+ },
+ {}
+};
+
/**
* ssctl_request_shutdown() - request shutdown via SSCTL QMI service
* @sysmon: sysmon context
@@ -262,6 +290,8 @@ static void ssctl_request_shutdown(struct qcom_sysmon *sysmon)
struct qmi_txn txn;
int ret;
+ reinit_completion(&sysmon->ind_comp);
+ reinit_completion(&sysmon->shutdown_comp);
ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_shutdown_resp_ei, &resp);
if (ret < 0) {
dev_err(sysmon->dev, "failed to allocate QMI txn\n");
@@ -283,6 +313,17 @@ static void ssctl_request_shutdown(struct qcom_sysmon *sysmon)
dev_err(sysmon->dev, "shutdown request failed\n");
else
dev_dbg(sysmon->dev, "shutdown request completed\n");
+
+ if (sysmon->shutdown_irq > 0) {
+ ret = wait_for_completion_timeout(&sysmon->shutdown_comp,
+ 10 * HZ);
+ if (!ret) {
+ ret = try_wait_for_completion(&sysmon->ind_comp);
+ if (!ret)
+ dev_err(sysmon->dev,
+ "timeout waiting for shutdown ack\n");
+ }
+ }
}
/**
@@ -432,6 +473,15 @@ static int sysmon_notify(struct notifier_block *nb, unsigned long event,
return NOTIFY_DONE;
}
+static irqreturn_t sysmon_shutdown_interrupt(int irq, void *data)
+{
+ struct qcom_sysmon *sysmon = data;
+
+ complete(&sysmon->shutdown_comp);
+
+ return IRQ_HANDLED;
+}
+
/**
* qcom_add_sysmon_subdev() - create a sysmon subdev for the given remoteproc
* @rproc: rproc context to associate the subdev with
@@ -449,7 +499,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
sysmon = kzalloc(sizeof(*sysmon), GFP_KERNEL);
if (!sysmon)
- return NULL;
+ return ERR_PTR(-ENOMEM);
sysmon->dev = rproc->dev.parent;
sysmon->rproc = rproc;
@@ -458,13 +508,37 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
sysmon->ssctl_instance = ssctl_instance;
init_completion(&sysmon->comp);
+ init_completion(&sysmon->ind_comp);
+ init_completion(&sysmon->shutdown_comp);
mutex_init(&sysmon->lock);
- ret = qmi_handle_init(&sysmon->qmi, SSCTL_MAX_MSG_LEN, &ssctl_ops, NULL);
+ sysmon->shutdown_irq = of_irq_get_byname(sysmon->dev->of_node,
+ "shutdown-ack");
+ if (sysmon->shutdown_irq < 0) {
+ if (sysmon->shutdown_irq != -ENODATA) {
+ dev_err(sysmon->dev,
+ "failed to retrieve shutdown-ack IRQ\n");
+ return ERR_PTR(sysmon->shutdown_irq);
+ }
+ } else {
+ ret = devm_request_threaded_irq(sysmon->dev,
+ sysmon->shutdown_irq,
+ NULL, sysmon_shutdown_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "q6v5 shutdown-ack", sysmon);
+ if (ret) {
+ dev_err(sysmon->dev,
+ "failed to acquire shutdown-ack IRQ\n");
+ return ERR_PTR(ret);
+ }
+ }
+
+ ret = qmi_handle_init(&sysmon->qmi, SSCTL_MAX_MSG_LEN, &ssctl_ops,
+ qmi_indication_handler);
if (ret < 0) {
dev_err(sysmon->dev, "failed to initialize qmi handle\n");
kfree(sysmon);
- return NULL;
+ return ERR_PTR(ret);
}
qmi_add_lookup(&sysmon->qmi, 43, 0, 0);