From 9e430a6e88080f520ff9fa6393e3f86d1a6aaa64 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Mon, 5 Aug 2019 17:31:42 -0700 Subject: [PATCH 1/2] soc: qcom: Add snapshot of MSM QMP debugfs client This snapshot is taken as of msm-4.19 'commit ("Merge "icnss: Skip removing WLAN host driver during recovery"")'. In addition, update copyright. Change-Id: If2810d0e21f21dd26c5e9202728dc8b9a8e3c59c Signed-off-by: Chris Lew --- drivers/soc/qcom/Kconfig | 9 ++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/qmp-debugfs-client.c | 114 ++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 drivers/soc/qcom/qmp-debugfs-client.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 3f8c6cdd9cb7..34449875fb6a 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -229,4 +229,13 @@ config QCOM_SECURE_BUFFER memory buffers. This ensures that only the correct clients can use this memory and no unauthorized access is made to the buffer. + +config QMP_DEBUGFS_CLIENT + bool "Debugfs Client to communicate with AOP using QMP protocol" + depends on DEBUG_FS + help + This options enables a driver which allows clients to send messages + to Alway On processor using QMP transport. Users can echo a message + into an exposed debugfs node to send to AOP. The driver expects the + passed in string argument to be formatted correctly for AOP to read. endmenu diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 3f9232d4d6c7..cce65a5925a4 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_QCOM_LAHAINA_LLCC) += llcc-lahaina.o obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o +obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o diff --git a/drivers/soc/qcom/qmp-debugfs-client.c b/drivers/soc/qcom/qmp-debugfs-client.c new file mode 100644 index 000000000000..35ce693a0da2 --- /dev/null +++ b/drivers/soc/qcom/qmp-debugfs-client.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_MSG_SIZE 96 /* Imposed by the remote*/ + +struct qmp_debugfs_data { + struct qmp_pkt pkt; + char buf[MAX_MSG_SIZE + 1]; +}; + +static struct qmp_debugfs_data data_pkt[MBOX_TX_QUEUE_LEN]; +static struct mbox_chan *chan; +static struct mbox_client *cl; + +static DEFINE_MUTEX(qmp_debugfs_mutex); + +static ssize_t aop_msg_write(struct file *file, const char __user *userstr, + size_t len, loff_t *pos) +{ + static int count; + int rc; + + if (!len || (len > MAX_MSG_SIZE)) + return len; + + mutex_lock(&qmp_debugfs_mutex); + + if (count >= MBOX_TX_QUEUE_LEN) + count = 0; + + memset(&(data_pkt[count]), 0, sizeof(data_pkt[count])); + rc = copy_from_user(data_pkt[count].buf, userstr, len); + if (rc) { + pr_err("%s copy from user failed, rc=%d\n", __func__, rc); + mutex_unlock(&qmp_debugfs_mutex); + return len; + } + + /* + * Controller expects a 4 byte aligned buffer + */ + data_pkt[count].pkt.size = (len + 0x3) & ~0x3; + data_pkt[count].pkt.data = data_pkt[count].buf; + + if (mbox_send_message(chan, &(data_pkt[count].pkt)) < 0) + pr_err("Failed to send qmp request\n"); + else + count++; + + mutex_unlock(&qmp_debugfs_mutex); + return len; +} + +static const struct file_operations aop_msg_fops = { + .write = aop_msg_write, +}; + +static int qmp_msg_probe(struct platform_device *pdev) +{ + struct dentry *file; + + cl = devm_kzalloc(&pdev->dev, sizeof(*cl), GFP_KERNEL); + if (!cl) + return -ENOMEM; + + cl->dev = &pdev->dev; + cl->tx_block = true; + cl->tx_tout = 1000; + cl->knows_txdone = false; + + chan = mbox_request_channel(cl, 0); + if (IS_ERR(chan)) { + dev_err(&pdev->dev, "Failed to mbox channel\n"); + return PTR_ERR(chan); + } + + file = debugfs_create_file("aop_send_message", 0220, NULL, NULL, + &aop_msg_fops); + if (!file) + goto err; + return 0; +err: + mbox_free_channel(chan); + chan = NULL; + return -ENOMEM; +} + +static const struct of_device_id aop_qmp_match_tbl[] = { + {.compatible = "qcom,debugfs-qmp-client"}, + {}, +}; + +static struct platform_driver aop_qmp_msg_driver = { + .probe = qmp_msg_probe, + .driver = { + .name = "debugfs-qmp-client", + .owner = THIS_MODULE, + .suppress_bind_attrs = true, + .of_match_table = aop_qmp_match_tbl, + }, +}; +builtin_platform_driver(aop_qmp_msg_driver); From 36d1eee8b0c531cd0106809df6ed91a138ddc10a Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Fri, 8 Dec 2017 19:36:13 +0000 Subject: [PATCH 2/2] drivers: mailbox: fix race resulting in multiple message submission The mailbox sends a request to the controller and the tx_done callback received for that request clears the active_req pointer. The callback sends the next request in the queue, if there is one. When a controller is busy and cannot accept any more requests until the interrupt is cleared, it would return -EAGAIN. The mailbox controller must unlock its spinlock and retry again. Change-Id: Id58c7365be8c6bfc7f90fe9445c88c1246d2d7f8 Signed-off-by: Lina Iyer --- drivers/mailbox/mailbox.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 0b821a5b2db8..9301cacc7305 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -50,7 +50,7 @@ static int add_to_rbuf(struct mbox_chan *chan, void *mssg) return idx; } -static void msg_submit(struct mbox_chan *chan) +static int __msg_submit(struct mbox_chan *chan) { unsigned count, idx; unsigned long flags; @@ -82,6 +82,24 @@ static void msg_submit(struct mbox_chan *chan) exit: spin_unlock_irqrestore(&chan->lock, flags); + return err; +} + +static void msg_submit(struct mbox_chan *chan) +{ + int err = 0; + + /* + * If the controller returns -EAGAIN, then it means, our spinlock + * here is preventing the controller from receiving its interrupt, + * that would help clear the controller channels that are currently + * blocked waiting on the interrupt response. + * Retry again. + */ + do { + err = __msg_submit(chan); + } while (err == -EAGAIN); + if (!err && (chan->txdone_method & TXDONE_BY_POLL)) /* kick start the timer immediately to avoid delays */ hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);