static int dma_init()

in ti/knav_dma.c [610:725]


static int dma_init(struct device_node *cloud, struct device_node *dma_node)
{
	unsigned max_tx_chan, max_rx_chan, max_rx_flow, max_tx_sched;
	struct device_node *node = dma_node;
	struct knav_dma_device *dma;
	int ret, len, num_chan = 0;
	resource_size_t size;
	u32 timeout;
	u32 i;

	dma = devm_kzalloc(kdev->dev, sizeof(*dma), GFP_KERNEL);
	if (!dma) {
		dev_err(kdev->dev, "could not allocate driver mem\n");
		return -ENOMEM;
	}
	INIT_LIST_HEAD(&dma->list);
	INIT_LIST_HEAD(&dma->chan_list);

	if (!of_find_property(cloud, "ti,navigator-cloud-address", &len)) {
		dev_err(kdev->dev, "unspecified navigator cloud addresses\n");
		return -ENODEV;
	}

	dma->logical_queue_managers = len / sizeof(u32);
	if (dma->logical_queue_managers > DMA_MAX_QMS) {
		dev_warn(kdev->dev, "too many queue mgrs(>%d) rest ignored\n",
			 dma->logical_queue_managers);
		dma->logical_queue_managers = DMA_MAX_QMS;
	}

	ret = of_property_read_u32_array(cloud, "ti,navigator-cloud-address",
					dma->qm_base_address,
					dma->logical_queue_managers);
	if (ret) {
		dev_err(kdev->dev, "invalid navigator cloud addresses\n");
		return -ENODEV;
	}

	dma->reg_global	 = pktdma_get_regs(dma, node, 0, &size);
	if (IS_ERR(dma->reg_global))
		return PTR_ERR(dma->reg_global);
	if (size < sizeof(struct reg_global)) {
		dev_err(kdev->dev, "bad size %pa for global regs\n", &size);
		return -ENODEV;
	}

	dma->reg_tx_chan = pktdma_get_regs(dma, node, 1, &size);
	if (IS_ERR(dma->reg_tx_chan))
		return PTR_ERR(dma->reg_tx_chan);

	max_tx_chan = size / sizeof(struct reg_chan);
	dma->reg_rx_chan = pktdma_get_regs(dma, node, 2, &size);
	if (IS_ERR(dma->reg_rx_chan))
		return PTR_ERR(dma->reg_rx_chan);

	max_rx_chan = size / sizeof(struct reg_chan);
	dma->reg_tx_sched = pktdma_get_regs(dma, node, 3, &size);
	if (IS_ERR(dma->reg_tx_sched))
		return PTR_ERR(dma->reg_tx_sched);

	max_tx_sched = size / sizeof(struct reg_tx_sched);
	dma->reg_rx_flow = pktdma_get_regs(dma, node, 4, &size);
	if (IS_ERR(dma->reg_rx_flow))
		return PTR_ERR(dma->reg_rx_flow);

	max_rx_flow = size / sizeof(struct reg_rx_flow);
	dma->rx_priority = DMA_PRIO_DEFAULT;
	dma->tx_priority = DMA_PRIO_DEFAULT;

	dma->enable_all	= (of_get_property(node, "ti,enable-all", NULL) != NULL);
	dma->loopback	= (of_get_property(node, "ti,loop-back",  NULL) != NULL);

	ret = of_property_read_u32(node, "ti,rx-retry-timeout", &timeout);
	if (ret < 0) {
		dev_dbg(kdev->dev, "unspecified rx timeout using value %d\n",
			DMA_RX_TIMEOUT_DEFAULT);
		timeout = DMA_RX_TIMEOUT_DEFAULT;
	}

	dma->rx_timeout = timeout;
	dma->max_rx_chan = max_rx_chan;
	dma->max_rx_flow = max_rx_flow;
	dma->max_tx_chan = min(max_tx_chan, max_tx_sched);
	atomic_set(&dma->ref_count, 0);
	strcpy(dma->name, node->name);
	spin_lock_init(&dma->lock);

	for (i = 0; i < dma->max_tx_chan; i++) {
		if (pktdma_init_chan(dma, DMA_MEM_TO_DEV, i) >= 0)
			num_chan++;
	}

	for (i = 0; i < dma->max_rx_flow; i++) {
		if (pktdma_init_chan(dma, DMA_DEV_TO_MEM, i) >= 0)
			num_chan++;
	}

	list_add_tail(&dma->list, &kdev->list);

	/*
	 * For DSP software usecases or userpace transport software, setup all
	 * the DMA hardware resources.
	 */
	if (dma->enable_all) {
		atomic_inc(&dma->ref_count);
		knav_dma_hw_init(dma);
		dma_hw_enable_all(dma);
	}

	dev_info(kdev->dev, "DMA %s registered %d logical channels, flows %d, tx chans: %d, rx chans: %d%s\n",
		dma->name, num_chan, dma->max_rx_flow,
		dma->max_tx_chan, dma->max_rx_chan,
		dma->loopback ? ", loopback" : "");

	return 0;
}