From: Michael Bringmann <michael.bringm...@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.bringm...@lsi.com>
---
 drivers/rapidio/devices/lsi/axxia-rio-irq.c |  108 ++++++++++++++++++++-------
 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                       |    2 +-
 5 files changed, 85 insertions(+), 31 deletions(-)

diff --git a/drivers/rapidio/devices/lsi/axxia-rio-irq.c 
b/drivers/rapidio/devices/lsi/axxia-rio-irq.c
index 6a4d227..ae965f9 100644
--- a/drivers/rapidio/devices/lsi/axxia-rio-irq.c
+++ b/drivers/rapidio/devices/lsi/axxia-rio-irq.c
@@ -1115,7 +1115,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;
 
@@ -1223,6 +1224,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 {
@@ -1243,6 +1247,8 @@ 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
@@ -1532,6 +1538,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) {
@@ -1543,6 +1550,7 @@ 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,
@@ -1556,7 +1564,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;
                        }
@@ -1570,6 +1577,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);
 
+#ifdef OBSOLETE_BZ47185
                if (dme_stat & IB_DME_STAT_SLEEPING) {
                        struct rio_msg_desc *desc;
                        u32 dme_ctrl;
@@ -1610,6 +1618,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 */
        }
 }
 
@@ -1762,6 +1771,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);
@@ -2104,19 +2115,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,14 +2131,11 @@ static struct rio_msg_desc *get_ob_desc(struct 
rio_mport *mport,
                                           &dw0);
                }
                if (!(dw0 & DME_DESC_DW0_VALID)) {
-                       if (desc_num != mb->write_idx)
-                               return NULL;
-                       if (desc_num == mb->write_idx)
-                               mb->write_idx = (mb->write_idx + 1) %
-                                                mb->entries;
+                       mb->write_idx = nxt_write_idx;
                        return desc;
                }
        }
+
        return NULL;
 }
 
@@ -2341,7 +2344,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))
@@ -2358,6 +2361,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;
@@ -2367,9 +2373,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;
 
@@ -2386,7 +2392,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)) =
@@ -2397,11 +2404,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];
@@ -2422,7 +2429,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;
@@ -2443,15 +2451,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 7ed5fd8..f5f85e5 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 1f1fc39..a8ff2bb 100644
--- a/drivers/rapidio/devices/lsi/axxia-rio.c
+++ b/drivers/rapidio/devices/lsi/axxia-rio.c
@@ -974,7 +974,7 @@ static int rio_start_port(struct rio_mport *mport)
                __rio_local_read_config_32(mport, RIO_DEV_ID_CAR, &didcar);
                __rio_local_read_config_32(mport, RAB_VER, &rabver);
 
-               printk("rio[%d]: AR[%d] DIDCAR[%x]=%08x RAB_VER[%x]=%08x\n",
+               printk(KERN_INFO "rio[%d]: AR[%d] DIDCAR[%x]=%08x 
RAB_VER[%x]=%08x\n",
                        mport->id,
                        __LINE__,
                        RIO_DEV_ID_CAR, didcar,
diff --git a/drivers/rapidio/devices/lsi/axxia-rio.h 
b/drivers/rapidio/devices/lsi/axxia-rio.h
index 55955ec..4d751d5 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 928f1eb..95b98b4 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -343,7 +343,7 @@ int rio_release_inb_mbox(struct rio_mport *mport, int mbox)
                mport->ops->close_inb_mbox(mport, mbox);
 
                /* Release the mailbox resource */
-               if (mport->outb_msg[mbox].res)
+               if (mport->inb_msg[mbox].res)
                        return release_resource(mport->inb_msg[mbox].res);
                else
                        return -ENOMEM;
-- 
1.7.9.5

-- 
_______________________________________________
linux-yocto mailing list
linux-yo...@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to