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

