Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Thu, 5 Jan 2012 15:12:45 +0000 (10:12 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 5 Jan 2012 15:13:24 +0000 (10:13 -0500)
Conflicts:
drivers/net/wireless/b43legacy/dma.c

1  2 
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43legacy/dma.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/rt2x00/rt2800usb.c
net/mac80211/scan.c

@@@ -105,16 -105,19 +105,19 @@@ static int ath_max_4ms_framelen[4][32] 
  /*********************/
  
  static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
+       __acquires(&txq->axq_lock)
  {
        spin_lock_bh(&txq->axq_lock);
  }
  
  static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
+       __releases(&txq->axq_lock)
  {
        spin_unlock_bh(&txq->axq_lock);
  }
  
  static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
+       __releases(&txq->axq_lock)
  {
        struct sk_buff_head q;
        struct sk_buff *skb;
@@@ -1961,7 -1964,7 +1964,7 @@@ int ath_tx_start(struct ieee80211_hw *h
        if (txq == sc->tx.txq_map[q] &&
            ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
                ieee80211_stop_queue(sc->hw, q);
 -              txq->stopped = 1;
 +              txq->stopped = true;
        }
  
        ath_tx_start_dma(sc, skb, txctl);
@@@ -2017,7 -2020,7 +2020,7 @@@ static void ath_tx_complete(struct ath_
  
                if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
                        ieee80211_wake_queue(sc->hw, q);
 -                      txq->stopped = 0;
 +                      txq->stopped = false;
                }
        }
  
@@@ -167,7 -167,7 +167,7 @@@ static void b43_nphy_rf_control_overrid
                                b43_phy_mask(dev, val_addr,
                                                ~(rf_ctrl->val_mask));
                        } else {
-                               if (core == 0 || ((1 << core) & i) != 0) {
+                               if (core == 0 || ((1 << i) & core)) {
                                        b43_phy_set(dev, en_addr, field);
                                        b43_phy_maskset(dev, val_addr,
                                                ~(rf_ctrl->val_mask),
                        addr = B43_PHY_N((i == 0) ?
                                rf_ctrl->addr0 : rf_ctrl->addr1);
  
-                       if ((core & (1 << i)) != 0)
+                       if ((1 << i) & core)
                                b43_phy_maskset(dev, addr, ~(rf_ctrl->bmask),
                                                (value << rf_ctrl->shift));
  
@@@ -956,7 -956,7 +956,7 @@@ static void b43_nphy_run_samples(struc
                        b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1);
        }
        for (i = 0; i < 100; i++) {
-               if (b43_phy_read(dev, B43_NPHY_RFSEQST) & 1) {
+               if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & 1)) {
                        i = 0;
                        break;
                }
@@@ -1511,7 -1511,8 +1511,8 @@@ static void b43_nphy_gain_ctl_workaroun
        /* Prepare values */
        ghz5 = b43_phy_read(dev, B43_NPHY_BANDCTL)
                & B43_NPHY_BANDCTL_5GHZ;
-       ext_lna = sprom->boardflags_lo & B43_BFL_EXTLNA;
+       ext_lna = ghz5 ? sprom->boardflags_hi & B43_BFH_EXTLNA_5GHZ :
+               sprom->boardflags_lo & B43_BFL_EXTLNA;
        e = b43_nphy_get_gain_ctl_workaround_ent(dev, ghz5, ext_lna);
        if (ghz5 && dev->phy.rev >= 5)
                rssi_gain = 0x90;
        b43_phy_write(dev, 0x2A7, e->init_gain);
        b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x106), 2,
                                e->rfseq_init);
-       b43_phy_write(dev, B43_NPHY_C1_INITGAIN, e->init_gain);
  
        /* TODO: check defines. Do not match variables names */
        b43_phy_write(dev, B43_NPHY_C1_CLIP1_MEDGAIN, e->cliphi_gain);
@@@ -1928,6 -1928,117 +1928,117 @@@ static void b43_nphy_workarounds(struc
                b43_nphy_stay_in_carrier_search(dev, 0);
  }
  
+ /**************************************************
+  * Tx/Rx common
+  **************************************************/
+ /*
+  * Transmits a known value for LO calibration
+  * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
+  */
+ static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val,
+                               bool iqmode, bool dac_test)
+ {
+       u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
+       if (samp == 0)
+               return -1;
+       b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test);
+       return 0;
+ }
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */
+ static void b43_nphy_update_txrx_chain(struct b43_wldev *dev)
+ {
+       struct b43_phy_n *nphy = dev->phy.n;
+       bool override = false;
+       u16 chain = 0x33;
+       if (nphy->txrx_chain == 0) {
+               chain = 0x11;
+               override = true;
+       } else if (nphy->txrx_chain == 1) {
+               chain = 0x22;
+               override = true;
+       }
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
+                       ~(B43_NPHY_RFSEQCA_TXEN | B43_NPHY_RFSEQCA_RXEN),
+                       chain);
+       if (override)
+               b43_phy_set(dev, B43_NPHY_RFSEQMODE,
+                               B43_NPHY_RFSEQMODE_CAOVER);
+       else
+               b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+                               ~B43_NPHY_RFSEQMODE_CAOVER);
+ }
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */
+ static void b43_nphy_stop_playback(struct b43_wldev *dev)
+ {
+       struct b43_phy_n *nphy = dev->phy.n;
+       u16 tmp;
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 1);
+       tmp = b43_phy_read(dev, B43_NPHY_SAMP_STAT);
+       if (tmp & 0x1)
+               b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP);
+       else if (tmp & 0x2)
+               b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
+       b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004);
+       if (nphy->bb_mult_save & 0x80000000) {
+               tmp = nphy->bb_mult_save & 0xFFFF;
+               b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
+               nphy->bb_mult_save = 0;
+       }
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
+ }
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */
+ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
+                                       struct nphy_txgains target,
+                                       struct nphy_iqcal_params *params)
+ {
+       int i, j, indx;
+       u16 gain;
+       if (dev->phy.rev >= 3) {
+               params->txgm = target.txgm[core];
+               params->pga = target.pga[core];
+               params->pad = target.pad[core];
+               params->ipa = target.ipa[core];
+               params->cal_gain = (params->txgm << 12) | (params->pga << 8) |
+                                       (params->pad << 4) | (params->ipa);
+               for (j = 0; j < 5; j++)
+                       params->ncorr[j] = 0x79;
+       } else {
+               gain = (target.pad[core]) | (target.pga[core] << 4) |
+                       (target.txgm[core] << 8);
+               indx = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ?
+                       1 : 0;
+               for (i = 0; i < 9; i++)
+                       if (tbl_iqcal_gainparams[indx][i][0] == gain)
+                               break;
+               i = min(i, 8);
+               params->txgm = tbl_iqcal_gainparams[indx][i][1];
+               params->pga = tbl_iqcal_gainparams[indx][i][2];
+               params->pad = tbl_iqcal_gainparams[indx][i][3];
+               params->cal_gain = (params->txgm << 7) | (params->pga << 4) |
+                                       (params->pad << 2);
+               for (j = 0; j < 4; j++)
+                       params->ncorr[j] = tbl_iqcal_gainparams[indx][i][4 + j];
+       }
+ }
  /**************************************************
   * Tx and Rx
   **************************************************/
