drivers/i3c/master/mipi-i3c-hci/dma.c

Source file repositories/reference/linux-study-clean/drivers/i3c/master/mipi-i3c-hci/dma.c

File Facts

System
Linux kernel
Corpus path
drivers/i3c/master/mipi-i3c-hci/dma.c
Extension
.c
Size
30419 bytes
Lines
1093
Domain
Driver Families
Bucket
drivers/i3c
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 hci_rh_data {
	void __iomem *regs;
	void *xfer, *resp, *ibi_status, *ibi_data;
	dma_addr_t xfer_dma, resp_dma, ibi_status_dma, ibi_data_dma;
	unsigned int xfer_entries, ibi_status_entries, ibi_chunks_total;
	unsigned int xfer_struct_sz, resp_struct_sz, ibi_status_sz, ibi_chunk_sz;
	unsigned int xfer_alloc_sz, done_ptr, ibi_chunk_ptr, xfer_space;
	struct hci_xfer **src_xfers;
	struct completion op_done;
};

struct hci_rings_data {
	struct device *sysdev;
	unsigned int total;
	struct hci_rh_data headers[] __counted_by(total);
};

struct hci_dma_dev_ibi_data {
	struct i3c_generic_ibi_pool *pool;
	unsigned int max_len;
};

static void hci_dma_cleanup(struct i3c_hci *hci)
{
	struct hci_rings_data *rings = hci->io_data;
	struct hci_rh_data *rh;
	unsigned int i;

	if (!rings)
		return;

	for (i = 0; i < rings->total; i++) {
		rh = &rings->headers[i];

		rh_reg_write(INTR_SIGNAL_ENABLE, 0);
		rh_reg_write(RING_CONTROL, 0);
	}

	i3c_hci_sync_irq_inactive(hci);

	for (i = 0; i < rings->total; i++) {
		rh = &rings->headers[i];

		rh_reg_write(CR_SETUP, 0);
		rh_reg_write(IBI_SETUP, 0);
	}

	rhs_reg_write(CONTROL, 0);
}

static void hci_dma_free(void *data)
{
	struct i3c_hci *hci = data;
	struct hci_rings_data *rings = hci->io_data;
	struct hci_rh_data *rh;

	if (!rings)
		return;

	for (int i = 0; i < rings->total; i++) {
		rh = &rings->headers[i];

		if (rh->xfer)
			dma_free_coherent(rings->sysdev, rh->xfer_alloc_sz, rh->xfer, rh->xfer_dma);
		kfree(rh->src_xfers);
		if (rh->ibi_status)
			dma_free_coherent(rings->sysdev,
					  rh->ibi_status_sz * rh->ibi_status_entries,
					  rh->ibi_status, rh->ibi_status_dma);
		if (rh->ibi_data_dma)
			dma_unmap_single(rings->sysdev, rh->ibi_data_dma,
					 rh->ibi_chunk_sz * rh->ibi_chunks_total,
					 DMA_FROM_DEVICE);
		kfree(rh->ibi_data);
	}

	kfree(rings);
	hci->io_data = NULL;
}

static void hci_dma_init_rh(struct i3c_hci *hci, struct hci_rh_data *rh, int i)
{
	u32 regval;

	rh_reg_write(CMD_RING_BASE_LO, lower_32_bits(rh->xfer_dma));
	rh_reg_write(CMD_RING_BASE_HI, upper_32_bits(rh->xfer_dma));
	rh_reg_write(RESP_RING_BASE_LO, lower_32_bits(rh->resp_dma));
	rh_reg_write(RESP_RING_BASE_HI, upper_32_bits(rh->resp_dma));

	regval = FIELD_PREP(CR_RING_SIZE, rh->xfer_entries);

Annotation

Implementation Notes