diff options
author | Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org> | 2016-08-22 20:18:25 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-08-23 09:13:10 +0200 |
commit | 080d5c5ac8e4cfab4f3b1239667cf422925efcc3 (patch) | |
tree | 373869a7aad67b1c177d008fecb123bc5bc6b941 /drivers/net/ethernet/ti/davinci_cpdma.c | |
parent | net: ethernet: ti: davinci_cpdma: split descs num between all channels (diff) | |
download | linux-080d5c5ac8e4cfab4f3b1239667cf422925efcc3.tar.xz linux-080d5c5ac8e4cfab4f3b1239667cf422925efcc3.zip |
net: ethernet: ti: davinci_cpdma: fix locking while ctrl_stop
The interrupts shouldn't be disabled while receiving skb, but while
ctrl_stop, the channels are stopped and all remaining packets are
handled with netif_receive_skb(), it can cause WARN_ONCE when ctrl
is stopping while not all packets were handled with NAPIs:
lock_irq_save
cpdma_ctlr_stop
cpdma_chan_top
__cpdma_chan_free
cpsw_rx_handler
netif_receive_skb
So, split locking while ctrl stop thus interrupts are still
enabled while skbs handling. It can cause WARN_ONCE in rare
cases when ctrl is stopping while not all packets were handled
with NAPIs.
Reviewed-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/ti/davinci_cpdma.c')
-rw-r--r-- | drivers/net/ethernet/ti/davinci_cpdma.c | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index 167fd659319d..ffb32af94f4c 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -334,12 +334,14 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr) } ctlr->state = CPDMA_STATE_TEARDOWN; + spin_unlock_irqrestore(&ctlr->lock, flags); for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) { if (ctlr->channels[i]) cpdma_chan_stop(ctlr->channels[i]); } + spin_lock_irqsave(&ctlr->lock, flags); dma_reg_write(ctlr, CPDMA_RXINTMASKCLEAR, 0xffffffff); dma_reg_write(ctlr, CPDMA_TXINTMASKCLEAR, 0xffffffff); |