@@@ -2107,7 -2218,7 +2218,7 @@@ static void b43_nphy_tx_power_fix(struc
                }
        }
        if (dev->phy.rev < 7 &&
-           (txpi[0] < 40 || txpi[0] > 100 || txpi[1] < 40 || txpi[1] > 10))
+           (txpi[0] < 40 || txpi[0] > 100 || txpi[1] < 40 || txpi[1] > 100))
                txpi[0] = txpi[1] = 91;
  
        /*
                b43_nphy_stay_in_carrier_search(dev, 0);
  }
  
+ static void b43_nphy_ipa_internal_tssi_setup(struct b43_wldev *dev)
+ {
+       struct b43_phy *phy = &dev->phy;
+       u8 core;
+       u16 r; /* routing */
+       if (phy->rev >= 7) {
+               for (core = 0; core < 2; core++) {
+                       r = core ? 0x190 : 0x170;
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+                               b43_radio_write(dev, r + 0x5, 0x5);
+                               b43_radio_write(dev, r + 0x9, 0xE);
+                               if (phy->rev != 5)
+                                       b43_radio_write(dev, r + 0xA, 0);
+                               if (phy->rev != 7)
+                                       b43_radio_write(dev, r + 0xB, 1);
+                               else
+                                       b43_radio_write(dev, r + 0xB, 0x31);
+                       } else {
+                               b43_radio_write(dev, r + 0x5, 0x9);
+                               b43_radio_write(dev, r + 0x9, 0xC);
+                               b43_radio_write(dev, r + 0xB, 0x0);
+                               if (phy->rev != 5)
+                                       b43_radio_write(dev, r + 0xA, 1);
+                               else
+                                       b43_radio_write(dev, r + 0xA, 0x31);
+                       }
+                       b43_radio_write(dev, r + 0x6, 0);
+                       b43_radio_write(dev, r + 0x7, 0);
+                       b43_radio_write(dev, r + 0x8, 3);
+                       b43_radio_write(dev, r + 0xC, 0);
+               }
+       } else {
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+                       b43_radio_write(dev, B2056_SYN_RESERVED_ADDR31, 0x128);
+               else
+                       b43_radio_write(dev, B2056_SYN_RESERVED_ADDR31, 0x80);
+               b43_radio_write(dev, B2056_SYN_RESERVED_ADDR30, 0);
+               b43_radio_write(dev, B2056_SYN_GPIO_MASTER1, 0x29);
+               for (core = 0; core < 2; core++) {
+                       r = core ? B2056_TX1 : B2056_TX0;
+                       b43_radio_write(dev, r | B2056_TX_IQCAL_VCM_HG, 0);
+                       b43_radio_write(dev, r | B2056_TX_IQCAL_IDAC, 0);
+                       b43_radio_write(dev, r | B2056_TX_TSSI_VCM, 3);
+                       b43_radio_write(dev, r | B2056_TX_TX_AMP_DET, 0);
+                       b43_radio_write(dev, r | B2056_TX_TSSI_MISC1, 8);
+                       b43_radio_write(dev, r | B2056_TX_TSSI_MISC2, 0);
+                       b43_radio_write(dev, r | B2056_TX_TSSI_MISC3, 0);
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+                               b43_radio_write(dev, r | B2056_TX_TX_SSI_MASTER,
+                                               0x5);
+                               if (phy->rev != 5)
+                                       b43_radio_write(dev, r | B2056_TX_TSSIA,
+                                                       0x00);
+                               if (phy->rev >= 5)
+                                       b43_radio_write(dev, r | B2056_TX_TSSIG,
+                                                       0x31);
+                               else
+                                       b43_radio_write(dev, r | B2056_TX_TSSIG,
+                                                       0x11);
+                               b43_radio_write(dev, r | B2056_TX_TX_SSI_MUX,
+                                               0xE);
+                       } else {
+                               b43_radio_write(dev, r | B2056_TX_TX_SSI_MASTER,
+                                               0x9);
+                               b43_radio_write(dev, r | B2056_TX_TSSIA, 0x31);
+                               b43_radio_write(dev, r | B2056_TX_TSSIG, 0x0);
+                               b43_radio_write(dev, r | B2056_TX_TX_SSI_MUX,
+                                               0xC);
+                       }
+               }
+       }
+ }
+ /*
+  * Stop radio and transmit known signal. Then check received signal strength to
+  * get TSSI (Transmit Signal Strength Indicator).
+  * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlIdleTssi
+  */
+ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
+ {
+       struct b43_phy *phy = &dev->phy;
+       struct b43_phy_n *nphy = dev->phy.n;
+       u32 tmp;
+       s32 rssi[4] = { };
+       /* TODO: check if we can transmit */
+       if (b43_nphy_ipa(dev))
+               b43_nphy_ipa_internal_tssi_setup(dev);
+       if (phy->rev >= 7)
+               ; /* TODO: Override Rev7 with 0x2000, 0, 3, 0, 0 as arguments */
+       else if (phy->rev >= 3)
+               b43_nphy_rf_control_override(dev, 0x2000, 0, 3, false);
+       b43_nphy_stop_playback(dev);
+       b43_nphy_tx_tone(dev, 0xFA0, 0, false, false);
+       udelay(20);
+       tmp = b43_nphy_poll_rssi(dev, 4, rssi, 1);
+       b43_nphy_stop_playback(dev);
+       b43_nphy_rssi_select(dev, 0, 0);
+       if (phy->rev >= 7)
+               ; /* TODO: Override Rev7 with 0x2000, 0, 3, 1, 0 as arguments */
+       else if (phy->rev >= 3)
+               b43_nphy_rf_control_override(dev, 0x2000, 0, 3, true);
+       if (phy->rev >= 3) {
+               nphy->pwr_ctl_info[0].idle_tssi_5g = (tmp >> 24) & 0xFF;
+               nphy->pwr_ctl_info[1].idle_tssi_5g = (tmp >> 8) & 0xFF;
+       } else {
+               nphy->pwr_ctl_info[0].idle_tssi_5g = (tmp >> 16) & 0xFF;
+               nphy->pwr_ctl_info[1].idle_tssi_5g = tmp & 0xFF;
+       }
+       nphy->pwr_ctl_info[0].idle_tssi_2g = (tmp >> 24) & 0xFF;
+       nphy->pwr_ctl_info[1].idle_tssi_2g = (tmp >> 8) & 0xFF;
+ }
  static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
  {
        struct b43_phy *phy = &dev->phy;
@@@ -2290,34 -2524,6 +2524,6 @@@ static void b43_nphy_tx_lp_fbw(struct b
        }
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */
- static void b43_nphy_update_txrx_chain(struct b43_wldev *dev)
- {
-       struct b43_phy_n *nphy = dev->phy.n;
-       bool override = false;
-       u16 chain = 0x33;
-       if (nphy->txrx_chain == 0) {
-               chain = 0x11;
-               override = true;
-       } else if (nphy->txrx_chain == 1) {
-               chain = 0x22;
-               override = true;
-       }
-       b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
-                       ~(B43_NPHY_RFSEQCA_TXEN | B43_NPHY_RFSEQCA_RXEN),
-                       chain);
-       if (override)
-               b43_phy_set(dev, B43_NPHY_RFSEQMODE,
-                               B43_NPHY_RFSEQMODE_CAOVER);
-       else
-               b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
-                               ~B43_NPHY_RFSEQMODE_CAOVER);
- }
  /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */
  static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est,
                                u16 samps, u8 time, bool wait)
