[PATCH 1/2] mailbox: Add power_get/power_put API to mbox_chan_ops

Jason-JH.Lin jason-jh.lin at mediatek.com
Thu Jun 13 21:01:32 PDT 2024


To avoid pm_runtime APIs calling sleep in all the atomic context APIs
in mbox_chan_ops, we add power_get/power_put API to let the controllers
implement them with pm_runtime APIs outside the other atomic context APIs
in mbox_chan_ops.

Signed-off-by: Jason-JH.Lin <jason-jh.lin at mediatek.com>
---
 drivers/mailbox/mailbox.c          | 55 ++++++++++++++++++++++++++++++
 include/linux/mailbox_controller.h | 11 ++++++
 2 files changed, 66 insertions(+)

diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index ebff3baf3045..bafcc7b0c0b8 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -58,6 +58,12 @@ static void msg_submit(struct mbox_chan *chan)
 	void *data;
 	int err = -EBUSY;
 
+	if (chan->mbox->ops->power_get) {
+		err = chan->mbox->ops->power_get(chan);
+		if (err < 0)
+			return;
+	}
+
 	spin_lock_irqsave(&chan->lock, flags);
 
 	if (!chan->msg_count || chan->active_req)
@@ -89,12 +95,16 @@ static void msg_submit(struct mbox_chan *chan)
 		hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
 		spin_unlock_irqrestore(&chan->mbox->poll_hrt_lock, flags);
 	}
+
+	if (chan->mbox->ops->power_put)
+		chan->mbox->ops->power_put(chan);
 }
 
 static void tx_tick(struct mbox_chan *chan, int r)
 {
 	unsigned long flags;
 	void *mssg;
+	int ret;
 
 	spin_lock_irqsave(&chan->lock, flags);
 	mssg = chan->active_req;
@@ -107,10 +117,19 @@ static void tx_tick(struct mbox_chan *chan, int r)
 	if (!mssg)
 		return;
 
+	if (chan->mbox->ops->power_get) {
+		ret = chan->mbox->ops->power_get(chan);
+		if (ret < 0)
+			return;
+	}
+
 	/* Notify the client */
 	if (chan->cl->tx_done)
 		chan->cl->tx_done(chan->cl, mssg, r);
 
+	if (chan->mbox->ops->power_put)
+		chan->mbox->ops->power_put(chan);
+
 	if (r != -ETIME && chan->cl->tx_block)
 		complete(&chan->tx_complete);
 }
@@ -223,9 +242,16 @@ EXPORT_SYMBOL_GPL(mbox_client_txdone);
  */
 bool mbox_client_peek_data(struct mbox_chan *chan)
 {
+	if (chan->mbox->ops->power_get)
+		if (chan->mbox->ops->power_get(chan) < 0)
+			return false;
+
 	if (chan->mbox->ops->peek_data)
 		return chan->mbox->ops->peek_data(chan);
 
+	if (chan->mbox->ops->power_put)
+		chan->mbox->ops->power_put(chan);
+
 	return false;
 }
 EXPORT_SYMBOL_GPL(mbox_client_peek_data);
@@ -310,10 +336,19 @@ int mbox_flush(struct mbox_chan *chan, unsigned long timeout)
 	if (!chan->mbox->ops->flush)
 		return -ENOTSUPP;
 
+	if (chan->mbox->ops->power_get) {
+		ret = chan->mbox->ops->power_get(chan);
+		if (ret < 0)
+			return ret;
+	}
+
 	ret = chan->mbox->ops->flush(chan, timeout);
 	if (ret < 0)
 		tx_tick(chan, ret);
 
+	if (chan->mbox->ops->power_put)
+		chan->mbox->ops->power_put(chan);
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(mbox_flush);
@@ -341,6 +376,12 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
 
 	spin_unlock_irqrestore(&chan->lock, flags);
 
+	if (chan->mbox->ops->power_get) {
+		ret = chan->mbox->ops->power_get(chan);
+		if (ret < 0)
+			return ERR_PTR(ret);
+	}
+
 	if (chan->mbox->ops->startup) {
 		ret = chan->mbox->ops->startup(chan);
 
@@ -441,7 +482,11 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
 	if (ret)
 		chan = ERR_PTR(ret);
 
+	if (chan->mbox->ops->power_put)
+		chan->mbox->ops->power_put(chan);
+
 	mutex_unlock(&con_mutex);
+
 	return chan;
 }
 EXPORT_SYMBOL_GPL(mbox_request_channel);
@@ -485,13 +530,23 @@ EXPORT_SYMBOL_GPL(mbox_request_channel_byname);
 void mbox_free_channel(struct mbox_chan *chan)
 {
 	unsigned long flags;
+	int ret;
 
 	if (!chan || !chan->cl)
 		return;
 
+	if (chan->mbox->ops->power_get) {
+		ret = chan->mbox->ops->power_get(chan);
+		if (ret < 0)
+			return;
+	}
+
 	if (chan->mbox->ops->shutdown)
 		chan->mbox->ops->shutdown(chan);
 
+	if (chan->mbox->ops->power_put)
+		chan->mbox->ops->power_put(chan);
+
 	/* The queued TX requests are simply aborted, no callbacks are made */
 	spin_lock_irqsave(&chan->lock, flags);
 	chan->cl = NULL;
diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
index 6fee33cb52f5..e8f26e7dabfd 100644
--- a/include/linux/mailbox_controller.h
+++ b/include/linux/mailbox_controller.h
@@ -42,6 +42,15 @@ struct mbox_chan;
  *		  Used only if txdone_poll:=true && txdone_irq:=false
  * @peek_data: Atomic check for any received data. Return true if controller
  *		  has some data to push to the client. False otherwise.
+ * @power_get:	Called when the controller need to get the reference to keep
+ *		the power on for the device of mailbox controller. It is
+ *		optional to implement this function with pm_runtime APIs or
+ *		more complicated operation.
+ *		Return 0 is success, otherwise are fail.
+ * @power_put:	Called when the controller need to put the reference to release
+ *		the power for the device of mailbox controller. It is optional
+ *		to implement this function with pm_runtime APIs or more
+ *		complicated operation.
  */
 struct mbox_chan_ops {
 	int (*send_data)(struct mbox_chan *chan, void *data);
@@ -50,6 +59,8 @@ struct mbox_chan_ops {
 	void (*shutdown)(struct mbox_chan *chan);
 	bool (*last_tx_done)(struct mbox_chan *chan);
 	bool (*peek_data)(struct mbox_chan *chan);
+	int (*power_get)(struct mbox_chan *chan);
+	void (*power_put)(struct mbox_chan *chan);
 };
 
 /**
-- 
2.18.0




More information about the linux-arm-kernel mailing list