This prepares some place for backporting extra patches.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
SVN-Revision: 46735
--- /dev/null
+From: Pontus Fuchs <pontusf@broadcom.com>
+Date: Thu, 11 Jun 2015 00:12:17 +0200
+Subject: [PATCH] brcmfmac: Check if firmware supports p2p
+
+Add a feature flag to reflect the firmware's p2p capability.
+
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Signed-off-by: Pontus Fuchs <pontusf@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
+@@ -129,6 +129,7 @@ void brcmf_feat_attach(struct brcmf_pub
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
+ if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID)
+ brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
++ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_P2P, "p2p");
+
+ /* set chip related quirks */
+ switch (drvr->bus_if->chip) {
+--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
+@@ -23,12 +23,14 @@
+ * MCHAN: multi-channel for concurrent P2P.
+ * PNO: preferred network offload.
+ * WOWL: Wake-On-WLAN.
++ * P2P: peer-to-peer
+ */
+ #define BRCMF_FEAT_LIST \
+ BRCMF_FEAT_DEF(MBSS) \
+ BRCMF_FEAT_DEF(MCHAN) \
+ BRCMF_FEAT_DEF(PNO) \
+- BRCMF_FEAT_DEF(WOWL)
++ BRCMF_FEAT_DEF(WOWL) \
++ BRCMF_FEAT_DEF(P2P)
+ /*
+ * Quirks:
+ *
--- /dev/null
+From: Pontus Fuchs <pontusf@broadcom.com>
+Date: Thu, 11 Jun 2015 00:12:18 +0200
+Subject: [PATCH] brcmfmac: Build wiphy mode and interface combinations
+ dynamically
+
+Switch from using semi hard coded interface combinations. This makes
+it easier to announce what the firmware actually supports. This fixes
+the case where brcmfmac announces p2p but the firmware doesn't
+support it.
+
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Signed-off-by: Pontus Fuchs <pontusf@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -52,8 +52,6 @@
+ #define BRCMF_PNO_SCAN_COMPLETE 1
+ #define BRCMF_PNO_SCAN_INCOMPLETE 0
+
+-#define BRCMF_IFACE_MAX_CNT 3
+-
+ #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
+ #define WPA_OUI_TYPE 1
+ #define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
+@@ -5639,53 +5637,6 @@ static int brcmf_setup_wiphybands(struct
+ return 0;
+ }
+
+-static const struct ieee80211_iface_limit brcmf_iface_limits_mbss[] = {
+- {
+- .max = 1,
+- .types = BIT(NL80211_IFTYPE_STATION) |
+- BIT(NL80211_IFTYPE_ADHOC)
+- },
+- {
+- .max = 4,
+- .types = BIT(NL80211_IFTYPE_AP)
+- },
+- {
+- .max = 1,
+- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+- BIT(NL80211_IFTYPE_P2P_GO)
+- },
+- {
+- .max = 1,
+- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+- }
+-};
+-
+-static const struct ieee80211_iface_limit brcmf_iface_limits_sbss[] = {
+- {
+- .max = 2,
+- .types = BIT(NL80211_IFTYPE_STATION) |
+- BIT(NL80211_IFTYPE_ADHOC) |
+- BIT(NL80211_IFTYPE_AP)
+- },
+- {
+- .max = 1,
+- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+- BIT(NL80211_IFTYPE_P2P_GO)
+- },
+- {
+- .max = 1,
+- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+- }
+-};
+-static struct ieee80211_iface_combination brcmf_iface_combos[] = {
+- {
+- .max_interfaces = BRCMF_IFACE_MAX_CNT,
+- .num_different_channels = 1,
+- .n_limits = ARRAY_SIZE(brcmf_iface_limits_sbss),
+- .limits = brcmf_iface_limits_sbss,
+- }
+-};
+-
+ static const struct ieee80211_txrx_stypes
+ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_STATION] = {
+@@ -5715,6 +5666,67 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
+ }
+ };
+
++static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
++{
++ struct ieee80211_iface_combination *combo = NULL;
++ struct ieee80211_iface_limit *limits = NULL;
++ int i = 0, max_iface_cnt;
++
++ combo = kzalloc(sizeof(*combo), GFP_KERNEL);
++ if (!combo)
++ goto err;
++
++ limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL);
++ if (!limits)
++ goto err;
++
++ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
++ BIT(NL80211_IFTYPE_ADHOC) |
++ BIT(NL80211_IFTYPE_AP);
++
++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
++ combo->num_different_channels = 2;
++ else
++ combo->num_different_channels = 1;
++
++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
++ limits[i].max = 1;
++ limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++ limits[i].max = 4;
++ limits[i++].types = BIT(NL80211_IFTYPE_AP);
++ max_iface_cnt = 5;
++ } else {
++ limits[i].max = 2;
++ limits[i++].types = BIT(NL80211_IFTYPE_STATION) |
++ BIT(NL80211_IFTYPE_AP);
++ max_iface_cnt = 2;
++ }
++
++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) {
++ wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
++ BIT(NL80211_IFTYPE_P2P_GO) |
++ BIT(NL80211_IFTYPE_P2P_DEVICE);
++ limits[i].max = 1;
++ limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
++ BIT(NL80211_IFTYPE_P2P_GO);
++ limits[i].max = 1;
++ limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
++ max_iface_cnt += 2;
++ }
++ combo->max_interfaces = max_iface_cnt;
++ combo->limits = limits;
++ combo->n_limits = i;
++
++ wiphy->iface_combinations = combo;
++ wiphy->n_iface_combinations = 1;
++ return 0;
++
++err:
++ kfree(limits);
++ kfree(combo);
++ return -ENOMEM;
++}
++
+ static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
+ {
+ /* scheduled scan settings */
+@@ -5745,7 +5757,6 @@ static void brcmf_wiphy_wowl_params(stru
+ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
+ {
+ struct ieee80211_supported_band *band;
+- struct ieee80211_iface_combination ifc_combo;
+ __le32 bandlist[3];
+ u32 n_bands;
+ int err, i;
+@@ -5753,24 +5764,11 @@ static int brcmf_setup_wiphy(struct wiph
+ wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
+ wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
+ wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+- BIT(NL80211_IFTYPE_ADHOC) |
+- BIT(NL80211_IFTYPE_AP) |
+- BIT(NL80211_IFTYPE_P2P_CLIENT) |
+- BIT(NL80211_IFTYPE_P2P_GO) |
+- BIT(NL80211_IFTYPE_P2P_DEVICE);
+- /* need VSDB firmware feature for concurrent channels */
+- ifc_combo = brcmf_iface_combos[0];
+- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
+- ifc_combo.num_different_channels = 2;
+- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
+- ifc_combo.n_limits = ARRAY_SIZE(brcmf_iface_limits_mbss),
+- ifc_combo.limits = brcmf_iface_limits_mbss;
+- }
+- wiphy->iface_combinations = kmemdup(&ifc_combo,
+- sizeof(ifc_combo),
+- GFP_KERNEL);
+- wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
++
++ err = brcmf_setup_ifmodes(wiphy, ifp);
++ if (err)
++ return err;
++
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wiphy->cipher_suites = __wl_cipher_suites;
+ wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
+@@ -6035,6 +6033,8 @@ static void brcmf_free_wiphy(struct wiph
+ if (!wiphy)
+ return;
+
++ if (wiphy->iface_combinations)
++ kfree(wiphy->iface_combinations->limits);
+ kfree(wiphy->iface_combinations);
+ if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
+ kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
--- /dev/null
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 11 Jun 2015 00:12:19 +0200
+Subject: [PATCH] brcmfmac: rework .get_station() callback
+
+The .get_station() cfg80211 callback is used in several scenarios. In
+managed mode it can obtain information about the access-point and its
+BSS parameters. In managed mode it can also obtain information about
+TDLS peers. In AP mode it can obtain information about connected
+clients.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -2395,27 +2395,80 @@ brcmf_cfg80211_reconfigure_wep(struct br
+ brcmf_err("set wsec error (%d)\n", err);
+ }
+
++static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
++{
++ struct nl80211_sta_flag_update *sfu;
++
++ brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
++ si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
++ sfu = &si->sta_flags;
++ sfu->mask = BIT(NL80211_STA_FLAG_WME) |
++ BIT(NL80211_STA_FLAG_AUTHENTICATED) |
++ BIT(NL80211_STA_FLAG_ASSOCIATED) |
++ BIT(NL80211_STA_FLAG_AUTHORIZED);
++ if (fw_sta_flags & BRCMF_STA_WME)
++ sfu->set |= BIT(NL80211_STA_FLAG_WME);
++ if (fw_sta_flags & BRCMF_STA_AUTHE)
++ sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
++ if (fw_sta_flags & BRCMF_STA_ASSOC)
++ sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
++ if (fw_sta_flags & BRCMF_STA_AUTHO)
++ sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
++}
++
++static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
++{
++ struct {
++ __le32 len;
++ struct brcmf_bss_info_le bss_le;
++ } *buf;
++ u16 capability;
++ int err;
++
++ buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
++ if (!buf)
++ return;
++
++ buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
++ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
++ WL_BSS_INFO_MAX);
++ if (err) {
++ brcmf_err("Failed to get bss info (%d)\n", err);
++ return;
++ }
++ si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
++ si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
++ si->bss_param.dtim_period = buf->bss_le.dtim_period;
++ capability = le16_to_cpu(buf->bss_le.capability);
++ if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
++ si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
++ if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
++ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
++ if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
++ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
++}
++
+ static s32
+ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
+ const u8 *mac, struct station_info *sinfo)
+ {
+ struct brcmf_if *ifp = netdev_priv(ndev);
+- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+- struct brcmf_scb_val_le scb_val;
+- int rssi;
+- s32 rate;
+ s32 err = 0;
+- u8 *bssid = profile->bssid;
+ struct brcmf_sta_info_le sta_info_le;
+- u32 beacon_period;
+- u32 dtim_period;
++ u32 sta_flags;
++ u32 is_tdls_peer;
+
+ brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+- if (brcmf_is_apmode(ifp->vif)) {
+- memcpy(&sta_info_le, mac, ETH_ALEN);
++ memset(&sta_info_le, 0, sizeof(sta_info_le));
++ memcpy(&sta_info_le, mac, ETH_ALEN);
++ err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
++ &sta_info_le,
++ sizeof(sta_info_le));
++ is_tdls_peer = !err;
++ if (err) {
+ err = brcmf_fil_iovar_data_get(ifp, "sta_info",
+ &sta_info_le,
+ sizeof(sta_info_le));
+@@ -2423,73 +2476,48 @@ brcmf_cfg80211_get_station(struct wiphy
+ brcmf_err("GET STA INFO failed, %d\n", err);
+ goto done;
+ }
+- sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
+- sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
+- if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
+- sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
+- sinfo->connected_time = le32_to_cpu(sta_info_le.in);
+- }
+- brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
+- sinfo->inactive_time, sinfo->connected_time);
+- } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
+- if (memcmp(mac, bssid, ETH_ALEN)) {
+- brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
+- mac, bssid);
+- err = -ENOENT;
+- goto done;
+- }
+- /* Report the current tx rate */
+- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
+- if (err) {
+- brcmf_err("Could not get rate (%d)\n", err);
+- goto done;
+- } else {
++ }
++ brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
++ sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
++ sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
++ sta_flags = le32_to_cpu(sta_info_le.flags);
++ brcmf_convert_sta_flags(sta_flags, sinfo);
++ sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
++ if (is_tdls_peer)
++ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
++ else
++ sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
++ if (sta_flags & BRCMF_STA_ASSOC) {
++ sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
++ sinfo->connected_time = le32_to_cpu(sta_info_le.in);
++ brcmf_fill_bss_param(ifp, sinfo);
++ }
++ if (sta_flags & BRCMF_STA_SCBSTATS) {
++ sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
++ sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
++ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
++ sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
++ sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
++ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
++ sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
++ sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
++ if (sinfo->tx_packets) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
+- sinfo->txrate.legacy = rate * 5;
+- brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
++ sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate);
++ sinfo->txrate.legacy /= 100;
+ }
+-
+- if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
+- &ifp->vif->sme_state)) {
+- memset(&scb_val, 0, sizeof(scb_val));
+- err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
+- &scb_val, sizeof(scb_val));
+- if (err) {
+- brcmf_err("Could not get rssi (%d)\n", err);
+- goto done;
+- } else {
+- rssi = le32_to_cpu(scb_val.val);
+- sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
+- sinfo->signal = rssi;
+- brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
+- }
+- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
+- &beacon_period);
+- if (err) {
+- brcmf_err("Could not get beacon period (%d)\n",
+- err);
+- goto done;
+- } else {
+- sinfo->bss_param.beacon_interval =
+- beacon_period;
+- brcmf_dbg(CONN, "Beacon peroid %d\n",
+- beacon_period);
+- }
+- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
+- &dtim_period);
+- if (err) {
+- brcmf_err("Could not get DTIM period (%d)\n",
+- err);
+- goto done;
+- } else {
+- sinfo->bss_param.dtim_period = dtim_period;
+- brcmf_dbg(CONN, "DTIM peroid %d\n",
+- dtim_period);
+- }
+- sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
++ if (sinfo->rx_packets) {
++ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
++ sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate);
++ sinfo->rxrate.legacy /= 100;
++ }
++ if (le16_to_cpu(sta_info_le.ver) >= 4) {
++ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
++ sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
++ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
++ sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
+ }
+- } else
+- err = -EPERM;
++ }
+ done:
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
+@@ -32,7 +32,11 @@
+ #define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */
+ #define BRCMF_BSS_RSSI_ON_CHANNEL 0x0002
+
+-#define BRCMF_STA_ASSOC 0x10 /* Associated */
++#define BRCMF_STA_WME 0x00000002 /* WMM association */
++#define BRCMF_STA_AUTHE 0x00000008 /* Authenticated */
++#define BRCMF_STA_ASSOC 0x00000010 /* Associated */
++#define BRCMF_STA_AUTHO 0x00000020 /* Authorized */
++#define BRCMF_STA_SCBSTATS 0x00004000 /* Per STA debug stats */
+
+ /* size of brcmf_scan_params not including variable length array */
+ #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
+@@ -113,6 +117,7 @@
+ #define BRCMF_WOWL_MAXPATTERNSIZE 128
+
+ #define BRCMF_COUNTRY_BUF_SZ 4
++#define BRCMF_ANT_MAX 4
+
+ /* join preference types for join_pref iovar */
+ enum brcmf_join_pref_types {
+@@ -456,25 +461,61 @@ struct brcmf_channel_info_le {
+ };
+
+ struct brcmf_sta_info_le {
+- __le16 ver; /* version of this struct */
+- __le16 len; /* length in bytes of this structure */
+- __le16 cap; /* sta's advertised capabilities */
+- __le32 flags; /* flags defined below */
+- __le32 idle; /* time since data pkt rx'd from sta */
+- u8 ea[ETH_ALEN]; /* Station address */
+- __le32 count; /* # rates in this set */
+- u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */
++ __le16 ver; /* version of this struct */
++ __le16 len; /* length in bytes of this structure */
++ __le16 cap; /* sta's advertised capabilities */
++ __le32 flags; /* flags defined below */
++ __le32 idle; /* time since data pkt rx'd from sta */
++ u8 ea[ETH_ALEN]; /* Station address */
++ __le32 count; /* # rates in this set */
++ u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */
+ /* w/hi bit set if basic */
+- __le32 in; /* seconds elapsed since associated */
+- __le32 listen_interval_inms; /* Min Listen interval in ms for STA */
+- __le32 tx_pkts; /* # of packets transmitted */
+- __le32 tx_failures; /* # of packets failed */
+- __le32 rx_ucast_pkts; /* # of unicast packets received */
+- __le32 rx_mcast_pkts; /* # of multicast packets received */
+- __le32 tx_rate; /* Rate of last successful tx frame */
+- __le32 rx_rate; /* Rate of last successful rx frame */
+- __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
+- __le32 rx_decrypt_failures; /* # of packet decrypted failed */
++ __le32 in; /* seconds elapsed since associated */
++ __le32 listen_interval_inms; /* Min Listen interval in ms for STA */
++ __le32 tx_pkts; /* # of packets transmitted */
++ __le32 tx_failures; /* # of packets failed */
++ __le32 rx_ucast_pkts; /* # of unicast packets received */
++ __le32 rx_mcast_pkts; /* # of multicast packets received */
++ __le32 tx_rate; /* Rate of last successful tx frame */
++ __le32 rx_rate; /* Rate of last successful rx frame */
++ __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
++ __le32 rx_decrypt_failures; /* # of packet decrypted failed */
++ __le32 tx_tot_pkts; /* # of tx pkts (ucast + mcast) */
++ __le32 rx_tot_pkts; /* # of data packets recvd (uni + mcast) */
++ __le32 tx_mcast_pkts; /* # of mcast pkts txed */
++ __le64 tx_tot_bytes; /* data bytes txed (ucast + mcast) */
++ __le64 rx_tot_bytes; /* data bytes recvd (ucast + mcast) */
++ __le64 tx_ucast_bytes; /* data bytes txed (ucast) */
++ __le64 tx_mcast_bytes; /* # data bytes txed (mcast) */
++ __le64 rx_ucast_bytes; /* data bytes recvd (ucast) */
++ __le64 rx_mcast_bytes; /* data bytes recvd (mcast) */
++ s8 rssi[BRCMF_ANT_MAX]; /* per antenna rssi */
++ s8 nf[BRCMF_ANT_MAX]; /* per antenna noise floor */
++ __le16 aid; /* association ID */
++ __le16 ht_capabilities; /* advertised ht caps */
++ __le16 vht_flags; /* converted vht flags */
++ __le32 tx_pkts_retry_cnt; /* # of frames where a retry was
++ * exhausted.
++ */
++ __le32 tx_pkts_retry_exhausted; /* # of user frames where a retry
++ * was exhausted
++ */
++ s8 rx_lastpkt_rssi[BRCMF_ANT_MAX]; /* Per antenna RSSI of last
++ * received data frame.
++ */
++ /* TX WLAN retry/failure statistics:
++ * Separated for host requested frames and locally generated frames.
++ * Include unicast frame only where the retries/failures can be counted.
++ */
++ __le32 tx_pkts_total; /* # user frames sent successfully */
++ __le32 tx_pkts_retries; /* # user frames retries */
++ __le32 tx_pkts_fw_total; /* # FW generated sent successfully */
++ __le32 tx_pkts_fw_retries; /* # retries for FW generated frames */
++ __le32 tx_pkts_fw_retry_exhausted; /* # FW generated where a retry
++ * was exhausted
++ */
++ __le32 rx_pkts_retried; /* # rx with retry bit set */
++ __le32 tx_rate_fallback; /* lowest fallback TX rate */
+ };
+
+ struct brcmf_chanspec_list {
--- /dev/null
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 11 Jun 2015 00:12:20 +0200
+Subject: [PATCH] brcmfmac: have sdio return -EIO when device communication
+ is not possible
+
+The bus interface functions txctl and rxctl may be used while the device
+can not be accessed, eg. upon driver .remove() callback. This patch will
+immediately return -EIO when this is the case which speeds up the module
+unload.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+@@ -988,6 +988,7 @@ static void brcmf_sdiod_freezer_detach(s
+
+ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
+ {
++ sdiodev->state = BRCMF_SDIOD_DOWN;
+ if (sdiodev->bus) {
+ brcmf_sdio_remove(sdiodev->bus);
+ sdiodev->bus = NULL;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+@@ -2820,6 +2820,8 @@ static int brcmf_sdio_bus_txdata(struct
+ struct brcmf_sdio *bus = sdiodev->bus;
+
+ brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);
++ if (sdiodev->state != BRCMF_SDIOD_DATA)
++ return -EIO;
+
+ /* Add space for the header */
+ skb_push(pkt, bus->tx_hdrlen);
+@@ -2948,6 +2950,8 @@ brcmf_sdio_bus_txctl(struct device *dev,
+ int ret;
+
+ brcmf_dbg(TRACE, "Enter\n");
++ if (sdiodev->state != BRCMF_SDIOD_DATA)
++ return -EIO;
+
+ /* Send from dpc */
+ bus->ctrl_frame_buf = msg;
+@@ -3238,6 +3242,8 @@ brcmf_sdio_bus_rxctl(struct device *dev,
+ struct brcmf_sdio *bus = sdiodev->bus;
+
+ brcmf_dbg(TRACE, "Enter\n");
++ if (sdiodev->state != BRCMF_SDIOD_DATA)
++ return -EIO;
+
+ /* Wait until control frame is available */
+ timeleft = brcmf_sdio_dcmd_resp_wait(bus, &bus->rxlen, &pending);
--- /dev/null
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Thu, 2 Jul 2015 13:35:05 +0200
+Subject: [PATCH] ath9k: make DMA stop related messages debug-only
+
+A long time ago, ath9k had issues during reset where the DMA engine
+would stay active and could potentially corrupt memory.
+To debug those issues, the driver would print warnings whenever they
+occur.
+
+Nowadays, these issues are gone and the primary cause of these messages
+is if the MAC is stuck during reset or busy processing a long
+transmission. This is fairly harmless, yet these messages continue to
+worry users.
+
+To reduce the number of bogus bug reports, turn these messages into
+debug messages and count their occurence in the "reset" debugfs file.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -765,6 +765,8 @@ static int read_file_reset(struct seq_fi
+ [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
+ [RESET_TYPE_MCI] = "MCI Reset",
+ [RESET_TYPE_CALIBRATION] = "Calibration error",
++ [RESET_TX_DMA_ERROR] = "Tx DMA stop error",
++ [RESET_RX_DMA_ERROR] = "Rx DMA stop error",
+ };
+ int i;
+
+--- a/drivers/net/wireless/ath/ath9k/debug.h
++++ b/drivers/net/wireless/ath/ath9k/debug.h
+@@ -50,6 +50,8 @@ enum ath_reset_type {
+ RESET_TYPE_BEACON_STUCK,
+ RESET_TYPE_MCI,
+ RESET_TYPE_CALIBRATION,
++ RESET_TX_DMA_ERROR,
++ RESET_RX_DMA_ERROR,
+ __RESET_TYPE_MAX
+ };
+
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -496,10 +496,9 @@ bool ath_stoprecv(struct ath_softc *sc)
+
+ if (!(ah->ah_flags & AH_UNPLUGGED) &&
+ unlikely(!stopped)) {
+- ath_err(ath9k_hw_common(sc->sc_ah),
+- "Could not stop RX, we could be "
+- "confusing the DMA engine when we start RX up\n");
+- ATH_DBG_WARN_ON_ONCE(!stopped);
++ ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
++ "Failed to stop Rx DMA\n");
++ RESET_STAT_INC(sc, RESET_RX_DMA_ERROR);
+ }
+ return stopped && !reset;
+ }
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -1896,8 +1896,11 @@ bool ath_drain_all_txq(struct ath_softc
+ npend |= BIT(i);
+ }
+
+- if (npend)
+- ath_err(common, "Failed to stop TX DMA, queues=0x%03x!\n", npend);
++ if (npend) {
++ RESET_STAT_INC(sc, RESET_TX_DMA_ERROR);
++ ath_dbg(common, RESET,
++ "Failed to stop TX DMA, queues=0x%03x!\n", npend);
++ }
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (!ATH_TXQ_SETUP(sc, i))
+++ /dev/null
-From: Pontus Fuchs <pontusf@broadcom.com>
-Date: Thu, 11 Jun 2015 00:12:17 +0200
-Subject: [PATCH] brcmfmac: Check if firmware supports p2p
-
-Add a feature flag to reflect the firmware's p2p capability.
-
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Signed-off-by: Pontus Fuchs <pontusf@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
-@@ -129,6 +129,7 @@ void brcmf_feat_attach(struct brcmf_pub
- brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
- if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID)
- brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
-+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_P2P, "p2p");
-
- /* set chip related quirks */
- switch (drvr->bus_if->chip) {
---- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
-@@ -23,12 +23,14 @@
- * MCHAN: multi-channel for concurrent P2P.
- * PNO: preferred network offload.
- * WOWL: Wake-On-WLAN.
-+ * P2P: peer-to-peer
- */
- #define BRCMF_FEAT_LIST \
- BRCMF_FEAT_DEF(MBSS) \
- BRCMF_FEAT_DEF(MCHAN) \
- BRCMF_FEAT_DEF(PNO) \
-- BRCMF_FEAT_DEF(WOWL)
-+ BRCMF_FEAT_DEF(WOWL) \
-+ BRCMF_FEAT_DEF(P2P)
- /*
- * Quirks:
- *
+++ /dev/null
-From: Pontus Fuchs <pontusf@broadcom.com>
-Date: Thu, 11 Jun 2015 00:12:18 +0200
-Subject: [PATCH] brcmfmac: Build wiphy mode and interface combinations
- dynamically
-
-Switch from using semi hard coded interface combinations. This makes
-it easier to announce what the firmware actually supports. This fixes
-the case where brcmfmac announces p2p but the firmware doesn't
-support it.
-
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Signed-off-by: Pontus Fuchs <pontusf@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-@@ -52,8 +52,6 @@
- #define BRCMF_PNO_SCAN_COMPLETE 1
- #define BRCMF_PNO_SCAN_INCOMPLETE 0
-
--#define BRCMF_IFACE_MAX_CNT 3
--
- #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
- #define WPA_OUI_TYPE 1
- #define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
-@@ -5639,53 +5637,6 @@ static int brcmf_setup_wiphybands(struct
- return 0;
- }
-
--static const struct ieee80211_iface_limit brcmf_iface_limits_mbss[] = {
-- {
-- .max = 1,
-- .types = BIT(NL80211_IFTYPE_STATION) |
-- BIT(NL80211_IFTYPE_ADHOC)
-- },
-- {
-- .max = 4,
-- .types = BIT(NL80211_IFTYPE_AP)
-- },
-- {
-- .max = 1,
-- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
-- BIT(NL80211_IFTYPE_P2P_GO)
-- },
-- {
-- .max = 1,
-- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
-- }
--};
--
--static const struct ieee80211_iface_limit brcmf_iface_limits_sbss[] = {
-- {
-- .max = 2,
-- .types = BIT(NL80211_IFTYPE_STATION) |
-- BIT(NL80211_IFTYPE_ADHOC) |
-- BIT(NL80211_IFTYPE_AP)
-- },
-- {
-- .max = 1,
-- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
-- BIT(NL80211_IFTYPE_P2P_GO)
-- },
-- {
-- .max = 1,
-- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
-- }
--};
--static struct ieee80211_iface_combination brcmf_iface_combos[] = {
-- {
-- .max_interfaces = BRCMF_IFACE_MAX_CNT,
-- .num_different_channels = 1,
-- .n_limits = ARRAY_SIZE(brcmf_iface_limits_sbss),
-- .limits = brcmf_iface_limits_sbss,
-- }
--};
--
- static const struct ieee80211_txrx_stypes
- brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
- [NL80211_IFTYPE_STATION] = {
-@@ -5715,6 +5666,67 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
- }
- };
-
-+static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
-+{
-+ struct ieee80211_iface_combination *combo = NULL;
-+ struct ieee80211_iface_limit *limits = NULL;
-+ int i = 0, max_iface_cnt;
-+
-+ combo = kzalloc(sizeof(*combo), GFP_KERNEL);
-+ if (!combo)
-+ goto err;
-+
-+ limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL);
-+ if (!limits)
-+ goto err;
-+
-+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-+ BIT(NL80211_IFTYPE_ADHOC) |
-+ BIT(NL80211_IFTYPE_AP);
-+
-+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
-+ combo->num_different_channels = 2;
-+ else
-+ combo->num_different_channels = 1;
-+
-+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
-+ limits[i].max = 1;
-+ limits[i++].types = BIT(NL80211_IFTYPE_STATION);
-+ limits[i].max = 4;
-+ limits[i++].types = BIT(NL80211_IFTYPE_AP);
-+ max_iface_cnt = 5;
-+ } else {
-+ limits[i].max = 2;
-+ limits[i++].types = BIT(NL80211_IFTYPE_STATION) |
-+ BIT(NL80211_IFTYPE_AP);
-+ max_iface_cnt = 2;
-+ }
-+
-+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) {
-+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
-+ BIT(NL80211_IFTYPE_P2P_GO) |
-+ BIT(NL80211_IFTYPE_P2P_DEVICE);
-+ limits[i].max = 1;
-+ limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
-+ BIT(NL80211_IFTYPE_P2P_GO);
-+ limits[i].max = 1;
-+ limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
-+ max_iface_cnt += 2;
-+ }
-+ combo->max_interfaces = max_iface_cnt;
-+ combo->limits = limits;
-+ combo->n_limits = i;
-+
-+ wiphy->iface_combinations = combo;
-+ wiphy->n_iface_combinations = 1;
-+ return 0;
-+
-+err:
-+ kfree(limits);
-+ kfree(combo);
-+ return -ENOMEM;
-+}
-+
- static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
- {
- /* scheduled scan settings */
-@@ -5745,7 +5757,6 @@ static void brcmf_wiphy_wowl_params(stru
- static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
- {
- struct ieee80211_supported_band *band;
-- struct ieee80211_iface_combination ifc_combo;
- __le32 bandlist[3];
- u32 n_bands;
- int err, i;
-@@ -5753,24 +5764,11 @@ static int brcmf_setup_wiphy(struct wiph
- wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
- wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
- wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
-- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-- BIT(NL80211_IFTYPE_ADHOC) |
-- BIT(NL80211_IFTYPE_AP) |
-- BIT(NL80211_IFTYPE_P2P_CLIENT) |
-- BIT(NL80211_IFTYPE_P2P_GO) |
-- BIT(NL80211_IFTYPE_P2P_DEVICE);
-- /* need VSDB firmware feature for concurrent channels */
-- ifc_combo = brcmf_iface_combos[0];
-- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
-- ifc_combo.num_different_channels = 2;
-- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
-- ifc_combo.n_limits = ARRAY_SIZE(brcmf_iface_limits_mbss),
-- ifc_combo.limits = brcmf_iface_limits_mbss;
-- }
-- wiphy->iface_combinations = kmemdup(&ifc_combo,
-- sizeof(ifc_combo),
-- GFP_KERNEL);
-- wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
-+
-+ err = brcmf_setup_ifmodes(wiphy, ifp);
-+ if (err)
-+ return err;
-+
- wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
- wiphy->cipher_suites = __wl_cipher_suites;
- wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
-@@ -6035,6 +6033,8 @@ static void brcmf_free_wiphy(struct wiph
- if (!wiphy)
- return;
-
-+ if (wiphy->iface_combinations)
-+ kfree(wiphy->iface_combinations->limits);
- kfree(wiphy->iface_combinations);
- if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
+++ /dev/null
-From: Arend van Spriel <arend@broadcom.com>
-Date: Thu, 11 Jun 2015 00:12:19 +0200
-Subject: [PATCH] brcmfmac: rework .get_station() callback
-
-The .get_station() cfg80211 callback is used in several scenarios. In
-managed mode it can obtain information about the access-point and its
-BSS parameters. In managed mode it can also obtain information about
-TDLS peers. In AP mode it can obtain information about connected
-clients.
-
-Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
-Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-@@ -2395,27 +2395,80 @@ brcmf_cfg80211_reconfigure_wep(struct br
- brcmf_err("set wsec error (%d)\n", err);
- }
-
-+static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
-+{
-+ struct nl80211_sta_flag_update *sfu;
-+
-+ brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
-+ si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
-+ sfu = &si->sta_flags;
-+ sfu->mask = BIT(NL80211_STA_FLAG_WME) |
-+ BIT(NL80211_STA_FLAG_AUTHENTICATED) |
-+ BIT(NL80211_STA_FLAG_ASSOCIATED) |
-+ BIT(NL80211_STA_FLAG_AUTHORIZED);
-+ if (fw_sta_flags & BRCMF_STA_WME)
-+ sfu->set |= BIT(NL80211_STA_FLAG_WME);
-+ if (fw_sta_flags & BRCMF_STA_AUTHE)
-+ sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
-+ if (fw_sta_flags & BRCMF_STA_ASSOC)
-+ sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
-+ if (fw_sta_flags & BRCMF_STA_AUTHO)
-+ sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
-+}
-+
-+static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
-+{
-+ struct {
-+ __le32 len;
-+ struct brcmf_bss_info_le bss_le;
-+ } *buf;
-+ u16 capability;
-+ int err;
-+
-+ buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
-+ if (!buf)
-+ return;
-+
-+ buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
-+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
-+ WL_BSS_INFO_MAX);
-+ if (err) {
-+ brcmf_err("Failed to get bss info (%d)\n", err);
-+ return;
-+ }
-+ si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
-+ si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
-+ si->bss_param.dtim_period = buf->bss_le.dtim_period;
-+ capability = le16_to_cpu(buf->bss_le.capability);
-+ if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
-+ si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
-+ if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
-+ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
-+ if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
-+ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
-+}
-+
- static s32
- brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
- const u8 *mac, struct station_info *sinfo)
- {
- struct brcmf_if *ifp = netdev_priv(ndev);
-- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
-- struct brcmf_scb_val_le scb_val;
-- int rssi;
-- s32 rate;
- s32 err = 0;
-- u8 *bssid = profile->bssid;
- struct brcmf_sta_info_le sta_info_le;
-- u32 beacon_period;
-- u32 dtim_period;
-+ u32 sta_flags;
-+ u32 is_tdls_peer;
-
- brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
-- if (brcmf_is_apmode(ifp->vif)) {
-- memcpy(&sta_info_le, mac, ETH_ALEN);
-+ memset(&sta_info_le, 0, sizeof(sta_info_le));
-+ memcpy(&sta_info_le, mac, ETH_ALEN);
-+ err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
-+ &sta_info_le,
-+ sizeof(sta_info_le));
-+ is_tdls_peer = !err;
-+ if (err) {
- err = brcmf_fil_iovar_data_get(ifp, "sta_info",
- &sta_info_le,
- sizeof(sta_info_le));
-@@ -2423,73 +2476,48 @@ brcmf_cfg80211_get_station(struct wiphy
- brcmf_err("GET STA INFO failed, %d\n", err);
- goto done;
- }
-- sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
-- sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
-- if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
-- sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
-- sinfo->connected_time = le32_to_cpu(sta_info_le.in);
-- }
-- brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
-- sinfo->inactive_time, sinfo->connected_time);
-- } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
-- if (memcmp(mac, bssid, ETH_ALEN)) {
-- brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
-- mac, bssid);
-- err = -ENOENT;
-- goto done;
-- }
-- /* Report the current tx rate */
-- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
-- if (err) {
-- brcmf_err("Could not get rate (%d)\n", err);
-- goto done;
-- } else {
-+ }
-+ brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
-+ sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
-+ sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
-+ sta_flags = le32_to_cpu(sta_info_le.flags);
-+ brcmf_convert_sta_flags(sta_flags, sinfo);
-+ sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
-+ if (is_tdls_peer)
-+ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
-+ else
-+ sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
-+ if (sta_flags & BRCMF_STA_ASSOC) {
-+ sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
-+ sinfo->connected_time = le32_to_cpu(sta_info_le.in);
-+ brcmf_fill_bss_param(ifp, sinfo);
-+ }
-+ if (sta_flags & BRCMF_STA_SCBSTATS) {
-+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
-+ sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
-+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
-+ sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
-+ sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
-+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
-+ sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
-+ sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
-+ if (sinfo->tx_packets) {
- sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
-- sinfo->txrate.legacy = rate * 5;
-- brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
-+ sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate);
-+ sinfo->txrate.legacy /= 100;
- }
--
-- if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
-- &ifp->vif->sme_state)) {
-- memset(&scb_val, 0, sizeof(scb_val));
-- err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
-- &scb_val, sizeof(scb_val));
-- if (err) {
-- brcmf_err("Could not get rssi (%d)\n", err);
-- goto done;
-- } else {
-- rssi = le32_to_cpu(scb_val.val);
-- sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
-- sinfo->signal = rssi;
-- brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
-- }
-- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
-- &beacon_period);
-- if (err) {
-- brcmf_err("Could not get beacon period (%d)\n",
-- err);
-- goto done;
-- } else {
-- sinfo->bss_param.beacon_interval =
-- beacon_period;
-- brcmf_dbg(CONN, "Beacon peroid %d\n",
-- beacon_period);
-- }
-- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
-- &dtim_period);
-- if (err) {
-- brcmf_err("Could not get DTIM period (%d)\n",
-- err);
-- goto done;
-- } else {
-- sinfo->bss_param.dtim_period = dtim_period;
-- brcmf_dbg(CONN, "DTIM peroid %d\n",
-- dtim_period);
-- }
-- sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
-+ if (sinfo->rx_packets) {
-+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
-+ sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate);
-+ sinfo->rxrate.legacy /= 100;
-+ }
-+ if (le16_to_cpu(sta_info_le.ver) >= 4) {
-+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
-+ sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
-+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
-+ sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
- }
-- } else
-- err = -EPERM;
-+ }
- done:
- brcmf_dbg(TRACE, "Exit\n");
- return err;
---- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
-@@ -32,7 +32,11 @@
- #define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */
- #define BRCMF_BSS_RSSI_ON_CHANNEL 0x0002
-
--#define BRCMF_STA_ASSOC 0x10 /* Associated */
-+#define BRCMF_STA_WME 0x00000002 /* WMM association */
-+#define BRCMF_STA_AUTHE 0x00000008 /* Authenticated */
-+#define BRCMF_STA_ASSOC 0x00000010 /* Associated */
-+#define BRCMF_STA_AUTHO 0x00000020 /* Authorized */
-+#define BRCMF_STA_SCBSTATS 0x00004000 /* Per STA debug stats */
-
- /* size of brcmf_scan_params not including variable length array */
- #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
-@@ -113,6 +117,7 @@
- #define BRCMF_WOWL_MAXPATTERNSIZE 128
-
- #define BRCMF_COUNTRY_BUF_SZ 4
-+#define BRCMF_ANT_MAX 4
-
- /* join preference types for join_pref iovar */
- enum brcmf_join_pref_types {
-@@ -456,25 +461,61 @@ struct brcmf_channel_info_le {
- };
-
- struct brcmf_sta_info_le {
-- __le16 ver; /* version of this struct */
-- __le16 len; /* length in bytes of this structure */
-- __le16 cap; /* sta's advertised capabilities */
-- __le32 flags; /* flags defined below */
-- __le32 idle; /* time since data pkt rx'd from sta */
-- u8 ea[ETH_ALEN]; /* Station address */
-- __le32 count; /* # rates in this set */
-- u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */
-+ __le16 ver; /* version of this struct */
-+ __le16 len; /* length in bytes of this structure */
-+ __le16 cap; /* sta's advertised capabilities */
-+ __le32 flags; /* flags defined below */
-+ __le32 idle; /* time since data pkt rx'd from sta */
-+ u8 ea[ETH_ALEN]; /* Station address */
-+ __le32 count; /* # rates in this set */
-+ u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */
- /* w/hi bit set if basic */
-- __le32 in; /* seconds elapsed since associated */
-- __le32 listen_interval_inms; /* Min Listen interval in ms for STA */
-- __le32 tx_pkts; /* # of packets transmitted */
-- __le32 tx_failures; /* # of packets failed */
-- __le32 rx_ucast_pkts; /* # of unicast packets received */
-- __le32 rx_mcast_pkts; /* # of multicast packets received */
-- __le32 tx_rate; /* Rate of last successful tx frame */
-- __le32 rx_rate; /* Rate of last successful rx frame */
-- __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
-- __le32 rx_decrypt_failures; /* # of packet decrypted failed */
-+ __le32 in; /* seconds elapsed since associated */
-+ __le32 listen_interval_inms; /* Min Listen interval in ms for STA */
-+ __le32 tx_pkts; /* # of packets transmitted */
-+ __le32 tx_failures; /* # of packets failed */
-+ __le32 rx_ucast_pkts; /* # of unicast packets received */
-+ __le32 rx_mcast_pkts; /* # of multicast packets received */
-+ __le32 tx_rate; /* Rate of last successful tx frame */
-+ __le32 rx_rate; /* Rate of last successful rx frame */
-+ __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
-+ __le32 rx_decrypt_failures; /* # of packet decrypted failed */
-+ __le32 tx_tot_pkts; /* # of tx pkts (ucast + mcast) */
-+ __le32 rx_tot_pkts; /* # of data packets recvd (uni + mcast) */
-+ __le32 tx_mcast_pkts; /* # of mcast pkts txed */
-+ __le64 tx_tot_bytes; /* data bytes txed (ucast + mcast) */
-+ __le64 rx_tot_bytes; /* data bytes recvd (ucast + mcast) */
-+ __le64 tx_ucast_bytes; /* data bytes txed (ucast) */
-+ __le64 tx_mcast_bytes; /* # data bytes txed (mcast) */
-+ __le64 rx_ucast_bytes; /* data bytes recvd (ucast) */
-+ __le64 rx_mcast_bytes; /* data bytes recvd (mcast) */
-+ s8 rssi[BRCMF_ANT_MAX]; /* per antenna rssi */
-+ s8 nf[BRCMF_ANT_MAX]; /* per antenna noise floor */
-+ __le16 aid; /* association ID */
-+ __le16 ht_capabilities; /* advertised ht caps */
-+ __le16 vht_flags; /* converted vht flags */
-+ __le32 tx_pkts_retry_cnt; /* # of frames where a retry was
-+ * exhausted.
-+ */
-+ __le32 tx_pkts_retry_exhausted; /* # of user frames where a retry
-+ * was exhausted
-+ */
-+ s8 rx_lastpkt_rssi[BRCMF_ANT_MAX]; /* Per antenna RSSI of last
-+ * received data frame.
-+ */
-+ /* TX WLAN retry/failure statistics:
-+ * Separated for host requested frames and locally generated frames.
-+ * Include unicast frame only where the retries/failures can be counted.
-+ */
-+ __le32 tx_pkts_total; /* # user frames sent successfully */
-+ __le32 tx_pkts_retries; /* # user frames retries */
-+ __le32 tx_pkts_fw_total; /* # FW generated sent successfully */
-+ __le32 tx_pkts_fw_retries; /* # retries for FW generated frames */
-+ __le32 tx_pkts_fw_retry_exhausted; /* # FW generated where a retry
-+ * was exhausted
-+ */
-+ __le32 rx_pkts_retried; /* # rx with retry bit set */
-+ __le32 tx_rate_fallback; /* lowest fallback TX rate */
- };
-
- struct brcmf_chanspec_list {
+++ /dev/null
-From: Arend van Spriel <arend@broadcom.com>
-Date: Thu, 11 Jun 2015 00:12:20 +0200
-Subject: [PATCH] brcmfmac: have sdio return -EIO when device communication
- is not possible
-
-The bus interface functions txctl and rxctl may be used while the device
-can not be accessed, eg. upon driver .remove() callback. This patch will
-immediately return -EIO when this is the case which speeds up the module
-unload.
-
-Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
-Signed-off-by: Arend van Spriel <arend@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
-
---- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
-@@ -988,6 +988,7 @@ static void brcmf_sdiod_freezer_detach(s
-
- static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
- {
-+ sdiodev->state = BRCMF_SDIOD_DOWN;
- if (sdiodev->bus) {
- brcmf_sdio_remove(sdiodev->bus);
- sdiodev->bus = NULL;
---- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
-@@ -2820,6 +2820,8 @@ static int brcmf_sdio_bus_txdata(struct
- struct brcmf_sdio *bus = sdiodev->bus;
-
- brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);
-+ if (sdiodev->state != BRCMF_SDIOD_DATA)
-+ return -EIO;
-
- /* Add space for the header */
- skb_push(pkt, bus->tx_hdrlen);
-@@ -2948,6 +2950,8 @@ brcmf_sdio_bus_txctl(struct device *dev,
- int ret;
-
- brcmf_dbg(TRACE, "Enter\n");
-+ if (sdiodev->state != BRCMF_SDIOD_DATA)
-+ return -EIO;
-
- /* Send from dpc */
- bus->ctrl_frame_buf = msg;
-@@ -3238,6 +3242,8 @@ brcmf_sdio_bus_rxctl(struct device *dev,
- struct brcmf_sdio *bus = sdiodev->bus;
-
- brcmf_dbg(TRACE, "Enter\n");
-+ if (sdiodev->state != BRCMF_SDIOD_DATA)
-+ return -EIO;
-
- /* Wait until control frame is available */
- timeleft = brcmf_sdio_dcmd_resp_wait(bus, &bus->rxlen, &pending);
+++ /dev/null
-From: Felix Fietkau <nbd@openwrt.org>
-Date: Thu, 2 Jul 2015 13:35:05 +0200
-Subject: [PATCH] ath9k: make DMA stop related messages debug-only
-
-A long time ago, ath9k had issues during reset where the DMA engine
-would stay active and could potentially corrupt memory.
-To debug those issues, the driver would print warnings whenever they
-occur.
-
-Nowadays, these issues are gone and the primary cause of these messages
-is if the MAC is stuck during reset or busy processing a long
-transmission. This is fairly harmless, yet these messages continue to
-worry users.
-
-To reduce the number of bogus bug reports, turn these messages into
-debug messages and count their occurence in the "reset" debugfs file.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
----
-
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -765,6 +765,8 @@ static int read_file_reset(struct seq_fi
- [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
- [RESET_TYPE_MCI] = "MCI Reset",
- [RESET_TYPE_CALIBRATION] = "Calibration error",
-+ [RESET_TX_DMA_ERROR] = "Tx DMA stop error",
-+ [RESET_RX_DMA_ERROR] = "Rx DMA stop error",
- };
- int i;
-
---- a/drivers/net/wireless/ath/ath9k/debug.h
-+++ b/drivers/net/wireless/ath/ath9k/debug.h
-@@ -50,6 +50,8 @@ enum ath_reset_type {
- RESET_TYPE_BEACON_STUCK,
- RESET_TYPE_MCI,
- RESET_TYPE_CALIBRATION,
-+ RESET_TX_DMA_ERROR,
-+ RESET_RX_DMA_ERROR,
- __RESET_TYPE_MAX
- };
-
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -496,10 +496,9 @@ bool ath_stoprecv(struct ath_softc *sc)
-
- if (!(ah->ah_flags & AH_UNPLUGGED) &&
- unlikely(!stopped)) {
-- ath_err(ath9k_hw_common(sc->sc_ah),
-- "Could not stop RX, we could be "
-- "confusing the DMA engine when we start RX up\n");
-- ATH_DBG_WARN_ON_ONCE(!stopped);
-+ ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
-+ "Failed to stop Rx DMA\n");
-+ RESET_STAT_INC(sc, RESET_RX_DMA_ERROR);
- }
- return stopped && !reset;
- }
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -1896,8 +1896,11 @@ bool ath_drain_all_txq(struct ath_softc
- npend |= BIT(i);
- }
-
-- if (npend)
-- ath_err(common, "Failed to stop TX DMA, queues=0x%03x!\n", npend);
-+ if (npend) {
-+ RESET_STAT_INC(sc, RESET_TX_DMA_ERROR);
-+ ath_dbg(common, RESET,
-+ "Failed to stop TX DMA, queues=0x%03x!\n", npend);
-+ }
-
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
- if (!ATH_TXQ_SETUP(sc, i))