@@@ -2569,33 -2775,6 +2775,6 @@@ static void b43_nphy_tx_iq_workaround(s
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW3, array[3]);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */
- static void b43_nphy_stop_playback(struct b43_wldev *dev)
- {
-       struct b43_phy_n *nphy = dev->phy.n;
-       u16 tmp;
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 1);
-       tmp = b43_phy_read(dev, B43_NPHY_SAMP_STAT);
-       if (tmp & 0x1)
-               b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP);
-       else if (tmp & 0x2)
-               b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
-       b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004);
-       if (nphy->bb_mult_save & 0x80000000) {
-               tmp = nphy->bb_mult_save & 0xFFFF;
-               b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
-               nphy->bb_mult_save = 0;
-       }
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 0);
- }
  /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */
  static void b43_nphy_spur_workaround(struct b43_wldev *dev)
  {
                b43_nphy_stay_in_carrier_search(dev, 0);
  }
  
- /*
-  * Transmits a known value for LO calibration
-  * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
-  */
- static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val,
-                               bool iqmode, bool dac_test)
- {
-       u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
-       if (samp == 0)
-               return -1;
-       b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test);
-       return 0;
- }
  /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */
  static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev)
  {
@@@ -2872,44 -3037,6 +3037,6 @@@ static void b43_nphy_tx_cal_radio_setup
        }
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */
- static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
-                                       struct nphy_txgains target,
-                                       struct nphy_iqcal_params *params)
- {
-       int i, j, indx;
-       u16 gain;
-       if (dev->phy.rev >= 3) {
-               params->txgm = target.txgm[core];
-               params->pga = target.pga[core];
-               params->pad = target.pad[core];
-               params->ipa = target.ipa[core];
-               params->cal_gain = (params->txgm << 12) | (params->pga << 8) |
-                                       (params->pad << 4) | (params->ipa);
-               for (j = 0; j < 5; j++)
-                       params->ncorr[j] = 0x79;
-       } else {
-               gain = (target.pad[core]) | (target.pga[core] << 4) |
-                       (target.txgm[core] << 8);
-               indx = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ?
-                       1 : 0;
-               for (i = 0; i < 9; i++)
-                       if (tbl_iqcal_gainparams[indx][i][0] == gain)
-                               break;
-               i = min(i, 8);
-               params->txgm = tbl_iqcal_gainparams[indx][i][1];
-               params->pga = tbl_iqcal_gainparams[indx][i][2];
-               params->pad = tbl_iqcal_gainparams[indx][i][3];
-               params->cal_gain = (params->txgm << 7) | (params->pga << 4) |
-                                       (params->pad << 2);
-               for (j = 0; j < 4; j++)
-                       params->ncorr[j] = tbl_iqcal_gainparams[indx][i][4 + j];
-       }
- }
  /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */
  static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core)
  {
@@@ -3289,7 -3416,7 +3416,7 @@@ static int b43_nphy_cal_tx_iq_lo(struc
  
        if (dev->phy.rev >= 4) {
                avoid = nphy->hang_avoid;
 -              nphy->hang_avoid = 0;
 +              nphy->hang_avoid = false;
        }
  
        b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, save);
  
                        if (phy6or5x && updated[core] == 0) {
                                b43_nphy_update_tx_cal_ladder(dev, core);
 -                              updated[core] = 1;
 +                              updated[core] = true;
                        }
  
                        tmp = (params[core].ncorr[type] << 8) | 0x66;
@@@ -3982,7 -4109,7 +4109,7 @@@ int b43_phy_initn(struct b43_wldev *dev
        tx_pwr_state = nphy->txpwrctrl;
        b43_nphy_tx_power_ctrl(dev, false);
        b43_nphy_tx_power_fix(dev);
-       /* TODO N PHY TX Power Control Idle TSSI */
+       b43_nphy_tx_power_ctl_idle_tssi(dev);
        /* TODO N PHY TX Power Control Setup */
        b43_nphy_tx_gain_table_upload(dev);
  
@@@ -715,7 -715,7 +715,7 @@@ struct b43legacy_dmaring *b43legacy_set
        ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index);
        ring->index = controller_index;
        if (for_tx) {
 -              ring->tx = 1;
 +              ring->tx = true;
                ring->current_slot = -1;
        } else {
                if (ring->index == 0) {
                } else
                        B43legacy_WARN_ON(1);
        }
-       spin_lock_init(&ring->lock);
  #ifdef CONFIG_B43LEGACY_DEBUG
        ring->last_injected_overflow = jiffies;
  #endif
@@@ -806,7 -805,7 +805,7 @@@ void b43legacy_dma_free(struct b43legac
  static int b43legacy_dma_set_mask(struct b43legacy_wldev *dev, u64 mask)
  {
        u64 orig_mask = mask;
 -      bool fallback = 0;
 +      bool fallback = false;
        int err;
  
        /* Try to set the DMA mask. If it fails, try falling back to a
                }
                if (mask == DMA_BIT_MASK(64)) {
                        mask = DMA_BIT_MASK(32);
 -                      fallback = 1;
 +                      fallback = true;
                        continue;
                }
                if (mask == DMA_BIT_MASK(32)) {
                        mask = DMA_BIT_MASK(30);
 -                      fallback = 1;
 +                      fallback = true;
                        continue;
                }
                b43legacyerr(dev->wl, "The machine/kernel does not support "
@@@ -858,7 -857,7 +857,7 @@@ int b43legacy_dma_init(struct b43legacy
  #ifdef CONFIG_B43LEGACY_PIO
                b43legacywarn(dev->wl, "DMA for this device not supported. "
                        "Falling back to PIO\n");
 -              dev->__using_pio = 1;
 +              dev->__using_pio = true;
                return -EAGAIN;
  #else
                b43legacyerr(dev->wl, "DMA for this device not supported and "
@@@ -1068,7 -1067,7 +1067,7 @@@ static int dma_tx_fragment(struct b43le
        memset(meta, 0, sizeof(*meta));
  
        meta->skb = skb;
 -      meta->is_last_fragment = 1;
 +      meta->is_last_fragment = true;
  
        meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
        /* create a bounce buffer in zone_dma on mapping failure. */
@@@ -1144,10 -1143,8 +1143,8 @@@ int b43legacy_dma_tx(struct b43legacy_w
  {
        struct b43legacy_dmaring *ring;
        int err = 0;
-       unsigned long flags;
  
        ring = priority_to_txring(dev, skb_get_queue_mapping(skb));
-       spin_lock_irqsave(&ring->lock, flags);
        B43legacy_WARN_ON(!ring->tx);
  
        if (unlikely(ring->stopped)) {
                 * For now, just refuse the transmit. */
                if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
                        b43legacyerr(dev->wl, "Packet after queue stopped\n");
-               err = -ENOSPC;
-               goto out_unlock;
+               return -ENOSPC;
        }
  
        if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) {
                /* If we get here, we have a real error with the queue
                 * full, but queues not stopped. */
                b43legacyerr(dev->wl, "DMA queue overflow\n");
-               err = -ENOSPC;
-               goto out_unlock;
+               return -ENOSPC;
        }
  
        /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing
                /* Drop this packet, as we don't have the encryption key
                 * anymore and must not transmit it unencrypted. */
                dev_kfree_skb_any(skb);
-               err = 0;
-               goto out_unlock;
+               return 0;
        }
        if (unlikely(err)) {
                b43legacyerr(dev->wl, "DMA tx mapping failure\n");
-               goto out_unlock;
+               return err;
        }
        if ((free_slots(ring) < SLOTS_PER_PACKET) ||
            should_inject_overflow(ring)) {
                /* This TX ring is full. */
-               ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
+               unsigned int skb_mapping = skb_get_queue_mapping(skb);
+               ieee80211_stop_queue(dev->wl->hw, skb_mapping);
+               dev->wl->tx_queue_stopped[skb_mapping] = 1;
 -              ring->stopped = 1;
 +              ring->stopped = true;
                if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
                        b43legacydbg(dev->wl, "Stopped TX ring %d\n",
                               ring->index);
        }
- out_unlock:
-       spin_unlock_irqrestore(&ring->lock, flags);
        return err;
  }
  
@@@ -1205,14 -1198,29 +1198,29 @@@ void b43legacy_dma_handle_txstatus(stru
        struct b43legacy_dmadesc_meta *meta;
        int retry_limit;
        int slot;
+       int firstused;
  
        ring = parse_cookie(dev, status->cookie, &slot);
        if (unlikely(!ring))
                return;
-       B43legacy_WARN_ON(!irqs_disabled());
-       spin_lock(&ring->lock);
        B43legacy_WARN_ON(!ring->tx);
+       /* Sanity check: TX packets are processed in-order on one ring.
+        * Check if the slot deduced from the cookie really is the first
+        * used slot. */
+       firstused = ring->current_slot - ring->used_slots + 1;
+       if (firstused < 0)
+               firstused = ring->nr_slots + firstused;
+       if (unlikely(slot != firstused)) {
+               /* This possibly is a firmware bug and will result in
+                * malfunction, memory leaks and/or stall of DMA functionality.
+                */
+               b43legacydbg(dev->wl, "Out of order TX status report on DMA "
+                            "ring %d. Expected %d, but got %d\n",
+                            ring->index, firstused, slot);
+               return;
+       }
        while (1) {
                B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
                op32_idx2desc(ring, slot, &meta);
        dev->stats.last_tx = jiffies;
        if (ring->stopped) {
                B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
-               ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
 -              ring->stopped = 0;
 +              ring->stopped = false;
+       }
+       if (dev->wl->tx_queue_stopped[ring->queue_prio]) {
+               dev->wl->tx_queue_stopped[ring->queue_prio] = 0;
+       } else {
+               /* If the driver queue is running wake the corresponding
+                * mac80211 queue. */
+               ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
                if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
                        b43legacydbg(dev->wl, "Woke up TX ring %d\n",
-                              ring->index);
+                                    ring->index);
        }
-       spin_unlock(&ring->lock);
+       /* Add work to the queue. */
+       ieee80211_queue_work(dev->wl->hw, &dev->wl->tx_work);
  }
  
  static void dma_rx(struct b43legacy_dmaring *ring,
@@@ -1415,22 -1430,14 +1430,14 @@@ void b43legacy_dma_rx(struct b43legacy_
  
  static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring)
  {
-       unsigned long flags;
-       spin_lock_irqsave(&ring->lock, flags);
        B43legacy_WARN_ON(!ring->tx);
        op32_tx_suspend(ring);
-       spin_unlock_irqrestore(&ring->lock, flags);
  }
  
  static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring)
  {
-       unsigned long flags;
-       spin_lock_irqsave(&ring->lock, flags);
        B43legacy_WARN_ON(!ring->tx);
        op32_tx_resume(ring);
-       spin_unlock_irqrestore(&ring->lock, flags);
  }
  
  void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev)
@@@ -722,9 -722,9 +722,9 @@@ void b43legacy_wireless_core_reset(stru
        macctl &= ~B43legacy_MACCTL_GMODE;
        if (flags & B43legacy_TMSLOW_GMODE) {
                macctl |= B43legacy_MACCTL_GMODE;
 -              dev->phy.gmode = 1;
 +              dev->phy.gmode = true;
        } else
 -              dev->phy.gmode = 0;
 +              dev->phy.gmode = false;
        macctl |= B43legacy_MACCTL_IHR_ENABLED;
        b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
  }
@@@ -811,7 -811,7 +811,7 @@@ static void b43legacy_calculate_link_qu
        if (dev->noisecalc.calculation_running)
                return;
        dev->noisecalc.channel_at_start = dev->phy.channel;
 -      dev->noisecalc.calculation_running = 1;
 +      dev->noisecalc.calculation_running = true;
        dev->noisecalc.nr_samples = 0;
  
        b43legacy_generate_noise_sample(dev);
@@@ -873,7 -873,7 +873,7 @@@ static void handle_irq_noise(struct b43
  
                dev->stats.link_noise = average;
  drop_calculation:
 -              dev->noisecalc.calculation_running = 0;
 +              dev->noisecalc.calculation_running = false;
                return;
        }
  generate_new:
@@@ -889,7 -889,7 +889,7 @@@ static void handle_irq_tbtt_indication(
                        b43legacy_power_saving_ctl_bits(dev, -1, -1);
        }
        if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
 -              dev->dfq_valid = 1;
 +              dev->dfq_valid = true;
  }
  
  static void handle_irq_atim_end(struct b43legacy_wldev *dev)
                b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
                                  b43legacy_read32(dev, B43legacy_MMIO_MACCMD)
                                  | B43legacy_MACCMD_DFQ_VALID);
 -              dev->dfq_valid = 0;
 +              dev->dfq_valid = false;
        }
  }
  
