]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mailbox: imx: Start splitting the IRQ handler in primary and threaded handler
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>
Wed, 17 Jun 2026 06:55:31 +0000 (08:55 +0200)
committerJassi Brar <jassisinghbrar@gmail.com>
Sun, 21 Jun 2026 02:18:38 +0000 (21:18 -0500)
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 <peng.fan@nxp.com>
Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Jassi Brar <jassisinghbrar@gmail.com>
drivers/mailbox/imx-mailbox.c

index 408cd083c64ee646f24007b3a5b1c91800c17bbc..87acc43cb99c45aecb17ac618b7deb76f5a49738 100644 (file)
@@ -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;