in devices/tsi721_dma.c [63:204]
static int tsi721_bdma_ch_init(struct tsi721_bdma_chan *bdma_chan, int bd_num)
{
struct tsi721_dma_desc *bd_ptr;
struct device *dev = bdma_chan->dchan.device->dev;
u64 *sts_ptr;
dma_addr_t bd_phys;
dma_addr_t sts_phys;
int sts_size;
#ifdef CONFIG_PCI_MSI
struct tsi721_device *priv = to_tsi721(bdma_chan->dchan.device);
#endif
tsi_debug(DMA, &bdma_chan->dchan.dev->device, "DMAC%d", bdma_chan->id);
/*
* Allocate space for DMA descriptors
* (add an extra element for link descriptor)
*/
bd_ptr = dma_alloc_coherent(dev,
(bd_num + 1) * sizeof(struct tsi721_dma_desc),
&bd_phys, GFP_ATOMIC);
if (!bd_ptr)
return -ENOMEM;
bdma_chan->bd_num = bd_num;
bdma_chan->bd_phys = bd_phys;
bdma_chan->bd_base = bd_ptr;
tsi_debug(DMA, &bdma_chan->dchan.dev->device,
"DMAC%d descriptors @ %p (phys = %pad)",
bdma_chan->id, bd_ptr, &bd_phys);
/* Allocate space for descriptor status FIFO */
sts_size = ((bd_num + 1) >= TSI721_DMA_MINSTSSZ) ?
(bd_num + 1) : TSI721_DMA_MINSTSSZ;
sts_size = roundup_pow_of_two(sts_size);
sts_ptr = dma_alloc_coherent(dev,
sts_size * sizeof(struct tsi721_dma_sts),
&sts_phys, GFP_ATOMIC);
if (!sts_ptr) {
/* Free space allocated for DMA descriptors */
dma_free_coherent(dev,
(bd_num + 1) * sizeof(struct tsi721_dma_desc),
bd_ptr, bd_phys);
bdma_chan->bd_base = NULL;
return -ENOMEM;
}
bdma_chan->sts_phys = sts_phys;
bdma_chan->sts_base = sts_ptr;
bdma_chan->sts_size = sts_size;
tsi_debug(DMA, &bdma_chan->dchan.dev->device,
"DMAC%d desc status FIFO @ %p (phys = %pad) size=0x%x",
bdma_chan->id, sts_ptr, &sts_phys, sts_size);
/* Initialize DMA descriptors ring using added link descriptor */
bd_ptr[bd_num].type_id = cpu_to_le32(DTYPE3 << 29);
bd_ptr[bd_num].next_lo = cpu_to_le32((u64)bd_phys &
TSI721_DMAC_DPTRL_MASK);
bd_ptr[bd_num].next_hi = cpu_to_le32((u64)bd_phys >> 32);
/* Setup DMA descriptor pointers */
iowrite32(((u64)bd_phys >> 32),
bdma_chan->regs + TSI721_DMAC_DPTRH);
iowrite32(((u64)bd_phys & TSI721_DMAC_DPTRL_MASK),
bdma_chan->regs + TSI721_DMAC_DPTRL);
/* Setup descriptor status FIFO */
iowrite32(((u64)sts_phys >> 32),
bdma_chan->regs + TSI721_DMAC_DSBH);
iowrite32(((u64)sts_phys & TSI721_DMAC_DSBL_MASK),
bdma_chan->regs + TSI721_DMAC_DSBL);
iowrite32(TSI721_DMAC_DSSZ_SIZE(sts_size),
bdma_chan->regs + TSI721_DMAC_DSSZ);
/* Clear interrupt bits */
iowrite32(TSI721_DMAC_INT_ALL,
bdma_chan->regs + TSI721_DMAC_INT);
ioread32(bdma_chan->regs + TSI721_DMAC_INT);
#ifdef CONFIG_PCI_MSI
/* Request interrupt service if we are in MSI-X mode */
if (priv->flags & TSI721_USING_MSIX) {
int rc, idx;
idx = TSI721_VECT_DMA0_DONE + bdma_chan->id;
rc = request_irq(priv->msix[idx].vector, tsi721_bdma_msix, 0,
priv->msix[idx].irq_name, (void *)bdma_chan);
if (rc) {
tsi_debug(DMA, &bdma_chan->dchan.dev->device,
"Unable to get MSI-X for DMAC%d-DONE",
bdma_chan->id);
goto err_out;
}
idx = TSI721_VECT_DMA0_INT + bdma_chan->id;
rc = request_irq(priv->msix[idx].vector, tsi721_bdma_msix, 0,
priv->msix[idx].irq_name, (void *)bdma_chan);
if (rc) {
tsi_debug(DMA, &bdma_chan->dchan.dev->device,
"Unable to get MSI-X for DMAC%d-INT",
bdma_chan->id);
free_irq(
priv->msix[TSI721_VECT_DMA0_DONE +
bdma_chan->id].vector,
(void *)bdma_chan);
}
err_out:
if (rc) {
/* Free space allocated for DMA descriptors */
dma_free_coherent(dev,
(bd_num + 1) * sizeof(struct tsi721_dma_desc),
bd_ptr, bd_phys);
bdma_chan->bd_base = NULL;
/* Free space allocated for status descriptors */
dma_free_coherent(dev,
sts_size * sizeof(struct tsi721_dma_sts),
sts_ptr, sts_phys);
bdma_chan->sts_base = NULL;
return -EIO;
}
}
#endif /* CONFIG_PCI_MSI */
/* Toggle DMA channel initialization */
iowrite32(TSI721_DMAC_CTL_INIT, bdma_chan->regs + TSI721_DMAC_CTL);
ioread32(bdma_chan->regs + TSI721_DMAC_CTL);
bdma_chan->wr_count = bdma_chan->wr_count_next = 0;
bdma_chan->sts_rdptr = 0;
udelay(10);
return 0;
}