in ti/k3-udma.c [2573:2722]
static int pktdma_alloc_chan_resources(struct dma_chan *chan)
{
struct udma_chan *uc = to_udma_chan(chan);
struct udma_dev *ud = to_udma_dev(chan->device);
const struct udma_oes_offsets *oes = &ud->soc_data->oes;
u32 irq_ring_idx;
int ret;
/*
* Make sure that the completion is in a known state:
* No teardown, the channel is idle
*/
reinit_completion(&uc->teardown_completed);
complete_all(&uc->teardown_completed);
uc->state = UDMA_CHAN_IS_IDLE;
switch (uc->config.dir) {
case DMA_MEM_TO_DEV:
/* Slave transfer synchronized - mem to dev (TX) trasnfer */
dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-DEV\n", __func__,
uc->id);
ret = udma_alloc_tx_resources(uc);
if (ret) {
uc->config.remote_thread_id = -1;
return ret;
}
uc->config.src_thread = ud->psil_base + uc->tchan->id;
uc->config.dst_thread = uc->config.remote_thread_id;
uc->config.dst_thread |= K3_PSIL_DST_THREAD_ID_OFFSET;
irq_ring_idx = uc->tchan->tflow_id + oes->pktdma_tchan_flow;
ret = pktdma_tisci_tx_channel_config(uc);
break;
case DMA_DEV_TO_MEM:
/* Slave transfer synchronized - dev to mem (RX) trasnfer */
dev_dbg(uc->ud->dev, "%s: chan%d as DEV-to-MEM\n", __func__,
uc->id);
ret = udma_alloc_rx_resources(uc);
if (ret) {
uc->config.remote_thread_id = -1;
return ret;
}
uc->config.src_thread = uc->config.remote_thread_id;
uc->config.dst_thread = (ud->psil_base + uc->rchan->id) |
K3_PSIL_DST_THREAD_ID_OFFSET;
irq_ring_idx = uc->rflow->id + oes->pktdma_rchan_flow;
ret = pktdma_tisci_rx_channel_config(uc);
break;
default:
/* Can not happen */
dev_err(uc->ud->dev, "%s: chan%d invalid direction (%u)\n",
__func__, uc->id, uc->config.dir);
return -EINVAL;
}
/* check if the channel configuration was successful */
if (ret)
goto err_res_free;
if (udma_is_chan_running(uc)) {
dev_warn(ud->dev, "chan%d: is running!\n", uc->id);
udma_reset_chan(uc, false);
if (udma_is_chan_running(uc)) {
dev_err(ud->dev, "chan%d: won't stop!\n", uc->id);
ret = -EBUSY;
goto err_res_free;
}
}
uc->dma_dev = dmaengine_get_dma_device(chan);
uc->hdesc_pool = dma_pool_create(uc->name, uc->dma_dev,
uc->config.hdesc_size, ud->desc_align,
0);
if (!uc->hdesc_pool) {
dev_err(ud->ddev.dev,
"Descriptor pool allocation failed\n");
uc->use_dma_pool = false;
ret = -ENOMEM;
goto err_res_free;
}
uc->use_dma_pool = true;
/* PSI-L pairing */
ret = navss_psil_pair(ud, uc->config.src_thread, uc->config.dst_thread);
if (ret) {
dev_err(ud->dev, "PSI-L pairing failed: 0x%04x -> 0x%04x\n",
uc->config.src_thread, uc->config.dst_thread);
goto err_res_free;
}
uc->psil_paired = true;
uc->irq_num_ring = msi_get_virq(ud->dev, irq_ring_idx);
if (uc->irq_num_ring <= 0) {
dev_err(ud->dev, "Failed to get ring irq (index: %u)\n",
irq_ring_idx);
ret = -EINVAL;
goto err_psi_free;
}
ret = request_irq(uc->irq_num_ring, udma_ring_irq_handler,
IRQF_TRIGGER_HIGH, uc->name, uc);
if (ret) {
dev_err(ud->dev, "chan%d: ring irq request failed\n", uc->id);
goto err_irq_free;
}
uc->irq_num_udma = 0;
udma_reset_rings(uc);
INIT_DELAYED_WORK_ONSTACK(&uc->tx_drain.work,
udma_check_tx_completion);
if (uc->tchan)
dev_dbg(ud->dev,
"chan%d: tchan%d, tflow%d, Remote thread: 0x%04x\n",
uc->id, uc->tchan->id, uc->tchan->tflow_id,
uc->config.remote_thread_id);
else if (uc->rchan)
dev_dbg(ud->dev,
"chan%d: rchan%d, rflow%d, Remote thread: 0x%04x\n",
uc->id, uc->rchan->id, uc->rflow->id,
uc->config.remote_thread_id);
return 0;
err_irq_free:
uc->irq_num_ring = 0;
err_psi_free:
navss_psil_unpair(ud, uc->config.src_thread, uc->config.dst_thread);
uc->psil_paired = false;
err_res_free:
udma_free_tx_resources(uc);
udma_free_rx_resources(uc);
udma_reset_uchan(uc);
dma_pool_destroy(uc->hdesc_pool);
uc->use_dma_pool = false;
return ret;
}