mac80211: fix spurious disconnections with powersave clients

This commit is contained in:
coolsnowwolf 2018-11-14 15:52:08 +08:00
parent 174d5713ee
commit 66d0992cde
27 changed files with 1549 additions and 18 deletions

View File

@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=mac80211
PKG_VERSION:=4.19-rc5-1
PKG_RELEASE:=2
PKG_RELEASE:=1
PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v4.19-rc5/
PKG_HASH:=5b61e64ea79d22bbac9e8612d5d5485974f223de00d4ec250b0faf4b7baf9957
@ -208,7 +208,7 @@ endef
define KernelPackage/hermes-pcmcia
$(call KernelPackage/mac80211/Default)
TITLE:=Hermes based PCMCIA adaptors
DEPENDS:=@PCMCIA_SUPPORT +kmod-hermes
DEPENDS:=@PCMCIA_SUPPORT +kmod-hermes +kmod-pcmcia-core
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/intersil/orinoco/orinoco_cs.ko
AUTOLOAD:=$(call AutoProbe,orinoco_cs)
endef

View File

@ -0,0 +1,27 @@
From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
Date: Fri, 2 Nov 2018 21:49:55 +0100
Subject: [PATCH] ath9k: dynack: use authentication messages for 'late' ack
In order to properly support dynack in ad-hoc mode running
wpa_supplicant, take into account authentication frames for
'late ack' detection. This patch has been tested on devices
mounted on offshore high-voltage stations connected through
~24Km link
Reported-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
Tested-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
--- a/drivers/net/wireless/ath/ath9k/dynack.c
+++ b/drivers/net/wireless/ath/ath9k/dynack.c
@@ -187,7 +187,8 @@ void ath_dynack_sample_tx_ts(struct ath_
/* late ACK */
if (ts->ts_status & ATH9K_TXERR_XRETRY) {
if (ieee80211_is_assoc_req(hdr->frame_control) ||
- ieee80211_is_assoc_resp(hdr->frame_control)) {
+ ieee80211_is_assoc_resp(hdr->frame_control) ||
+ ieee80211_is_auth(hdr->frame_control)) {
ath_dbg(common, DYNACK, "late ack\n");
ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2);
ath9k_hw_set_ack_timeout(ah, LATEACK_TO);

View File

@ -0,0 +1,88 @@
From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
Date: Fri, 2 Nov 2018 21:49:56 +0100
Subject: [PATCH] ath9k: dynack: move debug log after buffer increments
Move debug log in ath_dynack_sample_tx_ts and ath_dynack_sample_ack_ts
after timestamp buffer head/tail increments in order to make debugging
more user friendly
Tested-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
--- a/drivers/net/wireless/ath/ath9k/dynack.c
+++ b/drivers/net/wireless/ath/ath9k/dynack.c
@@ -171,11 +171,12 @@ static void ath_dynack_compute_to(struct
void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
struct ath_tx_status *ts)
{
- u8 ridx;
struct ieee80211_hdr *hdr;
struct ath_dynack *da = &ah->dynack;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ u32 dur = ts->duration;
+ u8 ridx;
if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !da->enabled)
return;
@@ -203,14 +204,13 @@ void ath_dynack_sample_tx_ts(struct ath_
ridx = ts->ts_rateindex;
da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp;
- da->st_rbf.ts[da->st_rbf.t_rb].dur = ts->duration;
ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1);
ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2);
if (!(info->status.rates[ridx].flags & IEEE80211_TX_RC_MCS)) {
- u32 phy, sifs;
const struct ieee80211_rate *rate;
struct ieee80211_tx_rate *rates = info->status.rates;
+ u32 phy;
rate = &common->sbands[info->band].bitrates[rates[ridx].idx];
if (info->band == NL80211_BAND_2GHZ &&
@@ -219,19 +219,18 @@ void ath_dynack_sample_tx_ts(struct ath_
else
phy = WLAN_RC_PHY_OFDM;
- sifs = ath_dynack_get_sifs(ah, phy);
- da->st_rbf.ts[da->st_rbf.t_rb].dur -= sifs;
+ dur -= ath_dynack_get_sifs(ah, phy);
}
-
- ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n",
- hdr->addr1, da->st_rbf.ts[da->st_rbf.t_rb].tstamp,
- da->st_rbf.ts[da->st_rbf.t_rb].dur, da->st_rbf.h_rb,
- (da->st_rbf.t_rb + 1) % ATH_DYN_BUF);
+ da->st_rbf.ts[da->st_rbf.t_rb].dur = dur;
INCR(da->st_rbf.t_rb, ATH_DYN_BUF);
if (da->st_rbf.t_rb == da->st_rbf.h_rb)
INCR(da->st_rbf.h_rb, ATH_DYN_BUF);
+ ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n",
+ hdr->addr1, ts->ts_tstamp, dur, da->st_rbf.h_rb,
+ da->st_rbf.t_rb);
+
ath_dynack_compute_to(ah);
spin_unlock_bh(&da->qlock);
@@ -258,14 +257,13 @@ void ath_dynack_sample_ack_ts(struct ath
spin_lock_bh(&da->qlock);
da->ack_rbf.tstamp[da->ack_rbf.t_rb] = ts;
- ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n",
- da->ack_rbf.tstamp[da->ack_rbf.t_rb],
- da->ack_rbf.h_rb, (da->ack_rbf.t_rb + 1) % ATH_DYN_BUF);
-
INCR(da->ack_rbf.t_rb, ATH_DYN_BUF);
if (da->ack_rbf.t_rb == da->ack_rbf.h_rb)
INCR(da->ack_rbf.h_rb, ATH_DYN_BUF);
+ ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n",
+ ts, da->ack_rbf.h_rb, da->ack_rbf.t_rb);
+
ath_dynack_compute_to(ah);
spin_unlock_bh(&da->qlock);

View File

@ -0,0 +1,33 @@
From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
Date: Fri, 2 Nov 2018 21:49:57 +0100
Subject: [PATCH] ath9k: dynack: check da->enabled first in sampling
routines
Check da->enabled flag first in ath_dynack_sample_tx_ts and
ath_dynack_sample_ack_ts routines in order to avoid useless
processing
Tested-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
--- a/drivers/net/wireless/ath/ath9k/dynack.c
+++ b/drivers/net/wireless/ath/ath9k/dynack.c
@@ -178,7 +178,7 @@ void ath_dynack_sample_tx_ts(struct ath_
u32 dur = ts->duration;
u8 ridx;
- if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !da->enabled)
+ if (!da->enabled || (info->flags & IEEE80211_TX_CTL_NO_ACK))
return;
spin_lock_bh(&da->qlock);
@@ -251,7 +251,7 @@ void ath_dynack_sample_ack_ts(struct ath
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- if (!ath_dynack_bssidmask(ah, hdr->addr1) || !da->enabled)
+ if (!da->enabled || !ath_dynack_bssidmask(ah, hdr->addr1))
return;
spin_lock_bh(&da->qlock);

View File

@ -0,0 +1,139 @@
From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
Date: Fri, 2 Nov 2018 21:49:58 +0100
Subject: [PATCH] ath9k: dynack: make ewma estimation faster
In order to make propagation time estimation faster,
use current sample as ewma output value during 'late ack'
tracking
Tested-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -274,7 +274,7 @@ struct ath_node {
#endif
u8 key_idx[4];
- u32 ackto;
+ int ackto;
struct list_head list;
};
--- a/drivers/net/wireless/ath/ath9k/dynack.c
+++ b/drivers/net/wireless/ath/ath9k/dynack.c
@@ -29,9 +29,13 @@
* ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation
*
*/
-static inline u32 ath_dynack_ewma(u32 old, u32 new)
+static inline int ath_dynack_ewma(int old, int new)
{
- return (new * (EWMA_DIV - EWMA_LEVEL) + old * EWMA_LEVEL) / EWMA_DIV;
+ if (old > 0)
+ return (new * (EWMA_DIV - EWMA_LEVEL) +
+ old * EWMA_LEVEL) / EWMA_DIV;
+ else
+ return new;
}
/**
@@ -82,10 +86,10 @@ static inline bool ath_dynack_bssidmask(
*/
static void ath_dynack_compute_ackto(struct ath_hw *ah)
{
- struct ath_node *an;
- u32 to = 0;
- struct ath_dynack *da = &ah->dynack;
struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_dynack *da = &ah->dynack;
+ struct ath_node *an;
+ int to = 0;
list_for_each_entry(an, &da->nodes, list)
if (an->ackto > to)
@@ -144,7 +148,8 @@ static void ath_dynack_compute_to(struct
an->ackto = ath_dynack_ewma(an->ackto,
ackto);
ath_dbg(ath9k_hw_common(ah), DYNACK,
- "%pM to %u\n", dst, an->ackto);
+ "%pM to %d [%u]\n", dst,
+ an->ackto, ackto);
if (time_is_before_jiffies(da->lto)) {
ath_dynack_compute_ackto(ah);
da->lto = jiffies + COMPUTE_TO;
@@ -166,10 +171,12 @@ static void ath_dynack_compute_to(struct
* @ah: ath hw
* @skb: socket buffer
* @ts: tx status info
+ * @sta: station pointer
*
*/
void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
- struct ath_tx_status *ts)
+ struct ath_tx_status *ts,
+ struct ieee80211_sta *sta)
{
struct ieee80211_hdr *hdr;
struct ath_dynack *da = &ah->dynack;
@@ -191,9 +198,16 @@ void ath_dynack_sample_tx_ts(struct ath_
ieee80211_is_assoc_resp(hdr->frame_control) ||
ieee80211_is_auth(hdr->frame_control)) {
ath_dbg(common, DYNACK, "late ack\n");
+
ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2);
ath9k_hw_set_ack_timeout(ah, LATEACK_TO);
ath9k_hw_set_cts_timeout(ah, LATEACK_TO);
+ if (sta) {
+ struct ath_node *an;
+
+ an = (struct ath_node *)sta->drv_priv;
+ an->ackto = -1;
+ }
da->lto = jiffies + LATEACK_DELAY;
}
--- a/drivers/net/wireless/ath/ath9k/dynack.h
+++ b/drivers/net/wireless/ath/ath9k/dynack.h
@@ -86,7 +86,8 @@ void ath_dynack_node_deinit(struct ath_h
void ath_dynack_init(struct ath_hw *ah);
void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, u32 ts);
void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
- struct ath_tx_status *ts);
+ struct ath_tx_status *ts,
+ struct ieee80211_sta *sta);
#else
static inline void ath_dynack_init(struct ath_hw *ah) {}
static inline void ath_dynack_node_init(struct ath_hw *ah,
@@ -97,7 +98,8 @@ static inline void ath_dynack_sample_ack
struct sk_buff *skb, u32 ts) {}
static inline void ath_dynack_sample_tx_ts(struct ath_hw *ah,
struct sk_buff *skb,
- struct ath_tx_status *ts) {}
+ struct ath_tx_status *ts,
+ struct ieee80211_sta *sta) {}
#endif
#endif /* DYNACK_H */
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -629,7 +629,7 @@ static void ath_tx_complete_aggr(struct
if (bf == bf->bf_lastbf)
ath_dynack_sample_tx_ts(sc->sc_ah,
bf->bf_mpdu,
- ts);
+ ts, sta);
}
ath_tx_complete_buf(sc, bf, txq, &bf_head, sta, ts,
@@ -773,7 +773,8 @@ static void ath_tx_process_buffer(struct
memcpy(info->control.rates, bf->rates,
sizeof(info->control.rates));
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
- ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts);
+ ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts,
+ sta);
}
ath_tx_complete_buf(sc, bf, txq, bf_head, sta, ts, txok);
} else

View File

@ -0,0 +1,22 @@
From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
Date: Fri, 2 Nov 2018 21:49:59 +0100
Subject: [PATCH] ath9k: dynack: remove 'experimental' tag
Remove experimental tag from dynack Kconfig entry since it has
been tested on outdoor 25Km links
Tested-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -132,7 +132,7 @@ config ATH9K_DFS_CERTIFIED
except increase code size.
config ATH9K_DYNACK
- bool "Atheros ath9k ACK timeout estimation algorithm (EXPERIMENTAL)"
+ bool "Atheros ath9k ACK timeout estimation algorithm"
depends on ATH9K
default n
---help---

View File

@ -0,0 +1,57 @@
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
@@ -1463,7 +1463,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;
@@ -1597,7 +1597,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 */
@@ -3405,7 +3404,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;
@@ -3448,7 +3446,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) {

View File

@ -0,0 +1,67 @@
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,

View File

@ -0,0 +1,79 @@
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);

View File

@ -0,0 +1,41 @@
From 3401d42c7ea2d064d15c66698ff8eb96553179ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Fri, 26 Oct 2018 12:50:39 +0200
Subject: [PATCH] brcmutil: really fix decoding channel info for 160 MHz
bandwidth
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Previous commit /adding/ support for 160 MHz chanspecs was incomplete.
It didn't set bandwidth info and didn't extract control channel info. As
the result it was also using uninitialized "sb" var.
This change has been tested for two chanspecs found to be reported by
some devices/firmwares:
1) 60/160 (0xee32)
Before: chnum:50 control_ch_num:36
After: chnum:50 control_ch_num:60
2) 120/160 (0xed72)
Before: chnum:114 control_ch_num:100
After: chnum:114 control_ch_num:120
Fixes: 330994e8e8ec ("brcmfmac: fix for proper support of 160MHz bandwidth")
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c
@@ -193,6 +193,9 @@ static void brcmu_d11ac_decchspec(struct
}
break;
case BRCMU_CHSPEC_D11AC_BW_160:
+ ch->bw = BRCMU_CHAN_BW_160;
+ ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
+ BRCMU_CHSPEC_D11AC_SB_SHIFT);
switch (ch->sb) {
case BRCMU_CHAN_SB_LLL:
ch->control_ch_num -= CH_70MHZ_APART;

View File

@ -0,0 +1,102 @@
From a1a3b762163868ad07a4499a73df324f40d5ab0b Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 10 Oct 2018 13:00:58 +0200
Subject: [PATCH] brcmfmac: Remove firmware-loading code duplication
brcmf_fw_request_next_item and brcmf_fw_request_done both have identical
code to complete the fw-request depending on the item-type.
This commit adds a new brcmf_fw_complete_request helper removing this code
duplication.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../broadcom/brcm80211/brcmfmac/firmware.c | 62 +++++++++++-----------
1 file changed, 31 insertions(+), 31 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -504,6 +504,34 @@ fail:
return -ENOENT;
}
+static int brcmf_fw_complete_request(const struct firmware *fw,
+ struct brcmf_fw *fwctx)
+{
+ struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos];
+ int ret = 0;
+
+ brcmf_dbg(TRACE, "firmware %s %sfound\n", cur->path, fw ? "" : "not ");
+
+ switch (cur->type) {
+ case BRCMF_FW_TYPE_NVRAM:
+ ret = brcmf_fw_request_nvram_done(fw, fwctx);
+ break;
+ case BRCMF_FW_TYPE_BINARY:
+ if (fw)
+ cur->binary = fw;
+ else
+ ret = -ENOENT;
+ break;
+ default:
+ /* something fishy here so bail out early */
+ brcmf_err("unknown fw type: %d\n", cur->type);
+ release_firmware(fw);
+ ret = -EINVAL;
+ }
+
+ return (cur->flags & BRCMF_FW_REQF_OPTIONAL) ? 0 : ret;
+}
+
static int brcmf_fw_request_next_item(struct brcmf_fw *fwctx, bool async)
{
struct brcmf_fw_item *cur;
@@ -525,15 +553,7 @@ static int brcmf_fw_request_next_item(st
if (ret < 0) {
brcmf_fw_request_done(NULL, fwctx);
} else if (!async && fw) {
- brcmf_dbg(TRACE, "firmware %s %sfound\n", cur->path,
- fw ? "" : "not ");
- if (cur->type == BRCMF_FW_TYPE_BINARY)
- cur->binary = fw;
- else if (cur->type == BRCMF_FW_TYPE_NVRAM)
- brcmf_fw_request_nvram_done(fw, fwctx);
- else
- release_firmware(fw);
-
+ brcmf_fw_complete_request(fw, fwctx);
return -EAGAIN;
}
return 0;
@@ -547,28 +567,8 @@ static void brcmf_fw_request_done(const
cur = &fwctx->req->items[fwctx->curpos];
- brcmf_dbg(TRACE, "enter: firmware %s %sfound\n", cur->path,
- fw ? "" : "not ");
-
- if (!fw)
- ret = -ENOENT;
-
- switch (cur->type) {
- case BRCMF_FW_TYPE_NVRAM:
- ret = brcmf_fw_request_nvram_done(fw, fwctx);
- break;
- case BRCMF_FW_TYPE_BINARY:
- cur->binary = fw;
- break;
- default:
- /* something fishy here so bail out early */
- brcmf_err("unknown fw type: %d\n", cur->type);
- release_firmware(fw);
- ret = -EINVAL;
- goto fail;
- }
-
- if (ret < 0 && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
+ ret = brcmf_fw_complete_request(fw, fwctx);
+ if (ret < 0)
goto fail;
do {

View File

@ -0,0 +1,126 @@
From 5b587496dc63595b71265d986ce69728c2724370 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 10 Oct 2018 13:00:59 +0200
Subject: [PATCH] brcmfmac: Remove recursion from firmware load error handling
Before this commit brcmf_fw_request_done would call
brcmf_fw_request_next_item to load the next item, which on an error would
call brcmf_fw_request_done, which if the error is recoverable (*) will
then continue calling brcmf_fw_request_next_item for the next item again
which on an error will call brcmf_fw_request_done again...
This does not blow up because we only have a limited number of items so
we never recurse too deep. But the recursion is still quite ugly and
frankly is giving me a headache, so lets fix this.
This commit fixes this by removing brcmf_fw_request_next_item and by
making brcmf_fw_get_firmwares and brcmf_fw_request_done directly call
firmware_request_nowait resp. firmware_request themselves.
*) brcmf_fw_request_nvram_done fallback path succeeds or
BRCMF_FW_REQF_OPTIONAL is set
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../broadcom/brcm80211/brcmfmac/firmware.c | 65 +++++++---------------
1 file changed, 19 insertions(+), 46 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -532,33 +532,6 @@ static int brcmf_fw_complete_request(con
return (cur->flags & BRCMF_FW_REQF_OPTIONAL) ? 0 : ret;
}
-static int brcmf_fw_request_next_item(struct brcmf_fw *fwctx, bool async)
-{
- struct brcmf_fw_item *cur;
- const struct firmware *fw = NULL;
- int ret;
-
- cur = &fwctx->req->items[fwctx->curpos];
-
- brcmf_dbg(TRACE, "%srequest for %s\n", async ? "async " : "",
- cur->path);
-
- if (async)
- ret = request_firmware_nowait(THIS_MODULE, true, cur->path,
- fwctx->dev, GFP_KERNEL, fwctx,
- brcmf_fw_request_done);
- else
- ret = request_firmware(&fw, cur->path, fwctx->dev);
-
- if (ret < 0) {
- brcmf_fw_request_done(NULL, fwctx);
- } else if (!async && fw) {
- brcmf_fw_complete_request(fw, fwctx);
- return -EAGAIN;
- }
- return 0;
-}
-
static void brcmf_fw_request_done(const struct firmware *fw, void *ctx)
{
struct brcmf_fw *fwctx = ctx;
@@ -568,26 +541,19 @@ static void brcmf_fw_request_done(const
cur = &fwctx->req->items[fwctx->curpos];
ret = brcmf_fw_complete_request(fw, fwctx);
- if (ret < 0)
- goto fail;
-
- do {
- if (++fwctx->curpos == fwctx->req->n_items) {
- ret = 0;
- goto done;
- }
- ret = brcmf_fw_request_next_item(fwctx, false);
- } while (ret == -EAGAIN);
-
- return;
+ while (ret == 0 && ++fwctx->curpos < fwctx->req->n_items) {
+ cur = &fwctx->req->items[fwctx->curpos];
+ request_firmware(&fw, cur->path, fwctx->dev);
+ ret = brcmf_fw_complete_request(fw, ctx);
+ }
-fail:
- brcmf_dbg(TRACE, "failed err=%d: dev=%s, fw=%s\n", ret,
- dev_name(fwctx->dev), cur->path);
- brcmf_fw_free_request(fwctx->req);
- fwctx->req = NULL;
-done:
+ if (ret) {
+ brcmf_dbg(TRACE, "failed err=%d: dev=%s, fw=%s\n", ret,
+ dev_name(fwctx->dev), cur->path);
+ brcmf_fw_free_request(fwctx->req);
+ fwctx->req = NULL;
+ }
fwctx->done(fwctx->dev, ret, fwctx->req);
kfree(fwctx);
}
@@ -611,7 +577,9 @@ int brcmf_fw_get_firmwares(struct device
void (*fw_cb)(struct device *dev, int err,
struct brcmf_fw_request *req))
{
+ struct brcmf_fw_item *first = &req->items[0];
struct brcmf_fw *fwctx;
+ int ret;
brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
if (!fw_cb)
@@ -628,7 +596,12 @@ int brcmf_fw_get_firmwares(struct device
fwctx->req = req;
fwctx->done = fw_cb;
- brcmf_fw_request_next_item(fwctx, true);
+ ret = request_firmware_nowait(THIS_MODULE, true, first->path,
+ fwctx->dev, GFP_KERNEL, fwctx,
+ brcmf_fw_request_done);
+ if (ret < 0)
+ brcmf_fw_request_done(NULL, fwctx);
+
return 0;
}

View File

@ -0,0 +1,77 @@
From eae8e50669e15002b195177212a6e25afbe7cf4d Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 10 Oct 2018 13:01:00 +0200
Subject: [PATCH] brcmfmac: Add support for first trying to get a board
specific nvram file
The nvram files which some brcmfmac chips need are board-specific. To be
able to distribute these as part of linux-firmware, so that devices with
such a wifi chip will work OOTB, multiple (one per board) versions must
co-exist under /lib/firmware.
This commit adds support for callers of the brcmfmac/firmware.c code to
pass in a board_type parameter through the request structure.
If that parameter is set then the code will first try to load
chipmodel.board_type.txt before falling back to the old chipmodel.txt name.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../broadcom/brcm80211/brcmfmac/firmware.c | 27 +++++++++++++++++++++-
.../broadcom/brcm80211/brcmfmac/firmware.h | 1 +
2 files changed, 27 insertions(+), 1 deletion(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -532,6 +532,31 @@ static int brcmf_fw_complete_request(con
return (cur->flags & BRCMF_FW_REQF_OPTIONAL) ? 0 : ret;
}
+static int brcmf_fw_request_firmware(const struct firmware **fw,
+ struct brcmf_fw *fwctx)
+{
+ struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos];
+ int ret;
+
+ /* nvram files are board-specific, first try a board-specific path */
+ if (cur->type == BRCMF_FW_TYPE_NVRAM && fwctx->req->board_type) {
+ char alt_path[BRCMF_FW_NAME_LEN];
+
+ strlcpy(alt_path, cur->path, BRCMF_FW_NAME_LEN);
+ /* strip .txt at the end */
+ alt_path[strlen(alt_path) - 4] = 0;
+ strlcat(alt_path, ".", BRCMF_FW_NAME_LEN);
+ strlcat(alt_path, fwctx->req->board_type, BRCMF_FW_NAME_LEN);
+ strlcat(alt_path, ".txt", BRCMF_FW_NAME_LEN);
+
+ ret = request_firmware(fw, alt_path, fwctx->dev);
+ if (ret == 0)
+ return ret;
+ }
+
+ return request_firmware(fw, cur->path, fwctx->dev);
+}
+
static void brcmf_fw_request_done(const struct firmware *fw, void *ctx)
{
struct brcmf_fw *fwctx = ctx;
@@ -544,7 +569,7 @@ static void brcmf_fw_request_done(const
while (ret == 0 && ++fwctx->curpos < fwctx->req->n_items) {
cur = &fwctx->req->items[fwctx->curpos];
- request_firmware(&fw, cur->path, fwctx->dev);
+ brcmf_fw_request_firmware(&fw, fwctx);
ret = brcmf_fw_complete_request(fw, ctx);
}
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
@@ -70,6 +70,7 @@ struct brcmf_fw_request {
u16 domain_nr;
u16 bus_nr;
u32 n_items;
+ const char *board_type;
struct brcmf_fw_item items[0];
};

View File

@ -0,0 +1,77 @@
From 0ad4b55b2f29784f93875e6231bf57cd233624a2 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 10 Oct 2018 13:01:01 +0200
Subject: [PATCH] brcmfmac: Set board_type used for nvram file selection to
machine-compatible
For of/devicetree using machines, set the board_type used for nvram file
selection to the first string listed in the top-level's node compatible
string, aka the machine-compatible as used by of_machine_is_compatible().
The board_type setting is used to load the board-specific nvram file with
a board-specific name so that we can ship files for each supported board
in linux-firmware.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h | 1 +
drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c | 11 ++++++++++-
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 1 +
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 1 +
4 files changed, 13 insertions(+), 1 deletion(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
@@ -59,6 +59,7 @@ struct brcmf_mp_device {
bool iapp;
bool ignore_probe_fail;
struct brcmfmac_pd_cc *country_codes;
+ const char *board_type;
union {
struct brcmfmac_sdio_pd sdio;
} bus;
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
@@ -27,11 +27,20 @@ void brcmf_of_probe(struct device *dev,
struct brcmf_mp_device *settings)
{
struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio;
- struct device_node *np = dev->of_node;
+ struct device_node *root, *np = dev->of_node;
+ struct property *prop;
int irq;
u32 irqf;
u32 val;
+ /* Set board-type to the first string of the machine compatible prop */
+ root = of_find_node_by_path("/");
+ if (root) {
+ prop = of_find_property(root, "compatible", NULL);
+ settings->board_type = of_prop_next_string(prop, NULL);
+ of_node_put(root);
+ }
+
if (!np || bus_type != BRCMF_BUSTYPE_SDIO ||
!of_device_is_compatible(np, "brcm,bcm4329-fmac"))
return;
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -1785,6 +1785,7 @@ brcmf_pcie_prepare_fw_request(struct brc
fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
+ fwreq->board_type = devinfo->settings->board_type;
/* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */
fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1;
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
@@ -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;
+ fwreq->board_type = bus->sdiodev->settings->board_type;
return fwreq;
}

View File

@ -0,0 +1,179 @@
From bd1e82bb420adf4ad7cd468d8a482cde622dd69d Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 10 Oct 2018 13:01:02 +0200
Subject: [PATCH] brcmfmac: Set board_type from DMI on x86 based machines
For x86 based machines, set the board_type used for nvram file selection
based on the DMI sys-vendor and product-name strings.
Since on some models these strings are too generic, this commit also adds
a quirk table overriding the strings for models listed in that table.
The board_type setting is used to load the board-specific nvram file with
a board-specific name so that we can ship files for each supported board
in linux-firmware.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../wireless/broadcom/brcm80211/brcmfmac/Makefile | 2 +
.../wireless/broadcom/brcm80211/brcmfmac/common.c | 3 +-
.../wireless/broadcom/brcm80211/brcmfmac/common.h | 7 ++
.../net/wireless/broadcom/brcm80211/brcmfmac/dmi.c | 116 +++++++++++++++++++++
4 files changed, 127 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
@@ -54,3 +54,5 @@ brcmfmac-$(CPTCFG_BRCM_TRACING) += \
tracepoint.o
brcmfmac-$(CONFIG_OF) += \
of.o
+brcmfmac-$(CONFIG_DMI) += \
+ dmi.o
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -448,8 +448,9 @@ struct brcmf_mp_device *brcmf_get_module
}
}
if (!found) {
- /* No platform data for this device, try OF (Open Firwmare) */
+ /* No platform data for this device, try OF and DMI data */
brcmf_of_probe(dev, bus_type, settings);
+ brcmf_dmi_probe(settings, chip, chiprev);
}
return settings;
}
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
@@ -75,4 +75,11 @@ void brcmf_release_module_param(struct b
/* Sets dongle media info (drv_version, mac address). */
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
+#ifdef CONFIG_DMI
+void brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev);
+#else
+static inline void
+brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev) {}
+#endif
+
#endif /* BRCMFMAC_COMMON_H */
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2018 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/dmi.h>
+#include <linux/mod_devicetable.h>
+#include "core.h"
+#include "common.h"
+#include "brcm_hw_ids.h"
+
+/* The DMI data never changes so we can use a static buf for this */
+static char dmi_board_type[128];
+
+struct brcmf_dmi_data {
+ u32 chip;
+ u32 chiprev;
+ const char *board_type;
+};
+
+/* NOTE: Please keep all entries sorted alphabetically */
+
+static const struct brcmf_dmi_data gpd_win_pocket_data = {
+ BRCM_CC_4356_CHIP_ID, 2, "gpd-win-pocket"
+};
+
+static const struct brcmf_dmi_data jumper_ezpad_mini3_data = {
+ BRCM_CC_43430_CHIP_ID, 0, "jumper-ezpad-mini3"
+};
+
+static const struct brcmf_dmi_data meegopad_t08_data = {
+ BRCM_CC_43340_CHIP_ID, 2, "meegopad-t08"
+};
+
+static const struct dmi_system_id dmi_platform_data[] = {
+ {
+ /* Match for the GPDwin which unfortunately uses somewhat
+ * generic dmi strings, which is why we test for 4 strings.
+ * Comparing against 23 other byt/cht boards, board_vendor
+ * and board_name are unique to the GPDwin, where as only one
+ * other board has the same board_serial and 3 others have
+ * the same default product_name. Also the GPDwin is the
+ * only device to have both board_ and product_name not set.
+ */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "Default string"),
+ DMI_MATCH(DMI_BOARD_SERIAL, "Default string"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+ },
+ .driver_data = (void *)&gpd_win_pocket_data,
+ },
+ {
+ /* Jumper EZpad mini3 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CherryTrail"),
+ /* jumperx.T87.KFBNEEA02 with the version-nr dropped */
+ DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"),
+ },
+ .driver_data = (void *)&jumper_ezpad_mini3_data,
+ },
+ {
+ /* Meegopad T08 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Default string"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+ DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
+ DMI_MATCH(DMI_BOARD_VERSION, "V1.1"),
+ },
+ .driver_data = (void *)&meegopad_t08_data,
+ },
+ {}
+};
+
+void brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev)
+{
+ const struct dmi_system_id *match;
+ const struct brcmf_dmi_data *data;
+ const char *sys_vendor;
+ const char *product_name;
+
+ /* Some models have DMI strings which are too generic, e.g.
+ * "Default string", we use a quirk table for these.
+ */
+ for (match = dmi_first_match(dmi_platform_data);
+ match;
+ match = dmi_first_match(match + 1)) {
+ data = match->driver_data;
+
+ if (data->chip == chip && data->chiprev == chiprev) {
+ settings->board_type = data->board_type;
+ return;
+ }
+ }
+
+ /* Not found in the quirk-table, use sys_vendor-product_name */
+ sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+ product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
+ if (sys_vendor && product_name) {
+ snprintf(dmi_board_type, sizeof(dmi_board_type), "%s-%s",
+ sys_vendor, product_name);
+ settings->board_type = dmi_board_type;
+ }
+}

View File

@ -0,0 +1,41 @@
From 55e491edbf14b2da5419c2a319ea3b1d6368d9a2 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 10 Oct 2018 13:01:03 +0200
Subject: [PATCH] brcmfmac: Cleanup brcmf_fw_request_done()
The "cur" variable is now only used for a debug print and we already
print the same info from brcmf_fw_complete_request(), so the debug print
does not provide any extra info and we can remove it.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -560,22 +560,16 @@ static int brcmf_fw_request_firmware(con
static void brcmf_fw_request_done(const struct firmware *fw, void *ctx)
{
struct brcmf_fw *fwctx = ctx;
- struct brcmf_fw_item *cur;
- int ret = 0;
-
- cur = &fwctx->req->items[fwctx->curpos];
+ int ret;
ret = brcmf_fw_complete_request(fw, fwctx);
while (ret == 0 && ++fwctx->curpos < fwctx->req->n_items) {
- cur = &fwctx->req->items[fwctx->curpos];
brcmf_fw_request_firmware(&fw, fwctx);
ret = brcmf_fw_complete_request(fw, ctx);
}
if (ret) {
- brcmf_dbg(TRACE, "failed err=%d: dev=%s, fw=%s\n", ret,
- dev_name(fwctx->dev), cur->path);
brcmf_fw_free_request(fwctx->req);
fwctx->req = NULL;
}

View File

@ -0,0 +1,132 @@
From ce2e6db554fad444fa0b3904fc3015336e0ef765 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Thu, 11 Oct 2018 11:51:06 +0200
Subject: [PATCH] brcmfmac: Add support for getting nvram contents from EFI
variables
Various X86 laptops with a SDIO attached brcmfmac wifi chip, store the
nvram contents in a special EFI variable. This commit adds support for
getting nvram directly from this EFI variable, without the user needing
to manually copy it.
This makes Wifi / Bluetooth work out of the box on these devices instead of
requiring manual setup.
This has been tested on the following models: Acer Iconia Tab8 w1-810,
Acer One 10, Asus T100CHI, Asus T100HA, Asus T100TA, Asus T200TA and a
Lenovo Mixx 2 8.
Tested-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../broadcom/brcm80211/brcmfmac/firmware.c | 63 +++++++++++++++++++---
1 file changed, 57 insertions(+), 6 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -14,6 +14,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/efi.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/device.h>
@@ -445,6 +446,51 @@ struct brcmf_fw {
static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
+#ifdef CONFIG_EFI
+static u8 *brcmf_fw_nvram_from_efi(size_t *data_len_ret)
+{
+ const u16 name[] = { 'n', 'v', 'r', 'a', 'm', 0 };
+ struct efivar_entry *nvram_efivar;
+ unsigned long data_len = 0;
+ u8 *data = NULL;
+ int err;
+
+ nvram_efivar = kzalloc(sizeof(*nvram_efivar), GFP_KERNEL);
+ if (!nvram_efivar)
+ return NULL;
+
+ memcpy(&nvram_efivar->var.VariableName, name, sizeof(name));
+ nvram_efivar->var.VendorGuid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61,
+ 0xb5, 0x1f, 0x43, 0x26,
+ 0x81, 0x23, 0xd1, 0x13);
+
+ err = efivar_entry_size(nvram_efivar, &data_len);
+ if (err)
+ goto fail;
+
+ data = kmalloc(data_len, GFP_KERNEL);
+ if (!data)
+ goto fail;
+
+ err = efivar_entry_get(nvram_efivar, NULL, &data_len, data);
+ if (err)
+ goto fail;
+
+ brcmf_info("Using nvram EFI variable\n");
+
+ kfree(nvram_efivar);
+ *data_len_ret = data_len;
+ return data;
+
+fail:
+ kfree(data);
+ kfree(nvram_efivar);
+ return NULL;
+}
+#else
+static u8 *brcmf_fw_nvram_from_efi(size_t *data_len) { return NULL; }
+#endif
+
static void brcmf_fw_free_request(struct brcmf_fw_request *req)
{
struct brcmf_fw_item *item;
@@ -463,11 +509,12 @@ static int brcmf_fw_request_nvram_done(c
{
struct brcmf_fw *fwctx = ctx;
struct brcmf_fw_item *cur;
+ bool free_bcm47xx_nvram = false;
+ bool kfree_nvram = false;
u32 nvram_length = 0;
void *nvram = NULL;
u8 *data = NULL;
size_t data_len;
- bool raw_nvram;
brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
@@ -476,12 +523,13 @@ static int brcmf_fw_request_nvram_done(c
if (fw && fw->data) {
data = (u8 *)fw->data;
data_len = fw->size;
- raw_nvram = false;
} else {
- data = bcm47xx_nvram_get_contents(&data_len);
- if (!data && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
+ if ((data = bcm47xx_nvram_get_contents(&data_len)))
+ free_bcm47xx_nvram = true;
+ else if ((data = brcmf_fw_nvram_from_efi(&data_len)))
+ kfree_nvram = true;
+ else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL))
goto fail;
- raw_nvram = true;
}
if (data)
@@ -489,8 +537,11 @@ static int brcmf_fw_request_nvram_done(c
fwctx->req->domain_nr,
fwctx->req->bus_nr);
- if (raw_nvram)
+ if (free_bcm47xx_nvram)
bcm47xx_nvram_release_contents(data);
+ if (kfree_nvram)
+ kfree(data);
+
release_firmware(fw);
if (!nvram && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
goto fail;

View File

@ -0,0 +1,97 @@
From 29ec3394f0bd85c22674ab6693d92da5e2324610 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Thu, 11 Oct 2018 11:51:07 +0200
Subject: [PATCH] brcmfmac: Fix ccode from EFI nvram when necessary
In some cases the EFI-var stored nvram contains "ccode=ALL" or "ccode=XV"
to specify "worldwide" compatible settings, but these 2 ccode-s do not work
properly.
I've tested the different known "worldwide" ccode-s used in various nvram
sources with the latest firmwares from linux-firmware for various brcmfmac
models, here is a simplified (*) table with what each setting results in:
ALL: 12-14 disab, U-NII-1, U-NII-2 no-IR/radar, U-NII-3
XV: 12-14 no-IR, disables all 5G channels
XY: 12-13 enab, 14 disab, U-NII-1 enab, U-NII-2 no-IR/radar, U-NII-3 disab
X2: 12-13 no-IR, 14 dis, U-NII-1 no-IR, U-NII-2 no-IR/radar, U-NII-3 no-IR
Where 12,13,14 are 2.4G channels 12-14 and U-NII-1/2/3 are the 3 different
5G channel groups. no-IR is no-Initiate-Radiation, we will never send on
these channels without first having received valid wifi traffic there.
This immediately shows that both ALL and XV are not as worldwide as we want
them to be. ALL causes channels 12 and 13 to not be available and XV causes
all 5GHz channels to not be available. Also ALL unconditionally enables the
U-NII-1 and U-NII-3 5G groups, while we really should be using no-IR for
these.
This commit replace XV and ALL with X2, which allows usage of chan 12-13
and 5G channels, but only after receiving valid wifi traffic there first.
Note that this configure the firmware's channel limits, the kernels own
regulatory restrictions based on e.g. regulatory info received from the
access-point, will be applied on top of this.
This fixes channels 12+13 not working on the Asus T200TA and the Lenovo
Mixx 2 8 and 5G channels not working on the Asus T100HA.
This has been tested on the following models: Acer Iconia Tab8 w1-810,
Acer One 10, Asus T100CHI, Asus T100HA, Asus T100TA, Asus T200TA and a
Lenovo Mixx 2 8.
*) There are some exceptions to this table:
1) On really old firmware e.g. linux-firmware's 2011 brcmfmac4330-sdio.bin
ALL really means all, unconditionally enabling everything
2) The exact meaning might be influenced by setting the regrev nvram var.
Specifically using ccode=XV + regrev=1 on brcmfmac43241b4 leads to:
12-14 no-ir, U-NII-1 no-ir, U-NII-2 no-ir/radar, U-NII-3 no-ir
But only on the brcmfmac43241b4 and not on e.g. the brcmfmac43340
Tested-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../broadcom/brcm80211/brcmfmac/firmware.c | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -447,6 +447,29 @@ struct brcmf_fw {
static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
#ifdef CONFIG_EFI
+/* In some cases the EFI-var stored nvram contains "ccode=ALL" or "ccode=XV"
+ * to specify "worldwide" compatible settings, but these 2 ccode-s do not work
+ * properly. "ccode=ALL" causes channels 12 and 13 to not be available,
+ * "ccode=XV" causes all 5GHz channels to not be available. So we replace both
+ * with "ccode=X2" which allows channels 12+13 and 5Ghz channels in
+ * no-Initiate-Radiation mode. This means that we will never send on these
+ * channels without first having received valid wifi traffic on the channel.
+ */
+static void brcmf_fw_fix_efi_nvram_ccode(char *data, unsigned long data_len)
+{
+ char *ccode;
+
+ ccode = strnstr((char *)data, "ccode=ALL", data_len);
+ if (!ccode)
+ ccode = strnstr((char *)data, "ccode=XV\r", data_len);
+ if (!ccode)
+ return;
+
+ ccode[6] = 'X';
+ ccode[7] = '2';
+ ccode[8] = '\r';
+}
+
static u8 *brcmf_fw_nvram_from_efi(size_t *data_len_ret)
{
const u16 name[] = { 'n', 'v', 'r', 'a', 'm', 0 };
@@ -476,6 +499,7 @@ static u8 *brcmf_fw_nvram_from_efi(size_
if (err)
goto fail;
+ brcmf_fw_fix_efi_nvram_ccode(data, data_len);
brcmf_info("Using nvram EFI variable\n");
kfree(nvram_efivar);

View File

@ -0,0 +1,34 @@
From e966a79c2f761a696dec9cfb0e2d4aa977bf78cb Mon Sep 17 00:00:00 2001
From: Colin Ian King <colin.king@canonical.com>
Date: Tue, 16 Oct 2018 18:43:42 +0100
Subject: [PATCH] brcmfmac: fix spelling mistake "Retreiving" -> "Retrieving"
Trivial fix to spelling mistake in brcmf_err error message.
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -214,7 +214,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_i
err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
sizeof(ifp->mac_addr));
if (err < 0) {
- brcmf_err("Retreiving cur_etheraddr failed, %d\n", err);
+ brcmf_err("Retrieving cur_etheraddr failed, %d\n", err);
goto done;
}
memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN);
@@ -269,7 +269,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_i
strcpy(buf, "ver");
err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
if (err < 0) {
- brcmf_err("Retreiving version information failed, %d\n",
+ brcmf_err("Retrieving version information failed, %d\n",
err);
goto done;
}

View File

@ -0,0 +1,83 @@
From ae5848cb4511bbbfe0306fcdbe5d9a95cd9546a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Fri, 26 Oct 2018 13:22:32 +0200
Subject: [PATCH] brcmutil: print invalid chanspec when WARN-ing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
On one of my devices I got WARNINGs when brcmfmac tried to decode
chanspec. I couldn't tell if it was some unsupported format or just a
malformed value passed by a firmware.
Print chanspec value so it's possible to debug a possible problem.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c
@@ -128,7 +128,7 @@ static void brcmu_d11n_decchspec(struct
}
break;
default:
- WARN_ON_ONCE(1);
+ WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
break;
}
@@ -140,7 +140,7 @@ static void brcmu_d11n_decchspec(struct
ch->band = BRCMU_CHAN_BAND_2G;
break;
default:
- WARN_ON_ONCE(1);
+ WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
break;
}
}
@@ -167,7 +167,7 @@ static void brcmu_d11ac_decchspec(struct
ch->sb = BRCMU_CHAN_SB_U;
ch->control_ch_num += CH_10MHZ_APART;
} else {
- WARN_ON_ONCE(1);
+ WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
}
break;
case BRCMU_CHSPEC_D11AC_BW_80:
@@ -188,7 +188,7 @@ static void brcmu_d11ac_decchspec(struct
ch->control_ch_num += CH_30MHZ_APART;
break;
default:
- WARN_ON_ONCE(1);
+ WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
break;
}
break;
@@ -222,13 +222,13 @@ static void brcmu_d11ac_decchspec(struct
ch->control_ch_num += CH_70MHZ_APART;
break;
default:
- WARN_ON_ONCE(1);
+ WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
break;
}
break;
case BRCMU_CHSPEC_D11AC_BW_8080:
default:
- WARN_ON_ONCE(1);
+ WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
break;
}
@@ -240,7 +240,7 @@ static void brcmu_d11ac_decchspec(struct
ch->band = BRCMU_CHAN_BAND_2G;
break;
default:
- WARN_ON_ONCE(1);
+ WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
break;
}
}

View File

@ -23,7 +23,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
}
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -441,6 +441,7 @@ struct brcmf_fw {
@@ -442,6 +442,7 @@ struct brcmf_fw {
struct brcmf_fw_request *req;
u32 curpos;
void (*done)(struct device *dev, int err, struct brcmf_fw_request *req);
@ -31,33 +31,37 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
};
static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
@@ -589,6 +590,8 @@ fail:
fwctx->req = NULL;
done:
@@ -649,6 +650,8 @@ static void brcmf_fw_request_done(const
fwctx->req = NULL;
}
fwctx->done(fwctx->dev, ret, fwctx->req);
+ if (fwctx->completion)
+ complete(fwctx->completion);
kfree(fwctx);
}
@@ -612,6 +615,8 @@ int brcmf_fw_get_firmwares(struct device
struct brcmf_fw_request *req))
@@ -673,6 +676,7 @@ int brcmf_fw_get_firmwares(struct device
{
struct brcmf_fw_item *first = &req->items[0];
struct brcmf_fw *fwctx;
+ struct completion completion;
+ int err;
int ret;
brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
if (!fw_cb)
@@ -628,7 +633,14 @@ int brcmf_fw_get_firmwares(struct device
@@ -689,6 +693,9 @@ int brcmf_fw_get_firmwares(struct device
fwctx->dev = dev;
fwctx->req = req;
fwctx->done = fw_cb;
+
+ init_completion(&completion);
+ fwctx->completion = &completion;
+
brcmf_fw_request_next_item(fwctx, true);
+
ret = request_firmware_nowait(THIS_MODULE, true, first->path,
fwctx->dev, GFP_KERNEL, fwctx,
@@ -696,6 +703,9 @@ int brcmf_fw_get_firmwares(struct device
if (ret < 0)
brcmf_fw_request_done(NULL, fwctx);
+ wait_for_completion_timeout(fwctx->completion, msecs_to_jiffies(5000));
+ fwctx->completion = NULL;
+

View File

@ -49,9 +49,9 @@ Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
struct brcmf_mp_device *settings)
{
@@ -32,6 +62,8 @@ void brcmf_of_probe(struct device *dev,
u32 irqf;
u32 val;
@@ -41,6 +71,8 @@ void brcmf_of_probe(struct device *dev,
of_node_put(root);
}
+ brcmf_of_probe_cc(dev, settings);
+

View File

@ -0,0 +1,26 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 13 Nov 2018 20:29:03 +0100
Subject: [PATCH] mac80211: ignore tx status for PS stations in
ieee80211_tx_status_ext
Make it behave like regular ieee80211_tx_status calls, except for the lack of
filtered frame processing.
This fixes spurious low-ack triggered disconnections with powersave clients
connected to an AP.
Fixes: f027c2aca0cf4 ("mac80211: add ieee80211_tx_status_noskb")
Cc: stable@vger.kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -987,6 +987,8 @@ void ieee80211_tx_status_ext(struct ieee
/* Track when last TDLS packet was ACKed */
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
sta->status_stats.last_tdls_pkt_time = jiffies;
+ } else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
+ return;
} else {
ieee80211_lost_packet(sta, info);
}