summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-05-09 02:11:27 +0400
committerStephen Hemminger <shemminger@osdl.org>2006-05-09 03:00:24 +0400
commit1e5f1283a2aed429f4457e2eb875b1928a6643df (patch)
tree7468304afc4e981f54686d719d7dfa6877dc7726
parentd324031245abbb54e4e0321004430826052b6c37 (diff)
downloadlinux-1e5f1283a2aed429f4457e2eb875b1928a6643df.tar.xz
sky2: status irq hang fix
The status interrupt flag should be cleared before processing, not afterwards to avoid race. Need to process in poll routine even if no new interrupt status. This is a normal occurrence when more than 64 frames (NAPI weight) are processed in one poll routine. Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
-rw-r--r--drivers/net/sky2.c53
1 files changed, 25 insertions, 28 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 76da74fbe859..552aca76b283 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -2105,45 +2105,42 @@ static int sky2_poll(struct net_device *dev0, int *budget)
int work_done = 0;
u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
- if (unlikely(status & ~Y2_IS_STAT_BMU)) {
- if (status & Y2_IS_HW_ERR)
- sky2_hw_intr(hw);
+ if (status & Y2_IS_HW_ERR)
+ sky2_hw_intr(hw);
- if (status & Y2_IS_IRQ_PHY1)
- sky2_phy_intr(hw, 0);
+ if (status & Y2_IS_IRQ_PHY1)
+ sky2_phy_intr(hw, 0);
- if (status & Y2_IS_IRQ_PHY2)
- sky2_phy_intr(hw, 1);
+ if (status & Y2_IS_IRQ_PHY2)
+ sky2_phy_intr(hw, 1);
- if (status & Y2_IS_IRQ_MAC1)
- sky2_mac_intr(hw, 0);
+ if (status & Y2_IS_IRQ_MAC1)
+ sky2_mac_intr(hw, 0);
- if (status & Y2_IS_IRQ_MAC2)
- sky2_mac_intr(hw, 1);
+ if (status & Y2_IS_IRQ_MAC2)
+ sky2_mac_intr(hw, 1);
- if (status & Y2_IS_CHK_RX1)
- sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1);
+ if (status & Y2_IS_CHK_RX1)
+ sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1);
- if (status & Y2_IS_CHK_RX2)
- sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2);
+ if (status & Y2_IS_CHK_RX2)
+ sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2);
- if (status & Y2_IS_CHK_TXA1)
- sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1);
+ if (status & Y2_IS_CHK_TXA1)
+ sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1);
- if (status & Y2_IS_CHK_TXA2)
- sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
- }
+ if (status & Y2_IS_CHK_TXA2)
+ sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
- if (status & Y2_IS_STAT_BMU) {
- work_done = sky2_status_intr(hw, work_limit);
- *budget -= work_done;
- dev0->quota -= work_done;
+ if (status & Y2_IS_STAT_BMU)
+ sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
- if (work_done >= work_limit)
- return 1;
+ work_done = sky2_status_intr(hw, work_limit);
+ *budget -= work_done;
+ dev0->quota -= work_done;
- sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
- }
+ if (work_done >= work_limit)
+ return 1;
mod_timer(&hw->idle_timer, jiffies + HZ);