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 threaded handler can invoke the actuall callback in
preemtible context.

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

Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
 drivers/mailbox/imx-mailbox.c | 33 ++++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index d1de07cc0ed62..006aa76b74b62 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -81,6 +81,7 @@ struct imx_mu_con_priv {
        struct mbox_chan        *chan;
        struct work_struct      txdb_work;
        bool                    shutdown;
+       bool                    pending;
 };
 
 struct imx_mu_priv {
@@ -539,11 +540,35 @@ 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;
+
+       if (!cp->pending)
+               return IRQ_NONE;
+
+       switch (cp->type) {
+       case IMX_MU_TYPE_TX:
+               cp->pending = false;
+               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) {
@@ -579,7 +604,8 @@ 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);
+               cp->pending = true;
+               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);
@@ -594,7 +620,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)
@@ -629,7 +655,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