in ti/k3-udma.c [2361:2553]
static int bcdma_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_udma_idx, irq_ring_idx;
int ret;
/* Only TR mode is supported */
uc->config.pkt_mode = false;
/*
* 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_MEM:
/* Non synchronized - mem to mem type of transfer */
dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-MEM\n", __func__,
uc->id);
ret = bcdma_alloc_bchan_resources(uc);
if (ret)
return ret;
irq_ring_idx = uc->bchan->id + oes->bcdma_bchan_ring;
irq_udma_idx = uc->bchan->id + oes->bcdma_bchan_data;
ret = bcdma_tisci_m2m_channel_config(uc);
break;
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->id + oes->bcdma_tchan_ring;
irq_udma_idx = uc->tchan->id + oes->bcdma_tchan_data;
ret = bcdma_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->rchan->id + oes->bcdma_rchan_ring;
irq_udma_idx = uc->rchan->id + oes->bcdma_rchan_data;
ret = bcdma_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);
if (uc->config.dir == DMA_MEM_TO_MEM && !uc->config.tr_trigger_type) {
uc->config.hdesc_size = cppi5_trdesc_calc_size(
sizeof(struct cppi5_tr_type15_t), 2);
uc->hdesc_pool = dma_pool_create(uc->name, ud->ddev.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;
} else if (uc->config.dir != DMA_MEM_TO_MEM) {
/* 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;
}
/* Event from BCDMA (TR events) only needed for slave channels */
if (is_slave_direction(uc->config.dir)) {
uc->irq_num_udma = msi_get_virq(ud->dev, irq_udma_idx);
if (uc->irq_num_udma <= 0) {
dev_err(ud->dev, "Failed to get bcdma irq (index: %u)\n",
irq_udma_idx);
free_irq(uc->irq_num_ring, uc);
ret = -EINVAL;
goto err_irq_free;
}
ret = request_irq(uc->irq_num_udma, udma_udma_irq_handler, 0,
uc->name, uc);
if (ret) {
dev_err(ud->dev, "chan%d: BCDMA irq request failed\n",
uc->id);
free_irq(uc->irq_num_ring, uc);
goto err_irq_free;
}
} else {
uc->irq_num_udma = 0;
}
udma_reset_rings(uc);
INIT_DELAYED_WORK_ONSTACK(&uc->tx_drain.work,
udma_check_tx_completion);
return 0;
err_irq_free:
uc->irq_num_ring = 0;
uc->irq_num_udma = 0;
err_psi_free:
if (uc->psil_paired)
navss_psil_unpair(ud, uc->config.src_thread,
uc->config.dst_thread);
uc->psil_paired = false;
err_res_free:
bcdma_free_bchan_resources(uc);
udma_free_tx_resources(uc);
udma_free_rx_resources(uc);
udma_reset_uchan(uc);
if (uc->use_dma_pool) {
dma_pool_destroy(uc->hdesc_pool);
uc->use_dma_pool = false;
}
return ret;
}