summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/ath9k
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9485_initvals.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h5
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c74
8 files changed, 75 insertions, 38 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 639ba7d18ea4..6988e1d081f2 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -965,7 +965,7 @@ static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah,
{
int i;
- if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah))
+ if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah) && !AR_SREV_9485(ah))
return;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
index 712f415b8c08..88ff1d7b53ab 100644
--- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
@@ -1020,7 +1020,7 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {
{0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+ {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
{0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982},
{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 8a1888d02070..366002f266f8 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -254,6 +254,7 @@ struct ath_atx_tid {
int sched;
int paused;
u8 state;
+ bool stop_cb;
};
struct ath_node {
@@ -351,7 +352,8 @@ void ath_tx_tasklet(struct ath_softc *sc);
void ath_tx_edma_tasklet(struct ath_softc *sc);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn);
-void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+bool ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid,
+ bool flush);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index e6307b86363a..b37eb8d38811 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -2008,6 +2008,14 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
WARN_ON(i != ATH9K_SSTATS_LEN);
}
+void ath9k_deinit_debug(struct ath_softc *sc)
+{
+ if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
+ relay_close(sc->rfs_chan_spec_scan);
+ sc->rfs_chan_spec_scan = NULL;
+ }
+}
+
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 794a7ec83a24..9d49aab8b989 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -304,6 +304,7 @@ struct ath9k_debug {
};
int ath9k_init_debug(struct ath_hw *ah);
+void ath9k_deinit_debug(struct ath_softc *sc);
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
@@ -339,6 +340,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah)
return 0;
}
+static inline void ath9k_deinit_debug(struct ath_softc *sc)
+{
+}
+
static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
enum ath9k_int status)
{
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 0237b2868961..aba415103f94 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -906,7 +906,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
if (!ath_is_world_regd(reg)) {
error = regulatory_hint(hw->wiphy, reg->alpha2);
if (error)
- goto unregister;
+ goto debug_cleanup;
}
ath_init_leds(sc);
@@ -914,6 +914,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
return 0;
+debug_cleanup:
+ ath9k_deinit_debug(sc);
unregister:
ieee80211_unregister_hw(hw);
rx_cleanup:
@@ -942,11 +944,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
sc->dfs_detector->exit(sc->dfs_detector);
ath9k_eeprom_release(sc);
-
- if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
- relay_close(sc->rfs_chan_spec_scan);
- sc->rfs_chan_spec_scan = NULL;
- }
}
void ath9k_deinit_device(struct ath_softc *sc)
@@ -960,6 +957,7 @@ void ath9k_deinit_device(struct ath_softc *sc)
ath9k_ps_restore(sc);
+ ath9k_deinit_debug(sc);
ieee80211_unregister_hw(hw);
ath_rx_cleanup(sc);
ath9k_deinit_softc(sc);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index a18414b5948b..2382d1262e7f 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1687,6 +1687,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
u16 tid, u16 *ssn, u8 buf_size)
{
struct ath_softc *sc = hw->priv;
+ bool flush = false;
int ret = 0;
local_bh_disable();
@@ -1703,12 +1704,13 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc);
break;
- case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+ flush = true;
+ case IEEE80211_AMPDU_TX_STOP_CONT:
ath9k_ps_wakeup(sc);
- ath_tx_aggr_stop(sc, sta, tid);
- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ if (ath_tx_aggr_stop(sc, sta, tid, flush))
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index eab0fcb7ded6..14bb3354ea64 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -164,7 +164,20 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
ARRAY_SIZE(bf->rates));
}
-static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
+static void ath_tx_clear_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
+{
+ tid->state &= ~AGGR_ADDBA_COMPLETE;
+ tid->state &= ~AGGR_CLEANUP;
+ if (!tid->stop_cb)
+ return;
+
+ ieee80211_start_tx_ba_cb_irqsafe(tid->an->vif, tid->an->sta->addr,
+ tid->tidno);
+ tid->stop_cb = false;
+}
+
+static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid,
+ bool flush_packets)
{
struct ath_txq *txq = tid->ac->txq;
struct sk_buff *skb;
@@ -181,16 +194,15 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
while ((skb = __skb_dequeue(&tid->buf_q))) {
fi = get_frame_info(skb);
bf = fi->bf;
+ if (!bf && !flush_packets)
+ bf = ath_tx_setup_buffer(sc, txq, tid, skb);
if (!bf) {
- bf = ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
+ ieee80211_free_txskb(sc->hw, skb);
+ continue;
}
- if (fi->retries) {
+ if (fi->retries || flush_packets) {
list_add_tail(&bf->list, &bf_head);
ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
@@ -201,12 +213,10 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
}
}
- if (tid->baw_head == tid->baw_tail) {
- tid->state &= ~AGGR_ADDBA_COMPLETE;
- tid->state &= ~AGGR_CLEANUP;
- }
+ if (tid->baw_head == tid->baw_tail)
+ ath_tx_clear_tid(sc, tid);
- if (sendbar) {
+ if (sendbar && !flush_packets) {
ath_txq_unlock(sc, txq);
ath_send_bar(tid, tid->seq_start);
ath_txq_lock(sc, txq);
@@ -277,9 +287,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
list_add_tail(&bf->list, &bf_head);
- if (fi->retries)
- ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
-
+ ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
}
@@ -602,7 +610,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
}
if (tid->state & AGGR_CLEANUP)
- ath_tx_flush_tid(sc, tid);
+ ath_tx_flush_tid(sc, tid, false);
rcu_read_unlock();
@@ -620,6 +628,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
struct ath_tx_status *ts, struct ath_buf *bf,
struct list_head *bf_head)
{
+ struct ieee80211_tx_info *info;
bool txok, flush;
txok = !(ts->ts_status & ATH9K_TXERR_MASK);
@@ -631,8 +640,12 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
txq->axq_ampdu_depth--;
if (!bf_isampdu(bf)) {
- if (!flush)
+ if (!flush) {
+ info = IEEE80211_SKB_CB(bf->bf_mpdu);
+ memcpy(info->control.rates, bf->rates,
+ sizeof(info->control.rates));
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
+ }
ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
} else
ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
@@ -676,7 +689,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
skb = bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb);
- rates = tx_info->control.rates;
+ rates = bf->rates;
/*
* Find the lowest frame length among the rate series that will have a
@@ -1256,18 +1269,23 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
return 0;
}
-void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
+bool ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid,
+ bool flush)
{
struct ath_node *an = (struct ath_node *)sta->drv_priv;
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
struct ath_txq *txq = txtid->ac->txq;
+ bool ret = !flush;
+
+ if (flush)
+ txtid->stop_cb = false;
if (txtid->state & AGGR_CLEANUP)
- return;
+ return false;
if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
txtid->state &= ~AGGR_ADDBA_PROGRESS;
- return;
+ return ret;
}
ath_txq_lock(sc, txq);
@@ -1279,13 +1297,17 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
* TID can only be reused after all in-progress subframes have been
* completed.
*/
- if (txtid->baw_head != txtid->baw_tail)
+ if (txtid->baw_head != txtid->baw_tail) {
txtid->state |= AGGR_CLEANUP;
- else
+ ret = false;
+ txtid->stop_cb = !flush;
+ } else {
txtid->state &= ~AGGR_ADDBA_COMPLETE;
+ }
- ath_tx_flush_tid(sc, txtid);
+ ath_tx_flush_tid(sc, txtid, flush);
ath_txq_unlock_complete(sc, txq);
+ return ret;
}
void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
@@ -2415,6 +2437,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
tid->ac = &an->ac[acno];
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_ADDBA_PROGRESS;
+ tid->stop_cb = false;
}
for (acno = 0, ac = &an->ac[acno];
@@ -2451,8 +2474,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
}
ath_tid_drain(sc, txq, tid);
- tid->state &= ~AGGR_ADDBA_COMPLETE;
- tid->state &= ~AGGR_CLEANUP;
+ ath_tx_clear_tid(sc, tid);
ath_txq_unlock(sc, txq);
}