brcmsmac: fix tx status processing
PATCH 1/1 brcmsmac: fix tx status processing
This issue was reported on the wireless list (see [1]) in which brcmsmac ran into a fatal error:
[ 588.284074] brcmsmac bcma0:0: frameid != txh->TxFrameID [ 588.284098] brcmsmac bcma0:0: MI_TFS: fatal [ 588.284103] brcmsmac bcma0:0: wl0: fatal error, reinitializing [ 588.286208] ieee80211 phy0: Hardware restart was requested
The tx status feedback is processed in a loop limiting the number of frames processed in one run. The code terminate processing when the limit is reached regardless the txstatus value read from the device register. When that status is is flagged as being valid it must be processed as the hardware will clear it after is has been read.
Bisecting was done by Seth Forshee and showed following commit as the culprit:
commit 57fe504817ccec9b6ac23e973d2925343bf1e3b6
Author: Piotr Haber <[email protected]> Date: Wed Nov 28 21:44:07 2012 +0100
brcmsmac: fix bounds checking in tx/rx
[1] http://www.spinics.net/lists/linux-wireless/msg101293.html
Reported-by Linus Torvalds <[email protected]>
Tested-by Seth Forshee <[email protected]>
Reviewed-by Hante Meuleman <[email protected]>
Reviewed-by Pieter-Paul Giesberts <[email protected]>
Signed-off-by Arend van Spriel <[email protected]>
--- drivers/net/wireless/brcm80211/brcmsmac/main.c | 25 +++++++++--------------- 1 file changed, 9 insertions(+), 16 deletions(-)
drivers/net/wireless/brcm80211/brcmsmac/main.c +9 -16
@@ -1027,7 +1027,6 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)static bool brcms_b_txstatus (struct brcms_hardware *wlc_hw,bool bound,bool *fatal) { -bool morepending = false;struct bcma_device *core;struct tx_status txstatus, *txs;u32 s1, s2;
@@ -1041,23 +1040,20 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) txs = &txstatus; core = wlc_hw->d11core; *fatal = false; - s1 =bcma_read32 (core,D11REGOFFS (frmtxstatus)); -while (!(*fatal) - && (s1 &TXS_V )) { -/* !give others some time to run! */ -if (n >= max_tx_num) { - morepending = true; -break ; - } +while (n < max_tx_num) { + s1 =bcma_read32 (core,D11REGOFFS (frmtxstatus));if (s1 ==0xffffffff ) {brcms_err (core,"wl%d: %s: dead chip\n" , wlc_hw->unit, __func__); *fatal = true;return false; } - s2 =bcma_read32 (core,D11REGOFFS (frmtxstatus2)); +/* only process when valid */ +if (!(s1 &TXS_V )) +break ; + s2 =bcma_read32 (core,D11REGOFFS (frmtxstatus2)); txs->status = s1 &TXS_STATUS_MASK ; txs->frameid = (s1 &TXS_FID_MASK ) >>TXS_FID_SHIFT ; txs->sequence = s2 &TXS_SEQ_MASK ;
@@ -1065,15 +1061,12 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) txs->lasttxtime =0 ; *fatal =brcms_c_dotxstatus (wlc_hw->wlc, txs); - - s1 =bcma_read32 (core,D11REGOFFS (frmtxstatus)); +if (*fatal == true) +return false; n++; } -if (*fatal) -return false; - -return morepending; +return n >= max_tx_num; }static void brcms_c_tbtt (struct brcms_c_info *wlc)
Signature · 1 line
1.7.10.4