Commit 2ece1caf authored by Alexandre Bounine's avatar Alexandre Bounine Committed by Linus Torvalds

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: default avatarAlexandre 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 9a0b0627
...@@ -1453,11 +1453,14 @@ tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, ...@@ -1453,11 +1453,14 @@ tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
struct tsi721_device *priv = mport->priv; struct tsi721_device *priv = mport->priv;
struct tsi721_omsg_desc *desc; struct tsi721_omsg_desc *desc;
u32 tx_slot; u32 tx_slot;
unsigned long flags;
if (!priv->omsg_init[mbox] || if (!priv->omsg_init[mbox] ||
len > TSI721_MSG_MAX_SIZE || len < 8) len > TSI721_MSG_MAX_SIZE || len < 8)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&priv->omsg_ring[mbox].lock, flags);
tx_slot = priv->omsg_ring[mbox].tx_slot; tx_slot = priv->omsg_ring[mbox].tx_slot;
/* Copy copy message into transfer buffer */ /* 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,9 +1472,11 @@ tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
/* Build descriptor associated with buffer */ /* Build descriptor associated with buffer */
desc = priv->omsg_ring[mbox].omd_base; desc = priv->omsg_ring[mbox].omd_base;
desc[tx_slot].type_id = cpu_to_le32((DTYPE4 << 29) | rdev->destid); desc[tx_slot].type_id = cpu_to_le32((DTYPE4 << 29) | rdev->destid);
#ifdef TSI721_OMSG_DESC_INT
/* Request IOF_DONE interrupt generation for each N-th frame in queue */
if (tx_slot % 4 == 0) if (tx_slot % 4 == 0)
desc[tx_slot].type_id |= cpu_to_le32(TSI721_OMD_IOF); desc[tx_slot].type_id |= cpu_to_le32(TSI721_OMD_IOF);
#endif
desc[tx_slot].msg_info = desc[tx_slot].msg_info =
cpu_to_le32((mport->sys_size << 26) | (mbox << 22) | cpu_to_le32((mport->sys_size << 26) | (mbox << 22) |
(0xe << 12) | (len & 0xff8)); (0xe << 12) | (len & 0xff8));
...@@ -1497,6 +1502,8 @@ tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, ...@@ -1497,6 +1502,8 @@ tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
spin_unlock_irqrestore(&priv->omsg_ring[mbox].lock, flags);
return 0; return 0;
} }
...@@ -1511,6 +1518,9 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch) ...@@ -1511,6 +1518,9 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch)
{ {
u32 omsg_int; u32 omsg_int;
struct rio_mport *mport = &priv->mport; struct rio_mport *mport = &priv->mport;
void *dev_id = NULL;
u32 tx_slot = 0xffffffff;
int do_callback = 0;
spin_lock(&priv->omsg_ring[ch].lock); spin_lock(&priv->omsg_ring[ch].lock);
...@@ -1524,7 +1534,6 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch) ...@@ -1524,7 +1534,6 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch)
u32 srd_ptr; u32 srd_ptr;
u64 *sts_ptr, last_ptr = 0, prev_ptr = 0; u64 *sts_ptr, last_ptr = 0, prev_ptr = 0;
int i, j; int i, j;
u32 tx_slot;
/* /*
* Find last successfully processed descriptor * Find last successfully processed descriptor
...@@ -1574,14 +1583,19 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch) ...@@ -1574,14 +1583,19 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch)
goto no_sts_update; goto no_sts_update;
} }
if (tx_slot >= priv->omsg_ring[ch].size)
dev_dbg(&priv->pdev->dev,
"OB_MSG tx_slot=%x > size=%x",
tx_slot, priv->omsg_ring[ch].size);
WARN_ON(tx_slot >= priv->omsg_ring[ch].size);
/* Move slot index to the next message to be sent */ /* Move slot index to the next message to be sent */
++tx_slot; ++tx_slot;
if (tx_slot == priv->omsg_ring[ch].size) if (tx_slot == priv->omsg_ring[ch].size)
tx_slot = 0; tx_slot = 0;
BUG_ON(tx_slot >= priv->omsg_ring[ch].size);
mport->outb_msg[ch].mcback(mport, dev_id = priv->omsg_ring[ch].dev_id;
priv->omsg_ring[ch].dev_id, ch, do_callback = 1;
tx_slot);
} }
no_sts_update: no_sts_update:
...@@ -1597,15 +1611,15 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch) ...@@ -1597,15 +1611,15 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch)
iowrite32(TSI721_OBDMAC_INT_ERROR, iowrite32(TSI721_OBDMAC_INT_ERROR,
priv->regs + TSI721_OBDMAC_INT(ch)); priv->regs + TSI721_OBDMAC_INT(ch));
iowrite32(TSI721_OBDMAC_CTL_INIT, iowrite32(TSI721_OBDMAC_CTL_RETRY_THR | TSI721_OBDMAC_CTL_INIT,
priv->regs + TSI721_OBDMAC_CTL(ch)); priv->regs + TSI721_OBDMAC_CTL(ch));
ioread32(priv->regs + TSI721_OBDMAC_CTL(ch)); ioread32(priv->regs + TSI721_OBDMAC_CTL(ch));
/* Inform upper level to clear all pending tx slots */ /* Inform upper level to clear all pending tx slots */
if (mport->outb_msg[ch].mcback) dev_id = priv->omsg_ring[ch].dev_id;
mport->outb_msg[ch].mcback(mport, tx_slot = priv->omsg_ring[ch].tx_slot;
priv->omsg_ring[ch].dev_id, ch, do_callback = 1;
priv->omsg_ring[ch].tx_slot);
/* Synch tx_slot tracking */ /* Synch tx_slot tracking */
iowrite32(priv->omsg_ring[ch].tx_slot, iowrite32(priv->omsg_ring[ch].tx_slot,
priv->regs + TSI721_OBDMAC_DRDCNT(ch)); priv->regs + TSI721_OBDMAC_DRDCNT(ch));
...@@ -1627,6 +1641,9 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch) ...@@ -1627,6 +1641,9 @@ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch)
} }
spin_unlock(&priv->omsg_ring[ch].lock); spin_unlock(&priv->omsg_ring[ch].lock);
if (mport->outb_msg[ch].mcback && do_callback)
mport->outb_msg[ch].mcback(mport, dev_id, ch, tx_slot);
} }
/** /**
...@@ -1768,7 +1785,8 @@ static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id, ...@@ -1768,7 +1785,8 @@ static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id,
mb(); mb();
/* Initialize Outbound Message engine */ /* Initialize Outbound Message engine */
iowrite32(TSI721_OBDMAC_CTL_INIT, priv->regs + TSI721_OBDMAC_CTL(mbox)); iowrite32(TSI721_OBDMAC_CTL_RETRY_THR | TSI721_OBDMAC_CTL_INIT,
priv->regs + TSI721_OBDMAC_CTL(mbox));
ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
udelay(10); udelay(10);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment