From: Michael Bringmann <michael.bringm...@lsi.com> Add additional spinlocks/mutexes to each controller state to increase concurrency and performance. Fix some bound checks for full outbound DME descriptor chains, correct a lockup/delay issue with errors in the outbound DME chains, and remove a delay loop.
rapidio/LSI AXM55xx: Correct some boundary checks for argument values. Also correct formatting of platform-specific function code. LSI AXM55xx: Expand valid condition checks for inbound message DME chains. Signed-off-by: Michael Bringmann <michael.bringm...@lsi.com> --- arch/arm/include/asm/axxia-rio.h | 31 ++++-- drivers/rapidio/devices/lsi/axxia-rio-ds.c | 22 ++-- drivers/rapidio/devices/lsi/axxia-rio-irq.c | 156 ++++++++------------------- drivers/rapidio/devices/lsi/axxia-rio-irq.h | 13 +-- drivers/rapidio/devices/lsi/axxia-rio.c | 3 +- drivers/rapidio/devices/lsi/axxia-rio.h | 16 ++- 6 files changed, 101 insertions(+), 140 deletions(-) diff --git a/arch/arm/include/asm/axxia-rio.h b/arch/arm/include/asm/axxia-rio.h index e01d6a3..492d476 100644 --- a/arch/arm/include/asm/axxia-rio.h +++ b/arch/arm/include/asm/axxia-rio.h @@ -94,21 +94,32 @@ static inline u32 CNTLZW(u32 val) int n = 0; if (val == 0) return 32; - if ((val & 0xFFFF0000) == 0) - n += 16; val = val << 16; + + if ((val & 0xFFFF0000) == 0) { + n += 16; + val = val << 16; + } /* 1111 1111 1111 1111 0000 0000 0000 0000 // 16 bits from left are zero! so we omit 16 left bits */ - if ((val & 0xFF000000) == 0) - n = n + 8; val = val << 8; + if ((val & 0xFF000000) == 0) { + n = n + 8; + val = val << 8; + } /* 8 left bits are 0 */ - if ((val & 0xF0000000) == 0) - n = n + 4; val = val << 4; + if ((val & 0xF0000000) == 0) { + n = n + 4; + val = val << 4; + } /* 4 left bits are 0 */ - if ((val & 0xC0000000) == 0) - n = n + 2, val = val << 2; + if ((val & 0xC0000000) == 0) { + n = n + 2; + val = val << 2; + } /* 110000....0 2 left bits are zero */ - if ((val & 0x80000000) == 0) - n = n + 1, val = val << 1; + if ((val & 0x80000000) == 0) { + n = n + 1; + val = val << 1; + } /* first left bit is zero */ return n; } diff --git a/drivers/rapidio/devices/lsi/axxia-rio-ds.c b/drivers/rapidio/devices/lsi/axxia-rio-ds.c index f4f44a6..02d3751 100755 --- a/drivers/rapidio/devices/lsi/axxia-rio-ds.c +++ b/drivers/rapidio/devices/lsi/axxia-rio-ds.c @@ -240,9 +240,10 @@ int axxia_open_ob_data_stream( int num_header_entries, int num_data_entries) { + struct rio_priv *priv = mport->priv; int rc = 0; - axxia_api_lock(); + axxia_api_lock(priv); rc = open_ob_data_stream(mport, dev_id, @@ -250,7 +251,7 @@ int axxia_open_ob_data_stream( num_header_entries, num_data_entries); - axxia_api_unlock(); + axxia_api_unlock(priv); return rc; } @@ -747,12 +748,12 @@ int axxia_close_ob_data_stream( struct rio_ds_hdr_desc *ptr_hdr_desc; u32 dse_ctrl, i; - axxia_api_lock(); + axxia_api_lock(priv); ptr_dse_cfg = &(ptr_ds_priv->obds_dse_cfg[dse_id]); if (ptr_dse_cfg->in_use == RIO_DS_FALSE) { - axxia_api_unlock(); + axxia_api_unlock(priv); return 0; } @@ -791,7 +792,7 @@ int axxia_close_ob_data_stream( /* release the IRQ handler */ release_irq_handler(&(ptr_ds_priv->ob_dse_irq[dse_id])); - axxia_api_unlock(); + axxia_api_unlock(priv); return 0; } @@ -830,9 +831,10 @@ int axxia_open_ib_data_stream( int desc_dbuf_size, int num_entries) { + struct rio_priv *priv = mport->priv; int rc = 0; - axxia_api_lock(); + axxia_api_lock(priv); rc = open_ib_data_stream(mport, dev_id, @@ -840,7 +842,7 @@ int axxia_open_ib_data_stream( cos, desc_dbuf_size, num_entries); - axxia_api_unlock(); + axxia_api_unlock(priv); return rc; } @@ -1522,7 +1524,7 @@ int axxia_close_ib_data_stream( struct rio_ids_data_desc *ptr_data_desc; u8 virt_vsid; - axxia_api_lock(); + axxia_api_lock(priv); for (i = 0; i < (ptr_ds_priv->num_ibds_virtual_m); i++) { ptr_virt_m_cfg = &(ptr_ds_priv->ibds_vsid_m_cfg[i]); @@ -1537,7 +1539,7 @@ int axxia_close_ib_data_stream( } if (find_ava_virt_m == RIO_DS_FALSE) { - axxia_api_unlock(); + axxia_api_unlock(priv); return 0; } @@ -1567,7 +1569,7 @@ int axxia_close_ib_data_stream( if (ptr_virt_m_cfg->ptr_ibds_data_desc != NULL) kfree(ptr_virt_m_cfg->ptr_ibds_data_desc); - axxia_api_unlock(); + axxia_api_unlock(priv); return 0; } diff --git a/drivers/rapidio/devices/lsi/axxia-rio-irq.c b/drivers/rapidio/devices/lsi/axxia-rio-irq.c index e962b0c..91175a0 100644 --- a/drivers/rapidio/devices/lsi/axxia-rio-irq.c +++ b/drivers/rapidio/devices/lsi/axxia-rio-irq.c @@ -44,8 +44,6 @@ ** Local State */ -DEFINE_MUTEX(axxia_rio_api_mutex); - atomic_t thrd_handler_calls = ATOMIC_INIT(0); atomic_t hw_handler_calls = ATOMIC_INIT(0); atomic_t port_irq_disabled = ATOMIC_INIT(0); @@ -475,11 +473,11 @@ static void rio_port_down_notify(struct rio_mport *mport) unsigned long flags; struct rio_priv *priv = mport->priv; - spin_lock_irqsave(&priv->rio_lock, flags); + spin_lock_irqsave(&priv->port_lock, flags); if (priv->port_notify_cb) priv->port_notify_cb(mport); - spin_unlock_irqrestore(&priv->rio_lock, flags); + spin_unlock_irqrestore(&priv->port_lock, flags); } #else #define rio_port_down_notify(mport) @@ -1018,7 +1016,7 @@ static inline int choose_ob_dme( if (len > sz) continue; - if (dme->entries > dme->entries_in_use) { + if (dme->entries >= (dme->entries_in_use+1)) { (*ob_dme) = dme; (*buf_sz) = sz; return ret + i; @@ -1209,11 +1207,9 @@ static void ob_dme_irq_handler(struct rio_irq_handler *h, u32 state) struct rio_mport *mport = h->mport; struct rio_priv *priv = mport->priv; struct rio_msg_dme *mbox = h->data; - int i, pending = 0, ack_id = 0; + int i, ack_id = 0; u32 dme_stat, dw0, dme_no = 31 - CNTLZW(state); - u64 start, curr; u32 dme_ctrl; - u32 debug = 0; unsigned long flags; /** @@ -1223,79 +1219,15 @@ static void ob_dme_irq_handler(struct rio_irq_handler *h, u32 state) __rio_local_write_config_32(mport, RAB_OB_DME_STAT(dme_no), dme_stat); __ob_dme_dbg(priv, dme_stat); - /** - * Wait for all pending transactions to finish before doing descriptor - * updates - */ spin_lock_irqsave(&mbox->lock, flags); - start = get_tb(); - do { - pending = 0; - for (i = 0; i < mbox->entries; i++) { - struct rio_msg_desc *desc = &mbox->desc[i]; - - if (!priv->internalDesc) { - dw0 = *((u32 *)DESC_TABLE_W0_MEM(mbox, - desc->desc_no)); - } else { - __rio_local_read_config_32(mport, - DESC_TABLE_W0(desc->desc_no), &dw0); - } - if ((dw0 & DME_DESC_DW0_VALID) && - !(dw0 & DME_DESC_DW0_READY_MASK)) - pending++; - } - if (!pending) { - mbox->tx_dme_tmo = 0; - break; - } - - /** - * Don't wait indefinitely - if something is broken - */ - curr = get_tb(); - if ((curr - start) > 200000) { - dev_dbg(priv->dev, - "RIO-IRQ: TO waiting for %d ob desc " - "transaction to finish\n", - pending); - } - } while (pending); /** * Try to kick back some life in the HW if it is un-responsive */ - if (pending) { - mbox->tx_dme_tmo++; - if (dme_stat & RIO_OB_DME_STAT_SLEEPING) - debug |= 1 << RIO_OB_DME_TX_SLEEP; - debug |= 1 << RIO_OB_DME_TX_PENDING; - - __rio_local_read_config_32(mport, RAB_OB_DME_CTRL(dme_no), - &dme_ctrl); - if (mbox->tx_dme_tmo > 100) { - /** - * Must be in serious trouble now, don't burn more - * CPU cycles. - * FIXME! Notify someone that we're broken, report - * state event through RIO maybe? - */ - dev_dbg(priv->dev, - "RIO-IRQ: OB DME %d disabled due to " - "excessive TO events\n", - dme_no); - dme_ctrl &= ~(DME_WAKEUP | DME_ENABLE); - } else { - debug |= 1 << RIO_OB_DME_TX_WAKEUP; - dme_ctrl |= DME_WAKEUP | DME_ENABLE; - } - __rio_local_write_config_32(mport, RAB_OB_DME_CTRL(dme_no), - dme_ctrl); - __ob_dme_event_dbg(priv, dme_no, debug); - spin_unlock_irqrestore(&mbox->lock, flags); - return; - } + __rio_local_read_config_32(mport, RAB_OB_DME_CTRL(dme_no), &dme_ctrl); + dme_ctrl |= DME_WAKEUP | DME_ENABLE; + __rio_local_write_config_32(mport, RAB_OB_DME_CTRL(dme_no), dme_ctrl); /** * Process all completed transactions @@ -1326,8 +1258,8 @@ static void ob_dme_irq_handler(struct rio_irq_handler *h, u32 state) dw0 & DME_DESC_DW0_NXT_DESC_VALID); } __ob_dme_dw_dbg(priv, dw0); - if (dw0 & DME_DESC_DW0_DONE) - mbox->entries_in_use--; + + mbox->entries_in_use--; } } spin_unlock_irqrestore(&mbox->lock, flags); @@ -1375,7 +1307,7 @@ static int open_outb_mbox(struct rio_mport *mport, void *dev_id, int dme_no, u64 descChainStart, descAddr; int buf_sz = 0; - if (entries > priv->desc_max_entries) + if ((entries <= 0) || (entries > priv->desc_max_entries)) return -EINVAL; if (test_bit(RIO_IRQ_ENABLED, &h->state)) @@ -1618,8 +1550,10 @@ static void ib_dme_irq_handler(struct rio_irq_handler *h, u32 state) DESC_TABLE_W0(desc->desc_no), &dw0); } - if ((dw0 & DME_DESC_DW0_READY_MASK) && - (dw0 & DME_DESC_DW0_VALID)) { + if (dw0 & DME_DESC_DW0_READY_MASK) { + + /* Some chips clear this bit, some don't. + ** Make sure in any event. */ if (!priv->internalDesc) { *((u32 *)DESC_TABLE_W0_MEM(me, desc->desc_no)) = @@ -1629,6 +1563,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); } + __ib_dme_dw_dbg(priv, dw0); __ib_dme_event_dbg(priv, dme_no, 1 << RIO_IB_DME_RX_PUSH); @@ -1730,7 +1665,7 @@ static int open_inb_mbox(struct rio_mport *mport, void *dev_id, if ((mbox < 0) || (mbox >= RIO_MAX_RX_MBOX)) return -EINVAL; - if (entries > priv->desc_max_entries) + if ((entries <= 0) || (entries > priv->desc_max_entries)) return -EINVAL; h = &priv->ib_dme_irq[mbox]; @@ -2070,12 +2005,12 @@ int axxia_rio_pw_enable(struct rio_mport *mport, int enable) struct rio_priv *priv = mport->priv; int rc = 0; - axxia_api_lock(); + axxia_api_lock(priv); if (enable) rc = enable_pw(&priv->pw_irq); else release_irq_handler(&priv->pw_irq); - axxia_api_unlock(); + axxia_api_unlock(priv); return rc; } @@ -2156,11 +2091,12 @@ int axxia_open_outb_mbox( int entries, int prio) { + struct rio_priv *priv = mport->priv; int rc = 0; - axxia_api_lock(); + axxia_api_lock(priv); rc = open_outb_mbox(mport, dev_id, mboxDme, entries, prio); - axxia_api_unlock(); + axxia_api_unlock(priv); return rc; } @@ -2181,9 +2117,9 @@ void axxia_close_outb_mbox(struct rio_mport *mport, int mboxDme) (mboxDme > (priv->numOutbDmes[0]+priv->numOutbDmes[0]))) return; - axxia_api_lock(); + axxia_api_lock(priv); release_irq_handler(&priv->ob_dme_irq[mboxDme]); - axxia_api_unlock(); + axxia_api_unlock(priv); return; } @@ -2211,13 +2147,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)) { + if (!(dw0 & DME_DESC_DW0_VALID) || + (dw0 & DME_DESC_DW0_ERROR_MASK)) { if (desc_num != mb->write_idx) - dev_dbg(priv->dev, - "RIO: Adding buffer descriptors " - "out of order to TX DME\n"); + return NULL; if (desc_num == mb->write_idx) - mb->write_idx = (mb->write_idx + 1) % + mb->write_idx = (mb->write_idx + 1) % mb->entries; return desc; } @@ -2245,7 +2180,7 @@ int axxia_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox_dest, int letter, int flags, void *buffer, size_t len, void *cookie) { - int rc = 0; + int rc = 0, dme; u32 dw0, dw1, dme_ctrl; u16 destid = (rdev ? rdev->destid : mport->host_deviceid); struct rio_priv *priv = mport->priv; @@ -2258,9 +2193,11 @@ int axxia_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, (mbox_dest >= RIO_MAX_TX_MBOX)) return -EINVAL; - rc = choose_ob_dme(priv, len, &mb, &buf_sz); - if (rc < 0) + dme = choose_ob_dme(priv, len, &mb, &buf_sz); + if (dme < 0) { + rc = dme; return rc; + } if ((len < 8) || (len > buf_sz)) return -EINVAL; @@ -2340,11 +2277,12 @@ done: int axxia_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) { + struct rio_priv *priv = mport->priv; int rc = 0; - axxia_api_lock(); + axxia_api_lock(priv); rc = open_inb_mbox(mport, dev_id, mbox, entries); - axxia_api_unlock(); + axxia_api_unlock(priv); return rc; } @@ -2364,9 +2302,9 @@ void axxia_close_inb_mbox(struct rio_mport *mport, int mbox) if ((mbox < 0) || (mbox >= RIO_MAX_RX_MBOX)) return; - axxia_api_lock(); + axxia_api_lock(priv); release_irq_handler(&priv->ib_dme_irq[mbox]); - axxia_api_unlock(); + axxia_api_unlock(priv); return; } @@ -2666,7 +2604,7 @@ int axxia_rio_port_notify_cb(struct rio_mport *mport, unsigned long flags; int rc = 0; - spin_lock_irqsave(&priv->rio_lock, flags); + spin_lock_irqsave(&priv->port_lock, flags); if (enable) { if (priv->port_notify_cb) rc = -EBUSY; @@ -2678,7 +2616,7 @@ int axxia_rio_port_notify_cb(struct rio_mport *mport, else priv->port_notify_cb = NULL; } - spin_unlock_irqrestore(&priv->rio_lock, flags); + spin_unlock_irqrestore(&priv->port_lock, flags); return rc; } @@ -2701,9 +2639,9 @@ int axxia_rio_apio_enable(struct rio_mport *mport, u32 mask, u32 bits) struct rio_priv *priv = mport->priv; int rc; - axxia_api_lock(); + axxia_api_lock(priv); rc = enable_apio(&priv->apio_irq, mask, bits); - axxia_api_unlock(); + axxia_api_unlock(priv); return rc; } @@ -2713,9 +2651,9 @@ int axxia_rio_apio_disable(struct rio_mport *mport) { struct rio_priv *priv = mport->priv; - axxia_api_lock(); + axxia_api_lock(priv); release_irq_handler(&priv->apio_irq); - axxia_api_unlock(); + axxia_api_unlock(priv); return 0; } @@ -2726,9 +2664,9 @@ int axxia_rio_rpio_enable(struct rio_mport *mport, u32 mask, u32 bits) struct rio_priv *priv = mport->priv; int rc = 0; - axxia_api_lock(); + axxia_api_lock(priv); rc = enable_rpio(&priv->rpio_irq, mask, bits); - axxia_api_unlock(); + axxia_api_unlock(priv); return rc; } @@ -2738,9 +2676,9 @@ int axxia_rio_rpio_disable(struct rio_mport *mport) { struct rio_priv *priv = mport->priv; - axxia_api_lock(); + axxia_api_lock(priv); release_irq_handler(&priv->rpio_irq); - axxia_api_unlock(); + axxia_api_unlock(priv); return 0; } diff --git a/drivers/rapidio/devices/lsi/axxia-rio-irq.h b/drivers/rapidio/devices/lsi/axxia-rio-irq.h index 9313ccd..b456541 100644 --- a/drivers/rapidio/devices/lsi/axxia-rio-irq.h +++ b/drivers/rapidio/devices/lsi/axxia-rio-irq.h @@ -3,6 +3,7 @@ /* forward declaration */ struct rio_priv; +struct mutex; #if !defined(CONFIG_AXXIA_RIO_STAT) @@ -281,16 +282,10 @@ struct rio_irq_handler { #endif }; -extern struct mutex axxia_rio_api_mutex; -static inline void axxia_api_lock(void) -{ - mutex_lock(&axxia_rio_api_mutex); -} -static inline void axxia_api_unlock(void) -{ - mutex_unlock(&axxia_rio_api_mutex); -} +/**********************************************/ +/* *********** External Functions *********** */ +/**********************************************/ void axxia_rio_port_irq_init(struct rio_mport *mport); void *axxia_get_inb_message(struct rio_mport *mport, int mbox, int letter, diff --git a/drivers/rapidio/devices/lsi/axxia-rio.c b/drivers/rapidio/devices/lsi/axxia-rio.c index 0baa7fc..5868569 100644 --- a/drivers/rapidio/devices/lsi/axxia-rio.c +++ b/drivers/rapidio/devices/lsi/axxia-rio.c @@ -1422,12 +1422,13 @@ static struct rio_priv *rio_priv_dtb_setup( if (!priv) return ERR_PTR(-ENOMEM); - /* mport port driver handle (bidirectional reference supported) */ + /* master port driver handle (bidirectional reference supported) */ mport->priv = priv; priv->cookie = LSI_AXXIA_RIO_COOKIE; priv->mport = mport; priv->ndx = ndx; priv->portNdx = portNdx; + mutex_init(&priv->api_mutex); /* Max descriptors */ priv->desc_max_entries = RIO_MSG_MAX_ENTRIES; diff --git a/drivers/rapidio/devices/lsi/axxia-rio.h b/drivers/rapidio/devices/lsi/axxia-rio.h index 3659138..55955ec 100644 --- a/drivers/rapidio/devices/lsi/axxia-rio.h +++ b/drivers/rapidio/devices/lsi/axxia-rio.h @@ -490,7 +490,8 @@ struct rio_desc { struct rio_priv { u32 cookie; - spinlock_t rio_lock; + struct mutex api_mutex; + spinlock_t port_lock; struct rio_mport *mport; struct device *dev; @@ -546,6 +547,19 @@ struct rio_priv { }; +/**********************************************/ +/* *********** External Functions *********** */ +/**********************************************/ + +static inline void axxia_api_lock(struct rio_priv *priv) +{ + mutex_lock(&priv->api_mutex); +} +static inline void axxia_api_unlock(struct rio_priv *priv) +{ + mutex_unlock(&priv->api_mutex); +} + extern int axxia_rio_start_port(struct rio_mport *mport); extern void axxia_rio_set_mport_disc_mode(struct rio_mport *mport); extern void axxia_rio_static_win_release(struct rio_mport *mport); -- 1.7.9.5 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto