Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73033c98 authored by Dmitry Tarnyagin's avatar Dmitry Tarnyagin Committed by David S. Miller
Browse files

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: default avatarSjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fe47f125
Loading
Loading
Loading
Loading
+7 −3
Original line number Original line Diff line number Diff line
@@ -551,7 +551,9 @@ static void cfhsi_rx_done_work(struct work_struct *work)
		return;
		return;


	/* Update inactivity timer if pending. */
	/* Update inactivity timer if pending. */
	spin_lock_bh(&cfhsi->lock);
	mod_timer_pending(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT);
	mod_timer_pending(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT);
	spin_unlock_bh(&cfhsi->lock);


	if (cfhsi->rx_state == CFHSI_RX_STATE_DESC) {
	if (cfhsi->rx_state == CFHSI_RX_STATE_DESC) {
		desc_pld_len = cfhsi_rx_desc(desc, cfhsi);
		desc_pld_len = cfhsi_rx_desc(desc, cfhsi);
@@ -866,10 +868,10 @@ static int cfhsi_xmit(struct sk_buff *skb, struct net_device *dev)
		start_xfer = 1;
		start_xfer = 1;
	}
	}


	if (!start_xfer) {
		spin_unlock_bh(&cfhsi->lock);
		spin_unlock_bh(&cfhsi->lock);

	if (!start_xfer)
		return 0;
		return 0;
	}


	/* Delete inactivity timer if started. */
	/* Delete inactivity timer if started. */
#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
@@ -878,6 +880,8 @@ static int cfhsi_xmit(struct sk_buff *skb, struct net_device *dev)
	timer_active = del_timer(&cfhsi->timer);
	timer_active = del_timer(&cfhsi->timer);
#endif /* CONFIG_SMP */
#endif /* CONFIG_SMP */


	spin_unlock_bh(&cfhsi->lock);

	if (timer_active) {
	if (timer_active) {
		struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf;
		struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf;
		int len;
		int len;