drivers/dma/dw-edma/dw-hdma-v0-core.c

Source file repositories/reference/linux-study-clean/drivers/dma/dw-edma/dw-hdma-v0-core.c

File Facts

System
Linux kernel
Corpus path
drivers/dma/dw-edma/dw-hdma-v0-core.c
Extension
.c
Size
10092 bytes
Lines
369
Domain
Driver Families
Bucket
drivers/dma
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 (FIELD_GET(HDMA_V0_STOP_INT_MASK, val)) {
			dw_hdma_v0_core_clear_done_int(chan);
			done(chan);

			ret = IRQ_HANDLED;
		}

		if (FIELD_GET(HDMA_V0_ABORT_INT_MASK, val)) {
			dw_hdma_v0_core_clear_abort_int(chan);
			abort(chan);

			ret = IRQ_HANDLED;
		}
	}

	return ret;
}

static void dw_hdma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
				     u32 control, u32 size, u64 sar, u64 dar)
{
	ptrdiff_t ofs = i * sizeof(struct dw_hdma_v0_lli);

	if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
		struct dw_hdma_v0_lli *lli = chunk->ll_region.vaddr.mem + ofs;

		lli->control = control;
		lli->transfer_size = size;
		lli->sar.reg = sar;
		lli->dar.reg = dar;
	} else {
		struct dw_hdma_v0_lli __iomem *lli = chunk->ll_region.vaddr.io + ofs;

		writel(control, &lli->control);
		writel(size, &lli->transfer_size);
		writeq(sar, &lli->sar.reg);
		writeq(dar, &lli->dar.reg);
	}
}

static void dw_hdma_v0_write_ll_link(struct dw_edma_chunk *chunk,
				     int i, u32 control, u64 pointer)
{
	ptrdiff_t ofs = i * sizeof(struct dw_hdma_v0_lli);

	if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
		struct dw_hdma_v0_llp *llp = chunk->ll_region.vaddr.mem + ofs;

		llp->control = control;
		llp->llp.reg = pointer;
	} else {
		struct dw_hdma_v0_llp __iomem *llp = chunk->ll_region.vaddr.io + ofs;

		writel(control, &llp->control);
		writeq(pointer, &llp->llp.reg);
	}
}

static void dw_hdma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
{
	struct dw_edma_burst *child;
	u32 control = 0, i = 0;

	if (chunk->cb)
		control = DW_HDMA_V0_CB;

	list_for_each_entry(child, &chunk->burst->list, list)
		dw_hdma_v0_write_ll_data(chunk, i++, control, child->sz,
					 child->sar, child->dar);

	control = DW_HDMA_V0_LLP | DW_HDMA_V0_TCB;
	if (!chunk->cb)
		control |= DW_HDMA_V0_CB;

	dw_hdma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr);
}

static void dw_hdma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
{
	/*
	 * In case of remote HDMA engine setup, the DW PCIe RP/EP internal
	 * configuration registers and application memory are normally accessed
	 * over different buses. Ensure LL-data reaches the memory before the
	 * doorbell register is toggled by issuing the dummy-read from the remote
	 * LL memory in a hope that the MRd TLP will return only after the
	 * last MWr TLP is completed
	 */
	if (!(chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
		readl(chunk->ll_region.vaddr.io);
}

Annotation

Implementation Notes