Need to avoid race in updating IRQ mask. This can probably be replaced smarter use of the interrupt control registers (if/when chipset docs are available).
Signed-off-by: Stephen Hemminger <[EMAIL PROTECTED]> --- sky2.orig/drivers/net/sky2.c 2006-02-22 11:33:41.000000000 -0800 +++ sky2/drivers/net/sky2.c 2006-02-22 11:33:45.000000000 -0800 @@ -1079,8 +1079,10 @@ goto err_out; /* Enable interrupts from phy/mac for port */ + spin_lock_irq(&hw->hw_lock); hw->intr_mask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; sky2_write32(hw, B0_IMSK, hw->intr_mask); + spin_unlock_irq(&hw->hw_lock); return 0; err_out: @@ -1380,10 +1382,10 @@ netif_stop_queue(dev); /* Disable port IRQ */ - local_irq_disable(); + spin_lock_irq(&hw->hw_lock); hw->intr_mask &= ~((sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2); sky2_write32(hw, B0_IMSK, hw->intr_mask); - local_irq_enable(); + spin_unlock_irq(&hw->hw_lock); flush_scheduled_work(); @@ -1665,10 +1667,10 @@ out: up(&sky2->phy_sema); - local_irq_disable(); + spin_lock_irq(&hw->hw_lock); hw->intr_mask |= (sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2; sky2_write32(hw, B0_IMSK, hw->intr_mask); - local_irq_enable(); + spin_unlock_irq(&hw->hw_lock); } @@ -1994,9 +1996,13 @@ } if (likely(work_done < to_do)) { - netif_rx_complete(dev0); + spin_lock_irq(&hw->hw_lock); + __netif_rx_complete(dev0); + hw->intr_mask |= Y2_IS_STAT_BMU; sky2_write32(hw, B0_IMSK, hw->intr_mask); + spin_unlock_irq(&hw->hw_lock); + return 0; } else { *budget -= work_done; @@ -2128,6 +2134,7 @@ hw->intr_mask &= ~(port == 0 ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2); sky2_write32(hw, B0_IMSK, hw->intr_mask); + schedule_work(&sky2->phy_task); } @@ -2141,6 +2148,7 @@ if (status == 0 || status == ~0) return IRQ_NONE; + spin_lock(&hw->hw_lock); if (status & Y2_IS_HW_ERR) sky2_hw_intr(hw); @@ -2169,7 +2177,7 @@ sky2_write32(hw, B0_Y2_SP_ICR, 2); - sky2_read32(hw, B0_IMSK); + spin_unlock(&hw->hw_lock); return IRQ_HANDLED; } @@ -3241,6 +3249,7 @@ goto err_out_free_hw; } hw->pm_cap = pm_cap; + spin_lock_init(&hw->hw_lock); #ifdef __BIG_ENDIAN /* byte swap descriptors in hardware */ --- sky2.orig/drivers/net/sky2.h 2006-02-22 11:33:41.000000000 -0800 +++ sky2/drivers/net/sky2.h 2006-02-22 11:33:45.000000000 -0800 @@ -1876,8 +1876,9 @@ struct sky2_hw { void __iomem *regs; struct pci_dev *pdev; - u32 intr_mask; struct net_device *dev[2]; + spinlock_t hw_lock; + u32 intr_mask; int pm_cap; int msi; -- - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html