Merge remote-tracking branch 'agust/next' into next
[deliverable/linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / wl_cfg80211.c
index 571f013cebbb0d0a80f32e2351975b659d7d53d1..d7718a5fa2f0323c46458300f417b7dbd6e46b8e 100644 (file)
@@ -202,9 +202,9 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = {
 
 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
  * By default world regulatory domain defined in reg.c puts the flags
- * NL80211_RRF_PASSIVE_SCAN and NL80211_RRF_NO_IBSS for 5GHz channels (for
- * 36..48 and 149..165). With respect to these flags, wpa_supplicant doesn't
- * start p2p operations on 5GHz channels. All the changes in world regulatory
+ * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
+ * With respect to these flags, wpa_supplicant doesn't * start p2p
+ * operations on 5GHz channels. All the changes in world regulatory
  * domain are to be done here.
  */
 static const struct ieee80211_regdomain brcmf_regdom = {
@@ -1095,10 +1095,10 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
                                             BRCMF_C_DISASSOC, NULL, 0);
                if (err) {
                        brcmf_err("WLC_DISASSOC failed (%d)\n", err);
-                       cfg80211_disconnected(vif->wdev.netdev, 0,
-                                             NULL, 0, GFP_KERNEL);
                }
                clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
+               cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
+
        }
        clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
        clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
@@ -1758,6 +1758,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
                return -EIO;
 
        clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
+       cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
 
        memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
        scbval.val = cpu_to_le32(reason_code);
@@ -2556,8 +2557,8 @@ brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
                ch_bss.band == ch_bss_info_le.band &&
                bss_info_le->SSID_len == bss->SSID_len &&
                !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
-               if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
-                       (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
+               if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
+                       (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
                        s16 bss_rssi = le16_to_cpu(bss->RSSI);
                        s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
 
@@ -2566,13 +2567,13 @@ brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
                        */
                        if (bss_info_rssi > bss_rssi)
                                bss->RSSI = bss_info_le->RSSI;
-               } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
-                       (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
+               } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
+                       (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
                        /* preserve the on-channel rssi measurement
                        * if the new measurement is off channel
                        */
                        bss->RSSI = bss_info_le->RSSI;
-                       bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
+                       bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
                }
                return 1;
        }
@@ -2988,6 +2989,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
                }
 
                set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
+               cfg->escan_info.run = brcmf_run_escan;
                err = brcmf_do_escan(cfg, wiphy, ifp, request);
                if (err) {
                        clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
@@ -3973,11 +3975,12 @@ brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
 
 static int
 brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
-                      struct ieee80211_channel *chan, bool offchan,
-                      unsigned int wait, const u8 *buf, size_t len,
-                      bool no_cck, bool dont_wait_for_ack, u64 *cookie)
+                      struct cfg80211_mgmt_tx_params *params, u64 *cookie)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct ieee80211_channel *chan = params->chan;
+       const u8 *buf = params->buf;
+       size_t len = params->len;
        const struct ieee80211_mgmt *mgmt;
        struct brcmf_cfg80211_vif *vif;
        s32 err = 0;
@@ -4341,7 +4344,7 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
        wiphy->max_remain_on_channel_duration = 5000;
        brcmf_wiphy_pno_params(wiphy);
        brcmf_dbg(INFO, "Registering custom regulatory\n");
-       wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+       wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
        wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
        err = wiphy_register(wiphy);
        if (err < 0) {
@@ -4358,9 +4361,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
 {
        struct brcmf_cfg80211_vif *vif;
 
-       if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
-               return ERR_PTR(-ENOSPC);
-
        brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
                  sizeof(*vif));
        vif = kzalloc(sizeof(*vif), GFP_KERNEL);
@@ -4377,21 +4377,25 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
        brcmf_init_prof(&vif->profile);
 
        list_add_tail(&vif->list, &cfg->vif_list);
-       cfg->vif_cnt++;
        return vif;
 }
 
-void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
-                   struct brcmf_cfg80211_vif *vif)
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
 {
        list_del(&vif->list);
-       cfg->vif_cnt--;
-
        kfree(vif);
-       if (!cfg->vif_cnt) {
-               wiphy_unregister(cfg->wiphy);
-               wiphy_free(cfg->wiphy);
-       }
+}
+
+void brcmf_cfg80211_free_netdev(struct net_device *ndev)
+{
+       struct brcmf_cfg80211_vif *vif;
+       struct brcmf_if *ifp;
+
+       ifp = netdev_priv(ndev);
+       vif = ifp->vif;
+
+       brcmf_free_vif(vif);
+       free_netdev(ndev);
 }
 
 static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