@@@ -971,7 -971,7 +971,7 @@@ static void b43legacy_write_beacon_temp
        unsigned int i, len, variable_len;
        const struct ieee80211_mgmt *bcn;
        const u8 *ie;
 -      bool tim_found = 0;
 +      bool tim_found = false;
        unsigned int rate;
        u16 ctl;
        int antenna;
                        /* A valid TIM is at least 4 bytes long. */
                        if (ie_len < 4)
                                break;
 -                      tim_found = 1;
 +                      tim_found = true;
  
                        tim_position = sizeof(struct b43legacy_plcp_hdr6);
                        tim_position += offsetof(struct ieee80211_mgmt,
@@@ -1172,7 -1172,7 +1172,7 @@@ static void b43legacy_upload_beacon0(st
         *        but we don't use that feature anyway. */
        b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
                                      &__b43legacy_ratetable[3]);
 -      wl->beacon0_uploaded = 1;
 +      wl->beacon0_uploaded = true;
  }
  
  static void b43legacy_upload_beacon1(struct b43legacy_wldev *dev)
        if (wl->beacon1_uploaded)
                return;
        b43legacy_write_beacon_template(dev, 0x468, 0x1A);
 -      wl->beacon1_uploaded = 1;
 +      wl->beacon1_uploaded = true;
  }
  
  static void handle_irq_beacon(struct b43legacy_wldev *dev)
        if (unlikely(wl->beacon_templates_virgin)) {
                /* We never uploaded a beacon before.
                 * Upload both templates now, but only mark one valid. */
 -              wl->beacon_templates_virgin = 0;
 +              wl->beacon_templates_virgin = false;
                b43legacy_upload_beacon0(dev);
                b43legacy_upload_beacon1(dev);
                cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
@@@ -1275,8 -1275,8 +1275,8 @@@ static void b43legacy_update_templates(
        if (wl->current_beacon)
                dev_kfree_skb_any(wl->current_beacon);
        wl->current_beacon = beacon;
 -      wl->beacon0_uploaded = 0;
 -      wl->beacon1_uploaded = 0;
 +      wl->beacon0_uploaded = false;
 +      wl->beacon1_uploaded = false;
        ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
  }
  
@@@ -2440,30 -2440,64 +2440,64 @@@ static int b43legacy_rng_init(struct b4
        return err;
  }
  
+ static void b43legacy_tx_work(struct work_struct *work)
+ {
+       struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl,
+                                 tx_work);
+       struct b43legacy_wldev *dev;
+       struct sk_buff *skb;
+       int queue_num;
+       int err = 0;
+       mutex_lock(&wl->mutex);
+       dev = wl->current_dev;
+       if (unlikely(!dev || b43legacy_status(dev) < B43legacy_STAT_STARTED)) {
+               mutex_unlock(&wl->mutex);
+               return;
+       }
+       for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) {
+               while (skb_queue_len(&wl->tx_queue[queue_num])) {
+                       skb = skb_dequeue(&wl->tx_queue[queue_num]);
+                       if (b43legacy_using_pio(dev))
+                               err = b43legacy_pio_tx(dev, skb);
+                       else
+                               err = b43legacy_dma_tx(dev, skb);
+                       if (err == -ENOSPC) {
+                               wl->tx_queue_stopped[queue_num] = 1;
+                               ieee80211_stop_queue(wl->hw, queue_num);
+                               skb_queue_head(&wl->tx_queue[queue_num], skb);
+                               break;
+                       }
+                       if (unlikely(err))
+                               dev_kfree_skb(skb); /* Drop it */
+                       err = 0;
+               }
+               if (!err)
+                       wl->tx_queue_stopped[queue_num] = 0;
+       }
+       mutex_unlock(&wl->mutex);
+ }
  static void b43legacy_op_tx(struct ieee80211_hw *hw,
                            struct sk_buff *skb)
  {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
-       struct b43legacy_wldev *dev = wl->current_dev;
-       int err = -ENODEV;
-       unsigned long flags;
  
-       if (unlikely(!dev))
-               goto out;
-       if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED))
-               goto out;
-       /* DMA-TX is done without a global lock. */
-       if (b43legacy_using_pio(dev)) {
-               spin_lock_irqsave(&wl->irq_lock, flags);
-               err = b43legacy_pio_tx(dev, skb);
-               spin_unlock_irqrestore(&wl->irq_lock, flags);
-       } else
-               err = b43legacy_dma_tx(dev, skb);
- out:
-       if (unlikely(err)) {
-               /* Drop the packet. */
+       if (unlikely(skb->len < 2 + 2 + 6)) {
+               /* Too short, this can't be a valid frame. */
                dev_kfree_skb_any(skb);
+               return;
        }
+       B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags);
+       skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb);
+       if (!wl->tx_queue_stopped[skb->queue_mapping])
+               ieee80211_queue_work(wl->hw, &wl->tx_work);
+       else
+               ieee80211_stop_queue(wl->hw, skb->queue_mapping);
  }
  
  static int b43legacy_op_conf_tx(struct ieee80211_hw *hw,
@@@ -2510,7 -2544,7 +2544,7 @@@ static int find_wldev_for_phymode(struc
                if (d->phy.possible_phymodes & phymode) {
                        /* Ok, this device supports the PHY-mode.
                         * Set the gmode bit. */
 -                      *gmode = 1;
 +                      *gmode = true;
                        *dev = d;
  
                        return 0;
@@@ -2546,7 -2580,7 +2580,7 @@@ static int b43legacy_switch_phymode(str
        struct b43legacy_wldev *uninitialized_var(up_dev);
        struct b43legacy_wldev *down_dev;
        int err;
 -      bool gmode = 0;
 +      bool gmode = false;
        int prev_status;
  
        err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode);
@@@ -2879,6 -2913,7 +2913,7 @@@ static void b43legacy_wireless_core_sto
  {
        struct b43legacy_wl *wl = dev->wl;
        unsigned long flags;
+       int queue_num;
  
        if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
                return;
        /* Must unlock as it would otherwise deadlock. No races here.
         * Cancel the possibly running self-rearming periodic work. */
        cancel_delayed_work_sync(&dev->periodic_work);
+       cancel_work_sync(&wl->tx_work);
        mutex_lock(&wl->mutex);
  
-       ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */
+       /* Drain all TX queues. */
+       for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) {
+               while (skb_queue_len(&wl->tx_queue[queue_num]))
+                       dev_kfree_skb(skb_dequeue(&wl->tx_queue[queue_num]));
+       }
  
      b43legacy_mac_suspend(dev);
+ b43legacy_mac_suspend(dev);
        free_irq(dev->dev->irq, dev);
        b43legacydbg(wl, "Wireless interface stopped\n");
  }
@@@ -3044,12 -3084,12 +3084,12 @@@ static void setup_struct_phy_for_init(s
  
        /* Assume the radio is enabled. If it's not enabled, the state will
         * immediately get fixed on the first periodic work run. */
 -      dev->radio_hw_enable = 1;
 +      dev->radio_hw_enable = true;
  
        phy->savedpctlreg = 0xFFFF;
 -      phy->aci_enable = 0;
 -      phy->aci_wlan_automatic = 0;
 -      phy->aci_hw_rssi = 0;
 +      phy->aci_enable = false;
 +      phy->aci_wlan_automatic = false;
 +      phy->aci_hw_rssi = false;
  
        lo = phy->_lo_pairs;
        if (lo)
  static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev)
  {
        /* Flags */
 -      dev->dfq_valid = 0;
 +      dev->dfq_valid = false;
  
        /* Stats */
        memset(&dev->stats, 0, sizeof(dev->stats));
@@@ -3187,9 -3227,9 +3227,9 @@@ static void prepare_phy_data_for_init(s
        phy->lofcal = 0xFFFF;
        phy->initval = 0xFFFF;
  
 -      phy->aci_enable = 0;
 -      phy->aci_wlan_automatic = 0;
 -      phy->aci_hw_rssi = 0;
 +      phy->aci_enable = false;
 +      phy->aci_wlan_automatic = false;
 +      phy->aci_hw_rssi = false;
  
        phy->antenna_diversity = 0xFFFF;
        memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
@@@ -3355,7 -3395,7 +3395,7 @@@ static int b43legacy_op_add_interface(s
        b43legacydbg(wl, "Adding Interface type %d\n", vif->type);
  
        dev = wl->current_dev;
 -      wl->operating = 1;
 +      wl->operating = true;
        wl->vif = vif;
        wl->if_type = vif->type;
        memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
@@@ -3389,7 -3429,7 +3429,7 @@@ static void b43legacy_op_remove_interfa
        B43legacy_WARN_ON(wl->vif != vif);
        wl->vif = NULL;
  
 -      wl->operating = 0;
 +      wl->operating = false;
  
        spin_lock_irqsave(&wl->irq_lock, flags);
        b43legacy_adjust_opmode(dev);
@@@ -3413,10 -3453,10 +3453,10 @@@ static int b43legacy_op_start(struct ie
        memset(wl->bssid, 0, ETH_ALEN);
        memset(wl->mac_addr, 0, ETH_ALEN);
        wl->filter_flags = 0;
 -      wl->beacon0_uploaded = 0;
 -      wl->beacon1_uploaded = 0;
 -      wl->beacon_templates_virgin = 1;
 -      wl->radio_enabled = 1;
 +      wl->beacon0_uploaded = false;
 +      wl->beacon1_uploaded = false;
 +      wl->beacon_templates_virgin = true;
 +      wl->radio_enabled = true;
  
        mutex_lock(&wl->mutex);
  
@@@ -3455,7 -3495,7 +3495,7 @@@ static void b43legacy_op_stop(struct ie
        if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
                b43legacy_wireless_core_stop(dev);
        b43legacy_wireless_core_exit(dev);
 -      wl->radio_enabled = 0;
 +      wl->radio_enabled = false;
        mutex_unlock(&wl->mutex);
  }
  
@@@ -3614,7 -3654,7 +3654,7 @@@ static int b43legacy_wireless_core_atta
                have_bphy = 1;
  
        dev->phy.gmode = (have_gphy || have_bphy);
 -      dev->phy.radio_on = 1;
 +      dev->phy.radio_on = true;
        tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
        b43legacy_wireless_core_reset(dev, tmp);
  
@@@ -3705,7 -3745,7 +3745,7 @@@ static int b43legacy_one_core_attach(st
                     (void (*)(unsigned long))b43legacy_interrupt_tasklet,
                     (unsigned long)wldev);
        if (modparam_pio)
 -              wldev->__using_pio = 1;
 +              wldev->__using_pio = true;
        INIT_LIST_HEAD(&wldev->list);
  
        err = b43legacy_wireless_core_attach(wldev);
@@@ -3748,6 -3788,7 +3788,7 @@@ static int b43legacy_wireless_init(stru
        struct ieee80211_hw *hw;
        struct b43legacy_wl *wl;
        int err = -ENOMEM;
+       int queue_num;
  
        b43legacy_sprom_fixup(dev->bus);
  
        mutex_init(&wl->mutex);
        INIT_LIST_HEAD(&wl->devlist);
        INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work);
+       INIT_WORK(&wl->tx_work, b43legacy_tx_work);
+       /* Initialize queues and flags. */
+       for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) {
+               skb_queue_head_init(&wl->tx_queue[queue_num]);
+               wl->tx_queue_stopped[queue_num] = 0;
+       }
  
        ssb_set_devtypedata(dev, wl);
        b43legacyinfo(wl, "Broadcom %04X WLAN found (core revision %u)\n",
@@@ -88,18 -88,16 +88,16 @@@ static int iwl_trans_rx_alloc(struct iw
                return -EINVAL;
  
        /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
-       rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                                    &rxq->bd_dma, GFP_KERNEL);
+       rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+                                     &rxq->bd_dma, GFP_KERNEL);
        if (!rxq->bd)
                goto err_bd;
-       memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE);
  
        /*Allocate the driver's pointer to receive buffer status */
-       rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts),
-                                         &rxq->rb_stts_dma, GFP_KERNEL);
+       rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
+                                          &rxq->rb_stts_dma, GFP_KERNEL);
        if (!rxq->rb_stts)
                goto err_rb_stts;
-       memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
  
        return 0;
  
@@@ -1188,7 -1186,9 +1186,7 @@@ static int iwl_trans_pcie_tx(struct iwl
        iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
  
        /* Set up entry for this TFD in Tx byte-count array */
 -      if (is_agg)
 -              iwl_trans_txq_update_byte_cnt_tbl(trans, txq,
 -                                             le16_to_cpu(tx_cmd->len));
 +      iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
  
        dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen,
                        DMA_BIDIRECTIONAL);
  
  #define MWL8K_DESC    "Marvell TOPDOG(R) 802.11 Wireless Network Driver"
  #define MWL8K_NAME    KBUILD_MODNAME
- #define MWL8K_VERSION "0.12"
+ #define MWL8K_VERSION "0.13"
  
  /* Module parameters */
 -static unsigned ap_mode_default;
 +static bool ap_mode_default;
  module_param(ap_mode_default, bool, 0);
  MODULE_PARM_DESC(ap_mode_default,
                 "Set to 1 to make ap mode the default instead of sta mode");
@@@ -198,6 -198,7 +198,7 @@@ struct mwl8k_priv 
        /* firmware access */
        struct mutex fw_mutex;
        struct task_struct *fw_mutex_owner;
+       struct task_struct *hw_restart_owner;
        int fw_mutex_depth;
        struct completion *hostcmd_wait;
  
         */
        struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES];
  
