sky2: status irq hang fix
authorStephen Hemminger <shemminger@osdl.org>
Mon, 8 May 2006 22:11:27 +0000 (15:11 -0700)
committerStephen Hemminger <shemminger@osdl.org>
Mon, 8 May 2006 23:00:24 +0000 (16:00 -0700)
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>
drivers/net/sky2.c

index 76da74fbe859b16d44c1ca109c6b77bb747e8f82..552aca76b283fd3263fbd945dc7c3c3c289a283b 100644 (file)
@@ -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);