Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 22 Aug 2011 18:28:50 +0000 (14:28 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 22 Aug 2011 18:28:50 +0000 (14:28 -0400)
Conflicts:
drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c
drivers/staging/ath6kl/os/linux/ar6000_drv.c

1  2 
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas/mesh.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/rndis_wlan.c
net/mac80211/cfg.c
net/mac80211/sta_info.c

@@@ -52,6 -52,7 +52,7 @@@
  #include <linux/uaccess.h>
  #include <linux/slab.h>
  #include <linux/etherdevice.h>
+ #include <linux/nl80211.h>
  
  #include <net/ieee80211_radiotap.h>
  
@@@ -61,6 -62,8 +62,8 @@@
  #include "reg.h"
  #include "debug.h"
  #include "ani.h"
+ #include "ath5k.h"
+ #include "../regd.h"
  
  #define CREATE_TRACE_POINTS
  #include "trace.h"
@@@ -272,20 -275,18 +275,18 @@@ static unsigned in
  ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels,
                unsigned int mode, unsigned int max)
  {
-       unsigned int count, size, chfreq, freq, ch;
+       unsigned int count, size, freq, ch;
        enum ieee80211_band band;
  
        switch (mode) {
        case AR5K_MODE_11A:
                /* 1..220, but 2GHz frequencies are filtered by check_channel */
                size = 220;
-               chfreq = CHANNEL_5GHZ;
                band = IEEE80211_BAND_5GHZ;
                break;
        case AR5K_MODE_11B:
        case AR5K_MODE_11G:
                size = 26;
-               chfreq = CHANNEL_2GHZ;
                band = IEEE80211_BAND_2GHZ;
                break;
        default:
                if (freq == 0) /* mapping failed - not a standard channel */
                        continue;
  
+               /* Write channel info, needed for ath5k_channel_ok() */
+               channels[count].center_freq = freq;
+               channels[count].band = band;
+               channels[count].hw_value = mode;
                /* Check if channel is supported by the chipset */
-               if (!ath5k_channel_ok(ah, freq, chfreq))
+               if (!ath5k_channel_ok(ah, &channels[count]))
                        continue;
  
                if (!modparam_all_channels &&
                    !ath5k_is_standard_channel(ch, band))
                        continue;
  
-               /* Write channel info and increment counter */
-               channels[count].center_freq = freq;
-               channels[count].band = band;
-               switch (mode) {
-               case AR5K_MODE_11A:
-               case AR5K_MODE_11G:
-                       channels[count].hw_value = chfreq | CHANNEL_OFDM;
-                       break;
-               case AR5K_MODE_11B:
-                       channels[count].hw_value = CHANNEL_B;
-               }
                count++;
        }
  
@@@ -1735,8 -1729,6 +1729,8 @@@ ath5k_beacon_setup(struct ath5k_hw *ah
  
        if (dma_mapping_error(ah->dev, bf->skbaddr)) {
                ATH5K_ERR(ah, "beacon DMA mapping failed\n");
 +              dev_kfree_skb_any(skb);
 +              bf->skb = NULL;
                return -EIO;
        }
  
@@@ -1821,6 -1813,8 +1815,6 @@@ ath5k_beacon_update(struct ieee80211_h
        ath5k_txbuf_free_skb(ah, avf->bbuf);
        avf->bbuf->skb = skb;
        ret = ath5k_beacon_setup(ah, avf->bbuf);
 -      if (ret)
 -              avf->bbuf->skb = NULL;
  out:
        return ret;
  }
@@@ -1840,7 -1834,6 +1834,7 @@@ ath5k_beacon_send(struct ath5k_hw *ah
        struct ath5k_vif *avf;
        struct ath5k_buf *bf;
        struct sk_buff *skb;
 +      int err;
  
        ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, "in beacon_send\n");
  
  
        avf = (void *)vif->drv_priv;
        bf = avf->bbuf;
 -      if (unlikely(bf->skb == NULL || ah->opmode == NL80211_IFTYPE_STATION ||
 -                   ah->opmode == NL80211_IFTYPE_MONITOR)) {
 -              ATH5K_WARN(ah, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
 -              return;
 -      }
  
        /*
         * Stop any current dma and put the new frame on the queue.
  
        /* refresh the beacon for AP or MESH mode */
        if (ah->opmode == NL80211_IFTYPE_AP ||
 -          ah->opmode == NL80211_IFTYPE_MESH_POINT)
 -              ath5k_beacon_update(ah->hw, vif);
 +          ah->opmode == NL80211_IFTYPE_MESH_POINT) {
 +              err = ath5k_beacon_update(ah->hw, vif);
 +              if (err)
 +                      return;
 +      }
 +
 +      if (unlikely(bf->skb == NULL || ah->opmode == NL80211_IFTYPE_STATION ||
 +                   ah->opmode == NL80211_IFTYPE_MONITOR)) {
 +              ATH5K_WARN(ah, "bf=%p bf_skb=%p\n", bf, bf->skb);
 +              return;
 +      }
  
        trace_ath5k_tx(ah, bf->skb, &ah->txqs[ah->bhalq]);
  
@@@ -2349,7 -2338,7 +2343,7 @@@ ath5k_tx_complete_poll_work(struct work
  \*************************/
  
  int __devinit
- ath5k_init_softc(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
+ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
  {
        struct ieee80211_hw *hw = ah->hw;
        struct ath_common *common;
@@@ -2867,7 -2856,6 +2861,6 @@@ ath5k_init(struct ieee80211_hw *hw
        }
  
        SET_IEEE80211_PERM_ADDR(hw, mac);
-       memcpy(&ah->lladdr, mac, ETH_ALEN);
        /* All MAC address bits matter for ACKs */
        ath5k_update_bssid_mask_and_opmode(ah, NULL);
  
@@@ -2903,7 -2891,7 +2896,7 @@@ err
  }
  
  void
- ath5k_deinit_softc(struct ath5k_hw *ah)
+ ath5k_deinit_ah(struct ath5k_hw *ah)
  {
        struct ieee80211_hw *hw = ah->hw;
  
@@@ -307,7 -307,7 +307,7 @@@ static const struct ar9300_eeprom ar930
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
  
 -               { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
 +               { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
  
@@@ -884,7 -884,7 +884,7 @@@ static const struct ar9300_eeprom ar930
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
  
 -               { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
 +               { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
  
@@@ -2040,7 -2040,7 +2040,7 @@@ static const struct ar9300_eeprom ar930
                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
  
 -              { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
 +              { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0) } },
                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
  
@@@ -3418,6 -3418,133 +3418,133 @@@ static bool ath9k_hw_ar9300_fill_eeprom
        return true;
  }
  
+ #if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
+ static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size,
+                                   struct ar9300_modal_eep_header *modal_hdr)
+ {
+       PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0]));
+       PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1]));
+       PR_EEP("Chain2 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[2]));
+       PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon));
+       PR_EEP("Ant. Common Control2", le32_to_cpu(modal_hdr->antCtrlCommon2));
+       PR_EEP("Ant. Gain", modal_hdr->antennaGain);
+       PR_EEP("Switch Settle", modal_hdr->switchSettling);
+       PR_EEP("Chain0 xatten1DB", modal_hdr->xatten1DB[0]);
+       PR_EEP("Chain1 xatten1DB", modal_hdr->xatten1DB[1]);
+       PR_EEP("Chain2 xatten1DB", modal_hdr->xatten1DB[2]);
+       PR_EEP("Chain0 xatten1Margin", modal_hdr->xatten1Margin[0]);
+       PR_EEP("Chain1 xatten1Margin", modal_hdr->xatten1Margin[1]);
+       PR_EEP("Chain2 xatten1Margin", modal_hdr->xatten1Margin[2]);
+       PR_EEP("Temp Slope", modal_hdr->tempSlope);
+       PR_EEP("Volt Slope", modal_hdr->voltSlope);
+       PR_EEP("spur Channels0", modal_hdr->spurChans[0]);
+       PR_EEP("spur Channels1", modal_hdr->spurChans[1]);
+       PR_EEP("spur Channels2", modal_hdr->spurChans[2]);
+       PR_EEP("spur Channels3", modal_hdr->spurChans[3]);
+       PR_EEP("spur Channels4", modal_hdr->spurChans[4]);
+       PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
+       PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
+       PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]);
+       PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
+       PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
+       PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
+       PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
+       PR_EEP("txClip", modal_hdr->txClip);
+       PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
+       PR_EEP("Chain0 ob", modal_hdr->ob[0]);
+       PR_EEP("Chain1 ob", modal_hdr->ob[1]);
+       PR_EEP("Chain2 ob", modal_hdr->ob[2]);
+       PR_EEP("Chain0 db_stage2", modal_hdr->db_stage2[0]);
+       PR_EEP("Chain1 db_stage2", modal_hdr->db_stage2[1]);
+       PR_EEP("Chain2 db_stage2", modal_hdr->db_stage2[2]);
+       PR_EEP("Chain0 db_stage3", modal_hdr->db_stage3[0]);
+       PR_EEP("Chain1 db_stage3", modal_hdr->db_stage3[1]);
+       PR_EEP("Chain2 db_stage3", modal_hdr->db_stage3[2]);
+       PR_EEP("Chain0 db_stage4", modal_hdr->db_stage4[0]);
+       PR_EEP("Chain1 db_stage4", modal_hdr->db_stage4[1]);
+       PR_EEP("Chain2 db_stage4", modal_hdr->db_stage4[2]);
+       return len;
+ }
+ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+                                      u8 *buf, u32 len, u32 size)
+ {
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       struct ar9300_base_eep_hdr *pBase;
+       if (!dump_base_hdr) {
+               len += snprintf(buf + len, size - len,
+                               "%20s :\n", "2GHz modal Header");
+               len += ar9003_dump_modal_eeprom(buf, len, size,
+                                               &eep->modalHeader2G);
+               len += snprintf(buf + len, size - len,
+                               "%20s :\n", "5GHz modal Header");
+               len += ar9003_dump_modal_eeprom(buf, len, size,
+                                               &eep->modalHeader5G);
+               goto out;
+       }
+       pBase = &eep->baseEepHeader;
+       PR_EEP("EEPROM Version", ah->eeprom.ar9300_eep.eepromVersion);
+       PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0]));
+       PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1]));
+       PR_EEP("TX Mask", (pBase->txrxMask >> 4));
+       PR_EEP("RX Mask", (pBase->txrxMask & 0x0f));
+       PR_EEP("Allow 5GHz", !!(pBase->opCapFlags.opFlags &
+                               AR5416_OPFLAGS_11A));
+       PR_EEP("Allow 2GHz", !!(pBase->opCapFlags.opFlags &
+                               AR5416_OPFLAGS_11G));
+       PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags.opFlags &
+                                       AR5416_OPFLAGS_N_2G_HT20));
+       PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags.opFlags &
+                                       AR5416_OPFLAGS_N_2G_HT40));
+       PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags.opFlags &
+                                       AR5416_OPFLAGS_N_5G_HT20));
+       PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags.opFlags &
+                                       AR5416_OPFLAGS_N_5G_HT40));
+       PR_EEP("Big Endian", !!(pBase->opCapFlags.eepMisc & 0x01));
+       PR_EEP("RF Silent", pBase->rfSilent);
+       PR_EEP("BT option", pBase->blueToothOptions);
+       PR_EEP("Device Cap", pBase->deviceCap);
+       PR_EEP("Device Type", pBase->deviceType);
+       PR_EEP("Power Table Offset", pBase->pwrTableOffset);
+       PR_EEP("Tuning Caps1", pBase->params_for_tuning_caps[0]);
+       PR_EEP("Tuning Caps2", pBase->params_for_tuning_caps[1]);
+       PR_EEP("Enable Tx Temp Comp", !!(pBase->featureEnable & BIT(0)));
+       PR_EEP("Enable Tx Volt Comp", !!(pBase->featureEnable & BIT(1)));
+       PR_EEP("Enable fast clock", !!(pBase->featureEnable & BIT(2)));
+       PR_EEP("Enable doubling", !!(pBase->featureEnable & BIT(3)));
+       PR_EEP("Internal regulator", !!(pBase->featureEnable & BIT(4)));
+       PR_EEP("Enable Paprd", !!(pBase->featureEnable & BIT(5)));
+       PR_EEP("Driver Strength", !!(pBase->miscConfiguration & BIT(0)));
+       PR_EEP("Chain mask Reduce", (pBase->miscConfiguration >> 0x3) & 0x1);
+       PR_EEP("Write enable Gpio", pBase->eepromWriteEnableGpio);
+       PR_EEP("WLAN Disable Gpio", pBase->wlanDisableGpio);
+       PR_EEP("WLAN LED Gpio", pBase->wlanLedGpio);
+       PR_EEP("Rx Band Select Gpio", pBase->rxBandSelectGpio);
+       PR_EEP("Tx Gain", pBase->txrxgain >> 4);
+       PR_EEP("Rx Gain", pBase->txrxgain & 0xf);
+       PR_EEP("SW Reg", le32_to_cpu(pBase->swreg));
+       len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+                       ah->eeprom.ar9300_eep.macAddr);
+ out:
+       if (len > size)
+               len = size;
+       return len;
+ }
+ #else
+ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+                                      u8 *buf, u32 len, u32 size)
+ {
+       return 0;
+ }
+ #endif
  /* XXX: review hardware docs */
  static int ath9k_hw_ar9300_get_eeprom_ver(struct ath_hw *ah)
  {
@@@ -3734,7 -3861,7 +3861,7 @@@ static void ar9003_hw_internal_regulato
                                }
                        } else {
                                reg_pmu_set = (5 << 1) | (7 << 4) |
 -                                            (1 << 8) | (2 << 14) |
 +                                            (2 << 8) | (2 << 14) |
                                              (6 << 17) | (1 << 20) |
                                              (3 << 24) | (1 << 28);
                        }