@@ -4978,20 +4982,20 @@ cfg80211_p2p_attach_out:
        wl_deinit_priv(cfg);
 
 cfg80211_attach_out:
-       brcmf_free_vif(cfg, vif);
+       brcmf_free_vif(vif);
        return NULL;
 }
 
 void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
 {
-       struct brcmf_cfg80211_vif *vif;
-       struct brcmf_cfg80211_vif *tmp;
+       if (!cfg)
+               return;
 
-       wl_deinit_priv(cfg);
+       WARN_ON(!list_empty(&cfg->vif_list));
+       wiphy_unregister(cfg->wiphy);
        brcmf_btcoex_detach(cfg);
-       list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
-               brcmf_free_vif(cfg, vif);
-       }
+       wl_deinit_priv(cfg);
+       wiphy_free(cfg->wiphy);
 }
 
 static s32
@@ -5086,7 +5090,8 @@ dongle_scantime_out:
 }
 
 
-static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
+static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
+                                  u32 bw_cap[])
 {
        struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
        struct ieee80211_channel *band_chan_arr;
@@ -5099,7 +5104,6 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
        enum ieee80211_band band;
        u32 channel;
        u32 *n_cnt;
-       bool ht40_allowed;
        u32 index;
        u32 ht40_flag;
        bool update;
@@ -5132,18 +5136,17 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
                        array_size = ARRAY_SIZE(__wl_2ghz_channels);
                        n_cnt = &__wl_band_2ghz.n_channels;
                        band = IEEE80211_BAND_2GHZ;
-                       ht40_allowed = (bw_cap == WLC_N_BW_40ALL);
                } else if (ch.band == BRCMU_CHAN_BAND_5G) {
                        band_chan_arr = __wl_5ghz_a_channels;
                        array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
                        n_cnt = &__wl_band_5ghz_a.n_channels;
                        band = IEEE80211_BAND_5GHZ;
-                       ht40_allowed = !(bw_cap == WLC_N_BW_20ALL);
                } else {
-                       brcmf_err("Invalid channel Sepc. 0x%x.\n", ch.chspec);
+                       brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
                        continue;
                }
-               if (!ht40_allowed && ch.bw == BRCMU_CHAN_BW_40)
+               if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) &&
+                   ch.bw == BRCMU_CHAN_BW_40)
                        continue;
                update = false;
                for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
@@ -5161,7 +5164,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
                                ieee80211_channel_to_frequency(ch.chnum, band);
                        band_chan_arr[index].hw_value = ch.chnum;
 
-                       if (ch.bw == BRCMU_CHAN_BW_40 && ht40_allowed) {
+                       brcmf_err("channel %d: f=%d bw=%d sb=%d\n",
+                                 ch.chnum, band_chan_arr[index].center_freq,
+                                 ch.bw, ch.sb);
+                       if (ch.bw == BRCMU_CHAN_BW_40) {
                                /* assuming the order is HT20, HT40 Upper,
                                 * HT40 lower from chanspecs
                                 */
@@ -5197,10 +5203,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
                                        if (channel & WL_CHAN_RADAR)
                                                band_chan_arr[index].flags |=
                                                        (IEEE80211_CHAN_RADAR |
-                                                       IEEE80211_CHAN_NO_IBSS);
+                                                       IEEE80211_CHAN_NO_IR);
                                        if (channel & WL_CHAN_PASSIVE)
                                                band_chan_arr[index].flags |=
-                                                   IEEE80211_CHAN_PASSIVE_SCAN;
+                                                   IEEE80211_CHAN_NO_IR;
                                }
                        }
                        if (!update)
@@ -5212,6 +5218,46 @@ exit:
        return err;
 }
 
