in devices/tsi721.c [1873:2047]
static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id,
int mbox, int entries)
{
struct tsi721_device *priv = mport->priv;
struct tsi721_omsg_desc *bd_ptr;
int i, rc = 0;
if ((entries < TSI721_OMSGD_MIN_RING_SIZE) ||
(entries > (TSI721_OMSGD_RING_SIZE)) ||
(!is_power_of_2(entries)) || mbox >= RIO_MAX_MBOX) {
rc = -EINVAL;
goto out;
}
if ((mbox_sel & (1 << mbox)) == 0) {
rc = -ENODEV;
goto out;
}
priv->omsg_ring[mbox].dev_id = dev_id;
priv->omsg_ring[mbox].size = entries;
priv->omsg_ring[mbox].sts_rdptr = 0;
spin_lock_init(&priv->omsg_ring[mbox].lock);
/* Outbound Msg Buffer allocation based on
the number of maximum descriptor entries */
for (i = 0; i < entries; i++) {
priv->omsg_ring[mbox].omq_base[i] =
dma_alloc_coherent(
&priv->pdev->dev, TSI721_MSG_BUFFER_SIZE,
&priv->omsg_ring[mbox].omq_phys[i],
GFP_KERNEL);
if (priv->omsg_ring[mbox].omq_base[i] == NULL) {
tsi_debug(OMSG, &priv->pdev->dev,
"ENOMEM for OB_MSG_%d data buffer", mbox);
rc = -ENOMEM;
goto out_buf;
}
}
/* Outbound message descriptor allocation */
priv->omsg_ring[mbox].omd_base = dma_alloc_coherent(
&priv->pdev->dev,
(entries + 1) * sizeof(struct tsi721_omsg_desc),
&priv->omsg_ring[mbox].omd_phys, GFP_KERNEL);
if (priv->omsg_ring[mbox].omd_base == NULL) {
tsi_debug(OMSG, &priv->pdev->dev,
"ENOMEM for OB_MSG_%d descriptor memory", mbox);
rc = -ENOMEM;
goto out_buf;
}
priv->omsg_ring[mbox].tx_slot = 0;
/* Outbound message descriptor status FIFO allocation */
priv->omsg_ring[mbox].sts_size = roundup_pow_of_two(entries + 1);
priv->omsg_ring[mbox].sts_base = dma_alloc_coherent(&priv->pdev->dev,
priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts),
&priv->omsg_ring[mbox].sts_phys,
GFP_KERNEL);
if (priv->omsg_ring[mbox].sts_base == NULL) {
tsi_debug(OMSG, &priv->pdev->dev,
"ENOMEM for OB_MSG_%d status FIFO", mbox);
rc = -ENOMEM;
goto out_desc;
}
/*
* Configure Outbound Messaging Engine
*/
/* Setup Outbound Message descriptor pointer */
iowrite32(((u64)priv->omsg_ring[mbox].omd_phys >> 32),
priv->regs + TSI721_OBDMAC_DPTRH(mbox));
iowrite32(((u64)priv->omsg_ring[mbox].omd_phys &
TSI721_OBDMAC_DPTRL_MASK),
priv->regs + TSI721_OBDMAC_DPTRL(mbox));
/* Setup Outbound Message descriptor status FIFO */
iowrite32(((u64)priv->omsg_ring[mbox].sts_phys >> 32),
priv->regs + TSI721_OBDMAC_DSBH(mbox));
iowrite32(((u64)priv->omsg_ring[mbox].sts_phys &
TSI721_OBDMAC_DSBL_MASK),
priv->regs + TSI721_OBDMAC_DSBL(mbox));
iowrite32(TSI721_DMAC_DSSZ_SIZE(priv->omsg_ring[mbox].sts_size),
priv->regs + (u32)TSI721_OBDMAC_DSSZ(mbox));
/* Enable interrupts */
#ifdef CONFIG_PCI_MSI
if (priv->flags & TSI721_USING_MSIX) {
int idx = TSI721_VECT_OMB0_DONE + mbox;
/* Request interrupt service if we are in MSI-X mode */
rc = request_irq(priv->msix[idx].vector, tsi721_omsg_msix, 0,
priv->msix[idx].irq_name, (void *)priv);
if (rc) {
tsi_debug(OMSG, &priv->pdev->dev,
"Unable to get MSI-X IRQ for OBOX%d-DONE",
mbox);
goto out_stat;
}
idx = TSI721_VECT_OMB0_INT + mbox;
rc = request_irq(priv->msix[idx].vector, tsi721_omsg_msix, 0,
priv->msix[idx].irq_name, (void *)priv);
if (rc) {
tsi_debug(OMSG, &priv->pdev->dev,
"Unable to get MSI-X IRQ for MBOX%d-INT", mbox);
idx = TSI721_VECT_OMB0_DONE + mbox;
free_irq(priv->msix[idx].vector, (void *)priv);
goto out_stat;
}
}
#endif /* CONFIG_PCI_MSI */
tsi721_omsg_interrupt_enable(priv, mbox, TSI721_OBDMAC_INT_ALL);
/* Initialize Outbound Message descriptors ring */
bd_ptr = priv->omsg_ring[mbox].omd_base;
bd_ptr[entries].type_id = cpu_to_le32(DTYPE5 << 29);
bd_ptr[entries].msg_info = 0;
bd_ptr[entries].next_lo =
cpu_to_le32((u64)priv->omsg_ring[mbox].omd_phys &
TSI721_OBDMAC_DPTRL_MASK);
bd_ptr[entries].next_hi =
cpu_to_le32((u64)priv->omsg_ring[mbox].omd_phys >> 32);
priv->omsg_ring[mbox].wr_count = 0;
mb();
/* Initialize Outbound Message engine */
iowrite32(TSI721_OBDMAC_CTL_RETRY_THR | TSI721_OBDMAC_CTL_INIT,
priv->regs + TSI721_OBDMAC_CTL(mbox));
ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
udelay(10);
priv->omsg_init[mbox] = 1;
return 0;
#ifdef CONFIG_PCI_MSI
out_stat:
dma_free_coherent(&priv->pdev->dev,
priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts),
priv->omsg_ring[mbox].sts_base,
priv->omsg_ring[mbox].sts_phys);
priv->omsg_ring[mbox].sts_base = NULL;
#endif /* CONFIG_PCI_MSI */
out_desc:
dma_free_coherent(&priv->pdev->dev,
(entries + 1) * sizeof(struct tsi721_omsg_desc),
priv->omsg_ring[mbox].omd_base,
priv->omsg_ring[mbox].omd_phys);
priv->omsg_ring[mbox].omd_base = NULL;
out_buf:
for (i = 0; i < priv->omsg_ring[mbox].size; i++) {
if (priv->omsg_ring[mbox].omq_base[i]) {
dma_free_coherent(&priv->pdev->dev,
TSI721_MSG_BUFFER_SIZE,
priv->omsg_ring[mbox].omq_base[i],
priv->omsg_ring[mbox].omq_phys[i]);
priv->omsg_ring[mbox].omq_base[i] = NULL;
}
}
out:
return rc;
}