@@@ -4061,7 -4188,7 +4188,7 @@@ static int ar9003_hw_tx_power_regwrite(
          /* Write the power for duplicated frames - HT40 */
  
          /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */
-       REG_WRITE(ah, 0xa3e0,
+       REG_WRITE(ah, AR_PHY_POWER_TX_RATE(8),
                  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) |
                  POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) |
                  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24],  8) |
@@@ -4922,25 -5049,7 +5049,7 @@@ static void ath9k_hw_ar9300_set_txpower
                        "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
        }
  
-       /*
-        * This is the TX power we send back to driver core,
-        * and it can use to pass to userspace to display our
-        * currently configured TX power setting.
-        *
-        * Since power is rate dependent, use one of the indices
-        * from the AR9300_Rates enum to select an entry from
-        * targetPowerValT2[] to report. Currently returns the
-        * power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps
-        * as CCK power is less interesting (?).
-        */
-       i = ALL_TARGET_LEGACY_6_24; /* legacy */
-       if (IS_CHAN_HT40(chan))
-               i = ALL_TARGET_HT40_0_8_16; /* ht40 */
-       else if (IS_CHAN_HT20(chan))
-               i = ALL_TARGET_HT20_0_8_16; /* ht20 */
-       ah->txpower_limit = targetPowerValT2[i];
-       regulatory->max_power_level = targetPowerValT2[i];
+       ah->txpower_limit = regulatory->max_power_level;
  
        /* Write target power array to registers */
        ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
