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>
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
index 1937813..36da27b 100644
--- a/drivers/net/caif/caif_hsi.c
+++ b/drivers/net/caif/caif_hsi.c
@@ -304,14 +304,22 @@
spin_unlock_bh(&cfhsi->lock);
/* Create HSI frame. */
- len = cfhsi_tx_frm(desc, cfhsi);
- if (!len) {
- cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
- /* Start inactivity timer. */
- mod_timer(&cfhsi->timer,
+ do {
+ len = cfhsi_tx_frm(desc, cfhsi);
+ if (!len) {
+ spin_lock_bh(&cfhsi->lock);
+ if (unlikely(skb_peek(&cfhsi->qhead))) {
+ spin_unlock_bh(&cfhsi->lock);
+ continue;
+ }
+ cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
+ /* Start inactivity timer. */
+ mod_timer(&cfhsi->timer,
jiffies + CFHSI_INACTIVITY_TOUT);
- break;
- }
+ spin_unlock_bh(&cfhsi->lock);
+ goto done;
+ }
+ } while (!len);
/* Set up new transfer. */
res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev);
@@ -320,6 +328,9 @@
__func__, res);
}
} while (res < 0);
+
+done:
+ return;
}
static void cfhsi_tx_done_cb(struct cfhsi_drv *drv)