/* Start DMA operation */
iowrite32(rd_count + 2,
priv->regs + TSI721_DMAC_DWRCNT(TSI721_DMACH_MAINT));
- (void)ioread32(priv->regs + TSI721_DMAC_DWRCNT(TSI721_DMACH_MAINT));
+ ioread32(priv->regs + TSI721_DMAC_DWRCNT(TSI721_DMACH_MAINT));
i = 0;
/* Wait until DMA transfer is finished */
while ((ch_stat = ioread32(priv->regs +
TSI721_DMAC_STS(TSI721_DMACH_MAINT))) & TSI721_DMAC_STS_RUN) {
- udelay(10);
- i++;
- if (i >= 5000000) {
+ udelay(1);
+ if (++i >= 5000000) {
dev_dbg(&priv->pdev->dev,
"%s : DMA[%d] read timeout ch_status=%x\n",
__func__, TSI721_DMACH_MAINT, ch_stat);
if (!do_wr)
*data = 0xffffffff;
- err = -EFAULT;
+ err = -EIO;
goto err_out;
}
}
udelay(1);
if (!do_wr)
*data = 0xffffffff;
- err = -EFAULT;
+ err = -EIO;
goto err_out;
}
{
struct tsi721_device *priv = container_of(work, struct tsi721_device,
pw_work);
- unsigned long flags;
u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)]; /* Use full size PW message
buffer for RIO layer */
/*
* Process port-write messages
*/
- spin_lock_irqsave(&priv->pw_fifo_lock, flags);
- while (kfifo_out(&priv->pw_fifo, (unsigned char *)msg_buffer,
- TSI721_RIO_PW_MSG_SIZE)) {
+ while (kfifo_out_spinlocked(&priv->pw_fifo, (unsigned char *)msg_buffer,
+ TSI721_RIO_PW_MSG_SIZE, &priv->pw_fifo_lock)) {
/* Process one message */
- spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
#ifdef DEBUG_PW
{
u32 i;
#endif
/* Pass the port-write message to RIO core for processing */
rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
- spin_lock_irqsave(&priv->pw_fifo_lock, flags);
}
- spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
}
/**
priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
}
-/**
- * tsi721_srio_msix - Tsi721 MSI-X SRIO MAC interrupt handler
- * @irq: Linux interrupt number
- * @ptr: Pointer to interrupt-specific data (mport structure)
- *
- * Handles Tsi721 interrupts from SRIO MAC.
- */
-static irqreturn_t tsi721_srio_msix(int irq, void *ptr)
-{
- struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv;
- u32 srio_int;
-
- /* Service SRIO MAC interrupts */
- srio_int = ioread32(priv->regs + TSI721_RIO_EM_INT_STAT);
- if (srio_int & TSI721_RIO_EM_INT_STAT_PW_RX)
- tsi721_pw_handler((struct rio_mport *)ptr);
-
- return IRQ_HANDLED;
-}
-
-/**
- * tsi721_sr2pc_ch_msix - Tsi721 MSI-X SR2PC Channel interrupt handler
- * @irq: Linux interrupt number
- * @ptr: Pointer to interrupt-specific data (mport structure)
- *
- * Handles Tsi721 interrupts from SR2PC Channel.
- * NOTE: At this moment services only one SR2PC channel associated with inbound
- * doorbells.
- */
-static irqreturn_t tsi721_sr2pc_ch_msix(int irq, void *ptr)
-{
- struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv;
- u32 sr_ch_int;
-
- /* Service Inbound DB interrupt from SR2PC channel */
- sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
- if (sr_ch_int & TSI721_SR_CHINT_IDBQRCV)
- tsi721_dbell_handler((struct rio_mport *)ptr);
-
- /* Clear interrupts */
- iowrite32(sr_ch_int, priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
- /* Read back to ensure that interrupt was cleared */
- sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
-
- return IRQ_HANDLED;
-}
-
-/**
- * tsi721_omsg_msix - MSI-X interrupt handler for outbound messaging
- * @irq: Linux interrupt number
- * @ptr: Pointer to interrupt-specific data (mport structure)
- *
- * Handles outbound messaging interrupts signaled using MSI-X.
- */
-static irqreturn_t tsi721_omsg_msix(int irq, void *ptr)
-{
- struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv;
- int mbox;
-
- mbox = (irq - priv->msix[TSI721_VECT_OMB0_DONE].vector) % RIO_MAX_MBOX;
- tsi721_omsg_handler(priv, mbox);
- return IRQ_HANDLED;
-}
-
-/**
- * tsi721_imsg_msix - MSI-X interrupt handler for inbound messaging
- * @irq: Linux interrupt number
- * @ptr: Pointer to interrupt-specific data (mport structure)
- *
- * Handles inbound messaging interrupts signaled using MSI-X.
- */
-static irqreturn_t tsi721_imsg_msix(int irq, void *ptr)
-{
- struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv;
- int mbox;
-
- mbox = (irq - priv->msix[TSI721_VECT_IMB0_RCV].vector) % RIO_MAX_MBOX;
- tsi721_imsg_handler(priv, mbox + 4);
- return IRQ_HANDLED;
-}
-
/**
* tsi721_irqhandler - Tsi721 interrupt handler
* @irq: Linux interrupt number
/* Clear interrupts */
iowrite32(intval,
priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
- (void)ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
+ ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
}
}
TSI721_DEV_INT_SMSG_CH;
iowrite32(intr, priv->regs + TSI721_DEV_INTE);
- (void)ioread32(priv->regs + TSI721_DEV_INTE);
+ ioread32(priv->regs + TSI721_DEV_INTE);
+}
+
+#ifdef CONFIG_PCI_MSI
+/**
+ * tsi721_omsg_msix - MSI-X interrupt handler for outbound messaging
+ * @irq: Linux interrupt number
+ * @ptr: Pointer to interrupt-specific data (mport structure)
+ *
+ * Handles outbound messaging interrupts signaled using MSI-X.
+ */
+static irqreturn_t tsi721_omsg_msix(int irq, void *ptr)
+{
+ struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv;
+ int mbox;
+
+ mbox = (irq - priv->msix[TSI721_VECT_OMB0_DONE].vector) % RIO_MAX_MBOX;
+ tsi721_omsg_handler(priv, mbox);
+ return IRQ_HANDLED;
+}
+
+/**
+ * tsi721_imsg_msix - MSI-X interrupt handler for inbound messaging
+ * @irq: Linux interrupt number
+ * @ptr: Pointer to interrupt-specific data (mport structure)
+ *
+ * Handles inbound messaging interrupts signaled using MSI-X.
+ */
+static irqreturn_t tsi721_imsg_msix(int irq, void *ptr)
+{
+ struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv;
+ int mbox;
+
+ mbox = (irq - priv->msix[TSI721_VECT_IMB0_RCV].vector) % RIO_MAX_MBOX;
+ tsi721_imsg_handler(priv, mbox + 4);
+ return IRQ_HANDLED;
+}
+
+/**
+ * tsi721_srio_msix - Tsi721 MSI-X SRIO MAC interrupt handler
+ * @irq: Linux interrupt number
+ * @ptr: Pointer to interrupt-specific data (mport structure)
+ *
+ * Handles Tsi721 interrupts from SRIO MAC.
+ */
+static irqreturn_t tsi721_srio_msix(int irq, void *ptr)
+{
+ struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv;
+ u32 srio_int;
+
+ /* Service SRIO MAC interrupts */
+ srio_int = ioread32(priv->regs + TSI721_RIO_EM_INT_STAT);
+ if (srio_int & TSI721_RIO_EM_INT_STAT_PW_RX)
+ tsi721_pw_handler((struct rio_mport *)ptr);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * tsi721_sr2pc_ch_msix - Tsi721 MSI-X SR2PC Channel interrupt handler
+ * @irq: Linux interrupt number
+ * @ptr: Pointer to interrupt-specific data (mport structure)
+ *
+ * Handles Tsi721 interrupts from SR2PC Channel.
+ * NOTE: At this moment services only one SR2PC channel associated with inbound
+ * doorbells.
+ */
+static irqreturn_t tsi721_sr2pc_ch_msix(int irq, void *ptr)
+{
+ struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv;
+ u32 sr_ch_int;
+
+ /* Service Inbound DB interrupt from SR2PC channel */
+ sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
+ if (sr_ch_int & TSI721_SR_CHINT_IDBQRCV)
+ tsi721_dbell_handler((struct rio_mport *)ptr);
+
+ /* Clear interrupts */
+ iowrite32(sr_ch_int, priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
+ /* Read back to ensure that interrupt was cleared */
+ sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
+
+ return IRQ_HANDLED;
}
/**
err = request_irq(priv->msix[TSI721_VECT_PWRX].vector,
tsi721_srio_msix, 0,
priv->msix[TSI721_VECT_PWRX].irq_name, (void *)mport);
-out:
- return err;
-}
-
-static int tsi721_request_irq(struct rio_mport *mport)
-{
- struct tsi721_device *priv = mport->priv;
- int err;
-
- if (priv->flags & TSI721_USING_MSIX)
- err = tsi721_request_msix(mport);
- else
- err = request_irq(priv->pdev->irq, tsi721_irqhandler,
- (priv->flags & TSI721_USING_MSI) ? 0 : IRQF_SHARED,
- DRV_NAME, (void *)mport);
-
if (err)
- dev_err(&priv->pdev->dev,
- "Unable to allocate interrupt, Error: %d\n", err);
-
+ free_irq(
+ priv->msix[TSI721_VECT_IDB].vector,
+ (void *)mport);
+out:
return err;
}
return 0;
}
+#endif /* CONFIG_PCI_MSI */
+
+static int tsi721_request_irq(struct rio_mport *mport)
+{
+ struct tsi721_device *priv = mport->priv;
+ int err;
+
+#ifdef CONFIG_PCI_MSI
+ if (priv->flags & TSI721_USING_MSIX)
+ err = tsi721_request_msix(mport);
+ else
+#endif
+ err = request_irq(priv->pdev->irq, tsi721_irqhandler,
+ (priv->flags & TSI721_USING_MSI) ? 0 : IRQF_SHARED,
+ DRV_NAME, (void *)mport);
+
+ if (err)
+ dev_err(&priv->pdev->dev,
+ "Unable to allocate interrupt, Error: %d\n", err);
+
+ return err;
+}
/**
* tsi721_init_pc2sr_mapping - initializes outbound (PCIe->SRIO)
iowrite32(TSI721_DMAC_INT_ALL,
priv->regs + TSI721_DMAC_INT(chnum));
- (void)ioread32(priv->regs + TSI721_DMAC_INT(chnum));
+ ioread32(priv->regs + TSI721_DMAC_INT(chnum));
/* Toggle DMA channel initialization */
iowrite32(TSI721_DMAC_CTL_INIT, priv->regs + TSI721_DMAC_CTL(chnum));
- (void)ioread32(priv->regs + TSI721_DMAC_CTL(chnum));
+ ioread32(priv->regs + TSI721_DMAC_CTL(chnum));
udelay(10);
return 0;
/* Set new write count value */
iowrite32(priv->omsg_ring[mbox].wr_count,
priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
- (void)ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
+ ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
return 0;
}
while (sts_ptr[j]) {
for (i = 0; i < 8 && sts_ptr[j]; i++, j++) {
prev_ptr = last_ptr;
- last_ptr = sts_ptr[j];
+ last_ptr = le64_to_cpu(sts_ptr[j]);
sts_ptr[j] = 0;
}
priv->regs + TSI721_OBDMAC_INT(ch));
iowrite32(TSI721_OBDMAC_CTL_INIT,
priv->regs + TSI721_OBDMAC_CTL(ch));
- (void)ioread32(priv->regs + TSI721_OBDMAC_CTL(ch));
+ ioread32(priv->regs + TSI721_OBDMAC_CTL(ch));
/* Inform upper level to clear all pending tx slots */
if (priv->mport->outb_msg[ch].mcback)
/* Synch tx_slot tracking */
iowrite32(priv->omsg_ring[ch].tx_slot,
priv->regs + TSI721_OBDMAC_DRDCNT(ch));
- (void)ioread32(priv->regs + TSI721_OBDMAC_DRDCNT(ch));
+ ioread32(priv->regs + TSI721_OBDMAC_DRDCNT(ch));
priv->omsg_ring[ch].wr_count = priv->omsg_ring[ch].tx_slot;
priv->omsg_ring[ch].sts_rdptr = 0;
}
goto out_buf;
}
- memset(priv->omsg_ring[mbox].omd_base, 0,
- (entries + 1) * sizeof(struct tsi721_omsg_desc));
priv->omsg_ring[mbox].tx_slot = 0;
/* Outbound message descriptor status FIFO allocation */
/* Enable interrupts */
+#ifdef CONFIG_PCI_MSI
if (priv->flags & TSI721_USING_MSIX) {
/* Request interrupt service if we are in MSI-X mode */
rc = request_irq(
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);
/* Initialize Outbound Message engine */
iowrite32(TSI721_OBDMAC_CTL_INIT, priv->regs + TSI721_OBDMAC_CTL(mbox));
- (void)ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(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_phys);
priv->omsg_ring[mbox].sts_base = NULL;
+#endif /* CONFIG_PCI_MSI */
out_desc:
dma_free_coherent(&priv->pdev->dev,
tsi721_omsg_interrupt_disable(priv, mbox, TSI721_OBDMAC_INT_ALL);
+#ifdef CONFIG_PCI_MSI
if (priv->flags & TSI721_USING_MSIX) {
free_irq(priv->msix[TSI721_VECT_OMB0_DONE + mbox].vector,
(void *)mport);
free_irq(priv->msix[TSI721_VECT_OMB0_INT + mbox].vector,
(void *)mport);
}
+#endif /* CONFIG_PCI_MSI */
/* Free OMSG Descriptor Status FIFO */
dma_free_coherent(&priv->pdev->dev,
u32 mbox = ch - 4;
u32 imsg_int;
+ spin_lock(&priv->imsg_ring[mbox].lock);
+
imsg_int = ioread32(priv->regs + TSI721_IBDMAC_INT(ch));
if (imsg_int & TSI721_IBDMAC_INT_SRTO)
ch_inte |= TSI721_INT_IMSG_CHAN(ch);
iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE);
}
+
+ spin_unlock(&priv->imsg_ring[mbox].lock);
}
/**
priv->imsg_ring[mbox].fq_wrptr = 0;
for (i = 0; i < priv->imsg_ring[mbox].size; i++)
priv->imsg_ring[mbox].imq_base[i] = NULL;
+ spin_lock_init(&priv->imsg_ring[mbox].lock);
/* Allocate buffers for incoming messages */
priv->imsg_ring[mbox].buf_base =
/* Enable interrupts */
+#ifdef CONFIG_PCI_MSI
if (priv->flags & TSI721_USING_MSIX) {
/* Request interrupt service if we are in MSI-X mode */
rc = request_irq(priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector,
dev_dbg(&priv->pdev->dev,
"Unable to allocate MSI-X interrupt for "
"IBOX%d-INT\n", mbox);
+ free_irq(
+ priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector,
+ (void *)mport);
goto out_desc;
}
}
+#endif /* CONFIG_PCI_MSI */
tsi721_imsg_interrupt_enable(priv, ch, TSI721_IBDMAC_INT_ALL);
/* Initialize Inbound Message Engine */
iowrite32(TSI721_IBDMAC_CTL_INIT, priv->regs + TSI721_IBDMAC_CTL(ch));
- (void)ioread32(priv->regs + TSI721_IBDMAC_CTL(ch));
+ ioread32(priv->regs + TSI721_IBDMAC_CTL(ch));
udelay(10);
priv->imsg_ring[mbox].fq_wrptr = entries - 1;
iowrite32(entries - 1, priv->regs + TSI721_IBDMAC_FQWP(ch));
priv->imsg_init[mbox] = 1;
return 0;
+#ifdef CONFIG_PCI_MSI
out_desc:
dma_free_coherent(&priv->pdev->dev,
priv->imsg_ring[mbox].size * sizeof(struct tsi721_imsg_desc),
priv->imsg_ring[mbox].imd_phys);
priv->imsg_ring[mbox].imd_base = NULL;
+#endif /* CONFIG_PCI_MSI */
out_dma:
dma_free_coherent(&priv->pdev->dev,
/* Disable Interrupts */
tsi721_imsg_interrupt_disable(priv, ch, TSI721_OBDMAC_INT_MASK);
+#ifdef CONFIG_PCI_MSI
if (priv->flags & TSI721_USING_MSIX) {
free_irq(priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector,
(void *)mport);
free_irq(priv->msix[TSI721_VECT_IMB0_INT + mbox].vector,
(void *)mport);
}
+#endif /* CONFIG_PCI_MSI */
/* Clear Inbound Buffer Queue */
for (rx_slot = 0; rx_slot < priv->imsg_ring[mbox].size; rx_slot++)
/* Hook up interrupt handler */
+#ifdef CONFIG_PCI_MSI
if (!tsi721_enable_msix(priv))
priv->flags |= TSI721_USING_MSIX;
else if (!pci_enable_msi(pdev))
else
dev_info(&pdev->dev,
"MSI/MSI-X is not available. Using legacy INTx.\n");
+#endif /* CONFIG_PCI_MSI */
err = tsi721_request_irq(mport);