[linux-yocto] [PATCH 13/57] LSI AXM55xx: Various performance and fixes for rapidio endpoint code.

Charlie Paul cpaul.windriver at gmail.com
Mon Mar 17 21:56:13 PDT 2014


From: Michael Bringmann <michael.bringmann at lsi.com>

Fix lockup issue processing inbound message descriptor chains.
Revise processing code for inbound/outbound message descriptor
chains to reduce overhead / improve performance.

Signed-off-by: Michael Bringmann <michael.bringmann at lsi.com>
---
 drivers/rapidio/devices/lsi/axxia-rio-irq.c |  132 ++++++++++++++++++---------
 drivers/rapidio/devices/lsi/axxia-rio-irq.h |    3 +-
 drivers/rapidio/devices/lsi/axxia-rio.c     |    2 +-
 drivers/rapidio/devices/lsi/axxia-rio.h     |    1 +
 drivers/rapidio/rio.c                       |   10 +-
 5 files changed, 100 insertions(+), 48 deletions(-)

diff --git a/drivers/rapidio/devices/lsi/axxia-rio-irq.c b/drivers/rapidio/devices/lsi/axxia-rio-irq.c
index d32c1c2..b26ed60 100644
--- a/drivers/rapidio/devices/lsi/axxia-rio-irq.c
+++ b/drivers/rapidio/devices/lsi/axxia-rio-irq.c
@@ -1010,7 +1010,7 @@ static inline int choose_ob_dme(
 			if (len > sz)
 				continue;
 
-			if (dme->entries >= (dme->entries_in_use+1)) {
+			if (dme->entries > (dme->entries_in_use+1)) {
 				(*ob_dme) = dme;
 				(*buf_sz) = sz;
 				return ret + i;
@@ -1114,7 +1114,8 @@ static struct rio_msg_dme *alloc_message_engine(struct rio_mport *mport,
 	me->entries_in_use = 0;
 	me->write_idx = 0;
 	me->read_idx = 0;
-	atomic_set(&me->pending, 0);
+	me->last_invalid_desc = 0;
+	me->last_compl_idx = 0;
 	me->tx_dme_tmo = 0;
 	me->dme_no = dme_no;
 
@@ -1221,6 +1222,9 @@ static void ob_dme_irq_handler(struct rio_irq_handler *h, u32 state)
 	for (i = 0; i < mbox->entries; i++) {
 		struct rio_msg_desc *desc = &mbox->desc[i];
 
+		if (mbox->last_compl_idx != desc->desc_no)
+			continue;
+
 		if (!priv->internalDesc) {
 			dw0 = *((u32 *)DESC_TABLE_W0_MEM(mbox, desc->desc_no));
 		} else {
@@ -1240,7 +1244,7 @@ static void ob_dme_irq_handler(struct rio_irq_handler *h, u32 state)
 			}
 			__ob_dme_dw_dbg(priv, dw0);
 
-			mbox->entries_in_use--;
+			mbox->last_compl_idx = (mbox->last_compl_idx + 1) % mbox->entries;
 
 			/**
 			* UP-call to net device handler
@@ -1472,7 +1476,6 @@ static void ib_dme_irq_handler(struct rio_irq_handler *h, u32 state)
 		u32 dw0;
 		int dme_no = 31 - CNTLZW(dme_mask);
 		int num_new;
-		int nPending;
 		dme_mask ^= (1 << dme_no);
 
 		while (mb->me[letter]->dme_no != dme_no)
@@ -1512,7 +1515,7 @@ static void ib_dme_irq_handler(struct rio_irq_handler *h, u32 state)
 #endif
 		/**
 		 * Set Valid flag to 0 on each desc with a new message.
-		 * Flag is reset when the message beloning to the desc
+		 * Flag is reset when the message belonging to the desc
 		 * is fetched in get_inb_message().
 		 * HW descriptor update and fetch is in order.
 		 */
@@ -1531,6 +1534,7 @@ static void ib_dme_irq_handler(struct rio_irq_handler *h, u32 state)
 			if ((dw0 & DME_DESC_DW0_READY_MASK) &&
 			    (dw0 & DME_DESC_DW0_VALID)) {
 
+#ifdef OBSOLETE_BZ47185
 				/* Some chips clear this bit, some don't.
 				** Make sure in any event. */
 				if (!priv->internalDesc) {
@@ -1542,6 +1546,13 @@ static void ib_dme_irq_handler(struct rio_irq_handler *h, u32 state)
 						DESC_TABLE_W0(desc->desc_no),
 						dw0 & ~DME_DESC_DW0_VALID);
 				}
+#endif /* OBSOLETE_BZ47185 */
+
+				if (mport->inb_msg[mbox_no].mcback)
+					mport->inb_msg[mbox_no].mcback(mport,
+								me->dev_id,
+								mbox_no,
+								desc->desc_no);
 
 				__ib_dme_dw_dbg(priv, dw0);
 				__ib_dme_event_dbg(priv, dme_no,
@@ -1549,7 +1560,6 @@ static void ib_dme_irq_handler(struct rio_irq_handler *h, u32 state)
 				me->write_idx = (me->write_idx + 1) %
 						 me->entries;
 				num_new++;
-				atomic_inc(&me->pending);
 				if (num_new == me->entries)
 					break;
 			}
@@ -1563,16 +1573,7 @@ static void ib_dme_irq_handler(struct rio_irq_handler *h, u32 state)
 			__ib_dme_event_dbg(priv, dme_no,
 					   1 << RIO_IB_DME_RX_RING_FULL);
 
-		nPending = atomic_read(&me->pending);
-		if (nPending &&
-		    mport->inb_msg[mbox_no].mcback)
-		{
-			mport->inb_msg[mbox_no].mcback(mport,
-						       me->dev_id,
-						       mbox_no,
-						       letter);
-		}
-
+#ifdef OBSOLETE_BZ47185
 		if (dme_stat & IB_DME_STAT_SLEEPING) {
 			struct rio_msg_desc *desc;
 			u32 dme_ctrl;
@@ -1613,6 +1614,7 @@ static void ib_dme_irq_handler(struct rio_irq_handler *h, u32 state)
 					 RAB_IB_DME_CTRL(dme_no), dme_ctrl);
 			}
 		}
+#endif /* OBSOLETE_BZ47185 */
 	}
 }
 
@@ -1765,6 +1767,8 @@ static int open_inb_mbox(struct rio_mport *mport, void *dev_id,
 		 */
 		desc--;
 		dw0 |= DME_DESC_DW0_NXT_DESC_VALID;
+		dw0 &= ~DME_DESC_DW0_VALID;
+		me->last_invalid_desc = desc->desc_no;
 		if (!priv->internalDesc) {
 			descChainStart = (uintptr_t)virt_to_phys(me->descriptors);
 
@@ -2105,19 +2109,14 @@ void axxia_close_outb_mbox(struct rio_mport *mport, int mboxDme)
 static struct rio_msg_desc *get_ob_desc(struct rio_mport *mport,
 					struct rio_msg_dme *mb)
 {
-	int i, desc_num = mb->write_idx;
+	int desc_num = mb->write_idx;
 	struct rio_priv *priv = mport->priv;
+	struct rio_msg_desc *desc = &mb->desc[desc_num];
+	int nxt_write_idx = (mb->write_idx + 1) % mb->entries;
+	u32 dw0;
 
-	/**
-	 * HW descriptor fetch and update may be out of order
-	 * Check state of all used descriptors
-	 */
-
-	for (i = 0; i < mb->entries;
-		 i++, desc_num = (desc_num + 1) % mb->entries) {
-		struct rio_msg_desc *desc = &mb->desc[desc_num];
-		u32 dw0;
-
+	if ((nxt_write_idx != mb->last_compl_idx) &&
+	    (mb->entries > (mb->entries_in_use + 1))) {
 		if (!priv->internalDesc) {
 			dw0 = *((u32 *)DESC_TABLE_W0_MEM(mb, desc->desc_no));
 		} else {
@@ -2125,16 +2124,12 @@ static struct rio_msg_desc *get_ob_desc(struct rio_mport *mport,
 					   DESC_TABLE_W0(desc->desc_no),
 					   &dw0);
 		}
-		if (!(dw0 & DME_DESC_DW0_VALID) ||
-		    (dw0 & DME_DESC_DW0_ERROR_MASK)) {
-			if (desc_num != mb->write_idx)
-				return NULL;
-			if (desc_num == mb->write_idx)
-				mb->write_idx = (mb->write_idx + 1) %
-						 mb->entries;
+		if (!(dw0 & DME_DESC_DW0_VALID)) {
+			mb->write_idx = nxt_write_idx;
 			return desc;
 		}
 	}
+
 	return NULL;
 }
 
@@ -2343,7 +2338,7 @@ void *axxia_get_inb_message(struct rio_mport *mport, int mbox, int letter,
 	struct rio_rx_mbox *mb;
 	struct rio_msg_dme *me;
 	unsigned long iflags;
-	int nPending;
+	int numProc = 0;
 	void *buf = NULL;
 
 	if ((mbox < 0) || (mbox >= RIO_MAX_RX_MBOX))
@@ -2360,6 +2355,9 @@ void *axxia_get_inb_message(struct rio_mport *mport, int mbox, int letter,
 		return ERR_PTR(-EINVAL);
 
 	spin_lock_irqsave(&mb->lock, iflags);
+
+#ifdef OBSOLETE_BZ47185
+	/* Make this conditional for AXM55xx??? */
 	if (!in_interrupt() &&
 	    !test_bit(RIO_IRQ_ACTIVE, &priv->ib_dme_irq[mbox].state)) {
 		u32	intr;
@@ -2369,9 +2367,9 @@ void *axxia_get_inb_message(struct rio_mport *mport, int mbox, int letter,
 		ib_dme_irq_handler(&priv->ib_dme_irq[mbox], (1 << me->dme_no));
 		__rio_local_write_config_32(mport, RAB_INTR_ENAB_IDME, intr);
 	}
+#endif /* OBSOLETE_BZ47185 */
 
-	nPending = atomic_read(&me->pending);
-	while (nPending) {
+	while (1) {
 		struct rio_msg_desc *desc = &me->desc[me->read_idx];
 		u32 dw0, dw1;
 
@@ -2388,7 +2386,8 @@ void *axxia_get_inb_message(struct rio_mport *mport, int mbox, int letter,
 					   DESC_TABLE_W1(desc->desc_no),
 					   &dw1);
 		}
-		if (dw0 & DME_DESC_DW0_ERROR_MASK) {
+		if ((dw0 & DME_DESC_DW0_ERROR_MASK) &&
+		    (dw0 & DME_DESC_DW0_VALID)) {
 			if (!priv->internalDesc) {
 				*((u32 *)DESC_TABLE_W0_MEM(me,
 					desc->desc_no)) =
@@ -2399,11 +2398,11 @@ void *axxia_get_inb_message(struct rio_mport *mport, int mbox, int letter,
 					(dw0 & 0xff) | DME_DESC_DW0_VALID);
 			}
 			me->read_idx = (me->read_idx + 1) % me->entries;
-			atomic_dec(&me->pending);
-			nPending--;
 			__ib_dme_event_dbg(priv, me->dme_no,
 					   1 << RIO_IB_DME_DESC_ERR);
-		} else {
+			numProc++;
+		} else if ((dw0 & DME_DESC_DW0_DONE) &&
+			   (dw0 & DME_DESC_DW0_VALID)) {
 			int seg = DME_DESC_DW1_SIZE_F(dw1);
 			int buf_sz = DME_DESC_DW1_SIZE_SENT(seg);
 			buf = mb->virt_buffer[mb->next_rx_slot];
@@ -2424,7 +2423,8 @@ void *axxia_get_inb_message(struct rio_mport *mport, int mbox, int letter,
 					   1 << RIO_IB_DME_RX_POP);
 			*sz = buf_sz;
 			*slot = me->read_idx;
-			*destid = (dw0 & 0xffff0000) >> 16;
+			*destid = DME_DESC_DW0_GET_DST_ID(dw0);
+
 #ifdef CONFIG_SRIO_IRQ_TIME
 			if (atomic_read(&priv->ib_dme_irq[mbox].start_time)) {
 				int add_time = 0;
@@ -2445,15 +2445,59 @@ void *axxia_get_inb_message(struct rio_mport *mport, int mbox, int letter,
 				me->bytes += buf_sz;
 			}
 #endif
+
 			mb->next_rx_slot = (mb->next_rx_slot + 1) %
 					    mb->ring_size;
 			me->read_idx = (me->read_idx + 1) % me->entries;
-			atomic_dec(&me->pending);
-			nPending--;
+			numProc++;
+			goto done;
+		} else {
 			goto done;
 		}
 	}
+
 done:
+	/* Advance VALID bit to next entry */
+	if (numProc > 0) {
+		u32 dw0;
+		int nxt_inval_desc = (me->last_invalid_desc + numProc) %
+				     me->entries;
+		if (!priv->internalDesc) {
+			dw0 = *((u32 *)DESC_TABLE_W0_MEM(me, nxt_inval_desc));
+			dw0 &= ~DME_DESC_DW0_VALID;
+			*((u32 *)DESC_TABLE_W0_MEM(me, nxt_inval_desc)) = dw0;
+
+			dw0 = *((u32 *)DESC_TABLE_W0_MEM(me,
+						me->last_invalid_desc));
+			dw0 |= DME_DESC_DW0_VALID;
+			*((u32 *)DESC_TABLE_W0_MEM(me,
+						me->last_invalid_desc)) = dw0;
+		} else {
+			__rio_local_read_config_32(mport,
+				DESC_TABLE_W0(nxt_inval_desc),
+				&dw0);
+			dw0 &= ~DME_DESC_DW0_VALID;
+			__rio_local_write_config_32(mport,
+					DESC_TABLE_W0(nxt_inval_desc),
+					dw0);
+			__rio_local_read_config_32(mport,
+				DESC_TABLE_W0(me->last_invalid_desc),
+				&dw0);
+			dw0 |= DME_DESC_DW0_VALID;
+			__rio_local_write_config_32(mport,
+					DESC_TABLE_W0(me->last_invalid_desc),
+					dw0);
+		}
+
+		/* And re-awaken the DME */
+		me->last_invalid_desc = nxt_inval_desc;
+		__rio_local_read_config_32(mport, RAB_IB_DME_CTRL(me->dme_no),
+					   &dw0);
+		dw0 |= DME_WAKEUP | DME_ENABLE;
+		__rio_local_write_config_32(mport, RAB_IB_DME_CTRL(me->dme_no),
+					    dw0);
+	}
+
 	spin_unlock_irqrestore(&mb->lock, iflags);
 	dme_put(me);
 	mbox_put(mb);
diff --git a/drivers/rapidio/devices/lsi/axxia-rio-irq.h b/drivers/rapidio/devices/lsi/axxia-rio-irq.h
index aafb3b8..961d93b 100644
--- a/drivers/rapidio/devices/lsi/axxia-rio-irq.h
+++ b/drivers/rapidio/devices/lsi/axxia-rio-irq.h
@@ -216,7 +216,8 @@ struct rio_msg_dme {
 	int entries_in_use;
 	int write_idx;
 	int read_idx;
-	atomic_t pending;
+	int last_invalid_desc;
+	int last_compl_idx;
 	int tx_dme_tmo;
 	void *dev_id;
 	int dme_no;
diff --git a/drivers/rapidio/devices/lsi/axxia-rio.c b/drivers/rapidio/devices/lsi/axxia-rio.c
index b128227..becdb1c 100644
--- a/drivers/rapidio/devices/lsi/axxia-rio.c
+++ b/drivers/rapidio/devices/lsi/axxia-rio.c
@@ -1365,7 +1365,7 @@ static int rio_mport_dtb_setup(struct platform_device *dev,
 		return -ENOMEM;
 	}
 	rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
-	rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 8);
+	rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 64);
 	rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 3);
 	sprintf(mport->name, "RIO%d mport", mport->id);
 
diff --git a/drivers/rapidio/devices/lsi/axxia-rio.h b/drivers/rapidio/devices/lsi/axxia-rio.h
index 37b633e..e13c8ac 100644
--- a/drivers/rapidio/devices/lsi/axxia-rio.h
+++ b/drivers/rapidio/devices/lsi/axxia-rio.h
@@ -356,6 +356,7 @@
 #define DESC_TABLE_W3_MEM(me, d)        (DESC_TABLE_W0_MEM_BASE(me, d) + 0xC)
 
 #define DME_DESC_DW0_SRC_DST_ID(id)     ((id) << 16)
+#define DME_DESC_DW0_GET_DST_ID(dw0)    (((dw0) >> 16) & 0xffff)
 #define DME_DESC_DW0_RIO_ERR            (1 << 11)
 #define DME_DESC_DW0_AXI_ERR            (1 << 10)
 #define DME_DESC_DW0_TIMEOUT_ERR        (1 << 9)
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index 8591024..c3ae3e2 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -343,7 +343,10 @@ int rio_release_inb_mbox(struct rio_mport *mport, int mbox)
 		mport->ops->close_inb_mbox(mport, mbox);
 
 		/* Release the mailbox resource */
-		return release_resource(mport->inb_msg[mbox].res);
+		if (mport->inb_msg[mbox].res)
+			return release_resource(mport->inb_msg[mbox].res);
+		else
+			return -ENOMEM;
 	} else
 		return -ENOSYS;
 }
@@ -411,7 +414,10 @@ int rio_release_outb_mbox(struct rio_mport *mport, int mbox)
 		mport->ops->close_outb_mbox(mport, mbox);
 
 		/* Release the mailbox resource */
-		return release_resource(mport->outb_msg[mbox].res);
+		if (mport->outb_msg[mbox].res)
+			return release_resource(mport->outb_msg[mbox].res);
+		else
+			return -ENOMEM;
 	} else
 		return -ENOSYS;
 }
-- 
1.7.9.5



More information about the linux-yocto mailing list