drivers/bus/mhi/ep/ring.c

Source file repositories/reference/linux-study-clean/drivers/bus/mhi/ep/ring.c

File Facts

System
Linux kernel
Corpus path
drivers/bus/mhi/ep/ring.c
Extension
.c
Size
6400 bytes
Lines
235
Domain
Driver Families
Bucket
drivers/bus
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

if (end) {
			buf_info.host_addr = ring->rbase;
			buf_info.dev_addr = &ring->ring_cache[0];
			buf_info.size = end * sizeof(struct mhi_ring_element);

			ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info);
			if (ret)
				return ret;
		}
	}

	dev_dbg(dev, "Cached ring: start %zu end %zu size %zu\n", start, end, buf_info.size);

	return 0;
}

static int mhi_ep_cache_ring(struct mhi_ep_ring *ring, u64 wr_ptr)
{
	size_t wr_offset;
	int ret;

	wr_offset = mhi_ep_ring_addr2offset(ring, wr_ptr);

	/* Cache the host ring till write offset */
	ret = __mhi_ep_cache_ring(ring, wr_offset);
	if (ret)
		return ret;

	ring->wr_offset = wr_offset;

	return 0;
}

int mhi_ep_update_wr_offset(struct mhi_ep_ring *ring)
{
	u64 wr_ptr;

	wr_ptr = mhi_ep_mmio_get_db(ring);

	return mhi_ep_cache_ring(ring, wr_ptr);
}

/* TODO: Support for adding multiple ring elements to the ring */
int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *el)
{
	struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
	struct device *dev = &mhi_cntrl->mhi_dev->dev;
	struct mhi_ep_buf_info buf_info = {};
	size_t old_offset = 0;
	u32 num_free_elem;
	__le64 rp;
	int ret;

	ret = mhi_ep_update_wr_offset(ring);
	if (ret) {
		dev_err(dev, "Error updating write pointer\n");
		return ret;
	}

	if (ring->rd_offset < ring->wr_offset)
		num_free_elem = (ring->wr_offset - ring->rd_offset) - 1;
	else
		num_free_elem = ((ring->ring_size - ring->rd_offset) + ring->wr_offset) - 1;

	/* Check if there is space in ring for adding at least an element */
	if (!num_free_elem) {
		dev_err(dev, "No space left in the ring\n");
		return -ENOSPC;
	}

	old_offset = ring->rd_offset;

	dev_dbg(dev, "Adding an element to ring at offset (%zu)\n", ring->rd_offset);
	buf_info.host_addr = ring->rbase + (old_offset * sizeof(*el));
	buf_info.dev_addr = el;
	buf_info.size = sizeof(*el);

	ret = mhi_cntrl->write_sync(mhi_cntrl, &buf_info);
	if (ret)
		return ret;

	mhi_ep_ring_inc_index(ring);

	/* Update rp in ring context */
	rp = cpu_to_le64(ring->rd_offset * sizeof(*el) + ring->rbase);
	memcpy_toio((void __iomem *) &ring->ring_ctx->generic.rp, &rp, sizeof(u64));

	return ret;
}

Annotation

Implementation Notes