summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vasanth@atheros.com>2010-06-24 02:42:44 -0700
committerJohn W. Linville <linville@tuxdriver.com>2010-06-24 15:42:39 -0400
commitca369eb494e45a3e3b8960775f88125fe1fbb0f2 (patch)
tree2a53c84c5d848e73a271005df56b754334e5d1a2
parent75f64dd54a185150ebfc45e99351c890d4a2252f (diff)
ath9k: Fix bug in paprd
It is possbile that the transmission of paprd test frame might not get completed in 100ms if tx is stuck. Freeing this skb upon timeout in ath_paprd_calibrate() will result in accessing already freed memory when the associated pending buffer is drained in txq. This patch fixes this issue. Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c12
3 files changed, 16 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 3a14630e808..ce74af6ef08 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -226,6 +226,7 @@ struct ath_buf_state {
int bfs_retries;
u8 bf_type;
u8 bfs_paprd;
+ unsigned long bfs_paprd_timestamp;
u32 bfs_keyix;
enum ath9k_key_type bfs_keytype;
};
@@ -425,6 +426,8 @@ int ath_beaconq_config(struct ath_softc *sc);
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
+#define ATH_PAPRD_TIMEOUT 100 /* msecs */
+
void ath_paprd_calibrate(struct work_struct *work);
void ath_ani_calibrate(unsigned long data);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 5af259644bf..c070e01c8de 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -310,13 +310,13 @@ void ath_paprd_calibrate(struct work_struct *work)
break;
time_left = wait_for_completion_timeout(&sc->paprd_complete,
- 100);
+ msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
if (!time_left) {
ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
"Timeout waiting for paprd training on "
"TX chain %d\n",
chain);
- break;
+ goto fail_paprd;
}
if (!ar9003_paprd_is_done(ah))
@@ -334,6 +334,7 @@ void ath_paprd_calibrate(struct work_struct *work)
ath_paprd_activate(sc);
}
+fail_paprd:
ath9k_ps_restore(sc);
}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 20221b8c04f..edbeffb14a1 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1644,6 +1644,8 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
}
bf->bf_state.bfs_paprd = txctl->paprd;
+ if (txctl->paprd)
+ bf->bf_state.bfs_paprd_timestamp = jiffies;
bf->bf_flags = setup_tx_flags(skb, use_ldpc);
bf->bf_keytype = get_hw_crypto_keytype(skb);
@@ -1944,8 +1946,14 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
if (bf->bf_state.bfs_paprd) {
- sc->paprd_txok = txok;
- complete(&sc->paprd_complete);
+ if (time_after(jiffies,
+ bf->bf_state.bfs_paprd_timestamp +
+ msecs_to_jiffies(ATH_PAPRD_TIMEOUT))) {
+ dev_kfree_skb_any(skb);
+ } else {
+ sc->paprd_txok = txok;
+ complete(&sc->paprd_complete);
+ }
} else {
ath_tx_complete(sc, skb, bf->aphy, tx_flags);
ath_debug_stat_tx(sc, txq, bf, ts);