+static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
+{
+       u32 band, mimo_bwcap;
+       int err;
+
+       band = WLC_BAND_2G;
+       err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
+       if (!err) {
+               bw_cap[IEEE80211_BAND_2GHZ] = band;
+               band = WLC_BAND_5G;
+               err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
+               if (!err) {
+                       bw_cap[IEEE80211_BAND_5GHZ] = band;
+                       return;
+               }
+               WARN_ON(1);
+               return;
+       }
+       brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
+       mimo_bwcap = 0;
+       err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
+       if (err)
+               /* assume 20MHz if firmware does not give a clue */
+               mimo_bwcap = WLC_N_BW_20ALL;
+
+       switch (mimo_bwcap) {
+       case WLC_N_BW_40ALL:
+               bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
+               /* fall-thru */
+       case WLC_N_BW_20IN2G_40IN5G:
+               bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
+               /* fall-thru */
+       case WLC_N_BW_20ALL:
+               bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
+               bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
+               break;
+       default:
+               brcmf_err("invalid mimo_bw_cap value\n");
+       }
+}
 
 static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
 {
@@ -5220,13 +5266,13 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        s32 phy_list;
        u32 band_list[3];
        u32 nmode;
-       u32 bw_cap = 0;
+       u32 bw_cap[2] = { 0, 0 };
        s8 phy;
        s32 err;
        u32 nband;
        s32 i;
-       struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
-       s32 index;
+       struct ieee80211_supported_band *bands[2] = { NULL, NULL };
+       struct ieee80211_supported_band *band;
 
        err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
                                     &phy_list, sizeof(phy_list));
@@ -5252,11 +5298,10 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        if (err) {
                brcmf_err("nmode error (%d)\n", err);
        } else {
-               err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &bw_cap);
-               if (err)
-                       brcmf_err("mimo_bw_cap error (%d)\n", err);
+               brcmf_get_bwcap(ifp, bw_cap);
        }
-       brcmf_dbg(INFO, "nmode=%d, mimo_bw_cap=%d\n", nmode, bw_cap);
+       brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
+                 bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
 
        err = brcmf_construct_reginfo(cfg, bw_cap);
        if (err) {
@@ -5265,40 +5310,33 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        }
 
        nband = band_list[0];
-       memset(bands, 0, sizeof(bands));
 
        for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
-               index = -1;
+               band = NULL;
                if ((band_list[i] == WLC_BAND_5G) &&
-                   (__wl_band_5ghz_a.n_channels > 0)) {
-                       index = IEEE80211_BAND_5GHZ;
-                       bands[index] = &__wl_band_5ghz_a;
-                       if ((bw_cap == WLC_N_BW_40ALL) ||
-                           (bw_cap == WLC_N_BW_20IN2G_40IN5G))
-                               bands[index]->ht_cap.cap |=
-                                                       IEEE80211_HT_CAP_SGI_40;
-               } else if ((band_list[i] == WLC_BAND_2G) &&
-                          (__wl_band_2ghz.n_channels > 0)) {
-                       index = IEEE80211_BAND_2GHZ;
-                       bands[index] = &__wl_band_2ghz;
-                       if (bw_cap == WLC_N_BW_40ALL)
-                               bands[index]->ht_cap.cap |=
-                                                       IEEE80211_HT_CAP_SGI_40;
-               }
+                   (__wl_band_5ghz_a.n_channels > 0))
+                       band = &__wl_band_5ghz_a;
+               else if ((band_list[i] == WLC_BAND_2G) &&
+                        (__wl_band_2ghz.n_channels > 0))
+                       band = &__wl_band_2ghz;
+               else
+                       continue;
 
-               if ((index >= 0) && nmode) {
-                       bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
-                       bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
-                       bands[index]->ht_cap.ht_supported = true;
-                       bands[index]->ht_cap.ampdu_factor =
-                                               IEEE80211_HT_MAX_AMPDU_64K;
-                       bands[index]->ht_cap.ampdu_density =
-                                               IEEE80211_HT_MPDU_DENSITY_16;
-                       /* An HT shall support all EQM rates for one spatial
-                        * stream
-                        */
-                       bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
+               if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
+                       band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+                       band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
                }
+               band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+               band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
+               band->ht_cap.ht_supported = true;
+               band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+               band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+               /* An HT shall support all EQM rates for one spatial
+                * stream
+                */
+               band->ht_cap.mcs.rx_mask[0] = 0xff;
+               band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+               bands[band->band] = band;
        }
 
        wiphy = cfg_to_wiphy(cfg);
This page took 0.031166 seconds and 5 git commands to generate.