aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorRajkumar Manoharan <rmanohar@qca.qualcomm.com>2011-06-23 04:09:13 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-06-27 15:09:40 -0400
commitdcfcbd590d91e8385eb554aaed419bdebaf4c72a (patch)
tree3ea376c7c1c866e6c8da62d11ff0a072a74340ec /drivers/net
parent15b4d843ab66bc0ac2cd46baa20a3ce9638604e6 (diff)
ath9k_hw: Fix false tx hung detection in AR9003 chips
The edma based (AR9003 family) chips update tx status descriptors in a common ring buffer for all transmitted frames. Whenever tx interrupt is raised, the descriptors are processed and tx status index is moved. The complete tx stauts ring are updated with beacons tx status when there are no data frames to be sent for a period of time. In this state, transmitting data frames causes the driver to wait for the tx status on an incorrect tx status index though the status was updated by hw properly. The driver detects this condition as a h/w hang and does unnecessary chip resets. This issue was orginally reported in adhoc mode while sending frames after an idle time. Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c6
2 files changed, 12 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 04e6be04acf9..575e185f454f 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -229,6 +229,7 @@ static void ar9003_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen,
229static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, 229static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
230 struct ath_tx_status *ts) 230 struct ath_tx_status *ts)
231{ 231{
232 struct ar9003_txc *txc = (struct ar9003_txc *) ds;
232 struct ar9003_txs *ads; 233 struct ar9003_txs *ads;
233 u32 status; 234 u32 status;
234 235
@@ -238,7 +239,11 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
238 if ((status & AR_TxDone) == 0) 239 if ((status & AR_TxDone) == 0)
239 return -EINPROGRESS; 240 return -EINPROGRESS;
240 241
241 ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size; 242 ts->qid = MS(ads->ds_info, AR_TxQcuNum);
243 if (!txc || (MS(txc->info, AR_TxQcuNum) == ts->qid))
244 ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size;
245 else
246 return -ENOENT;
242 247
243 if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) || 248 if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) ||
244 (MS(ads->ds_info, AR_TxRxDesc) != 1)) { 249 (MS(ads->ds_info, AR_TxRxDesc) != 1)) {
@@ -254,7 +259,6 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
254 ts->ts_seqnum = MS(status, AR_SeqNum); 259 ts->ts_seqnum = MS(status, AR_SeqNum);
255 ts->tid = MS(status, AR_TxTid); 260 ts->tid = MS(status, AR_TxTid);
256 261
257 ts->qid = MS(ads->ds_info, AR_TxQcuNum);
258 ts->desc_id = MS(ads->status1, AR_TxDescId); 262 ts->desc_id = MS(ads->status1, AR_TxDescId);
259 ts->ts_tstamp = ads->status4; 263 ts->ts_tstamp = ads->status4;
260 ts->ts_status = 0; 264 ts->ts_status = 0;
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 0174cdb65a83..0b6e3b65bb0b 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -360,6 +360,7 @@ void ath_beacon_tasklet(unsigned long data)
360 struct ath_common *common = ath9k_hw_common(ah); 360 struct ath_common *common = ath9k_hw_common(ah);
361 struct ath_buf *bf = NULL; 361 struct ath_buf *bf = NULL;
362 struct ieee80211_vif *vif; 362 struct ieee80211_vif *vif;
363 struct ath_tx_status ts;
363 int slot; 364 int slot;
364 u32 bfaddr, bc = 0; 365 u32 bfaddr, bc = 0;
365 366
@@ -464,6 +465,11 @@ void ath_beacon_tasklet(unsigned long data)
464 ath9k_hw_txstart(ah, sc->beacon.beaconq); 465 ath9k_hw_txstart(ah, sc->beacon.beaconq);
465 466
466 sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */ 467 sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */
468 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
469 spin_lock_bh(&sc->sc_pcu_lock);
470 ath9k_hw_txprocdesc(ah, bf->bf_desc, (void *)&ts);
471 spin_unlock_bh(&sc->sc_pcu_lock);
472 }
467 } 473 }
468} 474}
469 475