drivers/dma/apple-admac.c

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

File Facts

System
Linux kernel
Corpus path
drivers/dma/apple-admac.c
Extension
.c
Size
25097 bytes
Lines
958
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 admac_chan {
	unsigned int no;
	struct admac_data *host;
	struct dma_chan chan;
	struct tasklet_struct tasklet;

	u32 carveout;

	spinlock_t lock;
	struct admac_tx *current_tx;
	int nperiod_acks;

	/*
	 * We maintain a 'submitted' and 'issued' list mainly for interface
	 * correctness. Typical use of the driver (per channel) will be
	 * prepping, submitting and issuing a single cyclic transaction which
	 * will stay current until terminate_all is called.
	 */
	struct list_head submitted;
	struct list_head issued;

	struct list_head to_free;
};

struct admac_sram {
	u32 size;
	/*
	 * SRAM_CARVEOUT has 16-bit fields, so the SRAM cannot be larger than
	 * 64K and a 32-bit bitfield over 2K blocks covers it.
	 */
	u32 allocated;
};

struct admac_data {
	struct dma_device dma;
	struct device *dev;
	__iomem void *base;
	struct reset_control *rstc;

	struct mutex cache_alloc_lock;
	struct admac_sram txcache, rxcache;

	int irq;
	int irq_index;
	int nchannels;
	struct admac_chan channels[] __counted_by(nchannels);
};

struct admac_tx {
	struct dma_async_tx_descriptor tx;
	bool cyclic;
	dma_addr_t buf_addr;
	dma_addr_t buf_end;
	size_t buf_len;
	size_t period_len;

	size_t submitted_pos;
	size_t reclaimed_pos;

	struct list_head node;
};

static int admac_alloc_sram_carveout(struct admac_data *ad,
				     enum dma_transfer_direction dir,
				     u32 *out)
{
	struct admac_sram *sram;
	int i, ret = 0, nblocks;
	ad->txcache.size = readl_relaxed(ad->base + REG_TX_SRAM_SIZE);
	ad->rxcache.size = readl_relaxed(ad->base + REG_RX_SRAM_SIZE);

	if (dir == DMA_MEM_TO_DEV)
		sram = &ad->txcache;
	else
		sram = &ad->rxcache;

	mutex_lock(&ad->cache_alloc_lock);

	nblocks = sram->size / SRAM_BLOCK;
	for (i = 0; i < nblocks; i++)
		if (!(sram->allocated & BIT(i)))
			break;

	if (i < nblocks) {
		*out = FIELD_PREP(CHAN_SRAM_CARVEOUT_BASE, i * SRAM_BLOCK) |
			FIELD_PREP(CHAN_SRAM_CARVEOUT_SIZE, SRAM_BLOCK);
		sram->allocated |= BIT(i);
	} else {
		ret = -EBUSY;
	}

Annotation

Implementation Notes