diff options
author | Zhu Yi <yi.zhu@intel.com> | 2006-06-09 01:19:49 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2006-06-15 15:48:14 -0400 |
commit | 89c318ed3985da1271e00ad586f2dce8a6e75656 (patch) | |
tree | b8be0c7a76b11a971650eff3508efe197e896fe1 /drivers/net | |
parent | 7bd6b91800c996da328bd57e40e62b3f73760fbe (diff) |
[PATCH] ipw2200 locking fix
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@free.fr>
Cc: Arjan van de Ven <arjan@infradead.org>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ipw2200.c | 41 | ||||
-rw-r--r-- | drivers/net/wireless/ipw2200.h | 1 |
2 files changed, 33 insertions, 9 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 39f82f219749..081a8999666e 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -533,7 +533,7 @@ static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask) | |||
533 | ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); | 533 | ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); |
534 | } | 534 | } |
535 | 535 | ||
536 | static inline void ipw_enable_interrupts(struct ipw_priv *priv) | 536 | static inline void __ipw_enable_interrupts(struct ipw_priv *priv) |
537 | { | 537 | { |
538 | if (priv->status & STATUS_INT_ENABLED) | 538 | if (priv->status & STATUS_INT_ENABLED) |
539 | return; | 539 | return; |
@@ -541,7 +541,7 @@ static inline void ipw_enable_interrupts(struct ipw_priv *priv) | |||
541 | ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL); | 541 | ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL); |
542 | } | 542 | } |
543 | 543 | ||
544 | static inline void ipw_disable_interrupts(struct ipw_priv *priv) | 544 | static inline void __ipw_disable_interrupts(struct ipw_priv *priv) |
545 | { | 545 | { |
546 | if (!(priv->status & STATUS_INT_ENABLED)) | 546 | if (!(priv->status & STATUS_INT_ENABLED)) |
547 | return; | 547 | return; |
@@ -549,6 +549,24 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv) | |||
549 | ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); | 549 | ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); |
550 | } | 550 | } |
551 | 551 | ||
552 | static inline void ipw_enable_interrupts(struct ipw_priv *priv) | ||
553 | { | ||
554 | unsigned long flags; | ||
555 | |||
556 | spin_lock_irqsave(&priv->irq_lock, flags); | ||
557 | __ipw_enable_interrupts(priv); | ||
558 | spin_unlock_irqrestore(&priv->irq_lock, flags); | ||
559 | } | ||
560 | |||
561 | static inline void ipw_disable_interrupts(struct ipw_priv *priv) | ||
562 | { | ||
563 | unsigned long flags; | ||
564 | |||
565 | spin_lock_irqsave(&priv->irq_lock, flags); | ||
566 | __ipw_disable_interrupts(priv); | ||
567 | spin_unlock_irqrestore(&priv->irq_lock, flags); | ||
568 | } | ||
569 | |||
552 | #ifdef CONFIG_IPW2200_DEBUG | 570 | #ifdef CONFIG_IPW2200_DEBUG |
553 | static char *ipw_error_desc(u32 val) | 571 | static char *ipw_error_desc(u32 val) |
554 | { | 572 | { |
@@ -1856,7 +1874,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
1856 | unsigned long flags; | 1874 | unsigned long flags; |
1857 | int rc = 0; | 1875 | int rc = 0; |
1858 | 1876 | ||
1859 | spin_lock_irqsave(&priv->lock, flags); | 1877 | spin_lock_irqsave(&priv->irq_lock, flags); |
1860 | 1878 | ||
1861 | inta = ipw_read32(priv, IPW_INTA_RW); | 1879 | inta = ipw_read32(priv, IPW_INTA_RW); |
1862 | inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); | 1880 | inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); |
@@ -1865,6 +1883,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
1865 | /* Add any cached INTA values that need to be handled */ | 1883 | /* Add any cached INTA values that need to be handled */ |
1866 | inta |= priv->isr_inta; | 1884 | inta |= priv->isr_inta; |
1867 | 1885 | ||
1886 | spin_unlock_irqrestore(&priv->irq_lock, flags); | ||
1887 | |||
1888 | spin_lock_irqsave(&priv->lock, flags); | ||
1889 | |||
1868 | /* handle all the justifications for the interrupt */ | 1890 | /* handle all the justifications for the interrupt */ |
1869 | if (inta & IPW_INTA_BIT_RX_TRANSFER) { | 1891 | if (inta & IPW_INTA_BIT_RX_TRANSFER) { |
1870 | ipw_rx(priv); | 1892 | ipw_rx(priv); |
@@ -1993,10 +2015,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
1993 | IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); | 2015 | IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); |
1994 | } | 2016 | } |
1995 | 2017 | ||
2018 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2019 | |||
1996 | /* enable all interrupts */ | 2020 | /* enable all interrupts */ |
1997 | ipw_enable_interrupts(priv); | 2021 | ipw_enable_interrupts(priv); |
1998 | |||
1999 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2000 | } | 2022 | } |
2001 | 2023 | ||
2002 | #define IPW_CMD(x) case IPW_CMD_ ## x : return #x | 2024 | #define IPW_CMD(x) case IPW_CMD_ ## x : return #x |
@@ -10460,7 +10482,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | |||
10460 | if (!priv) | 10482 | if (!priv) |
10461 | return IRQ_NONE; | 10483 | return IRQ_NONE; |
10462 | 10484 | ||
10463 | spin_lock(&priv->lock); | 10485 | spin_lock(&priv->irq_lock); |
10464 | 10486 | ||
10465 | if (!(priv->status & STATUS_INT_ENABLED)) { | 10487 | if (!(priv->status & STATUS_INT_ENABLED)) { |
10466 | /* Shared IRQ */ | 10488 | /* Shared IRQ */ |
@@ -10482,7 +10504,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | |||
10482 | } | 10504 | } |
10483 | 10505 | ||
10484 | /* tell the device to stop sending interrupts */ | 10506 | /* tell the device to stop sending interrupts */ |
10485 | ipw_disable_interrupts(priv); | 10507 | __ipw_disable_interrupts(priv); |
10486 | 10508 | ||
10487 | /* ack current interrupts */ | 10509 | /* ack current interrupts */ |
10488 | inta &= (IPW_INTA_MASK_ALL & inta_mask); | 10510 | inta &= (IPW_INTA_MASK_ALL & inta_mask); |
@@ -10493,11 +10515,11 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | |||
10493 | 10515 | ||
10494 | tasklet_schedule(&priv->irq_tasklet); | 10516 | tasklet_schedule(&priv->irq_tasklet); |
10495 | 10517 | ||
10496 | spin_unlock(&priv->lock); | 10518 | spin_unlock(&priv->irq_lock); |
10497 | 10519 | ||
10498 | return IRQ_HANDLED; | 10520 | return IRQ_HANDLED; |
10499 | none: | 10521 | none: |
10500 | spin_unlock(&priv->lock); | 10522 | spin_unlock(&priv->irq_lock); |
10501 | return IRQ_NONE; | 10523 | return IRQ_NONE; |
10502 | } | 10524 | } |
10503 | 10525 | ||
@@ -11477,6 +11499,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
11477 | #ifdef CONFIG_IPW2200_DEBUG | 11499 | #ifdef CONFIG_IPW2200_DEBUG |
11478 | ipw_debug_level = debug; | 11500 | ipw_debug_level = debug; |
11479 | #endif | 11501 | #endif |
11502 | spin_lock_init(&priv->irq_lock); | ||
11480 | spin_lock_init(&priv->lock); | 11503 | spin_lock_init(&priv->lock); |
11481 | for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) | 11504 | for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) |
11482 | INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); | 11505 | INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); |
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 6044c0be2c80..ea12ad66b8e8 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h | |||
@@ -1173,6 +1173,7 @@ struct ipw_priv { | |||
1173 | struct ieee80211_device *ieee; | 1173 | struct ieee80211_device *ieee; |
1174 | 1174 | ||
1175 | spinlock_t lock; | 1175 | spinlock_t lock; |
1176 | spinlock_t irq_lock; | ||
1176 | struct mutex mutex; | 1177 | struct mutex mutex; |
1177 | 1178 | ||
1178 | /* basic pci-network driver stuff */ | 1179 | /* basic pci-network driver stuff */ |