lkml.org 
[lkml]   [2014]   [Aug]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.12 078/104] ixgbe: fix qv_lock_napi call in ixgbe_napi_disable_all
    Date
    From: Jacob Keller <jacob.e.keller@intel.com>

    3.12-stable review patch. If anyone has any objections, please let me know.

    ===============

    commit 27d9ce4fd0e2e75c2907f6d3dc0487012a3e4298 upstream.

    ixgbe_napi_disable_all calls napi_disable on each queue, however the busy
    polling code introduced a local_bh_disable()d context around the napi_disable.
    The original author did not realize that napi_disable might sleep, which would
    cause a sleep while atomic BUG. In addition, on a single processor system, the
    ixgbe_qv_lock_napi loop shouldn't have to mdelay. This patch adds an
    ixgbe_qv_disable along with a new IXGBE_QV_STATE_DISABLED bit, which it uses to
    indicate to the poll and napi routines that the q_vector has been disabled. Now
    the ixgbe_napi_disable_all function will wait until all pending work has been
    finished and prevent any future work from being started.

    Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
    Cc: Eliezer Tamir <eliezer.tamir@linux.intel.com>
    Cc: Alexander Duyck <alexander.duyck@intel.com>
    Cc: Hyong-Youb Kim <hykim@myri.com>
    Cc: Amir Vadai <amirv@mellanox.com>
    Cc: Dmitry Kravkov <dmitry@broadcom.com>
    Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
    Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
    Signed-off-by: Jiri Slaby <jslaby@suse.cz>
    ---
    drivers/net/ethernet/intel/ixgbe/ixgbe.h | 48 ++++++++++++++++++++-------
    drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 6 ++--
    2 files changed, 38 insertions(+), 16 deletions(-)

    diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
    index 0ac6b11c6e4e..4506f8a15c8a 100644
    --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
    +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
    @@ -369,11 +369,13 @@ struct ixgbe_q_vector {
    #ifdef CONFIG_NET_RX_BUSY_POLL
    unsigned int state;
    #define IXGBE_QV_STATE_IDLE 0
    -#define IXGBE_QV_STATE_NAPI 1 /* NAPI owns this QV */
    -#define IXGBE_QV_STATE_POLL 2 /* poll owns this QV */
    -#define IXGBE_QV_LOCKED (IXGBE_QV_STATE_NAPI | IXGBE_QV_STATE_POLL)
    -#define IXGBE_QV_STATE_NAPI_YIELD 4 /* NAPI yielded this QV */
    -#define IXGBE_QV_STATE_POLL_YIELD 8 /* poll yielded this QV */
    +#define IXGBE_QV_STATE_NAPI 1 /* NAPI owns this QV */
    +#define IXGBE_QV_STATE_POLL 2 /* poll owns this QV */
    +#define IXGBE_QV_STATE_DISABLED 4 /* QV is disabled */
    +#define IXGBE_QV_OWNED (IXGBE_QV_STATE_NAPI | IXGBE_QV_STATE_POLL)
    +#define IXGBE_QV_LOCKED (IXGBE_QV_OWNED | IXGBE_QV_STATE_DISABLED)
    +#define IXGBE_QV_STATE_NAPI_YIELD 8 /* NAPI yielded this QV */
    +#define IXGBE_QV_STATE_POLL_YIELD 16 /* poll yielded this QV */
    #define IXGBE_QV_YIELD (IXGBE_QV_STATE_NAPI_YIELD | IXGBE_QV_STATE_POLL_YIELD)
    #define IXGBE_QV_USER_PEND (IXGBE_QV_STATE_POLL | IXGBE_QV_STATE_POLL_YIELD)
    spinlock_t lock;
    @@ -394,7 +396,7 @@ static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
    static inline bool ixgbe_qv_lock_napi(struct ixgbe_q_vector *q_vector)
    {
    int rc = true;
    - spin_lock(&q_vector->lock);
    + spin_lock_bh(&q_vector->lock);
    if (q_vector->state & IXGBE_QV_LOCKED) {
    WARN_ON(q_vector->state & IXGBE_QV_STATE_NAPI);
    q_vector->state |= IXGBE_QV_STATE_NAPI_YIELD;
    @@ -405,7 +407,7 @@ static inline bool ixgbe_qv_lock_napi(struct ixgbe_q_vector *q_vector)
    } else
    /* we don't care if someone yielded */
    q_vector->state = IXGBE_QV_STATE_NAPI;
    - spin_unlock(&q_vector->lock);
    + spin_unlock_bh(&q_vector->lock);
    return rc;
    }

    @@ -413,14 +415,15 @@ static inline bool ixgbe_qv_lock_napi(struct ixgbe_q_vector *q_vector)
    static inline bool ixgbe_qv_unlock_napi(struct ixgbe_q_vector *q_vector)
    {
    int rc = false;
    - spin_lock(&q_vector->lock);
    + spin_lock_bh(&q_vector->lock);
    WARN_ON(q_vector->state & (IXGBE_QV_STATE_POLL |
    IXGBE_QV_STATE_NAPI_YIELD));

    if (q_vector->state & IXGBE_QV_STATE_POLL_YIELD)
    rc = true;
    - q_vector->state = IXGBE_QV_STATE_IDLE;
    - spin_unlock(&q_vector->lock);
    + /* will reset state to idle, unless QV is disabled */
    + q_vector->state &= IXGBE_QV_STATE_DISABLED;
    + spin_unlock_bh(&q_vector->lock);
    return rc;
    }

    @@ -451,7 +454,8 @@ static inline bool ixgbe_qv_unlock_poll(struct ixgbe_q_vector *q_vector)

    if (q_vector->state & IXGBE_QV_STATE_POLL_YIELD)
    rc = true;
    - q_vector->state = IXGBE_QV_STATE_IDLE;
    + /* will reset state to idle, unless QV is disabled */
    + q_vector->state &= IXGBE_QV_STATE_DISABLED;
    spin_unlock_bh(&q_vector->lock);
    return rc;
    }
    @@ -459,9 +463,23 @@ static inline bool ixgbe_qv_unlock_poll(struct ixgbe_q_vector *q_vector)
    /* true if a socket is polling, even if it did not get the lock */
    static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
    {
    - WARN_ON(!(q_vector->state & IXGBE_QV_LOCKED));
    + WARN_ON(!(q_vector->state & IXGBE_QV_OWNED));
    return q_vector->state & IXGBE_QV_USER_PEND;
    }
    +
    +/* false if QV is currently owned */
    +static inline bool ixgbe_qv_disable(struct ixgbe_q_vector *q_vector)
    +{
    + int rc = true;
    + spin_lock_bh(&q_vector->lock);
    + if (q_vector->state & IXGBE_QV_OWNED)
    + rc = false;
    + q_vector->state |= IXGBE_QV_STATE_DISABLED;
    + spin_unlock_bh(&q_vector->lock);
    +
    + return rc;
    +}
    +
    #else /* CONFIG_NET_RX_BUSY_POLL */
    static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
    {
    @@ -491,6 +509,12 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
    {
    return false;
    }
    +
    +static inline bool ixgbe_qv_disable(struct ixgbe_q_vector *q_vector)
    +{
    + return true;
    +}
    +
    #endif /* CONFIG_NET_RX_BUSY_POLL */

    #ifdef CONFIG_IXGBE_HWMON
    diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
    index bf046e14ceb5..a178a9caa763 100644
    --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
    +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
    @@ -3893,15 +3893,13 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter)
    {
    int q_idx;

    - local_bh_disable(); /* for ixgbe_qv_lock_napi() */
    for (q_idx = 0; q_idx < adapter->num_q_vectors; q_idx++) {
    napi_disable(&adapter->q_vector[q_idx]->napi);
    - while (!ixgbe_qv_lock_napi(adapter->q_vector[q_idx])) {
    + while (!ixgbe_qv_disable(adapter->q_vector[q_idx])) {
    pr_info("QV %d locked\n", q_idx);
    - mdelay(1);
    + usleep_range(1000, 20000);
    }
    }
    - local_bh_enable();
    }

    #ifdef CONFIG_IXGBE_DCB
    --
    2.0.4


    \
     
     \ /
      Last update: 2014-08-20 14:21    [W:4.067 / U:0.468 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site