+       /* To perform the task of reloading the firmware */
+       struct work_struct fw_reload;
+       bool hw_restart_in_progress;
        /* async firmware loading state */
        unsigned fw_state;
        char *fw_pref;
@@@ -738,10 -743,10 +743,10 @@@ static int mwl8k_load_firmware(struct i
  
                ready_code = ioread32(priv->regs + MWL8K_HIU_INT_CODE);
                if (ready_code == MWL8K_FWAP_READY) {
 -                      priv->ap_fw = 1;
 +                      priv->ap_fw = true;
                        break;
                } else if (ready_code == MWL8K_FWSTA_READY) {
 -                      priv->ap_fw = 0;
 +                      priv->ap_fw = false;
                        break;
                }
  
@@@ -1498,6 -1503,18 +1503,18 @@@ static int mwl8k_tx_wait_empty(struct i
  
        might_sleep();
  
+       /* Since fw restart is in progress, allow only the firmware
+        * commands from the restart code and block the other
+        * commands since they are going to fail in any case since
+        * the firmware has crashed
+        */
+       if (priv->hw_restart_in_progress) {
+               if (priv->hw_restart_owner == current)
+                       return 0;
+               else
+                       return -EBUSY;
+       }
        /*
         * The TX queues are stopped at this point, so this test
         * doesn't need to take ->tx_lock.
                wiphy_err(hw->wiphy, "tx rings stuck for %d ms\n",
                          MWL8K_TX_WAIT_TIMEOUT_MS);
                mwl8k_dump_tx_rings(hw);
+               priv->hw_restart_in_progress = true;
+               ieee80211_queue_work(hw, &priv->fw_reload);
  
                rc = -ETIMEDOUT;
        }
@@@ -2058,7 -2077,9 +2077,9 @@@ static int mwl8k_fw_lock(struct ieee802
  
                rc = mwl8k_tx_wait_empty(hw);
                if (rc) {
-                       ieee80211_wake_queues(hw);
+                       if (!priv->hw_restart_in_progress)
+                               ieee80211_wake_queues(hw);
                        mutex_unlock(&priv->fw_mutex);
  
                        return rc;
@@@ -2077,7 -2098,9 +2098,9 @@@ static void mwl8k_fw_unlock(struct ieee
        struct mwl8k_priv *priv = hw->priv;
  
        if (!--priv->fw_mutex_depth) {
-               ieee80211_wake_queues(hw);
+               if (!priv->hw_restart_in_progress)
+                       ieee80211_wake_queues(hw);
                priv->fw_mutex_owner = NULL;
                mutex_unlock(&priv->fw_mutex);
        }
@@@ -4398,7 -4421,8 +4421,8 @@@ static void mwl8k_stop(struct ieee80211
        struct mwl8k_priv *priv = hw->priv;
        int i;
  
-       mwl8k_cmd_radio_disable(hw);
+       if (!priv->hw_restart_in_progress)
+               mwl8k_cmd_radio_disable(hw);
  
        ieee80211_stop_queues(hw);
  
@@@ -4499,6 -4523,16 +4523,16 @@@ static int mwl8k_add_interface(struct i
        return 0;
  }
  
+ static void mwl8k_remove_vif(struct mwl8k_priv *priv, struct mwl8k_vif *vif)
+ {
+       /* Has ieee80211_restart_hw re-added the removed interfaces? */
+       if (!priv->macids_used)
+               return;
+       priv->macids_used &= ~(1 << vif->macid);
+       list_del(&vif->list);
+ }
  static void mwl8k_remove_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif)
  {
  
        mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00");
  
-       priv->macids_used &= ~(1 << mwl8k_vif->macid);
-       list_del(&mwl8k_vif->list);
+       mwl8k_remove_vif(priv, mwl8k_vif);
+ }
+ static void mwl8k_hw_restart_work(struct work_struct *work)
+ {
+       struct mwl8k_priv *priv =
+               container_of(work, struct mwl8k_priv, fw_reload);
+       struct ieee80211_hw *hw = priv->hw;
+       struct mwl8k_device_info *di;
+       int rc;
+       /* If some command is waiting for a response, clear it */
+       if (priv->hostcmd_wait != NULL) {
+               complete(priv->hostcmd_wait);
+               priv->hostcmd_wait = NULL;
+       }
+       priv->hw_restart_owner = current;
+       di = priv->device_info;
+       mwl8k_fw_lock(hw);
+       if (priv->ap_fw)
+               rc = mwl8k_reload_firmware(hw, di->fw_image_ap);
+       else
+               rc = mwl8k_reload_firmware(hw, di->fw_image_sta);
+       if (rc)
+               goto fail;
+       priv->hw_restart_owner = NULL;
+       priv->hw_restart_in_progress = false;
+       /*
+        * This unlock will wake up the queues and
+        * also opens the command path for other
+        * commands
+        */
+       mwl8k_fw_unlock(hw);
+       ieee80211_restart_hw(hw);
+       wiphy_err(hw->wiphy, "Firmware restarted successfully\n");
+       return;
+ fail:
+       mwl8k_fw_unlock(hw);
+       wiphy_err(hw->wiphy, "Firmware restart failed\n");
  }
  
  static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
