PKG_NAME:=mac80211
-PKG_VERSION:=4.19.57-1
+PKG_VERSION:=4.20.17-1
PKG_RELEASE:=1
-PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v4.19.57/
-PKG_HASH:=f9c2d888cd49bd85e3f625f440468a803eeabb36662b56426c6cb2d15a7e049d
+PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v4.20.17/
+PKG_HASH:=c7efc87babef35c08251a04cb26ffd683026d1365f5bbf8226c9e22462c41592
PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/backports-$(PKG_VERSION)
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
-@@ -85,6 +85,12 @@ config ATH10K_TRACING
+@@ -87,6 +87,12 @@ config ATH10K_TRACING
---help---
Select this to ath10k use tracing infrastructure.
void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
--- a/local-symbols
+++ b/local-symbols
-@@ -139,6 +139,7 @@ ATH10K_SNOC=
+@@ -137,6 +137,7 @@ ATH10K_SNOC=
ATH10K_DEBUG=
ATH10K_DEBUGFS=
ATH10K_SPECTRAL=
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Mon, 20 Aug 2018 11:35:05 +0200
-Subject: [PATCH] ath9k: fix tx99 with monitor mode interface
-
-Tx99 is typically configured via a monitor mode interface, which does
-not get added to the driver as a vif. Since the code currently expects
-a configured virtual interface for tx99, enabling tx99 via debugfs fails.
-Since the vif is not needed anyway, remove all checks for it.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -1074,7 +1074,6 @@ struct ath_softc {
-
- struct ath_spec_scan_priv spec_priv;
-
-- struct ieee80211_vif *tx99_vif;
- struct sk_buff *tx99_skb;
- bool tx99_state;
- s16 tx99_power;
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1251,15 +1251,10 @@ static int ath9k_add_interface(struct ie
- struct ath_vif *avp = (void *)vif->drv_priv;
- struct ath_node *an = &avp->mcast_node;
-
-- mutex_lock(&sc->mutex);
-+ if (IS_ENABLED(CPTCFG_ATH9K_TX99))
-+ return -EOPNOTSUPP;
-
-- if (IS_ENABLED(CPTCFG_ATH9K_TX99)) {
-- if (sc->cur_chan->nvifs >= 1) {
-- mutex_unlock(&sc->mutex);
-- return -EOPNOTSUPP;
-- }
-- sc->tx99_vif = vif;
-- }
-+ mutex_lock(&sc->mutex);
-
- ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
- sc->cur_chan->nvifs++;
-@@ -1342,7 +1337,6 @@ static void ath9k_remove_interface(struc
- ath9k_p2p_remove_vif(sc, vif);
-
- sc->cur_chan->nvifs--;
-- sc->tx99_vif = NULL;
- if (!ath9k_is_chanctx_enabled())
- list_del(&avp->list);
-
---- a/drivers/net/wireless/ath/ath9k/tx99.c
-+++ b/drivers/net/wireless/ath/ath9k/tx99.c
-@@ -54,12 +54,6 @@ static struct sk_buff *ath9k_build_tx99_
- struct ieee80211_hdr *hdr;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb;
-- struct ath_vif *avp;
--
-- if (!sc->tx99_vif)
-- return NULL;
--
-- avp = (struct ath_vif *)sc->tx99_vif->drv_priv;
-
- skb = alloc_skb(len, GFP_KERNEL);
- if (!skb)
-@@ -77,14 +71,11 @@ static struct sk_buff *ath9k_build_tx99_
- memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
- memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
-
-- hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
--
- tx_info = IEEE80211_SKB_CB(skb);
- memset(tx_info, 0, sizeof(*tx_info));
- rate = &tx_info->control.rates[0];
- tx_info->band = sc->cur_chan->chandef.chan->band;
- tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
-- tx_info->control.vif = sc->tx99_vif;
- rate->count = 1;
- if (ah->curchan && IS_CHAN_HT(ah->curchan)) {
- rate->flags |= IEEE80211_TX_RC_MCS;
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -2974,7 +2974,7 @@ int ath9k_tx99_send(struct ath_softc *sc
- return -EINVAL;
- }
-
-- ath_set_rates(sc->tx99_vif, NULL, bf);
-+ ath_set_rates(NULL, NULL, bf);
-
- ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr);
- ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum);
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 22 Sep 2018 15:20:50 +0200
-Subject: [PATCH] ath9k: add back support for using active monitor interfaces
- for tx99
-
-Various documented examples on how to set up tx99 with ath9k rely
-on setting up a regular monitor interface for setting the channel.
-My previous patch "ath9k: fix tx99 with monitor mode interface" made
-it possible to set it up this way again. However, it was removing support
-for using an active monitor interface, which is required for controlling
-the bitrate as well, since the bitrate is not passed down with a regular
-monitor interface.
-
-This patch partially reverts the previous one, but keeps support for using
-a regular monitor interface to keep documented steps working in cases
-where the bitrate does not matter
-
-Fixes: d9c52fd17cb48 ("ath9k: fix tx99 with monitor mode interface")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -1074,6 +1074,7 @@ struct ath_softc {
-
- struct ath_spec_scan_priv spec_priv;
-
-+ struct ieee80211_vif *tx99_vif;
- struct sk_buff *tx99_skb;
- bool tx99_state;
- s16 tx99_power;
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1251,8 +1251,13 @@ static int ath9k_add_interface(struct ie
- struct ath_vif *avp = (void *)vif->drv_priv;
- struct ath_node *an = &avp->mcast_node;
-
-- if (IS_ENABLED(CPTCFG_ATH9K_TX99))
-- return -EOPNOTSUPP;
-+ if (IS_ENABLED(CPTCFG_ATH9K_TX99)) {
-+ if (sc->cur_chan->nvifs >= 1) {
-+ mutex_unlock(&sc->mutex);
-+ return -EOPNOTSUPP;
-+ }
-+ sc->tx99_vif = vif;
-+ }
-
- mutex_lock(&sc->mutex);
-
-@@ -1337,6 +1342,7 @@ static void ath9k_remove_interface(struc
- ath9k_p2p_remove_vif(sc, vif);
-
- sc->cur_chan->nvifs--;
-+ sc->tx99_vif = NULL;
- if (!ath9k_is_chanctx_enabled())
- list_del(&avp->list);
-
---- a/drivers/net/wireless/ath/ath9k/tx99.c
-+++ b/drivers/net/wireless/ath/ath9k/tx99.c
-@@ -54,6 +54,7 @@ static struct sk_buff *ath9k_build_tx99_
- struct ieee80211_hdr *hdr;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb;
-+ struct ath_vif *avp;
-
- skb = alloc_skb(len, GFP_KERNEL);
- if (!skb)
-@@ -71,11 +72,17 @@ static struct sk_buff *ath9k_build_tx99_
- memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
- memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
-
-+ if (sc->tx99_vif) {
-+ avp = (struct ath_vif *) sc->tx99_vif->drv_priv;
-+ hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
-+ }
-+
- tx_info = IEEE80211_SKB_CB(skb);
- memset(tx_info, 0, sizeof(*tx_info));
- rate = &tx_info->control.rates[0];
- tx_info->band = sc->cur_chan->chandef.chan->band;
- tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
-+ tx_info->control.vif = sc->tx99_vif;
- rate->count = 1;
- if (ah->curchan && IS_CHAN_HT(ah->curchan)) {
- rate->flags |= IEEE80211_TX_RC_MCS;
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -2974,7 +2974,7 @@ int ath9k_tx99_send(struct ath_softc *sc
- return -EINVAL;
- }
-
-- ath_set_rates(NULL, NULL, bf);
-+ ath_set_rates(sc->tx99_vif, NULL, bf);
-
- ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr);
- ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum);
---help---
--- a/local-symbols
+++ b/local-symbols
-@@ -83,6 +83,7 @@ ADM8211=
+@@ -81,6 +81,7 @@ ADM8211=
ATH_COMMON=
WLAN_VENDOR_ATH=
ATH_DEBUG=
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
-@@ -3021,6 +3021,8 @@ void regulatory_hint_country_ie(struct w
+@@ -2988,6 +2988,8 @@ void regulatory_hint_country_ie(struct w
enum environment_cap env = ENVIRON_ANY;
struct regulatory_request *request = NULL, *lr;
/* IE len must be evenly divisible by 2 */
if (country_ie_len & 0x01)
return;
-@@ -3227,6 +3229,7 @@ static void restore_regulatory_settings(
+@@ -3213,6 +3215,7 @@ static bool is_wiphy_all_set_reg_flag(en
void regulatory_hint_disconnect(void)
{
+ return;
- pr_debug("All devices are disconnected, going to restore regulatory settings\n");
- restore_regulatory_settings(false);
- }
+ /* Restore of regulatory settings is not required when wiphy(s)
+ * ignore IE from connected access point but clearance of beacon hints
+ * is required when wiphy(s) supports beacon hints.
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1374,6 +1374,53 @@ void ath9k_deinit_debug(struct ath_softc
+@@ -1361,6 +1361,53 @@ void ath9k_deinit_debug(struct ath_softc
ath9k_cmn_spectral_deinit_debug(&sc->spec_priv);
}
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
-@@ -1393,6 +1440,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1380,6 +1427,8 @@ int ath9k_init_debug(struct ath_hw *ah)
ath9k_tx99_init_debug(sc);
ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy);
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1421,6 +1421,52 @@ static const struct file_operations fops
+@@ -1408,6 +1408,52 @@ static const struct file_operations fops
.owner = THIS_MODULE
};
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
-@@ -1442,6 +1488,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1429,6 +1475,8 @@ int ath9k_init_debug(struct ath_hw *ah)
debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_eeprom);
#endif
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1466,6 +1466,61 @@ static const struct file_operations fops
+@@ -1453,6 +1453,61 @@ static const struct file_operations fops
.llseek = default_llseek,
};
int ath9k_init_debug(struct ath_hw *ah)
{
-@@ -1490,6 +1545,10 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1477,6 +1532,10 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_eeprom);
debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
sc, &fops_chanbw);
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1522,6 +1522,50 @@ static const struct file_operations fops
+@@ -1509,6 +1509,50 @@ static const struct file_operations fops
#endif
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
-@@ -1549,6 +1593,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1536,6 +1580,8 @@ int ath9k_init_debug(struct ath_hw *ah)
debugfs_create_file("gpio_led", S_IWUSR,
sc->debug.debugfs_phy, sc, &fops_gpio_led);
#endif
static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
-@@ -1324,9 +1324,30 @@ void ar5008_hw_init_rate_txpower(struct
+@@ -1320,9 +1320,30 @@ void ar5008_hw_init_rate_txpower(struct
}
}
static const u32 ar5416_cca_regs[6] = {
AR_PHY_CCA,
AR_PHY_CH1_CCA,
-@@ -1341,6 +1362,8 @@ int ar5008_hw_attach_phy_ops(struct ath_
+@@ -1337,6 +1358,8 @@ int ar5008_hw_attach_phy_ops(struct ath_
if (ret)
return ret;
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
-@@ -953,55 +953,6 @@ static bool ar5008_hw_ani_control_new(st
+@@ -949,55 +949,6 @@ static bool ar5008_hw_ani_control_new(st
* on == 0 means more noise imm
*/
u32 on = param ? 1 : 0;
#endif /* _LINUX_ATH9K_PLATFORM_H */
--- a/local-symbols
+++ b/local-symbols
-@@ -110,6 +110,7 @@ ATH9K_WOW=
+@@ -108,6 +108,7 @@ ATH9K_WOW=
ATH9K_RFKILL=
ATH9K_CHANNEL_CONTEXT=
ATH9K_PCOEM=
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
-@@ -2720,6 +2720,16 @@ int ath10k_core_register(struct ath10k *
- ar->chip_id = chip_id;
+@@ -2978,6 +2978,16 @@ int ath10k_core_register(struct ath10k *
+ ar->dev_type = bus_params->dev_type;
queue_work(ar->workqueue, &ar->register_work);
+ /* OpenWrt requires all PHYs to be initialized to create the
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -8282,6 +8282,21 @@ static int ath10k_mac_init_rd(struct ath
+@@ -8383,6 +8383,21 @@ static int ath10k_mac_init_rd(struct ath
return 0;
}
int ath10k_mac_register(struct ath10k *ar)
{
static const u32 cipher_suites[] = {
-@@ -8571,6 +8586,12 @@ int ath10k_mac_register(struct ath10k *a
+@@ -8695,6 +8710,12 @@ int ath10k_mac_register(struct ath10k *a
wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
-@@ -238,7 +238,7 @@ enum htt_rx_ring_flags {
+@@ -237,7 +237,7 @@ enum htt_rx_ring_flags {
};
#define HTT_RX_RING_SIZE_MIN 128
3 files changed, 52 insertions(+), 23 deletions(-)
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -2469,7 +2469,7 @@ static void ath10k_peer_assoc_h_vht(stru
+@@ -2485,7 +2485,7 @@ static void ath10k_peer_assoc_h_vht(stru
const u16 *vht_mcs_mask;
u8 ampdu_factor;
u8 max_nss, vht_mcs;
if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
return;
-@@ -2529,23 +2529,45 @@ static void ath10k_peer_assoc_h_vht(stru
+@@ -2545,23 +2545,45 @@ static void ath10k_peer_assoc_h_vht(stru
__le16_to_cpu(vht_cap->vht_mcs.tx_highest);
arg->peer_vht_rates.tx_mcs_set = ath10k_peer_assoc_h_vht_limit(
__le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask);
}
static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
-@@ -2697,9 +2719,9 @@ static int ath10k_peer_assoc_prepare(str
+@@ -2713,9 +2735,9 @@ static int ath10k_peer_assoc_prepare(str
ath10k_peer_assoc_h_crypto(ar, vif, sta, arg);
ath10k_peer_assoc_h_rates(ar, vif, sta, arg);
ath10k_peer_assoc_h_ht(ar, vif, sta, arg);
}
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
-@@ -7357,12 +7357,7 @@ ath10k_wmi_peer_assoc_fill_10_4(struct a
+@@ -7416,12 +7416,7 @@ ath10k_wmi_peer_assoc_fill_10_4(struct a
struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf;
ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg);
static int
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
-@@ -6357,7 +6357,19 @@ struct wmi_10_2_peer_assoc_complete_cmd
+@@ -6387,7 +6387,19 @@ struct wmi_10_2_peer_assoc_complete_cmd
__le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
} __packed;
2 files changed, 8 insertions(+), 10 deletions(-)
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -4473,13 +4473,6 @@ static struct ieee80211_sta_vht_cap ath1
+@@ -4489,13 +4489,6 @@ static struct ieee80211_sta_vht_cap ath1
vht_cap.cap |= val;
}
if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i)))
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
-@@ -1677,13 +1677,18 @@ void ath10k_wmi_put_wmi_channel(struct w
+@@ -1678,13 +1678,18 @@ void ath10k_wmi_put_wmi_channel(struct w
flags |= WMI_CHAN_FLAG_HT40_PLUS;
if (arg->chan_radar)
flags |= WMI_CHAN_FLAG_DFS;
create mode 100644 drivers/net/wireless/ath/ath10k/leds.h
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
-@@ -69,6 +69,16 @@ config ATH10K_DEBUGFS
+@@ -71,6 +71,16 @@ config ATH10K_DEBUGFS
If unsure, say Y to make it easier to debug problems.
ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o
--- a/local-symbols
+++ b/local-symbols
-@@ -142,6 +142,7 @@ ATH10K_DEBUG=
+@@ -140,6 +140,7 @@ ATH10K_DEBUG=
ATH10K_DEBUGFS=
ATH10K_SPECTRAL=
ATH10K_THERMAL=
WCN36XX=
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
-@@ -34,6 +34,7 @@
+@@ -35,6 +35,7 @@
#include "testmode.h"
#include "wmi-ops.h"
#include "coredump.h"
unsigned int ath10k_debug_mask;
static unsigned int ath10k_cryptmode_param;
-@@ -64,6 +65,7 @@ static const struct ath10k_hw_params ath
- .id = QCA988X_HW_2_0_VERSION,
+@@ -66,6 +67,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA988X_2_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca988x hw2.0",
+ .led_pin = 1,
.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
-@@ -129,6 +131,7 @@ static const struct ath10k_hw_params ath
- .id = QCA9887_HW_1_0_VERSION,
+@@ -134,6 +136,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA9887_1_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca9887 hw1.0",
+ .led_pin = 1,
.patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
-@@ -293,6 +296,7 @@ static const struct ath10k_hw_params ath
- .id = QCA99X0_HW_2_0_DEV_VERSION,
+@@ -308,6 +311,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA99X0_2_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca99x0 hw2.0",
+ .led_pin = 17,
.patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.otp_exe_param = 0x00000700,
-@@ -331,6 +335,7 @@ static const struct ath10k_hw_params ath
- .id = QCA9984_HW_1_0_DEV_VERSION,
+@@ -348,6 +352,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA9984_1_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca9984/qca9994 hw1.0",
+ .led_pin = 17,
.patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
-@@ -374,6 +379,7 @@ static const struct ath10k_hw_params ath
- .id = QCA9888_HW_2_0_DEV_VERSION,
+@@ -395,6 +400,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA9888_2_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca9888 hw2.0",
+ .led_pin = 17,
.patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
-@@ -2441,6 +2447,10 @@ int ath10k_core_start(struct ath10k *ar,
+@@ -2695,6 +2701,10 @@ int ath10k_core_start(struct ath10k *ar,
if (status)
goto err_hif_stop;
return 0;
err_hif_stop:
-@@ -2695,9 +2705,18 @@ static void ath10k_core_register_work(st
+@@ -2951,9 +2961,18 @@ static void ath10k_core_register_work(st
goto err_spectral_destroy;
}
err_spectral_destroy:
ath10k_spectral_destroy(ar);
err_debug_destroy:
-@@ -2741,6 +2760,8 @@ void ath10k_core_unregister(struct ath10
+@@ -2999,6 +3018,8 @@ void ath10k_core_unregister(struct ath10
if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
return;
#include "htt.h"
#include "htc.h"
-@@ -908,7 +909,6 @@ struct ath10k {
- u32 low_5ghz_chan;
- u32 high_5ghz_chan;
- bool ani_enabled;
--
- bool p2p;
-
- struct {
-@@ -1099,6 +1099,13 @@ struct ath10k {
+@@ -1147,6 +1148,13 @@ struct ath10k {
} testmode;
struct {
u32 fw_warm_reset_counter;
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
-@@ -504,6 +504,7 @@ struct ath10k_hw_params {
+@@ -520,6 +520,7 @@ struct ath10k_hw_params {
const char *name;
u32 patch_load_addr;
int uart_pin;
/* Rates */
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
-@@ -216,7 +216,10 @@ struct wmi_ops {
+@@ -219,7 +219,10 @@ struct wmi_ops {
struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value);
struct sk_buff *(*gen_pdev_get_tpc_table_cmdid)(struct ath10k *ar,
u32 param);
};
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
-@@ -1054,6 +1057,35 @@ ath10k_wmi_force_fw_hang(struct ath10k *
+@@ -1057,6 +1060,35 @@ ath10k_wmi_force_fw_hang(struct ath10k *
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
}
{
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
-@@ -3976,6 +3976,8 @@ static const struct wmi_ops wmi_tlv_ops
+@@ -4168,6 +4168,8 @@ static const struct wmi_ops wmi_tlv_ops
.gen_echo = ath10k_wmi_tlv_op_gen_echo,
.gen_vdev_spectral_conf = ath10k_wmi_tlv_op_gen_vdev_spectral_conf,
.gen_vdev_spectral_enable = ath10k_wmi_tlv_op_gen_vdev_spectral_enable,
static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = {
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
-@@ -7177,6 +7177,49 @@ ath10k_wmi_op_gen_peer_set_param(struct
+@@ -7236,6 +7236,49 @@ ath10k_wmi_op_gen_peer_set_param(struct
return skb;
}
static struct sk_buff *
ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id,
enum wmi_sta_ps_mode psmode)
-@@ -8788,6 +8831,9 @@ static const struct wmi_ops wmi_ops = {
+@@ -8847,6 +8890,9 @@ static const struct wmi_ops wmi_ops = {
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
.gen_echo = ath10k_wmi_op_gen_echo,
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
-@@ -8858,6 +8904,8 @@ static const struct wmi_ops wmi_10_1_ops
+@@ -8917,6 +8963,8 @@ static const struct wmi_ops wmi_10_1_ops
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
.gen_echo = ath10k_wmi_op_gen_echo,
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
-@@ -8929,6 +8977,8 @@ static const struct wmi_ops wmi_10_2_ops
+@@ -8988,6 +9036,8 @@ static const struct wmi_ops wmi_10_2_ops
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
/* .gen_pdev_enable_adaptive_cca not implemented */
};
-@@ -8999,6 +9049,8 @@ static const struct wmi_ops wmi_10_2_4_o
+@@ -9058,6 +9108,8 @@ static const struct wmi_ops wmi_10_2_4_o
.gen_pdev_enable_adaptive_cca =
ath10k_wmi_op_gen_pdev_enable_adaptive_cca,
.get_vdev_subtype = ath10k_wmi_10_2_4_op_get_vdev_subtype,
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
-@@ -9078,6 +9130,8 @@ static const struct wmi_ops wmi_10_4_ops
+@@ -9137,6 +9189,8 @@ static const struct wmi_ops wmi_10_4_ops
.gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info,
.gen_echo = ath10k_wmi_op_gen_echo,
.gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config,
int ath10k_wmi_attach(struct ath10k *ar)
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
-@@ -2942,6 +2942,41 @@ enum wmi_10_4_feature_mask {
+@@ -2960,6 +2960,41 @@ enum wmi_10_4_feature_mask {
};
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
-@@ -1144,6 +1144,10 @@ struct ath10k {
+@@ -1193,6 +1193,10 @@ struct ath10k {
struct ath10k_radar_found_info last_radar_info;
struct work_struct radar_confirmation_work;
if (ret)
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -8603,7 +8603,7 @@ int ath10k_mac_register(struct ath10k *a
+@@ -8727,7 +8727,7 @@ int ath10k_mac_register(struct ath10k *a
wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
#ifdef CPTCFG_MAC80211_LEDS
+++ /dev/null
-From bbf0a8af2261bc7ae39b227ff6a1e9f45a008c27 Mon Sep 17 00:00:00 2001
-From: Sven Eckelmann <sven.eckelmann@openmesh.com>
-Date: Mon, 30 Jul 2018 17:31:41 +0200
-Subject: [PATCH] ath10k: Limit available channels via DT ieee80211-freq-limit
-
-Tri-band devices (1x 2.4GHz + 2x 5GHz) often incorporate special filters in
-the RX and TX path. These filtered channel can in theory still be used by
-the hardware but the signal strength is reduced so much that it makes no
-sense.
-
-There is already a DT property to limit the available channels but ath10k
-has to manually call this functionality to limit the currrently set wiphy
-channels further.
-
-Signed-off-by: Sven Eckelmann <sven.eckelmann@openmesh.com>
-
-Forwarded: https://patchwork.kernel.org/patch/10549245/
----
- drivers/net/wireless/ath/ath10k/mac.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/net/wireless/ath/ath10k/mac.c
-+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -18,6 +18,7 @@
-
- #include "mac.h"
-
-+#include <net/cfg80211.h>
- #include <net/mac80211.h>
- #include <linux/etherdevice.h>
- #include <linux/acpi.h>
-@@ -8390,6 +8391,7 @@ int ath10k_mac_register(struct ath10k *a
- ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band;
- }
-
-+ wiphy_read_of_freq_limits(ar->hw->wiphy);
- ath10k_mac_setup_ht_vht_cap(ar);
-
- ar->hw->wiphy->interface_modes =
+++ /dev/null
-From: Sriram R <srirrama@codeaurora.org>
-Date: Mon, 10 Sep 2018 11:09:40 +0530
-Subject: [PATCH] ath10k: add support for configuring management packet rate
-
-By default the firmware uses 1Mbps and 6Mbps rate for management packets
-in 2G and 5G bands respectively. But when the user selects different
-basic rates from the userspace, we need to send the management
-packets at the lowest basic rate selected by the user.
-
-This change makes use of WMI_VDEV_PARAM_MGMT_RATE param for configuring the
-management packets rate to the firmware.
-
-Chipsets Tested : QCA988X, QCA9887, QCA9984
-FW Tested : 10.2.4-1.0-41, 10.4-3.6.104
-
-Signed-off-by: Sriram R <srirrama@codeaurora.org>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-
-Origin: backport, https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f279294e9ee22a8f306fdc8e4181cf555e6f0f70
----
---- a/drivers/net/wireless/ath/ath10k/mac.c
-+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -158,6 +158,22 @@ u8 ath10k_mac_bitrate_to_idx(const struc
- return 0;
- }
-
-+static int ath10k_mac_get_rate_hw_value(int bitrate)
-+{
-+ int i;
-+ u8 hw_value_prefix = 0;
-+
-+ if (ath10k_mac_bitrate_is_cck(bitrate))
-+ hw_value_prefix = WMI_RATE_PREAMBLE_CCK << 6;
-+
-+ for (i = 0; i < sizeof(ath10k_rates); i++) {
-+ if (ath10k_rates[i].bitrate == bitrate)
-+ return hw_value_prefix | ath10k_rates[i].hw_value;
-+ }
-+
-+ return -EINVAL;
-+}
-+
- static int ath10k_mac_get_max_vht_mcs_map(u16 mcs_map, int nss)
- {
- switch ((mcs_map >> (2 * nss)) & 0x3) {
-@@ -5468,9 +5484,10 @@ static void ath10k_bss_info_changed(stru
- struct cfg80211_chan_def def;
- u32 vdev_param, pdev_param, slottime, preamble;
- u16 bitrate, hw_value;
-- u8 rate;
-- int rateidx, ret = 0;
-+ u8 rate, basic_rate_idx;
-+ int rateidx, ret = 0, hw_rate_code;
- enum nl80211_band band;
-+ const struct ieee80211_supported_band *sband;
-
- mutex_lock(&ar->conf_mutex);
-
-@@ -5676,6 +5693,30 @@ static void ath10k_bss_info_changed(stru
- arvif->vdev_id, ret);
- }
-
-+ if (changed & BSS_CHANGED_BASIC_RATES) {
-+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) {
-+ mutex_unlock(&ar->conf_mutex);
-+ return;
-+ }
-+
-+ sband = ar->hw->wiphy->bands[def.chan->band];
-+ basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1;
-+ bitrate = sband->bitrates[basic_rate_idx].bitrate;
-+
-+ hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate);
-+ if (hw_rate_code < 0) {
-+ ath10k_warn(ar, "bitrate not supported %d\n", bitrate);
-+ mutex_unlock(&ar->conf_mutex);
-+ return;
-+ }
-+
-+ vdev_param = ar->wmi.vdev_param->mgmt_rate;
-+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
-+ hw_rate_code);
-+ if (ret)
-+ ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret);
-+ }
-+
- mutex_unlock(&ar->conf_mutex);
- }
-
+++ /dev/null
-From: Sriram R <srirrama@codeaurora.org>
-Date: Wed, 3 Oct 2018 08:43:50 +0530
-Subject: [PATCH] ath10k: fix possible out of bound access of ath10k_rates array
-
-While using 'ath10k_mac_get_rate_hw_value()' to obtain the hw value
-from the passed bitrate, there is a chance of out of bound array access
-when wrong bitrate is passed. This is fixed by comparing the bitrates
-within the correct size of the ath10k_rates array.
-
-Fixes commit f279294e9ee2 ("ath10k: add support for configuring management
-packet rate"). Also correction made to some indents used in the above commit.
-
-Signed-off-by: Sriram R <srirrama@codeaurora.org>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-
-Origin: backport, https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=34e141eea7dd8525dd1ef7a925459e455b4d307f
----
---- a/drivers/net/wireless/ath/ath10k/mac.c
-+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -166,7 +166,7 @@ static int ath10k_mac_get_rate_hw_value(
- if (ath10k_mac_bitrate_is_cck(bitrate))
- hw_value_prefix = WMI_RATE_PREAMBLE_CCK << 6;
-
-- for (i = 0; i < sizeof(ath10k_rates); i++) {
-+ for (i = 0; i < ARRAY_SIZE(ath10k_rates); i++) {
- if (ath10k_rates[i].bitrate == bitrate)
- return hw_value_prefix | ath10k_rates[i].hw_value;
- }
-@@ -5699,22 +5699,22 @@ static void ath10k_bss_info_changed(stru
- return;
- }
-
-- sband = ar->hw->wiphy->bands[def.chan->band];
-- basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1;
-- bitrate = sband->bitrates[basic_rate_idx].bitrate;
--
-- hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate);
-- if (hw_rate_code < 0) {
-- ath10k_warn(ar, "bitrate not supported %d\n", bitrate);
-- mutex_unlock(&ar->conf_mutex);
-- return;
-- }
-+ sband = ar->hw->wiphy->bands[def.chan->band];
-+ basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1;
-+ bitrate = sband->bitrates[basic_rate_idx].bitrate;
-+
-+ hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate);
-+ if (hw_rate_code < 0) {
-+ ath10k_warn(ar, "bitrate not supported %d\n", bitrate);
-+ mutex_unlock(&ar->conf_mutex);
-+ return;
-+ }
-
-- vdev_param = ar->wmi.vdev_param->mgmt_rate;
-- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
-- hw_rate_code);
-- if (ret)
-- ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret);
-+ vdev_param = ar->wmi.vdev_param->mgmt_rate;
-+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
-+ hw_rate_code);
-+ if (ret)
-+ ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret);
- }
-
- mutex_unlock(&ar->conf_mutex);
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -5484,8 +5484,8 @@ static void ath10k_bss_info_changed(stru
+@@ -5491,8 +5491,8 @@ static void ath10k_bss_info_changed(stru
struct cfg80211_chan_def def;
u32 vdev_param, pdev_param, slottime, preamble;
u16 bitrate, hw_value;
enum nl80211_band band;
const struct ieee80211_supported_band *sband;
-@@ -5658,7 +5658,11 @@ static void ath10k_bss_info_changed(stru
+@@ -5665,7 +5665,11 @@ static void ath10k_bss_info_changed(stru
if (changed & BSS_CHANGED_MCAST_RATE &&
- !ath10k_mac_vif_chan(arvif->vif, &def)) {
+ !WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def))) {
band = def.chan->band;
- rateidx = vif->bss_conf.mcast_rate[band] - 1;
+ mcast_rate = vif->bss_conf.mcast_rate[band];
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -1020,7 +1020,7 @@ static int ath10k_monitor_vdev_start(str
+@@ -1019,7 +1019,7 @@ static int ath10k_monitor_vdev_start(str
arg.channel.min_power = 0;
arg.channel.max_power = channel->max_power * 2;
arg.channel.max_reg_power = channel->max_reg_power * 2;
reinit_completion(&ar->vdev_setup_done);
-@@ -1462,7 +1462,7 @@ static int ath10k_vdev_start_restart(str
+@@ -1461,7 +1461,7 @@ static int ath10k_vdev_start_restart(str
arg.channel.min_power = 0;
arg.channel.max_power = chandef->chan->max_power * 2;
arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
-@@ -3139,7 +3139,7 @@ static int ath10k_update_channel_list(st
+@@ -3138,7 +3138,7 @@ static int ath10k_update_channel_list(st
ch->min_power = 0;
ch->max_power = channel->max_power * 2;
ch->max_reg_power = channel->max_reg_power * 2;
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -988,6 +988,40 @@ static inline int ath10k_vdev_setup_sync
- return 0;
+@@ -987,6 +987,40 @@ static inline int ath10k_vdev_setup_sync
+ return ar->last_wmi_vdev_start_status;
}
+static u32 ath10k_get_max_antenna_gain(struct ath10k *ar,
static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
{
struct cfg80211_chan_def *chandef = NULL;
-@@ -1020,7 +1054,8 @@ static int ath10k_monitor_vdev_start(str
+@@ -1019,7 +1053,8 @@ static int ath10k_monitor_vdev_start(str
arg.channel.min_power = 0;
arg.channel.max_power = channel->max_power * 2;
arg.channel.max_reg_power = channel->max_reg_power * 2;
reinit_completion(&ar->vdev_setup_done);
-@@ -1462,7 +1497,8 @@ static int ath10k_vdev_start_restart(str
+@@ -1461,7 +1496,8 @@ static int ath10k_vdev_start_restart(str
arg.channel.min_power = 0;
arg.channel.max_power = chandef->chan->max_power * 2;
arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
-@@ -3139,7 +3175,8 @@ static int ath10k_update_channel_list(st
+@@ -3138,7 +3174,8 @@ static int ath10k_update_channel_list(st
ch->min_power = 0;
ch->max_power = channel->max_power * 2;
ch->max_reg_power = channel->max_reg_power * 2;
+++ /dev/null
-From 2fef681a4cf7994c882190fd2417b95f30510afb Mon Sep 17 00:00:00 2001
-From: Jia-Shyr Chuang <saint.chuang@cypress.com>
-Date: Wed, 15 Aug 2018 04:23:09 -0500
-Subject: [PATCH] brcmfmac: add CYW89342 mini-PCIe device
-
-CYW89342 is a 2x2 MIMO, 802.11a/b/g/n/ac for WLAN. It is a member of
-4355/4359 family.
-
-Signed-off-by: Jia-Shyr Chuang <saint.chuang@cypress.com>
-Signed-off-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
-@@ -2017,6 +2017,7 @@ static const struct dev_pm_ops brcmf_pci
-
- static const struct pci_device_id brcmf_pcie_devid_table[] = {
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID),
-+ BRCMF_PCIE_DEVICE_SUB(0x4355, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4355),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID),
+++ /dev/null
-From cb18e2e9ec71d42409a51b83546686c609780dde Mon Sep 17 00:00:00 2001
-From: Rasmus Villemoes <linux@rasmusvillemoes.dk>
-Date: Wed, 22 Aug 2018 15:22:15 +0200
-Subject: [PATCH] brcmfmac: fix wrong strnchr usage
-
-strnchr takes arguments in the order of its name: string, max bytes to
-read, character to search for. Here we're passing '\n' aka 10 as the
-buffer size, and searching for sizeof(buf) aka BRCMF_DCMD_SMLEN aka
-256 (aka '\0', since it's implicitly converted to char) within those 10
-bytes.
-
-Just interchanging the last two arguments would still leave a bug,
-because if we've been successful once, there are not sizeof(buf)
-characters left after the new value of p.
-
-Since clmver is immediately afterwards passed as a %s argument, I assume
-that it is actually a properly nul-terminated string. For that case, we
-have strreplace().
-
-Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 4 +---
- 1 file changed, 1 insertion(+), 3 deletions(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
-@@ -296,9 +296,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_i
- /* Replace all newline/linefeed characters with space
- * character
- */
-- ptr = clmver;
-- while ((ptr = strnchr(ptr, '\n', sizeof(buf))) != NULL)
-- *ptr = ' ';
-+ strreplace(clmver, '\n', ' ');
-
- brcmf_dbg(INFO, "CLM version = %s\n", clmver);
- }
+++ /dev/null
-From: Arend van Spriel <arend.vanspriel@broadcom.com>
-Date: Wed, 5 Sep 2018 09:48:59 +0200
-Subject: [PATCH] brcmfmac: increase buffer for obtaining firmware capabilities
-
-When obtaining the firmware capability a buffer is provided of 512
-bytes. However, if all features in firmware are supported the buffer
-needs to be 565 bytes as otherwise truncated information is retrieved
-from firmware. Increasing the buffer to 768 bytes on stack.
-
-Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Reviewed-by: Franky Lin <franky.lin@broadcom.com>
-Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
-@@ -178,7 +178,7 @@ static void brcmf_feat_iovar_data_set(st
- ifp->fwil_fwerr = false;
- }
-
--#define MAX_CAPS_BUFFER_SIZE 512
-+#define MAX_CAPS_BUFFER_SIZE 768
- static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)
- {
- char caps[MAX_CAPS_BUFFER_SIZE];
+++ /dev/null
-From a8254fa4ba60b85829b6e5ede6564f81cd70d59f Mon Sep 17 00:00:00 2001
-From: YueHaibing <yuehaibing@huawei.com>
-Date: Tue, 11 Sep 2018 11:24:04 +0800
-Subject: [PATCH] brcmfmac: remove set but not used variables 'sfdoff' and
- 'pad_size'
-
-Fixes gcc '-Wunused-but-set-variable' warning:
-
-drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c: In function 'brcmf_sdio_rxglom':
-drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c:1466:11: warning:
- variable 'sfdoff' set but not used [-Wunused-but-set-variable]
-
-drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c: In function 'brcmf_sdio_bus_preinit':
-drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c:3408:7: warning:
- variable 'pad_size' set but not used [-Wunused-but-set-variable]
-
-Signed-off-by: YueHaibing <yuehaibing@huawei.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 5 +----
- 1 file changed, 1 insertion(+), 4 deletions(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -1474,7 +1474,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf
- struct sk_buff *pfirst, *pnext;
-
- int errcode;
-- u8 doff, sfdoff;
-+ u8 doff;
-
- struct brcmf_sdio_hdrinfo rd_new;
-
-@@ -1608,7 +1608,6 @@ static u8 brcmf_sdio_rxglom(struct brcmf
-
- /* Remove superframe header, remember offset */
- skb_pull(pfirst, rd_new.dat_offset);
-- sfdoff = rd_new.dat_offset;
- num = 0;
-
- /* Validate all the subframe headers */
-@@ -3416,7 +3415,6 @@ static int brcmf_sdio_bus_preinit(struct
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- struct brcmf_sdio *bus = sdiodev->bus;
- struct brcmf_core *core = bus->sdio_core;
-- uint pad_size;
- u32 value;
- int err;
-
-@@ -3459,7 +3457,6 @@ static int brcmf_sdio_bus_preinit(struct
- if (sdiodev->sg_support) {
- bus->txglom = false;
- value = 1;
-- pad_size = bus->sdiodev->func2->cur_blksize << 1;
- err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
- &value, sizeof(u32));
- if (err < 0) {
+++ /dev/null
-From edb6d6885bef82d1eac432dbeca9fbf4ec349d7e Mon Sep 17 00:00:00 2001
-From: Chung-Hsien Hsu <stanley.hsu@cypress.com>
-Date: Thu, 27 Sep 2018 14:59:44 +0000
-Subject: [PATCH] brcmfmac: reduce timeout for action frame scan
-
-Finding a common channel to send an action frame out is required for
-some action types. Since a loop with several scan retry is used to find
-the channel, a short wait time could be considered for each attempt.
-This patch reduces the wait time from 1500 to 450 msec for each action
-frame scan.
-
-This patch fixes the WFA p2p certification 5.1.20 failure caused by the
-long action frame send time.
-
-Signed-off-by: Chung-Hsien Hsu <stanley.hsu@cypress.com>
-Signed-off-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 9 ++++-----
- 1 file changed, 4 insertions(+), 5 deletions(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
-@@ -74,7 +74,7 @@
- #define P2P_AF_MAX_WAIT_TIME msecs_to_jiffies(2000)
- #define P2P_INVALID_CHANNEL -1
- #define P2P_CHANNEL_SYNC_RETRY 5
--#define P2P_AF_FRM_SCAN_MAX_WAIT msecs_to_jiffies(1500)
-+#define P2P_AF_FRM_SCAN_MAX_WAIT msecs_to_jiffies(450)
- #define P2P_DEFAULT_SLEEP_TIME_VSDB 200
-
- /* WiFi P2P Public Action Frame OUI Subtypes */
-@@ -1134,7 +1134,6 @@ static s32 brcmf_p2p_af_searching_channe
- {
- struct afx_hdl *afx_hdl = &p2p->afx_hdl;
- struct brcmf_cfg80211_vif *pri_vif;
-- unsigned long duration;
- s32 retry;
-
- brcmf_dbg(TRACE, "Enter\n");
-@@ -1150,7 +1149,6 @@ static s32 brcmf_p2p_af_searching_channe
- * pending action frame tx is cancelled.
- */
- retry = 0;
-- duration = msecs_to_jiffies(P2P_AF_FRM_SCAN_MAX_WAIT);
- while ((retry < P2P_CHANNEL_SYNC_RETRY) &&
- (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) {
- afx_hdl->is_listen = false;
-@@ -1158,7 +1156,8 @@ static s32 brcmf_p2p_af_searching_channe
- retry);
- /* search peer on peer's listen channel */
- schedule_work(&afx_hdl->afx_work);
-- wait_for_completion_timeout(&afx_hdl->act_frm_scan, duration);
-+ wait_for_completion_timeout(&afx_hdl->act_frm_scan,
-+ P2P_AF_FRM_SCAN_MAX_WAIT);
- if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
- (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
- &p2p->status)))
-@@ -1171,7 +1170,7 @@ static s32 brcmf_p2p_af_searching_channe
- afx_hdl->is_listen = true;
- schedule_work(&afx_hdl->afx_work);
- wait_for_completion_timeout(&afx_hdl->act_frm_scan,
-- duration);
-+ P2P_AF_FRM_SCAN_MAX_WAIT);
- }
- if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
- (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+++ /dev/null
-From fbf07000960d9c8a13fdc17c6de0230d681c7543 Mon Sep 17 00:00:00 2001
-From: Chung-Hsien Hsu <stanley.hsu@cypress.com>
-Date: Thu, 27 Sep 2018 14:59:49 +0000
-Subject: [PATCH] brcmfmac: fix full timeout waiting for action frame
- on-channel tx
-
-The driver sends an action frame down and waits for a completion signal
-triggered by the received BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE event
-to continue the process. However, the action frame could be transmitted
-either on the current channel or on an off channel. For the on-channel
-case, only BRCMF_E_ACTION_FRAME_COMPLETE event will be received when
-the frame is transmitted, which make the driver always wait a full
-timeout duration. This patch has the completion signal be triggered by
-receiving the BRCMF_E_ACTION_FRAME_COMPLETE event for the on-channel
-case.
-
-This change fixes WFA p2p certification 5.1.19 failure.
-
-Signed-off-by: Chung-Hsien Hsu <stanley.hsu@cypress.com>
-Signed-off-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 17 +++++++++++++++--
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h | 2 ++
- 2 files changed, 17 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
-@@ -1457,10 +1457,12 @@ int brcmf_p2p_notify_action_tx_complete(
- return 0;
-
- if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) {
-- if (e->status == BRCMF_E_STATUS_SUCCESS)
-+ if (e->status == BRCMF_E_STATUS_SUCCESS) {
- set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
- &p2p->status);
-- else {
-+ if (!p2p->wait_for_offchan_complete)
-+ complete(&p2p->send_af_done);
-+ } else {
- set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
- /* If there is no ack, we don't need to wait for
- * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event
-@@ -1511,6 +1513,17 @@ static s32 brcmf_p2p_tx_action_frame(str
- p2p->af_sent_channel = le32_to_cpu(af_params->channel);
- p2p->af_tx_sent_jiffies = jiffies;
-
-+ if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status) &&
-+ p2p->af_sent_channel ==
-+ ieee80211_frequency_to_channel(p2p->remain_on_channel.center_freq))
-+ p2p->wait_for_offchan_complete = false;
-+ else
-+ p2p->wait_for_offchan_complete = true;
-+
-+ brcmf_dbg(TRACE, "Waiting for %s tx completion event\n",
-+ (p2p->wait_for_offchan_complete) ?
-+ "off-channel" : "on-channel");
-+
- timeout = wait_for_completion_timeout(&p2p->send_af_done,
- P2P_AF_MAX_WAIT_TIME);
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
-@@ -124,6 +124,7 @@ struct afx_hdl {
- * @gon_req_action: about to send go negotiation requets frame.
- * @block_gon_req_tx: drop tx go negotiation requets frame.
- * @p2pdev_dynamically: is p2p device if created by module param or supplicant.
-+ * @wait_for_offchan_complete: wait for off-channel tx completion event.
- */
- struct brcmf_p2p_info {
- struct brcmf_cfg80211_info *cfg;
-@@ -144,6 +145,7 @@ struct brcmf_p2p_info {
- bool gon_req_action;
- bool block_gon_req_tx;
- bool p2pdev_dynamically;
-+ bool wait_for_offchan_complete;
- };
-
- s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced);
fwreq->bus_nr = devinfo->pdev->bus->number;
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -4185,6 +4185,7 @@ brcmf_sdio_prepare_fw_request(struct brc
+@@ -4174,6 +4174,7 @@ brcmf_sdio_prepare_fw_request(struct brc
fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1];
int deq_node_pos[BRCMF_FWS_FIFO_COUNT];
u32 fifo_credit_map;
-@@ -1241,6 +1242,9 @@ static void brcmf_fws_return_credits(str
+@@ -1237,6 +1238,9 @@ static void brcmf_fws_return_credits(str
}
fws->fifo_credit[fifo] += credits;
}
static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws)
-@@ -1599,19 +1603,21 @@ static int brcmf_fws_notify_credit_map(s
+@@ -1595,19 +1599,21 @@ static int brcmf_fws_notify_credit_map(s
brcmf_err("event payload too small (%d)\n", e->datalen);
return -EINVAL;
}
}
brcmf_fws_schedule_deq(fws);
brcmf_fws_unlock(fws);
-@@ -2017,7 +2023,7 @@ static int brcmf_fws_borrow_credit(struc
+@@ -2013,7 +2019,7 @@ static int brcmf_fws_borrow_credit(struc
}
for (lender_ac = 0; lender_ac <= BRCMF_FWS_FIFO_AC_VO; lender_ac++) {
fws->credits_borrowed[lender_ac]++;
fws->fifo_credit[lender_ac]--;
if (fws->fifo_credit[lender_ac] == 0)
-@@ -2216,8 +2222,9 @@ static void brcmf_fws_dequeue_worker(str
+@@ -2210,8 +2216,9 @@ static void brcmf_fws_dequeue_worker(str
}
continue;
}
skb = brcmf_fws_deq(fws, fifo);
if (!skb)
break;
-@@ -2228,7 +2235,7 @@ static void brcmf_fws_dequeue_worker(str
+@@ -2222,7 +2229,7 @@ static void brcmf_fws_dequeue_worker(str
break;
}
if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -6644,6 +6644,12 @@ static s32 brcmf_config_dongle(struct br
+@@ -6646,6 +6646,12 @@ static s32 brcmf_config_dongle(struct br
brcmf_configure_arp_nd_offload(ifp, true);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
-@@ -1459,9 +1459,10 @@ static int brcmf_fws_txstatus_suppressed
+@@ -1455,9 +1455,10 @@ static int brcmf_fws_txstatus_suppressed
static int
brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
int ret;
bool remove_from_hanger = true;
struct sk_buff *skb;
-@@ -1472,60 +1473,71 @@ brcmf_fws_txs_process(struct brcmf_fws_i
+@@ -1468,60 +1469,71 @@ brcmf_fws_txs_process(struct brcmf_fws_i
brcmf_dbg(DATA, "flags %d\n", flags);
if (flags == BRCMF_FWS_TXSTATUS_DISCARD)
return 0;
}
-@@ -1551,7 +1563,8 @@ static int brcmf_fws_fifocreditback_indi
+@@ -1547,7 +1559,8 @@ static int brcmf_fws_fifocreditback_indi
return BRCMF_FWS_RET_OK_SCHEDULE;
}
{
__le32 status_le;
__le16 seq_le;
-@@ -1560,23 +1573,31 @@ static int brcmf_fws_txstatus_indicate(s
+@@ -1556,23 +1569,31 @@ static int brcmf_fws_txstatus_indicate(s
u32 genbit;
u8 flags;
u16 seq;
brcmf_fws_unlock(fws);
return BRCMF_FWS_RET_OK_NOSCHEDULE;
}
-@@ -1892,8 +1913,6 @@ void brcmf_fws_hdrpull(struct brcmf_if *
+@@ -1888,8 +1909,6 @@ void brcmf_fws_hdrpull(struct brcmf_if *
err = BRCMF_FWS_RET_OK_NOSCHEDULE;
switch (type) {
case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
rd = (struct brcmf_skb_reorder_data *)skb->cb;
rd->reorder = data;
-@@ -1916,7 +1935,8 @@ void brcmf_fws_hdrpull(struct brcmf_if *
+@@ -1912,7 +1931,8 @@ void brcmf_fws_hdrpull(struct brcmf_if *
err = brcmf_fws_request_indicate(fws, type, data);
break;
case BRCMF_FWS_TYPE_TXSTATUS:
break;
case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
err = brcmf_fws_fifocreditback_indicate(fws, data);
-@@ -2005,7 +2025,7 @@ static void brcmf_fws_rollback_toq(struc
+@@ -2001,7 +2021,7 @@ static void brcmf_fws_rollback_toq(struc
fws->stats.rollback_failed++;
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED,
} else {
fws->stats.rollback_success++;
brcmf_fws_return_credits(fws, fifo, 1);
-@@ -2476,7 +2496,8 @@ void brcmf_fws_bustxfail(struct brcmf_fw
+@@ -2462,7 +2482,8 @@ void brcmf_fws_bustxfail(struct brcmf_fw
}
brcmf_fws_lock(fws);
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
/* Force SD->SB reset mapping (rev 11) */
#define SBSDIO_DEVCTL_SB_RST_CTL 0x30
/* Determined by CoreControl bit */
-@@ -4057,6 +4063,7 @@ static void brcmf_sdio_firmware_callback
+@@ -4046,6 +4052,7 @@ static void brcmf_sdio_firmware_callback
void *nvram;
u32 nvram_len;
u8 saveclk;
brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
-@@ -4112,8 +4119,23 @@ static void brcmf_sdio_firmware_callback
+@@ -4101,8 +4108,23 @@ static void brcmf_sdio_firmware_callback
brcmf_sdiod_writel(sdiod, core->base + SD_REG(hostintmask),
bus->hostintmask, NULL);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -4130,6 +4130,9 @@ static void brcmf_sdio_firmware_callback
+@@ -4119,6 +4119,9 @@ static void brcmf_sdio_firmware_callback
devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl,
&err);
};
static void pkt_align(struct sk_buff *p, int len, int align)
-@@ -683,6 +685,14 @@ brcmf_sdio_kso_control(struct brcmf_sdio
+@@ -677,6 +679,14 @@ brcmf_sdio_kso_control(struct brcmf_sdio
/* 1st KSO write goes to AOS wake up core if device is asleep */
brcmf_sdiod_writeb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
if (on) {
/* device WAKEUP through KSO:
* write bit 0 & read back until
-@@ -2413,6 +2423,14 @@ static int brcmf_sdio_tx_ctrlframe(struc
+@@ -2402,6 +2412,14 @@ static int brcmf_sdio_tx_ctrlframe(struc
return ret;
}
static void brcmf_sdio_bus_stop(struct device *dev)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-@@ -2420,7 +2438,7 @@ static void brcmf_sdio_bus_stop(struct d
+@@ -2409,7 +2427,7 @@ static void brcmf_sdio_bus_stop(struct d
struct brcmf_sdio *bus = sdiodev->bus;
struct brcmf_core *core = bus->sdio_core;
u32 local_hostintmask;
int err;
brcmf_dbg(TRACE, "Enter\n");
-@@ -2447,9 +2465,14 @@ static void brcmf_sdio_bus_stop(struct d
+@@ -2436,9 +2454,14 @@ static void brcmf_sdio_bus_stop(struct d
/* Force backplane clocks to assure F2 interrupt propagates */
saveclk = brcmf_sdiod_readb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
&err);
if (err)
brcmf_err("Failed to force clock for F2: err %d\n",
err);
-@@ -3339,20 +3362,45 @@ err:
+@@ -3328,20 +3351,45 @@ err:
return bcmerror;
}
brcmf_sdiod_writeb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, val, &err);
if (err) {
brcmf_err("error writing SBSDIO_FUNC1_WAKEUPCTRL\n");
-@@ -3361,8 +3409,7 @@ static void brcmf_sdio_sr_init(struct br
+@@ -3350,8 +3398,7 @@ static void brcmf_sdio_sr_init(struct br
/* Add CMD14 Support */
brcmf_sdiod_func0_wb(bus->sdiodev, SDIO_CCCR_BRCM_CARDCAP,
&err);
if (err) {
brcmf_err("error writing SDIO_CCCR_BRCM_CARDCAP\n");
-@@ -3370,7 +3417,7 @@ static void brcmf_sdio_sr_init(struct br
+@@ -3359,7 +3406,7 @@ static void brcmf_sdio_sr_init(struct br
}
brcmf_sdiod_writeb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
if (err) {
brcmf_err("error writing SBSDIO_FUNC1_CHIPCLKCSR\n");
return;
-@@ -4062,7 +4109,7 @@ static void brcmf_sdio_firmware_callback
+@@ -4051,7 +4098,7 @@ static void brcmf_sdio_firmware_callback
const struct firmware *code;
void *nvram;
u32 nvram_len;
u8 devctl;
brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
-@@ -4096,8 +4143,11 @@ static void brcmf_sdio_firmware_callback
+@@ -4085,8 +4132,11 @@ static void brcmf_sdio_firmware_callback
/* Force clocks on backplane to be sure F2 interrupt propagates */
saveclk = brcmf_sdiod_readb(sdiod, SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (!err) {
#ifdef DEBUG
-@@ -4184,6 +4185,17 @@ static void brcmf_sdio_firmware_callback
+@@ -4173,6 +4174,17 @@ static void brcmf_sdio_firmware_callback
CY_4373_F2_WATERMARK |
SBSDIO_MESBUSYCTRL_ENAB, &err);
break;
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -3365,7 +3365,11 @@ err:
+@@ -3354,7 +3354,11 @@ err:
static bool brcmf_sdio_aos_no_decode(struct brcmf_sdio *bus)
{
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -6314,6 +6314,16 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
+@@ -6316,6 +6316,16 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
-@@ -1557,6 +1557,10 @@ void brcmf_usb_exit(void)
+@@ -1552,6 +1552,10 @@ void brcmf_usb_exit(void)
void brcmf_usb_register(void)
{
return -EINVAL;
}
} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
-@@ -1650,8 +1670,8 @@ brcmf_set_key_mgmt(struct net_device *nd
- val = WPA2_AUTH_PSK;
+@@ -1658,8 +1678,8 @@ brcmf_set_key_mgmt(struct net_device *nd
+ val = WPA2_AUTH_PSK | WPA2_AUTH_FT;
break;
default:
- brcmf_err("invalid cipher group (%d)\n",
return -EINVAL;
}
}
-@@ -1697,7 +1717,7 @@ skip_mfp_config:
+@@ -1705,7 +1725,7 @@ skip_mfp_config:
brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
if (err) {
return err;
}
-@@ -1708,6 +1728,8 @@ static s32
+@@ -1716,6 +1736,8 @@ static s32
brcmf_set_sharedkey(struct net_device *ndev,
struct cfg80211_connect_params *sme)
{
struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
struct brcmf_cfg80211_security *sec;
struct brcmf_wsec_key key;
-@@ -1734,7 +1756,7 @@ brcmf_set_sharedkey(struct net_device *n
+@@ -1742,7 +1764,7 @@ brcmf_set_sharedkey(struct net_device *n
key.len = (u32) sme->key_len;
key.index = (u32) sme->key_idx;
if (key.len > sizeof(key.data)) {
return -EINVAL;
}
memcpy(key.data, sme->key, key.len);
-@@ -1747,24 +1769,24 @@ brcmf_set_sharedkey(struct net_device *n
+@@ -1755,24 +1777,24 @@ brcmf_set_sharedkey(struct net_device *n
key.algo = CRYPTO_ALGO_WEP128;
break;
default:
}
return err;
}
-@@ -1784,6 +1806,7 @@ enum nl80211_auth_type brcmf_war_auth_ty
+@@ -1792,6 +1814,7 @@ enum nl80211_auth_type brcmf_war_auth_ty
static void brcmf_set_join_pref(struct brcmf_if *ifp,
struct cfg80211_bss_selection *bss_select)
{
struct brcmf_join_pref_params join_pref_params[2];
enum nl80211_band band;
int err, i = 0;
-@@ -1822,7 +1845,7 @@ static void brcmf_set_join_pref(struct b
+@@ -1830,7 +1853,7 @@ static void brcmf_set_join_pref(struct b
err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
sizeof(join_pref_params));
if (err)
}
static s32
-@@ -1849,7 +1872,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
+@@ -1857,7 +1880,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
return -EIO;
if (!sme->ssid) {
return -EOPNOTSUPP;
}
-@@ -1878,7 +1901,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
+@@ -1886,7 +1909,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
sme->ie, sme->ie_len);
if (err)
else
brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
-@@ -1899,32 +1922,32 @@ brcmf_cfg80211_connect(struct wiphy *wip
+@@ -1907,32 +1930,32 @@ brcmf_cfg80211_connect(struct wiphy *wip
err = brcmf_set_wpa_version(ndev, sme);
if (err) {
goto done;
}
-@@ -1941,7 +1964,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
+@@ -1949,7 +1972,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
/* enable firmware supplicant for this interface */
err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
if (err < 0) {
goto done;
}
}
-@@ -2036,7 +2059,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
+@@ -2044,7 +2067,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
&join_params, join_params_size);
if (err)
done:
if (err)
-@@ -2067,7 +2090,7 @@ brcmf_cfg80211_disconnect(struct wiphy *
+@@ -2075,7 +2098,7 @@ brcmf_cfg80211_disconnect(struct wiphy *
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
&scbval, sizeof(scbval));
if (err)
brcmf_dbg(TRACE, "Exit\n");
return err;
-@@ -2094,7 +2117,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy
+@@ -2102,7 +2125,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy
case NL80211_TX_POWER_LIMITED:
case NL80211_TX_POWER_FIXED:
if (mbm < 0) {
err = -EINVAL;
goto done;
}
-@@ -2104,7 +2127,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy
+@@ -2112,7 +2135,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy
qdbm |= WL_TXPWR_OVERRIDE;
break;
default:
err = -EINVAL;
goto done;
}
-@@ -2112,11 +2135,11 @@ brcmf_cfg80211_set_tx_power(struct wiphy
+@@ -2120,11 +2143,11 @@ brcmf_cfg80211_set_tx_power(struct wiphy
disable = WL_RADIO_SW_DISABLE << 16;
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
if (err)
done:
brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
-@@ -2137,7 +2160,7 @@ brcmf_cfg80211_get_tx_power(struct wiphy
+@@ -2145,7 +2168,7 @@ brcmf_cfg80211_get_tx_power(struct wiphy
err = brcmf_fil_iovar_int_get(vif->ifp, "qtxpower", &qdbm);
if (err) {
goto done;
}
*dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
-@@ -2163,7 +2186,7 @@ brcmf_cfg80211_config_default_key(struct
+@@ -2171,7 +2194,7 @@ brcmf_cfg80211_config_default_key(struct
err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
if (err) {
goto done;
}
-@@ -2173,7 +2196,7 @@ brcmf_cfg80211_config_default_key(struct
+@@ -2181,7 +2204,7 @@ brcmf_cfg80211_config_default_key(struct
err = brcmf_fil_cmd_int_set(ifp,
BRCMF_C_SET_KEY_PRIMARY, index);
if (err)
}
done:
brcmf_dbg(TRACE, "Exit\n");
-@@ -2237,7 +2260,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
+@@ -2245,7 +2268,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
/* we ignore this key index in this case */
return -EINVAL;
}
-@@ -2246,7 +2269,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
+@@ -2254,7 +2277,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
mac_addr);
if (params->key_len > sizeof(key->data)) {
return -EINVAL;
}
-@@ -2300,7 +2323,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
+@@ -2308,7 +2331,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
break;
default:
err = -EINVAL;
goto done;
}
-@@ -2311,13 +2334,13 @@ brcmf_cfg80211_add_key(struct wiphy *wip
+@@ -2319,13 +2342,13 @@ brcmf_cfg80211_add_key(struct wiphy *wip
err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
if (err) {
goto done;
}
-@@ -2348,7 +2371,7 @@ brcmf_cfg80211_get_key(struct wiphy *wip
+@@ -2356,7 +2379,7 @@ brcmf_cfg80211_get_key(struct wiphy *wip
err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
if (err) {
/* Ignore this error, may happen during DISASSOC */
err = -EAGAIN;
goto done;
-@@ -2369,7 +2392,7 @@ brcmf_cfg80211_get_key(struct wiphy *wip
+@@ -2377,7 +2400,7 @@ brcmf_cfg80211_get_key(struct wiphy *wip
params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
} else {
err = -EINVAL;
goto done;
}
-@@ -2399,6 +2422,7 @@ brcmf_cfg80211_config_default_mgmt_key(s
+@@ -2407,6 +2430,7 @@ brcmf_cfg80211_config_default_mgmt_key(s
static void
brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
{
s32 err;
u8 key_idx;
struct brcmf_wsec_key *key;
-@@ -2415,18 +2439,18 @@ brcmf_cfg80211_reconfigure_wep(struct br
+@@ -2423,18 +2447,18 @@ brcmf_cfg80211_reconfigure_wep(struct br
err = send_key_to_dongle(ifp, key);
if (err) {
}
static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
-@@ -2452,6 +2476,7 @@ static void brcmf_convert_sta_flags(u32
+@@ -2460,6 +2484,7 @@ static void brcmf_convert_sta_flags(u32
static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
{
struct {
__le32 len;
struct brcmf_bss_info_le bss_le;
-@@ -2467,7 +2492,7 @@ static void brcmf_fill_bss_param(struct
+@@ -2475,7 +2500,7 @@ static void brcmf_fill_bss_param(struct
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
WL_BSS_INFO_MAX);
if (err) {
goto out_kfree;
}
si->filled |= BIT_ULL(NL80211_STA_INFO_BSS_PARAM);
-@@ -2489,6 +2514,7 @@ static s32
+@@ -2497,6 +2522,7 @@ static s32
brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
struct station_info *sinfo)
{
struct brcmf_scb_val_le scbval;
struct brcmf_pktcnt_le pktcnt;
s32 err;
-@@ -2498,7 +2524,7 @@ brcmf_cfg80211_get_station_ibss(struct b
+@@ -2506,7 +2532,7 @@ brcmf_cfg80211_get_station_ibss(struct b
/* Get the current tx rate */
err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
if (err < 0) {
return err;
}
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
-@@ -2508,7 +2534,7 @@ brcmf_cfg80211_get_station_ibss(struct b
+@@ -2516,7 +2542,7 @@ brcmf_cfg80211_get_station_ibss(struct b
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
sizeof(scbval));
if (err) {
return err;
}
rssi = le32_to_cpu(scbval.val);
-@@ -2518,7 +2544,7 @@ brcmf_cfg80211_get_station_ibss(struct b
+@@ -2526,7 +2552,7 @@ brcmf_cfg80211_get_station_ibss(struct b
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
sizeof(pktcnt));
if (err) {
return err;
}
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS) |
-@@ -2566,7 +2592,7 @@ brcmf_cfg80211_get_station(struct wiphy
+@@ -2574,7 +2600,7 @@ brcmf_cfg80211_get_station(struct wiphy
&sta_info_le,
sizeof(sta_info_le));
if (err < 0) {
goto done;
}
}
-@@ -2635,7 +2661,8 @@ brcmf_cfg80211_get_station(struct wiphy
+@@ -2643,7 +2669,8 @@ brcmf_cfg80211_get_station(struct wiphy
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
&scb_val, sizeof(scb_val));
if (err) {
goto done;
} else {
rssi = le32_to_cpu(scb_val.val);
-@@ -2666,8 +2693,8 @@ brcmf_cfg80211_dump_station(struct wiphy
+@@ -2674,8 +2701,8 @@ brcmf_cfg80211_dump_station(struct wiphy
&cfg->assoclist,
sizeof(cfg->assoclist));
if (err) {
cfg->assoclist.count = 0;
return -EOPNOTSUPP;
}
-@@ -2715,9 +2742,9 @@ brcmf_cfg80211_set_power_mgmt(struct wip
+@@ -2723,9 +2750,9 @@ brcmf_cfg80211_set_power_mgmt(struct wip
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
if (err) {
if (err == -ENODEV)
}
done:
brcmf_dbg(TRACE, "Exit\n");
-@@ -2740,7 +2767,7 @@ static s32 brcmf_inform_single_bss(struc
+@@ -2748,7 +2775,7 @@ static s32 brcmf_inform_single_bss(struc
struct cfg80211_inform_bss bss_data = {};
if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
return 0;
}
-@@ -2799,6 +2826,7 @@ next_bss_le(struct brcmf_scan_results *l
+@@ -2807,6 +2834,7 @@ next_bss_le(struct brcmf_scan_results *l
static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
{
struct brcmf_scan_results *bss_list;
struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
s32 err = 0;
-@@ -2807,8 +2835,8 @@ static s32 brcmf_inform_bss(struct brcmf
+@@ -2815,8 +2843,8 @@ static s32 brcmf_inform_bss(struct brcmf
bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
if (bss_list->count != 0 &&
bss_list->version != BRCMF_BSS_INFO_VERSION) {
return -EOPNOTSUPP;
}
brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
-@@ -2852,7 +2880,7 @@ static s32 brcmf_inform_ibss(struct brcm
+@@ -2860,7 +2888,7 @@ static s32 brcmf_inform_ibss(struct brcm
err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
buf, WL_BSS_INFO_MAX);
if (err) {
goto CleanUp;
}
-@@ -2906,6 +2934,7 @@ CleanUp:
+@@ -2914,6 +2942,7 @@ CleanUp:
static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp)
{
struct brcmf_bss_info_le *bi;
const struct brcmf_tlv *tim;
u16 beacon_interval;
-@@ -2922,7 +2951,7 @@ static s32 brcmf_update_bss_info(struct
+@@ -2930,7 +2959,7 @@ static s32 brcmf_update_bss_info(struct
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
cfg->extra_buf, WL_EXTRA_BUF_MAX);
if (err) {
goto update_bss_info_out;
}
-@@ -2947,7 +2976,7 @@ static s32 brcmf_update_bss_info(struct
+@@ -2955,7 +2984,7 @@ static s32 brcmf_update_bss_info(struct
u32 var;
err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
if (err) {
goto update_bss_info_out;
}
dtim_period = (u8)var;
-@@ -2985,9 +3014,10 @@ static void brcmf_escan_timeout(struct t
+@@ -2993,9 +3022,10 @@ static void brcmf_escan_timeout(struct t
{
struct brcmf_cfg80211_info *cfg =
from_timer(cfg, t, escan_timeout);
schedule_work(&cfg->escan_timeout_work);
}
}
-@@ -3036,6 +3066,7 @@ brcmf_cfg80211_escan_handler(struct brcm
+@@ -3044,6 +3074,7 @@ brcmf_cfg80211_escan_handler(struct brcm
const struct brcmf_event_msg *e, void *data)
{
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
s32 status;
struct brcmf_escan_result_le *escan_result_le;
u32 escan_buflen;
-@@ -3052,32 +3083,33 @@ brcmf_cfg80211_escan_handler(struct brcm
+@@ -3060,32 +3091,33 @@ brcmf_cfg80211_escan_handler(struct brcm
goto exit;
if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
goto exit;
}
bss_info_le = &escan_result_le->bss_info_le;
-@@ -3092,8 +3124,8 @@ brcmf_cfg80211_escan_handler(struct brcm
+@@ -3100,8 +3132,8 @@ brcmf_cfg80211_escan_handler(struct brcm
bi_length = le32_to_cpu(bss_info_le->length);
if (bi_length != escan_buflen - WL_ESCAN_RESULTS_FIXED_SIZE) {
goto exit;
}
-@@ -3101,7 +3133,7 @@ brcmf_cfg80211_escan_handler(struct brcm
+@@ -3109,7 +3141,7 @@ brcmf_cfg80211_escan_handler(struct brcm
BIT(NL80211_IFTYPE_ADHOC))) {
if (le16_to_cpu(bss_info_le->capability) &
WLAN_CAPABILITY_IBSS) {
goto exit;
}
}
-@@ -3109,7 +3141,7 @@ brcmf_cfg80211_escan_handler(struct brcm
+@@ -3117,7 +3149,7 @@ brcmf_cfg80211_escan_handler(struct brcm
list = (struct brcmf_scan_results *)
cfg->escan_info.escan_buf;
if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
goto exit;
}
-@@ -3301,14 +3333,14 @@ brcmf_notify_sched_scan_results(struct b
+@@ -3309,14 +3341,14 @@ brcmf_notify_sched_scan_results(struct b
WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
if (!result_count) {
goto out_err;
}
-@@ -3362,8 +3394,8 @@ brcmf_cfg80211_sched_scan_start(struct w
+@@ -3370,8 +3402,8 @@ brcmf_cfg80211_sched_scan_start(struct w
req->n_match_sets, req->n_ssids);
if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
return -EAGAIN;
}
-@@ -3442,6 +3474,7 @@ brcmf_wowl_nd_results(struct brcmf_if *i
+@@ -3450,6 +3482,7 @@ brcmf_wowl_nd_results(struct brcmf_if *i
void *data)
{
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
struct brcmf_pno_scanresults_le *pfn_result;
struct brcmf_pno_net_info_le *netinfo;
-@@ -3460,8 +3493,8 @@ brcmf_wowl_nd_results(struct brcmf_if *i
+@@ -3468,8 +3501,8 @@ brcmf_wowl_nd_results(struct brcmf_if *i
}
if (le32_to_cpu(pfn_result->count) < 1) {
return -EINVAL;
}
-@@ -3500,7 +3533,7 @@ static void brcmf_report_wowl_wakeind(st
+@@ -3506,7 +3539,7 @@ static void brcmf_report_wowl_wakeind(st
err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
sizeof(wake_ind_le));
if (err) {
return;
}
-@@ -3541,7 +3574,7 @@ static void brcmf_report_wowl_wakeind(st
+@@ -3547,7 +3580,7 @@ static void brcmf_report_wowl_wakeind(st
cfg->wowl.nd_data_completed,
BRCMF_ND_INFO_TIMEOUT);
if (!timeout)
else
wakeup_data.net_detect = cfg->wowl.nd_info;
}
-@@ -3749,7 +3782,7 @@ brcmf_cfg80211_set_pmksa(struct wiphy *w
+@@ -3755,7 +3788,7 @@ brcmf_cfg80211_set_pmksa(struct wiphy *w
cfg->pmk_list.npmk = cpu_to_le32(npmk);
}
} else {
return -EINVAL;
}
-@@ -3795,7 +3828,7 @@ brcmf_cfg80211_del_pmksa(struct wiphy *w
+@@ -3801,7 +3834,7 @@ brcmf_cfg80211_del_pmksa(struct wiphy *w
memset(&pmk[i], 0, sizeof(*pmk));
cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
} else {
return -EINVAL;
}
-@@ -3827,19 +3860,20 @@ brcmf_cfg80211_flush_pmksa(struct wiphy
+@@ -3833,19 +3866,20 @@ brcmf_cfg80211_flush_pmksa(struct wiphy
static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
{
return err;
}
/* set upper-layer auth */
-@@ -3849,7 +3883,7 @@ static s32 brcmf_configure_opensecurity(
+@@ -3855,7 +3889,7 @@ static s32 brcmf_configure_opensecurity(
wpa_val = WPA_AUTH_DISABLED;
err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_val);
if (err < 0) {
return err;
}
-@@ -3869,6 +3903,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -3875,6 +3909,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
const struct brcmf_vs_tlv *wpa_ie,
bool is_rsn_ie)
{
u32 auth = 0; /* d11 open authentication */
u16 count;
s32 err = 0;
-@@ -3899,13 +3934,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -3905,13 +3940,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
/* check for multicast cipher suite */
if (offset + WPA_IE_MIN_OUI_LEN > len) {
err = -EINVAL;
goto exit;
}
offset += TLV_OUI_LEN;
-@@ -3927,7 +3962,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -3933,7 +3968,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
break;
default:
err = -EINVAL;
goto exit;
}
-@@ -3938,13 +3973,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -3944,13 +3979,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
/* Check for unicast suite(s) */
if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
err = -EINVAL;
goto exit;
}
offset += TLV_OUI_LEN;
-@@ -3962,7 +3997,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -3968,7 +4003,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
pval |= AES_ENABLED;
break;
default:
}
offset++;
}
-@@ -3972,13 +4007,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -3978,13 +4013,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
/* Check for auth key management suite(s) */
if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
err = -EINVAL;
goto exit;
}
offset += TLV_OUI_LEN;
-@@ -4006,7 +4041,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4012,7 +4047,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
wpa_auth |= WPA2_AUTH_1X_SHA256;
break;
default:
}
offset++;
}
-@@ -4048,7 +4083,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4054,7 +4089,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
wme_bss_disable);
if (err < 0) {
goto exit;
}
-@@ -4062,7 +4097,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4068,7 +4103,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
&data[offset],
WPA_IE_MIN_OUI_LEN);
if (err < 0) {
goto exit;
}
}
-@@ -4073,13 +4108,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4079,13 +4114,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
/* set auth */
err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
if (err < 0) {
goto exit;
}
/* Configure MFP, this needs to go after wsec otherwise the wsec command
-@@ -4088,14 +4123,14 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4094,14 +4129,14 @@ brcmf_configure_wpaie(struct brcmf_if *i
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
if (err < 0) {
goto exit;
}
-@@ -4182,6 +4217,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
+@@ -4188,6 +4223,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
const u8 *vndr_ie_buf, u32 vndr_ie_len)
{
struct brcmf_if *ifp;
struct vif_saved_ie *saved_ie;
s32 err = 0;
u8 *iovar_ie_buf;
-@@ -4202,6 +4238,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
+@@ -4208,6 +4244,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
if (!vif)
return -ENODEV;
ifp = vif->ifp;
saved_ie = &vif->saved_ie;
brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
-@@ -4233,13 +4270,13 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
+@@ -4239,13 +4276,13 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
break;
default:
err = -EPERM;
goto exit;
}
-@@ -4300,8 +4337,8 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
+@@ -4306,8 +4343,8 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
/* verify remained buf size before copy data */
if (remained_buf_len < (vndrie_info->vndrie.len +
VNDR_IE_VSIE_OFFSET)) {
break;
}
remained_buf_len -= (vndrie_info->ie_len +
-@@ -4332,7 +4369,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
+@@ -4338,7 +4375,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
total_ie_buf_len);
if (err)
}
exit:
-@@ -4360,13 +4397,14 @@ static s32
+@@ -4366,13 +4403,14 @@ static s32
brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
struct cfg80211_beacon_data *beacon)
{
return err;
}
brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
-@@ -4376,7 +4414,7 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg
+@@ -4382,7 +4420,7 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg
beacon->proberesp_ies,
beacon->proberesp_ies_len);
if (err)
else
brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
-@@ -4485,7 +4523,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4491,7 +4529,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
is_11d);
if (err < 0) {
goto exit;
}
}
-@@ -4493,8 +4532,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4499,8 +4538,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
settings->beacon_interval);
if (err < 0) {
goto exit;
}
}
-@@ -4502,7 +4541,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4508,7 +4547,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
settings->dtim_period);
if (err < 0) {
goto exit;
}
}
-@@ -4512,7 +4552,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4518,7 +4558,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
if (err < 0) {
goto exit;
}
brcmf_fil_iovar_int_set(ifp, "apsta", 0);
-@@ -4520,7 +4561,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4526,7 +4567,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
if (err < 0) {
goto exit;
}
} else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
-@@ -4536,7 +4577,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4542,7 +4583,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
if (err < 0) {
goto exit;
}
if (!mbss) {
-@@ -4545,14 +4587,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4551,14 +4593,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
*/
err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
if (err < 0) {
goto exit;
}
/* On DOWN the firmware removes the WEP keys, reconfigure
-@@ -4567,14 +4609,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4573,14 +4615,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
&join_params, sizeof(join_params));
if (err < 0) {
goto exit;
}
}
-@@ -4583,14 +4625,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4589,14 +4631,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
} else if (dev_role == NL80211_IFTYPE_P2P_GO) {
err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
if (err < 0) {
goto exit;
}
bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
-@@ -4598,7 +4640,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4604,7 +4646,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
sizeof(bss_enable));
if (err < 0) {
goto exit;
}
-@@ -4646,13 +4688,13 @@ static int brcmf_cfg80211_stop_ap(struct
+@@ -4652,13 +4694,13 @@ static int brcmf_cfg80211_stop_ap(struct
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
&join_params, sizeof(join_params));
if (err < 0)
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
brcmf_fil_iovar_int_set(ifp, "mbss", 0);
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
-@@ -4660,7 +4702,7 @@ static int brcmf_cfg80211_stop_ap(struct
+@@ -4666,7 +4708,7 @@ static int brcmf_cfg80211_stop_ap(struct
/* Bring device back up so it can be used again */
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
if (err < 0)
brcmf_vif_clear_mgmt_ies(ifp->vif);
} else {
-@@ -4669,7 +4711,7 @@ static int brcmf_cfg80211_stop_ap(struct
+@@ -4675,7 +4717,7 @@ static int brcmf_cfg80211_stop_ap(struct
err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
sizeof(bss_enable));
if (err < 0)
}
brcmf_set_mpc(ifp, 1);
brcmf_configure_arp_nd_offload(ifp, true);
-@@ -4717,7 +4759,8 @@ brcmf_cfg80211_del_station(struct wiphy
+@@ -4723,7 +4765,8 @@ brcmf_cfg80211_del_station(struct wiphy
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
&scbval, sizeof(scbval));
if (err)
brcmf_dbg(TRACE, "Exit\n");
return err;
-@@ -4747,7 +4790,7 @@ brcmf_cfg80211_change_station(struct wip
+@@ -4753,7 +4796,7 @@ brcmf_cfg80211_change_station(struct wip
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
(void *)mac, ETH_ALEN);
if (err < 0)
return err;
}
-@@ -4797,7 +4840,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wip
+@@ -4803,7 +4846,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wip
mgmt = (const struct ieee80211_mgmt *)buf;
if (!ieee80211_is_mgmt(mgmt->frame_control)) {
return -EPERM;
}
-@@ -4828,13 +4871,13 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wip
+@@ -4834,13 +4877,13 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wip
GFP_KERNEL);
} else if (ieee80211_is_action(mgmt->frame_control)) {
if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) {
err = -ENOMEM;
goto exit;
}
-@@ -4892,7 +4935,7 @@ brcmf_cfg80211_cancel_remain_on_channel(
+@@ -4898,7 +4941,7 @@ brcmf_cfg80211_cancel_remain_on_channel(
vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
if (vif == NULL) {
err = -ENODEV;
goto exit;
}
-@@ -4920,7 +4963,7 @@ static int brcmf_cfg80211_get_channel(st
+@@ -4926,7 +4969,7 @@ static int brcmf_cfg80211_get_channel(st
err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
if (err) {
return err;
}
-@@ -5059,7 +5102,7 @@ static int brcmf_cfg80211_tdls_oper(stru
+@@ -5065,7 +5108,7 @@ static int brcmf_cfg80211_tdls_oper(stru
ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
&info, sizeof(info));
if (ret < 0)
return ret;
}
-@@ -5080,7 +5123,7 @@ brcmf_cfg80211_update_conn_params(struct
+@@ -5086,7 +5129,7 @@ brcmf_cfg80211_update_conn_params(struct
err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
sme->ie, sme->ie_len);
if (err)
else
brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
-@@ -5106,7 +5149,7 @@ brcmf_cfg80211_set_rekey_data(struct wip
+@@ -5112,7 +5155,7 @@ brcmf_cfg80211_set_rekey_data(struct wip
ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", >k_le,
sizeof(gtk_le));
if (ret < 0)
return ret;
}
-@@ -5338,6 +5381,7 @@ static void brcmf_clear_assoc_ies(struct
+@@ -5344,6 +5387,7 @@ static void brcmf_clear_assoc_ies(struct
static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp)
{
struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
u32 req_len;
-@@ -5349,7 +5393,7 @@ static s32 brcmf_get_assoc_ies(struct br
+@@ -5355,7 +5399,7 @@ static s32 brcmf_get_assoc_ies(struct br
err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
cfg->extra_buf, WL_ASSOC_INFO_MAX);
if (err) {
return err;
}
assoc_info =
-@@ -5361,7 +5405,7 @@ static s32 brcmf_get_assoc_ies(struct br
+@@ -5367,7 +5411,7 @@ static s32 brcmf_get_assoc_ies(struct br
cfg->extra_buf,
WL_ASSOC_INFO_MAX);
if (err) {
return err;
}
conn_info->req_ie_len = req_len;
-@@ -5379,7 +5423,7 @@ static s32 brcmf_get_assoc_ies(struct br
+@@ -5383,7 +5427,7 @@ static s32 brcmf_get_assoc_ies(struct br
cfg->extra_buf,
WL_ASSOC_INFO_MAX);
if (err) {
return err;
}
conn_info->resp_ie_len = resp_len;
-@@ -5508,6 +5552,7 @@ brcmf_notify_connect_status_ap(struct br
+@@ -5510,6 +5554,7 @@ brcmf_notify_connect_status_ap(struct br
struct net_device *ndev,
const struct brcmf_event_msg *e, void *data)
{
static int generation;
u32 event = e->event_code;
u32 reason = e->reason;
-@@ -5525,7 +5570,7 @@ brcmf_notify_connect_status_ap(struct br
+@@ -5527,7 +5572,7 @@ brcmf_notify_connect_status_ap(struct br
if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
(reason == BRCMF_E_STATUS_SUCCESS)) {
if (!data) {
return -EINVAL;
}
-@@ -5817,6 +5862,7 @@ static void init_vif_event(struct brcmf_
+@@ -5819,6 +5864,7 @@ static void init_vif_event(struct brcmf_
static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
{
s32 err;
u32 bcn_timeout;
__le32 roamtrigger[2];
-@@ -5829,7 +5875,7 @@ static s32 brcmf_dongle_roam(struct brcm
+@@ -5831,7 +5877,7 @@ static s32 brcmf_dongle_roam(struct brcm
bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
if (err) {
goto roam_setup_done;
}
-@@ -5841,7 +5887,7 @@ static s32 brcmf_dongle_roam(struct brcm
+@@ -5843,7 +5889,7 @@ static s32 brcmf_dongle_roam(struct brcm
err = brcmf_fil_iovar_int_set(ifp, "roam_off",
ifp->drvr->settings->roamoff);
if (err) {
goto roam_setup_done;
}
-@@ -5850,7 +5896,7 @@ static s32 brcmf_dongle_roam(struct brcm
+@@ -5852,7 +5898,7 @@ static s32 brcmf_dongle_roam(struct brcm
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
(void *)roamtrigger, sizeof(roamtrigger));
if (err) {
goto roam_setup_done;
}
-@@ -5859,7 +5905,7 @@ static s32 brcmf_dongle_roam(struct brcm
+@@ -5861,7 +5907,7 @@ static s32 brcmf_dongle_roam(struct brcm
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
(void *)roam_delta, sizeof(roam_delta));
if (err) {
goto roam_setup_done;
}
-@@ -5870,25 +5916,26 @@ roam_setup_done:
+@@ -5872,25 +5918,26 @@ roam_setup_done:
static s32
brcmf_dongle_scantime(struct brcmf_if *ifp)
{
goto dongle_scantime_out;
}
-@@ -5920,10 +5967,10 @@ static void brcmf_update_bw40_channel_fl
+@@ -5922,10 +5969,10 @@ static void brcmf_update_bw40_channel_fl
static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
u32 bw_cap[])
{
struct brcmf_chanspec_list *list;
struct brcmu_chan ch;
int err;
-@@ -5942,11 +5989,10 @@ static int brcmf_construct_chaninfo(stru
+@@ -5944,11 +5991,10 @@ static int brcmf_construct_chaninfo(stru
err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
BRCMF_DCMD_MEDLEN);
if (err) {
band = wiphy->bands[NL80211_BAND_2GHZ];
if (band)
for (i = 0; i < band->n_channels; i++)
-@@ -5966,7 +6012,8 @@ static int brcmf_construct_chaninfo(stru
+@@ -5968,7 +6014,8 @@ static int brcmf_construct_chaninfo(stru
} else if (ch.band == BRCMU_CHAN_BAND_5G) {
band = wiphy->bands[NL80211_BAND_5GHZ];
} else {
continue;
}
if (!band)
-@@ -5989,8 +6036,8 @@ static int brcmf_construct_chaninfo(stru
+@@ -5991,8 +6038,8 @@ static int brcmf_construct_chaninfo(stru
/* It seems firmware supports some channel we never
* considered. Something new in IEEE standard?
*/
continue;
}
-@@ -6036,6 +6083,7 @@ fail_pbuf:
+@@ -6038,6 +6085,7 @@ fail_pbuf:
static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
{
struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
struct ieee80211_supported_band *band;
struct brcmf_fil_bwcap_le band_bwcap;
-@@ -6082,7 +6130,7 @@ static int brcmf_enable_bw40_2g(struct b
+@@ -6084,7 +6132,7 @@ static int brcmf_enable_bw40_2g(struct b
err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
BRCMF_DCMD_MEDLEN);
if (err) {
kfree(pbuf);
return err;
}
-@@ -6113,6 +6161,7 @@ static int brcmf_enable_bw40_2g(struct b
+@@ -6115,6 +6163,7 @@ static int brcmf_enable_bw40_2g(struct b
static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
{
u32 band, mimo_bwcap;
int err;
-@@ -6148,7 +6197,7 @@ static void brcmf_get_bwcap(struct brcmf
+@@ -6150,7 +6199,7 @@ static void brcmf_get_bwcap(struct brcmf
bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
break;
default:
}
}
-@@ -6224,7 +6273,7 @@ static void brcmf_update_vht_cap(struct
+@@ -6226,7 +6275,7 @@ static void brcmf_update_vht_cap(struct
static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg)
{
struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
u32 nmode = 0;
u32 vhtmode = 0;
u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
-@@ -6240,7 +6289,7 @@ static int brcmf_setup_wiphybands(struct
+@@ -6242,7 +6291,7 @@ static int brcmf_setup_wiphybands(struct
(void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
if (err) {
} else {
brcmf_get_bwcap(ifp, bw_cap);
}
-@@ -6250,7 +6299,7 @@ static int brcmf_setup_wiphybands(struct
+@@ -6252,7 +6301,7 @@ static int brcmf_setup_wiphybands(struct
err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
if (err) {
nchain = 1;
} else {
for (nchain = 0; rxchain; nchain++)
-@@ -6260,7 +6309,7 @@ static int brcmf_setup_wiphybands(struct
+@@ -6262,7 +6311,7 @@ static int brcmf_setup_wiphybands(struct
err = brcmf_construct_chaninfo(cfg, bw_cap);
if (err) {
return err;
}
-@@ -6272,7 +6321,6 @@ static int brcmf_setup_wiphybands(struct
+@@ -6274,7 +6323,6 @@ static int brcmf_setup_wiphybands(struct
&txbf_bfr_cap);
}
for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
band = wiphy->bands[i];
if (band == NULL)
-@@ -6473,7 +6521,7 @@ static void brcmf_wiphy_wowl_params(stru
+@@ -6475,7 +6523,7 @@ static void brcmf_wiphy_wowl_params(stru
wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support),
GFP_KERNEL);
if (!wowl) {
wiphy->wowlan = &brcmf_wowlan_support;
return;
}
-@@ -6570,7 +6618,7 @@ static int brcmf_setup_wiphy(struct wiph
+@@ -6572,7 +6620,7 @@ static int brcmf_setup_wiphy(struct wiph
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
sizeof(bandlist));
if (err) {
return err;
}
/* first entry in bandlist is number of bands */
-@@ -6619,6 +6667,7 @@ static int brcmf_setup_wiphy(struct wiph
+@@ -6621,6 +6669,7 @@ static int brcmf_setup_wiphy(struct wiph
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
{
struct net_device *ndev;
struct wireless_dev *wdev;
struct brcmf_if *ifp;
-@@ -6656,7 +6705,7 @@ static s32 brcmf_config_dongle(struct br
+@@ -6658,7 +6707,7 @@ static s32 brcmf_config_dongle(struct br
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_FAKEFRAG, 1);
if (err) {
goto default_conf_out;
}
-@@ -6848,8 +6897,8 @@ static void brcmf_cfg80211_reg_notifier(
+@@ -6850,8 +6899,8 @@ static void brcmf_cfg80211_reg_notifier(
/* ignore non-ISO3166 country codes */
for (i = 0; i < 2; i++)
if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
return;
}
-@@ -6858,7 +6907,7 @@ static void brcmf_cfg80211_reg_notifier(
+@@ -6860,7 +6909,7 @@ static void brcmf_cfg80211_reg_notifier(
err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
if (err) {
return;
}
-@@ -6868,7 +6917,7 @@ static void brcmf_cfg80211_reg_notifier(
+@@ -6870,7 +6919,7 @@ static void brcmf_cfg80211_reg_notifier(
err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
if (err) {
return;
}
brcmf_setup_wiphybands(cfg);
-@@ -6914,13 +6963,13 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -6916,13 +6965,13 @@ struct brcmf_cfg80211_info *brcmf_cfg802
u16 *cap = NULL;
if (!ndev) {
return NULL;
}
-@@ -6941,7 +6990,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -6943,7 +6992,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
err = wl_init_priv(cfg);
if (err) {
brcmf_free_vif(vif);
goto wiphy_out;
}
-@@ -6950,7 +6999,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -6952,7 +7001,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
/* determine d11 io type before wiphy setup */
err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
if (err) {
goto priv_out;
}
cfg->d11inf.io_type = (u8)io_type;
-@@ -6984,13 +7033,13 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -6986,13 +7035,13 @@ struct brcmf_cfg80211_info *brcmf_cfg802
#endif
err = wiphy_register(wiphy);
if (err < 0) {
goto wiphy_unreg_out;
}
-@@ -7008,24 +7057,24 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -7010,24 +7059,24 @@ struct brcmf_cfg80211_info *brcmf_cfg802
err = brcmf_fweh_activate_events(ifp);
if (err) {
brcmf_btcoex_detach(cfg);
brcmf_p2p_detach(&cfg->p2p);
goto wiphy_unreg_out;
-@@ -7045,7 +7094,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -7047,7 +7096,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
/* (re-) activate FWEH event handling */
err = brcmf_fweh_activate_events(ifp);
if (err) {
--- /dev/null
+From 1b5e2423164b3670e8bc9174e4762d297990deff Mon Sep 17 00:00:00 2001
+From: Arend van Spriel <arend.vanspriel@broadcom.com>
+Date: Thu, 14 Feb 2019 13:43:47 +0100
+Subject: [PATCH] brcmfmac: assure SSID length from firmware is limited
+
+The SSID length as received from firmware should not exceed
+IEEE80211_MAX_SSID_LEN as that would result in heap overflow.
+
+Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -3507,6 +3507,8 @@ brcmf_wowl_nd_results(struct brcmf_if *i
+ }
+
+ netinfo = brcmf_get_netinfo_array(pfn_result);
++ if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
++ netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
+ memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
+ cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
+ cfg->wowl.nd->n_channels = 1;
--- /dev/null
+From a4176ec356c73a46c07c181c6d04039fafa34a9f Mon Sep 17 00:00:00 2001
+From: Arend van Spriel <arend.vanspriel@broadcom.com>
+Date: Thu, 14 Feb 2019 13:43:48 +0100
+Subject: [PATCH] brcmfmac: add subtype check for event handling in data path
+
+For USB there is no separate channel being used to pass events
+from firmware to the host driver and as such are passed over the
+data path. In order to detect mock event messages an additional
+check is needed on event subtype. This check is added conditionally
+using unlikely() keyword.
+
+Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../wireless/broadcom/brcm80211/brcmfmac/core.c | 5 +++--
+ .../wireless/broadcom/brcm80211/brcmfmac/fweh.h | 16 ++++++++++++----
+ .../broadcom/brcm80211/brcmfmac/msgbuf.c | 2 +-
+ 3 files changed, 16 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+@@ -519,7 +519,8 @@ void brcmf_rx_frame(struct device *dev,
+ } else {
+ /* Process special event packets */
+ if (handle_event)
+- brcmf_fweh_process_skb(ifp->drvr, skb);
++ brcmf_fweh_process_skb(ifp->drvr, skb,
++ BCMILCP_SUBTYPE_VENDOR_LONG);
+
+ brcmf_netif_rx(ifp, skb);
+ }
+@@ -536,7 +537,7 @@ void brcmf_rx_event(struct device *dev,
+ if (brcmf_rx_hdrpull(drvr, skb, &ifp))
+ return;
+
+- brcmf_fweh_process_skb(ifp->drvr, skb);
++ brcmf_fweh_process_skb(ifp->drvr, skb, 0);
+ brcmu_pkt_buf_free_skb(skb);
+ }
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
+@@ -211,7 +211,7 @@ enum brcmf_fweh_event_code {
+ */
+ #define BRCM_OUI "\x00\x10\x18"
+ #define BCMILCP_BCM_SUBTYPE_EVENT 1
+-
++#define BCMILCP_SUBTYPE_VENDOR_LONG 32769
+
+ /**
+ * struct brcm_ethhdr - broadcom specific ether header.
+@@ -334,10 +334,10 @@ void brcmf_fweh_process_event(struct brc
+ void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
+
+ static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
+- struct sk_buff *skb)
++ struct sk_buff *skb, u16 stype)
+ {
+ struct brcmf_event *event_packet;
+- u16 usr_stype;
++ u16 subtype, usr_stype;
+
+ /* only process events when protocol matches */
+ if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
+@@ -346,8 +346,16 @@ static inline void brcmf_fweh_process_sk
+ if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
+ return;
+
+- /* check for BRCM oui match */
+ event_packet = (struct brcmf_event *)skb_mac_header(skb);
++
++ /* check subtype if needed */
++ if (unlikely(stype)) {
++ subtype = get_unaligned_be16(&event_packet->hdr.subtype);
++ if (subtype != stype)
++ return;
++ }
++
++ /* check for BRCM oui match */
+ if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
+ sizeof(event_packet->hdr.oui)))
+ return;
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+@@ -1116,7 +1116,7 @@ static void brcmf_msgbuf_process_event(s
+
+ skb->protocol = eth_type_trans(skb, ifp->ndev);
+
+- brcmf_fweh_process_skb(ifp->drvr, skb);
++ brcmf_fweh_process_skb(ifp->drvr, skb, 0);
+
+ exit:
+ brcmu_pkt_buf_free_skb(skb);
*/
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -1181,6 +1181,7 @@ static int brcmf_bus_started(struct brcm
+@@ -1177,6 +1177,7 @@ static int brcmf_bus_started(struct brcm
brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read);
brcmf_feat_debugfs_create(drvr);
brcmf_proto_debugfs_create(drvr);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -3154,9 +3154,12 @@ static int brcmf_debugfs_sdio_count_read
+@@ -3143,9 +3143,12 @@ static int brcmf_debugfs_sdio_count_read
return 0;
}
struct dentry *dentry = brcmf_debugfs_get_devdir(drvr);
if (IS_ERR_OR_NULL(dentry))
-@@ -3176,7 +3179,7 @@ static int brcmf_sdio_checkdied(struct b
+@@ -3165,7 +3168,7 @@ static int brcmf_sdio_checkdied(struct b
return 0;
}
{
}
#endif /* DEBUG */
-@@ -3488,8 +3491,6 @@ static int brcmf_sdio_bus_preinit(struct
+@@ -3477,8 +3480,6 @@ static int brcmf_sdio_bus_preinit(struct
if (bus->rxbuf)
bus->rxblen = value;
/* the commands below use the terms tx and rx from
* a device perspective, ie. bus:txglom affects the
* bus transfers from device to host.
-@@ -4099,6 +4100,7 @@ static const struct brcmf_bus_ops brcmf_
+@@ -4088,6 +4089,7 @@ static const struct brcmf_bus_ops brcmf_
.get_ramsize = brcmf_sdio_bus_get_ramsize,
.get_memdump = brcmf_sdio_bus_get_memdump,
.get_fwname = brcmf_sdio_get_fwname,
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -3010,21 +3010,35 @@ static int brcmf_sdio_trap_info(struct s
+@@ -2999,21 +2999,35 @@ static int brcmf_sdio_trap_info(struct s
if (error < 0)
return error;
return 0;
}
-@@ -3078,8 +3092,10 @@ static int brcmf_sdio_checkdied(struct b
+@@ -3067,8 +3081,10 @@ static int brcmf_sdio_checkdied(struct b
else if (sh.flags & SDPCM_SHARED_ASSERT)
brcmf_err("assertion in dongle\n");
return 0;
}
-@@ -4210,7 +4226,7 @@ static void brcmf_sdio_firmware_callback
+@@ -4199,7 +4215,7 @@ static void brcmf_sdio_firmware_callback
} else {
/* Disable F2 again */
sdio_disable_func(sdiod->func2);
}
if (brcmf_chip_sr_capable(bus->ci)) {
-@@ -4231,8 +4247,10 @@ static void brcmf_sdio_firmware_callback
+@@ -4220,8 +4236,10 @@ static void brcmf_sdio_firmware_callback
}
/* If we didn't come up, turn off backplane clock */
sdio_release_host(sdiod->func1);
-@@ -4246,12 +4264,15 @@ static void brcmf_sdio_firmware_callback
+@@ -4235,12 +4253,15 @@ static void brcmf_sdio_firmware_callback
err = brcmf_attach(sdiod->dev, sdiod->settings);
if (err != 0) {
brcmf_err("brcmf_attach failed\n");
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -6047,11 +6047,18 @@ static int brcmf_construct_chaninfo(stru
+@@ -6051,11 +6051,18 @@ static int brcmf_construct_chaninfo(stru
/* assuming the chanspecs order is HT20,
* HT40 upper, HT40 lower, and VHT80.
*/
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -6048,6 +6048,9 @@ static int brcmf_construct_chaninfo(stru
+@@ -6052,6 +6052,9 @@ static int brcmf_construct_chaninfo(stru
* HT40 upper, HT40 lower, and VHT80.
*/
switch (ch.bw) {
sme->crypto.cipher_group);
return -EINVAL;
}
-@@ -1670,7 +1677,7 @@ brcmf_set_key_mgmt(struct net_device *nd
- val = WPA2_AUTH_PSK;
+@@ -1678,7 +1685,7 @@ brcmf_set_key_mgmt(struct net_device *nd
+ val = WPA2_AUTH_PSK | WPA2_AUTH_FT;
break;
default:
- bphy_err(wiphy, "invalid cipher group (%d)\n",
sme->crypto.cipher_group);
return -EINVAL;
}
-@@ -1717,7 +1724,7 @@ skip_mfp_config:
+@@ -1725,7 +1732,7 @@ skip_mfp_config:
brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
if (err) {
return err;
}
-@@ -1729,7 +1736,7 @@ brcmf_set_sharedkey(struct net_device *n
+@@ -1737,7 +1744,7 @@ brcmf_set_sharedkey(struct net_device *n
struct cfg80211_connect_params *sme)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
struct brcmf_cfg80211_security *sec;
struct brcmf_wsec_key key;
-@@ -1756,7 +1763,7 @@ brcmf_set_sharedkey(struct net_device *n
+@@ -1764,7 +1771,7 @@ brcmf_set_sharedkey(struct net_device *n
key.len = (u32) sme->key_len;
key.index = (u32) sme->key_idx;
if (key.len > sizeof(key.data)) {
return -EINVAL;
}
memcpy(key.data, sme->key, key.len);
-@@ -1769,7 +1776,7 @@ brcmf_set_sharedkey(struct net_device *n
+@@ -1777,7 +1784,7 @@ brcmf_set_sharedkey(struct net_device *n
key.algo = CRYPTO_ALGO_WEP128;
break;
default:
sme->crypto.ciphers_pairwise[0]);
return -EINVAL;
}
-@@ -1786,7 +1793,7 @@ brcmf_set_sharedkey(struct net_device *n
+@@ -1794,7 +1801,7 @@ brcmf_set_sharedkey(struct net_device *n
val = WL_AUTH_SHARED_KEY; /* shared key */
err = brcmf_fil_bsscfg_int_set(ifp, "auth", val);
if (err)
}
return err;
}
-@@ -1806,7 +1813,7 @@ enum nl80211_auth_type brcmf_war_auth_ty
+@@ -1814,7 +1821,7 @@ enum nl80211_auth_type brcmf_war_auth_ty
static void brcmf_set_join_pref(struct brcmf_if *ifp,
struct cfg80211_bss_selection *bss_select)
{
struct brcmf_join_pref_params join_pref_params[2];
enum nl80211_band band;
int err, i = 0;
-@@ -1845,7 +1852,7 @@ static void brcmf_set_join_pref(struct b
+@@ -1853,7 +1860,7 @@ static void brcmf_set_join_pref(struct b
err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
sizeof(join_pref_params));
if (err)
}
static s32
-@@ -1856,6 +1863,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
+@@ -1864,6 +1871,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
struct ieee80211_channel *chan = sme->channel;
struct brcmf_join_params join_params;
size_t join_params_size;
const struct brcmf_tlv *rsn_ie;
-@@ -1872,7 +1880,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
+@@ -1880,7 +1888,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
return -EIO;
if (!sme->ssid) {
return -EOPNOTSUPP;
}
-@@ -1901,7 +1909,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
+@@ -1909,7 +1917,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
sme->ie, sme->ie_len);
if (err)
else
brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
-@@ -1922,32 +1930,32 @@ brcmf_cfg80211_connect(struct wiphy *wip
+@@ -1930,32 +1938,32 @@ brcmf_cfg80211_connect(struct wiphy *wip
err = brcmf_set_wpa_version(ndev, sme);
if (err) {
goto done;
}
-@@ -1964,7 +1972,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
+@@ -1972,7 +1980,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
/* enable firmware supplicant for this interface */
err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
if (err < 0) {
goto done;
}
}
-@@ -2059,7 +2067,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
+@@ -2067,7 +2075,7 @@ brcmf_cfg80211_connect(struct wiphy *wip
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
&join_params, join_params_size);
if (err)
done:
if (err)
-@@ -2072,8 +2080,10 @@ static s32
+@@ -2080,8 +2088,10 @@ static s32
brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
u16 reason_code)
{
struct brcmf_scb_val_le scbval;
s32 err = 0;
-@@ -2090,7 +2100,7 @@ brcmf_cfg80211_disconnect(struct wiphy *
+@@ -2098,7 +2108,7 @@ brcmf_cfg80211_disconnect(struct wiphy *
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
&scbval, sizeof(scbval));
if (err)
brcmf_dbg(TRACE, "Exit\n");
return err;
-@@ -2103,6 +2113,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy
+@@ -2111,6 +2121,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct net_device *ndev = cfg_to_ndev(cfg);
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err;
s32 disable;
u32 qdbm = 127;
-@@ -2117,7 +2128,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy
+@@ -2125,7 +2136,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy
case NL80211_TX_POWER_LIMITED:
case NL80211_TX_POWER_FIXED:
if (mbm < 0) {
err = -EINVAL;
goto done;
}
-@@ -2127,7 +2138,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy
+@@ -2135,7 +2146,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy
qdbm |= WL_TXPWR_OVERRIDE;
break;
default:
err = -EINVAL;
goto done;
}
-@@ -2135,11 +2146,11 @@ brcmf_cfg80211_set_tx_power(struct wiphy
+@@ -2143,11 +2154,11 @@ brcmf_cfg80211_set_tx_power(struct wiphy
disable = WL_RADIO_SW_DISABLE << 16;
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
if (err)
done:
brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
-@@ -2150,7 +2161,9 @@ static s32
+@@ -2158,7 +2169,9 @@ static s32
brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
s32 *dbm)
{
s32 qdbm = 0;
s32 err;
-@@ -2160,7 +2173,7 @@ brcmf_cfg80211_get_tx_power(struct wiphy
+@@ -2168,7 +2181,7 @@ brcmf_cfg80211_get_tx_power(struct wiphy
err = brcmf_fil_iovar_int_get(vif->ifp, "qtxpower", &qdbm);
if (err) {
goto done;
}
*dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
-@@ -2175,6 +2188,7 @@ brcmf_cfg80211_config_default_key(struct
+@@ -2183,6 +2196,7 @@ brcmf_cfg80211_config_default_key(struct
u8 key_idx, bool unicast, bool multicast)
{
struct brcmf_if *ifp = netdev_priv(ndev);
u32 index;
u32 wsec;
s32 err = 0;
-@@ -2186,7 +2200,7 @@ brcmf_cfg80211_config_default_key(struct
+@@ -2194,7 +2208,7 @@ brcmf_cfg80211_config_default_key(struct
err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
if (err) {
goto done;
}
-@@ -2196,7 +2210,7 @@ brcmf_cfg80211_config_default_key(struct
+@@ -2204,7 +2218,7 @@ brcmf_cfg80211_config_default_key(struct
err = brcmf_fil_cmd_int_set(ifp,
BRCMF_C_SET_KEY_PRIMARY, index);
if (err)
}
done:
brcmf_dbg(TRACE, "Exit\n");
-@@ -2245,7 +2259,9 @@ brcmf_cfg80211_add_key(struct wiphy *wip
+@@ -2253,7 +2267,9 @@ brcmf_cfg80211_add_key(struct wiphy *wip
u8 key_idx, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct brcmf_wsec_key *key;
s32 val;
s32 wsec;
-@@ -2260,7 +2276,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
+@@ -2268,7 +2284,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
/* we ignore this key index in this case */
return -EINVAL;
}
-@@ -2269,7 +2285,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
+@@ -2277,7 +2293,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
mac_addr);
if (params->key_len > sizeof(key->data)) {
return -EINVAL;
}
-@@ -2323,7 +2339,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
+@@ -2331,7 +2347,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
break;
default:
err = -EINVAL;
goto done;
}
-@@ -2334,13 +2350,13 @@ brcmf_cfg80211_add_key(struct wiphy *wip
+@@ -2342,13 +2358,13 @@ brcmf_cfg80211_add_key(struct wiphy *wip
err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
if (err) {
goto done;
}
-@@ -2355,9 +2371,11 @@ brcmf_cfg80211_get_key(struct wiphy *wip
+@@ -2363,9 +2379,11 @@ brcmf_cfg80211_get_key(struct wiphy *wip
void (*callback)(void *cookie,
struct key_params *params))
{
struct brcmf_cfg80211_security *sec;
s32 wsec;
s32 err = 0;
-@@ -2371,7 +2389,7 @@ brcmf_cfg80211_get_key(struct wiphy *wip
+@@ -2379,7 +2397,7 @@ brcmf_cfg80211_get_key(struct wiphy *wip
err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
if (err) {
/* Ignore this error, may happen during DISASSOC */
err = -EAGAIN;
goto done;
-@@ -2392,7 +2410,7 @@ brcmf_cfg80211_get_key(struct wiphy *wip
+@@ -2400,7 +2418,7 @@ brcmf_cfg80211_get_key(struct wiphy *wip
params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
} else {
err = -EINVAL;
goto done;
}
-@@ -2422,7 +2440,7 @@ brcmf_cfg80211_config_default_mgmt_key(s
+@@ -2430,7 +2448,7 @@ brcmf_cfg80211_config_default_mgmt_key(s
static void
brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
{
s32 err;
u8 key_idx;
struct brcmf_wsec_key *key;
-@@ -2439,18 +2457,18 @@ brcmf_cfg80211_reconfigure_wep(struct br
+@@ -2447,18 +2465,18 @@ brcmf_cfg80211_reconfigure_wep(struct br
err = send_key_to_dongle(ifp, key);
if (err) {
}
static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
-@@ -2476,7 +2494,7 @@ static void brcmf_convert_sta_flags(u32
+@@ -2484,7 +2502,7 @@ static void brcmf_convert_sta_flags(u32
static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
{
struct {
__le32 len;
struct brcmf_bss_info_le bss_le;
-@@ -2492,7 +2510,7 @@ static void brcmf_fill_bss_param(struct
+@@ -2500,7 +2518,7 @@ static void brcmf_fill_bss_param(struct
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
WL_BSS_INFO_MAX);
if (err) {
goto out_kfree;
}
si->filled |= BIT_ULL(NL80211_STA_INFO_BSS_PARAM);
-@@ -2514,7 +2532,7 @@ static s32
+@@ -2522,7 +2540,7 @@ static s32
brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp,
struct station_info *sinfo)
{
struct brcmf_scb_val_le scbval;
struct brcmf_pktcnt_le pktcnt;
s32 err;
-@@ -2524,7 +2542,7 @@ brcmf_cfg80211_get_station_ibss(struct b
+@@ -2532,7 +2550,7 @@ brcmf_cfg80211_get_station_ibss(struct b
/* Get the current tx rate */
err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
if (err < 0) {
return err;
}
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
-@@ -2534,7 +2552,7 @@ brcmf_cfg80211_get_station_ibss(struct b
+@@ -2542,7 +2560,7 @@ brcmf_cfg80211_get_station_ibss(struct b
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval,
sizeof(scbval));
if (err) {
return err;
}
rssi = le32_to_cpu(scbval.val);
-@@ -2544,7 +2562,7 @@ brcmf_cfg80211_get_station_ibss(struct b
+@@ -2552,7 +2570,7 @@ brcmf_cfg80211_get_station_ibss(struct b
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt,
sizeof(pktcnt));
if (err) {
return err;
}
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS) |
-@@ -2563,7 +2581,9 @@ static s32
+@@ -2571,7 +2589,9 @@ static s32
brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
const u8 *mac, struct station_info *sinfo)
{
struct brcmf_scb_val_le scb_val;
s32 err = 0;
struct brcmf_sta_info_le sta_info_le;
-@@ -2592,7 +2612,7 @@ brcmf_cfg80211_get_station(struct wiphy
+@@ -2600,7 +2620,7 @@ brcmf_cfg80211_get_station(struct wiphy
&sta_info_le,
sizeof(sta_info_le));
if (err < 0) {
goto done;
}
}
-@@ -2661,7 +2681,7 @@ brcmf_cfg80211_get_station(struct wiphy
+@@ -2669,7 +2689,7 @@ brcmf_cfg80211_get_station(struct wiphy
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
&scb_val, sizeof(scb_val));
if (err) {
err);
goto done;
} else {
-@@ -2683,6 +2703,7 @@ brcmf_cfg80211_dump_station(struct wiphy
+@@ -2691,6 +2711,7 @@ brcmf_cfg80211_dump_station(struct wiphy
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err;
brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
-@@ -2693,7 +2714,7 @@ brcmf_cfg80211_dump_station(struct wiphy
+@@ -2701,7 +2722,7 @@ brcmf_cfg80211_dump_station(struct wiphy
&cfg->assoclist,
sizeof(cfg->assoclist));
if (err) {
err);
cfg->assoclist.count = 0;
return -EOPNOTSUPP;
-@@ -2714,6 +2735,7 @@ brcmf_cfg80211_set_power_mgmt(struct wip
+@@ -2722,6 +2743,7 @@ brcmf_cfg80211_set_power_mgmt(struct wip
s32 err = 0;
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
brcmf_dbg(TRACE, "Enter\n");
-@@ -2742,9 +2764,9 @@ brcmf_cfg80211_set_power_mgmt(struct wip
+@@ -2750,9 +2772,9 @@ brcmf_cfg80211_set_power_mgmt(struct wip
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
if (err) {
if (err == -ENODEV)
}
done:
brcmf_dbg(TRACE, "Exit\n");
-@@ -2755,6 +2777,7 @@ static s32 brcmf_inform_single_bss(struc
+@@ -2763,6 +2785,7 @@ static s32 brcmf_inform_single_bss(struc
struct brcmf_bss_info_le *bi)
{
struct wiphy *wiphy = cfg_to_wiphy(cfg);
struct cfg80211_bss *bss;
enum nl80211_band band;
struct brcmu_chan ch;
-@@ -2767,7 +2790,7 @@ static s32 brcmf_inform_single_bss(struc
+@@ -2775,7 +2798,7 @@ static s32 brcmf_inform_single_bss(struc
struct cfg80211_inform_bss bss_data = {};
if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
return 0;
}
-@@ -2826,7 +2849,7 @@ next_bss_le(struct brcmf_scan_results *l
+@@ -2834,7 +2857,7 @@ next_bss_le(struct brcmf_scan_results *l
static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
{
struct brcmf_scan_results *bss_list;
struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
s32 err = 0;
-@@ -2835,7 +2858,7 @@ static s32 brcmf_inform_bss(struct brcmf
+@@ -2843,7 +2866,7 @@ static s32 brcmf_inform_bss(struct brcmf
bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
if (bss_list->count != 0 &&
bss_list->version != BRCMF_BSS_INFO_VERSION) {
bss_list->version);
return -EOPNOTSUPP;
}
-@@ -2853,6 +2876,7 @@ static s32 brcmf_inform_ibss(struct brcm
+@@ -2861,6 +2884,7 @@ static s32 brcmf_inform_ibss(struct brcm
struct net_device *ndev, const u8 *bssid)
{
struct wiphy *wiphy = cfg_to_wiphy(cfg);
struct ieee80211_channel *notify_channel;
struct brcmf_bss_info_le *bi = NULL;
struct ieee80211_supported_band *band;
-@@ -2880,7 +2904,7 @@ static s32 brcmf_inform_ibss(struct brcm
+@@ -2888,7 +2912,7 @@ static s32 brcmf_inform_ibss(struct brcm
err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
buf, WL_BSS_INFO_MAX);
if (err) {
goto CleanUp;
}
-@@ -2934,7 +2958,7 @@ CleanUp:
+@@ -2942,7 +2966,7 @@ CleanUp:
static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp)
{
struct brcmf_bss_info_le *bi;
const struct brcmf_tlv *tim;
u16 beacon_interval;
-@@ -2951,7 +2975,7 @@ static s32 brcmf_update_bss_info(struct
+@@ -2959,7 +2983,7 @@ static s32 brcmf_update_bss_info(struct
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
cfg->extra_buf, WL_EXTRA_BUF_MAX);
if (err) {
goto update_bss_info_out;
}
-@@ -2976,7 +3000,7 @@ static s32 brcmf_update_bss_info(struct
+@@ -2984,7 +3008,7 @@ static s32 brcmf_update_bss_info(struct
u32 var;
err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
if (err) {
goto update_bss_info_out;
}
dtim_period = (u8)var;
-@@ -3014,10 +3038,10 @@ static void brcmf_escan_timeout(struct t
+@@ -3022,10 +3046,10 @@ static void brcmf_escan_timeout(struct t
{
struct brcmf_cfg80211_info *cfg =
from_timer(cfg, t, escan_timeout);
schedule_work(&cfg->escan_timeout_work);
}
}
-@@ -3065,8 +3089,8 @@ static s32
+@@ -3073,8 +3097,8 @@ static s32
brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
const struct brcmf_event_msg *e, void *data)
{
s32 status;
struct brcmf_escan_result_le *escan_result_le;
u32 escan_buflen;
-@@ -3083,7 +3107,7 @@ brcmf_cfg80211_escan_handler(struct brcm
+@@ -3091,7 +3115,7 @@ brcmf_cfg80211_escan_handler(struct brcm
goto exit;
if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
ifp->bsscfgidx);
return -EPERM;
}
-@@ -3091,24 +3115,24 @@ brcmf_cfg80211_escan_handler(struct brcm
+@@ -3099,24 +3123,24 @@ brcmf_cfg80211_escan_handler(struct brcm
if (status == BRCMF_E_STATUS_PARTIAL) {
brcmf_dbg(SCAN, "ESCAN Partial result\n");
if (e->datalen < sizeof(*escan_result_le)) {
escan_result_le->bss_count);
goto exit;
}
-@@ -3124,7 +3148,7 @@ brcmf_cfg80211_escan_handler(struct brcm
+@@ -3132,7 +3156,7 @@ brcmf_cfg80211_escan_handler(struct brcm
bi_length = le32_to_cpu(bss_info_le->length);
if (bi_length != escan_buflen - WL_ESCAN_RESULTS_FIXED_SIZE) {
bi_length);
goto exit;
}
-@@ -3133,7 +3157,7 @@ brcmf_cfg80211_escan_handler(struct brcm
+@@ -3141,7 +3165,7 @@ brcmf_cfg80211_escan_handler(struct brcm
BIT(NL80211_IFTYPE_ADHOC))) {
if (le16_to_cpu(bss_info_le->capability) &
WLAN_CAPABILITY_IBSS) {
goto exit;
}
}
-@@ -3141,7 +3165,7 @@ brcmf_cfg80211_escan_handler(struct brcm
+@@ -3149,7 +3173,7 @@ brcmf_cfg80211_escan_handler(struct brcm
list = (struct brcmf_scan_results *)
cfg->escan_info.escan_buf;
if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
goto exit;
}
-@@ -3300,7 +3324,8 @@ static s32
+@@ -3308,7 +3332,8 @@ static s32
brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
const struct brcmf_event_msg *e, void *data)
{
struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
struct cfg80211_scan_request *request = NULL;
struct wiphy *wiphy = cfg_to_wiphy(cfg);
-@@ -3333,14 +3358,14 @@ brcmf_notify_sched_scan_results(struct b
+@@ -3341,14 +3366,14 @@ brcmf_notify_sched_scan_results(struct b
WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
if (!result_count) {
goto out_err;
}
-@@ -3387,14 +3412,15 @@ brcmf_cfg80211_sched_scan_start(struct w
+@@ -3395,14 +3420,15 @@ brcmf_cfg80211_sched_scan_start(struct w
struct net_device *ndev,
struct cfg80211_sched_scan_request *req)
{
cfg->scan_status);
return -EAGAIN;
}
-@@ -3473,8 +3499,8 @@ static s32
+@@ -3481,8 +3507,8 @@ static s32
brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
void *data)
{
struct brcmf_pno_scanresults_le *pfn_result;
struct brcmf_pno_net_info_le *netinfo;
-@@ -3493,7 +3519,7 @@ brcmf_wowl_nd_results(struct brcmf_if *i
+@@ -3501,7 +3527,7 @@ brcmf_wowl_nd_results(struct brcmf_if *i
}
if (le32_to_cpu(pfn_result->count) < 1) {
le32_to_cpu(pfn_result->count));
return -EINVAL;
}
-@@ -3523,6 +3549,7 @@ brcmf_wowl_nd_results(struct brcmf_if *i
+@@ -3531,6 +3557,7 @@ brcmf_wowl_nd_results(struct brcmf_if *i
static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_wowl_wakeind_le wake_ind_le;
struct cfg80211_wowlan_wakeup wakeup_data;
struct cfg80211_wowlan_wakeup *wakeup;
-@@ -3533,7 +3560,7 @@ static void brcmf_report_wowl_wakeind(st
+@@ -3541,7 +3568,7 @@ static void brcmf_report_wowl_wakeind(st
err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
sizeof(wake_ind_le));
if (err) {
return;
}
-@@ -3574,7 +3601,7 @@ static void brcmf_report_wowl_wakeind(st
+@@ -3582,7 +3609,7 @@ static void brcmf_report_wowl_wakeind(st
cfg->wowl.nd_data_completed,
BRCMF_ND_INFO_TIMEOUT);
if (!timeout)
else
wakeup_data.net_detect = cfg->wowl.nd_info;
}
-@@ -3763,6 +3790,7 @@ brcmf_cfg80211_set_pmksa(struct wiphy *w
+@@ -3771,6 +3798,7 @@ brcmf_cfg80211_set_pmksa(struct wiphy *w
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
s32 err;
u32 npmk, i;
-@@ -3782,7 +3810,7 @@ brcmf_cfg80211_set_pmksa(struct wiphy *w
+@@ -3790,7 +3818,7 @@ brcmf_cfg80211_set_pmksa(struct wiphy *w
cfg->pmk_list.npmk = cpu_to_le32(npmk);
}
} else {
return -EINVAL;
}
-@@ -3805,6 +3833,7 @@ brcmf_cfg80211_del_pmksa(struct wiphy *w
+@@ -3813,6 +3841,7 @@ brcmf_cfg80211_del_pmksa(struct wiphy *w
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
s32 err;
u32 npmk, i;
-@@ -3828,7 +3857,7 @@ brcmf_cfg80211_del_pmksa(struct wiphy *w
+@@ -3836,7 +3865,7 @@ brcmf_cfg80211_del_pmksa(struct wiphy *w
memset(&pmk[i], 0, sizeof(*pmk));
cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
} else {
return -EINVAL;
}
-@@ -3860,20 +3889,20 @@ brcmf_cfg80211_flush_pmksa(struct wiphy
+@@ -3868,20 +3897,20 @@ brcmf_cfg80211_flush_pmksa(struct wiphy
static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
{
return err;
}
/* set upper-layer auth */
-@@ -3883,7 +3912,7 @@ static s32 brcmf_configure_opensecurity(
+@@ -3891,7 +3920,7 @@ static s32 brcmf_configure_opensecurity(
wpa_val = WPA_AUTH_DISABLED;
err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_val);
if (err < 0) {
return err;
}
-@@ -3903,7 +3932,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -3911,7 +3940,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
const struct brcmf_vs_tlv *wpa_ie,
bool is_rsn_ie)
{
u32 auth = 0; /* d11 open authentication */
u16 count;
s32 err = 0;
-@@ -3934,13 +3963,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -3942,13 +3971,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
/* check for multicast cipher suite */
if (offset + WPA_IE_MIN_OUI_LEN > len) {
err = -EINVAL;
goto exit;
}
offset += TLV_OUI_LEN;
-@@ -3962,7 +3991,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -3970,7 +3999,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
break;
default:
err = -EINVAL;
goto exit;
}
-@@ -3973,13 +4002,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -3981,13 +4010,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
/* Check for unicast suite(s) */
if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
err = -EINVAL;
goto exit;
}
offset += TLV_OUI_LEN;
-@@ -3997,7 +4026,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4005,7 +4034,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
pval |= AES_ENABLED;
break;
default:
}
offset++;
}
-@@ -4007,13 +4036,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4015,13 +4044,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
/* Check for auth key management suite(s) */
if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
err = -EINVAL;
goto exit;
}
offset += TLV_OUI_LEN;
-@@ -4041,7 +4070,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4049,7 +4078,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
wpa_auth |= WPA2_AUTH_1X_SHA256;
break;
default:
}
offset++;
}
-@@ -4083,7 +4112,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4091,7 +4120,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
wme_bss_disable);
if (err < 0) {
goto exit;
}
-@@ -4097,7 +4126,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4105,7 +4134,7 @@ brcmf_configure_wpaie(struct brcmf_if *i
&data[offset],
WPA_IE_MIN_OUI_LEN);
if (err < 0) {
goto exit;
}
}
-@@ -4108,13 +4137,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4116,13 +4145,13 @@ brcmf_configure_wpaie(struct brcmf_if *i
/* set auth */
err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
if (err < 0) {
goto exit;
}
/* Configure MFP, this needs to go after wsec otherwise the wsec command
-@@ -4123,14 +4152,14 @@ brcmf_configure_wpaie(struct brcmf_if *i
+@@ -4131,14 +4160,14 @@ brcmf_configure_wpaie(struct brcmf_if *i
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
if (err < 0) {
goto exit;
}
-@@ -4216,8 +4245,8 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8
+@@ -4224,8 +4253,8 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8
s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
const u8 *vndr_ie_buf, u32 vndr_ie_len)
{
struct vif_saved_ie *saved_ie;
s32 err = 0;
u8 *iovar_ie_buf;
-@@ -4238,7 +4267,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
+@@ -4246,7 +4275,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
if (!vif)
return -ENODEV;
ifp = vif->ifp;
saved_ie = &vif->saved_ie;
brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx,
-@@ -4270,13 +4299,13 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
+@@ -4278,13 +4307,13 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
break;
default:
err = -EPERM;
goto exit;
}
-@@ -4337,7 +4366,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
+@@ -4345,7 +4374,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
/* verify remained buf size before copy data */
if (remained_buf_len < (vndrie_info->vndrie.len +
VNDR_IE_VSIE_OFFSET)) {
remained_buf_len);
break;
}
-@@ -4369,7 +4398,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
+@@ -4377,7 +4406,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_c
err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
total_ie_buf_len);
if (err)
}
exit:
-@@ -4397,14 +4426,14 @@ static s32
+@@ -4405,14 +4434,14 @@ static s32
brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
struct cfg80211_beacon_data *beacon)
{
return err;
}
brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
-@@ -4414,7 +4443,7 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg
+@@ -4422,7 +4451,7 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg
beacon->proberesp_ies,
beacon->proberesp_ies_len);
if (err)
else
brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
-@@ -4428,6 +4457,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4436,6 +4465,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
s32 ie_offset;
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
const struct brcmf_tlv *ssid_ie;
const struct brcmf_tlv *country_ie;
struct brcmf_ssid_le ssid_le;
-@@ -4523,7 +4553,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4531,7 +4561,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
is_11d);
if (err < 0) {
err);
goto exit;
}
-@@ -4532,7 +4562,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4540,7 +4570,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
settings->beacon_interval);
if (err < 0) {
err);
goto exit;
}
-@@ -4541,7 +4571,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4549,7 +4579,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
settings->dtim_period);
if (err < 0) {
err);
goto exit;
}
-@@ -4552,7 +4582,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4560,7 +4590,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
if (err < 0) {
err);
goto exit;
}
-@@ -4561,7 +4591,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4569,7 +4599,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
if (err < 0) {
goto exit;
}
} else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
-@@ -4577,7 +4607,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4585,7 +4615,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
if (err < 0) {
err);
goto exit;
}
-@@ -4587,14 +4617,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4595,14 +4625,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
*/
err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
if (err < 0) {
goto exit;
}
/* On DOWN the firmware removes the WEP keys, reconfigure
-@@ -4609,14 +4639,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4617,14 +4647,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
&join_params, sizeof(join_params));
if (err < 0) {
goto exit;
}
}
-@@ -4625,14 +4655,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4633,14 +4663,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
} else if (dev_role == NL80211_IFTYPE_P2P_GO) {
err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
if (err < 0) {
goto exit;
}
bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
-@@ -4640,7 +4670,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+@@ -4648,7 +4678,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
sizeof(bss_enable));
if (err < 0) {
goto exit;
}
-@@ -4663,7 +4693,9 @@ exit:
+@@ -4671,7 +4701,9 @@ exit:
static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
{
s32 err;
struct brcmf_fil_bss_enable_le bss_enable;
struct brcmf_join_params join_params;
-@@ -4688,13 +4720,13 @@ static int brcmf_cfg80211_stop_ap(struct
+@@ -4696,13 +4728,13 @@ static int brcmf_cfg80211_stop_ap(struct
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
&join_params, sizeof(join_params));
if (err < 0)
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
brcmf_fil_iovar_int_set(ifp, "mbss", 0);
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
-@@ -4702,7 +4734,7 @@ static int brcmf_cfg80211_stop_ap(struct
+@@ -4710,7 +4742,7 @@ static int brcmf_cfg80211_stop_ap(struct
/* Bring device back up so it can be used again */
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
if (err < 0)
brcmf_vif_clear_mgmt_ies(ifp->vif);
} else {
-@@ -4711,7 +4743,7 @@ static int brcmf_cfg80211_stop_ap(struct
+@@ -4719,7 +4751,7 @@ static int brcmf_cfg80211_stop_ap(struct
err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
sizeof(bss_enable));
if (err < 0)
}
brcmf_set_mpc(ifp, 1);
brcmf_configure_arp_nd_offload(ifp, true);
-@@ -4740,6 +4772,7 @@ brcmf_cfg80211_del_station(struct wiphy
+@@ -4748,6 +4780,7 @@ brcmf_cfg80211_del_station(struct wiphy
struct station_del_parameters *params)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_scb_val_le scbval;
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err;
-@@ -4759,7 +4792,7 @@ brcmf_cfg80211_del_station(struct wiphy
+@@ -4767,7 +4800,7 @@ brcmf_cfg80211_del_station(struct wiphy
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
&scbval, sizeof(scbval));
if (err)
err);
brcmf_dbg(TRACE, "Exit\n");
-@@ -4770,6 +4803,8 @@ static int
+@@ -4778,6 +4811,8 @@ static int
brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
const u8 *mac, struct station_parameters *params)
{
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err;
-@@ -4790,7 +4825,7 @@ brcmf_cfg80211_change_station(struct wip
+@@ -4798,7 +4833,7 @@ brcmf_cfg80211_change_station(struct wip
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
(void *)mac, ETH_ALEN);
if (err < 0)
return err;
}
-@@ -4820,6 +4855,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wip
+@@ -4828,6 +4863,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wip
{
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;
-@@ -4840,7 +4876,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wip
+@@ -4848,7 +4884,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wip
mgmt = (const struct ieee80211_mgmt *)buf;
if (!ieee80211_is_mgmt(mgmt->frame_control)) {
return -EPERM;
}
-@@ -4871,13 +4907,13 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wip
+@@ -4879,13 +4915,13 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wip
GFP_KERNEL);
} else if (ieee80211_is_action(mgmt->frame_control)) {
if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) {
err = -ENOMEM;
goto exit;
}
-@@ -4928,6 +4964,7 @@ brcmf_cfg80211_cancel_remain_on_channel(
+@@ -4936,6 +4972,7 @@ brcmf_cfg80211_cancel_remain_on_channel(
u64 cookie)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_cfg80211_vif *vif;
int err = 0;
-@@ -4935,7 +4972,7 @@ brcmf_cfg80211_cancel_remain_on_channel(
+@@ -4943,7 +4980,7 @@ brcmf_cfg80211_cancel_remain_on_channel(
vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
if (vif == NULL) {
err = -ENODEV;
goto exit;
}
-@@ -4950,6 +4987,7 @@ static int brcmf_cfg80211_get_channel(st
+@@ -4958,6 +4995,7 @@ static int brcmf_cfg80211_get_channel(st
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct net_device *ndev = wdev->netdev;
struct brcmf_if *ifp;
struct brcmu_chan ch;
enum nl80211_band band = 0;
-@@ -4963,7 +5001,7 @@ static int brcmf_cfg80211_get_channel(st
+@@ -4971,7 +5009,7 @@ static int brcmf_cfg80211_get_channel(st
err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
if (err) {
return err;
}
-@@ -5085,6 +5123,8 @@ static int brcmf_cfg80211_tdls_oper(stru
+@@ -5093,6 +5131,8 @@ static int brcmf_cfg80211_tdls_oper(stru
struct net_device *ndev, const u8 *peer,
enum nl80211_tdls_operation oper)
{
struct brcmf_if *ifp;
struct brcmf_tdls_iovar_le info;
int ret = 0;
-@@ -5102,7 +5142,7 @@ static int brcmf_cfg80211_tdls_oper(stru
+@@ -5110,7 +5150,7 @@ static int brcmf_cfg80211_tdls_oper(stru
ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
&info, sizeof(info));
if (ret < 0)
return ret;
}
-@@ -5113,6 +5153,8 @@ brcmf_cfg80211_update_conn_params(struct
+@@ -5121,6 +5161,8 @@ brcmf_cfg80211_update_conn_params(struct
struct cfg80211_connect_params *sme,
u32 changed)
{
struct brcmf_if *ifp;
int err;
-@@ -5123,7 +5165,7 @@ brcmf_cfg80211_update_conn_params(struct
+@@ -5131,7 +5173,7 @@ brcmf_cfg80211_update_conn_params(struct
err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
sme->ie, sme->ie_len);
if (err)
else
brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
-@@ -5135,6 +5177,8 @@ static int
+@@ -5143,6 +5185,8 @@ static int
brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_gtk_rekey_data *gtk)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_gtk_keyinfo_le gtk_le;
int ret;
-@@ -5149,7 +5193,7 @@ brcmf_cfg80211_set_rekey_data(struct wip
+@@ -5157,7 +5201,7 @@ brcmf_cfg80211_set_rekey_data(struct wip
ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", >k_le,
sizeof(gtk_le));
if (ret < 0)
return ret;
}
-@@ -5381,7 +5425,7 @@ static void brcmf_clear_assoc_ies(struct
+@@ -5389,7 +5433,7 @@ static void brcmf_clear_assoc_ies(struct
static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp)
{
struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
u32 req_len;
-@@ -5393,7 +5437,7 @@ static s32 brcmf_get_assoc_ies(struct br
+@@ -5401,7 +5445,7 @@ static s32 brcmf_get_assoc_ies(struct br
err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
cfg->extra_buf, WL_ASSOC_INFO_MAX);
if (err) {
return err;
}
assoc_info =
-@@ -5405,7 +5449,7 @@ static s32 brcmf_get_assoc_ies(struct br
+@@ -5413,7 +5457,7 @@ static s32 brcmf_get_assoc_ies(struct br
cfg->extra_buf,
WL_ASSOC_INFO_MAX);
if (err) {
return err;
}
conn_info->req_ie_len = req_len;
-@@ -5423,7 +5467,7 @@ static s32 brcmf_get_assoc_ies(struct br
+@@ -5429,7 +5473,7 @@ static s32 brcmf_get_assoc_ies(struct br
cfg->extra_buf,
WL_ASSOC_INFO_MAX);
if (err) {
return err;
}
conn_info->resp_ie_len = resp_len;
-@@ -5552,7 +5596,7 @@ brcmf_notify_connect_status_ap(struct br
+@@ -5556,7 +5600,7 @@ brcmf_notify_connect_status_ap(struct br
struct net_device *ndev,
const struct brcmf_event_msg *e, void *data)
{
static int generation;
u32 event = e->event_code;
u32 reason = e->reason;
-@@ -5570,7 +5614,7 @@ brcmf_notify_connect_status_ap(struct br
+@@ -5574,7 +5618,7 @@ brcmf_notify_connect_status_ap(struct br
if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
(reason == BRCMF_E_STATUS_SUCCESS)) {
if (!data) {
return -EINVAL;
}
-@@ -5862,7 +5906,7 @@ static void init_vif_event(struct brcmf_
+@@ -5866,7 +5910,7 @@ static void init_vif_event(struct brcmf_
static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
{
s32 err;
u32 bcn_timeout;
__le32 roamtrigger[2];
-@@ -5875,7 +5919,7 @@ static s32 brcmf_dongle_roam(struct brcm
+@@ -5879,7 +5923,7 @@ static s32 brcmf_dongle_roam(struct brcm
bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON;
err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
if (err) {
goto roam_setup_done;
}
-@@ -5887,7 +5931,7 @@ static s32 brcmf_dongle_roam(struct brcm
+@@ -5891,7 +5935,7 @@ static s32 brcmf_dongle_roam(struct brcm
err = brcmf_fil_iovar_int_set(ifp, "roam_off",
ifp->drvr->settings->roamoff);
if (err) {
goto roam_setup_done;
}
-@@ -5896,7 +5940,7 @@ static s32 brcmf_dongle_roam(struct brcm
+@@ -5900,7 +5944,7 @@ static s32 brcmf_dongle_roam(struct brcm
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
(void *)roamtrigger, sizeof(roamtrigger));
if (err) {
goto roam_setup_done;
}
-@@ -5905,7 +5949,7 @@ static s32 brcmf_dongle_roam(struct brcm
+@@ -5909,7 +5953,7 @@ static s32 brcmf_dongle_roam(struct brcm
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
(void *)roam_delta, sizeof(roam_delta));
if (err) {
goto roam_setup_done;
}
-@@ -5916,26 +5960,26 @@ roam_setup_done:
+@@ -5920,26 +5964,26 @@ roam_setup_done:
static s32
brcmf_dongle_scantime(struct brcmf_if *ifp)
{
goto dongle_scantime_out;
}
-@@ -5968,7 +6012,8 @@ static int brcmf_construct_chaninfo(stru
+@@ -5972,7 +6016,8 @@ static int brcmf_construct_chaninfo(stru
u32 bw_cap[])
{
struct wiphy *wiphy = cfg_to_wiphy(cfg);
struct ieee80211_supported_band *band;
struct ieee80211_channel *channel;
struct brcmf_chanspec_list *list;
-@@ -5989,7 +6034,7 @@ static int brcmf_construct_chaninfo(stru
+@@ -5993,7 +6038,7 @@ static int brcmf_construct_chaninfo(stru
err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
BRCMF_DCMD_MEDLEN);
if (err) {
goto fail_pbuf;
}
-@@ -6012,7 +6057,7 @@ static int brcmf_construct_chaninfo(stru
+@@ -6016,7 +6061,7 @@ static int brcmf_construct_chaninfo(stru
} else if (ch.band == BRCMU_CHAN_BAND_5G) {
band = wiphy->bands[NL80211_BAND_5GHZ];
} else {
ch.chspec);
continue;
}
-@@ -6036,7 +6081,7 @@ static int brcmf_construct_chaninfo(stru
+@@ -6040,7 +6085,7 @@ static int brcmf_construct_chaninfo(stru
/* It seems firmware supports some channel we never
* considered. Something new in IEEE standard?
*/
ch.control_ch_num);
continue;
}
-@@ -6093,8 +6138,8 @@ fail_pbuf:
+@@ -6097,8 +6142,8 @@ fail_pbuf:
static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
{
struct ieee80211_supported_band *band;
struct brcmf_fil_bwcap_le band_bwcap;
struct brcmf_chanspec_list *list;
-@@ -6140,7 +6185,7 @@ static int brcmf_enable_bw40_2g(struct b
+@@ -6144,7 +6189,7 @@ static int brcmf_enable_bw40_2g(struct b
err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
BRCMF_DCMD_MEDLEN);
if (err) {
kfree(pbuf);
return err;
}
-@@ -6171,7 +6216,7 @@ static int brcmf_enable_bw40_2g(struct b
+@@ -6175,7 +6220,7 @@ static int brcmf_enable_bw40_2g(struct b
static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
{
u32 band, mimo_bwcap;
int err;
-@@ -6207,7 +6252,7 @@ static void brcmf_get_bwcap(struct brcmf
+@@ -6211,7 +6256,7 @@ static void brcmf_get_bwcap(struct brcmf
bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
break;
default:
}
}
-@@ -6282,7 +6327,8 @@ static void brcmf_update_vht_cap(struct
+@@ -6286,7 +6331,8 @@ static void brcmf_update_vht_cap(struct
static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg)
{
struct wiphy *wiphy = cfg_to_wiphy(cfg);
u32 nmode = 0;
u32 vhtmode = 0;
-@@ -6299,7 +6345,7 @@ static int brcmf_setup_wiphybands(struct
+@@ -6303,7 +6349,7 @@ static int brcmf_setup_wiphybands(struct
(void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
if (err) {
} else {
brcmf_get_bwcap(ifp, bw_cap);
}
-@@ -6309,7 +6355,7 @@ static int brcmf_setup_wiphybands(struct
+@@ -6313,7 +6359,7 @@ static int brcmf_setup_wiphybands(struct
err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
if (err) {
nchain = 1;
} else {
for (nchain = 0; rxchain; nchain++)
-@@ -6319,7 +6365,7 @@ static int brcmf_setup_wiphybands(struct
+@@ -6323,7 +6369,7 @@ static int brcmf_setup_wiphybands(struct
err = brcmf_construct_chaninfo(cfg, bw_cap);
if (err) {
return err;
}
-@@ -6526,12 +6572,13 @@ static void brcmf_wiphy_wowl_params(stru
+@@ -6530,12 +6576,13 @@ static void brcmf_wiphy_wowl_params(stru
{
#ifdef CONFIG_PM
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
wiphy->wowlan = &brcmf_wowlan_support;
return;
}
-@@ -6628,7 +6675,7 @@ static int brcmf_setup_wiphy(struct wiph
+@@ -6632,7 +6679,7 @@ static int brcmf_setup_wiphy(struct wiph
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
sizeof(bandlist));
if (err) {
return err;
}
/* first entry in bandlist is number of bands */
-@@ -6677,7 +6724,7 @@ static int brcmf_setup_wiphy(struct wiph
+@@ -6681,7 +6728,7 @@ static int brcmf_setup_wiphy(struct wiph
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
{
struct net_device *ndev;
struct wireless_dev *wdev;
struct brcmf_if *ifp;
-@@ -6715,7 +6762,7 @@ static s32 brcmf_config_dongle(struct br
+@@ -6719,7 +6766,7 @@ static s32 brcmf_config_dongle(struct br
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_FAKEFRAG, 1);
if (err) {
goto default_conf_out;
}
-@@ -6896,6 +6943,7 @@ static void brcmf_cfg80211_reg_notifier(
+@@ -6900,6 +6947,7 @@ static void brcmf_cfg80211_reg_notifier(
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
struct brcmf_fil_country_le ccreq;
s32 err;
int i;
-@@ -6907,7 +6955,7 @@ static void brcmf_cfg80211_reg_notifier(
+@@ -6911,7 +6959,7 @@ static void brcmf_cfg80211_reg_notifier(
/* ignore non-ISO3166 country codes */
for (i = 0; i < 2; i++)
if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
req->alpha2[0], req->alpha2[1]);
return;
}
-@@ -6917,7 +6965,7 @@ static void brcmf_cfg80211_reg_notifier(
+@@ -6921,7 +6969,7 @@ static void brcmf_cfg80211_reg_notifier(
err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
if (err) {
return;
}
-@@ -6927,7 +6975,7 @@ static void brcmf_cfg80211_reg_notifier(
+@@ -6931,7 +6979,7 @@ static void brcmf_cfg80211_reg_notifier(
err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
if (err) {
return;
}
brcmf_setup_wiphybands(cfg);
-@@ -6973,13 +7021,13 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -6977,13 +7025,13 @@ struct brcmf_cfg80211_info *brcmf_cfg802
u16 *cap = NULL;
if (!ndev) {
return NULL;
}
-@@ -7000,7 +7048,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -7004,7 +7052,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
err = wl_init_priv(cfg);
if (err) {
brcmf_free_vif(vif);
goto wiphy_out;
}
-@@ -7009,7 +7057,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -7013,7 +7061,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
/* determine d11 io type before wiphy setup */
err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
if (err) {
goto priv_out;
}
cfg->d11inf.io_type = (u8)io_type;
-@@ -7043,13 +7091,13 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -7047,13 +7095,13 @@ struct brcmf_cfg80211_info *brcmf_cfg802
#endif
err = wiphy_register(wiphy);
if (err < 0) {
goto wiphy_unreg_out;
}
-@@ -7067,24 +7115,24 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -7071,24 +7119,24 @@ struct brcmf_cfg80211_info *brcmf_cfg802
err = brcmf_fweh_activate_events(ifp);
if (err) {
brcmf_btcoex_detach(cfg);
brcmf_p2p_detach(&cfg->p2p);
goto wiphy_unreg_out;
-@@ -7104,7 +7152,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -7108,7 +7156,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
/* (re-) activate FWEH event handling */
err = brcmf_fweh_activate_events(ifp);
if (err) {
brcmf_net_detach(ifp->ndev, false);
drvr->iflist[bsscfgidx] = NULL;
@@ -864,7 +866,7 @@ static void brcmf_del_if(struct brcmf_pu
-
ifp = drvr->iflist[bsscfgidx];
+ drvr->iflist[bsscfgidx] = NULL;
if (!ifp) {
- brcmf_err("Null interface, bsscfgidx=%d\n", bsscfgidx);
+ bphy_err(drvr, "Null interface, bsscfgidx=%d\n", bsscfgidx);
return;
}
brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", bsscfgidx,
-@@ -918,16 +920,17 @@ static int brcmf_psm_watchdog_notify(str
+@@ -914,16 +916,17 @@ static int brcmf_psm_watchdog_notify(str
const struct brcmf_event_msg *evtmsg,
void *data)
{
return err;
}
-@@ -971,7 +974,7 @@ static int brcmf_inetaddr_changed(struct
+@@ -967,7 +970,7 @@ static int brcmf_inetaddr_changed(struct
ret = brcmf_fil_iovar_data_get(ifp, "arp_hostip", addr_table,
sizeof(addr_table));
if (ret) {
return NOTIFY_OK;
}
-@@ -988,7 +991,7 @@ static int brcmf_inetaddr_changed(struct
+@@ -984,7 +987,7 @@ static int brcmf_inetaddr_changed(struct
ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
&ifa->ifa_address, sizeof(ifa->ifa_address));
if (ret)
}
break;
case NETDEV_DOWN:
-@@ -1000,8 +1003,8 @@ static int brcmf_inetaddr_changed(struct
+@@ -996,8 +999,8 @@ static int brcmf_inetaddr_changed(struct
ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear",
NULL, 0);
if (ret) {
return NOTIFY_OK;
}
for (i = 0; i < ARPOL_MAX_ENTRIES; i++) {
-@@ -1011,8 +1014,8 @@ static int brcmf_inetaddr_changed(struct
+@@ -1007,8 +1010,8 @@ static int brcmf_inetaddr_changed(struct
&addr_table[i],
sizeof(addr_table[i]));
if (ret)
}
}
break;
-@@ -1186,7 +1189,7 @@ static int brcmf_bus_started(struct brcm
+@@ -1182,7 +1185,7 @@ static int brcmf_bus_started(struct brcm
return 0;
fail:
if (drvr->config) {
brcmf_cfg80211_detach(drvr->config);
drvr->config = NULL;
-@@ -1238,7 +1241,7 @@ int brcmf_attach(struct device *dev, str
+@@ -1234,7 +1237,7 @@ int brcmf_attach(struct device *dev, str
/* Attach and link in the protocol */
ret = brcmf_proto_attach(drvr);
if (ret != 0) {
goto fail;
}
-@@ -1251,7 +1254,7 @@ int brcmf_attach(struct device *dev, str
+@@ -1247,7 +1250,7 @@ int brcmf_attach(struct device *dev, str
ret = brcmf_bus_started(drvr, ops);
if (ret != 0) {
goto fail;
}
-@@ -1353,6 +1356,7 @@ static int brcmf_get_pend_8021x_cnt(stru
+@@ -1347,6 +1350,7 @@ static int brcmf_get_pend_8021x_cnt(stru
int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp)
{
int err;
err = wait_event_timeout(ifp->pend_8021x_wait,
-@@ -1360,7 +1364,7 @@ int brcmf_netdev_wait_pend8021x(struct b
+@@ -1354,7 +1358,7 @@ int brcmf_netdev_wait_pend8021x(struct b
MAX_WAIT_FOR_8021X_TX);
if (!err)
ifp->bsscfgidx, name, len);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
-@@ -1259,6 +1259,7 @@ static int brcmf_fws_enq(struct brcmf_fw
+@@ -1255,6 +1255,7 @@ static int brcmf_fws_enq(struct brcmf_fw
enum brcmf_fws_skb_state state, int fifo,
struct sk_buff *p)
{
int prec = 2 * fifo;
u32 *qfull_stat = &fws->stats.delayq_full_error;
struct brcmf_fws_mac_descriptor *entry;
-@@ -1271,7 +1272,7 @@ static int brcmf_fws_enq(struct brcmf_fw
+@@ -1267,7 +1268,7 @@ static int brcmf_fws_enq(struct brcmf_fw
entry = brcmf_skbcb(p)->mac;
if (entry == NULL) {
return -ENOENT;
}
-@@ -1461,6 +1462,7 @@ static int
+@@ -1457,6 +1458,7 @@ static int
brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
u32 genbit, u16 seq, u8 compcnt)
{
u32 fifo;
u8 cnt = 0;
int ret;
-@@ -1485,14 +1487,14 @@ brcmf_fws_txs_process(struct brcmf_fws_i
+@@ -1481,14 +1483,14 @@ brcmf_fws_txs_process(struct brcmf_fws_i
else if (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)
fws->stats.txs_host_tossed += compcnt;
else
goto cont;
}
-@@ -1616,12 +1618,13 @@ static int brcmf_fws_notify_credit_map(s
+@@ -1612,12 +1614,13 @@ static int brcmf_fws_notify_credit_map(s
const struct brcmf_event_msg *e,
void *data)
{
return -EINVAL;
}
-@@ -1685,6 +1688,7 @@ static void brcmf_rxreorder_get_skb_list
+@@ -1681,6 +1684,7 @@ static void brcmf_rxreorder_get_skb_list
void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt)
{
u8 *reorder_data;
u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
struct brcmf_ampdu_rx_reorder *rfi;
-@@ -1699,7 +1703,7 @@ void brcmf_fws_rxreorder(struct brcmf_if
+@@ -1695,7 +1699,7 @@ void brcmf_fws_rxreorder(struct brcmf_if
/* validate flags and flow id */
if (flags == 0xFF) {
brcmf_netif_rx(ifp, pkt);
return;
}
-@@ -1736,7 +1740,7 @@ void brcmf_fws_rxreorder(struct brcmf_if
+@@ -1732,7 +1736,7 @@ void brcmf_fws_rxreorder(struct brcmf_if
flow_id, max_idx);
rfi = kzalloc(buf_size, GFP_ATOMIC);
if (rfi == NULL) {
brcmf_netif_rx(ifp, pkt);
return;
}
-@@ -2000,6 +2004,7 @@ static u8 brcmf_fws_precommit_skb(struct
+@@ -1996,6 +2000,7 @@ static u8 brcmf_fws_precommit_skb(struct
static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
struct sk_buff *skb, int fifo)
{
struct brcmf_fws_mac_descriptor *entry;
struct sk_buff *pktout;
int qidx, hslot;
-@@ -2013,11 +2018,11 @@ static void brcmf_fws_rollback_toq(struc
+@@ -2009,11 +2014,11 @@ static void brcmf_fws_rollback_toq(struc
pktout = brcmu_pktq_penq_head(&entry->psq, qidx, skb);
if (pktout == NULL) {
rc = -ENOENT;
}
-@@ -2122,7 +2127,8 @@ static int brcmf_fws_assign_htod(struct
+@@ -2118,7 +2123,8 @@ static int brcmf_fws_assign_htod(struct
int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
{
struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
struct ethhdr *eh = (struct ethhdr *)(skb->data);
int fifo = BRCMF_FWS_FIFO_BCMC;
-@@ -2150,7 +2156,7 @@ int brcmf_fws_process_skb(struct brcmf_i
+@@ -2146,7 +2152,7 @@ int brcmf_fws_process_skb(struct brcmf_i
brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
brcmf_fws_schedule_deq(fws);
} else {
brcmf_txfinalize(ifp, skb, false);
rc = -ENOMEM;
}
-@@ -2371,7 +2377,7 @@ struct brcmf_fws_info *brcmf_fws_attach(
+@@ -2365,7 +2371,7 @@ struct brcmf_fws_info *brcmf_fws_attach(
fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
if (fws->fws_wq == NULL) {
rc = -EBADF;
goto fail;
}
-@@ -2387,13 +2393,13 @@ struct brcmf_fws_info *brcmf_fws_attach(
+@@ -2381,13 +2387,13 @@ struct brcmf_fws_info *brcmf_fws_attach(
rc = brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP,
brcmf_fws_notify_credit_map);
if (rc < 0) {
brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP);
goto fail;
}
-@@ -2405,7 +2411,7 @@ struct brcmf_fws_info *brcmf_fws_attach(
+@@ -2399,7 +2405,7 @@ struct brcmf_fws_info *brcmf_fws_attach(
fws->fw_signals = true;
ifp = brcmf_get_ifp(drvr, 0);
if (brcmf_fil_iovar_int_set(ifp, "tlv", tlv)) {
void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -1298,6 +1298,16 @@ void brcmf_dev_coredump(struct device *d
+@@ -1294,6 +1294,16 @@ void brcmf_dev_coredump(struct device *d
brcmf_dbg(TRACE, "failed to create coredump\n");
}
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
-@@ -1101,8 +1101,8 @@ static u32 brcmf_sdio_hostmail(struct br
+@@ -1090,8 +1090,8 @@ static u32 brcmf_sdio_hostmail(struct br
/* dongle indicates the firmware has halted/crashed */
if (hmb_data & HMB_DATA_FWHALT) {
*/
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -1109,6 +1109,14 @@ static int brcmf_revinfo_read(struct seq
+@@ -1105,6 +1105,14 @@ static int brcmf_revinfo_read(struct seq
return 0;
}
static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)
{
int ret = -1;
-@@ -1180,6 +1188,8 @@ static int brcmf_bus_started(struct brcm
+@@ -1176,6 +1184,8 @@ static int brcmf_bus_started(struct brcm
#endif
#endif /* CONFIG_INET */
/* populate debugfs */
brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read);
brcmf_feat_debugfs_create(drvr);
-@@ -1306,6 +1316,8 @@ void brcmf_fw_crashed(struct device *dev
+@@ -1302,6 +1312,8 @@ void brcmf_fw_crashed(struct device *dev
bphy_err(drvr, "Firmware has halted or crashed\n");
brcmf_dev_coredump(dev);
--- /dev/null
+From c80d26e81ef1802f30364b4ad1955c1443a592b9 Mon Sep 17 00:00:00 2001
+From: Piotr Figiel <p.figiel@camlintechnologies.com>
+Date: Mon, 4 Mar 2019 15:42:49 +0000
+Subject: [PATCH] brcmfmac: fix WARNING during USB disconnect in case of
+ unempty psq
+
+brcmu_pkt_buf_free_skb emits WARNING when attempting to free a sk_buff
+which is part of any queue. After USB disconnect this may have happened
+when brcmf_fws_hanger_cleanup() is called as per-interface psq was never
+cleaned when removing the interface.
+Change brcmf_fws_macdesc_cleanup() in a way that it removes the
+corresponding packets from hanger table (to avoid double-free when
+brcmf_fws_hanger_cleanup() is called) and add a call to clean-up the
+interface specific packet queue.
+
+Below is a WARNING during USB disconnect with Raspberry Pi WiFi dongle
+running in AP mode. This was reproducible when the interface was
+transmitting during the disconnect and is fixed with this commit.
+
+------------[ cut here ]------------
+WARNING: CPU: 0 PID: 1171 at drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c:49 brcmu_pkt_buf_free_skb+0x3c/0x40
+Modules linked in: nf_log_ipv4 nf_log_common xt_LOG xt_limit iptable_mangle xt_connmark xt_tcpudp xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 iptable_filter ip_tables x_tables usb_f_mass_storage usb_f_rndis u_ether cdc_acm smsc95xx usbnet ci_hdrc_imx ci_hdrc ulpi usbmisc_imx 8250_exar 8250_pci 8250 8250_base libcomposite configfs udc_core
+CPU: 0 PID: 1171 Comm: kworker/0:0 Not tainted 4.19.23-00075-gde33ed8 #99
+Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
+Workqueue: usb_hub_wq hub_event
+[<8010ff84>] (unwind_backtrace) from [<8010bb64>] (show_stack+0x10/0x14)
+[<8010bb64>] (show_stack) from [<80840278>] (dump_stack+0x88/0x9c)
+[<80840278>] (dump_stack) from [<8011f5ec>] (__warn+0xfc/0x114)
+[<8011f5ec>] (__warn) from [<8011f71c>] (warn_slowpath_null+0x40/0x48)
+[<8011f71c>] (warn_slowpath_null) from [<805a476c>] (brcmu_pkt_buf_free_skb+0x3c/0x40)
+[<805a476c>] (brcmu_pkt_buf_free_skb) from [<805bb6c4>] (brcmf_fws_cleanup+0x1e4/0x22c)
+[<805bb6c4>] (brcmf_fws_cleanup) from [<805bc854>] (brcmf_fws_del_interface+0x58/0x68)
+[<805bc854>] (brcmf_fws_del_interface) from [<805b66ac>] (brcmf_remove_interface+0x40/0x150)
+[<805b66ac>] (brcmf_remove_interface) from [<805b6870>] (brcmf_detach+0x6c/0xb0)
+[<805b6870>] (brcmf_detach) from [<805bdbb8>] (brcmf_usb_disconnect+0x30/0x4c)
+[<805bdbb8>] (brcmf_usb_disconnect) from [<805e5d64>] (usb_unbind_interface+0x5c/0x1e0)
+[<805e5d64>] (usb_unbind_interface) from [<804aab10>] (device_release_driver_internal+0x154/0x1ec)
+[<804aab10>] (device_release_driver_internal) from [<804a97f4>] (bus_remove_device+0xcc/0xf8)
+[<804a97f4>] (bus_remove_device) from [<804a6fc0>] (device_del+0x118/0x308)
+[<804a6fc0>] (device_del) from [<805e488c>] (usb_disable_device+0xa0/0x1c8)
+[<805e488c>] (usb_disable_device) from [<805dcf98>] (usb_disconnect+0x70/0x1d8)
+[<805dcf98>] (usb_disconnect) from [<805ddd84>] (hub_event+0x464/0xf50)
+[<805ddd84>] (hub_event) from [<80135a70>] (process_one_work+0x138/0x3f8)
+[<80135a70>] (process_one_work) from [<80135d5c>] (worker_thread+0x2c/0x554)
+[<80135d5c>] (worker_thread) from [<8013b1a0>] (kthread+0x124/0x154)
+[<8013b1a0>] (kthread) from [<801010e8>] (ret_from_fork+0x14/0x2c)
+Exception stack(0xecf8dfb0 to 0xecf8dff8)
+dfa0: 00000000 00000000 00000000 00000000
+dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
+dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
+---[ end trace 38d234018e9e2a90 ]---
+------------[ cut here ]------------
+
+Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../broadcom/brcm80211/brcmfmac/fwsignal.c | 42 +++++++++++--------
+ 1 file changed, 24 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+@@ -580,24 +580,6 @@ static bool brcmf_fws_ifidx_match(struct
+ return ifidx == *(int *)arg;
+ }
+
+-static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
+- int ifidx)
+-{
+- bool (*matchfn)(struct sk_buff *, void *) = NULL;
+- struct sk_buff *skb;
+- int prec;
+-
+- if (ifidx != -1)
+- matchfn = brcmf_fws_ifidx_match;
+- for (prec = 0; prec < q->num_prec; prec++) {
+- skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
+- while (skb) {
+- brcmu_pkt_buf_free_skb(skb);
+- skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
+- }
+- }
+-}
+-
+ static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
+ {
+ int i;
+@@ -669,6 +651,28 @@ static inline int brcmf_fws_hanger_poppk
+ return 0;
+ }
+
++static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
++ int ifidx)
++{
++ bool (*matchfn)(struct sk_buff *, void *) = NULL;
++ struct sk_buff *skb;
++ int prec;
++ u32 hslot;
++
++ if (ifidx != -1)
++ matchfn = brcmf_fws_ifidx_match;
++ for (prec = 0; prec < q->num_prec; prec++) {
++ skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
++ while (skb) {
++ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
++ brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
++ true);
++ brcmu_pkt_buf_free_skb(skb);
++ skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
++ }
++ }
++}
++
+ static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
+ u32 slot_id)
+ {
+@@ -2200,6 +2204,8 @@ void brcmf_fws_del_interface(struct brcm
+ brcmf_fws_lock(fws);
+ ifp->fws_desc = NULL;
+ brcmf_dbg(TRACE, "deleting %s\n", entry->name);
++ brcmf_fws_macdesc_cleanup(fws, &fws->desc.iface[ifp->ifidx],
++ ifp->ifidx);
+ brcmf_fws_macdesc_deinit(entry);
+ brcmf_fws_cleanup(fws, ifp->ifidx);
+ brcmf_fws_unlock(fws);
--- /dev/null
+From 5cdb0ef6144f47440850553579aa923c20a63f23 Mon Sep 17 00:00:00 2001
+From: Piotr Figiel <p.figiel@camlintechnologies.com>
+Date: Mon, 4 Mar 2019 15:42:52 +0000
+Subject: [PATCH] brcmfmac: fix NULL pointer derefence during USB disconnect
+
+In case USB disconnect happens at the moment transmitting workqueue is in
+progress the underlying interface may be gone causing a NULL pointer
+dereference. Add synchronization of the workqueue destruction with the
+detach implementation in core so that the transmitting workqueue is stopped
+during detach before the interfaces are removed.
+
+Fix following Oops:
+
+Unable to handle kernel NULL pointer dereference at virtual address 00000008
+pgd = 9e6a802d
+[00000008] *pgd=00000000
+Internal error: Oops: 5 [#1] PREEMPT SMP ARM
+Modules linked in: nf_log_ipv4 nf_log_common xt_LOG xt_limit iptable_mangle
+xt_connmark xt_tcpudp xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4
+iptable_filter ip_tables x_tables usb_f_mass_storage usb_f_rndis u_ether
+usb_serial_simple usbserial cdc_acm brcmfmac brcmutil smsc95xx usbnet
+ci_hdrc_imx ci_hdrc ulpi usbmisc_imx 8250_exar 8250_pci 8250 8250_base
+libcomposite configfs udc_core
+CPU: 0 PID: 7 Comm: kworker/u8:0 Not tainted 4.19.23-00076-g03740aa-dirty #102
+Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
+Workqueue: brcmf_fws_wq brcmf_fws_dequeue_worker [brcmfmac]
+PC is at brcmf_txfinalize+0x34/0x90 [brcmfmac]
+LR is at brcmf_fws_dequeue_worker+0x218/0x33c [brcmfmac]
+pc : [<7f0dee64>] lr : [<7f0e4140>] psr: 60010093
+sp : ee8abef0 ip : 00000000 fp : edf38000
+r10: ffffffed r9 : edf38970 r8 : edf38004
+r7 : edf3e970 r6 : 00000000 r5 : ede69000 r4 : 00000000
+r3 : 00000a97 r2 : 00000000 r1 : 0000888e r0 : ede69000
+Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none
+Control: 10c5387d Table: 7d03c04a DAC: 00000051
+Process kworker/u8:0 (pid: 7, stack limit = 0x24ec3e04)
+Stack: (0xee8abef0 to 0xee8ac000)
+bee0: ede69000 00000000 ed56c3e0 7f0e4140
+bf00: 00000001 00000000 edf38004 edf3e99c ed56c3e0 80d03d00 edfea43a edf3e970
+bf20: ee809880 ee804200 ee971100 00000000 edf3e974 00000000 ee804200 80135a70
+bf40: 80d03d00 ee804218 ee809880 ee809894 ee804200 80d03d00 ee804218 ee8aa000
+bf60: 00000088 80135d5c 00000000 ee829f00 ee829dc0 00000000 ee809880 80135d30
+bf80: ee829f1c ee873eac 00000000 8013b1a0 ee829dc0 8013b07c 00000000 00000000
+bfa0: 00000000 00000000 00000000 801010e8 00000000 00000000 00000000 00000000
+bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
+bfe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
+[<7f0dee64>] (brcmf_txfinalize [brcmfmac]) from [<7f0e4140>] (brcmf_fws_dequeue_worker+0x218/0x33c [brcmfmac])
+[<7f0e4140>] (brcmf_fws_dequeue_worker [brcmfmac]) from [<80135a70>] (process_one_work+0x138/0x3f8)
+[<80135a70>] (process_one_work) from [<80135d5c>] (worker_thread+0x2c/0x554)
+[<80135d5c>] (worker_thread) from [<8013b1a0>] (kthread+0x124/0x154)
+[<8013b1a0>] (kthread) from [<801010e8>] (ret_from_fork+0x14/0x2c)
+Exception stack(0xee8abfb0 to 0xee8abff8)
+bfa0: 00000000 00000000 00000000 00000000
+bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
+bfe0: 00000000 00000000 00000000 00000000 00000013 00000000
+Code: e1530001 0a000007 e3560000 e1a00005 (05942008)
+---[ end trace 079239dd31c86e90 ]---
+
+Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 11 +++++++++--
+ .../wireless/broadcom/brcm80211/brcmfmac/bcdc.h | 6 ++++--
+ .../wireless/broadcom/brcm80211/brcmfmac/core.c | 4 +++-
+ .../broadcom/brcm80211/brcmfmac/fwsignal.c | 16 ++++++++++++----
+ .../broadcom/brcm80211/brcmfmac/fwsignal.h | 3 ++-
+ .../wireless/broadcom/brcm80211/brcmfmac/proto.c | 10 ++++++++--
+ .../wireless/broadcom/brcm80211/brcmfmac/proto.h | 3 ++-
+ 7 files changed, 40 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
+@@ -490,11 +490,18 @@ fail:
+ return -ENOMEM;
+ }
+
+-void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr)
++void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr)
++{
++ struct brcmf_bcdc *bcdc = drvr->proto->pd;
++
++ brcmf_fws_detach_pre_delif(bcdc->fws);
++}
++
++void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr)
+ {
+ struct brcmf_bcdc *bcdc = drvr->proto->pd;
+
+ drvr->proto->pd = NULL;
+- brcmf_fws_detach(bcdc->fws);
++ brcmf_fws_detach_post_delif(bcdc->fws);
+ kfree(bcdc);
+ }
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
+@@ -18,14 +18,16 @@
+
+ #ifdef CPTCFG_BRCMFMAC_PROTO_BCDC
+ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr);
+-void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr);
++void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr);
++void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr);
+ void brcmf_proto_bcdc_txflowblock(struct device *dev, bool state);
+ void brcmf_proto_bcdc_txcomplete(struct device *dev, struct sk_buff *txp,
+ bool success);
+ struct brcmf_fws_info *drvr_to_fws(struct brcmf_pub *drvr);
+ #else
+ static inline int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) { return 0; }
+-static inline void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) {}
++static void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr) {};
++static inline void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr) {}
+ #endif
+
+ #endif /* BRCMFMAC_BCDC_H */
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+@@ -1342,6 +1342,8 @@ void brcmf_detach(struct device *dev)
+
+ brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
+
++ brcmf_proto_detach_pre_delif(drvr);
++
+ /* make sure primary interface removed last */
+ for (i = BRCMF_MAX_IFS-1; i > -1; i--)
+ brcmf_remove_interface(drvr->iflist[i], false);
+@@ -1351,7 +1353,7 @@ void brcmf_detach(struct device *dev)
+
+ brcmf_bus_stop(drvr->bus_if);
+
+- brcmf_proto_detach(drvr);
++ brcmf_proto_detach_post_delif(drvr);
+
+ bus_if->drvr = NULL;
+ wiphy_free(drvr->wiphy);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+@@ -2443,17 +2443,25 @@ struct brcmf_fws_info *brcmf_fws_attach(
+ return fws;
+
+ fail:
+- brcmf_fws_detach(fws);
++ brcmf_fws_detach_pre_delif(fws);
++ brcmf_fws_detach_post_delif(fws);
+ return ERR_PTR(rc);
+ }
+
+-void brcmf_fws_detach(struct brcmf_fws_info *fws)
++void brcmf_fws_detach_pre_delif(struct brcmf_fws_info *fws)
+ {
+ if (!fws)
+ return;
+-
+- if (fws->fws_wq)
++ if (fws->fws_wq) {
+ destroy_workqueue(fws->fws_wq);
++ fws->fws_wq = NULL;
++ }
++}
++
++void brcmf_fws_detach_post_delif(struct brcmf_fws_info *fws)
++{
++ if (!fws)
++ return;
+
+ /* cleanup */
+ brcmf_fws_lock(fws);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
+@@ -19,7 +19,8 @@
+ #define FWSIGNAL_H_
+
+ struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr);
+-void brcmf_fws_detach(struct brcmf_fws_info *fws);
++void brcmf_fws_detach_pre_delif(struct brcmf_fws_info *fws);
++void brcmf_fws_detach_post_delif(struct brcmf_fws_info *fws);
+ void brcmf_fws_debugfs_create(struct brcmf_pub *drvr);
+ bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws);
+ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
+@@ -67,16 +67,22 @@ fail:
+ return -ENOMEM;
+ }
+
+-void brcmf_proto_detach(struct brcmf_pub *drvr)
++void brcmf_proto_detach_post_delif(struct brcmf_pub *drvr)
+ {
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (drvr->proto) {
+ if (drvr->bus_if->proto_type == BRCMF_PROTO_BCDC)
+- brcmf_proto_bcdc_detach(drvr);
++ brcmf_proto_bcdc_detach_post_delif(drvr);
+ else if (drvr->bus_if->proto_type == BRCMF_PROTO_MSGBUF)
+ brcmf_proto_msgbuf_detach(drvr);
+ kfree(drvr->proto);
+ drvr->proto = NULL;
+ }
+ }
++
++void brcmf_proto_detach_pre_delif(struct brcmf_pub *drvr)
++{
++ if (drvr->proto && drvr->bus_if->proto_type == BRCMF_PROTO_BCDC)
++ brcmf_proto_bcdc_detach_pre_delif(drvr);
++}
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
+@@ -54,7 +54,8 @@ struct brcmf_proto {
+
+
+ int brcmf_proto_attach(struct brcmf_pub *drvr);
+-void brcmf_proto_detach(struct brcmf_pub *drvr);
++void brcmf_proto_detach_pre_delif(struct brcmf_pub *drvr);
++void brcmf_proto_detach_post_delif(struct brcmf_pub *drvr);
+
+ static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,
+ struct sk_buff *skb,
--- /dev/null
+From db3b9e2e1d58080d0754bdf9293dabf8c6491b67 Mon Sep 17 00:00:00 2001
+From: Piotr Figiel <p.figiel@camlintechnologies.com>
+Date: Fri, 8 Mar 2019 15:25:04 +0000
+Subject: [PATCH] brcmfmac: fix race during disconnect when USB completion is
+ in progress
+
+It was observed that rarely during USB disconnect happening shortly after
+connect (before full initialization completes) usb_hub_wq would wait
+forever for the dev_init_lock to be unlocked. dev_init_lock would remain
+locked though because of infinite wait during usb_kill_urb:
+
+[ 2730.656472] kworker/0:2 D 0 260 2 0x00000000
+[ 2730.660700] Workqueue: events request_firmware_work_func
+[ 2730.664807] [<809dca20>] (__schedule) from [<809dd164>] (schedule+0x4c/0xac)
+[ 2730.670587] [<809dd164>] (schedule) from [<8069af44>] (usb_kill_urb+0xdc/0x114)
+[ 2730.676815] [<8069af44>] (usb_kill_urb) from [<7f258b50>] (brcmf_usb_free_q+0x34/0xa8 [brcmfmac])
+[ 2730.684833] [<7f258b50>] (brcmf_usb_free_q [brcmfmac]) from [<7f2517d4>] (brcmf_detach+0xa0/0xb8 [brcmfmac])
+[ 2730.693557] [<7f2517d4>] (brcmf_detach [brcmfmac]) from [<7f251a34>] (brcmf_attach+0xac/0x3d8 [brcmfmac])
+[ 2730.702094] [<7f251a34>] (brcmf_attach [brcmfmac]) from [<7f2587ac>] (brcmf_usb_probe_phase2+0x468/0x4a0 [brcmfmac])
+[ 2730.711601] [<7f2587ac>] (brcmf_usb_probe_phase2 [brcmfmac]) from [<7f252888>] (brcmf_fw_request_done+0x194/0x220 [brcmfmac])
+[ 2730.721795] [<7f252888>] (brcmf_fw_request_done [brcmfmac]) from [<805748e4>] (request_firmware_work_func+0x4c/0x88)
+[ 2730.731125] [<805748e4>] (request_firmware_work_func) from [<80141474>] (process_one_work+0x228/0x808)
+[ 2730.739223] [<80141474>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
+[ 2730.746105] [<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
+[ 2730.752227] [<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
+
+[ 2733.099695] kworker/0:3 D 0 1065 2 0x00000000
+[ 2733.103926] Workqueue: usb_hub_wq hub_event
+[ 2733.106914] [<809dca20>] (__schedule) from [<809dd164>] (schedule+0x4c/0xac)
+[ 2733.112693] [<809dd164>] (schedule) from [<809e2a8c>] (schedule_timeout+0x214/0x3e4)
+[ 2733.119621] [<809e2a8c>] (schedule_timeout) from [<809dde2c>] (wait_for_common+0xc4/0x1c0)
+[ 2733.126810] [<809dde2c>] (wait_for_common) from [<7f258d00>] (brcmf_usb_disconnect+0x1c/0x4c [brcmfmac])
+[ 2733.135206] [<7f258d00>] (brcmf_usb_disconnect [brcmfmac]) from [<8069e0c8>] (usb_unbind_interface+0x5c/0x1e4)
+[ 2733.143943] [<8069e0c8>] (usb_unbind_interface) from [<8056d3e8>] (device_release_driver_internal+0x164/0x1fc)
+[ 2733.152769] [<8056d3e8>] (device_release_driver_internal) from [<8056c078>] (bus_remove_device+0xd0/0xfc)
+[ 2733.161138] [<8056c078>] (bus_remove_device) from [<8056977c>] (device_del+0x11c/0x310)
+[ 2733.167939] [<8056977c>] (device_del) from [<8069cba8>] (usb_disable_device+0xa0/0x1cc)
+[ 2733.174743] [<8069cba8>] (usb_disable_device) from [<8069507c>] (usb_disconnect+0x74/0x1dc)
+[ 2733.181823] [<8069507c>] (usb_disconnect) from [<80695e88>] (hub_event+0x478/0xf88)
+[ 2733.188278] [<80695e88>] (hub_event) from [<80141474>] (process_one_work+0x228/0x808)
+[ 2733.194905] [<80141474>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
+[ 2733.201724] [<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
+[ 2733.207913] [<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
+
+It was traced down to a case where usb_kill_urb would be called on an URB
+structure containing more or less random data, including large number in
+its use_count. During the debugging it appeared that in brcmf_usb_free_q()
+the traversal over URBs' lists is not synchronized with operations on those
+lists in brcmf_usb_rx_complete() leading to handling
+brcmf_usbdev_info structure (holding lists' head) as lists' element and in
+result causing above problem.
+
+Fix it by walking through all URBs during brcmf_cancel_all_urbs using the
+arrays of requests instead of linked lists.
+
+Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+@@ -682,12 +682,18 @@ static int brcmf_usb_up(struct device *d
+
+ static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo)
+ {
++ int i;
++
+ if (devinfo->ctl_urb)
+ usb_kill_urb(devinfo->ctl_urb);
+ if (devinfo->bulk_urb)
+ usb_kill_urb(devinfo->bulk_urb);
+- brcmf_usb_free_q(&devinfo->tx_postq, true);
+- brcmf_usb_free_q(&devinfo->rx_postq, true);
++ if (devinfo->tx_reqs)
++ for (i = 0; i < devinfo->bus_pub.ntxq; i++)
++ usb_kill_urb(devinfo->tx_reqs[i].urb);
++ if (devinfo->rx_reqs)
++ for (i = 0; i < devinfo->bus_pub.nrxq; i++)
++ usb_kill_urb(devinfo->rx_reqs[i].urb);
+ }
+
+ static void brcmf_usb_down(struct device *dev)
--- /dev/null
+From 24d413a31afaee9bbbf79226052c386b01780ce2 Mon Sep 17 00:00:00 2001
+From: Piotr Figiel <p.figiel@camlintechnologies.com>
+Date: Wed, 13 Mar 2019 09:52:01 +0000
+Subject: [PATCH] brcmfmac: fix Oops when bringing up interface during USB
+ disconnect
+
+Fix a race which leads to an Oops with NULL pointer dereference. The
+dereference is in brcmf_config_dongle() when cfg_to_ndev() attempts to get
+net_device structure of interface with index 0 via if2bss mapping. This
+shouldn't fail because of check for bus being ready in brcmf_netdev_open(),
+but it's not synchronised with USB disconnect and there is a race: after
+the check the bus can be marked down and the mapping for interface 0 may be
+gone.
+
+Solve this by modifying disconnect handling so that the removal of mapping
+of ifidx to brcmf_if structure happens after netdev removal (which is
+synchronous with brcmf_netdev_open() thanks to rtln being locked in
+devinet_ioctl()). This assures brcmf_netdev_open() returns before the
+mapping is removed during disconnect.
+
+Unable to handle kernel NULL pointer dereference at virtual address 00000008
+pgd = bcae2612
+[00000008] *pgd=8be73831
+Internal error: Oops: 17 [#1] PREEMPT SMP ARM
+Modules linked in: brcmfmac brcmutil nf_log_ipv4 nf_log_common xt_LOG xt_limit
+iptable_mangle xt_connmark xt_tcpudp xt_conntrack nf_conntrack nf_defrag_ipv6
+nf_defrag_ipv4 iptable_filter ip_tables x_tables usb_f_mass_storage usb_f_rndis
+u_ether usb_serial_simple usbserial cdc_acm smsc95xx usbnet ci_hdrc_imx ci_hdrc
+usbmisc_imx ulpi 8250_exar 8250_pci 8250 8250_base libcomposite configfs
+udc_core [last unloaded: brcmutil]
+CPU: 2 PID: 24478 Comm: ifconfig Not tainted 4.19.23-00078-ga62866d-dirty #115
+Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
+PC is at brcmf_cfg80211_up+0x94/0x29c [brcmfmac]
+LR is at brcmf_cfg80211_up+0x8c/0x29c [brcmfmac]
+pc : [<7f26a91c>] lr : [<7f26a914>] psr: a0070013
+sp : eca99d28 ip : 00000000 fp : ee9c6c00
+r10: 00000036 r9 : 00000000 r8 : ece4002c
+r7 : edb5b800 r6 : 00000000 r5 : 80f08448 r4 : edb5b968
+r3 : ffffffff r2 : 00000000 r1 : 00000002 r0 : 00000000
+Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
+Control: 10c5387d Table: 7ca0c04a DAC: 00000051
+Process ifconfig (pid: 24478, stack limit = 0xd9e85a0e)
+Stack: (0xeca99d28 to 0xeca9a000)
+9d20: 00000000 80f873b0 0000000d 80f08448 eca99d68 50d45f32
+9d40: 7f27de94 ece40000 80f08448 80f08448 7f27de94 ece4002c 00000000 00000036
+9d60: ee9c6c00 7f27262c 00001002 50d45f32 ece40000 00000000 80f08448 80772008
+9d80: 00000001 00001043 00001002 ece40000 00000000 50d45f32 ece40000 00000001
+9da0: 80f08448 00001043 00001002 807723d0 00000000 50d45f32 80f08448 eca99e58
+9dc0: 80f87113 50d45f32 80f08448 ece40000 ece40138 00001002 80f08448 00000000
+9de0: 00000000 80772434 edbd5380 eca99e58 edbd5380 80f08448 ee9c6c0c 80805f70
+9e00: 00000000 ede08e00 00008914 ece40000 00000014 ee9c6c0c 600c0013 00001043
+9e20: 0208a8c0 ffffffff 00000000 50d45f32 eca98000 80f08448 7ee9fc38 00008914
+9e40: 80f68e40 00000051 eca98000 00000036 00000003 80808b9c 6e616c77 00000030
+9e60: 00000000 00000000 00001043 0208a8c0 ffffffff 00000000 80f08448 00000000
+9e80: 00000000 816d8b20 600c0013 00000001 ede09320 801763d4 00000000 50d45f32
+9ea0: eca98000 80f08448 7ee9fc38 50d45f32 00008914 80f08448 7ee9fc38 80f68e40
+9ec0: ed531540 8074721c 00000800 00000001 00000000 6e616c77 00000030 00000000
+9ee0: 00000000 00001002 0208a8c0 ffffffff 00000000 50d45f32 80f08448 7ee9fc38
+9f00: ed531560 ec8fc900 80285a6c 80285138 edb910c0 00000000 ecd91008 ede08e00
+9f20: 80f08448 00000000 00000000 816d8b20 600c0013 00000001 ede09320 801763d4
+9f40: 00000000 50d45f32 00021000 edb91118 edb910c0 80f08448 01b29000 edb91118
+9f60: eca99f7c 50d45f32 00021000 ec8fc900 00000003 ec8fc900 00008914 7ee9fc38
+9f80: eca98000 00000036 00000003 80285a6c 00086364 7ee9fe1c 000000c3 00000036
+9fa0: 801011c4 80101000 00086364 7ee9fe1c 00000003 00008914 7ee9fc38 00086364
+9fc0: 00086364 7ee9fe1c 000000c3 00000036 0008630c 7ee9fe1c 7ee9fc38 00000003
+9fe0: 000a42b8 7ee9fbd4 00019914 76e09acc 600c0010 00000003 00000000 00000000
+[<7f26a91c>] (brcmf_cfg80211_up [brcmfmac]) from [<7f27262c>] (brcmf_netdev_open+0x74/0xe8 [brcmfmac])
+[<7f27262c>] (brcmf_netdev_open [brcmfmac]) from [<80772008>] (__dev_open+0xcc/0x150)
+[<80772008>] (__dev_open) from [<807723d0>] (__dev_change_flags+0x168/0x1b4)
+[<807723d0>] (__dev_change_flags) from [<80772434>] (dev_change_flags+0x18/0x48)
+[<80772434>] (dev_change_flags) from [<80805f70>] (devinet_ioctl+0x67c/0x79c)
+[<80805f70>] (devinet_ioctl) from [<80808b9c>] (inet_ioctl+0x210/0x3d4)
+[<80808b9c>] (inet_ioctl) from [<8074721c>] (sock_ioctl+0x350/0x524)
+[<8074721c>] (sock_ioctl) from [<80285138>] (do_vfs_ioctl+0xb0/0x9b0)
+[<80285138>] (do_vfs_ioctl) from [<80285a6c>] (ksys_ioctl+0x34/0x5c)
+[<80285a6c>] (ksys_ioctl) from [<80101000>] (ret_fast_syscall+0x0/0x28)
+Exception stack(0xeca99fa8 to 0xeca99ff0)
+9fa0: 00086364 7ee9fe1c 00000003 00008914 7ee9fc38 00086364
+9fc0: 00086364 7ee9fe1c 000000c3 00000036 0008630c 7ee9fe1c 7ee9fc38 00000003
+9fe0: 000a42b8 7ee9fbd4 00019914 76e09acc
+Code: e5970328 eb002021 e1a02006 e3a01002 (e5909008)
+---[ end trace 5cbac2333f3ac5df ]---
+
+Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../net/wireless/broadcom/brcm80211/brcmfmac/core.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+@@ -862,17 +862,17 @@ static void brcmf_del_if(struct brcmf_pu
+ bool rtnl_locked)
+ {
+ struct brcmf_if *ifp;
++ int ifidx;
+
+ ifp = drvr->iflist[bsscfgidx];
+- drvr->iflist[bsscfgidx] = NULL;
+ if (!ifp) {
+ bphy_err(drvr, "Null interface, bsscfgidx=%d\n", bsscfgidx);
+ return;
+ }
+ brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", bsscfgidx,
+ ifp->ifidx);
+- if (drvr->if2bss[ifp->ifidx] == bsscfgidx)
+- drvr->if2bss[ifp->ifidx] = BRCMF_BSSIDX_INVALID;
++ ifidx = ifp->ifidx;
++
+ if (ifp->ndev) {
+ if (bsscfgidx == 0) {
+ if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+@@ -900,6 +900,10 @@ static void brcmf_del_if(struct brcmf_pu
+ brcmf_p2p_ifp_removed(ifp, rtnl_locked);
+ kfree(ifp);
+ }
++
++ drvr->iflist[bsscfgidx] = NULL;
++ if (drvr->if2bss[ifidx] == bsscfgidx)
++ drvr->if2bss[ifidx] = BRCMF_BSSIDX_INVALID;
+ }
+
+ void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked)
--- /dev/null
+From a9fd0953fa4a62887306be28641b4b0809f3b2fd Mon Sep 17 00:00:00 2001
+From: Piotr Figiel <p.figiel@camlintechnologies.com>
+Date: Wed, 13 Mar 2019 09:52:42 +0000
+Subject: [PATCH] brcmfmac: convert dev_init_lock mutex to completion
+
+Leaving dev_init_lock mutex locked in probe causes BUG and a WARNING when
+kernel is compiled with CONFIG_PROVE_LOCKING. Convert mutex to completion
+which silences those warnings and improves code readability.
+
+Fix below errors when connecting the USB WiFi dongle:
+
+brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac43143 for chip BCM43143/2
+BUG: workqueue leaked lock or atomic: kworker/0:2/0x00000000/434
+ last function: hub_event
+1 lock held by kworker/0:2/434:
+ #0: 18d5dcdf (&devinfo->dev_init_lock){+.+.}, at: brcmf_usb_probe+0x78/0x550 [brcmfmac]
+CPU: 0 PID: 434 Comm: kworker/0:2 Not tainted 4.19.23-00084-g454a789-dirty #123
+Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
+Workqueue: usb_hub_wq hub_event
+[<8011237c>] (unwind_backtrace) from [<8010d74c>] (show_stack+0x10/0x14)
+[<8010d74c>] (show_stack) from [<809c4324>] (dump_stack+0xa8/0xd4)
+[<809c4324>] (dump_stack) from [<8014195c>] (process_one_work+0x710/0x808)
+[<8014195c>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
+[<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
+[<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
+Exception stack(0xed1d9fb0 to 0xed1d9ff8)
+9fa0: 00000000 00000000 00000000 00000000
+9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
+9fe0: 00000000 00000000 00000000 00000000 00000013 00000000
+
+======================================================
+WARNING: possible circular locking dependency detected
+4.19.23-00084-g454a789-dirty #123 Not tainted
+------------------------------------------------------
+kworker/0:2/434 is trying to acquire lock:
+e29cf799 ((wq_completion)"events"){+.+.}, at: process_one_work+0x174/0x808
+
+but task is already holding lock:
+18d5dcdf (&devinfo->dev_init_lock){+.+.}, at: brcmf_usb_probe+0x78/0x550 [brcmfmac]
+
+which lock already depends on the new lock.
+
+the existing dependency chain (in reverse order) is:
+
+-> #2 (&devinfo->dev_init_lock){+.+.}:
+ mutex_lock_nested+0x1c/0x24
+ brcmf_usb_probe+0x78/0x550 [brcmfmac]
+ usb_probe_interface+0xc0/0x1bc
+ really_probe+0x228/0x2c0
+ __driver_attach+0xe4/0xe8
+ bus_for_each_dev+0x68/0xb4
+ bus_add_driver+0x19c/0x214
+ driver_register+0x78/0x110
+ usb_register_driver+0x84/0x148
+ process_one_work+0x228/0x808
+ worker_thread+0x2c/0x564
+ kthread+0x13c/0x16c
+ ret_from_fork+0x14/0x20
+ (null)
+
+-> #1 (brcmf_driver_work){+.+.}:
+ worker_thread+0x2c/0x564
+ kthread+0x13c/0x16c
+ ret_from_fork+0x14/0x20
+ (null)
+
+-> #0 ((wq_completion)"events"){+.+.}:
+ process_one_work+0x1b8/0x808
+ worker_thread+0x2c/0x564
+ kthread+0x13c/0x16c
+ ret_from_fork+0x14/0x20
+ (null)
+
+other info that might help us debug this:
+
+Chain exists of:
+ (wq_completion)"events" --> brcmf_driver_work --> &devinfo->dev_init_lock
+
+ Possible unsafe locking scenario:
+
+ CPU0 CPU1
+ ---- ----
+ lock(&devinfo->dev_init_lock);
+ lock(brcmf_driver_work);
+ lock(&devinfo->dev_init_lock);
+ lock((wq_completion)"events");
+
+ *** DEADLOCK ***
+
+1 lock held by kworker/0:2/434:
+ #0: 18d5dcdf (&devinfo->dev_init_lock){+.+.}, at: brcmf_usb_probe+0x78/0x550 [brcmfmac]
+
+stack backtrace:
+CPU: 0 PID: 434 Comm: kworker/0:2 Not tainted 4.19.23-00084-g454a789-dirty #123
+Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
+Workqueue: events request_firmware_work_func
+[<8011237c>] (unwind_backtrace) from [<8010d74c>] (show_stack+0x10/0x14)
+[<8010d74c>] (show_stack) from [<809c4324>] (dump_stack+0xa8/0xd4)
+[<809c4324>] (dump_stack) from [<80172838>] (print_circular_bug+0x210/0x330)
+[<80172838>] (print_circular_bug) from [<80175940>] (__lock_acquire+0x160c/0x1a30)
+[<80175940>] (__lock_acquire) from [<8017671c>] (lock_acquire+0xe0/0x268)
+[<8017671c>] (lock_acquire) from [<80141404>] (process_one_work+0x1b8/0x808)
+[<80141404>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
+[<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
+[<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
+Exception stack(0xed1d9fb0 to 0xed1d9ff8)
+9fa0: 00000000 00000000 00000000 00000000
+9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
+9fe0: 00000000 00000000 00000000 00000000 00000013 00000000
+
+Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../wireless/broadcom/brcm80211/brcmfmac/usb.c | 17 ++++++++---------
+ 1 file changed, 8 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+@@ -160,7 +160,7 @@ struct brcmf_usbdev_info {
+
+ struct usb_device *usbdev;
+ struct device *dev;
+- struct mutex dev_init_lock;
++ struct completion dev_init_done;
+
+ int ctl_in_pipe, ctl_out_pipe;
+ struct urb *ctl_urb; /* URB for control endpoint */
+@@ -1194,11 +1194,11 @@ static void brcmf_usb_probe_phase2(struc
+ if (ret)
+ goto error;
+
+- mutex_unlock(&devinfo->dev_init_lock);
++ complete(&devinfo->dev_init_done);
+ return;
+ error:
+ brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret);
+- mutex_unlock(&devinfo->dev_init_lock);
++ complete(&devinfo->dev_init_done);
+ device_release_driver(dev);
+ }
+
+@@ -1266,7 +1266,7 @@ static int brcmf_usb_probe_cb(struct brc
+ if (ret)
+ goto fail;
+ /* we are done */
+- mutex_unlock(&devinfo->dev_init_lock);
++ complete(&devinfo->dev_init_done);
+ return 0;
+ }
+ bus->chip = bus_pub->devid;
+@@ -1326,11 +1326,10 @@ brcmf_usb_probe(struct usb_interface *in
+
+ devinfo->usbdev = usb;
+ devinfo->dev = &usb->dev;
+- /* Take an init lock, to protect for disconnect while still loading.
++ /* Init completion, to protect for disconnect while still loading.
+ * Necessary because of the asynchronous firmware load construction
+ */
+- mutex_init(&devinfo->dev_init_lock);
+- mutex_lock(&devinfo->dev_init_lock);
++ init_completion(&devinfo->dev_init_done);
+
+ usb_set_intfdata(intf, devinfo);
+
+@@ -1408,7 +1407,7 @@ brcmf_usb_probe(struct usb_interface *in
+ return 0;
+
+ fail:
+- mutex_unlock(&devinfo->dev_init_lock);
++ complete(&devinfo->dev_init_done);
+ kfree(devinfo);
+ usb_set_intfdata(intf, NULL);
+ return ret;
+@@ -1423,7 +1422,7 @@ brcmf_usb_disconnect(struct usb_interfac
+ devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);
+
+ if (devinfo) {
+- mutex_lock(&devinfo->dev_init_lock);
++ wait_for_completion(&devinfo->dev_init_done);
+ /* Make sure that devinfo still exists. Firmware probe routines
+ * may have released the device and cleared the intfdata.
+ */
--- /dev/null
+From 46953f97224d56a12ccbe9c6acaa84ca0dab2780 Mon Sep 17 00:00:00 2001
+From: Kangjie Lu <kjlu@umn.edu>
+Date: Fri, 15 Mar 2019 12:04:32 -0500
+Subject: [PATCH] brcmfmac: fix missing checks for kmemdup
+
+In case kmemdup fails, the fix sets conn_info->req_ie_len and
+conn_info->resp_ie_len to zero to avoid buffer overflows.
+
+Signed-off-by: Kangjie Lu <kjlu@umn.edu>
+Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -5464,6 +5464,8 @@ static s32 brcmf_get_assoc_ies(struct br
+ conn_info->req_ie =
+ kmemdup(cfg->extra_buf, conn_info->req_ie_len,
+ GFP_KERNEL);
++ if (!conn_info->req_ie)
++ conn_info->req_ie_len = 0;
+ } else {
+ conn_info->req_ie_len = 0;
+ conn_info->req_ie = NULL;
+@@ -5480,6 +5482,8 @@ static s32 brcmf_get_assoc_ies(struct br
+ conn_info->resp_ie =
+ kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
+ GFP_KERNEL);
++ if (!conn_info->resp_ie)
++ conn_info->resp_ie_len = 0;
+ } else {
+ conn_info->resp_ie_len = 0;
+ conn_info->resp_ie = NULL;
--- /dev/null
+From e025da3d7aa4770bb1d1b3b0aa7cc4da1744852d Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Wed, 24 Apr 2019 12:52:18 +0300
+Subject: [PATCH] brcm80211: potential NULL dereference in
+ brcmf_cfg80211_vndr_cmds_dcmd_handler()
+
+If "ret_len" is negative then it could lead to a NULL dereference.
+
+The "ret_len" value comes from nl80211_vendor_cmd(), if it's negative
+then we don't allocate the "dcmd_buf" buffer. Then we pass "ret_len" to
+brcmf_fil_cmd_data_set() where it is cast to a very high u32 value.
+Most of the functions in that call tree check whether the buffer we pass
+is NULL but there are at least a couple places which don't such as
+brcmf_dbg_hex_dump() and brcmf_msgbuf_query_dcmd(). We memcpy() to and
+from the buffer so it would result in a NULL dereference.
+
+The fix is to change the types so that "ret_len" can't be negative. (If
+we memcpy() zero bytes to NULL, that's a no-op and doesn't cause an
+issue).
+
+Fixes: 1bacb0487d0e ("brcmfmac: replace cfg80211 testmode with vendor command")
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
+@@ -35,9 +35,10 @@ static int brcmf_cfg80211_vndr_cmds_dcmd
+ struct brcmf_if *ifp;
+ const struct brcmf_vndr_dcmd_hdr *cmdhdr = data;
+ struct sk_buff *reply;
+- int ret, payload, ret_len;
++ unsigned int payload, ret_len;
+ void *dcmd_buf = NULL, *wr_pointer;
+ u16 msglen, maxmsglen = PAGE_SIZE - 0x100;
++ int ret;
+
+ if (len < sizeof(*cmdhdr)) {
+ brcmf_err("vendor command too short: %d\n", len);
+@@ -65,7 +66,7 @@ static int brcmf_cfg80211_vndr_cmds_dcmd
+ brcmf_err("oversize return buffer %d\n", ret_len);
+ ret_len = BRCMF_DCMD_MAXLEN;
+ }
+- payload = max(ret_len, len) + 1;
++ payload = max_t(unsigned int, ret_len, len) + 1;
+ dcmd_buf = vzalloc(payload);
+ if (NULL == dcmd_buf)
+ return -ENOMEM;
};
/* Hard-reset the chip. Do not call this directly.
-@@ -5523,6 +5563,8 @@ static int b43_one_core_attach(struct b4
+@@ -5521,6 +5561,8 @@ static int b43_one_core_attach(struct b4
if (!wldev)
goto out;
wldev->use_pio = b43_modparam_pio;
wldev->dev = dev;
wldev->wl = wl;
-@@ -5617,6 +5659,9 @@ static struct b43_wl *b43_wireless_init(
+@@ -5615,6 +5657,9 @@ static struct b43_wl *b43_wireless_init(
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+ hw->wiphy->available_antennas_rx = 0x3;
+ hw->wiphy->available_antennas_tx = 0x3;
+
- wl->hw_registred = false;
+ wl->hw_registered = false;
hw->max_rates = 2;
SET_IEEE80211_DEV(hw, dev->dev);
--- a/drivers/net/wireless/broadcom/b43/b43.h
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -2774,6 +2774,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
+@@ -2782,6 +2782,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
* preference in cfg struct to apply this to
* FW later while initializing the dongle
*/
--- a/local-symbols
+++ b/local-symbols
-@@ -396,43 +396,6 @@ USB_IPHETH=
+@@ -398,43 +398,6 @@ USB_IPHETH=
USB_SIERRA_NET=
USB_VL600=
USB_NET_CH9200=
select BRCMUTIL
--- a/Kconfig.local
+++ b/Kconfig.local
-@@ -1192,117 +1192,6 @@ config BACKPORTED_USB_VL600
+@@ -1198,117 +1198,6 @@ config BACKPORTED_USB_VL600
config BACKPORTED_USB_NET_CH9200
tristate
default USB_NET_CH9200
--- a/drivers/net/wireless/marvell/mwl8k.c
+++ b/drivers/net/wireless/marvell/mwl8k.c
-@@ -5691,6 +5691,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
+@@ -5686,6 +5686,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API));
static const struct pci_device_id mwl8k_pci_id_table[] = {
err_wiphy_new:
--- a/drivers/net/wireless/marvell/libertas/main.c
+++ b/drivers/net/wireless/marvell/libertas/main.c
-@@ -930,6 +930,7 @@ struct lbs_private *lbs_add_card(void *c
+@@ -934,6 +934,7 @@ struct lbs_private *lbs_add_card(void *c
goto err_adapter;
}
--- a/drivers/net/wireless/marvell/mwl8k.c
+++ b/drivers/net/wireless/marvell/mwl8k.c
-@@ -6276,6 +6276,8 @@ static int mwl8k_probe(struct pci_dev *p
+@@ -6271,6 +6271,8 @@ static int mwl8k_probe(struct pci_dev *p
priv->running_bsses = 0;
return rc;
err_stop_firmware:
-@@ -6309,8 +6311,6 @@ static void mwl8k_remove(struct pci_dev
+@@ -6304,8 +6306,6 @@ static void mwl8k_remove(struct pci_dev
return;
priv = hw->priv;
--- /dev/null
+From b897577af85bb5e5638efa780bc3716fae5212d3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
+Date: Mon, 8 Apr 2019 09:45:56 +0200
+Subject: [PATCH] mwl8k: Fix rate_idx underflow
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It was reported on OpenWrt bug tracking system[1], that several users
+are affected by the endless reboot of their routers if they configure
+5GHz interface with channel 44 or 48.
+
+The reboot loop is caused by the following excessive number of WARN_ON
+messages:
+
+ WARNING: CPU: 0 PID: 0 at backports-4.19.23-1/net/mac80211/rx.c:4516
+ ieee80211_rx_napi+0x1fc/0xa54 [mac80211]
+
+as the messages are being correctly emitted by the following guard:
+
+ case RX_ENC_LEGACY:
+ if (WARN_ON(status->rate_idx >= sband->n_bitrates))
+
+as the rate_idx is in this case erroneously set to 251 (0xfb). This fix
+simply converts previously used magic number to proper constant and
+guards against substraction which is leading to the currently observed
+underflow.
+
+1. https://bugs.openwrt.org/index.php?do=details&task_id=2218
+
+Fixes: 854783444bab ("mwl8k: properly set receive status rate index on 5 GHz receive")
+Cc: <stable@vger.kernel.org>
+Tested-by: Eubert Bao <bunnier@gmail.com>
+Reported-by: Eubert Bao <bunnier@gmail.com>
+Signed-off-by: Petr Å tetiar <ynezz@true.cz>
+---
+ drivers/net/wireless/marvell/mwl8k.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireless/marvell/mwl8k.c
++++ b/drivers/net/wireless/marvell/mwl8k.c
+@@ -441,6 +441,9 @@ static const struct ieee80211_rate mwl8k
+ #define MWL8K_CMD_UPDATE_STADB 0x1123
+ #define MWL8K_CMD_BASTREAM 0x1125
+
++#define MWL8K_LEGACY_5G_RATE_OFFSET \
++ (ARRAY_SIZE(mwl8k_rates_24) - ARRAY_SIZE(mwl8k_rates_50))
++
+ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
+ {
+ u16 command = le16_to_cpu(cmd);
+@@ -1016,8 +1019,9 @@ mwl8k_rxd_ap_process(void *_rxd, struct
+
+ if (rxd->channel > 14) {
+ status->band = NL80211_BAND_5GHZ;
+- if (!(status->encoding == RX_ENC_HT))
+- status->rate_idx -= 5;
++ if (!(status->encoding == RX_ENC_HT) &&
++ status->rate_idx >= MWL8K_LEGACY_5G_RATE_OFFSET)
++ status->rate_idx -= MWL8K_LEGACY_5G_RATE_OFFSET;
+ } else {
+ status->band = NL80211_BAND_2GHZ;
+ }
+@@ -1124,8 +1128,9 @@ mwl8k_rxd_sta_process(void *_rxd, struct
+
+ if (rxd->channel > 14) {
+ status->band = NL80211_BAND_5GHZ;
+- if (!(status->encoding == RX_ENC_HT))
+- status->rate_idx -= 5;
++ if (!(status->encoding == RX_ENC_HT) &&
++ status->rate_idx >= MWL8K_LEGACY_5G_RATE_OFFSET)
++ status->rate_idx -= MWL8K_LEGACY_5G_RATE_OFFSET;
+ } else {
+ status->band = NL80211_BAND_2GHZ;
+ }
+++ /dev/null
-From f483039cf51acf30494cd754194562c22cf98764 Mon Sep 17 00:00:00 2001
-From: Dan Carpenter <dan.carpenter@oracle.com>
-Date: Wed, 22 Aug 2018 13:41:26 +0300
-Subject: [PATCH 01/28] rt2x00: use simple_read_from_buffer()
-
-The problem with this copy_to_user() calls is that they don't ensure
-that "size" is less than the "length" which the user provided.
-
-Obviously, this is debugfs and "size" is normally going to be very small
-so it probably doesn't matter, but this is the correct thing to do.
-
-Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
-Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- .../net/wireless/ralink/rt2x00/rt2x00debug.c | 18 +++---------------
- 1 file changed, 3 insertions(+), 15 deletions(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
-@@ -464,11 +464,7 @@ static ssize_t rt2x00debug_read_##__name
- \
- size = sprintf(line, __format, value); \
- \
-- if (copy_to_user(buf, line, size)) \
-- return -EFAULT; \
-- \
-- *offset += size; \
-- return size; \
-+ return simple_read_from_buffer(buf, length, offset, line, size); \
- }
-
- #define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \
-@@ -545,11 +541,7 @@ static ssize_t rt2x00debug_read_dev_flag
-
- size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags);
-
-- if (copy_to_user(buf, line, size))
-- return -EFAULT;
--
-- *offset += size;
-- return size;
-+ return simple_read_from_buffer(buf, length, offset, line, size);
- }
-
- static const struct file_operations rt2x00debug_fop_dev_flags = {
-@@ -574,11 +566,7 @@ static ssize_t rt2x00debug_read_cap_flag
-
- size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags);
-
-- if (copy_to_user(buf, line, size))
-- return -EFAULT;
--
-- *offset += size;
-- return size;
-+ return simple_read_from_buffer(buf, length, offset, line, size);
- }
-
- static const struct file_operations rt2x00debug_fop_cap_flags = {
+++ /dev/null
-From 5c656c71b1bf5611ce8262bab338104e04d10b8d Mon Sep 17 00:00:00 2001
-From: Stanislaw Gruszka <sgruszka@redhat.com>
-Date: Wed, 26 Sep 2018 12:24:53 +0200
-Subject: [PATCH 02/28] rt2800: move usb specific txdone/txstatus routines to
- rt2800lib
-
-In order to reuse usb txdone/txstatus routines for mmio, move them
-to common rt2800lib.c file.
-
-Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- .../net/wireless/ralink/rt2x00/rt2800lib.c | 138 +++++++++++++++++
- .../net/wireless/ralink/rt2x00/rt2800lib.h | 3 +
- .../net/wireless/ralink/rt2x00/rt2800usb.c | 143 +-----------------
- 3 files changed, 145 insertions(+), 139 deletions(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -957,6 +957,47 @@ static void rt2800_rate_from_status(stru
- skbdesc->tx_rate_flags = flags;
- }
-
-+static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg)
-+{
-+ __le32 *txwi;
-+ u32 word;
-+ int wcid, ack, pid;
-+ int tx_wcid, tx_ack, tx_pid, is_agg;
-+
-+ /*
-+ * This frames has returned with an IO error,
-+ * so the status report is not intended for this
-+ * frame.
-+ */
-+ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
-+ return false;
-+
-+ wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
-+ ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
-+ pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
-+ is_agg = rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE);
-+
-+ /*
-+ * Validate if this TX status report is intended for
-+ * this entry by comparing the WCID/ACK/PID fields.
-+ */
-+ txwi = rt2800_drv_get_txwi(entry);
-+
-+ word = rt2x00_desc_read(txwi, 1);
-+ tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
-+ tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
-+ tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
-+
-+ if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) {
-+ rt2x00_dbg(entry->queue->rt2x00dev,
-+ "TX status report missed for queue %d entry %d\n",
-+ entry->queue->qid, entry->entry_idx);
-+ return false;
-+ }
-+
-+ return true;
-+}
-+
- void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi,
- bool match)
- {
-@@ -1059,6 +1100,103 @@ void rt2800_txdone_entry(struct queue_en
- }
- EXPORT_SYMBOL_GPL(rt2800_txdone_entry);
-
-+void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
-+{
-+ struct data_queue *queue;
-+ struct queue_entry *entry;
-+ u32 reg;
-+ u8 qid;
-+ bool match;
-+
-+ while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) {
-+ /*
-+ * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is
-+ * guaranteed to be one of the TX QIDs .
-+ */
-+ qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
-+ queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
-+
-+ if (unlikely(rt2x00queue_empty(queue))) {
-+ rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
-+ qid);
-+ break;
-+ }
-+
-+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-+
-+ if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
-+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) {
-+ rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n",
-+ entry->entry_idx, qid);
-+ break;
-+ }
-+
-+ match = rt2800_txdone_entry_check(entry, reg);
-+ rt2800_txdone_entry(entry, reg, rt2800_drv_get_txwi(entry), match);
-+ }
-+}
-+EXPORT_SYMBOL_GPL(rt2800_txdone);
-+
-+static inline bool rt2800_entry_txstatus_timeout(struct queue_entry *entry)
-+{
-+ bool tout;
-+
-+ if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
-+ return false;
-+
-+ tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(500));
-+ if (unlikely(tout))
-+ rt2x00_dbg(entry->queue->rt2x00dev,
-+ "TX status timeout for entry %d in queue %d\n",
-+ entry->entry_idx, entry->queue->qid);
-+ return tout;
-+
-+}
-+
-+bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev)
-+{
-+ struct data_queue *queue;
-+ struct queue_entry *entry;
-+
-+ tx_queue_for_each(rt2x00dev, queue) {
-+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-+ if (rt2800_entry_txstatus_timeout(entry))
-+ return true;
-+ }
-+ return false;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_txstatus_timeout);
-+
-+void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev)
-+{
-+ struct data_queue *queue;
-+ struct queue_entry *entry;
-+
-+ /*
-+ * Process any trailing TX status reports for IO failures,
-+ * we loop until we find the first non-IO error entry. This
-+ * can either be a frame which is free, is being uploaded,
-+ * or has completed the upload but didn't have an entry
-+ * in the TX_STAT_FIFO register yet.
-+ */
-+ tx_queue_for_each(rt2x00dev, queue) {
-+ while (!rt2x00queue_empty(queue)) {
-+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-+
-+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
-+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
-+ break;
-+
-+ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) ||
-+ rt2800_entry_txstatus_timeout(entry))
-+ rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
-+ else
-+ break;
-+ }
-+ }
-+}
-+EXPORT_SYMBOL_GPL(rt2800_txdone_nostatus);
-+
- static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
- unsigned int index)
- {
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
-@@ -195,6 +195,9 @@ void rt2800_process_rxwi(struct queue_en
-
- void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi,
- bool match);
-+void rt2800_txdone(struct rt2x00_dev *rt2x00dev);
-+void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev);
-+bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev);
-
- void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
- void rt2800_clear_beacon(struct queue_entry *entry);
---- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
-@@ -116,35 +116,6 @@ static bool rt2800usb_txstatus_pending(s
- return false;
- }
-
--static inline bool rt2800usb_entry_txstatus_timeout(struct queue_entry *entry)
--{
-- bool tout;
--
-- if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
-- return false;
--
-- tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(500));
-- if (unlikely(tout))
-- rt2x00_dbg(entry->queue->rt2x00dev,
-- "TX status timeout for entry %d in queue %d\n",
-- entry->entry_idx, entry->queue->qid);
-- return tout;
--
--}
--
--static bool rt2800usb_txstatus_timeout(struct rt2x00_dev *rt2x00dev)
--{
-- struct data_queue *queue;
-- struct queue_entry *entry;
--
-- tx_queue_for_each(rt2x00dev, queue) {
-- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-- if (rt2800usb_entry_txstatus_timeout(entry))
-- return true;
-- }
-- return false;
--}
--
- #define TXSTATUS_READ_INTERVAL 1000000
-
- static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
-@@ -171,7 +142,7 @@ static bool rt2800usb_tx_sta_fifo_read_c
- }
-
- /* Check if there is any entry that timedout waiting on TX status */
-- if (rt2800usb_txstatus_timeout(rt2x00dev))
-+ if (rt2800_txstatus_timeout(rt2x00dev))
- queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
-
- if (rt2800usb_txstatus_pending(rt2x00dev)) {
-@@ -501,123 +472,17 @@ static int rt2800usb_get_tx_data_len(str
- /*
- * TX control handlers
- */
--static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg)
--{
-- __le32 *txwi;
-- u32 word;
-- int wcid, ack, pid;
-- int tx_wcid, tx_ack, tx_pid, is_agg;
--
-- /*
-- * This frames has returned with an IO error,
-- * so the status report is not intended for this
-- * frame.
-- */
-- if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
-- return false;
--
-- wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
-- ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
-- pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
-- is_agg = rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE);
--
-- /*
-- * Validate if this TX status report is intended for
-- * this entry by comparing the WCID/ACK/PID fields.
-- */
-- txwi = rt2800usb_get_txwi(entry);
--
-- word = rt2x00_desc_read(txwi, 1);
-- tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
-- tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
-- tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
--
-- if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) {
-- rt2x00_dbg(entry->queue->rt2x00dev,
-- "TX status report missed for queue %d entry %d\n",
-- entry->queue->qid, entry->entry_idx);
-- return false;
-- }
--
-- return true;
--}
--
--static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev)
--{
-- struct data_queue *queue;
-- struct queue_entry *entry;
-- u32 reg;
-- u8 qid;
-- bool match;
--
-- while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) {
-- /*
-- * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is
-- * guaranteed to be one of the TX QIDs .
-- */
-- qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
-- queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
--
-- if (unlikely(rt2x00queue_empty(queue))) {
-- rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
-- qid);
-- break;
-- }
--
-- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
--
-- if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
-- !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) {
-- rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n",
-- entry->entry_idx, qid);
-- break;
-- }
--
-- match = rt2800usb_txdone_entry_check(entry, reg);
-- rt2800_txdone_entry(entry, reg, rt2800usb_get_txwi(entry), match);
-- }
--}
--
--static void rt2800usb_txdone_nostatus(struct rt2x00_dev *rt2x00dev)
--{
-- struct data_queue *queue;
-- struct queue_entry *entry;
--
-- /*
-- * Process any trailing TX status reports for IO failures,
-- * we loop until we find the first non-IO error entry. This
-- * can either be a frame which is free, is being uploaded,
-- * or has completed the upload but didn't have an entry
-- * in the TX_STAT_FIFO register yet.
-- */
-- tx_queue_for_each(rt2x00dev, queue) {
-- while (!rt2x00queue_empty(queue)) {
-- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
--
-- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
-- !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
-- break;
--
-- if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) ||
-- rt2800usb_entry_txstatus_timeout(entry))
-- rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
-- else
-- break;
-- }
-- }
--}
--
- static void rt2800usb_work_txdone(struct work_struct *work)
- {
- struct rt2x00_dev *rt2x00dev =
- container_of(work, struct rt2x00_dev, txdone_work);
-
- while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) ||
-- rt2800usb_txstatus_timeout(rt2x00dev)) {
-+ rt2800_txstatus_timeout(rt2x00dev)) {
-
-- rt2800usb_txdone(rt2x00dev);
-+ rt2800_txdone(rt2x00dev);
-
-- rt2800usb_txdone_nostatus(rt2x00dev);
-+ rt2800_txdone_nostatus(rt2x00dev);
-
- /*
- * The hw may delay sending the packet after DMA complete
+++ /dev/null
-From 0b0d556e0ebb6c966bc993e21a22a156812d8fdf Mon Sep 17 00:00:00 2001
-From: Stanislaw Gruszka <sgruszka@redhat.com>
-Date: Wed, 26 Sep 2018 12:24:54 +0200
-Subject: [PATCH 03/28] rt2800mmio: use txdone/txstatus routines from lib
-
-Use usb txdone/txstatus routines (now in rt2800libc) for mmio devices.
-
-Note this also change how we handle INT_SOURCE_CSR_TX_FIFO_STATUS
-interrupt. Now it is disabled since IRQ routine till end of the txstatus
-tasklet (the same behaviour like others interrupts). Reason to do not
-disable this interrupt was not to miss any tx status from 16 entries
-FIFO register. Now, since we check for tx status timeout, we can
-allow to miss some tx statuses. However this will be improved in further
-patch where I also implement read status FIFO register in the tasklet.
-
-Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- .../net/wireless/ralink/rt2x00/rt2800mmio.c | 180 +-----------------
- .../net/wireless/ralink/rt2x00/rt2x00queue.c | 1 +
- 2 files changed, 9 insertions(+), 172 deletions(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
-@@ -175,161 +175,6 @@ static void rt2800mmio_wakeup(struct rt2
- rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
- }
-
--static bool rt2800mmio_txdone_entry_check(struct queue_entry *entry, u32 status)
--{
-- __le32 *txwi;
-- u32 word;
-- int wcid, tx_wcid;
--
-- wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID);
--
-- txwi = rt2800_drv_get_txwi(entry);
-- word = rt2x00_desc_read(txwi, 1);
-- tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
--
-- return (tx_wcid == wcid);
--}
--
--static bool rt2800mmio_txdone_find_entry(struct queue_entry *entry, void *data)
--{
-- u32 status = *(u32 *)data;
--
-- /*
-- * rt2800pci hardware might reorder frames when exchanging traffic
-- * with multiple BA enabled STAs.
-- *
-- * For example, a tx queue
-- * [ STA1 | STA2 | STA1 | STA2 ]
-- * can result in tx status reports
-- * [ STA1 | STA1 | STA2 | STA2 ]
-- * when the hw decides to aggregate the frames for STA1 into one AMPDU.
-- *
-- * To mitigate this effect, associate the tx status to the first frame
-- * in the tx queue with a matching wcid.
-- */
-- if (rt2800mmio_txdone_entry_check(entry, status) &&
-- !test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
-- /*
-- * Got a matching frame, associate the tx status with
-- * the frame
-- */
-- entry->status = status;
-- set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
-- return true;
-- }
--
-- /* Check the next frame */
-- return false;
--}
--
--static bool rt2800mmio_txdone_match_first(struct queue_entry *entry, void *data)
--{
-- u32 status = *(u32 *)data;
--
-- /*
-- * Find the first frame without tx status and assign this status to it
-- * regardless if it matches or not.
-- */
-- if (!test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
-- /*
-- * Got a matching frame, associate the tx status with
-- * the frame
-- */
-- entry->status = status;
-- set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
-- return true;
-- }
--
-- /* Check the next frame */
-- return false;
--}
--static bool rt2800mmio_txdone_release_entries(struct queue_entry *entry,
-- void *data)
--{
-- if (test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
-- rt2800_txdone_entry(entry, entry->status,
-- rt2800mmio_get_txwi(entry), true);
-- return false;
-- }
--
-- /* No more frames to release */
-- return true;
--}
--
--static bool rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev)
--{
-- struct data_queue *queue;
-- u32 status;
-- u8 qid;
-- int max_tx_done = 16;
--
-- while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) {
-- qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE);
-- if (unlikely(qid >= QID_RX)) {
-- /*
-- * Unknown queue, this shouldn't happen. Just drop
-- * this tx status.
-- */
-- rt2x00_warn(rt2x00dev, "Got TX status report with unexpected pid %u, dropping\n",
-- qid);
-- break;
-- }
--
-- queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
-- if (unlikely(queue == NULL)) {
-- /*
-- * The queue is NULL, this shouldn't happen. Stop
-- * processing here and drop the tx status
-- */
-- rt2x00_warn(rt2x00dev, "Got TX status for an unavailable queue %u, dropping\n",
-- qid);
-- break;
-- }
--
-- if (unlikely(rt2x00queue_empty(queue))) {
-- /*
-- * The queue is empty. Stop processing here
-- * and drop the tx status.
-- */
-- rt2x00_warn(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
-- qid);
-- break;
-- }
--
-- /*
-- * Let's associate this tx status with the first
-- * matching frame.
-- */
-- if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
-- Q_INDEX, &status,
-- rt2800mmio_txdone_find_entry)) {
-- /*
-- * We cannot match the tx status to any frame, so just
-- * use the first one.
-- */
-- if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
-- Q_INDEX, &status,
-- rt2800mmio_txdone_match_first)) {
-- rt2x00_warn(rt2x00dev, "No frame found for TX status on queue %u, dropping\n",
-- qid);
-- break;
-- }
-- }
--
-- /*
-- * Release all frames with a valid tx status.
-- */
-- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
-- Q_INDEX, NULL,
-- rt2800mmio_txdone_release_entries);
--
-- if (--max_tx_done == 0)
-- break;
-- }
--
-- return !max_tx_done;
--}
--
- static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev,
- struct rt2x00_field32 irq_field)
- {
-@@ -349,14 +194,14 @@ static inline void rt2800mmio_enable_int
- void rt2800mmio_txstatus_tasklet(unsigned long data)
- {
- struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
-- if (rt2800mmio_txdone(rt2x00dev))
-- tasklet_schedule(&rt2x00dev->txstatus_tasklet);
-
-- /*
-- * No need to enable the tx status interrupt here as we always
-- * leave it enabled to minimize the possibility of a tx status
-- * register overflow. See comment in interrupt handler.
-- */
-+ rt2800_txdone(rt2x00dev);
-+
-+ rt2800_txdone_nostatus(rt2x00dev);
-+
-+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
-+ rt2800mmio_enable_interrupt(rt2x00dev,
-+ INT_SOURCE_CSR_TX_FIFO_STATUS);
- }
- EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
-
-@@ -440,10 +285,6 @@ static void rt2800mmio_txstatus_interrup
- * because we can schedule the tasklet multiple times (when the
- * interrupt fires again during tx status processing).
- *
-- * Furthermore we don't disable the TX_FIFO_STATUS
-- * interrupt here but leave it enabled so that the TX_STA_FIFO
-- * can also be read while the tx status tasklet gets executed.
-- *
- * Since we have only one producer and one consumer we don't
- * need to lock the kfifo.
- */
-@@ -485,13 +326,8 @@ irqreturn_t rt2800mmio_interrupt(int irq
- */
- mask = ~reg;
-
-- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
-+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
- rt2800mmio_txstatus_interrupt(rt2x00dev);
-- /*
-- * Never disable the TX_FIFO_STATUS interrupt.
-- */
-- rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1);
-- }
-
- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
- tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet);
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
-@@ -113,6 +113,7 @@ int rt2x00queue_map_txskb(struct queue_e
- return -ENOMEM;
-
- skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
-+ rt2x00lib_dmadone(entry);
- return 0;
- }
- EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
+++ /dev/null
-From 5022efb50f625d11fdf18b1fee0f64ebb1863664 Mon Sep 17 00:00:00 2001
-From: Stanislaw Gruszka <sgruszka@redhat.com>
-Date: Wed, 26 Sep 2018 12:24:55 +0200
-Subject: [PATCH 04/28] rt2x00: do not check for txstatus timeout every time on
- tasklet
-
-Do not check for tx status timeout everytime we perform txstatus tasklet.
-Perform check once per half a second.
-
-Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 7 +++++++
- drivers/net/wireless/ralink/rt2x00/rt2800mmio.c | 3 ++-
- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 2 ++
- drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 1 +
- 4 files changed, 12 insertions(+), 1 deletion(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -1158,11 +1158,18 @@ bool rt2800_txstatus_timeout(struct rt2x
- struct data_queue *queue;
- struct queue_entry *entry;
-
-+ if (time_before(jiffies,
-+ rt2x00dev->last_nostatus_check + msecs_to_jiffies(500)))
-+ return false;
-+
-+ rt2x00dev->last_nostatus_check = jiffies;
-+
- tx_queue_for_each(rt2x00dev, queue) {
- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- if (rt2800_entry_txstatus_timeout(entry))
- return true;
- }
-+
- return false;
- }
- EXPORT_SYMBOL_GPL(rt2800_txstatus_timeout);
---- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
-@@ -197,7 +197,8 @@ void rt2800mmio_txstatus_tasklet(unsigne
-
- rt2800_txdone(rt2x00dev);
-
-- rt2800_txdone_nostatus(rt2x00dev);
-+ if (rt2800_txstatus_timeout(rt2x00dev))
-+ rt2800_txdone_nostatus(rt2x00dev);
-
- if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2800mmio_enable_interrupt(rt2x00dev,
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -979,6 +979,8 @@ struct rt2x00_dev {
- */
- DECLARE_KFIFO_PTR(txstatus_fifo, u32);
-
-+ unsigned long last_nostatus_check;
-+
- /*
- * Timer to ensure tx status reports are read (rt2800usb).
- */
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
-@@ -1042,6 +1042,7 @@ void rt2x00queue_start_queues(struct rt2
- */
- tx_queue_for_each(rt2x00dev, queue)
- rt2x00queue_start_queue(queue);
-+ rt2x00dev->last_nostatus_check = jiffies;
-
- rt2x00queue_start_queue(rt2x00dev->rx);
- }
+++ /dev/null
-From adf26a356f132e35093585521ea3e36cd185af83 Mon Sep 17 00:00:00 2001
-From: Stanislaw Gruszka <sgruszka@redhat.com>
-Date: Wed, 26 Sep 2018 12:24:56 +0200
-Subject: [PATCH 05/28] rt2x00: use different txstatus timeouts when flushing
-
-Use different tx status timeouts for normal operation and when flushing.
-This increase timeout to 2s for normal operation as when there are bad
-radio conditions and frames are reposted many times device can not provide
-the status for quite long. With new timeout we can still get valid status
-on such bad conditions.
-
-Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- .../net/wireless/ralink/rt2x00/rt2800lib.c | 31 +++++++++++++------
- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 +
- .../net/wireless/ralink/rt2x00/rt2x00mac.c | 4 +++
- 3 files changed, 26 insertions(+), 10 deletions(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -1137,36 +1137,47 @@ void rt2800_txdone(struct rt2x00_dev *rt
- }
- EXPORT_SYMBOL_GPL(rt2800_txdone);
-
--static inline bool rt2800_entry_txstatus_timeout(struct queue_entry *entry)
-+static inline bool rt2800_entry_txstatus_timeout(struct rt2x00_dev *rt2x00dev,
-+ struct queue_entry *entry)
- {
-- bool tout;
-+ bool ret;
-+ unsigned long tout;
-
- if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
- return false;
-
-- tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(500));
-- if (unlikely(tout))
-+ if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags))
-+ tout = msecs_to_jiffies(100);
-+ else
-+ tout = msecs_to_jiffies(2000);
-+
-+ ret = time_after(jiffies, entry->last_action + tout);
-+ if (unlikely(ret))
- rt2x00_dbg(entry->queue->rt2x00dev,
- "TX status timeout for entry %d in queue %d\n",
- entry->entry_idx, entry->queue->qid);
-- return tout;
--
-+ return ret;
- }
-
- bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev)
- {
- struct data_queue *queue;
- struct queue_entry *entry;
-+ unsigned long tout;
-+
-+ if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags))
-+ tout = msecs_to_jiffies(50);
-+ else
-+ tout = msecs_to_jiffies(1000);
-
-- if (time_before(jiffies,
-- rt2x00dev->last_nostatus_check + msecs_to_jiffies(500)))
-+ if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout))
- return false;
-
- rt2x00dev->last_nostatus_check = jiffies;
-
- tx_queue_for_each(rt2x00dev, queue) {
- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-- if (rt2800_entry_txstatus_timeout(entry))
-+ if (rt2800_entry_txstatus_timeout(rt2x00dev, entry))
- return true;
- }
-
-@@ -1195,7 +1206,7 @@ void rt2800_txdone_nostatus(struct rt2x0
- break;
-
- if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) ||
-- rt2800_entry_txstatus_timeout(entry))
-+ rt2800_entry_txstatus_timeout(rt2x00dev, entry))
- rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
- else
- break;
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -665,6 +665,7 @@ enum rt2x00_state_flags {
- DEVICE_STATE_STARTED,
- DEVICE_STATE_ENABLED_RADIO,
- DEVICE_STATE_SCANNING,
-+ DEVICE_STATE_FLUSHING,
-
- /*
- * Driver configuration
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
-@@ -710,8 +710,12 @@ void rt2x00mac_flush(struct ieee80211_hw
- if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
- return;
-
-+ set_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags);
-+
- tx_queue_for_each(rt2x00dev, queue)
- rt2x00queue_flush_queue(queue, drop);
-+
-+ clear_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags);
- }
- EXPORT_SYMBOL_GPL(rt2x00mac_flush);
-
+++ /dev/null
-From 0240564430c0697d8fde3743d70346a922466b36 Mon Sep 17 00:00:00 2001
-From: Stanislaw Gruszka <sgruszka@redhat.com>
-Date: Wed, 26 Sep 2018 12:24:57 +0200
-Subject: [PATCH 06/28] rt2800: flush and txstatus rework for rt2800mmio
-
-Implement custom rt2800mmio flush routine and change txstatus
-routine to read TX_STA_FIFO also in the tasklet.
-
-Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- .../net/wireless/ralink/rt2x00/rt2800lib.c | 14 +--
- .../net/wireless/ralink/rt2x00/rt2800mmio.c | 118 +++++++++++++-----
- .../net/wireless/ralink/rt2x00/rt2800mmio.h | 1 +
- .../net/wireless/ralink/rt2x00/rt2800pci.c | 2 +-
- 4 files changed, 97 insertions(+), 38 deletions(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -1147,7 +1147,7 @@ static inline bool rt2800_entry_txstatus
- return false;
-
- if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags))
-- tout = msecs_to_jiffies(100);
-+ tout = msecs_to_jiffies(50);
- else
- tout = msecs_to_jiffies(2000);
-
-@@ -1163,15 +1163,13 @@ bool rt2800_txstatus_timeout(struct rt2x
- {
- struct data_queue *queue;
- struct queue_entry *entry;
-- unsigned long tout;
-
-- if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags))
-- tout = msecs_to_jiffies(50);
-- else
-- tout = msecs_to_jiffies(1000);
-+ if (!test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags)) {
-+ unsigned long tout = msecs_to_jiffies(1000);
-
-- if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout))
-- return false;
-+ if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout))
-+ return false;
-+ }
-
- rt2x00dev->last_nostatus_check = jiffies;
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
-@@ -191,21 +191,6 @@ static inline void rt2800mmio_enable_int
- spin_unlock_irq(&rt2x00dev->irqmask_lock);
- }
-
--void rt2800mmio_txstatus_tasklet(unsigned long data)
--{
-- struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
--
-- rt2800_txdone(rt2x00dev);
--
-- if (rt2800_txstatus_timeout(rt2x00dev))
-- rt2800_txdone_nostatus(rt2x00dev);
--
-- if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
-- rt2800mmio_enable_interrupt(rt2x00dev,
-- INT_SOURCE_CSR_TX_FIFO_STATUS);
--}
--EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
--
- void rt2800mmio_pretbtt_tasklet(unsigned long data)
- {
- struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
-@@ -270,12 +255,26 @@ void rt2800mmio_autowake_tasklet(unsigne
- }
- EXPORT_SYMBOL_GPL(rt2800mmio_autowake_tasklet);
-
--static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
-+static void rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev)
-+{
-+ bool timeout = false;
-+
-+ while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) ||
-+ (timeout = rt2800_txstatus_timeout(rt2x00dev))) {
-+
-+ rt2800_txdone(rt2x00dev);
-+
-+ if (timeout)
-+ rt2800_txdone_nostatus(rt2x00dev);
-+ }
-+}
-+
-+static bool rt2800mmio_fetch_txstatus(struct rt2x00_dev *rt2x00dev)
- {
- u32 status;
-- int i;
-+ bool more = false;
-
-- /*
-+ /* FIXEME: rewrite this comment
- * The TX_FIFO_STATUS interrupt needs special care. We should
- * read TX_STA_FIFO but we should do it immediately as otherwise
- * the register can overflow and we would lose status reports.
-@@ -286,25 +285,37 @@ static void rt2800mmio_txstatus_interrup
- * because we can schedule the tasklet multiple times (when the
- * interrupt fires again during tx status processing).
- *
-- * Since we have only one producer and one consumer we don't
-+ * txstatus tasklet is called with INT_SOURCE_CSR_TX_FIFO_STATUS
-+ * disabled so have only one producer and one consumer - we don't
- * need to lock the kfifo.
- */
-- for (i = 0; i < rt2x00dev->tx->limit; i++) {
-+ while (!kfifo_is_full(&rt2x00dev->txstatus_fifo)) {
- status = rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO);
--
- if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
- break;
-
-- if (!kfifo_put(&rt2x00dev->txstatus_fifo, status)) {
-- rt2x00_warn(rt2x00dev, "TX status FIFO overrun, drop tx status report\n");
-- break;
-- }
-+ kfifo_put(&rt2x00dev->txstatus_fifo, status);
-+ more = true;
- }
-
-- /* Schedule the tasklet for processing the tx status. */
-- tasklet_schedule(&rt2x00dev->txstatus_tasklet);
-+ return more;
- }
-
-+void rt2800mmio_txstatus_tasklet(unsigned long data)
-+{
-+ struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
-+
-+ do {
-+ rt2800mmio_txdone(rt2x00dev);
-+
-+ } while (rt2800mmio_fetch_txstatus(rt2x00dev));
-+
-+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
-+ rt2800mmio_enable_interrupt(rt2x00dev,
-+ INT_SOURCE_CSR_TX_FIFO_STATUS);
-+}
-+EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
-+
- irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance)
- {
- struct rt2x00_dev *rt2x00dev = dev_instance;
-@@ -327,8 +338,10 @@ irqreturn_t rt2800mmio_interrupt(int irq
- */
- mask = ~reg;
-
-- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
-- rt2800mmio_txstatus_interrupt(rt2x00dev);
-+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
-+ rt2800mmio_fetch_txstatus(rt2x00dev);
-+ tasklet_schedule(&rt2x00dev->txstatus_tasklet);
-+ }
-
- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
- tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet);
-@@ -453,6 +466,53 @@ void rt2800mmio_kick_queue(struct data_q
- }
- EXPORT_SYMBOL_GPL(rt2800mmio_kick_queue);
-
-+void rt2800mmio_flush_queue(struct data_queue *queue, bool drop)
-+{
-+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
-+ bool tx_queue = false;
-+ unsigned int i;
-+
-+ switch (queue->qid) {
-+ case QID_AC_VO:
-+ case QID_AC_VI:
-+ case QID_AC_BE:
-+ case QID_AC_BK:
-+ tx_queue = true;
-+ break;
-+ case QID_RX:
-+ break;
-+ default:
-+ return;
-+ }
-+
-+ for (i = 0; i < 5; i++) {
-+ /*
-+ * Check if the driver is already done, otherwise we
-+ * have to sleep a little while to give the driver/hw
-+ * the oppurtunity to complete interrupt process itself.
-+ */
-+ if (rt2x00queue_empty(queue))
-+ break;
-+
-+ /*
-+ * For TX queues schedule completion tasklet to catch
-+ * tx status timeouts, othewise just wait.
-+ */
-+ if (tx_queue) {
-+ tasklet_disable(&rt2x00dev->txstatus_tasklet);
-+ rt2800mmio_txdone(rt2x00dev);
-+ tasklet_enable(&rt2x00dev->txstatus_tasklet);
-+ }
-+
-+ /*
-+ * Wait for a little while to give the driver
-+ * the oppurtunity to recover itself.
-+ */
-+ msleep(50);
-+ }
-+}
-+EXPORT_SYMBOL_GPL(rt2800mmio_flush_queue);
-+
- void rt2800mmio_stop_queue(struct data_queue *queue)
- {
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
---- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
-@@ -148,6 +148,7 @@ void rt2800mmio_toggle_irq(struct rt2x00
- /* Queue handlers */
- void rt2800mmio_start_queue(struct data_queue *queue);
- void rt2800mmio_kick_queue(struct data_queue *queue);
-+void rt2800mmio_flush_queue(struct data_queue *queue, bool drop);
- void rt2800mmio_stop_queue(struct data_queue *queue);
- void rt2800mmio_queue_init(struct data_queue *queue);
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
-@@ -364,7 +364,7 @@ static const struct rt2x00lib_ops rt2800
- .start_queue = rt2800mmio_start_queue,
- .kick_queue = rt2800mmio_kick_queue,
- .stop_queue = rt2800mmio_stop_queue,
-- .flush_queue = rt2x00mmio_flush_queue,
-+ .flush_queue = rt2800mmio_flush_queue,
- .write_tx_desc = rt2800mmio_write_tx_desc,
- .write_tx_data = rt2800_write_tx_data,
- .write_beacon = rt2800_write_beacon,
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
-@@ -6597,6 +6597,11 @@ int cfg80211_external_auth_request(struc
+@@ -6666,6 +6666,11 @@ int cfg80211_external_auth_request(struc
#define wiphy_info(wiphy, format, args...) \
dev_info(&(wiphy)->dev, format, ##args)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -1016,6 +1016,7 @@ struct rt2x00_dev {
+@@ -1017,6 +1017,7 @@ struct rt2x00_dev {
unsigned int extra_tx_headroom;
struct usb_anchor *anchor;
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
-@@ -674,7 +674,7 @@ int rt2x00queue_write_tx_frame(struct da
+@@ -671,7 +671,7 @@ int rt2x00queue_write_tx_frame(struct da
spin_lock(&queue->tx_lock);
if (unlikely(rt2x00queue_full(queue))) {
if (rt2800_entry_txstatus_timeout(rt2x00dev, entry))
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -980,8 +980,6 @@ struct rt2x00_dev {
+@@ -981,8 +981,6 @@ struct rt2x00_dev {
*/
DECLARE_KFIFO_PTR(txstatus_fifo, u32);
*/
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
-@@ -1042,7 +1042,6 @@ void rt2x00queue_start_queues(struct rt2
+@@ -1039,7 +1039,6 @@ void rt2x00queue_start_queues(struct rt2
*/
tx_queue_for_each(rt2x00dev, queue)
rt2x00queue_start_queue(queue);
--- /dev/null
+From 746ba11f170603bf1eaade817553a6c2e9135bbe Mon Sep 17 00:00:00 2001
+From: Vijayakumar Durai <vijayakumar.durai1@vivint.com>
+Date: Wed, 27 Mar 2019 11:03:17 +0100
+Subject: [PATCH] rt2x00: do not increment sequence number while
+ re-transmitting
+
+Currently rt2x00 devices retransmit the management frames with
+incremented sequence number if hardware is assigning the sequence.
+
+This is HW bug fixed already for non-QOS data frames, but it should
+be fixed for management frames except beacon.
+
+Without fix retransmitted frames have wrong SN:
+
+ AlphaNet_e8:fb:36 Vivotek_52:31:51 Authentication, SN=1648, FN=0, Flags=........C Frame is not being retransmitted 1648 1
+ AlphaNet_e8:fb:36 Vivotek_52:31:51 Authentication, SN=1649, FN=0, Flags=....R...C Frame is being retransmitted 1649 1
+ AlphaNet_e8:fb:36 Vivotek_52:31:51 Authentication, SN=1650, FN=0, Flags=....R...C Frame is being retransmitted 1650 1
+
+With the fix SN stays correctly the same:
+
+ 88:6a:e3:e8:f9:a2 8c:f5:a3:88:76:87 Authentication, SN=1450, FN=0, Flags=........C
+ 88:6a:e3:e8:f9:a2 8c:f5:a3:88:76:87 Authentication, SN=1450, FN=0, Flags=....R...C
+ 88:6a:e3:e8:f9:a2 8c:f5:a3:88:76:87 Authentication, SN=1450, FN=0, Flags=....R...C
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Vijayakumar Durai <vijayakumar.durai1@vivint.com>
+[sgruszka: simplify code, change comments and changelog]
+Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 -
+ drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 10 ----------
+ drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 15 +++++++++------
+ 3 files changed, 9 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+@@ -673,7 +673,6 @@ enum rt2x00_state_flags {
+ CONFIG_CHANNEL_HT40,
+ CONFIG_POWERSAVING,
+ CONFIG_HT_DISABLED,
+- CONFIG_QOS_DISABLED,
+ CONFIG_MONITORING,
+
+ /*
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
+@@ -642,19 +642,9 @@ void rt2x00mac_bss_info_changed(struct i
+ rt2x00dev->intf_associated--;
+
+ rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
+-
+- clear_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags);
+ }
+
+ /*
+- * Check for access point which do not support 802.11e . We have to
+- * generate data frames sequence number in S/W for such AP, because
+- * of H/W bug.
+- */
+- if (changes & BSS_CHANGED_QOS && !bss_conf->qos)
+- set_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags);
+-
+- /*
+ * When the erp information has changed, we should perform
+ * additional configuration steps. For all other changes we are done.
+ */
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+@@ -201,15 +201,18 @@ static void rt2x00queue_create_tx_descri
+ if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_SW_SEQNO)) {
+ /*
+ * rt2800 has a H/W (or F/W) bug, device incorrectly increase
+- * seqno on retransmited data (non-QOS) frames. To workaround
+- * the problem let's generate seqno in software if QOS is
+- * disabled.
++ * seqno on retransmitted data (non-QOS) and management frames.
++ * To workaround the problem let's generate seqno in software.
++ * Except for beacons which are transmitted periodically by H/W
++ * hence hardware has to assign seqno for them.
+ */
+- if (test_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags))
+- __clear_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+- else
++ if (ieee80211_is_beacon(hdr->frame_control)) {
++ __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+ /* H/W will generate sequence number */
+ return;
++ }
++
++ __clear_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+ }
+
+ /*
--- a/local-symbols
+++ b/local-symbols
-@@ -305,6 +305,7 @@ RT2X00_LIB_FIRMWARE=
+@@ -307,6 +307,7 @@ RT2X00_LIB_FIRMWARE=
RT2X00_LIB_CRYPTO=
RT2X00_LIB_LEDS=
RT2X00_LIB_DEBUGFS=
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_key *key = rx->key;
struct ieee80211_mmie_16 *mmie;
-- u8 aad[GMAC_AAD_LEN], *mic, ipn[6], nonce[GMAC_NONCE_LEN];
-+ u8 aad[20], *mic, ipn[6], nonce[12];
+- u8 aad[GMAC_AAD_LEN], mic[GMAC_MIC_LEN], ipn[6], nonce[GMAC_NONCE_LEN];
++ u8 aad[20], mic[16], ipn[6], nonce[12];
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
if (!ieee80211_is_mgmt(hdr->frame_control))
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -1067,7 +1067,6 @@ static int ieee80211_stop_ap(struct wiph
- sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
+@@ -1127,7 +1127,6 @@ static int ieee80211_stop_ap(struct wiph
+ sdata->vif.bss_conf.ftmr_params = NULL;
__sta_info_flush(sdata, true);
- ieee80211_free_keys(sdata, true);
* Copyright 2016, Qualcomm Atheros, Inc.
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
-@@ -570,7 +570,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
+@@ -571,7 +571,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
NL80211_FEATURE_MAC_ON_CREATE |
NL80211_FEATURE_USERSPACE_MPM |
NL80211_FEATURE_FULL_AP_CLIENT_STATE;
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -3800,6 +3800,12 @@ out:
+@@ -3834,6 +3834,12 @@ out:
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
-@@ -315,7 +315,7 @@ void ieee80211_restart_hw(struct ieee802
+@@ -316,7 +316,7 @@ void ieee80211_restart_hw(struct ieee802
}
EXPORT_SYMBOL(ieee80211_restart_hw);
static int ieee80211_ifa_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
-@@ -374,7 +374,7 @@ static int ieee80211_ifa_changed(struct
+@@ -375,7 +375,7 @@ static int ieee80211_ifa_changed(struct
}
#endif
static int ieee80211_ifa6_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
-@@ -1168,14 +1168,14 @@ int ieee80211_register_hw(struct ieee802
+@@ -1232,14 +1232,14 @@ int ieee80211_register_hw(struct ieee802
rtnl_unlock();
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
result = register_inet6addr_notifier(&local->ifa6_notifier);
if (result)
-@@ -1184,13 +1184,13 @@ int ieee80211_register_hw(struct ieee802
+@@ -1248,13 +1248,13 @@ int ieee80211_register_hw(struct ieee802
return 0;
fail_ifa:
#endif
rtnl_lock();
-@@ -1219,10 +1219,10 @@ void ieee80211_unregister_hw(struct ieee
+@@ -1283,10 +1283,10 @@ void ieee80211_unregister_hw(struct ieee
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -2237,7 +2237,7 @@ static int ieee80211_scan(struct wiphy *
+@@ -2253,7 +2253,7 @@ static int ieee80211_scan(struct wiphy *
* the frames sent while scanning on other channel will be
* lost)
*/
+++ /dev/null
-From: Manikanta Pubbisetty <mpubbise@codeaurora.org>
-Date: Wed, 11 Jul 2018 00:12:53 +0530
-Subject: [PATCH] mac80211: add stop/start logic for software TXQs
-
-Sometimes, it is required to stop the transmissions momentarily and
-resume it later; stopping the txqs becomes very critical in scenarios where
-the packet transmission has to be ceased completely. For example, during
-the hardware restart, during off channel operations,
-when initiating CSA(upon detecting a radar on the DFS channel), etc.
-
-The TX queue stop/start logic in mac80211 works well in stopping the TX
-when drivers make use of netdev queues, i.e, when Qdiscs in network layer
-take care of traffic scheduling. Since the devices implementing
-wake_tx_queue can run without Qdiscs, packets will be handed to mac80211
-directly without queueing them in the netdev queues.
-
-Also, mac80211 does not invoke any of the
-netif_stop_*/netif_wake_* APIs if wake_tx_queue is implemented.
-Since the queues are not stopped in this case, transmissions can continue
-and this will impact negatively on the operation of the wireless device.
-
-For example,
-During hardware restart, we stop the netdev queues so that packets are
-not sent to the driver. Since ath10k implements wake_tx_queue,
-TX queues will not be stopped and packets might reach the hardware while
-it is restarting; this can make hardware unresponsive and the only
-possible option for recovery is to reboot the entire system.
-
-There is another problem to this, it is observed that the packets
-were sent on the DFS channel for a prolonged duration after radar
-detection impacting the channel closing time.
-
-We can still invoke netif stop/wake APIs when wake_tx_queue is implemented
-but this could lead to packet drops in network layer; adding stop/start
-logic for software TXQs in mac80211 instead makes more sense; the change
-proposed adds the same in mac80211.
-
-Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -1504,6 +1504,8 @@ enum ieee80211_vif_flags {
- * @drv_priv: data area for driver use, will always be aligned to
- * sizeof(void \*).
- * @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
-+ * @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped,
-+ * protected by fq->lock.
- */
- struct ieee80211_vif {
- enum nl80211_iftype type;
-@@ -1528,6 +1530,8 @@ struct ieee80211_vif {
-
- unsigned int probe_req_reg;
-
-+ bool txqs_stopped[IEEE80211_NUM_ACS];
-+
- /* must be last */
- u8 drv_priv[0] __aligned(sizeof(void *));
- };
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -818,6 +818,7 @@ enum txq_info_flags {
- IEEE80211_TXQ_STOP,
- IEEE80211_TXQ_AMPDU,
- IEEE80211_TXQ_NO_AMSDU,
-+ IEEE80211_TXQ_STOP_NETIF_TX,
- };
-
- /**
-@@ -1226,6 +1227,7 @@ struct ieee80211_local {
-
- struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
- struct tasklet_struct tx_pending_tasklet;
-+ struct tasklet_struct wake_txqs_tasklet;
-
- atomic_t agg_queue_stop[IEEE80211_MAX_QUEUES];
-
-@@ -2039,6 +2041,7 @@ void ieee80211_txq_remove_vlan(struct ie
- struct ieee80211_sub_if_data *sdata);
- void ieee80211_fill_txq_stats(struct cfg80211_txq_stats *txqstats,
- struct txq_info *txqi);
-+void ieee80211_wake_txqs(unsigned long data);
- void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
- u16 transaction, u16 auth_alg, u16 status,
- const u8 *extra, size_t extra_len, const u8 *bssid,
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -686,6 +686,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_
- tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
- (unsigned long)local);
-
-+ if (ops->wake_tx_queue)
-+ tasklet_init(&local->wake_txqs_tasklet, ieee80211_wake_txqs,
-+ (unsigned long)local);
-+
- tasklet_init(&local->tasklet,
- ieee80211_tasklet_handler,
- (unsigned long) local);
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -3485,13 +3485,19 @@ struct sk_buff *ieee80211_tx_dequeue(str
- struct ieee80211_tx_info *info;
- struct ieee80211_tx_data tx;
- ieee80211_tx_result r;
-- struct ieee80211_vif *vif;
-+ struct ieee80211_vif *vif = txq->vif;
-
- spin_lock_bh(&fq->lock);
-
-- if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
-+ if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ||
-+ test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags))
- goto out;
-
-+ if (vif->txqs_stopped[ieee80211_ac_from_tid(txq->tid)]) {
-+ set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags);
-+ goto out;
-+ }
-+
- /* Make sure fragments stay together. */
- skb = __skb_dequeue(&txqi->frags);
- if (skb)
-@@ -3586,6 +3592,7 @@ begin:
- }
-
- IEEE80211_SKB_CB(skb)->control.vif = vif;
-+
- out:
- spin_unlock_bh(&fq->lock);
-
---- a/net/mac80211/util.c
-+++ b/net/mac80211/util.c
-@@ -240,6 +240,99 @@ __le16 ieee80211_ctstoself_duration(stru
- }
- EXPORT_SYMBOL(ieee80211_ctstoself_duration);
-
-+static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
-+{
-+ struct ieee80211_local *local = sdata->local;
-+ struct ieee80211_vif *vif = &sdata->vif;
-+ struct fq *fq = &local->fq;
-+ struct ps_data *ps = NULL;
-+ struct txq_info *txqi;
-+ struct sta_info *sta;
-+ int i;
-+
-+ spin_lock_bh(&fq->lock);
-+
-+ if (sdata->vif.type == NL80211_IFTYPE_AP)
-+ ps = &sdata->bss->ps;
-+
-+ sdata->vif.txqs_stopped[ac] = false;
-+
-+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
-+ if (sdata != sta->sdata)
-+ continue;
-+
-+ for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
-+ struct ieee80211_txq *txq = sta->sta.txq[i];
-+
-+ txqi = to_txq_info(txq);
-+
-+ if (ac != txq->ac)
-+ continue;
-+
-+ if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX,
-+ &txqi->flags))
-+ continue;
-+
-+ spin_unlock_bh(&fq->lock);
-+ drv_wake_tx_queue(local, txqi);
-+ spin_lock_bh(&fq->lock);
-+ }
-+ }
-+
-+ if (!vif->txq)
-+ goto out;
-+
-+ txqi = to_txq_info(vif->txq);
-+
-+ if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags) ||
-+ (ps && atomic_read(&ps->num_sta_ps)) || ac != vif->txq->ac)
-+ goto out;
-+
-+ spin_unlock_bh(&fq->lock);
-+
-+ drv_wake_tx_queue(local, txqi);
-+ return;
-+out:
-+ spin_unlock_bh(&fq->lock);
-+}
-+
-+void ieee80211_wake_txqs(unsigned long data)
-+{
-+ struct ieee80211_local *local = (struct ieee80211_local *)data;
-+ struct ieee80211_sub_if_data *sdata;
-+ int n_acs = IEEE80211_NUM_ACS;
-+ unsigned long flags;
-+ int i;
-+
-+ rcu_read_lock();
-+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-+
-+ if (local->hw.queues < IEEE80211_NUM_ACS)
-+ n_acs = 1;
-+
-+ for (i = 0; i < local->hw.queues; i++) {
-+ if (local->queue_stop_reasons[i])
-+ continue;
-+
-+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-+ int ac;
-+
-+ for (ac = 0; ac < n_acs; ac++) {
-+ int ac_queue = sdata->vif.hw_queue[ac];
-+
-+ if (ac_queue == i ||
-+ sdata->vif.cab_queue == i)
-+ __ieee80211_wake_txqs(sdata, ac);
-+ }
-+ }
-+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-+ }
-+
-+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-+ rcu_read_unlock();
-+}
-+
- void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
- {
- struct ieee80211_sub_if_data *sdata;
-@@ -308,6 +401,9 @@ static void __ieee80211_wake_queue(struc
- rcu_read_unlock();
- } else
- tasklet_schedule(&local->tx_pending_tasklet);
-+
-+ if (local->ops->wake_tx_queue)
-+ tasklet_schedule(&local->wake_txqs_tasklet);
- }
-
- void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
-@@ -351,9 +447,6 @@ static void __ieee80211_stop_queue(struc
- if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
- return;
-
-- if (local->ops->wake_tx_queue)
-- return;
--
- if (local->hw.queues < IEEE80211_NUM_ACS)
- n_acs = 1;
-
-@@ -366,8 +459,15 @@ static void __ieee80211_stop_queue(struc
-
- for (ac = 0; ac < n_acs; ac++) {
- if (sdata->vif.hw_queue[ac] == queue ||
-- sdata->vif.cab_queue == queue)
-- netif_stop_subqueue(sdata->dev, ac);
-+ sdata->vif.cab_queue == queue) {
-+ if (!local->ops->wake_tx_queue) {
-+ netif_stop_subqueue(sdata->dev, ac);
-+ continue;
-+ }
-+ spin_lock(&local->fq.lock);
-+ sdata->vif.txqs_stopped[ac] = true;
-+ spin_unlock(&local->fq.lock);
-+ }
- }
- }
- rcu_read_unlock();
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 1 Mar 2019 14:42:56 +0100
+Subject: [PATCH] mac80211: do not call driver wake_tx_queue op during reconfig
+
+There are several scenarios in which mac80211 can call drv_wake_tx_queue
+after ieee80211_restart_hw has been called and has not yet completed.
+Driver private structs are considered uninitialized until mac80211 has
+uploaded the vifs, stations and keys again, so using private tx queue
+data during that time is not safe.
+
+The driver can also not rely on drv_reconfig_complete to figure out when
+it is safe to accept drv_wake_tx_queue calls again, because it is only
+called after all tx queues are woken again.
+
+To fix this, bail out early in drv_wake_tx_queue if local->in_reconfig
+is set.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/driver-ops.h
++++ b/net/mac80211/driver-ops.h
+@@ -1166,6 +1166,9 @@ static inline void drv_wake_tx_queue(str
+ {
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif);
+
++ if (local->in_reconfig)
++ return;
++
+ if (!check_sdata_in_driver(sdata))
+ return;
+
+++ /dev/null
-From: Chaitanya T K <chaitanya.mgit@gmail.com>
-Date: Mon, 27 Jun 2016 15:23:26 +0530
-Subject: [PATCH] mac80211: minstrel: Enable STBC and LDPC for VHT Rates
-
-If peer support reception of STBC and LDPC, enable them for better
-performance.
-
-Signed-off-by: Chaitanya TK <chaitanya.mgit@gmail.com>
----
-
---- a/include/linux/ieee80211.h
-+++ b/include/linux/ieee80211.h
-@@ -1659,6 +1659,7 @@ struct ieee80211_mu_edca_param_set {
- #define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300
- #define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400
- #define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700
-+#define IEEE80211_VHT_CAP_RXSTBC_SHIFT 8
- #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800
- #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000
- #define IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT 13
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -1130,7 +1130,7 @@ minstrel_ht_update_caps(void *priv, stru
- struct minstrel_ht_sta_priv *msp = priv_sta;
- struct minstrel_ht_sta *mi = &msp->ht;
- struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
-- u16 sta_cap = sta->ht_cap.cap;
-+ u16 ht_cap = sta->ht_cap.cap;
- struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
- struct sta_info *sinfo = container_of(sta, struct sta_info, sta);
- int use_vht;
-@@ -1138,6 +1138,7 @@ minstrel_ht_update_caps(void *priv, stru
- int ack_dur;
- int stbc;
- int i;
-+ bool ldpc = false;
-
- /* fall back to the old minstrel for legacy stations */
- if (!sta->ht_cap.ht_supported)
-@@ -1175,16 +1176,24 @@ minstrel_ht_update_caps(void *priv, stru
- }
- mi->sample_tries = 4;
-
-- /* TODO tx_flags for vht - ATM the RC API is not fine-grained enough */
- if (!use_vht) {
-- stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >>
-+ stbc = (ht_cap & IEEE80211_HT_CAP_RX_STBC) >>
- IEEE80211_HT_CAP_RX_STBC_SHIFT;
-- mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
-
-- if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
-- mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
-+ if (ht_cap & IEEE80211_HT_CAP_LDPC_CODING)
-+ ldpc = true;
-+ } else {
-+ stbc = (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK) >>
-+ IEEE80211_VHT_CAP_RXSTBC_SHIFT;
-+
-+ if (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)
-+ ldpc = true;
- }
-
-+ mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
-+ if (ldpc)
-+ mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
-+
- for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
- u32 gflags = minstrel_mcs_groups[i].flags;
- int bw, nss;
-@@ -1197,10 +1206,10 @@ minstrel_ht_update_caps(void *priv, stru
-
- if (gflags & IEEE80211_TX_RC_SHORT_GI) {
- if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
-- if (!(sta_cap & IEEE80211_HT_CAP_SGI_40))
-+ if (!(ht_cap & IEEE80211_HT_CAP_SGI_40))
- continue;
- } else {
-- if (!(sta_cap & IEEE80211_HT_CAP_SGI_20))
-+ if (!(ht_cap & IEEE80211_HT_CAP_SGI_20))
- continue;
- }
- }
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 10 Feb 2018 12:41:51 +0100
-Subject: [PATCH] mac80211: minstrel: remove unnecessary debugfs cleanup
- code
-
-debugfs entries are cleaned up by debugfs_remove_recursive already.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel.c
-+++ b/net/mac80211/rc80211_minstrel.c
-@@ -689,8 +689,8 @@ minstrel_alloc(struct ieee80211_hw *hw,
-
- #ifdef CPTCFG_MAC80211_DEBUGFS
- mp->fixed_rate_idx = (u32) -1;
-- mp->dbg_fixed_rate = debugfs_create_u32("fixed_rate_idx",
-- 0666, debugfsdir, &mp->fixed_rate_idx);
-+ debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir,
-+ &mp->fixed_rate_idx);
- #endif
-
- minstrel_init_cck_rates(mp);
-@@ -701,9 +701,6 @@ minstrel_alloc(struct ieee80211_hw *hw,
- static void
- minstrel_free(void *priv)
- {
--#ifdef CPTCFG_MAC80211_DEBUGFS
-- debugfs_remove(((struct minstrel_priv *)priv)->dbg_fixed_rate);
--#endif
- kfree(priv);
- }
-
-@@ -735,7 +732,6 @@ const struct rate_control_ops mac80211_m
- .free_sta = minstrel_free_sta,
- #ifdef CPTCFG_MAC80211_DEBUGFS
- .add_sta_debugfs = minstrel_add_sta_debugfs,
-- .remove_sta_debugfs = minstrel_remove_sta_debugfs,
- #endif
- .get_expected_throughput = minstrel_get_expected_throughput,
- };
---- a/net/mac80211/rc80211_minstrel.h
-+++ b/net/mac80211/rc80211_minstrel.h
-@@ -109,11 +109,6 @@ struct minstrel_sta_info {
-
- /* sampling table */
- u8 *sample_table;
--
--#ifdef CPTCFG_MAC80211_DEBUGFS
-- struct dentry *dbg_stats;
-- struct dentry *dbg_stats_csv;
--#endif
- };
-
- struct minstrel_priv {
-@@ -137,7 +132,6 @@ struct minstrel_priv {
- * - setting will be applied on next update
- */
- u32 fixed_rate_idx;
-- struct dentry *dbg_fixed_rate;
- #endif
- };
-
-@@ -156,7 +150,6 @@ minstrel_get_ewmsd10(struct minstrel_rat
-
- extern const struct rate_control_ops mac80211_minstrel;
- void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
--void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);
-
- /* Recalculate success probabilities and counters for a given rate using EWMA */
- void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs);
---- a/net/mac80211/rc80211_minstrel_debugfs.c
-+++ b/net/mac80211/rc80211_minstrel_debugfs.c
-@@ -214,19 +214,7 @@ minstrel_add_sta_debugfs(void *priv, voi
- {
- struct minstrel_sta_info *mi = priv_sta;
-
-- mi->dbg_stats = debugfs_create_file("rc_stats", 0444, dir, mi,
-- &minstrel_stat_fops);
--
-- mi->dbg_stats_csv = debugfs_create_file("rc_stats_csv", 0444, dir, mi,
-- &minstrel_stat_csv_fops);
--}
--
--void
--minstrel_remove_sta_debugfs(void *priv, void *priv_sta)
--{
-- struct minstrel_sta_info *mi = priv_sta;
--
-- debugfs_remove(mi->dbg_stats);
--
-- debugfs_remove(mi->dbg_stats_csv);
-+ debugfs_create_file("rc_stats", S_IRUGO, dir, mi, &minstrel_stat_fops);
-+ debugfs_create_file("rc_stats_csv", S_IRUGO, dir, mi,
-+ &minstrel_stat_csv_fops);
- }
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -1393,7 +1393,6 @@ static const struct rate_control_ops mac
- .free = minstrel_ht_free,
- #ifdef CPTCFG_MAC80211_DEBUGFS
- .add_sta_debugfs = minstrel_ht_add_sta_debugfs,
-- .remove_sta_debugfs = minstrel_ht_remove_sta_debugfs,
- #endif
- .get_expected_throughput = minstrel_ht_get_expected_throughput,
- };
---- a/net/mac80211/rc80211_minstrel_ht.h
-+++ b/net/mac80211/rc80211_minstrel_ht.h
-@@ -110,17 +110,12 @@ struct minstrel_ht_sta_priv {
- struct minstrel_ht_sta ht;
- struct minstrel_sta_info legacy;
- };
--#ifdef CPTCFG_MAC80211_DEBUGFS
-- struct dentry *dbg_stats;
-- struct dentry *dbg_stats_csv;
--#endif
- void *ratelist;
- void *sample_table;
- bool is_ht;
- };
-
- void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
--void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta);
- int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate,
- int prob_ewma);
-
---- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
-+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
-@@ -303,17 +303,8 @@ minstrel_ht_add_sta_debugfs(void *priv,
- {
- struct minstrel_ht_sta_priv *msp = priv_sta;
-
-- msp->dbg_stats = debugfs_create_file("rc_stats", 0444, dir, msp,
-- &minstrel_ht_stat_fops);
-- msp->dbg_stats_csv = debugfs_create_file("rc_stats_csv", 0444, dir, msp,
-- &minstrel_ht_stat_csv_fops);
--}
--
--void
--minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta)
--{
-- struct minstrel_ht_sta_priv *msp = priv_sta;
--
-- debugfs_remove(msp->dbg_stats);
-- debugfs_remove(msp->dbg_stats_csv);
-+ debugfs_create_file("rc_stats", S_IRUGO, dir, msp,
-+ &minstrel_ht_stat_fops);
-+ debugfs_create_file("rc_stats_csv", S_IRUGO, dir, msp,
-+ &minstrel_ht_stat_csv_fops);
- }
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 10 Feb 2018 12:43:30 +0100
-Subject: [PATCH] mac80211: minstrel: merge with minstrel_ht, always enable
- VHT support
-
-Legacy-only devices are not very common and the overhead of the extra
-code for HT and VHT rates is not big enough to justify all those extra
-lines of code to make it optional.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/Kconfig
-+++ b/net/mac80211/Kconfig
-@@ -25,20 +25,6 @@ config MAC80211_RC_MINSTREL
- ---help---
- This option enables the 'minstrel' TX rate control algorithm
-
--config MAC80211_RC_MINSTREL_HT
-- bool "Minstrel 802.11n support" if EXPERT
-- depends on MAC80211_RC_MINSTREL
-- default y
-- ---help---
-- This option enables the 'minstrel_ht' TX rate control algorithm
--
--config MAC80211_RC_MINSTREL_VHT
-- bool "Minstrel 802.11ac support" if EXPERT
-- depends on MAC80211_RC_MINSTREL_HT
-- default n
-- ---help---
-- This option enables VHT in the 'minstrel_ht' TX rate control algorithm
--
- choice
- prompt "Default rate control algorithm"
- depends on MAC80211_HAS_RC
-@@ -60,8 +46,7 @@ endchoice
-
- config MAC80211_RC_DEFAULT
- string
-- default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT
-- default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL
-+ default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL
- default ""
-
- endif
---- a/net/mac80211/Makefile
-+++ b/net/mac80211/Makefile
-@@ -52,13 +52,14 @@ mac80211-$(CONFIG_PM) += pm.o
-
- CFLAGS_trace.o := -I$(src)
-
--rc80211_minstrel-y := rc80211_minstrel.o
--rc80211_minstrel-$(CPTCFG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o
-+rc80211_minstrel-y := \
-+ rc80211_minstrel.o \
-+ rc80211_minstrel_ht.o
-
--rc80211_minstrel_ht-y := rc80211_minstrel_ht.o
--rc80211_minstrel_ht-$(CPTCFG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o
-+rc80211_minstrel-$(CPTCFG_MAC80211_DEBUGFS) += \
-+ rc80211_minstrel_debugfs.o \
-+ rc80211_minstrel_ht_debugfs.o
-
- mac80211-$(CPTCFG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)
--mac80211-$(CPTCFG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y)
-
- ccflags-y += -DDEBUG
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -1308,18 +1308,12 @@ static int __init ieee80211_init(void)
- if (ret)
- return ret;
-
-- ret = rc80211_minstrel_ht_init();
-- if (ret)
-- goto err_minstrel;
--
- ret = ieee80211_iface_init();
- if (ret)
- goto err_netdev;
-
- return 0;
- err_netdev:
-- rc80211_minstrel_ht_exit();
-- err_minstrel:
- rc80211_minstrel_exit();
-
- return ret;
-@@ -1327,7 +1321,6 @@ static int __init ieee80211_init(void)
-
- static void __exit ieee80211_exit(void)
- {
-- rc80211_minstrel_ht_exit();
- rc80211_minstrel_exit();
-
- ieee80211s_stop();
---- a/net/mac80211/rate.h
-+++ b/net/mac80211/rate.h
-@@ -95,18 +95,5 @@ static inline void rc80211_minstrel_exit
- }
- #endif
-
--#ifdef CPTCFG_MAC80211_RC_MINSTREL_HT
--int rc80211_minstrel_ht_init(void);
--void rc80211_minstrel_ht_exit(void);
--#else
--static inline int rc80211_minstrel_ht_init(void)
--{
-- return 0;
--}
--static inline void rc80211_minstrel_ht_exit(void)
--{
--}
--#endif
--
-
- #endif /* IEEE80211_RATE_H */
---- a/net/mac80211/rc80211_minstrel.c
-+++ b/net/mac80211/rc80211_minstrel.c
-@@ -572,138 +572,6 @@ minstrel_rate_init(void *priv, struct ie
- minstrel_update_rates(mp, mi);
- }
-
--static void *
--minstrel_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
--{
-- struct ieee80211_supported_band *sband;
-- struct minstrel_sta_info *mi;
-- struct minstrel_priv *mp = priv;
-- struct ieee80211_hw *hw = mp->hw;
-- int max_rates = 0;
-- int i;
--
-- mi = kzalloc(sizeof(struct minstrel_sta_info), gfp);
-- if (!mi)
-- return NULL;
--
-- for (i = 0; i < NUM_NL80211_BANDS; i++) {
-- sband = hw->wiphy->bands[i];
-- if (sband && sband->n_bitrates > max_rates)
-- max_rates = sband->n_bitrates;
-- }
--
-- mi->r = kcalloc(max_rates, sizeof(struct minstrel_rate), gfp);
-- if (!mi->r)
-- goto error;
--
-- mi->sample_table = kmalloc_array(max_rates, SAMPLE_COLUMNS, gfp);
-- if (!mi->sample_table)
-- goto error1;
--
-- mi->last_stats_update = jiffies;
-- return mi;
--
--error1:
-- kfree(mi->r);
--error:
-- kfree(mi);
-- return NULL;
--}
--
--static void
--minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
--{
-- struct minstrel_sta_info *mi = priv_sta;
--
-- kfree(mi->sample_table);
-- kfree(mi->r);
-- kfree(mi);
--}
--
--static void
--minstrel_init_cck_rates(struct minstrel_priv *mp)
--{
-- static const int bitrates[4] = { 10, 20, 55, 110 };
-- struct ieee80211_supported_band *sband;
-- u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef);
-- int i, j;
--
-- sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ];
-- if (!sband)
-- return;
--
-- for (i = 0, j = 0; i < sband->n_bitrates; i++) {
-- struct ieee80211_rate *rate = &sband->bitrates[i];
--
-- if (rate->flags & IEEE80211_RATE_ERP_G)
-- continue;
--
-- if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
-- continue;
--
-- for (j = 0; j < ARRAY_SIZE(bitrates); j++) {
-- if (rate->bitrate != bitrates[j])
-- continue;
--
-- mp->cck_rates[j] = i;
-- break;
-- }
-- }
--}
--
--static void *
--minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
--{
-- struct minstrel_priv *mp;
--
-- mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC);
-- if (!mp)
-- return NULL;
--
-- /* contention window settings
-- * Just an approximation. Using the per-queue values would complicate
-- * the calculations and is probably unnecessary */
-- mp->cw_min = 15;
-- mp->cw_max = 1023;
--
-- /* number of packets (in %) to use for sampling other rates
-- * sample less often for non-mrr packets, because the overhead
-- * is much higher than with mrr */
-- mp->lookaround_rate = 5;
-- mp->lookaround_rate_mrr = 10;
--
-- /* maximum time that the hw is allowed to stay in one MRR segment */
-- mp->segment_size = 6000;
--
-- if (hw->max_rate_tries > 0)
-- mp->max_retry = hw->max_rate_tries;
-- else
-- /* safe default, does not necessarily have to match hw properties */
-- mp->max_retry = 7;
--
-- if (hw->max_rates >= 4)
-- mp->has_mrr = true;
--
-- mp->hw = hw;
-- mp->update_interval = 100;
--
--#ifdef CPTCFG_MAC80211_DEBUGFS
-- mp->fixed_rate_idx = (u32) -1;
-- debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir,
-- &mp->fixed_rate_idx);
--#endif
--
-- minstrel_init_cck_rates(mp);
--
-- return mp;
--}
--
--static void
--minstrel_free(void *priv)
--{
-- kfree(priv);
--}
--
- static u32 minstrel_get_expected_throughput(void *priv_sta)
- {
- struct minstrel_sta_info *mi = priv_sta;
-@@ -722,28 +590,8 @@ static u32 minstrel_get_expected_through
- }
-
- const struct rate_control_ops mac80211_minstrel = {
-- .name = "minstrel",
- .tx_status_ext = minstrel_tx_status,
- .get_rate = minstrel_get_rate,
- .rate_init = minstrel_rate_init,
-- .alloc = minstrel_alloc,
-- .free = minstrel_free,
-- .alloc_sta = minstrel_alloc_sta,
-- .free_sta = minstrel_free_sta,
--#ifdef CPTCFG_MAC80211_DEBUGFS
-- .add_sta_debugfs = minstrel_add_sta_debugfs,
--#endif
- .get_expected_throughput = minstrel_get_expected_throughput,
- };
--
--int __init
--rc80211_minstrel_init(void)
--{
-- return ieee80211_rate_control_register(&mac80211_minstrel);
--}
--
--void
--rc80211_minstrel_exit(void)
--{
-- ieee80211_rate_control_unregister(&mac80211_minstrel);
--}
---- a/net/mac80211/rc80211_minstrel.h
-+++ b/net/mac80211/rc80211_minstrel.h
-@@ -158,7 +158,5 @@ int minstrel_get_tp_avg(struct minstrel_
- /* debugfs */
- int minstrel_stats_open(struct inode *inode, struct file *file);
- int minstrel_stats_csv_open(struct inode *inode, struct file *file);
--ssize_t minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos);
--int minstrel_stats_release(struct inode *inode, struct file *file);
-
- #endif
---- a/net/mac80211/rc80211_minstrel_debugfs.c
-+++ b/net/mac80211/rc80211_minstrel_debugfs.c
-@@ -54,22 +54,6 @@
- #include <net/mac80211.h>
- #include "rc80211_minstrel.h"
-
--ssize_t
--minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos)
--{
-- struct minstrel_debugfs_info *ms;
--
-- ms = file->private_data;
-- return simple_read_from_buffer(buf, len, ppos, ms->buf, ms->len);
--}
--
--int
--minstrel_stats_release(struct inode *inode, struct file *file)
--{
-- kfree(file->private_data);
-- return 0;
--}
--
- int
- minstrel_stats_open(struct inode *inode, struct file *file)
- {
-@@ -135,14 +119,6 @@ minstrel_stats_open(struct inode *inode,
- return 0;
- }
-
--static const struct file_operations minstrel_stat_fops = {
-- .owner = THIS_MODULE,
-- .open = minstrel_stats_open,
-- .read = minstrel_stats_read,
-- .release = minstrel_stats_release,
-- .llseek = default_llseek,
--};
--
- int
- minstrel_stats_csv_open(struct inode *inode, struct file *file)
- {
-@@ -200,21 +176,3 @@ minstrel_stats_csv_open(struct inode *in
-
- return 0;
- }
--
--static const struct file_operations minstrel_stat_csv_fops = {
-- .owner = THIS_MODULE,
-- .open = minstrel_stats_csv_open,
-- .read = minstrel_stats_read,
-- .release = minstrel_stats_release,
-- .llseek = default_llseek,
--};
--
--void
--minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)
--{
-- struct minstrel_sta_info *mi = priv_sta;
--
-- debugfs_create_file("rc_stats", S_IRUGO, dir, mi, &minstrel_stat_fops);
-- debugfs_create_file("rc_stats_csv", S_IRUGO, dir, mi,
-- &minstrel_stat_csv_fops);
--}
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -137,12 +137,10 @@
- } \
- }
-
--#ifdef CPTCFG_MAC80211_RC_MINSTREL_VHT
- static bool minstrel_vht_only = true;
- module_param(minstrel_vht_only, bool, 0644);
- MODULE_PARM_DESC(minstrel_vht_only,
- "Use only VHT rates when VHT is supported by sta.");
--#endif
-
- /*
- * To enable sufficiently targeted rate sampling, MCS rates are divided into
-@@ -171,7 +169,6 @@ const struct mcs_group minstrel_mcs_grou
-
- CCK_GROUP,
-
--#ifdef CPTCFG_MAC80211_RC_MINSTREL_VHT
- VHT_GROUP(1, 0, BW_20),
- VHT_GROUP(2, 0, BW_20),
- VHT_GROUP(3, 0, BW_20),
-@@ -195,7 +192,6 @@ const struct mcs_group minstrel_mcs_grou
- VHT_GROUP(1, 1, BW_80),
- VHT_GROUP(2, 1, BW_80),
- VHT_GROUP(3, 1, BW_80),
--#endif
- };
-
- static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;
-@@ -1146,12 +1142,10 @@ minstrel_ht_update_caps(void *priv, stru
-
- BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB);
-
--#ifdef CPTCFG_MAC80211_RC_MINSTREL_VHT
- if (vht_cap->vht_supported)
- use_vht = vht_cap->vht_mcs.tx_mcs_map != cpu_to_le16(~0);
- else
--#endif
-- use_vht = 0;
-+ use_vht = 0;
-
- msp->is_ht = true;
- memset(mi, 0, sizeof(*mi));
-@@ -1226,10 +1220,9 @@ minstrel_ht_update_caps(void *priv, stru
-
- /* HT rate */
- if (gflags & IEEE80211_TX_RC_MCS) {
--#ifdef CPTCFG_MAC80211_RC_MINSTREL_VHT
- if (use_vht && minstrel_vht_only)
- continue;
--#endif
-+
- mi->supported[i] = mcs->rx_mask[nss - 1];
- if (mi->supported[i])
- n_supported++;
-@@ -1349,16 +1342,88 @@ minstrel_ht_free_sta(void *priv, struct
- kfree(msp);
- }
-
-+static void
-+minstrel_ht_init_cck_rates(struct minstrel_priv *mp)
-+{
-+ static const int bitrates[4] = { 10, 20, 55, 110 };
-+ struct ieee80211_supported_band *sband;
-+ u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef);
-+ int i, j;
-+
-+ sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ];
-+ if (!sband)
-+ return;
-+
-+ for (i = 0, j = 0; i < sband->n_bitrates; i++) {
-+ struct ieee80211_rate *rate = &sband->bitrates[i];
-+
-+ if (rate->flags & IEEE80211_RATE_ERP_G)
-+ continue;
-+
-+ if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
-+ continue;
-+
-+ for (j = 0; j < ARRAY_SIZE(bitrates); j++) {
-+ if (rate->bitrate != bitrates[j])
-+ continue;
-+
-+ mp->cck_rates[j] = i;
-+ break;
-+ }
-+ }
-+}
-+
- static void *
- minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
- {
-- return mac80211_minstrel.alloc(hw, debugfsdir);
-+ struct minstrel_priv *mp;
-+
-+ mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC);
-+ if (!mp)
-+ return NULL;
-+
-+ /* contention window settings
-+ * Just an approximation. Using the per-queue values would complicate
-+ * the calculations and is probably unnecessary */
-+ mp->cw_min = 15;
-+ mp->cw_max = 1023;
-+
-+ /* number of packets (in %) to use for sampling other rates
-+ * sample less often for non-mrr packets, because the overhead
-+ * is much higher than with mrr */
-+ mp->lookaround_rate = 5;
-+ mp->lookaround_rate_mrr = 10;
-+
-+ /* maximum time that the hw is allowed to stay in one MRR segment */
-+ mp->segment_size = 6000;
-+
-+ if (hw->max_rate_tries > 0)
-+ mp->max_retry = hw->max_rate_tries;
-+ else
-+ /* safe default, does not necessarily have to match hw properties */
-+ mp->max_retry = 7;
-+
-+ if (hw->max_rates >= 4)
-+ mp->has_mrr = true;
-+
-+ mp->hw = hw;
-+ mp->update_interval = 100;
-+
-+#ifdef CPTCFG_MAC80211_DEBUGFS
-+ mp->fixed_rate_idx = (u32) -1;
-+ debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir,
-+ &mp->fixed_rate_idx);
-+#endif
-+
-+ minstrel_ht_init_cck_rates(mp);
-+
-+ return mp;
- }
-
- static void
- minstrel_ht_free(void *priv)
- {
-- mac80211_minstrel.free(priv);
-+ kfree(priv);
- }
-
- static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
-@@ -1417,14 +1482,14 @@ static void __init init_sample_table(voi
- }
-
- int __init
--rc80211_minstrel_ht_init(void)
-+rc80211_minstrel_init(void)
- {
- init_sample_table();
- return ieee80211_rate_control_register(&mac80211_minstrel_ht);
- }
-
- void
--rc80211_minstrel_ht_exit(void)
-+rc80211_minstrel_exit(void)
- {
- ieee80211_rate_control_unregister(&mac80211_minstrel_ht);
- }
---- a/net/mac80211/rc80211_minstrel_ht.h
-+++ b/net/mac80211/rc80211_minstrel_ht.h
-@@ -15,11 +15,7 @@
- */
- #define MINSTREL_MAX_STREAMS 3
- #define MINSTREL_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */
--#ifdef CPTCFG_MAC80211_RC_MINSTREL_VHT
- #define MINSTREL_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */
--#else
--#define MINSTREL_VHT_STREAM_GROUPS 0
--#endif
-
- #define MINSTREL_HT_GROUPS_NB (MINSTREL_MAX_STREAMS * \
- MINSTREL_HT_STREAM_GROUPS)
-@@ -34,11 +30,7 @@
- #define MINSTREL_CCK_GROUP (MINSTREL_HT_GROUP_0 + MINSTREL_HT_GROUPS_NB)
- #define MINSTREL_VHT_GROUP_0 (MINSTREL_CCK_GROUP + 1)
-
--#ifdef CPTCFG_MAC80211_RC_MINSTREL_VHT
- #define MCS_GROUP_RATES 10
--#else
--#define MCS_GROUP_RATES 8
--#endif
-
- struct mcs_group {
- u32 flags;
---- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
-+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
-@@ -15,6 +15,22 @@
- #include "rc80211_minstrel.h"
- #include "rc80211_minstrel_ht.h"
-
-+static ssize_t
-+minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos)
-+{
-+ struct minstrel_debugfs_info *ms;
-+
-+ ms = file->private_data;
-+ return simple_read_from_buffer(buf, len, ppos, ms->buf, ms->len);
-+}
-+
-+static int
-+minstrel_stats_release(struct inode *inode, struct file *file)
-+{
-+ kfree(file->private_data);
-+ return 0;
-+}
-+
- static char *
- minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
- {
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 10 Feb 2018 12:45:47 +0100
-Subject: [PATCH] mac80211: minstrel: reduce minstrel_mcs_groups size
-
-By storing a shift value for all duration values of a group, we can
-reduce precision by a neglegible amount to make it fit into a u16 value.
-This improves cache footprint and reduces size:
-
-Before:
- text data bss dec hex filename
- 10024 116 0 10140 279c rc80211_minstrel_ht.o
-
-After:
- text data bss dec hex filename
- 9368 116 0 9484 250c rc80211_minstrel_ht.o
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -52,22 +52,23 @@
- _streams - 1
-
- /* MCS rate information for an MCS group */
--#define MCS_GROUP(_streams, _sgi, _ht40) \
-+#define MCS_GROUP(_streams, _sgi, _ht40, _s) \
- [GROUP_IDX(_streams, _sgi, _ht40)] = { \
- .streams = _streams, \
-+ .shift = _s, \
- .flags = \
- IEEE80211_TX_RC_MCS | \
- (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \
- (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \
- .duration = { \
-- MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26), \
-- MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52), \
-- MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78), \
-- MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104), \
-- MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156), \
-- MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208), \
-- MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234), \
-- MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) \
-+ MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26) >> _s, \
-+ MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52) >> _s, \
-+ MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78) >> _s, \
-+ MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104) >> _s, \
-+ MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156) >> _s, \
-+ MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208) >> _s, \
-+ MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234) >> _s, \
-+ MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) >> _s \
- } \
- }
-
-@@ -80,9 +81,10 @@
- #define BW2VBPS(_bw, r3, r2, r1) \
- (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
-
--#define VHT_GROUP(_streams, _sgi, _bw) \
-+#define VHT_GROUP(_streams, _sgi, _bw, _s) \
- [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \
- .streams = _streams, \
-+ .shift = _s, \
- .flags = \
- IEEE80211_TX_RC_VHT_MCS | \
- (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \
-@@ -90,25 +92,25 @@
- _bw == BW_40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \
- .duration = { \
- MCS_DURATION(_streams, _sgi, \
-- BW2VBPS(_bw, 117, 54, 26)), \
-+ BW2VBPS(_bw, 117, 54, 26)) >> _s, \
- MCS_DURATION(_streams, _sgi, \
-- BW2VBPS(_bw, 234, 108, 52)), \
-+ BW2VBPS(_bw, 234, 108, 52)) >> _s, \
- MCS_DURATION(_streams, _sgi, \
-- BW2VBPS(_bw, 351, 162, 78)), \
-+ BW2VBPS(_bw, 351, 162, 78)) >> _s, \
- MCS_DURATION(_streams, _sgi, \
-- BW2VBPS(_bw, 468, 216, 104)), \
-+ BW2VBPS(_bw, 468, 216, 104)) >> _s, \
- MCS_DURATION(_streams, _sgi, \
-- BW2VBPS(_bw, 702, 324, 156)), \
-+ BW2VBPS(_bw, 702, 324, 156)) >> _s, \
- MCS_DURATION(_streams, _sgi, \
-- BW2VBPS(_bw, 936, 432, 208)), \
-+ BW2VBPS(_bw, 936, 432, 208)) >> _s, \
- MCS_DURATION(_streams, _sgi, \
-- BW2VBPS(_bw, 1053, 486, 234)), \
-+ BW2VBPS(_bw, 1053, 486, 234)) >> _s, \
- MCS_DURATION(_streams, _sgi, \
-- BW2VBPS(_bw, 1170, 540, 260)), \
-+ BW2VBPS(_bw, 1170, 540, 260)) >> _s, \
- MCS_DURATION(_streams, _sgi, \
-- BW2VBPS(_bw, 1404, 648, 312)), \
-+ BW2VBPS(_bw, 1404, 648, 312)) >> _s, \
- MCS_DURATION(_streams, _sgi, \
-- BW2VBPS(_bw, 1560, 720, 346)) \
-+ BW2VBPS(_bw, 1560, 720, 346)) >> _s \
- } \
- }
-
-@@ -121,19 +123,20 @@
- (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \
- CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE))
-
--#define CCK_DURATION_LIST(_short) \
-- CCK_ACK_DURATION(10, _short), \
-- CCK_ACK_DURATION(20, _short), \
-- CCK_ACK_DURATION(55, _short), \
-- CCK_ACK_DURATION(110, _short)
-+#define CCK_DURATION_LIST(_short, _s) \
-+ CCK_ACK_DURATION(10, _short) >> _s, \
-+ CCK_ACK_DURATION(20, _short) >> _s, \
-+ CCK_ACK_DURATION(55, _short) >> _s, \
-+ CCK_ACK_DURATION(110, _short) >> _s
-
--#define CCK_GROUP \
-+#define CCK_GROUP(_s) \
- [MINSTREL_CCK_GROUP] = { \
- .streams = 0, \
- .flags = 0, \
-+ .shift = _s, \
- .duration = { \
-- CCK_DURATION_LIST(false), \
-- CCK_DURATION_LIST(true) \
-+ CCK_DURATION_LIST(false, _s), \
-+ CCK_DURATION_LIST(true, _s) \
- } \
- }
-
-@@ -151,47 +154,47 @@ MODULE_PARM_DESC(minstrel_vht_only,
- * BW -> SGI -> #streams
- */
- const struct mcs_group minstrel_mcs_groups[] = {
-- MCS_GROUP(1, 0, BW_20),
-- MCS_GROUP(2, 0, BW_20),
-- MCS_GROUP(3, 0, BW_20),
--
-- MCS_GROUP(1, 1, BW_20),
-- MCS_GROUP(2, 1, BW_20),
-- MCS_GROUP(3, 1, BW_20),
--
-- MCS_GROUP(1, 0, BW_40),
-- MCS_GROUP(2, 0, BW_40),
-- MCS_GROUP(3, 0, BW_40),
--
-- MCS_GROUP(1, 1, BW_40),
-- MCS_GROUP(2, 1, BW_40),
-- MCS_GROUP(3, 1, BW_40),
--
-- CCK_GROUP,
--
-- VHT_GROUP(1, 0, BW_20),
-- VHT_GROUP(2, 0, BW_20),
-- VHT_GROUP(3, 0, BW_20),
--
-- VHT_GROUP(1, 1, BW_20),
-- VHT_GROUP(2, 1, BW_20),
-- VHT_GROUP(3, 1, BW_20),
--
-- VHT_GROUP(1, 0, BW_40),
-- VHT_GROUP(2, 0, BW_40),
-- VHT_GROUP(3, 0, BW_40),
--
-- VHT_GROUP(1, 1, BW_40),
-- VHT_GROUP(2, 1, BW_40),
-- VHT_GROUP(3, 1, BW_40),
--
-- VHT_GROUP(1, 0, BW_80),
-- VHT_GROUP(2, 0, BW_80),
-- VHT_GROUP(3, 0, BW_80),
--
-- VHT_GROUP(1, 1, BW_80),
-- VHT_GROUP(2, 1, BW_80),
-- VHT_GROUP(3, 1, BW_80),
-+ MCS_GROUP(1, 0, BW_20, 5),
-+ MCS_GROUP(2, 0, BW_20, 4),
-+ MCS_GROUP(3, 0, BW_20, 4),
-+
-+ MCS_GROUP(1, 1, BW_20, 5),
-+ MCS_GROUP(2, 1, BW_20, 4),
-+ MCS_GROUP(3, 1, BW_20, 4),
-+
-+ MCS_GROUP(1, 0, BW_40, 4),
-+ MCS_GROUP(2, 0, BW_40, 4),
-+ MCS_GROUP(3, 0, BW_40, 4),
-+
-+ MCS_GROUP(1, 1, BW_40, 4),
-+ MCS_GROUP(2, 1, BW_40, 4),
-+ MCS_GROUP(3, 1, BW_40, 4),
-+
-+ CCK_GROUP(8),
-+
-+ VHT_GROUP(1, 0, BW_20, 5),
-+ VHT_GROUP(2, 0, BW_20, 4),
-+ VHT_GROUP(3, 0, BW_20, 4),
-+
-+ VHT_GROUP(1, 1, BW_20, 5),
-+ VHT_GROUP(2, 1, BW_20, 4),
-+ VHT_GROUP(3, 1, BW_20, 4),
-+
-+ VHT_GROUP(1, 0, BW_40, 4),
-+ VHT_GROUP(2, 0, BW_40, 4),
-+ VHT_GROUP(3, 0, BW_40, 4),
-+
-+ VHT_GROUP(1, 1, BW_40, 4),
-+ VHT_GROUP(2, 1, BW_40, 4),
-+ VHT_GROUP(3, 1, BW_40, 4),
-+
-+ VHT_GROUP(1, 0, BW_80, 4),
-+ VHT_GROUP(2, 0, BW_80, 4),
-+ VHT_GROUP(3, 0, BW_80, 4),
-+
-+ VHT_GROUP(1, 1, BW_80, 4),
-+ VHT_GROUP(2, 1, BW_80, 4),
-+ VHT_GROUP(3, 1, BW_80, 4),
- };
-
- static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;
-@@ -307,7 +310,8 @@ minstrel_ht_get_tp_avg(struct minstrel_h
- if (group != MINSTREL_CCK_GROUP)
- nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
-
-- nsecs += minstrel_mcs_groups[group].duration[rate];
-+ nsecs += minstrel_mcs_groups[group].duration[rate] <<
-+ minstrel_mcs_groups[group].shift;
-
- /*
- * For the throughput calculation, limit the probability value to 90% to
-@@ -755,12 +759,19 @@ minstrel_ht_tx_status(void *priv, struct
- minstrel_ht_update_rates(mp, mi);
- }
-
-+static inline int
-+minstrel_get_duration(int index)
-+{
-+ const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
-+ unsigned int duration = group->duration[index % MCS_GROUP_RATES];
-+ return duration << group->shift;
-+}
-+
- static void
- minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
- int index)
- {
- struct minstrel_rate_stats *mrs;
-- const struct mcs_group *group;
- unsigned int tx_time, tx_time_rtscts, tx_time_data;
- unsigned int cw = mp->cw_min;
- unsigned int ctime = 0;
-@@ -779,8 +790,7 @@ minstrel_calc_retransmit(struct minstrel
- mrs->retry_count_rtscts = 2;
- mrs->retry_updated = true;
-
-- group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
-- tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000;
-+ tx_time_data = minstrel_get_duration(index) * ampdu_len / 1000;
-
- /* Contention time for first 2 tries */
- ctime = (t_slot * cw) >> 1;
-@@ -874,20 +884,24 @@ minstrel_ht_get_max_amsdu_len(struct min
- int group = mi->max_prob_rate / MCS_GROUP_RATES;
- const struct mcs_group *g = &minstrel_mcs_groups[group];
- int rate = mi->max_prob_rate % MCS_GROUP_RATES;
-+ unsigned int duration;
-
- /* Disable A-MSDU if max_prob_rate is bad */
- if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100))
- return 1;
-
-+ duration = g->duration[rate];
-+ duration <<= g->shift;
-+
- /* If the rate is slower than single-stream MCS1, make A-MSDU limit small */
-- if (g->duration[rate] > MCS_DURATION(1, 0, 52))
-+ if (duration > MCS_DURATION(1, 0, 52))
- return 500;
-
- /*
- * If the rate is slower than single-stream MCS4, limit A-MSDU to usual
- * data packet size
- */
-- if (g->duration[rate] > MCS_DURATION(1, 0, 104))
-+ if (duration > MCS_DURATION(1, 0, 104))
- return 1600;
-
- /*
-@@ -895,7 +909,7 @@ minstrel_ht_get_max_amsdu_len(struct min
- * rate success probability is less than 75%, limit A-MSDU to twice the usual
- * data packet size
- */
-- if (g->duration[rate] > MCS_DURATION(1, 0, 260) ||
-+ if (duration > MCS_DURATION(1, 0, 260) ||
- (minstrel_ht_get_prob_ewma(mi, mi->max_tp_rate[0]) <
- MINSTREL_FRAC(75, 100)))
- return 3200;
-@@ -942,13 +956,6 @@ minstrel_ht_update_rates(struct minstrel
- rate_control_set_rates(mp->hw, mi->sta, rates);
- }
-
--static inline int
--minstrel_get_duration(int index)
--{
-- const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
-- return group->duration[index % MCS_GROUP_RATES];
--}
--
- static int
- minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
- {
---- a/net/mac80211/rc80211_minstrel_ht.h
-+++ b/net/mac80211/rc80211_minstrel_ht.h
-@@ -33,9 +33,10 @@
- #define MCS_GROUP_RATES 10
-
- struct mcs_group {
-- u32 flags;
-- unsigned int streams;
-- unsigned int duration[MCS_GROUP_RATES];
-+ u16 flags;
-+ u8 streams;
-+ u8 shift;
-+ u16 duration[MCS_GROUP_RATES];
- };
-
- extern const struct mcs_group minstrel_mcs_groups[];
---- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
-+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
-@@ -58,6 +58,7 @@ minstrel_ht_stats_dump(struct minstrel_h
- static const int bitrates[4] = { 10, 20, 55, 110 };
- int idx = i * MCS_GROUP_RATES + j;
- unsigned int prob_ewmsd;
-+ unsigned int duration;
-
- if (!(mi->supported[i] & BIT(j)))
- continue;
-@@ -95,7 +96,9 @@ minstrel_ht_stats_dump(struct minstrel_h
- p += sprintf(p, " %3u ", idx);
-
- /* tx_time[rate(i)] in usec */
-- tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
-+ duration = mg->duration[j];
-+ duration <<= mg->shift;
-+ tx_time = DIV_ROUND_CLOSEST(duration, 1000);
- p += sprintf(p, "%6u ", tx_time);
-
- tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
-@@ -204,6 +207,7 @@ minstrel_ht_stats_csv_dump(struct minstr
- static const int bitrates[4] = { 10, 20, 55, 110 };
- int idx = i * MCS_GROUP_RATES + j;
- unsigned int prob_ewmsd;
-+ unsigned int duration;
-
- if (!(mi->supported[i] & BIT(j)))
- continue;
-@@ -238,7 +242,10 @@ minstrel_ht_stats_csv_dump(struct minstr
- }
-
- p += sprintf(p, "%u,", idx);
-- tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
-+
-+ duration = mg->duration[j];
-+ duration <<= mg->shift;
-+ tx_time = DIV_ROUND_CLOSEST(duration, 1000);
- p += sprintf(p, "%u,", tx_time);
-
- tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 10 Feb 2018 13:43:07 +0100
-Subject: [PATCH] mac80211: minstrel: fix using short preamble CCK rates on
- HT clients
-
-mi->supported[MINSTREL_CCK_GROUP] needs to be updated
-
-Fixes: 782dda00ab8e ("mac80211: minstrel_ht: move short preamble check out of get_rate")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -1135,7 +1135,6 @@ minstrel_ht_update_caps(void *priv, stru
- struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
- u16 ht_cap = sta->ht_cap.cap;
- struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
-- struct sta_info *sinfo = container_of(sta, struct sta_info, sta);
- int use_vht;
- int n_supported = 0;
- int ack_dur;
-@@ -1267,8 +1266,7 @@ minstrel_ht_update_caps(void *priv, stru
- if (!n_supported)
- goto use_legacy;
-
-- if (test_sta_flag(sinfo, WLAN_STA_SHORT_PREAMBLE))
-- mi->cck_supported_short |= mi->cck_supported_short << 4;
-+ mi->supported[MINSTREL_CCK_GROUP] |= mi->cck_supported_short << 4;
-
- /* create an initial rate table with the lowest supported rates */
- minstrel_ht_update_stats(mp, mi);
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 1 Mar 2018 13:27:54 +0100
-Subject: [PATCH] mac80211: minstrel: fix CCK rate group streams value
-
-Fixes a harmless underflow issue when CCK rates are actively being used
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -131,7 +131,7 @@
-
- #define CCK_GROUP(_s) \
- [MINSTREL_CCK_GROUP] = { \
-- .streams = 0, \
-+ .streams = 1, \
- .flags = 0, \
- .shift = _s, \
- .duration = { \
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 1 Mar 2018 13:28:48 +0100
-Subject: [PATCH] mac80211: minstrel: fix sampling/reporting of CCK rates
- in HT mode
-
-Long/short preamble selection cannot be sampled separately, since it
-depends on the BSS state. Because of that, sampling attempts to
-currently not used preamble modes are not counted in the statistics,
-which leads to CCK rates being sampled too often.
-
-Fix statistics accounting for long/short preamble by increasing the
-index where necessary.
-Fix excessive CCK rate sampling by dropping unsupported sample attempts.
-
-This improves throughput on 2.4 GHz channels
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -281,7 +281,8 @@ minstrel_ht_get_stats(struct minstrel_pr
- break;
-
- /* short preamble */
-- if (!(mi->supported[group] & BIT(idx)))
-+ if ((mi->supported[group] & BIT(idx + 4)) &&
-+ (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE))
- idx += 4;
- }
- return &mi->groups[group].rates[idx];
-@@ -1080,18 +1081,23 @@ minstrel_ht_get_rate(void *priv, struct
- return;
-
- sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES];
-+ sample_idx %= MCS_GROUP_RATES;
-+
-+ if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP] &&
-+ (sample_idx >= 4) != txrc->short_preamble)
-+ return;
-+
- info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
- rate->count = 1;
-
-- if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
-+ if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP]) {
- int idx = sample_idx % ARRAY_SIZE(mp->cck_rates);
- rate->idx = mp->cck_rates[idx];
- } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) {
- ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES,
- sample_group->streams);
- } else {
-- rate->idx = sample_idx % MCS_GROUP_RATES +
-- (sample_group->streams - 1) * 8;
-+ rate->idx = sample_idx + (sample_group->streams - 1) * 8;
- }
-
- rate->flags = sample_group->flags;
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 3 Mar 2018 18:48:58 +0100
-Subject: [PATCH] mac80211: minstrel: do not sample rates 3 times slower than
- max_prob_rate
-
-These rates are highly unlikely to be used quickly, even if the link
-deteriorates rapidly. This improves throughput in cases where CCK rates
-are not reliable enough to be skipped entirely during sampling.
-Sampling these rates regularly can cost a lot of airtime.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -1004,10 +1004,13 @@ minstrel_get_sample_rate(struct minstrel
- return -1;
-
- /*
-- * Do not sample if the probability is already higher than 95%
-- * to avoid wasting airtime.
-+ * Do not sample if the probability is already higher than 95%,
-+ * or if the rate is 3 times slower than the current max probability
-+ * rate, to avoid wasting airtime.
- */
-- if (mrs->prob_ewma > MINSTREL_FRAC(95, 100))
-+ sample_dur = minstrel_get_duration(sample_idx);
-+ if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) ||
-+ minstrel_get_duration(mi->max_prob_rate) * 3 < sample_dur)
- return -1;
-
- /*
-@@ -1017,7 +1020,6 @@ minstrel_get_sample_rate(struct minstrel
-
- cur_max_tp_streams = minstrel_mcs_groups[tp_rate1 /
- MCS_GROUP_RATES].streams;
-- sample_dur = minstrel_get_duration(sample_idx);
- if (sample_dur >= minstrel_get_duration(tp_rate2) &&
- (cur_max_tp_streams - 1 <
- minstrel_mcs_groups[sample_group].streams ||
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 8 Mar 2018 21:00:56 +0100
+Subject: [PATCH] mac80211: fix memory accounting with A-MSDU aggregation
+
+fq uses skb->truesize for memory usage tracking. Increments/decrements
+are done on enqueue/dequeue.
+When A-MSDU aggregation is performed on tx side, the packet is
+aggregated with the last packet in the queue belonging to the same flow.
+There are multiple bugs here:
+- The truesize field of the aggregated packet isn't updated, so memory
+usage is underestimated
+- fq->memory_usage isn't adjusted.
+
+Because of the combination of both bugs, this only causes tx issues in
+rare cases, mainly when the A-MSDU head needs to be reallocated.
+
+Fix this by adjusting both truesize of the A-MSDU head and adding the
+truesize delta to fq->memory_usage.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -3214,6 +3214,7 @@ static bool ieee80211_amsdu_aggregate(st
+ u8 max_subframes = sta->sta.max_amsdu_subframes;
+ int max_frags = local->hw.max_tx_fragments;
+ int max_amsdu_len = sta->sta.max_amsdu_len;
++ int orig_truesize;
+ __be16 len;
+ void *data;
+ bool ret = false;
+@@ -3249,12 +3250,13 @@ static bool ieee80211_amsdu_aggregate(st
+ flow = fq_flow_classify(fq, tin, skb, fq_flow_get_default_func);
+ head = skb_peek_tail(&flow->queue);
+ if (!head)
+- goto out;
++ goto unlock;
+
++ orig_truesize = head->truesize;
+ orig_len = head->len;
+
+ if (skb->len + head->len > max_amsdu_len)
+- goto out;
++ goto unlock;
+
+ nfrags = 1 + skb_shinfo(skb)->nr_frags;
+ nfrags += 1 + skb_shinfo(head)->nr_frags;
+@@ -3315,6 +3317,9 @@ out_recalc:
+ fq_recalc_backlog(fq, tin, flow);
+ }
+ out:
++ fq->memory_usage += head->truesize - orig_truesize;
++
++unlock:
+ spin_unlock_bh(&fq->lock);
+
+ return ret;
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -2131,6 +2131,9 @@ struct ieee80211_txq {
- * @IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP: The driver (or firmware) doesn't
- * support QoS NDP for AP probing - that's most likely a driver bug.
+@@ -2181,6 +2181,9 @@ struct ieee80211_txq {
+ * MMPDUs on station interfaces. This of course requires the driver to use
+ * TXQs to start with.
*
+ * @IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN: Driver does not report accurate A-MPDU
+ * length in tx status information
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
-@@ -2176,6 +2179,7 @@ enum ieee80211_hw_flags {
- IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA,
- IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP,
- IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP,
+@@ -2229,6 +2232,7 @@ enum ieee80211_hw_flags {
+ IEEE80211_HW_BUFF_MMPDU_TXQ,
+ IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW,
+ IEEE80211_HW_STA_MMPDU_TXQ,
+ IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
-@@ -214,6 +214,7 @@ static const char *hw_flag_names[] = {
- FLAG(SUPPORTS_TDLS_BUFFER_STA),
- FLAG(DEAUTH_NEED_MGD_TX_PREP),
- FLAG(DOESNT_SUPPORT_QOS_NDP),
+@@ -218,6 +218,7 @@ static const char *hw_flag_names[] = {
+ FLAG(BUFF_MMPDU_TXQ),
+ FLAG(SUPPORTS_VHT_EXT_NSS_BW),
+ FLAG(STA_MMPDU_TXQ),
+ FLAG(TX_STATUS_NO_AMPDU_LEN),
#undef FLAG
};
mrs = minstrel_get_ratestats(mi, index);
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
-@@ -163,9 +163,10 @@ minstrel_ht_stats_open(struct inode *ino
+@@ -160,9 +160,10 @@ minstrel_ht_stats_open(struct inode *ino
"lookaround %d\n",
max(0, (int) mi->total_packets - (int) mi->sample_packets),
mi->sample_packets);
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 13 Mar 2019 18:52:56 +0100
+Subject: [PATCH] mac80211: fix unaligned access in mesh table hash function
+
+The pointer to the last four bytes of the address is not guaranteed to be
+aligned, so we need to use __get_unaligned_cpu32 here
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/mesh_pathtbl.c
++++ b/net/mac80211/mesh_pathtbl.c
+@@ -23,7 +23,7 @@ static void mesh_path_free_rcu(struct me
+ static u32 mesh_table_hash(const void *addr, u32 len, u32 seed)
+ {
+ /* Use last four bytes of hw addr as hash index */
+- return jhash_1word(*(u32 *)(addr+2), seed);
++ return jhash_1word(__get_unaligned_cpu32(addr+2), seed);
+ }
+
+ static const struct rhashtable_params mesh_rht_params = {
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -107,9 +107,15 @@
+@@ -108,9 +108,15 @@
* The driver is expected to initialize its private per-queue data for stations
* and interfaces in the .add_interface and .sta_add ops.
*
*
* For AP powersave TIM handling, the driver only needs to indicate if it has
* buffered packets in the driver specific data structures by calling
-@@ -5979,7 +5985,8 @@ void ieee80211_unreserve_tid(struct ieee
+@@ -6092,7 +6098,8 @@ void ieee80211_unreserve_tid(struct ieee
* ieee80211_tx_dequeue - dequeue a packet from a software tx queue
*
* @hw: pointer as obtained from ieee80211_alloc_hw()
*
* Returns the skb if successful, %NULL if no frame was available.
*/
-@@ -5987,6 +5994,54 @@ struct sk_buff *ieee80211_tx_dequeue(str
+@@ -6100,6 +6107,54 @@ struct sk_buff *ieee80211_tx_dequeue(str
struct ieee80211_txq *txq);
/**
}
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
-@@ -1176,6 +1176,15 @@ static inline void drv_wake_tx_queue(str
- local->ops->wake_tx_queue(&local->hw, &txq->txq);
+@@ -1202,6 +1202,15 @@ drv_get_ftm_responder_stats(struct ieee8
+ return ret;
}
+static inline void schedule_and_wake_txq(struct ieee80211_local *local,
struct cfg80211_nan_conf *conf)
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
-@@ -829,6 +829,8 @@ enum txq_info_flags {
+@@ -830,6 +830,8 @@ enum txq_info_flags {
* a fq_flow which is already owned by a different tin
* @def_cvars: codel vars for @def_flow
* @frags: used to keep fragments created after dequeue
*/
struct txq_info {
struct fq_tin tin;
-@@ -836,6 +838,8 @@ struct txq_info {
+@@ -837,6 +839,8 @@ struct txq_info {
struct codel_vars def_cvars;
struct codel_stats cstats;
struct sk_buff_head frags;
unsigned long flags;
/* keep last! */
-@@ -1127,6 +1131,11 @@ struct ieee80211_local {
+@@ -1128,6 +1132,11 @@ struct ieee80211_local {
struct codel_vars *cvars;
struct codel_params cparams;
/*
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
-@@ -652,6 +652,11 @@ struct ieee80211_hw *ieee80211_alloc_hw_
+@@ -665,6 +665,11 @@ struct ieee80211_hw *ieee80211_alloc_hw_
spin_lock_init(&local->rx_path_lock);
spin_lock_init(&local->queue_stop_reason_lock);
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
-@@ -1244,7 +1244,7 @@ void ieee80211_sta_ps_deliver_wakeup(str
- if (!txq_has_queue(sta->sta.txq[i]))
- continue;
+@@ -1249,7 +1249,7 @@ void ieee80211_sta_ps_deliver_wakeup(str
+ if (!sta->sta.txq[i] || !txq_has_queue(sta->sta.txq[i]))
+ continue;
-- drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i]));
-+ schedule_and_wake_txq(local, to_txq_info(sta->sta.txq[i]));
- }
+- drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i]));
++ schedule_and_wake_txq(local, to_txq_info(sta->sta.txq[i]));
}
+ skb_queue_head_init(&pending);
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -1441,6 +1441,7 @@ void ieee80211_txq_init(struct ieee80211
+@@ -1449,6 +1449,7 @@ void ieee80211_txq_init(struct ieee80211
codel_vars_init(&txqi->def_cvars);
codel_stats_init(&txqi->cstats);
__skb_queue_head_init(&txqi->frags);
txqi->txq.vif = &sdata->vif;
-@@ -1464,6 +1465,9 @@ void ieee80211_txq_purge(struct ieee8021
+@@ -1489,6 +1490,9 @@ void ieee80211_txq_purge(struct ieee8021
fq_tin_reset(fq, tin, fq_skb_free_func);
ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
}
void ieee80211_txq_set_params(struct ieee80211_local *local)
-@@ -1580,7 +1584,7 @@ static bool ieee80211_queue_skb(struct i
+@@ -1605,7 +1609,7 @@ static bool ieee80211_queue_skb(struct i
ieee80211_txq_enqueue(local, txqi, skb);
spin_unlock_bh(&fq->lock);
return true;
}
-@@ -3600,6 +3604,60 @@ out:
+@@ -3638,6 +3642,60 @@ out:
}
EXPORT_SYMBOL(ieee80211_tx_dequeue);
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
-@@ -988,6 +988,7 @@ enum station_parameters_apply_mask {
+@@ -1001,6 +1001,7 @@ enum station_parameters_apply_mask {
* @support_p2p_ps: information if station supports P2P PS mechanism
* @he_capa: HE capabilities of station
* @he_capa_len: the length of the HE capabilities
*/
struct station_parameters {
const u8 *supported_rates;
-@@ -1017,6 +1018,7 @@ struct station_parameters {
+@@ -1030,6 +1031,7 @@ struct station_parameters {
int support_p2p_ps;
const struct ieee80211_he_cap_elem *he_capa;
u8 he_capa_len;
};
/**
-@@ -1284,6 +1286,8 @@ struct cfg80211_tid_stats {
+@@ -1297,6 +1299,8 @@ struct cfg80211_tid_stats {
* @rx_beacon_signal_avg: signal strength average (in dBm) for beacons received
* from this peer
* @rx_duration: aggregate PPDU duration(usecs) for all the frames from a peer
* @pertid: per-TID statistics, see &struct cfg80211_tid_stats, using the last
* (IEEE80211_NUM_TIDS) index for MSDUs not encapsulated in QoS-MPDUs.
* Note that this doesn't use the @filled bit, but is used if non-NULL.
-@@ -1330,12 +1334,15 @@ struct station_info {
+@@ -1347,8 +1351,9 @@ struct station_info {
u32 expected_throughput;
u8 rx_beacon_signal_avg;
struct cfg80211_tid_stats *pertid;
s8 ack_signal;
- s8 avg_ack_signal;
+@@ -1356,6 +1361,8 @@ struct station_info {
+
+ u32 rx_mpdu_count;
+ u32 fcs_err_count;
+
+ u16 airtime_weight;
};
#if IS_ENABLED(CPTCFG_CFG80211)
-@@ -2361,6 +2368,8 @@ enum wiphy_params_flags {
+@@ -2381,6 +2388,8 @@ enum wiphy_params_flags {
WIPHY_PARAM_TXQ_QUANTUM = 1 << 8,
};
*
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
-@@ -2241,6 +2241,9 @@ enum nl80211_commands {
- * association request when used with NL80211_CMD_NEW_STATION). Can be set
- * only if %NL80211_STA_FLAG_WME is set.
+@@ -2254,6 +2254,9 @@ enum nl80211_commands {
+ * @NL80211_ATTR_FTM_RESPONDER_STATS: Nested attribute with FTM responder
+ * statistics, see &enum nl80211_ftm_responder_stats.
*
+ * @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime
+ * scheduler.
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
-@@ -2682,6 +2685,14 @@ enum nl80211_attrs {
+@@ -2699,6 +2702,12 @@ enum nl80211_attrs {
- NL80211_ATTR_HE_CAPABILITY,
+ NL80211_ATTR_FTM_RESPONDER_STATS,
+ /* not backported yet */
-+ NL80211_ATTR_FTM_RESPONDER,
-+ NL80211_ATTR_FTM_RESPONDER_STATS,
+ NL80211_ATTR_TIMEOUT,
+ NL80211_ATTR_PEER_MEASUREMENTS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
-@@ -3052,6 +3063,9 @@ enum nl80211_sta_bss_param {
- * @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm)
- * @NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG: avg signal strength of (data)
- * ACK frame (s8, dBm)
+@@ -3074,6 +3083,9 @@ enum nl80211_sta_bss_param {
+ * with an FCS error (u32, from this station). This count may not include
+ * some packets with an FCS error due to TA corruption. Hence this counter
+ * might not be fully accurate.
+ * @NL80211_STA_INFO_TX_DURATION: aggregate PPDU duration for all frames
+ * sent to the station (u64, usec)
+ * @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16)
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
-@@ -3093,6 +3107,14 @@ enum nl80211_sta_info {
- NL80211_STA_INFO_ACK_SIGNAL,
- NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG,
+@@ -3117,6 +3129,12 @@ enum nl80211_sta_info {
+ NL80211_STA_INFO_RX_MPDUS,
+ NL80211_STA_INFO_FCS_ERROR_COUNT,
+ /* not backported yet */
-+ NL80211_STA_INFO_RX_MPDUS,
-+ NL80211_STA_INFO_FCS_ERROR_COUNT,
+ NL80211_STA_INFO_CONNECTED_TO_GATE,
+
+ NL80211_STA_INFO_TX_DURATION,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
-@@ -5224,6 +5246,10 @@ enum nl80211_feature_flags {
- * except for supported rates from the probe request content if requested
- * by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
+@@ -5258,6 +5276,10 @@ enum nl80211_feature_flags {
+ * if this flag is not set. Ignoring this can leak clear text packets and/or
+ * freeze the connection.
*
+ * @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime
+ * fairness for transmitted packets and has enabled airtime fairness
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
-@@ -5260,6 +5286,12 @@ enum nl80211_ext_feature_index {
- NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
- NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
+@@ -5298,6 +5320,8 @@ enum nl80211_ext_feature_index {
+ NL80211_EXT_FEATURE_CAN_REPLACE_PTK0,
+ NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
-+ /* --- not backported yet --- */
-+ NL80211_EXT_FEATURE_CAN_REPLACE_PTK0,
-+ NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
-+
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
+
/* add new features before the definition below */
MAX_NL80211_EXT_FEATURES = NUM_NL80211_EXT_FEATURES - 1
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
-@@ -430,6 +430,7 @@ static const struct nla_policy nl80211_p
- [NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
- [NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY,
- .len = NL80211_HE_MAX_CAPABILITY_LEN },
+@@ -497,6 +497,7 @@ static const struct nla_policy nl80211_p
+ .type = NLA_NESTED,
+ .validation_data = nl80211_ftm_responder_policy,
+ },
+ [NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
};
/* policy for the key attributes */
-@@ -4664,6 +4665,11 @@ static int nl80211_send_station(struct s
+@@ -4694,6 +4695,11 @@ static int nl80211_send_station(struct s
PUT_SINFO(PLID, plid, u16);
PUT_SINFO(PLINK_STATE, plink_state, u8);
PUT_SINFO_U64(RX_DURATION, rx_duration);
switch (rdev->wiphy.signal_type) {
case CFG80211_SIGNAL_TYPE_MBM:
-@@ -5300,6 +5306,15 @@ static int nl80211_set_station(struct sk
+@@ -5312,6 +5318,15 @@ static int nl80211_set_station(struct sk
nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
}
/* Include parameters for TDLS peer (will check later) */
err = nl80211_set_station_tdls(info, ¶ms);
if (err)
-@@ -5438,6 +5453,15 @@ static int nl80211_new_station(struct sk
- return -EINVAL;
- }
+@@ -5440,6 +5455,15 @@ static int nl80211_new_station(struct sk
+ params.plink_action =
+ nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+ if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
+ params.airtime_weight =
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -2304,6 +2304,9 @@ enum ieee80211_hw_flags {
- * supported by HW.
- * @max_nan_de_entries: maximum number of NAN DE functions supported by the
- * device.
+@@ -2361,6 +2361,9 @@ enum ieee80211_hw_flags {
+ * @tx_sk_pacing_shift: Pacing shift to set on TCP sockets when frames from
+ * them are encountered. The default should typically not be changed,
+ * unless the driver has good reasons for needing more buffers.
+ *
+ * @weight_multipler: Driver specific airtime weight multiplier used while
+ * refilling deficit of each TXQ.
*/
struct ieee80211_hw {
struct ieee80211_conf conf;
-@@ -2339,6 +2342,7 @@ struct ieee80211_hw {
- u8 n_cipher_schemes;
+@@ -2397,6 +2400,7 @@ struct ieee80211_hw {
const struct ieee80211_cipher_scheme *cipher_schemes;
u8 max_nan_de_entries;
+ u8 tx_sk_pacing_shift;
+ u8 weight_multiplier;
};
static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
-@@ -5299,6 +5303,34 @@ void ieee80211_sta_eosp(struct ieee80211
+@@ -5397,6 +5401,34 @@ void ieee80211_sta_eosp(struct ieee80211
void ieee80211_send_eosp_nullfunc(struct ieee80211_sta *pubsta, int tid);
/**
* ieee80211_iter_keys - iterate keys programmed into the device
* @hw: pointer obtained from ieee80211_alloc_hw()
* @vif: virtual interface to iterate, may be %NULL for all
-@@ -6042,6 +6074,33 @@ void ieee80211_txq_schedule_end(struct i
+@@ -6155,6 +6187,33 @@ void ieee80211_txq_schedule_end(struct i
__releases(txq_lock);
/**
* The values are not guaranteed to be coherent with regard to each other, i.e.
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -1434,6 +1434,9 @@ static int sta_apply_parameters(struct i
+@@ -1450,6 +1450,9 @@ static int sta_apply_parameters(struct i
if (ieee80211_vif_is_mesh(&sdata->vif))
sta_apply_mesh_params(local, sta, params);
set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
-@@ -380,6 +380,9 @@ void debugfs_hw_add(struct ieee80211_loc
+@@ -384,6 +384,9 @@ void debugfs_hw_add(struct ieee80211_loc
if (local->ops->wake_tx_queue)
DEBUGFS_ADD_MODE(aqm, 0600);
/* if the dir failed, don't put all the other things into the root! */
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
-@@ -178,9 +178,9 @@ static ssize_t sta_aqm_read(struct file
+@@ -181,9 +181,9 @@ static ssize_t sta_aqm_read(struct file
txqi->tin.tx_bytes,
txqi->tin.tx_packets,
txqi->flags,
}
rcu_read_unlock();
-@@ -192,6 +192,64 @@ static ssize_t sta_aqm_read(struct file
+@@ -195,6 +195,64 @@ static ssize_t sta_aqm_read(struct file
}
STA_OPS(aqm);
static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
-@@ -546,6 +604,10 @@ void ieee80211_sta_debugfs_add(struct st
+@@ -906,6 +964,10 @@ void ieee80211_sta_debugfs_add(struct st
if (local->ops->wake_tx_queue)
DEBUGFS_ADD(aqm);
sta->debugfs_dir,
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
-@@ -1136,6 +1136,8 @@ struct ieee80211_local {
+@@ -1137,6 +1137,8 @@ struct ieee80211_local {
struct list_head active_txqs[IEEE80211_NUM_ACS];
u16 schedule_round[IEEE80211_NUM_ACS];
/*
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
-@@ -656,6 +656,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
+@@ -669,6 +669,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
INIT_LIST_HEAD(&local->active_txqs[i]);
spin_lock_init(&local->active_txq_lock[i]);
}
INIT_LIST_HEAD(&local->chanctx_list);
mutex_init(&local->chanctx_mtx);
-@@ -1142,6 +1143,9 @@ int ieee80211_register_hw(struct ieee802
+@@ -1155,6 +1156,9 @@ int ieee80211_register_hw(struct ieee802
if (!local->hw.max_nan_de_entries)
local->hw.max_nan_de_entries = IEEE80211_MAX_NAN_INSTANCE_ID;
struct ps_data *ps;
if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
-@@ -115,9 +114,7 @@ static void __cleanup_single_sta(struct
- for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
- struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
+@@ -120,9 +119,7 @@ static void __cleanup_single_sta(struct
+
+ txqi = to_txq_info(sta->sta.txq[i]);
- spin_lock_bh(&fq->lock);
ieee80211_txq_purge(local, txqi);
}
}
-@@ -381,9 +378,12 @@ struct sta_info *sta_info_alloc(struct i
+@@ -387,9 +384,12 @@ struct sta_info *sta_info_alloc(struct i
if (sta_prepare_rate_control(local, sta, gfp))
goto free_txq;
}
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
-@@ -1821,6 +1821,27 @@ void ieee80211_sta_set_buffered(struct i
+@@ -1826,6 +1826,27 @@ void ieee80211_sta_set_buffered(struct i
}
EXPORT_SYMBOL(ieee80211_sta_set_buffered);
int sta_info_move_state(struct sta_info *sta,
enum ieee80211_sta_state new_state)
{
-@@ -2183,6 +2204,23 @@ void sta_set_sinfo(struct sta_info *sta,
+@@ -2188,6 +2209,23 @@ void sta_set_sinfo(struct sta_info *sta,
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
}
if (sta->status_stats.lost_packets)
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -1463,8 +1463,11 @@ void ieee80211_txq_purge(struct ieee8021
+@@ -1488,8 +1488,11 @@ void ieee80211_txq_purge(struct ieee8021
struct fq *fq = &local->fq;
struct fq_tin *tin = &txqi->tin;
spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
list_del_init(&txqi->schedule_order);
spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
-@@ -3611,11 +3614,28 @@ struct ieee80211_txq *ieee80211_next_txq
+@@ -3649,11 +3652,28 @@ struct ieee80211_txq *ieee80211_next_txq
lockdep_assert_held(&local->active_txq_lock[ac]);
return NULL;
list_del_init(&txqi->schedule_order);
-@@ -3633,12 +3653,74 @@ void ieee80211_return_txq(struct ieee802
+@@ -3671,12 +3691,74 @@ void ieee80211_return_txq(struct ieee802
lockdep_assert_held(&local->active_txq_lock[txq->ac]);
if (list_empty(&txqi->schedule_order) &&
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -6074,6 +6074,19 @@ void ieee80211_txq_schedule_end(struct i
+@@ -6187,6 +6187,19 @@ void ieee80211_txq_schedule_end(struct i
__releases(txq_lock);
/**
* This function is used to check whether given txq is allowed to transmit by
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
-@@ -1179,9 +1179,7 @@ static inline void drv_wake_tx_queue(str
+@@ -1205,9 +1205,7 @@ drv_get_ftm_responder_stats(struct ieee8
static inline void schedule_and_wake_txq(struct ieee80211_local *local,
struct txq_info *txqi)
{
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -3673,6 +3673,19 @@ void ieee80211_return_txq(struct ieee802
+@@ -3711,6 +3711,19 @@ void ieee80211_return_txq(struct ieee802
}
EXPORT_SYMBOL(ieee80211_return_txq);
if (likely(sta)) {
if (!IS_ERR(sta))
tx->sta = sta;
-@@ -3523,6 +3523,7 @@ begin:
+@@ -3561,6 +3561,7 @@ begin:
tx.local = local;
tx.skb = skb;
tx.sdata = vif_to_sdata(info->control.vif);
if (txq->sta)
tx.sta = container_of(txq->sta, struct sta_info, sta);
-@@ -3549,7 +3550,7 @@ begin:
+@@ -3587,7 +3588,7 @@ begin:
if (tx.key &&
(tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
tx.key, skb);
-@@ -4006,6 +4007,7 @@ ieee80211_build_data_template(struct iee
+@@ -4038,6 +4039,7 @@ ieee80211_build_data_template(struct iee
hdr = (void *)skb->data;
tx.sta = sta_info_get(sdata, hdr->addr1);
tx.skb = skb;
rcu_read_unlock();
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
-@@ -1390,6 +1390,7 @@ void ieee80211_send_auth(struct ieee8021
+@@ -1414,6 +1414,7 @@ void ieee80211_send_auth(struct ieee8021
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
int err;
/* 24 + 6 = header + auth_algo + auth_transaction + status_code */
-@@ -1413,8 +1414,10 @@ void ieee80211_send_auth(struct ieee8021
+@@ -1437,8 +1438,10 @@ void ieee80211_send_auth(struct ieee8021
skb_put_data(skb, extra, extra_len);
if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -2140,6 +2140,9 @@ struct ieee80211_txq {
+@@ -2190,6 +2190,9 @@ struct ieee80211_txq {
* @IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN: Driver does not report accurate A-MPDU
* length in tx status information
*
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
-@@ -2186,6 +2189,7 @@ enum ieee80211_hw_flags {
- IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP,
- IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP,
+@@ -2239,6 +2242,7 @@ enum ieee80211_hw_flags {
+ IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW,
+ IEEE80211_HW_STA_MMPDU_TXQ,
IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
+ IEEE80211_HW_TX_NEEDS_ALIGNED4_SKBS,
/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS
-@@ -2472,6 +2476,40 @@ ieee80211_get_alt_retry_rate(const struc
+@@ -2530,6 +2534,40 @@ ieee80211_get_alt_retry_rate(const struc
void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
/**
if (!(mshdr->flags & MESH_FLAGS_AE)) {
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
-@@ -2597,7 +2597,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
+@@ -2639,7 +2639,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = rx->sdata;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
int tailroom = 0;
hdr = (struct ieee80211_hdr *) skb->data;
-@@ -2690,7 +2690,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
+@@ -2732,7 +2732,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
if (sdata->crypto_tx_tailroom_needed_cnt)
tailroom = IEEE80211_ENCRYPT_TAILROOM;
sdata->encrypt_headroom,
tailroom, GFP_ATOMIC);
if (!fwd_skb)
-@@ -2722,6 +2724,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
+@@ -2764,6 +2766,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
return RX_DROP_MONITOR;
}
if (likely(sta)) {
if (!IS_ERR(sta))
-@@ -2222,7 +2221,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
+@@ -2247,7 +2246,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
goto fail;
hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
if (skb->len < len_rthdr + hdrlen)
goto fail;
-@@ -2440,7 +2439,7 @@ static struct sk_buff *ieee80211_build_h
+@@ -2465,7 +2464,7 @@ static struct sk_buff *ieee80211_build_h
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_sub_if_data *ap_sdata;
enum nl80211_band band;
if (IS_ERR(sta))
sta = NULL;
-@@ -2739,7 +2738,9 @@ static struct sk_buff *ieee80211_build_h
+@@ -2764,7 +2763,9 @@ static struct sk_buff *ieee80211_build_h
}
skb_pull(skb, skip_header_bytes);
/*
* So we need to modify the skb header and hence need a copy of
-@@ -2772,6 +2773,9 @@ static struct sk_buff *ieee80211_build_h
+@@ -2797,6 +2798,9 @@ static struct sk_buff *ieee80211_build_h
memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
#endif
if (ieee80211_is_data_qos(fc)) {
__le16 *qos_control;
-@@ -2947,6 +2951,8 @@ void ieee80211_check_fast_xmit(struct st
+@@ -2972,6 +2976,8 @@ void ieee80211_check_fast_xmit(struct st
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
}
/* We store the key here so there's no point in using rcu_dereference()
* but that's fine because the code that changes the pointers will call
* this function after doing so. For a single CPU that would be enough,
-@@ -3523,7 +3529,7 @@ begin:
+@@ -3561,7 +3567,7 @@ begin:
tx.local = local;
tx.skb = skb;
tx.sdata = vif_to_sdata(info->control.vif);
if (txq->sta)
tx.sta = container_of(txq->sta, struct sta_info, sta);
-@@ -4007,7 +4013,7 @@ ieee80211_build_data_template(struct iee
+@@ -4039,7 +4045,7 @@ ieee80211_build_data_template(struct iee
hdr = (void *)skb->data;
tx.sta = sta_info_get(sdata, hdr->addr1);
tx.skb = skb;
rcu_read_unlock();
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
-@@ -215,6 +215,7 @@ static const char *hw_flag_names[] = {
- FLAG(DEAUTH_NEED_MGD_TX_PREP),
- FLAG(DOESNT_SUPPORT_QOS_NDP),
+@@ -219,6 +219,7 @@ static const char *hw_flag_names[] = {
+ FLAG(SUPPORTS_VHT_EXT_NSS_BW),
+ FLAG(STA_MMPDU_TXQ),
FLAG(TX_STATUS_NO_AMPDU_LEN),
+ FLAG(TX_NEEDS_ALIGNED4_SKBS),
#undef FLAG
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -6069,8 +6069,6 @@ struct sk_buff *ieee80211_tx_dequeue(str
+@@ -6182,8 +6182,6 @@ struct sk_buff *ieee80211_tx_dequeue(str
* @hw: pointer as obtained from ieee80211_alloc_hw()
* @ac: AC number to return packets from.
*
* Returns the next txq if successful, %NULL if no queue is eligible. If a txq
* is returned, it should be returned with ieee80211_return_txq() after the
* driver has finished scheduling it.
-@@ -6078,51 +6076,41 @@ struct sk_buff *ieee80211_tx_dequeue(str
+@@ -6191,51 +6189,41 @@ struct sk_buff *ieee80211_tx_dequeue(str
struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac);
/**
* ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -3617,16 +3617,17 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue);
+@@ -3655,16 +3655,17 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue);
struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
{
struct ieee80211_local *local = hw_to_local(hw);
if (txqi->txq.sta) {
struct sta_info *sta = container_of(txqi->txq.sta,
-@@ -3643,21 +3644,25 @@ struct ieee80211_txq *ieee80211_next_txq
+@@ -3681,21 +3682,25 @@ struct ieee80211_txq *ieee80211_next_txq
if (txqi->schedule_round == local->schedule_round[ac])
if (list_empty(&txqi->schedule_order) &&
(!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets)) {
-@@ -3677,18 +3682,7 @@ void ieee80211_return_txq(struct ieee802
+@@ -3715,18 +3720,7 @@ void ieee80211_return_txq(struct ieee802
list_add_tail(&txqi->schedule_order,
&local->active_txqs[txq->ac]);
}
spin_unlock_bh(&local->active_txq_lock[txq->ac]);
}
EXPORT_SYMBOL(ieee80211_schedule_txq);
-@@ -3701,7 +3695,7 @@ bool ieee80211_txq_may_transmit(struct i
+@@ -3739,7 +3733,7 @@ bool ieee80211_txq_may_transmit(struct i
struct sta_info *sta;
u8 ac = txq->ac;
if (!txqi->txq.sta)
goto out;
-@@ -3731,34 +3725,27 @@ bool ieee80211_txq_may_transmit(struct i
+@@ -3769,34 +3763,27 @@ bool ieee80211_txq_may_transmit(struct i
sta->airtime[ac].deficit += sta->airtime_weight;
list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
flow->backlog += skb->len;
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -1390,11 +1390,15 @@ static void ieee80211_txq_enqueue(struct
+@@ -1398,11 +1398,15 @@ static void ieee80211_txq_enqueue(struct
{
struct fq *fq = &local->fq;
struct fq_tin *tin = &txqi->tin;
}
static bool fq_vlan_filter_func(struct fq *fq, struct fq_tin *tin,
-@@ -1564,7 +1568,6 @@ static bool ieee80211_queue_skb(struct i
+@@ -1589,7 +1593,6 @@ static bool ieee80211_queue_skb(struct i
struct sta_info *sta,
struct sk_buff *skb)
{
struct ieee80211_vif *vif;
struct txq_info *txqi;
-@@ -1582,9 +1585,7 @@ static bool ieee80211_queue_skb(struct i
+@@ -1607,9 +1610,7 @@ static bool ieee80211_queue_skb(struct i
if (!txqi)
return false;
schedule_and_wake_txq(local, txqi);
-@@ -3198,6 +3199,7 @@ static bool ieee80211_amsdu_aggregate(st
+@@ -3227,6 +3228,7 @@ static bool ieee80211_amsdu_aggregate(st
u8 max_subframes = sta->sta.max_amsdu_subframes;
int max_frags = local->hw.max_tx_fragments;
int max_amsdu_len = sta->sta.max_amsdu_len;
int orig_truesize;
__be16 len;
void *data;
-@@ -3220,6 +3222,8 @@ static bool ieee80211_amsdu_aggregate(st
+@@ -3253,6 +3255,8 @@ static bool ieee80211_amsdu_aggregate(st
max_amsdu_len = min_t(int, max_amsdu_len,
- sta->sta.max_rc_amsdu_len);
+ sta->sta.max_tid_amsdu_len[tid]);
+ flow_idx = fq_flow_idx(fq, skb);
+
spin_lock_bh(&fq->lock);
/* TODO: Ideally aggregation should be done on dequeue to remain
-@@ -3227,7 +3231,8 @@ static bool ieee80211_amsdu_aggregate(st
+@@ -3260,7 +3264,8 @@ static bool ieee80211_amsdu_aggregate(st
*/
tin = &txqi->tin;
+ fq_flow_get_default_func);
head = skb_peek_tail(&flow->queue);
if (!head)
- goto out;
+ goto unlock;
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -3505,6 +3505,7 @@ struct sk_buff *ieee80211_tx_dequeue(str
+@@ -3543,6 +3543,7 @@ struct sk_buff *ieee80211_tx_dequeue(str
ieee80211_tx_result r;
struct ieee80211_vif *vif = txq->vif;
spin_lock_bh(&fq->lock);
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ||
-@@ -3521,11 +3522,12 @@ struct sk_buff *ieee80211_tx_dequeue(str
+@@ -3559,11 +3560,12 @@ struct sk_buff *ieee80211_tx_dequeue(str
if (skb)
goto out;
hdr = (struct ieee80211_hdr *)skb->data;
info = IEEE80211_SKB_CB(skb);
-@@ -3571,8 +3573,11 @@ begin:
+@@ -3609,8 +3611,11 @@ begin:
skb = __skb_dequeue(&tx.skbs);
}
if (skb && skb_has_frag_list(skb) &&
-@@ -3611,6 +3616,7 @@ begin:
+@@ -3649,6 +3654,7 @@ begin:
}
IEEE80211_SKB_CB(skb)->control.vif = vif;
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
-@@ -1761,6 +1761,9 @@ void ieee80211_clear_fast_xmit(struct st
+@@ -1765,6 +1765,9 @@ void ieee80211_clear_fast_xmit(struct st
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len,
const u8 *dest, __be16 proto, bool unencrypted);
if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -1914,37 +1914,53 @@ static bool ieee80211_tx(struct ieee8021
+@@ -1939,37 +1939,53 @@ static bool ieee80211_tx(struct ieee8021
}
/* device xmit handlers */
wiphy_debug(local->hw.wiphy,
"failed to reallocate TX buffer\n");
return -ENOMEM;
-@@ -1960,18 +1976,8 @@ void ieee80211_xmit(struct ieee80211_sub
+@@ -1985,18 +2001,8 @@ void ieee80211_xmit(struct ieee80211_sub
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
ieee80211_free_txskb(&local->hw, skb);
return;
}
-@@ -2740,30 +2746,14 @@ static struct sk_buff *ieee80211_build_h
+@@ -2765,30 +2771,14 @@ static struct sk_buff *ieee80211_build_h
skb_pull(skb, skip_header_bytes);
padsize = ieee80211_hdr_padsize(&local->hw, hdrlen);
}
if (encaps_data)
-@@ -3375,7 +3365,6 @@ static bool ieee80211_xmit_fast(struct i
+@@ -3413,7 +3403,6 @@ static bool ieee80211_xmit_fast(struct i
struct ieee80211_local *local = sdata->local;
u16 ethertype = (skb->data[12] << 8) | skb->data[13];
int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
struct ethhdr eth;
struct ieee80211_tx_info *info;
struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
-@@ -3427,10 +3416,7 @@ static bool ieee80211_xmit_fast(struct i
+@@ -3465,10 +3454,7 @@ static bool ieee80211_xmit_fast(struct i
* as the may-encrypt argument for the resize to not account for
* more room than we already have in 'extra_head'
*/
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -6090,26 +6090,42 @@ static inline void ieee80211_txq_schedul
+@@ -6203,26 +6203,42 @@ static inline void ieee80211_txq_schedul
{
}
/**
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -3653,8 +3653,9 @@ out:
+@@ -3691,8 +3691,9 @@ out:
}
EXPORT_SYMBOL(ieee80211_next_txq);
{
struct ieee80211_local *local = hw_to_local(hw);
struct txq_info *txqi = to_txq_info(txq);
-@@ -3662,7 +3663,8 @@ void ieee80211_schedule_txq(struct ieee8
+@@ -3700,7 +3701,8 @@ void ieee80211_schedule_txq(struct ieee8
spin_lock_bh(&local->active_txq_lock[txq->ac]);
if (list_empty(&txqi->schedule_order) &&
/* If airtime accounting is active, always enqueue STAs at the
* head of the list to ensure that they only get moved to the
* back by the airtime DRR scheduler once they have a negative
-@@ -3682,7 +3684,7 @@ void ieee80211_schedule_txq(struct ieee8
+@@ -3720,7 +3722,7 @@ void ieee80211_schedule_txq(struct ieee8
spin_unlock_bh(&local->active_txq_lock[txq->ac]);
}
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
-@@ -1508,7 +1508,15 @@ static void sta_ps_start(struct sta_info
+@@ -1547,7 +1547,15 @@ static void sta_ps_start(struct sta_info
return;
- for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
+ for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
- if (txq_has_queue(sta->sta.txq[tid]))
+ struct ieee80211_txq *txq = sta->sta.txq[tid];
+ struct txq_info *txqi = to_txq_info(txq);
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -3751,6 +3751,7 @@ void __ieee80211_subif_start_xmit(struct
+@@ -3789,6 +3789,7 @@ void __ieee80211_subif_start_xmit(struct
u32 info_flags)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta;
struct sk_buff *next;
-@@ -3764,7 +3765,15 @@ void __ieee80211_subif_start_xmit(struct
+@@ -3802,7 +3803,15 @@ void __ieee80211_subif_start_xmit(struct
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
goto out_free;
+ if (sta) {
struct ieee80211_fast_tx *fast_tx;
- /* We need a bit of data queued to build aggregates properly, so
+ sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -141,6 +141,42 @@ u16 ieee80211_select_queue_80211(struct
--- /dev/null
+From 33d915d9e8ce811d8958915ccd18d71a66c7c495 Mon Sep 17 00:00:00 2001
+From: Manikanta Pubbisetty <mpubbise@codeaurora.org>
+Date: Wed, 8 May 2019 14:55:33 +0530
+Subject: [PATCH] {nl,mac}80211: allow 4addr AP operation on crypto controlled
+ devices
+
+As per the current design, in the case of sw crypto controlled devices,
+it is the device which advertises the support for AP/VLAN iftype based
+on it's ability to tranmsit packets encrypted in software
+(In VLAN functionality, group traffic generated for a specific
+VLAN group is always encrypted in software). Commit db3bdcb9c3ff
+("mac80211: allow AP_VLAN operation on crypto controlled devices")
+has introduced this change.
+
+Since 4addr AP operation also uses AP/VLAN iftype, this conditional
+way of advertising AP/VLAN support has broken 4addr AP mode operation on
+crypto controlled devices which do not support VLAN functionality.
+
+In the case of ath10k driver, not all firmwares have support for VLAN
+functionality but all can support 4addr AP operation. Because AP/VLAN
+support is not advertised for these devices, 4addr AP operations are
+also blocked.
+
+Fix this by allowing 4addr operation on devices which do not support
+AP/VLAN iftype but can support 4addr AP operation (decision is based on
+the wiphy flag WIPHY_FLAG_4ADDR_AP).
+
+Cc: stable@vger.kernel.org
+Fixes: db3bdcb9c3ff ("mac80211: allow AP_VLAN operation on crypto controlled devices")
+Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+ include/net/cfg80211.h | 3 ++-
+ net/mac80211/util.c | 4 +++-
+ net/wireless/core.c | 6 +++++-
+ net/wireless/nl80211.c | 8 ++++++--
+ 4 files changed, 16 insertions(+), 5 deletions(-)
+
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -3518,7 +3518,8 @@ struct cfg80211_ops {
+ * on wiphy_new(), but can be changed by the driver if it has a good
+ * reason to override the default
+ * @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
+- * on a VLAN interface)
++ * on a VLAN interface). This flag also serves an extra purpose of
++ * supporting 4ADDR AP mode on devices which do not support AP/VLAN iftype.
+ * @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station
+ * @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
+ * control port protocol ethertype. The device also honours the
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -3667,7 +3667,9 @@ int ieee80211_check_combinations(struct
+ }
+
+ /* Always allow software iftypes */
+- if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
++ if (local->hw.wiphy->software_iftypes & BIT(iftype) ||
++ (iftype == NL80211_IFTYPE_AP_VLAN &&
++ local->hw.wiphy->flags & WIPHY_FLAG_4ADDR_AP)) {
+ if (radar_detect)
+ return -EINVAL;
+ return 0;
+--- a/net/wireless/core.c
++++ b/net/wireless/core.c
+@@ -1362,8 +1362,12 @@ static int cfg80211_netdev_notifier_call
+ }
+ break;
+ case NETDEV_PRE_UP:
+- if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
++ if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)) &&
++ !(wdev->iftype == NL80211_IFTYPE_AP_VLAN &&
++ rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP &&
++ wdev->use_4addr))
+ return notifier_from_errno(-EOPNOTSUPP);
++
+ if (rfkill_blocked(rdev->rfkill))
+ return notifier_from_errno(-ERFKILL);
+ break;
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -3233,8 +3233,7 @@ static int nl80211_new_interface(struct
+ if (info->attrs[NL80211_ATTR_IFTYPE])
+ type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
+
+- if (!rdev->ops->add_virtual_intf ||
+- !(rdev->wiphy.interface_modes & (1 << type)))
++ if (!rdev->ops->add_virtual_intf)
+ return -EOPNOTSUPP;
+
+ if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
+@@ -3253,6 +3252,11 @@ static int nl80211_new_interface(struct
+ return err;
+ }
+
++ if (!(rdev->wiphy.interface_modes & (1 << type)) &&
++ !(type == NL80211_IFTYPE_AP_VLAN && params.use_4addr &&
++ rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP))
++ return -EOPNOTSUPP;
++
+ err = nl80211_parse_mon_options(rdev, type, info, ¶ms);
+ if (err < 0)
+ return err;
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
-@@ -2968,6 +2968,7 @@ struct cfg80211_external_auth_params {
+@@ -3022,6 +3022,7 @@ struct cfg80211_ftm_responder_stats {
* (as advertised by the nl80211 feature flag.)
* @get_tx_power: store the current TX power into the dbm variable;
* return 0 if successful
*
* @set_wds_peer: set the WDS peer for a WDS interface
*
-@@ -3268,6 +3269,7 @@ struct cfg80211_ops {
+@@ -3325,6 +3326,7 @@ struct cfg80211_ops {
enum nl80211_tx_power_setting type, int mbm);
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
int *dbm);
const u8 *addr);
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -1395,6 +1395,7 @@ enum ieee80211_smps_mode {
+@@ -1428,6 +1428,7 @@ enum ieee80211_smps_mode {
*
* @power_level: requested transmit power (in dBm), backward compatibility
* value only that is set to the minimum of all interfaces
*
* @chandef: the channel definition to tune to
* @radar_enabled: whether radar detection is enabled
-@@ -1415,6 +1416,7 @@ enum ieee80211_smps_mode {
+@@ -1448,6 +1449,7 @@ enum ieee80211_smps_mode {
struct ieee80211_conf {
u32 flags;
int power_level, dynamic_ps_timeout;
u8 ps_dtim_period;
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
-@@ -2244,6 +2244,9 @@ enum nl80211_commands {
+@@ -2257,6 +2257,9 @@ enum nl80211_commands {
* @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime
* scheduler.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
-@@ -2693,6 +2696,8 @@ enum nl80211_attrs {
+@@ -2708,6 +2711,8 @@ enum nl80211_attrs {
NL80211_ATTR_AIRTIME_WEIGHT,
__NL80211_ATTR_AFTER_LAST,
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -2505,6 +2505,19 @@ static int ieee80211_get_tx_power(struct
+@@ -2521,6 +2521,19 @@ static int ieee80211_get_tx_power(struct
return 0;
}
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
const u8 *addr)
{
-@@ -3872,6 +3885,7 @@ const struct cfg80211_ops mac80211_confi
+@@ -3914,6 +3927,7 @@ const struct cfg80211_ops mac80211_confi
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
-@@ -1365,6 +1365,7 @@ struct ieee80211_local {
+@@ -1369,6 +1369,7 @@ struct ieee80211_local {
int dynamic_ps_forced_timeout;
int user_power_level; /* in dBm, for all interfaces */
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
-@@ -94,7 +94,7 @@ static u32 ieee80211_hw_conf_chan(struct
+@@ -95,7 +95,7 @@ static u32 ieee80211_hw_conf_chan(struct
struct ieee80211_sub_if_data *sdata;
struct cfg80211_chan_def chandef = {};
u32 changed = 0;
u32 offchannel_flag;
offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
-@@ -151,6 +151,12 @@ static u32 ieee80211_hw_conf_chan(struct
+@@ -152,6 +152,12 @@ static u32 ieee80211_hw_conf_chan(struct
}
rcu_read_unlock();
if (local->hw.conf.power_level != power) {
changed |= IEEE80211_CONF_CHANGE_POWER;
local->hw.conf.power_level = power;
-@@ -626,6 +632,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
+@@ -639,6 +645,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
IEEE80211_RADIOTAP_MCS_HAVE_BW;
local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI |
IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
-@@ -431,6 +431,7 @@ static const struct nla_policy nl80211_p
- [NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY,
- .len = NL80211_HE_MAX_CAPABILITY_LEN },
+@@ -498,6 +498,7 @@ static const struct nla_policy nl80211_p
+ .validation_data = nl80211_ftm_responder_policy,
+ },
[NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
};
/* policy for the key attributes */
-@@ -2588,6 +2589,20 @@ static int nl80211_set_wiphy(struct sk_b
+@@ -2636,6 +2637,20 @@ static int nl80211_set_wiphy(struct sk_b
if (result)
return result;
}