]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
rpmsg: qcom_smd: Access APCS through mailbox framework
authorBjorn Andersson <bjorn.andersson@linaro.org>
Fri, 20 Apr 2018 01:17:57 +0000 (18:17 -0700)
committerBjorn Andersson <bjorn.andersson@linaro.org>
Thu, 26 Apr 2018 00:09:57 +0000 (17:09 -0700)
Attempt to acquire the APCS IPC through the mailbox framework and fall
back to the old syscon based approach, to allow us to move away from
using the syscon.

Reviewed-by: Arun Kumar Neelakantam <aneela@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt
drivers/rpmsg/Kconfig
drivers/rpmsg/qcom_smd.c

index ea1dc75ec9eaca099589114a3c13322c1d193625..234ae2256501b7511976ffe6272d34a5c327c769 100644 (file)
@@ -22,9 +22,15 @@ The edge is described by the following properties:
        Definition: should specify the IRQ used by the remote processor to
                    signal this processor about communication related updates
 
-- qcom,ipc:
+- mboxes:
        Usage: required
        Value type: <prop-encoded-array>
+       Definition: reference to the associated doorbell in APCS, as described
+                   in mailbox/mailbox.txt
+
+- qcom,ipc:
+       Usage: required, unless mboxes is specified
+       Value type: <prop-encoded-array>
        Definition: three entries specifying the outgoing ipc bit used for
                    signaling the remote processor:
                    - phandle to a syscon node representing the apcs registers
index 65a9f6b892f06a9ffc06e93181a84cadefab09d2..9b14090e360399f756b00d2264ff562506444863 100644 (file)
@@ -39,6 +39,7 @@ config RPMSG_QCOM_GLINK_SMEM
 
 config RPMSG_QCOM_SMD
        tristate "Qualcomm Shared Memory Driver (SMD)"
+       depends on MAILBOX
        depends on QCOM_SMEM
        select RPMSG
        help
index 5ce9bf7b897d82da403c489ed69abd3ec5de41d5..b07e9a1a9d229ee495a53014e7768c334dd93c88 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/mailbox_client.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of_irq.h>
@@ -107,6 +108,8 @@ static const struct {
  * @ipc_regmap:                regmap handle holding the outgoing ipc register
  * @ipc_offset:                offset within @ipc_regmap of the register for ipc
  * @ipc_bit:           bit in the register at @ipc_offset of @ipc_regmap
+ * @mbox_client:       mailbox client handle
+ * @mbox_chan:         apcs ipc mailbox channel handle
  * @channels:          list of all channels detected on this edge
  * @channels_lock:     guard for modifications of @channels
  * @allocated:         array of bitmaps representing already allocated channels
@@ -129,6 +132,9 @@ struct qcom_smd_edge {
        int ipc_offset;
        int ipc_bit;
 
+       struct mbox_client mbox_client;
+       struct mbox_chan *mbox_chan;
+
        struct list_head channels;
        spinlock_t channels_lock;
 
@@ -366,7 +372,17 @@ static void qcom_smd_signal_channel(struct qcom_smd_channel *channel)
 {
        struct qcom_smd_edge *edge = channel->edge;
 
-       regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit));
+       if (edge->mbox_chan) {
+               /*
+                * We can ignore a failing mbox_send_message() as the only
+                * possible cause is that the FIFO in the framework is full of
+                * other writes to the same bit.
+                */
+               mbox_send_message(edge->mbox_chan, NULL);
+               mbox_client_txdone(edge->mbox_chan, 0);
+       } else {
+               regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit));
+       }
 }
 
 /*
@@ -1326,27 +1342,37 @@ static int qcom_smd_parse_edge(struct device *dev,
        key = "qcom,remote-pid";
        of_property_read_u32(node, key, &edge->remote_pid);
 
-       syscon_np = of_parse_phandle(node, "qcom,ipc", 0);
-       if (!syscon_np) {
-               dev_err(dev, "no qcom,ipc node\n");
-               return -ENODEV;
-       }
+       edge->mbox_client.dev = dev;
+       edge->mbox_client.knows_txdone = true;
+       edge->mbox_chan = mbox_request_channel(&edge->mbox_client, 0);
+       if (IS_ERR(edge->mbox_chan)) {
+               if (PTR_ERR(edge->mbox_chan) != -ENODEV)
+                       return PTR_ERR(edge->mbox_chan);
 
-       edge->ipc_regmap = syscon_node_to_regmap(syscon_np);
-       if (IS_ERR(edge->ipc_regmap))
-               return PTR_ERR(edge->ipc_regmap);
+               edge->mbox_chan = NULL;
 
-       key = "qcom,ipc";
-       ret = of_property_read_u32_index(node, key, 1, &edge->ipc_offset);
-       if (ret < 0) {
-               dev_err(dev, "no offset in %s\n", key);
-               return -EINVAL;
-       }
+               syscon_np = of_parse_phandle(node, "qcom,ipc", 0);
+               if (!syscon_np) {
+                       dev_err(dev, "no qcom,ipc node\n");
+                       return -ENODEV;
+               }
 
-       ret = of_property_read_u32_index(node, key, 2, &edge->ipc_bit);
-       if (ret < 0) {
-               dev_err(dev, "no bit in %s\n", key);
-               return -EINVAL;
+               edge->ipc_regmap = syscon_node_to_regmap(syscon_np);
+               if (IS_ERR(edge->ipc_regmap))
+                       return PTR_ERR(edge->ipc_regmap);
+
+               key = "qcom,ipc";
+               ret = of_property_read_u32_index(node, key, 1, &edge->ipc_offset);
+               if (ret < 0) {
+                       dev_err(dev, "no offset in %s\n", key);
+                       return -EINVAL;
+               }
+
+               ret = of_property_read_u32_index(node, key, 2, &edge->ipc_bit);
+               if (ret < 0) {
+                       dev_err(dev, "no bit in %s\n", key);
+                       return -EINVAL;
+               }
        }
 
        ret = of_property_read_string(node, "label", &edge->name);
@@ -1453,6 +1479,9 @@ struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent,
        return edge;
 
 unregister_dev:
+       if (!IS_ERR_OR_NULL(edge->mbox_chan))
+               mbox_free_channel(edge->mbox_chan);
+
        device_unregister(&edge->dev);
        return ERR_PTR(ret);
 }
@@ -1481,6 +1510,7 @@ int qcom_smd_unregister_edge(struct qcom_smd_edge *edge)
        if (ret)
                dev_warn(&edge->dev, "can't remove smd device: %d\n", ret);
 
+       mbox_free_channel(edge->mbox_chan);
        device_unregister(&edge->dev);
 
        return 0;