The patch titled ipw2200 locking fix has been added to the -mm tree. Its filename is ipw2200-locking-fix.patch See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find out what to do about this ------------------------------------------------------ Subject: ipw2200 locking fix From: Zhu Yi <yi.zhu@xxxxxxxxx> Well, this is not 100% if when the card fires two consecutive interrupts. Though unlikely, it's better to protect early than seeing some "weird" bugs one day. I proposed attached patch. If you can help to test, that will be appreciated (I cannot see the lockdep warning on my box somehow). Cc: Frederik Deweerdt <deweerdt@xxxxxxx> Cc: Arjan van de Ven <arjan@xxxxxxxxxxxxx> Cc: Ingo Molnar <mingo@xxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxx> --- drivers/net/wireless/ipw2200.c | 37 +++++++++++++++++++++++-------- drivers/net/wireless/ipw2200.h | 2 + 2 files changed, 30 insertions(+), 9 deletions(-) diff -puN drivers/net/wireless/ipw2200.c~ipw2200-locking-fix drivers/net/wireless/ipw2200.c --- devel/drivers/net/wireless/ipw2200.c~ipw2200-locking-fix 2006-06-04 23:34:52.000000000 -0700 +++ devel-akpm/drivers/net/wireless/ipw2200.c 2006-06-04 23:34:52.000000000 -0700 @@ -533,7 +533,7 @@ static inline void ipw_clear_bit(struct ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); } -static inline void ipw_enable_interrupts(struct ipw_priv *priv) +static inline void __ipw_enable_interrupts(struct ipw_priv *priv) { if (priv->status & STATUS_INT_ENABLED) return; @@ -541,7 +541,7 @@ static inline void ipw_enable_interrupts ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL); } -static inline void ipw_disable_interrupts(struct ipw_priv *priv) +static inline void __ipw_disable_interrupts(struct ipw_priv *priv) { if (!(priv->status & STATUS_INT_ENABLED)) return; @@ -549,6 +549,20 @@ static inline void ipw_disable_interrupt ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); } +static inline void ipw_enable_interrupts(struct ipw_priv *priv) +{ + spin_lock_irqsave(&priv->irq_lock, priv->lock_flags); + __ipw_enable_interrupts(priv); + spin_unlock_irqrestore(&priv->irq_lock, priv->lock_flags); +} + +static inline void ipw_disable_interrupts(struct ipw_priv *priv) +{ + spin_lock_irqsave(&priv->irq_lock, priv->lock_flags); + __ipw_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->irq_lock, priv->lock_flags); +} + #ifdef CONFIG_IPW2200_DEBUG static char *ipw_error_desc(u32 val) { @@ -1856,7 +1870,7 @@ static void ipw_irq_tasklet(struct ipw_p unsigned long flags; int rc = 0; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->irq_lock, flags); inta = ipw_read32(priv, IPW_INTA_RW); inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); @@ -1865,6 +1879,10 @@ static void ipw_irq_tasklet(struct ipw_p /* Add any cached INTA values that need to be handled */ inta |= priv->isr_inta; + spin_unlock_irqrestore(&priv->irq_lock, flags); + + spin_lock_irqsave(&priv->lock, flags); + /* handle all the justifications for the interrupt */ if (inta & IPW_INTA_BIT_RX_TRANSFER) { ipw_rx(priv); @@ -1993,10 +2011,10 @@ static void ipw_irq_tasklet(struct ipw_p IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); } + spin_unlock_irqrestore(&priv->lock, flags); + /* enable all interrupts */ ipw_enable_interrupts(priv); - - spin_unlock_irqrestore(&priv->lock, flags); } #define IPW_CMD(x) case IPW_CMD_ ## x : return #x @@ -10460,7 +10478,7 @@ static irqreturn_t ipw_isr(int irq, void if (!priv) return IRQ_NONE; - spin_lock(&priv->lock); + spin_lock(&priv->irq_lock); if (!(priv->status & STATUS_INT_ENABLED)) { /* Shared IRQ */ @@ -10482,7 +10500,7 @@ static irqreturn_t ipw_isr(int irq, void } /* tell the device to stop sending interrupts */ - ipw_disable_interrupts(priv); + __ipw_disable_interrupts(priv); /* ack current interrupts */ inta &= (IPW_INTA_MASK_ALL & inta_mask); @@ -10493,11 +10511,11 @@ static irqreturn_t ipw_isr(int irq, void tasklet_schedule(&priv->irq_tasklet); - spin_unlock(&priv->lock); + spin_unlock(&priv->irq_lock); return IRQ_HANDLED; none: - spin_unlock(&priv->lock); + spin_unlock(&priv->irq_lock); return IRQ_NONE; } @@ -11477,6 +11495,7 @@ static int ipw_pci_probe(struct pci_dev #ifdef CONFIG_IPW2200_DEBUG ipw_debug_level = debug; #endif + spin_lock_init(&priv->irq_lock); spin_lock_init(&priv->lock); for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); diff -puN drivers/net/wireless/ipw2200.h~ipw2200-locking-fix drivers/net/wireless/ipw2200.h --- devel/drivers/net/wireless/ipw2200.h~ipw2200-locking-fix 2006-06-04 23:34:52.000000000 -0700 +++ devel-akpm/drivers/net/wireless/ipw2200.h 2006-06-04 23:34:52.000000000 -0700 @@ -1173,6 +1173,8 @@ struct ipw_priv { struct ieee80211_device *ieee; spinlock_t lock; + spinlock_t irq_lock; + unsigned long lock_flags; struct mutex mutex; /* basic pci-network driver stuff */ _ Patches currently in -mm which might be from yi.zhu@xxxxxxxxx are git-netdev-all.patch ipw2200-locking-fix.patch - To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html