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 | 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 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto