diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2006-08-21 10:43:44 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2006-09-11 19:34:00 -0400 |
commit | 7d4b0394bbf5e306ff9d5753163a07187131bfd8 (patch) | |
tree | 24696862ca6df267b7c4d30feb240174c99d4237 /drivers/net/wireless | |
parent | 34fa0e319c760189f1fc226acc5b3b387dc58099 (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.c | 39 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_main.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 3 |
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 | ||
3189 | static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) | 3188 | void 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 | ||
3194 | static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) | 3193 | void 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 | */ |
4136 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) | 4141 | void 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); | |||
141 | void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); | 141 | void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); |
142 | void bcm43xx_mac_enable(struct bcm43xx_private *bcm); | 142 | void bcm43xx_mac_enable(struct bcm43xx_private *bcm); |
143 | 143 | ||
144 | void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm); | ||
145 | void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm); | ||
146 | |||
144 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); | 147 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); |
145 | 148 | ||
146 | int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom); | 149 | int 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; |