[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>
This commit is contained in:
Stephen Hemminger 2006-02-22 11:45:03 -08:00 committed by Francois Romieu
parent 56a645cc1b
commit 791917deb6
2 changed files with 17 additions and 7 deletions

View File

@ -1079,8 +1079,10 @@ static int sky2_up(struct net_device *dev)
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 @@ static int sky2_down(struct net_device *dev)
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 @@ static void sky2_phy_task(void *arg)
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 @@ exit_loop:
}
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 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
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 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
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 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
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 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out_free_hw;
}
hw->pm_cap = pm_cap;
spin_lock_init(&hw->hw_lock);
#ifdef __BIG_ENDIAN
/* byte swap descriptors in hardware */

View File

@ -1876,8 +1876,9 @@ struct sky2_port {
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;