Split the mailbox irq handling into a primary handler (imx_mu_isr()) and
a threaded handler (imx_mu_isr_th()). The primary handler masks the
interrupt event so the threaded handler can run without raising the
interrupt again.

The goal here is to invoke the mailbox core functions (such as
mbox_chan_received_data(), mbox_chan_txdone()) in preemptible context which is
made possible by using an threaded interrupt handler. This in turn means that
mailbox's client callbacks are invoked in preemptible context, too. This then
allows the mailbox client callback to skip an indirection via a workqueue if
it requries preemptible callback.

As a first step, prepare the logic and move TX handling part.

Reviewed-by: Peng Fan <[email protected]>
Reviewed-by: Mathieu Poirier <[email protected]>
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
 drivers/mailbox/imx-mailbox.c | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index 408cd083c64ee..87acc43cb99c4 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -540,11 +540,31 @@ static void imx_mu_txdb_work(struct work_struct *t)
        mbox_chan_txdone(cp->chan, 0);
 }
 
+static irqreturn_t imx_mu_isr_th(int irq, void *p)
+{
+       struct mbox_chan *chan = p;
+       struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
+       struct imx_mu_con_priv *cp = chan->con_priv;
+
+       switch (cp->type) {
+       case IMX_MU_TYPE_TX:
+               mbox_chan_txdone(chan, 0);
+               break;
+
+       default:
+               dev_warn_ratelimited(priv->dev, "Unhandled channel type %d\n",
+                                    cp->type);
+               return IRQ_NONE;
+       }
+       return IRQ_HANDLED;
+}
+
 static irqreturn_t imx_mu_isr(int irq, void *p)
 {
        struct mbox_chan *chan = p;
        struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
        struct imx_mu_con_priv *cp = chan->con_priv;
+       irqreturn_t ret = IRQ_HANDLED;
        u32 val, ctrl;
 
        switch (cp->type) {
@@ -580,7 +600,7 @@ static irqreturn_t imx_mu_isr(int irq, void *p)
        if ((val == IMX_MU_xSR_TEn(priv->dcfg->type, cp->idx)) &&
            (cp->type == IMX_MU_TYPE_TX)) {
                imx_mu_xcr_rmw(priv, IMX_MU_TCR, 0, 
IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx));
-               mbox_chan_txdone(chan, 0);
+               ret = IRQ_WAKE_THREAD;
        } else if ((val == IMX_MU_xSR_RFn(priv->dcfg->type, cp->idx)) &&
                   (cp->type == IMX_MU_TYPE_RX)) {
                priv->dcfg->rx(priv, cp);
@@ -595,7 +615,7 @@ static irqreturn_t imx_mu_isr(int irq, void *p)
        if (priv->suspend)
                pm_system_wakeup();
 
-       return IRQ_HANDLED;
+       return ret;
 }
 
 static int imx_mu_send_data(struct mbox_chan *chan, void *data)
@@ -630,7 +650,8 @@ static int imx_mu_startup(struct mbox_chan *chan)
        if (!(priv->dcfg->type & IMX_MU_V2_IRQ))
                irq_flag |= IRQF_SHARED;
 
-       ret = request_irq(priv->irq[cp->type], imx_mu_isr, irq_flag, 
cp->irq_desc, chan);
+       ret = request_threaded_irq(priv->irq[cp->type], imx_mu_isr, 
imx_mu_isr_th,
+                                  irq_flag, cp->irq_desc, chan);
        if (ret) {
                dev_err(priv->dev, "Unable to acquire IRQ %d\n", 
priv->irq[cp->type]);
                return ret;

-- 
2.53.0


Reply via email to