@@@ -5015,6 -5124,7 +5124,7 @@@ const struct eeprom_ops eep_ar9300_ops 
        .check_eeprom = ath9k_hw_ar9300_check_eeprom,
        .get_eeprom = ath9k_hw_ar9300_get_eeprom,
        .fill_eeprom = ath9k_hw_ar9300_fill_eeprom,
+       .dump_eeprom = ath9k_hw_ar9003_dump_eeprom,
        .get_eeprom_ver = ath9k_hw_ar9300_get_eeprom_ver,
        .get_eeprom_rev = ath9k_hw_ar9300_get_eeprom_rev,
        .set_board_values = ath9k_hw_ar9300_set_board_values,
@@@ -32,6 -32,7 +32,7 @@@
  
  #include <linux/sched.h>
  #include <linux/slab.h>
+ #include <net/cfg80211-wext.h>
  #include "ipw2200.h"
  
  
@@@ -11701,7 -11702,7 +11702,7 @@@ static const struct net_device_ops ipw_
        .ndo_init               = ipw_net_init,
        .ndo_open               = ipw_net_open,
        .ndo_stop               = ipw_net_stop,
 -      .ndo_set_multicast_list = ipw_net_set_multicast_list,
 +      .ndo_set_rx_mode        = ipw_net_set_multicast_list,
        .ndo_set_mac_address    = ipw_net_set_mac_address,
        .ndo_start_xmit         = libipw_xmit,
        .ndo_change_mtu         = libipw_change_mtu,
