From: Sebastian Andrzej Siewior Date: Wed, 24 Apr 2013 20:01:22 +0200 Subject: [PATCH] net/cpsw: use a lock around source testing Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/3.10/patches-3.10.4-rt1.tar.xz For some reason on RT it happens that the TX interrupt fires over and over again but according to tx_stat there is nothing going on. Same goes for RX but not that often. With this lock around it this is gone. However I still see from time to time interrupts where each source is set to 0. Signed-off-by: Sebastian Andrzej Siewior --- drivers/net/ethernet/ti/cpsw.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) Index: linux-stable/drivers/net/ethernet/ti/cpsw.c =================================================================== --- linux-stable.orig/drivers/net/ethernet/ti/cpsw.c +++ linux-stable/drivers/net/ethernet/ti/cpsw.c @@ -490,7 +490,7 @@ void cpsw_rx_handler(void *token, int le skb_put(skb, len); cpts_rx_timestamp(priv->cpts, skb); skb->protocol = eth_type_trans(skb, ndev); - netif_receive_skb(skb); + netif_rx(skb); priv->stats.rx_bytes += len; priv->stats.rx_packets++; } else { @@ -507,19 +507,24 @@ void cpsw_rx_handler(void *token, int le static irqreturn_t cpsw_interrupt(int irq, void *dev_id) { struct cpsw_priv *priv = dev_id; + unsigned long flags; u32 rx, tx, rx_thresh; + spin_lock_irqsave(&priv->lock, flags); rx_thresh = __raw_readl(&priv->wr_regs->rx_thresh_stat); rx = __raw_readl(&priv->wr_regs->rx_stat); tx = __raw_readl(&priv->wr_regs->tx_stat); - if (!rx_thresh && !rx && !tx) + if (!rx_thresh && !rx && !tx) { + spin_unlock_irqrestore(&priv->lock, flags); return IRQ_NONE; + } cpsw_intr_disable(priv); if (priv->irq_enabled == true) { cpsw_disable_irq(priv); priv->irq_enabled = false; } + spin_unlock_irqrestore(&priv->lock, flags); if (netif_running(priv->ndev)) { napi_schedule(&priv->napi); @@ -541,7 +546,9 @@ static int cpsw_poll(struct napi_struct { struct cpsw_priv *priv = napi_to_priv(napi); int num_tx, num_rx; + unsigned long flags; + spin_lock_irqsave(&priv->lock, flags); num_tx = cpdma_chan_process(priv->txch, 128); if (num_tx) cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);