@@@ -5024,7 -5104,11 +5104,11 @@@ mwl8k_ampdu_action(struct ieee80211_hw 
                for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) {
                        rc = mwl8k_check_ba(hw, stream);
  
-                       if (!rc)
+                       /* If HW restart is in progress mwl8k_post_cmd will
+                        * return -EBUSY. Avoid retrying mwl8k_check_ba in
+                        * such cases
+                        */
+                       if (!rc || rc == -EBUSY)
                                break;
                        /*
                         * HW queues take time to be flushed, give them
@@@ -5263,12 -5347,15 +5347,15 @@@ fail
        mwl8k_release_firmware(priv);
  }
  
+ #define MAX_RESTART_ATTEMPTS 1
  static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image,
                               bool nowait)
  {
        struct mwl8k_priv *priv = hw->priv;
        int rc;
+       int count = MAX_RESTART_ATTEMPTS;
  
+ retry:
        /* Reset firmware and hardware */
        mwl8k_hw_reset(priv);
  
        /* Reclaim memory once firmware is successfully loaded */
        mwl8k_release_firmware(priv);
  
+       if (rc && count) {
+               /* FW did not start successfully;
+                * lets try one more time
+                */
+               count--;
+               wiphy_err(hw->wiphy, "Trying to reload the firmware again\n");
+               msleep(20);
+               goto retry;
+       }
        return rc;
  }
  