@@@ -23,6 -23,7 +23,7 @@@
  #include "cfg.h"
  #include "debugfs.h"
  #include "cmd.h"
+ #include "mesh.h"
  
  #define DRIVER_RELEASE_VERSION "323.p0"
  const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
@@@ -98,6 -99,37 +99,37 @@@ u8 lbs_data_rate_to_fw_index(u32 rate
        return 0;
  }
  
+ int lbs_start_iface(struct lbs_private *priv)
+ {
+       struct cmd_ds_802_11_mac_address cmd;
+       int ret;
+       if (priv->power_restore) {
+               ret = priv->power_restore(priv);
+               if (ret)
+                       return ret;
+       }
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       memcpy(cmd.macadd, priv->current_addr, ETH_ALEN);
+       ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
+       if (ret) {
+               lbs_deb_net("set MAC address failed\n");
+               goto err;
+       }
+       lbs_update_channel(priv);
+       priv->iface_running = true;
+       return 0;
+ err:
+       if (priv->power_save)
+               priv->power_save(priv);
+       return ret;
+ }
  
  /**
   *  lbs_dev_open - open the ethX interface
@@@ -111,23 -143,64 +143,64 @@@ static int lbs_dev_open(struct net_devi
        int ret = 0;
  
        lbs_deb_enter(LBS_DEB_NET);
+       if (!priv->iface_running) {
+               ret = lbs_start_iface(priv);
+               if (ret)
+                       goto out;
+       }
  
        spin_lock_irq(&priv->driver_lock);
-       priv->stopping = false;
  
-       if (priv->connect_status == LBS_CONNECTED)
-               netif_carrier_on(dev);
-       else
-               netif_carrier_off(dev);
+       netif_carrier_off(dev);
  
        if (!priv->tx_pending_len)
                netif_wake_queue(dev);
  
        spin_unlock_irq(&priv->driver_lock);
+ out:
        lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
        return ret;
  }
  
+ static bool lbs_command_queue_empty(struct lbs_private *priv)
+ {
+       unsigned long flags;
+       bool ret;
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       ret = priv->cur_cmd == NULL && list_empty(&priv->cmdpendingq);
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+       return ret;
+ }
+ int lbs_stop_iface(struct lbs_private *priv)
+ {
+       unsigned long flags;
+       int ret = 0;
+       lbs_deb_enter(LBS_DEB_MAIN);
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       priv->iface_running = false;
+       kfree_skb(priv->currenttxskb);
+       priv->currenttxskb = NULL;
+       priv->tx_pending_len = 0;
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+       cancel_work_sync(&priv->mcast_work);
+       /* Disable command processing, and wait for all commands to complete */
+       lbs_deb_main("waiting for commands to complete\n");
+       wait_event(priv->waitq, lbs_command_queue_empty(priv));
+       lbs_deb_main("all commands completed\n");
+       if (priv->power_save)
+               ret = priv->power_save(priv);
+       lbs_deb_leave(LBS_DEB_MAIN);
+       return ret;
+ }
  /**
   *  lbs_eth_stop - close the ethX interface
   *
@@@ -140,18 -213,25 +213,25 @@@ static int lbs_eth_stop(struct net_devi
  
        lbs_deb_enter(LBS_DEB_NET);
  
+       if (priv->connect_status == LBS_CONNECTED)
+               lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING);
        spin_lock_irq(&priv->driver_lock);
-       priv->stopping = true;
        netif_stop_queue(dev);
        spin_unlock_irq(&priv->driver_lock);
  
-       schedule_work(&priv->mcast_work);
+       lbs_update_mcast(priv);
        cancel_delayed_work_sync(&priv->scan_work);
        if (priv->scan_req) {
                cfg80211_scan_done(priv->scan_req, false);
                priv->scan_req = NULL;
        }
  
+       netif_carrier_off(priv->dev);
+       if (!lbs_iface_active(priv))
+               lbs_stop_iface(priv);
        lbs_deb_leave(LBS_DEB_NET);
        return 0;
  }
@@@ -169,7 -249,7 +249,7 @@@ void lbs_host_to_card_done(struct lbs_p
        /* Wake main thread if commands are pending */
        if (!priv->cur_cmd || priv->tx_pending_len > 0) {
                if (!priv->wakeup_dev_required)
-                       wake_up_interruptible(&priv->waitq);
+                       wake_up(&priv->waitq);
        }
  
        spin_unlock_irqrestore(&priv->driver_lock, flags);
@@@ -182,29 -262,24 +262,24 @@@ int lbs_set_mac_address(struct net_devi
        int ret = 0;
        struct lbs_private *priv = dev->ml_priv;
        struct sockaddr *phwaddr = addr;
-       struct cmd_ds_802_11_mac_address cmd;
  
        lbs_deb_enter(LBS_DEB_NET);
  
+       /*
+        * Can only set MAC address when all interfaces are down, to be written
+        * to the hardware when one of them is brought up.
+        */
+       if (lbs_iface_active(priv))
+               return -EBUSY;
        /* In case it was called from the mesh device */
        dev = priv->dev;
  
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_SET);
-       memcpy(cmd.macadd, phwaddr->sa_data, ETH_ALEN);
-       ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
-       if (ret) {
-               lbs_deb_net("set MAC address failed\n");
-               goto done;
-       }
        memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
        memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
        if (priv->mesh_dev)
                memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
  
- done:
        lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
        return ret;
  }
@@@ -258,18 -333,18 +333,18 @@@ static int lbs_add_mcast_addrs(struct c
        return i;
  }
  
static void lbs_set_mcast_worker(struct work_struct *work)
void lbs_update_mcast(struct lbs_private *priv)
  {
-       struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
        struct cmd_ds_mac_multicast_adr mcast_cmd;
-       int dev_flags;
+       int dev_flags = 0;
        int nr_addrs;
        int old_mac_control = priv->mac_control;
  
        lbs_deb_enter(LBS_DEB_NET);
  
-       dev_flags = priv->dev->flags;
-       if (priv->mesh_dev)
+       if (netif_running(priv->dev))
+               dev_flags |= priv->dev->flags;
+       if (priv->mesh_dev && netif_running(priv->mesh_dev))
                dev_flags |= priv->mesh_dev->flags;
  
        if (dev_flags & IFF_PROMISC) {
        lbs_deb_leave(LBS_DEB_NET);
  }
  
+ static void lbs_set_mcast_worker(struct work_struct *work)
+ {
+       struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
+       lbs_update_mcast(priv);
+ }
  void lbs_set_multicast_list(struct net_device *dev)
  {
        struct lbs_private *priv = dev->ml_priv;
@@@ -647,7 -728,7 +728,7 @@@ static void lbs_cmd_timeout_handler(uns
        if (priv->dnld_sent == DNLD_CMD_SENT)
                priv->dnld_sent = DNLD_RES_RECEIVED;
  
-       wake_up_interruptible(&priv->waitq);
+       wake_up(&priv->waitq);
  out:
        spin_unlock_irqrestore(&priv->driver_lock, flags);
        lbs_deb_leave(LBS_DEB_CMD);
@@@ -786,7 -867,7 +867,7 @@@ static const struct net_device_ops lbs_
        .ndo_stop               = lbs_eth_stop,
        .ndo_start_xmit         = lbs_hard_start_xmit,
        .ndo_set_mac_address    = lbs_set_mac_address,
 -      .ndo_set_multicast_list = lbs_set_multicast_list,
 +      .ndo_set_rx_mode        = lbs_set_multicast_list,
        .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
  };
@@@ -889,10 -970,6 +970,6 @@@ void lbs_remove_card(struct lbs_privat
        lbs_remove_mesh(priv);
        lbs_scan_deinit(priv);
  
-       dev = priv->dev;
-       cancel_work_sync(&priv->mcast_work);
        /* worker thread destruction blocks on the in-flight command which
         * should have been cleared already in lbs_stop_card().
         */
@@@ -950,17 -1027,18 +1027,18 @@@ int lbs_start_card(struct lbs_private *
        if (ret)
                goto done;
  
+       if (!lbs_disablemesh)
+               lbs_init_mesh(priv);
+       else
+               pr_info("%s: mesh disabled\n", dev->name);
        if (lbs_cfg_register(priv)) {
                pr_err("cannot register device\n");
                goto done;
        }
  
-       lbs_update_channel(priv);
-       if (!lbs_disablemesh)
-               lbs_init_mesh(priv);
-       else
-               pr_info("%s: mesh disabled\n", dev->name);
+       if (lbs_mesh_activated(priv))
+               lbs_start_mesh(priv);
  
        lbs_debugfs_init_one(priv, dev);
  
@@@ -978,8 -1056,6 +1056,6 @@@ EXPORT_SYMBOL_GPL(lbs_start_card)
  void lbs_stop_card(struct lbs_private *priv)
  {
        struct net_device *dev;
-       struct cmd_ctrl_node *cmdnode;
-       unsigned long flags;
  
        lbs_deb_enter(LBS_DEB_MAIN);
  
  
        lbs_debugfs_remove_one(priv);
        lbs_deinit_mesh(priv);
-       /* Delete the timeout of the currently processing command */
-       del_timer_sync(&priv->command_timer);
-       del_timer_sync(&priv->auto_deepsleep_timer);
-       /* Flush pending command nodes */
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       lbs_deb_main("clearing pending commands\n");
-       list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
-               cmdnode->result = -ENOENT;
-               cmdnode->cmdwaitqwoken = 1;
-               wake_up(&cmdnode->cmdwait_q);
-       }
-       /* Flush the command the card is currently processing */
-       if (priv->cur_cmd) {
-               lbs_deb_main("clearing current command\n");
-               priv->cur_cmd->result = -ENOENT;
-               priv->cur_cmd->cmdwaitqwoken = 1;
-               wake_up(&priv->cur_cmd->cmdwait_q);
-       }
-       lbs_deb_main("done clearing commands\n");
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
        unregister_netdev(dev);
  
  out:
@@@ -1036,7 -1088,7 +1088,7 @@@ void lbs_queue_event(struct lbs_privat
  
        kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32));
  
-       wake_up_interruptible(&priv->waitq);
+       wake_up(&priv->waitq);
  
        spin_unlock_irqrestore(&priv->driver_lock, flags);
        lbs_deb_leave(LBS_DEB_THREAD);
@@@ -1054,7 -1106,7 +1106,7 @@@ void lbs_notify_command_response(struc
        BUG_ON(resp_idx > 1);
        priv->resp_idx = resp_idx;
  
-       wake_up_interruptible(&priv->waitq);
+       wake_up(&priv->waitq);
  
        lbs_deb_leave(LBS_DEB_THREAD);
  }
@@@ -129,6 -129,19 +129,19 @@@ static int lbs_mesh_config(struct lbs_p
        return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
  }
  
+ int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
+ {
+       return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
+ }
+ static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
+ {
+       struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
+       if (mesh_wdev->channel)
+               return mesh_wdev->channel->hw_value;
+       else
+               return 1;
+ }
  
  /***************************************************************************
   * Mesh sysfs support
@@@ -812,7 -825,6 +825,6 @@@ static void lbs_persist_config_remove(s
   */
  int lbs_init_mesh(struct lbs_private *priv)
  {
-       struct net_device *dev = priv->dev;
        int ret = 0;
  
        lbs_deb_enter(LBS_DEB_MESH);
                   useful */
  
                priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
-               if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
-                                   priv->channel)) {
+               if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
                        priv->mesh_tlv = TLV_TYPE_MESH_ID;
-                       if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
-                                           priv->channel))
+                       if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
                                priv->mesh_tlv = 0;
                }
        } else
                 * 0x100+37; Do not invoke command with old TLV.
                 */
                priv->mesh_tlv = TLV_TYPE_MESH_ID;
