diff options
author | Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> | 2011-10-13 07:29:24 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-10-19 03:25:41 -0400 |
commit | 73033c987a8bd0b080509063bb7c130b8941ad73 (patch) | |
tree | 3fc3b0f7160c9f9659eed18721b6770468def367 /drivers/net/caif | |
parent | fe47f1250805438fa06580c9ce6d37bc4bc595d2 (diff) |
caif-hsi: Fix for wakeup condition problem
Under stressed conditions a race could happen when del_timer_sync() was called
from softirq context at the same time when mod_timer_pending() for the same
timer was called from the workqueue. This leaded to a state mismatch in the
CAIF HSI driver and following unexpected link wakeup procedure.
The fix puts del_timer_sync() and mod_timer_pending() calls under a spin lock
to protect against the race condition.
Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/caif')
-rw-r--r-- | drivers/net/caif/caif_hsi.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c index 36da27b50114..82c4d6ca2d3f 100644 --- a/drivers/net/caif/caif_hsi.c +++ b/drivers/net/caif/caif_hsi.c | |||
@@ -551,7 +551,9 @@ static void cfhsi_rx_done_work(struct work_struct *work) | |||
551 | return; | 551 | return; |
552 | 552 | ||
553 | /* Update inactivity timer if pending. */ | 553 | /* Update inactivity timer if pending. */ |
554 | spin_lock_bh(&cfhsi->lock); | ||
554 | mod_timer_pending(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT); | 555 | mod_timer_pending(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT); |
556 | spin_unlock_bh(&cfhsi->lock); | ||
555 | 557 | ||
556 | if (cfhsi->rx_state == CFHSI_RX_STATE_DESC) { | 558 | if (cfhsi->rx_state == CFHSI_RX_STATE_DESC) { |
557 | desc_pld_len = cfhsi_rx_desc(desc, cfhsi); | 559 | desc_pld_len = cfhsi_rx_desc(desc, cfhsi); |
@@ -866,10 +868,10 @@ static int cfhsi_xmit(struct sk_buff *skb, struct net_device *dev) | |||
866 | start_xfer = 1; | 868 | start_xfer = 1; |
867 | } | 869 | } |
868 | 870 | ||
869 | spin_unlock_bh(&cfhsi->lock); | 871 | if (!start_xfer) { |
870 | 872 | spin_unlock_bh(&cfhsi->lock); | |
871 | if (!start_xfer) | ||
872 | return 0; | 873 | return 0; |
874 | } | ||
873 | 875 | ||
874 | /* Delete inactivity timer if started. */ | 876 | /* Delete inactivity timer if started. */ |
875 | #ifdef CONFIG_SMP | 877 | #ifdef CONFIG_SMP |
@@ -878,6 +880,8 @@ static int cfhsi_xmit(struct sk_buff *skb, struct net_device *dev) | |||
878 | timer_active = del_timer(&cfhsi->timer); | 880 | timer_active = del_timer(&cfhsi->timer); |
879 | #endif /* CONFIG_SMP */ | 881 | #endif /* CONFIG_SMP */ |
880 | 882 | ||
883 | spin_unlock_bh(&cfhsi->lock); | ||
884 | |||
881 | if (timer_active) { | 885 | if (timer_active) { |
882 | struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf; | 886 | struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf; |
883 | int len; | 887 | int len; |