summaryrefslogtreecommitdiff
path: root/drivers/rpmsg/qcom_glink_rpm.c
diff options
context:
space:
mode:
authorBjorn Andersson <quic_bjorande@quicinc.com>2023-02-13 18:52:13 +0300
committerBjorn Andersson <andersson@kernel.org>2023-02-14 19:19:38 +0300
commitf424d1cbe8c7ef78a4b639502fa9904c4198387b (patch)
tree874bfe240d4927f02e629e17b676f302147efa2a /drivers/rpmsg/qcom_glink_rpm.c
parent178c3af447f92c58d5b1153df2cd02b755c083c8 (diff)
downloadlinux-f424d1cbe8c7ef78a4b639502fa9904c4198387b.tar.xz
rpmsg: glink: Move irq and mbox handling to transports
Not all GLINK transports uses an interrupt and a mailbox instance. The interrupt for RPM needs to be IRQF_NOSUSPEND, while it seems reasonable for the SMEM interrupt to use irq_set_wake. The glink struct device is constructed in the SMEM and RPM drivers but torn down in the core driver. Move the interrupt and kick handling into the SMEM and RPM driver, to improve this and facilitate further improvements. Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com> Reviewed-by: Chris Lew <quic_clew@quicinc.com> Signed-off-by: Bjorn Andersson <andersson@kernel.org> Link: https://lore.kernel.org/r/20230213155215.1237059-5-quic_bjorande@quicinc.com
Diffstat (limited to 'drivers/rpmsg/qcom_glink_rpm.c')
-rw-r--r--drivers/rpmsg/qcom_glink_rpm.c50
1 files changed, 49 insertions, 1 deletions
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 6443843df6ca..5179f834a10f 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/rpmsg.h>
@@ -56,6 +57,11 @@ struct glink_rpm_pipe {
struct glink_rpm {
struct qcom_glink *glink;
+ int irq;
+
+ struct mbox_client mbox_client;
+ struct mbox_chan *mbox_chan;
+
struct glink_rpm_pipe rx_pipe;
struct glink_rpm_pipe tx_pipe;
};
@@ -186,6 +192,24 @@ static void glink_rpm_tx_write(struct qcom_glink_pipe *glink_pipe,
writel(head, pipe->head);
}
+static void glink_rpm_tx_kick(struct qcom_glink_pipe *glink_pipe)
+{
+ struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
+ struct glink_rpm *rpm = container_of(pipe, struct glink_rpm, tx_pipe);
+
+ mbox_send_message(rpm->mbox_chan, NULL);
+ mbox_client_txdone(rpm->mbox_chan, 0);
+}
+
+static irqreturn_t qcom_glink_rpm_intr(int irq, void *data)
+{
+ struct glink_rpm *rpm = data;
+
+ qcom_glink_native_rx(rpm->glink);
+
+ return IRQ_HANDLED;
+}
+
static int glink_rpm_parse_toc(struct device *dev,
void __iomem *msg_ram,
size_t msg_ram_size,
@@ -292,12 +316,28 @@ static int glink_rpm_probe(struct platform_device *pdev)
if (ret)
return ret;
+ rpm->irq = of_irq_get(dev->of_node, 0);
+ ret = devm_request_irq(dev, rpm->irq, qcom_glink_rpm_intr,
+ IRQF_NO_SUSPEND | IRQF_NO_AUTOEN,
+ "glink-rpm", rpm);
+ if (ret) {
+ dev_err(dev, "failed to request IRQ\n");
+ return ret;
+ }
+
+ rpm->mbox_client.dev = dev;
+ rpm->mbox_client.knows_txdone = true;
+ rpm->mbox_chan = mbox_request_channel(&rpm->mbox_client, 0);
+ if (IS_ERR(rpm->mbox_chan))
+ return dev_err_probe(dev, PTR_ERR(rpm->mbox_chan), "failed to acquire IPC channel\n");
+
/* Pipe specific accessors */
rpm->rx_pipe.native.avail = glink_rpm_rx_avail;
rpm->rx_pipe.native.peak = glink_rpm_rx_peak;
rpm->rx_pipe.native.advance = glink_rpm_rx_advance;
rpm->tx_pipe.native.avail = glink_rpm_tx_avail;
rpm->tx_pipe.native.write = glink_rpm_tx_write;
+ rpm->tx_pipe.native.kick = glink_rpm_tx_kick;
writel(0, rpm->tx_pipe.head);
writel(0, rpm->rx_pipe.tail);
@@ -307,13 +347,17 @@ static int glink_rpm_probe(struct platform_device *pdev)
&rpm->rx_pipe.native,
&rpm->tx_pipe.native,
true);
- if (IS_ERR(glink))
+ if (IS_ERR(glink)) {
+ mbox_free_channel(rpm->mbox_chan);
return PTR_ERR(glink);
+ }
rpm->glink = glink;
platform_set_drvdata(pdev, rpm);
+ enable_irq(rpm->irq);
+
return 0;
}
@@ -322,8 +366,12 @@ static int glink_rpm_remove(struct platform_device *pdev)
struct glink_rpm *rpm = platform_get_drvdata(pdev);
struct qcom_glink *glink = rpm->glink;
+ disable_irq(rpm->irq);
+
qcom_glink_native_remove(glink);
+ mbox_free_channel(rpm->mbox_chan);
+
return 0;
}