-               if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
-                                   priv->channel))
+               if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
                        priv->mesh_tlv = 0;
        }
  
        /* Stop meshing until interface is brought up */
-       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
+       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
  
        if (priv->mesh_tlv) {
                sprintf(priv->mesh_ssid, "mesh");
                priv->mesh_ssid_len = 4;
-               lbs_add_mesh(priv);
-               if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
-                       netdev_err(dev, "cannot register lbs_mesh attribute\n");
                ret = 1;
        }
  
        return ret;
  }
  
+ void lbs_start_mesh(struct lbs_private *priv)
+ {
+       lbs_add_mesh(priv);
+       if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
+               netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
+ }
  
  int lbs_deinit_mesh(struct lbs_private *priv)
  {
@@@ -904,7 -914,8 +914,8 @@@ static int lbs_mesh_stop(struct net_dev
        struct lbs_private *priv = dev->ml_priv;
  
        lbs_deb_enter(LBS_DEB_MESH);
-       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
+       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
+               lbs_mesh_get_channel(priv));
  
        spin_lock_irq(&priv->driver_lock);
  
  
        spin_unlock_irq(&priv->driver_lock);
  
-       schedule_work(&priv->mcast_work);
+       lbs_update_mcast(priv);
+       if (!lbs_iface_active(priv))
+               lbs_stop_iface(priv);
  
        lbs_deb_leave(LBS_DEB_MESH);
        return 0;
@@@ -931,6 -944,11 +944,11 @@@ static int lbs_mesh_dev_open(struct net
        int ret = 0;
  
        lbs_deb_enter(LBS_DEB_NET);
+       if (!priv->iface_running) {
+               ret = lbs_start_iface(priv);
+               if (ret)
+                       goto out;
+       }
  
        spin_lock_irq(&priv->driver_lock);
  
  
        spin_unlock_irq(&priv->driver_lock);
  
-       ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel);
+       ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+               lbs_mesh_get_channel(priv));
  
  out:
        lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
