drivers/dma/cv1800b-dmamux.c

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

File Facts

System
Linux kernel
Corpus path
drivers/dma/cv1800b-dmamux.c
Extension
.c
Size
6846 bytes
Lines
263
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 cv1800_dmamux_data {
	struct dma_router	dmarouter;
	struct regmap		*regmap;
	spinlock_t		lock;
	struct llist_head	free_maps;
	struct llist_head	reserve_maps;
	DECLARE_BITMAP(mapped_peripherals, MAX_DMA_MAPPING_ID);
};

struct cv1800_dmamux_map {
	struct llist_node node;
	unsigned int channel;
	unsigned int peripheral;
	unsigned int cpu;
};

static void cv1800_dmamux_free(struct device *dev, void *route_data)
{
	struct cv1800_dmamux_data *dmamux = dev_get_drvdata(dev);
	struct cv1800_dmamux_map *map = route_data;

	guard(spinlock_irqsave)(&dmamux->lock);

	regmap_update_bits(dmamux->regmap,
			   DMAMUX_CH_REG(map->channel),
			   DMAMUX_CH_MASK(map->channel),
			   DMAMUX_CH_UPDATE_BIT);

	regmap_update_bits(dmamux->regmap, REG_DMA_INT_MUX,
			   DMAMUX_INT_CH_MASK(map->channel, map->cpu),
			   DMAMUX_INTEN_BIT(map->cpu));

	dev_dbg(dev, "free channel %u for req %u (cpu %u)\n",
		map->channel, map->peripheral, map->cpu);
}

static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec,
					  struct of_dma *ofdma)
{
	struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
	struct cv1800_dmamux_data *dmamux = platform_get_drvdata(pdev);
	struct cv1800_dmamux_map *map;
	struct llist_node *node;
	unsigned long flags;
	unsigned int chid, devid, cpuid;
	int ret = -EINVAL;

	if (dma_spec->args_count != DMAMUX_NCELLS) {
		dev_err(&pdev->dev, "invalid number of dma mux args\n");
		goto err_put_pdev;
	}

	devid = dma_spec->args[0];
	cpuid = dma_spec->args[1];
	dma_spec->args_count = 1;

	if (devid > MAX_DMA_MAPPING_ID) {
		dev_err(&pdev->dev, "invalid device id: %u\n", devid);
		goto err_put_pdev;
	}

	if (cpuid > MAX_DMA_CPU_ID) {
		dev_err(&pdev->dev, "invalid cpu id: %u\n", cpuid);
		goto err_put_pdev;
	}

	dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
	if (!dma_spec->np) {
		dev_err(&pdev->dev, "can't get dma master\n");
		goto err_put_pdev;
	}

	spin_lock_irqsave(&dmamux->lock, flags);

	if (test_bit(devid, dmamux->mapped_peripherals)) {
		llist_for_each_entry(map, dmamux->reserve_maps.first, node) {
			if (map->peripheral == devid && map->cpu == cpuid)
				goto found;
		}
		goto failed;
	} else {
		node = llist_del_first(&dmamux->free_maps);
		if (!node) {
			ret = -ENODEV;
			goto failed;
		}

		map = llist_entry(node, struct cv1800_dmamux_map, node);
		llist_add(&map->node, &dmamux->reserve_maps);
		set_bit(devid, dmamux->mapped_peripherals);

Annotation

Implementation Notes