msm: rmnet_bam: Handle Network TX Queue Race Condition
The netif TX queue is started and stopped based upon the watermark state
maintained by BAM DMUX. The queue is checked after TX-enqueue
operations to disable the queue if the high watermark is hit and after
TX-dequeue operations to enable the queue if the low watermark is hit.
Without locking, this opens a race condition where the TX-dequeue check
and the call to stop the queue can happen after the write-done
completion has occurred which would restart the queue. This results in
the queue being stopped indefinitely which results in a permanent data
stall.
CRs-Fixed: 347174
Change-Id: I5975815f7ce774c1230f0254b40dfb3f056482c4
Signed-off-by: Eric Holmberg <eholmber@codeaurora.org>
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 89d7fc9..6361d6d 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -982,11 +982,13 @@
int msm_bam_dmux_is_ch_low(uint32_t id)
{
+ unsigned long flags;
int ret;
if (id >= BAM_DMUX_NUM_CHANNELS)
return -EINVAL;
+ spin_lock_irqsave(&bam_ch[id].lock, flags);
bam_ch[id].use_wm = 1;
ret = bam_ch[id].num_tx_pkts <= LOW_WATERMARK;
DBG("%s: ch %d num tx pkts=%d, LWM=%d\n", __func__,
@@ -995,6 +997,7 @@
ret = -ENODEV;
pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
}
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
return ret;
}