@@@ -959,7 -978,7 +978,7 @@@ static const struct net_device_ops mesh
        .ndo_stop               = lbs_mesh_stop,
        .ndo_start_xmit         = lbs_hard_start_xmit,
        .ndo_set_mac_address    = lbs_set_mac_address,
 -      .ndo_set_multicast_list = lbs_set_multicast_list,
 +      .ndo_set_rx_mode        = lbs_set_multicast_list,
  };
  
  /**
  static int lbs_add_mesh(struct lbs_private *priv)
  {
        struct net_device *mesh_dev = NULL;
+       struct wireless_dev *mesh_wdev;
        int ret = 0;
  
        lbs_deb_enter(LBS_DEB_MESH);
  
        /* Allocate a virtual mesh device */
+       mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+       if (!mesh_wdev) {
+               lbs_deb_mesh("init mshX wireless device failed\n");
+               ret = -ENOMEM;
+               goto done;
+       }
        mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
        if (!mesh_dev) {
                lbs_deb_mesh("init mshX device failed\n");
                ret = -ENOMEM;
-               goto done;
+               goto err_free_wdev;
        }
+       mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
+       mesh_wdev->wiphy = priv->wdev->wiphy;
+       mesh_wdev->netdev = mesh_dev;
        mesh_dev->ml_priv = priv;
+       mesh_dev->ieee80211_ptr = mesh_wdev;
        priv->mesh_dev = mesh_dev;
  
        mesh_dev->netdev_ops = &mesh_netdev_ops;
        ret = register_netdev(mesh_dev);
        if (ret) {
                pr_err("cannot register mshX virtual interface\n");
-               goto err_free;
+               goto err_free_netdev;
        }
  
        ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
  err_unregister:
        unregister_netdev(mesh_dev);
  
- err_free:
+ err_free_netdev:
        free_netdev(mesh_dev);
  
+ err_free_wdev:
+       kfree(mesh_wdev);
  done:
        lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
        return ret;
@@@ -1035,6 -1071,7 +1071,7 @@@ void lbs_remove_mesh(struct lbs_privat
        lbs_persist_config_remove(mesh_dev);
        unregister_netdev(mesh_dev);
        priv->mesh_dev = NULL;
+       kfree(mesh_dev->ieee80211_ptr);
        free_netdev(mesh_dev);
        lbs_deb_leave(LBS_DEB_MESH);
  }