@@@ -5365,7 -5462,14 +5462,14 @@@ static int mwl8k_probe_hw(struct ieee80
                goto err_free_queues;
        }
  
-       memset(priv->ampdu, 0, sizeof(priv->ampdu));
+       /*
+        * When hw restart is requested,
+        * mac80211 will take care of clearing
+        * the ampdu streams, so do not clear
+        * the ampdu state here
+        */
+       if (!priv->hw_restart_in_progress)
+               memset(priv->ampdu, 0, sizeof(priv->ampdu));
  
        /*
         * Temporarily enable interrupts.  Initial firmware host
@@@ -5439,10 -5543,20 +5543,20 @@@ static int mwl8k_reload_firmware(struc
  {
        int i, rc = 0;
        struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_vif *vif, *tmp_vif;
  
        mwl8k_stop(hw);
        mwl8k_rxq_deinit(hw, 0);
  
+       /*
+        * All the existing interfaces are re-added by the ieee80211_reconfig;
+        * which means driver should remove existing interfaces before calling
+        * ieee80211_restart_hw
+        */
+       if (priv->hw_restart_in_progress)
+               list_for_each_entry_safe(vif, tmp_vif, &priv->vif_list, list)
+                       mwl8k_remove_vif(priv, vif);
        for (i = 0; i < mwl8k_tx_queues(priv); i++)
                mwl8k_txq_deinit(hw, i);
  
        if (rc)
                goto fail;
  
+       if (priv->hw_restart_in_progress)
+               return rc;
        rc = mwl8k_start(hw);
        if (rc)
                goto fail;
@@@ -5517,13 -5634,15 +5634,15 @@@ static int mwl8k_firmware_load_success(
        INIT_LIST_HEAD(&priv->vif_list);
  
        /* Set default radio state and preamble */
 -      priv->radio_on = 0;
 -      priv->radio_short_preamble = 0;
 +      priv->radio_on = false;
 +      priv->radio_short_preamble = false;
  
        /* Finalize join worker */
        INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
        /* Handle watchdog ba events */
        INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events);
+       /* To reload the firmware if it crashes */
+       INIT_WORK(&priv->fw_reload, mwl8k_hw_restart_work);
  
        /* TX reclaim and RX tasklets.  */
        tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
@@@ -5667,6 -5786,9 +5786,9 @@@ static int __devinit mwl8k_probe(struc
        rc = mwl8k_init_firmware(hw, priv->fw_pref, true);
        if (rc)
                goto err_stop_firmware;
+       priv->hw_restart_in_progress = false;
        return rc;
  
  err_stop_firmware:
@@@ -45,7 -45,7 +45,7 @@@
  /*
   * Allow hardware encryption to be disabled.
   */
 -static int modparam_nohwcrypt;
 +static bool modparam_nohwcrypt;
  module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
  MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
  
@@@ -400,10 -400,10 +400,10 @@@ static void rt2800usb_write_tx_desc(str
        /*
         * The size of TXINFO_W0_USB_DMA_TX_PKT_LEN is
         * TXWI + 802.11 header + L2 pad + payload + pad,
-        * so need to decrease size of TXINFO and USB end pad.
+        * so need to decrease size of TXINFO.
         */
        rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
-                          entry->skb->len - TXINFO_DESC_SIZE - 4);
+                          roundup(entry->skb->len, 4) - TXINFO_DESC_SIZE);
        rt2x00_set_field32(&word, TXINFO_W0_WIV,
                           !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
        rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2);
        skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
  }
  
