diff options
author | Alexandre Bounine <alexandre.bounine@idt.com> | 2016-03-22 17:26:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-22 18:36:02 -0400 |
commit | 2ece1caf668f183d0606ea9fc85a1083d42b5b3a (patch) | |
tree | fa2300a954d25cfaa592ca10228e044742ac1bae /drivers/rapidio/devices | |
parent | 9a0b062742e7e039273c0c2ba4b96ad9ec7e7d8f (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.c | 42 |
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 | ||
1587 | no_sts_update: | 1601 | no_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 | ||