@@@ -627,7 -627,7 +627,7 @@@ static const struct net_device_ops mwif
        .ndo_set_mac_address = mwifiex_set_mac_address,
        .ndo_tx_timeout = mwifiex_tx_timeout,
        .ndo_get_stats = mwifiex_get_stats,
 -      .ndo_set_multicast_list = mwifiex_set_multicast_list,
 +      .ndo_set_rx_mode = mwifiex_set_multicast_list,
  };
  
  /*
@@@ -849,6 -849,7 +849,7 @@@ mwifiex_add_card(void *card, struct sem
  {
        int i;
        struct mwifiex_adapter *adapter;
+       char fmt[64];
  
        if (down_interruptible(sem))
                goto exit_sem_err;
  
        up(sem);
  
+       mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
+       dev_notice(adapter->dev, "driver_version = %s\n", fmt);
        return 0;
  
  err_add_intf:
  #include <linux/mii.h>
  #include <linux/usb.h>
  #include <linux/usb/cdc.h>
- #include <linux/wireless.h>
  #include <linux/ieee80211.h>
  #include <linux/if_arp.h>
  #include <linux/ctype.h>
  #include <linux/spinlock.h>
  #include <linux/slab.h>
- #include <net/iw_handler.h>
  #include <net/cfg80211.h>
  #include <linux/usb/usbnet.h>
  #include <linux/usb/rndis_host.h>
@@@ -3392,7 -3390,7 +3390,7 @@@ static const struct net_device_ops rndi
        .ndo_tx_timeout         = usbnet_tx_timeout,
        .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
 -      .ndo_set_multicast_list = rndis_wlan_set_multicast_list,
 +      .ndo_set_rx_mode        = rndis_wlan_set_multicast_list,
  };
  
  static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
diff --combined net/mac80211/cfg.c
@@@ -62,7 -62,7 +62,7 @@@ static int ieee80211_change_iface(struc
  
        if (type == NL80211_IFTYPE_AP_VLAN &&
            params && params->use_4addr == 0)
 -              rcu_assign_pointer(sdata->u.vlan.sta, NULL);
 +              RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
        else if (type == NL80211_IFTYPE_STATION &&
                 params && params->use_4addr >= 0)
                sdata->u.mgd.use_4addr = params->use_4addr;
@@@ -542,7 -542,7 +542,7 @@@ static int ieee80211_config_beacon(stru
  
        sdata->vif.bss_conf.dtim_period = new->dtim_period;
  
 -      rcu_assign_pointer(sdata->u.ap.beacon, new);
 +      RCU_INIT_POINTER(sdata->u.ap.beacon, new);
  
        synchronize_rcu();
  
@@@ -594,7 -594,7 +594,7 @@@ static int ieee80211_del_beacon(struct 
        if (!old)
                return -ENOENT;
  
 -      rcu_assign_pointer(sdata->u.ap.beacon, NULL);
 +      RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
        synchronize_rcu();
        kfree(old);
  
@@@ -857,7 -857,7 +857,7 @@@ static int ieee80211_change_station(str
                                return -EBUSY;
                        }
  
 -                      rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
 +                      RCU_INIT_POINTER(vlansdata->u.vlan.sta, sta);
                }
  
                sta->sdata = vlansdata;
@@@ -1898,33 -1898,6 +1898,6 @@@ static int ieee80211_mgmt_tx(struct wip
  
        *cookie = (unsigned long) skb;
  
-       if (is_offchan && local->ops->offchannel_tx) {
-               int ret;
-               IEEE80211_SKB_CB(skb)->band = chan->band;
-               mutex_lock(&local->mtx);
-               if (local->hw_offchan_tx_cookie) {
-                       mutex_unlock(&local->mtx);
-                       return -EBUSY;
-               }
-               /* TODO: bitrate control, TX processing? */
-               ret = drv_offchannel_tx(local, skb, chan, channel_type, wait);
-               if (ret == 0)
-                       local->hw_offchan_tx_cookie = *cookie;
-               mutex_unlock(&local->mtx);
-               /*
-                * Allow driver to return 1 to indicate it wants to have the
-                * frame transmitted with a remain_on_channel + regular TX.
-                */
-               if (ret != 1)
-                       return ret;
-       }
        if (is_offchan && local->ops->remain_on_channel) {
                unsigned int duration;
                int ret;
@@@ -2011,18 -1984,6 +1984,6 @@@ static int ieee80211_mgmt_tx_cancel_wai
  
        mutex_lock(&local->mtx);
  
-       if (local->ops->offchannel_tx_cancel_wait &&
-           local->hw_offchan_tx_cookie == cookie) {
-               ret = drv_offchannel_tx_cancel_wait(local);
-               if (!ret)
-                       local->hw_offchan_tx_cookie = 0;
-               mutex_unlock(&local->mtx);
-               return ret;
-       }
        if (local->ops->cancel_remain_on_channel) {
                cookie ^= 2;
                ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
diff --combined net/mac80211/sta_info.c
@@@ -72,7 -72,7 +72,7 @@@ static int sta_info_hash_del(struct iee
        if (!s)
                return -ENOENT;
        if (s == sta) {
 -              rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)],
 +              RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)],
                                   s->hnext);
                return 0;
        }
@@@ -82,7 -82,7 +82,7 @@@
                s = rcu_dereference_protected(s->hnext,
                                        lockdep_is_held(&local->sta_lock));
        if (rcu_access_pointer(s->hnext)) {
 -              rcu_assign_pointer(s->hnext, sta->hnext);
 +              RCU_INIT_POINTER(s->hnext, sta->hnext);
                return 0;
        }
  
@@@ -184,7 -184,7 +184,7 @@@ static void sta_info_hash_add(struct ie
                              struct sta_info *sta)
  {
        sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)];
 -      rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
 +      RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
  }
  
  static void sta_unblock(struct work_struct *wk)
@@@ -330,6 -330,7 +330,7 @@@ static int sta_info_finish_insert(struc
        ieee80211_sta_debugfs_add(sta);
        rate_control_add_sta_debugfs(sta);
  
+       memset(&sinfo, 0, sizeof(sinfo));
        sinfo.filled = 0;
        sinfo.generation = local->sta_generation;
        cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
@@@ -672,7 -673,7 +673,7 @@@ static int __must_check __sta_info_dest
        local->sta_generation++;
  
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 -              rcu_assign_pointer(sdata->u.vlan.sta, NULL);
 +              RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
  
        if (sta->uploaded) {
                if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)