drivers/dma/timb_dma.c

Source file repositories/reference/linux-study-clean/drivers/dma/timb_dma.c

File Facts

System
Linux kernel
Corpus path
drivers/dma/timb_dma.c
Extension
.c
Size
19328 bytes
Lines
772
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

struct timb_dma_desc {
	struct list_head		desc_node;
	struct dma_async_tx_descriptor	txd;
	u8				*desc_list;
	unsigned int			desc_list_len;
	bool				interrupt;
};

struct timb_dma_chan {
	struct dma_chan		chan;
	void __iomem		*membase;
	spinlock_t		lock; /* Used to protect data structures,
					especially the lists and descriptors,
					from races between the tasklet and calls
					from above */
	bool			ongoing;
	struct list_head	active_list;
	struct list_head	queue;
	struct list_head	free_list;
	unsigned int		bytes_per_line;
	enum dma_transfer_direction	direction;
	unsigned int		descs; /* Descriptors to allocate */
	unsigned int		desc_elems; /* number of elems per descriptor */
};

struct timb_dma {
	struct dma_device	dma;
	void __iomem		*membase;
	struct tasklet_struct	tasklet;
	struct timb_dma_chan	channels[];
};

static struct device *chan2dev(struct dma_chan *chan)
{
	return &chan->dev->device;
}
static struct device *chan2dmadev(struct dma_chan *chan)
{
	return chan2dev(chan)->parent->parent;
}

static struct timb_dma *tdchantotd(struct timb_dma_chan *td_chan)
{
	int id = td_chan->chan.chan_id;
	return (struct timb_dma *)((u8 *)td_chan -
		id * sizeof(struct timb_dma_chan) - sizeof(struct timb_dma));
}

/* Must be called with the spinlock held */
static void __td_enable_chan_irq(struct timb_dma_chan *td_chan)
{
	int id = td_chan->chan.chan_id;
	struct timb_dma *td = tdchantotd(td_chan);
	u32 ier;

	/* enable interrupt for this channel */
	ier = ioread32(td->membase + TIMBDMA_IER);
	ier |= 1 << id;
	dev_dbg(chan2dev(&td_chan->chan), "Enabling irq: %d, IER: 0x%x\n", id,
		ier);
	iowrite32(ier, td->membase + TIMBDMA_IER);
}

/* Should be called with the spinlock held */
static bool __td_dma_done_ack(struct timb_dma_chan *td_chan)
{
	int id = td_chan->chan.chan_id;
	struct timb_dma *td = (struct timb_dma *)((u8 *)td_chan -
		id * sizeof(struct timb_dma_chan) - sizeof(struct timb_dma));
	u32 isr;
	bool done = false;

	dev_dbg(chan2dev(&td_chan->chan), "Checking irq: %d, td: %p\n", id, td);

	isr = ioread32(td->membase + TIMBDMA_ISR) & (1 << id);
	if (isr) {
		iowrite32(isr, td->membase + TIMBDMA_ISR);
		done = true;
	}

	return done;
}

static int td_fill_desc(struct timb_dma_chan *td_chan, u8 *dma_desc,
	struct scatterlist *sg, bool last)
{
	if (sg_dma_len(sg) > USHRT_MAX) {
		dev_err(chan2dev(&td_chan->chan), "Too big sg element\n");
		return -EINVAL;
	}

Annotation

Implementation Notes