- static void rt2800usb_write_tx_data(struct queue_entry *entry,
-                                       struct txentry_desc *txdesc)
+ /*
+  * TX data initialization
+  */
+ static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
  {
-       unsigned int len;
-       int err;
-       rt2800_write_tx_data(entry, txdesc);
        /*
-        * pad(1~3 bytes) is added after each 802.11 payload.
-        * USB end pad(4 bytes) is added at each USB bulk out packet end.
+        * pad(1~3 bytes) is needed after each 802.11 payload.
+        * USB end pad(4 bytes) is needed at each USB bulk out packet end.
         * TX frame format is :
         * | TXINFO | TXWI | 802.11 header | L2 pad | payload | pad | USB end pad |
         *                 |<------------- tx_pkt_len ------------->|
         */
-       len = roundup(entry->skb->len, 4) + 4;
-       err = skb_padto(entry->skb, len);
-       if (unlikely(err)) {
-               WARNING(entry->queue->rt2x00dev, "TX SKB padding error, out of memory\n");
-               return;
-       }
  
-       entry->skb->len = len;
- }
- /*
-  * TX data initialization
-  */
- static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
- {
-       return entry->skb->len;
+       return roundup(entry->skb->len, 4) + 4;
  }
  
  /*
@@@ -807,7 -790,7 +790,7 @@@ static const struct rt2x00lib_ops rt280
        .flush_queue            = rt2x00usb_flush_queue,
        .tx_dma_done            = rt2800usb_tx_dma_done,
        .write_tx_desc          = rt2800usb_write_tx_desc,
-       .write_tx_data          = rt2800usb_write_tx_data,
+       .write_tx_data          = rt2800_write_tx_data,
        .write_beacon           = rt2800_write_beacon,
        .clear_beacon           = rt2800_clear_beacon,
        .get_tx_data_len        = rt2800usb_get_tx_data_len,
@@@ -914,12 -897,14 +897,14 @@@ static struct usb_device_id rt2800usb_d
        { USB_DEVICE(0x050d, 0x8053) },
        { USB_DEVICE(0x050d, 0x805c) },
        { USB_DEVICE(0x050d, 0x815c) },
+       { USB_DEVICE(0x050d, 0x825a) },
        { USB_DEVICE(0x050d, 0x825b) },
        { USB_DEVICE(0x050d, 0x935a) },
        { USB_DEVICE(0x050d, 0x935b) },
        /* Buffalo */
        { USB_DEVICE(0x0411, 0x00e8) },
        { USB_DEVICE(0x0411, 0x0158) },
+       { USB_DEVICE(0x0411, 0x015d) },
        { USB_DEVICE(0x0411, 0x016f) },
        { USB_DEVICE(0x0411, 0x01a2) },
        /* Corega */
        { USB_DEVICE(0x07d1, 0x3c0e) },
        { USB_DEVICE(0x07d1, 0x3c0f) },
        { USB_DEVICE(0x07d1, 0x3c11) },
+       { USB_DEVICE(0x07d1, 0x3c13) },
+       { USB_DEVICE(0x07d1, 0x3c15) },
        { USB_DEVICE(0x07d1, 0x3c16) },
        /* Draytek */
        { USB_DEVICE(0x07fa, 0x7712) },
        { USB_DEVICE(0x7392, 0x7711) },
        { USB_DEVICE(0x7392, 0x7717) },
        { USB_DEVICE(0x7392, 0x7718) },
+       { USB_DEVICE(0x7392, 0x7722) },
        /* Encore */
        { USB_DEVICE(0x203d, 0x1480) },
        { USB_DEVICE(0x203d, 0x14a9) },
        { USB_DEVICE(0x13b1, 0x0031) },
        { USB_DEVICE(0x1737, 0x0070) },
        { USB_DEVICE(0x1737, 0x0071) },
+       { USB_DEVICE(0x1737, 0x0077) },
+       { USB_DEVICE(0x1737, 0x0078) },
        /* Logitec */
        { USB_DEVICE(0x0789, 0x0162) },
        { USB_DEVICE(0x0789, 0x0163) },
        { USB_DEVICE(0x0db0, 0x871b) },
        { USB_DEVICE(0x0db0, 0x871c) },
        { USB_DEVICE(0x0db0, 0x899a) },
+       /* Ovislink */
+       { USB_DEVICE(0x1b75, 0x3071) },
+       { USB_DEVICE(0x1b75, 0x3072) },
        /* Para */
        { USB_DEVICE(0x20b8, 0x8888) },
        /* Pegatron */
+       { USB_DEVICE(0x1d4d, 0x0002) },
        { USB_DEVICE(0x1d4d, 0x000c) },
        { USB_DEVICE(0x1d4d, 0x000e) },
        { USB_DEVICE(0x1d4d, 0x0011) },
        /* Sparklan */
        { USB_DEVICE(0x15a9, 0x0006) },
        /* Sweex */
+       { USB_DEVICE(0x177f, 0x0153) },
        { USB_DEVICE(0x177f, 0x0302) },
+       { USB_DEVICE(0x177f, 0x0313) },
        /* U-Media */
        { USB_DEVICE(0x157e, 0x300e) },
        { USB_DEVICE(0x157e, 0x3013) },
        { USB_DEVICE(0x13d3, 0x3322) },
        /* Belkin */
        { USB_DEVICE(0x050d, 0x1003) },
-       { USB_DEVICE(0x050d, 0x825a) },
        /* Buffalo */
        { USB_DEVICE(0x0411, 0x012e) },
        { USB_DEVICE(0x0411, 0x0148) },
        { USB_DEVICE(0x0411, 0x0150) },
-       { USB_DEVICE(0x0411, 0x015d) },
        /* Corega */
        { USB_DEVICE(0x07aa, 0x0041) },
        { USB_DEVICE(0x07aa, 0x0042) },
        { USB_DEVICE(0x18c5, 0x0008) },
        /* D-Link */
        { USB_DEVICE(0x07d1, 0x3c0b) },
-       { USB_DEVICE(0x07d1, 0x3c13) },
-       { USB_DEVICE(0x07d1, 0x3c15) },
        { USB_DEVICE(0x07d1, 0x3c17) },
        { USB_DEVICE(0x2001, 0x3c17) },
        /* Edimax */
        { USB_DEVICE(0x7392, 0x4085) },
-       { USB_DEVICE(0x7392, 0x7722) },
        /* Encore */
        { USB_DEVICE(0x203d, 0x14a1) },
        /* Fujitsu Stylistic 550 */
        /* LevelOne */
        { USB_DEVICE(0x1740, 0x0605) },
        { USB_DEVICE(0x1740, 0x0615) },
-       /* Linksys */
-       { USB_DEVICE(0x1737, 0x0077) },
-       { USB_DEVICE(0x1737, 0x0078) },
        /* Logitec */
        { USB_DEVICE(0x0789, 0x0168) },
        { USB_DEVICE(0x0789, 0x0169) },
        /* Motorola */
        { USB_DEVICE(0x100d, 0x9032) },
-       /* Ovislink */
-       { USB_DEVICE(0x1b75, 0x3071) },
-       { USB_DEVICE(0x1b75, 0x3072) },
        /* Pegatron */
        { USB_DEVICE(0x05a6, 0x0101) },
-       { USB_DEVICE(0x1d4d, 0x0002) },
        { USB_DEVICE(0x1d4d, 0x0010) },
        /* Planex */
        { USB_DEVICE(0x2019, 0x5201) },
        { USB_DEVICE(0x083a, 0xc522) },
        { USB_DEVICE(0x083a, 0xd522) },
        { USB_DEVICE(0x083a, 0xf511) },
-       /* Sweex */
-       { USB_DEVICE(0x177f, 0x0153) },
-       { USB_DEVICE(0x177f, 0x0313) },
        /* Zyxel */
        { USB_DEVICE(0x0586, 0x341a) },
  #endif
diff --combined net/mac80211/scan.c
@@@ -106,7 -106,7 +106,7 @@@ ieee80211_bss_info_update(struct ieee80
        /* save the ERP value so that it is available at association time */
        if (elems->erp_info && elems->erp_info_len >= 1) {
                bss->erp_value = elems->erp_info[0];
 -              bss->has_erp_value = 1;
 +              bss->has_erp_value = true;
        }
  
        if (elems->tim) {
@@@ -625,7 -625,7 +625,7 @@@ static void ieee80211_scan_state_resume
        local->leave_oper_channel_time = jiffies;
  
        /* advance to the next channel to be scanned */
-       local->next_scan_state = SCAN_DECISION;
+       local->next_scan_state = SCAN_SET_CHANNEL;
  }
  
  void ieee80211_scan_work(struct work_struct *work)