Michael Buesch wrote:
> On Friday 31 August 2007, Larry Finger wrote:
>> This patch fixes a problem with work queues during shutdown. The bug
>> seems to be responsible for the boot-time crashes reported in
>> http://bugzilla.kernel.org/show_bug.cgi?id=8937.
>>
>> Signed-off-by: Larry Finger <[EMAIL PROTECTED]>
>> ---
>>
>> Index: linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_main.c
>> ===================================================================
>> --- linux-2.6.orig/drivers/net/wireless/bcm43xx/bcm43xx_main.c
>> +++ linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_main.c
>> @@ -3174,6 +3174,9 @@ static void bcm43xx_periodic_every1sec(s
>>  
>>  static void do_periodic_work(struct bcm43xx_private *bcm)
>>  {
>> +    /* keep from rearming periodic work if shutting down */
>> +    if (bcm43xx_status(bcm) == BCM43xx_STAT_UNINIT)
>> +            return;
> 
> I think this should be put at the beginning of bcm43xx_periodic_work_handler()
> after the mutex locking.
> 
>>      if (bcm->periodic_state % 120 == 0)
>>              bcm43xx_periodic_every120sec(bcm);
>>      if (bcm->periodic_state % 60 == 0)
>> @@ -3245,11 +3248,6 @@ static void bcm43xx_periodic_work_handle
>>      mutex_unlock(&bcm->mutex);
>>  }
>>  
>> -void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
>> -{
>> -    cancel_rearming_delayed_work(&bcm->periodic_work);
>> -}
>> -
>>  void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
>>  {
>>      struct delayed_work *work = &bcm->periodic_work;
>> @@ -3335,9 +3333,14 @@ static void bcm43xx_free_board(struct bc
>>  {
>>      bcm43xx_rng_exit(bcm);
>>      bcm43xx_sysfs_unregister(bcm);
>> -    bcm43xx_periodic_tasks_delete(bcm);
>> +
>> +    /* next 2 steps must be unlocked, else they may deadlock */
>> +    cancel_work_sync(&bcm->restart_work);
>> +    cancel_delayed_work_sync(&bcm->periodic_work);
> 
> 
> 
>>      mutex_lock(&(bcm)->mutex);
>> +    bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
>> +
> 
> This status change must be moved above the cancel calls.
> 
>>      bcm43xx_shutdown_all_wireless_cores(bcm);
>>      bcm43xx_pctl_set_crystal(bcm, 0);
>>      mutex_unlock(&(bcm)->mutex);
>> @@ -4030,7 +4033,6 @@ static int bcm43xx_net_stop(struct net_d
>>      err = bcm43xx_disable_interrupts_sync(bcm);
>>      assert(!err);
>>      bcm43xx_free_board(bcm);
>> -    flush_scheduled_work();
>>  
>>      return 0;
>>  }
>> @@ -4164,7 +4166,6 @@ static void bcm43xx_chip_reset(struct wo
>>  
>>      mutex_lock(&(bcm)->mutex);
>>      if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
>> -            bcm43xx_periodic_tasks_delete(bcm);
> 
> Look at the comment below. That also applies here.
> 
>>              phy = bcm43xx_current_phy(bcm);
>>              err = bcm43xx_select_wireless_core(bcm, phy->type);
>>              if (!err)
>> Index: linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_main.h
>> ===================================================================
>> --- linux-2.6.orig/drivers/net/wireless/bcm43xx/bcm43xx_main.h
>> +++ linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_main.h
>> @@ -122,7 +122,6 @@ void bcm43xx_wireless_core_reset(struct 
>>  void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
>>  void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
>>  
>> -void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm);
>>  void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);
>>  
>>  void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char 
>> *reason);
>> Index: linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
>> ===================================================================
>> --- linux-2.6.orig/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
>> +++ linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
>> @@ -327,7 +327,6 @@ static ssize_t bcm43xx_attr_phymode_stor
>>              goto out;
>>      }
>>  
>> -    bcm43xx_periodic_tasks_delete(bcm);
> 
> Well, this is tricky crap code.
> This breaks it.
> Look at the !err case below. We re-enable pwork there.
> We only do it for !err. So when core select failed, we
> end up without pwork, which is what we want.
> I think it might be OK to simply remove the delete _and_
> the setup below, as select core sets status to UNINIT when
> it failed. So pwork will bail out early (if you change your
> patch above as I suggested).
> 
>>      mutex_lock(&(bcm)->mutex);
>>      err = bcm43xx_select_wireless_core(bcm, phytype);
>>      if (!err)
>>
>>
> 
> 
> PS: Yes, this is crap code. :) All these cornercases.
> 

I think I understood your comments. The revised patch is as follows:

Larry

------

Index: linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_main.c
===================================================================
--- linux-2.6.orig/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -3197,6 +3197,9 @@ static void bcm43xx_periodic_work_handle
        unsigned long orig_trans_start = 0;

        mutex_lock(&bcm->mutex);
+       /* keep from doing and rearming periodic work if shutting down */
+       if (bcm43xx_status(bcm) == BCM43xx_STAT_UNINIT)
+               goto unlock_mutex;
        if (unlikely(bcm->periodic_state % 60 == 0)) {
                /* Periodic work will take a long time, so we want it to
                 * be preemtible.
@@ -3242,14 +3245,10 @@ static void bcm43xx_periodic_work_handle
        mmiowb();
        bcm->periodic_state++;
        spin_unlock_irqrestore(&bcm->irq_lock, flags);
+unlock_mutex:
        mutex_unlock(&bcm->mutex);
  }

-void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
-{
-       cancel_rearming_delayed_work(&bcm->periodic_work);
-}
-
  void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
  {
        struct delayed_work *work = &bcm->periodic_work;
@@ -3335,7 +3334,15 @@ static void bcm43xx_free_board(struct bc
  {
        bcm43xx_rng_exit(bcm);
        bcm43xx_sysfs_unregister(bcm);
-       bcm43xx_periodic_tasks_delete(bcm);
+
+       mutex_lock(&(bcm)->mutex);
+       bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+       mutex_unlock(&(bcm)->mutex);
+
+       /* next 2 steps must be unlocked, else they may deadlock */
+       cancel_work_sync(&bcm->restart_work);
+       cancel_delayed_work_sync(&bcm->periodic_work);
+

        mutex_lock(&(bcm)->mutex);
        bcm43xx_shutdown_all_wireless_cores(bcm);
@@ -4030,7 +4037,6 @@ static int bcm43xx_net_stop(struct net_d
        err = bcm43xx_disable_interrupts_sync(bcm);
        assert(!err);
        bcm43xx_free_board(bcm);
-       flush_scheduled_work();

        return 0;
  }
@@ -4164,11 +4170,8 @@ static void bcm43xx_chip_reset(struct wo

        mutex_lock(&(bcm)->mutex);
        if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
-               bcm43xx_periodic_tasks_delete(bcm);
                phy = bcm43xx_current_phy(bcm);
                err = bcm43xx_select_wireless_core(bcm, phy->type);
-               if (!err)
-                       bcm43xx_periodic_tasks_setup(bcm);
        }
        mutex_unlock(&(bcm)->mutex);

Index: linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_main.h
===================================================================
--- linux-2.6.orig/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -122,7 +122,6 @@ void bcm43xx_wireless_core_reset(struct
  void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
  void bcm43xx_mac_enable(struct bcm43xx_private *bcm);

-void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm);
  void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);

  void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char 
*reason);
Index: linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
===================================================================
--- linux-2.6.orig/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -327,11 +327,8 @@ static ssize_t bcm43xx_attr_phymode_stor
                goto out;
        }
  -     bcm43xx_periodic_tasks_delete(bcm);
        mutex_lock(&(bcm)->mutex);
        err = bcm43xx_select_wireless_core(bcm, phytype);
-       if (!err)
-               bcm43xx_periodic_tasks_setup(bcm);
        mutex_unlock(&(bcm)->mutex);
        if (err == -ESRCH)
                err = -ENODEV;


_______________________________________________
Bcm43xx-dev mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/bcm43xx-dev

Reply via email to