bnx2x: Protect a SM state change
authorVladislav Zolotarov <vladz@broadcom.com>
Wed, 21 Jul 2010 05:59:01 +0000 (05:59 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 21 Jul 2010 18:11:54 +0000 (11:11 -0700)
Bug fix: Protect the statistics state machine state update with a
spinlock.  Otherwise there was a race condition that would cause the
statistics to stay enabled despite the fact that they were disabled in
the LINK_DOWN event handler.

Signed-off-by: Vladislav Zolotarov <vladz@broadcom.com>
Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/bnx2x.h
drivers/net/bnx2x_main.c

index 8bd23687c530f2e244c7050091d14c05b8fa7901..bb0872a633157157501b5c2312cc6a73d642ed1b 100644 (file)
@@ -1062,6 +1062,10 @@ struct bnx2x {
 
        /* used to synchronize stats collecting */
        int                     stats_state;
+
+       /* used for synchronization of concurrent threads statistics handling */
+       spinlock_t              stats_lock;
+
        /* used by dmae command loader */
        struct dmae_command     stats_dmae;
        int                     executer_idx;
index 57ff5b3bcce6fcd58edc438998ea1bf1ca08ee63..3dc876ce6e1f3afcb4c1b9fdbefb4fb13ee3395c 100644 (file)
@@ -4849,16 +4849,18 @@ static const struct {
 
 static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
 {
-       enum bnx2x_stats_state state = bp->stats_state;
+       enum bnx2x_stats_state state;
 
        if (unlikely(bp->panic))
                return;
 
-       bnx2x_stats_stm[state][event].action(bp);
+       /* Protect a state change flow */
+       spin_lock_bh(&bp->stats_lock);
+       state = bp->stats_state;
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
+       spin_unlock_bh(&bp->stats_lock);
 
-       /* Make sure the state has been "changed" */
-       smp_wmb();
+       bnx2x_stats_stm[state][event].action(bp);
 
        if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
                DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
@@ -9908,6 +9910,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
 
        mutex_init(&bp->port.phy_mutex);
        mutex_init(&bp->fw_mb_mutex);
+       spin_lock_init(&bp->stats_lock);
 #ifdef BCM_CNIC
        mutex_init(&bp->cnic_mutex);
 #endif