mailbox: Allow direct registration to a channel
authorElliot Berman <quic_eberman@quicinc.com>
Mon, 10 Apr 2023 16:16:52 +0000 (09:16 -0700)
committerJassi Brar <jaswinder.singh@linaro.org>
Tue, 18 Apr 2023 16:48:55 +0000 (11:48 -0500)
Support virtual mailbox controllers and clients which are not platform
devices or come from the devicetree by allowing them to match client to
channel via some other mechanism.

Tested-by: Sudeep Holla <sudeep.holla@arm.com> (pcc)
Signed-off-by: Elliot Berman <quic_eberman@quicinc.com>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
drivers/mailbox/mailbox.c
include/linux/mailbox_client.h

index 4229b9b..adf36c0 100644 (file)
@@ -317,6 +317,71 @@ int mbox_flush(struct mbox_chan *chan, unsigned long timeout)
 }
 EXPORT_SYMBOL_GPL(mbox_flush);
 
+static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
+{
+       struct device *dev = cl->dev;
+       unsigned long flags;
+       int ret;
+
+       if (chan->cl || !try_module_get(chan->mbox->dev->driver->owner)) {
+               dev_dbg(dev, "%s: mailbox not free\n", __func__);
+               return -EBUSY;
+       }
+
+       spin_lock_irqsave(&chan->lock, flags);
+       chan->msg_free = 0;
+       chan->msg_count = 0;
+       chan->active_req = NULL;
+       chan->cl = cl;
+       init_completion(&chan->tx_complete);
+
+       if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone)
+               chan->txdone_method = TXDONE_BY_ACK;
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       if (chan->mbox->ops->startup) {
+               ret = chan->mbox->ops->startup(chan);
+
+               if (ret) {
+                       dev_err(dev, "Unable to startup the chan (%d)\n", ret);
+                       mbox_free_channel(chan);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * mbox_bind_client - Request a mailbox channel.
+ * @chan: The mailbox channel to bind the client to.
+ * @cl: Identity of the client requesting the channel.
+ *
+ * The Client specifies its requirements and capabilities while asking for
+ * a mailbox channel. It can't be called from atomic context.
+ * The channel is exclusively allocated and can't be used by another
+ * client before the owner calls mbox_free_channel.
+ * After assignment, any packet received on this channel will be
+ * handed over to the client via the 'rx_callback'.
+ * The framework holds reference to the client, so the mbox_client
+ * structure shouldn't be modified until the mbox_free_channel returns.
+ *
+ * Return: 0 if the channel was assigned to the client successfully.
+ *         <0 for request failure.
+ */
+int mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
+{
+       int ret;
+
+       mutex_lock(&con_mutex);
+       ret = __mbox_bind_client(chan, cl);
+       mutex_unlock(&con_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(mbox_bind_client);
+
 /**
  * mbox_request_channel - Request a mailbox channel.
  * @cl: Identity of the client requesting the channel.
@@ -340,7 +405,6 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
        struct mbox_controller *mbox;
        struct of_phandle_args spec;
        struct mbox_chan *chan;
-       unsigned long flags;
        int ret;
 
        if (!dev || !dev->of_node) {
@@ -372,33 +436,9 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
                return chan;
        }
 
-       if (chan->cl || !try_module_get(mbox->dev->driver->owner)) {
-               dev_dbg(dev, "%s: mailbox not free\n", __func__);
-               mutex_unlock(&con_mutex);
-               return ERR_PTR(-EBUSY);
-       }
-
-       spin_lock_irqsave(&chan->lock, flags);
-       chan->msg_free = 0;
-       chan->msg_count = 0;
-       chan->active_req = NULL;
-       chan->cl = cl;
-       init_completion(&chan->tx_complete);
-
-       if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone)
-               chan->txdone_method = TXDONE_BY_ACK;
-
-       spin_unlock_irqrestore(&chan->lock, flags);
-
-       if (chan->mbox->ops->startup) {
-               ret = chan->mbox->ops->startup(chan);
-
-               if (ret) {
-                       dev_err(dev, "Unable to startup the chan (%d)\n", ret);
-                       mbox_free_channel(chan);
-                       chan = ERR_PTR(ret);
-               }
-       }
+       ret = __mbox_bind_client(chan, cl);
+       if (ret)
+               chan = ERR_PTR(ret);
 
        mutex_unlock(&con_mutex);
        return chan;
index 65229a4..7346949 100644 (file)
@@ -37,6 +37,7 @@ struct mbox_client {
        void (*tx_done)(struct mbox_client *cl, void *mssg, int r);
 };
 
+int mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl);
 struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,
                                              const char *name);
 struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);