drivers/mailbox/arm_mhu_db.c

Source file repositories/reference/linux-study-clean/drivers/mailbox/arm_mhu_db.c

File Facts

System
Linux kernel
Corpus path
drivers/mailbox/arm_mhu_db.c
Extension
.c
Size
8481 bytes
Lines
352
Domain
Driver Families
Bucket
drivers/mailbox
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct mhu_db_link {
	unsigned int irq;
	void __iomem *tx_reg;
	void __iomem *rx_reg;
};

struct arm_mhu {
	void __iomem *base;
	struct mhu_db_link mlink[MHU_CHANS];
	struct mbox_controller mbox;
	struct device *dev;
};

/**
 * struct mhu_db_channel - ARM MHU Mailbox allocated channel information
 *
 * @mhu: Pointer to parent mailbox device
 * @pchan: Physical channel within which this doorbell resides in
 * @doorbell: doorbell number pertaining to this channel
 */
struct mhu_db_channel {
	struct arm_mhu *mhu;
	unsigned int pchan;
	unsigned int doorbell;
};

static inline struct mbox_chan *
mhu_db_mbox_to_channel(struct mbox_controller *mbox, unsigned int pchan,
		       unsigned int doorbell)
{
	int i;
	struct mhu_db_channel *chan_info;

	for (i = 0; i < mbox->num_chans; i++) {
		chan_info = mbox->chans[i].con_priv;
		if (chan_info && chan_info->pchan == pchan &&
		    chan_info->doorbell == doorbell)
			return &mbox->chans[i];
	}

	return NULL;
}

static void mhu_db_mbox_clear_irq(struct mbox_chan *chan)
{
	struct mhu_db_channel *chan_info = chan->con_priv;
	void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].rx_reg;

	writel_relaxed(BIT(chan_info->doorbell), base + INTR_CLR_OFS);
}

static unsigned int mhu_db_mbox_irq_to_pchan_num(struct arm_mhu *mhu, int irq)
{
	unsigned int pchan;

	for (pchan = 0; pchan < MHU_CHANS; pchan++)
		if (mhu->mlink[pchan].irq == irq)
			break;
	return pchan;
}

static struct mbox_chan *
mhu_db_mbox_irq_to_channel(struct arm_mhu *mhu, unsigned int pchan)
{
	unsigned long bits;
	unsigned int doorbell;
	struct mbox_chan *chan = NULL;
	struct mbox_controller *mbox = &mhu->mbox;
	void __iomem *base = mhu->mlink[pchan].rx_reg;

	bits = readl_relaxed(base + INTR_STAT_OFS);
	if (!bits)
		/* No IRQs fired in specified physical channel */
		return NULL;

	/* An IRQ has fired, find the associated channel */
	for (doorbell = 0; bits; doorbell++) {
		if (!test_and_clear_bit(doorbell, &bits))
			continue;

		chan = mhu_db_mbox_to_channel(mbox, pchan, doorbell);
		if (chan)
			break;
		dev_err(mbox->dev,
			"Channel not registered: pchan: %d doorbell: %d\n",
			pchan, doorbell);
	}

	return chan;
}

Annotation

Implementation Notes