diff options
| author | Tim Gardner <tim.gardner@canonical.com> | 2010-06-08 13:33:02 -0400 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2010-06-15 15:44:41 -0400 |
| commit | d6a574ff6bfb842bdb98065da053881ff527be46 (patch) | |
| tree | 899cdc5cdfc75d21a8c258ecfc2bc6b1e1c79895 | |
| parent | a69b03e941abae00380fc6bc1877fb797a1b31e6 (diff) | |
hostap: Protect against initialization interrupt
Use an irq spinlock to hold off the IRQ handler until
enough early card init is complete such that the handler
can run without faulting.
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Cc: stable@kernel.org
Signed-off-by: John W. Linville <linville@tuxdriver.com>
| -rw-r--r-- | drivers/net/wireless/hostap/hostap_cs.c | 15 | ||||
| -rw-r--r-- | drivers/net/wireless/hostap/hostap_hw.c | 13 | ||||
| -rw-r--r-- | drivers/net/wireless/hostap/hostap_wlan.h | 2 |
3 files changed, 27 insertions, 3 deletions
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index db72461c486b..29b31a694b59 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c | |||
| @@ -594,6 +594,7 @@ static int prism2_config(struct pcmcia_device *link) | |||
| 594 | local_info_t *local; | 594 | local_info_t *local; |
| 595 | int ret = 1; | 595 | int ret = 1; |
| 596 | struct hostap_cs_priv *hw_priv; | 596 | struct hostap_cs_priv *hw_priv; |
| 597 | unsigned long flags; | ||
| 597 | 598 | ||
| 598 | PDEBUG(DEBUG_FLOW, "prism2_config()\n"); | 599 | PDEBUG(DEBUG_FLOW, "prism2_config()\n"); |
| 599 | 600 | ||
| @@ -625,9 +626,15 @@ static int prism2_config(struct pcmcia_device *link) | |||
| 625 | local->hw_priv = hw_priv; | 626 | local->hw_priv = hw_priv; |
| 626 | hw_priv->link = link; | 627 | hw_priv->link = link; |
| 627 | 628 | ||
| 629 | /* | ||
| 630 | * Make sure the IRQ handler cannot proceed until at least | ||
| 631 | * dev->base_addr is initialized. | ||
| 632 | */ | ||
| 633 | spin_lock_irqsave(&local->irq_init_lock, flags); | ||
| 634 | |||
| 628 | ret = pcmcia_request_irq(link, prism2_interrupt); | 635 | ret = pcmcia_request_irq(link, prism2_interrupt); |
| 629 | if (ret) | 636 | if (ret) |
| 630 | goto failed; | 637 | goto failed_unlock; |
| 631 | 638 | ||
| 632 | /* | 639 | /* |
| 633 | * This actually configures the PCMCIA socket -- setting up | 640 | * This actually configures the PCMCIA socket -- setting up |
| @@ -636,11 +643,13 @@ static int prism2_config(struct pcmcia_device *link) | |||
| 636 | */ | 643 | */ |
| 637 | ret = pcmcia_request_configuration(link, &link->conf); | 644 | ret = pcmcia_request_configuration(link, &link->conf); |
| 638 | if (ret) | 645 | if (ret) |
| 639 | goto failed; | 646 | goto failed_unlock; |
| 640 | 647 | ||
| 641 | dev->irq = link->irq; | 648 | dev->irq = link->irq; |
| 642 | dev->base_addr = link->io.BasePort1; | 649 | dev->base_addr = link->io.BasePort1; |
| 643 | 650 | ||
| 651 | spin_unlock_irqrestore(&local->irq_init_lock, flags); | ||
| 652 | |||
| 644 | /* Finally, report what we've done */ | 653 | /* Finally, report what we've done */ |
| 645 | printk(KERN_INFO "%s: index 0x%02x: ", | 654 | printk(KERN_INFO "%s: index 0x%02x: ", |
| 646 | dev_info, link->conf.ConfigIndex); | 655 | dev_info, link->conf.ConfigIndex); |
| @@ -667,6 +676,8 @@ static int prism2_config(struct pcmcia_device *link) | |||
| 667 | 676 | ||
| 668 | return ret; | 677 | return ret; |
| 669 | 678 | ||
| 679 | failed_unlock: | ||
| 680 | spin_unlock_irqrestore(&local->irq_init_lock, flags); | ||
| 670 | failed: | 681 | failed: |
| 671 | kfree(hw_priv); | 682 | kfree(hw_priv); |
| 672 | prism2_release((u_long)link); | 683 | prism2_release((u_long)link); |
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index ff9b5c882184..2f999fc94f60 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c | |||
| @@ -2621,6 +2621,18 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id) | |||
| 2621 | iface = netdev_priv(dev); | 2621 | iface = netdev_priv(dev); |
| 2622 | local = iface->local; | 2622 | local = iface->local; |
| 2623 | 2623 | ||
| 2624 | /* Detect early interrupt before driver is fully configued */ | ||
| 2625 | spin_lock(&local->irq_init_lock); | ||
| 2626 | if (!dev->base_addr) { | ||
| 2627 | if (net_ratelimit()) { | ||
| 2628 | printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n", | ||
| 2629 | dev->name); | ||
| 2630 | } | ||
| 2631 | spin_unlock(&local->irq_init_lock); | ||
| 2632 | return IRQ_HANDLED; | ||
| 2633 | } | ||
| 2634 | spin_unlock(&local->irq_init_lock); | ||
| 2635 | |||
| 2624 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0); | 2636 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0); |
| 2625 | 2637 | ||
| 2626 | if (local->func->card_present && !local->func->card_present(local)) { | 2638 | if (local->func->card_present && !local->func->card_present(local)) { |
| @@ -3138,6 +3150,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, | |||
| 3138 | spin_lock_init(&local->cmdlock); | 3150 | spin_lock_init(&local->cmdlock); |
| 3139 | spin_lock_init(&local->baplock); | 3151 | spin_lock_init(&local->baplock); |
| 3140 | spin_lock_init(&local->lock); | 3152 | spin_lock_init(&local->lock); |
| 3153 | spin_lock_init(&local->irq_init_lock); | ||
| 3141 | mutex_init(&local->rid_bap_mtx); | 3154 | mutex_init(&local->rid_bap_mtx); |
| 3142 | 3155 | ||
| 3143 | if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) | 3156 | if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) |
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index 3d238917af07..1ba33be98b25 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h | |||
| @@ -654,7 +654,7 @@ struct local_info { | |||
| 654 | rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock | 654 | rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock |
| 655 | * when removing entries from the list. | 655 | * when removing entries from the list. |
| 656 | * TX and RX paths can use read lock. */ | 656 | * TX and RX paths can use read lock. */ |
| 657 | spinlock_t cmdlock, baplock, lock; | 657 | spinlock_t cmdlock, baplock, lock, irq_init_lock; |
| 658 | struct mutex rid_bap_mtx; | 658 | struct mutex rid_bap_mtx; |
| 659 | u16 infofid; /* MAC buffer id for info frame */ | 659 | u16 infofid; /* MAC buffer id for info frame */ |
| 660 | /* txfid, intransmitfid, next_txtid, and next_alloc are protected by | 660 | /* txfid, intransmitfid, next_txtid, and next_alloc are protected by |
