drivers/dma/hsu/hsu.c

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

File Facts

System
Linux kernel
Corpus path
drivers/dma/hsu/hsu.c
Extension
.c
Size
13173 bytes
Lines
513
Domain
Driver Families
Bucket
drivers/dma
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 (status & HSU_CH_SR_CHE) {
			desc->status = DMA_ERROR;
		} else if (desc->active < desc->nents) {
			hsu_dma_start_channel(hsuc);
		} else {
			vchan_cookie_complete(&desc->vdesc);
			desc->status = DMA_COMPLETE;
			stat->bytes_transferred += desc->length;
			hsu_dma_start_transfer(hsuc);
		}
	}
	spin_unlock_irqrestore(&hsuc->vchan.lock, flags);

	return 1;
}
EXPORT_SYMBOL_GPL(hsu_dma_do_irq);

static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents)
{
	struct hsu_dma_desc *desc;

	desc = kzalloc_obj(*desc, GFP_NOWAIT);
	if (!desc)
		return NULL;

	desc->sg = kzalloc_objs(*desc->sg, nents, GFP_NOWAIT);
	if (!desc->sg) {
		kfree(desc);
		return NULL;
	}

	return desc;
}

static void hsu_dma_desc_free(struct virt_dma_desc *vdesc)
{
	struct hsu_dma_desc *desc = to_hsu_dma_desc(vdesc);

	kfree(desc->sg);
	kfree(desc);
}

static struct dma_async_tx_descriptor *hsu_dma_prep_slave_sg(
		struct dma_chan *chan, struct scatterlist *sgl,
		unsigned int sg_len, enum dma_transfer_direction direction,
		unsigned long flags, void *context)
{
	struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan);
	struct hsu_dma_desc *desc;
	struct scatterlist *sg;
	unsigned int i;

	desc = hsu_dma_alloc_desc(sg_len);
	if (!desc)
		return NULL;

	for_each_sg(sgl, sg, sg_len, i) {
		desc->sg[i].addr = sg_dma_address(sg);
		desc->sg[i].len = sg_dma_len(sg);

		desc->length += sg_dma_len(sg);
	}

	desc->nents = sg_len;
	desc->direction = direction;
	/* desc->active = 0 by kzalloc */
	desc->status = DMA_IN_PROGRESS;

	return vchan_tx_prep(&hsuc->vchan, &desc->vdesc, flags);
}

static void hsu_dma_issue_pending(struct dma_chan *chan)
{
	struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan);
	unsigned long flags;

	spin_lock_irqsave(&hsuc->vchan.lock, flags);
	if (vchan_issue_pending(&hsuc->vchan) && !hsuc->desc)
		hsu_dma_start_transfer(hsuc);
	spin_unlock_irqrestore(&hsuc->vchan.lock, flags);
}

static size_t hsu_dma_active_desc_size(struct hsu_dma_chan *hsuc)
{
	struct hsu_dma_desc *desc = hsuc->desc;
	size_t bytes = 0;
	int i;

	for (i = desc->active; i < desc->nents; i++)
		bytes += desc->sg[i].len;

Annotation

Implementation Notes