lkml.org 
[lkml]   [2007]   [Sep]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[50/50] bcm43xx: Fix cancellation of work queue crashes
    From: Larry Finger <Larry.Finger@lwfinger.net>

    port of 3f7086978fc0193eff24a77d8b57ac4debc088fa from mainline.

    A crash upon booting that is caused by bcm43xx has been reported [1] and
    found to be due to a work queue being reinitialized while work on that
    queue is still pending. This fix modifies the shutdown of work queues and
    prevents periodic work from being requeued during shutdown. With this patch,
    no more crashes on reboot were observed by the original reporter. I do not
    get that particular failure on my system; however, when running a large
    number of ifdown/ifup sequences, my system would kernel panic with the
    'caps lock' light blinking at roughly a 1 Hz rate. In addition, there were
    infrequent failures in the firmware that resulted in 'IRQ READY TIMEOUT'
    errors. With this patch, no more of the first type of failure occur, and
    incidence of the second type is greatly reduced.

    [1] http://bugzilla.kernel.org/show_bug.cgi?id=8937

    Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
    Acked-by: Michael Buesch <mb@bu3sch.de>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    drivers/net/wireless/bcm43xx/bcm43xx_main.c | 28 +++++++++++++++++++--------
    drivers/net/wireless/bcm43xx/bcm43xx_main.h | 2 -
    drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 2 -
    3 files changed, 22 insertions(+), 10 deletions(-)

    --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
    +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
    @@ -3183,6 +3183,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.
    @@ -3228,14 +3231,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;
    @@ -3285,6 +3284,14 @@ static int bcm43xx_rng_init(struct bcm43
    return err;
    }

    +void bcm43xx_cancel_work(struct bcm43xx_private *bcm)
    +{
    + /* The system must be unlocked when this routine is entered.
    + * If not, the next 2 steps may deadlock */
    + cancel_work_sync(&bcm->restart_work);
    + cancel_rearming_delayed_work(&bcm->periodic_work);
    +}
    +
    static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
    {
    int ret = 0;
    @@ -3321,7 +3328,12 @@ 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);
    +
    + bcm43xx_cancel_work(bcm);

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

    return 0;
    }
    @@ -4150,9 +4162,9 @@ static void bcm43xx_chip_reset(struct wo
    struct bcm43xx_phyinfo *phy;
    int err = -ENODEV;

    + bcm43xx_cancel_work(bcm);
    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)
    --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
    +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
    @@ -122,7 +122,7 @@ 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_cancel_work(struct bcm43xx_private *bcm);
    void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);

    void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
    --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
    +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
    @@ -327,7 +327,7 @@ static ssize_t bcm43xx_attr_phymode_stor
    goto out;
    }

    - bcm43xx_periodic_tasks_delete(bcm);
    + bcm43xx_cancel_work(bcm);
    mutex_lock(&(bcm)->mutex);
    err = bcm43xx_select_wireless_core(bcm, phytype);
    if (!err)
    --
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-09-24 18:47    [W:0.025 / U:99.416 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site