drivers/dma/loongson/loongson1-apb-dma.c

Source file repositories/reference/linux-study-clean/drivers/dma/loongson/loongson1-apb-dma.c

File Facts

System
Linux kernel
Corpus path
drivers/dma/loongson/loongson1-apb-dma.c
Extension
.c
Size
16587 bytes
Lines
661
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 ls1x_dma_lli {
	unsigned int hw[LS1X_DMADESC_SIZE];
	dma_addr_t phys;
	struct list_head node;
} __aligned(LS1X_DMA_LLI_ALIGNMENT);

struct ls1x_dma_desc {
	struct virt_dma_desc vd;
	struct list_head lli_list;
};

struct ls1x_dma_chan {
	struct virt_dma_chan vc;
	struct dma_pool *lli_pool;
	phys_addr_t src_addr;
	phys_addr_t dst_addr;
	enum dma_slave_buswidth src_addr_width;
	enum dma_slave_buswidth dst_addr_width;
	unsigned int bus_width;
	void __iomem *reg_base;
	int irq;
	bool is_cyclic;
	struct ls1x_dma_lli *curr_lli;
};

struct ls1x_dma {
	struct dma_device ddev;
	unsigned int nr_chans;
	struct ls1x_dma_chan chan[];
};

static irqreturn_t ls1x_dma_irq_handler(int irq, void *data);

#define to_ls1x_dma_chan(dchan)		\
	container_of(dchan, struct ls1x_dma_chan, vc.chan)

#define to_ls1x_dma_desc(d)		\
	container_of(d, struct ls1x_dma_desc, vd)

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

static inline int ls1x_dma_query(struct ls1x_dma_chan *chan,
				 dma_addr_t *lli_phys)
{
	struct dma_chan *dchan = &chan->vc.chan;
	int val, ret;

	val = *lli_phys & LS1X_DMA_LLI_ADDR_MASK;
	val |= LS1X_DMA_ASK_VALID;
	val |= dchan->chan_id;
	writel(val, chan->reg_base + LS1X_DMA_CTRL);
	ret = readl_poll_timeout_atomic(chan->reg_base + LS1X_DMA_CTRL, val,
					!(val & LS1X_DMA_ASK_VALID), 0, 3000);
	if (ret)
		dev_err(chan2dev(dchan), "failed to query DMA\n");

	return ret;
}

static inline int ls1x_dma_start(struct ls1x_dma_chan *chan,
				 dma_addr_t *lli_phys)
{
	struct dma_chan *dchan = &chan->vc.chan;
	struct device *dev = chan2dev(dchan);
	int val, ret;

	val = *lli_phys & LS1X_DMA_LLI_ADDR_MASK;
	val |= LS1X_DMA_START;
	val |= dchan->chan_id;
	writel(val, chan->reg_base + LS1X_DMA_CTRL);
	ret = readl_poll_timeout(chan->reg_base + LS1X_DMA_CTRL, val,
				 !(val & LS1X_DMA_START), 0, 1000);
	if (!ret)
		dev_dbg(dev, "start DMA with lli_phys=%pad\n", lli_phys);
	else
		dev_err(dev, "failed to start DMA\n");

	return ret;
}

static inline void ls1x_dma_stop(struct ls1x_dma_chan *chan)
{
	int val = readl(chan->reg_base + LS1X_DMA_CTRL);

	writel(val | LS1X_DMA_STOP, chan->reg_base + LS1X_DMA_CTRL);
}

Annotation

Implementation Notes