drivers/dma/fsl-edma-common.c

Source file repositories/reference/linux-study-clean/drivers/dma/fsl-edma-common.c

File Facts

System
Linux kernel
Corpus path
drivers/dma/fsl-edma-common.c
Extension
.c
Size
27340 bytes
Lines
959
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 (dir == DMA_MEM_TO_DEV) {
			old_addr = edma_read_tcdreg(fsl_chan, saddr);
			cur_addr = edma_read_tcdreg(fsl_chan, saddr);
		} else {
			old_addr = edma_read_tcdreg(fsl_chan, daddr);
			cur_addr = edma_read_tcdreg(fsl_chan, daddr);
		}
	} while (upper_32_bits(cur_addr) != upper_32_bits(old_addr));

	/* figure out the finished and calculate the residue */
	for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
		nbytes = fsl_edma_get_tcd_to_cpu(fsl_chan, edesc->tcd[i].vtcd, nbytes);
		if (nbytes & (EDMA_V3_TCD_NBYTES_DMLOE | EDMA_V3_TCD_NBYTES_SMLOE))
			nbytes = EDMA_V3_TCD_NBYTES_MLOFF_NBYTES(nbytes);

		size = nbytes * fsl_edma_get_tcd_to_cpu(fsl_chan, edesc->tcd[i].vtcd, biter);

		if (dir == DMA_MEM_TO_DEV)
			dma_addr = fsl_edma_get_tcd_to_cpu(fsl_chan, edesc->tcd[i].vtcd, saddr);
		else
			dma_addr = fsl_edma_get_tcd_to_cpu(fsl_chan, edesc->tcd[i].vtcd, daddr);

		len -= size;
		if (cur_addr >= dma_addr && cur_addr < dma_addr + size) {
			len += dma_addr + size - cur_addr;
			break;
		}
	}

	return len;
}

enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
		dma_cookie_t cookie, struct dma_tx_state *txstate)
{
	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
	struct virt_dma_desc *vdesc;
	enum dma_status status;
	unsigned long flags;

	status = dma_cookie_status(chan, cookie, txstate);
	if (status == DMA_COMPLETE)
		return status;

	if (!txstate)
		return fsl_chan->status;

	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
	vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
	if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
		txstate->residue =
			fsl_edma_desc_residue(fsl_chan, vdesc, true);
	else if (vdesc)
		txstate->residue =
			fsl_edma_desc_residue(fsl_chan, vdesc, false);
	else
		txstate->residue = 0;

	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);

	return fsl_chan->status;
}

static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, void *tcd)
{
	u16 csr = 0;

	/*
	 * TCD parameters are stored in struct fsl_edma_hw_tcd in little
	 * endian format. However, we need to load the TCD registers in
	 * big- or little-endian obeying the eDMA engine model endian,
	 * and this is performed from specific edma_write functions
	 */
	edma_write_tcdreg(fsl_chan, 0, csr);

	edma_cp_tcd_to_reg(fsl_chan, tcd, saddr);
	edma_cp_tcd_to_reg(fsl_chan, tcd, daddr);

	edma_cp_tcd_to_reg(fsl_chan, tcd, attr);
	edma_cp_tcd_to_reg(fsl_chan, tcd, soff);

	edma_cp_tcd_to_reg(fsl_chan, tcd, nbytes);
	edma_cp_tcd_to_reg(fsl_chan, tcd, slast);

	edma_cp_tcd_to_reg(fsl_chan, tcd, citer);
	edma_cp_tcd_to_reg(fsl_chan, tcd, biter);
	edma_cp_tcd_to_reg(fsl_chan, tcd, doff);

	edma_cp_tcd_to_reg(fsl_chan, tcd, dlast_sga);

Annotation

Implementation Notes