aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2006-08-21 10:43:44 -0400
committerJohn W. Linville <linville@tuxdriver.com>2006-09-11 19:34:00 -0400
commit7d4b0394bbf5e306ff9d5753163a07187131bfd8 (patch)
tree24696862ca6df267b7c4d30feb240174c99d4237 /drivers/net/wireless
parent34fa0e319c760189f1fc226acc5b3b387dc58099 (diff)
[PATCH] bcm43xx-softmac: Init, shutdown and restart fixes
This fixes various bugs in the init and shutdown code that would lead to lockups and crashes. Signed-Off-By: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c39
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h3
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c3
3 files changed, 28 insertions, 17 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 966815be6955..96a5fdec8aad 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -519,6 +519,7 @@ static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm)
519 return -EBUSY; 519 return -EBUSY;
520 } 520 }
521 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); 521 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
522 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); /* flush */
522 spin_unlock_irqrestore(&bcm->irq_lock, flags); 523 spin_unlock_irqrestore(&bcm->irq_lock, flags);
523 bcm43xx_synchronize_irq(bcm); 524 bcm43xx_synchronize_irq(bcm);
524 525
@@ -3150,6 +3151,7 @@ static void bcm43xx_periodic_work_handler(void *d)
3150 /* Periodic work will take a long time, so we want it to 3151 /* Periodic work will take a long time, so we want it to
3151 * be preemtible. 3152 * be preemtible.
3152 */ 3153 */
3154 mutex_lock(&bcm->mutex);
3153 netif_stop_queue(bcm->net_dev); 3155 netif_stop_queue(bcm->net_dev);
3154 synchronize_net(); 3156 synchronize_net();
3155 spin_lock_irqsave(&bcm->irq_lock, flags); 3157 spin_lock_irqsave(&bcm->irq_lock, flags);
@@ -3158,7 +3160,6 @@ static void bcm43xx_periodic_work_handler(void *d)
3158 bcm43xx_pio_freeze_txqueues(bcm); 3160 bcm43xx_pio_freeze_txqueues(bcm);
3159 savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); 3161 savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3160 spin_unlock_irqrestore(&bcm->irq_lock, flags); 3162 spin_unlock_irqrestore(&bcm->irq_lock, flags);
3161 mutex_lock(&bcm->mutex);
3162 bcm43xx_synchronize_irq(bcm); 3163 bcm43xx_synchronize_irq(bcm);
3163 } else { 3164 } else {
3164 /* Periodic work should take short time, so we want low 3165 /* Periodic work should take short time, so we want low
@@ -3172,13 +3173,11 @@ static void bcm43xx_periodic_work_handler(void *d)
3172 3173
3173 if (badness > BADNESS_LIMIT) { 3174 if (badness > BADNESS_LIMIT) {
3174 spin_lock_irqsave(&bcm->irq_lock, flags); 3175 spin_lock_irqsave(&bcm->irq_lock, flags);
3175 if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) { 3176 tasklet_enable(&bcm->isr_tasklet);
3176 tasklet_enable(&bcm->isr_tasklet); 3177 bcm43xx_interrupt_enable(bcm, savedirqs);
3177 bcm43xx_interrupt_enable(bcm, savedirqs); 3178 if (bcm43xx_using_pio(bcm))
3178 if (bcm43xx_using_pio(bcm)) 3179 bcm43xx_pio_thaw_txqueues(bcm);
3179 bcm43xx_pio_thaw_txqueues(bcm); 3180 bcm43xx_mac_enable(bcm);
3180 bcm43xx_mac_enable(bcm);
3181 }
3182 netif_wake_queue(bcm->net_dev); 3181 netif_wake_queue(bcm->net_dev);
3183 } 3182 }
3184 mmiowb(); 3183 mmiowb();
@@ -3186,12 +3185,12 @@ static void bcm43xx_periodic_work_handler(void *d)
3186 mutex_unlock(&bcm->mutex); 3185 mutex_unlock(&bcm->mutex);
3187} 3186}
3188 3187
3189static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) 3188void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
3190{ 3189{
3191 cancel_rearming_delayed_work(&bcm->periodic_work); 3190 cancel_rearming_delayed_work(&bcm->periodic_work);
3192} 3191}
3193 3192
3194static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) 3193void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
3195{ 3194{
3196 struct work_struct *work = &(bcm->periodic_work); 3195 struct work_struct *work = &(bcm->periodic_work);
3197 3196
@@ -3539,11 +3538,10 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm)
3539 err = bcm43xx_select_wireless_core(bcm, -1); 3538 err = bcm43xx_select_wireless_core(bcm, -1);
3540 if (err) 3539 if (err)
3541 goto err_crystal_off; 3540 goto err_crystal_off;
3542
3543 bcm43xx_periodic_tasks_setup(bcm);
3544 err = bcm43xx_sysfs_register(bcm); 3541 err = bcm43xx_sysfs_register(bcm);
3545 if (err) 3542 if (err)
3546 goto err_wlshutdown; 3543 goto err_wlshutdown;
3544 bcm43xx_periodic_tasks_setup(bcm);
3547 err = bcm43xx_rng_init(bcm); 3545 err = bcm43xx_rng_init(bcm);
3548 if (err) 3546 if (err)
3549 goto err_sysfs_unreg; 3547 goto err_sysfs_unreg;
@@ -3969,6 +3967,7 @@ static int bcm43xx_net_stop(struct net_device *net_dev)
3969 err = bcm43xx_disable_interrupts_sync(bcm); 3967 err = bcm43xx_disable_interrupts_sync(bcm);
3970 assert(!err); 3968 assert(!err);
3971 bcm43xx_free_board(bcm); 3969 bcm43xx_free_board(bcm);
3970 flush_scheduled_work();
3972 3971
3973 return 0; 3972 return 0;
3974} 3973}
@@ -4119,11 +4118,16 @@ static void bcm43xx_chip_reset(void *_bcm)
4119{ 4118{
4120 struct bcm43xx_private *bcm = _bcm; 4119 struct bcm43xx_private *bcm = _bcm;
4121 struct bcm43xx_phyinfo *phy; 4120 struct bcm43xx_phyinfo *phy;
4122 int err; 4121 int err = -ENODEV;
4123 4122
4124 mutex_lock(&(bcm)->mutex); 4123 mutex_lock(&(bcm)->mutex);
4125 phy = bcm43xx_current_phy(bcm); 4124 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
4126 err = bcm43xx_select_wireless_core(bcm, phy->type); 4125 bcm43xx_periodic_tasks_delete(bcm);
4126 phy = bcm43xx_current_phy(bcm);
4127 err = bcm43xx_select_wireless_core(bcm, phy->type);
4128 if (!err)
4129 bcm43xx_periodic_tasks_setup(bcm);
4130 }
4127 mutex_unlock(&(bcm)->mutex); 4131 mutex_unlock(&(bcm)->mutex);
4128 4132
4129 printk(KERN_ERR PFX "Controller restart%s\n", 4133 printk(KERN_ERR PFX "Controller restart%s\n",
@@ -4132,11 +4136,12 @@ static void bcm43xx_chip_reset(void *_bcm)
4132 4136
4133/* Hard-reset the chip. 4137/* Hard-reset the chip.
4134 * This can be called from interrupt or process context. 4138 * This can be called from interrupt or process context.
4139 * bcm->irq_lock must be locked.
4135 */ 4140 */
4136void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) 4141void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
4137{ 4142{
4138 assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); 4143 if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
4139 bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); 4144 return;
4140 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); 4145 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
4141 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); 4146 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
4142 schedule_work(&bcm->restart_work); 4147 schedule_work(&bcm->restart_work);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index 505c86e2007a..f76357178e4d 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -141,6 +141,9 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
141void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); 141void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
142void bcm43xx_mac_enable(struct bcm43xx_private *bcm); 142void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
143 143
144void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm);
145void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);
146
144void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); 147void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
145 148
146int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom); 149int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index ece335178f6a..a16400d9ff4b 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -333,8 +333,11 @@ static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
333 goto out; 333 goto out;
334 } 334 }
335 335
336 bcm43xx_periodic_tasks_delete(bcm);
336 mutex_lock(&(bcm)->mutex); 337 mutex_lock(&(bcm)->mutex);
337 err = bcm43xx_select_wireless_core(bcm, phytype); 338 err = bcm43xx_select_wireless_core(bcm, phytype);
339 if (!err)
340 bcm43xx_periodic_tasks_setup(bcm);
338 mutex_unlock(&(bcm)->mutex); 341 mutex_unlock(&(bcm)->mutex);
339 if (err == -ESRCH) 342 if (err == -ESRCH)
340 err = -ENODEV; 343 err = -ENODEV;