aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/caif/caif_hsi.c
diff options
context:
space:
mode:
authorDmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>2011-10-13 07:29:23 -0400
committerDavid S. Miller <davem@davemloft.net>2011-10-19 03:25:41 -0400
commitfe47f1250805438fa06580c9ce6d37bc4bc595d2 (patch)
tree1e5b35b1e1c6fedad2c9d2eb3ec51b0e10941866 /drivers/net/caif/caif_hsi.c
parent94230febe47f82331f9493c4fd61085e2a6bf756 (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.c25
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
332done:
333 return;
323} 334}
324 335
325static void cfhsi_tx_done_cb(struct cfhsi_drv *drv) 336static void cfhsi_tx_done_cb(struct cfhsi_drv *drv)