mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
net/sonic: Clear interrupt flags immediately
commit5fedabf5a7upstream. The chip can change a packet's descriptor status flags at any time. However, an active interrupt flag gets cleared rather late. This allows a race condition that could theoretically lose an interrupt. Fix this by clearing asserted interrupt flags immediately. Fixes:efcce83936("[PATCH] macsonic/jazzsonic network drivers update") Tested-by: Stan Johnson <userm57@yahoo.com> Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
655fb22090
commit
b9ef3fe67d
@@ -303,10 +303,11 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
do {
|
||||
SONIC_WRITE(SONIC_ISR, status); /* clear the interrupt(s) */
|
||||
|
||||
if (status & SONIC_INT_PKTRX) {
|
||||
netif_dbg(lp, intr, dev, "%s: packet rx\n", __func__);
|
||||
sonic_rx(dev); /* got packet(s) */
|
||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_PKTRX); /* clear the interrupt */
|
||||
}
|
||||
|
||||
if (status & SONIC_INT_TXDN) {
|
||||
@@ -361,7 +362,6 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id)
|
||||
if (freed_some || lp->tx_skb[entry] == NULL)
|
||||
netif_wake_queue(dev); /* The ring is no longer full */
|
||||
lp->cur_tx = entry;
|
||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_TXDN); /* clear the interrupt */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -371,42 +371,31 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id)
|
||||
netif_dbg(lp, rx_err, dev, "%s: rx fifo overrun\n",
|
||||
__func__);
|
||||
lp->stats.rx_fifo_errors++;
|
||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_RFO); /* clear the interrupt */
|
||||
}
|
||||
if (status & SONIC_INT_RDE) {
|
||||
netif_dbg(lp, rx_err, dev, "%s: rx descriptors exhausted\n",
|
||||
__func__);
|
||||
lp->stats.rx_dropped++;
|
||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_RDE); /* clear the interrupt */
|
||||
}
|
||||
if (status & SONIC_INT_RBAE) {
|
||||
netif_dbg(lp, rx_err, dev, "%s: rx buffer area exceeded\n",
|
||||
__func__);
|
||||
lp->stats.rx_dropped++;
|
||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_RBAE); /* clear the interrupt */
|
||||
}
|
||||
|
||||
/* counter overruns; all counters are 16bit wide */
|
||||
if (status & SONIC_INT_FAE) {
|
||||
if (status & SONIC_INT_FAE)
|
||||
lp->stats.rx_frame_errors += 65536;
|
||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_FAE); /* clear the interrupt */
|
||||
}
|
||||
if (status & SONIC_INT_CRC) {
|
||||
if (status & SONIC_INT_CRC)
|
||||
lp->stats.rx_crc_errors += 65536;
|
||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_CRC); /* clear the interrupt */
|
||||
}
|
||||
if (status & SONIC_INT_MP) {
|
||||
if (status & SONIC_INT_MP)
|
||||
lp->stats.rx_missed_errors += 65536;
|
||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_MP); /* clear the interrupt */
|
||||
}
|
||||
|
||||
/* transmit error */
|
||||
if (status & SONIC_INT_TXER) {
|
||||
if (status & SONIC_INT_TXER)
|
||||
if (SONIC_READ(SONIC_TCR) & SONIC_TCR_FU)
|
||||
netif_dbg(lp, tx_err, dev, "%s: tx fifo underrun\n",
|
||||
__func__);
|
||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_TXER); /* clear the interrupt */
|
||||
}
|
||||
|
||||
/* bus retry */
|
||||
if (status & SONIC_INT_BR) {
|
||||
@@ -415,13 +404,8 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id)
|
||||
/* ... to help debug DMA problems causing endless interrupts. */
|
||||
/* Bounce the eth interface to turn on the interrupt again. */
|
||||
SONIC_WRITE(SONIC_IMR, 0);
|
||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_BR); /* clear the interrupt */
|
||||
}
|
||||
|
||||
/* load CAM done */
|
||||
if (status & SONIC_INT_LCD)
|
||||
SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */
|
||||
|
||||
status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT;
|
||||
} while (status);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user