static irqreturn_t mhuv2_sender_interrupt()

in arm_mhuv2.c [537:617]


static irqreturn_t mhuv2_sender_interrupt(int irq, void *data)
{
	struct mhuv2 *mhu = data;
	struct device *dev = mhu->mbox.dev;
	struct mhuv2_mbox_chan_priv *priv;
	struct mbox_chan *chan;
	unsigned long flags;
	int i, found = 0;
	u32 stat;

	chan = get_irq_chan_comb(mhu, mhu->send->chcomb_int_st);
	if (IS_ERR(chan)) {
		dev_warn(dev, "Failed to find channel for the Tx interrupt\n");
		return IRQ_NONE;
	}
	priv = chan->con_priv;

	if (!IS_PROTOCOL_DOORBELL(priv)) {
		writel_relaxed(1, &mhu->send->ch_wn[priv->ch_wn_idx + priv->windows - 1].int_clr);

		if (chan->cl) {
			mbox_chan_txdone(chan, 0);
			return IRQ_HANDLED;
		}

		dev_warn(dev, "Tx interrupt Received on channel (%u) not currently attached to a mailbox client\n",
			 priv->ch_wn_idx);
		return IRQ_NONE;
	}

	/* Clear the interrupt first, so we don't miss any doorbell later */
	writel_relaxed(1, &mhu->send->ch_wn[priv->ch_wn_idx].int_clr);

	/*
	 * In Doorbell mode, make sure no new transitions happen while the
	 * interrupt handler is trying to find the finished doorbell tx
	 * operations, else we may think few of the transfers were complete
	 * before they actually were.
	 */
	spin_lock_irqsave(&mhu->doorbell_pending_lock, flags);

	/*
	 * In case of doorbell mode, the first channel of the window is returned
	 * by get_irq_chan_comb(). Find all the pending channels here.
	 */
	stat = readl_relaxed(&mhu->send->ch_wn[priv->ch_wn_idx].stat);

	for (i = 0; i < MHUV2_STAT_BITS; i++) {
		priv = chan[i].con_priv;

		/* Find cases where pending was 1, but stat's bit is cleared */
		if (priv->pending ^ ((stat >> i) & 0x1)) {
			BUG_ON(!priv->pending);

			if (!chan->cl) {
				dev_warn(dev, "Tx interrupt received on doorbell (%u : %u) channel not currently attached to a mailbox client\n",
					 priv->ch_wn_idx, i);
				continue;
			}

			mbox_chan_txdone(&chan[i], 0);
			priv->pending = 0;
			found++;
		}
	}

	spin_unlock_irqrestore(&mhu->doorbell_pending_lock, flags);

	if (!found) {
		/*
		 * We may have already processed the doorbell in the previous
		 * iteration if the interrupt came right after we cleared it but
		 * before we read the stat register.
		 */
		dev_dbg(dev, "Couldn't find the doorbell (%u) for the Tx interrupt interrupt\n",
			priv->ch_wn_idx);
		return IRQ_NONE;
	}

	return IRQ_HANDLED;
}