summaryrefslogtreecommitdiffstats
path: root/drivers/rapidio/devices
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2016-03-22 17:26:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-22 18:36:02 -0400
commit2ece1caf668f183d0606ea9fc85a1083d42b5b3a (patch)
treefa2300a954d25cfaa592ca10228e044742ac1bae /drivers/rapidio/devices
parent9a0b062742e7e039273c0c2ba4b96ad9ec7e7d8f (diff)
rapidio/tsi721: fix locking in OB_MSG processing
- Add spinlock protection into outbound message queuing routine. - Change outbound message interrupt handler to avoid deadlock when calling registered callback routine. - Allow infinite retries for outbound messages to avoid retry threshold error signaling in systems with nodes that have slow message receive queue processing. Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Cc: Matt Porter <mporter@kernel.crashing.org> Cc: Aurelien Jacquiot <a-jacquiot@ti.com> Cc: Andre van Herk <andre.van.herk@prodrive-technologies.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rapidio/devices')
-rw-r--r--drivers/rapidio/devices/tsi721.c42
1 files changed, 30 insertions, 12 deletions
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c
index 5e1d52674e17..822fd4bebf75 100644
--- a/drivers/rapidio/devices/tsi721.c
+++ b/drivers/rapidio/devices/tsi721.c
@@ -1453,11 +1453,14 @@ tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
1453 struct tsi721_device *priv = mport->priv; 1453 struct tsi721_device *priv = mport->priv;
1454 struct tsi721_omsg_desc *desc; 1454 struct tsi721_omsg_desc *desc;
1455 u32 tx_slot; 1455 u32 tx_slot;
1456 unsigned long flags;
1456 1457
1457 if (!priv->omsg_init[mbox] || 1458 if (!priv->omsg_init[mbox] ||
1458 len > TSI721_MSG_MAX_SIZE || len < 8) 1459 len > TSI721_MSG_MAX_SIZE || len < 8)
1459 return -EINVAL; 1460 return -EINVAL;
1460 1461
1462 spin_lock_irqsave(&priv->omsg_ring[mbox].lock, flags);
1463
1461 tx_slot = priv->omsg_ring[mbox].tx_slot; 1464 tx_slot = priv->omsg_ring[mbox].tx_slot;
1462 1465
1463 /* Copy copy message into transfer buffer */ 1466 /* Copy copy message into transfer buffer */
@@ -1469,9 +1472,11 @@ tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
1469 /* Build descriptor associated with buffer */ 1472 /* Build descriptor associated with buffer */
1470 desc = priv->omsg_ring[mbox].omd_base; 1473 desc = priv->omsg_ring[mbox].omd_base;
1471 desc[tx_slot].type_id = cpu_to_le32((DTYPE4 << 29) | rdev->destid); 1474 desc[tx_slot].type_id = cpu_to_le32((DTYPE4 << 29) | rdev->destid);
1475#ifdef TSI721_OMSG_DESC_INT
1476 /* Request IOF_DONE interrupt generation for each N-th frame in queue */
1472 if (tx_slot % 4 == 0) 1477 if (tx_slot % 4 == 0)
1473 desc[tx_slot].type_id |= cpu_to_le32(TSI721_OMD_IOF); 1478 desc[tx_slot].type_id |= cpu_to_le32(TSI721_OMD_IOF);
1474 1479#endif
1475 desc[tx_slot].msg_info = 1480 desc[tx_slot].msg_info =
1476 cpu_to_le32((mport->sys_size << 26) | (mbox << 22) | 1481 cpu_to_le32((mport->sys_size << 26) | (mbox << 22) |
1477 (0xe << 12) | (len & 0xff8)); 1482 (0xe << 12) | (len & 0xff8));
@@ -1497,6 +1502,8 @@ tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
1497 priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); 1502 priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
1498 ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); 1503 ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
1499 1504
1505 spin_unlock_irqrestore(&priv->omsg_ring[mbox].lock, flags);
1506
1500 return 0; 1507 return 0;
1501} 1508}
1502 1509
@@ -1511,6 +1518,9 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch)
1511{ 1518{
1512 u32 omsg_int; 1519 u32 omsg_int;
1513 struct rio_mport *mport = &priv->mport; 1520 struct rio_mport *mport = &priv->mport;
1521 void *dev_id = NULL;
1522 u32 tx_slot = 0xffffffff;
1523 int do_callback = 0;
1514 1524
1515 spin_lock(&priv->omsg_ring[ch].lock); 1525 spin_lock(&priv->omsg_ring[ch].lock);
1516 1526
@@ -1524,7 +1534,6 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch)
1524 u32 srd_ptr; 1534 u32 srd_ptr;
1525 u64 *sts_ptr, last_ptr = 0, prev_ptr = 0; 1535 u64 *sts_ptr, last_ptr = 0, prev_ptr = 0;
1526 int i, j; 1536 int i, j;
1527 u32 tx_slot;
1528 1537
1529 /* 1538 /*
1530 * Find last successfully processed descriptor 1539 * Find last successfully processed descriptor
@@ -1574,14 +1583,19 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch)
1574 goto no_sts_update; 1583 goto no_sts_update;
1575 } 1584 }
1576 1585
1586 if (tx_slot >= priv->omsg_ring[ch].size)
1587 dev_dbg(&priv->pdev->dev,
1588 "OB_MSG tx_slot=%x > size=%x",
1589 tx_slot, priv->omsg_ring[ch].size);
1590 WARN_ON(tx_slot >= priv->omsg_ring[ch].size);
1591
1577 /* Move slot index to the next message to be sent */ 1592 /* Move slot index to the next message to be sent */
1578 ++tx_slot; 1593 ++tx_slot;
1579 if (tx_slot == priv->omsg_ring[ch].size) 1594 if (tx_slot == priv->omsg_ring[ch].size)
1580 tx_slot = 0; 1595 tx_slot = 0;
1581 BUG_ON(tx_slot >= priv->omsg_ring[ch].size); 1596
1582 mport->outb_msg[ch].mcback(mport, 1597 dev_id = priv->omsg_ring[ch].dev_id;
1583 priv->omsg_ring[ch].dev_id, ch, 1598 do_callback = 1;
1584 tx_slot);
1585 } 1599 }
1586 1600
1587no_sts_update: 1601no_sts_update:
@@ -1597,15 +1611,15 @@ no_sts_update:
1597 1611
1598 iowrite32(TSI721_OBDMAC_INT_ERROR, 1612 iowrite32(TSI721_OBDMAC_INT_ERROR,
1599 priv->regs + TSI721_OBDMAC_INT(ch)); 1613 priv->regs + TSI721_OBDMAC_INT(ch));
1600 iowrite32(TSI721_OBDMAC_CTL_INIT, 1614 iowrite32(TSI721_OBDMAC_CTL_RETRY_THR | TSI721_OBDMAC_CTL_INIT,
1601 priv->regs + TSI721_OBDMAC_CTL(ch)); 1615 priv->regs + TSI721_OBDMAC_CTL(ch));
1602 ioread32(priv->regs + TSI721_OBDMAC_CTL(ch)); 1616 ioread32(priv->regs + TSI721_OBDMAC_CTL(ch));
1603 1617
1604 /* Inform upper level to clear all pending tx slots */ 1618 /* Inform upper level to clear all pending tx slots */
1605 if (mport->outb_msg[ch].mcback) 1619 dev_id = priv->omsg_ring[ch].dev_id;
1606 mport->outb_msg[ch].mcback(mport, 1620 tx_slot = priv->omsg_ring[ch].tx_slot;
1607 priv->omsg_ring[ch].dev_id, ch, 1621 do_callback = 1;
1608 priv->omsg_ring[ch].tx_slot); 1622
1609 /* Synch tx_slot tracking */ 1623 /* Synch tx_slot tracking */
1610 iowrite32(priv->omsg_ring[ch].tx_slot, 1624 iowrite32(priv->omsg_ring[ch].tx_slot,
1611 priv->regs + TSI721_OBDMAC_DRDCNT(ch)); 1625 priv->regs + TSI721_OBDMAC_DRDCNT(ch));
@@ -1627,6 +1641,9 @@ no_sts_update:
1627 } 1641 }
1628 1642
1629 spin_unlock(&priv->omsg_ring[ch].lock); 1643 spin_unlock(&priv->omsg_ring[ch].lock);
1644
1645 if (mport->outb_msg[ch].mcback && do_callback)
1646 mport->outb_msg[ch].mcback(mport, dev_id, ch, tx_slot);
1630} 1647}
1631 1648
1632/** 1649/**
@@ -1768,7 +1785,8 @@ static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id,
1768 mb(); 1785 mb();
1769 1786
1770 /* Initialize Outbound Message engine */ 1787 /* Initialize Outbound Message engine */
1771 iowrite32(TSI721_OBDMAC_CTL_INIT, priv->regs + TSI721_OBDMAC_CTL(mbox)); 1788 iowrite32(TSI721_OBDMAC_CTL_RETRY_THR | TSI721_OBDMAC_CTL_INIT,
1789 priv->regs + TSI721_OBDMAC_CTL(mbox));
1772 ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); 1790 ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
1773 udelay(10); 1791 udelay(10);
1774 1792