aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-02-22 14:45:03 -0500
committerFrancois Romieu <romieu@fr.zoreil.com>2006-02-22 19:25:26 -0500
commit791917deb63c6d8beb3f347ea0911371deff1624 (patch)
tree170bc081f03326f75b6b5ccce7d7d1df28a2c833
parent56a645cc1bc16ab33b33a3e0854a46c5d2c864f3 (diff)
[PATCH] sky2: close race on IRQ mask update.
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 <shemminger@osdl.org>
-rw-r--r--drivers/net/sky2.c21
-rw-r--r--drivers/net/sky2.h3
2 files changed, 17 insertions, 7 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index fbbc85532c2e..ca8160d68229 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1079,8 +1079,10 @@ static int sky2_up(struct net_device *dev)
1079 goto err_out; 1079 goto err_out;
1080 1080
1081 /* Enable interrupts from phy/mac for port */ 1081 /* Enable interrupts from phy/mac for port */
1082 spin_lock_irq(&hw->hw_lock);
1082 hw->intr_mask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; 1083 hw->intr_mask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2;
1083 sky2_write32(hw, B0_IMSK, hw->intr_mask); 1084 sky2_write32(hw, B0_IMSK, hw->intr_mask);
1085 spin_unlock_irq(&hw->hw_lock);
1084 return 0; 1086 return 0;
1085 1087
1086err_out: 1088err_out:
@@ -1380,10 +1382,10 @@ static int sky2_down(struct net_device *dev)
1380 netif_stop_queue(dev); 1382 netif_stop_queue(dev);
1381 1383
1382 /* Disable port IRQ */ 1384 /* Disable port IRQ */
1383 local_irq_disable(); 1385 spin_lock_irq(&hw->hw_lock);
1384 hw->intr_mask &= ~((sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2); 1386 hw->intr_mask &= ~((sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2);
1385 sky2_write32(hw, B0_IMSK, hw->intr_mask); 1387 sky2_write32(hw, B0_IMSK, hw->intr_mask);
1386 local_irq_enable(); 1388 spin_unlock_irq(&hw->hw_lock);
1387 1389
1388 flush_scheduled_work(); 1390 flush_scheduled_work();
1389 1391
@@ -1665,10 +1667,10 @@ static void sky2_phy_task(void *arg)
1665out: 1667out:
1666 up(&sky2->phy_sema); 1668 up(&sky2->phy_sema);
1667 1669
1668 local_irq_disable(); 1670 spin_lock_irq(&hw->hw_lock);
1669 hw->intr_mask |= (sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2; 1671 hw->intr_mask |= (sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2;
1670 sky2_write32(hw, B0_IMSK, hw->intr_mask); 1672 sky2_write32(hw, B0_IMSK, hw->intr_mask);
1671 local_irq_enable(); 1673 spin_unlock_irq(&hw->hw_lock);
1672} 1674}
1673 1675
1674 1676
@@ -1994,9 +1996,13 @@ exit_loop:
1994 } 1996 }
1995 1997
1996 if (likely(work_done < to_do)) { 1998 if (likely(work_done < to_do)) {
1997 netif_rx_complete(dev0); 1999 spin_lock_irq(&hw->hw_lock);
2000 __netif_rx_complete(dev0);
2001
1998 hw->intr_mask |= Y2_IS_STAT_BMU; 2002 hw->intr_mask |= Y2_IS_STAT_BMU;
1999 sky2_write32(hw, B0_IMSK, hw->intr_mask); 2003 sky2_write32(hw, B0_IMSK, hw->intr_mask);
2004 spin_unlock_irq(&hw->hw_lock);
2005
2000 return 0; 2006 return 0;
2001 } else { 2007 } else {
2002 *budget -= work_done; 2008 *budget -= work_done;
@@ -2128,6 +2134,7 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
2128 2134
2129 hw->intr_mask &= ~(port == 0 ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2); 2135 hw->intr_mask &= ~(port == 0 ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2);
2130 sky2_write32(hw, B0_IMSK, hw->intr_mask); 2136 sky2_write32(hw, B0_IMSK, hw->intr_mask);
2137
2131 schedule_work(&sky2->phy_task); 2138 schedule_work(&sky2->phy_task);
2132} 2139}
2133 2140
@@ -2141,6 +2148,7 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
2141 if (status == 0 || status == ~0) 2148 if (status == 0 || status == ~0)
2142 return IRQ_NONE; 2149 return IRQ_NONE;
2143 2150
2151 spin_lock(&hw->hw_lock);
2144 if (status & Y2_IS_HW_ERR) 2152 if (status & Y2_IS_HW_ERR)
2145 sky2_hw_intr(hw); 2153 sky2_hw_intr(hw);
2146 2154
@@ -2169,7 +2177,7 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
2169 2177
2170 sky2_write32(hw, B0_Y2_SP_ICR, 2); 2178 sky2_write32(hw, B0_Y2_SP_ICR, 2);
2171 2179
2172 sky2_read32(hw, B0_IMSK); 2180 spin_unlock(&hw->hw_lock);
2173 2181
2174 return IRQ_HANDLED; 2182 return IRQ_HANDLED;
2175} 2183}
@@ -3241,6 +3249,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
3241 goto err_out_free_hw; 3249 goto err_out_free_hw;
3242 } 3250 }
3243 hw->pm_cap = pm_cap; 3251 hw->pm_cap = pm_cap;
3252 spin_lock_init(&hw->hw_lock);
3244 3253
3245#ifdef __BIG_ENDIAN 3254#ifdef __BIG_ENDIAN
3246 /* byte swap descriptors in hardware */ 3255 /* byte swap descriptors in hardware */
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 9e40766150b4..3edb98075e0a 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1876,8 +1876,9 @@ struct sky2_port {
1876struct sky2_hw { 1876struct sky2_hw {
1877 void __iomem *regs; 1877 void __iomem *regs;
1878 struct pci_dev *pdev; 1878 struct pci_dev *pdev;
1879 u32 intr_mask;
1880 struct net_device *dev[2]; 1879 struct net_device *dev[2];
1880 spinlock_t hw_lock;
1881 u32 intr_mask;
1881 1882
1882 int pm_cap; 1883 int pm_cap;
1883 int msi; 1884 int msi;