diff options
author | Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> | 2011-10-13 07:29:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-10-19 03:25:41 -0400 |
commit | fe47f1250805438fa06580c9ce6d37bc4bc595d2 (patch) | |
tree | 1e5b35b1e1c6fedad2c9d2eb3ec51b0e10941866 /drivers/net/caif/caif_hsi.c | |
parent | 94230febe47f82331f9493c4fd61085e2a6bf756 (diff) |
caif-hsi: Fixing a race condition in the caif_hsi code
cfhsi->tx_state was not protected by a spin lock. TX soft-irq could interrupt
cfhsi_tx_done_work work leading to inconsistent state of the driver.
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/caif_hsi.c')
-rw-r--r-- | drivers/net/caif/caif_hsi.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c index 193781389f73..36da27b50114 100644 --- a/drivers/net/caif/caif_hsi.c +++ b/drivers/net/caif/caif_hsi.c | |||
@@ -304,14 +304,22 @@ static void cfhsi_tx_done_work(struct work_struct *work) | |||
304 | spin_unlock_bh(&cfhsi->lock); | 304 | spin_unlock_bh(&cfhsi->lock); |
305 | 305 | ||
306 | /* Create HSI frame. */ | 306 | /* Create HSI frame. */ |
307 | len = cfhsi_tx_frm(desc, cfhsi); | 307 | do { |
308 | if (!len) { | 308 | len = cfhsi_tx_frm(desc, cfhsi); |
309 | cfhsi->tx_state = CFHSI_TX_STATE_IDLE; | 309 | if (!len) { |
310 | /* Start inactivity timer. */ | 310 | spin_lock_bh(&cfhsi->lock); |
311 | mod_timer(&cfhsi->timer, | 311 | if (unlikely(skb_peek(&cfhsi->qhead))) { |
312 | spin_unlock_bh(&cfhsi->lock); | ||
313 | continue; | ||
314 | } | ||
315 | cfhsi->tx_state = CFHSI_TX_STATE_IDLE; | ||
316 | /* Start inactivity timer. */ | ||
317 | mod_timer(&cfhsi->timer, | ||
312 | jiffies + CFHSI_INACTIVITY_TOUT); | 318 | jiffies + CFHSI_INACTIVITY_TOUT); |
313 | break; | 319 | spin_unlock_bh(&cfhsi->lock); |
314 | } | 320 | goto done; |
321 | } | ||
322 | } while (!len); | ||
315 | 323 | ||
316 | /* Set up new transfer. */ | 324 | /* Set up new transfer. */ |
317 | res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev); | 325 | res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev); |
@@ -320,6 +328,9 @@ static void cfhsi_tx_done_work(struct work_struct *work) | |||
320 | __func__, res); | 328 | __func__, res); |
321 | } | 329 | } |
322 | } while (res < 0); | 330 | } while (res < 0); |
331 | |||
332 | done: | ||
333 | return; | ||
323 | } | 334 | } |
324 | 335 | ||
325 | static void cfhsi_tx_done_cb(struct cfhsi_drv *drv) | 336 | static void cfhsi_tx_done_cb(struct cfhsi_drv *drv) |