drivers/bus/mhi/host/main.c

Source file repositories/reference/linux-study-clean/drivers/bus/mhi/host/main.c

File Facts

System
Linux kernel
Corpus path
drivers/bus/mhi/host/main.c
Extension
.c
Size
42565 bytes
Lines
1629
Domain
Driver Families
Bucket
drivers/bus
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

ret = device_add(&mhi_dev->dev);
		if (ret)
			put_device(&mhi_dev->dev);
	}
}

irqreturn_t mhi_irq_handler(int irq_number, void *dev)
{
	struct mhi_event *mhi_event = dev;
	struct mhi_controller *mhi_cntrl = mhi_event->mhi_cntrl;
	struct mhi_event_ctxt *er_ctxt;
	struct mhi_ring *ev_ring = &mhi_event->ring;
	dma_addr_t ptr;
	void *dev_rp;

	/*
	 * If CONFIG_DEBUG_SHIRQ is set, the IRQ handler will get invoked during __free_irq()
	 * and by that time mhi_ctxt() would've freed. So check for the existence of mhi_ctxt
	 * before handling the IRQs.
	 */
	if (!mhi_cntrl->mhi_ctxt) {
		dev_dbg(&mhi_cntrl->mhi_dev->dev,
			"mhi_ctxt has been freed\n");
		return IRQ_HANDLED;
	}

	er_ctxt = &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index];
	ptr = le64_to_cpu(er_ctxt->rp);

	if (!is_valid_ring_ptr(ev_ring, ptr)) {
		dev_err(&mhi_cntrl->mhi_dev->dev,
			"Event ring rp points outside of the event ring\n");
		return IRQ_HANDLED;
	}

	dev_rp = mhi_to_virtual(ev_ring, ptr);

	/* Only proceed if event ring has pending events */
	if (ev_ring->rp == dev_rp)
		return IRQ_HANDLED;

	/* For client managed event ring, notify pending data */
	if (mhi_event->cl_manage) {
		struct mhi_chan *mhi_chan = mhi_event->mhi_chan;
		struct mhi_device *mhi_dev = mhi_chan->mhi_dev;

		if (mhi_dev)
			mhi_notify(mhi_dev, MHI_CB_PENDING_DATA);
	} else {
		tasklet_schedule(&mhi_event->task);
	}

	return IRQ_HANDLED;
}

irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv)
{
	struct mhi_controller *mhi_cntrl = priv;
	struct device *dev = &mhi_cntrl->mhi_dev->dev;
	enum mhi_state state;
	enum mhi_pm_state pm_state = 0;
	enum mhi_ee_type ee;

	write_lock_irq(&mhi_cntrl->pm_lock);
	if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
		write_unlock_irq(&mhi_cntrl->pm_lock);
		goto exit_intvec;
	}

	state = mhi_get_mhi_state(mhi_cntrl);
	ee = mhi_get_exec_env(mhi_cntrl);

	trace_mhi_intvec_states(mhi_cntrl, ee, state);
	if (state == MHI_STATE_SYS_ERR) {
		dev_dbg(dev, "System error detected\n");
		pm_state = mhi_tryset_pm_state(mhi_cntrl,
					       MHI_PM_SYS_ERR_DETECT);
	}
	write_unlock_irq(&mhi_cntrl->pm_lock);

	if (pm_state != MHI_PM_SYS_ERR_DETECT)
		goto exit_intvec;

	switch (ee) {
	case MHI_EE_RDDM:
		/* proceed if power down is not already in progress */
		if (mhi_cntrl->rddm_image && mhi_is_active(mhi_cntrl)) {
			mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_RDDM);
			mhi_cntrl->ee = ee;
			mhi_uevent_notify(mhi_cntrl, mhi_cntrl->ee);

Annotation

Implementation Notes